[coreboot-gerrit] New patch to review for coreboot: a754046 ipq806x: Add USB support

Marc Jones (marc.jones@se-eng.com) gerrit at coreboot.org
Sat Jan 3 20:43:08 CET 2015


Marc Jones (marc.jones at se-eng.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/8056

-gerrit

commit a7540460aa904fbdf0a368c2b63044bed060e100
Author: Julius Werner <jwerner at chromium.org>
Date:   Fri May 30 18:01:44 2014 -0700

    ipq806x: Add USB support
    
    This patch adds code to initialize the two DWC3 USB host controllers and
    their associated PHYs to the IPQ806x SoC (closely imitating the existing
    DWC3 implementation for Exynos5), and uses them to initialize USB on the
    Storm mainboard.
    
    BUG=chrome-os-partner:29375
    TEST=Hack up netboot to get around missing SPI flash, load a file over
    TFTP. Hack a storage read into the storage attach function, dump the
    data and confirm that it looks right. Enable USB debugging and confirm
    3.0 devices get enumerated at SuperSpeed (mostly).
    
    Original-Change-Id: Iaf7b96bef994081ca222b7de9d8e8c49751d3f1d
    Original-Signed-off-by: Julius Werner <jwerner at chromium.org>
    Original-Reviewed-on: https://chromium-review.googlesource.com/202157
    Original-Reviewed-by: David Hendricks <dhendrix at chromium.org>
    Original-Reviewed-by: Vadim Bendebury <vbendeb at chromium.org>
    (cherry picked from commit 6349e7281d5accb1247acb0537a48fa3a5e1bf97)
    Signed-off-by: Marc Jones <marc.jones at se-eng.com>
    
    Change-Id: I749d265d45c6a807a7559bd4df2490a6eb8067af
---
 src/mainboard/google/storm/Kconfig       |   8 ++
 src/mainboard/google/storm/mainboard.c   |  33 ++++-
 src/soc/qualcomm/ipq806x/Makefile.inc    |   1 +
 src/soc/qualcomm/ipq806x/clock.c         |  26 ++++
 src/soc/qualcomm/ipq806x/include/clock.h |  11 ++
 src/soc/qualcomm/ipq806x/include/iomap.h |   8 ++
 src/soc/qualcomm/ipq806x/include/usb.h   |  26 ++++
 src/soc/qualcomm/ipq806x/usb.c           | 227 +++++++++++++++++++++++++++++++
 8 files changed, 333 insertions(+), 7 deletions(-)

diff --git a/src/mainboard/google/storm/Kconfig b/src/mainboard/google/storm/Kconfig
index 4c90c4e..1063f83 100644
--- a/src/mainboard/google/storm/Kconfig
+++ b/src/mainboard/google/storm/Kconfig
@@ -40,4 +40,12 @@ config DRAM_SIZE_MB
 	int
 	default 512
 
+config DRAM_DMA_START
+	hex
+	default 0x5a000000
+
+config DRAM_DMA_SIZE
+	hex
+	default 0x00200000
+
 endif # BOARD_GOOGLE_STORM
diff --git a/src/mainboard/google/storm/mainboard.c b/src/mainboard/google/storm/mainboard.c
index 1e622f4..301e645 100644
--- a/src/mainboard/google/storm/mainboard.c
+++ b/src/mainboard/google/storm/mainboard.c
@@ -20,17 +20,25 @@
 #include <arch/cache.h>
 #include <boot/coreboot_tables.h>
 #include <device/device.h>
-
-#define TO_MB(x)             ((x)>>20)
+#include <soc/qualcomm/ipq806x/include/clock.h>
+#include <soc/qualcomm/ipq806x/include/usb.h>
 
 /* convenient shorthand (in MB) */
-#define DRAM_START           TO_MB(CONFIG_SYS_SDRAM_BASE)
+#define DRAM_START           (CONFIG_SYS_SDRAM_BASE / MiB)
 #define DRAM_SIZE            (CONFIG_DRAM_SIZE_MB)
 #define DRAM_END             (DRAM_START + DRAM_SIZE)
 
 /* DMA memory for drivers */
-#define DMA_START            TO_MB(CONFIG_DRAM_DMA_START)
-#define DMA_SIZE             TO_MB(CONFIG_DRAM_DMA_SIZE)
+#define DMA_START            (CONFIG_DRAM_DMA_START / MiB)
+#define DMA_SIZE             (CONFIG_DRAM_DMA_SIZE / MiB)
+
+static void setup_usb(void)
+{
+	usb_clock_config();
+
+	setup_usb_host1();
+	setup_usb_host2();
+}
 
 static void setup_mmu(void)
 {
@@ -43,8 +51,7 @@ static void setup_mmu(void)
 	/* Map DRAM memory */
 	mmu_config_range(DRAM_START, DRAM_SIZE, DCACHE_WRITEBACK);
 	/* Map DMA memory */
-	if (DMA_SIZE)
-		mmu_config_range(DMA_START, DMA_SIZE, DCACHE_OFF);
+	mmu_config_range(DMA_START, DMA_SIZE, DCACHE_OFF);
 
 	mmu_disable_range(DRAM_END, 4096 - DRAM_END);
 
@@ -56,6 +63,7 @@ static void setup_mmu(void)
 static void mainboard_init(device_t dev)
 {
 	 setup_mmu();
+	 setup_usb();
 }
 
 static void mainboard_enable(device_t dev)
@@ -67,3 +75,14 @@ struct chip_operations mainboard_ops = {
 	.name	= "storm",
 	.enable_dev = mainboard_enable,
 };
+
+void lb_board(struct lb_header *header)
+{
+	struct lb_range *dma;
+
+	dma = (struct lb_range *)lb_new_record(header);
+	dma->tag = LB_TAB_DMA;
+	dma->size = sizeof(*dma);
+	dma->range_start = CONFIG_DRAM_DMA_START;
+	dma->range_size = CONFIG_DRAM_DMA_SIZE;
+}
diff --git a/src/soc/qualcomm/ipq806x/Makefile.inc b/src/soc/qualcomm/ipq806x/Makefile.inc
index f6acbed..a7dabc6 100644
--- a/src/soc/qualcomm/ipq806x/Makefile.inc
+++ b/src/soc/qualcomm/ipq806x/Makefile.inc
@@ -38,6 +38,7 @@ ramstage-y += soc.c
 ramstage-$(CONFIG_SPI_FLASH) += spi.c
 ramstage-y += timer.c
 ramstage-$(CONFIG_DRIVERS_UART) += uart.c
+ramstage-y += usb.c
 
 ifeq ($(CONFIG_USE_BLOBS),y)
 
diff --git a/src/soc/qualcomm/ipq806x/clock.c b/src/soc/qualcomm/ipq806x/clock.c
index 70afcec..88056d4 100644
--- a/src/soc/qualcomm/ipq806x/clock.c
+++ b/src/soc/qualcomm/ipq806x/clock.c
@@ -118,3 +118,29 @@ void nand_clock_config(void)
 	/* Wait for clock to stabilize. */
 	udelay(10);
 }
+
+/**
+ * usb_clock_config - configure USB controller clocks and reset the controller
+ */
+void usb_clock_config(void)
+{
+	/* Magic clock initialization numbers, nobody knows how they work... */
+	write32(0x10, USB30_MASTER_CLK_CTL_REG);
+	write32(0x10, USB30_1_MASTER_CLK_CTL_REG);
+	write32(0x500DF, USB30_MASTER_CLK_MD);
+	write32(0xE40942, USB30_MASTER_CLK_NS);
+	write32(0x100D7, USB30_MOC_UTMI_CLK_MD);
+	write32(0xD80942, USB30_MOC_UTMI_CLK_NS);
+	write32(0x10, USB30_MOC_UTMI_CLK_CTL);
+	write32(0x10, USB30_1_MOC_UTMI_CLK_CTL);
+
+	write32(1 << 5 |		/* assert port2 HS PHY async reset */
+		1 << 4 |		/* assert master async reset */
+		1 << 3 |		/* assert sleep async reset */
+		1 << 2 |		/* assert MOC UTMI async reset */
+		1 << 1 |		/* assert power-on async reset */
+		1 << 0 |		/* assert PHY async reset */
+		0, USB30_RESET);
+	udelay(5);
+	write32(0, USB30_RESET);	/* deassert all USB resets again */
+}
diff --git a/src/soc/qualcomm/ipq806x/include/clock.h b/src/soc/qualcomm/ipq806x/include/clock.h
index c5d4121..98f6661 100644
--- a/src/soc/qualcomm/ipq806x/include/clock.h
+++ b/src/soc/qualcomm/ipq806x/include/clock.h
@@ -63,6 +63,16 @@
 #define CFPB_SPLITTER_HCLK_CTL_REG          REG(0x026E0)
 #define EBI2_CLK_CTL_REG                    REG(0x03B00)
 
+#define USB30_MASTER_CLK_CTL_REG            REG(0x3b24)
+#define USB30_MASTER_CLK_MD                 REG(0x3b28)
+#define USB30_MASTER_CLK_NS                 REG(0x3b2c)
+#define USB30_1_MASTER_CLK_CTL_REG          REG(0x3b34)
+#define USB30_MOC_UTMI_CLK_MD               REG(0x3b40)
+#define USB30_MOC_UTMI_CLK_NS               REG(0x3b44)
+#define USB30_MOC_UTMI_CLK_CTL              REG(0x3b48)
+#define USB30_1_MOC_UTMI_CLK_CTL            REG(0x3b4c)
+#define USB30_RESET                         REG(0x3b50)
+
 #define ALWAYS_ON_CLK_BRANCH_ENA(i)         ((i) << 8)
 
 #define CLK_BRANCH_ENA_MASK                 0x00000010
@@ -182,5 +192,6 @@ void uart_pll_vote_clk_enable(unsigned int);
 void uart_clock_config(unsigned int gsbi_port, unsigned int m, unsigned int n,
 		unsigned int d, unsigned int clk_dummy);
 void nand_clock_config(void);
+void usb_clock_config(void);
 
 #endif  /*  __PLATFORM_IPQ860X_CLOCK_H_ */
diff --git a/src/soc/qualcomm/ipq806x/include/iomap.h b/src/soc/qualcomm/ipq806x/include/iomap.h
index be523a6..69744bc 100644
--- a/src/soc/qualcomm/ipq806x/include/iomap.h
+++ b/src/soc/qualcomm/ipq806x/include/iomap.h
@@ -85,6 +85,14 @@
 #define GPIO_CONFIG_ADDR(x) (TLMM_BASE_ADDR + 0x1000 + (x)*0x10)
 #define GPIO_IN_OUT_ADDR(x) (TLMM_BASE_ADDR + 0x1004 + (x)*0x10)
 
+/* 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 GSBI_1			1
 #define GSBI_2			2
 #define GSBI_4			4
diff --git a/src/soc/qualcomm/ipq806x/include/usb.h b/src/soc/qualcomm/ipq806x/include/usb.h
new file mode 100644
index 0000000..c3c4c48
--- /dev/null
+++ b/src/soc/qualcomm/ipq806x/include/usb.h
@@ -0,0 +1,26 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _IPQ806X_USB_H_
+#define _IPQ806X_USB_H_
+
+void setup_usb_host1(void);
+void setup_usb_host2(void);
+
+#endif /* _IPQ806X_USB_H_ */
diff --git a/src/soc/qualcomm/ipq806x/usb.c b/src/soc/qualcomm/ipq806x/usb.c
new file mode 100644
index 0000000..a9214be
--- /dev/null
+++ b/src/soc/qualcomm/ipq806x/usb.c
@@ -0,0 +1,227 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <delay.h>
+#include <arch/io.h>
+#include <console/console.h>
+
+#include "clock.h"
+#include "iomap.h"
+#include "usb.h"
+
+#define CRPORT_TX_OVRD_DRV_LO	0x1002
+#define CRPORT_RX_OVRD_IN_HI	0x1006
+#define CRPORT_TX_ALT_BLOCK	0x102d
+
+static u32 * const tcsr_usb_sel = (void *)0x1a4000b0;
+
+struct usb_qc_phy {
+	u32 ipcat;
+	u32 ctrl;
+	u32 general_cfg;
+	u32 ram1;
+	u32 hs_phy_ctrl;
+	u32 param_ovrd;
+	u32 chrg_det_ctrl;
+	u32 chrg_det_output;
+	u32 alt_irq_en;
+	u32 hs_phy_irq_stat;
+	u32 cgctl;
+	u32 dbg_bus;
+	u32 ss_phy_ctrl;
+	u32 ss_phy_param1;
+	u32 ss_phy_param2;
+	u32 crport_data_in;
+	u32 crport_data_out;
+	u32 crport_cap_addr;
+	u32 crport_cap_data;
+	u32 crport_ack_read;
+	u32 crport_ack_write;
+};
+check_member(usb_qc_phy, crport_ack_write, 0x50);
+
+static struct usb_qc_phy * const usb_host1_phy = (void *)USB_HOST1_PHY_BASE;
+static struct usb_qc_phy * const usb_host2_phy = (void *)USB_HOST2_PHY_BASE;
+
+struct usb_dwc3 {
+	u32 sbuscfg0;
+	u32 sbuscfg1;
+	u32 txthrcfg;
+	u32 rxthrcfg;
+	u32 ctl;
+	u32 evten;
+	u32 sts;
+	u8 reserved0[4];
+	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);
+
+static struct usb_dwc3 * const usb_host1_dwc3 = (void *)USB_HOST1_DWC3_BASE;
+static struct usb_dwc3 * const usb_host2_dwc3 = (void *)USB_HOST2_DWC3_BASE;
+
+static void setup_dwc3(struct usb_dwc3 *dwc3)
+{
+	write32(0x1 << 31 |	/* assert PHY soft reset */
+		0x1 << 25 |	/* (default) U1/U2 exit fail -> recovery? */
+		0x1 << 24 |	/* (default) activate PHY low power states */
+		0x1 << 19 |	/* (default) PHY low power delay value */
+		0x1 << 18 |	/* (default) activate PHY low power delay */
+		0x1 <<  1 |	/* (default) Tx deemphasis value */
+		0x1 <<  0 |	/* (default) elastic buffer mode */
+		0, &dwc3->usb3pipectl);
+
+	write32(0x1 << 31 |	/* assert PHY soft reset */
+		0x9 << 10 |	/* (default) PHY clock turnaround 8-bit UTMI+ */
+		0x1 <<  8 |	/* (default) enable PHY sleep in L1 */
+		0x1 <<  6 |	/* (default) enable PHY suspend */
+		0, &dwc3->usb2phycfg);
+
+	write32(0x2 << 19 |	/* (default) suspend clock scaling */
+		0x1 << 16 |	/* retry SS three times before HS downgrade */
+		0x1 << 12 |	/* port capability HOST */
+		0x1 << 11 |	/* assert core soft reset */
+		0x1 << 10 |	/* (default) sync ITP to refclk */
+		0x1 <<  2 |	/* U2 exit after 8us LFPS (instead of 248ns) */
+		0, &dwc3->ctl);
+
+	write32(0x32 << 22 |	/* (default) reference clock period in ns */
+		 0x1 << 15 |	/* (default) XHCI compliant device addressing */
+		0x10 <<  0 |	/* (default) devices time out after 32us */
+		0, &dwc3->uctl);
+
+	udelay(5);
+
+	clrbits_le32(&dwc3->ctl, 0x1 << 11);	/* deassert core soft reset */
+	clrbits_le32(&dwc3->usb2phycfg, 0x1 << 31);	/* PHY soft reset */
+	clrbits_le32(&dwc3->usb3pipectl, 0x1 << 31);	/* PHY soft reset */
+}
+
+static void setup_phy(struct usb_qc_phy *phy)
+{
+	write32(0x1  << 24 |	/* Indicate VBUS power present */
+		0x1  <<  8 |	/* Enable USB3 ref clock to prescaler */
+		0x1  <<  7 |	/* assert SS PHY reset */
+		0x19 <<  0 |	/* (default) reference clock multiplier */
+		0, &phy->ss_phy_ctrl);
+
+	write32(0x1 << 26 |	/* (default) unclamp DPSE/DMSE VLS */
+		0x1 << 25 |	/* (default) select freeclk for utmi_clk */
+		0x1 << 24 |	/* (default) unclamp DMSE VLS */
+		0x1 << 21 |	/* (default) enable UTMI clock */
+		0x1 << 20 |	/* set OTG VBUS as valid */
+		0x1 << 18 |	/* use ref clock from core */
+		0x1 << 17 |	/* (default) unclamp DPSE VLS */
+		0x1 << 11 |	/* force xo/bias/pll to stay on in suspend */
+		0x1 <<  9 | 	/* (default) unclamp IDHV */
+		0x1 <<  8 |	/* (default) unclamp VLS (again???) */
+		0x1 <<  7 |	/* (default) unclamp HV VLS */
+		0x7 <<  4 |	/* select frequency (no idea which one) */
+		0x1 <<  1 |	/* (default) "retention enable" */
+		0, &phy->hs_phy_ctrl);
+
+	write32(0x6e << 20 |	/* full TX swing amplitude */
+		0x20 << 14 |	/* (default) 6dB TX deemphasis */
+		0x17 <<  8 |	/* 3.5dB TX deemphasis */
+		0x9  <<  3 |	/* (default) LoS detector level */
+		0, &phy->ss_phy_param1);
+
+	write32(0x1 << 2, &phy->general_cfg);	/* set XHCI 1.00 compliance */
+
+	udelay(5);
+	clrbits_le32(&phy->ss_phy_ctrl, 0x1 << 7); /* deassert SS PHY reset */
+}
+
+static void crport_handshake(void *capture_reg, void *acknowledge_bit, u32 data)
+{
+	int usec = 100;
+
+	if (capture_reg)
+		write32(data, capture_reg);
+
+	write32(0x1 << 0, acknowledge_bit);
+	while (read32(acknowledge_bit) && --usec)
+		udelay(1);
+
+	if (!usec)
+		printk(BIOS_ERR, "CRPORT handshake timed out (0x%08x)\n", data);
+}
+
+static void crport_write(struct usb_qc_phy *phy, u16 addr, u16 data)
+{
+	crport_handshake(&phy->crport_data_in, &phy->crport_cap_addr, addr);
+	crport_handshake(&phy->crport_data_in, &phy->crport_cap_data, data);
+	crport_handshake(NULL, &phy->crport_ack_write, 0);
+}
+
+static void tune_phy(struct usb_qc_phy *phy)
+{
+	crport_write(phy, CRPORT_RX_OVRD_IN_HI,
+		      0x1 << 11 |	/* Set RX_EQ override? */
+		      0x4 <<  8 |	/* Set RX_EQ to 4? */
+		      0x1 <<  7);	/* Enable RX_EQ override */
+	crport_write(phy, CRPORT_TX_OVRD_DRV_LO,
+		      0x1 << 14 |	/* Enable amplitude (override?) */
+		     0x17 <<  7 |	/* Set TX deemphasis to 23 */
+		     0x6e <<  0);	/* Set amplitude to 110 */
+	crport_write(phy, CRPORT_TX_ALT_BLOCK,
+		      0x1 <<  7);	/* ALT block? ("partial RX reset") */
+}
+
+void setup_usb_host1(void)
+{
+	printk(BIOS_INFO, "Setting up USB HOST1 controller...\n");
+	setbits_le32(tcsr_usb_sel, 1 << 0);	/* Select DWC3 controller */
+	setup_phy(usb_host1_phy);
+	setup_dwc3(usb_host1_dwc3);
+	tune_phy(usb_host1_phy);
+}
+
+void setup_usb_host2(void)
+{
+	printk(BIOS_INFO, "Setting up USB HOST2 controller...\n");
+	setbits_le32(tcsr_usb_sel, 1 << 1);	/* Select DWC3 controller */
+	setup_phy(usb_host2_phy);
+	setup_dwc3(usb_host2_dwc3);
+	tune_phy(usb_host2_phy);
+}



More information about the coreboot-gerrit mailing list