Hi Maxim, On 4 January 2017 at 12:46, Maxim Sloyko <max...@google.com> wrote: > Add support for timer for Aspeed ast2400/ast2500 devices. > The driver actually controls several devices, but because all devices > share the same Control Register, it is somewhat difficult to completely > decouple them. Since only one timer is needed at the moment, this should > be OK. > > The timer uses fixed clock, so does not rely on a clock driver. > > Signed-off-by: Maxim Sloyko <max...@google.com> > --- > > arch/arm/include/asm/arch-aspeed/timer.h | 54 ++++++++++++++++++ > drivers/timer/Kconfig | 7 +++ > drivers/timer/Makefile | 1 + > drivers/timer/ast_timer.c | 96 > ++++++++++++++++++++++++++++++++ > 4 files changed, 158 insertions(+) > create mode 100644 arch/arm/include/asm/arch-aspeed/timer.h > create mode 100644 drivers/timer/ast_timer.c
Reviewed-by: Simon Glass <s...@chromium.org> nits below. > > diff --git a/arch/arm/include/asm/arch-aspeed/timer.h > b/arch/arm/include/asm/arch-aspeed/timer.h > new file mode 100644 > index 0000000000..87c5b354ec > --- /dev/null > +++ b/arch/arm/include/asm/arch-aspeed/timer.h > @@ -0,0 +1,54 @@ > +/* > + * Copyright (c) 2016 Google, Inc > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > +#ifndef _ASM_ARCH_TIMER_H > +#define _ASM_ARCH_TIMER_H > + > +/* Each timer has 4 control bits in ctrl1 register. > + * Timer1 uses bits 0:3, Timer2 uses bits 4:7 and so on, > + * such that timer X uses bits (4 * X - 4):(4 * X - 1) > + * If the timer does not support PWM, bit 4 is reserved. > + */ > +#define AST_TMC_EN (1 << 0) > +#define AST_TMC_1MHZ (1 << 1) > +#define AST_TMC_OVFINTR (1 << 2) > +#define AST_TMC_PWM (1 << 3) > + > +/* Timers are counted from 1 in the datasheet. */ > +#define AST_TMC_CTRL1_SHIFT(n) (4 * ((n) - 1)) > + > +#define AST_TMC_RATE (1000*1000) > + > +#ifndef __ASSEMBLY__ > + > +/* > + * All timers share control registers, which makes it harder to make them > + * separate devices. Since only one timer is needed at the moment, making > + * it this just one device. > + */ > + > +struct ast_timer_counter { > + u32 status; > + u32 reload_val; > + u32 match1; > + u32 match2; > +}; > + > +struct ast_timer { > + struct ast_timer_counter timers1[3]; > + u32 ctrl1; > + u32 ctrl2; > +#ifdef CONFIG_ASPEED_AST2500 > + u32 ctrl3; > + u32 ctrl1_clr; > +#else > + u32 reserved[2]; > +#endif > + struct ast_timer_counter timers2[5]; > +}; > + > +#endif /* __ASSEMBLY__ */ > + > +#endif /* _ASM_ARCH_TIMER_H */ > diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig > index cb18f12fc9..9c5f98bb88 100644 > --- a/drivers/timer/Kconfig > +++ b/drivers/timer/Kconfig > @@ -46,4 +46,11 @@ config OMAP_TIMER > help > Select this to enable an timer for Omap devices. > > +config AST_TIMER > + bool "Aspeed ast2400/ast2500 timer support" > + depends on TIMER > + default y if ARCH_ASPEED > + help > + Select this to enable timer for Aspeed ast2400/ast2500 devices. Can you add more detail? How many channels? What features are supported by the driver? > + > endmenu > diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile > index f351fbb4e0..a4b1a486b0 100644 > --- a/drivers/timer/Makefile > +++ b/drivers/timer/Makefile > @@ -9,3 +9,4 @@ obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o > obj-$(CONFIG_SANDBOX_TIMER) += sandbox_timer.o > obj-$(CONFIG_X86_TSC_TIMER) += tsc_timer.o > obj-$(CONFIG_OMAP_TIMER) += omap-timer.o > +obj-$(CONFIG_AST_TIMER) += ast_timer.o > diff --git a/drivers/timer/ast_timer.c b/drivers/timer/ast_timer.c > new file mode 100644 > index 0000000000..f644882f40 > --- /dev/null > +++ b/drivers/timer/ast_timer.c > @@ -0,0 +1,96 @@ > +/* > + * Copyright 2016 Google Inc. > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#include <common.h> > +#include <dm.h> > +#include <errno.h> > +#include <timer.h> > +#include <asm/io.h> > +#include <asm/arch/timer.h> > + > +DECLARE_GLOBAL_DATA_PTR; > + > +#define AST_TICK_TIMER 1 > +#define AST_TMC_RELOAD_VAL 0xffffffff > + > +struct ast_timer_priv { > + struct ast_timer *regs; > +}; > + > +static struct ast_timer_counter *ast_get_timer_counter(struct ast_timer > *timer, > + int n) > +{ > + if (n > 3) > + return &timer->timers2[n - 4]; > + else > + return &timer->timers1[n - 1]; > +} > + > +static int ast_timer_probe(struct udevice *dev) > +{ > + struct ast_timer_priv *priv = dev_get_priv(dev); > + struct ast_timer_counter *tmc = ast_get_timer_counter(priv->regs, > + AST_TICK_TIMER); I suppose tmc could be in your struct ast_timer_priv to save you doing this each time? > + struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); > + > + writel(AST_TMC_RELOAD_VAL, &tmc->reload_val); > + > + /* > + * Stop the timer. This will also load reload_val into > + * the status register. > + */ > + clrbits_le32(&priv->regs->ctrl1, > + AST_TMC_EN << AST_TMC_CTRL1_SHIFT(AST_TICK_TIMER)); > + /* Start the timer from the fixed 1MHz clock. */ > + setbits_le32(&priv->regs->ctrl1, > + (AST_TMC_EN | AST_TMC_1MHZ) << > + AST_TMC_CTRL1_SHIFT(AST_TICK_TIMER)); > + > + uc_priv->clock_rate = AST_TMC_RATE; > + > + return 0; > +} > + > +static int ast_timer_get_count(struct udevice *dev, u64 *count) > +{ > + struct ast_timer_priv *priv = dev_get_priv(dev); > + struct ast_timer_counter *tmc = ast_get_timer_counter(priv->regs, > + AST_TICK_TIMER); > + > + *count = AST_TMC_RELOAD_VAL - readl(&tmc->status); > + > + return 0; > +} > + > +static int ast_timer_ofdata_to_platdata(struct udevice *dev) > +{ > + struct ast_timer_priv *priv = dev_get_priv(dev); > + > + priv->regs = (struct ast_timer *)dev_get_addr(dev); You can use dev_get_addr_ptr() if you like. > + > + return 0; > +} > + > +static const struct timer_ops ast_timer_ops = { > + .get_count = ast_timer_get_count, > +}; > + > +static const struct udevice_id ast_timer_ids[] = { > + { .compatible = "aspeed,ast2500-timer" }, > + { .compatible = "aspeed,ast2400-timer" }, > + { } > +}; > + > +U_BOOT_DRIVER(sandbox_timer) = { s/sandbox/ast/ or something, as Tom, mentioned. > + .name = "ast_timer", > + .id = UCLASS_TIMER, > + .of_match = ast_timer_ids, > + .probe = ast_timer_probe, > + .priv_auto_alloc_size = sizeof(struct ast_timer_priv), > + .ofdata_to_platdata = ast_timer_ofdata_to_platdata, > + .ops = &ast_timer_ops, > + .flags = DM_FLAG_PRE_RELOC, > +}; > -- > 2.11.0.390.gc69c2f50cf-goog Regards, Simon > _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot