Merge tag 'u-boot-stm32-20190712' of https://gitlab.denx.de/u-boot/custodians/u-boot-stm
[oweals/u-boot.git] / drivers / mailbox / stm32-ipcc.c
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
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
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
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
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
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 };