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 <Henry.Wang@arm.com>
This commit is contained in:
Henry Wang 2021-03-07 20:11:07 +08:00 committed by Michael
parent 7c86ef8a69
commit a59ff42a95
5 changed files with 103 additions and 0 deletions

View File

@ -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<T: DeviceInfoForFDT + Clone + Debug>(
Ok(())
}
fn create_gpio_node<T: DeviceInfoForFDT + Clone + Debug>(
fdt: &mut Vec<u8>,
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<T: DeviceInfoForFDT + Clone + Debug, S: ::std::hash::BuildHasher>(
fdt: &mut Vec<u8>,
dev_info: &HashMap<(DeviceType, String), T, S>,
@ -529,6 +570,7 @@ fn create_devices_node<T: DeviceInfoForFDT + Clone + Debug, S: ::std::hash::Buil
for ((device_type, _device_id), info) in dev_info {
match device_type {
DeviceType::GPIO => create_gpio_node(fdt, info)?,
DeviceType::RTC => create_rtc_node(fdt, info)?,
DeviceType::Serial => create_serial_node(fdt, info)?,
DeviceType::Virtio(_) => {

View File

@ -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;

View File

@ -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.

View File

@ -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")]

View File

@ -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<Arc<Mutex<virtio_devices::Mem>>>,
#[cfg(target_arch = "aarch64")]
// GPIO device for AArch64
gpio_device: Option<Arc<Mutex<devices::legacy::GPIO>>>,
}
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<Mutex<dyn BusDevice>>);
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(())
}