1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <ddk/debug.h>
6#include <ddk/protocol/platform-defs.h>
7#include <hw/reg.h>
8#include <soc/aml-common/aml-usb-phy-v2.h>
9#include <soc/aml-s905d2/s905d2-hw.h>
10
11#include "astro.h"
12
13static const pbus_mmio_t xhci_mmios[] = {
14    {
15        .base = S905D2_USB0_BASE,
16        .length = S905D2_USB0_LENGTH,
17    },
18};
19
20static const pbus_irq_t xhci_irqs[] = {
21    {
22        .irq = S905D2_USB0_IRQ,
23        .mode = ZX_INTERRUPT_MODE_EDGE_HIGH,
24    },
25};
26
27static const pbus_bti_t xhci_btis[] = {
28    {
29        .iommu_index = 0,
30        .bti_id = BTI_USB_XHCI,
31    },
32};
33
34static const pbus_dev_t xhci_dev = {
35    .name = "xhci",
36    .vid = PDEV_VID_GENERIC,
37    .pid = PDEV_PID_GENERIC,
38    .did = PDEV_DID_USB_XHCI,
39    .mmios = xhci_mmios,
40    .mmio_count = countof(xhci_mmios),
41    .irqs = xhci_irqs,
42    .irq_count = countof(xhci_irqs),
43    .btis = xhci_btis,
44    .bti_count = countof(xhci_btis),
45};
46
47// magic numbers for USB PHY tuning
48#define PLL_SETTING_3   0xfe18
49#define PLL_SETTING_4   0xfff
50#define PLL_SETTING_5   0x78000
51#define PLL_SETTING_6   0xe0004
52#define PLL_SETTING_7   0xe000c
53
54static zx_status_t astro_usb_tuning(zx_handle_t bti, bool host, bool default_val) {
55    io_buffer_t buf;
56    zx_status_t status;
57
58    status = io_buffer_init_physical(&buf, bti, S905D2_USBPHY21_BASE, S905D2_USBPHY21_LENGTH,
59                                     get_root_resource(), ZX_CACHE_POLICY_UNCACHED_DEVICE);
60    if (status != ZX_OK) {
61        return status;
62    }
63
64    volatile void* base = io_buffer_virt(&buf);
65
66    if (default_val) {
67        writel(0, base + 0x38);
68        writel(PLL_SETTING_5, base + 0x34);
69    } else {
70        writel(PLL_SETTING_3, base + 0x50);
71        writel(PLL_SETTING_4, base + 0x10);
72        if (host) {
73            writel(PLL_SETTING_6, base + 0x38);
74        } else {
75            writel(PLL_SETTING_7, base + 0x38);
76        }
77        writel(PLL_SETTING_5, base + 0x34);
78    }
79
80    io_buffer_release(&buf);
81    return ZX_OK;
82}
83
84zx_status_t aml_usb_init(aml_bus_t* bus) {
85    zx_handle_t bti;
86
87    zx_status_t status = iommu_get_bti(&bus->iommu, 0, BTI_BOARD, &bti);
88    if (status != ZX_OK) {
89        zxlogf(ERROR, "aml_usb_init: iommu_get_bti failed: %d\n", status);
90        return status;
91    }
92
93    status = aml_usb_phy_v2_init(bti);
94    if (status != ZX_OK) {
95        return status;
96    }
97
98    status = astro_usb_tuning(bti, true, false);
99    zx_handle_close(bti);
100    if (status != ZX_OK) {
101        return status;
102    }
103
104    return pbus_device_add(&bus->pbus, &xhci_dev);
105}
106