[PATCH 0/5] board: xilinx: zyqmp: add Beckhoff CX8200

From: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
This adds support for the Beckhoff CX8200 series of industrial embedded PCs. There is some information about the device and features here: https://www.beckhoff.com/en-en/products/ipc/embedded-pcs/cx8200-arm-cortex-a...
We also add the rtc rv3032 driver from linux, as it is required for mac address loading, fix usb without reset gpios on zynqmp and move the fdt loadaddr to be compatible with less memory.
Steffen Dirkwinkel (5): drivers: rtc: add rv3032 driver drivers/usb/dwc3: zynqmp: only free reset gpio if we have one xilinx: zynqmp: move fdt_addr so we can use devices with less memory xilinx: zynqmp: add Beckhoff CX8200 xilinx: zynqmp: beckhoff cx8200: setup inner cache broadcasting
arch/arm/dts/Makefile | 1 + arch/arm/dts/zynqmp-beckhoff-cx8200.dts | 247 +++ .../zynqmp-beckhoff-cx8200/psu_init_gpl.c | 1960 +++++++++++++++++ .../zynqmp/zynqmp-beckhoff-cx8200/regs.init | 1 + configs/xilinx_zynqmp_virt_defconfig | 2 +- drivers/rtc/Kconfig | 10 + drivers/rtc/Makefile | 1 + drivers/rtc/rv3032.c | 334 +++ drivers/usb/dwc3/dwc3-generic.c | 4 +- include/configs/xilinx_zynqmp.h | 2 +- 10 files changed, 2559 insertions(+), 3 deletions(-) create mode 100644 arch/arm/dts/zynqmp-beckhoff-cx8200.dts create mode 100644 board/xilinx/zynqmp/zynqmp-beckhoff-cx8200/psu_init_gpl.c create mode 100644 board/xilinx/zynqmp/zynqmp-beckhoff-cx8200/regs.init create mode 100644 drivers/rtc/rv3032.c

From: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
Based on linux driver, with these differences: - no support for trickle charger - no support for hwmon - no support for battery backed memory - dm_i2c instead of regmap - different tm_year and tm_mon
read/write access the user eeprom. The read and write functions access the user eeprom so it can be used for nvmem-cells. (like in arch/sandbox/dts/test.dts). This is currently different from linux as you'd get nvram using nvmem-cells. I'm hoping to switch the order there too (there are currently no users) or to make a more specific binding. Currently this would also just work as is if used for mac addresses, as u-boot will put these into fdt before booting linux and linux will then prefer the u-boot provided mac.
Signed-off-by: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
---
drivers/rtc/Kconfig | 10 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rv3032.c | 334 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 345 insertions(+) create mode 100644 drivers/rtc/rv3032.c
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 23173139e0..a41ec9b6cc 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -172,6 +172,16 @@ config RTC_RV3029 This driver supports reading and writing the RTC/calendar and the battery-baced SRAM section.
+config RTC_RV3032 + bool "Enable RV3032 driver" + depends on DM_RTC + help + The MicroCrystal RV3032 is a I2C Real Time Clock (RTC) with a 16-byte + battery-backed SRAM and a 32-byte user eeprom. + + This driver supports reading and writing the RTC/calendar and the + user eeprom. + config RTC_RV8803 bool "Enable RV8803 driver" depends on DM_RTC diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 308fab8da9..9c2d8c7aa9 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_RTC_PL031) += pl031.o obj-$(CONFIG_RTC_PT7C4338) += pt7c4338.o obj-$(CONFIG_RTC_RV3028) += rv3028.o obj-$(CONFIG_RTC_RV3029) += rv3029.o +obj-$(CONFIG_RTC_RV3032) += rv3032.o obj-$(CONFIG_RTC_RV8803) += rv8803.o obj-$(CONFIG_RTC_RX8025) += rx8025.o obj-$(CONFIG_RTC_RX8010SJ) += rx8010sj.o diff --git a/drivers/rtc/rv3032.c b/drivers/rtc/rv3032.c new file mode 100644 index 0000000000..8d5d860c0a --- /dev/null +++ b/drivers/rtc/rv3032.c @@ -0,0 +1,334 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * RTC driver for the Micro Crystal RV3032 + * + * based on linux driver from + * Copyright (C) 2020 Micro Crystal SA + * + * Alexandre Belloni alexandre.belloni@bootlin.com + * + */ + +#include <dm.h> +#include <i2c.h> +#include <linux/delay.h> +#include <regmap.h> +#include <rtc.h> +#include <time.h> + +#define RV3032_SEC 0x01 +#define RV3032_MIN 0x02 +#define RV3032_HOUR 0x03 +#define RV3032_WDAY 0x04 +#define RV3032_DAY 0x05 +#define RV3032_MONTH 0x06 +#define RV3032_YEAR 0x07 +#define RV3032_ALARM_MIN 0x08 +#define RV3032_ALARM_HOUR 0x09 +#define RV3032_ALARM_DAY 0x0A +#define RV3032_STATUS 0x0D +#define RV3032_TLSB 0x0E +#define RV3032_TMSB 0x0F +#define RV3032_CTRL1 0x10 +#define RV3032_CTRL2 0x11 +#define RV3032_CTRL3 0x12 +#define RV3032_TS_CTRL 0x13 +#define RV3032_CLK_IRQ 0x14 +#define RV3032_EEPROM_ADDR 0x3D +#define RV3032_EEPROM_DATA 0x3E +#define RV3032_EEPROM_CMD 0x3F +#define RV3032_RAM1 0x40 +#define RV3032_PMU 0xC0 +#define RV3032_OFFSET 0xC1 +#define RV3032_CLKOUT1 0xC2 +#define RV3032_CLKOUT2 0xC3 +#define RV3032_TREF0 0xC4 +#define RV3032_TREF1 0xC5 + +#define RV3032_STATUS_VLF BIT(0) +#define RV3032_STATUS_PORF BIT(1) +#define RV3032_STATUS_EVF BIT(2) +#define RV3032_STATUS_AF BIT(3) +#define RV3032_STATUS_TF BIT(4) +#define RV3032_STATUS_UF BIT(5) +#define RV3032_STATUS_TLF BIT(6) +#define RV3032_STATUS_THF BIT(7) + +#define RV3032_TLSB_CLKF BIT(1) +#define RV3032_TLSB_EEBUSY BIT(2) +#define RV3032_TLSB_TEMP GENMASK(7, 4) + +#define RV3032_CLKOUT2_HFD_MSK GENMASK(4, 0) +#define RV3032_CLKOUT2_FD_MSK GENMASK(6, 5) +#define RV3032_CLKOUT2_OS BIT(7) + +#define RV3032_CTRL1_EERD BIT(3) +#define RV3032_CTRL1_WADA BIT(5) + +#define RV3032_CTRL2_STOP BIT(0) +#define RV3032_CTRL2_EIE BIT(2) +#define RV3032_CTRL2_AIE BIT(3) +#define RV3032_CTRL2_TIE BIT(4) +#define RV3032_CTRL2_UIE BIT(5) +#define RV3032_CTRL2_CLKIE BIT(6) +#define RV3032_CTRL2_TSE BIT(7) + +#define RV3032_PMU_TCM GENMASK(1, 0) +#define RV3032_PMU_TCR GENMASK(3, 2) +#define RV3032_PMU_BSM GENMASK(5, 4) +#define RV3032_PMU_NCLKE BIT(6) + +#define RV3032_PMU_BSM_DSM 1 +#define RV3032_PMU_BSM_LSM 2 + +#define RV3032_OFFSET_MSK GENMASK(5, 0) + +#define RV3032_EVT_CTRL_TSR BIT(2) + +#define RV3032_EEPROM_CMD_UPDATE 0x11 +#define RV3032_EEPROM_CMD_WRITE 0x21 +#define RV3032_EEPROM_CMD_READ 0x22 + +#define RV3032_EEPROM_USER 0xCB + +#define RV3032_EEBUSY_POLL 10000 +#define RV3032_EEBUSY_TIMEOUT 100000 + +#define OFFSET_STEP_PPT 238419 + +static int rv3032_update_bits(struct udevice *dev, u8 reg, u8 mask, u8 set) +{ + u8 buf; + int ret; + + ret = dm_i2c_read(dev, reg, &buf, 1); + if (ret < 0) + return ret; + + if ((buf & mask) == (set && mask)) + return 0; + + buf = (buf & ~mask) | (set & mask); + ret = dm_i2c_read(dev, reg, &buf, 1); + if (ret < 0) + return ret; + + return 0; +} + +static int rv3032_exit_eerd(struct udevice *dev, u32 eerd) +{ + if (eerd) + return 0; + + return rv3032_update_bits(dev, RV3032_CTRL1, RV3032_CTRL1_EERD, 0); +} + +static int rv3032_eeprom_busywait(struct udevice *dev) +{ + int ret; + u8 status; + unsigned long start = get_timer(0); + + for (;;) { + ret = dm_i2c_read(dev, RV3032_TLSB, &status, 1); + if (ret < 0) + break; + if (!(status & RV3032_TLSB_EEBUSY)) + break; + if (get_timer(start) > RV3032_EEBUSY_TIMEOUT) + return -ETIMEDOUT; + udelay(RV3032_EEBUSY_POLL); + } + + return ret; +} + +static int rv3032_enter_eerd(struct udevice *dev, u32 *eerd) +{ + u8 ctrl1; + int ret; + + ret = dm_i2c_read(dev, RV3032_CTRL1, &ctrl1, sizeof(ctrl1)); + if (ret) + return ret; + + *eerd = ctrl1 & RV3032_CTRL1_EERD; + if (*eerd) + return 0; + + ret = rv3032_update_bits(dev, RV3032_CTRL1, + RV3032_CTRL1_EERD, RV3032_CTRL1_EERD); + if (ret) + return ret; + + ret = rv3032_eeprom_busywait(dev); + if (ret) { + rv3032_exit_eerd(dev, *eerd); + + return ret; + } + + return 0; +} + +static int rv3032_get_time(struct udevice *dev, struct rtc_time *tm) +{ + u8 date[7]; + int ret; + u8 status; + + ret = dm_i2c_read(dev, RV3032_STATUS, &status, 1); + if (ret < 0) + return ret; + + if (status & (RV3032_STATUS_PORF | RV3032_STATUS_VLF)) + return -EINVAL; + + ret = dm_i2c_read(dev, RV3032_SEC, date, sizeof(date)); + if (ret) + return ret; + + tm->tm_sec = bcd2bin(date[0] & 0x7f); + tm->tm_min = bcd2bin(date[1] & 0x7f); + tm->tm_hour = bcd2bin(date[2] & 0x3f); + tm->tm_wday = date[3] & 0x7; + tm->tm_mday = bcd2bin(date[4] & 0x3f); + tm->tm_mon = bcd2bin(date[5] & 0x1f); + tm->tm_year = bcd2bin(date[6]) + 2000; + + return 0; +} + +static int rv3032_set_time(struct udevice *dev, const struct rtc_time *tm) +{ + u8 date[7]; + int ret; + + date[0] = bin2bcd(tm->tm_sec); + date[1] = bin2bcd(tm->tm_min); + date[2] = bin2bcd(tm->tm_hour); + date[3] = tm->tm_wday; + date[4] = bin2bcd(tm->tm_mday); + date[5] = bin2bcd(tm->tm_mon); + date[6] = bin2bcd(tm->tm_year - 2000); + + ret = dm_i2c_write(dev, RV3032_SEC, date, + sizeof(date)); + if (ret) + return ret; + + ret = rv3032_update_bits(dev, RV3032_STATUS, + RV3032_STATUS_PORF | RV3032_STATUS_VLF, 0); + + return ret; +} + +static int rv3032_eeprom_write(struct udevice *dev, unsigned int reg, + const u8 *buf, unsigned int len) +{ + u32 eerd; + int i, ret; + u8 cmd; + + ret = rv3032_enter_eerd(dev, &eerd); + if (ret) + return ret; + + for (i = 0; i < len; i++) { + cmd = RV3032_EEPROM_USER + reg + i; + ret = dm_i2c_write(dev, RV3032_EEPROM_ADDR, + &cmd, 1); + if (ret) + goto exit_eerd; + + ret = dm_i2c_write(dev, RV3032_EEPROM_DATA, &buf[i], 1); + if (ret) + goto exit_eerd; + + cmd = RV3032_EEPROM_CMD_WRITE; + ret = dm_i2c_write(dev, RV3032_EEPROM_CMD, + &cmd, 1); + if (ret) + goto exit_eerd; + + udelay(RV3032_EEBUSY_POLL); + + ret = rv3032_eeprom_busywait(dev); + if (ret) + goto exit_eerd; + } + +exit_eerd: + rv3032_exit_eerd(dev, eerd); + + return ret; +} + +static int rv3032_eeprom_read(struct udevice *dev, unsigned int reg, + u8 *buf, unsigned int len) +{ + u32 eerd; + int i, ret; + u8 cmd, data; + + ret = rv3032_enter_eerd(dev, &eerd); + if (ret) + return ret; + + for (i = 0; i < len; i++) { + cmd = RV3032_EEPROM_USER + reg + i; + ret = dm_i2c_write(dev, RV3032_EEPROM_ADDR, + &cmd, 1); + if (ret) + goto exit_eerd; + + cmd = RV3032_EEPROM_CMD_READ; + ret = dm_i2c_write(dev, RV3032_EEPROM_CMD, + &cmd, 1); + if (ret) + goto exit_eerd; + + ret = rv3032_eeprom_busywait(dev); + if (ret) + goto exit_eerd; + + ret = dm_i2c_read(dev, RV3032_EEPROM_DATA, &data, sizeof(data)); + if (ret) + goto exit_eerd; + buf[i] = data; + } + +exit_eerd: + rv3032_exit_eerd(dev, eerd); + + return ret; +} + +static int rv3032_probe(struct udevice *dev) +{ + i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS | + DM_I2C_CHIP_WR_ADDRESS); + + return 0; +} + +static const struct rtc_ops rv3032_rtc_ops = { + .get = rv3032_get_time, + .set = rv3032_set_time, + .read = rv3032_eeprom_read, + .write = rv3032_eeprom_write, +}; + +static const struct udevice_id rv3032_rtc_ids[] = { + { .compatible = "microcrystal,rv3032", }, + { } +}; + +U_BOOT_DRIVER(rtc_rv3032) = { + .name = "rtc-rv3028", + .id = UCLASS_RTC, + .probe = rv3032_probe, + .of_match = rv3032_rtc_ids, + .ops = &rv3032_rtc_ops, +};

Hello,
On 30/08/2023 16:03:30+0200, Steffen Dirkwinkel wrote:
From: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
Based on linux driver, with these differences:
- no support for trickle charger
- no support for hwmon
- no support for battery backed memory
- dm_i2c instead of regmap
- different tm_year and tm_mon
read/write access the user eeprom. The read and write functions access the user eeprom so it can be used for nvmem-cells. (like in arch/sandbox/dts/test.dts). This is currently different from linux as you'd get nvram using nvmem-cells. I'm hoping to switch the order there
I'm not sure I get this as both nvram and eeprom are exposed through nvmem. The solution is not to reorder but instead to fix the nvmem core so you can expose both using nvmem-cells as there are users that access the nvram to handle A/B updates (bootcount, rescue mode,...)
too (there are currently no users) or to make a more specific binding. Currently this would also just work as is if used for mac addresses, as u-boot will put these into fdt before booting linux and linux will then prefer the u-boot provided mac.
Signed-off-by: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
drivers/rtc/Kconfig | 10 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rv3032.c | 334 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 345 insertions(+) create mode 100644 drivers/rtc/rv3032.c
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 23173139e0..a41ec9b6cc 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -172,6 +172,16 @@ config RTC_RV3029 This driver supports reading and writing the RTC/calendar and the battery-baced SRAM section.
+config RTC_RV3032
- bool "Enable RV3032 driver"
- depends on DM_RTC
- help
The MicroCrystal RV3032 is a I2C Real Time Clock (RTC) with a 16-byte
battery-backed SRAM and a 32-byte user eeprom.
This driver supports reading and writing the RTC/calendar and the
user eeprom.
config RTC_RV8803 bool "Enable RV8803 driver" depends on DM_RTC diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 308fab8da9..9c2d8c7aa9 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_RTC_PL031) += pl031.o obj-$(CONFIG_RTC_PT7C4338) += pt7c4338.o obj-$(CONFIG_RTC_RV3028) += rv3028.o obj-$(CONFIG_RTC_RV3029) += rv3029.o +obj-$(CONFIG_RTC_RV3032) += rv3032.o obj-$(CONFIG_RTC_RV8803) += rv8803.o obj-$(CONFIG_RTC_RX8025) += rx8025.o obj-$(CONFIG_RTC_RX8010SJ) += rx8010sj.o diff --git a/drivers/rtc/rv3032.c b/drivers/rtc/rv3032.c new file mode 100644 index 0000000000..8d5d860c0a --- /dev/null +++ b/drivers/rtc/rv3032.c @@ -0,0 +1,334 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- RTC driver for the Micro Crystal RV3032
- based on linux driver from
- Copyright (C) 2020 Micro Crystal SA
- Alexandre Belloni alexandre.belloni@bootlin.com
- */
+#include <dm.h> +#include <i2c.h> +#include <linux/delay.h> +#include <regmap.h> +#include <rtc.h> +#include <time.h>
+#define RV3032_SEC 0x01 +#define RV3032_MIN 0x02 +#define RV3032_HOUR 0x03 +#define RV3032_WDAY 0x04 +#define RV3032_DAY 0x05 +#define RV3032_MONTH 0x06 +#define RV3032_YEAR 0x07 +#define RV3032_ALARM_MIN 0x08 +#define RV3032_ALARM_HOUR 0x09 +#define RV3032_ALARM_DAY 0x0A +#define RV3032_STATUS 0x0D +#define RV3032_TLSB 0x0E +#define RV3032_TMSB 0x0F +#define RV3032_CTRL1 0x10 +#define RV3032_CTRL2 0x11 +#define RV3032_CTRL3 0x12 +#define RV3032_TS_CTRL 0x13 +#define RV3032_CLK_IRQ 0x14 +#define RV3032_EEPROM_ADDR 0x3D +#define RV3032_EEPROM_DATA 0x3E +#define RV3032_EEPROM_CMD 0x3F +#define RV3032_RAM1 0x40 +#define RV3032_PMU 0xC0 +#define RV3032_OFFSET 0xC1 +#define RV3032_CLKOUT1 0xC2 +#define RV3032_CLKOUT2 0xC3 +#define RV3032_TREF0 0xC4 +#define RV3032_TREF1 0xC5
+#define RV3032_STATUS_VLF BIT(0) +#define RV3032_STATUS_PORF BIT(1) +#define RV3032_STATUS_EVF BIT(2) +#define RV3032_STATUS_AF BIT(3) +#define RV3032_STATUS_TF BIT(4) +#define RV3032_STATUS_UF BIT(5) +#define RV3032_STATUS_TLF BIT(6) +#define RV3032_STATUS_THF BIT(7)
+#define RV3032_TLSB_CLKF BIT(1) +#define RV3032_TLSB_EEBUSY BIT(2) +#define RV3032_TLSB_TEMP GENMASK(7, 4)
+#define RV3032_CLKOUT2_HFD_MSK GENMASK(4, 0) +#define RV3032_CLKOUT2_FD_MSK GENMASK(6, 5) +#define RV3032_CLKOUT2_OS BIT(7)
+#define RV3032_CTRL1_EERD BIT(3) +#define RV3032_CTRL1_WADA BIT(5)
+#define RV3032_CTRL2_STOP BIT(0) +#define RV3032_CTRL2_EIE BIT(2) +#define RV3032_CTRL2_AIE BIT(3) +#define RV3032_CTRL2_TIE BIT(4) +#define RV3032_CTRL2_UIE BIT(5) +#define RV3032_CTRL2_CLKIE BIT(6) +#define RV3032_CTRL2_TSE BIT(7)
+#define RV3032_PMU_TCM GENMASK(1, 0) +#define RV3032_PMU_TCR GENMASK(3, 2) +#define RV3032_PMU_BSM GENMASK(5, 4) +#define RV3032_PMU_NCLKE BIT(6)
+#define RV3032_PMU_BSM_DSM 1 +#define RV3032_PMU_BSM_LSM 2
+#define RV3032_OFFSET_MSK GENMASK(5, 0)
+#define RV3032_EVT_CTRL_TSR BIT(2)
+#define RV3032_EEPROM_CMD_UPDATE 0x11 +#define RV3032_EEPROM_CMD_WRITE 0x21 +#define RV3032_EEPROM_CMD_READ 0x22
+#define RV3032_EEPROM_USER 0xCB
+#define RV3032_EEBUSY_POLL 10000 +#define RV3032_EEBUSY_TIMEOUT 100000
+#define OFFSET_STEP_PPT 238419
+static int rv3032_update_bits(struct udevice *dev, u8 reg, u8 mask, u8 set) +{
- u8 buf;
- int ret;
- ret = dm_i2c_read(dev, reg, &buf, 1);
- if (ret < 0)
return ret;
- if ((buf & mask) == (set && mask))
return 0;
- buf = (buf & ~mask) | (set & mask);
- ret = dm_i2c_read(dev, reg, &buf, 1);
- if (ret < 0)
return ret;
- return 0;
+}
+static int rv3032_exit_eerd(struct udevice *dev, u32 eerd) +{
- if (eerd)
return 0;
- return rv3032_update_bits(dev, RV3032_CTRL1, RV3032_CTRL1_EERD, 0);
+}
+static int rv3032_eeprom_busywait(struct udevice *dev) +{
- int ret;
- u8 status;
- unsigned long start = get_timer(0);
- for (;;) {
ret = dm_i2c_read(dev, RV3032_TLSB, &status, 1);
if (ret < 0)
break;
if (!(status & RV3032_TLSB_EEBUSY))
break;
if (get_timer(start) > RV3032_EEBUSY_TIMEOUT)
return -ETIMEDOUT;
udelay(RV3032_EEBUSY_POLL);
- }
- return ret;
+}
+static int rv3032_enter_eerd(struct udevice *dev, u32 *eerd) +{
- u8 ctrl1;
- int ret;
- ret = dm_i2c_read(dev, RV3032_CTRL1, &ctrl1, sizeof(ctrl1));
- if (ret)
return ret;
- *eerd = ctrl1 & RV3032_CTRL1_EERD;
- if (*eerd)
return 0;
- ret = rv3032_update_bits(dev, RV3032_CTRL1,
RV3032_CTRL1_EERD, RV3032_CTRL1_EERD);
- if (ret)
return ret;
- ret = rv3032_eeprom_busywait(dev);
- if (ret) {
rv3032_exit_eerd(dev, *eerd);
return ret;
- }
- return 0;
+}
+static int rv3032_get_time(struct udevice *dev, struct rtc_time *tm) +{
- u8 date[7];
- int ret;
- u8 status;
- ret = dm_i2c_read(dev, RV3032_STATUS, &status, 1);
- if (ret < 0)
return ret;
- if (status & (RV3032_STATUS_PORF | RV3032_STATUS_VLF))
return -EINVAL;
- ret = dm_i2c_read(dev, RV3032_SEC, date, sizeof(date));
- if (ret)
return ret;
- tm->tm_sec = bcd2bin(date[0] & 0x7f);
- tm->tm_min = bcd2bin(date[1] & 0x7f);
- tm->tm_hour = bcd2bin(date[2] & 0x3f);
- tm->tm_wday = date[3] & 0x7;
- tm->tm_mday = bcd2bin(date[4] & 0x3f);
- tm->tm_mon = bcd2bin(date[5] & 0x1f);
- tm->tm_year = bcd2bin(date[6]) + 2000;
- return 0;
+}
+static int rv3032_set_time(struct udevice *dev, const struct rtc_time *tm) +{
- u8 date[7];
- int ret;
- date[0] = bin2bcd(tm->tm_sec);
- date[1] = bin2bcd(tm->tm_min);
- date[2] = bin2bcd(tm->tm_hour);
- date[3] = tm->tm_wday;
- date[4] = bin2bcd(tm->tm_mday);
- date[5] = bin2bcd(tm->tm_mon);
- date[6] = bin2bcd(tm->tm_year - 2000);
- ret = dm_i2c_write(dev, RV3032_SEC, date,
sizeof(date));
- if (ret)
return ret;
- ret = rv3032_update_bits(dev, RV3032_STATUS,
RV3032_STATUS_PORF | RV3032_STATUS_VLF, 0);
- return ret;
+}
+static int rv3032_eeprom_write(struct udevice *dev, unsigned int reg,
const u8 *buf, unsigned int len)
+{
- u32 eerd;
- int i, ret;
- u8 cmd;
- ret = rv3032_enter_eerd(dev, &eerd);
- if (ret)
return ret;
- for (i = 0; i < len; i++) {
cmd = RV3032_EEPROM_USER + reg + i;
ret = dm_i2c_write(dev, RV3032_EEPROM_ADDR,
&cmd, 1);
if (ret)
goto exit_eerd;
ret = dm_i2c_write(dev, RV3032_EEPROM_DATA, &buf[i], 1);
if (ret)
goto exit_eerd;
cmd = RV3032_EEPROM_CMD_WRITE;
ret = dm_i2c_write(dev, RV3032_EEPROM_CMD,
&cmd, 1);
if (ret)
goto exit_eerd;
udelay(RV3032_EEBUSY_POLL);
ret = rv3032_eeprom_busywait(dev);
if (ret)
goto exit_eerd;
- }
+exit_eerd:
- rv3032_exit_eerd(dev, eerd);
- return ret;
+}
+static int rv3032_eeprom_read(struct udevice *dev, unsigned int reg,
u8 *buf, unsigned int len)
+{
- u32 eerd;
- int i, ret;
- u8 cmd, data;
- ret = rv3032_enter_eerd(dev, &eerd);
- if (ret)
return ret;
- for (i = 0; i < len; i++) {
cmd = RV3032_EEPROM_USER + reg + i;
ret = dm_i2c_write(dev, RV3032_EEPROM_ADDR,
&cmd, 1);
if (ret)
goto exit_eerd;
cmd = RV3032_EEPROM_CMD_READ;
ret = dm_i2c_write(dev, RV3032_EEPROM_CMD,
&cmd, 1);
if (ret)
goto exit_eerd;
ret = rv3032_eeprom_busywait(dev);
if (ret)
goto exit_eerd;
ret = dm_i2c_read(dev, RV3032_EEPROM_DATA, &data, sizeof(data));
if (ret)
goto exit_eerd;
buf[i] = data;
- }
+exit_eerd:
- rv3032_exit_eerd(dev, eerd);
- return ret;
+}
+static int rv3032_probe(struct udevice *dev) +{
- i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS |
DM_I2C_CHIP_WR_ADDRESS);
- return 0;
+}
+static const struct rtc_ops rv3032_rtc_ops = {
- .get = rv3032_get_time,
- .set = rv3032_set_time,
- .read = rv3032_eeprom_read,
- .write = rv3032_eeprom_write,
+};
+static const struct udevice_id rv3032_rtc_ids[] = {
- { .compatible = "microcrystal,rv3032", },
- { }
+};
+U_BOOT_DRIVER(rtc_rv3032) = {
- .name = "rtc-rv3028",
- .id = UCLASS_RTC,
- .probe = rv3032_probe,
- .of_match = rv3032_rtc_ids,
- .ops = &rv3032_rtc_ops,
+};
2.42.0

Hi,
On 30. Aug 2023, at 21:43, Alexandre Belloni alexandre.belloni@bootlin.com wrote:
Hello,
On 30/08/2023 16:03:30+0200, Steffen Dirkwinkel wrote:
From: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
Based on linux driver, with these differences:
- no support for trickle charger
- no support for hwmon
- no support for battery backed memory
- dm_i2c instead of regmap
- different tm_year and tm_mon
read/write access the user eeprom. The read and write functions access the user eeprom so it can be used for nvmem-cells. (like in arch/sandbox/dts/test.dts). This is currently different from linux as you'd get nvram using nvmem-cells. I'm hoping to switch the order there
I'm not sure I get this as both nvram and eeprom are exposed through nvmem. The solution is not to reorder but instead to fix the nvmem core so you can expose both using nvmem-cells as there are users that access the nvram to handle A/B updates (bootcount, rescue mode,...)
How does one set the nvmem location to be in eeprom on the linux driver? Maybe I just don’t understand the binding correctly?
Currently I have this: rv3032: rtc@51 { #address-cells = <1>; #size-cells = <1>; compatible = "microcrystal,rv3032”; reg = <0x51>; interrupt-parent = <&gpio>; interrupts = <11 IRQ_TYPE_LEVEL_LOW>; gem2_mac_address: mac-address@0 { reg = <0x0 6>; }; };
On Linux that would read from battery backed ram. Is there some way to specify it is in eeprom?
too (there are currently no users) or to make a more specific binding. Currently this would also just work as is if used for mac addresses, as u-boot will put these into fdt before booting linux and linux will then prefer the u-boot provided mac.
Signed-off-by: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
drivers/rtc/Kconfig | 10 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rv3032.c | 334 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 345 insertions(+) create mode 100644 drivers/rtc/rv3032.c
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 23173139e0..a41ec9b6cc 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -172,6 +172,16 @@ config RTC_RV3029 This driver supports reading and writing the RTC/calendar and the battery-baced SRAM section.
+config RTC_RV3032
- bool "Enable RV3032 driver"
- depends on DM_RTC
- help
- The MicroCrystal RV3032 is a I2C Real Time Clock (RTC) with a 16-byte
- battery-backed SRAM and a 32-byte user eeprom.
- This driver supports reading and writing the RTC/calendar and the
- user eeprom.
config RTC_RV8803 bool "Enable RV8803 driver" depends on DM_RTC diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 308fab8da9..9c2d8c7aa9 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_RTC_PL031) += pl031.o obj-$(CONFIG_RTC_PT7C4338) += pt7c4338.o obj-$(CONFIG_RTC_RV3028) += rv3028.o obj-$(CONFIG_RTC_RV3029) += rv3029.o +obj-$(CONFIG_RTC_RV3032) += rv3032.o obj-$(CONFIG_RTC_RV8803) += rv8803.o obj-$(CONFIG_RTC_RX8025) += rx8025.o obj-$(CONFIG_RTC_RX8010SJ) += rx8010sj.o diff --git a/drivers/rtc/rv3032.c b/drivers/rtc/rv3032.c new file mode 100644 index 0000000000..8d5d860c0a --- /dev/null +++ b/drivers/rtc/rv3032.c @@ -0,0 +1,334 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- RTC driver for the Micro Crystal RV3032
- based on linux driver from
- Copyright (C) 2020 Micro Crystal SA
- Alexandre Belloni alexandre.belloni@bootlin.com
- */
+#include <dm.h> +#include <i2c.h> +#include <linux/delay.h> +#include <regmap.h> +#include <rtc.h> +#include <time.h>
+#define RV3032_SEC 0x01 +#define RV3032_MIN 0x02 +#define RV3032_HOUR 0x03 +#define RV3032_WDAY 0x04 +#define RV3032_DAY 0x05 +#define RV3032_MONTH 0x06 +#define RV3032_YEAR 0x07 +#define RV3032_ALARM_MIN 0x08 +#define RV3032_ALARM_HOUR 0x09 +#define RV3032_ALARM_DAY 0x0A +#define RV3032_STATUS 0x0D +#define RV3032_TLSB 0x0E +#define RV3032_TMSB 0x0F +#define RV3032_CTRL1 0x10 +#define RV3032_CTRL2 0x11 +#define RV3032_CTRL3 0x12 +#define RV3032_TS_CTRL 0x13 +#define RV3032_CLK_IRQ 0x14 +#define RV3032_EEPROM_ADDR 0x3D +#define RV3032_EEPROM_DATA 0x3E +#define RV3032_EEPROM_CMD 0x3F +#define RV3032_RAM1 0x40 +#define RV3032_PMU 0xC0 +#define RV3032_OFFSET 0xC1 +#define RV3032_CLKOUT1 0xC2 +#define RV3032_CLKOUT2 0xC3 +#define RV3032_TREF0 0xC4 +#define RV3032_TREF1 0xC5
+#define RV3032_STATUS_VLF BIT(0) +#define RV3032_STATUS_PORF BIT(1) +#define RV3032_STATUS_EVF BIT(2) +#define RV3032_STATUS_AF BIT(3) +#define RV3032_STATUS_TF BIT(4) +#define RV3032_STATUS_UF BIT(5) +#define RV3032_STATUS_TLF BIT(6) +#define RV3032_STATUS_THF BIT(7)
+#define RV3032_TLSB_CLKF BIT(1) +#define RV3032_TLSB_EEBUSY BIT(2) +#define RV3032_TLSB_TEMP GENMASK(7, 4)
+#define RV3032_CLKOUT2_HFD_MSK GENMASK(4, 0) +#define RV3032_CLKOUT2_FD_MSK GENMASK(6, 5) +#define RV3032_CLKOUT2_OS BIT(7)
+#define RV3032_CTRL1_EERD BIT(3) +#define RV3032_CTRL1_WADA BIT(5)
+#define RV3032_CTRL2_STOP BIT(0) +#define RV3032_CTRL2_EIE BIT(2) +#define RV3032_CTRL2_AIE BIT(3) +#define RV3032_CTRL2_TIE BIT(4) +#define RV3032_CTRL2_UIE BIT(5) +#define RV3032_CTRL2_CLKIE BIT(6) +#define RV3032_CTRL2_TSE BIT(7)
+#define RV3032_PMU_TCM GENMASK(1, 0) +#define RV3032_PMU_TCR GENMASK(3, 2) +#define RV3032_PMU_BSM GENMASK(5, 4) +#define RV3032_PMU_NCLKE BIT(6)
+#define RV3032_PMU_BSM_DSM 1 +#define RV3032_PMU_BSM_LSM 2
+#define RV3032_OFFSET_MSK GENMASK(5, 0)
+#define RV3032_EVT_CTRL_TSR BIT(2)
+#define RV3032_EEPROM_CMD_UPDATE 0x11 +#define RV3032_EEPROM_CMD_WRITE 0x21 +#define RV3032_EEPROM_CMD_READ 0x22
+#define RV3032_EEPROM_USER 0xCB
+#define RV3032_EEBUSY_POLL 10000 +#define RV3032_EEBUSY_TIMEOUT 100000
+#define OFFSET_STEP_PPT 238419
+static int rv3032_update_bits(struct udevice *dev, u8 reg, u8 mask, u8 set) +{
- u8 buf;
- int ret;
- ret = dm_i2c_read(dev, reg, &buf, 1);
- if (ret < 0)
- return ret;
- if ((buf & mask) == (set && mask))
- return 0;
- buf = (buf & ~mask) | (set & mask);
- ret = dm_i2c_read(dev, reg, &buf, 1);
- if (ret < 0)
- return ret;
- return 0;
+}
+static int rv3032_exit_eerd(struct udevice *dev, u32 eerd) +{
- if (eerd)
- return 0;
- return rv3032_update_bits(dev, RV3032_CTRL1, RV3032_CTRL1_EERD, 0);
+}
+static int rv3032_eeprom_busywait(struct udevice *dev) +{
- int ret;
- u8 status;
- unsigned long start = get_timer(0);
- for (;;) {
- ret = dm_i2c_read(dev, RV3032_TLSB, &status, 1);
- if (ret < 0)
- break;
- if (!(status & RV3032_TLSB_EEBUSY))
- break;
- if (get_timer(start) > RV3032_EEBUSY_TIMEOUT)
- return -ETIMEDOUT;
- udelay(RV3032_EEBUSY_POLL);
- }
- return ret;
+}
+static int rv3032_enter_eerd(struct udevice *dev, u32 *eerd) +{
- u8 ctrl1;
- int ret;
- ret = dm_i2c_read(dev, RV3032_CTRL1, &ctrl1, sizeof(ctrl1));
- if (ret)
- return ret;
- *eerd = ctrl1 & RV3032_CTRL1_EERD;
- if (*eerd)
- return 0;
- ret = rv3032_update_bits(dev, RV3032_CTRL1,
- RV3032_CTRL1_EERD, RV3032_CTRL1_EERD);
- if (ret)
- return ret;
- ret = rv3032_eeprom_busywait(dev);
- if (ret) {
- rv3032_exit_eerd(dev, *eerd);
- return ret;
- }
- return 0;
+}
+static int rv3032_get_time(struct udevice *dev, struct rtc_time *tm) +{
- u8 date[7];
- int ret;
- u8 status;
- ret = dm_i2c_read(dev, RV3032_STATUS, &status, 1);
- if (ret < 0)
- return ret;
- if (status & (RV3032_STATUS_PORF | RV3032_STATUS_VLF))
- return -EINVAL;
- ret = dm_i2c_read(dev, RV3032_SEC, date, sizeof(date));
- if (ret)
- return ret;
- tm->tm_sec = bcd2bin(date[0] & 0x7f);
- tm->tm_min = bcd2bin(date[1] & 0x7f);
- tm->tm_hour = bcd2bin(date[2] & 0x3f);
- tm->tm_wday = date[3] & 0x7;
- tm->tm_mday = bcd2bin(date[4] & 0x3f);
- tm->tm_mon = bcd2bin(date[5] & 0x1f);
- tm->tm_year = bcd2bin(date[6]) + 2000;
- return 0;
+}
+static int rv3032_set_time(struct udevice *dev, const struct rtc_time *tm) +{
- u8 date[7];
- int ret;
- date[0] = bin2bcd(tm->tm_sec);
- date[1] = bin2bcd(tm->tm_min);
- date[2] = bin2bcd(tm->tm_hour);
- date[3] = tm->tm_wday;
- date[4] = bin2bcd(tm->tm_mday);
- date[5] = bin2bcd(tm->tm_mon);
- date[6] = bin2bcd(tm->tm_year - 2000);
- ret = dm_i2c_write(dev, RV3032_SEC, date,
- sizeof(date));
- if (ret)
- return ret;
- ret = rv3032_update_bits(dev, RV3032_STATUS,
- RV3032_STATUS_PORF | RV3032_STATUS_VLF, 0);
- return ret;
+}
+static int rv3032_eeprom_write(struct udevice *dev, unsigned int reg,
const u8 *buf, unsigned int len)
+{
- u32 eerd;
- int i, ret;
- u8 cmd;
- ret = rv3032_enter_eerd(dev, &eerd);
- if (ret)
- return ret;
- for (i = 0; i < len; i++) {
- cmd = RV3032_EEPROM_USER + reg + i;
- ret = dm_i2c_write(dev, RV3032_EEPROM_ADDR,
- &cmd, 1);
- if (ret)
- goto exit_eerd;
- ret = dm_i2c_write(dev, RV3032_EEPROM_DATA, &buf[i], 1);
- if (ret)
- goto exit_eerd;
- cmd = RV3032_EEPROM_CMD_WRITE;
- ret = dm_i2c_write(dev, RV3032_EEPROM_CMD,
- &cmd, 1);
- if (ret)
- goto exit_eerd;
- udelay(RV3032_EEBUSY_POLL);
- ret = rv3032_eeprom_busywait(dev);
- if (ret)
- goto exit_eerd;
- }
+exit_eerd:
- rv3032_exit_eerd(dev, eerd);
- return ret;
+}
+static int rv3032_eeprom_read(struct udevice *dev, unsigned int reg,
u8 *buf, unsigned int len)
+{
- u32 eerd;
- int i, ret;
- u8 cmd, data;
- ret = rv3032_enter_eerd(dev, &eerd);
- if (ret)
- return ret;
- for (i = 0; i < len; i++) {
- cmd = RV3032_EEPROM_USER + reg + i;
- ret = dm_i2c_write(dev, RV3032_EEPROM_ADDR,
- &cmd, 1);
- if (ret)
- goto exit_eerd;
- cmd = RV3032_EEPROM_CMD_READ;
- ret = dm_i2c_write(dev, RV3032_EEPROM_CMD,
- &cmd, 1);
- if (ret)
- goto exit_eerd;
- ret = rv3032_eeprom_busywait(dev);
- if (ret)
- goto exit_eerd;
- ret = dm_i2c_read(dev, RV3032_EEPROM_DATA, &data, sizeof(data));
- if (ret)
- goto exit_eerd;
- buf[i] = data;
- }
+exit_eerd:
- rv3032_exit_eerd(dev, eerd);
- return ret;
+}
+static int rv3032_probe(struct udevice *dev) +{
- i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS |
- DM_I2C_CHIP_WR_ADDRESS);
- return 0;
+}
+static const struct rtc_ops rv3032_rtc_ops = {
- .get = rv3032_get_time,
- .set = rv3032_set_time,
- .read = rv3032_eeprom_read,
- .write = rv3032_eeprom_write,
+};
+static const struct udevice_id rv3032_rtc_ids[] = {
- { .compatible = "microcrystal,rv3032", },
- { }
+};
+U_BOOT_DRIVER(rtc_rv3032) = {
- .name = "rtc-rv3028",
- .id = UCLASS_RTC,
- .probe = rv3032_probe,
- .of_match = rv3032_rtc_ids,
- .ops = &rv3032_rtc_ops,
+};
2.42.0
-- Alexandre Belloni, co-owner and COO, Bootlin Embedded Linux and Kernel engineering https://bootlin.com
This email contains confidential information. If you have received it in error, you must not read, use, copy or pass on this e-mail or its attachments. If you have received the e-mail in error, please inform me immediately by reply e-mail and then delete this e-mail from your system. Thank you
Diese E-Mail enthält vertrauliche Informationen. Sollten Sie sie irrtümlich erhalten haben, dürfen Sie diese E-Mail oder ihre Anhänge nicht lesen, verwenden, kopieren oder weitergeben. Sollten Sie die Mail versehentlich erhalten haben, teilen Sie mir dies bitte umgehend per Antwort-E-Mail mit und löschen Sie diese E-Mail dann aus Ihrem System. Vielen Dank
Beckhoff Automation GmbH & Co. KG | Managing Director: Dipl. Phys. Hans Beckhoff Registered office: Verl, Germany | Register court: Guetersloh HRA 7075

From: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
This gpio is optional so undonditionally freeing it will crash.
Signed-off-by: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com ---
drivers/usb/dwc3/dwc3-generic.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c index 7f0af05855..dcc342ed04 100644 --- a/drivers/usb/dwc3/dwc3-generic.c +++ b/drivers/usb/dwc3/dwc3-generic.c @@ -149,7 +149,9 @@ static int dwc3_generic_remove(struct udevice *dev, priv->ulpi_reset) { struct gpio_desc *ulpi_reset = priv->ulpi_reset;
- dm_gpio_free(ulpi_reset->dev, ulpi_reset); + if (priv->ulpi_reset) { + dm_gpio_free(ulpi_reset->dev, ulpi_reset); + } }
dwc3_remove(dwc3);

st 30. 8. 2023 v 20:16 odesílatel Steffen Dirkwinkel lists@steffen.cc napsal:
From: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
This gpio is optional so undonditionally freeing it will crash.
Signed-off-by: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
drivers/usb/dwc3/dwc3-generic.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c index 7f0af05855..dcc342ed04 100644 --- a/drivers/usb/dwc3/dwc3-generic.c +++ b/drivers/usb/dwc3/dwc3-generic.c @@ -149,7 +149,9 @@ static int dwc3_generic_remove(struct udevice *dev, priv->ulpi_reset) { struct gpio_desc *ulpi_reset = priv->ulpi_reset;
dm_gpio_free(ulpi_reset->dev, ulpi_reset);
if (priv->ulpi_reset) {
dm_gpio_free(ulpi_reset->dev, ulpi_reset);
} } dwc3_remove(dwc3);
-- 2.42.0
Already fixed by: https://lore.kernel.org/all/20230809033350.5718-1-venkatesh.abbarapu@amd.com...
Thanks, Michal

From: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
With the current config we'd put the fdt outside of memory.
Signed-off-by: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com ---
include/configs/xilinx_zynqmp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/configs/xilinx_zynqmp.h b/include/configs/xilinx_zynqmp.h index 74264b7bee..334fe95d66 100644 --- a/include/configs/xilinx_zynqmp.h +++ b/include/configs/xilinx_zynqmp.h @@ -50,7 +50,7 @@ #endif
#define ENV_MEM_LAYOUT_SETTINGS \ - "fdt_addr_r=0x40000000\0" \ + "fdt_addr_r=0x28000000\0" \ "fdt_size_r=0x400000\0" \ "pxefile_addr_r=0x10000000\0" \ "kernel_addr_r=0x18000000\0" \

On 8/30/23 16:03, Steffen Dirkwinkel wrote:
From: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
With the current config we'd put the fdt outside of memory.
Signed-off-by: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
include/configs/xilinx_zynqmp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/configs/xilinx_zynqmp.h b/include/configs/xilinx_zynqmp.h index 74264b7bee..334fe95d66 100644 --- a/include/configs/xilinx_zynqmp.h +++ b/include/configs/xilinx_zynqmp.h @@ -50,7 +50,7 @@ #endif
#define ENV_MEM_LAYOUT_SETTINGS \
- "fdt_addr_r=0x40000000\0" \
- "fdt_addr_r=0x28000000\0" \ "fdt_size_r=0x400000\0" \ "pxefile_addr_r=0x10000000\0" \ "kernel_addr_r=0x18000000\0" \
This is not the right way to go.
I have started to move these variables setting to DT. You can take a look at https://github.com/devicetree-org/dt-schema/commit/3815da51a138619f443abcf2f...
And fdt_addr_r is the same case. It should be moved to DT and remove it from here.
Thanks, Michal

From: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
This adds support for the Beckhoff CX8200 series of industrial embedded PCs. There is some information about the device and features here: https://www.beckhoff.com/en-en/products/ipc/embedded-pcs/cx8200-arm-cortex-a...
Currently supported/tested: - Boot from microSD - Ethernet - USB - rtc / rtc eeprom - tpm access - uart
Open points: - adding the psgtr usb phy doesn't work in linux (failed to get pll lock) - fpga loading currently only as u-boot script or pre launch cmd (type may be stored in eeprom of rtc so this could be made generic)
Signed-off-by: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com ---
arch/arm/dts/Makefile | 1 + arch/arm/dts/zynqmp-beckhoff-cx8200.dts | 247 +++ .../zynqmp-beckhoff-cx8200/psu_init_gpl.c | 1960 +++++++++++++++++ configs/xilinx_zynqmp_virt_defconfig | 2 +- 4 files changed, 2209 insertions(+), 1 deletion(-) create mode 100644 arch/arm/dts/zynqmp-beckhoff-cx8200.dts create mode 100644 board/xilinx/zynqmp/zynqmp-beckhoff-cx8200/psu_init_gpl.c
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 85fd5b1157..c5b5615362 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -393,6 +393,7 @@ dtb-$(CONFIG_ARCH_ZYNQ) += \ dtb-$(CONFIG_ARCH_ZYNQMP) += \ avnet-ultra96-rev1.dtb \ zynqmp-a2197-revA.dtb \ + zynqmp-beckhoff-cx8200.dtb \ zynqmp-dlc21-revA.dtb \ zynqmp-e-a2197-00-revA.dtb \ zynqmp-g-a2197-00-revA.dtb \ diff --git a/arch/arm/dts/zynqmp-beckhoff-cx8200.dts b/arch/arm/dts/zynqmp-beckhoff-cx8200.dts new file mode 100644 index 0000000000..9ed54b29b9 --- /dev/null +++ b/arch/arm/dts/zynqmp-beckhoff-cx8200.dts @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * dts file for Beckhoff CX8200 + * + * (C) Copyright 2023, Beckhoff Automation GmbH & Co. KG + * + * Steffen Dirkwinkel s.dirkwinkel@beckhoff.com + */ + +/dts-v1/; + +#include "zynqmp.dtsi" +#include "zynqmp-clk-ccf.dtsi" +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/pinctrl/pinctrl-zynqmp.h> +#include <dt-bindings/phy/phy.h> +#include <dt-bindings/interrupt-controller/irq.h> + +/ { + model = "Beckhoff CX8200"; + compatible = "beckhoff,cx8200-rev1", "beckhoff,cx8200", + "xlnx,zynqmp"; + + aliases { + ethernet0 = &gem2; + rtc0 = &rv3032; + serial0 = &uart1; + usb0 = &usb1; + }; + + chosen { + bootargs = "earlycon"; + stdout-path = "serial0:115200n8"; + }; + + cpus { + /delete-node/ cpu@2 ; + /delete-node/ cpu@3 ; + }; + + memory { + device_type = "memory"; + reg = <0x0 0x0 0x0 0x3ff00000>; + }; + + pmu { + compatible = "arm,armv8-pmuv3"; + interrupt-parent = <&gic>; + interrupts = <0 143 4>, + <0 144 4>, + <0 145 4>, + <0 146 4>; + interrupt-affinity = <&cpu0>, + <&cpu1>; + }; + + usb1_clk: usb1_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <26000000>; + }; +}; + +&fpd_dma_chan1 { + status = "okay"; +}; + +&fpd_dma_chan2 { + status = "okay"; +}; + +&fpd_dma_chan3 { + status = "okay"; +}; + +&fpd_dma_chan4 { + status = "okay"; +}; + +&fpd_dma_chan5 { + status = "okay"; +}; + +&fpd_dma_chan6 { + status = "okay"; +}; + +&fpd_dma_chan7 { + status = "okay"; +}; + +&fpd_dma_chan8 { + status = "okay"; +}; + +&gem2 { + status = "okay"; + nvmem-cells = <&gem2_mac_address>; + nvmem-cell-names = "mac-address"; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + phy0: ethernet-phy@0 { /* Broadcom B50212E */ + reg = <0>; + }; +}; + +&gpio { + status = "okay"; + + /* USB_EN */ + enable-hog { + gpio-hog; + gpios = <47 0>; + output-high; + }; +}; + +&i2c1 { + status = "okay"; + clock-frequency = <200000>; + scl-gpios = <&gpio 32 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + sda-gpios = <&gpio 33 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + pinctrl-names = "default", "gpio"; + pinctrl-0 = <&pinctrl_i2c1_default>; + pinctrl-1 = <&pinctrl_i2c1_gpio>; + + rv3032: rtc@51 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "microcrystal,rv3032"; + reg = <0x51>; + interrupt-parent = <&gpio>; + interrupts = <11 IRQ_TYPE_LEVEL_LOW>; + gem2_mac_address: mac-address@0 { + reg = <0x0 6>; + }; + }; +}; + +&pinctrl0 { + status = "okay"; + + pinctrl_usb1_default: usb1-default { + mux { + groups = "usb1_0_grp"; + function = "usb1"; + }; + + 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>; + }; + }; + + pinctrl_i2c1_default: i2c1-default { + mux { + groups = "i2c1_8_grp"; + function = "i2c1"; + }; + + conf { + groups = "i2c1_8_grp"; + bias-pull-up; + slew-rate = <SLEW_RATE_SLOW>; + power-source = <IO_STANDARD_LVCMOS33>; + }; + }; + + pinctrl_i2c1_gpio: i2c1-gpio { + mux { + groups = "gpio0_32_grp", "gpio0_33_grp"; + function = "gpio0"; + }; + + conf { + groups = "gpio0_32_grp", "gpio0_33_grp"; + slew-rate = <SLEW_RATE_SLOW>; + power-source = <IO_STANDARD_LVCMOS33>; + }; + }; +}; + +&sdhci0 { + clock-frequency = <200000000>; + status = "okay"; + disable-wp; + no-1-8-v; + xlnx,mio-bank = <0x0>; +}; + +&spi0 { + status = "okay"; + label = "TPM"; + num-cs = <1>; + tpm@0 { + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; + reg = <0>; + spi-max-frequency = <18500000>; + }; +}; + +&uart1 { + status = "okay"; +}; + +&usb1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb1_default>; +}; + +&dwc3_1 { + status = "okay"; + dr_mode = "host"; + maximum-speed = "super-speed"; +}; + +&watchdog0 { + status = "okay"; +}; + +&xilinx_ams { + status = "okay"; +}; + +&ams_ps { + status = "okay"; +}; + +&ams_pl { + status = "okay"; +}; \ No newline at end of file diff --git a/board/xilinx/zynqmp/zynqmp-beckhoff-cx8200/psu_init_gpl.c b/board/xilinx/zynqmp/zynqmp-beckhoff-cx8200/psu_init_gpl.c new file mode 100644 index 0000000000..7437d46c59 --- /dev/null +++ b/board/xilinx/zynqmp/zynqmp-beckhoff-cx8200/psu_init_gpl.c @@ -0,0 +1,1960 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (c) Copyright 2015 Xilinx, Inc. All rights reserved. + */ + +#include <asm/arch/psu_init_gpl.h> +#include <xil_io.h> + +static int serdes_rst_seq(u32 pllsel, u32 lane3_protocol, u32 lane3_rate, + u32 lane2_protocol, u32 lane2_rate, + u32 lane1_protocol, u32 lane1_rate, + u32 lane0_protocol, u32 lane0_rate) +{ + Xil_Out32(0xFD410098, 0x00000000); + Xil_Out32(0xFD401010, 0x00000040); + Xil_Out32(0xFD405010, 0x00000040); + Xil_Out32(0xFD409010, 0x00000040); + Xil_Out32(0xFD40D010, 0x00000040); + Xil_Out32(0xFD402084, 0x00000080); + Xil_Out32(0xFD406084, 0x00000080); + Xil_Out32(0xFD40A084, 0x00000080); + Xil_Out32(0xFD40E084, 0x00000080); + Xil_Out32(0xFD410098, 0x00000004); + mask_delay(50); + if (lane0_rate == 1) + Xil_Out32(0xFD410098, 0x0000000E); + Xil_Out32(0xFD410098, 0x00000006); + if (lane0_rate == 1) { + Xil_Out32(0xFD40000C, 0x00000004); + Xil_Out32(0xFD40400C, 0x00000004); + Xil_Out32(0xFD40800C, 0x00000004); + Xil_Out32(0xFD40C00C, 0x00000004); + Xil_Out32(0xFD410098, 0x00000007); + mask_delay(400); + Xil_Out32(0xFD40000C, 0x0000000C); + Xil_Out32(0xFD40400C, 0x0000000C); + Xil_Out32(0xFD40800C, 0x0000000C); + Xil_Out32(0xFD40C00C, 0x0000000C); + mask_delay(15); + Xil_Out32(0xFD410098, 0x0000000F); + mask_delay(100); + } + if (pllsel == 0) + mask_poll(0xFD4023E4, 0x00000010U); + if (pllsel == 1) + mask_poll(0xFD4063E4, 0x00000010U); + if (pllsel == 2) + mask_poll(0xFD40A3E4, 0x00000010U); + if (pllsel == 3) + mask_poll(0xFD40E3E4, 0x00000010U); + mask_delay(50); + Xil_Out32(0xFD401010, 0x000000C0); + Xil_Out32(0xFD405010, 0x000000C0); + Xil_Out32(0xFD409010, 0x000000C0); + Xil_Out32(0xFD40D010, 0x000000C0); + Xil_Out32(0xFD401010, 0x00000080); + Xil_Out32(0xFD405010, 0x00000080); + Xil_Out32(0xFD409010, 0x00000080); + Xil_Out32(0xFD40D010, 0x00000080); + + Xil_Out32(0xFD402084, 0x000000C0); + Xil_Out32(0xFD406084, 0x000000C0); + Xil_Out32(0xFD40A084, 0x000000C0); + Xil_Out32(0xFD40E084, 0x000000C0); + mask_delay(50); + Xil_Out32(0xFD402084, 0x00000080); + Xil_Out32(0xFD406084, 0x00000080); + Xil_Out32(0xFD40A084, 0x00000080); + Xil_Out32(0xFD40E084, 0x00000080); + mask_delay(50); + Xil_Out32(0xFD401010, 0x00000000); + Xil_Out32(0xFD405010, 0x00000000); + Xil_Out32(0xFD409010, 0x00000000); + Xil_Out32(0xFD40D010, 0x00000000); + Xil_Out32(0xFD402084, 0x00000000); + Xil_Out32(0xFD406084, 0x00000000); + Xil_Out32(0xFD40A084, 0x00000000); + Xil_Out32(0xFD40E084, 0x00000000); + mask_delay(500); + return 1; +} + +static int serdes_bist_static_settings(u32 lane_active) +{ + if (lane_active == 0) { + Xil_Out32(0xFD403004, (Xil_In32(0xFD403004) & 0xFFFFFF1F)); + Xil_Out32(0xFD403068, 0x1); + Xil_Out32(0xFD40306C, 0x1); + Xil_Out32(0xFD4010AC, 0x0020); + Xil_Out32(0xFD403008, 0x0); + Xil_Out32(0xFD40300C, 0xF4); + Xil_Out32(0xFD403010, 0x0); + Xil_Out32(0xFD403014, 0x0); + Xil_Out32(0xFD403018, 0x00); + Xil_Out32(0xFD40301C, 0xFB); + Xil_Out32(0xFD403020, 0xFF); + Xil_Out32(0xFD403024, 0x0); + Xil_Out32(0xFD403028, 0x00); + Xil_Out32(0xFD40302C, 0x00); + Xil_Out32(0xFD403030, 0x4A); + Xil_Out32(0xFD403034, 0x4A); + Xil_Out32(0xFD403038, 0x4A); + Xil_Out32(0xFD40303C, 0x4A); + Xil_Out32(0xFD403040, 0x0); + Xil_Out32(0xFD403044, 0x14); + Xil_Out32(0xFD403048, 0x02); + Xil_Out32(0xFD403004, (Xil_In32(0xFD403004) & 0xFFFFFF1F)); + } + if (lane_active == 1) { + Xil_Out32(0xFD407004, (Xil_In32(0xFD407004) & 0xFFFFFF1F)); + Xil_Out32(0xFD407068, 0x1); + Xil_Out32(0xFD40706C, 0x1); + Xil_Out32(0xFD4050AC, 0x0020); + Xil_Out32(0xFD407008, 0x0); + Xil_Out32(0xFD40700C, 0xF4); + Xil_Out32(0xFD407010, 0x0); + Xil_Out32(0xFD407014, 0x0); + Xil_Out32(0xFD407018, 0x00); + Xil_Out32(0xFD40701C, 0xFB); + Xil_Out32(0xFD407020, 0xFF); + Xil_Out32(0xFD407024, 0x0); + Xil_Out32(0xFD407028, 0x00); + Xil_Out32(0xFD40702C, 0x00); + Xil_Out32(0xFD407030, 0x4A); + Xil_Out32(0xFD407034, 0x4A); + Xil_Out32(0xFD407038, 0x4A); + Xil_Out32(0xFD40703C, 0x4A); + Xil_Out32(0xFD407040, 0x0); + Xil_Out32(0xFD407044, 0x14); + Xil_Out32(0xFD407048, 0x02); + Xil_Out32(0xFD407004, (Xil_In32(0xFD407004) & 0xFFFFFF1F)); + } + + if (lane_active == 2) { + Xil_Out32(0xFD40B004, (Xil_In32(0xFD40B004) & 0xFFFFFF1F)); + Xil_Out32(0xFD40B068, 0x1); + Xil_Out32(0xFD40B06C, 0x1); + Xil_Out32(0xFD4090AC, 0x0020); + Xil_Out32(0xFD40B008, 0x0); + Xil_Out32(0xFD40B00C, 0xF4); + Xil_Out32(0xFD40B010, 0x0); + Xil_Out32(0xFD40B014, 0x0); + Xil_Out32(0xFD40B018, 0x00); + Xil_Out32(0xFD40B01C, 0xFB); + Xil_Out32(0xFD40B020, 0xFF); + Xil_Out32(0xFD40B024, 0x0); + Xil_Out32(0xFD40B028, 0x00); + Xil_Out32(0xFD40B02C, 0x00); + Xil_Out32(0xFD40B030, 0x4A); + Xil_Out32(0xFD40B034, 0x4A); + Xil_Out32(0xFD40B038, 0x4A); + Xil_Out32(0xFD40B03C, 0x4A); + Xil_Out32(0xFD40B040, 0x0); + Xil_Out32(0xFD40B044, 0x14); + Xil_Out32(0xFD40B048, 0x02); + Xil_Out32(0xFD40B004, (Xil_In32(0xFD40B004) & 0xFFFFFF1F)); + } + + if (lane_active == 3) { + Xil_Out32(0xFD40F004, (Xil_In32(0xFD40F004) & 0xFFFFFF1F)); + Xil_Out32(0xFD40F068, 0x1); + Xil_Out32(0xFD40F06C, 0x1); + Xil_Out32(0xFD40D0AC, 0x0020); + Xil_Out32(0xFD40F008, 0x0); + Xil_Out32(0xFD40F00C, 0xF4); + Xil_Out32(0xFD40F010, 0x0); + Xil_Out32(0xFD40F014, 0x0); + Xil_Out32(0xFD40F018, 0x00); + Xil_Out32(0xFD40F01C, 0xFB); + Xil_Out32(0xFD40F020, 0xFF); + Xil_Out32(0xFD40F024, 0x0); + Xil_Out32(0xFD40F028, 0x00); + Xil_Out32(0xFD40F02C, 0x00); + Xil_Out32(0xFD40F030, 0x4A); + Xil_Out32(0xFD40F034, 0x4A); + Xil_Out32(0xFD40F038, 0x4A); + Xil_Out32(0xFD40F03C, 0x4A); + Xil_Out32(0xFD40F040, 0x0); + Xil_Out32(0xFD40F044, 0x14); + Xil_Out32(0xFD40F048, 0x02); + Xil_Out32(0xFD40F004, (Xil_In32(0xFD40F004) & 0xFFFFFF1F)); + } + return 1; +} + +static int serdes_bist_run(u32 lane_active) +{ + if (lane_active == 0) { + psu_mask_write(0xFD410044, 0x00000003U, 0x00000000U); + psu_mask_write(0xFD410040, 0x00000003U, 0x00000000U); + psu_mask_write(0xFD410038, 0x00000007U, 0x00000001U); + Xil_Out32(0xFD4010AC, 0x0020); + Xil_Out32(0xFD403004, (Xil_In32(0xFD403004) | 0x1)); + } + if (lane_active == 1) { + psu_mask_write(0xFD410044, 0x0000000CU, 0x00000000U); + psu_mask_write(0xFD410040, 0x0000000CU, 0x00000000U); + psu_mask_write(0xFD410038, 0x00000070U, 0x00000010U); + Xil_Out32(0xFD4050AC, 0x0020); + Xil_Out32(0xFD407004, (Xil_In32(0xFD407004) | 0x1)); + } + if (lane_active == 2) { + psu_mask_write(0xFD410044, 0x00000030U, 0x00000000U); + psu_mask_write(0xFD410040, 0x00000030U, 0x00000000U); + psu_mask_write(0xFD41003C, 0x00000007U, 0x00000001U); + Xil_Out32(0xFD4090AC, 0x0020); + Xil_Out32(0xFD40B004, (Xil_In32(0xFD40B004) | 0x1)); + } + if (lane_active == 3) { + psu_mask_write(0xFD410040, 0x000000C0U, 0x00000000U); + psu_mask_write(0xFD410044, 0x000000C0U, 0x00000000U); + psu_mask_write(0xFD41003C, 0x00000070U, 0x00000010U); + Xil_Out32(0xFD40D0AC, 0x0020); + Xil_Out32(0xFD40F004, (Xil_In32(0xFD40F004) | 0x1)); + } + mask_delay(100); + return 1; +} + +static int serdes_bist_result(u32 lane_active) +{ + u32 pkt_cnt_l0, pkt_cnt_h0, err_cnt_l0, err_cnt_h0; + if (lane_active == 0) { + pkt_cnt_l0 = Xil_In32(0xFD40304C); + pkt_cnt_h0 = Xil_In32(0xFD403050); + err_cnt_l0 = Xil_In32(0xFD403054); + err_cnt_h0 = Xil_In32(0xFD403058); + } + if (lane_active == 1) { + pkt_cnt_l0 = Xil_In32(0xFD40704C); + pkt_cnt_h0 = Xil_In32(0xFD407050); + err_cnt_l0 = Xil_In32(0xFD407054); + err_cnt_h0 = Xil_In32(0xFD407058); + } + if (lane_active == 2) { + pkt_cnt_l0 = Xil_In32(0xFD40B04C); + pkt_cnt_h0 = Xil_In32(0xFD40B050); + err_cnt_l0 = Xil_In32(0xFD40B054); + err_cnt_h0 = Xil_In32(0xFD40B058); + } + if (lane_active == 3) { + pkt_cnt_l0 = Xil_In32(0xFD40F04C); + pkt_cnt_h0 = Xil_In32(0xFD40F050); + err_cnt_l0 = Xil_In32(0xFD40F054); + err_cnt_h0 = Xil_In32(0xFD40F058); + } + if (lane_active == 0) + Xil_Out32(0xFD403004, 0x0); + if (lane_active == 1) + Xil_Out32(0xFD407004, 0x0); + if (lane_active == 2) + Xil_Out32(0xFD40B004, 0x0); + if (lane_active == 3) + Xil_Out32(0xFD40F004, 0x0); + if ((err_cnt_l0 > 0) || (err_cnt_h0 > 0) + || ((pkt_cnt_l0 == 0) && (pkt_cnt_h0 == 0))) + return 0; + return 1; +} + +static int serdes_illcalib_pcie_gen1(u32 pllsel, u32 lane3_protocol, + u32 lane3_rate, u32 lane2_protocol, + u32 lane2_rate, u32 lane1_protocol, + u32 lane1_rate, u32 lane0_protocol, + u32 lane0_rate, u32 gen2_calib) +{ + u64 tempbistresult; + u32 currbistresult[4]; + u32 prevbistresult[4]; + u32 itercount = 0; + u32 ill12_val[4], ill1_val[4]; + u32 loop = 0; + u32 iterresult[8]; + u32 meancount[4]; + u32 bistpasscount[4]; + u32 meancountalt[4]; + u32 meancountalt_bistpasscount[4]; + u32 lane0_active; + u32 lane1_active; + u32 lane2_active; + u32 lane3_active; + + lane0_active = (lane0_protocol == 1); + lane1_active = (lane1_protocol == 1); + lane2_active = (lane2_protocol == 1); + lane3_active = (lane3_protocol == 1); + for (loop = 0; loop <= 3; loop++) { + iterresult[loop] = 0; + iterresult[loop + 4] = 0; + meancountalt[loop] = 0; + meancountalt_bistpasscount[loop] = 0; + meancount[loop] = 0; + prevbistresult[loop] = 0; + bistpasscount[loop] = 0; + } + itercount = 0; + if (lane0_active) + serdes_bist_static_settings(0); + if (lane1_active) + serdes_bist_static_settings(1); + if (lane2_active) + serdes_bist_static_settings(2); + if (lane3_active) + serdes_bist_static_settings(3); + do { + if (gen2_calib != 1) { + if (lane0_active == 1) + ill1_val[0] = ((0x04 + itercount * 8) % 0x100); + if (lane0_active == 1) + ill12_val[0] = + ((0x04 + itercount * 8) >= + 0x100) ? 0x10 : 0x00; + if (lane1_active == 1) + ill1_val[1] = ((0x04 + itercount * 8) % 0x100); + if (lane1_active == 1) + ill12_val[1] = + ((0x04 + itercount * 8) >= + 0x100) ? 0x10 : 0x00; + if (lane2_active == 1) + ill1_val[2] = ((0x04 + itercount * 8) % 0x100); + if (lane2_active == 1) + ill12_val[2] = + ((0x04 + itercount * 8) >= + 0x100) ? 0x10 : 0x00; + if (lane3_active == 1) + ill1_val[3] = ((0x04 + itercount * 8) % 0x100); + if (lane3_active == 1) + ill12_val[3] = + ((0x04 + itercount * 8) >= + 0x100) ? 0x10 : 0x00; + + if (lane0_active == 1) + Xil_Out32(0xFD401924, ill1_val[0]); + if (lane0_active == 1) + psu_mask_write(0xFD401990, 0x000000F0U, + ill12_val[0]); + if (lane1_active == 1) + Xil_Out32(0xFD405924, ill1_val[1]); + if (lane1_active == 1) + psu_mask_write(0xFD405990, 0x000000F0U, + ill12_val[1]); + if (lane2_active == 1) + Xil_Out32(0xFD409924, ill1_val[2]); + if (lane2_active == 1) + psu_mask_write(0xFD409990, 0x000000F0U, + ill12_val[2]); + if (lane3_active == 1) + Xil_Out32(0xFD40D924, ill1_val[3]); + if (lane3_active == 1) + psu_mask_write(0xFD40D990, 0x000000F0U, + ill12_val[3]); + } + if (gen2_calib == 1) { + if (lane0_active == 1) + ill1_val[0] = ((0x104 + itercount * 8) % 0x100); + if (lane0_active == 1) + ill12_val[0] = + ((0x104 + itercount * 8) >= + 0x200) ? 0x02 : 0x01; + if (lane1_active == 1) + ill1_val[1] = ((0x104 + itercount * 8) % 0x100); + if (lane1_active == 1) + ill12_val[1] = + ((0x104 + itercount * 8) >= + 0x200) ? 0x02 : 0x01; + if (lane2_active == 1) + ill1_val[2] = ((0x104 + itercount * 8) % 0x100); + if (lane2_active == 1) + ill12_val[2] = + ((0x104 + itercount * 8) >= + 0x200) ? 0x02 : 0x01; + if (lane3_active == 1) + ill1_val[3] = ((0x104 + itercount * 8) % 0x100); + if (lane3_active == 1) + ill12_val[3] = + ((0x104 + itercount * 8) >= + 0x200) ? 0x02 : 0x01; + + if (lane0_active == 1) + Xil_Out32(0xFD401928, ill1_val[0]); + if (lane0_active == 1) + psu_mask_write(0xFD401990, 0x0000000FU, + ill12_val[0]); + if (lane1_active == 1) + Xil_Out32(0xFD405928, ill1_val[1]); + if (lane1_active == 1) + psu_mask_write(0xFD405990, 0x0000000FU, + ill12_val[1]); + if (lane2_active == 1) + Xil_Out32(0xFD409928, ill1_val[2]); + if (lane2_active == 1) + psu_mask_write(0xFD409990, 0x0000000FU, + ill12_val[2]); + if (lane3_active == 1) + Xil_Out32(0xFD40D928, ill1_val[3]); + if (lane3_active == 1) + psu_mask_write(0xFD40D990, 0x0000000FU, + ill12_val[3]); + } + + if (lane0_active == 1) + psu_mask_write(0xFD401018, 0x00000030U, 0x00000010U); + if (lane1_active == 1) + psu_mask_write(0xFD405018, 0x00000030U, 0x00000010U); + if (lane2_active == 1) + psu_mask_write(0xFD409018, 0x00000030U, 0x00000010U); + if (lane3_active == 1) + psu_mask_write(0xFD40D018, 0x00000030U, 0x00000010U); + if (lane0_active == 1) + currbistresult[0] = 0; + if (lane1_active == 1) + currbistresult[1] = 0; + if (lane2_active == 1) + currbistresult[2] = 0; + if (lane3_active == 1) + currbistresult[3] = 0; + serdes_rst_seq(pllsel, lane3_protocol, lane3_rate, + lane2_protocol, lane2_rate, lane1_protocol, + lane1_rate, lane0_protocol, lane0_rate); + if (lane3_active == 1) + serdes_bist_run(3); + if (lane2_active == 1) + serdes_bist_run(2); + if (lane1_active == 1) + serdes_bist_run(1); + if (lane0_active == 1) + serdes_bist_run(0); + tempbistresult = 0; + if (lane3_active == 1) + tempbistresult = tempbistresult | serdes_bist_result(3); + tempbistresult = tempbistresult << 1; + if (lane2_active == 1) + tempbistresult = tempbistresult | serdes_bist_result(2); + tempbistresult = tempbistresult << 1; + if (lane1_active == 1) + tempbistresult = tempbistresult | serdes_bist_result(1); + tempbistresult = tempbistresult << 1; + if (lane0_active == 1) + tempbistresult = tempbistresult | serdes_bist_result(0); + Xil_Out32(0xFD410098, 0x0); + Xil_Out32(0xFD410098, 0x2); + + if (itercount < 32) { + iterresult[0] = + ((iterresult[0] << 1) | + ((tempbistresult & 0x1) == 0x1)); + iterresult[1] = + ((iterresult[1] << 1) | + ((tempbistresult & 0x2) == 0x2)); + iterresult[2] = + ((iterresult[2] << 1) | + ((tempbistresult & 0x4) == 0x4)); + iterresult[3] = + ((iterresult[3] << 1) | + ((tempbistresult & 0x8) == 0x8)); + } else { + iterresult[4] = + ((iterresult[4] << 1) | + ((tempbistresult & 0x1) == 0x1)); + iterresult[5] = + ((iterresult[5] << 1) | + ((tempbistresult & 0x2) == 0x2)); + iterresult[6] = + ((iterresult[6] << 1) | + ((tempbistresult & 0x4) == 0x4)); + iterresult[7] = + ((iterresult[7] << 1) | + ((tempbistresult & 0x8) == 0x8)); + } + currbistresult[0] = + currbistresult[0] | ((tempbistresult & 0x1) == 1); + currbistresult[1] = + currbistresult[1] | ((tempbistresult & 0x2) == 0x2); + currbistresult[2] = + currbistresult[2] | ((tempbistresult & 0x4) == 0x4); + currbistresult[3] = + currbistresult[3] | ((tempbistresult & 0x8) == 0x8); + + for (loop = 0; loop <= 3; loop++) { + if ((currbistresult[loop] == 1) + && (prevbistresult[loop] == 1)) + bistpasscount[loop] = bistpasscount[loop] + 1; + if ((bistpasscount[loop] < 4) + && (currbistresult[loop] == 0) && (itercount > 2)) { + if (meancountalt_bistpasscount[loop] < + bistpasscount[loop]) { + meancountalt_bistpasscount[loop] = + bistpasscount[loop]; + meancountalt[loop] = + ((itercount - 1) - + ((bistpasscount[loop] + 1) / 2)); + } + bistpasscount[loop] = 0; + } + if ((meancount[loop] == 0) && (bistpasscount[loop] >= 4) + && ((currbistresult[loop] == 0) + || (itercount == 63)) + && (prevbistresult[loop] == 1)) + meancount[loop] = + (itercount - 1) - + ((bistpasscount[loop] + 1) / 2); + prevbistresult[loop] = currbistresult[loop]; + } + } while (++itercount < 64); + + for (loop = 0; loop <= 3; loop++) { + if ((lane0_active == 0) && (loop == 0)) + continue; + if ((lane1_active == 0) && (loop == 1)) + continue; + if ((lane2_active == 0) && (loop == 2)) + continue; + if ((lane3_active == 0) && (loop == 3)) + continue; + + if (meancount[loop] == 0) + meancount[loop] = meancountalt[loop]; + + if (gen2_calib != 1) { + ill1_val[loop] = ((0x04 + meancount[loop] * 8) % 0x100); + ill12_val[loop] = + ((0x04 + meancount[loop] * 8) >= + 0x100) ? 0x10 : 0x00; + + } + if (gen2_calib == 1) { + ill1_val[loop] = + ((0x104 + meancount[loop] * 8) % 0x100); + ill12_val[loop] = + ((0x104 + meancount[loop] * 8) >= + 0x200) ? 0x02 : 0x01; + + } + } + if (gen2_calib != 1) { + if (lane0_active == 1) + Xil_Out32(0xFD401924, ill1_val[0]); + if (lane0_active == 1) + psu_mask_write(0xFD401990, 0x000000F0U, ill12_val[0]); + if (lane1_active == 1) + Xil_Out32(0xFD405924, ill1_val[1]); + if (lane1_active == 1) + psu_mask_write(0xFD405990, 0x000000F0U, ill12_val[1]); + if (lane2_active == 1) + Xil_Out32(0xFD409924, ill1_val[2]); + if (lane2_active == 1) + psu_mask_write(0xFD409990, 0x000000F0U, ill12_val[2]); + if (lane3_active == 1) + Xil_Out32(0xFD40D924, ill1_val[3]); + if (lane3_active == 1) + psu_mask_write(0xFD40D990, 0x000000F0U, ill12_val[3]); + } + if (gen2_calib == 1) { + if (lane0_active == 1) + Xil_Out32(0xFD401928, ill1_val[0]); + if (lane0_active == 1) + psu_mask_write(0xFD401990, 0x0000000FU, ill12_val[0]); + if (lane1_active == 1) + Xil_Out32(0xFD405928, ill1_val[1]); + if (lane1_active == 1) + psu_mask_write(0xFD405990, 0x0000000FU, ill12_val[1]); + if (lane2_active == 1) + Xil_Out32(0xFD409928, ill1_val[2]); + if (lane2_active == 1) + psu_mask_write(0xFD409990, 0x0000000FU, ill12_val[2]); + if (lane3_active == 1) + Xil_Out32(0xFD40D928, ill1_val[3]); + if (lane3_active == 1) + psu_mask_write(0xFD40D990, 0x0000000FU, ill12_val[3]); + } + + if (lane0_active == 1) + psu_mask_write(0xFD401018, 0x00000030U, 0x00000000U); + if (lane1_active == 1) + psu_mask_write(0xFD405018, 0x00000030U, 0x00000000U); + if (lane2_active == 1) + psu_mask_write(0xFD409018, 0x00000030U, 0x00000000U); + if (lane3_active == 1) + psu_mask_write(0xFD40D018, 0x00000030U, 0x00000000U); + + Xil_Out32(0xFD410098, 0); + if (lane0_active == 1) { + Xil_Out32(0xFD403004, 0); + Xil_Out32(0xFD403008, 0); + Xil_Out32(0xFD40300C, 0); + Xil_Out32(0xFD403010, 0); + Xil_Out32(0xFD403014, 0); + Xil_Out32(0xFD403018, 0); + Xil_Out32(0xFD40301C, 0); + Xil_Out32(0xFD403020, 0); + Xil_Out32(0xFD403024, 0); + Xil_Out32(0xFD403028, 0); + Xil_Out32(0xFD40302C, 0); + Xil_Out32(0xFD403030, 0); + Xil_Out32(0xFD403034, 0); + Xil_Out32(0xFD403038, 0); + Xil_Out32(0xFD40303C, 0); + Xil_Out32(0xFD403040, 0); + Xil_Out32(0xFD403044, 0); + Xil_Out32(0xFD403048, 0); + Xil_Out32(0xFD40304C, 0); + Xil_Out32(0xFD403050, 0); + Xil_Out32(0xFD403054, 0); + Xil_Out32(0xFD403058, 0); + Xil_Out32(0xFD403068, 1); + Xil_Out32(0xFD40306C, 0); + Xil_Out32(0xFD4010AC, 0); + psu_mask_write(0xFD410044, 0x00000003U, 0x00000001U); + psu_mask_write(0xFD410040, 0x00000003U, 0x00000001U); + psu_mask_write(0xFD410038, 0x00000007U, 0x00000000U); + } + if (lane1_active == 1) { + Xil_Out32(0xFD407004, 0); + Xil_Out32(0xFD407008, 0); + Xil_Out32(0xFD40700C, 0); + Xil_Out32(0xFD407010, 0); + Xil_Out32(0xFD407014, 0); + Xil_Out32(0xFD407018, 0); + Xil_Out32(0xFD40701C, 0); + Xil_Out32(0xFD407020, 0); + Xil_Out32(0xFD407024, 0); + Xil_Out32(0xFD407028, 0); + Xil_Out32(0xFD40702C, 0); + Xil_Out32(0xFD407030, 0); + Xil_Out32(0xFD407034, 0); + Xil_Out32(0xFD407038, 0); + Xil_Out32(0xFD40703C, 0); + Xil_Out32(0xFD407040, 0); + Xil_Out32(0xFD407044, 0); + Xil_Out32(0xFD407048, 0); + Xil_Out32(0xFD40704C, 0); + Xil_Out32(0xFD407050, 0); + Xil_Out32(0xFD407054, 0); + Xil_Out32(0xFD407058, 0); + Xil_Out32(0xFD407068, 1); + Xil_Out32(0xFD40706C, 0); + Xil_Out32(0xFD4050AC, 0); + psu_mask_write(0xFD410044, 0x0000000CU, 0x00000004U); + psu_mask_write(0xFD410040, 0x0000000CU, 0x00000004U); + psu_mask_write(0xFD410038, 0x00000070U, 0x00000000U); + } + if (lane2_active == 1) { + Xil_Out32(0xFD40B004, 0); + Xil_Out32(0xFD40B008, 0); + Xil_Out32(0xFD40B00C, 0); + Xil_Out32(0xFD40B010, 0); + Xil_Out32(0xFD40B014, 0); + Xil_Out32(0xFD40B018, 0); + Xil_Out32(0xFD40B01C, 0); + Xil_Out32(0xFD40B020, 0); + Xil_Out32(0xFD40B024, 0); + Xil_Out32(0xFD40B028, 0); + Xil_Out32(0xFD40B02C, 0); + Xil_Out32(0xFD40B030, 0); + Xil_Out32(0xFD40B034, 0); + Xil_Out32(0xFD40B038, 0); + Xil_Out32(0xFD40B03C, 0); + Xil_Out32(0xFD40B040, 0); + Xil_Out32(0xFD40B044, 0); + Xil_Out32(0xFD40B048, 0); + Xil_Out32(0xFD40B04C, 0); + Xil_Out32(0xFD40B050, 0); + Xil_Out32(0xFD40B054, 0); + Xil_Out32(0xFD40B058, 0); + Xil_Out32(0xFD40B068, 1); + Xil_Out32(0xFD40B06C, 0); + Xil_Out32(0xFD4090AC, 0); + psu_mask_write(0xFD410044, 0x00000030U, 0x00000010U); + psu_mask_write(0xFD410040, 0x00000030U, 0x00000010U); + psu_mask_write(0xFD41003C, 0x00000007U, 0x00000000U); + } + if (lane3_active == 1) { + Xil_Out32(0xFD40F004, 0); + Xil_Out32(0xFD40F008, 0); + Xil_Out32(0xFD40F00C, 0); + Xil_Out32(0xFD40F010, 0); + Xil_Out32(0xFD40F014, 0); + Xil_Out32(0xFD40F018, 0); + Xil_Out32(0xFD40F01C, 0); + Xil_Out32(0xFD40F020, 0); + Xil_Out32(0xFD40F024, 0); + Xil_Out32(0xFD40F028, 0); + Xil_Out32(0xFD40F02C, 0); + Xil_Out32(0xFD40F030, 0); + Xil_Out32(0xFD40F034, 0); + Xil_Out32(0xFD40F038, 0); + Xil_Out32(0xFD40F03C, 0); + Xil_Out32(0xFD40F040, 0); + Xil_Out32(0xFD40F044, 0); + Xil_Out32(0xFD40F048, 0); + Xil_Out32(0xFD40F04C, 0); + Xil_Out32(0xFD40F050, 0); + Xil_Out32(0xFD40F054, 0); + Xil_Out32(0xFD40F058, 0); + Xil_Out32(0xFD40F068, 1); + Xil_Out32(0xFD40F06C, 0); + Xil_Out32(0xFD40D0AC, 0); + psu_mask_write(0xFD410044, 0x000000C0U, 0x00000040U); + psu_mask_write(0xFD410040, 0x000000C0U, 0x00000040U); + psu_mask_write(0xFD41003C, 0x00000070U, 0x00000000U); + } + return 1; +} + +static int serdes_illcalib(u32 lane3_protocol, u32 lane3_rate, + u32 lane2_protocol, u32 lane2_rate, + u32 lane1_protocol, u32 lane1_rate, + u32 lane0_protocol, u32 lane0_rate) +{ + unsigned int rdata = 0; + unsigned int sata_gen2 = 1; + unsigned int temp_ill12 = 0; + unsigned int temp_PLL_REF_SEL_OFFSET; + unsigned int temp_TM_IQ_ILL1; + unsigned int temp_TM_E_ILL1; + unsigned int temp_tx_dig_tm_61; + unsigned int temp_tm_dig_6; + unsigned int temp_pll_fbdiv_frac_3_msb_offset; + + if ((lane0_protocol == 2) || (lane0_protocol == 1)) { + Xil_Out32(0xFD401910, 0xF3); + Xil_Out32(0xFD40193C, 0xF3); + Xil_Out32(0xFD401914, 0xF3); + Xil_Out32(0xFD401940, 0xF3); + } + if ((lane1_protocol == 2) || (lane1_protocol == 1)) { + Xil_Out32(0xFD405910, 0xF3); + Xil_Out32(0xFD40593C, 0xF3); + Xil_Out32(0xFD405914, 0xF3); + Xil_Out32(0xFD405940, 0xF3); + } + if ((lane2_protocol == 2) || (lane2_protocol == 1)) { + Xil_Out32(0xFD409910, 0xF3); + Xil_Out32(0xFD40993C, 0xF3); + Xil_Out32(0xFD409914, 0xF3); + Xil_Out32(0xFD409940, 0xF3); + } + if ((lane3_protocol == 2) || (lane3_protocol == 1)) { + Xil_Out32(0xFD40D910, 0xF3); + Xil_Out32(0xFD40D93C, 0xF3); + Xil_Out32(0xFD40D914, 0xF3); + Xil_Out32(0xFD40D940, 0xF3); + } + + if (sata_gen2 == 1) { + if (lane0_protocol == 2) { + temp_pll_fbdiv_frac_3_msb_offset = Xil_In32(0xFD402360); + Xil_Out32(0xFD402360, 0x0); + temp_PLL_REF_SEL_OFFSET = Xil_In32(0xFD410000); + psu_mask_write(0xFD410000, 0x0000001FU, 0x0000000DU); + temp_TM_IQ_ILL1 = Xil_In32(0xFD4018F8); + temp_TM_E_ILL1 = Xil_In32(0xFD401924); + Xil_Out32(0xFD4018F8, 0x78); + temp_tx_dig_tm_61 = Xil_In32(0xFD4000F4); + temp_tm_dig_6 = Xil_In32(0xFD40106C); + psu_mask_write(0xFD4000F4, 0x0000000BU, 0x00000000U); + psu_mask_write(0xFD40106C, 0x0000000FU, 0x00000000U); + temp_ill12 = Xil_In32(0xFD401990) & 0xF0; + + serdes_illcalib_pcie_gen1(0, 0, 0, 0, 0, 0, 0, 1, 0, 0); + + Xil_Out32(0xFD402360, temp_pll_fbdiv_frac_3_msb_offset); + Xil_Out32(0xFD410000, temp_PLL_REF_SEL_OFFSET); + Xil_Out32(0xFD4018F8, temp_TM_IQ_ILL1); + Xil_Out32(0xFD4000F4, temp_tx_dig_tm_61); + Xil_Out32(0xFD40106C, temp_tm_dig_6); + Xil_Out32(0xFD401928, Xil_In32(0xFD401924)); + temp_ill12 = + temp_ill12 | (Xil_In32(0xFD401990) >> 4 & 0xF); + Xil_Out32(0xFD401990, temp_ill12); + Xil_Out32(0xFD401924, temp_TM_E_ILL1); + } + if (lane1_protocol == 2) { + temp_pll_fbdiv_frac_3_msb_offset = Xil_In32(0xFD406360); + Xil_Out32(0xFD406360, 0x0); + temp_PLL_REF_SEL_OFFSET = Xil_In32(0xFD410004); + psu_mask_write(0xFD410004, 0x0000001FU, 0x0000000DU); + temp_TM_IQ_ILL1 = Xil_In32(0xFD4058F8); + temp_TM_E_ILL1 = Xil_In32(0xFD405924); + Xil_Out32(0xFD4058F8, 0x78); + temp_tx_dig_tm_61 = Xil_In32(0xFD4040F4); + temp_tm_dig_6 = Xil_In32(0xFD40506C); + psu_mask_write(0xFD4040F4, 0x0000000BU, 0x00000000U); + psu_mask_write(0xFD40506C, 0x0000000FU, 0x00000000U); + temp_ill12 = Xil_In32(0xFD405990) & 0xF0; + + serdes_illcalib_pcie_gen1(1, 0, 0, 0, 0, 1, 0, 0, 0, 0); + + Xil_Out32(0xFD406360, temp_pll_fbdiv_frac_3_msb_offset); + Xil_Out32(0xFD410004, temp_PLL_REF_SEL_OFFSET); + Xil_Out32(0xFD4058F8, temp_TM_IQ_ILL1); + Xil_Out32(0xFD4040F4, temp_tx_dig_tm_61); + Xil_Out32(0xFD40506C, temp_tm_dig_6); + Xil_Out32(0xFD405928, Xil_In32(0xFD405924)); + temp_ill12 = + temp_ill12 | (Xil_In32(0xFD405990) >> 4 & 0xF); + Xil_Out32(0xFD405990, temp_ill12); + Xil_Out32(0xFD405924, temp_TM_E_ILL1); + } + if (lane2_protocol == 2) { + temp_pll_fbdiv_frac_3_msb_offset = Xil_In32(0xFD40A360); + Xil_Out32(0xFD40A360, 0x0); + temp_PLL_REF_SEL_OFFSET = Xil_In32(0xFD410008); + psu_mask_write(0xFD410008, 0x0000001FU, 0x0000000DU); + temp_TM_IQ_ILL1 = Xil_In32(0xFD4098F8); + temp_TM_E_ILL1 = Xil_In32(0xFD409924); + Xil_Out32(0xFD4098F8, 0x78); + temp_tx_dig_tm_61 = Xil_In32(0xFD4080F4); + temp_tm_dig_6 = Xil_In32(0xFD40906C); + psu_mask_write(0xFD4080F4, 0x0000000BU, 0x00000000U); + psu_mask_write(0xFD40906C, 0x0000000FU, 0x00000000U); + temp_ill12 = Xil_In32(0xFD409990) & 0xF0; + + serdes_illcalib_pcie_gen1(2, 0, 0, 1, 0, 0, 0, 0, 0, 0); + + Xil_Out32(0xFD40A360, temp_pll_fbdiv_frac_3_msb_offset); + Xil_Out32(0xFD410008, temp_PLL_REF_SEL_OFFSET); + Xil_Out32(0xFD4098F8, temp_TM_IQ_ILL1); + Xil_Out32(0xFD4080F4, temp_tx_dig_tm_61); + Xil_Out32(0xFD40906C, temp_tm_dig_6); + Xil_Out32(0xFD409928, Xil_In32(0xFD409924)); + temp_ill12 = + temp_ill12 | (Xil_In32(0xFD409990) >> 4 & 0xF); + Xil_Out32(0xFD409990, temp_ill12); + Xil_Out32(0xFD409924, temp_TM_E_ILL1); + } + if (lane3_protocol == 2) { + temp_pll_fbdiv_frac_3_msb_offset = Xil_In32(0xFD40E360); + Xil_Out32(0xFD40E360, 0x0); + temp_PLL_REF_SEL_OFFSET = Xil_In32(0xFD41000C); + psu_mask_write(0xFD41000C, 0x0000001FU, 0x0000000DU); + temp_TM_IQ_ILL1 = Xil_In32(0xFD40D8F8); + temp_TM_E_ILL1 = Xil_In32(0xFD40D924); + Xil_Out32(0xFD40D8F8, 0x78); + temp_tx_dig_tm_61 = Xil_In32(0xFD40C0F4); + temp_tm_dig_6 = Xil_In32(0xFD40D06C); + psu_mask_write(0xFD40C0F4, 0x0000000BU, 0x00000000U); + psu_mask_write(0xFD40D06C, 0x0000000FU, 0x00000000U); + temp_ill12 = Xil_In32(0xFD40D990) & 0xF0; + + serdes_illcalib_pcie_gen1(3, 1, 0, 0, 0, 0, 0, 0, 0, 0); + + Xil_Out32(0xFD40E360, temp_pll_fbdiv_frac_3_msb_offset); + Xil_Out32(0xFD41000C, temp_PLL_REF_SEL_OFFSET); + Xil_Out32(0xFD40D8F8, temp_TM_IQ_ILL1); + Xil_Out32(0xFD40C0F4, temp_tx_dig_tm_61); + Xil_Out32(0xFD40D06C, temp_tm_dig_6); + Xil_Out32(0xFD40D928, Xil_In32(0xFD40D924)); + temp_ill12 = + temp_ill12 | (Xil_In32(0xFD40D990) >> 4 & 0xF); + Xil_Out32(0xFD40D990, temp_ill12); + Xil_Out32(0xFD40D924, temp_TM_E_ILL1); + } + rdata = Xil_In32(0xFD410098); + rdata = (rdata & 0xDF); + Xil_Out32(0xFD410098, rdata); + } + + if ((lane0_protocol == 2) && (lane0_rate == 3)) { + psu_mask_write(0xFD40198C, 0x000000F0U, 0x00000020U); + psu_mask_write(0xFD40192C, 0x000000FFU, 0x00000094U); + } + if ((lane1_protocol == 2) && (lane1_rate == 3)) { + psu_mask_write(0xFD40598C, 0x000000F0U, 0x00000020U); + psu_mask_write(0xFD40592C, 0x000000FFU, 0x00000094U); + } + if ((lane2_protocol == 2) && (lane2_rate == 3)) { + psu_mask_write(0xFD40998C, 0x000000F0U, 0x00000020U); + psu_mask_write(0xFD40992C, 0x000000FFU, 0x00000094U); + } + if ((lane3_protocol == 2) && (lane3_rate == 3)) { + psu_mask_write(0xFD40D98C, 0x000000F0U, 0x00000020U); + psu_mask_write(0xFD40D92C, 0x000000FFU, 0x00000094U); + } + + if (lane0_protocol == 1) { + if (lane0_rate == 0) { + serdes_illcalib_pcie_gen1(0, lane3_protocol, lane3_rate, + lane2_protocol, lane2_rate, + lane1_protocol, lane1_rate, + lane0_protocol, 0, 0); + } else { + serdes_illcalib_pcie_gen1(0, lane3_protocol, lane3_rate, + lane2_protocol, lane2_rate, + lane1_protocol, lane1_rate, + lane0_protocol, 0, 0); + serdes_illcalib_pcie_gen1(0, lane3_protocol, lane3_rate, + lane2_protocol, lane2_rate, + lane1_protocol, lane1_rate, + lane0_protocol, lane0_rate, + 1); + } + } + + if (lane0_protocol == 3) + Xil_Out32(0xFD401914, 0xF3); + if (lane0_protocol == 3) + Xil_Out32(0xFD401940, 0xF3); + if (lane0_protocol == 3) + Xil_Out32(0xFD401990, 0x20); + if (lane0_protocol == 3) + Xil_Out32(0xFD401924, 0x37); + + if (lane1_protocol == 3) + Xil_Out32(0xFD405914, 0xF3); + if (lane1_protocol == 3) + Xil_Out32(0xFD405940, 0xF3); + if (lane1_protocol == 3) + Xil_Out32(0xFD405990, 0x20); + if (lane1_protocol == 3) + Xil_Out32(0xFD405924, 0x37); + + if (lane2_protocol == 3) + Xil_Out32(0xFD409914, 0xF3); + if (lane2_protocol == 3) + Xil_Out32(0xFD409940, 0xF3); + if (lane2_protocol == 3) + Xil_Out32(0xFD409990, 0x20); + if (lane2_protocol == 3) + Xil_Out32(0xFD409924, 0x37); + + if (lane3_protocol == 3) + Xil_Out32(0xFD40D914, 0xF3); + if (lane3_protocol == 3) + Xil_Out32(0xFD40D940, 0xF3); + if (lane3_protocol == 3) + Xil_Out32(0xFD40D990, 0x20); + if (lane3_protocol == 3) + Xil_Out32(0xFD40D924, 0x37); + + return 1; +} + +static unsigned long psu_pll_init_data(void) +{ + psu_mask_write(0xFF5E0034, 0xFE7FEDEFU, 0x7E4B0C62U); + psu_mask_write(0xFF5E0030, 0x00717F00U, 0x00014800U); + psu_mask_write(0xFF5E0030, 0x00000008U, 0x00000008U); + psu_mask_write(0xFF5E0030, 0x00000001U, 0x00000001U); + psu_mask_write(0xFF5E0030, 0x00000001U, 0x00000000U); + mask_poll(0xFF5E0040, 0x00000002U); + psu_mask_write(0xFF5E0030, 0x00000008U, 0x00000000U); + psu_mask_write(0xFF5E0048, 0x00003F00U, 0x00000200U); + psu_mask_write(0xFF5E0038, 0x8000FFFFU, 0x00000000U); + psu_mask_write(0xFF5E0108, 0x013F3F07U, 0x01012300U); + psu_mask_write(0xFF5E0024, 0xFE7FEDEFU, 0x7E4B0C82U); + psu_mask_write(0xFF5E0020, 0x00717F00U, 0x00015A00U); + psu_mask_write(0xFF5E0020, 0x00000008U, 0x00000008U); + psu_mask_write(0xFF5E0020, 0x00000001U, 0x00000001U); + psu_mask_write(0xFF5E0020, 0x00000001U, 0x00000000U); + mask_poll(0xFF5E0040, 0x00000001U); + psu_mask_write(0xFF5E0020, 0x00000008U, 0x00000000U); + psu_mask_write(0xFF5E0044, 0x00003F00U, 0x00000300U); + psu_mask_write(0xFF5E0028, 0x8000FFFFU, 0x00000000U); + psu_mask_write(0xFD1A0024, 0xFE7FEDEFU, 0x7E4B0C62U); + psu_mask_write(0xFD1A0020, 0x00717F00U, 0x00014800U); + psu_mask_write(0xFD1A0020, 0x00000008U, 0x00000008U); + psu_mask_write(0xFD1A0020, 0x00000001U, 0x00000001U); + psu_mask_write(0xFD1A0020, 0x00000001U, 0x00000000U); + mask_poll(0xFD1A0044, 0x00000001U); + psu_mask_write(0xFD1A0020, 0x00000008U, 0x00000000U); + psu_mask_write(0xFD1A0048, 0x00003F00U, 0x00000300U); + psu_mask_write(0xFD1A0028, 0x8000FFFFU, 0x00000000U); + psu_mask_write(0xFD1A0030, 0xFE7FEDEFU, 0x7E4B0C62U); + psu_mask_write(0xFD1A002C, 0x00717F00U, 0x00015000U); + psu_mask_write(0xFD1A002C, 0x00000008U, 0x00000008U); + psu_mask_write(0xFD1A002C, 0x00000001U, 0x00000001U); + psu_mask_write(0xFD1A002C, 0x00000001U, 0x00000000U); + mask_poll(0xFD1A0044, 0x00000002U); + psu_mask_write(0xFD1A002C, 0x00000008U, 0x00000000U); + psu_mask_write(0xFD1A004C, 0x00003F00U, 0x00000300U); + psu_mask_write(0xFD1A0034, 0x8000FFFFU, 0x00000000U); + psu_mask_write(0xFD1A003C, 0xFE7FEDEFU, 0x7E4B0C62U); + psu_mask_write(0xFD1A0038, 0x00717F00U, 0x00013F00U); + psu_mask_write(0xFD1A0038, 0x00000008U, 0x00000008U); + psu_mask_write(0xFD1A0038, 0x00000001U, 0x00000001U); + psu_mask_write(0xFD1A0038, 0x00000001U, 0x00000000U); + mask_poll(0xFD1A0044, 0x00000004U); + psu_mask_write(0xFD1A0038, 0x00000008U, 0x00000000U); + psu_mask_write(0xFD1A0050, 0x00003F00U, 0x00000200U); + psu_mask_write(0xFD1A0040, 0x8000FFFFU, 0x00000000U); + + return 1; +} + +static unsigned long psu_clock_init_data(void) +{ + psu_mask_write(0xFF5E0058, 0x063F3F07U, 0x06010C00U); + psu_mask_write(0xFF5E0100, 0x013F3F07U, 0x01010600U); + psu_mask_write(0xFF5E0064, 0x023F3F07U, 0x02010600U); + psu_mask_write(0xFF5E004C, 0x023F3F07U, 0x02031900U); + psu_mask_write(0xFF5E0068, 0x013F3F07U, 0x01010500U); + psu_mask_write(0xFF5E006C, 0x013F3F07U, 0x01020302U); + psu_mask_write(0xFF18030C, 0x00000003U, 0x00000000U); + psu_mask_write(0xFF5E0078, 0x013F3F07U, 0x01010F00U); + psu_mask_write(0xFF5E0120, 0x013F3F07U, 0x01010F00U); + psu_mask_write(0xFF5E0124, 0x013F3F07U, 0x01010F00U); + psu_mask_write(0xFF5E007C, 0x013F3F07U, 0x01020302U); + psu_mask_write(0xFF5E0090, 0x01003F07U, 0x01000302U); + psu_mask_write(0xFF5E009C, 0x01003F07U, 0x01000602U); + psu_mask_write(0xFF5E00A4, 0x01003F07U, 0x01000800U); + psu_mask_write(0xFF5E00A8, 0x01003F07U, 0x01000302U); + psu_mask_write(0xFF5E00AC, 0x01003F07U, 0x01000F02U); + psu_mask_write(0xFF5E00B0, 0x01003F07U, 0x01000602U); + psu_mask_write(0xFF5E00B8, 0x01003F07U, 0x01000302U); + psu_mask_write(0xFF5E00C0, 0x013F3F07U, 0x01010802U); + psu_mask_write(0xFF5E0108, 0x013F3F07U, 0x01011E02U); + psu_mask_write(0xFF5E0104, 0x00000007U, 0x00000000U); + psu_mask_write(0xFF5E0128, 0x01003F07U, 0x01000104U); + psu_mask_write(0xFD1A00A0, 0x01003F07U, 0x01000200U); + psu_mask_write(0xFD1A0060, 0x03003F07U, 0x03000100U); + psu_mask_write(0xFD1A0068, 0x01003F07U, 0x01000200U); + psu_mask_write(0xFD1A0080, 0x00003F07U, 0x00000500U); + psu_mask_write(0xFD1A00B8, 0x01003F07U, 0x01000203U); + psu_mask_write(0xFD1A00BC, 0x01003F07U, 0x01000203U); + psu_mask_write(0xFD1A00C0, 0x01003F07U, 0x01000202U); + psu_mask_write(0xFD1A00C4, 0x01003F07U, 0x01000502U); + psu_mask_write(0xFD1A00F8, 0x00003F07U, 0x00000200U); + psu_mask_write(0xFF180380, 0x000000FFU, 0x00000000U); + psu_mask_write(0xFD610100, 0x00000001U, 0x00000000U); + psu_mask_write(0xFF180300, 0x00000001U, 0x00000000U); + psu_mask_write(0xFF410050, 0x00000001U, 0x00000000U); + + return 1; +} + +static unsigned long psu_ddr_init_data(void) +{ + psu_mask_write(0xFD1A0108, 0x00000008U, 0x00000008U); + psu_mask_write(0xFD070000, 0xE30FBE3DU, 0xC1081020U); + psu_mask_write(0xFD070010, 0x8000F03FU, 0x00000030U); + psu_mask_write(0xFD070020, 0x000003F3U, 0x00000102U); + psu_mask_write(0xFD070024, 0xFFFFFFFFU, 0x0028B0AAU); + psu_mask_write(0xFD070030, 0x0000007FU, 0x00000000U); + psu_mask_write(0xFD070034, 0x00FFFF1FU, 0x00404310U); + psu_mask_write(0xFD070050, 0x00F1F1F4U, 0x00210000U); + psu_mask_write(0xFD070054, 0x0FFF0FFFU, 0x00000000U); + psu_mask_write(0xFD070060, 0x00000073U, 0x00000001U); + psu_mask_write(0xFD070064, 0x0FFF83FFU, 0x00208030U); + psu_mask_write(0xFD070070, 0x00000017U, 0x00000010U); + psu_mask_write(0xFD070074, 0x00000003U, 0x00000000U); + psu_mask_write(0xFD0700C4, 0x3F000391U, 0x10000200U); + psu_mask_write(0xFD0700C8, 0x01FF1F3FU, 0x0030051FU); + psu_mask_write(0xFD0700D0, 0xC3FF0FFFU, 0x0002020AU); + psu_mask_write(0xFD0700D4, 0x01FF7F0FU, 0x00360000U); + psu_mask_write(0xFD0700D8, 0x0000FF0FU, 0x00001205U); + psu_mask_write(0xFD0700DC, 0xFFFFFFFFU, 0x00240052U); + psu_mask_write(0xFD0700E0, 0xFFFFFFFFU, 0x00310008U); + psu_mask_write(0xFD0700E4, 0x00FF03FFU, 0x00210004U); + psu_mask_write(0xFD0700E8, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD0700EC, 0xFFFF0000U, 0x00000000U); + psu_mask_write(0xFD0700F0, 0x0000003FU, 0x00000010U); + psu_mask_write(0xFD0700F4, 0x00000FFFU, 0x0000077FU); + psu_mask_write(0xFD070100, 0x7F3F7F3FU, 0x100B080CU); + psu_mask_write(0xFD070104, 0x001F1F7FU, 0x00030411U); + psu_mask_write(0xFD070108, 0x3F3F3F3FU, 0x0607150FU); + psu_mask_write(0xFD07010C, 0x3FF3F3FFU, 0x00A05000U); + psu_mask_write(0xFD070110, 0x1F0F0F1FU, 0x08040306U); + psu_mask_write(0xFD070114, 0x0F0F3F1FU, 0x01020404U); + psu_mask_write(0xFD070118, 0x0F0F000FU, 0x01010004U); + psu_mask_write(0xFD07011C, 0x00000F0FU, 0x00000201U); + psu_mask_write(0xFD070120, 0x7F7F7F7FU, 0x03030303U); + psu_mask_write(0xFD070124, 0x40070F3FU, 0x0004040DU); + psu_mask_write(0xFD07012C, 0x7F1F031FU, 0x440C011CU); + psu_mask_write(0xFD070130, 0x00030F1FU, 0x00020608U); + psu_mask_write(0xFD070180, 0xF7FF03FFU, 0x810B0008U); + psu_mask_write(0xFD070184, 0x3FFFFFFFU, 0x00E32DCDU); + psu_mask_write(0xFD070190, 0x1FBFBF3FU, 0x048B820AU); + psu_mask_write(0xFD070194, 0xF31F0F0FU, 0x00030304U); + psu_mask_write(0xFD070198, 0x0FF1F1F1U, 0x07000101U); + psu_mask_write(0xFD07019C, 0x000000F1U, 0x00000021U); + psu_mask_write(0xFD0701A0, 0xC3FF03FFU, 0x00400003U); + psu_mask_write(0xFD0701A4, 0x00FF00FFU, 0x00C800FFU); + psu_mask_write(0xFD0701B0, 0x00000007U, 0x00000004U); + psu_mask_write(0xFD0701B4, 0x00003F3FU, 0x00000908U); + psu_mask_write(0xFD0701C0, 0x00000007U, 0x00000001U); + psu_mask_write(0xFD070200, 0x0000001FU, 0x0000001FU); + psu_mask_write(0xFD070204, 0x001F1F1FU, 0x00070707U); + psu_mask_write(0xFD070208, 0x0F0F0F0FU, 0x00000000U); + psu_mask_write(0xFD07020C, 0x0F0F0F0FU, 0x0F000000U); + psu_mask_write(0xFD070210, 0x00000F0FU, 0x00000F0FU); + psu_mask_write(0xFD070214, 0x0F0F0F0FU, 0x060F0606U); + psu_mask_write(0xFD070218, 0x8F0F0F0FU, 0x0F060606U); + psu_mask_write(0xFD07021C, 0x00000F0FU, 0x00000F0FU); + psu_mask_write(0xFD070220, 0x00001F1FU, 0x00000000U); + psu_mask_write(0xFD070224, 0x0F0F0F0FU, 0x06060606U); + psu_mask_write(0xFD070228, 0x0F0F0F0FU, 0x06060606U); + psu_mask_write(0xFD07022C, 0x0000000FU, 0x00000006U); + psu_mask_write(0xFD070240, 0x0F1F0F7CU, 0x04000400U); + psu_mask_write(0xFD070244, 0x00003333U, 0x00000000U); + psu_mask_write(0xFD070250, 0x7FFF3F07U, 0x01002001U); + psu_mask_write(0xFD070264, 0xFF00FFFFU, 0x08000040U); + psu_mask_write(0xFD07026C, 0xFF00FFFFU, 0x08000040U); + psu_mask_write(0xFD070280, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD070284, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD070288, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD07028C, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD070290, 0x0000FFFFU, 0x00000000U); + psu_mask_write(0xFD070294, 0x00000001U, 0x00000001U); + psu_mask_write(0xFD070300, 0x00000011U, 0x00000000U); + psu_mask_write(0xFD07030C, 0x80000033U, 0x00000000U); + psu_mask_write(0xFD070320, 0x00000001U, 0x00000000U); + psu_mask_write(0xFD070400, 0x00000111U, 0x00000001U); + psu_mask_write(0xFD070404, 0x000073FFU, 0x0000200FU); + psu_mask_write(0xFD070408, 0x000073FFU, 0x0000200FU); + psu_mask_write(0xFD070490, 0x00000001U, 0x00000001U); + psu_mask_write(0xFD070494, 0x0033000FU, 0x0020000BU); + psu_mask_write(0xFD070498, 0x07FF07FFU, 0x00000000U); + psu_mask_write(0xFD0704B4, 0x000073FFU, 0x0000200FU); + psu_mask_write(0xFD0704B8, 0x000073FFU, 0x0000200FU); + psu_mask_write(0xFD070540, 0x00000001U, 0x00000001U); + psu_mask_write(0xFD070544, 0x03330F0FU, 0x02000B03U); + psu_mask_write(0xFD070548, 0x07FF07FFU, 0x00000000U); + psu_mask_write(0xFD070564, 0x000073FFU, 0x0000200FU); + psu_mask_write(0xFD070568, 0x000073FFU, 0x0000200FU); + psu_mask_write(0xFD0705F0, 0x00000001U, 0x00000001U); + psu_mask_write(0xFD0705F4, 0x03330F0FU, 0x02000B03U); + psu_mask_write(0xFD0705F8, 0x07FF07FFU, 0x00000000U); + psu_mask_write(0xFD070614, 0x000073FFU, 0x0000200FU); + psu_mask_write(0xFD070618, 0x000073FFU, 0x0000200FU); + psu_mask_write(0xFD0706A0, 0x00000001U, 0x00000001U); + psu_mask_write(0xFD0706A4, 0x0033000FU, 0x00100003U); + psu_mask_write(0xFD0706A8, 0x07FF07FFU, 0x0000004FU); + psu_mask_write(0xFD0706AC, 0x0033000FU, 0x00100003U); + psu_mask_write(0xFD0706B0, 0x000007FFU, 0x0000004FU); + psu_mask_write(0xFD0706C4, 0x000073FFU, 0x0000200FU); + psu_mask_write(0xFD0706C8, 0x000073FFU, 0x0000200FU); + psu_mask_write(0xFD070750, 0x00000001U, 0x00000001U); + psu_mask_write(0xFD070754, 0x0033000FU, 0x00100003U); + psu_mask_write(0xFD070758, 0x07FF07FFU, 0x0000004FU); + psu_mask_write(0xFD07075C, 0x0033000FU, 0x00100003U); + psu_mask_write(0xFD070760, 0x000007FFU, 0x0000004FU); + psu_mask_write(0xFD070774, 0x000073FFU, 0x0000200FU); + psu_mask_write(0xFD070778, 0x000073FFU, 0x0000200FU); + psu_mask_write(0xFD070800, 0x00000001U, 0x00000001U); + psu_mask_write(0xFD070804, 0x0033000FU, 0x00100003U); + psu_mask_write(0xFD070808, 0x07FF07FFU, 0x0000004FU); + psu_mask_write(0xFD07080C, 0x0033000FU, 0x00100003U); + psu_mask_write(0xFD070810, 0x000007FFU, 0x0000004FU); + psu_mask_write(0xFD070F04, 0x000001FFU, 0x00000000U); + psu_mask_write(0xFD070F08, 0x000000FFU, 0x00000000U); + psu_mask_write(0xFD070F0C, 0x000001FFU, 0x00000010U); + psu_mask_write(0xFD070F10, 0x000000FFU, 0x0000000FU); + psu_mask_write(0xFD072190, 0x1FBFBF3FU, 0x07828002U); + psu_mask_write(0xFD1A0108, 0x0000000CU, 0x00000000U); + psu_mask_write(0xFD080010, 0xFFFFFFFFU, 0x87001E00U); + psu_mask_write(0xFD080018, 0xFFFFFFFFU, 0x00F03D28U); + psu_mask_write(0xFD08001C, 0xFFFFFFFFU, 0x55AA5480U); + psu_mask_write(0xFD080024, 0xFFFFFFFFU, 0x010100F4U); + psu_mask_write(0xFD080040, 0xFFFFFFFFU, 0x21610AD0U); + psu_mask_write(0xFD080044, 0xFFFFFFFFU, 0x682B0960U); + psu_mask_write(0xFD080068, 0xFFFFFFFFU, 0x05102000U); + psu_mask_write(0xFD080090, 0xFFFFFFFFU, 0x02A040A1U); + psu_mask_write(0xFD0800C0, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD0800C4, 0xFFFFFFFFU, 0x000000E5U); + psu_mask_write(0xFD080100, 0xFFFFFFFFU, 0x0000040DU); + psu_mask_write(0xFD080110, 0xFFFFFFFFU, 0x06180C08U); + psu_mask_write(0xFD080114, 0xFFFFFFFFU, 0x2816070BU); + psu_mask_write(0xFD080118, 0xFFFFFFFFU, 0x000F0064U); + psu_mask_write(0xFD08011C, 0xFFFFFFFFU, 0x82000501U); + psu_mask_write(0xFD080120, 0xFFFFFFFFU, 0x00602B08U); + psu_mask_write(0xFD080124, 0xFFFFFFFFU, 0x00221008U); + psu_mask_write(0xFD080128, 0xFFFFFFFFU, 0x00000C0EU); + psu_mask_write(0xFD080140, 0xFFFFFFFFU, 0x08400020U); + psu_mask_write(0xFD080144, 0xFFFFFFFFU, 0x00000C80U); + psu_mask_write(0xFD080150, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD080154, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD080180, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD080184, 0xFFFFFFFFU, 0x00000024U); + psu_mask_write(0xFD080188, 0xFFFFFFFFU, 0x00000052U); + psu_mask_write(0xFD08018C, 0xFFFFFFFFU, 0x00000031U); + psu_mask_write(0xFD080190, 0xFFFFFFFFU, 0x00000008U); + psu_mask_write(0xFD080194, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD080198, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD0801AC, 0xFFFFFFFFU, 0x00000056U); + psu_mask_write(0xFD0801B0, 0xFFFFFFFFU, 0x00000056U); + psu_mask_write(0xFD0801B4, 0xFFFFFFFFU, 0x00000008U); + psu_mask_write(0xFD0801B8, 0xFFFFFFFFU, 0x00000019U); + psu_mask_write(0xFD0801D8, 0xFFFFFFFFU, 0x00000016U); + psu_mask_write(0xFD080200, 0xFFFFFFFFU, 0x800091C7U); + psu_mask_write(0xFD080204, 0xFFFFFFFFU, 0x00010236U); + psu_mask_write(0xFD080240, 0xFFFFFFFFU, 0x00141054U); + psu_mask_write(0xFD080250, 0xFFFFFFFFU, 0x00088000U); + psu_mask_write(0xFD080414, 0xFFFFFFFFU, 0x12340400U); + psu_mask_write(0xFD0804F4, 0xFFFFFFFFU, 0x0000000AU); + psu_mask_write(0xFD080500, 0xFFFFFFFFU, 0x30000028U); + psu_mask_write(0xFD080508, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD08050C, 0xFFFFFFFFU, 0x00000005U); + psu_mask_write(0xFD080510, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD080520, 0xFFFFFFFFU, 0x0300BD99U); + psu_mask_write(0xFD080528, 0xFFFFFFFFU, 0xF1032019U); + psu_mask_write(0xFD08052C, 0xFFFFFFFFU, 0x07F001E3U); + psu_mask_write(0xFD080544, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD080548, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD080558, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD08055C, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD080560, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD080564, 0xFFFFFFFFU, 0x00000000U); + psu_mask_write(0xFD080680, 0xFFFFFFFFU, 0x00894C58U); + psu_mask_write(0xFD080684, 0xFFFFFFFFU, 0x0001B39BU); + psu_mask_write(0xFD080694, 0xFFFFFFFFU, 0x01E10210U); + psu_mask_write(0xFD080698, 0xFFFFFFFFU, 0x01E10000U); + psu_mask_write(0xFD0806A4, 0xFFFFFFFFU, 0x0001BB9BU); + psu_mask_write(0xFD080700, 0xFFFFFFFFU, 0x40800604U); + psu_mask_write(0xFD080704, 0xFFFFFFFFU, 0x00007FFFU); + psu_mask_write(0xFD08070C, 0xFFFFFFFFU, 0x3F000008U); + psu_mask_write(0xFD080710, 0xFFFFFFFFU, 0x0E00F50CU); + psu_mask_write(0xFD080714, 0xFFFFFFFFU, 0x09091616U); + psu_mask_write(0xFD080718, 0xFFFFFFFFU, 0x09092B2BU); + psu_mask_write(0xFD080800, 0xFFFFFFFFU, 0x40800604U); + psu_mask_write(0xFD080804, 0xFFFFFFFFU, 0x00007FFFU); + psu_mask_write(0xFD08080C, 0xFFFFFFFFU, 0x3F000008U); + psu_mask_write(0xFD080810, 0xFFFFFFFFU, 0x0E00F50CU); + psu_mask_write(0xFD080814, 0xFFFFFFFFU, 0x09091616U); + psu_mask_write(0xFD080818, 0xFFFFFFFFU, 0x09092B2BU); + psu_mask_write(0xFD080900, 0xFFFFFFFFU, 0x40800604U); + psu_mask_write(0xFD080904, 0xFFFFFFFFU, 0x00007FFFU); + psu_mask_write(0xFD08090C, 0xFFFFFFFFU, 0x3F000008U); + psu_mask_write(0xFD080910, 0xFFFFFFFFU, 0x0E00F504U); + psu_mask_write(0xFD080914, 0xFFFFFFFFU, 0x09091616U); + psu_mask_write(0xFD080918, 0xFFFFFFFFU, 0x09092B2BU); + psu_mask_write(0xFD080A00, 0xFFFFFFFFU, 0x40800604U); + psu_mask_write(0xFD080A04, 0xFFFFFFFFU, 0x00007FFFU); + psu_mask_write(0xFD080A0C, 0xFFFFFFFFU, 0x3F000008U); + psu_mask_write(0xFD080A10, 0xFFFFFFFFU, 0x0E00F504U); + psu_mask_write(0xFD080A14, 0xFFFFFFFFU, 0x09091616U); + psu_mask_write(0xFD080A18, 0xFFFFFFFFU, 0x09092B2BU); + psu_mask_write(0xFD080B00, 0xFFFFFFFFU, 0x80803660U); + psu_mask_write(0xFD080B04, 0xFFFFFFFFU, 0x55556000U); + psu_mask_write(0xFD080B08, 0xFFFFFFFFU, 0xAAAAAAAAU); + psu_mask_write(0xFD080B0C, 0xFFFFFFFFU, 0x0029A4A4U); + psu_mask_write(0xFD080B10, 0xFFFFFFFFU, 0x0C00BD00U); + psu_mask_write(0xFD080B14, 0xFFFFFFFFU, 0x09091616U); + psu_mask_write(0xFD080B18, 0xFFFFFFFFU, 0x09092B2BU); + psu_mask_write(0xFD080C00, 0xFFFFFFFFU, 0x80803660U); + psu_mask_write(0xFD080C04, 0xFFFFFFFFU, 0x55556000U); + psu_mask_write(0xFD080C08, 0xFFFFFFFFU, 0xAAAAAAAAU); + psu_mask_write(0xFD080C0C, 0xFFFFFFFFU, 0x0029A4A4U); + psu_mask_write(0xFD080C10, 0xFFFFFFFFU, 0x0C00BD00U); + psu_mask_write(0xFD080C14, 0xFFFFFFFFU, 0x09091616U); + psu_mask_write(0xFD080C18, 0xFFFFFFFFU, 0x09092B2BU); + psu_mask_write(0xFD080D00, 0xFFFFFFFFU, 0x80803660U); + psu_mask_write(0xFD080D04, 0xFFFFFFFFU, 0x55556000U); + psu_mask_write(0xFD080D08, 0xFFFFFFFFU, 0xAAAAAAAAU); + psu_mask_write(0xFD080D0C, 0xFFFFFFFFU, 0x0029A4A4U); + psu_mask_write(0xFD080D10, 0xFFFFFFFFU, 0x0C00BD00U); + psu_mask_write(0xFD080D14, 0xFFFFFFFFU, 0x09091616U); + psu_mask_write(0xFD080D18, 0xFFFFFFFFU, 0x09092B2BU); + psu_mask_write(0xFD080E00, 0xFFFFFFFFU, 0x80803660U); + psu_mask_write(0xFD080E04, 0xFFFFFFFFU, 0x55556000U); + psu_mask_write(0xFD080E08, 0xFFFFFFFFU, 0xAAAAAAAAU); + psu_mask_write(0xFD080E0C, 0xFFFFFFFFU, 0x0029A4A4U); + psu_mask_write(0xFD080E10, 0xFFFFFFFFU, 0x0C00BD00U); + psu_mask_write(0xFD080E14, 0xFFFFFFFFU, 0x09091616U); + psu_mask_write(0xFD080E18, 0xFFFFFFFFU, 0x09092B2BU); + psu_mask_write(0xFD080F00, 0xFFFFFFFFU, 0x80803660U); + psu_mask_write(0xFD080F04, 0xFFFFFFFFU, 0x55556000U); + psu_mask_write(0xFD080F08, 0xFFFFFFFFU, 0xAAAAAAAAU); + psu_mask_write(0xFD080F0C, 0xFFFFFFFFU, 0x0029A4A4U); + psu_mask_write(0xFD080F10, 0xFFFFFFFFU, 0x0C00BD00U); + psu_mask_write(0xFD080F14, 0xFFFFFFFFU, 0x09091616U); + psu_mask_write(0xFD080F18, 0xFFFFFFFFU, 0x09092B2BU); + psu_mask_write(0xFD081400, 0xFFFFFFFFU, 0x2A019FFEU); + psu_mask_write(0xFD081404, 0xFFFFFFFFU, 0x05102000U); + psu_mask_write(0xFD08141C, 0xFFFFFFFFU, 0x01264300U); + psu_mask_write(0xFD08142C, 0xFFFFFFFFU, 0x000C1800U); + psu_mask_write(0xFD081430, 0xFFFFFFFFU, 0x71000000U); + psu_mask_write(0xFD081440, 0xFFFFFFFFU, 0x2A019FFEU); + psu_mask_write(0xFD081444, 0xFFFFFFFFU, 0x05102000U); + psu_mask_write(0xFD08145C, 0xFFFFFFFFU, 0x01264300U); + psu_mask_write(0xFD08146C, 0xFFFFFFFFU, 0x000C1800U); + psu_mask_write(0xFD081470, 0xFFFFFFFFU, 0x71000000U); + psu_mask_write(0xFD081480, 0xFFFFFFFFU, 0x15019FFEU); + psu_mask_write(0xFD081484, 0xFFFFFFFFU, 0x25102000U); + psu_mask_write(0xFD08149C, 0xFFFFFFFFU, 0x01266300U); + psu_mask_write(0xFD0814AC, 0xFFFFFFFFU, 0x000C1800U); + psu_mask_write(0xFD0814B0, 0xFFFFFFFFU, 0x70400000U); + psu_mask_write(0xFD0814C0, 0xFFFFFFFFU, 0x15019FFEU); + psu_mask_write(0xFD0814C4, 0xFFFFFFFFU, 0x25102000U); + psu_mask_write(0xFD0814DC, 0xFFFFFFFFU, 0x01266300U); + psu_mask_write(0xFD0814EC, 0xFFFFFFFFU, 0x000C1800U); + psu_mask_write(0xFD0814F0, 0xFFFFFFFFU, 0x70400000U); + psu_mask_write(0xFD081500, 0xFFFFFFFFU, 0x15019FFEU); + psu_mask_write(0xFD081504, 0xFFFFFFFFU, 0x25102000U); + psu_mask_write(0xFD08151C, 0xFFFFFFFFU, 0x01266300U); + psu_mask_write(0xFD08152C, 0xFFFFFFFFU, 0x000C1800U); + psu_mask_write(0xFD081530, 0xFFFFFFFFU, 0x70400000U); + psu_mask_write(0xFD0817DC, 0xFFFFFFFFU, 0x012643C4U); + + return 1; +} + +static unsigned long psu_ddr_qos_init_data(void) +{ + psu_mask_write(0xFD360008, 0x0000000FU, 0x00000000U); + psu_mask_write(0xFD36001C, 0x0000000FU, 0x00000000U); + psu_mask_write(0xFD370008, 0x0000000FU, 0x00000000U); + psu_mask_write(0xFD37001C, 0x0000000FU, 0x00000000U); + psu_mask_write(0xFD380008, 0x0000000FU, 0x00000000U); + psu_mask_write(0xFD38001C, 0x0000000FU, 0x00000000U); + psu_mask_write(0xFD390008, 0x0000000FU, 0x00000000U); + psu_mask_write(0xFD39001C, 0x0000000FU, 0x00000000U); + psu_mask_write(0xFD3A0008, 0x0000000FU, 0x00000000U); + psu_mask_write(0xFD3A001C, 0x0000000FU, 0x00000000U); + psu_mask_write(0xFD3B0008, 0x0000000FU, 0x00000000U); + psu_mask_write(0xFD3B001C, 0x0000000FU, 0x00000000U); + psu_mask_write(0xFF9B0008, 0x0000000FU, 0x00000000U); + psu_mask_write(0xFF9B001C, 0x0000000FU, 0x00000000U); + + return 1; +} + +static unsigned long psu_mio_init_data(void) +{ + psu_mask_write(0xFF180000, 0x000000FEU, 0x00000002U); + psu_mask_write(0xFF180004, 0x000000FEU, 0x00000002U); + psu_mask_write(0xFF180008, 0x000000FEU, 0x00000002U); + psu_mask_write(0xFF18000C, 0x000000FEU, 0x00000002U); + psu_mask_write(0xFF180010, 0x000000FEU, 0x00000002U); + psu_mask_write(0xFF180014, 0x000000FEU, 0x00000002U); + psu_mask_write(0xFF180018, 0x000000FEU, 0x00000002U); + psu_mask_write(0xFF18001C, 0x000000FEU, 0x00000000U); + psu_mask_write(0xFF180020, 0x000000FEU, 0x00000000U); + psu_mask_write(0xFF180024, 0x000000FEU, 0x00000000U); + psu_mask_write(0xFF180028, 0x000000FEU, 0x00000000U); + psu_mask_write(0xFF18002C, 0x000000FEU, 0x00000000U); + psu_mask_write(0xFF180030, 0x000000FEU, 0x00000000U); + psu_mask_write(0xFF180034, 0x000000FEU, 0x00000008U); + psu_mask_write(0xFF180038, 0x000000FEU, 0x00000008U); + psu_mask_write(0xFF18003C, 0x000000FEU, 0x00000008U); + psu_mask_write(0xFF180040, 0x000000FEU, 0x00000008U); + psu_mask_write(0xFF180044, 0x000000FEU, 0x00000008U); + psu_mask_write(0xFF180048, 0x000000FEU, 0x00000008U); + psu_mask_write(0xFF18004C, 0x000000FEU, 0x00000008U); + psu_mask_write(0xFF180050, 0x000000FEU, 0x00000008U); + psu_mask_write(0xFF180054, 0x000000FEU, 0x00000008U); + psu_mask_write(0xFF180058, 0x000000FEU, 0x00000008U); + psu_mask_write(0xFF18005C, 0x000000FEU, 0x00000008U); + psu_mask_write(0xFF180060, 0x000000FEU, 0x00000008U); + psu_mask_write(0xFF180064, 0x000000FEU, 0x00000008U); + psu_mask_write(0xFF180068, 0x000000FEU, 0x00000000U); + psu_mask_write(0xFF18006C, 0x000000FEU, 0x00000000U); + psu_mask_write(0xFF180070, 0x000000FEU, 0x00000000U); + psu_mask_write(0xFF180074, 0x000000FEU, 0x00000000U); + psu_mask_write(0xFF180078, 0x000000FEU, 0x00000000U); + psu_mask_write(0xFF18007C, 0x000000FEU, 0x00000000U); + psu_mask_write(0xFF180080, 0x000000FEU, 0x00000040U); + psu_mask_write(0xFF180084, 0x000000FEU, 0x00000040U); + psu_mask_write(0xFF180088, 0x000000FEU, 0x00000040U); + psu_mask_write(0xFF18008C, 0x000000FEU, 0x00000040U); + psu_mask_write(0xFF180090, 0x000000FEU, 0x000000C0U); + psu_mask_write(0xFF180094, 0x000000FEU, 0x000000C0U); + psu_mask_write(0xFF180098, 0x000000FEU, 0x00000080U); + psu_mask_write(0xFF18009C, 0x000000FEU, 0x00000000U); + psu_mask_write(0xFF1800A0, 0x000000FEU, 0x00000080U); + psu_mask_write(0xFF1800A4, 0x000000FEU, 0x00000080U); + psu_mask_write(0xFF1800A8, 0x000000FEU, 0x00000080U); + psu_mask_write(0xFF1800AC, 0x000000FEU, 0x00000080U); + psu_mask_write(0xFF1800B0, 0x000000FEU, 0x00000000U); + psu_mask_write(0xFF1800B4, 0x000000FEU, 0x00000000U); + psu_mask_write(0xFF1800B8, 0x000000FEU, 0x00000000U); + psu_mask_write(0xFF1800BC, 0x000000FEU, 0x00000000U); + psu_mask_write(0xFF1800C0, 0x000000FEU, 0x00000000U); + psu_mask_write(0xFF1800C4, 0x000000FEU, 0x00000000U); + psu_mask_write(0xFF1800C8, 0x000000FEU, 0x00000000U); + psu_mask_write(0xFF1800CC, 0x000000FEU, 0x00000000U); + psu_mask_write(0xFF1800D0, 0x000000FEU, 0x00000002U); + psu_mask_write(0xFF1800D4, 0x000000FEU, 0x00000002U); + psu_mask_write(0xFF1800D8, 0x000000FEU, 0x00000002U); + psu_mask_write(0xFF1800DC, 0x000000FEU, 0x00000002U); + psu_mask_write(0xFF1800E0, 0x000000FEU, 0x00000002U); + psu_mask_write(0xFF1800E4, 0x000000FEU, 0x00000002U); + psu_mask_write(0xFF1800E8, 0x000000FEU, 0x00000002U); + psu_mask_write(0xFF1800EC, 0x000000FEU, 0x00000002U); + psu_mask_write(0xFF1800F0, 0x000000FEU, 0x00000002U); + psu_mask_write(0xFF1800F4, 0x000000FEU, 0x00000002U); + psu_mask_write(0xFF1800F8, 0x000000FEU, 0x00000002U); + psu_mask_write(0xFF1800FC, 0x000000FEU, 0x00000002U); + psu_mask_write(0xFF180100, 0x000000FEU, 0x00000004U); + psu_mask_write(0xFF180104, 0x000000FEU, 0x00000004U); + psu_mask_write(0xFF180108, 0x000000FEU, 0x00000004U); + psu_mask_write(0xFF18010C, 0x000000FEU, 0x00000004U); + psu_mask_write(0xFF180110, 0x000000FEU, 0x00000004U); + psu_mask_write(0xFF180114, 0x000000FEU, 0x00000004U); + psu_mask_write(0xFF180118, 0x000000FEU, 0x00000004U); + psu_mask_write(0xFF18011C, 0x000000FEU, 0x00000004U); + psu_mask_write(0xFF180120, 0x000000FEU, 0x00000004U); + psu_mask_write(0xFF180124, 0x000000FEU, 0x00000004U); + psu_mask_write(0xFF180128, 0x000000FEU, 0x00000004U); + psu_mask_write(0xFF18012C, 0x000000FEU, 0x00000004U); + psu_mask_write(0xFF180130, 0x000000FEU, 0x000000A0U); + psu_mask_write(0xFF180134, 0x000000FEU, 0x000000A0U); + psu_mask_write(0xFF180204, 0xFFFFFFFFU, 0x03000000U); + psu_mask_write(0xFF180208, 0xFFFFFFFFU, 0xFC000020U); + psu_mask_write(0xFF18020C, 0x00003FFFU, 0x0000000BU); + psu_mask_write(0xFF180138, 0x03FFFFFFU, 0x03FFFFFFU); + psu_mask_write(0xFF18013C, 0x03FFFFFFU, 0x03FFFFFFU); + psu_mask_write(0xFF180140, 0x03FFFFFFU, 0x00000000U); + psu_mask_write(0xFF180144, 0x03FFFFFFU, 0x03FFFFFFU); + psu_mask_write(0xFF180148, 0x03FFFFFFU, 0x03FFFFFFU); + psu_mask_write(0xFF18014C, 0x03FFFFFFU, 0x00000000U); + psu_mask_write(0xFF180154, 0x03FFFFFFU, 0x03FFFFFFU); + psu_mask_write(0xFF180158, 0x03FFFFFFU, 0x03FFFFFFU); + psu_mask_write(0xFF18015C, 0x03FFFFFFU, 0x00000000U); + psu_mask_write(0xFF180160, 0x03FFFFFFU, 0x03FFFFFFU); + psu_mask_write(0xFF180164, 0x03FFFFFFU, 0x03FFFFFFU); + psu_mask_write(0xFF180168, 0x03FFFFFFU, 0x00000000U); + psu_mask_write(0xFF180170, 0x03FFFFFFU, 0x03FFFFFFU); + psu_mask_write(0xFF180174, 0x03FFFFFFU, 0x03FFFFFFU); + psu_mask_write(0xFF180178, 0x03FFFFFFU, 0x00000000U); + psu_mask_write(0xFF18017C, 0x03FFFFFFU, 0x03FFFFFFU); + psu_mask_write(0xFF180180, 0x03FFFFFFU, 0x03FFFFFFU); + psu_mask_write(0xFF180184, 0x03FFFFFFU, 0x00000000U); + psu_mask_write(0xFF180200, 0x0000000FU, 0x00000000U); + + return 1; +} + +static unsigned long psu_peripherals_pre_init_data(void) +{ + psu_mask_write(0xFF5E0108, 0x013F3F07U, 0x01012302U); + psu_mask_write(0xFF5E0238, 0x00000001U, 0x00000001U); + + return 1; +} + +static unsigned long psu_peripherals_init_data(void) +{ + psu_mask_write(0xFD1A0100, 0x00000046U, 0x00000000U); + psu_mask_write(0xFF5E0238, 0x001A0000U, 0x00000000U); + psu_mask_write(0xFF5E023C, 0x0093C018U, 0x00000000U); + psu_mask_write(0xFF5E0230, 0x00000004U, 0x00000000U); + psu_mask_write(0xFF5E0238, 0x00000001U, 0x00000000U); + psu_mask_write(0xFF180390, 0x00000004U, 0x00000000U); + psu_mask_write(0xFF5E023C, 0x00000800U, 0x00000000U); + psu_mask_write(0xFF5E0238, 0x00000020U, 0x00000000U); + psu_mask_write(0xFF180310, 0x00000001U, 0x00000000U); + psu_mask_write(0xFF180320, 0x00003384U, 0x00000284U); + psu_mask_write(0xFF18031C, 0x00007FFEU, 0x00006450U); + psu_mask_write(0xFF180358, 0x00080000U, 0x00080000U); + psu_mask_write(0xFF180324, 0x000003C0U, 0x00000000U); + psu_mask_write(0xFF5E0238, 0x00000600U, 0x00000000U); + psu_mask_write(0xFF5E0238, 0x00000008U, 0x00000000U); + psu_mask_write(0xFF5E0238, 0x00000004U, 0x00000000U); + psu_mask_write(0xFF5E0238, 0x00040000U, 0x00000000U); + psu_mask_write(0xFF4B0024, 0x000000FFU, 0x000000FFU); + psu_mask_write(0xFFCA5000, 0x00001FFFU, 0x00000000U); + psu_mask_write(0xFD5C0060, 0x000F000FU, 0x00000000U); + psu_mask_write(0xFFA60040, 0x80000000U, 0x80000000U); + psu_mask_write(0xFF260020, 0xFFFFFFFFU, 0x01FCA054U); + psu_mask_write(0xFF260000, 0x00000001U, 0x00000001U); + psu_mask_write(0xFF5E0250, 0x00000F0FU, 0x00000202U); + + mask_delay(1); + psu_mask_write(0xFF5E0250, 0x00000F0FU, 0x00000002U); + + mask_delay(5); + psu_mask_write(0xFF5E0250, 0x00000F0FU, 0x00000202U); + + return 1; +} + +static unsigned long psu_serdes_init_data(void) +{ + psu_mask_write(0xFD410008, 0x0000001FU, 0x0000000FU); + psu_mask_write(0xFD41000C, 0x0000001FU, 0x00000008U); + psu_mask_write(0xFD402868, 0x00000080U, 0x00000080U); + psu_mask_write(0xFD40286C, 0x00000080U, 0x00000080U); + psu_mask_write(0xFD40E094, 0x00000010U, 0x00000010U); + psu_mask_write(0xFD40A368, 0x000000FFU, 0x000000E0U); + psu_mask_write(0xFD40A36C, 0x00000007U, 0x00000003U); + psu_mask_write(0xFD40E368, 0x000000FFU, 0x00000038U); + psu_mask_write(0xFD40E36C, 0x00000007U, 0x00000003U); + psu_mask_write(0xFD40A370, 0x000000FFU, 0x000000C9U); + psu_mask_write(0xFD40A374, 0x000000FFU, 0x000000D2U); + psu_mask_write(0xFD40A378, 0x000000FFU, 0x00000001U); + psu_mask_write(0xFD40A37C, 0x000000B3U, 0x000000B0U); + psu_mask_write(0xFD40E370, 0x000000FFU, 0x000000F4U); + psu_mask_write(0xFD40E374, 0x000000FFU, 0x00000031U); + psu_mask_write(0xFD40E378, 0x000000FFU, 0x00000002U); + psu_mask_write(0xFD40E37C, 0x00000033U, 0x00000030U); + psu_mask_write(0xFD40A360, 0x00000040U, 0x00000040U); + psu_mask_write(0xFD40906C, 0x0000000FU, 0x0000000FU); + psu_mask_write(0xFD4080F4, 0x0000000BU, 0x0000000BU); + psu_mask_write(0xFD40D06C, 0x00000003U, 0x00000003U); + psu_mask_write(0xFD40C0F4, 0x00000003U, 0x00000003U); + psu_mask_write(0xFD40D0CC, 0x00000020U, 0x00000020U); + psu_mask_write(0xFD401074, 0x00000010U, 0x00000010U); + psu_mask_write(0xFD405074, 0x00000010U, 0x00000010U); + psu_mask_write(0xFD409074, 0x00000010U, 0x00000010U); + psu_mask_write(0xFD40D074, 0x00000010U, 0x00000010U); + psu_mask_write(0xFD401994, 0x00000007U, 0x00000007U); + psu_mask_write(0xFD405994, 0x00000007U, 0x00000007U); + psu_mask_write(0xFD40989C, 0x00000080U, 0x00000080U); + psu_mask_write(0xFD4098F8, 0x000000FFU, 0x0000007DU); + psu_mask_write(0xFD4098FC, 0x000000FFU, 0x0000007DU); + psu_mask_write(0xFD409990, 0x000000FFU, 0x00000001U); + psu_mask_write(0xFD409924, 0x000000FFU, 0x0000009CU); + psu_mask_write(0xFD409928, 0x000000FFU, 0x00000039U); + psu_mask_write(0xFD40998C, 0x000000F0U, 0x00000020U); + psu_mask_write(0xFD409900, 0x000000FFU, 0x0000007DU); + psu_mask_write(0xFD40992C, 0x000000FFU, 0x00000064U); + psu_mask_write(0xFD409980, 0x000000FFU, 0x000000FFU); + psu_mask_write(0xFD409914, 0x000000FFU, 0x000000F7U); + psu_mask_write(0xFD409918, 0x00000001U, 0x00000001U); + psu_mask_write(0xFD409940, 0x000000FFU, 0x000000F7U); + psu_mask_write(0xFD409944, 0x00000001U, 0x00000001U); + psu_mask_write(0xFD409994, 0x00000007U, 0x00000007U); + psu_mask_write(0xFD40D89C, 0x00000080U, 0x00000080U); + psu_mask_write(0xFD40D8F8, 0x000000FFU, 0x0000001AU); + psu_mask_write(0xFD40D8FC, 0x000000FFU, 0x0000001AU); + psu_mask_write(0xFD40D990, 0x000000FFU, 0x00000010U); + psu_mask_write(0xFD40D924, 0x000000FFU, 0x000000FEU); + psu_mask_write(0xFD40D928, 0x000000FFU, 0x00000000U); + psu_mask_write(0xFD40D900, 0x000000FFU, 0x0000001AU); + psu_mask_write(0xFD40D92C, 0x000000FFU, 0x00000000U); + psu_mask_write(0xFD40D980, 0x000000FFU, 0x000000FFU); + psu_mask_write(0xFD40D914, 0x000000FFU, 0x000000F7U); + psu_mask_write(0xFD40D918, 0x00000001U, 0x00000001U); + psu_mask_write(0xFD40D940, 0x000000FFU, 0x000000F7U); + psu_mask_write(0xFD40D944, 0x00000001U, 0x00000001U); + psu_mask_write(0xFD40D994, 0x00000007U, 0x00000007U); + psu_mask_write(0xFD40107C, 0x0000000FU, 0x00000001U); + psu_mask_write(0xFD40507C, 0x0000000FU, 0x00000001U); + psu_mask_write(0xFD40907C, 0x0000000FU, 0x00000001U); + psu_mask_write(0xFD40D07C, 0x0000000FU, 0x00000001U); + psu_mask_write(0xFD4019A4, 0x000000FFU, 0x000000FFU); + psu_mask_write(0xFD401038, 0x00000040U, 0x00000040U); + psu_mask_write(0xFD40102C, 0x00000040U, 0x00000040U); + psu_mask_write(0xFD4059A4, 0x000000FFU, 0x000000FFU); + psu_mask_write(0xFD405038, 0x00000040U, 0x00000040U); + psu_mask_write(0xFD40502C, 0x00000040U, 0x00000040U); + psu_mask_write(0xFD4099A4, 0x000000FFU, 0x000000FFU); + psu_mask_write(0xFD409038, 0x00000040U, 0x00000040U); + psu_mask_write(0xFD40902C, 0x00000040U, 0x00000040U); + psu_mask_write(0xFD40D9A4, 0x000000FFU, 0x000000FFU); + psu_mask_write(0xFD40D038, 0x00000040U, 0x00000040U); + psu_mask_write(0xFD40D02C, 0x00000040U, 0x00000040U); + psu_mask_write(0xFD4019AC, 0x00000003U, 0x00000000U); + psu_mask_write(0xFD4059AC, 0x00000003U, 0x00000000U); + psu_mask_write(0xFD4099AC, 0x00000003U, 0x00000000U); + psu_mask_write(0xFD40D9AC, 0x00000003U, 0x00000000U); + psu_mask_write(0xFD401978, 0x00000010U, 0x00000010U); + psu_mask_write(0xFD405978, 0x00000010U, 0x00000010U); + psu_mask_write(0xFD409978, 0x00000010U, 0x00000010U); + psu_mask_write(0xFD40D978, 0x00000010U, 0x00000010U); + + serdes_illcalib(3, 0, 2, 3, 0, 0, 0, 0); + psu_mask_write(0xFD410014, 0x00000077U, 0x00000032U); + psu_mask_write(0xFD4081D8, 0x00000001U, 0x00000001U); + psu_mask_write(0xFD409C14, 0x000000FFU, 0x000000E6U); + psu_mask_write(0xFD409C40, 0x0000001FU, 0x0000000CU); + psu_mask_write(0xFD40994C, 0x00000020U, 0x00000020U); + psu_mask_write(0xFD409950, 0x00000007U, 0x00000006U); + psu_mask_write(0xFD408048, 0x000000FFU, 0x00000001U); + + return 1; +} + +static unsigned long psu_resetout_init_data(void) +{ + psu_mask_write(0xFF5E023C, 0x00000800U, 0x00000000U); + psu_mask_write(0xFF9E0080, 0x00000001U, 0x00000001U); + psu_mask_write(0xFF9E007C, 0x00000001U, 0x00000000U); + psu_mask_write(0xFF5E023C, 0x00000280U, 0x00000000U); + psu_mask_write(0xFF5E0230, 0x00000004U, 0x00000000U); + psu_mask_write(0xFD3D0100, 0x00000003U, 0x00000002U); + psu_mask_write(0xFD1A0100, 0x00000002U, 0x00000000U); + psu_mask_write(0xFE30C200, 0x00023FFFU, 0x00022457U); + psu_mask_write(0xFE30C630, 0x003FFF00U, 0x00000000U); + psu_mask_write(0xFE30C12C, 0x00004000U, 0x00004000U); + psu_mask_write(0xFE30C11C, 0x00000600U, 0x00000600U); + psu_mask_write(0xFD480064, 0x00000200U, 0x00000200U); + mask_poll(0xFD40A3E4, 0x00000010U); + mask_poll(0xFD40E3E4, 0x00000010U); + psu_mask_write(0xFD0C00AC, 0xFFFFFFFFU, 0x28184018U); + psu_mask_write(0xFD0C00B0, 0xFFFFFFFFU, 0x0E081406U); + psu_mask_write(0xFD0C00B4, 0xFFFFFFFFU, 0x064A0813U); + psu_mask_write(0xFD0C00B8, 0xFFFFFFFFU, 0x3FFC96A4U); + + return 1; +} + +static unsigned long psu_resetin_init_data(void) +{ + psu_mask_write(0xFF5E023C, 0x00000A80U, 0x00000A80U); + psu_mask_write(0xFF5E0230, 0x00000004U, 0x00000004U); + psu_mask_write(0xFD1A0100, 0x00000002U, 0x00000002U); + + return 1; +} + +static unsigned long psu_afi_config(void) +{ + psu_mask_write(0xFD1A0100, 0x00001F80U, 0x00000000U); + psu_mask_write(0xFF5E023C, 0x00080000U, 0x00000000U); + psu_mask_write(0xFD615000, 0x00000300U, 0x00000100U); + psu_mask_write(0xFD360000, 0x00000003U, 0x00000001U); + psu_mask_write(0xFD360014, 0x00000003U, 0x00000001U); + + return 1; +} + +static unsigned long psu_ddr_phybringup_data(void) +{ + unsigned int regval = 0; + unsigned int pll_retry = 10; + unsigned int pll_locked = 0; + + while ((pll_retry > 0) && (!pll_locked)) { + Xil_Out32(0xFD080004, 0x00040010); + Xil_Out32(0xFD080004, 0x00040011); + + while ((Xil_In32(0xFD080030) & 0x1) != 1) + ; + pll_locked = (Xil_In32(0xFD080030) & 0x80000000) + >> 31; + pll_locked &= (Xil_In32(0xFD0807E0) & 0x10000) + >> 16; + pll_locked &= (Xil_In32(0xFD0809E0) & 0x10000) >> 16; + pll_retry--; + } + Xil_Out32(0xFD0800C4, Xil_In32(0xFD0800C4) | (pll_retry << 16)); + if (!pll_locked) + return 0; + + Xil_Out32(0xFD080004U, 0x00040063U); + Xil_Out32(0xFD0800C0U, 0x00000001U); + + while ((Xil_In32(0xFD080030U) & 0x0000000FU) != 0x0000000FU) + ; + prog_reg(0xFD080004U, 0x00000001U, 0x00000000U, 0x00000001U); + + while ((Xil_In32(0xFD080030U) & 0x000000FFU) != 0x0000001FU) + ; + Xil_Out32(0xFD070010U, 0x80000018U); + Xil_Out32(0xFD0701B0U, 0x00000005U); + regval = Xil_In32(0xFD070018); + while ((regval & 0x1) != 0x0) + regval = Xil_In32(0xFD070018); + + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + Xil_Out32(0xFD070014U, 0x00000331U); + Xil_Out32(0xFD070010U, 0x80000018U); + regval = Xil_In32(0xFD070018); + while ((regval & 0x1) != 0x0) + regval = Xil_In32(0xFD070018); + + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + Xil_Out32(0xFD070014U, 0x00000B36U); + Xil_Out32(0xFD070010U, 0x80000018U); + regval = Xil_In32(0xFD070018); + while ((regval & 0x1) != 0x0) + regval = Xil_In32(0xFD070018); + + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + Xil_Out32(0xFD070014U, 0x00000C56U); + Xil_Out32(0xFD070010U, 0x80000018U); + regval = Xil_In32(0xFD070018); + while ((regval & 0x1) != 0x0) + regval = Xil_In32(0xFD070018); + + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + Xil_Out32(0xFD070014U, 0x00000E19U); + Xil_Out32(0xFD070010U, 0x80000018U); + regval = Xil_In32(0xFD070018); + while ((regval & 0x1) != 0x0) + regval = Xil_In32(0xFD070018); + + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + regval = Xil_In32(0xFD070018); + Xil_Out32(0xFD070014U, 0x00001616U); + Xil_Out32(0xFD070010U, 0x80000018U); + Xil_Out32(0xFD070010U, 0x80000010U); + Xil_Out32(0xFD0701B0U, 0x00000005U); + Xil_Out32(0xFD070320U, 0x00000001U); + while ((Xil_In32(0xFD070004U) & 0x0000000FU) != 0x00000001U) + ; + prog_reg(0xFD080014U, 0x00000040U, 0x00000006U, 0x00000001U); + Xil_Out32(0xFD080004, 0x0014FE01); + + regval = Xil_In32(0xFD080030); + while (regval != 0x8000007E) + regval = Xil_In32(0xFD080030); + + Xil_Out32(0xFD080200U, 0x000091C7U); + regval = Xil_In32(0xFD080030); + while (regval != 0x80008FFF) + regval = Xil_In32(0xFD080030); + + Xil_Out32(0xFD080200U, 0x800091C7U); + regval = ((Xil_In32(0xFD080030) & 0x1FFF0000) >> 18); + if (regval != 0) + return 0; + + Xil_Out32(0xFD080200U, 0x800091C7U); + int cur_R006_tREFPRD; + + cur_R006_tREFPRD = (Xil_In32(0xFD080018U) & 0x0003FFFFU) >> 0x00000000U; + prog_reg(0xFD080018, 0x3FFFF, 0x0, cur_R006_tREFPRD); + + prog_reg(0xFD08001CU, 0x00000018U, 0x00000003U, 0x00000003U); + prog_reg(0xFD08142CU, 0x00000030U, 0x00000004U, 0x00000003U); + prog_reg(0xFD08146CU, 0x00000030U, 0x00000004U, 0x00000003U); + prog_reg(0xFD0814ACU, 0x00000030U, 0x00000004U, 0x00000003U); + prog_reg(0xFD0814ECU, 0x00000030U, 0x00000004U, 0x00000003U); + prog_reg(0xFD08152CU, 0x00000030U, 0x00000004U, 0x00000003U); + + Xil_Out32(0xFD080004, 0x00060001); + regval = Xil_In32(0xFD080030); + while ((regval & 0x80004001) != 0x80004001) + regval = Xil_In32(0xFD080030); + + regval = ((Xil_In32(0xFD080030) & 0x1FFF0000) >> 18); + if (regval != 0) + return 0; + + prog_reg(0xFD08001CU, 0x00000018U, 0x00000003U, 0x00000000U); + prog_reg(0xFD08142CU, 0x00000030U, 0x00000004U, 0x00000000U); + prog_reg(0xFD08146CU, 0x00000030U, 0x00000004U, 0x00000000U); + prog_reg(0xFD0814ACU, 0x00000030U, 0x00000004U, 0x00000000U); + prog_reg(0xFD0814ECU, 0x00000030U, 0x00000004U, 0x00000000U); + prog_reg(0xFD08152CU, 0x00000030U, 0x00000004U, 0x00000000U); + + Xil_Out32(0xFD080200U, 0x800091C7U); + prog_reg(0xFD080018, 0x3FFFF, 0x0, cur_R006_tREFPRD); + + Xil_Out32(0xFD080004, 0x0000C001); + regval = Xil_In32(0xFD080030); + while ((regval & 0x80000C01) != 0x80000C01) + regval = Xil_In32(0xFD080030); + + Xil_Out32(0xFD070180U, 0x010B0008U); + Xil_Out32(0xFD070060U, 0x00000000U); + prog_reg(0xFD080014U, 0x00000040U, 0x00000006U, 0x00000000U); + + return 1; +} + +static int serdes_enb_coarse_saturation(void) +{ + Xil_Out32(0xFD402094, 0x00000010); + Xil_Out32(0xFD406094, 0x00000010); + Xil_Out32(0xFD40A094, 0x00000010); + Xil_Out32(0xFD40E094, 0x00000010); + return 1; +} + +static int serdes_fixcal_code(void) +{ + int maskstatus = 1; + unsigned int rdata = 0; + unsigned int match_pmos_code[23]; + unsigned int match_nmos_code[23]; + unsigned int match_ical_code[7]; + unsigned int match_rcal_code[7]; + unsigned int p_code = 0; + unsigned int n_code = 0; + unsigned int i_code = 0; + unsigned int r_code = 0; + unsigned int repeat_count = 0; + unsigned int L3_TM_CALIB_DIG20 = 0; + unsigned int L3_TM_CALIB_DIG19 = 0; + unsigned int L3_TM_CALIB_DIG18 = 0; + unsigned int L3_TM_CALIB_DIG16 = 0; + unsigned int L3_TM_CALIB_DIG15 = 0; + unsigned int L3_TM_CALIB_DIG14 = 0; + int i = 0; + + rdata = Xil_In32(0xFD40289C); + rdata = rdata & ~0x03; + rdata = rdata | 0x1; + Xil_Out32(0xFD40289C, rdata); + int count = 0; + do { + if (count == 1100000) + break; + rdata = Xil_In32(0xFD402B1C); + count++; + } while ((rdata & 0x0000000E) != 0x0000000E); + + for (i = 0; i < 23; i++) { + match_pmos_code[i] = 0; + match_nmos_code[i] = 0; + } + for (i = 0; i < 7; i++) { + match_ical_code[i] = 0; + match_rcal_code[i] = 0; + } + + do { + Xil_Out32(0xFD410010, 0x00000000); + Xil_Out32(0xFD410014, 0x00000000); + + Xil_Out32(0xFD410010, 0x00000001); + Xil_Out32(0xFD410014, 0x00000000); + + maskstatus = mask_poll(0xFD40EF14, 0x2); + if (maskstatus == 0) { + xil_printf("#SERDES initialization timed out\n\r"); + return maskstatus; + } + + p_code = mask_read(0xFD40EF18, 0xFFFFFFFF); + n_code = mask_read(0xFD40EF1C, 0xFFFFFFFF); + ; + i_code = mask_read(0xFD40EF24, 0xFFFFFFFF); + r_code = mask_read(0xFD40EF28, 0xFFFFFFFF); + ; + + if (p_code >= 0x26 && p_code <= 0x3C) + match_pmos_code[p_code - 0x26] += 1; + + if (n_code >= 0x26 && n_code <= 0x3C) + match_nmos_code[n_code - 0x26] += 1; + + if (i_code >= 0xC && i_code <= 0x12) + match_ical_code[i_code - 0xC] += 1; + + if (r_code >= 0x6 && r_code <= 0xC) + match_rcal_code[r_code - 0x6] += 1; + + } while (repeat_count++ < 10); + + for (i = 0; i < 23; i++) { + if (match_pmos_code[i] >= match_pmos_code[0]) { + match_pmos_code[0] = match_pmos_code[i]; + p_code = 0x26 + i; + } + if (match_nmos_code[i] >= match_nmos_code[0]) { + match_nmos_code[0] = match_nmos_code[i]; + n_code = 0x26 + i; + } + } + + for (i = 0; i < 7; i++) { + if (match_ical_code[i] >= match_ical_code[0]) { + match_ical_code[0] = match_ical_code[i]; + i_code = 0xC + i; + } + if (match_rcal_code[i] >= match_rcal_code[0]) { + match_rcal_code[0] = match_rcal_code[i]; + r_code = 0x6 + i; + } + } + + L3_TM_CALIB_DIG20 = mask_read(0xFD40EC50, 0xFFFFFFF0); + L3_TM_CALIB_DIG20 = L3_TM_CALIB_DIG20 | 0x8 | ((p_code >> 2) & 0x7); + + L3_TM_CALIB_DIG19 = mask_read(0xFD40EC4C, 0xFFFFFF18); + L3_TM_CALIB_DIG19 = L3_TM_CALIB_DIG19 | ((p_code & 0x3) << 6) + | 0x20 | 0x4 | ((n_code >> 3) & 0x3); + + L3_TM_CALIB_DIG18 = mask_read(0xFD40EC48, 0xFFFFFF0F); + L3_TM_CALIB_DIG18 = L3_TM_CALIB_DIG18 | ((n_code & 0x7) << 5) | 0x10; + + L3_TM_CALIB_DIG16 = mask_read(0xFD40EC40, 0xFFFFFFF8); + L3_TM_CALIB_DIG16 = L3_TM_CALIB_DIG16 | ((r_code >> 1) & 0x7); + + L3_TM_CALIB_DIG15 = mask_read(0xFD40EC3C, 0xFFFFFF30); + L3_TM_CALIB_DIG15 = L3_TM_CALIB_DIG15 | ((r_code & 0x1) << 7) + | 0x40 | 0x8 | ((i_code >> 1) & 0x7); + + L3_TM_CALIB_DIG14 = mask_read(0xFD40EC38, 0xFFFFFF3F); + L3_TM_CALIB_DIG14 = L3_TM_CALIB_DIG14 | ((i_code & 0x1) << 7) | 0x40; + + Xil_Out32(0xFD40EC50, L3_TM_CALIB_DIG20); + Xil_Out32(0xFD40EC4C, L3_TM_CALIB_DIG19); + Xil_Out32(0xFD40EC48, L3_TM_CALIB_DIG18); + Xil_Out32(0xFD40EC40, L3_TM_CALIB_DIG16); + Xil_Out32(0xFD40EC3C, L3_TM_CALIB_DIG15); + Xil_Out32(0xFD40EC38, L3_TM_CALIB_DIG14); + return maskstatus; +} + +static int init_serdes(void) +{ + int status = 1; + + status &= psu_resetin_init_data(); + + status &= serdes_fixcal_code(); + status &= serdes_enb_coarse_saturation(); + + status &= psu_serdes_init_data(); + status &= psu_resetout_init_data(); + + return status; +} + +static void init_peripheral(void) +{ + psu_mask_write(0xFD5F0018, 0x8000001FU, 0x8000001FU); +} + +int psu_init(void) +{ + int status = 1; + + status &= psu_mio_init_data(); + status &= psu_peripherals_pre_init_data(); + status &= psu_pll_init_data(); + status &= psu_clock_init_data(); + status &= psu_ddr_init_data(); + status &= psu_ddr_phybringup_data(); + status &= psu_peripherals_init_data(); + status &= init_serdes(); + init_peripheral(); + + status &= psu_afi_config(); + psu_ddr_qos_init_data(); + + if (status == 0) + return 1; + return 0; +} diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig index acab38fefe..347a822eaf 100644 --- a/configs/xilinx_zynqmp_virt_defconfig +++ b/configs/xilinx_zynqmp_virt_defconfig @@ -104,7 +104,7 @@ CONFIG_CMD_UBI=y CONFIG_PARTITION_TYPE_GUID=y CONFIG_SPL_OF_CONTROL=y CONFIG_OF_BOARD=y -CONFIG_OF_LIST="avnet-ultra96-rev1 zynqmp-a2197-revA zynqmp-e-a2197-00-revA zynqmp-g-a2197-00-revA zynqmp-m-a2197-01-revA zynqmp-m-a2197-02-revA zynqmp-m-a2197-03-revA zynqmp-p-a2197-00-revA zynqmp-zc1232-revA zynqmp-zc1254-revA zynqmp-zc1751-xm015-dc1 zynqmp-zc1751-xm016-dc2 zynqmp-zc1751-xm017-dc3 zynqmp-zc1751-xm018-dc4 zynqmp-zc1751-xm019-dc5 zynqmp-zcu100-revC zynqmp-zcu102-rev1.1 zynqmp-zcu102-rev1.0 zynqmp-zcu102-revA zynqmp-zcu102-revB zynqmp-zcu104-revA zynqmp-zcu104-revC zynqmp-zcu106-revA zynqmp-zcu106-rev1.0 zynqmp-zcu111-revA zynqmp-zcu1275-revA zynqmp-zcu1275-revB zynqmp-zcu1285-revA zynqmp-zcu208-revA zynqmp-zcu216-revA zynqmp-topic-miamimp-xilinx-xdp-v1r1 zynqmp-sm-k26-revA zynqmp-smk-k26-revA zynqmp-dlc21-revA" +CONFIG_OF_LIST="avnet-ultra96-rev1 zynqmp-a2197-revA zynqmp-beckhoff-cx8200 zynqmp-e-a2197-00-revA zynqmp-g-a2197-00-revA zynqmp-m-a2197-01-revA zynqmp-m-a2197-02-revA zynqmp-m-a2197-03-revA zynqmp-p-a2197-00-revA zynqmp-zc1232-revA zynqmp-zc1254-revA zynqmp-zc1751-xm015-dc1 zynqmp-zc1751-xm016-dc2 zynqmp-zc1751-xm017-dc3 zynqmp-zc1751-xm018-dc4 zynqmp-zc1751-xm019-dc5 zynqmp-zcu100-revC zynqmp-zcu102-rev1.1 zynqmp-zcu102-rev1.0 zynqmp-zcu102-revA zynqmp-zcu102-revB zynqmp-zcu104-revA zynqmp-zcu104-revC zynqmp-zcu106-revA zynqmp-zcu106-rev1.0 zynqmp-zcu111-revA zynqmp-zcu1275-revA zynqmp-zcu1275-revB zynqmp-zcu1285-revA zynqmp-zcu208-revA zynqmp-zcu216-revA zynqmp-topic-miamimp-xilinx-xdp-v1r1 zynqmp-sm-k26-revA zynqmp-smk-k26-revA zynqmp-dlc21-revA" CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names interrupt-parent interrupts iommus power-domains" CONFIG_ENV_IS_NOWHERE=y CONFIG_ENV_IS_IN_FAT=y

On 8/30/23 16:03, Steffen Dirkwinkel wrote:
From: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
This adds support for the Beckhoff CX8200 series of industrial embedded PCs. There is some information about the device and features here: https://www.beckhoff.com/en-en/products/ipc/embedded-pcs/cx8200-arm-cortex-a...
Currently supported/tested:
- Boot from microSD
- Ethernet
- USB
- rtc / rtc eeprom
- tpm access
- uart
Open points:
- adding the psgtr usb phy doesn't work in linux (failed to get pll lock)
- fpga loading currently only as u-boot script or pre launch cmd (type may be stored in eeprom of rtc so this could be made generic)
Signed-off-by: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
arch/arm/dts/Makefile | 1 + arch/arm/dts/zynqmp-beckhoff-cx8200.dts | 247 +++ .../zynqmp-beckhoff-cx8200/psu_init_gpl.c | 1960 +++++++++++++++++ configs/xilinx_zynqmp_virt_defconfig | 2 +- 4 files changed, 2209 insertions(+), 1 deletion(-) create mode 100644 arch/arm/dts/zynqmp-beckhoff-cx8200.dts create mode 100644 board/xilinx/zynqmp/zynqmp-beckhoff-cx8200/psu_init_gpl.c
First of all xilinx folder is not the right location because Xilinx/AMD is not manufacturer of this board.
Second I am normally pushing back on adding these custom boards because it just increase time for maintaining. Your last commit was in 2019 but at least you have some commits that I can trust that you would maintain your board for some time.
My biggest question is in what category is your board unique that it should be added it to the tree?
Thanks, Michal

Am 01.09.23 um 09:36 schrieb Michal Simek:
On 8/30/23 16:03, Steffen Dirkwinkel wrote:
From: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
This adds support for the Beckhoff CX8200 series of industrial embedded PCs. There is some information about the device and features here: https://www.beckhoff.com/en-en/products/ipc/embedded-pcs/cx8200-arm-cortex-a...
Currently supported/tested:
- Boot from microSD
- Ethernet
- USB
- rtc / rtc eeprom
- tpm access
- uart
Open points:
- adding the psgtr usb phy doesn't work in linux (failed to get pll
lock)
- fpga loading currently only as u-boot script or pre launch cmd (type
may be stored in eeprom of rtc so this could be made generic)
Signed-off-by: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
arch/arm/dts/Makefile | 1 + arch/arm/dts/zynqmp-beckhoff-cx8200.dts | 247 +++ .../zynqmp-beckhoff-cx8200/psu_init_gpl.c | 1960 +++++++++++++++++ configs/xilinx_zynqmp_virt_defconfig | 2 +- 4 files changed, 2209 insertions(+), 1 deletion(-) create mode 100644 arch/arm/dts/zynqmp-beckhoff-cx8200.dts create mode 100644 board/xilinx/zynqmp/zynqmp-beckhoff-cx8200/psu_init_gpl.c
First of all xilinx folder is not the right location because Xilinx/AMD is not manufacturer of this board.
Yeah, sorry. I saw the avnet board and copied that.
Second I am normally pushing back on adding these custom boards because it just increase time for maintaining. Your last commit was in 2019 but at least you have some commits that I can trust that you would maintain your board for some time.
Our last board [1] only had linux/u-boot support as an afterthought. Customers had to buy a special option to set the right boot fuses, so most devices don’t boot u-boot. With this board and a second similar zynqmp board (CX9240 [2]) we’ll have u-boot as default (and probably only) bootloader, so we’ll be more active. We can also set two of us as maintainers and it would be fine to drop the boards if nobody responds. We generally support these industrial boards for long time frames and would like to stay close to mainline instead of maintaining forks.
The alternative would be to have a downstream u-boot repository on github or somewhere. We’ll still likely have something there for build scripts / firmware builds / integration, but don’t plan to really diverge from upstream u-boot.
The main advantage of being in upstream u-boot would be that we can trigger internal CI on upstream changes. We can still do that and apply patches, but even simple patches like adding files to a makefile may fail to apply and will need fixing.
My biggest question is in what category is your board unique that it should be added it to the tree?
Currently the board isn’t really unique. I guess we’d be the only users of the rtc with eeprom and there might be something needed for loading the correct fpga file based on eeprom (this might be done in linux / userspace or even u-boot script though)
[1] https://www.beckhoff.com/en-en/products/ipc/embedded-pcs/cx9020-arm-cortex-a... [2] https://www.beckhoff.com/en-en/products/ipc/embedded-pcs/cx9240-arm-cortex-a...
Thanks, Michal

On 9/1/23 11:00, Steffen Dirkwinkel wrote:
Am 01.09.23 um 09:36 schrieb Michal Simek:
On 8/30/23 16:03, Steffen Dirkwinkel wrote:
From: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
This adds support for the Beckhoff CX8200 series of industrial embedded PCs. There is some information about the device and features here: https://www.beckhoff.com/en-en/products/ipc/embedded-pcs/cx8200-arm-cortex-a...
Currently supported/tested:
- Boot from microSD
- Ethernet
- USB
- rtc / rtc eeprom
- tpm access
- uart
Open points:
- adding the psgtr usb phy doesn't work in linux (failed to get pll
lock)
- fpga loading currently only as u-boot script or pre launch cmd (type
may be stored in eeprom of rtc so this could be made generic)
Signed-off-by: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
arch/arm/dts/Makefile | 1 + arch/arm/dts/zynqmp-beckhoff-cx8200.dts | 247 +++ .../zynqmp-beckhoff-cx8200/psu_init_gpl.c | 1960 +++++++++++++++++ configs/xilinx_zynqmp_virt_defconfig | 2 +- 4 files changed, 2209 insertions(+), 1 deletion(-) create mode 100644 arch/arm/dts/zynqmp-beckhoff-cx8200.dts create mode 100644 board/xilinx/zynqmp/zynqmp-beckhoff-cx8200/psu_init_gpl.c
First of all xilinx folder is not the right location because Xilinx/AMD is not manufacturer of this board.
Yeah, sorry. I saw the avnet board and copied that.
Second I am normally pushing back on adding these custom boards because it just increase time for maintaining. Your last commit was in 2019 but at least you have some commits that I can trust that you would maintain your board for some time.
Our last board [1] only had linux/u-boot support as an afterthought. Customers had to buy a special option to set the right boot fuses, so most devices don’t boot u-boot. With this board and a second similar zynqmp board (CX9240 [2]) we’ll have u-boot as default (and probably only) bootloader, so we’ll be more active. We can also set two of us as maintainers and it would be fine to drop the boards if nobody responds. We generally support these industrial boards for long time frames and would like to stay close to mainline instead of maintaining forks.
The alternative would be to have a downstream u-boot repository on github or somewhere. We’ll still likely have something there for build scripts / firmware builds / integration, but don’t plan to really diverge from upstream u-boot.
The main advantage of being in upstream u-boot would be that we can trigger internal CI on upstream changes. We can still do that and apply patches, but even simple patches like adding files to a makefile may fail to apply and will need fixing.
My biggest question is in what category is your board unique that it should be added it to the tree?
Currently the board isn’t really unique. I guess we’d be the only users of the rtc with eeprom and there might be something needed for loading the correct fpga file based on eeprom (this might be done in linux / userspace or even u-boot script though)
[1] https://www.beckhoff.com/en-en/products/ipc/embedded-pcs/cx9020-arm-cortex-a... [2] https://www.beckhoff.com/en-en/products/ipc/embedded-pcs/cx9240-arm-cortex-a...
Regarding board itself. It is DTB - we use OF_SEPARATE/OF_BOARD it means building is easy. I expect you have pretty much something in PL that's why your DT is bigger if you don't use DT overlays but for fixed design there is actually no reason to use it.
psu_init_gpl. You are adding it to specific folder which match DEVICE_TREE variable when you use it. You can actually just copy it to board/xilinx/zynqmp/ folder and it will be pick up for your build.
xilinx_zynqmp_virt_defconfig - you likely don't want to use this in your product because there are things enabled which you don't use on your board. That's why you should tune it for your usage.
regs.init - that's for boot.bin generation with SPL - BOOT_INIT_FILE should be used and it can't be wired via generic defconfig anyway.
That pretty much leads to the state that make no sense for you to use xilinx_zynqmp_virt_defconfig.
I think we are still supporting defconfig fragments which is the way how to maintain your board to be close to mainline as possible.
And fdt_addr change. I think this is for me the most problematic part which should be solved. Pretty much all these variables should be moved out and that's what we started to work on. But it will take some time to get there.
Definitely there shouldn't be a problem to merge that rtc driver and I would prefer if you can stay with your board out of upstream and try to maintain it via your build scripts only. And let me know if we can improve/fix something to be able to do it in long term. But pretty much all things should be in place already to do it without pain. At least I would like you to try it and see if there is any major blocker which we can try to fix.
Thanks, Michal

Am 01.09.23 um 13:16 schrieb Michal Simek:
On 9/1/23 11:00, Steffen Dirkwinkel wrote:
Am 01.09.23 um 09:36 schrieb Michal Simek:
On 8/30/23 16:03, Steffen Dirkwinkel wrote:
From: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
This adds support for the Beckhoff CX8200 series of industrial embedded PCs. There is some information about the device and features here: https://www.beckhoff.com/en-en/products/ipc/embedded-pcs/cx8200-arm-cortex-a...
Currently supported/tested:
- Boot from microSD
- Ethernet
- USB
- rtc / rtc eeprom
- tpm access
- uart
Open points:
- adding the psgtr usb phy doesn't work in linux (failed to get pll
lock)
- fpga loading currently only as u-boot script or pre launch cmd (type
may be stored in eeprom of rtc so this could be made generic)
Signed-off-by: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
arch/arm/dts/Makefile | 1 + arch/arm/dts/zynqmp-beckhoff-cx8200.dts | 247 +++ .../zynqmp-beckhoff-cx8200/psu_init_gpl.c | 1960 +++++++++++++++++ configs/xilinx_zynqmp_virt_defconfig | 2 +- 4 files changed, 2209 insertions(+), 1 deletion(-) create mode 100644 arch/arm/dts/zynqmp-beckhoff-cx8200.dts create mode 100644 board/xilinx/zynqmp/zynqmp-beckhoff-cx8200/psu_init_gpl.c
First of all xilinx folder is not the right location because Xilinx/AMD is not manufacturer of this board.
Yeah, sorry. I saw the avnet board and copied that.
Second I am normally pushing back on adding these custom boards because it just increase time for maintaining. Your last commit was in 2019 but at least you have some commits that I can trust that you would maintain your board for some time.
Our last board [1] only had linux/u-boot support as an afterthought. Customers had to buy a special option to set the right boot fuses, so most devices don’t boot u-boot. With this board and a second similar zynqmp board (CX9240 [2]) we’ll have u-boot as default (and probably only) bootloader, so we’ll be more active. We can also set two of us as maintainers and it would be fine to drop the boards if nobody responds. We generally support these industrial boards for long time frames and would like to stay close to mainline instead of maintaining forks.
The alternative would be to have a downstream u-boot repository on github or somewhere. We’ll still likely have something there for build scripts / firmware builds / integration, but don’t plan to really diverge from upstream u-boot.
The main advantage of being in upstream u-boot would be that we can trigger internal CI on upstream changes. We can still do that and apply patches, but even simple patches like adding files to a makefile may fail to apply and will need fixing.
My biggest question is in what category is your board unique that it should be added it to the tree?
Currently the board isn’t really unique. I guess we’d be the only users of the rtc with eeprom and there might be something needed for loading the correct fpga file based on eeprom (this might be done in linux / userspace or even u-boot script though)
[1] https://www.beckhoff.com/en-en/products/ipc/embedded-pcs/cx9020-arm-cortex-a... [2] https://www.beckhoff.com/en-en/products/ipc/embedded-pcs/cx9240-arm-cortex-a...
Regarding board itself. It is DTB - we use OF_SEPARATE/OF_BOARD it means building is easy. I expect you have pretty much something in PL that's why your DT is bigger if you don't use DT overlays but for fixed design there is actually no reason to use it.
psu_init_gpl. You are adding it to specific folder which match DEVICE_TREE variable when you use it. You can actually just copy it to board/xilinx/zynqmp/ folder and it will be pick up for your build.
xilinx_zynqmp_virt_defconfig - you likely don't want to use this in your product because there are things enabled which you don't use on your board. That's why you should tune it for your usage.
regs.init - that's for boot.bin generation with SPL - BOOT_INIT_FILE should be used and it can't be wired via generic defconfig anyway.
That pretty much leads to the state that make no sense for you to use xilinx_zynqmp_virt_defconfig.
There are things in the defconfig we don't need, but size hasn't really been an issue, since we boot from relatively large sdcards. We might still do separate config for all our boards though.
We currently build virt_defconfig and set BOOT_INIT_FILE, PMUFW_INIT_FILE and ZYNQMP_SPL_PM_CFG_OBJ_FILE. If we ship this firmware somewhere (similar to linux-firmware?) we could set fixed paths for that and make rebuilding u-boot simpler. I've found reproducing images for zynqmp devboards with and without using petalinux and the xilinx fsbl to be quite annoying on the first try and this could be simpler if one just wants to support generic arm64 distros.
I think we are still supporting defconfig fragments which is the way how to maintain your board to be close to mainline as possible.
And fdt_addr change. I think this is for me the most problematic part which should be solved. Pretty much all these variables should be moved out and that's what we started to work on. But it will take some time to get there.
I agree, I can also work on that, but it will likely be in October since I'm on vacation for most of September. Maybe one of our other developers will work on it instead.
Definitely there shouldn't be a problem to merge that rtc driver and I would prefer if you can stay with your board out of upstream and try to maintain it via your build scripts only. And let me know if we can improve/fix something to be able to do it in long term. But pretty much all things should be in place already to do it without pain. At least I would like you to try it and see if there is any major blocker which we can try to fix.
I don't really understand why the board shouldn't be upstream, once it is just a dts file + psu_init_gpl + regs. There really isn't much to maintain there that wouldn't also break out of tree.
We might be different from most other out of tree zynqmp users, since we usually also offer to sell hardware without our software and users would then either download an image from us or build their own u-boot + linux and only download the fpga bitstreams. I expect most people would look at upstream u-boot and linux before looking for our downstream repositories.
We can and will of course start with a downstream repository, I just don't understand why real (non-devboard) hardware should be out of tree.
Thanks, Steffen
Thanks, Michal

On 9/1/23 17:03, Steffen Dirkwinkel wrote:
Am 01.09.23 um 13:16 schrieb Michal Simek:
On 9/1/23 11:00, Steffen Dirkwinkel wrote:
Am 01.09.23 um 09:36 schrieb Michal Simek:
On 8/30/23 16:03, Steffen Dirkwinkel wrote:
From: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
This adds support for the Beckhoff CX8200 series of industrial embedded PCs. There is some information about the device and features here: https://www.beckhoff.com/en-en/products/ipc/embedded-pcs/cx8200-arm-cortex-a...
Currently supported/tested:
- Boot from microSD
- Ethernet
- USB
- rtc / rtc eeprom
- tpm access
- uart
Open points:
- adding the psgtr usb phy doesn't work in linux (failed to get pll
lock)
- fpga loading currently only as u-boot script or pre launch cmd (type
may be stored in eeprom of rtc so this could be made generic)
Signed-off-by: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
arch/arm/dts/Makefile | 1 + arch/arm/dts/zynqmp-beckhoff-cx8200.dts | 247 +++ .../zynqmp-beckhoff-cx8200/psu_init_gpl.c | 1960 +++++++++++++++++ configs/xilinx_zynqmp_virt_defconfig | 2 +- 4 files changed, 2209 insertions(+), 1 deletion(-) create mode 100644 arch/arm/dts/zynqmp-beckhoff-cx8200.dts create mode 100644 board/xilinx/zynqmp/zynqmp-beckhoff-cx8200/psu_init_gpl.c
First of all xilinx folder is not the right location because Xilinx/AMD is not manufacturer of this board.
Yeah, sorry. I saw the avnet board and copied that.
Second I am normally pushing back on adding these custom boards because it just increase time for maintaining. Your last commit was in 2019 but at least you have some commits that I can trust that you would maintain your board for some time.
Our last board [1] only had linux/u-boot support as an afterthought. Customers had to buy a special option to set the right boot fuses, so most devices don’t boot u-boot. With this board and a second similar zynqmp board (CX9240 [2]) we’ll have u-boot as default (and probably only) bootloader, so we’ll be more active. We can also set two of us as maintainers and it would be fine to drop the boards if nobody responds. We generally support these industrial boards for long time frames and would like to stay close to mainline instead of maintaining forks.
The alternative would be to have a downstream u-boot repository on github or somewhere. We’ll still likely have something there for build scripts / firmware builds / integration, but don’t plan to really diverge from upstream u-boot.
The main advantage of being in upstream u-boot would be that we can trigger internal CI on upstream changes. We can still do that and apply patches, but even simple patches like adding files to a makefile may fail to apply and will need fixing.
My biggest question is in what category is your board unique that it should be added it to the tree?
Currently the board isn’t really unique. I guess we’d be the only users of the rtc with eeprom and there might be something needed for loading the correct fpga file based on eeprom (this might be done in linux / userspace or even u-boot script though)
[1] https://www.beckhoff.com/en-en/products/ipc/embedded-pcs/cx9020-arm-cortex-a... [2] https://www.beckhoff.com/en-en/products/ipc/embedded-pcs/cx9240-arm-cortex-a...
Regarding board itself. It is DTB - we use OF_SEPARATE/OF_BOARD it means building is easy. I expect you have pretty much something in PL that's why your DT is bigger if you don't use DT overlays but for fixed design there is actually no reason to use it.
psu_init_gpl. You are adding it to specific folder which match DEVICE_TREE variable when you use it. You can actually just copy it to board/xilinx/zynqmp/ folder and it will be pick up for your build.
xilinx_zynqmp_virt_defconfig - you likely don't want to use this in your product because there are things enabled which you don't use on your board. That's why you should tune it for your usage.
regs.init - that's for boot.bin generation with SPL - BOOT_INIT_FILE should be used and it can't be wired via generic defconfig anyway.
That pretty much leads to the state that make no sense for you to use xilinx_zynqmp_virt_defconfig.
There are things in the defconfig we don't need, but size hasn't really been an issue, since we boot from relatively large sdcards. We might still do separate config for all our boards though.
We currently build virt_defconfig and set BOOT_INIT_FILE, PMUFW_INIT_FILE and ZYNQMP_SPL_PM_CFG_OBJ_FILE. If we ship this firmware somewhere (similar to linux-firmware?) we could set fixed paths for that and make rebuilding u-boot simpler. I've found reproducing images for zynqmp devboards with and without using petalinux and the xilinx fsbl to be quite annoying on the first try and this could be simpler if one just wants to support generic arm64 distros.
I think we are still supporting defconfig fragments which is the way how to maintain your board to be close to mainline as possible.
And fdt_addr change. I think this is for me the most problematic part which should be solved. Pretty much all these variables should be moved out and that's what we started to work on. But it will take some time to get there.
I agree, I can also work on that, but it will likely be in October since I'm on vacation for most of September. Maybe one of our other developers will work on it instead.
Definitely there shouldn't be a problem to merge that rtc driver and I would prefer if you can stay with your board out of upstream and try to maintain it via your build scripts only. And let me know if we can improve/fix something to be able to do it in long term. But pretty much all things should be in place already to do it without pain. At least I would like you to try it and see if there is any major blocker which we can try to fix.
I don't really understand why the board shouldn't be upstream, once it is just a dts file + psu_init_gpl + regs. There really isn't much to maintain there that wouldn't also break out of tree.
We might be different from most other out of tree zynqmp users, since we usually also offer to sell hardware without our software and users would then either download an image from us or build their own u-boot + linux and only download the fpga bitstreams. I expect most people would look at upstream u-boot and linux before looking for our downstream repositories.
Sounds good.
We can and will of course start with a downstream repository, I just don't understand why real (non-devboard) hardware should be out of tree.
It can be I just want to make sure that you don't disappear after short time. Topic's platforms are also the part of tree. It means let's figure it out that fdt part which you need to solve and we can merge your platform if you give me commitment that you will test and support it.
Thanks, Michal

From: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
We need it for coherent access between pl and ps.
From xilinx documentation:
https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842098/Zynq+UltraSca...
Inner Cache Broadcasting
Linux sets up the MMU for cacheable memory to be inner shareable as that supports SMP operation. As modifying the MMU tables from kernel or userspace is not a straightforwards task, the inner cache broadcasting feature can be used to allow inner cacheble transactions be broadcasted. Outside the APU, in the outer domain, the CCI handles coherency across the system. The brdc_inner bit of the lpd_apu register within the LPD_SLCR module must be written while the APU is in reset.
The requirement to alter the register while the APU is in reset can be accomplished using the register initialization feature in the boot image. .set. 0xFF41A040 = 0x3;
Signed-off-by: Steffen Dirkwinkel s.dirkwinkel@beckhoff.com
---
board/xilinx/zynqmp/zynqmp-beckhoff-cx8200/regs.init | 1 + 1 file changed, 1 insertion(+) create mode 100644 board/xilinx/zynqmp/zynqmp-beckhoff-cx8200/regs.init
diff --git a/board/xilinx/zynqmp/zynqmp-beckhoff-cx8200/regs.init b/board/xilinx/zynqmp/zynqmp-beckhoff-cx8200/regs.init new file mode 100644 index 0000000000..e7038dd80a --- /dev/null +++ b/board/xilinx/zynqmp/zynqmp-beckhoff-cx8200/regs.init @@ -0,0 +1 @@ +0xFF41A040 0x3 \ No newline at end of file
participants (5)
-
Alexandre Belloni
-
Michal Simek
-
Michal Simek
-
Steffen Dirkwinkel
-
Steffen Dirkwinkel