use alloc::vec::Vec;
use crate::image::{Chip, CsConfig, CsLogic};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ControlLineKind {
Ce,
Oe,
Cs1,
Cs2,
Cs3,
}
impl ControlLineKind {
pub(crate) fn name(self) -> &'static str {
match self {
Self::Ce => "ce",
Self::Oe => "oe",
Self::Cs1 => "cs1",
Self::Cs2 => "cs2",
Self::Cs3 => "cs3",
}
}
}
fn name_to_control_line_kind(name: &str) -> Option<ControlLineKind> {
match name {
"ce" => Some(ControlLineKind::Ce),
"oe" => Some(ControlLineKind::Oe),
"cs1" => Some(ControlLineKind::Cs1),
"cs2" => Some(ControlLineKind::Cs2),
"cs3" => Some(ControlLineKind::Cs3),
_ => None,
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MultiChipCsConfig {
pub per_chip_select: ControlLineKind,
pub commoned_lines: Vec<ControlLineKind>,
pub ignored_lines: Vec<ControlLineKind>,
}
pub(crate) fn control_line_logic(name: &str, cs_config: &CsConfig) -> CsLogic {
match name {
"ce" => match cs_config {
CsConfig::CeOe => CsLogic::ActiveLow,
CsConfig::CeOeExplicit { ce, .. } => *ce,
CsConfig::ChipSelect { .. } => CsLogic::ActiveLow,
},
"oe" => match cs_config {
CsConfig::CeOe => CsLogic::ActiveLow,
CsConfig::CeOeExplicit { oe, .. } => *oe,
CsConfig::ChipSelect { .. } => CsLogic::ActiveLow,
},
"cs1" => cs_config.cs1_logic().unwrap_or(CsLogic::ActiveLow),
"cs2" => cs_config.cs2_logic().unwrap_or(CsLogic::ActiveLow),
"cs3" => cs_config.cs3_logic().unwrap_or(CsLogic::ActiveLow),
_ => CsLogic::ActiveLow,
}
}
pub fn derive_multi_cs_config(chips: &[Chip]) -> MultiChipCsConfig {
let chip0_type = *chips[0].chip_type();
let control_lines = chip0_type.control_lines();
let named: Vec<_> = control_lines
.iter()
.filter(|l| name_to_control_line_kind(l.name).is_some())
.collect();
if named.len() == 1 {
let kind = name_to_control_line_kind(named[0].name).expect("filtered to known names above");
return MultiChipCsConfig {
per_chip_select: kind,
commoned_lines: Vec::new(),
ignored_lines: Vec::new(),
};
}
let secondary_config = chips[1].cs_config();
let chip0_config = chips[0].cs_config();
let mut per_chip_select = None;
let mut commoned_lines = Vec::new();
let mut ignored_lines = Vec::new();
for line in &named {
let kind = name_to_control_line_kind(line.name).expect("filtered to known names above");
if control_line_logic(line.name, secondary_config) != CsLogic::Ignore {
per_chip_select = Some(kind);
} else if control_line_logic(line.name, chip0_config) == CsLogic::Ignore {
ignored_lines.push(kind);
} else {
commoned_lines.push(kind);
}
}
MultiChipCsConfig {
per_chip_select: per_chip_select.expect(
"Multi set must have exactly one active select line \
(validated by check_cs_v2)",
),
commoned_lines,
ignored_lines,
}
}