Xilinx changes for v2022.10

cpu:
 - Add driver for microblaze cpu
 
 net:
 - Add support for DM_ETH_PHY to AXI emac and emaclite
 
 xilinx:
 - Switch platforms to DM_ETH_PHY
 - DT chagnes in ZynqMP and Zynq
 - Enable support for SquashFS
 
 zynqmp:
 - Add support for KR260 boards
 - Move BSS from address 0
 - Move platform identification from board code to soc driver
 - Improve zynqmp_psu_init_minimize
 
 versal:
 - Enable loading app at EL1
 
 serial:
 - Setup default address and clock rates for DEBUG uarts
 
 pinctrl:
 - Add support for tri state and output enable properties
 
 relocate-rela:
 - Clean relocate-rela implementation for ARM64
 - Add support for Microblaze
 
 microblaze:
 - Add support for runtime relocation
 - Rework cache handling (wiring, Kconfig) based on cpuinfo
 - Remove interrupt support
 
 timer:
 - Extract axi timer driver from Microblaze to generic location
 -----BEGIN PGP SIGNATURE-----
 
 iF0EABECAB0WIQQbPNTMvXmYlBPRwx7KSWXLKUoMIQUCYrlYngAKCRDKSWXLKUoM
 ITgbAJ9S9xO2QqxtuodWAYMtJfvZ14c7mgCeKnyFTrrBnJkC0wPsGqE71oNJ49o=
 =3gGm
 -----END PGP SIGNATURE-----

Merge tag 'xilinx-for-v2022.10' of https://source.denx.de/u-boot/custodians/u-boot-microblaze into next

Xilinx changes for v2022.10

cpu:
- Add driver for microblaze cpu

net:
- Add support for DM_ETH_PHY to AXI emac and emaclite

xilinx:
- Switch platforms to DM_ETH_PHY
- DT chagnes in ZynqMP and Zynq
- Enable support for SquashFS

zynqmp:
- Add support for KR260 boards
- Move BSS from address 0
- Move platform identification from board code to soc driver
- Improve zynqmp_psu_init_minimize

versal:
- Enable loading app at EL1

serial:
- Setup default address and clock rates for DEBUG uarts

pinctrl:
- Add support for tri state and output enable properties

relocate-rela:
- Clean relocate-rela implementation for ARM64
- Add support for Microblaze

microblaze:
- Add support for runtime relocation
- Rework cache handling (wiring, Kconfig) based on cpuinfo
- Remove interrupt support

timer:
- Extract axi timer driver from Microblaze to generic location
This commit is contained in:
Tom Rini 2022-06-27 10:15:50 -04:00
commit c316ee674f
76 changed files with 5312 additions and 3332 deletions

View File

@ -1004,6 +1004,7 @@ F: drivers/net/xilinx_emaclite.c
F: drivers/serial/serial_xuartlite.c
F: drivers/spi/xilinx_spi.c
F: drivers/sysreset/sysreset_gpio.c
F: drivers/timer/xilinx-timer.c
F: drivers/watchdog/xilinx_tb_wdt.c
N: xilinx

View File

@ -922,12 +922,10 @@ endif
# the raw binary, but certain simulators only accept an ELF file (but don't
# do the relocation).
ifneq ($(CONFIG_STATIC_RELA),)
# $(1) is u-boot ELF, $(2) is u-boot bin, $(3) is text base
# $(2) is u-boot ELF, $(3) is u-boot bin, $(4) is text base
quiet_cmd_static_rela = RELOC $@
cmd_static_rela = \
start=$$($(NM) $(2) | grep __rel_dyn_start | cut -f 1 -d ' '); \
end=$$($(NM) $(2) | grep __rel_dyn_end | cut -f 1 -d ' '); \
tools/relocate-rela $(3) $(4) $$start $$end
tools/relocate-rela $(3) $(2)
else
quiet_cmd_static_rela =
cmd_static_rela =

View File

@ -8,9 +8,6 @@ config CREATE_ARCH_SYMLINK
config HAVE_ARCH_IOREMAP
bool
config NEEDS_MANUAL_RELOC
bool
config SYS_CACHE_SHIFT_4
bool
@ -76,9 +73,12 @@ config M68K
config MICROBLAZE
bool "MicroBlaze architecture"
select NEEDS_MANUAL_RELOC
select SUPPORT_OF_CONTROL
imply CMD_IRQ
imply CMD_TIMER
imply SPL_REGMAP if SPL
imply SPL_TIMER if SPL
imply TIMER
imply XILINX_TIMER
config MIPS
bool "MIPS architecture"
@ -452,3 +452,25 @@ source "arch/xtensa/Kconfig"
source "arch/riscv/Kconfig"
source "board/keymile/Kconfig"
if MIPS || MICROBLAZE
choice
prompt "Endianness selection"
help
Some MIPS boards can be configured for either little or big endian
byte order. These modes require different U-Boot images. In general there
is one preferred byteorder for a particular system but some systems are
just as commonly used in the one or the other endianness.
config SYS_BIG_ENDIAN
bool "Big endian"
depends on (SUPPORTS_BIG_ENDIAN && MIPS) || MICROBLAZE
config SYS_LITTLE_ENDIAN
bool "Little endian"
depends on (SUPPORTS_LITTLE_ENDIAN && MIPS) || MICROBLAZE
endchoice
endif

View File

@ -342,6 +342,8 @@ dtb-$(CONFIG_ARCH_ZYNQMP) += \
zynqmp-mini-qspi.dtb \
zynqmp-sm-k26-revA.dtb \
zynqmp-smk-k26-revA.dtb \
zynqmp-sck-kr-g-revA.dtbo \
zynqmp-sck-kr-g-revB.dtbo \
zynqmp-sck-kv-g-revA.dtbo \
zynqmp-sck-kv-g-revB.dtbo \
zynqmp-topic-miamimp-xilinx-xdp-v1r1.dtb \

View File

@ -287,7 +287,7 @@
reg = <0 0 0x1000000>;
status = "disabled";
#address-cells = <1>;
#size-cells = <1>;
#size-cells = <0>;
};
nor0: flash@1,0 {
status = "disabled";

View File

@ -294,10 +294,10 @@
#address-cells = <1>;
#size-cells = <0>;
reg = <2>;
clock_8t49n287: clock-generator@d8 { /* u39 8T49N240 */
clock_8t49n287: clock-generator@6c { /* u39 8T49N240 */
#clock-cells = <1>; /* author David Cater <david.cater@idt.com>*/
compatible = "idt,8t49n240", "idt,8t49n241"; /* FIXME no driver for 240 */
reg = <0xd8>;
reg = <0x6c>;
/* Documentation/devicetree/bindings/clock/idt,idt8t49n24x.txt */
/* FIXME there input via J241 Samtec CLK1 and CLK0 from U38 - selection PIN */
};
@ -447,7 +447,7 @@
si570_user1: clock-generator@5d { /* u205 */
#clock-cells = <0>;
compatible = "silabs,si570";
reg = <0x5f>;
reg = <0x5d>;
temperature-stability = <50>;
factory-fout = <100000000>;
clock-frequency = <100000000>;

View File

@ -260,9 +260,9 @@
reg = <0x45>;
shunt-resistor = <5000>;
};
tps53681@c0 { /* u53 - FIXME name - don't know what it does - also vcc_io_soc */
tps53681@60 { /* u53 - 0xc0 - FIXME name - don't know what it does - also vcc_io_soc */
compatible = "ti,tps53681", "ti,tps53679";
reg = <0xc0>;
reg = <0x60>;
};
};
i2c@3 { /* fmc1 via JA2G */

View File

@ -247,9 +247,9 @@
#address-cells = <1>;
#size-cells = <0>;
reg = <2>;
reg_vccint: tps53681@c0 { /* u69 */
reg_vccint: tps53681@60 { /* u69 - 0xc0 */
compatible = "ti,tps53681", "ti,tps53679";
reg = <0xc0>;
reg = <0x60>;
};
reg_vcc_pmc: tps544@7 { /* u80 */
compatible = "ti,tps544b25";

View File

@ -190,10 +190,6 @@
compatible = "ti,tps544b25";
reg = <0x1e>;
};
reg_vpp_2v5_ddr4: tps544@1x { /* u3007 */
compatible = "ti,tps544b25";
reg = <0x17>; /* FIXME wrong in schematics */
};
};
i2c@1 { /* PMBUS_INA226 */
#address-cells = <1>;
@ -239,9 +235,9 @@
#address-cells = <1>;
#size-cells = <0>;
reg = <2>;
reg_vccint: tps53681@c0 { /* u69 */
reg_vccint: tps53681@60 { /* u69 - 0xc0 */
compatible = "ti,tps53681", "ti,tps53679";
reg = <0xc0>;
reg = <0x60>;
};
reg_vcc_pmc: tps544@7 { /* u80 */
compatible = "ti,tps544b25";

View File

@ -190,9 +190,9 @@
compatible = "ti,tps544b25";
reg = <0x1e>;
};
reg_vpp_2v5_ddr4: tps544@1x { /* u3007 */
reg_vcc1v2_ddr4: tps544@18 { /* u3022 */
compatible = "ti,tps544b25";
reg = <0x17>; /* FIXME wrong in schematics */
reg = <0x18>;
};
};
i2c@1 { /* PMBUS_INA226 */
@ -239,9 +239,9 @@
#address-cells = <1>;
#size-cells = <0>;
reg = <2>;
reg_vccint: tps53681@c0 { /* u69 */
reg_vccint: tps53681@60 { /* u69 - 0xc0 */
compatible = "ti,tps53681", "ti,tps53679";
reg = <0xc0>;
reg = <0x60>;
};
reg_vcc_pmc: tps544@7 { /* u80 */
compatible = "ti,tps544b25";

View File

@ -0,0 +1,388 @@
// SPDX-License-Identifier: GPL-2.0
/*
* dts file for KR260 revA Carrier Card
*
* (C) Copyright 2021, Xilinx, Inc.
*
* Michal Simek <michal.simek@xilinx.com>
*/
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/net/ti-dp83867.h>
#include <dt-bindings/phy/phy.h>
#include <dt-bindings/pinctrl/pinctrl-zynqmp.h>
/dts-v1/;
/plugin/;
&{/} {
compatible = "xlnx,zynqmp-sk-kr260-revA",
"xlnx,zynqmp-sk-kr260", "xlnx,zynqmp";
ina260-u14 {
compatible = "iio-hwmon";
io-channels = <&u14 0>, <&u14 1>, <&u14 2>;
};
si5332_0: si5332_0 { /* u17 - GEM0/1 */
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <125000000>;
};
si5332_1: si5332_1 { /* u17 - DP */
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <27000000>;
};
si5332_2: si5332_2 { /* u17 - USB */
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <26000000>;
};
si5332_3: si5332_3 { /* u17 - SFP+ */
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <156250000>;
};
si5332_4: si5332_4 { /* u17 - GEM2 */
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <25000000>;
};
si5332_5: si5332_5 { /* u17 - GEM3 */
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <25000000>;
};
};
&i2c1 { /* I2C_SCK C26/C27 - MIO from SOM */
#address-cells = <1>;
#size-cells = <0>;
pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c1_default>;
pinctrl-1 = <&pinctrl_i2c1_gpio>;
scl-gpios = <&gpio 24 GPIO_ACTIVE_HIGH>;
sda-gpios = <&gpio 25 GPIO_ACTIVE_HIGH>;
u14: ina260@40 { /* u14 */
compatible = "ti,ina260";
#io-channel-cells = <1>;
label = "ina260-u14";
reg = <0x40>;
};
slg7xl45106: gpio@11 { /* u19 - reset logic */
compatible = "dlg,slg7xl45106";
reg = <0x11>;
label = "resetchip";
gpio-controller;
#gpio-cells = <2>;
gpio-line-names = "USB0_PHY_RESET_B", "USB1_PHY_RESET_B",
"SD_RESET_B", "USB0_HUB_RESET_B",
"USB1_HUB_RESET_B", "PS_GEM0_RESET_B",
"PS_GEM1_RESET_B", "";
};
i2c-mux@74 { /* u18 */
compatible = "nxp,pca9546";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x74>;
usbhub_i2c0: i2c@0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
};
usbhub_i2c1: i2c@1 {
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;
};
/* Bus 2/3 are not connected */
};
/* si5332@6a - u17 - clock-generator */
};
/* GEM SGMII/DP and USB 3.0 */
&psgtr {
status = "okay";
/* gem0/1, dp, usb */
clocks = <&si5332_0>, <&si5332_1>, <&si5332_2>;
clock-names = "ref0", "ref1", "ref2";
};
&zynqmp_dpsub {
status = "okay";
phy-names = "dp-phy0";
phys = <&psgtr 1 PHY_TYPE_DP 0 1>;
assigned-clock-rates = <27000000>, <25000000>, <300000000>;
};
&zynqmp_dpdma {
status = "okay";
assigned-clock-rates = <600000000>;
};
&usb0 { /* mio52 - mio63 */
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usb0_default>;
phy-names = "usb3-phy";
phys = <&psgtr 2 PHY_TYPE_USB3 0 2>;
reset-gpios = <&slg7xl45106 0 GPIO_ACTIVE_LOW>;
assigned-clock-rates = <250000000>, <20000000>;
usbhub0: usb-hub { /* u43 */
i2c-bus = <&usbhub_i2c0>;
compatible = "microchip,usb5744";
reset-gpios = <&slg7xl45106 3 GPIO_ACTIVE_LOW>;
};
usb2244: usb-sd { /* u38 */
compatible = "microchip,usb2244";
reset-gpios = <&slg7xl45106 2 GPIO_ACTIVE_LOW>;
};
};
&dwc3_0 {
status = "okay";
dr_mode = "host";
snps,usb3_lpm_capable;
maximum-speed = "super-speed";
};
&usb1 { /* mio64 - mio75 */
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usb1_default>;
phy-names = "usb3-phy";
phys = <&psgtr 3 PHY_TYPE_USB3 1 2>;
reset-gpios = <&slg7xl45106 1 GPIO_ACTIVE_LOW>;
assigned-clock-rates = <250000000>, <20000000>;
usbhub1: usb-hub { /* u84 */
i2c-bus = <&usbhub_i2c1>;
compatible = "microchip,usb5744";
reset-gpios = <&slg7xl45106 4 GPIO_ACTIVE_LOW>;
};
};
&dwc3_1 {
status = "okay";
dr_mode = "host";
snps,usb3_lpm_capable;
maximum-speed = "super-speed";
};
&gem0 { /* mdio mio50/51 */
status = "okay";
phys = <&psgtr 0 PHY_TYPE_SGMII 0 0>;
phy-handle = <&phy0>;
phy-mode = "sgmii";
is-internal-pcspma;
};
&gem1 { /* mdio mio50/51, gem mio38 - mio49 */
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gem1_default>;
phy-handle = <&phy1>;
phy-mode = "rgmii-id";
mdio: mdio {
#address-cells = <1>;
#size-cells = <0>;
phy0: ethernet-phy@4 { /* u81 */
#phy-cells = <1>;
compatible = "ethernet-phy-id2000.a231";
reg = <4>;
ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_75_NS>;
ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
ti,dp83867-rxctrl-strap-quirk;
reset-assert-us = <100>;
reset-deassert-us = <280>;
reset-gpios = <&slg7xl45106 5 GPIO_ACTIVE_LOW>;
};
phy1: ethernet-phy@8 { /* u36 */
#phy-cells = <1>;
compatible = "ethernet-phy-id2000.a231";
reg = <8>;
ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_75_NS>;
ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
ti,dp83867-rxctrl-strap-quirk;
reset-assert-us = <100>;
reset-deassert-us = <280>;
reset-gpios = <&slg7xl45106 6 GPIO_ACTIVE_LOW>;
};
};
};
/* gem2/gem3 via PL with phys u79@2 and u80@3 */
&pinctrl0 { /* required by spec */
status = "okay";
pinctrl_uart1_default: uart1-default {
conf {
groups = "uart1_9_grp";
slew-rate = <SLEW_RATE_SLOW>;
power-source = <IO_STANDARD_LVCMOS18>;
drive-strength = <12>;
};
conf-rx {
pins = "MIO37";
bias-high-impedance;
};
conf-tx {
pins = "MIO36";
bias-disable;
};
mux {
groups = "uart1_9_grp";
function = "uart1";
};
};
pinctrl_i2c1_default: i2c1-default {
conf {
groups = "i2c1_6_grp";
bias-pull-up;
slew-rate = <SLEW_RATE_SLOW>;
power-source = <IO_STANDARD_LVCMOS18>;
};
mux {
groups = "i2c1_6_grp";
function = "i2c1";
};
};
pinctrl_i2c1_gpio: i2c1-gpio {
conf {
groups = "gpio0_24_grp", "gpio0_25_grp";
slew-rate = <SLEW_RATE_SLOW>;
power-source = <IO_STANDARD_LVCMOS18>;
};
mux {
groups = "gpio0_24_grp", "gpio0_25_grp";
function = "gpio0";
};
};
pinctrl_gem1_default: gem1-default {
conf {
groups = "ethernet1_0_grp";
slew-rate = <SLEW_RATE_SLOW>;
power-source = <IO_STANDARD_LVCMOS18>;
};
conf-rx {
pins = "MIO44", "MIO46", "MIO48";
bias-high-impedance;
low-power-disable;
};
conf-bootstrap {
pins = "MIO45", "MIO47", "MIO49";
bias-disable;
low-power-disable;
};
conf-tx {
pins = "MIO38", "MIO39", "MIO40",
"MIO41", "MIO42", "MIO43";
bias-disable;
low-power-enable;
};
conf-mdio {
groups = "mdio1_0_grp";
slew-rate = <SLEW_RATE_SLOW>;
power-source = <IO_STANDARD_LVCMOS18>;
bias-disable;
};
mux-mdio {
function = "mdio1";
groups = "mdio1_0_grp";
};
mux {
function = "ethernet1";
groups = "ethernet1_0_grp";
};
};
pinctrl_usb0_default: usb0-default {
conf {
groups = "usb0_0_grp";
power-source = <IO_STANDARD_LVCMOS18>;
};
conf-rx {
pins = "MIO52", "MIO53", "MIO55";
bias-high-impedance;
drive-strength = <12>;
slew-rate = <SLEW_RATE_FAST>;
};
conf-tx {
pins = "MIO54", "MIO56", "MIO57", "MIO58", "MIO59",
"MIO60", "MIO61", "MIO62", "MIO63";
bias-disable;
drive-strength = <4>;
slew-rate = <SLEW_RATE_SLOW>;
};
mux {
groups = "usb0_0_grp";
function = "usb0";
};
};
pinctrl_usb1_default: usb1-default {
conf {
groups = "usb1_0_grp";
power-source = <IO_STANDARD_LVCMOS18>;
};
conf-rx {
pins = "MIO64", "MIO65", "MIO67";
bias-high-impedance;
drive-strength = <12>;
slew-rate = <SLEW_RATE_FAST>;
};
conf-tx {
pins = "MIO66", "MIO68", "MIO69", "MIO70", "MIO71",
"MIO72", "MIO73", "MIO74", "MIO75";
bias-disable;
drive-strength = <4>;
slew-rate = <SLEW_RATE_SLOW>;
};
mux {
groups = "usb1_0_grp";
function = "usb1";
};
};
};
&uart1 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1_default>;
};

View File

@ -0,0 +1,388 @@
// SPDX-License-Identifier: GPL-2.0
/*
* dts file for KR260 revB Carrier Card (A03 revision)
*
* (C) Copyright 2021 - 2022, Xilinx, Inc.
*
* Michal Simek <michal.simek@xilinx.com>
*/
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/net/ti-dp83867.h>
#include <dt-bindings/phy/phy.h>
#include <dt-bindings/pinctrl/pinctrl-zynqmp.h>
/dts-v1/;
/plugin/;
&{/} {
compatible = "xlnx,zynqmp-sk-kr260-revB",
"xlnx,zynqmp-sk-kr260", "xlnx,zynqmp";
ina260-u14 {
compatible = "iio-hwmon";
io-channels = <&u14 0>, <&u14 1>, <&u14 2>;
};
clk_125: clock0 { /* u87 - GEM0/1 */
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <125000000>;
};
clk_27: clock1 { /* u86 - DP */
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <27000000>;
};
clk_26: clock2 { /* u89 - USB */
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <26000000>;
};
clk_156: clock3 { /* u90 - SFP+ */
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <156250000>;
};
clk_25_0: clock4 { /* u92/u91 - GEM2 */
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <25000000>;
};
clk_25_1: clock5 { /* u92/u91 - GEM3 */
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <25000000>;
};
};
&i2c1 { /* I2C_SCK C26/C27 - MIO from SOM */
#address-cells = <1>;
#size-cells = <0>;
pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c1_default>;
pinctrl-1 = <&pinctrl_i2c1_gpio>;
scl-gpios = <&gpio 24 GPIO_ACTIVE_HIGH>;
sda-gpios = <&gpio 25 GPIO_ACTIVE_HIGH>;
u14: ina260@40 { /* u14 */
compatible = "ti,ina260";
#io-channel-cells = <1>;
label = "ina260-u14";
reg = <0x40>;
};
slg7xl45106: gpio@11 { /* u19 - reset logic */
compatible = "dlg,slg7xl45106";
reg = <0x11>;
label = "resetchip";
gpio-controller;
#gpio-cells = <2>;
gpio-line-names = "USB0_PHY_RESET_B", "USB1_PHY_RESET_B",
"SD_RESET_B", "USB0_HUB_RESET_B",
"USB1_HUB_RESET_B", "PS_GEM0_RESET_B",
"PS_GEM1_RESET_B", "";
};
i2c-mux@74 { /* u18 */
compatible = "nxp,pca9546";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x74>;
usbhub_i2c0: i2c@0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
};
usbhub_i2c1: i2c@1 {
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;
};
/* Bus 2/3 are not connected */
};
/* si5332@6a - u17 - clock-generator */
};
/* GEM SGMII/DP and USB 3.0 */
&psgtr {
status = "okay";
/* gem0/1, dp, usb */
clocks = <&clk_125>, <&clk_27>, <&clk_26>;
clock-names = "ref0", "ref1", "ref2";
};
&zynqmp_dpsub {
status = "okay";
phy-names = "dp-phy0";
phys = <&psgtr 1 PHY_TYPE_DP 0 1>;
assigned-clock-rates = <27000000>, <25000000>, <300000000>;
};
&zynqmp_dpdma {
status = "okay";
assigned-clock-rates = <600000000>;
};
&usb0 { /* mio52 - mio63 */
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usb0_default>;
phy-names = "usb3-phy";
phys = <&psgtr 2 PHY_TYPE_USB3 0 2>;
reset-gpios = <&slg7xl45106 0 GPIO_ACTIVE_LOW>;
assigned-clock-rates = <250000000>, <20000000>;
usbhub0: usb-hub { /* u43 */
i2c-bus = <&usbhub_i2c0>;
compatible = "microchip,usb5744";
reset-gpios = <&slg7xl45106 3 GPIO_ACTIVE_LOW>;
};
usb2244: usb-sd { /* u38 */
compatible = "microchip,usb2244";
reset-gpios = <&slg7xl45106 2 GPIO_ACTIVE_LOW>;
};
};
&dwc3_0 {
status = "okay";
dr_mode = "host";
snps,usb3_lpm_capable;
maximum-speed = "super-speed";
};
&usb1 { /* mio64 - mio75 */
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usb1_default>;
phy-names = "usb3-phy";
phys = <&psgtr 3 PHY_TYPE_USB3 1 2>;
reset-gpios = <&slg7xl45106 1 GPIO_ACTIVE_LOW>;
assigned-clock-rates = <250000000>, <20000000>;
usbhub1: usb-hub { /* u84 */
i2c-bus = <&usbhub_i2c1>;
compatible = "microchip,usb5744";
reset-gpios = <&slg7xl45106 4 GPIO_ACTIVE_LOW>;
};
};
&dwc3_1 {
status = "okay";
dr_mode = "host";
snps,usb3_lpm_capable;
maximum-speed = "super-speed";
};
&gem0 { /* mdio mio50/51 */
status = "okay";
phys = <&psgtr 0 PHY_TYPE_SGMII 0 0>;
phy-handle = <&phy0>;
phy-mode = "sgmii";
is-internal-pcspma;
};
&gem1 { /* mdio mio50/51, gem mio38 - mio49 */
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gem1_default>;
phy-handle = <&phy1>;
phy-mode = "rgmii-id";
mdio: mdio {
#address-cells = <1>;
#size-cells = <0>;
phy0: ethernet-phy@4 { /* u81 */
#phy-cells = <1>;
compatible = "ethernet-phy-id2000.a231";
reg = <4>;
ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_75_NS>;
ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
ti,dp83867-rxctrl-strap-quirk;
reset-assert-us = <100>;
reset-deassert-us = <280>;
reset-gpios = <&slg7xl45106 5 GPIO_ACTIVE_LOW>;
};
phy1: ethernet-phy@8 { /* u36 */
#phy-cells = <1>;
compatible = "ethernet-phy-id2000.a231";
reg = <8>;
ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_75_NS>;
ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
ti,dp83867-rxctrl-strap-quirk;
reset-assert-us = <100>;
reset-deassert-us = <280>;
reset-gpios = <&slg7xl45106 6 GPIO_ACTIVE_LOW>;
};
};
};
/* gem2/gem3 via PL with phys u79@2 and u80@3 */
&pinctrl0 { /* required by spec */
status = "okay";
pinctrl_uart1_default: uart1-default {
conf {
groups = "uart1_9_grp";
slew-rate = <SLEW_RATE_SLOW>;
power-source = <IO_STANDARD_LVCMOS18>;
drive-strength = <12>;
};
conf-rx {
pins = "MIO37";
bias-high-impedance;
};
conf-tx {
pins = "MIO36";
bias-disable;
};
mux {
groups = "uart1_9_grp";
function = "uart1";
};
};
pinctrl_i2c1_default: i2c1-default {
conf {
groups = "i2c1_6_grp";
bias-pull-up;
slew-rate = <SLEW_RATE_SLOW>;
power-source = <IO_STANDARD_LVCMOS18>;
};
mux {
groups = "i2c1_6_grp";
function = "i2c1";
};
};
pinctrl_i2c1_gpio: i2c1-gpio {
conf {
groups = "gpio0_24_grp", "gpio0_25_grp";
slew-rate = <SLEW_RATE_SLOW>;
power-source = <IO_STANDARD_LVCMOS18>;
};
mux {
groups = "gpio0_24_grp", "gpio0_25_grp";
function = "gpio0";
};
};
pinctrl_gem1_default: gem1-default {
conf {
groups = "ethernet1_0_grp";
slew-rate = <SLEW_RATE_SLOW>;
power-source = <IO_STANDARD_LVCMOS18>;
};
conf-rx {
pins = "MIO44", "MIO46", "MIO48";
bias-high-impedance;
low-power-disable;
};
conf-bootstrap {
pins = "MIO45", "MIO47", "MIO49";
bias-disable;
low-power-disable;
};
conf-tx {
pins = "MIO38", "MIO39", "MIO40",
"MIO41", "MIO42", "MIO43";
bias-disable;
low-power-enable;
};
conf-mdio {
groups = "mdio1_0_grp";
slew-rate = <SLEW_RATE_SLOW>;
power-source = <IO_STANDARD_LVCMOS18>;
bias-disable;
};
mux-mdio {
function = "mdio1";
groups = "mdio1_0_grp";
};
mux {
function = "ethernet1";
groups = "ethernet1_0_grp";
};
};
pinctrl_usb0_default: usb0-default {
conf {
groups = "usb0_0_grp";
power-source = <IO_STANDARD_LVCMOS18>;
};
conf-rx {
pins = "MIO52", "MIO53", "MIO55";
bias-high-impedance;
drive-strength = <12>;
slew-rate = <SLEW_RATE_FAST>;
};
conf-tx {
pins = "MIO54", "MIO56", "MIO57", "MIO58", "MIO59",
"MIO60", "MIO61", "MIO62", "MIO63";
bias-disable;
drive-strength = <4>;
slew-rate = <SLEW_RATE_SLOW>;
};
mux {
groups = "usb0_0_grp";
function = "usb0";
};
};
pinctrl_usb1_default: usb1-default {
conf {
groups = "usb1_0_grp";
power-source = <IO_STANDARD_LVCMOS18>;
};
conf-rx {
pins = "MIO64", "MIO65", "MIO67";
bias-high-impedance;
drive-strength = <12>;
slew-rate = <SLEW_RATE_FAST>;
};
conf-tx {
pins = "MIO66", "MIO68", "MIO69", "MIO70", "MIO71",
"MIO72", "MIO73", "MIO74", "MIO75";
bias-disable;
drive-strength = <4>;
slew-rate = <SLEW_RATE_SLOW>;
};
mux {
groups = "usb1_0_grp";
function = "usb1";
};
};
};
&uart1 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1_default>;
};

View File

@ -112,7 +112,7 @@
};
&zynqmp_dpsub {
status = "disabled";
status = "okay";
phy-names = "dp-phy0", "dp-phy1";
phys = <&psgtr 1 PHY_TYPE_DP 0 0>, <&psgtr 0 PHY_TYPE_DP 1 0>;
assigned-clock-rates = <27000000>, <25000000>, <300000000>;
@ -285,19 +285,22 @@
pinctrl_usb0_default: usb0-default {
conf {
groups = "usb0_0_grp";
slew-rate = <SLEW_RATE_SLOW>;
power-source = <IO_STANDARD_LVCMOS18>;
};
conf-rx {
pins = "MIO52", "MIO53", "MIO55";
bias-high-impedance;
drive-strength = <12>;
slew-rate = <SLEW_RATE_FAST>;
};
conf-tx {
pins = "MIO54", "MIO56", "MIO57", "MIO58", "MIO59",
"MIO60", "MIO61", "MIO62", "MIO63";
bias-disable;
drive-strength = <4>;
slew-rate = <SLEW_RATE_SLOW>;
};
mux {

View File

@ -272,19 +272,22 @@
pinctrl_usb0_default: usb0-default {
conf {
groups = "usb0_0_grp";
slew-rate = <SLEW_RATE_SLOW>;
power-source = <IO_STANDARD_LVCMOS18>;
};
conf-rx {
pins = "MIO52", "MIO53", "MIO55";
bias-high-impedance;
drive-strength = <12>;
slew-rate = <SLEW_RATE_FAST>;
};
conf-tx {
pins = "MIO54", "MIO56", "MIO57", "MIO58", "MIO59",
"MIO60", "MIO61", "MIO62", "MIO63";
bias-disable;
drive-strength = <4>;
slew-rate = <SLEW_RATE_SLOW>;
};
mux {

View File

@ -187,19 +187,22 @@
conf {
groups = "usb0_0_grp";
slew-rate = <SLEW_RATE_SLOW>;
power-source = <IO_STANDARD_LVCMOS18>;
};
conf-rx {
pins = "MIO52", "MIO53", "MIO55";
bias-high-impedance;
drive-strength = <12>;
slew-rate = <SLEW_RATE_FAST>;
};
conf-tx {
pins = "MIO54", "MIO56", "MIO57", "MIO58", "MIO59",
"MIO60", "MIO61", "MIO62", "MIO63";
bias-disable;
drive-strength = <4>;
slew-rate = <SLEW_RATE_SLOW>;
};
};

View File

@ -335,19 +335,22 @@
conf {
groups = "usb1_0_grp";
slew-rate = <SLEW_RATE_SLOW>;
power-source = <IO_STANDARD_LVCMOS18>;
};
conf-rx {
pins = "MIO64", "MIO65", "MIO67";
bias-high-impedance;
drive-strength = <12>;
slew-rate = <SLEW_RATE_FAST>;
};
conf-tx {
pins = "MIO66", "MIO68", "MIO69", "MIO70", "MIO71",
"MIO72", "MIO73", "MIO74", "MIO75";
bias-disable;
drive-strength = <4>;
slew-rate = <SLEW_RATE_SLOW>;
};
};

View File

@ -441,19 +441,22 @@
conf {
groups = "usb0_0_grp";
slew-rate = <SLEW_RATE_SLOW>;
power-source = <IO_STANDARD_LVCMOS18>;
};
conf-rx {
pins = "MIO52", "MIO53", "MIO55";
bias-high-impedance;
drive-strength = <12>;
slew-rate = <SLEW_RATE_FAST>;
};
conf-tx {
pins = "MIO54", "MIO56", "MIO57", "MIO58", "MIO59",
"MIO60", "MIO61", "MIO62", "MIO63";
bias-disable;
drive-strength = <4>;
slew-rate = <SLEW_RATE_SLOW>;
};
};
@ -465,19 +468,22 @@
conf {
groups = "usb1_0_grp";
slew-rate = <SLEW_RATE_SLOW>;
power-source = <IO_STANDARD_LVCMOS18>;
};
conf-rx {
pins = "MIO64", "MIO65", "MIO67";
bias-high-impedance;
drive-strength = <12>;
slew-rate = <SLEW_RATE_FAST>;
};
conf-tx {
pins = "MIO66", "MIO68", "MIO69", "MIO70", "MIO71",
"MIO72", "MIO73", "MIO74", "MIO75";
bias-disable;
drive-strength = <4>;
slew-rate = <SLEW_RATE_SLOW>;
};
};
};

View File

@ -795,19 +795,22 @@
conf {
groups = "usb0_0_grp";
slew-rate = <SLEW_RATE_SLOW>;
power-source = <IO_STANDARD_LVCMOS18>;
};
conf-rx {
pins = "MIO52", "MIO53", "MIO55";
bias-high-impedance;
drive-strength = <12>;
slew-rate = <SLEW_RATE_FAST>;
};
conf-tx {
pins = "MIO54", "MIO56", "MIO57", "MIO58", "MIO59",
"MIO60", "MIO61", "MIO62", "MIO63";
bias-disable;
drive-strength = <4>;
slew-rate = <SLEW_RATE_SLOW>;
};
};

View File

@ -402,20 +402,22 @@
conf {
groups = "usb0_0_grp";
slew-rate = <SLEW_RATE_SLOW>;
power-source = <IO_STANDARD_LVCMOS18>;
drive-strength = <12>;
};
conf-rx {
pins = "MIO52", "MIO53", "MIO55";
bias-high-impedance;
drive-strength = <12>;
slew-rate = <SLEW_RATE_FAST>;
};
conf-tx {
pins = "MIO54", "MIO56", "MIO57", "MIO58", "MIO59",
"MIO60", "MIO61", "MIO62", "MIO63";
bias-disable;
drive-strength = <4>;
slew-rate = <SLEW_RATE_SLOW>;
};
};
};

View File

@ -414,20 +414,22 @@
conf {
groups = "usb0_0_grp";
slew-rate = <SLEW_RATE_SLOW>;
power-source = <IO_STANDARD_LVCMOS18>;
drive-strength = <12>;
};
conf-rx {
pins = "MIO52", "MIO53", "MIO55";
bias-high-impedance;
drive-strength = <12>;
slew-rate = <SLEW_RATE_FAST>;
};
conf-tx {
pins = "MIO54", "MIO56", "MIO57", "MIO58", "MIO59",
"MIO60", "MIO61", "MIO62", "MIO63";
bias-disable;
drive-strength = <4>;
slew-rate = <SLEW_RATE_SLOW>;
};
};
};

View File

@ -793,19 +793,22 @@
conf {
groups = "usb0_0_grp";
slew-rate = <SLEW_RATE_SLOW>;
power-source = <IO_STANDARD_LVCMOS18>;
};
conf-rx {
pins = "MIO52", "MIO53", "MIO55";
bias-high-impedance;
drive-strength = <12>;
slew-rate = <SLEW_RATE_FAST>;
};
conf-tx {
pins = "MIO54", "MIO56", "MIO57", "MIO58", "MIO59",
"MIO60", "MIO61", "MIO62", "MIO63";
bias-disable;
drive-strength = <4>;
slew-rate = <SLEW_RATE_SLOW>;
};
};

View File

@ -652,19 +652,22 @@
conf {
groups = "usb0_0_grp";
slew-rate = <SLEW_RATE_SLOW>;
power-source = <IO_STANDARD_LVCMOS18>;
};
conf-rx {
pins = "MIO52", "MIO53", "MIO55";
bias-high-impedance;
drive-strength = <12>;
slew-rate = <SLEW_RATE_FAST>;
};
conf-tx {
pins = "MIO54", "MIO56", "MIO57", "MIO58", "MIO59",
"MIO60", "MIO61", "MIO62", "MIO63";
bias-disable;
drive-strength = <4>;
slew-rate = <SLEW_RATE_SLOW>;
};
};

View File

@ -79,7 +79,10 @@ struct bl31_params *bl2_plat_get_bl31_params(uintptr_t bl32_entry,
atfhandoffparams->magic[2] = 'N';
atfhandoffparams->magic[3] = 'X';
debug("Creating handoff:\n");
if (bl32_entry) {
debug(" to BL32 at 0x%x EL-1, Secure\n", (u32)bl32_entry);
atfhandoffparams->partition[index].entry_point = bl32_entry;
atfhandoffparams->partition[index].flags = FSBL_FLAGS_EL1 << FSBL_FLAGS_EL_SHIFT |
FSBL_FLAGS_SECURE << FSBL_FLAGS_TZ_SHIFT;
@ -87,6 +90,7 @@ struct bl31_params *bl2_plat_get_bl31_params(uintptr_t bl32_entry,
}
if (bl33_entry) {
debug(" to BL33 at 0x%x EL-2\n", (u32)bl33_entry);
atfhandoffparams->partition[index].entry_point = bl33_entry;
atfhandoffparams->partition[index].flags = FSBL_FLAGS_EL2 <<
FSBL_FLAGS_EL_SHIFT;

View File

@ -4,6 +4,9 @@ menu "M68000 architecture"
config SYS_ARCH
default "m68k"
config NEEDS_MANUAL_RELOC
def_bool y
# processor family
config MCF520x
select OF_CONTROL

View File

@ -4,6 +4,20 @@ menu "MicroBlaze architecture"
config SYS_ARCH
default "microblaze"
config NEEDS_MANUAL_RELOC
bool "Disable position-independent pre-relocation code"
default y
help
U-Boot expects to be linked to a specific hard-coded address, and to
be loaded to and run from that address. This option lifts that
restriction, thus allowing the code to be loaded to and executed from
almost any 4K aligned address. This logic relies on the relocation
information that is embedded in the binary to support U-Boot
relocating itself to the top-of-RAM later during execution.
config STATIC_RELA
def_bool y if !NEEDS_MANUAL_RELOC
choice
prompt "Target select"
optional
@ -25,14 +39,6 @@ config TARGET_MICROBLAZE_GENERIC
endchoice
config DCACHE
bool "Enable dcache support"
default y
config ICACHE
bool "Enable icache support"
default y
source "board/xilinx/Kconfig"
source "board/xilinx/microblaze-generic/Kconfig"

View File

@ -16,3 +16,14 @@ LDFLAGS_FINAL += --gc-sections
ifeq ($(CONFIG_SPL_BUILD),)
PLATFORM_CPPFLAGS += -fPIC
endif
ifeq ($(CONFIG_STATIC_RELA),y)
PLATFORM_CPPFLAGS += -fPIC
LDFLAGS_u-boot += -pic
endif
ifeq ($(CONFIG_SYS_LITTLE_ENDIAN),y)
PLATFORM_ELFFLAGS += -B microblaze $(OBJCOPYFLAGS) -O elf32-microblazeel
else
PLATFORM_ELFFLAGS += -B microblaze $(OBJCOPYFLAGS) -O elf32-microblaze
endif

View File

@ -5,5 +5,7 @@
extra-y = start.o
obj-y = irq.o
obj-y += interrupts.o cache.o exception.o timer.o
obj-y += interrupts.o cache.o exception.o cpuinfo.o
obj-$(CONFIG_STATIC_RELA) += relocate.o
obj-$(CONFIG_XILINX_MICROBLAZE0_PVR) += pvr.o
obj-$(CONFIG_SPL_BUILD) += spl.o

View File

@ -9,6 +9,61 @@
#include <cpu_func.h>
#include <asm/asm.h>
#include <asm/cache.h>
#include <asm/cpuinfo.h>
#include <asm/global_data.h>
DECLARE_GLOBAL_DATA_PTR;
static void __invalidate_icache(ulong addr, ulong size)
{
if (CONFIG_IS_ENABLED(XILINX_MICROBLAZE0_USE_WIC)) {
for (int i = 0; i < size;
i += gd_cpuinfo()->icache_line_length) {
asm volatile (
"wic %0, r0;"
"nop;"
:
: "r" (addr + i)
: "memory");
}
}
}
void invalidate_icache_all(void)
{
__invalidate_icache(0, gd_cpuinfo()->icache_size);
}
static void __flush_dcache(ulong addr, ulong size)
{
if (CONFIG_IS_ENABLED(XILINX_MICROBLAZE0_USE_WDC)) {
for (int i = 0; i < size;
i += gd_cpuinfo()->dcache_line_length) {
asm volatile (
"wdc.flush %0, r0;"
"nop;"
:
: "r" (addr + i)
: "memory");
}
}
}
void flush_dcache_range(unsigned long start, unsigned long end)
{
if (start >= end) {
debug("Invalid dcache range - start: 0x%08lx end: 0x%08lx\n",
start, end);
return;
}
__flush_dcache(start, end - start);
}
void flush_dcache_all(void)
{
__flush_dcache(0, gd_cpuinfo()->dcache_size);
}
int dcache_status(void)
{
@ -37,8 +92,8 @@ void icache_enable(void)
void icache_disable(void)
{
/* we are not generate ICACHE size -> flush whole cache */
flush_cache(0, 32768);
invalidate_icache_all();
MSRCLR(0x20);
}
@ -49,26 +104,19 @@ void dcache_enable(void)
void dcache_disable(void)
{
#ifdef XILINX_USE_DCACHE
flush_cache(0, XILINX_DCACHE_BYTE_SIZE);
#endif
flush_dcache_all();
MSRCLR(0x80);
}
void flush_cache(ulong addr, ulong size)
{
int i;
for (i = 0; i < size; i += 4)
asm volatile (
#ifdef CONFIG_ICACHE
"wic %0, r0;"
#endif
"nop;"
#ifdef CONFIG_DCACHE
"wdc.flush %0, r0;"
#endif
"nop;"
:
: "r" (addr + i)
: "memory");
__invalidate_icache(addr, size);
__flush_dcache(addr, size);
}
void flush_cache_all(void)
{
invalidate_icache_all();
flush_dcache_all();
}

View File

@ -0,0 +1,131 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2022, Ovidiu Panait <ovpanait@gmail.com>
*/
#include <common.h>
#include <asm/cpuinfo.h>
#include <asm/global_data.h>
DECLARE_GLOBAL_DATA_PTR;
#if CONFIG_IS_ENABLED(CPU_MICROBLAZE)
/* These key value are as per MBV field in PVR0 */
static const struct microblaze_version_map cpu_ver_lookup[] = {
{"5.00.a", 0x01},
{"5.00.b", 0x02},
{"5.00.c", 0x03},
{"6.00.a", 0x04},
{"6.00.b", 0x06},
{"7.00.a", 0x05},
{"7.00.b", 0x07},
{"7.10.a", 0x08},
{"7.10.b", 0x09},
{"7.10.c", 0x0a},
{"7.10.d", 0x0b},
{"7.20.a", 0x0c},
{"7.20.b", 0x0d},
{"7.20.c", 0x0e},
{"7.20.d", 0x0f},
{"7.30.a", 0x10},
{"7.30.b", 0x11},
{"8.00.a", 0x12},
{"8.00.b", 0x13},
{"8.10.a", 0x14},
{"8.20.a", 0x15},
{"8.20.b", 0x16},
{"8.30.a", 0x17},
{"8.40.a", 0x18},
{"8.40.b", 0x19},
{"8.50.a", 0x1a},
{"8.50.b", 0x1c},
{"8.50.c", 0x1e},
{"9.0", 0x1b},
{"9.1", 0x1d},
{"9.2", 0x1f},
{"9.3", 0x20},
{"9.4", 0x21},
{"9.5", 0x22},
{"9.6", 0x23},
{"10.0", 0x24},
{"11.0", 0x25},
{NULL, 0},
};
static const struct microblaze_version_map family_string_lookup[] = {
{"virtex2", 0x4},
{"virtex2pro", 0x5},
{"spartan3", 0x6},
{"virtex4", 0x7},
{"virtex5", 0x8},
{"spartan3e", 0x9},
{"spartan3a", 0xa},
{"spartan3an", 0xb},
{"spartan3adsp", 0xc},
{"spartan6", 0xd},
{"virtex6", 0xe},
{"virtex7", 0xf},
/* FIXME There is no key code defined for spartan2 */
{"spartan2", 0xf0},
{"kintex7", 0x10},
{"artix7", 0x11},
{"zynq7000", 0x12},
{"UltraScale Virtex", 0x13},
{"UltraScale Kintex", 0x14},
{"UltraScale+ Zynq", 0x15},
{"UltraScale+ Virtex", 0x16},
{"UltraScale+ Kintex", 0x17},
{"Spartan7", 0x18},
{NULL, 0},
};
static const char *lookup_string(u32 code,
const struct microblaze_version_map *entry)
{
for (; entry->string; ++entry)
if (entry->code == code)
return entry->string;
return "(unknown)";
}
static const u32 lookup_code(const char *string,
const struct microblaze_version_map *entry)
{
for (; entry->string; ++entry)
if (!strcmp(entry->string, string))
return entry->code;
return 0;
}
const char *microblaze_lookup_fpga_family_string(const u32 code)
{
return lookup_string(code, family_string_lookup);
}
const char *microblaze_lookup_cpu_version_string(const u32 code)
{
return lookup_string(code, cpu_ver_lookup);
}
const u32 microblaze_lookup_fpga_family_code(const char *string)
{
return lookup_code(string, family_string_lookup);
}
const u32 microblaze_lookup_cpu_version_code(const char *string)
{
return lookup_code(string, cpu_ver_lookup);
}
#endif /* CONFIG_CPU_MICROBLAZE */
void microblaze_early_cpuinfo_init(void)
{
struct microblaze_cpuinfo *ci = gd_cpuinfo();
ci->icache_size = CONFIG_XILINX_MICROBLAZE0_ICACHE_SIZE;
ci->icache_line_length = 4;
ci->dcache_size = CONFIG_XILINX_MICROBLAZE0_DCACHE_SIZE;
ci->dcache_line_length = 4;
}

View File

@ -16,7 +16,7 @@ void _hw_exception_handler (void)
/* loading address of exception EAR */
MFS(address, rear);
/* loading excetpion state register ESR */
/* loading exception state register ESR */
MFS(state, resr);
printf("Hardware exception at 0x%x address\n", address);
R17(address);

View File

@ -8,17 +8,8 @@
*/
#include <common.h>
#include <command.h>
#include <fdtdec.h>
#include <irq_func.h>
#include <log.h>
#include <malloc.h>
#include <asm/global_data.h>
#include <asm/microblaze_intc.h>
#include <asm/asm.h>
DECLARE_GLOBAL_DATA_PTR;
void enable_interrupts(void)
{
debug("Enable interrupts for the whole CPU\n");
@ -34,183 +25,12 @@ int disable_interrupts(void)
return (msr & 0x2) != 0;
}
static struct irq_action *vecs;
static u32 irq_no;
/* mapping structure to interrupt controller */
microblaze_intc_t *intc;
/* default handler */
static void def_hdlr(void)
{
puts("def_hdlr\n");
}
static void enable_one_interrupt(int irq)
{
int mask;
int offset = 1;
offset <<= irq;
mask = intc->ier;
intc->ier = (mask | offset);
debug("Enable one interrupt irq %x - mask %x,ier %x\n", offset, mask,
intc->ier);
debug("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier,
intc->iar, intc->mer);
}
static void disable_one_interrupt(int irq)
{
int mask;
int offset = 1;
offset <<= irq;
mask = intc->ier;
intc->ier = (mask & ~offset);
debug("Disable one interrupt irq %x - mask %x,ier %x\n", irq, mask,
intc->ier);
debug("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier,
intc->iar, intc->mer);
}
int install_interrupt_handler(int irq, interrupt_handler_t *hdlr, void *arg)
{
struct irq_action *act;
/* irq out of range */
if ((irq < 0) || (irq > irq_no)) {
puts("IRQ out of range\n");
return -1;
}
act = &vecs[irq];
if (hdlr) { /* enable */
act->handler = hdlr;
act->arg = arg;
act->count = 0;
enable_one_interrupt(irq);
return 0;
}
/* Disable */
act->handler = (interrupt_handler_t *)def_hdlr;
act->arg = (void *)irq;
disable_one_interrupt(irq);
return 1;
}
/* initialization interrupt controller - hardware */
static void intc_init(void)
{
intc->mer = 0;
intc->ier = 0;
intc->iar = 0xFFFFFFFF;
/* XIntc_Start - hw_interrupt enable and all interrupt enable */
intc->mer = 0x3;
debug("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier,
intc->iar, intc->mer);
}
int interrupt_init(void)
{
int i;
const void *blob = gd->fdt_blob;
int node = 0;
debug("INTC: Initialization\n");
node = fdt_node_offset_by_compatible(blob, node,
"xlnx,xps-intc-1.00.a");
if (node != -1) {
fdt_addr_t base = fdtdec_get_addr(blob, node, "reg");
if (base == FDT_ADDR_T_NONE)
return -1;
debug("INTC: Base addr %lx\n", base);
intc = (microblaze_intc_t *)base;
irq_no = fdtdec_get_int(blob, node, "xlnx,num-intr-inputs", 0);
debug("INTC: IRQ NO %x\n", irq_no);
} else {
return node;
}
if (irq_no) {
vecs = calloc(1, sizeof(struct irq_action) * irq_no);
if (vecs == NULL) {
puts("Interrupt vector allocation failed\n");
return -1;
}
/* initialize irq list */
for (i = 0; i < irq_no; i++) {
vecs[i].handler = (interrupt_handler_t *)def_hdlr;
vecs[i].arg = (void *)i;
vecs[i].count = 0;
}
/* initialize intc controller */
intc_init();
enable_interrupts();
} else {
puts("Undefined interrupt controller\n");
}
return 0;
}
void interrupt_handler(void)
{
int irqs = intc->ivr; /* find active interrupt */
int mask = 1;
int value;
struct irq_action *act = vecs + irqs;
debug("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier,
intc->iar, intc->mer);
#ifdef DEBUG
R14(value);
#endif
debug("Interrupt handler on %x line, r14 %x\n", irqs, value);
debug("Jumping to interrupt handler rutine addr %x,count %x,arg %x\n",
(u32)act->handler, act->count, (u32)act->arg);
act->handler(act->arg);
act->count++;
intc->iar = mask << irqs;
debug("Dump INTC reg, isr %x, ier %x, iar %x, mer %x\n", intc->isr,
intc->ier, intc->iar, intc->mer);
#ifdef DEBUG
R14(value);
#endif
debug("Interrupt handler on %x line, r14 %x\n", irqs, value);
panic("Interrupt occurred\n");
}
#if defined(CONFIG_CMD_IRQ)
int do_irqinfo(struct cmd_tbl *cmdtp, int flag, int argc, const char *argv[])
{
int i;
struct irq_action *act = vecs;
if (irq_no) {
puts("\nInterrupt-Information:\n\n"
"Nr Routine Arg Count\n"
"-----------------------------\n");
for (i = 0; i < irq_no; i++) {
if (act->handler != (interrupt_handler_t *)def_hdlr) {
printf("%02d %08x %08x %d\n", i,
(int)act->handler, (int)act->arg,
act->count);
}
act++;
}
puts("\n");
} else {
puts("Undefined interrupt controller\n");
}
return 0;
}
#endif

41
arch/microblaze/cpu/pvr.c Normal file
View File

@ -0,0 +1,41 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2022, Ovidiu Panait <ovpanait@gmail.com>
*/
#include <common.h>
#include <asm/asm.h>
#include <asm/pvr.h>
int microblaze_cpu_has_pvr_full(void)
{
u32 msr, pvr0;
MFS(msr, rmsr);
if (!(msr & PVR_MSR_BIT))
return 0;
get_pvr(0, pvr0);
debug("%s: pvr0 is 0x%08x\n", __func__, pvr0);
if (!(pvr0 & PVR0_PVR_FULL_MASK))
return 0;
return 1;
}
void microblaze_get_all_pvrs(u32 pvr[PVR_FULL_COUNT])
{
get_pvr(0, pvr[0]);
get_pvr(1, pvr[1]);
get_pvr(2, pvr[2]);
get_pvr(3, pvr[3]);
get_pvr(4, pvr[4]);
get_pvr(5, pvr[5]);
get_pvr(6, pvr[6]);
get_pvr(7, pvr[7]);
get_pvr(8, pvr[8]);
get_pvr(9, pvr[9]);
get_pvr(10, pvr[10]);
get_pvr(11, pvr[11]);
get_pvr(12, pvr[12]);
}

View File

@ -0,0 +1,111 @@
// SPDX-License-Identifier: GPL-2.0
/*
* (C) Copyright 2022 Advanced Micro Devices, Inc
* Michal Simek <michal.simek@amd.com>
*/
#include <common.h>
#include <elf.h>
#define R_MICROBLAZE_NONE 0
#define R_MICROBLAZE_32 1
#define R_MICROBLAZE_REL 16
#define R_MICROBLAZE_GLOB_DAT 18
/**
* mb_fix_rela - update relocation to new address
* @reloc_addr: new relocation address
* @verbose: enable version messages
* @rela_start: rela section start
* @rela_end: rela section end
* @dyn_start: dynamic section start
* @origin_addr: address where u-boot starts(doesn't need to be CONFIG_SYS_TEXT_BASE)
*/
void mb_fix_rela(u32 reloc_addr, u32 verbose, u32 rela_start,
u32 rela_end, u32 dyn_start, u32 origin_addr)
{
u32 num, type, mask, i, reloc_off;
/*
* Return in case u-boot.elf is used directly.
* Skip it when u-boot.bin is loaded to different address than
* CONFIG_SYS_TEXT_BASE. In this case relocation is necessary to run.
*/
if (reloc_addr == CONFIG_SYS_TEXT_BASE) {
debug_cond(verbose,
"Relocation address is the same - skip relocation\n");
return;
}
reloc_off = reloc_addr - origin_addr;
debug_cond(verbose, "Relocation address:\t0x%08x\n", reloc_addr);
debug_cond(verbose, "Relocation offset:\t0x%08x\n", reloc_off);
debug_cond(verbose, "Origin address:\t0x%08x\n", origin_addr);
debug_cond(verbose, "Rela start:\t0x%08x\n", rela_start);
debug_cond(verbose, "Rela end:\t0x%08x\n", rela_end);
debug_cond(verbose, "Dynsym start:\t0x%08x\n", dyn_start);
num = (rela_end - rela_start) / sizeof(Elf32_Rela);
debug_cond(verbose, "Number of entries:\t%u\n", num);
for (i = 0; i < num; i++) {
Elf32_Rela *rela;
u32 temp;
rela = (Elf32_Rela *)(rela_start + sizeof(Elf32_Rela) * i);
mask = 0xffULL; /* would be different on 32-bit */
type = rela->r_info & mask;
debug_cond(verbose, "\nRela possition:\t%d/0x%x\n",
i, (u32)rela);
switch (type) {
case R_MICROBLAZE_REL:
temp = *(u32 *)rela->r_offset;
debug_cond(verbose, "Type:\tREL\n");
debug_cond(verbose, "Rela r_offset:\t\t0x%x\n", rela->r_offset);
debug_cond(verbose, "Rela r_info:\t\t0x%x\n", rela->r_info);
debug_cond(verbose, "Rela r_addend:\t\t0x%x\n", rela->r_addend);
debug_cond(verbose, "Value at r_offset:\t0x%x\n", temp);
rela->r_offset += reloc_off;
rela->r_addend += reloc_off;
temp = *(u32 *)rela->r_offset;
temp += reloc_off;
*(u32 *)rela->r_offset = temp;
debug_cond(verbose, "New:Rela r_offset:\t0x%x\n", rela->r_offset);
debug_cond(verbose, "New:Rela r_addend:\t0x%x\n", rela->r_addend);
debug_cond(verbose, "New:Value at r_offset:\t0x%x\n", temp);
break;
case R_MICROBLAZE_32:
case R_MICROBLAZE_GLOB_DAT:
debug_cond(verbose, "Type:\t(32/GLOB) %u\n", type);
debug_cond(verbose, "Rela r_offset:\t\t0x%x\n", rela->r_offset);
debug_cond(verbose, "Rela r_info:\t\t0x%x\n", rela->r_info);
debug_cond(verbose, "Rela r_addend:\t\t0x%x\n", rela->r_addend);
debug_cond(verbose, "Value at r_offset:\t0x%x\n", temp);
rela->r_offset += reloc_off;
temp = *(u32 *)rela->r_offset;
temp += reloc_off;
*(u32 *)rela->r_offset = temp;
debug_cond(verbose, "New:Rela r_offset:\t0x%x\n", rela->r_offset);
debug_cond(verbose, "New:Value at r_offset:\t0x%x\n", temp);
break;
case R_MICROBLAZE_NONE:
debug_cond(verbose, "R_MICROBLAZE_NONE - skip\n");
break;
default:
debug_cond(verbose, "warning: unsupported relocation type %d at %x\n",
type, rela->r_offset);
}
}
}

View File

@ -10,18 +10,64 @@
#include <asm-offsets.h>
#include <config.h>
#if defined(CONFIG_STATIC_RELA)
#define SYM_ADDR(reg, reg_add, symbol) \
mfs r20, rpc; \
addik r20, r20, _GLOBAL_OFFSET_TABLE_ + 8; \
lwi reg, r20, symbol@GOT; \
addk reg, reg reg_add;
#else
#define SYM_ADDR(reg, reg_add, symbol) \
addi reg, reg_add, symbol
#endif
.text
.global _start
_start:
mts rmsr, r0 /* disable cache */
mfs r20, rpc
addi r20, r20, -4
addi r8, r0, _end
mts rslr, r8
mts rslr, r0
mts rshr, r20
#if defined(CONFIG_SPL_BUILD)
addi r1, r0, CONFIG_SPL_STACK
#else
addi r1, r0, CONFIG_SYS_INIT_SP_OFFSET
add r1, r0, r20
#if defined(CONFIG_STATIC_RELA)
bri 1f
/* Force alignment for easier ASM code below */
#define ALIGNMENT_ADDR 0x20
.align 4
uboot_dyn_start:
.word __rel_dyn_start
uboot_dyn_end:
.word __rel_dyn_end
uboot_sym_start:
.word __dyn_sym_start
1:
addi r5, r20, 0
add r6, r0, r0
lwi r7, r20, ALIGNMENT_ADDR
addi r7, r7, -CONFIG_SYS_TEXT_BASE
add r7, r7, r5
lwi r8, r20, ALIGNMENT_ADDR + 0x4
addi r8, r8, -CONFIG_SYS_TEXT_BASE
add r8, r8, r5
lwi r9, r20, ALIGNMENT_ADDR + 0x8
addi r9, r9, -CONFIG_SYS_TEXT_BASE
add r9, r9, r5
addi r10, r0, CONFIG_SYS_TEXT_BASE
brlid r15, mb_fix_rela
nop
#endif
#endif
addi r1, r1, -4 /* Decrement SP to top of memory */
@ -29,7 +75,7 @@ _start:
/* Call board_init_f_alloc_reserve with the current stack pointer as
* parameter. */
add r5, r0, r1
bralid r15, board_init_f_alloc_reserve
brlid r15, board_init_f_alloc_reserve
nop
/* board_init_f_alloc_reserve returns a pointer to the allocated area
@ -41,20 +87,25 @@ _start:
/* Call board_init_f_init_reserve with the address returned by
* board_init_f_alloc_reserve as parameter. */
add r5, r0, r3
bralid r15, board_init_f_init_reserve
brlid r15, board_init_f_init_reserve
nop
#if !defined(CONFIG_SPL_BUILD)
/* Setup vectors with pre-relocation symbols */
or r5, r0, r0
bralid r15, __setup_exceptions
brlid r15, __setup_exceptions
nop
#endif
/*
* Initialize global data cpuinfo with default values (cache
* size, cache line size, etc).
*/
brlid r15, microblaze_early_cpuinfo_init
nop
/* Flush cache before enable cache */
addik r5, r0, 0
addik r6, r0, XILINX_DCACHE_BYTE_SIZE
bralid r15, flush_cache
brlid r15, flush_cache_all
nop
/* enable instruction and data cache */
@ -64,8 +115,8 @@ _start:
clear_bss:
/* clear BSS segments */
addi r5, r0, __bss_start
addi r4, r0, __bss_end
SYM_ADDR(r5, r0, __bss_start)
SYM_ADDR(r4, r0, __bss_end)
cmp r6, r5, r4
beqi r6, 3f
2:
@ -75,14 +126,14 @@ clear_bss:
bnei r6, 2b
3: /* jumping to board_init */
#ifdef CONFIG_DEBUG_UART
bralid r15, debug_uart_init
brlid r15, debug_uart_init
nop
#endif
#ifndef CONFIG_SPL_BUILD
or r5, r0, r0 /* flags - empty */
brai board_init_f
bri board_init_f
#else
brai board_init_r
bri board_init_r
#endif
1: bri 1b
@ -141,7 +192,8 @@ __setup_exceptions:
swi r2, r4, 0x0 /* reset address - imm opcode */
swi r3, r4, 0x4 /* reset address - brai opcode */
addik r6, r0, CONFIG_SYS_TEXT_BASE
SYM_ADDR(r6, r0, _start)
/* Intentionally keep reset vector back to origin u-boot location */
sw r6, r1, r0
lhu r7, r1, r10
rsubi r8, r10, 0x2
@ -154,7 +206,7 @@ __setup_exceptions:
swi r2, r4, 0x8 /* user vector exception - imm opcode */
swi r3, r4, 0xC /* user vector exception - brai opcode */
addik r6, r5, _exception_handler
SYM_ADDR(r6, r5, _exception_handler)
sw r6, r1, r0
/*
* BIG ENDIAN memory map for user exception
@ -187,7 +239,7 @@ __setup_exceptions:
swi r2, r4, 0x10 /* interrupt - imm opcode */
swi r3, r4, 0x14 /* interrupt - brai opcode */
addik r6, r5, _interrupt_handler
SYM_ADDR(r6, r5, _interrupt_handler)
sw r6, r1, r0
lhu r7, r1, r10
rsubi r8, r10, 0x12
@ -199,7 +251,7 @@ __setup_exceptions:
swi r2, r4, 0x20 /* hardware exception - imm opcode */
swi r3, r4, 0x24 /* hardware exception - brai opcode */
addik r6, r5, _hw_exception_handler
SYM_ADDR(r6, r5, _hw_exception_handler)
sw r6, r1, r0
lhu r7, r1, r10
rsubi r8, r10, 0x22
@ -220,39 +272,6 @@ __setup_exceptions:
or r0, r0, r0
.end __setup_exceptions
/*
* Read 16bit little endian
*/
.text
.global in16
.ent in16
.align 2
in16: lhu r3, r0, r5
bslli r4, r3, 8
bsrli r3, r3, 8
andi r4, r4, 0xffff
or r3, r3, r4
rtsd r15, 8
sext16 r3, r3
.end in16
/*
* Write 16bit little endian
* first parameter(r5) - address, second(r6) - short value
*/
.text
.global out16
.ent out16
.align 2
out16: bslli r3, r6, 8
bsrli r6, r6, 8
andi r3, r3, 0xffff
or r3, r3, r6
sh r3, r0, r5
rtsd r15, 8
or r0, r0, r0
.end out16
/*
* Relocate u-boot
*/
@ -267,31 +286,54 @@ relocate_code:
* r7 - reloc_addr
*/
addi r1, r5, 0 /* Start to use new SP */
mts rshr, r1
addi r31, r6, 0 /* Start to use new GD */
add r23, r0, r7 /* Move reloc addr to r23 */
/* Relocate text and data - r12 temp value */
addi r21, r0, _start
addi r22, r0, _end - 4 /* Include BSS too */
SYM_ADDR(r21, r0, _start)
SYM_ADDR(r22, r0, _end) /* Include BSS too */
addi r22, r22, -4
rsub r6, r21, r22
or r5, r0, r0
1: lw r12, r21, r5 /* Load u-boot data */
sw r12, r23, r5 /* Write zero to loc */
sw r12, r7, r5 /* Write zero to loc */
cmp r12, r5, r6 /* Check if we have reach the end */
bneid r12, 1b
addi r5, r5, 4 /* Increment to next loc - relocate code */
/* R23 points to the base address. */
add r23, r0, r7 /* Move reloc addr to r23 */
addi r24, r0, CONFIG_SYS_TEXT_BASE /* Get reloc offset */
rsub r23, r24, r23 /* keep - this is already here gd->reloc_off */
rsub r23, r21, r7 /* keep - this is already here gd->reloc_off */
/* Setup vectors with post-relocation symbols */
add r5, r0, r23 /* load gd->reloc_off to r5 */
bralid r15, __setup_exceptions
brlid r15, __setup_exceptions
nop
#if defined(CONFIG_STATIC_RELA)
/* reloc_offset is current location */
SYM_ADDR(r10, r0, _start)
/* r5 new address where I should copy code */
add r5, r0, r7 /* Move reloc addr to r5 */
/* Verbose message */
addi r6, r0, 0
SYM_ADDR(r7, r0, __rel_dyn_start)
rsub r7, r10, r7
add r7, r7, r5
SYM_ADDR(r8, r0, __rel_dyn_end)
rsub r8, r10, r8
add r8, r8, r5
SYM_ADDR(r9, r0, __dyn_sym_start)
rsub r9, r10, r9
add r9, r9, r5
brlid r15, mb_fix_rela
nop
/* end of code which does relocation */
#else
/* Check if GOT exist */
addik r21, r23, _got_start
addik r22, r23, _got_end
@ -309,21 +351,15 @@ relocate_code:
cmpu r12, r21, r22 /* Check if this cross boundary */
bneid r12, 3b
addik r21. r21, 4
/* Update pointer to GOT */
mfs r20, rpc
addik r20, r20, _GLOBAL_OFFSET_TABLE_ + 8
addk r20, r20, r23
#endif
/* Flush caches to ensure consistency */
addik r5, r0, 0
addik r6, r0, XILINX_DCACHE_BYTE_SIZE
bralid r15, flush_cache
brlid r15, flush_cache_all
nop
2: addi r5, r31, 0 /* gd is initialized in board_r.c */
addi r6, r0, CONFIG_SYS_TEXT_BASE
addi r12, r23, board_init_r
SYM_ADDR(r6, r0, _start)
SYM_ADDR(r12, r23, board_init_r)
bra r12 /* Jump to relocated code */
.end relocate_code

View File

@ -1,123 +0,0 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2007 Michal Simek
*
* Michal SIMEK <monstr@monstr.eu>
*/
#include <common.h>
#include <fdtdec.h>
#include <init.h>
#include <log.h>
#include <time.h>
#include <asm/global_data.h>
#include <asm/microblaze_timer.h>
#include <asm/microblaze_intc.h>
#include <linux/delay.h>
DECLARE_GLOBAL_DATA_PTR;
volatile int timestamp = 0;
microblaze_timer_t *tmr;
ulong get_timer (ulong base)
{
if (tmr)
return timestamp - base;
return timestamp++ - base;
}
void __udelay(unsigned long usec)
{
u32 i;
if (tmr) {
i = get_timer(0);
while ((get_timer(0) - i) < (usec / 1000))
;
}
}
#ifndef CONFIG_SPL_BUILD
static void timer_isr(void *arg)
{
timestamp++;
tmr->control = tmr->control | TIMER_INTERRUPT;
}
int timer_init (void)
{
int irq = -1;
u32 preload = 0;
u32 ret = 0;
const void *blob = gd->fdt_blob;
int node = 0;
u32 cell[2];
debug("TIMER: Initialization\n");
/* Do not init before relocation */
if (!(gd->flags & GD_FLG_RELOC))
return 0;
node = fdt_node_offset_by_compatible(blob, node,
"xlnx,xps-timer-1.00.a");
if (node != -1) {
fdt_addr_t base = fdtdec_get_addr(blob, node, "reg");
if (base == FDT_ADDR_T_NONE)
return -1;
debug("TIMER: Base addr %lx\n", base);
tmr = (microblaze_timer_t *)base;
ret = fdtdec_get_int_array(blob, node, "interrupts",
cell, ARRAY_SIZE(cell));
if (ret)
return ret;
irq = cell[0];
debug("TIMER: IRQ %x\n", irq);
preload = fdtdec_get_int(blob, node, "clock-frequency", 0);
preload /= CONFIG_SYS_HZ;
} else {
return node;
}
if (tmr && preload && irq >= 0) {
tmr->loadreg = preload;
tmr->control = TIMER_INTERRUPT | TIMER_RESET;
tmr->control = TIMER_ENABLE | TIMER_ENABLE_INTR |\
TIMER_RELOAD | TIMER_DOWN_COUNT;
timestamp = 0;
ret = install_interrupt_handler (irq, timer_isr, (void *)tmr);
if (ret)
tmr = NULL;
}
/* No problem if timer is not found/initialized */
return 0;
}
#else
int timer_init(void)
{
return 0;
}
#endif
/*
* This function is derived from PowerPC code (read timebase as long long).
* On Microblaze it just returns the timer value.
*/
unsigned long long get_ticks(void)
{
return get_timer(0);
}
/*
* This function is derived from PowerPC code (timebase clock frequency).
* On Microblaze it returns the number of timer ticks per second.
*/
ulong get_tbclk(void)
{
return CONFIG_SYS_HZ;
}

View File

@ -46,6 +46,20 @@ SECTIONS
}
__init_end = . ;
. = ALIGN(4);
__rel_dyn_start = .;
.rela.dyn : {
*(.rela.dyn)
}
__rel_dyn_end = .;
. = ALIGN(4);
__dyn_sym_start = .;
.dynsym : {
*(.dynsym)
}
__dyn_sym_end = .;
.bss ALIGN(0x4):
{
__bss_start = .;

View File

@ -18,4 +18,9 @@
#define ARCH_DMA_MINALIGN 16
#endif
/**
* flush_cache_all - flush the entire instruction/data caches
*/
void flush_cache_all(void);
#endif /* __MICROBLAZE_CACHE_H__ */

View File

@ -0,0 +1,114 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2022, Ovidiu Panait <ovpanait@gmail.com>
*/
#ifndef __ASM_MICROBLAZE_CPUINFO_H
#define __ASM_MICROBLAZE_CPUINFO_H
/**
* struct microblaze_cpuinfo - CPU info for microblaze processor core.
*
* @icache_size: Size of instruction cache memory in bytes.
* @icache_line_length: Instruction cache line length in bytes.
* @dcache_size: Size of data cache memory in bytes.
* @dcache_line_length: Data cache line length in bytes.
* @use_mmu: MMU support flag.
* @cpu_freq: Cpu clock frequency in Hz.
* @addr_size: Address bus width in bits.
* @ver_code: Cpu version code.
* @fpga_code: FPGA family version code.
*/
struct microblaze_cpuinfo {
u32 icache_size;
u32 icache_line_length;
u32 dcache_size;
u32 dcache_line_length;
#if CONFIG_IS_ENABLED(CPU_MICROBLAZE)
u32 use_mmu;
u32 cpu_freq;
u32 addr_size;
u32 ver_code;
u32 fpga_code;
#endif /* CONFIG_CPU_MICROBLAZE */
};
/**
* struct microblaze_version_data - Maps a hex version code to a cpu/fpga name.
*/
struct microblaze_version_map {
const char *string;
const u32 code;
};
/**
* microblaze_lookup_cpu_version_code() - Get hex version code for the
* specified cpu name string.
*
* This function searches the cpu_ver_lookup[] array for the hex version code
* associated with a specific CPU name. The version code is returned if a match
* is found, otherwise 0.
*
* @string: cpu name string
*
* Return: >0 if the entry is found, 0 otherwise.
*/
const u32 microblaze_lookup_cpu_version_code(const char *string);
/**
* microblaze_lookup_fpga_family_code() - Get hex version code for the
* specified fpga family name.
*
* This function searches the family_string_lookup[] array for the hex version
* code associated with a specific fpga family name. The version code is
* returned if a match is found, otherwise 0.
*
* @string: fpga family name string
*
* Return: >0 if the entry is found, 0 otherwise.
*/
const u32 microblaze_lookup_fpga_family_code(const char *string);
/**
* microblaze_lookup_cpu_version_string() - Get cpu name for the specified cpu
* version code.
*
* This function searches the cpu_ver_lookup[] array for the cpu name string
* associated with a specific version code. The cpu name is returned if a match
* is found, otherwise "(unknown)".
*
* @code: cpu version code
*
* Return: Pointer to the cpu name if the entry is found, otherwise "(unknown)".
*/
const char *microblaze_lookup_cpu_version_string(const u32 code);
/**
* microblaze_lookup_fpga_family_string() - Get fpga family name for the
* specified version code.
*
* This function searches the family_string_lookup[] array for the fpga family
* name string associated with a specific version code. The fpga family name is
* returned if a match is found, otherwise "(unknown)".
*
* @code: fpga family version code
*
* Return: Pointer to the fpga family name if the entry is found, otherwise
* "(unknown)".
*/
const char *microblaze_lookup_fpga_family_string(const u32 code);
/**
* microblaze_early_cpuinfo_init() - Initialize cpuinfo with default values.
*
* Initializes the global data cpuinfo structure with default values (cache
* size, cache line size, etc.). It is called very early in the boot process
* (start.S codepath right before the first cache flush call) to ensure that
* cache related operations are properly handled.
*/
void microblaze_early_cpuinfo_init(void);
#endif /* __ASM_MICROBLAZE_CPUINFO_H */

View File

@ -8,12 +8,17 @@
#ifndef __ASM_GBL_DATA_H
#define __ASM_GBL_DATA_H
#include <asm/cpuinfo.h>
/* Architecture-specific global data */
struct arch_global_data {
struct microblaze_cpuinfo cpuinfo;
};
#include <asm-generic/global_data.h>
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r31")
#define gd_cpuinfo() ((struct microblaze_cpuinfo *)&gd->arch.cpuinfo)
#endif /* __ASM_GBL_DATA_H */

View File

@ -1,37 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* (C) Copyright 2007 Michal Simek
*
* Michal SIMEK <monstr@monstr.cz>
*/
#include <irq_func.h>
typedef volatile struct microblaze_intc_t {
int isr; /* interrupt status register */
int ipr; /* interrupt pending register */
int ier; /* interrupt enable register */
int iar; /* interrupt acknowledge register */
int sie; /* set interrupt enable bits */
int cie; /* clear interrupt enable bits */
int ivr; /* interrupt vector register */
int mer; /* master enable register */
} microblaze_intc_t;
struct irq_action {
interrupt_handler_t *handler; /* pointer to interrupt rutine */
void *arg;
int count; /* number of interrupt */
};
/**
* Register and unregister interrupt handler rutines
*
* @param irq IRQ number
* @param hdlr Interrupt handler rutine
* @param arg Pointer to argument which is passed to int. handler rutine
* Return: 0 if registration pass, 1 if unregistration pass,
* or an error code < 0 otherwise
*/
int install_interrupt_handler(int irq, interrupt_handler_t *hdlr,
void *arg);

View File

@ -1,26 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* (C) Copyright 2007 Michal Simek
*
* Michal SIMEK <monstr@monstr.cz>
*/
#define TIMER_ENABLE_ALL 0x400 /* ENALL */
#define TIMER_PWM 0x200 /* PWMA0 */
#define TIMER_INTERRUPT 0x100 /* T0INT */
#define TIMER_ENABLE 0x080 /* ENT0 */
#define TIMER_ENABLE_INTR 0x040 /* ENIT0 */
#define TIMER_RESET 0x020 /* LOAD0 */
#define TIMER_RELOAD 0x010 /* ARHT0 */
#define TIMER_EXT_CAPTURE 0x008 /* CAPT0 */
#define TIMER_EXT_COMPARE 0x004 /* GENT0 */
#define TIMER_DOWN_COUNT 0x002 /* UDT0 */
#define TIMER_CAPTURE_MODE 0x001 /* MDT0 */
typedef volatile struct microblaze_timer_t {
int control; /* control/statuc register TCSR */
int loadreg; /* load register TLR */
int counter; /* timer/counter register */
} microblaze_timer_t;
int timer_init(void);

View File

@ -0,0 +1,75 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2022, Ovidiu Panait <ovpanait@gmail.com>
*/
#ifndef __ASM_MICROBLAZE_PVR_H
#define __ASM_MICROBLAZE_PVR_H
#include <asm/asm.h>
#define PVR_FULL_COUNT 13 /* PVR0 - PVR12 */
#define __get_pvr(val, reg) \
__asm__ __volatile__ ("mfs %0," #reg : "=r" (val) :: "memory")
#define get_pvr(pvrid, val) \
__get_pvr(val, rpvr ## pvrid)
#define PVR_MSR_BIT 0x00000400
/* PVR0 masks */
#define PVR0_PVR_FULL_MASK 0x80000000
#define PVR0_VERSION_MASK 0x0000FF00
/* PVR4 masks - ICache configs */
#define PVR4_ICACHE_LINE_LEN_MASK 0x00E00000 /* ICLL */
#define PVR4_ICACHE_BYTE_SIZE_MASK 0x001F0000 /* ICBS */
/* PVR5 masks - DCache configs */
#define PVR5_DCACHE_LINE_LEN_MASK 0x00E00000 /* DCLL */
#define PVR5_DCACHE_BYTE_SIZE_MASK 0x001F0000 /* DCBS */
/* PVR10 masks - FPGA family */
#define PVR10_TARGET_FAMILY_MASK 0xFF000000
/* PVR11 masks - MMU */
#define PVR11_USE_MMU 0xC0000000
/* PVR access macros */
#define PVR_VERSION(pvr) \
((pvr[0] & PVR0_VERSION_MASK) >> 8)
#define PVR_ICACHE_LINE_LEN(pvr) \
((1 << ((pvr[4] & PVR4_ICACHE_LINE_LEN_MASK) >> 21)) << 2)
#define PVR_ICACHE_BYTE_SIZE(pvr) \
(1 << ((pvr[4] & PVR4_ICACHE_BYTE_SIZE_MASK) >> 16))
#define PVR_DCACHE_LINE_LEN(pvr) \
((1 << ((pvr[5] & PVR5_DCACHE_LINE_LEN_MASK) >> 21)) << 2)
#define PVR_DCACHE_BYTE_SIZE(pvr) \
(1 << ((pvr[5] & PVR5_DCACHE_BYTE_SIZE_MASK) >> 16))
#define PVR_USE_MMU(pvr) \
((pvr[11] & PVR11_USE_MMU) >> 30)
#define PVR_TARGET_FAMILY(pvr) \
((pvr[10] & PVR10_TARGET_FAMILY_MASK) >> 24)
/**
* microblaze_cpu_has_pvr_full() - Check for full PVR support
*
* Check MSR register for PVR support and, if applicable, check the PVR0
* register for full PVR support.
*
* Return: 1 if there is full PVR support, 0 otherwise.
*/
int microblaze_cpu_has_pvr_full(void);
/**
* microblaze_get_all_pvrs() - Copy PVR0-PVR12 to destination array
*
* @pvr: destination array of size PVR_FULL_COUNT
*/
void microblaze_get_all_pvrs(u32 pvr[PVR_FULL_COUNT]);
#endif /* __ASM_MICROBLAZE_PVR_H */

View File

@ -57,9 +57,7 @@ static void boot_jump_linux(bootm_headers_t *images, int flag)
"(fake run for tracing)" : "");
bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
#ifdef XILINX_USE_DCACHE
flush_cache(0, XILINX_DCACHE_BYTE_SIZE);
#endif
flush_cache_all();
if (!fake) {
/*

View File

@ -180,24 +180,6 @@ source "arch/mips/mach-octeon/Kconfig"
if MIPS
choice
prompt "Endianness selection"
help
Some MIPS boards can be configured for either little or big endian
byte order. These modes require different U-Boot images. In general there
is one preferred byteorder for a particular system but some systems are
just as commonly used in the one or the other endianness.
config SYS_BIG_ENDIAN
bool "Big endian"
depends on SUPPORTS_BIG_ENDIAN
config SYS_LITTLE_ENDIAN
bool "Little endian"
depends on SUPPORTS_LITTLE_ENDIAN
endchoice
choice
prompt "CPU selection"
default CPU_MIPS32_R2

View File

@ -5,6 +5,9 @@
#
obj-y += board.o
ifndef CONFIG_ARCH_ZYNQ
obj-$(CONFIG_DISPLAY_CPUINFO) += cpu-info.o
endif
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_CMD_FRU) += fru.o fru_ops.o
endif

View File

@ -485,31 +485,6 @@ int __maybe_unused board_fit_config_name_match(const char *name)
return -1;
}
#if defined(CONFIG_DISPLAY_CPUINFO) && !defined(CONFIG_ARCH_ZYNQ)
int print_cpuinfo(void)
{
struct udevice *soc;
char name[SOC_MAX_STR_SIZE];
int ret;
ret = soc_get(&soc);
if (ret) {
printf("CPU: UNKNOWN\n");
return 0;
}
ret = soc_get_family(soc, name, SOC_MAX_STR_SIZE);
if (ret)
printf("CPU: %s\n", name);
ret = soc_get_revision(soc, name, SOC_MAX_STR_SIZE);
if (ret)
printf("Silicon: %s\n", name);
return 0;
}
#endif
#if CONFIG_IS_ENABLED(DTB_RESELECT)
#define MAX_NAME_LENGTH 50

View File

@ -0,0 +1,35 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2014 - 2020 Xilinx, Inc.
* Michal Simek <michal.simek@xilinx.com>
*/
#include <common.h>
#include <soc.h>
int print_cpuinfo(void)
{
struct udevice *soc;
char name[SOC_MAX_STR_SIZE];
int ret;
ret = soc_get(&soc);
if (ret) {
printf("CPU: UNKNOWN\n");
return 0;
}
ret = soc_get_family(soc, name, SOC_MAX_STR_SIZE);
if (ret)
printf("CPU: %s\n", name);
ret = soc_get_revision(soc, name, SOC_MAX_STR_SIZE);
if (ret)
printf("Silicon: %s\n", name);
ret = soc_get_machine(soc, name, SOC_MAX_STR_SIZE);
if (ret)
printf("Chip: %s\n", name);
return 0;
}

View File

@ -38,6 +38,14 @@ config XILINX_MICROBLAZE0_HW_VER
string "Core version number"
default "7.10.d"
config XILINX_MICROBLAZE0_FPGA_FAMILY
string "Targeted FPGA family"
default "virtex5"
help
This option contains info about the target FPGA architecture
(Zynq-7000, UltraScale+ Kintex, etc) that the MicroBlaze soft core is
implemented on. It corresponds to the C_FAMILY hdl parameter.
config XILINX_MICROBLAZE0_USR_EXCEP
bool "MicroBlaze user exception support"
default y
@ -63,4 +71,50 @@ config XILINX_MICROBLAZE0_VECTOR_BASE_ADDR
Memory address location of the exception vector table. It is
configurable via the C_BASE_VECTORS hdl parameter.
config XILINX_MICROBLAZE0_USE_WDC
bool "MicroBlaze wdc instruction support"
default y
help
Enable this option if the MicroBlaze processor is configured with
support for the "wdc" (Write to Data Cache) instruction.
config SPL_XILINX_MICROBLAZE0_USE_WDC
bool
default XILINX_MICROBLAZE0_USE_WDC
config XILINX_MICROBLAZE0_USE_WIC
bool "MicroBlaze wic instruction support"
default y
help
Enable this option if the MicroBlaze processor is configured with
support for the "wic" (Write to Instruction Cache) instruction.
config SPL_XILINX_MICROBLAZE0_USE_WIC
bool
default XILINX_MICROBLAZE0_USE_WIC
config XILINX_MICROBLAZE0_DCACHE_SIZE
int "Default data cache size"
default 32768
help
This fallback size will be used when no dcache info can be found in
the device tree, or when the data cache is flushed very early in the
boot process, before device tree is available.
config XILINX_MICROBLAZE0_ICACHE_SIZE
int "Default instruction cache size"
default 32768
help
This fallback size will be used when no icache info can be found in
the device tree, or when the instruction cache is flushed very early
in the boot process, before device tree is available.
config XILINX_MICROBLAZE0_PVR
bool "MicroBlaze PVR support"
help
Enables helper functions and macros needed to manipulate PVR
(Processor Version Register) data. Currently, only the microblaze
UCLASS_CPU driver makes use of this feature to retrieve CPU info at
runtime.
endif

View File

@ -91,6 +91,23 @@ int board_early_init_r(void)
return 0;
}
unsigned long do_go_exec(ulong (*entry)(int, char * const []), int argc,
char *const argv[])
{
int ret = 0;
if (current_el() > 1) {
smp_kick_all_cpus();
dcache_disable();
armv8_switch_to_el1(0x0, 0, 0, 0, (unsigned long)entry,
ES_TO_AARCH64);
} else {
printf("FAIL: current EL is not above EL1\n");
ret = EINVAL;
}
return ret;
}
static u8 versal_get_bootmode(void)
{
u8 bootmode;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -19,6 +19,7 @@
#include <sata.h>
#include <ahci.h>
#include <scsi.h>
#include <soc.h>
#include <malloc.h>
#include <memalign.h>
#include <wdt.h>
@ -44,278 +45,10 @@
#include "pm_cfg_obj.h"
#define ZYNQMP_VERSION_SIZE 7
#define EFUSE_VCU_DIS_MASK 0x100
#define EFUSE_VCU_DIS_SHIFT 8
#define EFUSE_GPU_DIS_MASK 0x20
#define EFUSE_GPU_DIS_SHIFT 5
#define IDCODE2_PL_INIT_MASK 0x200
#define IDCODE2_PL_INIT_SHIFT 9
DECLARE_GLOBAL_DATA_PTR;
#if CONFIG_IS_ENABLED(FPGA) && defined(CONFIG_FPGA_ZYNQMPPL)
static xilinx_desc zynqmppl = XILINX_ZYNQMP_DESC;
enum {
ZYNQMP_VARIANT_EG = BIT(0U),
ZYNQMP_VARIANT_EV = BIT(1U),
ZYNQMP_VARIANT_CG = BIT(2U),
ZYNQMP_VARIANT_DR = BIT(3U),
};
static const struct {
u32 id;
u8 device;
u8 variants;
} zynqmp_devices[] = {
{
.id = 0x04688093,
.device = 1,
.variants = ZYNQMP_VARIANT_EG,
},
{
.id = 0x04711093,
.device = 2,
.variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG,
},
{
.id = 0x04710093,
.device = 3,
.variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG,
},
{
.id = 0x04721093,
.device = 4,
.variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG |
ZYNQMP_VARIANT_EV,
},
{
.id = 0x04720093,
.device = 5,
.variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG |
ZYNQMP_VARIANT_EV,
},
{
.id = 0x04739093,
.device = 6,
.variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG,
},
{
.id = 0x04730093,
.device = 7,
.variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG |
ZYNQMP_VARIANT_EV,
},
{
.id = 0x04738093,
.device = 9,
.variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG,
},
{
.id = 0x04740093,
.device = 11,
.variants = ZYNQMP_VARIANT_EG,
},
{
.id = 0x04750093,
.device = 15,
.variants = ZYNQMP_VARIANT_EG,
},
{
.id = 0x04759093,
.device = 17,
.variants = ZYNQMP_VARIANT_EG,
},
{
.id = 0x04758093,
.device = 19,
.variants = ZYNQMP_VARIANT_EG,
},
{
.id = 0x047E1093,
.device = 21,
.variants = ZYNQMP_VARIANT_DR,
},
{
.id = 0x047E3093,
.device = 23,
.variants = ZYNQMP_VARIANT_DR,
},
{
.id = 0x047E5093,
.device = 25,
.variants = ZYNQMP_VARIANT_DR,
},
{
.id = 0x047E4093,
.device = 27,
.variants = ZYNQMP_VARIANT_DR,
},
{
.id = 0x047E0093,
.device = 28,
.variants = ZYNQMP_VARIANT_DR,
},
{
.id = 0x047E2093,
.device = 29,
.variants = ZYNQMP_VARIANT_DR,
},
{
.id = 0x047E6093,
.device = 39,
.variants = ZYNQMP_VARIANT_DR,
},
{
.id = 0x047FD093,
.device = 43,
.variants = ZYNQMP_VARIANT_DR,
},
{
.id = 0x047F8093,
.device = 46,
.variants = ZYNQMP_VARIANT_DR,
},
{
.id = 0x047FF093,
.device = 47,
.variants = ZYNQMP_VARIANT_DR,
},
{
.id = 0x047FB093,
.device = 48,
.variants = ZYNQMP_VARIANT_DR,
},
{
.id = 0x047FE093,
.device = 49,
.variants = ZYNQMP_VARIANT_DR,
},
{
.id = 0x046d0093,
.device = 67,
.variants = ZYNQMP_VARIANT_DR,
},
};
static const struct {
u32 id;
char *name;
} zynqmp_svd_devices[] = {
{
.id = 0x04714093,
.name = "xck24"
},
{
.id = 0x04724093,
.name = "xck26",
},
};
static char *zynqmp_detect_svd_name(u32 idcode)
{
u32 i;
for (i = 0; i < ARRAY_SIZE(zynqmp_svd_devices); i++) {
if (zynqmp_svd_devices[i].id == (idcode & 0x0FFFFFFF))
return zynqmp_svd_devices[i].name;
}
return "unknown";
}
static char *zynqmp_get_silicon_idcode_name(void)
{
u32 i;
u32 idcode, idcode2;
char name[ZYNQMP_VERSION_SIZE];
u32 ret_payload[PAYLOAD_ARG_CNT];
int ret;
ret = xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0, ret_payload);
if (ret) {
debug("%s: Getting chipid failed\n", __func__);
return "unknown";
}
/*
* Firmware returns:
* payload[0][31:0] = status of the operation
* payload[1]] = IDCODE
* payload[2][19:0] = Version
* payload[2][28:20] = EXTENDED_IDCODE
* payload[2][29] = PL_INIT
*/
idcode = ret_payload[1];
idcode2 = ret_payload[2] >> ZYNQMP_CSU_VERSION_EMPTY_SHIFT;
debug("%s, IDCODE: 0x%0x, IDCODE2: 0x%0x\r\n", __func__, idcode,
idcode2);
for (i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) {
if (zynqmp_devices[i].id == (idcode & 0x0FFFFFFF))
break;
}
if (i >= ARRAY_SIZE(zynqmp_devices))
return zynqmp_detect_svd_name(idcode);
/* Add device prefix to the name */
ret = snprintf(name, ZYNQMP_VERSION_SIZE, "zu%d",
zynqmp_devices[i].device);
if (ret < 0)
return "unknown";
if (zynqmp_devices[i].variants & ZYNQMP_VARIANT_EV) {
/* Devices with EV variant might be EG/CG/EV family */
if (idcode2 & IDCODE2_PL_INIT_MASK) {
u32 family = ((idcode2 & EFUSE_VCU_DIS_MASK) >>
EFUSE_VCU_DIS_SHIFT) << 1 |
((idcode2 & EFUSE_GPU_DIS_MASK) >>
EFUSE_GPU_DIS_SHIFT);
/*
* Get family name based on extended idcode values as
* determined on UG1087, EXTENDED_IDCODE register
* description
*/
switch (family) {
case 0x00:
strncat(name, "ev", 2);
break;
case 0x10:
strncat(name, "eg", 2);
break;
case 0x11:
strncat(name, "cg", 2);
break;
default:
/* Do not append family name*/
break;
}
} else {
/*
* When PL powered down the VCU Disable efuse cannot be
* read. So, ignore the bit and just findout if it is CG
* or EG/EV variant.
*/
strncat(name, (idcode2 & EFUSE_GPU_DIS_MASK) ? "cg" :
"e", 2);
}
} else if (zynqmp_devices[i].variants & ZYNQMP_VARIANT_CG) {
/* Devices with CG variant might be EG or CG family */
strncat(name, (idcode2 & EFUSE_GPU_DIS_MASK) ? "cg" : "eg", 2);
} else if (zynqmp_devices[i].variants & ZYNQMP_VARIANT_EG) {
strncat(name, "eg", 2);
} else if (zynqmp_devices[i].variants & ZYNQMP_VARIANT_DR) {
strncat(name, "dr", 2);
} else {
debug("Variant not identified\n");
}
return strdup(name);
}
#endif
int __maybe_unused psu_uboot_init(void)
@ -406,6 +139,11 @@ static void print_secure_boot(void)
int board_init(void)
{
#if CONFIG_IS_ENABLED(FPGA) && defined(CONFIG_FPGA_ZYNQMPPL)
struct udevice *soc;
char name[SOC_MAX_STR_SIZE];
int ret;
#endif
#if defined(CONFIG_ZYNQMP_FIRMWARE)
struct udevice *dev;
@ -432,10 +170,15 @@ int board_init(void)
printf("EL Level:\tEL%d\n", current_el());
#if CONFIG_IS_ENABLED(FPGA) && defined(CONFIG_FPGA_ZYNQMPPL)
zynqmppl.name = zynqmp_get_silicon_idcode_name();
printf("Chip ID:\t%s\n", zynqmppl.name);
fpga_init();
fpga_add(fpga_xilinx, &zynqmppl);
ret = soc_get(&soc);
if (!ret) {
ret = soc_get_machine(soc, name, sizeof(name));
if (ret >= 0) {
zynqmppl.name = strdup(name);
fpga_init();
fpga_add(fpga_xilinx, &zynqmppl);
}
}
#endif
/* display secure boot information */
@ -924,6 +667,7 @@ void set_dfu_alt_info(char *interface, char *devstr)
bootseq, multiboot, bootseq,
CONFIG_SPL_FS_LOAD_PAYLOAD_NAME, bootseq);
break;
#if defined(CONFIG_SYS_SPI_U_BOOT_OFFS)
case QSPI_MODE_24BIT:
case QSPI_MODE_32BIT:
snprintf(buf, DFU_ALT_BUF_LEN,
@ -932,6 +676,7 @@ void set_dfu_alt_info(char *interface, char *devstr)
multiboot * SZ_32K, CONFIG_SPL_FS_LOAD_PAYLOAD_NAME,
CONFIG_SYS_SPI_U_BOOT_OFFS);
break;
#endif
default:
return;
}

View File

@ -82,36 +82,13 @@ static int do_cpu_detail(struct cmd_tbl *cmdtp, int flag, int argc,
return 0;
}
static struct cmd_tbl cmd_cpu_sub[] = {
U_BOOT_CMD_MKENT(list, 2, 1, do_cpu_list, "", ""),
U_BOOT_CMD_MKENT(detail, 4, 0, do_cpu_detail, "", ""),
};
/*
* Process a cpu sub-command
*/
static int do_cpu(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
struct cmd_tbl *c = NULL;
/* Strip off leading 'cpu' command argument */
argc--;
argv++;
if (argc)
c = find_cmd_tbl(argv[0], cmd_cpu_sub,
ARRAY_SIZE(cmd_cpu_sub));
if (c)
return c->cmd(cmdtp, flag, argc, argv);
else
return CMD_RET_USAGE;
}
U_BOOT_CMD(
cpu, 2, 1, do_cpu,
"display information about CPUs",
#if CONFIG_IS_ENABLED(SYS_LONGHELP)
static char cpu_help_text[] =
"list - list available CPUs\n"
"cpu detail - show CPU detail"
);
;
#endif
U_BOOT_CMD_WITH_SUBCMDS(cpu, "display information about CPUs", cpu_help_text,
U_BOOT_SUBCMD_MKENT(list, 1, 1, do_cpu_list),
U_BOOT_SUBCMD_MKENT(detail, 1, 0, do_cpu_detail));

View File

@ -684,6 +684,8 @@ static int setup_reloc(void)
#ifdef CONFIG_SYS_TEXT_BASE
#ifdef ARM
gd->reloc_off = gd->relocaddr - (unsigned long)__image_copy_start;
#elif defined(CONFIG_MICROBLAZE)
gd->reloc_off = gd->relocaddr - (u32)_start;
#elif defined(CONFIG_M68K)
/*
* On all ColdFire arch cpu, monitor code starts always

View File

@ -14,6 +14,7 @@ CONFIG_XILINX_MICROBLAZE0_USE_BARREL=1
CONFIG_XILINX_MICROBLAZE0_USE_DIV=1
CONFIG_XILINX_MICROBLAZE0_USE_HW_MUL=1
CONFIG_DISTRO_DEFAULTS=y
CONFIG_REMAKE_ELF=y
CONFIG_FIT=y
CONFIG_FIT_VERBOSE=y
CONFIG_BOOTDELAY=-1
@ -84,6 +85,7 @@ CONFIG_PHY_NATSEMI=y
CONFIG_PHY_REALTEK=y
CONFIG_PHY_VITESSE=y
CONFIG_DM_ETH=y
CONFIG_DM_ETH_PHY=y
CONFIG_XILINX_AXIEMAC=y
CONFIG_XILINX_EMACLITE=y
CONFIG_SYS_NS16550=y

View File

@ -46,6 +46,7 @@ CONFIG_CMD_EFIDEBUG=y
CONFIG_CMD_TIME=y
CONFIG_CMD_TIMER=y
CONFIG_CMD_EXT4_WRITE=y
CONFIG_CMD_SQUASHFS=y
CONFIG_CMD_MTDPARTS=y
CONFIG_CMD_UBI=y
CONFIG_PARTITION_TYPE_GUID=y
@ -94,6 +95,7 @@ CONFIG_PHY_REALTEK=y
CONFIG_PHY_TI_DP83867=y
CONFIG_PHY_VITESSE=y
CONFIG_PHY_FIXED=y
CONFIG_DM_ETH_PHY=y
CONFIG_PHY_GIGE=y
CONFIG_XILINX_AXIEMAC=y
CONFIG_XILINX_AXIMRMAC=y

View File

@ -71,6 +71,7 @@ CONFIG_CMD_EFIDEBUG=y
CONFIG_CMD_TIME=y
CONFIG_CMD_TIMER=y
CONFIG_CMD_EXT4_WRITE=y
CONFIG_CMD_SQUASHFS=y
CONFIG_CMD_MTDPARTS=y
CONFIG_CMD_MTDPARTS_SPREAD=y
CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES=y
@ -124,6 +125,7 @@ CONFIG_PHY_MICREL=y
CONFIG_PHY_MICREL_KSZ90X1=y
CONFIG_PHY_REALTEK=y
CONFIG_PHY_XILINX=y
CONFIG_DM_ETH_PHY=y
CONFIG_MII=y
CONFIG_ZYNQ_GEM=y
CONFIG_ARM_DCC=y

View File

@ -94,6 +94,7 @@ CONFIG_CMD_TIMER=y
CONFIG_CMD_REGULATOR=y
CONFIG_CMD_TPM=y
CONFIG_CMD_EXT4_WRITE=y
CONFIG_CMD_SQUASHFS=y
CONFIG_CMD_MTDPARTS=y
CONFIG_CMD_MTDPARTS_SPREAD=y
CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES=y
@ -175,6 +176,7 @@ CONFIG_PHY_TI_DP83867=y
CONFIG_PHY_VITESSE=y
CONFIG_PHY_XILINX_GMII2RGMII=y
CONFIG_PHY_FIXED=y
CONFIG_DM_ETH_PHY=y
CONFIG_XILINX_AXIEMAC=y
CONFIG_ZYNQ_GEM=y
CONFIG_DM_REGULATOR=y

View File

@ -328,13 +328,8 @@ static void *alloc_priv(int size, uint flags)
* within this range at the start. The driver can then
* use normal flush-after-write, invalidate-before-read
* procedures.
*
* TODO(sjg@chromium.org): Drop this microblaze
* exception.
*/
#ifndef CONFIG_MICROBLAZE
flush_dcache_range((ulong)priv, (ulong)priv + size);
#endif
}
} else {
priv = calloc(1, size);

View File

@ -19,3 +19,12 @@ config CPU_RISCV
depends on CPU && RISCV
help
Support CPU cores for RISC-V architecture.
config CPU_MICROBLAZE
bool "Enable Microblaze CPU driver"
depends on CPU && MICROBLAZE
select EVENT
select DM_EVENT
select XILINX_MICROBLAZE0_PVR
help
Support CPU cores for Microblaze architecture.

View File

@ -11,4 +11,5 @@ obj-$(CONFIG_ARCH_IMX8) += imx8_cpu.o
obj-$(CONFIG_ARCH_AT91) += at91_cpu.o
obj-$(CONFIG_CPU_MPC83XX) += mpc83xx_cpu.o
obj-$(CONFIG_CPU_RISCV) += riscv_cpu.o
obj-$(CONFIG_CPU_MICROBLAZE) += microblaze_cpu.o
obj-$(CONFIG_SANDBOX) += cpu_sandbox.o

View File

@ -14,6 +14,9 @@
#include <dm/lists.h>
#include <dm/root.h>
#include <linux/err.h>
#include <relocate.h>
DECLARE_GLOBAL_DATA_PTR;
int cpu_probe_all(void)
{
@ -136,9 +139,36 @@ static int uclass_cpu_init(struct uclass *uc)
return ret;
}
static int uclass_cpu_post_bind(struct udevice *dev)
{
if (IS_ENABLED(CONFIG_NEEDS_MANUAL_RELOC) &&
(gd->flags & GD_FLG_RELOC)) {
struct cpu_ops *ops = cpu_get_ops(dev);
static int reloc_done;
if (!reloc_done) {
if (ops->get_desc)
MANUAL_RELOC(ops->get_desc);
if (ops->get_info)
MANUAL_RELOC(ops->get_info);
if (ops->get_count)
MANUAL_RELOC(ops->get_count);
if (ops->get_vendor)
MANUAL_RELOC(ops->get_vendor);
if (ops->is_current)
MANUAL_RELOC(ops->is_current);
reloc_done++;
}
}
return 0;
}
UCLASS_DRIVER(cpu) = {
.id = UCLASS_CPU,
.name = "cpu",
.flags = DM_UC_FLAG_SEQ_ALIAS,
.init = uclass_cpu_init,
.post_bind = uclass_cpu_post_bind,
};

View File

@ -0,0 +1,180 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2022, Ovidiu Panait <ovpanait@gmail.com>
*/
#include <common.h>
#include <cpu.h>
#include <dm.h>
#include <asm/cpuinfo.h>
#include <asm/global_data.h>
#include <asm/pvr.h>
DECLARE_GLOBAL_DATA_PTR;
#define update_cpuinfo_pvr(pvr, ci, name) \
{ \
u32 tmp = PVR_##name(pvr); \
if (ci != tmp) \
printf("PVR value for " #name " does not match static data!\n");\
ci = tmp; \
}
static int microblaze_cpu_probe_all(void *ctx, struct event *event)
{
int ret;
ret = cpu_probe_all();
if (ret)
return log_msg_ret("Microblaze cpus probe failed\n", ret);
return 0;
}
EVENT_SPY(EVT_DM_POST_INIT, microblaze_cpu_probe_all);
static void microblaze_set_cpuinfo_pvr(struct microblaze_cpuinfo *ci)
{
u32 pvr[PVR_FULL_COUNT];
microblaze_get_all_pvrs(pvr);
update_cpuinfo_pvr(pvr, ci->icache_size, ICACHE_BYTE_SIZE);
update_cpuinfo_pvr(pvr, ci->icache_line_length, ICACHE_LINE_LEN);
update_cpuinfo_pvr(pvr, ci->dcache_size, DCACHE_BYTE_SIZE);
update_cpuinfo_pvr(pvr, ci->dcache_line_length, DCACHE_LINE_LEN);
update_cpuinfo_pvr(pvr, ci->use_mmu, USE_MMU);
update_cpuinfo_pvr(pvr, ci->ver_code, VERSION);
update_cpuinfo_pvr(pvr, ci->fpga_code, TARGET_FAMILY);
}
static void microblaze_set_cpuinfo_static(struct udevice *dev,
struct microblaze_cpuinfo *ci)
{
const char *hw_ver = CONFIG_XILINX_MICROBLAZE0_HW_VER;
const char *fpga_family = CONFIG_XILINX_MICROBLAZE0_FPGA_FAMILY;
ci->icache_size = dev_read_u32_default(dev, "i-cache-size", 0);
ci->icache_line_length = dev_read_u32_default(dev,
"i-cache-line-size", 0);
ci->dcache_size = dev_read_u32_default(dev, "d-cache-size", 0);
ci->dcache_line_length = dev_read_u32_default(dev,
"d-cache-line-size", 0);
ci->cpu_freq = dev_read_u32_default(dev, "clock-frequency", 0);
ci->addr_size = dev_read_u32_default(dev, "xlnx,addr-size", 32);
ci->use_mmu = dev_read_u32_default(dev, "xlnx,use-mmu", 0);
ci->ver_code = microblaze_lookup_cpu_version_code(hw_ver);
ci->fpga_code = microblaze_lookup_fpga_family_code(fpga_family);
}
static int microblaze_cpu_probe(struct udevice *dev)
{
microblaze_set_cpuinfo_static(dev, gd_cpuinfo());
if (microblaze_cpu_has_pvr_full())
microblaze_set_cpuinfo_pvr(gd_cpuinfo());
else
debug("No PVR support. Using only static CPU info.\n");
return 0;
}
static int microblaze_cpu_get_desc(const struct udevice *dev, char *buf,
int size)
{
struct microblaze_cpuinfo *ci = gd_cpuinfo();
const char *cpu_ver, *fpga_family;
u32 cpu_freq_mhz;
int ret;
cpu_freq_mhz = ci->cpu_freq / 1000000;
cpu_ver = microblaze_lookup_cpu_version_string(ci->ver_code);
fpga_family = microblaze_lookup_fpga_family_string(ci->fpga_code);
ret = snprintf(buf, size,
"MicroBlaze @ %uMHz, Rev: %s, FPGA family: %s",
cpu_freq_mhz, cpu_ver, fpga_family);
return 0;
}
static int microblaze_cpu_get_info(const struct udevice *dev,
struct cpu_info *info)
{
struct microblaze_cpuinfo *ci = gd_cpuinfo();
info->cpu_freq = ci->cpu_freq;
info->address_width = ci->addr_size;
if (ci->icache_size || ci->dcache_size)
info->features |= BIT(CPU_FEAT_L1_CACHE);
if (ci->use_mmu)
info->features |= BIT(CPU_FEAT_MMU);
return 0;
}
static int microblaze_cpu_get_count(const struct udevice *dev)
{
return 1;
}
static const struct cpu_ops microblaze_cpu_ops = {
.get_desc = microblaze_cpu_get_desc,
.get_info = microblaze_cpu_get_info,
.get_count = microblaze_cpu_get_count,
};
static const struct udevice_id microblaze_cpu_ids[] = {
{ .compatible = "xlnx,microblaze-11.0" },
{ .compatible = "xlnx,microblaze-10.0" },
{ .compatible = "xlnx,microblaze-9.6" },
{ .compatible = "xlnx,microblaze-9.5" },
{ .compatible = "xlnx,microblaze-9.4" },
{ .compatible = "xlnx,microblaze-9.3" },
{ .compatible = "xlnx,microblaze-9.2" },
{ .compatible = "xlnx,microblaze-9.1" },
{ .compatible = "xlnx,microblaze-9.0" },
{ .compatible = "xlnx,microblaze-8.50.c" },
{ .compatible = "xlnx,microblaze-8.50.b" },
{ .compatible = "xlnx,microblaze-8.50.a" },
{ .compatible = "xlnx,microblaze-8.40.b" },
{ .compatible = "xlnx,microblaze-8.40.a" },
{ .compatible = "xlnx,microblaze-8.30.a" },
{ .compatible = "xlnx,microblaze-8.20.b" },
{ .compatible = "xlnx,microblaze-8.20.a" },
{ .compatible = "xlnx,microblaze-8.10.a" },
{ .compatible = "xlnx,microblaze-8.00.b" },
{ .compatible = "xlnx,microblaze-8.00.a" },
{ .compatible = "xlnx,microblaze-7.30.b" },
{ .compatible = "xlnx,microblaze-7.30.a" },
{ .compatible = "xlnx,microblaze-7.20.d" },
{ .compatible = "xlnx,microblaze-7.20.c" },
{ .compatible = "xlnx,microblaze-7.20.b" },
{ .compatible = "xlnx,microblaze-7.20.a" },
{ .compatible = "xlnx,microblaze-7.10.d" },
{ .compatible = "xlnx,microblaze-7.10.c" },
{ .compatible = "xlnx,microblaze-7.10.b" },
{ .compatible = "xlnx,microblaze-7.10.a" },
{ .compatible = "xlnx,microblaze-7.00.b" },
{ .compatible = "xlnx,microblaze-7.00.a" },
{ .compatible = "xlnx,microblaze-6.00.b" },
{ .compatible = "xlnx,microblaze-6.00.a" },
{ .compatible = "xlnx,microblaze-5.00.c" },
{ .compatible = "xlnx,microblaze-5.00.b" },
{ .compatible = "xlnx,microblaze-5.00.a" },
{ }
};
U_BOOT_DRIVER(microblaze_cpu) = {
.name = "microblaze_cpu",
.id = UCLASS_CPU,
.of_match = microblaze_cpu_ids,
.probe = microblaze_cpu_probe,
.ops = &microblaze_cpu_ops,
.flags = DM_FLAG_PRE_RELOC,
};

View File

@ -26,7 +26,7 @@
struct zynqmp_power {
struct mbox_chan tx_chan;
struct mbox_chan rx_chan;
} zynqmp_power;
} zynqmp_power = {};
#define NODE_ID_LOCATION 5
@ -79,6 +79,20 @@ int zynqmp_pmufw_node(u32 id)
return 0;
}
static int do_pm_probe(void)
{
struct udevice *dev;
int ret;
ret = uclass_get_device_by_driver(UCLASS_FIRMWARE,
DM_DRIVER_GET(zynqmp_power),
&dev);
if (ret)
debug("%s: Probing device failed: %d\n", __func__, ret);
return ret;
}
static int ipi_req(const u32 *req, size_t req_len, u32 *res, size_t res_maxlen)
{
struct zynqmp_ipi_msg msg;
@ -92,8 +106,11 @@ static int ipi_req(const u32 *req, size_t req_len, u32 *res, size_t res_maxlen)
res_maxlen > PMUFW_PAYLOAD_ARG_CNT)
return -EINVAL;
if (!(zynqmp_power.tx_chan.dev) || !(&zynqmp_power.rx_chan.dev))
return -EINVAL;
if (!(zynqmp_power.tx_chan.dev) || !(zynqmp_power.rx_chan.dev)) {
ret = do_pm_probe();
if (ret)
return ret;
}
debug("%s, Sending IPI message with ID: 0x%0x\n", __func__, req[0]);
msg.buf = (u32 *)req;

View File

@ -19,6 +19,7 @@
#include <miiphy.h>
#include <wait_bit.h>
#include <linux/delay.h>
#include <eth_phy.h>
DECLARE_GLOBAL_DATA_PTR;
@ -295,6 +296,9 @@ static int axiemac_phy_init(struct udevice *dev)
/* Set default MDIO divisor */
writel(XAE_MDIO_DIV_DFT | XAE_MDIO_MC_MDIOEN_MASK, &regs->mdio_mc);
if (IS_ENABLED(CONFIG_DM_ETH_PHY))
priv->phyaddr = eth_phy_get_addr(dev);
if (priv->phyaddr == -1) {
/* Detect the PHY address */
for (i = 31; i >= 0; i--) {
@ -778,18 +782,29 @@ static int axi_emac_probe(struct udevice *dev)
priv->phy_of_handle = plat->phy_of_handle;
priv->interface = pdata->phy_interface;
priv->bus = mdio_alloc();
priv->bus->read = axiemac_miiphy_read;
priv->bus->write = axiemac_miiphy_write;
priv->bus->priv = priv;
if (IS_ENABLED(CONFIG_DM_ETH_PHY))
priv->bus = eth_phy_get_mdio_bus(dev);
ret = mdio_register_seq(priv->bus, dev_seq(dev));
if (ret)
return ret;
if (!priv->bus) {
priv->bus = mdio_alloc();
priv->bus->read = axiemac_miiphy_read;
priv->bus->write = axiemac_miiphy_write;
priv->bus->priv = priv;
ret = mdio_register_seq(priv->bus, dev_seq(dev));
if (ret)
return ret;
}
if (IS_ENABLED(CONFIG_DM_ETH_PHY))
eth_phy_set_mdio_bus(dev, priv->bus);
axiemac_phy_init(dev);
}
printf("AXI EMAC: %lx, phyaddr %d, interface %s\n", (ulong)pdata->iobase,
priv->phyaddr, phy_string_for_interface(pdata->phy_interface));
return 0;
}
@ -844,8 +859,10 @@ static int axi_emac_of_to_plat(struct udevice *dev)
offset = fdtdec_lookup_phandle(gd->fdt_blob, node,
"phy-handle");
if (offset > 0) {
plat->phyaddr = fdtdec_get_int(gd->fdt_blob, offset,
"reg", -1);
if (!(IS_ENABLED(CONFIG_DM_ETH_PHY)))
plat->phyaddr = fdtdec_get_int(gd->fdt_blob,
offset,
"reg", -1);
plat->phy_of_handle = offset;
}
@ -857,9 +874,6 @@ static int axi_emac_of_to_plat(struct udevice *dev)
"xlnx,eth-hasnobuf");
}
printf("AXI EMAC: %lx, phyaddr %d, interface %s\n", (ulong)pdata->iobase,
plat->phyaddr, phy_string_for_interface(pdata->phy_interface));
return 0;
}

View File

@ -22,6 +22,7 @@
#include <linux/errno.h>
#include <linux/kernel.h>
#include <asm/io.h>
#include <eth_phy.h>
DECLARE_GLOBAL_DATA_PTR;
@ -564,14 +565,27 @@ static int emaclite_probe(struct udevice *dev)
struct xemaclite *emaclite = dev_get_priv(dev);
int ret;
emaclite->bus = mdio_alloc();
emaclite->bus->read = emaclite_miiphy_read;
emaclite->bus->write = emaclite_miiphy_write;
emaclite->bus->priv = emaclite;
if (IS_ENABLED(CONFIG_DM_ETH_PHY))
emaclite->bus = eth_phy_get_mdio_bus(dev);
ret = mdio_register_seq(emaclite->bus, dev_seq(dev));
if (ret)
return ret;
if (!emaclite->bus) {
emaclite->bus = mdio_alloc();
emaclite->bus->read = emaclite_miiphy_read;
emaclite->bus->write = emaclite_miiphy_write;
emaclite->bus->priv = emaclite;
ret = mdio_register_seq(emaclite->bus, dev_seq(dev));
if (ret)
return ret;
}
if (IS_ENABLED(CONFIG_DM_ETH_PHY)) {
eth_phy_set_mdio_bus(dev, emaclite->bus);
emaclite->phyaddr = eth_phy_get_addr(dev);
}
printf("EMACLITE: %lx, phyaddr %d, %d/%d\n", (ulong)emaclite->regs,
emaclite->phyaddr, emaclite->txpp, emaclite->rxpp);
return 0;
}
@ -606,20 +620,19 @@ static int emaclite_of_to_plat(struct udevice *dev)
emaclite->phyaddr = -1;
offset = fdtdec_lookup_phandle(gd->fdt_blob, dev_of_offset(dev),
"phy-handle");
if (offset > 0)
emaclite->phyaddr = fdtdec_get_int(gd->fdt_blob, offset,
"reg", -1);
if (!(IS_ENABLED(CONFIG_DM_ETH_PHY))) {
offset = fdtdec_lookup_phandle(gd->fdt_blob, dev_of_offset(dev),
"phy-handle");
if (offset > 0)
emaclite->phyaddr = fdtdec_get_int(gd->fdt_blob,
offset, "reg", -1);
}
emaclite->txpp = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
"xlnx,tx-ping-pong", 0);
emaclite->rxpp = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
"xlnx,rx-ping-pong", 0);
printf("EMACLITE: %lx, phyaddr %d, %d/%d\n", (ulong)emaclite->regs,
emaclite->phyaddr, emaclite->txpp, emaclite->rxpp);
return 0;
}

View File

@ -467,6 +467,10 @@ static int zynqmp_pinconf_set(struct udevice *dev, unsigned int pin,
pin);
break;
case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
param = PM_PINCTRL_CONFIG_TRI_STATE;
arg = PM_PINCTRL_TRI_STATE_ENABLE;
ret = zynqmp_pm_pinctrl_set_config(pin, param, arg);
break;
case PIN_CONFIG_LOW_POWER_MODE:
/*
* This cases are mentioned in dts but configurable
@ -475,6 +479,11 @@ static int zynqmp_pinconf_set(struct udevice *dev, unsigned int pin,
*/
ret = 0;
break;
case PIN_CONFIG_OUTPUT_ENABLE:
param = PM_PINCTRL_CONFIG_TRI_STATE;
arg = PM_PINCTRL_TRI_STATE_DISABLE;
ret = zynqmp_pm_pinctrl_set_config(pin, param, arg);
break;
default:
dev_warn(dev, "unsupported configuration parameter '%u'\n",
param);

View File

@ -476,6 +476,8 @@ config DEBUG_UART_BASE
depends on DEBUG_UART
default 0 if DEBUG_SBI_CONSOLE
default 0 if DEBUG_UART_SANDBOX
default 0xff000000 if DEBUG_UART_ZYNQ && ARCH_ZYNQMP
default 0xe0000000 if DEBUG_UART_ZYNQ && ARCH_ZYNQ
help
This is the base address of your UART for memory-mapped UARTs.
@ -502,6 +504,8 @@ config DEBUG_UART_CLOCK
default 0 if DEBUG_SBI_CONSOLE
default 0 if DEBUG_UART_SANDBOX
default 0 if DEBUG_MVEBU_A3700_UART
default 100000000 if DEBUG_UART_ZYNQ && ARCH_ZYNQMP
default 50000000 if DEBUG_UART_ZYNQ && ARCH_ZYNQ
help
The UART input clock determines the speed of the internal UART
circuitry. The baud rate is derived from this by dividing the input

View File

@ -3,10 +3,15 @@
* Xilinx ZynqMP SOC driver
*
* Copyright (C) 2021 Xilinx, Inc.
* Michal Simek <michal.simek@xilinx.com>
*
* Copyright (C) 2022 Weidmüller Interface GmbH & Co. KG
* Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
*/
#include <common.h>
#include <dm.h>
#include <dm/device_compat.h>
#include <asm/cache.h>
#include <soc.h>
#include <zynqmp_firmware.h>
@ -22,11 +27,257 @@
*/
static const char zynqmp_family[] = "ZynqMP";
#define EFUSE_VCU_DIS_SHIFT 8
#define EFUSE_VCU_DIS_MASK BIT(EFUSE_VCU_DIS_SHIFT)
#define EFUSE_GPU_DIS_SHIFT 5
#define EFUSE_GPU_DIS_MASK BIT(EFUSE_GPU_DIS_SHIFT)
#define IDCODE_DEV_TYPE_MASK GENMASK(27, 0)
#define IDCODE2_PL_INIT_SHIFT 9
#define IDCODE2_PL_INIT_MASK BIT(IDCODE2_PL_INIT_SHIFT)
#define ZYNQMP_VERSION_SIZE 7
enum {
ZYNQMP_VARIANT_EG = BIT(0),
ZYNQMP_VARIANT_EV = BIT(1),
ZYNQMP_VARIANT_CG = BIT(2),
ZYNQMP_VARIANT_DR = BIT(3),
};
struct zynqmp_device {
u32 id;
u8 device;
u8 variants;
};
struct soc_xilinx_zynqmp_priv {
const char *family;
char machine[ZYNQMP_VERSION_SIZE];
char revision;
};
static const struct zynqmp_device zynqmp_devices[] = {
{
.id = 0x04688093,
.device = 1,
.variants = ZYNQMP_VARIANT_EG,
},
{
.id = 0x04711093,
.device = 2,
.variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG,
},
{
.id = 0x04710093,
.device = 3,
.variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG,
},
{
.id = 0x04721093,
.device = 4,
.variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG |
ZYNQMP_VARIANT_EV,
},
{
.id = 0x04720093,
.device = 5,
.variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG |
ZYNQMP_VARIANT_EV,
},
{
.id = 0x04739093,
.device = 6,
.variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG,
},
{
.id = 0x04730093,
.device = 7,
.variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG |
ZYNQMP_VARIANT_EV,
},
{
.id = 0x04738093,
.device = 9,
.variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG,
},
{
.id = 0x04740093,
.device = 11,
.variants = ZYNQMP_VARIANT_EG,
},
{
.id = 0x04750093,
.device = 15,
.variants = ZYNQMP_VARIANT_EG,
},
{
.id = 0x04759093,
.device = 17,
.variants = ZYNQMP_VARIANT_EG,
},
{
.id = 0x04758093,
.device = 19,
.variants = ZYNQMP_VARIANT_EG,
},
{
.id = 0x047E1093,
.device = 21,
.variants = ZYNQMP_VARIANT_DR,
},
{
.id = 0x047E3093,
.device = 23,
.variants = ZYNQMP_VARIANT_DR,
},
{
.id = 0x047E5093,
.device = 25,
.variants = ZYNQMP_VARIANT_DR,
},
{
.id = 0x047E4093,
.device = 27,
.variants = ZYNQMP_VARIANT_DR,
},
{
.id = 0x047E0093,
.device = 28,
.variants = ZYNQMP_VARIANT_DR,
},
{
.id = 0x047E2093,
.device = 29,
.variants = ZYNQMP_VARIANT_DR,
},
{
.id = 0x047E6093,
.device = 39,
.variants = ZYNQMP_VARIANT_DR,
},
{
.id = 0x047FD093,
.device = 43,
.variants = ZYNQMP_VARIANT_DR,
},
{
.id = 0x047F8093,
.device = 46,
.variants = ZYNQMP_VARIANT_DR,
},
{
.id = 0x047FF093,
.device = 47,
.variants = ZYNQMP_VARIANT_DR,
},
{
.id = 0x047FB093,
.device = 48,
.variants = ZYNQMP_VARIANT_DR,
},
{
.id = 0x047FE093,
.device = 49,
.variants = ZYNQMP_VARIANT_DR,
},
{
.id = 0x046d0093,
.device = 67,
.variants = ZYNQMP_VARIANT_DR,
},
{
.id = 0x04714093,
.device = 24,
.variants = 0,
},
{
.id = 0x04724093,
.device = 26,
.variants = 0,
},
};
static const struct zynqmp_device *zynqmp_get_device(u32 idcode)
{
idcode &= IDCODE_DEV_TYPE_MASK;
for (int i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) {
if (zynqmp_devices[i].id == idcode)
return &zynqmp_devices[i];
}
return NULL;
}
static int soc_xilinx_zynqmp_detect_machine(struct udevice *dev, u32 idcode,
u32 idcode2)
{
struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev);
const struct zynqmp_device *device;
int ret;
device = zynqmp_get_device(idcode);
if (!device)
return 0;
/* Add device prefix to the name */
ret = snprintf(priv->machine, sizeof(priv->machine), "%s%d",
device->variants ? "zu" : "xck", device->device);
if (ret < 0)
return ret;
if (device->variants & ZYNQMP_VARIANT_EV) {
/* Devices with EV variant might be EG/CG/EV family */
if (idcode2 & IDCODE2_PL_INIT_MASK) {
u32 family = ((idcode2 & EFUSE_VCU_DIS_MASK) >>
EFUSE_VCU_DIS_SHIFT) << 1 |
((idcode2 & EFUSE_GPU_DIS_MASK) >>
EFUSE_GPU_DIS_SHIFT);
/*
* Get family name based on extended idcode values as
* determined on UG1087, EXTENDED_IDCODE register
* description
*/
switch (family) {
case 0x00:
strlcat(priv->machine, "ev",
sizeof(priv->machine));
break;
case 0x10:
strlcat(priv->machine, "eg",
sizeof(priv->machine));
break;
case 0x11:
strlcat(priv->machine, "cg",
sizeof(priv->machine));
break;
default:
/* Do not append family name*/
break;
}
} else {
/*
* When PL powered down the VCU Disable efuse cannot be
* read. So, ignore the bit and just findout if it is CG
* or EG/EV variant.
*/
strlcat(priv->machine, (idcode2 & EFUSE_GPU_DIS_MASK) ?
"cg" : "e", sizeof(priv->machine));
}
} else if (device->variants & ZYNQMP_VARIANT_CG) {
/* Devices with CG variant might be EG or CG family */
strlcat(priv->machine, (idcode2 & EFUSE_GPU_DIS_MASK) ?
"cg" : "eg", sizeof(priv->machine));
} else if (device->variants & ZYNQMP_VARIANT_EG) {
strlcat(priv->machine, "eg", sizeof(priv->machine));
} else if (device->variants & ZYNQMP_VARIANT_DR) {
strlcat(priv->machine, "dr", sizeof(priv->machine));
}
return 0;
}
static int soc_xilinx_zynqmp_get_family(struct udevice *dev, char *buf, int size)
{
struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev);
@ -34,6 +285,17 @@ static int soc_xilinx_zynqmp_get_family(struct udevice *dev, char *buf, int size
return snprintf(buf, size, "%s", priv->family);
}
int soc_xilinx_zynqmp_get_machine(struct udevice *dev, char *buf, int size)
{
struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev);
const char *machine = priv->machine;
if (!machine[0])
machine = "unknown";
return snprintf(buf, size, "%s", machine);
}
static int soc_xilinx_zynqmp_get_revision(struct udevice *dev, char *buf, int size)
{
struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev);
@ -44,6 +306,7 @@ static int soc_xilinx_zynqmp_get_revision(struct udevice *dev, char *buf, int si
static const struct soc_ops soc_xilinx_zynqmp_ops = {
.get_family = soc_xilinx_zynqmp_get_family,
.get_revision = soc_xilinx_zynqmp_get_revision,
.get_machine = soc_xilinx_zynqmp_get_machine,
};
static int soc_xilinx_zynqmp_probe(struct udevice *dev)
@ -54,8 +317,7 @@ static int soc_xilinx_zynqmp_probe(struct udevice *dev)
priv->family = zynqmp_family;
if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3 ||
!IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE))
if (!IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE))
ret = zynqmp_mmio_read(ZYNQMP_PS_VERSION, &ret_payload[2]);
else
ret = xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0,
@ -65,6 +327,26 @@ static int soc_xilinx_zynqmp_probe(struct udevice *dev)
priv->revision = ret_payload[2] & ZYNQMP_PS_VER_MASK;
if (IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE)) {
/*
* Firmware returns:
* payload[0][31:0] = status of the operation
* payload[1] = IDCODE
* payload[2][19:0] = Version
* payload[2][28:20] = EXTENDED_IDCODE
* payload[2][29] = PL_INIT
*/
u32 idcode = ret_payload[1];
u32 idcode2 = ret_payload[2] >>
ZYNQMP_CSU_VERSION_EMPTY_SHIFT;
dev_dbg(dev, "IDCODE: 0x%0x, IDCODE2: 0x%0x\n", idcode,
idcode2);
ret = soc_xilinx_zynqmp_detect_machine(dev, idcode, idcode2);
if (ret)
return ret;
}
return 0;
}

View File

@ -279,4 +279,13 @@ config IMX_GPT_TIMER
Select this to enable support for the timer found on
NXP i.MX devices.
config XILINX_TIMER
bool "Xilinx timer support"
depends on TIMER
select REGMAP
select SPL_REGMAP if SPL
help
Select this to enable support for the timer found on
any Xilinx boards (axi timer).
endmenu

View File

@ -28,3 +28,4 @@ obj-$(CONFIG_X86_TSC_TIMER) += tsc_timer.o
obj-$(CONFIG_MTK_TIMER) += mtk_timer.o
obj-$(CONFIG_MCHP_PIT64B_TIMER) += mchp-pit64b-timer.o
obj-$(CONFIG_IMX_GPT_TIMER) += imx-gpt-timer.o
obj-$(CONFIG_XILINX_TIMER) += xilinx-timer.o

View File

@ -0,0 +1,82 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2022 Advanced Micro Devices, Inc
* Michal Simek <michal.simek@amd.com>
*
* (C) Copyright 2007 Michal Simek
* Michal SIMEK <monstr@monstr.eu>
*/
#include <common.h>
#include <dm.h>
#include <timer.h>
#include <regmap.h>
#include <dm/device_compat.h>
#define TIMER_ENABLE_ALL 0x400 /* ENALL */
#define TIMER_PWM 0x200 /* PWMA0 */
#define TIMER_INTERRUPT 0x100 /* T0INT */
#define TIMER_ENABLE 0x080 /* ENT0 */
#define TIMER_ENABLE_INTR 0x040 /* ENIT0 */
#define TIMER_RESET 0x020 /* LOAD0 */
#define TIMER_RELOAD 0x010 /* ARHT0 */
#define TIMER_EXT_CAPTURE 0x008 /* CAPT0 */
#define TIMER_EXT_COMPARE 0x004 /* GENT0 */
#define TIMER_DOWN_COUNT 0x002 /* UDT0 */
#define TIMER_CAPTURE_MODE 0x001 /* MDT0 */
#define TIMER_CONTROL_OFFSET 0
#define TIMER_LOADREG_OFFSET 4
#define TIMER_COUNTER_OFFSET 8
struct xilinx_timer_priv {
struct regmap *regs;
};
static u64 xilinx_timer_get_count(struct udevice *dev)
{
struct xilinx_timer_priv *priv = dev_get_priv(dev);
u32 value;
regmap_read(priv->regs, TIMER_COUNTER_OFFSET, &value);
return value;
}
static int xilinx_timer_probe(struct udevice *dev)
{
struct xilinx_timer_priv *priv = dev_get_priv(dev);
int ret;
/* uc_priv->clock_rate has already clock rate */
ret = regmap_init_mem(dev_ofnode(dev), &priv->regs);
if (ret) {
dev_dbg(dev, "failed to get regbase of timer\n");
return ret;
}
regmap_write(priv->regs, TIMER_LOADREG_OFFSET, 0);
regmap_write(priv->regs, TIMER_CONTROL_OFFSET, TIMER_RESET);
regmap_write(priv->regs, TIMER_CONTROL_OFFSET,
TIMER_ENABLE | TIMER_RELOAD);
return 0;
}
static const struct timer_ops xilinx_timer_ops = {
.get_count = xilinx_timer_get_count,
};
static const struct udevice_id xilinx_timer_ids[] = {
{ .compatible = "xlnx,xps-timer-1.00.a" },
{}
};
U_BOOT_DRIVER(xilinx_timer) = {
.name = "xilinx_timer",
.id = UCLASS_TIMER,
.of_match = xilinx_timer_ids,
.priv_auto = sizeof(struct xilinx_timer_priv),
.probe = xilinx_timer_probe,
.ops = &xilinx_timer_ops,
};

View File

@ -18,10 +18,6 @@
# define CONFIG_SYS_BAUDRATE_TABLE \
{300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400}
/* Stack location before relocation */
#define CONFIG_SYS_INIT_SP_OFFSET (CONFIG_SYS_TEXT_BASE - \
CONFIG_SYS_MALLOC_F_LEN)
#ifdef CONFIG_CFI_FLASH
/* ?empty sector */
# define CONFIG_SYS_FLASH_EMPTY_INFO 1
@ -30,10 +26,6 @@
# define CONFIG_SYS_MAX_FLASH_SECT 2048
#endif
#ifndef XILINX_DCACHE_BYTE_SIZE
#define XILINX_DCACHE_BYTE_SIZE 32768
#endif
#define CONFIG_HOSTNAME "microblaze-generic"
/* architecture dependent code */

View File

@ -20,6 +20,10 @@
#define R_AARCH64_RELATIVE 1027
#endif
static int ei_class;
static uint64_t rela_start, rela_end, text_base, dyn_start;
static const bool debug_en;
static void debug(const char *fmt, ...)
@ -52,58 +56,310 @@ static bool supported_rela(Elf64_Rela *rela)
}
}
static bool read_num(const char *str, uint64_t *num)
static int decode_elf64(FILE *felf, char **argv)
{
char *endptr;
*num = strtoull(str, &endptr, 16);
return str[0] && !endptr[0];
}
size_t size;
Elf64_Ehdr header;
uint64_t section_header_base, section_header_size, sh_offset, sh_size;
Elf64_Shdr *sh_table; /* Elf symbol table */
int ret, i, machine;
char *sh_str;
int main(int argc, char **argv)
{
FILE *f;
int i, num;
uint64_t rela_start, rela_end, text_base, file_size;
debug("64bit version\n");
if (argc != 5) {
fprintf(stderr, "Statically apply ELF rela relocations\n");
fprintf(stderr, "Usage: %s <bin file> <text base> " \
"<rela start> <rela end>\n", argv[0]);
fprintf(stderr, "All numbers in hex.\n");
return 1;
/* Make sure we are at start */
rewind(felf);
size = fread(&header, 1, sizeof(header), felf);
if (size != sizeof(header)) {
fclose(felf);
return 25;
}
f = fopen(argv[1], "r+b");
if (!f) {
machine = header.e_machine;
debug("Machine\t%d\n", machine);
if (machine != EM_AARCH64) {
fprintf(stderr, "%s: Not supported machine type\n", argv[0]);
return 30;
}
text_base = header.e_entry;
section_header_base = header.e_shoff;
section_header_size = header.e_shentsize * header.e_shnum;
sh_table = malloc(section_header_size);
if (!sh_table) {
fprintf(stderr, "%s: Cannot allocate space for section header\n",
argv[0]);
fclose(felf);
return 26;
}
ret = fseek(felf, section_header_base, SEEK_SET);
if (ret) {
fprintf(stderr, "%s: Can't set pointer to section header: %x/%lx\n",
argv[0], ret, section_header_base);
free(sh_table);
fclose(felf);
return 26;
}
size = fread(sh_table, 1, section_header_size, felf);
if (size != section_header_size) {
fprintf(stderr, "%s: Can't read section header: %lx/%lx\n",
argv[0], size, section_header_size);
free(sh_table);
fclose(felf);
return 27;
}
sh_size = sh_table[header.e_shstrndx].sh_size;
debug("e_shstrndx\t0x%08x\n", header.e_shstrndx);
debug("sh_size\t\t0x%08lx\n", sh_size);
sh_str = malloc(sh_size);
if (!sh_str) {
fprintf(stderr, "malloc failed\n");
free(sh_table);
fclose(felf);
return 28;
}
/*
* Specifies the byte offset from the beginning of the file
* to the first byte in the section.
*/
sh_offset = sh_table[header.e_shstrndx].sh_offset;
debug("sh_offset\t0x%08x\n", header.e_shnum);
ret = fseek(felf, sh_offset, SEEK_SET);
if (ret) {
fprintf(stderr, "Setting up sh_offset failed\n");
free(sh_str);
free(sh_table);
fclose(felf);
return 29;
}
size = fread(sh_str, 1, sh_size, felf);
if (size != sh_size) {
fprintf(stderr, "%s: Can't read section: %lx/%lx\n",
argv[0], size, sh_size);
free(sh_str);
free(sh_table);
fclose(felf);
return 30;
}
for (i = 0; i < header.e_shnum; i++) {
/* fprintf(stderr, "%s\n", sh_str + sh_table[i].sh_name); Debug only */
if (!strcmp(".rela.dyn", (sh_str + sh_table[i].sh_name))) {
debug("Found section\t\".rela_dyn\"\n");
debug(" at addr\t0x%08x\n",
(unsigned int)sh_table[i].sh_addr);
debug(" at offset\t0x%08x\n",
(unsigned int)sh_table[i].sh_offset);
debug(" of size\t0x%08x\n",
(unsigned int)sh_table[i].sh_size);
rela_start = sh_table[i].sh_addr;
rela_end = rela_start + sh_table[i].sh_size;
break;
}
}
/* Clean up */
free(sh_str);
free(sh_table);
fclose(felf);
debug("text_base\t0x%08lx\n", text_base);
debug("rela_start\t0x%08lx\n", rela_start);
debug("rela_end\t0x%08lx\n", rela_end);
if (!rela_start)
return 1;
return 0;
}
static int decode_elf32(FILE *felf, char **argv)
{
size_t size;
Elf32_Ehdr header;
uint64_t section_header_base, section_header_size, sh_offset, sh_size;
Elf32_Shdr *sh_table; /* Elf symbol table */
int ret, i, machine;
char *sh_str;
debug("32bit version\n");
/* Make sure we are at start */
rewind(felf);
size = fread(&header, 1, sizeof(header), felf);
if (size != sizeof(header)) {
fclose(felf);
return 25;
}
machine = header.e_machine;
debug("Machine %d\n", machine);
if (machine != EM_MICROBLAZE) {
fprintf(stderr, "%s: Not supported machine type\n", argv[0]);
return 30;
}
text_base = header.e_entry;
section_header_base = header.e_shoff;
debug("Section header base %x\n", section_header_base);
section_header_size = header.e_shentsize * header.e_shnum;
debug("Section header size %d\n", section_header_size);
sh_table = malloc(section_header_size);
if (!sh_table) {
fprintf(stderr, "%s: Cannot allocate space for section header\n",
argv[0]);
fclose(felf);
return 26;
}
ret = fseek(felf, section_header_base, SEEK_SET);
if (ret) {
fprintf(stderr, "%s: Can't set pointer to section header: %x/%lx\n",
argv[0], ret, section_header_base);
free(sh_table);
fclose(felf);
return 26;
}
size = fread(sh_table, 1, section_header_size, felf);
if (size != section_header_size) {
fprintf(stderr, "%s: Can't read section header: %lx/%lx\n",
argv[0], size, section_header_size);
free(sh_table);
fclose(felf);
return 27;
}
sh_size = sh_table[header.e_shstrndx].sh_size;
debug("e_shstrndx %x, sh_size %lx\n", header.e_shstrndx, sh_size);
sh_str = malloc(sh_size);
if (!sh_str) {
fprintf(stderr, "malloc failed\n");
free(sh_table);
fclose(felf);
return 28;
}
/*
* Specifies the byte offset from the beginning of the file
* to the first byte in the section.
*/
sh_offset = sh_table[header.e_shstrndx].sh_offset;
debug("sh_offset %x\n", header.e_shnum);
ret = fseek(felf, sh_offset, SEEK_SET);
if (ret) {
fprintf(stderr, "Setting up sh_offset failed\n");
free(sh_str);
free(sh_table);
fclose(felf);
return 29;
}
size = fread(sh_str, 1, sh_size, felf);
if (size != sh_size) {
fprintf(stderr, "%s: Can't read section: %lx/%lx\n",
argv[0], size, sh_size);
free(sh_str);
free(sh_table);
fclose(felf);
return 30;
}
for (i = 0; i < header.e_shnum; i++) {
debug("%s\n", sh_str + sh_table[i].sh_name);
if (!strcmp(".rela.dyn", (sh_str + sh_table[i].sh_name))) {
debug("Found section\t\".rela_dyn\"\n");
debug(" at addr\t0x%08x\n", (unsigned int)sh_table[i].sh_addr);
debug(" at offset\t0x%08x\n", (unsigned int)sh_table[i].sh_offset);
debug(" of size\t0x%08x\n", (unsigned int)sh_table[i].sh_size);
rela_start = sh_table[i].sh_addr;
rela_end = rela_start + sh_table[i].sh_size;
}
if (!strcmp(".dynsym", (sh_str + sh_table[i].sh_name))) {
debug("Found section\t\".dynsym\"\n");
debug(" at addr\t0x%08x\n", (unsigned int)sh_table[i].sh_addr);
debug(" at offset\t0x%08x\n", (unsigned int)sh_table[i].sh_offset);
debug(" of size\t0x%08x\n", (unsigned int)sh_table[i].sh_size);
dyn_start = sh_table[i].sh_addr;
}
}
/* Clean up */
free(sh_str);
free(sh_table);
fclose(felf);
debug("text_base\t0x%08lx\n", text_base);
debug("rela_start\t0x%08lx\n", rela_start);
debug("rela_end\t0x%08lx\n", rela_end);
debug("dyn_start\t0x%08lx\n", dyn_start);
if (!rela_start)
return 1;
return 0;
}
static int decode_elf(char **argv)
{
FILE *felf;
size_t size;
unsigned char e_ident[EI_NIDENT];
felf = fopen(argv[2], "r+b");
if (!felf) {
fprintf(stderr, "%s: Cannot open %s: %s\n",
argv[0], argv[1], strerror(errno));
argv[0], argv[5], strerror(errno));
return 2;
}
if (!read_num(argv[2], &text_base) ||
!read_num(argv[3], &rela_start) ||
!read_num(argv[4], &rela_end)) {
fprintf(stderr, "%s: bad number\n", argv[0]);
return 3;
size = fread(e_ident, 1, EI_NIDENT, felf);
if (size != EI_NIDENT) {
fclose(felf);
return 25;
}
if (rela_start > rela_end || rela_start < text_base) {
fprintf(stderr, "%s: bad rela bounds\n", argv[0]);
return 3;
/* Check if this is really ELF file */
if (e_ident[0] != 0x7f &&
e_ident[1] != 'E' &&
e_ident[2] != 'L' &&
e_ident[3] != 'F') {
fclose(felf);
return 1;
}
rela_start -= text_base;
rela_end -= text_base;
ei_class = e_ident[4];
debug("EI_CLASS(1=32bit, 2=64bit) %d\n", ei_class);
fseek(f, 0, SEEK_END);
file_size = ftell(f);
rewind(f);
if (ei_class == 2)
return decode_elf64(felf, argv);
if (rela_end > file_size) {
// Most likely compiler inserted some section that didn't get
// objcopy-ed into the final binary
rela_end = file_size;
}
return decode_elf32(felf, argv);
}
static int rela_elf64(char **argv, FILE *f)
{
int i, num;
if ((rela_end - rela_start) % sizeof(Elf64_Rela)) {
fprintf(stderr, "%s: rela size isn't a multiple of Elf64_Rela\n", argv[0]);
@ -161,11 +417,228 @@ int main(int argc, char **argv)
}
}
return 0;
}
static bool supported_rela32(Elf32_Rela *rela, uint32_t *type)
{
uint32_t mask = 0xffULL; /* would be different on 32-bit */
*type = rela->r_info & mask;
debug("Type:\t");
switch (*type) {
case R_MICROBLAZE_32:
debug("R_MICROBLAZE_32\n");
return true;
case R_MICROBLAZE_GLOB_DAT:
debug("R_MICROBLAZE_GLOB_DAT\n");
return true;
case R_MICROBLAZE_NONE:
debug("R_MICROBLAZE_NONE - ignoring - do nothing\n");
return false;
case R_MICROBLAZE_REL:
debug("R_MICROBLAZE_REL\n");
return true;
default:
fprintf(stderr, "warning: unsupported relocation type %"
PRIu32 " at %" PRIx32 "\n", *type, rela->r_offset);
return false;
}
}
static int rela_elf32(char **argv, FILE *f)
{
int i, num, index;
uint32_t value, type;
if ((rela_end - rela_start) % sizeof(Elf32_Rela)) {
fprintf(stderr, "%s: rela size isn't a multiple of Elf32_Rela\n", argv[0]);
return 3;
}
num = (rela_end - rela_start) / sizeof(Elf32_Rela);
debug("Number of entries: %u\n", num);
for (i = 0; i < num; i++) {
Elf32_Rela rela, swrela;
Elf32_Sym symbols;
uint32_t pos = rela_start + sizeof(Elf32_Rela) * i;
uint32_t addr, pos_dyn;
debug("\nPossition:\t%d/0x%x\n", i, pos);
if (fseek(f, pos, SEEK_SET) < 0) {
fprintf(stderr, "%s: %s: seek to %" PRIx32
" failed: %s\n",
argv[0], argv[1], pos, strerror(errno));
}
if (fread(&rela, sizeof(rela), 1, f) != 1) {
fprintf(stderr, "%s: %s: read rela failed at %"
PRIx32 "\n",
argv[0], argv[1], pos);
return 4;
}
debug("Rela:\toffset:\t%" PRIx32 " r_info:\t%"
PRIu32 " r_addend:\t%" PRIx32 "\n",
rela.r_offset, rela.r_info, rela.r_addend);
swrela.r_offset = cpu_to_le32(rela.r_offset);
swrela.r_info = cpu_to_le32(rela.r_info);
swrela.r_addend = cpu_to_le32(rela.r_addend);
debug("SWRela:\toffset:\t%" PRIx32 " r_info:\t%"
PRIu32 " r_addend:\t%" PRIx32 "\n",
swrela.r_offset, swrela.r_info, swrela.r_addend);
if (!supported_rela32(&swrela, &type))
continue;
if (swrela.r_offset < text_base) {
fprintf(stderr, "%s: %s: bad rela at %" PRIx32 "\n",
argv[0], argv[1], pos);
return 4;
}
addr = swrela.r_offset - text_base;
debug("Addr:\t0x%" PRIx32 "\n", addr);
switch (type) {
case R_MICROBLAZE_REL:
if (fseek(f, addr, SEEK_SET) < 0) {
fprintf(stderr, "%s: %s: seek to %"
PRIx32 " failed: %s\n",
argv[0], argv[1], addr, strerror(errno));
return 5;
}
debug("Write addend\n");
if (fwrite(&rela.r_addend, sizeof(rela.r_addend), 1, f) != 1) {
fprintf(stderr, "%s: %s: write failed at %" PRIx32 "\n",
argv[0], argv[1], addr);
return 4;
}
break;
case R_MICROBLAZE_32:
case R_MICROBLAZE_GLOB_DAT:
/* global symbols read it and add reloc offset */
index = swrela.r_info >> 8;
pos_dyn = dyn_start + sizeof(Elf32_Sym) * index;
debug("Index:\t%d\n", index);
debug("Pos_dyn:\t0x%x\n", pos_dyn);
if (fseek(f, pos_dyn, SEEK_SET) < 0) {
fprintf(stderr, "%s: %s: seek to %"
PRIx32 " failed: %s\n",
argv[0], argv[1], pos_dyn, strerror(errno));
return 5;
}
if (fread(&symbols, sizeof(symbols), 1, f) != 1) {
fprintf(stderr, "%s: %s: read symbols failed at %"
PRIx32 "\n",
argv[0], argv[1], pos_dyn);
return 4;
}
debug("Symbol description:\n");
debug(" st_name:\t0x%x\n", symbols.st_name);
debug(" st_value:\t0x%x\n", symbols.st_value);
debug(" st_size:\t0x%x\n", symbols.st_size);
value = swrela.r_addend + symbols.st_value;
debug("Value:\t0x%x\n", value);
if (fseek(f, addr, SEEK_SET) < 0) {
fprintf(stderr, "%s: %s: seek to %"
PRIx32 " failed: %s\n",
argv[0], argv[1], addr, strerror(errno));
return 5;
}
if (fwrite(&value, sizeof(rela.r_addend), 1, f) != 1) {
fprintf(stderr, "%s: %s: write failed at %" PRIx32 "\n",
argv[0], argv[1], addr);
return 4;
}
break;
case R_MICROBLAZE_NONE:
debug("R_MICROBLAZE_NONE - skip\n");
break;
default:
fprintf(stderr, "warning: unsupported relocation type %"
PRIu32 " at %" PRIx32 "\n",
type, rela.r_offset);
}
}
return 0;
}
int main(int argc, char **argv)
{
FILE *f;
int ret;
uint64_t file_size;
if (argc != 3) {
fprintf(stderr, "Statically apply ELF rela relocations\n");
fprintf(stderr, "Usage: %s <bin file> <u-boot ELF>\n",
argv[0]);
return 1;
}
ret = decode_elf(argv);
if (ret) {
fprintf(stderr, "ELF decoding failed\n");
return ret;
}
if (rela_start > rela_end || rela_start < text_base) {
fprintf(stderr, "%s: bad rela bounds\n", argv[0]);
return 3;
}
rela_start -= text_base;
rela_end -= text_base;
dyn_start -= text_base;
f = fopen(argv[1], "r+b");
if (!f) {
fprintf(stderr, "%s: Cannot open %s: %s\n",
argv[0], argv[1], strerror(errno));
return 2;
}
fseek(f, 0, SEEK_END);
file_size = ftell(f);
rewind(f);
if (rela_end > file_size) {
// Most likely compiler inserted some section that didn't get
// objcopy-ed into the final binary
rela_end = file_size;
}
if (ei_class == 2)
ret = rela_elf64(argv, f);
else
ret = rela_elf32(argv, f);
if (fclose(f) < 0) {
fprintf(stderr, "%s: %s: close failed: %s\n",
argv[0], argv[1], strerror(errno));
return 4;
}
return 0;
return ret;
}

View File

@ -2,6 +2,8 @@
# SPDX-License-Identifier: GPL-2.0+
# Copyright (C) 2018 Michal Simek <michal.simek@xilinx.com>
# Copyright (C) 2019 Luca Ceresoli <luca@lucaceresoli.net>
# Copyright (C) 2022 Weidmüller Interface GmbH & Co. KG
# Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
usage()
{
@ -119,7 +121,7 @@ tr "\n" "\r" <${OUT} >${TMP}
# | | ==> |while (e)|
# | } | | ; |
# | |
sed -i -r 's| \{\r+(\t*)\}\r\r|\n\1\t;\n|g' ${TMP}
sed -i -r 's| \{\r+(\t*)\}\r\r|\r\1\t;\r|g' ${TMP}
# Remove empty line between variable declaration
sed -i -r 's|\r(\r\t(unsigned )?int )|\1|g' ${TMP}
@ -141,7 +143,30 @@ sed -i -r 's| \{(\r[^\r]*;)\r\t*\}|\1|g' ${TMP}
# if ((p_code >= 0x26) && ...) -> if (p_code >= 0x26 && ...)
sed -i -r 's|\((._code .= [x[:xdigit:]]+)\)|\1|g' ${TMP}
# Move helper functions below header includes
TARGET="#include <xil_io.h>"
START="static int serdes_rst_seq"
END="static int serdes_enb_coarse_saturation"
sed -i -e "s|\(${TARGET}\r\r\)\(.*\)\(${START}(.*\)\(${END}(\)|\1\3\2\4|g" \
${TMP}
# Convert back newlines
tr "\r" "\n" <${TMP} >${OUT}
# Remove unnecessary settings
# - Low level UART
SETTINGS_TO_REMOVE="0xFF000000
0xFF000004
0xFF000018
0xFF000034
0xFF010000
0xFF010004
0xFF010018
0xFF010034
"
for i in $SETTINGS_TO_REMOVE; do
sed -i "/^\tpsu_mask_write($i,.*$/d" ${OUT}
done
rm ${TMP}