diff options
75 files changed, 3687 insertions, 296 deletions
diff --git a/.gitignore b/.gitignore index 8d18d6f49b..3df3139d23 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ *.bin *.cfgout *.dtb +*.dtbo *.dtb.S *.elf *.exe diff --git a/MAINTAINERS b/MAINTAINERS index f1f8818d6b..4fabb75eda 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -471,6 +471,8 @@ F: lib/efi*/ F: test/py/tests/test_efi* F: test/unicode_ut.c F: cmd/bootefi.c +F: cmd/efidebug.c +F: cmd/nvedit_efi.c F: tools/file2include.c FPGA diff --git a/arch/Kconfig b/arch/Kconfig index d9afe269f2..2f3d07c13a 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -61,6 +61,7 @@ config PPC config RISCV bool "RISC-V architecture" + select CREATE_ARCH_SYMLINK select SUPPORT_OF_CONTROL select OF_CONTROL select DM diff --git a/arch/arm/dts/sun50i-h5-bananapi-m2-plus.dts b/arch/arm/dts/sun50i-h5-bananapi-m2-plus.dts new file mode 100644 index 0000000000..3503767483 --- /dev/null +++ b/arch/arm/dts/sun50i-h5-bananapi-m2-plus.dts @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +// Copyright (C) 2018 Chen-Yu Tsai <wens@csie.org> + +/dts-v1/; +#include "sun50i-h5.dtsi" +#include <sunxi-bananapi-m2-plus.dtsi> + +/ { + model = "Banana Pi BPI-M2-Plus H5"; + compatible = "sinovoip,bpi-m2-plus", "allwinner,sun50i-h5"; +}; diff --git a/arch/arm/dts/sun8i-h3-bananapi-m2-plus.dts b/arch/arm/dts/sun8i-h3-bananapi-m2-plus.dts index 30540dc8e0..195a75da13 100644 --- a/arch/arm/dts/sun8i-h3-bananapi-m2-plus.dts +++ b/arch/arm/dts/sun8i-h3-bananapi-m2-plus.dts @@ -42,195 +42,9 @@ /dts-v1/; #include "sun8i-h3.dtsi" -#include "sunxi-common-regulators.dtsi" - -#include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/input/input.h> +#include "sunxi-bananapi-m2-plus.dtsi" / { - model = "Banana Pi BPI-M2-Plus"; + model = "Banana Pi BPI-M2-Plus H3"; compatible = "sinovoip,bpi-m2-plus", "allwinner,sun8i-h3"; - - aliases { - ethernet0 = &emac; - serial0 = &uart0; - serial1 = &uart1; - }; - - chosen { - stdout-path = "serial0:115200n8"; - }; - - connector { - compatible = "hdmi-connector"; - type = "a"; - - port { - hdmi_con_in: endpoint { - remote-endpoint = <&hdmi_out_con>; - }; - }; - }; - - leds { - compatible = "gpio-leds"; - pinctrl-names = "default"; - - pwr_led { - label = "bananapi-m2-plus:red:pwr"; - gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; /* PL10 */ - default-state = "on"; - }; - }; - - gpio_keys { - compatible = "gpio-keys"; - pinctrl-names = "default"; - - sw4 { - label = "power"; - linux,code = <BTN_0>; - gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>; - }; - }; - - reg_gmac_3v3: gmac-3v3 { - compatible = "regulator-fixed"; - regulator-name = "gmac-3v3"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - startup-delay-us = <100000>; - enable-active-high; - gpio = <&pio 3 6 GPIO_ACTIVE_HIGH>; - }; - - wifi_pwrseq: wifi_pwrseq { - compatible = "mmc-pwrseq-simple"; - pinctrl-names = "default"; - reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 */ - }; -}; - -&de { - status = "okay"; -}; - -&ehci0 { - status = "okay"; -}; - -&ehci1 { - status = "okay"; -}; - -&ehci2 { - status = "okay"; -}; - -&emac { - pinctrl-names = "default"; - pinctrl-0 = <&emac_rgmii_pins>; - phy-supply = <®_gmac_3v3>; - phy-handle = <&ext_rgmii_phy>; - phy-mode = "rgmii"; - - status = "okay"; -}; - -&external_mdio { - ext_rgmii_phy: ethernet-phy@1 { - compatible = "ethernet-phy-ieee802.3-c22"; - reg = <0>; - }; -}; - -&hdmi { - status = "okay"; -}; - -&hdmi_out { - hdmi_out_con: endpoint { - remote-endpoint = <&hdmi_con_in>; - }; -}; - -&ir { - pinctrl-names = "default"; - pinctrl-0 = <&ir_pins_a>; - status = "okay"; -}; - -&mmc0 { - vmmc-supply = <®_vcc3v3>; - bus-width = <4>; - cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */ - status = "okay"; -}; - -&mmc1 { - vmmc-supply = <®_vcc3v3>; - vqmmc-supply = <®_vcc3v3>; - mmc-pwrseq = <&wifi_pwrseq>; - bus-width = <4>; - non-removable; - status = "okay"; - - brcmf: wifi@1 { - reg = <1>; - compatible = "brcm,bcm4329-fmac"; - interrupt-parent = <&pio>; - interrupts = <6 10 IRQ_TYPE_LEVEL_LOW>; /* PG10 / EINT10 */ - interrupt-names = "host-wake"; - }; -}; - -&mmc2 { - pinctrl-names = "default"; - pinctrl-0 = <&mmc2_8bit_pins>; - vmmc-supply = <®_vcc3v3>; - vqmmc-supply = <®_vcc3v3>; - bus-width = <8>; - non-removable; - status = "okay"; -}; - -&ohci0 { - status = "okay"; -}; - -&ohci1 { - status = "okay"; -}; - -&ohci2 { - status = "okay"; -}; - -®_usb0_vbus { - gpio = <&pio 3 11 GPIO_ACTIVE_HIGH>; /* PD11 */ - status = "okay"; -}; - -&uart0 { - pinctrl-names = "default"; - pinctrl-0 = <&uart0_pins_a>; - status = "okay"; -}; - -&uart1 { - pinctrl-names = "default"; - pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>; - status = "okay"; -}; - -&usb_otg { - dr_mode = "otg"; - status = "okay"; -}; - -&usbphy { - usb0_id_det-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 */ - usb0_vbus-supply = <®_usb0_vbus>; - /* USB host VBUS is on as long as VCC-IO is on */ - status = "okay"; }; diff --git a/arch/arm/dts/sunxi-bananapi-m2-plus.dtsi b/arch/arm/dts/sunxi-bananapi-m2-plus.dtsi new file mode 100644 index 0000000000..3bed375b9c --- /dev/null +++ b/arch/arm/dts/sunxi-bananapi-m2-plus.dtsi @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2016 Chen-Yu Tsai <wens@csie.org> + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "sunxi-common-regulators.dtsi" + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/input/input.h> + +/ { + aliases { + ethernet0 = &emac; + serial0 = &uart0; + serial1 = &uart1; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi_out_con>; + }; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + + pwr_led { + label = "bananapi-m2-plus:red:pwr"; + gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; /* PL10 */ + default-state = "on"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + + sw4 { + label = "power"; + linux,code = <BTN_0>; + gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>; + }; + }; + + reg_gmac_3v3: gmac-3v3 { + compatible = "regulator-fixed"; + regulator-name = "gmac-3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + startup-delay-us = <100000>; + enable-active-high; + gpio = <&pio 3 6 GPIO_ACTIVE_HIGH>; + }; + + wifi_pwrseq: wifi_pwrseq { + compatible = "mmc-pwrseq-simple"; + pinctrl-names = "default"; + reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 */ + clocks = <&rtc 1>; + clock-names = "ext_clock"; + }; +}; + +&de { + status = "okay"; +}; + +&ehci0 { + status = "okay"; +}; + +&ehci1 { + status = "okay"; +}; + +&ehci2 { + status = "okay"; +}; + +&emac { + pinctrl-names = "default"; + pinctrl-0 = <&emac_rgmii_pins>; + phy-supply = <®_gmac_3v3>; + phy-handle = <&ext_rgmii_phy>; + phy-mode = "rgmii"; + + status = "okay"; +}; + +&external_mdio { + ext_rgmii_phy: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + }; +}; + +&hdmi { + status = "okay"; +}; + +&hdmi_out { + hdmi_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; +}; + +&ir { + pinctrl-names = "default"; + pinctrl-0 = <&ir_pins_a>; + status = "okay"; +}; + +&mmc0 { + vmmc-supply = <®_vcc3v3>; + bus-width = <4>; + cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */ + status = "okay"; +}; + +&mmc1 { + vmmc-supply = <®_vcc3v3>; + vqmmc-supply = <®_vcc3v3>; + mmc-pwrseq = <&wifi_pwrseq>; + bus-width = <4>; + non-removable; + status = "okay"; + + brcmf: wifi@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + interrupt-parent = <&pio>; + interrupts = <6 10 IRQ_TYPE_LEVEL_LOW>; /* PG10 / EINT10 */ + interrupt-names = "host-wake"; + }; +}; + +&mmc2 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc2_8bit_pins>; + vmmc-supply = <®_vcc3v3>; + vqmmc-supply = <®_vcc3v3>; + bus-width = <8>; + non-removable; + status = "okay"; +}; + +&ohci0 { + status = "okay"; +}; + +&ohci1 { + status = "okay"; +}; + +&ohci2 { + status = "okay"; +}; + +®_usb0_vbus { + gpio = <&pio 3 11 GPIO_ACTIVE_HIGH>; /* PD11 */ + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins_a>; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>; + uart-has-rtscts; + status = "okay"; + + bluetooth { + compatible = "brcm,bcm43438-bt"; + clocks = <&rtc 1>; + clock-names = "lpo"; + vbat-supply = <®_vcc3v3>; + vddio-supply = <®_vcc3v3>; + device-wakeup-gpios = <&pio 6 13 GPIO_ACTIVE_HIGH>; /* PG13 */ + host-wakeup-gpios = <&pio 6 11 GPIO_ACTIVE_HIGH>; /* PG11 */ + shutdown-gpios = <&pio 6 12 GPIO_ACTIVE_HIGH>; /* PG12 */ + }; +}; + +&usb_otg { + dr_mode = "otg"; + status = "okay"; +}; + +&usbphy { + usb0_id_det-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 */ + usb0_vbus-supply = <®_usb0_vbus>; + /* USB host VBUS is on as long as VCC-IO is on */ + status = "okay"; +}; diff --git a/arch/arm/mach-rmobile/Kconfig.32 b/arch/arm/mach-rmobile/Kconfig.32 index 076a019135..67f669a6fc 100644 --- a/arch/arm/mach-rmobile/Kconfig.32 +++ b/arch/arm/mach-rmobile/Kconfig.32 @@ -16,25 +16,35 @@ config R8A7790 bool "Renesas SoC R8A7790" select RCAR_GEN2 select ARM_CORTEX_A15_CVE_2017_5715 + imply CLK_R8A7790 + imply PINCTRL_PFC_R8A7790 config R8A7791 bool "Renesas SoC R8A7791" select RCAR_GEN2 select ARM_CORTEX_A15_CVE_2017_5715 + imply CLK_R8A7791 + imply PINCTRL_PFC_R8A7791 config R8A7792 bool "Renesas SoC R8A7792" select RCAR_GEN2 select ARM_CORTEX_A15_CVE_2017_5715 + imply CLK_R8A7792 + imply PINCTRL_PFC_R8A7792 config R8A7793 bool "Renesas SoC R8A7793" select RCAR_GEN2 select ARM_CORTEX_A15_CVE_2017_5715 + imply CLK_R8A7793 + imply PINCTRL_PFC_R8A7793 config R8A7794 bool "Renesas SoC R8A7794" select RCAR_GEN2 + imply CLK_R8A7794 + imply PINCTRL_PFC_R8A7794 choice prompt "Renesas ARM SoCs board select" diff --git a/arch/arm/mach-rmobile/Kconfig.64 b/arch/arm/mach-rmobile/Kconfig.64 index cb9f569e5f..b2ac1cdad7 100644 --- a/arch/arm/mach-rmobile/Kconfig.64 +++ b/arch/arm/mach-rmobile/Kconfig.64 @@ -1,51 +1,67 @@ if RCAR_GEN3 -choice - prompt "Select Target SoC" +menu "Select Target SoC" config R8A7795 bool "Renesas SoC R8A7795" + imply CLK_R8A7795 + imply PINCTRL_PFC_R8A7795 config R8A7796 bool "Renesas SoC R8A7796" + imply CLK_R8A7796 + imply PINCTRL_PFC_R8A7796 config R8A77970 bool "Renesas SoC R8A77970" + imply CLK_R8A77970 + imply PINCTRL_PFC_R8A77970 config R8A77990 bool "Renesas SoC R8A77990" + imply CLK_R8A77990 + imply PINCTRL_PFC_R8A77990 config R8A77995 bool "Renesas SoC R8A77995" + imply CLK_R8A77995 + imply PINCTRL_PFC_R8A77995 -endchoice +endmenu choice - prompt "Renesus ARM64 SoCs board select" + prompt "Renesas ARM64 SoCs board select" optional config TARGET_DRAAK bool "Draak board" + imply R8A77995 help Support for Renesas R-Car Gen3 Draak platform config TARGET_EAGLE bool "Eagle board" + imply R8A77970 help Support for Renesas R-Car Gen3 Eagle platform config TARGET_EBISU bool "Ebisu board" + imply R8A77990 help Support for Renesas R-Car Gen3 Ebisu platform config TARGET_SALVATOR_X bool "Salvator-X board" + imply R8A7795 + imply R8A7796 help Support for Renesas R-Car Gen3 platform config TARGET_ULCB bool "ULCB board" + imply R8A7795 + imply R8A7796 help Support for Renesas R-Car Gen3 ULCB platform diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index c45e4d73a8..36512a8995 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -14,15 +14,19 @@ config TARGET_AX25_AE350 config TARGET_QEMU_VIRT bool "Support QEMU Virt Board" +config TARGET_SIFIVE_FU540 + bool "Support SiFive FU540 Board" + endchoice # board-specific options below source "board/AndesTech/ax25-ae350/Kconfig" source "board/emulation/qemu-riscv/Kconfig" +source "board/sifive/fu540/Kconfig" # platform-specific options below source "arch/riscv/cpu/ax25/Kconfig" -source "arch/riscv/cpu/qemu/Kconfig" +source "arch/riscv/cpu/generic/Kconfig" # architecture-specific options below diff --git a/arch/riscv/cpu/qemu/Kconfig b/arch/riscv/cpu/generic/Kconfig index f48751e6de..1d6ab5032d 100644 --- a/arch/riscv/cpu/qemu/Kconfig +++ b/arch/riscv/cpu/generic/Kconfig @@ -2,7 +2,7 @@ # # Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com> -config QEMU_RISCV +config GENERIC_RISCV bool select ARCH_EARLY_INIT_R imply CPU diff --git a/arch/riscv/cpu/qemu/Makefile b/arch/riscv/cpu/generic/Makefile index 258e4620dd..258e4620dd 100644 --- a/arch/riscv/cpu/qemu/Makefile +++ b/arch/riscv/cpu/generic/Makefile diff --git a/arch/riscv/cpu/qemu/cpu.c b/arch/riscv/cpu/generic/cpu.c index ad2950ce40..ad2950ce40 100644 --- a/arch/riscv/cpu/qemu/cpu.c +++ b/arch/riscv/cpu/generic/cpu.c diff --git a/arch/riscv/cpu/generic/dram.c b/arch/riscv/cpu/generic/dram.c new file mode 100644 index 0000000000..b7b1207235 --- /dev/null +++ b/arch/riscv/cpu/generic/dram.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com> + */ + +#include <common.h> +#include <fdtdec.h> +#include <linux/sizes.h> + +DECLARE_GLOBAL_DATA_PTR; + +int dram_init(void) +{ + return fdtdec_setup_mem_size_base(); +} + +int dram_init_banksize(void) +{ + return fdtdec_setup_memory_banksize(); +} + +ulong board_get_usable_ram_top(ulong total_size) +{ +#ifdef CONFIG_64BIT + /* + * Ensure that we run from first 4GB so that all + * addresses used by U-Boot are 32bit addresses. + * + * This in-turn ensures that 32bit DMA capable + * devices work fine because DMA mapping APIs will + * provide 32bit DMA addresses only. + */ + if (gd->ram_top > SZ_4G) + return SZ_4G; +#endif + return gd->ram_top; +} diff --git a/arch/riscv/cpu/qemu/dram.c b/arch/riscv/cpu/qemu/dram.c deleted file mode 100644 index 84d87d2a7f..0000000000 --- a/arch/riscv/cpu/qemu/dram.c +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com> - */ - -#include <common.h> -#include <fdtdec.h> - -int dram_init(void) -{ - return fdtdec_setup_mem_size_base(); -} - -int dram_init_banksize(void) -{ - return fdtdec_setup_memory_banksize(); -} diff --git a/arch/riscv/include/asm/arch-generic/clk.h b/arch/riscv/include/asm/arch-generic/clk.h new file mode 100644 index 0000000000..1631f5f0bd --- /dev/null +++ b/arch/riscv/include/asm/arch-generic/clk.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2019 Western Digital Corporation or its affiliates. + * + * Authors: + * Anup Patel <anup.patel@wdc.com> + */ + +#ifndef __ASM_RISCV_ARCH_CLK_H +#define __ASM_RISCV_ARCH_CLK_H + +/* Note: This is a placeholder header for driver compilation. */ + +#endif diff --git a/arch/riscv/include/asm/config.h b/arch/riscv/include/asm/config.h index 81bc975d2e..156cb94dc0 100644 --- a/arch/riscv/include/asm/config.h +++ b/arch/riscv/include/asm/config.h @@ -8,5 +8,6 @@ #define _ASM_CONFIG_H_ #define CONFIG_LMB +#define CONFIG_SYS_BOOT_RAMDISK_HIGH #endif diff --git a/arch/riscv/include/asm/dma-mapping.h b/arch/riscv/include/asm/dma-mapping.h new file mode 100644 index 0000000000..3d930c90ec --- /dev/null +++ b/arch/riscv/include/asm/dma-mapping.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2018 Western Digital Corporation or its affiliates. + * + * Authors: + * Anup Patel <anup.patel@wdc.com> + */ + +#ifndef __ASM_RISCV_DMA_MAPPING_H +#define __ASM_RISCV_DMA_MAPPING_H + +#include <linux/dma-direction.h> + +#define dma_mapping_error(x, y) 0 + +static inline void *dma_alloc_coherent(size_t len, unsigned long *handle) +{ + *handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len); + return (void *)*handle; +} + +static inline void dma_free_coherent(void *addr) +{ + free(addr); +} + +static inline unsigned long dma_map_single(volatile void *vaddr, size_t len, + enum dma_data_direction dir) +{ + return (unsigned long)vaddr; +} + +static inline void dma_unmap_single(volatile void *vaddr, size_t len, + unsigned long paddr) +{ +} + +#endif /* __ASM_RISCV_DMA_MAPPING_H */ diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index d4c708c79e..87d8e5bcc9 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -203,6 +203,14 @@ #clock-cells = <0>; clock-frequency = <1234>; }; + + clk_fixed_factor: clk-fixed-factor { + compatible = "fixed-factor-clock"; + #clock-cells = <0>; + clock-div = <3>; + clock-mult = <2>; + clocks = <&clk_fixed>; + }; }; clk_sandbox: clk-sbox { diff --git a/board/eets/pdu001/mux.c b/board/eets/pdu001/mux.c index f1d38e9b74..f0f9e262eb 100644 --- a/board/eets/pdu001/mux.c +++ b/board/eets/pdu001/mux.c @@ -8,11 +8,11 @@ */ #include <common.h> +#include <i2c.h> #include <asm/arch/sys_proto.h> #include <asm/arch/hardware.h> #include <asm/arch/mux.h> #include <asm/io.h> -#include <i2c.h> #include "board.h" static struct module_pin_mux uart0_pin_mux[] = { diff --git a/board/emulation/qemu-riscv/Kconfig b/board/emulation/qemu-riscv/Kconfig index 0d865acf10..88d07d568e 100644 --- a/board/emulation/qemu-riscv/Kconfig +++ b/board/emulation/qemu-riscv/Kconfig @@ -7,7 +7,7 @@ config SYS_VENDOR default "emulation" config SYS_CPU - default "qemu" + default "generic" config SYS_CONFIG_NAME default "qemu-riscv" @@ -18,7 +18,7 @@ config SYS_TEXT_BASE config BOARD_SPECIFIC_OPTIONS # dummy def_bool y - select QEMU_RISCV + select GENERIC_RISCV imply SYS_NS16550 imply VIRTIO_MMIO imply VIRTIO_NET diff --git a/board/sifive/fu540/Kconfig b/board/sifive/fu540/Kconfig new file mode 100644 index 0000000000..6be3d88144 --- /dev/null +++ b/board/sifive/fu540/Kconfig @@ -0,0 +1,42 @@ +if TARGET_SIFIVE_FU540 + +config SYS_BOARD + default "fu540" + +config SYS_VENDOR + default "sifive" + +config SYS_CPU + default "generic" + +config SYS_CONFIG_NAME + default "sifive-fu540" + +config SYS_TEXT_BASE + default 0x80000000 if !RISCV_SMODE + default 0x80200000 if RISCV_SMODE + +config BOARD_SPECIFIC_OPTIONS # dummy + def_bool y + select GENERIC_RISCV + imply CMD_DHCP + imply CMD_EXT2 + imply CMD_EXT4 + imply CMD_FAT + imply CMD_FS_GENERIC + imply CMD_NET + imply CMD_PING + imply CLK_SIFIVE + imply CLK_SIFIVE_FU540_PRCI + imply DOS_PARTITION + imply EFI_PARTITION + imply IP_DYN + imply ISO_PARTITION + imply MACB + imply MII + imply NET_RANDOM_ETHADDR + imply PHY_LIB + imply PHY_MSCC + imply SIFIVE_SERIAL + +endif diff --git a/board/sifive/fu540/MAINTAINERS b/board/sifive/fu540/MAINTAINERS new file mode 100644 index 0000000000..702d803ad8 --- /dev/null +++ b/board/sifive/fu540/MAINTAINERS @@ -0,0 +1,9 @@ +SiFive FU540 BOARD +M: Paul Walmsley <paul.walmsley@sifive.com> +M: Palmer Dabbelt <palmer@sifive.com> +M: Anup Patel <anup.patel@wdc.com> +M: Atish Patra <atish.patra@wdc.com> +S: Maintained +F: board/sifive/fu540/ +F: include/configs/sifive-fu540.h +F: configs/sifive_fu540_defconfig diff --git a/board/sifive/fu540/Makefile b/board/sifive/fu540/Makefile new file mode 100644 index 0000000000..6e1862c475 --- /dev/null +++ b/board/sifive/fu540/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c) 2019 Western Digital Corporation or its affiliates. + +obj-y += fu540.o diff --git a/board/sifive/fu540/fu540.c b/board/sifive/fu540/fu540.c new file mode 100644 index 0000000000..5adc4a3d4a --- /dev/null +++ b/board/sifive/fu540/fu540.c @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2019 Western Digital Corporation or its affiliates. + * + * Authors: + * Anup Patel <anup.patel@wdc.com> + */ + +#include <common.h> +#include <dm.h> + +int board_init(void) +{ + /* For now nothing to do here. */ + + return 0; +} diff --git a/board/sunxi/MAINTAINERS b/board/sunxi/MAINTAINERS index 608a86be49..8e2f90fc68 100644 --- a/board/sunxi/MAINTAINERS +++ b/board/sunxi/MAINTAINERS @@ -137,6 +137,13 @@ M: Jagan Teki <jagan@amarulasolutions.com> S: Maintained F: configs/bananapi_m2_berry_defconfig +BANANAPI M2 PLUS BOARDS +M: Icenowy Zheng <icenowy@aosc.io> +M: Chen-Yu Tsai <wens@csie.org> +S: Maintained +F: configs/bananapi_m2_plus_h3_defconfig +F: configs/bananapi_m2_plus_h5_defconfig + BANANAPI M2 ULTRA BOARD M: Chen-Yu Tsai <wens@csie.org> S: Maintained @@ -418,11 +425,6 @@ S: Maintained F: configs/Sinlinx_SinA33_defconfig W: http://linux-sunxi.org/Sinlinx_SinA33 -SINOVOIP BPI M2 PLUS H3 BOARD -M: Icenowy Zheng <icenowy@aosc.io> -S: Maintained -F: configs/Sinovoip_BPI_M2_Plus_defconfig - SINOVOIP BPI M3 A83T BOARD M: VishnuPatekar <vishnupatekar0510@gmail.com> S: Maintained diff --git a/cmd/Kconfig b/cmd/Kconfig index ed8d85bfa6..4bcc5c4557 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -420,6 +420,16 @@ config CMD_ENV_FLAGS be deleted. This command shows the variables that have special flags. +config CMD_NVEDIT_EFI + bool "env [set|print] -e - set/print UEFI variables" + depends on EFI_LOADER + default y + imply HEXDUMP + help + UEFI variables are encoded as some form of U-Boot variables. + If enabled, we are allowed to set/print UEFI variables using + "env" command with "-e" option without knowing details. + endmenu menu "Memory commands" @@ -1397,6 +1407,16 @@ config CMD_DISPLAY displayed on a simple board-specific display. Implement display_putc() to use it. +config CMD_EFIDEBUG + bool "efidebug - display/configure UEFI environment" + depends on EFI_LOADER + default n + help + Enable the 'efidebug' command which provides a subset of UEFI + shell utility with simplified functionality. It will be useful + particularly for managing boot parameters as well as examining + various EFI status for debugging. + config CMD_LED bool "led" depends on LED diff --git a/cmd/Makefile b/cmd/Makefile index a127a99539..acb85f49fb 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_CMD_ECHO) += echo.o obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o obj-$(CONFIG_CMD_EEPROM) += eeprom.o obj-$(CONFIG_EFI_STUB) += efi.o +obj-$(CONFIG_CMD_EFIDEBUG) += efidebug.o obj-$(CONFIG_CMD_ELF) += elf.o obj-$(CONFIG_HUSH_PARSER) += exit.o obj-$(CONFIG_CMD_EXT4) += ext4.o @@ -98,6 +99,7 @@ obj-$(CONFIG_CMD_MTD) += mtd.o obj-$(CONFIG_CMD_MTDPARTS) += mtdparts.o obj-$(CONFIG_CMD_NAND) += nand.o obj-$(CONFIG_CMD_NET) += net.o +obj-$(CONFIG_CMD_NVEDIT_EFI) += nvedit_efi.o obj-$(CONFIG_CMD_ONENAND) += onenand.o obj-$(CONFIG_CMD_OSD) += osd.o obj-$(CONFIG_CMD_PART) += part.o diff --git a/cmd/efidebug.c b/cmd/efidebug.c new file mode 100644 index 0000000000..5072a7b39b --- /dev/null +++ b/cmd/efidebug.c @@ -0,0 +1,1046 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * UEFI Shell-like command + * + * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited + */ + +#include <charset.h> +#include <common.h> +#include <command.h> +#include <efi_loader.h> +#include <environment.h> +#include <exports.h> +#include <malloc.h> +#include <search.h> +#include <linux/ctype.h> + +#define BS systab.boottime +#define RT systab.runtime + +/** + * efi_get_device_handle_info() - get information of UEFI device + * + * @handle: Handle of UEFI device + * @dev_path_text: Pointer to text of device path + * Return: 0 on success, -1 on failure + * + * Currently return a formatted text of device path. + */ +static int efi_get_device_handle_info(efi_handle_t handle, u16 **dev_path_text) +{ + struct efi_device_path *dp; + efi_status_t ret; + + ret = EFI_CALL(BS->open_protocol(handle, &efi_guid_device_path, + (void **)&dp, NULL /* FIXME */, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL)); + if (ret == EFI_SUCCESS) { + *dev_path_text = efi_dp_str(dp); + return 0; + } else { + return -1; + } +} + +#define EFI_HANDLE_WIDTH ((int)sizeof(efi_handle_t) * 2) + +static const char spc[] = " "; +static const char sep[] = "================"; + +/** + * do_efi_show_devices() - show UEFI devices + * + * @cmdtp: Command table + * @flag: Command flag + * @argc: Number of arguments + * @argv: Argument array + * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure + * + * Implement efidebug "devices" sub-command. + * Show all UEFI devices and their information. + */ +static int do_efi_show_devices(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + efi_handle_t *handles; + efi_uintn_t num, i; + u16 *dev_path_text; + efi_status_t ret; + + ret = EFI_CALL(BS->locate_handle_buffer(ALL_HANDLES, NULL, NULL, + &num, &handles)); + if (ret != EFI_SUCCESS) + return CMD_RET_FAILURE; + + if (!num) + return CMD_RET_SUCCESS; + + printf("Device%.*s Device Path\n", EFI_HANDLE_WIDTH - 6, spc); + printf("%.*s ====================\n", EFI_HANDLE_WIDTH, sep); + for (i = 0; i < num; i++) { + if (!efi_get_device_handle_info(handles[i], &dev_path_text)) { + printf("%p %ls\n", handles[i], dev_path_text); + efi_free_pool(dev_path_text); + } + } + + EFI_CALL(BS->free_pool(handles)); + + return CMD_RET_SUCCESS; +} + +/** + * efi_get_driver_handle_info() - get information of UEFI driver + * + * @handle: Handle of UEFI device + * @driver_name: Driver name + * @image_path: Pointer to text of device path + * Return: 0 on success, -1 on failure + * + * Currently return no useful information as all UEFI drivers are + * built-in.. + */ +static int efi_get_driver_handle_info(efi_handle_t handle, u16 **driver_name, + u16 **image_path) +{ + struct efi_handler *handler; + struct efi_loaded_image *image; + efi_status_t ret; + + /* + * driver name + * TODO: support EFI_COMPONENT_NAME2_PROTOCOL + */ + *driver_name = NULL; + + /* image name */ + ret = efi_search_protocol(handle, &efi_guid_loaded_image, &handler); + if (ret != EFI_SUCCESS) { + *image_path = NULL; + return 0; + } + + image = handler->protocol_interface; + *image_path = efi_dp_str(image->file_path); + + return 0; +} + +/** + * do_efi_show_drivers() - show UEFI drivers + * + * @cmdtp: Command table + * @flag: Command flag + * @argc: Number of arguments + * @argv: Argument array + * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure + * + * Implement efidebug "drivers" sub-command. + * Show all UEFI drivers and their information. + */ +static int do_efi_show_drivers(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + efi_handle_t *handles; + efi_uintn_t num, i; + u16 *driver_name, *image_path_text; + efi_status_t ret; + + ret = EFI_CALL(BS->locate_handle_buffer( + BY_PROTOCOL, &efi_guid_driver_binding_protocol, + NULL, &num, &handles)); + if (ret != EFI_SUCCESS) + return CMD_RET_FAILURE; + + if (!num) + return CMD_RET_SUCCESS; + + printf("Driver%.*s Name Image Path\n", + EFI_HANDLE_WIDTH - 6, spc); + printf("%.*s ==================== ====================\n", + EFI_HANDLE_WIDTH, sep); + for (i = 0; i < num; i++) { + if (!efi_get_driver_handle_info(handles[i], &driver_name, + &image_path_text)) { + if (image_path_text) + printf("%p %-20ls %ls\n", handles[i], + driver_name, image_path_text); + else + printf("%p %-20ls <built-in>\n", + handles[i], driver_name); + EFI_CALL(BS->free_pool(driver_name)); + EFI_CALL(BS->free_pool(image_path_text)); + } + } + + EFI_CALL(BS->free_pool(handles)); + + return CMD_RET_SUCCESS; +} + +static const struct { + const char *text; + const efi_guid_t guid; +} guid_list[] = { + { + "Device Path", + DEVICE_PATH_GUID, + }, + { + "Device Path To Text", + EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID, + }, + { + "Device Path Utilities", + EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID, + }, + { + "Unicode Collation 2", + EFI_UNICODE_COLLATION_PROTOCOL2_GUID, + }, + { + "Driver Binding", + EFI_DRIVER_BINDING_PROTOCOL_GUID, + }, + { + "Simple Text Input", + EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID, + }, + { + "Simple Text Input Ex", + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID, + }, + { + "Simple Text Output", + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID, + }, + { + "Block IO", + BLOCK_IO_GUID, + }, + { + "Simple File System", + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID, + }, + { + "Loaded Image", + LOADED_IMAGE_PROTOCOL_GUID, + }, + { + "GOP", + EFI_GOP_GUID, + }, +}; + +/** + * get_guid_text - get string of protocol guid + * @guid: Protocol guid + * Return: String + * + * Return string for display to represent the protocol. + */ +static const char *get_guid_text(const efi_guid_t *guid) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(guid_list); i++) + if (!guidcmp(&guid_list[i].guid, guid)) + break; + + if (i != ARRAY_SIZE(guid_list)) + return guid_list[i].text; + else + return NULL; +} + +/** + * do_efi_show_handles() - show UEFI handles + * + * @cmdtp: Command table + * @flag: Command flag + * @argc: Number of arguments + * @argv: Argument array + * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure + * + * Implement efidebug "dh" sub-command. + * Show all UEFI handles and their information, currently all protocols + * added to handle. + */ +static int do_efi_show_handles(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + efi_handle_t *handles; + efi_guid_t **guid; + efi_uintn_t num, count, i, j; + const char *guid_text; + efi_status_t ret; + + ret = EFI_CALL(BS->locate_handle_buffer(ALL_HANDLES, NULL, NULL, + &num, &handles)); + if (ret != EFI_SUCCESS) + return CMD_RET_FAILURE; + + if (!num) + return CMD_RET_SUCCESS; + + printf("Handle%.*s Protocols\n", EFI_HANDLE_WIDTH - 6, spc); + printf("%.*s ====================\n", EFI_HANDLE_WIDTH, sep); + for (i = 0; i < num; i++) { + printf("%p", handles[i]); + ret = EFI_CALL(BS->protocols_per_handle(handles[i], &guid, + &count)); + if (ret || !count) { + putc('\n'); + continue; + } + + for (j = 0; j < count; j++) { + if (j) + printf(", "); + else + putc(' '); + + guid_text = get_guid_text(guid[j]); + if (guid_text) + puts(guid_text); + else + printf("%pUl", guid[j]); + } + putc('\n'); + } + + EFI_CALL(BS->free_pool(handles)); + + return CMD_RET_SUCCESS; +} + +/** + * do_efi_show_images() - show UEFI images + * + * @cmdtp: Command table + * @flag: Command flag + * @argc: Number of arguments + * @argv: Argument array + * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure + * + * Implement efidebug "images" sub-command. + * Show all UEFI loaded images and their information. + */ +static int do_efi_show_images(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + efi_print_image_infos(NULL); + + return CMD_RET_SUCCESS; +} + +static const char * const efi_mem_type_string[] = { + [EFI_RESERVED_MEMORY_TYPE] = "RESERVED", + [EFI_LOADER_CODE] = "LOADER CODE", + [EFI_LOADER_DATA] = "LOADER DATA", + [EFI_BOOT_SERVICES_CODE] = "BOOT CODE", + [EFI_BOOT_SERVICES_DATA] = "BOOT DATA", + [EFI_RUNTIME_SERVICES_CODE] = "RUNTIME CODE", + [EFI_RUNTIME_SERVICES_DATA] = "RUNTIME DATA", + [EFI_CONVENTIONAL_MEMORY] = "CONVENTIONAL", + [EFI_UNUSABLE_MEMORY] = "UNUSABLE MEM", + [EFI_ACPI_RECLAIM_MEMORY] = "ACPI RECLAIM MEM", + [EFI_ACPI_MEMORY_NVS] = "ACPI NVS", + [EFI_MMAP_IO] = "IO", + [EFI_MMAP_IO_PORT] = "IO PORT", + [EFI_PAL_CODE] = "PAL", +}; + +static const struct efi_mem_attrs { + const u64 bit; + const char *text; +} efi_mem_attrs[] = { + {EFI_MEMORY_UC, "UC"}, + {EFI_MEMORY_UC, "UC"}, + {EFI_MEMORY_WC, "WC"}, + {EFI_MEMORY_WT, "WT"}, + {EFI_MEMORY_WB, "WB"}, + {EFI_MEMORY_UCE, "UCE"}, + {EFI_MEMORY_WP, "WP"}, + {EFI_MEMORY_RP, "RP"}, + {EFI_MEMORY_XP, "WP"}, + {EFI_MEMORY_NV, "NV"}, + {EFI_MEMORY_MORE_RELIABLE, "REL"}, + {EFI_MEMORY_RO, "RO"}, + {EFI_MEMORY_RUNTIME, "RT"}, +}; + +/** + * print_memory_attributes() - print memory map attributes + * @attributes: Attribute value + * + * Print memory map attributes + */ +static void print_memory_attributes(u64 attributes) +{ + int sep, i; + + for (sep = 0, i = 0; i < ARRAY_SIZE(efi_mem_attrs); i++) + if (attributes & efi_mem_attrs[i].bit) { + if (sep) { + putc('|'); + } else { + putc(' '); + sep = 1; + } + puts(efi_mem_attrs[i].text); + } +} + +#define EFI_PHYS_ADDR_WIDTH (int)(sizeof(efi_physical_addr_t) * 2) + +/** + * do_efi_show_memmap() - show UEFI memory map + * + * @cmdtp: Command table + * @flag: Command flag + * @argc: Number of arguments + * @argv: Argument array + * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure + * + * Implement efidebug "memmap" sub-command. + * Show UEFI memory map. + */ +static int do_efi_show_memmap(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + struct efi_mem_desc *memmap = NULL, *map; + efi_uintn_t map_size = 0; + const char *type; + int i; + efi_status_t ret; + + ret = EFI_CALL(BS->get_memory_map(&map_size, memmap, NULL, NULL, NULL)); + if (ret == EFI_BUFFER_TOO_SMALL) { + map_size += sizeof(struct efi_mem_desc); /* for my own */ + ret = EFI_CALL(BS->allocate_pool(EFI_LOADER_DATA, + map_size, (void *)&memmap)); + if (ret != EFI_SUCCESS) + return CMD_RET_FAILURE; + ret = EFI_CALL(BS->get_memory_map(&map_size, memmap, + NULL, NULL, NULL)); + } + if (ret != EFI_SUCCESS) { + EFI_CALL(BS->free_pool(memmap)); + return CMD_RET_FAILURE; + } + + printf("Type Start%.*s End%.*s Attributes\n", + EFI_PHYS_ADDR_WIDTH - 5, spc, EFI_PHYS_ADDR_WIDTH - 3, spc); + printf("================ %.*s %.*s ==========\n", + EFI_PHYS_ADDR_WIDTH, sep, EFI_PHYS_ADDR_WIDTH, sep); + for (i = 0, map = memmap; i < map_size / sizeof(*map); map++, i++) { + if (map->type < EFI_MAX_MEMORY_TYPE) + type = efi_mem_type_string[map->type]; + else + type = "(unknown)"; + + printf("%-16s %.*llx-%.*llx", type, + EFI_PHYS_ADDR_WIDTH, + map->physical_start, + EFI_PHYS_ADDR_WIDTH, + map->physical_start + map->num_pages * EFI_PAGE_SIZE); + + print_memory_attributes(map->attribute); + putc('\n'); + } + + EFI_CALL(BS->free_pool(memmap)); + + return CMD_RET_SUCCESS; +} + +/** + * do_efi_boot_add() - set UEFI load option + * + * @cmdtp: Command table + * @flag: Command flag + * @argc: Number of arguments + * @argv: Argument array + * Return: CMD_RET_SUCCESS on success, + * CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure + * + * Implement efidebug "boot add" sub-command. + * Create or change UEFI load option. + * - boot add <id> <label> <interface> <devnum>[:<part>] <file> <options> + */ +static int do_efi_boot_add(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + int id; + char *endp; + char var_name[9]; + u16 var_name16[9], *p; + efi_guid_t guid; + size_t label_len, label_len16; + u16 *label; + struct efi_device_path *device_path = NULL, *file_path = NULL; + struct efi_load_option lo; + void *data = NULL; + efi_uintn_t size; + int ret; + + if (argc < 6 || argc > 7) + return CMD_RET_USAGE; + + id = (int)simple_strtoul(argv[1], &endp, 16); + if (*endp != '\0' || id > 0xffff) + return CMD_RET_FAILURE; + + sprintf(var_name, "Boot%04X", id); + p = var_name16; + utf8_utf16_strncpy(&p, var_name, 9); + + guid = efi_global_variable_guid; + + /* attributes */ + lo.attributes = LOAD_OPTION_ACTIVE; /* always ACTIVE */ + + /* label */ + label_len = strlen(argv[2]); + label_len16 = utf8_utf16_strnlen(argv[2], label_len); + label = malloc((label_len16 + 1) * sizeof(u16)); + if (!label) + return CMD_RET_FAILURE; + lo.label = label; /* label will be changed below */ + utf8_utf16_strncpy(&label, argv[2], label_len); + + /* file path */ + ret = efi_dp_from_name(argv[3], argv[4], argv[5], &device_path, + &file_path); + if (ret != EFI_SUCCESS) { + printf("Cannot create device path for \"%s %s\"\n", + argv[3], argv[4]); + ret = CMD_RET_FAILURE; + goto out; + } + lo.file_path = file_path; + lo.file_path_length = efi_dp_size(file_path) + + sizeof(struct efi_device_path); /* for END */ + + /* optional data */ + lo.optional_data = (u8 *)(argc == 6 ? "" : argv[6]); + + size = efi_serialize_load_option(&lo, (u8 **)&data); + if (!size) { + ret = CMD_RET_FAILURE; + goto out; + } + + ret = EFI_CALL(RT->set_variable(var_name16, &guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + size, data)); + ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE); +out: + free(data); + efi_free_pool(device_path); + efi_free_pool(file_path); + free(lo.label); + + return ret; +} + +/** + * do_efi_boot_rm() - delete UEFI load options + * + * @cmdtp: Command table + * @flag: Command flag + * @argc: Number of arguments + * @argv: Argument array + * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure + * + * Implement efidebug "boot rm" sub-command. + * Delete UEFI load options. + * - boot rm <id> ... + */ +static int do_efi_boot_rm(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + efi_guid_t guid; + int id, i; + char *endp; + char var_name[9]; + u16 var_name16[9]; + efi_status_t ret; + + if (argc == 1) + return CMD_RET_USAGE; + + guid = efi_global_variable_guid; + for (i = 1; i < argc; i++, argv++) { + id = (int)simple_strtoul(argv[1], &endp, 16); + if (*endp != '\0' || id > 0xffff) + return CMD_RET_FAILURE; + + sprintf(var_name, "Boot%04X", id); + utf8_utf16_strncpy((u16 **)&var_name16, var_name, 9); + + ret = EFI_CALL(RT->set_variable(var_name16, &guid, 0, 0, NULL)); + if (ret) { + printf("cannot remove Boot%04X", id); + return CMD_RET_FAILURE; + } + } + + return CMD_RET_SUCCESS; +} + +/** + * show_efi_boot_opt_data() - dump UEFI load option + * + * @id: Load option number + * @data: Value of UEFI load option variable + * + * Decode the value of UEFI load option variable and print information. + */ +static void show_efi_boot_opt_data(int id, void *data) +{ + struct efi_load_option lo; + char *label, *p; + size_t label_len16, label_len; + u16 *dp_str; + + efi_deserialize_load_option(&lo, data); + + label_len16 = u16_strlen(lo.label); + label_len = utf16_utf8_strnlen(lo.label, label_len16); + label = malloc(label_len + 1); + if (!label) + return; + p = label; + utf16_utf8_strncpy(&p, lo.label, label_len16); + + printf("Boot%04X:\n", id); + printf("\tattributes: %c%c%c (0x%08x)\n", + /* ACTIVE */ + lo.attributes & LOAD_OPTION_ACTIVE ? 'A' : '-', + /* FORCE RECONNECT */ + lo.attributes & LOAD_OPTION_FORCE_RECONNECT ? 'R' : '-', + /* HIDDEN */ + lo.attributes & LOAD_OPTION_HIDDEN ? 'H' : '-', + lo.attributes); + printf("\tlabel: %s\n", label); + + dp_str = efi_dp_str(lo.file_path); + printf("\tfile_path: %ls\n", dp_str); + efi_free_pool(dp_str); + + printf("\tdata: %s\n", lo.optional_data); + + free(label); +} + +/** + * show_efi_boot_opt() - dump UEFI load option + * + * @id: Load option number + * + * Dump information defined by UEFI load option. + */ +static void show_efi_boot_opt(int id) +{ + char var_name[9]; + u16 var_name16[9], *p; + efi_guid_t guid; + void *data = NULL; + efi_uintn_t size; + int ret; + + sprintf(var_name, "Boot%04X", id); + p = var_name16; + utf8_utf16_strncpy(&p, var_name, 9); + guid = efi_global_variable_guid; + + size = 0; + ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size, NULL)); + if (ret == (int)EFI_BUFFER_TOO_SMALL) { + data = malloc(size); + ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size, + data)); + } + if (ret == EFI_SUCCESS) + show_efi_boot_opt_data(id, data); + else if (ret == EFI_NOT_FOUND) + printf("Boot%04X: not found\n", id); + + free(data); +} + +/** + * show_efi_boot_dump() - dump all UEFI load options + * + * @cmdtp: Command table + * @flag: Command flag + * @argc: Number of arguments + * @argv: Argument array + * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure + * + * Implement efidebug "boot dump" sub-command. + * Dump information of all UEFI load options defined. + * - boot dump + */ +static int do_efi_boot_dump(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + char regex[256]; + char * const regexlist[] = {regex}; + char *variables = NULL, *boot, *value; + int len; + int id; + + if (argc > 1) + return CMD_RET_USAGE; + + snprintf(regex, 256, "efi_.*-.*-.*-.*-.*_Boot[0-9A-F]+"); + + /* TODO: use GetNextVariableName? */ + len = hexport_r(&env_htab, '\n', H_MATCH_REGEX | H_MATCH_KEY, + &variables, 0, 1, regexlist); + + if (!len) + return CMD_RET_SUCCESS; + + if (len < 0) + return CMD_RET_FAILURE; + + boot = variables; + while (*boot) { + value = strstr(boot, "Boot") + 4; + id = (int)simple_strtoul(value, NULL, 16); + show_efi_boot_opt(id); + boot = strchr(boot, '\n'); + if (!*boot) + break; + boot++; + } + free(variables); + + return CMD_RET_SUCCESS; +} + +/** + * show_efi_boot_order() - show order of UEFI load options + * + * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure + * + * Show order of UEFI load options defined by BootOrder variable. + */ +static int show_efi_boot_order(void) +{ + efi_guid_t guid; + u16 *bootorder = NULL; + efi_uintn_t size; + int num, i; + char var_name[9]; + u16 var_name16[9], *p16; + void *data; + struct efi_load_option lo; + char *label, *p; + size_t label_len16, label_len; + efi_status_t ret; + + guid = efi_global_variable_guid; + size = 0; + ret = EFI_CALL(RT->get_variable(L"BootOrder", &guid, NULL, &size, + NULL)); + if (ret == EFI_BUFFER_TOO_SMALL) { + bootorder = malloc(size); + ret = EFI_CALL(RT->get_variable(L"BootOrder", &guid, NULL, + &size, bootorder)); + } + if (ret == EFI_NOT_FOUND) { + printf("BootOrder not defined\n"); + ret = CMD_RET_SUCCESS; + goto out; + } else if (ret != EFI_SUCCESS) { + ret = CMD_RET_FAILURE; + goto out; + } + + num = size / sizeof(u16); + for (i = 0; i < num; i++) { + sprintf(var_name, "Boot%04X", bootorder[i]); + p16 = var_name16; + utf8_utf16_strncpy(&p16, var_name, 9); + + size = 0; + ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size, + NULL)); + if (ret != EFI_BUFFER_TOO_SMALL) { + printf("%2d: Boot%04X: (not defined)\n", + i + 1, bootorder[i]); + continue; + } + + data = malloc(size); + if (!data) { + ret = CMD_RET_FAILURE; + goto out; + } + ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size, + data)); + if (ret != EFI_SUCCESS) { + free(data); + ret = CMD_RET_FAILURE; + goto out; + } + + efi_deserialize_load_option(&lo, data); + + label_len16 = u16_strlen(lo.label); + label_len = utf16_utf8_strnlen(lo.label, label_len16); + label = malloc(label_len + 1); + if (!label) { + free(data); + ret = CMD_RET_FAILURE; + goto out; + } + p = label; + utf16_utf8_strncpy(&p, lo.label, label_len16); + printf("%2d: Boot%04X: %s\n", i + 1, bootorder[i], label); + free(label); + + free(data); + } +out: + free(bootorder); + + return ret; +} + +/** + * do_efi_boot_next() - manage UEFI BootNext variable + * + * @cmdtp: Command table + * @flag: Command flag + * @argc: Number of arguments + * @argv: Argument array + * Return: CMD_RET_SUCCESS on success, + * CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure + * + * Implement efidebug "boot next" sub-command. + * Set BootNext variable. + * - boot next <id> + */ +static int do_efi_boot_next(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + u16 bootnext; + efi_uintn_t size; + char *endp; + efi_guid_t guid; + efi_status_t ret; + + if (argc != 2) + return CMD_RET_USAGE; + + bootnext = (u16)simple_strtoul(argv[1], &endp, 16); + if (*endp != '\0' || bootnext > 0xffff) { + printf("invalid value: %s\n", argv[1]); + ret = CMD_RET_FAILURE; + goto out; + } + + guid = efi_global_variable_guid; + size = sizeof(u16); + ret = EFI_CALL(RT->set_variable(L"BootNext", &guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + size, &bootnext)); + ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE); +out: + return ret; +} + +/** + * do_efi_boot_order() - manage UEFI BootOrder variable + * + * @cmdtp: Command table + * @flag: Command flag + * @argc: Number of arguments + * @argv: Argument array + * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure + * + * Implement efidebug "boot order" sub-command. + * Show order of UEFI load options, or change it in BootOrder variable. + * - boot order [<id> ...] + */ +static int do_efi_boot_order(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + u16 *bootorder = NULL; + efi_uintn_t size; + int id, i; + char *endp; + efi_guid_t guid; + efi_status_t ret; + + if (argc == 1) + return show_efi_boot_order(); + + argc--; + argv++; + + size = argc * sizeof(u16); + bootorder = malloc(size); + if (!bootorder) + return CMD_RET_FAILURE; + + for (i = 0; i < argc; i++) { + id = (int)simple_strtoul(argv[i], &endp, 16); + if (*endp != '\0' || id > 0xffff) { + printf("invalid value: %s\n", argv[i]); + ret = CMD_RET_FAILURE; + goto out; + } + + bootorder[i] = (u16)id; + } + + guid = efi_global_variable_guid; + ret = EFI_CALL(RT->set_variable(L"BootOrder", &guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + size, bootorder)); + ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE); +out: + free(bootorder); + + return ret; +} + +static cmd_tbl_t cmd_efidebug_boot_sub[] = { + U_BOOT_CMD_MKENT(add, CONFIG_SYS_MAXARGS, 1, do_efi_boot_add, "", ""), + U_BOOT_CMD_MKENT(rm, CONFIG_SYS_MAXARGS, 1, do_efi_boot_rm, "", ""), + U_BOOT_CMD_MKENT(dump, CONFIG_SYS_MAXARGS, 1, do_efi_boot_dump, "", ""), + U_BOOT_CMD_MKENT(next, CONFIG_SYS_MAXARGS, 1, do_efi_boot_next, "", ""), + U_BOOT_CMD_MKENT(order, CONFIG_SYS_MAXARGS, 1, do_efi_boot_order, + "", ""), +}; + +/** + * do_efi_boot_opt() - manage UEFI load options + * + * @cmdtp: Command table + * @flag: Command flag + * @argc: Number of arguments + * @argv: Argument array + * Return: CMD_RET_SUCCESS on success, + * CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure + * + * Implement efidebug "boot" sub-command. + * See above for details of sub-commands. + */ +static int do_efi_boot_opt(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + cmd_tbl_t *cp; + + if (argc < 2) + return CMD_RET_USAGE; + + argc--; argv++; + + cp = find_cmd_tbl(argv[0], cmd_efidebug_boot_sub, + ARRAY_SIZE(cmd_efidebug_boot_sub)); + if (!cp) + return CMD_RET_USAGE; + + return cp->cmd(cmdtp, flag, argc, argv); +} + +static cmd_tbl_t cmd_efidebug_sub[] = { + U_BOOT_CMD_MKENT(boot, CONFIG_SYS_MAXARGS, 1, do_efi_boot_opt, "", ""), + U_BOOT_CMD_MKENT(devices, CONFIG_SYS_MAXARGS, 1, do_efi_show_devices, + "", ""), + U_BOOT_CMD_MKENT(drivers, CONFIG_SYS_MAXARGS, 1, do_efi_show_drivers, + "", ""), + U_BOOT_CMD_MKENT(dh, CONFIG_SYS_MAXARGS, 1, do_efi_show_handles, + "", ""), + U_BOOT_CMD_MKENT(images, CONFIG_SYS_MAXARGS, 1, do_efi_show_images, + "", ""), + U_BOOT_CMD_MKENT(memmap, CONFIG_SYS_MAXARGS, 1, do_efi_show_memmap, + "", ""), +}; + +/** + * do_efidebug() - display and configure UEFI environment + * + * @cmdtp: Command table + * @flag: Command flag + * @argc: Number of arguments + * @argv: Argument array + * Return: CMD_RET_SUCCESS on success, + * CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure + * + * Implement efidebug command which allows us to display and + * configure UEFI environment. + * See above for details of sub-commands. + */ +static int do_efidebug(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + cmd_tbl_t *cp; + efi_status_t r; + + if (argc < 2) + return CMD_RET_USAGE; + + argc--; argv++; + + /* Initialize UEFI drivers */ + r = efi_init_obj_list(); + if (r != EFI_SUCCESS) { + printf("Error: Cannot initialize UEFI sub-system, r = %lu\n", + r & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + cp = find_cmd_tbl(argv[0], cmd_efidebug_sub, + ARRAY_SIZE(cmd_efidebug_sub)); + if (!cp) + return CMD_RET_USAGE; + + return cp->cmd(cmdtp, flag, argc, argv); +} + +#ifdef CONFIG_SYS_LONGHELP +static char efidebug_help_text[] = + " - UEFI Shell-like interface to configure UEFI environment\n" + "\n" + "efidebug boot add <bootid> <label> <interface> <devnum>[:<part>] <file path> [<load options>]\n" + " - set UEFI BootXXXX variable\n" + " <load options> will be passed to UEFI application\n" + "efidebug boot rm <bootid#1> [<bootid#2> [<bootid#3> [...]]]\n" + " - delete UEFI BootXXXX variables\n" + "efidebug boot dump\n" + " - dump all UEFI BootXXXX variables\n" + "efidebug boot next <bootid>\n" + " - set UEFI BootNext variable\n" + "efidebug boot order [<bootid#1> [<bootid#2> [<bootid#3> [...]]]]\n" + " - set/show UEFI boot order\n" + "\n" + "efidebug devices\n" + " - show uefi devices\n" + "efidebug drivers\n" + " - show uefi drivers\n" + "efidebug dh\n" + " - show uefi handles\n" + "efidebug images\n" + " - show loaded images\n" + "efidebug memmap\n" + " - show uefi memory map\n"; +#endif + +U_BOOT_CMD( + efidebug, 10, 0, do_efidebug, + "Configure UEFI environment", + efidebug_help_text +); diff --git a/cmd/nvedit.c b/cmd/nvedit.c index ebaa16b754..24a6cf7824 100644 --- a/cmd/nvedit.c +++ b/cmd/nvedit.c @@ -119,6 +119,11 @@ static int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc, int rcode = 0; int env_flag = H_HIDE_DOT; +#if defined(CONFIG_CMD_NVEDIT_EFI) + if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'e') + return do_env_print_efi(cmdtp, flag, --argc, ++argv); +#endif + if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'a') { argc--; argv++; @@ -216,6 +221,12 @@ static int _do_env_set(int flag, int argc, char * const argv[], int env_flag) ENTRY e, *ep; debug("Initial value for argc=%d\n", argc); + +#if CONFIG_IS_ENABLED(CMD_NVEDIT_EFI) + if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'e') + return do_env_set_efi(NULL, flag, --argc, ++argv); +#endif + while (argc > 1 && **(argv + 1) == '-') { char *arg = *++argv; @@ -1263,12 +1274,18 @@ static char env_help_text[] = "env import [-d] [-t [-r] | -b | -c] addr [size] [var ...] - import environment\n" #endif "env print [-a | name ...] - print environment\n" +#if defined(CONFIG_CMD_NVEDIT_EFI) + "env print -e [name ...] - print UEFI environment\n" +#endif #if defined(CONFIG_CMD_RUN) "env run var [...] - run commands in an environment variable\n" #endif #if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE) "env save - save environment\n" #endif +#if defined(CONFIG_CMD_NVEDIT_EFI) + "env set -e name [arg ...] - set UEFI variable; unset if 'arg' not specified\n" +#endif "env set [-f] name [arg ...]\n"; #endif @@ -1295,6 +1312,10 @@ U_BOOT_CMD_COMPLETE( printenv, CONFIG_SYS_MAXARGS, 1, do_env_print, "print environment variables", "[-a]\n - print [all] values of all environment variables\n" +#if defined(CONFIG_CMD_NVEDIT_EFI) + "printenv -e [name ...]\n" + " - print UEFI variable 'name' or all the variables\n" +#endif "printenv name ...\n" " - print value of environment variable 'name'", var_complete @@ -1322,7 +1343,12 @@ U_BOOT_CMD_COMPLETE( U_BOOT_CMD_COMPLETE( setenv, CONFIG_SYS_MAXARGS, 0, do_env_set, "set environment variables", - "[-f] name value ...\n" +#if defined(CONFIG_CMD_NVEDIT_EFI) + "-e name [value ...]\n" + " - set UEFI variable 'name' to 'value' ...'\n" + " - delete UEFI variable 'name' if 'value' not specified\n" +#endif + "setenv [-f] name value ...\n" " - [forcibly] set environment variable 'name' to 'value ...'\n" "setenv [-f] name\n" " - [forcibly] delete environment variable 'name'", diff --git a/cmd/nvedit_efi.c b/cmd/nvedit_efi.c new file mode 100644 index 0000000000..ca32566a61 --- /dev/null +++ b/cmd/nvedit_efi.c @@ -0,0 +1,399 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Integrate UEFI variables to u-boot env interface + * + * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited + */ + +#include <charset.h> +#include <common.h> +#include <command.h> +#include <efi_loader.h> +#include <exports.h> +#include <hexdump.h> +#include <malloc.h> +#include <linux/kernel.h> + +/* + * From efi_variable.c, + * + * Mapping between UEFI variables and u-boot variables: + * + * efi_$guid_$varname = {attributes}(type)value + */ + +static const struct { + u32 mask; + char *text; +} efi_var_attrs[] = { + {EFI_VARIABLE_NON_VOLATILE, "NV"}, + {EFI_VARIABLE_BOOTSERVICE_ACCESS, "BS"}, + {EFI_VARIABLE_RUNTIME_ACCESS, "RT"}, + {EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, "AW"}, + {EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS, "AT"}, +}; + +/** + * efi_dump_single_var() - show information about a UEFI variable + * + * @name: Name of the variable + * @guid: Vendor GUID + * + * Show information encoded in one UEFI variable + */ +static void efi_dump_single_var(u16 *name, efi_guid_t *guid) +{ + u32 attributes; + u8 *data; + efi_uintn_t size; + int count, i; + efi_status_t ret; + + data = NULL; + size = 0; + ret = EFI_CALL(efi_get_variable(name, guid, &attributes, &size, data)); + if (ret == EFI_BUFFER_TOO_SMALL) { + data = malloc(size); + if (!data) + goto out; + + ret = EFI_CALL(efi_get_variable(name, guid, &attributes, &size, + data)); + } + if (ret == EFI_NOT_FOUND) { + printf("Error: \"%ls\" not defined\n", name); + goto out; + } + if (ret != EFI_SUCCESS) + goto out; + + printf("%ls:", name); + for (count = 0, i = 0; i < ARRAY_SIZE(efi_var_attrs); i++) + if (attributes & efi_var_attrs[i].mask) { + if (count) + putc('|'); + else + putc(' '); + count++; + puts(efi_var_attrs[i].text); + } + printf(", DataSize = 0x%zx\n", size); + print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1, data, size, true); + + return; +out: + free(data); +} + +/** + * efi_dump_vars() - show information about named UEFI variables + * + * @argc: Number of arguments (variables) + * @argv: Argument (variable name) array + * Return: CMD_RET_SUCCESS on success, or CMD_RET_RET_FAILURE + * + * Show information encoded in named UEFI variables + */ +static int efi_dump_vars(int argc, char * const argv[]) +{ + u16 *var_name16, *p; + efi_uintn_t buf_size, size; + + buf_size = 128; + var_name16 = malloc(buf_size); + if (!var_name16) + return CMD_RET_FAILURE; + + for (; argc > 0; argc--, argv++) { + size = (utf8_utf16_strlen(argv[0]) + 1) * sizeof(u16); + if (buf_size < size) { + buf_size = size; + p = realloc(var_name16, buf_size); + if (!p) { + free(var_name16); + return CMD_RET_FAILURE; + } + var_name16 = p; + } + + p = var_name16; + utf8_utf16_strcpy(&p, argv[0]); + + efi_dump_single_var(var_name16, + (efi_guid_t *)&efi_global_variable_guid); + } + + free(var_name16); + + return CMD_RET_SUCCESS; +} + +/** + * efi_dump_vars() - show information about all the UEFI variables + * + * Return: CMD_RET_SUCCESS on success, or CMD_RET_RET_FAILURE + * + * Show information encoded in all the UEFI variables + */ +static int efi_dump_var_all(void) +{ + u16 *var_name16, *p; + efi_uintn_t buf_size, size; + efi_guid_t guid; + efi_status_t ret; + + buf_size = 128; + var_name16 = malloc(buf_size); + if (!var_name16) + return CMD_RET_FAILURE; + + var_name16[0] = 0; + for (;;) { + size = buf_size; + ret = EFI_CALL(efi_get_next_variable_name(&size, var_name16, + &guid)); + if (ret == EFI_NOT_FOUND) + break; + if (ret == EFI_BUFFER_TOO_SMALL) { + buf_size = size; + p = realloc(var_name16, buf_size); + if (!p) { + free(var_name16); + return CMD_RET_FAILURE; + } + var_name16 = p; + ret = EFI_CALL(efi_get_next_variable_name(&size, + var_name16, + &guid)); + } + if (ret != EFI_SUCCESS) { + free(var_name16); + return CMD_RET_FAILURE; + } + + efi_dump_single_var(var_name16, &guid); + } + + free(var_name16); + + return CMD_RET_SUCCESS; +} + +/** + * do_env_print_efi() - show information about UEFI variables + * + * @cmdtp: Command table + * @flag: Command flag + * @argc: Number of arguments + * @argv: Argument array + * Return: CMD_RET_SUCCESS on success, or CMD_RET_RET_FAILURE + * + * This function is for "env print -e" or "printenv -e" command: + * => env print -e [var [...]] + * If one or more variable names are specified, show information + * named UEFI variables, otherwise show all the UEFI variables. + */ +int do_env_print_efi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + efi_status_t ret; + + /* Initialize EFI drivers */ + ret = efi_init_obj_list(); + if (ret != EFI_SUCCESS) { + printf("Error: Cannot initialize UEFI sub-system, r = %lu\n", + ret & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + if (argc > 1) + /* show specified UEFI variables */ + return efi_dump_vars(--argc, ++argv); + + /* enumerate and show all UEFI variables */ + return efi_dump_var_all(); +} + +/** + * append_value() - encode UEFI variable's value + * @bufp: Buffer of encoded UEFI variable's value + * @sizep: Size of buffer + * @data: data to be encoded into the value + * Return: 0 on success, -1 otherwise + * + * Interpret a given data string and append it to buffer. + * Buffer will be realloc'ed if necessary. + * + * Currently supported formats are: + * =0x0123...: Hexadecimal number + * =H0123...: Hexadecimal-byte array + * ="...", =S"..." or <string>: + * String + */ +static int append_value(char **bufp, size_t *sizep, char *data) +{ + char *tmp_buf = NULL, *new_buf = NULL, *value; + unsigned long len = 0; + + if (!strncmp(data, "=0x", 2)) { /* hexadecimal number */ + union { + u8 u8; + u16 u16; + u32 u32; + u64 u64; + } tmp_data; + unsigned long hex_value; + void *hex_ptr; + + data += 3; + len = strlen(data); + if ((len & 0x1)) /* not multiple of two */ + return -1; + + len /= 2; + if (len > 8) + return -1; + else if (len > 4) + len = 8; + else if (len > 2) + len = 4; + + /* convert hex hexadecimal number */ + if (strict_strtoul(data, 16, &hex_value) < 0) + return -1; + + tmp_buf = malloc(len); + if (!tmp_buf) + return -1; + + if (len == 1) { + tmp_data.u8 = hex_value; + hex_ptr = &tmp_data.u8; + } else if (len == 2) { + tmp_data.u16 = hex_value; + hex_ptr = &tmp_data.u16; + } else if (len == 4) { + tmp_data.u32 = hex_value; + hex_ptr = &tmp_data.u32; + } else { + tmp_data.u64 = hex_value; + hex_ptr = &tmp_data.u64; + } + memcpy(tmp_buf, hex_ptr, len); + value = tmp_buf; + + } else if (!strncmp(data, "=H", 2)) { /* hexadecimal-byte array */ + data += 2; + len = strlen(data); + if (len & 0x1) /* not multiple of two */ + return -1; + + len /= 2; + tmp_buf = malloc(len); + if (!tmp_buf) + return -1; + + if (hex2bin((u8 *)tmp_buf, data, len) < 0) + return -1; + + value = tmp_buf; + } else { /* string */ + if (!strncmp(data, "=\"", 2) || !strncmp(data, "=S\"", 3)) { + if (data[1] == '"') + data += 2; + else + data += 3; + value = data; + len = strlen(data) - 1; + if (data[len] != '"') + return -1; + } else { + value = data; + len = strlen(data); + } + } + + new_buf = realloc(*bufp, *sizep + len); + if (!new_buf) + goto out; + + memcpy(new_buf + *sizep, value, len); + *bufp = new_buf; + *sizep += len; + +out: + free(tmp_buf); + + return 0; +} + +/** + * do_env_print_efi() - set UEFI variable + * + * @cmdtp: Command table + * @flag: Command flag + * @argc: Number of arguments + * @argv: Argument array + * Return: CMD_RET_SUCCESS on success, or CMD_RET_RET_FAILURE + * + * This function is for "env set -e" or "setenv -e" command: + * => env set -e var [value ...]] + * Encode values specified and set given UEFI variable. + * If no value is specified, delete the variable. + */ +int do_env_set_efi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + char *var_name, *value = NULL; + efi_uintn_t size = 0; + u16 *var_name16 = NULL, *p; + size_t len; + efi_guid_t guid; + efi_status_t ret; + + if (argc == 1) + return CMD_RET_USAGE; + + /* Initialize EFI drivers */ + ret = efi_init_obj_list(); + if (ret != EFI_SUCCESS) { + printf("Error: Cannot initialize UEFI sub-system, r = %lu\n", + ret & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + var_name = argv[1]; + if (argc == 2) { + /* delete */ + value = NULL; + size = 0; + } else { /* set */ + argc -= 2; + argv += 2; + + for ( ; argc > 0; argc--, argv++) + if (append_value(&value, &size, argv[0]) < 0) { + ret = CMD_RET_FAILURE; + goto out; + } + } + + len = utf8_utf16_strnlen(var_name, strlen(var_name)); + var_name16 = malloc((len + 1) * 2); + if (!var_name16) { + ret = CMD_RET_FAILURE; + goto out; + } + p = var_name16; + utf8_utf16_strncpy(&p, var_name, len + 1); + + guid = efi_global_variable_guid; + ret = EFI_CALL(efi_set_variable(var_name16, &guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + size, value)); + ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE); +out: + free(value); + free(var_name16); + + return ret; +} diff --git a/common/spl/spl.c b/common/spl/spl.c index 2e2af1b28e..88d4b8a9bf 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -728,6 +728,8 @@ ulong spl_relocate_stack_gd(void) #if defined(CONFIG_SPL_SYS_MALLOC_SIMPLE) && CONFIG_VAL(SYS_MALLOC_F_LEN) if (CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN) { + debug("SPL malloc() before relocation used 0x%lx bytes (%ld KB)\n", + gd->malloc_ptr, gd->malloc_ptr / 1024); ptr -= CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN; gd->malloc_base = ptr; gd->malloc_limit = CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN; diff --git a/configs/alt_defconfig b/configs/alt_defconfig index 44f1e1c51a..c4ece79507 100644 --- a/configs/alt_defconfig +++ b/configs/alt_defconfig @@ -50,7 +50,6 @@ CONFIG_CMD_MTDPARTS=y CONFIG_MTDIDS_DEFAULT="nor0=spi0.0" CONFIG_MTDPARTS_DEFAULT="mtdparts=spi0.0:256k(u-boot-spl),512k(u-boot-env1),512k(u-boot-env2),768k(u-boot),-(user)" CONFIG_OF_CONTROL=y -CONFIG_OF_EMBED=y CONFIG_DEFAULT_DEVICE_TREE="r8a7794-alt-u-boot" CONFIG_ENV_IS_IN_SPI_FLASH=y CONFIG_CLK=y diff --git a/configs/Sinovoip_BPI_M2_Plus_defconfig b/configs/bananapi_m2_plus_h3_defconfig index 597618fb90..597618fb90 100644 --- a/configs/Sinovoip_BPI_M2_Plus_defconfig +++ b/configs/bananapi_m2_plus_h3_defconfig diff --git a/configs/bananapi_m2_plus_h5_defconfig b/configs/bananapi_m2_plus_h5_defconfig new file mode 100644 index 0000000000..e7c10dbdf2 --- /dev/null +++ b/configs/bananapi_m2_plus_h5_defconfig @@ -0,0 +1,20 @@ +CONFIG_ARM=y +CONFIG_ARCH_SUNXI=y +CONFIG_SPL=y +CONFIG_MACH_SUN50I_H5=y +CONFIG_DRAM_CLK=672 +CONFIG_DRAM_ZQ=3881979 +CONFIG_DRAM_ODT_EN=y +CONFIG_MACPWR="PD6" +CONFIG_MMC_SUNXI_SLOT_EXTRA=2 +CONFIG_NR_DRAM_BANKS=1 +# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +# CONFIG_CMD_FLASH is not set +# CONFIG_SPL_DOS_PARTITION is not set +# CONFIG_SPL_EFI_PARTITION is not set +CONFIG_DEFAULT_DEVICE_TREE="sun50i-h5-bananapi-m2-plus" +CONFIG_SUN8I_EMAC=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_MUSB_GADGET=y +CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE=y diff --git a/configs/blanche_defconfig b/configs/blanche_defconfig index c5042d885f..c2d53a3d11 100644 --- a/configs/blanche_defconfig +++ b/configs/blanche_defconfig @@ -32,7 +32,6 @@ CONFIG_CMD_EXT4=y CONFIG_CMD_EXT4_WRITE=y CONFIG_CMD_FAT=y CONFIG_OF_CONTROL=y -CONFIG_OF_EMBED=y CONFIG_DEFAULT_DEVICE_TREE="r8a7792-blanche-u-boot" CONFIG_ENV_IS_IN_FLASH=y CONFIG_ENV_IS_IN_SPI_FLASH=y diff --git a/configs/gose_defconfig b/configs/gose_defconfig index a5afb3c569..39e4cfdfc2 100644 --- a/configs/gose_defconfig +++ b/configs/gose_defconfig @@ -50,7 +50,6 @@ CONFIG_CMD_MTDPARTS=y CONFIG_MTDIDS_DEFAULT="nor0=spi0.0" CONFIG_MTDPARTS_DEFAULT="mtdparts=spi0.0:256k(u-boot-spl),512k(u-boot-env1),512k(u-boot-env2),768k(u-boot),-(user)" CONFIG_OF_CONTROL=y -CONFIG_OF_EMBED=y CONFIG_DEFAULT_DEVICE_TREE="r8a7793-gose-u-boot" CONFIG_ENV_IS_IN_SPI_FLASH=y CONFIG_CLK=y diff --git a/configs/koelsch_defconfig b/configs/koelsch_defconfig index 1ff14ac4ab..75beab4cce 100644 --- a/configs/koelsch_defconfig +++ b/configs/koelsch_defconfig @@ -50,7 +50,6 @@ CONFIG_CMD_MTDPARTS=y CONFIG_MTDIDS_DEFAULT="nor0=spi0.0" CONFIG_MTDPARTS_DEFAULT="mtdparts=spi0.0:256k(u-boot-spl),512k(u-boot-env1),512k(u-boot-env2),768k(u-boot),-(user)" CONFIG_OF_CONTROL=y -CONFIG_OF_EMBED=y CONFIG_DEFAULT_DEVICE_TREE="r8a7791-koelsch-u-boot" CONFIG_ENV_IS_IN_SPI_FLASH=y CONFIG_CLK=y diff --git a/configs/lager_defconfig b/configs/lager_defconfig index d924d76911..686aa2c171 100644 --- a/configs/lager_defconfig +++ b/configs/lager_defconfig @@ -50,7 +50,6 @@ CONFIG_CMD_MTDPARTS=y CONFIG_MTDIDS_DEFAULT="nor0=spi0.0" CONFIG_MTDPARTS_DEFAULT="mtdparts=spi0.0:256k(u-boot-spl),512k(u-boot-env1),512k(u-boot-env2),768k(u-boot),-(user)" CONFIG_OF_CONTROL=y -CONFIG_OF_EMBED=y CONFIG_DEFAULT_DEVICE_TREE="r8a7790-lager-u-boot" CONFIG_ENV_IS_IN_SPI_FLASH=y CONFIG_CLK=y diff --git a/configs/porter_defconfig b/configs/porter_defconfig index 7c54a54638..ce309b6d86 100644 --- a/configs/porter_defconfig +++ b/configs/porter_defconfig @@ -50,7 +50,6 @@ CONFIG_CMD_MTDPARTS=y CONFIG_MTDIDS_DEFAULT="nor0=spi0.0" CONFIG_MTDPARTS_DEFAULT="mtdparts=spi0.0:256k(u-boot-spl),512k(u-boot-env1),512k(u-boot-env2),768k(u-boot),-(user)" CONFIG_OF_CONTROL=y -CONFIG_OF_EMBED=y CONFIG_DEFAULT_DEVICE_TREE="r8a7791-porter-u-boot" CONFIG_ENV_IS_IN_SPI_FLASH=y CONFIG_CLK=y diff --git a/configs/r8a77965_salvator-x_defconfig b/configs/r8a77965_salvator-x_defconfig index 3580a44d5e..b34fddda1c 100644 --- a/configs/r8a77965_salvator-x_defconfig +++ b/configs/r8a77965_salvator-x_defconfig @@ -3,7 +3,6 @@ CONFIG_ARCH_RMOBILE=y CONFIG_SYS_TEXT_BASE=0x50000000 CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_RCAR_GEN3=y -CONFIG_R8A7796=y CONFIG_TARGET_SALVATOR_X=y CONFIG_SMBIOS_PRODUCT_NAME="" CONFIG_FIT=y diff --git a/configs/r8a7796_salvator-x_defconfig b/configs/r8a7796_salvator-x_defconfig index 9006b9fc3c..6a9c1bdc0c 100644 --- a/configs/r8a7796_salvator-x_defconfig +++ b/configs/r8a7796_salvator-x_defconfig @@ -3,7 +3,6 @@ CONFIG_ARCH_RMOBILE=y CONFIG_SYS_TEXT_BASE=0x50000000 CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_RCAR_GEN3=y -CONFIG_R8A7796=y CONFIG_TARGET_SALVATOR_X=y CONFIG_SMBIOS_PRODUCT_NAME="" CONFIG_FIT=y diff --git a/configs/r8a7796_ulcb_defconfig b/configs/r8a7796_ulcb_defconfig index 37b70b993b..aff4c9cb61 100644 --- a/configs/r8a7796_ulcb_defconfig +++ b/configs/r8a7796_ulcb_defconfig @@ -3,7 +3,6 @@ CONFIG_ARCH_RMOBILE=y CONFIG_SYS_TEXT_BASE=0x50000000 CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_RCAR_GEN3=y -CONFIG_R8A7796=y CONFIG_TARGET_ULCB=y CONFIG_SMBIOS_PRODUCT_NAME="" CONFIG_FIT=y diff --git a/configs/sifive_fu540_defconfig b/configs/sifive_fu540_defconfig new file mode 100644 index 0000000000..2f8cca9de0 --- /dev/null +++ b/configs/sifive_fu540_defconfig @@ -0,0 +1,11 @@ +CONFIG_RISCV=y +CONFIG_TARGET_SIFIVE_FU540=y +CONFIG_RISCV_SMODE=y +CONFIG_ARCH_RV64I=y +CONFIG_DISTRO_DEFAULTS=y +CONFIG_NR_DRAM_BANKS=1 +CONFIG_FIT=y +CONFIG_DISPLAY_CPUINFO=y +CONFIG_DISPLAY_BOARDINFO=y +CONFIG_CMD_MII=y +CONFIG_OF_PRIOR_STAGE=y diff --git a/configs/silk_defconfig b/configs/silk_defconfig index 3cb4f6e005..0291a7c981 100644 --- a/configs/silk_defconfig +++ b/configs/silk_defconfig @@ -50,7 +50,6 @@ CONFIG_CMD_MTDPARTS=y CONFIG_MTDIDS_DEFAULT="nor0=spi0.0" CONFIG_MTDPARTS_DEFAULT="mtdparts=spi0.0:256k(u-boot-spl),512k(u-boot-env1),512k(u-boot-env2),768k(u-boot),-(user)" CONFIG_OF_CONTROL=y -CONFIG_OF_EMBED=y CONFIG_DEFAULT_DEVICE_TREE="r8a7794-silk-u-boot" CONFIG_ENV_IS_IN_SPI_FLASH=y CONFIG_CLK=y diff --git a/configs/stout_defconfig b/configs/stout_defconfig index 1b1ed8d3ac..1c92cb6117 100644 --- a/configs/stout_defconfig +++ b/configs/stout_defconfig @@ -50,7 +50,6 @@ CONFIG_CMD_MTDPARTS=y CONFIG_MTDIDS_DEFAULT="nor0=spi0.0" CONFIG_MTDPARTS_DEFAULT="mtdparts=spi0.0:256k(u-boot-spl),512k(u-boot-env1),512k(u-boot-env2),768k(u-boot),-(user)" CONFIG_OF_CONTROL=y -CONFIG_OF_EMBED=y CONFIG_DEFAULT_DEVICE_TREE="r8a7790-stout-u-boot" CONFIG_ENV_IS_IN_SPI_FLASH=y CONFIG_CLK=y diff --git a/doc/README.sifive-fu540 b/doc/README.sifive-fu540 new file mode 100644 index 0000000000..fd9f2a8e46 --- /dev/null +++ b/doc/README.sifive-fu540 @@ -0,0 +1,303 @@ +FU540-C000 RISC-V SoC +===================== +The FU540-C000 is the world’s first 4+1 64-bit RISC‑V SoC from SiFive. + +The HiFive Unleashed development platform is based on FU540-C000 and capable +of running Linux. + +Mainline support +================ +The support for following drivers are already enabled: +1. SiFive UART Driver. +2. SiFive PRCI Driver for clock. +3. Cadence MACB ethernet driver for networking support. + +TODO: +1. SPI driver is still missing. So MMC card can't be used in U-Boot as of now. +2. U-Boot expects the serial console device entry to be present under /chosen + DT node. Example: + chosen { + stdout-path = "/soc/serial@10010000:115200"; + }; + + Without a serial console U-Boot will panic. + +Building +======== +1. Add the RISC-V toolchain to your PATH. +2. Setup ARCH & cross compilation enviornment variable. + a. export ARCH=riscv + b. export CROSS_COMPILE=<riscv64 toolchain prefix> +3. make sifive_fu540_defconfig +4. make + +Flashing +======== +The current U-Boot port is supported in S-mode only and loaded from DRAM. + +A prior stage (M-mode) firmware/bootloader (e.g OpenSBI or BBL) is required to +load the u-boot.bin into memory and provide runtime services. The u-boot.bin +can be given as a payload to the prior stage (M-mode) firmware/bootloader. + +The description of steps required to build the firmware is beyond the scope of +this document. Please refer OpenSBI or BBL documenation. +(Note: OpenSBI git repo is at https://github.com/riscv/opensbi.git) +(Note: BBL git repo is at https://github.com/riscv/riscv-pk.git) + +Once the prior stage firmware/bootloader binary is generated, it should be +copied to the first partition of the sdcard. + +sudo dd if=<prior_stage_firmware_binary> of=/dev/disk2s1 bs=1024 + +Booting +======= +Once you plugin the sdcard and power up, you should see the U-Boot prompt. + +Sample boot log from HiFive Unleashed board +=========================================== +U-Boot 2019.01-00019-gc7953536-dirty (Jan 22 2019 - 11:05:40 -0800) + +CPU: rv64imafdc +Model: sifive,hifive-unleashed-a00 +DRAM: 8 GiB +In: serial@10010000 +Out: serial@10010000 +Err: serial@10010000 +Net: +Warning: ethernet@10090000 (eth0) using random MAC address - b6:75:4d:48:50:94 +eth0: ethernet@10090000 +Hit any key to stop autoboot: 0 +=> version +U-Boot 2019.01-00019-gc7953536-dirty (Jan 22 2019 - 11:05:40 -0800) + +riscv64-linux-gcc.br_real (Buildroot 2018.11-rc2-00003-ga0787e9) 8.2.0 +GNU ld (GNU Binutils) 2.31.1 +=> +=============================================================================== + +Now you can configure your networking, tftp server and use tftp boot method to +load uImage. + +========================================================================== +=> setenv ethaddr 70:B3:D5:92:F0:C2 +=> setenv ipaddr 10.196.157.189 +=> setenv serverip 10.11.143.218 +=> setenv gatewayip 10.196.156.1 +=> setenv netmask 255.255.252.0 +=> bdinfo +boot_params = 0x0000000000000000 +DRAM bank = 0x0000000000000000 +-> start = 0x0000000080000000 +-> size = 0x0000000200000000 +relocaddr = 0x00000000fff90000 +reloc off = 0x000000007fd90000 +ethaddr = 70:B3:D5:92:F0:C2 +IP addr = 10.196.157.189 +baudrate = 115200 bps +=> tftpboot uImage +ethernet@10090000: PHY present at 0 +ethernet@10090000: Starting autonegotiation... +ethernet@10090000: Autonegotiation complete +ethernet@10090000: link up, 1000Mbps full-duplex (lpa: 0x3800) +Using ethernet@10090000 device +TFTP from server 10.11.143.218; our IP address is 10.196.157.189; sending through gateway 10.196.156.1 +Filename 'uImage'. +Load address: 0x80200000 +Loading: ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ################################################################# + ########################################################## + 2.5 MiB/s +done +Bytes transferred = 14939132 (e3f3fc hex) +=> bootm 0x80200000 - 0x82200000 +## Booting kernel from Legacy Image at 80200000 ... + Image Name: Linux + Image Type: RISC-V Linux Kernel Image (uncompressed) + Data Size: 14939068 Bytes = 14.2 MiB + Load Address: 80200000 + Entry Point: 80200000 + Verifying Checksum ... OK +## Flattened Device Tree blob at 82200000 + Booting using the fdt blob at 0x82200000 + Loading Kernel Image ... OK + Using Device Tree in place at 0000000082200000, end 0000000082205c69 + +Starting kernel ... + +[ 0.000000] OF: fdt: Ignoring memory range 0x80000000 - 0x80200000 +[ 0.000000] Linux version 5.0.0-rc1-00020-g4b51f736 (atish@jedi-01) (gcc version 7.2.0 (GCC)) #262 SMP Mon Jan 21 17:39:27 PST 2019 +[ 0.000000] initrd not found or empty - disabling initrd +[ 0.000000] Zone ranges: +[ 0.000000] DMA32 [mem 0x0000000080200000-0x00000000ffffffff] +[ 0.000000] Normal [mem 0x0000000100000000-0x000027ffffffffff] +[ 0.000000] Movable zone start for each node +[ 0.000000] Early memory node ranges +[ 0.000000] node 0: [mem 0x0000000080200000-0x000000027fffffff] +[ 0.000000] Initmem setup node 0 [mem 0x0000000080200000-0x000000027fffffff] +[ 0.000000] software IO TLB: mapped [mem 0xfbfff000-0xfffff000] (64MB) +[ 0.000000] CPU with hartid=0 has a non-okay status of "masked" +[ 0.000000] CPU with hartid=0 has a non-okay status of "masked" +[ 0.000000] elf_hwcap is 0x112d +[ 0.000000] percpu: Embedded 15 pages/cpu @(____ptrval____) s29720 r0 d31720 u61440 +[ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 2067975 +[ 0.000000] Kernel command line: earlyprintk +[ 0.000000] Dentry cache hash table entries: 1048576 (order: 11, 8388608 bytes) +[ 0.000000] Inode-cache hash table entries: 524288 (order: 10, 4194304 bytes) +[ 0.000000] Sorting __ex_table... +[ 0.000000] Memory: 8178760K/8386560K available (3309K kernel code, 248K rwdata, 872K rodata, 9381K init, 763K bss, 207800K reserved, 0K cma-reserved) +[ 0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1 +[ 0.000000] rcu: Hierarchical RCU implementation. +[ 0.000000] rcu: RCU event tracing is enabled. +[ 0.000000] rcu: RCU restricting CPUs from NR_CPUS=8 to nr_cpu_ids=4. +[ 0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 10 jiffies. +[ 0.000000] rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=4 +[ 0.000000] NR_IRQS: 0, nr_irqs: 0, preallocated irqs: 0 +[ 0.000000] plic: mapped 53 interrupts to 4 (out of 9) handlers. +[ 0.000000] riscv_timer_init_dt: Registering clocksource cpuid [0] hartid [1] +[ 0.000000] clocksource: riscv_clocksource: mask: 0xffffffffffffffff max_cycles: 0x1d854df40, max_idle_ns: 3526361616960 ns +[ 0.000008] sched_clock: 64 bits at 1000kHz, resolution 1000ns, wraps every 2199023255500ns +[ 0.000221] Console: colour dummy device 80x25 +[ 0.000902] printk: console [tty0] enabled +[ 0.000963] Calibrating delay loop (skipped), value calculated using timer frequency.. 2.00 BogoMIPS (lpj=10000) +[ 0.001034] pid_max: default: 32768 minimum: 301 +[ 0.001541] Mount-cache hash table entries: 16384 (order: 5, 131072 bytes) +[ 0.001912] Mountpoint-cache hash table entries: 16384 (order: 5, 131072 bytes) +[ 0.003542] rcu: Hierarchical SRCU implementation. +[ 0.004347] smp: Bringing up secondary CPUs ... +[ 1.040259] CPU1: failed to come online +[ 2.080483] CPU2: failed to come online +[ 3.120699] CPU3: failed to come online +[ 3.120765] smp: Brought up 1 node, 1 CPU +[ 3.121923] devtmpfs: initialized +[ 3.124649] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns +[ 3.124727] futex hash table entries: 1024 (order: 4, 65536 bytes) +[ 3.125346] random: get_random_u32 called from bucket_table_alloc+0x72/0x172 with crng_init=0 +[ 3.125578] NET: Registered protocol family 16 +[ 3.126400] sifive-u54-prci 10000000.prci: Registered U54 core clocks +[ 3.126649] sifive-gemgxl-mgmt 100a0000.cadence-gemgxl-mgmt: Registered clock switch 'cadence-gemgxl-mgmt' +[ 3.135572] vgaarb: loaded +[ 3.135858] SCSI subsystem initialized +[ 3.136193] usbcore: registered new interface driver usbfs +[ 3.136266] usbcore: registered new interface driver hub +[ 3.136348] usbcore: registered new device driver usb +[ 3.136446] pps_core: LinuxPPS API ver. 1 registered +[ 3.136484] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it> +[ 3.136575] PTP clock support registered +[ 3.137256] clocksource: Switched to clocksource riscv_clocksource +[ 3.142711] NET: Registered protocol family 2 +[ 3.143322] tcp_listen_portaddr_hash hash table entries: 4096 (order: 4, 65536 bytes) +[ 3.143634] TCP established hash table entries: 65536 (order: 7, 524288 bytes) +[ 3.145799] TCP bind hash table entries: 65536 (order: 8, 1048576 bytes) +[ 3.149121] TCP: Hash tables configured (established 65536 bind 65536) +[ 3.149591] UDP hash table entries: 4096 (order: 5, 131072 bytes) +[ 3.150094] UDP-Lite hash table entries: 4096 (order: 5, 131072 bytes) +[ 3.150781] NET: Registered protocol family 1 +[ 3.230693] workingset: timestamp_bits=62 max_order=21 bucket_order=0 +[ 3.241224] io scheduler mq-deadline registered +[ 3.241269] io scheduler kyber registered +[ 3.242143] sifive_gpio 10060000.gpio: SiFive GPIO chip registered 16 GPIOs +[ 3.242357] pwm-sifivem 10020000.pwm: Unable to find controller clock +[ 3.242439] pwm-sifivem 10021000.pwm: Unable to find controller clock +[ 3.243228] xilinx-pcie 2000000000.pci: PCIe Link is DOWN +[ 3.243289] xilinx-pcie 2000000000.pci: host bridge /soc/pci@2000000000 ranges: +[ 3.243360] xilinx-pcie 2000000000.pci: No bus range found for /soc/pci@2000000000, using [bus 00-ff] +[ 3.243447] xilinx-pcie 2000000000.pci: MEM 0x40000000..0x5fffffff -> 0x40000000 +[ 3.243591] xilinx-pcie 2000000000.pci: PCI host bridge to bus 0000:00 +[ 3.243636] pci_bus 0000:00: root bus resource [bus 00-ff] +[ 3.243676] pci_bus 0000:00: root bus resource [mem 0x40000000-0x5fffffff] +[ 3.276547] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled +[ 3.277689] 10010000.serial: ttySIF0 at MMIO 0x10010000 (irq = 39, base_baud = 0) is a SiFive UART v0 +[ 3.786963] printk: console [ttySIF0] enabled +[ 3.791504] 10011000.serial: ttySIF1 at MMIO 0x10011000 (irq = 40, base_baud = 0) is a SiFive UART v0 +[ 3.801251] sifive_spi 10040000.spi: mapped; irq=41, cs=1 +[ 3.806362] m25p80 spi0.0: unrecognized JEDEC id bytes: 9d, 70, 19 +[ 3.812084] m25p80: probe of spi0.0 failed with error -2 +[ 3.817453] sifive_spi 10041000.spi: mapped; irq=42, cs=4 +[ 3.823027] sifive_spi 10050000.spi: mapped; irq=43, cs=1 +[ 3.828604] libphy: Fixed MDIO Bus: probed +[ 3.832623] macb: GEM doesn't support hardware ptp. +[ 3.837196] libphy: MACB_mii_bus: probed +[ 4.041156] Microsemi VSC8541 SyncE 10090000.ethernet-ffffffff:00: attached PHY driver [Microsemi VSC8541 SyncE] (mii_bus:phy_addr=10090000.ethernet-ffffffff:00, irq=POLL) +[ 4.055779] macb 10090000.ethernet eth0: Cadence GEM rev 0x10070109 at 0x10090000 irq 12 (70:b3:d5:92:f0:c2) +[ 4.065780] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver +[ 4.072033] ehci-pci: EHCI PCI platform driver +[ 4.076521] usbcore: registered new interface driver usb-storage +[ 4.082843] softdog: initialized. soft_noboot=0 soft_margin=60 sec soft_panic=0 (nowayout=0) +[ 4.127465] mmc_spi spi2.0: SD/MMC host mmc0, no DMA, no WP, no poweroff +[ 4.133645] usbcore: registered new interface driver usbhid +[ 4.138980] usbhid: USB HID core driver +[ 4.143017] NET: Registered protocol family 17 +[ 4.147885] pwm-sifivem 10020000.pwm: SiFive PWM chip registered 4 PWMs +[ 4.153945] pwm-sifivem 10021000.pwm: SiFive PWM chip registered 4 PWMs +[ 4.186407] Freeing unused kernel memory: 9380K +[ 4.190224] This architecture does not have kernel memory protection. +[ 4.196609] Run /init as init process +Starting logging: OK +Starting mdev... +[ 4.303785] mmc0: host does not support reading read-only switch, assuming write-enable +[ 4.311109] mmc0: new SDHC card on SPI +[ 4.317103] mmcblk0: mmc0:0000 SS08G 7.40 GiB +[ 4.386471] mmcblk0: p1 p2 +sort: /sys/devices/platform/Fixed: No such file or directory +modprobe: can't change directory to '/lib/modules': No such file or directory +Initializing random[ 4.759075] random: dd: uninitialized urandom read (512 bytes read) + number generator... done. +Starting network... +udhcpc (v1.24.2) started +Sending discover... +Sending discover... +[ 7.927510] macb 10090000.ethernet eth0: link up (1000/Full) +Sending discover... +Sending select for 10.196.157.190... +Lease of 10.196.157.190 obtained, lease time 499743 +deleting routers +adding dns 10.86.1.1 +adding dns 10.86.2.1 +/etc/init.d/S50dropbear +Starting dropbear sshd: [ 12.772393] random: dropbear: uninitialized urandom read (32 bytes read) +OK + +Welcome to Buildroot +buildroot login: diff --git a/doc/device-tree-bindings/clock/fixed-factor-clock.txt b/doc/device-tree-bindings/clock/fixed-factor-clock.txt new file mode 100644 index 0000000000..1bae8527eb --- /dev/null +++ b/doc/device-tree-bindings/clock/fixed-factor-clock.txt @@ -0,0 +1,24 @@ +Binding for simple fixed factor rate clock sources. + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be "fixed-factor-clock". +- #clock-cells : from common clock binding; shall be set to 0. +- clock-div: fixed divider. +- clock-mult: fixed multiplier. +- clocks: parent clock. + +Optional properties: +- clock-output-names : From common clock binding. + +Example: + clock { + compatible = "fixed-factor-clock"; + clocks = <&parentclk>; + #clock-cells = <0>; + clock-div = <2>; + clock-mult = <1>; + }; diff --git a/doc/device-tree-bindings/ram/k3-am654-ddrss.txt b/doc/device-tree-bindings/memory-controllers/k3-am654-ddrss.txt index 4ed731c524..4ed731c524 100644 --- a/doc/device-tree-bindings/ram/k3-am654-ddrss.txt +++ b/doc/device-tree-bindings/memory-controllers/k3-am654-ddrss.txt diff --git a/doc/device-tree-bindings/ram/st,stm32-fmc.txt b/doc/device-tree-bindings/memory-controllers/st,stm32-fmc.txt index 99f76d515f..99f76d515f 100644 --- a/doc/device-tree-bindings/ram/st,stm32-fmc.txt +++ b/doc/device-tree-bindings/memory-controllers/st,stm32-fmc.txt diff --git a/doc/device-tree-bindings/ram/st,stm32mp1-ddr.txt b/doc/device-tree-bindings/memory-controllers/st,stm32mp1-ddr.txt index 3028636c45..3028636c45 100644 --- a/doc/device-tree-bindings/ram/st,stm32mp1-ddr.txt +++ b/doc/device-tree-bindings/memory-controllers/st,stm32mp1-ddr.txt diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 51c931b906..ff60fc5c45 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -105,6 +105,7 @@ source "drivers/clk/mvebu/Kconfig" source "drivers/clk/owl/Kconfig" source "drivers/clk/renesas/Kconfig" source "drivers/clk/sunxi/Kconfig" +source "drivers/clk/sifive/Kconfig" source "drivers/clk/tegra/Kconfig" source "drivers/clk/uniphier/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 6a4ff9143b..1d9d725cae 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -4,7 +4,9 @@ # Wolfgang Denk, DENX Software Engineering, wd@denx.de. # -obj-$(CONFIG_$(SPL_TPL_)CLK) += clk-uclass.o clk_fixed_rate.o +obj-$(CONFIG_$(SPL_TPL_)CLK) += clk-uclass.o +obj-$(CONFIG_$(SPL_TPL_)CLK) += clk_fixed_rate.o +obj-$(CONFIG_$(SPL_TPL_)CLK) += clk_fixed_factor.o obj-y += imx/ obj-y += tegra/ @@ -22,6 +24,7 @@ obj-$(CONFIG_CLK_HSDK) += clk-hsdk-cgu.o obj-$(CONFIG_CLK_MPC83XX) += mpc83xx_clk.o obj-$(CONFIG_CLK_OWL) += owl/ obj-$(CONFIG_CLK_RENESAS) += renesas/ +obj-$(CONFIG_CLK_SIFIVE) += sifive/ obj-$(CONFIG_ARCH_SUNXI) += sunxi/ obj-$(CONFIG_CLK_STM32F) += clk_stm32f.o obj-$(CONFIG_CLK_STM32MP1) += clk_stm32mp1.o diff --git a/drivers/clk/clk_fixed_factor.c b/drivers/clk/clk_fixed_factor.c new file mode 100644 index 0000000000..5fa20a84db --- /dev/null +++ b/drivers/clk/clk_fixed_factor.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2019 Western Digital Corporation or its affiliates. + * + * Author: Anup Patel <anup.patel@wdc.com> + */ + +#include <common.h> +#include <clk-uclass.h> +#include <div64.h> +#include <dm.h> + +struct clk_fixed_factor { + struct clk parent; + unsigned int div; + unsigned int mult; +}; + +#define to_clk_fixed_factor(dev) \ + ((struct clk_fixed_factor *)dev_get_platdata(dev)) + +static ulong clk_fixed_factor_get_rate(struct clk *clk) +{ + uint64_t rate; + struct clk_fixed_factor *ff = to_clk_fixed_factor(clk->dev); + + if (clk->id != 0) + return -EINVAL; + + rate = clk_get_rate(&ff->parent); + if (IS_ERR_VALUE(rate)) + return rate; + + do_div(rate, ff->div); + + return rate * ff->mult; +} + +const struct clk_ops clk_fixed_factor_ops = { + .get_rate = clk_fixed_factor_get_rate, +}; + +static int clk_fixed_factor_ofdata_to_platdata(struct udevice *dev) +{ +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + int err; + struct clk_fixed_factor *ff = to_clk_fixed_factor(dev); + + err = clk_get_by_index(dev, 0, &ff->parent); + if (err) + return err; + + ff->div = dev_read_u32_default(dev, "clock-div", 1); + ff->mult = dev_read_u32_default(dev, "clock-mult", 1); +#endif + + return 0; +} + +static const struct udevice_id clk_fixed_factor_match[] = { + { + .compatible = "fixed-factor-clock", + }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(clk_fixed_factor) = { + .name = "fixed_factor_clock", + .id = UCLASS_CLK, + .of_match = clk_fixed_factor_match, + .ofdata_to_platdata = clk_fixed_factor_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct clk_fixed_factor), + .ops = &clk_fixed_factor_ops, +}; diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index 578e6a8049..e062eccdae 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -13,35 +13,30 @@ config CLK_RCAR_GEN2 config CLK_R8A7790 bool "Renesas R8A7790 clock driver" - def_bool y if R8A7790 depends on CLK_RCAR_GEN2 help Enable this to support the clocks on Renesas R8A7790 SoC. config CLK_R8A7791 bool "Renesas R8A7791 clock driver" - def_bool y if R8A7791 depends on CLK_RCAR_GEN2 help Enable this to support the clocks on Renesas R8A7791 SoC. config CLK_R8A7792 bool "Renesas R8A7792 clock driver" - def_bool y if R8A7792 depends on CLK_RCAR_GEN2 help Enable this to support the clocks on Renesas R8A7792 SoC. config CLK_R8A7793 bool "Renesas R8A7793 clock driver" - def_bool y if R8A7793 depends on CLK_RCAR_GEN2 help Enable this to support the clocks on Renesas R8A7793 SoC. config CLK_R8A7794 bool "Renesas R8A7794 clock driver" - def_bool y if R8A7794 depends on CLK_RCAR_GEN2 help Enable this to support the clocks on Renesas R8A7794 SoC. @@ -55,35 +50,30 @@ config CLK_RCAR_GEN3 config CLK_R8A7795 bool "Renesas R8A7795 clock driver" - def_bool y if R8A7795 depends on CLK_RCAR_GEN3 help Enable this to support the clocks on Renesas R8A7795 SoC. config CLK_R8A7796 bool "Renesas R8A7796 clock driver" - def_bool y if R8A7796 depends on CLK_RCAR_GEN3 help Enable this to support the clocks on Renesas R8A7796 SoC. config CLK_R8A77970 bool "Renesas R8A77970 clock driver" - def_bool y if R8A77970 depends on CLK_RCAR_GEN3 help Enable this to support the clocks on Renesas R8A77970 SoC. config CLK_R8A77990 bool "Renesas R8A77990 clock driver" - def_bool y if R8A77990 depends on CLK_RCAR_GEN3 help Enable this to support the clocks on Renesas R8A77990 SoC. config CLK_R8A77995 bool "Renesas R8A77995 clock driver" - def_bool y if R8A77995 depends on CLK_RCAR_GEN3 help Enable this to support the clocks on Renesas R8A77995 SoC. diff --git a/drivers/clk/sifive/Kconfig b/drivers/clk/sifive/Kconfig new file mode 100644 index 0000000000..81fc9f8fda --- /dev/null +++ b/drivers/clk/sifive/Kconfig @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0 + +config CLK_ANALOGBITS_WRPLL_CLN28HPC + bool + +config CLK_SIFIVE + bool "SiFive SoC driver support" + depends on CLK + help + SoC drivers for SiFive Linux-capable SoCs. + +config CLK_SIFIVE_FU540_PRCI + bool "PRCI driver for SiFive FU540 SoCs" + depends on CLK_SIFIVE + select CLK_ANALOGBITS_WRPLL_CLN28HPC + help + Supports the Power Reset Clock interface (PRCI) IP block found in + FU540 SoCs. If this kernel is meant to run on a SiFive FU540 SoC, + enable this driver. diff --git a/drivers/clk/sifive/Makefile b/drivers/clk/sifive/Makefile new file mode 100644 index 0000000000..1155e07e37 --- /dev/null +++ b/drivers/clk/sifive/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0+ + +obj-$(CONFIG_CLK_ANALOGBITS_WRPLL_CLN28HPC) += wrpll-cln28hpc.o + +obj-$(CONFIG_CLK_SIFIVE_FU540_PRCI) += fu540-prci.o diff --git a/drivers/clk/sifive/analogbits-wrpll-cln28hpc.h b/drivers/clk/sifive/analogbits-wrpll-cln28hpc.h new file mode 100644 index 0000000000..4432e24749 --- /dev/null +++ b/drivers/clk/sifive/analogbits-wrpll-cln28hpc.h @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019 Western Digital Corporation or its affiliates. + * + * Copyright (C) 2018 SiFive, Inc. + * Wesley Terpstra + * Paul Walmsley + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __LINUX_CLK_ANALOGBITS_WRPLL_CLN28HPC_H +#define __LINUX_CLK_ANALOGBITS_WRPLL_CLN28HPC_H + +#include <linux/types.h> + +/* DIVQ_VALUES: number of valid DIVQ values */ +#define DIVQ_VALUES 6 + +/* + * Bit definitions for struct analogbits_wrpll_cfg.flags + * + * WRPLL_FLAGS_BYPASS_FLAG: if set, the PLL is either in bypass, or should be + * programmed to enter bypass + * WRPLL_FLAGS_RESET_FLAG: if set, the PLL is in reset + * WRPLL_FLAGS_INT_FEEDBACK_FLAG: if set, the PLL is configured for internal + * feedback mode + * WRPLL_FLAGS_EXT_FEEDBACK_FLAG: if set, the PLL is configured for external + * feedback mode (not yet supported by this driver) + * + * The flags WRPLL_FLAGS_INT_FEEDBACK_FLAG and WRPLL_FLAGS_EXT_FEEDBACK_FLAG are + * mutually exclusive. If both bits are set, or both are zero, the struct + * analogbits_wrpll_cfg record is uninitialized or corrupt. + */ +#define WRPLL_FLAGS_BYPASS_SHIFT 0 +#define WRPLL_FLAGS_BYPASS_MASK BIT(WRPLL_FLAGS_BYPASS_SHIFT) +#define WRPLL_FLAGS_RESET_SHIFT 1 +#define WRPLL_FLAGS_RESET_MASK BIT(WRPLL_FLAGS_RESET_SHIFT) +#define WRPLL_FLAGS_INT_FEEDBACK_SHIFT 2 +#define WRPLL_FLAGS_INT_FEEDBACK_MASK BIT(WRPLL_FLAGS_INT_FEEDBACK_SHIFT) +#define WRPLL_FLAGS_EXT_FEEDBACK_SHIFT 3 +#define WRPLL_FLAGS_EXT_FEEDBACK_MASK BIT(WRPLL_FLAGS_EXT_FEEDBACK_SHIFT) + +/** + * struct analogbits_wrpll_cfg - WRPLL configuration values + * @divr: reference divider value (6 bits), as presented to the PLL signals. + * @divf: feedback divider value (9 bits), as presented to the PLL signals. + * @divq: output divider value (3 bits), as presented to the PLL signals. + * @flags: PLL configuration flags. See above for more information. + * @range: PLL loop filter range. See below for more information. + * @_output_rate_cache: cached output rates, swept across DIVQ. + * @_parent_rate: PLL refclk rate for which values are valid + * @_max_r: maximum possible R divider value, given @parent_rate + * @_init_r: initial R divider value to start the search from + * + * @divr, @divq, @divq, @range represent what the PLL expects to see + * on its input signals. Thus @divr and @divf are the actual divisors + * minus one. @divq is a power-of-two divider; for example, 1 = + * divide-by-2 and 6 = divide-by-64. 0 is an invalid @divq value. + * + * When initially passing a struct analogbits_wrpll_cfg record, the + * record should be zero-initialized with the exception of the @flags + * field. The only flag bits that need to be set are either + * WRPLL_FLAGS_INT_FEEDBACK or WRPLL_FLAGS_EXT_FEEDBACK. + * + * Field names beginning with an underscore should be considered + * private to the wrpll-cln28hpc.c code. + */ +struct analogbits_wrpll_cfg { + u8 divr; + u8 divq; + u8 range; + u8 flags; + u16 divf; + u32 _output_rate_cache[DIVQ_VALUES]; + unsigned long _parent_rate; + u8 _max_r; + u8 _init_r; +}; + +/* + * Function prototypes + */ + +int analogbits_wrpll_configure_for_rate(struct analogbits_wrpll_cfg *c, + u32 target_rate, + unsigned long parent_rate); + +unsigned int analogbits_wrpll_calc_max_lock_us(struct analogbits_wrpll_cfg *c); + +unsigned long analogbits_wrpll_calc_output_rate(struct analogbits_wrpll_cfg *c, + unsigned long parent_rate); + +#endif /* __LINUX_CLK_ANALOGBITS_WRPLL_CLN28HPC_H */ diff --git a/drivers/clk/sifive/fu540-prci.c b/drivers/clk/sifive/fu540-prci.c new file mode 100644 index 0000000000..e1b5f8e6a9 --- /dev/null +++ b/drivers/clk/sifive/fu540-prci.c @@ -0,0 +1,604 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019 Western Digital Corporation or its affiliates. + * + * Copyright (C) 2018 SiFive, Inc. + * Wesley Terpstra + * Paul Walmsley + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * The FU540 PRCI implements clock and reset control for the SiFive + * FU540-C000 chip. This driver assumes that it has sole control + * over all PRCI resources. + * + * This driver is based on the PRCI driver written by Wesley Terpstra. + * + * Refer, commit 999529edf517ed75b56659d456d221b2ee56bb60 of: + * https://github.com/riscv/riscv-linux + * + * References: + * - SiFive FU540-C000 manual v1p0, Chapter 7 "Clocking and Reset" + */ + +#include <asm/io.h> +#include <clk-uclass.h> +#include <clk.h> +#include <common.h> +#include <div64.h> +#include <dm.h> +#include <errno.h> + +#include <linux/math64.h> +#include <dt-bindings/clk/sifive-fu540-prci.h> + +#include "analogbits-wrpll-cln28hpc.h" + +/* + * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects: + * hfclk and rtcclk + */ +#define EXPECTED_CLK_PARENT_COUNT 2 + +/* + * Register offsets and bitmasks + */ + +/* COREPLLCFG0 */ +#define PRCI_COREPLLCFG0_OFFSET 0x4 +#define PRCI_COREPLLCFG0_DIVR_SHIFT 0 +#define PRCI_COREPLLCFG0_DIVR_MASK (0x3f << PRCI_COREPLLCFG0_DIVR_SHIFT) +#define PRCI_COREPLLCFG0_DIVF_SHIFT 6 +#define PRCI_COREPLLCFG0_DIVF_MASK (0x1ff << PRCI_COREPLLCFG0_DIVF_SHIFT) +#define PRCI_COREPLLCFG0_DIVQ_SHIFT 15 +#define PRCI_COREPLLCFG0_DIVQ_MASK (0x7 << PRCI_COREPLLCFG0_DIVQ_SHIFT) +#define PRCI_COREPLLCFG0_RANGE_SHIFT 18 +#define PRCI_COREPLLCFG0_RANGE_MASK (0x7 << PRCI_COREPLLCFG0_RANGE_SHIFT) +#define PRCI_COREPLLCFG0_BYPASS_SHIFT 24 +#define PRCI_COREPLLCFG0_BYPASS_MASK (0x1 << PRCI_COREPLLCFG0_BYPASS_SHIFT) +#define PRCI_COREPLLCFG0_FSE_SHIFT 25 +#define PRCI_COREPLLCFG0_FSE_MASK (0x1 << PRCI_COREPLLCFG0_FSE_SHIFT) +#define PRCI_COREPLLCFG0_LOCK_SHIFT 31 +#define PRCI_COREPLLCFG0_LOCK_MASK (0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT) + +/* DDRPLLCFG0 */ +#define PRCI_DDRPLLCFG0_OFFSET 0xc +#define PRCI_DDRPLLCFG0_DIVR_SHIFT 0 +#define PRCI_DDRPLLCFG0_DIVR_MASK (0x3f << PRCI_DDRPLLCFG0_DIVR_SHIFT) +#define PRCI_DDRPLLCFG0_DIVF_SHIFT 6 +#define PRCI_DDRPLLCFG0_DIVF_MASK (0x1ff << PRCI_DDRPLLCFG0_DIVF_SHIFT) +#define PRCI_DDRPLLCFG0_DIVQ_SHIFT 15 +#define PRCI_DDRPLLCFG0_DIVQ_MASK (0x7 << PRCI_DDRPLLCFG0_DIVQ_SHIFT) +#define PRCI_DDRPLLCFG0_RANGE_SHIFT 18 +#define PRCI_DDRPLLCFG0_RANGE_MASK (0x7 << PRCI_DDRPLLCFG0_RANGE_SHIFT) +#define PRCI_DDRPLLCFG0_BYPASS_SHIFT 24 +#define PRCI_DDRPLLCFG0_BYPASS_MASK (0x1 << PRCI_DDRPLLCFG0_BYPASS_SHIFT) +#define PRCI_DDRPLLCFG0_FSE_SHIFT 25 +#define PRCI_DDRPLLCFG0_FSE_MASK (0x1 << PRCI_DDRPLLCFG0_FSE_SHIFT) +#define PRCI_DDRPLLCFG0_LOCK_SHIFT 31 +#define PRCI_DDRPLLCFG0_LOCK_MASK (0x1 << PRCI_DDRPLLCFG0_LOCK_SHIFT) + +/* DDRPLLCFG1 */ +#define PRCI_DDRPLLCFG1_OFFSET 0x10 +#define PRCI_DDRPLLCFG1_CKE_SHIFT 24 +#define PRCI_DDRPLLCFG1_CKE_MASK (0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT) + +/* GEMGXLPLLCFG0 */ +#define PRCI_GEMGXLPLLCFG0_OFFSET 0x1c +#define PRCI_GEMGXLPLLCFG0_DIVR_SHIFT 0 +#define PRCI_GEMGXLPLLCFG0_DIVR_MASK \ + (0x3f << PRCI_GEMGXLPLLCFG0_DIVR_SHIFT) +#define PRCI_GEMGXLPLLCFG0_DIVF_SHIFT 6 +#define PRCI_GEMGXLPLLCFG0_DIVF_MASK \ + (0x1ff << PRCI_GEMGXLPLLCFG0_DIVF_SHIFT) +#define PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT 15 +#define PRCI_GEMGXLPLLCFG0_DIVQ_MASK (0x7 << PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT) +#define PRCI_GEMGXLPLLCFG0_RANGE_SHIFT 18 +#define PRCI_GEMGXLPLLCFG0_RANGE_MASK \ + (0x7 << PRCI_GEMGXLPLLCFG0_RANGE_SHIFT) +#define PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT 24 +#define PRCI_GEMGXLPLLCFG0_BYPASS_MASK \ + (0x1 << PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT) +#define PRCI_GEMGXLPLLCFG0_FSE_SHIFT 25 +#define PRCI_GEMGXLPLLCFG0_FSE_MASK \ + (0x1 << PRCI_GEMGXLPLLCFG0_FSE_SHIFT) +#define PRCI_GEMGXLPLLCFG0_LOCK_SHIFT 31 +#define PRCI_GEMGXLPLLCFG0_LOCK_MASK (0x1 << PRCI_GEMGXLPLLCFG0_LOCK_SHIFT) + +/* GEMGXLPLLCFG1 */ +#define PRCI_GEMGXLPLLCFG1_OFFSET 0x20 +#define PRCI_GEMGXLPLLCFG1_CKE_SHIFT 24 +#define PRCI_GEMGXLPLLCFG1_CKE_MASK (0x1 << PRCI_GEMGXLPLLCFG1_CKE_SHIFT) + +/* CORECLKSEL */ +#define PRCI_CORECLKSEL_OFFSET 0x24 +#define PRCI_CORECLKSEL_CORECLKSEL_SHIFT 0 +#define PRCI_CORECLKSEL_CORECLKSEL_MASK \ + (0x1 << PRCI_CORECLKSEL_CORECLKSEL_SHIFT) + +/* DEVICESRESETREG */ +#define PRCI_DEVICESRESETREG_OFFSET 0x28 +#define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT 0 +#define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK \ + (0x1 << PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT) +#define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT 1 +#define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_MASK \ + (0x1 << PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT) +#define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT 2 +#define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_MASK \ + (0x1 << PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT) +#define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT 3 +#define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_MASK \ + (0x1 << PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT) +#define PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT 5 +#define PRCI_DEVICESRESETREG_GEMGXL_RST_N_MASK \ + (0x1 << PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT) + +/* CLKMUXSTATUSREG */ +#define PRCI_CLKMUXSTATUSREG_OFFSET 0x2c +#define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT 1 +#define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK \ + (0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT) + +/* + * Private structures + */ + +/** + * struct __prci_data - per-device-instance data + * @va: base virtual address of the PRCI IP block + * @parent: parent clk instance + * + * PRCI per-device instance data + */ +struct __prci_data { + void *base; + struct clk parent; +}; + +/** + * struct __prci_wrpll_data - WRPLL configuration and integration data + * @c: WRPLL current configuration record + * @bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL) + * @no_bypass: fn ptr to code to not bypass the WRPLL (if applicable; else NULL) + * @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address + * + * @bypass and @no_bypass are used for WRPLL instances that contain a separate + * external glitchless clock mux downstream from the PLL. The WRPLL internal + * bypass mux is not glitchless. + */ +struct __prci_wrpll_data { + struct analogbits_wrpll_cfg c; + void (*bypass)(struct __prci_data *pd); + void (*no_bypass)(struct __prci_data *pd); + u8 cfg0_offs; +}; + +struct __prci_clock; + +struct __prci_clock_ops { + int (*set_rate)(struct __prci_clock *pc, + unsigned long rate, + unsigned long parent_rate); + unsigned long (*round_rate)(struct __prci_clock *pc, + unsigned long rate, + unsigned long *parent_rate); + unsigned long (*recalc_rate)(struct __prci_clock *pc, + unsigned long parent_rate); +}; + +/** + * struct __prci_clock - describes a clock device managed by PRCI + * @name: user-readable clock name string - should match the manual + * @parent_name: parent name for this clock + * @ops: struct clk_ops for the Linux clock framework to use for control + * @hw: Linux-private clock data + * @pwd: WRPLL-specific data, associated with this clock (if not NULL) + * @pd: PRCI-specific data associated with this clock (if not NULL) + * + * PRCI clock data. Used by the PRCI driver to register PRCI-provided + * clocks to the Linux clock infrastructure. + */ +struct __prci_clock { + const char *name; + const char *parent_name; + const struct __prci_clock_ops *ops; + struct __prci_wrpll_data *pwd; + struct __prci_data *pd; +}; + +/* + * Private functions + */ + +/** + * __prci_readl() - read from a PRCI register + * @pd: PRCI context + * @offs: register offset to read from (in bytes, from PRCI base address) + * + * Read the register located at offset @offs from the base virtual + * address of the PRCI register target described by @pd, and return + * the value to the caller. + * + * Context: Any context. + * + * Return: the contents of the register described by @pd and @offs. + */ +static u32 __prci_readl(struct __prci_data *pd, u32 offs) +{ + return readl(pd->base + offs); +} + +static void __prci_writel(u32 v, u32 offs, struct __prci_data *pd) +{ + return writel(v, pd->base + offs); +} + +/* WRPLL-related private functions */ + +/** + * __prci_wrpll_unpack() - unpack WRPLL configuration registers into parameters + * @c: ptr to a struct analogbits_wrpll_cfg record to write config into + * @r: value read from the PRCI PLL configuration register + * + * Given a value @r read from an FU540 PRCI PLL configuration register, + * split it into fields and populate it into the WRPLL configuration record + * pointed to by @c. + * + * The COREPLLCFG0 macros are used below, but the other *PLLCFG0 macros + * have the same register layout. + * + * Context: Any context. + */ +static void __prci_wrpll_unpack(struct analogbits_wrpll_cfg *c, u32 r) +{ + u32 v; + + v = r & PRCI_COREPLLCFG0_DIVR_MASK; + v >>= PRCI_COREPLLCFG0_DIVR_SHIFT; + c->divr = v; + + v = r & PRCI_COREPLLCFG0_DIVF_MASK; + v >>= PRCI_COREPLLCFG0_DIVF_SHIFT; + c->divf = v; + + v = r & PRCI_COREPLLCFG0_DIVQ_MASK; + v >>= PRCI_COREPLLCFG0_DIVQ_SHIFT; + c->divq = v; + + v = r & PRCI_COREPLLCFG0_RANGE_MASK; + v >>= PRCI_COREPLLCFG0_RANGE_SHIFT; + c->range = v; + + c->flags &= (WRPLL_FLAGS_INT_FEEDBACK_MASK | + WRPLL_FLAGS_EXT_FEEDBACK_MASK); + + if (r & PRCI_COREPLLCFG0_FSE_MASK) + c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK; + else + c->flags |= WRPLL_FLAGS_EXT_FEEDBACK_MASK; +} + +/** + * __prci_wrpll_pack() - pack PLL configuration parameters into a register value + * @c: pointer to a struct analogbits_wrpll_cfg record containing the PLL's cfg + * + * Using a set of WRPLL configuration values pointed to by @c, + * assemble a PRCI PLL configuration register value, and return it to + * the caller. + * + * Context: Any context. Caller must ensure that the contents of the + * record pointed to by @c do not change during the execution + * of this function. + * + * Returns: a value suitable for writing into a PRCI PLL configuration + * register + */ +static u32 __prci_wrpll_pack(struct analogbits_wrpll_cfg *c) +{ + u32 r = 0; + + r |= c->divr << PRCI_COREPLLCFG0_DIVR_SHIFT; + r |= c->divf << PRCI_COREPLLCFG0_DIVF_SHIFT; + r |= c->divq << PRCI_COREPLLCFG0_DIVQ_SHIFT; + r |= c->range << PRCI_COREPLLCFG0_RANGE_SHIFT; + if (c->flags & WRPLL_FLAGS_INT_FEEDBACK_MASK) + r |= PRCI_COREPLLCFG0_FSE_MASK; + + return r; +} + +/** + * __prci_wrpll_read_cfg() - read the WRPLL configuration from the PRCI + * @pd: PRCI context + * @pwd: PRCI WRPLL metadata + * + * Read the current configuration of the PLL identified by @pwd from + * the PRCI identified by @pd, and store it into the local configuration + * cache in @pwd. + * + * Context: Any context. Caller must prevent the records pointed to by + * @pd and @pwd from changing during execution. + */ +static void __prci_wrpll_read_cfg(struct __prci_data *pd, + struct __prci_wrpll_data *pwd) +{ + __prci_wrpll_unpack(&pwd->c, __prci_readl(pd, pwd->cfg0_offs)); +} + +/** + * __prci_wrpll_write_cfg() - write WRPLL configuration into the PRCI + * @pd: PRCI context + * @pwd: PRCI WRPLL metadata + * @c: WRPLL configuration record to write + * + * Write the WRPLL configuration described by @c into the WRPLL + * configuration register identified by @pwd in the PRCI instance + * described by @c. Make a cached copy of the WRPLL's current + * configuration so it can be used by other code. + * + * Context: Any context. Caller must prevent the records pointed to by + * @pd and @pwd from changing during execution. + */ +static void __prci_wrpll_write_cfg(struct __prci_data *pd, + struct __prci_wrpll_data *pwd, + struct analogbits_wrpll_cfg *c) +{ + __prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd); + + memcpy(&pwd->c, c, sizeof(struct analogbits_wrpll_cfg)); +} + +/* Core clock mux control */ + +/** + * __prci_coreclksel_use_hfclk() - switch the CORECLK mux to output HFCLK + * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg + * + * Switch the CORECLK mux to the HFCLK input source; return once complete. + * + * Context: Any context. Caller must prevent concurrent changes to the + * PRCI_CORECLKSEL_OFFSET register. + */ +static void __prci_coreclksel_use_hfclk(struct __prci_data *pd) +{ + u32 r; + + r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); + r |= PRCI_CORECLKSEL_CORECLKSEL_MASK; + __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd); + + r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */ +} + +/** + * __prci_coreclksel_use_corepll() - switch the CORECLK mux to output COREPLL + * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg + * + * Switch the CORECLK mux to the PLL output clock; return once complete. + * + * Context: Any context. Caller must prevent concurrent changes to the + * PRCI_CORECLKSEL_OFFSET register. + */ +static void __prci_coreclksel_use_corepll(struct __prci_data *pd) +{ + u32 r; + + r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); + r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK; + __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd); + + r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */ +} + +static unsigned long sifive_fu540_prci_wrpll_recalc_rate( + struct __prci_clock *pc, + unsigned long parent_rate) +{ + struct __prci_wrpll_data *pwd = pc->pwd; + + return analogbits_wrpll_calc_output_rate(&pwd->c, parent_rate); +} + +static unsigned long sifive_fu540_prci_wrpll_round_rate( + struct __prci_clock *pc, + unsigned long rate, + unsigned long *parent_rate) +{ + struct __prci_wrpll_data *pwd = pc->pwd; + struct analogbits_wrpll_cfg c; + + memcpy(&c, &pwd->c, sizeof(c)); + + analogbits_wrpll_configure_for_rate(&c, rate, *parent_rate); + + return analogbits_wrpll_calc_output_rate(&c, *parent_rate); +} + +static int sifive_fu540_prci_wrpll_set_rate(struct __prci_clock *pc, + unsigned long rate, + unsigned long parent_rate) +{ + struct __prci_wrpll_data *pwd = pc->pwd; + struct __prci_data *pd = pc->pd; + int r; + + r = analogbits_wrpll_configure_for_rate(&pwd->c, rate, parent_rate); + if (r) + return -ERANGE; + + if (pwd->bypass) + pwd->bypass(pd); + + __prci_wrpll_write_cfg(pd, pwd, &pwd->c); + + udelay(analogbits_wrpll_calc_max_lock_us(&pwd->c)); + + if (pwd->no_bypass) + pwd->no_bypass(pd); + + return 0; +} + +static const struct __prci_clock_ops sifive_fu540_prci_wrpll_clk_ops = { + .set_rate = sifive_fu540_prci_wrpll_set_rate, + .round_rate = sifive_fu540_prci_wrpll_round_rate, + .recalc_rate = sifive_fu540_prci_wrpll_recalc_rate, +}; + +static const struct __prci_clock_ops sifive_fu540_prci_wrpll_ro_clk_ops = { + .recalc_rate = sifive_fu540_prci_wrpll_recalc_rate, +}; + +/* TLCLKSEL clock integration */ + +static unsigned long sifive_fu540_prci_tlclksel_recalc_rate( + struct __prci_clock *pc, + unsigned long parent_rate) +{ + struct __prci_data *pd = pc->pd; + u32 v; + u8 div; + + v = __prci_readl(pd, PRCI_CLKMUXSTATUSREG_OFFSET); + v &= PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK; + div = v ? 1 : 2; + + return div_u64(parent_rate, div); +} + +static const struct __prci_clock_ops sifive_fu540_prci_tlclksel_clk_ops = { + .recalc_rate = sifive_fu540_prci_tlclksel_recalc_rate, +}; + +/* + * PRCI integration data for each WRPLL instance + */ + +static struct __prci_wrpll_data __prci_corepll_data = { + .cfg0_offs = PRCI_COREPLLCFG0_OFFSET, + .bypass = __prci_coreclksel_use_hfclk, + .no_bypass = __prci_coreclksel_use_corepll, +}; + +static struct __prci_wrpll_data __prci_ddrpll_data = { + .cfg0_offs = PRCI_DDRPLLCFG0_OFFSET, +}; + +static struct __prci_wrpll_data __prci_gemgxlpll_data = { + .cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET, +}; + +/* + * List of clock controls provided by the PRCI + */ + +static struct __prci_clock __prci_init_clocks[] = { + [PRCI_CLK_COREPLL] = { + .name = "corepll", + .parent_name = "hfclk", + .ops = &sifive_fu540_prci_wrpll_clk_ops, + .pwd = &__prci_corepll_data, + }, + [PRCI_CLK_DDRPLL] = { + .name = "ddrpll", + .parent_name = "hfclk", + .ops = &sifive_fu540_prci_wrpll_ro_clk_ops, + .pwd = &__prci_ddrpll_data, + }, + [PRCI_CLK_GEMGXLPLL] = { + .name = "gemgxlpll", + .parent_name = "hfclk", + .ops = &sifive_fu540_prci_wrpll_clk_ops, + .pwd = &__prci_gemgxlpll_data, + }, + [PRCI_CLK_TLCLK] = { + .name = "tlclk", + .parent_name = "corepll", + .ops = &sifive_fu540_prci_tlclksel_clk_ops, + }, +}; + +static ulong sifive_fu540_prci_get_rate(struct clk *clk) +{ + struct __prci_clock *pc; + + if (ARRAY_SIZE(__prci_init_clocks) <= clk->id) + return -ENXIO; + + pc = &__prci_init_clocks[clk->id]; + if (!pc->pd || !pc->ops->recalc_rate) + return -ENXIO; + + return pc->ops->recalc_rate(pc, clk_get_rate(&pc->pd->parent)); +} + +static ulong sifive_fu540_prci_set_rate(struct clk *clk, ulong rate) +{ + int err; + struct __prci_clock *pc; + + if (ARRAY_SIZE(__prci_init_clocks) <= clk->id) + return -ENXIO; + + pc = &__prci_init_clocks[clk->id]; + if (!pc->pd || !pc->ops->set_rate) + return -ENXIO; + + err = pc->ops->set_rate(pc, rate, clk_get_rate(&pc->pd->parent)); + if (err) + return err; + + return rate; +} + +static int sifive_fu540_prci_probe(struct udevice *dev) +{ + int i, err; + struct __prci_clock *pc; + struct __prci_data *pd = dev_get_priv(dev); + + pd->base = (void *)dev_read_addr(dev); + if (IS_ERR(pd->base)) + return PTR_ERR(pd->base); + + err = clk_get_by_index(dev, 0, &pd->parent); + if (err) + return err; + + for (i = 0; i < ARRAY_SIZE(__prci_init_clocks); ++i) { + pc = &__prci_init_clocks[i]; + pc->pd = pd; + if (pc->pwd) + __prci_wrpll_read_cfg(pd, pc->pwd); + } + + return 0; +} + +static struct clk_ops sifive_fu540_prci_ops = { + .set_rate = sifive_fu540_prci_set_rate, + .get_rate = sifive_fu540_prci_get_rate, +}; + +static const struct udevice_id sifive_fu540_prci_ids[] = { + { .compatible = "sifive,fu540-c000-prci0" }, + { .compatible = "sifive,aloeprci0" }, + { } +}; + +U_BOOT_DRIVER(sifive_fu540_prci) = { + .name = "sifive-fu540-prci", + .id = UCLASS_CLK, + .of_match = sifive_fu540_prci_ids, + .probe = sifive_fu540_prci_probe, + .ops = &sifive_fu540_prci_ops, + .priv_auto_alloc_size = sizeof(struct __prci_data), +}; diff --git a/drivers/clk/sifive/wrpll-cln28hpc.c b/drivers/clk/sifive/wrpll-cln28hpc.c new file mode 100644 index 0000000000..d377849693 --- /dev/null +++ b/drivers/clk/sifive/wrpll-cln28hpc.c @@ -0,0 +1,390 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019 Western Digital Corporation or its affiliates. + * + * Copyright (C) 2018 SiFive, Inc. + * Wesley Terpstra + * Paul Walmsley + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This library supports configuration parsing and reprogramming of + * the CLN28HPC variant of the Analog Bits Wide Range PLL. The + * intention is for this library to be reusable for any device that + * integrates this PLL; thus the register structure and programming + * details are expected to be provided by a separate IP block driver. + * + * The bulk of this code is primarily useful for clock configurations + * that must operate at arbitrary rates, as opposed to clock configurations + * that are restricted by software or manufacturer guidance to a small, + * pre-determined set of performance points. + * + * References: + * - Analog Bits "Wide Range PLL Datasheet", version 2015.10.01 + * - SiFive FU540-C000 Manual v1p0, Chapter 7 "Clocking and Reset" + */ + +#include <linux/bug.h> +#include <linux/err.h> +#include <linux/log2.h> +#include <linux/math64.h> + +#include "analogbits-wrpll-cln28hpc.h" + +/* MIN_INPUT_FREQ: minimum input clock frequency, in Hz (Fref_min) */ +#define MIN_INPUT_FREQ 7000000 + +/* MAX_INPUT_FREQ: maximum input clock frequency, in Hz (Fref_max) */ +#define MAX_INPUT_FREQ 600000000 + +/* MIN_POST_DIVIDE_REF_FREQ: minimum post-divider reference frequency, in Hz */ +#define MIN_POST_DIVR_FREQ 7000000 + +/* MAX_POST_DIVIDE_REF_FREQ: maximum post-divider reference frequency, in Hz */ +#define MAX_POST_DIVR_FREQ 200000000 + +/* MIN_VCO_FREQ: minimum VCO frequency, in Hz (Fvco_min) */ +#define MIN_VCO_FREQ 2400000000UL + +/* MAX_VCO_FREQ: maximum VCO frequency, in Hz (Fvco_max) */ +#define MAX_VCO_FREQ 4800000000ULL + +/* MAX_DIVQ_DIVISOR: maximum output divisor. Selected by DIVQ = 6 */ +#define MAX_DIVQ_DIVISOR 64 + +/* MAX_DIVR_DIVISOR: maximum reference divisor. Selected by DIVR = 63 */ +#define MAX_DIVR_DIVISOR 64 + +/* MAX_LOCK_US: maximum PLL lock time, in microseconds (tLOCK_max) */ +#define MAX_LOCK_US 70 + +/* + * ROUND_SHIFT: number of bits to shift to avoid precision loss in the rounding + * algorithm + */ +#define ROUND_SHIFT 20 + +/* + * Private functions + */ + +/** + * __wrpll_calc_filter_range() - determine PLL loop filter bandwidth + * @post_divr_freq: input clock rate after the R divider + * + * Select the value to be presented to the PLL RANGE input signals, based + * on the input clock frequency after the post-R-divider @post_divr_freq. + * This code follows the recommendations in the PLL datasheet for filter + * range selection. + * + * Return: The RANGE value to be presented to the PLL configuration inputs, + * or -1 upon error. + */ +static int __wrpll_calc_filter_range(unsigned long post_divr_freq) +{ + u8 range; + + if (post_divr_freq < MIN_POST_DIVR_FREQ || + post_divr_freq > MAX_POST_DIVR_FREQ) { + WARN(1, "%s: post-divider reference freq out of range: %lu", + __func__, post_divr_freq); + return -1; + } + + if (post_divr_freq < 11000000) + range = 1; + else if (post_divr_freq < 18000000) + range = 2; + else if (post_divr_freq < 30000000) + range = 3; + else if (post_divr_freq < 50000000) + range = 4; + else if (post_divr_freq < 80000000) + range = 5; + else if (post_divr_freq < 130000000) + range = 6; + else + range = 7; + + return range; +} + +/** + * __wrpll_calc_fbdiv() - return feedback fixed divide value + * @c: ptr to a struct analogbits_wrpll_cfg record to read from + * + * The internal feedback path includes a fixed by-two divider; the + * external feedback path does not. Return the appropriate divider + * value (2 or 1) depending on whether internal or external feedback + * is enabled. This code doesn't test for invalid configurations + * (e.g. both or neither of WRPLL_FLAGS_*_FEEDBACK are set); it relies + * on the caller to do so. + * + * Context: Any context. Caller must protect the memory pointed to by + * @c from simultaneous modification. + * + * Return: 2 if internal feedback is enabled or 1 if external feedback + * is enabled. + */ +static u8 __wrpll_calc_fbdiv(struct analogbits_wrpll_cfg *c) +{ + return (c->flags & WRPLL_FLAGS_INT_FEEDBACK_MASK) ? 2 : 1; +} + +/** + * __wrpll_calc_divq() - determine DIVQ based on target PLL output clock rate + * @target_rate: target PLL output clock rate + * @vco_rate: pointer to a u64 to store the computed VCO rate into + * + * Determine a reasonable value for the PLL Q post-divider, based on the + * target output rate @target_rate for the PLL. Along with returning the + * computed Q divider value as the return value, this function stores the + * desired target VCO rate into the variable pointed to by @vco_rate. + * + * Context: Any context. Caller must protect the memory pointed to by + * @vco_rate from simultaneous access or modification. + * + * Return: a positive integer DIVQ value to be programmed into the hardware + * upon success, or 0 upon error (since 0 is an invalid DIVQ value) + */ +static u8 __wrpll_calc_divq(u32 target_rate, u64 *vco_rate) +{ + u64 s; + u8 divq = 0; + + if (!vco_rate) { + WARN_ON(1); + goto wcd_out; + } + + s = div_u64(MAX_VCO_FREQ, target_rate); + if (s <= 1) { + divq = 1; + *vco_rate = MAX_VCO_FREQ; + } else if (s > MAX_DIVQ_DIVISOR) { + divq = ilog2(MAX_DIVQ_DIVISOR); + *vco_rate = MIN_VCO_FREQ; + } else { + divq = ilog2(s); + *vco_rate = target_rate << divq; + } + +wcd_out: + return divq; +} + +/** + * __wrpll_update_parent_rate() - update PLL data when parent rate changes + * @c: ptr to a struct analogbits_wrpll_cfg record to write PLL data to + * @parent_rate: PLL input refclk rate (pre-R-divider) + * + * Pre-compute some data used by the PLL configuration algorithm when + * the PLL's reference clock rate changes. The intention is to avoid + * computation when the parent rate remains constant - expected to be + * the common case. + * + * Returns: 0 upon success or -1 if the reference clock rate is out of range. + */ +static int __wrpll_update_parent_rate(struct analogbits_wrpll_cfg *c, + unsigned long parent_rate) +{ + u8 max_r_for_parent; + + if (parent_rate > MAX_INPUT_FREQ || parent_rate < MIN_POST_DIVR_FREQ) + return -1; + + c->_parent_rate = parent_rate; + max_r_for_parent = div_u64(parent_rate, MIN_POST_DIVR_FREQ); + c->_max_r = min_t(u8, MAX_DIVR_DIVISOR, max_r_for_parent); + + /* Round up */ + c->_init_r = div_u64(parent_rate + MAX_POST_DIVR_FREQ - 1, + MAX_POST_DIVR_FREQ); + + return 0; +} + +/* + * Public functions + */ + +/** + * analogbits_wrpll_configure() - compute PLL configuration for a target rate + * @c: ptr to a struct analogbits_wrpll_cfg record to write into + * @target_rate: target PLL output clock rate (post-Q-divider) + * @parent_rate: PLL input refclk rate (pre-R-divider) + * + * Given a pointer to a PLL context @c, a desired PLL target output + * rate @target_rate, and a reference clock input rate @parent_rate, + * compute the appropriate PLL signal configuration values. PLL + * reprogramming is not glitchless, so the caller should switch any + * downstream logic to a different clock source or clock-gate it + * before presenting these values to the PLL configuration signals. + * + * The caller must pass this function a pre-initialized struct + * analogbits_wrpll_cfg record: either initialized to zero (with the + * exception of the .name and .flags fields) or read from the PLL. + * + * Context: Any context. Caller must protect the memory pointed to by @c + * from simultaneous access or modification. + * + * Return: 0 upon success; anything else upon failure. + */ +int analogbits_wrpll_configure_for_rate(struct analogbits_wrpll_cfg *c, + u32 target_rate, + unsigned long parent_rate) +{ + unsigned long ratio; + u64 target_vco_rate, delta, best_delta, f_pre_div, vco, vco_pre; + u32 best_f, f, post_divr_freq, fbcfg; + u8 fbdiv, divq, best_r, r; + + if (!c) + return -1; + + if (c->flags == 0) { + WARN(1, "%s called with uninitialized PLL config", __func__); + return -1; + } + + fbcfg = WRPLL_FLAGS_INT_FEEDBACK_MASK | WRPLL_FLAGS_EXT_FEEDBACK_MASK; + if ((c->flags & fbcfg) == fbcfg) { + WARN(1, "%s called with invalid PLL config", __func__); + return -1; + } + + if (c->flags == WRPLL_FLAGS_EXT_FEEDBACK_MASK) { + WARN(1, "%s: external feedback mode not currently supported", + __func__); + return -1; + } + + /* Initialize rounding data if it hasn't been initialized already */ + if (parent_rate != c->_parent_rate) { + if (__wrpll_update_parent_rate(c, parent_rate)) { + pr_err("%s: PLL input rate is out of range\n", + __func__); + return -1; + } + } + + c->flags &= ~WRPLL_FLAGS_RESET_MASK; + + /* Put the PLL into bypass if the user requests the parent clock rate */ + if (target_rate == parent_rate) { + c->flags |= WRPLL_FLAGS_BYPASS_MASK; + return 0; + } + c->flags &= ~WRPLL_FLAGS_BYPASS_MASK; + + /* Calculate the Q shift and target VCO rate */ + divq = __wrpll_calc_divq(target_rate, &target_vco_rate); + if (divq == 0) + return -1; + c->divq = divq; + + /* Precalculate the pre-Q divider target ratio */ + ratio = div64_u64((target_vco_rate << ROUND_SHIFT), parent_rate); + + fbdiv = __wrpll_calc_fbdiv(c); + best_r = 0; + best_f = 0; + best_delta = MAX_VCO_FREQ; + + /* + * Consider all values for R which land within + * [MIN_POST_DIVR_FREQ, MAX_POST_DIVR_FREQ]; prefer smaller R + */ + for (r = c->_init_r; r <= c->_max_r; ++r) { + /* What is the best F we can pick in this case? */ + f_pre_div = ratio * r; + f = (f_pre_div + (1 << ROUND_SHIFT)) >> ROUND_SHIFT; + f >>= (fbdiv - 1); + + post_divr_freq = div_u64(parent_rate, r); + vco_pre = fbdiv * post_divr_freq; + vco = vco_pre * f; + + /* Ensure rounding didn't take us out of range */ + if (vco > target_vco_rate) { + --f; + vco = vco_pre * f; + } else if (vco < MIN_VCO_FREQ) { + ++f; + vco = vco_pre * f; + } + + delta = abs(target_rate - vco); + if (delta < best_delta) { + best_delta = delta; + best_r = r; + best_f = f; + } + } + + c->divr = best_r - 1; + c->divf = best_f - 1; + + post_divr_freq = div_u64(parent_rate, best_r); + + /* Pick the best PLL jitter filter */ + c->range = __wrpll_calc_filter_range(post_divr_freq); + + return 0; +} + +/** + * analogbits_wrpll_calc_output_rate() - calculate the PLL's target output rate + * @c: ptr to a struct analogbits_wrpll_cfg record to read from + * @parent_rate: PLL refclk rate + * + * Given a pointer to the PLL's current input configuration @c and the + * PLL's input reference clock rate @parent_rate (before the R + * pre-divider), calculate the PLL's output clock rate (after the Q + * post-divider) + * + * Context: Any context. Caller must protect the memory pointed to by @c + * from simultaneous modification. + * + * Return: the PLL's output clock rate, in Hz. + */ +unsigned long analogbits_wrpll_calc_output_rate(struct analogbits_wrpll_cfg *c, + unsigned long parent_rate) +{ + u8 fbdiv; + u64 n; + + WARN(c->flags & WRPLL_FLAGS_EXT_FEEDBACK_MASK, + "external feedback mode not yet supported"); + + fbdiv = __wrpll_calc_fbdiv(c); + n = parent_rate * fbdiv * (c->divf + 1); + n = div_u64(n, (c->divr + 1)); + n >>= c->divq; + + return n; +} + +/** + * analogbits_wrpll_calc_max_lock_us() - return the time for the PLL to lock + * @c: ptr to a struct analogbits_wrpll_cfg record to read from + * + * Return the minimum amount of time (in microseconds) that the caller + * must wait after reprogramming the PLL to ensure that it is locked + * to the input frequency and stable. This is likely to depend on the DIVR + * value; this is under discussion with the manufacturer. + * + * Return: the minimum amount of time the caller must wait for the PLL + * to lock (in microseconds) + */ +unsigned int analogbits_wrpll_calc_max_lock_us(struct analogbits_wrpll_cfg *c) +{ + return MAX_LOCK_US; +} diff --git a/drivers/cpu/riscv_cpu.c b/drivers/cpu/riscv_cpu.c index 5e15df590e..f77c126499 100644 --- a/drivers/cpu/riscv_cpu.c +++ b/drivers/cpu/riscv_cpu.c @@ -10,6 +10,8 @@ #include <dm/device-internal.h> #include <dm/lists.h> +DECLARE_GLOBAL_DATA_PTR; + static int riscv_cpu_get_desc(struct udevice *dev, char *buf, int size) { const char *isa; @@ -62,7 +64,6 @@ static int riscv_cpu_bind(struct udevice *dev) /* save the hart id */ plat->cpu_id = dev_read_addr(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 */ @@ -71,7 +72,7 @@ static int riscv_cpu_bind(struct udevice *dev) &plat->timebase_freq); /* - * Bind riscv-timer driver on hart 0 + * Bind riscv-timer driver on boot hart. * * We only instantiate one timer device which is enough for U-Boot. * Pass the "timebase-frequency" value as the driver data for the @@ -80,7 +81,7 @@ static int riscv_cpu_bind(struct udevice *dev) * Return value is not checked since it's possible that the timer * driver is not included. */ - if (!plat->cpu_id && plat->timebase_freq) { + if (plat->cpu_id == gd->arch.boot_hart && plat->timebase_freq) { drv = lists_driver_lookup_name("riscv_timer"); if (!drv) { debug("Cannot find the timer driver, not included?\n"); diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 923f846370..6c51ccc294 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -137,7 +137,7 @@ static int renesas_sdhi_hs400(struct udevice *dev) tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_TMPPORT2); - tmio_sd_writel(priv, (taps << RENESAS_SDHI_SCC_DTCNTL_TAPNUM_SHIFT) | + tmio_sd_writel(priv, (0x8 << RENESAS_SDHI_SCC_DTCNTL_TAPNUM_SHIFT) | RENESAS_SDHI_SCC_DTCNTL_TAPEN, RENESAS_SDHI_SCC_DTCNTL); diff --git a/drivers/mmc/tmio-common.c b/drivers/mmc/tmio-common.c index 6e656e5a9b..01d8c2b925 100644 --- a/drivers/mmc/tmio-common.c +++ b/drivers/mmc/tmio-common.c @@ -707,7 +707,7 @@ static void tmio_sd_host_init(struct tmio_sd_priv *priv) */ if (priv->version >= 0x10) { if (priv->caps & TMIO_SD_CAP_64BIT) - tmio_sd_writel(priv, 0x100, TMIO_SD_HOST_MODE); + tmio_sd_writel(priv, 0x000, TMIO_SD_HOST_MODE); else tmio_sd_writel(priv, 0x101, TMIO_SD_HOST_MODE); } else { diff --git a/drivers/net/macb.c b/drivers/net/macb.c index c9ee22279a..182331f61d 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -143,7 +143,7 @@ struct macb_device { static int macb_is_gem(struct macb_device *macb) { - return MACB_BFEXT(IDNUM, macb_readl(macb, MID)) == 0x2; + return MACB_BFEXT(IDNUM, macb_readl(macb, MID)) >= 0x2; } #ifndef cpu_is_sama5d2 @@ -1061,14 +1061,13 @@ static int macb_enable_clk(struct udevice *dev) return -EINVAL; /* - * Zynq clock driver didn't support for enable or disable - * clock. Hence, clk_enable() didn't apply for Zynq + * If clock driver didn't support enable or disable then + * we get -ENOSYS from clk_enable(). To handle this, we + * don't fail for ret == -ENOSYS. */ -#ifndef CONFIG_MACB_ZYNQ ret = clk_enable(&clk); - if (ret) + if (ret && ret != -ENOSYS) return ret; -#endif clk_rate = clk_get_rate(&clk); if (!clk_rate) diff --git a/drivers/pinctrl/renesas/Kconfig b/drivers/pinctrl/renesas/Kconfig index 1baab9088a..0cb577037c 100644 --- a/drivers/pinctrl/renesas/Kconfig +++ b/drivers/pinctrl/renesas/Kconfig @@ -8,7 +8,6 @@ config PINCTRL_PFC config PINCTRL_PFC_R8A7790 bool "Renesas RCar Gen2 R8A7790 pin control driver" - def_bool y if R8A7790 depends on PINCTRL_PFC help Support pin multiplexing control on Renesas RCar Gen3 R8A7790 SoCs. @@ -19,7 +18,6 @@ config PINCTRL_PFC_R8A7790 config PINCTRL_PFC_R8A7791 bool "Renesas RCar Gen2 R8A7791 pin control driver" - def_bool y if R8A7791 depends on PINCTRL_PFC help Support pin multiplexing control on Renesas RCar Gen3 R8A7791 SoCs. @@ -30,7 +28,6 @@ config PINCTRL_PFC_R8A7791 config PINCTRL_PFC_R8A7792 bool "Renesas RCar Gen2 R8A7792 pin control driver" - def_bool y if R8A7792 depends on PINCTRL_PFC help Support pin multiplexing control on Renesas RCar Gen3 R8A7792 SoCs. @@ -41,7 +38,6 @@ config PINCTRL_PFC_R8A7792 config PINCTRL_PFC_R8A7793 bool "Renesas RCar Gen2 R8A7793 pin control driver" - def_bool y if R8A7793 depends on PINCTRL_PFC help Support pin multiplexing control on Renesas RCar Gen3 R8A7793 SoCs. @@ -52,7 +48,6 @@ config PINCTRL_PFC_R8A7793 config PINCTRL_PFC_R8A7794 bool "Renesas RCar Gen2 R8A7794 pin control driver" - def_bool y if R8A7794 depends on PINCTRL_PFC help Support pin multiplexing control on Renesas RCar Gen3 R8A7794 SoCs. @@ -63,7 +58,6 @@ config PINCTRL_PFC_R8A7794 config PINCTRL_PFC_R8A7795 bool "Renesas RCar Gen3 R8A7795 pin control driver" - def_bool y if R8A7795 depends on PINCTRL_PFC help Support pin multiplexing control on Renesas RCar Gen3 R8A7795 SoCs. @@ -74,7 +68,6 @@ config PINCTRL_PFC_R8A7795 config PINCTRL_PFC_R8A7796 bool "Renesas RCar Gen3 R8A7796 pin control driver" - def_bool y if R8A7796 depends on PINCTRL_PFC help Support pin multiplexing control on Renesas RCar Gen3 R8A7796 SoCs. @@ -85,7 +78,6 @@ config PINCTRL_PFC_R8A7796 config PINCTRL_PFC_R8A77970 bool "Renesas RCar Gen3 R8A77970 pin control driver" - def_bool y if R8A77970 depends on PINCTRL_PFC help Support pin multiplexing control on Renesas RCar Gen3 R8A77970 SoCs. @@ -96,7 +88,6 @@ config PINCTRL_PFC_R8A77970 config PINCTRL_PFC_R8A77990 bool "Renesas RCar Gen3 R8A77990 pin control driver" - def_bool y if R8A77990 depends on PINCTRL_PFC help Support pin multiplexing control on Renesas RCar Gen3 R8A77990 SoCs. @@ -107,7 +98,6 @@ config PINCTRL_PFC_R8A77990 config PINCTRL_PFC_R8A77995 bool "Renesas RCar Gen3 R8A77995 pin control driver" - def_bool y if R8A77995 depends on PINCTRL_PFC help Support pin multiplexing control on Renesas RCar Gen3 R8A77995 SoCs. diff --git a/drivers/serial/serial_sifive.c b/drivers/serial/serial_sifive.c index 341728a690..537bc7a975 100644 --- a/drivers/serial/serial_sifive.c +++ b/drivers/serial/serial_sifive.c @@ -33,16 +33,40 @@ struct uart_sifive { }; struct sifive_uart_platdata { - unsigned int clock; + unsigned long clock; int saved_input_char; struct uart_sifive *regs; }; +/** + * Find minimum divisor divides in_freq to max_target_hz; + * Based on uart driver n SiFive FSBL. + * + * f_baud = f_in / (div + 1) => div = (f_in / f_baud) - 1 + * The nearest integer solution requires rounding up as to not exceed + * max_target_hz. + * div = ceil(f_in / f_baud) - 1 + * = floor((f_in - 1 + f_baud) / f_baud) - 1 + * This should not overflow as long as (f_in - 1 + f_baud) does not exceed + * 2^32 - 1, which is unlikely since we represent frequencies in kHz. + */ +static inline unsigned int uart_min_clk_divisor(unsigned long in_freq, + unsigned long max_target_hz) +{ + unsigned long quotient = + (in_freq + max_target_hz - 1) / (max_target_hz); + /* Avoid underflow */ + if (quotient == 0) + return 0; + else + return quotient - 1; +} + /* Set up the baud rate in gd struct */ static void _sifive_serial_setbrg(struct uart_sifive *regs, unsigned long clock, unsigned long baud) { - writel((u32)((clock / baud) - 1), ®s->div); + writel((uart_min_clk_divisor(clock, baud)), ®s->div); } static void _sifive_serial_init(struct uart_sifive *regs) @@ -75,27 +99,27 @@ static int _sifive_serial_getc(struct uart_sifive *regs) static int sifive_serial_setbrg(struct udevice *dev, int baudrate) { - int err; + int ret; struct clk clk; struct sifive_uart_platdata *platdata = dev_get_platdata(dev); + u32 clock = 0; - err = clk_get_by_index(dev, 0, &clk); - if (!err) { - err = clk_get_rate(&clk); - if (!IS_ERR_VALUE(err)) - platdata->clock = err; - } else if (err != -ENOENT && err != -ENODEV && err != -ENOSYS) { + ret = clk_get_by_index(dev, 0, &clk); + if (IS_ERR_VALUE(ret)) { debug("SiFive UART failed to get clock\n"); - return err; - } - - if (!platdata->clock) - platdata->clock = dev_read_u32_default(dev, "clock-frequency", 0); - if (!platdata->clock) { - debug("SiFive UART clock not defined\n"); - return -EINVAL; + ret = dev_read_u32(dev, "clock-frequency", &clock); + if (IS_ERR_VALUE(ret)) { + debug("SiFive UART clock not defined\n"); + return 0; + } + } else { + clock = clk_get_rate(&clk); + if (IS_ERR_VALUE(clock)) { + debug("SiFive UART clock get rate failed\n"); + return 0; + } } - + platdata->clock = clock; _sifive_serial_setbrg(platdata->regs, platdata->clock, baudrate); return 0; diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c index c7fcf050a5..ff4c700645 100644 --- a/drivers/spi/omap3_spi.c +++ b/drivers/spi/omap3_spi.c @@ -415,7 +415,7 @@ static void _omap3_spi_set_wordlen(struct omap3_spi_priv *priv) unsigned int confr; /* McSPI individual channel configuration */ - confr = readl(&priv->regs->channel[priv->wordlen].chconf); + confr = readl(&priv->regs->channel[priv->cs].chconf); /* wordlength */ confr &= ~OMAP3_MCSPI_CHCONF_WL_MASK; diff --git a/dts/Makefile b/dts/Makefile index a7a604303c..4970223b3d 100644 --- a/dts/Makefile +++ b/dts/Makefile @@ -40,6 +40,7 @@ endif echo >&2; \ /bin/false) +PHONY += arch-dtbs arch-dtbs: $(Q)$(MAKE) $(build)=$(ARCH_PATH) dtbs diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c index 3272412ca9..852f874e58 100644 --- a/fs/fat/fat_write.c +++ b/fs/fat/fat_write.c @@ -696,11 +696,11 @@ static int set_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos, __u8 *buffer, loff_t maxsize, loff_t *gotsize) { - loff_t filesize; unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; __u32 curclust = START(dentptr); __u32 endclust = 0, newclust = 0; - loff_t cur_pos, offset, actsize, wsize; + u64 cur_pos, filesize; + loff_t offset, actsize, wsize; *gotsize = 0; filesize = pos + maxsize; @@ -828,7 +828,7 @@ set_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos, __u8 *buffer, curclust = endclust; filesize -= cur_pos; - assert(!(cur_pos % bytesperclust)); + assert(!do_div(cur_pos, bytesperclust)); set_clusters: /* allocate and write */ diff --git a/include/command.h b/include/command.h index 461b17447c..2e24e8ad3e 100644 --- a/include/command.h +++ b/include/command.h @@ -139,6 +139,14 @@ extern int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] extern unsigned long do_go_exec(ulong (*entry)(int, char * const []), int argc, char * const argv[]); + +#if defined(CONFIG_CMD_NVEDIT_EFI) +extern int do_env_print_efi(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]); +extern int do_env_set_efi(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]); +#endif + /* * Error codes that commands return to cmd_process(). We use the standard 0 * and 1 for success and failure, but add one more case - failure with a diff --git a/include/configs/sifive-fu540.h b/include/configs/sifive-fu540.h new file mode 100644 index 0000000000..7007b5f6af --- /dev/null +++ b/include/configs/sifive-fu540.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2019 Western Digital Corporation or its affiliates. + * + * Authors: + * Anup Patel <anup.patel@wdc.com> + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#include <linux/sizes.h> + +#define CONFIG_SYS_SDRAM_BASE 0x80000000 +#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + SZ_2M) + +#define CONFIG_SYS_LOAD_ADDR (CONFIG_SYS_SDRAM_BASE + SZ_2M) + +#define CONFIG_SYS_MALLOC_LEN SZ_8M + +#define CONFIG_SYS_BOOTM_LEN SZ_16M + +#define CONFIG_STANDALONE_LOAD_ADDR 0x80200000 + +/* Environment options */ +#define CONFIG_ENV_SIZE SZ_4K + +#define BOOT_TARGET_DEVICES(func) \ + func(DHCP, dhcp, na) + +#include <config_distro_bootcmd.h> + +#define CONFIG_EXTRA_ENV_SETTINGS \ + "fdt_high=0xffffffffffffffff\0" \ + "initrd_high=0xffffffffffffffff\0" \ + "kernel_addr_r=0x80600000\0" \ + "fdt_addr_r=0x82200000\0" \ + "scriptaddr=0x82300000\0" \ + "pxefile_addr_r=0x82400000\0" \ + "ramdisk_addr_r=0x82500000\0" \ + BOOTENV + +#endif /* __CONFIG_H */ diff --git a/include/dt-bindings/clk/sifive-fu540-prci.h b/include/dt-bindings/clk/sifive-fu540-prci.h new file mode 100644 index 0000000000..531523ea62 --- /dev/null +++ b/include/dt-bindings/clk/sifive-fu540-prci.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019 Western Digital Corporation or its affiliates. + * + * Copyright (C) 2018 SiFive, Inc. + * Wesley Terpstra + * Paul Walmsley + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __LINUX_CLK_SIFIVE_FU540_PRCI_H +#define __LINUX_CLK_SIFIVE_FU540_PRCI_H + +/* Clock indexes for use by Device Tree data */ + +#define PRCI_CLK_COREPLL 0 +#define PRCI_CLK_DDRPLL 1 +#define PRCI_CLK_GEMGXLPLL 2 +#define PRCI_CLK_TLCLK 3 + +#endif diff --git a/include/efi_api.h b/include/efi_api.h index 45ca05e8ac..ccf608653d 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -1438,4 +1438,13 @@ struct efi_unicode_collation_protocol { char *supported_languages; }; +/* Boot manager load options */ +#define LOAD_OPTION_ACTIVE 0x00000001 +#define LOAD_OPTION_FORCE_RECONNECT 0x00000002 +#define LOAD_OPTION_HIDDEN 0x00000008 +/* All values 0x00000200-0x00001F00 are reserved */ +#define LOAD_OPTION_CATEGORY 0x00001F00 +#define LOAD_OPTION_CATEGORY_BOOT 0x00000000 +#define LOAD_OPTION_CATEGORY_APP 0x00000100 + #endif diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c index 196116b547..417016102b 100644 --- a/lib/efi_loader/efi_bootmgr.c +++ b/lib/efi_loader/efi_bootmgr.c @@ -14,10 +14,6 @@ static const struct efi_boot_services *bs; static const struct efi_runtime_services *rs; -#define LOAD_OPTION_ACTIVE 0x00000001 -#define LOAD_OPTION_FORCE_RECONNECT 0x00000002 -#define LOAD_OPTION_HIDDEN 0x00000008 - /* * bootmgr implements the logic of trying to find a payload to boot * based on the BootOrder + BootXXXX variables, and then loading it. @@ -178,14 +174,14 @@ void *efi_bootmgr_load(struct efi_device_path **device_path, void *image = NULL; int i, num; - __efi_entry_check(); - bs = systab.boottime; rs = systab.runtime; bootorder = get_var(L"BootOrder", &efi_global_variable_guid, &size); - if (!bootorder) + if (!bootorder) { + printf("BootOrder not defined\n"); goto error; + } num = size / sizeof(uint16_t); for (i = 0; i < num; i++) { @@ -198,7 +194,5 @@ void *efi_bootmgr_load(struct efi_device_path **device_path, free(bootorder); error: - __efi_exit_check(); - return image; } diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 704d644f6f..ec5c41ec56 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -301,7 +301,8 @@ cmd_dtc = mkdir -p $(dir ${dtc-tmp}) ; \ $(DTC) -O dtb -o $@ -b 0 \ -i $(dir $<) $(DTC_FLAGS) \ -d $(depfile).dtc.tmp $(dtc-tmp) ; \ - cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile) + cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile) ; \ + sed -i "s:$(pre-tmp):$(<):" $(depfile) $(obj)/%.dtb: $(src)/%.dts FORCE $(call if_changed_dep,dtc) diff --git a/test/dm/clk.c b/test/dm/clk.c index 898c034e27..112d5cbbc9 100644 --- a/test/dm/clk.c +++ b/test/dm/clk.c @@ -12,12 +12,15 @@ static int dm_test_clk(struct unit_test_state *uts) { - struct udevice *dev_fixed, *dev_clk, *dev_test; + struct udevice *dev_fixed, *dev_fixed_factor, *dev_clk, *dev_test; ulong rate; ut_assertok(uclass_get_device_by_name(UCLASS_CLK, "clk-fixed", &dev_fixed)); + ut_assertok(uclass_get_device_by_name(UCLASS_CLK, "clk-fixed-factor", + &dev_fixed_factor)); + ut_assertok(uclass_get_device_by_name(UCLASS_CLK, "clk-sbox", &dev_clk)); ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_SPI)); |