crab_usb/backend/kmod/dwc/udphy/
mod.rs1use alloc::{boxed::Box, collections::BTreeMap, string::String, sync::Arc};
2use core::time::Duration;
3
4use super::{
5 NamedResetLine, ResetLine,
6 udphy::regmap::{RK3588_UDPHY_24M_REFCLK_CFG, RK3588_UDPHY_INIT_SEQUENCE, Regmap},
7};
8use crate::{
9 Mmio,
10 err::Result,
11 osal::{Kernel, SpinWhile},
12};
13
14pub mod config;
15mod consts;
16pub mod regmap;
17
18use consts::*;
19use tock_registers::{interfaces::*, registers::*};
20
21const RK3588_GRF_VO0_CON0: u32 = 0x0000;
23const RK3588_GRF_VO0_CON2: u32 = 0x0008;
24
25const DP_AUX_DIN_SEL: u32 = 1 << 9;
27const DP_AUX_DOUT_SEL: u32 = 1 << 8;
28const DP_LANE_SEL_ALL: u32 = 0xFF;
29
30bitflags::bitflags! {
31 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
32 pub struct UdphyMode: u8 {
33 const NONE = 0;
34 const USB = 1;
35 const DP = 1 << 1;
36 const DP_USB = Self::DP.bits() | Self::USB.bits();
37 }
38}
39
40pub const UDPHY_PMA: usize = 0x8000;
42
43pub struct UdphyParam<'a> {
44 pub id: usize,
45 pub u2phy_grf: Mmio,
47 pub usb_grf: Mmio,
49 pub usbdpphy_grf: Mmio,
51 pub vo_grf: Mmio,
53 pub dp_lane_mux: &'a [u32],
55 pub rst_list: &'a [NamedResetLine],
56}
57
58pub struct Udphy {
59 id: usize,
60 cfg: Box<config::UdphyCfg>,
61 mode: UdphyMode,
62 phy_base: usize,
64
65 pma_remap: Regmap,
66 udphygrf: Regmap,
68 usb_grf: Regmap,
70 vo_grf: Regmap,
72 lane_mux_sel: [u32; 4],
75 dp_lane_sel: [u32; 4],
76 flip: bool,
78 rsts: BTreeMap<String, Arc<dyn ResetLine>>,
79}
80
81impl Udphy {
82 pub fn new(base: Mmio, param: UdphyParam<'_>) -> Self {
83 let cfg = Box::new(config::RK3588_UDPHY_CFGS.clone());
84 let mut lane_mux_sel = [0u32; 4];
85 let mut dp_lane_sel = [0u32; 4];
86
87 let mut mode;
89 let mut flip = false;
90
91 if param.dp_lane_mux.is_empty() {
92 mode = UdphyMode::USB;
94 info!("Udphy: No dp-lane-mux property, using USB-only mode");
95 } else {
96 let num_lanes = param.dp_lane_mux.len();
98
99 if num_lanes != 2 && num_lanes != 4 {
100 panic!("Invalid number of lane mux: {}", num_lanes);
101 }
102
103 for (i, &lane) in param.dp_lane_mux.iter().enumerate() {
105 if lane > 3 {
106 panic!("Lane mux must be between 0 and 3, got {}", lane);
107 }
108 lane_mux_sel[lane as usize] = PHY_LANE_MUX_DP;
109 dp_lane_sel[i] = lane;
110 }
111
112 mode = UdphyMode::DP; if num_lanes == 2 {
114 mode |= UdphyMode::USB;
116 flip = lane_mux_sel[0] == PHY_LANE_MUX_DP;
117 info!("Udphy: Configured for USB+DP mode with 2 DP lanes");
118 } else {
119 info!("Udphy: Configured for DP-only mode with 4 DP lanes");
121 }
122
123 debug!("dp_lane_sel: {:?}", dp_lane_sel);
125 debug!("lane_mux_sel: {:?}", lane_mux_sel);
126 }
127
128 let mut rsts = BTreeMap::new();
129 for reset in param.rst_list.iter() {
130 if cfg.rst_list.contains(&reset.name()) {
131 rsts.insert(String::from(reset.name()), reset.line());
132 } else {
133 panic!("unsupported reset name: {}", reset.name());
134 }
135 }
136
137 Udphy {
138 id: param.id,
139 cfg,
140 mode,
141 phy_base: base.as_ptr() as usize,
142 pma_remap: Regmap::new(unsafe { base.add(UDPHY_PMA) }),
143 udphygrf: Regmap::new(param.usbdpphy_grf),
144 usb_grf: Regmap::new(param.usb_grf),
145 vo_grf: Regmap::new(param.vo_grf),
146 lane_mux_sel,
147 dp_lane_sel,
148 rsts,
149 flip,
150 }
151 }
152
153 pub async fn setup(&mut self, kernel: &Kernel) -> Result<()> {
154 info!("Starting initialization");
155 for &rst in self.cfg.rst_list {
156 self.reset_assert(rst);
157 }
158
159 if self.mode.contains(UdphyMode::USB) {
161 debug!("Enabling RX LFPS for USB mode");
162 self.udphygrf.grfreg_write(&self.cfg.grf.rx_lfps, true);
163 }
164
165 self.udphygrf.grfreg_write(&self.cfg.grf.low_pwrn, true);
167
168 self.reset_deassert("pma_apb");
169 self.reset_deassert("pcs_apb");
170 debug!("PMA powered on and APB resets deasserted");
171
172 self.pma_remap.multi_reg_write(RK3588_UDPHY_INIT_SEQUENCE);
174
175 debug!("Initial register sequences applied");
176
177 self.pma_remap.multi_reg_write(RK3588_UDPHY_24M_REFCLK_CFG);
178
179 debug!("24M reference clock configured");
180
181 self.cmn_lane_mux_and_en().write(
183 CMN_LANE_MUX_EN::LANE0_MUX.val(self.lane_mux_sel[0])
184 + CMN_LANE_MUX_EN::LANE1_MUX.val(self.lane_mux_sel[1])
185 + CMN_LANE_MUX_EN::LANE2_MUX.val(self.lane_mux_sel[2])
186 + CMN_LANE_MUX_EN::LANE3_MUX.val(self.lane_mux_sel[3])
187 + CMN_LANE_MUX_EN::LANE0_EN::Disable
188 + CMN_LANE_MUX_EN::LANE1_EN::Disable
189 + CMN_LANE_MUX_EN::LANE2_EN::Disable
190 + CMN_LANE_MUX_EN::LANE3_EN::Disable,
191 );
192 if self.mode.contains(UdphyMode::USB) {
194 self.reset_deassert("init");
195 }
196
197 if self.mode.contains(UdphyMode::DP) {
198 self.cmn_dp_rstn().modify(CMN_DP_RSTN::DP_INIT_RSTN::Enable);
199 }
200
201 kernel.delay(Duration::from_micros(1));
202
203 if self.mode.contains(UdphyMode::USB) {
204 self.reset_deassert("cmn");
206 self.reset_deassert("lane");
207 }
208 self.status_check().await;
210 info!("Udphy initialized");
211
212 self.u3_port_disable(!self.mode.contains(UdphyMode::USB));
213
214 let dplanes = self.dplane_get();
215 debug!(
216 "Configured for {:?} mode with {} DP lanes",
217 self.mode, dplanes
218 );
219 self.dplane_enable(dplanes);
220 self.dplane_select();
221
222 self.dump_registers();
224
225 Ok(())
226 }
227
228 fn dplane_select(&self) {
232 let mut value = 0u32;
233
234 match self.mode {
235 UdphyMode::DP => {
236 value |= 0u32 << (self.dp_lane_sel[0] * 2);
238 value |= 1u32 << (self.dp_lane_sel[1] * 2);
239 value |= 2u32 << (self.dp_lane_sel[2] * 2);
240 value |= 3u32 << (self.dp_lane_sel[3] * 2);
241 }
242 UdphyMode::DP_USB => {
243 value |= 0u32 << (self.dp_lane_sel[0] * 2);
245 value |= 1u32 << (self.dp_lane_sel[1] * 2);
246 }
247 UdphyMode::USB => {
248 debug!("Udphy: USB-only mode, skipping DP lane selection");
250 return;
251 }
252 _ => {
253 debug!("Udphy: Unknown mode, skipping DP lane selection");
254 return;
255 }
256 }
257
258 let reg_offset = if self.id > 0 {
260 RK3588_GRF_VO0_CON2
261 } else {
262 RK3588_GRF_VO0_CON0
263 };
264
265 let mask = (DP_AUX_DIN_SEL | DP_AUX_DOUT_SEL | DP_LANE_SEL_ALL) << 16;
269 let dp_aux_val = 0; let final_value = mask | dp_aux_val | value;
272
273 debug!(
274 "Udphy: Writing VO GRF register 0x{:03x} with value 0x{:08x} (lane value: 0x{:02x})",
275 reg_offset, final_value, value
276 );
277
278 self.vo_grf.reg_write(reg_offset, final_value);
279 }
280
281 fn dplane_enable(&self, lanes: usize) {
282 if lanes == 0 {
284 self.cmn_lane_mux_and_en().modify(
285 CMN_LANE_MUX_EN::LANE0_EN::Disable
286 + CMN_LANE_MUX_EN::LANE1_EN::Disable
287 + CMN_LANE_MUX_EN::LANE2_EN::Disable
288 + CMN_LANE_MUX_EN::LANE3_EN::Disable,
289 );
290 self.cmn_dp_rstn().modify(CMN_DP_RSTN::DP_CMN_RSTN::Reset);
291 return;
292 }
293
294 let mut fv = CMN_LANE_MUX_EN::LANE0_EN::Disable
296 + CMN_LANE_MUX_EN::LANE1_EN::Disable
297 + CMN_LANE_MUX_EN::LANE2_EN::Disable
298 + CMN_LANE_MUX_EN::LANE3_EN::Disable;
299
300 for (idx, sel) in self.lane_mux_sel.iter().enumerate() {
301 if *sel == PHY_LANE_MUX_DP {
302 fv += match idx {
303 0 => CMN_LANE_MUX_EN::LANE0_EN::Enable,
304 1 => CMN_LANE_MUX_EN::LANE1_EN::Enable,
305 2 => CMN_LANE_MUX_EN::LANE2_EN::Enable,
306 3 => CMN_LANE_MUX_EN::LANE3_EN::Enable,
307 _ => unreachable!(),
308 };
309 }
310 }
311 self.cmn_lane_mux_and_en().modify(fv);
317 }
318
319 fn dplane_get(&self) -> usize {
320 match self.mode {
321 UdphyMode::DP => 4,
322 UdphyMode::DP_USB => 2,
323 _ => 0,
324 }
325 }
326
327 async fn status_check(&self) {
328 if self.mode.contains(UdphyMode::USB) {
329 debug!("Waiting for PLL lock...");
330 SpinWhile::new(|| {
331 !self.cmn_ana_lcpll().is_set(CMN_ANA_LCPLL::AFC_DONE)
332 || !self.cmn_ana_lcpll().is_set(CMN_ANA_LCPLL::LOCK_DONE)
333 })
334 .await;
335
336 if self.flip {
337 SpinWhile::new(|| {
338 !self
339 .trsv_ln2_mon_rx_cdr()
340 .is_set(TRSV_LN2_MON_RX_CDR::LOCK_DONE)
341 })
342 .await;
343 } else {
344 SpinWhile::new(|| {
345 !self
346 .trsv_ln0_mon_rx_cdr()
347 .is_set(TRSV_LN0_MON_RX_CDR::LOCK_DONE)
348 })
349 .await;
350 }
351 }
352 }
353
354 pub fn u3_port_disable(&self, disable: bool) {
355 debug!("udphy{}: u3 port set disable: {disable}", self.id);
356
357 let cfg = if self.id > 0 {
358 &self.cfg.grf.usb3otg1_cfg
359 } else {
360 &self.cfg.grf.usb3otg0_cfg
361 };
362
363 self.usb_grf.grfreg_write(cfg, disable);
364 }
365
366 fn cmn_lane_mux_and_en(&self) -> &ReadWrite<u32, CMN_LANE_MUX_EN::Register> {
367 unsafe { &*((self.phy_base + UDPHY_PMA + pma_offset::CMN_LANE_MUX_AND_EN) as *const _) }
368 }
369
370 fn cmn_dp_rstn(&self) -> &ReadWrite<u32, CMN_DP_RSTN::Register> {
371 unsafe { &*((self.phy_base + UDPHY_PMA + pma_offset::CMN_DP_RSTN) as *const _) }
372 }
373
374 fn cmn_ana_lcpll(&self) -> &ReadWrite<u32, CMN_ANA_LCPLL::Register> {
375 unsafe { &*((self.phy_base + UDPHY_PMA + pma_offset::CMN_ANA_LCPLL_DONE) as *const _) }
376 }
377
378 fn trsv_ln0_mon_rx_cdr(&self) -> &ReadOnly<u32, TRSV_LN0_MON_RX_CDR::Register> {
379 unsafe { &*((self.phy_base + UDPHY_PMA + pma_offset::TRSV_LN0_MON_RX_CDR) as *const _) }
380 }
381
382 fn trsv_ln2_mon_rx_cdr(&self) -> &ReadOnly<u32, TRSV_LN2_MON_RX_CDR::Register> {
383 unsafe { &*((self.phy_base + UDPHY_PMA + pma_offset::TRSV_LN2_MON_RX_CDR) as *const _) }
384 }
385
386 fn reset_assert(&self, name: &str) {
387 if let Some(reset) = self.rsts.get(name) {
388 reset.assert();
389 } else {
390 panic!("unsupported reset name: {}", name);
391 }
392 }
393
394 fn reset_deassert(&self, name: &str) {
395 if let Some(reset) = self.rsts.get(name) {
396 reset.deassert();
397 } else {
398 panic!("unsupported reset name: {}", name);
399 }
400 }
401
402 fn dump_registers(&self) {
404 info!("=== USB3/DP PHY Register Dump ===");
405 info!("PHY ID: {}", self.id);
406 info!("PHY Mode: {:?}", self.mode);
407 info!("PHY Base: 0x{:08x}", self.phy_base);
408
409 let lane_mux = self.cmn_lane_mux_and_en().extract();
411 info!("CMN_LANE_MUX_AND_EN = 0x{:08x}", lane_mux.get());
412 info!(
413 " LANE0_MUX = {} ({})",
414 lane_mux.read(CMN_LANE_MUX_EN::LANE0_MUX),
415 self.lane_mux_name(lane_mux.read(CMN_LANE_MUX_EN::LANE0_MUX))
416 );
417 info!(
418 " LANE1_MUX = {} ({})",
419 lane_mux.read(CMN_LANE_MUX_EN::LANE1_MUX),
420 self.lane_mux_name(lane_mux.read(CMN_LANE_MUX_EN::LANE1_MUX))
421 );
422 info!(
423 " LANE2_MUX = {} ({})",
424 lane_mux.read(CMN_LANE_MUX_EN::LANE2_MUX),
425 self.lane_mux_name(lane_mux.read(CMN_LANE_MUX_EN::LANE2_MUX))
426 );
427 info!(
428 " LANE3_MUX = {} ({})",
429 lane_mux.read(CMN_LANE_MUX_EN::LANE3_MUX),
430 self.lane_mux_name(lane_mux.read(CMN_LANE_MUX_EN::LANE3_MUX))
431 );
432 info!(
433 " LANE0_EN = {}",
434 if lane_mux.read(CMN_LANE_MUX_EN::LANE0_EN) == 0 {
435 "Disabled"
436 } else {
437 "Enabled ✅"
438 }
439 );
440 info!(
441 " LANE1_EN = {}",
442 if lane_mux.read(CMN_LANE_MUX_EN::LANE1_EN) == 0 {
443 "Disabled"
444 } else {
445 "Enabled ✅"
446 }
447 );
448 info!(
449 " LANE2_EN = {}",
450 if lane_mux.read(CMN_LANE_MUX_EN::LANE2_EN) == 0 {
451 "Disabled"
452 } else {
453 "Enabled ✅"
454 }
455 );
456 info!(
457 " LANE3_EN = {}",
458 if lane_mux.read(CMN_LANE_MUX_EN::LANE3_EN) == 0 {
459 "Disabled"
460 } else {
461 "Enabled ✅"
462 }
463 );
464
465 let lcpll = self.cmn_ana_lcpll().extract();
467 info!("CMN_ANA_LCPLL_DONE = 0x{:08x}", lcpll.get());
468 info!(
469 " AFC_DONE = {}",
470 if lcpll.is_set(CMN_ANA_LCPLL::AFC_DONE) {
471 "Locked ✅"
472 } else {
473 "Not Locked ❌"
474 }
475 );
476 info!(
477 " LOCK_DONE = {}",
478 if lcpll.is_set(CMN_ANA_LCPLL::LOCK_DONE) {
479 "Locked ✅"
480 } else {
481 "Not Locked ❌"
482 }
483 );
484
485 if self.mode.contains(UdphyMode::USB) {
487 if self.flip {
488 let cdr = self.trsv_ln2_mon_rx_cdr().extract();
489 info!("TRSV_LN2_MON_RX_CDR = 0x{:08x}", cdr.get());
490 info!(
491 " LOCK_DONE (Lane 2) = {}",
492 if cdr.is_set(TRSV_LN2_MON_RX_CDR::LOCK_DONE) {
493 "Locked ✅"
494 } else {
495 "Not Locked ❌"
496 }
497 );
498 } else {
499 let cdr = self.trsv_ln0_mon_rx_cdr().extract();
500 info!("TRSV_LN0_MON_RX_CDR = 0x{:08x}", cdr.get());
501 info!(
502 " LOCK_DONE (Lane 0) = {}",
503 if cdr.is_set(TRSV_LN0_MON_RX_CDR::LOCK_DONE) {
504 "Locked ✅"
505 } else {
506 "Not Locked ❌"
507 }
508 );
509 }
510 }
511
512 let dp_rstn = self.cmn_dp_rstn().extract();
514 info!("CMN_DP_RSTN = 0x{:08x}", dp_rstn.get());
515 info!(
516 " DP_CMN_RSTN = {}",
517 if dp_rstn.read(CMN_DP_RSTN::DP_CMN_RSTN) == 1 {
518 "Released ✅"
519 } else {
520 "Asserted"
521 }
522 );
523 if self.mode.contains(UdphyMode::DP) {
524 info!(
525 " DP_INIT_RSTN = {}",
526 if dp_rstn.read(CMN_DP_RSTN::DP_INIT_RSTN) == 1 {
527 "Released ✅"
528 } else {
529 "Asserted"
530 }
531 );
532 }
533
534 info!(
535 " U3 Port Disable = {}",
536 !self.mode.contains(UdphyMode::USB)
537 );
538 info!("================================");
539 }
540
541 fn lane_mux_name(&self, val: u32) -> &'static str {
542 match val {
543 0 => "USB",
544 1 => "DP",
545 2 => "Reserved",
546 3 => "Reserved",
547 _ => "Unknown",
548 }
549 }
550}