
On 09/26/12 00:35, Lucas Stach wrote:
This adds the required code to set up a ULPI USB port. It is mostly a port of the Linux ULPI setup code with some tweaks added for more correctness, discovered along the way of debugging this.
To use this both CONFIG_USB_ULPI and CONFIG_USB_ULPI_VIEWPORT have to be set in the board configuration file.
v2:
- move all controller init stuff in the respective functions to make them self contained
- let board define ULPI_REF_CLK to account for the possibility that some ULPI phys need a other ref clk than 24MHz
- don't touch ULPI regs directly, use ULPI framework functions
- don't hide error messages under debug()
v3:
- apply last comments from Igor, which make code still a bit cleaner
- add description of CONFIG_ULPI_REF_CLK to README
I think the above (change history) belongs under the scissors line ('---').
Signed-off-by: Lucas Stach dev@lynxeye.de
Apart from some (this time really) minor comments above and below: Acked-by: Igor Grinberg grinberg@compulab.co.il
README | 3 + arch/arm/cpu/armv7/tegra20/usb.c | 152 +++++++++++++++++++++++++++----- arch/arm/include/asm/arch-tegra20/usb.h | 29 ++++-- 3 Dateien geändert, 157 Zeilen hinzugefügt(+), 27 Zeilen entfernt(-)
diff --git a/README b/README index 4428205..3919143 100644 --- a/README +++ b/README @@ -1239,6 +1239,9 @@ The following options need to be configured: viewport is supported. To enable the ULPI layer support, define CONFIG_USB_ULPI and CONFIG_USB_ULPI_VIEWPORT in your board configuration file.
If your ULPI phy needs a different reference clock than the
standard 24 MHz then you have to define CONFIG_ULPI_REF_CLK to
the appropiate value in Hz.
s/appropiate/appropriate/
- MMC Support: The MMC controller on the Intel PXA is supported. To
diff --git a/arch/arm/cpu/armv7/tegra20/usb.c b/arch/arm/cpu/armv7/tegra20/usb.c index cac0918..86e52f6 100644 --- a/arch/arm/cpu/armv7/tegra20/usb.c +++ b/arch/arm/cpu/armv7/tegra20/usb.c @@ -32,9 +32,17 @@ #include <asm/arch/sys_proto.h> #include <asm/arch/uart.h> #include <asm/arch/usb.h> +#include <usb/ulpi.h> #include <libfdt.h> #include <fdtdec.h>
+#ifdef CONFIG_USB_ULPI
- #ifndef CONFIG_USB_ULPI_VIEWPORT
- #error "To use CONFIG_USB_ULPI on Tegra Boards you have to also \
define CONFIG_USB_ULPI_VIEWPORT"
- #endif
+#endif
enum { USB_PORTS_MAX = 4, /* Maximum ports we allow */ }; @@ -68,11 +76,13 @@ enum dr_mode { struct fdt_usb { struct usb_ctlr *reg; /* address of registers in physical memory */ unsigned utmi:1; /* 1 if port has external tranceiver, else 0 */
- unsigned ulpi:1; /* 1 if port has external ULPI transceiver */ unsigned enabled:1; /* 1 to enable, 0 to disable */ unsigned has_legacy_mode:1; /* 1 if this port has legacy mode */ enum dr_mode dr_mode; /* dual role mode */ enum periph_id periph_id;/* peripheral id */ struct fdt_gpio_state vbus_gpio; /* GPIO for vbus enable */
- struct fdt_gpio_state phy_reset_gpio; /* GPIO to reset ULPI phy */
};
static struct fdt_usb port[USB_PORTS_MAX]; /* List of valid USB ports */ @@ -188,8 +198,8 @@ void usbf_reset_controller(struct fdt_usb *config, struct usb_ctlr *usbctlr) */ }
-/* set up the USB controller with the parameters provided */ -static int init_usb_controller(struct fdt_usb *config, +/* set up the UTMI USB controller with the parameters provided */ +static int init_utmi_usb_controller(struct fdt_usb *config, struct usb_ctlr *usbctlr, const u32 timing[]) { u32 val; @@ -298,17 +308,114 @@ static int init_usb_controller(struct fdt_usb *config, if (!loop_count) return -1;
- return 0;
-}
- /* Disable ICUSB FS/LS transceiver */
- clrbits_le32(&usbctlr->icusb_ctrl, IC_ENB1);
- /* Select UTMI parallel interface */
- clrsetbits_le32(&usbctlr->port_sc1, PTS_MASK,
PTS_UTMI << PTS_SHIFT);
- clrbits_le32(&usbctlr->port_sc1, STS);
-static void power_up_port(struct usb_ctlr *usbctlr) -{ /* Deassert power down state */ clrbits_le32(&usbctlr->utmip_xcvr_cfg0, UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN | UTMIP_FORCE_PDZI_POWERDOWN); clrbits_le32(&usbctlr->utmip_xcvr_cfg1, UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN | UTMIP_FORCE_PDDR_POWERDOWN);
- return 0;
+}
an empty line here would be nice.
+#ifdef CONFIG_USB_ULPI +/* if board file does not set a ULPI reference frequency we default to 24MHz */ +#ifndef CONFIG_ULPI_REF_CLK +#define CONFIG_ULPI_REF_CLK 24000000 +#endif
+/* set up the ULPI USB controller with the parameters provided */ +static int init_ulpi_usb_controller(struct fdt_usb *config,
struct usb_ctlr *usbctlr)
+{
- u32 val;
- int loop_count;
- struct ulpi_viewport ulpi_vp;
- /* set up ULPI reference clock on pllp_out4 */
- clock_enable(PERIPH_ID_DEV2_OUT);
- clock_set_pllout(CLOCK_ID_PERIPH, PLL_OUT4, CONFIG_ULPI_REF_CLK);
- /* reset ULPI phy */
- if (fdt_gpio_isvalid(&config->phy_reset_gpio)) {
fdtdec_setup_gpio(&config->phy_reset_gpio);
gpio_direction_output(config->phy_reset_gpio.gpio, 0);
mdelay(5);
gpio_set_value(config->phy_reset_gpio.gpio, 1);
- }
- /* Reset the usb controller */
- clock_enable(config->periph_id);
- usbf_reset_controller(config, usbctlr);
- /* enable pinmux bypass */
- setbits_le32(&usbctlr->ulpi_timing_ctrl_0,
ULPI_CLKOUT_PINMUX_BYP | ULPI_OUTPUT_PINMUX_BYP);
- /* Select ULPI parallel interface */
- clrsetbits_le32(&usbctlr->port_sc1, PTS_MASK, PTS_ULPI << PTS_SHIFT);
- /* enable ULPI transceiver */
- setbits_le32(&usbctlr->susp_ctrl, ULPI_PHY_ENB);
- /* configure ULPI transceiver timings */
- val = 0;
- writel(val, &usbctlr->ulpi_timing_ctrl_1);
- val |= ULPI_DATA_TRIMMER_SEL(4);
- val |= ULPI_STPDIRNXT_TRIMMER_SEL(4);
- val |= ULPI_DIR_TRIMMER_SEL(4);
- writel(val, &usbctlr->ulpi_timing_ctrl_1);
- udelay(10);
- val |= ULPI_DATA_TRIMMER_LOAD;
- val |= ULPI_STPDIRNXT_TRIMMER_LOAD;
- val |= ULPI_DIR_TRIMMER_LOAD;
- writel(val, &usbctlr->ulpi_timing_ctrl_1);
- /* set up phy for host operation with external vbus supply */
- ulpi_vp.port_num = 0;
- ulpi_vp.viewport_addr = (u32)&usbctlr->ulpi_viewport;
- if (ulpi_init(&ulpi_vp)) {
printf("Tegra ULPI viewport init failed\n");
return -1;
- }
- ulpi_set_vbus(&ulpi_vp, 1, 1);
- ulpi_set_vbus_indicator(&ulpi_vp, 1, 1, 0);
- /* enable wakeup events */
- setbits_le32(&usbctlr->port_sc1, WKCN | WKDS | WKOC);
- /* Enable and wait for the phy clock to become valid in 100 ms */
- setbits_le32(&usbctlr->susp_ctrl, USB_SUSP_CLR);
- for (loop_count = 100000; loop_count != 0; loop_count--) {
if (readl(&usbctlr->susp_ctrl) & USB_PHY_CLK_VALID)
break;
udelay(1);
- }
- if (!loop_count)
return -1;
- clrbits_le32(&usbctlr->susp_ctrl, USB_SUSP_CLR);
- return 0;
} +#else +static int init_ulpi_usb_controller(struct fdt_usb *config,
struct usb_ctlr *usbctlr)
+{
- printf("No code to set up ULPI controller, please enable"
"CONFIG_USB_ULPI and CONFIG_USB_ULPI_VIEWPORT");
- return -1;
+} +#endif
static void config_clock(const u32 timing[]) { @@ -328,24 +435,21 @@ static int add_port(struct fdt_usb *config, const u32 timing[]) struct usb_ctlr *usbctlr = config->reg;
if (port_count == USB_PORTS_MAX) {
debug("tegrausb: Cannot register more than %d ports\n",
return -1; }printf("tegrausb: Cannot register more than %d ports\n", USB_PORTS_MAX);
- if (init_usb_controller(config, usbctlr, timing)) {
debug("tegrausb: Cannot init port\n");
- if (config->utmi && init_utmi_usb_controller(config, usbctlr, timing)) {
return -1; }printf("tegrausb: Cannot init port\n");
- if (config->utmi) {
/* Disable ICUSB FS/LS transceiver */
clrbits_le32(&usbctlr->icusb_ctrl, IC_ENB1);
/* Select UTMI parallel interface */
clrsetbits_le32(&usbctlr->port_sc1, PTS_MASK,
PTS_UTMI << PTS_SHIFT);
clrbits_le32(&usbctlr->port_sc1, STS);
power_up_port(usbctlr);
if (config->ulpi && init_ulpi_usb_controller(config, usbctlr)) {
printf("tegrausb: Cannot init port\n");
return -1;
}
port[port_count++] = *config;
return 0;
@@ -412,6 +516,7 @@ int fdt_decode_usb(const void *blob, int node, unsigned osc_frequency_mhz,
phy = fdt_getprop(blob, node, "phy_type", NULL); config->utmi = phy && 0 == strcmp("utmi", phy);
- config->ulpi = phy && 0 == strcmp("ulpi", phy); config->enabled = fdtdec_get_is_enabled(blob, node); config->has_legacy_mode = fdtdec_get_bool(blob, node, "nvidia,has-legacy-mode");
@@ -421,10 +526,13 @@ int fdt_decode_usb(const void *blob, int node, unsigned osc_frequency_mhz, return -FDT_ERR_NOTFOUND; } fdtdec_decode_gpio(blob, node, "nvidia,vbus-gpio", &config->vbus_gpio);
- debug("enabled=%d, legacy_mode=%d, utmi=%d, periph_id=%d, vbus=%d, "
"dr_mode=%d\n", config->enabled, config->has_legacy_mode,
config->utmi, config->periph_id, config->vbus_gpio.gpio,
config->dr_mode);
fdtdec_decode_gpio(blob, node, "nvidia,phy-reset-gpio",
&config->phy_reset_gpio);
debug("enabled=%d, legacy_mode=%d, utmi=%d, ulpi=%d, periph_id=%d, "
"vbus=%d, phy_reset=%d, dr_mode=%d\n",
config->enabled, config->has_legacy_mode, config->utmi,
config->ulpi, config->periph_id, config->vbus_gpio.gpio,
config->phy_reset_gpio.gpio, config->dr_mode);
return 0;
} diff --git a/arch/arm/include/asm/arch-tegra20/usb.h b/arch/arm/include/asm/arch-tegra20/usb.h index 638033b..bd89d66 100644 --- a/arch/arm/include/asm/arch-tegra20/usb.h +++ b/arch/arm/include/asm/arch-tegra20/usb.h @@ -100,10 +100,12 @@ struct usb_ctlr {
/* 0x410 */ uint usb1_legacy_ctrl;
- uint reserved12[3];
- uint reserved12[4];
- /* 0x420 */
- uint reserved13[56];
/* 0x424 */
uint ulpi_timing_ctrl_0;
uint ulpi_timing_ctrl_1;
uint reserved13[53];
/* 0x500 */ uint reserved14[64 * 3];
@@ -144,10 +146,24 @@ struct usb_ctlr { #define VBUS_SENSE_CTL_AB_SESS_VLD 2 #define VBUS_SENSE_CTL_A_SESS_VLD 3
+/* USB2_IF_ULPI_TIMING_CTRL_0 */ +#define ULPI_OUTPUT_PINMUX_BYP (1 << 10) +#define ULPI_CLKOUT_PINMUX_BYP (1 << 11)
+/* USB2_IF_ULPI_TIMING_CTRL_1 */ +#define ULPI_DATA_TRIMMER_LOAD (1 << 0) +#define ULPI_DATA_TRIMMER_SEL(x) (((x) & 0x7) << 1) +#define ULPI_STPDIRNXT_TRIMMER_LOAD (1 << 16) +#define ULPI_STPDIRNXT_TRIMMER_SEL(x) (((x) & 0x7) << 17) +#define ULPI_DIR_TRIMMER_LOAD (1 << 24) +#define ULPI_DIR_TRIMMER_SEL(x) (((x) & 0x7) << 25)
/* USBx_IF_USB_SUSP_CTRL_0 */ +#define ULPI_PHY_ENB (1 << 13) #define UTMIP_PHY_ENB (1 << 12) #define UTMIP_RESET (1 << 11) #define USB_PHY_CLK_VALID (1 << 7) +#define USB_SUSP_CLR (1 << 5)
/* USBx_UTMIP_MISC_CFG1 */ #define UTMIP_PLLU_STABLE_COUNT_SHIFT 6 @@ -203,12 +219,15 @@ struct usb_ctlr { /* SB2_CONTROLLER_2_USB2D_PORTSC1_0 */ #define PTS_SHIFT 30 #define PTS_MASK (3U << PTS_SHIFT) -#define PTS_UTMI 0 +#define PTS_UTMI 0 #define PTS_RESERVED 1 -#define PTS_ULP 2 +#define PTS_ULPI 2 #define PTS_ICUSB_SER 3
#define STS (1 << 29) +#define WKOC (1 << 22) +#define WKDS (1 << 21) +#define WKCN (1 << 20)
/* USBx_UTMIP_XCVR_CFG0_0 */ #define UTMIP_FORCE_PD_POWERDOWN (1 << 14)