xref: /openbmc/u-boot/drivers/mailbox/tegra-hsp.c (revision 135aa950)
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