1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Microchip's PolarFire SoC (MPFS) Mailbox Driver
4  *
5  * Copyright (C) 2024 Microchip Technology Inc. All rights reserved.
6  *
7  * Author: Jamie Gibbons <jamie.gibbons@microchip.com>
8  *
9  */
10 
11 #include <asm/io.h>
12 #include <dm.h>
13 #include <dm/device-internal.h>
14 #include <dm/device.h>
15 #include <dm/device_compat.h>
16 #include <dm/devres.h>
17 #include <dm/ofnode.h>
18 #include <linux/bitops.h>
19 #include <linux/compat.h>
20 #include <linux/io.h>
21 #include <linux/ioport.h>
22 #include <log.h>
23 #include <mailbox-uclass.h>
24 #include <malloc.h>
25 #include <mpfs-mailbox.h>
26 
27 #define SERVICES_CR_OFFSET 0x50u
28 #define SERVICES_SR_OFFSET 0x54u
29 
30 #define SERVICE_CR_REQ_MASK 0x1u
31 #define SERVICE_SR_BUSY_MASK 0x2u
32 #define SERVICE_SR_STATUS_SHIFT 16
33 #define SERVICE_CR_COMMAND_SHIFT 16
34 #define MASK_8BIT 0xFF
35 
36 struct mpfs_mbox {
37 	struct udevice *dev;
38 	void __iomem *ctrl_base;
39 	void __iomem *mbox_base;
40 	struct mbox_chan *chan;
41 };
42 
mpfs_mbox_busy(struct mbox_chan * chan)43 static bool mpfs_mbox_busy(struct mbox_chan *chan)
44 {
45 	struct mpfs_mbox *mbox = dev_get_priv(chan->dev);
46 	uint16_t status;
47 
48 	status = readl(mbox->ctrl_base + SERVICES_SR_OFFSET);
49 
50 	return status & SERVICE_SR_BUSY_MASK;
51 }
52 
mpfs_mbox_send(struct mbox_chan * chan,const void * data)53 static int mpfs_mbox_send(struct mbox_chan *chan, const void *data)
54 {
55 	struct mpfs_mbox *mbox = dev_get_priv(chan->dev);
56 	struct mpfs_mss_msg *msg = (struct mpfs_mss_msg *)data;
57 	u32 mailbox_val, cmd_shifted, value;
58 	u8 *byte_buf;
59 	u8 idx, byte_idx, byte_offset;
60 
61 	u32 *word_buf = (u32 *)msg->cmd_data;
62 
63 	if (mpfs_mbox_busy(chan))
64 		return -EBUSY;
65 
66 	for (idx = 0; idx < (msg->cmd_data_size / BYTES_4); idx++)
67 		writel(word_buf[idx], mbox->mbox_base + msg->mbox_offset + idx * BYTES_4);
68 
69 	if ((msg->cmd_data_size % BYTES_4) > 0) {
70 		byte_offset = (msg->cmd_data_size / BYTES_4) * BYTES_4;
71 		byte_buf = (u8 *)(msg->cmd_data + byte_offset);
72 		mailbox_val = readl(mbox->mbox_base + msg->mbox_offset + idx * BYTES_4);
73 
74 		for (byte_idx = 0; byte_idx < (msg->cmd_data_size % BYTES_4); byte_idx++) {
75 			mailbox_val &= ~(MASK_8BIT << (byte_idx * 0x8u));
76 			mailbox_val |= (u32)byte_buf[byte_idx] << (byte_idx * 0x8u);
77 		}
78 		writel(mailbox_val, mbox->mbox_base + msg->mbox_offset + idx * BYTES_4);
79 	}
80 
81 	cmd_shifted = msg->cmd_opcode << SERVICE_CR_COMMAND_SHIFT;
82 	cmd_shifted |= SERVICE_CR_REQ_MASK;
83 	writel(cmd_shifted, mbox->ctrl_base + SERVICES_CR_OFFSET);
84 
85 	do {
86 		value = readl(mbox->ctrl_base + SERVICES_CR_OFFSET);
87 	} while (SERVICE_CR_REQ_MASK == (value & SERVICE_CR_REQ_MASK));
88 
89 	do {
90 		value = readl(mbox->ctrl_base + SERVICES_SR_OFFSET);
91 	} while (SERVICE_SR_BUSY_MASK == (value & SERVICE_SR_BUSY_MASK));
92 
93 	msg->response->resp_status = (value >> SERVICE_SR_STATUS_SHIFT);
94 	if (msg->response->resp_status)
95 		return -EBADMSG;
96 
97 	return 0;
98 }
99 
mpfs_mbox_recv(struct mbox_chan * chan,void * data)100 static int mpfs_mbox_recv(struct mbox_chan *chan, void *data)
101 {
102 	struct mpfs_mbox *mbox = dev_get_priv(chan->dev);
103 	struct mpfs_mss_msg *msg = data;
104 	struct mpfs_mss_response *response = msg->response;
105 	u8 idx;
106 
107 	if (!response->resp_msg) {
108 		dev_err(chan->dev, "failed to assign memory for response %d\n", -ENOMEM);
109 		return -EINVAL;
110 	}
111 
112 	if (mpfs_mbox_busy(chan)) {
113 		dev_err(chan->dev, "mailbox is busy\n");
114 		response->resp_status = 0xDEAD;
115 		return -EINVAL;
116 	}
117 
118 	for (idx = 0; idx < response->resp_size; idx++)
119 		*((u8 *)(response->resp_msg) + idx) = readb(mbox->mbox_base + msg->resp_offset  + idx);
120 
121 	return 0;
122 }
123 
124 static const struct mbox_ops mpfs_mbox_ops = {
125 	.send = mpfs_mbox_send,
126 	.recv = mpfs_mbox_recv,
127 };
128 
mpfs_mbox_probe(struct udevice * dev)129 static int mpfs_mbox_probe(struct udevice *dev)
130 {
131 	struct mpfs_mbox *mbox;
132 	struct resource regs;
133 	ofnode node;
134 	int ret;
135 
136 	node = dev_ofnode(dev);
137 
138 	mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
139 	if (!mbox)
140 		return -ENOMEM;
141 
142 	ret = ofnode_read_resource(node, 0, &regs);
143 	if (ret) {
144 		dev_err(dev, "No reg property for controller base\n");
145 		return ret;
146 	};
147 
148 	mbox->ctrl_base = devm_ioremap(dev, regs.start, regs.start - regs.end);
149 
150 	ret = ofnode_read_resource(node, 2, &regs);
151 	if (ret) {
152 		dev_err(dev, "No reg property for mailbox base\n");
153 		return ret;
154 	};
155 
156 	mbox->mbox_base = devm_ioremap(dev, regs.start, regs.start - regs.end);
157 
158 	mbox->dev = dev;
159 	dev_set_priv(dev, mbox);
160 	mbox->chan->con_priv = mbox;
161 
162 	return 0;
163 }
164 
165 static const struct udevice_id mpfs_mbox_ids[] = {
166 	{.compatible = "microchip,mpfs-mailbox"},
167 	{ }
168 };
169 
170 U_BOOT_DRIVER(mpfs_mbox) = {
171 	.name = "mpfs-mbox",
172 	.id = UCLASS_MAILBOX,
173 	.of_match = mpfs_mbox_ids,
174 	.probe = mpfs_mbox_probe,
175 	.priv_auto = sizeof(struct mpfs_mbox),
176 	.ops = &mpfs_mbox_ops,
177 };
178