blob: c181a7b817682c597f79ed62c112a9e845a0ea91 [file] [log] [blame]
Ibai Erkiaga660b0c72019-09-27 11:36:56 +01001// 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
22struct 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
33struct 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
40static 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
61static 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
74static 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
117static const struct udevice_id zynqmp_ipi_ids[] = {
118 { .compatible = "xlnx,zynqmp-ipi-mailbox" },
119 { }
120};
121
122struct mbox_ops zynqmp_ipi_mbox_ops = {
123 .send = zynqmp_ipi_send,
124 .recv = zynqmp_ipi_recv,
125};
126
127U_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};