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 DECLARE_GLOBAL_DATA_PTR; 40 41 static uint32_t *tegra_hsp_reg(struct tegra_hsp *thsp, uint32_t db_id, 42 uint32_t reg) 43 { 44 return (uint32_t *)(thsp->regs + thsp->db_base + (db_id * 0x100) + reg); 45 } 46 47 static uint32_t tegra_hsp_readl(struct tegra_hsp *thsp, uint32_t db_id, 48 uint32_t reg) 49 { 50 uint32_t *r = tegra_hsp_reg(thsp, db_id, reg); 51 return readl(r); 52 } 53 54 static void tegra_hsp_writel(struct tegra_hsp *thsp, uint32_t val, 55 uint32_t db_id, uint32_t reg) 56 { 57 uint32_t *r = tegra_hsp_reg(thsp, db_id, reg); 58 59 writel(val, r); 60 readl(r); 61 } 62 63 static int tegra_hsp_db_id(ulong chan_id) 64 { 65 switch (chan_id) { 66 case (HSP_MBOX_TYPE_DB << 16) | HSP_DB_MASTER_BPMP: 67 return TEGRA_HSP_DB_ID_BPMP; 68 default: 69 debug("Invalid channel ID\n"); 70 return -EINVAL; 71 } 72 } 73 74 static int tegra_hsp_of_xlate(struct mbox_chan *chan, 75 struct fdtdec_phandle_args *args) 76 { 77 debug("%s(chan=%p)\n", __func__, chan); 78 79 if (args->args_count != 2) { 80 debug("Invaild args_count: %d\n", args->args_count); 81 return -EINVAL; 82 } 83 84 chan->id = (args->args[0] << 16) | args->args[1]; 85 86 return 0; 87 } 88 89 static int tegra_hsp_request(struct mbox_chan *chan) 90 { 91 int db_id; 92 93 debug("%s(chan=%p)\n", __func__, chan); 94 95 db_id = tegra_hsp_db_id(chan->id); 96 if (db_id < 0) { 97 debug("tegra_hsp_db_id() failed: %d\n", db_id); 98 return -EINVAL; 99 } 100 101 return 0; 102 } 103 104 static int tegra_hsp_free(struct mbox_chan *chan) 105 { 106 debug("%s(chan=%p)\n", __func__, chan); 107 108 return 0; 109 } 110 111 static int tegra_hsp_send(struct mbox_chan *chan, const void *data) 112 { 113 struct tegra_hsp *thsp = dev_get_priv(chan->dev); 114 int db_id; 115 116 debug("%s(chan=%p, data=%p)\n", __func__, chan, data); 117 118 db_id = tegra_hsp_db_id(chan->id); 119 tegra_hsp_writel(thsp, 1, db_id, TEGRA_HSP_DB_REG_TRIGGER); 120 121 return 0; 122 } 123 124 static int tegra_hsp_recv(struct mbox_chan *chan, void *data) 125 { 126 struct tegra_hsp *thsp = dev_get_priv(chan->dev); 127 uint32_t db_id = TEGRA_HSP_DB_ID_CCPLEX; 128 uint32_t val; 129 130 debug("%s(chan=%p, data=%p)\n", __func__, chan, data); 131 132 val = tegra_hsp_readl(thsp, db_id, TEGRA_HSP_DB_REG_RAW); 133 if (!(val & BIT(chan->id))) 134 return -ENODATA; 135 136 tegra_hsp_writel(thsp, BIT(chan->id), db_id, TEGRA_HSP_DB_REG_RAW); 137 138 return 0; 139 } 140 141 static int tegra_hsp_bind(struct udevice *dev) 142 { 143 debug("%s(dev=%p)\n", __func__, dev); 144 145 return 0; 146 } 147 148 static int tegra_hsp_probe(struct udevice *dev) 149 { 150 struct tegra_hsp *thsp = dev_get_priv(dev); 151 u32 val; 152 int nr_sm, nr_ss, nr_as; 153 154 debug("%s(dev=%p)\n", __func__, dev); 155 156 thsp->regs = dev_get_addr(dev); 157 if (thsp->regs == FDT_ADDR_T_NONE) 158 return -ENODEV; 159 160 val = readl(thsp->regs + TEGRA_HSP_INT_DIMENSIONING); 161 nr_sm = (val >> TEGRA_HSP_INT_DIMENSIONING_NSM_SHIFT) & 162 TEGRA_HSP_INT_DIMENSIONING_NSM_MASK; 163 nr_ss = (val >> TEGRA_HSP_INT_DIMENSIONING_NSS_SHIFT) & 164 TEGRA_HSP_INT_DIMENSIONING_NSS_MASK; 165 nr_as = (val >> TEGRA_HSP_INT_DIMENSIONING_NAS_SHIFT) & 166 TEGRA_HSP_INT_DIMENSIONING_NAS_MASK; 167 168 thsp->db_base = (1 + (nr_sm >> 1) + nr_ss + nr_as) << 16; 169 170 return 0; 171 } 172 173 static const struct udevice_id tegra_hsp_ids[] = { 174 { .compatible = "nvidia,tegra186-hsp" }, 175 { } 176 }; 177 178 struct mbox_ops tegra_hsp_mbox_ops = { 179 .of_xlate = tegra_hsp_of_xlate, 180 .request = tegra_hsp_request, 181 .free = tegra_hsp_free, 182 .send = tegra_hsp_send, 183 .recv = tegra_hsp_recv, 184 }; 185 186 U_BOOT_DRIVER(tegra_hsp) = { 187 .name = "tegra-hsp", 188 .id = UCLASS_MAILBOX, 189 .of_match = tegra_hsp_ids, 190 .bind = tegra_hsp_bind, 191 .probe = tegra_hsp_probe, 192 .priv_auto_alloc_size = sizeof(struct tegra_hsp), 193 .ops = &tegra_hsp_mbox_ops, 194 }; 195