Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
23eca831
Commit
23eca831
authored
Jun 11, 2021
by
Thierry Reding
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for-5.14/phy' into for-5.14/usb
parents
6efb943b
1f9cab6c
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
2127 additions
and
424 deletions
+2127
-424
drivers/phy/tegra/xusb-tegra186.c
drivers/phy/tegra/xusb-tegra186.c
+549
-1
drivers/phy/tegra/xusb-tegra210.c
drivers/phy/tegra/xusb-tegra210.c
+1460
-417
drivers/phy/tegra/xusb.c
drivers/phy/tegra/xusb.c
+90
-2
drivers/phy/tegra/xusb.h
drivers/phy/tegra/xusb.h
+19
-3
include/linux/phy/tegra/xusb.h
include/linux/phy/tegra/xusb.h
+9
-1
No files found.
drivers/phy/tegra/xusb-tegra186.c
View file @
23eca831
// SPDX-License-Identifier: GPL-2.0
// SPDX-License-Identifier: GPL-2.0
/*
/*
* Copyright (c) 2016-20
19
, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2016-20
20
, NVIDIA CORPORATION. All rights reserved.
*/
*/
#include <linux/delay.h>
#include <linux/delay.h>
...
@@ -113,6 +113,117 @@
...
@@ -113,6 +113,117 @@
#define ID_OVERRIDE_FLOATING ID_OVERRIDE(8)
#define ID_OVERRIDE_FLOATING ID_OVERRIDE(8)
#define ID_OVERRIDE_GROUNDED ID_OVERRIDE(0)
#define ID_OVERRIDE_GROUNDED ID_OVERRIDE(0)
/* XUSB AO registers */
#define XUSB_AO_USB_DEBOUNCE_DEL (0x4)
#define UHSIC_LINE_DEB_CNT(x) (((x) & 0xf) << 4)
#define UTMIP_LINE_DEB_CNT(x) ((x) & 0xf)
#define XUSB_AO_UTMIP_TRIGGERS(x) (0x40 + (x) * 4)
#define CLR_WALK_PTR BIT(0)
#define CAP_CFG BIT(1)
#define CLR_WAKE_ALARM BIT(3)
#define XUSB_AO_UHSIC_TRIGGERS(x) (0x60 + (x) * 4)
#define HSIC_CLR_WALK_PTR BIT(0)
#define HSIC_CLR_WAKE_ALARM BIT(3)
#define HSIC_CAP_CFG BIT(4)
#define XUSB_AO_UTMIP_SAVED_STATE(x) (0x70 + (x) * 4)
#define SPEED(x) ((x) & 0x3)
#define UTMI_HS SPEED(0)
#define UTMI_FS SPEED(1)
#define UTMI_LS SPEED(2)
#define UTMI_RST SPEED(3)
#define XUSB_AO_UHSIC_SAVED_STATE(x) (0x90 + (x) * 4)
#define MODE(x) ((x) & 0x1)
#define MODE_HS MODE(0)
#define MODE_RST MODE(1)
#define XUSB_AO_UTMIP_SLEEPWALK_CFG(x) (0xd0 + (x) * 4)
#define XUSB_AO_UHSIC_SLEEPWALK_CFG(x) (0xf0 + (x) * 4)
#define FAKE_USBOP_VAL BIT(0)
#define FAKE_USBON_VAL BIT(1)
#define FAKE_USBOP_EN BIT(2)
#define FAKE_USBON_EN BIT(3)
#define FAKE_STROBE_VAL BIT(0)
#define FAKE_DATA_VAL BIT(1)
#define FAKE_STROBE_EN BIT(2)
#define FAKE_DATA_EN BIT(3)
#define WAKE_WALK_EN BIT(14)
#define MASTER_ENABLE BIT(15)
#define LINEVAL_WALK_EN BIT(16)
#define WAKE_VAL(x) (((x) & 0xf) << 17)
#define WAKE_VAL_NONE WAKE_VAL(12)
#define WAKE_VAL_ANY WAKE_VAL(15)
#define WAKE_VAL_DS10 WAKE_VAL(2)
#define LINE_WAKEUP_EN BIT(21)
#define MASTER_CFG_SEL BIT(22)
#define XUSB_AO_UTMIP_SLEEPWALK(x) (0x100 + (x) * 4)
/* phase A */
#define USBOP_RPD_A BIT(0)
#define USBON_RPD_A BIT(1)
#define AP_A BIT(4)
#define AN_A BIT(5)
#define HIGHZ_A BIT(6)
/* phase B */
#define USBOP_RPD_B BIT(8)
#define USBON_RPD_B BIT(9)
#define AP_B BIT(12)
#define AN_B BIT(13)
#define HIGHZ_B BIT(14)
/* phase C */
#define USBOP_RPD_C BIT(16)
#define USBON_RPD_C BIT(17)
#define AP_C BIT(20)
#define AN_C BIT(21)
#define HIGHZ_C BIT(22)
/* phase D */
#define USBOP_RPD_D BIT(24)
#define USBON_RPD_D BIT(25)
#define AP_D BIT(28)
#define AN_D BIT(29)
#define HIGHZ_D BIT(30)
#define XUSB_AO_UHSIC_SLEEPWALK(x) (0x120 + (x) * 4)
/* phase A */
#define RPD_STROBE_A BIT(0)
#define RPD_DATA0_A BIT(1)
#define RPU_STROBE_A BIT(2)
#define RPU_DATA0_A BIT(3)
/* phase B */
#define RPD_STROBE_B BIT(8)
#define RPD_DATA0_B BIT(9)
#define RPU_STROBE_B BIT(10)
#define RPU_DATA0_B BIT(11)
/* phase C */
#define RPD_STROBE_C BIT(16)
#define RPD_DATA0_C BIT(17)
#define RPU_STROBE_C BIT(18)
#define RPU_DATA0_C BIT(19)
/* phase D */
#define RPD_STROBE_D BIT(24)
#define RPD_DATA0_D BIT(25)
#define RPU_STROBE_D BIT(26)
#define RPU_DATA0_D BIT(27)
#define XUSB_AO_UTMIP_PAD_CFG(x) (0x130 + (x) * 4)
#define FSLS_USE_XUSB_AO BIT(3)
#define TRK_CTRL_USE_XUSB_AO BIT(4)
#define RPD_CTRL_USE_XUSB_AO BIT(5)
#define RPU_USE_XUSB_AO BIT(6)
#define VREG_USE_XUSB_AO BIT(7)
#define USBOP_VAL_PD BIT(8)
#define USBON_VAL_PD BIT(9)
#define E_DPD_OVRD_EN BIT(10)
#define E_DPD_OVRD_VAL BIT(11)
#define XUSB_AO_UHSIC_PAD_CFG(x) (0x150 + (x) * 4)
#define STROBE_VAL_PD BIT(0)
#define DATA0_VAL_PD BIT(1)
#define USE_XUSB_AO BIT(4)
#define TEGRA186_LANE(_name, _offset, _shift, _mask, _type) \
#define TEGRA186_LANE(_name, _offset, _shift, _mask, _type) \
{ \
{ \
.name = _name, \
.name = _name, \
...
@@ -130,16 +241,37 @@ struct tegra_xusb_fuse_calibration {
...
@@ -130,16 +241,37 @@ struct tegra_xusb_fuse_calibration {
u32
rpd_ctrl
;
u32
rpd_ctrl
;
};
};
struct
tegra186_xusb_padctl_context
{
u32
vbus_id
;
u32
usb2_pad_mux
;
u32
usb2_port_cap
;
u32
ss_port_cap
;
};
struct
tegra186_xusb_padctl
{
struct
tegra186_xusb_padctl
{
struct
tegra_xusb_padctl
base
;
struct
tegra_xusb_padctl
base
;
void
__iomem
*
ao_regs
;
struct
tegra_xusb_fuse_calibration
calib
;
struct
tegra_xusb_fuse_calibration
calib
;
/* UTMI bias and tracking */
/* UTMI bias and tracking */
struct
clk
*
usb2_trk_clk
;
struct
clk
*
usb2_trk_clk
;
unsigned
int
bias_pad_enable
;
unsigned
int
bias_pad_enable
;
/* padctl context */
struct
tegra186_xusb_padctl_context
context
;
};
};
static
inline
void
ao_writel
(
struct
tegra186_xusb_padctl
*
priv
,
u32
value
,
unsigned
int
offset
)
{
writel
(
value
,
priv
->
ao_regs
+
offset
);
}
static
inline
u32
ao_readl
(
struct
tegra186_xusb_padctl
*
priv
,
unsigned
int
offset
)
{
return
readl
(
priv
->
ao_regs
+
offset
);
}
static
inline
struct
tegra186_xusb_padctl
*
static
inline
struct
tegra186_xusb_padctl
*
to_tegra186_xusb_padctl
(
struct
tegra_xusb_padctl
*
padctl
)
to_tegra186_xusb_padctl
(
struct
tegra_xusb_padctl
*
padctl
)
{
{
...
@@ -180,9 +312,264 @@ static void tegra186_usb2_lane_remove(struct tegra_xusb_lane *lane)
...
@@ -180,9 +312,264 @@ static void tegra186_usb2_lane_remove(struct tegra_xusb_lane *lane)
kfree
(
usb2
);
kfree
(
usb2
);
}
}
static
int
tegra186_utmi_enable_phy_sleepwalk
(
struct
tegra_xusb_lane
*
lane
,
enum
usb_device_speed
speed
)
{
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
struct
tegra186_xusb_padctl
*
priv
=
to_tegra186_xusb_padctl
(
padctl
);
unsigned
int
index
=
lane
->
index
;
u32
value
;
mutex_lock
(
&
padctl
->
lock
);
/* ensure sleepwalk logic is disabled */
value
=
ao_readl
(
priv
,
XUSB_AO_UTMIP_SLEEPWALK_CFG
(
index
));
value
&=
~
MASTER_ENABLE
;
ao_writel
(
priv
,
value
,
XUSB_AO_UTMIP_SLEEPWALK_CFG
(
index
));
/* ensure sleepwalk logics are in low power mode */
value
=
ao_readl
(
priv
,
XUSB_AO_UTMIP_SLEEPWALK_CFG
(
index
));
value
|=
MASTER_CFG_SEL
;
ao_writel
(
priv
,
value
,
XUSB_AO_UTMIP_SLEEPWALK_CFG
(
index
));
/* set debounce time */
value
=
ao_readl
(
priv
,
XUSB_AO_USB_DEBOUNCE_DEL
);
value
&=
~
UTMIP_LINE_DEB_CNT
(
~
0
);
value
|=
UTMIP_LINE_DEB_CNT
(
1
);
ao_writel
(
priv
,
value
,
XUSB_AO_USB_DEBOUNCE_DEL
);
/* ensure fake events of sleepwalk logic are desiabled */
value
=
ao_readl
(
priv
,
XUSB_AO_UTMIP_SLEEPWALK_CFG
(
index
));
value
&=
~
(
FAKE_USBOP_VAL
|
FAKE_USBON_VAL
|
FAKE_USBOP_EN
|
FAKE_USBON_EN
);
ao_writel
(
priv
,
value
,
XUSB_AO_UTMIP_SLEEPWALK_CFG
(
index
));
/* ensure wake events of sleepwalk logic are not latched */
value
=
ao_readl
(
priv
,
XUSB_AO_UTMIP_SLEEPWALK_CFG
(
index
));
value
&=
~
LINE_WAKEUP_EN
;
ao_writel
(
priv
,
value
,
XUSB_AO_UTMIP_SLEEPWALK_CFG
(
index
));
/* disable wake event triggers of sleepwalk logic */
value
=
ao_readl
(
priv
,
XUSB_AO_UTMIP_SLEEPWALK_CFG
(
index
));
value
&=
~
WAKE_VAL
(
~
0
);
value
|=
WAKE_VAL_NONE
;
ao_writel
(
priv
,
value
,
XUSB_AO_UTMIP_SLEEPWALK_CFG
(
index
));
/* power down the line state detectors of the pad */
value
=
ao_readl
(
priv
,
XUSB_AO_UTMIP_PAD_CFG
(
index
));
value
|=
(
USBOP_VAL_PD
|
USBON_VAL_PD
);
ao_writel
(
priv
,
value
,
XUSB_AO_UTMIP_PAD_CFG
(
index
));
/* save state per speed */
value
=
ao_readl
(
priv
,
XUSB_AO_UTMIP_SAVED_STATE
(
index
));
value
&=
~
SPEED
(
~
0
);
switch
(
speed
)
{
case
USB_SPEED_HIGH
:
value
|=
UTMI_HS
;
break
;
case
USB_SPEED_FULL
:
value
|=
UTMI_FS
;
break
;
case
USB_SPEED_LOW
:
value
|=
UTMI_LS
;
break
;
default:
value
|=
UTMI_RST
;
break
;
}
ao_writel
(
priv
,
value
,
XUSB_AO_UTMIP_SAVED_STATE
(
index
));
/* enable the trigger of the sleepwalk logic */
value
=
ao_readl
(
priv
,
XUSB_AO_UTMIP_SLEEPWALK_CFG
(
index
));
value
|=
LINEVAL_WALK_EN
;
value
&=
~
WAKE_WALK_EN
;
ao_writel
(
priv
,
value
,
XUSB_AO_UTMIP_SLEEPWALK_CFG
(
index
));
/* reset the walk pointer and clear the alarm of the sleepwalk logic,
* as well as capture the configuration of the USB2.0 pad
*/
value
=
ao_readl
(
priv
,
XUSB_AO_UTMIP_TRIGGERS
(
index
));
value
|=
(
CLR_WALK_PTR
|
CLR_WAKE_ALARM
|
CAP_CFG
);
ao_writel
(
priv
,
value
,
XUSB_AO_UTMIP_TRIGGERS
(
index
));
/* setup the pull-ups and pull-downs of the signals during the four
* stages of sleepwalk.
* if device is connected, program sleepwalk logic to maintain a J and
* keep driving K upon seeing remote wake.
*/
value
=
USBOP_RPD_A
|
USBOP_RPD_B
|
USBOP_RPD_C
|
USBOP_RPD_D
;
value
|=
USBON_RPD_A
|
USBON_RPD_B
|
USBON_RPD_C
|
USBON_RPD_D
;
switch
(
speed
)
{
case
USB_SPEED_HIGH
:
case
USB_SPEED_FULL
:
/* J state: D+/D- = high/low, K state: D+/D- = low/high */
value
|=
HIGHZ_A
;
value
|=
AP_A
;
value
|=
AN_B
|
AN_C
|
AN_D
;
break
;
case
USB_SPEED_LOW
:
/* J state: D+/D- = low/high, K state: D+/D- = high/low */
value
|=
HIGHZ_A
;
value
|=
AN_A
;
value
|=
AP_B
|
AP_C
|
AP_D
;
break
;
default:
value
|=
HIGHZ_A
|
HIGHZ_B
|
HIGHZ_C
|
HIGHZ_D
;
break
;
}
ao_writel
(
priv
,
value
,
XUSB_AO_UTMIP_SLEEPWALK
(
index
));
/* power up the line state detectors of the pad */
value
=
ao_readl
(
priv
,
XUSB_AO_UTMIP_PAD_CFG
(
index
));
value
&=
~
(
USBOP_VAL_PD
|
USBON_VAL_PD
);
ao_writel
(
priv
,
value
,
XUSB_AO_UTMIP_PAD_CFG
(
index
));
usleep_range
(
150
,
200
);
/* switch the electric control of the USB2.0 pad to XUSB_AO */
value
=
ao_readl
(
priv
,
XUSB_AO_UTMIP_PAD_CFG
(
index
));
value
|=
FSLS_USE_XUSB_AO
|
TRK_CTRL_USE_XUSB_AO
|
RPD_CTRL_USE_XUSB_AO
|
RPU_USE_XUSB_AO
|
VREG_USE_XUSB_AO
;
ao_writel
(
priv
,
value
,
XUSB_AO_UTMIP_PAD_CFG
(
index
));
/* set the wake signaling trigger events */
value
=
ao_readl
(
priv
,
XUSB_AO_UTMIP_SLEEPWALK_CFG
(
index
));
value
&=
~
WAKE_VAL
(
~
0
);
value
|=
WAKE_VAL_ANY
;
ao_writel
(
priv
,
value
,
XUSB_AO_UTMIP_SLEEPWALK_CFG
(
index
));
/* enable the wake detection */
value
=
ao_readl
(
priv
,
XUSB_AO_UTMIP_SLEEPWALK_CFG
(
index
));
value
|=
MASTER_ENABLE
|
LINE_WAKEUP_EN
;
ao_writel
(
priv
,
value
,
XUSB_AO_UTMIP_SLEEPWALK_CFG
(
index
));
mutex_unlock
(
&
padctl
->
lock
);
return
0
;
}
static
int
tegra186_utmi_disable_phy_sleepwalk
(
struct
tegra_xusb_lane
*
lane
)
{
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
struct
tegra186_xusb_padctl
*
priv
=
to_tegra186_xusb_padctl
(
padctl
);
unsigned
int
index
=
lane
->
index
;
u32
value
;
mutex_lock
(
&
padctl
->
lock
);
/* disable the wake detection */
value
=
ao_readl
(
priv
,
XUSB_AO_UTMIP_SLEEPWALK_CFG
(
index
));
value
&=
~
(
MASTER_ENABLE
|
LINE_WAKEUP_EN
);
ao_writel
(
priv
,
value
,
XUSB_AO_UTMIP_SLEEPWALK_CFG
(
index
));
/* switch the electric control of the USB2.0 pad to XUSB vcore logic */
value
=
ao_readl
(
priv
,
XUSB_AO_UTMIP_PAD_CFG
(
index
));
value
&=
~
(
FSLS_USE_XUSB_AO
|
TRK_CTRL_USE_XUSB_AO
|
RPD_CTRL_USE_XUSB_AO
|
RPU_USE_XUSB_AO
|
VREG_USE_XUSB_AO
);
ao_writel
(
priv
,
value
,
XUSB_AO_UTMIP_PAD_CFG
(
index
));
/* disable wake event triggers of sleepwalk logic */
value
=
ao_readl
(
priv
,
XUSB_AO_UTMIP_SLEEPWALK_CFG
(
index
));
value
&=
~
WAKE_VAL
(
~
0
);
value
|=
WAKE_VAL_NONE
;
ao_writel
(
priv
,
value
,
XUSB_AO_UTMIP_SLEEPWALK_CFG
(
index
));
/* power down the line state detectors of the port */
value
=
ao_readl
(
priv
,
XUSB_AO_UTMIP_PAD_CFG
(
index
));
value
|=
USBOP_VAL_PD
|
USBON_VAL_PD
;
ao_writel
(
priv
,
value
,
XUSB_AO_UTMIP_PAD_CFG
(
index
));
/* clear alarm of the sleepwalk logic */
value
=
ao_readl
(
priv
,
XUSB_AO_UTMIP_TRIGGERS
(
index
));
value
|=
CLR_WAKE_ALARM
;
ao_writel
(
priv
,
value
,
XUSB_AO_UTMIP_TRIGGERS
(
index
));
mutex_unlock
(
&
padctl
->
lock
);
return
0
;
}
static
int
tegra186_utmi_enable_phy_wake
(
struct
tegra_xusb_lane
*
lane
)
{
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
unsigned
int
index
=
lane
->
index
;
u32
value
;
mutex_lock
(
&
padctl
->
lock
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM
);
value
&=
~
ALL_WAKE_EVENTS
;
value
|=
USB2_PORT_WAKEUP_EVENT
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM
);
usleep_range
(
10
,
20
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM
);
value
&=
~
ALL_WAKE_EVENTS
;
value
|=
USB2_PORT_WAKE_INTERRUPT_ENABLE
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM
);
mutex_unlock
(
&
padctl
->
lock
);
return
0
;
}
static
int
tegra186_utmi_disable_phy_wake
(
struct
tegra_xusb_lane
*
lane
)
{
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
unsigned
int
index
=
lane
->
index
;
u32
value
;
mutex_lock
(
&
padctl
->
lock
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM
);
value
&=
~
ALL_WAKE_EVENTS
;
value
&=
~
USB2_PORT_WAKE_INTERRUPT_ENABLE
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM
);
usleep_range
(
10
,
20
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM
);
value
&=
~
ALL_WAKE_EVENTS
;
value
|=
USB2_PORT_WAKEUP_EVENT
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM
);
mutex_unlock
(
&
padctl
->
lock
);
return
0
;
}
static
bool
tegra186_utmi_phy_remote_wake_detected
(
struct
tegra_xusb_lane
*
lane
)
{
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
unsigned
int
index
=
lane
->
index
;
u32
value
;
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM
);
if
((
value
&
USB2_PORT_WAKE_INTERRUPT_ENABLE
(
index
))
&&
(
value
&
USB2_PORT_WAKEUP_EVENT
(
index
)))
return
true
;
return
false
;
}
static
const
struct
tegra_xusb_lane_ops
tegra186_usb2_lane_ops
=
{
static
const
struct
tegra_xusb_lane_ops
tegra186_usb2_lane_ops
=
{
.
probe
=
tegra186_usb2_lane_probe
,
.
probe
=
tegra186_usb2_lane_probe
,
.
remove
=
tegra186_usb2_lane_remove
,
.
remove
=
tegra186_usb2_lane_remove
,
.
enable_phy_sleepwalk
=
tegra186_utmi_enable_phy_sleepwalk
,
.
disable_phy_sleepwalk
=
tegra186_utmi_disable_phy_sleepwalk
,
.
enable_phy_wake
=
tegra186_utmi_enable_phy_wake
,
.
disable_phy_wake
=
tegra186_utmi_disable_phy_wake
,
.
remote_wake_detected
=
tegra186_utmi_phy_remote_wake_detected
,
};
};
static
void
tegra186_utmi_bias_pad_power_on
(
struct
tegra_xusb_padctl
*
padctl
)
static
void
tegra186_utmi_bias_pad_power_on
(
struct
tegra_xusb_padctl
*
padctl
)
...
@@ -656,10 +1043,128 @@ static void tegra186_usb3_lane_remove(struct tegra_xusb_lane *lane)
...
@@ -656,10 +1043,128 @@ static void tegra186_usb3_lane_remove(struct tegra_xusb_lane *lane)
kfree
(
usb3
);
kfree
(
usb3
);
}
}
static
int
tegra186_usb3_enable_phy_sleepwalk
(
struct
tegra_xusb_lane
*
lane
,
enum
usb_device_speed
speed
)
{
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
unsigned
int
index
=
lane
->
index
;
u32
value
;
mutex_lock
(
&
padctl
->
lock
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM_1
);
value
|=
SSPX_ELPG_CLAMP_EN_EARLY
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM_1
);
usleep_range
(
100
,
200
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM_1
);
value
|=
SSPX_ELPG_CLAMP_EN
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM_1
);
usleep_range
(
250
,
350
);
mutex_unlock
(
&
padctl
->
lock
);
return
0
;
}
static
int
tegra186_usb3_disable_phy_sleepwalk
(
struct
tegra_xusb_lane
*
lane
)
{
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
unsigned
int
index
=
lane
->
index
;
u32
value
;
mutex_lock
(
&
padctl
->
lock
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM_1
);
value
&=
~
SSPX_ELPG_CLAMP_EN_EARLY
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM_1
);
usleep_range
(
100
,
200
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM_1
);
value
&=
~
SSPX_ELPG_CLAMP_EN
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM_1
);
mutex_unlock
(
&
padctl
->
lock
);
return
0
;
}
static
int
tegra186_usb3_enable_phy_wake
(
struct
tegra_xusb_lane
*
lane
)
{
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
unsigned
int
index
=
lane
->
index
;
u32
value
;
mutex_lock
(
&
padctl
->
lock
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM
);
value
&=
~
ALL_WAKE_EVENTS
;
value
|=
SS_PORT_WAKEUP_EVENT
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM
);
usleep_range
(
10
,
20
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM
);
value
&=
~
ALL_WAKE_EVENTS
;
value
|=
SS_PORT_WAKE_INTERRUPT_ENABLE
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM
);
mutex_unlock
(
&
padctl
->
lock
);
return
0
;
}
static
int
tegra186_usb3_disable_phy_wake
(
struct
tegra_xusb_lane
*
lane
)
{
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
unsigned
int
index
=
lane
->
index
;
u32
value
;
mutex_lock
(
&
padctl
->
lock
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM
);
value
&=
~
ALL_WAKE_EVENTS
;
value
&=
~
SS_PORT_WAKE_INTERRUPT_ENABLE
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM
);
usleep_range
(
10
,
20
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM
);
value
&=
~
ALL_WAKE_EVENTS
;
value
|=
SS_PORT_WAKEUP_EVENT
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM
);
mutex_unlock
(
&
padctl
->
lock
);
return
0
;
}
static
bool
tegra186_usb3_phy_remote_wake_detected
(
struct
tegra_xusb_lane
*
lane
)
{
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
unsigned
int
index
=
lane
->
index
;
u32
value
;
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM
);
if
((
value
&
SS_PORT_WAKE_INTERRUPT_ENABLE
(
index
))
&&
(
value
&
SS_PORT_WAKEUP_EVENT
(
index
)))
return
true
;
return
false
;
}
static
const
struct
tegra_xusb_lane_ops
tegra186_usb3_lane_ops
=
{
static
const
struct
tegra_xusb_lane_ops
tegra186_usb3_lane_ops
=
{
.
probe
=
tegra186_usb3_lane_probe
,
.
probe
=
tegra186_usb3_lane_probe
,
.
remove
=
tegra186_usb3_lane_remove
,
.
remove
=
tegra186_usb3_lane_remove
,
.
enable_phy_sleepwalk
=
tegra186_usb3_enable_phy_sleepwalk
,
.
disable_phy_sleepwalk
=
tegra186_usb3_disable_phy_sleepwalk
,
.
enable_phy_wake
=
tegra186_usb3_enable_phy_wake
,
.
disable_phy_wake
=
tegra186_usb3_disable_phy_wake
,
.
remote_wake_detected
=
tegra186_usb3_phy_remote_wake_detected
,
};
};
static
int
tegra186_usb3_port_enable
(
struct
tegra_xusb_port
*
port
)
static
int
tegra186_usb3_port_enable
(
struct
tegra_xusb_port
*
port
)
{
{
return
0
;
return
0
;
...
@@ -913,7 +1418,9 @@ static struct tegra_xusb_padctl *
...
@@ -913,7 +1418,9 @@ static struct tegra_xusb_padctl *
tegra186_xusb_padctl_probe
(
struct
device
*
dev
,
tegra186_xusb_padctl_probe
(
struct
device
*
dev
,
const
struct
tegra_xusb_padctl_soc
*
soc
)
const
struct
tegra_xusb_padctl_soc
*
soc
)
{
{
struct
platform_device
*
pdev
=
to_platform_device
(
dev
);
struct
tegra186_xusb_padctl
*
priv
;
struct
tegra186_xusb_padctl
*
priv
;
struct
resource
*
res
;
int
err
;
int
err
;
priv
=
devm_kzalloc
(
dev
,
sizeof
(
*
priv
),
GFP_KERNEL
);
priv
=
devm_kzalloc
(
dev
,
sizeof
(
*
priv
),
GFP_KERNEL
);
...
@@ -923,6 +1430,11 @@ tegra186_xusb_padctl_probe(struct device *dev,
...
@@ -923,6 +1430,11 @@ tegra186_xusb_padctl_probe(struct device *dev,
priv
->
base
.
dev
=
dev
;
priv
->
base
.
dev
=
dev
;
priv
->
base
.
soc
=
soc
;
priv
->
base
.
soc
=
soc
;
res
=
platform_get_resource_byname
(
pdev
,
IORESOURCE_MEM
,
"ao"
);
priv
->
ao_regs
=
devm_ioremap_resource
(
dev
,
res
);
if
(
IS_ERR
(
priv
->
ao_regs
))
return
ERR_CAST
(
priv
->
ao_regs
);
err
=
tegra186_xusb_read_fuse_calibration
(
priv
);
err
=
tegra186_xusb_read_fuse_calibration
(
priv
);
if
(
err
<
0
)
if
(
err
<
0
)
return
ERR_PTR
(
err
);
return
ERR_PTR
(
err
);
...
@@ -930,6 +1442,40 @@ tegra186_xusb_padctl_probe(struct device *dev,
...
@@ -930,6 +1442,40 @@ tegra186_xusb_padctl_probe(struct device *dev,
return
&
priv
->
base
;
return
&
priv
->
base
;
}
}
static
void
tegra186_xusb_padctl_save
(
struct
tegra_xusb_padctl
*
padctl
)
{
struct
tegra186_xusb_padctl
*
priv
=
to_tegra186_xusb_padctl
(
padctl
);
priv
->
context
.
vbus_id
=
padctl_readl
(
padctl
,
USB2_VBUS_ID
);
priv
->
context
.
usb2_pad_mux
=
padctl_readl
(
padctl
,
XUSB_PADCTL_USB2_PAD_MUX
);
priv
->
context
.
usb2_port_cap
=
padctl_readl
(
padctl
,
XUSB_PADCTL_USB2_PORT_CAP
);
priv
->
context
.
ss_port_cap
=
padctl_readl
(
padctl
,
XUSB_PADCTL_SS_PORT_CAP
);
}
static
void
tegra186_xusb_padctl_restore
(
struct
tegra_xusb_padctl
*
padctl
)
{
struct
tegra186_xusb_padctl
*
priv
=
to_tegra186_xusb_padctl
(
padctl
);
padctl_writel
(
padctl
,
priv
->
context
.
usb2_pad_mux
,
XUSB_PADCTL_USB2_PAD_MUX
);
padctl_writel
(
padctl
,
priv
->
context
.
usb2_port_cap
,
XUSB_PADCTL_USB2_PORT_CAP
);
padctl_writel
(
padctl
,
priv
->
context
.
ss_port_cap
,
XUSB_PADCTL_SS_PORT_CAP
);
padctl_writel
(
padctl
,
priv
->
context
.
vbus_id
,
USB2_VBUS_ID
);
}
static
int
tegra186_xusb_padctl_suspend_noirq
(
struct
tegra_xusb_padctl
*
padctl
)
{
tegra186_xusb_padctl_save
(
padctl
);
return
0
;
}
static
int
tegra186_xusb_padctl_resume_noirq
(
struct
tegra_xusb_padctl
*
padctl
)
{
tegra186_xusb_padctl_restore
(
padctl
);
return
0
;
}
static
void
tegra186_xusb_padctl_remove
(
struct
tegra_xusb_padctl
*
padctl
)
static
void
tegra186_xusb_padctl_remove
(
struct
tegra_xusb_padctl
*
padctl
)
{
{
}
}
...
@@ -937,6 +1483,8 @@ static void tegra186_xusb_padctl_remove(struct tegra_xusb_padctl *padctl)
...
@@ -937,6 +1483,8 @@ static void tegra186_xusb_padctl_remove(struct tegra_xusb_padctl *padctl)
static
const
struct
tegra_xusb_padctl_ops
tegra186_xusb_padctl_ops
=
{
static
const
struct
tegra_xusb_padctl_ops
tegra186_xusb_padctl_ops
=
{
.
probe
=
tegra186_xusb_padctl_probe
,
.
probe
=
tegra186_xusb_padctl_probe
,
.
remove
=
tegra186_xusb_padctl_remove
,
.
remove
=
tegra186_xusb_padctl_remove
,
.
suspend_noirq
=
tegra186_xusb_padctl_suspend_noirq
,
.
resume_noirq
=
tegra186_xusb_padctl_resume_noirq
,
.
vbus_override
=
tegra186_xusb_padctl_vbus_override
,
.
vbus_override
=
tegra186_xusb_padctl_vbus_override
,
};
};
...
...
drivers/phy/tegra/xusb-tegra210.c
View file @
23eca831
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-License-Identifier: GPL-2.0-only
/*
/*
* Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2014
-2020
, NVIDIA CORPORATION. All rights reserved.
* Copyright (C) 2015 Google, Inc.
* Copyright (C) 2015 Google, Inc.
*/
*/
...
@@ -11,8 +11,10 @@
...
@@ -11,8 +11,10 @@
#include <linux/mailbox_client.h>
#include <linux/mailbox_client.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/phy/phy.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/reset.h>
#include <linux/slab.h>
#include <linux/slab.h>
...
@@ -52,6 +54,20 @@
...
@@ -52,6 +54,20 @@
#define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(x, v) (((v) & 0x7) << ((x) * 5))
#define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(x, v) (((v) & 0x7) << ((x) * 5))
#define XUSB_PADCTL_SS_PORT_MAP_PORT_DISABLED 0x7
#define XUSB_PADCTL_SS_PORT_MAP_PORT_DISABLED 0x7
#define XUSB_PADCTL_ELPG_PROGRAM_0 0x20
#define USB2_PORT_WAKE_INTERRUPT_ENABLE(x) BIT((x))
#define USB2_PORT_WAKEUP_EVENT(x) BIT((x) + 7)
#define SS_PORT_WAKE_INTERRUPT_ENABLE(x) BIT((x) + 14)
#define SS_PORT_WAKEUP_EVENT(x) BIT((x) + 21)
#define USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(x) BIT((x) + 28)
#define USB2_HSIC_PORT_WAKEUP_EVENT(x) BIT((x) + 30)
#define ALL_WAKE_EVENTS ( \
USB2_PORT_WAKEUP_EVENT(0) | USB2_PORT_WAKEUP_EVENT(1) | \
USB2_PORT_WAKEUP_EVENT(2) | USB2_PORT_WAKEUP_EVENT(3) | \
SS_PORT_WAKEUP_EVENT(0) | SS_PORT_WAKEUP_EVENT(1) | \
SS_PORT_WAKEUP_EVENT(2) | SS_PORT_WAKEUP_EVENT(3) | \
USB2_HSIC_PORT_WAKEUP_EVENT(0))
#define XUSB_PADCTL_ELPG_PROGRAM1 0x024
#define XUSB_PADCTL_ELPG_PROGRAM1 0x024
#define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN (1 << 31)
#define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN (1 << 31)
#define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 30)
#define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 30)
...
@@ -90,6 +106,8 @@
...
@@ -90,6 +106,8 @@
#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR (1 << 2)
#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR (1 << 2)
#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_OVRD (1 << 1)
#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_OVRD (1 << 1)
#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_OVRD (1 << 0)
#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_OVRD (1 << 0)
#define RPD_CTRL(x) (((x) & 0x1f) << 26)
#define RPD_CTRL_VALUE(x) (((x) >> 26) & 0x1f)
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x284
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x284
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD (1 << 11)
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD (1 << 11)
...
@@ -108,6 +126,8 @@
...
@@ -108,6 +126,8 @@
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT 12
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT 12
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK 0x7f
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK 0x7f
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_VAL 0x1e
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_VAL 0x1e
#define TCTRL_VALUE(x) (((x) & 0x3f) >> 0)
#define PCTRL_VALUE(x) (((x) >> 6) & 0x3f)
#define XUSB_PADCTL_HSIC_PADX_CTL0(x) (0x300 + (x) * 0x20)
#define XUSB_PADCTL_HSIC_PADX_CTL0(x) (0x300 + (x) * 0x20)
#define XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE (1 << 18)
#define XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE (1 << 18)
...
@@ -198,6 +218,18 @@
...
@@ -198,6 +218,18 @@
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_TERM_EN BIT(18)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_TERM_EN BIT(18)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_MODE_OVRD BIT(13)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_MODE_OVRD BIT(13)
#define XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(x) (0x464 + (x) * 0x40)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ BIT(0)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ_OVRD BIT(1)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_MASK GENMASK(5, 4)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_VAL GENMASK(5, 4)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_PWR_OVRD BIT(24)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ BIT(8)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ_OVRD BIT(9)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_MASK GENMASK(13, 12)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_VAL GENMASK(13, 12)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_PWR_OVRD BIT(25)
#define XUSB_PADCTL_UPHY_PLL_S0_CTL1 0x860
#define XUSB_PADCTL_UPHY_PLL_S0_CTL1 0x860
#define XUSB_PADCTL_UPHY_PLL_S0_CTL2 0x864
#define XUSB_PADCTL_UPHY_PLL_S0_CTL2 0x864
...
@@ -209,6 +241,7 @@
...
@@ -209,6 +241,7 @@
#define XUSB_PADCTL_UPHY_PLL_S0_CTL8 0x87c
#define XUSB_PADCTL_UPHY_PLL_S0_CTL8 0x87c
#define XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL1 0x960
#define XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL1 0x960
#define XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL2 0x964
#define XUSB_PADCTL_UPHY_USB3_PADX_ECTL1(x) (0xa60 + (x) * 0x40)
#define XUSB_PADCTL_UPHY_USB3_PADX_ECTL1(x) (0xa60 + (x) * 0x40)
#define XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT 16
#define XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT 16
...
@@ -238,16 +271,161 @@
...
@@ -238,16 +271,161 @@
#define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING 8
#define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING 8
#define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_GROUNDED 0
#define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_GROUNDED 0
/* USB2 SLEEPWALK registers */
#define UTMIP(_port, _offset1, _offset2) \
(((_port) <= 2) ? (_offset1) : (_offset2))
#define PMC_UTMIP_UHSIC_SLEEP_CFG(x) UTMIP(x, 0x1fc, 0x4d0)
#define UTMIP_MASTER_ENABLE(x) UTMIP(x, BIT(8 * (x)), BIT(0))
#define UTMIP_FSLS_USE_PMC(x) UTMIP(x, BIT(8 * (x) + 1), \
BIT(1))
#define UTMIP_PCTRL_USE_PMC(x) UTMIP(x, BIT(8 * (x) + 2), \
BIT(2))
#define UTMIP_TCTRL_USE_PMC(x) UTMIP(x, BIT(8 * (x) + 3), \
BIT(3))
#define UTMIP_WAKE_VAL(_port, _value) (((_value) & 0xf) << \
(UTMIP(_port, 8 * (_port) + 4, 4)))
#define UTMIP_WAKE_VAL_NONE(_port) UTMIP_WAKE_VAL(_port, 12)
#define UTMIP_WAKE_VAL_ANY(_port) UTMIP_WAKE_VAL(_port, 15)
#define PMC_UTMIP_UHSIC_SLEEP_CFG1 (0x4d0)
#define UTMIP_RPU_SWITC_LOW_USE_PMC_PX(x) BIT((x) + 8)
#define UTMIP_RPD_CTRL_USE_PMC_PX(x) BIT((x) + 16)
#define PMC_UTMIP_MASTER_CONFIG (0x274)
#define UTMIP_PWR(x) UTMIP(x, BIT(x), BIT(4))
#define UHSIC_PWR BIT(3)
#define PMC_USB_DEBOUNCE_DEL (0xec)
#define DEBOUNCE_VAL(x) (((x) & 0xffff) << 0)
#define UTMIP_LINE_DEB_CNT(x) (((x) & 0xf) << 16)
#define UHSIC_LINE_DEB_CNT(x) (((x) & 0xf) << 20)
#define PMC_UTMIP_UHSIC_FAKE(x) UTMIP(x, 0x218, 0x294)
#define UTMIP_FAKE_USBOP_VAL(x) UTMIP(x, BIT(4 * (x)), BIT(8))
#define UTMIP_FAKE_USBON_VAL(x) UTMIP(x, BIT(4 * (x) + 1), \
BIT(9))
#define UTMIP_FAKE_USBOP_EN(x) UTMIP(x, BIT(4 * (x) + 2), \
BIT(10))
#define UTMIP_FAKE_USBON_EN(x) UTMIP(x, BIT(4 * (x) + 3), \
BIT(11))
#define PMC_UTMIP_UHSIC_SLEEPWALK_CFG(x) UTMIP(x, 0x200, 0x288)
#define UTMIP_LINEVAL_WALK_EN(x) UTMIP(x, BIT(8 * (x) + 7), \
BIT(15))
#define PMC_USB_AO (0xf0)
#define USBOP_VAL_PD(x) UTMIP(x, BIT(4 * (x)), BIT(20))
#define USBON_VAL_PD(x) UTMIP(x, BIT(4 * (x) + 1), \
BIT(21))
#define STROBE_VAL_PD BIT(12)
#define DATA0_VAL_PD BIT(13)
#define DATA1_VAL_PD BIT(24)
#define PMC_UTMIP_UHSIC_SAVED_STATE(x) UTMIP(x, 0x1f0, 0x280)
#define SPEED(_port, _value) (((_value) & 0x3) << \
(UTMIP(_port, 8 * (_port), 8)))
#define UTMI_HS(_port) SPEED(_port, 0)
#define UTMI_FS(_port) SPEED(_port, 1)
#define UTMI_LS(_port) SPEED(_port, 2)
#define UTMI_RST(_port) SPEED(_port, 3)
#define PMC_UTMIP_UHSIC_TRIGGERS (0x1ec)
#define UTMIP_CLR_WALK_PTR(x) UTMIP(x, BIT(x), BIT(16))
#define UTMIP_CAP_CFG(x) UTMIP(x, BIT((x) + 4), BIT(17))
#define UTMIP_CLR_WAKE_ALARM(x) UTMIP(x, BIT((x) + 12), \
BIT(19))
#define UHSIC_CLR_WALK_PTR BIT(3)
#define UHSIC_CLR_WAKE_ALARM BIT(15)
#define PMC_UTMIP_SLEEPWALK_PX(x) UTMIP(x, 0x204 + (4 * (x)), \
0x4e0)
/* phase A */
#define UTMIP_USBOP_RPD_A BIT(0)
#define UTMIP_USBON_RPD_A BIT(1)
#define UTMIP_AP_A BIT(4)
#define UTMIP_AN_A BIT(5)
#define UTMIP_HIGHZ_A BIT(6)
/* phase B */
#define UTMIP_USBOP_RPD_B BIT(8)
#define UTMIP_USBON_RPD_B BIT(9)
#define UTMIP_AP_B BIT(12)
#define UTMIP_AN_B BIT(13)
#define UTMIP_HIGHZ_B BIT(14)
/* phase C */
#define UTMIP_USBOP_RPD_C BIT(16)
#define UTMIP_USBON_RPD_C BIT(17)
#define UTMIP_AP_C BIT(20)
#define UTMIP_AN_C BIT(21)
#define UTMIP_HIGHZ_C BIT(22)
/* phase D */
#define UTMIP_USBOP_RPD_D BIT(24)
#define UTMIP_USBON_RPD_D BIT(25)
#define UTMIP_AP_D BIT(28)
#define UTMIP_AN_D BIT(29)
#define UTMIP_HIGHZ_D BIT(30)
#define PMC_UTMIP_UHSIC_LINE_WAKEUP (0x26c)
#define UTMIP_LINE_WAKEUP_EN(x) UTMIP(x, BIT(x), BIT(4))
#define UHSIC_LINE_WAKEUP_EN BIT(3)
#define PMC_UTMIP_TERM_PAD_CFG (0x1f8)
#define PCTRL_VAL(x) (((x) & 0x3f) << 1)
#define TCTRL_VAL(x) (((x) & 0x3f) << 7)
#define PMC_UTMIP_PAD_CFGX(x) (0x4c0 + (4 * (x)))
#define RPD_CTRL_PX(x) (((x) & 0x1f) << 22)
#define PMC_UHSIC_SLEEP_CFG PMC_UTMIP_UHSIC_SLEEP_CFG(0)
#define UHSIC_MASTER_ENABLE BIT(24)
#define UHSIC_WAKE_VAL(_value) (((_value) & 0xf) << 28)
#define UHSIC_WAKE_VAL_SD10 UHSIC_WAKE_VAL(2)
#define UHSIC_WAKE_VAL_NONE UHSIC_WAKE_VAL(12)
#define PMC_UHSIC_FAKE PMC_UTMIP_UHSIC_FAKE(0)
#define UHSIC_FAKE_STROBE_VAL BIT(12)
#define UHSIC_FAKE_DATA_VAL BIT(13)
#define UHSIC_FAKE_STROBE_EN BIT(14)
#define UHSIC_FAKE_DATA_EN BIT(15)
#define PMC_UHSIC_SAVED_STATE PMC_UTMIP_UHSIC_SAVED_STATE(0)
#define UHSIC_MODE(_value) (((_value) & 0x1) << 24)
#define UHSIC_HS UHSIC_MODE(0)
#define UHSIC_RST UHSIC_MODE(1)
#define PMC_UHSIC_SLEEPWALK_CFG PMC_UTMIP_UHSIC_SLEEPWALK_CFG(0)
#define UHSIC_WAKE_WALK_EN BIT(30)
#define UHSIC_LINEVAL_WALK_EN BIT(31)
#define PMC_UHSIC_SLEEPWALK_P0 (0x210)
#define UHSIC_DATA0_RPD_A BIT(1)
#define UHSIC_DATA0_RPU_B BIT(11)
#define UHSIC_DATA0_RPU_C BIT(19)
#define UHSIC_DATA0_RPU_D BIT(27)
#define UHSIC_STROBE_RPU_A BIT(2)
#define UHSIC_STROBE_RPD_B BIT(8)
#define UHSIC_STROBE_RPD_C BIT(16)
#define UHSIC_STROBE_RPD_D BIT(24)
struct
tegra210_xusb_fuse_calibration
{
struct
tegra210_xusb_fuse_calibration
{
u32
hs_curr_level
[
4
];
u32
hs_curr_level
[
4
];
u32
hs_term_range_adj
;
u32
hs_term_range_adj
;
u32
rpd_ctrl
;
u32
rpd_ctrl
;
};
};
struct
tegra210_xusb_padctl_context
{
u32
usb2_pad_mux
;
u32
usb2_port_cap
;
u32
ss_port_map
;
u32
usb3_pad_mux
;
};
struct
tegra210_xusb_padctl
{
struct
tegra210_xusb_padctl
{
struct
tegra_xusb_padctl
base
;
struct
tegra_xusb_padctl
base
;
struct
regmap
*
regmap
;
struct
tegra210_xusb_fuse_calibration
fuse
;
struct
tegra210_xusb_fuse_calibration
fuse
;
struct
tegra210_xusb_padctl_context
context
;
};
};
static
inline
struct
tegra210_xusb_padctl
*
static
inline
struct
tegra210_xusb_padctl
*
...
@@ -256,23 +434,51 @@ to_tegra210_xusb_padctl(struct tegra_xusb_padctl *padctl)
...
@@ -256,23 +434,51 @@ to_tegra210_xusb_padctl(struct tegra_xusb_padctl *padctl)
return
container_of
(
padctl
,
struct
tegra210_xusb_padctl
,
base
);
return
container_of
(
padctl
,
struct
tegra210_xusb_padctl
,
base
);
}
}
static
const
struct
tegra_xusb_lane_map
tegra210_usb3_map
[]
=
{
{
0
,
"pcie"
,
6
},
{
1
,
"pcie"
,
5
},
{
2
,
"pcie"
,
0
},
{
2
,
"pcie"
,
3
},
{
3
,
"pcie"
,
4
},
{
3
,
"sata"
,
0
},
{
0
,
NULL
,
0
}
};
static
int
tegra210_usb3_lane_map
(
struct
tegra_xusb_lane
*
lane
)
{
const
struct
tegra_xusb_lane_map
*
map
;
for
(
map
=
tegra210_usb3_map
;
map
->
type
;
map
++
)
{
if
(
map
->
index
==
lane
->
index
&&
strcmp
(
map
->
type
,
lane
->
pad
->
soc
->
name
)
==
0
)
{
dev_dbg
(
lane
->
pad
->
padctl
->
dev
,
"lane = %s map to port = usb3-%d
\n
"
,
lane
->
pad
->
soc
->
lanes
[
lane
->
index
].
name
,
map
->
port
);
return
map
->
port
;
}
}
return
-
EINVAL
;
}
/* must be called under padctl->lock */
/* must be called under padctl->lock */
static
int
tegra210_pex_uphy_enable
(
struct
tegra_xusb_padctl
*
padctl
)
static
int
tegra210_pex_uphy_enable
(
struct
tegra_xusb_padctl
*
padctl
)
{
{
struct
tegra_xusb_pcie_pad
*
pcie
=
to_pcie_pad
(
padctl
->
pcie
);
struct
tegra_xusb_pcie_pad
*
pcie
=
to_pcie_pad
(
padctl
->
pcie
);
unsigned
long
timeout
;
unsigned
long
timeout
;
u32
value
;
u32
value
;
unsigned
int
i
;
int
err
;
int
err
;
if
(
pcie
->
enable
>
0
)
{
if
(
pcie
->
enable
)
pcie
->
enable
++
;
return
0
;
return
0
;
}
err
=
clk_prepare_enable
(
pcie
->
pll
);
err
=
clk_prepare_enable
(
pcie
->
pll
);
if
(
err
<
0
)
if
(
err
<
0
)
return
err
;
return
err
;
if
(
tegra210_plle_hw_sequence_is_enabled
())
goto
skip_pll_init
;
err
=
reset_control_deassert
(
pcie
->
rst
);
err
=
reset_control_deassert
(
pcie
->
rst
);
if
(
err
<
0
)
if
(
err
<
0
)
goto
disable
;
goto
disable
;
...
@@ -455,7 +661,14 @@ static int tegra210_pex_uphy_enable(struct tegra_xusb_padctl *padctl)
...
@@ -455,7 +661,14 @@ static int tegra210_pex_uphy_enable(struct tegra_xusb_padctl *padctl)
tegra210_xusb_pll_hw_sequence_start
();
tegra210_xusb_pll_hw_sequence_start
();
pcie
->
enable
++
;
skip_pll_init:
pcie
->
enable
=
true
;
for
(
i
=
0
;
i
<
padctl
->
pcie
->
soc
->
num_lanes
;
i
++
)
{
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_USB3_PAD_MUX
);
value
|=
XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE
(
i
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_USB3_PAD_MUX
);
}
return
0
;
return
0
;
...
@@ -469,34 +682,44 @@ static int tegra210_pex_uphy_enable(struct tegra_xusb_padctl *padctl)
...
@@ -469,34 +682,44 @@ static int tegra210_pex_uphy_enable(struct tegra_xusb_padctl *padctl)
static
void
tegra210_pex_uphy_disable
(
struct
tegra_xusb_padctl
*
padctl
)
static
void
tegra210_pex_uphy_disable
(
struct
tegra_xusb_padctl
*
padctl
)
{
{
struct
tegra_xusb_pcie_pad
*
pcie
=
to_pcie_pad
(
padctl
->
pcie
);
struct
tegra_xusb_pcie_pad
*
pcie
=
to_pcie_pad
(
padctl
->
pcie
);
u32
value
;
unsigned
int
i
;
mutex_lock
(
&
padctl
->
lock
);
if
(
WARN_ON
(
!
pcie
->
enable
))
return
;
if
(
WARN_ON
(
pcie
->
enable
==
0
))
pcie
->
enable
=
false
;
goto
unlock
;
if
(
--
pcie
->
enable
>
0
)
for
(
i
=
0
;
i
<
padctl
->
pcie
->
soc
->
num_lanes
;
i
++
)
{
goto
unlock
;
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_USB3_PAD_MUX
);
value
&=
~
XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE
(
i
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_USB3_PAD_MUX
);
}
reset_control_assert
(
pcie
->
rst
);
clk_disable_unprepare
(
pcie
->
pll
);
clk_disable_unprepare
(
pcie
->
pll
);
unlock:
mutex_unlock
(
&
padctl
->
lock
);
}
}
/* must be called under padctl->lock */
/* must be called under padctl->lock */
static
int
tegra210_sata_uphy_enable
(
struct
tegra_xusb_padctl
*
padctl
,
bool
usb
)
static
int
tegra210_sata_uphy_enable
(
struct
tegra_xusb_padctl
*
padctl
)
{
{
struct
tegra_xusb_sata_pad
*
sata
=
to_sata_pad
(
padctl
->
sata
);
struct
tegra_xusb_sata_pad
*
sata
=
to_sata_pad
(
padctl
->
sata
);
struct
tegra_xusb_lane
*
lane
=
tegra_xusb_find_lane
(
padctl
,
"sata"
,
0
);
unsigned
long
timeout
;
unsigned
long
timeout
;
u32
value
;
u32
value
;
unsigned
int
i
;
int
err
;
int
err
;
bool
usb
;
if
(
sata
->
enable
>
0
)
{
if
(
sata
->
enable
)
sata
->
enable
++
;
return
0
;
if
(
IS_ERR
(
lane
))
return
0
;
return
0
;
}
if
(
tegra210_plle_hw_sequence_is_enabled
())
goto
skip_pll_init
;
usb
=
tegra_xusb_lane_check
(
lane
,
"usb3-ss"
);
err
=
clk_prepare_enable
(
sata
->
pll
);
err
=
clk_prepare_enable
(
sata
->
pll
);
if
(
err
<
0
)
if
(
err
<
0
)
...
@@ -697,7 +920,14 @@ static int tegra210_sata_uphy_enable(struct tegra_xusb_padctl *padctl, bool usb)
...
@@ -697,7 +920,14 @@ static int tegra210_sata_uphy_enable(struct tegra_xusb_padctl *padctl, bool usb)
tegra210_sata_pll_hw_sequence_start
();
tegra210_sata_pll_hw_sequence_start
();
sata
->
enable
++
;
skip_pll_init:
sata
->
enable
=
true
;
for
(
i
=
0
;
i
<
padctl
->
sata
->
soc
->
num_lanes
;
i
++
)
{
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_USB3_PAD_MUX
);
value
|=
XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE
(
i
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_USB3_PAD_MUX
);
}
return
0
;
return
0
;
...
@@ -711,31 +941,27 @@ static int tegra210_sata_uphy_enable(struct tegra_xusb_padctl *padctl, bool usb)
...
@@ -711,31 +941,27 @@ static int tegra210_sata_uphy_enable(struct tegra_xusb_padctl *padctl, bool usb)
static
void
tegra210_sata_uphy_disable
(
struct
tegra_xusb_padctl
*
padctl
)
static
void
tegra210_sata_uphy_disable
(
struct
tegra_xusb_padctl
*
padctl
)
{
{
struct
tegra_xusb_sata_pad
*
sata
=
to_sata_pad
(
padctl
->
sata
);
struct
tegra_xusb_sata_pad
*
sata
=
to_sata_pad
(
padctl
->
sata
);
u32
value
;
unsigned
int
i
;
mutex_lock
(
&
padctl
->
lock
);
if
(
WARN_ON
(
!
sata
->
enable
))
return
;
if
(
WARN_ON
(
sata
->
enable
==
0
))
sata
->
enable
=
false
;
goto
unlock
;
if
(
--
sata
->
enable
>
0
)
for
(
i
=
0
;
i
<
padctl
->
sata
->
soc
->
num_lanes
;
i
++
)
{
goto
unlock
;
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_USB3_PAD_MUX
);
value
&=
~
XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE
(
i
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_USB3_PAD_MUX
);
}
reset_control_assert
(
sata
->
rst
);
clk_disable_unprepare
(
sata
->
pll
);
clk_disable_unprepare
(
sata
->
pll
);
unlock:
mutex_unlock
(
&
padctl
->
lock
);
}
}
static
int
tegra210_xusb_padctl_en
able
(
struct
tegra_xusb_padctl
*
padctl
)
static
void
tegra210_aux_mux_lp0_clamp_dis
able
(
struct
tegra_xusb_padctl
*
padctl
)
{
{
u32
value
;
u32
value
;
mutex_lock
(
&
padctl
->
lock
);
if
(
padctl
->
enable
++
>
0
)
goto
out
;
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM1
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM1
);
value
&=
~
XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN
;
value
&=
~
XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN
;
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM1
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM1
);
...
@@ -751,24 +977,12 @@ static int tegra210_xusb_padctl_enable(struct tegra_xusb_padctl *padctl)
...
@@ -751,24 +977,12 @@ static int tegra210_xusb_padctl_enable(struct tegra_xusb_padctl *padctl)
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM1
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM1
);
value
&=
~
XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN
;
value
&=
~
XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN
;
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM1
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM1
);
out:
mutex_unlock
(
&
padctl
->
lock
);
return
0
;
}
}
static
int
tegra210_xusb_padctl_dis
able
(
struct
tegra_xusb_padctl
*
padctl
)
static
void
tegra210_aux_mux_lp0_clamp_en
able
(
struct
tegra_xusb_padctl
*
padctl
)
{
{
u32
value
;
u32
value
;
mutex_lock
(
&
padctl
->
lock
);
if
(
WARN_ON
(
padctl
->
enable
==
0
))
goto
out
;
if
(
--
padctl
->
enable
>
0
)
goto
out
;
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM1
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM1
);
value
|=
XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN
;
value
|=
XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN
;
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM1
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM1
);
...
@@ -784,12 +998,38 @@ static int tegra210_xusb_padctl_disable(struct tegra_xusb_padctl *padctl)
...
@@ -784,12 +998,38 @@ static int tegra210_xusb_padctl_disable(struct tegra_xusb_padctl *padctl)
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM1
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM1
);
value
|=
XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN
;
value
|=
XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN
;
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM1
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM1
);
}
static
int
tegra210_uphy_init
(
struct
tegra_xusb_padctl
*
padctl
)
{
if
(
padctl
->
pcie
)
tegra210_pex_uphy_enable
(
padctl
);
if
(
padctl
->
sata
)
tegra210_sata_uphy_enable
(
padctl
);
if
(
!
tegra210_plle_hw_sequence_is_enabled
())
tegra210_plle_hw_sequence_start
();
else
dev_dbg
(
padctl
->
dev
,
"PLLE is already in HW control
\n
"
);
tegra210_aux_mux_lp0_clamp_disable
(
padctl
);
out:
mutex_unlock
(
&
padctl
->
lock
);
return
0
;
return
0
;
}
}
static
void
__maybe_unused
tegra210_uphy_deinit
(
struct
tegra_xusb_padctl
*
padctl
)
{
tegra210_aux_mux_lp0_clamp_enable
(
padctl
);
if
(
padctl
->
sata
)
tegra210_sata_uphy_disable
(
padctl
);
if
(
padctl
->
pcie
)
tegra210_pex_uphy_disable
(
padctl
);
}
static
int
tegra210_hsic_set_idle
(
struct
tegra_xusb_padctl
*
padctl
,
static
int
tegra210_hsic_set_idle
(
struct
tegra_xusb_padctl
*
padctl
,
unsigned
int
index
,
bool
idle
)
unsigned
int
index
,
bool
idle
)
{
{
...
@@ -815,193 +1055,869 @@ static int tegra210_hsic_set_idle(struct tegra_xusb_padctl *padctl,
...
@@ -815,193 +1055,869 @@ static int tegra210_hsic_set_idle(struct tegra_xusb_padctl *padctl,
return
0
;
return
0
;
}
}
static
int
tegra210_usb3_
set_lfps_detect
(
struct
tegra_xusb_padctl
*
padctl
,
static
int
tegra210_usb3_
enable_phy_sleepwalk
(
struct
tegra_xusb_lane
*
lane
,
unsigned
int
index
,
bool
enable
)
enum
usb_device_speed
speed
)
{
{
struct
tegra_xusb_port
*
port
;
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
struct
tegra_xusb_lane
*
lane
;
int
port
=
tegra210_usb3_lane_map
(
lane
);
u32
value
,
offset
;
struct
device
*
dev
=
padctl
->
dev
;
u32
value
;
port
=
tegra_xusb_find_port
(
padctl
,
"usb3"
,
index
);
if
(
port
<
0
)
{
if
(
!
port
)
dev_err
(
dev
,
"invalid usb3 port number
\n
"
);
return
-
ENODEV
;
return
-
EINVAL
;
}
lane
=
port
->
lane
;
mutex_lock
(
&
padctl
->
lock
)
;
if
(
lane
->
pad
==
padctl
->
pcie
)
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM1
);
offset
=
XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL1
(
lane
->
index
);
value
|=
XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY
(
port
);
else
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM1
);
offset
=
XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL1
;
value
=
padctl_readl
(
padctl
,
offset
);
usleep_range
(
100
,
200
);
value
&=
~
((
XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_MASK
<<
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM1
);
XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_SHIFT
)
|
value
|=
XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN
(
port
);
XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_TERM_EN
|
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM1
);
XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_MODE_OVRD
);
if
(
!
enable
)
{
usleep_range
(
250
,
350
);
value
|=
(
XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_VAL
<<
XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_SHIFT
)
|
XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_TERM_EN
|
XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_MODE_OVRD
;
}
padctl_writel
(
padctl
,
value
,
offset
);
mutex_unlock
(
&
padctl
->
lock
);
return
0
;
return
0
;
}
}
#define TEGRA210_LANE(_name, _offset, _shift, _mask, _type) \
static
int
tegra210_usb3_disable_phy_sleepwalk
(
struct
tegra_xusb_lane
*
lane
)
{ \
{
.name = _name, \
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
.offset = _offset, \
int
port
=
tegra210_usb3_lane_map
(
lane
);
.shift = _shift, \
struct
device
*
dev
=
padctl
->
dev
;
.mask = _mask, \
u32
value
;
.num_funcs = ARRAY_SIZE(tegra210_##_type##_functions), \
.funcs = tegra210_##_type##_functions, \
}
static
const
char
*
tegra210_usb2_functions
[]
=
{
if
(
port
<
0
)
{
"snps"
,
dev_err
(
dev
,
"invalid usb3 port number
\n
"
);
"xusb"
,
return
-
EINVAL
;
"uart"
}
};
static
const
struct
tegra_xusb_lane_soc
tegra210_usb2_lanes
[]
=
{
mutex_lock
(
&
padctl
->
lock
);
TEGRA210_LANE
(
"usb2-0"
,
0x004
,
0
,
0x3
,
usb2
),
TEGRA210_LANE
(
"usb2-1"
,
0x004
,
2
,
0x3
,
usb2
),
TEGRA210_LANE
(
"usb2-2"
,
0x004
,
4
,
0x3
,
usb2
),
TEGRA210_LANE
(
"usb2-3"
,
0x004
,
6
,
0x3
,
usb2
),
};
static
struct
tegra_xusb_lane
*
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM1
);
tegra210_usb2_lane_probe
(
struct
tegra_xusb_pad
*
pad
,
struct
device_node
*
np
,
value
&=
~
XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY
(
port
);
unsigned
int
index
)
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM1
);
{
struct
tegra_xusb_usb2_lane
*
usb2
;
int
err
;
usb2
=
kzalloc
(
sizeof
(
*
usb2
),
GFP_KERNEL
);
usleep_range
(
100
,
200
);
if
(
!
usb2
)
return
ERR_PTR
(
-
ENOMEM
);
INIT_LIST_HEAD
(
&
usb2
->
base
.
list
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM1
);
usb2
->
base
.
soc
=
&
pad
->
soc
->
lanes
[
index
];
value
&=
~
XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN
(
port
);
usb2
->
base
.
index
=
index
;
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM1
);
usb2
->
base
.
pad
=
pad
;
usb2
->
base
.
np
=
np
;
err
=
tegra_xusb_lane_parse_dt
(
&
usb2
->
base
,
np
);
mutex_unlock
(
&
padctl
->
lock
);
if
(
err
<
0
)
{
kfree
(
usb2
);
return
ERR_PTR
(
err
);
}
return
&
usb2
->
base
;
return
0
;
}
}
static
void
tegra210_usb2_lane_remov
e
(
struct
tegra_xusb_lane
*
lane
)
static
int
tegra210_usb3_enable_phy_wak
e
(
struct
tegra_xusb_lane
*
lane
)
{
{
struct
tegra_xusb_usb2_lane
*
usb2
=
to_usb2_lane
(
lane
);
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
int
port
=
tegra210_usb3_lane_map
(
lane
);
struct
device
*
dev
=
padctl
->
dev
;
u32
value
;
kfree
(
usb2
);
if
(
port
<
0
)
{
}
dev_err
(
dev
,
"invalid usb3 port number
\n
"
);
return
-
EINVAL
;
}
static
const
struct
tegra_xusb_lane_ops
tegra210_usb2_lane_ops
=
{
mutex_lock
(
&
padctl
->
lock
);
.
probe
=
tegra210_usb2_lane_probe
,
.
remove
=
tegra210_usb2_lane_remove
,
};
static
int
tegra210_usb2_phy_init
(
struct
phy
*
phy
)
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
{
value
&=
~
ALL_WAKE_EVENTS
;
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
value
|=
SS_PORT_WAKEUP_EVENT
(
port
);
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
u32
value
;
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_USB2_PAD_MUX
);
usleep_range
(
10
,
20
);
value
&=
~
(
XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK
<<
XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT
);
value
|=
XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_XUSB
<<
XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT
;
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_USB2_PAD_MUX
);
return
tegra210_xusb_padctl_enable
(
padctl
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
}
value
&=
~
ALL_WAKE_EVENTS
;
value
|=
SS_PORT_WAKE_INTERRUPT_ENABLE
(
port
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
static
int
tegra210_usb2_phy_exit
(
struct
phy
*
phy
)
mutex_unlock
(
&
padctl
->
lock
);
{
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
return
tegra210_xusb_padctl_disable
(
lane
->
pad
->
padctl
)
;
return
0
;
}
}
static
int
tegra210_xusb_padctl_vbus_override
(
struct
tegra_xusb_padctl
*
padctl
,
static
int
tegra210_usb3_disable_phy_wake
(
struct
tegra_xusb_lane
*
lane
)
bool
status
)
{
{
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
int
port
=
tegra210_usb3_lane_map
(
lane
);
struct
device
*
dev
=
padctl
->
dev
;
u32
value
;
u32
value
;
dev_dbg
(
padctl
->
dev
,
"%s vbus override
\n
"
,
status
?
"set"
:
"clear"
);
if
(
port
<
0
)
{
dev_err
(
dev
,
"invalid usb3 port number
\n
"
);
return
-
EINVAL
;
}
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_USB2_VBUS_ID
);
mutex_lock
(
&
padctl
->
lock
);
if
(
status
)
{
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
value
|=
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON
;
value
&=
~
ALL_WAKE_EVENTS
;
value
&=
~
(
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK
<<
value
&=
~
SS_PORT_WAKE_INTERRUPT_ENABLE
(
port
);
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
value
|=
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING
<<
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT
;
}
else
{
value
&=
~
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON
;
}
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_USB2_VBUS_ID
);
usleep_range
(
10
,
20
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
value
&=
~
ALL_WAKE_EVENTS
;
value
|=
SS_PORT_WAKEUP_EVENT
(
port
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
mutex_unlock
(
&
padctl
->
lock
);
return
0
;
return
0
;
}
}
static
int
tegra210_xusb_padctl_id_override
(
struct
tegra_xusb_padctl
*
padctl
,
static
bool
tegra210_usb3_phy_remote_wake_detected
(
struct
tegra_xusb_lane
*
lane
)
bool
status
)
{
{
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
int
index
=
tegra210_usb3_lane_map
(
lane
);
u32
value
;
u32
value
;
dev_dbg
(
padctl
->
dev
,
"%s id override
\n
"
,
status
?
"set"
:
"clear"
);
if
(
index
<
0
)
return
false
;
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_USB2_VBUS_ID
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
if
((
value
&
SS_PORT_WAKE_INTERRUPT_ENABLE
(
index
))
&&
(
value
&
SS_PORT_WAKEUP_EVENT
(
index
)))
return
true
;
if
(
status
)
{
return
false
;
if
(
value
&
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON
)
{
}
value
&=
~
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON
;
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_USB2_VBUS_ID
);
usleep_range
(
1000
,
2000
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_USB2_VBUS_ID
);
static
int
tegra210_utmi_enable_phy_wake
(
struct
tegra_xusb_lane
*
lane
)
}
{
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
unsigned
int
index
=
lane
->
index
;
u32
value
;
value
&=
~
(
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK
<<
mutex_lock
(
&
padctl
->
lock
);
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT
);
value
|=
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_GROUNDED
<<
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT
;
}
else
{
value
&=
~
(
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK
<<
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT
);
value
|=
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING
<<
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT
;
}
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_USB2_VBUS_ID
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
value
&=
~
ALL_WAKE_EVENTS
;
value
|=
USB2_PORT_WAKEUP_EVENT
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
usleep_range
(
10
,
20
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
value
&=
~
ALL_WAKE_EVENTS
;
value
|=
USB2_PORT_WAKE_INTERRUPT_ENABLE
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
mutex_unlock
(
&
padctl
->
lock
);
return
0
;
return
0
;
}
}
static
int
tegra210_usb2_phy_set_mode
(
struct
phy
*
phy
,
enum
phy_mode
mode
,
static
int
tegra210_utmi_disable_phy_wake
(
struct
tegra_xusb_lane
*
lane
)
int
submode
)
{
{
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
struct
tegra_xusb_usb2_port
*
port
=
tegra_xusb_find_usb2_port
(
padctl
,
unsigned
int
index
=
lane
->
index
;
lane
->
index
);
u32
value
;
int
err
=
0
;
mutex_lock
(
&
padctl
->
lock
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
value
&=
~
ALL_WAKE_EVENTS
;
value
&=
~
USB2_PORT_WAKE_INTERRUPT_ENABLE
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
usleep_range
(
10
,
20
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
value
&=
~
ALL_WAKE_EVENTS
;
value
|=
USB2_PORT_WAKEUP_EVENT
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
mutex_unlock
(
&
padctl
->
lock
);
return
0
;
}
static
bool
tegra210_utmi_phy_remote_wake_detected
(
struct
tegra_xusb_lane
*
lane
)
{
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
unsigned
int
index
=
lane
->
index
;
u32
value
;
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
if
((
value
&
USB2_PORT_WAKE_INTERRUPT_ENABLE
(
index
))
&&
(
value
&
USB2_PORT_WAKEUP_EVENT
(
index
)))
return
true
;
return
false
;
}
static
int
tegra210_hsic_enable_phy_wake
(
struct
tegra_xusb_lane
*
lane
)
{
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
unsigned
int
index
=
lane
->
index
;
u32
value
;
mutex_lock
(
&
padctl
->
lock
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
value
&=
~
ALL_WAKE_EVENTS
;
value
|=
USB2_HSIC_PORT_WAKEUP_EVENT
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
usleep_range
(
10
,
20
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
value
&=
~
ALL_WAKE_EVENTS
;
value
|=
USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
mutex_unlock
(
&
padctl
->
lock
);
return
0
;
}
static
int
tegra210_hsic_disable_phy_wake
(
struct
tegra_xusb_lane
*
lane
)
{
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
unsigned
int
index
=
lane
->
index
;
u32
value
;
mutex_lock
(
&
padctl
->
lock
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
value
&=
~
ALL_WAKE_EVENTS
;
value
&=
~
USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
usleep_range
(
10
,
20
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
value
&=
~
ALL_WAKE_EVENTS
;
value
|=
USB2_HSIC_PORT_WAKEUP_EVENT
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
mutex_unlock
(
&
padctl
->
lock
);
return
0
;
}
static
bool
tegra210_hsic_phy_remote_wake_detected
(
struct
tegra_xusb_lane
*
lane
)
{
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
unsigned
int
index
=
lane
->
index
;
u32
value
;
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM_0
);
if
((
value
&
USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE
(
index
))
&&
(
value
&
USB2_HSIC_PORT_WAKEUP_EVENT
(
index
)))
return
true
;
return
false
;
}
#define padctl_pmc_readl(_priv, _offset) \
({ \
u32 value; \
WARN(regmap_read(_priv->regmap, _offset, &value), "read %s failed\n", #_offset);\
value; \
})
#define padctl_pmc_writel(_priv, _value, _offset) \
WARN(regmap_write(_priv->regmap, _offset, _value), "write %s failed\n", #_offset)
static
int
tegra210_pmc_utmi_enable_phy_sleepwalk
(
struct
tegra_xusb_lane
*
lane
,
enum
usb_device_speed
speed
)
{
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
struct
tegra210_xusb_padctl
*
priv
=
to_tegra210_xusb_padctl
(
padctl
);
unsigned
int
port
=
lane
->
index
;
u32
value
,
tctrl
,
pctrl
,
rpd_ctrl
;
if
(
!
priv
->
regmap
)
return
-
EOPNOTSUPP
;
if
(
speed
>
USB_SPEED_HIGH
)
return
-
EINVAL
;
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_USB2_BIAS_PAD_CTL1
);
tctrl
=
TCTRL_VALUE
(
value
);
pctrl
=
PCTRL_VALUE
(
value
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_USB2_OTG_PADX_CTL1
(
port
));
rpd_ctrl
=
RPD_CTRL_VALUE
(
value
);
/* ensure sleepwalk logic is disabled */
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_UHSIC_SLEEP_CFG
(
port
));
value
&=
~
UTMIP_MASTER_ENABLE
(
port
);
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_UHSIC_SLEEP_CFG
(
port
));
/* ensure sleepwalk logics are in low power mode */
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_MASTER_CONFIG
);
value
|=
UTMIP_PWR
(
port
);
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_MASTER_CONFIG
);
/* set debounce time */
value
=
padctl_pmc_readl
(
priv
,
PMC_USB_DEBOUNCE_DEL
);
value
&=
~
UTMIP_LINE_DEB_CNT
(
~
0
);
value
|=
UTMIP_LINE_DEB_CNT
(
0x1
);
padctl_pmc_writel
(
priv
,
value
,
PMC_USB_DEBOUNCE_DEL
);
/* ensure fake events of sleepwalk logic are desiabled */
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_UHSIC_FAKE
(
port
));
value
&=
~
(
UTMIP_FAKE_USBOP_VAL
(
port
)
|
UTMIP_FAKE_USBON_VAL
(
port
)
|
UTMIP_FAKE_USBOP_EN
(
port
)
|
UTMIP_FAKE_USBON_EN
(
port
));
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_UHSIC_FAKE
(
port
));
/* ensure wake events of sleepwalk logic are not latched */
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_UHSIC_LINE_WAKEUP
);
value
&=
~
UTMIP_LINE_WAKEUP_EN
(
port
);
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_UHSIC_LINE_WAKEUP
);
/* disable wake event triggers of sleepwalk logic */
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_UHSIC_SLEEP_CFG
(
port
));
value
&=
~
UTMIP_WAKE_VAL
(
port
,
~
0
);
value
|=
UTMIP_WAKE_VAL_NONE
(
port
);
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_UHSIC_SLEEP_CFG
(
port
));
/* power down the line state detectors of the pad */
value
=
padctl_pmc_readl
(
priv
,
PMC_USB_AO
);
value
|=
(
USBOP_VAL_PD
(
port
)
|
USBON_VAL_PD
(
port
));
padctl_pmc_writel
(
priv
,
value
,
PMC_USB_AO
);
/* save state per speed */
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_UHSIC_SAVED_STATE
(
port
));
value
&=
~
SPEED
(
port
,
~
0
);
switch
(
speed
)
{
case
USB_SPEED_HIGH
:
value
|=
UTMI_HS
(
port
);
break
;
case
USB_SPEED_FULL
:
value
|=
UTMI_FS
(
port
);
break
;
case
USB_SPEED_LOW
:
value
|=
UTMI_LS
(
port
);
break
;
default:
value
|=
UTMI_RST
(
port
);
break
;
}
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_UHSIC_SAVED_STATE
(
port
));
/* enable the trigger of the sleepwalk logic */
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_UHSIC_SLEEPWALK_CFG
(
port
));
value
|=
UTMIP_LINEVAL_WALK_EN
(
port
);
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_UHSIC_SLEEPWALK_CFG
(
port
));
/*
* Reset the walk pointer and clear the alarm of the sleepwalk logic,
* as well as capture the configuration of the USB2.0 pad.
*/
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_UHSIC_TRIGGERS
);
value
|=
UTMIP_CLR_WALK_PTR
(
port
)
|
UTMIP_CLR_WAKE_ALARM
(
port
)
|
UTMIP_CAP_CFG
(
port
);
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_UHSIC_TRIGGERS
);
/* program electrical parameters read from XUSB PADCTL */
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_TERM_PAD_CFG
);
value
&=
~
(
TCTRL_VAL
(
~
0
)
|
PCTRL_VAL
(
~
0
));
value
|=
(
TCTRL_VAL
(
tctrl
)
|
PCTRL_VAL
(
pctrl
));
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_TERM_PAD_CFG
);
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_PAD_CFGX
(
port
));
value
&=
~
RPD_CTRL_PX
(
~
0
);
value
|=
RPD_CTRL_PX
(
rpd_ctrl
);
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_PAD_CFGX
(
port
));
/*
* Set up the pull-ups and pull-downs of the signals during the four
* stages of sleepwalk. If a device is connected, program sleepwalk
* logic to maintain a J and keep driving K upon seeing remote wake.
*/
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_SLEEPWALK_PX
(
port
));
value
=
UTMIP_USBOP_RPD_A
|
UTMIP_USBOP_RPD_B
|
UTMIP_USBOP_RPD_C
|
UTMIP_USBOP_RPD_D
;
value
|=
UTMIP_USBON_RPD_A
|
UTMIP_USBON_RPD_B
|
UTMIP_USBON_RPD_C
|
UTMIP_USBON_RPD_D
;
switch
(
speed
)
{
case
USB_SPEED_HIGH
:
case
USB_SPEED_FULL
:
/* J state: D+/D- = high/low, K state: D+/D- = low/high */
value
|=
UTMIP_HIGHZ_A
;
value
|=
UTMIP_AP_A
;
value
|=
UTMIP_AN_B
|
UTMIP_AN_C
|
UTMIP_AN_D
;
break
;
case
USB_SPEED_LOW
:
/* J state: D+/D- = low/high, K state: D+/D- = high/low */
value
|=
UTMIP_HIGHZ_A
;
value
|=
UTMIP_AN_A
;
value
|=
UTMIP_AP_B
|
UTMIP_AP_C
|
UTMIP_AP_D
;
break
;
default:
value
|=
UTMIP_HIGHZ_A
|
UTMIP_HIGHZ_B
|
UTMIP_HIGHZ_C
|
UTMIP_HIGHZ_D
;
break
;
}
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_SLEEPWALK_PX
(
port
));
/* power up the line state detectors of the pad */
value
=
padctl_pmc_readl
(
priv
,
PMC_USB_AO
);
value
&=
~
(
USBOP_VAL_PD
(
port
)
|
USBON_VAL_PD
(
port
));
padctl_pmc_writel
(
priv
,
value
,
PMC_USB_AO
);
usleep_range
(
50
,
100
);
/* switch the electric control of the USB2.0 pad to PMC */
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_UHSIC_SLEEP_CFG
(
port
));
value
|=
UTMIP_FSLS_USE_PMC
(
port
)
|
UTMIP_PCTRL_USE_PMC
(
port
)
|
UTMIP_TCTRL_USE_PMC
(
port
);
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_UHSIC_SLEEP_CFG
(
port
));
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_UHSIC_SLEEP_CFG1
);
value
|=
UTMIP_RPD_CTRL_USE_PMC_PX
(
port
)
|
UTMIP_RPU_SWITC_LOW_USE_PMC_PX
(
port
);
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_UHSIC_SLEEP_CFG1
);
/* set the wake signaling trigger events */
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_UHSIC_SLEEP_CFG
(
port
));
value
&=
~
UTMIP_WAKE_VAL
(
port
,
~
0
);
value
|=
UTMIP_WAKE_VAL_ANY
(
port
);
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_UHSIC_SLEEP_CFG
(
port
));
/* enable the wake detection */
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_UHSIC_SLEEP_CFG
(
port
));
value
|=
UTMIP_MASTER_ENABLE
(
port
);
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_UHSIC_SLEEP_CFG
(
port
));
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_UHSIC_LINE_WAKEUP
);
value
|=
UTMIP_LINE_WAKEUP_EN
(
port
);
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_UHSIC_LINE_WAKEUP
);
return
0
;
}
static
int
tegra210_pmc_utmi_disable_phy_sleepwalk
(
struct
tegra_xusb_lane
*
lane
)
{
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
struct
tegra210_xusb_padctl
*
priv
=
to_tegra210_xusb_padctl
(
padctl
);
unsigned
int
port
=
lane
->
index
;
u32
value
;
if
(
!
priv
->
regmap
)
return
-
EOPNOTSUPP
;
/* disable the wake detection */
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_UHSIC_SLEEP_CFG
(
port
));
value
&=
~
UTMIP_MASTER_ENABLE
(
port
);
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_UHSIC_SLEEP_CFG
(
port
));
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_UHSIC_LINE_WAKEUP
);
value
&=
~
UTMIP_LINE_WAKEUP_EN
(
port
);
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_UHSIC_LINE_WAKEUP
);
/* switch the electric control of the USB2.0 pad to XUSB or USB2 */
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_UHSIC_SLEEP_CFG
(
port
));
value
&=
~
(
UTMIP_FSLS_USE_PMC
(
port
)
|
UTMIP_PCTRL_USE_PMC
(
port
)
|
UTMIP_TCTRL_USE_PMC
(
port
));
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_UHSIC_SLEEP_CFG
(
port
));
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_UHSIC_SLEEP_CFG1
);
value
&=
~
(
UTMIP_RPD_CTRL_USE_PMC_PX
(
port
)
|
UTMIP_RPU_SWITC_LOW_USE_PMC_PX
(
port
));
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_UHSIC_SLEEP_CFG1
);
/* disable wake event triggers of sleepwalk logic */
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_UHSIC_SLEEP_CFG
(
port
));
value
&=
~
UTMIP_WAKE_VAL
(
port
,
~
0
);
value
|=
UTMIP_WAKE_VAL_NONE
(
port
);
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_UHSIC_SLEEP_CFG
(
port
));
/* power down the line state detectors of the port */
value
=
padctl_pmc_readl
(
priv
,
PMC_USB_AO
);
value
|=
(
USBOP_VAL_PD
(
port
)
|
USBON_VAL_PD
(
port
));
padctl_pmc_writel
(
priv
,
value
,
PMC_USB_AO
);
/* clear alarm of the sleepwalk logic */
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_UHSIC_TRIGGERS
);
value
|=
UTMIP_CLR_WAKE_ALARM
(
port
);
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_UHSIC_TRIGGERS
);
return
0
;
}
static
int
tegra210_pmc_hsic_enable_phy_sleepwalk
(
struct
tegra_xusb_lane
*
lane
,
enum
usb_device_speed
speed
)
{
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
struct
tegra210_xusb_padctl
*
priv
=
to_tegra210_xusb_padctl
(
padctl
);
u32
value
;
if
(
!
priv
->
regmap
)
return
-
EOPNOTSUPP
;
/* ensure sleepwalk logic is disabled */
value
=
padctl_pmc_readl
(
priv
,
PMC_UHSIC_SLEEP_CFG
);
value
&=
~
UHSIC_MASTER_ENABLE
;
padctl_pmc_writel
(
priv
,
value
,
PMC_UHSIC_SLEEP_CFG
);
/* ensure sleepwalk logics are in low power mode */
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_MASTER_CONFIG
);
value
|=
UHSIC_PWR
;
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_MASTER_CONFIG
);
/* set debounce time */
value
=
padctl_pmc_readl
(
priv
,
PMC_USB_DEBOUNCE_DEL
);
value
&=
~
UHSIC_LINE_DEB_CNT
(
~
0
);
value
|=
UHSIC_LINE_DEB_CNT
(
0x1
);
padctl_pmc_writel
(
priv
,
value
,
PMC_USB_DEBOUNCE_DEL
);
/* ensure fake events of sleepwalk logic are desiabled */
value
=
padctl_pmc_readl
(
priv
,
PMC_UHSIC_FAKE
);
value
&=
~
(
UHSIC_FAKE_STROBE_VAL
|
UHSIC_FAKE_DATA_VAL
|
UHSIC_FAKE_STROBE_EN
|
UHSIC_FAKE_DATA_EN
);
padctl_pmc_writel
(
priv
,
value
,
PMC_UHSIC_FAKE
);
/* ensure wake events of sleepwalk logic are not latched */
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_UHSIC_LINE_WAKEUP
);
value
&=
~
UHSIC_LINE_WAKEUP_EN
;
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_UHSIC_LINE_WAKEUP
);
/* disable wake event triggers of sleepwalk logic */
value
=
padctl_pmc_readl
(
priv
,
PMC_UHSIC_SLEEP_CFG
);
value
&=
~
UHSIC_WAKE_VAL
(
~
0
);
value
|=
UHSIC_WAKE_VAL_NONE
;
padctl_pmc_writel
(
priv
,
value
,
PMC_UHSIC_SLEEP_CFG
);
/* power down the line state detectors of the port */
value
=
padctl_pmc_readl
(
priv
,
PMC_USB_AO
);
value
|=
STROBE_VAL_PD
|
DATA0_VAL_PD
|
DATA1_VAL_PD
;
padctl_pmc_writel
(
priv
,
value
,
PMC_USB_AO
);
/* save state, HSIC always comes up as HS */
value
=
padctl_pmc_readl
(
priv
,
PMC_UHSIC_SAVED_STATE
);
value
&=
~
UHSIC_MODE
(
~
0
);
value
|=
UHSIC_HS
;
padctl_pmc_writel
(
priv
,
value
,
PMC_UHSIC_SAVED_STATE
);
/* enable the trigger of the sleepwalk logic */
value
=
padctl_pmc_readl
(
priv
,
PMC_UHSIC_SLEEPWALK_CFG
);
value
|=
UHSIC_WAKE_WALK_EN
|
UHSIC_LINEVAL_WALK_EN
;
padctl_pmc_writel
(
priv
,
value
,
PMC_UHSIC_SLEEPWALK_CFG
);
/*
* Reset the walk pointer and clear the alarm of the sleepwalk logic,
* as well as capture the configuration of the USB2.0 port.
*/
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_UHSIC_TRIGGERS
);
value
|=
UHSIC_CLR_WALK_PTR
|
UHSIC_CLR_WAKE_ALARM
;
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_UHSIC_TRIGGERS
);
/*
* Set up the pull-ups and pull-downs of the signals during the four
* stages of sleepwalk. Maintain a HSIC IDLE and keep driving HSIC
* RESUME upon remote wake.
*/
value
=
padctl_pmc_readl
(
priv
,
PMC_UHSIC_SLEEPWALK_P0
);
value
=
UHSIC_DATA0_RPD_A
|
UHSIC_DATA0_RPU_B
|
UHSIC_DATA0_RPU_C
|
UHSIC_DATA0_RPU_D
|
UHSIC_STROBE_RPU_A
|
UHSIC_STROBE_RPD_B
|
UHSIC_STROBE_RPD_C
|
UHSIC_STROBE_RPD_D
;
padctl_pmc_writel
(
priv
,
value
,
PMC_UHSIC_SLEEPWALK_P0
);
/* power up the line state detectors of the port */
value
=
padctl_pmc_readl
(
priv
,
PMC_USB_AO
);
value
&=
~
(
STROBE_VAL_PD
|
DATA0_VAL_PD
|
DATA1_VAL_PD
);
padctl_pmc_writel
(
priv
,
value
,
PMC_USB_AO
);
usleep_range
(
50
,
100
);
/* set the wake signaling trigger events */
value
=
padctl_pmc_readl
(
priv
,
PMC_UHSIC_SLEEP_CFG
);
value
&=
~
UHSIC_WAKE_VAL
(
~
0
);
value
|=
UHSIC_WAKE_VAL_SD10
;
padctl_pmc_writel
(
priv
,
value
,
PMC_UHSIC_SLEEP_CFG
);
/* enable the wake detection */
value
=
padctl_pmc_readl
(
priv
,
PMC_UHSIC_SLEEP_CFG
);
value
|=
UHSIC_MASTER_ENABLE
;
padctl_pmc_writel
(
priv
,
value
,
PMC_UHSIC_SLEEP_CFG
);
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_UHSIC_LINE_WAKEUP
);
value
|=
UHSIC_LINE_WAKEUP_EN
;
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_UHSIC_LINE_WAKEUP
);
return
0
;
}
static
int
tegra210_pmc_hsic_disable_phy_sleepwalk
(
struct
tegra_xusb_lane
*
lane
)
{
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
struct
tegra210_xusb_padctl
*
priv
=
to_tegra210_xusb_padctl
(
padctl
);
u32
value
;
if
(
!
priv
->
regmap
)
return
-
EOPNOTSUPP
;
/* disable the wake detection */
value
=
padctl_pmc_readl
(
priv
,
PMC_UHSIC_SLEEP_CFG
);
value
&=
~
UHSIC_MASTER_ENABLE
;
padctl_pmc_writel
(
priv
,
value
,
PMC_UHSIC_SLEEP_CFG
);
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_UHSIC_LINE_WAKEUP
);
value
&=
~
UHSIC_LINE_WAKEUP_EN
;
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_UHSIC_LINE_WAKEUP
);
/* disable wake event triggers of sleepwalk logic */
value
=
padctl_pmc_readl
(
priv
,
PMC_UHSIC_SLEEP_CFG
);
value
&=
~
UHSIC_WAKE_VAL
(
~
0
);
value
|=
UHSIC_WAKE_VAL_NONE
;
padctl_pmc_writel
(
priv
,
value
,
PMC_UHSIC_SLEEP_CFG
);
/* power down the line state detectors of the port */
value
=
padctl_pmc_readl
(
priv
,
PMC_USB_AO
);
value
|=
STROBE_VAL_PD
|
DATA0_VAL_PD
|
DATA1_VAL_PD
;
padctl_pmc_writel
(
priv
,
value
,
PMC_USB_AO
);
/* clear alarm of the sleepwalk logic */
value
=
padctl_pmc_readl
(
priv
,
PMC_UTMIP_UHSIC_TRIGGERS
);
value
|=
UHSIC_CLR_WAKE_ALARM
;
padctl_pmc_writel
(
priv
,
value
,
PMC_UTMIP_UHSIC_TRIGGERS
);
return
0
;
}
static
int
tegra210_usb3_set_lfps_detect
(
struct
tegra_xusb_padctl
*
padctl
,
unsigned
int
index
,
bool
enable
)
{
struct
tegra_xusb_port
*
port
;
struct
tegra_xusb_lane
*
lane
;
u32
value
,
offset
;
port
=
tegra_xusb_find_port
(
padctl
,
"usb3"
,
index
);
if
(
!
port
)
return
-
ENODEV
;
lane
=
port
->
lane
;
if
(
lane
->
pad
==
padctl
->
pcie
)
offset
=
XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL1
(
lane
->
index
);
else
offset
=
XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL1
;
value
=
padctl_readl
(
padctl
,
offset
);
value
&=
~
((
XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_MASK
<<
XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_SHIFT
)
|
XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_TERM_EN
|
XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_MODE_OVRD
);
if
(
!
enable
)
{
value
|=
(
XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_VAL
<<
XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_SHIFT
)
|
XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_TERM_EN
|
XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_MODE_OVRD
;
}
padctl_writel
(
padctl
,
value
,
offset
);
return
0
;
}
#define TEGRA210_LANE(_name, _offset, _shift, _mask, _type) \
{ \
.name = _name, \
.offset = _offset, \
.shift = _shift, \
.mask = _mask, \
.num_funcs = ARRAY_SIZE(tegra210_##_type##_functions), \
.funcs = tegra210_##_type##_functions, \
}
static
const
char
*
tegra210_usb2_functions
[]
=
{
"snps"
,
"xusb"
,
"uart"
};
static
const
struct
tegra_xusb_lane_soc
tegra210_usb2_lanes
[]
=
{
TEGRA210_LANE
(
"usb2-0"
,
0x004
,
0
,
0x3
,
usb2
),
TEGRA210_LANE
(
"usb2-1"
,
0x004
,
2
,
0x3
,
usb2
),
TEGRA210_LANE
(
"usb2-2"
,
0x004
,
4
,
0x3
,
usb2
),
TEGRA210_LANE
(
"usb2-3"
,
0x004
,
6
,
0x3
,
usb2
),
};
static
struct
tegra_xusb_lane
*
tegra210_usb2_lane_probe
(
struct
tegra_xusb_pad
*
pad
,
struct
device_node
*
np
,
unsigned
int
index
)
{
struct
tegra_xusb_usb2_lane
*
usb2
;
int
err
;
usb2
=
kzalloc
(
sizeof
(
*
usb2
),
GFP_KERNEL
);
if
(
!
usb2
)
return
ERR_PTR
(
-
ENOMEM
);
INIT_LIST_HEAD
(
&
usb2
->
base
.
list
);
usb2
->
base
.
soc
=
&
pad
->
soc
->
lanes
[
index
];
usb2
->
base
.
index
=
index
;
usb2
->
base
.
pad
=
pad
;
usb2
->
base
.
np
=
np
;
err
=
tegra_xusb_lane_parse_dt
(
&
usb2
->
base
,
np
);
if
(
err
<
0
)
{
kfree
(
usb2
);
return
ERR_PTR
(
err
);
}
return
&
usb2
->
base
;
}
static
void
tegra210_usb2_lane_remove
(
struct
tegra_xusb_lane
*
lane
)
{
struct
tegra_xusb_usb2_lane
*
usb2
=
to_usb2_lane
(
lane
);
kfree
(
usb2
);
}
static
const
struct
tegra_xusb_lane_ops
tegra210_usb2_lane_ops
=
{
.
probe
=
tegra210_usb2_lane_probe
,
.
remove
=
tegra210_usb2_lane_remove
,
.
enable_phy_sleepwalk
=
tegra210_pmc_utmi_enable_phy_sleepwalk
,
.
disable_phy_sleepwalk
=
tegra210_pmc_utmi_disable_phy_sleepwalk
,
.
enable_phy_wake
=
tegra210_utmi_enable_phy_wake
,
.
disable_phy_wake
=
tegra210_utmi_disable_phy_wake
,
.
remote_wake_detected
=
tegra210_utmi_phy_remote_wake_detected
,
};
static
int
tegra210_usb2_phy_init
(
struct
phy
*
phy
)
{
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
unsigned
int
index
=
lane
->
index
;
struct
tegra_xusb_usb2_port
*
port
;
int
err
;
u32
value
;
port
=
tegra_xusb_find_usb2_port
(
padctl
,
index
);
if
(
!
port
)
{
dev_err
(
&
phy
->
dev
,
"no port found for USB2 lane %u
\n
"
,
index
);
return
-
ENODEV
;
}
if
(
port
->
supply
&&
port
->
mode
==
USB_DR_MODE_HOST
)
{
err
=
regulator_enable
(
port
->
supply
);
if
(
err
)
return
err
;
}
mutex_lock
(
&
padctl
->
lock
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_USB2_PAD_MUX
);
value
&=
~
(
XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK
<<
XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT
);
value
|=
XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_XUSB
<<
XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT
;
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_USB2_PAD_MUX
);
mutex_unlock
(
&
padctl
->
lock
);
return
0
;
}
static
int
tegra210_usb2_phy_exit
(
struct
phy
*
phy
)
{
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
struct
tegra_xusb_usb2_port
*
port
;
int
err
;
port
=
tegra_xusb_find_usb2_port
(
padctl
,
lane
->
index
);
if
(
!
port
)
{
dev_err
(
&
phy
->
dev
,
"no port found for USB2 lane %u
\n
"
,
lane
->
index
);
return
-
ENODEV
;
}
if
(
port
->
supply
&&
port
->
mode
==
USB_DR_MODE_HOST
)
{
err
=
regulator_disable
(
port
->
supply
);
if
(
err
)
return
err
;
}
return
0
;
}
static
int
tegra210_xusb_padctl_vbus_override
(
struct
tegra_xusb_padctl
*
padctl
,
bool
status
)
{
u32
value
;
dev_dbg
(
padctl
->
dev
,
"%s vbus override
\n
"
,
status
?
"set"
:
"clear"
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_USB2_VBUS_ID
);
if
(
status
)
{
value
|=
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON
;
value
&=
~
(
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK
<<
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT
);
value
|=
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING
<<
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT
;
}
else
{
value
&=
~
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON
;
}
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_USB2_VBUS_ID
);
return
0
;
}
static
int
tegra210_xusb_padctl_id_override
(
struct
tegra_xusb_padctl
*
padctl
,
bool
status
)
{
u32
value
;
dev_dbg
(
padctl
->
dev
,
"%s id override
\n
"
,
status
?
"set"
:
"clear"
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_USB2_VBUS_ID
);
if
(
status
)
{
if
(
value
&
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON
)
{
value
&=
~
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON
;
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_USB2_VBUS_ID
);
usleep_range
(
1000
,
2000
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_USB2_VBUS_ID
);
}
value
&=
~
(
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK
<<
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT
);
value
|=
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_GROUNDED
<<
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT
;
}
else
{
value
&=
~
(
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK
<<
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT
);
value
|=
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING
<<
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT
;
}
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_USB2_VBUS_ID
);
return
0
;
}
static
int
tegra210_usb2_phy_set_mode
(
struct
phy
*
phy
,
enum
phy_mode
mode
,
int
submode
)
{
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
struct
tegra_xusb_usb2_port
*
port
=
tegra_xusb_find_usb2_port
(
padctl
,
lane
->
index
);
int
err
=
0
;
mutex_lock
(
&
padctl
->
lock
);
mutex_lock
(
&
padctl
->
lock
);
...
@@ -1053,6 +1969,8 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
...
@@ -1053,6 +1969,8 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
priv
=
to_tegra210_xusb_padctl
(
padctl
);
priv
=
to_tegra210_xusb_padctl
(
padctl
);
mutex_lock
(
&
padctl
->
lock
);
if
(
port
->
usb3_port_fake
!=
-
1
)
{
if
(
port
->
usb3_port_fake
!=
-
1
)
{
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_SS_PORT_MAP
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_SS_PORT_MAP
);
value
&=
~
XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK
(
value
&=
~
XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK
(
...
@@ -1146,14 +2064,6 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
...
@@ -1146,14 +2064,6 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
padctl_writel
(
padctl
,
value
,
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1
(
index
));
XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1
(
index
));
if
(
port
->
supply
&&
port
->
mode
==
USB_DR_MODE_HOST
)
{
err
=
regulator_enable
(
port
->
supply
);
if
(
err
)
return
err
;
}
mutex_lock
(
&
padctl
->
lock
);
if
(
pad
->
enable
>
0
)
{
if
(
pad
->
enable
>
0
)
{
pad
->
enable
++
;
pad
->
enable
++
;
mutex_unlock
(
&
padctl
->
lock
);
mutex_unlock
(
&
padctl
->
lock
);
...
@@ -1162,7 +2072,7 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
...
@@ -1162,7 +2072,7 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
err
=
clk_prepare_enable
(
pad
->
clk
);
err
=
clk_prepare_enable
(
pad
->
clk
);
if
(
err
)
if
(
err
)
goto
disable_regulator
;
goto
out
;
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_USB2_BIAS_PAD_CTL1
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_USB2_BIAS_PAD_CTL1
);
value
&=
~
((
XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK
<<
value
&=
~
((
XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK
<<
...
@@ -1194,8 +2104,7 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
...
@@ -1194,8 +2104,7 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
return
0
;
return
0
;
disable_regulator:
out:
regulator_disable
(
port
->
supply
);
mutex_unlock
(
&
padctl
->
lock
);
mutex_unlock
(
&
padctl
->
lock
);
return
err
;
return
err
;
}
}
...
@@ -1254,7 +2163,6 @@ static int tegra210_usb2_phy_power_off(struct phy *phy)
...
@@ -1254,7 +2163,6 @@ static int tegra210_usb2_phy_power_off(struct phy *phy)
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_USB2_BIAS_PAD_CTL0
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_USB2_BIAS_PAD_CTL0
);
out:
out:
regulator_disable
(
port
->
supply
);
mutex_unlock
(
&
padctl
->
lock
);
mutex_unlock
(
&
padctl
->
lock
);
return
0
;
return
0
;
}
}
...
@@ -1376,6 +2284,11 @@ static void tegra210_hsic_lane_remove(struct tegra_xusb_lane *lane)
...
@@ -1376,6 +2284,11 @@ static void tegra210_hsic_lane_remove(struct tegra_xusb_lane *lane)
static
const
struct
tegra_xusb_lane_ops
tegra210_hsic_lane_ops
=
{
static
const
struct
tegra_xusb_lane_ops
tegra210_hsic_lane_ops
=
{
.
probe
=
tegra210_hsic_lane_probe
,
.
probe
=
tegra210_hsic_lane_probe
,
.
remove
=
tegra210_hsic_lane_remove
,
.
remove
=
tegra210_hsic_lane_remove
,
.
enable_phy_sleepwalk
=
tegra210_pmc_hsic_enable_phy_sleepwalk
,
.
disable_phy_sleepwalk
=
tegra210_pmc_hsic_disable_phy_sleepwalk
,
.
enable_phy_wake
=
tegra210_hsic_enable_phy_wake
,
.
disable_phy_wake
=
tegra210_hsic_disable_phy_wake
,
.
remote_wake_detected
=
tegra210_hsic_phy_remote_wake_detected
,
};
};
static
int
tegra210_hsic_phy_init
(
struct
phy
*
phy
)
static
int
tegra210_hsic_phy_init
(
struct
phy
*
phy
)
...
@@ -1391,14 +2304,12 @@ static int tegra210_hsic_phy_init(struct phy *phy)
...
@@ -1391,14 +2304,12 @@ static int tegra210_hsic_phy_init(struct phy *phy)
XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_SHIFT
;
XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_SHIFT
;
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_USB2_PAD_MUX
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_USB2_PAD_MUX
);
return
tegra210_xusb_padctl_enable
(
padctl
)
;
return
0
;
}
}
static
int
tegra210_hsic_phy_exit
(
struct
phy
*
phy
)
static
int
tegra210_hsic_phy_exit
(
struct
phy
*
phy
)
{
{
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
return
0
;
return
tegra210_xusb_padctl_disable
(
lane
->
pad
->
padctl
);
}
}
static
int
tegra210_hsic_phy_power_on
(
struct
phy
*
phy
)
static
int
tegra210_hsic_phy_power_on
(
struct
phy
*
phy
)
...
@@ -1536,69 +2447,240 @@ tegra210_hsic_pad_probe(struct tegra_xusb_padctl *padctl,
...
@@ -1536,69 +2447,240 @@ tegra210_hsic_pad_probe(struct tegra_xusb_padctl *padctl,
pad
->
ops
=
&
tegra210_hsic_lane_ops
;
pad
->
ops
=
&
tegra210_hsic_lane_ops
;
pad
->
soc
=
soc
;
pad
->
soc
=
soc
;
err
=
tegra_xusb_pad_init
(
pad
,
padctl
,
np
);
err
=
tegra_xusb_pad_init
(
pad
,
padctl
,
np
);
if
(
err
<
0
)
{
if
(
err
<
0
)
{
kfree
(
hsic
);
kfree
(
hsic
);
goto
out
;
goto
out
;
}
}
hsic
->
clk
=
devm_clk_get
(
&
pad
->
dev
,
"trk"
);
if
(
IS_ERR
(
hsic
->
clk
))
{
err
=
PTR_ERR
(
hsic
->
clk
);
dev_err
(
&
pad
->
dev
,
"failed to get trk clock: %d
\n
"
,
err
);
goto
unregister
;
}
err
=
tegra_xusb_pad_register
(
pad
,
&
tegra210_hsic_phy_ops
);
if
(
err
<
0
)
goto
unregister
;
dev_set_drvdata
(
&
pad
->
dev
,
pad
);
return
pad
;
unregister:
device_unregister
(
&
pad
->
dev
);
out:
return
ERR_PTR
(
err
);
}
static
void
tegra210_hsic_pad_remove
(
struct
tegra_xusb_pad
*
pad
)
{
struct
tegra_xusb_hsic_pad
*
hsic
=
to_hsic_pad
(
pad
);
kfree
(
hsic
);
}
static
const
struct
tegra_xusb_pad_ops
tegra210_hsic_ops
=
{
.
probe
=
tegra210_hsic_pad_probe
,
.
remove
=
tegra210_hsic_pad_remove
,
};
static
const
struct
tegra_xusb_pad_soc
tegra210_hsic_pad
=
{
.
name
=
"hsic"
,
.
num_lanes
=
ARRAY_SIZE
(
tegra210_hsic_lanes
),
.
lanes
=
tegra210_hsic_lanes
,
.
ops
=
&
tegra210_hsic_ops
,
};
static
void
tegra210_uphy_lane_iddq_enable
(
struct
tegra_xusb_lane
*
lane
)
{
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
u32
value
;
value
=
padctl_readl
(
padctl
,
lane
->
soc
->
regs
.
misc_ctl2
);
value
|=
XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ_OVRD
;
value
|=
XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ_OVRD
;
value
|=
XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_PWR_OVRD
;
value
|=
XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_PWR_OVRD
;
value
|=
XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ
;
value
&=
~
XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_MASK
;
value
|=
XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_VAL
;
value
|=
XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ
;
value
&=
~
XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_MASK
;
value
|=
XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_VAL
;
padctl_writel
(
padctl
,
value
,
lane
->
soc
->
regs
.
misc_ctl2
);
}
static
void
tegra210_uphy_lane_iddq_disable
(
struct
tegra_xusb_lane
*
lane
)
{
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
u32
value
;
value
=
padctl_readl
(
padctl
,
lane
->
soc
->
regs
.
misc_ctl2
);
value
&=
~
XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ_OVRD
;
value
&=
~
XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ_OVRD
;
value
&=
~
XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_PWR_OVRD
;
value
&=
~
XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_PWR_OVRD
;
value
|=
XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ
;
value
&=
~
XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_MASK
;
value
|=
XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_VAL
;
value
|=
XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ
;
value
&=
~
XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_MASK
;
value
|=
XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_VAL
;
padctl_writel
(
padctl
,
value
,
lane
->
soc
->
regs
.
misc_ctl2
);
}
#define TEGRA210_UPHY_LANE(_name, _offset, _shift, _mask, _type, _misc) \
{ \
.name = _name, \
.offset = _offset, \
.shift = _shift, \
.mask = _mask, \
.num_funcs = ARRAY_SIZE(tegra210_##_type##_functions), \
.funcs = tegra210_##_type##_functions, \
.regs.misc_ctl2 = _misc, \
}
static
const
char
*
tegra210_pcie_functions
[]
=
{
"pcie-x1"
,
"usb3-ss"
,
"sata"
,
"pcie-x4"
,
};
static
const
struct
tegra_xusb_lane_soc
tegra210_pcie_lanes
[]
=
{
TEGRA210_UPHY_LANE
(
"pcie-0"
,
0x028
,
12
,
0x3
,
pcie
,
XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2
(
0
)),
TEGRA210_UPHY_LANE
(
"pcie-1"
,
0x028
,
14
,
0x3
,
pcie
,
XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2
(
1
)),
TEGRA210_UPHY_LANE
(
"pcie-2"
,
0x028
,
16
,
0x3
,
pcie
,
XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2
(
2
)),
TEGRA210_UPHY_LANE
(
"pcie-3"
,
0x028
,
18
,
0x3
,
pcie
,
XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2
(
3
)),
TEGRA210_UPHY_LANE
(
"pcie-4"
,
0x028
,
20
,
0x3
,
pcie
,
XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2
(
4
)),
TEGRA210_UPHY_LANE
(
"pcie-5"
,
0x028
,
22
,
0x3
,
pcie
,
XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2
(
5
)),
TEGRA210_UPHY_LANE
(
"pcie-6"
,
0x028
,
24
,
0x3
,
pcie
,
XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2
(
6
)),
};
static
struct
tegra_xusb_usb3_port
*
tegra210_lane_to_usb3_port
(
struct
tegra_xusb_lane
*
lane
)
{
int
port
;
if
(
!
lane
||
!
lane
->
pad
||
!
lane
->
pad
->
padctl
)
return
NULL
;
port
=
tegra210_usb3_lane_map
(
lane
);
if
(
port
<
0
)
return
NULL
;
return
tegra_xusb_find_usb3_port
(
lane
->
pad
->
padctl
,
port
);
}
static
int
tegra210_usb3_phy_power_on
(
struct
phy
*
phy
)
{
struct
device
*
dev
=
&
phy
->
dev
;
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
struct
tegra_xusb_usb3_port
*
usb3
=
tegra210_lane_to_usb3_port
(
lane
);
unsigned
int
index
;
u32
value
;
if
(
!
usb3
)
{
dev_err
(
dev
,
"no USB3 port found for lane %u
\n
"
,
lane
->
index
);
return
-
ENODEV
;
}
index
=
usb3
->
base
.
index
;
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_SS_PORT_MAP
);
if
(
!
usb3
->
internal
)
value
&=
~
XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL
(
index
);
else
value
|=
XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL
(
index
);
value
&=
~
XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK
(
index
);
value
|=
XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP
(
index
,
usb3
->
port
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_SS_PORT_MAP
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_UPHY_USB3_PADX_ECTL1
(
index
));
value
&=
~
(
XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_MASK
<<
XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT
);
value
|=
XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_VAL
<<
XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT
;
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_UPHY_USB3_PADX_ECTL1
(
index
));
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_UPHY_USB3_PADX_ECTL2
(
index
));
value
&=
~
(
XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_MASK
<<
XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_SHIFT
);
value
|=
XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_VAL
<<
XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_SHIFT
;
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_UPHY_USB3_PADX_ECTL2
(
index
));
padctl_writel
(
padctl
,
XUSB_PADCTL_UPHY_USB3_PAD_ECTL3_RX_DFE_VAL
,
XUSB_PADCTL_UPHY_USB3_PADX_ECTL3
(
index
));
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_UPHY_USB3_PADX_ECTL4
(
index
));
value
&=
~
(
XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_MASK
<<
XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_SHIFT
);
value
|=
XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_VAL
<<
XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_SHIFT
;
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_UPHY_USB3_PADX_ECTL4
(
index
));
padctl_writel
(
padctl
,
XUSB_PADCTL_UPHY_USB3_PAD_ECTL6_RX_EQ_CTRL_H_VAL
,
XUSB_PADCTL_UPHY_USB3_PADX_ECTL6
(
index
));
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM1
);
value
&=
~
XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM1
);
hsic
->
clk
=
devm_clk_get
(
&
pad
->
dev
,
"trk"
);
usleep_range
(
100
,
200
);
if
(
IS_ERR
(
hsic
->
clk
))
{
err
=
PTR_ERR
(
hsic
->
clk
);
dev_err
(
&
pad
->
dev
,
"failed to get trk clock: %d
\n
"
,
err
);
goto
unregister
;
}
err
=
tegra_xusb_pad_register
(
pad
,
&
tegra210_hsic_phy_ops
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM1
);
if
(
err
<
0
)
value
&=
~
XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY
(
index
);
goto
unregister
;
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM1
)
;
dev_set_drvdata
(
&
pad
->
dev
,
pad
);
usleep_range
(
100
,
200
);
return
pad
;
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM1
);
value
&=
~
XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM1
);
unregister:
return
0
;
device_unregister
(
&
pad
->
dev
);
out:
return
ERR_PTR
(
err
);
}
}
static
void
tegra210_hsic_pad_remove
(
struct
tegra_xusb_pad
*
pad
)
static
int
tegra210_usb3_phy_power_off
(
struct
phy
*
phy
)
{
{
struct
tegra_xusb_hsic_pad
*
hsic
=
to_hsic_pad
(
pad
);
struct
device
*
dev
=
&
phy
->
dev
;
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
struct
tegra_xusb_usb3_port
*
usb3
=
tegra210_lane_to_usb3_port
(
lane
);
unsigned
int
index
;
u32
value
;
kfree
(
hsic
);
if
(
!
usb3
)
{
}
dev_err
(
dev
,
"no USB3 port found for lane %u
\n
"
,
lane
->
index
);
return
-
ENODEV
;
}
static
const
struct
tegra_xusb_pad_ops
tegra210_hsic_ops
=
{
index
=
usb3
->
base
.
index
;
.
probe
=
tegra210_hsic_pad_probe
,
.
remove
=
tegra210_hsic_pad_remove
,
};
static
const
struct
tegra_xusb_pad_soc
tegra210_hsic_pad
=
{
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM1
);
.
name
=
"hsic"
,
value
|=
XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY
(
index
);
.
num_lanes
=
ARRAY_SIZE
(
tegra210_hsic_lanes
),
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM1
);
.
lanes
=
tegra210_hsic_lanes
,
.
ops
=
&
tegra210_hsic_ops
,
};
static
const
char
*
tegra210_pcie_functions
[]
=
{
usleep_range
(
100
,
200
);
"pcie-x1"
,
"usb3-ss"
,
"sata"
,
"pcie-x4"
,
};
static
const
struct
tegra_xusb_lane_soc
tegra210_pcie_lanes
[]
=
{
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM1
);
TEGRA210_LANE
(
"pcie-0"
,
0x028
,
12
,
0x3
,
pcie
),
value
|=
XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN
(
index
);
TEGRA210_LANE
(
"pcie-1"
,
0x028
,
14
,
0x3
,
pcie
),
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM1
);
TEGRA210_LANE
(
"pcie-2"
,
0x028
,
16
,
0x3
,
pcie
),
TEGRA210_LANE
(
"pcie-3"
,
0x028
,
18
,
0x3
,
pcie
),
usleep_range
(
250
,
350
);
TEGRA210_LANE
(
"pcie-4"
,
0x028
,
20
,
0x3
,
pcie
),
TEGRA210_LANE
(
"pcie-5"
,
0x028
,
22
,
0x3
,
pcie
),
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM1
);
TEGRA210_LANE
(
"pcie-6"
,
0x028
,
24
,
0x3
,
pcie
),
value
|=
XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN
(
index
);
}
;
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM1
)
;
return
0
;
}
static
struct
tegra_xusb_lane
*
static
struct
tegra_xusb_lane
*
tegra210_pcie_lane_probe
(
struct
tegra_xusb_pad
*
pad
,
struct
device_node
*
np
,
tegra210_pcie_lane_probe
(
struct
tegra_xusb_pad
*
pad
,
struct
device_node
*
np
,
unsigned
int
index
)
unsigned
int
index
)
...
@@ -1635,40 +2717,40 @@ static void tegra210_pcie_lane_remove(struct tegra_xusb_lane *lane)
...
@@ -1635,40 +2717,40 @@ static void tegra210_pcie_lane_remove(struct tegra_xusb_lane *lane)
static
const
struct
tegra_xusb_lane_ops
tegra210_pcie_lane_ops
=
{
static
const
struct
tegra_xusb_lane_ops
tegra210_pcie_lane_ops
=
{
.
probe
=
tegra210_pcie_lane_probe
,
.
probe
=
tegra210_pcie_lane_probe
,
.
remove
=
tegra210_pcie_lane_remove
,
.
remove
=
tegra210_pcie_lane_remove
,
.
iddq_enable
=
tegra210_uphy_lane_iddq_enable
,
.
iddq_disable
=
tegra210_uphy_lane_iddq_disable
,
.
enable_phy_sleepwalk
=
tegra210_usb3_enable_phy_sleepwalk
,
.
disable_phy_sleepwalk
=
tegra210_usb3_disable_phy_sleepwalk
,
.
enable_phy_wake
=
tegra210_usb3_enable_phy_wake
,
.
disable_phy_wake
=
tegra210_usb3_disable_phy_wake
,
.
remote_wake_detected
=
tegra210_usb3_phy_remote_wake_detected
,
};
};
static
int
tegra210_pcie_phy_init
(
struct
phy
*
phy
)
static
int
tegra210_pcie_phy_init
(
struct
phy
*
phy
)
{
{
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
return
tegra210_xusb_padctl_enable
(
lane
->
pad
->
padctl
);
mutex_lock
(
&
padctl
->
lock
);
}
static
int
tegra210_pcie_phy_exit
(
struct
phy
*
phy
)
tegra210_uphy_init
(
padctl
);
{
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
mutex_unlock
(
&
padctl
->
lock
);
return
tegra210_xusb_padctl_disable
(
lane
->
pad
->
padctl
)
;
return
0
;
}
}
static
int
tegra210_pcie_phy_power_on
(
struct
phy
*
phy
)
static
int
tegra210_pcie_phy_power_on
(
struct
phy
*
phy
)
{
{
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
u32
value
;
int
err
=
0
;
int
err
;
mutex_lock
(
&
padctl
->
lock
);
mutex_lock
(
&
padctl
->
lock
);
err
=
tegra210_pex_uphy_enable
(
padctl
);
if
(
tegra_xusb_lane_check
(
lane
,
"usb3-ss"
))
if
(
err
<
0
)
err
=
tegra210_usb3_phy_power_on
(
phy
);
goto
unlock
;
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_USB3_PAD_MUX
);
value
|=
XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE
(
lane
->
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_USB3_PAD_MUX
);
unlock:
mutex_unlock
(
&
padctl
->
lock
);
mutex_unlock
(
&
padctl
->
lock
);
return
err
;
return
err
;
}
}
...
@@ -1677,20 +2759,19 @@ static int tegra210_pcie_phy_power_off(struct phy *phy)
...
@@ -1677,20 +2759,19 @@ static int tegra210_pcie_phy_power_off(struct phy *phy)
{
{
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
u32
value
;
int
err
=
0
;
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_USB3_PAD_MUX
);
mutex_lock
(
&
padctl
->
lock
);
value
&=
~
XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE
(
lane
->
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_USB3_PAD_MUX
);
tegra210_pex_uphy_disable
(
padctl
);
if
(
tegra_xusb_lane_check
(
lane
,
"usb3-ss"
))
err
=
tegra210_usb3_phy_power_off
(
phy
);
return
0
;
mutex_unlock
(
&
padctl
->
lock
);
return
err
;
}
}
static
const
struct
phy_ops
tegra210_pcie_phy_ops
=
{
static
const
struct
phy_ops
tegra210_pcie_phy_ops
=
{
.
init
=
tegra210_pcie_phy_init
,
.
init
=
tegra210_pcie_phy_init
,
.
exit
=
tegra210_pcie_phy_exit
,
.
power_on
=
tegra210_pcie_phy_power_on
,
.
power_on
=
tegra210_pcie_phy_power_on
,
.
power_off
=
tegra210_pcie_phy_power_off
,
.
power_off
=
tegra210_pcie_phy_power_off
,
.
owner
=
THIS_MODULE
,
.
owner
=
THIS_MODULE
,
...
@@ -1767,7 +2848,7 @@ static const struct tegra_xusb_pad_soc tegra210_pcie_pad = {
...
@@ -1767,7 +2848,7 @@ static const struct tegra_xusb_pad_soc tegra210_pcie_pad = {
};
};
static
const
struct
tegra_xusb_lane_soc
tegra210_sata_lanes
[]
=
{
static
const
struct
tegra_xusb_lane_soc
tegra210_sata_lanes
[]
=
{
TEGRA210_
LANE
(
"sata-0"
,
0x028
,
30
,
0x3
,
pcie
),
TEGRA210_
UPHY_LANE
(
"sata-0"
,
0x028
,
30
,
0x3
,
pcie
,
XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL2
),
};
};
static
struct
tegra_xusb_lane
*
static
struct
tegra_xusb_lane
*
...
@@ -1806,40 +2887,39 @@ static void tegra210_sata_lane_remove(struct tegra_xusb_lane *lane)
...
@@ -1806,40 +2887,39 @@ static void tegra210_sata_lane_remove(struct tegra_xusb_lane *lane)
static
const
struct
tegra_xusb_lane_ops
tegra210_sata_lane_ops
=
{
static
const
struct
tegra_xusb_lane_ops
tegra210_sata_lane_ops
=
{
.
probe
=
tegra210_sata_lane_probe
,
.
probe
=
tegra210_sata_lane_probe
,
.
remove
=
tegra210_sata_lane_remove
,
.
remove
=
tegra210_sata_lane_remove
,
.
iddq_enable
=
tegra210_uphy_lane_iddq_enable
,
.
iddq_disable
=
tegra210_uphy_lane_iddq_disable
,
.
enable_phy_sleepwalk
=
tegra210_usb3_enable_phy_sleepwalk
,
.
disable_phy_sleepwalk
=
tegra210_usb3_disable_phy_sleepwalk
,
.
enable_phy_wake
=
tegra210_usb3_enable_phy_wake
,
.
disable_phy_wake
=
tegra210_usb3_disable_phy_wake
,
.
remote_wake_detected
=
tegra210_usb3_phy_remote_wake_detected
,
};
};
static
int
tegra210_sata_phy_init
(
struct
phy
*
phy
)
static
int
tegra210_sata_phy_init
(
struct
phy
*
phy
)
{
{
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
return
tegra210_xusb_padctl_enable
(
lane
->
pad
->
padctl
);
mutex_lock
(
&
padctl
->
lock
);
}
static
int
tegra210_sata_phy_exit
(
struct
phy
*
phy
)
tegra210_uphy_init
(
padctl
);
{
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
return
tegra210_xusb_padctl_disable
(
lane
->
pad
->
padctl
);
mutex_unlock
(
&
padctl
->
lock
);
return
0
;
}
}
static
int
tegra210_sata_phy_power_on
(
struct
phy
*
phy
)
static
int
tegra210_sata_phy_power_on
(
struct
phy
*
phy
)
{
{
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
u32
value
;
int
err
=
0
;
int
err
;
mutex_lock
(
&
padctl
->
lock
);
mutex_lock
(
&
padctl
->
lock
);
err
=
tegra210_sata_uphy_enable
(
padctl
,
false
);
if
(
tegra_xusb_lane_check
(
lane
,
"usb3-ss"
))
if
(
err
<
0
)
err
=
tegra210_usb3_phy_power_on
(
phy
);
goto
unlock
;
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_USB3_PAD_MUX
);
value
|=
XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE
(
lane
->
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_USB3_PAD_MUX
);
unlock:
mutex_unlock
(
&
padctl
->
lock
);
mutex_unlock
(
&
padctl
->
lock
);
return
err
;
return
err
;
}
}
...
@@ -1848,20 +2928,19 @@ static int tegra210_sata_phy_power_off(struct phy *phy)
...
@@ -1848,20 +2928,19 @@ static int tegra210_sata_phy_power_off(struct phy *phy)
{
{
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
struct
tegra_xusb_padctl
*
padctl
=
lane
->
pad
->
padctl
;
u32
value
;
int
err
=
0
;
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_USB3_PAD_MUX
);
mutex_lock
(
&
padctl
->
lock
);
value
&=
~
XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE
(
lane
->
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_USB3_PAD_MUX
);
tegra210_sata_uphy_disable
(
lane
->
pad
->
padctl
);
if
(
tegra_xusb_lane_check
(
lane
,
"usb3-ss"
))
err
=
tegra210_usb3_phy_power_off
(
phy
);
return
0
;
mutex_unlock
(
&
padctl
->
lock
);
return
err
;
}
}
static
const
struct
phy_ops
tegra210_sata_phy_ops
=
{
static
const
struct
phy_ops
tegra210_sata_phy_ops
=
{
.
init
=
tegra210_sata_phy_init
,
.
init
=
tegra210_sata_phy_init
,
.
exit
=
tegra210_sata_phy_exit
,
.
power_on
=
tegra210_sata_phy_power_on
,
.
power_on
=
tegra210_sata_phy_power_on
,
.
power_off
=
tegra210_sata_phy_power_off
,
.
power_off
=
tegra210_sata_phy_power_off
,
.
owner
=
THIS_MODULE
,
.
owner
=
THIS_MODULE
,
...
@@ -1984,137 +3063,13 @@ static const struct tegra_xusb_port_ops tegra210_hsic_port_ops = {
...
@@ -1984,137 +3063,13 @@ static const struct tegra_xusb_port_ops tegra210_hsic_port_ops = {
static
int
tegra210_usb3_port_enable
(
struct
tegra_xusb_port
*
port
)
static
int
tegra210_usb3_port_enable
(
struct
tegra_xusb_port
*
port
)
{
{
struct
tegra_xusb_usb3_port
*
usb3
=
to_usb3_port
(
port
);
struct
tegra_xusb_padctl
*
padctl
=
port
->
padctl
;
struct
tegra_xusb_lane
*
lane
=
usb3
->
base
.
lane
;
unsigned
int
index
=
port
->
index
;
u32
value
;
int
err
;
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_SS_PORT_MAP
);
if
(
!
usb3
->
internal
)
value
&=
~
XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL
(
index
);
else
value
|=
XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL
(
index
);
value
&=
~
XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK
(
index
);
value
|=
XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP
(
index
,
usb3
->
port
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_SS_PORT_MAP
);
/*
* TODO: move this code into the PCIe/SATA PHY ->power_on() callbacks
* and conditionalize based on mux function? This seems to work, but
* might not be the exact proper sequence.
*/
err
=
regulator_enable
(
usb3
->
supply
);
if
(
err
<
0
)
return
err
;
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_UPHY_USB3_PADX_ECTL1
(
index
));
value
&=
~
(
XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_MASK
<<
XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT
);
value
|=
XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_VAL
<<
XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT
;
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_UPHY_USB3_PADX_ECTL1
(
index
));
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_UPHY_USB3_PADX_ECTL2
(
index
));
value
&=
~
(
XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_MASK
<<
XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_SHIFT
);
value
|=
XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_VAL
<<
XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_SHIFT
;
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_UPHY_USB3_PADX_ECTL2
(
index
));
padctl_writel
(
padctl
,
XUSB_PADCTL_UPHY_USB3_PAD_ECTL3_RX_DFE_VAL
,
XUSB_PADCTL_UPHY_USB3_PADX_ECTL3
(
index
));
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_UPHY_USB3_PADX_ECTL4
(
index
));
value
&=
~
(
XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_MASK
<<
XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_SHIFT
);
value
|=
XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_VAL
<<
XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_SHIFT
;
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_UPHY_USB3_PADX_ECTL4
(
index
));
padctl_writel
(
padctl
,
XUSB_PADCTL_UPHY_USB3_PAD_ECTL6_RX_EQ_CTRL_H_VAL
,
XUSB_PADCTL_UPHY_USB3_PADX_ECTL6
(
index
));
if
(
lane
->
pad
==
padctl
->
sata
)
err
=
tegra210_sata_uphy_enable
(
padctl
,
true
);
else
err
=
tegra210_pex_uphy_enable
(
padctl
);
if
(
err
)
{
dev_err
(
&
port
->
dev
,
"%s: failed to enable UPHY: %d
\n
"
,
__func__
,
err
);
return
err
;
}
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM1
);
value
&=
~
XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM1
);
usleep_range
(
100
,
200
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM1
);
value
&=
~
XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM1
);
usleep_range
(
100
,
200
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM1
);
value
&=
~
XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM1
);
return
0
;
return
0
;
}
}
static
void
tegra210_usb3_port_disable
(
struct
tegra_xusb_port
*
port
)
static
void
tegra210_usb3_port_disable
(
struct
tegra_xusb_port
*
port
)
{
{
struct
tegra_xusb_usb3_port
*
usb3
=
to_usb3_port
(
port
);
struct
tegra_xusb_padctl
*
padctl
=
port
->
padctl
;
struct
tegra_xusb_lane
*
lane
=
port
->
lane
;
unsigned
int
index
=
port
->
index
;
u32
value
;
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM1
);
value
|=
XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM1
);
usleep_range
(
100
,
200
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM1
);
value
|=
XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM1
);
usleep_range
(
250
,
350
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_ELPG_PROGRAM1
);
value
|=
XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN
(
index
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_ELPG_PROGRAM1
);
if
(
lane
->
pad
==
padctl
->
sata
)
tegra210_sata_uphy_disable
(
padctl
);
else
tegra210_pex_uphy_disable
(
padctl
);
regulator_disable
(
usb3
->
supply
);
value
=
padctl_readl
(
padctl
,
XUSB_PADCTL_SS_PORT_MAP
);
value
&=
~
XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK
(
index
);
value
|=
XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP
(
index
,
0x7
);
padctl_writel
(
padctl
,
value
,
XUSB_PADCTL_SS_PORT_MAP
);
}
}
static
const
struct
tegra_xusb_lane_map
tegra210_usb3_map
[]
=
{
{
0
,
"pcie"
,
6
},
{
1
,
"pcie"
,
5
},
{
2
,
"pcie"
,
0
},
{
2
,
"pcie"
,
3
},
{
3
,
"pcie"
,
4
},
{
3
,
"pcie"
,
4
},
{
0
,
NULL
,
0
}
};
static
struct
tegra_xusb_lane
*
static
struct
tegra_xusb_lane
*
tegra210_usb3_port_map
(
struct
tegra_xusb_port
*
port
)
tegra210_usb3_port_map
(
struct
tegra_xusb_port
*
port
)
{
{
...
@@ -2188,6 +3143,8 @@ tegra210_xusb_padctl_probe(struct device *dev,
...
@@ -2188,6 +3143,8 @@ tegra210_xusb_padctl_probe(struct device *dev,
const
struct
tegra_xusb_padctl_soc
*
soc
)
const
struct
tegra_xusb_padctl_soc
*
soc
)
{
{
struct
tegra210_xusb_padctl
*
padctl
;
struct
tegra210_xusb_padctl
*
padctl
;
struct
platform_device
*
pdev
;
struct
device_node
*
np
;
int
err
;
int
err
;
padctl
=
devm_kzalloc
(
dev
,
sizeof
(
*
padctl
),
GFP_KERNEL
);
padctl
=
devm_kzalloc
(
dev
,
sizeof
(
*
padctl
),
GFP_KERNEL
);
...
@@ -2201,6 +3158,26 @@ tegra210_xusb_padctl_probe(struct device *dev,
...
@@ -2201,6 +3158,26 @@ tegra210_xusb_padctl_probe(struct device *dev,
if
(
err
<
0
)
if
(
err
<
0
)
return
ERR_PTR
(
err
);
return
ERR_PTR
(
err
);
np
=
of_parse_phandle
(
dev
->
of_node
,
"nvidia,pmc"
,
0
);
if
(
!
np
)
{
dev_warn
(
dev
,
"nvidia,pmc property is missing
\n
"
);
goto
out
;
}
pdev
=
of_find_device_by_node
(
np
);
if
(
!
pdev
)
{
dev_warn
(
dev
,
"PMC device is not available
\n
"
);
goto
out
;
}
if
(
!
platform_get_drvdata
(
pdev
))
return
ERR_PTR
(
-
EPROBE_DEFER
);
padctl
->
regmap
=
dev_get_regmap
(
&
pdev
->
dev
,
"usb_sleepwalk"
);
if
(
!
padctl
->
regmap
)
dev_info
(
dev
,
"failed to find PMC regmap
\n
"
);
out:
return
&
padctl
->
base
;
return
&
padctl
->
base
;
}
}
...
@@ -2208,9 +3185,75 @@ static void tegra210_xusb_padctl_remove(struct tegra_xusb_padctl *padctl)
...
@@ -2208,9 +3185,75 @@ static void tegra210_xusb_padctl_remove(struct tegra_xusb_padctl *padctl)
{
{
}
}
static
void
tegra210_xusb_padctl_save
(
struct
tegra_xusb_padctl
*
padctl
)
{
struct
tegra210_xusb_padctl
*
priv
=
to_tegra210_xusb_padctl
(
padctl
);
priv
->
context
.
usb2_pad_mux
=
padctl_readl
(
padctl
,
XUSB_PADCTL_USB2_PAD_MUX
);
priv
->
context
.
usb2_port_cap
=
padctl_readl
(
padctl
,
XUSB_PADCTL_USB2_PORT_CAP
);
priv
->
context
.
ss_port_map
=
padctl_readl
(
padctl
,
XUSB_PADCTL_SS_PORT_MAP
);
priv
->
context
.
usb3_pad_mux
=
padctl_readl
(
padctl
,
XUSB_PADCTL_USB3_PAD_MUX
);
}
static
void
tegra210_xusb_padctl_restore
(
struct
tegra_xusb_padctl
*
padctl
)
{
struct
tegra210_xusb_padctl
*
priv
=
to_tegra210_xusb_padctl
(
padctl
);
struct
tegra_xusb_lane
*
lane
;
padctl_writel
(
padctl
,
priv
->
context
.
usb2_pad_mux
,
XUSB_PADCTL_USB2_PAD_MUX
);
padctl_writel
(
padctl
,
priv
->
context
.
usb2_port_cap
,
XUSB_PADCTL_USB2_PORT_CAP
);
padctl_writel
(
padctl
,
priv
->
context
.
ss_port_map
,
XUSB_PADCTL_SS_PORT_MAP
);
list_for_each_entry
(
lane
,
&
padctl
->
lanes
,
list
)
{
if
(
lane
->
pad
->
ops
->
iddq_enable
)
tegra210_uphy_lane_iddq_enable
(
lane
);
}
padctl_writel
(
padctl
,
priv
->
context
.
usb3_pad_mux
,
XUSB_PADCTL_USB3_PAD_MUX
);
list_for_each_entry
(
lane
,
&
padctl
->
lanes
,
list
)
{
if
(
lane
->
pad
->
ops
->
iddq_disable
)
tegra210_uphy_lane_iddq_disable
(
lane
);
}
}
static
int
tegra210_xusb_padctl_suspend_noirq
(
struct
tegra_xusb_padctl
*
padctl
)
{
mutex_lock
(
&
padctl
->
lock
);
tegra210_uphy_deinit
(
padctl
);
tegra210_xusb_padctl_save
(
padctl
);
mutex_unlock
(
&
padctl
->
lock
);
return
0
;
}
static
int
tegra210_xusb_padctl_resume_noirq
(
struct
tegra_xusb_padctl
*
padctl
)
{
mutex_lock
(
&
padctl
->
lock
);
tegra210_xusb_padctl_restore
(
padctl
);
tegra210_uphy_init
(
padctl
);
mutex_unlock
(
&
padctl
->
lock
);
return
0
;
}
static
const
struct
tegra_xusb_padctl_ops
tegra210_xusb_padctl_ops
=
{
static
const
struct
tegra_xusb_padctl_ops
tegra210_xusb_padctl_ops
=
{
.
probe
=
tegra210_xusb_padctl_probe
,
.
probe
=
tegra210_xusb_padctl_probe
,
.
remove
=
tegra210_xusb_padctl_remove
,
.
remove
=
tegra210_xusb_padctl_remove
,
.
suspend_noirq
=
tegra210_xusb_padctl_suspend_noirq
,
.
resume_noirq
=
tegra210_xusb_padctl_resume_noirq
,
.
usb3_set_lfps_detect
=
tegra210_usb3_set_lfps_detect
,
.
usb3_set_lfps_detect
=
tegra210_usb3_set_lfps_detect
,
.
hsic_set_idle
=
tegra210_hsic_set_idle
,
.
hsic_set_idle
=
tegra210_hsic_set_idle
,
.
vbus_override
=
tegra210_xusb_padctl_vbus_override
,
.
vbus_override
=
tegra210_xusb_padctl_vbus_override
,
...
...
drivers/phy/tegra/xusb.c
View file @
23eca831
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-License-Identifier: GPL-2.0-only
/*
/*
* Copyright (c) 2014-20
16
, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2014-20
20
, NVIDIA CORPORATION. All rights reserved.
*/
*/
#include <linux/delay.h>
#include <linux/delay.h>
...
@@ -321,11 +321,17 @@ static void tegra_xusb_lane_program(struct tegra_xusb_lane *lane)
...
@@ -321,11 +321,17 @@ static void tegra_xusb_lane_program(struct tegra_xusb_lane *lane)
if
(
soc
->
num_funcs
<
2
)
if
(
soc
->
num_funcs
<
2
)
return
;
return
;
if
(
lane
->
pad
->
ops
->
iddq_enable
)
lane
->
pad
->
ops
->
iddq_enable
(
lane
);
/* choose function */
/* choose function */
value
=
padctl_readl
(
padctl
,
soc
->
offset
);
value
=
padctl_readl
(
padctl
,
soc
->
offset
);
value
&=
~
(
soc
->
mask
<<
soc
->
shift
);
value
&=
~
(
soc
->
mask
<<
soc
->
shift
);
value
|=
lane
->
function
<<
soc
->
shift
;
value
|=
lane
->
function
<<
soc
->
shift
;
padctl_writel
(
padctl
,
value
,
soc
->
offset
);
padctl_writel
(
padctl
,
value
,
soc
->
offset
);
if
(
lane
->
pad
->
ops
->
iddq_disable
)
lane
->
pad
->
ops
->
iddq_disable
(
lane
);
}
}
static
void
tegra_xusb_pad_program
(
struct
tegra_xusb_pad
*
pad
)
static
void
tegra_xusb_pad_program
(
struct
tegra_xusb_pad
*
pad
)
...
@@ -376,7 +382,7 @@ static int tegra_xusb_setup_pads(struct tegra_xusb_padctl *padctl)
...
@@ -376,7 +382,7 @@ static int tegra_xusb_setup_pads(struct tegra_xusb_padctl *padctl)
return
0
;
return
0
;
}
}
static
bool
tegra_xusb_lane_check
(
struct
tegra_xusb_lane
*
lane
,
bool
tegra_xusb_lane_check
(
struct
tegra_xusb_lane
*
lane
,
const
char
*
function
)
const
char
*
function
)
{
{
const
char
*
func
=
lane
->
soc
->
funcs
[
lane
->
function
];
const
char
*
func
=
lane
->
soc
->
funcs
[
lane
->
function
];
...
@@ -1267,10 +1273,36 @@ static int tegra_xusb_padctl_remove(struct platform_device *pdev)
...
@@ -1267,10 +1273,36 @@ static int tegra_xusb_padctl_remove(struct platform_device *pdev)
return
err
;
return
err
;
}
}
static
int
tegra_xusb_padctl_suspend_noirq
(
struct
device
*
dev
)
{
struct
tegra_xusb_padctl
*
padctl
=
dev_get_drvdata
(
dev
);
if
(
padctl
->
soc
&&
padctl
->
soc
->
ops
&&
padctl
->
soc
->
ops
->
suspend_noirq
)
return
padctl
->
soc
->
ops
->
suspend_noirq
(
padctl
);
return
0
;
}
static
int
tegra_xusb_padctl_resume_noirq
(
struct
device
*
dev
)
{
struct
tegra_xusb_padctl
*
padctl
=
dev_get_drvdata
(
dev
);
if
(
padctl
->
soc
&&
padctl
->
soc
->
ops
&&
padctl
->
soc
->
ops
->
resume_noirq
)
return
padctl
->
soc
->
ops
->
resume_noirq
(
padctl
);
return
0
;
}
static
const
struct
dev_pm_ops
tegra_xusb_padctl_pm_ops
=
{
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS
(
tegra_xusb_padctl_suspend_noirq
,
tegra_xusb_padctl_resume_noirq
)
};
static
struct
platform_driver
tegra_xusb_padctl_driver
=
{
static
struct
platform_driver
tegra_xusb_padctl_driver
=
{
.
driver
=
{
.
driver
=
{
.
name
=
"tegra-xusb-padctl"
,
.
name
=
"tegra-xusb-padctl"
,
.
of_match_table
=
tegra_xusb_padctl_of_match
,
.
of_match_table
=
tegra_xusb_padctl_of_match
,
.
pm
=
&
tegra_xusb_padctl_pm_ops
,
},
},
.
probe
=
tegra_xusb_padctl_probe
,
.
probe
=
tegra_xusb_padctl_probe
,
.
remove
=
tegra_xusb_padctl_remove
,
.
remove
=
tegra_xusb_padctl_remove
,
...
@@ -1337,6 +1369,62 @@ int tegra_xusb_padctl_hsic_set_idle(struct tegra_xusb_padctl *padctl,
...
@@ -1337,6 +1369,62 @@ int tegra_xusb_padctl_hsic_set_idle(struct tegra_xusb_padctl *padctl,
}
}
EXPORT_SYMBOL_GPL
(
tegra_xusb_padctl_hsic_set_idle
);
EXPORT_SYMBOL_GPL
(
tegra_xusb_padctl_hsic_set_idle
);
int
tegra_xusb_padctl_enable_phy_sleepwalk
(
struct
tegra_xusb_padctl
*
padctl
,
struct
phy
*
phy
,
enum
usb_device_speed
speed
)
{
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
if
(
lane
->
pad
->
ops
->
enable_phy_sleepwalk
)
return
lane
->
pad
->
ops
->
enable_phy_sleepwalk
(
lane
,
speed
);
return
-
EOPNOTSUPP
;
}
EXPORT_SYMBOL_GPL
(
tegra_xusb_padctl_enable_phy_sleepwalk
);
int
tegra_xusb_padctl_disable_phy_sleepwalk
(
struct
tegra_xusb_padctl
*
padctl
,
struct
phy
*
phy
)
{
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
if
(
lane
->
pad
->
ops
->
disable_phy_sleepwalk
)
return
lane
->
pad
->
ops
->
disable_phy_sleepwalk
(
lane
);
return
-
EOPNOTSUPP
;
}
EXPORT_SYMBOL_GPL
(
tegra_xusb_padctl_disable_phy_sleepwalk
);
int
tegra_xusb_padctl_enable_phy_wake
(
struct
tegra_xusb_padctl
*
padctl
,
struct
phy
*
phy
)
{
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
if
(
lane
->
pad
->
ops
->
enable_phy_wake
)
return
lane
->
pad
->
ops
->
enable_phy_wake
(
lane
);
return
-
EOPNOTSUPP
;
}
EXPORT_SYMBOL_GPL
(
tegra_xusb_padctl_enable_phy_wake
);
int
tegra_xusb_padctl_disable_phy_wake
(
struct
tegra_xusb_padctl
*
padctl
,
struct
phy
*
phy
)
{
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
if
(
lane
->
pad
->
ops
->
disable_phy_wake
)
return
lane
->
pad
->
ops
->
disable_phy_wake
(
lane
);
return
-
EOPNOTSUPP
;
}
EXPORT_SYMBOL_GPL
(
tegra_xusb_padctl_disable_phy_wake
);
bool
tegra_xusb_padctl_remote_wake_detected
(
struct
tegra_xusb_padctl
*
padctl
,
struct
phy
*
phy
)
{
struct
tegra_xusb_lane
*
lane
=
phy_get_drvdata
(
phy
);
if
(
lane
->
pad
->
ops
->
remote_wake_detected
)
return
lane
->
pad
->
ops
->
remote_wake_detected
(
lane
);
return
false
;
}
EXPORT_SYMBOL_GPL
(
tegra_xusb_padctl_remote_wake_detected
);
int
tegra_xusb_padctl_usb3_set_lfps_detect
(
struct
tegra_xusb_padctl
*
padctl
,
int
tegra_xusb_padctl_usb3_set_lfps_detect
(
struct
tegra_xusb_padctl
*
padctl
,
unsigned
int
port
,
bool
enable
)
unsigned
int
port
,
bool
enable
)
{
{
...
...
drivers/phy/tegra/xusb.h
View file @
23eca831
/* SPDX-License-Identifier: GPL-2.0-only */
/* SPDX-License-Identifier: GPL-2.0-only */
/*
/*
* Copyright (c) 2014-20
15
, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2014-20
20
, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2015, Google Inc.
* Copyright (c) 2015, Google Inc.
*/
*/
...
@@ -11,6 +11,7 @@
...
@@ -11,6 +11,7 @@
#include <linux/mutex.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
#include <linux/workqueue.h>
#include <linux/usb/ch9.h>
#include <linux/usb/otg.h>
#include <linux/usb/otg.h>
#include <linux/usb/role.h>
#include <linux/usb/role.h>
...
@@ -35,6 +36,10 @@ struct tegra_xusb_lane_soc {
...
@@ -35,6 +36,10 @@ struct tegra_xusb_lane_soc {
const
char
*
const
*
funcs
;
const
char
*
const
*
funcs
;
unsigned
int
num_funcs
;
unsigned
int
num_funcs
;
struct
{
unsigned
int
misc_ctl2
;
}
regs
;
};
};
struct
tegra_xusb_lane
{
struct
tegra_xusb_lane
{
...
@@ -126,8 +131,17 @@ struct tegra_xusb_lane_ops {
...
@@ -126,8 +131,17 @@ struct tegra_xusb_lane_ops {
struct
device_node
*
np
,
struct
device_node
*
np
,
unsigned
int
index
);
unsigned
int
index
);
void
(
*
remove
)(
struct
tegra_xusb_lane
*
lane
);
void
(
*
remove
)(
struct
tegra_xusb_lane
*
lane
);
void
(
*
iddq_enable
)(
struct
tegra_xusb_lane
*
lane
);
void
(
*
iddq_disable
)(
struct
tegra_xusb_lane
*
lane
);
int
(
*
enable_phy_sleepwalk
)(
struct
tegra_xusb_lane
*
lane
,
enum
usb_device_speed
speed
);
int
(
*
disable_phy_sleepwalk
)(
struct
tegra_xusb_lane
*
lane
);
int
(
*
enable_phy_wake
)(
struct
tegra_xusb_lane
*
lane
);
int
(
*
disable_phy_wake
)(
struct
tegra_xusb_lane
*
lane
);
bool
(
*
remote_wake_detected
)(
struct
tegra_xusb_lane
*
lane
);
};
};
bool
tegra_xusb_lane_check
(
struct
tegra_xusb_lane
*
lane
,
const
char
*
function
);
/*
/*
* pads
* pads
*/
*/
...
@@ -230,7 +244,7 @@ struct tegra_xusb_pcie_pad {
...
@@ -230,7 +244,7 @@ struct tegra_xusb_pcie_pad {
struct
reset_control
*
rst
;
struct
reset_control
*
rst
;
struct
clk
*
pll
;
struct
clk
*
pll
;
unsigned
int
enable
;
bool
enable
;
};
};
static
inline
struct
tegra_xusb_pcie_pad
*
static
inline
struct
tegra_xusb_pcie_pad
*
...
@@ -245,7 +259,7 @@ struct tegra_xusb_sata_pad {
...
@@ -245,7 +259,7 @@ struct tegra_xusb_sata_pad {
struct
reset_control
*
rst
;
struct
reset_control
*
rst
;
struct
clk
*
pll
;
struct
clk
*
pll
;
unsigned
int
enable
;
bool
enable
;
};
};
static
inline
struct
tegra_xusb_sata_pad
*
static
inline
struct
tegra_xusb_sata_pad
*
...
@@ -388,6 +402,8 @@ struct tegra_xusb_padctl_ops {
...
@@ -388,6 +402,8 @@ struct tegra_xusb_padctl_ops {
const
struct
tegra_xusb_padctl_soc
*
soc
);
const
struct
tegra_xusb_padctl_soc
*
soc
);
void
(
*
remove
)(
struct
tegra_xusb_padctl
*
padctl
);
void
(
*
remove
)(
struct
tegra_xusb_padctl
*
padctl
);
int
(
*
suspend_noirq
)(
struct
tegra_xusb_padctl
*
padctl
);
int
(
*
resume_noirq
)(
struct
tegra_xusb_padctl
*
padctl
);
int
(
*
usb3_save_context
)(
struct
tegra_xusb_padctl
*
padctl
,
int
(
*
usb3_save_context
)(
struct
tegra_xusb_padctl
*
padctl
,
unsigned
int
index
);
unsigned
int
index
);
int
(
*
hsic_set_idle
)(
struct
tegra_xusb_padctl
*
padctl
,
int
(
*
hsic_set_idle
)(
struct
tegra_xusb_padctl
*
padctl
,
...
...
include/linux/phy/tegra/xusb.h
View file @
23eca831
/* SPDX-License-Identifier: GPL-2.0-only */
/* SPDX-License-Identifier: GPL-2.0-only */
/*
/*
* Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2016
-2020
, NVIDIA CORPORATION. All rights reserved.
*/
*/
#ifndef PHY_TEGRA_XUSB_H
#ifndef PHY_TEGRA_XUSB_H
...
@@ -8,6 +8,7 @@
...
@@ -8,6 +8,7 @@
struct
tegra_xusb_padctl
;
struct
tegra_xusb_padctl
;
struct
device
;
struct
device
;
enum
usb_device_speed
;
struct
tegra_xusb_padctl
*
tegra_xusb_padctl_get
(
struct
device
*
dev
);
struct
tegra_xusb_padctl
*
tegra_xusb_padctl_get
(
struct
device
*
dev
);
void
tegra_xusb_padctl_put
(
struct
tegra_xusb_padctl
*
padctl
);
void
tegra_xusb_padctl_put
(
struct
tegra_xusb_padctl
*
padctl
);
...
@@ -23,4 +24,11 @@ int tegra_xusb_padctl_set_vbus_override(struct tegra_xusb_padctl *padctl,
...
@@ -23,4 +24,11 @@ int tegra_xusb_padctl_set_vbus_override(struct tegra_xusb_padctl *padctl,
int
tegra_phy_xusb_utmi_port_reset
(
struct
phy
*
phy
);
int
tegra_phy_xusb_utmi_port_reset
(
struct
phy
*
phy
);
int
tegra_xusb_padctl_get_usb3_companion
(
struct
tegra_xusb_padctl
*
padctl
,
int
tegra_xusb_padctl_get_usb3_companion
(
struct
tegra_xusb_padctl
*
padctl
,
unsigned
int
port
);
unsigned
int
port
);
int
tegra_xusb_padctl_enable_phy_sleepwalk
(
struct
tegra_xusb_padctl
*
padctl
,
struct
phy
*
phy
,
enum
usb_device_speed
speed
);
int
tegra_xusb_padctl_disable_phy_sleepwalk
(
struct
tegra_xusb_padctl
*
padctl
,
struct
phy
*
phy
);
int
tegra_xusb_padctl_enable_phy_wake
(
struct
tegra_xusb_padctl
*
padctl
,
struct
phy
*
phy
);
int
tegra_xusb_padctl_disable_phy_wake
(
struct
tegra_xusb_padctl
*
padctl
,
struct
phy
*
phy
);
bool
tegra_xusb_padctl_remote_wake_detected
(
struct
tegra_xusb_padctl
*
padctl
,
struct
phy
*
phy
);
#endif
/* PHY_TEGRA_XUSB_H */
#endif
/* PHY_TEGRA_XUSB_H */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment