blob: cdb85b999db522f71a8693ae01543b578e514d5d [file] [log] [blame]
Ye Li0db17f42021-08-07 16:00:41 +08001// SPDX-License-Identifier: GPL-2.0
2/*
Ye Lic408ed32022-07-26 16:40:49 +08003 * Copyright 2020-2022 NXP
Ye Li0db17f42021-08-07 16:00:41 +08004 */
5
Ye Li0db17f42021-08-07 16:00:41 +08006#include <asm/io.h>
7#include <dm.h>
8#include <dm/lists.h>
9#include <dm/root.h>
10#include <dm/device-internal.h>
Peng Fand5c31832023-06-15 18:09:05 +080011#include <asm/mach-imx/ele_api.h>
Peng Fanf6928f92021-08-07 16:01:09 +080012#include <asm/arch/imx-regs.h>
Ye Li0db17f42021-08-07 16:00:41 +080013#include <linux/iopoll.h>
14#include <misc.h>
15
16DECLARE_GLOBAL_DATA_PTR;
17
Ye Li0db17f42021-08-07 16:00:41 +080018struct imx8ulp_mu {
19 struct mu_type *base;
20};
21
22#define MU_SR_TE0_MASK BIT(0)
23#define MU_SR_RF0_MASK BIT(0)
Ye Li0db17f42021-08-07 16:00:41 +080024
Ye Li853cc9d2021-08-07 16:00:55 +080025void mu_hal_init(ulong base)
Ye Li0db17f42021-08-07 16:00:41 +080026{
Ye Li853cc9d2021-08-07 16:00:55 +080027 struct mu_type *mu_base = (struct mu_type *)base;
Peng Fan25a3fc32024-10-06 08:22:51 +080028 u32 rr_num = (readl(&mu_base->par) & 0xFF00) >> 8;
29 int i;
Ye Li853cc9d2021-08-07 16:00:55 +080030
31 writel(0, &mu_base->tcr);
32 writel(0, &mu_base->rcr);
Peng Fan25a3fc32024-10-06 08:22:51 +080033
34 while (true) {
35 /* If there is pending RX data, clear them by read them out */
36 if (!(readl(&mu_base->sr) & BIT(6)))
37 return;
38
39 for (i = 0; i < rr_num; i++)
40 readl(&mu_base->rr[i]);
41 }
Ye Li0db17f42021-08-07 16:00:41 +080042}
43
Ye Li853cc9d2021-08-07 16:00:55 +080044int mu_hal_sendmsg(ulong base, u32 reg_index, u32 msg)
Ye Li0db17f42021-08-07 16:00:41 +080045{
Ye Li853cc9d2021-08-07 16:00:55 +080046 struct mu_type *mu_base = (struct mu_type *)base;
Ye Li0db17f42021-08-07 16:00:41 +080047 u32 mask = MU_SR_TE0_MASK << reg_index;
Ye Li41a9a4f2024-10-06 08:22:50 +080048 u32 val, tr_num;
Ye Li0db17f42021-08-07 16:00:41 +080049 int ret;
50
Ye Li41a9a4f2024-10-06 08:22:50 +080051 tr_num = readl(&mu_base->par) & 0xFF;
52 assert(reg_index < tr_num);
Ye Li0db17f42021-08-07 16:00:41 +080053
Ye Li58a69282023-06-15 18:09:13 +080054 debug("sendmsg tsr 0x%x\n", readl(&mu_base->tsr));
Ye Li0db17f42021-08-07 16:00:41 +080055
56 /* Wait TX register to be empty. */
Ye Li853cc9d2021-08-07 16:00:55 +080057 ret = readl_poll_timeout(&mu_base->tsr, val, val & mask, 10000);
Ye Li0db17f42021-08-07 16:00:41 +080058 if (ret < 0) {
59 debug("%s timeout\n", __func__);
60 return -ETIMEDOUT;
61 }
62
63 debug("tr[%d] 0x%x\n", reg_index, msg);
64
Ye Li853cc9d2021-08-07 16:00:55 +080065 writel(msg, &mu_base->tr[reg_index]);
Ye Li0db17f42021-08-07 16:00:41 +080066
67 return 0;
68}
69
Ye Li853cc9d2021-08-07 16:00:55 +080070int mu_hal_receivemsg(ulong base, u32 reg_index, u32 *msg)
Ye Li0db17f42021-08-07 16:00:41 +080071{
Ye Li853cc9d2021-08-07 16:00:55 +080072 struct mu_type *mu_base = (struct mu_type *)base;
Ye Li0db17f42021-08-07 16:00:41 +080073 u32 mask = MU_SR_RF0_MASK << reg_index;
Ye Li41a9a4f2024-10-06 08:22:50 +080074 u32 val, rr_num;
Ye Li0db17f42021-08-07 16:00:41 +080075 int ret;
Ye Li58a69282023-06-15 18:09:13 +080076 u32 count = 10;
Ye Li0db17f42021-08-07 16:00:41 +080077
Ye Li41a9a4f2024-10-06 08:22:50 +080078 rr_num = (readl(&mu_base->par) & 0xFF00) >> 8;
79 assert(reg_index < rr_num);
Ye Li0db17f42021-08-07 16:00:41 +080080
Ye Li58a69282023-06-15 18:09:13 +080081 debug("receivemsg rsr 0x%x\n", readl(&mu_base->rsr));
Ye Li0db17f42021-08-07 16:00:41 +080082
Ye Li58a69282023-06-15 18:09:13 +080083 do {
84 /* Wait RX register to be full. */
85 ret = readl_poll_timeout(&mu_base->rsr, val, val & mask, 1000000);
86 if (ret < 0) {
87 count--;
88 printf("mu receive msg wait %us\n", 10 - count);
89 } else {
90 break;
91 }
92 } while (count > 0);
93
94 if (count == 0) {
Ye Li0db17f42021-08-07 16:00:41 +080095 debug("%s timeout\n", __func__);
96 return -ETIMEDOUT;
97 }
98
Ye Li853cc9d2021-08-07 16:00:55 +080099 *msg = readl(&mu_base->rr[reg_index]);
Ye Li0db17f42021-08-07 16:00:41 +0800100
101 debug("rr[%d] 0x%x\n", reg_index, *msg);
102
103 return 0;
104}
105
106static int imx8ulp_mu_read(struct mu_type *base, void *data)
107{
Peng Fand5c31832023-06-15 18:09:05 +0800108 struct ele_msg *msg = (struct ele_msg *)data;
Ye Li0db17f42021-08-07 16:00:41 +0800109 int ret;
Ye Li41a9a4f2024-10-06 08:22:50 +0800110 u8 count = 0, rr_num;
Ye Li0db17f42021-08-07 16:00:41 +0800111
112 if (!msg)
113 return -EINVAL;
114
115 /* Read first word */
Ye Li853cc9d2021-08-07 16:00:55 +0800116 ret = mu_hal_receivemsg((ulong)base, 0, (u32 *)msg);
Ye Li0db17f42021-08-07 16:00:41 +0800117 if (ret)
118 return ret;
119 count++;
120
121 /* Check size */
Peng Fand5c31832023-06-15 18:09:05 +0800122 if (msg->size > ELE_MAX_MSG) {
Ye Li0db17f42021-08-07 16:00:41 +0800123 *((u32 *)msg) = 0;
124 return -EINVAL;
125 }
126
Ye Li41a9a4f2024-10-06 08:22:50 +0800127 rr_num = (readl(&base->par) & 0xFF00) >> 8;
128
Ye Li0db17f42021-08-07 16:00:41 +0800129 /* Read remaining words */
130 while (count < msg->size) {
Ye Li41a9a4f2024-10-06 08:22:50 +0800131 ret = mu_hal_receivemsg((ulong)base, count % rr_num,
Ye Li0db17f42021-08-07 16:00:41 +0800132 &msg->data[count - 1]);
133 if (ret)
134 return ret;
135 count++;
136 }
137
138 return 0;
139}
140
141static int imx8ulp_mu_write(struct mu_type *base, void *data)
142{
Peng Fand5c31832023-06-15 18:09:05 +0800143 struct ele_msg *msg = (struct ele_msg *)data;
Ye Li0db17f42021-08-07 16:00:41 +0800144 int ret;
Ye Li41a9a4f2024-10-06 08:22:50 +0800145 u8 count = 0, tr_num;
Ye Li0db17f42021-08-07 16:00:41 +0800146
147 if (!msg)
148 return -EINVAL;
149
150 /* Check size */
Peng Fand5c31832023-06-15 18:09:05 +0800151 if (msg->size > ELE_MAX_MSG)
Ye Li0db17f42021-08-07 16:00:41 +0800152 return -EINVAL;
153
154 /* Write first word */
Ye Li853cc9d2021-08-07 16:00:55 +0800155 ret = mu_hal_sendmsg((ulong)base, 0, *((u32 *)msg));
Ye Li0db17f42021-08-07 16:00:41 +0800156 if (ret)
157 return ret;
158 count++;
159
Ye Li41a9a4f2024-10-06 08:22:50 +0800160 tr_num = readl(&base->par) & 0xFF;
161
Ye Li0db17f42021-08-07 16:00:41 +0800162 /* Write remaining words */
163 while (count < msg->size) {
Ye Li41a9a4f2024-10-06 08:22:50 +0800164 ret = mu_hal_sendmsg((ulong)base, count % tr_num,
Ye Li0db17f42021-08-07 16:00:41 +0800165 msg->data[count - 1]);
166 if (ret)
167 return ret;
168 count++;
169 }
170
171 return 0;
172}
173
174/*
175 * Note the function prototype use msgid as the 2nd parameter, here
176 * we take it as no_resp.
177 */
178static int imx8ulp_mu_call(struct udevice *dev, int no_resp, void *tx_msg,
179 int tx_size, void *rx_msg, int rx_size)
180{
181 struct imx8ulp_mu *priv = dev_get_priv(dev);
182 u32 result;
183 int ret;
184
185 /* Expect tx_msg, rx_msg are the same value */
186 if (rx_msg && tx_msg != rx_msg)
187 printf("tx_msg %p, rx_msg %p\n", tx_msg, rx_msg);
188
189 ret = imx8ulp_mu_write(priv->base, tx_msg);
190 if (ret)
191 return ret;
192 if (!no_resp) {
193 ret = imx8ulp_mu_read(priv->base, rx_msg);
194 if (ret)
195 return ret;
196 }
197
Peng Fand5c31832023-06-15 18:09:05 +0800198 result = ((struct ele_msg *)rx_msg)->data[0];
Ye Li79581a62021-08-07 16:00:51 +0800199 if ((result & 0xff) == 0xd6)
Ye Li0db17f42021-08-07 16:00:41 +0800200 return 0;
201
202 return -EIO;
203}
204
205static int imx8ulp_mu_probe(struct udevice *dev)
206{
207 struct imx8ulp_mu *priv = dev_get_priv(dev);
208 fdt_addr_t addr;
209
210 debug("%s(dev=%p) (priv=%p)\n", __func__, dev, priv);
211
212 addr = devfdt_get_addr(dev);
213 if (addr == FDT_ADDR_T_NONE)
214 return -EINVAL;
215
216 priv->base = (struct mu_type *)addr;
217
218 debug("mu base 0x%lx\n", (ulong)priv->base);
219
220 /* U-Boot not enable interrupts, so need to enable RX interrupts */
Ye Li853cc9d2021-08-07 16:00:55 +0800221 mu_hal_init((ulong)priv->base);
Ye Li0db17f42021-08-07 16:00:41 +0800222
Peng Fand5c31832023-06-15 18:09:05 +0800223 gd->arch.ele_dev = dev;
Ye Li0db17f42021-08-07 16:00:41 +0800224
225 return 0;
226}
227
228static int imx8ulp_mu_remove(struct udevice *dev)
229{
230 return 0;
231}
232
233static int imx8ulp_mu_bind(struct udevice *dev)
234{
235 debug("%s(dev=%p)\n", __func__, dev);
236
237 return 0;
238}
239
240static struct misc_ops imx8ulp_mu_ops = {
241 .call = imx8ulp_mu_call,
242};
243
244static const struct udevice_id imx8ulp_mu_ids[] = {
245 { .compatible = "fsl,imx8ulp-mu" },
Peng Fan1e9aff12022-07-26 16:40:50 +0800246 { .compatible = "fsl,imx93-mu-s4" },
Ye Li41a9a4f2024-10-06 08:22:50 +0800247 { .compatible = "fsl,imx95-mu-ele" },
Ye Li0db17f42021-08-07 16:00:41 +0800248 { }
249};
250
251U_BOOT_DRIVER(imx8ulp_mu) = {
252 .name = "imx8ulp_mu",
253 .id = UCLASS_MISC,
254 .of_match = imx8ulp_mu_ids,
255 .probe = imx8ulp_mu_probe,
256 .bind = imx8ulp_mu_bind,
257 .remove = imx8ulp_mu_remove,
258 .ops = &imx8ulp_mu_ops,
259 .priv_auto = sizeof(struct imx8ulp_mu),
260};