[PATCH] timer: starfive: Add Starfive timer support

Simon Glass sjg at google.com
Wed Oct 4 04:10:51 CEST 2023


On Tue, 19 Sept 2023 at 06:08, Kuan Lim Lee
<kuanlim.lee at starfivetech.com> wrote:
>
> Add timer driver in Starfive SoC. It is an timer that outside
> of CPU core and inside Starfive SoC.
>
> Signed-off-by: Kuan Lim Lee <kuanlim.lee at starfivetech.com>
> Reviewed-by: Wei Liang Lim <weiliang.lim at starfivetech.com>
> ---
>  drivers/timer/Kconfig          |  7 +++
>  drivers/timer/Makefile         |  1 +
>  drivers/timer/starfive-timer.c | 94 ++++++++++++++++++++++++++++++++++
>  3 files changed, 102 insertions(+)
>  create mode 100644 drivers/timer/starfive-timer.c

Reviewed-by: Simon Glass <sjg at chromium.org>

nits below

>
> diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
> index 915b2af160..a98be9dfae 100644
> --- a/drivers/timer/Kconfig
> +++ b/drivers/timer/Kconfig
> @@ -326,4 +326,11 @@ config XILINX_TIMER
>           Select this to enable support for the timer found on
>           any Xilinx boards (axi timer).
>
> +config STARFIVE_TIMER
> +       bool "Starfive timer support"
> +       depends on TIMER
> +       help
> +         Select this to enable support for the timer found on
> +         Starfive SoC.

What resolution is the timer? How is it clocked? Is there only one channel?

> +
>  endmenu
> diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile
> index 1ca74805fd..1ef814970b 100644
> --- a/drivers/timer/Makefile
> +++ b/drivers/timer/Makefile
> @@ -34,3 +34,4 @@ obj-$(CONFIG_MTK_TIMER)               += mtk_timer.o
>  obj-$(CONFIG_MCHP_PIT64B_TIMER)        += mchp-pit64b-timer.o
>  obj-$(CONFIG_IMX_GPT_TIMER)    += imx-gpt-timer.o
>  obj-$(CONFIG_XILINX_TIMER)     += xilinx-timer.o
> +obj-$(CONFIG_STARFIVE_TIMER)   += starfive-timer.o
> diff --git a/drivers/timer/starfive-timer.c b/drivers/timer/starfive-timer.c
> new file mode 100644
> index 0000000000..816402fdbf
> --- /dev/null
> +++ b/drivers/timer/starfive-timer.c
> @@ -0,0 +1,94 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright 2022 StarFive, Inc. All rights reserved.
> + *   Author: Lee Kuan Lim <kuanlim.lee at starfivetech.com>
> + */
> +
> +#include <common.h>
> +#include <clk.h>
> +#include <dm.h>
> +#include <time.h>
> +#include <timer.h>
> +#include <asm/io.h>
> +#include <dm/device-internal.h>
> +#include <linux/err.h>
> +
> +#define        STF_TIMER_INT_STATUS    0x00
> +#define STF_TIMER_CTL          0x04
> +#define STF_TIMER_LOAD         0x08
> +#define STF_TIMER_ENABLE       0x10
> +#define STF_TIMER_RELOAD       0x14
> +#define STF_TIMER_VALUE                0x18
> +#define STF_TIMER_INT_CLR      0x20
> +#define STF_TIMER_INT_MASK     0x24
> +
> +struct starfive_timer_priv {
> +       void __iomem *base;
> +       u32 timer_size;
> +};
> +
> +static u64 notrace starfive_get_count(struct udevice *dev)
> +{
> +       struct starfive_timer_priv *priv = dev_get_priv(dev);
> +
> +       /* Read decrement timer value and convert to increment value */
> +       return priv->timer_size - readl(priv->base + STF_TIMER_VALUE);
> +}

As an enhancement, you could provide a timer_early_get_count()
function and an easly setup, so you can use bootstage.

> +
> +static const struct timer_ops starfive_ops = {
> +       .get_count = starfive_get_count,
> +};
> +
> +static int starfive_probe(struct udevice *dev)
> +{
> +       struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
> +       struct starfive_timer_priv *priv = dev_get_priv(dev);
> +       int timer_channel;
> +       struct clk clk;
> +       int ret;
> +
> +       priv->base = dev_read_addr_ptr(dev);
> +       if (IS_ERR(priv->base))

if (!priv->base)
    return -EINVAL

> +               return PTR_ERR(priv->base);
> +
> +       timer_channel = dev_read_u32_default(dev, "channel", 0);
> +       priv->base = priv->base + (0x40 * timer_channel);
> +
> +       /* Get clock rate from channel selectecd*/
> +       ret = clk_get_by_index(dev, timer_channel, &clk);
> +       if (ret)
> +               return ret;
> +
> +       ret = clk_enable(&clk);
> +       if (ret)
> +               return ret;
> +       uc_priv->clock_rate = clk_get_rate(&clk);
> +
> +       /* Initiate timer, channel 0 */
> +       /* Unmask Interrupt Mask */

multi-line comment style is:

 /*
  * line 1
  * line 2
  */

> +       writel(0, priv->base + STF_TIMER_INT_MASK);
> +       /* Single run mode Setting */
> +       if (dev_read_bool(dev, "single-run"))
> +               writel(1, priv->base + STF_TIMER_CTL);
> +       /* Set Reload value */
> +       priv->timer_size = dev_read_u32_default(dev, "timer-size", 0xffffffff);

-1U  ?

> +       writel(priv->timer_size, priv->base + STF_TIMER_LOAD);
> +       /* Enable to start timer */
> +       writel(1, priv->base + STF_TIMER_ENABLE);
> +
> +       return 0;
> +}
> +
> +static const struct udevice_id starfive_ids[] = {
> +       { .compatible = "starfive,jh8100-timers" },
> +       { }
> +};
> +
> +U_BOOT_DRIVER(jh8100_starfive_timer) = {
> +       .name           = "jh8100_starfive_timer",

What is jh8100 ? Do you need that?

> +       .id             = UCLASS_TIMER,
> +       .of_match       = starfive_ids,
> +       .probe          = starfive_probe,
> +       .ops            = &starfive_ops,
> +       .priv_auto      = sizeof(struct starfive_timer_priv),
> +};
> --
> 2.34.1
>

Regards,
Simon


More information about the U-Boot mailing list