From 02414112fc677087f5b558a0344c9a5fa7c6cbf1 Mon Sep 17 00:00:00 2001 From: Matt Keeter Date: Wed, 15 Jan 2025 14:53:46 -0500 Subject: [PATCH] Add IMX3112 mux and APML devices to Grapefruit --- app/grapefruit/app.toml | 25 +++++++ drv/stm32xx-i2c/src/imx3112.rs | 114 +++++++++++++++++++++++++++++ drv/stm32xx-i2c/src/lib.rs | 1 + task/thermal/src/bsp/grapefruit.rs | 9 ++- 4 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 drv/stm32xx-i2c/src/imx3112.rs diff --git a/app/grapefruit/app.toml b/app/grapefruit/app.toml index 7d21e50ea..d468ebe8a 100644 --- a/app/grapefruit/app.toml +++ b/app/grapefruit/app.toml @@ -403,6 +403,11 @@ sda.pin = 11 scl.pin = 10 af = 4 +[[config.i2c.controllers.ports.B.muxes]] +driver = "imx3112" +address = 0x70 +# U6 on AMD Ruby schematic + [config.i2c.controllers.ports.F] name = "pcie" sda.pin = 0 @@ -528,6 +533,26 @@ sensors = { temperature = 1 } description = "LM75 (H)" refdes = "U104" +[[config.i2c.devices]] +bus = "apml" +address = 0x3c +device = "sbrmi" +name = "RMI" +mux = 1 +segment = 1 +description = "CPU via SB-RMI" + +[[config.i2c.devices]] +bus = "apml" +address = 0x4c +device = "sbtsi" +name = "CPU" +mux = 1 +segment = 1 +description = "CPU temperature sensor" +sensors = { temperature = 1 } + + ################################################################################ [config.spi.spi2] diff --git a/drv/stm32xx-i2c/src/imx3112.rs b/drv/stm32xx-i2c/src/imx3112.rs new file mode 100644 index 000000000..9cfb592d2 --- /dev/null +++ b/drv/stm32xx-i2c/src/imx3112.rs @@ -0,0 +1,114 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +//! Driver for the IMX3112 I2C mux + +use crate::*; +use drv_i2c_api::{ResponseCode, Segment}; + +use bitfield::bitfield; + +#[allow(dead_code)] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum Register { + DeviceTypeLo = 0x0, + DeviceTypeHi = 0x1, + DeviceRevision = 0x2, + VendorIdLo = 0x3, + VendorIdHi = 0x4, + LocalInterfaceCfg = 0xe, + PullupResistorConfig = 0xf, + DeviceCfg = 0x12, + ClearTempSensorAlarm = 0x13, + ClearEccError = 0x14, + TempSensorCfg = 0x1a, + InterruptCfg = 0x1b, + TempHiLimitCfgLo = 0x1c, + TempHiLimitCfgHi = 0x1d, + TempLoLimitCfgLo = 0x1e, + TempLoLimitCfgHi = 0x1f, + TempCritHiLimitCfgLo = 0x20, + TempCritHiLimitCfgHi = 0x21, + TempCritLoLimitCfgLo = 0x22, + TempCritLoLimitCfgHi = 0x23, + DeviceStatus = 0x30, + CurrentTemperatureLo = 0x31, + CurrentTemperatureHi = 0x32, + TemperatureStatus = 0x33, + ErrorStatus = 0x34, + MuxConfig = 0x40, + MuxSelect = 0x41, +} + +bitfield! { + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct MuxSelectRegister(u8); + channel1_enabled, set_channel1_enabled: 6; + channel0_enabled, set_channel0_enabled: 7; +} + +pub struct Imx3112; + +fn write_reg_u8( + mux: &I2cMux<'_>, + controller: &I2cController<'_>, + reg: Register, + val: u8, + ctrl: &I2cControl, +) -> Result<(), ResponseCode> { + controller + .write_read( + mux.address, + 2, + |pos| Some(if pos == 0 { reg as u8 } else { val }), + ReadLength::Fixed(0), + |_, _| Some(()), + ctrl, + ) + .map_err(|e| mux.error_code(e)) +} + +impl I2cMuxDriver for Imx3112 { + fn configure( + &self, + mux: &I2cMux<'_>, + _controller: &I2cController<'_>, + gpio: &sys_api::Sys, + _ctrl: &I2cControl, + ) -> Result<(), drv_i2c_api::ResponseCode> { + // TODO configure registers? + mux.configure(gpio) + } + + fn enable_segment( + &self, + mux: &I2cMux<'_>, + controller: &I2cController<'_>, + segment: Option, + ctrl: &I2cControl, + ) -> Result<(), ResponseCode> { + let mut reg = MuxSelectRegister(0); + match segment { + Some(Segment::S1) => reg.set_channel0_enabled(true), + Some(Segment::S2) => reg.set_channel1_enabled(true), + None => (), + _ => return Err(ResponseCode::SegmentNotFound), + } + // Disable both outputs + write_reg_u8(mux, controller, Register::MuxConfig, 0, ctrl)?; + // Select our desired output + write_reg_u8(mux, controller, Register::MuxSelect, reg.0, ctrl)?; + // Enable our desired output + write_reg_u8(mux, controller, Register::MuxConfig, reg.0, ctrl)?; + Ok(()) + } + + fn reset( + &self, + mux: &I2cMux<'_>, + gpio: &sys_api::Sys, + ) -> Result<(), drv_i2c_api::ResponseCode> { + mux.reset(gpio) + } +} diff --git a/drv/stm32xx-i2c/src/lib.rs b/drv/stm32xx-i2c/src/lib.rs index 3ad18c6d9..4557a9cb2 100644 --- a/drv/stm32xx-i2c/src/lib.rs +++ b/drv/stm32xx-i2c/src/lib.rs @@ -35,6 +35,7 @@ pub type RegisterBlock = device::i2c1::RegisterBlock; ))] pub type Isr = device::i2c1::isr::R; +pub mod imx3112; pub mod ltc4306; pub mod max7358; pub mod pca9545; diff --git a/task/thermal/src/bsp/grapefruit.rs b/task/thermal/src/bsp/grapefruit.rs index 9b989fe24..0642f8e4f 100644 --- a/task/thermal/src/bsp/grapefruit.rs +++ b/task/thermal/src/bsp/grapefruit.rs @@ -22,7 +22,7 @@ use i2c_config::sensors; // Constants! // Air temperature sensors, which aren't used in the control loop -const NUM_TEMPERATURE_SENSORS: usize = 0; +const NUM_TEMPERATURE_SENSORS: usize = 1; // Temperature inputs (I2C devices), which are used in the control loop. pub const NUM_TEMPERATURE_INPUTS: usize = 1; @@ -135,4 +135,9 @@ const INPUTS: [InputChannel; NUM_TEMPERATURE_INPUTS] = [InputChannel::new( ChannelType::MustBePresent, )]; -const MISC_SENSORS: [TemperatureSensor; NUM_TEMPERATURE_SENSORS] = []; +const MISC_SENSORS: [TemperatureSensor; NUM_TEMPERATURE_SENSORS] = + [TemperatureSensor::new( + Device::CPU, + devices::sbtsi_cpu, + sensors::SBTSI_CPU_TEMPERATURE_SENSOR, + )];