Merge branch 'master' of git://git.denx.de/u-boot-usb

This commit is contained in:
Tom Rini 2013-10-21 08:10:36 -04:00
commit 748bde608a
127 changed files with 7334 additions and 612 deletions

View File

@ -59,6 +59,28 @@ void set_usbhost_phy_ctrl(unsigned int enable)
exynos5_set_usbhost_phy_ctrl(enable);
}
static void exynos5_set_usbdrd_phy_ctrl(unsigned int enable)
{
struct exynos5_power *power =
(struct exynos5_power *)samsung_get_base_power();
if (enable) {
/* Enabling USBDRD_PHY */
setbits_le32(&power->usbdrd_phy_control,
POWER_USB_DRD_PHY_CTRL_EN);
} else {
/* Disabling USBDRD_PHY */
clrbits_le32(&power->usbdrd_phy_control,
POWER_USB_DRD_PHY_CTRL_EN);
}
}
void set_usbdrd_phy_ctrl(unsigned int enable)
{
if (cpu_is_exynos5())
exynos5_set_usbdrd_phy_ctrl(enable);
}
static void exynos5_dp_phy_control(unsigned int enable)
{
unsigned int cfg;

View File

@ -339,7 +339,7 @@ void configure_mpu_dpll(void)
debug("MPU DPLL locked\n");
}
#ifdef CONFIG_USB_EHCI_OMAP
#if defined(CONFIG_USB_EHCI_OMAP) || defined(CONFIG_USB_XHCI_OMAP)
static void setup_usb_dpll(void)
{
const struct dpll_params *params;
@ -404,7 +404,7 @@ static void setup_dplls(void)
/* MPU dpll */
configure_mpu_dpll();
#ifdef CONFIG_USB_EHCI_OMAP
#if defined(CONFIG_USB_EHCI_OMAP) || defined(CONFIG_USB_XHCI_OMAP)
setup_usb_dpll();
#endif
params = get_ddr_dpll_params(*dplls_data);

View File

@ -295,6 +295,7 @@ struct prcm_regs const omap5_es1_prcm = {
struct omap_sys_ctrl_regs const omap5_ctrl = {
.control_status = 0x4A002134,
.control_std_fuse_opp_vdd_mpu_2 = 0x4A0021B4,
.control_phy_power_usb = 0x4A002370,
.control_padconf_core_base = 0x4A002800,
.control_paconf_global = 0x4A002DA0,
.control_paconf_mode = 0x4A002DA4,
@ -567,6 +568,7 @@ struct prcm_regs const omap5_es2_prcm = {
.cm_div_m2_dpll_unipro = 0x4a0081d0,
.cm_ssc_deltamstep_dpll_unipro = 0x4a0081e8,
.cm_ssc_modfreqdiv_dpll_unipro = 0x4a0081ec,
.cm_coreaon_usb_phy_core_clkctrl = 0x4A008640,
.cm_coreaon_bandgap_clkctrl = 0x4a008648,
.cm_coreaon_io_srcomp_clkctrl = 0x4a008650,
@ -698,6 +700,8 @@ struct prcm_regs const omap5_es2_prcm = {
.cm_l3init_p1500_clkctrl = 0x4a009678,
.cm_l3init_fsusb_clkctrl = 0x4a0096d0,
.cm_l3init_ocp2scp1_clkctrl = 0x4a0096e0,
.cm_l3init_ocp2scp3_clkctrl = 0x4a0096e8,
.cm_l3init_usb_otg_ss_clkctrl = 0x4a0096f0,
/* prm irqstatus regs */
.prm_irqstatus_mpu_2 = 0x4ae06014,
@ -789,6 +793,7 @@ struct prcm_regs const dra7xx_prcm = {
.cm_clkmode_dpll_dsp = 0x4a005234,
.cm_shadow_freq_config1 = 0x4a005260,
.cm_clkmode_dpll_gmac = 0x4a0052a8,
.cm_coreaon_usb_phy2_core_clkctrl = 0x4a008688,
/* cm1.mpu */
.cm_mpu_mpu_clkctrl = 0x4a005320,

View File

@ -158,6 +158,18 @@
interrupts = <0 130 0>;
};
xhci@12000000 {
compatible = "samsung,exynos5250-xhci";
reg = <0x12000000 0x10000>;
#address-cells = <1>;
#size-cells = <1>;
phy {
compatible = "samsung,exynos5250-usb3-phy";
reg = <0x12100000 0x100>;
};
};
ehci@12110000 {
compatible = "samsung,exynos-ehci";
reg = <0x12110000 0x100>;

View File

@ -51,4 +51,14 @@
/* RTC base address */
#define RTC_BASE 0x44E3E000
/* USB Clock Control */
#define PRM_PER_USB_OTG_SS0_CLKCTRL (CM_PER + 0x260)
#define PRM_PER_USB_OTG_SS1_CLKCTRL (CM_PER + 0x268)
#define USBOTGSSX_CLKCTRL_MODULE_EN (1 << 2)
#define USBOTGSSX_CLKCTRL_OPTFCLKEN_REFCLK960 (1 << 8)
#define PRM_PER_USBPHYOCP2SCP0_CLKCTRL (CM_PER + 0x5b8)
#define PRM_PER_USBPHYOCP2SCP1_CLKCTRL (CM_PER + 0x5c0)
#define USBPHYOCPSCP_MODULE_EN (1 << 2)
#endif /* __AM43XX_HARDWARE_AM43XX_H */

View File

@ -51,6 +51,8 @@
#define EXYNOS4_ACE_SFR_BASE DEVICE_NOT_AVAILABLE
#define EXYNOS4_DMC_PHY_BASE DEVICE_NOT_AVAILABLE
#define EXYNOS4_AUDIOSS_BASE DEVICE_NOT_AVAILABLE
#define EXYNOS4_USB_HOST_XHCI_BASE DEVICE_NOT_AVAILABLE
#define EXYNOS4_USB3PHY_BASE DEVICE_NOT_AVAILABLE
/* EXYNOS4X12 */
#define EXYNOS4X12_GPIO_PART3_BASE 0x03860000
@ -87,6 +89,8 @@
#define EXYNOS4X12_ACE_SFR_BASE DEVICE_NOT_AVAILABLE
#define EXYNOS4X12_DMC_PHY_BASE DEVICE_NOT_AVAILABLE
#define EXYNOS4X12_AUDIOSS_BASE DEVICE_NOT_AVAILABLE
#define EXYNOS4X12_USB_HOST_XHCI_BASE DEVICE_NOT_AVAILABLE
#define EXYNOS4X12_USB3PHY_BASE DEVICE_NOT_AVAILABLE
/* EXYNOS5 Common*/
#define EXYNOS5_I2C_SPACING 0x10000
@ -106,6 +110,8 @@
#define EXYNOS5_DMC_CTRL_BASE 0x10DD0000
#define EXYNOS5_GPIO_PART1_BASE 0x11400000
#define EXYNOS5_MIPI_DSIM_BASE 0x11D00000
#define EXYNOS5_USB_HOST_XHCI_BASE 0x12000000
#define EXYNOS5_USB3PHY_BASE 0x12100000
#define EXYNOS5_USB_HOST_EHCI_BASE 0x12110000
#define EXYNOS5_USBPHY_BASE 0x12130000
#define EXYNOS5_USBOTG_BASE 0x12140000
@ -220,7 +226,9 @@ SAMSUNG_BASE(swreset, SWRESET)
SAMSUNG_BASE(timer, PWMTIMER_BASE)
SAMSUNG_BASE(uart, UART_BASE)
SAMSUNG_BASE(usb_phy, USBPHY_BASE)
SAMSUNG_BASE(usb3_phy, USB3PHY_BASE)
SAMSUNG_BASE(usb_ehci, USB_HOST_EHCI_BASE)
SAMSUNG_BASE(usb_xhci, USB_HOST_XHCI_BASE)
SAMSUNG_BASE(usb_otg, USBOTG_BASE)
SAMSUNG_BASE(watchdog, WATCHDOG_BASE)
SAMSUNG_BASE(power, POWER_BASE)

View File

@ -847,6 +847,11 @@ void set_hw_thermal_trip(void);
#define POWER_USB_HOST_PHY_CTRL_EN (1 << 0)
#define POWER_USB_HOST_PHY_CTRL_DISABLE (0 << 0)
void set_usbdrd_phy_ctrl(unsigned int enable);
#define POWER_USB_DRD_PHY_CTRL_EN (1 << 0)
#define POWER_USB_DRD_PHY_CTRL_DISABLE (0 << 0)
void set_dp_phy_ctrl(unsigned int enable);
#define EXYNOS_DP_PHY_ENABLE (1 << 0)

View File

@ -0,0 +1,88 @@
/* Copyright (c) 2012 Samsung Electronics Co. Ltd
*
* Exynos Phy register definitions
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _ASM_ARCH_XHCI_EXYNOS_H_
#define _ASM_ARCH_XHCI_EXYNOS_H_
/* Phy register MACRO definitions */
#define LINKSYSTEM_FLADJ_MASK (0x3f << 1)
#define LINKSYSTEM_FLADJ(_x) ((_x) << 1)
#define LINKSYSTEM_XHCI_VERSION_CONTROL (0x1 << 27)
#define PHYUTMI_OTGDISABLE (1 << 6)
#define PHYUTMI_FORCESUSPEND (1 << 1)
#define PHYUTMI_FORCESLEEP (1 << 0)
#define PHYCLKRST_SSC_REFCLKSEL_MASK (0xff << 23)
#define PHYCLKRST_SSC_REFCLKSEL(_x) ((_x) << 23)
#define PHYCLKRST_SSC_RANGE_MASK (0x03 << 21)
#define PHYCLKRST_SSC_RANGE(_x) ((_x) << 21)
#define PHYCLKRST_SSC_EN (0x1 << 20)
#define PHYCLKRST_REF_SSP_EN (0x1 << 19)
#define PHYCLKRST_REF_CLKDIV2 (0x1 << 18)
#define PHYCLKRST_MPLL_MULTIPLIER_MASK (0x7f << 11)
#define PHYCLKRST_MPLL_MULTIPLIER_100MHZ_REF (0x19 << 11)
#define PHYCLKRST_MPLL_MULTIPLIER_50M_REF (0x02 << 11)
#define PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF (0x68 << 11)
#define PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF (0x7d << 11)
#define PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF (0x02 << 11)
#define PHYCLKRST_FSEL_MASK (0x3f << 5)
#define PHYCLKRST_FSEL(_x) ((_x) << 5)
#define PHYCLKRST_FSEL_PAD_100MHZ (0x27 << 5)
#define PHYCLKRST_FSEL_PAD_24MHZ (0x2a << 5)
#define PHYCLKRST_FSEL_PAD_20MHZ (0x31 << 5)
#define PHYCLKRST_FSEL_PAD_19_2MHZ (0x38 << 5)
#define PHYCLKRST_RETENABLEN (0x1 << 4)
#define PHYCLKRST_REFCLKSEL_MASK (0x03 << 2)
#define PHYCLKRST_REFCLKSEL_PAD_REFCLK (0x2 << 2)
#define PHYCLKRST_REFCLKSEL_EXT_REFCLK (0x3 << 2)
#define PHYCLKRST_PORTRESET (0x1 << 1)
#define PHYCLKRST_COMMONONN (0x1 << 0)
#define PHYPARAM0_REF_USE_PAD (0x1 << 31)
#define PHYPARAM0_REF_LOSLEVEL_MASK (0x1f << 26)
#define PHYPARAM0_REF_LOSLEVEL (0x9 << 26)
#define PHYPARAM1_PCS_TXDEEMPH_MASK (0x1f << 0)
#define PHYPARAM1_PCS_TXDEEMPH (0x1c)
#define PHYTEST_POWERDOWN_SSP (0x1 << 3)
#define PHYTEST_POWERDOWN_HSP (0x1 << 2)
#define PHYBATCHG_UTMI_CLKSEL (0x1 << 2)
#define FSEL_CLKSEL_24M (0x5)
/* XHCI PHY register structure */
struct exynos_usb3_phy {
unsigned int reserve1;
unsigned int link_system;
unsigned int phy_utmi;
unsigned int phy_pipe;
unsigned int phy_clk_rst;
unsigned int phy_reg0;
unsigned int phy_reg1;
unsigned int phy_param0;
unsigned int phy_param1;
unsigned int phy_term;
unsigned int phy_test;
unsigned int phy_adp;
unsigned int phy_batchg;
unsigned int phy_resume;
unsigned int reserve2[3];
unsigned int link_port;
};
#endif /* _ASM_ARCH_XHCI_EXYNOS_H_ */

View File

@ -9,6 +9,12 @@
#define MX6_IOMUXC_GPR6 0x020e0018
#define MX6_IOMUXC_GPR7 0x020e001c
/*
* IOMUXC_GPR1 bit fields
*/
#define IOMUXC_GPR1_OTG_ID_ENET_RX_ERR (0<<13)
#define IOMUXC_GPR1_OTG_ID_GPIO1 (1<<13)
#define IOMUXC_GPR1_OTG_ID_MASK (1<<13)
/*
* IOMUXC_GPR13 bit fields
*/

View File

@ -166,6 +166,16 @@
#define OPTFCLKEN_USB_CH1_CLK_ENABLE (1 << 9)
#define OPTFCLKEN_USB_CH2_CLK_ENABLE (1 << 10)
/* CM_COREAON_USB_PHY_CORE_CLKCTRL */
#define USBPHY_CORE_CLKCTRL_OPTFCLKEN_CLK32K (1 << 8)
/* CM_L3INIT_USB_OTG_SS_CLKCTRL */
#define OTG_SS_CLKCTRL_MODULEMODE_HW (1 << 0)
#define OPTFCLKEN_REFCLK960M (1 << 8)
/* CM_L3INIT_OCP2SCP1_CLKCTRL */
#define OCP2SCP1_CLKCTRL_MODULEMODE_HW (1 << 0)
/* CM_MPU_MPU_CLKCTRL */
#define MPU_CLKCTRL_CLKSEL_EMIF_DIV_MODE_SHIFT 24
#define MPU_CLKCTRL_CLKSEL_EMIF_DIV_MODE_MASK (3 << 24)
@ -192,6 +202,10 @@
/* PRM_VC_VAL_BYPASS */
#define PRM_VC_I2C_CHANNEL_FREQ_KHZ 400
/* CTRL_CORE_SRCOMP_NORTH_SIDE */
#define USB2PHY_DISCHGDET (1 << 29)
#define USB2PHY_AUTORESUME_EN (1 << 30)
/* SMPS */
#define SMPS_I2C_SLAVE_ADDR 0x12
#define SMPS_REG_ADDR_12_MPU 0x23

View File

@ -131,8 +131,7 @@
/* USB3_IF_USB_PHY_VBUS_SENSORS_0 */
#define VBUS_VLD_STS (1 << 26)
/* Setup USB on the board */
int board_usb_init(const void *blob);
int usb_process_devicetree(const void *blob);
#endif /* _TEGRA_USB_H_ */

View File

@ -145,8 +145,8 @@ struct omap_ehci {
struct ehci_hccr;
struct ehci_hcor;
int omap_ehci_hcd_init(struct omap_usbhs_board_data *usbhs_pdata,
struct ehci_hccr **hccr, struct ehci_hcor **hcor);
int omap_ehci_hcd_init(int index, struct omap_usbhs_board_data *usbhs_pdata,
struct ehci_hccr **hccr, struct ehci_hcor **hcor);
int omap_ehci_hcd_stop(void);
#endif /* _OMAP_COMMON_EHCI_H_ */

View File

@ -143,6 +143,8 @@ struct prcm_regs {
u32 cm_div_m2_dpll_unipro;
u32 cm_ssc_deltamstep_dpll_unipro;
u32 cm_ssc_modfreqdiv_dpll_unipro;
u32 cm_coreaon_usb_phy_core_clkctrl;
u32 cm_coreaon_usb_phy2_core_clkctrl;
/* cm2.core */
u32 cm_coreaon_bandgap_clkctrl;
@ -226,6 +228,8 @@ struct prcm_regs {
u32 cm_l3init_p1500_clkctrl;
u32 cm_l3init_fsusb_clkctrl;
u32 cm_l3init_ocp2scp1_clkctrl;
u32 cm_l3init_ocp2scp3_clkctrl;
u32 cm_l3init_usb_otg_ss_clkctrl;
u32 prm_irqstatus_mpu_2;
@ -348,6 +352,7 @@ struct omap_sys_ctrl_regs {
u32 control_core_mac_id_1_lo;
u32 control_core_mac_id_1_hi;
u32 control_std_fuse_opp_vdd_mpu_2;
u32 control_phy_power_usb;
u32 control_core_mmr_lock1;
u32 control_core_mmr_lock2;
u32 control_core_mmr_lock3;

View File

@ -1548,7 +1548,7 @@ static void hc_release_ohci (ohci_t *ohci)
*/
static char ohci_inited = 0;
int usb_lowlevel_init(int index, void **controller)
int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
{
u32 pin_func;
u32 sys_freqctrl, sys_clksrc;

View File

@ -1544,7 +1544,7 @@ static void hc_release_ohci (ohci_t *ohci)
*/
static char ohci_inited = 0;
int usb_lowlevel_init(int index, void **controller)
int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
{
/* Set the USB Clock */

View File

@ -1549,7 +1549,7 @@ static void hc_release_ohci (ohci_t *ohci)
*/
static char ohci_inited = 0;
int usb_lowlevel_init(int index, void **controller)
int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
{
memset (&gohci, 0, sizeof (ohci_t));
memset (&urb_priv, 0, sizeof (urb_priv_t));

View File

@ -688,7 +688,7 @@ void handle_usb_interrupt(void)
/* init uhci
*/
int usb_lowlevel_init(int index, void **controller)
int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
{
unsigned char temp;
ambapp_ahbdev ahbdev;

View File

@ -16,6 +16,7 @@
#include <asm/4xx_pcie.h>
#include <asm/ppc4xx-gpio.h>
#include <asm/errno.h>
#include <usb.h>
extern flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
@ -188,7 +189,7 @@ int board_early_init_f(void)
}
#if defined(CONFIG_USB_OHCI_NEW) && defined(CONFIG_SYS_USB_OHCI_BOARD_INIT)
int usb_board_init(void)
int board_usb_init(int index, enum usb_init_type init)
{
struct board_bcsr *bcsr_data =
(struct board_bcsr *)CONFIG_SYS_BCSR_BASE;
@ -229,7 +230,7 @@ int usb_board_stop(void)
return 0;
}
int usb_board_init_fail(void)
int board_usb_cleanup(int index, enum usb_init_type init)
{
return usb_board_stop();
}

View File

@ -13,6 +13,7 @@
#include <asm/io.h>
#include <spartan3.h>
#include <command.h>
#include <usb.h>
DECLARE_GLOBAL_DATA_PTR;
@ -59,7 +60,7 @@ void dram_init_banksize(void)
}
#ifdef CONFIG_CMD_USB
int usb_board_init(void)
int board_usb_init(int index, enum usb_init_type init)
{
writel((readl(UHCHR) | UHCHR_PCPL | UHCHR_PSPL) &
~(UHCHR_SSEP0 | UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSE),
@ -90,9 +91,9 @@ int usb_board_init(void)
return 0;
}
void usb_board_init_fail(void)
int board_usb_cleanup(int index, enum usb_init_type init)
{
return;
return 0;
}
void usb_board_stop(void)

View File

@ -30,6 +30,7 @@
#include <i2c.h>
DECLARE_GLOBAL_DATA_PTR;
#define GP_USB_OTG_PWR IMX_GPIO_NR(3, 22)
#define UART_PAD_CTRL (PAD_CTL_PUS_100K_UP | \
PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | \
@ -179,6 +180,14 @@ iomux_v3_cfg_t const enet_pads2[] = {
MX6_PAD_RGMII_RX_CTL__RGMII_RX_CTL | MUX_PAD_CTRL(ENET_PAD_CTRL),
};
static iomux_v3_cfg_t const misc_pads[] = {
MX6_PAD_GPIO_1__USB_OTG_ID | MUX_PAD_CTRL(WEAK_PULLUP),
MX6_PAD_KEY_COL4__USBOH3_USBOTG_OC | MUX_PAD_CTRL(WEAK_PULLUP),
MX6_PAD_EIM_D30__USBOH3_USBH1_OC | MUX_PAD_CTRL(WEAK_PULLUP),
/* OTG Power enable */
MX6_PAD_EIM_D22__GPIO_3_22 | MUX_PAD_CTRL(OUTPUT_40OHM),
};
/* wl1271 pads on nitrogen6x */
iomux_v3_cfg_t const wl12xx_pads[] = {
(MX6_PAD_NANDF_CS1__GPIO_6_14 & ~MUX_PAD_CTRL_MASK)
@ -250,6 +259,15 @@ int board_ehci_hcd_init(int port)
return 0;
}
int board_ehci_power(int port, int on)
{
if (port)
return 0;
gpio_set_value(GP_USB_OTG_PWR, on);
return 0;
}
#endif
#ifdef CONFIG_FSL_ESDHC
@ -369,6 +387,11 @@ int board_eth_init(bd_t *bis)
free(bus);
}
#endif
#ifdef CONFIG_MV_UDC
/* For otg ethernet*/
usb_eth_initialize(bis);
#endif
return 0;
}
@ -685,6 +708,7 @@ int board_early_init_f(void)
gpio_direction_input(WL12XX_WL_IRQ_GP);
gpio_direction_output(WL12XX_WL_ENABLE_GP, 0);
gpio_direction_output(WL12XX_BT_ENABLE_GP, 0);
gpio_direction_output(GP_USB_OTG_PWR, 0); /* OTG power off */
imx_iomux_v3_setup_multiple_pads(wl12xx_pads, ARRAY_SIZE(wl12xx_pads));
setup_buttons();
@ -706,6 +730,15 @@ int overwrite_console(void)
int board_init(void)
{
struct iomuxc_base_regs *const iomuxc_regs
= (struct iomuxc_base_regs *)IOMUXC_BASE_ADDR;
clrsetbits_le32(&iomuxc_regs->gpr[1],
IOMUXC_GPR1_OTG_ID_MASK,
IOMUXC_GPR1_OTG_ID_GPIO1);
imx_iomux_v3_setup_multiple_pads(misc_pads, ARRAY_SIZE(misc_pads));
/* address of boot parameters */
gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;

View File

@ -565,7 +565,8 @@ struct omap_usbhs_board_data usbhs_bdata = {
};
#define SB_T35_USB_HUB_RESET_GPIO 167
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
u8 val;
int offset;
@ -591,7 +592,7 @@ int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
twl4030_i2c_write_u8(TWL4030_CHIP_GPIO, offset, 0xC0);
udelay(1);
return omap_ehci_hcd_init(&usbhs_bdata, hccr, hcor);
return omap_ehci_hcd_init(index, &usbhs_bdata, hccr, hcor);
}
int ehci_hcd_stop(void)

View File

@ -17,6 +17,7 @@
#include <mtd/cfi_flash.h>
#include <asm/4xx_pci.h>
#include <pci.h>
#include <usb.h>
DECLARE_GLOBAL_DATA_PTR;
@ -428,7 +429,7 @@ void reset_phy(void)
}
#if defined(CONFIG_USB_OHCI_NEW) && defined(CONFIG_SYS_USB_OHCI_BOARD_INIT)
int usb_board_init(void)
int board_usb_init(int index, enum usb_init_type init)
{
return 0;
}
@ -453,9 +454,8 @@ int usb_board_stop(void)
return 0;
}
int usb_board_init_fail(void)
int board_usb_cleanup(int index, enum usb_init_type init)
{
usb_board_stop();
return 0;
return usb_board_stop();
}
#endif /* defined(CONFIG_USB_OHCI) && defined(CONFIG_SYS_USB_OHCI_BOARD_INIT) */

View File

@ -27,6 +27,7 @@
#endif
#include <serial.h>
#include <asm/4xx_pci.h>
#include <usb.h>
#include "fpga.h"
#include "pmc440.h"
@ -821,7 +822,7 @@ int bootstrap_eeprom_read (unsigned dev_addr, unsigned offset,
}
#if defined(CONFIG_USB_OHCI_NEW) && defined(CONFIG_SYS_USB_OHCI_BOARD_INIT)
int usb_board_init(void)
int board_usb_init(int index, enum usb_init_type init)
{
char *act = getenv("usbact");
int i;
@ -845,10 +846,9 @@ int usb_board_stop(void)
return 0;
}
int usb_board_init_fail(void)
int board_usb_cleanup(int index, enum usb_init_type init)
{
usb_board_stop();
return 0;
return usb_board_stop();
}
#endif /* defined(CONFIG_USB_OHCI) && defined(CONFIG_SYS_USB_OHCI_BOARD_INIT) */

View File

@ -40,9 +40,10 @@ static struct omap_usbhs_board_data usbhs_bdata = {
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
};
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
return omap_ehci_hcd_init(&usbhs_bdata, hccr, hcor);
return omap_ehci_hcd_init(index, &usbhs_bdata, hccr, hcor);
}
int ehci_hcd_stop(int index)

View File

@ -15,6 +15,7 @@
#include <netdev.h>
#include <serial.h>
#include <asm/io.h>
#include <usb.h>
DECLARE_GLOBAL_DATA_PTR;
@ -58,7 +59,7 @@ int board_mmc_init(bd_t *bis)
#endif
#ifdef CONFIG_CMD_USB
int usb_board_init(void)
int board_usb_init(int index, enum usb_init_type init)
{
writel((UHCHR | UHCHR_PCPL | UHCHR_PSPL) &
~(UHCHR_SSEP0 | UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSE),
@ -89,9 +90,9 @@ int usb_board_init(void)
return 0;
}
void usb_board_init_fail(void)
int board_usb_cleanup(int index, enum usb_init_type init)
{
return;
return 0;
}
void usb_board_stop(void)

View File

@ -584,7 +584,7 @@ void handle_usb_interrupt(void)
/* init uhci
*/
int usb_lowlevel_init(int index, void **controller)
int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
{
unsigned char temp;
int busdevfunc;

View File

@ -32,6 +32,7 @@
#ifdef CONFIG_USB_EHCI_TEGRA
#include <asm/arch-tegra/usb.h>
#include <asm/arch/usb.h>
#include <usb.h>
#endif
#ifdef CONFIG_TEGRA_MMC
#include <asm/arch-tegra/tegra_mmc.h>
@ -153,8 +154,9 @@ int board_init(void)
#ifdef CONFIG_USB_EHCI_TEGRA
pin_mux_usb();
board_usb_init(gd->fdt_blob);
usb_process_devicetree(gd->fdt_blob);
#endif
#ifdef CONFIG_LCD
tegra_lcd_check_next_stage(gd->fdt_blob, 0);
#endif

View File

@ -10,6 +10,7 @@ include $(TOPDIR)/config.mk
LIB = $(obj)libsamsung.o
COBJS-$(CONFIG_SOFT_I2C_MULTI_BUS) += multi_i2c.o
COBJS-$(CONFIG_THOR_FUNCTION) += thor.o
SRCS := $(COBJS-y:.o=.c)
OBJS := $(addprefix $(obj),$(COBJS-y))

View File

@ -0,0 +1,21 @@
/*
* Copyright (C) 2013 Samsung Electronics
* Lukasz Majewski <l.majewski@samsung.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <linux/usb/ch9.h>
int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
{
if (!strcmp(name, "usb_dnl_thor")) {
put_unaligned(CONFIG_G_DNL_THOR_VENDOR_NUM, &dev->idVendor);
put_unaligned(CONFIG_G_DNL_THOR_PRODUCT_NUM, &dev->idProduct);
} else {
put_unaligned(CONFIG_G_DNL_VENDOR_NUM, &dev->idVendor);
put_unaligned(CONFIG_G_DNL_PRODUCT_NUM, &dev->idProduct);
}
return 0;
}

View File

@ -144,4 +144,8 @@
mmc@12230000 {
status = "disabled";
};
ehci@12110000 {
samsung,vbus-gpio = <&gpio 0xbe 0>; /* X26 */
};
};

View File

@ -109,6 +109,14 @@
status = "disabled";
};
ehci@12110000 {
samsung,vbus-gpio = <&gpio 0xb1 0>; /* X11 */
};
xhci@12000000 {
samsung,vbus-gpio = <&gpio 0xbf 0>; /* X27 */
};
tmu@10060000 {
samsung,min-temp = <25>;
samsung,max-temp = <125>;

View File

@ -61,22 +61,6 @@ struct local_info {
static struct local_info local;
#ifdef CONFIG_USB_EHCI_EXYNOS
int board_usb_vbus_init(void)
{
struct exynos5_gpio_part1 *gpio1 = (struct exynos5_gpio_part1 *)
samsung_get_base_gpio_part1();
/* Enable VBUS power switch */
s5p_gpio_direction_output(&gpio1->x2, 6, 1);
/* VBUS turn ON time */
mdelay(3);
return 0;
}
#endif
#ifdef CONFIG_SOUND_MAX98095
static void board_enable_audio_codec(void)
{
@ -122,9 +106,6 @@ int board_init(void)
if (board_init_cros_ec_devices(gd->fdt_blob))
return -1;
#ifdef CONFIG_USB_EHCI_EXYNOS
board_usb_vbus_init();
#endif
#ifdef CONFIG_SOUND_MAX98095
board_enable_audio_codec();
#endif

View File

@ -26,6 +26,7 @@
#include <power/max8997_muic.h>
#include <power/battery.h>
#include <power/max17042_fg.h>
#include <usb.h>
#include <usb_mass_storage.h>
#include "setup.h"
@ -495,10 +496,10 @@ struct s3c_plat_otg_data s5pc210_otg_data = {
.usb_flags = PHY0_SLEEP,
};
void board_usb_init(void)
int board_usb_init(int index, enum usb_init_type init)
{
debug("USB_udc_probe\n");
s3c_udc_probe(&s5pc210_otg_data);
return s3c_udc_probe(&s5pc210_otg_data);
}
#endif

View File

@ -275,7 +275,7 @@ int factoryset_setenv(void)
return ret;
}
int g_dnl_bind_fixup(struct usb_device_descriptor *dev)
int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
{
put_unaligned(factory_dat.usb_vendor_id, &dev->idVendor);
put_unaligned(factory_dat.usb_product_id, &dev->idProduct);

View File

@ -51,9 +51,10 @@ static struct omap_usbhs_board_data usbhs_bdata = {
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
};
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
return omap_ehci_hcd_init(&usbhs_bdata, hccr, hcor);
return omap_ehci_hcd_init(index, &usbhs_bdata, hccr, hcor);
}
int ehci_hcd_stop(int index)

View File

@ -102,9 +102,10 @@ static struct omap_usbhs_board_data usbhs_bdata = {
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
};
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
return omap_ehci_hcd_init(&usbhs_bdata, hccr, hcor);
return omap_ehci_hcd_init(index, &usbhs_bdata, hccr, hcor);
}
int ehci_hcd_stop(int index)

View File

@ -521,9 +521,10 @@ static struct omap_usbhs_board_data usbhs_bdata = {
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED
};
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
return omap_ehci_hcd_init(&usbhs_bdata, hccr, hcor);
return omap_ehci_hcd_init(index, &usbhs_bdata, hccr, hcor);
}
int ehci_hcd_stop(int index)

View File

@ -17,12 +17,6 @@
#include "mux_data.h"
#ifdef CONFIG_USB_EHCI
#include <usb.h>
#include <asm/arch/ehci.h>
#include <asm/ehci-omap.h>
#endif
#ifdef CONFIG_DRIVER_TI_CPSW
#include <cpsw.h>
#endif

View File

@ -61,5 +61,6 @@ const struct pad_conf_entry core_padconf_array_essential[] = {
{GPMC_A4, (IEN | PDIS | M1)}, /* QSPI1_CS3 */
{GPMC_CS2, (IEN | PTU | PDIS | M1)}, /* QSPI1_CS0 */
{GPMC_CS3, (IEN | PTU | PDIS | M1)}, /* QSPI1_CS1*/
{USB2_DRVVBUS, (M0 | IEN | FSC) },
};
#endif /* _MUX_DATA_DRA7XX_H_ */

View File

@ -14,7 +14,7 @@
#include "mux_data.h"
#ifdef CONFIG_USB_EHCI
#if defined(CONFIG_USB_EHCI) || defined(CONFIG_USB_XHCI_OMAP)
#include <usb.h>
#include <asm/gpio.h>
#include <asm/arch/clock.h>
@ -72,6 +72,35 @@ int board_eth_init(bd_t *bis)
return 0;
}
#if defined(CONFIG_USB_EHCI) || defined(CONFIG_USB_XHCI_OMAP)
static void enable_host_clocks(void)
{
int auxclk;
int hs_clk_ctrl_val = (OPTFCLKEN_HSIC60M_P3_CLK |
OPTFCLKEN_HSIC480M_P3_CLK |
OPTFCLKEN_HSIC60M_P2_CLK |
OPTFCLKEN_HSIC480M_P2_CLK |
OPTFCLKEN_UTMI_P3_CLK | OPTFCLKEN_UTMI_P2_CLK);
/* Enable port 2 and 3 clocks*/
setbits_le32((*prcm)->cm_l3init_hsusbhost_clkctrl, hs_clk_ctrl_val);
/* Enable port 2 and 3 usb host ports tll clocks*/
setbits_le32((*prcm)->cm_l3init_hsusbtll_clkctrl,
(OPTFCLKEN_USB_CH1_CLK_ENABLE | OPTFCLKEN_USB_CH2_CLK_ENABLE));
#ifdef CONFIG_USB_XHCI_OMAP
/* Enable the USB OTG Super speed clocks */
setbits_le32((*prcm)->cm_l3init_usb_otg_ss_clkctrl,
(OPTFCLKEN_REFCLK960M | OTG_SS_CLKCTRL_MODULEMODE_HW));
#endif
auxclk = readl((*prcm)->scrm_auxclk1);
/* Request auxilary clock */
auxclk |= AUXCLK_ENABLE_MASK;
writel(auxclk, (*prcm)->scrm_auxclk1);
}
#endif
/**
* @brief misc_init_r - Configure EVM board specific configurations
* such as power configurations, ethernet initialization as phase2 of
@ -81,9 +110,30 @@ int board_eth_init(bd_t *bis)
*/
int misc_init_r(void)
{
int reg;
uint8_t device_mac[6];
#ifdef CONFIG_PALMAS_POWER
palmas_init_settings();
#endif
if (!getenv("usbethaddr")) {
reg = DIE_ID_REG_BASE + DIE_ID_REG_OFFSET;
/*
* create a fake MAC address from the processor ID code.
* first byte is 0x02 to signify locally administered.
*/
device_mac[0] = 0x02;
device_mac[1] = readl(reg + 0x10) & 0xff;
device_mac[2] = readl(reg + 0xC) & 0xff;
device_mac[3] = readl(reg + 0x8) & 0xff;
device_mac[4] = readl(reg) & 0xff;
device_mac[5] = (readl(reg) >> 8) & 0xff;
eth_setenv_enetaddr("usbethaddr", device_mac);
}
return 0;
}
@ -129,54 +179,14 @@ static struct omap_usbhs_board_data usbhs_bdata = {
.port_mode[2] = OMAP_EHCI_PORT_MODE_HSIC,
};
static void enable_host_clocks(void)
{
int hs_clk_ctrl_val = (OPTFCLKEN_HSIC60M_P3_CLK |
OPTFCLKEN_HSIC480M_P3_CLK |
OPTFCLKEN_HSIC60M_P2_CLK |
OPTFCLKEN_HSIC480M_P2_CLK |
OPTFCLKEN_UTMI_P3_CLK | OPTFCLKEN_UTMI_P2_CLK);
/* Enable port 2 and 3 clocks*/
setbits_le32((*prcm)->cm_l3init_hsusbhost_clkctrl, hs_clk_ctrl_val);
/* Enable port 2 and 3 usb host ports tll clocks*/
setbits_le32((*prcm)->cm_l3init_hsusbtll_clkctrl,
(OPTFCLKEN_USB_CH1_CLK_ENABLE | OPTFCLKEN_USB_CH2_CLK_ENABLE));
}
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
int ret;
int auxclk;
int reg;
uint8_t device_mac[6];
enable_host_clocks();
if (!getenv("usbethaddr")) {
reg = DIE_ID_REG_BASE + DIE_ID_REG_OFFSET;
/*
* create a fake MAC address from the processor ID code.
* first byte is 0x02 to signify locally administered.
*/
device_mac[0] = 0x02;
device_mac[1] = readl(reg + 0x10) & 0xff;
device_mac[2] = readl(reg + 0xC) & 0xff;
device_mac[3] = readl(reg + 0x8) & 0xff;
device_mac[4] = readl(reg) & 0xff;
device_mac[5] = (readl(reg) >> 8) & 0xff;
eth_setenv_enetaddr("usbethaddr", device_mac);
}
auxclk = readl((*prcm)->scrm_auxclk1);
/* Request auxilary clock */
auxclk |= AUXCLK_ENABLE_MASK;
writel(auxclk, (*prcm)->scrm_auxclk1);
ret = omap_ehci_hcd_init(&usbhs_bdata, hccr, hcor);
ret = omap_ehci_hcd_init(index, &usbhs_bdata, hccr, hcor);
if (ret < 0) {
puts("Failed to initialize ehci\n");
return ret;
@ -203,3 +213,23 @@ void usb_hub_reset_devices(int port)
}
}
#endif
#ifdef CONFIG_USB_XHCI_OMAP
/**
* @brief board_usb_init - Configure EVM board specific configurations
* for the LDO's and clocks for the USB blocks.
*
* @return 0
*/
int board_usb_init(int index, enum board_usb_init_type init)
{
int ret;
#ifdef CONFIG_PALMAS_USB_SS_PWR
ret = palmas_enable_ss_ldo();
#endif
enable_host_clocks();
return 0;
}
#endif

View File

@ -269,7 +269,8 @@ static struct omap_usbhs_board_data usbhs_bdata = {
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
};
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
int ret;
unsigned int utmi_clk;
@ -279,7 +280,7 @@ int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
utmi_clk |= HSUSBHOST_CLKCTRL_CLKSEL_UTMI_P1_MASK;
sr32((void *)CM_L3INIT_HSUSBHOST_CLKCTRL, 0, 32, utmi_clk);
ret = omap_ehci_hcd_init(&usbhs_bdata, hccr, hcor);
ret = omap_ehci_hcd_init(index, &usbhs_bdata, hccr, hcor);
if (ret < 0)
return ret;

View File

@ -13,6 +13,7 @@
#include <netdev.h>
#include <asm/io.h>
#include <serial.h>
#include <usb.h>
DECLARE_GLOBAL_DATA_PTR;
@ -39,7 +40,7 @@ int dram_init(void)
}
#ifdef CONFIG_CMD_USB
int usb_board_init(void)
int board_usb_init(int index, enum usb_init_type init)
{
writel((readl(UHCHR) | UHCHR_PCPL | UHCHR_PSPL) &
~(UHCHR_SSEP0 | UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSE),
@ -70,9 +71,9 @@ int usb_board_init(void)
return 0;
}
void usb_board_init_fail(void)
int board_usb_cleanup(int index, enum usb_init_type init)
{
return;
return 0;
}
void usb_board_stop(void)

View File

@ -21,6 +21,7 @@
#include <asm/arch/regs-mmc.h>
#include <netdev.h>
#include <asm/io.h>
#include <usb.h>
DECLARE_GLOBAL_DATA_PTR;
@ -42,7 +43,7 @@ extern struct serial_device serial_stuart_device;
* Miscelaneous platform dependent initialisations
*/
int usb_board_init(void)
int board_usb_init(int index, enum usb_init_type init)
{
writel((readl(UHCHR) | UHCHR_PCPL | UHCHR_PSPL) &
~(UHCHR_SSEP0 | UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSE),
@ -69,9 +70,9 @@ int usb_board_init(void)
return 0;
}
void usb_board_init_fail(void)
int board_usb_cleanup(int index, enum usb_init_type init)
{
return;
return 0;
}
void usb_board_stop(void)

View File

@ -13,6 +13,7 @@
#include <netdev.h>
#include <serial.h>
#include <asm/io.h>
#include <usb.h>
DECLARE_GLOBAL_DATA_PTR;
@ -66,7 +67,7 @@ int board_mmc_init(bd_t *bis)
#endif
#ifdef CONFIG_CMD_USB
int usb_board_init(void)
int board_usb_init(int index, enum usb_init_type init)
{
writel((UHCHR | UHCHR_PCPL | UHCHR_PSPL) &
~(UHCHR_SSEP0 | UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSE),
@ -97,9 +98,9 @@ int usb_board_init(void)
return 0;
}
void usb_board_init_fail(void)
int board_usb_cleanup(int index, enum usb_init_type init)
{
return;
return 0;
}
void usb_board_stop(void)

View File

@ -168,6 +168,7 @@ COBJS-y += usb.o usb_hub.o
COBJS-$(CONFIG_USB_STORAGE) += usb_storage.o
endif
COBJS-$(CONFIG_CMD_USB_MASS_STORAGE) += cmd_usb_mass_storage.o
COBJS-$(CONFIG_CMD_THOR_DOWNLOAD) += cmd_thordown.o
COBJS-$(CONFIG_CMD_XIMG) += cmd_ximg.o
COBJS-$(CONFIG_YAFFS2) += cmd_yaffs2.o
COBJS-$(CONFIG_CMD_SPL) += cmd_spl.o

View File

@ -11,27 +11,32 @@
#include <common.h>
#include <dfu.h>
#include <g_dnl.h>
#include <usb.h>
static int do_dfu(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
if (argc < 4)
return CMD_RET_USAGE;
char *usb_controller = argv[1];
char *interface = argv[2];
char *devstring = argv[3];
char *s = "dfu";
int ret, i = 0;
if (argc < 3)
return CMD_RET_USAGE;
ret = dfu_init_env_entities(argv[1], simple_strtoul(argv[2], NULL, 10));
ret = dfu_init_env_entities(interface, simple_strtoul(devstring,
NULL, 10));
if (ret)
return ret;
if (argc > 3 && strcmp(argv[3], "list") == 0) {
if (argc > 4 && strcmp(argv[4], "list") == 0) {
dfu_show_entities();
goto done;
}
#ifdef CONFIG_TRATS
board_usb_init();
#endif
int controller_index = simple_strtoul(usb_controller, NULL, 0);
board_usb_init(controller_index, USB_INIT_DEVICE);
g_dnl_register(s);
while (1) {
@ -62,8 +67,9 @@ done:
U_BOOT_CMD(dfu, CONFIG_SYS_MAXARGS, 1, do_dfu,
"Device Firmware Upgrade",
"<interface> <dev> [list]\n"
" - device firmware upgrade on a device <dev>\n"
" attached to interface <interface>\n"
" [list] - list available alt settings"
"<USB_controller> <interface> <dev> [list]\n"
" - device firmware upgrade via <USB_controller>\n"
" on device <dev>, attached to interface\n"
" <interface>\n"
" [list] - list available alt settings\n"
);

72
common/cmd_thordown.c Normal file
View File

@ -0,0 +1,72 @@
/*
* cmd_thordown.c -- USB TIZEN "THOR" Downloader gadget
*
* Copyright (C) 2013 Lukasz Majewski <l.majewski@samsung.com>
* All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <thor.h>
#include <dfu.h>
#include <g_dnl.h>
#include <usb.h>
int do_thor_down(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
if (argc < 4)
return CMD_RET_USAGE;
char *usb_controller = argv[1];
char *interface = argv[2];
char *devstring = argv[3];
const char *s = "thor";
int ret;
puts("TIZEN \"THOR\" Downloader\n");
ret = dfu_init_env_entities(interface, simple_strtoul(devstring,
NULL, 10));
if (ret)
return ret;
int controller_index = simple_strtoul(usb_controller, NULL, 0);
ret = board_usb_init(controller_index, USB_INIT_DEVICE);
if (ret) {
error("USB init failed: %d", ret);
ret = CMD_RET_FAILURE;
goto exit;
}
g_dnl_register(s);
ret = thor_init();
if (ret) {
error("THOR DOWNLOAD failed: %d", ret);
ret = CMD_RET_FAILURE;
goto exit;
}
ret = thor_handle();
if (ret) {
error("THOR failed: %d", ret);
ret = CMD_RET_FAILURE;
goto exit;
}
exit:
g_dnl_unregister();
dfu_free_entities();
return ret;
}
U_BOOT_CMD(thordown, CONFIG_SYS_MAXARGS, 1, do_thor_down,
"TIZEN \"THOR\" downloader",
"<USB_controller> <interface> <dev>\n"
" - device software upgrade via LTHOR TIZEN dowload\n"
" program via <USB_controller> on device <dev>,\n"
" attached to interface <interface>\n"
);

View File

@ -8,51 +8,53 @@
#include <common.h>
#include <command.h>
#include <g_dnl.h>
#include <usb.h>
#include <usb_mass_storage.h>
int do_usb_mass_storage(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
char *ep;
unsigned int dev_num = 0, offset = 0, part_size = 0;
int rc;
if (argc < 3)
return CMD_RET_USAGE;
struct ums_board_info *ums_info;
static char *s = "ums";
if (argc < 2) {
printf("usage: ums <dev> - e.g. ums 0\n");
return 0;
}
dev_num = (int)simple_strtoul(argv[1], &ep, 16);
const char *usb_controller = argv[1];
const char *mmc_devstring = argv[2];
unsigned int dev_num = (unsigned int)(simple_strtoul(mmc_devstring,
NULL, 0));
if (dev_num) {
puts("\nSet eMMC device to 0! - e.g. ums 0\n");
error("Set eMMC device to 0! - e.g. ums 0");
goto fail;
}
board_usb_init();
ums_info = board_ums_init(dev_num, offset, part_size);
unsigned int controller_index = (unsigned int)(simple_strtoul(
usb_controller, NULL, 0));
if (board_usb_init(controller_index, USB_INIT_DEVICE)) {
error("Couldn't init USB controller.");
goto fail;
}
struct ums_board_info *ums_info = board_ums_init(dev_num, 0, 0);
if (!ums_info) {
printf("MMC: %d -> NOT available\n", dev_num);
goto fail;
}
rc = fsg_init(ums_info);
if (rc) {
printf("cmd ums: fsg_init failed\n");
error("MMC: %d -> NOT available", dev_num);
goto fail;
}
g_dnl_register(s);
int rc = fsg_init(ums_info);
if (rc) {
error("fsg_init failed");
goto fail;
}
g_dnl_register("ums");
while (1) {
/* Handle control-c and timeouts */
if (ctrlc()) {
printf("The remote end did not respond in time.\n");
error("The remote end did not respond in time.");
goto exit;
}
usb_gadget_handle_interrupts();
/* Check if USB cable has been detached */
if (fsg_main_thread(NULL) == EIO)
@ -68,5 +70,5 @@ fail:
U_BOOT_CMD(ums, CONFIG_SYS_MAXARGS, 1, do_usb_mass_storage,
"Use the UMS [User Mass Storage]",
"ums - User Mass Storage Gadget"
"<USB_controller> <mmc_dev>"
);

View File

@ -33,6 +33,7 @@
#include <linux/ctype.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
#include <compiler.h>
#include <usb.h>
#ifdef CONFIG_4xx
@ -74,7 +75,7 @@ int usb_init(void)
for (i = 0; i < CONFIG_USB_MAX_CONTROLLER_COUNT; i++) {
/* init low_level USB */
printf("USB%d: ", i);
if (usb_lowlevel_init(i, &ctrl)) {
if (usb_lowlevel_init(i, USB_INIT_HOST, &ctrl)) {
puts("lowlevel init failed\n");
continue;
}
@ -854,6 +855,16 @@ void usb_free_device(void)
usb_dev[dev_index].devnum = -1;
}
/*
* XHCI issues Enable Slot command and thereafter
* allocates device contexts. Provide a weak alias
* function for the purpose, so that XHCI overrides it
* and EHCI/OHCI just work out of the box.
*/
__weak int usb_alloc_device(struct usb_device *udev)
{
return 0;
}
/*
* By the time we get here, the device has gotten a new device ID
* and is in the default state. We need to identify the thing and
@ -867,6 +878,17 @@ int usb_new_device(struct usb_device *dev)
int tmp;
ALLOC_CACHE_ALIGN_BUFFER(unsigned char, tmpbuf, USB_BUFSIZ);
/*
* Allocate usb 3.0 device context.
* USB 3.0 (xHCI) protocol tries to allocate device slot
* and related data structures first. This call does that.
* Refer to sec 4.3.2 in xHCI spec rev1.0
*/
if (usb_alloc_device(dev)) {
printf("Cannot allocate device context to get SLOT_ID\n");
return -1;
}
/* We still haven't set the Address yet */
addr = dev->devnum;
dev->devnum = 0;
@ -897,7 +919,7 @@ int usb_new_device(struct usb_device *dev)
* http://sourceforge.net/mailarchive/forum.php?
* thread_id=5729457&forum_id=5398
*/
struct usb_device_descriptor *desc;
__maybe_unused struct usb_device_descriptor *desc;
int port = -1;
struct usb_device *parent = dev->parent;
unsigned short portstatus;
@ -914,6 +936,13 @@ int usb_new_device(struct usb_device *dev)
dev->epmaxpacketin[0] = 64;
dev->epmaxpacketout[0] = 64;
/*
* XHCI needs to issue a Address device command to setup
* proper device context structures, before it can interact
* with the device. So a get_descriptor will fail before any
* of that is done for XHCI unlike EHCI.
*/
#ifndef CONFIG_USB_XHCI
err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, 64);
if (err < 0) {
debug("usb_new_device: usb_get_descriptor() failed\n");
@ -926,11 +955,12 @@ int usb_new_device(struct usb_device *dev)
* to differentiate between HUB and DEVICE.
*/
dev->descriptor.bDeviceClass = desc->bDeviceClass;
#endif
/* find the port number we're at */
if (parent) {
int j;
/* find the port number we're at */
for (j = 0; j < parent->maxchild; j++) {
if (parent->children[j] == dev) {
port = j;
@ -1037,4 +1067,9 @@ int usb_new_device(struct usb_device *dev)
return 0;
}
__weak
int board_usb_init(int index, enum usb_init_type init)
{
return 0;
}
/* EOF */

View File

@ -67,14 +67,14 @@ int dfu_init_env_entities(char *interface, int dev)
static unsigned char *dfu_buf;
static unsigned long dfu_buf_size = CONFIG_SYS_DFU_DATA_BUF_SIZE;
static unsigned char *dfu_free_buf(void)
unsigned char *dfu_free_buf(void)
{
free(dfu_buf);
dfu_buf = NULL;
return dfu_buf;
}
static unsigned char *dfu_get_buf(void)
unsigned char *dfu_get_buf(void)
{
char *s;
@ -330,7 +330,7 @@ int dfu_read(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num)
}
static int dfu_fill_entity(struct dfu_entity *dfu, char *s, int alt,
char *interface, int num)
char *interface, int num)
{
char *st;
@ -440,3 +440,15 @@ struct dfu_entity *dfu_get_entity(int alt)
return NULL;
}
int dfu_get_alt(char *name)
{
struct dfu_entity *dfu;
list_for_each_entry(dfu, &dfu_list, list) {
if (!strncmp(dfu->name, name, strlen(dfu->name)))
return dfu->alt;
}
return -ENODEV;
}

View File

@ -127,6 +127,21 @@ int twl603x_audio_power(u8 on)
}
#endif
#ifdef CONFIG_PALMAS_USB_SS_PWR
/**
* @brief palmas_enable_ss_ldo - Configure EVM board specific configurations
* for the USB Super speed SMPS10 regulator.
*
* @return 0
*/
int palmas_enable_ss_ldo(void)
{
/* Enable smps10 regulator */
return palmas_i2c_write_u8(TWL603X_CHIP_P1, SMPS10_CTRL,
SMPS10_MODE_ACTIVE_D);
}
#endif
/*
* Enable/disable back-up battery (or super cap) charging on TWL6035/37.
* Please use defined BB_xxx values.

View File

@ -16,8 +16,6 @@
#include <usb/mpc8xx_udc.h>
#elif defined(CONFIG_OMAP1510)
#include <usb/omap1510_udc.h>
#elif defined(CONFIG_MUSB_UDC)
#include <usb/musb_udc.h>
#elif defined(CONFIG_CPU_PXA27X)
#include <usb/pxa27x_udc.h>
#elif defined(CONFIG_DW_UDC)
@ -26,6 +24,7 @@
#include <usb/mv_udc.h>
#endif
#include <usb/udc.h>
#include <version.h>
/* If no VendorID/ProductID is defined in config.h, pretend to be Linux

View File

@ -14,6 +14,12 @@
/* SMSC LAN95xx based USB 2.0 Ethernet Devices */
/* LED defines */
#define LED_GPIO_CFG (0x24)
#define LED_GPIO_CFG_SPD_LED (0x01000000)
#define LED_GPIO_CFG_LNK_LED (0x00100000)
#define LED_GPIO_CFG_FDX_LED (0x00010000)
/* Tx command words */
#define TX_CMD_A_FIRST_SEG_ 0x00002000
#define TX_CMD_A_LAST_SEG_ 0x00001000
@ -591,6 +597,14 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd)
return ret;
debug("ID_REV = 0x%08x\n", read_buf);
/* Configure GPIO pins as LED outputs */
write_buf = LED_GPIO_CFG_SPD_LED | LED_GPIO_CFG_LNK_LED |
LED_GPIO_CFG_FDX_LED;
ret = smsc95xx_write_reg(dev, LED_GPIO_CFG, write_buf);
if (ret < 0)
return ret;
debug("LED_GPIO_CFG set\n");
/* Init Tx */
write_buf = 0;
ret = smsc95xx_write_reg(dev, FLOW, write_buf);

View File

@ -21,6 +21,7 @@ ifdef CONFIG_USB_GADGET
COBJS-$(CONFIG_USB_GADGET_ATMEL_USBA) += atmel_usba_udc.o
COBJS-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o
COBJS-$(CONFIG_USB_GADGET_FOTG210) += fotg210.o
COBJS-$(CONFIG_THOR_FUNCTION) += f_thor.o
COBJS-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o
COBJS-$(CONFIG_DFU_FUNCTION) += f_dfu.o
COBJS-$(CONFIG_USB_GADGET_MASS_STORAGE) += f_mass_storage.o

View File

@ -14,6 +14,7 @@
#include <usbdevice.h>
#include "ep0.h"
#include <usb/designware_udc.h>
#include <usb/udc.h>
#include <asm/arch/hardware.h>
#define UDC_INIT_MDELAY 80 /* Device settle delay */

View File

@ -635,6 +635,7 @@ fs_source_desc = {
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = __constant_cpu_to_le16(64),
};
static struct usb_endpoint_descriptor
@ -644,6 +645,7 @@ fs_sink_desc = {
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = __constant_cpu_to_le16(64),
};
static const struct usb_descriptor_header *fs_eth_function[11] = {
@ -1534,6 +1536,8 @@ static int rx_submit(struct eth_dev *dev, struct usb_request *req,
*/
debug("%s\n", __func__);
if (!req)
return -EINVAL;
size = (ETHER_HDR_SIZE + dev->mtu + RX_EXTRA);
size += dev->out_ep->maxpacket - 1;

1003
drivers/usb/gadget/f_thor.c Normal file

File diff suppressed because it is too large Load Diff

124
drivers/usb/gadget/f_thor.h Normal file
View File

@ -0,0 +1,124 @@
/*
* f_thor.h - USB TIZEN THOR - internal gadget definitions
*
* Copyright (C) 2013 Samsung Electronics
* Lukasz Majewski <l.majewski@samsung.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _USB_THOR_H_
#define _USB_THOR_H_
#include <linux/compiler.h>
#include <asm/sizes.h>
/* THOR Composite Gadget */
#define STRING_MANUFACTURER_IDX 0
#define STRING_PRODUCT_IDX 1
#define STRING_SERIAL_IDX 2
/* ********************************************************** */
/* THOR protocol definitions */
/* ********************************************************** */
/*
* Attribute Vendor descriptor - necessary to prevent ZLP transmission
* from Windows XP HOST PC
*/
struct usb_cdc_attribute_vendor_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubType;
__u16 DAUType;
__u16 DAULength;
__u8 DAUValue;
} __packed;
#define VER_PROTOCOL_MAJOR 4
#define VER_PROTOCOL_MINOR 0
enum rqt {
RQT_INFO = 200,
RQT_CMD,
RQT_DL,
RQT_UL,
};
enum rqt_data {
/* RQT_INFO */
RQT_INFO_VER_PROTOCOL = 1,
RQT_INIT_VER_HW,
RQT_INIT_VER_BOOT,
RQT_INIT_VER_KERNEL,
RQT_INIT_VER_PLATFORM,
RQT_INIT_VER_CSC,
/* RQT_CMD */
RQT_CMD_REBOOT = 1,
RQT_CMD_POWEROFF,
RQT_CMD_EFSCLEAR,
/* RQT_DL */
RQT_DL_INIT = 1,
RQT_DL_FILE_INFO,
RQT_DL_FILE_START,
RQT_DL_FILE_END,
RQT_DL_EXIT,
/* RQT_UL */
RQT_UL_INIT = 1,
RQT_UL_START,
RQT_UL_END,
RQT_UL_EXIT,
};
struct rqt_box { /* total: 256B */
s32 rqt; /* request id */
s32 rqt_data; /* request data id */
s32 int_data[14]; /* int data */
char str_data[5][32]; /* string data */
char md5[32]; /* md5 checksum */
} __packed;
struct rsp_box { /* total: 128B */
s32 rsp; /* response id (= request id) */
s32 rsp_data; /* response data id */
s32 ack; /* ack */
s32 int_data[5]; /* int data */
char str_data[3][32]; /* string data */
} __packed;
struct data_rsp_box { /* total: 8B */
s32 ack; /* response id (= request id) */
s32 count; /* response data id */
} __packed;
enum {
FILE_TYPE_NORMAL,
FILE_TYPE_PIT,
};
struct thor_dev {
struct usb_gadget *gadget;
struct usb_request *req; /* EP0 -> control responses */
/* IN/OUT EP's and correspoinding requests */
struct usb_ep *in_ep, *out_ep, *int_ep;
struct usb_request *in_req, *out_req;
/* Control flow variables */
unsigned char configuration_done;
unsigned char rxdata;
unsigned char txdata;
};
struct f_thor {
struct usb_function usb_function;
struct thor_dev *dev;
};
#define F_NAME_BUF_SIZE 32
#define THOR_PACKET_SIZE SZ_1M /* 1 MiB */
#define THOR_STORE_UNIT_SIZE SZ_32M /* 32 MiB */
#endif /* _USB_THOR_H_ */

View File

@ -16,6 +16,7 @@
#include <g_dnl.h>
#include <usb_mass_storage.h>
#include <dfu.h>
#include <thor.h>
#include "gadget_chips.h"
#include "composite.c"
@ -79,6 +80,8 @@ static int g_dnl_unbind(struct usb_composite_dev *cdev)
{
struct usb_gadget *gadget = cdev->gadget;
free(cdev->config);
cdev->config = NULL;
debug("%s: calling usb_gadget_disconnect for "
"controller '%s'\n", shortname, gadget->name);
usb_gadget_disconnect(gadget);
@ -99,26 +102,34 @@ static int g_dnl_do_config(struct usb_configuration *c)
ret = dfu_add(c);
else if (!strcmp(s, "usb_dnl_ums"))
ret = fsg_add(c);
else if (!strcmp(s, "usb_dnl_thor"))
ret = thor_add(c);
return ret;
}
static int g_dnl_config_register(struct usb_composite_dev *cdev)
{
static struct usb_configuration config = {
.label = "usb_dnload",
.bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
.bConfigurationValue = CONFIGURATION_NUMBER,
.iConfiguration = STRING_USBDOWN,
struct usb_configuration *config;
const char *name = "usb_dnload";
.bind = g_dnl_do_config,
};
config = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*config));
if (!config)
return -ENOMEM;
return usb_add_config(cdev, &config);
memset(config, 0, sizeof(*config));
config->label = name;
config->bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER;
config->bConfigurationValue = CONFIGURATION_NUMBER;
config->iConfiguration = STRING_USBDOWN;
config->bind = g_dnl_do_config;
return usb_add_config(cdev, config);
}
__weak
int g_dnl_bind_fixup(struct usb_device_descriptor *dev)
int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
{
return 0;
}
@ -145,7 +156,7 @@ static int g_dnl_bind(struct usb_composite_dev *cdev)
g_dnl_string_defs[1].id = id;
device_desc.iProduct = id;
g_dnl_bind_fixup(&device_desc);
g_dnl_bind_fixup(&device_desc, cdev->driver->name);
ret = g_dnl_config_register(cdev);
if (ret)
goto error;
@ -183,8 +194,8 @@ static struct usb_composite_driver g_dnl_driver = {
int g_dnl_register(const char *type)
{
/* We only allow "dfu" atm, so 3 should be enough */
static char name[sizeof(shortname) + 3];
/* The largest function name is 4 */
static char name[sizeof(shortname) + 4];
int ret;
if (!strcmp(type, "dfu")) {
@ -193,6 +204,9 @@ int g_dnl_register(const char *type)
} else if (!strcmp(type, "ums")) {
strcpy(name, shortname);
strcat(name, type);
} else if (!strcmp(type, "thor")) {
strcpy(name, shortname);
strcat(name, type);
} else {
printf("%s: unknown command: %s\n", __func__, type);
return -EINVAL;

View File

@ -47,6 +47,7 @@
#include <commproc.h>
#include <usbdevice.h>
#include <usb/mpc8xx_udc.h>
#include <usb/udc.h>
#include "ep0.h"

View File

@ -13,13 +13,16 @@
#include <config.h>
#include <net.h>
#include <malloc.h>
#include <asm/byteorder.h>
#include <asm/errno.h>
#include <asm/io.h>
#include <asm/unaligned.h>
#include <linux/types.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <usb/mv_udc.h>
#if CONFIG_USB_MAX_CONTROLLER_COUNT > 1
#error This driver only supports one single controller.
#endif
#include "../host/ehci.h"
#include "mv_udc.h"
/*
* Check if the system has too long cachelines. If the cachelines are
@ -107,6 +110,7 @@ static struct mv_drv controller = {
.gadget = {
.name = "mv_udc",
.ops = &mv_udc_ops,
.is_dualspeed = 1,
},
};
@ -210,12 +214,10 @@ static void mv_ep_free_request(struct usb_ep *ep, struct usb_request *_req)
return;
}
static void ep_enable(int num, int in)
static void ep_enable(int num, int in, int maxpacket)
{
struct ept_queue_head *head;
struct mv_udc *udc = (struct mv_udc *)controller.ctrl->hcor;
unsigned n;
head = mv_get_qh(num, in);
n = readl(&udc->epctrl[num]);
if (in)
@ -224,7 +226,9 @@ static void ep_enable(int num, int in)
n |= (CTRL_RXE | CTRL_RXR | CTRL_RXT_BULK);
if (num != 0) {
head->config = CONFIG_MAX_PKT(EP_MAX_PACKET_SIZE) | CONFIG_ZLT;
struct ept_queue_head *head = mv_get_qh(num, in);
head->config = CONFIG_MAX_PKT(maxpacket) | CONFIG_ZLT;
mv_flush_qh(num);
}
writel(n, &udc->epctrl[num]);
@ -237,17 +241,33 @@ static int mv_ep_enable(struct usb_ep *ep,
int num, in;
num = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
in = (desc->bEndpointAddress & USB_DIR_IN) != 0;
ep_enable(num, in);
mv_ep->desc = desc;
if (num) {
int max = get_unaligned_le16(&desc->wMaxPacketSize);
if ((max > 64) && (controller.gadget.speed == USB_SPEED_FULL))
max = 64;
if (ep->maxpacket != max) {
DBG("%s: from %d to %d\n", __func__,
ep->maxpacket, max);
ep->maxpacket = max;
}
}
ep_enable(num, in, ep->maxpacket);
DBG("%s: num=%d maxpacket=%d\n", __func__, num, ep->maxpacket);
return 0;
}
static int mv_ep_disable(struct usb_ep *ep)
{
struct mv_ep *mv_ep = container_of(ep, struct mv_ep, ep);
mv_ep->desc = NULL;
return 0;
}
static int mv_bounce(struct mv_ep *ep)
static int mv_bounce(struct mv_ep *ep, int in)
{
uint32_t addr = (uint32_t)ep->req.buf;
uint32_t ba;
@ -276,8 +296,8 @@ align:
if (!ep->b_buf)
return -ENOMEM;
}
memcpy(ep->b_buf, ep->req.buf, ep->req.length);
if (in)
memcpy(ep->b_buf, ep->req.buf, ep->req.length);
flush:
ba = (uint32_t)ep->b_buf;
@ -286,29 +306,25 @@ flush:
return 0;
}
static void mv_debounce(struct mv_ep *ep)
static void mv_debounce(struct mv_ep *ep, int in)
{
uint32_t addr = (uint32_t)ep->req.buf;
uint32_t ba = (uint32_t)ep->b_buf;
if (in) {
if (addr == ba)
return; /* not a bounce */
goto free;
}
invalidate_dcache_range(ba, ba + ep->b_len);
/* Input buffer address is not aligned. */
if (addr & (ARCH_DMA_MINALIGN - 1))
goto copy;
if (addr == ba)
return; /* not a bounce */
/* Input buffer length is not aligned. */
if (ep->req.length & (ARCH_DMA_MINALIGN - 1))
goto copy;
/* The buffer is well aligned, only invalidate cache. */
return;
copy:
memcpy(ep->req.buf, ep->b_buf, ep->req.length);
free:
/* Large payloads use allocated buffer, free it. */
if (ep->req.length > 64)
if (ep->b_buf != ep->b_fast)
free(ep->b_buf);
}
@ -326,7 +342,7 @@ static int mv_ep_queue(struct usb_ep *ep,
head = mv_get_qh(num, in);
len = req->length;
ret = mv_bounce(mv_ep);
ret = mv_bounce(mv_ep, in);
if (ret)
return ret;
@ -334,21 +350,20 @@ static int mv_ep_queue(struct usb_ep *ep,
item->info = INFO_BYTES(len) | INFO_IOC | INFO_ACTIVE;
item->page0 = (uint32_t)mv_ep->b_buf;
item->page1 = ((uint32_t)mv_ep->b_buf & 0xfffff000) + 0x1000;
mv_flush_qtd(num);
head->next = (unsigned) item;
head->info = 0;
DBG("ept%d %s queue len %x, buffer %p\n",
num, in ? "in" : "out", len, mv_ep->b_buf);
mv_flush_qh(num);
if (in)
bit = EPT_TX(num);
else
bit = EPT_RX(num);
mv_flush_qh(num);
mv_flush_qtd(num);
writel(bit, &udc->epprime);
return 0;
@ -366,14 +381,13 @@ static void handle_ep_complete(struct mv_ep *ep)
mv_invalidate_qtd(num);
if (item->info & 0xff)
printf("EP%d/%s FAIL nfo=%x pg0=%x\n",
num, in ? "in" : "out", item->info, item->page0);
printf("EP%d/%s FAIL info=%x pg0=%x\n",
num, in ? "in" : "out", item->info, item->page0);
len = (item->info >> 16) & 0x7fff;
mv_debounce(ep);
ep->req.length -= len;
mv_debounce(ep, in);
DBG("ept%d %s complete %x\n",
num, in ? "in" : "out", len);
ep->req.complete(&ep->ep, &ep->req);
@ -411,14 +425,16 @@ static void handle_setup(void)
if ((r.wValue == 0) && (r.wLength == 0)) {
req->length = 0;
for (i = 0; i < NUM_ENDPOINTS; i++) {
if (!controller.ep[i].desc)
struct mv_ep *ep = &controller.ep[i];
if (!ep->desc)
continue;
num = controller.ep[i].desc->bEndpointAddress
num = ep->desc->bEndpointAddress
& USB_ENDPOINT_NUMBER_MASK;
in = (controller.ep[i].desc->bEndpointAddress
in = (ep->desc->bEndpointAddress
& USB_DIR_IN) != 0;
if ((num == _num) && (in == _in)) {
ep_enable(num, in);
ep_enable(num, in, ep->ep.maxpacket);
usb_ep_queue(controller.gadget.ep0,
req, 0);
break;
@ -502,15 +518,19 @@ void udc_irq(void)
DBG("-- suspend --\n");
if (n & STS_PCI) {
DBG("-- portchange --\n");
int max = 64;
int speed = USB_SPEED_FULL;
bit = (readl(&udc->portsc) >> 26) & 3;
DBG("-- portchange %x %s\n", bit, (bit == 2) ? "High" : "Full");
if (bit == 2) {
controller.gadget.speed = USB_SPEED_HIGH;
for (i = 1; i < NUM_ENDPOINTS && n; i++)
if (controller.ep[i].desc)
controller.ep[i].ep.maxpacket = 512;
} else {
controller.gadget.speed = USB_SPEED_FULL;
speed = USB_SPEED_HIGH;
max = 512;
}
controller.gadget.speed = speed;
for (i = 1; i < NUM_ENDPOINTS; i++) {
if (controller.ep[i].ep.maxpacket > max)
controller.ep[i].ep.maxpacket = max;
}
}
@ -626,6 +646,7 @@ static int mvudc_probe(void)
free(controller.epts);
return -ENOMEM;
}
memset(controller.items_mem, 0, ilist_sz);
for (i = 0; i < 2 * NUM_ENDPOINTS; i++) {
/*
@ -688,7 +709,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
if (driver->speed != USB_SPEED_FULL && driver->speed != USB_SPEED_HIGH)
return -EINVAL;
ret = usb_lowlevel_init(0, (void **)&controller.ctrl);
ret = usb_lowlevel_init(0, USB_INIT_DEVICE, (void **)&controller.ctrl);
if (ret)
return ret;

115
drivers/usb/gadget/mv_udc.h Normal file
View File

@ -0,0 +1,115 @@
/*
* Copyright 2011, Marvell Semiconductor Inc.
*
* Licensed under the GPL-2 or later.
*/
#ifndef __GADGET__MV_UDC_H__
#define __GADGET__MV_UDC_H__
#define NUM_ENDPOINTS 6
struct mv_udc {
#define MICRO_8FRAME 0x8
#define USBCMD_ITC(x) ((((x) > 0xff) ? 0xff : x) << 16)
#define USBCMD_FS2 (1 << 15)
#define USBCMD_RST (1 << 1)
#define USBCMD_RUN (1)
u32 usbcmd; /* 0x140 */
#define STS_SLI (1 << 8)
#define STS_URI (1 << 6)
#define STS_PCI (1 << 2)
#define STS_UEI (1 << 1)
#define STS_UI (1 << 0)
u32 usbsts; /* 0x144 */
u32 pad1[3];
u32 devaddr; /* 0x154 */
u32 epinitaddr; /* 0x158 */
u32 pad2[10];
#define PTS_ENABLE 2
#define PTS(x) (((x) & 0x3) << 30)
#define PFSC (1 << 24)
u32 portsc; /* 0x184 */
u32 pad3[8];
#define USBMODE_DEVICE 2
u32 usbmode; /* 0x1a8 */
u32 epstat; /* 0x1ac */
#define EPT_TX(x) (1 << (((x) & 0xffff) + 16))
#define EPT_RX(x) (1 << ((x) & 0xffff))
u32 epprime; /* 0x1b0 */
u32 epflush; /* 0x1b4 */
u32 pad4;
u32 epcomp; /* 0x1bc */
#define CTRL_TXE (1 << 23)
#define CTRL_TXR (1 << 22)
#define CTRL_RXE (1 << 7)
#define CTRL_RXR (1 << 6)
#define CTRL_TXT_BULK (2 << 18)
#define CTRL_RXT_BULK (2 << 2)
u32 epctrl[16]; /* 0x1c0 */
};
struct mv_ep {
struct usb_ep ep;
struct list_head queue;
const struct usb_endpoint_descriptor *desc;
struct usb_request req;
uint8_t *b_buf;
uint32_t b_len;
uint8_t b_fast[64] __aligned(ARCH_DMA_MINALIGN);
};
struct mv_drv {
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
struct ehci_ctrl *ctrl;
struct ept_queue_head *epts;
struct ept_queue_item *items[2 * NUM_ENDPOINTS];
uint8_t *items_mem;
struct mv_ep ep[NUM_ENDPOINTS];
};
struct ept_queue_head {
unsigned config;
unsigned current; /* read-only */
unsigned next;
unsigned info;
unsigned page0;
unsigned page1;
unsigned page2;
unsigned page3;
unsigned page4;
unsigned reserved_0;
unsigned char setup_data[8];
unsigned reserved_1;
unsigned reserved_2;
unsigned reserved_3;
unsigned reserved_4;
};
#define CONFIG_MAX_PKT(n) ((n) << 16)
#define CONFIG_ZLT (1 << 29) /* stop on zero-len xfer */
#define CONFIG_IOS (1 << 15) /* IRQ on setup */
struct ept_queue_item {
unsigned next;
unsigned info;
unsigned page0;
unsigned page1;
unsigned page2;
unsigned page3;
unsigned page4;
unsigned reserved;
};
#define TERMINATE 1
#define INFO_BYTES(n) ((n) << 16)
#define INFO_IOC (1 << 15)
#define INFO_ACTIVE (1 << 7)
#define INFO_HALTED (1 << 6)
#define INFO_BUFFER_ERROR (1 << 5)
#define INFO_TX_ERROR (1 << 3)
#endif

View File

@ -20,6 +20,7 @@
#endif
#include <usbdevice.h>
#include <usb/omap1510_udc.h>
#include <usb/udc.h>
#include "ep0.h"

View File

@ -16,6 +16,7 @@
#include <asm/arch/hardware.h>
#include <asm/io.h>
#include <usb/pxa27x_udc.h>
#include <usb/udc.h>
#include "ep0.h"

View File

@ -117,7 +117,8 @@ static int setdma_rx(struct s3c_ep *ep, struct s3c_request *req)
invalidate_dcache_range((unsigned long) ep->dev->dma_buf[ep_num],
(unsigned long) ep->dev->dma_buf[ep_num]
+ DMA_BUFFER_SIZE);
+ ROUND(ep->ep.maxpacket,
CONFIG_SYS_CACHELINE_SIZE));
if (length == 0)
pktcnt = 1;

View File

@ -42,6 +42,11 @@ COBJS-$(CONFIG_USB_EHCI_SPEAR) += ehci-spear.o
COBJS-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o
COBJS-$(CONFIG_USB_EHCI_VCT) += ehci-vct.o
# xhci
COBJS-$(CONFIG_USB_XHCI) += xhci.o xhci-mem.o xhci-ring.o
COBJS-$(CONFIG_USB_XHCI_EXYNOS) += xhci-exynos5.o
COBJS-$(CONFIG_USB_XHCI_OMAP) += xhci-omap.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(COBJS))

View File

@ -22,7 +22,8 @@
/*
* EHCI host controller init
*/
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
if (utmi_init() < 0)
return -1;

View File

@ -21,7 +21,8 @@
*/
#define EN_UPLL_TIMEOUT 500UL
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
at91_pmc_t *pmc = (at91_pmc_t *)ATMEL_BASE_PMC;
ulong start_time, tmp_time;

View File

@ -16,6 +16,7 @@
#include <asm/arch/ehci.h>
#include <asm/arch/system.h>
#include <asm/arch/power.h>
#include <asm/gpio.h>
#include <asm-generic/errno.h>
#include <linux/compat.h>
#include "ehci.h"
@ -30,6 +31,7 @@ DECLARE_GLOBAL_DATA_PTR;
struct exynos_ehci {
struct exynos_usb_phy *usb;
struct ehci_hccr *hcd;
struct fdt_gpio_state vbus_gpio;
};
static struct exynos_ehci exynos;
@ -58,6 +60,9 @@ static int exynos_usb_parse_dt(const void *blob, struct exynos_ehci *exynos)
exynos->hcd = (struct ehci_hccr *)addr;
/* Vbus gpio */
fdtdec_decode_gpio(blob, node, "samsung,vbus-gpio", &exynos->vbus_gpio);
depth = 0;
node = fdtdec_next_compatible_subnode(blob, node,
COMPAT_SAMSUNG_EXYNOS_USB_PHY, &depth);
@ -136,7 +141,8 @@ static void reset_usb_phy(struct exynos_usb_phy *usb)
* Create the appropriate control structures to manage
* a new EHCI host controller.
*/
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
struct exynos_ehci *ctx = &exynos;
@ -150,6 +156,12 @@ int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
ctx->hcd = (struct ehci_hccr *)samsung_get_base_usb_ehci();
#endif
#ifdef CONFIG_OF_CONTROL
/* setup the Vbus gpio here */
if (!fdtdec_setup_gpio(&ctx->vbus_gpio))
gpio_direction_output(ctx->vbus_gpio.gpio, 1);
#endif
setup_usb_phy(ctx->usb);
*hccr = ctx->hcd;

View File

@ -33,8 +33,8 @@ static inline int ehci_is_fotg2xx(union ehci_faraday_regs *regs)
* Create the appropriate control structures to manage
* a new EHCI host controller.
*/
int ehci_hcd_init(int index, struct ehci_hccr **ret_hccr,
struct ehci_hcor **ret_hcor)
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **ret_hccr, struct ehci_hcor **ret_hcor)
{
struct ehci_hccr *hccr;
struct ehci_hcor *hcor;

View File

@ -35,7 +35,8 @@ static int usb_phy_clk_valid(struct usb_ehci *ehci)
*
* Excerpts from linux ehci fsl driver.
*/
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
struct usb_ehci *ehci;
const char *phy_type = NULL;

View File

@ -919,24 +919,29 @@ int usb_lowlevel_stop(int index)
return ehci_hcd_stop(index);
}
int usb_lowlevel_init(int index, void **controller)
int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
{
uint32_t reg;
uint32_t cmd;
struct QH *qh_list;
struct QH *periodic;
int i;
int rc;
if (ehci_hcd_init(index, &ehcic[index].hccr, &ehcic[index].hcor))
return -1;
rc = ehci_hcd_init(index, init, &ehcic[index].hccr, &ehcic[index].hcor);
if (rc)
return rc;
if (init == USB_INIT_DEVICE)
goto done;
/* EHCI spec section 4.1 */
if (ehci_reset(index))
return -1;
#if defined(CONFIG_EHCI_HCD_INIT_AFTER_RESET)
if (ehci_hcd_init(index, &ehcic[index].hccr, &ehcic[index].hcor))
return -1;
rc = ehci_hcd_init(index, init, &ehcic[index].hccr, &ehcic[index].hcor);
if (rc)
return rc;
#endif
/* Set the high address word (aka segment) for 64-bit controller */
if (ehci_readl(&ehcic[index].hccr->cr_hccparams) & 1)
@ -1037,7 +1042,7 @@ int usb_lowlevel_init(int index, void **controller)
printf("USB EHCI %x.%02x\n", reg >> 8, reg & 0xff);
ehcic[index].rootdev = 0;
done:
*controller = &ehcic[index];
return 0;
}

View File

@ -14,7 +14,8 @@
* Create the appropriate control structures to manage
* a new EHCI host controller.
*/
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
*hccr = (struct ehci_hccr *)(0xcd000100);
*hcor = (struct ehci_hcor *)((uint32_t) *hccr

View File

@ -74,7 +74,8 @@ static void usb_brg_adrdec_setup(void)
* Create the appropriate control structures to manage
* a new EHCI host controller.
*/
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
usb_brg_adrdec_setup();

View File

@ -32,7 +32,8 @@ static void usb_platform_dr_init(volatile struct usb_ehci *ehci);
* This code is derived from EHCI FSL USB Linux driver for MPC5121
*
*/
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
volatile struct usb_ehci *ehci;

View File

@ -218,7 +218,8 @@ void __weak board_ehci_hcd_postinit(struct usb_ehci *ehci, int port)
{
}
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
struct usb_ehci *ehci;

View File

@ -35,6 +35,7 @@
#define USBPHY_CTRL_CLKGATE 0x40000000
#define USBPHY_CTRL_ENUTMILEVEL3 0x00008000
#define USBPHY_CTRL_ENUTMILEVEL2 0x00004000
#define USBPHY_CTRL_OTG_ID 0x08000000
#define ANADIG_USB2_CHRG_DETECT_EN_B 0x00100000
#define ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B 0x00080000
@ -49,52 +50,84 @@
#define UCTRL_OVER_CUR_DIS (1 << 7) /* Disable OTG Overcurrent Detection */
/* USBCMD */
#define UH1_USBCMD_OFFSET 0x140
#define UCMD_RUN_STOP (1 << 0) /* controller run/stop */
#define UCMD_RESET (1 << 1) /* controller reset */
static void usbh1_internal_phy_clock_gate(int on)
{
void __iomem *phy_reg = (void __iomem *)USB_PHY1_BASE_ADDR;
static const unsigned phy_bases[] = {
USB_PHY0_BASE_ADDR,
USB_PHY1_BASE_ADDR,
};
static void usb_internal_phy_clock_gate(int index, int on)
{
void __iomem *phy_reg;
if (index >= ARRAY_SIZE(phy_bases))
return;
phy_reg = (void __iomem *)phy_bases[index];
phy_reg += on ? USBPHY_CTRL_CLR : USBPHY_CTRL_SET;
__raw_writel(USBPHY_CTRL_CLKGATE, phy_reg);
}
static void usbh1_power_config(void)
static void usb_power_config(int index)
{
struct anatop_regs __iomem *anatop =
(struct anatop_regs __iomem *)ANATOP_BASE_ADDR;
void __iomem *chrg_detect;
void __iomem *pll_480_ctrl_clr;
void __iomem *pll_480_ctrl_set;
switch (index) {
case 0:
chrg_detect = &anatop->usb1_chrg_detect;
pll_480_ctrl_clr = &anatop->usb1_pll_480_ctrl_clr;
pll_480_ctrl_set = &anatop->usb1_pll_480_ctrl_set;
break;
case 1:
chrg_detect = &anatop->usb2_chrg_detect;
pll_480_ctrl_clr = &anatop->usb2_pll_480_ctrl_clr;
pll_480_ctrl_set = &anatop->usb2_pll_480_ctrl_set;
break;
default:
return;
}
/*
* Some phy and power's special controls for host1
* Some phy and power's special controls
* 1. The external charger detector needs to be disabled
* or the signal at DP will be poor
* 2. The PLL's power and output to usb for host 1
* 2. The PLL's power and output to usb
* is totally controlled by IC, so the Software only needs
* to enable them at initializtion.
*/
__raw_writel(ANADIG_USB2_CHRG_DETECT_EN_B |
ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B,
&anatop->usb2_chrg_detect);
chrg_detect);
__raw_writel(ANADIG_USB2_PLL_480_CTRL_BYPASS,
&anatop->usb2_pll_480_ctrl_clr);
pll_480_ctrl_clr);
__raw_writel(ANADIG_USB2_PLL_480_CTRL_ENABLE |
ANADIG_USB2_PLL_480_CTRL_POWER |
ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS,
&anatop->usb2_pll_480_ctrl_set);
pll_480_ctrl_set);
}
static int usbh1_phy_enable(void)
/* Return 0 : host node, <>0 : device mode */
static int usb_phy_enable(int index, struct usb_ehci *ehci)
{
void __iomem *phy_reg = (void __iomem *)USB_PHY1_BASE_ADDR;
void __iomem *phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL);
void __iomem *usb_cmd = (void __iomem *)(USBOH3_USB_BASE_ADDR +
USB_H1REGS_OFFSET +
UH1_USBCMD_OFFSET);
void __iomem *phy_reg;
void __iomem *phy_ctrl;
void __iomem *usb_cmd;
u32 val;
if (index >= ARRAY_SIZE(phy_bases))
return 0;
phy_reg = (void __iomem *)phy_bases[index];
phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL);
usb_cmd = (void __iomem *)&ehci->usbcmd;
/* Stop then Reset */
val = __raw_readl(usb_cmd);
val &= ~UCMD_RUN_STOP;
@ -123,31 +156,41 @@ static int usbh1_phy_enable(void)
/* Power up the PHY */
__raw_writel(0, phy_reg + USBPHY_PWD);
/* enable FS/LS device */
val = __raw_readl(phy_reg + USBPHY_CTRL);
val = __raw_readl(phy_ctrl);
val |= (USBPHY_CTRL_ENUTMILEVEL2 | USBPHY_CTRL_ENUTMILEVEL3);
__raw_writel(val, phy_reg + USBPHY_CTRL);
__raw_writel(val, phy_ctrl);
return 0;
return val & USBPHY_CTRL_OTG_ID;
}
static void usbh1_oc_config(void)
/* Base address for this IP block is 0x02184800 */
struct usbnc_regs {
u32 ctrl[4]; /* otg/host1-3 */
u32 uh2_hsic_ctrl;
u32 uh3_hsic_ctrl;
u32 otg_phy_ctrl_0;
u32 uh1_phy_ctrl_0;
};
static void usb_oc_config(int index)
{
void __iomem *usb_base = (void __iomem *)USBOH3_USB_BASE_ADDR;
void __iomem *usbother_base = usb_base + USB_OTHERREGS_OFFSET;
struct usbnc_regs *usbnc = (struct usbnc_regs *)(USBOH3_USB_BASE_ADDR +
USB_OTHERREGS_OFFSET);
void __iomem *ctrl = (void __iomem *)(&usbnc->ctrl[index]);
u32 val;
val = __raw_readl(usbother_base + USB_H1_CTRL_OFFSET);
val = __raw_readl(ctrl);
#if CONFIG_MACH_TYPE == MACH_TYPE_MX6Q_ARM2
/* mx6qarm2 seems to required a different setting*/
val &= ~UCTRL_OVER_CUR_POL;
#else
val |= UCTRL_OVER_CUR_POL;
#endif
__raw_writel(val, usbother_base + USB_H1_CTRL_OFFSET);
__raw_writel(val, ctrl);
val = __raw_readl(usbother_base + USB_H1_CTRL_OFFSET);
val = __raw_readl(ctrl);
val |= UCTRL_OVER_CUR_DIS;
__raw_writel(val, usbother_base + USB_H1_CTRL_OFFSET);
__raw_writel(val, ctrl);
}
int __weak board_ehci_hcd_init(int port)
@ -155,33 +198,42 @@ int __weak board_ehci_hcd_init(int port)
return 0;
}
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
int __weak board_ehci_power(int port, int on)
{
struct usb_ehci *ehci;
return 0;
}
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
enum usb_init_type type;
struct usb_ehci *ehci = (struct usb_ehci *)(USBOH3_USB_BASE_ADDR +
(0x200 * index));
if (index > 3)
return -EINVAL;
enable_usboh3_clk(1);
mdelay(1);
/* Do board specific initialization */
board_ehci_hcd_init(CONFIG_MXC_USB_PORT);
board_ehci_hcd_init(index);
#if CONFIG_MXC_USB_PORT == 1
/* USB Host 1 */
usbh1_power_config();
usbh1_oc_config();
usbh1_internal_phy_clock_gate(1);
usbh1_phy_enable();
#else
#error "MXC USB port not yet supported"
#endif
usb_power_config(index);
usb_oc_config(index);
usb_internal_phy_clock_gate(index, 1);
type = usb_phy_enable(index, ehci) ? USB_INIT_DEVICE : USB_INIT_HOST;
ehci = (struct usb_ehci *)(USBOH3_USB_BASE_ADDR +
(0x200 * CONFIG_MXC_USB_PORT));
*hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
*hcor = (struct ehci_hcor *)((uint32_t)*hccr +
HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
setbits_le32(&ehci->usbmode, CM_HOST);
if ((type == init) || (type == USB_INIT_DEVICE))
board_ehci_power(index, (type == USB_INIT_DEVICE) ? 0 : 1);
if (type != init)
return -ENODEV;
if (type == USB_INIT_DEVICE)
return 0;
setbits_le32(&ehci->usbmode, CM_HOST);
__raw_writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc);
setbits_le32(&ehci->portsc, USB_EN);

View File

@ -208,7 +208,8 @@ static int mxc_set_usbcontrol(int port, unsigned int flags)
return 0;
}
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
struct usb_ehci *ehci;
#ifdef CONFIG_MX31

View File

@ -77,7 +77,8 @@ static int ehci_mxs_toggle_clock(const struct ehci_mxs_port *port, int enable)
return 0;
}
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
int ret;

View File

@ -96,12 +96,6 @@ static void omap_ehci_soft_phy_reset(int port)
}
#endif
inline int __board_usb_init(void)
{
return 0;
}
int board_usb_init(void) __attribute__((weak, alias("__board_usb_init")));
#if defined(CONFIG_OMAP_EHCI_PHY1_RESET_GPIO) || \
defined(CONFIG_OMAP_EHCI_PHY2_RESET_GPIO) || \
defined(CONFIG_OMAP_EHCI_PHY3_RESET_GPIO)
@ -157,15 +151,15 @@ int omap_ehci_hcd_stop(void)
* Based on "drivers/usb/host/ehci-omap.c" from Linux 3.1
* See there for additional Copyrights.
*/
int omap_ehci_hcd_init(struct omap_usbhs_board_data *usbhs_pdata,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
int omap_ehci_hcd_init(int index, struct omap_usbhs_board_data *usbhs_pdata,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
int ret;
unsigned int i, reg = 0, rev = 0;
debug("Initializing OMAP EHCI\n");
ret = board_usb_init();
ret = board_usb_init(index, USB_INIT_HOST);
if (ret < 0)
return ret;

View File

@ -69,8 +69,8 @@ static pci_dev_t ehci_find_class(int index)
* Create the appropriate control structures to manage
* a new EHCI host controller.
*/
int ehci_hcd_init(int index, struct ehci_hccr **ret_hccr,
struct ehci_hcor **ret_hcor)
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **ret_hccr, struct ehci_hcor **ret_hcor)
{
pci_dev_t pdev;
uint32_t cmd;

View File

@ -15,7 +15,8 @@
* Create the appropriate control structures to manage
* a new EHCI host controller.
*/
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
*hccr = (struct ehci_hccr *)(CONFIG_SYS_PPC4XX_USB_ADDR);
*hcor = (struct ehci_hcor *)((uint32_t) *hccr +

View File

@ -20,7 +20,8 @@
* Create the appropriate control structures to manage
* a new EHCI host controller.
*/
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
*hccr = (struct ehci_hccr *)(CONFIG_SYS_UHC0_EHCI_BASE + 0x100);
*hcor = (struct ehci_hcor *)((uint32_t)*hccr

View File

@ -699,7 +699,7 @@ static int process_usb_nodes(const void *blob, int node_list[], int count)
return 0;
}
int board_usb_init(const void *blob)
int usb_process_devicetree(const void *blob)
{
int node_list[USB_PORTS_MAX];
int count, err = 0;
@ -734,7 +734,8 @@ int board_usb_init(const void *blob)
* @param hcor returns start address of EHCI HCOR registers
* @return 0 if ok, -1 on error (generally invalid port number)
*/
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
struct fdt_usb *config;
struct usb_ctlr *usbctlr;

View File

@ -15,7 +15,8 @@ int vct_ehci_hcd_init(u32 *hccr, u32 *hcor);
* Create the appropriate control structures to manage
* a new EHCI host controller.
*/
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
int ret;
u32 vct_hccr;

View File

@ -28,22 +28,6 @@
#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 2
#endif
/* (shifted) direction/type/recipient from the USB 2.0 spec, table 9.2 */
#define DeviceRequest \
((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE) << 8)
#define DeviceOutRequest \
((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE) << 8)
#define InterfaceRequest \
((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8)
#define EndpointRequest \
((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8)
#define EndpointOutRequest \
((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8)
/*
* Register Space.
*/
@ -266,7 +250,8 @@ struct ehci_ctrl {
};
/* Low level init functions */
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor);
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor);
int ehci_hcd_stop(int index);
#endif /* USB_EHCI_H */

View File

@ -1377,7 +1377,7 @@ int isp116x_check_id(struct isp116x *isp116x)
return 0;
}
int usb_lowlevel_init(int index, void **controller))
int usb_lowlevel_init(int index, enum usb_init_type init, void **controller))
{
struct isp116x *isp116x = &isp116x_dev;

View File

@ -1847,7 +1847,7 @@ static void hc_release_ohci(ohci_t *ohci)
*/
static char ohci_inited = 0;
int usb_lowlevel_init(int index, void **controller)
int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
{
#ifdef CONFIG_PCI_OHCI
pci_dev_t pdev;
@ -1861,7 +1861,7 @@ int usb_lowlevel_init(int index, void **controller)
#ifdef CONFIG_SYS_USB_OHCI_BOARD_INIT
/* board dependant init */
if (usb_board_init())
if (board_usb_init(index, USB_INIT_HOST))
return -1;
#endif
memset(&gohci, 0, sizeof(ohci_t));
@ -1918,7 +1918,7 @@ int usb_lowlevel_init(int index, void **controller)
err ("can't reset usb-%s", gohci.slot_name);
#ifdef CONFIG_SYS_USB_OHCI_BOARD_INIT
/* board dependant cleanup */
usb_board_init_fail();
board_usb_cleanup(index, USB_INIT_HOST);
#endif
#ifdef CONFIG_SYS_USB_OHCI_CPU_INIT

View File

@ -1642,7 +1642,7 @@ static void hc_release_ohci(struct ohci *ohci)
*/
static char ohci_inited = 0;
int usb_lowlevel_init(int index, void **controller)
int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
{
struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();

View File

@ -19,14 +19,11 @@
#endif /* CONFIG_SYS_OHCI_SWAP_REG_ACCESS */
/* functions for doing board or CPU specific setup/cleanup */
extern int usb_board_init(void);
extern int usb_board_stop(void);
extern int usb_board_init_fail(void);
extern int usb_cpu_init(void);
extern int usb_cpu_stop(void);
extern int usb_cpu_init_fail(void);
int usb_board_stop(void);
int usb_cpu_init(void);
int usb_cpu_stop(void);
int usb_cpu_init_fail(void);
static int cc_to_error[16] = {

View File

@ -903,7 +903,7 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
return 0;
}
int usb_lowlevel_init(int index, void **controller)
int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
{
struct r8a66597 *r8a66597 = &gr8a66597;

View File

@ -194,7 +194,7 @@ static int sl811_hc_reset(void)
return 1;
}
int usb_lowlevel_init(int index, void **controller)
int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
{
root_hub_devnum = 0;
sl811_hc_reset();

View File

@ -0,0 +1,327 @@
/*
* SAMSUNG EXYNOS5 USB HOST XHCI Controller
*
* Copyright (C) 2012 Samsung Electronics Co.Ltd
* Vivek Gautam <gautam.vivek@samsung.com>
* Vikas Sajjan <vikas.sajjan@samsung.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
/*
* This file is a conglomeration for DWC3-init sequence and further
* exynos5 specific PHY-init sequence.
*/
#include <common.h>
#include <fdtdec.h>
#include <libfdt.h>
#include <malloc.h>
#include <usb.h>
#include <watchdog.h>
#include <asm/arch/cpu.h>
#include <asm/arch/power.h>
#include <asm/arch/xhci-exynos.h>
#include <asm/gpio.h>
#include <asm-generic/errno.h>
#include <linux/compat.h>
#include <linux/usb/dwc3.h>
#include "xhci.h"
/* Declare global data pointer */
DECLARE_GLOBAL_DATA_PTR;
/**
* Contains pointers to register base addresses
* for the usb controller.
*/
struct exynos_xhci {
struct exynos_usb3_phy *usb3_phy;
struct xhci_hccr *hcd;
struct dwc3 *dwc3_reg;
struct fdt_gpio_state vbus_gpio;
};
static struct exynos_xhci exynos;
#ifdef CONFIG_OF_CONTROL
static int exynos_usb3_parse_dt(const void *blob, struct exynos_xhci *exynos)
{
fdt_addr_t addr;
unsigned int node;
int depth;
node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS5_XHCI);
if (node <= 0) {
debug("XHCI: Can't get device node for xhci\n");
return -ENODEV;
}
/*
* Get the base address for XHCI controller from the device node
*/
addr = fdtdec_get_addr(blob, node, "reg");
if (addr == FDT_ADDR_T_NONE) {
debug("Can't get the XHCI register base address\n");
return -ENXIO;
}
exynos->hcd = (struct xhci_hccr *)addr;
/* Vbus gpio */
fdtdec_decode_gpio(blob, node, "samsung,vbus-gpio", &exynos->vbus_gpio);
depth = 0;
node = fdtdec_next_compatible_subnode(blob, node,
COMPAT_SAMSUNG_EXYNOS5_USB3_PHY, &depth);
if (node <= 0) {
debug("XHCI: Can't get device node for usb3-phy controller\n");
return -ENODEV;
}
/*
* Get the base address for usbphy from the device node
*/
exynos->usb3_phy = (struct exynos_usb3_phy *)fdtdec_get_addr(blob, node,
"reg");
if (exynos->usb3_phy == NULL) {
debug("Can't get the usbphy register address\n");
return -ENXIO;
}
return 0;
}
#endif
static void exynos5_usb3_phy_init(struct exynos_usb3_phy *phy)
{
u32 reg;
/* enabling usb_drd phy */
set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_EN);
/* Reset USB 3.0 PHY */
writel(0x0, &phy->phy_reg0);
clrbits_le32(&phy->phy_param0,
/* Select PHY CLK source */
PHYPARAM0_REF_USE_PAD |
/* Set Loss-of-Signal Detector sensitivity */
PHYPARAM0_REF_LOSLEVEL_MASK);
setbits_le32(&phy->phy_param0, PHYPARAM0_REF_LOSLEVEL);
writel(0x0, &phy->phy_resume);
/*
* Setting the Frame length Adj value[6:1] to default 0x20
* See xHCI 1.0 spec, 5.2.4
*/
setbits_le32(&phy->link_system,
LINKSYSTEM_XHCI_VERSION_CONTROL |
LINKSYSTEM_FLADJ(0x20));
/* Set Tx De-Emphasis level */
clrbits_le32(&phy->phy_param1, PHYPARAM1_PCS_TXDEEMPH_MASK);
setbits_le32(&phy->phy_param1, PHYPARAM1_PCS_TXDEEMPH);
setbits_le32(&phy->phy_batchg, PHYBATCHG_UTMI_CLKSEL);
/* PHYTEST POWERDOWN Control */
clrbits_le32(&phy->phy_test,
PHYTEST_POWERDOWN_SSP |
PHYTEST_POWERDOWN_HSP);
/* UTMI Power Control */
writel(PHYUTMI_OTGDISABLE, &phy->phy_utmi);
/* Use core clock from main PLL */
reg = PHYCLKRST_REFCLKSEL_EXT_REFCLK |
/* Default 24Mhz crystal clock */
PHYCLKRST_FSEL(FSEL_CLKSEL_24M) |
PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF |
PHYCLKRST_SSC_REFCLKSEL(0x88) |
/* Force PortReset of PHY */
PHYCLKRST_PORTRESET |
/* Digital power supply in normal operating mode */
PHYCLKRST_RETENABLEN |
/* Enable ref clock for SS function */
PHYCLKRST_REF_SSP_EN |
/* Enable spread spectrum */
PHYCLKRST_SSC_EN |
/* Power down HS Bias and PLL blocks in suspend mode */
PHYCLKRST_COMMONONN;
writel(reg, &phy->phy_clk_rst);
/* giving time to Phy clock to settle before resetting */
udelay(10);
reg &= ~PHYCLKRST_PORTRESET;
writel(reg, &phy->phy_clk_rst);
}
static void exynos5_usb3_phy_exit(struct exynos_usb3_phy *phy)
{
setbits_le32(&phy->phy_utmi,
PHYUTMI_OTGDISABLE |
PHYUTMI_FORCESUSPEND |
PHYUTMI_FORCESLEEP);
clrbits_le32(&phy->phy_clk_rst,
PHYCLKRST_REF_SSP_EN |
PHYCLKRST_SSC_EN |
PHYCLKRST_COMMONONN);
/* PHYTEST POWERDOWN Control to remove leakage current */
setbits_le32(&phy->phy_test,
PHYTEST_POWERDOWN_SSP |
PHYTEST_POWERDOWN_HSP);
/* disabling usb_drd phy */
set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_DISABLE);
}
void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode)
{
clrsetbits_le32(&dwc3_reg->g_ctl,
DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG),
DWC3_GCTL_PRTCAPDIR(mode));
}
static void dwc3_core_soft_reset(struct dwc3 *dwc3_reg)
{
/* Before Resetting PHY, put Core in Reset */
setbits_le32(&dwc3_reg->g_ctl,
DWC3_GCTL_CORESOFTRESET);
/* Assert USB3 PHY reset */
setbits_le32(&dwc3_reg->g_usb3pipectl[0],
DWC3_GUSB3PIPECTL_PHYSOFTRST);
/* Assert USB2 PHY reset */
setbits_le32(&dwc3_reg->g_usb2phycfg,
DWC3_GUSB2PHYCFG_PHYSOFTRST);
mdelay(100);
/* Clear USB3 PHY reset */
clrbits_le32(&dwc3_reg->g_usb3pipectl[0],
DWC3_GUSB3PIPECTL_PHYSOFTRST);
/* Clear USB2 PHY reset */
clrbits_le32(&dwc3_reg->g_usb2phycfg,
DWC3_GUSB2PHYCFG_PHYSOFTRST);
/* After PHYs are stable we can take Core out of reset state */
clrbits_le32(&dwc3_reg->g_ctl,
DWC3_GCTL_CORESOFTRESET);
}
static int dwc3_core_init(struct dwc3 *dwc3_reg)
{
u32 reg;
u32 revision;
unsigned int dwc3_hwparams1;
revision = readl(&dwc3_reg->g_snpsid);
/* This should read as U3 followed by revision number */
if ((revision & DWC3_GSNPSID_MASK) != 0x55330000) {
puts("this is not a DesignWare USB3 DRD Core\n");
return -EINVAL;
}
dwc3_core_soft_reset(dwc3_reg);
dwc3_hwparams1 = readl(&dwc3_reg->g_hwparams1);
reg = readl(&dwc3_reg->g_ctl);
reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
reg &= ~DWC3_GCTL_DISSCRAMBLE;
switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc3_hwparams1)) {
case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
reg &= ~DWC3_GCTL_DSBLCLKGTNG;
break;
default:
debug("No power optimization available\n");
}
/*
* WORKAROUND: DWC3 revisions <1.90a have a bug
* where the device can fail to connect at SuperSpeed
* and falls back to high-speed mode which causes
* the device to enter a Connect/Disconnect loop
*/
if ((revision & DWC3_REVISION_MASK) < 0x190a)
reg |= DWC3_GCTL_U2RSTECN;
writel(reg, &dwc3_reg->g_ctl);
return 0;
}
static int exynos_xhci_core_init(struct exynos_xhci *exynos)
{
int ret;
exynos5_usb3_phy_init(exynos->usb3_phy);
ret = dwc3_core_init(exynos->dwc3_reg);
if (ret) {
debug("failed to initialize core\n");
return -EINVAL;
}
/* We are hard-coding DWC3 core to Host Mode */
dwc3_set_mode(exynos->dwc3_reg, DWC3_GCTL_PRTCAP_HOST);
return 0;
}
static void exynos_xhci_core_exit(struct exynos_xhci *exynos)
{
exynos5_usb3_phy_exit(exynos->usb3_phy);
}
int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
{
struct exynos_xhci *ctx = &exynos;
int ret;
#ifdef CONFIG_OF_CONTROL
exynos_usb3_parse_dt(gd->fdt_blob, ctx);
#else
ctx->usb3_phy = (struct exynos_usb3_phy *)samsung_get_base_usb3_phy();
ctx->hcd = (struct xhci_hccr *)samsung_get_base_usb_xhci();
#endif
ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET);
#ifdef CONFIG_OF_CONTROL
/* setup the Vbus gpio here */
if (!fdtdec_setup_gpio(&ctx->vbus_gpio))
gpio_direction_output(ctx->vbus_gpio.gpio, 1);
#endif
ret = exynos_xhci_core_init(ctx);
if (ret) {
puts("XHCI: failed to initialize controller\n");
return -EINVAL;
}
*hccr = (ctx->hcd);
*hcor = (struct xhci_hcor *)((uint32_t) *hccr
+ HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
debug("Exynos5-xhci: init hccr %x and hcor %x hc_length %d\n",
(uint32_t)*hccr, (uint32_t)*hcor,
(uint32_t)HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
return 0;
}
void xhci_hcd_stop(int index)
{
struct exynos_xhci *ctx = &exynos;
exynos_xhci_core_exit(ctx);
}

720
drivers/usb/host/xhci-mem.c Normal file
View File

@ -0,0 +1,720 @@
/*
* USB HOST XHCI Controller stack
*
* Based on xHCI host controller driver in linux-kernel
* by Sarah Sharp.
*
* Copyright (C) 2008 Intel Corp.
* Author: Sarah Sharp
*
* Copyright (C) 2013 Samsung Electronics Co.Ltd
* Authors: Vivek Gautam <gautam.vivek@samsung.com>
* Vikas Sajjan <vikas.sajjan@samsung.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/byteorder.h>
#include <usb.h>
#include <malloc.h>
#include <asm/cache.h>
#include <asm-generic/errno.h>
#include "xhci.h"
#define CACHELINE_SIZE CONFIG_SYS_CACHELINE_SIZE
/**
* flushes the address passed till the length
*
* @param addr pointer to memory region to be flushed
* @param len the length of the cache line to be flushed
* @return none
*/
void xhci_flush_cache(uint32_t addr, u32 len)
{
BUG_ON((void *)addr == NULL || len == 0);
flush_dcache_range(addr & ~(CACHELINE_SIZE - 1),
ALIGN(addr + len, CACHELINE_SIZE));
}
/**
* invalidates the address passed till the length
*
* @param addr pointer to memory region to be invalidates
* @param len the length of the cache line to be invalidated
* @return none
*/
void xhci_inval_cache(uint32_t addr, u32 len)
{
BUG_ON((void *)addr == NULL || len == 0);
invalidate_dcache_range(addr & ~(CACHELINE_SIZE - 1),
ALIGN(addr + len, CACHELINE_SIZE));
}
/**
* frees the "segment" pointer passed
*
* @param ptr pointer to "segement" to be freed
* @return none
*/
static void xhci_segment_free(struct xhci_segment *seg)
{
free(seg->trbs);
seg->trbs = NULL;
free(seg);
}
/**
* frees the "ring" pointer passed
*
* @param ptr pointer to "ring" to be freed
* @return none
*/
static void xhci_ring_free(struct xhci_ring *ring)
{
struct xhci_segment *seg;
struct xhci_segment *first_seg;
BUG_ON(!ring);
first_seg = ring->first_seg;
seg = first_seg->next;
while (seg != first_seg) {
struct xhci_segment *next = seg->next;
xhci_segment_free(seg);
seg = next;
}
xhci_segment_free(first_seg);
free(ring);
}
/**
* frees the "xhci_container_ctx" pointer passed
*
* @param ptr pointer to "xhci_container_ctx" to be freed
* @return none
*/
static void xhci_free_container_ctx(struct xhci_container_ctx *ctx)
{
free(ctx->bytes);
free(ctx);
}
/**
* frees the virtual devices for "xhci_ctrl" pointer passed
*
* @param ptr pointer to "xhci_ctrl" whose virtual devices are to be freed
* @return none
*/
static void xhci_free_virt_devices(struct xhci_ctrl *ctrl)
{
int i;
int slot_id;
struct xhci_virt_device *virt_dev;
/*
* refactored here to loop through all virt_dev
* Slot ID 0 is reserved
*/
for (slot_id = 0; slot_id < MAX_HC_SLOTS; slot_id++) {
virt_dev = ctrl->devs[slot_id];
if (!virt_dev)
continue;
ctrl->dcbaa->dev_context_ptrs[slot_id] = 0;
for (i = 0; i < 31; ++i)
if (virt_dev->eps[i].ring)
xhci_ring_free(virt_dev->eps[i].ring);
if (virt_dev->in_ctx)
xhci_free_container_ctx(virt_dev->in_ctx);
if (virt_dev->out_ctx)
xhci_free_container_ctx(virt_dev->out_ctx);
free(virt_dev);
/* make sure we are pointing to NULL */
ctrl->devs[slot_id] = NULL;
}
}
/**
* frees all the memory allocated
*
* @param ptr pointer to "xhci_ctrl" to be cleaned up
* @return none
*/
void xhci_cleanup(struct xhci_ctrl *ctrl)
{
xhci_ring_free(ctrl->event_ring);
xhci_ring_free(ctrl->cmd_ring);
xhci_free_virt_devices(ctrl);
free(ctrl->erst.entries);
free(ctrl->dcbaa);
memset(ctrl, '\0', sizeof(struct xhci_ctrl));
}
/**
* Malloc the aligned memory
*
* @param size size of memory to be allocated
* @return allocates the memory and returns the aligned pointer
*/
static void *xhci_malloc(unsigned int size)
{
void *ptr;
size_t cacheline_size = max(XHCI_ALIGNMENT, CACHELINE_SIZE);
ptr = memalign(cacheline_size, ALIGN(size, cacheline_size));
BUG_ON(!ptr);
memset(ptr, '\0', size);
xhci_flush_cache((uint32_t)ptr, size);
return ptr;
}
/**
* Make the prev segment point to the next segment.
* Change the last TRB in the prev segment to be a Link TRB which points to the
* address of the next segment. The caller needs to set any Link TRB
* related flags, such as End TRB, Toggle Cycle, and no snoop.
*
* @param prev pointer to the previous segment
* @param next pointer to the next segment
* @param link_trbs flag to indicate whether to link the trbs or NOT
* @return none
*/
static void xhci_link_segments(struct xhci_segment *prev,
struct xhci_segment *next, bool link_trbs)
{
u32 val;
u64 val_64 = 0;
if (!prev || !next)
return;
prev->next = next;
if (link_trbs) {
val_64 = (uintptr_t)next->trbs;
prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr = val_64;
/*
* Set the last TRB in the segment to
* have a TRB type ID of Link TRB
*/
val = le32_to_cpu(prev->trbs[TRBS_PER_SEGMENT-1].link.control);
val &= ~TRB_TYPE_BITMASK;
val |= (TRB_LINK << TRB_TYPE_SHIFT);
prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val);
}
}
/**
* Initialises the Ring's enqueue,dequeue,enq_seg pointers
*
* @param ring pointer to the RING to be intialised
* @return none
*/
static void xhci_initialize_ring_info(struct xhci_ring *ring)
{
/*
* The ring is empty, so the enqueue pointer == dequeue pointer
*/
ring->enqueue = ring->first_seg->trbs;
ring->enq_seg = ring->first_seg;
ring->dequeue = ring->enqueue;
ring->deq_seg = ring->first_seg;
/*
* The ring is initialized to 0. The producer must write 1 to the
* cycle bit to handover ownership of the TRB, so PCS = 1.
* The consumer must compare CCS to the cycle bit to
* check ownership, so CCS = 1.
*/
ring->cycle_state = 1;
}
/**
* Allocates a generic ring segment from the ring pool, sets the dma address,
* initializes the segment to zero, and sets the private next pointer to NULL.
* Section 4.11.1.1:
* "All components of all Command and Transfer TRBs shall be initialized to '0'"
*
* @param none
* @return pointer to the newly allocated SEGMENT
*/
static struct xhci_segment *xhci_segment_alloc(void)
{
struct xhci_segment *seg;
seg = (struct xhci_segment *)malloc(sizeof(struct xhci_segment));
BUG_ON(!seg);
seg->trbs = (union xhci_trb *)xhci_malloc(SEGMENT_SIZE);
seg->next = NULL;
return seg;
}
/**
* Create a new ring with zero or more segments.
* TODO: current code only uses one-time-allocated single-segment rings
* of 1KB anyway, so we might as well get rid of all the segment and
* linking code (and maybe increase the size a bit, e.g. 4KB).
*
*
* Link each segment together into a ring.
* Set the end flag and the cycle toggle bit on the last segment.
* See section 4.9.2 and figures 15 and 16 of XHCI spec rev1.0.
*
* @param num_segs number of segments in the ring
* @param link_trbs flag to indicate whether to link the trbs or NOT
* @return pointer to the newly created RING
*/
struct xhci_ring *xhci_ring_alloc(unsigned int num_segs, bool link_trbs)
{
struct xhci_ring *ring;
struct xhci_segment *prev;
ring = (struct xhci_ring *)malloc(sizeof(struct xhci_ring));
BUG_ON(!ring);
if (num_segs == 0)
return ring;
ring->first_seg = xhci_segment_alloc();
BUG_ON(!ring->first_seg);
num_segs--;
prev = ring->first_seg;
while (num_segs > 0) {
struct xhci_segment *next;
next = xhci_segment_alloc();
BUG_ON(!next);
xhci_link_segments(prev, next, link_trbs);
prev = next;
num_segs--;
}
xhci_link_segments(prev, ring->first_seg, link_trbs);
if (link_trbs) {
/* See section 4.9.2.1 and 6.4.4.1 */
prev->trbs[TRBS_PER_SEGMENT-1].link.control |=
cpu_to_le32(LINK_TOGGLE);
}
xhci_initialize_ring_info(ring);
return ring;
}
/**
* Allocates the Container context
*
* @param ctrl Host controller data structure
* @param type type of XHCI Container Context
* @return NULL if failed else pointer to the context on success
*/
static struct xhci_container_ctx
*xhci_alloc_container_ctx(struct xhci_ctrl *ctrl, int type)
{
struct xhci_container_ctx *ctx;
ctx = (struct xhci_container_ctx *)
malloc(sizeof(struct xhci_container_ctx));
BUG_ON(!ctx);
BUG_ON((type != XHCI_CTX_TYPE_DEVICE) && (type != XHCI_CTX_TYPE_INPUT));
ctx->type = type;
ctx->size = (MAX_EP_CTX_NUM + 1) *
CTX_SIZE(readl(&ctrl->hccr->cr_hccparams));
if (type == XHCI_CTX_TYPE_INPUT)
ctx->size += CTX_SIZE(readl(&ctrl->hccr->cr_hccparams));
ctx->bytes = (u8 *)xhci_malloc(ctx->size);
return ctx;
}
/**
* Allocating virtual device
*
* @param udev pointer to USB deivce structure
* @return 0 on success else -1 on failure
*/
int xhci_alloc_virt_device(struct usb_device *udev)
{
u64 byte_64 = 0;
unsigned int slot_id = udev->slot_id;
struct xhci_virt_device *virt_dev;
struct xhci_ctrl *ctrl = udev->controller;
/* Slot ID 0 is reserved */
if (ctrl->devs[slot_id]) {
printf("Virt dev for slot[%d] already allocated\n", slot_id);
return -EEXIST;
}
ctrl->devs[slot_id] = (struct xhci_virt_device *)
malloc(sizeof(struct xhci_virt_device));
if (!ctrl->devs[slot_id]) {
puts("Failed to allocate virtual device\n");
return -ENOMEM;
}
memset(ctrl->devs[slot_id], 0, sizeof(struct xhci_virt_device));
virt_dev = ctrl->devs[slot_id];
/* Allocate the (output) device context that will be used in the HC. */
virt_dev->out_ctx = xhci_alloc_container_ctx(ctrl,
XHCI_CTX_TYPE_DEVICE);
if (!virt_dev->out_ctx) {
puts("Failed to allocate out context for virt dev\n");
return -ENOMEM;
}
/* Allocate the (input) device context for address device command */
virt_dev->in_ctx = xhci_alloc_container_ctx(ctrl,
XHCI_CTX_TYPE_INPUT);
if (!virt_dev->in_ctx) {
puts("Failed to allocate in context for virt dev\n");
return -ENOMEM;
}
/* Allocate endpoint 0 ring */
virt_dev->eps[0].ring = xhci_ring_alloc(1, true);
byte_64 = (uintptr_t)(virt_dev->out_ctx->bytes);
/* Point to output device context in dcbaa. */
ctrl->dcbaa->dev_context_ptrs[slot_id] = byte_64;
xhci_flush_cache((uint32_t)&ctrl->dcbaa->dev_context_ptrs[slot_id],
sizeof(__le64));
return 0;
}
/**
* Allocates the necessary data structures
* for XHCI host controller
*
* @param ctrl Host controller data structure
* @param hccr pointer to HOST Controller Control Registers
* @param hcor pointer to HOST Controller Operational Registers
* @return 0 if successful else -1 on failure
*/
int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr,
struct xhci_hcor *hcor)
{
uint64_t val_64;
uint64_t trb_64;
uint32_t val;
unsigned long deq;
int i;
struct xhci_segment *seg;
/* DCBAA initialization */
ctrl->dcbaa = (struct xhci_device_context_array *)
xhci_malloc(sizeof(struct xhci_device_context_array));
if (ctrl->dcbaa == NULL) {
puts("unable to allocate DCBA\n");
return -ENOMEM;
}
val_64 = (uintptr_t)ctrl->dcbaa;
/* Set the pointer in DCBAA register */
xhci_writeq(&hcor->or_dcbaap, val_64);
/* Command ring control pointer register initialization */
ctrl->cmd_ring = xhci_ring_alloc(1, true);
/* Set the address in the Command Ring Control register */
trb_64 = (uintptr_t)ctrl->cmd_ring->first_seg->trbs;
val_64 = xhci_readq(&hcor->or_crcr);
val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
(trb_64 & (u64) ~CMD_RING_RSVD_BITS) |
ctrl->cmd_ring->cycle_state;
xhci_writeq(&hcor->or_crcr, val_64);
/* write the address of db register */
val = xhci_readl(&hccr->cr_dboff);
val &= DBOFF_MASK;
ctrl->dba = (struct xhci_doorbell_array *)((char *)hccr + val);
/* write the address of runtime register */
val = xhci_readl(&hccr->cr_rtsoff);
val &= RTSOFF_MASK;
ctrl->run_regs = (struct xhci_run_regs *)((char *)hccr + val);
/* writting the address of ir_set structure */
ctrl->ir_set = &ctrl->run_regs->ir_set[0];
/* Event ring does not maintain link TRB */
ctrl->event_ring = xhci_ring_alloc(ERST_NUM_SEGS, false);
ctrl->erst.entries = (struct xhci_erst_entry *)
xhci_malloc(sizeof(struct xhci_erst_entry) * ERST_NUM_SEGS);
ctrl->erst.num_entries = ERST_NUM_SEGS;
for (val = 0, seg = ctrl->event_ring->first_seg;
val < ERST_NUM_SEGS;
val++) {
trb_64 = 0;
trb_64 = (uintptr_t)seg->trbs;
struct xhci_erst_entry *entry = &ctrl->erst.entries[val];
xhci_writeq(&entry->seg_addr, trb_64);
entry->seg_size = cpu_to_le32(TRBS_PER_SEGMENT);
entry->rsvd = 0;
seg = seg->next;
}
xhci_flush_cache((uint32_t)ctrl->erst.entries,
ERST_NUM_SEGS * sizeof(struct xhci_erst_entry));
deq = (unsigned long)ctrl->event_ring->dequeue;
/* Update HC event ring dequeue pointer */
xhci_writeq(&ctrl->ir_set->erst_dequeue,
(u64)deq & (u64)~ERST_PTR_MASK);
/* set ERST count with the number of entries in the segment table */
val = xhci_readl(&ctrl->ir_set->erst_size);
val &= ERST_SIZE_MASK;
val |= ERST_NUM_SEGS;
xhci_writel(&ctrl->ir_set->erst_size, val);
/* this is the event ring segment table pointer */
val_64 = xhci_readq(&ctrl->ir_set->erst_base);
val_64 &= ERST_PTR_MASK;
val_64 |= ((u32)(ctrl->erst.entries) & ~ERST_PTR_MASK);
xhci_writeq(&ctrl->ir_set->erst_base, val_64);
/* initializing the virtual devices to NULL */
for (i = 0; i < MAX_HC_SLOTS; ++i)
ctrl->devs[i] = NULL;
/*
* Just Zero'ing this register completely,
* or some spurious Device Notification Events
* might screw things here.
*/
xhci_writel(&hcor->or_dnctrl, 0x0);
return 0;
}
/**
* Give the input control context for the passed container context
*
* @param ctx pointer to the context
* @return pointer to the Input control context data
*/
struct xhci_input_control_ctx
*xhci_get_input_control_ctx(struct xhci_container_ctx *ctx)
{
BUG_ON(ctx->type != XHCI_CTX_TYPE_INPUT);
return (struct xhci_input_control_ctx *)ctx->bytes;
}
/**
* Give the slot context for the passed container context
*
* @param ctrl Host controller data structure
* @param ctx pointer to the context
* @return pointer to the slot control context data
*/
struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_ctrl *ctrl,
struct xhci_container_ctx *ctx)
{
if (ctx->type == XHCI_CTX_TYPE_DEVICE)
return (struct xhci_slot_ctx *)ctx->bytes;
return (struct xhci_slot_ctx *)
(ctx->bytes + CTX_SIZE(readl(&ctrl->hccr->cr_hccparams)));
}
/**
* Gets the EP context from based on the ep_index
*
* @param ctrl Host controller data structure
* @param ctx context container
* @param ep_index index of the endpoint
* @return pointer to the End point context
*/
struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_ctrl *ctrl,
struct xhci_container_ctx *ctx,
unsigned int ep_index)
{
/* increment ep index by offset of start of ep ctx array */
ep_index++;
if (ctx->type == XHCI_CTX_TYPE_INPUT)
ep_index++;
return (struct xhci_ep_ctx *)
(ctx->bytes +
(ep_index * CTX_SIZE(readl(&ctrl->hccr->cr_hccparams))));
}
/**
* Copy output xhci_ep_ctx to the input xhci_ep_ctx copy.
* Useful when you want to change one particular aspect of the endpoint
* and then issue a configure endpoint command.
*
* @param ctrl Host controller data structure
* @param in_ctx contains the input context
* @param out_ctx contains the input context
* @param ep_index index of the end point
* @return none
*/
void xhci_endpoint_copy(struct xhci_ctrl *ctrl,
struct xhci_container_ctx *in_ctx,
struct xhci_container_ctx *out_ctx,
unsigned int ep_index)
{
struct xhci_ep_ctx *out_ep_ctx;
struct xhci_ep_ctx *in_ep_ctx;
out_ep_ctx = xhci_get_ep_ctx(ctrl, out_ctx, ep_index);
in_ep_ctx = xhci_get_ep_ctx(ctrl, in_ctx, ep_index);
in_ep_ctx->ep_info = out_ep_ctx->ep_info;
in_ep_ctx->ep_info2 = out_ep_ctx->ep_info2;
in_ep_ctx->deq = out_ep_ctx->deq;
in_ep_ctx->tx_info = out_ep_ctx->tx_info;
}
/**
* Copy output xhci_slot_ctx to the input xhci_slot_ctx.
* Useful when you want to change one particular aspect of the endpoint
* and then issue a configure endpoint command.
* Only the context entries field matters, but
* we'll copy the whole thing anyway.
*
* @param ctrl Host controller data structure
* @param in_ctx contains the inpout context
* @param out_ctx contains the inpout context
* @return none
*/
void xhci_slot_copy(struct xhci_ctrl *ctrl, struct xhci_container_ctx *in_ctx,
struct xhci_container_ctx *out_ctx)
{
struct xhci_slot_ctx *in_slot_ctx;
struct xhci_slot_ctx *out_slot_ctx;
in_slot_ctx = xhci_get_slot_ctx(ctrl, in_ctx);
out_slot_ctx = xhci_get_slot_ctx(ctrl, out_ctx);
in_slot_ctx->dev_info = out_slot_ctx->dev_info;
in_slot_ctx->dev_info2 = out_slot_ctx->dev_info2;
in_slot_ctx->tt_info = out_slot_ctx->tt_info;
in_slot_ctx->dev_state = out_slot_ctx->dev_state;
}
/**
* Setup an xHCI virtual device for a Set Address command
*
* @param udev pointer to the Device Data Structure
* @return returns negative value on failure else 0 on success
*/
void xhci_setup_addressable_virt_dev(struct usb_device *udev)
{
struct usb_device *hop = udev;
struct xhci_virt_device *virt_dev;
struct xhci_ep_ctx *ep0_ctx;
struct xhci_slot_ctx *slot_ctx;
u32 port_num = 0;
u64 trb_64 = 0;
struct xhci_ctrl *ctrl = udev->controller;
virt_dev = ctrl->devs[udev->slot_id];
BUG_ON(!virt_dev);
/* Extract the EP0 and Slot Ctrl */
ep0_ctx = xhci_get_ep_ctx(ctrl, virt_dev->in_ctx, 0);
slot_ctx = xhci_get_slot_ctx(ctrl, virt_dev->in_ctx);
/* Only the control endpoint is valid - one endpoint context */
slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1) | 0);
switch (udev->speed) {
case USB_SPEED_SUPER:
slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_SS);
break;
case USB_SPEED_HIGH:
slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_HS);
break;
case USB_SPEED_FULL:
slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_FS);
break;
case USB_SPEED_LOW:
slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_LS);
break;
default:
/* Speed was set earlier, this shouldn't happen. */
BUG();
}
/* Extract the root hub port number */
if (hop->parent)
while (hop->parent->parent)
hop = hop->parent;
port_num = hop->portnr;
debug("port_num = %d\n", port_num);
slot_ctx->dev_info2 |=
cpu_to_le32(((port_num & ROOT_HUB_PORT_MASK) <<
ROOT_HUB_PORT_SHIFT));
/* Step 4 - ring already allocated */
/* Step 5 */
ep0_ctx->ep_info2 = cpu_to_le32(CTRL_EP << EP_TYPE_SHIFT);
debug("SPEED = %d\n", udev->speed);
switch (udev->speed) {
case USB_SPEED_SUPER:
ep0_ctx->ep_info2 |= cpu_to_le32(((512 & MAX_PACKET_MASK) <<
MAX_PACKET_SHIFT));
debug("Setting Packet size = 512bytes\n");
break;
case USB_SPEED_HIGH:
/* USB core guesses at a 64-byte max packet first for FS devices */
case USB_SPEED_FULL:
ep0_ctx->ep_info2 |= cpu_to_le32(((64 & MAX_PACKET_MASK) <<
MAX_PACKET_SHIFT));
debug("Setting Packet size = 64bytes\n");
break;
case USB_SPEED_LOW:
ep0_ctx->ep_info2 |= cpu_to_le32(((8 & MAX_PACKET_MASK) <<
MAX_PACKET_SHIFT));
debug("Setting Packet size = 8bytes\n");
break;
default:
/* New speed? */
BUG();
}
/* EP 0 can handle "burst" sizes of 1, so Max Burst Size field is 0 */
ep0_ctx->ep_info2 |=
cpu_to_le32(((0 & MAX_BURST_MASK) << MAX_BURST_SHIFT) |
((3 & ERROR_COUNT_MASK) << ERROR_COUNT_SHIFT));
trb_64 = (uintptr_t)virt_dev->eps[0].ring->first_seg->trbs;
ep0_ctx->deq = cpu_to_le64(trb_64 | virt_dev->eps[0].ring->cycle_state);
/* Steps 7 and 8 were done in xhci_alloc_virt_device() */
xhci_flush_cache((uint32_t)ep0_ctx, sizeof(struct xhci_ep_ctx));
xhci_flush_cache((uint32_t)slot_ctx, sizeof(struct xhci_slot_ctx));
}

View File

@ -0,0 +1,158 @@
/*
* OMAP USB HOST xHCI Controller
*
* (C) Copyright 2013
* Texas Instruments, <www.ti.com>
*
* Author: Dan Murphy <dmurphy@ti.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <usb.h>
#include <asm-generic/errno.h>
#include <asm/omap_common.h>
#include <asm/arch/cpu.h>
#include <asm/arch/sys_proto.h>
#include <linux/compat.h>
#include <linux/usb/dwc3.h>
#include <linux/usb/xhci-omap.h>
#include "xhci.h"
/* Declare global data pointer */
DECLARE_GLOBAL_DATA_PTR;
static struct omap_xhci omap;
inline int __board_usb_init(int index, enum board_usb_init_type init)
{
return 0;
}
int board_usb_init(int index, enum board_usb_init_type init) \
__attribute__((weak, alias("__board_usb_init")));
static void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode)
{
clrsetbits_le32(&dwc3_reg->g_ctl,
DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG),
DWC3_GCTL_PRTCAPDIR(mode));
}
static void dwc3_core_soft_reset(struct dwc3 *dwc3_reg)
{
/* Before Resetting PHY, put Core in Reset */
setbits_le32(&dwc3_reg->g_ctl, DWC3_GCTL_CORESOFTRESET);
omap_reset_usb_phy(dwc3_reg);
/* After PHYs are stable we can take Core out of reset state */
clrbits_le32(&dwc3_reg->g_ctl, DWC3_GCTL_CORESOFTRESET);
}
static int dwc3_core_init(struct dwc3 *dwc3_reg)
{
u32 reg;
u32 revision;
unsigned int dwc3_hwparams1;
revision = readl(&dwc3_reg->g_snpsid);
/* This should read as U3 followed by revision number */
if ((revision & DWC3_GSNPSID_MASK) != 0x55330000) {
puts("this is not a DesignWare USB3 DRD Core\n");
return -1;
}
dwc3_core_soft_reset(dwc3_reg);
dwc3_hwparams1 = readl(&dwc3_reg->g_hwparams1);
reg = readl(&dwc3_reg->g_ctl);
reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
reg &= ~DWC3_GCTL_DISSCRAMBLE;
switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc3_hwparams1)) {
case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
reg &= ~DWC3_GCTL_DSBLCLKGTNG;
break;
default:
debug("No power optimization available\n");
}
/*
* WORKAROUND: DWC3 revisions <1.90a have a bug
* where the device can fail to connect at SuperSpeed
* and falls back to high-speed mode which causes
* the device to enter a Connect/Disconnect loop
*/
if ((revision & DWC3_REVISION_MASK) < 0x190a)
reg |= DWC3_GCTL_U2RSTECN;
writel(reg, &dwc3_reg->g_ctl);
return 0;
}
static int omap_xhci_core_init(struct omap_xhci *omap)
{
int ret = 0;
omap_enable_phy(omap);
ret = dwc3_core_init(omap->dwc3_reg);
if (ret) {
debug("%s:failed to initialize core\n", __func__);
return ret;
}
/* We are hard-coding DWC3 core to Host Mode */
dwc3_set_mode(omap->dwc3_reg, DWC3_GCTL_PRTCAP_HOST);
return ret;
}
static void omap_xhci_core_exit(struct omap_xhci *omap)
{
usb_phy_power(0);
}
int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
{
struct omap_xhci *ctx = &omap;
int ret = 0;
ctx->hcd = (struct xhci_hccr *)OMAP_XHCI_BASE;
ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET);
ctx->usb3_phy = (struct omap_usb3_phy *)OMAP_OCP1_SCP_BASE;
ctx->otg_wrapper = (struct omap_dwc_wrapper *)OMAP_OTG_WRAPPER_BASE;
ret = board_usb_init(index, USB_INIT_HOST);
if (ret != 0) {
puts("Failed to initialize board for USB\n");
return ret;
}
ret = omap_xhci_core_init(ctx);
if (ret < 0) {
puts("Failed to initialize xhci\n");
return ret;
}
*hccr = (struct xhci_hccr *)(OMAP_XHCI_BASE);
*hcor = (struct xhci_hcor *)((uint32_t) *hccr
+ HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
debug("omap-xhci: init hccr %x and hcor %x hc_length %d\n",
(uint32_t)*hccr, (uint32_t)*hcor,
(uint32_t)HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
return ret;
}
void xhci_hcd_stop(int index)
{
struct omap_xhci *ctx = &omap;
omap_xhci_core_exit(ctx);
}

View File

@ -0,0 +1,939 @@
/*
* USB HOST XHCI Controller stack
*
* Based on xHCI host controller driver in linux-kernel
* by Sarah Sharp.
*
* Copyright (C) 2008 Intel Corp.
* Author: Sarah Sharp
*
* Copyright (C) 2013 Samsung Electronics Co.Ltd
* Authors: Vivek Gautam <gautam.vivek@samsung.com>
* Vikas Sajjan <vikas.sajjan@samsung.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/byteorder.h>
#include <usb.h>
#include <asm/unaligned.h>
#include <asm-generic/errno.h>
#include "xhci.h"
/**
* Is this TRB a link TRB or was the last TRB the last TRB in this event ring
* segment? I.e. would the updated event TRB pointer step off the end of the
* event seg ?
*
* @param ctrl Host controller data structure
* @param ring pointer to the ring
* @param seg poniter to the segment to which TRB belongs
* @param trb poniter to the ring trb
* @return 1 if this TRB a link TRB else 0
*/
static int last_trb(struct xhci_ctrl *ctrl, struct xhci_ring *ring,
struct xhci_segment *seg, union xhci_trb *trb)
{
if (ring == ctrl->event_ring)
return trb == &seg->trbs[TRBS_PER_SEGMENT];
else
return TRB_TYPE_LINK_LE32(trb->link.control);
}
/**
* Does this link TRB point to the first segment in a ring,
* or was the previous TRB the last TRB on the last segment in the ERST?
*
* @param ctrl Host controller data structure
* @param ring pointer to the ring
* @param seg poniter to the segment to which TRB belongs
* @param trb poniter to the ring trb
* @return 1 if this TRB is the last TRB on the last segment else 0
*/
static bool last_trb_on_last_seg(struct xhci_ctrl *ctrl,
struct xhci_ring *ring,
struct xhci_segment *seg,
union xhci_trb *trb)
{
if (ring == ctrl->event_ring)
return ((trb == &seg->trbs[TRBS_PER_SEGMENT]) &&
(seg->next == ring->first_seg));
else
return le32_to_cpu(trb->link.control) & LINK_TOGGLE;
}
/**
* See Cycle bit rules. SW is the consumer for the event ring only.
* Don't make a ring full of link TRBs. That would be dumb and this would loop.
*
* If we've just enqueued a TRB that is in the middle of a TD (meaning the
* chain bit is set), then set the chain bit in all the following link TRBs.
* If we've enqueued the last TRB in a TD, make sure the following link TRBs
* have their chain bit cleared (so that each Link TRB is a separate TD).
*
* Section 6.4.4.1 of the 0.95 spec says link TRBs cannot have the chain bit
* set, but other sections talk about dealing with the chain bit set. This was
* fixed in the 0.96 specification errata, but we have to assume that all 0.95
* xHCI hardware can't handle the chain bit being cleared on a link TRB.
*
* @param ctrl Host controller data structure
* @param ring pointer to the ring
* @param more_trbs_coming flag to indicate whether more trbs
* are expected or NOT.
* Will you enqueue more TRBs before calling
* prepare_ring()?
* @return none
*/
static void inc_enq(struct xhci_ctrl *ctrl, struct xhci_ring *ring,
bool more_trbs_coming)
{
u32 chain;
union xhci_trb *next;
chain = le32_to_cpu(ring->enqueue->generic.field[3]) & TRB_CHAIN;
next = ++(ring->enqueue);
/*
* Update the dequeue pointer further if that was a link TRB or we're at
* the end of an event ring segment (which doesn't have link TRBS)
*/
while (last_trb(ctrl, ring, ring->enq_seg, next)) {
if (ring != ctrl->event_ring) {
/*
* If the caller doesn't plan on enqueueing more
* TDs before ringing the doorbell, then we
* don't want to give the link TRB to the
* hardware just yet. We'll give the link TRB
* back in prepare_ring() just before we enqueue
* the TD at the top of the ring.
*/
if (!chain && !more_trbs_coming)
break;
/*
* If we're not dealing with 0.95 hardware or
* isoc rings on AMD 0.96 host,
* carry over the chain bit of the previous TRB
* (which may mean the chain bit is cleared).
*/
next->link.control &= cpu_to_le32(~TRB_CHAIN);
next->link.control |= cpu_to_le32(chain);
next->link.control ^= cpu_to_le32(TRB_CYCLE);
xhci_flush_cache((uint32_t)next,
sizeof(union xhci_trb));
}
/* Toggle the cycle bit after the last ring segment. */
if (last_trb_on_last_seg(ctrl, ring,
ring->enq_seg, next))
ring->cycle_state = (ring->cycle_state ? 0 : 1);
ring->enq_seg = ring->enq_seg->next;
ring->enqueue = ring->enq_seg->trbs;
next = ring->enqueue;
}
}
/**
* See Cycle bit rules. SW is the consumer for the event ring only.
* Don't make a ring full of link TRBs. That would be dumb and this would loop.
*
* @param ctrl Host controller data structure
* @param ring Ring whose Dequeue TRB pointer needs to be incremented.
* return none
*/
static void inc_deq(struct xhci_ctrl *ctrl, struct xhci_ring *ring)
{
do {
/*
* Update the dequeue pointer further if that was a link TRB or
* we're at the end of an event ring segment (which doesn't have
* link TRBS)
*/
if (last_trb(ctrl, ring, ring->deq_seg, ring->dequeue)) {
if (ring == ctrl->event_ring &&
last_trb_on_last_seg(ctrl, ring,
ring->deq_seg, ring->dequeue)) {
ring->cycle_state = (ring->cycle_state ? 0 : 1);
}
ring->deq_seg = ring->deq_seg->next;
ring->dequeue = ring->deq_seg->trbs;
} else {
ring->dequeue++;
}
} while (last_trb(ctrl, ring, ring->deq_seg, ring->dequeue));
}
/**
* Generic function for queueing a TRB on a ring.
* The caller must have checked to make sure there's room on the ring.
*
* @param more_trbs_coming: Will you enqueue more TRBs before calling
* prepare_ring()?
* @param ctrl Host controller data structure
* @param ring pointer to the ring
* @param more_trbs_coming flag to indicate whether more trbs
* @param trb_fields pointer to trb field array containing TRB contents
* @return pointer to the enqueued trb
*/
static struct xhci_generic_trb *queue_trb(struct xhci_ctrl *ctrl,
struct xhci_ring *ring,
bool more_trbs_coming,
unsigned int *trb_fields)
{
struct xhci_generic_trb *trb;
int i;
trb = &ring->enqueue->generic;
for (i = 0; i < 4; i++)
trb->field[i] = cpu_to_le32(trb_fields[i]);
xhci_flush_cache((uint32_t)trb, sizeof(struct xhci_generic_trb));
inc_enq(ctrl, ring, more_trbs_coming);
return trb;
}
/**
* Does various checks on the endpoint ring, and makes it ready
* to queue num_trbs.
*
* @param ctrl Host controller data structure
* @param ep_ring pointer to the EP Transfer Ring
* @param ep_state State of the End Point
* @return error code in case of invalid ep_state, 0 on success
*/
static int prepare_ring(struct xhci_ctrl *ctrl, struct xhci_ring *ep_ring,
u32 ep_state)
{
union xhci_trb *next = ep_ring->enqueue;
/* Make sure the endpoint has been added to xHC schedule */
switch (ep_state) {
case EP_STATE_DISABLED:
/*
* USB core changed config/interfaces without notifying us,
* or hardware is reporting the wrong state.
*/
puts("WARN urb submitted to disabled ep\n");
return -ENOENT;
case EP_STATE_ERROR:
puts("WARN waiting for error on ep to be cleared\n");
return -EINVAL;
case EP_STATE_HALTED:
puts("WARN halted endpoint, queueing URB anyway.\n");
case EP_STATE_STOPPED:
case EP_STATE_RUNNING:
debug("EP STATE RUNNING.\n");
break;
default:
puts("ERROR unknown endpoint state for ep\n");
return -EINVAL;
}
while (last_trb(ctrl, ep_ring, ep_ring->enq_seg, next)) {
/*
* If we're not dealing with 0.95 hardware or isoc rings
* on AMD 0.96 host, clear the chain bit.
*/
next->link.control &= cpu_to_le32(~TRB_CHAIN);
next->link.control ^= cpu_to_le32(TRB_CYCLE);
xhci_flush_cache((uint32_t)next, sizeof(union xhci_trb));
/* Toggle the cycle bit after the last ring segment. */
if (last_trb_on_last_seg(ctrl, ep_ring,
ep_ring->enq_seg, next))
ep_ring->cycle_state = (ep_ring->cycle_state ? 0 : 1);
ep_ring->enq_seg = ep_ring->enq_seg->next;
ep_ring->enqueue = ep_ring->enq_seg->trbs;
next = ep_ring->enqueue;
}
return 0;
}
/**
* Generic function for queueing a command TRB on the command ring.
* Check to make sure there's room on the command ring for one command TRB.
*
* @param ctrl Host controller data structure
* @param ptr Pointer address to write in the first two fields (opt.)
* @param slot_id Slot ID to encode in the flags field (opt.)
* @param ep_index Endpoint index to encode in the flags field (opt.)
* @param cmd Command type to enqueue
* @return none
*/
void xhci_queue_command(struct xhci_ctrl *ctrl, u8 *ptr, u32 slot_id,
u32 ep_index, trb_type cmd)
{
u32 fields[4];
u64 val_64 = (uintptr_t)ptr;
BUG_ON(prepare_ring(ctrl, ctrl->cmd_ring, EP_STATE_RUNNING));
fields[0] = lower_32_bits(val_64);
fields[1] = upper_32_bits(val_64);
fields[2] = 0;
fields[3] = TRB_TYPE(cmd) | EP_ID_FOR_TRB(ep_index) |
SLOT_ID_FOR_TRB(slot_id) | ctrl->cmd_ring->cycle_state;
queue_trb(ctrl, ctrl->cmd_ring, false, fields);
/* Ring the command ring doorbell */
xhci_writel(&ctrl->dba->doorbell[0], DB_VALUE_HOST);
}
/**
* The TD size is the number of bytes remaining in the TD (including this TRB),
* right shifted by 10.
* It must fit in bits 21:17, so it can't be bigger than 31.
*
* @param remainder remaining packets to be sent
* @return remainder if remainder is less than max else max
*/
static u32 xhci_td_remainder(unsigned int remainder)
{
u32 max = (1 << (21 - 17 + 1)) - 1;
if ((remainder >> 10) >= max)
return max << 17;
else
return (remainder >> 10) << 17;
}
/**
* Finds out the remanining packets to be sent
*
* @param running_total total size sent so far
* @param trb_buff_len length of the TRB Buffer
* @param total_packet_count total packet count
* @param maxpacketsize max packet size of current pipe
* @param num_trbs_left number of TRBs left to be processed
* @return 0 if running_total or trb_buff_len is 0, else remainder
*/
static u32 xhci_v1_0_td_remainder(int running_total,
int trb_buff_len,
unsigned int total_packet_count,
int maxpacketsize,
unsigned int num_trbs_left)
{
int packets_transferred;
/* One TRB with a zero-length data packet. */
if (num_trbs_left == 0 || (running_total == 0 && trb_buff_len == 0))
return 0;
/*
* All the TRB queueing functions don't count the current TRB in
* running_total.
*/
packets_transferred = (running_total + trb_buff_len) / maxpacketsize;
if ((total_packet_count - packets_transferred) > 31)
return 31 << 17;
return (total_packet_count - packets_transferred) << 17;
}
/**
* Ring the doorbell of the End Point
*
* @param udev pointer to the USB device structure
* @param ep_index index of the endpoint
* @param start_cycle cycle flag of the first TRB
* @param start_trb pionter to the first TRB
* @return none
*/
static void giveback_first_trb(struct usb_device *udev, int ep_index,
int start_cycle,
struct xhci_generic_trb *start_trb)
{
struct xhci_ctrl *ctrl = udev->controller;
/*
* Pass all the TRBs to the hardware at once and make sure this write
* isn't reordered.
*/
if (start_cycle)
start_trb->field[3] |= cpu_to_le32(start_cycle);
else
start_trb->field[3] &= cpu_to_le32(~TRB_CYCLE);
xhci_flush_cache((uint32_t)start_trb, sizeof(struct xhci_generic_trb));
/* Ringing EP doorbell here */
xhci_writel(&ctrl->dba->doorbell[udev->slot_id],
DB_VALUE(ep_index, 0));
return;
}
/**** POLLING mechanism for XHCI ****/
/**
* Finalizes a handled event TRB by advancing our dequeue pointer and giving
* the TRB back to the hardware for recycling. Must call this exactly once at
* the end of each event handler, and not touch the TRB again afterwards.
*
* @param ctrl Host controller data structure
* @return none
*/
void xhci_acknowledge_event(struct xhci_ctrl *ctrl)
{
/* Advance our dequeue pointer to the next event */
inc_deq(ctrl, ctrl->event_ring);
/* Inform the hardware */
xhci_writeq(&ctrl->ir_set->erst_dequeue,
(uintptr_t)ctrl->event_ring->dequeue | ERST_EHB);
}
/**
* Checks if there is a new event to handle on the event ring.
*
* @param ctrl Host controller data structure
* @return 0 if failure else 1 on success
*/
static int event_ready(struct xhci_ctrl *ctrl)
{
union xhci_trb *event;
xhci_inval_cache((uint32_t)ctrl->event_ring->dequeue,
sizeof(union xhci_trb));
event = ctrl->event_ring->dequeue;
/* Does the HC or OS own the TRB? */
if ((le32_to_cpu(event->event_cmd.flags) & TRB_CYCLE) !=
ctrl->event_ring->cycle_state)
return 0;
return 1;
}
/**
* Waits for a specific type of event and returns it. Discards unexpected
* events. Caller *must* call xhci_acknowledge_event() after it is finished
* processing the event, and must not access the returned pointer afterwards.
*
* @param ctrl Host controller data structure
* @param expected TRB type expected from Event TRB
* @return pointer to event trb
*/
union xhci_trb *xhci_wait_for_event(struct xhci_ctrl *ctrl, trb_type expected)
{
trb_type type;
unsigned long ts = get_timer(0);
do {
union xhci_trb *event = ctrl->event_ring->dequeue;
if (!event_ready(ctrl))
continue;
type = TRB_FIELD_TO_TYPE(le32_to_cpu(event->event_cmd.flags));
if (type == expected)
return event;
if (type == TRB_PORT_STATUS)
/* TODO: remove this once enumeration has been reworked */
/*
* Port status change events always have a
* successful completion code
*/
BUG_ON(GET_COMP_CODE(
le32_to_cpu(event->generic.field[2])) !=
COMP_SUCCESS);
else
printf("Unexpected XHCI event TRB, skipping... "
"(%08x %08x %08x %08x)\n",
le32_to_cpu(event->generic.field[0]),
le32_to_cpu(event->generic.field[1]),
le32_to_cpu(event->generic.field[2]),
le32_to_cpu(event->generic.field[3]));
xhci_acknowledge_event(ctrl);
} while (get_timer(ts) < XHCI_TIMEOUT);
if (expected == TRB_TRANSFER)
return NULL;
printf("XHCI timeout on event type %d... cannot recover.\n", expected);
BUG();
}
/*
* Stops transfer processing for an endpoint and throws away all unprocessed
* TRBs by setting the xHC's dequeue pointer to our enqueue pointer. The next
* xhci_bulk_tx/xhci_ctrl_tx on this enpoint will add new transfers there and
* ring the doorbell, causing this endpoint to start working again.
* (Careful: This will BUG() when there was no transfer in progress. Shouldn't
* happen in practice for current uses and is too complicated to fix right now.)
*/
static void abort_td(struct usb_device *udev, int ep_index)
{
struct xhci_ctrl *ctrl = udev->controller;
struct xhci_ring *ring = ctrl->devs[udev->slot_id]->eps[ep_index].ring;
union xhci_trb *event;
u32 field;
xhci_queue_command(ctrl, NULL, udev->slot_id, ep_index, TRB_STOP_RING);
event = xhci_wait_for_event(ctrl, TRB_TRANSFER);
field = le32_to_cpu(event->trans_event.flags);
BUG_ON(TRB_TO_SLOT_ID(field) != udev->slot_id);
BUG_ON(TRB_TO_EP_INDEX(field) != ep_index);
BUG_ON(GET_COMP_CODE(le32_to_cpu(event->trans_event.transfer_len
!= COMP_STOP)));
xhci_acknowledge_event(ctrl);
event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags))
!= udev->slot_id || GET_COMP_CODE(le32_to_cpu(
event->event_cmd.status)) != COMP_SUCCESS);
xhci_acknowledge_event(ctrl);
xhci_queue_command(ctrl, (void *)((uintptr_t)ring->enqueue |
ring->cycle_state), udev->slot_id, ep_index, TRB_SET_DEQ);
event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags))
!= udev->slot_id || GET_COMP_CODE(le32_to_cpu(
event->event_cmd.status)) != COMP_SUCCESS);
xhci_acknowledge_event(ctrl);
}
static void record_transfer_result(struct usb_device *udev,
union xhci_trb *event, int length)
{
udev->act_len = min(length, length -
EVENT_TRB_LEN(le32_to_cpu(event->trans_event.transfer_len)));
switch (GET_COMP_CODE(le32_to_cpu(event->trans_event.transfer_len))) {
case COMP_SUCCESS:
BUG_ON(udev->act_len != length);
/* fallthrough */
case COMP_SHORT_TX:
udev->status = 0;
break;
case COMP_STALL:
udev->status = USB_ST_STALLED;
break;
case COMP_DB_ERR:
case COMP_TRB_ERR:
udev->status = USB_ST_BUF_ERR;
break;
case COMP_BABBLE:
udev->status = USB_ST_BABBLE_DET;
break;
default:
udev->status = 0x80; /* USB_ST_TOO_LAZY_TO_MAKE_A_NEW_MACRO */
}
}
/**** Bulk and Control transfer methods ****/
/**
* Queues up the BULK Request
*
* @param udev pointer to the USB device structure
* @param pipe contains the DIR_IN or OUT , devnum
* @param length length of the buffer
* @param buffer buffer to be read/written based on the request
* @return returns 0 if successful else -1 on failure
*/
int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
int length, void *buffer)
{
int num_trbs = 0;
struct xhci_generic_trb *start_trb;
bool first_trb = 0;
int start_cycle;
u32 field = 0;
u32 length_field = 0;
struct xhci_ctrl *ctrl = udev->controller;
int slot_id = udev->slot_id;
int ep_index;
struct xhci_virt_device *virt_dev;
struct xhci_ep_ctx *ep_ctx;
struct xhci_ring *ring; /* EP transfer ring */
union xhci_trb *event;
int running_total, trb_buff_len;
unsigned int total_packet_count;
int maxpacketsize;
u64 addr;
int ret;
u32 trb_fields[4];
u64 val_64 = (uintptr_t)buffer;
debug("dev=%p, pipe=%lx, buffer=%p, length=%d\n",
udev, pipe, buffer, length);
ep_index = usb_pipe_ep_index(pipe);
virt_dev = ctrl->devs[slot_id];
xhci_inval_cache((uint32_t)virt_dev->out_ctx->bytes,
virt_dev->out_ctx->size);
ep_ctx = xhci_get_ep_ctx(ctrl, virt_dev->out_ctx, ep_index);
ring = virt_dev->eps[ep_index].ring;
/*
* How much data is (potentially) left before the 64KB boundary?
* XHCI Spec puts restriction( TABLE 49 and 6.4.1 section of XHCI Spec)
* that the buffer should not span 64KB boundary. if so
* we send request in more than 1 TRB by chaining them.
*/
running_total = TRB_MAX_BUFF_SIZE -
(lower_32_bits(val_64) & (TRB_MAX_BUFF_SIZE - 1));
trb_buff_len = running_total;
running_total &= TRB_MAX_BUFF_SIZE - 1;
/*
* If there's some data on this 64KB chunk, or we have to send a
* zero-length transfer, we need at least one TRB
*/
if (running_total != 0 || length == 0)
num_trbs++;
/* How many more 64KB chunks to transfer, how many more TRBs? */
while (running_total < length) {
num_trbs++;
running_total += TRB_MAX_BUFF_SIZE;
}
/*
* XXX: Calling routine prepare_ring() called in place of
* prepare_trasfer() as there in 'Linux' since we are not
* maintaining multiple TDs/transfer at the same time.
*/
ret = prepare_ring(ctrl, ring,
le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK);
if (ret < 0)
return ret;
/*
* Don't give the first TRB to the hardware (by toggling the cycle bit)
* until we've finished creating all the other TRBs. The ring's cycle
* state may change as we enqueue the other TRBs, so save it too.
*/
start_trb = &ring->enqueue->generic;
start_cycle = ring->cycle_state;
running_total = 0;
maxpacketsize = usb_maxpacket(udev, pipe);
total_packet_count = DIV_ROUND_UP(length, maxpacketsize);
/* How much data is in the first TRB? */
/*
* How much data is (potentially) left before the 64KB boundary?
* XHCI Spec puts restriction( TABLE 49 and 6.4.1 section of XHCI Spec)
* that the buffer should not span 64KB boundary. if so
* we send request in more than 1 TRB by chaining them.
*/
addr = val_64;
if (trb_buff_len > length)
trb_buff_len = length;
first_trb = true;
/* flush the buffer before use */
xhci_flush_cache((uint32_t)buffer, length);
/* Queue the first TRB, even if it's zero-length */
do {
u32 remainder = 0;
field = 0;
/* Don't change the cycle bit of the first TRB until later */
if (first_trb) {
first_trb = false;
if (start_cycle == 0)
field |= TRB_CYCLE;
} else {
field |= ring->cycle_state;
}
/*
* Chain all the TRBs together; clear the chain bit in the last
* TRB to indicate it's the last TRB in the chain.
*/
if (num_trbs > 1)
field |= TRB_CHAIN;
else
field |= TRB_IOC;
/* Only set interrupt on short packet for IN endpoints */
if (usb_pipein(pipe))
field |= TRB_ISP;
/* Set the TRB length, TD size, and interrupter fields. */
if (HC_VERSION(xhci_readl(&ctrl->hccr->cr_capbase)) < 0x100)
remainder = xhci_td_remainder(length - running_total);
else
remainder = xhci_v1_0_td_remainder(running_total,
trb_buff_len,
total_packet_count,
maxpacketsize,
num_trbs - 1);
length_field = ((trb_buff_len & TRB_LEN_MASK) |
remainder |
((0 & TRB_INTR_TARGET_MASK) <<
TRB_INTR_TARGET_SHIFT));
trb_fields[0] = lower_32_bits(addr);
trb_fields[1] = upper_32_bits(addr);
trb_fields[2] = length_field;
trb_fields[3] = field | (TRB_NORMAL << TRB_TYPE_SHIFT);
queue_trb(ctrl, ring, (num_trbs > 1), trb_fields);
--num_trbs;
running_total += trb_buff_len;
/* Calculate length for next transfer */
addr += trb_buff_len;
trb_buff_len = min((length - running_total), TRB_MAX_BUFF_SIZE);
} while (running_total < length);
giveback_first_trb(udev, ep_index, start_cycle, start_trb);
event = xhci_wait_for_event(ctrl, TRB_TRANSFER);
if (!event) {
debug("XHCI bulk transfer timed out, aborting...\n");
abort_td(udev, ep_index);
udev->status = USB_ST_NAK_REC; /* closest thing to a timeout */
udev->act_len = 0;
return -ETIMEDOUT;
}
field = le32_to_cpu(event->trans_event.flags);
BUG_ON(TRB_TO_SLOT_ID(field) != slot_id);
BUG_ON(TRB_TO_EP_INDEX(field) != ep_index);
BUG_ON(*(void **)(uintptr_t)le64_to_cpu(event->trans_event.buffer) -
buffer > (size_t)length);
record_transfer_result(udev, event, length);
xhci_acknowledge_event(ctrl);
xhci_inval_cache((uint32_t)buffer, length);
return (udev->status != USB_ST_NOT_PROC) ? 0 : -1;
}
/**
* Queues up the Control Transfer Request
*
* @param udev pointer to the USB device structure
* @param pipe contains the DIR_IN or OUT , devnum
* @param req request type
* @param length length of the buffer
* @param buffer buffer to be read/written based on the request
* @return returns 0 if successful else error code on failure
*/
int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
struct devrequest *req, int length,
void *buffer)
{
int ret;
int start_cycle;
int num_trbs;
u32 field;
u32 length_field;
u64 buf_64 = 0;
struct xhci_generic_trb *start_trb;
struct xhci_ctrl *ctrl = udev->controller;
int slot_id = udev->slot_id;
int ep_index;
u32 trb_fields[4];
struct xhci_virt_device *virt_dev = ctrl->devs[slot_id];
struct xhci_ring *ep_ring;
union xhci_trb *event;
debug("req=%u (%#x), type=%u (%#x), value=%u (%#x), index=%u\n",
req->request, req->request,
req->requesttype, req->requesttype,
le16_to_cpu(req->value), le16_to_cpu(req->value),
le16_to_cpu(req->index));
ep_index = usb_pipe_ep_index(pipe);
ep_ring = virt_dev->eps[ep_index].ring;
/*
* Check to see if the max packet size for the default control
* endpoint changed during FS device enumeration
*/
if (udev->speed == USB_SPEED_FULL) {
ret = xhci_check_maxpacket(udev);
if (ret < 0)
return ret;
}
xhci_inval_cache((uint32_t)virt_dev->out_ctx->bytes,
virt_dev->out_ctx->size);
struct xhci_ep_ctx *ep_ctx = NULL;
ep_ctx = xhci_get_ep_ctx(ctrl, virt_dev->out_ctx, ep_index);
/* 1 TRB for setup, 1 for status */
num_trbs = 2;
/*
* Don't need to check if we need additional event data and normal TRBs,
* since data in control transfers will never get bigger than 16MB
* XXX: can we get a buffer that crosses 64KB boundaries?
*/
if (length > 0)
num_trbs++;
/*
* XXX: Calling routine prepare_ring() called in place of
* prepare_trasfer() as there in 'Linux' since we are not
* maintaining multiple TDs/transfer at the same time.
*/
ret = prepare_ring(ctrl, ep_ring,
le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK);
if (ret < 0)
return ret;
/*
* Don't give the first TRB to the hardware (by toggling the cycle bit)
* until we've finished creating all the other TRBs. The ring's cycle
* state may change as we enqueue the other TRBs, so save it too.
*/
start_trb = &ep_ring->enqueue->generic;
start_cycle = ep_ring->cycle_state;
debug("start_trb %p, start_cycle %d\n", start_trb, start_cycle);
/* Queue setup TRB - see section 6.4.1.2.1 */
/* FIXME better way to translate setup_packet into two u32 fields? */
field = 0;
field |= TRB_IDT | (TRB_SETUP << TRB_TYPE_SHIFT);
if (start_cycle == 0)
field |= 0x1;
/* xHCI 1.0 6.4.1.2.1: Transfer Type field */
if (HC_VERSION(xhci_readl(&ctrl->hccr->cr_capbase)) == 0x100) {
if (length > 0) {
if (req->requesttype & USB_DIR_IN)
field |= (TRB_DATA_IN << TRB_TX_TYPE_SHIFT);
else
field |= (TRB_DATA_OUT << TRB_TX_TYPE_SHIFT);
}
}
debug("req->requesttype = %d, req->request = %d,"
"le16_to_cpu(req->value) = %d,"
"le16_to_cpu(req->index) = %d,"
"le16_to_cpu(req->length) = %d\n",
req->requesttype, req->request, le16_to_cpu(req->value),
le16_to_cpu(req->index), le16_to_cpu(req->length));
trb_fields[0] = req->requesttype | req->request << 8 |
le16_to_cpu(req->value) << 16;
trb_fields[1] = le16_to_cpu(req->index) |
le16_to_cpu(req->length) << 16;
/* TRB_LEN | (TRB_INTR_TARGET) */
trb_fields[2] = (8 | ((0 & TRB_INTR_TARGET_MASK) <<
TRB_INTR_TARGET_SHIFT));
/* Immediate data in pointer */
trb_fields[3] = field;
queue_trb(ctrl, ep_ring, true, trb_fields);
/* Re-initializing field to zero */
field = 0;
/* If there's data, queue data TRBs */
/* Only set interrupt on short packet for IN endpoints */
if (usb_pipein(pipe))
field = TRB_ISP | (TRB_DATA << TRB_TYPE_SHIFT);
else
field = (TRB_DATA << TRB_TYPE_SHIFT);
length_field = (length & TRB_LEN_MASK) | xhci_td_remainder(length) |
((0 & TRB_INTR_TARGET_MASK) << TRB_INTR_TARGET_SHIFT);
debug("length_field = %d, length = %d,"
"xhci_td_remainder(length) = %d , TRB_INTR_TARGET(0) = %d\n",
length_field, (length & TRB_LEN_MASK),
xhci_td_remainder(length), 0);
if (length > 0) {
if (req->requesttype & USB_DIR_IN)
field |= TRB_DIR_IN;
buf_64 = (uintptr_t)buffer;
trb_fields[0] = lower_32_bits(buf_64);
trb_fields[1] = upper_32_bits(buf_64);
trb_fields[2] = length_field;
trb_fields[3] = field | ep_ring->cycle_state;
xhci_flush_cache((uint32_t)buffer, length);
queue_trb(ctrl, ep_ring, true, trb_fields);
}
/*
* Queue status TRB -
* see Table 7 and sections 4.11.2.2 and 6.4.1.2.3
*/
/* If the device sent data, the status stage is an OUT transfer */
field = 0;
if (length > 0 && req->requesttype & USB_DIR_IN)
field = 0;
else
field = TRB_DIR_IN;
trb_fields[0] = 0;
trb_fields[1] = 0;
trb_fields[2] = ((0 & TRB_INTR_TARGET_MASK) << TRB_INTR_TARGET_SHIFT);
/* Event on completion */
trb_fields[3] = field | TRB_IOC |
(TRB_STATUS << TRB_TYPE_SHIFT) |
ep_ring->cycle_state;
queue_trb(ctrl, ep_ring, false, trb_fields);
giveback_first_trb(udev, ep_index, start_cycle, start_trb);
event = xhci_wait_for_event(ctrl, TRB_TRANSFER);
if (!event)
goto abort;
field = le32_to_cpu(event->trans_event.flags);
BUG_ON(TRB_TO_SLOT_ID(field) != slot_id);
BUG_ON(TRB_TO_EP_INDEX(field) != ep_index);
record_transfer_result(udev, event, length);
xhci_acknowledge_event(ctrl);
/* Invalidate buffer to make it available to usb-core */
if (length > 0)
xhci_inval_cache((uint32_t)buffer, length);
if (GET_COMP_CODE(le32_to_cpu(event->trans_event.transfer_len))
== COMP_SHORT_TX) {
/* Short data stage, clear up additional status stage event */
event = xhci_wait_for_event(ctrl, TRB_TRANSFER);
if (!event)
goto abort;
BUG_ON(TRB_TO_SLOT_ID(field) != slot_id);
BUG_ON(TRB_TO_EP_INDEX(field) != ep_index);
xhci_acknowledge_event(ctrl);
}
return (udev->status != USB_ST_NOT_PROC) ? 0 : -1;
abort:
debug("XHCI control transfer timed out, aborting...\n");
abort_td(udev, ep_index);
udev->status = USB_ST_NAK_REC;
udev->act_len = 0;
return -ETIMEDOUT;
}

1030
drivers/usb/host/xhci.c Normal file

File diff suppressed because it is too large Load Diff

1255
drivers/usb/host/xhci.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -112,7 +112,7 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe,
return submit_urb(&hcd, urb);
}
int usb_lowlevel_init(int index, void **controller)
int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
{
u8 power;
void *mbase;

View File

@ -1089,7 +1089,7 @@ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
/*
* This function initializes the usb controller module.
*/
int usb_lowlevel_init(int index, void **controller)
int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
{
u8 power;
u32 timeout;

Some files were not shown because too many files have changed in this diff Show More