strat9_bus_drivers/
imx_weim.rs1use crate::{BusChild, BusDriver, BusError, PowerState, mmio::MmioRegion};
2use alloc::{string::String, vec::Vec};
3
4const MAX_CS_REGS_COUNT: usize = 6;
5const MAX_CS_COUNT: usize = 6;
6
7const COMPATIBLE: &[&str] = &[
8 "fsl,imx1-weim",
9 "fsl,imx27-weim",
10 "fsl,imx50-weim",
11 "fsl,imx51-weim",
12 "fsl,imx6q-weim",
13];
14
15#[derive(Clone, Copy)]
16pub struct WeimDevtype {
17 pub cs_count: usize,
18 pub cs_regs_count: usize,
19 pub cs_stride: usize,
20 pub wcr_offset: usize,
21 pub wcr_bcm: u32,
22 pub wcr_cont_bclk: u32,
23}
24
25pub const IMX1_WEIM: WeimDevtype = WeimDevtype {
26 cs_count: 6,
27 cs_regs_count: 2,
28 cs_stride: 0x08,
29 wcr_offset: 0,
30 wcr_bcm: 0,
31 wcr_cont_bclk: 0,
32};
33
34pub const IMX27_WEIM: WeimDevtype = WeimDevtype {
35 cs_count: 6,
36 cs_regs_count: 3,
37 cs_stride: 0x10,
38 wcr_offset: 0,
39 wcr_bcm: 0,
40 wcr_cont_bclk: 0,
41};
42
43pub const IMX50_WEIM: WeimDevtype = WeimDevtype {
44 cs_count: 4,
45 cs_regs_count: 6,
46 cs_stride: 0x18,
47 wcr_offset: 0x90,
48 wcr_bcm: 1 << 0,
49 wcr_cont_bclk: 1 << 3,
50};
51
52pub const IMX51_WEIM: WeimDevtype = WeimDevtype {
53 cs_count: 6,
54 cs_regs_count: 6,
55 cs_stride: 0x18,
56 wcr_offset: 0,
57 wcr_bcm: 0,
58 wcr_cont_bclk: 0,
59};
60
61pub struct CsTiming {
62 pub is_applied: bool,
63 pub regs: [u32; MAX_CS_REGS_COUNT],
64}
65
66impl CsTiming {
67 pub const fn new() -> Self {
69 Self {
70 is_applied: false,
71 regs: [0; MAX_CS_REGS_COUNT],
72 }
73 }
74}
75
76pub struct ImxWeim {
77 regs: MmioRegion,
78 devtype: WeimDevtype,
79 timings: [CsTiming; MAX_CS_COUNT],
80 power_state: PowerState,
81 children: Vec<BusChild>,
82}
83
84impl ImxWeim {
85 pub fn new(devtype: WeimDevtype) -> Self {
87 Self {
88 regs: MmioRegion::new(),
89 devtype,
90 timings: [const { CsTiming::new() }; MAX_CS_COUNT],
91 power_state: PowerState::Off,
92 children: Vec::new(),
93 }
94 }
95
96 pub fn set_cs_timing(&mut self, cs: usize, regs: &[u32]) {
98 if cs >= self.devtype.cs_count || regs.len() > self.devtype.cs_regs_count {
99 return;
100 }
101 for (i, &val) in regs.iter().enumerate() {
102 self.timings[cs].regs[i] = val;
103 }
104 self.timings[cs].is_applied = true;
105 }
106
107 pub fn apply_timings(&self) {
109 for cs in 0..self.devtype.cs_count {
110 if !self.timings[cs].is_applied {
111 continue;
112 }
113 let base = cs * self.devtype.cs_stride;
114 for i in 0..self.devtype.cs_regs_count {
115 self.regs.write32(base + i * 4, self.timings[cs].regs[i]);
116 }
117 }
118 }
119
120 pub fn set_burst_clock(&self, enable: bool) {
122 if self.devtype.wcr_offset == 0 {
123 return;
124 }
125 let mut wcr = self.regs.read32(self.devtype.wcr_offset);
126 if enable {
127 wcr |= self.devtype.wcr_bcm;
128 } else {
129 wcr &= !self.devtype.wcr_bcm;
130 }
131 self.regs.write32(self.devtype.wcr_offset, wcr);
132 }
133
134 pub fn add_child(&mut self, child: BusChild) {
136 self.children.push(child);
137 }
138}
139
140impl BusDriver for ImxWeim {
141 fn name(&self) -> &str {
143 "imx-weim"
144 }
145
146 fn compatible(&self) -> &[&str] {
148 COMPATIBLE
149 }
150
151 fn init(&mut self, base: usize) -> Result<(), BusError> {
153 let size = self.devtype.cs_count * self.devtype.cs_stride + 0x100;
154 self.regs.init(base, size);
155 self.apply_timings();
156 self.power_state = PowerState::On;
157 Ok(())
158 }
159
160 fn shutdown(&mut self) -> Result<(), BusError> {
162 self.power_state = PowerState::Off;
163 Ok(())
164 }
165
166 fn read_reg(&self, offset: usize) -> Result<u32, BusError> {
168 if !self.regs.is_valid() {
169 return Err(BusError::InitFailed);
170 }
171 Ok(self.regs.read32(offset))
172 }
173
174 fn write_reg(&mut self, offset: usize, value: u32) -> Result<(), BusError> {
176 if !self.regs.is_valid() {
177 return Err(BusError::InitFailed);
178 }
179 self.regs.write32(offset, value);
180 Ok(())
181 }
182
183 fn children(&self) -> Vec<BusChild> {
185 self.children.clone()
186 }
187}