Merge branch 'master' of git://git.denx.de/u-boot-video
This commit is contained in:
commit
282ce6454c
22
Documentation/devicetree/bindings/axi/gdsys,ihs_axi.txt
Normal file
22
Documentation/devicetree/bindings/axi/gdsys,ihs_axi.txt
Normal file
@ -0,0 +1,22 @@
|
||||
gdsys AXI busses of IHS FPGA devices
|
||||
|
||||
Certain gdsys IHS FPGAs offer a interface to their built-in AXI bus with which
|
||||
the connected devices (usually IP cores) can be controlled via software.
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "gdsys,ihs_axi"
|
||||
- reg: describes the address and length of the AXI bus's register map (within
|
||||
the FPGA's register space)
|
||||
|
||||
Example:
|
||||
|
||||
fpga0_axi_video0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "gdsys,ihs_axi";
|
||||
reg = <0x170 0x10>;
|
||||
|
||||
axi_dev_1 {
|
||||
...
|
||||
};
|
||||
};
|
@ -11,6 +11,7 @@
|
||||
i2c0 = &i2c_0;
|
||||
pci0 = &pci;
|
||||
rtc0 = &rtc_0;
|
||||
axi0 = &axi;
|
||||
};
|
||||
|
||||
chosen {
|
||||
@ -311,6 +312,16 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
axi: axi@0 {
|
||||
compatible = "sandbox,axi";
|
||||
#address-cells = <0x1>;
|
||||
#size-cells = <0x1>;
|
||||
store@0 {
|
||||
compatible = "sandbox,sandbox_store";
|
||||
reg = <0x0 0x400>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#include "cros-ec-keyboard.dtsi"
|
||||
|
@ -36,6 +36,7 @@
|
||||
usb0 = &usb_0;
|
||||
usb1 = &usb_1;
|
||||
usb2 = &usb_2;
|
||||
axi0 = &axi;
|
||||
};
|
||||
|
||||
a-test {
|
||||
@ -552,6 +553,16 @@
|
||||
compatible = "sandbox,wdt";
|
||||
};
|
||||
|
||||
axi: axi@0 {
|
||||
compatible = "sandbox,axi";
|
||||
#address-cells = <0x1>;
|
||||
#size-cells = <0x1>;
|
||||
store@0 {
|
||||
compatible = "sandbox,sandbox_store";
|
||||
reg = <0x0 0x400>;
|
||||
};
|
||||
};
|
||||
|
||||
chosen {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
66
arch/sandbox/include/asm/axi.h
Normal file
66
arch/sandbox/include/asm/axi.h
Normal file
@ -0,0 +1,66 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (C) Copyright 2018
|
||||
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
|
||||
*/
|
||||
|
||||
#ifndef __asm_axi_h
|
||||
#define __asm_axi_h
|
||||
|
||||
#define axi_emul_get_ops(dev) ((struct axi_emul_ops *)(dev)->driver->ops)
|
||||
|
||||
/**
|
||||
* axi_sandbox_get_emul() - Retrieve a pointer to a AXI emulation device
|
||||
* @bus: The AXI bus from which to retrieve a emulation device
|
||||
* @address: The address of a transfer that should be handled by a emulation
|
||||
* device
|
||||
* @length: The data width of a transfer that should be handled by a emulation
|
||||
* device
|
||||
* @emulp: Pointer to a buffer receiving the emulation device that handles
|
||||
* the transfer specified by the address and length parameters
|
||||
*
|
||||
* To test the AXI uclass, we implement a simple AXI emulation device, which is
|
||||
* a virtual device on a AXI bus that exposes a simple storage interface: When
|
||||
* reading and writing from the device, the addresses are translated to offsets
|
||||
* within the device's storage. For write accesses the data is written to the
|
||||
* specified storage offset, and for read accesses the data is read from the
|
||||
* specified storage offset.
|
||||
*
|
||||
* A DTS entry might look like this:
|
||||
*
|
||||
* axi: axi@0 {
|
||||
* compatible = "sandbox,axi";
|
||||
* #address-cells = <0x1>;
|
||||
* #size-cells = <0x1>;
|
||||
* store@0 {
|
||||
* compatible = "sandbox,sandbox_store";
|
||||
* reg = <0x0 0x400>;
|
||||
* };
|
||||
* };
|
||||
*
|
||||
* This function may then be used to retrieve the pointer to the sandbox_store
|
||||
* emulation device given the AXI bus device, and the data (address, data
|
||||
* width) of a AXI transfer which should be handled by a emulation device.
|
||||
*
|
||||
* Return: 0 of OK, -ENODEV if no device capable of handling the specified
|
||||
* transfer exists or the device could not be retrieved
|
||||
*/
|
||||
int axi_sandbox_get_emul(struct udevice *bus, ulong address, uint length,
|
||||
struct udevice **emulp);
|
||||
/**
|
||||
* axi_get_store() - Get address of internal storage of a emulated AXI device
|
||||
* @dev: Emulated AXI device to get the pointer of the internal storage
|
||||
* for.
|
||||
* @storep: Pointer to the internal storage of the emulated AXI device.
|
||||
*
|
||||
* To preset or read back the contents internal storage of the emulated AXI
|
||||
* device, this function returns the pointer to the storage. Changes to the
|
||||
* contents of the storage are reflected when using the AXI read/write API
|
||||
* methods, and vice versa, so by using this method expected read data can be
|
||||
* set up in advance, and written data can be checked in unit tests.
|
||||
*
|
||||
* Return: 0 if OK, -ve on error.
|
||||
*/
|
||||
int axi_get_store(struct udevice *dev, u8 **storep);
|
||||
|
||||
#endif /* __asm_axi_h */
|
@ -1027,6 +1027,14 @@ config CMD_USB_MASS_STORAGE
|
||||
help
|
||||
USB mass storage support
|
||||
|
||||
config CMD_AXI
|
||||
bool "axi"
|
||||
depends on AXI
|
||||
help
|
||||
Enable the command "axi" for accessing AXI (Advanced eXtensible
|
||||
Interface) busses, a on-chip interconnect specification for managing
|
||||
functional blocks in SoC designs, which is also often used in designs
|
||||
involving FPGAs (e.g. communication with IP cores in Xilinx FPGAs).
|
||||
endmenu
|
||||
|
||||
|
||||
|
@ -149,6 +149,7 @@ obj-$(CONFIG_CMD_ZFS) += zfs.o
|
||||
obj-$(CONFIG_CMD_DFU) += dfu.o
|
||||
obj-$(CONFIG_CMD_GPT) += gpt.o
|
||||
obj-$(CONFIG_CMD_ETHSW) += ethsw.o
|
||||
obj-$(CONFIG_CMD_AXI) += axi.o
|
||||
|
||||
# Power
|
||||
obj-$(CONFIG_CMD_PMIC) += pmic.o
|
||||
|
352
cmd/axi.c
Normal file
352
cmd/axi.c
Normal file
@ -0,0 +1,352 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2016
|
||||
* Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc
|
||||
*
|
||||
* (C) Copyright 2017, 2018
|
||||
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <axi.h>
|
||||
#include <command.h>
|
||||
#include <console.h>
|
||||
#include <dm.h>
|
||||
|
||||
/* Currently selected AXI bus device */
|
||||
static struct udevice *axi_cur_bus;
|
||||
/* Transmission size from last command */
|
||||
static uint dp_last_size;
|
||||
/* Address from last command */
|
||||
static uint dp_last_addr;
|
||||
/* Number of bytes to display from last command; default = 64 */
|
||||
static uint dp_last_length = 0x40;
|
||||
|
||||
/**
|
||||
* show_bus() - Show devices on a single AXI bus
|
||||
* @bus: The AXI bus device to printt information for
|
||||
*/
|
||||
static void show_bus(struct udevice *bus)
|
||||
{
|
||||
struct udevice *dev;
|
||||
|
||||
printf("Bus %d:\t%s", bus->req_seq, bus->name);
|
||||
if (device_active(bus))
|
||||
printf(" (active %d)", bus->seq);
|
||||
printf("\n");
|
||||
for (device_find_first_child(bus, &dev);
|
||||
dev;
|
||||
device_find_next_child(&dev))
|
||||
printf(" %s\n", dev->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* axi_set_cur_bus() - Set the currently active AXI bus
|
||||
* @busnum: The number of the bus (i.e. its sequence number) that should be
|
||||
* made active
|
||||
*
|
||||
* The operations supplied by this command operate only on the currently active
|
||||
* bus.
|
||||
*
|
||||
* Return: 0 if OK, -ve on error
|
||||
*/
|
||||
static int axi_set_cur_bus(unsigned int busnum)
|
||||
{
|
||||
struct udevice *bus;
|
||||
struct udevice *dummy;
|
||||
int ret;
|
||||
|
||||
/* Make sure that all sequence numbers are initialized */
|
||||
for (uclass_first_device(UCLASS_AXI, &dummy);
|
||||
dummy;
|
||||
uclass_next_device(&dummy))
|
||||
;
|
||||
|
||||
ret = uclass_get_device_by_seq(UCLASS_AXI, busnum, &bus);
|
||||
if (ret) {
|
||||
debug("%s: No bus %d\n", __func__, busnum);
|
||||
return ret;
|
||||
}
|
||||
axi_cur_bus = bus;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* axi_get_cur_bus() - Retrieve the currently active AXI bus device
|
||||
* @busp: Pointer to a struct udevice that receives the currently active bus
|
||||
* device
|
||||
*
|
||||
* Return: 0 if OK, -ve on error
|
||||
*/
|
||||
static int axi_get_cur_bus(struct udevice **busp)
|
||||
{
|
||||
if (!axi_cur_bus) {
|
||||
puts("No AXI bus selected\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
*busp = axi_cur_bus;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Command handlers
|
||||
*/
|
||||
|
||||
static int do_axi_show_bus(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
struct udevice *dummy;
|
||||
|
||||
/* Make sure that all sequence numbers are initialized */
|
||||
for (uclass_first_device(UCLASS_AXI, &dummy);
|
||||
dummy;
|
||||
uclass_next_device(&dummy))
|
||||
;
|
||||
|
||||
if (argc == 1) {
|
||||
/* show all busses */
|
||||
struct udevice *bus;
|
||||
|
||||
for (uclass_first_device(UCLASS_AXI, &bus);
|
||||
bus;
|
||||
uclass_next_device(&bus))
|
||||
show_bus(bus);
|
||||
} else {
|
||||
int i;
|
||||
|
||||
/* show specific bus */
|
||||
i = simple_strtoul(argv[1], NULL, 10);
|
||||
|
||||
struct udevice *bus;
|
||||
int ret;
|
||||
|
||||
ret = uclass_get_device_by_seq(UCLASS_AXI, i, &bus);
|
||||
if (ret) {
|
||||
printf("Invalid bus %d: err=%d\n", i, ret);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
show_bus(bus);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_axi_bus_num(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
int ret = 0;
|
||||
int bus_no;
|
||||
|
||||
if (argc == 1) {
|
||||
/* querying current setting */
|
||||
struct udevice *bus;
|
||||
|
||||
if (!axi_get_cur_bus(&bus))
|
||||
bus_no = bus->seq;
|
||||
else
|
||||
bus_no = -1;
|
||||
|
||||
printf("Current bus is %d\n", bus_no);
|
||||
} else {
|
||||
bus_no = simple_strtoul(argv[1], NULL, 10);
|
||||
printf("Setting bus to %d\n", bus_no);
|
||||
|
||||
ret = axi_set_cur_bus(bus_no);
|
||||
if (ret)
|
||||
printf("Failure changing bus number (%d)\n", ret);
|
||||
}
|
||||
|
||||
return ret ? CMD_RET_FAILURE : 0;
|
||||
}
|
||||
|
||||
static int do_axi_md(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
/* Print that many bytes per line */
|
||||
const uint DISP_LINE_LEN = 16;
|
||||
u8 linebuf[DISP_LINE_LEN];
|
||||
unsigned int k;
|
||||
ulong addr, length, size;
|
||||
ulong nbytes;
|
||||
enum axi_size_t axisize;
|
||||
int unitsize;
|
||||
|
||||
/*
|
||||
* We use the last specified parameters, unless new ones are
|
||||
* entered.
|
||||
*/
|
||||
size = dp_last_size;
|
||||
addr = dp_last_addr;
|
||||
length = dp_last_length;
|
||||
|
||||
if (argc < 3)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if (!axi_cur_bus) {
|
||||
puts("No AXI bus selected\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
if ((flag & CMD_FLAG_REPEAT) == 0) {
|
||||
size = simple_strtoul(argv[1], NULL, 10);
|
||||
|
||||
/*
|
||||
* Address is specified since argc >= 3
|
||||
*/
|
||||
addr = simple_strtoul(argv[2], NULL, 16);
|
||||
|
||||
/*
|
||||
* If there's another parameter, it is the length to display;
|
||||
* length is the number of objects, not number of bytes
|
||||
*/
|
||||
if (argc > 3)
|
||||
length = simple_strtoul(argv[3], NULL, 16);
|
||||
}
|
||||
|
||||
switch (size) {
|
||||
case 8:
|
||||
axisize = AXI_SIZE_8;
|
||||
unitsize = 1;
|
||||
break;
|
||||
case 16:
|
||||
axisize = AXI_SIZE_16;
|
||||
unitsize = 2;
|
||||
break;
|
||||
case 32:
|
||||
axisize = AXI_SIZE_32;
|
||||
unitsize = 4;
|
||||
break;
|
||||
default:
|
||||
printf("Unknown read size '%lu'\n", size);
|
||||
return CMD_RET_USAGE;
|
||||
};
|
||||
|
||||
nbytes = length * unitsize;
|
||||
do {
|
||||
ulong linebytes = (nbytes > DISP_LINE_LEN) ?
|
||||
DISP_LINE_LEN : nbytes;
|
||||
|
||||
for (k = 0; k < linebytes / unitsize; ++k) {
|
||||
int ret = axi_read(axi_cur_bus, addr + k * unitsize,
|
||||
linebuf + k * unitsize, axisize);
|
||||
|
||||
if (!ret) /* Continue if axi_read was successful */
|
||||
continue;
|
||||
|
||||
if (ret == -ENOSYS)
|
||||
printf("axi_read failed; read size not supported?\n");
|
||||
else
|
||||
printf("axi_read failed: err = %d\n", ret);
|
||||
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
print_buffer(addr, (void *)linebuf, unitsize,
|
||||
linebytes / unitsize,
|
||||
DISP_LINE_LEN / unitsize);
|
||||
|
||||
nbytes -= max(linebytes, 1UL);
|
||||
addr += linebytes;
|
||||
|
||||
if (ctrlc())
|
||||
break;
|
||||
} while (nbytes > 0);
|
||||
|
||||
dp_last_size = size;
|
||||
dp_last_addr = addr;
|
||||
dp_last_length = length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_axi_mw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
u32 writeval;
|
||||
ulong addr, count, size;
|
||||
enum axi_size_t axisize;
|
||||
|
||||
if (argc <= 3 || argc >= 6)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
size = simple_strtoul(argv[1], NULL, 10);
|
||||
|
||||
switch (size) {
|
||||
case 8:
|
||||
axisize = AXI_SIZE_8;
|
||||
break;
|
||||
case 16:
|
||||
axisize = AXI_SIZE_16;
|
||||
break;
|
||||
case 32:
|
||||
axisize = AXI_SIZE_32;
|
||||
break;
|
||||
default:
|
||||
printf("Unknown write size '%lu'\n", size);
|
||||
return CMD_RET_USAGE;
|
||||
};
|
||||
|
||||
/* Address is specified since argc > 4 */
|
||||
addr = simple_strtoul(argv[2], NULL, 16);
|
||||
|
||||
/* Get the value to write */
|
||||
writeval = simple_strtoul(argv[3], NULL, 16);
|
||||
|
||||
/* Count ? */
|
||||
if (argc == 5)
|
||||
count = simple_strtoul(argv[4], NULL, 16);
|
||||
else
|
||||
count = 1;
|
||||
|
||||
while (count-- > 0) {
|
||||
int ret = axi_write(axi_cur_bus, addr + count * sizeof(u32),
|
||||
&writeval, axisize);
|
||||
|
||||
if (ret) {
|
||||
printf("axi_write failed: err = %d\n", ret);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cmd_tbl_t cmd_axi_sub[] = {
|
||||
U_BOOT_CMD_MKENT(bus, 1, 1, do_axi_show_bus, "", ""),
|
||||
U_BOOT_CMD_MKENT(dev, 1, 1, do_axi_bus_num, "", ""),
|
||||
U_BOOT_CMD_MKENT(md, 4, 1, do_axi_md, "", ""),
|
||||
U_BOOT_CMD_MKENT(mw, 5, 1, do_axi_mw, "", ""),
|
||||
};
|
||||
|
||||
static int do_ihs_axi(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
cmd_tbl_t *c;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
/* Strip off leading 'axi' command argument */
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
/* Hand off rest of command line to sub-commands */
|
||||
c = find_cmd_tbl(argv[0], &cmd_axi_sub[0], ARRAY_SIZE(cmd_axi_sub));
|
||||
|
||||
if (c)
|
||||
return c->cmd(cmdtp, flag, argc, argv);
|
||||
else
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
static char axi_help_text[] =
|
||||
"bus - show AXI bus info\n"
|
||||
"axi dev [bus] - show or set current AXI bus to bus number [bus]\n"
|
||||
"axi md size addr [# of objects] - read from AXI device at address [addr] and data width [size] (one of 8, 16, 32)\n"
|
||||
"axi mw size addr value [count] - write data [value] to AXI device at address [addr] and data width [size] (one of 8, 16, 32)\n";
|
||||
|
||||
U_BOOT_CMD(axi, 7, 1, do_ihs_axi,
|
||||
"AXI sub-system",
|
||||
axi_help_text
|
||||
);
|
@ -45,6 +45,7 @@ CONFIG_CMD_REMOTEPROC=y
|
||||
CONFIG_CMD_SF=y
|
||||
CONFIG_CMD_SPI=y
|
||||
CONFIG_CMD_USB=y
|
||||
CONFIG_CMD_AXI=y
|
||||
CONFIG_CMD_TFTPPUT=y
|
||||
CONFIG_CMD_TFTPSRV=y
|
||||
CONFIG_CMD_RARP=y
|
||||
@ -80,6 +81,8 @@ CONFIG_DEVRES=y
|
||||
CONFIG_DEBUG_DEVRES=y
|
||||
CONFIG_ADC=y
|
||||
CONFIG_ADC_SANDBOX=y
|
||||
CONFIG_AXI=y
|
||||
CONFIG_AXI_SANDBOX=y
|
||||
CONFIG_CLK=y
|
||||
CONFIG_CPU=y
|
||||
CONFIG_DM_DEMO=y
|
||||
|
@ -8,6 +8,8 @@ source "drivers/adc/Kconfig"
|
||||
|
||||
source "drivers/ata/Kconfig"
|
||||
|
||||
source "drivers/axi/Kconfig"
|
||||
|
||||
source "drivers/block/Kconfig"
|
||||
|
||||
source "drivers/bootcount/Kconfig"
|
||||
|
@ -103,6 +103,7 @@ obj-y += smem/
|
||||
obj-y += soc/
|
||||
obj-$(CONFIG_REMOTEPROC) += remoteproc/
|
||||
obj-y += thermal/
|
||||
obj-y += axi/
|
||||
|
||||
obj-$(CONFIG_MACH_PIC32) += ddr/microchip/
|
||||
endif
|
||||
|
32
drivers/axi/Kconfig
Normal file
32
drivers/axi/Kconfig
Normal file
@ -0,0 +1,32 @@
|
||||
menuconfig AXI
|
||||
bool "AXI bus drivers"
|
||||
help
|
||||
Support AXI (Advanced eXtensible Interface) busses, a on-chip
|
||||
interconnect specification for managing functional blocks in SoC
|
||||
designs, which is also often used in designs involving FPGAs (e.g.
|
||||
communication with IP cores in Xilinx FPGAs).
|
||||
|
||||
These types of busses expose a virtual address space that can be
|
||||
accessed using different address widths (8, 16, and 32 are supported
|
||||
for now).
|
||||
|
||||
Other similar bus architectures may be compatible as well.
|
||||
|
||||
if AXI
|
||||
|
||||
config IHS_AXI
|
||||
bool "Enable IHS AXI driver"
|
||||
depends on DM
|
||||
help
|
||||
Support for gdsys Integrated Hardware Systems Advanced eXtensible
|
||||
Interface (IHS AXI) bus on a gdsys IHS FPGA used to communicate with
|
||||
IP cores in the FPGA (e.g. video transmitter cores).
|
||||
|
||||
config AXI_SANDBOX
|
||||
bool "Enable AXI sandbox driver"
|
||||
depends on DM
|
||||
help
|
||||
Support AXI (Advanced eXtensible Interface) emulation for the sandbox
|
||||
environment.
|
||||
|
||||
endif
|
12
drivers/axi/Makefile
Normal file
12
drivers/axi/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
#
|
||||
# (C) Copyright 2017
|
||||
# Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-$(CONFIG_AXI) += axi-uclass.o
|
||||
obj-$(CONFIG_IHS_AXI) += ihs_axi.o
|
||||
obj-$(CONFIG_SANDBOX) += axi-emul-uclass.o
|
||||
obj-$(CONFIG_SANDBOX) += sandbox_store.o
|
||||
obj-$(CONFIG_AXI_SANDBOX) += axi_sandbox.o
|
85
drivers/axi/axi-emul-uclass.c
Normal file
85
drivers/axi/axi-emul-uclass.c
Normal file
@ -0,0 +1,85 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2018
|
||||
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <axi.h>
|
||||
#include <dm.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <asm/axi.h>
|
||||
|
||||
int axi_sandbox_get_emul(struct udevice *bus, ulong address,
|
||||
enum axi_size_t size, struct udevice **emulp)
|
||||
{
|
||||
struct udevice *dev;
|
||||
u32 reg[2];
|
||||
uint offset;
|
||||
|
||||
switch (size) {
|
||||
case AXI_SIZE_8:
|
||||
offset = 1;
|
||||
break;
|
||||
case AXI_SIZE_16:
|
||||
offset = 2;
|
||||
break;
|
||||
case AXI_SIZE_32:
|
||||
offset = 4;
|
||||
break;
|
||||
default:
|
||||
debug("%s: Unknown AXI transfer size '%d'", bus->name, size);
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: device_find_* don't activate the devices; they're activated
|
||||
* as-needed below.
|
||||
*/
|
||||
for (device_find_first_child(bus, &dev);
|
||||
dev;
|
||||
device_find_next_child(&dev)) {
|
||||
int ret;
|
||||
|
||||
ret = dev_read_u32_array(dev, "reg", reg, ARRAY_SIZE(reg));
|
||||
if (ret) {
|
||||
debug("%s: Could not read 'reg' property of %s\n",
|
||||
bus->name, dev->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Does the transfer's address fall into this device's address
|
||||
* space?
|
||||
*/
|
||||
if (address >= reg[0] && address <= reg[0] + reg[1] - offset) {
|
||||
/* If yes, activate it... */
|
||||
if (device_probe(dev)) {
|
||||
debug("%s: Could not activate %s\n",
|
||||
bus->name, dev->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* ...and return it */
|
||||
*emulp = dev;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int axi_get_store(struct udevice *dev, u8 **storep)
|
||||
{
|
||||
struct axi_emul_ops *ops = axi_emul_get_ops(dev);
|
||||
|
||||
if (!ops->get_store)
|
||||
return -ENOSYS;
|
||||
|
||||
return ops->get_store(dev, storep);
|
||||
}
|
||||
|
||||
UCLASS_DRIVER(axi_emul) = {
|
||||
.id = UCLASS_AXI_EMUL,
|
||||
.name = "axi_emul",
|
||||
};
|
39
drivers/axi/axi-uclass.c
Normal file
39
drivers/axi/axi-uclass.c
Normal file
@ -0,0 +1,39 @@
|
||||
// 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 <axi.h>
|
||||
|
||||
int axi_read(struct udevice *dev, ulong address, void *data,
|
||||
enum axi_size_t size)
|
||||
{
|
||||
struct axi_ops *ops = axi_get_ops(dev);
|
||||
|
||||
if (!ops->read)
|
||||
return -ENOSYS;
|
||||
|
||||
return ops->read(dev, address, data, size);
|
||||
}
|
||||
|
||||
int axi_write(struct udevice *dev, ulong address, void *data,
|
||||
enum axi_size_t size)
|
||||
{
|
||||
struct axi_ops *ops = axi_get_ops(dev);
|
||||
|
||||
if (!ops->write)
|
||||
return -ENOSYS;
|
||||
|
||||
return ops->write(dev, address, data, size);
|
||||
}
|
||||
|
||||
UCLASS_DRIVER(axi) = {
|
||||
.id = UCLASS_AXI,
|
||||
.name = "axi",
|
||||
.post_bind = dm_scan_fdt_dev,
|
||||
.flags = DM_UC_FLAG_SEQ_ALIAS,
|
||||
};
|
||||
|
77
drivers/axi/axi_sandbox.c
Normal file
77
drivers/axi/axi_sandbox.c
Normal file
@ -0,0 +1,77 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2018
|
||||
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <axi.h>
|
||||
#include <dm.h>
|
||||
#include <asm/axi.h>
|
||||
|
||||
/*
|
||||
* This driver implements a AXI bus for the sandbox architecture for testing
|
||||
* purposes.
|
||||
*
|
||||
* The bus forwards every access to it to a special AXI emulation device (which
|
||||
* it gets via the axi_emul_get_ops function) that implements a simple
|
||||
* read/write storage.
|
||||
*
|
||||
* The emulator device must still be contained in the device tree in the usual
|
||||
* way, since configuration data for the storage is read from the DT.
|
||||
*/
|
||||
|
||||
static int axi_sandbox_read(struct udevice *bus, ulong address, void *data,
|
||||
enum axi_size_t size)
|
||||
{
|
||||
struct axi_emul_ops *ops;
|
||||
struct udevice *emul;
|
||||
int ret;
|
||||
|
||||
/* Get emulator device */
|
||||
ret = axi_sandbox_get_emul(bus, address, size, &emul);
|
||||
if (ret)
|
||||
return ret == -ENODEV ? 0 : ret;
|
||||
/* Forward all reads to the AXI emulator */
|
||||
ops = axi_emul_get_ops(emul);
|
||||
if (!ops || !ops->read)
|
||||
return -ENOSYS;
|
||||
|
||||
return ops->read(emul, address, data, size);
|
||||
}
|
||||
|
||||
static int axi_sandbox_write(struct udevice *bus, ulong address, void *data,
|
||||
enum axi_size_t size)
|
||||
{
|
||||
struct axi_emul_ops *ops;
|
||||
struct udevice *emul;
|
||||
int ret;
|
||||
|
||||
/* Get emulator device */
|
||||
ret = axi_sandbox_get_emul(bus, address, size, &emul);
|
||||
if (ret)
|
||||
return ret == -ENODEV ? 0 : ret;
|
||||
/* Forward all writes to the AXI emulator */
|
||||
ops = axi_emul_get_ops(emul);
|
||||
if (!ops || !ops->write)
|
||||
return -ENOSYS;
|
||||
|
||||
return ops->write(emul, address, data, size);
|
||||
}
|
||||
|
||||
static const struct udevice_id axi_sandbox_ids[] = {
|
||||
{ .compatible = "sandbox,axi" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static const struct axi_ops axi_sandbox_ops = {
|
||||
.read = axi_sandbox_read,
|
||||
.write = axi_sandbox_write,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(axi_sandbox_bus) = {
|
||||
.name = "axi_sandbox_bus",
|
||||
.id = UCLASS_AXI,
|
||||
.of_match = axi_sandbox_ids,
|
||||
.ops = &axi_sandbox_ops,
|
||||
};
|
293
drivers/axi/ihs_axi.c
Normal file
293
drivers/axi/ihs_axi.c
Normal file
@ -0,0 +1,293 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2016
|
||||
* Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc
|
||||
*
|
||||
* (C) Copyright 2017, 2018
|
||||
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <axi.h>
|
||||
#include <dm.h>
|
||||
#include <regmap.h>
|
||||
|
||||
/**
|
||||
* struct ihs_axi_regs - Structure for the register map of a IHS AXI device
|
||||
* @interrupt_status: Status register to indicate certain events (e.g.
|
||||
* error during transfer, transfer complete, etc.)
|
||||
* @interrupt_enable_control: Register to both control which statuses will be
|
||||
* indicated in the interrupt_status register, and
|
||||
* to change bus settings
|
||||
* @address_lsb: Least significant 16-bit word of the address of a
|
||||
* device to transfer data from/to
|
||||
* @address_msb: Most significant 16-bit word of the address of a
|
||||
* device to transfer data from/to
|
||||
* @write_data_lsb: Least significant 16-bit word of the data to be
|
||||
* written to a device
|
||||
* @write_data_msb: Most significant 16-bit word of the data to be
|
||||
* written to a device
|
||||
* @read_data_lsb: Least significant 16-bit word of the data read
|
||||
* from a device
|
||||
* @read_data_msb: Most significant 16-bit word of the data read
|
||||
* from a device
|
||||
*/
|
||||
struct ihs_axi_regs {
|
||||
u16 interrupt_status;
|
||||
u16 interrupt_enable_control;
|
||||
u16 address_lsb;
|
||||
u16 address_msb;
|
||||
u16 write_data_lsb;
|
||||
u16 write_data_msb;
|
||||
u16 read_data_lsb;
|
||||
u16 read_data_msb;
|
||||
};
|
||||
|
||||
/**
|
||||
* ihs_axi_set() - Convenience macro to set values in register map
|
||||
* @map: The register map to write to
|
||||
* @member: The member of the ihs_axi_regs structure to write
|
||||
* @val: The value to write to the register map
|
||||
*/
|
||||
#define ihs_axi_set(map, member, val) \
|
||||
regmap_set(map, struct ihs_axi_regs, member, val)
|
||||
|
||||
/**
|
||||
* ihs_axi_get() - Convenience macro to read values from register map
|
||||
* @map: The register map to read from
|
||||
* @member: The member of the ihs_axi_regs structure to read
|
||||
* @valp: Pointer to a buffer to receive the value read
|
||||
*/
|
||||
#define ihs_axi_get(map, member, valp) \
|
||||
regmap_get(map, struct ihs_axi_regs, member, valp)
|
||||
|
||||
/**
|
||||
* struct ihs_axi_priv - Private data structure of IHS AXI devices
|
||||
* @map: Register map for the IHS AXI device
|
||||
*/
|
||||
struct ihs_axi_priv {
|
||||
struct regmap *map;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum status_reg - Description of bits in the interrupt_status register
|
||||
* @STATUS_READ_COMPLETE_EVENT: A read transfer was completed
|
||||
* @STATUS_WRITE_COMPLETE_EVENT: A write transfer was completed
|
||||
* @STATUS_TIMEOUT_EVENT: A timeout has occurred during the transfer
|
||||
* @STATUS_ERROR_EVENT: A error has occurred during the transfer
|
||||
* @STATUS_AXI_INT: A AXI interrupt has occurred
|
||||
* @STATUS_READ_DATA_AVAILABLE: Data is available to be read
|
||||
* @STATUS_BUSY: The bus is busy
|
||||
* @STATUS_INIT_DONE: The bus has finished initializing
|
||||
*/
|
||||
enum status_reg {
|
||||
STATUS_READ_COMPLETE_EVENT = BIT(15),
|
||||
STATUS_WRITE_COMPLETE_EVENT = BIT(14),
|
||||
STATUS_TIMEOUT_EVENT = BIT(13),
|
||||
STATUS_ERROR_EVENT = BIT(12),
|
||||
STATUS_AXI_INT = BIT(11),
|
||||
STATUS_READ_DATA_AVAILABLE = BIT(7),
|
||||
STATUS_BUSY = BIT(6),
|
||||
STATUS_INIT_DONE = BIT(5),
|
||||
};
|
||||
|
||||
/**
|
||||
* enum control_reg - Description of bit fields in the interrupt_enable_control
|
||||
* register
|
||||
* @CONTROL_READ_COMPLETE_EVENT_ENABLE: STATUS_READ_COMPLETE_EVENT will be
|
||||
* raised in the interrupt_status register
|
||||
* @CONTROL_WRITE_COMPLETE_EVENT_ENABLE: STATUS_WRITE_COMPLETE_EVENT will be
|
||||
* raised in the interrupt_status register
|
||||
* @CONTROL_TIMEOUT_EVENT_ENABLE: STATUS_TIMEOUT_EVENT will be raised in
|
||||
* the interrupt_status register
|
||||
* @CONTROL_ERROR_EVENT_ENABLE: STATUS_ERROR_EVENT will be raised in
|
||||
* the interrupt_status register
|
||||
* @CONTROL_AXI_INT_ENABLE: STATUS_AXI_INT will be raised in the
|
||||
* interrupt_status register
|
||||
* @CONTROL_CMD_NOP: Configure bus to send a NOP command
|
||||
* for the next transfer
|
||||
* @CONTROL_CMD_WRITE: Configure bus to do a write transfer
|
||||
* @CONTROL_CMD_WRITE_POST_INC: Auto-increment address after write
|
||||
* transfer
|
||||
* @CONTROL_CMD_READ: Configure bus to do a read transfer
|
||||
* @CONTROL_CMD_READ_POST_INC: Auto-increment address after read
|
||||
* transfer
|
||||
*/
|
||||
enum control_reg {
|
||||
CONTROL_READ_COMPLETE_EVENT_ENABLE = BIT(15),
|
||||
CONTROL_WRITE_COMPLETE_EVENT_ENABLE = BIT(14),
|
||||
CONTROL_TIMEOUT_EVENT_ENABLE = BIT(13),
|
||||
CONTROL_ERROR_EVENT_ENABLE = BIT(12),
|
||||
CONTROL_AXI_INT_ENABLE = BIT(11),
|
||||
|
||||
CONTROL_CMD_NOP = 0x0,
|
||||
CONTROL_CMD_WRITE = 0x8,
|
||||
CONTROL_CMD_WRITE_POST_INC = 0x9,
|
||||
CONTROL_CMD_READ = 0xa,
|
||||
CONTROL_CMD_READ_POST_INC = 0xb,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum axi_cmd - Determine if transfer is read or write transfer
|
||||
* @AXI_CMD_READ: The transfer should be a read transfer
|
||||
* @AXI_CMD_WRITE: The transfer should be a write transfer
|
||||
*/
|
||||
enum axi_cmd {
|
||||
AXI_CMD_READ,
|
||||
AXI_CMD_WRITE,
|
||||
};
|
||||
|
||||
/**
|
||||
* ihs_axi_transfer() - Run transfer on the AXI bus
|
||||
* @bus: The AXI bus device on which to run the transfer on
|
||||
* @address: The address to use in the transfer (i.e. which address to
|
||||
* read/write from/to)
|
||||
* @cmd: Should the transfer be a read or write transfer?
|
||||
*
|
||||
* Return: 0 if OK, -ve on error
|
||||
*/
|
||||
static int ihs_axi_transfer(struct udevice *bus, ulong address,
|
||||
enum axi_cmd cmd)
|
||||
{
|
||||
struct ihs_axi_priv *priv = dev_get_priv(bus);
|
||||
/* Try waiting for events up to 10 times */
|
||||
const uint WAIT_TRIES = 10;
|
||||
u16 wait_mask = STATUS_TIMEOUT_EVENT |
|
||||
STATUS_ERROR_EVENT;
|
||||
u16 complete_flag;
|
||||
u16 status;
|
||||
uint k;
|
||||
|
||||
if (cmd == AXI_CMD_READ) {
|
||||
complete_flag = STATUS_READ_COMPLETE_EVENT;
|
||||
cmd = CONTROL_CMD_READ;
|
||||
} else {
|
||||
complete_flag = STATUS_WRITE_COMPLETE_EVENT;
|
||||
cmd = CONTROL_CMD_WRITE;
|
||||
}
|
||||
|
||||
wait_mask |= complete_flag;
|
||||
|
||||
/* Lower 16 bit */
|
||||
ihs_axi_set(priv->map, address_lsb, address & 0xffff);
|
||||
/* Upper 16 bit */
|
||||
ihs_axi_set(priv->map, address_msb, (address >> 16) & 0xffff);
|
||||
|
||||
ihs_axi_set(priv->map, interrupt_status, wait_mask);
|
||||
ihs_axi_set(priv->map, interrupt_enable_control, cmd);
|
||||
|
||||
for (k = WAIT_TRIES; k > 0; --k) {
|
||||
ihs_axi_get(priv->map, interrupt_status, &status);
|
||||
if (status & wait_mask)
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* k == 0 -> Tries ran out with no event we were waiting for actually
|
||||
* occurring.
|
||||
*/
|
||||
if (!k)
|
||||
ihs_axi_get(priv->map, interrupt_status, &status);
|
||||
|
||||
if (status & complete_flag)
|
||||
return 0;
|
||||
|
||||
if (status & STATUS_ERROR_EVENT) {
|
||||
debug("%s: Error occurred during transfer\n", bus->name);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
debug("%s: Transfer timed out\n", bus->name);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/*
|
||||
* API
|
||||
*/
|
||||
|
||||
static int ihs_axi_read(struct udevice *dev, ulong address, void *data,
|
||||
enum axi_size_t size)
|
||||
{
|
||||
struct ihs_axi_priv *priv = dev_get_priv(dev);
|
||||
int ret;
|
||||
u16 data_lsb, data_msb;
|
||||
u32 *p = data;
|
||||
|
||||
if (size != AXI_SIZE_32) {
|
||||
debug("%s: transfer size '%d' not supported\n",
|
||||
dev->name, size);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
ret = ihs_axi_transfer(dev, address, AXI_CMD_READ);
|
||||
if (ret < 0) {
|
||||
debug("%s: Error during AXI transfer (err = %d)\n",
|
||||
dev->name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ihs_axi_get(priv->map, read_data_lsb, &data_lsb);
|
||||
ihs_axi_get(priv->map, read_data_msb, &data_msb);
|
||||
|
||||
/* Assemble data from two 16-bit words */
|
||||
*p = (data_msb << 16) | data_lsb;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ihs_axi_write(struct udevice *dev, ulong address, void *data,
|
||||
enum axi_size_t size)
|
||||
{
|
||||
struct ihs_axi_priv *priv = dev_get_priv(dev);
|
||||
int ret;
|
||||
u32 *p = data;
|
||||
|
||||
if (size != AXI_SIZE_32) {
|
||||
debug("%s: transfer size '%d' not supported\n",
|
||||
dev->name, size);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/* Lower 16 bit */
|
||||
ihs_axi_set(priv->map, write_data_lsb, *p & 0xffff);
|
||||
/* Upper 16 bit */
|
||||
ihs_axi_set(priv->map, write_data_msb, (*p >> 16) & 0xffff);
|
||||
|
||||
ret = ihs_axi_transfer(dev, address, AXI_CMD_WRITE);
|
||||
if (ret < 0) {
|
||||
debug("%s: Error during AXI transfer (err = %d)\n",
|
||||
dev->name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id ihs_axi_ids[] = {
|
||||
{ .compatible = "gdsys,ihs_axi" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static const struct axi_ops ihs_axi_ops = {
|
||||
.read = ihs_axi_read,
|
||||
.write = ihs_axi_write,
|
||||
};
|
||||
|
||||
static int ihs_axi_probe(struct udevice *dev)
|
||||
{
|
||||
struct ihs_axi_priv *priv = dev_get_priv(dev);
|
||||
|
||||
regmap_init_mem(dev_ofnode(dev), &priv->map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(ihs_axi_bus) = {
|
||||
.name = "ihs_axi_bus",
|
||||
.id = UCLASS_AXI,
|
||||
.of_match = ihs_axi_ids,
|
||||
.ops = &ihs_axi_ops,
|
||||
.priv_auto_alloc_size = sizeof(struct ihs_axi_priv),
|
||||
.probe = ihs_axi_probe,
|
||||
};
|
123
drivers/axi/sandbox_store.c
Normal file
123
drivers/axi/sandbox_store.c
Normal file
@ -0,0 +1,123 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2018
|
||||
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <axi.h>
|
||||
#include <dm.h>
|
||||
|
||||
/**
|
||||
* struct sandbox_store_priv - Private data structure of a AXI store device
|
||||
* @store: The buffer holding the device's internal memory, which is read from
|
||||
* and written to using the driver's methods
|
||||
*/
|
||||
struct sandbox_store_priv {
|
||||
u8 *store;
|
||||
};
|
||||
|
||||
/**
|
||||
* copy_axi_data() - Copy data from source to destination with a given AXI
|
||||
* transfer width
|
||||
* @src: Pointer to the data source from where data will be read
|
||||
* @dst: Pointer to the data destination where data will be written to
|
||||
* @size: Size of the data to be copied given by a axi_size_t enum value
|
||||
*
|
||||
* Return: 0 if OK, -ve on error
|
||||
*/
|
||||
static int copy_axi_data(void *src, void *dst, enum axi_size_t size)
|
||||
{
|
||||
switch (size) {
|
||||
case AXI_SIZE_8:
|
||||
*((u8 *)dst) = *((u8 *)src);
|
||||
return 0;
|
||||
case AXI_SIZE_16:
|
||||
*((u16 *)dst) = be16_to_cpu(*((u16 *)src));
|
||||
return 0;
|
||||
case AXI_SIZE_32:
|
||||
*((u32 *)dst) = be32_to_cpu(*((u32 *)src));
|
||||
return 0;
|
||||
default:
|
||||
debug("%s: Unknown AXI transfer size '%d'\n", __func__, size);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int sandbox_store_read(struct udevice *dev, ulong address, void *data,
|
||||
enum axi_size_t size)
|
||||
{
|
||||
struct sandbox_store_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return copy_axi_data(priv->store + address, data, size);
|
||||
}
|
||||
|
||||
static int sandbox_store_write(struct udevice *dev, ulong address, void *data,
|
||||
enum axi_size_t size)
|
||||
{
|
||||
struct sandbox_store_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return copy_axi_data(data, priv->store + address, size);
|
||||
}
|
||||
|
||||
static int sandbox_store_get_store(struct udevice *dev, u8 **store)
|
||||
{
|
||||
struct sandbox_store_priv *priv = dev_get_priv(dev);
|
||||
|
||||
*store = priv->store;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id sandbox_store_ids[] = {
|
||||
{ .compatible = "sandbox,sandbox_store" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static const struct axi_emul_ops sandbox_store_ops = {
|
||||
.read = sandbox_store_read,
|
||||
.write = sandbox_store_write,
|
||||
.get_store = sandbox_store_get_store,
|
||||
};
|
||||
|
||||
static int sandbox_store_probe(struct udevice *dev)
|
||||
{
|
||||
struct sandbox_store_priv *priv = dev_get_priv(dev);
|
||||
u32 reg[2];
|
||||
int ret;
|
||||
|
||||
ret = dev_read_u32_array(dev, "reg", reg, ARRAY_SIZE(reg));
|
||||
if (ret) {
|
||||
debug("%s: Could not read 'reg' property\n", dev->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate the device's internal storage that will be read
|
||||
* from/written to
|
||||
*/
|
||||
priv->store = calloc(reg[1], 1);
|
||||
if (!priv->store)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sandbox_store_remove(struct udevice *dev)
|
||||
{
|
||||
struct sandbox_store_priv *priv = dev_get_priv(dev);
|
||||
|
||||
free(priv->store);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(sandbox_axi_store) = {
|
||||
.name = "sandbox_axi_store",
|
||||
.id = UCLASS_AXI_EMUL,
|
||||
.of_match = sandbox_store_ids,
|
||||
.ops = &sandbox_store_ops,
|
||||
.priv_auto_alloc_size = sizeof(struct sandbox_store_priv),
|
||||
.probe = sandbox_store_probe,
|
||||
.remove = sandbox_store_remove,
|
||||
};
|
@ -431,6 +431,17 @@ config ATMEL_HLCD
|
||||
help
|
||||
HLCDC supports video output to an attached LCD panel.
|
||||
|
||||
config LOGICORE_DP_TX
|
||||
bool "Enable Logicore DP TX driver"
|
||||
depends on DISPLAY
|
||||
help
|
||||
Enable the driver for the transmitter part of the Xilinx LogiCORE
|
||||
DisplayPort, a IP core for Xilinx FPGAs that implements a DisplayPort
|
||||
video interface as defined by VESA DisplayPort v1.2.
|
||||
|
||||
Note that this is a pure transmitter device, and has no display
|
||||
capabilities by itself.
|
||||
|
||||
config VIDEO_BROADWELL_IGD
|
||||
bool "Enable Intel Broadwell integrated graphics device"
|
||||
depends on X86
|
||||
|
@ -4,57 +4,58 @@
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
|
||||
ifdef CONFIG_DM
|
||||
obj-$(CONFIG_BACKLIGHT_GPIO) += backlight_gpio.o
|
||||
obj-$(CONFIG_BACKLIGHT_PWM) += pwm_backlight.o
|
||||
obj-$(CONFIG_CONSOLE_NORMAL) += console_normal.o
|
||||
obj-$(CONFIG_CONSOLE_ROTATION) += console_rotate.o
|
||||
obj-$(CONFIG_CONSOLE_TRUETYPE) += console_truetype.o fonts/
|
||||
obj-$(CONFIG_DISPLAY) += display-uclass.o
|
||||
obj-$(CONFIG_DM_VIDEO) += backlight-uclass.o
|
||||
obj-$(CONFIG_DM_VIDEO) += panel-uclass.o simple_panel.o
|
||||
obj-$(CONFIG_DM_VIDEO) += video-uclass.o vidconsole-uclass.o
|
||||
obj-$(CONFIG_DM_VIDEO) += video_bmp.o
|
||||
obj-$(CONFIG_BACKLIGHT_PWM) += pwm_backlight.o
|
||||
obj-$(CONFIG_BACKLIGHT_GPIO) += backlight_gpio.o
|
||||
obj-$(CONFIG_CONSOLE_NORMAL) += console_normal.o
|
||||
obj-$(CONFIG_CONSOLE_ROTATION) += console_rotate.o
|
||||
obj-$(CONFIG_CONSOLE_TRUETYPE) += console_truetype.o fonts/
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_VIDEO_BROADWELL_IGD) += broadwell_igd.o
|
||||
obj-$(CONFIG_VIDEO_IVYBRIDGE_IGD) += ivybridge_igd.o
|
||||
obj-${CONFIG_EXYNOS_FB} += exynos/
|
||||
obj-${CONFIG_VIDEO_ROCKCHIP} += rockchip/
|
||||
obj-${CONFIG_VIDEO_STM32} += stm32/
|
||||
obj-${CONFIG_VIDEO_TEGRA124} += tegra124/
|
||||
|
||||
obj-$(CONFIG_AM335X_LCD) += am335x-fb.o
|
||||
obj-$(CONFIG_ATI_RADEON_FB) += ati_radeon_fb.o videomodes.o
|
||||
obj-$(CONFIG_ATMEL_HLCD) += atmel_hlcdfb.o
|
||||
obj-$(CONFIG_ATMEL_LCD) += atmel_lcdfb.o
|
||||
obj-$(CONFIG_CFB_CONSOLE) += cfb_console.o
|
||||
obj-$(CONFIG_FORMIKE) += formike.o
|
||||
obj-$(CONFIG_FSL_DIU_FB) += fsl_diu_fb.o videomodes.o
|
||||
obj-$(CONFIG_VIDEO_FSL_DCU_FB) += fsl_dcu_fb.o videomodes.o
|
||||
obj-$(CONFIG_PXA_LCD) += pxa_lcd.o
|
||||
obj-$(CONFIG_SCF0403_LCD) += scf0403_lcd.o
|
||||
obj-$(CONFIG_S6E8AX0) += s6e8ax0.o
|
||||
obj-$(CONFIG_LD9040) += ld9040.o
|
||||
obj-$(CONFIG_LG4573) += lg4573.o
|
||||
obj-$(CONFIG_LOGICORE_DP_TX) += logicore_dp_tx.o
|
||||
obj-$(CONFIG_PXA_LCD) += pxa_lcd.o
|
||||
obj-$(CONFIG_S6E8AX0) += s6e8ax0.o
|
||||
obj-$(CONFIG_SCF0403_LCD) += scf0403_lcd.o
|
||||
obj-$(CONFIG_VIDEO_BCM2835) += bcm2835.o
|
||||
obj-$(CONFIG_VIDEO_BROADWELL_IGD) += broadwell_igd.o
|
||||
obj-$(CONFIG_VIDEO_COREBOOT) += coreboot.o
|
||||
obj-$(CONFIG_VIDEO_DA8XX) += da8xx-fb.o videomodes.o
|
||||
obj-$(CONFIG_VIDEO_DW_HDMI) += dw_hdmi.o
|
||||
obj-$(CONFIG_VIDEO_EFI) += efi.o
|
||||
obj-$(CONFIG_VIDEO_FSL_DCU_FB) += fsl_dcu_fb.o videomodes.o
|
||||
obj-$(CONFIG_VIDEO_IPUV3) += mxc_ipuv3_fb.o ipu_common.o ipu_disp.o
|
||||
obj-$(CONFIG_VIDEO_IVYBRIDGE_IGD) += ivybridge_igd.o
|
||||
obj-$(CONFIG_VIDEO_LCD_ANX9804) += anx9804.o
|
||||
obj-$(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM) += hitachi_tx18d42vm_lcd.o
|
||||
obj-$(CONFIG_VIDEO_LCD_SSD2828) += ssd2828.o
|
||||
obj-$(CONFIG_VIDEO_MB862xx) += mb862xx.o videomodes.o
|
||||
obj-$(CONFIG_VIDEO_MX3) += mx3fb.o videomodes.o
|
||||
obj-$(CONFIG_VIDEO_IPUV3) += mxc_ipuv3_fb.o ipu_common.o ipu_disp.o
|
||||
obj-$(CONFIG_VIDEO_MVEBU) += mvebu_lcd.o
|
||||
obj-$(CONFIG_VIDEO_MX3) += mx3fb.o videomodes.o
|
||||
obj-$(CONFIG_VIDEO_MXS) += mxsfb.o videomodes.o
|
||||
obj-$(CONFIG_VIDEO_OMAP3) += omap3_dss.o
|
||||
obj-$(CONFIG_VIDEO_SANDBOX_SDL) += sandbox_sdl.o
|
||||
obj-$(CONFIG_VIDEO_SIMPLE) += simplefb.o
|
||||
obj-$(CONFIG_VIDEO_TEGRA20) += tegra.o
|
||||
obj-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o
|
||||
obj-$(CONFIG_VIDEO_VESA) += vesa.o
|
||||
obj-$(CONFIG_FORMIKE) += formike.o
|
||||
obj-$(CONFIG_LG4573) += lg4573.o
|
||||
obj-$(CONFIG_AM335X_LCD) += am335x-fb.o
|
||||
obj-$(CONFIG_VIDEO_DW_HDMI) += dw_hdmi.o
|
||||
obj-$(CONFIG_VIDEO_SIMPLE) += simplefb.o
|
||||
obj-${CONFIG_VIDEO_TEGRA124} += tegra124/
|
||||
obj-${CONFIG_EXYNOS_FB} += exynos/
|
||||
obj-${CONFIG_VIDEO_ROCKCHIP} += rockchip/
|
||||
obj-${CONFIG_VIDEO_STM32} += stm32/
|
||||
|
||||
obj-y += bridge/
|
||||
obj-y += sunxi/
|
||||
|
341
drivers/video/logicore_dp_dpcd.h
Normal file
341
drivers/video/logicore_dp_dpcd.h
Normal file
@ -0,0 +1,341 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* logicore_dp_dpcd.h
|
||||
*
|
||||
* DPCD interface definition for XILINX LogiCore DisplayPort v6.1
|
||||
* based on Xilinx dp_v3_1 driver sources
|
||||
*
|
||||
* (C) Copyright 2016
|
||||
* Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc
|
||||
*/
|
||||
|
||||
#ifndef __GDSYS_LOGICORE_DP_DPCD_H__
|
||||
#define __GDSYS_LOGICORE_DP_DPCD_H__
|
||||
|
||||
/* receiver capability field */
|
||||
#define DPCD_REV 0x00000
|
||||
#define DPCD_MAX_LINK_RATE 0x00001
|
||||
#define DPCD_MAX_LANE_COUNT 0x00002
|
||||
#define DPCD_MAX_DOWNSPREAD 0x00003
|
||||
#define DPCD_NORP_PWR_V_CAP 0x00004
|
||||
#define DPCD_DOWNSP_PRESENT 0x00005
|
||||
#define DPCD_ML_CH_CODING_CAP 0x00006
|
||||
#define DPCD_DOWNSP_COUNT_MSA_OUI 0x00007
|
||||
#define DPCD_RX_PORT0_CAP_0 0x00008
|
||||
#define DPCD_RX_PORT0_CAP_1 0x00009
|
||||
#define DPCD_RX_PORT1_CAP_0 0x0000A
|
||||
#define DPCD_RX_PORT1_CAP_1 0x0000B
|
||||
#define DPCD_I2C_SPEED_CTL_CAP 0x0000C
|
||||
#define DPCD_EDP_CFG_CAP 0x0000D
|
||||
#define DPCD_TRAIN_AUX_RD_INTERVAL 0x0000E
|
||||
#define DPCD_ADAPTER_CAP 0x0000F
|
||||
#define DPCD_FAUX_CAP 0x00020
|
||||
#define DPCD_MSTM_CAP 0x00021
|
||||
#define DPCD_NUM_AUDIO_EPS 0x00022
|
||||
#define DPCD_AV_GRANULARITY 0x00023
|
||||
#define DPCD_AUD_DEC_LAT_7_0 0x00024
|
||||
#define DPCD_AUD_DEC_LAT_15_8 0x00025
|
||||
#define DPCD_AUD_PP_LAT_7_0 0x00026
|
||||
#define DPCD_AUD_PP_LAT_15_8 0x00027
|
||||
#define DPCD_VID_INTER_LAT 0x00028
|
||||
#define DPCD_VID_PROG_LAT 0x00029
|
||||
#define DPCD_REP_LAT 0x0002A
|
||||
#define DPCD_AUD_DEL_INS_7_0 0x0002B
|
||||
#define DPCD_AUD_DEL_INS_15_8 0x0002C
|
||||
#define DPCD_AUD_DEL_INS_23_16 0x0002D
|
||||
#define DPCD_GUID 0x00030
|
||||
#define DPCD_RX_GTC_VALUE_7_0 0x00054
|
||||
#define DPCD_RX_GTC_VALUE_15_8 0x00055
|
||||
#define DPCD_RX_GTC_VALUE_23_16 0x00056
|
||||
#define DPCD_RX_GTC_VALUE_31_24 0x00057
|
||||
#define DPCD_RX_GTC_MSTR_REQ 0x00058
|
||||
#define DPCD_RX_GTC_FREQ_LOCK_DONE 0x00059
|
||||
#define DPCD_DOWNSP_0_CAP 0x00080
|
||||
#define DPCD_DOWNSP_1_CAP 0x00081
|
||||
#define DPCD_DOWNSP_2_CAP 0x00082
|
||||
#define DPCD_DOWNSP_3_CAP 0x00083
|
||||
#define DPCD_DOWNSP_0_DET_CAP 0x00080
|
||||
#define DPCD_DOWNSP_1_DET_CAP 0x00084
|
||||
#define DPCD_DOWNSP_2_DET_CAP 0x00088
|
||||
#define DPCD_DOWNSP_3_DET_CAP 0x0008C
|
||||
|
||||
/* link configuration field */
|
||||
#define DPCD_LINK_BW_SET 0x00100
|
||||
#define DPCD_LANE_COUNT_SET 0x00101
|
||||
#define DPCD_TP_SET 0x00102
|
||||
#define DPCD_TRAINING_LANE0_SET 0x00103
|
||||
#define DPCD_TRAINING_LANE1_SET 0x00104
|
||||
#define DPCD_TRAINING_LANE2_SET 0x00105
|
||||
#define DPCD_TRAINING_LANE3_SET 0x00106
|
||||
#define DPCD_DOWNSPREAD_CTRL 0x00107
|
||||
#define DPCD_ML_CH_CODING_SET 0x00108
|
||||
#define DPCD_I2C_SPEED_CTL_SET 0x00109
|
||||
#define DPCD_EDP_CFG_SET 0x0010A
|
||||
#define DPCD_LINK_QUAL_LANE0_SET 0x0010B
|
||||
#define DPCD_LINK_QUAL_LANE1_SET 0x0010C
|
||||
#define DPCD_LINK_QUAL_LANE2_SET 0x0010D
|
||||
#define DPCD_LINK_QUAL_LANE3_SET 0x0010E
|
||||
#define DPCD_TRAINING_LANE0_1_SET2 0x0010F
|
||||
#define DPCD_TRAINING_LANE2_3_SET2 0x00110
|
||||
#define DPCD_MSTM_CTRL 0x00111
|
||||
#define DPCD_AUDIO_DELAY_7_0 0x00112
|
||||
#define DPCD_AUDIO_DELAY_15_8 0x00113
|
||||
#define DPCD_AUDIO_DELAY_23_6 0x00114
|
||||
#define DPCD_UPSTREAM_DEVICE_DP_PWR_NEED 0x00118
|
||||
#define DPCD_FAUX_MODE_CTRL 0x00120
|
||||
#define DPCD_FAUX_FORWARD_CH_DRIVE_SET 0x00121
|
||||
#define DPCD_BACK_CH_STATUS 0x00122
|
||||
#define DPCD_FAUX_BACK_CH_SYMBOL_ERROR_COUNT 0x00123
|
||||
#define DPCD_FAUX_BACK_CH_TRAINING_PATTERN_TIME 0x00125
|
||||
#define DPCD_TX_GTC_VALUE_7_0 0x00154
|
||||
#define DPCD_TX_GTC_VALUE_15_8 0x00155
|
||||
#define DPCD_TX_GTC_VALUE_23_16 0x00156
|
||||
#define DPCD_TX_GTC_VALUE_31_24 0x00157
|
||||
#define DPCD_RX_GTC_VALUE_PHASE_SKEW_EN 0x00158
|
||||
#define DPCD_TX_GTC_FREQ_LOCK_DONE 0x00159
|
||||
#define DPCD_ADAPTER_CTRL 0x001A0
|
||||
#define DPCD_BRANCH_DEVICE_CTRL 0x001A1
|
||||
#define DPCD_PAYLOAD_ALLOCATE_SET 0x001C0
|
||||
#define DPCD_PAYLOAD_ALLOCATE_START_TIME_SLOT 0x001C1
|
||||
#define DPCD_PAYLOAD_ALLOCATE_TIME_SLOT_COUNT 0x001C2
|
||||
|
||||
/* link/sink status field */
|
||||
#define DPCD_SINK_COUNT 0x00200
|
||||
#define DPCD_DEVICE_SERVICE_IRQ 0x00201
|
||||
#define DPCD_STATUS_LANE_0_1 0x00202
|
||||
#define DPCD_STATUS_LANE_2_3 0x00203
|
||||
#define DPCD_LANE_ALIGN_STATUS_UPDATED 0x00204
|
||||
#define DPCD_SINK_STATUS 0x00205
|
||||
#define DPCD_ADJ_REQ_LANE_0_1 0x00206
|
||||
#define DPCD_ADJ_REQ_LANE_2_3 0x00207
|
||||
#define DPCD_TRAINING_SCORE_LANE_0 0x00208
|
||||
#define DPCD_TRAINING_SCORE_LANE_1 0x00209
|
||||
#define DPCD_TRAINING_SCORE_LANE_2 0x0020A
|
||||
#define DPCD_TRAINING_SCORE_LANE_3 0x0020B
|
||||
#define DPCD_ADJ_REQ_PC2 0x0020C
|
||||
#define DPCD_FAUX_FORWARD_CH_SYMBOL_ERROR_COUNT 0x0020D
|
||||
#define DPCD_SYMBOL_ERROR_COUNT_LANE_0 0x00210
|
||||
#define DPCD_SYMBOL_ERROR_COUNT_LANE_1 0x00212
|
||||
#define DPCD_SYMBOL_ERROR_COUNT_LANE_2 0x00214
|
||||
#define DPCD_SYMBOL_ERROR_COUNT_LANE_3 0x00216
|
||||
|
||||
/* automated testing sub-field */
|
||||
#define DPCD_FAUX_FORWARD_CH_STATUS 0x00280
|
||||
#define DPCD_FAUX_BACK_CH_DRIVE_SET 0x00281
|
||||
#define DPCD_FAUX_BACK_CH_SYM_ERR_COUNT_CTRL 0x00282
|
||||
#define DPCD_PAYLOAD_TABLE_UPDATE_STATUS 0x002C0
|
||||
#define DPCD_VC_PAYLOAD_ID_SLOT(slotnum) \
|
||||
(DPCD_PAYLOAD_TABLE_UPDATE_STATUS + slotnum)
|
||||
|
||||
/* sink control field */
|
||||
#define DPCD_SET_POWER_DP_PWR_VOLTAGE 0x00600
|
||||
|
||||
/* sideband message buffers */
|
||||
#define DPCD_DOWN_REQ 0x01000
|
||||
#define DPCD_UP_REP 0x01200
|
||||
#define DPCD_DOWN_REP 0x01400
|
||||
#define DPCD_UP_REQ 0x01600
|
||||
|
||||
/* event status indicator field */
|
||||
#define DPCD_SINK_COUNT_ESI 0x02002
|
||||
#define DPCD_SINK_DEVICE_SERVICE_IRQ_VECTOR_ESI0 0x02003
|
||||
#define DPCD_SINK_DEVICE_SERVICE_IRQ_VECTOR_ESI1 0x02004
|
||||
#define DPCD_SINK_LINK_SERVICE_IRQ_VECTOR_ESI0 0x02005
|
||||
#define DPCD_SINK_LANE0_1_STATUS 0x0200C
|
||||
#define DPCD_SINK_LANE2_3_STATUS 0x0200D
|
||||
#define DPCD_SINK_ALIGN_STATUS_UPDATED_ESI 0x0200E
|
||||
#define DPCD_SINK_STATUS_ESI 0x0200F
|
||||
|
||||
/*
|
||||
* field addresses and sizes.
|
||||
*/
|
||||
#define DPCD_RECEIVER_CAP_FIELD_START DPCD_REV
|
||||
#define DPCD_RECEIVER_CAP_FIELD_SIZE 0x100
|
||||
#define DPCD_LINK_CFG_FIELD_START DPCD_LINK_BW_SET
|
||||
#define DPCD_LINK_CFG_FIELD_SIZE 0x100
|
||||
#define DPCD_LINK_SINK_STATUS_FIELD_START DPCD_SINK_COUNT
|
||||
#define DPCD_LINK_SINK_STATUS_FIELD_SIZE 0x17
|
||||
/* 0x00000: DPCD_REV */
|
||||
#define DPCD_REV_MNR_MASK 0x0F
|
||||
#define DPCD_REV_MJR_MASK 0xF0
|
||||
#define DPCD_REV_MJR_SHIFT 4
|
||||
/* 0x00001: MAX_LINK_RATE */
|
||||
#define DPCD_MAX_LINK_RATE_162GBPS 0x06
|
||||
#define DPCD_MAX_LINK_RATE_270GBPS 0x0A
|
||||
#define DPCD_MAX_LINK_RATE_540GBPS 0x14
|
||||
/* 0x00002: MAX_LANE_COUNT */
|
||||
#define DPCD_MAX_LANE_COUNT_MASK 0x1F
|
||||
#define DPCD_MAX_LANE_COUNT_1 0x01
|
||||
#define DPCD_MAX_LANE_COUNT_2 0x02
|
||||
#define DPCD_MAX_LANE_COUNT_4 0x04
|
||||
#define DPCD_TPS3_SUPPORT_MASK 0x40
|
||||
#define DPCD_ENHANCED_FRAME_SUPPORT_MASK 0x80
|
||||
/* 0x00003: MAX_DOWNSPREAD */
|
||||
#define DPCD_MAX_DOWNSPREAD_MASK 0x01
|
||||
#define DPCD_NO_AUX_HANDSHAKE_LINK_TRAIN_MASK 0x40
|
||||
/* 0x00005: DOWNSP_PRESENT */
|
||||
#define DPCD_DOWNSP_PRESENT_MASK 0x01
|
||||
#define DPCD_DOWNSP_TYPE_MASK 0x06
|
||||
#define DPCD_DOWNSP_TYPE_SHIFT 1
|
||||
#define DPCD_DOWNSP_TYPE_DP 0x0
|
||||
#define DPCD_DOWNSP_TYPE_AVGA_ADVII 0x1
|
||||
#define DPCD_DOWNSP_TYPE_DVI_HDMI_DPPP 0x2
|
||||
#define DPCD_DOWNSP_TYPE_OTHERS 0x3
|
||||
#define DPCD_DOWNSP_FORMAT_CONV_MASK 0x08
|
||||
#define DPCD_DOWNSP_DCAP_INFO_AVAIL_MASK 0x10
|
||||
/* 0x00006, 0x00108: ML_CH_CODING_SUPPORT, ML_CH_CODING_SET */
|
||||
#define DPCD_ML_CH_CODING_MASK 0x01
|
||||
/* 0x00007: DOWNSP_COUNT_MSA_OUI */
|
||||
#define DPCD_DOWNSP_COUNT_MASK 0x0F
|
||||
#define DPCD_MSA_TIMING_PAR_IGNORED_MASK 0x40
|
||||
#define DPCD_OUI_SUPPORT_MASK 0x80
|
||||
/* 0x00008, 0x0000A: RX_PORT[0-1]_CAP_0 */
|
||||
#define DPCD_RX_PORTX_CAP_0_LOCAL_EDID_PRESENT_MASK 0x02
|
||||
#define DPCD_RX_PORTX_CAP_0_ASSOC_TO_PRECEDING_PORT_MASK 0x04
|
||||
/* 0x0000C, 0x00109: I2C_SPEED_CTL_CAP, I2C_SPEED_CTL_SET */
|
||||
#define DPCD_I2C_SPEED_CTL_NONE 0x00
|
||||
#define DPCD_I2C_SPEED_CTL_1KBIPS 0x01
|
||||
#define DPCD_I2C_SPEED_CTL_5KBIPS 0x02
|
||||
#define DPCD_I2C_SPEED_CTL_10KBIPS 0x04
|
||||
#define DPCD_I2C_SPEED_CTL_100KBIPS 0x08
|
||||
#define DPCD_I2C_SPEED_CTL_400KBIPS 0x10
|
||||
#define DPCD_I2C_SPEED_CTL_1MBIPS 0x20
|
||||
/* 0x0000E: TRAIN_AUX_RD_INTERVAL */
|
||||
#define DPCD_TRAIN_AUX_RD_INT_100_400US 0x00
|
||||
#define DPCD_TRAIN_AUX_RD_INT_4MS 0x01
|
||||
#define DPCD_TRAIN_AUX_RD_INT_8MS 0x02
|
||||
#define DPCD_TRAIN_AUX_RD_INT_12MS 0x03
|
||||
#define DPCD_TRAIN_AUX_RD_INT_16MS 0x04
|
||||
/* 0x00020: DPCD_FAUX_CAP */
|
||||
#define DPCD_FAUX_CAP_MASK 0x01
|
||||
/* 0x00021: MSTM_CAP */
|
||||
#define DPCD_MST_CAP_MASK 0x01
|
||||
/* 0x00080, 0x00081|4, 0x00082|8, 0x00083|C: DOWNSP_X_(DET_)CAP */
|
||||
#define DPCD_DOWNSP_X_CAP_TYPE_MASK 0x07
|
||||
#define DPCD_DOWNSP_X_CAP_TYPE_DP 0x0
|
||||
#define DPCD_DOWNSP_X_CAP_TYPE_AVGA 0x1
|
||||
#define DPCD_DOWNSP_X_CAP_TYPE_DVI 0x2
|
||||
#define DPCD_DOWNSP_X_CAP_TYPE_HDMI 0x3
|
||||
#define DPCD_DOWNSP_X_CAP_TYPE_OTHERS 0x4
|
||||
#define DPCD_DOWNSP_X_CAP_TYPE_DPPP 0x5
|
||||
#define DPCD_DOWNSP_X_CAP_HPD_MASK 0x80
|
||||
#define DPCD_DOWNSP_X_CAP_NON_EDID_ATTR_MASK 0xF0
|
||||
#define DPCD_DOWNSP_X_CAP_NON_EDID_ATTR_SHIFT 4
|
||||
#define DPCD_DOWNSP_X_CAP_NON_EDID_ATTR_720_480_I_60 0x1
|
||||
#define DPCD_DOWNSP_X_CAP_NON_EDID_ATTR_720_480_I_50 0x2
|
||||
#define DPCD_DOWNSP_X_CAP_NON_EDID_ATTR_1920_1080_I_60 0x3
|
||||
#define DPCD_DOWNSP_X_CAP_NON_EDID_ATTR_1920_1080_I_50 0x4
|
||||
#define DPCD_DOWNSP_X_CAP_NON_EDID_ATTR_1280_720_P_60 0x5
|
||||
#define DPCD_DOWNSP_X_CAP_NON_EDID_ATTR_1280_720_P_50 0x7
|
||||
/* 0x00082, 0x00086, 0x0008A, 0x0008E: DOWNSP_X_(DET_)CAP2 */
|
||||
#define DPCD_DOWNSP_X_DCAP_MAX_BPC_MASK 0x03
|
||||
#define DPCD_DOWNSP_X_DCAP_MAX_BPC_8 0x0
|
||||
#define DPCD_DOWNSP_X_DCAP_MAX_BPC_10 0x1
|
||||
#define DPCD_DOWNSP_X_DCAP_MAX_BPC_12 0x2
|
||||
#define DPCD_DOWNSP_X_DCAP_MAX_BPC_16 0x3
|
||||
/* 0x00082, 0x00086, 0x0008A, 0x0008E: DOWNSP_X_(DET_)CAP2 */
|
||||
#define DPCD_DOWNSP_X_DCAP_HDMI_DPPP_FS2FP_MASK 0x01
|
||||
#define DPCD_DOWNSP_X_DCAP_DVI_DL_MASK 0x02
|
||||
#define DPCD_DOWNSP_X_DCAP_DVI_HCD_MASK 0x04
|
||||
|
||||
/* link configuration field masks, shifts, and register values */
|
||||
/* 0x00100: DPCD_LINK_BW_SET */
|
||||
#define DPCD_LINK_BW_SET_162GBPS 0x06
|
||||
#define DPCD_LINK_BW_SET_270GBPS 0x0A
|
||||
#define DPCD_LINK_BW_SET_540GBPS 0x14
|
||||
/* 0x00101: LANE_COUNT_SET */
|
||||
#define DPCD_LANE_COUNT_SET_MASK 0x1F
|
||||
#define DPCD_LANE_COUNT_SET_1 0x01
|
||||
#define DPCD_LANE_COUNT_SET_2 0x02
|
||||
#define DPCD_LANE_COUNT_SET_4 0x04
|
||||
#define DPCD_ENHANCED_FRAME_EN_MASK 0x80
|
||||
/* 0x00102: TP_SET */
|
||||
#define DPCD_TP_SEL_MASK 0x03
|
||||
#define DPCD_TP_SEL_OFF 0x0
|
||||
#define DPCD_TP_SEL_TP1 0x1
|
||||
#define DPCD_TP_SEL_TP2 0x2
|
||||
#define DPCD_TP_SEL_TP3 0x3
|
||||
#define DPCD_TP_SET_LQP_MASK 0x06
|
||||
#define DPCD_TP_SET_LQP_SHIFT 2
|
||||
#define DPCD_TP_SET_LQP_OFF 0x0
|
||||
#define DPCD_TP_SET_LQP_D102_TEST 0x1
|
||||
#define DPCD_TP_SET_LQP_SER_MES 0x2
|
||||
#define DPCD_TP_SET_LQP_PRBS7 0x3
|
||||
#define DPCD_TP_SET_REC_CLK_OUT_EN_MASK 0x10
|
||||
#define DPCD_TP_SET_SCRAMB_DIS_MASK 0x20
|
||||
#define DPCD_TP_SET_SE_COUNT_SEL_MASK 0xC0
|
||||
#define DPCD_TP_SET_SE_COUNT_SEL_SHIFT 6
|
||||
#define DPCD_TP_SET_SE_COUNT_SEL_DE_ISE 0x0
|
||||
#define DPCD_TP_SET_SE_COUNT_SEL_DE 0x1
|
||||
#define DPCD_TP_SET_SE_COUNT_SEL_ISE 0x2
|
||||
/* 0x00103-0x00106: TRAINING_LANE[0-3]_SET */
|
||||
#define DPCD_TRAINING_LANEX_SET_VS_MASK 0x03
|
||||
#define DPCD_TRAINING_LANEX_SET_MAX_VS_MASK 0x04
|
||||
#define DPCD_TRAINING_LANEX_SET_PE_MASK 0x18
|
||||
#define DPCD_TRAINING_LANEX_SET_PE_SHIFT 3
|
||||
#define DPCD_TRAINING_LANEX_SET_MAX_PE_MASK 0x20
|
||||
/* 0x00107: DOWNSPREAD_CTRL */
|
||||
#define DPCD_SPREAD_AMP_MASK 0x10
|
||||
#define DPCD_MSA_TIMING_PAR_IGNORED_EN_MASK 0x80
|
||||
/* 0x00108: ML_CH_CODING_SET - Same as 0x00006: ML_CH_CODING_SUPPORT */
|
||||
/* 0x00109: I2C_SPEED_CTL_SET - Same as 0x0000C: I2C_SPEED_CTL_CAP */
|
||||
/* 0x0010F-0x00110: TRAINING_LANE[0_1-2_3]_SET2 */
|
||||
#define DPCD_TRAINING_LANE_0_2_SET_PC2_MASK 0x03
|
||||
#define DPCD_TRAINING_LANE_0_2_SET_MAX_PC2_MASK 0x04
|
||||
#define DPCD_TRAINING_LANE_1_3_SET_PC2_MASK 0x30
|
||||
#define DPCD_TRAINING_LANE_1_3_SET_PC2_SHIFT 4
|
||||
#define DPCD_TRAINING_LANE_1_3_SET_MAX_PC2_MASK 0x40
|
||||
/* 0x00111: MSTM_CTRL */
|
||||
#define DPCD_MST_EN_MASK 0x01
|
||||
#define DPCD_UP_REQ_EN_MASK 0x02
|
||||
#define DPCD_UP_IS_SRC_MASK 0x03
|
||||
|
||||
/* link/sink status field masks, shifts, and register values */
|
||||
/* 0x00200: SINK_COUNT */
|
||||
#define DPCD_SINK_COUNT_LOW_MASK 0x3F
|
||||
#define DPCD_SINK_CP_READY_MASK 0x40
|
||||
#define DPCD_SINK_COUNT_HIGH_MASK 0x80
|
||||
#define DPCD_SINK_COUNT_HIGH_LOW_SHIFT 1
|
||||
/* 0x00202: STATUS_LANE_0_1 */
|
||||
#define DPCD_STATUS_LANE_0_CR_DONE_MASK 0x01
|
||||
#define DPCD_STATUS_LANE_0_CE_DONE_MASK 0x02
|
||||
#define DPCD_STATUS_LANE_0_SL_DONE_MASK 0x04
|
||||
#define DPCD_STATUS_LANE_1_CR_DONE_MASK 0x10
|
||||
#define DPCD_STATUS_LANE_1_CE_DONE_MASK 0x20
|
||||
#define DPCD_STATUS_LANE_1_SL_DONE_MASK 0x40
|
||||
/* 0x00202: STATUS_LANE_2_3 */
|
||||
#define DPCD_STATUS_LANE_2_CR_DONE_MASK 0x01
|
||||
#define DPCD_STATUS_LANE_2_CE_DONE_MASK 0x02
|
||||
#define DPCD_STATUS_LANE_2_SL_DONE_MASK 0x04
|
||||
#define DPCD_STATUS_LANE_3_CR_DONE_MASK 0x10
|
||||
#define DPCD_STATUS_LANE_3_CE_DONE_MASK 0x20
|
||||
#define DPCD_STATUS_LANE_3_SL_DONE_MASK 0x40
|
||||
/* 0x00204: LANE_ALIGN_STATUS_UPDATED */
|
||||
#define DPCD_LANE_ALIGN_STATUS_UPDATED_IA_DONE_MASK \
|
||||
0x01
|
||||
#define DPCD_LANE_ALIGN_STATUS_UPDATED_DOWNSP_STATUS_CHANGED_MASK \
|
||||
0x40
|
||||
#define DPCD_LANE_ALIGN_STATUS_UPDATED_LINK_STATUS_UPDATED_MASK \
|
||||
0x80
|
||||
/* 0x00205: SINK_STATUS */
|
||||
#define DPCD_SINK_STATUS_RX_PORT0_SYNC_STATUS_MASK 0x01
|
||||
#define DPCD_SINK_STATUS_RX_PORT1_SYNC_STATUS_MASK 0x02
|
||||
|
||||
/* 0x00206, 0x00207: ADJ_REQ_LANE_[0,2]_[1,3] */
|
||||
#define DPCD_ADJ_REQ_LANE_0_2_VS_MASK 0x03
|
||||
#define DPCD_ADJ_REQ_LANE_0_2_PE_MASK 0x0C
|
||||
#define DPCD_ADJ_REQ_LANE_0_2_PE_SHIFT 2
|
||||
#define DPCD_ADJ_REQ_LANE_1_3_VS_MASK 0x30
|
||||
#define DPCD_ADJ_REQ_LANE_1_3_VS_SHIFT 4
|
||||
#define DPCD_ADJ_REQ_LANE_1_3_PE_MASK 0xC0
|
||||
#define DPCD_ADJ_REQ_LANE_1_3_PE_SHIFT 6
|
||||
/* 0x0020C: ADJ_REQ_PC2 */
|
||||
#define DPCD_ADJ_REQ_PC2_LANE_0_MASK 0x03
|
||||
#define DPCD_ADJ_REQ_PC2_LANE_1_MASK 0x0C
|
||||
#define DPCD_ADJ_REQ_PC2_LANE_1_SHIFT 2
|
||||
#define DPCD_ADJ_REQ_PC2_LANE_2_MASK 0x30
|
||||
#define DPCD_ADJ_REQ_PC2_LANE_2_SHIFT 4
|
||||
#define DPCD_ADJ_REQ_PC2_LANE_3_MASK 0xC0
|
||||
#define DPCD_ADJ_REQ_PC2_LANE_3_SHIFT 6
|
||||
|
||||
#endif /* __GDSYS_LOGICORE_DP_DPCD_H__ */
|
2296
drivers/video/logicore_dp_tx.c
Normal file
2296
drivers/video/logicore_dp_tx.c
Normal file
File diff suppressed because it is too large
Load Diff
54
drivers/video/logicore_dp_tx.h
Normal file
54
drivers/video/logicore_dp_tx.h
Normal file
@ -0,0 +1,54 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* logicore_dp_tx.h
|
||||
*
|
||||
* Driver for XILINX LogiCore DisplayPort v6.1 TX (Source)
|
||||
*
|
||||
* (C) Copyright 2016
|
||||
* Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc
|
||||
*/
|
||||
|
||||
#ifndef __GDSYS_LOGICORE_DP_TX_H__
|
||||
#define __GDSYS_LOGICORE_DP_TX_H__
|
||||
|
||||
/*
|
||||
* struct logicore_dp_tx_msa - Main Stream Attributes (MSA)
|
||||
* @pixel_clock_hz: The pixel clock of the stream (in Hz)
|
||||
* @bits_per_color: Number of bits per color component
|
||||
* @h_active: Horizontal active resolution (pixels)
|
||||
* @h_start: Horizontal blank start (in pixels)
|
||||
* @h_sync_polarity: Horizontal sync polarity
|
||||
* (0 = negative | 1 = positive)
|
||||
* @h_sync_width: Horizontal sync width (pixels)
|
||||
* @h_total: Horizontal total (pixels)
|
||||
* @v_active: Vertical active resolution (lines)
|
||||
* @v_start: Vertical blank start (in lines).
|
||||
* @v_sync_polarity: Vertical sync polarity
|
||||
* (0 = negative | 1 = positive)
|
||||
* @v_sync_width: Vertical sync width (lines)
|
||||
* @v_total: Vertical total (lines)
|
||||
* @override_user_pixel_width: If true, the value stored for user_pixel_width
|
||||
* will be used as the pixel width.
|
||||
* @user_pixel_width: The width of the user data input port.
|
||||
*
|
||||
* This is a stripped down version of struct main_stream_attributes that
|
||||
* contains only the parameters that are not set by cfg_msa_recalculate()
|
||||
*/
|
||||
struct logicore_dp_tx_msa {
|
||||
u32 pixel_clock_hz;
|
||||
u32 bits_per_color;
|
||||
u16 h_active;
|
||||
u32 h_start;
|
||||
bool h_sync_polarity;
|
||||
u16 h_sync_width;
|
||||
u16 h_total;
|
||||
u16 v_active;
|
||||
u32 v_start;
|
||||
bool v_sync_polarity;
|
||||
u16 v_sync_width;
|
||||
u16 v_total;
|
||||
bool override_user_pixel_width;
|
||||
u32 user_pixel_width;
|
||||
};
|
||||
|
||||
#endif /* __GDSYS_LOGICORE_DP_TX_H__ */
|
396
drivers/video/logicore_dp_tx_regif.h
Normal file
396
drivers/video/logicore_dp_tx_regif.h
Normal file
@ -0,0 +1,396 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* logicore_dp_tx_regif.h
|
||||
*
|
||||
* Register interface definition for XILINX LogiCore DisplayPort v6.1 TX
|
||||
* (Source) based on Xilinx dp_v3_1 driver sources
|
||||
*
|
||||
* (C) Copyright 2016
|
||||
* Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc
|
||||
*/
|
||||
|
||||
#ifndef __GDSYS_LOGICORE_DP_TX_REGIF_H__
|
||||
#define __GDSYS_LOGICORE_DP_TX_REGIF_H__
|
||||
|
||||
enum {
|
||||
/* link configuration field */
|
||||
REG_LINK_BW_SET = 0x000,
|
||||
REG_LANE_COUNT_SET = 0x004,
|
||||
REG_ENHANCED_FRAME_EN = 0x008,
|
||||
REG_TRAINING_PATTERN_SET = 0x00C,
|
||||
REG_LINK_QUAL_PATTERN_SET = 0x010,
|
||||
REG_SCRAMBLING_DISABLE = 0x014,
|
||||
REG_DOWNSPREAD_CTRL = 0x018,
|
||||
REG_SOFT_RESET = 0x01C,
|
||||
};
|
||||
|
||||
enum {
|
||||
/* core enables */
|
||||
REG_ENABLE = 0x080,
|
||||
REG_ENABLE_MAIN_STREAM = 0x084,
|
||||
REG_ENABLE_SEC_STREAM = 0x088,
|
||||
REG_FORCE_SCRAMBLER_RESET = 0x0C0,
|
||||
REG_MST_CONFIG = 0x0D0,
|
||||
REG_LINE_RESET_DISABLE = 0x0F0,
|
||||
};
|
||||
|
||||
enum {
|
||||
/* core ID */
|
||||
REG_VERSION = 0x0F8,
|
||||
REG_CORE_ID = 0x0FC,
|
||||
};
|
||||
|
||||
enum {
|
||||
/* AUX channel interface */
|
||||
REG_AUX_CMD = 0x100,
|
||||
REG_AUX_WRITE_FIFO = 0x104,
|
||||
REG_AUX_ADDRESS = 0x108,
|
||||
REG_AUX_CLK_DIVIDER = 0x10C,
|
||||
REG_USER_FIFO_OVERFLOW = 0x110,
|
||||
REG_INTERRUPT_SIG_STATE = 0x130,
|
||||
REG_AUX_REPLY_DATA = 0x134,
|
||||
REG_AUX_REPLY_CODE = 0x138,
|
||||
REG_AUX_REPLY_COUNT = 0x13C,
|
||||
REG_INTERRUPT_STATUS = 0x140,
|
||||
REG_INTERRUPT_MASK = 0x144,
|
||||
REG_REPLY_DATA_COUNT = 0x148,
|
||||
REG_REPLY_STATUS = 0x14C,
|
||||
REG_HPD_DURATION = 0x150,
|
||||
};
|
||||
|
||||
enum {
|
||||
/* main stream attributes for SST / MST STREAM1 */
|
||||
REG_STREAM1_MSA_START = 0x180,
|
||||
REG_MAIN_STREAM_HTOTAL = 0x180,
|
||||
REG_MAIN_STREAM_VTOTAL = 0x184,
|
||||
REG_MAIN_STREAM_POLARITY = 0x188,
|
||||
REG_MAIN_STREAM_HSWIDTH = 0x18C,
|
||||
REG_MAIN_STREAM_VSWIDTH = 0x190,
|
||||
REG_MAIN_STREAM_HRES = 0x194,
|
||||
REG_MAIN_STREAM_VRES = 0x198,
|
||||
REG_MAIN_STREAM_HSTART = 0x19C,
|
||||
REG_MAIN_STREAM_VSTART = 0x1A0,
|
||||
REG_MAIN_STREAM_MISC0 = 0x1A4,
|
||||
REG_MAIN_STREAM_MISC1 = 0x1A8,
|
||||
REG_M_VID = 0x1AC,
|
||||
REG_TU_SIZE = 0x1B0,
|
||||
REG_N_VID = 0x1B4,
|
||||
REG_USER_PIXEL_WIDTH = 0x1B8,
|
||||
REG_USER_DATA_COUNT_PER_LANE = 0x1BC,
|
||||
REG_MAIN_STREAM_INTERLACED = 0x1C0,
|
||||
REG_MIN_BYTES_PER_TU = 0x1C4,
|
||||
REG_FRAC_BYTES_PER_TU = 0x1C8,
|
||||
REG_INIT_WAIT = 0x1CC,
|
||||
REG_STREAM1 = 0x1D0,
|
||||
REG_STREAM2 = 0x1D4,
|
||||
REG_STREAM3 = 0x1D8,
|
||||
REG_STREAM4 = 0x1DC,
|
||||
};
|
||||
|
||||
enum {
|
||||
/* PHY configuration status */
|
||||
REG_PHY_CONFIG = 0x200,
|
||||
REG_PHY_VOLTAGE_DIFF_LANE_0 = 0x220,
|
||||
REG_PHY_VOLTAGE_DIFF_LANE_1 = 0x224,
|
||||
REG_PHY_VOLTAGE_DIFF_LANE_2 = 0x228,
|
||||
REG_PHY_VOLTAGE_DIFF_LANE_3 = 0x22C,
|
||||
REG_PHY_TRANSMIT_PRBS7 = 0x230,
|
||||
REG_PHY_CLOCK_SELECT = 0x234,
|
||||
REG_PHY_POWER_DOWN = 0x238,
|
||||
REG_PHY_PRECURSOR_LANE_0 = 0x23C,
|
||||
REG_PHY_PRECURSOR_LANE_1 = 0x240,
|
||||
REG_PHY_PRECURSOR_LANE_2 = 0x244,
|
||||
REG_PHY_PRECURSOR_LANE_3 = 0x248,
|
||||
REG_PHY_POSTCURSOR_LANE_0 = 0x24C,
|
||||
REG_PHY_POSTCURSOR_LANE_1 = 0x250,
|
||||
REG_PHY_POSTCURSOR_LANE_2 = 0x254,
|
||||
REG_PHY_POSTCURSOR_LANE_3 = 0x258,
|
||||
REG_PHY_STATUS = 0x280,
|
||||
REG_GT_DRP_COMMAND = 0x2A0,
|
||||
REG_GT_DRP_READ_DATA = 0x2A4,
|
||||
REG_GT_DRP_CHANNEL_STATUS = 0x2A8,
|
||||
};
|
||||
|
||||
enum {
|
||||
/* DisplayPort audio */
|
||||
REG_AUDIO_CONTROL = 0x300,
|
||||
REG_AUDIO_CHANNELS = 0x304,
|
||||
REG_AUDIO_INFO_DATA = 0x308,
|
||||
REG_AUDIO_MAUD = 0x328,
|
||||
REG_AUDIO_NAUD = 0x32C,
|
||||
REG_AUDIO_EXT_DATA = 0x330,
|
||||
};
|
||||
|
||||
enum {
|
||||
/* HDCP */
|
||||
REG_HDCP_ENABLE = 0x400,
|
||||
};
|
||||
|
||||
enum {
|
||||
/* main stream attributes for MST STREAM2, 3, and 4 */
|
||||
REG_STREAM2_MSA_START = 0x500,
|
||||
REG_STREAM3_MSA_START = 0x550,
|
||||
REG_STREAM4_MSA_START = 0x5A0,
|
||||
|
||||
REG_VC_PAYLOAD_BUFFER_ADDR = 0x800,
|
||||
};
|
||||
|
||||
enum {
|
||||
LINK_BW_SET_162GBPS = 0x06,
|
||||
LINK_BW_SET_270GBPS = 0x0A,
|
||||
LINK_BW_SET_540GBPS = 0x14,
|
||||
};
|
||||
|
||||
enum {
|
||||
LANE_COUNT_SET_1 = 0x1,
|
||||
LANE_COUNT_SET_2 = 0x2,
|
||||
LANE_COUNT_SET_4 = 0x4,
|
||||
};
|
||||
|
||||
enum {
|
||||
TRAINING_PATTERN_SET_OFF = 0x0,
|
||||
/* training pattern 1 used for clock recovery */
|
||||
TRAINING_PATTERN_SET_TP1 = 0x1,
|
||||
/* training pattern 2 used for channel equalization */
|
||||
TRAINING_PATTERN_SET_TP2 = 0x2,
|
||||
/*
|
||||
* training pattern 3 used for channel equalization for cores with DP
|
||||
* v1.2
|
||||
*/
|
||||
TRAINING_PATTERN_SET_TP3 = 0x3,
|
||||
};
|
||||
|
||||
enum {
|
||||
LINK_QUAL_PATTERN_SET_OFF = 0x0,
|
||||
/* D10.2 unscrambled test pattern transmitted */
|
||||
LINK_QUAL_PATTERN_SET_D102_TEST = 0x1,
|
||||
/* symbol error rate measurement pattern transmitted */
|
||||
LINK_QUAL_PATTERN_SET_SER_MES = 0x2,
|
||||
/* pseudo random bit sequence 7 transmitted */
|
||||
LINK_QUAL_PATTERN_SET_PRBS7 = 0x3,
|
||||
};
|
||||
|
||||
enum {
|
||||
SOFT_RESET_VIDEO_STREAM1_MASK = 0x00000001,
|
||||
SOFT_RESET_VIDEO_STREAM2_MASK = 0x00000002,
|
||||
SOFT_RESET_VIDEO_STREAM3_MASK = 0x00000004,
|
||||
SOFT_RESET_VIDEO_STREAM4_MASK = 0x00000008,
|
||||
SOFT_RESET_AUX_MASK = 0x00000080,
|
||||
SOFT_RESET_VIDEO_STREAM_ALL_MASK = 0x0000000F,
|
||||
};
|
||||
|
||||
enum {
|
||||
MST_CONFIG_MST_EN_MASK = 0x00000001,
|
||||
};
|
||||
|
||||
enum {
|
||||
LINE_RESET_DISABLE_MASK = 0x1,
|
||||
};
|
||||
|
||||
#define AUX_CMD_NBYTES_TRANSFER_MASK 0x0000000F
|
||||
|
||||
#define AUX_CMD_SHIFT 8
|
||||
#define AUX_CMD_MASK 0x00000F00
|
||||
enum {
|
||||
AUX_CMD_I2C_WRITE = 0x0,
|
||||
AUX_CMD_I2C_READ = 0x1,
|
||||
AUX_CMD_I2C_WRITE_STATUS = 0x2,
|
||||
AUX_CMD_I2C_WRITE_MOT = 0x4,
|
||||
AUX_CMD_I2C_READ_MOT = 0x5,
|
||||
AUX_CMD_I2C_WRITE_STATUS_MOT = 0x6,
|
||||
AUX_CMD_WRITE = 0x8,
|
||||
AUX_CMD_READ = 0x9,
|
||||
};
|
||||
|
||||
#define AUX_CLK_DIVIDER_VAL_MASK 0x00FF
|
||||
|
||||
#define AUX_CLK_DIVIDER_AUX_SIG_WIDTH_FILT_SHIFT 8
|
||||
#define AUX_CLK_DIVIDER_AUX_SIG_WIDTH_FILT_MASK 0xFF00
|
||||
|
||||
enum {
|
||||
INTERRUPT_SIG_STATE_HPD_STATE_MASK = 0x00000001,
|
||||
INTERRUPT_SIG_STATE_REQUEST_STATE_MASK = 0x00000002,
|
||||
INTERRUPT_SIG_STATE_REPLY_STATE_MASK = 0x00000004,
|
||||
INTERRUPT_SIG_STATE_REPLY_TIMEOUT_MASK = 0x00000008,
|
||||
};
|
||||
|
||||
enum {
|
||||
AUX_REPLY_CODE_ACK = 0x0,
|
||||
AUX_REPLY_CODE_I2C_ACK = 0x0,
|
||||
AUX_REPLY_CODE_NACK = 0x1,
|
||||
AUX_REPLY_CODE_DEFER = 0x2,
|
||||
AUX_REPLY_CODE_I2C_NACK = 0x4,
|
||||
AUX_REPLY_CODE_I2C_DEFER = 0x8,
|
||||
};
|
||||
|
||||
enum {
|
||||
INTERRUPT_STATUS_HPD_IRQ_MASK = 0x00000001,
|
||||
INTERRUPT_STATUS_HPD_EVENT_MASK = 0x00000002,
|
||||
INTERRUPT_STATUS_REPLY_RECEIVED_MASK = 0x00000004,
|
||||
INTERRUPT_STATUS_REPLY_TIMEOUT_MASK = 0x00000008,
|
||||
INTERRUPT_STATUS_HPD_PULSE_DETECTED_MASK = 0x00000010,
|
||||
INTERRUPT_STATUS_EXT_PKT_TXD_MASK = 0x00000020,
|
||||
};
|
||||
|
||||
enum {
|
||||
INTERRUPT_MASK_HPD_IRQ_MASK = 0x00000001,
|
||||
INTERRUPT_MASK_HPD_EVENT_MASK = 0x00000002,
|
||||
INTERRUPT_MASK_REPLY_RECEIVED_MASK = 0x00000004,
|
||||
INTERRUPT_MASK_REPLY_TIMEOUT_MASK = 0x00000008,
|
||||
INTERRUPT_MASK_HPD_PULSE_DETECTED_MASK = 0x00000010,
|
||||
INTERRUPT_MASK_EXT_PKT_TXD_MASK = 0x00000020,
|
||||
};
|
||||
|
||||
#define REPLY_STATUS_REPLY_STATUS_STATE_SHIFT 4
|
||||
#define REPLY_STATUS_REPLY_STATUS_STATE_MASK 0x00000FF0
|
||||
enum {
|
||||
REPLY_STATUS_REPLY_RECEIVED_MASK = 0x00000001,
|
||||
REPLY_STATUS_REPLY_IN_PROGRESS_MASK = 0x00000002,
|
||||
REPLY_STATUS_REQUEST_IN_PROGRESS_MASK = 0x00000004,
|
||||
REPLY_STATUS_REPLY_ERROR_MASK = 0x00000008,
|
||||
};
|
||||
|
||||
#define MAIN_STREAMX_POLARITY_VSYNC_POL_SHIFT 1
|
||||
enum {
|
||||
MAIN_STREAMX_POLARITY_HSYNC_POL_MASK = 0x00000001,
|
||||
MAIN_STREAMX_POLARITY_VSYNC_POL_MASK = 0x00000002,
|
||||
};
|
||||
|
||||
enum {
|
||||
MAIN_STREAMX_MISC0_SYNC_CLK_MASK = 0x00000001,
|
||||
};
|
||||
|
||||
#define MAIN_STREAMX_MISC0_COMPONENT_FORMAT_SHIFT 1
|
||||
#define MAIN_STREAMX_MISC0_COMPONENT_FORMAT_MASK 0x00000006
|
||||
enum {
|
||||
MAIN_STREAMX_MISC0_COMPONENT_FORMAT_RGB = 0x0,
|
||||
MAIN_STREAMX_MISC0_COMPONENT_FORMAT_YCBCR422 = 0x1,
|
||||
MAIN_STREAMX_MISC0_COMPONENT_FORMAT_YCBCR444 = 0x2,
|
||||
};
|
||||
|
||||
#define MAIN_STREAMX_MISC0_DYNAMIC_RANGE_SHIFT 3
|
||||
#define MAIN_STREAMX_MISC0_DYNAMIC_RANGE_MASK 0x00000008
|
||||
|
||||
#define MAIN_STREAMX_MISC0_YCBCR_COLORIMETRY_SHIFT 4
|
||||
#define MAIN_STREAMX_MISC0_YCBCR_COLORIMETRY_MASK 0x00000010
|
||||
|
||||
#define MAIN_STREAMX_MISC0_BDC_SHIFT 5
|
||||
#define MAIN_STREAMX_MISC0_BDC_MASK 0x000000E0
|
||||
enum {
|
||||
MAIN_STREAMX_MISC0_BDC_6BPC = 0x0,
|
||||
MAIN_STREAMX_MISC0_BDC_8BPC = 0x1,
|
||||
MAIN_STREAMX_MISC0_BDC_10BPC = 0x2,
|
||||
MAIN_STREAMX_MISC0_BDC_12BPC = 0x3,
|
||||
MAIN_STREAMX_MISC0_BDC_16BPC = 0x4,
|
||||
};
|
||||
|
||||
enum {
|
||||
PHY_CONFIG_PHY_RESET_ENABLE_MASK = 0x0000000,
|
||||
PHY_CONFIG_PHY_RESET_MASK = 0x0000001,
|
||||
PHY_CONFIG_GTTX_RESET_MASK = 0x0000002,
|
||||
PHY_CONFIG_GT_ALL_RESET_MASK = 0x0000003,
|
||||
PHY_CONFIG_TX_PHY_PMA_RESET_MASK = 0x0000100,
|
||||
PHY_CONFIG_TX_PHY_PCS_RESET_MASK = 0x0000200,
|
||||
PHY_CONFIG_TX_PHY_POLARITY_MASK = 0x0000800,
|
||||
PHY_CONFIG_TX_PHY_PRBSFORCEERR_MASK = 0x0001000,
|
||||
PHY_CONFIG_TX_PHY_POLARITY_IND_LANE_MASK = 0x0010000,
|
||||
PHY_CONFIG_TX_PHY_POLARITY_LANE0_MASK = 0x0020000,
|
||||
PHY_CONFIG_TX_PHY_POLARITY_LANE1_MASK = 0x0040000,
|
||||
PHY_CONFIG_TX_PHY_POLARITY_LANE2_MASK = 0x0080000,
|
||||
PHY_CONFIG_TX_PHY_POLARITY_LANE3_MASK = 0x0100000,
|
||||
PHY_CONFIG_TX_PHY_8B10BEN_MASK = 0x0200000,
|
||||
};
|
||||
|
||||
#define PHY_CONFIG_TX_PHY_LOOPBACK_SHIFT 13
|
||||
#define PHY_CONFIG_TX_PHY_LOOPBACK_MASK 0x000E000
|
||||
|
||||
enum {
|
||||
PHY_CLOCK_SELECT_162GBPS = 0x1,
|
||||
PHY_CLOCK_SELECT_270GBPS = 0x3,
|
||||
PHY_CLOCK_SELECT_540GBPS = 0x5,
|
||||
};
|
||||
|
||||
enum {
|
||||
VS_LEVEL_0 = 0x2,
|
||||
VS_LEVEL_1 = 0x5,
|
||||
VS_LEVEL_2 = 0x8,
|
||||
VS_LEVEL_3 = 0xF,
|
||||
VS_LEVEL_OFFSET = 0x4,
|
||||
};
|
||||
|
||||
enum {
|
||||
PE_LEVEL_0 = 0x00,
|
||||
PE_LEVEL_1 = 0x0E,
|
||||
PE_LEVEL_2 = 0x14,
|
||||
PE_LEVEL_3 = 0x1B,
|
||||
};
|
||||
|
||||
enum {
|
||||
PHY_STATUS_RESET_LANE_2_3_DONE_SHIFT = 2,
|
||||
PHY_STATUS_TX_ERROR_LANE_0_SHIFT = 18,
|
||||
PHY_STATUS_TX_BUFFER_STATUS_LANE_1_SHIFT = 20,
|
||||
PHY_STATUS_TX_ERROR_LANE_1_SHIFT = 22,
|
||||
PHY_STATUS_TX_BUFFER_STATUS_LANE_0_SHIFT = 16,
|
||||
PHY_STATUS_TX_BUFFER_STATUS_LANE_2_SHIFT = 24,
|
||||
PHY_STATUS_TX_ERROR_LANE_2_SHIFT = 26,
|
||||
PHY_STATUS_TX_BUFFER_STATUS_LANE_3_SHIFT = 28,
|
||||
PHY_STATUS_TX_ERROR_LANE_3_SHIFT = 30,
|
||||
};
|
||||
|
||||
enum {
|
||||
PHY_STATUS_RESET_LANE_0_DONE_MASK = 0x00000001,
|
||||
PHY_STATUS_RESET_LANE_1_DONE_MASK = 0x00000002,
|
||||
PHY_STATUS_RESET_LANE_2_3_DONE_MASK = 0x0000000C,
|
||||
PHY_STATUS_PLL_LANE0_1_LOCK_MASK = 0x00000010,
|
||||
PHY_STATUS_PLL_LANE2_3_LOCK_MASK = 0x00000020,
|
||||
PHY_STATUS_PLL_FABRIC_LOCK_MASK = 0x00000040,
|
||||
PHY_STATUS_TX_BUFFER_STATUS_LANE_0_MASK = 0x00030000,
|
||||
PHY_STATUS_TX_ERROR_LANE_0_MASK = 0x000C0000,
|
||||
PHY_STATUS_TX_BUFFER_STATUS_LANE_1_MASK = 0x00300000,
|
||||
PHY_STATUS_TX_ERROR_LANE_1_MASK = 0x00C00000,
|
||||
PHY_STATUS_TX_BUFFER_STATUS_LANE_2_MASK = 0x03000000,
|
||||
PHY_STATUS_TX_ERROR_LANE_2_MASK = 0x0C000000,
|
||||
PHY_STATUS_TX_BUFFER_STATUS_LANE_3_MASK = 0x30000000,
|
||||
PHY_STATUS_TX_ERROR_LANE_3_MASK = 0xC0000000,
|
||||
};
|
||||
|
||||
#define PHY_STATUS_LANE_0_READY_MASK \
|
||||
(PHY_STATUS_RESET_LANE_0_DONE_MASK | \
|
||||
PHY_STATUS_PLL_LANE0_1_LOCK_MASK)
|
||||
#define PHY_STATUS_LANES_0_1_READY_MASK \
|
||||
(PHY_STATUS_LANE_0_READY_MASK | \
|
||||
PHY_STATUS_RESET_LANE_1_DONE_MASK)
|
||||
/*
|
||||
* PHY_STATUS_ALL_LANES_READY_MASK seems to be missing lanes 0 and 1 in
|
||||
* Xilinx dp_v3_0 implementation
|
||||
*/
|
||||
#define PHY_STATUS_ALL_LANES_READY_MASK \
|
||||
(PHY_STATUS_LANES_0_1_READY_MASK | \
|
||||
PHY_STATUS_RESET_LANE_2_3_DONE_MASK | \
|
||||
PHY_STATUS_PLL_LANE2_3_LOCK_MASK)
|
||||
|
||||
/**
|
||||
* phy_status_lanes_ready_mask() - Generate phy status ready mask
|
||||
* @lane_count: Number of lanes for which to generate a mask
|
||||
*
|
||||
* Return: The generated phy status ready mask
|
||||
*/
|
||||
static inline u32 phy_status_lanes_ready_mask(u8 lane_count)
|
||||
{
|
||||
if (lane_count > 2)
|
||||
return PHY_STATUS_ALL_LANES_READY_MASK;
|
||||
|
||||
if (lane_count == 2)
|
||||
return PHY_STATUS_LANES_0_1_READY_MASK;
|
||||
|
||||
return PHY_STATUS_LANE_0_READY_MASK;
|
||||
}
|
||||
|
||||
#define GT_DRP_COMMAND_DRP_ADDR_MASK 0x000F
|
||||
#define GT_DRP_COMMAND_DRP_RW_CMD_MASK 0x0080
|
||||
#define GT_DRP_COMMAND_DRP_W_DATA_SHIFT 16
|
||||
#define GT_DRP_COMMAND_DRP_W_DATA_MASK 0xFF00
|
||||
|
||||
#define HDCP_ENABLE_BYPASS_DISABLE_MASK 0x0001
|
||||
|
||||
#endif /* __GDSYS_LOGICORE_DP_TX_REGIF_H__ */
|
118
include/axi.h
Normal file
118
include/axi.h
Normal file
@ -0,0 +1,118 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (C) Copyright 2017, 2018
|
||||
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
|
||||
*/
|
||||
|
||||
#ifndef _AXI_H_
|
||||
#define _AXI_H_
|
||||
|
||||
/**
|
||||
* enum axi_size_t - Determine size of AXI transfer
|
||||
* @AXI_SIZE_8: AXI sransfer is 8-bit wide
|
||||
* @AXI_SIZE_16: AXI sransfer is 16-bit wide
|
||||
* @AXI_SIZE_32: AXI sransfer is 32-bit wide
|
||||
*/
|
||||
enum axi_size_t {
|
||||
AXI_SIZE_8,
|
||||
AXI_SIZE_16,
|
||||
AXI_SIZE_32,
|
||||
};
|
||||
|
||||
struct axi_ops {
|
||||
/**
|
||||
* read() - Read a single value from a specified address on a AXI bus
|
||||
* @dev: AXI bus to read from.
|
||||
* @address: The address to read from.
|
||||
* @data: Pointer to a variable that takes the data value read
|
||||
* from the address on the AXI bus.
|
||||
* @size: The size of the data to be read.
|
||||
*
|
||||
* Return: 0 if OK, -ve on error.
|
||||
*/
|
||||
int (*read)(struct udevice *dev, ulong address, void *data,
|
||||
enum axi_size_t size);
|
||||
|
||||
/**
|
||||
* write() - Write a single value to a specified address on a AXI bus
|
||||
* @dev: AXI bus to write to.
|
||||
* @address: The address to write to.
|
||||
* @data: Pointer to the data value to be written to the address
|
||||
* on the AXI bus.
|
||||
* @size: The size of the data to write.
|
||||
*
|
||||
* Return 0 if OK, -ve on error.
|
||||
*/
|
||||
int (*write)(struct udevice *dev, ulong address, void *data,
|
||||
enum axi_size_t size);
|
||||
};
|
||||
|
||||
#define axi_get_ops(dev) ((struct axi_ops *)(dev)->driver->ops)
|
||||
|
||||
/**
|
||||
* axi_read() - Read a single value from a specified address on a AXI bus
|
||||
* @dev: AXI bus to read from.
|
||||
* @address: The address to read from.
|
||||
* @data: Pointer to a variable that takes the data value read from the
|
||||
* address on the AXI bus.
|
||||
* @size: The size of the data to write.
|
||||
*
|
||||
* Return: 0 if OK, -ve on error.
|
||||
*/
|
||||
int axi_read(struct udevice *dev, ulong address, void *data,
|
||||
enum axi_size_t size);
|
||||
|
||||
/**
|
||||
* axi_write() - Write a single value to a specified address on a AXI bus
|
||||
* @dev: AXI bus to write to.
|
||||
* @address: The address to write to.
|
||||
* @data: Pointer to the data value to be written to the address on the
|
||||
* AXI bus.
|
||||
* @size: The size of the data to write.
|
||||
*
|
||||
* Return: 0 if OK, -ve on error.
|
||||
*/
|
||||
int axi_write(struct udevice *dev, ulong address, void *data,
|
||||
enum axi_size_t size);
|
||||
|
||||
struct axi_emul_ops {
|
||||
/**
|
||||
* read() - Read a single value from a specified address on a AXI bus
|
||||
* @dev: AXI bus to read from.
|
||||
* @address: The address to read from.
|
||||
* @data: Pointer to a variable that takes the data value read
|
||||
* from the address on the AXI bus.
|
||||
* @size: The size of the data to be read.
|
||||
*
|
||||
* Return: 0 if OK, -ve on error.
|
||||
*/
|
||||
int (*read)(struct udevice *dev, ulong address, void *data,
|
||||
enum axi_size_t size);
|
||||
|
||||
/**
|
||||
* write() - Write a single value to a specified address on a AXI bus
|
||||
* @dev: AXI bus to write to.
|
||||
* @address: The address to write to.
|
||||
* @data: Pointer to the data value to be written to the address
|
||||
* on the AXI bus.
|
||||
* @size: The size of the data to write.
|
||||
*
|
||||
* Return: 0 if OK, -ve on error.
|
||||
*/
|
||||
int (*write)(struct udevice *dev, ulong address, void *data,
|
||||
enum axi_size_t size);
|
||||
|
||||
/**
|
||||
* get_store() - Get address of internal storage of a emulated AXI
|
||||
* device
|
||||
* @dev: Emulated AXI device to get the pointer of the internal
|
||||
* storage for.
|
||||
* @storep: Pointer to the internal storage of the emulated AXI
|
||||
* device.
|
||||
*
|
||||
* Return: 0 if OK, -ve on error.
|
||||
*/
|
||||
int (*get_store)(struct udevice *dev, u8 **storep);
|
||||
};
|
||||
|
||||
#endif
|
@ -23,6 +23,7 @@ enum uclass_id {
|
||||
UCLASS_I2C_EMUL, /* sandbox I2C device emulator */
|
||||
UCLASS_PCI_EMUL, /* sandbox PCI device emulator */
|
||||
UCLASS_USB_EMUL, /* sandbox USB bus device emulator */
|
||||
UCLASS_AXI_EMUL, /* sandbox AXI bus device emulator */
|
||||
UCLASS_SIMPLE_BUS, /* bus with child devices */
|
||||
|
||||
/* U-Boot uclasses start here - in alphabetical order */
|
||||
@ -43,6 +44,7 @@ enum uclass_id {
|
||||
UCLASS_I2C_GENERIC, /* Generic I2C device */
|
||||
UCLASS_I2C_MUX, /* I2C multiplexer */
|
||||
UCLASS_IDE, /* IDE device */
|
||||
UCLASS_AXI, /* AXI bus */
|
||||
UCLASS_IRQ, /* Interrupt controller */
|
||||
UCLASS_KEYBOARD, /* Keyboard input device */
|
||||
UCLASS_LED, /* Light-emitting diode (LED) */
|
||||
|
@ -44,4 +44,5 @@ obj-$(CONFIG_DM_VIDEO) += video.o
|
||||
obj-$(CONFIG_ADC) += adc.o
|
||||
obj-$(CONFIG_SPMI) += spmi.o
|
||||
obj-$(CONFIG_WDT) += wdt.o
|
||||
obj-$(CONFIG_AXI) += axi.o
|
||||
endif
|
||||
|
77
test/dm/axi.c
Normal file
77
test/dm/axi.c
Normal file
@ -0,0 +1,77 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2018
|
||||
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <axi.h>
|
||||
#include <dm.h>
|
||||
#include <dm/test.h>
|
||||
#include <test/ut.h>
|
||||
#include <asm/axi.h>
|
||||
|
||||
/* Test that sandbox AXI works correctly */
|
||||
static int dm_test_axi_base(struct unit_test_state *uts)
|
||||
{
|
||||
struct udevice *bus;
|
||||
|
||||
ut_assertok(uclass_get_device(UCLASS_AXI, 0, &bus));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DM_TEST(dm_test_axi_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
|
||||
|
||||
/* Test that sandbox PCI bus numbering works correctly */
|
||||
static int dm_test_axi_busnum(struct unit_test_state *uts)
|
||||
{
|
||||
struct udevice *bus;
|
||||
|
||||
ut_assertok(uclass_get_device_by_seq(UCLASS_AXI, 0, &bus));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DM_TEST(dm_test_axi_busnum, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
|
||||
|
||||
/* Test that we can use the store device correctly */
|
||||
static int dm_test_axi_store(struct unit_test_state *uts)
|
||||
{
|
||||
struct udevice *store;
|
||||
u8 tdata1[] = {0x55, 0x66, 0x77, 0x88};
|
||||
u8 tdata2[] = {0xaa, 0xbb, 0xcc, 0xdd};
|
||||
u32 val;
|
||||
u8 *data;
|
||||
|
||||
/* Check that asking for the device automatically fires up AXI */
|
||||
ut_assertok(uclass_get_device(UCLASS_AXI_EMUL, 0, &store));
|
||||
ut_assert(device_active(store));
|
||||
|
||||
axi_get_store(store, &data);
|
||||
|
||||
/* Test reading */
|
||||
memcpy(data, tdata1, ARRAY_SIZE(tdata1));
|
||||
axi_read(store, 0, &val, AXI_SIZE_32);
|
||||
ut_asserteq(0x55667788, val);
|
||||
|
||||
memcpy(data + 3, tdata2, ARRAY_SIZE(tdata2));
|
||||
axi_read(store, 3, &val, AXI_SIZE_32);
|
||||
ut_asserteq(0xaabbccdd, val);
|
||||
|
||||
/* Reset data store */
|
||||
memset(data, 0, 16);
|
||||
|
||||
/* Test writing */
|
||||
val = 0x55667788;
|
||||
axi_write(store, 0, &val, AXI_SIZE_32);
|
||||
ut_asserteq(0, memcmp(data, tdata1, ARRAY_SIZE(tdata1)));
|
||||
|
||||
val = 0xaabbccdd;
|
||||
axi_write(store, 3, &val, AXI_SIZE_32);
|
||||
ut_asserteq(0, memcmp(data + 3, tdata2, ARRAY_SIZE(tdata1)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DM_TEST(dm_test_axi_store, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
|
Loading…
Reference in New Issue
Block a user