strat9_bus_drivers/
tegra_gmi.rs1use crate::{BusChild, BusDriver, BusError, PowerState, mmio::MmioRegion};
2use alloc::{string::String, vec::Vec};
3
4const TEGRA_GMI_CONFIG: usize = 0x00;
5const TEGRA_GMI_TIMING0: usize = 0x10;
6const TEGRA_GMI_TIMING1: usize = 0x14;
7
8const CONFIG_GO: u32 = 1 << 31;
9const BUS_WIDTH_32BIT: u32 = 1 << 30;
10const MUX_MODE: u32 = 1 << 28;
11const RDY_BEFORE_DATA: u32 = 1 << 24;
12const RDY_ACTIVE_HIGH: u32 = 1 << 23;
13const ADV_ACTIVE_HIGH: u32 = 1 << 22;
14const OE_ACTIVE_HIGH: u32 = 1 << 21;
15const CS_ACTIVE_HIGH: u32 = 1 << 20;
16
17const MAX_CHIP_SELECT: u32 = 8;
18
19const COMPATIBLE: &[&str] = &["nvidia,tegra20-gmi", "nvidia,tegra30-gmi"];
20
21fn cs_select(x: u32) -> u32 {
23 (x & 0x7) << 4
24}
25fn muxed_width(x: u32) -> u32 {
27 (x & 0xF) << 12
28}
29fn hold_width(x: u32) -> u32 {
31 (x & 0xF) << 8
32}
33fn adv_width(x: u32) -> u32 {
35 (x & 0xF) << 4
36}
37fn ce_width(x: u32) -> u32 {
39 x & 0xF
40}
41fn we_width(x: u32) -> u32 {
43 (x & 0xFF) << 16
44}
45fn oe_width(x: u32) -> u32 {
47 (x & 0xFF) << 8
48}
49fn wait_width(x: u32) -> u32 {
51 x & 0xFF
52}
53
54pub struct GmiConfig {
55 pub bus_width_32: bool,
56 pub mux_mode: bool,
57 pub rdy_before_data: bool,
58 pub rdy_active_high: bool,
59 pub adv_active_high: bool,
60 pub oe_active_high: bool,
61 pub cs_active_high: bool,
62 pub chip_select: u32,
63}
64
65pub struct GmiTiming {
66 pub muxed_width: u32,
67 pub hold_width: u32,
68 pub adv_width: u32,
69 pub ce_width: u32,
70 pub we_width: u32,
71 pub oe_width: u32,
72 pub wait_width: u32,
73}
74
75pub struct TegraGmi {
76 regs: MmioRegion,
77 power_state: PowerState,
78 snor_config: u32,
79 snor_timing0: u32,
80 snor_timing1: u32,
81}
82
83impl TegraGmi {
84 pub fn new() -> Self {
86 Self {
87 regs: MmioRegion::new(),
88 power_state: PowerState::Off,
89 snor_config: 0,
90 snor_timing0: 0,
91 snor_timing1: 0,
92 }
93 }
94
95 pub fn configure(&mut self, cfg: &GmiConfig, timing: &GmiTiming) {
97 let mut config = 0u32;
98 if cfg.bus_width_32 {
99 config |= BUS_WIDTH_32BIT;
100 }
101 if cfg.mux_mode {
102 config |= MUX_MODE;
103 }
104 if cfg.rdy_before_data {
105 config |= RDY_BEFORE_DATA;
106 }
107 if cfg.rdy_active_high {
108 config |= RDY_ACTIVE_HIGH;
109 }
110 if cfg.adv_active_high {
111 config |= ADV_ACTIVE_HIGH;
112 }
113 if cfg.oe_active_high {
114 config |= OE_ACTIVE_HIGH;
115 }
116 if cfg.cs_active_high {
117 config |= CS_ACTIVE_HIGH;
118 }
119 if cfg.chip_select < MAX_CHIP_SELECT {
120 config |= cs_select(cfg.chip_select);
121 }
122 self.snor_config = config;
123
124 self.snor_timing0 = muxed_width(timing.muxed_width)
125 | hold_width(timing.hold_width)
126 | adv_width(timing.adv_width)
127 | ce_width(timing.ce_width);
128
129 self.snor_timing1 =
130 we_width(timing.we_width) | oe_width(timing.oe_width) | wait_width(timing.wait_width);
131 }
132
133 pub fn apply_config(&self) {
135 if !self.regs.is_valid() {
136 return;
137 }
138 self.regs.write32(TEGRA_GMI_TIMING0, self.snor_timing0);
139 self.regs.write32(TEGRA_GMI_TIMING1, self.snor_timing1);
140 self.regs
141 .write32(TEGRA_GMI_CONFIG, self.snor_config | CONFIG_GO);
142 }
143}
144
145impl BusDriver for TegraGmi {
146 fn name(&self) -> &str {
148 "tegra-gmi"
149 }
150
151 fn compatible(&self) -> &[&str] {
153 COMPATIBLE
154 }
155
156 fn init(&mut self, base: usize) -> Result<(), BusError> {
158 self.regs.init(base, 0x20);
159 self.apply_config();
160 self.power_state = PowerState::On;
161 Ok(())
162 }
163
164 fn shutdown(&mut self) -> Result<(), BusError> {
166 self.power_state = PowerState::Off;
167 Ok(())
168 }
169
170 fn suspend(&mut self) -> Result<(), BusError> {
172 self.power_state = PowerState::Suspended;
173 Ok(())
174 }
175
176 fn resume(&mut self) -> Result<(), BusError> {
178 self.apply_config();
179 self.power_state = PowerState::On;
180 Ok(())
181 }
182
183 fn read_reg(&self, offset: usize) -> Result<u32, BusError> {
185 if !self.regs.is_valid() {
186 return Err(BusError::InitFailed);
187 }
188 Ok(self.regs.read32(offset))
189 }
190
191 fn write_reg(&mut self, offset: usize, value: u32) -> Result<(), BusError> {
193 if !self.regs.is_valid() {
194 return Err(BusError::InitFailed);
195 }
196 self.regs.write32(offset, value);
197 Ok(())
198 }
199}