Skip to main content

strat9_bus_drivers/
intel_ixp4xx_eb.rs

1use crate::{BusChild, BusDriver, BusError, PowerState, mmio::MmioRegion};
2use alloc::{string::String, vec::Vec};
3
4const IXP4XX_EXP_CS_EN: u32 = 1 << 31;
5const IXP456_EXP_PAR_EN: u32 = 1 << 30;
6const IXP4XX_EXP_T1_MASK: u32 = 0x3 << 28;
7const IXP4XX_EXP_T1_SHIFT: u32 = 28;
8const IXP4XX_EXP_T2_MASK: u32 = 0x3 << 26;
9const IXP4XX_EXP_T2_SHIFT: u32 = 26;
10const IXP4XX_EXP_T3_MASK: u32 = 0xF << 22;
11const IXP4XX_EXP_T3_SHIFT: u32 = 22;
12const IXP4XX_EXP_T4_MASK: u32 = 0x3 << 20;
13const IXP4XX_EXP_T4_SHIFT: u32 = 20;
14const IXP4XX_EXP_T5_MASK: u32 = 0xF << 16;
15const IXP4XX_EXP_T5_SHIFT: u32 = 16;
16const IXP4XX_EXP_CYC_TYPE_MASK: u32 = 0x3 << 14;
17const IXP4XX_EXP_CYC_TYPE_SHIFT: u32 = 14;
18const IXP4XX_EXP_SIZE_MASK: u32 = 0xF << 10;
19const IXP4XX_EXP_SIZE_SHIFT: u32 = 10;
20const IXP4XX_EXP_BYTE_RD16: u32 = 1 << 6;
21const IXP4XX_EXP_HRDY_POL: u32 = 1 << 5;
22const IXP4XX_EXP_MUX_EN: u32 = 1 << 4;
23const IXP4XX_EXP_SPLT_EN: u32 = 1 << 3;
24const IXP4XX_EXP_WR_EN: u32 = 1 << 1;
25const IXP4XX_EXP_BYTE_EN: u32 = 1 << 0;
26
27const IXP4XX_EXP_CNFG0: usize = 0x20;
28const IXP4XX_EXP_CNFG0_MEM_MAP: u32 = 1 << 31;
29
30const BOOT_BASE: u64 = 0x0000_0000;
31const NORMAL_BASE: u64 = 0x5000_0000;
32const CS_STRIDE: u64 = 0x0100_0000;
33const MAX_CS: usize = 8;
34
35const COMPATIBLE: &[&str] = &[
36    "intel,ixp42x-expansion-bus-controller",
37    "intel,ixp43x-expansion-bus-controller",
38    "intel,ixp45x-expansion-bus-controller",
39    "intel,ixp46x-expansion-bus-controller",
40];
41
42pub struct CsTimingConfig {
43    pub t1: u32,
44    pub t2: u32,
45    pub t3: u32,
46    pub t4: u32,
47    pub t5: u32,
48    pub cycle_type: u32,
49    pub byte_rd16: bool,
50    pub mux_en: bool,
51    pub splt_en: bool,
52    pub wr_en: bool,
53    pub byte_en: bool,
54    pub hrdy_pol: bool,
55}
56
57pub struct IntelIxp4xxEb {
58    regs: MmioRegion,
59    bus_base: u64,
60    num_cs: usize,
61    is_42x: bool,
62    is_43x: bool,
63    power_state: PowerState,
64    children: Vec<BusChild>,
65}
66
67impl IntelIxp4xxEb {
68    /// Creates a new instance.
69    pub fn new() -> Self {
70        Self {
71            regs: MmioRegion::new(),
72            bus_base: NORMAL_BASE,
73            num_cs: MAX_CS,
74            is_42x: false,
75            is_43x: false,
76            power_state: PowerState::Off,
77            children: Vec::new(),
78        }
79    }
80
81    /// Sets variant.
82    pub fn set_variant(&mut self, is_42x: bool, is_43x: bool) {
83        self.is_42x = is_42x;
84        self.is_43x = is_43x;
85        if is_43x {
86            self.num_cs = 4;
87        }
88    }
89
90    /// Performs the detect bus base operation.
91    fn detect_bus_base(&mut self) {
92        let cnfg0 = self.regs.read32(IXP4XX_EXP_CNFG0);
93        self.bus_base = if cnfg0 & IXP4XX_EXP_CNFG0_MEM_MAP != 0 {
94            NORMAL_BASE
95        } else {
96            BOOT_BASE
97        };
98    }
99
100    /// Performs the configure cs operation.
101    pub fn configure_cs(&self, cs: usize, config: &CsTimingConfig) -> Result<(), BusError> {
102        if cs >= self.num_cs {
103            return Err(BusError::InvalidArgument);
104        }
105
106        let offset = cs * 4;
107        let mut val = IXP4XX_EXP_CS_EN;
108
109        val |= (config.t1 << IXP4XX_EXP_T1_SHIFT) & IXP4XX_EXP_T1_MASK;
110        val |= (config.t2 << IXP4XX_EXP_T2_SHIFT) & IXP4XX_EXP_T2_MASK;
111        val |= (config.t3 << IXP4XX_EXP_T3_SHIFT) & IXP4XX_EXP_T3_MASK;
112        val |= (config.t4 << IXP4XX_EXP_T4_SHIFT) & IXP4XX_EXP_T4_MASK;
113        val |= (config.t5 << IXP4XX_EXP_T5_SHIFT) & IXP4XX_EXP_T5_MASK;
114        val |= (config.cycle_type << IXP4XX_EXP_CYC_TYPE_SHIFT) & IXP4XX_EXP_CYC_TYPE_MASK;
115
116        if config.byte_rd16 {
117            val |= IXP4XX_EXP_BYTE_RD16;
118        }
119        if config.mux_en {
120            val |= IXP4XX_EXP_MUX_EN;
121        }
122        if config.splt_en {
123            val |= IXP4XX_EXP_SPLT_EN;
124        }
125        if config.wr_en {
126            val |= IXP4XX_EXP_WR_EN;
127        }
128        if config.byte_en {
129            val |= IXP4XX_EXP_BYTE_EN;
130        }
131        if config.hrdy_pol && self.is_42x {
132            val |= IXP4XX_EXP_HRDY_POL;
133        }
134
135        self.regs.write32(offset, val);
136        Ok(())
137    }
138
139    /// Performs the cs base addr operation.
140    pub fn cs_base_addr(&self, cs: usize) -> u64 {
141        self.bus_base + (cs as u64) * CS_STRIDE
142    }
143
144    /// Performs the add child operation.
145    pub fn add_child(&mut self, child: BusChild) {
146        self.children.push(child);
147    }
148}
149
150impl BusDriver for IntelIxp4xxEb {
151    /// Performs the name operation.
152    fn name(&self) -> &str {
153        "intel-ixp4xx-eb"
154    }
155
156    /// Performs the compatible operation.
157    fn compatible(&self) -> &[&str] {
158        COMPATIBLE
159    }
160
161    /// Performs the init operation.
162    fn init(&mut self, base: usize) -> Result<(), BusError> {
163        self.regs.init(base, 0x30);
164        self.detect_bus_base();
165        self.power_state = PowerState::On;
166        Ok(())
167    }
168
169    /// Performs the shutdown operation.
170    fn shutdown(&mut self) -> Result<(), BusError> {
171        self.power_state = PowerState::Off;
172        Ok(())
173    }
174
175    /// Reads reg.
176    fn read_reg(&self, offset: usize) -> Result<u32, BusError> {
177        if !self.regs.is_valid() {
178            return Err(BusError::InitFailed);
179        }
180        Ok(self.regs.read32(offset))
181    }
182
183    /// Writes reg.
184    fn write_reg(&mut self, offset: usize, value: u32) -> Result<(), BusError> {
185        if !self.regs.is_valid() {
186            return Err(BusError::InitFailed);
187        }
188        self.regs.write32(offset, value);
189        Ok(())
190    }
191
192    /// Performs the children operation.
193    fn children(&self) -> Vec<BusChild> {
194        self.children.clone()
195    }
196}