• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
4  */
5 
6 #include <common.h>
7 #include <clk.h>
8 #include <dm.h>
9 #include <mailbox-uclass.h>
10 #include <asm/io.h>
11 
12 /*
13  * IPCC has one set of registers per CPU
14  * IPCC_PROC_OFFST allows to define cpu registers set base address
15  * according to the assigned proc_id.
16  */
17 
18 #define IPCC_PROC_OFFST		0x010
19 
20 #define IPCC_XSCR		0x008
21 #define IPCC_XTOYSR		0x00c
22 
23 #define IPCC_HWCFGR		0x3f0
24 #define IPCFGR_CHAN_MASK	GENMASK(7, 0)
25 
26 #define RX_BIT_CHAN(chan)	BIT(chan)
27 #define TX_BIT_SHIFT		16
28 #define TX_BIT_CHAN(chan)	BIT(TX_BIT_SHIFT + (chan))
29 
30 #define STM32_MAX_PROCS		2
31 
32 struct stm32_ipcc {
33 	void __iomem *reg_base;
34 	void __iomem *reg_proc;
35 	u32 proc_id;
36 	u32 n_chans;
37 };
38 
stm32_ipcc_request(struct mbox_chan * chan)39 static int stm32_ipcc_request(struct mbox_chan *chan)
40 {
41 	struct stm32_ipcc *ipcc = dev_get_priv(chan->dev);
42 
43 	debug("%s(chan=%p)\n", __func__, chan);
44 
45 	if (chan->id >= ipcc->n_chans) {
46 		debug("%s failed to request channel: %ld\n",
47 		      __func__, chan->id);
48 		return -EINVAL;
49 	}
50 
51 	return 0;
52 }
53 
stm32_ipcc_free(struct mbox_chan * chan)54 static int stm32_ipcc_free(struct mbox_chan *chan)
55 {
56 	debug("%s(chan=%p)\n", __func__, chan);
57 
58 	return 0;
59 }
60 
stm32_ipcc_send(struct mbox_chan * chan,const void * data)61 static int stm32_ipcc_send(struct mbox_chan *chan, const void *data)
62 {
63 	struct stm32_ipcc *ipcc = dev_get_priv(chan->dev);
64 
65 	debug("%s(chan=%p, data=%p)\n", __func__, chan, data);
66 
67 	if (readl(ipcc->reg_proc + IPCC_XTOYSR) & BIT(chan->id))
68 		return -EBUSY;
69 
70 	/* set channel n occupied */
71 	setbits_le32(ipcc->reg_proc + IPCC_XSCR, TX_BIT_CHAN(chan->id));
72 
73 	return 0;
74 }
75 
stm32_ipcc_recv(struct mbox_chan * chan,void * data)76 static int stm32_ipcc_recv(struct mbox_chan *chan, void *data)
77 {
78 	struct stm32_ipcc *ipcc = dev_get_priv(chan->dev);
79 	u32 val;
80 	int proc_offset;
81 
82 	debug("%s(chan=%p, data=%p)\n", __func__, chan, data);
83 
84 	/* read 'channel occupied' status from other proc */
85 	proc_offset = ipcc->proc_id ? -IPCC_PROC_OFFST : IPCC_PROC_OFFST;
86 	val = readl(ipcc->reg_proc + proc_offset + IPCC_XTOYSR);
87 
88 	if (!(val & BIT(chan->id)))
89 		return -ENODATA;
90 
91 	setbits_le32(ipcc->reg_proc + IPCC_XSCR, RX_BIT_CHAN(chan->id));
92 
93 	return 0;
94 }
95 
stm32_ipcc_probe(struct udevice * dev)96 static int stm32_ipcc_probe(struct udevice *dev)
97 {
98 	struct stm32_ipcc *ipcc = dev_get_priv(dev);
99 	fdt_addr_t addr;
100 	const fdt32_t *cell;
101 	struct clk clk;
102 	int len, ret;
103 
104 	debug("%s(dev=%p)\n", __func__, dev);
105 
106 	addr = dev_read_addr(dev);
107 	if (addr == FDT_ADDR_T_NONE)
108 		return -EINVAL;
109 
110 	ipcc->reg_base = (void __iomem *)addr;
111 
112 	/* proc_id */
113 	cell = dev_read_prop(dev, "st,proc_id", &len);
114 	if (len < sizeof(fdt32_t)) {
115 		dev_dbg(dev, "Missing st,proc_id\n");
116 		return -EINVAL;
117 	}
118 
119 	ipcc->proc_id = fdtdec_get_number(cell, 1);
120 
121 	if (ipcc->proc_id >= STM32_MAX_PROCS) {
122 		dev_err(dev, "Invalid proc_id (%d)\n", ipcc->proc_id);
123 		return -EINVAL;
124 	}
125 
126 	ipcc->reg_proc = ipcc->reg_base + ipcc->proc_id * IPCC_PROC_OFFST;
127 
128 	ret = clk_get_by_index(dev, 0, &clk);
129 	if (ret)
130 		return ret;
131 
132 	ret = clk_enable(&clk);
133 	if (ret)
134 		goto clk_free;
135 
136 	/* get channel number */
137 	ipcc->n_chans = readl(ipcc->reg_base + IPCC_HWCFGR);
138 	ipcc->n_chans &= IPCFGR_CHAN_MASK;
139 
140 	return 0;
141 
142 clk_free:
143 	clk_free(&clk);
144 
145 	return ret;
146 }
147 
148 static const struct udevice_id stm32_ipcc_ids[] = {
149 	{ .compatible = "st,stm32mp1-ipcc" },
150 	{ }
151 };
152 
153 struct mbox_ops stm32_ipcc_mbox_ops = {
154 	.request = stm32_ipcc_request,
155 	.free = stm32_ipcc_free,
156 	.send = stm32_ipcc_send,
157 	.recv = stm32_ipcc_recv,
158 };
159 
160 U_BOOT_DRIVER(stm32_ipcc) = {
161 	.name = "stm32_ipcc",
162 	.id = UCLASS_MAILBOX,
163 	.of_match = stm32_ipcc_ids,
164 	.probe = stm32_ipcc_probe,
165 	.priv_auto_alloc_size = sizeof(struct stm32_ipcc),
166 	.ops = &stm32_ipcc_mbox_ops,
167 };
168