diff options
Diffstat (limited to 'roms/u-boot/drivers/mailbox/tegra-hsp.c')
-rw-r--r-- | roms/u-boot/drivers/mailbox/tegra-hsp.c | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/mailbox/tegra-hsp.c b/roms/u-boot/drivers/mailbox/tegra-hsp.c new file mode 100644 index 000000000..1d66d95fe --- /dev/null +++ b/roms/u-boot/drivers/mailbox/tegra-hsp.c @@ -0,0 +1,194 @@ +// 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, +}; |