GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
+26
View File
@@ -0,0 +1,26 @@
menuconfig LOTUS_USB
bool "LOTUS USB support"
default y
select CMD_USB
select USB
help
LOTUS USB support.
if LOTUS_USB
config USB_PWREN_OFF_DELAY
int "usb port power off delay(ms)"
default 100
help
Some usb device can't be recognize in U-boot because of error state, so
we power off them and wait a delay to restart them, we call the delay
as USB_PWREN_OFF_DELAY.
config USB_DUAL_PORT_SUPPORT
bool "support dual-usb-port(U2 & U3) in host mode"
default n
help
Some lotus chips support 2 usb host ports, contains U2 and U3. If your
chip support 2 ports, enable this config could recognize U3 and U2 dev
meanwhile, but cause to U3 couldn't be recognized sometimes.
endif
@@ -0,0 +1,6 @@
obj-y += phy/
ccflags-y += -I$(srctree)/cmd
obj-$(CONFIG_USB_GADGET)+= udc3/
@@ -0,0 +1,2 @@
obj-$(CONFIG_TARGET_XMFALCON) += phy-xmfalcon-usb.o
obj-$(CONFIG_TARGET_XMORCA) += phy-xmorca-usb.o
@@ -0,0 +1,31 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#ifndef PHY_LOTUS_USB
#define PHY_LOTUS_USB
#define U_LEVEL1 10
#define U_LEVEL2 20
#define U_LEVEL3 30
#define U_LEVEL4 50
#define U_LEVEL5 100
#define U_LEVEL6 200
#define U_LEVEL7 300
#define U_LEVEL8 500
#define U_LEVEL9 1000
#define U_LEVEL10 2000
enum usb_phy_width_mode {
PHY_WIDTH_8BIT = 0,
PHY_WIDTH_16BIT,
};
enum usb_scenes {
/* U3 CTRL connect U3/U2 PHY */
LOTUS_USB_SCENE2 = 0,
/* U3 CTRL connect U3 PHY, U2 CTRL connect U2 PHY */
LOTUS_USB_SCENE1 = 1,
};
#endif // PHY_LOTUS_USB
@@ -0,0 +1,699 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#include <asm/arch/platform.h>
#include <dm.h>
#include <linux/lotus/usb.h>
#include <usb.h>
#include <usb/xhci.h>
#include <linux/lotus/chip.h>
#include "phy-usb.h"
#ifdef __USB_DEBUG
#define USB_DEBUG(...) printf(__VA_ARGS__)
#else
#define USB_DEBUG(...)
#endif
/* CRG PERI_CRG80: usb clk & reset, offset 0x140 */
#define USB2_CTRL 0x140
#define OUTER_PHY_CRG_DEF_VAL 0x130d
#define LOTUS_PHY_CRG_DEF_VAL 0x3130d
#define LOTUS_PHY_REF_CKEN (0x1 << 17)
#define LOTUS_PHY_APB_CKEN (0x1 << 16)
#define USB2_UTMI_CKEN (0x1 << 12)
#define USB2_PHY_APB_CKEN (0x1 << 11)
#define USB2_REF_CKEN (0x1 << 9)
#define USB2_BUS_CKEN (0x1 << 8)
#define USB2_PHY_PLL_CKEN (0x1 << 4)
#define USB2_PHY_XTAL_CKEN (0x1 << 2)
#define USB2_FREECLK_CKSEL (0x1 << 13)
#define USB2_PHY_APB_RST (0x1 << 10)
#define USB2_VCC_SRST_REQ (0x1 << 3)
#define USB2_PHY_REQ (0x1 << 0)
#define USB2_PHY_PORT_TREQ (0x1 << 1)
#define USB3_CTRL 0x13c
#define USB3_PHY_SRST (0x1 << 8)
#define USB3_PHY_XTAL_CKEN (0x1 << 7)
#define USB3_VCC_SRST (0x1 << 6)
#define USB3_PIPE3_RX_CKEN (0x1 << 5)
#define USB3_PIPE3_TX_CKEN (0x1 << 4)
#define USB3_UTMI_CKEN (0x1 << 3)
#define USB3_SUSPEND_CKEN (0x1 << 2)
#define USB3_REF_CKEN (0x1 << 1)
#define USB3_BUS_CKEN (0x1 << 0)
#define GTXTHRCFG 0xc108
#define GRXTHRCFG 0xc10c
#define REG_GCTL 0xc110
#define GUSB2PHYCFG 0xc200
#define REG_GUSB3PIPECTL0 0xc2c0
#define PCS_SSP_SOFT_RESET (0x1 << 31)
#define USBTRDTIM_MASK 0x00003c00
#define USBTRDTIM_16BIT (0x5 << 10)
#define USBTRDTIM_8BIT (0x9 << 10)
#define PHYIF (0x1 << 3)
#define SUSPENDUSB20 (0x1 << 6)
#define ENBLSLPM (0x1 << 8)
#define LSIPD_MASK (0x7 << 19)
#define LSIPD_3_BIT (0x2 << 19)
#define U2_FREECLK_EXISTS (0x1 << 30)
#define PORT_CAP_DIR (0x3 << 12)
#define PORT_SET_HOST (0x1 << 12)
#define PORT_DISABLE_SUSPEND (0x1 << 17)
#define USB2_G_TXTHRCFG 0x23100000
#define USB2_G_RXTHRCFG 0x23100000
/* Lotus phy use reg, reg's misc_base=0x12028000 */
#define MISC_LOTUS_PHY2_CTRL_REG 0x28
#define MISC_USB_SEL_SCENE1 (0x0 << 0)
#define MISC_USB_SEL_SCENE2 (0x1 << 0)
#define MISC_USB_SCENE_MASK (0x1 << 0)
#define USB2_UTMI_REG_PROTECT1 (0x1 << 8)
#define USB2_UTMI_REG_PROTECT2 (0x1 << 9)
#define USB2_UTMI_REG_PROTECT3 (0x1 << 10)
#define USB2_HW_CHIRP (0x1 << 14)
#define USB2_UTMI_IDPULLUP (0x1 << 15)
/* Outer phy use reg, reg's misc_base=0x12028000 */
#define MISC_OUT_PHY2_CTRL_REG 0x2C
#define USB2_OSCOUTEN (0x1 << 8)
#define USB2_PLL_EN (0x1 << 12)
#define USB2_UTMI_DATABUS16_8 (0x1 << 16)
#define MISC_OUT_PHY2_XCFGI_63TO32 0x988
#define CFG_OUT_PHY2_EYE_VAL (0x1 << 5)
/* reg base(misc_base): 0x12028000 */
#define MISC_USB2_CTRL_REG 0x24
#define U2_BUS_FILTER_BYPASS (0xf << 0)
#define U2_PWREN_MODE_MASK (0x1 << 4)
#define U2_PWREN_MODE_MISC (0x0 << 4)
#define U2_PWREN_MODE_CTRL (0x1 << 4)
#define U2_OVERCURR_MODE_MASK (0x1 << 5)
#define U2_OVERCURR_MODE_DISABLE (0x0 << 5)
#define U2_OVERCURR_MODE_ENABLE (0x1 << 5)
#define U2_PWREN_MASK (0x1 << 6)
#define U2_PWREN_ON (0x0 << 6)
#define U2_PWREN_OFF (0x1 << 6)
#define U2_OVERCURR_MASK (0x1 << 7)
#define U2_OVERCURR_ON (0x0 << 7)
#define U2_OVERCURR_OFF (0x1 << 7)
#define U2_FLADJ_30MHZ (0x20 << 13)
#define MISC_USB3_CTRL_REG 0x1110
#define U3_BUS_FILTER_BYPASS (0xf << 0)
#define U3_FLADJ_30MHZ (0x20 << 4)
#define U3_PWREN_MODE_MASK (0x1 << 11)
#define U3_PWREN_MODE_MISC (0x0 << 11)
#define U3_PWREN_MODE_CTRL (0x1 << 11)
#define U3_OVERCURR_MODE_MASK (0x1 << 12)
#define U3_OVERCURR_MODE_DISABLE (0x0 << 12)
#define U3_OVERCURR_MODE_ENABLE (0x1 << 12)
#define U3_PWREN_MASK (0x1 << 13)
#define U3_PWREN_ON (0x0 << 13)
#define U3_PWREN_OFF (0x1 << 13)
#define U3_OVERCURR_MASK (0x1 << 14)
#define U3_OVERCURR_ON (0x0 << 14)
#define U3_OVERCURR_OFF (0x1 << 14)
#define HOST_U2_PORT_MASK (0xf << 20)
#define HOST_U2_PORT(n) (n << 20)
#define HOST_U3_PORT_MASK (0xf << 24)
#define HOST_U3_PORT(n) (n << 24)
#define USB2_HOST_VBUS_EN (0x1 << 30)
#define USB3_HOST_VBUS_EN (0x1 << 31)
#define MISC_USB3_PHY_REG 0x112c
/* SYSBOOT1[2:2]: usb scene select */
#define SYSBOOT1 0x12020134
#define SYSBOOT1_SEL_USB_SCENE_MASK (1 << 2)
static uintptr_t xhci_base;
/**
* lotus_chip_u3_ability - whether current chip support u3.
*
* @return:
* 1: support u3.
* 0: only support u2.
*/
static int lotus_chip_u3_ability(void)
{
u32 id = get_chipid();
USB_DEBUG("%s: chid id 0x%x\n", __func__, id);
if (id == 0x76050110 || id == 0x06050110)
return 0;
/* if id == 0, consider chip support U3. */
return 1;
}
int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
{
#ifdef CONFIG_USB_DUAL_PORT_SUPPORT
unsigned int reg;
reg = readl(MISC_REG_BASE + MISC_LOTUS_PHY2_CTRL_REG);
reg &= MISC_USB_SCENE_MASK;
if (index >= LOTUS_USB_CTRL_UNKNOWN)
return -ENODEV;
/* 7605v11 only support u2 host */
if (!lotus_chip_u3_ability() && index == LOTUS_DWC_U3)
return -ENODEV;
/* Scene2 don't init U2 host. */
if (index == LOTUS_DWC_U2 && reg)
return -ENODEV;
#endif
if ((hccr == NULL) || (hcor == NULL))
return -EINVAL;
#ifdef CONFIG_USB_DUAL_PORT_SUPPORT
if (index == LOTUS_DWC_U3)
xhci_base = USB3_CTRL_REG_BASE;
else if (index == LOTUS_DWC_U2)
xhci_base = USB2_CTRL_REG_BASE;
#else
/* single usb port, U3 is default */
if (index == LOTUS_DWC_U3) {
/* 7605v11 only support U2 host */
if (!lotus_chip_u3_ability())
xhci_base = USB2_CTRL_REG_BASE;
else
xhci_base = USB3_CTRL_REG_BASE;
} else
return -ENODEV;
#endif
*hccr = (struct xhci_hccr *)(xhci_base);
*hcor = (struct xhci_hcor *)((uintptr_t) *hccr +
HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
USB_DEBUG("hccr:0x%x, hcor:0x%x.\n", (unsigned int)*hccr, (unsigned int)*hcor);
return 0;
}
/* Get usb scene from SYSBOOT1 and config to MISC
* usb_scene: 0-scene1, 1-scene2.
* scene1:U3 only + U2.
* scene2:U3(compatible to U2).
*/
#ifdef CONFIG_USB_DUAL_PORT_SUPPORT
static void usb_scene_select(int index, int type)
#else
static void usb_scene_select(int index)
#endif
{
unsigned int reg, usb_scene = LOTUS_USB_SCENE2;
#ifdef CONFIG_USB_DUAL_PORT_SUPPORT
reg = readl(SYSBOOT1);
if (reg & SYSBOOT1_SEL_USB_SCENE_MASK)
usb_scene = LOTUS_USB_SCENE1;
/* used by usb download */
if (index == LOTUS_DWC_U2 && type == USB_INIT_DEVICE)
usb_scene = LOTUS_USB_SCENE1;
#else
/* used by usb download */
if ((index == LOTUS_DWC_U2) ||
(index == LOTUS_DWC_U3 && !lotus_chip_u3_ability()))
usb_scene = LOTUS_USB_SCENE1;
#endif
reg = 0;
if (usb_scene == LOTUS_USB_SCENE1) {
/* u3 ctrl connect u3 phy, u2 ctrl connect u2 phy */
reg |= MISC_USB_SEL_SCENE1;
printf("%s:select U3 only + U2.\n", __func__);
} else if (usb_scene == LOTUS_USB_SCENE2) {
/* u3 ctrl connect u3 phy and u2 phy */
reg |= MISC_USB_SEL_SCENE2;
printf("%s:select U3(compatible to U2).\n", __func__);
}
writel(reg, MISC_REG_BASE + MISC_LOTUS_PHY2_CTRL_REG);
USB_DEBUG("MISC_LOTUS_PHY2_CTRL_REG(0x12028028):0x%X\n",
readl(MISC_REG_BASE + MISC_LOTUS_PHY2_CTRL_REG));
}
static void lotus_u2_phy_eye_config(void)
{
unsigned int reg;
/* outer phy eye diagram config */
reg = readl(MISC_REG_BASE + MISC_OUT_PHY2_XCFGI_63TO32);
reg |= CFG_OUT_PHY2_EYE_VAL;
writel(reg, MISC_REG_BASE + MISC_OUT_PHY2_XCFGI_63TO32);
}
static void lotus_dwc_data_width_config(int index,
enum usb_phy_width_mode mode)
{
unsigned int reg, base = 0;
/* GUSB2PHYCFG register: config val 0x40001548(HS/FS) or
* 0x00381548(LS) according to IC.
*
* USBTRDTIM: USB 2.0 Turnaround Time in PHY clocks.
* PHYIF: 1 UTMI+ PHY is 16-bit, 0 UTMI+ PHY is 8-bit.
*/
reg = 0;
switch (mode) {
case PHY_WIDTH_8BIT:
/* 8-bits usb phy configure */
reg |= USBTRDTIM_8BIT;
reg &= ~PHYIF;
break;
case PHY_WIDTH_16BIT:
/* 16-bits usb phy configure */
reg |= (USBTRDTIM_16BIT | PHYIF);
break;
default:
printf("usb phy width config val error.\n");
return;
}
#ifdef CONFIG_USB_DUAL_PORT_SUPPORT
if (index == LOTUS_DWC_U3)
base = USB3_CTRL_REG_BASE;
else
base = USB2_CTRL_REG_BASE;
#else
if (index == LOTUS_DWC_U3 && lotus_chip_u3_ability())
base = USB3_CTRL_REG_BASE;
else
base = USB2_CTRL_REG_BASE;
#endif
writel(reg, base + GUSB2PHYCFG);
}
static inline void lotus_usb2_vbus_valid_en(void)
{
unsigned int reg;
/* enable U2 vbus valid */
reg = readl(MISC_REG_BASE + MISC_USB3_CTRL_REG);
reg |= USB2_HOST_VBUS_EN;
writel(reg, MISC_REG_BASE + MISC_USB3_CTRL_REG);
}
static inline void lotus_usb3_vbus_valid_en(void)
{
unsigned int reg;
/* enable U3 vbus valid */
reg = readl(MISC_REG_BASE + MISC_USB3_CTRL_REG);
reg |= USB3_HOST_VBUS_EN;
writel(reg, MISC_REG_BASE + MISC_USB3_CTRL_REG);
}
static void lotus_u2_phy_clk_init(void)
{
unsigned int reg;
/* enable u2 phy clk and do reset */
reg = (USB2_PHY_REQ | USB2_PHY_XTAL_CKEN);
writel(reg, CRG_REG_BASE + USB2_CTRL);
udelay(U_LEVEL6);
/* undo phy reset */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg &= ~USB2_PHY_REQ;
writel(reg, CRG_REG_BASE + USB2_CTRL);
USB_DEBUG("USB2_CRG(0x12010140), expext:0x4,"
"acutal:0x%X\n", readl(CRG_REG_BASE + USB2_CTRL));
}
static void lotus_u2_ctrl_clk_init(void)
{
unsigned int reg;
/* enable u2 ctrl clk and do reset */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg |= (USB2_VCC_SRST_REQ | USB2_BUS_CKEN | USB2_REF_CKEN |
USB2_UTMI_CKEN);
writel(reg, CRG_REG_BASE + USB2_CTRL);
udelay(U_LEVEL6);
/* undo ctrl vcc reset */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg &= ~USB2_VCC_SRST_REQ;
writel(reg, CRG_REG_BASE + USB2_CTRL);
}
static void inline lotus_usb2_clk_init(void)
{
/* write CRG default value 0x130d, including:
*
* USB2_PHY_REQ: reset PHY UTMI
* USB2_PHY_XTAL_CKEN: open phy xtal clk
* USB2_VCC_SRST_REQ: reset ctrl VCC
* USB2_BUS_CKEN: open bus clk
* USB2_REF_CKEN: open ctrl ref clk
* USB2_UTMI_CKEN: open UTMI clk
* LOTUS_PHY_APB_CKEN: open LOTUS phy apb clk
* USB2_UTMI_CKEN: open LOTUS phy ref clk
*/
lotus_u2_phy_clk_init();
lotus_u2_ctrl_clk_init();
USB_DEBUG("USB2_CRG(0x12010140), expext:0x1304,"
"acutal:0x%X\n", readl(CRG_REG_BASE + USB2_CTRL));
}
static void inline lotus_usb2_clk_exit(void)
{
unsigned int reg;
/* disable usb2 clk and do reset */
reg = 0;
reg |= (USB2_VCC_SRST_REQ | USB2_PHY_REQ);
writel(reg, CRG_REG_BASE + USB2_CTRL);
USB_DEBUG("USB2_CRG(0x12010140), expext:0x9,"
"acutal:0x%X\n", readl(CRG_REG_BASE + USB2_CTRL));
}
static void lotus_usb3_clk_init(void)
{
unsigned int reg;
/* write CRG default value 0x1ff, including:
*
* USB3_PHY_SRST: reset U3 PHY UTMI
* USB3_PHY_XTAL_CKEN: open U3 phy xtal clk
* USB3_VCC_SRST: reset U3 ctrl VCC
* USB3_PIPE3_RX_CKEN: open PIPE3 RX clk
* USB3_PIPE3_TX_CKEN: open PIPE3 TX clk
* USB3_UTMI_CKEN: open UTMI clk
* USB3_SUSPEND_CKEN: open U3 ctrl suspend clk
* USB3_REF_CKEN: open U3 ctrl ref clk
* USB3_BUS_CKEN: open U3 ctrl bus clk
*/
reg = 0;
reg |= (USB3_PHY_SRST | USB3_PHY_XTAL_CKEN | USB3_VCC_SRST |
USB3_PIPE3_RX_CKEN | USB3_PIPE3_TX_CKEN | USB3_UTMI_CKEN |
USB3_SUSPEND_CKEN | USB3_REF_CKEN | USB3_BUS_CKEN);
writel(reg, CRG_REG_BASE + USB3_CTRL);
USB_DEBUG("USB3_CRG(0x1201013c), expext:0x1ff,"
"acutal:0x%X\n", readl(CRG_REG_BASE + USB3_CTRL));
udelay(U_LEVEL6);
/* undo usb phy and ctrl reset */
reg = readl(CRG_REG_BASE + USB3_CTRL);
reg &= ~USB3_PHY_SRST;
reg &= ~USB3_VCC_SRST;
writel(reg, CRG_REG_BASE + USB3_CTRL);
USB_DEBUG("USB3_CRG(0x1201013c), expext:0xbf,"
"acutal:0x%X\n", readl(CRG_REG_BASE + USB3_CTRL));
}
static void lotus_usb3_clk_exit(void)
{
unsigned int reg;
/* disable usb3 clk and do reset */
reg = 0;
reg |= (USB3_PHY_SRST | USB3_VCC_SRST);
writel(reg, CRG_REG_BASE + USB3_CTRL);
USB_DEBUG("USB3_CRG(0x1201013c), expext:0x140,"
"acutal:0x%X\n", readl(CRG_REG_BASE + USB3_CTRL));
}
static void lotus_u2_phy_misc_config(void)
{
unsigned int reg;
/* MISC_OUT_PHY2_CTRL: config 0x11100 according to IC. */
reg = 0;
reg |= (USB2_OSCOUTEN | USB2_PLL_EN | USB2_UTMI_DATABUS16_8);
writel(reg, MISC_REG_BASE + MISC_OUT_PHY2_CTRL_REG);
USB_DEBUG("MISC_OUT_PHY2_CTRL_REG(0x1202802c),"
"expext:0x11100, acutal:0x%X\n",
readl(MISC_REG_BASE + MISC_OUT_PHY2_CTRL_REG));
}
static void lotus_u2_ctrl_misc_config(void)
{
unsigned int reg;
/* MISC_USB2_CTRL_REG: config 0x400ff according to IC. */
reg = 0;
reg |= (U2_BUS_FILTER_BYPASS | U2_PWREN_MODE_CTRL | U2_OVERCURR_MODE_ENABLE |\
U2_PWREN_OFF | U2_OVERCURR_OFF | U2_FLADJ_30MHZ);
writel(reg, MISC_REG_BASE + MISC_USB2_CTRL_REG);
USB_DEBUG("MISC_USB2_CTRL_REG(0x12028024),"
"expext:0x400ff, acutal:0x%X\n",
readl(MISC_REG_BASE + MISC_USB2_CTRL_REG));
}
static void lotus_u3_ctrl_misc_config(void)
{
unsigned int reg;
/* MISC_USB3_CTRL_REG: config 0xc1107a0f according to IC. */
reg = 0;
reg |= HOST_U3_PORT(1);
reg |= HOST_U2_PORT(1);
reg |= (U3_OVERCURR_OFF | U3_PWREN_OFF | U3_OVERCURR_MODE_ENABLE |\
U3_PWREN_MODE_CTRL | U3_FLADJ_30MHZ | U3_BUS_FILTER_BYPASS);
writel(reg, MISC_REG_BASE + MISC_USB3_CTRL_REG);
USB_DEBUG("MISC_USB3_CTRL_REG(0x12029110), acutal:0x%X\n",
readl(MISC_REG_BASE + MISC_USB3_CTRL_REG));
}
/* config U3 phy inner reg, insure U3 phy CRG already open. */
static void lotus_u3_phy_misc_config(void)
{
/* adjust pi_current_trim */
writel(0x11, MISC_REG_BASE + MISC_USB3_PHY_REG);
udelay(1); /* asic say delay 10ns, we delay 1us */
writel(0x4211, MISC_REG_BASE + MISC_USB3_PHY_REG);
udelay(1);
writel(0x11, MISC_REG_BASE + MISC_USB3_PHY_REG);
udelay(1);
/* close slew_assist_dis */
writel(0x2, MISC_REG_BASE + MISC_USB3_PHY_REG);
udelay(1);
writel(0x100202, MISC_REG_BASE + MISC_USB3_PHY_REG);
udelay(1);
writel(0x2, MISC_REG_BASE + MISC_USB3_PHY_REG);
udelay(1);
USB_DEBUG("MISC_USB3_PHY_REG(0x1202912c):0x%X\n",
readl(MISC_REG_BASE + MISC_USB3_PHY_REG));
}
static void lotus_dwc_usb_config(int index)
{
unsigned int reg, base = 0;
#ifdef CONFIG_USB_DUAL_PORT_SUPPORT
if (index == LOTUS_DWC_U2)
base = USB2_CTRL_REG_BASE;
else
base = USB3_CTRL_REG_BASE;
#else
if (index == LOTUS_DWC_U2 ||
(index == LOTUS_DWC_U3 && !lotus_chip_u3_ability())) {
/* USB2 Controller configs */
base = USB2_CTRL_REG_BASE;
}
if ((index == LOTUS_DWC_U3 && lotus_chip_u3_ability())) {
/* USB3 Controller configs */
base = USB3_CTRL_REG_BASE;
}
#endif
reg = readl(base + REG_GUSB3PIPECTL0);
reg |= PCS_SSP_SOFT_RESET;
writel(reg, base + REG_GUSB3PIPECTL0);
udelay(U_LEVEL2);
reg = readl(base + REG_GCTL);
reg &= ~PORT_CAP_DIR;
reg |= PORT_SET_HOST; /* [13:12] 01: Host; 10: Device; 11: OTG */
writel(reg, base + REG_GCTL);
udelay(U_LEVEL2);
reg = readl(base + REG_GUSB3PIPECTL0);
reg &= ~PCS_SSP_SOFT_RESET;
reg &= ~PORT_DISABLE_SUSPEND; /* disable suspend */
writel(reg, base + REG_GUSB3PIPECTL0);
udelay(U_LEVEL2);
writel(USB2_G_TXTHRCFG, base + GTXTHRCFG);
writel(USB2_G_RXTHRCFG, base + GRXTHRCFG);
udelay(U_LEVEL2);
lotus_dwc_data_width_config(index, PHY_WIDTH_16BIT);
reg = readl(base + GUSB2PHYCFG);
reg &= ~SUSPENDUSB20; /* disable suspend */
reg &= ~ENBLSLPM; /* suspend not transfer to external PHY */
reg &= ~U2_FREECLK_EXISTS;
reg &= ~LSIPD_MASK;
reg |= LSIPD_3_BIT;
writel(reg, base + GUSB2PHYCFG);
#ifdef CONFIG_USB_DUAL_PORT_SUPPORT
if (index == LOTUS_DWC_U2) {
#else
if (index == LOTUS_DWC_U2 ||
(index == LOTUS_DWC_U3 && !lotus_chip_u3_ability())) {
#endif
USB_DEBUG("U2 GUSB2PHYCFG(0xc200):0x%X\n",
readl(base + GUSB2PHYCFG));
USB_DEBUG("U2 GUSB3PIPECTL0(0xc2c0):0x%X\n",
readl(base + REG_GUSB3PIPECTL0));
USB_DEBUG("U2 GCTL(0xc110):0x%X\n",
readl(base + REG_GCTL));
#ifdef CONFIG_USB_DUAL_PORT_SUPPORT
} else if (index == LOTUS_DWC_U3) {
#else
} else if ((index == LOTUS_DWC_U3 && lotus_chip_u3_ability())) {
#endif
USB_DEBUG("U3 GUSB2PHYCFG(0xc200):0x%X\n",
readl(base + GUSB2PHYCFG));
USB_DEBUG("U3 GUSB3PIPECTL0(0xc2c0):0x%X\n",
readl(base + REG_GUSB3PIPECTL0));
USB_DEBUG("U3 GCTL(0xc110):0x%X\n",
readl(base + REG_GCTL));
}
}
#ifdef CONFIG_USB_DUAL_PORT_SUPPORT
void phy_usb_init(int index, int type)
#else
void phy_usb_init(int index)
#endif
{
#ifdef CONFIG_USB_DUAL_PORT_SUPPORT
unsigned int reg;
/* 7605v11 only support u2 host */
if (!lotus_chip_u3_ability() && index == LOTUS_DWC_U3)
return;
usb_scene_select(index, type);
#else
usb_scene_select(index);
#endif
#ifdef CONFIG_USB_DUAL_PORT_SUPPORT
reg = readl(MISC_REG_BASE + MISC_LOTUS_PHY2_CTRL_REG);
reg &= MISC_USB_SCENE_MASK;
/* Scene2 don't init U2 host. */
if (index == LOTUS_DWC_U2 && reg)
return;
if (index == LOTUS_DWC_U3) {
#else
if (index == LOTUS_DWC_U3 && lotus_chip_u3_ability()) {
#endif
printf("USB3 init...\n");
/* config u3 ctrl/u3 phy/u2 phy */
lotus_u3_ctrl_misc_config();
lotus_usb3_vbus_valid_en();
lotus_u2_phy_misc_config();
lotus_usb3_clk_init();
lotus_u3_phy_misc_config();
lotus_u2_phy_clk_init();
lotus_dwc_usb_config(index);
#ifdef CONFIG_USB_DUAL_PORT_SUPPORT
} else if (index == LOTUS_DWC_U2) {
#else
} else if ((index == LOTUS_DWC_U2) ||
(index == LOTUS_DWC_U3 && !lotus_chip_u3_ability())) {
#endif
printf("USB2 init...\n");
/* config u2 ctrl and u2 phy */
lotus_u2_ctrl_misc_config();
lotus_usb2_vbus_valid_en();
lotus_u2_phy_misc_config();
lotus_usb2_clk_init();
lotus_dwc_usb_config(index);
/* u2 phy eye diagram config */
lotus_u2_phy_eye_config();
}
/* According to IC, usb phy clk init need 1ms delay */
mdelay(1);
}
EXPORT_SYMBOL(phy_usb_init);
void xhci_hcd_stop(int index)
{
if (index == LOTUS_DWC_U3 && lotus_chip_u3_ability())
lotus_usb3_clk_exit();
else if ((index == LOTUS_DWC_U2) ||
(index == LOTUS_DWC_U3 && !lotus_chip_u3_ability()))
lotus_usb2_clk_exit();
}
EXPORT_SYMBOL(xhci_hcd_stop);
/* Some usb device can't be recognize in U-boot because
* of error state, so we power off them and wait a delay
* to restart them, similar to unplug and then insert.
*/
void lotus_usb_pwren_control(void)
{
u32 reg, default_val;
int delay __attribute__((unused));
#ifndef CONFIG_USB_DUAL_PORT_SUPPORT
delay = CONFIG_USB_PWREN_OFF_DELAY ?
CONFIG_USB_PWREN_OFF_DELAY : 100;
#endif
reg = readl(MISC_REG_BASE + MISC_USB2_CTRL_REG);
default_val = reg;
reg &= ~U2_PWREN_MODE_MASK; /* set PWREN_MISC mode */
reg |= U2_PWREN_OFF; /* turn off PWREN */
writel(reg, MISC_REG_BASE + MISC_USB2_CTRL_REG);
#ifndef CONFIG_USB_DUAL_PORT_SUPPORT
mdelay(delay);
#endif
reg = readl(MISC_REG_BASE + MISC_USB2_CTRL_REG);
reg &= ~U2_PWREN_MASK; /* turn on PWREN */
writel(reg, MISC_REG_BASE + MISC_USB2_CTRL_REG);
reg = default_val; /* set PWREN_CTRL mode(default val) */
writel(reg, MISC_REG_BASE + MISC_USB2_CTRL_REG);
/* U3 CTRL PWREN control */
reg = readl(MISC_REG_BASE + MISC_USB3_CTRL_REG);
default_val = reg;
reg &= ~U3_PWREN_MODE_MASK;
reg |= U3_PWREN_OFF; /* turn off PWREN */
writel(reg, MISC_REG_BASE + MISC_USB3_CTRL_REG);
USB_DEBUG("U3 MISC GCTL(0x1110):0x%X\n",
readl(MISC_REG_BASE + MISC_USB3_CTRL_REG));
#ifndef CONFIG_USB_DUAL_PORT_SUPPORT
mdelay(delay);
#endif
reg = readl(MISC_REG_BASE + MISC_USB3_CTRL_REG);
reg &= ~U3_PWREN_MASK; /* turn on PWREN */
writel(reg, MISC_REG_BASE + MISC_USB3_CTRL_REG);
USB_DEBUG("U3 MISC GCTL(0x1110):0x%X\n",
readl(MISC_REG_BASE + MISC_USB3_CTRL_REG));
reg = default_val; /* set PWREN_CTRL mode(default val) */
writel(reg, MISC_REG_BASE + MISC_USB3_CTRL_REG);
USB_DEBUG("U3 MISC GCTL(0x1110):0x%X\n",
readl(MISC_REG_BASE + MISC_USB3_CTRL_REG));
}
@@ -0,0 +1,307 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#ifdef CONFIG_PHY_LOTUS_USB
#include <asm/arch/platform.h>
#include <dm.h>
#include <linux/lotus/usb.h>
#include <usb/xhci.h>
#include "phy-usb.h"
/* offset 0x140 */
#define USB2_CTRL 0x140
#define USB2_CRG_DEFAULT_VAL 0x3b2f
#define USB2_UTMI_CKEN (0x1 << 12)
#define USB2_PHY_APB_CKEN (0x1 << 11)
#define USB2_REF_CKEN (0x1 << 9)
#define USB2_BUS_CKEN (0x1 << 8)
#define USB2_PHY_PLL_CKEN (0x1 << 4)
#define USB2_PHY_XTAL_CKEN (0x1 << 2)
#define USB2_FREECLK_CKSEL (0x1 << 13)
#define USB2_PHY_APB_RST (0x1 << 10)
#define USB2_VCC_SRST_REQ (0x1 << 3)
#define USB2_PHY_REQ (0x1 << 0)
#define USB2_PHY_PORT_TREQ (0x1 << 1)
#define GTXTHRCFG 0xc108
#define GRXTHRCFG 0xc10c
#define REG_GCTL 0xc110
#define REG_GUSB3PIPECTL0 0xc2c0
#define PCS_SSP_SOFT_RESET (0x1 << 31)
#define PORT_CAP_DIR (0x3 << 12)
#define PORT_SET_HOST (0x1 << 12)
#define PORT_DISABLE_SUSPEND (0x1 << 17)
#define USB2_G_TXTHRCFG 0x23100000
#define USB2_G_RXTHRCFG 0x23100000
/* PHY base register */
#define USB2_PHY_BASE_REG 0x100D0000
#define RG_PLL_EN_MASK 0x0003
#define RG_PLL_EN_VAL 0x0003
#define PHY_PLL_OFFSET 0x0014
#define USB_VBUS_IO_CONFIG_REG 0x100c007C
#define USB_VBUS_IO_CONFIG_VAL 0x0531
#define USB_PWREN_CONFIG_REG 0x100c0080
#define USB_PWREN_CONFIG_VAL 0x1
/* PHY eye config */
#define PHY_ANA_CFG_0_OFFSET 0x00
#define PHY_PRE_DRIVE_MASK (0xf << 24)
#define PHY_PRE_DRIVE_VAL (0x4 << 24)
#define PHY_HSTX_DE_MASK (0xf << 8)
#define PHY_HSTX_DE_VAL (0xc << 8)
#define PHY_HSTX_DEEN_BIT (0x1 << 5)
#define PHY_ANA_CFG_2_OFFSET 0x08
#define PHY_TX_TEST_BIT (0x1 << 20)
#define PHY_HALF_DEEM_BIT (0x1 << 21)
#define PHY_DISCONNECT_REFERENCE_MASK (0x7 << 16)
#define PHY_DISCONNECT_REFERENCE_VAL (0x2 << 16)
#define PHY_ANA_CFG_4_OFFSET 0x10
#define PHY_TX_REFERENCE_MASK (0x7 << 4)
#define PHY_TX_REFERENCE_VAL (0x5 << 4)
#define PHY_SQUELCH_REFERENCE_MASK (0x7 << 0)
#define PHY_SQUELCH_REFERENCE_VAL (0x5 << 0)
/* PHY trim config */
#define USB_TRIM_BASE_REG 0x12028004
#define USB_TRIM_VAL_MASK 0x001F
#define USB_TRIM_VAL_MIN 0x0009
#define USB_TRIM_VAL_MAX 0x001D
#define USB2_TRIM_OFFSET 0x0008
#define USB2_TRIM_MASK 0x1f00
#define usb2_trim_val(a) (((a) << 8) & USB2_TRIM_MASK)
#define USB2_TRIM_DEFAULT_VAL 0x000F
static uintptr_t xhci_base = 0;
int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
{
if ((hccr == NULL) || (hcor == NULL))
return -EINVAL;
xhci_base = USB3_CTRL_REG_BASE;
*hccr = (struct xhci_hccr *)(xhci_base);
*hcor = (struct xhci_hcor *)((uintptr_t) *hccr +
HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
return 0;
}
void usb2_eye_config(void)
{
unsigned int reg;
/* HSTX pre-drive strength */
reg = readl(USB2_PHY_BASE_REG + PHY_ANA_CFG_0_OFFSET);
reg &= ~PHY_PRE_DRIVE_MASK;
reg |= PHY_PRE_DRIVE_VAL;
writel(reg, USB2_PHY_BASE_REG + PHY_ANA_CFG_0_OFFSET);
/* HSTX de-emphasis strength */
reg = readl(USB2_PHY_BASE_REG + PHY_ANA_CFG_0_OFFSET);
reg &= ~PHY_HSTX_DE_MASK;
reg |= PHY_HSTX_DE_VAL;
writel(reg, USB2_PHY_BASE_REG + PHY_ANA_CFG_0_OFFSET);
/* HSTX de-emphasis enable */
reg = readl(USB2_PHY_BASE_REG + PHY_ANA_CFG_0_OFFSET);
reg |= PHY_HSTX_DEEN_BIT;
writel(reg, USB2_PHY_BASE_REG + PHY_ANA_CFG_0_OFFSET);
/* TX test bit */
reg = readl(USB2_PHY_BASE_REG + PHY_ANA_CFG_2_OFFSET);
reg |= PHY_TX_TEST_BIT;
writel(reg, USB2_PHY_BASE_REG + PHY_ANA_CFG_2_OFFSET);
/* TX half de-emphasis bit */
reg = readl(USB2_PHY_BASE_REG + PHY_ANA_CFG_2_OFFSET);
reg |= PHY_HALF_DEEM_BIT;
writel(reg, USB2_PHY_BASE_REG + PHY_ANA_CFG_2_OFFSET);
/* Disconnect reference voltage sel */
reg = readl(USB2_PHY_BASE_REG + PHY_ANA_CFG_2_OFFSET);
reg &= ~PHY_DISCONNECT_REFERENCE_MASK;
reg |= PHY_DISCONNECT_REFERENCE_VAL;
writel(reg, USB2_PHY_BASE_REG + PHY_ANA_CFG_2_OFFSET);
/* TX reference voltage sel */
reg = readl(USB2_PHY_BASE_REG + PHY_ANA_CFG_4_OFFSET);
reg &= ~PHY_TX_REFERENCE_MASK;
reg |= PHY_TX_REFERENCE_VAL;
writel(reg, USB2_PHY_BASE_REG + PHY_ANA_CFG_4_OFFSET);
/* Squlech reference voltage sel */
reg = readl(USB2_PHY_BASE_REG + PHY_ANA_CFG_4_OFFSET);
reg &= ~PHY_SQUELCH_REFERENCE_MASK;
reg |= PHY_SQUELCH_REFERENCE_VAL;
writel(reg, USB2_PHY_BASE_REG + PHY_ANA_CFG_4_OFFSET);
}
void usb2_trim_config(void)
{
unsigned int ret;
unsigned int reg;
unsigned int trim_val;
ret = readl(USB_TRIM_BASE_REG);
trim_val = (ret & USB_TRIM_VAL_MASK); /* get usb trim value */
reg = readl(USB2_PHY_BASE_REG + USB2_TRIM_OFFSET);
reg &= ~USB2_TRIM_MASK;
if ((trim_val >= USB_TRIM_VAL_MIN) && (trim_val <= USB_TRIM_VAL_MAX))
reg |= usb2_trim_val(trim_val);
else
reg |= usb2_trim_val(USB2_TRIM_DEFAULT_VAL);
writel(reg, USB2_PHY_BASE_REG + USB2_TRIM_OFFSET);
}
void phy_usb_init_crg_clk(int index)
{
unsigned int reg;
/* set usb2 CRG default val */
reg = USB2_CRG_DEFAULT_VAL;
writel(reg, CRG_REG_BASE + USB2_CTRL);
udelay(U_LEVEL6);
/* open UTMI clk */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg |= USB2_UTMI_CKEN;
writel(reg, CRG_REG_BASE + USB2_CTRL);
/* open phy apb clk */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg |= USB2_PHY_APB_CKEN;
writel(reg, CRG_REG_BASE + USB2_CTRL);
/* open ctrl ref clk */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg |= USB2_REF_CKEN;
writel(reg, CRG_REG_BASE + USB2_CTRL);
/* open bus clk */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg |= USB2_BUS_CKEN;
writel(reg, CRG_REG_BASE + USB2_CTRL);
/* open phy pll clk */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg |= USB2_PHY_PLL_CKEN;
writel(reg, CRG_REG_BASE + USB2_CTRL);
/* open phy xtal clk */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg |= USB2_PHY_XTAL_CKEN;
writel(reg, CRG_REG_BASE + USB2_CTRL);
/* freeclk_cksel_free */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg |= USB2_FREECLK_CKSEL;
writel(reg, CRG_REG_BASE + USB2_CTRL);
udelay(U_LEVEL5);
}
void phy_usb_init(int index)
{
unsigned int reg;
/* VBUS config */
reg = USB_VBUS_IO_CONFIG_VAL;
writel(reg, USB_VBUS_IO_CONFIG_REG);
reg = USB_PWREN_CONFIG_VAL;
writel(reg, USB_PWREN_CONFIG_REG);
/* init crg and clk */
phy_usb_init_crg_clk(index);
/* release phy apb */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg &= ~USB2_PHY_APB_RST;
writel(reg, CRG_REG_BASE + USB2_CTRL);
udelay(U_LEVEL5);
/* por noreset */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg &= ~USB2_PHY_REQ;
writel(reg, CRG_REG_BASE + USB2_CTRL);
reg = readl(USB2_PHY_BASE_REG + PHY_PLL_OFFSET);
reg &= ~RG_PLL_EN_MASK;
reg |= RG_PLL_EN_VAL;
writel(reg, USB2_PHY_BASE_REG + PHY_PLL_OFFSET);
udelay(U_LEVEL10);
/* cancel TPOR */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg &= ~USB2_PHY_PORT_TREQ;
writel(reg, CRG_REG_BASE + USB2_CTRL);
udelay(U_LEVEL6);
/* vcc reset */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg &= ~USB2_VCC_SRST_REQ;
writel(reg, CRG_REG_BASE + USB2_CTRL);
/* USB2 Controller configs */
reg = readl(USB3_CTRL_REG_BASE + REG_GUSB3PIPECTL0);
reg |= PCS_SSP_SOFT_RESET;
writel(reg, USB3_CTRL_REG_BASE + REG_GUSB3PIPECTL0);
udelay(U_LEVEL2);
reg = readl(USB3_CTRL_REG_BASE + REG_GCTL);
reg &= ~PORT_CAP_DIR;
reg |= PORT_SET_HOST; /* [13:12] 01: Host; 10: Device; 11: OTG */
writel(reg, USB3_CTRL_REG_BASE + REG_GCTL);
udelay(U_LEVEL2);
reg = readl(USB3_CTRL_REG_BASE + REG_GUSB3PIPECTL0);
reg &= ~PCS_SSP_SOFT_RESET;
reg &= ~PORT_DISABLE_SUSPEND; /* disable suspend */
writel(reg, USB3_CTRL_REG_BASE + REG_GUSB3PIPECTL0);
udelay(U_LEVEL2);
writel(USB2_G_TXTHRCFG, USB3_CTRL_REG_BASE + GTXTHRCFG);
writel(USB2_G_RXTHRCFG, USB3_CTRL_REG_BASE + GRXTHRCFG);
udelay(U_LEVEL2);
/* USB2 eye config */
usb2_eye_config();
/* USB2 trim config */
usb2_trim_config();
}
EXPORT_SYMBOL(phy_usb_init);
void xhci_hcd_stop(int index)
{
unsigned int reg;
/* por noreset */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg |= USB2_PHY_REQ;
writel(reg, CRG_REG_BASE + USB2_CTRL);
udelay(U_LEVEL10);
/* cancel TPOR */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg |= USB2_PHY_PORT_TREQ;
writel(reg, CRG_REG_BASE + USB2_CTRL);
udelay(U_LEVEL6);
/* vcc reset */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg |= USB2_VCC_SRST_REQ;
writel(reg, CRG_REG_BASE + USB2_CTRL);
}
EXPORT_SYMBOL(xhci_hcd_stop);
#endif
@@ -0,0 +1,313 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#include <asm/arch/platform.h>
#include <dm.h>
#include <linux/lotus/usb.h>
#include <usb.h>
#include <usb/xhci.h>
#include "phy-usb.h"
#ifdef __USB_DEBUG
#define USB_DEBUG(...) printf(__VA_ARGS__)
#else
#define USB_DEBUG(...)
#endif
#define GTXTHRCFG 0xc108
#define GRXTHRCFG 0xc10c
#define REG_GCTL 0xc110
#define GUSB2PHYCFG 0xc200
#define REG_GUSB3PIPECTL0 0xc2c0
#define PCS_SSP_SOFT_RESET (0x1 << 31)
#define USBTRDTIM_MASK 0x00003c00
#define USBTRDTIM_16BIT (0x5 << 10)
#define USBTRDTIM_8BIT (0x9 << 10)
#define PHYIF (0x1 << 3)
#define SUSPENDUSB20 (0x1 << 6)
#define ENBLSLPM (0x1 << 8)
#define LSIPD_MASK (0x7 << 19)
#define LSIPD_3_BIT (0x2 << 19)
#define U2_FREECLK_EXISTS (0x1 << 30)
#define PORT_CAP_DIR (0x3 << 12)
#define PORT_SET_HOST (0x1 << 12)
#define PORT_DISABLE_SUSPEND (0x1 << 17)
#define USB2_G_TXTHRCFG 0x23100000
#define USB2_G_RXTHRCFG 0x23100000
/* CRG PERI_CRG80: usb clk & reset, offset 0x140 */
#define USB2_CTRL 0x140
#define USB2_CRG_DEF_VAL 0x1307
#define USB2_PHY_CFG_REQ (0x1 << 0)
#define USB2_PHY_PORT_SRST (0x1 << 1)
#define USB2_PHY_XTAL_CKEN (0x1 << 2)
#define USB2_VCC_SRST_REQ (0x1 << 3)
#define USB2_BUS_CKEN (0x1 << 8)
#define USB2_REF_CKEN (0x1 << 9)
#define USB2_UTMI_CKEN (0x1 << 12)
#define USB2_FREECLK_CKSEL (0x1 << 13)
/* u2 ctrl use reg, reg's misc_base=0x12028000 */
#define MISC_USB2_CTRL_REG 0x24
#define U2_BUS_FILTER_BYPASS (0xf << 0)
#define U2_PWREN_MODE_MASK (0x1 << 4)
#define U2_PWREN_MODE_MISC (0x0 << 4)
#define U2_PWREN_MODE_CTRL (0x1 << 4)
#define U2_OVERCURR_MODE_MASK (0x1 << 5)
#define U2_OVERCURR_MODE_DISABLE (0x0 << 5)
#define U2_OVERCURR_MODE_ENABLE (0x1 << 5)
#define U2_PWREN_MASK (0x1 << 6)
#define U2_PWREN_ON (0x0 << 6)
#define U2_PWREN_OFF (0x1 << 6)
#define U2_OVERCURR_MASK (0x1 << 7)
#define U2_OVERCURR_ON (0x0 << 7)
#define U2_OVERCURR_OFF (0x1 << 7)
#define U2_FLADJ_30MHZ (0x20 << 13)
/* Outer phy use reg, reg's misc_base=0x12028000 */
#define MISC_OUT_PHY2_CTRL_REG 0x2C
#define USB2_PLL_EN (0x1 << 0)
#define USB2_UTMI_DATABUS16_8 (0x1 << 1)
#define MISC_USB2_VBUS_REG 0x980
#define U2_VBUS_EN (0x1 << 0)
static uintptr_t xhci_base;
int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
{
if ((hccr == NULL) || (hcor == NULL))
return -EINVAL;
xhci_base = USB2_CTRL_REG_BASE;
*hccr = (struct xhci_hccr *)(xhci_base);
*hcor = (struct xhci_hcor *)((uintptr_t) *hccr +
HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
return 0;
}
void xhci_hcd_stop(int index)
{
unsigned int reg;
/* por reset */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg |= USB2_PHY_CFG_REQ;
reg |= USB2_PHY_PORT_SRST;
writel(reg, CRG_REG_BASE + USB2_CTRL);
udelay(U_LEVEL10);
/* vcc reset */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg |= USB2_VCC_SRST_REQ;
writel(reg, CRG_REG_BASE + USB2_CTRL);
}
EXPORT_SYMBOL(xhci_hcd_stop);
static void usb2_eye_config(void)
{
}
static void usb2_trim_config(void)
{
}
static void lotus_u2_phy_clk_init(void)
{
unsigned int reg;
/* enable u2 phy clk and do reset */
reg = (USB2_PHY_CFG_REQ | USB2_PHY_PORT_SRST | \
USB2_PHY_XTAL_CKEN);
writel(reg, CRG_REG_BASE + USB2_CTRL);
USB_DEBUG("USB2_CRG(0x12010140), expext:0x7,"
"acutal:0x%X\n", readl(CRG_REG_BASE + USB2_CTRL));
udelay(1);
/* undo phy reset */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg &= ~USB2_PHY_CFG_REQ;
reg &= ~USB2_PHY_PORT_SRST;
writel(reg, CRG_REG_BASE + USB2_CTRL);
USB_DEBUG("USB2_CRG(0x12010140), expext:0x4,"
"acutal:0x%X\n", readl(CRG_REG_BASE + USB2_CTRL));
}
static void lotus_u2_ctrl_clk_init(void)
{
unsigned int reg;
/* enable u2 ctrl clk and do reset */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg |= (USB2_VCC_SRST_REQ | USB2_BUS_CKEN | USB2_REF_CKEN |
USB2_UTMI_CKEN);
writel(reg, CRG_REG_BASE + USB2_CTRL);
USB_DEBUG("USB2_CRG(0x12010140), expext:0x130c,"
"acutal:0x%X\n", readl(CRG_REG_BASE + USB2_CTRL));
udelay(1);
/* undo ctrl vcc reset */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg &= ~USB2_VCC_SRST_REQ;
writel(reg, CRG_REG_BASE + USB2_CTRL);
USB_DEBUG("USB2_CRG(0x12010140), expext:0x1304,"
"acutal:0x%X\n", readl(CRG_REG_BASE + USB2_CTRL));
}
static void lotus_usb2_clk_init(void)
{
lotus_u2_phy_clk_init();
lotus_u2_ctrl_clk_init();
}
static void lotus_u2_phy_misc_config(void)
{
unsigned int reg;
/* MISC_CTRL11: config 0x3 according to IC. */
reg = 0;
reg |= (USB2_PLL_EN | USB2_UTMI_DATABUS16_8);
writel(reg, MISC_REG_BASE + MISC_OUT_PHY2_CTRL_REG);
USB_DEBUG("MISC_OUT_PHY2_CTRL_REG(0x1202802c),"
"expext:0x3, acutal:0x%X\n",
readl(MISC_REG_BASE + MISC_OUT_PHY2_CTRL_REG));
}
static inline void lotus_usb2_vbus_valid_en(void)
{
unsigned int reg;
/* enable U2 vbus valid */
reg = readl(MISC_REG_BASE + MISC_USB2_VBUS_REG);
reg |= U2_VBUS_EN;
writel(reg, MISC_REG_BASE + MISC_USB2_VBUS_REG);
}
static void lotus_dwc_data_width_config(enum usb_phy_width_mode mode)
{
unsigned int reg, base = USB2_CTRL_REG_BASE;
/* GUSB2PHYCFG register: config val 0x40001548(HS/FS) or
* 0x00381548(LS) according to IC.
*
* USBTRDTIM: USB 2.0 Turnaround Time in PHY clocks.
* PHYIF: 1 UTMI+ PHY is 16-bit, 0 UTMI+ PHY is 8-bit.
*/
reg = 0;
switch (mode) {
case PHY_WIDTH_8BIT:
/* 8-bits usb phy configure */
reg |= USBTRDTIM_8BIT;
reg &= ~PHYIF;
break;
case PHY_WIDTH_16BIT:
/* 16-bits usb phy configure */
reg |= (USBTRDTIM_16BIT | PHYIF);
break;
default:
printf("usb phy width config val error.\n");
return;
}
writel(reg, base + GUSB2PHYCFG);
}
static void lotus_dwc_usb_config(void)
{
unsigned int reg, base = USB2_CTRL_REG_BASE;
reg = readl(base + REG_GUSB3PIPECTL0);
reg |= PCS_SSP_SOFT_RESET;
writel(reg, base + REG_GUSB3PIPECTL0);
udelay(U_LEVEL2);
reg = readl(base + REG_GCTL);
reg &= ~PORT_CAP_DIR;
reg |= PORT_SET_HOST; /* host mode is default. */
writel(reg, base + REG_GCTL);
udelay(U_LEVEL2);
reg = readl(base + REG_GUSB3PIPECTL0);
reg &= ~PCS_SSP_SOFT_RESET;
reg &= ~PORT_DISABLE_SUSPEND; /* disable suspend */
writel(reg, base + REG_GUSB3PIPECTL0);
udelay(U_LEVEL2);
writel(USB2_G_TXTHRCFG, base + GTXTHRCFG);
writel(USB2_G_RXTHRCFG, base + GRXTHRCFG);
udelay(U_LEVEL2);
lotus_dwc_data_width_config(PHY_WIDTH_16BIT);
reg = readl(base + GUSB2PHYCFG);
reg &= ~SUSPENDUSB20; /* disable suspend */
reg &= ~ENBLSLPM; /* suspend not transfer to external PHY */
reg &= ~U2_FREECLK_EXISTS;
reg &= ~LSIPD_MASK;
reg |= LSIPD_3_BIT;
writel(reg, base + GUSB2PHYCFG);
USB_DEBUG("GUSB2PHYCFG(0xc200):0x%X\n",
readl(base + GUSB2PHYCFG));
USB_DEBUG("GUSB3PIPECTL0(0xc2c0):0x%X\n",
readl(base + REG_GUSB3PIPECTL0));
USB_DEBUG("GCTL(0xc110):0x%X\n",
readl(base + REG_GCTL));
}
void phy_usb_init(int index)
{
/* u2 utmi data bus config, u2 phy pll en */
lotus_u2_phy_misc_config();
/* init crg and clk */
lotus_usb2_clk_init();
/* enable u2 vbusvalid */
lotus_usb2_vbus_valid_en();
/* USB2 Controller configs */
lotus_dwc_usb_config();
/* lotus phy eye diagram config */
usb2_eye_config();
/* lotus phy trim config */
usb2_trim_config();
}
EXPORT_SYMBOL(phy_usb_init);
/* Some usb device can't be recognize in U-boot because
* of error state, so we power off them and wait a delay
* to restart them, similar to unplug and then insert.
*/
void lotus_usb_pwren_control(void)
{
u32 reg, default_val, delay;
delay = CONFIG_USB_PWREN_OFF_DELAY ?
CONFIG_USB_PWREN_OFF_DELAY : 100;
reg = readl(MISC_REG_BASE + MISC_USB2_CTRL_REG);
default_val = reg;
reg &= ~U2_PWREN_MODE_MASK; /* set PWREN_MISC mode */
reg |= U2_PWREN_OFF; /* turn off PWREN */
writel(reg, MISC_REG_BASE + MISC_USB2_CTRL_REG);
mdelay(delay);
reg = readl(MISC_REG_BASE + MISC_USB2_CTRL_REG);
reg &= ~U2_PWREN_MASK; /* turn on PWREN */
writel(reg, MISC_REG_BASE + MISC_USB2_CTRL_REG);
reg = default_val; /* set PWREN_CTRL mode(default val) */
writel(reg, MISC_REG_BASE + MISC_USB2_CTRL_REG);
}
@@ -0,0 +1,307 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#ifdef CONFIG_PHY_LOTUS_USB
#include <asm/arch/platform.h>
#include <dm.h>
#include <linux/lotus/usb.h>
#include <usb/xhci.h>
#include "phy-usb.h"
/* offset 0x140 */
#define USB2_CTRL 0x140
#define USB2_CRG_DEFAULT_VAL 0x3b2f
#define USB2_UTMI_CKEN (0x1 << 12)
#define USB2_PHY_APB_CKEN (0x1 << 11)
#define USB2_REF_CKEN (0x1 << 9)
#define USB2_BUS_CKEN (0x1 << 8)
#define USB2_PHY_PLL_CKEN (0x1 << 4)
#define USB2_PHY_XTAL_CKEN (0x1 << 2)
#define USB2_FREECLK_CKSEL (0x1 << 13)
#define USB2_PHY_APB_RST (0x1 << 10)
#define USB2_VCC_SRST_REQ (0x1 << 3)
#define USB2_PHY_REQ (0x1 << 0)
#define USB2_PHY_PORT_TREQ (0x1 << 1)
#define GTXTHRCFG 0xc108
#define GRXTHRCFG 0xc10c
#define REG_GCTL 0xc110
#define REG_GUSB3PIPECTL0 0xc2c0
#define PCS_SSP_SOFT_RESET (0x1 << 31)
#define PORT_CAP_DIR (0x3 << 12)
#define PORT_SET_HOST (0x1 << 12)
#define PORT_DISABLE_SUSPEND (0x1 << 17)
#define USB2_G_TXTHRCFG 0x23100000
#define USB2_G_RXTHRCFG 0x23100000
/* PHY base register */
#define USB2_PHY_BASE_REG 0x100D0000
#define RG_PLL_EN_MASK 0x0003
#define RG_PLL_EN_VAL 0x0003
#define PHY_PLL_OFFSET 0x0014
#define USB_VBUS_IO_CONFIG_REG 0x100c007C
#define USB_VBUS_IO_CONFIG_VAL 0x0531
#define USB_PWREN_CONFIG_REG 0x100c0080
#define USB_PWREN_CONFIG_VAL 0x1
/* PHY eye config */
#define PHY_ANA_CFG_0_OFFSET 0x00
#define PHY_PRE_DRIVE_MASK (0xf << 24)
#define PHY_PRE_DRIVE_VAL (0x4 << 24)
#define PHY_HSTX_DE_MASK (0xf << 8)
#define PHY_HSTX_DE_VAL (0xc << 8)
#define PHY_HSTX_DEEN_BIT (0x1 << 5)
#define PHY_ANA_CFG_2_OFFSET 0x08
#define PHY_TX_TEST_BIT (0x1 << 20)
#define PHY_HALF_DEEM_BIT (0x1 << 21)
#define PHY_DISCONNECT_REFERENCE_MASK (0x7 << 16)
#define PHY_DISCONNECT_REFERENCE_VAL (0x2 << 16)
#define PHY_ANA_CFG_4_OFFSET 0x10
#define PHY_TX_REFERENCE_MASK (0x7 << 4)
#define PHY_TX_REFERENCE_VAL (0x5 << 4)
#define PHY_SQUELCH_REFERENCE_MASK (0x7 << 0)
#define PHY_SQUELCH_REFERENCE_VAL (0x5 << 0)
/* PHY trim config */
#define USB_TRIM_BASE_REG 0x12028004
#define USB_TRIM_VAL_MASK 0x001F
#define USB_TRIM_VAL_MIN 0x0009
#define USB_TRIM_VAL_MAX 0x001D
#define USB2_TRIM_OFFSET 0x0008
#define USB2_TRIM_MASK 0x1f00
#define usb2_trim_val(a) (((a) << 8) & USB2_TRIM_MASK)
#define USB2_TRIM_DEFAULT_VAL 0x000F
static uintptr_t xhci_base = 0;
int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
{
if ((hccr == NULL) || (hcor == NULL))
return -EINVAL;
xhci_base = USB3_CTRL_REG_BASE;
*hccr = (struct xhci_hccr *)(xhci_base);
*hcor = (struct xhci_hcor *)((uintptr_t) *hccr +
HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
return 0;
}
void usb2_eye_config(void)
{
unsigned int reg;
/* HSTX pre-drive strength */
reg = readl(USB2_PHY_BASE_REG + PHY_ANA_CFG_0_OFFSET);
reg &= ~PHY_PRE_DRIVE_MASK;
reg |= PHY_PRE_DRIVE_VAL;
writel(reg, USB2_PHY_BASE_REG + PHY_ANA_CFG_0_OFFSET);
/* HSTX de-emphasis strength */
reg = readl(USB2_PHY_BASE_REG + PHY_ANA_CFG_0_OFFSET);
reg &= ~PHY_HSTX_DE_MASK;
reg |= PHY_HSTX_DE_VAL;
writel(reg, USB2_PHY_BASE_REG + PHY_ANA_CFG_0_OFFSET);
/* HSTX de-emphasis enable */
reg = readl(USB2_PHY_BASE_REG + PHY_ANA_CFG_0_OFFSET);
reg |= PHY_HSTX_DEEN_BIT;
writel(reg, USB2_PHY_BASE_REG + PHY_ANA_CFG_0_OFFSET);
/* TX test bit */
reg = readl(USB2_PHY_BASE_REG + PHY_ANA_CFG_2_OFFSET);
reg |= PHY_TX_TEST_BIT;
writel(reg, USB2_PHY_BASE_REG + PHY_ANA_CFG_2_OFFSET);
/* TX half de-emphasis bit */
reg = readl(USB2_PHY_BASE_REG + PHY_ANA_CFG_2_OFFSET);
reg |= PHY_HALF_DEEM_BIT;
writel(reg, USB2_PHY_BASE_REG + PHY_ANA_CFG_2_OFFSET);
/* Disconnect reference voltage sel */
reg = readl(USB2_PHY_BASE_REG + PHY_ANA_CFG_2_OFFSET);
reg &= ~PHY_DISCONNECT_REFERENCE_MASK;
reg |= PHY_DISCONNECT_REFERENCE_VAL;
writel(reg, USB2_PHY_BASE_REG + PHY_ANA_CFG_2_OFFSET);
/* TX reference voltage sel */
reg = readl(USB2_PHY_BASE_REG + PHY_ANA_CFG_4_OFFSET);
reg &= ~PHY_TX_REFERENCE_MASK;
reg |= PHY_TX_REFERENCE_VAL;
writel(reg, USB2_PHY_BASE_REG + PHY_ANA_CFG_4_OFFSET);
/* Squlech reference voltage sel */
reg = readl(USB2_PHY_BASE_REG + PHY_ANA_CFG_4_OFFSET);
reg &= ~PHY_SQUELCH_REFERENCE_MASK;
reg |= PHY_SQUELCH_REFERENCE_VAL;
writel(reg, USB2_PHY_BASE_REG + PHY_ANA_CFG_4_OFFSET);
}
void usb2_trim_config(void)
{
unsigned int ret;
unsigned int reg;
unsigned int trim_val;
ret = readl(USB_TRIM_BASE_REG);
trim_val = (ret & USB_TRIM_VAL_MASK); /* get usb trim value */
reg = readl(USB2_PHY_BASE_REG + USB2_TRIM_OFFSET);
reg &= ~USB2_TRIM_MASK;
if ((trim_val >= USB_TRIM_VAL_MIN) && (trim_val <= USB_TRIM_VAL_MAX))
reg |= usb2_trim_val(trim_val);
else
reg |= usb2_trim_val(USB2_TRIM_DEFAULT_VAL);
writel(reg, USB2_PHY_BASE_REG + USB2_TRIM_OFFSET);
}
void phy_usb_init_crg_clk(int index)
{
unsigned int reg;
/* set usb2 CRG default val */
reg = USB2_CRG_DEFAULT_VAL;
writel(reg, CRG_REG_BASE + USB2_CTRL);
udelay(U_LEVEL6);
/* open UTMI clk */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg |= USB2_UTMI_CKEN;
writel(reg, CRG_REG_BASE + USB2_CTRL);
/* open phy apb clk */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg |= USB2_PHY_APB_CKEN;
writel(reg, CRG_REG_BASE + USB2_CTRL);
/* open ctrl ref clk */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg |= USB2_REF_CKEN;
writel(reg, CRG_REG_BASE + USB2_CTRL);
/* open bus clk */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg |= USB2_BUS_CKEN;
writel(reg, CRG_REG_BASE + USB2_CTRL);
/* open phy pll clk */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg |= USB2_PHY_PLL_CKEN;
writel(reg, CRG_REG_BASE + USB2_CTRL);
/* open phy xtal clk */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg |= USB2_PHY_XTAL_CKEN;
writel(reg, CRG_REG_BASE + USB2_CTRL);
/* freeclk_cksel_free */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg |= USB2_FREECLK_CKSEL;
writel(reg, CRG_REG_BASE + USB2_CTRL);
udelay(U_LEVEL5);
}
void phy_usb_init(int index)
{
unsigned int reg;
/* VBUS config */
reg = USB_VBUS_IO_CONFIG_VAL;
writel(reg, USB_VBUS_IO_CONFIG_REG);
reg = USB_PWREN_CONFIG_VAL;
writel(reg, USB_PWREN_CONFIG_REG);
/* init crg and clk */
phy_usb_init_crg_clk(index);
/* release phy apb */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg &= ~USB2_PHY_APB_RST;
writel(reg, CRG_REG_BASE + USB2_CTRL);
udelay(U_LEVEL5);
/* por noreset */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg &= ~USB2_PHY_REQ;
writel(reg, CRG_REG_BASE + USB2_CTRL);
reg = readl(USB2_PHY_BASE_REG + PHY_PLL_OFFSET);
reg &= ~RG_PLL_EN_MASK;
reg |= RG_PLL_EN_VAL;
writel(reg, USB2_PHY_BASE_REG + PHY_PLL_OFFSET);
udelay(U_LEVEL10);
/* cancel TPOR */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg &= ~USB2_PHY_PORT_TREQ;
writel(reg, CRG_REG_BASE + USB2_CTRL);
udelay(U_LEVEL6);
/* vcc reset */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg &= ~USB2_VCC_SRST_REQ;
writel(reg, CRG_REG_BASE + USB2_CTRL);
/* USB2 Controller configs */
reg = readl(USB3_CTRL_REG_BASE + REG_GUSB3PIPECTL0);
reg |= PCS_SSP_SOFT_RESET;
writel(reg, USB3_CTRL_REG_BASE + REG_GUSB3PIPECTL0);
udelay(U_LEVEL2);
reg = readl(USB3_CTRL_REG_BASE + REG_GCTL);
reg &= ~PORT_CAP_DIR;
reg |= PORT_SET_HOST; /* [13:12] 01: Host; 10: Device; 11: OTG */
writel(reg, USB3_CTRL_REG_BASE + REG_GCTL);
udelay(U_LEVEL2);
reg = readl(USB3_CTRL_REG_BASE + REG_GUSB3PIPECTL0);
reg &= ~PCS_SSP_SOFT_RESET;
reg &= ~PORT_DISABLE_SUSPEND; /* disable suspend */
writel(reg, USB3_CTRL_REG_BASE + REG_GUSB3PIPECTL0);
udelay(U_LEVEL2);
writel(USB2_G_TXTHRCFG, USB3_CTRL_REG_BASE + GTXTHRCFG);
writel(USB2_G_RXTHRCFG, USB3_CTRL_REG_BASE + GRXTHRCFG);
udelay(U_LEVEL2);
/* USB2 eye config */
usb2_eye_config();
/* USB2 trim config */
usb2_trim_config();
}
EXPORT_SYMBOL(phy_usb_init);
void xhci_hcd_stop(int index)
{
unsigned int reg;
/* por noreset */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg |= USB2_PHY_REQ;
writel(reg, CRG_REG_BASE + USB2_CTRL);
udelay(U_LEVEL10);
/* cancel TPOR */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg |= USB2_PHY_PORT_TREQ;
writel(reg, CRG_REG_BASE + USB2_CTRL);
udelay(U_LEVEL6);
/* vcc reset */
reg = readl(CRG_REG_BASE + USB2_CTRL);
reg |= USB2_VCC_SRST_REQ;
writel(reg, CRG_REG_BASE + USB2_CTRL);
}
EXPORT_SYMBOL(xhci_hcd_stop);
#endif
@@ -0,0 +1,2 @@
obj-y += usb3_drv.o usb3_pcd.o usb3_intr.o usb3_pcd_intr.o usb3_prot.o
@@ -0,0 +1,157 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#ifndef __DEBUG_H__
#define __DEBUG_H__
#include "types.h"
#include "platform.h"
#include <stdarg.h>
#ifdef DEBUG
#define MHZ (1000 * 1000)
#define CFG_CLK_OTHER (19200000)
/* -----------------------------------------------------------------------
* Serial Configuration
*/
#define CONFIG_PL011_CLOCK CFG_CLK_OTHER
#define CONFIG_CONS_INDEX 0 /* select the default console */
#define CONFIG_BAUDRATE 115200
#define CFG_SERIAL0 REG_BASE_UART6
/*
* ARM PrimeCell UART's (PL010 & PL011)
* ------------------------------------
*
* Definitions common to both PL010 & PL011
*
*/
#define UART_PL01X_DR 0x00 /* Data read or written from the interface. */
#define UART_PL01X_RSR 0x04 /* Receive status register (Read). */
#define UART_PL01X_ECR 0x04 /* Error clear register (Write). */
#define UART_PL01X_ECR 0x18 /* Flag register (Read only). */
#define UART_PL01X_RSR_OE 0x08
#define UART_PL01X_RSR_BE 0x04
#define UART_PL01X_RSR_PE 0x02
#define UART_PL01X_RSR_FE 0x01
#define UART_PL01X_FR_TXFE 0x80
#define UART_PL01X_FR_RXFF 0x40
#define UART_PL01X_FR_TXFF 0x20
#define UART_PL01X_FR_RXFE 0x10
#define UART_PL01X_FR_BUSY 0x08
#define UART_PL01X_FR_TMSK (UART_PL01X_FR_TXFF + UART_PL01X_FR_BUSY)
/*
* PL010 definitions
*
*/
#define UART_PL010_LCRH 0x08 /* Line control register, high byte. */
#define UART_PL010_LCRM 0x0C /* Line control register, middle byte. */
#define UART_PL010_LCRL 0x10 /* Line control register, low byte. */
#define UART_PL010_CR 0x14 /* Control register. */
#define UART_PL010_IIR 0x1C /* Interrupt indentification register (Read). */
#define UART_PL010_ICR 0x1C /* Interrupt clear register (Write). */
#define UART_PL010_ILPR 0x20 /* IrDA low power counter register. */
#define UART_PL010_CR_LPE (1 << 7)
#define UART_PL010_CR_RTIE (1 << 6)
#define UART_PL010_CR_TIE (1 << 5)
#define UART_PL010_CR_RIE (1 << 4)
#define UART_PL010_CR_MSIE (1 << 3)
#define UART_PL010_CR_IIRLP (1 << 2)
#define UART_PL010_CR_SIREN (1 << 1)
#define UART_PL010_CR_UARTEN (1 << 0)
#define UART_PL010_LCRH_WLEN_8 (3 << 5)
#define UART_PL010_LCRH_WLEN_7 (2 << 5)
#define UART_PL010_LCRH_WLEN_6 (1 << 5)
#define UART_PL010_LCRH_WLEN_5 (0 << 5)
#define UART_PL010_LCRH_FEN (1 << 4)
#define UART_PL010_LCRH_STP2 (1 << 3)
#define UART_PL010_LCRH_EPS (1 << 2)
#define UART_PL010_LCRH_PEN (1 << 1)
#define UART_PL010_LCRH_BRK (1 << 0)
#define UART_PL010_BAUD_460800 1
#define UART_PL010_BAUD_230400 3
#define UART_PL010_BAUD_115200 7
#define UART_PL010_BAUD_57600 15
#define UART_PL010_BAUD_38400 23
#define UART_PL010_BAUD_19200 47
#define UART_PL010_BAUD_14400 63
#define UART_PL010_BAUD_9600 95
#define UART_PL010_BAUD_4800 191
#define UART_PL010_BAUD_2400 383
#define UART_PL010_BAUD_1200 767
/*
* PL011 definitions
*
*/
#define UART_PL011_IBRD 0x24
#define UART_PL011_FBRD 0x28
#define UART_PL011_LCRH 0x2C
#define UART_PL011_CR 0x30
#define UART_PL011_IMSC 0x38
#define UART_PL011_PERIPH_ID0 0xFE0
#define UART_PL011_LCRH_SPS (1 << 7)
#define UART_PL011_LCRH_WLEN_8 (3 << 5)
#define UART_PL011_LCRH_WLEN_7 (2 << 5)
#define UART_PL011_LCRH_WLEN_6 (1 << 5)
#define UART_PL011_LCRH_WLEN_5 (0 << 5)
#define UART_PL011_LCRH_FEN (1 << 4)
#define UART_PL011_LCRH_STP2 (1 << 3)
#define UART_PL011_LCRH_EPS (1 << 2)
#define UART_PL011_LCRH_PEN (1 << 1)
#define UART_PL011_LCRH_BRK (1 << 0)
#define UART_PL011_CR_CTSEN (1 << 15)
#define UART_PL011_CR_RTSEN (1 << 14)
#define UART_PL011_CR_OUT2 (1 << 13)
#define UART_PL011_CR_OUT1 (1 << 12)
#define UART_PL011_CR_RTS (1 << 11)
#define UART_PL011_CR_DTR (1 << 10)
#define UART_PL011_CR_RXE (1 << 9)
#define UART_PL011_CR_TXE (1 << 8)
#define UART_PL011_CR_LPE (1 << 7)
#define UART_PL011_CR_IIRLP (1 << 2)
#define UART_PL011_CR_SIREN (1 << 1)
#define UART_PL011_CR_UARTEN (1 << 0)
#define UART_PL011_IMSC_OEIM (1 << 10)
#define UART_PL011_IMSC_BEIM (1 << 9)
#define UART_PL011_IMSC_PEIM (1 << 8)
#define UART_PL011_IMSC_FEIM (1 << 7)
#define UART_PL011_IMSC_RTIM (1 << 6)
#define UART_PL011_IMSC_TXIM (1 << 5)
#define UART_PL011_IMSC_RXIM (1 << 4)
#define UART_PL011_IMSC_DSRMIM (1 << 3)
#define UART_PL011_IMSC_DCDMIM (1 << 2)
#define UART_PL011_IMSC_CTSMIM (1 << 1)
#define UART_PL011_IMSC_RIMIM (1 << 0)
void console_init();
void __xprintf(const char *fmt, va_list ap, void (*xputc)(unsigned n, void *cookie), void *cookie);
void cprintf(const char *fmt, ...);
#define debug_init() console_init()
#define DEBUG_PRINTF cprintf
#define msglogstr(x) cprintf(x);
#else
#define debug_init()
#define debug_printf(exp, ...)
#define msglogstr(x)
#endif
#endif /* end of __DEBUG_H__ */
@@ -0,0 +1,65 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#ifndef __ONCHIPROM_H__
#define __ONCHIPROM_H__
#include "platform.h"
/* define vrl table of xloader loaded address & size */
#define VRL_TABLE_LOAD_ADDRESS REG_BASE_LP_RAM
#define VRL_TABLE_LOAD_SIZE (4 * 1024)
/* define xloader loaded address & size */
#define XLOADER_IMAGE_LOAD_ADDRESS (VRL_TABLE_LOAD_ADDRESS + VRL_TABLE_LOAD_SIZE)
#ifdef EDA_SPEEDUP
#define XLOADER_IMAGE_LOAD_SIZE (4 * 1024)
#else
#define XLOADER_IMAGE_LOAD_SIZE (28 * 1024)
#endif
#define ONCHIPROM_IMAGE_LOAD_MAX (100 * 1024)
/* define ufs work space area */
#define UFS_STATIC_WORK_SPACE_ADDRESS (REG_BASE_LP_RAM + 0x1C000)
#define UFS_STATIC_WORK_SPACE_SIZE (0xE00)
/* define onchiprom static area */
#define ONCHIPROM_STATIC_AREA_ADDRESS (REG_BASE_LP_RAM + 0x1CE00)
#define ONCHIPROM_STATIC_AREA_SIZE (0x100)
/* define secure engine static area */
#define SECURE_ENGINE_STATIC_AREA_ADDRESS (REG_BASE_LP_RAM + 0x1CF00)
#define SECURE_ENGINE_STATIC_AREA_SIZE (0x100)
/* define secure engine work space address & size */
#define SECURE_ENGINE_WORK_SPACE_ADDRESS (REG_BASE_LP_RAM + 0x1D000)
#define SECURE_ENGINE_WORK_SPACE_SIZE (0x1800)
/* define secure engine work space address & size */
#define USB_STATIC_WORK_SPACE_ADDRESS (REG_BASE_LP_RAM + 0x1E800)
#define USB_STATIC_WORK_SPACE_SIZE (0x1800)
/* xloader image length address */
#define VRL_TABLE_IMAGE_LENGTH_OFFEST_ADDR (0xFFC)
#define LPRAM_MEMORY_MAP_OFFEST_ADDRESS SECURE_ENGINE_STATIC_AREA_ADDRESS
#define LPRAM_MEMORY_MAP_OFFEST (REG_BASE_LP_RAM_ACORE - REG_BASE_LP_RAM)
/* static variable */
#define STATIC_ERROR_CODE_ADDR (ONCHIPROM_STATIC_AREA_ADDRESS + 0x4)
#define STATIC_TIMER_STATUS_ADDR (ONCHIPROM_STATIC_AREA_ADDRESS + 0x8)
#define STATIC_TIMER_COUNT_ADDR (ONCHIPROM_STATIC_AREA_ADDRESS + 0xC)
#define STATIC_UFS_TAG_ADDR (ONCHIPROM_STATIC_AREA_ADDRESS + 0x10)
/* define boot mode */
#define BOOT_MODE_USB_DOWNLOAD 0
#define BOOT_MODE_NORMAL_BOOT 1
#define BOOT_MODE_EMMC_BOOT 0
#define BOOT_MODE_UFS_BOOT 1
typedef void (*PJUMPTOADDR)(void); /* addr of xloader */
#endif /* end of __ONCHIPROM_H__ */
@@ -0,0 +1,35 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#ifndef __PLATFORM_H__
#define __PLATFORM_H__
/* fpga memory map */
#define REG_BASE_EMMC0 0xBF3FB000
#define REG_BASE_USB_OTG 0x10180000
#define REG_BASE_USB_OTG_BC 0XBF200000
#define REG_BASE_LP_RAM 0x00020000
#define REG_BASE_UFS_SYS 0xBF3B1000
#define REG_BASE_UFS 0xBF3B0000
#define REG_BASE_PCTRL 0xA8A09000
#define REG_BASE_IOC 0xA896C000
#define REG_BASE_PMC 0x40231000
#define REG_BASE_UART6 0x40232000
#define REG_BASE_PERI_CRG 0x40235000
#define REG_BASE_LP_TIMER 0x4023E000
#define REG_BASE_SCTRL 0x4020A000
#define REG_BASE_AO_IOC 0x40211000
#define REG_BASE_GPIO 0xA8A0B000 /* GPIO0~21 */
#define reg_gpio(x) (REG_BASE_GPIO + (0x1000 * (x)))
#define REG_GPIO22 0x4020B000
#define LP_RAM_SIZE (96*1024)
#define REG_BASE_LP_RAM_ACORE 0xFFF50000
#endif /* end of __PLATFORM_H__ */
@@ -0,0 +1,56 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#ifndef __SYS_H__
#define __SYS_H__
#include "types.h"
static inline void writel(unsigned int val, unsigned long int addr)
{
(*(volatile unsigned int *)(addr)) = (val);
}
static inline void writew(unsigned short val, unsigned long int addr)
{
(*(volatile unsigned short *)(addr)) = (val);
}
static inline void writeb(unsigned char val, unsigned long int addr)
{
(*(volatile unsigned char *)(addr)) = (val);
}
static inline unsigned int readl(unsigned long int addr)
{
return (*(volatile unsigned int *)(addr));
}
static inline unsigned short readw(unsigned long int addr)
{
return (*(volatile unsigned short *)(addr));
}
static inline unsigned char readb(unsigned long int addr)
{
return (*(volatile unsigned char *)(addr));
}
/* Set the bits of addr to 1, which in mask is 1 */
static inline void set_bits(unsigned int mask, unsigned long int addr)
{
(*(volatile unsigned int *)(addr)) |= mask;
}
/* Clear the bits of addr to 0, which in mask is 1 */
static inline void clr_bits(unsigned int mask, unsigned long int addr)
{
(*(volatile unsigned int *)(addr)) &= ~(mask);
}
/* Return True if all the bits of addr are 1, which is 1 in mask.
Else, return False. */
static inline unsigned int is_bits_set(unsigned int mask, unsigned long int addr)
{
return (((*(volatile unsigned int *)(addr)) & (mask)) == (mask));
}
#endif /* end of __SYS_H__ */
@@ -0,0 +1,16 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#ifndef __TYPES_H__
#define __TYPES_H__
#ifndef NULL
#define NULL (void *)0
#endif
#define TRUE 1
#define FALSE 0
#endif /* end of __TYPES_H__ */
@@ -0,0 +1,244 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#ifndef __USB3_H__
#define __USB3_H__
#include "asm/types.h"
#include "types.h"
#define STRING_LANGUAGE 0
#define STRING_MANUFACTURER 1
#define STRING_PRODUCT 2
#define USB_SPEED_UNKNOWN 0x00
#define USB_SPEED_LOW 0x01
#define USB_SPEED_FULL 0x02
#define USB_SPEED_HIGH 0x03
#define USB_SPEED_VARIABLE 0x04
#define USB_SPEED_SUPER 0x05
#define UDESC_DEVICE 0x01
#define UDESC_CONFIG 0x02
#define UDESC_STRING 0x03
#define UDESC_INTERFACE 0x04
#define UDESC_ENDPOINT 0x05
#define UDESC_SS_USB_COMPANION 0x30
#define UDESC_DEVICE_QUALIFIER 0x06
#define UDESC_BOS 0x0f
#define UDESC_DEVICE_CAPABILITY 0x10
#define ut_get_dir(a) ((a)&0x80)
#define UT_WRITE 0x00
#define UT_READ 0x80
#define ut_get_type(a) ((a)&0x60)
#define UT_STANDARD 0x00
#define UT_CLASS 0x20
#define UT_VENDOR 0x40
#define ut_get_recipient(a) ((a)&0x1f)
#define UT_DEVICE 0x00
#define UT_INTERFACE 0x01
#define UT_ENDPOINT 0x02
#define UT_OTHER 0x03
#define UR_GET_STATUS 0x00
#define UR_CLEAR_FEATURE 0x01
#define UR_SET_FEATURE 0x03
#define UR_SET_ADDRESS 0x05
#define UR_GET_DESCRIPTOR 0x06
#define UR_SET_DESCRIPTOR 0x07
#define UR_GET_CONFIG 0x08
#define UR_SET_CONFIG 0x09
#define UR_GET_INTERFACE 0x0a
#define UR_SET_INTERFACE 0x0b
#define UR_SYNCH_FRAME 0x0c
#define UR_SET_SEL 0x30
#define UR_SET_ISOC_DELAY 0x31
/* Feature numbers */
#define UF_ENDPOINT_HALT 0
#define UF_DEVICE_REMOTE_WAKEUP 1
#define UF_TEST_MODE 2
#define UF_DEVICE_B_HNP_ENABLE 3
#define UF_DEVICE_A_HNP_SUPPORT 4
#define UF_DEVICE_A_ALT_HNP_SUPPORT 5
#define UF_FUNCTION_SUSPEND 0
#define UF_U1_ENABLE 48
#define UF_U2_ENABLE 49
#define UF_LTM_ENABLE 50
/* OTG feature selectors */
#define UOTG_B_HNP_ENABLE 3
#define UOTG_A_HNP_SUPPORT 4
#define UOTG_A_ALT_HNP_SUPPORT 5
#define UOTG_NTF_HOST_REL 51
#define UOTG_B3_RSP_ENABLE 52
#define ue_get_dir(a) ((a)&0x80)
#define ue_set_dir(a, d) ((a) | (((d)&1) << 7))
#define UE_DIR_IN 0x80
#define UE_DIR_OUT 0x00
#define UE_ADDR 0x0f
#define ue_get_addr(a) ((a)&UE_ADDR)
/* * Maxpacket size for EP0, defined by USB3 spec */
#define USB3_MAX_EP0_SIZE 512
/* * Maxpacket size for any EP, defined by USB3 spec */
#define USB3_MAX_PACKET_SIZE 1024
#define USB2_HS_MAX_PACKET_SIZE 512
#define USB2_FS_MAX_PACKET_SIZE 64
#define USB3_BULK_IN_EP 1
#define USB3_BULK_OUT_EP 1
typedef struct usb_device_request {
unsigned char bm_request_type;
unsigned char b_request;
unsigned short w_value;
unsigned short w_index;
unsigned short w_length;
} usb_device_request_t;
#pragma pack(1)
/* * USB_DT_DEVICE: Device descriptor */
typedef struct usb_device_descriptor {
unsigned char b_length;
unsigned char b_descriptor_type;
unsigned short bcd_usb;
#define USB_CLASS_COMM 0x02
#define USB_CLASS_VENDOR_SPEC 0xFF
#define USB_SC_VENDOR_SPEC 0xFF
#define USB_PR_VENDOR_SPEC 0xFF
unsigned char b_device_class;
unsigned char b_device_sub_class;
unsigned char b_device_protocol;
unsigned char b_max_packet_size0;
unsigned short id_vendor;
unsigned short id_product;
unsigned short bcd_device;
unsigned char i_manufacturer;
unsigned char i_product;
unsigned char i_serial_number;
unsigned char b_num_configurations;
} usb_device_descriptor_t;
/* USB_DT_CONFIG: Config descriptor */
typedef struct usb_config_descriptor {
unsigned char b_length;
unsigned char b_descriptor_type;
unsigned short w_total_length;
unsigned char b_num_interfaces;
#define CONFIG_VALUE 1
unsigned char b_configuration_value;
unsigned char i_configuration;
#define USB_CONFIG_ATT_ONE (1 << 7)
unsigned char bm_attributes;
#define USB_CONFIG_VBUS_DRAW (0xFA)
unsigned char b_max_power;
} usb_config_descriptor_t;
/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */
typedef struct usb_qualifier_descriptor {
unsigned char b_length;
unsigned char b_descriptor_type;
unsigned short bcd_usb;
unsigned char b_device_class;
unsigned char b_device_sub_class;
unsigned char b_device_protocol;
unsigned char b_max_packet_size0;
unsigned char b_num_configurations;
unsigned char b_reserved;
} usb_qualifier_descriptor_t;
/* USB_DT_INTERFACE: Interface descriptor */
typedef struct usb_interface_descriptor {
unsigned char b_length;
unsigned char b_descriptor_type;
unsigned char b_interface_number;
unsigned char b_alternate_setting;
unsigned char b_num_endpoints;
unsigned char b_interface_class;
unsigned char b_interface_subclass;
unsigned char b_interface_protocol;
unsigned char i_interface;
} usb_interface_descriptor_t;
/* USB_DT_ENDPOINT: Endpoint descriptor */
typedef struct usb_endpoint_descriptor {
unsigned char b_length;
unsigned char b_descriptor_type;
unsigned char b_endpoint_address;
unsigned char bm_attributes;
#define USB_ENDPOINT_XFER_CONTROL 0x00
#define USB_ENDPOINT_XFER_ISOC 0x01
#define USB_ENDPOINT_XFER_BULK 0x02
#define USB_ENDPOINT_XFER_INT 0x03
unsigned short w_max_packet_size;
unsigned char b_interval;
} usb_endpoint_descriptor_t;
/* USB_DT_SS_ENDPOINT_COMP: SuperSpeed Endpoint Companion descriptor */
typedef struct usb_ss_ep_comp_descriptor {
unsigned char b_length;
unsigned char b_descriptor_type;
unsigned char b_max_burst;
unsigned char bm_attributes;
unsigned short w_bytes_per_interval;
} usb_ss_ep_comp_descriptor_t;
/* WUSB BOS Descriptor (Binary device Object Store) */
typedef struct wusb_bos_desc {
unsigned char b_length;
unsigned char b_descriptor_type;
unsigned short w_total_length;
unsigned char b_num_device_caps;
} wusb_bos_desc_t;
#define USB_DEVICE_CAPABILITY_20_EXTENSION 0x02
typedef struct usb_dev_cap_20_ext_desc {
unsigned char b_length;
unsigned char b_descriptor_type;
unsigned char b_devcapability_type;
#define USB_20_EXT_LPM 0x02
unsigned int bm_attributes;
} usb_dev_cap_20_ext_desc_t;
#define USB_DEVICE_CAPABILITY_SS_USB 0x03
typedef struct usb_dev_cap_ss_usb {
unsigned char b_length;
unsigned char b_descriptor_type;
unsigned char b_devcapability_type;
#define USB_DC_SS_USB_LTM_CAPABLE 0x02
unsigned char bm_attributes;
#define USB_DC_SS_USB_SPEED_SUPPORT_LOW 0x01
#define USB_DC_SS_USB_SPEED_SUPPORT_FULL 0x02
#define USB_DC_SS_USB_SPEED_SUPPORT_HIGH 0x04
#define USB_DC_SS_USB_SPEED_SUPPORT_SS 0x08
unsigned int w_speeds_supported;
unsigned char b_functionality_support;
unsigned char b_u1dev_exit_lat;
unsigned int w_u2dev_exit_lat;
} usb_dev_cap_ss_usb_t;
#define USB_DEVICE_CAPABILITY_CONTAINER_ID 0x04
typedef struct usb_dev_cap_container_id {
unsigned char b_length;
unsigned char b_descriptor_type;
unsigned char b_devcapability_type;
unsigned char b_reserved;
unsigned char container_id[16];
} usb_dev_cap_container_id_t;
#pragma pack()
#endif /* __USB3_H__ */
@@ -0,0 +1,770 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#include "usb3_drv.h"
#include "common.h"
#include <cpu_func.h>
#include <linux/compat.h>
#include <linux/lotus/usb.h>
unsigned int usb3_rd32(volatile unsigned int *addr)
{
return readl((unsigned int)addr);
}
void usb3_wr32(volatile unsigned int *addr, unsigned int val)
{
writel(val, (unsigned int)addr);
}
unsigned int usb3_is_host_mode(usb3_device_t *dev)
{
return usb3_rd32(&dev->core_global_regs->gsts) & 0x01;
}
void pcd_epinit(usb3_pcd_t *pcd)
{
usb3_pcd_ep_t *ep;
/* Init EP0 */
do {
ep = &pcd->ep0;
ep->pcd = pcd;
ep->stopped = 1;
ep->is_in = 0;
ep->active = 0;
ep->phys = 0;
ep->num = 0;
ep->tx_fifo_num = 0;
ep->out_ep_reg = &pcd->out_ep_regs[0];
ep->in_ep_reg = &pcd->in_ep_regs[0];
ep->type = USB3_EP_TYPE_CONTROL;
ep->maxburst = 0;
ep->maxpacket = 64; /* 64 bytes */
ep->send_zlp = 0;
ep->req.length = 0;
ep->req.actual = 0;
pcd->ep0_req.length = 0;
pcd->ep0_req.actual = 0;
} while (0);
/* Init EP1-OUT */
do {
ep = &pcd->out_ep;
ep->pcd = pcd;
ep->stopped = 1;
ep->is_in = 0;
ep->active = 0;
ep->phys = USB3_BULK_OUT_EP << 1;
ep->num = 1;
ep->tx_fifo_num = 0;
ep->out_ep_reg = &pcd->out_ep_regs[USB3_BULK_OUT_EP];
/* Bulk EP is activated */
ep->type = USB3_EP_TYPE_BULK;
ep->maxburst = 0;
ep->maxpacket = USB2_FS_MAX_PACKET_SIZE;
ep->send_zlp = 0;
ep->req.length = 0;
ep->req.actual = 0;
} while (0);
/* Init EP1-IN */
do {
ep = &pcd->in_ep;
ep->pcd = pcd;
ep->stopped = 1;
ep->is_in = 1;
ep->active = 0;
ep->phys = (USB3_BULK_IN_EP << 1) | 1;
ep->num = 1;
ep->tx_fifo_num = USB3_BULK_IN_EP;
ep->in_ep_reg = &pcd->in_ep_regs[USB3_BULK_IN_EP];
/* Bulk EP is activated */
ep->type = USB3_EP_TYPE_BULK;
ep->maxburst = 0;
ep->maxpacket = USB2_FS_MAX_PACKET_SIZE;
ep->send_zlp = 0;
ep->req.length = 0;
ep->req.actual = 0;
} while (0);
pcd->ep0state = EP0_IDLE;
}
void usb3_set_address(usb3_pcd_t *pcd, unsigned int addr)
{
unsigned int dcfg;
dcfg = usb3_rd32(&pcd->dev_global_regs->dcfg);
dcfg &= ~USB3_DCFG_DEVADDR_BITS;
dcfg |= addr << USB3_DCFG_DEVADDR_SHIFT;
usb3_wr32(&pcd->dev_global_regs->dcfg, dcfg);
}
#define RAM_WIDTH 8
#define RAM_RX_DEPTH 4096
#define RAM_TX0_DEPTH 1024
#define RAM_TX1_DEPTH 2048
void usb3_set_tx_fifo_size(usb3_device_t *dev)
{
usb3_core_global_regs_t *global_regs = dev->core_global_regs;
unsigned int prev_start = 0;
/* Set 1K for tx fifo0 */
usb3_wr32(&global_regs->gtxfifosiz[0],
((RAM_TX0_DEPTH / RAM_WIDTH) << USB3_FIFOSZ_DEPTH_SHIFT) |
(prev_start << USB3_FIFOSZ_STARTADDR_SHIFT));
prev_start += RAM_TX0_DEPTH / RAM_WIDTH;
/* Set 2K for tx fifo1 */
usb3_wr32(&global_regs->gtxfifosiz[1],
((RAM_TX1_DEPTH / RAM_WIDTH) << USB3_FIFOSZ_DEPTH_SHIFT) |
(prev_start << USB3_FIFOSZ_STARTADDR_SHIFT));
}
void usb3_set_rx_fifo_size(usb3_device_t *dev)
{
usb3_core_global_regs_t *global_regs = dev->core_global_regs;
/* Set 4K for rx fifo */
usb3_wr32(&global_regs->grxfifosiz[0],
((RAM_RX_DEPTH / RAM_WIDTH) << USB3_FIFOSZ_DEPTH_SHIFT));
}
void usb3_resume_usb2_phy(usb3_pcd_t *pcd)
{
unsigned int usb2phycfg;
usb3_device_t *dev = pcd->usb3_dev;
usb3_core_global_regs_t *global_regs = dev->core_global_regs;
usb2phycfg = usb3_rd32(&global_regs->gusb2phycfg[0]);
usb2phycfg |= USB3_USB2PHYCFG_SUS_PHY_BIT;
usb3_wr32(&global_regs->gusb2phycfg[0], usb2phycfg);
}
void usb3_resume_usb3_phy(usb3_pcd_t *pcd)
{
unsigned int pipectl;
usb3_device_t *dev = pcd->usb3_dev;
usb3_core_global_regs_t *global_regs = dev->core_global_regs;
pipectl = usb3_rd32(&global_regs->gusb3pipectl[0]);
pipectl |= USB3_PIPECTL_SUS_PHY_BIT;
usb3_wr32(&global_regs->gusb3pipectl[0], pipectl);
}
void usb3_accept_u1(usb3_pcd_t *pcd)
{
unsigned int dctl;
dctl = usb3_rd32(&pcd->dev_global_regs->dctl);
dctl |= USB3_DCTL_ACCEPT_U1_EN_BIT;
usb3_wr32(&pcd->dev_global_regs->dctl, dctl);
}
void usb3_accept_u2(usb3_pcd_t *pcd) {}
void usb3_enable_u1(usb3_pcd_t *pcd)
{
unsigned int dctl;
dctl = usb3_rd32(&pcd->dev_global_regs->dctl);
dctl |= USB3_DCTL_INIT_U1_EN_BIT;
usb3_wr32(&pcd->dev_global_regs->dctl, dctl);
}
void usb3_enable_u2(usb3_pcd_t *pcd) {}
void usb3_disable_u1(usb3_pcd_t *pcd) {}
void usb3_disable_u2(usb3_pcd_t *pcd)
{
unsigned int dctl;
dctl = usb3_rd32(&pcd->dev_global_regs->dctl);
dctl &= ~USB3_DCTL_INIT_U2_EN_BIT;
usb3_wr32(&pcd->dev_global_regs->dctl, dctl);
}
unsigned int usb3_u1_enabled(usb3_pcd_t *pcd)
{
unsigned int dctl;
dctl = usb3_rd32(&pcd->dev_global_regs->dctl);
return !!(dctl & USB3_DCTL_INIT_U1_EN_BIT);
}
unsigned int usb3_u2_enabled(usb3_pcd_t *pcd)
{
unsigned int dctl;
dctl = usb3_rd32(&pcd->dev_global_regs->dctl);
return !!(dctl & USB3_DCTL_INIT_U2_EN_BIT);
}
void usb3_dep_cstall(usb3_pcd_t *pcd, usb3_dev_ep_regs_t *ep_reg)
{
/* Start the command */
usb3_wr32(&ep_reg->depcmd, USB3_EPCMD_CLR_STALL | USB3_EPCMD_ACT_BIT);
/* Wait for command completion */
handshake(pcd->usb3_dev, &ep_reg->depcmd, USB3_EPCMD_ACT_BIT, 0);
}
void usb3_dep_sstall(usb3_pcd_t *pcd, usb3_dev_ep_regs_t *ep_reg)
{
/* Start the command */
usb3_wr32(&ep_reg->depcmd, USB3_EPCMD_SET_STALL | USB3_EPCMD_ACT_BIT);
/* Wait for command completion */
handshake(pcd->usb3_dev, &ep_reg->depcmd, USB3_EPCMD_ACT_BIT, 0);
}
unsigned int handshake(usb3_device_t *dev, volatile unsigned int *ptr,
unsigned int mask, unsigned int done)
{
unsigned int usec = 1000;
unsigned int result;
do {
result = usb3_rd32(ptr);
if ((result & mask) == done)
return 1;
udelay(1);
usec -= 1;
} while (usec > 0);
return 0;
}
void usb3_fill_desc(usb3_dma_desc_t *desc, phys_addr_t dma_addr,
unsigned int dma_len, unsigned int stream, unsigned int type,
unsigned int ctrlbits, int own)
{
dma_addr = map_to_dma_addr(dma_addr);
desc->bptl = (phys_addr_t)(dma_addr & 0xffffffffU);
desc->bpth = 0;
desc->status &= ~USB3_DSCSTS_XFRCNT_BITS;
desc->status |= ((dma_len << USB3_DSCSTS_XFRCNT_SHIFT) &
USB3_DSCSTS_XFRCNT_BITS);
/* Note: If type is 0, leave original control bits intact (for isoc) */
if (type)
desc->control = type << USB3_DSCCTL_TRBCTL_SHIFT;
desc->control |= (stream << USB3_DSCCTL_STRMID_SOFN_SHIFT) | ctrlbits;
/* Must do this last! */
if (own)
desc->control |= USB3_DSCCTL_HWO_BIT;
flush_dcache_all();
}
void usb3_dep_startnewcfg(usb3_pcd_t *pcd,
usb3_dev_ep_regs_t *ep_reg, unsigned int rsrcidx)
{
/* Start the command */
usb3_wr32(&ep_reg->depcmd,
(rsrcidx << USB3_EPCMD_XFER_RSRC_IDX_SHIFT) |
USB3_EPCMD_START_NEW_CFG | USB3_EPCMD_ACT_BIT);
/* Wait for command completion */
handshake(pcd->usb3_dev, &ep_reg->depcmd, USB3_EPCMD_ACT_BIT, 0);
}
void usb3_dep_cfg(usb3_pcd_t *pcd, usb3_dev_ep_regs_t *ep_reg,
unsigned int depcfg0, unsigned int depcfg1, unsigned int depcfg2)
{
/* Set param 2 */
usb3_wr32(&ep_reg->depcmdpar2, depcfg2);
/* Set param 1 */
usb3_wr32(&ep_reg->depcmdpar1, depcfg1);
/* Set param 0 */
usb3_wr32(&ep_reg->depcmdpar0, depcfg0); /* mm 0x1018c808 0x200 */
/* Start the command */
usb3_wr32(&ep_reg->depcmd, USB3_EPCMD_SET_EP_CFG | USB3_EPCMD_ACT_BIT);
/* Wait for command completion */
handshake(pcd->usb3_dev, &ep_reg->depcmd, USB3_EPCMD_ACT_BIT, 0);
}
void usb3_dep_xfercfg(usb3_pcd_t *pcd, usb3_dev_ep_regs_t *ep_reg,
unsigned int depstrmcfg)
{
/* Set param 0 */
usb3_wr32(&ep_reg->depcmdpar0, depstrmcfg);
/* Start the command */
usb3_wr32(&ep_reg->depcmd, USB3_EPCMD_SET_XFER_CFG |
USB3_EPCMD_ACT_BIT);
/* Wait for command completion */
handshake(pcd->usb3_dev, &ep_reg->depcmd, USB3_EPCMD_ACT_BIT, 0);
}
unsigned char usb3_dep_startxfer(usb3_pcd_t *pcd,
usb3_dev_ep_regs_t *ep_reg, phys_addr_t dma_addr,
unsigned int stream_or_uf)
{
unsigned int depcmd;
dma_addr = map_to_dma_addr(dma_addr);
/* Set param 1 */
usb3_wr32(&ep_reg->depcmdpar1, dma_addr & 0xffffffffU);
/* Set param 0 */
usb3_wr32(&ep_reg->depcmdpar0, 0);
usb3_wr32(&ep_reg->depcmd,
(stream_or_uf << USB3_EPCMD_STR_NUM_OR_UF_SHIFT) |
USB3_EPCMD_START_XFER | USB3_EPCMD_ACT_BIT);
/* Wait for command completion */
handshake(pcd->usb3_dev, &ep_reg->depcmd, USB3_EPCMD_ACT_BIT, 0);
depcmd = usb3_rd32(&ep_reg->depcmd);
return (depcmd >> USB3_EPCMD_XFER_RSRC_IDX_SHIFT) &
(USB3_EPCMD_XFER_RSRC_IDX_BITS >> USB3_EPCMD_XFER_RSRC_IDX_SHIFT);
}
void usb3_dep_updatexfer(usb3_pcd_t *pcd, usb3_dev_ep_regs_t *ep_reg,
unsigned int tri)
{
/* Start the command */
usb3_wr32(&ep_reg->depcmd, (tri << USB3_EPCMD_XFER_RSRC_IDX_SHIFT) |
USB3_EPCMD_UPDATE_XFER | USB3_EPCMD_ACT_BIT);
/* Wait for command completion */
handshake(pcd->usb3_dev, &ep_reg->depcmd, USB3_EPCMD_ACT_BIT, 0);
}
void usb3_enable_ep(usb3_pcd_t *pcd, usb3_pcd_ep_t *ep)
{
unsigned int ep_index_num, dalepena;
ep_index_num = ep->num * 0x2;
if (ep->is_in)
ep_index_num += 1;
dalepena = usb3_rd32(&pcd->dev_global_regs->dalepena);
/* If we have already enabled this EP, leave it alone
* (shouldn't happen)
*/
if (dalepena & (1 << ep_index_num))
return;
dalepena |= 1 << ep_index_num;
usb3_wr32(&pcd->dev_global_regs->dalepena, dalepena);
}
void usb3_dis_usb2_suspend(usb3_pcd_t *pcd)
{
unsigned int usb2phycfg;
usb3_device_t *dev = pcd->usb3_dev;
usb3_core_global_regs_t *global_regs = dev->core_global_regs;
if (pcd->speed == USB_SPEED_SUPER)
return;
usb2phycfg = usb3_rd32(&global_regs->gusb2phycfg[0]);
usb2phycfg &= ~USB3_USB2PHYCFG_SUS_PHY_BIT;
usb2phycfg &= ~USB3_USB2PHYCFG_ENBL_SLP_M_BIT;
usb3_wr32(&global_regs->gusb2phycfg[0], usb2phycfg);
}
void usb3_ep0_activate(usb3_pcd_t *pcd)
{
unsigned int diepcfg0, doepcfg0, diepcfg1, doepcfg1;
unsigned int diepcfg2 = 0;
unsigned int doepcfg2 = 0;
usb3_dev_ep_regs_t *ep_reg;
diepcfg0 = USB3_EP_TYPE_CONTROL << USB3_EPCFG0_EPTYPE_SHIFT;
diepcfg1 =
USB3_EPCFG1_XFER_CMPL_BIT | USB3_EPCFG1_XFER_IN_PROG_BIT |
USB3_EPCFG1_XFER_NRDY_BIT | USB3_EPCFG1_EP_DIR_BIT;
doepcfg0 = USB3_EP_TYPE_CONTROL << USB3_EPCFG0_EPTYPE_SHIFT;
doepcfg1 = USB3_EPCFG1_XFER_CMPL_BIT | USB3_EPCFG1_XFER_IN_PROG_BIT |
USB3_EPCFG1_XFER_NRDY_BIT;
/* Default to MPS of 512 (will reconfigure
* after ConnectDone event)
*/
diepcfg0 |= 512 << USB3_EPCFG0_MPS_SHIFT;
/* Default to MPS of 512 (will reconfigure
* after ConnectDone event)
*/
doepcfg0 |= 512 << USB3_EPCFG0_MPS_SHIFT;
diepcfg0 |= pcd->ep0.tx_fifo_num << USB3_EPCFG0_TXFNUM_SHIFT;
/* Issue "DEPCFG" command to EP0-OUT */
ep_reg = &pcd->out_ep_regs[0];
usb3_dis_usb2_suspend(pcd); /* mm 0x1018c200 0x102400 */
/* If core is version 1.09a or later */
/* Must issue DEPSTRTNEWCFG command first */
usb3_dep_startnewcfg(pcd, ep_reg, 0);
usb3_dep_cfg(pcd, ep_reg, doepcfg0, doepcfg1, doepcfg2);
/* Issue "DEPSTRMCFG" command to EP0-OUT */
/* One stream */
usb3_dep_xfercfg(pcd, ep_reg, 1);
/* Issue "DEPCFG" command to EP0-IN */
ep_reg = &pcd->in_ep_regs[0];
usb3_dep_cfg(pcd, ep_reg, diepcfg0, diepcfg1, diepcfg2);
/* Issue "DEPSTRMCFG" command to EP0-IN */
/* One stream */
usb3_dep_xfercfg(pcd, ep_reg, 1);
pcd->ep0.active = 1;
}
void usb3_ep_activate(usb3_pcd_t *pcd, usb3_pcd_ep_t *ep)
{
usb3_dev_ep_regs_t *ep_reg, *ep0_reg;
unsigned int depcfg0;
unsigned int depcfg1;
unsigned int depcfg2 = 0;
/*
* Get the appropriate EP registers
*/
if (ep->is_in)
ep_reg = ep->in_ep_reg;
else
ep_reg = ep->out_ep_reg;
/* If this is first EP enable (ie. start of a new configuration) */
if (!pcd->eps_enabled) {
pcd->eps_enabled = 1;
/* NOTE: When setting a new configuration, we must issue a
* "DEPCFG" command to physical EP1 (logical EP0-IN) first.
* This resets the core's Tx FIFO mapping table
*/
depcfg0 = USB3_EP_TYPE_CONTROL << USB3_EPCFG0_EPTYPE_SHIFT;
depcfg0 |= USB3_CFG_ACTION_MODIFY <<
USB3_EPCFG0_CFG_ACTION_SHIFT;
depcfg1 = USB3_EPCFG1_XFER_CMPL_BIT |
USB3_EPCFG1_XFER_NRDY_BIT | USB3_EPCFG1_EP_DIR_BIT;
switch (pcd->speed) {
case USB_SPEED_SUPER:
/* Default to MPS of 512 (will reconfigure
* after ConnectDone event)
*/
depcfg0 |= 512 << USB3_EPCFG0_MPS_SHIFT;
break;
case USB_SPEED_HIGH:
case USB_SPEED_FULL:
/* Default to MPS of 64 (will reconfigure
* after ConnectDone event)
*/
depcfg0 |= 64 << USB3_EPCFG0_MPS_SHIFT;
break;
case USB_SPEED_LOW:
/* Default to MPS of 8 (will reconfigure
* after ConnectDone event)
*/
depcfg0 |= 8 << USB3_EPCFG0_MPS_SHIFT;
break;
default:
break;
}
ep0_reg = &pcd->in_ep_regs[0];
usb3_dep_cfg(pcd, ep0_reg, depcfg0, depcfg1, 0);
/* If core is version 1.09a or later */
/* Must issue DEPSTRTNEWCFG command first */
ep0_reg = &pcd->out_ep_regs[0];
usb3_dep_startnewcfg(pcd, ep0_reg, 0x2);
}
/*
* Issue "DEPCFG" command to EP
*/
depcfg0 = ep->type << USB3_EPCFG0_EPTYPE_SHIFT;
depcfg0 |= ep->maxpacket << USB3_EPCFG0_MPS_SHIFT;
if (ep->is_in)
depcfg0 |= ep->tx_fifo_num << USB3_EPCFG0_TXFNUM_SHIFT;
depcfg0 |= ep->maxburst << USB3_EPCFG0_BRSTSIZ_SHIFT;
depcfg1 = ep->num << USB3_EPCFG1_EP_NUM_SHIFT;
if (ep->is_in)
depcfg1 |= USB3_EPCFG1_EP_DIR_BIT;
depcfg1 |= USB3_EPCFG1_XFER_CMPL_BIT;
usb3_dep_cfg(pcd, ep_reg, depcfg0, depcfg1, depcfg2);
/*
* Issue "DEPSTRMCFG" command to EP
*/
/* Setting 1 stream resource */
usb3_dep_xfercfg(pcd, ep_reg, 1);
/* Enable EP in DALEPENA reg */
usb3_enable_ep(pcd, ep);
ep->active = 1;
}
void usb3_ep0_out_start(usb3_pcd_t *pcd)
{
usb3_dev_ep_regs_t *ep_reg;
usb3_dma_desc_t *desc;
unsigned int desc_dma;
unsigned char tri;
/* Get the SETUP packet DMA Descriptor (TRB) */
desc = pcd->ep0_setup_desc;
desc_dma = (phys_addr_t)pcd->ep0_setup_desc;
/* DMA Descriptor setup */
usb3_fill_desc(desc, (phys_addr_t)pcd->ep0_setup_pkt,
pcd->ep0.maxpacket, 0, USB3_DSCCTL_TRBCTL_SETUP,
USB3_DSCCTL_IOC_BIT | USB3_DSCCTL_ISP_BIT |
USB3_DSCCTL_LST_BIT, 1);
ep_reg = &pcd->out_ep_regs[0];
/* Issue "DEPSTRTXFER" command to EP0-OUT */
tri = usb3_dep_startxfer(pcd, ep_reg, desc_dma, 0);
pcd->ep0.tri_out = tri;
}
void usb3_core_dev_init(usb3_device_t *dev)
{
usb3_core_global_regs_t *global_regs = dev->core_global_regs;
usb3_pcd_t *pcd = &dev->pcd;
usb3_dev_global_regs_t *dev_global_regs = pcd->dev_global_regs;
unsigned int temp_t;
/* Soft-reset the core */
do {
temp_t = usb3_rd32(&dev_global_regs->dctl);
temp_t &= ~USB3_DCTL_RUN_STOP_BIT;
temp_t |= USB3_DCTL_CSFT_RST_BIT;
usb3_wr32(&dev_global_regs->dctl, temp_t);
do {
udelay(1);
temp_t = usb3_rd32(&dev_global_regs->dctl);
} while (temp_t & USB3_DCTL_CSFT_RST_BIT);
/* Wait for at least 3 PHY clocks */
udelay(1);
} while (0);
pcd->link_state = 0;
temp_t = 0x13802004;
usb3_wr32(&global_regs->gctl, temp_t);
usb_info("evnt buffer addr: 0x%x\n", (u32)dev->event_buf);
usb3_init_eventbuf(dev, USB3_EVENT_BUF_SIZE,
(phys_addr_t)dev->event_buf);
dev->event_ptr = dev->event_buf;
/* Set speed to Super */
temp_t = usb3_rd32(&pcd->dev_global_regs->dcfg);
temp_t &= ~(USB3_DCFG_DEVSPD_BITS << USB3_DCFG_DEVSPD_SHIFT);
temp_t |= USB3_SPEED_HS_PHY_30MHZ_OR_60MHZ << USB3_DCFG_DEVSPD_SHIFT;
usb3_wr32(&pcd->dev_global_regs->dcfg, temp_t);
/* If LPM enable was requested */
temp_t = usb3_rd32(&pcd->dev_global_regs->dcfg);
temp_t |= USB3_DCFG_LPM_CAP_BIT;
/* mm 0x1018c700 0x480804 */
usb3_wr32(&pcd->dev_global_regs->dcfg, temp_t);
/* Set Nump */
temp_t = usb3_rd32(&pcd->dev_global_regs->dcfg);
temp_t &= ~USB3_DCFG_NUM_RCV_BUF_BITS;
temp_t |= 0x10 << USB3_DCFG_NUM_RCV_BUF_SHIFT;
usb3_wr32(&pcd->dev_global_regs->dcfg, temp_t);
usb3_set_address(pcd, 0);
/* disable Phy suspend */
usb3_resume_usb3_phy(pcd);
/* mm 0x1018c200 0x102540 */
usb3_resume_usb2_phy(pcd);
/* Enable Global and Device interrupts */
usb3_enable_device_interrupts(dev);
/* Activate EP0 */
usb3_ep0_activate(pcd);
/* Start EP0 to receive SETUP packets */
usb3_ep0_out_start(pcd);
/* Enable EP0-OUT/IN in DALEPENA register */
usb3_wr32(&pcd->dev_global_regs->dalepena, 0x3);
/* Set Run/Stop bit */
temp_t = usb3_rd32(&pcd->dev_global_regs->dctl);
temp_t |= USB3_DCTL_RUN_STOP_BIT;
usb3_wr32(&pcd->dev_global_regs->dctl, temp_t);
}
void usb3_pcd_init(usb3_device_t *dev)
{
usb3_pcd_t *pcd = &dev->pcd;
pcd->usb3_dev = dev;
pcd->speed = USB_SPEED_UNKNOWN;
/* Initialize EP structures */
pcd_epinit(pcd);
/* Initialize the Core (also enables interrupts
* and sets Run/Stop bit)
*/
usb3_core_dev_init(dev);
}
void usb3_common_init(usb3_device_t *dev, volatile unsigned char *base)
{
usb3_pcd_t *pcd;
dev->core_global_regs =
(usb3_core_global_regs_t *)(base + USB3_CORE_GLOBAL_REG_OFFSET);
pcd = &dev->pcd;
pcd->dev_global_regs =
(usb3_dev_global_regs_t *)(base + USB3_DEV_GLOBAL_REG_OFFSET);
pcd->out_ep_regs =
(usb3_dev_ep_regs_t *)(base + USB3_DEV_OUT_EP_REG_OFFSET);
pcd->in_ep_regs =
(usb3_dev_ep_regs_t *)(base + USB3_DEV_IN_EP_REG_OFFSET);
}
void usb3_init(usb3_device_t *dev)
{
/* Init the PCD (also enables interrupts and sets Run/Stop bit) */
usb3_pcd_init(dev);
}
static unsigned char string_manu[] = {'B', 0, 'o', 0, 'o', 0, 't', 0};
static unsigned char string_prod[] = {'U', 0, 'S', 0, 'B', 0, 'B', 0,
'u', 0, 'r', 0, 'n', 0};
#define USB_INIT_DEVICE 1
static int usb3_driver_init(const char *manu_suffix)
{
volatile unsigned char *reg;
usb3_device_t *usb3_dev;
struct usb_device_descriptor *usb3_dev_desc;
usb3_dev = malloc(sizeof(usb3_device_t));
if (!usb3_dev) {
debug("usb3_dev: out of memory\n");
return -ENOMEM;
}
memset((void *)usb3_dev, 0, sizeof(usb3_device_t));
usb3_dev_desc = malloc(sizeof(struct usb_device_descriptor));
if (usb3_dev_desc == NULL)
return -ENOMEM;
usb3_pcd_t *pcd = &usb3_dev->pcd;
usb3_pcd_ep_t *ep = &pcd->in_ep;
usb3_pcd_req_t *req = &ep->req;
req->bufdma = (unsigned char *)malloc(512); /* 512 bytes */
usb_info("size of usb3_dev %d\n", sizeof(*usb3_dev));
usb3_dev->base = (volatile unsigned char *)USB2_CTRL_REG_BASE;
usb3_dev->string_manu_len = sizeof(string_manu);
usb3_dev->string_prod_len = sizeof(string_prod);
usb3_dev->dev_desc = usb3_dev_desc;
memcpy(usb3_dev->string_manu, string_manu, usb3_dev->string_manu_len);
memcpy(usb3_dev->string_prod, string_prod, usb3_dev->string_prod_len);
strncpy(usb3_dev->manu_suffix, manu_suffix,
sizeof(usb3_dev->manu_suffix));
usb3_dev->pcd.ep0_setup_desc = (usb3_dma_desc_t *)((phys_addr_t)
(usb3_dev->pcd.ep0_setup + 0xf) & (unsigned int)(~0xf));
usb3_dev->pcd.ep0_in_desc = (usb3_dma_desc_t *)
((phys_addr_t)(usb3_dev->pcd.ep0_in + 0xf) &
(unsigned int)(~0xf));
usb3_dev->pcd.ep0_out_desc = (usb3_dma_desc_t *)
((phys_addr_t)(usb3_dev->pcd.ep0_out + 0xf) &
(unsigned int)(~0xf));
usb3_dev->pcd.in_ep.ep_desc = (usb3_dma_desc_t *)
((phys_addr_t)(usb3_dev->pcd.in_ep.epx_desc + 0xf) &
(unsigned int)(~0xf));
usb3_dev->pcd.out_ep.ep_desc = (usb3_dma_desc_t *)
((phys_addr_t)(usb3_dev->pcd.out_ep.epx_desc + 0xf) &
(unsigned int)(~0xf));
/* Release usb3.0 controller */
phy_usb_init(USB_INIT_DEVICE);
/* Get usb3.0 version number */
reg = usb3_dev->base + USB3_CORE_REG_BASE +
USB3_CORE_GSNPSID_REG_OFFSET;
usb3_dev->snpsid = usb3_rd32((volatile unsigned int *)reg);
/* Initialize usb3.0 core */
usb3_common_init(usb3_dev, usb3_dev->base + USB3_CORE_REG_BASE);
/* Initialize usb3.0 pcd */
usb3_init(usb3_dev);
usb_info("usb init done\n");
for (;;)
usb3_handle_event(usb3_dev);
}
/*
* Interface func for download the mirror, address from return.
*/
void udc_connect(void)
{
dcache_disable();
if (usb3_driver_init("") < 0)
usb_info("usb3 driver init error\n");
dcache_enable();
}
EXPORT_SYMBOL(udc_connect);
/*
* Interface func for download the mirror, address from return.
*/
void usbburn_connect(const char *manu_suffix)
{
dcache_disable();
if (usb3_driver_init(manu_suffix) < 0)
usb_info("usb3 driver init error\n");
dcache_enable();
}
EXPORT_SYMBOL(usbburn_connect);
@@ -0,0 +1,244 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#ifndef __USB3_DRIVER_H__
#define __USB3_DRIVER_H__
#include "sys.h"
#include "usb3.h"
#include "usb3_hw.h"
#include "debug.h"
/* time limit of waiting for key enents */
#define USB_WAIT_FOR_ENUM_DONE_TIME_MS (300 * 1000)
#define USB_WAIT_FOR_RX_NEXT_TIME_MS (60 * 1000)
enum usb_error_type {
USB_RX_NEXT_TIMEOUT = -5,
USB_ENUM_DONE_TIMEOUT = -3,
USB_PROCESS_ERR = -1,
USB_NO_ERR = 0,
};
struct usb_data_handle {
unsigned int u_file_type;
unsigned int u_file_address;
unsigned int u_file_length;
unsigned int is_rx_start;
unsigned int init_time_stamp;
unsigned int rx_time_stamp;
};
#define usb_info(format, arg...) debug_printf("[USBINFO]" format, ##arg)
#define usb_err(format, arg...) debug_printf("[USBERR]" format, ##arg)
typedef enum pcd_state {
USB3_STATE_UNCONNECTED, /* no host */
USB3_STATE_DEFAULT,
USB3_STATE_ADDRESSED,
USB3_STATE_CONFIGURED,
} pcdstate_e;
typedef enum ep0_state {
EP0_IDLE,
EP0_IN_DATA_PHASE,
EP0_OUT_DATA_PHASE,
EP0_IN_WAIT_NRDY,
EP0_OUT_WAIT_NRDY,
EP0_IN_STATUS_PHASE,
EP0_OUT_STATUS_PHASE,
EP0_STALL,
} ep0state_e;
typedef union usb_setup_pkt {
usb_device_request_t req;
unsigned int d32[2];
unsigned char d8[8];
} usb_setup_pkt_t;
typedef struct usb3_pcd_req {
usb3_dma_desc_t *trb;
phys_addr_t trbdma;
unsigned int length;
unsigned int actual;
unsigned char *bufdma;
void (*complete)(void *dev);
} usb3_pcd_req_t;
typedef struct usb3_pcd_ep {
struct usb3_pcd *pcd;
usb3_dev_ep_regs_t *out_ep_reg;
usb3_dev_ep_regs_t *in_ep_reg;
unsigned char phys;
unsigned char num;
unsigned char type;
unsigned char maxburst;
unsigned short maxpacket;
/* Tx FIFO # for IN EPs */
unsigned char tx_fifo_num;
/* The Transfer Resource Index from the Start Transfer command */
unsigned char tri_out;
unsigned char tri_in;
unsigned char stopped;
/* Send ZLP */
unsigned char send_zlp;
/* True if 3-stage control transfer */
unsigned char three_stage;
/* True if transfer has been started on EP */
unsigned char xfer_started;
/* EP direction 0 = OUT */
unsigned char is_in;
/* True if endpoint is active */
unsigned char active;
/* Initial data pid of bulk endpoint */
unsigned char data_pid_start;
/* ep_desc (excluding ep0) */
usb3_dma_desc_t *ep_desc;
/* TRB descriptor must be aligned to 16 bytes */
unsigned char epx_desc[32];
/* request (excluding ep0) */
usb3_pcd_req_t req;
} usb3_pcd_ep_t;
typedef struct usb3_pcd {
struct usb3_device *usb3_dev;
signed int link_state;
pcdstate_e state;
unsigned char new_config;
ep0state_e ep0state;
unsigned int eps_enabled;
unsigned int ltm_enable;
usb3_pcd_ep_t ep0;
usb3_pcd_ep_t out_ep;
usb3_pcd_ep_t in_ep;
usb3_dev_global_regs_t *dev_global_regs;
usb3_dev_ep_regs_t *out_ep_regs;
usb3_dev_ep_regs_t *in_ep_regs;
usb3_pcd_req_t ep0_req;
unsigned char speed;
usb3_dma_desc_t *ep0_setup_desc;
usb3_dma_desc_t *ep0_in_desc;
usb3_dma_desc_t *ep0_out_desc;
/* TRB descriptor must be aligned to 16 bytes */
unsigned char ep0_setup[32];
unsigned char ep0_in[32];
unsigned char ep0_out[32];
usb_setup_pkt_t ep0_setup_pkt[5];
#define USB3_STATUS_BUF_SIZE 512
unsigned char ep0_status_buf[USB3_STATUS_BUF_SIZE];
#define USB3_BULK_BUF_SIZE 512
unsigned char ss_bulk_buf[USB3_BULK_BUF_SIZE];
unsigned int file_type;
unsigned int file_address;
unsigned int file_capacity;
unsigned int file_total_frame;
unsigned int file_curr_frame;
unsigned int file_next_frame;
unsigned int file_received;
unsigned int file_complete;
} usb3_pcd_t;
#define usb3_pcd_ep_to_pcd(pcd_ep) ((pcd_ep)->usb3_pcd_ep_t.pcd)
#define usb3_pcd_ep_num(pcd_ep) ((pcd_ep)->usb3_pcd_ep_t.num)
#define usb3_pcd_ep_type(pcd_ep) ((pcd_ep)->usb3_pcd_ep_t.type)
#define usb3_pcd_ep_is_in(pcd_ep) ((pcd_ep)->usb3_pcd_ep_t.is_in)
#define dwc_usb3_is_hwo(desc) ((desc)->control & USB3_DSCCTL_HWO_BIT)
#define dwc_usb3_is_ioc(desc) ((desc)->control & USB3_DSCCTL_IOC_BIT)
#define usb3_get_xfercnt(desc) \
(((desc)->status >> USB3_DSCSTS_XFRCNT_SHIFT) & \
(USB3_DSCSTS_XFRCNT_BITS >> USB3_DSCSTS_XFRCNT_SHIFT))
#define usb3_get_xfersts(desc) \
(((desc)->status >> USB3_DSCSTS_TRBRSP_SHIFT) & \
(USB3_DSCSTS_TRBRSP_BITS >> USB3_DSCSTS_TRBRSP_SHIFT))
#define map_to_dma_addr(addr) ((addr))
//((addr) + (REG_BASE_LP_RAM_ACORE - REG_BASE_LP_RAM))
typedef struct usb3_device {
volatile unsigned char *base;
void *dev_desc;
unsigned char string_manu[32];
unsigned char string_prod[32];
unsigned int string_manu_len;
unsigned int string_prod_len;
char manu_suffix[16];
usb3_pcd_t pcd;
unsigned int snpsid;
usb3_core_global_regs_t *core_global_regs;
#define USB3_EVENT_BUF_SIZE 256
unsigned int event_buf[USB3_EVENT_BUF_SIZE];
unsigned int *event_ptr;
struct usb_data_handle *p_handle;
} usb3_device_t;
unsigned int usb3_rd32(volatile unsigned int *addr);
void usb3_wr32(volatile unsigned int *addr, unsigned int val);
void usb3_set_address(usb3_pcd_t *pcd, unsigned int addr);
void usb3_accept_u1(usb3_pcd_t *pcd);
void usb3_accept_u2(usb3_pcd_t *pcd);
void usb3_enable_u1(usb3_pcd_t *pcd);
void usb3_enable_u2(usb3_pcd_t *pcd);
void usb3_disable_u1(usb3_pcd_t *pcd);
void usb3_disable_u2(usb3_pcd_t *pcd);
unsigned int usb3_u1_enabled(usb3_pcd_t *pcd);
unsigned int usb3_u2_enabled(usb3_pcd_t *pcd);
void usb3_dep_cstall(usb3_pcd_t *pcd, usb3_dev_ep_regs_t *ep_reg);
void usb3_dep_sstall(usb3_pcd_t *pcd, usb3_dev_ep_regs_t *ep_reg);
unsigned int handshake(usb3_device_t *dev, volatile unsigned int *ptr,
unsigned int mask, unsigned int done);
void usb3_fill_desc(usb3_dma_desc_t *desc, phys_addr_t dma_addr,
unsigned int dma_len, unsigned int stream, unsigned int type,
unsigned int ctrlbits, int own);
void usb3_dep_startnewcfg(usb3_pcd_t *pcd, usb3_dev_ep_regs_t *ep_reg,
unsigned int rsrcidx);
void usb3_dep_cfg(usb3_pcd_t *pcd, usb3_dev_ep_regs_t *ep_reg,
unsigned int depcfg0, unsigned int depcfg1, unsigned int depcfg2);
void usb3_dep_xfercfg(usb3_pcd_t *pcd, usb3_dev_ep_regs_t *ep_reg,
unsigned int depstrmcfg);
unsigned char usb3_dep_startxfer(usb3_pcd_t *pcd, usb3_dev_ep_regs_t *ep_reg,
phys_addr_t dma_addr, unsigned int stream_or_uf);
void usb3_dep_updatexfer(usb3_pcd_t *pcd, usb3_dev_ep_regs_t *ep_reg,
unsigned int tri);
void usb3_ep_activate(usb3_pcd_t *pcd, usb3_pcd_ep_t *ep);
void usb3_ep0_out_start(usb3_pcd_t *pcd);
void usb3_ep0_start_transfer(usb3_pcd_t *pcd, usb3_pcd_req_t *req);
void usb3_resume_usb2_phy(usb3_pcd_t *pcd);
void usb3_handle_dev_intr(usb3_pcd_t *pcd, unsigned int event);
int usb3_handle_ep_intr(usb3_pcd_t *pcd, unsigned int physep,
unsigned int event);
void usb3_handle_event(usb3_device_t *dev);
void usb3_enable_device_interrupts(usb3_device_t *dev);
void usb3_dis_flush_eventbuf_intr(usb3_device_t *dev);
void usb3_init_eventbuf(usb3_device_t *dev, unsigned int size,
phys_addr_t dma_addr);
#endif /* __USB3_DRIVER_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,133 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#include "usb3_hw.h"
#include "usb3_drv.h"
#include <cpu_func.h>
void ena_eventbuf_intr(usb3_device_t *dev)
{
unsigned int eventsiz;
eventsiz = usb3_rd32(&dev->core_global_regs->geventbuf[0].geventsiz);
eventsiz &= ~USB3_EVENTSIZ_INT_MSK_BIT;
usb3_wr32(&dev->core_global_regs->geventbuf[0].geventsiz, eventsiz);
}
void dis_eventbuf_intr(usb3_device_t *dev)
{
unsigned int eventsiz;
eventsiz = usb3_rd32(&dev->core_global_regs->geventbuf[0].geventsiz);
eventsiz |= USB3_EVENTSIZ_INT_MSK_BIT;
usb3_wr32(&dev->core_global_regs->geventbuf[0].geventsiz, eventsiz);
}
void usb3_dis_flush_eventbuf_intr(usb3_device_t *dev)
{
unsigned int cnt;
unsigned int gevntsize;
dis_eventbuf_intr(dev);
cnt = usb3_rd32(&dev->core_global_regs->geventbuf[0].geventcnt);
usb3_wr32(&dev->core_global_regs->geventbuf[0].geventcnt, cnt);
if (cnt != 0) {
gevntsize = sizeof(dev->event_buf[0]) * USB3_EVENT_BUF_SIZE;
usb_info("evnt count 0x%x, evnt buf size 0x%x\n", cnt, gevntsize);
dev->event_ptr += cnt % gevntsize;
}
}
int get_eventbuf_count(usb3_device_t *dev)
{
unsigned int cnt;
cnt = usb3_rd32(&dev->core_global_regs->geventbuf[0].geventcnt);
return cnt & USB3_EVENTCNT_CNT_BITS;
}
void update_eventbuf_count(usb3_device_t *dev, int cnt)
{
usb3_wr32(&dev->core_global_regs->geventbuf[0].geventcnt, cnt);
}
unsigned int get_eventbuf_event(usb3_device_t *dev, int size)
{
unsigned int event;
event = *dev->event_ptr++;
if (dev->event_ptr >= dev->event_buf + size)
dev->event_ptr = dev->event_buf;
return event;
}
void usb3_init_eventbuf(usb3_device_t *dev, unsigned int size, phys_addr_t dma_addr)
{
dma_addr = map_to_dma_addr(dma_addr);
usb3_wr32(&dev->core_global_regs->geventbuf[0].geventadr_lo, dma_addr & 0xffffffff);
usb3_wr32(&dev->core_global_regs->geventbuf[0].geventadr_hi, 0);
usb3_wr32(&dev->core_global_regs->geventbuf[0].geventsiz, size << 2); /* left shift 2bit */
usb3_wr32(&dev->core_global_regs->geventbuf[0].geventcnt, 0);
}
void usb3_enable_device_interrupts(usb3_device_t *dev)
{
unsigned int eventsiz;
/* Clear any pending interrupts */
usb3_dis_flush_eventbuf_intr(dev);
/* *
* This routine enables the Event Buffer interrupt.
*/
eventsiz = usb3_rd32(&dev->core_global_regs->geventbuf[0].geventsiz);
eventsiz &= ~USB3_EVENTSIZ_INT_MSK_BIT;
usb3_wr32(&dev->core_global_regs->geventbuf[0].geventsiz, eventsiz);
/* Enable device interrupts */
usb3_wr32(&dev->pcd.dev_global_regs->devten, USB3_DEVTEN_DISCONN_BIT | USB3_DEVTEN_CONNDONE_BIT |
USB3_DEVTEN_USBRESET_BIT | USB3_DEVTEN_HIBER_REQ_EVT_BIT | USB3_DEVTEN_WKUP_BIT | USB3_DEVTEN_EOPF_BIT);
}
void usb3_handle_event(usb3_device_t *dev)
{
usb3_pcd_t *pcd = &dev->pcd;
unsigned int event, physep;
int intr, count, i;
intr = 0;
invalidate_dcache_all();
count = get_eventbuf_count(dev);
if ((count & USB3_EVENTCNT_CNT_BITS) == USB3_EVENTCNT_CNT_BITS || count >= USB3_EVENT_BUF_SIZE * 0x4) {
update_eventbuf_count(dev, count);
count = 0;
}
for (i = 0; i < count; i += 0x4) {
event = get_eventbuf_event(dev, USB3_EVENT_BUF_SIZE);
update_eventbuf_count(dev, 0x4);
if (event == 0) {
/* Ignore null events */
continue;
}
if (event & USB3_EVENT_NON_EP_BIT) {
intr = event & USB3_EVENT_INTTYPE_BITS;
if (intr == (USB3_EVENT_DEV_INT << USB3_EVENT_INTTYPE_SHIFT)) {
usb3_handle_dev_intr(pcd, event);
} else {
/* @todo Handle non-Device interrupts
* (OTG, CarKit, I2C)
*/
}
} else {
physep = (event >> USB3_DEPEVT_EPNUM_SHIFT) & (USB3_DEPEVT_EPNUM_BITS >> USB3_DEPEVT_EPNUM_SHIFT);
usb3_handle_ep_intr(pcd, physep, event);
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,24 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#ifndef __USB3_PCD_H__
#define __USB3_PCD_H__
usb3_pcd_ep_t *usb3_get_out_ep(usb3_pcd_t *pcd, unsigned int ep_num);
usb3_pcd_ep_t *usb3_get_in_ep(usb3_pcd_t *pcd, unsigned int ep_num);
usb3_pcd_ep_t *usb3_get_ep_by_addr(usb3_pcd_t *pcd, unsigned short index);
void usb3_ep_clear_stall(usb3_pcd_t *pcd, usb3_pcd_ep_t *ep);
unsigned int usb3_get_device_speed(usb3_pcd_t *pcd);
void usb3_pcd_set_speed(usb3_pcd_t *pcd, int speed);
void usb3_ep_set_stall(usb3_pcd_t *pcd, usb3_pcd_ep_t *ep);
void usb3_bulk_in_transfer(void *dev, const char *status);
void usb3_bulk_out_transfer_cmd(void *dev);
int usb3_bulk_out_transfer_data(void *dev);
void usb3_bulk_out_transfer(void *dev);
void usb3_ep_start_transfer(usb3_pcd_t *pcd, usb3_pcd_ep_t *ep);
int usb3_ep_complete_request(usb3_pcd_t *pcd, usb3_pcd_ep_t *ep, unsigned int event);
void usb3_os_handle_ep0(usb3_pcd_t *pcd, unsigned int event);
void usb_tx_status_complete(void *dev);
#endif /* __USB3_PCD_H__ */
@@ -0,0 +1,159 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#include "usb3_drv.h"
#include "usb3_pcd.h"
static void handle_usb_reset_intr(usb3_pcd_t *pcd)
{
usb3_pcd_ep_t *ep;
/* Clear stall on each EP */
ep = &pcd->in_ep;
if (ep->stopped)
usb3_ep_clear_stall(pcd, ep);
ep = &pcd->out_ep;
if (ep->stopped)
usb3_ep_clear_stall(pcd, ep);
/* Set Device Address to 0 */
usb3_set_address(pcd, 0);
pcd->ltm_enable = 0;
}
static void handle_connect_done_intr(usb3_pcd_t *pcd)
{
usb3_pcd_ep_t *ep0 = &pcd->ep0;
unsigned int diepcfg0, doepcfg0, diepcfg1, doepcfg1;
usb3_dev_ep_regs_t *ep_reg;
int speed;
ep0->stopped = 0;
speed = usb3_get_device_speed(pcd);
pcd->speed = speed;
usb3_pcd_set_speed(pcd, speed);
/*
* Set the MPS of EP0 based on the connection speed
*/
diepcfg0 = USB3_EP_TYPE_CONTROL << USB3_EPCFG0_EPTYPE_SHIFT;
diepcfg0 |= USB3_CFG_ACTION_MODIFY << USB3_EPCFG0_CFG_ACTION_SHIFT;
diepcfg1 =
USB3_EPCFG1_XFER_CMPL_BIT | USB3_EPCFG1_XFER_IN_PROG_BIT | USB3_EPCFG1_XFER_NRDY_BIT | USB3_EPCFG1_EP_DIR_BIT;
doepcfg0 = USB3_EP_TYPE_CONTROL << USB3_EPCFG0_EPTYPE_SHIFT;
doepcfg0 |= USB3_CFG_ACTION_MODIFY << USB3_EPCFG0_CFG_ACTION_SHIFT;
doepcfg1 = USB3_EPCFG1_XFER_CMPL_BIT | USB3_EPCFG1_XFER_IN_PROG_BIT | USB3_EPCFG1_XFER_NRDY_BIT;
switch (speed) {
case USB_SPEED_SUPER:
diepcfg0 |= 512 << USB3_EPCFG0_MPS_SHIFT; /* 512 for super speed */
doepcfg0 |= 512 << USB3_EPCFG0_MPS_SHIFT; /* 512 for super speed */
break;
case USB_SPEED_HIGH:
case USB_SPEED_FULL:
diepcfg0 |= 64 << USB3_EPCFG0_MPS_SHIFT; /* 64 for high\full speed */
doepcfg0 |= 64 << USB3_EPCFG0_MPS_SHIFT; /* 64 for high\full speed */
break;
case USB_SPEED_LOW:
diepcfg0 |= 8 << USB3_EPCFG0_MPS_SHIFT; /* 8 for low speed */
doepcfg0 |= 8 << USB3_EPCFG0_MPS_SHIFT; /* 8 for low speed */
break;
default:
break;
}
diepcfg0 |= ep0->tx_fifo_num << USB3_EPCFG0_TXFNUM_SHIFT;
/* Issue "DEPCFG" command to EP0-OUT */
ep_reg = &pcd->out_ep_regs[0];
usb3_dep_cfg(pcd, ep_reg, doepcfg0, doepcfg1, 0);
/* Issue "DEPCFG" command to EP0-IN */
ep_reg = &pcd->in_ep_regs[0];
usb3_dep_cfg(pcd, ep_reg, diepcfg0, diepcfg1, 0);
pcd->state = USB3_STATE_DEFAULT;
}
int usb3_handle_ep_intr(usb3_pcd_t *pcd, unsigned int physep, unsigned int event)
{
usb3_pcd_ep_t *ep;
int epnum, is_in;
int error = USB_NO_ERR;
if (pcd == NULL)
return USB_PROCESS_ERR;
/* Physical Out EPs are even, physical In EPs are odd */
is_in = physep & 1;
epnum = (physep >> 1) & 0xf;
/* Get EP pointer */
if (is_in) {
ep = usb3_get_in_ep(pcd, epnum);
} else {
ep = usb3_get_out_ep(pcd, epnum);
}
if (ep == NULL)
return USB_PROCESS_ERR;
// printf("\n##########%s,%d,event=0x%x\n",__func__,__LINE__,event);
switch (event & USB3_DEPEVT_INTTYPE_BITS) {
case USB3_DEPEVT_XFER_CMPL << USB3_DEPEVT_INTTYPE_SHIFT:
ep->xfer_started = 0;
/* Complete the transfer */
if (epnum == 0) {
usb3_os_handle_ep0(pcd, event);
} else {
// printf("\n##########%s,%d,event=0x%x\n",__func__,__LINE__,event);
error = usb3_ep_complete_request(pcd, ep, event);
}
break;
case USB3_DEPEVT_XFER_NRDY << USB3_DEPEVT_INTTYPE_SHIFT:
if (epnum != 0)
break;
switch (pcd->ep0state) {
case EP0_IN_WAIT_NRDY:
if (is_in)
usb3_os_handle_ep0(pcd, event);
break;
case EP0_OUT_WAIT_NRDY:
if (!is_in)
usb3_os_handle_ep0(pcd, event);
break;
default:
break;
}
break;
default:
break;
}
return error;
}
void usb3_handle_dev_intr(usb3_pcd_t *pcd, unsigned int event)
{
unsigned int dint = (event >> USB3_DEVT_SHIFT) & (USB3_DEVT_BITS >> USB3_DEVT_SHIFT);
switch (dint) {
case USB3_DEVT_USBRESET:
handle_usb_reset_intr(pcd);
break;
case USB3_DEVT_CONNDONE:
handle_connect_done_intr(pcd);
break;
default:
break;
}
}
@@ -0,0 +1,190 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#include "usb3_drv.h"
#include "usb3_pcd.h"
#include "usb3_prot.h"
#include "onchiprom.h"
#include <common.h>
#include <linux/string.h>
#define USTART 0xFA
#define UHEAD 0xFE
#define UDATA 0xDA
#define UTAIL 0xED
#define UCMD 0XAB
#define UREQ 0XFB
#define TX_STATE_BUFFER 500
#define TX_STATE_LIMIT 400
#define BUFFER_SIZE 512
char u_ack[2] = {0xAA, '\0'};
char u_nak[2] = {0x55, '\0'};
char tx_state[TX_STATE_BUFFER] = {0, 0x55, 0};
static phys_addr_t rx_addr;
static unsigned int rx_length;
int usb_connected;
int usb_out_open = 0;
void usb3_bulk_out_transfer_cmd(void *dev)
{
usb3_pcd_t *pcd = (usb3_pcd_t *)dev;
usb3_pcd_ep_t *ep = &pcd->out_ep;
usb3_pcd_req_t *req = &ep->req;
memset(pcd->ss_bulk_buf, 0x0, USB3_BULK_BUF_SIZE);
req->length = ep->maxpacket;
req->bufdma = pcd->ss_bulk_buf;
req->complete = usb3_handle_protocol;
usb3_ep_start_transfer(pcd, ep);
return;
}
void usb3_handle_data(void *dev)
{
usb3_pcd_t *pcd = NULL;
usb3_pcd_ep_t *ep = NULL;
usb3_pcd_req_t *req = NULL;
if (dev == NULL)
return;
pcd = (usb3_pcd_t *)dev;
ep = &pcd->out_ep;
req = &ep->req;
if (req->actual > rx_length)
req->actual = rx_length;
rx_addr += req->actual;
rx_length -= req->actual;
if (rx_length > 0) {
usb3_bulk_out_transfer_data(dev);
} else {
usb3_bulk_out_transfer_cmd(dev);
}
}
int usb3_bulk_out_transfer_data(void *dev)
{
usb3_pcd_t *pcd = NULL;
usb3_pcd_ep_t *ep = NULL;
usb3_pcd_req_t *req = NULL;
if (dev == NULL)
return USB_PROCESS_ERR;
pcd = (usb3_pcd_t *)dev;
ep = &pcd->out_ep;
req = &ep->req;
/* For DWC3 controller,If CHN=0 and HWO=0 for the TRB, this field represents the total remaining Buffer
* Descriptor buffer size in bytes. Valid Range: 0 bytes to (16 MB - 1 byte).
* The hardware decrements this field to represent the remaining buffer size after data is
* transferred.
* Note: for bulk transfer, max length = 16MB - maxpacket;
* */
if (rx_length >= (USB3_DSCSTS_XFRCNT_MAX - ep->maxpacket)) {
req->length = USB3_DSCSTS_XFRCNT_MAX - ep->maxpacket;
} else {
req->length = rx_length;
}
req->bufdma = (unsigned char *)rx_addr;
req->complete = usb3_handle_data;
usb3_ep_start_transfer(pcd, ep);
return USB_NO_ERR;
}
void udc_puts(const char *s)
{
if (s == NULL)
return;
if (strlen(tx_state) + strlen(s) > TX_STATE_LIMIT)
(void)memset(tx_state, 0, TX_STATE_BUFFER);
if (strlen(s) > TX_STATE_BUFFER) {
return;
} else {
if (usb_out_open == 1) {
strcat(tx_state, s);
}
}
}
typedef int (*USB3_HANDLE_REQUEST)(unsigned char * const buff, unsigned int *bufflen);
USB3_HANDLE_REQUEST handle_request = NULL;
void set_usb3_call_back_func(USB3_HANDLE_REQUEST func)
{
handle_request = func;
}
void usb3_handle_protocol(void *dev)
{
usb3_pcd_t *pcd = (usb3_pcd_t *)dev;
int ret;
char *buf = (char *)pcd->ss_bulk_buf;
if (buf[0] == USTART) {
usb3_bulk_out_transfer_cmd(pcd);
usb3_bulk_in_transfer(dev, u_ack);
} else if (buf[0] == UHEAD) {
/*left shift 8/16/24 bit [5][6][7][8]:buffer number */
rx_addr = (buf[5] << 24) | (buf[6] << 16) | (buf[7] << 8) | (buf[8]);
/*left shift 8/16/24 bit [1][2][3][4]:buffer number */
rx_length = (buf[1] << 24) | (buf[2] << 16) | (buf[3] << 8) | (buf[4]);
if (rx_addr == rx_length) {
usb3_bulk_out_transfer_cmd(pcd);
usb_connected = 1;
usb_out_open = 1;
} else {
usb3_bulk_out_transfer_data(pcd);
}
usb3_bulk_in_transfer(dev, u_ack);
return;
} else if(buf[0]==UCMD) {
strcat(tx_state, " ");
usb_out_open = 1;
ret = run_command(buf + 0x3, 0);
if (ret) {
usb3_bulk_in_transfer(dev, "[EOT](ERROR)\r\n");
} else {
strcat(tx_state, "[EOT](OK)\r\n");
usb3_bulk_out_transfer_cmd(pcd);
usb3_bulk_in_transfer(dev, tx_state);
memset(tx_state, 0, TX_STATE_BUFFER);
}
} else if (buf[0] == UTAIL) {
if (rx_length > 0) {
usb3_bulk_out_transfer_cmd(pcd);
usb3_bulk_in_transfer(dev, u_nak);
} else {
usb3_bulk_in_transfer(dev, u_ack);
usb3_bulk_out_transfer_cmd(pcd);
}
} else if (buf[0] == UREQ) {
usb_out_open = 0;
if (handle_request != NULL) {
usb3_pcd_ep_t *ep = &pcd->in_ep;
usb3_pcd_req_t *req = &ep->req;
memset(req->bufdma, 0, BUFFER_SIZE);
req->length = 0;
ret = (*handle_request)(req->bufdma, &req->length);
req->complete = usb_tx_status_complete;
usb3_ep_start_transfer(pcd, ep);
usb3_bulk_out_transfer_cmd(pcd);
}
}
}
@@ -0,0 +1,49 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#ifndef __USB3_PROT_H__
#define __USB3_PROT_H__
/* FILE FRAME: TYPE(1)+SEQ(1)+CSEQ(1)+FILE(1)+LENGTH(4)+ADDRESS(4)+CRC(2) */
/* DATA FRAME: TYPE(1)+SEQ(1)+CSEQ(1)+DATA(0~1024)+CRC(2) */
/* EOT FRAME: TYPE(1)+SEQ(1)+CSEQ(1)+CRC(2) */
#define FRAME_HEAD 0
#define FRAME_SEQ 1
#define FRAME_CSEQ 2
#define FRAME_TYPE 3
#define FRAME_DATA_START 3
#define FRAME_LENGTH 4
#define FRAME_ADDRESS 8
#define FRAME_FILE 0xFE
#define FRAME_DATA 0xDA
#define FRAME_EOT 0xED
#define FRAME_INQUIRE 0xCD
#define USB3_RESPONSE_ACK 0xAA
#define USB3_RESPONSE_NAK 0x55
#define FRAME_FILE_LEN 14
#define FRAME_EOT_LEN 5
#define FRAME_HEAD_LEN 5
#define FRAME_DATA_LEN 1024
#define FILE_RAMINIT 1
#define FILE_USB 2
#define USB3_XFR_PROT_OK 0
#define USB3_XFR_PROT_ERR 1
#define USB3_XFR_PROT_SKIP 2
#define USB3_XFR_PROT_COMPLETE 3
#define USB3_XFR_PROT_INPROGRESS 4
#define USB3_XFR_PROT_WAIT 0x05
#define USB3_XFR_PROT_INQUIRE 0x06
#define USB3_XFR_PROT_ADDR_ERROR 0x07
void usb3_handle_protocol(void *dev);
#endif /* __USB3_PROT_H__ */