Compare commits
21 Commits
443c947541
...
2c90f5e347
| Author | SHA1 | Date | |
|---|---|---|---|
| 2c90f5e347 | |||
|
|
6aba9ba3f1 | ||
| a78a344fd0 | |||
| c1ee39366e | |||
|
|
3aa523ae1d | ||
|
|
a929bd5691 | ||
|
|
c40af5a19a | ||
|
|
51ab98c25e | ||
|
|
5f8f949eb9 | ||
|
|
93c3ba9fdf | ||
|
|
348ae91e1a | ||
|
|
8af3eba1f7 | ||
|
|
f83cd25494 | ||
|
|
e9c1ca6fac | ||
|
|
ddc4aa6226 | ||
|
|
0b7877f108 | ||
| 355f66d016 | |||
| 27390404e4 | |||
| b6d2c6e4c0 | |||
| fbbdd32f90 | |||
| aef62ecd2f |
@@ -12,10 +12,14 @@
|
||||
|
||||
dc@54200000 {
|
||||
nvidia,outputs = <&dsia &dsib &sor1>;
|
||||
/delete-property/ interconnects;
|
||||
/delete-property/ interconnect-names;
|
||||
};
|
||||
|
||||
dc@54240000 {
|
||||
nvidia,outputs = <&dsia &dsib &sor1>;
|
||||
/delete-property/ interconnects;
|
||||
/delete-property/ interconnect-names;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -29,14 +33,28 @@
|
||||
/delete-property/ pinctrl-names;
|
||||
};
|
||||
|
||||
emc: external-memory-controller@7001b000 {
|
||||
compatible = "nvidia,tegra210b01-emc";
|
||||
mc: memory-controller@70019000 {
|
||||
emc: external-memory-controller@7001b000 {
|
||||
compatible = "nvidia,tegra210b01-emc";
|
||||
reg = <0x0 0x7001b000 0x0 0x1000>,
|
||||
<0x0 0x7001e000 0x0 0x1000>,
|
||||
<0x0 0x7001f000 0x0 0x1000>;
|
||||
clocks = <&bpmp 0>;
|
||||
clock-names = "emc";
|
||||
interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
|
||||
|
||||
clocks = <&bpmp 0>;
|
||||
clock-names = "emc";
|
||||
#interconnect-cells = <0>;
|
||||
#cooling-cells = <2>;
|
||||
|
||||
nvidia,bpmp = <&bpmp>;
|
||||
/delete-property/ operating-points-v2;
|
||||
nvidia,bpmp = <&bpmp>;
|
||||
};
|
||||
};
|
||||
|
||||
/delete-node/ external-memory-controller@7001b000;
|
||||
|
||||
actmon@6000c800 {
|
||||
clocks = <&tegra_car TEGRA210_CLK_ACTMON>,
|
||||
<&bpmp 0>;
|
||||
};
|
||||
|
||||
mmc@700b0600 {
|
||||
@@ -89,7 +107,7 @@
|
||||
};
|
||||
};
|
||||
|
||||
bpmp@70016000 {
|
||||
bpmp: bpmp@70016000 {
|
||||
status = "okay";
|
||||
|
||||
#clock-cells = <1>;
|
||||
@@ -105,35 +123,31 @@
|
||||
|
||||
pinmux@700008d4 {
|
||||
status = "okay";
|
||||
sdmmc1_drv_code_1_8V: sdmmc1_drv_code {
|
||||
sdmmc1_1v8_drv: pinmux-sdmmc1-1v8-drv {
|
||||
sdmmc1 {
|
||||
nvidia,pins = "drive_sdmmc1";
|
||||
nvidia,pull-down-strength = <8>;
|
||||
nvidia,pull-up-strength = <8>;
|
||||
nvidia,pull-down-strength = <0x8>;
|
||||
nvidia,pull-up-strength = <0x8>;
|
||||
};
|
||||
};
|
||||
|
||||
sdmmc1_default_drv_code_3_3V: sdmmc1_default_drv_code {
|
||||
sdmmc1_3v3_drv: pinmux-sdmmc1-3v3-drv {
|
||||
sdmmc1 {
|
||||
nvidia,pins = "drive_sdmmc1";
|
||||
nvidia,pull-down-strength = <8>;
|
||||
nvidia,pull-up-strength = <8>;
|
||||
nvidia,pull-down-strength = <0x8>;
|
||||
nvidia,pull-up-strength = <0x8>;
|
||||
};
|
||||
};
|
||||
|
||||
sdmmc3_drv_code_1_8V: sdmmc3_drv_code {
|
||||
sdmmc3_1v8_drv: pinmux-sdmmc3-1v8-drv {
|
||||
sdmmc3 {
|
||||
nvidia,pins = "drive_sdmmc3";
|
||||
nvidia,pull-down-strength = <8>;
|
||||
nvidia,pull-up-strength = <8>;
|
||||
nvidia,pull-down-strength = <0x8>;
|
||||
nvidia,pull-up-strength = <0x8>;
|
||||
};
|
||||
};
|
||||
|
||||
sdmmc3_default_drv_code_3_3V: sdmmc3_default_drv_code {
|
||||
sdmmc3_3v3_drv: pinmux-sdmmc3-3v3-drv {
|
||||
sdmmc3 {
|
||||
nvidia,pins = "drive_sdmmc3";
|
||||
nvidia,pull-down-strength = <8>;
|
||||
nvidia,pull-up-strength = <8>;
|
||||
nvidia,pull-down-strength = <0x8>;
|
||||
nvidia,pull-up-strength = <0x8>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2173,6 +2173,15 @@ static int fw_devlink_create_devlink(struct device *con,
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* SYNC_STATE_ONLY links are useless once a consumer device has probed.
|
||||
* So, only create it if the consumer hasn't probed yet.
|
||||
*/
|
||||
if (flags & DL_FLAG_SYNC_STATE_ONLY &&
|
||||
con->links.status != DL_DEV_NO_DRIVER &&
|
||||
con->links.status != DL_DEV_PROBING)
|
||||
goto out;
|
||||
|
||||
if (con != sup_dev && !device_link_add(con, sup_dev, flags)) {
|
||||
dev_err(con, "Failed to create device link (0x%x) with %s\n",
|
||||
flags, dev_name(sup_dev));
|
||||
|
||||
@@ -503,6 +503,72 @@ static unsigned long tegra210_input_freq[] = {
|
||||
#define PLLE_SS_COEFFICIENTS_VAL \
|
||||
(PLLE_SS_MAX_VAL | PLLE_SS_INC_VAL | PLLE_SS_INCINTRV_VAL)
|
||||
|
||||
bool tegra210b01_plle_hw_sequence_is_enabled(void)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl_relaxed(clk_base + PLLE_AUX);
|
||||
if (value & PLLE_AUX_SEQ_ENABLE)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tegra210b01_plle_hw_sequence_is_enabled);
|
||||
|
||||
int tegra210b01_plle_hw_sequence_start(void)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
if (tegra210b01_plle_hw_sequence_is_enabled())
|
||||
return 0;
|
||||
|
||||
/* skip if PLLE is not enabled yet */
|
||||
value = readl_relaxed(clk_base + PLLE_MISC0);
|
||||
if (!(value & PLLE_MISC_LOCK))
|
||||
return -EIO;
|
||||
|
||||
value &= ~PLLE_MISC_IDDQ_SW_CTRL;
|
||||
writel_relaxed(value, clk_base + PLLE_MISC0);
|
||||
|
||||
value = readl_relaxed(clk_base + PLLE_AUX);
|
||||
value |= (PLLE_AUX_USE_LOCKDET | PLLE_AUX_SS_SEQ_INCLUDE);
|
||||
value &= ~(PLLE_AUX_ENABLE_SWCTL | PLLE_AUX_SS_SWCTL);
|
||||
writel_relaxed(value, clk_base + PLLE_AUX);
|
||||
|
||||
fence_udelay(1, clk_base);
|
||||
|
||||
value |= PLLE_AUX_SEQ_ENABLE;
|
||||
writel_relaxed(value, clk_base + PLLE_AUX);
|
||||
|
||||
fence_udelay(1, clk_base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tegra210b01_plle_hw_sequence_start);
|
||||
|
||||
void tegra210b01_xusb_pll_hw_control_enable(void)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl_relaxed(clk_base + XUSBIO_PLL_CFG0);
|
||||
val &= ~(XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL |
|
||||
XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL);
|
||||
val |= XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET |
|
||||
XUSBIO_PLL_CFG0_PADPLL_SLEEP_IDDQ;
|
||||
writel_relaxed(val, clk_base + XUSBIO_PLL_CFG0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tegra210b01_xusb_pll_hw_control_enable);
|
||||
|
||||
void tegra210b01_xusb_pll_hw_sequence_start(void)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl_relaxed(clk_base + XUSBIO_PLL_CFG0);
|
||||
val |= XUSBIO_PLL_CFG0_SEQ_ENABLE;
|
||||
writel_relaxed(val, clk_base + XUSBIO_PLL_CFG0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tegra210b01_xusb_pll_hw_sequence_start);
|
||||
|
||||
static inline void _pll_misc_chk_default(void __iomem *base,
|
||||
struct tegra_clk_pll_params *params,
|
||||
u8 misc_num, u32 default_val, u32 mask)
|
||||
|
||||
@@ -395,8 +395,12 @@ static int tegra_emc_interconnect_init(struct tegra186_emc *emc)
|
||||
emc->provider.xlate = tegra_emc_of_icc_xlate;
|
||||
emc->provider.get_bw = tegra_emc_icc_get_init_bw;
|
||||
|
||||
printk("186-emc: init icc provider\n");
|
||||
|
||||
icc_provider_init(&emc->provider);
|
||||
|
||||
printk("186-emc: create icc node\n");
|
||||
|
||||
/* create External Memory Controller node */
|
||||
node = icc_node_create(TEGRA_ICC_EMC);
|
||||
if (IS_ERR(node)) {
|
||||
@@ -404,14 +408,20 @@ static int tegra_emc_interconnect_init(struct tegra186_emc *emc)
|
||||
goto err_msg;
|
||||
}
|
||||
|
||||
printk("186-emc: add icc node\n");
|
||||
|
||||
node->name = "External Memory Controller";
|
||||
icc_node_add(node, &emc->provider);
|
||||
|
||||
printk("186-emc: link emc icc to dram\n");
|
||||
|
||||
/* link External Memory Controller to External Memory (DRAM) */
|
||||
err = icc_link_create(node, TEGRA_ICC_EMEM);
|
||||
if (err)
|
||||
goto remove_nodes;
|
||||
|
||||
printk("186-emc: create dram node\n");
|
||||
|
||||
/* create External Memory node */
|
||||
node = icc_node_create(TEGRA_ICC_EMEM);
|
||||
if (IS_ERR(node)) {
|
||||
@@ -419,16 +429,23 @@ static int tegra_emc_interconnect_init(struct tegra186_emc *emc)
|
||||
goto remove_nodes;
|
||||
}
|
||||
|
||||
printk("186-emc: add dram node\n");
|
||||
|
||||
node->name = "External Memory (DRAM)";
|
||||
icc_node_add(node, &emc->provider);
|
||||
|
||||
printk("186-emc: register icc provider\n");
|
||||
|
||||
err = icc_provider_register(&emc->provider);
|
||||
if (err)
|
||||
goto remove_nodes;
|
||||
|
||||
printk("186-emc: icc init success\n");
|
||||
|
||||
return 0;
|
||||
|
||||
remove_nodes:
|
||||
printk("186-emc: removing icc nodes\n");
|
||||
icc_nodes_remove(&emc->provider);
|
||||
err_msg:
|
||||
dev_err(emc->dev, "failed to initialize ICC: %d\n", err);
|
||||
@@ -460,16 +477,24 @@ static int tegra186_emc_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, emc);
|
||||
emc->dev = &pdev->dev;
|
||||
|
||||
printk("186-emc: emc_rate_requests_init\n");
|
||||
|
||||
tegra_emc_rate_requests_init(emc);
|
||||
|
||||
printk("186-emc: mrq supported?\n");
|
||||
|
||||
if (tegra_bpmp_mrq_is_supported(emc->bpmp, MRQ_EMC_DVFS_LATENCY)) {
|
||||
printk("186-emc: mrq supported\n");
|
||||
err = tegra186_emc_get_emc_dvfs_latency(emc);
|
||||
if (err)
|
||||
goto put_bpmp;
|
||||
printk("186-emc: got emc dvfs latency\n");
|
||||
}
|
||||
|
||||
if (mc && mc->soc->icc_ops) {
|
||||
printk("186-emc: icc ops -> mrq supported?\n");
|
||||
if (tegra_bpmp_mrq_is_supported(emc->bpmp, MRQ_BWMGR_INT)) {
|
||||
printk("186-emc: mrq supported, configuring mc\n");
|
||||
mc->bwmgr_mrq_supported = true;
|
||||
|
||||
/*
|
||||
@@ -481,6 +506,8 @@ static int tegra186_emc_probe(struct platform_device *pdev)
|
||||
barrier();
|
||||
}
|
||||
|
||||
printk("186-emc: init emc interconnect\n");
|
||||
|
||||
/*
|
||||
* Initialize the ICC even if BPMP-FW doesn't support 'MRQ_BWMGR_INT'.
|
||||
* Use the flag 'mc->bwmgr_mrq_supported' within MC driver and return
|
||||
@@ -497,6 +524,7 @@ static int tegra186_emc_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
put_bpmp:
|
||||
printk("186-emc: FAILED\n");
|
||||
tegra_bpmp_put(emc->bpmp);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Author: Mike Rapoport <mike@compulab.co.il>
|
||||
*
|
||||
* Based on NVIDIA PCIe driver
|
||||
* Copyright (c) 2008-2009, NVIDIA Corporation.
|
||||
* Copyright (c) 2008-2020, NVIDIA Corporation.
|
||||
*
|
||||
* Bits taken from arch/arm/mach-dove/pcie.c
|
||||
*
|
||||
@@ -163,10 +163,64 @@
|
||||
|
||||
#define AFI_PLLE_CONTROL 0x160
|
||||
#define AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL (1 << 9)
|
||||
#define AFI_PLLE_CONTROL_BYPASS_PCIE2PLLE_CONTROL (1 << 8)
|
||||
#define AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN (1 << 1)
|
||||
#define AFI_PLLE_CONTROL_PCIE2PLLE_CONTROL_EN (1 << 0)
|
||||
|
||||
#define AFI_PEXBIAS_CTRL_0 0x168
|
||||
|
||||
|
||||
#define RP_PRIV_XP_DL 0x00000494
|
||||
#define RP_PRIV_XP_DL_GEN2_UPD_FC_TSHOLD (0x1ff << 1)
|
||||
|
||||
#define RP_L1_PM_SUBSTATES_CTL 0xc00
|
||||
#define RP_L1_PM_SUBSTATES_CTL_PCI_PM_L1_2 (0x1 << 0)
|
||||
#define RP_L1_PM_SUBSTATES_CTL_PCI_PM_L1_1 (0x1 << 1)
|
||||
#define RP_L1_PM_SUBSTATES_CTL_ASPM_L1_2 (0x1 << 2)
|
||||
#define RP_L1_PM_SUBSTATES_CTL_ASPM_L1_1 (0x1 << 3)
|
||||
#define RP_L1_PM_SUBSTATES_CTL_CM_RTIME_MASK (0xff << 8)
|
||||
#define RP_L1_PM_SUBSTATES_CTL_CM_RTIME_SHIFT 8
|
||||
#define RP_L1_PM_SUBSTATES_CTL_T_PWRN_SCL_MASK (0x3 << 16)
|
||||
#define RP_L1_PM_SUBSTATES_CTL_T_PWRN_SCL_SHIFT 16
|
||||
#define RP_L1_PM_SUBSTATES_CTL_T_PWRN_VAL_MASK (0x1f << 19)
|
||||
#define RP_L1_PM_SUBSTATES_CTL_T_PWRN_VAL_SHIFT 19
|
||||
#define RP_L1_PM_SUBSTATES_CTL_HIDE_CAP (0x1 << 24)
|
||||
|
||||
#define RP_L1_PM_SUBSTATES_1_CTL 0xc04
|
||||
#define RP_L1_PM_SUBSTATES_1_CTL_PWR_OFF_DLY_MASK 0x1fff
|
||||
#define RP_L1_PM_SUBSTATES_1_CTL_PWR_OFF_DLY 0x26
|
||||
#define RP_L1SS_1_CTL_CLKREQ_ASSERTED_DLY_MASK (0x1ff << 13)
|
||||
#define RP_L1SS_1_CTL_CLKREQ_ASSERTED_DLY (0x27 << 13)
|
||||
|
||||
#define RP_L1_PM_SUBSTATES_2_CTL 0xc08
|
||||
#define RP_L1_PM_SUBSTATES_2_CTL_T_L1_2_DLY_MASK 0x1fff
|
||||
#define RP_L1_PM_SUBSTATES_2_CTL_T_L1_2_DLY 0x4d
|
||||
#define RP_L1_PM_SUBSTATES_2_CTL_MICROSECOND_MASK (0xff << 13)
|
||||
#define RP_L1_PM_SUBSTATES_2_CTL_MICROSECOND (0x13 << 13)
|
||||
#define RP_L1_PM_SUBSTATES_2_CTL_MICROSECOND_COMP_MASK (0xf << 21)
|
||||
#define RP_L1_PM_SUBSTATES_2_CTL_MICROSECOND_COMP (0x2 << 21)
|
||||
|
||||
#define RP_RX_HDR_LIMIT 0x00000e00
|
||||
#define RP_RX_HDR_LIMIT_PW_MASK (0xff << 8)
|
||||
#define RP_RX_HDR_LIMIT_PW (0x0e << 8)
|
||||
|
||||
#define RP_TIMEOUT0 0xe24
|
||||
#define RP_TIMEOUT0_PAD_PWRUP_MASK 0xff
|
||||
#define RP_TIMEOUT0_PAD_PWRUP 0xa
|
||||
#define RP_TIMEOUT0_PAD_PWRUP_CM_MASK 0xffff00
|
||||
#define RP_TIMEOUT0_PAD_PWRUP_CM (0x180 << 8)
|
||||
#define RP_TIMEOUT0_PAD_SPDCHNG_GEN2_MASK (0xff << 24)
|
||||
#define RP_TIMEOUT0_PAD_SPDCHNG_GEN2 (0xa << 24)
|
||||
|
||||
#define RP_TIMEOUT1 0xe28
|
||||
#define RP_TIMEOUT1_RCVRY_SPD_SUCCESS_EIDLE_MASK (0xff << 16)
|
||||
#define RP_TIMEOUT1_RCVRY_SPD_SUCCESS_EIDLE (0x10 << 16)
|
||||
#define RP_TIMEOUT1_RCVRY_SPD_UNSUCCESS_EIDLE_MASK (0xff << 24)
|
||||
#define RP_TIMEOUT1_RCVRY_SPD_UNSUCCESS_EIDLE (0x74 << 24)
|
||||
|
||||
#define RP_ECTL_1_R1 0x00000e80
|
||||
#define RP_ECTL_1_R1_TX_DRV_AMP_1C_MASK 0x3f
|
||||
|
||||
#define RP_ECTL_2_R1 0x00000e84
|
||||
#define RP_ECTL_2_R1_RX_CTLE_1C_MASK 0xffff
|
||||
|
||||
@@ -180,6 +234,9 @@
|
||||
#define RP_ECTL_6_R1 0x00000e94
|
||||
#define RP_ECTL_6_R1_RX_EQ_CTRL_H_1C_MASK 0xffffffff
|
||||
|
||||
#define RP_ECTL_1_R2 0x00000ea0
|
||||
#define RP_ECTL_1_R2_TX_DRV_AMP_1C_MASK 0x3f
|
||||
|
||||
#define RP_ECTL_2_R2 0x00000ea4
|
||||
#define RP_ECTL_2_R2_RX_CTLE_1C_MASK 0xffff
|
||||
|
||||
@@ -199,6 +256,19 @@
|
||||
#define RP_VEND_XP_OPPORTUNISTIC_UPDATEFC (1 << 28)
|
||||
#define RP_VEND_XP_UPDATE_FC_THRESHOLD_MASK (0xff << 18)
|
||||
|
||||
#define RP_VEND_XP1 0xf04
|
||||
#define RP_VEND_XP1_LINK_PVT_CTL_IGNORE_L0S (1 << 23)
|
||||
#define RP_VEND_XP1_LINK_PVT_CTL_L1_ASPM_SUPPORT (1 << 21)
|
||||
|
||||
|
||||
#define RP_XP_REF 0xf30
|
||||
#define RP_XP_REF_MICROSECOND_LIMIT_MASK 0xff
|
||||
#define RP_XP_REF_MICROSECOND_LIMIT 0x14
|
||||
#define RP_XP_REF_MICROSECOND_ENABLE (1 << 8)
|
||||
#define RP_XP_REF_CPL_TO_OVERRIDE (1 << 13)
|
||||
#define RP_XP_REF_CPL_TO_CUSTOM_VALUE_MASK (0x1ffff << 14)
|
||||
#define RP_XP_REF_CPL_TO_CUSTOM_VALUE (0x1770 << 14)
|
||||
|
||||
#define RP_VEND_CTL0 0x00000f44
|
||||
#define RP_VEND_CTL0_DSK_RST_PULSE_WIDTH_MASK (0xf << 12)
|
||||
#define RP_VEND_CTL0_DSK_RST_PULSE_WIDTH (0x9 << 12)
|
||||
@@ -222,12 +292,23 @@
|
||||
#define RP_PRIV_MISC_TMS_CLK_CLAMP_THRESHOLD (0xf << 24)
|
||||
#define RP_PRIV_MISC_TMS_CLK_CLAMP_ENABLE (1 << 31)
|
||||
|
||||
#define RP_VEND_XP_PAD_PWRDN 0x00000f50
|
||||
#define RP_VEND_XP_PAD_PWRDN_L1_EN (1 << 0)
|
||||
#define RP_VEND_XP_PAD_PWRDN_DYNAMIC_EN (1 << 1)
|
||||
#define RP_VEND_XP_PAD_PWRDN_DISABLED_EN (1 << 2)
|
||||
#define RP_VEND_XP_PAD_PWRDN_L1_CLKREQ_EN (1 << 15)
|
||||
#define RP_VEND_XP_PAD_PWRDN_SLEEP_MODE_DYNAMIC_L1PP (3 << 5)
|
||||
#define RP_VEND_XP_PAD_PWRDN_SLEEP_MODE_L1_L1PP (3 << 3)
|
||||
#define RP_VEND_XP_PAD_PWRDN_SLEEP_MODE_L1_CLKREQ_L1PP (3 << 16)
|
||||
|
||||
#define RP_LINK_CONTROL_STATUS 0x00000090
|
||||
#define RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE 0x20000000
|
||||
#define RP_LINK_CONTROL_STATUS_LINKSTAT_MASK 0x3fff0000
|
||||
|
||||
#define RP_LINK_CONTROL_STATUS_2 0x000000b0
|
||||
|
||||
#define RP_L1_PM_SUBSTATES_CAP 0x144
|
||||
|
||||
#define PADS_CTL_SEL 0x0000009c
|
||||
|
||||
#define PADS_CTL 0x000000a0
|
||||
@@ -304,12 +385,18 @@ struct tegra_pcie_soc {
|
||||
bool program_deskew_time;
|
||||
bool update_fc_timer;
|
||||
bool has_cache_bars;
|
||||
bool enable_wrap;
|
||||
bool has_aspm_l1;
|
||||
bool has_aspm_l1ss;
|
||||
bool l1ss_rp_wake_fixup;
|
||||
struct {
|
||||
struct {
|
||||
u32 rp_ectl_1_r1;
|
||||
u32 rp_ectl_2_r1;
|
||||
u32 rp_ectl_4_r1;
|
||||
u32 rp_ectl_5_r1;
|
||||
u32 rp_ectl_6_r1;
|
||||
u32 rp_ectl_1_r2;
|
||||
u32 rp_ectl_2_r2;
|
||||
u32 rp_ectl_4_r2;
|
||||
u32 rp_ectl_5_r2;
|
||||
@@ -366,6 +453,8 @@ struct tegra_pcie_port {
|
||||
void __iomem *base;
|
||||
unsigned int index;
|
||||
unsigned int lanes;
|
||||
unsigned int aspm_state;
|
||||
bool supports_clkreq;
|
||||
|
||||
struct phy **phys;
|
||||
|
||||
@@ -394,6 +483,14 @@ static inline u32 pads_readl(struct tegra_pcie *pcie, unsigned long offset)
|
||||
return readl(pcie->pads + offset);
|
||||
}
|
||||
|
||||
static bool tegra_pcie_link_up(struct tegra_pcie_port *port)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl(port->base + RP_LINK_CONTROL_STATUS);
|
||||
return !!(value & RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE);
|
||||
}
|
||||
|
||||
/*
|
||||
* The configuration space mapping on Tegra is somewhat similar to the ECAM
|
||||
* defined by PCIe. However it deviates a bit in how the 4 bits for extended
|
||||
@@ -459,20 +556,50 @@ static void __iomem *tegra_pcie_map_bus(struct pci_bus *bus,
|
||||
static int tegra_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 *value)
|
||||
{
|
||||
struct tegra_pcie *pcie = bus->sysdata;
|
||||
struct pci_dev *bridge;
|
||||
struct tegra_pcie_port *port;
|
||||
|
||||
if (bus->number == 0)
|
||||
return pci_generic_config_read32(bus, devfn, where, size,
|
||||
value);
|
||||
|
||||
bridge = pcie_find_root_port(bus->self);
|
||||
|
||||
list_for_each_entry(port, &pcie->ports, list)
|
||||
if (port->index + 1 == PCI_SLOT(bridge->devfn))
|
||||
break;
|
||||
|
||||
/* If there is no link, then there is no device */
|
||||
if (!tegra_pcie_link_up(port)) {
|
||||
*value = 0xffffffff;
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
return pci_generic_config_read(bus, devfn, where, size, value);
|
||||
}
|
||||
|
||||
static int tegra_pcie_config_write(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 value)
|
||||
{
|
||||
struct tegra_pcie *pcie = bus->sysdata;
|
||||
struct tegra_pcie_port *port;
|
||||
struct pci_dev *bridge;
|
||||
|
||||
if (bus->number == 0)
|
||||
return pci_generic_config_write32(bus, devfn, where, size,
|
||||
value);
|
||||
|
||||
bridge = pcie_find_root_port(bus->self);
|
||||
|
||||
list_for_each_entry(port, &pcie->ports, list)
|
||||
if (port->index + 1 == PCI_SLOT(bridge->devfn))
|
||||
break;
|
||||
|
||||
/* If there is no link, then there is no device */
|
||||
if (!tegra_pcie_link_up(port))
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
|
||||
return pci_generic_config_write(bus, devfn, where, size, value);
|
||||
}
|
||||
|
||||
@@ -529,6 +656,44 @@ static void tegra_pcie_port_reset(struct tegra_pcie_port *port)
|
||||
}
|
||||
}
|
||||
|
||||
static void disable_aspm_l0s(struct tegra_pcie_port *port)
|
||||
{
|
||||
u32 val = 0;
|
||||
|
||||
val = readl(port->base + RP_VEND_XP1);
|
||||
val |= RP_VEND_XP1_LINK_PVT_CTL_IGNORE_L0S;
|
||||
writel(val, port->base + RP_VEND_XP1);
|
||||
}
|
||||
|
||||
static void disable_aspm_l10(struct tegra_pcie_port *port)
|
||||
{
|
||||
u32 val = 0;
|
||||
|
||||
val = readl(port->base + RP_VEND_XP1);
|
||||
val &= ~RP_VEND_XP1_LINK_PVT_CTL_L1_ASPM_SUPPORT;
|
||||
writel(val, port->base + RP_VEND_XP1);
|
||||
}
|
||||
|
||||
static void disable_aspm_l11(struct tegra_pcie_port *port)
|
||||
{
|
||||
u32 val = 0;
|
||||
|
||||
val = readl(port->base + RP_L1_PM_SUBSTATES_CTL);
|
||||
val &= ~RP_L1_PM_SUBSTATES_CTL_PCI_PM_L1_1;
|
||||
val &= ~RP_L1_PM_SUBSTATES_CTL_ASPM_L1_1;
|
||||
writel(val, port->base + RP_L1_PM_SUBSTATES_CTL);
|
||||
}
|
||||
|
||||
static void disable_aspm_l12(struct tegra_pcie_port *port)
|
||||
{
|
||||
u32 val = 0;
|
||||
|
||||
val = readl(port->base + RP_L1_PM_SUBSTATES_CTL);
|
||||
val &= ~RP_L1_PM_SUBSTATES_CTL_PCI_PM_L1_2;
|
||||
val &= ~RP_L1_PM_SUBSTATES_CTL_ASPM_L1_2;
|
||||
writel(val, port->base + RP_L1_PM_SUBSTATES_CTL);
|
||||
}
|
||||
|
||||
static void tegra_pcie_enable_rp_features(struct tegra_pcie_port *port)
|
||||
{
|
||||
const struct tegra_pcie_soc *soc = port->pcie->soc;
|
||||
@@ -565,6 +730,47 @@ static void tegra_pcie_enable_rp_features(struct tegra_pcie_port *port)
|
||||
}
|
||||
|
||||
writel(value, port->base + RP_PRIV_MISC);
|
||||
|
||||
if (soc->has_aspm_l1) {
|
||||
/* Advertise ASPM-L1 state capability*/
|
||||
value = readl(port->base + RP_VEND_XP1);
|
||||
value |= RP_VEND_XP1_LINK_PVT_CTL_L1_ASPM_SUPPORT;
|
||||
writel(value, port->base + RP_VEND_XP1);
|
||||
|
||||
/* Power saving configuration for L1 sleep/idle */
|
||||
value = readl(port->base + RP_VEND_XP_PAD_PWRDN);
|
||||
value |= RP_VEND_XP_PAD_PWRDN_DISABLED_EN;
|
||||
value |= RP_VEND_XP_PAD_PWRDN_DYNAMIC_EN;
|
||||
value |= RP_VEND_XP_PAD_PWRDN_L1_EN;
|
||||
value |= RP_VEND_XP_PAD_PWRDN_L1_CLKREQ_EN;
|
||||
value |= RP_VEND_XP_PAD_PWRDN_SLEEP_MODE_DYNAMIC_L1PP;
|
||||
value |= RP_VEND_XP_PAD_PWRDN_SLEEP_MODE_L1_L1PP;
|
||||
value |= RP_VEND_XP_PAD_PWRDN_SLEEP_MODE_L1_CLKREQ_L1PP;
|
||||
writel(value, port->base + RP_VEND_XP_PAD_PWRDN);
|
||||
|
||||
if (port->aspm_state & 0x1)
|
||||
disable_aspm_l0s(port);
|
||||
if (port->aspm_state & 0x2)
|
||||
disable_aspm_l10(port);
|
||||
}
|
||||
|
||||
if (soc->has_aspm_l1ss) {
|
||||
if (port->aspm_state & 0x2) {
|
||||
disable_aspm_l11(port);
|
||||
disable_aspm_l12(port);
|
||||
}
|
||||
if (port->aspm_state & 0x4)
|
||||
disable_aspm_l11(port);
|
||||
if (port->aspm_state & 0x8)
|
||||
disable_aspm_l12(port);
|
||||
|
||||
/* Disable L1SS capability if CLKREQ# is not present */
|
||||
if (!port->supports_clkreq) {
|
||||
value = readl(port->base + RP_L1_PM_SUBSTATES_CTL);
|
||||
value |= RP_L1_PM_SUBSTATES_CTL_HIDE_CAP;
|
||||
writel(value, port->base + RP_L1_PM_SUBSTATES_CTL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void tegra_pcie_program_ectl_settings(struct tegra_pcie_port *port)
|
||||
@@ -572,6 +778,11 @@ static void tegra_pcie_program_ectl_settings(struct tegra_pcie_port *port)
|
||||
const struct tegra_pcie_soc *soc = port->pcie->soc;
|
||||
u32 value;
|
||||
|
||||
value = readl(port->base + RP_ECTL_1_R1);
|
||||
value &= ~RP_ECTL_1_R1_TX_DRV_AMP_1C_MASK;
|
||||
value |= soc->ectl.regs.rp_ectl_1_r1;
|
||||
writel(value, port->base + RP_ECTL_1_R1);
|
||||
|
||||
value = readl(port->base + RP_ECTL_2_R1);
|
||||
value &= ~RP_ECTL_2_R1_RX_CTLE_1C_MASK;
|
||||
value |= soc->ectl.regs.rp_ectl_2_r1;
|
||||
@@ -593,6 +804,11 @@ static void tegra_pcie_program_ectl_settings(struct tegra_pcie_port *port)
|
||||
value |= soc->ectl.regs.rp_ectl_6_r1;
|
||||
writel(value, port->base + RP_ECTL_6_R1);
|
||||
|
||||
value = readl(port->base + RP_ECTL_1_R2);
|
||||
value &= ~RP_ECTL_1_R2_TX_DRV_AMP_1C_MASK;
|
||||
value |= soc->ectl.regs.rp_ectl_1_r2;
|
||||
writel(value, port->base + RP_ECTL_1_R2);
|
||||
|
||||
value = readl(port->base + RP_ECTL_2_R2);
|
||||
value &= ~RP_ECTL_2_R2_RX_CTLE_1C_MASK;
|
||||
value |= soc->ectl.regs.rp_ectl_2_r2;
|
||||
@@ -615,6 +831,26 @@ static void tegra_pcie_program_ectl_settings(struct tegra_pcie_port *port)
|
||||
writel(value, port->base + RP_ECTL_6_R2);
|
||||
}
|
||||
|
||||
static void tegra_pcie_enable_wrap(void)
|
||||
{
|
||||
u32 val;
|
||||
void __iomem *msel_base;
|
||||
|
||||
#define MSELECT_CONFIG_BASE 0x50060000
|
||||
#define MSELECT_CONFIG_WRAP_TO_INCR_SLAVE1 BIT(28)
|
||||
#define MSELECT_CONFIG_ERR_RESP_EN_SLAVE1 BIT(24)
|
||||
|
||||
/* Config MSELECT to support wrap trans for normal NC & GRE mapping */
|
||||
msel_base = ioremap(MSELECT_CONFIG_BASE, 4);
|
||||
val = readl(msel_base);
|
||||
/* Enable WRAP_TO_INCR_SLAVE1 */
|
||||
val |= MSELECT_CONFIG_WRAP_TO_INCR_SLAVE1;
|
||||
/* Disable ERR_RESP_EN_SLAVE1 */
|
||||
val &= ~MSELECT_CONFIG_ERR_RESP_EN_SLAVE1;
|
||||
writel(val, msel_base);
|
||||
iounmap(msel_base);
|
||||
}
|
||||
|
||||
static void tegra_pcie_apply_sw_fixup(struct tegra_pcie_port *port)
|
||||
{
|
||||
const struct tegra_pcie_soc *soc = port->pcie->soc;
|
||||
@@ -649,6 +885,76 @@ static void tegra_pcie_apply_sw_fixup(struct tegra_pcie_port *port)
|
||||
value &= ~PCI_EXP_LNKSTA_CLS;
|
||||
value |= PCI_EXP_LNKSTA_CLS_2_5GB;
|
||||
writel(value, port->base + RP_LINK_CONTROL_STATUS_2);
|
||||
|
||||
if (soc->enable_wrap)
|
||||
tegra_pcie_enable_wrap();
|
||||
|
||||
if (soc->has_aspm_l1ss) {
|
||||
/* Set port Common_Mode_Restore_Time to 30us */
|
||||
value = readl(port->base + RP_L1_PM_SUBSTATES_CTL);
|
||||
value &= ~RP_L1_PM_SUBSTATES_CTL_CM_RTIME_MASK;
|
||||
value |= (0x1E << RP_L1_PM_SUBSTATES_CTL_CM_RTIME_SHIFT);
|
||||
writel(value, port->base + RP_L1_PM_SUBSTATES_CTL);
|
||||
|
||||
/* set port T_POWER_ON to 70us */
|
||||
value = readl(port->base + RP_L1_PM_SUBSTATES_CTL);
|
||||
value &= ~(RP_L1_PM_SUBSTATES_CTL_T_PWRN_SCL_MASK |
|
||||
RP_L1_PM_SUBSTATES_CTL_T_PWRN_VAL_MASK);
|
||||
value |= (1 << RP_L1_PM_SUBSTATES_CTL_T_PWRN_SCL_SHIFT) |
|
||||
(7 << RP_L1_PM_SUBSTATES_CTL_T_PWRN_VAL_SHIFT);
|
||||
writel(value, port->base + RP_L1_PM_SUBSTATES_CTL);
|
||||
|
||||
/* Following is based on clk_m being 19.2 MHz */
|
||||
value = readl(port->base + RP_TIMEOUT0);
|
||||
value &= ~RP_TIMEOUT0_PAD_PWRUP_MASK;
|
||||
value |= RP_TIMEOUT0_PAD_PWRUP;
|
||||
value &= ~RP_TIMEOUT0_PAD_PWRUP_CM_MASK;
|
||||
value |= RP_TIMEOUT0_PAD_PWRUP_CM;
|
||||
value &= ~RP_TIMEOUT0_PAD_SPDCHNG_GEN2_MASK;
|
||||
value |= RP_TIMEOUT0_PAD_SPDCHNG_GEN2;
|
||||
writel(value, port->base + RP_TIMEOUT0);
|
||||
|
||||
value = readl(port->base + RP_TIMEOUT1);
|
||||
value &= ~RP_TIMEOUT1_RCVRY_SPD_SUCCESS_EIDLE_MASK;
|
||||
value |= RP_TIMEOUT1_RCVRY_SPD_SUCCESS_EIDLE;
|
||||
value &= ~RP_TIMEOUT1_RCVRY_SPD_UNSUCCESS_EIDLE_MASK;
|
||||
value |= RP_TIMEOUT1_RCVRY_SPD_UNSUCCESS_EIDLE;
|
||||
writel(value, port->base + RP_TIMEOUT1);
|
||||
|
||||
value = readl(port->base + RP_XP_REF);
|
||||
value &= ~RP_XP_REF_MICROSECOND_LIMIT_MASK;
|
||||
value |= RP_XP_REF_MICROSECOND_LIMIT;
|
||||
value |= RP_XP_REF_MICROSECOND_ENABLE;
|
||||
value |= RP_XP_REF_CPL_TO_OVERRIDE;
|
||||
value &= ~RP_XP_REF_CPL_TO_CUSTOM_VALUE_MASK;
|
||||
value |= RP_XP_REF_CPL_TO_CUSTOM_VALUE;
|
||||
writel(value, port->base + RP_XP_REF);
|
||||
|
||||
value = readl(port->base + RP_L1_PM_SUBSTATES_1_CTL);
|
||||
value &= ~RP_L1_PM_SUBSTATES_1_CTL_PWR_OFF_DLY_MASK;
|
||||
value |= RP_L1_PM_SUBSTATES_1_CTL_PWR_OFF_DLY;
|
||||
writel(value, port->base + RP_L1_PM_SUBSTATES_1_CTL);
|
||||
|
||||
value = readl(port->base + RP_L1_PM_SUBSTATES_2_CTL);
|
||||
value &= ~RP_L1_PM_SUBSTATES_2_CTL_T_L1_2_DLY_MASK;
|
||||
value |= RP_L1_PM_SUBSTATES_2_CTL_T_L1_2_DLY;
|
||||
value &= ~RP_L1_PM_SUBSTATES_2_CTL_MICROSECOND_MASK;
|
||||
value |= RP_L1_PM_SUBSTATES_2_CTL_MICROSECOND;
|
||||
value &= ~RP_L1_PM_SUBSTATES_2_CTL_MICROSECOND_COMP_MASK;
|
||||
value |= RP_L1_PM_SUBSTATES_2_CTL_MICROSECOND_COMP;
|
||||
writel(value, port->base + RP_L1_PM_SUBSTATES_2_CTL);
|
||||
}
|
||||
|
||||
if (soc->l1ss_rp_wake_fixup) {
|
||||
/*
|
||||
* Set CLKREQ asserted delay greater than Power_Off
|
||||
* time (2us) to avoid RP wakeup in L1.2.ENTRY
|
||||
*/
|
||||
value = readl(port->base + RP_L1_PM_SUBSTATES_1_CTL);
|
||||
value &= ~RP_L1SS_1_CTL_CLKREQ_ASSERTED_DLY_MASK;
|
||||
value |= RP_L1SS_1_CTL_CLKREQ_ASSERTED_DLY;
|
||||
writel(value, port->base + RP_L1_PM_SUBSTATES_1_CTL);
|
||||
}
|
||||
}
|
||||
|
||||
static void tegra_pcie_port_enable(struct tegra_pcie_port *port)
|
||||
@@ -661,8 +967,12 @@ static void tegra_pcie_port_enable(struct tegra_pcie_port *port)
|
||||
value = afi_readl(port->pcie, ctrl);
|
||||
value |= AFI_PEX_CTRL_REFCLK_EN;
|
||||
|
||||
if (soc->has_pex_clkreq_en)
|
||||
value |= AFI_PEX_CTRL_CLKREQ_EN;
|
||||
if (soc->has_pex_clkreq_en) {
|
||||
if (port->supports_clkreq)
|
||||
value &= ~AFI_PEX_CTRL_CLKREQ_EN;
|
||||
else
|
||||
value |= AFI_PEX_CTRL_CLKREQ_EN;
|
||||
}
|
||||
|
||||
value |= AFI_PEX_CTRL_OVERRIDE_EN;
|
||||
|
||||
@@ -1092,10 +1402,20 @@ static void tegra_pcie_enable_controller(struct tegra_pcie *pcie)
|
||||
unsigned long value;
|
||||
|
||||
/* enable PLL power down */
|
||||
if (pcie->phy) {
|
||||
if (soc->has_aspm_l1ss) {
|
||||
value = afi_readl(pcie, AFI_PLLE_CONTROL);
|
||||
value &= ~AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL;
|
||||
value |= AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN;
|
||||
|
||||
list_for_each_entry(port, &pcie->ports, list) {
|
||||
if (!port->supports_clkreq) {
|
||||
value &= ~AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
value &= ~AFI_PLLE_CONTROL_BYPASS_PCIE2PLLE_CONTROL;
|
||||
value |= AFI_PLLE_CONTROL_PCIE2PLLE_CONTROL_EN;
|
||||
afi_writel(pcie, value, AFI_PLLE_CONTROL);
|
||||
}
|
||||
|
||||
@@ -1527,6 +1847,11 @@ static void tegra_pcie_pme_turnoff(struct tegra_pcie_port *port)
|
||||
val = afi_readl(pcie, AFI_PCIE_PME);
|
||||
val &= ~(0x1 << soc->ports[port->index].pme.turnoff_bit);
|
||||
afi_writel(pcie, val, AFI_PCIE_PME);
|
||||
|
||||
/* PCIe link is in L2, bypass CLKREQ# control over PLLE power down */
|
||||
val = afi_readl(pcie, AFI_PLLE_CONTROL);
|
||||
val |= AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL;
|
||||
afi_writel(pcie, val, AFI_PLLE_CONTROL);
|
||||
}
|
||||
|
||||
static void tegra_pcie_msi_irq(struct irq_desc *desc)
|
||||
@@ -1876,6 +2201,10 @@ static int tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes,
|
||||
*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211;
|
||||
return 0;
|
||||
}
|
||||
} else if (of_device_is_compatible(np, "nvidia,tegra210b01-pcie")) {
|
||||
dev_info(dev, "4x1, 1x1 configuration\n");
|
||||
*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1;
|
||||
return 0;
|
||||
} else if (of_device_is_compatible(np, "nvidia,tegra124-pcie") ||
|
||||
of_device_is_compatible(np, "nvidia,tegra210-pcie")) {
|
||||
switch (lanes) {
|
||||
@@ -2209,6 +2538,14 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
|
||||
}
|
||||
}
|
||||
|
||||
err = of_property_read_u32(port, "nvidia,disable-aspm-states",
|
||||
&rp->aspm_state);
|
||||
if (err < 0)
|
||||
rp->aspm_state = 0;
|
||||
|
||||
rp->supports_clkreq = of_property_read_bool(port,
|
||||
"supports-clkreq");
|
||||
|
||||
list_add_tail(&rp->list, &pcie->ports);
|
||||
}
|
||||
|
||||
@@ -2402,6 +2739,10 @@ static const struct tegra_pcie_soc tegra20_pcie = {
|
||||
.program_deskew_time = false,
|
||||
.update_fc_timer = false,
|
||||
.has_cache_bars = true,
|
||||
.enable_wrap = false,
|
||||
.has_aspm_l1 = false,
|
||||
.has_aspm_l1ss = false,
|
||||
.l1ss_rp_wake_fixup = false,
|
||||
.ectl.enable = false,
|
||||
};
|
||||
|
||||
@@ -2431,6 +2772,10 @@ static const struct tegra_pcie_soc tegra30_pcie = {
|
||||
.program_deskew_time = false,
|
||||
.update_fc_timer = false,
|
||||
.has_cache_bars = false,
|
||||
.enable_wrap = false,
|
||||
.has_aspm_l1 = true,
|
||||
.has_aspm_l1ss = false,
|
||||
.l1ss_rp_wake_fixup = false,
|
||||
.ectl.enable = false,
|
||||
};
|
||||
|
||||
@@ -2452,6 +2797,10 @@ static const struct tegra_pcie_soc tegra124_pcie = {
|
||||
.program_deskew_time = false,
|
||||
.update_fc_timer = false,
|
||||
.has_cache_bars = false,
|
||||
.enable_wrap = false,
|
||||
.has_aspm_l1 = true,
|
||||
.has_aspm_l1ss = false,
|
||||
.l1ss_rp_wake_fixup = false,
|
||||
.ectl.enable = false,
|
||||
};
|
||||
|
||||
@@ -2475,12 +2824,18 @@ static const struct tegra_pcie_soc tegra210_pcie = {
|
||||
.program_deskew_time = true,
|
||||
.update_fc_timer = true,
|
||||
.has_cache_bars = false,
|
||||
.enable_wrap = true,
|
||||
.has_aspm_l1 = true,
|
||||
.has_aspm_l1ss = true,
|
||||
.l1ss_rp_wake_fixup = true,
|
||||
.ectl = {
|
||||
.regs = {
|
||||
.rp_ectl_1_r1 = 0x0000001f,
|
||||
.rp_ectl_2_r1 = 0x0000000f,
|
||||
.rp_ectl_4_r1 = 0x00000067,
|
||||
.rp_ectl_5_r1 = 0x55010000,
|
||||
.rp_ectl_6_r1 = 0x00000001,
|
||||
.rp_ectl_1_r2 = 0x0000001f,
|
||||
.rp_ectl_2_r2 = 0x0000008f,
|
||||
.rp_ectl_4_r2 = 0x000000c7,
|
||||
.rp_ectl_5_r2 = 0x55010000,
|
||||
@@ -2490,6 +2845,42 @@ static const struct tegra_pcie_soc tegra210_pcie = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct tegra_pcie_soc tegra210b01_pcie = {
|
||||
.num_ports = 2,
|
||||
.ports = tegra20_pcie_ports,
|
||||
.msi_base_shift = 8,
|
||||
.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
|
||||
.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
|
||||
.pads_refclk_cfg0 = 0x90b890b8,
|
||||
/* FC threshold is bit[25:18] */
|
||||
.update_fc_threshold = 0x01800000,
|
||||
.has_pex_clkreq_en = true,
|
||||
.has_pex_bias_ctrl = true,
|
||||
.has_intr_prsnt_sense = true,
|
||||
.has_cml_clk = true,
|
||||
.has_gen2 = true,
|
||||
.force_pca_enable = true,
|
||||
.program_uphy = true,
|
||||
.program_deskew_time = true,
|
||||
.update_fc_timer = true,
|
||||
.has_cache_bars = false,
|
||||
.ectl = {
|
||||
.regs = {
|
||||
.rp_ectl_1_r1 = 0x00000027,
|
||||
.rp_ectl_2_r1 = 0x0000000f,
|
||||
.rp_ectl_4_r1 = 0x00000067,
|
||||
.rp_ectl_5_r1 = 0x00000000,
|
||||
.rp_ectl_6_r1 = 0x00000000,
|
||||
.rp_ectl_1_r2 = 0x00000027,
|
||||
.rp_ectl_2_r2 = 0x0000008f,
|
||||
.rp_ectl_4_r2 = 0x000000c7,
|
||||
.rp_ectl_5_r2 = 0x00000000,
|
||||
.rp_ectl_6_r2 = 0x00000000,
|
||||
},
|
||||
.enable = true,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct tegra_pcie_port_soc tegra186_pcie_ports[] = {
|
||||
{ .pme.turnoff_bit = 0, .pme.ack_bit = 5 },
|
||||
{ .pme.turnoff_bit = 8, .pme.ack_bit = 10 },
|
||||
@@ -2516,11 +2907,16 @@ static const struct tegra_pcie_soc tegra186_pcie = {
|
||||
.program_deskew_time = false,
|
||||
.update_fc_timer = false,
|
||||
.has_cache_bars = false,
|
||||
.enable_wrap = false,
|
||||
.has_aspm_l1 = true,
|
||||
.has_aspm_l1ss = true,
|
||||
.l1ss_rp_wake_fixup = false,
|
||||
.ectl.enable = false,
|
||||
};
|
||||
|
||||
static const struct of_device_id tegra_pcie_of_match[] = {
|
||||
{ .compatible = "nvidia,tegra186-pcie", .data = &tegra186_pcie },
|
||||
{ .compatible = "nvidia,tegra210b01-pcie", .data = &tegra210b01_pcie },
|
||||
{ .compatible = "nvidia,tegra210-pcie", .data = &tegra210_pcie },
|
||||
{ .compatible = "nvidia,tegra124-pcie", .data = &tegra124_pcie },
|
||||
{ .compatible = "nvidia,tegra30-pcie", .data = &tegra30_pcie },
|
||||
@@ -2607,6 +3003,7 @@ static int tegra_pcie_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct pci_host_bridge *host;
|
||||
struct tegra_pcie_port *port;
|
||||
struct tegra_pcie *pcie;
|
||||
int err;
|
||||
|
||||
@@ -2645,6 +3042,8 @@ static int tegra_pcie_probe(struct platform_device *pdev)
|
||||
goto pm_runtime_put;
|
||||
}
|
||||
|
||||
pci_add_flags(PCI_REASSIGN_ALL_BUS);
|
||||
|
||||
host->ops = &tegra_pcie_ops;
|
||||
host->map_irq = tegra_pcie_map_irq;
|
||||
|
||||
|
||||
@@ -230,6 +230,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_MISC_PAD_PX_CTL8(x) (0x460 + (x) * (0x1c))
|
||||
#define CFG_ADDR(x) (((x) & 0xff) << 16)
|
||||
#define CFG_WDATA(x) (((x) & 0xffff) << 0)
|
||||
#define CFG_RESET (1 << 27)
|
||||
#define CFG_WS (1 << 24)
|
||||
|
||||
#define XUSB_PADCTL_UPHY_PLL_S0_CTL1 0x860
|
||||
|
||||
#define XUSB_PADCTL_UPHY_PLL_S0_CTL2 0x864
|
||||
@@ -240,6 +246,8 @@
|
||||
|
||||
#define XUSB_PADCTL_UPHY_PLL_S0_CTL8 0x87c
|
||||
|
||||
#define XUSB_PADCTL_UPHY_PLL_S0_CTL10 0x384
|
||||
|
||||
#define XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL1 0x960
|
||||
#define XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL2 0x964
|
||||
|
||||
@@ -407,6 +415,18 @@
|
||||
#define UHSIC_STROBE_RPD_C BIT(16)
|
||||
#define UHSIC_STROBE_RPD_D BIT(24)
|
||||
|
||||
struct init_data {
|
||||
u8 cfg_addr;
|
||||
u16 cfg_wdata;
|
||||
};
|
||||
|
||||
static struct init_data usb3_pll_g1_init_data[] = {
|
||||
{.cfg_addr = 0x2, .cfg_wdata = 0x0000},
|
||||
{.cfg_addr = 0x3, .cfg_wdata = 0x7051},
|
||||
{.cfg_addr = 0x25, .cfg_wdata = 0x0130},
|
||||
{.cfg_addr = 0x1E, .cfg_wdata = 0x0017},
|
||||
};
|
||||
|
||||
struct tegra210_xusb_fuse_calibration {
|
||||
u32 hs_curr_level[4];
|
||||
u32 hs_term_range_adj;
|
||||
@@ -444,11 +464,38 @@ static const struct tegra_xusb_lane_map tegra210_usb3_map[] = {
|
||||
{ 0, NULL, 0 }
|
||||
};
|
||||
|
||||
static const struct tegra_xusb_lane_map tegra210b01_usb3_map[] = {
|
||||
{ 0, "pcie", 5 },
|
||||
{ 1, "pcie", 4 },
|
||||
{ 2, "pcie", 1 },
|
||||
{ 0, NULL, 0 }
|
||||
};
|
||||
|
||||
static int t210b01_compatible(struct tegra_xusb_padctl *padctl)
|
||||
{
|
||||
struct device_node *np;
|
||||
const char *compatible;
|
||||
|
||||
np = padctl->dev->of_node;
|
||||
compatible = of_get_property(np, "compatible", NULL);
|
||||
|
||||
if (!compatible) {
|
||||
dev_err(padctl->dev, "Failed to get compatible property\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (strstr(compatible, "tegra210b01") != NULL)
|
||||
return 1;
|
||||
return 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++) {
|
||||
for (map = t210b01_compatible(lane->pad->padctl) ?
|
||||
tegra210b01_usb3_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",
|
||||
@@ -476,6 +523,12 @@ static int tegra210_pex_uphy_enable(struct tegra_xusb_padctl *padctl)
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (t210b01_compatible(padctl) == 1) {
|
||||
err = clk_prepare_enable(pcie->uphy_mgmt_clk);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (tegra210_plle_hw_sequence_is_enabled())
|
||||
goto skip_pll_init;
|
||||
|
||||
@@ -483,6 +536,18 @@ static int tegra210_pex_uphy_enable(struct tegra_xusb_padctl *padctl)
|
||||
if (err < 0)
|
||||
goto disable;
|
||||
|
||||
if (t210b01_compatible(padctl) == 1) {
|
||||
for (i = 0; i < ARRAY_SIZE(usb3_pll_g1_init_data); i++) {
|
||||
value = 0;
|
||||
value |= CFG_ADDR(usb3_pll_g1_init_data[i].cfg_addr);
|
||||
value |= CFG_WDATA(usb3_pll_g1_init_data[i].cfg_wdata);
|
||||
value |= CFG_RESET;
|
||||
value |= CFG_WS;
|
||||
padctl_writel(padctl, value,
|
||||
XUSB_PADCTL_UPHY_PLL_S0_CTL10);
|
||||
}
|
||||
}
|
||||
|
||||
value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
|
||||
value &= ~(XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_MASK <<
|
||||
XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT);
|
||||
@@ -676,6 +741,8 @@ reset:
|
||||
reset_control_assert(pcie->rst);
|
||||
disable:
|
||||
clk_disable_unprepare(pcie->pll);
|
||||
if (t210b01_compatible(padctl) == 1)
|
||||
clk_disable_unprepare(pcie->uphy_mgmt_clk);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -697,6 +764,8 @@ static void tegra210_pex_uphy_disable(struct tegra_xusb_padctl *padctl)
|
||||
}
|
||||
|
||||
clk_disable_unprepare(pcie->pll);
|
||||
if (t210b01_compatible(padctl) == 1)
|
||||
clk_disable_unprepare(pcie->uphy_mgmt_clk);
|
||||
}
|
||||
|
||||
/* must be called under padctl->lock */
|
||||
@@ -2560,12 +2629,12 @@ static const struct tegra_xusb_lane_soc tegra210_pcie_lanes[] = {
|
||||
};
|
||||
|
||||
static const struct tegra_xusb_lane_soc tegra210b01_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-0", 0x28, 12, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(0)),
|
||||
TEGRA210_UPHY_LANE("pcie-1", 0x28, 14, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(0)),
|
||||
TEGRA210_UPHY_LANE("pcie-2", 0x28, 16, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(0)),
|
||||
TEGRA210_UPHY_LANE("pcie-3", 0x28, 18, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(0)),
|
||||
TEGRA210_UPHY_LANE("pcie-4", 0x28, 20, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(0)),
|
||||
TEGRA210_UPHY_LANE("pcie-5", 0x28, 22, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(0)),
|
||||
};
|
||||
|
||||
static struct tegra_xusb_usb3_port *
|
||||
@@ -2816,6 +2885,15 @@ tegra210_pcie_pad_probe(struct tegra_xusb_padctl *padctl,
|
||||
goto unregister;
|
||||
}
|
||||
|
||||
if (t210b01_compatible(padctl) == 1) {
|
||||
pcie->uphy_mgmt_clk = devm_clk_get(&pad->dev, "uphy_mgmt");
|
||||
if (IS_ERR(pcie->uphy_mgmt_clk)) {
|
||||
err = PTR_ERR(pcie->uphy_mgmt_clk);
|
||||
dev_err(&pad->dev,
|
||||
"failed to get uphy_mgmt_clk clock: %d\n", err);
|
||||
}
|
||||
}
|
||||
|
||||
pcie->rst = devm_reset_control_get(&pad->dev, "phy");
|
||||
if (IS_ERR(pcie->rst)) {
|
||||
err = PTR_ERR(pcie->rst);
|
||||
@@ -3094,7 +3172,16 @@ static void tegra210_usb3_port_disable(struct tegra_xusb_port *port)
|
||||
static struct tegra_xusb_lane *
|
||||
tegra210_usb3_port_map(struct tegra_xusb_port *port)
|
||||
{
|
||||
return tegra_xusb_port_find_lane(port, tegra210_usb3_map, "usb3-ss");
|
||||
int err = t210b01_compatible(port->padctl);
|
||||
|
||||
if (err == 1)
|
||||
return tegra_xusb_port_find_lane(port,
|
||||
tegra210b01_usb3_map, "usb3-ss");
|
||||
else if (err == 0)
|
||||
return tegra_xusb_port_find_lane(port,
|
||||
tegra210_usb3_map, "usb3-ss");
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const struct tegra_xusb_port_ops tegra210_usb3_port_ops = {
|
||||
@@ -3287,6 +3374,14 @@ static const char * const tegra210_xusb_padctl_supply_names[] = {
|
||||
"hvdd-pex-pll-e",
|
||||
};
|
||||
|
||||
static const char * const tegra210b01_supply_names[] = {
|
||||
"avdd_pll_uerefe",
|
||||
"hvdd_pex_pll_e",
|
||||
"dvdd_pex_pll",
|
||||
"hvddio_pex",
|
||||
"dvddio_pex",
|
||||
};
|
||||
|
||||
const struct tegra_xusb_padctl_soc tegra210_xusb_padctl_soc = {
|
||||
.num_pads = ARRAY_SIZE(tegra210_pads),
|
||||
.pads = tegra210_pads,
|
||||
@@ -3325,8 +3420,8 @@ const struct tegra_xusb_padctl_soc tegra210b01_xusb_padctl_soc = {
|
||||
},
|
||||
},
|
||||
.ops = &tegra210_xusb_padctl_ops,
|
||||
.supply_names = tegra210_xusb_padctl_supply_names,
|
||||
.num_supplies = ARRAY_SIZE(tegra210_xusb_padctl_supply_names),
|
||||
.supply_names = tegra210b01_supply_names,
|
||||
.num_supplies = ARRAY_SIZE(tegra210b01_supply_names),
|
||||
.need_fake_usb3_port = true,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(tegra210b01_xusb_padctl_soc);
|
||||
|
||||
@@ -564,6 +564,7 @@ static int tegra_xusb_port_init(struct tegra_xusb_port *port,
|
||||
if (err < 0)
|
||||
goto put_device;
|
||||
|
||||
printk("init done!\n");
|
||||
return 0;
|
||||
|
||||
put_device:
|
||||
@@ -799,24 +800,31 @@ static int tegra_xusb_add_usb2_port(struct tegra_xusb_padctl *padctl,
|
||||
struct device_node *np;
|
||||
int err = 0;
|
||||
|
||||
printk("adding usb2 port");
|
||||
|
||||
/*
|
||||
* USB2 ports don't require additional properties, but if the port is
|
||||
* marked as disabled there is no reason to register it.
|
||||
*/
|
||||
printk("find port node");
|
||||
np = tegra_xusb_find_port_node(padctl, "usb2", index);
|
||||
if (!np || !of_device_is_available(np))
|
||||
goto out;
|
||||
|
||||
printk("kzalloc");
|
||||
usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL);
|
||||
if (!usb2) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
printk("init usb2 xusb port");
|
||||
err = tegra_xusb_port_init(&usb2->base, padctl, np, "usb2", index);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
printk("set usb2 ops");
|
||||
|
||||
usb2->base.ops = padctl->soc->ports.usb2.ops;
|
||||
|
||||
usb2->base.lane = usb2->base.ops->map(&usb2->base);
|
||||
@@ -880,6 +888,8 @@ static int tegra_xusb_add_ulpi_port(struct tegra_xusb_padctl *padctl,
|
||||
goto out;
|
||||
}
|
||||
|
||||
printk("init ulpi xusb port");
|
||||
|
||||
err = tegra_xusb_port_init(&ulpi->base, padctl, np, "ulpi", index);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
@@ -926,6 +936,7 @@ static int tegra_xusb_add_hsic_port(struct tegra_xusb_padctl *padctl,
|
||||
struct device_node *np;
|
||||
int err = 0;
|
||||
|
||||
printk("find hsic port node");
|
||||
np = tegra_xusb_find_port_node(padctl, "hsic", index);
|
||||
if (!np || !of_device_is_available(np))
|
||||
goto out;
|
||||
@@ -936,10 +947,13 @@ static int tegra_xusb_add_hsic_port(struct tegra_xusb_padctl *padctl,
|
||||
goto out;
|
||||
}
|
||||
|
||||
printk("init hsic xusb port");
|
||||
|
||||
err = tegra_xusb_port_init(&hsic->base, padctl, np, "hsic", index);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
printk("setting hsic ops");
|
||||
hsic->base.ops = padctl->soc->ports.hsic.ops;
|
||||
|
||||
hsic->base.lane = hsic->base.ops->map(&hsic->base);
|
||||
@@ -1028,10 +1042,14 @@ static int tegra_xusb_add_usb3_port(struct tegra_xusb_padctl *padctl,
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
printk("xusb port inited. setting ops");
|
||||
usb3->base.ops = padctl->soc->ports.usb3.ops;
|
||||
|
||||
printk("set lane");
|
||||
|
||||
usb3->base.lane = usb3->base.ops->map(&usb3->base);
|
||||
if (IS_ERR(usb3->base.lane)) {
|
||||
printk("usb3 lane is error!");
|
||||
err = PTR_ERR(usb3->base.lane);
|
||||
goto out;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user