From 68aef1169239cc5d33fb36f05cd32d7e062b7743 Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Tue, 3 Sep 2013 15:07:31 -0700 Subject: exynos5: Implement support for USB 3.0 DRD PHYs/controllers This patch adds support for the DesignWare3 USB 3.0 DRD controller and PHY to the Exynos5250 and Exynos5420 CPUs. It also adds code to the Google Snow and Pit boards to turn these controllers on where applicable. Change-Id: Idcca627363a69f1d65402e1acb9a62b439f077ff Signed-off-by: Julius Werner Reviewed-on: https://chromium-review.googlesource.com/169452 Reviewed-by: Stefan Reinauer (cherry picked from commit e9809ae12ef8b8bd6cd61d3f604cb9e4718cf7eb) Signed-off-by: Isaac Christensen Reviewed-on: http://review.coreboot.org/6642 Tested-by: build bot (Jenkins) Reviewed-by: Ronald G. Minnich --- src/cpu/samsung/exynos5250/cpu.h | 1 + src/cpu/samsung/exynos5250/power.h | 5 +- src/cpu/samsung/exynos5250/usb.c | 110 ++++++++++++++++++++++++++++++++++++- src/cpu/samsung/exynos5250/usb.h | 77 ++++++++++++++++++++++++-- 4 files changed, 185 insertions(+), 8 deletions(-) (limited to 'src/cpu/samsung/exynos5250') diff --git a/src/cpu/samsung/exynos5250/cpu.h b/src/cpu/samsung/exynos5250/cpu.h index 12745d3d85..85b6fae464 100644 --- a/src/cpu/samsung/exynos5250/cpu.h +++ b/src/cpu/samsung/exynos5250/cpu.h @@ -41,6 +41,7 @@ #define EXYNOS5_GPIO_PART2_BASE 0x11400c00 /* X00..X37 */ #define EXYNOS5_USB_DRD_XHCI_BASE 0x12000000 #define EXYNOS5_USB_DRD_PHY_BASE 0x12100000 +#define EXYNOS5_USB_DRD_DWC3_BASE 0x1200C100 #define EXYNOS5_USB_HOST_EHCI_BASE 0x12110000 #define EXYNOS5_USB_HOST_PHY_BASE 0x12130000 #define EXYNOS5_MMC_BASE 0x12200000 diff --git a/src/cpu/samsung/exynos5250/power.h b/src/cpu/samsung/exynos5250/power.h index 293fe3b704..df68b53dbd 100644 --- a/src/cpu/samsung/exynos5250/power.h +++ b/src/cpu/samsung/exynos5250/power.h @@ -30,7 +30,7 @@ void power_enable_hw_thermal_trip(void); #define MIPI_PHY1_CONTROL_ENABLE (1 << 0) #define MIPI_PHY1_CONTROL_M_RESETN (1 << 2) -#define POWER_USB_HOST_PHY_CTRL_EN (1 << 0) +#define POWER_USB_PHY_CTRL_EN (1 << 0) #define POWER_PS_HOLD_CONTROL_DATA_HIGH (1 << 8) #define POWER_ENABLE_HW_TRIP (1UL << 31) @@ -47,7 +47,8 @@ struct exynos5_power { uint32_t om_stat; /* 0x0000 */ uint8_t reserved1[0x03fc]; uint32_t sw_reset; /* 0x0400 */ - uint8_t reserved2[0x0304]; + uint8_t reserved2[0x0300]; + uint32_t usb_drd_phy_ctrl; /* 0x0704 */ uint32_t usb_host_phy_ctrl; /* 0x0708 */ uint8_t reserved3[0x8]; uint32_t mipi_phy1_control; /* 0x0714 */ diff --git a/src/cpu/samsung/exynos5250/usb.c b/src/cpu/samsung/exynos5250/usb.c index 521ea4da5a..76da1dd56e 100644 --- a/src/cpu/samsung/exynos5250/usb.c +++ b/src/cpu/samsung/exynos5250/usb.c @@ -27,13 +27,119 @@ #include "sysreg.h" #include "usb.h" +static void reset_dwc3(struct exynos5_usb_drd_dwc3 *dwc3) +{ + setbits_le32(&dwc3->ctl, 0x1 << 11); /* core soft reset */ + setbits_le32(&dwc3->usb3pipectl, 0x1 << 31); /* PHY soft reset */ + setbits_le32(&dwc3->usb2phycfg, 0x1 << 31); /* PHY soft reset */ +} + +void reset_usb_drd_dwc3() +{ + printk(BIOS_DEBUG, "Starting DWC3 reset for USB DRD\n"); + reset_dwc3(exynos_usb_drd_dwc3); +} + +static void setup_dwc3(struct exynos5_usb_drd_dwc3 *dwc3) +{ + if (!(dwc3->ctl & 0x1 << 11) || + !(dwc3->usb3pipectl & 0x1 << 31) || + !(dwc3->usb2phycfg & 0x1 << 31)) { + printk(BIOS_ERR, "DWC3 at %p not in reset (you need to call " + "reset_usb_drd_dwc3() first)!\n", dwc3); + } + + /* Set relevant registers to default values (clearing all reset bits) */ + + writel(0x1 << 24 | /* activate PHY low power states */ + 0x4 << 19 | /* low power delay value */ + 0x1 << 18 | /* activate PHY low power delay */ + 0x1 << 17 | /* enable SuperSpeed PHY suspend */ + 0x1 << 1 | /* default Tx deemphasis value */ + 0, &dwc3->usb3pipectl); + + /* Configure PHY clock turnaround for 8-bit UTMI+, disable suspend */ + writel(0x9 << 10 | /* PHY clock turnaround for 8-bit UTMI+ */ + 0x1 << 8 | /* enable PHY sleep in L1 */ + 0x1 << 6 | /* enable PHY suspend */ + 0, &dwc3->usb2phycfg); + + writel(0x5dc << 19 | /* suspend clock scale for 24MHz */ + 0x1 << 16 | /* retry SS three times (bugfix from U-Boot) */ + 0x1 << 12 | /* port capability HOST */ + 0, &dwc3->ctl); +} + +void setup_usb_drd_dwc3() +{ + setup_dwc3(exynos_usb_drd_dwc3); + printk(BIOS_DEBUG, "DWC3 setup for USB DRD finished\n"); +} + +static void setup_drd_phy(struct exynos5_usb_drd_phy *phy) +{ + /* Set all PHY registers to default values */ + + /* XHCI Version 1.0, Frame Length adjustment 30 MHz */ + setbits_le32(&phy->linksystem, 0x1 << 27 | 0x20 << 1); + + /* Disable OTG, ID0 and DRVVBUS, do not force sleep/suspend */ + writel(1 << 6, &phy->utmi); + + writel(0x88 << 23 | /* spread spectrum refclk selector */ + 0x1 << 20 | /* enable spread spectrum */ + 0x1 << 19 | /* enable prescaler refclk */ + 0x68 << 11 | /* multiplier for 24MHz refclk */ + 0x5 << 5 | /* select 24MHz refclk (weird, from U-Boot) */ + 0x1 << 4 | /* power supply in normal operating mode */ + 0x3 << 2 | /* use external refclk (undocumented on 5420?)*/ + 0x1 << 1 | /* force port reset */ + 0x1 << 0 | /* normal operating mode */ + 0, &phy->clkrst); + + writel(0x9 << 26 | /* LOS level */ + 0x3 << 22 | /* TX VREF tune */ + 0x1 << 20 | /* TX rise tune */ + 0x1 << 18 | /* TX res tune */ + 0x3 << 13 | /* TX HS X Vtune */ + 0x3 << 9 | /* TX FS/LS tune */ + 0x3 << 6 | /* SQRX tune */ + 0x4 << 3 | /* OTG tune */ + 0x4 << 0 | /* comp disc tune */ + 0, &phy->param0); + + writel(0x7f << 19 | /* reserved */ + 0x7f << 12 | /* Tx launch amplitude */ + 0x20 << 6 | /* Tx deemphasis 6dB */ + 0x1c << 0 | /* Tx deemphasis 3.5dB (value from U-Boot) */ + 0, &phy->param1); + + /* disable all test features */ + writel(0, &phy->test); + + /* UTMI clock select? ("must be 0x1") */ + writel(0x1 << 2, &phy->utmiclksel); + + /* Samsung magic, undocumented (from U-Boot) */ + writel(0x0, &phy->resume); + + udelay(10); + clrbits_le32(&phy->clkrst, 0x1 << 1); /* deassert port reset */ +} + +void setup_usb_drd_phy() +{ + printk(BIOS_DEBUG, "Powering up USB DRD PHY\n"); + setbits_le32(&exynos_power->usb_drd_phy_ctrl, POWER_USB_PHY_CTRL_EN); + setup_drd_phy(exynos_usb_drd_phy); +} + void setup_usb_host_phy(int hsic_gpio) { unsigned int hostphy_ctrl0; setbits_le32(&exynos_sysreg->usb20_phy_cfg, USB20_PHY_CFG_EN); - setbits_le32(&exynos_power->usb_host_phy_ctrl, - POWER_USB_HOST_PHY_CTRL_EN); + setbits_le32(&exynos_power->usb_host_phy_ctrl, POWER_USB_PHY_CTRL_EN); printk(BIOS_DEBUG, "Powering up USB HOST PHY (%s HSIC)\n", hsic_gpio ? "with" : "without"); diff --git a/src/cpu/samsung/exynos5250/usb.h b/src/cpu/samsung/exynos5250/usb.h index c951c1fbbb..ad617da96c 100644 --- a/src/cpu/samsung/exynos5250/usb.h +++ b/src/cpu/samsung/exynos5250/usb.h @@ -45,24 +45,93 @@ struct exynos5_usb_host_phy { uint32_t usbphyctrl0; uint32_t usbphytune0; - uint32_t reserved1[2]; + uint8_t reserved1[8]; uint32_t hsicphyctrl1; uint32_t hsicphytune1; - uint32_t reserved2[2]; + uint8_t reserved2[8]; uint32_t hsicphyctrl2; uint32_t hsicphytune2; - uint32_t reserved3[2]; + uint8_t reserved3[8]; uint32_t ehcictrl; uint32_t ohcictrl; uint32_t usbotgsys; - uint32_t reserved4; + uint8_t reserved4[4]; uint32_t usbotgtune; }; static struct exynos5_usb_host_phy * const exynos_usb_host_phy = (void *)EXYNOS5_USB_HOST_PHY_BASE; +struct exynos5_usb_drd_phy { + uint8_t reserved1[4]; + uint32_t linksystem; + uint32_t utmi; + uint32_t pipe; + uint32_t clkrst; + uint32_t reg0; + uint32_t reg1; + uint32_t param0; + uint32_t param1; + uint32_t term; + uint32_t test; + uint32_t adp; + uint32_t utmiclksel; + uint32_t resume; + uint8_t reserved2[8]; + uint32_t linkhcbelt; + uint32_t linkport; +}; + +static struct exynos5_usb_drd_phy * const exynos_usb_drd_phy = + (void *)EXYNOS5_USB_DRD_PHY_BASE; + +struct exynos5_usb_drd_dwc3 { + uint32_t sbuscfg0; + uint32_t sbuscfg1; + uint32_t txthrcfg; + uint32_t rxthrcfg; + uint32_t ctl; + uint32_t evten; + uint32_t sts; + uint8_t reserved0[4]; + uint32_t snpsid; + uint32_t gpio; + uint32_t uid; + uint32_t uctl; + uint64_t buserraddr; + uint64_t prtbimap; + uint8_t reserved1[32]; + uint32_t dbgfifospace; + uint32_t dbgltssm; + uint32_t dbglnmcc; + uint32_t dbgbmu; + uint32_t dbglspmux; + uint32_t dbglsp; + uint32_t dbgepinfo0; + uint32_t dbgepinfo1; + uint64_t prtbimap_hs; + uint64_t prtbimap_fs; + uint8_t reserved2[112]; + uint32_t usb2phycfg; + uint8_t reserved3[60]; + uint32_t usb2i2cctl; + uint8_t reserved4[60]; + uint32_t usb2phyacc; + uint8_t reserved5[60]; + uint32_t usb3pipectl; + uint8_t reserved6[60]; +}; + +static struct exynos5_usb_drd_dwc3 * const exynos_usb_drd_dwc3 = + (void *)EXYNOS5_USB_DRD_DWC3_BASE; + /* Leave hsic_gpio at 0 to not enable HSIC. */ void setup_usb_host_phy(int hsic_gpio); +void setup_usb_drd_phy(void); + +/* Call reset_ before setup_, ensure at least 100ms pass in between. */ +void reset_usb_drd_dwc3(void); +void setup_usb_drd_dwc3(void); + #endif -- cgit v1.2.3