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