- virtio implementation and supporting patches

- DM_FLAG_PRE_RELOC fixes
 - regmap improvements
 - minor buildman and sandbox things
 -----BEGIN PGP SIGNATURE-----
 
 iQFFBAABCgAvFiEEslwAIq+Gp8wWVbYnfxc6PpAIreYFAlvsxt8RHHNqZ0BjaHJv
 bWl1bS5vcmcACgkQfxc6PpAIrebPtQgAxR8bKdTNODUuVrw5OUIl40ziKQvNIlG5
 uiVsQLDI7Cd9D3Yls8yNffXqkNcQj+0/MJa38UZsm32c/uR4PU0zyFxpz4mwgyXk
 ZMrJ15AEAxf4IOHjbh52sNgR2mw+PeP9A3NO5LnZAMd/rnRF2MgBTy28FvjsBlNn
 z4OUjUpNv4ePND0QQ1EoGPlYotYPASEw8iK1pc5L+Rwq/ponAnNqegKIxQtiMugY
 kLtuFe0JJ704T20UkwYvI8LsnuB50ANRLLMyy5JLy1UtCpS24cc86ml49IKk3pqb
 v4GbnMI67s7S+Imzm4A7Mg8fgGnkkpLqacI3gnlpbIPkLrqRM2C20g==
 =RORj
 -----END PGP SIGNATURE-----

Merge tag 'pull-14nov18' of git://git.denx.de/u-boot-dm

- virtio implementation and supporting patches
- DM_FLAG_PRE_RELOC fixes
- regmap improvements
- minor buildman and sandbox things
This commit is contained in:
Tom Rini 2018-11-16 08:37:50 -05:00
commit 1d6edcbfed
171 changed files with 7490 additions and 347 deletions

View File

@ -0,0 +1,19 @@
gdsys IHS FPGA for CON devices
The gdsys IHS FPGA is the main FPGA on gdsys CON devices. This driver provides
support for enabling and starting the FPGA, as well as verifying working bus
communication.
Required properties:
- compatible: must be "gdsys,iocon_fpga"
- reset-gpios: List of GPIOs controlling the FPGA's reset
- done-gpios: List of GPIOs notifying whether the FPGA's reconfiguration is
done
Example:
FPGA0 {
compatible = "gdsys,iocon_fpga";
reset-gpios = <&PPCPCA 26 0>;
done-gpios = <&GPIO_VB0 19 0>;
};

View File

@ -0,0 +1,19 @@
gdsys IHS FPGA for CPU devices
The gdsys IHS FPGA is the main FPGA on gdsys CPU devices. This driver provides
support for enabling and starting the FPGA, as well as verifying working bus
communication.
Required properties:
- compatible: must be "gdsys,iocpu_fpga"
- reset-gpios: List of GPIOs controlling the FPGA's reset
- done-gpios: List of GPIOs notifying whether the FPGA's reconfiguration is
done
Example:
FPGA0 {
compatible = "gdsys,iocpu_fpga";
reset-gpios = <&PPCPCA 26 0>;
done-gpios = <&GPIO_VB0 19 0>;
};

View File

@ -0,0 +1,16 @@
gdsys soc bus driver
This driver provides a simple interface for the busses associated with gdsys
IHS FPGAs. The bus itself contains devices whose register maps are contained
within the FPGA's register space.
Required properties:
- fpga: A phandle to the controlling IHS FPGA
Example:
FPGA0BUS: fpga0bus {
compatible = "gdsys,soc";
ranges = <0x0 0xe0600000 0x00004000>;
fpga = <&FPGA0>;
};

View File

@ -110,6 +110,11 @@ config SANDBOX
imply LIBAVB
imply CMD_AVB
imply UDP_FUNCTION_FASTBOOT
imply VIRTIO_MMIO
imply VIRTIO_PCI
imply VIRTIO_SANDBOX
imply VIRTIO_BLK
imply VIRTIO_NET
config SH
bool "SuperH architecture"
@ -120,6 +125,7 @@ config X86
select CREATE_ARCH_SYMLINK
select DM
select DM_PCI
select HAVE_ARCH_IOMAP
select HAVE_PRIVATE_LIBGCC
select OF_CONTROL
select PCI

View File

@ -1496,6 +1496,7 @@ source "board/broadcom/bcmns2/Kconfig"
source "board/cavium/thunderx/Kconfig"
source "board/cirrus/edb93xx/Kconfig"
source "board/eets/pdu001/Kconfig"
source "board/emulation/qemu-arm/Kconfig"
source "board/freescale/ls2080a/Kconfig"
source "board/freescale/ls2080aqds/Kconfig"
source "board/freescale/ls2080ardb/Kconfig"

View File

@ -417,7 +417,6 @@ U_BOOT_DRIVER(stm32mp_bsec) = {
.ofdata_to_platdata = stm32mp_bsec_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct stm32mp_bsec_platdata),
.ops = &stm32mp_bsec_ops,
.flags = DM_FLAG_PRE_RELOC,
};
/* bsec IP is not present in device tee, manage IP address by platdata */

View File

@ -547,6 +547,28 @@ __BUILD_CLRSETBITS(bwlq, sfx, end, type)
#define __to_cpu(v) (v)
#define cpu_to__(v) (v)
#define out_arch(type, endian, a, v) __raw_write##type(cpu_to_##endian(v),a)
#define in_arch(type, endian, a) endian##_to_cpu(__raw_read##type(a))
#define out_le64(a, v) out_arch(q, le64, a, v)
#define out_le32(a, v) out_arch(l, le32, a, v)
#define out_le16(a, v) out_arch(w, le16, a, v)
#define in_le64(a) in_arch(q, le64, a)
#define in_le32(a) in_arch(l, le32, a)
#define in_le16(a) in_arch(w, le16, a)
#define out_be64(a, v) out_arch(q, be64, a, v)
#define out_be32(a, v) out_arch(l, be32, a, v)
#define out_be16(a, v) out_arch(w, be16, a, v)
#define in_be64(a) in_arch(q, be64, a)
#define in_be32(a) in_arch(l, be32, a)
#define in_be16(a) in_arch(w, be16, a)
#define out_8(a, v) __raw_writeb(v, a)
#define in_8(a) __raw_readb(a)
BUILD_CLRSETBITS(b, 8, _, u8)
BUILD_CLRSETBITS(w, le16, le16, u16)
BUILD_CLRSETBITS(w, be16, be16, u16)

View File

@ -9,9 +9,11 @@
#include <common.h>
#include <command.h>
#include <image.h>
#include <u-boot/zlib.h>
#include <asm/byteorder.h>
#include <asm/csr.h>
#include <dm/device.h>
#include <dm/root.h>
#include <u-boot/zlib.h>
DECLARE_GLOBAL_DATA_PTR;
@ -57,6 +59,13 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
/* we assume that the kernel is in place */
printf("\nStarting kernel ...\n\n");
/*
* Call remove function of all devices with a removal flag set.
* This may be useful for last-stage operations, like cancelling
* of DMA operation or releasing device internal buffers.
*/
dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
cleanup_before_linux();
if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)

View File

@ -174,7 +174,12 @@ void *os_malloc(size_t length)
struct os_mem_hdr *hdr;
int page_size = getpagesize();
hdr = mmap(NULL, length + page_size,
/*
* Use an address that is hopefully available to us so that pointers
* to this memory are fairly obvious. If we end up with a different
* address, that's fine too.
*/
hdr = mmap((void *)0x10000000, length + page_size,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (hdr == MAP_FAILED)

View File

@ -186,6 +186,10 @@
compatible = "denx,u-boot-fdt-test";
};
h-test {
compatible = "denx,u-boot-fdt-test1";
};
clocks {
clk_fixed: clk-fixed {
compatible = "fixed-clock";
@ -346,14 +350,17 @@
cpu-test1 {
compatible = "sandbox,cpu_sandbox";
u-boot,dm-pre-reloc;
};
cpu-test2 {
compatible = "sandbox,cpu_sandbox";
u-boot,dm-pre-reloc;
};
cpu-test3 {
compatible = "sandbox,cpu_sandbox";
u-boot,dm-pre-reloc;
};
misc-test {
@ -525,7 +532,7 @@
syscon@0 {
compatible = "sandbox,syscon0";
reg = <0x10 4>;
reg = <0x10 16>;
};
syscon@1 {
@ -712,6 +719,14 @@
sandbox_tee {
compatible = "sandbox,tee";
};
sandbox_virtio1 {
compatible = "sandbox,virtio1";
};
sandbox_virtio2 {
compatible = "sandbox,virtio2";
};
};
#include "sandbox_pmic.dtsi"

View File

@ -203,4 +203,5 @@ U_BOOT_DRIVER(cpu_x86_baytrail_drv) = {
.bind = cpu_x86_bind,
.probe = cpu_x86_baytrail_probe,
.ops = &cpu_x86_baytrail_ops,
.flags = DM_FLAG_PRE_RELOC,
};

View File

@ -764,4 +764,5 @@ U_BOOT_DRIVER(cpu_x86_broadwell_drv) = {
.probe = cpu_x86_broadwell_probe,
.ops = &cpu_x86_broadwell_ops,
.priv_auto_alloc_size = sizeof(struct cpu_broadwell_priv),
.flags = DM_FLAG_PRE_RELOC,
};

View File

@ -94,4 +94,5 @@ U_BOOT_DRIVER(cpu_x86_drv) = {
.of_match = cpu_x86_ids,
.bind = cpu_x86_bind,
.ops = &cpu_x86_ops,
.flags = DM_FLAG_PRE_RELOC,
};

View File

@ -478,4 +478,5 @@ U_BOOT_DRIVER(cpu_x86_model_206ax_drv) = {
.bind = cpu_x86_bind,
.probe = cpu_x86_model_206ax_probe,
.ops = &cpu_x86_model_206ax_ops,
.flags = DM_FLAG_PRE_RELOC,
};

View File

@ -44,5 +44,4 @@ U_BOOT_DRIVER(tangier_sysreset) = {
.id = UCLASS_SYSRESET,
.of_match = tangier_sysreset_ids,
.ops = &tangier_sysreset_ops,
.flags = DM_FLAG_PRE_RELOC,
};

View File

@ -241,6 +241,72 @@ static inline void sync(void)
#define __iormb() dmb()
#define __iowmb() dmb()
/*
* Read/write from/to an (offsettable) iomem cookie. It might be a PIO
* access or a MMIO access, these functions don't care. The info is
* encoded in the hardware mapping set up by the mapping functions
* (or the cookie itself, depending on implementation and hw).
*
* The generic routines don't assume any hardware mappings, and just
* encode the PIO/MMIO as part of the cookie. They coldly assume that
* the MMIO IO mappings are not in the low address range.
*
* Architectures for which this is not true can't use this generic
* implementation and should do their own copy.
*/
/*
* We assume that all the low physical PIO addresses (0-0xffff) always
* PIO. That means we can do some sanity checks on the low bits, and
* don't need to just take things for granted.
*/
#define PIO_RESERVED 0x10000UL
/*
* Ugly macros are a way of life.
*/
#define IO_COND(addr, is_pio, is_mmio) do { \
unsigned long port = (unsigned long __force)addr; \
if (port >= PIO_RESERVED) { \
is_mmio; \
} else { \
is_pio; \
} \
} while (0)
static inline u8 ioread8(const volatile void __iomem *addr)
{
IO_COND(addr, return inb(port), return readb(addr));
return 0xff;
}
static inline u16 ioread16(const volatile void __iomem *addr)
{
IO_COND(addr, return inw(port), return readw(addr));
return 0xffff;
}
static inline u32 ioread32(const volatile void __iomem *addr)
{
IO_COND(addr, return inl(port), return readl(addr));
return 0xffffffff;
}
static inline void iowrite8(u8 value, volatile void __iomem *addr)
{
IO_COND(addr, outb(value, port), writeb(value, addr));
}
static inline void iowrite16(u16 value, volatile void __iomem *addr)
{
IO_COND(addr, outw(value, port), writew(value, addr));
}
static inline void iowrite32(u32 value, volatile void __iomem *addr)
{
IO_COND(addr, outl(value, port), writel(value, addr));
}
#include <asm-generic/io.h>
#endif /* _ASM_IO_H */

View File

@ -0,0 +1,13 @@
if TARGET_QEMU_ARM_32BIT || TARGET_QEMU_ARM_64BIT
config SYS_TEXT_BASE
default 0x00000000
config BOARD_SPECIFIC_OPTIONS # dummy
def_bool y
imply VIRTIO_MMIO
imply VIRTIO_PCI
imply VIRTIO_NET
imply VIRTIO_BLK
endif

View File

@ -2,8 +2,12 @@
/*
* Copyright (c) 2017 Tuomas Tynkkynen
*/
#include <common.h>
#include <dm.h>
#include <fdtdec.h>
#include <virtio_types.h>
#include <virtio.h>
#ifdef CONFIG_ARM64
#include <asm/armv8/mmu.h>
@ -58,6 +62,12 @@ struct mm_region *mem_map = qemu_arm64_mem_map;
int board_init(void)
{
/*
* Make sure virtio bus is enumerated so that peripherals
* on the virtio bus can be discovered by their drivers
*/
virtio_init();
return 0;
}

View File

@ -18,5 +18,16 @@ config SYS_TEXT_BASE
config BOARD_SPECIFIC_OPTIONS # dummy
def_bool y
imply SYS_NS16550
imply VIRTIO_MMIO
imply VIRTIO_NET
imply VIRTIO_BLK
imply CMD_PING
imply CMD_FS_GENERIC
imply DOS_PARTITION
imply EFI_PARTITION
imply ISO_PARTITION
imply CMD_EXT2
imply CMD_EXT4
imply CMD_FAT
endif

View File

@ -4,12 +4,21 @@
*/
#include <common.h>
#include <dm.h>
#include <fdtdec.h>
#include <virtio_types.h>
#include <virtio.h>
#define MROM_FDT_ADDR 0x1020
int board_init(void)
{
/*
* Make sure virtio bus is enumerated so that peripherals
* on the virtio bus can be discovered by their drivers
*/
virtio_init();
return 0;
}

View File

@ -21,5 +21,8 @@ config BOARD_SPECIFIC_OPTIONS # dummy
select X86_RESET_VECTOR
select QEMU
select BOARD_ROMSIZE_KB_1024
imply VIRTIO_PCI
imply VIRTIO_NET
imply VIRTIO_BLK
endif

View File

@ -1065,6 +1065,13 @@ config CMD_USB_MASS_STORAGE
help
USB mass storage support
config CMD_VIRTIO
bool "virtio"
depends on VIRTIO
default y if VIRTIO
help
VirtIO block device support
config CMD_AXI
bool "axi"
depends on AXI

View File

@ -135,6 +135,7 @@ obj-$(CONFIG_CMD_UBI) += ubi.o
obj-$(CONFIG_CMD_UBIFS) += ubifs.o
obj-$(CONFIG_CMD_UNIVERSE) += universe.o
obj-$(CONFIG_CMD_UNZIP) += unzip.o
obj-$(CONFIG_CMD_VIRTIO) += virtio.o
obj-$(CONFIG_CMD_LZMADEC) += lzmadec.o
obj-$(CONFIG_CMD_USB) += usb.o disk.o

View File

@ -51,7 +51,6 @@ int sata_probe(int devnum)
{
#ifdef CONFIG_AHCI
struct udevice *dev;
struct udevice *blk;
int rc;
rc = uclass_get_device(UCLASS_AHCI, devnum, &dev);
@ -67,14 +66,6 @@ int sata_probe(int devnum)
return CMD_RET_FAILURE;
}
rc = blk_get_from_parent(dev, &blk);
if (!rc) {
struct blk_desc *desc = dev_get_uclass_platdata(blk);
if (desc->lba > 0 && desc->blksz > 0)
part_init(desc);
}
return 0;
#else
return sata_initialize() < 0 ? CMD_RET_FAILURE : CMD_RET_SUCCESS;

38
cmd/virtio.c Normal file
View File

@ -0,0 +1,38 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2018, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
* Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
*/
#include <common.h>
#include <command.h>
#include <dm.h>
#include <virtio_types.h>
#include <virtio.h>
static int virtio_curr_dev;
static int do_virtio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
if (argc == 2 && !strcmp(argv[1], "scan")) {
/* make sure all virtio devices are enumerated */
virtio_init();
return CMD_RET_SUCCESS;
}
return blk_common_cmd(argc, argv, IF_TYPE_VIRTIO, &virtio_curr_dev);
}
U_BOOT_CMD(
virtio, 8, 1, do_virtio,
"virtio block devices sub-system",
"scan - initialize virtio bus\n"
"virtio info - show all available virtio block devices\n"
"virtio device [dev] - show or set current virtio block device\n"
"virtio part [dev] - print partition table of one or all virtio block devices\n"
"virtio read addr blk# cnt - read `cnt' blocks starting at block\n"
" `blk#' to memory address `addr'\n"
"virtio write addr blk# cnt - write `cnt' blocks starting at block\n"
" `blk#' from memory address `addr'"
);

View File

@ -11,6 +11,7 @@
#include <common.h>
#include <console.h>
#include <cpu.h>
#include <dm.h>
#include <environment.h>
#include <fdtdec.h>
@ -165,6 +166,33 @@ static int print_resetinfo(void)
}
#endif
#if defined(CONFIG_DISPLAY_CPUINFO) && CONFIG_IS_ENABLED(CPU)
static int print_cpuinfo(void)
{
struct udevice *dev;
char desc[512];
int ret;
ret = uclass_first_device_err(UCLASS_CPU, &dev);
if (ret) {
debug("%s: Could not get CPU device (err = %d)\n",
__func__, ret);
return ret;
}
ret = cpu_get_desc(dev, desc, sizeof(desc));
if (ret) {
debug("%s: Could not get CPU description (err = %d)\n",
dev->name, ret);
return ret;
}
printf("CPU: %s\n", desc);
return 0;
}
#endif
static int announce_dram_init(void)
{
puts("DRAM: ");

View File

@ -226,9 +226,7 @@ static int usb_stor_probe_device(struct usb_device *udev)
blkdev->lun = lun;
ret = usb_stor_get_info(udev, data, blkdev);
if (ret == 1)
ret = blk_prepare_device(dev);
if (!ret) {
if (ret == 1) {
usb_max_devs++;
debug("%s: Found device %p\n", __func__, udev);
} else {

View File

@ -6,7 +6,6 @@ CONFIG_TARGET_IMX8QXP_MEK=y
CONFIG_NR_DRAM_BANKS=3
CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/imx8qxp_mek/imximage.cfg"
CONFIG_BOOTDELAY=3
# CONFIG_DISPLAY_CPUINFO is not set
CONFIG_CMD_CPU=y
# CONFIG_CMD_IMPORTENV is not set
CONFIG_CMD_CLK=y

View File

@ -1,7 +1,6 @@
CONFIG_ARM=y
CONFIG_ARM_SMCCC=y
CONFIG_ARCH_QEMU=y
CONFIG_SYS_TEXT_BASE=0x00000000
CONFIG_TARGET_QEMU_ARM_64BIT=y
CONFIG_AHCI=y
CONFIG_DISTRO_DEFAULTS=y

View File

@ -1,7 +1,6 @@
CONFIG_ARM=y
CONFIG_ARM_SMCCC=y
CONFIG_ARCH_QEMU=y
CONFIG_SYS_TEXT_BASE=0x00000000
CONFIG_TARGET_QEMU_ARM_32BIT=y
CONFIG_AHCI=y
CONFIG_DISTRO_DEFAULTS=y

View File

@ -171,6 +171,7 @@ CONFIG_CONSOLE_TRUETYPE_CANTORAONE=y
CONFIG_VIDEO_SANDBOX_SDL=y
CONFIG_OSD=y
CONFIG_SANDBOX_OSD=y
# CONFIG_VIRTIO_BLK is not set
CONFIG_FS_CBFS=y
CONFIG_FS_CRAMFS=y
CONFIG_CMD_DHRYSTONE=y

View File

@ -150,6 +150,9 @@ void dev_print (struct blk_desc *dev_desc)
dev_desc->revision,
dev_desc->product);
break;
case IF_TYPE_VIRTIO:
printf("%s VirtIO Block Device\n", dev_desc->vendor);
break;
case IF_TYPE_DOC:
puts("device type DOC\n");
return;
@ -281,6 +284,9 @@ static void print_part_header(const char *type, struct blk_desc *dev_desc)
case IF_TYPE_NVME:
puts ("NVMe");
break;
case IF_TYPE_VIRTIO:
puts("VirtIO");
break;
default:
puts ("UNKNOWN");
break;

253
doc/README.virtio Normal file
View File

@ -0,0 +1,253 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
VirtIO Support
==============
This document describes the information about U-Boot support for VirtIO [1]
devices, including supported boards, build instructions, driver details etc.
What's VirtIO?
--------------
VirtIO is a virtualization standard for network and disk device drivers where
just the guest's device driver "knows" it is running in a virtual environment,
and cooperates with the hypervisor. This enables guests to get high performance
network and disk operations, and gives most of the performance benefits of
paravirtualization. In the U-Boot case, the guest is U-Boot itself, while the
virtual environment are normally QEMU [2] targets like ARM, RISC-V and x86.
Status
------
VirtIO can use various different buses, aka transports as described in the
spec. While VirtIO devices are commonly implemented as PCI devices on x86,
embedded devices models like ARM/RISC-V, which does not normally come with
PCI support might use simple memory mapped device (MMIO) instead of the PCI
device. The memory mapped virtio device behaviour is based on the PCI device
specification. Therefore most operations including device initialization,
queues configuration and buffer transfers are nearly identical. Both MMIO
and PCI transport options are supported in U-Boot.
The VirtIO spec defines a lots of VirtIO device types, however at present only
network and block device, the most two commonly used devices, are supported.
The following QEMU targets are supported.
- qemu_arm_defconfig
- qemu_arm64_defconfig
- qemu-riscv32_defconfig
- qemu-riscv64_defconfig
- qemu-x86_defconfig
- qemu-x86_64_defconfig
Note ARM and RISC-V targets are configured with VirtIO MMIO transport driver,
and on x86 it's the PCI transport driver.
Build Instructions
------------------
Building U-Boot for pre-configured QEMU targets is no different from others.
For example, we can do the following with the CROSS_COMPILE environment
variable being properly set to a working toolchain for ARM:
$ make qemu_arm_defconfig
$ make
You can even create a QEMU ARM target with VirtIO devices showing up on both
MMIO and PCI buses. In this case, you can enable the PCI transport driver
from 'make menuconfig':
Device Drivers --->
...
VirtIO Drivers --->
...
[*] PCI driver for virtio devices
Other drivers are at the same location and can be tuned to suit the needs.
Requirements
------------
It is required that QEMU v2.5.0+ should be used to test U-Boot VirtIO support
on QEMU ARM and x86, and v2.12.0+ on QEMU RISC-V.
Testing
-------
The following QEMU command line is used to get U-Boot up and running with
VirtIO net and block devices on ARM.
$ qemu-system-arm -nographic -machine virt -bios u-boot.bin \
-netdev tap,ifname=tap0,id=net0 \
-device virtio-net-device,netdev=net0 \
-drive if=none,file=test.img,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0
On x86, command is slightly different to create PCI VirtIO devices.
$ qemu-system-i386 -nographic -bios u-boot.rom \
-netdev tap,ifname=tap0,id=net0 \
-device virtio-net-pci,netdev=net0 \
-drive if=none,file=test.img,format=raw,id=hd0 \
-device virtio-blk-pci,drive=hd0
Additional net and block devices can be created by appending more '-device'
parameters. It is also possible to specify both MMIO and PCI VirtIO devices.
For example, the following commnad creates 3 VirtIO devices, with 1 on MMIO
and 2 on PCI bus.
$ qemu-system-arm -nographic -machine virt -bios u-boot.bin \
-netdev tap,ifname=tap0,id=net0 \
-device virtio-net-pci,netdev=net0 \
-drive if=none,file=test0.img,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \
-drive if=none,file=test1.img,format=raw,id=hd1 \
-device virtio-blk-pci,drive=hd1
By default QEMU creates VirtIO legacy devices by default. To create non-legacy
(aka modern) devices, pass additional device property/value pairs like below:
$ qemu-system-i386 -nographic -bios u-boot.rom \
-netdev tap,ifname=tap0,id=net0 \
-device virtio-net-pci,netdev=net0,disable-legacy=true,disable-modern=false \
-drive if=none,file=test.img,format=raw,id=hd0 \
-device virtio-blk-pci,drive=hd0,disable-legacy=true,disable-modern=false
A 'virtio' command is provided in U-Boot shell.
=> virtio
virtio - virtio block devices sub-system
Usage:
virtio scan - initialize virtio bus
virtio info - show all available virtio block devices
virtio device [dev] - show or set current virtio block device
virtio part [dev] - print partition table of one or all virtio block devices
virtio read addr blk# cnt - read `cnt' blocks starting at block
`blk#' to memory address `addr'
virtio write addr blk# cnt - write `cnt' blocks starting at block
`blk#' from memory address `addr'
To probe all the VirtIO devices, type:
=> virtio scan
Then we can show the connected block device details by:
=> virtio info
Device 0: QEMU VirtIO Block Device
Type: Hard Disk
Capacity: 4096.0 MB = 4.0 GB (8388608 x 512)
And list the directories and files on the disk by:
=> ls virtio 0 /
<DIR> 4096 .
<DIR> 4096 ..
<DIR> 16384 lost+found
<DIR> 4096 dev
<DIR> 4096 proc
<DIR> 4096 sys
<DIR> 4096 var
<DIR> 4096 etc
<DIR> 4096 usr
<SYM> 7 bin
<SYM> 8 sbin
<SYM> 7 lib
<SYM> 9 lib64
<DIR> 4096 run
<DIR> 4096 boot
<DIR> 4096 home
<DIR> 4096 media
<DIR> 4096 mnt
<DIR> 4096 opt
<DIR> 4096 root
<DIR> 4096 srv
<DIR> 4096 tmp
0 .autorelabel
Driver Internals
----------------
There are 3 level of drivers in the VirtIO driver family.
+---------------------------------------+
| virtio device drivers |
| +-------------+ +------------+ |
| | virtio-net | | virtio-blk | |
| +-------------+ +------------+ |
+---------------------------------------+
+---------------------------------------+
| virtio transport drivers |
| +-------------+ +------------+ |
| | virtio-mmio | | virtio-pci | |
| +-------------+ +------------+ |
+---------------------------------------+
+----------------------+
| virtio uclass driver |
+----------------------+
The root one is the virtio uclass driver (virtio-uclass.c), which does lots of
common stuff for the transport drivers (virtio_mmio.c, virtio_pci.c). The real
virtio device is discovered in the transport driver's probe() method, and its
device ID is saved in the virtio uclass's private data of the transport device.
Then in the virtio uclass's post_probe() method, the real virtio device driver
(virtio_net.c, virtio_blk.c) is bound if there is a match on the device ID.
The child_post_bind(), child_pre_probe() and child_post_probe() methods of the
virtio uclass driver help bring the virtio device driver online. They do things
like acknowledging device, feature negotiation, etc, which are really common
for all virtio devices.
The transport drivers provide a set of ops (struct dm_virtio_ops) for the real
virtio device driver to call. These ops APIs's parameter is designed to remind
the caller to pass the correct 'struct udevice' id of the virtio device, eg:
int virtio_get_status(struct udevice *vdev, u8 *status)
So the parameter 'vdev' indicates the device should be the real virtio device.
But we also have an API like:
struct virtqueue *vring_create_virtqueue(unsigned int index, unsigned int num,
unsigned int vring_align,
struct udevice *udev)
Here the parameter 'udev' indicates the device should be the transport device.
Similar naming is applied in other functions that are even not APIs, eg:
static int virtio_uclass_post_probe(struct udevice *udev)
static int virtio_uclass_child_pre_probe(struct udevice *vdev)
So it's easy to tell which device these functions are operating on.
Development Flow
----------------
At present only VirtIO network card (device ID 1) and block device (device
ID 2) are supported. If you want to develop new driver for new devices,
please follow the guideline below.
1. add new device ID in virtio.h
#define VIRTIO_ID_XXX X
2. update VIRTIO_ID_MAX_NUM to be the largest device ID plus 1
3. add new driver name string in virtio.h
#define VIRTIO_XXX_DRV_NAME "virtio-xxx"
4. create a new driver with name set to the name string above
U_BOOT_DRIVER(virtio_xxx) = {
.name = VIRTIO_XXX_DRV_NAME,
...
.remove = virtio_reset,
.flags = DM_FLAG_ACTIVE_DMA,
}
Note the driver needs to provide the remove method and normally this can be
hooked to virtio_reset(). The driver flags should contain DM_FLAG_ACTIVE_DMA
for the remove method to be called before jumping to OS.
5. provide bind() method in the driver, where virtio_driver_features_init()
should be called for driver to negotiate feature support with the device.
6. do funny stuff with the driver
References
----------
[1] http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.pdf
[2] https://www.qemu.org

View File

@ -830,10 +830,18 @@ Pre-Relocation Support
----------------------
For pre-relocation we simply call the driver model init function. Only
drivers marked with DM_FLAG_PRE_RELOC or the device tree
'u-boot,dm-pre-reloc' flag are initialised prior to relocation. This helps
to reduce the driver model overhead. This flag applies to SPL and TPL as
well, if device tree is enabled there.
drivers marked with DM_FLAG_PRE_RELOC or the device tree 'u-boot,dm-pre-reloc'
property are initialised prior to relocation. This helps to reduce the driver
model overhead. This flag applies to SPL and TPL as well, if device tree is
enabled (CONFIG_OF_CONTROL) there.
Note when device tree is enabled, the device tree 'u-boot,dm-pre-reloc'
property can provide better control granularity on which device is bound
before relocation. While with DM_FLAG_PRE_RELOC flag of the driver all
devices with the same driver are bound, which requires allocation a large
amount of memory. When device tree is not used, DM_FLAG_PRE_RELOC is the
only way for statically declared devices via U_BOOT_DEVICE() to be bound
prior to relocation.
It is possible to limit this to specific relocation steps, by using
the more specialized 'u-boot,dm-spl' and 'u-boot,dm-tpl' flags

View File

@ -112,6 +112,8 @@ source "drivers/usb/Kconfig"
source "drivers/video/Kconfig"
source "drivers/virtio/Kconfig"
source "drivers/w1/Kconfig"
source "drivers/w1-eeprom/Kconfig"

View File

@ -14,6 +14,7 @@ obj-$(CONFIG_$(SPL_TPL_)SERIAL_SUPPORT) += serial/
obj-$(CONFIG_$(SPL_TPL_)SPI_FLASH_SUPPORT) += mtd/spi/
obj-$(CONFIG_$(SPL_TPL_)SPI_SUPPORT) += spi/
obj-$(CONFIG_$(SPL_TPL_)TIMER) += timer/
obj-$(CONFIG_$(SPL_TPL_)VIRTIO) += virtio/
obj-$(CONFIG_$(SPL_)DM_MAILBOX) += mailbox/
obj-$(CONFIG_$(SPL_)REMOTEPROC) += remoteproc/

View File

@ -23,6 +23,7 @@ static const char *if_typename_str[IF_TYPE_COUNT] = {
[IF_TYPE_HOST] = "host",
[IF_TYPE_NVME] = "nvme",
[IF_TYPE_EFI] = "efi",
[IF_TYPE_VIRTIO] = "virtio",
};
static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
@ -37,6 +38,7 @@ static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
[IF_TYPE_HOST] = UCLASS_ROOT,
[IF_TYPE_NVME] = UCLASS_NVME,
[IF_TYPE_EFI] = UCLASS_EFI,
[IF_TYPE_VIRTIO] = UCLASS_VIRTIO,
};
static enum if_type if_typename_to_iftype(const char *if_typename)
@ -471,15 +473,6 @@ unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start,
return ops->erase(dev, start, blkcnt);
}
int blk_prepare_device(struct udevice *dev)
{
struct blk_desc *desc = dev_get_uclass_platdata(dev);
part_init(desc);
return 0;
}
int blk_get_from_parent(struct udevice *parent, struct udevice **devp)
{
struct udevice *dev;
@ -526,7 +519,7 @@ int blk_find_max_devnum(enum if_type if_type)
return max_devnum;
}
static int blk_next_free_devnum(enum if_type if_type)
int blk_next_free_devnum(enum if_type if_type)
{
int ret;
@ -644,8 +637,20 @@ int blk_unbind_all(int if_type)
return 0;
}
static int blk_post_probe(struct udevice *dev)
{
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
struct blk_desc *desc = dev_get_uclass_platdata(dev);
part_init(desc);
#endif
return 0;
}
UCLASS_DRIVER(blk) = {
.id = UCLASS_BLK,
.name = "blk",
.post_probe = blk_post_probe,
.per_device_platdata_auto_alloc_size = sizeof(struct blk_desc),
};

View File

@ -1169,8 +1169,6 @@ static int ide_blk_probe(struct udevice *udev)
BLK_REV_SIZE);
desc->revision[BLK_REV_SIZE] = '\0';
part_init(desc);
return 0;
}

View File

@ -33,7 +33,7 @@ static unsigned long host_block_read(struct udevice *dev,
unsigned long start, lbaint_t blkcnt,
void *buffer)
{
struct host_block_dev *host_dev = dev_get_priv(dev);
struct host_block_dev *host_dev = dev_get_platdata(dev);
struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
#else
@ -64,7 +64,7 @@ static unsigned long host_block_write(struct udevice *dev,
unsigned long start, lbaint_t blkcnt,
const void *buffer)
{
struct host_block_dev *host_dev = dev_get_priv(dev);
struct host_block_dev *host_dev = dev_get_platdata(dev);
struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
#else
static unsigned long host_block_write(struct blk_desc *block_dev,
@ -131,17 +131,18 @@ int host_dev_bind(int devnum, char *filename)
os_lseek(fd, 0, OS_SEEK_END) / 512, &dev);
if (ret)
goto err_file;
host_dev = dev_get_platdata(dev);
host_dev->fd = fd;
host_dev->filename = fname;
ret = device_probe(dev);
if (ret) {
device_unbind(dev);
goto err_file;
}
host_dev = dev_get_priv(dev);
host_dev->fd = fd;
host_dev->filename = fname;
return blk_prepare_device(dev);
return 0;
err_file:
os_close(fd);
err:
@ -226,7 +227,7 @@ U_BOOT_DRIVER(sandbox_host_blk) = {
.name = "sandbox_host_blk",
.id = UCLASS_BLK,
.ops = &sandbox_host_blk_ops,
.priv_auto_alloc_size = sizeof(struct host_block_dev),
.platdata_auto_alloc_size = sizeof(struct host_block_dev),
};
#else
U_BOOT_LEGACY_BLK(sandbox_host) = {

View File

@ -352,7 +352,6 @@ static const struct udevice_id socfpga_a10_clk_match[] = {
U_BOOT_DRIVER(socfpga_a10_clk) = {
.name = "clk-a10",
.id = UCLASS_CLK,
.flags = DM_FLAG_PRE_RELOC,
.of_match = socfpga_a10_clk_match,
.ops = &socfpga_a10_clk_ops,
.bind = socfpga_a10_clk_bind,

View File

@ -418,7 +418,6 @@ U_BOOT_DRIVER(pic32_clk) = {
.name = "pic32_clk",
.id = UCLASS_CLK,
.of_match = pic32_clk_ids,
.flags = DM_FLAG_PRE_RELOC,
.ops = &pic32_pic32_clk_ops,
.probe = pic32_clk_probe,
.priv_auto_alloc_size = sizeof(struct pic32_clk_priv),

View File

@ -480,7 +480,6 @@ U_BOOT_DRIVER(zynq_clk) = {
.name = "zynq_clk",
.id = UCLASS_CLK,
.of_match = zynq_clk_ids,
.flags = DM_FLAG_PRE_RELOC,
.ops = &zynq_clk_ops,
.priv_auto_alloc_size = sizeof(struct zynq_clk_priv),
.probe = zynq_clk_probe,

View File

@ -201,7 +201,6 @@ U_BOOT_DRIVER(exynos7420_clk_topc) = {
.probe = exynos7420_clk_topc_probe,
.priv_auto_alloc_size = sizeof(struct exynos7420_clk_topc_priv),
.ops = &exynos7420_clk_topc_ops,
.flags = DM_FLAG_PRE_RELOC,
};
static const struct udevice_id exynos7420_clk_top0_compat[] = {
@ -216,7 +215,6 @@ U_BOOT_DRIVER(exynos7420_clk_top0) = {
.probe = exynos7420_clk_top0_probe,
.priv_auto_alloc_size = sizeof(struct exynos7420_clk_top0_priv),
.ops = &exynos7420_clk_top0_ops,
.flags = DM_FLAG_PRE_RELOC,
};
static const struct udevice_id exynos7420_clk_peric1_compat[] = {
@ -229,5 +227,4 @@ U_BOOT_DRIVER(exynos7420_clk_peric1) = {
.id = UCLASS_CLK,
.of_match = exynos7420_clk_peric1_compat,
.ops = &exynos7420_clk_peric1_ops,
.flags = DM_FLAG_PRE_RELOC,
};

View File

@ -134,5 +134,4 @@ U_BOOT_DRIVER(clk_owl) = {
.ops = &owl_clk_ops,
.priv_auto_alloc_size = sizeof(struct owl_clk_priv),
.probe = owl_clk_probe,
.flags = DM_FLAG_PRE_RELOC,
};

View File

@ -834,5 +834,5 @@ int dev_enable_by_path(const char *path)
if (ret)
return ret;
return lists_bind_fdt(parent, node, NULL);
return lists_bind_fdt(parent, node, NULL, false);
}

View File

@ -89,7 +89,7 @@ void dm_dump_uclass(void)
printf("uclass %d: %s\n", id, uc->uc_drv->name);
if (list_empty(&uc->dev_head))
continue;
list_for_each_entry(dev, &uc->dev_head, uclass_node) {
uclass_foreach_dev(dev, uc) {
dm_display_line(dev, i);
i++;
}

View File

@ -122,7 +122,8 @@ static int driver_check_compatible(const struct udevice_id *of_match,
return -ENOENT;
}
int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp)
int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp,
bool pre_reloc_only)
{
struct driver *driver = ll_entry_start(struct driver, driver);
const int n_ents = ll_entry_count(struct driver, driver);
@ -171,6 +172,12 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp)
if (entry == driver + n_ents)
continue;
if (pre_reloc_only) {
if (!dm_ofnode_pre_reloc(node) &&
!(entry->flags & DM_FLAG_PRE_RELOC))
return 0;
}
pr_debug(" - found match at '%s'\n", entry->name);
ret = device_bind_with_driver_data(parent, entry, name,
id->data, node, &dev);

View File

@ -831,8 +831,10 @@ int ofnode_write_prop(ofnode node, const char *propname, int len,
return -ENOMEM;
new->name = strdup(propname);
if (!new->name)
if (!new->name) {
free(new);
return -ENOMEM;
}
new->value = (void *)value;
new->length = len;

View File

@ -17,6 +17,12 @@
DECLARE_GLOBAL_DATA_PTR;
/**
* regmap_alloc() - Allocate a regmap with a given number of ranges.
*
* @count: Number of ranges to be allocated for the regmap.
* Return: A pointer to the newly allocated regmap, or NULL on error.
*/
static struct regmap *regmap_alloc(int count)
{
struct regmap *map;
@ -50,6 +56,58 @@ int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count,
return 0;
}
#else
/**
* init_range() - Initialize a single range of a regmap
* @node: Device node that will use the map in question
* @range: Pointer to a regmap_range structure that will be initialized
* @addr_len: The length of the addr parts of the reg property
* @size_len: The length of the size parts of the reg property
* @index: The index of the range to initialize
*
* This function will read the necessary 'reg' information from the device tree
* (the 'addr' part, and the 'length' part), and initialize the range in
* quesion.
*
* Return: 0 if OK, -ve on error
*/
static int init_range(ofnode node, struct regmap_range *range, int addr_len,
int size_len, int index)
{
fdt_size_t sz;
struct resource r;
if (of_live_active()) {
int ret;
ret = of_address_to_resource(ofnode_to_np(node),
index, &r);
if (ret) {
debug("%s: Could not read resource of range %d (ret = %d)\n",
ofnode_get_name(node), index, ret);
return ret;
}
range->start = r.start;
range->size = r.end - r.start + 1;
} else {
int offset = ofnode_to_offset(node);
range->start = fdtdec_get_addr_size_fixed(gd->fdt_blob, offset,
"reg", index,
addr_len, size_len,
&sz, true);
if (range->start == FDT_ADDR_T_NONE) {
debug("%s: Could not read start of range %d\n",
ofnode_get_name(node), index);
return -EINVAL;
}
range->size = sz;
}
return 0;
}
int regmap_init_mem(ofnode node, struct regmap **mapp)
{
struct regmap_range *range;
@ -58,19 +116,41 @@ int regmap_init_mem(ofnode node, struct regmap **mapp)
int addr_len, size_len, both_len;
int len;
int index;
struct resource r;
addr_len = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
if (addr_len < 0) {
debug("%s: Error while reading the addr length (ret = %d)\n",
ofnode_get_name(node), addr_len);
return addr_len;
}
size_len = ofnode_read_simple_size_cells(ofnode_get_parent(node));
if (size_len < 0) {
debug("%s: Error while reading the size length: (ret = %d)\n",
ofnode_get_name(node), size_len);
return size_len;
}
both_len = addr_len + size_len;
if (!both_len) {
debug("%s: Both addr and size length are zero\n",
ofnode_get_name(node));
return -EINVAL;
}
len = ofnode_read_size(node, "reg");
if (len < 0)
if (len < 0) {
debug("%s: Error while reading reg size (ret = %d)\n",
ofnode_get_name(node), len);
return len;
}
len /= sizeof(fdt32_t);
count = len / both_len;
if (!count)
if (!count) {
debug("%s: Not enough data in reg property\n",
ofnode_get_name(node));
return -EINVAL;
}
map = regmap_alloc(count);
if (!map)
@ -78,19 +158,21 @@ int regmap_init_mem(ofnode node, struct regmap **mapp)
for (range = map->ranges, index = 0; count > 0;
count--, range++, index++) {
fdt_size_t sz;
if (of_live_active()) {
of_address_to_resource(ofnode_to_np(node), index, &r);
range->start = r.start;
range->size = r.end - r.start + 1;
} else {
range->start = fdtdec_get_addr_size_fixed(gd->fdt_blob,
ofnode_to_offset(node), "reg", index,
addr_len, size_len, &sz, true);
range->size = sz;
}
int ret = init_range(node, range, addr_len, size_len, index);
if (ret)
return ret;
}
if (ofnode_read_bool(node, "little-endian"))
map->endianness = REGMAP_LITTLE_ENDIAN;
else if (ofnode_read_bool(node, "big-endian"))
map->endianness = REGMAP_BIG_ENDIAN;
else if (ofnode_read_bool(node, "native-endian"))
map->endianness = REGMAP_NATIVE_ENDIAN;
else /* Default: native endianness */
map->endianness = REGMAP_NATIVE_ENDIAN;
*mapp = map;
return 0;
@ -115,24 +197,218 @@ int regmap_uninit(struct regmap *map)
return 0;
}
int regmap_read(struct regmap *map, uint offset, uint *valp)
static inline u8 __read_8(u8 *addr, enum regmap_endianness_t endianness)
{
u32 *ptr = map_physmem(map->ranges[0].start + offset, 4, MAP_NOCACHE);
return readb(addr);
}
*valp = le32_to_cpu(readl(ptr));
static inline u16 __read_16(u16 *addr, enum regmap_endianness_t endianness)
{
switch (endianness) {
case REGMAP_LITTLE_ENDIAN:
return in_le16(addr);
case REGMAP_BIG_ENDIAN:
return in_be16(addr);
case REGMAP_NATIVE_ENDIAN:
return readw(addr);
}
return readw(addr);
}
static inline u32 __read_32(u32 *addr, enum regmap_endianness_t endianness)
{
switch (endianness) {
case REGMAP_LITTLE_ENDIAN:
return in_le32(addr);
case REGMAP_BIG_ENDIAN:
return in_be32(addr);
case REGMAP_NATIVE_ENDIAN:
return readl(addr);
}
return readl(addr);
}
#if defined(in_le64) && defined(in_be64) && defined(readq)
static inline u64 __read_64(u64 *addr, enum regmap_endianness_t endianness)
{
switch (endianness) {
case REGMAP_LITTLE_ENDIAN:
return in_le64(addr);
case REGMAP_BIG_ENDIAN:
return in_be64(addr);
case REGMAP_NATIVE_ENDIAN:
return readq(addr);
}
return readq(addr);
}
#endif
int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset,
void *valp, size_t val_len)
{
struct regmap_range *range;
void *ptr;
if (range_num >= map->range_count) {
debug("%s: range index %d larger than range count\n",
__func__, range_num);
return -ERANGE;
}
range = &map->ranges[range_num];
ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE);
if (offset + val_len > range->size) {
debug("%s: offset/size combination invalid\n", __func__);
return -ERANGE;
}
switch (val_len) {
case REGMAP_SIZE_8:
*((u8 *)valp) = __read_8(ptr, map->endianness);
break;
case REGMAP_SIZE_16:
*((u16 *)valp) = __read_16(ptr, map->endianness);
break;
case REGMAP_SIZE_32:
*((u32 *)valp) = __read_32(ptr, map->endianness);
break;
#if defined(in_le64) && defined(in_be64) && defined(readq)
case REGMAP_SIZE_64:
*((u64 *)valp) = __read_64(ptr, map->endianness);
break;
#endif
default:
debug("%s: regmap size %zu unknown\n", __func__, val_len);
return -EINVAL;
}
return 0;
}
int regmap_write(struct regmap *map, uint offset, uint val)
int regmap_raw_read(struct regmap *map, uint offset, void *valp, size_t val_len)
{
u32 *ptr = map_physmem(map->ranges[0].start + offset, 4, MAP_NOCACHE);
return regmap_raw_read_range(map, 0, offset, valp, val_len);
}
writel(cpu_to_le32(val), ptr);
int regmap_read(struct regmap *map, uint offset, uint *valp)
{
return regmap_raw_read(map, offset, valp, REGMAP_SIZE_32);
}
static inline void __write_8(u8 *addr, const u8 *val,
enum regmap_endianness_t endianness)
{
writeb(*val, addr);
}
static inline void __write_16(u16 *addr, const u16 *val,
enum regmap_endianness_t endianness)
{
switch (endianness) {
case REGMAP_NATIVE_ENDIAN:
writew(*val, addr);
break;
case REGMAP_LITTLE_ENDIAN:
out_le16(addr, *val);
break;
case REGMAP_BIG_ENDIAN:
out_be16(addr, *val);
break;
}
}
static inline void __write_32(u32 *addr, const u32 *val,
enum regmap_endianness_t endianness)
{
switch (endianness) {
case REGMAP_NATIVE_ENDIAN:
writel(*val, addr);
break;
case REGMAP_LITTLE_ENDIAN:
out_le32(addr, *val);
break;
case REGMAP_BIG_ENDIAN:
out_be32(addr, *val);
break;
}
}
#if defined(out_le64) && defined(out_be64) && defined(writeq)
static inline void __write_64(u64 *addr, const u64 *val,
enum regmap_endianness_t endianness)
{
switch (endianness) {
case REGMAP_NATIVE_ENDIAN:
writeq(*val, addr);
break;
case REGMAP_LITTLE_ENDIAN:
out_le64(addr, *val);
break;
case REGMAP_BIG_ENDIAN:
out_be64(addr, *val);
break;
}
}
#endif
int regmap_raw_write_range(struct regmap *map, uint range_num, uint offset,
const void *val, size_t val_len)
{
struct regmap_range *range;
void *ptr;
if (range_num >= map->range_count) {
debug("%s: range index %d larger than range count\n",
__func__, range_num);
return -ERANGE;
}
range = &map->ranges[range_num];
ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE);
if (offset + val_len > range->size) {
debug("%s: offset/size combination invalid\n", __func__);
return -ERANGE;
}
switch (val_len) {
case REGMAP_SIZE_8:
__write_8(ptr, val, map->endianness);
break;
case REGMAP_SIZE_16:
__write_16(ptr, val, map->endianness);
break;
case REGMAP_SIZE_32:
__write_32(ptr, val, map->endianness);
break;
#if defined(out_le64) && defined(out_be64) && defined(writeq)
case REGMAP_SIZE_64:
__write_64(ptr, val, map->endianness);
break;
#endif
default:
debug("%s: regmap size %zu unknown\n", __func__, val_len);
return -EINVAL;
}
return 0;
}
int regmap_raw_write(struct regmap *map, uint offset, const void *val,
size_t val_len)
{
return regmap_raw_write_range(map, 0, offset, val, val_len);
}
int regmap_write(struct regmap *map, uint offset, uint val)
{
return regmap_raw_write(map, offset, &val, REGMAP_SIZE_32);
}
int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val)
{
uint reg;

View File

@ -222,14 +222,22 @@ static int dm_scan_fdt_live(struct udevice *parent,
int ret = 0, err;
for (np = node_parent->child; np; np = np->sibling) {
if (pre_reloc_only &&
!of_find_property(np, "u-boot,dm-pre-reloc", NULL))
/* "chosen" node isn't a device itself but may contain some: */
if (!strcmp(np->name, "chosen")) {
pr_debug("parsing subnodes of \"chosen\"\n");
err = dm_scan_fdt_live(parent, np, pre_reloc_only);
if (err && !ret)
ret = err;
continue;
}
if (!of_device_is_available(np)) {
pr_debug(" - ignoring disabled device\n");
continue;
}
err = lists_bind_fdt(parent, np_to_ofnode(np), NULL);
err = lists_bind_fdt(parent, np_to_ofnode(np), NULL,
pre_reloc_only);
if (err && !ret) {
ret = err;
debug("%s: ret=%d\n", np->name, ret);
@ -282,14 +290,12 @@ static int dm_scan_fdt_node(struct udevice *parent, const void *blob,
continue;
}
if (pre_reloc_only &&
!dm_fdt_pre_reloc(blob, offset))
continue;
if (!fdtdec_get_is_enabled(blob, offset)) {
pr_debug(" - ignoring disabled device\n");
continue;
}
err = lists_bind_fdt(parent, offset_to_ofnode(offset), NULL);
err = lists_bind_fdt(parent, offset_to_ofnode(offset), NULL,
pre_reloc_only);
if (err && !ret) {
ret = err;
debug("%s: ret=%d\n", node_name, ret);

View File

@ -180,7 +180,7 @@ int dev_get_uclass_index(struct udevice *dev, struct uclass **ucp)
if (list_empty(&uc->dev_head))
return -ENODEV;
list_for_each_entry(iter, &uc->dev_head, uclass_node) {
uclass_foreach_dev(iter, uc) {
if (iter == dev) {
if (ucp)
*ucp = uc;
@ -205,7 +205,7 @@ int uclass_find_device(enum uclass_id id, int index, struct udevice **devp)
if (list_empty(&uc->dev_head))
return -ENODEV;
list_for_each_entry(dev, &uc->dev_head, uclass_node) {
uclass_foreach_dev(dev, uc) {
if (!index--) {
*devp = dev;
return 0;
@ -259,7 +259,7 @@ int uclass_find_device_by_name(enum uclass_id id, const char *name,
if (ret)
return ret;
list_for_each_entry(dev, &uc->dev_head, uclass_node) {
uclass_foreach_dev(dev, uc) {
if (!strncmp(dev->name, name, strlen(name))) {
*devp = dev;
return 0;
@ -284,7 +284,7 @@ int uclass_find_device_by_seq(enum uclass_id id, int seq_or_req_seq,
if (ret)
return ret;
list_for_each_entry(dev, &uc->dev_head, uclass_node) {
uclass_foreach_dev(dev, uc) {
debug(" - %d %d '%s'\n", dev->req_seq, dev->seq, dev->name);
if ((find_req_seq ? dev->req_seq : dev->seq) ==
seq_or_req_seq) {
@ -312,7 +312,7 @@ int uclass_find_device_by_of_offset(enum uclass_id id, int node,
if (ret)
return ret;
list_for_each_entry(dev, &uc->dev_head, uclass_node) {
uclass_foreach_dev(dev, uc) {
if (dev_of_offset(dev) == node) {
*devp = dev;
return 0;
@ -337,7 +337,7 @@ int uclass_find_device_by_ofnode(enum uclass_id id, ofnode node,
if (ret)
return ret;
list_for_each_entry(dev, &uc->dev_head, uclass_node) {
uclass_foreach_dev(dev, uc) {
log(LOGC_DM, LOGL_DEBUG_CONTENT, " - checking %s\n",
dev->name);
if (ofnode_equal(dev_ofnode(dev), node)) {
@ -372,7 +372,7 @@ static int uclass_find_device_by_phandle(enum uclass_id id,
if (ret)
return ret;
list_for_each_entry(dev, &uc->dev_head, uclass_node) {
uclass_foreach_dev(dev, uc) {
uint phandle;
phandle = dev_read_phandle(dev);
@ -399,7 +399,7 @@ int uclass_get_device_by_driver(enum uclass_id id,
if (ret)
return ret;
list_for_each_entry(dev, &uc->dev_head, uclass_node) {
uclass_foreach_dev(dev, uc) {
if (dev->driver == find_drv)
return uclass_get_device_tail(dev, 0, devp);
}
@ -499,7 +499,7 @@ int uclass_get_device_by_phandle_id(enum uclass_id id, uint phandle_id,
if (ret)
return ret;
list_for_each_entry(dev, &uc->dev_head, uclass_node) {
uclass_foreach_dev(dev, uc) {
uint phandle;
phandle = dev_read_phandle(dev);
@ -687,8 +687,19 @@ int uclass_pre_probe_device(struct udevice *dev)
int uclass_post_probe_device(struct udevice *dev)
{
struct uclass_driver *uc_drv = dev->uclass->uc_drv;
struct uclass_driver *uc_drv;
int ret;
if (dev->parent) {
uc_drv = dev->parent->uclass->uc_drv;
if (uc_drv->child_post_probe) {
ret = uc_drv->child_post_probe(dev);
if (ret)
return ret;
}
}
uc_drv = dev->uclass->uc_drv;
if (uc_drv->post_probe)
return uc_drv->post_probe(dev);

View File

@ -4,6 +4,7 @@
*/
#include <common.h>
#include <dm/ofnode.h>
#include <dm/util.h>
#include <linux/libfdt.h>
#include <vsprintf.h>
@ -53,3 +54,27 @@ bool dm_fdt_pre_reloc(const void *blob, int offset)
return false;
}
bool dm_ofnode_pre_reloc(ofnode node)
{
if (ofnode_read_bool(node, "u-boot,dm-pre-reloc"))
return true;
#ifdef CONFIG_TPL_BUILD
if (ofnode_read_bool(node, "u-boot,dm-tpl"))
return true;
#elif defined(CONFIG_SPL_BUILD)
if (ofnode_read_bool(node, "u-boot,dm-spl"))
return true;
#else
/*
* In regular builds individual spl and tpl handling both
* count as handled pre-relocation for later second init.
*/
if (ofnode_read_bool(node, "u-boot,dm-spl") ||
ofnode_read_bool(node, "u-boot,dm-tpl"))
return true;
#endif
return false;
}

View File

@ -262,7 +262,7 @@ static int mpc83xx_cpu_get_desc(struct udevice *dev, char *buf, int size)
determine_cpu_data(dev);
snprintf(buf, size,
"CPU: %s, MPC%s%s%s, Rev: %d.%d at %s MHz, CSB: %s MHz\n",
"%s, MPC%s%s%s, Rev: %d.%d at %s MHz, CSB: %s MHz",
e300_names[priv->e300_type],
cpu_type_names[priv->type],
priv->is_e_processor ? "E" : "",

View File

@ -372,7 +372,9 @@ U_BOOT_DRIVER(gpio_omap) = {
.ops = &gpio_omap_ops,
.probe = omap_gpio_probe,
.priv_auto_alloc_size = sizeof(struct gpio_bank),
#if !CONFIG_IS_ENABLED(OF_CONTROL)
.flags = DM_FLAG_PRE_RELOC,
#endif
};
#endif /* CONFIG_DM_GPIO */

View File

@ -123,6 +123,6 @@ U_BOOT_DRIVER(gpio_stm32) = {
.of_match = stm32_gpio_ids,
.probe = gpio_stm32_probe,
.ops = &gpio_stm32_ops,
.flags = DM_FLAG_PRE_RELOC | DM_UC_FLAG_SEQ_ALIAS,
.flags = DM_UC_FLAG_SEQ_ALIAS,
.priv_auto_alloc_size = sizeof(struct stm32_gpio_priv),
};

View File

@ -281,5 +281,4 @@ U_BOOT_DRIVER(tegra186_gpio) = {
.bind = tegra186_gpio_bind,
.probe = tegra186_gpio_probe,
.ops = &tegra186_gpio_ops,
.flags = DM_FLAG_PRE_RELOC,
};

View File

@ -378,5 +378,4 @@ U_BOOT_DRIVER(gpio_tegra) = {
.probe = gpio_tegra_probe,
.priv_auto_alloc_size = sizeof(struct tegra_port_info),
.ops = &gpio_tegra_ops,
.flags = DM_FLAG_PRE_RELOC,
};

View File

@ -925,7 +925,9 @@ U_BOOT_DRIVER(i2c_omap) = {
.probe = omap_i2c_probe,
.priv_auto_alloc_size = sizeof(struct omap_i2c),
.ops = &omap_i2c_ops,
#if !CONFIG_IS_ENABLED(OF_CONTROL)
.flags = DM_FLAG_PRE_RELOC,
#endif
};
#endif /* CONFIG_DM_I2C */

View File

@ -312,4 +312,21 @@ config FS_LOADER
The consumer driver would then use this loader to program whatever,
ie. the FPGA device.
config GDSYS_SOC
bool "Enable gdsys SOC driver"
depends on MISC
help
Support for gdsys IHS SOC, a simple bus associated with each gdsys
IHS (Integrated Hardware Systems) FPGA, which holds all devices whose
register maps are contained within the FPGA's register map.
config IHS_FPGA
bool "Enable IHS FPGA driver"
depends on MISC
help
Support IHS (Integrated Hardware Systems) FPGA, the main FPGAs on
gdsys devices, which supply the majority of the functionality offered
by the devices. This driver supports both CON and CPU variants of the
devices, depending on the device tree entry.
endmenu

View File

@ -4,11 +4,6 @@
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
obj-$(CONFIG_MISC) += misc-uclass.o
obj-$(CONFIG_ALI152X) += ali512x.o
obj-$(CONFIG_ALTERA_SYSID) += altera_sysid.o
obj-$(CONFIG_ATSHA204A) += atsha204a-i2c.o
obj-$(CONFIG_DS4510) += ds4510.o
obj-$(CONFIG_CBMEM_CONSOLE) += cbmem_console.o
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_CROS_EC) += cros_ec.o
obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpc.o
@ -16,46 +11,54 @@ obj-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o
obj-$(CONFIG_CROS_EC_SANDBOX) += cros_ec_sandbox.o
obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o
endif
obj-$(CONFIG_FSL_IIM) += fsl_iim.o
obj-$(CONFIG_LED_STATUS_GPIO) += gpio_led.o
obj-$(CONFIG_$(SPL_)I2C_EEPROM) += i2c_eeprom.o
obj-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o
obj-$(CONFIG_IMX8) += imx8/
obj-$(CONFIG_MXC_OCOTP) += mxc_ocotp.o
obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o
obj-$(CONFIG_NUVOTON_NCT6102D) += nuvoton_nct6102d.o
obj-$(CONFIG_NS87308) += ns87308.o
obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o
ifdef CONFIG_DM_I2C
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_SANDBOX) += i2c_eeprom_emul.o
endif
endif
obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o
obj-$(CONFIG_SMSC_SIO1007) += smsc_sio1007.o
obj-$(CONFIG_LED_STATUS) += status_led.o
obj-$(CONFIG_SANDBOX) += swap_case.o
ifdef CONFIG_SPL_OF_PLATDATA
ifdef CONFIG_SPL_BUILD
obj-$(CONFIG_SANDBOX) += spltest_sandbox.o
endif
endif
obj-$(CONFIG_SANDBOX) += syscon_sandbox.o misc_sandbox.o
obj-$(CONFIG_TEGRA_CAR) += tegra_car.o
obj-$(CONFIG_TEGRA186_BPMP) += tegra186_bpmp.o
obj-$(CONFIG_TWL4030_LED) += twl4030_led.o
obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
obj-$(CONFIG_FSL_SEC_MON) += fsl_sec_mon.o
obj-$(CONFIG_PCA9551_LED) += pca9551_led.o
obj-$(CONFIG_ALI152X) += ali512x.o
obj-$(CONFIG_ALTERA_SYSID) += altera_sysid.o
obj-$(CONFIG_ATSHA204A) += atsha204a-i2c.o
obj-$(CONFIG_CBMEM_CONSOLE) += cbmem_console.o
obj-$(CONFIG_DS4510) += ds4510.o
obj-$(CONFIG_FSL_DEVICE_DISABLE) += fsl_devdis.o
obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o
obj-$(CONFIG_QFW) += qfw.o
obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o
obj-$(CONFIG_STM32_RCC) += stm32_rcc.o
obj-$(CONFIG_STM32MP_FUSE) += stm32mp_fuse.o
obj-$(CONFIG_SYS_DPAA_QBMAN) += fsl_portals.o
obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
obj-$(CONFIG_FSL_IIM) += fsl_iim.o
obj-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o
obj-$(CONFIG_FSL_SEC_MON) += fsl_sec_mon.o
obj-$(CONFIG_FS_LOADER) += fs_loader.o
obj-$(CONFIG_GDSYS_IOEP) += gdsys_ioep.o
obj-$(CONFIG_GDSYS_RXAUI_CTRL) += gdsys_rxaui_ctrl.o
obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress_config.o
obj-$(CONFIG_GDSYS_SOC) += gdsys_soc.o
obj-$(CONFIG_$(SPL_)I2C_EEPROM) += i2c_eeprom.o
obj-$(CONFIG_IHS_FPGA) += ihs_fpga.o
obj-$(CONFIG_IMX8) += imx8/
obj-$(CONFIG_LED_STATUS) += status_led.o
obj-$(CONFIG_LED_STATUS_GPIO) += gpio_led.o
obj-$(CONFIG_MPC83XX_SERDES) += mpc83xx_serdes.o
obj-$(CONFIG_FS_LOADER) += fs_loader.o
obj-$(CONFIG_MXC_OCOTP) += mxc_ocotp.o
obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o
obj-$(CONFIG_NS87308) += ns87308.o
obj-$(CONFIG_NUVOTON_NCT6102D) += nuvoton_nct6102d.o
obj-$(CONFIG_PCA9551_LED) += pca9551_led.o
obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o
obj-$(CONFIG_QFW) += qfw.o
obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o
obj-$(CONFIG_SANDBOX) += swap_case.o
obj-$(CONFIG_SANDBOX) += syscon_sandbox.o misc_sandbox.o
obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o
obj-$(CONFIG_SMSC_SIO1007) += smsc_sio1007.o
obj-$(CONFIG_STM32MP_FUSE) += stm32mp_fuse.o
obj-$(CONFIG_STM32_RCC) += stm32_rcc.o
obj-$(CONFIG_SYS_DPAA_QBMAN) += fsl_portals.o
obj-$(CONFIG_TEGRA186_BPMP) += tegra186_bpmp.o
obj-$(CONFIG_TEGRA_CAR) += tegra_car.o
obj-$(CONFIG_TWL4030_LED) += twl4030_led.o
obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress_config.o
obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o

74
drivers/misc/gdsys_soc.c Normal file
View File

@ -0,0 +1,74 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2017
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
*/
#include <common.h>
#include <dm.h>
#include <dm/lists.h>
#include "gdsys_soc.h"
/**
* struct gdsys_soc_priv - Private data for gdsys soc bus
* @fpga: The gdsys IHS FPGA this bus is associated with
*/
struct gdsys_soc_priv {
struct udevice *fpga;
};
static const struct udevice_id gdsys_soc_ids[] = {
{ .compatible = "gdsys,soc" },
{ /* sentinel */ }
};
int gdsys_soc_get_fpga(struct udevice *child, struct udevice **fpga)
{
struct gdsys_soc_priv *bus_priv;
if (!child->parent) {
debug("%s: Invalid parent\n", child->name);
return -EINVAL;
}
if (!device_is_compatible(child->parent, "gdsys,soc")) {
debug("%s: Not child of a gdsys soc\n", child->name);
return -EINVAL;
}
bus_priv = dev_get_priv(child->parent);
*fpga = bus_priv->fpga;
return 0;
}
static int gdsys_soc_probe(struct udevice *dev)
{
struct gdsys_soc_priv *priv = dev_get_priv(dev);
struct udevice *fpga;
int res = uclass_get_device_by_phandle(UCLASS_MISC, dev, "fpga",
&fpga);
if (res == -ENOENT) {
debug("%s: Could not find 'fpga' phandle\n", dev->name);
return -EINVAL;
}
if (res == -ENODEV) {
debug("%s: Could not get FPGA device\n", dev->name);
return -EINVAL;
}
priv->fpga = fpga;
return 0;
}
U_BOOT_DRIVER(gdsys_soc_bus) = {
.name = "gdsys_soc_bus",
.id = UCLASS_SIMPLE_BUS,
.of_match = gdsys_soc_ids,
.probe = gdsys_soc_probe,
.priv_auto_alloc_size = sizeof(struct gdsys_soc_priv),
};

23
drivers/misc/gdsys_soc.h Normal file
View File

@ -0,0 +1,23 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* (C) Copyright 2017
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
*/
#ifndef _GDSYS_SOC_H_
#define _GDSYS_SOC_H_
/**
* gdsys_soc_get_fpga() - Retrieve pointer to parent bus' FPGA device
* @child: The child device on the FPGA bus needing access to the FPGA.
* @fpga: Pointer to the retrieved FPGA device.
*
* To access their register maps, devices on gdsys soc buses usually have
* facilitate the accessor function of the IHS FPGA their parent bus is
* attached to. To access the FPGA device from within the bus' children, this
* function returns a pointer to it.
*
* Return: 0 on success, -ve on failure
*/
int gdsys_soc_get_fpga(struct udevice *child, struct udevice **fpga);
#endif /* _GDSYS_SOC_H_ */

867
drivers/misc/ihs_fpga.c Normal file
View File

@ -0,0 +1,867 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2017
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
*
* based on the ioep-fpga driver, which is
*
* (C) Copyright 2014
* Dirk Eibach, Guntermann & Drunck GmbH, eibach@gdsys.de
*/
#include <common.h>
#include <dm.h>
#include <regmap.h>
#include <asm/gpio.h>
#include "ihs_fpga.h"
/**
* struct ihs_fpga_priv - Private data structure for IHS FPGA driver
* @map: Register map for the FPGA's own register space
* @reset_gpio: GPIO to start FPGA reconfiguration
* @done_gpio: GPOI to read the 'ready' status of the FPGA
*/
struct ihs_fpga_priv {
struct regmap *map;
struct gpio_desc reset_gpio;
struct gpio_desc done_gpio;
};
/* Test pattern for reflection test */
const u16 REFLECTION_TESTPATTERN = 0xdead;
/* Delay (in ms) for each round in the reflection test */
const uint REFLECTION_TEST_DELAY = 100;
/* Maximum number of rounds in the reflection test */
const uint REFLECTION_TEST_ROUNDS = 5;
/* Delay (in ms) for each round waiting for the FPGA's done GPIO */
const uint FPGA_DONE_WAIT_DELAY = 100;
/* Maximum number of rounds for waiting for the FPGA's done GPIO */
const uint FPGA_DONE_WAIT_ROUND = 5;
/**
* enum pcb_video_type - Video type of the PCB
* @PCB_DVI_SL: Video type is DVI single-link
* @PCB_DP_165MPIX: Video type is DisplayPort (165Mpix)
* @PCB_DP_300MPIX: Video type is DisplayPort (300Mpix)
* @PCB_HDMI: Video type is HDMI
* @PCB_DP_1_2: Video type is DisplayPort 1.2
* @PCB_HDMI_2_0: Video type is HDMI 2.0
*/
enum pcb_video_type {
PCB_DVI_SL,
PCB_DP_165MPIX,
PCB_DP_300MPIX,
PCB_HDMI,
PCB_DP_1_2,
PCB_HDMI_2_0,
};
/**
* enum pcb_transmission_type - Transmission type of the PCB
* @PCB_CAT_1G: Transmission type is 1G Ethernet
* @PCB_FIBER_3G: Transmission type is 3G Fiber
* @PCB_CAT_10G: Transmission type is 10G Ethernet
* @PCB_FIBER_10G: Transmission type is 10G Fiber
*/
enum pcb_transmission_type {
PCB_CAT_1G,
PCB_FIBER_3G,
PCB_CAT_10G,
PCB_FIBER_10G,
};
/**
* enum carrier_speed - Speed of the FPGA's carrier
* @CARRIER_SPEED_1G: The carrier speed is 1G
* @CARRIER_SPEED_2_5G: The carrier speed is 2.5G
* @CARRIER_SPEED_3G: The carrier speed is 3G
* @CARRIER_SPEED_10G: The carrier speed is 10G
*/
enum carrier_speed {
CARRIER_SPEED_1G,
CARRIER_SPEED_3G,
CARRIER_SPEED_2_5G = CARRIER_SPEED_3G,
CARRIER_SPEED_10G,
};
/**
* enum ram_config - FPGA's RAM configuration
* @RAM_DDR2_32BIT_295MBPS: DDR2 32 bit at 295Mb/s
* @RAM_DDR3_32BIT_590MBPS: DDR3 32 bit at 590Mb/s
* @RAM_DDR3_48BIT_590MBPS: DDR3 48 bit at 590Mb/s
* @RAM_DDR3_64BIT_1800MBPS: DDR3 64 bit at 1800Mb/s
* @RAM_DDR3_48BIT_1800MBPS: DDR3 48 bit at 1800Mb/s
*/
enum ram_config {
RAM_DDR2_32BIT_295MBPS,
RAM_DDR3_32BIT_590MBPS,
RAM_DDR3_48BIT_590MBPS,
RAM_DDR3_64BIT_1800MBPS,
RAM_DDR3_48BIT_1800MBPS,
};
/**
* enum sysclock - Speed of the FPGA's system clock
* @SYSCLK_147456: System clock is 147.456 MHz
*/
enum sysclock {
SYSCLK_147456,
};
/**
* struct fpga_versions - Data read from the versions register
* @video_channel: Is the FPGA for a video channel (true) or main
* channel (false) device?
* @con_side: Is the FPGA for a CON (true) or a CPU (false) device?
* @pcb_video_type: Defines for whch video type the FPGA is configured
* @pcb_transmission_type: Defines for which transmission type the FPGA is
* configured
* @hw_version: Hardware version of the FPGA
*/
struct fpga_versions {
bool video_channel;
bool con_side;
enum pcb_video_type pcb_video_type;
enum pcb_transmission_type pcb_transmission_type;
unsigned int hw_version;
};
/**
* struct fpga_features - Data read from the features register
* @video_channels: Number of video channels supported
* @carriers: Number of carrier channels supported
* @carrier_speed: Speed of carriers
* @ram_config: RAM configuration of FPGA
* @sysclock: System clock speed of FPGA
* @pcm_tx: Support for PCM transmission
* @pcm_rx: Support for PCM reception
* @spdif_tx: Support for SPDIF audio transmission
* @spdif_rx: Support for SPDIF audio reception
* @usb2: Support for transparent USB2.0
* @rs232: Support for bidirectional RS232
* @compression_type1: Support for compression type 1
* @compression_type2: Support for compression type 2
* @compression_type3: Support for compression type 3
* @interlace: Support for interlace image formats
* @osd: Support for a OSD
* @compression_pipes: Number of compression pipes supported
*/
struct fpga_features {
u8 video_channels;
u8 carriers;
enum carrier_speed carrier_speed;
enum ram_config ram_config;
enum sysclock sysclock;
bool pcm_tx;
bool pcm_rx;
bool spdif_tx;
bool spdif_rx;
bool usb2;
bool rs232;
bool compression_type1;
bool compression_type2;
bool compression_type3;
bool interlace;
bool osd;
bool compression_pipes;
};
#ifdef CONFIG_SYS_FPGA_FLAVOR_GAZERBEAM
/**
* get_versions() - Fill structure with info from version register.
* @dev: FPGA device to be queried for information
* @versions: Pointer to the structure to fill with information from the
* versions register
* Return: 0
*/
static int get_versions(struct udevice *dev, struct fpga_versions *versions)
{
struct ihs_fpga_priv *priv = dev_get_priv(dev);
enum {
VERSIONS_FPGA_VIDEO_CHANNEL = BIT(12),
VERSIONS_FPGA_CON_SIDE = BIT(13),
VERSIONS_FPGA_SC = BIT(14),
VERSIONS_PCB_CON = BIT(9),
VERSIONS_PCB_SC = BIT(8),
VERSIONS_PCB_VIDEO_MASK = 0x3 << 6,
VERSIONS_PCB_VIDEO_DP_1_2 = 0x0 << 6,
VERSIONS_PCB_VIDEO_HDMI_2_0 = 0x1 << 6,
VERSIONS_PCB_TRANSMISSION_MASK = 0x3 << 4,
VERSIONS_PCB_TRANSMISSION_FIBER_10G = 0x0 << 4,
VERSIONS_PCB_TRANSMISSION_CAT_10G = 0x1 << 4,
VERSIONS_PCB_TRANSMISSION_FIBER_3G = 0x2 << 4,
VERSIONS_PCB_TRANSMISSION_CAT_1G = 0x3 << 4,
VERSIONS_HW_VER_MASK = 0xf << 0,
};
u16 raw_versions;
memset(versions, 0, sizeof(struct fpga_versions));
ihs_fpga_get(priv->map, versions, &raw_versions);
versions->video_channel = raw_versions & VERSIONS_FPGA_VIDEO_CHANNEL;
versions->con_side = raw_versions & VERSIONS_FPGA_CON_SIDE;
switch (raw_versions & VERSIONS_PCB_VIDEO_MASK) {
case VERSIONS_PCB_VIDEO_DP_1_2:
versions->pcb_video_type = PCB_DP_1_2;
break;
case VERSIONS_PCB_VIDEO_HDMI_2_0:
versions->pcb_video_type = PCB_HDMI_2_0;
break;
}
switch (raw_versions & VERSIONS_PCB_TRANSMISSION_MASK) {
case VERSIONS_PCB_TRANSMISSION_FIBER_10G:
versions->pcb_transmission_type = PCB_FIBER_10G;
break;
case VERSIONS_PCB_TRANSMISSION_CAT_10G:
versions->pcb_transmission_type = PCB_CAT_10G;
break;
case VERSIONS_PCB_TRANSMISSION_FIBER_3G:
versions->pcb_transmission_type = PCB_FIBER_3G;
break;
case VERSIONS_PCB_TRANSMISSION_CAT_1G:
versions->pcb_transmission_type = PCB_CAT_1G;
break;
}
versions->hw_version = raw_versions & VERSIONS_HW_VER_MASK;
return 0;
}
/**
* get_features() - Fill structure with info from features register.
* @dev: FPGA device to be queried for information
* @features: Pointer to the structure to fill with information from the
* features register
* Return: 0
*/
static int get_features(struct udevice *dev, struct fpga_features *features)
{
struct ihs_fpga_priv *priv = dev_get_priv(dev);
enum {
FEATURE_SPDIF_RX = BIT(15),
FEATURE_SPDIF_TX = BIT(14),
FEATURE_PCM_RX = BIT(13),
FEATURE_PCM_TX = BIT(12),
FEATURE_RAM_MASK = GENMASK(11, 8),
FEATURE_RAM_DDR2_32BIT_295MBPS = 0x0 << 8,
FEATURE_RAM_DDR3_32BIT_590MBPS = 0x1 << 8,
FEATURE_RAM_DDR3_48BIT_590MBPS = 0x2 << 8,
FEATURE_RAM_DDR3_64BIT_1800MBPS = 0x3 << 8,
FEATURE_RAM_DDR3_48BIT_1800MBPS = 0x4 << 8,
FEATURE_CARRIER_SPEED_MASK = GENMASK(7, 6),
FEATURE_CARRIER_SPEED_1G = 0x0 << 6,
FEATURE_CARRIER_SPEED_2_5G = 0x1 << 6,
FEATURE_CARRIER_SPEED_10G = 0x2 << 6,
FEATURE_CARRIERS_MASK = GENMASK(5, 4),
FEATURE_CARRIERS_0 = 0x0 << 4,
FEATURE_CARRIERS_1 = 0x1 << 4,
FEATURE_CARRIERS_2 = 0x2 << 4,
FEATURE_CARRIERS_4 = 0x3 << 4,
FEATURE_USB2 = BIT(3),
FEATURE_VIDEOCHANNELS_MASK = GENMASK(2, 0),
FEATURE_VIDEOCHANNELS_0 = 0x0 << 0,
FEATURE_VIDEOCHANNELS_1 = 0x1 << 0,
FEATURE_VIDEOCHANNELS_1_1 = 0x2 << 0,
FEATURE_VIDEOCHANNELS_2 = 0x3 << 0,
};
enum {
EXT_FEATURE_OSD = BIT(15),
EXT_FEATURE_ETHERNET = BIT(9),
EXT_FEATURE_INTERLACE = BIT(8),
EXT_FEATURE_RS232 = BIT(7),
EXT_FEATURE_COMPRESSION_PERF_MASK = GENMASK(6, 4),
EXT_FEATURE_COMPRESSION_PERF_1X = 0x0 << 4,
EXT_FEATURE_COMPRESSION_PERF_2X = 0x1 << 4,
EXT_FEATURE_COMPRESSION_PERF_4X = 0x2 << 4,
EXT_FEATURE_COMPRESSION_TYPE1 = BIT(0),
EXT_FEATURE_COMPRESSION_TYPE2 = BIT(1),
EXT_FEATURE_COMPRESSION_TYPE3 = BIT(2),
};
u16 raw_features;
u16 raw_extended_features;
memset(features, 0, sizeof(struct fpga_features));
ihs_fpga_get(priv->map, features, &raw_features);
ihs_fpga_get(priv->map, extended_features, &raw_extended_features);
switch (raw_features & FEATURE_VIDEOCHANNELS_MASK) {
case FEATURE_VIDEOCHANNELS_0:
features->video_channels = 0;
break;
case FEATURE_VIDEOCHANNELS_1:
features->video_channels = 1;
break;
case FEATURE_VIDEOCHANNELS_1_1:
case FEATURE_VIDEOCHANNELS_2:
features->video_channels = 2;
break;
};
switch (raw_features & FEATURE_CARRIERS_MASK) {
case FEATURE_CARRIERS_0:
features->carriers = 0;
break;
case FEATURE_CARRIERS_1:
features->carriers = 1;
break;
case FEATURE_CARRIERS_2:
features->carriers = 2;
break;
case FEATURE_CARRIERS_4:
features->carriers = 4;
break;
}
switch (raw_features & FEATURE_CARRIER_SPEED_MASK) {
case FEATURE_CARRIER_SPEED_1G:
features->carrier_speed = CARRIER_SPEED_1G;
break;
case FEATURE_CARRIER_SPEED_2_5G:
features->carrier_speed = CARRIER_SPEED_2_5G;
break;
case FEATURE_CARRIER_SPEED_10G:
features->carrier_speed = CARRIER_SPEED_10G;
break;
}
switch (raw_features & FEATURE_RAM_MASK) {
case FEATURE_RAM_DDR2_32BIT_295MBPS:
features->ram_config = RAM_DDR2_32BIT_295MBPS;
break;
case FEATURE_RAM_DDR3_32BIT_590MBPS:
features->ram_config = RAM_DDR3_32BIT_590MBPS;
break;
case FEATURE_RAM_DDR3_48BIT_590MBPS:
features->ram_config = RAM_DDR3_48BIT_590MBPS;
break;
case FEATURE_RAM_DDR3_64BIT_1800MBPS:
features->ram_config = RAM_DDR3_64BIT_1800MBPS;
break;
case FEATURE_RAM_DDR3_48BIT_1800MBPS:
features->ram_config = RAM_DDR3_48BIT_1800MBPS;
break;
}
features->pcm_tx = raw_features & FEATURE_PCM_TX;
features->pcm_rx = raw_features & FEATURE_PCM_RX;
features->spdif_tx = raw_features & FEATURE_SPDIF_TX;
features->spdif_rx = raw_features & FEATURE_SPDIF_RX;
features->usb2 = raw_features & FEATURE_USB2;
features->rs232 = raw_extended_features & EXT_FEATURE_RS232;
features->compression_type1 = raw_extended_features &
EXT_FEATURE_COMPRESSION_TYPE1;
features->compression_type2 = raw_extended_features &
EXT_FEATURE_COMPRESSION_TYPE2;
features->compression_type3 = raw_extended_features &
EXT_FEATURE_COMPRESSION_TYPE3;
features->interlace = raw_extended_features & EXT_FEATURE_INTERLACE;
features->osd = raw_extended_features & EXT_FEATURE_OSD;
features->compression_pipes = raw_extended_features &
EXT_FEATURE_COMPRESSION_PERF_MASK;
return 0;
}
#else
/**
* get_versions() - Fill structure with info from version register.
* @fpga: Identifier of the FPGA device to be queried for information
* @versions: Pointer to the structure to fill with information from the
* versions register
*
* This is the legacy version and should be considered deprecated for new
* devices.
*
* Return: 0
*/
static int get_versions(unsigned int fpga, struct fpga_versions *versions)
{
enum {
/* HW version encoding is a mess, leave it for the moment */
VERSIONS_HW_VER_MASK = 0xf << 0,
VERSIONS_PIX_CLOCK_GEN_IDT8N3QV01 = BIT(4),
VERSIONS_SFP = BIT(5),
VERSIONS_VIDEO_MASK = 0x7 << 6,
VERSIONS_VIDEO_DVI = 0x0 << 6,
VERSIONS_VIDEO_DP_165 = 0x1 << 6,
VERSIONS_VIDEO_DP_300 = 0x2 << 6,
VERSIONS_VIDEO_HDMI = 0x3 << 6,
VERSIONS_UT_MASK = 0xf << 12,
VERSIONS_UT_MAIN_SERVER = 0x0 << 12,
VERSIONS_UT_MAIN_USER = 0x1 << 12,
VERSIONS_UT_VIDEO_SERVER = 0x2 << 12,
VERSIONS_UT_VIDEO_USER = 0x3 << 12,
};
u16 raw_versions;
memset(versions, 0, sizeof(struct fpga_versions));
FPGA_GET_REG(fpga, versions, &raw_versions);
switch (raw_versions & VERSIONS_UT_MASK) {
case VERSIONS_UT_MAIN_SERVER:
versions->video_channel = false;
versions->con_side = false;
break;
case VERSIONS_UT_MAIN_USER:
versions->video_channel = false;
versions->con_side = true;
break;
case VERSIONS_UT_VIDEO_SERVER:
versions->video_channel = true;
versions->con_side = false;
break;
case VERSIONS_UT_VIDEO_USER:
versions->video_channel = true;
versions->con_side = true;
break;
}
switch (raw_versions & VERSIONS_VIDEO_MASK) {
case VERSIONS_VIDEO_DVI:
versions->pcb_video_type = PCB_DVI_SL;
break;
case VERSIONS_VIDEO_DP_165:
versions->pcb_video_type = PCB_DP_165MPIX;
break;
case VERSIONS_VIDEO_DP_300:
versions->pcb_video_type = PCB_DP_300MPIX;
break;
case VERSIONS_VIDEO_HDMI:
versions->pcb_video_type = PCB_HDMI;
break;
}
versions->hw_version = raw_versions & VERSIONS_HW_VER_MASK;
if (raw_versions & VERSIONS_SFP)
versions->pcb_transmission_type = PCB_FIBER_3G;
else
versions->pcb_transmission_type = PCB_CAT_1G;
return 0;
}
/**
* get_features() - Fill structure with info from features register.
* @fpga: Identifier of the FPGA device to be queried for information
* @features: Pointer to the structure to fill with information from the
* features register
*
* This is the legacy version and should be considered deprecated for new
* devices.
*
* Return: 0
*/
static int get_features(unsigned int fpga, struct fpga_features *features)
{
enum {
FEATURE_CARRIER_SPEED_2_5 = BIT(4),
FEATURE_RAM_MASK = 0x7 << 5,
FEATURE_RAM_DDR2_32BIT = 0x0 << 5,
FEATURE_RAM_DDR3_32BIT = 0x1 << 5,
FEATURE_RAM_DDR3_48BIT = 0x2 << 5,
FEATURE_PCM_AUDIO_TX = BIT(9),
FEATURE_PCM_AUDIO_RX = BIT(10),
FEATURE_OSD = BIT(11),
FEATURE_USB20 = BIT(12),
FEATURE_COMPRESSION_MASK = 7 << 13,
FEATURE_COMPRESSION_TYPE1 = 0x1 << 13,
FEATURE_COMPRESSION_TYPE1_TYPE2 = 0x3 << 13,
FEATURE_COMPRESSION_TYPE1_TYPE2_TYPE3 = 0x7 << 13,
};
enum {
EXTENDED_FEATURE_SPDIF_AUDIO_TX = BIT(0),
EXTENDED_FEATURE_SPDIF_AUDIO_RX = BIT(1),
EXTENDED_FEATURE_RS232 = BIT(2),
EXTENDED_FEATURE_COMPRESSION_PIPES = BIT(3),
EXTENDED_FEATURE_INTERLACE = BIT(4),
};
u16 raw_features;
u16 raw_extended_features;
memset(features, 0, sizeof(struct fpga_features));
FPGA_GET_REG(fpga, fpga_features, &raw_features);
FPGA_GET_REG(fpga, fpga_ext_features, &raw_extended_features);
features->video_channels = raw_features & 0x3;
features->carriers = (raw_features >> 2) & 0x3;
features->carrier_speed = (raw_features & FEATURE_CARRIER_SPEED_2_5)
? CARRIER_SPEED_2_5G : CARRIER_SPEED_1G;
switch (raw_features & FEATURE_RAM_MASK) {
case FEATURE_RAM_DDR2_32BIT:
features->ram_config = RAM_DDR2_32BIT_295MBPS;
break;
case FEATURE_RAM_DDR3_32BIT:
features->ram_config = RAM_DDR3_32BIT_590MBPS;
break;
case FEATURE_RAM_DDR3_48BIT:
features->ram_config = RAM_DDR3_48BIT_590MBPS;
break;
}
features->pcm_tx = raw_features & FEATURE_PCM_AUDIO_TX;
features->pcm_rx = raw_features & FEATURE_PCM_AUDIO_RX;
features->spdif_tx = raw_extended_features &
EXTENDED_FEATURE_SPDIF_AUDIO_TX;
features->spdif_rx = raw_extended_features &
EXTENDED_FEATURE_SPDIF_AUDIO_RX;
features->usb2 = raw_features & FEATURE_USB20;
features->rs232 = raw_extended_features & EXTENDED_FEATURE_RS232;
features->compression_type1 = false;
features->compression_type2 = false;
features->compression_type3 = false;
switch (raw_features & FEATURE_COMPRESSION_MASK) {
case FEATURE_COMPRESSION_TYPE1_TYPE2_TYPE3:
features->compression_type3 = true;
/* fall-through */
case FEATURE_COMPRESSION_TYPE1_TYPE2:
features->compression_type2 = true;
/* fall-through */
case FEATURE_COMPRESSION_TYPE1:
features->compression_type1 = true;
break;
}
features->interlace = raw_extended_features &
EXTENDED_FEATURE_INTERLACE;
features->osd = raw_features & FEATURE_OSD;
features->compression_pipes = raw_extended_features &
EXTENDED_FEATURE_COMPRESSION_PIPES;
return 0;
}
#endif
/**
* fpga_print_info() - Print information about FPGA device
* @dev: FPGA device to print information about
*/
static void fpga_print_info(struct udevice *dev)
{
struct ihs_fpga_priv *priv = dev_get_priv(dev);
u16 fpga_version;
struct fpga_versions versions;
struct fpga_features features;
ihs_fpga_get(priv->map, fpga_version, &fpga_version);
get_versions(dev, &versions);
get_features(dev, &features);
if (versions.video_channel)
printf("Videochannel");
else
printf("Mainchannel");
if (versions.con_side)
printf(" User");
else
printf(" Server");
switch (versions.pcb_transmission_type) {
case PCB_CAT_1G:
case PCB_CAT_10G:
printf(" CAT");
break;
case PCB_FIBER_3G:
case PCB_FIBER_10G:
printf(" Fiber");
break;
};
switch (versions.pcb_video_type) {
case PCB_DVI_SL:
printf(" DVI,");
break;
case PCB_DP_165MPIX:
printf(" DP 165MPix/s,");
break;
case PCB_DP_300MPIX:
printf(" DP 300MPix/s,");
break;
case PCB_HDMI:
printf(" HDMI,");
break;
case PCB_DP_1_2:
printf(" DP 1.2,");
break;
case PCB_HDMI_2_0:
printf(" HDMI 2.0,");
break;
}
printf(" FPGA V %d.%02d\n features: ",
fpga_version / 100, fpga_version % 100);
if (!features.compression_type1 &&
!features.compression_type2 &&
!features.compression_type3)
printf("no compression, ");
if (features.compression_type1)
printf("type1, ");
if (features.compression_type2)
printf("type2, ");
if (features.compression_type3)
printf("type3, ");
printf("%sosd", features.osd ? "" : "no ");
if (features.pcm_rx && features.pcm_tx)
printf(", pcm rx+tx");
else if (features.pcm_rx)
printf(", pcm rx");
else if (features.pcm_tx)
printf(", pcm tx");
if (features.spdif_rx && features.spdif_tx)
printf(", spdif rx+tx");
else if (features.spdif_rx)
printf(", spdif rx");
else if (features.spdif_tx)
printf(", spdif tx");
puts(",\n ");
switch (features.sysclock) {
case SYSCLK_147456:
printf("clock 147.456 MHz");
break;
}
switch (features.ram_config) {
case RAM_DDR2_32BIT_295MBPS:
printf(", RAM 32 bit DDR2");
break;
case RAM_DDR3_32BIT_590MBPS:
printf(", RAM 32 bit DDR3");
break;
case RAM_DDR3_48BIT_590MBPS:
case RAM_DDR3_48BIT_1800MBPS:
printf(", RAM 48 bit DDR3");
break;
case RAM_DDR3_64BIT_1800MBPS:
printf(", RAM 64 bit DDR3");
break;
}
printf(", %d carrier(s)", features.carriers);
switch (features.carrier_speed) {
case CARRIER_SPEED_1G:
printf(", 1Gbit/s");
break;
case CARRIER_SPEED_3G:
printf(", 3Gbit/s");
break;
case CARRIER_SPEED_10G:
printf(", 10Gbit/s");
break;
}
printf(", %d video channel(s)\n", features.video_channels);
}
/**
* do_reflection_test() - Run reflection test on a FPGA device
* @dev: FPGA device to run reflection test on
*
* Return: 0 if reflection test succeeded, -ve on error
*/
static int do_reflection_test(struct udevice *dev)
{
struct ihs_fpga_priv *priv = dev_get_priv(dev);
int ctr = 0;
while (1) {
u16 val;
ihs_fpga_set(priv->map, reflection_low, REFLECTION_TESTPATTERN);
ihs_fpga_get(priv->map, reflection_low, &val);
if (val == (~REFLECTION_TESTPATTERN & 0xffff))
return -EIO;
mdelay(REFLECTION_TEST_DELAY);
if (ctr++ > REFLECTION_TEST_ROUNDS)
return 0;
}
}
/**
* wait_for_fpga_done() - Wait until 'done'-flag is set for FPGA device
* @dev: FPGA device whose done flag to wait for
*
* This function waits until it detects that the done-GPIO's value was changed
* to 1 by the FPGA, which indicates that the device is configured and ready to
* use.
*
* Return: 0 if done flag was detected, -ve on error
*/
static int wait_for_fpga_done(struct udevice *dev)
{
struct ihs_fpga_priv *priv = dev_get_priv(dev);
int ctr = 0;
int done_val;
while (1) {
done_val = dm_gpio_get_value(&priv->done_gpio);
if (done_val < 0) {
debug("%s: Error while reading done-GPIO (err = %d)\n",
dev->name, done_val);
return done_val;
}
if (done_val)
return 0;
mdelay(FPGA_DONE_WAIT_DELAY);
if (ctr++ > FPGA_DONE_WAIT_ROUND) {
debug("%s: FPGA init failed (done not detected)\n",
dev->name);
return -EIO;
}
}
}
static int ihs_fpga_probe(struct udevice *dev)
{
struct ihs_fpga_priv *priv = dev_get_priv(dev);
int ret;
/* TODO(mario.six@gdsys.cc): Case of FPGA attached to MCLink bus */
ret = regmap_init_mem(dev_ofnode(dev), &priv->map);
if (ret) {
debug("%s: Could not initialize regmap (err = %d)",
dev->name, ret);
return ret;
}
ret = gpio_request_by_name(dev, "reset-gpios", 0, &priv->reset_gpio,
GPIOD_IS_OUT);
if (ret) {
debug("%s: Could not get reset-GPIO (err = %d)\n",
dev->name, ret);
return ret;
}
if (!priv->reset_gpio.dev) {
debug("%s: Could not get reset-GPIO\n", dev->name);
return -ENOENT;
}
ret = gpio_request_by_name(dev, "done-gpios", 0, &priv->done_gpio,
GPIOD_IS_IN);
if (ret) {
debug("%s: Could not get done-GPIO (err = %d)\n",
dev->name, ret);
return ret;
}
if (!priv->done_gpio.dev) {
debug("%s: Could not get done-GPIO\n", dev->name);
return -ENOENT;
}
ret = dm_gpio_set_value(&priv->reset_gpio, 1);
if (ret) {
debug("%s: Error while setting reset-GPIO (err = %d)\n",
dev->name, ret);
return ret;
}
/* If FPGA already runs, don't initialize again */
if (do_reflection_test(dev))
goto reflection_ok;
ret = dm_gpio_set_value(&priv->reset_gpio, 0);
if (ret) {
debug("%s: Error while setting reset-GPIO (err = %d)\n",
dev->name, ret);
return ret;
}
ret = wait_for_fpga_done(dev);
if (ret) {
debug("%s: Error while waiting for FPGA done (err = %d)\n",
dev->name, ret);
return ret;
}
udelay(10);
ret = dm_gpio_set_value(&priv->reset_gpio, 1);
if (ret) {
debug("%s: Error while setting reset-GPIO (err = %d)\n",
dev->name, ret);
return ret;
}
if (!do_reflection_test(dev)) {
debug("%s: Reflection test FAILED\n", dev->name);
return -EIO;
}
reflection_ok:
printf("%s: Reflection test passed.\n", dev->name);
fpga_print_info(dev);
return 0;
}
static const struct udevice_id ihs_fpga_ids[] = {
{ .compatible = "gdsys,iocon_fpga" },
{ .compatible = "gdsys,iocpu_fpga" },
{ }
};
U_BOOT_DRIVER(ihs_fpga_bus) = {
.name = "ihs_fpga_bus",
.id = UCLASS_MISC,
.of_match = ihs_fpga_ids,
.probe = ihs_fpga_probe,
.priv_auto_alloc_size = sizeof(struct ihs_fpga_priv),
};

49
drivers/misc/ihs_fpga.h Normal file
View File

@ -0,0 +1,49 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* (C) Copyright 2018
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
*/
/**
* struct ihs_fpga_regs - IHS FPGA register map structure
* @reflection_low: Lower reflection register
* @versions: PCB versions register
* @fpga_version: FPGA versions register
* @features: FPGA features register
* @extended_features: FPGA extended features register
* @top_interrupt: Top interrupt register
* @top_interrupt_enable: Top interrupt enable register
* @status: FPGA status register
* @control: FPGA control register
* @extended_control: FPGA extended control register
*/
struct ihs_fpga_regs {
u16 reflection_low;
u16 versions;
u16 fpga_version;
u16 features;
u16 extended_features;
u16 top_interrupt;
u16 top_interrupt_enable;
u16 status;
u16 control;
u16 extended_control;
};
/**
* ihs_fpga_set() - Convenience macro to set values in FPGA register map
* @map: Register map to set a value in
* @member: Name of member (described by ihs_fpga_regs) to set
* @val: Value to set the member to
*/
#define ihs_fpga_set(map, member, val) \
regmap_set(map, struct ihs_fpga_regs, member, val)
/**
* ihs_fpga_get() - Convenience macro to get values from FPGA register map
* @map: Register map to read value from
* @member: Name of member (described by ihs_fpga_regs) to get
* @valp: Pointe to variable to receive the value read
*/
#define ihs_fpga_get(map, member, valp) \
regmap_get(map, struct ihs_fpga_regs, member, valp)

View File

@ -223,7 +223,7 @@ static int imx8_scu_bind(struct udevice *dev)
if (node < 0)
panic("No clk node found\n");
ret = lists_bind_fdt(dev, offset_to_ofnode(node), &child);
ret = lists_bind_fdt(dev, offset_to_ofnode(node), &child, true);
if (ret)
return ret;
@ -234,7 +234,7 @@ static int imx8_scu_bind(struct udevice *dev)
if (node < 0)
panic("No iomuxc node found\n");
ret = lists_bind_fdt(dev, offset_to_ofnode(node), &child);
ret = lists_bind_fdt(dev, offset_to_ofnode(node), &child, true);
if (ret)
return ret;

View File

@ -124,12 +124,21 @@ static int sandbox_swap_case_read_config(struct udevice *emul, uint offset,
case PCI_CAP_ID_PM_OFFSET:
*valuep = (PCI_CAP_ID_EXP_OFFSET << 8) | PCI_CAP_ID_PM;
break;
case PCI_CAP_ID_PM_OFFSET + PCI_CAP_LIST_NEXT:
*valuep = PCI_CAP_ID_EXP_OFFSET;
break;
case PCI_CAP_ID_EXP_OFFSET:
*valuep = (PCI_CAP_ID_MSIX_OFFSET << 8) | PCI_CAP_ID_EXP;
break;
case PCI_CAP_ID_EXP_OFFSET + PCI_CAP_LIST_NEXT:
*valuep = PCI_CAP_ID_MSIX_OFFSET;
break;
case PCI_CAP_ID_MSIX_OFFSET:
*valuep = PCI_CAP_ID_MSIX;
break;
case PCI_CAP_ID_MSIX_OFFSET + PCI_CAP_LIST_NEXT:
*valuep = 0;
break;
case PCI_EXT_CAP_ID_ERR_OFFSET:
*valuep = (PCI_EXT_CAP_ID_VC_OFFSET << 20) | PCI_EXT_CAP_ID_ERR;
break;

View File

@ -2444,9 +2444,6 @@ static int mmc_startup(struct mmc *mmc)
bdesc->product[0] = 0;
bdesc->revision[0] = 0;
#endif
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
part_init(bdesc);
#endif
return 0;
}

View File

@ -1953,6 +1953,8 @@ U_BOOT_DRIVER(omap_hsmmc) = {
.ops = &omap_hsmmc_ops,
.probe = omap_hsmmc_probe,
.priv_auto_alloc_size = sizeof(struct omap_hsmmc_data),
#if !CONFIG_IS_ENABLED(OF_CONTROL)
.flags = DM_FLAG_PRE_RELOC,
#endif
};
#endif

View File

@ -664,7 +664,6 @@ static int nvme_blk_probe(struct udevice *udev)
sprintf(desc->vendor, "0x%.4x", pplat->vendor);
memcpy(desc->product, ndev->serial, sizeof(ndev->serial));
memcpy(desc->revision, ndev->firmware_rev, sizeof(ndev->firmware_rev));
part_init(desc);
return 0;
}

View File

@ -1344,26 +1344,14 @@ void *dm_pci_map_bar(struct udevice *dev, int bar, int flags)
return dm_pci_bus_to_virt(dev, pci_bus_addr, flags, 0, MAP_NOCACHE);
}
int dm_pci_find_capability(struct udevice *dev, int cap)
static int _dm_pci_find_next_capability(struct udevice *dev, u8 pos, int cap)
{
u16 status;
u8 header_type;
int ttl = PCI_FIND_CAP_TTL;
u8 id;
u16 ent;
u8 pos;
dm_pci_read_config16(dev, PCI_STATUS, &status);
if (!(status & PCI_STATUS_CAP_LIST))
return 0;
dm_pci_read_config8(dev, PCI_HEADER_TYPE, &header_type);
if ((header_type & 0x7f) == PCI_HEADER_TYPE_CARDBUS)
pos = PCI_CB_CAPABILITY_LIST;
else
pos = PCI_CAPABILITY_LIST;
dm_pci_read_config8(dev, pos, &pos);
while (ttl--) {
if (pos < PCI_STD_HEADER_SIZEOF)
break;
@ -1381,7 +1369,32 @@ int dm_pci_find_capability(struct udevice *dev, int cap)
return 0;
}
int dm_pci_find_ext_capability(struct udevice *dev, int cap)
int dm_pci_find_next_capability(struct udevice *dev, u8 start, int cap)
{
return _dm_pci_find_next_capability(dev, start + PCI_CAP_LIST_NEXT,
cap);
}
int dm_pci_find_capability(struct udevice *dev, int cap)
{
u16 status;
u8 header_type;
u8 pos;
dm_pci_read_config16(dev, PCI_STATUS, &status);
if (!(status & PCI_STATUS_CAP_LIST))
return 0;
dm_pci_read_config8(dev, PCI_HEADER_TYPE, &header_type);
if ((header_type & 0x7f) == PCI_HEADER_TYPE_CARDBUS)
pos = PCI_CB_CAPABILITY_LIST;
else
pos = PCI_CAPABILITY_LIST;
return _dm_pci_find_next_capability(dev, pos, cap);
}
int dm_pci_find_next_ext_capability(struct udevice *dev, int start, int cap)
{
u32 header;
int ttl;
@ -1390,6 +1403,9 @@ int dm_pci_find_ext_capability(struct udevice *dev, int cap)
/* minimum 8 bytes per capability */
ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
if (start)
pos = start;
dm_pci_read_config32(dev, pos, &header);
/*
* If we have no capabilities, this is indicated by cap ID,
@ -1412,6 +1428,11 @@ int dm_pci_find_ext_capability(struct udevice *dev, int cap)
return 0;
}
int dm_pci_find_ext_capability(struct udevice *dev, int cap)
{
return dm_pci_find_next_ext_capability(dev, 0, cap);
}
UCLASS_DRIVER(pci) = {
.id = UCLASS_PCI,
.name = "pci",

View File

@ -148,5 +148,7 @@ U_BOOT_DRIVER(pinctrl_bcm283x) = {
.priv_auto_alloc_size = sizeof(struct bcm283x_pinctrl_priv),
.ops = &bcm283x_pinctrl_ops,
.probe = bcm283x_pinctl_probe,
#if !CONFIG_IS_ENABLED(OF_CONTROL)
.flags = DM_FLAG_PRE_RELOC,
#endif
};

View File

@ -113,5 +113,4 @@ U_BOOT_DRIVER(pinctrl_exynos7420) = {
.priv_auto_alloc_size = sizeof(struct exynos_pinctrl_priv),
.ops = &exynos7420_pinctrl_ops,
.probe = exynos_pinctrl_probe,
.flags = DM_FLAG_PRE_RELOC
};

View File

@ -40,5 +40,7 @@ U_BOOT_DRIVER(imx5_pinctrl) = {
.remove = imx_pinctrl_remove,
.priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv),
.ops = &imx_pinctrl_ops,
#if !CONFIG_IS_ENABLED(OF_CONTROL)
.flags = DM_FLAG_PRE_RELOC,
#endif
};

View File

@ -49,5 +49,7 @@ U_BOOT_DRIVER(imx6_pinctrl) = {
.remove = imx_pinctrl_remove,
.priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv),
.ops = &imx_pinctrl_ops,
#if !CONFIG_IS_ENABLED(OF_CONTROL)
.flags = DM_FLAG_PRE_RELOC,
#endif
};

View File

@ -37,5 +37,7 @@ U_BOOT_DRIVER(imx7_pinctrl) = {
.remove = imx_pinctrl_remove,
.priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv),
.ops = &imx_pinctrl_ops,
#if !CONFIG_IS_ENABLED(OF_CONTROL)
.flags = DM_FLAG_PRE_RELOC,
#endif
};

View File

@ -41,5 +41,7 @@ U_BOOT_DRIVER(imx7ulp_pinctrl) = {
.remove = imx_pinctrl_remove,
.priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv),
.ops = &imx_pinctrl_ops,
#if !CONFIG_IS_ENABLED(OF_CONTROL)
.flags = DM_FLAG_PRE_RELOC,
#endif
};

View File

@ -136,7 +136,6 @@ U_BOOT_DRIVER(single_pinctrl) = {
.id = UCLASS_PINCTRL,
.of_match = single_pinctrl_match,
.ops = &single_pinctrl_ops,
.flags = DM_FLAG_PRE_RELOC,
.platdata_auto_alloc_size = sizeof(struct single_pdata),
.ofdata_to_platdata = single_ofdata_to_platdata,
};

View File

@ -171,5 +171,7 @@ U_BOOT_DRIVER(uniphier_pro4_pinctrl) = {
.probe = uniphier_pro4_pinctrl_probe,
.priv_auto_alloc_size = sizeof(struct uniphier_pinctrl_priv),
.ops = &uniphier_pinctrl_ops,
#if !CONFIG_IS_ENABLED(OF_CONTROL)
.flags = DM_FLAG_PRE_RELOC,
#endif
};

View File

@ -153,5 +153,7 @@ U_BOOT_DRIVER(uniphier_pro5_pinctrl) = {
.probe = uniphier_pro5_pinctrl_probe,
.priv_auto_alloc_size = sizeof(struct uniphier_pinctrl_priv),
.ops = &uniphier_pinctrl_ops,
#if !CONFIG_IS_ENABLED(OF_CONTROL)
.flags = DM_FLAG_PRE_RELOC,
#endif
};

View File

@ -173,5 +173,4 @@ U_BOOT_DRIVER(bmips_ram) = {
.probe = bmips_ram_probe,
.priv_auto_alloc_size = sizeof(struct bmips_ram_priv),
.ops = &bmips_ram_ops,
.flags = DM_FLAG_PRE_RELOC,
};

View File

@ -592,7 +592,6 @@ static int do_scsi_scan_one(struct udevice *dev, int id, int lun, bool verbose)
memcpy(&bdesc->vendor, &bd.vendor, sizeof(bd.vendor));
memcpy(&bdesc->product, &bd.product, sizeof(bd.product));
memcpy(&bdesc->revision, &bd.revision, sizeof(bd.revision));
part_init(bdesc);
if (verbose) {
printf(" Device %d: ", 0);

View File

@ -121,7 +121,6 @@ U_BOOT_DRIVER(altera_jtaguart) = {
.platdata_auto_alloc_size = sizeof(struct altera_jtaguart_platdata),
.probe = altera_jtaguart_probe,
.ops = &altera_jtaguart_ops,
.flags = DM_FLAG_PRE_RELOC,
};
#ifdef CONFIG_DEBUG_UART_ALTERA_JTAGUART

View File

@ -117,7 +117,6 @@ U_BOOT_DRIVER(altera_uart) = {
.platdata_auto_alloc_size = sizeof(struct altera_uart_platdata),
.probe = altera_uart_probe,
.ops = &altera_uart_ops,
.flags = DM_FLAG_PRE_RELOC,
};
#ifdef CONFIG_DEBUG_UART_ALTERA_UART

View File

@ -155,7 +155,6 @@ U_BOOT_DRIVER(serial_dcc) = {
.id = UCLASS_SERIAL,
.of_match = arm_dcc_ids,
.ops = &arm_dcc_ops,
.flags = DM_FLAG_PRE_RELOC,
};
#ifdef CONFIG_DEBUG_UART_ARM_DCC

View File

@ -294,7 +294,9 @@ U_BOOT_DRIVER(serial_atmel) = {
#endif
.probe = atmel_serial_probe,
.ops = &atmel_serial_ops,
#if !CONFIG_IS_ENABLED(OF_CONTROL)
.flags = DM_FLAG_PRE_RELOC,
#endif
.priv_auto_alloc_size = sizeof(struct atmel_serial_priv),
};
#endif

View File

@ -267,12 +267,26 @@ static inline void _debug_uart_init(void)
serial_dout(&com_port->lcr, UART_LCRVAL);
}
static inline int NS16550_read_baud_divisor(struct NS16550 *com_port)
{
int ret;
serial_dout(&com_port->lcr, UART_LCR_BKSE | UART_LCRVAL);
ret = serial_din(&com_port->dll) & 0xff;
ret |= (serial_din(&com_port->dlm) & 0xff) << 8;
serial_dout(&com_port->lcr, UART_LCRVAL);
return ret;
}
static inline void _debug_uart_putc(int ch)
{
struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
while (!(serial_din(&com_port->lsr) & UART_LSR_THRE))
;
while (!(serial_din(&com_port->lsr) & UART_LSR_THRE)) {
if (!NS16550_read_baud_divisor(com_port))
return;
}
serial_dout(&com_port->thr, ch);
}
@ -473,7 +487,9 @@ U_BOOT_DRIVER(ns16550_serial) = {
.priv_auto_alloc_size = sizeof(struct NS16550),
.probe = ns16550_serial_probe,
.ops = &ns16550_serial_ops,
#if !CONFIG_IS_ENABLED(OF_CONTROL)
.flags = DM_FLAG_PRE_RELOC,
#endif
};
#endif
#endif /* SERIAL_PRESENT */

View File

@ -62,7 +62,7 @@ static int serial_check_stdout(const void *blob, struct udevice **devp)
* anyway.
*/
if (node > 0 && !lists_bind_fdt(gd->dm_root, offset_to_ofnode(node),
devp)) {
devp, false)) {
if (!device_probe(*devp))
return 0;
}

View File

@ -189,7 +189,6 @@ U_BOOT_DRIVER(serial_ar933x) = {
.priv_auto_alloc_size = sizeof(struct ar933x_serial_priv),
.probe = ar933x_serial_probe,
.ops = &ar933x_serial_ops,
.flags = DM_FLAG_PRE_RELOC,
};
#ifdef CONFIG_DEBUG_UART_AR933X

View File

@ -128,7 +128,6 @@ U_BOOT_DRIVER(serial_arc) = {
.ofdata_to_platdata = arc_serial_ofdata_to_platdata,
.probe = arc_serial_probe,
.ops = &arc_serial_ops,
.flags = DM_FLAG_PRE_RELOC,
};
#ifdef CONFIG_DEBUG_ARC_SERIAL

View File

@ -199,6 +199,8 @@ U_BOOT_DRIVER(serial_bcm283x_mu) = {
.platdata_auto_alloc_size = sizeof(struct bcm283x_mu_serial_platdata),
.probe = bcm283x_mu_serial_probe,
.ops = &bcm283x_mu_serial_ops,
#if !CONFIG_IS_ENABLED(OF_CONTROL)
.flags = DM_FLAG_PRE_RELOC,
#endif
.priv_auto_alloc_size = sizeof(struct bcm283x_mu_priv),
};

View File

@ -90,6 +90,8 @@ U_BOOT_DRIVER(bcm283x_pl011_uart) = {
.platdata_auto_alloc_size = sizeof(struct pl01x_serial_platdata),
.probe = pl01x_serial_probe,
.ops = &bcm283x_pl011_serial_ops,
#if !CONFIG_IS_ENABLED(OF_CONTROL)
.flags = DM_FLAG_PRE_RELOC,
#endif
.priv_auto_alloc_size = sizeof(struct pl01x_priv),
};

View File

@ -264,7 +264,6 @@ U_BOOT_DRIVER(bcm6345_serial) = {
.probe = bcm6345_serial_probe,
.priv_auto_alloc_size = sizeof(struct bcm6345_serial_priv),
.ops = &bcm6345_serial_ops,
.flags = DM_FLAG_PRE_RELOC,
};
#ifdef CONFIG_DEBUG_UART_BCM6345

View File

@ -152,5 +152,4 @@ U_BOOT_DRIVER(serial_efi) = {
.priv_auto_alloc_size = sizeof(struct serial_efi_priv),
.probe = serial_efi_probe,
.ops = &serial_efi_ops,
.flags = DM_FLAG_PRE_RELOC,
};

View File

@ -64,5 +64,4 @@ U_BOOT_DRIVER(serial_intel_mid) = {
.priv_auto_alloc_size = sizeof(struct NS16550),
.probe = mid_serial_probe,
.ops = &ns16550_serial_ops,
.flags = DM_FLAG_PRE_RELOC,
};

View File

@ -540,5 +540,4 @@ U_BOOT_DRIVER(serial_lpuart) = {
.platdata_auto_alloc_size = sizeof(struct lpuart_serial_platdata),
.probe = lpuart_serial_probe,
.ops = &lpuart_serial_ops,
.flags = DM_FLAG_PRE_RELOC,
};

View File

@ -132,7 +132,6 @@ U_BOOT_DRIVER(serial_meson) = {
.of_match = meson_serial_ids,
.probe = meson_serial_probe,
.ops = &meson_serial_ops,
.flags = DM_FLAG_PRE_RELOC,
.ofdata_to_platdata = meson_serial_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct meson_serial_platdata),
};

View File

@ -129,7 +129,6 @@ U_BOOT_DRIVER(serial_mvebu) = {
.platdata_auto_alloc_size = sizeof(struct mvebu_platdata),
.probe = mvebu_serial_probe,
.ops = &mvebu_serial_ops,
.flags = DM_FLAG_PRE_RELOC,
};
#ifdef CONFIG_DEBUG_MVEBU_A3700_UART

View File

@ -354,7 +354,9 @@ U_BOOT_DRIVER(serial_mxc) = {
#endif
.probe = mxc_serial_probe,
.ops = &mxc_serial_ops,
#if !CONFIG_IS_ENABLED(OF_CONTROL)
.flags = DM_FLAG_PRE_RELOC,
#endif
};
#endif

View File

@ -121,7 +121,9 @@ U_BOOT_DRIVER(omap_serial) = {
.priv_auto_alloc_size = sizeof(struct NS16550),
.probe = ns16550_serial_probe,
.ops = &ns16550_serial_ops,
#if !CONFIG_IS_ENABLED(OF_CONTROL)
.flags = DM_FLAG_PRE_RELOC,
#endif
};
#endif
#endif /* DM_SERIAL */

View File

@ -132,5 +132,4 @@ U_BOOT_DRIVER(serial_owl) = {
.priv_auto_alloc_size = sizeof(struct owl_serial_priv),
.probe = owl_serial_probe,
.ops = &owl_serial_ops,
.flags = DM_FLAG_PRE_RELOC,
};

Some files were not shown because too many files have changed in this diff Show More