blob: 3356d889c4199a82592d383c2debba1ed7202073 [file] [log] [blame]
// Copyright 2018 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 <ddk/debug.h>
#include <ddk/mmio-buffer.h>
#include <hw/reg.h>
#include <zircon/syscalls.h>
#include <soc/aml-common/aml-usb-phy-v2-regs.h>
#include <soc/aml-s905d2/s905d2-hw.h>
// from mesong12a.dtsi
#define PLL_SETTING_0 0x09400414
#define PLL_SETTING_1 0x927E0000
#define PLL_SETTING_2 0xac5f49e5
#define PLL_SETTING_3 0xfe18
#define PLL_SETTING_4 0xfff
#define PLL_SETTING_5 0x78000
#define PLL_SETTING_6 0xe0004
#define PLL_SETTING_7 0xe000c
// Order PLL, tuning
// set_usb_pll() in phy_aml_new_usb2_v2.c
static zx_status_t set_usb_pll(zx_paddr_t reg_base) {
mmio_buffer_t buf;
zx_status_t status;
// Please do not use get_root_resource() in new code. See ZX-1467.
status = mmio_buffer_init_physical(&buf, reg_base, ZX_PAGE_SIZE, get_root_resource(),
ZX_CACHE_POLICY_UNCACHED_DEVICE);
if (status != ZX_OK) {
return status;
}
void* reg = buf.vaddr;
writel((0x30000000 | PLL_SETTING_0), reg + 0x40);
writel(PLL_SETTING_1, reg + 0x44);
writel(PLL_SETTING_2, reg + 0x48);
zx_nanosleep(zx_deadline_after(ZX_USEC(100)));
writel((0x10000000 | PLL_SETTING_0), reg + 0x40);
// PLL
zx_nanosleep(zx_deadline_after(ZX_USEC(100)));
writel((PLL_SETTING_3), reg + 0x50);
writel((PLL_SETTING_4), reg + 0x10);
// Recovery state
writel(0, reg + 0x38);
writel((PLL_SETTING_5), reg + 0x34);
// Disconnect threshold
writel(0x3c, reg + 0xc);
// Tuning
zx_nanosleep(zx_deadline_after(ZX_USEC(100)));
writel(PLL_SETTING_6, reg + 0x38);
writel(PLL_SETTING_5, reg + 0x34);
zx_nanosleep(zx_deadline_after(ZX_MSEC(100)));
mmio_buffer_release(&buf);
return ZX_OK;
}
zx_status_t aml_usb_phy_v2_init(zx_handle_t bti) {
zx_status_t status;
mmio_buffer_t reset_buf;
mmio_buffer_t usbctrl_buf;
status = mmio_buffer_init_physical(&reset_buf, S905D2_RESET_BASE, S905D2_RESET_LENGTH,
// Please do not use get_root_resource() in new code. See ZX-1467.
get_root_resource(), ZX_CACHE_POLICY_UNCACHED_DEVICE);
if (status != ZX_OK) {
zxlogf(ERROR, "aml_usb_init io_buffer_init_physical failed %d\n", status);
return status;
}
status = mmio_buffer_init_physical(&usbctrl_buf, S905D2_USBCTRL_BASE, S905D2_USBCTRL_LENGTH,
// Please do not use get_root_resource() in new code. See ZX-1467.
get_root_resource(), ZX_CACHE_POLICY_UNCACHED_DEVICE);
if (status != ZX_OK) {
zxlogf(ERROR, "aml_usb_init io_buffer_init_physical failed %d\n", status);
mmio_buffer_release(&reset_buf);
return status;
}
volatile void* reset_regs = reset_buf.vaddr;
volatile void* usbctrl_regs = usbctrl_buf.vaddr;
// first reset USB
uint32_t val = readl(reset_regs + 0x21 * 4);
writel((val | (0x3 << 16)), reset_regs + 0x21 * 4);
// amlogic_new_usbphy_reset_v2()
volatile uint32_t* reset_1 = (uint32_t *)(reset_regs + S905D2_RESET1_REGISTER);
set_bitsl(S905D2_RESET1_USB, reset_1);
// FIXME(voydanoff) this delay is very long, but it is what the Amlogic Linux kernel is doing.
zx_nanosleep(zx_deadline_after(ZX_MSEC(500)));
// amlogic_new_usb2_init()
for (int i = 0; i < 2; i++) {
volatile void* addr = usbctrl_regs + (i * PHY_REGISTER_SIZE) + U2P_R0_OFFSET;
uint32_t temp = readl(addr);
temp |= U2P_R0_POR;
temp |= U2P_R0_HOST_DEVICE;
if (i == 1) {
temp |= U2P_R0_IDPULLUP0;
temp |= U2P_R0_DRVVBUS0;
}
writel(temp, addr);
zx_nanosleep(zx_deadline_after(ZX_USEC(10)));
// amlogic_new_usbphy_reset_phycfg_v2()
set_bitsl((1 << (16 + 0 /*i is always zero here */)), reset_1);
zx_nanosleep(zx_deadline_after(ZX_USEC(50)));
addr = usbctrl_regs + (i * PHY_REGISTER_SIZE) + U2P_R1_OFFSET;
temp = readl(addr);
int cnt = 0;
while (!(temp & U2P_R1_PHY_RDY)) {
temp = readl(addr);
// wait phy ready max 1ms, common is 100us
if (cnt > 200) {
zxlogf(ERROR, "aml_usb_init U2P_R1_PHY_RDY wait failed\n");
break;
}
cnt++;
zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
}
}
// set up PLLs
if ((status = set_usb_pll(S905D2_USBPHY20_BASE)) != ZX_OK ||
(status = set_usb_pll(S905D2_USBPHY21_BASE)) != ZX_OK) {
zxlogf(ERROR, "aml_usb_init: set_usb_pll failed: %d\n", status);
}
mmio_buffer_release(&reset_buf);
mmio_buffer_release(&usbctrl_buf);
return ZX_OK;
}