nsekar@codeaurora.org has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/29966
Change subject: Coreboot: Add support for USB host mode for mistral platform ......................................................................
Coreboot: Add support for USB host mode for mistral platform
Add required changes for USB host mode working on mistral platform for USB disk enumeration.
Change-Id: I35ec549b49b9789389c80843f6103e7243d52aac Signed-off-by: Nitheesh Sekar nsekar@codeaurora.org Signed-off-by: Vijayavardhan Vennapusa vvreddy@partner-android.googlesource.com Signed-off-by: Sricharan R sricharan@codeaurora.org --- M src/mainboard/google/mistral/mainboard.c M src/mainboard/google/mistral/romstage.c M src/soc/qualcomm/qcs405/Makefile.inc M src/soc/qualcomm/qcs405/include/soc/addressmap.h M src/soc/qualcomm/qcs405/include/soc/clock.h M src/soc/qualcomm/qcs405/include/soc/iomap.h A src/soc/qualcomm/qcs405/include/soc/usb.h A src/soc/qualcomm/qcs405/usb.c 8 files changed, 370 insertions(+), 11 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/66/29966/1
diff --git a/src/mainboard/google/mistral/mainboard.c b/src/mainboard/google/mistral/mainboard.c index c249a32..7201874 100644 --- a/src/mainboard/google/mistral/mainboard.c +++ b/src/mainboard/google/mistral/mainboard.c @@ -16,10 +16,34 @@ #include <device/device.h> #include <bootblock_common.h> #include <timestamp.h> +#include <soc/usb.h> + +static struct usb_board_data usb0_board_data = { + .parameter_override_x0 = 0x63, + .parameter_override_x1 = 0x03, + .parameter_override_x0 = 0x1d, + .parameter_override_x1 = 0x03, +}; + +static struct usb_board_data usb1_board_data = { + .parameter_override_x0 = 0x63, + .parameter_override_x1 = 0x03, + .parameter_override_x0 = 0x1d, + .parameter_override_x1 = 0x03, +}; + +static void setup_usb(void) +{ + /* Setting Primarty usb controller */ + setup_usb_host(HSUSB_SS_PORT_0, &usb0_board_data); + + /* Setting secondary usb controller */ + setup_usb_host(HSUSB_HS_PORT_1, &usb1_board_data); +}
static void mainboard_init(device_t dev) { - + setup_usb(); }
static void mainboard_enable(device_t dev) diff --git a/src/mainboard/google/mistral/romstage.c b/src/mainboard/google/mistral/romstage.c index 71968fc..31e5113 100644 --- a/src/mainboard/google/mistral/romstage.c +++ b/src/mainboard/google/mistral/romstage.c @@ -20,12 +20,19 @@ #include <console/console.h> #include <timestamp.h> #include <arch/stages.h> +#include <soc/usb.h>
#ifdef CONFIG_QC_SOC_SIMULATE extern void qcs405_mmu_dram_config_c(void); #endif void platform_romstage_main(void) { + /* + * Do DWC3 core and phy reset. Kick these resets off early + * so they get atleast 1msec to settle. + */ + reset_usb(HSUSB_SS_PORT_0); + reset_usb(HSUSB_HS_PORT_1); #ifdef CONFIG_QC_SOC_SIMULATE qcs405_mmu_dram_config_c(); #endif diff --git a/src/soc/qualcomm/qcs405/Makefile.inc b/src/soc/qualcomm/qcs405/Makefile.inc index 57d59f8..c174cae 100644 --- a/src/soc/qualcomm/qcs405/Makefile.inc +++ b/src/soc/qualcomm/qcs405/Makefile.inc @@ -27,6 +27,7 @@ romstage-y += mmu.c romstage-$(CONFIG_DRIVERS_UART) += uart.c romstage-$(CONFIG_QC_SOC_SIMULATE) += flash_controller.c +romstage-y += usb.c
################################################################################ ramstage-y += soc.c @@ -37,6 +38,7 @@ ramstage-y += clock.c ramstage-$(CONFIG_DRIVERS_UART) += uart.c ramstage-$(CONFIG_QC_SOC_SIMULATE) += flash_controller.c +ramstage-y += usb.c
################################################################################
diff --git a/src/soc/qualcomm/qcs405/include/soc/addressmap.h b/src/soc/qualcomm/qcs405/include/soc/addressmap.h index 435b680..696bc42 100644 --- a/src/soc/qualcomm/qcs405/include/soc/addressmap.h +++ b/src/soc/qualcomm/qcs405/include/soc/addressmap.h @@ -23,4 +23,12 @@ #define TLMM_NORTH_TILE_BASE 0x1300000 #define TLMM_SOUTH_TILE_BASE 0x1000000
+/* USB BASE ADDRESS */ +#define USB_HOST0_DWC3_BASE 0x758C100 +#define USB3_USB30_QSCRATCH_BASE 0x7678800 +#define USB2_FEMTO_PHY_PRI_BASE 0x007A000 + +#define USB_HOST1_DWC3_BASE 0x78CC100 +#define USB2_USB30_QSCRATCH_BASE 0x79B8800 +#define USB2_FEMTO_PHY_SEC_BASE 0x007C000 #endif /* __SOC_QUALCOMM_QCS405_ADDRESS_MAP_H__ */ diff --git a/src/soc/qualcomm/qcs405/include/soc/clock.h b/src/soc/qualcomm/qcs405/include/soc/clock.h index aa8bbe5..d02ecd7 100644 --- a/src/soc/qualcomm/qcs405/include/soc/clock.h +++ b/src/soc/qualcomm/qcs405/include/soc/clock.h @@ -65,10 +65,10 @@ /** * USB BCR registers */ -#define GCC_USB_HS_PHY_CFG_AHB_BCR 0x1841038 +#define GCC_USB_HS_PHY_CFG_AHB_BCR 0x180000C #define GCC_USB_HS_BCR 0x1841000 #define GCC_USB_30_BCR 0x1839000 -#define GCC_USB2A_PHY_BCR 0x1841028 +#define GCC_USB2A_PHY_BCR 0x180000C #define GCC_USB2_HS_PHY_ONLY_BCR 0x1841034 #define GCC_QUSB2_PHY_BCR 0x184103C
diff --git a/src/soc/qualcomm/qcs405/include/soc/iomap.h b/src/soc/qualcomm/qcs405/include/soc/iomap.h index 2a7a148..571c62f 100644 --- a/src/soc/qualcomm/qcs405/include/soc/iomap.h +++ b/src/soc/qualcomm/qcs405/include/soc/iomap.h @@ -99,14 +99,6 @@ #define GPIO_CONFIG_ADDR(x) (TLMM_BASE_ADDR + 0x1000 * (x)) #define GPIO_IN_OUT_ADDR(x) (GPIO_CONFIG_ADDR(x) + 4)
-/* Yes, this is not a typo... host2 is actually mapped before host1. */ -#define USB_HOST2_XHCI_BASE 0x10000000 -#define USB_HOST2_DWC3_BASE 0x1000C100 -#define USB_HOST2_PHY_BASE 0x100F8800 -#define USB_HOST1_XHCI_BASE 0x11000000 -#define USB_HOST1_DWC3_BASE 0x1100C100 -#define USB_HOST1_PHY_BASE 0x110F8800 - #define UART1_DM_BASE ((void *)0x078af000) #define UART2_DM_BASE ((void *)0x078B1000)
diff --git a/src/soc/qualcomm/qcs405/include/soc/usb.h b/src/soc/qualcomm/qcs405/include/soc/usb.h new file mode 100644 index 0000000..80674bb --- /dev/null +++ b/src/soc/qualcomm/qcs405/include/soc/usb.h @@ -0,0 +1,76 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (c) 2018 Qualcomm Technologies + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <types.h> + +#ifndef _QCS405_USB_H_ +#define _QCS405_USB_H_ + +/* QSCRATCH_GENERAL_CFG register bit offset */ +#define PIPE_UTMI_CLK_SEL BIT(0) +#define PIPE3_PHYSTATUS_SW BIT(3) +#define PIPE_UTMI_CLK_DIS BIT(8) + +/* Global USB3 Control Registers */ +#define DWC3_GUSB3PIPECTL_DELAYP1TRANS BIT(18) +#define DWC3_GUSB3PIPECTL_UX_EXIT_IN_PX BIT(27) +#define DWC3_GCTL_PRTCAPDIR(n) ((n) << 12) +#define DWC3_GCTL_PRTCAP_OTG 3 +#define DWC3_GCTL_PRTCAP_HOST 1 + +/* Global USB2 PHY Configuration Register */ +#define DWC3_GUSB2PHYCFG_USBTRDTIM(n) ((n) << 10) +#define DWC3_GUSB2PHYCFG_USB2TRDTIM_MASK DWC3_GUSB2PHYCFG_USBTRDTIM(0xf) +#define DWC3_GUSB2PHYCFG_PHYIF(n) ((n) << 3) +#define DWC3_GUSB2PHYCFG_PHYIF_MASK DWC3_GUSB2PHYCFG_PHYIF(1) +#define USBTRDTIM_UTMI_8_BIT 9 +#define UTMI_PHYIF_8_BIT 0 + +#define DWC3_GCTL_SCALEDOWN(n) ((n) << 4) +#define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3) +#define DWC3_GCTL_DISSCRAMBLE (1 << 3) +#define DWC3_GCTL_U2EXIT_LFPS (1 << 2) +#define DWC3_GCTL_DSBLCLKGTNG (1 << 0) + +/* USB2 PHY register values */ +#define USB2PHY_TCSR_CTRL 0x01 +#define USB2PHY_REFCLK_CTRL 0x0d +#define USB2PHY_UTMI_CTRL5 0x12 +#define USB2PHY_PARAMETER_OVERRIDE_X0 0x63 +#define USB2PHY_PARAMETER_OVERRIDE_X1 0x03 +#define USB2PHY_PARAMETER_OVERRIDE_X2 0x1d +#define USB2PHY_PARAMETER_OVERRIDE_X3 0x03 +#define USB2PHY_HS_PHY_CTRL1 0x23 +#define QUSB2PHY_HS_PHY_CTRL_COMMON0 0x08 +#define QUSB2PHY_HS_PHY_CTRL_COMMON1 0xdc +#define USB2PHY_HS_PHY_CTRL2 0xe0 + +struct usb_board_data { + /* Register values going to override from the boardfile */ + u8 parameter_override_x0; + u8 parameter_override_x1; + u8 parameter_override_x2; + u8 parameter_override_x3; +}; + +enum usb_port { + HSUSB_SS_PORT_0, + HSUSB_HS_PORT_1, +}; + +void setup_usb_host(enum usb_port port, struct usb_board_data *data); +/* Call reset_ before setup_ */ +void reset_usb(enum usb_port port); + +#endif /* _QCS405_USB_H_ */ diff --git a/src/soc/qualcomm/qcs405/usb.c b/src/soc/qualcomm/qcs405/usb.c new file mode 100644 index 0000000..67574cf --- /dev/null +++ b/src/soc/qualcomm/qcs405/usb.c @@ -0,0 +1,250 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (c) 2018 Qualcomm Technologies + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <arch/io.h> +#include <lib.h> +#include <stdlib.h> +#include <console/console.h> +#include <delay.h> +#include <soc/usb.h> +#include <soc/clock.h> +#include <soc/addressmap.h> +#include <timer.h> + +struct usb_qscratch { + u8 rsvd0[8]; + u32 *qscratch_cfg_reg; + +}; +check_member(usb_qscratch, qscratch_cfg_reg, 0x08); + +struct usb_usb2_phy_dig { + u8 rsvd1[116]; + u32 utmi_ctrl5; + u32 ctrl_common0; + u32 ctrl_common1; + u8 rsvd2[12]; + u32 phy_ctrl1; + u32 phy_ctrl2; + u8 rsvd3; + u32 override_x0; + u32 override_x1; + u32 override_x2; + u32 override_x3; + u8 rsvd4[24]; + u32 tcsr_ctrl; + u8 rsvd5[36]; + u32 refclk_ctrl; +}; +check_member(usb_usb2_phy_dig, utmi_ctrl5, 0x74); +check_member(usb_usb2_phy_dig, phy_ctrl1, 0x8C); +check_member(usb_usb2_phy_dig, override_x0, 0x98); +check_member(usb_usb2_phy_dig, tcsr_ctrl, 0xC0); +check_member(usb_usb2_phy_dig, refclk_ctrl, 0xE8); + +struct usb_dwc3 { + u32 sbuscfg0; + u32 sbuscfg1; + u32 txthrcfg; + u32 rxthrcfg; + u32 ctl; + u32 pmsts; + u32 sts; + u32 uctl1; + u32 snpsid; + u32 gpio; + u32 uid; + u32 uctl; + u64 buserraddr; + u64 prtbimap; + u8 reserved1[32]; + u32 dbgfifospace; + u32 dbgltssm; + u32 dbglnmcc; + u32 dbgbmu; + u32 dbglspmux; + u32 dbglsp; + u32 dbgepinfo0; + u32 dbgepinfo1; + u64 prtbimap_hs; + u64 prtbimap_fs; + u8 reserved2[112]; + u32 usb2phycfg; + u8 reserved3[60]; + u32 usb2i2cctl; + u8 reserved4[60]; + u32 usb2phyacc; + u8 reserved5[60]; + u32 usb3pipectl; + u8 reserved6[60]; +}; +check_member(usb_dwc3, usb3pipectl, 0x1c0); + +struct usb_dwc3_cfg { + struct usb_dwc3 *usb_host_dwc3; + struct usb_usb2_phy_dig *usb2_phy_dig; + struct usb_qscratch *usb_qscratch_reg; + u32 *usb2_phy_bcr; + u32 *usb2_phy_por_bcr; + u32 *usb3_bcr; + struct usb_board_data *board_data; +}; + +static struct usb_dwc3_cfg usb_host_base[2] = { + [HSUSB_SS_PORT_0] = { + .usb_host_dwc3 = (void *)USB_HOST0_DWC3_BASE, + .usb2_phy_dig = (void *)USB2_FEMTO_PHY_PRI_BASE, + .usb2_phy_bcr = (void *)GCC_USB_HS_PHY_CFG_AHB_BCR, + .usb2_phy_por_bcr = (void *)GCC_USB2A_PHY_BCR, + .usb3_bcr = (void *)GCC_USB_30_BCR, + .usb_qscratch_reg = (void *)USB3_USB30_QSCRATCH_BASE, + }, + [HSUSB_HS_PORT_1] = { + .usb_host_dwc3 = (void *)USB_HOST1_DWC3_BASE, + .usb2_phy_dig = (void *)USB2_FEMTO_PHY_SEC_BASE, + .usb2_phy_bcr = (void *)GCC_QUSB2_PHY_BCR, + .usb2_phy_por_bcr = (void *)GCC_USB2_HS_PHY_ONLY_BCR, + .usb3_bcr = (void *)GCC_USB_HS_BCR, + .usb_qscratch_reg = (void *)USB2_USB30_QSCRATCH_BASE, + }, +}; + +void reset_usb(enum usb_port port) +{ + struct usb_dwc3_cfg *dwc3 = &usb_host_base[port]; + + /* Put Core in Reset */ + printk(BIOS_INFO, "Starting DWC3 reset for USB%d\n", port); + + /* Assert Core reset */ + clock_reset_bcr(dwc3->usb3_bcr, 1); +} + +static void usb2_phy_override_phy_params(struct usb_dwc3_cfg *dwc3) +{ + write8(&dwc3->usb2_phy_dig->override_x0, dwc3->board_data->parameter_override_x0); + write8(&dwc3->usb2_phy_dig->override_x1, dwc3->board_data->parameter_override_x1); + write8(&dwc3->usb2_phy_dig->override_x2, dwc3->board_data->parameter_override_x2); + write8(&dwc3->usb2_phy_dig->override_x3, dwc3->board_data->parameter_override_x3); +} + +static void hs_usb_phy_init(struct usb_dwc3_cfg *dwc3) +{ + write8(&dwc3->usb2_phy_dig->tcsr_ctrl, USB2PHY_TCSR_CTRL); + write8(&dwc3->usb2_phy_dig->refclk_ctrl, USB2PHY_REFCLK_CTRL); + write8(&dwc3->usb2_phy_dig->utmi_ctrl5, USB2PHY_UTMI_CTRL5); + write8(&dwc3->usb2_phy_dig->override_x0, USB2PHY_PARAMETER_OVERRIDE_X0); + write8(&dwc3->usb2_phy_dig->override_x1, USB2PHY_PARAMETER_OVERRIDE_X1); + write8(&dwc3->usb2_phy_dig->override_x2, USB2PHY_PARAMETER_OVERRIDE_X2); + write8(&dwc3->usb2_phy_dig->override_x3, USB2PHY_PARAMETER_OVERRIDE_X3); + + if (dwc3->board_data) + /* Overridw board specific PHY tuning values */ + usb2_phy_override_phy_params(dwc3); + + write8(&dwc3->usb2_phy_dig->phy_ctrl1, USB2PHY_HS_PHY_CTRL1); + write8(&dwc3->usb2_phy_dig->ctrl_common0, QUSB2PHY_HS_PHY_CTRL_COMMON0); + write8(&dwc3->usb2_phy_dig->ctrl_common1, QUSB2PHY_HS_PHY_CTRL_COMMON1); + write8(&dwc3->usb2_phy_dig->phy_ctrl2, USB2PHY_HS_PHY_CTRL2); + udelay(20); + write8(&dwc3->usb2_phy_dig->utmi_ctrl5, 0x10); + write8(&dwc3->usb2_phy_dig->phy_ctrl2, 0x60); +} + +static void setup_dwc3(struct usb_dwc3 *dwc3) +{ + /* core exits U1/U2/U3 only in PHY power state P1/P2/P3 respectively */ + clrsetbits_le32(&dwc3->usb3pipectl, + DWC3_GUSB3PIPECTL_DELAYP1TRANS, + DWC3_GUSB3PIPECTL_UX_EXIT_IN_PX); + + clrsetbits_le32(&dwc3->ctl, (DWC3_GCTL_SCALEDOWN_MASK | + DWC3_GCTL_DISSCRAMBLE), + DWC3_GCTL_U2EXIT_LFPS | DWC3_GCTL_DSBLCLKGTNG); + + /* configure controller in Host mode */ + clrsetbits_le32(&dwc3->ctl, (DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)), + DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_HOST)); + printk(BIOS_INFO, "Configure USB in Host mode\n"); +} + +/* Initialization of DWC3 Core and PHY */ +void setup_usb_host(enum usb_port port, struct usb_board_data *board_data) +{ + struct usb_dwc3_cfg *dwc3 = &usb_host_base[port]; + u32 val; + + printk(BIOS_INFO, "Setting up USB HOST%d controller.\n", port); + + dwc3->board_data = board_data; + + /* Clear core reset. */ + clock_reset_bcr(dwc3->usb3_bcr, 0); + + + if (port == HSUSB_SS_PORT_0) { + /* Set PHY reset. */ + setbits_le32(&dwc3->usb2_phy_bcr, BIT(1)); + udelay(15); + /* Clear PHY reset. */ + clrbits_le32(&dwc3->usb2_phy_bcr, BIT(1)); + } else { + clock_reset_bcr(dwc3->usb2_phy_bcr, 1); + udelay(15); + clock_reset_bcr(dwc3->usb2_phy_bcr, 0); + } + udelay(100); + + /* Initialize PHYs */ + hs_usb_phy_init(dwc3); + + if (port == HSUSB_SS_PORT_0) { + /* Set PHY POR reset. */ + setbits_le32(&dwc3->usb2_phy_por_bcr, BIT(0)); + val = read8(&dwc3->usb2_phy_dig->ctrl_common0); + val &= ~(0x4); + write8(&dwc3->usb2_phy_dig->ctrl_common0, val); + udelay(20); + /* Clear PHY POR reset. */ + clrbits_le32(&dwc3->usb2_phy_por_bcr, BIT(0)); + } else { + clock_reset_bcr(dwc3->usb2_phy_por_bcr, 1); + val = read8(&dwc3->usb2_phy_dig->ctrl_common0); + val &= ~(0x4); + write8(&dwc3->usb2_phy_dig->ctrl_common0, val); + udelay(20); + clock_reset_bcr(dwc3->usb2_phy_por_bcr, 0); + } + udelay(100); + + setup_dwc3(dwc3->usb_host_dwc3); + + /* + * Below sequence is used when dwc3 operates without + * SSPHY and only HS/FS/LS modes are supported. + */ + + /* Configure dwc3 to use UTMI clock as PIPE clock not present */ + setbits_le32(&dwc3->usb_qscratch_reg->qscratch_cfg_reg, + PIPE_UTMI_CLK_DIS); + udelay(2); + setbits_le32(&dwc3->usb_qscratch_reg->qscratch_cfg_reg, + PIPE_UTMI_CLK_SEL | PIPE3_PHYSTATUS_SW); + udelay(3); + clrbits_le32(&dwc3->usb_qscratch_reg->qscratch_cfg_reg, + PIPE_UTMI_CLK_DIS); + + printk(BIOS_INFO, "DWC3 and PHY setup finished\n"); +}