blob: a6a7f795b1afe40fb4e1ae03c419b0a29fc9f06e [file]
// 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 <fidl/fuchsia.hardware.platform.bus/cpp/driver/fidl.h>
#include <fidl/fuchsia.hardware.platform.bus/cpp/fidl.h>
#include <lib/ddk/binding.h>
#include <lib/ddk/debug.h>
#include <lib/ddk/metadata.h>
#include <lib/ddk/platform-defs.h>
#include <lib/mmio/mmio.h>
#include <lib/zircon-internal/align.h>
#include <stdlib.h>
#include <string.h>
#include <ddk/usb-peripheral-config.h>
#include <soc/aml-s905d3/s905d3-hw.h>
#include <usb/cdc.h>
#include <usb/dwc2/metadata.h>
#include <usb/peripheral-config.h>
#include <usb/peripheral.h>
#include <usb/usb.h>
#include "nelson.h"
#include "src/devices/board/drivers/nelson/nelson_dwc2_bind.h"
#include "src/devices/board/drivers/nelson/nelson_xhci_bind.h"
#include "src/devices/bus/lib/platform-bus-composites/platform-bus-composite.h"
namespace nelson {
namespace fpbus = fuchsia_hardware_platform_bus;
static const std::vector<fpbus::Mmio> dwc2_mmios{
{{
.base = S905D3_USB1_BASE,
.length = S905D3_USB1_LENGTH,
}},
};
static const std::vector<fpbus::Irq> dwc2_irqs{
{{
.irq = S905D3_USB1_IRQ,
.mode = ZX_INTERRUPT_MODE_EDGE_HIGH,
}},
};
static const std::vector<fpbus::Bti> dwc2_btis{
{{
.iommu_index = 0,
.bti_id = BTI_USB,
}},
};
// 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.
},
};
using FunctionDescriptor = fuchsia_hardware_usb_peripheral::wire::FunctionDescriptor;
static const std::vector<fpbus::BootMetadata> usb_boot_metadata{
{{
// Use Bluetooth MAC address for USB ethernet as well.
.zbi_type = DEVICE_METADATA_MAC_ADDRESS,
.zbi_extra = MACADDR_BLUETOOTH,
}},
{{
// Advertise serial number over USB
.zbi_type = DEVICE_METADATA_SERIAL_NUMBER,
.zbi_extra = 0,
}},
};
static const std::vector<fpbus::Mmio> xhci_mmios{
{{
.base = S905D3_USB0_BASE,
.length = S905D3_USB0_LENGTH,
}},
};
static const std::vector<fpbus::Irq> xhci_irqs{
{{
.irq = S905D3_USB0_IRQ,
.mode = ZX_INTERRUPT_MODE_LEVEL_HIGH,
}},
};
static const std::vector<fpbus::Bti> usb_btis{
{{
.iommu_index = 0,
.bti_id = BTI_USB,
}},
};
static const fpbus::Node xhci_dev = []() {
fpbus::Node dev = {};
dev.name() = "xhci";
dev.vid() = PDEV_VID_GENERIC;
dev.pid() = PDEV_PID_GENERIC;
dev.did() = PDEV_DID_USB_XHCI_COMPOSITE;
dev.mmio() = xhci_mmios;
dev.irq() = xhci_irqs;
dev.bti() = usb_btis;
return dev;
}();
static const std::vector<fpbus::Mmio> usb_phy_mmios{
{{
.base = S905D3_RESET1_BASE,
.length = S905D3_RESET1_LENGTH,
}},
{{
.base = S905D3_USBCTRL_BASE,
.length = S905D3_USBCTRL_LENGTH,
}},
{{
.base = S905D3_USBPHY20_BASE,
.length = S905D3_USBPHY20_LENGTH,
}},
{{
.base = S905D3_USBPHY21_BASE,
.length = S905D3_USBPHY21_LENGTH,
}},
{{
.base = S905D3_POWER_BASE,
.length = S905D3_POWER_LENGTH,
}},
{{
.base = S905D3_SLEEP_BASE,
.length = S905D3_SLEEP_LENGTH,
}},
};
static const std::vector<fpbus::Irq> usb_phy_irqs{
{{
.irq = S905D3_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 std::vector<fpbus::Metadata> usb_phy_metadata{
{{
.type = DEVICE_METADATA_PRIVATE,
.data = std::vector<uint8_t>(
reinterpret_cast<const uint8_t*>(&pll_settings),
reinterpret_cast<const uint8_t*>(&pll_settings) + sizeof(pll_settings)),
}},
};
static const fpbus::Node usb_phy_dev = []() {
fpbus::Node dev = {};
dev.name() = "aml-usb-phy-v2";
dev.vid() = PDEV_VID_AMLOGIC;
dev.pid() = PDEV_PID_NELSON;
dev.did() = PDEV_DID_NELSON_USB_PHY;
dev.mmio() = usb_phy_mmios;
dev.irq() = usb_phy_irqs;
dev.bti() = usb_btis;
dev.metadata() = usb_phy_metadata;
return dev;
}();
zx_status_t Nelson::UsbInit() {
fidl::Arena<> fidl_arena;
fdf::Arena arena('USB_');
auto result = pbus_.buffer(arena)->NodeAdd(fidl::ToWire(fidl_arena, usb_phy_dev));
if (!result.ok()) {
zxlogf(ERROR, "%s: NodeAdd Usb(usb_phy_dev) request failed: %s", __func__,
result.FormatDescription().data());
return result.status();
}
if (result->is_error()) {
zxlogf(ERROR, "%s: NodeAdd Usb(usb_phy_dev) failed: %s", __func__,
zx_status_get_string(result->error_value()));
return result->error_value();
}
// Add XHCI and DWC2 to the same devhost as the aml-usb-phy.
{
auto result = pbus_.buffer(arena)->AddComposite(
fidl::ToWire(fidl_arena, xhci_dev),
platform_bus_composite::MakeFidlFragment(fidl_arena, xhci_fragments,
std::size(xhci_fragments)),
"xhci-phy");
if (!result.ok()) {
zxlogf(ERROR, "%s: AddComposite Usb(xhci_dev) request failed: %s", __func__,
result.FormatDescription().data());
return result.status();
}
if (result->is_error()) {
zxlogf(ERROR, "%s: AddComposite Usb(xhci_dev) failed: %s", __func__,
zx_status_get_string(result->error_value()));
return result->error_value();
}
}
std::unique_ptr<usb::UsbPeripheralConfig> peripheral_config;
auto status = usb::UsbPeripheralConfig::CreateFromBootArgs(parent_, &peripheral_config);
if (status != ZX_OK) {
zxlogf(ERROR, "Failed to get usb config from boot args - %d", status);
return status;
}
const std::vector<fpbus::Metadata> usb_metadata{
{{
.type = DEVICE_METADATA_USB_CONFIG,
.data = peripheral_config->config_data(),
}},
{{
.type = DEVICE_METADATA_PRIVATE,
.data = std::vector<uint8_t>(
reinterpret_cast<const uint8_t*>(&dwc2_metadata),
reinterpret_cast<const uint8_t*>(&dwc2_metadata) + sizeof(dwc2_metadata)),
}},
};
const fpbus::Node dwc2_dev = [&]() {
fpbus::Node dev = {};
dev.name() = "dwc2";
dev.vid() = PDEV_VID_GENERIC;
dev.pid() = PDEV_PID_GENERIC;
dev.did() = PDEV_DID_USB_DWC2;
dev.mmio() = dwc2_mmios;
dev.irq() = dwc2_irqs;
dev.bti() = dwc2_btis;
dev.metadata() = std::move(usb_metadata);
dev.boot_metadata() = usb_boot_metadata;
return dev;
}();
{
auto result = pbus_.buffer(arena)->AddComposite(
fidl::ToWire(fidl_arena, dwc2_dev),
platform_bus_composite::MakeFidlFragment(fidl_arena, dwc2_fragments,
std::size(dwc2_fragments)),
"dwc2-phy");
if (!result.ok()) {
zxlogf(ERROR, "%s: AddComposite Usb(dwc2_dev) request failed: %s", __func__,
result.FormatDescription().data());
return result.status();
}
if (result->is_error()) {
zxlogf(ERROR, "%s: AddComposite Usb(dwc2_dev) failed: %s", __func__,
zx_status_get_string(result->error_value()));
return result->error_value();
}
}
return ZX_OK;
}
} // namespace nelson