blob: 5fcc94a2ace603d32284d0b5f0eec8558013f0b8 [file] [log] [blame]
// 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