[coreboot-gerrit] Patch set updated for coreboot: 3ed52d6 libpayload: usb: Support MTK xHCI host controller

Patrick Georgi (pgeorgi@google.com) gerrit at coreboot.org
Tue Jun 2 14:12:13 CEST 2015


Patrick Georgi (pgeorgi at google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/10389

-gerrit

commit 3ed52d665c124da37cabce8339f7b72c44a43f8a
Author: Yidi Lin <yidi.lin at mediatek.com>
Date:   Thu May 7 15:36:04 2015 +0800

    libpayload: usb: Support MTK xHCI host controller
    
    1. There is a mis-understanding to calculate the value of TD Size
       in Normal TRB. For MTK's xHCI controller it defines a number of
       packets that remain to be transferred for a TD after processing
       all Max packets in all previous TRBs,that means don't include the
       current TRB's.
    2. To minimize the scheduling effort for synchronous endpoints in xHC,
       the MTK architecture defines some extra SW scheduling parameters for
       HW. According to these parameters provided by SW, the xHC can easily
       decide whether a synchronous endpoint should be scheduled in a specific
       uFrame. The extra SW scheduling parameters are put into reserved DWs
       in Slot and Endpoint Context. But in core-boot synchronous transfer can
       be ignored, so only tow fields are set to a default value 1 to support
       bulk and interrupt transfers, and others are set to zero.
    3. For control transfer, it is better to read back doorbell register or add
       a memory barrier after ringing the doorbell to flush posted write.
       Otherwise the first command will be aborted on MTK's xHCI controller.
    4. Before send commands to a port, the Port Power in PORTSC register should
       be set to 1 on MTK's xHCI. so a hook function of enbale_port in
       generic_hub_ops_t struct is provided.
    
    Change-Id: Ie8878b50c048907ebf939b3f6657535a54877fde
    Signed-off-by: Patrick Georgi <pgeorgi at chromium.org>
    Original-Commit-Id: 738609c11f16264c6e6429d478b2040cb391fe41
    Original-Change-Id: Id9156892699e2e42a166c77fbf6690049abe953b
    Original-Signed-off-by: Chunfeng Yun <chunfeng.yun at mediatek.com>
    Original-Reviewed-on: https://chromium-review.googlesource.com/265362
    Original-Reviewed-by: Julius Werner <jwerner at chromium.org>
    Original-Commit-Queue: Yidi Lin <yidi.lin at mediatek.com>
    Original-Tested-by: Yidi Lin <yidi.lin at mediatek.com>
---
 payloads/libpayload/Config.in                   |  6 ++++++
 payloads/libpayload/drivers/usb/xhci.c          | 17 ++++++++++++++++-
 payloads/libpayload/drivers/usb/xhci_commands.c |  2 ++
 payloads/libpayload/drivers/usb/xhci_devconf.c  | 10 ++++++++++
 payloads/libpayload/drivers/usb/xhci_private.h  |  9 +++++++++
 payloads/libpayload/drivers/usb/xhci_rh.c       | 20 +++++++++++++++++++-
 6 files changed, 62 insertions(+), 2 deletions(-)

diff --git a/payloads/libpayload/Config.in b/payloads/libpayload/Config.in
index 4d48761..92c89ab 100644
--- a/payloads/libpayload/Config.in
+++ b/payloads/libpayload/Config.in
@@ -495,6 +495,12 @@ config USB_XHCI
 	  Select this option if you want to use USB 3.0
 	  NOTE: This option is not (fully) implemented yet
 
+config USB_XHCI_MTK_QUIRK
+	bool "Support for USB xHCI controllers on MTK SoC"
+	depends on USB_XHCI
+	help
+	  Select this option if you want to use USB 3.0 on MTK platform.
+
 config USB_DWC2
 	bool "Support for USB DesignWare HCD controllers"
 	depends on USB && !USB_HID
diff --git a/payloads/libpayload/drivers/usb/xhci.c b/payloads/libpayload/drivers/usb/xhci.c
index 26dcdbe..77645bf 100644
--- a/payloads/libpayload/drivers/usb/xhci.c
+++ b/payloads/libpayload/drivers/usb/xhci.c
@@ -370,6 +370,8 @@ xhci_reinit (hci_t *controller)
 	xhci->ev_ring_table[0].seg_base_hi = 0;
 	xhci->ev_ring_table[0].seg_size = EVENT_RING_SIZE;
 
+	/* pass event ring table to hardware */
+	wmb();
 	/* Initialize primary interrupter */
 	xhci->hcrreg->intrrs[0].erstsz = 1;
 	xhci_update_event_dq(xhci);
@@ -510,6 +512,7 @@ xhci_enqueue_trb(transfer_ring_t *const tr)
 		xhci_spew("Handling LINK pointer\n");
 		const int tc = TRB_GET(TC, tr->cur);
 		TRB_SET(CH, tr->cur, chain);
+		wmb();
 		TRB_SET(C, tr->cur, tr->pcs);
 		tr->cur = phys_to_virt(tr->cur->ptr_low);
 		if (tc)
@@ -535,7 +538,7 @@ xhci_enqueue_td(transfer_ring_t *const tr, const int ep, const size_t mps,
 			cur_length = length;
 			packets = 0;
 			length = 0;
-		} else {
+		} else if (!IS_ENABLED(CONFIG_LP_XHCI_MTK_QUIRK)) {
 			packets -= (residue + cur_length) / mps;
 			residue = (residue + cur_length) % mps;
 			length -= cur_length;
@@ -548,6 +551,18 @@ xhci_enqueue_td(transfer_ring_t *const tr, const int ep, const size_t mps,
 		TRB_SET(TDS, trb, MIN(TRB_MAX_TD_SIZE, packets));
 		TRB_SET(CH, trb, 1);
 
+		if (length && IS_ENABLED(CONFIG_LP_XHCI_MTK_QUIRK)) {
+			/*
+			 * For MTK's xHCI controller, TDS defines a number of
+			 * packets that remain to be transferred for a TD after
+			 * processing all Max packets in all previousTRBs, that
+			 * means don't include the current TRB's.
+			 */
+			packets -= (residue + cur_length) / mps;
+			residue = (residue + cur_length) % mps;
+			length -= cur_length;
+		}
+
 		/* Check for first, data stage TRB */
 		if (!trb_count && ep == 1) {
 			TRB_SET(DIR, trb, dir);
diff --git a/payloads/libpayload/drivers/usb/xhci_commands.c b/payloads/libpayload/drivers/usb/xhci_commands.c
index 009a69c..845a34d 100644
--- a/payloads/libpayload/drivers/usb/xhci_commands.c
+++ b/payloads/libpayload/drivers/usb/xhci_commands.c
@@ -47,6 +47,8 @@ xhci_post_command(xhci_t *const xhci)
 	TRB_SET(C, xhci->cr.cur, xhci->cr.pcs);
 	++xhci->cr.cur;
 
+	/* pass command trb to hardware */
+	wmb();
 	/* Ring the doorbell */
 	xhci->dbreg[0] = 0;
 
diff --git a/payloads/libpayload/drivers/usb/xhci_devconf.c b/payloads/libpayload/drivers/usb/xhci_devconf.c
index 012f610..5b5bb5e 100644
--- a/payloads/libpayload/drivers/usb/xhci_devconf.c
+++ b/payloads/libpayload/drivers/usb/xhci_devconf.c
@@ -313,6 +313,16 @@ xhci_finish_ep_config(const endpoint_t *const ep, inputctx_t *const ic)
 	EC_SET(AVRTRB,	epctx, avrtrb);
 	EC_SET(MXESIT,  epctx, EC_GET(MPS, epctx) * EC_GET(MBS, epctx));
 
+	if (IS_ENABLED(CONFIG_LP_USB_XHCI_MTK_QUIRK)) {
+		/* The MTK xHCI defines some extra SW parameters which are
+		 * put into reserved DWs in Slot and Endpoint Contexts for
+		 * synchronous endpoints. But for non-isochronous transfers,
+		 * it is enough to set the following two fields to 1, and others
+		 * are set to 0.
+		 */
+		EC_SET(BPKTS, epctx, 1);
+		EC_SET(BBM, epctx, 1);
+	}
 	return 0;
 }
 
diff --git a/payloads/libpayload/drivers/usb/xhci_private.h b/payloads/libpayload/drivers/usb/xhci_private.h
index 3861858..f01a37f 100644
--- a/payloads/libpayload/drivers/usb/xhci_private.h
+++ b/payloads/libpayload/drivers/usb/xhci_private.h
@@ -33,6 +33,8 @@
 
 //#define USB_DEBUG
 #include <usb/usb.h>
+#include <arch/barrier.h>
+#include <kconfig.h>
 
 //#define XHCI_DUMPS
 #define xhci_debug(fmt, args...) usb_debug("%s: " fmt, __func__, ## args)
@@ -242,6 +244,13 @@ typedef volatile struct slotctx {
 #define EC_MXESIT_FIELD		f5		/* MXESIT - Max ESIT Payload */
 #define EC_MXESIT_START		16
 #define EC_MXESIT_LEN		16
+#define EC_BPKTS_FIELD		rsvd[0]		/* BPKTS - packets tx in scheduled uframe */
+#define EC_BPKTS_START		0
+#define EC_BPKTS_LEN		6
+#define EC_BBM_FIELD		rsvd[0]		/* BBM - burst mode for scheduling */
+#define EC_BBM_START		11
+#define EC_BBM_LEN		1
+
 #define EC_MASK(tok)		MASK(EC_##tok##_START, EC_##tok##_LEN)
 #define EC_GET(tok, ec)		(((ec)->EC_##tok##_FIELD & EC_MASK(tok)) \
 				 >> EC_##tok##_START)
diff --git a/payloads/libpayload/drivers/usb/xhci_rh.c b/payloads/libpayload/drivers/usb/xhci_rh.c
index fa118fe..a6b94c2 100644
--- a/payloads/libpayload/drivers/usb/xhci_rh.c
+++ b/payloads/libpayload/drivers/usb/xhci_rh.c
@@ -119,6 +119,24 @@ xhci_rh_reset_port(usbdev_t *const dev, const int port)
 	return 0;
 }
 
+static int
+xhci_rh_enable_port(usbdev_t *const dev, int port)
+{
+	if (IS_ENABLED(CONFIG_LP_USB_XHCI_MTK_QUIRK)) {
+		xhci_t *const xhci = XHCI_INST(dev->controller);
+		volatile u32 *const portsc =
+			&xhci->opreg->prs[port - 1].portsc;
+
+		/*
+		 * Before send commands to a port, the Port Power in
+		 * PORTSC register should be enabled on MTK's xHCI.
+		 */
+		*portsc = (*portsc & PORTSC_RW_MASK) | PORTSC_PP;
+	}
+	return 0;
+}
+
+
 static const generic_hub_ops_t xhci_rh_ops = {
 	.hub_status_changed	= xhci_rh_hub_status_changed,
 	.port_status_changed	= xhci_rh_port_status_changed,
@@ -126,7 +144,7 @@ static const generic_hub_ops_t xhci_rh_ops = {
 	.port_in_reset		= xhci_rh_port_in_reset,
 	.port_enabled		= xhci_rh_port_enabled,
 	.port_speed		= xhci_rh_port_speed,
-	.enable_port		= NULL,
+	.enable_port		= xhci_rh_enable_port,
 	.disable_port		= NULL,
 	.start_port_reset	= NULL,
 	.reset_port		= xhci_rh_reset_port,



More information about the coreboot-gerrit mailing list