mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-20 10:13:09 +00:00
41575d8e4c
This construct is quite long-winded. In earlier days it made some sense since auto-allocation was a strange concept. But with driver model now used pretty universally, we can shorten this to 'auto'. This reduces verbosity and makes it easier to read. Coincidentally it also ensures that every declaration is on one line, thus making dtoc's job easier. Signed-off-by: Simon Glass <sjg@chromium.org>
194 lines
4.4 KiB
C
194 lines
4.4 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2016, NVIDIA CORPORATION.
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <log.h>
|
|
#include <malloc.h>
|
|
#include <asm/io.h>
|
|
#include <dm.h>
|
|
#include <mailbox-uclass.h>
|
|
#include <dt-bindings/mailbox/tegra186-hsp.h>
|
|
#include <linux/bitops.h>
|
|
|
|
#define TEGRA_HSP_INT_DIMENSIONING 0x380
|
|
#define TEGRA_HSP_INT_DIMENSIONING_NSI_SHIFT 16
|
|
#define TEGRA_HSP_INT_DIMENSIONING_NSI_MASK 0xf
|
|
#define TEGRA_HSP_INT_DIMENSIONING_NDB_SHIFT 12
|
|
#define TEGRA_HSP_INT_DIMENSIONING_NDB_MASK 0xf
|
|
#define TEGRA_HSP_INT_DIMENSIONING_NAS_SHIFT 8
|
|
#define TEGRA_HSP_INT_DIMENSIONING_NAS_MASK 0xf
|
|
#define TEGRA_HSP_INT_DIMENSIONING_NSS_SHIFT 4
|
|
#define TEGRA_HSP_INT_DIMENSIONING_NSS_MASK 0xf
|
|
#define TEGRA_HSP_INT_DIMENSIONING_NSM_SHIFT 0
|
|
#define TEGRA_HSP_INT_DIMENSIONING_NSM_MASK 0xf
|
|
|
|
#define TEGRA_HSP_DB_REG_TRIGGER 0x0
|
|
#define TEGRA_HSP_DB_REG_ENABLE 0x4
|
|
#define TEGRA_HSP_DB_REG_RAW 0x8
|
|
#define TEGRA_HSP_DB_REG_PENDING 0xc
|
|
|
|
#define TEGRA_HSP_DB_ID_CCPLEX 1
|
|
#define TEGRA_HSP_DB_ID_BPMP 3
|
|
#define TEGRA_HSP_DB_ID_NUM 7
|
|
|
|
struct tegra_hsp {
|
|
fdt_addr_t regs;
|
|
uint32_t db_base;
|
|
};
|
|
|
|
static uint32_t *tegra_hsp_reg(struct tegra_hsp *thsp, uint32_t db_id,
|
|
uint32_t reg)
|
|
{
|
|
return (uint32_t *)(thsp->regs + thsp->db_base + (db_id * 0x100) + reg);
|
|
}
|
|
|
|
static uint32_t tegra_hsp_readl(struct tegra_hsp *thsp, uint32_t db_id,
|
|
uint32_t reg)
|
|
{
|
|
uint32_t *r = tegra_hsp_reg(thsp, db_id, reg);
|
|
return readl(r);
|
|
}
|
|
|
|
static void tegra_hsp_writel(struct tegra_hsp *thsp, uint32_t val,
|
|
uint32_t db_id, uint32_t reg)
|
|
{
|
|
uint32_t *r = tegra_hsp_reg(thsp, db_id, reg);
|
|
|
|
writel(val, r);
|
|
readl(r);
|
|
}
|
|
|
|
static int tegra_hsp_db_id(ulong chan_id)
|
|
{
|
|
switch (chan_id) {
|
|
case (HSP_MBOX_TYPE_DB << 16) | HSP_DB_MASTER_BPMP:
|
|
return TEGRA_HSP_DB_ID_BPMP;
|
|
default:
|
|
debug("Invalid channel ID\n");
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
static int tegra_hsp_of_xlate(struct mbox_chan *chan,
|
|
struct ofnode_phandle_args *args)
|
|
{
|
|
debug("%s(chan=%p)\n", __func__, chan);
|
|
|
|
if (args->args_count != 2) {
|
|
debug("Invaild args_count: %d\n", args->args_count);
|
|
return -EINVAL;
|
|
}
|
|
|
|
chan->id = (args->args[0] << 16) | args->args[1];
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int tegra_hsp_request(struct mbox_chan *chan)
|
|
{
|
|
int db_id;
|
|
|
|
debug("%s(chan=%p)\n", __func__, chan);
|
|
|
|
db_id = tegra_hsp_db_id(chan->id);
|
|
if (db_id < 0) {
|
|
debug("tegra_hsp_db_id() failed: %d\n", db_id);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int tegra_hsp_free(struct mbox_chan *chan)
|
|
{
|
|
debug("%s(chan=%p)\n", __func__, chan);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int tegra_hsp_send(struct mbox_chan *chan, const void *data)
|
|
{
|
|
struct tegra_hsp *thsp = dev_get_priv(chan->dev);
|
|
int db_id;
|
|
|
|
debug("%s(chan=%p, data=%p)\n", __func__, chan, data);
|
|
|
|
db_id = tegra_hsp_db_id(chan->id);
|
|
tegra_hsp_writel(thsp, 1, db_id, TEGRA_HSP_DB_REG_TRIGGER);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int tegra_hsp_recv(struct mbox_chan *chan, void *data)
|
|
{
|
|
struct tegra_hsp *thsp = dev_get_priv(chan->dev);
|
|
uint32_t db_id = TEGRA_HSP_DB_ID_CCPLEX;
|
|
uint32_t val;
|
|
|
|
debug("%s(chan=%p, data=%p)\n", __func__, chan, data);
|
|
|
|
val = tegra_hsp_readl(thsp, db_id, TEGRA_HSP_DB_REG_RAW);
|
|
if (!(val & BIT(chan->id)))
|
|
return -ENODATA;
|
|
|
|
tegra_hsp_writel(thsp, BIT(chan->id), db_id, TEGRA_HSP_DB_REG_RAW);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int tegra_hsp_bind(struct udevice *dev)
|
|
{
|
|
debug("%s(dev=%p)\n", __func__, dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int tegra_hsp_probe(struct udevice *dev)
|
|
{
|
|
struct tegra_hsp *thsp = dev_get_priv(dev);
|
|
u32 val;
|
|
int nr_sm, nr_ss, nr_as;
|
|
|
|
debug("%s(dev=%p)\n", __func__, dev);
|
|
|
|
thsp->regs = dev_read_addr(dev);
|
|
if (thsp->regs == FDT_ADDR_T_NONE)
|
|
return -ENODEV;
|
|
|
|
val = readl(thsp->regs + TEGRA_HSP_INT_DIMENSIONING);
|
|
nr_sm = (val >> TEGRA_HSP_INT_DIMENSIONING_NSM_SHIFT) &
|
|
TEGRA_HSP_INT_DIMENSIONING_NSM_MASK;
|
|
nr_ss = (val >> TEGRA_HSP_INT_DIMENSIONING_NSS_SHIFT) &
|
|
TEGRA_HSP_INT_DIMENSIONING_NSS_MASK;
|
|
nr_as = (val >> TEGRA_HSP_INT_DIMENSIONING_NAS_SHIFT) &
|
|
TEGRA_HSP_INT_DIMENSIONING_NAS_MASK;
|
|
|
|
thsp->db_base = (1 + (nr_sm >> 1) + nr_ss + nr_as) << 16;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct udevice_id tegra_hsp_ids[] = {
|
|
{ .compatible = "nvidia,tegra186-hsp" },
|
|
{ }
|
|
};
|
|
|
|
struct mbox_ops tegra_hsp_mbox_ops = {
|
|
.of_xlate = tegra_hsp_of_xlate,
|
|
.request = tegra_hsp_request,
|
|
.rfree = tegra_hsp_free,
|
|
.send = tegra_hsp_send,
|
|
.recv = tegra_hsp_recv,
|
|
};
|
|
|
|
U_BOOT_DRIVER(tegra_hsp) = {
|
|
.name = "tegra-hsp",
|
|
.id = UCLASS_MAILBOX,
|
|
.of_match = tegra_hsp_ids,
|
|
.bind = tegra_hsp_bind,
|
|
.probe = tegra_hsp_probe,
|
|
.priv_auto = sizeof(struct tegra_hsp),
|
|
.ops = &tegra_hsp_mbox_ops,
|
|
};
|