diff options
Diffstat (limited to 'roms/u-boot/drivers/rtc')
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, ¢, 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, ¢, 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, ¢, 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(®s->time); + + /* read the date register */ + date = readl(®s->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, ®s->time); + + /* write the date register */ + writel(date, ®s->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(®s->time); + sec = bcd2bin((time >> MVRTC_SEC_SFT) & MVRTC_SEC_MSK); + udelay(1000000); + time = readl(®s->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 + */ +} |