1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (c) 2016, NVIDIA CORPORATION. 4 */ 5 6#include <log.h> 7#include <malloc.h> 8#include <asm/io.h> 9#include <dm.h> 10#include <mailbox-uclass.h> 11#include <dt-bindings/mailbox/tegra186-hsp.h> 12#include <linux/bitops.h> 13 14#define TEGRA_HSP_INT_DIMENSIONING 0x380 15#define TEGRA_HSP_INT_DIMENSIONING_NSI_SHIFT 16 16#define TEGRA_HSP_INT_DIMENSIONING_NSI_MASK 0xf 17#define TEGRA_HSP_INT_DIMENSIONING_NDB_SHIFT 12 18#define TEGRA_HSP_INT_DIMENSIONING_NDB_MASK 0xf 19#define TEGRA_HSP_INT_DIMENSIONING_NAS_SHIFT 8 20#define TEGRA_HSP_INT_DIMENSIONING_NAS_MASK 0xf 21#define TEGRA_HSP_INT_DIMENSIONING_NSS_SHIFT 4 22#define TEGRA_HSP_INT_DIMENSIONING_NSS_MASK 0xf 23#define TEGRA_HSP_INT_DIMENSIONING_NSM_SHIFT 0 24#define TEGRA_HSP_INT_DIMENSIONING_NSM_MASK 0xf 25 26#define TEGRA_HSP_DB_REG_TRIGGER 0x0 27#define TEGRA_HSP_DB_REG_ENABLE 0x4 28#define TEGRA_HSP_DB_REG_RAW 0x8 29#define TEGRA_HSP_DB_REG_PENDING 0xc 30 31#define TEGRA_HSP_DB_ID_CCPLEX 1 32#define TEGRA_HSP_DB_ID_BPMP 3 33#define TEGRA_HSP_DB_ID_NUM 7 34 35struct tegra_hsp { 36 fdt_addr_t regs; 37 uint32_t db_base; 38}; 39 40static uint32_t *tegra_hsp_reg(struct tegra_hsp *thsp, uint32_t db_id, 41 uint32_t reg) 42{ 43 return (uint32_t *)(thsp->regs + thsp->db_base + (db_id * 0x100) + reg); 44} 45 46static uint32_t tegra_hsp_readl(struct tegra_hsp *thsp, uint32_t db_id, 47 uint32_t reg) 48{ 49 uint32_t *r = tegra_hsp_reg(thsp, db_id, reg); 50 return readl(r); 51} 52 53static void tegra_hsp_writel(struct tegra_hsp *thsp, uint32_t val, 54 uint32_t db_id, uint32_t reg) 55{ 56 uint32_t *r = tegra_hsp_reg(thsp, db_id, reg); 57 58 writel(val, r); 59 readl(r); 60} 61 62static int tegra_hsp_db_id(ulong chan_id) 63{ 64 switch (chan_id) { 65 case (HSP_MBOX_TYPE_DB << 16) | HSP_DB_MASTER_BPMP: 66 return TEGRA_HSP_DB_ID_BPMP; 67 default: 68 debug("Invalid channel ID\n"); 69 return -EINVAL; 70 } 71} 72 73static int tegra_hsp_of_xlate(struct mbox_chan *chan, 74 struct ofnode_phandle_args *args) 75{ 76 debug("%s(chan=%p)\n", __func__, chan); 77 78 if (args->args_count != 2) { 79 debug("Invalid args_count: %d\n", args->args_count); 80 return -EINVAL; 81 } 82 83 chan->id = (args->args[0] << 16) | args->args[1]; 84 85 return 0; 86} 87 88static int tegra_hsp_request(struct mbox_chan *chan) 89{ 90 int db_id; 91 92 debug("%s(chan=%p)\n", __func__, chan); 93 94 db_id = tegra_hsp_db_id(chan->id); 95 if (db_id < 0) { 96 debug("tegra_hsp_db_id() failed: %d\n", db_id); 97 return -EINVAL; 98 } 99 100 return 0; 101} 102 103static int tegra_hsp_free(struct mbox_chan *chan) 104{ 105 debug("%s(chan=%p)\n", __func__, chan); 106 107 return 0; 108} 109 110static int tegra_hsp_send(struct mbox_chan *chan, const void *data) 111{ 112 struct tegra_hsp *thsp = dev_get_priv(chan->dev); 113 int db_id; 114 115 debug("%s(chan=%p, data=%p)\n", __func__, chan, data); 116 117 db_id = tegra_hsp_db_id(chan->id); 118 tegra_hsp_writel(thsp, 1, db_id, TEGRA_HSP_DB_REG_TRIGGER); 119 120 return 0; 121} 122 123static int tegra_hsp_recv(struct mbox_chan *chan, void *data) 124{ 125 struct tegra_hsp *thsp = dev_get_priv(chan->dev); 126 uint32_t db_id = TEGRA_HSP_DB_ID_CCPLEX; 127 uint32_t val; 128 129 debug("%s(chan=%p, data=%p)\n", __func__, chan, data); 130 131 val = tegra_hsp_readl(thsp, db_id, TEGRA_HSP_DB_REG_RAW); 132 if (!(val & BIT(chan->id))) 133 return -ENODATA; 134 135 tegra_hsp_writel(thsp, BIT(chan->id), db_id, TEGRA_HSP_DB_REG_RAW); 136 137 return 0; 138} 139 140static int tegra_hsp_bind(struct udevice *dev) 141{ 142 debug("%s(dev=%p)\n", __func__, dev); 143 144 return 0; 145} 146 147static int tegra_hsp_probe(struct udevice *dev) 148{ 149 struct tegra_hsp *thsp = dev_get_priv(dev); 150 u32 val; 151 int nr_sm, nr_ss, nr_as; 152 153 debug("%s(dev=%p)\n", __func__, dev); 154 155 thsp->regs = dev_read_addr(dev); 156 if (thsp->regs == FDT_ADDR_T_NONE) 157 return -ENODEV; 158 159 val = readl(thsp->regs + TEGRA_HSP_INT_DIMENSIONING); 160 nr_sm = (val >> TEGRA_HSP_INT_DIMENSIONING_NSM_SHIFT) & 161 TEGRA_HSP_INT_DIMENSIONING_NSM_MASK; 162 nr_ss = (val >> TEGRA_HSP_INT_DIMENSIONING_NSS_SHIFT) & 163 TEGRA_HSP_INT_DIMENSIONING_NSS_MASK; 164 nr_as = (val >> TEGRA_HSP_INT_DIMENSIONING_NAS_SHIFT) & 165 TEGRA_HSP_INT_DIMENSIONING_NAS_MASK; 166 167 thsp->db_base = (1 + (nr_sm >> 1) + nr_ss + nr_as) << 16; 168 169 return 0; 170} 171 172static const struct udevice_id tegra_hsp_ids[] = { 173 { .compatible = "nvidia,tegra186-hsp" }, 174 { } 175}; 176 177struct mbox_ops tegra_hsp_mbox_ops = { 178 .of_xlate = tegra_hsp_of_xlate, 179 .request = tegra_hsp_request, 180 .rfree = tegra_hsp_free, 181 .send = tegra_hsp_send, 182 .recv = tegra_hsp_recv, 183}; 184 185U_BOOT_DRIVER(tegra_hsp) = { 186 .name = "tegra-hsp", 187 .id = UCLASS_MAILBOX, 188 .of_match = tegra_hsp_ids, 189 .bind = tegra_hsp_bind, 190 .probe = tegra_hsp_probe, 191 .priv_auto = sizeof(struct tegra_hsp), 192 .ops = &tegra_hsp_mbox_ops, 193}; 194