aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/drivers/rtc
diff options
context:
space:
mode:
authorAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
committerAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
commitaf1a266670d040d2f4083ff309d732d648afba2a (patch)
tree2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/u-boot/drivers/rtc
parente02cda008591317b1625707ff8e115a4841aa889 (diff)
Add submodule dependency filesHEADmaster
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/u-boot/drivers/rtc')
-rw-r--r--roms/u-boot/drivers/rtc/Kconfig191
-rw-r--r--roms/u-boot/drivers/rtc/Makefile60
-rw-r--r--roms/u-boot/drivers/rtc/abx80x.c553
-rw-r--r--roms/u-boot/drivers/rtc/armada38x.c184
-rw-r--r--roms/u-boot/drivers/rtc/at91sam9_rtt.c78
-rw-r--r--roms/u-boot/drivers/rtc/davinci.c82
-rw-r--r--roms/u-boot/drivers/rtc/ds1302.c329
-rw-r--r--roms/u-boot/drivers/rtc/ds1306.c438
-rw-r--r--roms/u-boot/drivers/rtc/ds1307.c362
-rw-r--r--roms/u-boot/drivers/rtc/ds1337.c319
-rw-r--r--roms/u-boot/drivers/rtc/ds1374.c214
-rw-r--r--roms/u-boot/drivers/rtc/ds1556.c179
-rw-r--r--roms/u-boot/drivers/rtc/ds164x.c171
-rw-r--r--roms/u-boot/drivers/rtc/ds174x.c172
-rw-r--r--roms/u-boot/drivers/rtc/ds3231.c292
-rw-r--r--roms/u-boot/drivers/rtc/ds3232.c276
-rw-r--r--roms/u-boot/drivers/rtc/emul_rtc.c96
-rw-r--r--roms/u-boot/drivers/rtc/ftrtc010.c122
-rw-r--r--roms/u-boot/drivers/rtc/i2c_rtc_emul.c219
-rw-r--r--roms/u-boot/drivers/rtc/imxdi.c223
-rw-r--r--roms/u-boot/drivers/rtc/isl1208.c197
-rw-r--r--roms/u-boot/drivers/rtc/m41t11.c168
-rw-r--r--roms/u-boot/drivers/rtc/m41t60.c239
-rw-r--r--roms/u-boot/drivers/rtc/m41t62.c356
-rw-r--r--roms/u-boot/drivers/rtc/m41t94.c123
-rw-r--r--roms/u-boot/drivers/rtc/m48t35ax.c135
-rw-r--r--roms/u-boot/drivers/rtc/max6900.c105
-rw-r--r--roms/u-boot/drivers/rtc/mc13xxx-rtc.c65
-rw-r--r--roms/u-boot/drivers/rtc/mc146818.c308
-rw-r--r--roms/u-boot/drivers/rtc/mcfrtc.c104
-rw-r--r--roms/u-boot/drivers/rtc/mk48t59.c175
-rw-r--r--roms/u-boot/drivers/rtc/mvrtc.c186
-rw-r--r--roms/u-boot/drivers/rtc/mvrtc.h53
-rw-r--r--roms/u-boot/drivers/rtc/mx27rtc.c64
-rw-r--r--roms/u-boot/drivers/rtc/mxsrtc.c71
-rw-r--r--roms/u-boot/drivers/rtc/pcf2127.c132
-rw-r--r--roms/u-boot/drivers/rtc/pcf8563.c225
-rw-r--r--roms/u-boot/drivers/rtc/pl031.c142
-rw-r--r--roms/u-boot/drivers/rtc/pt7c4338.c228
-rw-r--r--roms/u-boot/drivers/rtc/rs5c372.c256
-rw-r--r--roms/u-boot/drivers/rtc/rtc-lib.c77
-rw-r--r--roms/u-boot/drivers/rtc/rtc-uclass.c180
-rw-r--r--roms/u-boot/drivers/rtc/rv3028.c208
-rw-r--r--roms/u-boot/drivers/rtc/rv3029.c500
-rw-r--r--roms/u-boot/drivers/rtc/rv8803.c169
-rw-r--r--roms/u-boot/drivers/rtc/rx8010sj.c380
-rw-r--r--roms/u-boot/drivers/rtc/rx8025.c306
-rw-r--r--roms/u-boot/drivers/rtc/s35392a.c374
-rw-r--r--roms/u-boot/drivers/rtc/s3c24x0_rtc.c149
-rw-r--r--roms/u-boot/drivers/rtc/sandbox_rtc.c114
-rw-r--r--roms/u-boot/drivers/rtc/stm32_rtc.c334
-rw-r--r--roms/u-boot/drivers/rtc/x1205.c161
52 files changed, 10844 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/rtc/Kconfig b/roms/u-boot/drivers/rtc/Kconfig
new file mode 100644
index 000000000..c84a9d2b2
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/Kconfig
@@ -0,0 +1,191 @@
+#
+# RTC drivers configuration
+#
+
+menu "Real Time Clock"
+
+config DM_RTC
+ bool "Enable Driver Model for RTC drivers"
+ depends on DM
+ select LIB_DATE
+ help
+ Enable drver model for real-time-clock drivers. The RTC uclass
+ then provides the rtc_get()/rtc_set() interface, delegating to
+ drivers to perform the actual functions. See rtc.h for a
+ description of the API.
+
+config SPL_DM_RTC
+ bool "Enable Driver Model for RTC drivers in SPL"
+ depends on SPL_DM
+ help
+ Enable drver model for real-time-clock drivers. The RTC uclass
+ then provides the rtc_get()/rtc_set() interface, delegating to
+ drivers to perform the actual functions. See rtc.h for a
+ description of the API.
+
+config TPL_DM_RTC
+ bool "Enable Driver Model for RTC drivers in TPL"
+ depends on TPL_DM
+ help
+ Enable drver model for real-time-clock drivers. The RTC uclass
+ then provides the rtc_get()/rtc_set() interface, delegating to
+ drivers to perform the actual functions. See rtc.h for a
+ description of the API.
+
+config RTC_ENABLE_32KHZ_OUTPUT
+ bool "Enable RTC 32Khz output"
+ help
+ Some real-time clocks support the output of 32kHz square waves (such as ds3231),
+ the config symbol choose Real Time Clock device 32Khz output feature.
+
+config RTC_ARMADA38X
+ bool "Enable Armada 38x Marvell SoC RTC"
+ depends on DM_RTC && ARCH_MVEBU
+ help
+ This adds support for the in-chip RTC that can be found in the
+ Armada 38x Marvell's SoC devices.
+
+config RTC_PCF2127
+ bool "Enable PCF2127 driver"
+ depends on DM_RTC
+ help
+ The PCF2127 is a CMOS Real Time Clock (RTC) and calendar with an integrated
+ Temperature Compensated Crystal (Xtal) Oscillator (TCXO) and a 32.768 kHz quartz
+ crystal optimized for very high accuracy and very low power consumption. The PCF2127
+ has a selectable I2C-bus or SPI-bus, a backup battery switch-over circuit, a
+ programmable watchdog function, a timestamp function, and many other features.
+
+config RTC_DS1307
+ bool "Enable DS1307 driver"
+ depends on DM_RTC
+ help
+ Support for Dallas Semiconductor (now Maxim) DS1307 and DS1338/9 and
+ compatible Real Time Clock devices.
+
+config RTC_DS3232
+ bool "Enable DS3232 driver"
+ depends on DM_RTC
+ depends on DM_I2C
+ help
+ Support for Dallas Semiconductor (now Maxim) DS3232 compatible
+ Real Time Clock devices.
+
+config RTC_EMULATION
+ bool "Enable emulated RTC"
+ depends on DM_RTC
+ help
+ On a board without hardware clock this software real time clock can be
+ used. The initial time may be provided via the environment variable
+ 'rtc_emul_epoch' as a decimal string indicating seconds since
+ 1970-01-01. If the environment variable is missing, the build time is
+ used to initialize the RTC. The time can be adjusted manually via the
+ 'date' command or the 'sntp' command can be used to update the RTC
+ with the time from a network time server. See CONFIG_CMD_SNTP and
+ CONFIG_BOOTP_NTPSERVER. The RTC time is advanced according to CPU
+ ticks.
+
+config RTC_ISL1208
+ bool "Enable ISL1208 driver"
+ depends on DM_RTC
+ help
+ The Renesas (formerly Intersil) ISL1208 is a I2C Real Time Clock (RTC) and
+ calendar with automatic leap year correction, 2-byte battery backed SRAM,
+ automatic power switch-over, alarm function and 15 selectable frequency
+ outputs.
+
+ This driver supports reading and writing the RTC/calendar and detects
+ total power failures.
+
+config RTC_PCF8563
+ tristate "Philips PCF8563"
+ help
+ If you say yes here you get support for the Philips PCF8563 RTC
+ and compatible chips.
+
+config RTC_RV3028
+ bool "Enable RV3028 driver"
+ depends on DM_RTC
+ help
+ The MicroCrystal RV3028 is a I2C Real Time Clock (RTC)
+
+config RTC_RV3029
+ bool "Enable RV3029 driver"
+ depends on DM_RTC
+ help
+ The MicroCrystal RV3029 is a I2C Real Time Clock (RTC) with 8-byte
+ battery-backed SRAM.
+
+ This driver supports reading and writing the RTC/calendar and the
+ battery-baced SRAM section.
+
+config RTC_RV8803
+ bool "Enable RV8803 driver"
+ depends on DM_RTC
+ help
+ The Micro Crystal RV8803 is a high accuracy, ultra-low power I2C
+ Real Time Clock (RTC) with temperature compensation.
+
+ This driver supports reading and writing the RTC/calendar and
+ detects total power failures.
+
+config RTC_RX8010SJ
+ bool "Enable RX8010SJ driver"
+ depends on DM_RTC
+ help
+ Support for Epson RX8010SJ Real Time Clock devices.
+
+config RTC_RX8025
+ bool "Enable RX8025 driver"
+ help
+ Support for Epson RX8025 Real Time Clock devices.
+
+config RTC_PL031
+ bool "Enable ARM AMBA PL031 RTC driver"
+ help
+ The ARM PrimeCell Real Time Clock (PL031) is an optional SoC
+ peripheral based on the Advanced Microcontroller Bus Architecture
+ (AMBA). It is emulated in QEMU virtual ARM machines.
+
+config RTC_MV
+ bool "Enable Marvell RTC driver"
+ depends on DM_RTC
+ help
+ Enable Marvell RTC driver. This driver supports the rtc that is present
+ on some Marvell SoCs.
+
+config RTC_S35392A
+ bool "Enable S35392A driver"
+ select BITREVERSE
+ help
+ Enable s35392a driver which provides rtc get and set function.
+
+config RTC_MC146818
+ bool "Enable MC146818 driver"
+ help
+ This is a widely used real-time clock chip originally by Motorola
+ and now available from NXP. It includes a battery-backed real-time
+ clock with a wide array of features and 50 bytes of general-purpose,
+ battery-backed RAM. The driver supports access to the clock and RAM.
+
+config RTC_M41T62
+ bool "Enable M41T62 driver"
+ help
+ Enable driver for ST's M41T62 compatible RTC devices (like RV-4162).
+ It is a serial (I2C) real-time clock (RTC) with alarm.
+
+config RTC_STM32
+ bool "Enable STM32 RTC driver"
+ depends on DM_RTC
+ help
+ Enable STM32 RTC driver. This driver supports the rtc that is present
+ on some STM32 SoCs.
+
+config RTC_ABX80X
+ bool "Enable Abracon ABx80x RTC driver"
+ depends on DM_RTC
+ help
+ If you say yes here you get support for Abracon AB080X and AB180X
+ families of ultra-low-power battery- and capacitor-backed real-time
+ clock chips.
+
+endmenu
diff --git a/roms/u-boot/drivers/rtc/Makefile b/roms/u-boot/drivers/rtc/Makefile
new file mode 100644
index 000000000..f668cf905
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/Makefile
@@ -0,0 +1,60 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2001-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#ccflags-y += -DDEBUG
+
+obj-$(CONFIG_$(SPL_TPL_)DM_RTC) += rtc-uclass.o
+
+obj-$(CONFIG_RTC_AT91SAM9_RTT) += at91sam9_rtt.o
+obj-y += rtc-lib.o
+obj-$(CONFIG_RTC_ARMADA38X) += armada38x.o
+obj-$(CONFIG_RTC_DAVINCI) += davinci.o
+obj-$(CONFIG_RTC_DS1302) += ds1302.o
+obj-$(CONFIG_RTC_DS1306) += ds1306.o
+obj-$(CONFIG_RTC_DS1307) += ds1307.o
+obj-$(CONFIG_RTC_DS1338) += ds1307.o
+obj-$(CONFIG_RTC_DS1339) += ds1307.o
+obj-$(CONFIG_RTC_DS1337) += ds1337.o
+obj-$(CONFIG_RTC_DS1374) += ds1374.o
+obj-$(CONFIG_RTC_DS1388) += ds1337.o
+obj-$(CONFIG_RTC_DS1556) += ds1556.o
+obj-$(CONFIG_RTC_DS164x) += ds164x.o
+obj-$(CONFIG_RTC_DS174x) += ds174x.o
+obj-$(CONFIG_RTC_DS3231) += ds3231.o
+obj-$(CONFIG_RTC_DS3232) += ds3232.o
+obj-$(CONFIG_RTC_EMULATION) += emul_rtc.o
+obj-$(CONFIG_RTC_FTRTC010) += ftrtc010.o
+obj-$(CONFIG_SANDBOX) += i2c_rtc_emul.o
+obj-$(CONFIG_RTC_IMXDI) += imxdi.o
+obj-$(CONFIG_RTC_ISL1208) += isl1208.o
+obj-$(CONFIG_RTC_M41T11) += m41t11.o
+obj-$(CONFIG_RTC_M41T60) += m41t60.o
+obj-$(CONFIG_RTC_M41T62) += m41t62.o
+obj-$(CONFIG_RTC_M41T94) += m41t94.o
+obj-$(CONFIG_RTC_M48T35A) += m48t35ax.o
+obj-$(CONFIG_RTC_MAX6900) += max6900.o
+obj-$(CONFIG_RTC_MC13XXX) += mc13xxx-rtc.o
+obj-$(CONFIG_RTC_MC146818) += mc146818.o
+obj-$(CONFIG_RTC_MCP79411) += ds1307.o
+obj-$(CONFIG_MCFRTC) += mcfrtc.o
+obj-$(CONFIG_RTC_MK48T59) += mk48t59.o
+obj-$(CONFIG_RTC_MV) += mvrtc.o
+obj-$(CONFIG_RTC_MX27) += mx27rtc.o
+obj-$(CONFIG_RTC_MXS) += mxsrtc.o
+obj-$(CONFIG_RTC_PCF8563) += pcf8563.o
+obj-$(CONFIG_RTC_PCF2127) += pcf2127.o
+obj-$(CONFIG_RTC_PL031) += pl031.o
+obj-$(CONFIG_RTC_PT7C4338) += pt7c4338.o
+obj-$(CONFIG_RTC_RS5C372A) += rs5c372.o
+obj-$(CONFIG_RTC_RV3028) += rv3028.o
+obj-$(CONFIG_RTC_RV3029) += rv3029.o
+obj-$(CONFIG_RTC_RV8803) += rv8803.o
+obj-$(CONFIG_RTC_RX8025) += rx8025.o
+obj-$(CONFIG_RTC_RX8010SJ) += rx8010sj.o
+obj-$(CONFIG_RTC_S3C24X0) += s3c24x0_rtc.o
+obj-$(CONFIG_RTC_S35392A) += s35392a.o
+obj-$(CONFIG_RTC_STM32) += stm32_rtc.o
+obj-$(CONFIG_SANDBOX) += sandbox_rtc.o
+obj-$(CONFIG_RTC_X1205) += x1205.o
+obj-$(CONFIG_RTC_ABX80X) += abx80x.o
diff --git a/roms/u-boot/drivers/rtc/abx80x.c b/roms/u-boot/drivers/rtc/abx80x.c
new file mode 100644
index 000000000..528b06cbd
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/abx80x.c
@@ -0,0 +1,553 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * A driver for the I2C members of the Abracon AB x8xx RTC family,
+ * and compatible: AB 1805 and AB 0805
+ *
+ * Copyright 2014-2015 Macq S.A.
+ * Copyright 2020 Linaro
+ *
+ * Author: Philippe De Muyter <phdm@macqel.be>
+ * Author: Alexandre Belloni <alexandre.belloni@bootlin.com>
+ * Author: Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <rtc.h>
+#include <log.h>
+
+#define ABX8XX_REG_HTH 0x00
+#define ABX8XX_REG_SC 0x01
+#define ABX8XX_REG_MN 0x02
+#define ABX8XX_REG_HR 0x03
+#define ABX8XX_REG_DA 0x04
+#define ABX8XX_REG_MO 0x05
+#define ABX8XX_REG_YR 0x06
+#define ABX8XX_REG_WD 0x07
+
+#define ABX8XX_REG_AHTH 0x08
+#define ABX8XX_REG_ASC 0x09
+#define ABX8XX_REG_AMN 0x0a
+#define ABX8XX_REG_AHR 0x0b
+#define ABX8XX_REG_ADA 0x0c
+#define ABX8XX_REG_AMO 0x0d
+#define ABX8XX_REG_AWD 0x0e
+
+#define ABX8XX_REG_STATUS 0x0f
+#define ABX8XX_STATUS_AF BIT(2)
+#define ABX8XX_STATUS_BLF BIT(4)
+#define ABX8XX_STATUS_WDT BIT(6)
+
+#define ABX8XX_REG_CTRL1 0x10
+#define ABX8XX_CTRL_WRITE BIT(0)
+#define ABX8XX_CTRL_ARST BIT(2)
+#define ABX8XX_CTRL_12_24 BIT(6)
+
+#define ABX8XX_REG_CTRL2 0x11
+#define ABX8XX_CTRL2_RSVD BIT(5)
+
+#define ABX8XX_REG_IRQ 0x12
+#define ABX8XX_IRQ_AIE BIT(2)
+#define ABX8XX_IRQ_IM_1_4 (0x3 << 5)
+
+#define ABX8XX_REG_CD_TIMER_CTL 0x18
+
+#define ABX8XX_REG_OSC 0x1c
+#define ABX8XX_OSC_FOS BIT(3)
+#define ABX8XX_OSC_BOS BIT(4)
+#define ABX8XX_OSC_ACAL_512 BIT(5)
+#define ABX8XX_OSC_ACAL_1024 BIT(6)
+
+#define ABX8XX_OSC_OSEL BIT(7)
+
+#define ABX8XX_REG_OSS 0x1d
+#define ABX8XX_OSS_OF BIT(1)
+#define ABX8XX_OSS_OMODE BIT(4)
+
+#define ABX8XX_REG_WDT 0x1b
+#define ABX8XX_WDT_WDS BIT(7)
+#define ABX8XX_WDT_BMB_MASK 0x7c
+#define ABX8XX_WDT_BMB_SHIFT 2
+#define ABX8XX_WDT_MAX_TIME (ABX8XX_WDT_BMB_MASK >> ABX8XX_WDT_BMB_SHIFT)
+#define ABX8XX_WDT_WRB_MASK 0x03
+#define ABX8XX_WDT_WRB_1HZ 0x02
+
+#define ABX8XX_REG_CFG_KEY 0x1f
+#define ABX8XX_CFG_KEY_OSC 0xa1
+#define ABX8XX_CFG_KEY_MISC 0x9d
+
+#define ABX8XX_REG_ID0 0x28
+
+#define ABX8XX_REG_OUT_CTRL 0x30
+#define ABX8XX_OUT_CTRL_EXDS BIT(4)
+
+#define ABX8XX_REG_TRICKLE 0x20
+#define ABX8XX_TRICKLE_CHARGE_ENABLE 0xa0
+#define ABX8XX_TRICKLE_STANDARD_DIODE 0x8
+#define ABX8XX_TRICKLE_SCHOTTKY_DIODE 0x4
+
+static u8 trickle_resistors[] = {0, 3, 6, 11};
+
+enum abx80x_chip {AB0801, AB0803, AB0804, AB0805,
+ AB1801, AB1803, AB1804, AB1805, RV1805, ABX80X};
+
+struct abx80x_cap {
+ u16 pn;
+ bool has_tc;
+ bool has_wdog;
+};
+
+static struct abx80x_cap abx80x_caps[] = {
+ [AB0801] = {.pn = 0x0801},
+ [AB0803] = {.pn = 0x0803},
+ [AB0804] = {.pn = 0x0804, .has_tc = true, .has_wdog = true},
+ [AB0805] = {.pn = 0x0805, .has_tc = true, .has_wdog = true},
+ [AB1801] = {.pn = 0x1801},
+ [AB1803] = {.pn = 0x1803},
+ [AB1804] = {.pn = 0x1804, .has_tc = true, .has_wdog = true},
+ [AB1805] = {.pn = 0x1805, .has_tc = true, .has_wdog = true},
+ [RV1805] = {.pn = 0x1805, .has_tc = true, .has_wdog = true},
+ [ABX80X] = {.pn = 0}
+};
+
+static int abx80x_rtc_read8(struct udevice *dev, unsigned int reg)
+{
+ int ret = 0;
+ u8 buf;
+
+ if (reg > 0xff)
+ return -EINVAL;
+
+ ret = dm_i2c_read(dev, reg, &buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+
+ return buf;
+}
+
+static int abx80x_rtc_write8(struct udevice *dev, unsigned int reg, int val)
+{
+ u8 buf = (u8)val;
+
+ if (reg > 0xff)
+ return -EINVAL;
+
+ return dm_i2c_write(dev, reg, &buf, sizeof(buf));
+}
+
+static int abx80x_is_rc_mode(struct udevice *dev)
+{
+ int flags = 0;
+
+ flags = dm_i2c_reg_read(dev, ABX8XX_REG_OSS);
+ if (flags < 0) {
+ log_err("Failed to read autocalibration attribute\n");
+ return flags;
+ }
+
+ return (flags & ABX8XX_OSS_OMODE) ? 1 : 0;
+}
+
+static int abx80x_enable_trickle_charger(struct udevice *dev, u8 trickle_cfg)
+{
+ int err;
+
+ /*
+ * Write the configuration key register to enable access to the Trickle
+ * register
+ */
+ err = dm_i2c_reg_write(dev, ABX8XX_REG_CFG_KEY, ABX8XX_CFG_KEY_MISC);
+ if (err < 0) {
+ log_err("Unable to write configuration key\n");
+ return -EIO;
+ }
+
+ err = dm_i2c_reg_write(dev, ABX8XX_REG_TRICKLE,
+ ABX8XX_TRICKLE_CHARGE_ENABLE | trickle_cfg);
+ if (err < 0) {
+ log_err("Unable to write trickle register\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int abx80x_rtc_read_time(struct udevice *dev, struct rtc_time *tm)
+{
+ unsigned char buf[8];
+ int err, flags, rc_mode = 0;
+
+ /* Read the Oscillator Failure only in XT mode */
+ rc_mode = abx80x_is_rc_mode(dev);
+ if (rc_mode < 0)
+ return rc_mode;
+
+ if (!rc_mode) {
+ flags = dm_i2c_reg_read(dev, ABX8XX_REG_OSS);
+ if (flags < 0) {
+ log_err("Unable to read oscillator status.\n");
+ return flags;
+ }
+
+ if (flags & ABX8XX_OSS_OF)
+ log_debug("Oscillator fail, data is not accurate.\n");
+ }
+
+ err = dm_i2c_read(dev, ABX8XX_REG_HTH,
+ buf, sizeof(buf));
+ if (err < 0) {
+ log_err("Unable to read date\n");
+ return -EIO;
+ }
+
+ tm->tm_sec = bcd2bin(buf[ABX8XX_REG_SC] & 0x7F);
+ tm->tm_min = bcd2bin(buf[ABX8XX_REG_MN] & 0x7F);
+ tm->tm_hour = bcd2bin(buf[ABX8XX_REG_HR] & 0x3F);
+ tm->tm_wday = buf[ABX8XX_REG_WD] & 0x7;
+ tm->tm_mday = bcd2bin(buf[ABX8XX_REG_DA] & 0x3F);
+ tm->tm_mon = bcd2bin(buf[ABX8XX_REG_MO] & 0x1F);
+ tm->tm_year = bcd2bin(buf[ABX8XX_REG_YR]) + 2000;
+
+ return 0;
+}
+
+static int abx80x_rtc_set_time(struct udevice *dev, const struct rtc_time *tm)
+{
+ unsigned char buf[8];
+ int err, flags;
+
+ if (tm->tm_year < 2000)
+ return -EINVAL;
+
+ buf[ABX8XX_REG_HTH] = 0;
+ buf[ABX8XX_REG_SC] = bin2bcd(tm->tm_sec);
+ buf[ABX8XX_REG_MN] = bin2bcd(tm->tm_min);
+ buf[ABX8XX_REG_HR] = bin2bcd(tm->tm_hour);
+ buf[ABX8XX_REG_DA] = bin2bcd(tm->tm_mday);
+ buf[ABX8XX_REG_MO] = bin2bcd(tm->tm_mon);
+ buf[ABX8XX_REG_YR] = bin2bcd(tm->tm_year - 2000);
+ buf[ABX8XX_REG_WD] = tm->tm_wday;
+
+ err = dm_i2c_write(dev, ABX8XX_REG_HTH,
+ buf, sizeof(buf));
+ if (err < 0) {
+ log_err("Unable to write to date registers\n");
+ return -EIO;
+ }
+
+ /* Clear the OF bit of Oscillator Status Register */
+ flags = dm_i2c_reg_read(dev, ABX8XX_REG_OSS);
+ if (flags < 0) {
+ log_err("Unable to read oscillator status.\n");
+ return flags;
+ }
+
+ err = dm_i2c_reg_write(dev, ABX8XX_REG_OSS,
+ flags & ~ABX8XX_OSS_OF);
+ if (err < 0) {
+ log_err("Unable to write oscillator status register\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static int abx80x_rtc_set_autocalibration(struct udevice *dev,
+ int autocalibration)
+{
+ int retval, flags = 0;
+
+ if (autocalibration != 0 && autocalibration != 1024 &&
+ autocalibration != 512) {
+ log_err("autocalibration value outside permitted range\n");
+ return -EINVAL;
+ }
+
+ flags = dm_i2c_reg_read(dev, ABX8XX_REG_OSC);
+ if (flags < 0)
+ return flags;
+
+ if (autocalibration == 0) {
+ flags &= ~(ABX8XX_OSC_ACAL_512 | ABX8XX_OSC_ACAL_1024);
+ } else if (autocalibration == 1024) {
+ /* 1024 autocalibration is 0x10 */
+ flags |= ABX8XX_OSC_ACAL_1024;
+ flags &= ~(ABX8XX_OSC_ACAL_512);
+ } else {
+ /* 512 autocalibration is 0x11 */
+ flags |= (ABX8XX_OSC_ACAL_1024 | ABX8XX_OSC_ACAL_512);
+ }
+
+ /* Unlock write access to Oscillator Control Register */
+ retval = dm_i2c_reg_write(dev, ABX8XX_REG_CFG_KEY,
+ ABX8XX_CFG_KEY_OSC);
+ if (retval < 0) {
+ log_err("Failed to write CONFIG_KEY register\n");
+ return retval;
+ }
+
+ retval = dm_i2c_reg_write(dev, ABX8XX_REG_OSC, flags);
+
+ return retval;
+}
+
+static int abx80x_rtc_get_autocalibration(struct udevice *dev)
+{
+ int flags = 0, autocalibration;
+
+ flags = dm_i2c_reg_read(dev, ABX8XX_REG_OSC);
+ if (flags < 0)
+ return flags;
+
+ if (flags & ABX8XX_OSC_ACAL_512)
+ autocalibration = 512;
+ else if (flags & ABX8XX_OSC_ACAL_1024)
+ autocalibration = 1024;
+ else
+ autocalibration = 0;
+
+ return autocalibration;
+}
+
+static struct rtc_time default_tm = { 0, 0, 0, 1, 1, 2000, 6, 0, 0 };
+
+static int abx80x_rtc_reset(struct udevice *dev)
+{
+ int ret = 0;
+
+ int autocalib = abx80x_rtc_get_autocalibration(dev);
+
+ if (autocalib != 0)
+ abx80x_rtc_set_autocalibration(dev, 0);
+
+ ret = abx80x_rtc_set_time(dev, &default_tm);
+ if (ret != 0) {
+ log_err("cannot set time to default_tm. error %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static const struct rtc_ops abx80x_rtc_ops = {
+ .get = abx80x_rtc_read_time,
+ .set = abx80x_rtc_set_time,
+ .reset = abx80x_rtc_reset,
+ .read8 = abx80x_rtc_read8,
+ .write8 = abx80x_rtc_write8
+};
+
+static int abx80x_dt_trickle_cfg(struct udevice *dev)
+{
+ const char *diode;
+ int trickle_cfg = 0;
+ int i, ret = 0;
+ u32 tmp;
+
+ diode = ofnode_read_string(dev_ofnode(dev), "abracon,tc-diode");
+ if (!diode)
+ return ret;
+
+ if (!strcmp(diode, "standard")) {
+ trickle_cfg |= ABX8XX_TRICKLE_STANDARD_DIODE;
+ } else if (!strcmp(diode, "schottky")) {
+ trickle_cfg |= ABX8XX_TRICKLE_SCHOTTKY_DIODE;
+ } else {
+ log_err("Invalid tc-diode value: %s\n", diode);
+ return -EINVAL;
+ }
+
+ ret = ofnode_read_u32(dev_ofnode(dev), "abracon,tc-resistor", &tmp);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < sizeof(trickle_resistors); i++)
+ if (trickle_resistors[i] == tmp)
+ break;
+
+ if (i == sizeof(trickle_resistors)) {
+ log_err("Invalid tc-resistor value: %u\n", tmp);
+ return -EINVAL;
+ }
+
+ return (trickle_cfg | i);
+}
+
+static int abx80x_probe(struct udevice *dev)
+{
+ int i, data, err, trickle_cfg = -EINVAL;
+ unsigned char buf[7];
+ unsigned int part = dev->driver_data;
+ unsigned int partnumber;
+ unsigned int majrev, minrev;
+ unsigned int lot;
+ unsigned int wafer;
+ unsigned int uid;
+
+ err = dm_i2c_read(dev, ABX8XX_REG_ID0, buf, sizeof(buf));
+ if (err < 0) {
+ log_err("Unable to read partnumber\n");
+ return -EIO;
+ }
+
+ partnumber = (buf[0] << 8) | buf[1];
+ majrev = buf[2] >> 3;
+ minrev = buf[2] & 0x7;
+ lot = ((buf[4] & 0x80) << 2) | ((buf[6] & 0x80) << 1) | buf[3];
+ uid = ((buf[4] & 0x7f) << 8) | buf[5];
+ wafer = (buf[6] & 0x7c) >> 2;
+ log_debug("model %04x, revision %u.%u, lot %x, wafer %x, uid %x\n",
+ partnumber, majrev, minrev, lot, wafer, uid);
+
+ data = dm_i2c_reg_read(dev, ABX8XX_REG_CTRL1);
+ if (data < 0) {
+ log_err("Unable to read control register\n");
+ return -EIO;
+ }
+
+ err = dm_i2c_reg_write(dev, ABX8XX_REG_CTRL1,
+ ((data & ~(ABX8XX_CTRL_12_24 |
+ ABX8XX_CTRL_ARST)) |
+ ABX8XX_CTRL_WRITE));
+ if (err < 0) {
+ log_err("Unable to write control register\n");
+ return -EIO;
+ }
+
+ /* Configure RV1805 specifics */
+ if (part == RV1805) {
+ /*
+ * Avoid accidentally entering test mode. This can happen
+ * on the RV1805 in case the reserved bit 5 in control2
+ * register is set. RV-1805-C3 datasheet indicates that
+ * the bit should be cleared in section 11h - Control2.
+ */
+ data = dm_i2c_reg_read(dev, ABX8XX_REG_CTRL2);
+ if (data < 0) {
+ log_err("Unable to read control2 register\n");
+ return -EIO;
+ }
+
+ err = dm_i2c_reg_write(dev, ABX8XX_REG_CTRL2,
+ data & ~ABX8XX_CTRL2_RSVD);
+ if (err < 0) {
+ log_err("Unable to write control2 register\n");
+ return -EIO;
+ }
+
+ /*
+ * Avoid extra power leakage. The RV1805 uses smaller
+ * 10pin package and the EXTI input is not present.
+ * Disable it to avoid leakage.
+ */
+ data = dm_i2c_reg_read(dev, ABX8XX_REG_OUT_CTRL);
+ if (data < 0) {
+ log_err("Unable to read output control register\n");
+ return -EIO;
+ }
+
+ /*
+ * Write the configuration key register to enable access to
+ * the config2 register
+ */
+ err = dm_i2c_reg_write(dev, ABX8XX_REG_CFG_KEY,
+ ABX8XX_CFG_KEY_MISC);
+ if (err < 0) {
+ log_err("Unable to write configuration key\n");
+ return -EIO;
+ }
+
+ err = dm_i2c_reg_write(dev, ABX8XX_REG_OUT_CTRL,
+ data | ABX8XX_OUT_CTRL_EXDS);
+ if (err < 0) {
+ log_err("Unable to write output control register\n");
+ return -EIO;
+ }
+ }
+
+ /* part autodetection */
+ if (part == ABX80X) {
+ for (i = 0; abx80x_caps[i].pn; i++)
+ if (partnumber == abx80x_caps[i].pn)
+ break;
+ if (abx80x_caps[i].pn == 0) {
+ log_err("Unknown part: %04x\n", partnumber);
+ return -EINVAL;
+ }
+ part = i;
+ }
+
+ if (partnumber != abx80x_caps[part].pn) {
+ log_err("partnumber mismatch %04x != %04x\n",
+ partnumber, abx80x_caps[part].pn);
+ return -EINVAL;
+ }
+
+ if (abx80x_caps[part].has_tc)
+ trickle_cfg = abx80x_dt_trickle_cfg(dev);
+
+ if (trickle_cfg > 0) {
+ log_debug("Enabling trickle charger: %02x\n", trickle_cfg);
+ abx80x_enable_trickle_charger(dev, trickle_cfg);
+ }
+
+ err = dm_i2c_reg_write(dev, ABX8XX_REG_CD_TIMER_CTL, BIT(2));
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static const struct udevice_id abx80x_of_match[] = {
+ {
+ .compatible = "abracon,abx80x",
+ .data = ABX80X
+ },
+ {
+ .compatible = "abracon,ab0801",
+ .data = AB0801
+ },
+ {
+ .compatible = "abracon,ab0803",
+ .data = AB0803
+ },
+ {
+ .compatible = "abracon,ab0804",
+ .data = AB0804
+ },
+ {
+ .compatible = "abracon,ab0805",
+ .data = AB0805
+ },
+ {
+ .compatible = "abracon,ab1801",
+ .data = AB1801
+ },
+ {
+ .compatible = "abracon,ab1803",
+ .data = AB1803
+ },
+ {
+ .compatible = "abracon,ab1804",
+ .data = AB1804
+ },
+ {
+ .compatible = "abracon,ab1805",
+ .data = AB1805
+ },
+ {
+ .compatible = "microcrystal,rv1805",
+ .data = RV1805
+ },
+ { }
+};
+
+U_BOOT_DRIVER(abx80x_rtc) = {
+ .name = "rtc-abx80x",
+ .id = UCLASS_RTC,
+ .probe = abx80x_probe,
+ .of_match = abx80x_of_match,
+ .ops = &abx80x_rtc_ops,
+};
diff --git a/roms/u-boot/drivers/rtc/armada38x.c b/roms/u-boot/drivers/rtc/armada38x.c
new file mode 100644
index 000000000..2d264acf7
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/armada38x.c
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * RTC driver for the Armada 38x Marvell SoCs
+ *
+ * Copyright (C) 2021 Marek Behun <marek.behun@nic.cz>
+ *
+ * Based on Linux' driver by Gregory Clement and Marvell
+ */
+
+#include <asm/io.h>
+#include <dm.h>
+#include <linux/delay.h>
+#include <rtc.h>
+
+#define RTC_STATUS 0x0
+#define RTC_TIME 0xC
+#define RTC_CONF_TEST 0x1C
+
+/* Armada38x SoC registers */
+#define RTC_38X_BRIDGE_TIMING_CTL 0x0
+#define RTC_38X_PERIOD_OFFS 0
+#define RTC_38X_PERIOD_MASK (0x3FF << RTC_38X_PERIOD_OFFS)
+#define RTC_38X_READ_DELAY_OFFS 26
+#define RTC_38X_READ_DELAY_MASK (0x1F << RTC_38X_READ_DELAY_OFFS)
+
+#define SAMPLE_NR 100
+
+struct armada38x_rtc {
+ void __iomem *regs;
+ void __iomem *regs_soc;
+};
+
+/*
+ * According to Erratum RES-3124064 we have to do some configuration in MBUS.
+ * To read an RTC register we need to read it 100 times and return the most
+ * frequent value.
+ * To write an RTC register we need to write 2x zero into STATUS register,
+ * followed by the proper write. Linux adds an 5 us delay after this, so we do
+ * it here as well.
+ */
+static void update_38x_mbus_timing_params(struct armada38x_rtc *rtc)
+{
+ u32 reg;
+
+ reg = readl(rtc->regs_soc + RTC_38X_BRIDGE_TIMING_CTL);
+ reg &= ~RTC_38X_PERIOD_MASK;
+ reg |= 0x3FF << RTC_38X_PERIOD_OFFS; /* Maximum value */
+ reg &= ~RTC_38X_READ_DELAY_MASK;
+ reg |= 0x1F << RTC_38X_READ_DELAY_OFFS; /* Maximum value */
+ writel(reg, rtc->regs_soc + RTC_38X_BRIDGE_TIMING_CTL);
+}
+
+static void armada38x_rtc_write(u32 val, struct armada38x_rtc *rtc, u8 reg)
+{
+ writel(0, rtc->regs + RTC_STATUS);
+ writel(0, rtc->regs + RTC_STATUS);
+ writel(val, rtc->regs + reg);
+ udelay(5);
+}
+
+static u32 armada38x_rtc_read(struct armada38x_rtc *rtc, u8 reg)
+{
+ u8 counts[SAMPLE_NR], max_idx;
+ u32 samples[SAMPLE_NR], max;
+ int i, j, last;
+
+ for (i = 0, last = 0; i < SAMPLE_NR; ++i) {
+ u32 sample = readl(rtc->regs + reg);
+
+ /* find if this value was already read */
+ for (j = 0; j < last; ++j) {
+ if (samples[j] == sample)
+ break;
+ }
+
+ if (j < last) {
+ /* if yes, increment count */
+ ++counts[j];
+ } else {
+ /* if not, add */
+ samples[last] = sample;
+ counts[last] = 1;
+ ++last;
+ }
+ }
+
+ /* finally find the sample that was read the most */
+ max = 0;
+ max_idx = 0;
+
+ for (i = 0; i < last; ++i) {
+ if (counts[i] > max) {
+ max = counts[i];
+ max_idx = i;
+ }
+ }
+
+ return samples[max_idx];
+}
+
+static int armada38x_rtc_get(struct udevice *dev, struct rtc_time *tm)
+{
+ struct armada38x_rtc *rtc = dev_get_priv(dev);
+ u32 time;
+
+ time = armada38x_rtc_read(rtc, RTC_TIME);
+
+ rtc_to_tm(time, tm);
+
+ return 0;
+}
+
+static int armada38x_rtc_reset(struct udevice *dev)
+{
+ struct armada38x_rtc *rtc = dev_get_priv(dev);
+ u32 reg;
+
+ reg = armada38x_rtc_read(rtc, RTC_CONF_TEST);
+
+ if (reg & 0xff) {
+ armada38x_rtc_write(0, rtc, RTC_CONF_TEST);
+ mdelay(500);
+ armada38x_rtc_write(0, rtc, RTC_TIME);
+ armada38x_rtc_write(BIT(0) | BIT(1), 0, RTC_STATUS);
+ }
+
+ return 0;
+}
+
+static int armada38x_rtc_set(struct udevice *dev, const struct rtc_time *tm)
+{
+ struct armada38x_rtc *rtc = dev_get_priv(dev);
+ unsigned long time;
+
+ time = rtc_mktime(tm);
+
+ if (time > U32_MAX)
+ printf("%s: requested time to set will overflow\n", dev->name);
+
+ armada38x_rtc_reset(dev);
+ armada38x_rtc_write(time, rtc, RTC_TIME);
+
+ return 0;
+}
+
+static int armada38x_probe(struct udevice *dev)
+{
+ struct armada38x_rtc *rtc = dev_get_priv(dev);
+
+ rtc->regs = dev_remap_addr_name(dev, "rtc");
+ if (!rtc->regs)
+ goto err;
+
+ rtc->regs_soc = dev_remap_addr_name(dev, "rtc-soc");
+ if (!rtc->regs_soc)
+ goto err;
+
+ update_38x_mbus_timing_params(rtc);
+
+ return 0;
+err:
+ printf("%s: io address missing\n", dev->name);
+ return -ENODEV;
+}
+
+static const struct rtc_ops armada38x_rtc_ops = {
+ .get = armada38x_rtc_get,
+ .set = armada38x_rtc_set,
+ .reset = armada38x_rtc_reset,
+};
+
+static const struct udevice_id armada38x_rtc_ids[] = {
+ { .compatible = "marvell,armada-380-rtc", .data = 0 },
+ { }
+};
+
+U_BOOT_DRIVER(rtc_armada38x) = {
+ .name = "rtc-armada38x",
+ .id = UCLASS_RTC,
+ .of_match = armada38x_rtc_ids,
+ .probe = armada38x_probe,
+ .priv_auto = sizeof(struct armada38x_rtc),
+ .ops = &armada38x_rtc_ops,
+};
diff --git a/roms/u-boot/drivers/rtc/at91sam9_rtt.c b/roms/u-boot/drivers/rtc/at91sam9_rtt.c
new file mode 100644
index 000000000..6f92660ef
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/at91sam9_rtt.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2010
+ * Reinhard Meyer, reinhard.meyer@emk-elektronik.de
+ */
+
+/*
+ * Date & Time support for the internal Real-time Timer
+ * of AT91SAM9260 and compatibles.
+ * Compatible with the LinuX rtc driver workaround:
+ * The RTT cannot be written to, but only reset.
+ * The actual time is the sum of RTT and one of
+ * the four GPBR registers.
+ *
+ * The at91sam9260 has 4 GPBR (0-3).
+ * For their typical use see at91_gpbr.h !
+ *
+ * make sure u-boot and kernel use the same GPBR !
+ */
+
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+#include <asm/io.h>
+#include <linux/errno.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/at91_rtt.h>
+#include <asm/arch/at91_gpbr.h>
+
+int rtc_get (struct rtc_time *tmp)
+{
+ at91_rtt_t *rtt = (at91_rtt_t *) ATMEL_BASE_RTT;
+ at91_gpbr_t *gpbr = (at91_gpbr_t *) ATMEL_BASE_GPBR;
+ ulong tim;
+ ulong tim2;
+ ulong off;
+
+ do {
+ tim = readl(&rtt->vr);
+ tim2 = readl(&rtt->vr);
+ } while (tim!=tim2);
+ off = readl(&gpbr->reg[AT91_GPBR_INDEX_TIMEOFF]);
+ /* off==0 means time is invalid, but we ignore that */
+ rtc_to_tm(tim+off, tmp);
+ return 0;
+}
+
+int rtc_set (struct rtc_time *tmp)
+{
+ at91_rtt_t *rtt = (at91_rtt_t *) ATMEL_BASE_RTT;
+ at91_gpbr_t *gpbr = (at91_gpbr_t *) ATMEL_BASE_GPBR;
+ ulong tim;
+
+ tim = rtc_mktime(tmp);
+
+ /* clear alarm, set prescaler to 32768, clear counter */
+ writel(32768+AT91_RTT_RTTRST, &rtt->mr);
+ writel(~0, &rtt->ar);
+ writel(tim, &gpbr->reg[AT91_GPBR_INDEX_TIMEOFF]);
+ /* wait for counter clear to happen, takes less than a 1/32768th second */
+ while (readl(&rtt->vr) != 0)
+ ;
+ return 0;
+}
+
+void rtc_reset (void)
+{
+ at91_rtt_t *rtt = (at91_rtt_t *) ATMEL_BASE_RTT;
+ at91_gpbr_t *gpbr = (at91_gpbr_t *) ATMEL_BASE_GPBR;
+
+ /* clear alarm, set prescaler to 32768, clear counter */
+ writel(32768+AT91_RTT_RTTRST, &rtt->mr);
+ writel(~0, &rtt->ar);
+ writel(0, &gpbr->reg[AT91_GPBR_INDEX_TIMEOFF]);
+ /* wait for counter clear to happen, takes less than a 1/32768th second */
+ while (readl(&rtt->vr) != 0)
+ ;
+}
diff --git a/roms/u-boot/drivers/rtc/davinci.c b/roms/u-boot/drivers/rtc/davinci.c
new file mode 100644
index 000000000..c446e7a73
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/davinci.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2011 DENX Software Engineering GmbH
+ * Heiko Schocher <hs@denx.de>
+ */
+#include <common.h>
+#include <command.h>
+#include <log.h>
+#include <rtc.h>
+#include <asm/io.h>
+#include <asm/davinci_rtc.h>
+#include <linux/delay.h>
+
+int rtc_get(struct rtc_time *tmp)
+{
+ struct davinci_rtc *rtc = (struct davinci_rtc *)DAVINCI_RTC_BASE;
+ unsigned long sec, min, hour, mday, wday, mon_cent, year;
+ unsigned long status;
+
+ status = readl(&rtc->status);
+ if ((status & RTC_STATE_RUN) != RTC_STATE_RUN) {
+ printf("RTC doesn't run\n");
+ return -1;
+ }
+ if ((status & RTC_STATE_BUSY) == RTC_STATE_BUSY)
+ udelay(20);
+
+ sec = readl(&rtc->second);
+ min = readl(&rtc->minutes);
+ hour = readl(&rtc->hours);
+ mday = readl(&rtc->day);
+ wday = readl(&rtc->dotw);
+ mon_cent = readl(&rtc->month);
+ year = readl(&rtc->year);
+
+ debug("Get RTC year: %02lx mon/cent: %02lx mday: %02lx wday: %02lx "
+ "hr: %02lx min: %02lx sec: %02lx\n",
+ year, mon_cent, mday, wday,
+ hour, min, sec);
+
+ tmp->tm_sec = bcd2bin(sec & 0x7F);
+ tmp->tm_min = bcd2bin(min & 0x7F);
+ tmp->tm_hour = bcd2bin(hour & 0x3F);
+ tmp->tm_mday = bcd2bin(mday & 0x3F);
+ tmp->tm_mon = bcd2bin(mon_cent & 0x1F);
+ tmp->tm_year = bcd2bin(year) + 2000;
+ tmp->tm_wday = bcd2bin(wday & 0x07);
+ tmp->tm_yday = 0;
+ tmp->tm_isdst = 0;
+
+ debug("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ return 0;
+}
+
+int rtc_set(struct rtc_time *tmp)
+{
+ struct davinci_rtc *rtc = (struct davinci_rtc *)DAVINCI_RTC_BASE;
+
+ debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+ writel(bin2bcd(tmp->tm_year % 100), &rtc->year);
+ writel(bin2bcd(tmp->tm_mon), &rtc->month);
+
+ writel(bin2bcd(tmp->tm_wday), &rtc->dotw);
+ writel(bin2bcd(tmp->tm_mday), &rtc->day);
+ writel(bin2bcd(tmp->tm_hour), &rtc->hours);
+ writel(bin2bcd(tmp->tm_min), &rtc->minutes);
+ writel(bin2bcd(tmp->tm_sec), &rtc->second);
+ return 0;
+}
+
+void rtc_reset(void)
+{
+ struct davinci_rtc *rtc = (struct davinci_rtc *)DAVINCI_RTC_BASE;
+
+ /* run RTC counter */
+ writel(0x01, &rtc->ctrl);
+}
diff --git a/roms/u-boot/drivers/rtc/ds1302.c b/roms/u-boot/drivers/rtc/ds1302.c
new file mode 100644
index 000000000..189607c3e
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/ds1302.c
@@ -0,0 +1,329 @@
+/*
+ * ds1302.c - Support for the Dallas Semiconductor DS1302 Timekeeping Chip
+ *
+ * Rex G. Feany <rfeany@zumanetworks.com>
+ *
+ */
+
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+#include <linux/delay.h>
+
+/* GPP Pins */
+#define DATA 0x200
+#define SCLK 0x400
+#define RST 0x800
+
+/* Happy Fun Defines(tm) */
+#define RESET rtc_go_low(RST), rtc_go_low(SCLK)
+#define N_RESET rtc_go_high(RST), rtc_go_low(SCLK)
+
+#define CLOCK_HIGH rtc_go_high(SCLK)
+#define CLOCK_LOW rtc_go_low(SCLK)
+
+#define DATA_HIGH rtc_go_high(DATA)
+#define DATA_LOW rtc_go_low(DATA)
+#define DATA_READ (GTREGREAD(GPP_VALUE) & DATA)
+
+#undef RTC_DEBUG
+
+#ifdef RTC_DEBUG
+# define DPRINTF(x,args...) printf("ds1302: " x , ##args)
+static inline void DUMP(const char *ptr, int num)
+{
+ while (num--) printf("%x ", *ptr++);
+ printf("]\n");
+}
+#else
+# define DPRINTF(x,args...)
+# define DUMP(ptr, num)
+#endif
+
+/* time data format for DS1302 */
+struct ds1302_st
+{
+ unsigned char CH:1; /* clock halt 1=stop 0=start */
+ unsigned char sec10:3;
+ unsigned char sec:4;
+
+ unsigned char zero0:1;
+ unsigned char min10:3;
+ unsigned char min:4;
+
+ unsigned char fmt:1; /* 1=12 hour 0=24 hour */
+ unsigned char zero1:1;
+ unsigned char hr10:2; /* 10 (0-2) or am/pm (am/pm, 0-1) */
+ unsigned char hr:4;
+
+ unsigned char zero2:2;
+ unsigned char date10:2;
+ unsigned char date:4;
+
+ unsigned char zero3:3;
+ unsigned char month10:1;
+ unsigned char month:4;
+
+ unsigned char zero4:5;
+ unsigned char day:3; /* day of week */
+
+ unsigned char year10:4;
+ unsigned char year:4;
+
+ unsigned char WP:1; /* write protect 1=protect 0=unprot */
+ unsigned char zero5:7;
+};
+
+static int ds1302_initted=0;
+
+/* Pin control */
+static inline void
+rtc_go_high(unsigned int mask)
+{
+ unsigned int f = GTREGREAD(GPP_VALUE) | mask;
+
+ GT_REG_WRITE(GPP_VALUE, f);
+}
+
+static inline void
+rtc_go_low(unsigned int mask)
+{
+ unsigned int f = GTREGREAD(GPP_VALUE) & ~mask;
+
+ GT_REG_WRITE(GPP_VALUE, f);
+}
+
+static inline void
+rtc_go_input(unsigned int mask)
+{
+ unsigned int f = GTREGREAD(GPP_IO_CONTROL) & ~mask;
+
+ GT_REG_WRITE(GPP_IO_CONTROL, f);
+}
+
+static inline void
+rtc_go_output(unsigned int mask)
+{
+ unsigned int f = GTREGREAD(GPP_IO_CONTROL) | mask;
+
+ GT_REG_WRITE(GPP_IO_CONTROL, f);
+}
+
+/* Access data in RTC */
+
+static void
+write_byte(unsigned char b)
+{
+ int i;
+ unsigned char mask=1;
+
+ for(i=0;i<8;i++) {
+ CLOCK_LOW; /* Lower clock */
+ (b&mask)?DATA_HIGH:DATA_LOW; /* set data */
+ udelay(1);
+ CLOCK_HIGH; /* latch data with rising clock */
+ udelay(1);
+ mask=mask<<1;
+ }
+}
+
+static unsigned char
+read_byte(void)
+{
+ int i;
+ unsigned char mask=1;
+ unsigned char b=0;
+
+ for(i=0;i<8;i++) {
+ CLOCK_LOW;
+ udelay(1);
+ if (DATA_READ) b|=mask; /* if this bit is high, set in b */
+ CLOCK_HIGH; /* clock out next bit */
+ udelay(1);
+ mask=mask<<1;
+ }
+ return b;
+}
+
+static void
+read_ser_drv(unsigned char addr, unsigned char *buf, int count)
+{
+ int i;
+#ifdef RTC_DEBUG
+ char *foo = buf;
+#endif
+
+ DPRINTF("READ 0x%x bytes @ 0x%x [ ", count, addr);
+
+ addr|=1; /* READ */
+ N_RESET;
+ udelay(4);
+ write_byte(addr);
+ rtc_go_input(DATA); /* Put gpp pin into input mode */
+ udelay(1);
+ for(i=0;i<count;i++) *(buf++)=read_byte();
+ RESET;
+ rtc_go_output(DATA);/* Reset gpp for output */
+ udelay(4);
+
+ DUMP(foo, count);
+}
+
+static void
+write_ser_drv(unsigned char addr, unsigned char *buf, int count)
+{
+ int i;
+
+ DPRINTF("WRITE 0x%x bytes @ 0x%x [ ", count, addr);
+ DUMP(buf, count);
+
+ addr&=~1; /* WRITE */
+ N_RESET;
+ udelay(4);
+ write_byte(addr);
+ for(i=0;i<count;i++) write_byte(*(buf++));
+ RESET;
+ udelay(4);
+
+}
+
+void
+rtc_init(void)
+{
+ struct ds1302_st bbclk;
+ unsigned char b;
+ int mod;
+
+ DPRINTF("init\n");
+
+ rtc_go_output(DATA|SCLK|RST);
+
+ /* disable write protect */
+ b = 0;
+ write_ser_drv(0x8e,&b,1);
+
+ /* enable trickle */
+ b = 0xa5; /* 1010.0101 */
+ write_ser_drv(0x90,&b,1);
+
+ /* read burst */
+ read_ser_drv(0xbe, (unsigned char *)&bbclk, 8);
+
+ /* Sanity checks */
+ mod = 0;
+ if (bbclk.CH) {
+ printf("ds1302: Clock was halted, starting clock\n");
+ bbclk.CH=0;
+ mod=1;
+ }
+
+ if (bbclk.fmt) {
+ printf("ds1302: Clock was in 12 hour mode, fixing\n");
+ bbclk.fmt=0;
+ mod=1;
+ }
+
+ if (bbclk.year>9) {
+ printf("ds1302: Year was corrupted, fixing\n");
+ bbclk.year10=100/10; /* 2000 - why not? ;) */
+ bbclk.year=0;
+ mod=1;
+ }
+
+ /* Write out the changes if needed */
+ if (mod) {
+ /* enable write protect */
+ bbclk.WP = 1;
+ write_ser_drv(0xbe,(unsigned char *)&bbclk,8);
+ } else {
+ /* Else just turn write protect on */
+ b = 0x80;
+ write_ser_drv(0x8e,&b,1);
+ }
+ DPRINTF("init done\n");
+
+ ds1302_initted=1;
+}
+
+void
+rtc_reset(void)
+{
+ if(!ds1302_initted) rtc_init();
+ /* TODO */
+}
+
+int
+rtc_get(struct rtc_time *tmp)
+{
+ int rel = 0;
+ struct ds1302_st bbclk;
+
+ if(!ds1302_initted) rtc_init();
+
+ read_ser_drv(0xbe,(unsigned char *)&bbclk, 8); /* read burst */
+
+ if (bbclk.CH) {
+ printf("ds1302: rtc_get: Clock was halted, clock probably "
+ "corrupt\n");
+ rel = -1;
+ }
+
+ tmp->tm_sec=10*bbclk.sec10+bbclk.sec;
+ tmp->tm_min=10*bbclk.min10+bbclk.min;
+ tmp->tm_hour=10*bbclk.hr10+bbclk.hr;
+ tmp->tm_wday=bbclk.day;
+ tmp->tm_mday=10*bbclk.date10+bbclk.date;
+ tmp->tm_mon=10*bbclk.month10+bbclk.month;
+ tmp->tm_year=10*bbclk.year10+bbclk.year + 1900;
+
+ tmp->tm_yday = 0;
+ tmp->tm_isdst= 0;
+
+ DPRINTF("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec );
+
+ return rel;
+}
+
+int rtc_set(struct rtc_time *tmp)
+{
+ struct ds1302_st bbclk;
+ unsigned char b=0;
+
+ if(!ds1302_initted) rtc_init();
+
+ DPRINTF("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ memset(&bbclk,0,sizeof(bbclk));
+ bbclk.CH=0; /* dont halt */
+ bbclk.WP=1; /* write protect when we're done */
+
+ bbclk.sec10=tmp->tm_sec/10;
+ bbclk.sec=tmp->tm_sec%10;
+
+ bbclk.min10=tmp->tm_min/10;
+ bbclk.min=tmp->tm_min%10;
+
+ bbclk.hr10=tmp->tm_hour/10;
+ bbclk.hr=tmp->tm_hour%10;
+
+ bbclk.day=tmp->tm_wday;
+
+ bbclk.date10=tmp->tm_mday/10;
+ bbclk.date=tmp->tm_mday%10;
+
+ bbclk.month10=tmp->tm_mon/10;
+ bbclk.month=tmp->tm_mon%10;
+
+ tmp->tm_year -= 1900;
+ bbclk.year10=tmp->tm_year/10;
+ bbclk.year=tmp->tm_year%10;
+
+ write_ser_drv(0x8e,&b,1); /* disable write protect */
+ write_ser_drv(0xbe,(unsigned char *)&bbclk, 8); /* write burst */
+
+ return 0;
+}
diff --git a/roms/u-boot/drivers/rtc/ds1306.c b/roms/u-boot/drivers/rtc/ds1306.c
new file mode 100644
index 000000000..36d615812
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/ds1306.c
@@ -0,0 +1,438 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2002 SIXNET, dge@sixnetio.com.
+ *
+ * (C) Copyright 2004, Li-Pro.Net <www.li-pro.net>
+ * Stephan Linz <linz@li-pro.net>
+ */
+
+/*
+ * Date & Time support for DS1306 RTC using SPI:
+ *
+ * - SXNI855T: it uses its own soft SPI here in this file
+ * - all other: use the external spi_xfer() function
+ * (see include/spi.h)
+ */
+
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+#include <spi.h>
+#include <linux/delay.h>
+
+#define RTC_SECONDS 0x00
+#define RTC_MINUTES 0x01
+#define RTC_HOURS 0x02
+#define RTC_DAY_OF_WEEK 0x03
+#define RTC_DATE_OF_MONTH 0x04
+#define RTC_MONTH 0x05
+#define RTC_YEAR 0x06
+
+#define RTC_SECONDS_ALARM0 0x07
+#define RTC_MINUTES_ALARM0 0x08
+#define RTC_HOURS_ALARM0 0x09
+#define RTC_DAY_OF_WEEK_ALARM0 0x0a
+
+#define RTC_SECONDS_ALARM1 0x0b
+#define RTC_MINUTES_ALARM1 0x0c
+#define RTC_HOURS_ALARM1 0x0d
+#define RTC_DAY_OF_WEEK_ALARM1 0x0e
+
+#define RTC_CONTROL 0x0f
+#define RTC_STATUS 0x10
+#define RTC_TRICKLE_CHARGER 0x11
+
+#define RTC_USER_RAM_BASE 0x20
+
+/* ************************************************************************* */
+#ifdef CONFIG_SXNI855T /* !!! SHOULD BE CHANGED TO NEW CODE !!! */
+
+static void soft_spi_send (unsigned char n);
+static unsigned char soft_spi_read (void);
+static void init_spi (void);
+
+/*-----------------------------------------------------------------------
+ * Definitions
+ */
+
+#define PB_SPISCK 0x00000002 /* PB 30 */
+#define PB_SPIMOSI 0x00000004 /* PB 29 */
+#define PB_SPIMISO 0x00000008 /* PB 28 */
+#define PB_SPI_CE 0x00010000 /* PB 15 */
+
+/* ------------------------------------------------------------------------- */
+
+/* read clock time from DS1306 and return it in *tmp */
+int rtc_get (struct rtc_time *tmp)
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ unsigned char spi_byte; /* Data Byte */
+
+ init_spi (); /* set port B for software SPI */
+
+ /* Now we can enable the DS1306 RTC */
+ immap->im_cpm.cp_pbdat |= PB_SPI_CE;
+ udelay(10);
+
+ /* Shift out the address (0) of the time in the Clock Chip */
+ soft_spi_send (0);
+
+ /* Put the clock readings into the rtc_time structure */
+ tmp->tm_sec = bcd2bin (soft_spi_read ()); /* Read seconds */
+ tmp->tm_min = bcd2bin (soft_spi_read ()); /* Read minutes */
+
+ /* Hours are trickier */
+ spi_byte = soft_spi_read (); /* Read Hours into temporary value */
+ if (spi_byte & 0x40) {
+ /* 12 hour mode bit is set (time is in 1-12 format) */
+ if (spi_byte & 0x20) {
+ /* since PM we add 11 to get 0-23 for hours */
+ tmp->tm_hour = (bcd2bin (spi_byte & 0x1F)) + 11;
+ } else {
+ /* since AM we subtract 1 to get 0-23 for hours */
+ tmp->tm_hour = (bcd2bin (spi_byte & 0x1F)) - 1;
+ }
+ } else {
+ /* Otherwise, 0-23 hour format */
+ tmp->tm_hour = (bcd2bin (spi_byte & 0x3F));
+ }
+
+ soft_spi_read (); /* Read and discard Day of week */
+ tmp->tm_mday = bcd2bin (soft_spi_read ()); /* Read Day of the Month */
+ tmp->tm_mon = bcd2bin (soft_spi_read ()); /* Read Month */
+
+ /* Read Year and convert to this century */
+ tmp->tm_year = bcd2bin (soft_spi_read ()) + 2000;
+
+ /* Now we can disable the DS1306 RTC */
+ immap->im_cpm.cp_pbdat &= ~PB_SPI_CE; /* Disable DS1306 Chip */
+ udelay(10);
+
+ rtc_calc_weekday(tmp); /* Determine the day of week */
+
+ debug ("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* set clock time in DS1306 RTC and in MPC8xx RTC */
+int rtc_set (struct rtc_time *tmp)
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+ init_spi (); /* set port B for software SPI */
+
+ /* Now we can enable the DS1306 RTC */
+ immap->im_cpm.cp_pbdat |= PB_SPI_CE; /* Enable DS1306 Chip */
+ udelay(10);
+
+ /* First disable write protect in the clock chip control register */
+ soft_spi_send (0x8F); /* send address of the control register */
+ soft_spi_send (0x00); /* send control register contents */
+
+ /* Now disable the DS1306 to terminate the write */
+ immap->im_cpm.cp_pbdat &= ~PB_SPI_CE;
+ udelay(10);
+
+ /* Now enable the DS1306 to initiate a new write */
+ immap->im_cpm.cp_pbdat |= PB_SPI_CE;
+ udelay(10);
+
+ /* Next, send the address of the clock time write registers */
+ soft_spi_send (0x80); /* send address of the first time register */
+
+ /* Use Burst Mode to send all of the time data to the clock */
+ bin2bcd (tmp->tm_sec);
+ soft_spi_send (bin2bcd (tmp->tm_sec)); /* Send Seconds */
+ soft_spi_send (bin2bcd (tmp->tm_min)); /* Send Minutes */
+ soft_spi_send (bin2bcd (tmp->tm_hour)); /* Send Hour */
+ soft_spi_send (bin2bcd (tmp->tm_wday)); /* Send Day of the Week */
+ soft_spi_send (bin2bcd (tmp->tm_mday)); /* Send Day of Month */
+ soft_spi_send (bin2bcd (tmp->tm_mon)); /* Send Month */
+ soft_spi_send (bin2bcd (tmp->tm_year - 2000)); /* Send Year */
+
+ /* Now we can disable the Clock chip to terminate the burst write */
+ immap->im_cpm.cp_pbdat &= ~PB_SPI_CE; /* Disable DS1306 Chip */
+ udelay(10);
+
+ /* Now we can enable the Clock chip to initiate a new write */
+ immap->im_cpm.cp_pbdat |= PB_SPI_CE; /* Enable DS1306 Chip */
+ udelay(10);
+
+ /* First we Enable write protect in the clock chip control register */
+ soft_spi_send (0x8F); /* send address of the control register */
+ soft_spi_send (0x40); /* send out Control Register contents */
+
+ /* Now disable the DS1306 */
+ immap->im_cpm.cp_pbdat &= ~PB_SPI_CE; /* Disable DS1306 Chip */
+ udelay(10);
+
+ /* Set standard MPC8xx clock to the same time so Linux will
+ * see the time even if it doesn't have a DS1306 clock driver.
+ * This helps with experimenting with standard kernels.
+ */
+ {
+ ulong tim;
+
+ tim = rtc_mktime(tmp);
+
+ immap->im_sitk.sitk_rtck = KAPWR_KEY;
+ immap->im_sit.sit_rtc = tim;
+ }
+
+ debug ("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* Initialize Port B for software SPI */
+static void init_spi (void)
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+ /* Force output pins to begin at logic 0 */
+ immap->im_cpm.cp_pbdat &= ~(PB_SPI_CE | PB_SPIMOSI | PB_SPISCK);
+
+ /* Set these 3 signals as outputs */
+ immap->im_cpm.cp_pbdir |= (PB_SPIMOSI | PB_SPI_CE | PB_SPISCK);
+
+ immap->im_cpm.cp_pbdir &= ~PB_SPIMISO; /* Make MISO pin an input */
+ udelay(10);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* NOTE: soft_spi_send() assumes that the I/O lines are configured already */
+static void soft_spi_send (unsigned char n)
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ unsigned char bitpos; /* bit position to receive */
+ unsigned char i; /* Loop Control */
+
+ /* bit position to send, start with most significant bit */
+ bitpos = 0x80;
+
+ /* Send 8 bits to software SPI */
+ for (i = 0; i < 8; i++) { /* Loop for 8 bits */
+ immap->im_cpm.cp_pbdat |= PB_SPISCK; /* Raise SCK */
+
+ if (n & bitpos)
+ immap->im_cpm.cp_pbdat |= PB_SPIMOSI; /* Set MOSI to 1 */
+ else
+ immap->im_cpm.cp_pbdat &= ~PB_SPIMOSI; /* Set MOSI to 0 */
+ udelay(10);
+
+ immap->im_cpm.cp_pbdat &= ~PB_SPISCK; /* Lower SCK */
+ udelay(10);
+
+ bitpos >>= 1; /* Shift for next bit position */
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* NOTE: soft_spi_read() assumes that the I/O lines are configured already */
+static unsigned char soft_spi_read (void)
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+ unsigned char spi_byte = 0; /* Return value, assume success */
+ unsigned char bitpos; /* bit position to receive */
+ unsigned char i; /* Loop Control */
+
+ /* bit position to receive, start with most significant bit */
+ bitpos = 0x80;
+
+ /* Read 8 bits here */
+ for (i = 0; i < 8; i++) { /* Do 8 bits in loop */
+ immap->im_cpm.cp_pbdat |= PB_SPISCK; /* Raise SCK */
+ udelay(10);
+ if (immap->im_cpm.cp_pbdat & PB_SPIMISO) /* Get a bit of data */
+ spi_byte |= bitpos; /* Set data accordingly */
+ immap->im_cpm.cp_pbdat &= ~PB_SPISCK; /* Lower SCK */
+ udelay(10);
+ bitpos >>= 1; /* Shift for next bit position */
+ }
+
+ return spi_byte; /* Return the byte read */
+}
+
+/* ------------------------------------------------------------------------- */
+
+void rtc_reset (void)
+{
+ return; /* nothing to do */
+}
+
+#else /* not CONFIG_SXNI855T */
+/* ************************************************************************* */
+
+static unsigned char rtc_read (unsigned char reg);
+static void rtc_write (unsigned char reg, unsigned char val);
+
+static struct spi_slave *slave;
+
+/* read clock time from DS1306 and return it in *tmp */
+int rtc_get (struct rtc_time *tmp)
+{
+ unsigned char sec, min, hour, mday, wday, mon, year;
+
+ /*
+ * Assuming Vcc = 2.0V (lowest speed)
+ *
+ * REVISIT: If we add an rtc_init() function we can do this
+ * step just once.
+ */
+ if (!slave) {
+ slave = spi_setup_slave(0, CONFIG_SYS_SPI_RTC_DEVID, 600000,
+ SPI_MODE_3 | SPI_CS_HIGH);
+ if (!slave)
+ return;
+ }
+
+ if (spi_claim_bus(slave))
+ return;
+
+ sec = rtc_read (RTC_SECONDS);
+ min = rtc_read (RTC_MINUTES);
+ hour = rtc_read (RTC_HOURS);
+ mday = rtc_read (RTC_DATE_OF_MONTH);
+ wday = rtc_read (RTC_DAY_OF_WEEK);
+ mon = rtc_read (RTC_MONTH);
+ year = rtc_read (RTC_YEAR);
+
+ spi_release_bus(slave);
+
+ debug ("Get RTC year: %02x mon: %02x mday: %02x wday: %02x "
+ "hr: %02x min: %02x sec: %02x\n",
+ year, mon, mday, wday, hour, min, sec);
+ debug ("Alarms[0]: wday: %02x hour: %02x min: %02x sec: %02x\n",
+ rtc_read (RTC_DAY_OF_WEEK_ALARM0),
+ rtc_read (RTC_HOURS_ALARM0),
+ rtc_read (RTC_MINUTES_ALARM0), rtc_read (RTC_SECONDS_ALARM0));
+ debug ("Alarms[1]: wday: %02x hour: %02x min: %02x sec: %02x\n",
+ rtc_read (RTC_DAY_OF_WEEK_ALARM1),
+ rtc_read (RTC_HOURS_ALARM1),
+ rtc_read (RTC_MINUTES_ALARM1), rtc_read (RTC_SECONDS_ALARM1));
+
+ tmp->tm_sec = bcd2bin (sec & 0x7F); /* convert Seconds */
+ tmp->tm_min = bcd2bin (min & 0x7F); /* convert Minutes */
+
+ /* convert Hours */
+ tmp->tm_hour = (hour & 0x40)
+ ? ((hour & 0x20) /* 12 hour mode */
+ ? bcd2bin (hour & 0x1F) + 11 /* PM */
+ : bcd2bin (hour & 0x1F) - 1 /* AM */
+ )
+ : bcd2bin (hour & 0x3F); /* 24 hour mode */
+
+ tmp->tm_mday = bcd2bin (mday & 0x3F); /* convert Day of the Month */
+ tmp->tm_mon = bcd2bin (mon & 0x1F); /* convert Month */
+ tmp->tm_year = bcd2bin (year) + 2000; /* convert Year */
+ tmp->tm_wday = bcd2bin (wday & 0x07) - 1; /* convert Day of the Week */
+ tmp->tm_yday = 0;
+ tmp->tm_isdst = 0;
+
+ debug ("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* set clock time from *tmp in DS1306 RTC */
+int rtc_set (struct rtc_time *tmp)
+{
+ /* Assuming Vcc = 2.0V (lowest speed) */
+ if (!slave) {
+ slave = spi_setup_slave(0, CONFIG_SYS_SPI_RTC_DEVID, 600000,
+ SPI_MODE_3 | SPI_CS_HIGH);
+ if (!slave)
+ return;
+ }
+
+ if (spi_claim_bus(slave))
+ return;
+
+ debug ("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ rtc_write (RTC_SECONDS, bin2bcd (tmp->tm_sec));
+ rtc_write (RTC_MINUTES, bin2bcd (tmp->tm_min));
+ rtc_write (RTC_HOURS, bin2bcd (tmp->tm_hour));
+ rtc_write (RTC_DAY_OF_WEEK, bin2bcd (tmp->tm_wday + 1));
+ rtc_write (RTC_DATE_OF_MONTH, bin2bcd (tmp->tm_mday));
+ rtc_write (RTC_MONTH, bin2bcd (tmp->tm_mon));
+ rtc_write (RTC_YEAR, bin2bcd (tmp->tm_year - 2000));
+
+ spi_release_bus(slave);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* reset the DS1306 */
+void rtc_reset (void)
+{
+ /* Assuming Vcc = 2.0V (lowest speed) */
+ if (!slave) {
+ slave = spi_setup_slave(0, CONFIG_SYS_SPI_RTC_DEVID, 600000,
+ SPI_MODE_3 | SPI_CS_HIGH);
+ if (!slave)
+ return;
+ }
+
+ if (spi_claim_bus(slave))
+ return;
+
+ /* clear the control register */
+ rtc_write (RTC_CONTROL, 0x00); /* 1st step: reset WP */
+ rtc_write (RTC_CONTROL, 0x00); /* 2nd step: reset 1Hz, AIE1, AIE0 */
+
+ /* reset all alarms */
+ rtc_write (RTC_SECONDS_ALARM0, 0x00);
+ rtc_write (RTC_SECONDS_ALARM1, 0x00);
+ rtc_write (RTC_MINUTES_ALARM0, 0x00);
+ rtc_write (RTC_MINUTES_ALARM1, 0x00);
+ rtc_write (RTC_HOURS_ALARM0, 0x00);
+ rtc_write (RTC_HOURS_ALARM1, 0x00);
+ rtc_write (RTC_DAY_OF_WEEK_ALARM0, 0x00);
+ rtc_write (RTC_DAY_OF_WEEK_ALARM1, 0x00);
+
+ spi_release_bus(slave);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static unsigned char rtc_read (unsigned char reg)
+{
+ int ret;
+
+ ret = spi_w8r8(slave, reg);
+ return ret < 0 ? 0 : ret;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void rtc_write (unsigned char reg, unsigned char val)
+{
+ unsigned char dout[2]; /* SPI Output Data Bytes */
+ unsigned char din[2]; /* SPI Input Data Bytes */
+
+ dout[0] = 0x80 | reg;
+ dout[1] = val;
+
+ spi_xfer (slave, 16, dout, din, SPI_XFER_BEGIN | SPI_XFER_END);
+}
+
+#endif /* end of code exclusion (see #ifdef CONFIG_SXNI855T above) */
diff --git a/roms/u-boot/drivers/rtc/ds1307.c b/roms/u-boot/drivers/rtc/ds1307.c
new file mode 100644
index 000000000..2015ce9bb
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/ds1307.c
@@ -0,0 +1,362 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2001, 2002, 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * Keith Outwater, keith_outwater@mvis.com`
+ * Steven Scholz, steven.scholz@imc-berlin.de
+ */
+
+/*
+ * Date & Time support (no alarms) for Dallas Semiconductor (now Maxim)
+ * DS1307 and DS1338/9 Real Time Clock (RTC).
+ *
+ * based on ds1337.c
+ */
+
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <log.h>
+#include <rtc.h>
+#include <i2c.h>
+
+enum ds_type {
+ ds_1307,
+ ds_1337,
+ ds_1339,
+ ds_1340,
+ m41t11,
+ mcp794xx,
+};
+
+/*
+ * RTC register addresses
+ */
+#define RTC_SEC_REG_ADDR 0x00
+#define RTC_MIN_REG_ADDR 0x01
+#define RTC_HR_REG_ADDR 0x02
+#define RTC_DAY_REG_ADDR 0x03
+#define RTC_DATE_REG_ADDR 0x04
+#define RTC_MON_REG_ADDR 0x05
+#define RTC_YR_REG_ADDR 0x06
+#define RTC_CTL_REG_ADDR 0x07
+
+#define RTC_SEC_BIT_CH 0x80 /* Clock Halt (in Register 0) */
+
+#define RTC_CTL_BIT_RS0 0x01 /* Rate select 0 */
+#define RTC_CTL_BIT_RS1 0x02 /* Rate select 1 */
+#define RTC_CTL_BIT_SQWE 0x10 /* Square Wave Enable */
+#define RTC_CTL_BIT_OUT 0x80 /* Output Control */
+
+/* MCP7941X-specific bits */
+#define MCP7941X_BIT_ST 0x80
+#define MCP7941X_BIT_VBATEN 0x08
+
+#ifndef CONFIG_DM_RTC
+
+/*---------------------------------------------------------------------*/
+#undef DEBUG_RTC
+
+#ifdef DEBUG_RTC
+#define DEBUGR(fmt, args...) printf(fmt, ##args)
+#else
+#define DEBUGR(fmt, args...)
+#endif
+/*---------------------------------------------------------------------*/
+
+#ifndef CONFIG_SYS_I2C_RTC_ADDR
+# define CONFIG_SYS_I2C_RTC_ADDR 0x68
+#endif
+
+#if defined(CONFIG_RTC_DS1307) && (CONFIG_SYS_I2C_SPEED > 100000)
+# error The DS1307 is specified only up to 100kHz!
+#endif
+
+static uchar rtc_read (uchar reg);
+static void rtc_write (uchar reg, uchar val);
+
+/*
+ * Get the current time from the RTC
+ */
+int rtc_get (struct rtc_time *tmp)
+{
+ int rel = 0;
+ uchar sec, min, hour, mday, wday, mon, year;
+
+#ifdef CONFIG_RTC_MCP79411
+read_rtc:
+#endif
+ sec = rtc_read (RTC_SEC_REG_ADDR);
+ min = rtc_read (RTC_MIN_REG_ADDR);
+ hour = rtc_read (RTC_HR_REG_ADDR);
+ wday = rtc_read (RTC_DAY_REG_ADDR);
+ mday = rtc_read (RTC_DATE_REG_ADDR);
+ mon = rtc_read (RTC_MON_REG_ADDR);
+ year = rtc_read (RTC_YR_REG_ADDR);
+
+ DEBUGR ("Get RTC year: %02x mon: %02x mday: %02x wday: %02x "
+ "hr: %02x min: %02x sec: %02x\n",
+ year, mon, mday, wday, hour, min, sec);
+
+#ifdef CONFIG_RTC_DS1307
+ if (sec & RTC_SEC_BIT_CH) {
+ printf ("### Warning: RTC oscillator has stopped\n");
+ /* clear the CH flag */
+ rtc_write (RTC_SEC_REG_ADDR,
+ rtc_read (RTC_SEC_REG_ADDR) & ~RTC_SEC_BIT_CH);
+ rel = -1;
+ }
+#endif
+
+#ifdef CONFIG_RTC_MCP79411
+ /* make sure that the backup battery is enabled */
+ if (!(wday & MCP7941X_BIT_VBATEN)) {
+ rtc_write(RTC_DAY_REG_ADDR,
+ wday | MCP7941X_BIT_VBATEN);
+ }
+
+ /* clock halted? turn it on, so clock can tick. */
+ if (!(sec & MCP7941X_BIT_ST)) {
+ rtc_write(RTC_SEC_REG_ADDR, MCP7941X_BIT_ST);
+ printf("Started RTC\n");
+ goto read_rtc;
+ }
+#endif
+
+
+ tmp->tm_sec = bcd2bin (sec & 0x7F);
+ tmp->tm_min = bcd2bin (min & 0x7F);
+ tmp->tm_hour = bcd2bin (hour & 0x3F);
+ tmp->tm_mday = bcd2bin (mday & 0x3F);
+ tmp->tm_mon = bcd2bin (mon & 0x1F);
+ tmp->tm_year = bcd2bin (year) + ( bcd2bin (year) >= 70 ? 1900 : 2000);
+ tmp->tm_wday = bcd2bin ((wday - 1) & 0x07);
+ tmp->tm_yday = 0;
+ tmp->tm_isdst= 0;
+
+ DEBUGR ("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ return rel;
+}
+
+
+/*
+ * Set the RTC
+ */
+int rtc_set (struct rtc_time *tmp)
+{
+ DEBUGR ("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ if (tmp->tm_year < 1970 || tmp->tm_year > 2069)
+ printf("WARNING: year should be between 1970 and 2069!\n");
+
+ rtc_write (RTC_YR_REG_ADDR, bin2bcd (tmp->tm_year % 100));
+ rtc_write (RTC_MON_REG_ADDR, bin2bcd (tmp->tm_mon));
+#ifdef CONFIG_RTC_MCP79411
+ rtc_write (RTC_DAY_REG_ADDR,
+ bin2bcd (tmp->tm_wday + 1) | MCP7941X_BIT_VBATEN);
+#else
+ rtc_write (RTC_DAY_REG_ADDR, bin2bcd (tmp->tm_wday + 1));
+#endif
+ rtc_write (RTC_DATE_REG_ADDR, bin2bcd (tmp->tm_mday));
+ rtc_write (RTC_HR_REG_ADDR, bin2bcd (tmp->tm_hour));
+ rtc_write (RTC_MIN_REG_ADDR, bin2bcd (tmp->tm_min));
+#ifdef CONFIG_RTC_MCP79411
+ rtc_write (RTC_SEC_REG_ADDR, bin2bcd (tmp->tm_sec) | MCP7941X_BIT_ST);
+#else
+ rtc_write (RTC_SEC_REG_ADDR, bin2bcd (tmp->tm_sec));
+#endif
+
+ return 0;
+}
+
+
+/*
+ * Reset the RTC. We setting the date back to 1970-01-01.
+ * We also enable the oscillator output on the SQW/OUT pin and program
+ * it for 32,768 Hz output. Note that according to the datasheet, turning
+ * on the square wave output increases the current drain on the backup
+ * battery to something between 480nA and 800nA.
+ */
+void rtc_reset (void)
+{
+ rtc_write (RTC_SEC_REG_ADDR, 0x00); /* clearing Clock Halt */
+ rtc_write (RTC_CTL_REG_ADDR, RTC_CTL_BIT_SQWE | RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS0);
+}
+
+
+/*
+ * Helper functions
+ */
+
+static
+uchar rtc_read (uchar reg)
+{
+ return (i2c_reg_read (CONFIG_SYS_I2C_RTC_ADDR, reg));
+}
+
+
+static void rtc_write (uchar reg, uchar val)
+{
+ i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val);
+}
+
+#endif /* !CONFIG_DM_RTC */
+
+#ifdef CONFIG_DM_RTC
+static int ds1307_rtc_set(struct udevice *dev, const struct rtc_time *tm)
+{
+ int ret;
+ uchar buf[7];
+ enum ds_type type = dev_get_driver_data(dev);
+
+ debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ if (tm->tm_year < 1970 || tm->tm_year > 2069)
+ printf("WARNING: year should be between 1970 and 2069!\n");
+
+ buf[RTC_YR_REG_ADDR] = bin2bcd(tm->tm_year % 100);
+ buf[RTC_MON_REG_ADDR] = bin2bcd(tm->tm_mon);
+ buf[RTC_DAY_REG_ADDR] = bin2bcd(tm->tm_wday + 1);
+ buf[RTC_DATE_REG_ADDR] = bin2bcd(tm->tm_mday);
+ buf[RTC_HR_REG_ADDR] = bin2bcd(tm->tm_hour);
+ buf[RTC_MIN_REG_ADDR] = bin2bcd(tm->tm_min);
+ buf[RTC_SEC_REG_ADDR] = bin2bcd(tm->tm_sec);
+
+ if (type == mcp794xx) {
+ buf[RTC_DAY_REG_ADDR] |= MCP7941X_BIT_VBATEN;
+ buf[RTC_SEC_REG_ADDR] |= MCP7941X_BIT_ST;
+ }
+
+ ret = dm_i2c_write(dev, 0, buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int ds1307_rtc_get(struct udevice *dev, struct rtc_time *tm)
+{
+ int ret;
+ uchar buf[7];
+ enum ds_type type = dev_get_driver_data(dev);
+
+read_rtc:
+ ret = dm_i2c_read(dev, 0, buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+
+ if (type == ds_1307) {
+ if (buf[RTC_SEC_REG_ADDR] & RTC_SEC_BIT_CH) {
+ printf("### Warning: RTC oscillator has stopped\n");
+ /* clear the CH flag */
+ buf[RTC_SEC_REG_ADDR] &= ~RTC_SEC_BIT_CH;
+ dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR,
+ buf[RTC_SEC_REG_ADDR]);
+ return -1;
+ }
+ }
+
+ if (type == m41t11) {
+ /* clock halted? turn it on, so clock can tick. */
+ if (buf[RTC_SEC_REG_ADDR] & RTC_SEC_BIT_CH) {
+ buf[RTC_SEC_REG_ADDR] &= ~RTC_SEC_BIT_CH;
+ dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR,
+ MCP7941X_BIT_ST);
+ dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR,
+ buf[RTC_SEC_REG_ADDR]);
+ goto read_rtc;
+ }
+ }
+
+ if (type == mcp794xx) {
+ /* make sure that the backup battery is enabled */
+ if (!(buf[RTC_DAY_REG_ADDR] & MCP7941X_BIT_VBATEN)) {
+ dm_i2c_reg_write(dev, RTC_DAY_REG_ADDR,
+ buf[RTC_DAY_REG_ADDR] |
+ MCP7941X_BIT_VBATEN);
+ }
+
+ /* clock halted? turn it on, so clock can tick. */
+ if (!(buf[RTC_SEC_REG_ADDR] & MCP7941X_BIT_ST)) {
+ dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR,
+ MCP7941X_BIT_ST);
+ printf("Started RTC\n");
+ goto read_rtc;
+ }
+ }
+
+ tm->tm_sec = bcd2bin(buf[RTC_SEC_REG_ADDR] & 0x7F);
+ tm->tm_min = bcd2bin(buf[RTC_MIN_REG_ADDR] & 0x7F);
+ tm->tm_hour = bcd2bin(buf[RTC_HR_REG_ADDR] & 0x3F);
+ tm->tm_mday = bcd2bin(buf[RTC_DATE_REG_ADDR] & 0x3F);
+ tm->tm_mon = bcd2bin(buf[RTC_MON_REG_ADDR] & 0x1F);
+ tm->tm_year = bcd2bin(buf[RTC_YR_REG_ADDR]) +
+ (bcd2bin(buf[RTC_YR_REG_ADDR]) >= 70 ?
+ 1900 : 2000);
+ tm->tm_wday = bcd2bin((buf[RTC_DAY_REG_ADDR] - 1) & 0x07);
+ tm->tm_yday = 0;
+ tm->tm_isdst = 0;
+
+ debug("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ return 0;
+}
+
+static int ds1307_rtc_reset(struct udevice *dev)
+{
+ int ret;
+
+ /* clear Clock Halt */
+ ret = dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR, 0x00);
+ if (ret < 0)
+ return ret;
+ ret = dm_i2c_reg_write(dev, RTC_CTL_REG_ADDR,
+ RTC_CTL_BIT_SQWE | RTC_CTL_BIT_RS1 |
+ RTC_CTL_BIT_RS0);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int ds1307_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 ds1307_rtc_ops = {
+ .get = ds1307_rtc_get,
+ .set = ds1307_rtc_set,
+ .reset = ds1307_rtc_reset,
+};
+
+static const struct udevice_id ds1307_rtc_ids[] = {
+ { .compatible = "dallas,ds1307", .data = ds_1307 },
+ { .compatible = "dallas,ds1337", .data = ds_1337 },
+ { .compatible = "dallas,ds1339", .data = ds_1339 },
+ { .compatible = "dallas,ds1340", .data = ds_1340 },
+ { .compatible = "microchip,mcp7941x", .data = mcp794xx },
+ { .compatible = "st,m41t11", .data = m41t11 },
+ { }
+};
+
+U_BOOT_DRIVER(rtc_ds1307) = {
+ .name = "rtc-ds1307",
+ .id = UCLASS_RTC,
+ .probe = ds1307_probe,
+ .of_match = ds1307_rtc_ids,
+ .ops = &ds1307_rtc_ops,
+};
+#endif /* CONFIG_DM_RTC */
diff --git a/roms/u-boot/drivers/rtc/ds1337.c b/roms/u-boot/drivers/rtc/ds1337.c
new file mode 100644
index 000000000..4986c96f8
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/ds1337.c
@@ -0,0 +1,319 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2001-2008
+ * Copyright 2020 NXP
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * Keith Outwater, keith_outwater@mvis.com`
+ */
+
+/*
+ * Date & Time support (no alarms) for Dallas Semiconductor (now Maxim)
+ * DS1337 Real Time Clock (RTC).
+ */
+
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <log.h>
+#include <rtc.h>
+#include <i2c.h>
+
+/*
+ * RTC register addresses
+ */
+#if defined CONFIG_RTC_DS1337
+#define RTC_SEC_REG_ADDR 0x0
+#define RTC_MIN_REG_ADDR 0x1
+#define RTC_HR_REG_ADDR 0x2
+#define RTC_DAY_REG_ADDR 0x3
+#define RTC_DATE_REG_ADDR 0x4
+#define RTC_MON_REG_ADDR 0x5
+#define RTC_YR_REG_ADDR 0x6
+#define RTC_CTL_REG_ADDR 0x0e
+#define RTC_STAT_REG_ADDR 0x0f
+#define RTC_TC_REG_ADDR 0x10
+#elif defined CONFIG_RTC_DS1388
+#define RTC_SEC_REG_ADDR 0x1
+#define RTC_MIN_REG_ADDR 0x2
+#define RTC_HR_REG_ADDR 0x3
+#define RTC_DAY_REG_ADDR 0x4
+#define RTC_DATE_REG_ADDR 0x5
+#define RTC_MON_REG_ADDR 0x6
+#define RTC_YR_REG_ADDR 0x7
+#define RTC_CTL_REG_ADDR 0x0c
+#define RTC_STAT_REG_ADDR 0x0b
+#define RTC_TC_REG_ADDR 0x0a
+#endif
+
+/*
+ * RTC control register bits
+ */
+#define RTC_CTL_BIT_A1IE 0x1 /* Alarm 1 interrupt enable */
+#define RTC_CTL_BIT_A2IE 0x2 /* Alarm 2 interrupt enable */
+#define RTC_CTL_BIT_INTCN 0x4 /* Interrupt control */
+#define RTC_CTL_BIT_RS1 0x8 /* Rate select 1 */
+#define RTC_CTL_BIT_RS2 0x10 /* Rate select 2 */
+#define RTC_CTL_BIT_DOSC 0x80 /* Disable Oscillator */
+
+/*
+ * RTC status register bits
+ */
+#define RTC_STAT_BIT_A1F 0x1 /* Alarm 1 flag */
+#define RTC_STAT_BIT_A2F 0x2 /* Alarm 2 flag */
+#define RTC_STAT_BIT_OSF 0x80 /* Oscillator stop flag */
+
+
+#if !CONFIG_IS_ENABLED(DM_RTC)
+static uchar rtc_read (uchar reg);
+static void rtc_write (uchar reg, uchar val);
+
+/*
+ * Get the current time from the RTC
+ */
+int rtc_get (struct rtc_time *tmp)
+{
+ int rel = 0;
+ uchar sec, min, hour, mday, wday, mon_cent, year, control, status;
+
+ control = rtc_read (RTC_CTL_REG_ADDR);
+ status = rtc_read (RTC_STAT_REG_ADDR);
+ sec = rtc_read (RTC_SEC_REG_ADDR);
+ min = rtc_read (RTC_MIN_REG_ADDR);
+ hour = rtc_read (RTC_HR_REG_ADDR);
+ wday = rtc_read (RTC_DAY_REG_ADDR);
+ mday = rtc_read (RTC_DATE_REG_ADDR);
+ mon_cent = rtc_read (RTC_MON_REG_ADDR);
+ year = rtc_read (RTC_YR_REG_ADDR);
+
+ /* No century bit, assume year 2000 */
+#ifdef CONFIG_RTC_DS1388
+ mon_cent |= 0x80;
+#endif
+
+ debug("Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x "
+ "hr: %02x min: %02x sec: %02x control: %02x status: %02x\n",
+ year, mon_cent, mday, wday, hour, min, sec, control, status);
+
+ if (status & RTC_STAT_BIT_OSF) {
+ printf ("### Warning: RTC oscillator has stopped\n");
+ /* clear the OSF flag */
+ rtc_write (RTC_STAT_REG_ADDR,
+ rtc_read (RTC_STAT_REG_ADDR) & ~RTC_STAT_BIT_OSF);
+ rel = -1;
+ }
+
+ tmp->tm_sec = bcd2bin (sec & 0x7F);
+ tmp->tm_min = bcd2bin (min & 0x7F);
+ tmp->tm_hour = bcd2bin (hour & 0x3F);
+ tmp->tm_mday = bcd2bin (mday & 0x3F);
+ tmp->tm_mon = bcd2bin (mon_cent & 0x1F);
+ tmp->tm_year = bcd2bin (year) + ((mon_cent & 0x80) ? 2000 : 1900);
+ tmp->tm_wday = bcd2bin ((wday - 1) & 0x07);
+ tmp->tm_yday = 0;
+ tmp->tm_isdst= 0;
+
+ debug("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ return rel;
+}
+
+
+/*
+ * Set the RTC
+ */
+int rtc_set (struct rtc_time *tmp)
+{
+ uchar century;
+
+ debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ rtc_write (RTC_YR_REG_ADDR, bin2bcd (tmp->tm_year % 100));
+
+ century = (tmp->tm_year >= 2000) ? 0x80 : 0;
+ rtc_write (RTC_MON_REG_ADDR, bin2bcd (tmp->tm_mon) | century);
+
+ rtc_write (RTC_DAY_REG_ADDR, bin2bcd (tmp->tm_wday + 1));
+ rtc_write (RTC_DATE_REG_ADDR, bin2bcd (tmp->tm_mday));
+ rtc_write (RTC_HR_REG_ADDR, bin2bcd (tmp->tm_hour));
+ rtc_write (RTC_MIN_REG_ADDR, bin2bcd (tmp->tm_min));
+ rtc_write (RTC_SEC_REG_ADDR, bin2bcd (tmp->tm_sec));
+
+ return 0;
+}
+
+
+/*
+ * Reset the RTC. We also enable the oscillator output on the
+ * SQW/INTB* pin and program it for 32,768 Hz output. Note that
+ * according to the datasheet, turning on the square wave output
+ * increases the current drain on the backup battery from about
+ * 600 nA to 2uA. Define CONFIG_RTC_DS1337_NOOSC if you wish to turn
+ * off the OSC output.
+ */
+
+#ifdef CONFIG_RTC_DS1337_NOOSC
+ #define RTC_DS1337_RESET_VAL \
+ (RTC_CTL_BIT_INTCN | RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS2)
+#else
+ #define RTC_DS1337_RESET_VAL (RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS2)
+#endif
+void rtc_reset (void)
+{
+#ifdef CONFIG_RTC_DS1337
+ rtc_write (RTC_CTL_REG_ADDR, RTC_DS1337_RESET_VAL);
+#elif defined CONFIG_RTC_DS1388
+ rtc_write(RTC_CTL_REG_ADDR, 0x0); /* hw default */
+#endif
+#ifdef CONFIG_RTC_DS1339_TCR_VAL
+ rtc_write (RTC_TC_REG_ADDR, CONFIG_RTC_DS1339_TCR_VAL);
+#endif
+#ifdef CONFIG_RTC_DS1388_TCR_VAL
+ rtc_write(RTC_TC_REG_ADDR, CONFIG_RTC_DS1388_TCR_VAL);
+#endif
+}
+
+
+/*
+ * Helper functions
+ */
+
+static
+uchar rtc_read (uchar reg)
+{
+ return (i2c_reg_read (CONFIG_SYS_I2C_RTC_ADDR, reg));
+}
+
+
+static void rtc_write (uchar reg, uchar val)
+{
+ i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val);
+}
+#else
+static uchar rtc_read(struct udevice *dev, uchar reg)
+{
+ return dm_i2c_reg_read(dev, reg);
+}
+
+static void rtc_write(struct udevice *dev, uchar reg, uchar val)
+{
+ dm_i2c_reg_write(dev, reg, val);
+}
+
+static int ds1337_rtc_get(struct udevice *dev, struct rtc_time *tmp)
+{
+ int rel = 0;
+ uchar sec, min, hour, mday, wday, mon_cent, year, control, status;
+
+ control = rtc_read(dev, RTC_CTL_REG_ADDR);
+ status = rtc_read(dev, RTC_STAT_REG_ADDR);
+ sec = rtc_read(dev, RTC_SEC_REG_ADDR);
+ min = rtc_read(dev, RTC_MIN_REG_ADDR);
+ hour = rtc_read(dev, RTC_HR_REG_ADDR);
+ wday = rtc_read(dev, RTC_DAY_REG_ADDR);
+ mday = rtc_read(dev, RTC_DATE_REG_ADDR);
+ mon_cent = rtc_read(dev, RTC_MON_REG_ADDR);
+ year = rtc_read(dev, RTC_YR_REG_ADDR);
+
+ /* No century bit, assume year 2000 */
+#ifdef CONFIG_RTC_DS1388
+ mon_cent |= 0x80;
+#endif
+
+ debug("Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x\n",
+ year, mon_cent, mday, wday);
+ debug("hr: %02x min: %02x sec: %02x control: %02x status: %02x\n",
+ hour, min, sec, control, status);
+
+ if (status & RTC_STAT_BIT_OSF) {
+ printf("### Warning: RTC oscillator has stopped\n");
+ /* clear the OSF flag */
+ rtc_write(dev, RTC_STAT_REG_ADDR,
+ rtc_read(dev, RTC_STAT_REG_ADDR) & ~RTC_STAT_BIT_OSF);
+ rel = -1;
+ }
+
+ tmp->tm_sec = bcd2bin(sec & 0x7F);
+ tmp->tm_min = bcd2bin(min & 0x7F);
+ tmp->tm_hour = bcd2bin(hour & 0x3F);
+ tmp->tm_mday = bcd2bin(mday & 0x3F);
+ tmp->tm_mon = bcd2bin(mon_cent & 0x1F);
+ tmp->tm_year = bcd2bin(year) + ((mon_cent & 0x80) ? 2000 : 1900);
+ tmp->tm_wday = bcd2bin((wday - 1) & 0x07);
+ tmp->tm_yday = 0;
+ tmp->tm_isdst = 0;
+
+ debug("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ return rel;
+}
+
+static int ds1337_rtc_set(struct udevice *dev, const struct rtc_time *tmp)
+{
+ uchar century;
+
+ debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ rtc_write(dev, RTC_YR_REG_ADDR, bin2bcd(tmp->tm_year % 100));
+
+ century = (tmp->tm_year >= 2000) ? 0x80 : 0;
+ rtc_write(dev, RTC_MON_REG_ADDR, bin2bcd(tmp->tm_mon) | century);
+
+ rtc_write(dev, RTC_DAY_REG_ADDR, bin2bcd(tmp->tm_wday + 1));
+ rtc_write(dev, RTC_DATE_REG_ADDR, bin2bcd(tmp->tm_mday));
+ rtc_write(dev, RTC_HR_REG_ADDR, bin2bcd(tmp->tm_hour));
+ rtc_write(dev, RTC_MIN_REG_ADDR, bin2bcd(tmp->tm_min));
+ rtc_write(dev, RTC_SEC_REG_ADDR, bin2bcd(tmp->tm_sec));
+
+ return 0;
+}
+
+#ifdef CONFIG_RTC_DS1337_NOOSC
+ #define RTC_DS1337_RESET_VAL \
+ (RTC_CTL_BIT_INTCN | RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS2)
+#else
+ #define RTC_DS1337_RESET_VAL (RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS2)
+#endif
+static int ds1337_rtc_reset(struct udevice *dev)
+{
+#ifdef CONFIG_RTC_DS1337
+ rtc_write(dev, RTC_CTL_REG_ADDR, RTC_DS1337_RESET_VAL);
+#elif defined CONFIG_RTC_DS1388
+ rtc_write(dev, RTC_CTL_REG_ADDR, 0x0); /* hw default */
+#endif
+#ifdef CONFIG_RTC_DS1339_TCR_VAL
+ rtc_write(dev, RTC_TC_REG_ADDR, CONFIG_RTC_DS1339_TCR_VAL);
+#endif
+#ifdef CONFIG_RTC_DS1388_TCR_VAL
+ rtc_write(dev, RTC_TC_REG_ADDR, CONFIG_RTC_DS1388_TCR_VAL);
+#endif
+ return 0;
+}
+
+static const struct rtc_ops ds1337_rtc_ops = {
+ .get = ds1337_rtc_get,
+ .set = ds1337_rtc_set,
+ .reset = ds1337_rtc_reset,
+};
+
+static const struct udevice_id ds1337_rtc_ids[] = {
+ { .compatible = "ds1337" },
+ { .compatible = "ds1338" },
+ { .compatible = "ds1338" },
+ { }
+};
+
+U_BOOT_DRIVER(rtc_ds1337) = {
+ .name = "rtc-ds1337",
+ .id = UCLASS_RTC,
+ .of_match = ds1337_rtc_ids,
+ .ops = &ds1337_rtc_ops,
+};
+#endif
diff --git a/roms/u-boot/drivers/rtc/ds1374.c b/roms/u-boot/drivers/rtc/ds1374.c
new file mode 100644
index 000000000..9f2647d70
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/ds1374.c
@@ -0,0 +1,214 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2001, 2002, 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * Keith Outwater, keith_outwater@mvis.com`
+ * Steven Scholz, steven.scholz@imc-berlin.de
+ */
+
+/*
+ * Date & Time support (no alarms) for Dallas Semiconductor (now Maxim)
+ * DS1374 Real Time Clock (RTC).
+ *
+ * based on ds1337.c
+ */
+
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+#include <i2c.h>
+
+/*---------------------------------------------------------------------*/
+#undef DEBUG_RTC
+#define DEBUG_RTC
+
+#ifdef DEBUG_RTC
+#define DEBUGR(fmt,args...) printf(fmt ,##args)
+#else
+#define DEBUGR(fmt,args...)
+#endif
+/*---------------------------------------------------------------------*/
+
+#ifndef CONFIG_SYS_I2C_RTC_ADDR
+# define CONFIG_SYS_I2C_RTC_ADDR 0x68
+#endif
+
+#if defined(CONFIG_RTC_DS1374) && (CONFIG_SYS_I2C_SPEED > 400000)
+# error The DS1374 is specified up to 400kHz in fast mode!
+#endif
+
+/*
+ * RTC register addresses
+ */
+#define RTC_TOD_CNT_BYTE0_ADDR 0x00 /* TimeOfDay */
+#define RTC_TOD_CNT_BYTE1_ADDR 0x01
+#define RTC_TOD_CNT_BYTE2_ADDR 0x02
+#define RTC_TOD_CNT_BYTE3_ADDR 0x03
+
+#define RTC_WD_ALM_CNT_BYTE0_ADDR 0x04
+#define RTC_WD_ALM_CNT_BYTE1_ADDR 0x05
+#define RTC_WD_ALM_CNT_BYTE2_ADDR 0x06
+
+#define RTC_CTL_ADDR 0x07 /* RTC-CoNTrol-register */
+#define RTC_SR_ADDR 0x08 /* RTC-StatusRegister */
+#define RTC_TCS_DS_ADDR 0x09 /* RTC-TrickleChargeSelect DiodeSelect-register */
+
+#define RTC_CTL_BIT_AIE (1<<0) /* Bit 0 - Alarm Interrupt enable */
+#define RTC_CTL_BIT_RS1 (1<<1) /* Bit 1/2 - Rate Select square wave output */
+#define RTC_CTL_BIT_RS2 (1<<2) /* Bit 2/2 - Rate Select square wave output */
+#define RTC_CTL_BIT_WDSTR (1<<3) /* Bit 3 - Watchdog Reset Steering */
+#define RTC_CTL_BIT_BBSQW (1<<4) /* Bit 4 - Battery-Backed Square-Wave */
+#define RTC_CTL_BIT_WD_ALM (1<<5) /* Bit 5 - Watchdog/Alarm Counter Select */
+#define RTC_CTL_BIT_WACE (1<<6) /* Bit 6 - Watchdog/Alarm Counter Enable WACE*/
+#define RTC_CTL_BIT_EN_OSC (1<<7) /* Bit 7 - Enable Oscilator */
+
+#define RTC_SR_BIT_AF 0x01 /* Bit 0 = Alarm Flag */
+#define RTC_SR_BIT_OSF 0x80 /* Bit 7 - Osc Stop Flag */
+
+const char RtcTodAddr[] = {
+ RTC_TOD_CNT_BYTE0_ADDR,
+ RTC_TOD_CNT_BYTE1_ADDR,
+ RTC_TOD_CNT_BYTE2_ADDR,
+ RTC_TOD_CNT_BYTE3_ADDR
+};
+
+static uchar rtc_read (uchar reg);
+static void rtc_write(uchar reg, uchar val, bool set);
+static void rtc_write_raw (uchar reg, uchar val);
+
+/*
+ * Get the current time from the RTC
+ */
+int rtc_get (struct rtc_time *tm){
+ int rel = 0;
+ unsigned long time1, time2;
+ unsigned int limit;
+ unsigned char tmp;
+ unsigned int i;
+
+ /*
+ * Since the reads are being performed one byte at a time,
+ * there is a chance that a carry will occur during the read.
+ * To detect this, 2 reads are performed and compared.
+ */
+ limit = 10;
+ do {
+ i = 4;
+ time1 = 0;
+ while (i--) {
+ tmp = rtc_read(RtcTodAddr[i]);
+ time1 = (time1 << 8) | (tmp & 0xff);
+ }
+
+ i = 4;
+ time2 = 0;
+ while (i--) {
+ tmp = rtc_read(RtcTodAddr[i]);
+ time2 = (time2 << 8) | (tmp & 0xff);
+ }
+ } while ((time1 != time2) && limit--);
+
+ if (time1 != time2) {
+ printf("can't get consistent time from rtc chip\n");
+ rel = -1;
+ }
+
+ DEBUGR ("Get RTC s since 1.1.1970: %ld\n", time1);
+
+ rtc_to_tm(time1, tm); /* To Gregorian Date */
+
+ if (rtc_read(RTC_SR_ADDR) & RTC_SR_BIT_OSF) {
+ printf ("### Warning: RTC oscillator has stopped\n");
+ rel = -1;
+ }
+
+ DEBUGR ("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ return rel;
+}
+
+/*
+ * Set the RTC
+ */
+int rtc_set (struct rtc_time *tmp){
+
+ unsigned long time;
+ unsigned i;
+
+ DEBUGR ("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ if (tmp->tm_year < 1970 || tmp->tm_year > 2069)
+ printf("WARNING: year should be between 1970 and 2069!\n");
+
+ time = rtc_mktime(tmp);
+
+ DEBUGR ("Set RTC s since 1.1.1970: %ld (0x%02lx)\n", time, time);
+
+ /* write to RTC_TOD_CNT_BYTEn_ADDR */
+ for (i = 0; i <= 3; i++) {
+ rtc_write_raw(RtcTodAddr[i], (unsigned char)(time & 0xff));
+ time = time >> 8;
+ }
+
+ /* Start clock */
+ rtc_write(RTC_CTL_ADDR, RTC_CTL_BIT_EN_OSC, false);
+
+ return 0;
+}
+
+/*
+ * Reset the RTC. We setting the date back to 1970-01-01.
+ * We also enable the oscillator output on the SQW/OUT pin and program
+ * it for 32,768 Hz output. Note that according to the datasheet, turning
+ * on the square wave output increases the current drain on the backup
+ * battery to something between 480nA and 800nA.
+ */
+void rtc_reset (void){
+
+ /* clear status flags */
+ rtc_write(RTC_SR_ADDR, (RTC_SR_BIT_AF|RTC_SR_BIT_OSF), false); /* clearing OSF and AF */
+
+ /* Initialise DS1374 oriented to MPC8349E-ADS */
+ rtc_write (RTC_CTL_ADDR, (RTC_CTL_BIT_EN_OSC
+ |RTC_CTL_BIT_WACE
+ |RTC_CTL_BIT_AIE), false);/* start osc, disable WACE, clear AIE
+ - set to 0 */
+ rtc_write (RTC_CTL_ADDR, (RTC_CTL_BIT_WD_ALM
+ |RTC_CTL_BIT_WDSTR
+ |RTC_CTL_BIT_RS1
+ |RTC_CTL_BIT_RS2
+ |RTC_CTL_BIT_BBSQW), true);/* disable WD/ALM, WDSTR set to INT-pin,
+ set BBSQW and SQW to 32k
+ - set to 1 */
+ rtc_write(RTC_WD_ALM_CNT_BYTE2_ADDR, 0xAC, true);
+ rtc_write(RTC_WD_ALM_CNT_BYTE1_ADDR, 0xDE, true);
+ rtc_write(RTC_WD_ALM_CNT_BYTE2_ADDR, 0xAD, true);
+}
+
+/*
+ * Helper functions
+ */
+static uchar rtc_read (uchar reg)
+{
+ return (i2c_reg_read (CONFIG_SYS_I2C_RTC_ADDR, reg));
+}
+
+static void rtc_write(uchar reg, uchar val, bool set)
+{
+ if (set == true) {
+ val |= i2c_reg_read (CONFIG_SYS_I2C_RTC_ADDR, reg);
+ i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val);
+ } else {
+ val = i2c_reg_read (CONFIG_SYS_I2C_RTC_ADDR, reg) & ~val;
+ i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val);
+ }
+}
+
+static void rtc_write_raw (uchar reg, uchar val)
+{
+ i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val);
+}
diff --git a/roms/u-boot/drivers/rtc/ds1556.c b/roms/u-boot/drivers/rtc/ds1556.c
new file mode 100644
index 000000000..687b32937
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/ds1556.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2002
+ * ARIO Data Networks, Inc. dchiu@ariodata.com
+ *
+ * modified for DS1556:
+ * Frank Panno <fpanno@delphintech.com>, Delphin Technology AG
+ *
+ * Based on MontaVista DS1743 code and U-Boot mc146818 code
+ */
+
+/*
+ * Date & Time support for the DS1556 RTC
+ */
+
+/*#define RTC_DEBUG */
+
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+
+#if defined(CONFIG_CMD_DATE)
+
+static uchar rtc_read( unsigned int addr );
+static void rtc_write( unsigned int addr, uchar val);
+
+#define RTC_BASE ( CONFIG_SYS_NVRAM_SIZE + CONFIG_SYS_NVRAM_BASE_ADDR )
+
+#define RTC_YEAR ( RTC_BASE + 0xf )
+#define RTC_MONTH ( RTC_BASE + 0xe )
+#define RTC_DAY_OF_MONTH ( RTC_BASE + 0xd )
+#define RTC_DAY_OF_WEEK ( RTC_BASE + 0xc )
+#define RTC_HOURS ( RTC_BASE + 0xb )
+#define RTC_MINUTES ( RTC_BASE + 0xa )
+#define RTC_SECONDS ( RTC_BASE + 0x9 )
+#define RTC_CENTURY ( RTC_BASE + 0x8 )
+
+#define RTC_CONTROLA RTC_CENTURY
+#define RTC_CONTROLB RTC_SECONDS
+#define RTC_CONTROLC RTC_BASE
+
+#define RTC_CA_WRITE 0x80
+#define RTC_CA_READ 0x40
+
+#define RTC_CB_OSC_DISABLE 0x80
+
+#define RTC_CC_BATTERY_FLAG 0x10
+#define RTC_CC_FREQ_TEST 0x40
+
+/* ------------------------------------------------------------------------- */
+
+int rtc_get( struct rtc_time *tmp )
+{
+ uchar sec, min, hour;
+ uchar mday, wday, mon, year;
+
+ int century;
+
+ uchar reg_a;
+
+ reg_a = rtc_read( RTC_CONTROLA );
+ /* lock clock registers for read */
+ rtc_write( RTC_CONTROLA, ( reg_a | RTC_CA_READ ));
+
+ sec = rtc_read( RTC_SECONDS );
+ min = rtc_read( RTC_MINUTES );
+ hour = rtc_read( RTC_HOURS );
+ mday = rtc_read( RTC_DAY_OF_MONTH );
+ wday = rtc_read( RTC_DAY_OF_WEEK );
+ mon = rtc_read( RTC_MONTH );
+ year = rtc_read( RTC_YEAR );
+ century = rtc_read( RTC_CENTURY );
+
+ /* unlock clock registers after read */
+ rtc_write( RTC_CONTROLA, ( reg_a & ~RTC_CA_READ ));
+
+#ifdef RTC_DEBUG
+ printf( "Get RTC year: %02x mon/cent: %02x mon: %02x mday: %02x wday: %02x "
+ "hr: %02x min: %02x sec: %02x\n",
+ year, century, mon, mday, wday,
+ hour, min, sec );
+#endif
+ tmp->tm_sec = bcd2bin( sec & 0x7F );
+ tmp->tm_min = bcd2bin( min & 0x7F );
+ tmp->tm_hour = bcd2bin( hour & 0x3F );
+ tmp->tm_mday = bcd2bin( mday & 0x3F );
+ tmp->tm_mon = bcd2bin( mon & 0x1F );
+ tmp->tm_wday = bcd2bin( wday & 0x07 );
+
+ /* glue year from century and year in century */
+ tmp->tm_year = bcd2bin( year ) +
+ ( bcd2bin( century & 0x3F ) * 100 );
+
+ tmp->tm_yday = 0;
+ tmp->tm_isdst= 0;
+#ifdef RTC_DEBUG
+ printf( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec );
+#endif
+ return 0;
+}
+
+int rtc_set( struct rtc_time *tmp )
+{
+ uchar reg_a;
+#ifdef RTC_DEBUG
+ printf( "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+#endif
+ /* lock clock registers for write */
+ reg_a = rtc_read( RTC_CONTROLA );
+ rtc_write( RTC_CONTROLA, ( reg_a | RTC_CA_WRITE ));
+
+ rtc_write( RTC_MONTH, bin2bcd( tmp->tm_mon ));
+
+ rtc_write( RTC_DAY_OF_WEEK, bin2bcd( tmp->tm_wday ));
+ rtc_write( RTC_DAY_OF_MONTH, bin2bcd( tmp->tm_mday ));
+ rtc_write( RTC_HOURS, bin2bcd( tmp->tm_hour ));
+ rtc_write( RTC_MINUTES, bin2bcd( tmp->tm_min ));
+ rtc_write( RTC_SECONDS, bin2bcd( tmp->tm_sec ));
+
+ /* break year up into century and year in century */
+ rtc_write( RTC_YEAR, bin2bcd( tmp->tm_year % 100 ));
+ rtc_write( RTC_CENTURY, bin2bcd( tmp->tm_year / 100 ));
+
+ /* unlock clock registers after read */
+ rtc_write( RTC_CONTROLA, ( reg_a & ~RTC_CA_WRITE ));
+
+ return 0;
+}
+
+void rtc_reset (void)
+{
+ uchar reg_a, reg_b, reg_c;
+
+ reg_a = rtc_read( RTC_CONTROLA );
+ reg_b = rtc_read( RTC_CONTROLB );
+
+ if ( reg_b & RTC_CB_OSC_DISABLE )
+ {
+ printf( "real-time-clock was stopped. Now starting...\n" );
+ reg_a |= RTC_CA_WRITE;
+ reg_b &= ~RTC_CB_OSC_DISABLE;
+
+ rtc_write( RTC_CONTROLA, reg_a );
+ rtc_write( RTC_CONTROLB, reg_b );
+ }
+
+ /* make sure read/write clock register bits are cleared */
+ reg_a &= ~( RTC_CA_WRITE | RTC_CA_READ );
+ rtc_write( RTC_CONTROLA, reg_a );
+
+ reg_c = rtc_read( RTC_CONTROLC );
+ if (( reg_c & RTC_CC_BATTERY_FLAG ) == 0 )
+ printf( "RTC battery low. Clock setting may not be reliable.\n" );
+}
+
+/* ------------------------------------------------------------------------- */
+
+static uchar rtc_read( unsigned int addr )
+{
+ uchar val = *(volatile unsigned char*)(addr);
+#ifdef RTC_DEBUG
+ printf( "rtc_read: %x:%x\n", addr, val );
+#endif
+ return( val );
+}
+
+static void rtc_write( unsigned int addr, uchar val )
+{
+#ifdef RTC_DEBUG
+ printf( "rtc_write: %x:%x\n", addr, val );
+#endif
+ *(volatile unsigned char*)(addr) = val;
+}
+
+#endif
diff --git a/roms/u-boot/drivers/rtc/ds164x.c b/roms/u-boot/drivers/rtc/ds164x.c
new file mode 100644
index 000000000..f8707892e
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/ds164x.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2002
+ * ARIO Data Networks, Inc. dchiu@ariodata.com
+ *
+ * modified for DS164x:
+ * The LEOX team <team@leox.org>, http://www.leox.org
+ *
+ * Based on MontaVista DS1743 code and U-Boot mc146818 code
+ */
+
+/*
+ * Date & Time support for the DS164x RTC
+ */
+
+/* #define RTC_DEBUG */
+
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+
+
+static uchar rtc_read(unsigned int addr );
+static void rtc_write(unsigned int addr, uchar val);
+
+#define RTC_EPOCH 2000 /* century */
+
+/*
+ * DS164x registers layout
+ */
+#define RTC_BASE ( CONFIG_SYS_NVRAM_BASE_ADDR + CONFIG_SYS_NVRAM_SIZE )
+
+#define RTC_YEAR ( RTC_BASE + 0x07 )
+#define RTC_MONTH ( RTC_BASE + 0x06 )
+#define RTC_DAY_OF_MONTH ( RTC_BASE + 0x05 )
+#define RTC_DAY_OF_WEEK ( RTC_BASE + 0x04 )
+#define RTC_HOURS ( RTC_BASE + 0x03 )
+#define RTC_MINUTES ( RTC_BASE + 0x02 )
+#define RTC_SECONDS ( RTC_BASE + 0x01 )
+#define RTC_CONTROL ( RTC_BASE + 0x00 )
+
+#define RTC_CONTROLA RTC_CONTROL /* W=bit6, R=bit5 */
+#define RTC_CA_WRITE 0x80
+#define RTC_CA_READ 0x40
+#define RTC_CONTROLB RTC_SECONDS /* OSC=bit7 */
+#define RTC_CB_OSC_DISABLE 0x80
+#define RTC_CONTROLC RTC_DAY_OF_WEEK /* FT=bit6 */
+#define RTC_CC_FREQ_TEST 0x40
+
+/* ------------------------------------------------------------------------- */
+
+int rtc_get( struct rtc_time *tmp )
+{
+ uchar sec, min, hour;
+ uchar mday, wday, mon, year;
+
+ uchar reg_a;
+
+ reg_a = rtc_read( RTC_CONTROLA );
+ /* lock clock registers for read */
+ rtc_write( RTC_CONTROLA, ( reg_a | RTC_CA_READ ));
+
+ sec = rtc_read( RTC_SECONDS );
+ min = rtc_read( RTC_MINUTES );
+ hour = rtc_read( RTC_HOURS );
+ mday = rtc_read( RTC_DAY_OF_MONTH );
+ wday = rtc_read( RTC_DAY_OF_WEEK );
+ mon = rtc_read( RTC_MONTH );
+ year = rtc_read( RTC_YEAR );
+
+ /* unlock clock registers after read */
+ rtc_write( RTC_CONTROLA, ( reg_a & ~RTC_CA_READ ));
+
+#ifdef RTC_DEBUG
+ printf( "Get RTC year: %02x mon: %02x mday: %02x wday: %02x "
+ "hr: %02x min: %02x sec: %02x\n",
+ year, mon, mday, wday,
+ hour, min, sec );
+#endif
+ tmp->tm_sec = bcd2bin( sec & 0x7F );
+ tmp->tm_min = bcd2bin( min & 0x7F );
+ tmp->tm_hour = bcd2bin( hour & 0x3F );
+ tmp->tm_mday = bcd2bin( mday & 0x3F );
+ tmp->tm_mon = bcd2bin( mon & 0x1F );
+ tmp->tm_wday = bcd2bin( wday & 0x07 );
+
+ /* glue year in century (2000) */
+ tmp->tm_year = bcd2bin( year ) + RTC_EPOCH;
+
+ tmp->tm_yday = 0;
+ tmp->tm_isdst= 0;
+#ifdef RTC_DEBUG
+ printf( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec );
+#endif
+
+ return 0;
+}
+
+int rtc_set( struct rtc_time *tmp )
+{
+ uchar reg_a;
+
+#ifdef RTC_DEBUG
+ printf( "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+#endif
+ /* lock clock registers for write */
+ reg_a = rtc_read( RTC_CONTROLA );
+ rtc_write( RTC_CONTROLA, ( reg_a | RTC_CA_WRITE ));
+
+ rtc_write( RTC_MONTH, bin2bcd( tmp->tm_mon ));
+
+ rtc_write( RTC_DAY_OF_WEEK, bin2bcd( tmp->tm_wday ));
+ rtc_write( RTC_DAY_OF_MONTH, bin2bcd( tmp->tm_mday ));
+ rtc_write( RTC_HOURS, bin2bcd( tmp->tm_hour ));
+ rtc_write( RTC_MINUTES, bin2bcd( tmp->tm_min ));
+ rtc_write( RTC_SECONDS, bin2bcd( tmp->tm_sec ));
+
+ /* break year in century */
+ rtc_write( RTC_YEAR, bin2bcd( tmp->tm_year % 100 ));
+
+ /* unlock clock registers after read */
+ rtc_write( RTC_CONTROLA, ( reg_a & ~RTC_CA_WRITE ));
+
+ return 0;
+}
+
+void rtc_reset (void)
+{
+ uchar reg_a, reg_b;
+
+ reg_a = rtc_read( RTC_CONTROLA );
+ reg_b = rtc_read( RTC_CONTROLB );
+
+ if ( reg_b & RTC_CB_OSC_DISABLE )
+ {
+ printf( "real-time-clock was stopped. Now starting...\n" );
+ reg_a |= RTC_CA_WRITE;
+ reg_b &= ~RTC_CB_OSC_DISABLE;
+
+ rtc_write( RTC_CONTROLA, reg_a );
+ rtc_write( RTC_CONTROLB, reg_b );
+ }
+
+ /* make sure read/write clock register bits are cleared */
+ reg_a &= ~( RTC_CA_WRITE | RTC_CA_READ );
+ rtc_write( RTC_CONTROLA, reg_a );
+}
+
+/* ------------------------------------------------------------------------- */
+
+static uchar rtc_read( unsigned int addr )
+{
+ uchar val = *(volatile unsigned char*)(addr);
+
+#ifdef RTC_DEBUG
+ printf( "rtc_read: %x:%x\n", addr, val );
+#endif
+ return( val );
+}
+
+static void rtc_write( unsigned int addr, uchar val )
+{
+#ifdef RTC_DEBUG
+ printf( "rtc_write: %x:%x\n", addr, val );
+#endif
+ *(volatile unsigned char*)(addr) = val;
+}
diff --git a/roms/u-boot/drivers/rtc/ds174x.c b/roms/u-boot/drivers/rtc/ds174x.c
new file mode 100644
index 000000000..94f943d97
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/ds174x.c
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2001
+ * ARIO Data Networks, Inc. dchiu@ariodata.com
+ *
+ * Based on MontaVista DS1743 code and U-Boot mc146818 code
+ */
+
+/*
+ * Date & Time support for the DS174x RTC
+ */
+
+/*#define DEBUG*/
+
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+
+static uchar rtc_read( unsigned int addr );
+static void rtc_write( unsigned int addr, uchar val);
+
+#define RTC_BASE ( CONFIG_SYS_NVRAM_SIZE + CONFIG_SYS_NVRAM_BASE_ADDR )
+
+#define RTC_YEAR ( RTC_BASE + 7 )
+#define RTC_MONTH ( RTC_BASE + 6 )
+#define RTC_DAY_OF_MONTH ( RTC_BASE + 5 )
+#define RTC_DAY_OF_WEEK ( RTC_BASE + 4 )
+#define RTC_HOURS ( RTC_BASE + 3 )
+#define RTC_MINUTES ( RTC_BASE + 2 )
+#define RTC_SECONDS ( RTC_BASE + 1 )
+#define RTC_CENTURY ( RTC_BASE + 0 )
+
+#define RTC_CONTROLA RTC_CENTURY
+#define RTC_CONTROLB RTC_SECONDS
+#define RTC_CONTROLC RTC_DAY_OF_WEEK
+
+#define RTC_CA_WRITE 0x80
+#define RTC_CA_READ 0x40
+
+#define RTC_CB_OSC_DISABLE 0x80
+
+#define RTC_CC_BATTERY_FLAG 0x80
+#define RTC_CC_FREQ_TEST 0x40
+
+/* ------------------------------------------------------------------------- */
+
+int rtc_get( struct rtc_time *tmp )
+{
+ uchar sec, min, hour;
+ uchar mday, wday, mon, year;
+
+ int century;
+
+ uchar reg_a;
+
+ reg_a = rtc_read( RTC_CONTROLA );
+ /* lock clock registers for read */
+ rtc_write( RTC_CONTROLA, ( reg_a | RTC_CA_READ ));
+
+ sec = rtc_read( RTC_SECONDS );
+ min = rtc_read( RTC_MINUTES );
+ hour = rtc_read( RTC_HOURS );
+ mday = rtc_read( RTC_DAY_OF_MONTH );
+ wday = rtc_read( RTC_DAY_OF_WEEK );
+ mon = rtc_read( RTC_MONTH );
+ year = rtc_read( RTC_YEAR );
+ century = rtc_read( RTC_CENTURY );
+
+ /* unlock clock registers after read */
+ rtc_write( RTC_CONTROLA, ( reg_a & ~RTC_CA_READ ));
+
+#ifdef RTC_DEBUG
+ printf( "Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x "
+ "hr: %02x min: %02x sec: %02x\n",
+ year, mon_cent, mday, wday,
+ hour, min, sec );
+#endif
+ tmp->tm_sec = bcd2bin( sec & 0x7F );
+ tmp->tm_min = bcd2bin( min & 0x7F );
+ tmp->tm_hour = bcd2bin( hour & 0x3F );
+ tmp->tm_mday = bcd2bin( mday & 0x3F );
+ tmp->tm_mon = bcd2bin( mon & 0x1F );
+ tmp->tm_wday = bcd2bin( wday & 0x07 );
+
+ /* glue year from century and year in century */
+ tmp->tm_year = bcd2bin( year ) +
+ ( bcd2bin( century & 0x3F ) * 100 );
+
+ tmp->tm_yday = 0;
+ tmp->tm_isdst= 0;
+#ifdef RTC_DEBUG
+ printf( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec );
+#endif
+ return 0;
+}
+
+int rtc_set( struct rtc_time *tmp )
+{
+ uchar reg_a;
+#ifdef RTC_DEBUG
+ printf( "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+#endif
+ /* lock clock registers for write */
+ reg_a = rtc_read( RTC_CONTROLA );
+ rtc_write( RTC_CONTROLA, ( reg_a | RTC_CA_WRITE ));
+
+ rtc_write( RTC_MONTH, bin2bcd( tmp->tm_mon ));
+
+ rtc_write( RTC_DAY_OF_WEEK, bin2bcd( tmp->tm_wday ));
+ rtc_write( RTC_DAY_OF_MONTH, bin2bcd( tmp->tm_mday ));
+ rtc_write( RTC_HOURS, bin2bcd( tmp->tm_hour ));
+ rtc_write( RTC_MINUTES, bin2bcd( tmp->tm_min ));
+ rtc_write( RTC_SECONDS, bin2bcd( tmp->tm_sec ));
+
+ /* break year up into century and year in century */
+ rtc_write( RTC_YEAR, bin2bcd( tmp->tm_year % 100 ));
+ rtc_write( RTC_CENTURY, bin2bcd( tmp->tm_year / 100 ));
+
+ /* unlock clock registers after read */
+ rtc_write( RTC_CONTROLA, ( reg_a & ~RTC_CA_WRITE ));
+
+ return 0;
+}
+
+void rtc_reset (void)
+{
+ uchar reg_a, reg_b, reg_c;
+
+ reg_a = rtc_read( RTC_CONTROLA );
+ reg_b = rtc_read( RTC_CONTROLB );
+
+ if ( reg_b & RTC_CB_OSC_DISABLE )
+ {
+ printf( "real-time-clock was stopped. Now starting...\n" );
+ reg_a |= RTC_CA_WRITE;
+ reg_b &= ~RTC_CB_OSC_DISABLE;
+
+ rtc_write( RTC_CONTROLA, reg_a );
+ rtc_write( RTC_CONTROLB, reg_b );
+ }
+
+ /* make sure read/write clock register bits are cleared */
+ reg_a &= ~( RTC_CA_WRITE | RTC_CA_READ );
+ rtc_write( RTC_CONTROLA, reg_a );
+
+ reg_c = rtc_read( RTC_CONTROLC );
+ if (( reg_c & RTC_CC_BATTERY_FLAG ) == 0 )
+ printf( "RTC battery low. Clock setting may not be reliable.\n" );
+}
+
+/* ------------------------------------------------------------------------- */
+
+static uchar rtc_read( unsigned int addr )
+{
+ uchar val = in8( addr );
+#ifdef RTC_DEBUG
+ printf( "rtc_read: %x:%x\n", addr, val );
+#endif
+ return( val );
+}
+
+static void rtc_write( unsigned int addr, uchar val )
+{
+#ifdef RTC_DEBUG
+ printf( "rtc_write: %x:%x\n", addr, val );
+#endif
+ out8( addr, val );
+}
diff --git a/roms/u-boot/drivers/rtc/ds3231.c b/roms/u-boot/drivers/rtc/ds3231.c
new file mode 100644
index 000000000..5b72e8676
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/ds3231.c
@@ -0,0 +1,292 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2006
+ * Markus Klotzbuecher, mk@denx.de
+ *
+ * (C) Copyright 2019 NXP
+ * Chuanhua Han <chuanhua.han@nxp.com>
+ */
+
+/*
+ * Date & Time support (no alarms) for Dallas Semiconductor (now Maxim)
+ * Extremly Accurate DS3231 Real Time Clock (RTC).
+ *
+ * copied from ds1337.c
+ */
+
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <log.h>
+#include <rtc.h>
+#include <i2c.h>
+
+/*
+ * RTC register addresses
+ */
+#define RTC_SEC_REG_ADDR 0x0
+#define RTC_MIN_REG_ADDR 0x1
+#define RTC_HR_REG_ADDR 0x2
+#define RTC_DAY_REG_ADDR 0x3
+#define RTC_DATE_REG_ADDR 0x4
+#define RTC_MON_REG_ADDR 0x5
+#define RTC_YR_REG_ADDR 0x6
+#define RTC_CTL_REG_ADDR 0x0e
+#define RTC_STAT_REG_ADDR 0x0f
+
+
+/*
+ * RTC control register bits
+ */
+#define RTC_CTL_BIT_A1IE 0x1 /* Alarm 1 interrupt enable */
+#define RTC_CTL_BIT_A2IE 0x2 /* Alarm 2 interrupt enable */
+#define RTC_CTL_BIT_INTCN 0x4 /* Interrupt control */
+#define RTC_CTL_BIT_RS1 0x8 /* Rate select 1 */
+#define RTC_CTL_BIT_RS2 0x10 /* Rate select 2 */
+#define RTC_CTL_BIT_DOSC 0x80 /* Disable Oscillator */
+
+/*
+ * RTC status register bits
+ */
+#define RTC_STAT_BIT_A1F 0x1 /* Alarm 1 flag */
+#define RTC_STAT_BIT_A2F 0x2 /* Alarm 2 flag */
+#define RTC_STAT_BIT_OSF 0x80 /* Oscillator stop flag */
+#define RTC_STAT_BIT_BB32KHZ 0x40 /* Battery backed 32KHz Output */
+#define RTC_STAT_BIT_EN32KHZ 0x8 /* Enable 32KHz Output */
+
+
+#if !CONFIG_IS_ENABLED(DM_RTC)
+static uchar rtc_read (uchar reg);
+static void rtc_write (uchar reg, uchar val);
+
+
+/*
+ * Get the current time from the RTC
+ */
+int rtc_get (struct rtc_time *tmp)
+{
+ int rel = 0;
+ uchar sec, min, hour, mday, wday, mon_cent, year, control, status;
+
+ control = rtc_read (RTC_CTL_REG_ADDR);
+ status = rtc_read (RTC_STAT_REG_ADDR);
+ sec = rtc_read (RTC_SEC_REG_ADDR);
+ min = rtc_read (RTC_MIN_REG_ADDR);
+ hour = rtc_read (RTC_HR_REG_ADDR);
+ wday = rtc_read (RTC_DAY_REG_ADDR);
+ mday = rtc_read (RTC_DATE_REG_ADDR);
+ mon_cent = rtc_read (RTC_MON_REG_ADDR);
+ year = rtc_read (RTC_YR_REG_ADDR);
+
+ debug("Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x "
+ "hr: %02x min: %02x sec: %02x control: %02x status: %02x\n",
+ year, mon_cent, mday, wday, hour, min, sec, control, status);
+
+ if (status & RTC_STAT_BIT_OSF) {
+ printf ("### Warning: RTC oscillator has stopped\n");
+ /* clear the OSF flag */
+ rtc_write (RTC_STAT_REG_ADDR,
+ rtc_read (RTC_STAT_REG_ADDR) & ~RTC_STAT_BIT_OSF);
+ rel = -1;
+ }
+
+ tmp->tm_sec = bcd2bin (sec & 0x7F);
+ tmp->tm_min = bcd2bin (min & 0x7F);
+ tmp->tm_hour = bcd2bin (hour & 0x3F);
+ tmp->tm_mday = bcd2bin (mday & 0x3F);
+ tmp->tm_mon = bcd2bin (mon_cent & 0x1F);
+ tmp->tm_year = bcd2bin (year) + ((mon_cent & 0x80) ? 2000 : 1900);
+ tmp->tm_wday = bcd2bin ((wday - 1) & 0x07);
+ tmp->tm_yday = 0;
+ tmp->tm_isdst= 0;
+
+ debug("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ return rel;
+}
+
+
+/*
+ * Set the RTC
+ */
+int rtc_set (struct rtc_time *tmp)
+{
+ uchar century;
+
+ debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ rtc_write (RTC_YR_REG_ADDR, bin2bcd (tmp->tm_year % 100));
+
+ century = (tmp->tm_year >= 2000) ? 0x80 : 0;
+ rtc_write (RTC_MON_REG_ADDR, bin2bcd (tmp->tm_mon) | century);
+
+ rtc_write (RTC_DAY_REG_ADDR, bin2bcd (tmp->tm_wday + 1));
+ rtc_write (RTC_DATE_REG_ADDR, bin2bcd (tmp->tm_mday));
+ rtc_write (RTC_HR_REG_ADDR, bin2bcd (tmp->tm_hour));
+ rtc_write (RTC_MIN_REG_ADDR, bin2bcd (tmp->tm_min));
+ rtc_write (RTC_SEC_REG_ADDR, bin2bcd (tmp->tm_sec));
+
+ return 0;
+}
+
+
+/*
+ * Reset the RTC. We also enable the oscillator output on the
+ * SQW/INTB* pin and program it for 32,768 Hz output. Note that
+ * according to the datasheet, turning on the square wave output
+ * increases the current drain on the backup battery from about
+ * 600 nA to 2uA.
+ */
+void rtc_reset (void)
+{
+ rtc_write (RTC_CTL_REG_ADDR, RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS2);
+}
+
+/*
+ * Enable 32KHz output
+ */
+#ifdef CONFIG_RTC_ENABLE_32KHZ_OUTPUT
+void rtc_enable_32khz_output(void)
+{
+ rtc_write(RTC_STAT_REG_ADDR,
+ RTC_STAT_BIT_BB32KHZ | RTC_STAT_BIT_EN32KHZ);
+}
+#endif
+
+/*
+ * Helper functions
+ */
+
+static
+uchar rtc_read (uchar reg)
+{
+ return (i2c_reg_read (CONFIG_SYS_I2C_RTC_ADDR, reg));
+}
+
+
+static void rtc_write (uchar reg, uchar val)
+{
+ i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val);
+}
+#else
+static int ds3231_rtc_get(struct udevice *dev, struct rtc_time *tmp)
+{
+ uchar sec, min, hour, mday, wday, mon_cent, year, status;
+
+ status = dm_i2c_reg_read(dev, RTC_STAT_REG_ADDR);
+ sec = dm_i2c_reg_read(dev, RTC_SEC_REG_ADDR);
+ min = dm_i2c_reg_read(dev, RTC_MIN_REG_ADDR);
+ hour = dm_i2c_reg_read(dev, RTC_HR_REG_ADDR);
+ wday = dm_i2c_reg_read(dev, RTC_DAY_REG_ADDR);
+ mday = dm_i2c_reg_read(dev, RTC_DATE_REG_ADDR);
+ mon_cent = dm_i2c_reg_read(dev, RTC_MON_REG_ADDR);
+ year = dm_i2c_reg_read(dev, RTC_YR_REG_ADDR);
+
+ if (status & RTC_STAT_BIT_OSF) {
+ printf("### Warning: RTC oscillator has stopped\n");
+ /* clear the OSF flag */
+ dm_i2c_reg_write(dev, RTC_STAT_REG_ADDR,
+ dm_i2c_reg_read(dev, RTC_STAT_REG_ADDR)
+ & ~RTC_STAT_BIT_OSF);
+ return -EINVAL;
+ }
+
+ tmp->tm_sec = bcd2bin(sec & 0x7F);
+ tmp->tm_min = bcd2bin(min & 0x7F);
+ tmp->tm_hour = bcd2bin(hour & 0x3F);
+ tmp->tm_mday = bcd2bin(mday & 0x3F);
+ tmp->tm_mon = bcd2bin(mon_cent & 0x1F);
+ tmp->tm_year = bcd2bin(year) + ((mon_cent & 0x80) ? 2000 : 1900);
+ tmp->tm_wday = bcd2bin((wday - 1) & 0x07);
+ tmp->tm_yday = 0;
+ tmp->tm_isdst = 0;
+
+ debug("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ return 0;
+}
+
+static int ds3231_rtc_set(struct udevice *dev, const struct rtc_time *tmp)
+{
+ uchar century;
+
+ debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ dm_i2c_reg_write(dev, RTC_YR_REG_ADDR, bin2bcd(tmp->tm_year % 100));
+
+ century = (tmp->tm_year >= 2000) ? 0x80 : 0;
+ dm_i2c_reg_write(dev, RTC_MON_REG_ADDR, bin2bcd(tmp->tm_mon) | century);
+
+ dm_i2c_reg_write(dev, RTC_DAY_REG_ADDR, bin2bcd(tmp->tm_wday + 1));
+ dm_i2c_reg_write(dev, RTC_DATE_REG_ADDR, bin2bcd(tmp->tm_mday));
+ dm_i2c_reg_write(dev, RTC_HR_REG_ADDR, bin2bcd(tmp->tm_hour));
+ dm_i2c_reg_write(dev, RTC_MIN_REG_ADDR, bin2bcd(tmp->tm_min));
+ dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR, bin2bcd(tmp->tm_sec));
+
+ return 0;
+}
+
+static int ds3231_rtc_reset(struct udevice *dev)
+{
+ int ret;
+
+ ret = dm_i2c_reg_write(dev, RTC_CTL_REG_ADDR,
+ RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS2);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int ds3231_probe(struct udevice *dev)
+{
+ i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS |
+ DM_I2C_CHIP_WR_ADDRESS);
+
+ return 0;
+}
+
+#ifdef CONFIG_RTC_ENABLE_32KHZ_OUTPUT
+int rtc_enable_32khz_output(int busnum, int chip_addr)
+{
+ int ret;
+ struct udevice *dev;
+
+ ret = i2c_get_chip_for_busnum(busnum, chip_addr, 1, &dev);
+ if (!ret) {
+ ret = dm_i2c_reg_write(dev, RTC_STAT_REG_ADDR,
+ RTC_STAT_BIT_BB32KHZ |
+ RTC_STAT_BIT_EN32KHZ);
+ }
+ return ret;
+}
+#endif
+
+static const struct rtc_ops ds3231_rtc_ops = {
+ .get = ds3231_rtc_get,
+ .set = ds3231_rtc_set,
+ .reset = ds3231_rtc_reset,
+};
+
+static const struct udevice_id ds3231_rtc_ids[] = {
+ { .compatible = "dallas,ds3231" },
+ { .compatible = "dallas,ds3232" },
+ { }
+};
+
+U_BOOT_DRIVER(rtc_ds3231) = {
+ .name = "rtc-ds3231",
+ .id = UCLASS_RTC,
+ .probe = ds3231_probe,
+ .of_match = ds3231_rtc_ids,
+ .ops = &ds3231_rtc_ops,
+};
+#endif
diff --git a/roms/u-boot/drivers/rtc/ds3232.c b/roms/u-boot/drivers/rtc/ds3232.c
new file mode 100644
index 000000000..16501cfe5
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/ds3232.c
@@ -0,0 +1,276 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2019, Vaisala Oyj
+ */
+
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <i2c.h>
+#include <rtc.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+
+/*
+ * RTC register addresses
+ */
+#define RTC_SEC_REG_ADDR 0x00
+#define RTC_MIN_REG_ADDR 0x01
+#define RTC_HR_REG_ADDR 0x02
+#define RTC_DAY_REG_ADDR 0x03
+#define RTC_DATE_REG_ADDR 0x04
+#define RTC_MON_REG_ADDR 0x05
+#define RTC_YR_REG_ADDR 0x06
+#define RTC_CTL_REG_ADDR 0x0e
+#define RTC_STAT_REG_ADDR 0x0f
+#define RTC_TEST_REG_ADDR 0x13
+
+/*
+ * RTC control register bits
+ */
+#define RTC_CTL_BIT_A1IE BIT(0) /* Alarm 1 interrupt enable */
+#define RTC_CTL_BIT_A2IE BIT(1) /* Alarm 2 interrupt enable */
+#define RTC_CTL_BIT_INTCN BIT(2) /* Interrupt control */
+#define RTC_CTL_BIT_DOSC BIT(7) /* Disable Oscillator */
+
+/*
+ * RTC status register bits
+ */
+#define RTC_STAT_BIT_A1F BIT(0) /* Alarm 1 flag */
+#define RTC_STAT_BIT_A2F BIT(1) /* Alarm 2 flag */
+#define RTC_STAT_BIT_EN32KHZ BIT(3) /* Enable 32KHz Output */
+#define RTC_STAT_BIT_BB32KHZ BIT(6) /* Battery backed 32KHz Output */
+#define RTC_STAT_BIT_OSF BIT(7) /* Oscillator stop flag */
+
+/*
+ * RTC test register bits
+ */
+#define RTC_TEST_BIT_SWRST BIT(7) /* Software reset */
+
+#define RTC_DATE_TIME_REG_SIZE 7
+#define RTC_SRAM_START 0x14
+#define RTC_SRAM_END 0xFF
+#define RTC_SRAM_SIZE 236
+
+struct ds3232_priv_data {
+ u8 max_register;
+ u8 sram_start;
+ int sram_size;
+};
+
+static int ds3232_rtc_read8(struct udevice *dev, unsigned int reg)
+{
+ int ret;
+ u8 buf;
+ struct ds3232_priv_data *priv_data;
+
+ priv_data = dev_get_priv(dev);
+ if (!priv_data)
+ return -EINVAL;
+
+ if (reg > priv_data->max_register)
+ return -EINVAL;
+
+ ret = dm_i2c_read(dev, reg, &buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+
+ return buf;
+}
+
+static int ds3232_rtc_write8(struct udevice *dev, unsigned int reg, int val)
+{
+ u8 buf = (u8)val;
+ struct ds3232_priv_data *priv_data;
+
+ priv_data = dev_get_priv(dev);
+ if (!priv_data)
+ return -EINVAL;
+
+ if (reg > priv_data->max_register)
+ return -EINVAL;
+
+ return dm_i2c_write(dev, reg, &buf, sizeof(buf));
+}
+
+static int reset_sram(struct udevice *dev)
+{
+ int ret, sram_end, reg;
+ struct ds3232_priv_data *priv_data;
+
+ priv_data = dev_get_priv(dev);
+ if (!priv_data)
+ return -EINVAL;
+
+ sram_end = priv_data->sram_start + priv_data->sram_size;
+
+ for (reg = priv_data->sram_start; reg < sram_end; reg++) {
+ ret = ds3232_rtc_write8(dev, reg, 0x00);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int verify_osc(struct udevice *dev)
+{
+ int ret, rtc_status;
+
+ ret = ds3232_rtc_read8(dev, RTC_STAT_REG_ADDR);
+ if (ret < 0)
+ return ret;
+
+ rtc_status = ret;
+
+ if (rtc_status & RTC_STAT_BIT_OSF) {
+ dev_warn(dev,
+ "oscillator discontinuity flagged, time unreliable\n");
+ /*
+ * In case OSC was off we cannot trust the SRAM data anymore.
+ * Reset it to 0x00.
+ */
+ ret = reset_sram(dev);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ds3232_rtc_set(struct udevice *dev, const struct rtc_time *tm)
+{
+ u8 buf[RTC_DATE_TIME_REG_SIZE];
+ u8 is_century;
+
+ if (tm->tm_year < 1900 || tm->tm_year > 2099)
+ dev_warn(dev, "WARNING: year should be between 1900 and 2099!\n");
+
+ is_century = (tm->tm_year >= 2000) ? 0x80 : 0;
+
+ buf[RTC_SEC_REG_ADDR] = bin2bcd(tm->tm_sec);
+ buf[RTC_MIN_REG_ADDR] = bin2bcd(tm->tm_min);
+ buf[RTC_HR_REG_ADDR] = bin2bcd(tm->tm_hour);
+ buf[RTC_DAY_REG_ADDR] = bin2bcd(tm->tm_wday + 1);
+ buf[RTC_DATE_REG_ADDR] = bin2bcd(tm->tm_mday);
+ buf[RTC_MON_REG_ADDR] = bin2bcd(tm->tm_mon) | is_century;
+ buf[RTC_YR_REG_ADDR] = bin2bcd(tm->tm_year % 100);
+
+ return dm_i2c_write(dev, 0, buf, sizeof(buf));
+}
+
+static int ds3232_rtc_get(struct udevice *dev, struct rtc_time *tm)
+{
+ int ret;
+ u8 buf[RTC_DATE_TIME_REG_SIZE];
+ u8 is_twelve_hr;
+ u8 is_pm;
+ u8 is_century;
+
+ ret = verify_osc(dev);
+ if (ret < 0)
+ return ret;
+
+ ret = dm_i2c_read(dev, 0, buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+
+ /* Extract additional information for AM/PM and century */
+ is_twelve_hr = buf[RTC_HR_REG_ADDR] & 0x40;
+ is_pm = buf[RTC_HR_REG_ADDR] & 0x20;
+ is_century = buf[RTC_MON_REG_ADDR] & 0x80;
+
+ tm->tm_sec = bcd2bin(buf[RTC_SEC_REG_ADDR] & 0x7F);
+ tm->tm_min = bcd2bin(buf[RTC_MIN_REG_ADDR] & 0x7F);
+
+ if (is_twelve_hr)
+ tm->tm_hour = bcd2bin(buf[RTC_HR_REG_ADDR] & 0x1F)
+ + (is_pm ? 12 : 0);
+ else
+ tm->tm_hour = bcd2bin(buf[RTC_HR_REG_ADDR]);
+
+ tm->tm_wday = bcd2bin((buf[RTC_DAY_REG_ADDR] & 0x07) - 1);
+ tm->tm_mday = bcd2bin(buf[RTC_DATE_REG_ADDR] & 0x3F);
+ tm->tm_mon = bcd2bin((buf[RTC_MON_REG_ADDR] & 0x7F));
+ tm->tm_year = bcd2bin(buf[RTC_YR_REG_ADDR])
+ + (is_century ? 2000 : 1900);
+ tm->tm_yday = 0;
+ tm->tm_isdst = 0;
+
+ return 0;
+}
+
+static int ds3232_rtc_reset(struct udevice *dev)
+{
+ int ret;
+
+ ret = reset_sram(dev);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * From datasheet
+ * (https://datasheets.maximintegrated.com/en/ds/DS3232M.pdf):
+ *
+ * The device reset occurs during the normal acknowledge time slot
+ * following the receipt of the data byte carrying that
+ * SWRST instruction a NACK occurs due to the resetting action.
+ *
+ * Therefore we don't verify the result of I2C write operation since it
+ * will fail due the NACK.
+ */
+ ds3232_rtc_write8(dev, RTC_TEST_REG_ADDR, RTC_TEST_BIT_SWRST);
+
+ return 0;
+}
+
+static int ds3232_probe(struct udevice *dev)
+{
+ int rtc_status;
+ int ret;
+ struct ds3232_priv_data *priv_data;
+
+ priv_data = dev_get_priv(dev);
+ if (!priv_data)
+ return -EINVAL;
+
+ priv_data->sram_start = RTC_SRAM_START;
+ priv_data->max_register = RTC_SRAM_END;
+ priv_data->sram_size = RTC_SRAM_SIZE;
+
+ ret = ds3232_rtc_read8(dev, RTC_STAT_REG_ADDR);
+ if (ret < 0)
+ return ret;
+
+ rtc_status = ret;
+
+ ret = verify_osc(dev);
+ if (ret < 0)
+ return ret;
+
+ rtc_status &= ~(RTC_STAT_BIT_OSF | RTC_STAT_BIT_A1F | RTC_STAT_BIT_A2F);
+
+ return ds3232_rtc_write8(dev, RTC_STAT_REG_ADDR, rtc_status);
+}
+
+static const struct rtc_ops ds3232_rtc_ops = {
+ .get = ds3232_rtc_get,
+ .set = ds3232_rtc_set,
+ .reset = ds3232_rtc_reset,
+ .read8 = ds3232_rtc_read8,
+ .write8 = ds3232_rtc_write8
+};
+
+static const struct udevice_id ds3232_rtc_ids[] = {
+ { .compatible = "dallas,ds3232" },
+ { }
+};
+
+U_BOOT_DRIVER(rtc_ds3232) = {
+ .name = "rtc-ds3232",
+ .id = UCLASS_RTC,
+ .probe = ds3232_probe,
+ .of_match = ds3232_rtc_ids,
+ .ops = &ds3232_rtc_ops,
+ .priv_auto = sizeof(struct ds3232_priv_data),
+};
diff --git a/roms/u-boot/drivers/rtc/emul_rtc.c b/roms/u-boot/drivers/rtc/emul_rtc.c
new file mode 100644
index 000000000..8f0e1ab5a
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/emul_rtc.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * This driver emulates a real time clock based on timer ticks.
+ */
+
+#include <common.h>
+#include <div64.h>
+#include <dm.h>
+#include <env.h>
+#include <generated/timestamp_autogenerated.h>
+#include <rtc.h>
+
+/**
+ * struct emul_rtc - private data for emulated RTC driver
+ */
+struct emul_rtc {
+ /**
+ * @offset_us: microseconds from 1970-01-01 to timer_get_us() base
+ */
+ u64 offset_us;
+ /**
+ * @isdst: daylight saving time
+ */
+ int isdst;
+};
+
+static int emul_rtc_get(struct udevice *dev, struct rtc_time *time)
+{
+ struct emul_rtc *priv = dev_get_priv(dev);
+ u64 now;
+
+ now = timer_get_us() + priv->offset_us;
+ do_div(now, 1000000);
+ rtc_to_tm(now, time);
+ time->tm_isdst = priv->isdst;
+
+ return 0;
+}
+
+static int emul_rtc_set(struct udevice *dev, const struct rtc_time *time)
+{
+ struct emul_rtc *priv = dev_get_priv(dev);
+
+ if (time->tm_year < 1970)
+ return -EINVAL;
+
+ priv->offset_us = rtc_mktime(time) * 1000000ULL - timer_get_us();
+
+ if (time->tm_isdst > 0)
+ priv->isdst = 1;
+ else if (time->tm_isdst < 0)
+ priv->isdst = -1;
+ else
+ priv->isdst = 0;
+
+ return 0;
+}
+
+int emul_rtc_probe(struct udevice *dev)
+{
+ struct emul_rtc *priv = dev_get_priv(dev);
+ const char *epoch_str;
+ u64 epoch;
+
+ epoch_str = env_get("rtc_emul_epoch");
+
+ if (epoch_str) {
+ epoch = simple_strtoull(epoch_str, NULL, 10);
+ } else {
+ /* Use the build date as initial time */
+ epoch = U_BOOT_EPOCH;
+ }
+ priv->offset_us = epoch * 1000000ULL - timer_get_us();
+ priv->isdst = -1;
+
+ return 0;
+}
+
+static const struct rtc_ops emul_rtc_ops = {
+ .get = emul_rtc_get,
+ .set = emul_rtc_set,
+};
+
+U_BOOT_DRIVER(rtc_emul) = {
+ .name = "rtc_emul",
+ .id = UCLASS_RTC,
+ .ops = &emul_rtc_ops,
+ .probe = emul_rtc_probe,
+ .priv_auto = sizeof(struct emul_rtc),
+};
+
+U_BOOT_DRVINFO(rtc_emul) = {
+ .name = "rtc_emul",
+};
diff --git a/roms/u-boot/drivers/rtc/ftrtc010.c b/roms/u-boot/drivers/rtc/ftrtc010.c
new file mode 100644
index 000000000..67c2b6e32
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/ftrtc010.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Faraday FTRTC010 Real Time Clock
+ *
+ * (C) Copyright 2009 Faraday Technology
+ * Po-Yu Chuang <ratbert@faraday-tech.com>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <log.h>
+#include <rtc.h>
+#include <asm/io.h>
+
+struct ftrtc010 {
+ unsigned int sec; /* 0x00 */
+ unsigned int min; /* 0x04 */
+ unsigned int hour; /* 0x08 */
+ unsigned int day; /* 0x0c */
+ unsigned int alarm_sec; /* 0x10 */
+ unsigned int alarm_min; /* 0x14 */
+ unsigned int alarm_hour; /* 0x18 */
+ unsigned int record; /* 0x1c */
+ unsigned int cr; /* 0x20 */
+ unsigned int wsec; /* 0x24 */
+ unsigned int wmin; /* 0x28 */
+ unsigned int whour; /* 0x2c */
+ unsigned int wday; /* 0x30 */
+ unsigned int intr; /* 0x34 */
+ unsigned int div; /* 0x38 */
+ unsigned int rev; /* 0x3c */
+};
+
+/*
+ * RTC Control Register
+ */
+#define FTRTC010_CR_ENABLE (1 << 0)
+#define FTRTC010_CR_INTERRUPT_SEC (1 << 1) /* per second irq */
+#define FTRTC010_CR_INTERRUPT_MIN (1 << 2) /* per minute irq */
+#define FTRTC010_CR_INTERRUPT_HR (1 << 3) /* per hour irq */
+#define FTRTC010_CR_INTERRUPT_DAY (1 << 4) /* per day irq */
+
+static struct ftrtc010 *rtc = (struct ftrtc010 *)CONFIG_FTRTC010_BASE;
+
+static void ftrtc010_enable(void)
+{
+ writel(FTRTC010_CR_ENABLE, &rtc->cr);
+}
+
+/*
+ * return current time in seconds
+ */
+static unsigned long ftrtc010_time(void)
+{
+ unsigned long day;
+ unsigned long hour;
+ unsigned long minute;
+ unsigned long second;
+ unsigned long second2;
+
+ do {
+ second = readl(&rtc->sec);
+ day = readl(&rtc->day);
+ hour = readl(&rtc->hour);
+ minute = readl(&rtc->min);
+ second2 = readl(&rtc->sec);
+ } while (second != second2);
+
+ return day * 24 * 60 * 60 + hour * 60 * 60 + minute * 60 + second;
+}
+
+/*
+ * Get the current time from the RTC
+ */
+
+int rtc_get(struct rtc_time *tmp)
+{
+ unsigned long now;
+
+ debug("%s(): record register: %x\n",
+ __func__, readl(&rtc->record));
+
+#ifdef CONFIG_FTRTC010_PCLK
+ now = (ftrtc010_time() + readl(&rtc->record)) / RTC_DIV_COUNT;
+#else /* CONFIG_FTRTC010_EXTCLK */
+ now = ftrtc010_time() + readl(&rtc->record);
+#endif
+
+ rtc_to_tm(now, tmp);
+
+ return 0;
+}
+
+/*
+ * Set the RTC
+ */
+int rtc_set(struct rtc_time *tmp)
+{
+ unsigned long new;
+ unsigned long now;
+
+ debug("%s(): DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ __func__,
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ new = rtc_mktime(tmp);
+
+ now = ftrtc010_time();
+
+ debug("%s(): write %lx to record register\n", __func__, new - now);
+
+ writel(new - now, &rtc->record);
+
+ return 0;
+}
+
+void rtc_reset(void)
+{
+ debug("%s()\n", __func__);
+ ftrtc010_enable();
+}
diff --git a/roms/u-boot/drivers/rtc/i2c_rtc_emul.c b/roms/u-boot/drivers/rtc/i2c_rtc_emul.c
new file mode 100644
index 000000000..ba418c25d
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/i2c_rtc_emul.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Simulate an I2C real time clock
+ *
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+/*
+ * This is a test driver. It starts off with the current time of the machine,
+ * but also supports setting the time, using an offset from the current
+ * clock. This driver is only intended for testing, not accurate
+ * time-keeping. It does not change the system time.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <os.h>
+#include <rtc.h>
+#include <asm/rtc.h>
+#include <asm/test.h>
+
+#ifdef DEBUG
+#define debug_buffer print_buffer
+#else
+#define debug_buffer(x, ...)
+#endif
+
+long sandbox_i2c_rtc_set_offset(struct udevice *dev, bool use_system_time,
+ int offset)
+{
+ struct sandbox_i2c_rtc_plat_data *plat = dev_get_plat(dev);
+ long old_offset;
+
+ old_offset = plat->offset;
+ plat->use_system_time = use_system_time;
+ if (offset != -1)
+ plat->offset = offset;
+ os_set_time_offset(plat->offset);
+
+ return old_offset;
+}
+
+long sandbox_i2c_rtc_get_set_base_time(struct udevice *dev, long base_time)
+{
+ struct sandbox_i2c_rtc_plat_data *plat = dev_get_plat(dev);
+ long old_base_time;
+
+ old_base_time = plat->base_time;
+ if (base_time != -1)
+ plat->base_time = base_time;
+
+ return old_base_time;
+}
+
+static void reset_time(struct udevice *dev)
+{
+ struct sandbox_i2c_rtc_plat_data *plat = dev_get_plat(dev);
+ struct rtc_time now;
+
+ os_localtime(&now);
+ plat->base_time = rtc_mktime(&now);
+ plat->offset = os_get_time_offset();
+ plat->use_system_time = true;
+}
+
+static int sandbox_i2c_rtc_get(struct udevice *dev, struct rtc_time *time)
+{
+ struct sandbox_i2c_rtc_plat_data *plat = dev_get_plat(dev);
+ struct rtc_time tm_now;
+ long now;
+
+ if (plat->use_system_time) {
+ os_localtime(&tm_now);
+ now = rtc_mktime(&tm_now);
+ } else {
+ now = plat->base_time;
+ }
+
+ rtc_to_tm(now + plat->offset, time);
+
+ return 0;
+}
+
+static int sandbox_i2c_rtc_set(struct udevice *dev, const struct rtc_time *time)
+{
+ struct sandbox_i2c_rtc_plat_data *plat = dev_get_plat(dev);
+ struct rtc_time tm_now;
+ long now;
+
+ if (plat->use_system_time) {
+ os_localtime(&tm_now);
+ now = rtc_mktime(&tm_now);
+ } else {
+ now = plat->base_time;
+ }
+ plat->offset = rtc_mktime(time) - now;
+ os_set_time_offset(plat->offset);
+
+ return 0;
+}
+
+/* Update the current time in the registers */
+static int sandbox_i2c_rtc_prepare_read(struct udevice *emul)
+{
+ struct sandbox_i2c_rtc_plat_data *plat = dev_get_plat(emul);
+ struct rtc_time time;
+ int ret;
+
+ ret = sandbox_i2c_rtc_get(emul, &time);
+ if (ret)
+ return ret;
+
+ plat->reg[REG_SEC] = time.tm_sec;
+ plat->reg[REG_MIN] = time.tm_min;
+ plat->reg[REG_HOUR] = time.tm_hour;
+ plat->reg[REG_MDAY] = time.tm_mday;
+ plat->reg[REG_MON] = time.tm_mon;
+ plat->reg[REG_YEAR] = time.tm_year - 1900;
+ plat->reg[REG_WDAY] = time.tm_wday;
+
+ return 0;
+}
+
+static int sandbox_i2c_rtc_complete_write(struct udevice *emul)
+{
+ struct sandbox_i2c_rtc_plat_data *plat = dev_get_plat(emul);
+ struct rtc_time time;
+ int ret;
+
+ time.tm_sec = plat->reg[REG_SEC];
+ time.tm_min = plat->reg[REG_MIN];
+ time.tm_hour = plat->reg[REG_HOUR];
+ time.tm_mday = plat->reg[REG_MDAY];
+ time.tm_mon = plat->reg[REG_MON];
+ time.tm_year = plat->reg[REG_YEAR] + 1900;
+ time.tm_wday = plat->reg[REG_WDAY];
+
+ ret = sandbox_i2c_rtc_set(emul, &time);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int sandbox_i2c_rtc_xfer(struct udevice *emul, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct sandbox_i2c_rtc_plat_data *plat = dev_get_plat(emul);
+ uint offset = 0;
+ int ret;
+
+ debug("\n%s\n", __func__);
+ ret = sandbox_i2c_rtc_prepare_read(emul);
+ if (ret)
+ return ret;
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ int len;
+ u8 *ptr;
+
+ len = msg->len;
+ debug(" %s: msg->len=%d",
+ msg->flags & I2C_M_RD ? "read" : "write",
+ msg->len);
+ if (msg->flags & I2C_M_RD) {
+ debug(", offset %x, len %x: ", offset, len);
+
+ /* Read the register */
+ memcpy(msg->buf, plat->reg + offset, len);
+ memset(msg->buf + len, '\xff', msg->len - len);
+ debug_buffer(0, msg->buf, 1, msg->len, 0);
+ } else if (len >= 1) {
+ ptr = msg->buf;
+ offset = *ptr++ & (REG_COUNT - 1);
+ len--;
+ debug(", set offset %x: ", offset);
+ debug_buffer(0, msg->buf, 1, msg->len, 0);
+
+ /* Write the register */
+ memcpy(plat->reg + offset, ptr, len);
+ /* If the reset register was written to, do reset. */
+ if (offset <= REG_RESET && REG_RESET < offset + len)
+ reset_time(emul);
+ }
+ }
+ ret = sandbox_i2c_rtc_complete_write(emul);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+struct dm_i2c_ops sandbox_i2c_rtc_emul_ops = {
+ .xfer = sandbox_i2c_rtc_xfer,
+};
+
+static int sandbox_i2c_rtc_bind(struct udevice *dev)
+{
+ reset_time(dev);
+
+ return 0;
+}
+
+static const struct udevice_id sandbox_i2c_rtc_ids[] = {
+ { .compatible = "sandbox,i2c-rtc-emul" },
+ { }
+};
+
+U_BOOT_DRIVER(sandbox_i2c_rtc_emul) = {
+ .name = "sandbox_i2c_rtc_emul",
+ .id = UCLASS_I2C_EMUL,
+ .of_match = sandbox_i2c_rtc_ids,
+ .bind = sandbox_i2c_rtc_bind,
+ .priv_auto = sizeof(struct sandbox_i2c_rtc),
+ .plat_auto = sizeof(struct sandbox_i2c_rtc_plat_data),
+ .ops = &sandbox_i2c_rtc_emul_ops,
+};
diff --git a/roms/u-boot/drivers/rtc/imxdi.c b/roms/u-boot/drivers/rtc/imxdi.c
new file mode 100644
index 000000000..e3a139326
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/imxdi.c
@@ -0,0 +1,223 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2009-2012 ADVANSEE
+ * Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
+ *
+ * Based on the Linux rtc-imxdi.c driver, which is:
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2010 Orex Computed Radiography
+ */
+
+/*
+ * Date & Time support for Freescale i.MX DryIce RTC
+ */
+
+#include <common.h>
+#include <command.h>
+#include <linux/compat.h>
+#include <rtc.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/arch/imx-regs.h>
+
+/* DryIce Register Definitions */
+
+struct imxdi_regs {
+ u32 dtcmr; /* Time Counter MSB Reg */
+ u32 dtclr; /* Time Counter LSB Reg */
+ u32 dcamr; /* Clock Alarm MSB Reg */
+ u32 dcalr; /* Clock Alarm LSB Reg */
+ u32 dcr; /* Control Reg */
+ u32 dsr; /* Status Reg */
+ u32 dier; /* Interrupt Enable Reg */
+};
+
+#define DCAMR_UNSET 0xFFFFFFFF /* doomsday - 1 sec */
+
+#define DCR_TCE (1 << 3) /* Time Counter Enable */
+
+#define DSR_WBF (1 << 10) /* Write Busy Flag */
+#define DSR_WNF (1 << 9) /* Write Next Flag */
+#define DSR_WCF (1 << 8) /* Write Complete Flag */
+#define DSR_WEF (1 << 7) /* Write Error Flag */
+#define DSR_CAF (1 << 4) /* Clock Alarm Flag */
+#define DSR_NVF (1 << 1) /* Non-Valid Flag */
+#define DSR_SVF (1 << 0) /* Security Violation Flag */
+
+#define DIER_WNIE (1 << 9) /* Write Next Interrupt Enable */
+#define DIER_WCIE (1 << 8) /* Write Complete Interrupt Enable */
+#define DIER_WEIE (1 << 7) /* Write Error Interrupt Enable */
+#define DIER_CAIE (1 << 4) /* Clock Alarm Interrupt Enable */
+
+/* Driver Private Data */
+
+struct imxdi_data {
+ struct imxdi_regs __iomem *regs;
+ int init_done;
+};
+
+static struct imxdi_data data;
+
+/*
+ * This function attempts to clear the dryice write-error flag.
+ *
+ * A dryice write error is similar to a bus fault and should not occur in
+ * normal operation. Clearing the flag requires another write, so the root
+ * cause of the problem may need to be fixed before the flag can be cleared.
+ */
+static void clear_write_error(void)
+{
+ int cnt;
+
+ puts("### Warning: RTC - Register write error!\n");
+
+ /* clear the write error flag */
+ __raw_writel(DSR_WEF, &data.regs->dsr);
+
+ /* wait for it to take effect */
+ for (cnt = 0; cnt < 1000; cnt++) {
+ if ((__raw_readl(&data.regs->dsr) & DSR_WEF) == 0)
+ return;
+ udelay(10);
+ }
+ puts("### Error: RTC - Cannot clear write-error flag!\n");
+}
+
+/*
+ * Write a dryice register and wait until it completes.
+ *
+ * Use interrupt flags to determine when the write has completed.
+ */
+#define DI_WRITE_WAIT(val, reg) \
+( \
+ /* do the register write */ \
+ __raw_writel((val), &data.regs->reg), \
+ \
+ di_write_wait((val), #reg) \
+)
+static int di_write_wait(u32 val, const char *reg)
+{
+ int cnt;
+ int ret = 0;
+ int rc = 0;
+
+ /* wait for the write to finish */
+ for (cnt = 0; cnt < 100; cnt++) {
+ if ((__raw_readl(&data.regs->dsr) & (DSR_WCF | DSR_WEF)) != 0) {
+ ret = 1;
+ break;
+ }
+ udelay(10);
+ }
+ if (ret == 0)
+ printf("### Warning: RTC - Write-wait timeout "
+ "val = 0x%.8x reg = %s\n", val, reg);
+
+ /* check for write error */
+ if (__raw_readl(&data.regs->dsr) & DSR_WEF) {
+ clear_write_error();
+ rc = -1;
+ }
+
+ return rc;
+}
+
+/*
+ * Initialize dryice hardware
+ */
+static int di_init(void)
+{
+ int rc = 0;
+
+ data.regs = (struct imxdi_regs __iomem *)IMX_DRYICE_BASE;
+
+ /* mask all interrupts */
+ __raw_writel(0, &data.regs->dier);
+
+ /* put dryice into valid state */
+ if (__raw_readl(&data.regs->dsr) & DSR_NVF) {
+ rc = DI_WRITE_WAIT(DSR_NVF | DSR_SVF, dsr);
+ if (rc)
+ goto err;
+ }
+
+ /* initialize alarm */
+ rc = DI_WRITE_WAIT(DCAMR_UNSET, dcamr);
+ if (rc)
+ goto err;
+ rc = DI_WRITE_WAIT(0, dcalr);
+ if (rc)
+ goto err;
+
+ /* clear alarm flag */
+ if (__raw_readl(&data.regs->dsr) & DSR_CAF) {
+ rc = DI_WRITE_WAIT(DSR_CAF, dsr);
+ if (rc)
+ goto err;
+ }
+
+ /* the timer won't count if it has never been written to */
+ if (__raw_readl(&data.regs->dtcmr) == 0) {
+ rc = DI_WRITE_WAIT(0, dtcmr);
+ if (rc)
+ goto err;
+ }
+
+ /* start keeping time */
+ if (!(__raw_readl(&data.regs->dcr) & DCR_TCE)) {
+ rc = DI_WRITE_WAIT(__raw_readl(&data.regs->dcr) | DCR_TCE, dcr);
+ if (rc)
+ goto err;
+ }
+
+ data.init_done = 1;
+ return 0;
+
+err:
+ return rc;
+}
+
+int rtc_get(struct rtc_time *tmp)
+{
+ unsigned long now;
+ int rc = 0;
+
+ if (!data.init_done) {
+ rc = di_init();
+ if (rc)
+ goto err;
+ }
+
+ now = __raw_readl(&data.regs->dtcmr);
+ rtc_to_tm(now, tmp);
+
+err:
+ return rc;
+}
+
+int rtc_set(struct rtc_time *tmp)
+{
+ unsigned long now;
+ int rc;
+
+ if (!data.init_done) {
+ rc = di_init();
+ if (rc)
+ goto err;
+ }
+
+ now = rtc_mktime(tmp);
+ /* zero the fractional part first */
+ rc = DI_WRITE_WAIT(0, dtclr);
+ if (rc == 0)
+ rc = DI_WRITE_WAIT(now, dtcmr);
+
+err:
+ return rc;
+}
+
+void rtc_reset(void)
+{
+ di_init();
+}
diff --git a/roms/u-boot/drivers/rtc/isl1208.c b/roms/u-boot/drivers/rtc/isl1208.c
new file mode 100644
index 000000000..59a60b75b
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/isl1208.c
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2008
+ * Tor Krill, Excito Elektronik i Skåne , tor@excito.com
+ *
+ * Modelled after the ds1337 driver
+ */
+
+/*
+ * Date & Time support (no alarms) for Intersil
+ * ISL1208 Real Time Clock (RTC).
+ */
+
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <rtc.h>
+#include <i2c.h>
+
+/*---------------------------------------------------------------------*/
+#ifdef DEBUG_RTC
+#define DEBUGR(fmt,args...) printf(fmt ,##args)
+#else
+#define DEBUGR(fmt,args...)
+#endif
+/*---------------------------------------------------------------------*/
+
+/*
+ * RTC register addresses
+ */
+
+#define RTC_SEC_REG_ADDR 0x0
+#define RTC_MIN_REG_ADDR 0x1
+#define RTC_HR_REG_ADDR 0x2
+#define RTC_DATE_REG_ADDR 0x3
+#define RTC_MON_REG_ADDR 0x4
+#define RTC_YR_REG_ADDR 0x5
+#define RTC_DAY_REG_ADDR 0x6
+#define RTC_STAT_REG_ADDR 0x7
+/*
+ * RTC control register bits
+ */
+
+/*
+ * RTC status register bits
+ */
+#define RTC_STAT_BIT_ARST 0x80 /* AUTO RESET ENABLE BIT */
+#define RTC_STAT_BIT_XTOSCB 0x40 /* CRYSTAL OSCILLATOR ENABLE BIT */
+#define RTC_STAT_BIT_WRTC 0x10 /* WRITE RTC ENABLE BIT */
+#define RTC_STAT_BIT_ALM 0x04 /* ALARM BIT */
+#define RTC_STAT_BIT_BAT 0x02 /* BATTERY BIT */
+#define RTC_STAT_BIT_RTCF 0x01 /* REAL TIME CLOCK FAIL BIT */
+
+/*
+ * Read an RTC register
+ */
+
+static int isl1208_rtc_read8(struct udevice *dev, unsigned int reg)
+{
+ return dm_i2c_reg_read(dev, reg);
+}
+
+/*
+ * Write an RTC register
+ */
+
+static int isl1208_rtc_write8(struct udevice *dev, unsigned int reg, int val)
+{
+ return dm_i2c_reg_write(dev, reg, val);
+}
+
+/*
+ * Get the current time from the RTC
+ */
+
+static int isl1208_rtc_get(struct udevice *dev, struct rtc_time *tmp)
+{
+ int ret;
+ uchar buf[8], val;
+
+ ret = dm_i2c_read(dev, 0, buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+
+ if (buf[RTC_STAT_REG_ADDR] & RTC_STAT_BIT_RTCF) {
+ printf ("### Warning: RTC oscillator has stopped\n");
+ ret = dm_i2c_read(dev, RTC_STAT_REG_ADDR, &val, sizeof(val));
+ if (ret < 0)
+ return ret;
+
+ val = val & ~(RTC_STAT_BIT_BAT | RTC_STAT_BIT_RTCF);
+ ret = dm_i2c_write(dev, RTC_STAT_REG_ADDR, &val, sizeof(val));
+ if (ret < 0)
+ return ret;
+ }
+
+ tmp->tm_sec = bcd2bin(buf[RTC_SEC_REG_ADDR] & 0x7F);
+ tmp->tm_min = bcd2bin(buf[RTC_MIN_REG_ADDR] & 0x7F);
+ tmp->tm_hour = bcd2bin(buf[RTC_HR_REG_ADDR] & 0x3F);
+ tmp->tm_mday = bcd2bin(buf[RTC_DATE_REG_ADDR] & 0x3F);
+ tmp->tm_mon = bcd2bin(buf[RTC_MON_REG_ADDR] & 0x1F);
+ tmp->tm_year = bcd2bin(buf[RTC_YR_REG_ADDR]) + 2000;
+ tmp->tm_wday = bcd2bin(buf[RTC_DAY_REG_ADDR] & 0x07);
+ tmp->tm_yday = 0;
+ tmp->tm_isdst= 0;
+
+ DEBUGR ("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ return 0;
+}
+
+/*
+ * Set the RTC
+ */
+static int isl1208_rtc_set(struct udevice *dev, const struct rtc_time *tmp)
+{
+ int ret;
+ uchar val, buf[7];
+
+ DEBUGR ("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ if (tmp->tm_year < 2000 || tmp->tm_year > 2099)
+ printf("WARNING: year should be between 2000 and 2099!\n");
+
+ /* enable write */
+ ret = dm_i2c_read(dev, RTC_STAT_REG_ADDR, &val, sizeof(val));
+ if (ret < 0)
+ return ret;
+
+ val = val | RTC_STAT_BIT_WRTC;
+
+ ret = dm_i2c_write(dev, RTC_STAT_REG_ADDR, &val, sizeof(val));
+ if (ret < 0)
+ return ret;
+
+ buf[RTC_YR_REG_ADDR] = bin2bcd(tmp->tm_year % 100);
+ buf[RTC_MON_REG_ADDR] = bin2bcd(tmp->tm_mon);
+ buf[RTC_DAY_REG_ADDR] = bin2bcd(tmp->tm_wday);
+ buf[RTC_DATE_REG_ADDR] = bin2bcd(tmp->tm_mday);
+ buf[RTC_HR_REG_ADDR] = bin2bcd(tmp->tm_hour) | 0x80; /* 24h clock */
+ buf[RTC_MIN_REG_ADDR] = bin2bcd(tmp->tm_min);
+ buf[RTC_SEC_REG_ADDR] = bin2bcd(tmp->tm_sec);
+
+ ret = dm_i2c_write(dev, 0, buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+
+ /* disable write */
+ ret = dm_i2c_read(dev, RTC_STAT_REG_ADDR, &val, sizeof(val));
+ if (ret < 0)
+ return ret;
+
+ val = val & ~RTC_STAT_BIT_WRTC;
+ ret = dm_i2c_write(dev, RTC_STAT_REG_ADDR, &val, sizeof(val));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int isl1208_rtc_reset(struct udevice *dev)
+{
+ return 0;
+}
+
+static int isl1208_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 isl1208_rtc_ops = {
+ .get = isl1208_rtc_get,
+ .set = isl1208_rtc_set,
+ .reset = isl1208_rtc_reset,
+ .read8 = isl1208_rtc_read8,
+ .write8 = isl1208_rtc_write8,
+};
+
+static const struct udevice_id isl1208_rtc_ids[] = {
+ { .compatible = "isil,isl1208" },
+ { }
+};
+
+U_BOOT_DRIVER(rtc_isl1208) = {
+ .name = "rtc-isl1208",
+ .id = UCLASS_RTC,
+ .probe = isl1208_probe,
+ .of_match = isl1208_rtc_ids,
+ .ops = &isl1208_rtc_ops,
+};
diff --git a/roms/u-boot/drivers/rtc/m41t11.c b/roms/u-boot/drivers/rtc/m41t11.c
new file mode 100644
index 000000000..706b7188c
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/m41t11.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2002
+ * Andrew May, Viasat Inc, amay@viasat.com
+ */
+
+/*
+ * M41T11 Serial Access Timekeeper(R) SRAM
+ * can you believe a trademark on that?
+ */
+
+/* #define DEBUG 1 */
+
+#include <common.h>
+#include <command.h>
+#include <log.h>
+#include <rtc.h>
+#include <i2c.h>
+
+/*
+ I Don't have an example config file but this
+ is what should be done.
+
+#define CONFIG_RTC_M41T11 1
+#define CONFIG_SYS_I2C_RTC_ADDR 0x68
+#if 0
+#define CONFIG_SYS_M41T11_EXT_CENTURY_DATA
+#else
+#define CONFIG_SYS_M41T11_BASE_YEAR 2000
+#endif
+*/
+
+/* ------------------------------------------------------------------------- */
+/*
+ these are simple defines for the chip local to here so they aren't too
+ verbose
+ DAY/DATE aren't nice but that is how they are on the data sheet
+*/
+#define RTC_SEC_ADDR 0x0
+#define RTC_MIN_ADDR 0x1
+#define RTC_HOUR_ADDR 0x2
+#define RTC_DAY_ADDR 0x3
+#define RTC_DATE_ADDR 0x4
+#define RTC_MONTH_ADDR 0x5
+#define RTC_YEARS_ADDR 0x6
+
+#define RTC_REG_CNT 7
+
+#define RTC_CONTROL_ADDR 0x7
+
+
+#ifndef CONFIG_SYS_M41T11_EXT_CENTURY_DATA
+
+#define REG_CNT (RTC_REG_CNT+1)
+
+/*
+ you only get 00-99 for the year we will asume you
+ want from the year 2000 if you don't set the config
+*/
+#ifndef CONFIG_SYS_M41T11_BASE_YEAR
+#define CONFIG_SYS_M41T11_BASE_YEAR 2000
+#endif
+
+#else
+/* we will store extra year info in byte 9*/
+#define M41T11_YEAR_DATA 0x8
+#define M41T11_YEAR_SIZE 1
+#define REG_CNT (RTC_REG_CNT+1+M41T11_YEAR_SIZE)
+#endif
+
+#define M41T11_STORAGE_SZ (64-REG_CNT)
+
+int rtc_get (struct rtc_time *tmp)
+{
+ int rel = 0;
+ uchar data[RTC_REG_CNT];
+
+ i2c_read(CONFIG_SYS_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, data, RTC_REG_CNT);
+
+ if( data[RTC_SEC_ADDR] & 0x80 ){
+ printf( "m41t11 RTC Clock stopped!!!\n" );
+ rel = -1;
+ }
+ tmp->tm_sec = bcd2bin (data[RTC_SEC_ADDR] & 0x7F);
+ tmp->tm_min = bcd2bin (data[RTC_MIN_ADDR] & 0x7F);
+ tmp->tm_hour = bcd2bin (data[RTC_HOUR_ADDR] & 0x3F);
+ tmp->tm_mday = bcd2bin (data[RTC_DATE_ADDR] & 0x3F);
+ tmp->tm_mon = bcd2bin (data[RTC_MONTH_ADDR]& 0x1F);
+#ifndef CONFIG_SYS_M41T11_EXT_CENTURY_DATA
+ tmp->tm_year = CONFIG_SYS_M41T11_BASE_YEAR
+ + bcd2bin(data[RTC_YEARS_ADDR])
+ + ((data[RTC_HOUR_ADDR]&0x40) ? 100 : 0);
+#else
+ {
+ unsigned char cent;
+ i2c_read(CONFIG_SYS_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, &cent, M41T11_YEAR_SIZE);
+ if( !(data[RTC_HOUR_ADDR] & 0x80) ){
+ printf( "m41t11 RTC: cann't keep track of years without CEB set\n" );
+ rel = -1;
+ }
+ if( (cent & 0x1) != ((data[RTC_HOUR_ADDR]&0x40)>>7) ){
+ /*century flip store off new year*/
+ cent += 1;
+ i2c_write(CONFIG_SYS_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, &cent, M41T11_YEAR_SIZE);
+ }
+ tmp->tm_year =((int)cent*100)+bcd2bin(data[RTC_YEARS_ADDR]);
+ }
+#endif
+ tmp->tm_wday = bcd2bin (data[RTC_DAY_ADDR] & 0x07);
+ tmp->tm_yday = 0;
+ tmp->tm_isdst= 0;
+
+ debug("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ return rel;
+}
+
+int rtc_set (struct rtc_time *tmp)
+{
+ uchar data[RTC_REG_CNT];
+
+ debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ data[RTC_SEC_ADDR] = bin2bcd(tmp->tm_sec) & 0x7F;/*just in case*/
+ data[RTC_MIN_ADDR] = bin2bcd(tmp->tm_min);
+ data[RTC_HOUR_ADDR] = bin2bcd(tmp->tm_hour) & 0x3F;/*handle cent stuff later*/
+ data[RTC_DATE_ADDR] = bin2bcd(tmp->tm_mday) & 0x3F;
+ data[RTC_MONTH_ADDR] = bin2bcd(tmp->tm_mon);
+ data[RTC_DAY_ADDR] = bin2bcd(tmp->tm_wday) & 0x07;
+
+ data[RTC_HOUR_ADDR] |= 0x80;/*we will always use CEB*/
+
+ data[RTC_YEARS_ADDR] = bin2bcd(tmp->tm_year%100);/*same thing either way*/
+#ifndef CONFIG_SYS_M41T11_EXT_CENTURY_DATA
+ if( ((tmp->tm_year - CONFIG_SYS_M41T11_BASE_YEAR) > 200) ||
+ (tmp->tm_year < CONFIG_SYS_M41T11_BASE_YEAR) ){
+ printf( "m41t11 RTC setting year out of range!!need recompile\n" );
+ }
+ data[RTC_HOUR_ADDR] |= (tmp->tm_year - CONFIG_SYS_M41T11_BASE_YEAR) > 100 ? 0x40 : 0;
+#else
+ {
+ unsigned char cent;
+ cent = tmp->tm_year ? tmp->tm_year / 100 : 0;
+ data[RTC_HOUR_ADDR] |= (cent & 0x1) ? 0x40 : 0;
+ i2c_write(CONFIG_SYS_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, &cent, M41T11_YEAR_SIZE);
+ }
+#endif
+ i2c_write(CONFIG_SYS_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, data, RTC_REG_CNT);
+
+ return 0;
+}
+
+void rtc_reset (void)
+{
+ unsigned char val;
+ /* clear all control & status registers */
+ i2c_read(CONFIG_SYS_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, &val, 1);
+ val = val & 0x7F;/*make sure we are running*/
+ i2c_write(CONFIG_SYS_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, &val, RTC_REG_CNT);
+
+ i2c_read(CONFIG_SYS_I2C_RTC_ADDR, RTC_CONTROL_ADDR, 1, &val, 1);
+ val = val & 0x3F;/*turn off freq test keep calibration*/
+ i2c_write(CONFIG_SYS_I2C_RTC_ADDR, RTC_CONTROL_ADDR, 1, &val, 1);
+}
diff --git a/roms/u-boot/drivers/rtc/m41t60.c b/roms/u-boot/drivers/rtc/m41t60.c
new file mode 100644
index 000000000..692042b93
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/m41t60.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2007
+ * Larry Johnson, lrj@acm.org
+ *
+ * based on rtc/m41t11.c which is ...
+ *
+ * (C) Copyright 2002
+ * Andrew May, Viasat Inc, amay@viasat.com
+ */
+
+/*
+ * STMicroelectronics M41T60 serial access real-time clock
+ */
+
+/* #define DEBUG 1 */
+
+#include <common.h>
+#include <command.h>
+#include <env.h>
+#include <log.h>
+#include <rtc.h>
+#include <i2c.h>
+
+/*
+ * Convert between century and "century bits" (CB1 and CB0). These routines
+ * assume years are in the range 1900 - 2299.
+ */
+
+static unsigned char year2cb(unsigned const year)
+{
+ if (year < 1900 || year >= 2300)
+ printf("M41T60 RTC: year %d out of range\n", year);
+
+ return (year / 100) & 0x3;
+}
+
+static unsigned cb2year(unsigned const cb)
+{
+ return 1900 + 100 * ((cb + 1) & 0x3);
+}
+
+/*
+ * These are simple defines for the chip local to here so they aren't too
+ * verbose. DAY/DATE aren't nice but that is how they are on the data sheet.
+ */
+#define RTC_SEC 0x0
+#define RTC_MIN 0x1
+#define RTC_HOUR 0x2
+#define RTC_DAY 0x3
+#define RTC_DATE 0x4
+#define RTC_MONTH 0x5
+#define RTC_YEAR 0x6
+
+#define RTC_REG_CNT 7
+
+#define RTC_CTRL 0x7
+
+#if defined(DEBUG)
+static void rtc_dump(char const *const label)
+{
+ uchar data[8];
+
+ if (i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, data, sizeof(data))) {
+ printf("I2C read failed in rtc_dump()\n");
+ return;
+ }
+ printf("RTC dump %s: %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n",
+ label, data[0], data[1], data[2], data[3],
+ data[4], data[5], data[6], data[7]);
+}
+#else
+#define rtc_dump(label)
+#endif
+
+static uchar *rtc_validate(void)
+{
+ /*
+ * This routine uses the OUT bit and the validity of the time values to
+ * determine whether there has been an initial power-up since the last
+ * time the routine was run. It assumes that the OUT bit is not being
+ * used for any other purpose.
+ */
+ static const uchar daysInMonth[0x13] = {
+ 0x00, 0x31, 0x29, 0x31, 0x30, 0x31, 0x30, 0x31,
+ 0x31, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x31, 0x30, 0x31
+ };
+ static uchar data[8];
+ uchar min, date, month, years;
+
+ rtc_dump("begin validate");
+ if (i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, data, sizeof(data))) {
+ printf("I2C read failed in rtc_validate()\n");
+ return 0;
+ }
+ /*
+ * If the OUT bit is "1", there has been a loss of power, so stop the
+ * oscillator so it can be "kick-started" as per data sheet.
+ */
+ if (0x00 != (data[RTC_CTRL] & 0x80)) {
+ printf("M41T60 RTC clock lost power.\n");
+ data[RTC_SEC] = 0x80;
+ if (i2c_write(CONFIG_SYS_I2C_RTC_ADDR, RTC_SEC, 1, data, 1)) {
+ printf("I2C write failed in rtc_validate()\n");
+ return 0;
+ }
+ }
+ /*
+ * If the oscillator is stopped or the date is invalid, then reset the
+ * OUT bit to "0", reset the date registers, and start the oscillator.
+ */
+ min = data[RTC_MIN] & 0x7F;
+ date = data[RTC_DATE];
+ month = data[RTC_MONTH] & 0x3F;
+ years = data[RTC_YEAR];
+ if (0x59 < data[RTC_SEC] || 0x09 < (data[RTC_SEC] & 0x0F) ||
+ 0x59 < min || 0x09 < (min & 0x0F) ||
+ 0x23 < data[RTC_HOUR] || 0x09 < (data[RTC_HOUR] & 0x0F) ||
+ 0x07 < data[RTC_DAY] || 0x00 == data[RTC_DAY] ||
+ 0x12 < month ||
+ 0x99 < years || 0x09 < (years & 0x0F) ||
+ daysInMonth[month] < date || 0x09 < (date & 0x0F) || 0x00 == date ||
+ (0x29 == date && 0x02 == month &&
+ ((0x00 != (years & 0x03)) ||
+ (0x00 == years && 0x00 != (data[RTC_MONTH] & 0xC0))))) {
+ printf("Resetting M41T60 RTC clock.\n");
+ /*
+ * Set to 00:00:00 1900-01-01 (Monday)
+ */
+ data[RTC_SEC] = 0x00;
+ data[RTC_MIN] &= 0x80; /* preserve OFIE bit */
+ data[RTC_HOUR] = 0x00;
+ data[RTC_DAY] = 0x02;
+ data[RTC_DATE] = 0x01;
+ data[RTC_MONTH] = 0xC1;
+ data[RTC_YEAR] = 0x00;
+ data[RTC_CTRL] &= 0x7F; /* reset OUT bit */
+
+ if (i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, data, sizeof(data))) {
+ printf("I2C write failed in rtc_validate()\n");
+ return 0;
+ }
+ }
+ return data;
+}
+
+int rtc_get(struct rtc_time *tmp)
+{
+ uchar const *const data = rtc_validate();
+
+ if (!data)
+ return -1;
+
+ tmp->tm_sec = bcd2bin(data[RTC_SEC] & 0x7F);
+ tmp->tm_min = bcd2bin(data[RTC_MIN] & 0x7F);
+ tmp->tm_hour = bcd2bin(data[RTC_HOUR] & 0x3F);
+ tmp->tm_mday = bcd2bin(data[RTC_DATE] & 0x3F);
+ tmp->tm_mon = bcd2bin(data[RTC_MONTH] & 0x1F);
+ tmp->tm_year = cb2year(data[RTC_MONTH] >> 6) + bcd2bin(data[RTC_YEAR]);
+ tmp->tm_wday = bcd2bin(data[RTC_DAY] & 0x07) - 1;
+ tmp->tm_yday = 0;
+ tmp->tm_isdst = 0;
+
+ debug("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ return 0;
+}
+
+int rtc_set(struct rtc_time *tmp)
+{
+ uchar *const data = rtc_validate();
+
+ if (!data)
+ return -1;
+
+ debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ data[RTC_SEC] = (data[RTC_SEC] & 0x80) | (bin2bcd(tmp->tm_sec) & 0x7F);
+ data[RTC_MIN] = (data[RTC_MIN] & 0X80) | (bin2bcd(tmp->tm_min) & 0X7F);
+ data[RTC_HOUR] = bin2bcd(tmp->tm_hour) & 0x3F;
+ data[RTC_DATE] = bin2bcd(tmp->tm_mday) & 0x3F;
+ data[RTC_MONTH] = bin2bcd(tmp->tm_mon) & 0x1F;
+ data[RTC_YEAR] = bin2bcd(tmp->tm_year % 100);
+ data[RTC_MONTH] |= year2cb(tmp->tm_year) << 6;
+ data[RTC_DAY] = bin2bcd(tmp->tm_wday + 1) & 0x07;
+ if (i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, data, RTC_REG_CNT)) {
+ printf("I2C write failed in rtc_set()\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+void rtc_reset(void)
+{
+ uchar *const data = rtc_validate();
+ char const *const s = env_get("rtccal");
+
+ if (!data)
+ return;
+
+ rtc_dump("begin reset");
+ /*
+ * If environmental variable "rtccal" is present, it must be a hex value
+ * between 0x00 and 0x3F, inclusive. The five least-significan bits
+ * represent the calibration magnitude, and the sixth bit the sign bit.
+ * If these do not match the contents of the hardware register, that
+ * register is updated. The value 0x00 imples no correction. Consult
+ * the M41T60 documentation for further details.
+ */
+ if (s) {
+ unsigned long const l = simple_strtoul(s, 0, 16);
+
+ if (l <= 0x3F) {
+ if ((data[RTC_CTRL] & 0x3F) != l) {
+ printf("Setting RTC calibration to 0x%02lX\n",
+ l);
+ data[RTC_CTRL] &= 0xC0;
+ data[RTC_CTRL] |= (uchar) l;
+ }
+ } else
+ printf("environment parameter \"rtccal\" not valid: "
+ "ignoring\n");
+ }
+ /*
+ * Turn off frequency test.
+ */
+ data[RTC_CTRL] &= 0xBF;
+ if (i2c_write(CONFIG_SYS_I2C_RTC_ADDR, RTC_CTRL, 1, data + RTC_CTRL, 1)) {
+ printf("I2C write failed in rtc_reset()\n");
+ return;
+ }
+ rtc_dump("end reset");
+}
diff --git a/roms/u-boot/drivers/rtc/m41t62.c b/roms/u-boot/drivers/rtc/m41t62.c
new file mode 100644
index 000000000..0a4e12d69
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/m41t62.c
@@ -0,0 +1,356 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2018
+ * Lukasz Majewski, DENX Software Engineering, lukma@denx.de.
+ *
+ * (C) Copyright 2008
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * based on a the Linux rtc-m41t80.c driver which is:
+ * Alexander Bigga <ab@mycable.de>, 2006 (c) mycable GmbH
+ */
+
+/*
+ * Date & Time support for STMicroelectronics M41T62
+ */
+
+/* #define DEBUG */
+
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <log.h>
+#include <rtc.h>
+#include <i2c.h>
+#include <linux/log2.h>
+#include <linux/delay.h>
+
+#define M41T62_REG_SSEC 0
+#define M41T62_REG_SEC 1
+#define M41T62_REG_MIN 2
+#define M41T62_REG_HOUR 3
+#define M41T62_REG_WDAY 4
+#define M41T62_REG_DAY 5
+#define M41T62_REG_MON 6
+#define M41T62_REG_YEAR 7
+#define M41T62_REG_ALARM_MON 0xa
+#define M41T62_REG_ALARM_DAY 0xb
+#define M41T62_REG_ALARM_HOUR 0xc
+#define M41T62_REG_ALARM_MIN 0xd
+#define M41T62_REG_ALARM_SEC 0xe
+#define M41T62_REG_FLAGS 0xf
+
+#define M41T62_DATETIME_REG_SIZE (M41T62_REG_YEAR + 1)
+#define M41T62_ALARM_REG_SIZE \
+ (M41T62_REG_ALARM_SEC + 1 - M41T62_REG_ALARM_MON)
+
+#define M41T62_SEC_ST (1 << 7) /* ST: Stop Bit */
+#define M41T62_ALMON_AFE (1 << 7) /* AFE: AF Enable Bit */
+#define M41T62_ALMON_SQWE (1 << 6) /* SQWE: SQW Enable Bit */
+#define M41T62_ALHOUR_HT (1 << 6) /* HT: Halt Update Bit */
+#define M41T62_FLAGS_AF (1 << 6) /* AF: Alarm Flag Bit */
+#define M41T62_FLAGS_OF (1 << 2) /* OF: Oscillator Flag Bit */
+#define M41T62_FLAGS_BATT_LOW (1 << 4) /* BL: Battery Low Bit */
+
+#define M41T62_WDAY_SQW_FREQ_MASK 0xf0
+#define M41T62_WDAY_SQW_FREQ_SHIFT 4
+
+#define M41T62_SQW_MAX_FREQ 32768
+
+#define M41T62_FEATURE_HT (1 << 0)
+#define M41T62_FEATURE_BL (1 << 1)
+
+#define M41T80_ALHOUR_HT (1 << 6) /* HT: Halt Update Bit */
+
+static void m41t62_update_rtc_time(struct rtc_time *tm, u8 *buf)
+{
+ debug("%s: raw read data - sec=%02x, min=%02x, hr=%02x, "
+ "mday=%02x, mon=%02x, year=%02x, wday=%02x, y2k=%02x\n",
+ __FUNCTION__,
+ buf[0], buf[1], buf[2], buf[3],
+ buf[4], buf[5], buf[6], buf[7]);
+
+ tm->tm_sec = bcd2bin(buf[M41T62_REG_SEC] & 0x7f);
+ tm->tm_min = bcd2bin(buf[M41T62_REG_MIN] & 0x7f);
+ tm->tm_hour = bcd2bin(buf[M41T62_REG_HOUR] & 0x3f);
+ tm->tm_mday = bcd2bin(buf[M41T62_REG_DAY] & 0x3f);
+ tm->tm_wday = buf[M41T62_REG_WDAY] & 0x07;
+ tm->tm_mon = bcd2bin(buf[M41T62_REG_MON] & 0x1f);
+
+ /* assume 20YY not 19YY, and ignore the Century Bit */
+ /* U-Boot needs to add 1900 here */
+ tm->tm_year = bcd2bin(buf[M41T62_REG_YEAR]) + 100 + 1900;
+
+ debug("%s: tm is secs=%d, mins=%d, hours=%d, "
+ "mday=%d, mon=%d, year=%d, wday=%d\n",
+ __FUNCTION__,
+ tm->tm_sec, tm->tm_min, tm->tm_hour,
+ tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+}
+
+static void m41t62_set_rtc_buf(const struct rtc_time *tm, u8 *buf)
+{
+ debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ /* Merge time-data and register flags into buf[0..7] */
+ buf[M41T62_REG_SSEC] = 0;
+ buf[M41T62_REG_SEC] =
+ bin2bcd(tm->tm_sec) | (buf[M41T62_REG_SEC] & ~0x7f);
+ buf[M41T62_REG_MIN] =
+ bin2bcd(tm->tm_min) | (buf[M41T62_REG_MIN] & ~0x7f);
+ buf[M41T62_REG_HOUR] =
+ bin2bcd(tm->tm_hour) | (buf[M41T62_REG_HOUR] & ~0x3f) ;
+ buf[M41T62_REG_WDAY] =
+ (tm->tm_wday & 0x07) | (buf[M41T62_REG_WDAY] & ~0x07);
+ buf[M41T62_REG_DAY] =
+ bin2bcd(tm->tm_mday) | (buf[M41T62_REG_DAY] & ~0x3f);
+ buf[M41T62_REG_MON] =
+ bin2bcd(tm->tm_mon) | (buf[M41T62_REG_MON] & ~0x1f);
+ /* assume 20YY not 19YY */
+ buf[M41T62_REG_YEAR] = bin2bcd(tm->tm_year % 100);
+}
+
+#ifdef CONFIG_DM_RTC
+static int m41t62_rtc_get(struct udevice *dev, struct rtc_time *tm)
+{
+ u8 buf[M41T62_DATETIME_REG_SIZE];
+ int ret;
+
+ ret = dm_i2c_read(dev, 0, buf, sizeof(buf));
+ if (ret)
+ return ret;
+
+ m41t62_update_rtc_time(tm, buf);
+
+ return 0;
+}
+
+static int m41t62_rtc_set(struct udevice *dev, const struct rtc_time *tm)
+{
+ u8 buf[M41T62_DATETIME_REG_SIZE];
+ int ret;
+
+ ret = dm_i2c_read(dev, 0, buf, sizeof(buf));
+ if (ret)
+ return ret;
+
+ m41t62_set_rtc_buf(tm, buf);
+
+ ret = dm_i2c_write(dev, 0, buf, sizeof(buf));
+ if (ret) {
+ printf("I2C write failed in %s()\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int m41t62_sqw_enable(struct udevice *dev, bool enable)
+{
+ u8 val;
+ int ret;
+
+ ret = dm_i2c_read(dev, M41T62_REG_ALARM_MON, &val, sizeof(val));
+ if (ret)
+ return ret;
+
+ if (enable)
+ val |= M41T62_ALMON_SQWE;
+ else
+ val &= ~M41T62_ALMON_SQWE;
+
+ return dm_i2c_write(dev, M41T62_REG_ALARM_MON, &val, sizeof(val));
+}
+
+static int m41t62_sqw_set_rate(struct udevice *dev, unsigned int rate)
+{
+ u8 val, newval, sqwrateval;
+ int ret;
+
+ if (rate >= M41T62_SQW_MAX_FREQ)
+ sqwrateval = 1;
+ else if (rate >= M41T62_SQW_MAX_FREQ / 4)
+ sqwrateval = 2;
+ else if (rate)
+ sqwrateval = 15 - ilog2(rate);
+
+ ret = dm_i2c_read(dev, M41T62_REG_WDAY, &val, sizeof(val));
+ if (ret)
+ return ret;
+
+ newval = val;
+ newval &= ~M41T62_WDAY_SQW_FREQ_MASK;
+ newval |= (sqwrateval << M41T62_WDAY_SQW_FREQ_SHIFT);
+
+ /*
+ * Try to avoid writing unchanged values. Writing to this register
+ * will reset the internal counter pipeline and thus affect system
+ * time.
+ */
+ if (newval == val)
+ return 0;
+
+ return dm_i2c_write(dev, M41T62_REG_WDAY, &newval, sizeof(newval));
+}
+
+static int m41t62_rtc_restart_osc(struct udevice *dev)
+{
+ u8 val;
+ int ret;
+
+ /* 0. check if oscillator failure happened */
+ ret = dm_i2c_read(dev, M41T62_REG_FLAGS, &val, sizeof(val));
+ if (ret)
+ return ret;
+ if (!(val & M41T62_FLAGS_OF))
+ return 0;
+
+ ret = dm_i2c_read(dev, M41T62_REG_SEC, &val, sizeof(val));
+ if (ret)
+ return ret;
+
+ /* 1. Set stop bit */
+ val |= M41T62_SEC_ST;
+ ret = dm_i2c_write(dev, M41T62_REG_ALARM_HOUR, &val, sizeof(val));
+ if (ret)
+ return ret;
+
+ /* 2. Clear stop bit */
+ val &= ~M41T62_SEC_ST;
+ ret = dm_i2c_write(dev, M41T62_REG_ALARM_HOUR, &val, sizeof(val));
+ if (ret)
+ return ret;
+
+ /* 3. wait 4 seconds */
+ mdelay(4000);
+
+ ret = dm_i2c_read(dev, M41T62_REG_FLAGS, &val, sizeof(val));
+ if (ret)
+ return ret;
+
+ /* 4. clear M41T62_FLAGS_OF bit */
+ val &= ~M41T62_FLAGS_OF;
+ ret = dm_i2c_write(dev, M41T62_REG_FLAGS, &val, sizeof(val));
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int m41t62_rtc_clear_ht(struct udevice *dev)
+{
+ u8 val;
+ int ret;
+
+ /*
+ * M41T82: Make sure HT (Halt Update) bit is cleared.
+ * This bit is 0 in M41T62 so its save to clear it always.
+ */
+
+ ret = dm_i2c_read(dev, M41T62_REG_ALARM_HOUR, &val, sizeof(val));
+ if (ret)
+ return ret;
+ val &= ~M41T80_ALHOUR_HT;
+ ret = dm_i2c_write(dev, M41T62_REG_ALARM_HOUR, &val, sizeof(val));
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int m41t62_rtc_reset(struct udevice *dev)
+{
+ int ret;
+
+ ret = m41t62_rtc_restart_osc(dev);
+ if (ret)
+ return ret;
+
+ ret = m41t62_rtc_clear_ht(dev);
+ if (ret)
+ return ret;
+
+ /*
+ * Some boards feed the square wave as clock input into
+ * the SoC. This enables a 32.768kHz square wave, which is
+ * also the hardware default after power-loss.
+ */
+ ret = m41t62_sqw_set_rate(dev, 32768);
+ if (ret)
+ return ret;
+ return m41t62_sqw_enable(dev, true);
+}
+
+/*
+ * Make sure HT bit is cleared. This bit is set on entering battery backup
+ * mode, so do this before the first read access.
+ */
+static int m41t62_rtc_probe(struct udevice *dev)
+{
+ return m41t62_rtc_clear_ht(dev);
+}
+
+static const struct rtc_ops m41t62_rtc_ops = {
+ .get = m41t62_rtc_get,
+ .set = m41t62_rtc_set,
+ .reset = m41t62_rtc_reset,
+};
+
+static const struct udevice_id m41t62_rtc_ids[] = {
+ { .compatible = "st,m41t62" },
+ { .compatible = "st,m41t82" },
+ { .compatible = "st,m41st87" },
+ { .compatible = "microcrystal,rv4162" },
+ { }
+};
+
+U_BOOT_DRIVER(rtc_m41t62) = {
+ .name = "rtc-m41t62",
+ .id = UCLASS_RTC,
+ .of_match = m41t62_rtc_ids,
+ .ops = &m41t62_rtc_ops,
+ .probe = &m41t62_rtc_probe,
+};
+
+#else /* NON DM RTC code - will be removed */
+int rtc_get(struct rtc_time *tm)
+{
+ u8 buf[M41T62_DATETIME_REG_SIZE];
+
+ i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, buf, M41T62_DATETIME_REG_SIZE);
+ m41t62_update_rtc_time(tm, buf);
+
+ return 0;
+}
+
+int rtc_set(struct rtc_time *tm)
+{
+ u8 buf[M41T62_DATETIME_REG_SIZE];
+
+ i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, buf, M41T62_DATETIME_REG_SIZE);
+ m41t62_set_rtc_buf(tm, buf);
+
+ if (i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, buf,
+ M41T62_DATETIME_REG_SIZE)) {
+ printf("I2C write failed in %s()\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+void rtc_reset(void)
+{
+ u8 val;
+
+ /*
+ * M41T82: Make sure HT (Halt Update) bit is cleared.
+ * This bit is 0 in M41T62 so its save to clear it always.
+ */
+ i2c_read(CONFIG_SYS_I2C_RTC_ADDR, M41T62_REG_ALARM_HOUR, 1, &val, 1);
+ val &= ~M41T80_ALHOUR_HT;
+ i2c_write(CONFIG_SYS_I2C_RTC_ADDR, M41T62_REG_ALARM_HOUR, 1, &val, 1);
+}
+#endif /* CONFIG_DM_RTC */
diff --git a/roms/u-boot/drivers/rtc/m41t94.c b/roms/u-boot/drivers/rtc/m41t94.c
new file mode 100644
index 000000000..5b665bb01
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/m41t94.c
@@ -0,0 +1,123 @@
+/*
+ * Driver for ST M41T94 SPI RTC
+ *
+ * Taken from the Linux kernel drivier:
+ * Copyright (C) 2008 Kim B. Heino
+ *
+ * Adaptation for U-Boot:
+ * Copyright (C) 2009
+ * Albin Tonnerre, Free Electrons <albin.tonnerre@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <rtc.h>
+#include <spi.h>
+
+static struct spi_slave *slave;
+
+#define M41T94_REG_SECONDS 0x01
+#define M41T94_REG_MINUTES 0x02
+#define M41T94_REG_HOURS 0x03
+#define M41T94_REG_WDAY 0x04
+#define M41T94_REG_DAY 0x05
+#define M41T94_REG_MONTH 0x06
+#define M41T94_REG_YEAR 0x07
+#define M41T94_REG_HT 0x0c
+
+#define M41T94_BIT_HALT 0x40
+#define M41T94_BIT_STOP 0x80
+#define M41T94_BIT_CB 0x40
+#define M41T94_BIT_CEB 0x80
+
+int rtc_set(struct rtc_time *tm)
+{
+ u8 buf[8]; /* write cmd + 7 registers */
+ int ret;
+
+ if (!slave) {
+ slave = spi_setup_slave(CONFIG_M41T94_SPI_BUS,
+ CONFIG_M41T94_SPI_CS, 1000000,
+ SPI_MODE_3);
+ if (!slave)
+ return -1;
+ }
+ spi_claim_bus(slave);
+
+ buf[0] = 0x80 | M41T94_REG_SECONDS; /* write time + date */
+ buf[M41T94_REG_SECONDS] = bin2bcd(tm->tm_sec);
+ buf[M41T94_REG_MINUTES] = bin2bcd(tm->tm_min);
+ buf[M41T94_REG_HOURS] = bin2bcd(tm->tm_hour);
+ buf[M41T94_REG_WDAY] = bin2bcd(tm->tm_wday + 1);
+ buf[M41T94_REG_DAY] = bin2bcd(tm->tm_mday);
+ buf[M41T94_REG_MONTH] = bin2bcd(tm->tm_mon + 1);
+
+ buf[M41T94_REG_HOURS] |= M41T94_BIT_CEB;
+ if (tm->tm_year >= 100)
+ buf[M41T94_REG_HOURS] |= M41T94_BIT_CB;
+ buf[M41T94_REG_YEAR] = bin2bcd(tm->tm_year % 100);
+
+ ret = spi_xfer(slave, 64, buf, NULL, SPI_XFER_BEGIN | SPI_XFER_END);
+ spi_release_bus(slave);
+ return ret;
+}
+
+int rtc_get(struct rtc_time *tm)
+{
+ u8 buf[2];
+ int ret, hour;
+
+ if (!slave) {
+ slave = spi_setup_slave(CONFIG_M41T94_SPI_BUS,
+ CONFIG_M41T94_SPI_CS, 1000000,
+ SPI_MODE_3);
+ if (!slave)
+ return -1;
+ }
+ spi_claim_bus(slave);
+
+ /* clear halt update bit */
+ ret = spi_w8r8(slave, M41T94_REG_HT);
+ if (ret < 0)
+ return ret;
+ if (ret & M41T94_BIT_HALT) {
+ buf[0] = 0x80 | M41T94_REG_HT;
+ buf[1] = ret & ~M41T94_BIT_HALT;
+ spi_xfer(slave, 16, buf, NULL, SPI_XFER_BEGIN | SPI_XFER_END);
+ }
+
+ /* clear stop bit */
+ ret = spi_w8r8(slave, M41T94_REG_SECONDS);
+ if (ret < 0)
+ return ret;
+ if (ret & M41T94_BIT_STOP) {
+ buf[0] = 0x80 | M41T94_REG_SECONDS;
+ buf[1] = ret & ~M41T94_BIT_STOP;
+ spi_xfer(slave, 16, buf, NULL, SPI_XFER_BEGIN | SPI_XFER_END);
+ }
+
+ tm->tm_sec = bcd2bin(spi_w8r8(slave, M41T94_REG_SECONDS));
+ tm->tm_min = bcd2bin(spi_w8r8(slave, M41T94_REG_MINUTES));
+ hour = spi_w8r8(slave, M41T94_REG_HOURS);
+ tm->tm_hour = bcd2bin(hour & 0x3f);
+ tm->tm_wday = bcd2bin(spi_w8r8(slave, M41T94_REG_WDAY)) - 1;
+ tm->tm_mday = bcd2bin(spi_w8r8(slave, M41T94_REG_DAY));
+ tm->tm_mon = bcd2bin(spi_w8r8(slave, M41T94_REG_MONTH)) - 1;
+ tm->tm_year = bcd2bin(spi_w8r8(slave, M41T94_REG_YEAR));
+ if ((hour & M41T94_BIT_CB) || !(hour & M41T94_BIT_CEB))
+ tm->tm_year += 100;
+
+ spi_release_bus(slave);
+ return 0;
+}
+
+void rtc_reset(void)
+{
+ /*
+ * Could not be tested as the reset pin is not wired on
+ * the sbc35-ag20 board
+ */
+}
diff --git a/roms/u-boot/drivers/rtc/m48t35ax.c b/roms/u-boot/drivers/rtc/m48t35ax.c
new file mode 100644
index 000000000..1cc24ccca
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/m48t35ax.c
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2001
+ * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com.
+ */
+
+/*
+ * Date & Time support for ST Electronics M48T35Ax RTC
+ */
+
+/*#define DEBUG */
+
+
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+#include <config.h>
+
+static uchar rtc_read (uchar reg);
+static void rtc_write (uchar reg, uchar val);
+
+/* ------------------------------------------------------------------------- */
+
+int rtc_get (struct rtc_time *tmp)
+{
+ uchar sec, min, hour, cent_day, date, month, year;
+ uchar ccr; /* Clock control register */
+
+ /* Lock RTC for read using clock control register */
+ ccr = rtc_read(0);
+ ccr = ccr | 0x40;
+ rtc_write(0, ccr);
+
+ sec = rtc_read (0x1);
+ min = rtc_read (0x2);
+ hour = rtc_read (0x3);
+ cent_day= rtc_read (0x4);
+ date = rtc_read (0x5);
+ month = rtc_read (0x6);
+ year = rtc_read (0x7);
+
+ /* UNLock RTC */
+ ccr = rtc_read(0);
+ ccr = ccr & 0xBF;
+ rtc_write(0, ccr);
+
+ debug ( "Get RTC year: %02x month: %02x date: %02x cent_day: %02x "
+ "hr: %02x min: %02x sec: %02x\n",
+ year, month, date, cent_day,
+ hour, min, sec );
+
+ tmp->tm_sec = bcd2bin (sec & 0x7F);
+ tmp->tm_min = bcd2bin (min & 0x7F);
+ tmp->tm_hour = bcd2bin (hour & 0x3F);
+ tmp->tm_mday = bcd2bin (date & 0x3F);
+ tmp->tm_mon = bcd2bin (month & 0x1F);
+ tmp->tm_year = bcd2bin (year) + ((cent_day & 0x10) ? 2000 : 1900);
+ tmp->tm_wday = bcd2bin (cent_day & 0x07);
+ tmp->tm_yday = 0;
+ tmp->tm_isdst= 0;
+
+ debug ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ return 0;
+}
+
+int rtc_set (struct rtc_time *tmp)
+{
+ uchar ccr; /* Clock control register */
+ uchar century;
+
+ debug ( "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ /* Lock RTC for write using clock control register */
+ ccr = rtc_read(0);
+ ccr = ccr | 0x80;
+ rtc_write(0, ccr);
+
+ rtc_write (0x07, bin2bcd(tmp->tm_year % 100));
+ rtc_write (0x06, bin2bcd(tmp->tm_mon));
+ rtc_write (0x05, bin2bcd(tmp->tm_mday));
+
+ century = ((tmp->tm_year >= 2000) ? 0x10 : 0) | 0x20;
+ rtc_write (0x04, bin2bcd(tmp->tm_wday) | century);
+
+ rtc_write (0x03, bin2bcd(tmp->tm_hour));
+ rtc_write (0x02, bin2bcd(tmp->tm_min ));
+ rtc_write (0x01, bin2bcd(tmp->tm_sec ));
+
+ /* UNLock RTC */
+ ccr = rtc_read(0);
+ ccr = ccr & 0x7F;
+ rtc_write(0, ccr);
+
+ return 0;
+}
+
+void rtc_reset (void)
+{
+ uchar val;
+
+ /* Clear all clock control registers */
+ rtc_write (0x0, 0x80); /* No Read Lock or calibration */
+
+ /* Clear stop bit */
+ val = rtc_read (0x1);
+ val &= 0x7f;
+ rtc_write(0x1, val);
+
+ /* Enable century / disable frequency test */
+ val = rtc_read (0x4);
+ val = (val & 0xBF) | 0x20;
+ rtc_write(0x4, val);
+
+ /* Clear write lock */
+ rtc_write(0x0, 0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static uchar rtc_read (uchar reg)
+{
+ return *(unsigned char *)
+ ((CONFIG_SYS_NVRAM_BASE_ADDR + CONFIG_SYS_NVRAM_SIZE - 8) + reg);
+}
+
+static void rtc_write (uchar reg, uchar val)
+{
+ *(unsigned char *)
+ ((CONFIG_SYS_NVRAM_BASE_ADDR + CONFIG_SYS_NVRAM_SIZE - 8) + reg) = val;
+}
diff --git a/roms/u-boot/drivers/rtc/max6900.c b/roms/u-boot/drivers/rtc/max6900.c
new file mode 100644
index 000000000..11928839d
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/max6900.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+
+/*
+ * Date & Time support for MAXIM MAX6900 RTC
+ */
+
+/* #define DEBUG */
+
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+#include <i2c.h>
+#include <linux/delay.h>
+
+#ifndef CONFIG_SYS_I2C_RTC_ADDR
+#define CONFIG_SYS_I2C_RTC_ADDR 0x50
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+static uchar rtc_read (uchar reg)
+{
+ return (i2c_reg_read (CONFIG_SYS_I2C_RTC_ADDR, reg));
+}
+
+static void rtc_write (uchar reg, uchar val)
+{
+ i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val);
+ udelay(2500);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int rtc_get (struct rtc_time *tmp)
+{
+ uchar sec, min, hour, mday, wday, mon, cent, year;
+ int retry = 1;
+
+ do {
+ sec = rtc_read (0x80);
+ min = rtc_read (0x82);
+ hour = rtc_read (0x84);
+ mday = rtc_read (0x86);
+ mon = rtc_read (0x88);
+ wday = rtc_read (0x8a);
+ year = rtc_read (0x8c);
+ cent = rtc_read (0x92);
+ /*
+ * Check for seconds rollover
+ */
+ if ((sec != 59) || (rtc_read(0x80) == sec)){
+ retry = 0;
+ }
+ } while (retry);
+
+ debug ( "Get RTC year: %02x mon: %02x cent: %02x mday: %02x wday: %02x "
+ "hr: %02x min: %02x sec: %02x\n",
+ year, mon, cent, mday, wday,
+ hour, min, sec );
+
+ tmp->tm_sec = bcd2bin (sec & 0x7F);
+ tmp->tm_min = bcd2bin (min & 0x7F);
+ tmp->tm_hour = bcd2bin (hour & 0x3F);
+ tmp->tm_mday = bcd2bin (mday & 0x3F);
+ tmp->tm_mon = bcd2bin (mon & 0x1F);
+ tmp->tm_year = bcd2bin (year) + bcd2bin(cent) * 100;
+ tmp->tm_wday = bcd2bin (wday & 0x07);
+ tmp->tm_yday = 0;
+ tmp->tm_isdst= 0;
+
+ debug ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ return 0;
+}
+
+int rtc_set (struct rtc_time *tmp)
+{
+
+ debug ( "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ rtc_write (0x9E, 0x00);
+ rtc_write (0x80, 0); /* Clear seconds to ensure no rollover */
+ rtc_write (0x92, bin2bcd(tmp->tm_year / 100));
+ rtc_write (0x8c, bin2bcd(tmp->tm_year % 100));
+ rtc_write (0x8a, bin2bcd(tmp->tm_wday));
+ rtc_write (0x88, bin2bcd(tmp->tm_mon));
+ rtc_write (0x86, bin2bcd(tmp->tm_mday));
+ rtc_write (0x84, bin2bcd(tmp->tm_hour));
+ rtc_write (0x82, bin2bcd(tmp->tm_min ));
+ rtc_write (0x80, bin2bcd(tmp->tm_sec ));
+
+ return 0;
+}
+
+void rtc_reset (void)
+{
+}
diff --git a/roms/u-boot/drivers/rtc/mc13xxx-rtc.c b/roms/u-boot/drivers/rtc/mc13xxx-rtc.c
new file mode 100644
index 000000000..6c2aef897
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/mc13xxx-rtc.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2008, Guennadi Liakhovetski <lg@denx.de>
+ */
+
+#include <common.h>
+#include <rtc.h>
+#include <spi.h>
+#include <power/pmic.h>
+#include <fsl_pmic.h>
+
+int rtc_get(struct rtc_time *rtc)
+{
+ u32 day1, day2, time;
+ int tim, i = 0;
+ struct pmic *p = pmic_get("FSL_PMIC");
+ int ret;
+
+ if (!p)
+ return -1;
+ do {
+ ret = pmic_reg_read(p, REG_RTC_DAY, &day1);
+ if (ret < 0)
+ return -1;
+
+ ret = pmic_reg_read(p, REG_RTC_TIME, &time);
+ if (ret < 0)
+ return -1;
+
+ ret = pmic_reg_read(p, REG_RTC_DAY, &day2);
+ if (ret < 0)
+ return -1;
+
+ } while (day1 != day2 && i++ < 3);
+
+ tim = day1 * 86400 + time;
+
+ rtc_to_tm(tim, rtc);
+
+ rtc->tm_yday = 0;
+ rtc->tm_isdst = 0;
+
+ return 0;
+}
+
+int rtc_set(struct rtc_time *rtc)
+{
+ u32 time, day;
+ struct pmic *p = pmic_get("FSL_PMIC");
+ if (!p)
+ return -1;
+
+ time = rtc_mktime(rtc);
+ day = time / 86400;
+ time %= 86400;
+
+ pmic_reg_write(p, REG_RTC_DAY, day);
+ pmic_reg_write(p, REG_RTC_TIME, time);
+
+ return 0;
+}
+
+void rtc_reset(void)
+{
+}
diff --git a/roms/u-boot/drivers/rtc/mc146818.c b/roms/u-boot/drivers/rtc/mc146818.c
new file mode 100644
index 000000000..71f96e282
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/mc146818.c
@@ -0,0 +1,308 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2001
+ * Denis Peter MPL AG Switzerland. d.peter@mpl.ch
+ */
+
+/*
+ * Date & Time support for the MC146818 (PIXX4) RTC
+ */
+
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <rtc.h>
+
+#if defined(CONFIG_X86) || defined(CONFIG_MALTA)
+#include <asm/io.h>
+#define in8(p) inb(p)
+#define out8(p, v) outb(v, p)
+#endif
+
+/* Set this to 1 to clear the CMOS RAM */
+#define CLEAR_CMOS 0
+
+#define RTC_PORT_MC146818 CONFIG_SYS_ISA_IO_BASE_ADDRESS + 0x70
+#define RTC_SECONDS 0x00
+#define RTC_SECONDS_ALARM 0x01
+#define RTC_MINUTES 0x02
+#define RTC_MINUTES_ALARM 0x03
+#define RTC_HOURS 0x04
+#define RTC_HOURS_ALARM 0x05
+#define RTC_DAY_OF_WEEK 0x06
+#define RTC_DATE_OF_MONTH 0x07
+#define RTC_MONTH 0x08
+#define RTC_YEAR 0x09
+#define RTC_CONFIG_A 0x0a
+#define RTC_CONFIG_B 0x0b
+#define RTC_CONFIG_C 0x0c
+#define RTC_CONFIG_D 0x0d
+#define RTC_REG_SIZE 0x80
+
+#define RTC_CONFIG_A_REF_CLCK_32KHZ (1 << 5)
+#define RTC_CONFIG_A_RATE_1024HZ 6
+
+#define RTC_CONFIG_B_24H (1 << 1)
+
+#define RTC_CONFIG_D_VALID_RAM_AND_TIME 0x80
+
+static int mc146818_read8(int reg)
+{
+#ifdef CONFIG_SYS_RTC_REG_BASE_ADDR
+ return in8(CONFIG_SYS_RTC_REG_BASE_ADDR + reg);
+#else
+ int ofs = 0;
+
+ if (reg >= 128) {
+ ofs = 2;
+ reg -= 128;
+ }
+ out8(RTC_PORT_MC146818 + ofs, reg);
+
+ return in8(RTC_PORT_MC146818 + ofs + 1);
+#endif
+}
+
+static void mc146818_write8(int reg, uchar val)
+{
+#ifdef CONFIG_SYS_RTC_REG_BASE_ADDR
+ out8(CONFIG_SYS_RTC_REG_BASE_ADDR + reg, val);
+#else
+ int ofs = 0;
+
+ if (reg >= 128) {
+ ofs = 2;
+ reg -= 128;
+ }
+ out8(RTC_PORT_MC146818 + ofs, reg);
+ out8(RTC_PORT_MC146818 + ofs + 1, val);
+#endif
+}
+
+static int mc146818_get(struct rtc_time *tmp)
+{
+ uchar sec, min, hour, mday, wday __attribute__((unused)),mon, year;
+
+ /* here check if rtc can be accessed */
+ while ((mc146818_read8(RTC_CONFIG_A) & 0x80) == 0x80)
+ ;
+
+ sec = mc146818_read8(RTC_SECONDS);
+ min = mc146818_read8(RTC_MINUTES);
+ hour = mc146818_read8(RTC_HOURS);
+ mday = mc146818_read8(RTC_DATE_OF_MONTH);
+ wday = mc146818_read8(RTC_DAY_OF_WEEK);
+ mon = mc146818_read8(RTC_MONTH);
+ year = mc146818_read8(RTC_YEAR);
+#ifdef RTC_DEBUG
+ printf("Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x hr: %02x min: %02x sec: %02x\n",
+ year, mon, mday, wday, hour, min, sec);
+ printf("Alarms: mday: %02x hour: %02x min: %02x sec: %02x\n",
+ mc146818_read8(RTC_CONFIG_D) & 0x3f,
+ mc146818_read8(RTC_HOURS_ALARM),
+ mc146818_read8(RTC_MINUTES_ALARM),
+ mc146818_read8(RTC_SECONDS_ALARM));
+#endif
+ tmp->tm_sec = bcd2bin(sec & 0x7f);
+ tmp->tm_min = bcd2bin(min & 0x7f);
+ tmp->tm_hour = bcd2bin(hour & 0x3f);
+ tmp->tm_mday = bcd2bin(mday & 0x3f);
+ tmp->tm_mon = bcd2bin(mon & 0x1f);
+ tmp->tm_year = bcd2bin(year);
+
+ if (tmp->tm_year < 70)
+ tmp->tm_year += 2000;
+ else
+ tmp->tm_year += 1900;
+
+ tmp->tm_yday = 0;
+ tmp->tm_isdst = 0;
+ /*
+ * The mc146818 only updates wday if it is non-zero, sunday is 1
+ * saturday is 7. So let's use our library routine.
+ */
+ rtc_calc_weekday(tmp);
+#ifdef RTC_DEBUG
+ printf("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+#endif
+
+ return 0;
+}
+
+static int mc146818_set(struct rtc_time *tmp)
+{
+#ifdef RTC_DEBUG
+ printf("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+#endif
+ /* Disable the RTC to update the regs */
+ mc146818_write8(RTC_CONFIG_B, 0x82);
+
+ mc146818_write8(RTC_YEAR, bin2bcd(tmp->tm_year % 100));
+ mc146818_write8(RTC_MONTH, bin2bcd(tmp->tm_mon));
+ /* Sunday = 1, Saturday = 7 */
+ mc146818_write8(RTC_DAY_OF_WEEK, bin2bcd(tmp->tm_wday + 1));
+ mc146818_write8(RTC_DATE_OF_MONTH, bin2bcd(tmp->tm_mday));
+ mc146818_write8(RTC_HOURS, bin2bcd(tmp->tm_hour));
+ mc146818_write8(RTC_MINUTES, bin2bcd(tmp->tm_min));
+ mc146818_write8(RTC_SECONDS, bin2bcd(tmp->tm_sec));
+
+ /* Enable the RTC to update the regs */
+ mc146818_write8(RTC_CONFIG_B, 0x02);
+
+ return 0;
+}
+
+static void mc146818_reset(void)
+{
+ /* Disable the RTC to update the regs */
+ mc146818_write8(RTC_CONFIG_B, 0x82);
+
+ /* Normal OP */
+ mc146818_write8(RTC_CONFIG_A, 0x20);
+ mc146818_write8(RTC_CONFIG_B, 0x00);
+ mc146818_write8(RTC_CONFIG_B, 0x00);
+
+ /* Enable the RTC to update the regs */
+ mc146818_write8(RTC_CONFIG_B, 0x02);
+}
+
+static void mc146818_init(void)
+{
+#if CLEAR_CMOS
+ int i;
+
+ rtc_write8(RTC_SECONDS_ALARM, 0);
+ rtc_write8(RTC_MINUTES_ALARM, 0);
+ rtc_write8(RTC_HOURS_ALARM, 0);
+ for (i = RTC_CONFIG_A; i < RTC_REG_SIZE; i++)
+ rtc_write8(i, 0);
+ printf("RTC: zeroing CMOS RAM\n");
+#endif
+
+ /* Setup the real time clock */
+ mc146818_write8(RTC_CONFIG_B, RTC_CONFIG_B_24H);
+ /* Setup the frequency it operates at */
+ mc146818_write8(RTC_CONFIG_A, RTC_CONFIG_A_REF_CLCK_32KHZ |
+ RTC_CONFIG_A_RATE_1024HZ);
+ /* Ensure all reserved bits are 0 in register D */
+ mc146818_write8(RTC_CONFIG_D, RTC_CONFIG_D_VALID_RAM_AND_TIME);
+
+ /* Clear any pending interrupts */
+ mc146818_read8(RTC_CONFIG_C);
+}
+
+#ifdef CONFIG_DM_RTC
+
+static int rtc_mc146818_get(struct udevice *dev, struct rtc_time *time)
+{
+ return mc146818_get(time);
+}
+
+static int rtc_mc146818_set(struct udevice *dev, const struct rtc_time *time)
+{
+ return mc146818_set((struct rtc_time *)time);
+}
+
+static int rtc_mc146818_reset(struct udevice *dev)
+{
+ mc146818_reset();
+
+ return 0;
+}
+
+static int rtc_mc146818_read8(struct udevice *dev, unsigned int reg)
+{
+ return mc146818_read8(reg);
+}
+
+static int rtc_mc146818_write8(struct udevice *dev, unsigned int reg, int val)
+{
+ mc146818_write8(reg, val);
+
+ return 0;
+}
+
+static int rtc_mc146818_probe(struct udevice *dev)
+{
+ mc146818_init();
+
+ return 0;
+}
+
+static const struct rtc_ops rtc_mc146818_ops = {
+ .get = rtc_mc146818_get,
+ .set = rtc_mc146818_set,
+ .reset = rtc_mc146818_reset,
+ .read8 = rtc_mc146818_read8,
+ .write8 = rtc_mc146818_write8,
+};
+
+static const struct udevice_id rtc_mc146818_ids[] = {
+ { .compatible = "motorola,mc146818" },
+ { }
+};
+
+U_BOOT_DRIVER(motorola_mc146818) = {
+ .name = "motorola_mc146818",
+ .id = UCLASS_RTC,
+ .of_match = rtc_mc146818_ids,
+ .probe = rtc_mc146818_probe,
+ .ops = &rtc_mc146818_ops,
+};
+
+#else /* !CONFIG_DM_RTC */
+
+int rtc_get(struct rtc_time *tmp)
+{
+ return mc146818_get(tmp);
+}
+
+int rtc_set(struct rtc_time *tmp)
+{
+ return mc146818_set(tmp);
+}
+
+void rtc_reset(void)
+{
+ mc146818_reset();
+}
+
+int rtc_read8(int reg)
+{
+ return mc146818_read8(reg);
+}
+
+void rtc_write8(int reg, uchar val)
+{
+ mc146818_write8(reg, val);
+}
+
+u32 rtc_read32(int reg)
+{
+ u32 value = 0;
+ int i;
+
+ for (i = 0; i < sizeof(value); i++)
+ value |= rtc_read8(reg + i) << (i << 3);
+
+ return value;
+}
+
+void rtc_write32(int reg, u32 value)
+{
+ int i;
+
+ for (i = 0; i < sizeof(value); i++)
+ rtc_write8(reg + i, (value >> (i << 3)) & 0xff);
+}
+
+void rtc_init(void)
+{
+ mc146818_init();
+}
+
+#endif /* CONFIG_DM_RTC */
diff --git a/roms/u-boot/drivers/rtc/mcfrtc.c b/roms/u-boot/drivers/rtc/mcfrtc.c
new file mode 100644
index 000000000..e10638ec7
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/mcfrtc.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
+ * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
+ */
+
+#include <common.h>
+
+#include <command.h>
+#include <rtc.h>
+#include <asm/immap.h>
+#include <asm/rtc.h>
+
+#undef RTC_DEBUG
+
+#ifndef CONFIG_SYS_MCFRTC_BASE
+#error RTC_BASE is not defined!
+#endif
+
+#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
+#define STARTOFTIME 1970
+
+int rtc_get(struct rtc_time *tmp)
+{
+ volatile rtc_t *rtc = (rtc_t *) (CONFIG_SYS_MCFRTC_BASE);
+
+ int rtc_days, rtc_hrs, rtc_mins;
+ int tim;
+
+ rtc_days = rtc->days;
+ rtc_hrs = rtc->hourmin >> 8;
+ rtc_mins = RTC_HOURMIN_MINUTES(rtc->hourmin);
+
+ tim = (rtc_days * 24) + rtc_hrs;
+ tim = (tim * 60) + rtc_mins;
+ tim = (tim * 60) + rtc->seconds;
+
+ rtc_to_tm(tim, tmp);
+
+ tmp->tm_yday = 0;
+ tmp->tm_isdst = 0;
+
+#ifdef RTC_DEBUG
+ printf("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+#endif
+
+ return 0;
+}
+
+int rtc_set(struct rtc_time *tmp)
+{
+ volatile rtc_t *rtc = (rtc_t *) (CONFIG_SYS_MCFRTC_BASE);
+
+ static int month_days[12] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+ };
+ int days, i, months;
+
+ if (tmp->tm_year > 2037) {
+ printf("Unable to handle. Exceeding integer limitation!\n");
+ tmp->tm_year = 2027;
+ }
+#ifdef RTC_DEBUG
+ printf("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+#endif
+
+ /* calculate days by years */
+ for (i = STARTOFTIME, days = 0; i < tmp->tm_year; i++) {
+ days += 365 + isleap(i);
+ }
+
+ /* calculate days by months */
+ months = tmp->tm_mon - 1;
+ for (i = 0; i < months; i++) {
+ days += month_days[i];
+
+ if (i == 1)
+ days += isleap(i);
+ }
+
+ days += tmp->tm_mday - 1;
+
+ rtc->days = days;
+ rtc->hourmin = (tmp->tm_hour << 8) | tmp->tm_min;
+ rtc->seconds = tmp->tm_sec;
+
+ return 0;
+}
+
+void rtc_reset(void)
+{
+ volatile rtc_t *rtc = (rtc_t *) (CONFIG_SYS_MCFRTC_BASE);
+
+ if ((rtc->cr & RTC_CR_EN) == 0) {
+ printf("real-time-clock was stopped. Now starting...\n");
+ rtc->cr |= RTC_CR_EN;
+ }
+
+ rtc->cr |= RTC_CR_SWR;
+}
diff --git a/roms/u-boot/drivers/rtc/mk48t59.c b/roms/u-boot/drivers/rtc/mk48t59.c
new file mode 100644
index 000000000..8c90a7040
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/mk48t59.c
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+ */
+
+/*
+ * Date & Time support for the MK48T59 RTC
+ */
+
+#undef RTC_DEBUG
+
+#include <common.h>
+#include <command.h>
+#include <config.h>
+#include <rtc.h>
+#include <mk48t59.h>
+
+#if defined(CONFIG_BAB7xx)
+
+static uchar rtc_read (short reg)
+{
+ out8(RTC_PORT_ADDR0, reg & 0xFF);
+ out8(RTC_PORT_ADDR1, (reg>>8) & 0xFF);
+ return in8(RTC_PORT_DATA);
+}
+
+static void rtc_write (short reg, uchar val)
+{
+ out8(RTC_PORT_ADDR0, reg & 0xFF);
+ out8(RTC_PORT_ADDR1, (reg>>8) & 0xFF);
+ out8(RTC_PORT_DATA, val);
+}
+
+#elif defined(CONFIG_EVAL5200)
+
+static uchar rtc_read (short reg)
+{
+ return in8(RTC(reg));
+}
+
+static void rtc_write (short reg, uchar val)
+{
+ out8(RTC(reg),val);
+}
+
+#else
+# error Board specific rtc access functions should be supplied
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+void *nvram_read(void *dest, const short src, size_t count)
+{
+ uchar *d = (uchar *) dest;
+ short s = src;
+
+ while (count--)
+ *d++ = rtc_read(s++);
+
+ return dest;
+}
+
+void nvram_write(short dest, const void *src, size_t count)
+{
+ short d = dest;
+ uchar *s = (uchar *) src;
+
+ while (count--)
+ rtc_write(d++, *s++);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int rtc_get (struct rtc_time *tmp)
+{
+ uchar save_ctrl_a;
+ uchar sec, min, hour, mday, wday, mon, year;
+
+ /* Simple: freeze the clock, read it and allow updates again */
+ save_ctrl_a = rtc_read(RTC_CONTROLA);
+
+ /* Set the register to read the value. */
+ save_ctrl_a |= RTC_CA_READ;
+ rtc_write(RTC_CONTROLA, save_ctrl_a);
+
+ sec = rtc_read (RTC_SECONDS);
+ min = rtc_read (RTC_MINUTES);
+ hour = rtc_read (RTC_HOURS);
+ mday = rtc_read (RTC_DAY_OF_MONTH);
+ wday = rtc_read (RTC_DAY_OF_WEEK);
+ mon = rtc_read (RTC_MONTH);
+ year = rtc_read (RTC_YEAR);
+
+ /* re-enable update */
+ save_ctrl_a &= ~RTC_CA_READ;
+ rtc_write(RTC_CONTROLA, save_ctrl_a);
+
+#ifdef RTC_DEBUG
+ printf ( "Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x "
+ "hr: %02x min: %02x sec: %02x\n",
+ year, mon, mday, wday,
+ hour, min, sec );
+#endif
+ tmp->tm_sec = bcd2bin (sec & 0x7F);
+ tmp->tm_min = bcd2bin (min & 0x7F);
+ tmp->tm_hour = bcd2bin (hour & 0x3F);
+ tmp->tm_mday = bcd2bin (mday & 0x3F);
+ tmp->tm_mon = bcd2bin (mon & 0x1F);
+ tmp->tm_year = bcd2bin (year);
+ tmp->tm_wday = bcd2bin (wday & 0x07);
+ if(tmp->tm_year<70)
+ tmp->tm_year+=2000;
+ else
+ tmp->tm_year+=1900;
+ tmp->tm_yday = 0;
+ tmp->tm_isdst= 0;
+#ifdef RTC_DEBUG
+ printf ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+#endif
+
+ return 0;
+}
+
+int rtc_set (struct rtc_time *tmp)
+{
+ uchar save_ctrl_a;
+
+#ifdef RTC_DEBUG
+ printf ( "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+#endif
+ save_ctrl_a = rtc_read(RTC_CONTROLA);
+
+ save_ctrl_a |= RTC_CA_WRITE;
+ rtc_write(RTC_CONTROLA, save_ctrl_a); /* disables the RTC to update the regs */
+
+ rtc_write (RTC_YEAR, bin2bcd(tmp->tm_year % 100));
+ rtc_write (RTC_MONTH, bin2bcd(tmp->tm_mon));
+
+ rtc_write (RTC_DAY_OF_WEEK, bin2bcd(tmp->tm_wday));
+ rtc_write (RTC_DAY_OF_MONTH, bin2bcd(tmp->tm_mday));
+ rtc_write (RTC_HOURS, bin2bcd(tmp->tm_hour));
+ rtc_write (RTC_MINUTES, bin2bcd(tmp->tm_min ));
+ rtc_write (RTC_SECONDS, bin2bcd(tmp->tm_sec ));
+
+ save_ctrl_a &= ~RTC_CA_WRITE;
+ rtc_write(RTC_CONTROLA, save_ctrl_a); /* enables the RTC to update the regs */
+
+ return 0;
+}
+
+void rtc_reset (void)
+{
+ uchar control_b;
+
+ /*
+ * Start oscillator here.
+ */
+ control_b = rtc_read(RTC_CONTROLB);
+
+ control_b &= ~RTC_CB_STOP;
+ rtc_write(RTC_CONTROLB, control_b);
+}
+
+void rtc_set_watchdog(short multi, short res)
+{
+ uchar wd_value;
+
+ wd_value = RTC_WDS | ((multi & 0x1F) << 2) | (res & 0x3);
+ rtc_write(RTC_WATCHDOG, wd_value);
+}
diff --git a/roms/u-boot/drivers/rtc/mvrtc.c b/roms/u-boot/drivers/rtc/mvrtc.c
new file mode 100644
index 000000000..50240d57f
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/mvrtc.c
@@ -0,0 +1,186 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2011
+ * Jason Cooper <u-boot@lakedaemon.net>
+ */
+
+/*
+ * Date & Time support for Marvell Integrated RTC
+ */
+
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <rtc.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include "mvrtc.h"
+
+/* This RTC does not support century, so we assume 20 */
+#define CENTURY 20
+
+static int __mv_rtc_get(struct mvrtc_registers *regs, struct rtc_time *t)
+{
+ u32 time;
+ u32 date;
+
+ /* read the time register */
+ time = readl(&regs->time);
+
+ /* read the date register */
+ date = readl(&regs->date);
+
+ /* test for 12 hour clock (can't tell if it's am/pm) */
+ if (time & MVRTC_HRFMT_MSK) {
+ printf("Error: RTC in 12 hour mode, can't determine AM/PM.\n");
+ return -1;
+ }
+
+ /* time */
+ t->tm_sec = bcd2bin((time >> MVRTC_SEC_SFT) & MVRTC_SEC_MSK);
+ t->tm_min = bcd2bin((time >> MVRTC_MIN_SFT) & MVRTC_MIN_MSK);
+ t->tm_hour = bcd2bin((time >> MVRTC_HOUR_SFT) & MVRTC_HOUR_MSK);
+ t->tm_wday = bcd2bin((time >> MVRTC_DAY_SFT) & MVRTC_DAY_MSK);
+ t->tm_wday--;
+
+ /* date */
+ t->tm_mday = bcd2bin((date >> MVRTC_DATE_SFT) & MVRTC_DATE_MSK);
+ t->tm_mon = bcd2bin((date >> MVRTC_MON_SFT) & MVRTC_MON_MSK);
+ t->tm_year = bcd2bin((date >> MVRTC_YEAR_SFT) & MVRTC_YEAR_MSK);
+ t->tm_year += CENTURY * 100;
+
+ /* not supported in this RTC */
+ t->tm_yday = 0;
+ t->tm_isdst = 0;
+
+ return 0;
+}
+
+#ifndef CONFIG_DM_RTC
+int rtc_get(struct rtc_time *t)
+{
+ struct mvrtc_registers *regs;
+
+ regs = (struct mvrtc_registers *)KW_RTC_BASE;
+ return __mv_rtc_get(regs, t);
+}
+#endif /* !CONFIG_DM_RTC */
+
+static int __mv_rtc_set(struct mvrtc_registers *regs, const struct rtc_time *t)
+{
+ u32 time = 0; /* sets hour format bit to zero, 24hr format. */
+ u32 date = 0;
+
+ /* check that this code isn't 80+ years old ;-) */
+ if ((t->tm_year / 100) != CENTURY)
+ printf("Warning: Only century %d supported.\n", CENTURY);
+
+ /* time */
+ time |= (bin2bcd(t->tm_sec) & MVRTC_SEC_MSK) << MVRTC_SEC_SFT;
+ time |= (bin2bcd(t->tm_min) & MVRTC_MIN_MSK) << MVRTC_MIN_SFT;
+ time |= (bin2bcd(t->tm_hour) & MVRTC_HOUR_MSK) << MVRTC_HOUR_SFT;
+ time |= (bin2bcd(t->tm_wday + 1) & MVRTC_DAY_MSK) << MVRTC_DAY_SFT;
+
+ /* date */
+ date |= (bin2bcd(t->tm_mday) & MVRTC_DATE_MSK) << MVRTC_DATE_SFT;
+ date |= (bin2bcd(t->tm_mon) & MVRTC_MON_MSK) << MVRTC_MON_SFT;
+ date |= (bin2bcd(t->tm_year % 100) & MVRTC_YEAR_MSK) << MVRTC_YEAR_SFT;
+
+ /* write the time register */
+ writel(time, &regs->time);
+
+ /* write the date register */
+ writel(date, &regs->date);
+
+ return 0;
+}
+
+#ifndef CONFIG_DM_RTC
+int rtc_set(struct rtc_time *t)
+{
+ struct mvrtc_registers *regs;
+
+ regs = (struct mvrtc_registers *)KW_RTC_BASE;
+ return __mv_rtc_set(regs, t);
+}
+#endif /* !CONFIG_DM_RTC */
+
+static void __mv_rtc_reset(struct mvrtc_registers *regs)
+{
+ u32 time;
+ u32 sec;
+
+ /* no init routine for this RTC needed, just check that it's working */
+ time = readl(&regs->time);
+ sec = bcd2bin((time >> MVRTC_SEC_SFT) & MVRTC_SEC_MSK);
+ udelay(1000000);
+ time = readl(&regs->time);
+
+ if (sec == bcd2bin((time >> MVRTC_SEC_SFT) & MVRTC_SEC_MSK))
+ printf("Error: RTC did not increment.\n");
+}
+
+#ifndef CONFIG_DM_RTC
+void rtc_reset(void)
+{
+ struct mvrtc_registers *regs;
+
+ regs = (struct mvrtc_registers *)KW_RTC_BASE;
+ __mv_rtc_reset(regs);
+}
+#endif /* !CONFIG_DM_RTC */
+
+#ifdef CONFIG_DM_RTC
+static int mv_rtc_get(struct udevice *dev, struct rtc_time *tm)
+{
+ struct mvrtc_pdata *pdata = dev_get_plat(dev);
+ struct mvrtc_registers *regs = (struct mvrtc_registers *)pdata->iobase;
+
+ return __mv_rtc_get(regs, tm);
+}
+
+static int mv_rtc_set(struct udevice *dev, const struct rtc_time *tm)
+{
+ struct mvrtc_pdata *pdata = dev_get_plat(dev);
+ struct mvrtc_registers *regs = (struct mvrtc_registers *)pdata->iobase;
+
+ return __mv_rtc_set(regs, tm);
+}
+
+static int mv_rtc_reset(struct udevice *dev)
+{
+ struct mvrtc_pdata *pdata = dev_get_plat(dev);
+ struct mvrtc_registers *regs = (struct mvrtc_registers *)pdata->iobase;
+
+ __mv_rtc_reset(regs);
+ return 0;
+}
+
+static const struct rtc_ops mv_rtc_ops = {
+ .get = mv_rtc_get,
+ .set = mv_rtc_set,
+ .reset = mv_rtc_reset,
+};
+
+static const struct udevice_id mv_rtc_ids[] = {
+ { .compatible = "marvell,kirkwood-rtc" },
+ { .compatible = "marvell,orion-rtc" },
+ { }
+};
+
+static int mv_rtc_of_to_plat(struct udevice *dev)
+{
+ struct mvrtc_pdata *pdata = dev_get_plat(dev);
+
+ pdata->iobase = dev_read_addr(dev);
+ return 0;
+}
+
+U_BOOT_DRIVER(rtc_mv) = {
+ .name = "rtc-mv",
+ .id = UCLASS_RTC,
+ .of_to_plat = mv_rtc_of_to_plat,
+ .of_match = mv_rtc_ids,
+ .ops = &mv_rtc_ops,
+};
+#endif /* CONFIG_DM_RTC */
diff --git a/roms/u-boot/drivers/rtc/mvrtc.h b/roms/u-boot/drivers/rtc/mvrtc.h
new file mode 100644
index 000000000..87ff43299
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/mvrtc.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2011
+ * Jason Cooper <u-boot@lakedaemon.net>
+ */
+
+/*
+ * Date & Time support for Marvell Integrated RTC
+ */
+
+#ifndef _MVRTC_H_
+#define _MVRTC_H_
+
+#include <asm/arch/soc.h>
+#include <linux/compiler.h>
+
+/* RTC registers */
+struct mvrtc_registers {
+ u32 time;
+ u32 date;
+};
+
+/* Platform data */
+struct mvrtc_pdata {
+ phys_addr_t iobase;
+};
+
+/* time register */
+#define MVRTC_SEC_SFT 0
+#define MVRTC_SEC_MSK 0x7f
+#define MVRTC_MIN_SFT 8
+#define MVRTC_MIN_MSK 0x7f
+#define MVRTC_HOUR_SFT 16
+#define MVRTC_HOUR_MSK 0x3f
+#define MVRTC_DAY_SFT 24
+#define MVRTC_DAY_MSK 0x7
+
+/*
+ * Hour format bit
+ * 1 = 12 hour clock
+ * 0 = 24 hour clock
+ */
+#define MVRTC_HRFMT_MSK 0x00400000
+
+/* date register */
+#define MVRTC_DATE_SFT 0
+#define MVRTC_DATE_MSK 0x3f
+#define MVRTC_MON_SFT 8
+#define MVRTC_MON_MSK 0x1f
+#define MVRTC_YEAR_SFT 16
+#define MVRTC_YEAR_MSK 0xff
+
+#endif
diff --git a/roms/u-boot/drivers/rtc/mx27rtc.c b/roms/u-boot/drivers/rtc/mx27rtc.c
new file mode 100644
index 000000000..563e8a4a3
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/mx27rtc.c
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Freescale i.MX27 RTC Driver
+ *
+ * Copyright (C) 2012 Philippe Reynes <tremyfr@yahoo.fr>
+ */
+
+#include <common.h>
+#include <rtc.h>
+#include <asm/io.h>
+#include <asm/arch/imx-regs.h>
+
+#define HOUR_SHIFT 8
+#define HOUR_MASK 0x1f
+#define MIN_SHIFT 0
+#define MIN_MASK 0x3f
+
+int rtc_get(struct rtc_time *time)
+{
+ struct rtc_regs *rtc_regs = (struct rtc_regs *)IMX_RTC_BASE;
+ uint32_t day, hour, min, sec;
+
+ day = readl(&rtc_regs->dayr);
+ hour = readl(&rtc_regs->hourmin);
+ sec = readl(&rtc_regs->seconds);
+
+ min = (hour >> MIN_SHIFT) & MIN_MASK;
+ hour = (hour >> HOUR_SHIFT) & HOUR_MASK;
+
+ sec += min * 60 + hour * 3600 + day * 24 * 3600;
+
+ rtc_to_tm(sec, time);
+
+ return 0;
+}
+
+int rtc_set(struct rtc_time *time)
+{
+ struct rtc_regs *rtc_regs = (struct rtc_regs *)IMX_RTC_BASE;
+ uint32_t day, hour, min, sec;
+
+ sec = rtc_mktime(time);
+
+ day = sec / (24 * 3600);
+ sec = sec % (24 * 3600);
+ hour = sec / 3600;
+ sec = sec % 3600;
+ min = sec / 60;
+ sec = sec % 60;
+
+ hour = (hour & HOUR_MASK) << HOUR_SHIFT;
+ hour |= (min & MIN_MASK) << MIN_SHIFT;
+
+ writel(day, &rtc_regs->dayr);
+ writel(hour, &rtc_regs->hourmin);
+ writel(sec, &rtc_regs->seconds);
+
+ return 0;
+}
+
+void rtc_reset(void)
+{
+ /* nothing to do */
+}
diff --git a/roms/u-boot/drivers/rtc/mxsrtc.c b/roms/u-boot/drivers/rtc/mxsrtc.c
new file mode 100644
index 000000000..be899a925
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/mxsrtc.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Freescale i.MX28 RTC Driver
+ *
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ * on behalf of DENX Software Engineering GmbH
+ */
+
+#include <common.h>
+#include <rtc.h>
+#include <asm/io.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/sys_proto.h>
+
+#define MXS_RTC_MAX_TIMEOUT 1000000
+
+/* Set time in seconds since 1970-01-01 */
+int mxs_rtc_set_time(uint32_t secs)
+{
+ struct mxs_rtc_regs *rtc_regs = (struct mxs_rtc_regs *)MXS_RTC_BASE;
+ int ret;
+
+ writel(secs, &rtc_regs->hw_rtc_seconds);
+
+ /*
+ * The 0x80 here means seconds were copied to analog. This information
+ * is taken from the linux kernel driver for the STMP37xx RTC since
+ * documentation doesn't mention it.
+ */
+ ret = mxs_wait_mask_clr(&rtc_regs->hw_rtc_stat_reg,
+ 0x80 << RTC_STAT_STALE_REGS_OFFSET, MXS_RTC_MAX_TIMEOUT);
+
+ if (ret)
+ printf("MXS RTC: Timeout waiting for update\n");
+
+ return ret;
+}
+
+int rtc_get(struct rtc_time *time)
+{
+ struct mxs_rtc_regs *rtc_regs = (struct mxs_rtc_regs *)MXS_RTC_BASE;
+ uint32_t secs;
+
+ secs = readl(&rtc_regs->hw_rtc_seconds);
+ rtc_to_tm(secs, time);
+
+ return 0;
+}
+
+int rtc_set(struct rtc_time *time)
+{
+ uint32_t secs;
+
+ secs = rtc_mktime(time);
+
+ return mxs_rtc_set_time(secs);
+}
+
+void rtc_reset(void)
+{
+ struct mxs_rtc_regs *rtc_regs = (struct mxs_rtc_regs *)MXS_RTC_BASE;
+ int ret;
+
+ /* Set time to 1970-01-01 */
+ mxs_rtc_set_time(0);
+
+ /* Reset the RTC block */
+ ret = mxs_reset_block(&rtc_regs->hw_rtc_ctrl_reg);
+ if (ret)
+ printf("MXS RTC: Block reset timeout\n");
+}
diff --git a/roms/u-boot/drivers/rtc/pcf2127.c b/roms/u-boot/drivers/rtc/pcf2127.c
new file mode 100644
index 000000000..57f86401d
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/pcf2127.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2016 by NXP Semiconductors Inc.
+ * Date & Time support for PCF2127 RTC
+ */
+
+/* #define DEBUG */
+
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <rtc.h>
+
+#define PCF2127_REG_CTRL1 0x00
+#define PCF2127_REG_CTRL2 0x01
+#define PCF2127_REG_CTRL3 0x02
+#define PCF2127_REG_SC 0x03
+#define PCF2127_REG_MN 0x04
+#define PCF2127_REG_HR 0x05
+#define PCF2127_REG_DM 0x06
+#define PCF2127_REG_DW 0x07
+#define PCF2127_REG_MO 0x08
+#define PCF2127_REG_YR 0x09
+
+static int pcf2127_rtc_read(struct udevice *dev, uint offset, u8 *buffer, uint len)
+{
+ struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
+ struct i2c_msg msg;
+ int ret;
+
+ /* Set the address of the start register to be read */
+ ret = dm_i2c_write(dev, offset, NULL, 0);
+ if (ret < 0)
+ return ret;
+
+ /* Read register's data */
+ msg.addr = chip->chip_addr;
+ msg.flags |= I2C_M_RD;
+ msg.len = len;
+ msg.buf = buffer;
+
+ return dm_i2c_xfer(dev, &msg, 1);
+}
+
+static int pcf2127_rtc_write(struct udevice *dev, uint offset,
+ const u8 *buffer, uint len)
+{
+ return dm_i2c_write(dev, offset, buffer, len);
+}
+
+static int pcf2127_rtc_set(struct udevice *dev, const struct rtc_time *tm)
+{
+ uchar buf[7] = {0};
+ int i = 0, ret;
+
+ /* hours, minutes and seconds */
+ buf[i++] = bin2bcd(tm->tm_sec);
+ buf[i++] = bin2bcd(tm->tm_min);
+ buf[i++] = bin2bcd(tm->tm_hour);
+ buf[i++] = bin2bcd(tm->tm_mday);
+ buf[i++] = tm->tm_wday & 0x07;
+
+ /* month, 1 - 12 */
+ buf[i++] = bin2bcd(tm->tm_mon);
+
+ /* year */
+ buf[i++] = bin2bcd(tm->tm_year % 100);
+
+ /* write register's data */
+ ret = dm_i2c_write(dev, PCF2127_REG_SC, buf, i);
+
+ return ret;
+}
+
+static int pcf2127_rtc_get(struct udevice *dev, struct rtc_time *tm)
+{
+ int ret = 0;
+ uchar buf[10] = { PCF2127_REG_CTRL1 };
+
+ ret = pcf2127_rtc_read(dev, PCF2127_REG_CTRL1, buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+
+ if (buf[PCF2127_REG_CTRL3] & 0x04)
+ puts("### Warning: RTC Low Voltage - date/time not reliable\n");
+
+ tm->tm_sec = bcd2bin(buf[PCF2127_REG_SC] & 0x7F);
+ tm->tm_min = bcd2bin(buf[PCF2127_REG_MN] & 0x7F);
+ tm->tm_hour = bcd2bin(buf[PCF2127_REG_HR] & 0x3F);
+ tm->tm_mday = bcd2bin(buf[PCF2127_REG_DM] & 0x3F);
+ tm->tm_mon = bcd2bin(buf[PCF2127_REG_MO] & 0x1F);
+ tm->tm_year = bcd2bin(buf[PCF2127_REG_YR]) + 1900;
+ if (tm->tm_year < 1970)
+ tm->tm_year += 100; /* assume we are in 1970...2069 */
+ tm->tm_wday = buf[PCF2127_REG_DW] & 0x07;
+ tm->tm_yday = 0;
+ tm->tm_isdst = 0;
+
+ debug("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ return ret;
+}
+
+static int pcf2127_rtc_reset(struct udevice *dev)
+{
+ /*Doing nothing here*/
+
+ return 0;
+}
+
+static const struct rtc_ops pcf2127_rtc_ops = {
+ .get = pcf2127_rtc_get,
+ .set = pcf2127_rtc_set,
+ .reset = pcf2127_rtc_reset,
+ .read = pcf2127_rtc_read,
+ .write = pcf2127_rtc_write,
+};
+
+static const struct udevice_id pcf2127_rtc_ids[] = {
+ { .compatible = "pcf2127-rtc" },
+ { }
+};
+
+U_BOOT_DRIVER(rtc_pcf2127) = {
+ .name = "rtc-pcf2127",
+ .id = UCLASS_RTC,
+ .of_match = pcf2127_rtc_ids,
+ .ops = &pcf2127_rtc_ops,
+};
diff --git a/roms/u-boot/drivers/rtc/pcf8563.c b/roms/u-boot/drivers/rtc/pcf8563.c
new file mode 100644
index 000000000..19faefba7
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/pcf8563.c
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+
+/*
+ * Date & Time support for Philips PCF8563 RTC
+ */
+
+/* #define DEBUG */
+
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <log.h>
+#include <rtc.h>
+#include <i2c.h>
+
+#if !CONFIG_IS_ENABLED(DM_RTC)
+static uchar rtc_read (uchar reg);
+static void rtc_write (uchar reg, uchar val);
+
+/* ------------------------------------------------------------------------- */
+
+int rtc_get (struct rtc_time *tmp)
+{
+ int rel = 0;
+ uchar sec, min, hour, mday, wday, mon_cent, year;
+
+ sec = rtc_read (0x02);
+ min = rtc_read (0x03);
+ hour = rtc_read (0x04);
+ mday = rtc_read (0x05);
+ wday = rtc_read (0x06);
+ mon_cent= rtc_read (0x07);
+ year = rtc_read (0x08);
+
+ debug ( "Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x "
+ "hr: %02x min: %02x sec: %02x\n",
+ year, mon_cent, mday, wday,
+ hour, min, sec );
+ debug ( "Alarms: wday: %02x day: %02x hour: %02x min: %02x\n",
+ rtc_read (0x0C),
+ rtc_read (0x0B),
+ rtc_read (0x0A),
+ rtc_read (0x09) );
+
+ if (sec & 0x80) {
+ puts ("### Warning: RTC Low Voltage - date/time not reliable\n");
+ rel = -1;
+ }
+
+ tmp->tm_sec = bcd2bin (sec & 0x7F);
+ tmp->tm_min = bcd2bin (min & 0x7F);
+ tmp->tm_hour = bcd2bin (hour & 0x3F);
+ tmp->tm_mday = bcd2bin (mday & 0x3F);
+ tmp->tm_mon = bcd2bin (mon_cent & 0x1F);
+ tmp->tm_year = bcd2bin (year) + ((mon_cent & 0x80) ? 1900 : 2000);
+ tmp->tm_wday = bcd2bin (wday & 0x07);
+ tmp->tm_yday = 0;
+ tmp->tm_isdst= 0;
+
+ debug ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ return rel;
+}
+
+int rtc_set (struct rtc_time *tmp)
+{
+ uchar century;
+
+ debug ( "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ rtc_write (0x08, bin2bcd(tmp->tm_year % 100));
+
+ century = (tmp->tm_year >= 2000) ? 0 : 0x80;
+ rtc_write (0x07, bin2bcd(tmp->tm_mon) | century);
+
+ rtc_write (0x06, bin2bcd(tmp->tm_wday));
+ rtc_write (0x05, bin2bcd(tmp->tm_mday));
+ rtc_write (0x04, bin2bcd(tmp->tm_hour));
+ rtc_write (0x03, bin2bcd(tmp->tm_min ));
+ rtc_write (0x02, bin2bcd(tmp->tm_sec ));
+
+ return 0;
+}
+
+void rtc_reset (void)
+{
+ /* clear all control & status registers */
+ rtc_write (0x00, 0x00);
+ rtc_write (0x01, 0x00);
+ rtc_write (0x0D, 0x00);
+
+ /* clear Voltage Low bit */
+ rtc_write (0x02, rtc_read (0x02) & 0x7F);
+
+ /* reset all alarms */
+ rtc_write (0x09, 0x00);
+ rtc_write (0x0A, 0x00);
+ rtc_write (0x0B, 0x00);
+ rtc_write (0x0C, 0x00);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static uchar rtc_read (uchar reg)
+{
+ return (i2c_reg_read (CONFIG_SYS_I2C_RTC_ADDR, reg));
+}
+
+static void rtc_write (uchar reg, uchar val)
+{
+ i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val);
+}
+#else
+static int pcf8563_rtc_get(struct udevice *dev, struct rtc_time *tmp)
+{
+ int rel = 0;
+ uchar sec, min, hour, mday, wday, mon_cent, year;
+
+ sec = dm_i2c_reg_read(dev, 0x02);
+ min = dm_i2c_reg_read(dev, 0x03);
+ hour = dm_i2c_reg_read(dev, 0x04);
+ mday = dm_i2c_reg_read(dev, 0x05);
+ wday = dm_i2c_reg_read(dev, 0x06);
+ mon_cent = dm_i2c_reg_read(dev, 0x07);
+ year = dm_i2c_reg_read(dev, 0x08);
+
+ debug("Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x ",
+ year, mon_cent, mday, wday);
+ debug("hr: %02x min: %02x sec: %02x\n",
+ hour, min, sec);
+ debug("Alarms: wday: %02x day: %02x hour: %02x min: %02x\n",
+ dm_i2c_reg_read(dev, 0x0C),
+ dm_i2c_reg_read(dev, 0x0B),
+ dm_i2c_reg_read(dev, 0x0A),
+ dm_i2c_reg_read(dev, 0x09));
+
+ if (sec & 0x80) {
+ puts("### Warning: RTC Low Voltage - date/time not reliable\n");
+ rel = -1;
+ }
+
+ tmp->tm_sec = bcd2bin(sec & 0x7F);
+ tmp->tm_min = bcd2bin(min & 0x7F);
+ tmp->tm_hour = bcd2bin(hour & 0x3F);
+ tmp->tm_mday = bcd2bin(mday & 0x3F);
+ tmp->tm_mon = bcd2bin(mon_cent & 0x1F);
+ tmp->tm_year = bcd2bin(year) + ((mon_cent & 0x80) ? 1900 : 2000);
+ tmp->tm_wday = bcd2bin(wday & 0x07);
+ tmp->tm_yday = 0;
+ tmp->tm_isdst = 0;
+
+ debug("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ return rel;
+}
+
+static int pcf8563_rtc_set(struct udevice *dev, const struct rtc_time *tmp)
+{
+ uchar century;
+
+ debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ dm_i2c_reg_write(dev, 0x08, bin2bcd(tmp->tm_year % 100));
+
+ century = (tmp->tm_year >= 2000) ? 0 : 0x80;
+ dm_i2c_reg_write(dev, 0x07, bin2bcd(tmp->tm_mon) | century);
+
+ dm_i2c_reg_write(dev, 0x06, bin2bcd(tmp->tm_wday));
+ dm_i2c_reg_write(dev, 0x05, bin2bcd(tmp->tm_mday));
+ dm_i2c_reg_write(dev, 0x04, bin2bcd(tmp->tm_hour));
+ dm_i2c_reg_write(dev, 0x03, bin2bcd(tmp->tm_min));
+ dm_i2c_reg_write(dev, 0x02, bin2bcd(tmp->tm_sec));
+
+ return 0;
+}
+
+static int pcf8563_rtc_reset(struct udevice *dev)
+{
+ /* clear all control & status registers */
+ dm_i2c_reg_write(dev, 0x00, 0x00);
+ dm_i2c_reg_write(dev, 0x01, 0x00);
+ dm_i2c_reg_write(dev, 0x0D, 0x00);
+
+ /* clear Voltage Low bit */
+ dm_i2c_reg_write(dev, 0x02, dm_i2c_reg_read(dev, 0x02) & 0x7F);
+
+ /* reset all alarms */
+ dm_i2c_reg_write(dev, 0x09, 0x00);
+ dm_i2c_reg_write(dev, 0x0A, 0x00);
+ dm_i2c_reg_write(dev, 0x0B, 0x00);
+ dm_i2c_reg_write(dev, 0x0C, 0x00);
+
+ return 0;
+}
+
+static const struct rtc_ops pcf8563_rtc_ops = {
+ .get = pcf8563_rtc_get,
+ .set = pcf8563_rtc_set,
+ .reset = pcf8563_rtc_reset,
+};
+
+static const struct udevice_id pcf8563_rtc_ids[] = {
+ { .compatible = "nxp,pcf8563" },
+ { }
+};
+
+U_BOOT_DRIVER(rtc_pcf8563) = {
+ .name = "rtc-pcf8563",
+ .id = UCLASS_RTC,
+ .of_match = pcf8563_rtc_ids,
+ .ops = &pcf8563_rtc_ops,
+};
+#endif
diff --git a/roms/u-boot/drivers/rtc/pl031.c b/roms/u-boot/drivers/rtc/pl031.c
new file mode 100644
index 000000000..a1d376611
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/pl031.c
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2008
+ * Gururaja Hebbar gururajakr@sanyo.co.in
+ *
+ * reference linux-2.6.20.6/drivers/rtc/rtc-pl031.c
+ */
+
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <rtc.h>
+#include <asm/io.h>
+#include <asm/types.h>
+
+/*
+ * Register definitions
+ */
+#define RTC_DR 0x00 /* Data read register */
+#define RTC_MR 0x04 /* Match register */
+#define RTC_LR 0x08 /* Data load register */
+#define RTC_CR 0x0c /* Control register */
+#define RTC_IMSC 0x10 /* Interrupt mask and set register */
+#define RTC_RIS 0x14 /* Raw interrupt status register */
+#define RTC_MIS 0x18 /* Masked interrupt status register */
+#define RTC_ICR 0x1c /* Interrupt clear register */
+
+#define RTC_CR_START (1 << 0)
+
+struct pl031_plat {
+ phys_addr_t base;
+};
+
+static inline u32 pl031_read_reg(struct udevice *dev, int reg)
+{
+ struct pl031_plat *pdata = dev_get_plat(dev);
+
+ return readl(pdata->base + reg);
+}
+
+static inline u32 pl031_write_reg(struct udevice *dev, int reg, u32 value)
+{
+ struct pl031_plat *pdata = dev_get_plat(dev);
+
+ return writel(value, pdata->base + reg);
+}
+
+/*
+ * Probe RTC device
+ */
+static int pl031_probe(struct udevice *dev)
+{
+ /* Enable RTC Start in Control register*/
+ pl031_write_reg(dev, RTC_CR, RTC_CR_START);
+
+ return 0;
+}
+
+/*
+ * Get the current time from the RTC
+ */
+static int pl031_get(struct udevice *dev, struct rtc_time *tm)
+{
+ unsigned long tim;
+
+ if (!tm)
+ return -EINVAL;
+
+ tim = pl031_read_reg(dev, RTC_DR);
+
+ rtc_to_tm(tim, tm);
+
+ debug("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ return 0;
+}
+
+/*
+ * Set the RTC
+ */
+static int pl031_set(struct udevice *dev, const struct rtc_time *tm)
+{
+ unsigned long tim;
+
+ if (!tm)
+ return -EINVAL;
+
+ debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ /* Calculate number of seconds this incoming time represents */
+ tim = rtc_mktime(tm);
+
+ pl031_write_reg(dev, RTC_LR, tim);
+
+ return 0;
+}
+
+/*
+ * Reset the RTC. We set the date back to 1970-01-01.
+ */
+static int pl031_reset(struct udevice *dev)
+{
+ pl031_write_reg(dev, RTC_LR, 0);
+
+ return 0;
+}
+
+static const struct rtc_ops pl031_ops = {
+ .get = pl031_get,
+ .set = pl031_set,
+ .reset = pl031_reset,
+};
+
+static const struct udevice_id pl031_ids[] = {
+ { .compatible = "arm,pl031" },
+ { }
+};
+
+static int pl031_of_to_plat(struct udevice *dev)
+{
+ struct pl031_plat *pdata = dev_get_plat(dev);
+
+ pdata->base = dev_read_addr(dev);
+
+ return 0;
+}
+
+U_BOOT_DRIVER(rtc_pl031) = {
+ .name = "rtc-pl031",
+ .id = UCLASS_RTC,
+ .of_match = pl031_ids,
+ .probe = pl031_probe,
+ .of_to_plat = pl031_of_to_plat,
+ .plat_auto = sizeof(struct pl031_plat),
+ .ops = &pl031_ops,
+};
diff --git a/roms/u-boot/drivers/rtc/pt7c4338.c b/roms/u-boot/drivers/rtc/pt7c4338.c
new file mode 100644
index 000000000..c987494b6
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/pt7c4338.c
@@ -0,0 +1,228 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ * Copyright 2020 NXP
+ *
+ * Author: Priyanka Jain <Priyanka.Jain@freescale.com>
+ */
+
+/*
+ * This file provides Date & Time support (no alarms) for PT7C4338 chip.
+ *
+ * This file is based on drivers/rtc/ds1337.c
+ *
+ * PT7C4338 chip is manufactured by Pericom Technology Inc.
+ * It is a serial real-time clock which provides
+ * 1)Low-power clock/calendar.
+ * 2)Programmable square-wave output.
+ * It has 56 bytes of nonvolatile RAM.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <log.h>
+#include <rtc.h>
+#include <i2c.h>
+
+/* RTC register addresses */
+#define RTC_SEC_REG_ADDR 0x0
+#define RTC_MIN_REG_ADDR 0x1
+#define RTC_HR_REG_ADDR 0x2
+#define RTC_DAY_REG_ADDR 0x3
+#define RTC_DATE_REG_ADDR 0x4
+#define RTC_MON_REG_ADDR 0x5
+#define RTC_YR_REG_ADDR 0x6
+#define RTC_CTL_STAT_REG_ADDR 0x7
+
+/* RTC second register address bit */
+#define RTC_SEC_BIT_CH 0x80 /* Clock Halt (in Register 0) */
+
+/* RTC control and status register bits */
+#define RTC_CTL_STAT_BIT_RS0 0x1 /* Rate select 0 */
+#define RTC_CTL_STAT_BIT_RS1 0x2 /* Rate select 1 */
+#define RTC_CTL_STAT_BIT_SQWE 0x10 /* Square Wave Enable */
+#define RTC_CTL_STAT_BIT_OSF 0x20 /* Oscillator Stop Flag */
+#define RTC_CTL_STAT_BIT_OUT 0x80 /* Output Level Control */
+
+/* RTC reset value */
+#define RTC_PT7C4338_RESET_VAL \
+ (RTC_CTL_STAT_BIT_RS0 | RTC_CTL_STAT_BIT_RS1 | RTC_CTL_STAT_BIT_OUT)
+
+#if !CONFIG_IS_ENABLED(DM_RTC)
+/****** Helper functions ****************************************/
+static u8 rtc_read(u8 reg)
+{
+ return i2c_reg_read(CONFIG_SYS_I2C_RTC_ADDR, reg);
+}
+
+static void rtc_write(u8 reg, u8 val)
+{
+ i2c_reg_write(CONFIG_SYS_I2C_RTC_ADDR, reg, val);
+}
+/****************************************************************/
+
+/* Get the current time from the RTC */
+int rtc_get(struct rtc_time *tmp)
+{
+ int ret = 0;
+ u8 sec, min, hour, mday, wday, mon, year, ctl_stat;
+
+ ctl_stat = rtc_read(RTC_CTL_STAT_REG_ADDR);
+ sec = rtc_read(RTC_SEC_REG_ADDR);
+ min = rtc_read(RTC_MIN_REG_ADDR);
+ hour = rtc_read(RTC_HR_REG_ADDR);
+ wday = rtc_read(RTC_DAY_REG_ADDR);
+ mday = rtc_read(RTC_DATE_REG_ADDR);
+ mon = rtc_read(RTC_MON_REG_ADDR);
+ year = rtc_read(RTC_YR_REG_ADDR);
+ debug("Get RTC year: %02x mon: %02x mday: %02x wday: %02x "
+ "hr: %02x min: %02x sec: %02x control_status: %02x\n",
+ year, mon, mday, wday, hour, min, sec, ctl_stat);
+
+ if (ctl_stat & RTC_CTL_STAT_BIT_OSF) {
+ printf("### Warning: RTC oscillator has stopped\n");
+ /* clear the OSF flag */
+ rtc_write(RTC_CTL_STAT_REG_ADDR,
+ rtc_read(RTC_CTL_STAT_REG_ADDR)\
+ & ~RTC_CTL_STAT_BIT_OSF);
+ ret = -1;
+ }
+
+ tmp->tm_sec = bcd2bin(sec & 0x7F);
+ tmp->tm_min = bcd2bin(min & 0x7F);
+ tmp->tm_hour = bcd2bin(hour & 0x3F);
+ tmp->tm_mday = bcd2bin(mday & 0x3F);
+ tmp->tm_mon = bcd2bin(mon & 0x1F);
+ tmp->tm_year = bcd2bin(year) + 2000;
+ tmp->tm_wday = bcd2bin((wday - 1) & 0x07);
+ tmp->tm_yday = 0;
+ tmp->tm_isdst = 0;
+ debug("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ return ret;
+}
+
+/* Set the RTC */
+int rtc_set(struct rtc_time *tmp)
+{
+ debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ rtc_write(RTC_YR_REG_ADDR, bin2bcd(tmp->tm_year % 100));
+ rtc_write(RTC_MON_REG_ADDR, bin2bcd(tmp->tm_mon));
+ rtc_write(RTC_DAY_REG_ADDR, bin2bcd(tmp->tm_wday + 1));
+ rtc_write(RTC_DATE_REG_ADDR, bin2bcd(tmp->tm_mday));
+ rtc_write(RTC_HR_REG_ADDR, bin2bcd(tmp->tm_hour));
+ rtc_write(RTC_MIN_REG_ADDR, bin2bcd(tmp->tm_min));
+ rtc_write(RTC_SEC_REG_ADDR, bin2bcd(tmp->tm_sec));
+
+ return 0;
+}
+
+/* Reset the RTC */
+void rtc_reset(void)
+{
+ rtc_write(RTC_SEC_REG_ADDR, 0x00); /* clearing Clock Halt */
+ rtc_write(RTC_CTL_STAT_REG_ADDR, RTC_PT7C4338_RESET_VAL);
+}
+#else
+static u8 rtc_read(struct udevice *dev, u8 reg)
+{
+ return dm_i2c_reg_read(dev, reg);
+}
+
+static void rtc_write(struct udevice *dev, u8 reg, u8 val)
+{
+ dm_i2c_reg_write(dev, reg, val);
+}
+
+static int pt7c4338_rtc_get(struct udevice *dev, struct rtc_time *tmp)
+{
+ int ret = 0;
+ u8 sec, min, hour, mday, wday, mon, year, ctl_stat;
+
+ ctl_stat = rtc_read(dev, RTC_CTL_STAT_REG_ADDR);
+ sec = rtc_read(dev, RTC_SEC_REG_ADDR);
+ min = rtc_read(dev, RTC_MIN_REG_ADDR);
+ hour = rtc_read(dev, RTC_HR_REG_ADDR);
+ wday = rtc_read(dev, RTC_DAY_REG_ADDR);
+ mday = rtc_read(dev, RTC_DATE_REG_ADDR);
+ mon = rtc_read(dev, RTC_MON_REG_ADDR);
+ year = rtc_read(dev, RTC_YR_REG_ADDR);
+ debug("Get RTC year: %02x mon: %02x mday: %02x wday: %02x\n",
+ year, mon, mday, wday);
+ debug("hr: %02x min: %02x sec: %02x control_status: %02x\n",
+ hour, min, sec, ctl_stat);
+
+ if (ctl_stat & RTC_CTL_STAT_BIT_OSF) {
+ printf("### Warning: RTC oscillator has stopped\n");
+ /* clear the OSF flag */
+ rtc_write(dev, RTC_CTL_STAT_REG_ADDR,
+ rtc_read(dev,
+ RTC_CTL_STAT_REG_ADDR)
+ & ~RTC_CTL_STAT_BIT_OSF);
+ ret = -1;
+ }
+
+ tmp->tm_sec = bcd2bin(sec & 0x7F);
+ tmp->tm_min = bcd2bin(min & 0x7F);
+ tmp->tm_hour = bcd2bin(hour & 0x3F);
+ tmp->tm_mday = bcd2bin(mday & 0x3F);
+ tmp->tm_mon = bcd2bin(mon & 0x1F);
+ tmp->tm_year = bcd2bin(year) + 2000;
+ tmp->tm_wday = bcd2bin((wday - 1) & 0x07);
+ tmp->tm_yday = 0;
+ tmp->tm_isdst = 0;
+ debug("Get DATE: %4d-%02d-%02d [wday=%d] TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ return ret;
+}
+
+static int pt7c4338_rtc_set(struct udevice *dev, const struct rtc_time *tmp)
+{
+ debug("Set DATE: %4d-%02d-%02d [wday=%d] TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ rtc_write(dev, RTC_YR_REG_ADDR, bin2bcd(tmp->tm_year % 100));
+ rtc_write(dev, RTC_MON_REG_ADDR, bin2bcd(tmp->tm_mon));
+ rtc_write(dev, RTC_DAY_REG_ADDR, bin2bcd(tmp->tm_wday + 1));
+ rtc_write(dev, RTC_DATE_REG_ADDR, bin2bcd(tmp->tm_mday));
+ rtc_write(dev, RTC_HR_REG_ADDR, bin2bcd(tmp->tm_hour));
+ rtc_write(dev, RTC_MIN_REG_ADDR, bin2bcd(tmp->tm_min));
+ rtc_write(dev, RTC_SEC_REG_ADDR, bin2bcd(tmp->tm_sec));
+
+ return 0;
+}
+
+static int pt7c4338_rtc_reset(struct udevice *dev)
+{
+ rtc_write(dev, RTC_SEC_REG_ADDR, 0x00); /* clearing Clock Halt */
+ rtc_write(dev, RTC_CTL_STAT_REG_ADDR, RTC_PT7C4338_RESET_VAL);
+ return 0;
+}
+
+static const struct rtc_ops pt7c4338_rtc_ops = {
+ .get = pt7c4338_rtc_get,
+ .set = pt7c4338_rtc_set,
+ .reset = pt7c4338_rtc_reset,
+};
+
+static const struct udevice_id pt7c4338_rtc_ids[] = {
+ { .compatible = "pericom,pt7c4338" },
+ { }
+};
+
+U_BOOT_DRIVER(rtc_pt7c4338) = {
+ .name = "rtc-pt7c4338",
+ .id = UCLASS_RTC,
+ .of_match = pt7c4338_rtc_ids,
+ .ops = &pt7c4338_rtc_ops,
+};
+#endif
diff --git a/roms/u-boot/drivers/rtc/rs5c372.c b/roms/u-boot/drivers/rtc/rs5c372.c
new file mode 100644
index 000000000..97ec001ae
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/rs5c372.c
@@ -0,0 +1,256 @@
+/*
+ * rs5c372.c
+ *
+ * Device driver for Ricoh's Real Time Controller RS5C372A.
+ *
+ * Copyright (C) 2004 Gary Jennejohn garyj@denx.de
+ *
+ * Based in part in ds1307.c -
+ * (C) Copyright 2001, 2002, 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * Keith Outwater, keith_outwater@mvis.com`
+ * Steven Scholz, steven.scholz@imc-berlin.de
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+#include <i2c.h>
+
+/*
+ * Reads are always done starting with register 15, which requires some
+ * jumping-through-hoops to access the data correctly.
+ *
+ * Writes are always done starting with register 0.
+ */
+
+#define DEBUG 0
+
+#if DEBUG
+static unsigned int rtc_debug = DEBUG;
+#else
+#define rtc_debug 0 /* gcc will remove all the debug code for us */
+#endif
+
+#ifndef CONFIG_SYS_I2C_RTC_ADDR
+#define CONFIG_SYS_I2C_RTC_ADDR 0x32
+#endif
+
+#define RS5C372_RAM_SIZE 0x10
+#define RATE_32000HZ 0x80 /* Rate Select 32.000KHz */
+#define RATE_32768HZ 0x00 /* Rate Select 32.768KHz */
+
+#define STATUS_XPT 0x10 /* data invalid because voltage was 0 */
+
+#define USE_24HOUR_MODE 0x20
+#define TWELVE_HOUR_MODE(n) ((((n) >> 5) & 1) == 0)
+#define HOURS_AP(n) (((n) >> 5) & 1)
+#define HOURS_12(n) bcd2bin((n) & 0x1F)
+#define HOURS_24(n) bcd2bin((n) & 0x3F)
+
+
+static int setup_done = 0;
+
+static int
+rs5c372_readram(unsigned char *buf, int len)
+{
+ int ret;
+
+ ret = i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 0, buf, len);
+ if (ret != 0) {
+ printf("%s: failed to read\n", __FUNCTION__);
+ return ret;
+ }
+
+ if (buf[0] & STATUS_XPT)
+ printf("### Warning: RTC lost power\n");
+
+ return ret;
+}
+
+static void
+rs5c372_enable(void)
+{
+ unsigned char buf[RS5C372_RAM_SIZE + 1];
+ int ret;
+
+ /* note that this returns reg. 15 in buf[1] */
+ ret = rs5c372_readram(&buf[1], RS5C372_RAM_SIZE);
+ if (ret != 0) {
+ printf("%s: failed\n", __FUNCTION__);
+ return;
+ }
+
+ buf[0] = 0;
+ /* we want to start writing at register 0 so we have to copy the */
+ /* register contents up one slot */
+ for (ret = 2; ret < 9; ret++)
+ buf[ret - 1] = buf[ret];
+ /* registers 0 to 6 (time values) are not touched */
+ buf[8] = RATE_32768HZ; /* reg. 7 */
+ buf[9] = 0; /* reg. 8 */
+ buf[10] = 0; /* reg. 9 */
+ buf[11] = 0; /* reg. 10 */
+ buf[12] = 0; /* reg. 11 */
+ buf[13] = 0; /* reg. 12 */
+ buf[14] = 0; /* reg. 13 */
+ buf[15] = 0; /* reg. 14 */
+ buf[16] = USE_24HOUR_MODE; /* reg. 15 */
+ ret = i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0, 0, buf, RS5C372_RAM_SIZE+1);
+ if (ret != 0) {
+ printf("%s: failed\n", __FUNCTION__);
+ return;
+ }
+ setup_done = 1;
+
+ return;
+}
+
+static void
+rs5c372_convert_to_time(struct rtc_time *dt, unsigned char *buf)
+{
+ /* buf[0] is register 15 */
+ dt->tm_sec = bcd2bin(buf[1]);
+ dt->tm_min = bcd2bin(buf[2]);
+
+ if (TWELVE_HOUR_MODE(buf[0])) {
+ dt->tm_hour = HOURS_12(buf[3]);
+ if (HOURS_AP(buf[3])) /* PM */
+ dt->tm_hour += 12;
+ } else /* 24-hour-mode */
+ dt->tm_hour = HOURS_24(buf[3]);
+
+ dt->tm_mday = bcd2bin(buf[5]);
+ dt->tm_mon = bcd2bin(buf[6]);
+ dt->tm_year = bcd2bin(buf[7]);
+ if (dt->tm_year >= 70)
+ dt->tm_year += 1900;
+ else
+ dt->tm_year += 2000;
+ /* 0 is Sunday */
+ dt->tm_wday = bcd2bin(buf[4] & 0x07);
+ dt->tm_yday = 0;
+ dt->tm_isdst= 0;
+
+ if(rtc_debug > 2) {
+ printf("rs5c372_convert_to_time: year = %d\n", dt->tm_year);
+ printf("rs5c372_convert_to_time: mon = %d\n", dt->tm_mon);
+ printf("rs5c372_convert_to_time: mday = %d\n", dt->tm_mday);
+ printf("rs5c372_convert_to_time: hour = %d\n", dt->tm_hour);
+ printf("rs5c372_convert_to_time: min = %d\n", dt->tm_min);
+ printf("rs5c372_convert_to_time: sec = %d\n", dt->tm_sec);
+ }
+}
+
+/*
+ * Get the current time from the RTC
+ */
+int
+rtc_get (struct rtc_time *tmp)
+{
+ unsigned char buf[RS5C372_RAM_SIZE];
+ int ret;
+
+ if (!setup_done)
+ rs5c372_enable();
+
+ if (!setup_done)
+ return -1;
+
+ memset(buf, 0, sizeof(buf));
+
+ /* note that this returns reg. 15 in buf[0] */
+ ret = rs5c372_readram(buf, RS5C372_RAM_SIZE);
+ if (ret != 0) {
+ printf("%s: failed\n", __FUNCTION__);
+ return -1;
+ }
+
+ rs5c372_convert_to_time(tmp, buf);
+
+ return 0;
+}
+
+/*
+ * Set the RTC
+ */
+int rtc_set (struct rtc_time *tmp)
+{
+ unsigned char buf[8], reg15;
+ int ret;
+
+ if (!setup_done)
+ rs5c372_enable();
+
+ if (!setup_done)
+ return -1;
+
+ if(rtc_debug > 2) {
+ printf("rtc_set: tm_year = %d\n", tmp->tm_year);
+ printf("rtc_set: tm_mon = %d\n", tmp->tm_mon);
+ printf("rtc_set: tm_mday = %d\n", tmp->tm_mday);
+ printf("rtc_set: tm_hour = %d\n", tmp->tm_hour);
+ printf("rtc_set: tm_min = %d\n", tmp->tm_min);
+ printf("rtc_set: tm_sec = %d\n", tmp->tm_sec);
+ }
+
+ memset(buf, 0, sizeof(buf));
+
+ /* only read register 15 */
+ ret = i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 0, buf, 1);
+
+ if (ret == 0) {
+ /* need to save register 15 */
+ reg15 = buf[0];
+ buf[0] = 0; /* register address on RS5C372 */
+ buf[1] = bin2bcd(tmp->tm_sec);
+ buf[2] = bin2bcd(tmp->tm_min);
+ /* need to handle 12 hour mode */
+ if (TWELVE_HOUR_MODE(reg15)) {
+ if (tmp->tm_hour >= 12) { /* PM */
+ /* 12 PM is a special case */
+ if (tmp->tm_hour == 12)
+ buf[3] = bin2bcd(tmp->tm_hour);
+ else
+ buf[3] = bin2bcd(tmp->tm_hour - 12);
+ buf[3] |= 0x20;
+ }
+ } else {
+ buf[3] = bin2bcd(tmp->tm_hour);
+ }
+
+ buf[4] = bin2bcd(tmp->tm_wday);
+ buf[5] = bin2bcd(tmp->tm_mday);
+ buf[6] = bin2bcd(tmp->tm_mon);
+ if (tmp->tm_year < 1970 || tmp->tm_year > 2069)
+ printf("WARNING: year should be between 1970 and 2069!\n");
+ buf[7] = bin2bcd(tmp->tm_year % 100);
+
+ ret = i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0, 0, buf, 8);
+ if (ret != 0) {
+ printf("rs5c372_set_datetime(), i2c_master_send() returned %d\n",ret);
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Reset the RTC.
+ */
+void
+rtc_reset (void)
+{
+ if (!setup_done)
+ rs5c372_enable();
+}
diff --git a/roms/u-boot/drivers/rtc/rtc-lib.c b/roms/u-boot/drivers/rtc/rtc-lib.c
new file mode 100644
index 000000000..1f7bdade2
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/rtc-lib.c
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * rtc and date/time utility functions
+ *
+ * Copyright (C) 2005-06 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * U-Boot rtc_time differs from Linux rtc_time:
+ * - The year field takes the actual value, not year - 1900.
+ * - January is month 1.
+ */
+
+#include <common.h>
+#include <rtc.h>
+#include <linux/math64.h>
+
+static const unsigned char rtc_days_in_month[] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
+
+/*
+ * The number of days in the month.
+ */
+int rtc_month_days(unsigned int month, unsigned int year)
+{
+ return rtc_days_in_month[month] + (is_leap_year(year) && month == 1);
+}
+
+/*
+ * rtc_to_tm - Converts u64 to rtc_time.
+ * Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
+ *
+ * This function is copied from rtc_time64_to_tm() in the Linux kernel.
+ * But in U-Boot January is month 1 and we do not subtract 1900 from the year.
+ */
+void rtc_to_tm(u64 time, struct rtc_time *tm)
+{
+ unsigned int month, year, secs;
+ int days;
+
+ days = div_u64_rem(time, 86400, &secs);
+
+ /* day of the week, 1970-01-01 was a Thursday */
+ tm->tm_wday = (days + 4) % 7;
+
+ year = 1970 + days / 365;
+ days -= (year - 1970) * 365
+ + LEAPS_THRU_END_OF(year - 1)
+ - LEAPS_THRU_END_OF(1970 - 1);
+ while (days < 0) {
+ year -= 1;
+ days += 365 + is_leap_year(year);
+ }
+ tm->tm_year = year; /* Not year - 1900 */
+ tm->tm_yday = days + 1;
+
+ for (month = 0; month < 11; month++) {
+ int newdays;
+
+ newdays = days - rtc_month_days(month, year);
+ if (newdays < 0)
+ break;
+ days = newdays;
+ }
+ tm->tm_mon = month + 1; /* January = 1 */
+ tm->tm_mday = days + 1;
+
+ tm->tm_hour = secs / 3600;
+ secs -= tm->tm_hour * 3600;
+ tm->tm_min = secs / 60;
+ tm->tm_sec = secs - tm->tm_min * 60;
+
+ /* Zero unused fields */
+ tm->tm_isdst = 0;
+}
diff --git a/roms/u-boot/drivers/rtc/rtc-uclass.c b/roms/u-boot/drivers/rtc/rtc-uclass.c
new file mode 100644
index 000000000..b406bab32
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/rtc-uclass.c
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <rtc.h>
+
+int dm_rtc_get(struct udevice *dev, struct rtc_time *time)
+{
+ struct rtc_ops *ops = rtc_get_ops(dev);
+
+ assert(ops);
+ if (!ops->get)
+ return -ENOSYS;
+ return ops->get(dev, time);
+}
+
+int dm_rtc_set(struct udevice *dev, struct rtc_time *time)
+{
+ struct rtc_ops *ops = rtc_get_ops(dev);
+
+ assert(ops);
+ if (!ops->set)
+ return -ENOSYS;
+ return ops->set(dev, time);
+}
+
+int dm_rtc_reset(struct udevice *dev)
+{
+ struct rtc_ops *ops = rtc_get_ops(dev);
+
+ assert(ops);
+ if (!ops->reset)
+ return -ENOSYS;
+ return ops->reset(dev);
+}
+
+int dm_rtc_read(struct udevice *dev, unsigned int reg, u8 *buf, unsigned int len)
+{
+ struct rtc_ops *ops = rtc_get_ops(dev);
+
+ assert(ops);
+ if (ops->read)
+ return ops->read(dev, reg, buf, len);
+ if (!ops->read8)
+ return -ENOSYS;
+ while (len--) {
+ int ret = ops->read8(dev, reg++);
+
+ if (ret < 0)
+ return ret;
+ *buf++ = ret;
+ }
+ return 0;
+}
+
+int dm_rtc_write(struct udevice *dev, unsigned int reg,
+ const u8 *buf, unsigned int len)
+{
+ struct rtc_ops *ops = rtc_get_ops(dev);
+
+ assert(ops);
+ if (ops->write)
+ return ops->write(dev, reg, buf, len);
+ if (!ops->write8)
+ return -ENOSYS;
+ while (len--) {
+ int ret = ops->write8(dev, reg++, *buf++);
+
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+int rtc_read8(struct udevice *dev, unsigned int reg)
+{
+ struct rtc_ops *ops = rtc_get_ops(dev);
+
+ assert(ops);
+ if (ops->read8)
+ return ops->read8(dev, reg);
+ if (ops->read) {
+ u8 buf[1];
+ int ret = ops->read(dev, reg, buf, 1);
+
+ if (ret < 0)
+ return ret;
+ return buf[0];
+ }
+ return -ENOSYS;
+}
+
+int rtc_write8(struct udevice *dev, unsigned int reg, int val)
+{
+ struct rtc_ops *ops = rtc_get_ops(dev);
+
+ assert(ops);
+ if (ops->write8)
+ return ops->write8(dev, reg, val);
+ if (ops->write) {
+ u8 buf[1] = { val };
+
+ return ops->write(dev, reg, buf, 1);
+ }
+ return -ENOSYS;
+}
+
+int rtc_read16(struct udevice *dev, unsigned int reg, u16 *valuep)
+{
+ u16 value = 0;
+ int ret;
+ int i;
+
+ for (i = 0; i < sizeof(value); i++) {
+ ret = rtc_read8(dev, reg + i);
+ if (ret < 0)
+ return ret;
+ value |= ret << (i << 3);
+ }
+
+ *valuep = value;
+ return 0;
+}
+
+int rtc_write16(struct udevice *dev, unsigned int reg, u16 value)
+{
+ int i, ret;
+
+ for (i = 0; i < sizeof(value); i++) {
+ ret = rtc_write8(dev, reg + i, (value >> (i << 3)) & 0xff);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int rtc_read32(struct udevice *dev, unsigned int reg, u32 *valuep)
+{
+ u32 value = 0;
+ int ret;
+ int i;
+
+ for (i = 0; i < sizeof(value); i++) {
+ ret = rtc_read8(dev, reg + i);
+ if (ret < 0)
+ return ret;
+ value |= ret << (i << 3);
+ }
+
+ *valuep = value;
+ return 0;
+}
+
+int rtc_write32(struct udevice *dev, unsigned int reg, u32 value)
+{
+ int i, ret;
+
+ for (i = 0; i < sizeof(value); i++) {
+ ret = rtc_write8(dev, reg + i, (value >> (i << 3)) & 0xff);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+UCLASS_DRIVER(rtc) = {
+ .name = "rtc",
+ .id = UCLASS_RTC,
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+ .post_bind = dm_scan_fdt_dev,
+#endif
+};
diff --git a/roms/u-boot/drivers/rtc/rv3028.c b/roms/u-boot/drivers/rtc/rv3028.c
new file mode 100644
index 000000000..9f63afc14
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/rv3028.c
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * RTC driver for the Micro Crystal RV3028
+ *
+ * based on linux driver from
+ * Copyright (C) 2019 Micro Crystal SA
+ *
+ * Alexandre Belloni <alexandre.belloni@bootlin.com>
+ *
+ */
+
+#include <dm.h>
+#include <i2c.h>
+#include <rtc.h>
+
+#define RV3028_SEC 0x00
+#define RV3028_MIN 0x01
+#define RV3028_HOUR 0x02
+#define RV3028_WDAY 0x03
+#define RV3028_DAY 0x04
+#define RV3028_MONTH 0x05
+#define RV3028_YEAR 0x06
+#define RV3028_ALARM_MIN 0x07
+#define RV3028_ALARM_HOUR 0x08
+#define RV3028_ALARM_DAY 0x09
+#define RV3028_STATUS 0x0E
+#define RV3028_CTRL1 0x0F
+#define RV3028_CTRL2 0x10
+#define RV3028_EVT_CTRL 0x13
+#define RV3028_TS_COUNT 0x14
+#define RV3028_TS_SEC 0x15
+#define RV3028_RAM1 0x1F
+#define RV3028_EEPROM_ADDR 0x25
+#define RV3028_EEPROM_DATA 0x26
+#define RV3028_EEPROM_CMD 0x27
+#define RV3028_CLKOUT 0x35
+#define RV3028_OFFSET 0x36
+#define RV3028_BACKUP 0x37
+
+#define RV3028_STATUS_PORF BIT(0)
+#define RV3028_STATUS_EVF BIT(1)
+#define RV3028_STATUS_AF BIT(2)
+#define RV3028_STATUS_TF BIT(3)
+#define RV3028_STATUS_UF BIT(4)
+#define RV3028_STATUS_BSF BIT(5)
+#define RV3028_STATUS_CLKF BIT(6)
+#define RV3028_STATUS_EEBUSY BIT(7)
+
+#define RV3028_CLKOUT_FD_MASK GENMASK(2, 0)
+#define RV3028_CLKOUT_PORIE BIT(3)
+#define RV3028_CLKOUT_CLKSY BIT(6)
+#define RV3028_CLKOUT_CLKOE BIT(7)
+
+#define RV3028_CTRL1_EERD BIT(3)
+#define RV3028_CTRL1_WADA BIT(5)
+
+#define RV3028_CTRL2_RESET BIT(0)
+#define RV3028_CTRL2_12_24 BIT(1)
+#define RV3028_CTRL2_EIE BIT(2)
+#define RV3028_CTRL2_AIE BIT(3)
+#define RV3028_CTRL2_TIE BIT(4)
+#define RV3028_CTRL2_UIE BIT(5)
+#define RV3028_CTRL2_TSE BIT(7)
+
+#define RV3028_EVT_CTRL_TSR BIT(2)
+
+#define RV3028_EEPROM_CMD_UPDATE 0x11
+#define RV3028_EEPROM_CMD_WRITE 0x21
+#define RV3028_EEPROM_CMD_READ 0x22
+
+#define RV3028_EEBUSY_POLL 10000
+#define RV3028_EEBUSY_TIMEOUT 100000
+
+#define RV3028_BACKUP_TCE BIT(5)
+#define RV3028_BACKUP_TCR_MASK GENMASK(1, 0)
+
+#define OFFSET_STEP_PPT 953674
+
+#define RTC_RV3028_LEN 7
+
+static int rv3028_rtc_get(struct udevice *dev, struct rtc_time *tm)
+{
+ u8 regs[RTC_RV3028_LEN];
+ u8 status;
+ int ret;
+
+ ret = dm_i2c_read(dev, RV3028_STATUS, &status, 1);
+ if (ret < 0) {
+ printf("%s: error reading RTC status: %x\n", __func__, ret);
+ return -EIO;
+ }
+
+ if (status & RV3028_STATUS_PORF) {
+ printf("Voltage low, data is invalid.\n");
+ return -EINVAL;
+ }
+
+ ret = dm_i2c_read(dev, RV3028_SEC, regs, sizeof(regs));
+ if (ret < 0) {
+ printf("%s: error reading RTC: %x\n", __func__, ret);
+ return -EIO;
+ }
+
+ tm->tm_sec = bcd2bin(regs[RV3028_SEC] & 0x7f);
+ tm->tm_min = bcd2bin(regs[RV3028_MIN] & 0x7f);
+ tm->tm_hour = bcd2bin(regs[RV3028_HOUR] & 0x3f);
+ tm->tm_wday = regs[RV3028_WDAY] & 0x7;
+ tm->tm_mday = bcd2bin(regs[RV3028_DAY] & 0x3f);
+ tm->tm_mon = bcd2bin(regs[RV3028_MONTH] & 0x1f);
+ tm->tm_year = bcd2bin(regs[RV3028_YEAR]) + 2000;
+ tm->tm_yday = 0;
+ tm->tm_isdst = 0;
+
+ debug("%s: %4d-%02d-%02d (wday=%d) %2d:%02d:%02d\n",
+ __func__, tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ return 0;
+}
+
+static int rv3028_rtc_set(struct udevice *dev, const struct rtc_time *tm)
+{
+ u8 regs[RTC_RV3028_LEN];
+ u8 status;
+ int ret;
+
+ debug("%s: %4d-%02d-%02d (wday=%d( %2d:%02d:%02d\n",
+ __func__, tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ if (tm->tm_year < 2000) {
+ printf("%s: year %d (before 2000) not supported\n",
+ __func__, tm->tm_year);
+ return -EINVAL;
+ }
+
+ regs[RV3028_SEC] = bin2bcd(tm->tm_sec);
+ regs[RV3028_MIN] = bin2bcd(tm->tm_min);
+ regs[RV3028_HOUR] = bin2bcd(tm->tm_hour);
+ regs[RV3028_WDAY] = tm->tm_wday;
+ regs[RV3028_DAY] = bin2bcd(tm->tm_mday);
+ regs[RV3028_MONTH] = bin2bcd(tm->tm_mon);
+ regs[RV3028_YEAR] = bin2bcd(tm->tm_year - 2000);
+
+ ret = dm_i2c_write(dev, RV3028_SEC, regs, sizeof(regs));
+ if (ret) {
+ printf("%s: set rtc error: %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = dm_i2c_read(dev, RV3028_STATUS, &status, 1);
+ if (ret < 0) {
+ printf("%s: error reading RTC status: %x\n", __func__, ret);
+ return -EIO;
+ }
+ status |= RV3028_STATUS_PORF;
+ return dm_i2c_write(dev, RV3028_STATUS, &status, 1);
+}
+
+static int rv3028_rtc_reset(struct udevice *dev)
+{
+ return 0;
+}
+
+static int rv3028_rtc_read8(struct udevice *dev, unsigned int reg)
+{
+ u8 data;
+ int ret;
+
+ ret = dm_i2c_read(dev, reg, &data, sizeof(data));
+ return ret < 0 ? ret : data;
+}
+
+static int rv3028_rtc_write8(struct udevice *dev, unsigned int reg, int val)
+{
+ u8 data = val;
+
+ return dm_i2c_write(dev, reg, &data, 1);
+}
+
+static int rv3028_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 rv3028_rtc_ops = {
+ .get = rv3028_rtc_get,
+ .set = rv3028_rtc_set,
+ .read8 = rv3028_rtc_read8,
+ .write8 = rv3028_rtc_write8,
+ .reset = rv3028_rtc_reset,
+};
+
+static const struct udevice_id rv3028_rtc_ids[] = {
+ { .compatible = "microcrystal,rv3028" },
+ { }
+};
+
+U_BOOT_DRIVER(rtc_rv3028) = {
+ .name = "rtc-rv3028",
+ .id = UCLASS_RTC,
+ .probe = rv3028_probe,
+ .of_match = rv3028_rtc_ids,
+ .ops = &rv3028_rtc_ops,
+};
diff --git a/roms/u-boot/drivers/rtc/rv3029.c b/roms/u-boot/drivers/rtc/rv3029.c
new file mode 100644
index 000000000..3afe5b2fd
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/rv3029.c
@@ -0,0 +1,500 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2018 Theobroma Systems Design und Consulting GmbH
+ *
+ * Based on a the Linux rtc-rv3029c2.c driver written by:
+ * Gregory Hermant <gregory.hermant@calao-systems.com>
+ * Michael Buesch <m@bues.ch>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <eeprom.h>
+#include <i2c.h>
+#include <log.h>
+#include <rtc.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+
+#define RTC_RV3029_PAGE_LEN 7
+
+/* control section */
+#define RV3029_ONOFF_CTRL 0x00
+#define RV3029_ONOFF_CTRL_WE BIT(0)
+#define RV3029_ONOFF_CTRL_TE BIT(1)
+#define RV3029_ONOFF_CTRL_TAR BIT(2)
+#define RV3029_ONOFF_CTRL_EERE BIT(3)
+#define RV3029_ONOFF_CTRL_SRON BIT(4)
+#define RV3029_ONOFF_CTRL_TD0 BIT(5)
+#define RV3029_ONOFF_CTRL_TD1 BIT(6)
+#define RV3029_ONOFF_CTRL_CLKINT BIT(7)
+#define RV3029_IRQ_CTRL 0x01
+#define RV3029_IRQ_CTRL_AIE BIT(0)
+#define RV3029_IRQ_CTRL_TIE BIT(1)
+#define RV3029_IRQ_CTRL_V1IE BIT(2)
+#define RV3029_IRQ_CTRL_V2IE BIT(3)
+#define RV3029_IRQ_CTRL_SRIE BIT(4)
+#define RV3029_IRQ_FLAGS 0x02
+#define RV3029_IRQ_FLAGS_AF BIT(0)
+#define RV3029_IRQ_FLAGS_TF BIT(1)
+#define RV3029_IRQ_FLAGS_V1IF BIT(2)
+#define RV3029_IRQ_FLAGS_V2IF BIT(3)
+#define RV3029_IRQ_FLAGS_SRF BIT(4)
+#define RV3029_STATUS 0x03
+#define RV3029_STATUS_VLOW1 BIT(2)
+#define RV3029_STATUS_VLOW2 BIT(3)
+#define RV3029_STATUS_SR BIT(4)
+#define RV3029_STATUS_PON BIT(5)
+#define RV3029_STATUS_EEBUSY BIT(7)
+#define RV3029_RST_CTRL 0x04
+#define RV3029_RST_CTRL_SYSR BIT(4)
+#define RV3029_CONTROL_SECTION_LEN 0x05
+
+/* watch section */
+#define RV3029_W_SEC 0x08
+#define RV3029_W_MINUTES 0x09
+#define RV3029_W_HOURS 0x0A
+#define RV3029_REG_HR_12_24 BIT(6) /* 24h/12h mode */
+#define RV3029_REG_HR_PM BIT(5) /* PM/AM bit in 12h mode */
+#define RV3029_W_DATE 0x0B
+#define RV3029_W_DAYS 0x0C
+#define RV3029_W_MONTHS 0x0D
+#define RV3029_W_YEARS 0x0E
+
+/* eeprom control section */
+#define RV3029_CONTROL_E2P_EECTRL 0x30
+#define RV3029_TRICKLE_1K BIT(4) /* 1.5K resistance */
+#define RV3029_TRICKLE_5K BIT(5) /* 5K resistance */
+#define RV3029_TRICKLE_20K BIT(6) /* 20K resistance */
+#define RV3029_TRICKLE_80K BIT(7) /* 80K resistance */
+#define RV3029_TRICKLE_MASK (RV3029_TRICKLE_1K |\
+ RV3029_TRICKLE_5K |\
+ RV3029_TRICKLE_20K |\
+ RV3029_TRICKLE_80K)
+#define RV3029_TRICKLE_SHIFT 4
+
+
+static int rv3029_rtc_get(struct udevice *dev, struct rtc_time *tm)
+{
+ u8 regs[RTC_RV3029_PAGE_LEN];
+ int ret;
+
+ ret = dm_i2c_read(dev, RV3029_W_SEC, regs, sizeof(regs));
+ if (ret < 0) {
+ printf("%s: error reading RTC: %x\n", __func__, ret);
+ return -EIO;
+ }
+
+ tm->tm_sec = bcd2bin(regs[RV3029_W_SEC - RV3029_W_SEC]);
+ tm->tm_min = bcd2bin(regs[RV3029_W_MINUTES - RV3029_W_SEC]);
+
+ /* HR field has a more complex interpretation */
+ {
+ const u8 _hr = regs[RV3029_W_HOURS - RV3029_W_SEC];
+
+ if (_hr & RV3029_REG_HR_12_24) {
+ /* 12h format */
+ tm->tm_hour = bcd2bin(_hr & 0x1f);
+ if (_hr & RV3029_REG_HR_PM) /* PM flag set */
+ tm->tm_hour += 12;
+ } else {
+ /* 24h format */
+ tm->tm_hour = bcd2bin(_hr & 0x3f);
+ }
+ }
+
+ tm->tm_mday = bcd2bin(regs[RV3029_W_DATE - RV3029_W_SEC]);
+ tm->tm_mon = bcd2bin(regs[RV3029_W_MONTHS - RV3029_W_SEC]) - 1;
+ /* RTC supports only years > 1999 */
+ tm->tm_year = bcd2bin(regs[RV3029_W_YEARS - RV3029_W_SEC]) + 2000;
+ tm->tm_wday = bcd2bin(regs[RV3029_W_DAYS - RV3029_W_SEC]) - 1;
+
+ tm->tm_yday = 0;
+ tm->tm_isdst = 0;
+
+ debug("%s: %4d-%02d-%02d (wday=%d) %2d:%02d:%02d\n",
+ __func__, tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ return 0;
+}
+
+static int rv3029_rtc_set(struct udevice *dev, const struct rtc_time *tm)
+{
+ u8 regs[RTC_RV3029_PAGE_LEN];
+
+ debug("%s: %4d-%02d-%02d (wday=%d( %2d:%02d:%02d\n",
+ __func__, tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+
+ if (tm->tm_year < 2000) {
+ printf("%s: year %d (before 2000) not supported\n",
+ __func__, tm->tm_year);
+ return -EINVAL;
+ }
+
+ regs[RV3029_W_SEC - RV3029_W_SEC] = bin2bcd(tm->tm_sec);
+ regs[RV3029_W_MINUTES - RV3029_W_SEC] = bin2bcd(tm->tm_min);
+ regs[RV3029_W_HOURS - RV3029_W_SEC] = bin2bcd(tm->tm_hour);
+ regs[RV3029_W_DATE - RV3029_W_SEC] = bin2bcd(tm->tm_mday);
+ regs[RV3029_W_MONTHS - RV3029_W_SEC] = bin2bcd(tm->tm_mon + 1);
+ regs[RV3029_W_DAYS - RV3029_W_SEC] = bin2bcd(tm->tm_wday + 1) & 0x7;
+ regs[RV3029_W_YEARS - RV3029_W_SEC] = bin2bcd(tm->tm_year - 2000);
+
+ return dm_i2c_write(dev, RV3029_W_SEC, regs, sizeof(regs));
+}
+
+static int rv3029_rtc_reset(struct udevice *dev)
+{
+ u8 ctrl = RV3029_RST_CTRL_SYSR;
+ unsigned long start;
+ const unsigned long timeout_ms = 10000;
+ int ret;
+
+ /* trigger the system-reset */
+ ret = dm_i2c_write(dev, RV3029_RST_CTRL, &ctrl, 1);
+ if (ret < 0)
+ return -EIO;
+
+ /* wait for the system-reset to complete */
+ start = get_timer(0);
+ do {
+ if (get_timer(start) > timeout_ms)
+ return -ETIMEDOUT;
+
+ ret = dm_i2c_read(dev, RV3029_RST_CTRL, &ctrl, 1);
+ if (ret < 0)
+ return -EIO;
+ } while (ctrl & RV3029_RST_CTRL_SYSR);
+
+ return 0;
+}
+
+static int rv3029_rtc_read8(struct udevice *dev, unsigned int reg)
+{
+ u8 data;
+ int ret;
+
+ ret = dm_i2c_read(dev, reg, &data, sizeof(data));
+ return ret < 0 ? ret : data;
+}
+
+static int rv3029_rtc_write8(struct udevice *dev, unsigned int reg, int val)
+{
+ u8 data = val;
+
+ return dm_i2c_write(dev, reg, &data, 1);
+}
+
+#if defined(OF_CONTROL)
+static int rv3029_get_sr(struct udevice *dev, u8 *buf)
+{
+ int ret = dm_i2c_read(dev, RV3029_STATUS, buf, 1);
+
+ if (ret < 0)
+ return -EIO;
+
+ dev_dbg(dev, "status = 0x%.2x (%d)\n", buf[0], buf[0]);
+ return 0;
+}
+
+static int rv3029_set_sr(struct udevice *dev, u8 val)
+{
+ int ret;
+
+ ret = dm_i2c_read(dev, RV3029_STATUS, &val, 1);
+ if (ret < 0)
+ return -EIO;
+
+ dev_dbg(dev, "status = 0x%.2x (%d)\n", val, val);
+ return 0;
+}
+
+static int rv3029_eeprom_busywait(struct udevice *dev)
+{
+ int i, ret;
+ u8 sr;
+
+ for (i = 100; i > 0; i--) {
+ ret = rv3029_get_sr(dev, &sr);
+ if (ret < 0)
+ break;
+ if (!(sr & RV3029_STATUS_EEBUSY))
+ break;
+ udelay(10000);
+ }
+ if (i <= 0) {
+ dev_err(dev, "EEPROM busy wait timeout.\n");
+ return -ETIMEDOUT;
+ }
+
+ return ret;
+}
+
+static int rv3029_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 rv3029_eeprom_exit(struct udevice *dev)
+{
+ /* Re-enable eeprom refresh */
+ return rv3029_update_bits(dev, RV3029_ONOFF_CTRL,
+ RV3029_ONOFF_CTRL_EERE,
+ RV3029_ONOFF_CTRL_EERE);
+}
+
+static int rv3029_eeprom_enter(struct udevice *dev)
+{
+ int ret;
+ u8 sr;
+
+ /* Check whether we are in the allowed voltage range. */
+ ret = rv3029_get_sr(dev, &sr);
+ if (ret < 0)
+ return ret;
+ if (sr & (RV3029_STATUS_VLOW1 | RV3029_STATUS_VLOW2)) {
+ /* We clear the bits and retry once just in case
+ * we had a brown out in early startup.
+ */
+ sr &= ~RV3029_STATUS_VLOW1;
+ sr &= ~RV3029_STATUS_VLOW2;
+ ret = rv3029_set_sr(dev, sr);
+ if (ret < 0)
+ return ret;
+ udelay(10000);
+ ret = rv3029_get_sr(dev, &sr);
+ if (ret < 0)
+ return ret;
+ if (sr & (RV3029_STATUS_VLOW1 | RV3029_STATUS_VLOW2)) {
+ dev_err(dev, "Supply voltage is too low to safely access the EEPROM.\n");
+ return -ENODEV;
+ }
+ }
+
+ /* Disable eeprom refresh. */
+ ret = rv3029_update_bits(dev,
+ RV3029_ONOFF_CTRL, RV3029_ONOFF_CTRL_EERE, 0);
+ if (ret < 0)
+ return ret;
+
+ /* Wait for any previous eeprom accesses to finish. */
+ ret = rv3029_eeprom_busywait(dev);
+ if (ret < 0)
+ rv3029_eeprom_exit(dev);
+
+ return ret;
+}
+
+static int rv3029_eeprom_read(struct udevice *dev, u8 reg,
+ u8 buf[], size_t len)
+{
+ int ret, err;
+
+ err = rv3029_eeprom_enter(dev);
+ if (err < 0)
+ return err;
+
+ ret = dm_i2c_read(dev, reg, buf, len);
+
+ err = rv3029_eeprom_exit(dev);
+ if (err < 0)
+ return err;
+
+ return ret;
+}
+
+static int rv3029_eeprom_write(struct udevice *dev, u8 reg,
+ u8 const buf[], size_t len)
+{
+ int ret;
+ size_t i;
+ u8 tmp;
+
+ ret = rv3029_eeprom_enter(dev);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < len; i++, reg++) {
+ ret = dm_i2c_read(dev, reg, &tmp, 1);
+ if (ret < 0)
+ break;
+ if (tmp != buf[i]) {
+ ret = dm_i2c_write(dev, reg, &buf[i], 1);
+ if (ret < 0)
+ break;
+ }
+ ret = rv3029_eeprom_busywait(dev);
+ if (ret < 0)
+ break;
+ }
+
+ ret = rv3029_eeprom_exit(dev);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int rv3029_eeprom_update_bits(struct udevice *dev,
+ u8 reg, u8 mask, u8 set)
+{
+ u8 buf;
+ int ret;
+
+ ret = rv3029_eeprom_read(dev, reg, &buf, 1);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * If the EEPROM already reads the correct bitpattern, we don't need
+ * to update it.
+ */
+ if ((buf & mask) == (set & mask))
+ return 0;
+
+ buf = (buf & ~mask) | (set & mask);
+ ret = rv3029_eeprom_write(dev, reg, &buf, 1);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static void rv3029_trickle_config(struct udevice *dev)
+{
+ static const struct rv3029_trickle_tab_elem {
+ u32 r; /* resistance in ohms */
+ u8 conf; /* trickle config bits */
+ } rv3029_trickle_tab[] = {
+ {
+ .r = 1076,
+ .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K |
+ RV3029_TRICKLE_20K | RV3029_TRICKLE_80K,
+ }, {
+ .r = 1091,
+ .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K |
+ RV3029_TRICKLE_20K,
+ }, {
+ .r = 1137,
+ .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K |
+ RV3029_TRICKLE_80K,
+ }, {
+ .r = 1154,
+ .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K,
+ }, {
+ .r = 1371,
+ .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_20K |
+ RV3029_TRICKLE_80K,
+ }, {
+ .r = 1395,
+ .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_20K,
+ }, {
+ .r = 1472,
+ .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_80K,
+ }, {
+ .r = 1500,
+ .conf = RV3029_TRICKLE_1K,
+ }, {
+ .r = 3810,
+ .conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_20K |
+ RV3029_TRICKLE_80K,
+ }, {
+ .r = 4000,
+ .conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_20K,
+ }, {
+ .r = 4706,
+ .conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_80K,
+ }, {
+ .r = 5000,
+ .conf = RV3029_TRICKLE_5K,
+ }, {
+ .r = 16000,
+ .conf = RV3029_TRICKLE_20K | RV3029_TRICKLE_80K,
+ }, {
+ .r = 20000,
+ .conf = RV3029_TRICKLE_20K,
+ }, {
+ .r = 80000,
+ .conf = RV3029_TRICKLE_80K,
+ },
+ };
+ int err;
+ u32 ohms;
+ u8 trickle_set_bits = 0;
+
+ /* Configure the trickle charger. */
+ err = dev_read_u32(dev, "trickle-resistor-ohms", &ohms);
+
+ if (!err) {
+ /* Find trickle-charger config */
+ for (int i = 0; i < ARRAY_SIZE(rv3029_trickle_tab); i++)
+ if (rv3029_trickle_tab[i].r >= ohms) {
+ dev_dbg(dev, "trickle charger at %d ohms\n",
+ rv3029_trickle_tab[i].r);
+ trickle_set_bits = rv3029_trickle_tab[i].conf;
+ break;
+ }
+ }
+
+ dev_dbg(dev, "trickle charger config 0x%x\n", trickle_set_bits);
+ err = rv3029_eeprom_update_bits(dev, RV3029_CONTROL_E2P_EECTRL,
+ RV3029_TRICKLE_MASK,
+ trickle_set_bits);
+ if (err < 0)
+ dev_dbg(dev, "failed to update trickle charger\n");
+}
+#else
+static inline void rv3029_trickle_config(struct udevice *dev)
+{
+}
+#endif
+
+static int rv3029_probe(struct udevice *dev)
+{
+ i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS |
+ DM_I2C_CHIP_WR_ADDRESS);
+
+ rv3029_trickle_config(dev);
+ return 0;
+}
+
+static const struct rtc_ops rv3029_rtc_ops = {
+ .get = rv3029_rtc_get,
+ .set = rv3029_rtc_set,
+ .read8 = rv3029_rtc_read8,
+ .write8 = rv3029_rtc_write8,
+ .reset = rv3029_rtc_reset,
+};
+
+static const struct udevice_id rv3029_rtc_ids[] = {
+ { .compatible = "mc,rv3029" },
+ { .compatible = "mc,rv3029c2" },
+ { }
+};
+
+U_BOOT_DRIVER(rtc_rv3029) = {
+ .name = "rtc-rv3029",
+ .id = UCLASS_RTC,
+ .probe = rv3029_probe,
+ .of_match = rv3029_rtc_ids,
+ .ops = &rv3029_rtc_ops,
+};
diff --git a/roms/u-boot/drivers/rtc/rv8803.c b/roms/u-boot/drivers/rtc/rv8803.c
new file mode 100644
index 000000000..acd50c656
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/rv8803.c
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Date & Time support for Micro Crystal RV-8803-C7.
+ *
+ * based on ds1307.c which is
+ * (C) Copyright 2001, 2002, 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * Keith Outwater, keith_outwater@mvis.com`
+ * Steven Scholz, steven.scholz@imc-berlin.de
+ *
+ */
+
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <log.h>
+#include <rtc.h>
+#include <i2c.h>
+#include <linux/bitops.h>
+
+/*
+ * RTC register addresses
+ */
+#define RTC_SEC_REG_ADDR 0x00
+#define RTC_MIN_REG_ADDR 0x01
+#define RTC_HR_REG_ADDR 0x02
+#define RTC_DAY_REG_ADDR 0x03
+#define RTC_DATE_REG_ADDR 0x04
+#define RTC_MON_REG_ADDR 0x05
+#define RTC_YR_REG_ADDR 0x06
+
+#define RTC_FLAG_REG_ADDR 0x0E
+#define RTC_FLAG_BIT_V1F BIT(0)
+#define RTC_FLAG_BIT_V2F BIT(1)
+
+#define RTC_CTL_REG_ADDR 0x0F
+#define RTC_CTL_BIT_RST BIT(0)
+
+static int rv8803_rtc_set(struct udevice *dev, const struct rtc_time *tm)
+{
+ int ret;
+ u8 buf[7];
+
+ debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ if (tm->tm_year < 2000 || tm->tm_year > 2099)
+ printf("WARNING: year should be between 2000 and 2099!\n");
+
+ buf[RTC_YR_REG_ADDR] = bin2bcd(tm->tm_year % 100);
+ buf[RTC_MON_REG_ADDR] = bin2bcd(tm->tm_mon);
+ buf[RTC_DAY_REG_ADDR] = 1 << (tm->tm_wday & 0x7);
+ buf[RTC_DATE_REG_ADDR] = bin2bcd(tm->tm_mday);
+ buf[RTC_HR_REG_ADDR] = bin2bcd(tm->tm_hour);
+ buf[RTC_MIN_REG_ADDR] = bin2bcd(tm->tm_min);
+ buf[RTC_SEC_REG_ADDR] = bin2bcd(tm->tm_sec);
+
+ ret = dm_i2c_write(dev, 0, buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int rv8803_rtc_get(struct udevice *dev, struct rtc_time *tm)
+{
+ int ret;
+ u8 buf[7];
+ int flags;
+
+ flags = dm_i2c_reg_read(dev, RTC_FLAG_REG_ADDR);
+ if (flags < 0)
+ return flags;
+ debug("%s: flags=%Xh\n", __func__, flags);
+
+ if (flags & RTC_FLAG_BIT_V1F)
+ printf("### Warning: temperature compensation has stopped\n");
+
+ if (flags & RTC_FLAG_BIT_V2F) {
+ printf("### Warning: Voltage low, data is invalid\n");
+ return -1;
+ }
+
+ ret = dm_i2c_read(dev, 0, buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+
+ tm->tm_sec = bcd2bin(buf[RTC_SEC_REG_ADDR] & 0x7F);
+ tm->tm_min = bcd2bin(buf[RTC_MIN_REG_ADDR] & 0x7F);
+ tm->tm_hour = bcd2bin(buf[RTC_HR_REG_ADDR] & 0x3F);
+ tm->tm_mday = bcd2bin(buf[RTC_DATE_REG_ADDR] & 0x3F);
+ tm->tm_mon = bcd2bin(buf[RTC_MON_REG_ADDR] & 0x1F);
+ tm->tm_year = bcd2bin(buf[RTC_YR_REG_ADDR]) + 2000;
+ tm->tm_wday = fls(buf[RTC_DAY_REG_ADDR] & 0x7F) - 1;
+ tm->tm_yday = 0;
+ tm->tm_isdst = 0;
+
+ debug("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ return 0;
+}
+
+static int rv8803_rtc_reset(struct udevice *dev)
+{
+ int ret;
+ struct rtc_time tmp = {
+ .tm_year = 2000,
+ .tm_mon = 1,
+ .tm_mday = 1,
+ .tm_hour = 0,
+ .tm_min = 0,
+ .tm_sec = 0,
+ };
+
+ /* assert reset */
+ ret = dm_i2c_reg_write(dev, RTC_CTL_REG_ADDR, RTC_CTL_BIT_RST);
+ if (ret < 0)
+ return ret;
+
+ /* clear all flags */
+ ret = dm_i2c_reg_write(dev, RTC_FLAG_REG_ADDR, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = rv8803_rtc_set(dev, &tmp);
+ if (ret < 0)
+ return ret;
+
+ /* clear reset */
+ ret = dm_i2c_reg_write(dev, RTC_CTL_REG_ADDR, 0);
+ if (ret < 0)
+ return ret;
+
+ debug("RTC: %4d-%02d-%02d %2d:%02d:%02d UTC\n",
+ tmp.tm_year, tmp.tm_mon, tmp.tm_mday,
+ tmp.tm_hour, tmp.tm_min, tmp.tm_sec);
+
+ return 0;
+}
+
+static int rv8803_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 rv8803_rtc_ops = {
+ .get = rv8803_rtc_get,
+ .set = rv8803_rtc_set,
+ .reset = rv8803_rtc_reset,
+};
+
+static const struct udevice_id rv8803_rtc_ids[] = {
+ { .compatible = "microcrystal,rv8803", },
+ { }
+};
+
+U_BOOT_DRIVER(rtc_rv8803) = {
+ .name = "rtc-rv8803",
+ .id = UCLASS_RTC,
+ .probe = rv8803_probe,
+ .of_match = rv8803_rtc_ids,
+ .ops = &rv8803_rtc_ops,
+};
diff --git a/roms/u-boot/drivers/rtc/rx8010sj.c b/roms/u-boot/drivers/rtc/rx8010sj.c
new file mode 100644
index 000000000..d513561b8
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/rx8010sj.c
@@ -0,0 +1,380 @@
+/*
+ * Epson RX8010 RTC driver.
+ *
+ * Copyright (c) 2017, General Electric Company
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <command.h>
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <rtc.h>
+#include <linux/bitops.h>
+
+/*---------------------------------------------------------------------*/
+/* #undef DEBUG_RTC */
+
+#ifdef DEBUG_RTC
+#define DEBUGR(fmt, args...) printf(fmt, ##args)
+#else
+#define DEBUGR(fmt, args...)
+#endif
+/*---------------------------------------------------------------------*/
+
+#ifndef CONFIG_SYS_I2C_RTC_ADDR
+# define CONFIG_SYS_I2C_RTC_ADDR 0x32
+#endif
+
+/*
+ * RTC register addresses
+ */
+#define RX8010_SEC 0x10
+#define RX8010_MIN 0x11
+#define RX8010_HOUR 0x12
+#define RX8010_WDAY 0x13
+#define RX8010_MDAY 0x14
+#define RX8010_MONTH 0x15
+#define RX8010_YEAR 0x16
+#define RX8010_YEAR 0x16
+#define RX8010_RESV17 0x17
+#define RX8010_ALMIN 0x18
+#define RX8010_ALHOUR 0x19
+#define RX8010_ALWDAY 0x1A
+#define RX8010_TCOUNT0 0x1B
+#define RX8010_TCOUNT1 0x1C
+#define RX8010_EXT 0x1D
+#define RX8010_FLAG 0x1E
+#define RX8010_CTRL 0x1F
+/* 0x20 to 0x2F are user registers */
+#define RX8010_RESV30 0x30
+#define RX8010_RESV31 0x32
+#define RX8010_IRQ 0x32
+
+#define RX8010_EXT_WADA BIT(3)
+
+#define RX8010_FLAG_VLF BIT(1)
+#define RX8010_FLAG_AF BIT(3)
+#define RX8010_FLAG_TF BIT(4)
+#define RX8010_FLAG_UF BIT(5)
+
+#define RX8010_CTRL_AIE BIT(3)
+#define RX8010_CTRL_UIE BIT(5)
+#define RX8010_CTRL_STOP BIT(6)
+#define RX8010_CTRL_TEST BIT(7)
+
+#define RX8010_ALARM_AE BIT(7)
+
+#ifdef CONFIG_DM_RTC
+
+#define DEV_TYPE struct udevice
+
+#else
+
+/* Local udevice */
+struct ludevice {
+ u8 chip;
+};
+
+#define DEV_TYPE struct ludevice
+
+#endif
+
+static int rx8010sj_rtc_read8(DEV_TYPE *dev, unsigned int reg)
+{
+ u8 val;
+ int ret;
+
+#ifdef CONFIG_DM_RTC
+ ret = dm_i2c_read(dev, reg, &val, sizeof(val));
+#else
+ ret = i2c_read(dev->chip, reg, 1, &val, 1);
+#endif
+
+ return ret < 0 ? ret : val;
+}
+
+static int rx8010sj_rtc_write8(DEV_TYPE *dev, unsigned int reg, int val)
+{
+ int ret;
+ u8 lval = val;
+
+#ifdef CONFIG_DM_RTC
+ ret = dm_i2c_write(dev, reg, &lval, 1);
+#else
+ ret = i2c_write(dev->chip, reg, 1, &lval, 1);
+#endif
+
+ return ret < 0 ? ret : 0;
+}
+
+static int validate_time(const struct rtc_time *tm)
+{
+ if ((tm->tm_year < 2000) || (tm->tm_year > 2099))
+ return -EINVAL;
+
+ if ((tm->tm_mon < 1) || (tm->tm_mon > 12))
+ return -EINVAL;
+
+ if ((tm->tm_mday < 1) || (tm->tm_mday > 31))
+ return -EINVAL;
+
+ if ((tm->tm_wday < 0) || (tm->tm_wday > 6))
+ return -EINVAL;
+
+ if ((tm->tm_hour < 0) || (tm->tm_hour > 23))
+ return -EINVAL;
+
+ if ((tm->tm_min < 0) || (tm->tm_min > 59))
+ return -EINVAL;
+
+ if ((tm->tm_sec < 0) || (tm->tm_sec > 59))
+ return -EINVAL;
+
+ return 0;
+}
+
+void rx8010sj_rtc_init(DEV_TYPE *dev)
+{
+ u8 ctrl[2];
+ int need_clear = 0, ret = 0;
+
+ /* Initialize reserved registers as specified in datasheet */
+ ret = rx8010sj_rtc_write8(dev, RX8010_RESV17, 0xD8);
+ if (ret < 0)
+ goto error;
+
+ ret = rx8010sj_rtc_write8(dev, RX8010_RESV30, 0x00);
+ if (ret < 0)
+ goto error;
+
+ ret = rx8010sj_rtc_write8(dev, RX8010_RESV31, 0x08);
+ if (ret < 0)
+ goto error;
+
+ ret = rx8010sj_rtc_write8(dev, RX8010_IRQ, 0x00);
+ if (ret < 0)
+ goto error;
+
+ for (int i = 0; i < 2; i++) {
+ ret = rx8010sj_rtc_read8(dev, RX8010_FLAG + i);
+ if (ret < 0)
+ goto error;
+
+ ctrl[i] = ret;
+ }
+
+ if (ctrl[0] & RX8010_FLAG_VLF)
+ printf("RTC low voltage detected\n");
+
+ if (ctrl[0] & RX8010_FLAG_AF) {
+ printf("Alarm was detected\n");
+ need_clear = 1;
+ }
+
+ if (ctrl[0] & RX8010_FLAG_TF)
+ need_clear = 1;
+
+ if (ctrl[0] & RX8010_FLAG_UF)
+ need_clear = 1;
+
+ if (need_clear) {
+ ctrl[0] &= ~(RX8010_FLAG_AF | RX8010_FLAG_TF | RX8010_FLAG_UF);
+ ret = rx8010sj_rtc_write8(dev, RX8010_FLAG, ctrl[0]);
+ if (ret < 0)
+ goto error;
+ }
+
+ return;
+
+error:
+ printf("Error rtc init.\n");
+}
+
+/* Get the current time from the RTC */
+static int rx8010sj_rtc_get(DEV_TYPE *dev, struct rtc_time *tmp)
+{
+ u8 date[7];
+ int flagreg;
+ int ret;
+
+ flagreg = rx8010sj_rtc_read8(dev, RX8010_FLAG);
+ if (flagreg < 0) {
+ DEBUGR("Error reading from RTC. err: %d\n", flagreg);
+ return -EIO;
+ }
+
+ if (flagreg & RX8010_FLAG_VLF) {
+ DEBUGR("RTC low voltage detected\n");
+ return -EINVAL;
+ }
+
+ for (int i = 0; i < 7; i++) {
+ ret = rx8010sj_rtc_read8(dev, RX8010_SEC + i);
+ if (ret < 0) {
+ DEBUGR("Error reading from RTC. err: %d\n", ret);
+ return -EIO;
+ }
+ date[i] = ret;
+ }
+
+ tmp->tm_sec = bcd2bin(date[RX8010_SEC - RX8010_SEC] & 0x7f);
+ tmp->tm_min = bcd2bin(date[RX8010_MIN - RX8010_SEC] & 0x7f);
+ tmp->tm_hour = bcd2bin(date[RX8010_HOUR - RX8010_SEC] & 0x3f);
+ tmp->tm_mday = bcd2bin(date[RX8010_MDAY - RX8010_SEC] & 0x3f);
+ tmp->tm_mon = bcd2bin(date[RX8010_MONTH - RX8010_SEC] & 0x1f);
+ tmp->tm_year = bcd2bin(date[RX8010_YEAR - RX8010_SEC]) + 2000;
+ tmp->tm_wday = 0;
+ tmp->tm_yday = 0;
+ tmp->tm_isdst = 0;
+
+ DEBUGR("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ return 0;
+}
+
+/* Set the RTC */
+static int rx8010sj_rtc_set(DEV_TYPE *dev, const struct rtc_time *tm)
+{
+ u8 date[7];
+ int ctrl, flagreg;
+ int ret;
+
+ ret = validate_time(tm);
+ if (ret < 0)
+ return -EINVAL;
+
+ /* set STOP bit before changing clock/calendar */
+ ctrl = rx8010sj_rtc_read8(dev, RX8010_CTRL);
+ if (ctrl < 0)
+ return ctrl;
+ ret = rx8010sj_rtc_write8(dev, RX8010_CTRL, ctrl | RX8010_CTRL_STOP);
+ if (ret < 0)
+ return ret;
+
+ date[RX8010_SEC - RX8010_SEC] = bin2bcd(tm->tm_sec);
+ date[RX8010_MIN - RX8010_SEC] = bin2bcd(tm->tm_min);
+ date[RX8010_HOUR - RX8010_SEC] = bin2bcd(tm->tm_hour);
+ date[RX8010_MDAY - RX8010_SEC] = bin2bcd(tm->tm_mday);
+ date[RX8010_MONTH - RX8010_SEC] = bin2bcd(tm->tm_mon);
+ date[RX8010_YEAR - RX8010_SEC] = bin2bcd(tm->tm_year - 2000);
+ date[RX8010_WDAY - RX8010_SEC] = bin2bcd(tm->tm_wday);
+
+ for (int i = 0; i < 7; i++) {
+ ret = rx8010sj_rtc_write8(dev, RX8010_SEC + i, date[i]);
+ if (ret < 0) {
+ DEBUGR("Error writing to RTC. err: %d\n", ret);
+ return -EIO;
+ }
+ }
+
+ /* clear STOP bit after changing clock/calendar */
+ ctrl = rx8010sj_rtc_read8(dev, RX8010_CTRL);
+ if (ctrl < 0)
+ return ctrl;
+
+ ret = rx8010sj_rtc_write8(dev, RX8010_CTRL, ctrl & ~RX8010_CTRL_STOP);
+ if (ret < 0)
+ return ret;
+
+ flagreg = rx8010sj_rtc_read8(dev, RX8010_FLAG);
+ if (flagreg < 0)
+ return flagreg;
+
+ if (flagreg & RX8010_FLAG_VLF)
+ ret = rx8010sj_rtc_write8(dev, RX8010_FLAG,
+ flagreg & ~RX8010_FLAG_VLF);
+
+ return 0;
+}
+
+/* Reset the RTC. */
+static int rx8010sj_rtc_reset(DEV_TYPE *dev)
+{
+ /* Not needed */
+ return 0;
+}
+
+#ifndef CONFIG_DM_RTC
+
+int rtc_get(struct rtc_time *tm)
+{
+ struct ludevice dev = {
+ .chip = CONFIG_SYS_I2C_RTC_ADDR,
+ };
+
+ return rx8010sj_rtc_get(&dev, tm);
+}
+
+int rtc_set(struct rtc_time *tm)
+{
+ struct ludevice dev = {
+ .chip = CONFIG_SYS_I2C_RTC_ADDR,
+ };
+
+ return rx8010sj_rtc_set(&dev, tm);
+}
+
+void rtc_reset(void)
+{
+ struct ludevice dev = {
+ .chip = CONFIG_SYS_I2C_RTC_ADDR,
+ };
+
+ rx8010sj_rtc_reset(&dev);
+}
+
+void rtc_init(void)
+{
+ struct ludevice dev = {
+ .chip = CONFIG_SYS_I2C_RTC_ADDR,
+ };
+
+ rx8010sj_rtc_init(&dev);
+}
+
+#else
+
+static int rx8010sj_probe(struct udevice *dev)
+{
+ rx8010sj_rtc_init(dev);
+
+ return 0;
+}
+
+static const struct rtc_ops rx8010sj_rtc_ops = {
+ .get = rx8010sj_rtc_get,
+ .set = rx8010sj_rtc_set,
+ .read8 = rx8010sj_rtc_read8,
+ .write8 = rx8010sj_rtc_write8,
+ .reset = rx8010sj_rtc_reset,
+};
+
+static const struct udevice_id rx8010sj_rtc_ids[] = {
+ { .compatible = "epson,rx8010sj-rtc" },
+ { .compatible = "epson,rx8010" },
+ { }
+};
+
+U_BOOT_DRIVER(rx8010sj_rtc) = {
+ .name = "rx8010sj_rtc",
+ .id = UCLASS_RTC,
+ .probe = rx8010sj_probe,
+ .of_match = rx8010sj_rtc_ids,
+ .ops = &rx8010sj_rtc_ops,
+};
+
+#endif
diff --git a/roms/u-boot/drivers/rtc/rx8025.c b/roms/u-boot/drivers/rtc/rx8025.c
new file mode 100644
index 000000000..e717dcbbf
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/rx8025.c
@@ -0,0 +1,306 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2007
+ * Matthias Fuchs, esd gmbh, matthias.fuchs@esd-electronics.com.
+ */
+
+/*
+ * Epson RX8025 RTC driver.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <i2c.h>
+#include <rtc.h>
+
+/*---------------------------------------------------------------------*/
+#undef DEBUG_RTC
+
+#ifdef DEBUG_RTC
+#define DEBUGR(fmt,args...) printf(fmt ,##args)
+#else
+#define DEBUGR(fmt,args...)
+#endif
+/*---------------------------------------------------------------------*/
+
+#ifndef CONFIG_SYS_I2C_RTC_ADDR
+# define CONFIG_SYS_I2C_RTC_ADDR 0x32
+#endif
+
+#ifdef CONFIG_DM_RTC
+#define DEV_TYPE struct udevice
+#else
+/* Local udevice */
+struct ludevice {
+ u8 chip;
+};
+
+#define DEV_TYPE struct ludevice
+
+#endif
+
+/*
+ * RTC register addresses
+ */
+#define RTC_SEC_REG_ADDR 0x00
+#define RTC_MIN_REG_ADDR 0x01
+#define RTC_HR_REG_ADDR 0x02
+#define RTC_DAY_REG_ADDR 0x03
+#define RTC_DATE_REG_ADDR 0x04
+#define RTC_MON_REG_ADDR 0x05
+#define RTC_YR_REG_ADDR 0x06
+
+#define RTC_CTL1_REG_ADDR 0x0e
+#define RTC_CTL2_REG_ADDR 0x0f
+
+/*
+ * Control register 1 bits
+ */
+#define RTC_CTL1_BIT_2412 0x20
+
+/*
+ * Control register 2 bits
+ */
+#define RTC_CTL2_BIT_PON 0x10
+#define RTC_CTL2_BIT_VDET 0x40
+#define RTC_CTL2_BIT_XST 0x20
+#define RTC_CTL2_BIT_VDSL 0x80
+
+/*
+ * Note: the RX8025 I2C RTC requires register
+ * reads and write to consist of a single bus
+ * cycle. It is not allowed to write the register
+ * address in a first cycle that is terminated by
+ * a STOP condition. The chips needs a 'restart'
+ * sequence (start sequence without a prior stop).
+ * This driver has been written for a 4xx board.
+ * U-Boot's 4xx i2c driver is currently not capable
+ * to generate such cycles to some work arounds
+ * are used.
+ */
+
+/* static uchar rtc_read (uchar reg); */
+#ifdef CONFIG_DM_RTC
+/*
+ * on mpc85xx based board with DM and offset len 1
+ * accessing rtc works fine. May we can drop this ?
+ */
+#define rtc_read(reg) buf[(reg) & 0xf]
+#else
+#define rtc_read(reg) buf[((reg) + 1) & 0xf]
+#endif
+
+static int rtc_write(DEV_TYPE *dev, uchar reg, uchar val);
+
+/*
+ * Get the current time from the RTC
+ */
+static int rx8025_rtc_get(DEV_TYPE *dev, struct rtc_time *tmp)
+{
+ int rel = 0;
+ uchar sec, min, hour, mday, wday, mon, year, ctl2;
+ uchar buf[16];
+
+#ifdef CONFIG_DM_RTC
+ if (dm_i2c_read(dev, 0, buf, sizeof(buf))) {
+#else
+ if (i2c_read(dev->chip, 0, 0, buf, 16)) {
+#endif
+ printf("Error reading from RTC\n");
+ return -EIO;
+ }
+
+ sec = rtc_read(RTC_SEC_REG_ADDR);
+ min = rtc_read(RTC_MIN_REG_ADDR);
+ hour = rtc_read(RTC_HR_REG_ADDR);
+ wday = rtc_read(RTC_DAY_REG_ADDR);
+ mday = rtc_read(RTC_DATE_REG_ADDR);
+ mon = rtc_read(RTC_MON_REG_ADDR);
+ year = rtc_read(RTC_YR_REG_ADDR);
+
+ DEBUGR("Get RTC year: %02x mon: %02x mday: %02x wday: %02x "
+ "hr: %02x min: %02x sec: %02x\n",
+ year, mon, mday, wday, hour, min, sec);
+
+ /* dump status */
+ ctl2 = rtc_read(RTC_CTL2_REG_ADDR);
+ if (ctl2 & RTC_CTL2_BIT_PON) {
+ printf("RTC: power-on detected\n");
+ rel = -1;
+ }
+
+ if (ctl2 & RTC_CTL2_BIT_VDET) {
+ printf("RTC: voltage drop detected\n");
+ rel = -1;
+ }
+
+ if (!(ctl2 & RTC_CTL2_BIT_XST)) {
+ printf("RTC: oscillator stop detected\n");
+ rel = -1;
+ }
+
+ tmp->tm_sec = bcd2bin(sec & 0x7F);
+ tmp->tm_min = bcd2bin(min & 0x7F);
+ if (rtc_read(RTC_CTL1_REG_ADDR) & RTC_CTL1_BIT_2412)
+ tmp->tm_hour = bcd2bin(hour & 0x3F);
+ else
+ tmp->tm_hour = bcd2bin(hour & 0x1F) % 12 +
+ ((hour & 0x20) ? 12 : 0);
+
+ tmp->tm_mday = bcd2bin (mday & 0x3F);
+ tmp->tm_mon = bcd2bin (mon & 0x1F);
+ tmp->tm_year = bcd2bin (year) + ( bcd2bin (year) >= 70 ? 1900 : 2000);
+ tmp->tm_wday = bcd2bin (wday & 0x07);
+ tmp->tm_yday = 0;
+ tmp->tm_isdst= 0;
+
+ DEBUGR("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ return rel;
+}
+
+/*
+ * Set the RTC
+ */
+static int rx8025_rtc_set(DEV_TYPE *dev, const struct rtc_time *tmp)
+{
+ DEBUGR("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ if (tmp->tm_year < 1970 || tmp->tm_year > 2069)
+ printf("WARNING: year should be between 1970 and 2069!\n");
+
+ if (rtc_write(dev, RTC_YR_REG_ADDR, bin2bcd(tmp->tm_year % 100)))
+ return -EIO;
+
+ if (rtc_write(dev, RTC_MON_REG_ADDR, bin2bcd(tmp->tm_mon)))
+ return -EIO;
+
+ if (rtc_write(dev, RTC_DAY_REG_ADDR, bin2bcd(tmp->tm_wday)))
+ return -EIO;
+
+ if (rtc_write(dev, RTC_DATE_REG_ADDR, bin2bcd(tmp->tm_mday)))
+ return -EIO;
+
+ if (rtc_write(dev, RTC_HR_REG_ADDR, bin2bcd(tmp->tm_hour)))
+ return -EIO;
+
+ if (rtc_write(dev, RTC_MIN_REG_ADDR, bin2bcd(tmp->tm_min)))
+ return -EIO;
+
+ if (rtc_write(dev, RTC_SEC_REG_ADDR, bin2bcd(tmp->tm_sec)))
+ return -EIO;
+
+ return rtc_write(dev, RTC_CTL1_REG_ADDR, RTC_CTL1_BIT_2412);
+}
+
+/*
+ * Reset the RTC
+ */
+static int rx8025_rtc_reset(DEV_TYPE *dev)
+{
+ uchar buf[16];
+ uchar ctl2;
+
+#ifdef CONFIG_DM_RTC
+ if (dm_i2c_read(dev, 0, buf, sizeof(buf))) {
+#else
+ if (i2c_read(dev->chip, 0, 0, buf, 16)) {
+#endif
+ printf("Error reading from RTC\n");
+ return -EIO;
+ }
+
+ ctl2 = rtc_read(RTC_CTL2_REG_ADDR);
+ ctl2 &= ~(RTC_CTL2_BIT_PON | RTC_CTL2_BIT_VDET);
+ ctl2 |= RTC_CTL2_BIT_XST | RTC_CTL2_BIT_VDSL;
+
+ return rtc_write(dev, RTC_CTL2_REG_ADDR, ctl2);
+}
+
+/*
+ * Helper functions
+ */
+static int rtc_write(DEV_TYPE *dev, uchar reg, uchar val)
+{
+ uchar buf[2];
+ buf[0] = reg << 4;
+ buf[1] = val;
+
+#ifdef CONFIG_DM_RTC
+ if (dm_i2c_write(dev, 0, buf, 2)) {
+#else
+ if (i2c_write(dev->chip, 0, 0, buf, 2) != 0) {
+#endif
+ printf("Error writing to RTC\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_DM_RTC
+static int rx8025_probe(struct udevice *dev)
+{
+ uchar buf[16];
+ int ret = 0;
+
+ if (i2c_get_chip_offset_len(dev) != 1)
+ ret = i2c_set_chip_offset_len(dev, 1);
+
+ if (ret)
+ return ret;
+
+ return dm_i2c_read(dev, 0, buf, sizeof(buf));
+}
+
+static const struct rtc_ops rx8025_rtc_ops = {
+ .get = rx8025_rtc_get,
+ .set = rx8025_rtc_set,
+ .reset = rx8025_rtc_reset,
+};
+
+static const struct udevice_id rx8025_rtc_ids[] = {
+ { .compatible = "epson,rx8025" },
+ { }
+};
+
+U_BOOT_DRIVER(rx8010sj_rtc) = {
+ .name = "rx8025_rtc",
+ .id = UCLASS_RTC,
+ .probe = rx8025_probe,
+ .of_match = rx8025_rtc_ids,
+ .ops = &rx8025_rtc_ops,
+};
+#else
+int rtc_get(struct rtc_time *tm)
+{
+ struct ludevice dev = {
+ .chip = CONFIG_SYS_I2C_RTC_ADDR,
+ };
+
+ return rx8025_rtc_get(&dev, tm);
+}
+
+int rtc_set(struct rtc_time *tm)
+{
+ struct ludevice dev = {
+ .chip = CONFIG_SYS_I2C_RTC_ADDR,
+ };
+
+ return rx8025_rtc_set(&dev, tm);
+}
+
+void rtc_reset(void)
+{
+ struct ludevice dev = {
+ .chip = CONFIG_SYS_I2C_RTC_ADDR,
+ };
+
+ rx8025_rtc_reset(&dev);
+}
+#endif
diff --git a/roms/u-boot/drivers/rtc/s35392a.c b/roms/u-boot/drivers/rtc/s35392a.c
new file mode 100644
index 000000000..80f55c862
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/s35392a.c
@@ -0,0 +1,374 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SII Semiconductor Corporation S35392A RTC driver.
+ *
+ * Copyright (c) 2017, General Electric Company
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <command.h>
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <linux/bitrev.h>
+#include <rtc.h>
+#include <linux/delay.h>
+
+#define S35390A_CHIP_ADDR 0x30
+
+#define S35390A_CMD_STATUS1 0x0
+#define S35390A_CMD_STATUS2 0x1
+#define S35390A_CMD_TIME1 0x2
+#define S35390A_CMD_TIME2 0x3
+#define S35390A_CMD_INT2_REG1 0x5
+
+#define S35390A_BYTE_YEAR 0
+#define S35390A_BYTE_MONTH 1
+#define S35390A_BYTE_DAY 2
+#define S35390A_BYTE_WDAY 3
+#define S35390A_BYTE_HOURS 4
+#define S35390A_BYTE_MINS 5
+#define S35390A_BYTE_SECS 6
+
+/* flags for STATUS1 */
+#define S35390A_FLAG_POC 0x01
+#define S35390A_FLAG_BLD 0x02
+#define S35390A_FLAG_INT2 0x04
+#define S35390A_FLAG_24H 0x40
+#define S35390A_FLAG_RESET 0x80
+
+/*
+ * If either BLD or POC is set, then the chip has lost power long enough for
+ * the time value to become invalid.
+ */
+#define S35390A_LOW_VOLTAGE (S35390A_FLAG_POC | S35390A_FLAG_BLD)
+
+/*---------------------------------------------------------------------*/
+#undef DEBUG_RTC
+
+#ifdef DEBUG_RTC
+#define DEBUGR(fmt, args...) printf(fmt, ##args)
+#else
+#define DEBUGR(fmt, args...)
+#endif
+/*---------------------------------------------------------------------*/
+
+#ifdef CONFIG_DM_RTC
+#define DEV_TYPE struct udevice
+#else
+/* Local udevice */
+struct ludevice {
+ u8 chip;
+};
+
+#define DEV_TYPE struct ludevice
+struct ludevice dev;
+
+#endif
+
+#define msleep(a) udelay(a * 1000)
+
+int lowvoltage;
+
+static int s35392a_rtc_reset(DEV_TYPE *dev);
+
+static int s35392a_rtc_read(DEV_TYPE *dev, u8 reg, u8 *buf, int len)
+{
+ int ret;
+
+#ifdef CONFIG_DM_RTC
+ ret = dm_i2c_read(dev, reg, buf, len);
+#else
+ (void)dev;
+ ret = i2c_read(S35390A_CHIP_ADDR | reg, 0, -1, buf, len);
+#endif
+
+ return ret;
+}
+
+static int s35392a_rtc_write(DEV_TYPE *dev, u8 reg, u8 *buf, int len)
+{
+ int ret;
+
+#ifdef CONFIG_DM_RTC
+ ret = dm_i2c_write(dev, reg, buf, len);
+#else
+ (void)dev;
+ ret = i2c_write(S35390A_CHIP_ADDR | reg, 0, 0, buf, len);
+#endif
+
+ return ret;
+}
+
+static int s35392a_rtc_read8(DEV_TYPE *dev, unsigned int reg)
+{
+ u8 val;
+ int ret;
+
+ ret = s35392a_rtc_read(dev, reg, &val, sizeof(val));
+ return ret < 0 ? ret : val;
+}
+
+static int s35392a_rtc_write8(DEV_TYPE *dev, unsigned int reg, int val)
+{
+ int ret;
+ u8 lval = val;
+
+ ret = s35392a_rtc_write(dev, reg, &lval, sizeof(lval));
+ return ret < 0 ? ret : 0;
+}
+
+static int validate_time(const struct rtc_time *tm)
+{
+ if ((tm->tm_year < 2000) || (tm->tm_year > 2099))
+ return -EINVAL;
+
+ if ((tm->tm_mon < 1) || (tm->tm_mon > 12))
+ return -EINVAL;
+
+ if ((tm->tm_mday < 1) || (tm->tm_mday > 31))
+ return -EINVAL;
+
+ if ((tm->tm_wday < 0) || (tm->tm_wday > 6))
+ return -EINVAL;
+
+ if ((tm->tm_hour < 0) || (tm->tm_hour > 23))
+ return -EINVAL;
+
+ if ((tm->tm_min < 0) || (tm->tm_min > 59))
+ return -EINVAL;
+
+ if ((tm->tm_sec < 0) || (tm->tm_sec > 59))
+ return -EINVAL;
+
+ return 0;
+}
+
+void s35392a_rtc_init(DEV_TYPE *dev)
+{
+ int status;
+
+ status = s35392a_rtc_read8(dev, S35390A_CMD_STATUS1);
+ if (status < 0)
+ goto error;
+
+ DEBUGR("init: S35390A_CMD_STATUS1: 0x%x\n", status);
+
+ lowvoltage = status & S35390A_LOW_VOLTAGE ? 1 : 0;
+
+ if (status & S35390A_FLAG_POC)
+ /*
+ * Do not communicate for 0.5 seconds since the power-on
+ * detection circuit is in operation.
+ */
+ msleep(500);
+
+ else if (!lowvoltage)
+ /*
+ * If both POC and BLD are unset everything is fine.
+ */
+ return;
+
+ if (lowvoltage)
+ printf("RTC low voltage detected\n");
+
+ if (!s35392a_rtc_reset(dev))
+ return;
+
+error:
+ printf("Error RTC init.\n");
+}
+
+/* Get the current time from the RTC */
+static int s35392a_rtc_get(DEV_TYPE *dev, struct rtc_time *tm)
+{
+ u8 date[7];
+ int ret, i;
+
+ if (lowvoltage) {
+ DEBUGR("RTC low voltage detected\n");
+ return -EINVAL;
+ }
+
+ ret = s35392a_rtc_read(dev, S35390A_CMD_TIME1, date, sizeof(date));
+ if (ret < 0) {
+ DEBUGR("Error reading date from RTC\n");
+ return -EIO;
+ }
+
+ /* This chip returns the bits of each byte in reverse order */
+ for (i = 0; i < 7; ++i)
+ date[i] = bitrev8(date[i]);
+
+ tm->tm_sec = bcd2bin(date[S35390A_BYTE_SECS]);
+ tm->tm_min = bcd2bin(date[S35390A_BYTE_MINS]);
+ tm->tm_hour = bcd2bin(date[S35390A_BYTE_HOURS] & ~S35390A_FLAG_24H);
+ tm->tm_wday = bcd2bin(date[S35390A_BYTE_WDAY]);
+ tm->tm_mday = bcd2bin(date[S35390A_BYTE_DAY]);
+ tm->tm_mon = bcd2bin(date[S35390A_BYTE_MONTH]);
+ tm->tm_year = bcd2bin(date[S35390A_BYTE_YEAR]) + 2000;
+
+ DEBUGR("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ return 0;
+}
+
+/* Set the RTC */
+static int s35392a_rtc_set(DEV_TYPE *dev, const struct rtc_time *tm)
+{
+ int i, ret;
+ int status;
+ u8 date[7];
+
+ DEBUGR("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ ret = validate_time(tm);
+ if (ret < 0)
+ return -EINVAL;
+
+ /* We support only 24h mode */
+ ret = s35392a_rtc_read8(dev, S35390A_CMD_STATUS1);
+ if (ret < 0)
+ return -EIO;
+ status = ret;
+
+ ret = s35392a_rtc_write8(dev, S35390A_CMD_STATUS1,
+ status | S35390A_FLAG_24H);
+ if (ret < 0)
+ return -EIO;
+
+ date[S35390A_BYTE_YEAR] = bin2bcd(tm->tm_year - 2000);
+ date[S35390A_BYTE_MONTH] = bin2bcd(tm->tm_mon);
+ date[S35390A_BYTE_DAY] = bin2bcd(tm->tm_mday);
+ date[S35390A_BYTE_WDAY] = bin2bcd(tm->tm_wday);
+ date[S35390A_BYTE_HOURS] = bin2bcd(tm->tm_hour);
+ date[S35390A_BYTE_MINS] = bin2bcd(tm->tm_min);
+ date[S35390A_BYTE_SECS] = bin2bcd(tm->tm_sec);
+
+ /* This chip expects the bits of each byte to be in reverse order */
+ for (i = 0; i < 7; ++i)
+ date[i] = bitrev8(date[i]);
+
+ ret = s35392a_rtc_write(dev, S35390A_CMD_TIME1, date, sizeof(date));
+ if (ret < 0) {
+ DEBUGR("Error writing date to RTC\n");
+ return -EIO;
+ }
+
+ /* Now we have time. Reset the low voltage status */
+ lowvoltage = 0;
+
+ return 0;
+}
+
+/* Reset the RTC. */
+static int s35392a_rtc_reset(DEV_TYPE *dev)
+{
+ int buf;
+ int ret;
+ unsigned int initcount = 0;
+
+ buf = S35390A_FLAG_RESET;
+
+initialize:
+ ret = s35392a_rtc_write8(dev, S35390A_CMD_STATUS1, buf);
+ if (ret < 0)
+ return -EIO;
+
+ ret = s35392a_rtc_read8(dev, S35390A_CMD_STATUS1);
+ if (ret < 0)
+ return -EIO;
+ buf = ret;
+
+ if (!lowvoltage)
+ lowvoltage = buf & S35390A_LOW_VOLTAGE ? 1 : 0;
+
+ if (buf & S35390A_LOW_VOLTAGE) {
+ /* Try up to five times to reset the chip */
+ if (initcount < 5) {
+ ++initcount;
+ goto initialize;
+ } else {
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+#ifndef CONFIG_DM_RTC
+
+int rtc_get(struct rtc_time *tm)
+{
+ return s35392a_rtc_get(&dev, tm);
+}
+
+int rtc_set(struct rtc_time *tm)
+{
+ return s35392a_rtc_set(&dev, tm);
+}
+
+void rtc_reset(void)
+{
+ s35392a_rtc_reset(&dev);
+}
+
+void rtc_init(void)
+{
+ s35392a_rtc_init(&dev);
+}
+
+#else
+
+static int s35392a_probe(struct udevice *dev)
+{
+#if defined(CONFIG_DM_RTC)
+ /* 3-bit "command", or register, is encoded within the device address.
+ */
+ i2c_set_chip_offset_len(dev, 0);
+ i2c_set_chip_addr_offset_mask(dev, 0x7);
+#endif
+
+ s35392a_rtc_init(dev);
+ return 0;
+}
+
+static const struct rtc_ops s35392a_rtc_ops = {
+ .get = s35392a_rtc_get,
+ .set = s35392a_rtc_set,
+ .read8 = s35392a_rtc_read8,
+ .write8 = s35392a_rtc_write8,
+ .reset = s35392a_rtc_reset,
+};
+
+static const struct udevice_id s35392a_rtc_ids[] = {
+ { .compatible = "sii,s35392a-rtc" },
+ { .compatible = "sii,s35392a" },
+ { .compatible = "s35392a" },
+ { }
+};
+
+U_BOOT_DRIVER(s35392a_rtc) = {
+ .name = "s35392a_rtc",
+ .id = UCLASS_RTC,
+ .probe = s35392a_probe,
+ .of_match = s35392a_rtc_ids,
+ .ops = &s35392a_rtc_ops,
+};
+
+#endif
diff --git a/roms/u-boot/drivers/rtc/s3c24x0_rtc.c b/roms/u-boot/drivers/rtc/s3c24x0_rtc.c
new file mode 100644
index 000000000..96ea3cf87
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/s3c24x0_rtc.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2003
+ * David Müller ELSOFT AG Switzerland. d.mueller@elsoft.ch
+ */
+
+/*
+ * Date & Time support for the built-in Samsung S3C24X0 RTC
+ */
+
+#include <common.h>
+#include <command.h>
+
+#include <asm/arch/s3c24x0_cpu.h>
+
+#include <rtc.h>
+#include <asm/io.h>
+#include <linux/compiler.h>
+
+typedef enum {
+ RTC_ENABLE,
+ RTC_DISABLE
+} RTC_ACCESS;
+
+
+static inline void SetRTC_Access(RTC_ACCESS a)
+{
+ struct s3c24x0_rtc *rtc = s3c24x0_get_base_rtc();
+
+ switch (a) {
+ case RTC_ENABLE:
+ writeb(readb(&rtc->rtccon) | 0x01, &rtc->rtccon);
+ break;
+
+ case RTC_DISABLE:
+ writeb(readb(&rtc->rtccon) & ~0x01, &rtc->rtccon);
+ break;
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+int rtc_get(struct rtc_time *tmp)
+{
+ struct s3c24x0_rtc *rtc = s3c24x0_get_base_rtc();
+ uchar sec, min, hour, mday, wday, mon, year;
+ __maybe_unused uchar a_sec, a_min, a_hour, a_date,
+ a_mon, a_year, a_armed;
+
+ /* enable access to RTC registers */
+ SetRTC_Access(RTC_ENABLE);
+
+ /* read RTC registers */
+ do {
+ sec = readb(&rtc->bcdsec);
+ min = readb(&rtc->bcdmin);
+ hour = readb(&rtc->bcdhour);
+ mday = readb(&rtc->bcddate);
+ wday = readb(&rtc->bcdday);
+ mon = readb(&rtc->bcdmon);
+ year = readb(&rtc->bcdyear);
+ } while (sec != readb(&rtc->bcdsec));
+
+ /* read ALARM registers */
+ a_sec = readb(&rtc->almsec);
+ a_min = readb(&rtc->almmin);
+ a_hour = readb(&rtc->almhour);
+ a_date = readb(&rtc->almdate);
+ a_mon = readb(&rtc->almmon);
+ a_year = readb(&rtc->almyear);
+ a_armed = readb(&rtc->rtcalm);
+
+ /* disable access to RTC registers */
+ SetRTC_Access(RTC_DISABLE);
+
+#ifdef RTC_DEBUG
+ printf("Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x "
+ "hr: %02x min: %02x sec: %02x\n",
+ year, mon, mday, wday, hour, min, sec);
+ printf("Alarms: %02x: year: %02x month: %02x date: %02x hour: "
+ "%02x min: %02x sec: %02x\n",
+ a_armed, a_year, a_mon, a_date, a_hour, a_min, a_sec);
+#endif
+
+ tmp->tm_sec = bcd2bin(sec & 0x7F);
+ tmp->tm_min = bcd2bin(min & 0x7F);
+ tmp->tm_hour = bcd2bin(hour & 0x3F);
+ tmp->tm_mday = bcd2bin(mday & 0x3F);
+ tmp->tm_mon = bcd2bin(mon & 0x1F);
+ tmp->tm_year = bcd2bin(year);
+ tmp->tm_wday = bcd2bin(wday & 0x07);
+ if (tmp->tm_year < 70)
+ tmp->tm_year += 2000;
+ else
+ tmp->tm_year += 1900;
+ tmp->tm_yday = 0;
+ tmp->tm_isdst = 0;
+#ifdef RTC_DEBUG
+ printf("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+#endif
+
+ return 0;
+}
+
+int rtc_set(struct rtc_time *tmp)
+{
+ struct s3c24x0_rtc *rtc = s3c24x0_get_base_rtc();
+ uchar sec, min, hour, mday, wday, mon, year;
+
+#ifdef RTC_DEBUG
+ printf("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+#endif
+ year = bin2bcd(tmp->tm_year % 100);
+ mon = bin2bcd(tmp->tm_mon);
+ wday = bin2bcd(tmp->tm_wday);
+ mday = bin2bcd(tmp->tm_mday);
+ hour = bin2bcd(tmp->tm_hour);
+ min = bin2bcd(tmp->tm_min);
+ sec = bin2bcd(tmp->tm_sec);
+
+ /* enable access to RTC registers */
+ SetRTC_Access(RTC_ENABLE);
+
+ /* write RTC registers */
+ writeb(sec, &rtc->bcdsec);
+ writeb(min, &rtc->bcdmin);
+ writeb(hour, &rtc->bcdhour);
+ writeb(mday, &rtc->bcddate);
+ writeb(wday, &rtc->bcdday);
+ writeb(mon, &rtc->bcdmon);
+ writeb(year, &rtc->bcdyear);
+
+ /* disable access to RTC registers */
+ SetRTC_Access(RTC_DISABLE);
+
+ return 0;
+}
+
+void rtc_reset(void)
+{
+ struct s3c24x0_rtc *rtc = s3c24x0_get_base_rtc();
+
+ writeb((readb(&rtc->rtccon) & ~0x06) | 0x08, &rtc->rtccon);
+ writeb(readb(&rtc->rtccon) & ~(0x08 | 0x01), &rtc->rtccon);
+}
diff --git a/roms/u-boot/drivers/rtc/sandbox_rtc.c b/roms/u-boot/drivers/rtc/sandbox_rtc.c
new file mode 100644
index 000000000..657e5c7be
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/sandbox_rtc.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <rtc.h>
+#include <asm/rtc.h>
+#include <dm/acpi.h>
+
+#define REG_COUNT 0x80
+
+static int sandbox_rtc_get(struct udevice *dev, struct rtc_time *time)
+{
+ u8 buf[7];
+ int ret;
+
+ ret = dm_i2c_read(dev, REG_SEC, buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+
+ time->tm_sec = buf[REG_SEC - REG_SEC];
+ time->tm_min = buf[REG_MIN - REG_SEC];
+ time->tm_hour = buf[REG_HOUR - REG_SEC];
+ time->tm_mday = buf[REG_MDAY - REG_SEC];
+ time->tm_mon = buf[REG_MON - REG_SEC];
+ time->tm_year = buf[REG_YEAR - REG_SEC] + 1900;
+ time->tm_wday = buf[REG_WDAY - REG_SEC];
+
+ return 0;
+}
+
+static int sandbox_rtc_set(struct udevice *dev, const struct rtc_time *time)
+{
+ u8 buf[7];
+ int ret;
+
+ buf[REG_SEC - REG_SEC] = time->tm_sec;
+ buf[REG_MIN - REG_SEC] = time->tm_min;
+ buf[REG_HOUR - REG_SEC] = time->tm_hour;
+ buf[REG_MDAY - REG_SEC] = time->tm_mday;
+ buf[REG_MON - REG_SEC] = time->tm_mon;
+ buf[REG_YEAR - REG_SEC] = time->tm_year - 1900;
+ buf[REG_WDAY - REG_SEC] = time->tm_wday;
+
+ ret = dm_i2c_write(dev, REG_SEC, buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int sandbox_rtc_reset(struct udevice *dev)
+{
+ return dm_i2c_reg_write(dev, REG_RESET, 0);
+}
+
+static int sandbox_rtc_read8(struct udevice *dev, unsigned int reg)
+{
+ return dm_i2c_reg_read(dev, reg);
+}
+
+static int sandbox_rtc_write8(struct udevice *dev, unsigned int reg, int val)
+{
+ return dm_i2c_reg_write(dev, reg, val);
+}
+
+#if CONFIG_IS_ENABLED(ACPIGEN)
+static int sandbox_rtc_get_name(const struct udevice *dev, char *out_name)
+{
+ return acpi_copy_name(out_name, "RTCC");
+}
+
+struct acpi_ops sandbox_rtc_acpi_ops = {
+ .get_name = sandbox_rtc_get_name,
+};
+#endif
+
+static int sandbox_rtc_bind(struct udevice *dev)
+{
+#if CONFIG_IS_ENABLED(PLATDATA)
+ struct sandbox_i2c_rtc_plat_data *plat = dev_get_plat(dev);
+
+ /* Set up the emul_idx for i2c_emul_find() */
+ i2c_emul_set_idx(dev, plat->dtplat.sandbox_emul->idx);
+#endif
+
+ return 0;
+}
+
+static const struct rtc_ops sandbox_rtc_ops = {
+ .get = sandbox_rtc_get,
+ .set = sandbox_rtc_set,
+ .reset = sandbox_rtc_reset,
+ .read8 = sandbox_rtc_read8,
+ .write8 = sandbox_rtc_write8,
+};
+
+static const struct udevice_id sandbox_rtc_ids[] = {
+ { .compatible = "sandbox-rtc" },
+ { }
+};
+
+U_BOOT_DRIVER(sandbox_rtc) = {
+ .name = "sandbox_rtc",
+ .id = UCLASS_RTC,
+ .of_match = sandbox_rtc_ids,
+ .ops = &sandbox_rtc_ops,
+ .bind = sandbox_rtc_bind,
+ ACPI_OPS_PTR(&sandbox_rtc_acpi_ops)
+};
diff --git a/roms/u-boot/drivers/rtc/stm32_rtc.c b/roms/u-boot/drivers/rtc/stm32_rtc.c
new file mode 100644
index 000000000..175328346
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/stm32_rtc.c
@@ -0,0 +1,334 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
+ */
+
+#define LOG_CATEGORY UCLASS_RTC
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <malloc.h>
+#include <rtc.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/iopoll.h>
+
+#define STM32_RTC_TR 0x00
+#define STM32_RTC_DR 0x04
+#define STM32_RTC_ISR 0x0C
+#define STM32_RTC_PRER 0x10
+#define STM32_RTC_CR 0x18
+#define STM32_RTC_WPR 0x24
+
+/* STM32_RTC_TR bit fields */
+#define STM32_RTC_SEC_SHIFT 0
+#define STM32_RTC_SEC GENMASK(6, 0)
+#define STM32_RTC_MIN_SHIFT 8
+#define STM32_RTC_MIN GENMASK(14, 8)
+#define STM32_RTC_HOUR_SHIFT 16
+#define STM32_RTC_HOUR GENMASK(21, 16)
+
+/* STM32_RTC_DR bit fields */
+#define STM32_RTC_DATE_SHIFT 0
+#define STM32_RTC_DATE GENMASK(5, 0)
+#define STM32_RTC_MONTH_SHIFT 8
+#define STM32_RTC_MONTH GENMASK(12, 8)
+#define STM32_RTC_WDAY_SHIFT 13
+#define STM32_RTC_WDAY GENMASK(15, 13)
+#define STM32_RTC_YEAR_SHIFT 16
+#define STM32_RTC_YEAR GENMASK(23, 16)
+
+/* STM32_RTC_CR bit fields */
+#define STM32_RTC_CR_FMT BIT(6)
+
+/* STM32_RTC_ISR/STM32_RTC_ICSR bit fields */
+#define STM32_RTC_ISR_INITS BIT(4)
+#define STM32_RTC_ISR_RSF BIT(5)
+#define STM32_RTC_ISR_INITF BIT(6)
+#define STM32_RTC_ISR_INIT BIT(7)
+
+/* STM32_RTC_PRER bit fields */
+#define STM32_RTC_PRER_PRED_S_SHIFT 0
+#define STM32_RTC_PRER_PRED_S GENMASK(14, 0)
+#define STM32_RTC_PRER_PRED_A_SHIFT 16
+#define STM32_RTC_PRER_PRED_A GENMASK(22, 16)
+
+/* STM32_RTC_WPR key constants */
+#define RTC_WPR_1ST_KEY 0xCA
+#define RTC_WPR_2ND_KEY 0x53
+#define RTC_WPR_WRONG_KEY 0xFF
+
+struct stm32_rtc_priv {
+ fdt_addr_t base;
+};
+
+static int stm32_rtc_get(struct udevice *dev, struct rtc_time *tm)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+ u32 tr, dr;
+
+ tr = readl(priv->base + STM32_RTC_TR);
+ dr = readl(priv->base + STM32_RTC_DR);
+
+ tm->tm_sec = bcd2bin((tr & STM32_RTC_SEC) >> STM32_RTC_SEC_SHIFT);
+ tm->tm_min = bcd2bin((tr & STM32_RTC_MIN) >> STM32_RTC_MIN_SHIFT);
+ tm->tm_hour = bcd2bin((tr & STM32_RTC_HOUR) >> STM32_RTC_HOUR_SHIFT);
+
+ tm->tm_mday = bcd2bin((dr & STM32_RTC_DATE) >> STM32_RTC_DATE_SHIFT);
+ tm->tm_mon = bcd2bin((dr & STM32_RTC_MONTH) >> STM32_RTC_MONTH_SHIFT);
+ tm->tm_year = 2000 +
+ bcd2bin((dr & STM32_RTC_YEAR) >> STM32_RTC_YEAR_SHIFT);
+ tm->tm_wday = bcd2bin((dr & STM32_RTC_WDAY) >> STM32_RTC_WDAY_SHIFT);
+ tm->tm_yday = 0;
+ tm->tm_isdst = 0;
+
+ dev_dbg(dev, "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ return 0;
+}
+
+static void stm32_rtc_unlock(struct udevice *dev)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+
+ writel(RTC_WPR_1ST_KEY, priv->base + STM32_RTC_WPR);
+ writel(RTC_WPR_2ND_KEY, priv->base + STM32_RTC_WPR);
+}
+
+static void stm32_rtc_lock(struct udevice *dev)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+
+ writel(RTC_WPR_WRONG_KEY, priv->base + STM32_RTC_WPR);
+}
+
+static int stm32_rtc_enter_init_mode(struct udevice *dev)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+ u32 isr = readl(priv->base + STM32_RTC_ISR);
+
+ if (!(isr & STM32_RTC_ISR_INITF)) {
+ isr |= STM32_RTC_ISR_INIT;
+ writel(isr, priv->base + STM32_RTC_ISR);
+
+ return readl_poll_timeout(priv->base + STM32_RTC_ISR,
+ isr,
+ (isr & STM32_RTC_ISR_INITF),
+ 100000);
+ }
+
+ return 0;
+}
+
+static int stm32_rtc_wait_sync(struct udevice *dev)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+ u32 isr = readl(priv->base + STM32_RTC_ISR);
+
+ isr &= ~STM32_RTC_ISR_RSF;
+ writel(isr, priv->base + STM32_RTC_ISR);
+
+ /*
+ * Wait for RSF to be set to ensure the calendar registers are
+ * synchronised, it takes around 2 rtc_ck clock cycles
+ */
+ return readl_poll_timeout(priv->base + STM32_RTC_ISR,
+ isr, (isr & STM32_RTC_ISR_RSF),
+ 100000);
+}
+
+static void stm32_rtc_exit_init_mode(struct udevice *dev)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+ u32 isr = readl(priv->base + STM32_RTC_ISR);
+
+ isr &= ~STM32_RTC_ISR_INIT;
+ writel(isr, priv->base + STM32_RTC_ISR);
+}
+
+static int stm32_rtc_set_time(struct udevice *dev, u32 time, u32 date)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ stm32_rtc_unlock(dev);
+
+ ret = stm32_rtc_enter_init_mode(dev);
+ if (ret)
+ goto lock;
+
+ writel(time, priv->base + STM32_RTC_TR);
+ writel(date, priv->base + STM32_RTC_DR);
+
+ stm32_rtc_exit_init_mode(dev);
+
+ ret = stm32_rtc_wait_sync(dev);
+
+lock:
+ stm32_rtc_lock(dev);
+ return ret;
+}
+
+static int stm32_rtc_set(struct udevice *dev, const struct rtc_time *tm)
+{
+ u32 t, d;
+
+ dev_dbg(dev, "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ if (tm->tm_year < 2000 || tm->tm_year > 2099)
+ return -EINVAL;
+
+ /* Time in BCD format */
+ t = (bin2bcd(tm->tm_sec) << STM32_RTC_SEC_SHIFT) & STM32_RTC_SEC;
+ t |= (bin2bcd(tm->tm_min) << STM32_RTC_MIN_SHIFT) & STM32_RTC_MIN;
+ t |= (bin2bcd(tm->tm_hour) << STM32_RTC_HOUR_SHIFT) & STM32_RTC_HOUR;
+
+ /* Date in BCD format */
+ d = (bin2bcd(tm->tm_mday) << STM32_RTC_DATE_SHIFT) & STM32_RTC_DATE;
+ d |= (bin2bcd(tm->tm_mon) << STM32_RTC_MONTH_SHIFT) & STM32_RTC_MONTH;
+ d |= (bin2bcd(tm->tm_year - 2000) << STM32_RTC_YEAR_SHIFT) &
+ STM32_RTC_YEAR;
+ d |= (bin2bcd(tm->tm_wday) << STM32_RTC_WDAY_SHIFT) & STM32_RTC_WDAY;
+
+ return stm32_rtc_set_time(dev, t, d);
+}
+
+static int stm32_rtc_reset(struct udevice *dev)
+{
+ dev_dbg(dev, "Reset DATE\n");
+
+ return stm32_rtc_set_time(dev, 0, 0);
+}
+
+static int stm32_rtc_init(struct udevice *dev)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+ unsigned int prer, pred_a, pred_s, pred_a_max, pred_s_max, cr;
+ unsigned int rate;
+ struct clk clk;
+ int ret;
+ u32 isr = readl(priv->base + STM32_RTC_ISR);
+
+ if (isr & STM32_RTC_ISR_INITS)
+ return 0;
+
+ ret = clk_get_by_index(dev, 1, &clk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&clk);
+ if (ret) {
+ clk_free(&clk);
+ return ret;
+ }
+
+ rate = clk_get_rate(&clk);
+
+ /* Find prediv_a and prediv_s to obtain the 1Hz calendar clock */
+ pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT;
+ pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT;
+
+ for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) {
+ pred_s = (rate / (pred_a + 1)) - 1;
+
+ if (((pred_s + 1) * (pred_a + 1)) == rate)
+ break;
+ }
+
+ /*
+ * Can't find a 1Hz, so give priority to RTC power consumption
+ * by choosing the higher possible value for prediv_a
+ */
+ if (pred_s > pred_s_max || pred_a > pred_a_max) {
+ pred_a = pred_a_max;
+ pred_s = (rate / (pred_a + 1)) - 1;
+ }
+
+ stm32_rtc_unlock(dev);
+
+ ret = stm32_rtc_enter_init_mode(dev);
+ if (ret) {
+ dev_err(dev,
+ "Can't enter in init mode. Prescaler config failed.\n");
+ goto unlock;
+ }
+
+ prer = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) & STM32_RTC_PRER_PRED_S;
+ prer |= (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & STM32_RTC_PRER_PRED_A;
+ writel(prer, priv->base + STM32_RTC_PRER);
+
+ /* Force 24h time format */
+ cr = readl(priv->base + STM32_RTC_CR);
+ cr &= ~STM32_RTC_CR_FMT;
+ writel(cr, priv->base + STM32_RTC_CR);
+
+ stm32_rtc_exit_init_mode(dev);
+
+ ret = stm32_rtc_wait_sync(dev);
+
+unlock:
+ stm32_rtc_lock(dev);
+
+ if (ret) {
+ clk_disable(&clk);
+ clk_free(&clk);
+ }
+
+ return ret;
+}
+
+static int stm32_rtc_probe(struct udevice *dev)
+{
+ struct stm32_rtc_priv *priv = dev_get_priv(dev);
+ struct clk clk;
+ int ret;
+
+ priv->base = dev_read_addr(dev);
+ if (priv->base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&clk);
+ if (ret) {
+ clk_free(&clk);
+ return ret;
+ }
+
+ ret = stm32_rtc_init(dev);
+
+ if (ret) {
+ clk_disable(&clk);
+ clk_free(&clk);
+ }
+
+ return ret;
+}
+
+static const struct rtc_ops stm32_rtc_ops = {
+ .get = stm32_rtc_get,
+ .set = stm32_rtc_set,
+ .reset = stm32_rtc_reset,
+};
+
+static const struct udevice_id stm32_rtc_ids[] = {
+ { .compatible = "st,stm32mp1-rtc" },
+ { }
+};
+
+U_BOOT_DRIVER(rtc_stm32) = {
+ .name = "rtc-stm32",
+ .id = UCLASS_RTC,
+ .probe = stm32_rtc_probe,
+ .of_match = stm32_rtc_ids,
+ .ops = &stm32_rtc_ops,
+ .priv_auto = sizeof(struct stm32_rtc_priv),
+};
diff --git a/roms/u-boot/drivers/rtc/x1205.c b/roms/u-boot/drivers/rtc/x1205.c
new file mode 100644
index 000000000..ce23427b1
--- /dev/null
+++ b/roms/u-boot/drivers/rtc/x1205.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2007
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * based on a the Linux rtc-x1207.c driver which is:
+ * Copyright 2004 Karen Spearel
+ * Copyright 2005 Alessandro Zummo
+ *
+ * Information and datasheet:
+ * http://www.intersil.com/cda/deviceinfo/0,1477,X1205,00.html
+ */
+
+/*
+ * Date & Time support for Xicor/Intersil X1205 RTC
+ */
+
+/* #define DEBUG */
+
+#include <common.h>
+#include <command.h>
+#include <log.h>
+#include <rtc.h>
+#include <i2c.h>
+
+#define CCR_SEC 0
+#define CCR_MIN 1
+#define CCR_HOUR 2
+#define CCR_MDAY 3
+#define CCR_MONTH 4
+#define CCR_YEAR 5
+#define CCR_WDAY 6
+#define CCR_Y2K 7
+
+#define X1205_REG_SR 0x3F /* status register */
+#define X1205_REG_Y2K 0x37
+#define X1205_REG_DW 0x36
+#define X1205_REG_YR 0x35
+#define X1205_REG_MO 0x34
+#define X1205_REG_DT 0x33
+#define X1205_REG_HR 0x32
+#define X1205_REG_MN 0x31
+#define X1205_REG_SC 0x30
+#define X1205_REG_DTR 0x13
+#define X1205_REG_ATR 0x12
+#define X1205_REG_INT 0x11
+#define X1205_REG_0 0x10
+#define X1205_REG_Y2K1 0x0F
+#define X1205_REG_DWA1 0x0E
+#define X1205_REG_YRA1 0x0D
+#define X1205_REG_MOA1 0x0C
+#define X1205_REG_DTA1 0x0B
+#define X1205_REG_HRA1 0x0A
+#define X1205_REG_MNA1 0x09
+#define X1205_REG_SCA1 0x08
+#define X1205_REG_Y2K0 0x07
+#define X1205_REG_DWA0 0x06
+#define X1205_REG_YRA0 0x05
+#define X1205_REG_MOA0 0x04
+#define X1205_REG_DTA0 0x03
+#define X1205_REG_HRA0 0x02
+#define X1205_REG_MNA0 0x01
+#define X1205_REG_SCA0 0x00
+
+#define X1205_CCR_BASE 0x30 /* Base address of CCR */
+#define X1205_ALM0_BASE 0x00 /* Base address of ALARM0 */
+
+#define X1205_SR_RTCF 0x01 /* Clock failure */
+#define X1205_SR_WEL 0x02 /* Write Enable Latch */
+#define X1205_SR_RWEL 0x04 /* Register Write Enable */
+
+#define X1205_DTR_DTR0 0x01
+#define X1205_DTR_DTR1 0x02
+#define X1205_DTR_DTR2 0x04
+
+#define X1205_HR_MIL 0x80 /* Set in ccr.hour for 24 hr mode */
+
+static void rtc_write(int reg, u8 val)
+{
+ i2c_write(CONFIG_SYS_I2C_RTC_ADDR, reg, 2, &val, 1);
+}
+
+/*
+ * In the routines that deal directly with the x1205 hardware, we use
+ * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch
+ * Epoch is initialized as 2000. Time is set to UTC.
+ */
+int rtc_get(struct rtc_time *tm)
+{
+ u8 buf[8];
+
+ i2c_read(CONFIG_SYS_I2C_RTC_ADDR, X1205_CCR_BASE, 2, buf, 8);
+
+ debug("%s: raw read data - sec=%02x, min=%02x, hr=%02x, "
+ "mday=%02x, mon=%02x, year=%02x, wday=%02x, y2k=%02x\n",
+ __FUNCTION__,
+ buf[0], buf[1], buf[2], buf[3],
+ buf[4], buf[5], buf[6], buf[7]);
+
+ tm->tm_sec = bcd2bin(buf[CCR_SEC]);
+ tm->tm_min = bcd2bin(buf[CCR_MIN]);
+ tm->tm_hour = bcd2bin(buf[CCR_HOUR] & 0x3F); /* hr is 0-23 */
+ tm->tm_mday = bcd2bin(buf[CCR_MDAY]);
+ tm->tm_mon = bcd2bin(buf[CCR_MONTH]); /* mon is 0-11 */
+ tm->tm_year = bcd2bin(buf[CCR_YEAR])
+ + (bcd2bin(buf[CCR_Y2K]) * 100);
+ tm->tm_wday = buf[CCR_WDAY];
+
+ debug("%s: tm is secs=%d, mins=%d, hours=%d, "
+ "mday=%d, mon=%d, year=%d, wday=%d\n",
+ __FUNCTION__,
+ tm->tm_sec, tm->tm_min, tm->tm_hour,
+ tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+ return 0;
+}
+
+int rtc_set(struct rtc_time *tm)
+{
+ int i;
+ u8 buf[8];
+
+ debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ buf[CCR_SEC] = bin2bcd(tm->tm_sec);
+ buf[CCR_MIN] = bin2bcd(tm->tm_min);
+
+ /* set hour and 24hr bit */
+ buf[CCR_HOUR] = bin2bcd(tm->tm_hour) | X1205_HR_MIL;
+
+ buf[CCR_MDAY] = bin2bcd(tm->tm_mday);
+
+ /* month, 1 - 12 */
+ buf[CCR_MONTH] = bin2bcd(tm->tm_mon);
+
+ /* year, since the rtc epoch*/
+ buf[CCR_YEAR] = bin2bcd(tm->tm_year % 100);
+ buf[CCR_WDAY] = tm->tm_wday & 0x07;
+ buf[CCR_Y2K] = bin2bcd(tm->tm_year / 100);
+
+ /* this sequence is required to unlock the chip */
+ rtc_write(X1205_REG_SR, X1205_SR_WEL);
+ rtc_write(X1205_REG_SR, X1205_SR_WEL | X1205_SR_RWEL);
+
+ /* write register's data */
+ for (i = 0; i < 8; i++)
+ rtc_write(X1205_CCR_BASE + i, buf[i]);
+
+ rtc_write(X1205_REG_SR, 0);
+
+ return 0;
+}
+
+void rtc_reset(void)
+{
+ /*
+ * Nothing to do
+ */
+}