From 187573405d9fd1d070f035806769cfee52224ac9 Mon Sep 17 00:00:00 2001 Message-Id: <187573405d9fd1d070f035806769cfee52224ac9.1540752056.git.aditya@kobol.io> In-Reply-To: <3eb15c0c6a0f26e418074cf3be9490a36f9161fd.1540752056.git.aditya@kobol.io> References: <3eb15c0c6a0f26e418074cf3be9490a36f9161fd.1540752056.git.aditya@kobol.io> From: Jon Nettleton Date: Thu, 24 Aug 2017 22:28:06 +0200 Subject: [PATCH 03/11] mvebu: rtc: Add DM driver for mvebu rtc This is heavily based on the linux kernel driver. Please note the long timeout I have added. I have found that adding this additional time fixes a lot of the other timing problems that were worked around with various delays and repeated commands. Signed-off-by: Jon Nettleton --- drivers/rtc/Kconfig | 7 +++ drivers/rtc/Makefile | 1 + drivers/rtc/mvebu_rtc.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 159 insertions(+) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index bcc01b1..59b3d2c 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -31,6 +31,13 @@ config TPL_DM_RTC drivers to perform the actual functions. See rtc.h for a description of the API. +config RTC_MVEBU + bool "Armada 38x Marvell SoC RTC" + depends on DM_RTC + help + If you say yes here you will get support for the in-chip RTC + that can be found in the Armada 38x Marvell's SoC device + config RTC_PCF2127 bool "Enable PCF2127 driver" depends on DM_RTC diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 1724602..0e23190 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -38,6 +38,7 @@ 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_MVEBU) += mvebu_rtc.o obj-$(CONFIG_RTC_MX27) += mx27rtc.o obj-$(CONFIG_RTC_MXS) += mxsrtc.o obj-$(CONFIG_RTC_PCF8563) += pcf8563.o diff --git a/drivers/rtc/mvebu_rtc.c b/drivers/rtc/mvebu_rtc.c new file mode 100644 index 0000000..b04d8e6 --- /dev/null +++ b/drivers/rtc/mvebu_rtc.c @@ -0,0 +1,151 @@ +/* + * (C) Copyright 2015 Solid Run Ltd. + * Author: Jon Nettleton + * + * Based on Linux Kernel driver rtc-armada38x.c + * Copyright (C) 2015 Marvell + * Gregory Clement + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#define RTC_NOMINAL_TIMING 0x2000 + +#define RTC_STATUS 0x0 +#define RTC_STATUS_ALARM1 BIT(0) +#define RTC_STATUS_ALARM2 BIT(1) +#define RTC_TIME 0xC +#define RTC_ALARM1 0x10 +#define RTC_CLOCK_CORR 0x18 +#define RTC_TEST_CONF 0x1C + +/* armada38x SoC registers */ +#define RTC_38X_BRIDGE_TIMING_CTRL_REG_OFFS 0x0 +#define RTC_38X_WRCLK_PERIOD_OFFS 0 +#define RTC_38X_WRCLK_PERIOD_MASK (0x3FF << RTC_38X_WRCLK_PERIOD_OFFS) +#define RTC_38X_READ_OUTPUT_DELAY_OFFS 26 +#define RTC_38X_READ_OUTPUT_DELAY_MASK (0x1F << RTC_38X_READ_OUTPUT_DELAY_OFFS) + +struct mvebu_rtc_platdata { + fdt_addr_t base; + fdt_addr_t soc_base; +}; + +/* + * According to the datasheet, the OS should wait 5us after every + * register write to the RTC hard macro so that the required update + * can occur without holding off the system bus + * According to errata FE-3124064, Write to any RTC register + * may fail. As a workaround, before writing to RTC + * register, issue a dummy write of 0x0 twice to RTC Status + * register. + */ + +static void rtc_delayed_write(u32 val, struct mvebu_rtc_platdata *rtc, int offset) +{ + writel(0, rtc->base + RTC_STATUS); + writel(0, rtc->base + RTC_STATUS); + writel(val, rtc->base + offset); + mdelay(10); +} + +static unsigned long read_rtc_reg(struct mvebu_rtc_platdata *rtc, uint8_t rtc_reg) +{ + unsigned long value = readl(rtc->base + rtc_reg); + + return value; +} + +static void rtc_update_38x_mbus_timing_params(struct mvebu_rtc_platdata *rtc) +{ + uint32_t reg; + + reg = readl(rtc->soc_base + RTC_38X_BRIDGE_TIMING_CTRL_REG_OFFS); + reg &= ~RTC_38X_WRCLK_PERIOD_MASK; + reg |= 0x3FF << RTC_38X_WRCLK_PERIOD_OFFS; /*Maximum value*/ + reg &= ~RTC_38X_READ_OUTPUT_DELAY_MASK; + reg |= 0x1F << RTC_38X_READ_OUTPUT_DELAY_OFFS; /*Maximum value*/ + writel(reg, rtc->soc_base + RTC_38X_BRIDGE_TIMING_CTRL_REG_OFFS); +} + +static int mvebu_rtc_get(struct udevice *dev, struct rtc_time *tm) +{ + struct mvebu_rtc_platdata *rtc = dev_get_platdata(dev); + + rtc_to_tm(read_rtc_reg(rtc, RTC_TIME), tm); + + return 0; +} + +static int mvebu_rtc_set(struct udevice *dev, const struct rtc_time *tm) +{ + struct mvebu_rtc_platdata *rtc = dev_get_platdata(dev); + unsigned long time; + + time = rtc_mktime(tm); + rtc_delayed_write(time, rtc, RTC_TIME); + + return 0; +} + +static int mvebu_rtc_reset(struct udevice *dev) +{ + struct mvebu_rtc_platdata *rtc = dev_get_platdata(dev); + + rtc_delayed_write(0, rtc, RTC_TEST_CONF); + rtc_delayed_write(0, rtc, RTC_TIME); + rtc_delayed_write((RTC_STATUS_ALARM1 | RTC_STATUS_ALARM2), rtc, RTC_STATUS); + rtc_delayed_write(RTC_NOMINAL_TIMING, rtc, RTC_CLOCK_CORR); + + return 0; +} + +static int mvebu_rtc_read8(struct udevice *dev, unsigned int reg) +{ + return -ENOSYS; +} + +static int mvebu_rtc_write8(struct udevice *dev, unsigned int reg, int val) +{ + return -ENOSYS; +} + +static int mvebu_rtc_probe(struct udevice *dev) +{ + struct mvebu_rtc_platdata *rtc = dev_get_platdata(dev); + + rtc->base = devfdt_get_addr(dev); + rtc->soc_base = devfdt_get_addr_name(dev, "rtc-soc"); + + rtc_update_38x_mbus_timing_params(rtc); + + return 0; +} + +static const struct rtc_ops mvebu_rtc_ops = { + .get = mvebu_rtc_get, + .set = mvebu_rtc_set, + .reset = mvebu_rtc_reset, + .read8 = mvebu_rtc_read8, + .write8 = mvebu_rtc_write8, +}; + +static const struct udevice_id mvebu_rtc_ids[] = { + { .compatible = "marvell,armada-380-rtc" }, + { } +}; + +U_BOOT_DRIVER(rtc_mvebu) = { + .name = "rtc-mvebu", + .id = UCLASS_RTC, + .of_match = mvebu_rtc_ids, + .probe = mvebu_rtc_probe, + .ops = &mvebu_rtc_ops, +}; -- 2.7.4