10f67e239SStephen Warren /* 20f67e239SStephen Warren * Copyright (c) 2016, NVIDIA CORPORATION. 30f67e239SStephen Warren * 40f67e239SStephen Warren * SPDX-License-Identifier: GPL-2.0 50f67e239SStephen Warren */ 60f67e239SStephen Warren 70f67e239SStephen Warren #include <common.h> 80f67e239SStephen Warren #include <asm/io.h> 90f67e239SStephen Warren #include <dm.h> 100f67e239SStephen Warren #include <mailbox-uclass.h> 11*729c2db7SStephen Warren #include <dt-bindings/mailbox/tegra186-hsp.h> 12*729c2db7SStephen Warren 13*729c2db7SStephen Warren #define TEGRA_HSP_INT_DIMENSIONING 0x380 14*729c2db7SStephen Warren #define TEGRA_HSP_INT_DIMENSIONING_NSI_SHIFT 16 15*729c2db7SStephen Warren #define TEGRA_HSP_INT_DIMENSIONING_NSI_MASK 0xf 16*729c2db7SStephen Warren #define TEGRA_HSP_INT_DIMENSIONING_NDB_SHIFT 12 17*729c2db7SStephen Warren #define TEGRA_HSP_INT_DIMENSIONING_NDB_MASK 0xf 18*729c2db7SStephen Warren #define TEGRA_HSP_INT_DIMENSIONING_NAS_SHIFT 8 19*729c2db7SStephen Warren #define TEGRA_HSP_INT_DIMENSIONING_NAS_MASK 0xf 20*729c2db7SStephen Warren #define TEGRA_HSP_INT_DIMENSIONING_NSS_SHIFT 4 21*729c2db7SStephen Warren #define TEGRA_HSP_INT_DIMENSIONING_NSS_MASK 0xf 22*729c2db7SStephen Warren #define TEGRA_HSP_INT_DIMENSIONING_NSM_SHIFT 0 23*729c2db7SStephen Warren #define TEGRA_HSP_INT_DIMENSIONING_NSM_MASK 0xf 240f67e239SStephen Warren 250f67e239SStephen Warren #define TEGRA_HSP_DB_REG_TRIGGER 0x0 260f67e239SStephen Warren #define TEGRA_HSP_DB_REG_ENABLE 0x4 270f67e239SStephen Warren #define TEGRA_HSP_DB_REG_RAW 0x8 280f67e239SStephen Warren #define TEGRA_HSP_DB_REG_PENDING 0xc 290f67e239SStephen Warren 300f67e239SStephen Warren #define TEGRA_HSP_DB_ID_CCPLEX 1 310f67e239SStephen Warren #define TEGRA_HSP_DB_ID_BPMP 3 320f67e239SStephen Warren #define TEGRA_HSP_DB_ID_NUM 7 330f67e239SStephen Warren 340f67e239SStephen Warren struct tegra_hsp { 350f67e239SStephen Warren fdt_addr_t regs; 360f67e239SStephen Warren uint32_t db_base; 370f67e239SStephen Warren }; 380f67e239SStephen Warren 390f67e239SStephen Warren DECLARE_GLOBAL_DATA_PTR; 400f67e239SStephen Warren 410f67e239SStephen Warren static uint32_t *tegra_hsp_reg(struct tegra_hsp *thsp, uint32_t db_id, 420f67e239SStephen Warren uint32_t reg) 430f67e239SStephen Warren { 440f67e239SStephen Warren return (uint32_t *)(thsp->regs + thsp->db_base + (db_id * 0x100) + reg); 450f67e239SStephen Warren } 460f67e239SStephen Warren 470f67e239SStephen Warren static uint32_t tegra_hsp_readl(struct tegra_hsp *thsp, uint32_t db_id, 480f67e239SStephen Warren uint32_t reg) 490f67e239SStephen Warren { 500f67e239SStephen Warren uint32_t *r = tegra_hsp_reg(thsp, db_id, reg); 510f67e239SStephen Warren return readl(r); 520f67e239SStephen Warren } 530f67e239SStephen Warren 540f67e239SStephen Warren static void tegra_hsp_writel(struct tegra_hsp *thsp, uint32_t val, 550f67e239SStephen Warren uint32_t db_id, uint32_t reg) 560f67e239SStephen Warren { 570f67e239SStephen Warren uint32_t *r = tegra_hsp_reg(thsp, db_id, reg); 580f67e239SStephen Warren 590f67e239SStephen Warren writel(val, r); 600f67e239SStephen Warren readl(r); 610f67e239SStephen Warren } 620f67e239SStephen Warren 630f67e239SStephen Warren static int tegra_hsp_db_id(ulong chan_id) 640f67e239SStephen Warren { 650f67e239SStephen Warren switch (chan_id) { 66*729c2db7SStephen Warren case (HSP_MBOX_TYPE_DB << 16) | HSP_DB_MASTER_BPMP: 670f67e239SStephen Warren return TEGRA_HSP_DB_ID_BPMP; 680f67e239SStephen Warren default: 690f67e239SStephen Warren debug("Invalid channel ID\n"); 700f67e239SStephen Warren return -EINVAL; 710f67e239SStephen Warren } 720f67e239SStephen Warren } 730f67e239SStephen Warren 74*729c2db7SStephen Warren static int tegra_hsp_of_xlate(struct mbox_chan *chan, 75*729c2db7SStephen Warren struct fdtdec_phandle_args *args) 76*729c2db7SStephen Warren { 77*729c2db7SStephen Warren debug("%s(chan=%p)\n", __func__, chan); 78*729c2db7SStephen Warren 79*729c2db7SStephen Warren if (args->args_count != 2) { 80*729c2db7SStephen Warren debug("Invaild args_count: %d\n", args->args_count); 81*729c2db7SStephen Warren return -EINVAL; 82*729c2db7SStephen Warren } 83*729c2db7SStephen Warren 84*729c2db7SStephen Warren chan->id = (args->args[0] << 16) | args->args[1]; 85*729c2db7SStephen Warren 86*729c2db7SStephen Warren return 0; 87*729c2db7SStephen Warren } 88*729c2db7SStephen Warren 890f67e239SStephen Warren static int tegra_hsp_request(struct mbox_chan *chan) 900f67e239SStephen Warren { 910f67e239SStephen Warren int db_id; 920f67e239SStephen Warren 930f67e239SStephen Warren debug("%s(chan=%p)\n", __func__, chan); 940f67e239SStephen Warren 950f67e239SStephen Warren db_id = tegra_hsp_db_id(chan->id); 960f67e239SStephen Warren if (db_id < 0) { 970f67e239SStephen Warren debug("tegra_hsp_db_id() failed: %d\n", db_id); 980f67e239SStephen Warren return -EINVAL; 990f67e239SStephen Warren } 1000f67e239SStephen Warren 1010f67e239SStephen Warren return 0; 1020f67e239SStephen Warren } 1030f67e239SStephen Warren 1040f67e239SStephen Warren static int tegra_hsp_free(struct mbox_chan *chan) 1050f67e239SStephen Warren { 1060f67e239SStephen Warren debug("%s(chan=%p)\n", __func__, chan); 1070f67e239SStephen Warren 1080f67e239SStephen Warren return 0; 1090f67e239SStephen Warren } 1100f67e239SStephen Warren 1110f67e239SStephen Warren static int tegra_hsp_send(struct mbox_chan *chan, const void *data) 1120f67e239SStephen Warren { 1130f67e239SStephen Warren struct tegra_hsp *thsp = dev_get_priv(chan->dev); 1140f67e239SStephen Warren int db_id; 1150f67e239SStephen Warren 1160f67e239SStephen Warren debug("%s(chan=%p, data=%p)\n", __func__, chan, data); 1170f67e239SStephen Warren 1180f67e239SStephen Warren db_id = tegra_hsp_db_id(chan->id); 1190f67e239SStephen Warren tegra_hsp_writel(thsp, 1, db_id, TEGRA_HSP_DB_REG_TRIGGER); 1200f67e239SStephen Warren 1210f67e239SStephen Warren return 0; 1220f67e239SStephen Warren } 1230f67e239SStephen Warren 1240f67e239SStephen Warren static int tegra_hsp_recv(struct mbox_chan *chan, void *data) 1250f67e239SStephen Warren { 1260f67e239SStephen Warren struct tegra_hsp *thsp = dev_get_priv(chan->dev); 1270f67e239SStephen Warren uint32_t db_id = TEGRA_HSP_DB_ID_CCPLEX; 1280f67e239SStephen Warren uint32_t val; 1290f67e239SStephen Warren 1300f67e239SStephen Warren debug("%s(chan=%p, data=%p)\n", __func__, chan, data); 1310f67e239SStephen Warren 1320f67e239SStephen Warren val = tegra_hsp_readl(thsp, db_id, TEGRA_HSP_DB_REG_RAW); 1330f67e239SStephen Warren if (!(val & BIT(chan->id))) 1340f67e239SStephen Warren return -ENODATA; 1350f67e239SStephen Warren 1360f67e239SStephen Warren tegra_hsp_writel(thsp, BIT(chan->id), db_id, TEGRA_HSP_DB_REG_RAW); 1370f67e239SStephen Warren 1380f67e239SStephen Warren return 0; 1390f67e239SStephen Warren } 1400f67e239SStephen Warren 1410f67e239SStephen Warren static int tegra_hsp_bind(struct udevice *dev) 1420f67e239SStephen Warren { 1430f67e239SStephen Warren debug("%s(dev=%p)\n", __func__, dev); 1440f67e239SStephen Warren 1450f67e239SStephen Warren return 0; 1460f67e239SStephen Warren } 1470f67e239SStephen Warren 1480f67e239SStephen Warren static int tegra_hsp_probe(struct udevice *dev) 1490f67e239SStephen Warren { 1500f67e239SStephen Warren struct tegra_hsp *thsp = dev_get_priv(dev); 151*729c2db7SStephen Warren u32 val; 1520f67e239SStephen Warren int nr_sm, nr_ss, nr_as; 1530f67e239SStephen Warren 1540f67e239SStephen Warren debug("%s(dev=%p)\n", __func__, dev); 1550f67e239SStephen Warren 1560f67e239SStephen Warren thsp->regs = dev_get_addr(dev); 1570f67e239SStephen Warren if (thsp->regs == FDT_ADDR_T_NONE) 1580f67e239SStephen Warren return -ENODEV; 1590f67e239SStephen Warren 160*729c2db7SStephen Warren val = readl(thsp->regs + TEGRA_HSP_INT_DIMENSIONING); 161*729c2db7SStephen Warren nr_sm = (val >> TEGRA_HSP_INT_DIMENSIONING_NSM_SHIFT) & 162*729c2db7SStephen Warren TEGRA_HSP_INT_DIMENSIONING_NSM_MASK; 163*729c2db7SStephen Warren nr_ss = (val >> TEGRA_HSP_INT_DIMENSIONING_NSS_SHIFT) & 164*729c2db7SStephen Warren TEGRA_HSP_INT_DIMENSIONING_NSS_MASK; 165*729c2db7SStephen Warren nr_as = (val >> TEGRA_HSP_INT_DIMENSIONING_NAS_SHIFT) & 166*729c2db7SStephen Warren TEGRA_HSP_INT_DIMENSIONING_NAS_MASK; 167*729c2db7SStephen Warren 1680f67e239SStephen Warren thsp->db_base = (1 + (nr_sm >> 1) + nr_ss + nr_as) << 16; 1690f67e239SStephen Warren 1700f67e239SStephen Warren return 0; 1710f67e239SStephen Warren } 1720f67e239SStephen Warren 1730f67e239SStephen Warren static const struct udevice_id tegra_hsp_ids[] = { 1740f67e239SStephen Warren { .compatible = "nvidia,tegra186-hsp" }, 1750f67e239SStephen Warren { } 1760f67e239SStephen Warren }; 1770f67e239SStephen Warren 1780f67e239SStephen Warren struct mbox_ops tegra_hsp_mbox_ops = { 179*729c2db7SStephen Warren .of_xlate = tegra_hsp_of_xlate, 1800f67e239SStephen Warren .request = tegra_hsp_request, 1810f67e239SStephen Warren .free = tegra_hsp_free, 1820f67e239SStephen Warren .send = tegra_hsp_send, 1830f67e239SStephen Warren .recv = tegra_hsp_recv, 1840f67e239SStephen Warren }; 1850f67e239SStephen Warren 1860f67e239SStephen Warren U_BOOT_DRIVER(tegra_hsp) = { 1870f67e239SStephen Warren .name = "tegra-hsp", 1880f67e239SStephen Warren .id = UCLASS_MAILBOX, 1890f67e239SStephen Warren .of_match = tegra_hsp_ids, 1900f67e239SStephen Warren .bind = tegra_hsp_bind, 1910f67e239SStephen Warren .probe = tegra_hsp_probe, 1920f67e239SStephen Warren .priv_auto_alloc_size = sizeof(struct tegra_hsp), 1930f67e239SStephen Warren .ops = &tegra_hsp_mbox_ops, 1940f67e239SStephen Warren }; 195