162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#include <linux/platform_device.h>
462306a36Sopenharmony_ci#include <linux/interrupt.h>
562306a36Sopenharmony_ci#include <linux/memblock.h>
662306a36Sopenharmony_ci#include <asm/virt.h>
762306a36Sopenharmony_ci#include <asm/irq.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#define VIRTIO_BUS_NB	128
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_cistatic struct platform_device * __init virt_virtio_init(unsigned int id)
1262306a36Sopenharmony_ci{
1362306a36Sopenharmony_ci	const struct resource res[] = {
1462306a36Sopenharmony_ci		DEFINE_RES_MEM(virt_bi_data.virtio.mmio + id * 0x200, 0x200),
1562306a36Sopenharmony_ci		DEFINE_RES_IRQ(virt_bi_data.virtio.irq + id),
1662306a36Sopenharmony_ci	};
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci	return platform_device_register_simple("virtio-mmio", id,
1962306a36Sopenharmony_ci					       res, ARRAY_SIZE(res));
2062306a36Sopenharmony_ci}
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic int __init virt_platform_init(void)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci	const struct resource goldfish_tty_res[] = {
2562306a36Sopenharmony_ci		DEFINE_RES_MEM(virt_bi_data.tty.mmio, 1),
2662306a36Sopenharmony_ci		DEFINE_RES_IRQ(virt_bi_data.tty.irq),
2762306a36Sopenharmony_ci	};
2862306a36Sopenharmony_ci	/* this is the second gf-rtc, the first one is used by the scheduler */
2962306a36Sopenharmony_ci	const struct resource goldfish_rtc_res[] = {
3062306a36Sopenharmony_ci		DEFINE_RES_MEM(virt_bi_data.rtc.mmio + 0x1000, 0x1000),
3162306a36Sopenharmony_ci		DEFINE_RES_IRQ(virt_bi_data.rtc.irq + 1),
3262306a36Sopenharmony_ci	};
3362306a36Sopenharmony_ci	struct platform_device *pdev1, *pdev2;
3462306a36Sopenharmony_ci	struct platform_device *pdevs[VIRTIO_BUS_NB];
3562306a36Sopenharmony_ci	unsigned int i;
3662306a36Sopenharmony_ci	int ret = 0;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	if (!MACH_IS_VIRT)
3962306a36Sopenharmony_ci		return -ENODEV;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	/* We need this to have DMA'able memory provided to goldfish-tty */
4262306a36Sopenharmony_ci	min_low_pfn = 0;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	pdev1 = platform_device_register_simple("goldfish_tty",
4562306a36Sopenharmony_ci						PLATFORM_DEVID_NONE,
4662306a36Sopenharmony_ci						goldfish_tty_res,
4762306a36Sopenharmony_ci						ARRAY_SIZE(goldfish_tty_res));
4862306a36Sopenharmony_ci	if (IS_ERR(pdev1))
4962306a36Sopenharmony_ci		return PTR_ERR(pdev1);
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	pdev2 = platform_device_register_simple("goldfish_rtc",
5262306a36Sopenharmony_ci						PLATFORM_DEVID_NONE,
5362306a36Sopenharmony_ci						goldfish_rtc_res,
5462306a36Sopenharmony_ci						ARRAY_SIZE(goldfish_rtc_res));
5562306a36Sopenharmony_ci	if (IS_ERR(pdev2)) {
5662306a36Sopenharmony_ci		ret = PTR_ERR(pdev2);
5762306a36Sopenharmony_ci		goto err_unregister_tty;
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	for (i = 0; i < VIRTIO_BUS_NB; i++) {
6162306a36Sopenharmony_ci		pdevs[i] = virt_virtio_init(i);
6262306a36Sopenharmony_ci		if (IS_ERR(pdevs[i])) {
6362306a36Sopenharmony_ci			ret = PTR_ERR(pdevs[i]);
6462306a36Sopenharmony_ci			goto err_unregister_rtc_virtio;
6562306a36Sopenharmony_ci		}
6662306a36Sopenharmony_ci	}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	return 0;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cierr_unregister_rtc_virtio:
7162306a36Sopenharmony_ci	while (i > 0)
7262306a36Sopenharmony_ci		platform_device_unregister(pdevs[--i]);
7362306a36Sopenharmony_ci	platform_device_unregister(pdev2);
7462306a36Sopenharmony_cierr_unregister_tty:
7562306a36Sopenharmony_ci	platform_device_unregister(pdev1);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	return ret;
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ciarch_initcall(virt_platform_init);
81