Tegra 2 USB ULPI series
Subsystems (3)
v3 cover Tegra 2 USB ULPI series
Hopefully final round of the Tegra ULPI patchset. This is just the USB part that can go in through the u-boot-usb tree.
This was again tested on the Toradex Colibri T20, without any regressions.
v2 of the patches were Tested-by: Stephen Warren <[email protected]>
v3 incorporates Igors feedback.
Lucas Stach (2):
usb: ulpi: add indicator configuration function
tegra20: add USB ULPI init code
README | 3 + arch/arm/cpu/armv7/tegra20/usb.c | 152 +++++++++++++++++++++++++++----- arch/arm/include/asm/arch-tegra20/usb.h | 29 ++++-- drivers/usb/ulpi/ulpi.c | 32 ++++++- include/usb/ulpi.h | 13 ++-
5 Dateien ge?ndert, 196 Zeilen hinzugef?gt(+), 33 Zeilen entfernt(-)
Signature · 1 line
1.7.11.4
PATCH v3 1/2 usb: ulpi: add indicator configuration function
Allows for easy configuration of the VBUS indicator related ULPI config bits.
Also move the external indicator setup from ulpi_set_vbus() to the new function.
---
v3: Only touch each register once. Now checkpatch clean.
--- drivers/usb/ulpi/ulpi.c | 32 ++++++++++++++++++++++++++++---- include/usb/ulpi.h | 13 +++++++++++--
2 Dateien ge?ndert, 39 Zeilen hinzugef?gt(+), 6 Zeilen entfernt(-)
drivers/usb/ulpi/ulpi.c +28 -4
@@ -106,20 +106,44 @@ int ulpi_select_transceiver(struct ulpi_viewport *ulpi_vp, unsigned speed)return ulpi_write (ulpi_vp, &ulpi->function_ctrl, val); } -int ulpi_set_vbus (struct ulpi_viewport *ulpi_vp,int on,int ext_power, -int ext_ind) +int ulpi_set_vbus (struct ulpi_viewport *ulpi_vp,int on,int ext_power) {u32 flags =ULPI_OTG_DRVVBUS ;u8 *reg = on ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;if (ext_power) flags |=ULPI_OTG_DRVVBUS_EXT ; -if (ext_ind) - flags |=ULPI_OTG_EXTVBUSIND ;return ulpi_write (ulpi_vp, reg, flags); } +int ulpi_set_vbus_indicator (struct ulpi_viewport *ulpi_vp,int external, +int passthu,int complement) +{ +u32 flags; +int ret; + + ret =ulpi_write (ulpi_vp, + external ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear, +ULPI_OTG_EXTVBUSIND ); +if (ret) +return ret; + + flags = passthu ?ULPI_IFACE_PASSTHRU :0 ; + flags |= complement ?ULPI_IFACE_EXTVBUS_COMPLEMENT :0 ; + ret =ulpi_write (ulpi_vp, &ulpi->iface_ctrl_set, flags); +if (ret) +return ret; + + flags = passthu ?0 :ULPI_IFACE_PASSTHRU ; + flags |= complement ?0 :ULPI_IFACE_EXTVBUS_COMPLEMENT ; + ret =ulpi_write (ulpi_vp, &ulpi->iface_ctrl_clear, flags); +if (ret) +return ret; + +return 0 ; +} +int ulpi_set_pd (struct ulpi_viewport *ulpi_vp,int enable) {u32 val =ULPI_OTG_DP_PULLDOWN |ULPI_OTG_DM_PULLDOWN ;
include/usb/ulpi.h +11 -2
@@ -61,8 +61,17 @@ int ulpi_select_transceiver(struct ulpi_viewport *ulpi_vp, unsigned speed);* * returns 0 on success, ULPI_ERROR on failure. */ -int ulpi_set_vbus (struct ulpi_viewport *ulpi_vp, -int on,int ext_power,int ext_ind); +int ulpi_set_vbus (struct ulpi_viewport *ulpi_vp,int on,int ext_power); + +/* +* Configure VBUS indicator +* @external - external VBUS over-current indicator is used +* @passthru - disables ANDing of internal VBUS comparator +* with external VBUS input +* @complement - inverts the external VBUS input +*/ +int ulpi_set_vbus_indicator (struct ulpi_viewport *ulpi_vp,int external, +int passthru,int complement);/* * Enable/disable pull-down resistors on D+ and D- USB lines.
Signature · 1 line
1.7.11.4
PATCH v3 1/2 usb: ulpi: add indicator configuration function
Quoted 37 lines · Lucas Stach
Allows for easy configuration of the VBUS indicator related ULPI config bits.
Also move the external indicator setup from
ulpi_set_vbus()to the new function.Signed-off-by Lucas Stach <[email protected]>Acked-by Igor Grinberg <[email protected]>---
v3: Only touch each register once. Now checkpatch clean.--- drivers/usb/ulpi/ulpi.c | 32 ++++++++++++++++++++++++++++---- include/usb/ulpi.h | 13 +++++++++++--2 Dateien ge?ndert, 39 Zeilen hinzugef?gt(+), 6 Zeilen entfernt(-)
drivers/usb/ulpi/ulpi.c +1
-4@@ -106,20 +106,44 @@ int ulpi_select_transceiver(struct ulpi_viewport *ulpi_vp, unsigned speed)return ulpi_write (ulpi_vp, &ulpi->function_ctrl, val); } -int ulpi_set_vbus (struct ulpi_viewport *ulpi_vp,int on,int ext_power, -int ext_ind) +int ulpi_set_vbus (struct ulpi_viewport *ulpi_vp,int on,int ext_power) {u32 flags =ULPI_OTG_DRVVBUS ;u8 *reg = on ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;if (ext_power) flags |=ULPI_OTG_DRVVBUS_EXT ; -if (ext_ind) - flags |=ULPI_OTG_EXTVBUSIND ;return ulpi_write (ulpi_vp, reg, flags); }
drivers/usb/ulpi/ulpi.c int ulpi_select_transceiver(struct ulpi_viewport *ulpi_vp, unsigned speed) · line 128
Quoted 10 lines
drivers/usb/ulpi/ulpi.c +9
-0+int ulpi_set_vbus_indicator (struct ulpi_viewport *ulpi_vp,int external, +int passthu,int complement) +{ +u32 flags; +int ret; + + ret =ulpi_write (ulpi_vp, + external ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear, +ULPI_OTG_EXTVBUSIND );
I think the below would be clearer and also will look as the rest of the file does:
reg = external ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear; ret = ulpi_write(ulpi_vp, reg, ULPI_OTG_EXTVBUSIND);
drivers/usb/ulpi/ulpi.c int ulpi_select_transceiver(struct ulpi_viewport *ulpi_vp, unsigned speed) · line 140
Quoted 12 lines
drivers/usb/ulpi/ulpi.c +12
-0+if (ret) +return ret; + + flags = passthu ?ULPI_IFACE_PASSTHRU :0 ; + flags |= complement ?ULPI_IFACE_EXTVBUS_COMPLEMENT :0 ; + ret =ulpi_write (ulpi_vp, &ulpi->iface_ctrl_set, flags); +if (ret) +return ret; + + flags = passthu ?0 :ULPI_IFACE_PASSTHRU ; + flags |= complement ?0 :ULPI_IFACE_EXTVBUS_COMPLEMENT ; + ret =ulpi_write (ulpi_vp, &ulpi->iface_ctrl_clear, flags);
Errr..., that is not what I meant... sorry for confusion. What I meant is something like:
u32 pthrough = passthu ? ULPI_IFACE_PASSTHRU : 0;
u32 extcompl |= complement ? ULPI_IFACE_EXTVBUS_COMPLEMENT : 0;
val = ulpi_read(ulpi_vp, &ulpi->iface_ctrl);
if (val == ULPI_ERROR)
return val;
val = (val & ~ULPI_IFACE_PASSTHRU) | pthrough; val = (val & ~ULPI_IFACE_EXTVBUS_COMPLEMENT) | extcompl; ret = ulpi_write(ulpi_vp, &ulpi->iface_ctrl, val);
That way you write only once to each register and the code also look uniform.
Quoted 33 lines
drivers/usb/ulpi/ulpi.c +6
-0+if (ret) +return ret; + +return 0 ; +} +int ulpi_set_pd (struct ulpi_viewport *ulpi_vp,int enable) {u32 val =ULPI_OTG_DP_PULLDOWN |ULPI_OTG_DM_PULLDOWN ;include/usb/ulpi.h +11
-2@@ -61,8 +61,17 @@ int ulpi_select_transceiver(struct ulpi_viewport *ulpi_vp, unsigned speed);* * returns 0 on success, ULPI_ERROR on failure. */ -int ulpi_set_vbus (struct ulpi_viewport *ulpi_vp, -int on,int ext_power,int ext_ind); +int ulpi_set_vbus (struct ulpi_viewport *ulpi_vp,int on,int ext_power); + +/* +* Configure VBUS indicator +* @external - external VBUS over-current indicator is used +* @passthru - disables ANDing of internal VBUS comparator +* with external VBUS input +* @complement - inverts the external VBUS input +*/ +int ulpi_set_vbus_indicator (struct ulpi_viewport *ulpi_vp,int external, +int passthru,int complement);/* * Enable/disable pull-down resistors on D+ and D- USB lines.
Signature · 2 lines
Regards, Igor.
PATCH v3 1/2 usb: ulpi: add indicator configuration function
Am Freitag, den 28.09.2012, 10:15 +0200 schrieb Igor Grinberg:
Quoted 75 lines · Lucas Stach
Quoted 37 lines
Allows for easy configuration of the VBUS indicator related ULPI config bits.
Also move the external indicator setup from
ulpi_set_vbus()to the new function.Signed-off-by Lucas Stach <[email protected]>Acked-by Igor Grinberg <[email protected]>---
v3: Only touch each register once. Now checkpatch clean.--- drivers/usb/ulpi/ulpi.c | 32 ++++++++++++++++++++++++++++---- include/usb/ulpi.h | 13 +++++++++++--2 Dateien ge?ndert, 39 Zeilen hinzugef?gt(+), 6 Zeilen entfernt(-)
drivers/usb/ulpi/ulpi.c +1
-4@@ -106,20 +106,44 @@ int ulpi_select_transceiver(struct ulpi_viewport *ulpi_vp, unsigned speed)return ulpi_write (ulpi_vp, &ulpi->function_ctrl, val); } -int ulpi_set_vbus (struct ulpi_viewport *ulpi_vp,int on,int ext_power, -int ext_ind) +int ulpi_set_vbus (struct ulpi_viewport *ulpi_vp,int on,int ext_power) {u32 flags =ULPI_OTG_DRVVBUS ;u8 *reg = on ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;if (ext_power) flags |=ULPI_OTG_DRVVBUS_EXT ; -if (ext_ind) - flags |=ULPI_OTG_EXTVBUSIND ;return ulpi_write (ulpi_vp, reg, flags); }drivers/usb/ulpi/ulpi.c int ulpi_select_transceiver(struct ulpi_viewport *ulpi_vp, unsigned speed) · line 128
Quoted 10 lines
drivers/usb/ulpi/ulpi.c +9
-0+int ulpi_set_vbus_indicator (struct ulpi_viewport *ulpi_vp,int external, +int passthu,int complement) +{ +u32 flags; +int ret; + + ret =ulpi_write (ulpi_vp, + external ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear, +ULPI_OTG_EXTVBUSIND );I think the below would be clearer and also will look as the rest of the file does:
reg = external ?
&ulpi->otg_ctrl_set:&ulpi->otg_ctrl_clear; ret =ulpi_write(ulpi_vp, reg, ULPI_OTG_EXTVBUSIND);drivers/usb/ulpi/ulpi.c int ulpi_select_transceiver(struct ulpi_viewport *ulpi_vp, unsigned speed) · line 140
Quoted 12 lines
drivers/usb/ulpi/ulpi.c +12
-0+if (ret) +return ret; + + flags = passthu ?ULPI_IFACE_PASSTHRU :0 ; + flags |= complement ?ULPI_IFACE_EXTVBUS_COMPLEMENT :0 ; + ret =ulpi_write (ulpi_vp, &ulpi->iface_ctrl_set, flags); +if (ret) +return ret; + + flags = passthu ?0 :ULPI_IFACE_PASSTHRU ; + flags |= complement ?0 :ULPI_IFACE_EXTVBUS_COMPLEMENT ; + ret =ulpi_write (ulpi_vp, &ulpi->iface_ctrl_clear, flags);Errr..., that is not what I meant... sorry for confusion. What I meant is something like:
u32 pthrough = passthu ?
ULPI_IFACE_PASSTHRU: 0;
u32 extcompl |= complement ?ULPI_IFACE_EXTVBUS_COMPLEMENT: 0;val =
ulpi_read(ulpi_vp, &ulpi->iface_ctrl);
if (val ==ULPI_ERROR)
Quoted 8 lines
return val;val = (val & ~ULPI_IFACE_PASSTHRU) | pthrough; val = (val & ~ULPI_IFACE_EXTVBUS_COMPLEMENT) | extcompl; ret =
ulpi_write(ulpi_vp, &ulpi->iface_ctrl, val);That way you write only once to each register and the code also look uniform.
I tend to disagree. The ULPI PHY register set was specifically designed to not need this use-modify-write dance. Why would we like to ignore this?
Yes we are possible doing one unneeded register access here, but what would it buy us to ignore the set/clear registers just to avoid one register access?
Quoted 34 lines
Quoted 33 lines
drivers/usb/ulpi/ulpi.c +6
-0+if (ret) +return ret; + +return 0 ; +} +int ulpi_set_pd (struct ulpi_viewport *ulpi_vp,int enable) {u32 val =ULPI_OTG_DP_PULLDOWN |ULPI_OTG_DM_PULLDOWN ;include/usb/ulpi.h +11
-2@@ -61,8 +61,17 @@ int ulpi_select_transceiver(struct ulpi_viewport *ulpi_vp, unsigned speed);* * returns 0 on success, ULPI_ERROR on failure. */ -int ulpi_set_vbus (struct ulpi_viewport *ulpi_vp, -int on,int ext_power,int ext_ind); +int ulpi_set_vbus (struct ulpi_viewport *ulpi_vp,int on,int ext_power); + +/* +* Configure VBUS indicator +* @external - external VBUS over-current indicator is used +* @passthru - disables ANDing of internal VBUS comparator +* with external VBUS input +* @complement - inverts the external VBUS input +*/ +int ulpi_set_vbus_indicator (struct ulpi_viewport *ulpi_vp,int external, +int passthru,int complement);/* * Enable/disable pull-down resistors on D+ and D- USB lines.
PATCH v3 1/2 usb: ulpi: add indicator configuration function
Hi Lucas,
Quoted 16 lines · Lucas Stach
Am Freitag, den 28.09.2012, 10:15 +0200 schrieb Igor Grinberg:
Quoted 15 lines · Lucas Stach
Quoted 14 lines
Allows for easy configuration of the VBUS indicator related ULPI config bits.
Also move the external indicator setup from
ulpi_set_vbus()to the new function.Signed-off-by Lucas Stach <[email protected]>Acked-by Igor Grinberg <[email protected]>---
v3: Only touch each register once. Now checkpatch clean.--- drivers/usb/ulpi/ulpi.c | 32 ++++++++++++++++++++++++++++---- include/usb/ulpi.h | 13 +++++++++++--2 Dateien ge?ndert, 39 Zeilen hinzugef?gt(+), 6 Zeilen entfernt(-)
[...]
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
drivers/usb/ulpi/ulpi.c +0
-0
[...]
Quoted 42 lines
Quoted 42 lines
drivers/usb/ulpi/ulpi.c int ulpi_select_transceiver(struct ulpi_viewport *ulpi_vp, unsigned speed) · line 128
Quoted 9 lines
drivers/usb/ulpi/ulpi.c +9
-0+int ulpi_set_vbus_indicator (struct ulpi_viewport *ulpi_vp,int external, +int passthu,int complement) +{ +u32 flags; +int ret; + + ret =ulpi_write (ulpi_vp, + external ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear, +ULPI_OTG_EXTVBUSIND );I think the below would be clearer and also will look as the rest of the file does:
reg = external ?
&ulpi->otg_ctrl_set:&ulpi->otg_ctrl_clear; ret =ulpi_write(ulpi_vp, reg, ULPI_OTG_EXTVBUSIND);drivers/usb/ulpi/ulpi.c int ulpi_select_transceiver(struct ulpi_viewport *ulpi_vp, unsigned speed) · line 140
Quoted 12 lines
drivers/usb/ulpi/ulpi.c +12
-0+if (ret) +return ret; + + flags = passthu ?ULPI_IFACE_PASSTHRU :0 ; + flags |= complement ?ULPI_IFACE_EXTVBUS_COMPLEMENT :0 ; + ret =ulpi_write (ulpi_vp, &ulpi->iface_ctrl_set, flags); +if (ret) +return ret; + + flags = passthu ?0 :ULPI_IFACE_PASSTHRU ; + flags |= complement ?0 :ULPI_IFACE_EXTVBUS_COMPLEMENT ; + ret =ulpi_write (ulpi_vp, &ulpi->iface_ctrl_clear, flags);Errr..., that is not what I meant... sorry for confusion. What I meant is something like:
u32 pthrough = passthu ?
ULPI_IFACE_PASSTHRU: 0;
u32 extcompl |= complement ?ULPI_IFACE_EXTVBUS_COMPLEMENT: 0;val =
ulpi_read(ulpi_vp, &ulpi->iface_ctrl);
if (val ==ULPI_ERROR)return val;val = (val & ~ULPI_IFACE_PASSTHRU) | pthrough; val = (val & ~ULPI_IFACE_EXTVBUS_COMPLEMENT) | extcompl; ret =
ulpi_write(ulpi_vp, &ulpi->iface_ctrl, val);
Quoted 5 lines
Quoted 2 lines
That way you write only once to each register and the code also look uniform.
I tend to disagree. The ULPI PHY register set was specifically designed to not need this use-modify-write dance. Why would we like to ignore this?
We don't...
I mean, we use this in cases when only one bit needs to be modified. When you need to modify more then one bit (or more precisely >2 bits), it is better be done in r-m-w manner, so you do as few ULPI bus accesses as possible. Each ULPI transaction takes much more time than playing with bits in the function.
Quoted 4 lines
Yes we are possible doing one unneeded register access here, but what would it buy us to ignore the set/clear registers just to avoid one register access?
In this function only two bits are changed, so it is still two transactions on the ULPI bus, but if for some reason, in the future, we will need to change more bits in the same function and register, we will get patches adding more transactions instead of updating the local variable. Also, the ulpi.c is done having this in mind, so for it to be uniform, we'd better do this in the same fashion.
Also, I've understood from your patch, that what you have understood from my comments was not exactly what meant, so I wanted to make my comments clear and open for discussion. It does not meter now, as Marek already applied the new version.
Anyway, thanks for the patches and the effort!
[...]
Signature · 2 lines
Regards, Igor.
PATCH v3 2/2 tegra20: add USB ULPI init code
In reply to Lucas StachThis 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
--- 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(-)
README +3 -0
@@ -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. - MMC Support: The MMC controller on the Intel PXA is supported. To
arch/arm/cpu/armv7/tegra20/usb.c +130 -22
215 lines not on this page · raw message
arch/arm/include/asm/arch-tegra20/usb.h +24 -5
@@ -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)
Signature · 1 line
1.7.11.4
PATCH v3 2/2 tegra20: add USB ULPI init code
Quoted 16 lines · Lucas Stach
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_ULPIandCONFIG_USB_ULPI_VIEWPORThave 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 defineULPI_REF_CLKto 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 underdebug()
Quoted 3 lines
v3:
- apply last comments from Igor, which make code still a bit cleaner
- add description ofCONFIG_ULPI_REF_CLKto README
I think the above (change history) belongs under the scissors line ('---').
Quoted 2 lines
Signed-off-by Lucas Stach <[email protected]>
Apart from some (this time really) minor comments above and below:
Quoted 11 lines
--- 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(-)
README +0
-0
README The following options need to be configured: · line 1244
Quoted 6 lines
README +3
-0@@ -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/
Quoted 64 lines
README +0
-0- MMC Support: The MMC controller on the Intel PXA is supported. Toarch/arm/cpu/armv7/tegra20/usb.c +19
-4@@ -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 );
arch/arm/cpu/armv7/tegra20/usb.c static int init_usb_controller(struct fdt_usb *config, · line 326
Quoted 10 lines
arch/arm/cpu/armv7/tegra20/usb.c +3
-2-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.
Quoted 218 lines
arch/arm/cpu/armv7/tegra20/usb.c +108
-16+#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" , +printf ("tegrausb: Cannot register more than %d ports\n" ,USB_PORTS_MAX );return -1 ; } -if (init_usb_controller (config, usbctlr, timing)) { -debug ("tegrausb: Cannot init port\n" ); + +if (config->utmi &&init_utmi_usb_controller (config, usbctlr, timing)) { +printf ("tegrausb: Cannot init port\n" );return -1 ; } -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 ; }arch/arm/include/asm/arch-tegra20/usb.h +24
-5@@ -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)
Signature · 2 lines
Regards, Igor.