blob: c3df9678a7472fb516249712f7cf79ad5465a67b [file] [log] [blame]
Fabien Dessenneac0da892019-05-14 11:20:34 +02001// 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
32struct stm32_ipcc {
33 void __iomem *reg_base;
34 void __iomem *reg_proc;
35 u32 proc_id;
36 u32 n_chans;
37};
38
39static 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
54static int stm32_ipcc_free(struct mbox_chan *chan)
55{
56 debug("%s(chan=%p)\n", __func__, chan);
57
58 return 0;
59}
60
61static 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
76static 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
96static 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
142clk_free:
143 clk_free(&clk);
144
145 return ret;
146}
147
148static const struct udevice_id stm32_ipcc_ids[] = {
149 { .compatible = "st,stm32mp1-ipcc" },
150 { }
151};
152
153struct 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
160U_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};