1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
4 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
5 *
6 * VirtIO memory-maped I/O transport driver
7 * Ported from Linux drivers/virtio/virtio_mmio.c
8 */
9
10#include <common.h>
11#include <dm.h>
12#include <log.h>
13#include <virtio_types.h>
14#include <virtio.h>
15#include <virtio_ring.h>
16#include <linux/bug.h>
17#include <linux/compat.h>
18#include <linux/err.h>
19#include <linux/io.h>
20#include "virtio_mmio.h"
21
22static int virtio_mmio_get_config(struct udevice *udev, unsigned int offset,
23				  void *buf, unsigned int len)
24{
25	struct virtio_mmio_priv *priv = dev_get_priv(udev);
26	void __iomem *base = priv->base + VIRTIO_MMIO_CONFIG;
27	u8 b;
28	__le16 w;
29	__le32 l;
30
31	if (priv->version == 1) {
32		u8 *ptr = buf;
33		int i;
34
35		for (i = 0; i < len; i++)
36			ptr[i] = readb(base + offset + i);
37
38		return 0;
39	}
40
41	switch (len) {
42	case 1:
43		b = readb(base + offset);
44		memcpy(buf, &b, sizeof(b));
45		break;
46	case 2:
47		w = cpu_to_le16(readw(base + offset));
48		memcpy(buf, &w, sizeof(w));
49		break;
50	case 4:
51		l = cpu_to_le32(readl(base + offset));
52		memcpy(buf, &l, sizeof(l));
53		break;
54	case 8:
55		l = cpu_to_le32(readl(base + offset));
56		memcpy(buf, &l, sizeof(l));
57		l = cpu_to_le32(readl(base + offset + sizeof(l)));
58		memcpy(buf + sizeof(l), &l, sizeof(l));
59		break;
60	default:
61		WARN_ON(true);
62	}
63
64	return 0;
65}
66
67static int virtio_mmio_set_config(struct udevice *udev, unsigned int offset,
68				  const void *buf, unsigned int len)
69{
70	struct virtio_mmio_priv *priv = dev_get_priv(udev);
71	void __iomem *base = priv->base + VIRTIO_MMIO_CONFIG;
72	u8 b;
73	__le16 w;
74	__le32 l;
75
76	if (priv->version == 1) {
77		const u8 *ptr = buf;
78		int i;
79
80		for (i = 0; i < len; i++)
81			writeb(ptr[i], base + offset + i);
82
83		return 0;
84	}
85
86	switch (len) {
87	case 1:
88		memcpy(&b, buf, sizeof(b));
89		writeb(b, base + offset);
90		break;
91	case 2:
92		memcpy(&w, buf, sizeof(w));
93		writew(le16_to_cpu(w), base + offset);
94		break;
95	case 4:
96		memcpy(&l, buf, sizeof(l));
97		writel(le32_to_cpu(l), base + offset);
98		break;
99	case 8:
100		memcpy(&l, buf, sizeof(l));
101		writel(le32_to_cpu(l), base + offset);
102		memcpy(&l, buf + sizeof(l), sizeof(l));
103		writel(le32_to_cpu(l), base + offset + sizeof(l));
104		break;
105	default:
106		WARN_ON(true);
107	}
108
109	return 0;
110}
111
112static int virtio_mmio_generation(struct udevice *udev, u32 *counter)
113{
114	struct virtio_mmio_priv *priv = dev_get_priv(udev);
115
116	if (priv->version == 1)
117		*counter = 0;
118	else
119		*counter = readl(priv->base + VIRTIO_MMIO_CONFIG_GENERATION);
120
121	return 0;
122}
123
124static int virtio_mmio_get_status(struct udevice *udev, u8 *status)
125{
126	struct virtio_mmio_priv *priv = dev_get_priv(udev);
127
128	*status = readl(priv->base + VIRTIO_MMIO_STATUS) & 0xff;
129
130	return 0;
131}
132
133static int virtio_mmio_set_status(struct udevice *udev, u8 status)
134{
135	struct virtio_mmio_priv *priv = dev_get_priv(udev);
136
137	/* We should never be setting status to 0 */
138	WARN_ON(status == 0);
139
140	writel(status, priv->base + VIRTIO_MMIO_STATUS);
141
142	return 0;
143}
144
145static int virtio_mmio_reset(struct udevice *udev)
146{
147	struct virtio_mmio_priv *priv = dev_get_priv(udev);
148
149	/* 0 status means a reset */
150	writel(0, priv->base + VIRTIO_MMIO_STATUS);
151
152	return 0;
153}
154
155static int virtio_mmio_get_features(struct udevice *udev, u64 *features)
156{
157	struct virtio_mmio_priv *priv = dev_get_priv(udev);
158
159	writel(1, priv->base + VIRTIO_MMIO_DEVICE_FEATURES_SEL);
160	*features = readl(priv->base + VIRTIO_MMIO_DEVICE_FEATURES);
161	*features <<= 32;
162
163	writel(0, priv->base + VIRTIO_MMIO_DEVICE_FEATURES_SEL);
164	*features |= readl(priv->base + VIRTIO_MMIO_DEVICE_FEATURES);
165
166	return 0;
167}
168
169static int virtio_mmio_set_features(struct udevice *udev)
170{
171	struct virtio_mmio_priv *priv = dev_get_priv(udev);
172	struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
173
174	/* Make sure there is are no mixed devices */
175	if (priv->version == 2 && uc_priv->legacy) {
176		debug("New virtio-mmio devices (version 2) must provide VIRTIO_F_VERSION_1 feature!\n");
177		return -EINVAL;
178	}
179
180	writel(1, priv->base + VIRTIO_MMIO_DRIVER_FEATURES_SEL);
181	writel((u32)(uc_priv->features >> 32),
182	       priv->base + VIRTIO_MMIO_DRIVER_FEATURES);
183
184	writel(0, priv->base + VIRTIO_MMIO_DRIVER_FEATURES_SEL);
185	writel((u32)uc_priv->features,
186	       priv->base + VIRTIO_MMIO_DRIVER_FEATURES);
187
188	return 0;
189}
190
191static struct virtqueue *virtio_mmio_setup_vq(struct udevice *udev,
192					      unsigned int index)
193{
194	struct virtio_mmio_priv *priv = dev_get_priv(udev);
195	struct virtqueue *vq;
196	unsigned int num;
197	int err;
198
199	/* Select the queue we're interested in */
200	writel(index, priv->base + VIRTIO_MMIO_QUEUE_SEL);
201
202	/* Queue shouldn't already be set up */
203	if (readl(priv->base + (priv->version == 1 ?
204	    VIRTIO_MMIO_QUEUE_PFN : VIRTIO_MMIO_QUEUE_READY))) {
205		err = -ENOENT;
206		goto error_available;
207	}
208
209	num = readl(priv->base + VIRTIO_MMIO_QUEUE_NUM_MAX);
210	if (num == 0) {
211		err = -ENOENT;
212		goto error_new_virtqueue;
213	}
214
215	/* Create the vring */
216	vq = vring_create_virtqueue(index, num, VIRTIO_MMIO_VRING_ALIGN, udev);
217	if (!vq) {
218		err = -ENOMEM;
219		goto error_new_virtqueue;
220	}
221
222	/* Activate the queue */
223	writel(virtqueue_get_vring_size(vq),
224	       priv->base + VIRTIO_MMIO_QUEUE_NUM);
225	if (priv->version == 1) {
226		u64 q_pfn = virtqueue_get_desc_addr(vq) >> PAGE_SHIFT;
227
228		/*
229		 * virtio-mmio v1 uses a 32bit QUEUE PFN. If we have something
230		 * that doesn't fit in 32bit, fail the setup rather than
231		 * pretending to be successful.
232		 */
233		if (q_pfn >> 32) {
234			debug("platform bug: legacy virtio-mmio must not be used with RAM above 0x%llxGB\n",
235			      0x1ULL << (32 + PAGE_SHIFT - 30));
236			err = -E2BIG;
237			goto error_bad_pfn;
238		}
239
240		writel(PAGE_SIZE, priv->base + VIRTIO_MMIO_QUEUE_ALIGN);
241		writel(q_pfn, priv->base + VIRTIO_MMIO_QUEUE_PFN);
242	} else {
243		u64 addr;
244
245		addr = virtqueue_get_desc_addr(vq);
246		writel((u32)addr, priv->base + VIRTIO_MMIO_QUEUE_DESC_LOW);
247		writel((u32)(addr >> 32),
248		       priv->base + VIRTIO_MMIO_QUEUE_DESC_HIGH);
249
250		addr = virtqueue_get_avail_addr(vq);
251		writel((u32)addr, priv->base + VIRTIO_MMIO_QUEUE_AVAIL_LOW);
252		writel((u32)(addr >> 32),
253		       priv->base + VIRTIO_MMIO_QUEUE_AVAIL_HIGH);
254
255		addr = virtqueue_get_used_addr(vq);
256		writel((u32)addr, priv->base + VIRTIO_MMIO_QUEUE_USED_LOW);
257		writel((u32)(addr >> 32),
258		       priv->base + VIRTIO_MMIO_QUEUE_USED_HIGH);
259
260		writel(1, priv->base + VIRTIO_MMIO_QUEUE_READY);
261	}
262
263	return vq;
264
265error_bad_pfn:
266	vring_del_virtqueue(vq);
267
268error_new_virtqueue:
269	if (priv->version == 1) {
270		writel(0, priv->base + VIRTIO_MMIO_QUEUE_PFN);
271	} else {
272		writel(0, priv->base + VIRTIO_MMIO_QUEUE_READY);
273		WARN_ON(readl(priv->base + VIRTIO_MMIO_QUEUE_READY));
274	}
275
276error_available:
277	return ERR_PTR(err);
278}
279
280static void virtio_mmio_del_vq(struct virtqueue *vq)
281{
282	struct virtio_mmio_priv *priv = dev_get_priv(vq->vdev);
283	unsigned int index = vq->index;
284
285	/* Select and deactivate the queue */
286	writel(index, priv->base + VIRTIO_MMIO_QUEUE_SEL);
287	if (priv->version == 1) {
288		writel(0, priv->base + VIRTIO_MMIO_QUEUE_PFN);
289	} else {
290		writel(0, priv->base + VIRTIO_MMIO_QUEUE_READY);
291		WARN_ON(readl(priv->base + VIRTIO_MMIO_QUEUE_READY));
292	}
293
294	vring_del_virtqueue(vq);
295}
296
297static int virtio_mmio_del_vqs(struct udevice *udev)
298{
299	struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
300	struct virtqueue *vq, *n;
301
302	list_for_each_entry_safe(vq, n, &uc_priv->vqs, list)
303		virtio_mmio_del_vq(vq);
304
305	return 0;
306}
307
308static int virtio_mmio_find_vqs(struct udevice *udev, unsigned int nvqs,
309				struct virtqueue *vqs[])
310{
311	int i;
312
313	for (i = 0; i < nvqs; ++i) {
314		vqs[i] = virtio_mmio_setup_vq(udev, i);
315		if (IS_ERR(vqs[i])) {
316			virtio_mmio_del_vqs(udev);
317			return PTR_ERR(vqs[i]);
318		}
319	}
320
321	return 0;
322}
323
324static int virtio_mmio_notify(struct udevice *udev, struct virtqueue *vq)
325{
326	struct virtio_mmio_priv *priv = dev_get_priv(udev);
327
328	/*
329	 * We write the queue's selector into the notification register
330	 * to signal the other end
331	 */
332	writel(vq->index, priv->base + VIRTIO_MMIO_QUEUE_NOTIFY);
333
334	return 0;
335}
336
337static int virtio_mmio_of_to_plat(struct udevice *udev)
338{
339	struct virtio_mmio_priv *priv = dev_get_priv(udev);
340
341	priv->base = (void __iomem *)(ulong)dev_read_addr(udev);
342	if (priv->base == (void __iomem *)FDT_ADDR_T_NONE)
343		return -EINVAL;
344
345	return 0;
346}
347
348static int virtio_mmio_probe(struct udevice *udev)
349{
350	struct virtio_mmio_priv *priv = dev_get_priv(udev);
351	struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
352	u32 magic;
353
354	/* Check magic value */
355	magic = readl(priv->base + VIRTIO_MMIO_MAGIC_VALUE);
356	if (magic != ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)) {
357		debug("(%s): wrong magic value 0x%08x!\n", udev->name, magic);
358		return 0;
359	}
360
361	/* Check device version */
362	priv->version = readl(priv->base + VIRTIO_MMIO_VERSION);
363	if (priv->version < 1 || priv->version > 2) {
364		debug("(%s): version %d not supported!\n",
365		      udev->name, priv->version);
366		return 0;
367	}
368
369	/* Check device ID */
370	uc_priv->device = readl(priv->base + VIRTIO_MMIO_DEVICE_ID);
371	if (uc_priv->device == 0) {
372		/*
373		 * virtio-mmio device with an ID 0 is a (dummy) placeholder
374		 * with no function. End probing now with no error reported.
375		 */
376		return 0;
377	}
378	uc_priv->vendor = readl(priv->base + VIRTIO_MMIO_VENDOR_ID);
379
380	if (priv->version == 1)
381		writel(PAGE_SIZE, priv->base + VIRTIO_MMIO_GUEST_PAGE_SIZE);
382
383	debug("(%s): device (%d) vendor (%08x) version (%d)\n", udev->name,
384	      uc_priv->device, uc_priv->vendor, priv->version);
385
386	return 0;
387}
388
389static const struct dm_virtio_ops virtio_mmio_ops = {
390	.get_config	= virtio_mmio_get_config,
391	.set_config	= virtio_mmio_set_config,
392	.generation	= virtio_mmio_generation,
393	.get_status	= virtio_mmio_get_status,
394	.set_status	= virtio_mmio_set_status,
395	.reset		= virtio_mmio_reset,
396	.get_features	= virtio_mmio_get_features,
397	.set_features	= virtio_mmio_set_features,
398	.find_vqs	= virtio_mmio_find_vqs,
399	.del_vqs	= virtio_mmio_del_vqs,
400	.notify		= virtio_mmio_notify,
401};
402
403static const struct udevice_id virtio_mmio_ids[] = {
404	{ .compatible = "virtio,mmio" },
405	{ }
406};
407
408U_BOOT_DRIVER(virtio_mmio) = {
409	.name	= "virtio-mmio",
410	.id	= UCLASS_VIRTIO,
411	.of_match = virtio_mmio_ids,
412	.ops	= &virtio_mmio_ops,
413	.probe	= virtio_mmio_probe,
414	.of_to_plat = virtio_mmio_of_to_plat,
415	.priv_auto	= sizeof(struct virtio_mmio_priv),
416};
417