1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (c) 2018 Pengutronix, Oleksij Rempel <o.rempel@pengutronix.de> |
4 | * Copyright 2022 NXP, Peng Fan <peng.fan@nxp.com> |
5 | */ |
6 | |
7 | #include <linux/bitfield.h> |
8 | #include <linux/clk.h> |
9 | #include <linux/firmware/imx/ipc.h> |
10 | #include <linux/firmware/imx/s4.h> |
11 | #include <linux/interrupt.h> |
12 | #include <linux/io.h> |
13 | #include <linux/iopoll.h> |
14 | #include <linux/jiffies.h> |
15 | #include <linux/kernel.h> |
16 | #include <linux/mailbox_controller.h> |
17 | #include <linux/module.h> |
18 | #include <linux/of.h> |
19 | #include <linux/of_platform.h> |
20 | #include <linux/platform_device.h> |
21 | #include <linux/pm_runtime.h> |
22 | #include <linux/suspend.h> |
23 | #include <linux/slab.h> |
24 | |
25 | #include "mailbox.h" |
26 | |
27 | #define IMX_MU_CHANS 24 |
28 | /* TX0/RX0/RXDB[0-3] */ |
29 | #define IMX_MU_SCU_CHANS 6 |
30 | /* TX0/RX0 */ |
31 | #define IMX_MU_S4_CHANS 2 |
32 | #define IMX_MU_CHAN_NAME_SIZE 20 |
33 | |
34 | #define IMX_MU_V2_PAR_OFF 0x4 |
35 | #define IMX_MU_V2_TR_MASK GENMASK(7, 0) |
36 | #define IMX_MU_V2_RR_MASK GENMASK(15, 8) |
37 | |
38 | #define IMX_MU_SECO_TX_TOUT (msecs_to_jiffies(3000)) |
39 | #define IMX_MU_SECO_RX_TOUT (msecs_to_jiffies(3000)) |
40 | |
41 | /* Please not change TX & RX */ |
42 | enum imx_mu_chan_type { |
43 | IMX_MU_TYPE_TX = 0, /* Tx */ |
44 | IMX_MU_TYPE_RX = 1, /* Rx */ |
45 | IMX_MU_TYPE_TXDB = 2, /* Tx doorbell */ |
46 | IMX_MU_TYPE_RXDB = 3, /* Rx doorbell */ |
47 | IMX_MU_TYPE_RST = 4, /* Reset */ |
48 | IMX_MU_TYPE_TXDB_V2 = 5, /* Tx doorbell with S/W ACK */ |
49 | }; |
50 | |
51 | enum imx_mu_xcr { |
52 | IMX_MU_CR, |
53 | IMX_MU_GIER, |
54 | IMX_MU_GCR, |
55 | IMX_MU_TCR, |
56 | IMX_MU_RCR, |
57 | IMX_MU_xCR_MAX, |
58 | }; |
59 | |
60 | enum imx_mu_xsr { |
61 | IMX_MU_SR, |
62 | IMX_MU_GSR, |
63 | IMX_MU_TSR, |
64 | IMX_MU_RSR, |
65 | IMX_MU_xSR_MAX, |
66 | }; |
67 | |
68 | struct imx_sc_rpc_msg_max { |
69 | struct imx_sc_rpc_msg hdr; |
70 | u32 data[30]; |
71 | }; |
72 | |
73 | struct imx_s4_rpc_msg_max { |
74 | struct imx_s4_rpc_msg hdr; |
75 | u32 data[254]; |
76 | }; |
77 | |
78 | struct imx_mu_con_priv { |
79 | unsigned int idx; |
80 | char irq_desc[IMX_MU_CHAN_NAME_SIZE]; |
81 | enum imx_mu_chan_type type; |
82 | struct mbox_chan *chan; |
83 | struct tasklet_struct txdb_tasklet; |
84 | }; |
85 | |
86 | struct imx_mu_priv { |
87 | struct device *dev; |
88 | void __iomem *base; |
89 | void *msg; |
90 | spinlock_t xcr_lock; /* control register lock */ |
91 | |
92 | struct mbox_controller mbox; |
93 | struct mbox_chan mbox_chans[IMX_MU_CHANS]; |
94 | |
95 | struct imx_mu_con_priv con_priv[IMX_MU_CHANS]; |
96 | const struct imx_mu_dcfg *dcfg; |
97 | struct clk *clk; |
98 | int irq[IMX_MU_CHANS]; |
99 | bool suspend; |
100 | bool side_b; |
101 | |
102 | u32 xcr[IMX_MU_xCR_MAX]; |
103 | u32 num_tr; |
104 | u32 num_rr; |
105 | }; |
106 | |
107 | enum imx_mu_type { |
108 | IMX_MU_V1, |
109 | IMX_MU_V2 = BIT(1), |
110 | IMX_MU_V2_S4 = BIT(15), |
111 | IMX_MU_V2_IRQ = BIT(16), |
112 | }; |
113 | |
114 | struct imx_mu_dcfg { |
115 | int (*tx)(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp, void *data); |
116 | int (*rx)(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp); |
117 | int (*rxdb)(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp); |
118 | int (*init)(struct imx_mu_priv *priv); |
119 | enum imx_mu_type type; |
120 | u32 xTR; /* Transmit Register0 */ |
121 | u32 xRR; /* Receive Register0 */ |
122 | u32 xSR[IMX_MU_xSR_MAX]; /* Status Registers */ |
123 | u32 xCR[IMX_MU_xCR_MAX]; /* Control Registers */ |
124 | }; |
125 | |
126 | #define IMX_MU_xSR_GIPn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(28 + (3 - (x)))) |
127 | #define IMX_MU_xSR_RFn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(24 + (3 - (x)))) |
128 | #define IMX_MU_xSR_TEn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(20 + (3 - (x)))) |
129 | |
130 | /* General Purpose Interrupt Enable */ |
131 | #define IMX_MU_xCR_GIEn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(28 + (3 - (x)))) |
132 | /* Receive Interrupt Enable */ |
133 | #define IMX_MU_xCR_RIEn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(24 + (3 - (x)))) |
134 | /* Transmit Interrupt Enable */ |
135 | #define IMX_MU_xCR_TIEn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(20 + (3 - (x)))) |
136 | /* General Purpose Interrupt Request */ |
137 | #define IMX_MU_xCR_GIRn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(16 + (3 - (x)))) |
138 | /* MU reset */ |
139 | #define IMX_MU_xCR_RST(type) (type & IMX_MU_V2 ? BIT(0) : BIT(5)) |
140 | #define IMX_MU_xSR_RST(type) (type & IMX_MU_V2 ? BIT(0) : BIT(7)) |
141 | |
142 | |
143 | static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller *mbox) |
144 | { |
145 | return container_of(mbox, struct imx_mu_priv, mbox); |
146 | } |
147 | |
148 | static void imx_mu_write(struct imx_mu_priv *priv, u32 val, u32 offs) |
149 | { |
150 | iowrite32(val, priv->base + offs); |
151 | } |
152 | |
153 | static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) |
154 | { |
155 | return ioread32(priv->base + offs); |
156 | } |
157 | |
158 | static int imx_mu_tx_waiting_write(struct imx_mu_priv *priv, u32 val, u32 idx) |
159 | { |
160 | u64 timeout_time = get_jiffies_64() + IMX_MU_SECO_TX_TOUT; |
161 | u32 status; |
162 | u32 can_write; |
163 | |
164 | dev_dbg(priv->dev, "Trying to write %.8x to idx %d\n" , val, idx); |
165 | |
166 | do { |
167 | status = imx_mu_read(priv, offs: priv->dcfg->xSR[IMX_MU_TSR]); |
168 | can_write = status & IMX_MU_xSR_TEn(priv->dcfg->type, idx % 4); |
169 | } while (!can_write && time_is_after_jiffies64(timeout_time)); |
170 | |
171 | if (!can_write) { |
172 | dev_err(priv->dev, "timeout trying to write %.8x at %d(%.8x)\n" , |
173 | val, idx, status); |
174 | return -ETIME; |
175 | } |
176 | |
177 | imx_mu_write(priv, val, offs: priv->dcfg->xTR + (idx % 4) * 4); |
178 | |
179 | return 0; |
180 | } |
181 | |
182 | static int imx_mu_rx_waiting_read(struct imx_mu_priv *priv, u32 *val, u32 idx) |
183 | { |
184 | u64 timeout_time = get_jiffies_64() + IMX_MU_SECO_RX_TOUT; |
185 | u32 status; |
186 | u32 can_read; |
187 | |
188 | dev_dbg(priv->dev, "Trying to read from idx %d\n" , idx); |
189 | |
190 | do { |
191 | status = imx_mu_read(priv, offs: priv->dcfg->xSR[IMX_MU_RSR]); |
192 | can_read = status & IMX_MU_xSR_RFn(priv->dcfg->type, idx % 4); |
193 | } while (!can_read && time_is_after_jiffies64(timeout_time)); |
194 | |
195 | if (!can_read) { |
196 | dev_err(priv->dev, "timeout trying to read idx %d (%.8x)\n" , |
197 | idx, status); |
198 | return -ETIME; |
199 | } |
200 | |
201 | *val = imx_mu_read(priv, offs: priv->dcfg->xRR + (idx % 4) * 4); |
202 | dev_dbg(priv->dev, "Read %.8x\n" , *val); |
203 | |
204 | return 0; |
205 | } |
206 | |
207 | static u32 imx_mu_xcr_rmw(struct imx_mu_priv *priv, enum imx_mu_xcr type, u32 set, u32 clr) |
208 | { |
209 | unsigned long flags; |
210 | u32 val; |
211 | |
212 | spin_lock_irqsave(&priv->xcr_lock, flags); |
213 | val = imx_mu_read(priv, offs: priv->dcfg->xCR[type]); |
214 | val &= ~clr; |
215 | val |= set; |
216 | imx_mu_write(priv, val, offs: priv->dcfg->xCR[type]); |
217 | spin_unlock_irqrestore(lock: &priv->xcr_lock, flags); |
218 | |
219 | return val; |
220 | } |
221 | |
222 | static int imx_mu_generic_tx(struct imx_mu_priv *priv, |
223 | struct imx_mu_con_priv *cp, |
224 | void *data) |
225 | { |
226 | u32 *arg = data; |
227 | |
228 | switch (cp->type) { |
229 | case IMX_MU_TYPE_TX: |
230 | imx_mu_write(priv, val: *arg, offs: priv->dcfg->xTR + cp->idx * 4); |
231 | imx_mu_xcr_rmw(priv, type: IMX_MU_TCR, IMX_MU_xCR_TIEn(priv->dcfg->type, cp->idx), clr: 0); |
232 | break; |
233 | case IMX_MU_TYPE_TXDB: |
234 | imx_mu_xcr_rmw(priv, type: IMX_MU_GCR, IMX_MU_xCR_GIRn(priv->dcfg->type, cp->idx), clr: 0); |
235 | tasklet_schedule(t: &cp->txdb_tasklet); |
236 | break; |
237 | case IMX_MU_TYPE_TXDB_V2: |
238 | imx_mu_xcr_rmw(priv, type: IMX_MU_GCR, IMX_MU_xCR_GIRn(priv->dcfg->type, cp->idx), clr: 0); |
239 | break; |
240 | default: |
241 | dev_warn_ratelimited(priv->dev, "Send data on wrong channel type: %d\n" , cp->type); |
242 | return -EINVAL; |
243 | } |
244 | |
245 | return 0; |
246 | } |
247 | |
248 | static int imx_mu_generic_rx(struct imx_mu_priv *priv, |
249 | struct imx_mu_con_priv *cp) |
250 | { |
251 | u32 dat; |
252 | |
253 | dat = imx_mu_read(priv, offs: priv->dcfg->xRR + (cp->idx) * 4); |
254 | mbox_chan_received_data(chan: cp->chan, data: (void *)&dat); |
255 | |
256 | return 0; |
257 | } |
258 | |
259 | static int imx_mu_generic_rxdb(struct imx_mu_priv *priv, |
260 | struct imx_mu_con_priv *cp) |
261 | { |
262 | imx_mu_write(priv, IMX_MU_xSR_GIPn(priv->dcfg->type, cp->idx), |
263 | offs: priv->dcfg->xSR[IMX_MU_GSR]); |
264 | mbox_chan_received_data(chan: cp->chan, NULL); |
265 | |
266 | return 0; |
267 | } |
268 | |
269 | static int imx_mu_specific_tx(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp, void *data) |
270 | { |
271 | u32 *arg = data; |
272 | u32 num_tr = priv->num_tr; |
273 | int i, ret; |
274 | u32 xsr; |
275 | u32 size, max_size; |
276 | |
277 | if (priv->dcfg->type & IMX_MU_V2_S4) { |
278 | size = ((struct imx_s4_rpc_msg_max *)data)->hdr.size; |
279 | max_size = sizeof(struct imx_s4_rpc_msg_max); |
280 | } else { |
281 | size = ((struct imx_sc_rpc_msg_max *)data)->hdr.size; |
282 | max_size = sizeof(struct imx_sc_rpc_msg_max); |
283 | } |
284 | |
285 | switch (cp->type) { |
286 | case IMX_MU_TYPE_TX: |
287 | /* |
288 | * msg->hdr.size specifies the number of u32 words while |
289 | * sizeof yields bytes. |
290 | */ |
291 | |
292 | if (size > max_size / 4) { |
293 | /* |
294 | * The real message size can be different to |
295 | * struct imx_sc_rpc_msg_max/imx_s4_rpc_msg_max size |
296 | */ |
297 | dev_err(priv->dev, "Maximal message size (%u bytes) exceeded on TX; got: %i bytes\n" , max_size, size << 2); |
298 | return -EINVAL; |
299 | } |
300 | |
301 | for (i = 0; i < num_tr && i < size; i++) |
302 | imx_mu_write(priv, val: *arg++, offs: priv->dcfg->xTR + (i % num_tr) * 4); |
303 | for (; i < size; i++) { |
304 | ret = readl_poll_timeout(priv->base + priv->dcfg->xSR[IMX_MU_TSR], |
305 | xsr, |
306 | xsr & IMX_MU_xSR_TEn(priv->dcfg->type, i % num_tr), |
307 | 0, 5 * USEC_PER_SEC); |
308 | if (ret) { |
309 | dev_err(priv->dev, "Send data index: %d timeout\n" , i); |
310 | return ret; |
311 | } |
312 | imx_mu_write(priv, val: *arg++, offs: priv->dcfg->xTR + (i % num_tr) * 4); |
313 | } |
314 | |
315 | imx_mu_xcr_rmw(priv, type: IMX_MU_TCR, IMX_MU_xCR_TIEn(priv->dcfg->type, cp->idx), clr: 0); |
316 | break; |
317 | default: |
318 | dev_warn_ratelimited(priv->dev, "Send data on wrong channel type: %d\n" , cp->type); |
319 | return -EINVAL; |
320 | } |
321 | |
322 | return 0; |
323 | } |
324 | |
325 | static int imx_mu_specific_rx(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp) |
326 | { |
327 | u32 *data; |
328 | int i, ret; |
329 | u32 xsr; |
330 | u32 size, max_size; |
331 | u32 num_rr = priv->num_rr; |
332 | |
333 | data = (u32 *)priv->msg; |
334 | |
335 | imx_mu_xcr_rmw(priv, type: IMX_MU_RCR, set: 0, IMX_MU_xCR_RIEn(priv->dcfg->type, 0)); |
336 | *data++ = imx_mu_read(priv, offs: priv->dcfg->xRR); |
337 | |
338 | if (priv->dcfg->type & IMX_MU_V2_S4) { |
339 | size = ((struct imx_s4_rpc_msg_max *)priv->msg)->hdr.size; |
340 | max_size = sizeof(struct imx_s4_rpc_msg_max); |
341 | } else { |
342 | size = ((struct imx_sc_rpc_msg_max *)priv->msg)->hdr.size; |
343 | max_size = sizeof(struct imx_sc_rpc_msg_max); |
344 | } |
345 | |
346 | if (size > max_size / 4) { |
347 | dev_err(priv->dev, "Maximal message size (%u bytes) exceeded on RX; got: %i bytes\n" , max_size, size << 2); |
348 | return -EINVAL; |
349 | } |
350 | |
351 | for (i = 1; i < size; i++) { |
352 | ret = readl_poll_timeout(priv->base + priv->dcfg->xSR[IMX_MU_RSR], xsr, |
353 | xsr & IMX_MU_xSR_RFn(priv->dcfg->type, i % num_rr), 0, |
354 | 5 * USEC_PER_SEC); |
355 | if (ret) { |
356 | dev_err(priv->dev, "timeout read idx %d\n" , i); |
357 | return ret; |
358 | } |
359 | *data++ = imx_mu_read(priv, offs: priv->dcfg->xRR + (i % num_rr) * 4); |
360 | } |
361 | |
362 | imx_mu_xcr_rmw(priv, type: IMX_MU_RCR, IMX_MU_xCR_RIEn(priv->dcfg->type, 0), clr: 0); |
363 | mbox_chan_received_data(chan: cp->chan, data: (void *)priv->msg); |
364 | |
365 | return 0; |
366 | } |
367 | |
368 | static int imx_mu_seco_tx(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp, |
369 | void *data) |
370 | { |
371 | struct imx_sc_rpc_msg_max *msg = data; |
372 | u32 *arg = data; |
373 | u32 byte_size; |
374 | int err; |
375 | int i; |
376 | |
377 | dev_dbg(priv->dev, "Sending message\n" ); |
378 | |
379 | switch (cp->type) { |
380 | case IMX_MU_TYPE_TXDB: |
381 | byte_size = msg->hdr.size * sizeof(u32); |
382 | if (byte_size > sizeof(*msg)) { |
383 | /* |
384 | * The real message size can be different to |
385 | * struct imx_sc_rpc_msg_max size |
386 | */ |
387 | dev_err(priv->dev, |
388 | "Exceed max msg size (%zu) on TX, got: %i\n" , |
389 | sizeof(*msg), byte_size); |
390 | return -EINVAL; |
391 | } |
392 | |
393 | print_hex_dump_debug("from client " , DUMP_PREFIX_OFFSET, 4, 4, |
394 | data, byte_size, false); |
395 | |
396 | /* Send first word */ |
397 | dev_dbg(priv->dev, "Sending header\n" ); |
398 | imx_mu_write(priv, val: *arg++, offs: priv->dcfg->xTR); |
399 | |
400 | /* Send signaling */ |
401 | dev_dbg(priv->dev, "Sending signaling\n" ); |
402 | imx_mu_xcr_rmw(priv, type: IMX_MU_GCR, |
403 | IMX_MU_xCR_GIRn(priv->dcfg->type, cp->idx), clr: 0); |
404 | |
405 | /* Send words to fill the mailbox */ |
406 | for (i = 1; i < 4 && i < msg->hdr.size; i++) { |
407 | dev_dbg(priv->dev, "Sending word %d\n" , i); |
408 | imx_mu_write(priv, val: *arg++, |
409 | offs: priv->dcfg->xTR + (i % 4) * 4); |
410 | } |
411 | |
412 | /* Send rest of message waiting for remote read */ |
413 | for (; i < msg->hdr.size; i++) { |
414 | dev_dbg(priv->dev, "Sending word %d\n" , i); |
415 | err = imx_mu_tx_waiting_write(priv, val: *arg++, idx: i); |
416 | if (err) { |
417 | dev_err(priv->dev, "Timeout tx %d\n" , i); |
418 | return err; |
419 | } |
420 | } |
421 | |
422 | /* Simulate hack for mbox framework */ |
423 | tasklet_schedule(t: &cp->txdb_tasklet); |
424 | |
425 | break; |
426 | default: |
427 | dev_warn_ratelimited(priv->dev, |
428 | "Send data on wrong channel type: %d\n" , |
429 | cp->type); |
430 | return -EINVAL; |
431 | } |
432 | |
433 | return 0; |
434 | } |
435 | |
436 | static int imx_mu_seco_rxdb(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp) |
437 | { |
438 | struct imx_sc_rpc_msg_max msg; |
439 | u32 *data = (u32 *)&msg; |
440 | u32 byte_size; |
441 | int err = 0; |
442 | int i; |
443 | |
444 | dev_dbg(priv->dev, "Receiving message\n" ); |
445 | |
446 | /* Read header */ |
447 | dev_dbg(priv->dev, "Receiving header\n" ); |
448 | *data++ = imx_mu_read(priv, offs: priv->dcfg->xRR); |
449 | byte_size = msg.hdr.size * sizeof(u32); |
450 | if (byte_size > sizeof(msg)) { |
451 | dev_err(priv->dev, "Exceed max msg size (%zu) on RX, got: %i\n" , |
452 | sizeof(msg), byte_size); |
453 | err = -EINVAL; |
454 | goto error; |
455 | } |
456 | |
457 | /* Read message waiting they are written */ |
458 | for (i = 1; i < msg.hdr.size; i++) { |
459 | dev_dbg(priv->dev, "Receiving word %d\n" , i); |
460 | err = imx_mu_rx_waiting_read(priv, val: data++, idx: i); |
461 | if (err) { |
462 | dev_err(priv->dev, "Timeout rx %d\n" , i); |
463 | goto error; |
464 | } |
465 | } |
466 | |
467 | /* Clear GIP */ |
468 | imx_mu_write(priv, IMX_MU_xSR_GIPn(priv->dcfg->type, cp->idx), |
469 | offs: priv->dcfg->xSR[IMX_MU_GSR]); |
470 | |
471 | print_hex_dump_debug("to client " , DUMP_PREFIX_OFFSET, 4, 4, |
472 | &msg, byte_size, false); |
473 | |
474 | /* send data to client */ |
475 | dev_dbg(priv->dev, "Sending message to client\n" ); |
476 | mbox_chan_received_data(chan: cp->chan, data: (void *)&msg); |
477 | |
478 | goto exit; |
479 | |
480 | error: |
481 | mbox_chan_received_data(chan: cp->chan, data: ERR_PTR(error: err)); |
482 | |
483 | exit: |
484 | return err; |
485 | } |
486 | |
487 | static void imx_mu_txdb_tasklet(unsigned long data) |
488 | { |
489 | struct imx_mu_con_priv *cp = (struct imx_mu_con_priv *)data; |
490 | |
491 | mbox_chan_txdone(chan: cp->chan, r: 0); |
492 | } |
493 | |
494 | static irqreturn_t imx_mu_isr(int irq, void *p) |
495 | { |
496 | struct mbox_chan *chan = p; |
497 | struct imx_mu_priv *priv = to_imx_mu_priv(mbox: chan->mbox); |
498 | struct imx_mu_con_priv *cp = chan->con_priv; |
499 | u32 val, ctrl; |
500 | |
501 | switch (cp->type) { |
502 | case IMX_MU_TYPE_TX: |
503 | ctrl = imx_mu_read(priv, offs: priv->dcfg->xCR[IMX_MU_TCR]); |
504 | val = imx_mu_read(priv, offs: priv->dcfg->xSR[IMX_MU_TSR]); |
505 | val &= IMX_MU_xSR_TEn(priv->dcfg->type, cp->idx) & |
506 | (ctrl & IMX_MU_xCR_TIEn(priv->dcfg->type, cp->idx)); |
507 | break; |
508 | case IMX_MU_TYPE_RX: |
509 | ctrl = imx_mu_read(priv, offs: priv->dcfg->xCR[IMX_MU_RCR]); |
510 | val = imx_mu_read(priv, offs: priv->dcfg->xSR[IMX_MU_RSR]); |
511 | val &= IMX_MU_xSR_RFn(priv->dcfg->type, cp->idx) & |
512 | (ctrl & IMX_MU_xCR_RIEn(priv->dcfg->type, cp->idx)); |
513 | break; |
514 | case IMX_MU_TYPE_RXDB: |
515 | ctrl = imx_mu_read(priv, offs: priv->dcfg->xCR[IMX_MU_GIER]); |
516 | val = imx_mu_read(priv, offs: priv->dcfg->xSR[IMX_MU_GSR]); |
517 | val &= IMX_MU_xSR_GIPn(priv->dcfg->type, cp->idx) & |
518 | (ctrl & IMX_MU_xCR_GIEn(priv->dcfg->type, cp->idx)); |
519 | break; |
520 | case IMX_MU_TYPE_RST: |
521 | return IRQ_NONE; |
522 | default: |
523 | dev_warn_ratelimited(priv->dev, "Unhandled channel type %d\n" , |
524 | cp->type); |
525 | return IRQ_NONE; |
526 | } |
527 | |
528 | if (!val) |
529 | return IRQ_NONE; |
530 | |
531 | if ((val == IMX_MU_xSR_TEn(priv->dcfg->type, cp->idx)) && |
532 | (cp->type == IMX_MU_TYPE_TX)) { |
533 | imx_mu_xcr_rmw(priv, type: IMX_MU_TCR, set: 0, IMX_MU_xCR_TIEn(priv->dcfg->type, cp->idx)); |
534 | mbox_chan_txdone(chan, r: 0); |
535 | } else if ((val == IMX_MU_xSR_RFn(priv->dcfg->type, cp->idx)) && |
536 | (cp->type == IMX_MU_TYPE_RX)) { |
537 | priv->dcfg->rx(priv, cp); |
538 | } else if ((val == IMX_MU_xSR_GIPn(priv->dcfg->type, cp->idx)) && |
539 | (cp->type == IMX_MU_TYPE_RXDB)) { |
540 | priv->dcfg->rxdb(priv, cp); |
541 | } else { |
542 | dev_warn_ratelimited(priv->dev, "Not handled interrupt\n" ); |
543 | return IRQ_NONE; |
544 | } |
545 | |
546 | if (priv->suspend) |
547 | pm_system_wakeup(); |
548 | |
549 | return IRQ_HANDLED; |
550 | } |
551 | |
552 | static int imx_mu_send_data(struct mbox_chan *chan, void *data) |
553 | { |
554 | struct imx_mu_priv *priv = to_imx_mu_priv(mbox: chan->mbox); |
555 | struct imx_mu_con_priv *cp = chan->con_priv; |
556 | |
557 | return priv->dcfg->tx(priv, cp, data); |
558 | } |
559 | |
560 | static int imx_mu_startup(struct mbox_chan *chan) |
561 | { |
562 | struct imx_mu_priv *priv = to_imx_mu_priv(mbox: chan->mbox); |
563 | struct imx_mu_con_priv *cp = chan->con_priv; |
564 | unsigned long irq_flag = 0; |
565 | int ret; |
566 | |
567 | pm_runtime_get_sync(dev: priv->dev); |
568 | if (cp->type == IMX_MU_TYPE_TXDB_V2) |
569 | return 0; |
570 | |
571 | if (cp->type == IMX_MU_TYPE_TXDB) { |
572 | /* Tx doorbell don't have ACK support */ |
573 | tasklet_init(t: &cp->txdb_tasklet, func: imx_mu_txdb_tasklet, |
574 | data: (unsigned long)cp); |
575 | return 0; |
576 | } |
577 | |
578 | /* IPC MU should be with IRQF_NO_SUSPEND set */ |
579 | if (!priv->dev->pm_domain) |
580 | irq_flag |= IRQF_NO_SUSPEND; |
581 | |
582 | if (!(priv->dcfg->type & IMX_MU_V2_IRQ)) |
583 | irq_flag |= IRQF_SHARED; |
584 | |
585 | ret = request_irq(irq: priv->irq[cp->type], handler: imx_mu_isr, flags: irq_flag, name: cp->irq_desc, dev: chan); |
586 | if (ret) { |
587 | dev_err(priv->dev, "Unable to acquire IRQ %d\n" , priv->irq[cp->type]); |
588 | return ret; |
589 | } |
590 | |
591 | switch (cp->type) { |
592 | case IMX_MU_TYPE_RX: |
593 | imx_mu_xcr_rmw(priv, type: IMX_MU_RCR, IMX_MU_xCR_RIEn(priv->dcfg->type, cp->idx), clr: 0); |
594 | break; |
595 | case IMX_MU_TYPE_RXDB: |
596 | imx_mu_xcr_rmw(priv, type: IMX_MU_GIER, IMX_MU_xCR_GIEn(priv->dcfg->type, cp->idx), clr: 0); |
597 | break; |
598 | default: |
599 | break; |
600 | } |
601 | |
602 | return 0; |
603 | } |
604 | |
605 | static void imx_mu_shutdown(struct mbox_chan *chan) |
606 | { |
607 | struct imx_mu_priv *priv = to_imx_mu_priv(mbox: chan->mbox); |
608 | struct imx_mu_con_priv *cp = chan->con_priv; |
609 | int ret; |
610 | u32 sr; |
611 | |
612 | if (cp->type == IMX_MU_TYPE_TXDB_V2) { |
613 | pm_runtime_put_sync(dev: priv->dev); |
614 | return; |
615 | } |
616 | |
617 | if (cp->type == IMX_MU_TYPE_TXDB) { |
618 | tasklet_kill(t: &cp->txdb_tasklet); |
619 | pm_runtime_put_sync(dev: priv->dev); |
620 | return; |
621 | } |
622 | |
623 | switch (cp->type) { |
624 | case IMX_MU_TYPE_TX: |
625 | imx_mu_xcr_rmw(priv, type: IMX_MU_TCR, set: 0, IMX_MU_xCR_TIEn(priv->dcfg->type, cp->idx)); |
626 | break; |
627 | case IMX_MU_TYPE_RX: |
628 | imx_mu_xcr_rmw(priv, type: IMX_MU_RCR, set: 0, IMX_MU_xCR_RIEn(priv->dcfg->type, cp->idx)); |
629 | break; |
630 | case IMX_MU_TYPE_RXDB: |
631 | imx_mu_xcr_rmw(priv, type: IMX_MU_GIER, set: 0, IMX_MU_xCR_GIEn(priv->dcfg->type, cp->idx)); |
632 | break; |
633 | case IMX_MU_TYPE_RST: |
634 | imx_mu_xcr_rmw(priv, type: IMX_MU_CR, IMX_MU_xCR_RST(priv->dcfg->type), clr: 0); |
635 | ret = readl_poll_timeout(priv->base + priv->dcfg->xSR[IMX_MU_SR], sr, |
636 | !(sr & IMX_MU_xSR_RST(priv->dcfg->type)), 1, 5); |
637 | if (ret) |
638 | dev_warn(priv->dev, "RST channel timeout\n" ); |
639 | break; |
640 | default: |
641 | break; |
642 | } |
643 | |
644 | free_irq(priv->irq[cp->type], chan); |
645 | pm_runtime_put_sync(dev: priv->dev); |
646 | } |
647 | |
648 | static const struct mbox_chan_ops imx_mu_ops = { |
649 | .send_data = imx_mu_send_data, |
650 | .startup = imx_mu_startup, |
651 | .shutdown = imx_mu_shutdown, |
652 | }; |
653 | |
654 | static struct mbox_chan *imx_mu_specific_xlate(struct mbox_controller *mbox, |
655 | const struct of_phandle_args *sp) |
656 | { |
657 | u32 type, idx, chan; |
658 | |
659 | if (sp->args_count != 2) { |
660 | dev_err(mbox->dev, "Invalid argument count %d\n" , sp->args_count); |
661 | return ERR_PTR(error: -EINVAL); |
662 | } |
663 | |
664 | type = sp->args[0]; /* channel type */ |
665 | idx = sp->args[1]; /* index */ |
666 | |
667 | switch (type) { |
668 | case IMX_MU_TYPE_TX: |
669 | case IMX_MU_TYPE_RX: |
670 | if (idx != 0) |
671 | dev_err(mbox->dev, "Invalid chan idx: %d\n" , idx); |
672 | chan = type; |
673 | break; |
674 | case IMX_MU_TYPE_RXDB: |
675 | chan = 2 + idx; |
676 | break; |
677 | default: |
678 | dev_err(mbox->dev, "Invalid chan type: %d\n" , type); |
679 | return ERR_PTR(error: -EINVAL); |
680 | } |
681 | |
682 | if (chan >= mbox->num_chans) { |
683 | dev_err(mbox->dev, "Not supported channel number: %d. (type: %d, idx: %d)\n" , chan, type, idx); |
684 | return ERR_PTR(error: -EINVAL); |
685 | } |
686 | |
687 | return &mbox->chans[chan]; |
688 | } |
689 | |
690 | static struct mbox_chan * imx_mu_xlate(struct mbox_controller *mbox, |
691 | const struct of_phandle_args *sp) |
692 | { |
693 | struct mbox_chan *p_chan; |
694 | u32 type, idx, chan; |
695 | |
696 | if (sp->args_count != 2) { |
697 | dev_err(mbox->dev, "Invalid argument count %d\n" , sp->args_count); |
698 | return ERR_PTR(error: -EINVAL); |
699 | } |
700 | |
701 | type = sp->args[0]; /* channel type */ |
702 | idx = sp->args[1]; /* index */ |
703 | |
704 | /* RST only supports 1 channel */ |
705 | if ((type == IMX_MU_TYPE_RST) && idx) { |
706 | dev_err(mbox->dev, "Invalid RST channel %d\n" , idx); |
707 | return ERR_PTR(error: -EINVAL); |
708 | } |
709 | |
710 | chan = type * 4 + idx; |
711 | if (chan >= mbox->num_chans) { |
712 | dev_err(mbox->dev, "Not supported channel number: %d. (type: %d, idx: %d)\n" , chan, type, idx); |
713 | return ERR_PTR(error: -EINVAL); |
714 | } |
715 | |
716 | p_chan = &mbox->chans[chan]; |
717 | |
718 | if (type == IMX_MU_TYPE_TXDB_V2) |
719 | p_chan->txdone_method = TXDONE_BY_ACK; |
720 | |
721 | return p_chan; |
722 | } |
723 | |
724 | static struct mbox_chan *imx_mu_seco_xlate(struct mbox_controller *mbox, |
725 | const struct of_phandle_args *sp) |
726 | { |
727 | u32 type; |
728 | |
729 | if (sp->args_count < 1) { |
730 | dev_err(mbox->dev, "Invalid argument count %d\n" , sp->args_count); |
731 | return ERR_PTR(error: -EINVAL); |
732 | } |
733 | |
734 | type = sp->args[0]; /* channel type */ |
735 | |
736 | /* Only supports TXDB and RXDB */ |
737 | if (type == IMX_MU_TYPE_TX || type == IMX_MU_TYPE_RX) { |
738 | dev_err(mbox->dev, "Invalid type: %d\n" , type); |
739 | return ERR_PTR(error: -EINVAL); |
740 | } |
741 | |
742 | return imx_mu_xlate(mbox, sp); |
743 | } |
744 | |
745 | static void imx_mu_get_tr_rr(struct imx_mu_priv *priv) |
746 | { |
747 | u32 val; |
748 | |
749 | if (priv->dcfg->type & IMX_MU_V2) { |
750 | val = imx_mu_read(priv, IMX_MU_V2_PAR_OFF); |
751 | priv->num_tr = FIELD_GET(IMX_MU_V2_TR_MASK, val); |
752 | priv->num_rr = FIELD_GET(IMX_MU_V2_RR_MASK, val); |
753 | } else { |
754 | priv->num_tr = 4; |
755 | priv->num_rr = 4; |
756 | } |
757 | } |
758 | |
759 | static int imx_mu_init_generic(struct imx_mu_priv *priv) |
760 | { |
761 | unsigned int i; |
762 | unsigned int val; |
763 | |
764 | if (priv->num_rr > 4 || priv->num_tr > 4) { |
765 | WARN_ONCE(true, "%s not support TR/RR larger than 4\n" , __func__); |
766 | return -EOPNOTSUPP; |
767 | } |
768 | |
769 | for (i = 0; i < IMX_MU_CHANS; i++) { |
770 | struct imx_mu_con_priv *cp = &priv->con_priv[i]; |
771 | |
772 | cp->idx = i % 4; |
773 | cp->type = i >> 2; |
774 | cp->chan = &priv->mbox_chans[i]; |
775 | priv->mbox_chans[i].con_priv = cp; |
776 | snprintf(buf: cp->irq_desc, size: sizeof(cp->irq_desc), |
777 | fmt: "imx_mu_chan[%i-%i]" , cp->type, cp->idx); |
778 | } |
779 | |
780 | priv->mbox.num_chans = IMX_MU_CHANS; |
781 | priv->mbox.of_xlate = imx_mu_xlate; |
782 | |
783 | if (priv->side_b) |
784 | return 0; |
785 | |
786 | /* Set default MU configuration */ |
787 | for (i = 0; i < IMX_MU_xCR_MAX; i++) |
788 | imx_mu_write(priv, val: 0, offs: priv->dcfg->xCR[i]); |
789 | |
790 | /* Clear any pending GIP */ |
791 | val = imx_mu_read(priv, offs: priv->dcfg->xSR[IMX_MU_GSR]); |
792 | imx_mu_write(priv, val, offs: priv->dcfg->xSR[IMX_MU_GSR]); |
793 | |
794 | /* Clear any pending RSR */ |
795 | for (i = 0; i < priv->num_rr; i++) |
796 | imx_mu_read(priv, offs: priv->dcfg->xRR + i * 4); |
797 | |
798 | return 0; |
799 | } |
800 | |
801 | static int imx_mu_init_specific(struct imx_mu_priv *priv) |
802 | { |
803 | unsigned int i; |
804 | int num_chans = priv->dcfg->type & IMX_MU_V2_S4 ? IMX_MU_S4_CHANS : IMX_MU_SCU_CHANS; |
805 | |
806 | for (i = 0; i < num_chans; i++) { |
807 | struct imx_mu_con_priv *cp = &priv->con_priv[i]; |
808 | |
809 | cp->idx = i < 2 ? 0 : i - 2; |
810 | cp->type = i < 2 ? i : IMX_MU_TYPE_RXDB; |
811 | cp->chan = &priv->mbox_chans[i]; |
812 | priv->mbox_chans[i].con_priv = cp; |
813 | snprintf(buf: cp->irq_desc, size: sizeof(cp->irq_desc), |
814 | fmt: "imx_mu_chan[%i-%i]" , cp->type, cp->idx); |
815 | } |
816 | |
817 | priv->mbox.num_chans = num_chans; |
818 | priv->mbox.of_xlate = imx_mu_specific_xlate; |
819 | |
820 | /* Set default MU configuration */ |
821 | for (i = 0; i < IMX_MU_xCR_MAX; i++) |
822 | imx_mu_write(priv, val: 0, offs: priv->dcfg->xCR[i]); |
823 | |
824 | return 0; |
825 | } |
826 | |
827 | static int imx_mu_init_seco(struct imx_mu_priv *priv) |
828 | { |
829 | int ret; |
830 | |
831 | ret = imx_mu_init_generic(priv); |
832 | if (ret) |
833 | return ret; |
834 | priv->mbox.of_xlate = imx_mu_seco_xlate; |
835 | |
836 | return 0; |
837 | } |
838 | |
839 | static int imx_mu_probe(struct platform_device *pdev) |
840 | { |
841 | struct device *dev = &pdev->dev; |
842 | struct device_node *np = dev->of_node; |
843 | struct imx_mu_priv *priv; |
844 | const struct imx_mu_dcfg *dcfg; |
845 | int i, ret; |
846 | u32 size; |
847 | |
848 | priv = devm_kzalloc(dev, size: sizeof(*priv), GFP_KERNEL); |
849 | if (!priv) |
850 | return -ENOMEM; |
851 | |
852 | priv->dev = dev; |
853 | |
854 | priv->base = devm_platform_ioremap_resource(pdev, index: 0); |
855 | if (IS_ERR(ptr: priv->base)) |
856 | return PTR_ERR(ptr: priv->base); |
857 | |
858 | dcfg = of_device_get_match_data(dev); |
859 | if (!dcfg) |
860 | return -EINVAL; |
861 | priv->dcfg = dcfg; |
862 | if (priv->dcfg->type & IMX_MU_V2_IRQ) { |
863 | priv->irq[IMX_MU_TYPE_TX] = platform_get_irq_byname(pdev, "tx" ); |
864 | if (priv->irq[IMX_MU_TYPE_TX] < 0) |
865 | return priv->irq[IMX_MU_TYPE_TX]; |
866 | priv->irq[IMX_MU_TYPE_RX] = platform_get_irq_byname(pdev, "rx" ); |
867 | if (priv->irq[IMX_MU_TYPE_RX] < 0) |
868 | return priv->irq[IMX_MU_TYPE_RX]; |
869 | } else { |
870 | ret = platform_get_irq(pdev, 0); |
871 | if (ret < 0) |
872 | return ret; |
873 | |
874 | for (i = 0; i < IMX_MU_CHANS; i++) |
875 | priv->irq[i] = ret; |
876 | } |
877 | |
878 | if (priv->dcfg->type & IMX_MU_V2_S4) |
879 | size = sizeof(struct imx_s4_rpc_msg_max); |
880 | else |
881 | size = sizeof(struct imx_sc_rpc_msg_max); |
882 | |
883 | priv->msg = devm_kzalloc(dev, size, GFP_KERNEL); |
884 | if (!priv->msg) |
885 | return -ENOMEM; |
886 | |
887 | priv->clk = devm_clk_get(dev, NULL); |
888 | if (IS_ERR(ptr: priv->clk)) { |
889 | if (PTR_ERR(ptr: priv->clk) != -ENOENT) |
890 | return PTR_ERR(ptr: priv->clk); |
891 | |
892 | priv->clk = NULL; |
893 | } |
894 | |
895 | ret = clk_prepare_enable(clk: priv->clk); |
896 | if (ret) { |
897 | dev_err(dev, "Failed to enable clock\n" ); |
898 | return ret; |
899 | } |
900 | |
901 | imx_mu_get_tr_rr(priv); |
902 | |
903 | priv->side_b = of_property_read_bool(np, propname: "fsl,mu-side-b" ); |
904 | |
905 | ret = priv->dcfg->init(priv); |
906 | if (ret) { |
907 | dev_err(dev, "Failed to init MU\n" ); |
908 | goto disable_clk; |
909 | } |
910 | |
911 | spin_lock_init(&priv->xcr_lock); |
912 | |
913 | priv->mbox.dev = dev; |
914 | priv->mbox.ops = &imx_mu_ops; |
915 | priv->mbox.chans = priv->mbox_chans; |
916 | priv->mbox.txdone_irq = true; |
917 | |
918 | platform_set_drvdata(pdev, data: priv); |
919 | |
920 | ret = devm_mbox_controller_register(dev, mbox: &priv->mbox); |
921 | if (ret) |
922 | goto disable_clk; |
923 | |
924 | of_platform_populate(root: dev->of_node, NULL, NULL, parent: dev); |
925 | |
926 | pm_runtime_enable(dev); |
927 | |
928 | ret = pm_runtime_resume_and_get(dev); |
929 | if (ret < 0) |
930 | goto disable_runtime_pm; |
931 | |
932 | ret = pm_runtime_put_sync(dev); |
933 | if (ret < 0) |
934 | goto disable_runtime_pm; |
935 | |
936 | clk_disable_unprepare(clk: priv->clk); |
937 | |
938 | return 0; |
939 | |
940 | disable_runtime_pm: |
941 | pm_runtime_disable(dev); |
942 | disable_clk: |
943 | clk_disable_unprepare(clk: priv->clk); |
944 | return ret; |
945 | } |
946 | |
947 | static void imx_mu_remove(struct platform_device *pdev) |
948 | { |
949 | struct imx_mu_priv *priv = platform_get_drvdata(pdev); |
950 | |
951 | pm_runtime_disable(dev: priv->dev); |
952 | } |
953 | |
954 | static const struct imx_mu_dcfg imx_mu_cfg_imx6sx = { |
955 | .tx = imx_mu_generic_tx, |
956 | .rx = imx_mu_generic_rx, |
957 | .rxdb = imx_mu_generic_rxdb, |
958 | .init = imx_mu_init_generic, |
959 | .xTR = 0x0, |
960 | .xRR = 0x10, |
961 | .xSR = {0x20, 0x20, 0x20, 0x20}, |
962 | .xCR = {0x24, 0x24, 0x24, 0x24, 0x24}, |
963 | }; |
964 | |
965 | static const struct imx_mu_dcfg imx_mu_cfg_imx7ulp = { |
966 | .tx = imx_mu_generic_tx, |
967 | .rx = imx_mu_generic_rx, |
968 | .rxdb = imx_mu_generic_rxdb, |
969 | .init = imx_mu_init_generic, |
970 | .xTR = 0x20, |
971 | .xRR = 0x40, |
972 | .xSR = {0x60, 0x60, 0x60, 0x60}, |
973 | .xCR = {0x64, 0x64, 0x64, 0x64, 0x64}, |
974 | }; |
975 | |
976 | static const struct imx_mu_dcfg imx_mu_cfg_imx8ulp = { |
977 | .tx = imx_mu_generic_tx, |
978 | .rx = imx_mu_generic_rx, |
979 | .rxdb = imx_mu_generic_rxdb, |
980 | .init = imx_mu_init_generic, |
981 | .type = IMX_MU_V2, |
982 | .xTR = 0x200, |
983 | .xRR = 0x280, |
984 | .xSR = {0xC, 0x118, 0x124, 0x12C}, |
985 | .xCR = {0x8, 0x110, 0x114, 0x120, 0x128}, |
986 | }; |
987 | |
988 | static const struct imx_mu_dcfg imx_mu_cfg_imx8ulp_s4 = { |
989 | .tx = imx_mu_specific_tx, |
990 | .rx = imx_mu_specific_rx, |
991 | .init = imx_mu_init_specific, |
992 | .type = IMX_MU_V2 | IMX_MU_V2_S4, |
993 | .xTR = 0x200, |
994 | .xRR = 0x280, |
995 | .xSR = {0xC, 0x118, 0x124, 0x12C}, |
996 | .xCR = {0x8, 0x110, 0x114, 0x120, 0x128}, |
997 | }; |
998 | |
999 | static const struct imx_mu_dcfg imx_mu_cfg_imx93_s4 = { |
1000 | .tx = imx_mu_specific_tx, |
1001 | .rx = imx_mu_specific_rx, |
1002 | .init = imx_mu_init_specific, |
1003 | .type = IMX_MU_V2 | IMX_MU_V2_S4 | IMX_MU_V2_IRQ, |
1004 | .xTR = 0x200, |
1005 | .xRR = 0x280, |
1006 | .xSR = {0xC, 0x118, 0x124, 0x12C}, |
1007 | .xCR = {0x8, 0x110, 0x114, 0x120, 0x128}, |
1008 | }; |
1009 | |
1010 | static const struct imx_mu_dcfg imx_mu_cfg_imx8_scu = { |
1011 | .tx = imx_mu_specific_tx, |
1012 | .rx = imx_mu_specific_rx, |
1013 | .init = imx_mu_init_specific, |
1014 | .rxdb = imx_mu_generic_rxdb, |
1015 | .xTR = 0x0, |
1016 | .xRR = 0x10, |
1017 | .xSR = {0x20, 0x20, 0x20, 0x20}, |
1018 | .xCR = {0x24, 0x24, 0x24, 0x24, 0x24}, |
1019 | }; |
1020 | |
1021 | static const struct imx_mu_dcfg imx_mu_cfg_imx8_seco = { |
1022 | .tx = imx_mu_seco_tx, |
1023 | .rx = imx_mu_generic_rx, |
1024 | .rxdb = imx_mu_seco_rxdb, |
1025 | .init = imx_mu_init_seco, |
1026 | .xTR = 0x0, |
1027 | .xRR = 0x10, |
1028 | .xSR = {0x20, 0x20, 0x20, 0x20}, |
1029 | .xCR = {0x24, 0x24, 0x24, 0x24, 0x24}, |
1030 | }; |
1031 | |
1032 | static const struct of_device_id imx_mu_dt_ids[] = { |
1033 | { .compatible = "fsl,imx7ulp-mu" , .data = &imx_mu_cfg_imx7ulp }, |
1034 | { .compatible = "fsl,imx6sx-mu" , .data = &imx_mu_cfg_imx6sx }, |
1035 | { .compatible = "fsl,imx8ulp-mu" , .data = &imx_mu_cfg_imx8ulp }, |
1036 | { .compatible = "fsl,imx8ulp-mu-s4" , .data = &imx_mu_cfg_imx8ulp_s4 }, |
1037 | { .compatible = "fsl,imx93-mu-s4" , .data = &imx_mu_cfg_imx93_s4 }, |
1038 | { .compatible = "fsl,imx95-mu" , .data = &imx_mu_cfg_imx8ulp }, |
1039 | { .compatible = "fsl,imx95-mu-ele" , .data = &imx_mu_cfg_imx8ulp_s4 }, |
1040 | { .compatible = "fsl,imx95-mu-v2x" , .data = &imx_mu_cfg_imx8ulp_s4 }, |
1041 | { .compatible = "fsl,imx8-mu-scu" , .data = &imx_mu_cfg_imx8_scu }, |
1042 | { .compatible = "fsl,imx8-mu-seco" , .data = &imx_mu_cfg_imx8_seco }, |
1043 | { }, |
1044 | }; |
1045 | MODULE_DEVICE_TABLE(of, imx_mu_dt_ids); |
1046 | |
1047 | static int __maybe_unused imx_mu_suspend_noirq(struct device *dev) |
1048 | { |
1049 | struct imx_mu_priv *priv = dev_get_drvdata(dev); |
1050 | int i; |
1051 | |
1052 | if (!priv->clk) { |
1053 | for (i = 0; i < IMX_MU_xCR_MAX; i++) |
1054 | priv->xcr[i] = imx_mu_read(priv, offs: priv->dcfg->xCR[i]); |
1055 | } |
1056 | |
1057 | priv->suspend = true; |
1058 | |
1059 | return 0; |
1060 | } |
1061 | |
1062 | static int __maybe_unused imx_mu_resume_noirq(struct device *dev) |
1063 | { |
1064 | struct imx_mu_priv *priv = dev_get_drvdata(dev); |
1065 | int i; |
1066 | |
1067 | /* |
1068 | * ONLY restore MU when context lost, the TIE could |
1069 | * be set during noirq resume as there is MU data |
1070 | * communication going on, and restore the saved |
1071 | * value will overwrite the TIE and cause MU data |
1072 | * send failed, may lead to system freeze. This issue |
1073 | * is observed by testing freeze mode suspend. |
1074 | */ |
1075 | if (!priv->clk && !imx_mu_read(priv, offs: priv->dcfg->xCR[0])) { |
1076 | for (i = 0; i < IMX_MU_xCR_MAX; i++) |
1077 | imx_mu_write(priv, val: priv->xcr[i], offs: priv->dcfg->xCR[i]); |
1078 | } |
1079 | |
1080 | priv->suspend = false; |
1081 | |
1082 | return 0; |
1083 | } |
1084 | |
1085 | static int __maybe_unused imx_mu_runtime_suspend(struct device *dev) |
1086 | { |
1087 | struct imx_mu_priv *priv = dev_get_drvdata(dev); |
1088 | |
1089 | clk_disable_unprepare(clk: priv->clk); |
1090 | |
1091 | return 0; |
1092 | } |
1093 | |
1094 | static int __maybe_unused imx_mu_runtime_resume(struct device *dev) |
1095 | { |
1096 | struct imx_mu_priv *priv = dev_get_drvdata(dev); |
1097 | int ret; |
1098 | |
1099 | ret = clk_prepare_enable(clk: priv->clk); |
1100 | if (ret) |
1101 | dev_err(dev, "failed to enable clock\n" ); |
1102 | |
1103 | return ret; |
1104 | } |
1105 | |
1106 | static const struct dev_pm_ops imx_mu_pm_ops = { |
1107 | SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_mu_suspend_noirq, |
1108 | imx_mu_resume_noirq) |
1109 | SET_RUNTIME_PM_OPS(imx_mu_runtime_suspend, |
1110 | imx_mu_runtime_resume, NULL) |
1111 | }; |
1112 | |
1113 | static struct platform_driver imx_mu_driver = { |
1114 | .probe = imx_mu_probe, |
1115 | .remove_new = imx_mu_remove, |
1116 | .driver = { |
1117 | .name = "imx_mu" , |
1118 | .of_match_table = imx_mu_dt_ids, |
1119 | .pm = &imx_mu_pm_ops, |
1120 | }, |
1121 | }; |
1122 | module_platform_driver(imx_mu_driver); |
1123 | |
1124 | MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>" ); |
1125 | MODULE_DESCRIPTION("Message Unit driver for i.MX" ); |
1126 | MODULE_LICENSE("GPL v2" ); |
1127 | |