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