Merge tag 'xilinx-for-v2020.01' of https://gitlab.denx.de/u-boot/custodians/u-boot...
[platform/kernel/u-boot.git] / drivers / mailbox / zynqmp-ipi.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Xilinx Zynq MPSoC Mailbox driver
4  *
5  * Copyright (C) 2018-2019 Xilinx, Inc.
6  */
7
8 #include <common.h>
9 #include <asm/io.h>
10 #include <dm.h>
11 #include <mailbox-uclass.h>
12 #include <mach/sys_proto.h>
13 #include <linux/ioport.h>
14 #include <linux/io.h>
15 #include <wait_bit.h>
16
17 /* IPI bitmasks, register base */
18 /* TODO: move reg base to DT */
19 #define IPI_BIT_MASK_PMU0     0x10000
20 #define IPI_INT_REG_BASE_APU  0xFF300000
21
22 struct ipi_int_regs {
23         u32 trig; /* 0x0  */
24         u32 obs;  /* 0x4  */
25         u32 ist;  /* 0x8  */
26         u32 imr;  /* 0xC  */
27         u32 ier;  /* 0x10 */
28         u32 idr;  /* 0x14 */
29 };
30
31 #define ipi_int_apu ((struct ipi_int_regs *)IPI_INT_REG_BASE_APU)
32
33 struct zynqmp_ipi {
34         void __iomem *local_req_regs;
35         void __iomem *local_res_regs;
36         void __iomem *remote_req_regs;
37         void __iomem *remote_res_regs;
38 };
39
40 static int zynqmp_ipi_send(struct mbox_chan *chan, const void *data)
41 {
42         const struct zynqmp_ipi_msg *msg = (struct zynqmp_ipi_msg *)data;
43         struct zynqmp_ipi *zynqmp = dev_get_priv(chan->dev);
44         u32 ret;
45         u32 *mbx = (u32 *)zynqmp->local_req_regs;
46
47         for (size_t i = 0; i < msg->len; i++)
48                 writel(msg->buf[i], &mbx[i]);
49
50         /* Write trigger interrupt */
51         writel(IPI_BIT_MASK_PMU0, &ipi_int_apu->trig);
52
53         /* Wait until observation bit is cleared */
54         ret = wait_for_bit_le32(&ipi_int_apu->obs, IPI_BIT_MASK_PMU0, false,
55                                 100, false);
56
57         debug("%s, send %ld bytes\n", __func__, msg->len);
58         return ret;
59 };
60
61 static int zynqmp_ipi_recv(struct mbox_chan *chan, void *data)
62 {
63         struct zynqmp_ipi_msg *msg = (struct zynqmp_ipi_msg *)data;
64         struct zynqmp_ipi *zynqmp = dev_get_priv(chan->dev);
65         u32 *mbx = (u32 *)zynqmp->local_res_regs;
66
67         for (size_t i = 0; i < msg->len; i++)
68                 msg->buf[i] = readl(&mbx[i]);
69
70         debug("%s, recv %ld bytes\n", __func__, msg->len);
71         return 0;
72 };
73
74 static int zynqmp_ipi_probe(struct udevice *dev)
75 {
76         struct zynqmp_ipi *zynqmp = dev_get_priv(dev);
77         struct resource res;
78         ofnode node;
79
80         debug("%s(dev=%p)\n", __func__, dev);
81
82         /* Get subnode where the regs are defined */
83         /* Note IPI mailbox node needs to be the first one in DT */
84         node = ofnode_first_subnode(dev_ofnode(dev));
85
86         if (ofnode_read_resource_byname(node, "local_request_region", &res)) {
87                 dev_err(dev, "No reg property for local_request_region\n");
88                 return -EINVAL;
89         };
90         zynqmp->local_req_regs = devm_ioremap(dev, res.start,
91                                               (res.start - res.end));
92
93         if (ofnode_read_resource_byname(node, "local_response_region", &res)) {
94                 dev_err(dev, "No reg property for local_response_region\n");
95                 return -EINVAL;
96         };
97         zynqmp->local_res_regs = devm_ioremap(dev, res.start,
98                                               (res.start - res.end));
99
100         if (ofnode_read_resource_byname(node, "remote_request_region", &res)) {
101                 dev_err(dev, "No reg property for remote_request_region\n");
102                 return -EINVAL;
103         };
104         zynqmp->remote_req_regs = devm_ioremap(dev, res.start,
105                                                (res.start - res.end));
106
107         if (ofnode_read_resource_byname(node, "remote_response_region", &res)) {
108                 dev_err(dev, "No reg property for remote_response_region\n");
109                 return -EINVAL;
110         };
111         zynqmp->remote_res_regs = devm_ioremap(dev, res.start,
112                                                (res.start - res.end));
113
114         return 0;
115 };
116
117 static const struct udevice_id zynqmp_ipi_ids[] = {
118         { .compatible = "xlnx,zynqmp-ipi-mailbox" },
119         { }
120 };
121
122 struct mbox_ops zynqmp_ipi_mbox_ops = {
123         .send = zynqmp_ipi_send,
124         .recv = zynqmp_ipi_recv,
125 };
126
127 U_BOOT_DRIVER(zynqmp_ipi) = {
128         .name = "zynqmp-ipi",
129         .id = UCLASS_MAILBOX,
130         .of_match = zynqmp_ipi_ids,
131         .probe = zynqmp_ipi_probe,
132         .priv_auto_alloc_size = sizeof(struct zynqmp_ipi),
133         .ops = &zynqmp_ipi_mbox_ops,
134 };