dde_linux: usb host controller driver version 4.16

This commit is contained in:
Stefan Kalkowski
2018-08-22 16:31:34 +02:00
committed by Christian Helmuth
parent 9d712b2ce9
commit b02f483841
36 changed files with 8195 additions and 32 deletions

View File

@ -0,0 +1,66 @@
USB host controller driver
##########################
Allows access to USB devices via the 'Usb' session interface.
Configuration snippet:
!<start name="usb_host_drv">
! <resource name="RAM" quantum="10M"/>
! <provides><service name="Usb"/></provides>
! <config>
! <report devices="yes"/>
! </config>
!</start>
The optional 'devices' report lists the connected devices and gets updated
when devices are added or removed.
Example report:
!<devices>
! <device label="usb-1-2" vendor_id="0x046d" product_id="0xc077" bus="0x0001" dev="0x0002" class="0x03"/>
! <device label="usb-1-1" vendor_id="0x1d6b" product_id="0x0002" bus="0x0001" dev="0x0001" class="0x09"/>
!</devices>
For every device a unique identifier is generated that is used to access the
USB device. Only devices that have a valid policy configured at the USB driver
can be accessed by a client. The following configuration allows 'comp1' to
access the device 'usb-1-6':
!<start name="usb_drv">
! <resource name="RAM" quantum="8M"/>
! <provides><service name="Usb"/></provides>
! <config uhci="yes" ohci="yes" ehci="yes" xhci="yes">
! <raw>
! <report devices="yes"/>
! <policy label="comp1 -> usb-1-6" vendor_id="0x13fe" product_id="0x5200" bus="0x0001" dev="0x0006"/>
! </raw>
! </config>
!</start>
In addition to the mandatory 'label' attribute the policy node also
contains optional attribute tuples of which at least one has to be present.
The 'vendor_id' and 'product_id' tuple selects a device regardless of its
location on the USB bus and is mostly used in static configurations. The
'bus' and 'dev' tuple selects a specific device via its bus locations and
device address. It is mostly used in dynamic configurations because the device
address is not fixed and may change every time the same device is plugged in.
If the class attribute is defined only, the usb host controller driver allows
access to all devives of that class. In that case the actual device is chosen
by the last label given when a session gets opened.
BIOS Handoff
~~~~~~~~~~~~
Per default the USB driver performs a hand off of the USB controller from the
BIOS, since it still may access the controller when booting, for example, from
a USB device. The BIOS hand off induces the execution of BIOS/SMM USB driver
code and potentially DMA operations. Unfortunately, some ACPI tables report
wrong RMRR information, which implicates IOMMU faults on illegal DMA
operations and consequently the hand off may fail after noticeably long
timeouts. Therefore, the hand off can be disabled in the USB driver
configuration like follows.
! <config bios_handoff="no"/>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,171 @@
/*
* \brief Startup USB driver library
* \author Sebastian Sumpf
* \date 2013-02-20
*/
/*
* Copyright (C) 2013-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Genode */
#include <base/component.h>
#include <base/attached_rom_dataspace.h>
#include <base/sleep.h>
/* Local */
#include <signal.h>
#include <lx_emul.h>
#include <lx_kit/env.h>
#include <lx_kit/pci.h>
#include <lx_kit/irq.h>
#include <lx_kit/malloc.h>
#include <lx_kit/scheduler.h>
#include <lx_kit/timer.h>
#include <lx_kit/work.h>
using namespace Genode;
extern "C" int subsys_usb_init();
extern "C" void module_raw_driver_init();
extern "C" void start_input_service(void *ep, void *services);
struct workqueue_struct *system_power_efficient_wq;
struct workqueue_struct *system_wq;
struct workqueue_struct *tasklet_wq;
void breakpoint() { Genode::log("BREAK"); }
extern "C" int stdout_write(const char *);
static void run_linux(void *s)
{
Services *services = (Services *)s;
system_power_efficient_wq = alloc_workqueue("system_power_efficient_wq", 0, 0);
system_wq = alloc_workqueue("system_wq", 0, 0);
tasklet_wq = alloc_workqueue("tasklet_wq", 0, 0);
/* low level interface */
module_raw_driver_init();
/* USB */
subsys_usb_init();
/* host controller */
platform_hcd_init(services);
while (true)
Lx::scheduler().current()->block_and_schedule();
}
static void start_usb_driver(Genode::Env &env)
{
/* initialize USB env */
Lx_kit::construct_env(env);
/* sets up backend alloc needed by malloc */
backend_alloc_init(env, env.ram(), Lx_kit::env().heap());
Lx::malloc_init(env, Lx_kit::env().heap());
static Services services(env);
Raw::init(env, services.raw_report_device_list);
Lx::scheduler(&env);
Lx::timer(&env, &env.ep(), &Lx_kit::env().heap(), &jiffies);
Lx::Irq::irq(&env.ep(), &Lx_kit::env().heap());
Lx::Work::work_queue(&Lx_kit::env().heap());
static Lx::Task linux(run_linux, &services, "linux", Lx::Task::PRIORITY_0,
Lx::scheduler());
Lx::scheduler().schedule();
}
namespace Usb_driver {
using namespace Genode;
struct Driver_starter { virtual void start_driver() = 0; };
struct Main;
}
struct Usb_driver::Main : Driver_starter
{
Env &_env;
/*
* Defer the startup of the USB driver until the first configuration
* becomes available. This is needed in scenarios where the configuration
* is dynamically generated and supplied to the USB driver via the
* report-ROM service.
*/
struct Initial_config_handler
{
Driver_starter &_driver_starter;
Attached_rom_dataspace _config;
Signal_handler<Initial_config_handler> _config_handler;
void _handle_config()
{
_config.update();
if (_config.xml().type() == "config")
_driver_starter.start_driver();
}
Initial_config_handler(Env &env, Driver_starter &driver_starter)
:
_driver_starter(driver_starter),
_config(env, "config"),
_config_handler(env.ep(), *this, &Initial_config_handler::_handle_config)
{
_config.sigh(_config_handler);
_handle_config();
}
};
void _handle_start()
{
if (_initial_config_handler.constructed()) {
_initial_config_handler.destruct();
start_usb_driver(_env);
}
}
Signal_handler<Main> _start_handler {
_env.ep(), *this, &Main::_handle_start };
Reconstructible<Initial_config_handler> _initial_config_handler { _env, *this };
/*
* Called from 'Initial_config_handler'
*/
void start_driver() override
{
Signal_transmitter(_start_handler).submit();
}
Main(Env &env) : _env(env) { }
};
void Component::construct(Genode::Env &env)
{
/* XXX execute constructors of global statics */
env.exec_static_constructors();
static Usb_driver::Main main(env);
}

View File

@ -0,0 +1,50 @@
/*
* \brief Platform specific definitions
* \author Sebastian Sumpf
* \date 2012-07-06
*
* These functions have to be implemented on all supported platforms.
*/
/*
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _PLATFORM_H_
#define _PLATFORM_H_
#include <base/log.h>
#include <util/xml_node.h>
#include <irq_session/capability.h>
#include <lx_kit/env.h>
struct Services
{
Genode::Env &env;
/* report generation */
bool raw_report_device_list = false;
Services(Genode::Env &env) : env(env)
{
using namespace Genode;
Genode::Xml_node config_node = Lx_kit::env().config_rom().xml();
try {
Genode::Xml_node node_report = config_node.sub_node("report");
raw_report_device_list = node_report.attribute_value("devices", false);
} catch (...) { }
}
};
void backend_alloc_init(Genode::Env &env, Genode::Ram_session &ram, Genode::Allocator &alloc);
void platform_hcd_init(Services *services);
Genode::Irq_session_capability platform_irq_activate(int irq);
#endif /* _PLATFORM_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,12 @@
#ifndef _RAW_H_
#define _RAW_H_
struct usb_device;
struct usb_driver;
extern struct usb_device_driver raw_driver;
extern struct usb_driver raw_intf_driver;
int raw_notify(struct notifier_block *nb, unsigned long action, void *data);
#endif /* _RAW_H_ */

View File

@ -0,0 +1,94 @@
/*
* \brief Low level USB access driver
* \author Sebastian Sumpf
* \date 2014-11-11
*/
/*
* Copyright (C) 2014-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <linux/usb.h>
#include "raw.h"
static int raw_probe(struct usb_device *udev)
{
printk("RAW: vendor: %x product: %x dev %p\n",
udev->descriptor.idVendor, udev->descriptor.idProduct, udev);
return -ENODEV;
}
static void raw_disconnect(struct usb_device *udev)
{
printk("driver disconnect called\n");
}
struct usb_device_driver raw_driver =
{
.name = "raw",
.probe = raw_probe,
.disconnect = raw_disconnect,
.supports_autosuspend = 0,
};
static int raw_intf_probe(struct usb_interface *intf,
struct usb_device_id const *id)
{
struct usb_device *udev = interface_to_usbdev(intf);
printk("RAW_INTF: vendor: %04x product: %04x\n", udev->descriptor.idVendor,
udev->descriptor.idProduct);
return -ENODEV;
}
void raw_intf_disconnect(struct usb_interface *intf) { }
static const struct usb_device_id raw_intf_id_table[] = {
{ .driver_info = 1 }
};
struct usb_driver raw_intf_driver =
{
.name = "rawintf",
.probe = raw_intf_probe,
.disconnect = raw_intf_disconnect,
.supports_autosuspend = 0,
};
struct notifier_block usb_nb =
{
.notifier_call = raw_notify
};
static int raw_driver_init(void)
{
int err;
if ((err = usb_register_device_driver(&raw_driver, THIS_MODULE)))
return err;
printk("RAW: driver registered\n");
if ((err = usb_register(&raw_intf_driver)))
return err;
printk("RAW: interface driver registered\n");
usb_register_notify(&usb_nb);
printk("RAW: notify function registered\n");
return 0;
}
module_init(raw_driver_init);

View File

@ -0,0 +1,52 @@
/*
* \brief Main-signal receiver and signal-helper functions
* \author Sebastian Sumpf <sebastian.sumpf@genode-labs.com>
* \date 2012-05-23
*/
/*
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _SIGNAL_H_
#define _SIGNAL_H_
#include <platform.h>
#include <base/signal.h>
static bool const verbose = false;
/**
* Helper that holds sender and entrypoint
*/
class Signal_helper
{
private:
Genode::Env &_env;
Genode::Signal_transmitter _sender;
public:
Signal_helper(Genode::Env &env) : _env(env) { }
Genode::Entrypoint &ep() { return _env.ep(); }
Genode::Signal_transmitter &sender() { return _sender; }
Genode::Parent &parent() { return _env.parent(); }
Genode::Env &env() { return _env; }
Genode::Ram_session &ram() { return _env.ram(); }
Genode::Region_map &rm() { return _env.rm(); }
};
namespace Raw
{
void init(Genode::Env &env, bool report_device_list);
}
#endif /* _SIGNAL_H_ */

View File

@ -0,0 +1,87 @@
/*
* \brief ARM specific implemenations used on all SOCs
* \author Sebastian Sumpf
* \date 2016-04-25
*/
/*
* Copyright (C) 2016-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <base/attached_io_mem_dataspace.h>
#include <base/env.h>
#include <lx_emul.h>
#include <lx_kit/backend_alloc.h>
#include <lx_kit/env.h>
#include <lx_kit/irq.h>
/****************************
** lx_kit/backend_alloc.h **
****************************/
void backend_alloc_init(Genode::Env&, Genode::Ram_session&,
Genode::Allocator&)
{
/* intentionally left blank */
}
Genode::Ram_dataspace_capability
Lx::backend_alloc(Genode::addr_t size, Genode::Cache_attribute cached) {
return Lx_kit::env().env().ram().alloc(size, cached); }
void Lx::backend_free(Genode::Ram_dataspace_capability cap) {
return Lx_kit::env().env().ram().free(cap); }
/***********************
** linux/interrupt.h **
***********************/
extern "C" int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
const char *name, void *dev)
{
Lx::Irq::irq().request_irq(Platform::Device::create(Lx_kit::env().env(), irq), handler, dev);
return 0;
}
int devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id)
{
Lx::Irq::irq().request_irq(Platform::Device::create(Lx_kit::env().env(), irq), handler, dev_id);
return 0;
}
/**********************
** asm-generic/io.h **
**********************/
void *_ioremap(phys_addr_t phys_addr, unsigned long size, int wc)
{
try {
Genode::Attached_io_mem_dataspace *ds =
new(Lx::Malloc::mem())
Genode::Attached_io_mem_dataspace(Lx_kit::env().env(), phys_addr, size, !!wc);
return ds->local_addr<void>();
} catch (...) {
panic("Failed to request I/O memory: [%lx,%lx)", phys_addr, phys_addr + size);
return 0;
}
}
void *ioremap(phys_addr_t offset, unsigned long size)
{
return _ioremap(offset, size, 0);
}

View File

@ -0,0 +1,81 @@
/*
* \brief Platform_device implementation for ARM
* \author Sebastian Sumpf
* \date 2016-04-25
*
* Note: Throw away when there exists a plaform device implementation for ARM
* in generic code
*/
/*
* Copyright (C) 2016-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _ARM__PLATFORM_DEVICE__PLATFORM_DEVICE_H_
#define _ARM__PLATFORM_DEVICE__PLATFORM_DEVICE_H_
#include <lx_emul/extern_c_begin.h>
#include <lx_emul/printf.h>
#include <lx_emul/extern_c_end.h>
#include <lx_kit/malloc.h>
#include <platform_device/device.h>
#include <irq_session/connection.h>
#include <util/list.h>
#include <util/reconstructible.h>
namespace Platform { struct Device; }
struct Platform::Device : Platform::Abstract_device, Genode::List<Device>::Element
{
Genode::Env &env;
unsigned irq_num;
Genode::Constructible<Genode::Irq_connection> irq_connection;
Device(Genode::Env &env, unsigned irq) : env(env), irq_num(irq) { }
unsigned vendor_id() { return ~0U; }
unsigned device_id() { return ~0U; }
Genode::Irq_session_capability irq(Genode::uint8_t) override
{
irq_connection.construct(env, irq_num);
return irq_connection->cap();
}
Genode::Io_mem_session_capability io_mem(Genode::uint8_t,
Genode::Cache_attribute,
Genode::addr_t, Genode::size_t) override
{
lx_printf("%s: not implemented\n", __PRETTY_FUNCTION__);
return Genode::Io_mem_session_capability();
}
static Genode::List<Device> &list()
{
static Genode::List<Device> l;
return l;
}
static Device &create(Genode::Env &env, unsigned irq_num)
{
Device *d;
for (d = list().first(); d; d = d->next())
if (d->irq_num == irq_num)
return *d;
d = new (Lx::Malloc::mem()) Device(env, irq_num);
list().insert(d);
return *d;
}
};
#endif /* _ARM__PLATFORM_DEVICE__PLATFORM_DEVICE_H_ */

View File

@ -0,0 +1,340 @@
/*
* \brief EHCI for Arndale initialization code
* \author Sebastian Sumpf
* \date 2013-02-20
*/
/*
* Copyright (C) 2013-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Genode */
#include <drivers/defs/arndale.h>
#include <base/attached_io_mem_dataspace.h>
#include <io_mem_session/connection.h>
#include <regulator/consts.h>
#include <regulator_session/connection.h>
#include <timer_session/connection.h>
#include <util/mmio.h>
/* Emulation */
#include <lx_emul.h>
#include <platform.h>
using namespace Genode;
enum {
EHCI_BASE = 0x12110000,
DWC3_BASE = 0x12000000,
DWC3_PHY_BASE = 0x12100000,
GPIO_BASE = 0x11400000,
EHCI_IRQ = Arndale::USB_HOST20_IRQ,
DWC3_IRQ = Arndale::USB_DRD30_IRQ,
};
static resource _ehci[] =
{
{ EHCI_BASE, EHCI_BASE + 0xfff, "ehci", IORESOURCE_MEM },
{ EHCI_IRQ, EHCI_IRQ, "ehci-irq", IORESOURCE_IRQ },
};
static resource _dwc3[] =
{
{ DWC3_BASE, DWC3_BASE + 0xcfff, "dwc3", IORESOURCE_MEM },
{ DWC3_IRQ, DWC3_IRQ, "dwc3-irq", IORESOURCE_IRQ },
};
/**
* EHCI controller
*/
struct Ehci : Genode::Mmio
{
Ehci(addr_t const mmio_base) : Mmio(mmio_base)
{
write<Cmd>(0);
/* reset */
write<Cmd::Reset>(1);
while(read<Cmd::Reset>())
msleep(1);
}
struct Cmd : Register<0x10, 32>
{
struct Reset : Bitfield<1, 1> { };
};
};
/**
* Gpio handling
*/
struct Gpio_bank {
unsigned con;
unsigned dat;
};
static inline
unsigned con_mask(unsigned val) { return 0xf << ((val) << 2); }
static inline
unsigned con_sfr(unsigned x, unsigned v) { return (v) << ((x) << 2); }
static void gpio_cfg_pin(Gpio_bank *bank, int gpio, int cfg)
{
unsigned int value;
value = readl(&bank->con);
value &= ~con_mask(gpio);
value |= con_sfr(gpio, cfg);
writel(value, &bank->con);
}
static void gpio_direction_output(Gpio_bank *bank, int gpio, int en)
{
unsigned int value;
enum { GPIO_OUTPUT = 0x1 };
gpio_cfg_pin(bank, gpio, GPIO_OUTPUT);
value = readl(&bank->dat);
value &= ~(0x1 << gpio);
if (en)
value |= 0x1 << gpio;
writel(value, &bank->dat);
}
static void arndale_ehci_init(Genode::Env &env)
{
enum Gpio_offset { D1 = 0x180, X3 = 0xc60 };
/* enable USB3 clock and power up */
static Regulator::Connection reg_clk(env, Regulator::CLK_USB20);
reg_clk.state(true);
static Regulator::Connection reg_pwr(env, Regulator::PWR_USB20);
reg_pwr.state(true);
/* reset hub via GPIO */
Io_mem_connection io_gpio(env, GPIO_BASE, 0x1000);
addr_t gpio_base = (addr_t)env.rm().attach(io_gpio.dataspace());
Gpio_bank *d1 = reinterpret_cast<Gpio_bank *>(gpio_base + D1);
Gpio_bank *x3 = reinterpret_cast<Gpio_bank *>(gpio_base + X3);
/* hub reset */
gpio_direction_output(x3, 5, 0);
/* hub connect */
gpio_direction_output(d1, 7, 0);
gpio_direction_output(x3, 5, 1);
gpio_direction_output(d1, 7, 1);
env.rm().detach(gpio_base);
/* reset ehci controller */
Io_mem_connection io_ehci(env, EHCI_BASE, 0x1000);
addr_t ehci_base = (addr_t)env.rm().attach(io_ehci.dataspace());
Ehci ehci(ehci_base);
env.rm().detach(ehci_base);
}
struct Phy_usb3 : Genode::Mmio
{
struct Link_system : Register<0x4, 32>
{
struct Fladj : Bitfield<1, 6> { };
struct Ehci_version_control : Bitfield<27, 1> { };
};
struct Phy_utmi : Register<0x8, 32> { };
struct Phy_clk_rst : Register<0x10, 32>
{
struct Common_onn : Bitfield<0, 1> { };
struct Port_reset : Bitfield<1, 1> { };
struct Ref_clk_sel : Bitfield<2, 2> { };
struct Retenablen : Bitfield<4, 1> { };
struct Fsel : Bitfield<5, 6> { };
struct Mpll_mult : Bitfield<11, 7> { };
struct Ref_ssp_en : Bitfield<19, 1> { };
struct Ssc_en : Bitfield<20, 1> { };
struct Ssc_ref_clk_sel : Bitfield<23, 8> { };
};
struct Phy_reg0 : Register<0x14, 32> { };
struct Phy_param0 : Register<0x1c, 32>
{
struct Loss_level : Bitfield<26, 5> { };
struct Ref_use_pad : Bitfield<31, 1> { };
};
struct Phy_param1 : Register<0x20, 32>
{
struct Pcs_txdeemph : Bitfield<0, 5> { };
};
struct Phy_test : Register<0x28, 32>
{
struct Power_down_ssb_hsb : Bitfield<2, 2> { };
};
struct Phy_batchg : Register<0x30, 32>
{
struct Utmi_clksel : Bitfield<2, 1> { };
};
struct Phy_resume : Register<0x34, 32> { };
Phy_usb3 (Genode::Env & env, addr_t const base) : Mmio(base)
{
Timer::Connection timer(env);
/* reset */
write<Phy_reg0>(0);
/* clock source */
write<Phy_param0::Ref_use_pad>(0);
/* set Loss-of-Signal Detector sensitivity */
write<Phy_param0::Loss_level>(0x9);
write<Phy_resume>(0);
/*
* Setting the Frame length Adj value[6:1] to default 0x20
* See xHCI 1.0 spec, 5.2.4
*/
write<Link_system::Ehci_version_control>(1);
write<Link_system::Fladj>(0x20);
/* set Tx De-Emphasis level */
write<Phy_param1::Pcs_txdeemph>(0x1c);
/* set clock */
write<Phy_batchg::Utmi_clksel>(1);
/* PHYTEST POWERDOWN Control */
write<Phy_test::Power_down_ssb_hsb>(0);
/* UTMI power */
enum { OTG_DISABLE = (1 << 6) };
write<Phy_utmi>(OTG_DISABLE);
/* setup clock */
Phy_clk_rst::access_t clk = 0;
/*
* Use same reference clock for high speed
* as for super speed
*/
Phy_clk_rst::Ref_clk_sel::set(clk, 0x2);
/* 24 MHz */
Phy_clk_rst::Fsel::set(clk, 0x2a);
Phy_clk_rst::Mpll_mult::set(clk, 0x68);
Phy_clk_rst::Ssc_ref_clk_sel::set(clk, 0x88);
/* port reset */
Phy_clk_rst::Port_reset::set(clk, 1);
/* digital power supply in normal operating mode */
Phy_clk_rst::Retenablen::set(clk, 1);
/* enable ref clock for SS function */
Phy_clk_rst::Ref_ssp_en::set(clk, 1);
/* enable spread spectrum */
Phy_clk_rst::Ssc_en::set(clk, 1);
/* power down HS Bias and PLL blocks in suspend mode */
Phy_clk_rst::Common_onn::set(clk, 1);
write<Phy_clk_rst>(clk);
timer.usleep(10);
write<Phy_clk_rst::Port_reset>(0);
}
};
static void arndale_xhci_init(Genode::Env &env)
{
/* enable USB3 clock and power up */
static Regulator::Connection reg_clk(env, Regulator::CLK_USB30);
reg_clk.state(true);
static Regulator::Connection reg_pwr(env, Regulator::PWR_USB30);
reg_pwr.state(true);
/* setup PHY */
Attached_io_mem_dataspace io_phy(env, DWC3_PHY_BASE, 0x1000);
Phy_usb3 phy(env, (addr_t)io_phy.local_addr<addr_t>());
}
extern "C" void module_ehci_exynos_init();
extern "C" void module_dwc3_driver_init();
extern "C" void module_xhci_plat_init();
void ehci_setup(Services *services)
{
/* register EHCI controller */
module_ehci_exynos_init();
/* setup controller */
arndale_ehci_init(services->env);
/* setup EHCI-controller platform device */
platform_device *pdev = (platform_device *)kzalloc(sizeof(platform_device), 0);
pdev->name = (char *)"exynos-ehci";
pdev->id = 0;
pdev->num_resources = 2;
pdev->resource = _ehci;
/*needed for DMA buffer allocation. See 'hcd_buffer_alloc' in 'buffer.c' */
static u64 dma_mask = ~(u64)0;
pdev->dev.dma_mask = &dma_mask;
pdev->dev.coherent_dma_mask = ~0;
platform_device_register(pdev);
}
void xhci_setup(Services *services)
{
module_dwc3_driver_init();
module_xhci_plat_init();
arndale_xhci_init(services->env);
/* setup DWC3-controller platform device */
platform_device *pdev = (platform_device *)kzalloc(sizeof(platform_device), 0);
pdev->name = (char *)"dwc3";
pdev->id = 0;
pdev->num_resources = 2;
pdev->resource = _dwc3;
/*needed for DMA buffer allocation. See 'hcd_buffer_alloc' in 'buffer.c' */
static u64 dma_mask = ~(u64)0;
pdev->dev.dma_mask = &dma_mask;
pdev->dev.coherent_dma_mask = ~0;
platform_device_register(pdev);
}
void platform_hcd_init(Services *services)
{
ehci_setup(services);
xhci_setup(services);
}

View File

@ -0,0 +1,22 @@
include $(REP_DIR)/src/drivers/usb_host/target.inc
TARGET = arndale_usb_host_drv
REQUIRES = arndale
INC_DIR += $(REP_DIR)/src/drivers/usb_host/spec/arm
INC_DIR += $(REP_DIR)/src/include/spec/arm
SRC_CC += spec/arm/platform.cc
SRC_CC += spec/arndale/platform.cc
SRC_C += usb/dwc3/core.c
SRC_C += usb/dwc3/dwc3-exynos.c
SRC_C += usb/dwc3/host.c
SRC_C += usb/host/ehci-exynos.c
SRC_C += usb/host/xhci-plat.c
CC_OPT += -DCONFIG_USB_EHCI_TT_NEWSCHED=1
CC_OPT += -DCONFIG_USB_DWC3_HOST=1
CC_OPT += -DCONFIG_USB_OTG_UTILS=1
CC_OPT += -DCONFIG_USB_XHCI_PLATFORM=1
CC_OPT += -DDWC3_QUIRK

View File

@ -0,0 +1,207 @@
/*
* \brief EHCI for Odroid-x2 initializaion code
* \author Sebastian Sumpf
* \author Alexy Gallardo Segura <alexy@uclv.cu>
* \author Humberto Lopez Leon <humberto@uclv.cu>
* \author Reinir Millo Sanchez <rmillo@uclv.cu>
* \date 2015-07-08
*/
/*
* Copyright (C) 2015-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Genode */
#include <drivers/defs/odroid_x2.h>
#include <base/attached_io_mem_dataspace.h>
#include <io_mem_session/connection.h>
#include <regulator/consts.h>
#include <regulator_session/connection.h>
#include <timer_session/connection.h>
#include <util/mmio.h>
#include <gpio_session/connection.h>
/* Emulation */
#include <lx_emul.h>
#include <platform.h>
using namespace Genode;
enum Usb_masks {
PHY0_NORMAL_MASK = 0x39 << 0,
PHY0_SWRST_MASK = 0x7 << 0,
PHY1_STD_NORMAL_MASK = 0x7 << 6,
EXYNOS4X12_HSIC0_NORMAL_MASK = 0x7 << 9,
EXYNOS4X12_HSIC1_NORMAL_MASK = 0x7 << 12,
EXYNOS4X12_HOST_LINK_PORT_SWRST_MASK = 0xf << 7,
EXYNOS4X12_PHY1_SWRST_MASK = 0xf << 3,
};
enum {
/*The EHCI base is taken from linux kernel */
EHCI_BASE = 0x12580000,
GPIO_BASE = 0x11000000,
USBOTG = 0x125B0000,
EHCI_IRQ = Odroid_x2::USB_HOST20_IRQ,
};
static resource _ehci[] =
{
{ EHCI_BASE, EHCI_BASE + 0xfff, "ehci", IORESOURCE_MEM },
{ EHCI_IRQ, EHCI_IRQ, "ehci-irq", IORESOURCE_IRQ },
};
/**
* EHCI controller
*/
struct Ehci : Genode::Mmio
{
Ehci(addr_t const mmio_base) : Mmio(mmio_base)
{
write<Cmd>(0);
/* reset */
write<Cmd::Reset>(1);
while(read<Cmd::Reset>())
msleep(1);
}
struct Cmd : Register<0x10, 32>
{
struct Reset : Bitfield<1, 1> { };
};
};
/**
* USB OTG handling
*/
struct Usb_otg : Genode::Mmio
{
Usb_otg(Genode::Env &env, Genode::addr_t base)
: Genode::Mmio (base)
{
Timer::Connection timer(env);
unsigned int rstcon_mask = 0;
unsigned int phyclk_mask = 5;
unsigned int phypwr_mask = 0;
/*set the clock of device*/
write<Phyclk>(phyclk_mask);
rstcon_mask= read<Phyclk>();
/* set to normal of Device */
phypwr_mask= read<Phypwr>() & ~PHY0_NORMAL_MASK;
write<Phypwr>(phypwr_mask);
/* set to normal of Host */
phypwr_mask=read<Phypwr>();
phypwr_mask &= ~(PHY1_STD_NORMAL_MASK
|EXYNOS4X12_HSIC0_NORMAL_MASK
|EXYNOS4X12_HSIC1_NORMAL_MASK);
write<Phypwr>(phypwr_mask);
/* reset both PHY and Link of Device */
rstcon_mask = read<Rstcon>() | PHY0_SWRST_MASK;
write<Rstcon>(rstcon_mask);
timer.usleep(10);
rstcon_mask &= ~PHY0_SWRST_MASK;
write<Rstcon>(rstcon_mask);
/* reset both PHY and Link of Host */
rstcon_mask = read<Rstcon>()
|EXYNOS4X12_HOST_LINK_PORT_SWRST_MASK
|EXYNOS4X12_PHY1_SWRST_MASK;
write<Rstcon>(rstcon_mask);
timer.usleep(10);
rstcon_mask &= ~(EXYNOS4X12_HOST_LINK_PORT_SWRST_MASK
|EXYNOS4X12_PHY1_SWRST_MASK);
write<Rstcon>(rstcon_mask);
timer.usleep(10);
}
struct Phypwr : Register <0x0,32>{};
struct Phyclk : Register <0x4,32>{};
struct Rstcon : Register <0x8,32>{};
};
static void clock_pwr_init(Genode::Env &env)
{
/* enable USB2 clock and power up */
static Regulator::Connection reg_clk(env, Regulator::CLK_USB20);
reg_clk.state(true);
static Regulator::Connection reg_pwr(env, Regulator::PWR_USB20);
reg_pwr.state(true);
}
static void usb_phy_init(Genode::Env &env)
{
Io_mem_connection io_usbotg(env, USBOTG, 0x1000);
addr_t usbotg_base = (addr_t)env.rm().attach(io_usbotg.dataspace());
Usb_otg usbotg(env, usbotg_base);
env.rm().detach(usbotg_base);
}
static void odroidx2_ehci_init(Genode::Env &env)
{
clock_pwr_init(env);
usb_phy_init(env);
/* reset hub via GPIO */
enum { X30 = 294, X34 = 298, X35 = 299 };
Gpio::Connection gpio_x30(env, X30);
Gpio::Connection gpio_x34(env, X34);
Gpio::Connection gpio_x35(env, X35);
/* Set Ref freq 0 => 24MHz, 1 => 26MHz*/
/* Odroid Us have it at 24MHz, Odroid Xs at 26MHz */
gpio_x30.write(true);
/* Disconnect, Reset, Connect */
gpio_x34.write(false);
gpio_x35.write(false);
gpio_x35.write(true);
gpio_x34.write(true);
/* reset ehci controller */
Io_mem_connection io_ehci(env, EHCI_BASE, 0x1000);
addr_t ehci_base = (addr_t)env.rm().attach(io_ehci.dataspace());
Ehci ehci(ehci_base);
env.rm().detach(ehci_base);
}
extern "C" void module_ehci_exynos_init();
extern "C" int module_usbnet_init();
extern "C" int module_smsc95xx_driver_init();
void platform_hcd_init(Services *services)
{
/* register EHCI controller */
module_ehci_exynos_init();
/* setup controller */
odroidx2_ehci_init(services->env);
/* setup EHCI-controller platform device */
platform_device *pdev = (platform_device *)kzalloc(sizeof(platform_device), 0);
pdev->name = (char *)"exynos-ehci";
pdev->id = 0;
pdev->num_resources = 2;
pdev->resource = _ehci;
/*needed for DMA buffer allocation. See 'hcd_buffer_alloc' in 'buffer.c' */
static u64 dma_mask = ~(u64)0;
pdev->dev.dma_mask = &dma_mask;
pdev->dev.coherent_dma_mask = ~0;
platform_device_register(pdev);
}

View File

@ -0,0 +1,14 @@
include $(REP_DIR)/src/drivers/usb_host/target.inc
TARGET = odroid_x2_usb_host_drv
REQUIRES = odroid_x2
INC_DIR += $(REP_DIR)/src/drivers/usb_host/spec/arm
INC_DIR += $(REP_DIR)/src/include/spec/arm
SRC_CC += spec/arm/platform.cc
SRC_CC += spec/odroid_x2/platform.cc
SRC_C += usb/host/ehci-exynos.c
CC_OPT += -DCONFIG_USB_OTG_UTILS=1

View File

@ -0,0 +1,309 @@
/*
* \brief EHCI for OMAP4
* \author Sebastian Sumpf <sebastian.sumpf@genode-labs.com>
* \date 2012-06-20
*/
/*
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <platform.h>
#include <drivers/defs/panda.h>
#include <gpio_session/connection.h>
#include <io_mem_session/connection.h>
#include <util/mmio.h>
#include <lx_emul.h>
#include <linux/platform_data/usb-omap.h>
using namespace Genode;
/**
* Base addresses
*/
enum {
EHCI_BASE = 0x4a064c00,
UHH_BASE = 0x4a064000,
TLL_BASE = 0x4a062000,
SCRM_BASE = 0x4a30a000,
CAM_BASE = 0x4a009000, /* used for L3INIT_CM2 */
};
/**
* Inerrupt numbers
*/
enum { IRQ_EHCI = Panda::HSUSB_EHCI_IRQ };
/**
* Resources for platform device
*/
static resource _ehci[] =
{
{ EHCI_BASE, EHCI_BASE + 0x400 - 1, "ehci", IORESOURCE_MEM },
{ IRQ_EHCI, IRQ_EHCI, "ehci-irq", IORESOURCE_IRQ },
};
/**
* Port informations for platform device
*/
static struct ehci_hcd_omap_platform_data _ehci_data;
/**
* Enables USB clocks
*/
struct Clocks : Genode::Mmio
{
Clocks(Genode::addr_t const mmio_base) : Mmio(mmio_base)
{
write<Usb_phy_clk>(0x101);
write<Usb_host_clk>(0x1008002);
write<Usb_tll_clk>(0x1);
}
struct Usb_host_clk : Register<0x358, 32> { };
struct Usb_tll_clk : Register<0x368, 32> { };
struct Usb_phy_clk : Register<0x3e0, 32> { };
template <typename T> void update(unsigned val)
{
typename T::access_t access = read<T>();
access |= val;
write<T>(access);
};
void dump()
{
Usb_host_clk::access_t a1 = read<Usb_host_clk>();
Usb_tll_clk::access_t a3 = read<Usb_tll_clk>();
Usb_phy_clk::access_t a4 = read<Usb_phy_clk>();
}
};
/**
* Panda board reference USB clock
*/
struct Aux3 : Genode::Mmio
{
Aux3(addr_t const mmio_base) : Mmio(mmio_base)
{
enable();
}
/* the clock register */
struct Aux3_clk : Register<0x31c, 32>
{
struct Src_select : Bitfield<1, 2> { };
struct Div : Bitfield<16, 4> { enum { DIV_2 = 1 }; };
struct Enable : Bitfield<8, 1> { enum { ON = 1 }; };
};
/* clock source register */
struct Aux_src : Register<0x110, 32, true> { };
void enable()
{
/* select system clock */
write<Aux3_clk::Src_select>(0);
/* set to 19.2 Mhz */
write<Aux3_clk::Div>(Aux3_clk::Div::DIV_2);
/* enable clock */
write<Aux3_clk::Enable>(Aux3_clk::Enable::ON);
/* enable_ext = 1 | enable_int = 1| mode = 0x01 */
write<Aux_src>(0xd);
}
};
/**
* ULPI transceiverless link
*/
struct Tll : Genode::Mmio
{
Tll(addr_t const mmio_base) : Mmio(mmio_base)
{
reset();
}
struct Sys_config : Register<0x10, 32>
{
struct Soft_reset : Bitfield<1, 1> { };
struct Cactivity : Bitfield<8, 1> { };
struct Sidle_mode : Bitfield<3, 2> { };
struct Ena_wakeup : Bitfield<2, 1> { };
};
struct Sys_status : Register<0x14, 32> { };
void reset()
{
write<Sys_config>(0x0);
/* reset */
write<Sys_config::Soft_reset>(0x1);
while(!read<Sys_status>())
msleep(1);
/* disable IDLE, enable wake up, enable auto gating */
write<Sys_config::Cactivity>(1);
write<Sys_config::Sidle_mode>(1);
write<Sys_config::Ena_wakeup>(1);
}
};
/**
* USB high-speed host
*/
struct Uhh : Genode::Mmio
{
Uhh(addr_t const mmio_base) : Mmio(mmio_base)
{
/* diable idle and standby */
write<Sys_config::Idle>(1);
write<Sys_config::Standby>(1);
/* set ports to external phy */
write<Host_config::P1_mode>(0);
write<Host_config::P2_mode>(0);
}
struct Sys_config : Register<0x10, 32>
{
struct Idle : Bitfield<2, 2> { };
struct Standby : Bitfield<4, 2> { };
};
struct Host_config : Register<0x40, 32>
{
struct P1_mode : Bitfield<16, 2> { };
struct P2_mode : Bitfield<18, 2> { };
};
};
/**
* EHCI controller
*/
struct Ehci : Genode::Mmio
{
Ehci(addr_t const mmio_base) : Mmio(mmio_base)
{
write<Cmd>(0);
/* reset */
write<Cmd::Reset>(1);
while(read<Cmd::Reset>())
msleep(1);
}
struct Cmd : Register<0x10, 32>
{
struct Reset : Bitfield<1, 1> { };
};
};
/**
* Initialize the USB controller from scratch, since the boot loader might not
* do it or even disable USB.
*/
static void omap_ehci_init(Genode::Env &env)
{
/* taken from the Panda board manual */
enum { HUB_POWER = 1, HUB_NRESET = 62, ULPI_PHY_TYPE = 182 };
/* SCRM */
Io_mem_connection io_scrm(env, SCRM_BASE, 0x1000);
addr_t scrm_base = (addr_t)env.rm().attach(io_scrm.dataspace());
/* enable reference clock */
Aux3 aux3(scrm_base);
/* init GPIO */
Gpio::Connection gpio_power(env, HUB_POWER);
Gpio::Connection gpio_reset(env, HUB_NRESET);
/* disable the hub power and reset before init */
gpio_power.direction(Gpio::Session::OUT);
gpio_reset.direction(Gpio::Session::OUT);
gpio_power.write(false);
gpio_reset.write(true);
/* enable clocks */
Io_mem_connection io_clock(env, CAM_BASE, 0x1000);
addr_t clock_base = (addr_t)env.rm().attach(io_clock.dataspace());
Clocks c(clock_base);
/* reset TLL */
Io_mem_connection io_tll(env, TLL_BASE, 0x1000);
addr_t tll_base = (addr_t)env.rm().attach(io_tll.dataspace());
Tll t(tll_base);
/* reset host */
Io_mem_connection io_uhh(env, UHH_BASE, 0x1000);
addr_t uhh_base = (addr_t)env.rm().attach(io_uhh.dataspace());
Uhh uhh(uhh_base);
/* enable hub power */
gpio_power.write(true);
/* reset EHCI */
addr_t ehci_base = uhh_base + 0xc00;
Ehci ehci(ehci_base);
addr_t base[] = { scrm_base, clock_base, tll_base, uhh_base, 0 };
for (int i = 0; base[i]; i++)
env.rm().detach(base[i]);
}
extern "C" void module_ehci_omap_init();
extern "C" int module_usbnet_init();
extern "C" int module_smsc95xx_driver_init();
void platform_hcd_init(Services *services)
{
/* register EHCI controller */
module_ehci_omap_init();
/* initialize EHCI */
omap_ehci_init(services->env);
/* setup EHCI-controller platform device */
platform_device *pdev = (platform_device *)kzalloc(sizeof(platform_device), 0);
pdev->name = (char *)"ehci-omap";
pdev->id = 0;
pdev->num_resources = 2;
pdev->resource = _ehci;
_ehci_data.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY;
_ehci_data.port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED;
_ehci_data.phy_reset = 0;
pdev->dev.platform_data = &_ehci_data;
/*
* Needed for DMA buffer allocation. See 'hcd_buffer_alloc' in 'buffer.c'
*/
static u64 dma_mask = ~(u64)0;
pdev->dev.dma_mask = &dma_mask;
pdev->dev.coherent_dma_mask = ~0;
platform_device_register(pdev);
}

View File

@ -0,0 +1,15 @@
include $(REP_DIR)/src/drivers/usb_host/target.inc
TARGET = panda_usb_host_drv
REQUIRES = panda
INC_DIR += $(REP_DIR)/src/drivers/usb_host/spec/arm
INC_DIR += $(REP_DIR)/src/include/spec/arm
SRC_CC += spec/arm/platform.cc
SRC_CC += spec/panda/platform.cc
SRC_C += usb/host/ehci-omap.c
CC_OPT += -DCONFIG_USB_EHCI_HCD_OMAP=1
CC_OPT += -DCONFIG_USB_EHCI_TT_NEWSCHED=1
CC_OPT += -DCONFIG_EXTCON=1

View File

@ -0,0 +1,84 @@
/*
* \brief USB initialization for Raspberry Pi
* \author Norman Feske
* \date 2013-09-11
*/
/*
* Copyright (C) 2013-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Genode includes */
#include <io_mem_session/connection.h>
#include <util/mmio.h>
#include <platform_session/connection.h>
/* emulation */
#include <platform.h>
#include <lx_emul.h>
#include <timer_session/connection.h>
/* dwc-otg */
#define new new_
#include <dwc_otg_dbg.h>
#undef new
using namespace Genode;
unsigned dwc_irq();
/************************************************
** Resource info passed to the dwc_otg driver **
************************************************/
enum {
DWC_BASE = 0x20980000,
DWC_SIZE = 0x20000,
};
static resource _dwc_otg_resource[] =
{
{ DWC_BASE, DWC_BASE + DWC_SIZE - 1, "dwc_otg", IORESOURCE_MEM },
{ dwc_irq(), dwc_irq(), "dwc_otg-irq" /* name unused */, IORESOURCE_IRQ }
};
/*******************
** Init function **
*******************/
extern "C" void module_dwc_otg_driver_init();
extern bool fiq_enable, fiq_fsm_enable;
void platform_hcd_init(Services *services)
{
/* enable USB power */
Platform::Connection platform(services->env);
platform.power_state(Platform::Session::POWER_USB_HCD, true);
/* disable fiq optimization */
fiq_enable = false;
fiq_fsm_enable = false;
module_dwc_otg_driver_init();
/* setup host-controller platform device */
platform_device *pdev = (platform_device *)kzalloc(sizeof(platform_device), 0);
pdev->name = (char *)"dwc_otg";
pdev->id = 0;
pdev->num_resources = sizeof(_dwc_otg_resource)/sizeof(resource);
pdev->resource = _dwc_otg_resource;
/* needed for DMA buffer allocation. See 'hcd_buffer_alloc' in 'buffer.c' */
static u64 dma_mask = ~(u64)0;
pdev->dev.dma_mask = &dma_mask;
pdev->dev.coherent_dma_mask = ~0;
platform_device_register(pdev);
}

View File

@ -0,0 +1,49 @@
include $(REP_DIR)/src/drivers/usb_host/target.inc
TARGET = rpi_usb_host_drv
REQUIRES = rpi
INC_DIR += $(REP_DIR)/src/drivers/usb_host/spec/arm
INC_DIR += $(REP_DIR)/src/include/spec/arm
SRC_CC += spec/arm/platform.cc
SRC_CC += spec/rpi/platform.cc
SRC_C += dwc_common_port/dwc_cc.c
SRC_C += dwc_common_port/dwc_common_linux.c
SRC_C += dwc_common_port/dwc_crypto.c
SRC_C += dwc_common_port/dwc_dh.c
SRC_C += dwc_common_port/dwc_mem.c
SRC_C += dwc_common_port/dwc_modpow.c
SRC_C += dwc_common_port/dwc_notifier.c
SRC_C += dwc_otg/dwc_otg_adp.c
SRC_C += dwc_otg/dwc_otg_attr.c
SRC_C += dwc_otg/dwc_otg_cfi.c
SRC_C += dwc_otg/dwc_otg_cil.c
SRC_C += dwc_otg/dwc_otg_cil_intr.c
SRC_C += dwc_otg/dwc_otg_driver.c
SRC_C += dwc_otg/dwc_otg_hcd.c
SRC_C += dwc_otg/dwc_otg_hcd_ddma.c
SRC_C += dwc_otg/dwc_otg_hcd_intr.c
SRC_C += dwc_otg/dwc_otg_hcd_linux.c
SRC_C += dwc_otg/dwc_otg_hcd_queue.c
CC_OPT += -DDWC_LINUX -DPLATFORM_INTERFACE
# needed for 'ehci-hcd.c', which we don't use on the rpi, but it is still
# part of the generic usb USB driver
CC_OPT += -DCONFIG_USB_EHCI_PCI=1
# for 'dwc_otg_hcd_linux.c' for enabling the FIQ, which we don't use anyway
CC_OPT += -DINTERRUPT_VC_USB=9
# for 'dwc_otg_driver.c' for preventing calls to set_irq_type
CC_OPT += -DIRQF_TRIGGER_LOW=1
INC_DIR += $(LX_CONTRIB_DIR)/drivers/usb/host/dwc_common_port \
$(LX_CONTRIB_DIR)/drivers/usb/host/dwc_otg \
$(REP_DIR)/src/lib/usb_host/spec/arm
vpath %.c $(LX_CONTRIB_DIR)/drivers/usb/host
LIBS += rpi_usb

View File

@ -0,0 +1,132 @@
/*
* \brief EHCI for Freescale i.MX6
* \author Stefan Kalkowski
* \date 2018-04-11
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <platform.h>
#include <lx_emul.h>
extern "C" int module_ci_hdrc_platform_register();
extern "C" int module_ci_hdrc_imx_driver_init();
extern "C" int module_usbmisc_imx_driver_init();
extern "C" int postcore_mxs_phy_module_init();
extern "C" void module_ehci_hcd_init();
extern "C" void module_xhci_hcd_init();
void platform_hcd_init(Services *services)
{
module_ehci_hcd_init();
module_ci_hdrc_platform_register();
postcore_mxs_phy_module_init();
module_usbmisc_imx_driver_init();
module_ci_hdrc_imx_driver_init();
/* USB PHY initialization */
{
static resource usbphy_res[] =
{
{ 0x020ca000, 0x020cafff, "usbphy", IORESOURCE_MEM },
{ 77, 77, "usbphy-irq", IORESOURCE_IRQ },
};
platform_device *pdev = (platform_device *)kzalloc(sizeof(platform_device), 0);
pdev->name = (char *)"mxs_phy";
pdev->id = 0;
pdev->num_resources = 2;
pdev->resource = usbphy_res;
pdev->dev.of_node = (device_node*)kzalloc(sizeof(device_node), 0);
pdev->dev.of_node->properties = (property*)kzalloc(sizeof(property), 0);
pdev->dev.of_node->properties->name = "compatible";
pdev->dev.of_node->properties->value = (void*)"fsl,imx6q-usbphy";
pdev->dev.of_node->properties->next = (property*)kzalloc(sizeof(property), 0);
pdev->dev.of_node->properties->next->name = "fsl,anatop";
pdev->dev.of_node->properties->next->value = (void*)0xdeaddead;
platform_device_register(pdev);
}
device_node * usbmisc_of_node = nullptr;
/* USB MISC initialization */
{
static resource usbmisc_res[] = { { 0x02184800, 0x021849ff, "usbmisc", IORESOURCE_MEM }, };
platform_device *pdev = (platform_device *)kzalloc(sizeof(platform_device), 0);
pdev->name = (char *)"usbmisc_imx";
pdev->id = 1;
pdev->num_resources = 1;
pdev->resource = usbmisc_res;
pdev->dev.of_node = (device_node*)kzalloc(sizeof(device_node), 0);
pdev->dev.of_node->properties = (property*)kzalloc(sizeof(property), 0);
pdev->dev.of_node->properties->name = "compatible";
pdev->dev.of_node->properties->value = (void*)"fsl,imx6q-usbmisc";
pdev->dev.of_node->dev = &pdev->dev;
usbmisc_of_node = pdev->dev.of_node;
platform_device_register(pdev);
}
/* setup EHCI-controller platform device */
{
static resource ehci_res[] =
{
{ 0x02184200, 0x021843ff, "imx_usb", IORESOURCE_MEM },
{ 72, 72, "imx_usb-irq", IORESOURCE_IRQ },
};
platform_device *pdev = (platform_device *)kzalloc(sizeof(platform_device), 0);
pdev->name = (char *)"imx_usb";
pdev->id = 2;
pdev->num_resources = 2;
pdev->resource = ehci_res;
pdev->dev.of_node = (device_node*)kzalloc(sizeof(device_node), 0);
pdev->dev.of_node->properties = (property*)kzalloc(sizeof(property), 0);
pdev->dev.of_node->properties->name = "compatible";
pdev->dev.of_node->properties->value = (void*)"fsl,imx6q-usb";
pdev->dev.of_node->properties->next = (property*)kzalloc(sizeof(property), 0);
pdev->dev.of_node->properties->next->name = "fsl,usbmisc";
pdev->dev.of_node->properties->next->value = (void*)usbmisc_of_node;
pdev->dev.of_node->properties->next->next = (property*)kzalloc(sizeof(property), 0);
pdev->dev.of_node->properties->next->next->name = "dr_mode";
pdev->dev.of_node->properties->next->next->value = (void*)"host";
/*
* Needed for DMA buffer allocation. See 'hcd_buffer_alloc' in 'buffer.c'
*/
static u64 dma_mask = ~(u64)0;
pdev->dev.dma_mask = &dma_mask;
pdev->dev.coherent_dma_mask = ~0;
platform_device_register(pdev);
}
}
extern "C" int devm_extcon_register_notifier(struct device *dev, struct extcon_dev *edev, unsigned int id, struct notifier_block *nb)
{
BUG();
return -1;
}
extern "C" struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index)
{
BUG();
return NULL;
}
extern "C" int extcon_get_state(struct extcon_dev *edev, unsigned int id)
{
BUG();
return -1;
}

View File

@ -0,0 +1,27 @@
include $(REP_DIR)/src/drivers/usb_host/target.inc
TARGET = wand_quad_usb_host_drv
REQUIRES = wand_quad
SRC_C += usb/chipidea/ci_hdrc_imx.c
SRC_C += usb/chipidea/core.c
SRC_C += usb/chipidea/host.c
SRC_C += usb/chipidea/otg.c
SRC_C += usb/chipidea/usbmisc_imx.c
SRC_C += usb/phy/phy-mxs-usb.c
INC_DIR += $(REP_DIR)/src/drivers/usb_host/spec/arm
INC_DIR += $(REP_DIR)/src/include/spec/arm
SRC_CC += spec/arm/platform.cc
SRC_CC += spec/wand_quad/platform.cc
CC_OPT += -DCONFIG_USB_CHIPIDEA
CC_OPT += -DCONFIG_USB_CHIPIDEA_HOST
CC_OPT += -DCONFIG_USB_EHCI_HCD
CC_OPT += -DCONFIG_USB_EHCI_ROOT_HUB_TT
CC_OPT += -DCONFIG_USB_MXS_PHY
CC_OPT += -DCONFIG_USB_EHCI_TT_NEWSCHED=1
CC_OPT += -DCONFIG_EXTCON=1
CC_C_OPT += -Wno-incompatible-pointer-types

View File

@ -0,0 +1,223 @@
/*
* \brief PCI device handling
* \author Sebastian Sumpf
* \date 2016-04-25
*/
/*
* Copyright (C) 2016-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Genode includes */
#include <base/allocator.h>
#include <base/entrypoint.h>
#include <base/lock.h>
#include <base/signal.h>
#include <util/misc_math.h>
#include <lx_emul.h>
#include <platform.h>
#include <lx_kit/env.h>
#include <lx_kit/irq.h>
#include <lx_kit/pci_dev_registry.h>
#include <lx_kit/malloc.h>
#include <lx_kit/mapped_io_mem_range.h>
#include <lx_emul/impl/io.h>
#include <lx_emul/impl/pci_resource.h>
/**
* Quirks
*/
extern "C" void __pci_fixup_quirk_usb_early_handoff(void *data);
/**
* List of pci devices from platform driver
*/
class Pci_dev_list
{
private:
struct Element : public Lx_kit::List<Element>::Element
{
Platform::Device_capability cap;
Element(Platform::Device_capability cap) : cap(cap) { }
};
Lx_kit::List<Element> _pci_caps;
public:
Pci_dev_list()
{
/*
* Obtain first device, the operation may exceed the session quota.
* So we use the 'with_upgrade' mechanism.
*/
Platform::Device_capability cap =
Lx::pci()->with_upgrade([&] () {
return Lx::pci()->first_device(); });
/*
* Iterate over the devices of the platform session.
*/
while (cap.valid()) {
_pci_caps.insert(new (Lx::Malloc::mem()) Element(cap));
/* try next one. Upgrade session quota on demand.*/
Lx::pci()->with_upgrade([&] () {
cap = Lx::pci()->next_device(cap); });
}
}
template <typename FUNC>
void for_each_pci_device(FUNC const &func)
{
for (Element *e = _pci_caps.first(); e; e = e->next())
func(e->cap);
}
};
Pci_dev_list *pci_dev_list()
{
static Pci_dev_list _list;
return &_list;
}
extern "C" int pci_register_driver(struct pci_driver *driver)
{
driver->driver.name = driver->name;
pci_device_id const *id_table = driver->id_table;
if (!id_table)
return -ENODEV;
using namespace Genode;
bool found = false;
auto lamda = [&] (Platform::Device_capability cap) {
Platform::Device_client client(cap);
/* request device ID from platform driver */
unsigned const class_code = client.class_code();
/* look if we find the device ID in the driver's 'id_table' */
pci_device_id const *matching_id = nullptr;
for (pci_device_id const *id = id_table; id->device; id++) {
lx_log(DEBUG_PCI,"idclass: %x idclassm: %x devclass %x", id->class_,
id->class_mask, class_code);
/* check for drivers that support any device for a given class */
if (id->device != (unsigned)PCI_ANY_ID || !id->class_mask)
continue;
if ((id->class_ & id->class_mask) == (class_code & id->class_mask)) {
matching_id = id;
break;
}
}
/* skip device that is not handled by driver */
if (!matching_id)
return false;
/* create 'pci_dev' struct for matching device */
Lx::Pci_dev *pci_dev = new (Lx::Malloc::mem()) Lx::Pci_dev(cap);
/* enable ioremap to work */
Lx::pci_dev_registry()->insert(pci_dev);
/* register driver at the 'pci_dev' struct */
pci_dev->dev.driver = &driver->driver;
/*
* This quirk handles device handoff from BIOS, since the BIOS may still
* access the USB controller after bootup. For this the ext cap register of
* the PCI config space is checked
*/
if (Lx_kit::env().config_rom().xml().attribute_value("bios_handoff", true))
__pci_fixup_quirk_usb_early_handoff(pci_dev);
/* call probe function of the Linux driver */
if (driver->probe(pci_dev, matching_id)) {
/* if the probing failed, revert the creation of 'pci_dev' */
pci_dev_put(pci_dev);
return false;
}
found = true;
/* multiple device support continue */
return true;
};
pci_dev_list()->for_each_pci_device(lamda);
return found ? 0 : -ENODEV;
}
/***********************
** linux/interrupt.h **
***********************/
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
const char *name, void *dev)
{
for (Lx::Pci_dev *pci_dev = Lx::pci_dev_registry()->first(); pci_dev; pci_dev = pci_dev->next())
if (pci_dev->irq == irq) {
Lx::Irq::irq().request_irq(pci_dev->client(), handler, dev);
return 0;
}
return -ENODEV;
}
/*********************************
** Platform backend alloc init **
*********************************/
void backend_alloc_init(Genode::Env &env, Genode::Ram_session &ram,
Genode::Allocator &alloc)
{
Lx::pci_init(env, ram, alloc);
}
extern "C" void module_ehci_hcd_init();
extern "C" void module_ehci_pci_init();
extern "C" void module_ohci_hcd_mod_init();
extern "C" void module_ohci_pci_init();
extern "C" void module_uhci_hcd_init();
extern "C" void module_xhci_hcd_init();
extern "C" void module_xhci_pci_init();
void platform_hcd_init(Services *s)
{
module_xhci_hcd_init();
module_xhci_pci_init();
/* ehci_hcd should always be loaded before uhci_hcd and ohci_hcd, not after */
module_ehci_hcd_init();
module_ehci_pci_init();
module_ohci_hcd_mod_init();
module_ohci_pci_init();
module_uhci_hcd_init();
}

View File

@ -0,0 +1,24 @@
include $(REP_DIR)/src/drivers/usb_host/target.inc
TARGET = x86_pc_usb_host_drv
INC_DIR += $(REP_DIR)/src_drivers/usb_host/spec/x86
INC_DIR += $(REP_DIR)/src/include/spec/x86
SRC_C += usb/core/hcd-pci.c
SRC_C += usb/host/ehci-pci.c
SRC_C += usb/host/ohci-hcd.c
SRC_C += usb/host/ohci-pci.c
SRC_C += usb/host/pci-quirks.c
SRC_C += usb/host/uhci-hcd.c
SRC_C += usb/host/xhci-pci.c
SRC_CC += lx_kit/mapped_io_mem_range.cc
SRC_CC += lx_kit/pci.cc
SRC_CC += spec/x86/platform.cc
CC_OPT += -DCONFIG_PCI=1
CC_OPT += -DCONFIG_USB_PCI=1
CC_OPT += -DCONFIG_USB_EHCI_PCI=1
CC_OPT += -DCONFIG_USB_XHCI_HCD=1

View File

@ -0,0 +1,4 @@
include $(REP_DIR)/src/drivers/usb_host/spec/x86/target.inc
REQUIRES = x86_32
INC_DIR += $(REP_DIR)/src/include/spec/x86_32

View File

@ -0,0 +1,4 @@
include $(REP_DIR)/src/drivers/usb_host/spec/x86/target.inc
REQUIRES = x86_64
INC_DIR += $(REP_DIR)/src/include/spec/x86_64

View File

@ -0,0 +1,66 @@
LX_CONTRIB_DIR := $(call select_from_ports,dde_linux)/src/drivers/usb_host
SRC_CC = main.cc lx_emul.cc raw.cc
SRC_C = dummies.c raw_driver.c
LIBS = base usb_host_include lx_kit_setjmp
CC_CXX_WARN_STRICT =
INC_DIR += $(REP_DIR)/src/drivers/usb_host
INC_DIR += $(REP_DIR)/src/include
# lx_kit
SRC_CC += lx_kit/printf.cc
SRC_CC += lx_kit/work.cc
SRC_CC += lx_kit/timer.cc
SRC_CC += lx_kit/scheduler.cc
SRC_CC += lx_kit/irq.cc
SRC_CC += lx_kit/malloc.cc
SRC_CC += lx_kit/env.cc
# contrib code
SRC_C += usb/common/common.c
SRC_C += usb/core/buffer.c
SRC_C += usb/core/config.c
SRC_C += usb/core/devices.c
SRC_C += usb/core/driver.c
SRC_C += usb/core/endpoint.c
SRC_C += usb/core/file.c
SRC_C += usb/core/generic.c
SRC_C += usb/core/hcd.c
SRC_C += usb/core/hub.c
SRC_C += usb/core/message.c
SRC_C += usb/core/notify.c
SRC_C += usb/core/port.c
SRC_C += usb/core/quirks.c
SRC_C += usb/core/urb.c
SRC_C += usb/core/usb.c
SRC_C += usb/host/ehci-hcd.c
SRC_C += usb/host/xhci-dbg.c
SRC_C += usb/host/xhci-hub.c
SRC_C += usb/host/xhci-mem.c
SRC_C += usb/host/xhci-ring.c
SRC_C += usb/host/xhci.c
SRC_C += lib/ctype.c
SRC_C += lib/find_bit.c
CC_OPT += -U__linux__
CC_OPT += -D__KERNEL__
CC_OPT += -DCONFIG_USB_DEVICEFS=1
CC_OPT += -DCONFIG_HOTPLUG=1
CC_OPT += -DCONFIG_USB_PHY=1
CC_OPT += -DCONFIG_HAS_DMA=1
CC_C_OPT += -std=gnu89
CC_C_OPT += -Wno-pointer-sign
CC_C_OPT += -Wno-unused-variable
CC_C_OPT += -Wno-unused-function
CC_C_OPT += -Wno-implicit-int
CC_C_OPT += -Wno-unused-but-set-variable
CC_C_OPT += -Wno-uninitialized
CC_C_OPT += -Wno-maybe-uninitialized
CC_C_OPT += -Wno-unused-label
CC_C_OPT += -Wno-format
vpath lib/ctype.c $(LX_CONTRIB_DIR)
vpath lib/find_bit.c $(LX_CONTRIB_DIR)
vpath %.c $(LX_CONTRIB_DIR)/drivers
vpath %.cc $(REP_DIR)/src
vpath % $(REP_DIR)/src/drivers/usb_host