| // Copyright 2024 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/devices/usb/drivers/aml-usb-phy/usb-phy3.h" |
| |
| #include <lib/driver/logging/cpp/logger.h> |
| |
| #include "src/devices/usb/drivers/aml-usb-phy/usb-phy-regs.h" |
| #include "src/devices/usb/drivers/aml-usb-phy/usb-phy3-regs.h" |
| |
| namespace aml_usb_phy { |
| |
| namespace { |
| |
| void dump_phy3_regs(const fdf::MmioBuffer& mmio) { |
| DUMP_REG(PHY3_R1, mmio) |
| DUMP_REG(PHY3_R2, mmio) |
| DUMP_REG(PHY3_R4, mmio) |
| DUMP_REG(PHY3_R5, mmio) |
| } |
| |
| } // namespace |
| |
| void UsbPhy3::dump_regs() const { |
| FDF_LOG(INFO, " UsbPhy3"); |
| dump_phy3_regs(mmio()); |
| } |
| |
| zx_status_t UsbPhy3::CrBusAddr(uint32_t addr) { |
| auto phy3_r4 = PHY3_R4::Get().FromValue(0).set_phy_cr_data_in(addr); |
| phy3_r4.WriteTo(&mmio()); |
| phy3_r4.set_phy_cr_cap_addr(0); |
| phy3_r4.WriteTo(&mmio()); |
| phy3_r4.set_phy_cr_cap_addr(1); |
| phy3_r4.WriteTo(&mmio()); |
| |
| auto timeout = zx::deadline_after(zx::msec(1000)); |
| auto phy3_r5 = PHY3_R5::Get().FromValue(0); |
| do { |
| phy3_r5 = PHY3_R5::Get().ReadFrom(&mmio()); |
| } while (phy3_r5.phy_cr_ack() == 0 && timeout > zx::clock::get_monotonic()); |
| |
| if (phy3_r5.phy_cr_ack() != 1) { |
| FDF_LOG(WARNING, "Read set cap addr for addr %x timed out", addr); |
| } |
| |
| phy3_r4.set_phy_cr_cap_addr(0); |
| phy3_r4.WriteTo(&mmio()); |
| timeout = zx::deadline_after(zx::msec(1000)); |
| do { |
| phy3_r5 = PHY3_R5::Get().ReadFrom(&mmio()); |
| } while (phy3_r5.phy_cr_ack() == 1 && timeout > zx::clock::get_monotonic()); |
| |
| if (phy3_r5.phy_cr_ack() != 0) { |
| FDF_LOG(WARNING, "Read cap addr for addr %x timed out", addr); |
| } |
| |
| return ZX_OK; |
| } |
| |
| uint32_t UsbPhy3::CrBusRead(uint32_t addr) { |
| CrBusAddr(addr); |
| |
| auto phy3_r4 = PHY3_R4::Get().FromValue(0); |
| phy3_r4.set_phy_cr_read(0); |
| phy3_r4.WriteTo(&mmio()); |
| phy3_r4.set_phy_cr_read(1); |
| phy3_r4.WriteTo(&mmio()); |
| |
| auto timeout = zx::deadline_after(zx::msec(1000)); |
| auto phy3_r5 = PHY3_R5::Get().FromValue(0); |
| do { |
| phy3_r5 = PHY3_R5::Get().ReadFrom(&mmio()); |
| } while (phy3_r5.phy_cr_ack() == 0 && timeout > zx::clock::get_monotonic()); |
| |
| if (phy3_r5.phy_cr_ack() != 1) { |
| FDF_LOG(WARNING, "Read set for addr %x timed out", addr); |
| } |
| |
| uint32_t data = phy3_r5.phy_cr_data_out(); |
| |
| phy3_r4.set_phy_cr_read(0); |
| phy3_r4.WriteTo(&mmio()); |
| timeout = zx::deadline_after(zx::msec(1000)); |
| do { |
| phy3_r5 = PHY3_R5::Get().ReadFrom(&mmio()); |
| } while (phy3_r5.phy_cr_ack() == 1 && timeout > zx::clock::get_monotonic()); |
| |
| if (phy3_r5.phy_cr_ack() != 0) { |
| FDF_LOG(WARNING, "Read for addr %x timed out", addr); |
| } |
| |
| return data; |
| } |
| |
| zx_status_t UsbPhy3::CrBusWrite(uint32_t addr, uint32_t data) { |
| CrBusAddr(addr); |
| |
| auto phy3_r4 = PHY3_R4::Get().FromValue(0); |
| phy3_r4.set_phy_cr_data_in(data); |
| phy3_r4.WriteTo(&mmio()); |
| |
| phy3_r4.set_phy_cr_cap_data(0); |
| phy3_r4.WriteTo(&mmio()); |
| phy3_r4.set_phy_cr_cap_data(1); |
| phy3_r4.WriteTo(&mmio()); |
| |
| auto timeout = zx::deadline_after(zx::msec(1000)); |
| auto phy3_r5 = PHY3_R5::Get().FromValue(0); |
| do { |
| phy3_r5 = PHY3_R5::Get().ReadFrom(&mmio()); |
| } while (phy3_r5.phy_cr_ack() == 0 && timeout > zx::clock::get_monotonic()); |
| |
| if (phy3_r5.phy_cr_ack() != 1) { |
| FDF_LOG(WARNING, "Write cap data for addr %x timed out", addr); |
| } |
| |
| phy3_r4.set_phy_cr_cap_data(0); |
| phy3_r4.WriteTo(&mmio()); |
| timeout = zx::deadline_after(zx::msec(1000)); |
| do { |
| phy3_r5 = PHY3_R5::Get().ReadFrom(&mmio()); |
| } while (phy3_r5.phy_cr_ack() == 1 && timeout > zx::clock::get_monotonic()); |
| |
| if (phy3_r5.phy_cr_ack() != 0) { |
| FDF_LOG(WARNING, "Write cap data reset for addr %x timed out", addr); |
| } |
| |
| phy3_r4.set_phy_cr_write(0); |
| phy3_r4.WriteTo(&mmio()); |
| phy3_r4.set_phy_cr_write(1); |
| phy3_r4.WriteTo(&mmio()); |
| timeout = zx::deadline_after(zx::msec(1000)); |
| do { |
| phy3_r5 = PHY3_R5::Get().ReadFrom(&mmio()); |
| } while (phy3_r5.phy_cr_ack() == 0 && timeout > zx::clock::get_monotonic()); |
| |
| if (phy3_r5.phy_cr_ack() != 1) { |
| FDF_LOG(WARNING, "Write for addr %x timed out", addr); |
| } |
| |
| phy3_r4.set_phy_cr_write(0); |
| phy3_r4.WriteTo(&mmio()); |
| timeout = zx::deadline_after(zx::msec(1000)); |
| do { |
| phy3_r5 = PHY3_R5::Get().ReadFrom(&mmio()); |
| } while (phy3_r5.phy_cr_ack() == 1 && timeout > zx::clock::get_monotonic()); |
| |
| if (phy3_r5.phy_cr_ack() != 0) { |
| FDF_LOG(WARNING, "Disable write for addr %x timed out", addr); |
| } |
| |
| return ZX_OK; |
| } |
| |
| zx_status_t UsbPhy3::Init(fdf::MmioBuffer& usbctrl_mmio) { |
| auto reg = mmio().Read32(0); |
| reg = reg | (3 << 5); |
| mmio().Write32(reg, 0); |
| |
| zx::nanosleep(zx::deadline_after(zx::usec(100))); |
| |
| USB_R3_V2::Get() |
| .ReadFrom(&usbctrl_mmio) |
| .set_p30_ssc_en(1) |
| .set_p30_ssc_range(2) |
| .set_p30_ref_ssp_en(1) |
| .WriteTo(&usbctrl_mmio); |
| |
| zx::nanosleep(zx::deadline_after(zx::usec(2))); |
| |
| USB_R2_V2::Get() |
| .ReadFrom(&usbctrl_mmio) |
| .set_p30_pcs_tx_deemph_3p5db(0x15) |
| .set_p30_pcs_tx_deemph_6db(0x20) |
| .WriteTo(&usbctrl_mmio); |
| |
| zx::nanosleep(zx::deadline_after(zx::usec(2))); |
| |
| USB_R1_V2::Get() |
| .ReadFrom(&usbctrl_mmio) |
| .set_u3h_host_port_power_control_present(1) |
| .set_u3h_fladj_30mhz_reg(0x20) |
| .set_p30_pcs_tx_swing_full(127) |
| .WriteTo(&usbctrl_mmio); |
| |
| zx::nanosleep(zx::deadline_after(zx::usec(2))); |
| |
| auto phy3_r2 = PHY3_R2::Get().ReadFrom(&mmio()); |
| phy3_r2.set_phy_tx_vboost_lvl(0x4); |
| phy3_r2.WriteTo(&mmio()); |
| zx::nanosleep(zx::deadline_after(zx::usec(2))); |
| |
| uint32_t data = CrBusRead(0x102d); |
| data |= (1 << 7); |
| CrBusWrite(0x102D, data); |
| |
| data = CrBusRead(0x1010); |
| data &= ~0xff0; |
| data |= 0x20; |
| CrBusWrite(0x1010, data); |
| |
| data = CrBusRead(0x1006); |
| data &= ~(1 << 6); |
| data |= (1 << 7); |
| data &= ~(0x7 << 8); |
| data |= (0x3 << 8); |
| data |= (0x1 << 11); |
| CrBusWrite(0x1006, data); |
| |
| data = CrBusRead(0x1002); |
| data &= ~0x3f80; |
| data |= (0x16 << 7); |
| data &= ~0x7f; |
| data |= (0x7f | (1 << 14)); |
| CrBusWrite(0x1002, data); |
| |
| data = CrBusRead(0x30); |
| data &= ~(0xf << 4); |
| data |= (0x8 << 4); |
| CrBusWrite(0x30, data); |
| zx::nanosleep(zx::deadline_after(zx::usec(2))); |
| |
| auto phy3_r1 = PHY3_R1::Get().ReadFrom(&mmio()); |
| phy3_r1.set_phy_los_bias(0x4); |
| phy3_r1.set_phy_los_level(0x9); |
| phy3_r1.WriteTo(&mmio()); |
| |
| return ZX_OK; |
| } |
| |
| } // namespace aml_usb_phy |