From a59ff42a9566045d42d16ff1c60acbaf7743b8c8 Mon Sep 17 00:00:00 2001 From: Henry Wang Date: Sun, 7 Mar 2021 20:11:07 +0800 Subject: [PATCH] aarch64: Add PL061 for device tree implementation This commit adds a new legacy device PL011 for the AArch64 device tree implementation. Signed-off-by: Henry Wang --- arch/src/aarch64/fdt.rs | 42 +++++++++++++++++++++++++++++ arch/src/aarch64/layout.rs | 1 + arch/src/lib.rs | 3 +++ devices/src/legacy/mod.rs | 2 ++ vmm/src/device_manager.rs | 55 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 103 insertions(+) diff --git a/arch/src/aarch64/fdt.rs b/arch/src/aarch64/fdt.rs index 2b03c3602..bd98cb0c2 100644 --- a/arch/src/aarch64/fdt.rs +++ b/arch/src/aarch64/fdt.rs @@ -30,6 +30,8 @@ const GIC_PHANDLE: u32 = 1; const MSI_PHANDLE: u32 = 2; // This is a value for uniquely identifying the FDT node containing the clock definition. const CLOCK_PHANDLE: u32 = 3; +// This is a value for uniquely identifying the FDT node containing the gpio controller. +const GPIO_PHANDLE: u32 = 4; // Read the documentation specified when appending the root node to the FDT. const ADDRESS_CELLS: u32 = 0x2; @@ -45,6 +47,10 @@ const GIC_FDT_IRQ_TYPE_PPI: u32 = 1; const IRQ_TYPE_EDGE_RISING: u32 = 1; const IRQ_TYPE_LEVEL_HI: u32 = 4; +// Keys and Buttons +// System Power Down +const KEY_POWER: u32 = 116; + // This links to libfdt which handles the creation of the binary blob // flattened device tree (fdt) that is passed to the kernel and indicates // the hardware configuration of the machine. @@ -520,6 +526,41 @@ fn create_rtc_node( Ok(()) } +fn create_gpio_node( + fdt: &mut Vec, + dev_info: &T, +) -> Result<()> { + // PL061 GPIO controller node + let compatible = b"arm,pl061\0arm,primecell\0"; + let gpio_reg_prop = generate_prop64(&[dev_info.addr(), dev_info.length()]); + let irq = generate_prop32(&[GIC_FDT_IRQ_TYPE_SPI, dev_info.irq(), IRQ_TYPE_EDGE_RISING]); + append_begin_node(fdt, &format!("pl061@{:x}", dev_info.addr()))?; + append_property(fdt, "compatible", compatible)?; + append_property(fdt, "reg", &gpio_reg_prop)?; + append_property(fdt, "interrupts", &irq)?; + append_property_null(fdt, "gpio-controller")?; + append_property_u32(fdt, "#gpio-cells", 2)?; + append_property_u32(fdt, "clocks", CLOCK_PHANDLE)?; + append_property_string(fdt, "clock-names", "apb_pclk")?; + append_property_u32(fdt, "phandle", GPIO_PHANDLE)?; + append_end_node(fdt)?; + + // gpio-keys node + append_begin_node(fdt, "/gpio-keys")?; + append_property_string(fdt, "compatible", "gpio-keys")?; + append_property_u32(fdt, "#size-cells", 0)?; + append_property_u32(fdt, "#address-cells", 1)?; + append_begin_node(fdt, "/gpio-keys/poweroff")?; + append_property_string(fdt, "label", "GPIO Key Poweroff")?; + append_property_u32(fdt, "linux,code", KEY_POWER)?; + let gpios = generate_prop32(&[GPIO_PHANDLE, 3, 0]); + append_property(fdt, "gpios", &gpios)?; + append_end_node(fdt)?; + append_end_node(fdt)?; + + Ok(()) +} + fn create_devices_node( fdt: &mut Vec, dev_info: &HashMap<(DeviceType, String), T, S>, @@ -529,6 +570,7 @@ fn create_devices_node create_gpio_node(fdt, info)?, DeviceType::RTC => create_rtc_node(fdt, info)?, DeviceType::Serial => create_serial_node(fdt, info)?, DeviceType::Virtio(_) => { diff --git a/arch/src/aarch64/layout.rs b/arch/src/aarch64/layout.rs index 16b559ac8..38f5aa019 100644 --- a/arch/src/aarch64/layout.rs +++ b/arch/src/aarch64/layout.rs @@ -51,6 +51,7 @@ pub const MAPPED_IO_START: u64 = 0x0900_0000; /// Space 0x0900_0000 ~ 0x1000_0000 is reserved for legacy devices. pub const LEGACY_SERIAL_MAPPED_IO_START: u64 = 0x0900_0000; pub const LEGACY_RTC_MAPPED_IO_START: u64 = 0x0901_0000; +pub const LEGACY_GPIO_MAPPED_IO_START: u64 = 0x0902_0000; /// Legacy space will be allocated at once whiling setting up legacy devices. pub const LEGACY_DEVICES_MAPPED_IO_SIZE: u64 = 0x0700_0000; diff --git a/arch/src/lib.rs b/arch/src/lib.rs index ef5810690..e6cccc7ca 100644 --- a/arch/src/lib.rs +++ b/arch/src/lib.rs @@ -129,6 +129,9 @@ pub enum DeviceType { /// Device Type: RTC. #[cfg(target_arch = "aarch64")] RTC, + /// Device Type: GPIO. + #[cfg(target_arch = "aarch64")] + GPIO, } /// Default (smallest) memory page size for the supported architectures. diff --git a/devices/src/legacy/mod.rs b/devices/src/legacy/mod.rs index 08eb7a56e..21e254d33 100644 --- a/devices/src/legacy/mod.rs +++ b/devices/src/legacy/mod.rs @@ -25,6 +25,8 @@ pub use self::fwdebug::FwDebugDevice; pub use self::i8042::I8042Device; pub use self::serial::Serial; +#[cfg(target_arch = "aarch64")] +pub use self::gpio_pl061::GPIO; #[cfg(target_arch = "aarch64")] pub use self::rtc_pl031::RTC; #[cfg(target_arch = "aarch64")] diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index 88c969585..119642813 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -118,6 +118,8 @@ const VFIO_DEVICE_NAME_PREFIX: &str = "_vfio"; const IOAPIC_DEVICE_NAME: &str = "_ioapic"; const SERIAL_DEVICE_NAME_PREFIX: &str = "_serial"; +#[cfg(target_arch = "aarch64")] +const GPIO_DEVICE_NAME_PREFIX: &str = "_gpio"; const CONSOLE_DEVICE_NAME: &str = "_console"; const DISK_DEVICE_NAME_PREFIX: &str = "_disk"; @@ -929,6 +931,10 @@ pub struct DeviceManager { // Possible handle to the virtio-balloon device virtio_mem_devices: Vec>>, + + #[cfg(target_arch = "aarch64")] + // GPIO device for AArch64 + gpio_device: Option>>, } impl DeviceManager { @@ -1015,6 +1021,8 @@ impl DeviceManager { serial_pty: None, console_pty: None, virtio_mem_devices: Vec::new(), + #[cfg(target_arch = "aarch64")] + gpio_device: None, }; let device_manager = Arc::new(Mutex::new(device_manager)); @@ -1547,6 +1555,53 @@ impl DeviceManager { }, ); + // Add a GPIO device + let id = String::from(GPIO_DEVICE_NAME_PREFIX); + let gpio_irq = self + .address_manager + .allocator + .lock() + .unwrap() + .allocate_irq() + .unwrap(); + + let interrupt_group = interrupt_manager + .create_group(LegacyIrqGroupConfig { + irq: gpio_irq as InterruptIndex, + }) + .map_err(DeviceManagerError::CreateInterruptGroup)?; + + let gpio_device = Arc::new(Mutex::new(devices::legacy::GPIO::new( + id.clone(), + interrupt_group, + ))); + + self.bus_devices + .push(Arc::clone(&gpio_device) as Arc>); + + let addr = GuestAddress(arch::layout::LEGACY_GPIO_MAPPED_IO_START); + + self.address_manager + .mmio_bus + .insert(gpio_device.clone(), addr.0, MMIO_LEN) + .map_err(DeviceManagerError::BusError)?; + + self.gpio_device = Some(gpio_device.clone()); + + self.id_to_dev_info.insert( + (DeviceType::GPIO, "gpio".to_string()), + MMIODeviceInfo { + addr: addr.0, + len: MMIO_LEN, + irq: gpio_irq, + }, + ); + + self.device_tree + .lock() + .unwrap() + .insert(id.clone(), device_node!(id, gpio_device)); + Ok(()) }