Basic pinmux capsule / HAL - Implements input_select / output_select - Syscall interface + mailbox client integration Change-Id: I2dc7ee742f32193be776b1edf5e19998c75b97e2
diff --git a/app/src/mailbox_client.rs b/app/src/mailbox_client.rs index c7a36f4..f2a26aa 100644 --- a/app/src/mailbox_client.rs +++ b/app/src/mailbox_client.rs
@@ -30,6 +30,9 @@ FindFile(&'a str), // Find file by name -> (/*fid*/ u32, /*size*/ u32) GetFilePage(u32, u32), // Read data from fid at offset -> <attached page> + InputSelect(u32 /* peripheral */, u32 /* pad */), // Connect the input of `pad` to `peripheral` + OutputSelect(u32 /* pad */, u32 /* peripheral */), // Connect the output of `peripheral` to `pad` + Test(/*count*/ u32), // Scribble on count words of supplied page // NB: must be last to match up with stripped down rootserver driver @@ -85,6 +88,7 @@ pub fn init() { let _ = syscalls::command(CAPSULE_MAILBOX, CMD_MAILBOX_INIT, 0, 0); let _ = syscalls::command(CAPSULE_STORAGE, CMD_STORAGE_INIT, 0, 0); + let _ = syscalls::command(CAPSULE_PINMUX, CMD_PINMUX_INIT, 0, 0); } // Support for receiving inbound mailbox messages. This is split into @@ -206,6 +210,12 @@ SECRequest::GetFilePage(fid, offset) => { MailboxClient::get_file_page_async(fid, offset, opt_page, reply_slice).await } + SECRequest::InputSelect(peripheral, pad) => { + MailboxClient::input_select_async(peripheral, pad).await + } + SECRequest::OutputSelect(pad, peripheral) => { + MailboxClient::output_select_async(pad, peripheral).await + } SECRequest::Test(count) => { MailboxClient::test_sync(count as usize, opt_page, reply_slice) } @@ -218,6 +228,78 @@ } } + pub async fn input_select_async(peripheral: u32, pad: u32) -> Result<usize, SECRequestError> { + let input_select_result: Cell<Option<bool>> = Cell::new(None); + unsafe extern "C" fn input_select_callback( + ok: usize, + _argument1: usize, + _argument2: usize, + data: usize, + ) { + let result = &*(data as *const Cell<Option<bool>>); + result.set(Some(ok == 0)); + } + unsafe { + syscalls::raw::subscribe( + CAPSULE_PINMUX, + CMD_PINMUX_INPUT_SELECT, + input_select_callback as *const _, + &input_select_result as *const _ as usize, + ); + let _ = syscalls::command( + CAPSULE_PINMUX, + CMD_PINMUX_INPUT_SELECT, + peripheral as usize, pad as usize + ); + } + futures::wait_until(|| (input_select_result.get().is_some())).await; + unsafe { + syscalls::raw::subscribe(CAPSULE_PINMUX, 0, ptr::null(), 0); + } + let ok = input_select_result.into_inner(); + if ok.unwrap() { + Ok(0) + } else { + Err(SECRequestError::UnknownError) + } + } + + pub async fn output_select_async(pad: u32, peripheral: u32) -> Result<usize, SECRequestError> { + let output_select_result: Cell<Option<bool>> = Cell::new(None); + unsafe extern "C" fn output_select_callback( + ok: usize, + _argument1: usize, + _argument2: usize, + data: usize, + ) { + let result = &*(data as *const Cell<Option<bool>>); + result.set(Some(ok == 0)); + } + unsafe { + syscalls::raw::subscribe( + CAPSULE_PINMUX, + CMD_PINMUX_OUTPUT_SELECT, + output_select_callback as *const _, + &output_select_result as *const _ as usize, + ); + let _ = syscalls::command( + CAPSULE_PINMUX, + CMD_PINMUX_OUTPUT_SELECT, + pad as usize, peripheral as usize + ); + } + futures::wait_until(|| (output_select_result.get().is_some())).await; + unsafe { + syscalls::raw::subscribe(CAPSULE_PINMUX, 0, ptr::null(), 0); + } + let ok = output_select_result.into_inner(); + if ok.unwrap() { + Ok(0) + } else { + Err(SECRequestError::UnknownError) + } + } + // Returns the names of objects that can be looked up using FindFile. async fn get_builtins_async(reply_buffer: &mut [u8]) -> Result<usize, SECRequestError> { const NAME_SIZE: usize = 100; // Arbitrary but matches TarHeader.name
diff --git a/capsules/src/lib.rs b/capsules/src/lib.rs index fdf2117..2cf9803 100644 --- a/capsules/src/lib.rs +++ b/capsules/src/lib.rs
@@ -20,3 +20,4 @@ pub mod mailbox_capsule; pub mod nexus_spiflash; pub mod storage_capsule; +pub mod pinmux_capsule;
diff --git a/capsules/src/pinmux_capsule.rs b/capsules/src/pinmux_capsule.rs new file mode 100644 index 0000000..0d08f9b --- /dev/null +++ b/capsules/src/pinmux_capsule.rs
@@ -0,0 +1,171 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use core::cell::Cell; +use kernel::common::cells::OptionalCell; +use kernel::{AppId, AppSlice, Callback, Driver, Grant, ReturnCode, Shared}; +use matcha_config::*; +use matcha_hal::pinmux_hal::PinmuxHAL; + +pub struct AppData { + input_select_callback: Option<Callback>, + output_select_callback: Option<Callback>, +} + +impl Default for AppData { + fn default() -> AppData { + AppData { + input_select_callback: None, + output_select_callback: None, + } + } +} + +pub struct PinmuxCapsule { + pub app_data_grant: Grant<AppData>, + pub pinmux_hal: OptionalCell<&'static dyn PinmuxHAL>, + pub current_app: Cell<Option<AppId>>, +} + +impl PinmuxCapsule { + pub fn new(app_data_grant: Grant<AppData>) -> Self { + PinmuxCapsule { + app_data_grant: app_data_grant, + pinmux_hal: OptionalCell::empty(), + current_app: Cell::new(None), + } + } + + pub fn set_pinmux(&self, pinmux: &'static dyn PinmuxHAL) { + self.pinmux_hal.set(pinmux); + } + + pub fn handle_command( + &self, + app_id: AppId, + _app_data: &mut AppData, + minor_num: usize, + arg2: usize, + arg3: usize, + ) -> ReturnCode { + match minor_num { + CMD_PINMUX_INIT => { + self.current_app.set(Some(app_id)); + ReturnCode::SUCCESS + } + CMD_PINMUX_INPUT_SELECT => { + let peripheral: u32 = arg2 as u32; + let pad: u32 = arg3 as u32; + let ret = self.pinmux_hal.map_or_else( + || { ReturnCode::EINVAL }, + |pinmux| { + pinmux.input_select(peripheral, pad) + } + ); + self.current_app.get().map(|app_id| { + let _ = self.app_data_grant.enter(app_id, |app_data, _| { + app_data.input_select_callback.map(|mut callback| { + callback.schedule(usize::from(ret), 0, 0); + }); + }); + }); + ret + } + CMD_PINMUX_OUTPUT_SELECT => { + let pad: u32 = arg2 as u32; + let peripheral: u32 = arg3 as u32; + let ret = self.pinmux_hal.map_or_else( + || { ReturnCode::EINVAL }, + |pinmux| { + pinmux.output_select(pad, peripheral) + } + ); + self.current_app.get().map(|app_id| { + let _ = self.app_data_grant.enter(app_id, |app_data, _| { + app_data.output_select_callback.map(|mut callback| { + callback.schedule(usize::from(ret), 0, 0); + }); + }); + }); + ret + } + _ => ReturnCode::EINVAL, + } + } + + pub fn handle_subscribe( + &self, + _app_id: AppId, + app_data: &mut AppData, + minor_num: usize, + callback: Option<Callback>, + ) -> ReturnCode { + match minor_num { + CMD_PINMUX_INPUT_SELECT => { + app_data.input_select_callback = callback; + ReturnCode::SUCCESS + } + CMD_PINMUX_OUTPUT_SELECT => { + app_data.output_select_callback = callback; + ReturnCode::SUCCESS + } + _ => ReturnCode::EINVAL, + } + } + + pub fn handle_allow( + &self, + _app_id: AppId, + _app_data: &mut AppData, + minor_num: usize, + _slice: Option<AppSlice<Shared, u8>>, + ) -> ReturnCode { + match minor_num { + CMD_PINMUX_INPUT_SELECT => ReturnCode::SUCCESS, + CMD_PINMUX_OUTPUT_SELECT => ReturnCode::SUCCESS, + _ => ReturnCode::EINVAL, + } + } +} + +impl Driver for PinmuxCapsule { + fn subscribe(&self, minor_num: usize, callback: Option<Callback>, app_id: AppId) -> ReturnCode { + self.app_data_grant + .enter(app_id, |app_data, _| { + self.handle_subscribe(app_id, app_data, minor_num, callback) + }) + .unwrap_or_else(|err| err.into()) + } + + fn command(&self, minor_num: usize, r2: usize, r3: usize, app_id: AppId) -> ReturnCode { + self.app_data_grant + .enter(app_id, |app_data, _| { + self.handle_command(app_id, app_data, minor_num, r2, r3) + }) + .unwrap_or_else(|err| err.into()) + } + + fn allow( + &self, + app_id: AppId, + minor_num: usize, + slice: Option<AppSlice<Shared, u8>>, + ) -> ReturnCode { + self.app_data_grant + .enter(app_id, |app_data, _| { + self.handle_allow(app_id, app_data, minor_num, slice) + }) + .unwrap_or_else(|err| err.into()) + } +} \ No newline at end of file
diff --git a/config/src/lib.rs b/config/src/lib.rs index 8e2e30c..e51481d 100644 --- a/config/src/lib.rs +++ b/config/src/lib.rs
@@ -33,6 +33,7 @@ pub const CAPSULE_ELFLOADER: usize = 0x50004; pub const CAPSULE_MAILBOX: usize = 0x50005; pub const CAPSULE_SPIFLASH: usize = 0x50006; +pub const CAPSULE_PINMUX: usize = 0x50007; pub const CMD_MAILBOX_INIT: usize = 1; pub const CMD_MAILBOX_SEND: usize = 2; @@ -67,3 +68,8 @@ pub const UART0_BASE_ADDRESS: u32 = 0x40000000; // TOP_MATCHA_UART0_BASE_ADDR pub const UART0_BAUDRATE: u32 = 115200; + +pub const PINMUX_BASE_ADDRESS: u32 = 0x40460000; // TOP_MATCHA_PINMUX_AON_BASE_ADDR +pub const CMD_PINMUX_INIT: usize = 1; +pub const CMD_PINMUX_INPUT_SELECT: usize = 2; +pub const CMD_PINMUX_OUTPUT_SELECT: usize = 3;
diff --git a/hal/src/lib.rs b/hal/src/lib.rs index 5d64683..2079236 100644 --- a/hal/src/lib.rs +++ b/hal/src/lib.rs
@@ -21,6 +21,7 @@ pub mod dprintf_hal; pub mod mailbox_hal; +pub mod pinmux_hal; pub mod plic_constants; pub mod plic_hal; pub mod rv_core_ibex_hal;
diff --git a/hal/src/pinmux_hal.rs b/hal/src/pinmux_hal.rs new file mode 100644 index 0000000..261b6d6 --- /dev/null +++ b/hal/src/pinmux_hal.rs
@@ -0,0 +1,351 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Generated register constants for pinmux. +// Build date: 2023-11-10T00:20:05.600739 + +// Original reference file: hw/matcha/hw/top_matcha/ip/pinmux/data/autogen/pinmux.hjson +use kernel::common::registers::ReadWrite; +use kernel::common::registers::{register_bitfields, register_structs}; +use kernel::common::StaticRef; +use kernel::ReturnCode; + +// Pad attribute data width +pub const PINMUX_PARAM_ATTR_DW: u32 = 13; +// Number of muxed peripheral inputs +pub const PINMUX_PARAM_N_MIO_PERIPH_IN: u32 = 76; +// Number of muxed peripheral outputs +pub const PINMUX_PARAM_N_MIO_PERIPH_OUT: u32 = 89; +// Number of muxed IO pads +pub const PINMUX_PARAM_N_MIO_PADS: u32 = 53; +// Number of dedicated IO pads +pub const PINMUX_PARAM_N_DIO_PADS: u32 = 16; +// Number of wakeup detectors +pub const PINMUX_PARAM_N_WKUP_DETECT: u32 = 8; +// Number of wakeup counter bits +pub const PINMUX_PARAM_WKUP_CNT_WIDTH: u32 = 8; +// Number of alerts +pub const PINMUX_PARAM_NUM_ALERTS: u32 = 1; +// Register width +pub const PINMUX_PARAM_REG_WIDTH: u32 = 32; + +pub enum PinmuxLockTarget { + Insel = 0, + Outsel, + MioSleep, + DioSleep, + MioPadAttr, + DioPadAttr, + WakeupDetector, +} + +pub const PINMUX_REGISTERS: StaticRef<PinmuxRegisters> = + unsafe { StaticRef::new(matcha_config::PINMUX_BASE_ADDRESS as *const PinmuxRegisters) }; +pub static mut PINMUX: PinmuxHw = PinmuxHw::new(PINMUX_REGISTERS); + +register_structs! { + pub PinmuxRegisters { + // Alert Test Register + (0x0000 => pub(crate) alert_test: ReadWrite<u32, ALERT_TEST::Register>), + // Register write enable for MIO peripheral input selects. + (0x0004 => pub(crate) mio_periph_insel_regwen: [ReadWrite<u32, MIO_PERIPH_INSEL_REGWEN::Register>; 76]), + // For each peripheral input, this selects the muxable pad input. + (0x0134 => pub(crate) mio_periph_insel: [ReadWrite<u32, MIO_PERIPH_INSEL::Register>; 76]), + // Register write enable for MIO output selects. + (0x0264 => pub(crate) mio_outsel_regwen: [ReadWrite<u32, MIO_OUTSEL_REGWEN::Register>; 53]), + // For each muxable pad, this selects the peripheral output. + (0x0338 => pub(crate) mio_outsel: [ReadWrite<u32, MIO_OUTSEL::Register>; 53]), + // Register write enable for MIO PAD attributes. + (0x040c => pub(crate) mio_pad_attr_regwen: [ReadWrite<u32, MIO_PAD_ATTR_REGWEN::Register>; 53]), + // Muxed pad attributes. + (0x04e0 => pub(crate) mio_pad_attr: [ReadWrite<u32, MIO_PAD_ATTR::Register>; 53]), + // Register write enable for DIO PAD attributes. + (0x05b4 => pub(crate) dio_pad_attr_regwen: [ReadWrite<u32, DIO_PAD_ATTR_REGWEN::Register>; 16]), + // Dedicated pad attributes. + (0x05f4 => pub(crate) dio_pad_attr: [ReadWrite<u32, DIO_PAD_ATTR::Register>; 16]), + // Register indicating whether the corresponding pad is in sleep mode. + (0x0634 => pub(crate) mio_pad_sleep_status: [ReadWrite<u32, MIO_PAD_SLEEP_STATUS::Register>; 2]), + // Register write enable for MIO sleep value configuration. + (0x063c => pub(crate) mio_pad_sleep_regwen: [ReadWrite<u32, MIO_PAD_SLEEP_REGWEN::Register>; 53]), + // Enables the sleep mode of the corresponding muxed pad. + (0x0710 => pub(crate) mio_pad_sleep_en: [ReadWrite<u32, MIO_PAD_SLEEP_EN::Register>; 53]), + // Defines sleep behavior of the corresponding muxed pad. + (0x07e4 => pub(crate) mio_pad_sleep_mode: [ReadWrite<u32, MIO_PAD_SLEEP_MODE::Register>; 53]), + // Register indicating whether the corresponding pad is in sleep mode. + (0x08b8 => pub(crate) dio_pad_sleep_status: [ReadWrite<u32, DIO_PAD_SLEEP_STATUS::Register>; 1]), + // Register write enable for DIO sleep value configuration. + (0x08bc => pub(crate) dio_pad_sleep_regwen: [ReadWrite<u32, DIO_PAD_SLEEP_REGWEN::Register>; 16]), + // Enables the sleep mode of the corresponding dedicated pad. + (0x08fc => pub(crate) dio_pad_sleep_en: [ReadWrite<u32, DIO_PAD_SLEEP_EN::Register>; 16]), + // Defines sleep behavior of the corresponding dedicated pad. + (0x093c => pub(crate) dio_pad_sleep_mode: [ReadWrite<u32, DIO_PAD_SLEEP_MODE::Register>; 16]), + // Register write enable for wakeup detectors. + (0x097c => pub(crate) wkup_detector_regwen: [ReadWrite<u32, WKUP_DETECTOR_REGWEN::Register>; 8]), + // Enables for the wakeup detectors. + (0x099c => pub(crate) wkup_detector_en: [ReadWrite<u32, WKUP_DETECTOR_EN::Register>; 8]), + // Configuration of wakeup condition detectors. + (0x09bc => pub(crate) wkup_detector: [ReadWrite<u32, WKUP_DETECTOR::Register>; 8]), + // Counter thresholds for wakeup condition detectors. + (0x09dc => pub(crate) wkup_detector_cnt_th: [ReadWrite<u32, WKUP_DETECTOR_CNT_TH::Register>; 8]), + // Pad selects for pad wakeup condition detectors. + (0x09fc => pub(crate) wkup_detector_padsel: [ReadWrite<u32, WKUP_DETECTOR_PADSEL::Register>; 8]), + // Cause registers for wakeup detectors. + (0x0a1c => pub(crate) wkup_cause: [ReadWrite<u32, WKUP_CAUSE::Register>; 1]), + (0x0a20 => @END), + } +} + +register_bitfields![u32, + pub(crate) ALERT_TEST [ + FATAL_FAULT OFFSET(0) NUMBITS(1) [] + ], + pub(crate) MIO_PERIPH_INSEL_REGWEN [ + EN_0 OFFSET(0) NUMBITS(1) [] + ], + pub(crate) MIO_PERIPH_INSEL [ + IN_0 OFFSET(0) NUMBITS(6) [] + ], + pub(crate) MIO_OUTSEL_REGWEN [ + EN_0 OFFSET(0) NUMBITS(1) [] + ], + pub(crate) MIO_OUTSEL [ + OUT_0 OFFSET(0) NUMBITS(7) [] + ], + pub(crate) MIO_PAD_ATTR_REGWEN [ + EN_0 OFFSET(0) NUMBITS(1) [] + ], + pub(crate) MIO_PAD_ATTR [ + INVERT_0 OFFSET(0) NUMBITS(1) [], + VIRTUAL_OD_EN_0 OFFSET(1) NUMBITS(1) [], + PULL_EN_0 OFFSET(2) NUMBITS(1) [], + PULL_SELECT_0 OFFSET(3) NUMBITS(1) [ + PULL_DOWN = 0, + PULL_UP = 1 + ], + KEEPER_EN_0 OFFSET(4) NUMBITS(1) [], + SCHMITT_EN_0 OFFSET(5) NUMBITS(1) [], + OD_EN_0 OFFSET(6) NUMBITS(1) [], + SLEW_RATE_0 OFFSET(16) NUMBITS(2) [], + DRIVE_STRENGTH_0 OFFSET(20) NUMBITS(4) [] + ], + pub(crate) DIO_PAD_ATTR_REGWEN [ + EN_0 OFFSET(0) NUMBITS(1) [] + ], + pub(crate) DIO_PAD_ATTR [ + INVERT_0 OFFSET(0) NUMBITS(1) [], + VIRTUAL_OD_EN_0 OFFSET(1) NUMBITS(1) [], + PULL_EN_0 OFFSET(2) NUMBITS(1) [], + PULL_SELECT_0 OFFSET(3) NUMBITS(1) [ + PULL_DOWN = 0, + PULL_UP = 1 + ], + KEEPER_EN_0 OFFSET(4) NUMBITS(1) [], + SCHMITT_EN_0 OFFSET(5) NUMBITS(1) [], + OD_EN_0 OFFSET(6) NUMBITS(1) [], + SLEW_RATE_0 OFFSET(16) NUMBITS(2) [], + DRIVE_STRENGTH_0 OFFSET(20) NUMBITS(4) [] + ], + pub(crate) MIO_PAD_SLEEP_STATUS [ + EN_0 OFFSET(0) NUMBITS(1) [], + EN_1 OFFSET(1) NUMBITS(1) [], + EN_2 OFFSET(2) NUMBITS(1) [], + EN_3 OFFSET(3) NUMBITS(1) [], + EN_4 OFFSET(4) NUMBITS(1) [], + EN_5 OFFSET(5) NUMBITS(1) [], + EN_6 OFFSET(6) NUMBITS(1) [], + EN_7 OFFSET(7) NUMBITS(1) [], + EN_8 OFFSET(8) NUMBITS(1) [], + EN_9 OFFSET(9) NUMBITS(1) [], + EN_10 OFFSET(10) NUMBITS(1) [], + EN_11 OFFSET(11) NUMBITS(1) [], + EN_12 OFFSET(12) NUMBITS(1) [], + EN_13 OFFSET(13) NUMBITS(1) [], + EN_14 OFFSET(14) NUMBITS(1) [], + EN_15 OFFSET(15) NUMBITS(1) [], + EN_16 OFFSET(16) NUMBITS(1) [], + EN_17 OFFSET(17) NUMBITS(1) [], + EN_18 OFFSET(18) NUMBITS(1) [], + EN_19 OFFSET(19) NUMBITS(1) [], + EN_20 OFFSET(20) NUMBITS(1) [], + EN_21 OFFSET(21) NUMBITS(1) [], + EN_22 OFFSET(22) NUMBITS(1) [], + EN_23 OFFSET(23) NUMBITS(1) [], + EN_24 OFFSET(24) NUMBITS(1) [], + EN_25 OFFSET(25) NUMBITS(1) [], + EN_26 OFFSET(26) NUMBITS(1) [], + EN_27 OFFSET(27) NUMBITS(1) [], + EN_28 OFFSET(28) NUMBITS(1) [], + EN_29 OFFSET(29) NUMBITS(1) [], + EN_30 OFFSET(30) NUMBITS(1) [], + EN_31 OFFSET(31) NUMBITS(1) [] + ], + pub(crate) MIO_PAD_SLEEP_REGWEN [ + EN_0 OFFSET(0) NUMBITS(1) [] + ], + pub(crate) MIO_PAD_SLEEP_EN [ + EN_0 OFFSET(0) NUMBITS(1) [] + ], + pub(crate) MIO_PAD_SLEEP_MODE [ + OUT_0 OFFSET(0) NUMBITS(2) [ + TIE_LOW = 0, + TIE_HIGH = 1, + HIGH_Z = 2, + KEEP = 3 + ] + ], + pub(crate) DIO_PAD_SLEEP_STATUS [ + EN_0 OFFSET(0) NUMBITS(1) [], + EN_1 OFFSET(1) NUMBITS(1) [], + EN_2 OFFSET(2) NUMBITS(1) [], + EN_3 OFFSET(3) NUMBITS(1) [], + EN_4 OFFSET(4) NUMBITS(1) [], + EN_5 OFFSET(5) NUMBITS(1) [], + EN_6 OFFSET(6) NUMBITS(1) [], + EN_7 OFFSET(7) NUMBITS(1) [], + EN_8 OFFSET(8) NUMBITS(1) [], + EN_9 OFFSET(9) NUMBITS(1) [], + EN_10 OFFSET(10) NUMBITS(1) [], + EN_11 OFFSET(11) NUMBITS(1) [], + EN_12 OFFSET(12) NUMBITS(1) [], + EN_13 OFFSET(13) NUMBITS(1) [], + EN_14 OFFSET(14) NUMBITS(1) [], + EN_15 OFFSET(15) NUMBITS(1) [] + ], + pub(crate) DIO_PAD_SLEEP_REGWEN [ + EN_0 OFFSET(0) NUMBITS(1) [] + ], + pub(crate) DIO_PAD_SLEEP_EN [ + EN_0 OFFSET(0) NUMBITS(1) [] + ], + pub(crate) DIO_PAD_SLEEP_MODE [ + OUT_0 OFFSET(0) NUMBITS(2) [ + TIE_LOW = 0, + TIE_HIGH = 1, + HIGH_Z = 2, + KEEP = 3 + ] + ], + pub(crate) WKUP_DETECTOR_REGWEN [ + EN_0 OFFSET(0) NUMBITS(1) [] + ], + pub(crate) WKUP_DETECTOR_EN [ + EN_0 OFFSET(0) NUMBITS(1) [] + ], + pub(crate) WKUP_DETECTOR [ + MODE_0 OFFSET(0) NUMBITS(3) [ + POSEDGE = 0, + NEGEDGE = 1, + EDGE = 2, + TIMEDHIGH = 3, + TIMEDLOW = 4 + ], + FILTER_0 OFFSET(3) NUMBITS(1) [], + MIODIO_0 OFFSET(4) NUMBITS(1) [] + ], + pub(crate) WKUP_DETECTOR_CNT_TH [ + TH_0 OFFSET(0) NUMBITS(8) [] + ], + pub(crate) WKUP_DETECTOR_PADSEL [ + SEL_0 OFFSET(0) NUMBITS(6) [] + ], + pub(crate) WKUP_CAUSE [ + CAUSE_0 OFFSET(0) NUMBITS(1) [], + CAUSE_1 OFFSET(1) NUMBITS(1) [], + CAUSE_2 OFFSET(2) NUMBITS(1) [], + CAUSE_3 OFFSET(3) NUMBITS(1) [], + CAUSE_4 OFFSET(4) NUMBITS(1) [], + CAUSE_5 OFFSET(5) NUMBITS(1) [], + CAUSE_6 OFFSET(6) NUMBITS(1) [], + CAUSE_7 OFFSET(7) NUMBITS(1) [] + ] +]; + +// End generated register constants for pinmux + +pub trait PinmuxHAL { + fn output_select(&self, pad: u32, peripheral: u32) -> ReturnCode; + fn input_select(&self, peripheral: u32, pad: u32) -> ReturnCode; +} + +pub struct PinmuxHw { + registers: StaticRef<PinmuxRegisters>, +} + +impl PinmuxHw { + pub const fn new(base: StaticRef<PinmuxRegisters>) -> PinmuxHw { + PinmuxHw { + registers: base + } + } + + fn is_locked(&self, pad: u32, target: PinmuxLockTarget) -> bool { + match target { + PinmuxLockTarget::Insel => + !self.registers.mio_periph_insel_regwen[pad as usize] + .is_set(MIO_PERIPH_INSEL_REGWEN::EN_0), + PinmuxLockTarget::Outsel => + !self.registers.mio_outsel_regwen[pad as usize] + .is_set(MIO_OUTSEL_REGWEN::EN_0), + PinmuxLockTarget::MioSleep => + !self.registers.mio_pad_sleep_regwen[pad as usize] + .is_set(MIO_PAD_SLEEP_REGWEN::EN_0), + PinmuxLockTarget::DioSleep => + !self.registers.dio_pad_sleep_regwen[pad as usize] + .is_set(DIO_PAD_SLEEP_REGWEN::EN_0), + PinmuxLockTarget::MioPadAttr => + !self.registers.mio_pad_attr_regwen[pad as usize] + .is_set(MIO_PAD_ATTR_REGWEN::EN_0), + PinmuxLockTarget::DioPadAttr => + !self.registers.dio_pad_attr_regwen[pad as usize] + .is_set(DIO_PAD_ATTR_REGWEN::EN_0), + PinmuxLockTarget::WakeupDetector => + !self.registers.wkup_detector_regwen[pad as usize] + .is_set(WKUP_DETECTOR_REGWEN::EN_0), + } + } +} + +impl PinmuxHAL for PinmuxHw { + fn output_select(&self, pad: u32, peripheral: u32) -> ReturnCode { + if pad >= PINMUX_PARAM_N_MIO_PADS || + peripheral >= (3 + PINMUX_PARAM_N_MIO_PERIPH_OUT) { + return ReturnCode::EINVAL; + } + + if self.is_locked(pad, PinmuxLockTarget::Outsel) { + return ReturnCode::EINVAL; + } + + self.registers.mio_outsel[pad as usize] + .modify(MIO_OUTSEL::OUT_0.val(peripheral)); + + ReturnCode::SUCCESS + } + + fn input_select(&self, peripheral: u32, pad: u32) -> ReturnCode { + if peripheral >= PINMUX_PARAM_N_MIO_PERIPH_IN || + pad >= (2 + PINMUX_PARAM_N_MIO_PADS) { + return ReturnCode::EINVAL; + } + + if self.is_locked(peripheral, PinmuxLockTarget::Insel) { + return ReturnCode::EINVAL; + } + + self.registers.mio_periph_insel[peripheral as usize] + .modify(MIO_PERIPH_INSEL::IN_0.val(pad)); + + ReturnCode::SUCCESS + } +}
diff --git a/platform/src/main.rs b/platform/src/main.rs index 98186f1..77c566a 100644 --- a/platform/src/main.rs +++ b/platform/src/main.rs
@@ -37,11 +37,13 @@ use matcha_capsules::elfloader_capsule::ElfLoaderCapsule; use matcha_capsules::mailbox_capsule::MailboxCapsule; use matcha_capsules::storage_capsule::StorageCapsule; +use matcha_capsules::pinmux_capsule::PinmuxCapsule; use matcha_config::*; use matcha_hal::spi_host_hal; use matcha_hal::timer_hal; use matcha_hal::uart_hal; use matcha_hal::smc_ctrl_hal; +use matcha_hal::pinmux_hal; use rv32i::csr; pub mod chip; @@ -151,6 +153,7 @@ 'static, capsules::virtual_uart::UartDevice<'static>, >, + pinmux_capsule: &'static PinmuxCapsule, } /// Mapping of integer syscalls to objects that implement syscalls. @@ -167,6 +170,7 @@ CAPSULE_ELFLOADER => f(Some(self.elfloader_capsule)), CAPSULE_MAILBOX => f(Some(self.mailbox_capsule)), CAPSULE_LLDB => f(Some(self.lldb_capsule)), + CAPSULE_PINMUX => f(Some(self.pinmux_capsule)), _ => f(None), } } @@ -314,6 +318,14 @@ elfloader_capsule.set_mailbox(mailbox_hal); chip.set_mailbox_isr(mailbox_hal); + let pinmux_capsule = static_init!( + matcha_capsules::pinmux_capsule::PinmuxCapsule, + matcha_capsules::pinmux_capsule::PinmuxCapsule::new( + board_kernel.create_grant(&memory_allocation_cap), + ) + ); + pinmux_capsule.set_pinmux(&pinmux_hal::PINMUX); + let mux_spi = components::spi::SpiMuxComponent::new( &spi_host_hal::SPI_HOST0 ).finalize(components::spi_mux_component_helper!(spi_host_hal::SpiHw)); @@ -389,6 +401,7 @@ elfloader_capsule: elfloader_capsule, mailbox_capsule: mailbox_capsule, lldb_capsule: lldb_capsule, + pinmux_capsule: pinmux_capsule, }; kernel::procs::load_processes(