From 3c1a1b24bcebe56d1e36d8ed92fb531efe9d49d0 Mon Sep 17 00:00:00 2001 From: Terry She Date: Tue, 2 Jan 2024 20:46:51 +0800 Subject: [PATCH 1/2] run bcm2835_gpio_rust in qemu identified, cannot run on rpi4b --- drivers/pinctrl/bcm/Kconfig | 12 + drivers/pinctrl/bcm/Makefile | 3 + drivers/pinctrl/bcm/pinctrl_bcm2835_rust.rs | 268 ++++++++++++++++++++ rust/kernel/platform.rs | 12 + 4 files changed, 295 insertions(+) create mode 100644 drivers/pinctrl/bcm/pinctrl_bcm2835_rust.rs diff --git a/drivers/pinctrl/bcm/Kconfig b/drivers/pinctrl/bcm/Kconfig index 35b51ce4298e25..fb36a760202ac7 100644 --- a/drivers/pinctrl/bcm/Kconfig +++ b/drivers/pinctrl/bcm/Kconfig @@ -29,6 +29,18 @@ config PINCTRL_BCM2835 help Say Y here to enable the Broadcom BCM2835 GPIO driver. +config PINCTRL_BCM2835_RUST + tristate "Broadcom BCM2835 GPIO (with PINCONF) driver written in rust" + depends on OF && (ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST) && RUST + select PINMUX + select PINCONF + select GENERIC_PINCONF + select GPIOLIB + select GPIOLIB_IRQCHIP + default ARCH_BCM2835 || ARCH_BRCMSTB + help + Say Y here to enable the Broadcom BCM2835 GPIO driver. + config PINCTRL_BCM4908 tristate "Broadcom BCM4908 pinmux driver" depends on OF && (ARCH_BCMBCA || COMPILE_TEST) diff --git a/drivers/pinctrl/bcm/Makefile b/drivers/pinctrl/bcm/Makefile index 82b868ec14716d..b200e52ea0ac95 100644 --- a/drivers/pinctrl/bcm/Makefile +++ b/drivers/pinctrl/bcm/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o +obj-$(CONFIG_PINCTRL_BCM2835_RUST) += pinctrl_bcm2835_rust.o obj-$(CONFIG_PINCTRL_BCM4908) += pinctrl-bcm4908.o obj-$(CONFIG_PINCTRL_BCM63XX) += pinctrl-bcm63xx.o obj-$(CONFIG_PINCTRL_BCM6318) += pinctrl-bcm6318.o @@ -17,3 +18,5 @@ obj-$(CONFIG_PINCTRL_NS) += pinctrl-ns.o obj-$(CONFIG_PINCTRL_NSP_GPIO) += pinctrl-nsp-gpio.o obj-$(CONFIG_PINCTRL_NS2_MUX) += pinctrl-ns2-mux.o obj-$(CONFIG_PINCTRL_NSP_MUX) += pinctrl-nsp-mux.o + + diff --git a/drivers/pinctrl/bcm/pinctrl_bcm2835_rust.rs b/drivers/pinctrl/bcm/pinctrl_bcm2835_rust.rs new file mode 100644 index 00000000000000..38309340801461 --- /dev/null +++ b/drivers/pinctrl/bcm/pinctrl_bcm2835_rust.rs @@ -0,0 +1,268 @@ +//SPDX-License-Identifier: GPL-2.0 + +//! Driver for Boradcom BCM2835 GPIO unit (pinctrl + GPIO) +//! +//! Based on the C driver + +use core::result::Result::Ok; + +use kernel::{ + bit, define_of_id_table, device, gpio, + io_mem::IoMem, + module_platform_driver, of, platform, + prelude::*, + sync::{Arc, ArcBorrow}, +}; + +macro_rules! FSEL_REG { + ($p:expr) => { + GPFSEL0 + (($p / 10) * 4) + }; +} + +macro_rules! FSEL_SHIFT { + ($p:expr) => { + (($p % 10) * 3) + }; +} + +macro_rules! GPIO_REG_OFFSET { + ($p:expr) => { + $p / 32 + }; +} + +macro_rules! GPIO_REG_SHIFT { + ($p:expr) => { + $p % 32 + }; +} + +//GPIO register offsets +const GPFSEL0: usize = 0x0; //function select +const GPSET0: usize = 0x1c; //pin output set +const GPCLR0: usize = 0x28; //pin output clear +const GPLEV0: usize = 0x34; //pin level + // const GPEDS0:usize = 0x40; //pin event detect Status + // const GPREN0:usize = 0x4c; //pin rising edge detect enable + // const GPFEN0:usize = 0x58; //pin falling edge detect enable + // const GPHEN0:usize = 0x64; //pin high detect enable + // const GPLEN0:usize = 0x70; //pin low detect enable + // const GPAREN0:usize= 0x7c; //pin async rising edge detect + // const GPAFEN0:usize= 0x88; // pin async falling edge detect + // const GPPUD:usize = 0x94; //pin pull-up/down enable + // const GPPUDCLK0:usize = 0x98; // pin pull-up/down enable clock + //TODO: no sure the precise offset size of BCM2835 +const GPIO_SIZE: usize = 0x1000; + +const BCM2835_NUM_GPIOS: u16 = 54; +// const BCM2835_NUM_BANKS:usize = 2; +// const BCM2835_NUM_IRQS:usize = 3; + +// bcm2835_fsel +// const BCM2835_FSEL_COUNT:usize = 8; +const BCM2835_FSEL_MASK: u32 = 0x7; +// brcm, function property +const BCM2835_FSEL_GPIO_IN: u32 = 0; +const BCM2835_FSEL_GPIO_OUT: u32 = 1; +// const BCM2835_FSEL_ALT5:u32 = 2; +// const BCM2835_FSEL_ALT4:u32 = 3; +// const BCM2835_FSEL_ALT0:u32 = 4; +// const BCM2835_FSEL_ALT1:u32 = 5; +// const BCM2835_FSEL_ALT2:u32 = 6; +// const BCM2835_FSEL_ALT3:u32 = 7; + +// const BCM2835_FUNCTIONS:[&str;BCM2835_FSEL_COUNT]= [ +// "gpio_in", +// "gpio_out", +// "alt0", +// "alt1", +// "alt2", +// "alt3", +// "alt4", +// "alt5", +// ]; + +// struct BCM2835DataInner{ +// //TODO: data in bcm2835 +// } + +struct BCM2835Resources { + base: IoMem, + // wake_irq:&'a[i32], + // enablied_irq_map:[u64;BCM2835_NUM_BANKS], + // irq_type:[u32;BCM2835_NUM_GPIOS], +} + +struct BCM2835Data { + dev: device::Device, + // inner: RawSpinLock, +} + +type BCM2835Registrations = gpio::Registration; + +type DeviceData = device::Data; + +struct BCM2835Device; + +impl BCM2835Device { + #[inline] + fn bcm2835_gpio_rd(data: ArcBorrow<'_, DeviceData>, reg: usize) -> Result { + let bcm2835 = data.resources().ok_or(ENXIO)?; + bcm2835.base.try_readl(reg) + } + + #[inline] + fn bcm2835_gpio_wr(data: ArcBorrow<'_, DeviceData>, reg: usize, val: u32) -> Result { + let bcm2835 = data.resources().ok_or(ENXIO)?; + bcm2835.base.try_writel(val, reg)?; + Ok(()) + } + + #[inline] + fn bcm2835_gpio_get_bit( + data: ArcBorrow<'_, DeviceData>, + reg: usize, + offset: u32, + ) -> Result { + let reg = reg + GPIO_REG_OFFSET!(offset as usize) * 4; + Ok(((Self::bcm2835_gpio_rd(data, reg)? >> (GPIO_REG_SHIFT!(offset))) & 1) != 0) + } + + #[inline] + fn bcm2835_gpio_set_bit(data: ArcBorrow<'_, DeviceData>, reg: usize, offset: u32) -> Result { + let reg = reg + GPIO_REG_OFFSET!(offset as usize) * 4; + let val = bit(GPIO_REG_SHIFT!(offset)).into(); + Self::bcm2835_gpio_wr(data, reg, val)?; + Ok(()) + } + + #[inline] + fn bcm2835_pinctrl_fsel_get(data: ArcBorrow<'_, DeviceData>, pin: usize) -> Result { + let val = Self::bcm2835_gpio_rd(data, FSEL_REG!(pin))?; + let status = (val >> FSEL_SHIFT!(pin as u32)) & BCM2835_FSEL_MASK; + Ok(status) + } + + #[inline] + fn bcm2835_pinctrl_fsel_set(data: ArcBorrow<'_, DeviceData>, pin: usize, fsel: u32) -> Result { + let mut val = Self::bcm2835_gpio_rd(data, FSEL_REG!(pin))?; + let cur = (val >> FSEL_SHIFT!(pin as u32)) & BCM2835_FSEL_MASK; + + // dev_dbg!(data.dev,"read{}({}=>{}\n)",val,pin,BCM2835_FUNCTIONS[cur]); + + if cur == fsel { + return Ok(()); + } + + if cur != BCM2835_FSEL_GPIO_IN && fsel != BCM2835_FSEL_GPIO_IN { + val &= !(BCM2835_FSEL_MASK << FSEL_SHIFT!(pin as u32)); + val |= fsel << FSEL_SHIFT!(pin as u32); + + // dev_dbg!(data.dev,"trans {} ({} <= {})\n",val,pin,BCM2835_FUNCTIONS[BCM2835_FSEL_GPIO_IN as usize]); + Self::bcm2835_gpio_wr(data, FSEL_REG!(pin), val)?; + } + + val &= !(BCM2835_FSEL_MASK << FSEL_SHIFT!(pin as u32)); + val |= fsel << FSEL_SHIFT!(pin as u32); + + // dev_dbg!(data,"write {} ({}<={})\n",val,pin,BCM2835_FUNCTIONS[fsel]); + Self::bcm2835_gpio_wr(data, FSEL_REG!(pin), val)?; + Ok(()) + } +} + +//TODO: implement the items in trait gpio::Chip +#[vtable] +impl gpio::Chip for BCM2835Device { + type Data = Arc; + + fn get_direction(data: ArcBorrow<'_, DeviceData>, offset: u32) -> Result { + // let bcm2835_pinctrl = data.resources().ok_or(ENXIO)?; + let fsel = Self::bcm2835_pinctrl_fsel_get(data, offset as usize)?; + + //Alternative function doesn't clearly provide a direction + if fsel > BCM2835_FSEL_GPIO_OUT { + //FIXME: Err(EINVAL) + return Err(ENOTSUPP); + } + + Ok(if fsel == BCM2835_FSEL_GPIO_IN { + gpio::LineDirection::In + } else { + gpio::LineDirection::Out + }) + } + + fn direction_input(data: ArcBorrow<'_, DeviceData>, offset: u32) -> Result { + // let bcm2835_pinctrl = data.resources().ok_or(ENXIO); + Self::bcm2835_pinctrl_fsel_set( + data, + offset as usize, + BCM2835_FSEL_GPIO_IN, + ) + } + + fn direction_output(data: ArcBorrow<'_, DeviceData>, offset: u32, value: bool) -> Result { + let reg = if value { GPSET0 } else { GPCLR0 }; + Self::bcm2835_gpio_set_bit(data, reg, offset)?; + Self::bcm2835_pinctrl_fsel_set(data, offset as usize, BCM2835_FSEL_GPIO_OUT)?; + Ok(()) + } + + fn set(data: ArcBorrow<'_, DeviceData>, offset: u32, value: bool) { + let reg = if value { GPSET0 } else { GPCLR0 }; + let _ = Self::bcm2835_pinctrl_fsel_set(data, reg, offset); + } + + fn get(data: ArcBorrow<'_, DeviceData>, offset: u32) -> Result { + Self::bcm2835_gpio_get_bit(data, GPLEV0, offset) + } +} + +impl platform::Driver for BCM2835Device { + type Data = Arc; + + define_of_id_table! {(),[ + //FIXME: None is likely not correct, should fix it maybe + (of::DeviceId::Compatible(b"brcm,bcm2835-gpio"),None), + ]} + + fn probe(dev: &mut platform::Device, _data: Option<&Self::IdInfo>) -> Result> { + let res = dev.res().ok_or(ENXIO)?; + + let data = kernel::new_device_data!( + gpio::Registration::new(), + BCM2835Resources { + //SAFETY: + base: unsafe { IoMem::try_new(res)? }, + }, + BCM2835Data { + dev: device::Device::from_dev(dev), + }, + "BCM2835::Regsiterations" + )?; + + let data = Arc::::from(data); + + kernel::gpio_chip_register!( + data.registrations().ok_or(ENXIO)?.as_pinned_mut(), + BCM2835_NUM_GPIOS, + None, + dev, + data.clone() + )?; + + dev_info!(data.dev, "RUST BCM2835 GPIO CHIP registered!!!\n"); + + Ok(data) + } +} + +module_platform_driver! { + type: BCM2835Device, + name: "pinctrl_bcm2835_rust", + author: "Tianyu She", + description: "BCM2835 GPIO Part", + license: "GPL", +} diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index d358e9da81fac3..1eba3d9d95da17 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -6,11 +6,14 @@ //! //! C header: [`include/linux/platform_device.h`](../../../../include/linux/platform_device.h) +// use bindings::slab; + use crate::{ bindings, device::{self, RawDevice}, driver, error::{from_kernel_result, Result}, + io_mem::Resource, of, str::CStr, to_result, @@ -183,6 +186,15 @@ impl Device { // SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid. unsafe { (*self.ptr).id } } + + /// Returns the Resource of the platform device + pub fn res(&self) -> Option { + //SAFETY: By the type invariants, we know that 'self.ptr' is non-null and valid + let pdev = unsafe { &*self.ptr }; + //SAFETY: we know that 'platform_device.resource[0]' is non-null + let res = unsafe { *pdev.resource }; + Resource::new(res.start, res.end) + } } // SAFETY: The device returned by `raw_device` is the raw platform device. From 74f0fac283d7ea8decada0781d6f363ba076587c Mon Sep 17 00:00:00 2001 From: Terry She Date: Mon, 22 Apr 2024 22:07:55 +0800 Subject: [PATCH 2/2] delete useless comments --- drivers/pinctrl/bcm/pinctrl_bcm2835_rust.rs | 54 ++------------------- 1 file changed, 4 insertions(+), 50 deletions(-) diff --git a/drivers/pinctrl/bcm/pinctrl_bcm2835_rust.rs b/drivers/pinctrl/bcm/pinctrl_bcm2835_rust.rs index 38309340801461..ae73124d3338ea 100644 --- a/drivers/pinctrl/bcm/pinctrl_bcm2835_rust.rs +++ b/drivers/pinctrl/bcm/pinctrl_bcm2835_rust.rs @@ -43,60 +43,24 @@ const GPFSEL0: usize = 0x0; //function select const GPSET0: usize = 0x1c; //pin output set const GPCLR0: usize = 0x28; //pin output clear const GPLEV0: usize = 0x34; //pin level - // const GPEDS0:usize = 0x40; //pin event detect Status - // const GPREN0:usize = 0x4c; //pin rising edge detect enable - // const GPFEN0:usize = 0x58; //pin falling edge detect enable - // const GPHEN0:usize = 0x64; //pin high detect enable - // const GPLEN0:usize = 0x70; //pin low detect enable - // const GPAREN0:usize= 0x7c; //pin async rising edge detect - // const GPAFEN0:usize= 0x88; // pin async falling edge detect - // const GPPUD:usize = 0x94; //pin pull-up/down enable - // const GPPUDCLK0:usize = 0x98; // pin pull-up/down enable clock - //TODO: no sure the precise offset size of BCM2835 const GPIO_SIZE: usize = 0x1000; const BCM2835_NUM_GPIOS: u16 = 54; -// const BCM2835_NUM_BANKS:usize = 2; -// const BCM2835_NUM_IRQS:usize = 3; // bcm2835_fsel -// const BCM2835_FSEL_COUNT:usize = 8; const BCM2835_FSEL_MASK: u32 = 0x7; // brcm, function property const BCM2835_FSEL_GPIO_IN: u32 = 0; const BCM2835_FSEL_GPIO_OUT: u32 = 1; -// const BCM2835_FSEL_ALT5:u32 = 2; -// const BCM2835_FSEL_ALT4:u32 = 3; -// const BCM2835_FSEL_ALT0:u32 = 4; -// const BCM2835_FSEL_ALT1:u32 = 5; -// const BCM2835_FSEL_ALT2:u32 = 6; -// const BCM2835_FSEL_ALT3:u32 = 7; - -// const BCM2835_FUNCTIONS:[&str;BCM2835_FSEL_COUNT]= [ -// "gpio_in", -// "gpio_out", -// "alt0", -// "alt1", -// "alt2", -// "alt3", -// "alt4", -// "alt5", -// ]; - -// struct BCM2835DataInner{ -// //TODO: data in bcm2835 -// } + + struct BCM2835Resources { base: IoMem, - // wake_irq:&'a[i32], - // enablied_irq_map:[u64;BCM2835_NUM_BANKS], - // irq_type:[u32;BCM2835_NUM_GPIOS], } struct BCM2835Data { dev: device::Device, - // inner: RawSpinLock, } type BCM2835Registrations = gpio::Registration; @@ -149,8 +113,6 @@ impl BCM2835Device { let mut val = Self::bcm2835_gpio_rd(data, FSEL_REG!(pin))?; let cur = (val >> FSEL_SHIFT!(pin as u32)) & BCM2835_FSEL_MASK; - // dev_dbg!(data.dev,"read{}({}=>{}\n)",val,pin,BCM2835_FUNCTIONS[cur]); - if cur == fsel { return Ok(()); } @@ -159,14 +121,12 @@ impl BCM2835Device { val &= !(BCM2835_FSEL_MASK << FSEL_SHIFT!(pin as u32)); val |= fsel << FSEL_SHIFT!(pin as u32); - // dev_dbg!(data.dev,"trans {} ({} <= {})\n",val,pin,BCM2835_FUNCTIONS[BCM2835_FSEL_GPIO_IN as usize]); Self::bcm2835_gpio_wr(data, FSEL_REG!(pin), val)?; } val &= !(BCM2835_FSEL_MASK << FSEL_SHIFT!(pin as u32)); val |= fsel << FSEL_SHIFT!(pin as u32); - // dev_dbg!(data,"write {} ({}<={})\n",val,pin,BCM2835_FUNCTIONS[fsel]); Self::bcm2835_gpio_wr(data, FSEL_REG!(pin), val)?; Ok(()) } @@ -178,7 +138,6 @@ impl gpio::Chip for BCM2835Device { type Data = Arc; fn get_direction(data: ArcBorrow<'_, DeviceData>, offset: u32) -> Result { - // let bcm2835_pinctrl = data.resources().ok_or(ENXIO)?; let fsel = Self::bcm2835_pinctrl_fsel_get(data, offset as usize)?; //Alternative function doesn't clearly provide a direction @@ -195,12 +154,7 @@ impl gpio::Chip for BCM2835Device { } fn direction_input(data: ArcBorrow<'_, DeviceData>, offset: u32) -> Result { - // let bcm2835_pinctrl = data.resources().ok_or(ENXIO); - Self::bcm2835_pinctrl_fsel_set( - data, - offset as usize, - BCM2835_FSEL_GPIO_IN, - ) + Self::bcm2835_pinctrl_fsel_set(data,offset as usize,BCM2835_FSEL_GPIO_IN) } fn direction_output(data: ArcBorrow<'_, DeviceData>, offset: u32, value: bool) -> Result { @@ -234,7 +188,7 @@ impl platform::Driver for BCM2835Device { let data = kernel::new_device_data!( gpio::Registration::new(), BCM2835Resources { - //SAFETY: + //SAFETY:This device doesn't support DMA. base: unsafe { IoMem::try_new(res)? }, }, BCM2835Data {