NVIDIA: SAUCE: tegra: prod: use legacy prod settings

BugLink: https://bugs.launchpad.net/bugs/2080908

This is an integration squash commit of following commits:

- [INTG: NVIDIA INTERNAL] phy: tegra: xusb: Support prod-settings properties
- [INTG]: drivers: spi: add support for prod framework
- [INTG: NVIDIA INTERNAL]: mmc: host: Add prod framework changes
- i2c: Add prod settings support
- i2c: tegra: Add new prod setting support
- spi: tegra114: Add new prod settings
- sdhci: tegra: Add new prod settings
- [NV INTERNAL] xusb: tegra: Add new prod setting
- sdhci-tegra: host: Avoid access to prod settings on PreSi.
- tegra: prod: use legacy prod settings

http://nvbugs/4359070
http://nvbugs/4097475
http://nvbugs/4099482
http://nvbugs/4189448
http://nvbugs/4189442
http://nvbugs/4165914
http://nvbugs/4165933
http://nvbugs/4165918
http://nvbugs/4165919
http://nvbugs/4765671
http://nvbugs/4754882

Signed-off-by: Krishna Yarlagadda <kyarlagadda@nvidia.com>
Signed-off-by: Petlozu Pravareshwar <petlozup@nvidia.com>
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Acked-by: Noah Wager <noah.wager@canonical.com>
Acked-by: Jacob Martin <jacob.martin@canonical.com>
Signed-off-by: Noah Wager <noah.wager@canonical.com>
This commit is contained in:
Krishna Yarlagadda
2023-06-26 08:45:11 +00:00
committed by Thomas Makin
parent 9cf1f30f0a
commit a52caa6411
5 changed files with 300 additions and 46 deletions

View File

@@ -27,6 +27,7 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/tegra_prod.h>
#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);

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2010 Google, Inc.
* Copyright (C) 2013 Google, Inc.
*/
#include <linux/bitfield.h>
@@ -28,6 +28,7 @@
#include <linux/reset.h>
#include <soc/tegra/common.h>
#include <linux/tegra_prod.h>
#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",

View File

@@ -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 <linux/delay.h>
@@ -12,6 +12,7 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/tegra_prod.h>
#include <soc/tegra/fuse.h>
@@ -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;
}

View File

@@ -22,6 +22,7 @@
#include <linux/of.h>
#include <linux/reset.h>
#include <linux/spi/spi.h>
#include <linux/tegra_prod.h>
#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,

View File

@@ -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) */