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/tegra-hsp.h> 12 13 #define TEGRA_HSP_DB_REG_TRIGGER 0x0 14 #define TEGRA_HSP_DB_REG_ENABLE 0x4 15 #define TEGRA_HSP_DB_REG_RAW 0x8 16 #define TEGRA_HSP_DB_REG_PENDING 0xc 17 18 #define TEGRA_HSP_DB_ID_CCPLEX 1 19 #define TEGRA_HSP_DB_ID_BPMP 3 20 #define TEGRA_HSP_DB_ID_NUM 7 21 22 struct tegra_hsp { 23 fdt_addr_t regs; 24 uint32_t db_base; 25 }; 26 27 DECLARE_GLOBAL_DATA_PTR; 28 29 static uint32_t *tegra_hsp_reg(struct tegra_hsp *thsp, uint32_t db_id, 30 uint32_t reg) 31 { 32 return (uint32_t *)(thsp->regs + thsp->db_base + (db_id * 0x100) + reg); 33 } 34 35 static uint32_t tegra_hsp_readl(struct tegra_hsp *thsp, uint32_t db_id, 36 uint32_t reg) 37 { 38 uint32_t *r = tegra_hsp_reg(thsp, db_id, reg); 39 return readl(r); 40 } 41 42 static void tegra_hsp_writel(struct tegra_hsp *thsp, uint32_t val, 43 uint32_t db_id, uint32_t reg) 44 { 45 uint32_t *r = tegra_hsp_reg(thsp, db_id, reg); 46 47 writel(val, r); 48 readl(r); 49 } 50 51 static int tegra_hsp_db_id(ulong chan_id) 52 { 53 switch (chan_id) { 54 case TEGRA_HSP_MASTER_BPMP: 55 return TEGRA_HSP_DB_ID_BPMP; 56 default: 57 debug("Invalid channel ID\n"); 58 return -EINVAL; 59 } 60 } 61 62 static int tegra_hsp_request(struct mbox_chan *chan) 63 { 64 int db_id; 65 66 debug("%s(chan=%p)\n", __func__, chan); 67 68 db_id = tegra_hsp_db_id(chan->id); 69 if (db_id < 0) { 70 debug("tegra_hsp_db_id() failed: %d\n", db_id); 71 return -EINVAL; 72 } 73 74 return 0; 75 } 76 77 static int tegra_hsp_free(struct mbox_chan *chan) 78 { 79 debug("%s(chan=%p)\n", __func__, chan); 80 81 return 0; 82 } 83 84 static int tegra_hsp_send(struct mbox_chan *chan, const void *data) 85 { 86 struct tegra_hsp *thsp = dev_get_priv(chan->dev); 87 int db_id; 88 89 debug("%s(chan=%p, data=%p)\n", __func__, chan, data); 90 91 db_id = tegra_hsp_db_id(chan->id); 92 tegra_hsp_writel(thsp, 1, db_id, TEGRA_HSP_DB_REG_TRIGGER); 93 94 return 0; 95 } 96 97 static int tegra_hsp_recv(struct mbox_chan *chan, void *data) 98 { 99 struct tegra_hsp *thsp = dev_get_priv(chan->dev); 100 uint32_t db_id = TEGRA_HSP_DB_ID_CCPLEX; 101 uint32_t val; 102 103 debug("%s(chan=%p, data=%p)\n", __func__, chan, data); 104 105 val = tegra_hsp_readl(thsp, db_id, TEGRA_HSP_DB_REG_RAW); 106 if (!(val & BIT(chan->id))) 107 return -ENODATA; 108 109 tegra_hsp_writel(thsp, BIT(chan->id), db_id, TEGRA_HSP_DB_REG_RAW); 110 111 return 0; 112 } 113 114 static int tegra_hsp_bind(struct udevice *dev) 115 { 116 debug("%s(dev=%p)\n", __func__, dev); 117 118 return 0; 119 } 120 121 static int tegra_hsp_probe(struct udevice *dev) 122 { 123 struct tegra_hsp *thsp = dev_get_priv(dev); 124 int nr_sm, nr_ss, nr_as; 125 126 debug("%s(dev=%p)\n", __func__, dev); 127 128 thsp->regs = dev_get_addr(dev); 129 if (thsp->regs == FDT_ADDR_T_NONE) 130 return -ENODEV; 131 132 nr_sm = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "nvidia,num-SM", 133 0); 134 nr_ss = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "nvidia,num-SS", 135 0); 136 nr_as = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "nvidia,num-AS", 137 0); 138 thsp->db_base = (1 + (nr_sm >> 1) + nr_ss + nr_as) << 16; 139 140 return 0; 141 } 142 143 static const struct udevice_id tegra_hsp_ids[] = { 144 { .compatible = "nvidia,tegra186-hsp" }, 145 { } 146 }; 147 148 struct mbox_ops tegra_hsp_mbox_ops = { 149 .request = tegra_hsp_request, 150 .free = tegra_hsp_free, 151 .send = tegra_hsp_send, 152 .recv = tegra_hsp_recv, 153 }; 154 155 U_BOOT_DRIVER(tegra_hsp) = { 156 .name = "tegra-hsp", 157 .id = UCLASS_MAILBOX, 158 .of_match = tegra_hsp_ids, 159 .bind = tegra_hsp_bind, 160 .probe = tegra_hsp_probe, 161 .priv_auto_alloc_size = sizeof(struct tegra_hsp), 162 .ops = &tegra_hsp_mbox_ops, 163 }; 164