foc_odroid_x2: USB support

Fixes #1627
This commit is contained in:
Reinier Millo Sánchez 2015-07-08 16:35:22 -04:00 committed by Christian Helmuth
parent 6776d6c9a8
commit 433f859cb9
10 changed files with 456 additions and 96 deletions

View File

@ -3,7 +3,7 @@
* \author Alexy Gallardo Segura <alexy@uclv.cu>
* \author Humberto López León <humberto@uclv.cu>
* \author Reinier Millo Sánchez <rmillo@uclv.cu>
* \date 2015-04-27
* \date 2015-07-08
*/
/*
@ -30,12 +30,16 @@ struct Genode::Board_base : Exynos4
enum
{
/* clock management unit */
CMU_MMIO_BASE = 0x10040000,
CMU_MMIO_BASE = 0x10030000,
CMU_MMIO_SIZE = 0x18000,
/* power management unit */
PMU_MMIO_BASE = 0x10020000,
PMU_MMIO_SIZE = 0x5000,
/* USB HOST interrupt */
USB_HOST20_IRQ = 102,
};
};

View File

@ -3,11 +3,11 @@
# \author Alexy Gallardo Segura <alexy@uclv.cu>
# \author Humberto López León <humberto@uclv.cu>
# \author Reinier Millo Sánchez <rmillo@uclv.cu>
# \date 2015-04-28
# \date 2015-07-08
#
# denote specs that are fullfilled by this spec
SPECS += exynos4 cortex_a9
SPECS += exynos4 cortex_a9 usb
# add repository relative paths
REP_INC_DIR += include/platform/odroid_x2

View File

@ -2,6 +2,7 @@ proc have_platform_drv {} {
if {[have_spec linux]} {
return 0
}
return [expr [have_spec platform_arndale] \
|| [have_spec platform_imx53] \
|| [have_spec platform_rpi] \

View File

@ -0,0 +1,29 @@
/*
* \brief USB registers masks for Odroid-x2
* \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 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _USB_MASKS_H_
#define _USB_MASKS_H_
enum {
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,
};
#endif /* _USB_MASKS_H_ */

View File

@ -0,0 +1,4 @@
LIBS += net-stat
CC_OPT += -DGENODE_NET_STAT
include $(REP_DIR)/lib/mk/platform_odroid_x2/usb.mk

View File

@ -0,0 +1,15 @@
SRC_C += $(addprefix net/usb/, usbnet.c smsc95xx.c)
SRC_C += usb/host/ehci-exynos.c
include $(REP_DIR)/lib/mk/usb.inc
include $(REP_DIR)/lib/mk/armv7/usb.inc
CC_OPT += -DCONFIG_USB_EHCI_TT_NEWSCHED \
-DCONFIG_USB_OTG_UTILS
SRC_CC += platform.cc
INC_DIR += $(REP_DIR)/include/usb/platform_odroid_x2
vpath platform.cc $(LIB_DIR)/arm/platform_odroid_x2

View File

@ -0,0 +1,296 @@
/*
* \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 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode */
#include <drivers/board_base.h>
#include <os/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 <irq_session/connection.h>
#include <util/mmio.h>
/* Emulation */
#include <platform/platform.h>
#include <extern_c_begin.h>
#include <lx_emul.h>
#include <extern_c_end.h>
#include <platform.h>
#include <usb_masks.h>
using namespace Genode;
enum {
/*The EHCI base is taken from linux kernel */
EHCI_BASE = 0x12580000,
GPIO_BASE = 0x11000000,
USBOTG = 0x125B0000,
EHCI_IRQ = Board_base::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> { };
};
};
/**
* Gpio ETC6 register handling
*/
struct Etc6 : Genode::Mmio
{
Etc6(Genode::addr_t base):Genode::Mmio (base)
{
unsigned int value;
value = read<Pud>();
write<Pud>((value & ~(0x3 << 14)) | (0x3 << 14));
value = read<Pud>();
}
struct Pud : Register<0x0228, 16>{};
};
/**
* USB OTG handling
*/
struct Usb_Otg : Genode::Mmio
{
Usb_Otg(Genode::addr_t base):Genode::Mmio (base)
{
Timer::Connection timer;
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>{};
};
/**
* Gpio handling
*/
class Gpio_bank : Genode::Mmio
{
public:
Gpio_bank(Genode::addr_t base):Genode::Mmio (base){}
struct Con : Register<0x0C60, 32>{};
struct Dat : Register<0x0C64, 32>{};
void setDirection(int gpio , int en)
{
unsigned int value;
enum { GPIO_OUTPUT = 0x1 };
value = read<Dat>();
value &= ~(0x1 << gpio);
if (en)
value |= 0x1 << gpio;
write<Dat>(value);
configurePin(gpio, GPIO_OUTPUT);
write<Dat>(value);
}
private:
void configurePin(int gpio, int cfg)
{
unsigned int value;
value = read<Con>();
value &= ~con_mask(gpio);
value |= con_sfr(gpio, cfg);
write<Con>(value);
}
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 clock_pwr_init()
{
/*Initialization of register etc6*/
Io_mem_connection io_gpio(GPIO_BASE, 0x1000);
addr_t gpio_base = (addr_t)env()->rm_session()->attach(io_gpio.dataspace());
Etc6 etc6(gpio_base);
env()->rm_session()->detach(gpio_base);
/* enable USB2 clock and power up */
static Regulator::Connection reg_clk(Regulator::CLK_USB20);
reg_clk.state(true);
static Regulator::Connection reg_pwr(Regulator::PWR_USB20);
reg_pwr.state(true);
}
static void usb_phy_init()
{
Io_mem_connection io_usbotg(USBOTG, 0x1000);
addr_t usbotg_base = (addr_t)env()->rm_session()->attach(io_usbotg.dataspace());
Usb_Otg usbotg(usbotg_base);
env()->rm_session()->detach(usbotg_base);
}
static void odroidx2_ehci_init()
{
clock_pwr_init();
usb_phy_init();
/* reset hub via GPIO */
Io_mem_connection io_gpio(GPIO_BASE, 0x1000);
addr_t gpio_base = (addr_t)env()->rm_session()->attach(io_gpio.dataspace());
Gpio_bank x3(gpio_base);
/* Set Ref freq 0 => 24MHz, 1 => 26MHz*/
/* Odroid Us have it at 24MHz, Odroid Xs at 26MHz */
x3.setDirection(0,1);
/* Disconnect, Reset, Connect */
x3.setDirection(4,0);
x3.setDirection(5,0);
x3.setDirection(5,1);
x3.setDirection(4,1);
env()->rm_session()->detach(gpio_base);
/* reset ehci controller */
Io_mem_connection io_ehci(EHCI_BASE, 0x1000);
addr_t ehci_base = (addr_t)env()->rm_session()->attach(io_ehci.dataspace());
Ehci ehci(ehci_base);
env()->rm_session()->detach(ehci_base);
}
extern "C" void module_ehci_exynos_init();
extern "C" int module_usbnet_init();
extern "C" int module_smsc95xx_driver_init();
void ehci_setup(Services *services)
{
/* register network */
if (services->nic){
module_usbnet_init();
module_smsc95xx_driver_init();
}
/* register EHCI controller */
module_ehci_exynos_init();
/* setup controller */
odroidx2_ehci_init();
/* 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 platform_hcd_init(Services *services)
{
/* register network */
if (services->nic){
module_usbnet_init();
module_smsc95xx_driver_init();
}
/* register ehci */
if (services->ehci)
ehci_setup(services);
}
Genode::Irq_session_capability platform_irq_activate(int irq)
{
try {
Genode::Irq_connection conn(irq);
conn.on_destruction(Genode::Irq_connection::KEEP_OPEN);
return conn;
} catch (...) { }
return Genode::Irq_session_capability();
}

View File

@ -3,7 +3,7 @@
* \author Alexy Gallardo Segura <alexy@uclv.cu>
* \author Humberto Lopez Leon <humberto@uclv.cu>
* \author Reinier Millo Sanchez <rmillo@uclv.cu>
* \date 2015-04-30
* \date 2015-07-08
*/
/*
@ -58,9 +58,10 @@ class Cmu : public Regulator::Driver,
** CMU CPU registers **
***********************/
typedef Pll_lock<4000> Apll_lock;
typedef Pll_con0<0x4100> Apll_con0;
typedef Pll_con0<0x14100> Apll_con0;
struct Clk_src_cpu : Register<0x4200, 32>
struct Clk_src_cpu : Register<0x14200, 32>
{
struct Mux_core_sel : Bitfield<16, 1>
{
@ -68,28 +69,30 @@ class Cmu : public Regulator::Driver,
};
};
struct Clk_mux_stat_cpu : Register<0x4400, 32>
struct Clk_mux_stat_cpu : Register<0x14400, 32>
{
struct Core_sel : Bitfield<16, 3>
{
enum { MOUT_APLL = 0b1, SCLK_MPLL = 0b10 };
};
};
struct Clk_div_cpu0 : Register<0x4500, 32>
struct Clk_div_cpu0 : Register<0x14500, 32>
{
/* Cpu0 divider values for frequencies 200 - 1400 */
static const Genode::uint32_t values[];
};
struct Clk_div_cpu1 : Register<0x4504, 32>
struct Clk_div_cpu1 : Register<0x14504, 32>
{
/* Divider for cpu1 doesn't change */
enum { FIX_VALUE = 32 };
};
struct Clk_div_stat_cpu0 : Register<0x4600, 32>
struct Clk_div_stat_cpu0 : Register<0x14600, 32>
{
struct Div_core : Bitfield< 0, 1> {};
struct Div_corem0 : Bitfield< 4, 1> {};
struct Div_corem1 : Bitfield< 8, 1> {};
@ -99,6 +102,7 @@ class Cmu : public Regulator::Driver,
struct Div_apll : Bitfield<24, 1> {};
struct Div_core2 : Bitfield<28, 1> {};
static bool in_progress(access_t stat_word)
{
return stat_word & (Div_core::bits(1) |
@ -112,7 +116,7 @@ class Cmu : public Regulator::Driver,
}
};
struct Clk_div_stat_cpu1 : Register<0x4604, 32>
struct Clk_div_stat_cpu1 : Register<0x14604, 32>
{
struct Div_copy : Bitfield<0, 1> { };
struct Div_hpm : Bitfield<4, 1> { };
@ -128,18 +132,37 @@ class Cmu : public Regulator::Driver,
/************************
** CMU CORE registers **
************************/
typedef Pll_lock<0x0008> Mpll_lock;
typedef Pll_con0<0x0108> Mpll_con0;
struct Clk_src_dmc : Register<0x4200, 32>
struct Clk_src_dmc : Register<0x10200, 32>
{
struct Mux_mpll_sel : Bitfield<12, 1> { enum { XXTI, MPLL_FOUT_RGT }; };
};
struct Clk_gate_ip_dmc : Register<0x0900, 32> { };
struct Clk_gate_ip_acp : Register<0x0900, 32> { };
struct Clk_gate_ip_isp0 : Register<0x8800, 32> { };
struct Clk_gate_ip_isp1 : Register<0x8804, 32> { };
/***********************
** CMU TOP registers **
***********************/
struct Clk_gate_ip_fsys : Register<0xC940, 32>
{
struct Usbhost20 : Bitfield<12, 1> { };
struct Usbdevice : Bitfield<13, 1> { };
};
/*******************
** CPU functions **
*******************/
@ -148,7 +171,7 @@ class Cmu : public Regulator::Driver,
void _cpu_clk_freq(unsigned long level)
{
PINF("Setting CPU frequency %lu\n",level);
PINF("Changing CPU frequency to %lu",level);
unsigned freq;
switch (level) {
case CPU_FREQ_200:
@ -218,6 +241,34 @@ class Cmu : public Regulator::Driver,
!= Clk_mux_stat_cpu::Core_sel::MOUT_APLL) ;
_cpu_freq = static_cast<Cpu_clock_freq>(level);
PINF("End of Changing CPU frequency to %lu",level);
}
void _enable(Regulator_id id)
{
switch (id) {
case CLK_USB20:
{
write<Clk_gate_ip_fsys::Usbdevice>(1);
return write<Clk_gate_ip_fsys::Usbhost20>(1);
}
default:
PWRN("Unsupported for %s", names[id].name);
}
}
void _disable(Regulator_id id)
{
switch (id) {
case CLK_USB20:
{
write<Clk_gate_ip_fsys::Usbdevice>(0);
return write<Clk_gate_ip_fsys::Usbhost20>(0);
}
default:
PWRN("Unsupported for %s", names[id].name);
}
}
public:
@ -230,9 +281,19 @@ class Cmu : public Regulator::Driver,
Genode::Board_base::CMU_MMIO_SIZE),
_cpu_freq(CPU_FREQ_1400)
{
/**
* Close certain clock gates by default (~ 0.7 Watt reduction)
*/
write<Clk_gate_ip_fsys>(0);
/**
* Set default CPU frequency
*/
_cpu_clk_freq(_cpu_freq);
}
@ -265,10 +326,21 @@ class Cmu : public Regulator::Driver,
void state(Regulator_id id, bool enable)
{
if (enable)
_enable(id);
else
_disable(id);
}
bool state(Regulator_id id)
{
switch (id) {
case CLK_USB20:
return read<Clk_gate_ip_fsys::Usbhost20>();
default:
PWRN("Unsupported for %s", names[id].name);
}
return true;
}
};

View File

@ -3,7 +3,7 @@
* \author Alexy Gallardo Segura <alexy@uclv.cu>
* \author Humberto Lopez Leon <humberto@uclv.cu>
* \author Reinier Millo Sanchez <rmillo@uclv.cu>
* \date 2015-04-30
* \date 2015-07-08
*/
/*
@ -24,14 +24,17 @@
struct Driver_factory: Regulator::Driver_factory
{
Cmu _cmu;
Pmu _pmu;
Regulator::Driver &create(Regulator::Regulator_id id)
{
switch (id) {
case Regulator::CLK_CPU:
case Regulator::CLK_USB20:
return _cmu;
case Regulator::PWR_USB20:
return _pmu;
default:
throw Root::Invalid_args(); /* invalid regulator */
};
@ -39,14 +42,13 @@ struct Driver_factory: Regulator::Driver_factory
void destroy(Regulator::Driver &driver) {
}
};
int main(int, char **)
{
using namespace Genode;
PINF("--- Odroid-x2 platform driver ---\n");
PINF("--- Odroid-x2 platform driver ---");
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, 4096, "odroid_x2_plat_ep");
@ -54,6 +56,7 @@ int main(int, char **)
static Regulator::Root reg_root(&ep, env()->heap(), driver_factory);
env()->parent()->announce(ep.manage(&reg_root));
PINF("--- Odroid-x2 platform driver. Done ---");
sleep_forever();
return 0;
}

View File

@ -3,7 +3,7 @@
* \author Alexy Gallardo Segura <alexy@uclv.cu>
* \author Humberto Lopez Leon <humberto@uclv.cu>
* \author Reinier Millo Sanchez <rmillo@uclv.cu>
* \date 2015-04-30
* \date 2015-07-08
*/
/*
@ -65,68 +65,19 @@ class Pmu : public Regulator::Driver,
struct Div_ratio : Bitfield<16, 10> { };
};
typedef Control<0x704> Usbdrd_phy_control;
typedef Control<0x708> Usbhost_phy_control;
typedef Control<0x70c> Efnand_phy_control;
typedef Control<0x718> Adc_phy_control;
typedef Control<0x71c> Mtcadc_phy_control;
typedef Control<0x720> Dptx_phy_control;
typedef Control<0x724> Sata_phy_control;
typedef Control<0x0704> Usbdrd_phy_control;
typedef Control<0x0708> Usbhost_phy1_control;
typedef Control<0x70c> Usbhost_phy2_control;
typedef Sysclk_configuration<0x2a40> Vpll_sysclk_configuration;
typedef Sysclk_status<0x2a44> Vpll_sysclk_status;
typedef Sysclk_configuration<0x2a60> Epll_sysclk_configuration;
typedef Sysclk_status<0x2a64> Epll_sysclk_status;
typedef Sysclk_configuration<0x2aa0> Cpll_sysclk_configuration;
typedef Sysclk_status<0x2aa4> Cpll_sysclk_status;
typedef Sysclk_configuration<0x2ac0> Gpll_sysclk_configuration;
typedef Sysclk_status<0x2ac4> Gpll_sysclk_status;
typedef Configuration<0x4000> Gscl_configuration;
typedef Status<0x4004> Gscl_status;
typedef Configuration<0x4020> Isp_configuration;
typedef Status<0x4024> Isp_status;
typedef Configuration<0x4040> Mfc_configuration;
typedef Status<0x4044> Mfc_status;
typedef Configuration<0x4060> G3d_configuration;
typedef Status<0x4064> G3d_status;
typedef Configuration<0x40A0> Disp1_configuration;
typedef Status<0x40A4> Disp1_status;
typedef Configuration<0x40C0> Mau_configuration;
typedef Status<0x40C4> Mau_status;
template <typename C, typename S>
void _disable_domain()
{
if (read<typename S::Stat>() == 0)
return;
write<typename C::Local_pwr_cfg>(0);
while (read<typename S::Stat>() != 0) ;
}
template <typename C, typename S>
void _enable_domain()
{
if (read<typename S::Stat>() == 7)
return;
write<typename C::Local_pwr_cfg>(7);
while (read<typename S::Stat>() != 7) ;
}
void _enable(unsigned long id)
{
switch (id) {
case PWR_USB20:
write<Usbhost_phy_control::Enable>(1);
write<Usbdrd_phy_control::Enable>(1);
write<Usbhost_phy1_control::Enable>(1);
write<Usbhost_phy2_control::Enable>(1);
break;
case PWR_HDMI: {
_enable_domain<Disp1_configuration, Disp1_status>();
Hdmi_phy_control::access_t hpc = read<Hdmi_phy_control>();
Hdmi_phy_control::Div_ratio::set(hpc, 150);
Hdmi_phy_control::Enable::set(hpc, 1);
write<Hdmi_phy_control>(hpc);
break; }
default:
PWRN("Unsupported for %s", names[id].name);
}
@ -136,7 +87,9 @@ class Pmu : public Regulator::Driver,
{
switch (id) {
case PWR_USB20:
write<Usbhost_phy_control::Enable>(0);
write<Usbdrd_phy_control::Enable>(0);
write<Usbhost_phy1_control::Enable>(0);
write<Usbhost_phy2_control::Enable>(0);
break;
default:
PWRN("Unsupported for %s", names[id].name);
@ -151,26 +104,9 @@ class Pmu : public Regulator::Driver,
Pmu() : Genode::Attached_mmio(Genode::Board_base::PMU_MMIO_BASE,
Genode::Board_base::PMU_MMIO_SIZE)
{
write<Hdmi_phy_control ::Enable>(0);
write<Usbdrd_phy_control ::Enable>(0);
write<Usbhost_phy_control::Enable>(0);
write<Efnand_phy_control ::Enable>(0);
write<Adc_phy_control ::Enable>(0);
write<Mtcadc_phy_control ::Enable>(0);
write<Dptx_phy_control ::Enable>(0);
_disable_domain<Gscl_configuration, Gscl_status>();
_disable_domain<Isp_configuration, Isp_status>();
_disable_domain<Mfc_configuration, Mfc_status>();
_disable_domain<G3d_configuration, G3d_status>();
_disable_domain<Disp1_configuration, Disp1_status>();
_disable_domain<Mau_configuration, Mau_status>();
_disable_domain<Vpll_sysclk_configuration, Vpll_sysclk_status>();
_disable_domain<Epll_sysclk_configuration, Epll_sysclk_status>();
_disable_domain<Cpll_sysclk_configuration, Cpll_sysclk_status>();
_disable_domain<Gpll_sysclk_configuration, Gpll_sysclk_status>();
write<Usbhost_phy1_control::Enable>(0);
write<Usbhost_phy2_control::Enable>(0);
}
@ -207,7 +143,7 @@ class Pmu : public Regulator::Driver,
{
switch (id) {
case PWR_USB20:
return read<Usbhost_phy_control::Enable>();
return read<Usbdrd_phy_control::Enable>();
default:
PWRN("Unsupported for %s", names[id].name);
}