xref: /rk3399_rockchip-uboot/drivers/mailbox/tegra-hsp.c (revision 0f67e2395be44db2c1bef17b6ada2e46221908ed)
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