blob: 4f3f00fa6f19e0880d744442d603b5ca86aaed98 [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/binding.h>
#include <ddk/debug.h>
#include <ddk/metadata.h>
#include <ddk/mmio-buffer.h>
#include <ddk/metadata.h>
#include <ddk/platform-defs.h>
#include <ddk/usb-peripheral-config.h>
#include <soc/aml-s905d2/s905d2-hw.h>
#include <usb/dwc2/metadata.h>
#include <zircon/device/usb-peripheral.h>
#include <zircon/hw/usb.h>
#include <zircon/hw/usb/cdc.h>
#include <stdlib.h>
#include <string.h>
#include "astro.h"
static const pbus_mmio_t dwc2_mmios[] = {
{
.base = S905D2_USB1_BASE,
.length = S905D2_USB1_LENGTH,
},
};
static const pbus_irq_t dwc2_irqs[] = {
{
.irq = S905D2_USB1_IRQ,
.mode = ZX_INTERRUPT_MODE_EDGE_HIGH,
},
};
static const pbus_bti_t dwc2_btis[] = {
{
.iommu_index = 0,
.bti_id = BTI_USB,
},
};
static const char kManufacturer[] = "Zircon";
static const char kProduct[] = "CDC-Ethernet";
static const char kSerial[] = "0123456789ABCDEF";
// Metadata for DWC2 driver.
static const dwc2_metadata_t dwc2_metadata = {
.dma_burst_len = DWC2_DMA_BURST_INCR8,
.usb_turnaround_time = 9,
.rx_fifo_size = 256, // for all OUT endpoints.
.nptx_fifo_size = 32, // for endpoint zero IN direction.
.tx_fifo_sizes = {
128, // for CDC ethernet bulk IN.
4, // for CDC ethernet interrupt IN.
128, // for test function bulk IN.
16, // for test function interrupt IN.
},
};
static pbus_metadata_t usb_metadata[] = {
{
.type = DEVICE_METADATA_USB_CONFIG,
.data_buffer = NULL,
.data_size = 0,
},
{
.type = DEVICE_METADATA_PRIVATE,
.data_buffer = &dwc2_metadata,
.data_size = sizeof(dwc2_metadata),
},
};
static const pbus_boot_metadata_t usb_boot_metadata[] = {
{
// Use Bluetooth MAC address for USB ethernet as well.
.zbi_type = DEVICE_METADATA_MAC_ADDRESS,
.zbi_extra = MACADDR_BLUETOOTH,
},
};
static const pbus_dev_t dwc2_dev = {
.name = "dwc2",
.vid = PDEV_VID_GENERIC,
.pid = PDEV_PID_GENERIC,
.did = PDEV_DID_USB_DWC2,
.mmio_list = dwc2_mmios,
.mmio_count = countof(dwc2_mmios),
.irq_list = dwc2_irqs,
.irq_count = countof(dwc2_irqs),
.bti_list = dwc2_btis,
.bti_count = countof(dwc2_btis),
.metadata_list = usb_metadata,
.metadata_count = countof(usb_metadata),
.boot_metadata_list = usb_boot_metadata,
.boot_metadata_count = countof(usb_boot_metadata),
};
static const pbus_mmio_t xhci_mmios[] = {
{
.base = S905D2_USB0_BASE,
.length = S905D2_USB0_LENGTH,
},
};
static const pbus_irq_t xhci_irqs[] = {
{
.irq = S905D2_USB0_IRQ,
.mode = ZX_INTERRUPT_MODE_EDGE_HIGH,
},
};
static const pbus_bti_t usb_btis[] = {
{
.iommu_index = 0,
.bti_id = BTI_USB,
},
};
static const pbus_dev_t xhci_dev = {
.name = "xhci",
.vid = PDEV_VID_GENERIC,
.pid = PDEV_PID_GENERIC,
.did = PDEV_DID_USB_XHCI_COMPOSITE,
.mmio_list = xhci_mmios,
.mmio_count = countof(xhci_mmios),
.irq_list = xhci_irqs,
.irq_count = countof(xhci_irqs),
.bti_list = usb_btis,
.bti_count = countof(usb_btis),
};
static const pbus_mmio_t usb_phy_mmios[] = {
{
.base = S905D2_RESET_BASE,
.length = S905D2_RESET_LENGTH,
},
{
.base = S905D2_USBCTRL_BASE,
.length = S905D2_USBCTRL_LENGTH,
},
{
.base = S905D2_USBPHY20_BASE,
.length = S905D2_USBPHY20_LENGTH,
},
{
.base = S905D2_USBPHY21_BASE,
.length = S905D2_USBPHY21_LENGTH,
},
};
static const pbus_irq_t usb_phy_irqs[] = {
{
.irq = S905D2_USB_IDDIG_IRQ,
.mode = ZX_INTERRUPT_MODE_EDGE_HIGH,
},
};
// values from mesong12b.dtsi usb2_phy_v2 pll-setting-#
static const uint32_t pll_settings[] = {
0x09400414,
0x927E0000,
0xac5f49e5,
0xfe18,
0xfff,
0x78000,
0xe0004,
0xe000c,
};
static const pbus_metadata_t usb_phy_metadata[] = {
{
.type = DEVICE_METADATA_PRIVATE,
.data_buffer = pll_settings,
.data_size = sizeof(pll_settings),
},
};
static const pbus_dev_t usb_phy_dev = {
.name = "aml-usb-phy-v2",
.vid = PDEV_VID_AMLOGIC,
.did = PDEV_DID_AML_USB_PHY_V2,
.mmio_list = usb_phy_mmios,
.mmio_count = countof(usb_phy_mmios),
.irq_list = usb_phy_irqs,
.irq_count = countof(usb_phy_irqs),
.bti_list = usb_btis,
.bti_count = countof(usb_btis),
.metadata_list = usb_phy_metadata,
.metadata_count = countof(usb_phy_metadata),
};
static const zx_bind_inst_t root_match[] = {
BI_MATCH(),
};
static const zx_bind_inst_t xhci_phy_match[] = {
BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_USB_PHY),
BI_ABORT_IF(NE, BIND_PLATFORM_DEV_VID, PDEV_VID_GENERIC),
BI_ABORT_IF(NE, BIND_PLATFORM_DEV_PID, PDEV_PID_GENERIC),
BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_DID, PDEV_DID_USB_XHCI_COMPOSITE),
};
static const device_component_part_t xhci_phy_component[] = {
{ countof(root_match), root_match },
{ countof(xhci_phy_match), xhci_phy_match },
};
static const device_component_t xhci_components[] = {
{ countof(xhci_phy_component), xhci_phy_component },
};
static const zx_bind_inst_t dwc2_phy_match[] = {
BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_USB_PHY),
BI_ABORT_IF(NE, BIND_PLATFORM_DEV_VID, PDEV_VID_GENERIC),
BI_ABORT_IF(NE, BIND_PLATFORM_DEV_PID, PDEV_PID_GENERIC),
BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_DID, PDEV_DID_USB_DWC2),
};
static const device_component_part_t dwc2_phy_component[] = {
{ countof(root_match), root_match },
{ countof(dwc2_phy_match), dwc2_phy_match },
};
static const device_component_t dwc2_components[] = {
{ countof(dwc2_phy_component), dwc2_phy_component },
};
zx_status_t aml_usb_init(aml_bus_t* bus) {
zx_status_t status = pbus_device_add(&bus->pbus, &usb_phy_dev);
if (status != ZX_OK) {
zxlogf(ERROR, "%s: pbus_device_add failed %d\n", __func__, status);
return status;
}
// Add XHCI and DWC2 to the same devhost as the aml-usb-phy.
status = pbus_composite_device_add(&bus->pbus, &xhci_dev, xhci_components,
countof(xhci_components), 1);
if (status != ZX_OK) {
zxlogf(ERROR, "%s: pbus_composite_device_add failed %d\n", __func__, status);
return status;
}
const size_t config_size = sizeof(struct UsbConfig) +
2 * sizeof(fuchsia_hardware_usb_peripheral_FunctionDescriptor);
struct UsbConfig* config = (struct UsbConfig*)calloc(1, config_size);
if (!config) {
return ZX_ERR_NO_MEMORY;
}
config->vid = GOOGLE_USB_VID;
config->pid = GOOGLE_USB_CDC_AND_FUNCTION_TEST_PID;
strcpy(config->manufacturer, kManufacturer);
strcpy(config->serial, kSerial);
strcpy(config->product, kProduct);
config->functions[0].interface_class = USB_CLASS_COMM;
config->functions[0].interface_subclass = USB_CDC_SUBCLASS_ETHERNET;
config->functions[0].interface_protocol = 0;
config->functions[1].interface_class = USB_CLASS_VENDOR;
config->functions[1].interface_subclass = 0;
config->functions[1].interface_protocol = 0;
usb_metadata[0].data_size = config_size;
usb_metadata[0].data_buffer = config;
status = pbus_composite_device_add(&bus->pbus, &dwc2_dev, dwc2_components,
countof(dwc2_components), 1);
free(config);
if (status != ZX_OK) {
zxlogf(ERROR, "%s: pbus_composite_device_add failed %d\n", __func__, status);
return status;
}
return ZX_OK;
}