blob: 4813ae269443f5b43578d22a80d91cad594d997c [file] [log] [blame]
/*
* Copyright 2017, Data61
* Commonwealth Scientific and Industrial Research Organisation (CSIRO)
* ABN 41 687 119 230.
*
* This software may be distributed and modified according to the terms of
* the BSD 2-Clause license. Note that NO WARRANTY is provided.
* See "LICENSE_BSD2.txt" for details.
*
* @TAG(DATA61_BSD)
*/
#include <platsupport/clock.h>
#include <usb/usb_host.h>
#include "../usb_otg.h"
#include "../../ehci/ehci.h"
#include "../../services.h"
#include <stdio.h>
#include <stddef.h>
#define USB_PHY1_PADDR 0x20C9000
#define USB_PHY2_PADDR 0x20CA000
#define USB_PADDR 0x2184000
#define USB_HOST1_IRQ 72
#define USB_HOST2_IRQ 73
#define USB_HOST3_IRQ 74
#define USB_OTG_IRQ 75
#define USB_PHY1_SIZE 0x0001000
#define USB_PHY2_SIZE 0x0001000
#define USB_SIZE 0x0001000
#define IMX6_PORTSC_PTS_MASK ((3UL << 30) | (1UL << 25))
#define IMX6_PORTSC_PTS_UTMI ((0UL << 30) | (0UL << 25))
#define IMX6_PORTSC_PTS_ULPI ((2UL << 30) | (0UL << 25))
#define IMX6_PORTSC_PTS_ICUSB ((3UL << 30) | (0UL << 25))
#define IMX6_PORTSC_PTS_HSIC ((4UL << 30) | (1UL << 25))
#define IMX6_PORTSC_STS (1UL << 29)
#define IMX6_PORTSC_PTW (1UL << 28)
struct usb_sct {
uint32_t val;
uint32_t set;
uint32_t clr;
uint32_t tog;
};
//USB_PHY1_PADDR
//USB_PHY2_PADDR
struct usb_phy_regs {
struct usb_sct pwd; /* 0x00 */
struct usb_sct tx; /* 0x10 */
struct usb_sct rx; /* 0x20 */
#define PHYCTRL_SFTRST BIT(31)
#define PHYCTRL_CLKGATE BIT(30)
#define PHYCTRL_UTMI_SUSPENDM BIT(29)
#define PHYCTRL_HOST_FORCE_LS_SE0 BIT(28)
#define PHYCTRL_OTG_ID_VALUE BIT(27)
#define PHYCTRL_FSDLL_RST_EN BIT(24)
#define PHYCTRL_ENVBUSCHG_WKUP BIT(23)
#define PHYCTRL_ENIDCHG_WKUP BIT(22)
#define PHYCTRL_ENDPDMCHG_WKUP BIT(21)
#define PHYCTRL_ENAUTOCLR_PHY_PWD BIT(20)
#define PHYCTRL_ENAUTOCLR_CLKGATE BIT(19)
#define PHYCTRL_WAKEUP_IRQ BIT(17)
#define PHYCTRL_ENIRQWAKEUP BIT(16)
#define PHYCTRL_ENUTMIL3 BIT(15)
#define PHYCTRL_ENUTMIL2 BIT(14)
#define PHYCTRL_DATA_ON_LRADC BIT(13)
#define PHYCTRL_DEVPLUGIN_IRQ BIT(12)
#define PHYCTRL_ENIRQDEVPLUGIN BIT(11)
#define PHYCTRL_RESUME_IRQ BIT(10)
#define PHYCTRL_ENIRQRESUMEDETECT BIT( 9)
#define PHYCTRL_RESUMEIRQSTICKY BIT( 8)
#define PHYCTRL_ENOTGIDDETECT BIT( 7)
#define PHYCTRL_OTG_ID_CHG_IRQ BIT( 6)
#define PHYCTRL_DEVPLUGIN_POLARITY BIT( 5)
#define PHYCTRL_ENDEVPLUGINDETECT BIT( 4)
#define PHYCTRL_HOSTDISCONDETECT_IRQ BIT( 3)
#define PHYCTRL_ENIRQHOSTDISCON BIT( 2)
#define PHYCTRL_ENHOSTDISCONDETECT BIT( 1)
#define PHYCTRL_ENOTG_ID_CHG_IRQ BIT( 0)
struct usb_sct ctrl; /* 0x30 */
uint32_t status; /* 0x40 */
uint32_t res0[3];
struct usb_sct debug; /* 0x50 */
uint32_t debug0_status; /* 0x60 */
uint32_t res1[3];
struct usb_sct debug1; /* 0x70 */
uint32_t version; /* 0x80 */
};
struct usb_otg_regs {
uint32_t id; /* +0x000 */
uint32_t hwgeneral; /* +0x004 */
uint32_t hwhost; /* +0x008 */
uint32_t otg_hwdevice; /* +0x00C */
uint32_t hwtxbuf; /* +0x010 */
uint32_t hwrxbuf; /* +0x014 */
uint32_t res02[26];
uint32_t gptimer0ld; /* +0x080 */
uint32_t gptimer0ctrl; /* +0x084 */
uint32_t gptimer1ld; /* +0x088 */
uint32_t gptimer1ctrl; /* +0x08C */
uint32_t sbuscfg; /* +0x090 */
uint32_t res03[27];
/* capability registers */
uint8_t caplength; /* +0x100 */
uint8_t res05[1];
uint16_t hciversion; /* +0x102 */
uint32_t hcsparams; /* +0x104 */
uint32_t hccparams; /* +0x108 */
uint32_t res06[5];
uint32_t otg_dciversion; /* +0x120 */
uint32_t otg_dccparams; /* +0x124 */
uint32_t res08[6];
/* operational registers */
uint32_t usbcmd; /* +0x140 */
uint32_t usbsts; /* +0x144 */
uint32_t usbintr; /* +0x148 */
uint32_t frindex; /* +0x14C */
uint32_t res09[1];
uint32_t otg_deviceaddr; /* +0x154 */
uint32_t otg_endptlistaddr; /* +0x158 */
uint32_t res10[1];
uint32_t burstsize; /* +0x160 */
uint32_t txfilltuning; /* +0x164 */
uint32_t res11[4];
uint32_t otg_endptnak; /* +0x178 */
uint32_t otg_endptnaken; /* +0x17C */
uint32_t configflag; /* +0x180 */
uint32_t portsc1; /* +0x184 */
uint32_t res13[7];
uint32_t otg_otgsc; /* +0x1A4 */
#define USBMODE_HOST (0x3 << 0)
#define USBMODE_DEV (0x2 << 0)
#define USBMODE_IDLE (0x0 << 0)
uint32_t usbmode; /* +0x1A8 */
uint32_t otg_endptsetupstat; /* +0x1AC */
uint32_t otg_endptprime; /* +0x1B0 */
uint32_t otg_endptflush; /* +0x1B4 */
uint32_t otg_endptstat; /* +0x1B8 */
uint32_t otg_endptcomplete; /* +0x1BC */
uint32_t otg_endptctrl0; /* +0x1C0 */
uint32_t otg_endptctrl1; /* +0x1C4 */
uint32_t otg_endptctrl2; /* +0x1C8 */
uint32_t otg_endptctrl3; /* +0x1CC */
uint32_t otg_endptctrl4; /* +0x1D0 */
uint32_t otg_endptctrl5; /* +0x1D4 */
uint32_t otg_endptctrl6; /* +0x1D8 */
uint32_t otg_endptctrl7; /* +0x1DC */
uint32_t res16[8];
};
struct usb_host_regs {
uint32_t id; /* +0x000 */
uint32_t hwgeneral; /* +0x004 */
uint32_t hwhost; /* +0x008 */
uint32_t res01[1];
uint32_t hwtxbuf; /* +0x010 */
uint32_t hwrxbuf; /* +0x014 */
uint32_t res02[26];
uint32_t gptimer0ld; /* +0x080 */
uint32_t gptimer0ctrl; /* +0x084 */
uint32_t gptimer1ld; /* +0x088 */
uint32_t gptimer1ctrl; /* +0x08C */
uint32_t sbuscfg; /* +0x090 */
uint32_t res03[27];
/* capability registers */
uint8_t caplength; /* +0x100 */
uint8_t res05[1];
uint16_t hciversion; /* +0x102 */
uint32_t hcsparams; /* +0x104 */
uint32_t hccparams; /* +0x108 */
uint32_t res06[5];
uint32_t res07[2];
uint32_t res08[6];
/* operational registers */
uint32_t usbcmd; /* +0x140 */
uint32_t usbsts; /* +0x144 */
uint32_t usbintr; /* +0x148 */
uint32_t frindex; /* +0x14C */
uint32_t res09[1];
uint32_t host_periodiclistbase; /* +0x154 */
uint32_t host_asynclistaddr; /* +0x158 */
uint32_t res10[1];
uint32_t burstsize; /* +0x160 */
uint32_t txfilltuning; /* +0x164 */
uint32_t res11[4];
uint32_t res12[2];
uint32_t configflag; /* +0x180 */
uint32_t portsc1; /* +0x184 */
uint32_t res13[7];
uint32_t res14[1];
uint32_t usbmode; /* +0x1A8 */
uint32_t res15[13];
uint32_t res16[8];
};
struct usb_regs {
/* Core */
struct usb_otg_regs otg; /* +0x000 */
struct usb_host_regs host1; /* +0x200 */
struct usb_host_regs host2; /* +0x400 */
struct usb_host_regs host3; /* +0x600 */
/* Non-core */
#define USBCTRL_WIR BIT(31)
#define USBCTRL_WKUP_VBUS_EN BIT(17)
#define USBCTRL_WKUP_ID_EN BIT(16)
#define USBCTRL_WKUP_SW BIT(15)
#define USBCTRL_WKUP_SW_EN BIT(14)
#define USBCTRL_UTMI_ON_CLOCK BIT(13)
#define USBCTRL_SUSPENDM BIT(12)
#define USBCTRL_RESET BIT(11)
#define USBCTRL_WIE BIT(10)
#define USBCTRL_PWR_POL BIT( 9)
#define USBCTRL_OVER_CUR_POL BIT( 8)
#define USBCTRL_OVER_CUR_DIS BIT( 7)
uint32_t otg_ctrl; /* +0x800 */
uint32_t host1_ctrl; /* +0x804 */
uint32_t host2_ctrl; /* +0x808 */
uint32_t host3_ctrl; /* +0x80C */
uint32_t host2_hsic_ctrl; /* +0x810 */
uint32_t host3_hsic_ctrl; /* +0x814 */
uint32_t otg_phy_ctrl_0; /* +0x818 */
uint32_t host1_phy_ctrl_0; /* +0x81C */
};
static volatile struct usb_phy_regs *_usb_phy1_regs = NULL;
static volatile struct usb_phy_regs *_usb_phy2_regs = NULL;
static volatile struct usb_regs *_usb_regs = NULL;
static const int _usb_irqs[] = {
[USB_OTG0] = USB_OTG_IRQ,
[USB_HOST1] = USB_HOST1_IRQ,
[USB_HOST2] = USB_HOST2_IRQ,
[USB_HOST3] = USB_HOST3_IRQ
};
static void
phy_enable(int devid, ps_io_ops_t* o)
{
volatile struct usb_phy_regs* phy_regs;
clk_t* clk;
clock_sys_init(o, &o->clock_sys);
switch (devid) {
case 0:
clk = clk_get_clock(&o->clock_sys, CLK_USB1);
if (_usb_phy1_regs == NULL) {
_usb_phy1_regs = GET_RESOURCE(o, USB_PHY1);
}
phy_regs = _usb_phy1_regs;
if (!clk || !phy_regs) {
ZF_LOGF("Clock error\n");
}
break;
case 1:
clk = clk_get_clock(&o->clock_sys, CLK_USB2);
if (_usb_phy2_regs == NULL) {
_usb_phy2_regs = GET_RESOURCE(o, USB_PHY2);
}
phy_regs = _usb_phy2_regs;
if (!clk || !phy_regs) {
ZF_LOGF("Clock error\n");
}
break;
default:
phy_regs = NULL;
clk = NULL;
break;
}
if (phy_regs) {
if (clk == NULL) {
ZF_LOGD("Failed to initialise USB PHY clock\n");
}
/* Enable clocks */
phy_regs->ctrl.clr = PHYCTRL_CLKGATE;
/* Reset PHY */
phy_regs->ctrl.set = PHYCTRL_SFTRST;
dsb();
ps_udelay(10);
phy_regs->ctrl.clr = PHYCTRL_SFTRST;
dsb();
ps_udelay(10);
/* Enable PHY and FS/LS */
phy_regs->pwd.val = 0;
phy_regs->ctrl.set = PHYCTRL_ENUTMIL3 | PHYCTRL_ENUTMIL2;
dsb();
ps_mdelay(10);
}
}
static int
imx6_usb_generic_init(int id, ps_io_ops_t* ioops)
{
struct usb_host_regs * hc_regs = NULL;
volatile uint32_t* hc_ctrl;
if (id < 0 || id > USB_NHOSTS) {
ZF_LOGF("Invalid host id\n");
}
/* Check device mappings */
if (_usb_regs == NULL) {
_usb_regs = GET_RESOURCE(ioops, USB);
}
if (_usb_regs == NULL) {
return -1;
}
hc_regs = (struct usb_host_regs*)_usb_regs + id;
hc_ctrl = &_usb_regs->otg_ctrl + id;
/* Reset the EHCI controller */
hc_regs->usbcmd |= EHCICMD_HCRESET;
/* Disable over-current */
*hc_ctrl |= USBCTRL_OVER_CUR_POL;
*hc_ctrl |= USBCTRL_OVER_CUR_DIS;
/* Enable the PHY */
phy_enable(id, ioops);
return 0;
}
int
usb_host_init(enum usb_host_id id, ps_io_ops_t* ioops, ps_mutex_ops_t *sync,
usb_host_t* hdev)
{
struct usb_host_regs * hc_regs = NULL;
int err;
if (id < 0 || id > USB_NHOSTS) {
return -1;
}
if (!ioops || !hdev) {
ZF_LOGF("Invalid arguments\n");
}
hdev->id = id;
hdev->dman = &ioops->dma_manager;
hdev->sync = sync;
err = imx6_usb_generic_init(hdev->id, ioops);
if (err) {
return -1;
}
/* Pass control to EHCI initialisation */
hc_regs = (struct usb_host_regs*)_usb_regs + hdev->id;
hc_regs->usbmode = USBMODE_HOST;
err = ehci_host_init(hdev, (uintptr_t)&hc_regs->caplength, NULL);
/* Configure ports */
hc_regs->portsc1 = IMX6_PORTSC_PTS_UTMI | IMX6_PORTSC_PTW;
return err;
}
const int*
usb_host_irqs(usb_host_t* host, int* nirqs)
{
if (host->id < 0 || host->id > USB_NHOSTS) {
return NULL;
}
if (nirqs) {
*nirqs = 1;
}
host->irqs = &_usb_irqs[host->id];
return host->irqs;
}
int
usb_plat_otg_init(usb_otg_t odev, ps_io_ops_t* ioops)
{
struct usb_otg_regs* otg_regs;
int err;
if (!odev->dman || !odev->id) {
ZF_LOGF("Invalid arguments\n");
}
err = imx6_usb_generic_init(odev->id, ioops);
if (err) {
return -1;
}
otg_regs = (struct usb_otg_regs*)_usb_regs + odev->id;
otg_regs->usbmode = USBMODE_DEV;
err = ehci_otg_init(odev, (uintptr_t)&otg_regs->caplength);
if (otg_regs->usbmode != USBMODE_DEV) {
ZF_LOGF("Set the hardware to device mode\n");
}
return err;
}