| // SPDX-License-Identifier: GPL-2.0 | |
| #include <linux/platform_device.h> | |
| #include <linux/interrupt.h> | |
| #include <linux/memblock.h> | |
| #include <asm/virt.h> | |
| #include <asm/irq.h> | |
| #define VIRTIO_BUS_NB 128 | |
| static struct platform_device * __init virt_virtio_init(unsigned int id) | |
| { | |
| const struct resource res[] = { | |
| DEFINE_RES_MEM(virt_bi_data.virtio.mmio + id * 0x200, 0x200), | |
| DEFINE_RES_IRQ(virt_bi_data.virtio.irq + id), | |
| }; | |
| return platform_device_register_simple("virtio-mmio", id, | |
| res, ARRAY_SIZE(res)); | |
| } | |
| static int __init virt_platform_init(void) | |
| { | |
| const struct resource goldfish_tty_res[] = { | |
| DEFINE_RES_MEM(virt_bi_data.tty.mmio, 1), | |
| DEFINE_RES_IRQ(virt_bi_data.tty.irq), | |
| }; | |
| /* this is the second gf-rtc, the first one is used by the scheduler */ | |
| const struct resource goldfish_rtc_res[] = { | |
| DEFINE_RES_MEM(virt_bi_data.rtc.mmio + 0x1000, 0x1000), | |
| DEFINE_RES_IRQ(virt_bi_data.rtc.irq + 1), | |
| }; | |
| const struct resource virt_ctrl_res[] = { | |
| DEFINE_RES_MEM(virt_bi_data.ctrl.mmio, 0x100), | |
| }; | |
| struct platform_device *pdev1, *pdev2, *pdev3; | |
| struct platform_device *pdevs[VIRTIO_BUS_NB]; | |
| unsigned int i; | |
| int ret = 0; | |
| if (!MACH_IS_VIRT) | |
| return -ENODEV; | |
| /* We need this to have DMA'able memory provided to goldfish-tty */ | |
| min_low_pfn = 0; | |
| pdev1 = platform_device_register_simple("goldfish_tty", | |
| PLATFORM_DEVID_NONE, | |
| goldfish_tty_res, | |
| ARRAY_SIZE(goldfish_tty_res)); | |
| if (IS_ERR(pdev1)) | |
| return PTR_ERR(pdev1); | |
| pdev2 = platform_device_register_simple("goldfish_rtc", | |
| PLATFORM_DEVID_NONE, | |
| goldfish_rtc_res, | |
| ARRAY_SIZE(goldfish_rtc_res)); | |
| if (IS_ERR(pdev2)) { | |
| ret = PTR_ERR(pdev2); | |
| goto err_unregister_tty; | |
| } | |
| pdev3 = platform_device_register_simple("qemu-virt-ctrl", | |
| PLATFORM_DEVID_NONE, | |
| virt_ctrl_res, | |
| ARRAY_SIZE(virt_ctrl_res)); | |
| if (IS_ERR(pdev3)) { | |
| ret = PTR_ERR(pdev3); | |
| goto err_unregister_rtc; | |
| } | |
| for (i = 0; i < VIRTIO_BUS_NB; i++) { | |
| pdevs[i] = virt_virtio_init(i); | |
| if (IS_ERR(pdevs[i])) { | |
| ret = PTR_ERR(pdevs[i]); | |
| goto err_unregister_virtio; | |
| } | |
| } | |
| return 0; | |
| err_unregister_virtio: | |
| while (i > 0) | |
| platform_device_unregister(pdevs[--i]); | |
| platform_device_unregister(pdev3); | |
| err_unregister_rtc: | |
| platform_device_unregister(pdev2); | |
| err_unregister_tty: | |
| platform_device_unregister(pdev1); | |
| return ret; | |
| } | |
| arch_initcall(virt_platform_init); |