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