1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
|
/*
* Copyright (c) 2016, NVIDIA CORPORATION.
*
* SPDX-License-Identifier: GPL-2.0
*/
#include <common.h>
#include <asm/io.h>
#include <dm.h>
#include <mailbox-uclass.h>
#include <dt-bindings/mailbox/tegra186-hsp.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;
};
DECLARE_GLOBAL_DATA_PTR;
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 fdtdec_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_get_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,
.free = 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_alloc_size = sizeof(struct tegra_hsp),
.ops = &tegra_hsp_mbox_ops,
};
|