diff options
50 files changed, 1061 insertions, 252 deletions
diff --git a/Documentation/devel/porting.rst b/Documentation/devel/porting.rst index 8af0456ab2..619c5e49e0 100644 --- a/Documentation/devel/porting.rst +++ b/Documentation/devel/porting.rst @@ -258,7 +258,7 @@ tree binding, you can write a driver that matches against your board's { /* sentinel */ }, }; - static struct driver_d my_board_driver = { + static struct driver my_board_driver = { .name = "board-mine", .probe = my_board_probe, .of_compatible = my_board_of_match, diff --git a/Documentation/user/booting-linux.rst b/Documentation/user/booting-linux.rst index 60babb513c..1a95f87e77 100644 --- a/Documentation/user/booting-linux.rst +++ b/Documentation/user/booting-linux.rst @@ -232,6 +232,8 @@ device where the entry is found on. This makes it possible to use the same rootf image on different devices without having to specify a different root= option each time. +.. _booting_linux_net: + Network boot ------------ diff --git a/Documentation/user/networking.rst b/Documentation/user/networking.rst index 9231ebde56..2306cb6a60 100644 --- a/Documentation/user/networking.rst +++ b/Documentation/user/networking.rst @@ -45,15 +45,17 @@ device: | | | any directly visible subnet. May be set | | | | automatically by DHCP. | +------------------------------+--------------+------------------------------------------------+ -| global.net.server | hostname or | The default server. If unspecified, may be set | -| | ipv4 address | by DHCP | +| global.net.server | hostname or | The default server used by the defaultenv boot | +| | ipv4 address | scripts for NFS and TFTP; see | +| | | :ref:`booting_linux_net`. | +| | | If unspecified, may be set by DHCP. | +------------------------------+--------------+------------------------------------------------+ | global.net.nameserver | ipv4 address | The DNS server used for resolving host names. | -| | | May be set by DHCP | +| | | May be set by DHCP. | +------------------------------+--------------+------------------------------------------------+ | global.net.ifup_force_detect | boolean | Set to true if your network device is not | | | | detected automatically during start (i.e. for | -| | | USB network adapters) | +| | | USB network adapters). | +------------------------------+--------------+------------------------------------------------+ The first step for networking is configuring the network device. The network diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 759b29ee77..8183f6d546 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -292,6 +292,7 @@ config ARCH_ARM64_VIRT select ARM_AMBA select BOARD_ARM_VIRT select HW_HAS_PCI + select HAS_ASM_DEBUG_LL endchoice diff --git a/arch/arm/cpu/board-dt-2nd.c b/arch/arm/cpu/board-dt-2nd.c index 6f4a6f26a8..6f69a6dd27 100644 --- a/arch/arm/cpu/board-dt-2nd.c +++ b/arch/arm/cpu/board-dt-2nd.c @@ -19,6 +19,8 @@ void dt_2nd_aarch64(void *fdt) { unsigned long membase, memsize; + putc_ll('>'); + /* entry point already set up stack */ arm_cpu_lowlevel_init(); diff --git a/arch/arm/include/asm/debug_ll.h b/arch/arm/include/asm/debug_ll.h new file mode 100644 index 0000000000..d7b25a7fca --- /dev/null +++ b/arch/arm/include/asm/debug_ll.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __ASM_DEBUG_LL_H__ +#define __ASM_DEBUG_LL_H__ + +#ifdef CONFIG_DEBUG_QEMU_ARM64_VIRT +#define DEBUG_LL_UART_ADDR 0x9000000 +#include <debug_ll/pl011.h> +#endif + +#endif diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 279db046c0..1371f17e7c 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -5,21 +5,27 @@ KBUILD_DEFCONFIG := rv64i_defconfig KBUILD_CPPFLAGS += -fno-strict-aliasing ifeq ($(CONFIG_ARCH_RV32I),y) - riscv-cflags-y += -march=rv32im -mabi=ilp32 + KBUILD_CPPFLAGS += -mabi=ilp32 riscv-ldflags-y += -melf32lriscv else - riscv-cflags-y += -march=rv64im -mabi=lp64 + KBUILD_CPPFLAGS += -mabi=lp64 riscv-ldflags-y += -melf64lriscv endif -riscv-cflags-y += -Wstrict-prototypes -mcmodel=medany -fpic -riscv-ldflags-y += -pie -static +# ISA string setting +riscv-march-$(CONFIG_ARCH_RV32I) := rv32im +riscv-march-$(CONFIG_ARCH_RV64I) := rv64im -PBL_CPPFLAGS += $(riscv-cflags-y) -LDFLAGS_pbl += $(riscv-ldflags-y) +# Newer binutils versions default to ISA spec version 20191213 which moves some +# instructions from the I extension to the Zicsr and Zifencei extensions. +toolchain-need-zicsr-zifencei := $(call cc-option-yn, -march=$(riscv-march-y)_zicsr_zifencei) +riscv-march-$(toolchain-need-zicsr-zifencei) := $(riscv-march-y)_zicsr_zifencei -cflags-y += $(riscv-cflags-y) +KBUILD_CPPFLAGS += -march=$(riscv-march-y) +KBUILD_CPPFLAGS += -Wstrict-prototypes -mcmodel=medany -fpic +riscv-ldflags-y += -pie -static +LDFLAGS_pbl += $(riscv-ldflags-y) LDFLAGS_barebox += $(riscv-ldflags-y) ifndef CONFIG_MODULES @@ -29,6 +35,7 @@ LDFLAGS_barebox += -static --gc-sections endif KBUILD_BINARY := barebox.bin +KBUILD_IMAGE := $(KBUILD_BINARY) archprepare: maketools @@ -41,11 +48,6 @@ common-y += arch/riscv/boot/ common-$(CONFIG_OFTREE) += arch/riscv/dts/ -KBUILD_CPPFLAGS += $(cflags-y) -KBUILD_CFLAGS += $(cflags-y) - lds-y := arch/riscv/lib/barebox.lds CLEAN_FILES += arch/riscv/lib/barebox.lds - -KBUILD_IMAGE := $(KBUILD_BINARY) diff --git a/arch/riscv/boards/riscvemu/overlay-of-sram.dts b/arch/riscv/boards/riscvemu/overlay-of-sram.dts index 506d45bde9..395fde84c1 100644 --- a/arch/riscv/boards/riscvemu/overlay-of-sram.dts +++ b/arch/riscv/boards/riscvemu/overlay-of-sram.dts @@ -3,127 +3,110 @@ /dts-v1/; /plugin/; -/ { - fragment@0 { - target-path = "/soc"; - __overlay__ { - #address-cells = <2>; - #size-cells = <2>; - sram@0 { - compatible = "mtd-ram"; - reg = <0 0x1000 0 0x10000>; - #address-cells = <1>; - #size-cells = <1>; +&{/soc} { + #address-cells = <2>; + #size-cells = <2>; + sram@1000 { + compatible = "mtd-ram"; + reg = <0 0x1000 0 0x10000>; + #address-cells = <1>; + #size-cells = <1>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "bootrom"; + reg = <0x0 0x40>; + }; - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - partition@0 { - label = "bootrom"; - reg = <0x0 0x40>; - }; - - partition@40 { - label = "fdt"; - reg = <0x40 0x1fc0>; - }; - - environment_sram: partition@3000 { - label = "barebox-environment"; - reg = <0x3000 0xb000>; - }; - - backend_state_sram: partition@e000 { - label = "barebox-state"; - reg = <0xe000 0x1000>; - }; - }; + partition@40 { + label = "fdt"; + reg = <0x40 0x1fc0>; + }; + + environment_sram: partition@3000 { + label = "barebox-environment"; + reg = <0x3000 0xb000>; }; - }; - }; - fragment@2 { - target-path = "/chosen"; - __overlay__ { - environment { - compatible = "barebox,environment"; - device-path = "/soc/sram@0/partitions/partition@3000"; + backend_state_sram: partition@e000 { + label = "barebox-state"; + reg = <0xe000 0x1000>; }; }; }; +}; - fragment@3 { - target-path = "/"; - __overlay__ { - aliases { - state = "/state"; - }; +&{/chosen} { + environment { + compatible = "barebox,environment"; + device-path = "/soc/sram@1000/partitions/partition@3000"; + }; +}; + +&{/} { + aliases { + state = "/state"; + }; + + state { + #address-cells = <1>; + #size-cells = <1>; + compatible = "barebox,state"; + magic = <0x290cf8c6>; + backend-type = "raw"; + backend = <&backend_state_sram>; + backend-stridesize = <64>; + + bootstate { + #address-cells = <1>; + #size-cells = <1>; - state { + system0 { #address-cells = <1>; #size-cells = <1>; - compatible = "barebox,state"; - magic = <0x290cf8c6>; - backend-type = "raw"; - backend = <&backend_state_sram>; - backend-stridesize = <64>; - - bootstate { - #address-cells = <1>; - #size-cells = <1>; - - system0 { - #address-cells = <1>; - #size-cells = <1>; - - remaining_attempts@0 { - reg = <0x0 0x4>; - type = "uint32"; - default = <3>; - }; - - priority@4 { - reg = <0x4 0x4>; - type = "uint32"; - default = <20>; - }; - }; - - system1 { - #address-cells = <1>; - #size-cells = <1>; - - remaining_attempts@8 { - reg = <0x8 0x4>; - type = "uint32"; - default = <3>; - }; - - priority@c { - reg = <0xc 0x4>; - type = "uint32"; - default = <21>; - }; - }; - - last_chosen@10 { - reg = <0x10 0x4>; - type = "uint32"; - }; + + remaining_attempts@0 { + reg = <0x0 0x4>; + type = "uint32"; + default = <3>; + }; + + priority@4 { + reg = <0x4 0x4>; + type = "uint32"; + default = <20>; }; }; - }; - }; - fragment@4 { - target-path = "/htif"; - #address-cells = <2>; - #size-cells = <2>; + system1 { + #address-cells = <1>; + #size-cells = <1>; - __overlay__ { - reg = <0 0x40008000 0 0x8>; + remaining_attempts@8 { + reg = <0x8 0x4>; + type = "uint32"; + default = <3>; + }; + + priority@c { + reg = <0xc 0x4>; + type = "uint32"; + default = <21>; + }; + }; + + last_chosen@10 { + reg = <0x10 0x4>; + type = "uint32"; + }; }; }; }; + +&{/htif} { + reg = <0 0x40008000 0 0x8>; +}; diff --git a/common/Kconfig b/common/Kconfig index 9e175d36c4..d957970993 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -1479,6 +1479,10 @@ config DEBUG_SUN20I depends on SOC_ALLWINNER_SUN20I select DEBUG_LL_NS16550 +config DEBUG_QEMU_ARM64_VIRT + bool "QEMU ARM64 Virt PL011 console" + depends on ARCH_ARM64_VIRT + endchoice config DEBUG_LL_NS16550 diff --git a/common/boards/qemu-virt/overlay-of-flash.dts b/common/boards/qemu-virt/overlay-of-flash.dts index 3f2beaac37..15c8cc450d 100644 --- a/common/boards/qemu-virt/overlay-of-flash.dts +++ b/common/boards/qemu-virt/overlay-of-flash.dts @@ -4,110 +4,99 @@ /plugin/; #ifdef RISCV_VIRT -#define PARTS_TARGET_PATH "/flash@20000000" +#define PARTS_TARGET_PATH /flash@20000000 #define ENV_DEVICE_PATH "/flash@20000000/partitions/partition@3c00000" #else -#define PARTS_TARGET_PATH "/flash@0" +#define PARTS_TARGET_PATH /flash@0 #define ENV_DEVICE_PATH "/flash@0/partitions/partition@3c00000" #endif -/ { - fragment@0 { - target-path = PARTS_TARGET_PATH; - __overlay__ { - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; +&{PARTS_TARGET_PATH} { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; - partition@0 { - label = "initramfs"; - reg = <0x0 0x3c00000>; - }; + partition@0 { + label = "initramfs"; + reg = <0x0 0x3c00000>; + }; - environment_flash: partition@3c00000 { - label = "barebox-environment"; - reg = <0x3c00000 0x200000>; - }; + environment_flash: partition@3c00000 { + label = "barebox-environment"; + reg = <0x3c00000 0x200000>; + }; - backend_state_flash: partition@3e00000 { - label = "barebox-state"; - reg = <0x3e00000 0x200000>; - }; - }; + backend_state_flash: partition@3e00000 { + label = "barebox-state"; + reg = <0x3e00000 0x200000>; }; }; +}; - fragment@1 { - target-path = "/chosen"; - __overlay__ { - environment { - compatible = "barebox,environment"; - device-path = ENV_DEVICE_PATH; - }; - }; +&{/chosen} { + environment { + compatible = "barebox,environment"; + device-path = ENV_DEVICE_PATH; + }; +}; + +&{/} { + aliases { + state = "/state"; }; - fragment@2 { - target-path = "/"; - __overlay__ { - aliases { - state = "/state"; + state { + #address-cells = <1>; + #size-cells = <1>; + compatible = "barebox,state"; + magic = <0x290cf8c6>; + backend-type = "raw"; + backend = < &backend_state_flash >; + backend-stridesize = <0x200>; + + bootstate { + #address-cells = <1>; + #size-cells = <1>; + + system0 { + #address-cells = <1>; + #size-cells = <1>; + + remaining_attempts@0 { + reg = <0x0 0x4>; + type = "uint32"; + default = <3>; + }; + + priority@4 { + reg = <0x4 0x4>; + type = "uint32"; + default = <20>; + }; }; - state { + system1 { #address-cells = <1>; #size-cells = <1>; - compatible = "barebox,state"; - magic = <0x290cf8c6>; - backend-type = "raw"; - backend = < &backend_state_flash >; - backend-stridesize = <0x200>; - - bootstate { - #address-cells = <1>; - #size-cells = <1>; - - system0 { - #address-cells = <1>; - #size-cells = <1>; - - remaining_attempts@0 { - reg = <0x0 0x4>; - type = "uint32"; - default = <3>; - }; - - priority@4 { - reg = <0x4 0x4>; - type = "uint32"; - default = <20>; - }; - }; - - system1 { - #address-cells = <1>; - #size-cells = <1>; - - remaining_attempts@8 { - reg = <0x8 0x4>; - type = "uint32"; - default = <3>; - }; - - priority@c { - reg = <0xc 0x4>; - type = "uint32"; - default = <21>; - }; - }; - - last_chosen@10 { - reg = <0x10 0x4>; - type = "uint32"; - }; + + remaining_attempts@8 { + reg = <0x8 0x4>; + type = "uint32"; + default = <3>; + }; + + priority@c { + reg = <0xc 0x4>; + type = "uint32"; + default = <21>; }; }; + + last_chosen@10 { + reg = <0x10 0x4>; + type = "uint32"; + }; }; }; }; diff --git a/drivers/dma/map.c b/drivers/dma/map.c index a00abf6421..114c0f7db3 100644 --- a/drivers/dma/map.c +++ b/drivers/dma/map.c @@ -2,26 +2,22 @@ /* SPDX-FileCopyrightText: 2012 Marc Kleine-Budde <mkl@pengutronix.de> */ #include <dma.h> +#include <asm/io.h> -static inline dma_addr_t cpu_to_dma(struct device *dev, - unsigned long cpu_addr) +static inline dma_addr_t cpu_to_dma(struct device *dev, void *cpu_addr) { - dma_addr_t dma_addr = cpu_addr; + if (dev && dev->dma_offset) + return (unsigned long)cpu_addr - dev->dma_offset; - if (dev) - dma_addr -= dev->dma_offset; - - return dma_addr; + return virt_to_phys(cpu_addr); } -static inline unsigned long dma_to_cpu(struct device *dev, dma_addr_t addr) +static inline void *dma_to_cpu(struct device *dev, dma_addr_t addr) { - unsigned long cpu_addr = addr; - - if (dev) - cpu_addr += dev->dma_offset; + if (dev && dev->dma_offset) + return (void *)(addr + dev->dma_offset); - return cpu_addr; + return phys_to_virt(addr); } dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, @@ -31,13 +27,13 @@ dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, dma_sync_single_for_device(addr, size, dir); - return cpu_to_dma(dev, addr); + return cpu_to_dma(dev, ptr); } void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction dir) { - unsigned long addr = dma_to_cpu(dev, dma_addr); + unsigned long addr = (unsigned long)dma_to_cpu(dev, dma_addr); dma_sync_single_for_cpu(addr, size, dir); } diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index d3cca41a7e..a6c564320e 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -32,4 +32,14 @@ config ARM_SCMI_PROTOCOL set of operating system-independent software interfaces that are used in system management. +config QEMU_FW_CFG + bool "QEMU FW CFG interface" + help + This driver exposes the QEMU FW CFG conduit as a single + character device. + + The selector key can be set via ioctl or device parameter + and read/writes are translated to the MMIO/IO port appropriate + for the platform. + endmenu diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 26d6f3275a..90f5113f53 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -2,4 +2,5 @@ obj-$(CONFIG_FIRMWARE_ALTERA_SERIAL) += altera_serial.o obj-$(CONFIG_FIRMWARE_ALTERA_SOCFPGA) += socfpga.o socfpga_sdr.o obj-$(CONFIG_FIRMWARE_ZYNQMP_FPGA) += zynqmp-fpga.o +obj-$(CONFIG_QEMU_FW_CFG) += qemu_fw_cfg.o obj-y += arm_scmi/ diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c new file mode 100644 index 0000000000..3fad90bbde --- /dev/null +++ b/drivers/firmware/qemu_fw_cfg.c @@ -0,0 +1,307 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * qemu_fw_cfg.c - QEMU FW CFG character device + * + * Copyright (C) 2022 Adrian Negreanu + * Copyright (C) 2022 Ahmad Fatoum + */ + +#include <common.h> +#include <driver.h> +#include <init.h> +#include <fcntl.h> +#include <dma.h> +#include <linux/err.h> +#include <linux/bitfield.h> +#include <linux/qemu_fw_cfg.h> +#include <asm/unaligned.h> +#include <io-64-nonatomic-lo-hi.h> + +/* arch-specific ctrl & data register offsets are not available in ACPI, DT */ +#ifdef CONFIG_X86 +# define FW_CFG_CTRL_OFF 0x00 +# define FW_CFG_DATA_OFF 0x01 +# define FW_CFG_DMA_OFF 0x04 +#else +# define FW_CFG_CTRL_OFF 0x08 +# define FW_CFG_DATA_OFF 0x00 +# define FW_CFG_DMA_OFF 0x10 +#endif + +/* fw_cfg DMA commands */ +#define FW_CFG_DMA_CTL_ERROR 0x01 +#define FW_CFG_DMA_CTL_READ 0x02 +#define FW_CFG_DMA_CTL_SKIP 0x04 +#define FW_CFG_DMA_CTL_SELECT 0x08 +#define FW_CFG_DMA_CTL_WRITE 0x10 + +struct fw_cfg_dma { + __be32 control; + __be32 length; + __be64 address; +} __packed; + +/* fw_cfg device i/o register addresses */ +struct fw_cfg { + struct resource *iores; + void __iomem *reg_ctrl; + void __iomem *reg_data; + void __iomem *reg_dma; + struct cdev cdev; + loff_t next_read_offset; + u32 sel; + bool is_mmio; + struct fw_cfg_dma __iomem *acc_virt; + dma_addr_t acc_dma; +}; + +static struct fw_cfg *to_fw_cfg(struct cdev *cdev) +{ + return container_of(cdev, struct fw_cfg, cdev); +} + +/* pick appropriate endianness for selector key */ +static void fw_cfg_select(struct fw_cfg *fw_cfg) +{ + if (fw_cfg->is_mmio) + iowrite16be(fw_cfg->sel, fw_cfg->reg_ctrl); + else + iowrite16(fw_cfg->sel, fw_cfg->reg_ctrl); +} + +/* clean up fw_cfg device i/o */ +static void fw_cfg_io_cleanup(struct fw_cfg *fw_cfg) +{ + release_region(fw_cfg->iores); +} + +static int fw_cfg_ioctl(struct cdev *cdev, int request, void *buf) +{ + struct fw_cfg *fw_cfg = to_fw_cfg(cdev); + int ret = 0; + + switch (request) { + case FW_CFG_SELECT: + fw_cfg->sel = *(u16 *)buf; + break; + default: + ret = -ENOTTY; + } + + return 0; +} + +#define __raw_readu64 __raw_readq +#define __raw_readu32 __raw_readl +#define __raw_readu16 __raw_readw +#define __raw_readu8 __raw_readb + +#define fw_cfg_data_read_sized(fw_cfg, remaining, address, type) do { \ + while (*remaining >= sizeof(type)) { \ + val = __raw_read##type((fw_cfg)->reg_data); \ + *remaining -= sizeof(type); \ + if (*address) { \ + put_unaligned(val, (type *)*address); \ + *address += sizeof(type); \ + } \ + } \ +} while(0) + +static void fw_cfg_data_read(struct fw_cfg *fw_cfg, void *address, size_t remaining, + unsigned rdsize) +{ + + u64 val; + + if (fw_cfg->is_mmio) { + /* + * This is just a preference. If we can't honour it, we + * fall back to byte-sized copy + */ + switch(rdsize) { + case 8: +#ifdef CONFIG_64BIT + fw_cfg_data_read_sized(fw_cfg, &remaining, &address, u64); + break; +#endif + case 4: + fw_cfg_data_read_sized(fw_cfg, &remaining, &address, u32); + break; + case 2: + fw_cfg_data_read_sized(fw_cfg, &remaining, &address, u16); + break; + } + } + + fw_cfg_data_read_sized(fw_cfg, &remaining, &address, u8); +} + +static ssize_t fw_cfg_read(struct cdev *cdev, void *buf, size_t count, + loff_t pos, unsigned long flags) +{ + struct fw_cfg *fw_cfg = to_fw_cfg(cdev); + unsigned rdsize = FIELD_GET(O_RWSIZE_MASK, flags); + + if (!pos || pos != fw_cfg->next_read_offset) { + fw_cfg_select(fw_cfg); + fw_cfg->next_read_offset = 0; + } + + if (!rdsize) { + if (pos % 8 == 0) + rdsize = 8; + else if (pos % 4 == 0) + rdsize = 4; + else if (pos % 2 == 0) + rdsize = 2; + else + rdsize = 1; + } + + while (pos-- > fw_cfg->next_read_offset) + fw_cfg_data_read(fw_cfg, NULL, count, rdsize); + + fw_cfg_data_read(fw_cfg, buf, count, rdsize); + + fw_cfg->next_read_offset += count; + return count; +} + +static ssize_t fw_cfg_write(struct cdev *cdev, const void *buf, size_t count, + loff_t pos, unsigned long flags) +{ + struct fw_cfg *fw_cfg = to_fw_cfg(cdev); + struct device_d *dev = cdev->dev; + struct fw_cfg_dma __iomem *acc = fw_cfg->acc_virt; + dma_addr_t mapping; + + if (pos != 0) + return -EINVAL; + + mapping = dma_map_single(dev, (void *)buf, count, DMA_TO_DEVICE); + if (dma_mapping_error(dev, mapping)) + return -EFAULT; + + fw_cfg->next_read_offset = 0; + + acc->address = cpu_to_be64(mapping); + acc->length = cpu_to_be32(count); + acc->control = cpu_to_be32(FW_CFG_DMA_CTL_WRITE | + FW_CFG_DMA_CTL_SELECT | fw_cfg->sel << 16); + + iowrite64be(fw_cfg->acc_dma, fw_cfg->reg_dma); + + while (ioread32be(&acc->control) & ~FW_CFG_DMA_CTL_ERROR) + ; + + dma_unmap_single(dev, mapping, count, DMA_FROM_DEVICE); + + return count; +} + +static struct cdev_operations fw_cfg_ops = { + .read = fw_cfg_read, + .write = fw_cfg_write, + .ioctl = fw_cfg_ioctl, +}; + +static int fw_cfg_param_select(struct param_d *p, void *priv) +{ + struct fw_cfg *fw_cfg = priv; + + return fw_cfg->sel <= U16_MAX ? 0 : -EINVAL; +} + +static int fw_cfg_probe(struct device_d *dev) +{ + struct device_node *np = dev_of_node(dev); + struct resource *parent_res, *iores; + char sig[FW_CFG_SIG_SIZE]; + struct fw_cfg *fw_cfg; + int ret; + + fw_cfg = xzalloc(sizeof(*fw_cfg)); + + /* acquire i/o range details */ + fw_cfg->is_mmio = false; + iores = dev_get_resource(dev, IORESOURCE_IO, 0); + if (IS_ERR(iores)) { + fw_cfg->is_mmio = true; + iores = dev_get_resource(dev, IORESOURCE_MEM, 0); + if (IS_ERR(iores)) + return -EINVAL; + } + + parent_res = fw_cfg->is_mmio ? &iomem_resource : &ioport_resource; + iores = __request_region(parent_res, iores->start, iores->end, dev_name(dev), 0); + if (IS_ERR(iores)) + return -EBUSY; + + /* use architecture-specific offsets */ + fw_cfg->reg_ctrl = IOMEM(iores->start + FW_CFG_CTRL_OFF); + fw_cfg->reg_data = IOMEM(iores->start + FW_CFG_DATA_OFF); + fw_cfg->reg_dma = IOMEM(iores->start + FW_CFG_DMA_OFF); + + fw_cfg->iores = iores; + + /* verify fw_cfg device signature */ + fw_cfg->sel = FW_CFG_SIGNATURE; + fw_cfg_read(&fw_cfg->cdev, sig, FW_CFG_SIG_SIZE, 0, 0); + + if (memcmp(sig, "QEMU", FW_CFG_SIG_SIZE) != 0) { + ret = np ? -EILSEQ : -ENODEV; + goto err; + } + + fw_cfg->acc_virt = dma_alloc_coherent(sizeof(*fw_cfg->acc_virt), &fw_cfg->acc_dma); + + fw_cfg->cdev.name = basprintf("fw_cfg%d", cdev_find_free_index("fw_cfg")); + fw_cfg->cdev.flags = DEVFS_IS_CHARACTER_DEV; + fw_cfg->cdev.size = 0; + fw_cfg->cdev.ops = &fw_cfg_ops; + fw_cfg->cdev.dev = dev; + fw_cfg->cdev.filetype = filetype_qemu_fw_cfg; + + dev_set_name(dev, fw_cfg->cdev.name); + + ret = devfs_create(&fw_cfg->cdev); + if (ret) { + dev_err(dev, "Failed to create corresponding cdev\n"); + goto err; + } + + cdev_create_default_automount(&fw_cfg->cdev); + + dev_add_param_uint32(dev, "selector", fw_cfg_param_select, + NULL, &fw_cfg->sel, "%u", fw_cfg); + + dev->priv = fw_cfg; + + return 0; +err: + fw_cfg_io_cleanup(fw_cfg); + return ret; +} + +static const struct of_device_id qemu_fw_cfg_of_match[] = { + { .compatible = "qemu,fw-cfg-mmio", }, + { /* sentinel */ }, +}; + +static struct driver_d qemu_fw_cfg_drv = { + .name = "fw_cfg", + .probe = fw_cfg_probe, + .of_compatible = of_match_ptr(qemu_fw_cfg_of_match), +}; + +static int qemu_fw_cfg_init(void) +{ + int ret; + + ret = platform_driver_register(&qemu_fw_cfg_drv); + if (ret) + return ret; + + return of_devices_ensure_probed_by_dev_id(qemu_fw_cfg_of_match); +} +postmmu_initcall(qemu_fw_cfg_init); diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c index f3efb62087..efcad29342 100644 --- a/drivers/i2c/i2c.c +++ b/drivers/i2c/i2c.c @@ -473,6 +473,14 @@ int of_i2c_register_devices_by_node(struct device_node *node) static int i2c_bus_detect(struct device *dev) { + struct i2c_adapter *adap = container_of(dev, struct i2c_adapter, dev); + + of_i2c_register_devices(adap); + return 0; +} + +static int i2c_hw_detect(struct device *dev) +{ struct i2c_adapter *adap; list_for_each_entry(adap, &i2c_adapter_list, list) { @@ -712,6 +720,7 @@ int i2c_add_numbered_adapter(struct i2c_adapter *adapter) } adapter->dev.id = adapter->nr; + adapter->dev.detect = i2c_bus_detect; dev_set_name(&adapter->dev, "i2c"); ret = register_device(&adapter->dev); @@ -726,8 +735,8 @@ int i2c_add_numbered_adapter(struct i2c_adapter *adapter) hw_dev = adapter->dev.parent; if (hw_dev && dev_of_node(hw_dev)) { if (!hw_dev->detect) - hw_dev->detect = i2c_bus_detect; - i2c_bus_detect(hw_dev); + hw_dev->detect = i2c_hw_detect; + i2c_hw_detect(hw_dev); } return 0; diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c index e8e6903111..c7252ce72a 100644 --- a/drivers/mtd/nand/nand_omap_gpmc.c +++ b/drivers/mtd/nand/nand_omap_gpmc.c @@ -12,7 +12,7 @@ * A typical device registration is as follows: * * @code - * static struct device_d my_nand_device = { + * static struct device my_nand_device = { * .name = "gpmc_nand", * .id = some identifier you need to show.. e.g. "gpmc_nand0" * .resource[0].start = GPMC base address diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index d0fabc4247..a9fc073d57 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -240,7 +240,6 @@ config DRIVER_NET_ORION config DRIVER_NET_RTL8139 bool "RealTek RTL-8139 PCI Ethernet driver" depends on PCI - depends on MIPS select PHYLIB help This is a driver for the Fast Ethernet PCI network cards based on diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 558a4ac271..d440d7540a 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -2183,7 +2183,9 @@ struct e1000_hw { struct mii_bus miibus; struct e1000_tx_desc *tx_base; + dma_addr_t tx_base_phys; struct e1000_rx_desc *rx_base; + dma_addr_t rx_base_phys; unsigned char *packet; dma_addr_t packet_dma; diff --git a/drivers/net/e1000/main.c b/drivers/net/e1000/main.c index e00bc48417..c259d72f27 100644 --- a/drivers/net/e1000/main.c +++ b/drivers/net/e1000/main.c @@ -3267,7 +3267,7 @@ static void e1000_configure_tx(struct e1000_hw *hw) unsigned long tctl; unsigned long tipg, tarc; uint32_t ipgr1, ipgr2; - const unsigned long tx_base = (unsigned long)hw->tx_base; + const unsigned long tx_base = (unsigned long)hw->tx_base_phys; e1000_write_reg(hw, E1000_TDBAL, lower_32_bits(tx_base)); e1000_write_reg(hw, E1000_TDBAH, upper_32_bits(tx_base)); @@ -3386,7 +3386,7 @@ static void e1000_setup_rctl(struct e1000_hw *hw) static void e1000_configure_rx(struct e1000_hw *hw) { unsigned long rctl, ctrl_ext; - const unsigned long rx_base = (unsigned long)hw->rx_base; + const unsigned long rx_base = (unsigned long)hw->rx_base_phys; hw->rx_tail = 0; /* make sure receives are disabled while setting up the descriptors */ @@ -3595,8 +3595,8 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *id) hw = xzalloc(sizeof(*hw)); - hw->tx_base = dma_alloc_coherent(16 * sizeof(*hw->tx_base), DMA_ADDRESS_BROKEN); - hw->rx_base = dma_alloc_coherent(16 * sizeof(*hw->rx_base), DMA_ADDRESS_BROKEN); + hw->tx_base = dma_alloc_coherent(16 * sizeof(*hw->tx_base), &hw->tx_base_phys); + hw->rx_base = dma_alloc_coherent(16 * sizeof(*hw->rx_base), &hw->rx_base_phys); edev = &hw->edev; diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c index 972a127655..2120657bd9 100644 --- a/drivers/net/ks8851_mll.c +++ b/drivers/net/ks8851_mll.c @@ -353,7 +353,6 @@ * struct ks_net - KS8851 driver private data * @hw_addr : start address of data register. * @hw_addr_cmd : start address of command register. - * @pdev : Pointer to platform device. * @bus_width : i/o bus width. * @extra_byte : number of extra byte prepended rx pkt. * @@ -364,7 +363,6 @@ struct ks_net { struct mii_bus miibus; void __iomem *hw_addr; void __iomem *hw_addr_cmd; - struct platform_device *pdev; int bus_width; void *rx_buf; }; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 2c3a96bfc5..54dbbca725 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -20,8 +20,6 @@ #include <linux/phy.h> #include <linux/err.h> -#define PHY_AN_TIMEOUT 10 - static struct phy_driver genphy_driver; /** diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index 617a60bfcb..5c91c10fea 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -373,7 +373,6 @@ static int rtl8139_init_dev(struct eth_device *edev) struct rtl8139_priv *priv = edev->priv; rtl8139_chip_reset(priv); - pci_set_master(priv->pci_dev); return 0; } @@ -390,6 +389,8 @@ static int rtl8139_eth_open(struct eth_device *edev) rtl8139_init_ring(priv); rtl8139_hw_start(priv); + pci_set_master(priv->pci_dev); + ret = phy_device_connect(edev, &priv->miibus, 0, NULL, 0, PHY_INTERFACE_MODE_NA); @@ -408,6 +409,11 @@ static void rtl8139_eth_halt(struct eth_device *edev) pci_clear_master(priv->pci_dev); + dma_free_coherent((void *)priv->tx_bufs, priv->tx_bufs_dma, + TX_BUF_TOT_LEN); + dma_free_coherent((void *)priv->rx_ring, priv->rx_ring_dma, + RX_BUF_TOT_LEN); + /* Green! Put the chip in low-power mode. */ RTL_W8(priv, Cfg9346, Cfg9346_Unlock); } diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 79a5f9325e..bf9176ce09 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only #include <common.h> +#include <disks.h> #include "nvme.h" @@ -372,6 +373,10 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid) goto out_free_id; } + ret = parse_partition_table(&ns->blk); + if (ret) + dev_warn(ctrl->dev, "No partition table found\n"); + return; out_free_id: kfree(id); diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c index 189aab705d..e579fcaed6 100644 --- a/drivers/spi/atmel-quadspi.c +++ b/drivers/spi/atmel-quadspi.c @@ -157,7 +157,6 @@ struct atmel_qspi { void __iomem *mem; struct clk *pclk; struct clk *qspick; - struct platform_device *pdev; const struct atmel_qspi_caps *caps; u32 mr; }; diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index 399c47c81d..9bf85874c5 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c @@ -408,7 +408,7 @@ static int atmel_spi_probe(struct device *dev) master->num_chipselect = pdata->num_chipselect; as->cs_pins = pdata->chipselect; } else { - master->num_chipselect = of_gpio_named_count(node, "cs-gpios"); + master->num_chipselect = of_gpio_count_csgpios(node); as->cs_pins = xzalloc(sizeof(u32) * master->num_chipselect); for (i = 0; i < master->num_chipselect; i++) { diff --git a/drivers/spi/imx_spi.c b/drivers/spi/imx_spi.c index eb30d757d5..f81d9e851f 100644 --- a/drivers/spi/imx_spi.c +++ b/drivers/spi/imx_spi.c @@ -568,7 +568,7 @@ static int imx_spi_dt_probe(struct imx_spi *imx) if (!node) return -ENODEV; - imx->master.num_chipselect = of_gpio_named_count(node, "cs-gpios"); + imx->master.num_chipselect = of_gpio_count_csgpios(node); imx->cs_array = xzalloc(sizeof(u32) * imx->master.num_chipselect); for (i = 0; i < imx->master.num_chipselect; i++) diff --git a/drivers/spi/stm32_spi.c b/drivers/spi/stm32_spi.c index 821a95980f..0d7407c279 100644 --- a/drivers/spi/stm32_spi.c +++ b/drivers/spi/stm32_spi.c @@ -514,7 +514,7 @@ static void stm32_spi_dt_probe(struct stm32_spi_priv *priv) struct device_node *node = priv->master.dev->of_node; int i; - priv->master.num_chipselect = of_gpio_named_count(node, "cs-gpios"); + priv->master.num_chipselect = of_gpio_count_csgpios(node); priv->cs_gpios = xzalloc(sizeof(u32) * priv->master.num_chipselect); for (i = 0; i < priv->master.num_chipselect; i++) diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 7c589ec06f..a974614c06 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -576,6 +576,8 @@ int usb_host_detect(struct usb_host *host) { int ret; + of_usb_host_probe_hubs(host); + if (!host->root_dev) { if (host->init) { ret = host->init(host); diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 9799af4725..fde57fd743 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -14,3 +14,13 @@ config USB_HUB_USB251XB Microchip USB251x/xBi USB 2.0 Hub Controller series. Configuration parameters may be set in devicetree or platform data. Say Y or M here if you need to configure such a device via SMBus. + +config USB_ONBOARD_HUB + bool "Onboard USB hub support" + depends on OFDEVICE || COMPILE_TEST + help + Say Y here if you want to support discrete onboard USB hubs that + don't require an additional control bus for initialization, but + need some non-trivial form of initialization, such as enabling a + power regulator. An example for such a hub is the Realtek + RTS5411. diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index be5c044f5a..e00f66a5ed 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -4,3 +4,4 @@ # (the ones that don't fit into any other categories) # obj-$(CONFIG_USB_HUB_USB251XB) += usb251xb.o +obj-$(CONFIG_USB_ONBOARD_HUB) += onboard_usb_hub.o diff --git a/drivers/usb/misc/onboard_usb_hub.c b/drivers/usb/misc/onboard_usb_hub.c new file mode 100644 index 0000000000..0b847f06ad --- /dev/null +++ b/drivers/usb/misc/onboard_usb_hub.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for onboard USB hubs + * + * Copyright (c) 2022, Google LLC + */ + +#include <driver.h> +#include <gpiod.h> +#include <init.h> +#include <of.h> +#include <linux/printk.h> +#include <of_device.h> +#include <regulator.h> +#include <usb/usb.h> + +#include "onboard_usb_hub.h" + +void of_usb_host_probe_hubs(struct usb_host *host) +{ + struct device_node *np; + + np = dev_of_node(host->hw_dev); + if (!np) + return; + + of_platform_populate(np, onboard_hub_match, host->hw_dev); +} + +struct onboard_hub { + struct regulator *vdd; + struct device *dev; + const struct onboard_hub_pdata *pdata; + int reset_gpio; +}; + +static int onboard_hub_power_on(struct onboard_hub *hub) +{ + int err; + + err = regulator_enable(hub->vdd); + if (err) { + dev_err(hub->dev, "failed to enable regulator: %pe\n", + ERR_PTR(err)); + return err; + } + + udelay(hub->pdata->reset_us); + gpiod_set_value(hub->reset_gpio, 0); + + return 0; +} + +static int onboard_hub_probe(struct device *dev) +{ + struct onboard_hub *hub; + + hub = xzalloc(sizeof(*hub)); + + hub->pdata = device_get_match_data(dev); + if (!hub->pdata) + return -EINVAL; + + hub->vdd = regulator_get(dev, "vdd"); + if (IS_ERR(hub->vdd)) + return PTR_ERR(hub->vdd); + + hub->reset_gpio = gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (hub->reset_gpio < 0 && hub->reset_gpio != -ENOENT) + return dev_err_probe(dev, hub->reset_gpio, "failed to get reset GPIO\n"); + + hub->dev = dev; + + return onboard_hub_power_on(hub); +} + +static struct driver onboard_hub_driver = { + .name = "onboard-usb-hub", + .probe = onboard_hub_probe, + .of_compatible = onboard_hub_match, +}; +device_platform_driver(onboard_hub_driver); + +MODULE_AUTHOR("Matthias Kaehlcke <mka@chromium.org>"); +MODULE_DESCRIPTION("Driver for discrete onboard USB hubs"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/misc/onboard_usb_hub.h b/drivers/usb/misc/onboard_usb_hub.h new file mode 100644 index 0000000000..e90be47b67 --- /dev/null +++ b/drivers/usb/misc/onboard_usb_hub.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2022, Google LLC + */ + +#ifndef _USB_MISC_ONBOARD_USB_HUB_H +#define _USB_MISC_ONBOARD_USB_HUB_H + +struct onboard_hub_pdata { + unsigned long reset_us; /* reset pulse width in us */ +}; + +static const struct onboard_hub_pdata microchip_usb424_data = { + .reset_us = 1, +}; + +static const struct onboard_hub_pdata realtek_rts5411_data = { + .reset_us = 0, +}; + +static const struct onboard_hub_pdata ti_tusb8041_data = { + .reset_us = 3000, +}; + +const struct of_device_id onboard_hub_match[] = { + { .compatible = "usb424,2514", .data = µchip_usb424_data, }, + { .compatible = "usb451,8140", .data = &ti_tusb8041_data, }, + { .compatible = "usb451,8142", .data = &ti_tusb8041_data, }, + { .compatible = "usbbda,411", .data = &realtek_rts5411_data, }, + { .compatible = "usbbda,5411", .data = &realtek_rts5411_data, }, + { .compatible = "usbbda,414", .data = &realtek_rts5411_data, }, + { .compatible = "usbbda,5414", .data = &realtek_rts5411_data, }, + {} +}; + +#endif /* _USB_MISC_ONBOARD_USB_HUB_H */ diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index a0467ff3c4..a4e97c989b 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -324,7 +324,6 @@ struct musb { u16 int_rx; u16 int_tx; - //struct device_d *phydev; struct usb_host host; struct usb_phy *xceiv; diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index a20b7bbee9..01bdaf47bf 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -123,6 +123,12 @@ config DRIVER_VIDEO_SIMPLEFB Add support for setting up the kernel's simple framebuffer driver based on the active barebox framebuffer. +config DRIVER_VIDEO_RAMFB + bool "QEMU RamFB support" + select QEMU_FW_CFG + help + Add support for setting up a QEMU RamFB driver. + config DRIVER_VIDEO_EDID bool "Add EDID support" help diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 9ec0420cca..d50d2d3ba5 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_DRIVER_VIDEO_OMAP) += omap.o obj-$(CONFIG_DRIVER_VIDEO_BCM283X) += bcm2835.o obj-$(CONFIG_DRIVER_VIDEO_SIMPLEFB_CLIENT) += simplefb-client.o obj-$(CONFIG_DRIVER_VIDEO_SIMPLEFB) += simplefb-fixup.o +obj-$(CONFIG_DRIVER_VIDEO_RAMFB) += ramfb.o obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3) += imx-ipu-v3/ obj-$(CONFIG_DRIVER_VIDEO_EFI_GOP) += efi_gop.o obj-$(CONFIG_DRIVER_VIDEO_FB_SSD1307) += ssd1307fb.o diff --git a/drivers/video/ramfb.c b/drivers/video/ramfb.c new file mode 100644 index 0000000000..26e01196fc --- /dev/null +++ b/drivers/video/ramfb.c @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: (C) 2022 Adrian Negreanu + +#define pr_fmt(fmt) "ramfb: " fmt + +#include <common.h> +#include <fb.h> +#include <fcntl.h> +#include <dma.h> +#include <init.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <fs.h> +#include <linux/qemu_fw_cfg.h> +#include <video/fourcc.h> + +struct ramfb { + int fd; + struct fb_info info; + dma_addr_t screen_dma; + struct fb_videomode mode; + u16 etcfb_select; +}; + +struct fw_cfg_etc_ramfb { + u64 addr; + u32 fourcc; + u32 flags; + u32 width; + u32 height; + u32 stride; +} __packed; + +static int fw_cfg_find_file(struct device *dev, int fd, const char *filename) +{ + size_t filename_len = strlen(filename); + ssize_t ret; + __be32 count; + int i; + + ioctl(fd, FW_CFG_SELECT, &(u16) { FW_CFG_FILE_DIR }); + + lseek(fd, 0, SEEK_SET); + + ret = read(fd, &count, sizeof(count)); + if (ret < 0) + return ret; + + for (i = 0; i < be32_to_cpu(count); i++) { + struct fw_cfg_file qfile; + + read(fd, &qfile, sizeof(qfile)); + + dev_dbg(dev, "enumerating file %s\n", qfile.name); + + if (memcmp(qfile.name, filename, filename_len)) + continue; + + return be16_to_cpu(qfile.select); + } + + return -ENOENT; +} + +static void ramfb_populate_modes(struct ramfb *ramfb) +{ + struct fb_info *info = &ramfb->info; + + ramfb->mode.name = "x8r8g8b8"; + info->xres = ramfb->mode.xres = 640; + info->yres = ramfb->mode.yres = 480; + + info->mode = &ramfb->mode; + info->bits_per_pixel = 32; + info->red = (struct fb_bitfield) {16, 8}; + info->green = (struct fb_bitfield) {8, 8}; + info->blue = (struct fb_bitfield) {0, 8}; + info->transp = (struct fb_bitfield) {0, 0}; +} + +static int ramfb_activate_var(struct fb_info *fbi) +{ + struct ramfb *ramfb = fbi->priv; + + if (fbi->screen_base) + dma_free_coherent(fbi->screen_base, ramfb->screen_dma, fbi->screen_size); + + fbi->screen_size = fbi->xres * fbi->yres * fbi->bits_per_pixel; + fbi->screen_base = dma_alloc_coherent(fbi->screen_size, &ramfb->screen_dma); + + return 0; +} + +static void ramfb_enable(struct fb_info *fbi) +{ + struct ramfb *ramfb = fbi->priv; + struct fw_cfg_etc_ramfb *etc_ramfb; + + etc_ramfb = dma_alloc(sizeof(*etc_ramfb)); + + etc_ramfb->addr = cpu_to_be64(ramfb->screen_dma); + etc_ramfb->fourcc = cpu_to_be32(DRM_FORMAT_XRGB8888); + etc_ramfb->flags = cpu_to_be32(0); + etc_ramfb->width = cpu_to_be32(fbi->xres); + etc_ramfb->height = cpu_to_be32(fbi->yres); + etc_ramfb->stride = cpu_to_be32(fbi->line_length); + + ioctl(ramfb->fd, FW_CFG_SELECT, &ramfb->etcfb_select); + + pwrite(ramfb->fd, etc_ramfb, sizeof(*etc_ramfb), 0); + + dma_free(etc_ramfb); +} + +static struct fb_ops ramfb_ops = { + .fb_activate_var = ramfb_activate_var, + .fb_enable = ramfb_enable, +}; + +static int ramfb_probe(struct device *parent_dev, int fd) +{ + int ret; + struct ramfb *ramfb; + struct fb_info *fbi; + + ret = -ENODEV; + + ramfb = xzalloc(sizeof(*ramfb)); + + ramfb->fd = fd; + + ret = fw_cfg_find_file(parent_dev, fd, "etc/ramfb"); + if (ret < 0) { + dev_err(parent_dev, "ramfb: fw_cfg (etc/ramfb) file not found\n"); + return -ENODEV; + } + + ramfb->etcfb_select = ret; + dev_dbg(parent_dev, "etc/ramfb file at slot 0x%x\n", ramfb->etcfb_select); + + fbi = &ramfb->info; + fbi->priv = ramfb; + fbi->fbops = &ramfb_ops; + fbi->dev.parent = parent_dev; + + ramfb_populate_modes(ramfb); + + ret = register_framebuffer(fbi); + if (ret < 0) { + dev_err(parent_dev, "Unable to register ramfb: %d\n", ret); + return ret; + } + + dev_info(parent_dev, "ramfb registered\n"); + + return 0; +} + +static int ramfb_driver_init(void) +{ + struct cdev *cdev; + int err = 0; + + for_each_cdev(cdev) { + int fd, ret; + + if (!strstarts(cdev->name, "fw_cfg")) + continue; + + fd = cdev_fdopen(cdev, O_RDWR); + if (fd < 0) { + err = fd; + continue; + } + + ret = ramfb_probe(cdev->dev, fd); + if (ret == 0) + continue; + if (ret != -ENODEV && ret != -ENXIO) + err = ret; + + close(fd); + } + + return err; +} +device_initcall(ramfb_driver_init); + +MODULE_AUTHOR("Adrian Negreanu <adrian.negreanu@nxp.com>"); +MODULE_DESCRIPTION("QEMU RamFB driver"); +MODULE_LICENSE("GPL v2"); diff --git a/fs/cramfs/cramfs.c b/fs/cramfs/cramfs.c index 4676af8a55..2d1070f1a7 100644 --- a/fs/cramfs/cramfs.c +++ b/fs/cramfs/cramfs.c @@ -168,7 +168,7 @@ static int cramfs_read(struct device *_dev, FILE *f, void *buf, size_t size) } #if 0 -static int cramfs_info (struct device_d *dev) +static int cramfs_info (struct device *dev) { if (cramfs_read_super (dev)) return 0; diff --git a/fs/devfs-core.c b/fs/devfs-core.c index 2a259c2fe0..fbcf68e815 100644 --- a/fs/devfs-core.c +++ b/fs/devfs-core.c @@ -177,6 +177,26 @@ int cdev_open(struct cdev *cdev, unsigned long flags) return 0; } +int cdev_fdopen(struct cdev *cdev, unsigned long flags) +{ + char *path; + int fd; + + if (!cdev) + return -ENODEV; + if (IS_ERR(cdev)) + return PTR_ERR(cdev); + + path = basprintf("/dev/%s", cdev->name); + if (!path) + return -ENOMEM; + + fd = open(path, flags); + + free(path); + return fd; +} + struct cdev *cdev_open_by_name(const char *name, unsigned long flags) { struct cdev *cdev; @@ -160,9 +160,9 @@ void stat_print(const char *filename, const struct stat *st) fdev = get_fsdevice_by_path(filename); - printf("\nDevice: %s\tInode: %lu\tLinks: %u\n", + printf("\nDevice: %s\tInode: %lu\n", fdev ? dev_name(&fdev->dev) : "<unknown>", - st->st_ino, st->st_nlink); + st->st_ino); printf("Access: (%04o/%s)\tUid: (%u)\tGid: (%u)\n", st->st_mode & 07777, modestr, st->st_uid, st->st_gid); @@ -571,6 +571,12 @@ static int rpc_lookup_req(struct nfs_priv *npriv, uint32_t prog, uint32_t ver) nfs_free_packet(nfs_packet); + if (port == 0) { + pr_warn("No UDP port for RPC program %i! " + "Is your NFS server TCP only?\n", prog); + return -ENOENT; + } + return port; } diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h index acb70509d1..6e91c0aea6 100644 --- a/include/asm-generic/io.h +++ b/include/asm-generic/io.h @@ -12,6 +12,7 @@ #define __ASM_GENERIC_IO_H #include <linux/string.h> /* for memset() and memcpy() */ +#include <linux/compiler.h> #include <linux/types.h> #include <asm/byteorder.h> @@ -86,7 +87,7 @@ static inline void __raw_writeq(u64 b, volatile void __iomem *addr) #endif #ifndef PCI_IOBASE -#define PCI_IOBASE ((void __iomem *)0) +#define PCI_IOBASE ((void __iomem *)RELOC_HIDE((void *)0, 0)) #endif #ifndef IO_SPACE_LIMIT diff --git a/include/driver.h b/include/driver.h index f0a0b9d6ae..f53668711b 100644 --- a/include/driver.h +++ b/include/driver.h @@ -535,6 +535,7 @@ struct cdev *cdev_open_by_name(const char *name, unsigned long flags); struct cdev *cdev_create_loop(const char *path, ulong flags, loff_t offset); void cdev_remove_loop(struct cdev *cdev); int cdev_open(struct cdev *, unsigned long flags); +int cdev_fdopen(struct cdev *cdev, unsigned long flags); void cdev_close(struct cdev *cdev); int cdev_flush(struct cdev *cdev); ssize_t cdev_read(struct cdev *cdev, void *buf, size_t count, loff_t offset, ulong flags); diff --git a/include/filetype.h b/include/filetype.h index 00d54e48d5..1a7d145555 100644 --- a/include/filetype.h +++ b/include/filetype.h @@ -58,6 +58,7 @@ enum filetype { filetype_mxs_sd_image, filetype_rockchip_rkns_image, filetype_fip, + filetype_qemu_fw_cfg, filetype_max, }; diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h index 5175bbe370..18ff16a642 100644 --- a/include/linux/mfd/core.h +++ b/include/linux/mfd/core.h @@ -12,7 +12,7 @@ struct device; /* * This struct describes the MFD part ("cell"). * After registration the copy of this structure will become the platform data - * of the resulting device_d + * of the resulting device */ struct mfd_cell { const char *name; diff --git a/include/linux/stat.h b/include/linux/stat.h index 2bdf3ec9c9..fc3dd222a6 100644 --- a/include/linux/stat.h +++ b/include/linux/stat.h @@ -49,11 +49,8 @@ extern "C" { struct stat { unsigned long st_ino; unsigned short st_mode; - unsigned short st_nlink; unsigned short st_uid; unsigned short st_gid; - unsigned short st_rdev; - unsigned short __pad2; loff_t st_size; }; diff --git a/include/of_gpio.h b/include/of_gpio.h index 30ff204baf..794a9926cd 100644 --- a/include/of_gpio.h +++ b/include/of_gpio.h @@ -69,6 +69,23 @@ static inline int of_gpio_count(struct device_node *np) return of_gpio_named_count(np, "gpios"); } +/** + * of_gpio_count() - Count cs-gpios for a device + * @np: device node to count cs-gpios for + * + * Same as of_gpio_named_count, but hard coded to use the 'cs-gpios' property + * Returns 0 on error + */ +static inline int of_gpio_count_csgpios(struct device_node *np) +{ + int count = of_gpio_named_count(np, "cs-gpios"); + + if (count > 0) + return count; + else + return 0; +} + static inline int of_get_gpio_flags(struct device_node *np, int index, enum of_gpio_flags *flags) { diff --git a/include/platform_data/eth-smc911x.h b/include/platform_data/eth-smc911x.h index c97a2967c9..77b4f44633 100644 --- a/include/platform_data/eth-smc911x.h +++ b/include/platform_data/eth-smc911x.h @@ -9,7 +9,7 @@ /** * @brief Platform dependent feature: - * Pass pointer to this structure as part of device_d -> platform_data + * Pass pointer to this structure as part of device -> platform_data */ struct smc911x_plat { u32 shift; diff --git a/include/platform_data/serial-ns16550.h b/include/platform_data/serial-ns16550.h index ccf950b077..11a5e9c7a3 100644 --- a/include/platform_data/serial-ns16550.h +++ b/include/platform_data/serial-ns16550.h @@ -28,7 +28,7 @@ /** * @brief Platform dependent feature: - * Pass pointer to this structure as part of device_d -> platform_data + * Pass pointer to this structure as part of device -> platform_data */ struct NS16550_plat { /** Clock speed */ diff --git a/include/uapi/linux/qemu_fw_cfg.h b/include/uapi/linux/qemu_fw_cfg.h new file mode 100644 index 0000000000..97a720c383 --- /dev/null +++ b/include/uapi/linux/qemu_fw_cfg.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +#ifndef _LINUX_FW_CFG_H +#define _LINUX_FW_CFG_H + +#include <linux/types.h> +#include <ioctl.h> + +#define FW_CFG_ACPI_DEVICE_ID "QEMU0002" + +/* selector key values for "well-known" fw_cfg entries */ +#define FW_CFG_SIGNATURE 0x00 +#define FW_CFG_ID 0x01 +#define FW_CFG_UUID 0x02 +#define FW_CFG_RAM_SIZE 0x03 +#define FW_CFG_NOGRAPHIC 0x04 +#define FW_CFG_NB_CPUS 0x05 +#define FW_CFG_MACHINE_ID 0x06 +#define FW_CFG_KERNEL_ADDR 0x07 +#define FW_CFG_KERNEL_SIZE 0x08 +#define FW_CFG_KERNEL_CMDLINE 0x09 +#define FW_CFG_INITRD_ADDR 0x0a +#define FW_CFG_INITRD_SIZE 0x0b +#define FW_CFG_BOOT_DEVICE 0x0c +#define FW_CFG_NUMA 0x0d +#define FW_CFG_BOOT_MENU 0x0e +#define FW_CFG_MAX_CPUS 0x0f +#define FW_CFG_KERNEL_ENTRY 0x10 +#define FW_CFG_KERNEL_DATA 0x11 +#define FW_CFG_INITRD_DATA 0x12 +#define FW_CFG_CMDLINE_ADDR 0x13 +#define FW_CFG_CMDLINE_SIZE 0x14 +#define FW_CFG_CMDLINE_DATA 0x15 +#define FW_CFG_SETUP_ADDR 0x16 +#define FW_CFG_SETUP_SIZE 0x17 +#define FW_CFG_SETUP_DATA 0x18 +#define FW_CFG_FILE_DIR 0x19 + +#define FW_CFG_FILE_FIRST 0x20 +#define FW_CFG_FILE_SLOTS_MIN 0x10 + +#define FW_CFG_WRITE_CHANNEL 0x4000 +#define FW_CFG_ARCH_LOCAL 0x8000 +#define FW_CFG_ENTRY_MASK (~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL)) + +#define FW_CFG_INVALID 0xffff + +/* width in bytes of fw_cfg control register */ +#define FW_CFG_CTL_SIZE 0x02 + +/* fw_cfg "file name" is up to 56 characters (including terminating nul) */ +#define FW_CFG_MAX_FILE_PATH 56 + +/* size in bytes of fw_cfg signature */ +#define FW_CFG_SIG_SIZE 4 + +/* FW_CFG_ID bits */ +#define FW_CFG_VERSION 0x01 +#define FW_CFG_VERSION_DMA 0x02 + +/* fw_cfg file directory entry type */ +struct fw_cfg_file { + __be32 size; + __be16 select; + __u16 reserved; + char name[FW_CFG_MAX_FILE_PATH]; +}; + +/* FW_CFG_DMA_CONTROL bits */ +#define FW_CFG_DMA_CTL_ERROR 0x01 +#define FW_CFG_DMA_CTL_READ 0x02 +#define FW_CFG_DMA_CTL_SKIP 0x04 +#define FW_CFG_DMA_CTL_SELECT 0x08 +#define FW_CFG_DMA_CTL_WRITE 0x10 + +#define FW_CFG_DMA_SIGNATURE 0x51454d5520434647ULL /* "QEMU CFG" */ + +/* Control as first field allows for different structures selected by this + * field, which might be useful in the future + */ +struct fw_cfg_dma_access { + __be32 control; + __be32 length; + __be64 address; +}; + +#define FW_CFG_VMCOREINFO_FILENAME "etc/vmcoreinfo" + +#define FW_CFG_VMCOREINFO_FORMAT_NONE 0x0 +#define FW_CFG_VMCOREINFO_FORMAT_ELF 0x1 + +struct fw_cfg_vmcoreinfo { + __le16 host_format; + __le16 guest_format; + __le32 size; + __le64 paddr; +}; + +#define FW_CFG_SELECT _IOW('Q', 1, __u16) + +#endif diff --git a/include/usb/usb.h b/include/usb/usb.h index 9b36122436..717bcf935a 100644 --- a/include/usb/usb.h +++ b/include/usb/usb.h @@ -484,4 +484,12 @@ extern struct list_head usb_device_list; bool usb_hub_is_root_hub(struct usb_device *hdev); +#ifdef CONFIG_USB_ONBOARD_HUB +void of_usb_host_probe_hubs(struct usb_host *host); +#else +static inline void of_usb_host_probe_hubs(struct usb_host *host) +{ +} +#endif + #endif /*_USB_H_ */ |