Skip to content

Commit

Permalink
Merge #1981
Browse files Browse the repository at this point in the history
1981: LowRISC: Initial commit of Pad Controller r=hudson-ayers a=alistair23

### Pull Request Overview

This PR adds support for the Pad Controller to the GPIO device.


### Testing Strategy

Booting Tock on the OT FPGA.


### TODO or Help Wanted

### Documentation Updated

- [X] Updated the relevant files in `/docs`, or no updates are required.

### Formatting

- [X] Ran `make prepush`.


Co-authored-by: Alistair Francis <alistair.francis@wdc.com>
  • Loading branch information
bors[bot] and alistair23 committed Jun 29, 2020
2 parents 4e3c160 + a10d0c5 commit 57f8a12
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 72 deletions.
68 changes: 36 additions & 32 deletions chips/ibex/src/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ use core::ops::{Index, IndexMut};
use kernel::common::StaticRef;
pub use lowrisc::gpio::GpioPin;
use lowrisc::gpio::{pins, GpioRegisters};
use lowrisc::padctrl::PadCtrlRegisters;

const PADCTRL_BASE: StaticRef<PadCtrlRegisters> =
unsafe { StaticRef::new(0x4016_0000 as *const PadCtrlRegisters) };

const GPIO0_BASE: StaticRef<GpioRegisters> =
unsafe { StaticRef::new(0x4001_0000 as *const GpioRegisters) };
Expand All @@ -29,37 +33,37 @@ impl IndexMut<usize> for Port {

pub static mut PORT: Port = Port {
pins: [
GpioPin::new(GPIO0_BASE, pins::pin0),
GpioPin::new(GPIO0_BASE, pins::pin1),
GpioPin::new(GPIO0_BASE, pins::pin2),
GpioPin::new(GPIO0_BASE, pins::pin3),
GpioPin::new(GPIO0_BASE, pins::pin4),
GpioPin::new(GPIO0_BASE, pins::pin5),
GpioPin::new(GPIO0_BASE, pins::pin6),
GpioPin::new(GPIO0_BASE, pins::pin7),
GpioPin::new(GPIO0_BASE, pins::pin8),
GpioPin::new(GPIO0_BASE, pins::pin9),
GpioPin::new(GPIO0_BASE, pins::pin10),
GpioPin::new(GPIO0_BASE, pins::pin11),
GpioPin::new(GPIO0_BASE, pins::pin12),
GpioPin::new(GPIO0_BASE, pins::pin13),
GpioPin::new(GPIO0_BASE, pins::pin14),
GpioPin::new(GPIO0_BASE, pins::pin15),
GpioPin::new(GPIO0_BASE, pins::pin16),
GpioPin::new(GPIO0_BASE, pins::pin17),
GpioPin::new(GPIO0_BASE, pins::pin18),
GpioPin::new(GPIO0_BASE, pins::pin19),
GpioPin::new(GPIO0_BASE, pins::pin20),
GpioPin::new(GPIO0_BASE, pins::pin21),
GpioPin::new(GPIO0_BASE, pins::pin22),
GpioPin::new(GPIO0_BASE, pins::pin23),
GpioPin::new(GPIO0_BASE, pins::pin24),
GpioPin::new(GPIO0_BASE, pins::pin25),
GpioPin::new(GPIO0_BASE, pins::pin26),
GpioPin::new(GPIO0_BASE, pins::pin27),
GpioPin::new(GPIO0_BASE, pins::pin28),
GpioPin::new(GPIO0_BASE, pins::pin29),
GpioPin::new(GPIO0_BASE, pins::pin30),
GpioPin::new(GPIO0_BASE, pins::pin31),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin0),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin1),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin2),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin3),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin4),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin5),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin6),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin7),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin8),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin9),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin10),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin11),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin12),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin13),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin14),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin15),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin16),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin17),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin18),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin19),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin20),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin21),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin22),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin23),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin24),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin25),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin26),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin27),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin28),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin29),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin30),
GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin31),
],
};
124 changes: 84 additions & 40 deletions chips/lowrisc/src/gpio.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! General Purpose Input/Output driver.

use crate::padctrl;
use kernel::common::cells::OptionalCell;
use kernel::common::registers::{
register_bitfields, register_structs, Field, ReadOnly, ReadWrite, WriteOnly,
Expand Down Expand Up @@ -70,15 +71,21 @@ register_bitfields![u32,
];

pub struct GpioPin {
registers: StaticRef<GpioRegisters>,
gpio_registers: StaticRef<GpioRegisters>,
padctrl_registers: StaticRef<padctrl::PadCtrlRegisters>,
pin: Field<u32, pins::Register>,
client: OptionalCell<&'static dyn gpio::Client>,
}

impl GpioPin {
pub const fn new(base: StaticRef<GpioRegisters>, pin: Field<u32, pins::Register>) -> GpioPin {
pub const fn new(
gpio_base: StaticRef<GpioRegisters>,
padctrl_base: StaticRef<padctrl::PadCtrlRegisters>,
pin: Field<u32, pins::Register>,
) -> GpioPin {
GpioPin {
registers: base,
gpio_registers: gpio_base,
padctrl_registers: padctrl_base,
pin: pin,
client: OptionalCell::empty(),
}
Expand All @@ -104,11 +111,10 @@ impl GpioPin {
}

pub fn handle_interrupt(&self) {
let regs = self.registers;
let pin = self.pin;

if regs.intr_state.is_set(pin) {
regs.intr_state.modify(pin.val(1));
if self.gpio_registers.intr_state.is_set(pin) {
self.gpio_registers.intr_state.modify(pin.val(1));
self.client.map(|client| {
client.fired();
});
Expand All @@ -118,19 +124,59 @@ impl GpioPin {

impl gpio::Configure for GpioPin {
fn configuration(&self) -> gpio::Configuration {
match self.registers.direct_oe.is_set(self.pin) {
match self.gpio_registers.direct_oe.is_set(self.pin) {
true => gpio::Configuration::InputOutput,
false => gpio::Configuration::Input,
}
}

fn set_floating_state(&self, _mode: gpio::FloatingState) {
panic!("OpenTitan does not allow configuration of floating state");
fn set_floating_state(&self, mode: gpio::FloatingState) {
// There is unfortunately no documentation about how these
// registers map to the actual GPIOs, so just write all of them.
match mode {
gpio::FloatingState::PullUp => {
self.padctrl_registers.dio_pads.write(
padctrl::DIO_PADS::ATTR0_PULL_UP::SET
+ padctrl::DIO_PADS::ATTR1_PULL_UP::SET
+ padctrl::DIO_PADS::ATTR2_PULL_UP::SET
+ padctrl::DIO_PADS::ATTR3_PULL_UP::SET,
);
}
gpio::FloatingState::PullDown => {
self.padctrl_registers.dio_pads.write(
padctrl::DIO_PADS::ATTR0_PULL_DOWN::SET
+ padctrl::DIO_PADS::ATTR1_PULL_DOWN::SET
+ padctrl::DIO_PADS::ATTR2_PULL_DOWN::SET
+ padctrl::DIO_PADS::ATTR3_PULL_DOWN::SET,
);
}
gpio::FloatingState::PullNone => {
self.padctrl_registers.dio_pads.write(
padctrl::DIO_PADS::ATTR0_OPEN_DRAIN::SET
+ padctrl::DIO_PADS::ATTR1_OPEN_DRAIN::SET
+ padctrl::DIO_PADS::ATTR2_OPEN_DRAIN::SET
+ padctrl::DIO_PADS::ATTR3_OPEN_DRAIN::SET,
);
}
}
}

fn floating_state(&self) -> gpio::FloatingState {
// TODO: check this against the design
gpio::FloatingState::PullNone
if self
.padctrl_registers
.dio_pads
.is_set(padctrl::DIO_PADS::ATTR0_PULL_UP)
{
gpio::FloatingState::PullUp
} else if self
.padctrl_registers
.dio_pads
.is_set(padctrl::DIO_PADS::ATTR0_PULL_DOWN)
{
gpio::FloatingState::PullDown
} else {
gpio::FloatingState::PullNone
}
}

fn deactivate_to_low_power(&self) {
Expand All @@ -139,18 +185,21 @@ impl gpio::Configure for GpioPin {
}

fn make_output(&self) -> gpio::Configuration {
let regs = self.registers;
GpioPin::half_set(true, self.pin, &regs.masked_oe_lower, &regs.masked_oe_upper);
GpioPin::half_set(
true,
self.pin,
&self.gpio_registers.masked_oe_lower,
&self.gpio_registers.masked_oe_upper,
);
gpio::Configuration::InputOutput
}

fn disable_output(&self) -> gpio::Configuration {
let regs = self.registers;
GpioPin::half_set(
false,
self.pin,
&regs.masked_oe_lower,
&regs.masked_oe_upper,
&self.gpio_registers.masked_oe_lower,
&self.gpio_registers.masked_oe_upper,
);
gpio::Configuration::Input
}
Expand All @@ -166,42 +215,39 @@ impl gpio::Configure for GpioPin {

impl gpio::Input for GpioPin {
fn read(&self) -> bool {
self.registers.data_in.is_set(self.pin)
self.gpio_registers.data_in.is_set(self.pin)
}
}

impl gpio::Output for GpioPin {
fn toggle(&self) -> bool {
let regs = self.registers;
let pin = self.pin;
let new_state = !regs.direct_out.is_set(pin);
let new_state = !self.gpio_registers.direct_out.is_set(pin);

GpioPin::half_set(
new_state,
self.pin,
&regs.masked_out_lower,
&regs.masked_out_upper,
&self.gpio_registers.masked_out_lower,
&self.gpio_registers.masked_out_upper,
);
new_state
}

fn set(&self) {
let regs = self.registers;
GpioPin::half_set(
true,
self.pin,
&regs.masked_out_lower,
&regs.masked_out_upper,
&self.gpio_registers.masked_out_lower,
&self.gpio_registers.masked_out_upper,
);
}

fn clear(&self) {
let regs = self.registers;
GpioPin::half_set(
false,
self.pin,
&regs.masked_out_lower,
&regs.masked_out_upper,
&self.gpio_registers.masked_out_lower,
&self.gpio_registers.masked_out_upper,
);
}
}
Expand All @@ -212,38 +258,36 @@ impl gpio::Interrupt for GpioPin {
}

fn enable_interrupts(&self, mode: gpio::InterruptEdge) {
let regs = self.registers;
let pin = self.pin;

match mode {
gpio::InterruptEdge::RisingEdge => {
regs.intr_ctrl_en_rising.modify(pin.val(1));
regs.intr_ctrl_en_falling.modify(pin.val(0));
self.gpio_registers.intr_ctrl_en_rising.modify(pin.val(1));
self.gpio_registers.intr_ctrl_en_falling.modify(pin.val(0));
}
gpio::InterruptEdge::FallingEdge => {
regs.intr_ctrl_en_rising.modify(pin.val(0));
regs.intr_ctrl_en_falling.modify(pin.val(1));
self.gpio_registers.intr_ctrl_en_rising.modify(pin.val(0));
self.gpio_registers.intr_ctrl_en_falling.modify(pin.val(1));
}
gpio::InterruptEdge::EitherEdge => {
regs.intr_ctrl_en_rising.modify(pin.val(1));
regs.intr_ctrl_en_falling.modify(pin.val(1));
self.gpio_registers.intr_ctrl_en_rising.modify(pin.val(1));
self.gpio_registers.intr_ctrl_en_falling.modify(pin.val(1));
}
}
regs.intr_state.modify(pin.val(1));
regs.intr_enable.modify(pin.val(1));
self.gpio_registers.intr_state.modify(pin.val(1));
self.gpio_registers.intr_enable.modify(pin.val(1));
}

fn disable_interrupts(&self) {
let regs = self.registers;
let pin = self.pin;

regs.intr_enable.modify(pin.val(0));
self.gpio_registers.intr_enable.modify(pin.val(0));
// Clear any pending interrupt
regs.intr_state.modify(pin.val(1));
self.gpio_registers.intr_state.modify(pin.val(1));
}

fn is_pending(&self) -> bool {
self.registers.intr_state.is_set(self.pin)
self.gpio_registers.intr_state.is_set(self.pin)
}
}

Expand Down
1 change: 1 addition & 0 deletions chips/lowrisc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
pub mod gpio;
pub mod hmac;
pub mod i2c;
pub mod padctrl;
pub mod pwrmgr;
pub mod uart;
pub mod usbdev;
47 changes: 47 additions & 0 deletions chips/lowrisc/src/padctrl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//! General Purpose Input/Output driver.

use kernel::common::registers::{register_bitfields, register_structs, ReadWrite};

register_structs! {
pub PadCtrlRegisters {
(0x00 => pub regen: ReadWrite<u32, REGEN::Register>),
(0x04 => pub dio_pads: ReadWrite<u32, DIO_PADS::Register>),
(0x08 => pub mio_pads0: ReadWrite<u32, DIO_PADS::Register>),
(0x0c => pub mio_pads1: ReadWrite<u32, DIO_PADS::Register>),
(0x10 => pub mio_pads2: ReadWrite<u32, DIO_PADS::Register>),
(0x14 => pub mio_pads3: ReadWrite<u32, DIO_PADS::Register>),
(0x18 => @END),
}
}

register_bitfields![u32,
pub REGEN [
WEN OFFSET(0) NUMBITS(1) []
],
pub DIO_PADS [
ATTR0_IO_INV OFFSET(0) NUMBITS(1) [],
ATTR0_OPEN_DRAIN OFFSET(1) NUMBITS(1) [],
ATTR0_PULL_DOWN OFFSET(2) NUMBITS(1) [],
ATTR0_PULL_UP OFFSET(3) NUMBITS(1) [],
ATTR0_KEEPER OFFSET(4) NUMBITS(1) [],
ATTR0_STRENGTH OFFSET(5) NUMBITS(1) [],
ATTR1_IO_INV OFFSET(8) NUMBITS(1) [],
ATTR1_OPEN_DRAIN OFFSET(9) NUMBITS(1) [],
ATTR1_PULL_DOWN OFFSET(10) NUMBITS(1) [],
ATTR1_PULL_UP OFFSET(11) NUMBITS(1) [],
ATTR1_KEEPER OFFSET(12) NUMBITS(1) [],
ATTR1_STRENGTH OFFSET(13) NUMBITS(1) [],
ATTR2_IO_INV OFFSET(16) NUMBITS(1) [],
ATTR2_OPEN_DRAIN OFFSET(17) NUMBITS(1) [],
ATTR2_PULL_DOWN OFFSET(18) NUMBITS(1) [],
ATTR2_PULL_UP OFFSET(19) NUMBITS(1) [],
ATTR2_KEEPER OFFSET(20) NUMBITS(1) [],
ATTR2_STRENGTH OFFSET(21) NUMBITS(1) [],
ATTR3_IO_INV OFFSET(24) NUMBITS(1) [],
ATTR3_OPEN_DRAIN OFFSET(25) NUMBITS(1) [],
ATTR3_PULL_DOWN OFFSET(26) NUMBITS(1) [],
ATTR3_PULL_UP OFFSET(27) NUMBITS(1) [],
ATTR3_KEEPER OFFSET(28) NUMBITS(1) [],
ATTR3_STRENGTH OFFSET(29) NUMBITS(1) []
]
];

0 comments on commit 57f8a12

Please sign in to comment.