mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-14 08:57:58 +00:00
db41d65a97
At present panic() is in the vsprintf.h header file. That does not seem like an obvious choice for hang(), even though it relates to panic(). So let's put hang() in its own header. Signed-off-by: Simon Glass <sjg@chromium.org> [trini: Migrate a few more files] Signed-off-by: Tom Rini <trini@konsulko.com>
187 lines
4.5 KiB
C
187 lines
4.5 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 2019 Andes Technology Corporation
|
|
* Rick Chen, Andes Technology Corporation <rick@andestech.com>
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <command.h>
|
|
#include <cache.h>
|
|
#include <dm.h>
|
|
#include <hang.h>
|
|
#include <asm/io.h>
|
|
#include <dm/ofnode.h>
|
|
|
|
struct l2cache {
|
|
volatile u64 configure;
|
|
volatile u64 control;
|
|
volatile u64 hpm0;
|
|
volatile u64 hpm1;
|
|
volatile u64 hpm2;
|
|
volatile u64 hpm3;
|
|
volatile u64 error_status;
|
|
volatile u64 ecc_error;
|
|
volatile u64 cctl_command0;
|
|
volatile u64 cctl_access_line0;
|
|
volatile u64 cctl_command1;
|
|
volatile u64 cctl_access_line1;
|
|
volatile u64 cctl_command2;
|
|
volatile u64 cctl_access_line2;
|
|
volatile u64 cctl_command3;
|
|
volatile u64 cctl_access_line4;
|
|
volatile u64 cctl_status;
|
|
};
|
|
|
|
/* Control Register */
|
|
#define L2_ENABLE 0x1
|
|
/* prefetch */
|
|
#define IPREPETCH_OFF 3
|
|
#define DPREPETCH_OFF 5
|
|
#define IPREPETCH_MSK (3 << IPREPETCH_OFF)
|
|
#define DPREPETCH_MSK (3 << DPREPETCH_OFF)
|
|
/* tag ram */
|
|
#define TRAMOCTL_OFF 8
|
|
#define TRAMICTL_OFF 10
|
|
#define TRAMOCTL_MSK (3 << TRAMOCTL_OFF)
|
|
#define TRAMICTL_MSK BIT(TRAMICTL_OFF)
|
|
/* data ram */
|
|
#define DRAMOCTL_OFF 11
|
|
#define DRAMICTL_OFF 13
|
|
#define DRAMOCTL_MSK (3 << DRAMOCTL_OFF)
|
|
#define DRAMICTL_MSK BIT(DRAMICTL_OFF)
|
|
|
|
/* CCTL Command Register */
|
|
#define CCTL_CMD_REG(base, hart) ((ulong)(base) + 0x40 + (hart) * 0x10)
|
|
#define L2_WBINVAL_ALL 0x12
|
|
|
|
/* CCTL Status Register */
|
|
#define CCTL_STATUS_MSK(hart) (0xf << ((hart) * 4))
|
|
#define CCTL_STATUS_IDLE(hart) (0 << ((hart) * 4))
|
|
#define CCTL_STATUS_PROCESS(hart) (1 << ((hart) * 4))
|
|
#define CCTL_STATUS_ILLEGAL(hart) (2 << ((hart) * 4))
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
struct v5l2_plat {
|
|
struct l2cache *regs;
|
|
u32 iprefetch;
|
|
u32 dprefetch;
|
|
u32 tram_ctl[2];
|
|
u32 dram_ctl[2];
|
|
};
|
|
|
|
static int v5l2_enable(struct udevice *dev)
|
|
{
|
|
struct v5l2_plat *plat = dev_get_platdata(dev);
|
|
volatile struct l2cache *regs = plat->regs;
|
|
|
|
if (regs)
|
|
setbits_le32(®s->control, L2_ENABLE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int v5l2_disable(struct udevice *dev)
|
|
{
|
|
struct v5l2_plat *plat = dev_get_platdata(dev);
|
|
volatile struct l2cache *regs = plat->regs;
|
|
u8 hart = gd->arch.boot_hart;
|
|
void __iomem *cctlcmd = (void __iomem *)CCTL_CMD_REG(regs, hart);
|
|
|
|
if ((regs) && (readl(®s->control) & L2_ENABLE)) {
|
|
writel(L2_WBINVAL_ALL, cctlcmd);
|
|
|
|
while ((readl(®s->cctl_status) & CCTL_STATUS_MSK(hart))) {
|
|
if ((readl(®s->cctl_status) & CCTL_STATUS_ILLEGAL(hart))) {
|
|
printf("L2 flush illegal! hanging...");
|
|
hang();
|
|
}
|
|
}
|
|
clrbits_le32(®s->control, L2_ENABLE);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int v5l2_ofdata_to_platdata(struct udevice *dev)
|
|
{
|
|
struct v5l2_plat *plat = dev_get_platdata(dev);
|
|
struct l2cache *regs;
|
|
|
|
regs = (struct l2cache *)dev_read_addr(dev);
|
|
plat->regs = regs;
|
|
|
|
plat->iprefetch = -EINVAL;
|
|
plat->dprefetch = -EINVAL;
|
|
plat->tram_ctl[0] = -EINVAL;
|
|
plat->dram_ctl[0] = -EINVAL;
|
|
|
|
/* Instruction and data fetch prefetch depth */
|
|
dev_read_u32(dev, "andes,inst-prefetch", &plat->iprefetch);
|
|
dev_read_u32(dev, "andes,data-prefetch", &plat->dprefetch);
|
|
|
|
/* Set tag RAM and data RAM setup and output cycle */
|
|
dev_read_u32_array(dev, "andes,tag-ram-ctl", plat->tram_ctl, 2);
|
|
dev_read_u32_array(dev, "andes,data-ram-ctl", plat->dram_ctl, 2);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int v5l2_probe(struct udevice *dev)
|
|
{
|
|
struct v5l2_plat *plat = dev_get_platdata(dev);
|
|
struct l2cache *regs = plat->regs;
|
|
u32 ctl_val;
|
|
|
|
ctl_val = readl(®s->control);
|
|
|
|
if (!(ctl_val & L2_ENABLE))
|
|
ctl_val |= L2_ENABLE;
|
|
|
|
if (plat->iprefetch != -EINVAL) {
|
|
ctl_val &= ~(IPREPETCH_MSK);
|
|
ctl_val |= (plat->iprefetch << IPREPETCH_OFF);
|
|
}
|
|
|
|
if (plat->dprefetch != -EINVAL) {
|
|
ctl_val &= ~(DPREPETCH_MSK);
|
|
ctl_val |= (plat->dprefetch << DPREPETCH_OFF);
|
|
}
|
|
|
|
if (plat->tram_ctl[0] != -EINVAL) {
|
|
ctl_val &= ~(TRAMOCTL_MSK | TRAMICTL_MSK);
|
|
ctl_val |= plat->tram_ctl[0] << TRAMOCTL_OFF;
|
|
ctl_val |= plat->tram_ctl[1] << TRAMICTL_OFF;
|
|
}
|
|
|
|
if (plat->dram_ctl[0] != -EINVAL) {
|
|
ctl_val &= ~(DRAMOCTL_MSK | DRAMICTL_MSK);
|
|
ctl_val |= plat->dram_ctl[0] << DRAMOCTL_OFF;
|
|
ctl_val |= plat->dram_ctl[1] << DRAMICTL_OFF;
|
|
}
|
|
|
|
writel(ctl_val, ®s->control);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct udevice_id v5l2_cache_ids[] = {
|
|
{ .compatible = "v5l2cache" },
|
|
{}
|
|
};
|
|
|
|
static const struct cache_ops v5l2_cache_ops = {
|
|
.enable = v5l2_enable,
|
|
.disable = v5l2_disable,
|
|
};
|
|
|
|
U_BOOT_DRIVER(v5l2_cache) = {
|
|
.name = "v5l2_cache",
|
|
.id = UCLASS_CACHE,
|
|
.of_match = v5l2_cache_ids,
|
|
.ofdata_to_platdata = v5l2_ofdata_to_platdata,
|
|
.probe = v5l2_probe,
|
|
.platdata_auto_alloc_size = sizeof(struct v5l2_plat),
|
|
.ops = &v5l2_cache_ops,
|
|
.flags = DM_FLAG_PRE_RELOC,
|
|
};
|