diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 89ce8a62b37c..b54e6dc17300 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -27,6 +27,7 @@ #include #include #include +#include #define BYTES_PER_FIFO_WORD 4 @@ -64,6 +65,10 @@ #define I2C_CLK_DIVISOR 0x06c #define I2C_CLK_DIVISOR_STD_FAST_MODE GENMASK(31, 16) #define I2C_CLK_DIVISOR_HSMODE GENMASK(15, 0) +#define I2C_CLK_DIVISOR_STD_FAST_MODE_START 16 +#define I2C_CLK_DIVISOR_STD_FAST_MODE_WIDTH 16 +#define I2C_CLK_DIVISOR_HSMODE_START 0 +#define I2C_CLK_DIVISOR_HSMODE_WIDTH 16 #define DVC_CTRL_REG1 0x000 #define DVC_CTRL_REG1_INTR_EN BIT(10) @@ -108,21 +113,45 @@ #define I2C_MST_CORE_CLKEN_OVR BIT(0) #define I2C_INTERFACE_TIMING_0 0x094 -#define I2C_INTERFACE_TIMING_THIGH GENMASK(13, 8) -#define I2C_INTERFACE_TIMING_TLOW GENMASK(5, 0) +#define I2C_INTERFACE_TIMING_THIGH GENMASK(15, 8) +#define I2C_INTERFACE_TIMING_TLOW GENMASK(7, 0) +#define I2C_INTERFACE_TIMING_THIGH_START 8 +#define I2C_INTERFACE_TIMING_THIGH_WIDTH 8 +#define I2C_INTERFACE_TIMING_TLOW_START 0 +#define I2C_INTERFACE_TIMING_TLOW_WIDTH 8 + #define I2C_INTERFACE_TIMING_1 0x098 #define I2C_INTERFACE_TIMING_TBUF GENMASK(29, 24) #define I2C_INTERFACE_TIMING_TSU_STO GENMASK(21, 16) #define I2C_INTERFACE_TIMING_THD_STA GENMASK(13, 8) #define I2C_INTERFACE_TIMING_TSU_STA GENMASK(5, 0) +#define I2C_INTERFACE_TIMING_TBUF_START 24 +#define I2C_INTERFACE_TIMING_TBUF_WIDTH 6 +#define I2C_INTERFACE_TIMING_TSU_STO_START 16 +#define I2C_INTERFACE_TIMING_TSU_STO_WIDTH 6 +#define I2C_INTERFACE_TIMING_THD_STA_START 8 +#define I2C_INTERFACE_TIMING_THD_STA_WIDTH 6 +#define I2C_INTERFACE_TIMING_TSU_STA_START 0 +#define I2C_INTERFACE_TIMING_TSU_STA_WIDTH 6 #define I2C_HS_INTERFACE_TIMING_0 0x09c -#define I2C_HS_INTERFACE_TIMING_THIGH GENMASK(13, 8) -#define I2C_HS_INTERFACE_TIMING_TLOW GENMASK(5, 0) +#define I2C_HS_INTERFACE_TIMING_THIGH GENMASK(15, 8) +#define I2C_HS_INTERFACE_TIMING_TLOW GENMASK(7, 0) +#define I2C_HS_INTERFACE_TIMING_THIGH_START 8 +#define I2C_HS_INTERFACE_TIMING_THIGH_WIDTH 8 +#define I2C_HS_INTERFACE_TIMING_TLOW_START 0 +#define I2C_HS_INTERFACE_TIMING_TLOW_WIDTH 8 + #define I2C_HS_INTERFACE_TIMING_1 0x0a0 #define I2C_HS_INTERFACE_TIMING_TSU_STO GENMASK(21, 16) #define I2C_HS_INTERFACE_TIMING_THD_STA GENMASK(13, 8) #define I2C_HS_INTERFACE_TIMING_TSU_STA GENMASK(5, 0) +#define I2C_HS_INTERFACE_TIMING_TSU_STO_START 16 +#define I2C_HS_INTERFACE_TIMING_TSU_STO_WIDTH 6 +#define I2C_HS_INTERFACE_TIMING_THD_STA_START 8 +#define I2C_HS_INTERFACE_TIMING_THD_STA_WIDTH 6 +#define I2C_HS_INTERFACE_TIMING_TSU_STA_START 0 +#define I2C_HS_INTERFACE_TIMING_TSU_STA_WIDTH 6 #define I2C_MST_FIFO_CONTROL 0x0b4 #define I2C_MST_FIFO_CONTROL_RX_FLUSH BIT(0) @@ -288,6 +317,8 @@ struct tegra_i2c_dev { dma_addr_t dma_phys; void *dma_buf; + struct tegra_prod *prod_list; + bool multimaster_mode; bool atomic_mode; bool dma_mode; @@ -604,42 +635,46 @@ static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev *i2c_dev) return 0; } -static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) +static void tegra_i2c_write_prod_settings(struct tegra_i2c_dev *i2c_dev, + const char *prod_name) { - u32 val, clk_divisor, clk_multiplier, tsu_thd, tlow, thigh, non_hs_mode; - acpi_handle handle = ACPI_HANDLE(i2c_dev->dev); - struct i2c_timings *t = &i2c_dev->timings; int err; - /* - * The reset shouldn't ever fail in practice. The failure will be a - * sign of a severe problem that needs to be resolved. Still we don't - * want to fail the initialization completely because this may break - * kernel boot up since voltage regulators use I2C. Hence, we will - * emit a noisy warning on error, which won't stay unnoticed and - * won't hose machine entirely. - */ - if (handle) - err = acpi_evaluate_object(handle, "_RST", NULL, NULL); - else - err = reset_control_reset(i2c_dev->rst); + err = tegra_prod_set_by_name(&i2c_dev->base, prod_name, i2c_dev->prod_list); + if (err < 0) + dev_dbg_once(i2c_dev->dev, + "Prod config not found for I2C: %d\n", err); +} - WARN_ON_ONCE(err); +static void tegra_i2c_config_prod_settings(struct tegra_i2c_dev *i2c_dev) +{ + struct i2c_timings *t = &i2c_dev->timings; + char *prod_name; - if (IS_DVC(i2c_dev)) - tegra_dvc_init(i2c_dev); + switch (t->bus_freq_hz) { + case I2C_MAX_FAST_MODE_PLUS_FREQ + 1 ... I2C_MAX_HIGH_SPEED_MODE_FREQ: + prod_name = "prod_c_hs"; + break; + case I2C_MAX_FAST_MODE_FREQ + 1 ... I2C_MAX_FAST_MODE_PLUS_FREQ: + prod_name = "prod_c_fmplus"; + break; + case I2C_MAX_STANDARD_MODE_FREQ + 1 ... I2C_MAX_FAST_MODE_FREQ: + prod_name = "prod_c_fm"; + break; + case 0 ... I2C_MAX_STANDARD_MODE_FREQ: + default: + prod_name = "prod_c_sm"; + break; + } - val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN | - FIELD_PREP(I2C_CNFG_DEBOUNCE_CNT, 2); + tegra_i2c_write_prod_settings(i2c_dev, "prod"); + tegra_i2c_write_prod_settings(i2c_dev, prod_name); +} - if (i2c_dev->hw->has_multi_master_mode) - val |= I2C_CNFG_MULTI_MASTER_MODE; - - i2c_writel(i2c_dev, val, I2C_CNFG); - i2c_writel(i2c_dev, 0, I2C_INT_MASK); - - if (IS_VI(i2c_dev)) - tegra_i2c_vi_init(i2c_dev); +static void tegra_i2c_set_clk_params(struct tegra_i2c_dev *i2c_dev) +{ + u32 val, clk_divisor, tsu_thd, tlow, thigh, non_hs_mode; + struct i2c_timings *t = &i2c_dev->timings; switch (t->bus_freq_hz) { case I2C_MAX_STANDARD_MODE_FREQ + 1 ... I2C_MAX_FAST_MODE_PLUS_FREQ: @@ -680,6 +715,23 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) */ if (i2c_dev->hw->has_interface_timing_reg && tsu_thd) i2c_writel(i2c_dev, tsu_thd, I2C_INTERFACE_TIMING_1); +} + +static int tegra_i2c_set_div_clk(struct tegra_i2c_dev *i2c_dev) +{ + u32 clk_multiplier, tlow, thigh, non_hs_mode; + struct i2c_timings *t = &i2c_dev->timings; + u32 timing, clk_divisor; + int err; + + timing = i2c_readl(i2c_dev, I2C_INTERFACE_TIMING_0); + + tlow = FIELD_GET(I2C_INTERFACE_TIMING_TLOW, timing); + thigh = FIELD_GET(I2C_INTERFACE_TIMING_THIGH, timing); + + clk_divisor = i2c_readl(i2c_dev, I2C_CLK_DIVISOR); + + non_hs_mode = FIELD_GET(I2C_CLK_DIVISOR_STD_FAST_MODE, clk_divisor); clk_multiplier = (tlow + thigh + 2) * (non_hs_mode + 1); @@ -690,6 +742,54 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) return err; } + return 0; +} + +static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) +{ + acpi_handle handle = ACPI_HANDLE(i2c_dev->dev); + u32 val; + int err; + + /* + * The reset shouldn't ever fail in practice. The failure will be a + * sign of a severe problem that needs to be resolved. Still we don't + * want to fail the initialization completely because this may break + * kernel boot up since voltage regulators use I2C. Hence, we will + * emit a noisy warning on error, which won't stay unnoticed and + * won't hose machine entirely. + */ + if (handle) + err = acpi_evaluate_object(handle, "_RST", NULL, NULL); + else + err = reset_control_reset(i2c_dev->rst); + + WARN_ON_ONCE(err); + + if (IS_DVC(i2c_dev)) + tegra_dvc_init(i2c_dev); + + val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN | + FIELD_PREP(I2C_CNFG_DEBOUNCE_CNT, 2); + + if (i2c_dev->hw->has_multi_master_mode) + val |= I2C_CNFG_MULTI_MASTER_MODE; + + i2c_writel(i2c_dev, val, I2C_CNFG); + i2c_writel(i2c_dev, 0, I2C_INT_MASK); + + if (IS_VI(i2c_dev)) + tegra_i2c_vi_init(i2c_dev); + + if (i2c_dev->prod_list) + tegra_i2c_config_prod_settings(i2c_dev); + else + tegra_i2c_set_clk_params(i2c_dev); + + err = tegra_i2c_set_div_clk(i2c_dev); + if (err) + return err; + if (!IS_DVC(i2c_dev) && !IS_VI(i2c_dev)) { u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG); @@ -1786,6 +1886,12 @@ static int tegra_i2c_probe(struct platform_device *pdev) if (err) return err; + i2c_dev->prod_list = devm_tegra_prod_get(i2c_dev->dev); + if (IS_ERR_OR_NULL(i2c_dev->prod_list)) { + dev_dbg(&pdev->dev, "Prod-setting not available\n"); + i2c_dev->prod_list = NULL; + } + tegra_i2c_parse_dt(i2c_dev); err = tegra_i2c_init_reset(i2c_dev); diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 7b6b82bec855..9af96a021187 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) 2010 Google, Inc. + * Copyright (C) 2013 Google, Inc. */ #include @@ -28,6 +28,7 @@ #include #include +#include #include "sdhci-cqhci.h" #include "sdhci-pltfm.h" @@ -37,21 +38,28 @@ #define SDHCI_TEGRA_VENDOR_CLOCK_CTRL 0x100 #define SDHCI_CLOCK_CTRL_TAP_MASK 0x00ff0000 #define SDHCI_CLOCK_CTRL_TAP_SHIFT 16 +#define SDHCI_CLOCK_CTRL_TAP_WIDTH 8 #define SDHCI_CLOCK_CTRL_TRIM_MASK 0x1f000000 #define SDHCI_CLOCK_CTRL_TRIM_SHIFT 24 +#define SDHCI_CLOCK_CTRL_TRIM_WIDTH 5 #define SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE BIT(5) #define SDHCI_CLOCK_CTRL_PADPIPE_CLKEN_OVERRIDE BIT(3) #define SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE BIT(2) #define SDHCI_TEGRA_VENDOR_SYS_SW_CTRL 0x104 #define SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE BIT(31) +#define SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE_SHIFT 31 +#define SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE_WIDTH 1 #define SDHCI_TEGRA_VENDOR_CAP_OVERRIDES 0x10c #define SDHCI_TEGRA_CAP_OVERRIDES_DQS_TRIM_MASK 0x00003f00 #define SDHCI_TEGRA_CAP_OVERRIDES_DQS_TRIM_SHIFT 8 +#define SDHCI_TEGRA_CAP_OVERRIDES_DQS_TRIM_WIDTH 6 #define SDHCI_TEGRA_VENDOR_MISC_CTRL 0x120 #define SDHCI_MISC_CTRL_ERASE_TIMEOUT_LIMIT BIT(0) +#define SDHCI_MISC_CTRL_ERASE_TIMEOUT_LIMIT_SHIFT 0 +#define SDHCI_MISC_CTRL_ERASE_TIMEOUT_LIMIT_WIDTH 1 #define SDHCI_MISC_CTRL_ENABLE_SDR104 0x8 #define SDHCI_MISC_CTRL_ENABLE_SDR50 0x10 #define SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 0x20 @@ -64,6 +72,8 @@ #define SDHCI_TEGRA_DLLCAL_STA_ACTIVE BIT(31) #define SDHCI_VNDR_TUN_CTRL0_0 0x1c0 +#define SDHCI_VNDR_TUN_CTRL0_CMD_CRC_ERR_EN_SHIFT 28 +#define SDHCI_VNDR_TUN_CTRL0_CMD_CRC_ERR_EN_WIDTH 1 #define SDHCI_VNDR_TUN_CTRL0_TUN_HW_TAP 0x20000 #define SDHCI_VNDR_TUN_CTRL0_START_TAP_VAL_MASK 0x03fc0000 #define SDHCI_VNDR_TUN_CTRL0_START_TAP_VAL_SHIFT 18 @@ -71,9 +81,12 @@ #define SDHCI_VNDR_TUN_CTRL0_MUL_M_SHIFT 6 #define SDHCI_VNDR_TUN_CTRL0_TUN_ITER_MASK 0x000e000 #define SDHCI_VNDR_TUN_CTRL0_TUN_ITER_SHIFT 13 +#define SDHCI_VNDR_TUN_CTRL0_TUN_ITER_WIDTH 3 #define TRIES_128 2 #define TRIES_256 4 #define SDHCI_VNDR_TUN_CTRL0_TUN_WORD_SEL_MASK 0x7 +#define SDHCI_VNDR_TUN_CTRL0_DIV_N_SHIFT 3 +#define SDHCI_VNDR_TUN_CTRL0_DIV_N_WIDTH 3 #define SDHCI_TEGRA_VNDR_TUN_CTRL1_0 0x1c4 #define SDHCI_TEGRA_VNDR_TUN_STATUS0 0x1C8 @@ -134,6 +147,20 @@ SDHCI_TRNS_BLK_CNT_EN | \ SDHCI_TRNS_DMA) +static char prod_device_states[MMC_TIMING_COUNTER][20] = { + "prod_c_ds", /* MMC_TIMING_LEGACY */ + "prod_c_hs", /* MMC_TIMING_MMC_HS */ + "prod_c_hs", /* MMC_TIMING_SD_HS */ + "prod_c_sdr12", /* MMC_TIMING_UHS_SDR12 */ + "prod_c_sdr25", /* MMC_TIMING_UHS_SDR25 */ + "prod_c_sdr50", /* MMC_TIMING_UHS_SDR50 */ + "prod_c_sdr104", /* MMC_TIMING_UHS_SDR104 */ + "prod_c_ddr52", /* MMC_TIMING_UHS_DDR50 */ + "prod_c_ddr52", /* MMC_TIMING_MMC_DDR52 */ + "prod_c_hs200", /* MMC_TIMING_MMC_HS200 */ + "prod_c_hs400", /* MMC_TIMING_MMC_HS400 */ +}; + struct sdhci_tegra_soc_data { const struct sdhci_pltfm_data *pdata; u64 dma_mask; @@ -183,6 +210,7 @@ struct sdhci_tegra { unsigned long curr_clk_rate; u8 tuned_tap_delay; u32 stream_id; + struct tegra_prod *prod_list; }; static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) @@ -362,6 +390,19 @@ static void tegra_sdhci_set_tap(struct sdhci_host *host, unsigned int tap) } } +static void tegra_sdhci_write_prod_settings(struct sdhci_host *host, + const char *prod_name) +{ + int err; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); + + err = tegra_prod_set_by_name(&host->ioaddr, prod_name, tegra_host->prod_list); + if (err < 0) + dev_dbg_once(mmc_dev(host->mmc), + "Prod config not found for SDHCI: %d\n", err); +} + static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -374,6 +415,9 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) if (!(mask & SDHCI_RESET_ALL)) return; + if (tegra_get_platform() == TEGRA_PLATFORM_SILICON) + tegra_sdhci_write_prod_settings(host, "prod"); + tegra_sdhci_set_tap(host, tegra_host->default_tap); misc_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_MISC_CTRL); @@ -1011,6 +1055,7 @@ static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host, bool set_default_tap = false; bool set_dqs_trim = false; bool do_hs400_dll_cal = false; + bool set_padpipe_clk_override = false; u8 iter = TRIES_256; u32 val; @@ -1027,6 +1072,7 @@ static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host, set_dqs_trim = true; do_hs400_dll_cal = true; iter = TRIES_128; + set_padpipe_clk_override = true; break; case MMC_TIMING_MMC_DDR52: case MMC_TIMING_UHS_DDR50: @@ -1059,6 +1105,11 @@ static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host, else tegra_sdhci_set_tap(host, tegra_host->default_tap); + /*set padpipe_clk_override*/ + if (set_padpipe_clk_override) { + tegra_sdhci_write_prod_settings(host, + prod_device_states[timing]); + } if (set_dqs_trim) tegra_sdhci_set_dqs_trim(host, tegra_host->dqs_trim); @@ -1129,6 +1180,15 @@ static int sdhci_tegra_start_signal_voltage_switch(struct mmc_host *mmc, static int tegra_sdhci_init_pinctrl_info(struct device *dev, struct sdhci_tegra *tegra_host) { + if (!(tegra_get_platform() == TEGRA_PLATFORM_SILICON)) + return 0; + + tegra_host->prod_list = devm_tegra_prod_get(dev); + if (IS_ERR_OR_NULL(tegra_host->prod_list)) { + dev_dbg(dev, "Prod-setting not available\n"); + tegra_host->prod_list = NULL; + } + tegra_host->pinctrl_sdmmc = devm_pinctrl_get(dev); if (IS_ERR(tegra_host->pinctrl_sdmmc)) { dev_dbg(dev, "No pinctrl info, err: %ld\n", diff --git a/drivers/phy/tegra/xusb-tegra186.c b/drivers/phy/tegra/xusb-tegra186.c index 23a23f2d64e5..858f80b9acf3 100644 --- a/drivers/phy/tegra/xusb-tegra186.c +++ b/drivers/phy/tegra/xusb-tegra186.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2016-2024, NVIDIA CORPORATION. All rights reserved. */ #include @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -239,6 +240,24 @@ #define TEGRA_UTMI_PAD_MAX 4 +/* Prod fields */ +#define USB2_OTG_PADX_CTL0_LS_RSLEW_FIELD_START 17 +#define USB2_OTG_PADX_CTL0_LS_RSLEW_FIELD_WIDTH 4 +#define USB2_OTG_PADX_CTL0_LS_FSLEW_FIELD_START 21 +#define USB2_OTG_PADX_CTL0_LS_FSLEW_FIELD_WIDTH 4 + +#define USB2_OTG_PADX_CTL3_HS_TXEQ_FIELD_START 1 +#define USB2_OTG_PADX_CTL3_HS_TXEQ_FIELD_WIDTH 3 + +#define USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_FIELD_START 3 +#define USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_FIELD_WIDTH 3 +#define USB2_BIAS_PAD_CTL1_TRK_START_TIMER_FIELD_START 12 +#define USB2_BIAS_PAD_CTL1_TRK_START_TIMER_FIELD_WIDTH 7 +#define USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_FIELD_START 19 +#define USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_FIELD_WIDTH 7 + +#define XUSB_PADCTL_USB2_OTG_PADX_CTL3(x) (0x94 + (x) * 0x40) + #define TEGRA186_LANE(_name, _offset, _shift, _mask, _type) \ { \ .name = _name, \ @@ -267,6 +286,8 @@ struct tegra186_xusb_padctl { struct tegra_xusb_padctl base; void __iomem *ao_regs; + /* prod settings */ + struct tegra_prod *prod_list; struct tegra_xusb_fuse_calibration calib; /* UTMI bias and tracking */ @@ -850,6 +871,14 @@ static int tegra186_utmi_phy_set_mode(struct phy *phy, enum phy_mode mode, return err; } +static int tegra186_utmi_write_prod_settings(struct tegra_xusb_padctl *padctl, + const char *prod_name) +{ + struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl); + + return tegra_prod_set_by_name(&padctl->regs, prod_name, priv->prod_list); +} + static int tegra186_utmi_phy_power_on(struct phy *phy) { struct tegra_xusb_lane *lane = phy_get_drvdata(phy); @@ -867,6 +896,12 @@ static int tegra186_utmi_phy_power_on(struct phy *phy) return -ENODEV; } + if (priv->prod_list) { + int err = tegra186_utmi_write_prod_settings(padctl, "prod"); + if (err) + dev_dbg(dev, "failed to apply prod settings\n"); + } + value = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX); value &= ~(USB2_PORT_MASK << USB2_PORT_SHIFT(index)); value |= (PORT_XUSB << USB2_PORT_SHIFT(index)); @@ -1512,6 +1547,12 @@ tegra186_xusb_padctl_probe(struct device *dev, if (err < 0) return ERR_PTR(err); + priv->prod_list = devm_tegra_prod_get(dev); + if (IS_ERR_OR_NULL(priv->prod_list)) { + dev_dbg(dev, "Prod-settings is not available\n"); + priv->prod_list = NULL; + } + return &priv->base; } diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index 11db703a0dde..052ed7935efd 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -22,6 +22,7 @@ #include #include #include +#include #define SPI_COMMAND1 0x000 #define SPI_BIT_LENGTH(x) (((x) & 0x1f) << 0) @@ -63,6 +64,10 @@ #define SPI_COMMAND2 0x004 #define SPI_TX_TAP_DELAY(x) (((x) & 0x3F) << 6) #define SPI_RX_TAP_DELAY(x) (((x) & 0x3F) << 0) +#define SPI_COMMAND2_RX_CLK_TAP_DELAY_START 0 +#define SPI_COMMAND2_RX_CLK_TAP_DELAY_WIDTH 6 +#define SPI_COMMAND2_TX_CLK_TAP_DELAY_START 6 +#define SPI_COMMAND2_TX_CLK_TAP_DELAY_WIDTH 6 #define SPI_CS_TIMING1 0x008 #define SPI_SETUP_HOLD(setup, hold) (((setup) << 4) | (hold)) @@ -146,6 +151,10 @@ #define DATA_DIR_TX (1 << 0) #define DATA_DIR_RX (1 << 1) +#define SPI_MISC 0x194 +#define SPI_MISC_CLKEN_OVERRIDE_START 31 +#define SPI_MISC_CLKEN_OVERRIDE_WIDTH 1 + #define SPI_DMA_TIMEOUT (msecs_to_jiffies(1000)) #define DEFAULT_SPI_DMA_BUF_LEN (16*1024) #define TX_FIFO_EMPTY_COUNT_MAX SPI_TX_FIFO_EMPTY_COUNT(0x40) @@ -218,6 +227,7 @@ struct tegra_spi_data { dma_addr_t tx_dma_phys; struct dma_async_tx_descriptor *tx_dma_desc; const struct tegra_spi_soc_data *soc_data; + struct tegra_prod *prod_list; }; static int tegra_spi_runtime_suspend(struct device *dev); @@ -716,6 +726,31 @@ static void tegra_spi_deinit_dma_param(struct tegra_spi_data *tspi, dma_release_channel(dma_chan); } +static void tegra_spi_write_prod_settings(struct tegra_spi_data *tspi, + const char *prod_name) +{ + int err; + + err = tegra_prod_set_by_name(&tspi->base, prod_name, tspi->prod_list); + if (err < 0) + dev_dbg_once(tspi->dev, + "Prod config not found for SPI: %d\n", err); +} + +static void tegra_spi_set_prod(struct tegra_spi_data *tspi, int cs) +{ + char prod_name[15]; + + /* Avoid write to register for transfers to last used device */ + if (tspi->last_used_cs == cs) + return; + + sprintf(prod_name, "prod_c_cs%d", cs); + tegra_spi_write_prod_settings(tspi, "prod"); + tegra_spi_write_prod_settings(tspi, prod_name); + tspi->last_used_cs = cs; +} + static int tegra_spi_set_hw_cs_timing(struct spi_device *spi) { struct tegra_spi_data *tspi = spi_controller_get_devdata(spi->controller); @@ -841,16 +876,20 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi, command1 &= ~SPI_CS_SW_VAL; } - if (tspi->last_used_cs != spi_get_chipselect(spi, 0)) { - if (cdata && cdata->tx_clk_tap_delay) - tx_tap = cdata->tx_clk_tap_delay; - if (cdata && cdata->rx_clk_tap_delay) - rx_tap = cdata->rx_clk_tap_delay; - command2 = SPI_TX_TAP_DELAY(tx_tap) | - SPI_RX_TAP_DELAY(rx_tap); - if (command2 != tspi->def_command2_reg) - tegra_spi_writel(tspi, command2, SPI_COMMAND2); - tspi->last_used_cs = spi_get_chipselect(spi, 0); + if (!tspi->prod_list) { + if (tspi->last_used_cs != spi_get_chipselect(spi, 0)) { + if (cdata && cdata->tx_clk_tap_delay) + tx_tap = cdata->tx_clk_tap_delay; + if (cdata && cdata->rx_clk_tap_delay) + rx_tap = cdata->rx_clk_tap_delay; + command2 = SPI_TX_TAP_DELAY(tx_tap) | + SPI_RX_TAP_DELAY(rx_tap); + if (command2 != tspi->def_command2_reg) + tegra_spi_writel(tspi, command2, SPI_COMMAND2); + tspi->last_used_cs = spi_get_chipselect(spi, 0); + } + } else { + tegra_spi_set_prod(tspi, spi_get_chipselect(spi, 0)); } } else { @@ -1328,6 +1367,11 @@ static int tegra_spi_probe(struct platform_device *pdev) tspi->host = host; tspi->dev = &pdev->dev; + tspi->prod_list = devm_tegra_prod_get(tspi->dev); + if (IS_ERR_OR_NULL(tspi->prod_list)) { + dev_dbg(&pdev->dev, "Prod settings list not initialized\n"); + tspi->prod_list = NULL; + } spin_lock_init(&tspi->lock); tspi->soc_data = of_device_get_match_data(&pdev->dev); @@ -1396,12 +1440,14 @@ static int tegra_spi_probe(struct platform_device *pdev) reset_control_assert(tspi->rst); udelay(2); reset_control_deassert(tspi->rst); + tspi->last_used_cs = host->num_chipselect + 1; + /* initialize CS with 0 in probe */ + tegra_spi_set_prod(tspi, 0); tspi->def_command1_reg = SPI_M_S; tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1); tspi->spi_cs_timing1 = tegra_spi_readl(tspi, SPI_CS_TIMING1); tspi->spi_cs_timing2 = tegra_spi_readl(tspi, SPI_CS_TIMING2); tspi->def_command2_reg = tegra_spi_readl(tspi, SPI_COMMAND2); - tspi->last_used_cs = host->num_chipselect + 1; pm_runtime_put(&pdev->dev); ret = request_threaded_irq(tspi->irq, tegra_spi_isr, tegra_spi_isr_thread, IRQF_ONESHOT, diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 0eb3d44f5b1c..a4bbbe1006c7 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -65,6 +65,7 @@ struct mmc_ios { #define MMC_TIMING_MMC_HS400 10 #define MMC_TIMING_SD_EXP 11 #define MMC_TIMING_SD_EXP_1_2V 12 +#define MMC_TIMING_COUNTER 11 unsigned char signal_voltage; /* signalling voltage (1.8V or 3.3V) */