提交 e5ca9a75 编写于 作者: S Sean Anderson 提交者: Andes

riscv: Rework Sifive CLINT as UCLASS_TIMER driver

This converts the clint driver from the riscv-specific interface to be a
DM-based UCLASS_TIMER driver. In addition, the SiFive DDR driver previously
implicitly depended on the CLINT to select REGMAP.

Unlike Andes's PLMT/PLIC (which AFAIK never have anything pass it a dtb),
the SiFive CLINT is part of the device tree passed in by qemu. This device
tree doesn't have a clocks or clock-frequency property on clint, so we need
to fall back on the timebase-frequency property. Perhaps in the future we
can get a clock-frequency property added to the qemu dtb.

Unlike with the Andes PLMT, the Sifive CLINT is also an IPI controller.
RISCV_SYSCON_CLINT is retained for this purpose.
Signed-off-by: NSean Anderson <seanga2@gmail.com>
Reviewed-by: NPragnesh Patel <pragnesh.patel@openfive.com>
上级 15943bb5
......@@ -155,10 +155,6 @@ config 64BIT
config SIFIVE_CLINT
bool
depends on RISCV_MMODE || SPL_RISCV_MMODE
select REGMAP
select SYSCON
select SPL_REGMAP if SPL
select SPL_SYSCON if SPL
help
The SiFive CLINT block holds memory-mapped control and status registers
associated with software and timer interrupts.
......
......@@ -8,9 +8,9 @@
*/
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <regmap.h>
#include <syscon.h>
#include <timer.h>
#include <asm/io.h>
#include <asm/syscon.h>
#include <linux/err.h>
......@@ -24,68 +24,74 @@
DECLARE_GLOBAL_DATA_PTR;
int riscv_get_time(u64 *time)
int riscv_init_ipi(void)
{
/* ensure timer register base has a sane value */
riscv_init_ipi();
int ret;
struct udevice *dev;
ret = uclass_get_device_by_driver(UCLASS_TIMER,
DM_GET_DRIVER(sifive_clint), &dev);
if (ret)
return ret;
*time = readq((void __iomem *)MTIME_REG(gd->arch.clint));
gd->arch.clint = dev_read_addr_ptr(dev);
if (!gd->arch.clint)
return -EINVAL;
return 0;
}
int riscv_set_timecmp(int hart, u64 cmp)
int riscv_send_ipi(int hart)
{
/* ensure timer register base has a sane value */
riscv_init_ipi();
writeq(cmp, (void __iomem *)MTIMECMP_REG(gd->arch.clint, hart));
writel(1, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
return 0;
}
int riscv_init_ipi(void)
int riscv_clear_ipi(int hart)
{
if (!gd->arch.clint) {
long *ret = syscon_get_first_range(RISCV_SYSCON_CLINT);
if (IS_ERR(ret))
return PTR_ERR(ret);
gd->arch.clint = ret;
}
writel(0, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
return 0;
}
int riscv_send_ipi(int hart)
int riscv_get_ipi(int hart, int *pending)
{
writel(1, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
*pending = readl((void __iomem *)MSIP_REG(gd->arch.clint, hart));
return 0;
}
int riscv_clear_ipi(int hart)
static int sifive_clint_get_count(struct udevice *dev, u64 *count)
{
writel(0, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
*count = readq((void __iomem *)MTIME_REG(dev->priv));
return 0;
}
int riscv_get_ipi(int hart, int *pending)
static const struct timer_ops sifive_clint_ops = {
.get_count = sifive_clint_get_count,
};
static int sifive_clint_probe(struct udevice *dev)
{
*pending = readl((void __iomem *)MSIP_REG(gd->arch.clint, hart));
dev->priv = dev_read_addr_ptr(dev);
if (!dev->priv)
return -EINVAL;
return 0;
return timer_timebase_fallback(dev);
}
static const struct udevice_id sifive_clint_ids[] = {
{ .compatible = "riscv,clint0", .data = RISCV_SYSCON_CLINT },
{ .compatible = "riscv,clint0" },
{ }
};
U_BOOT_DRIVER(sifive_clint) = {
.name = "sifive_clint",
.id = UCLASS_SYSCON,
.id = UCLASS_TIMER,
.of_match = sifive_clint_ids,
.probe = sifive_clint_probe,
.ops = &sifive_clint_ops,
.flags = DM_FLAG_PRE_RELOC,
};
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册