Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
U-Boot
U-Boot
Commits
282ce645
Commit
282ce645
authored
Aug 11, 2018
by
Tom Rini
Browse files
Merge branch 'master' of
git://git.denx.de/u-boot-video
parents
a032e0a6
25a9f974
Changes
27
Hide whitespace changes
Inline
Side-by-side
Documentation/devicetree/bindings/axi/gdsys,ihs_axi.txt
0 → 100644
View file @
282ce645
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 {
...
};
};
arch/sandbox/dts/sandbox.dts
View file @
282ce645
...
...
@@ -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"
...
...
arch/sandbox/dts/test.dts
View file @
282ce645
...
...
@@ -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
>;
...
...
arch/sandbox/include/asm/axi.h
0 → 100644
View file @
282ce645
/* 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 */
cmd/Kconfig
View file @
282ce645
...
...
@@ -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
...
...
cmd/Makefile
View file @
282ce645
...
...
@@ -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
...
...
cmd/axi.c
0 → 100644
View file @
282ce645
// 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
);
configs/sandbox_defconfig
View file @
282ce645
...
...
@@ -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
...
...
drivers/Kconfig
View file @
282ce645
...
...
@@ -8,6 +8,8 @@ source "drivers/adc/Kconfig"
source "drivers/ata/Kconfig"
source "drivers/axi/Kconfig"
source "drivers/block/Kconfig"
source "drivers/bootcount/Kconfig"
...
...
drivers/Makefile
View file @
282ce645
...
...
@@ -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
drivers/axi/Kconfig
0 → 100644
View file @
282ce645
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
drivers/axi/Makefile
0 → 100644
View file @
282ce645
#
# (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
drivers/axi/axi-emul-uclass.c
0 → 100644
View file @
282ce645
// 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