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