Commit 66f3431a authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

Merge tag 'tegra-for-5.13-soc' of...

Merge tag 'tegra-for-5.13-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into arm/drivers

soc/tegra: Changes for v5.13-rc1

Contains a couple of fixes to the PMC power domain implementation and
exports a regmap from PMC needed to implement USB sleepwalk support.

* tag 'tegra-for-5.13-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux:
  soc/tegra: pmc: Print out domain name when reset fails to acquire
  soc/tegra: pmc: Ensure that clock rates aren't too high
  soc/tegra: pmc: Fix completion of power-gate toggling
  soc/tegra: pmc: Fix imbalanced clock disabling in error code path
  soc/tegra: regulators: Fix locking up when voltage-spread is out of range
  soc/tegra: pmc: Provide USB sleepwalk register map

Link: https://lore.kernel.org/r/20210401172622.3352990-3-thierry.reding@gmail.com


Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents 16320d7f 366d7c64
Loading
Loading
Loading
Loading
+251 −8
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
@@ -102,6 +103,9 @@

#define PMC_PWR_DET_VALUE		0xe4

#define PMC_USB_DEBOUNCE_DEL		0xec
#define PMC_USB_AO			0xf0

#define PMC_SCRATCH41			0x140

#define PMC_WAKE2_MASK			0x160
@@ -133,6 +137,13 @@
#define IO_DPD2_STATUS			0x1c4
#define SEL_DPD_TIM			0x1c8

#define PMC_UTMIP_UHSIC_TRIGGERS	0x1ec
#define PMC_UTMIP_UHSIC_SAVED_STATE	0x1f0

#define PMC_UTMIP_TERM_PAD_CFG		0x1f8
#define PMC_UTMIP_UHSIC_SLEEP_CFG	0x1fc
#define PMC_UTMIP_UHSIC_FAKE		0x218

#define PMC_SCRATCH54			0x258
#define  PMC_SCRATCH54_DATA_SHIFT	8
#define  PMC_SCRATCH54_ADDR_SHIFT	0
@@ -145,8 +156,18 @@
#define  PMC_SCRATCH55_CHECKSUM_SHIFT	16
#define  PMC_SCRATCH55_I2CSLV1_SHIFT	0

#define  PMC_UTMIP_UHSIC_LINE_WAKEUP	0x26c

#define PMC_UTMIP_BIAS_MASTER_CNTRL	0x270
#define PMC_UTMIP_MASTER_CONFIG		0x274
#define PMC_UTMIP_UHSIC2_TRIGGERS	0x27c
#define PMC_UTMIP_MASTER2_CONFIG	0x29c

#define GPU_RG_CNTRL			0x2d4

#define PMC_UTMIP_PAD_CFG0		0x4c0
#define PMC_UTMIP_UHSIC_SLEEP_CFG1	0x4d0
#define PMC_UTMIP_SLEEPWALK_P3		0x4e0
/* Tegra186 and later */
#define WAKE_AOWAKE_CNTRL(x) (0x000 + ((x) << 2))
#define WAKE_AOWAKE_CNTRL_LEVEL (1 << 3)
@@ -237,6 +258,7 @@ struct tegra_powergate {
	unsigned int id;
	struct clk **clks;
	unsigned int num_clks;
	unsigned long *clk_rates;
	struct reset_control *reset;
};

@@ -317,6 +339,8 @@ struct tegra_pmc_soc {
				   bool invert);
	int (*irq_set_wake)(struct irq_data *data, unsigned int on);
	int (*irq_set_type)(struct irq_data *data, unsigned int type);
	int (*powergate_set)(struct tegra_pmc *pmc, unsigned int id,
			     bool new_state);

	const char * const *reset_sources;
	unsigned int num_reset_sources;
@@ -334,6 +358,7 @@ struct tegra_pmc_soc {
	const struct pmc_clk_init_data *pmc_clks_data;
	unsigned int num_pmc_clks;
	bool has_blink_output;
	bool has_usb_sleepwalk;
};

/**
@@ -517,6 +542,63 @@ static int tegra_powergate_lookup(struct tegra_pmc *pmc, const char *name)
	return -ENODEV;
}

static int tegra20_powergate_set(struct tegra_pmc *pmc, unsigned int id,
				 bool new_state)
{
	unsigned int retries = 100;
	bool status;
	int ret;

	/*
	 * As per TRM documentation, the toggle command will be dropped by PMC
	 * if there is contention with a HW-initiated toggling (i.e. CPU core
	 * power-gated), the command should be retried in that case.
	 */
	do {
		tegra_pmc_writel(pmc, PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);

		/* wait for PMC to execute the command */
		ret = readx_poll_timeout(tegra_powergate_state, id, status,
					 status == new_state, 1, 10);
	} while (ret == -ETIMEDOUT && retries--);

	return ret;
}

static inline bool tegra_powergate_toggle_ready(struct tegra_pmc *pmc)
{
	return !(tegra_pmc_readl(pmc, PWRGATE_TOGGLE) & PWRGATE_TOGGLE_START);
}

static int tegra114_powergate_set(struct tegra_pmc *pmc, unsigned int id,
				  bool new_state)
{
	bool status;
	int err;

	/* wait while PMC power gating is contended */
	err = readx_poll_timeout(tegra_powergate_toggle_ready, pmc, status,
				 status == true, 1, 100);
	if (err)
		return err;

	tegra_pmc_writel(pmc, PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);

	/* wait for PMC to accept the command */
	err = readx_poll_timeout(tegra_powergate_toggle_ready, pmc, status,
				 status == true, 1, 100);
	if (err)
		return err;

	/* wait for PMC to execute the command */
	err = readx_poll_timeout(tegra_powergate_state, id, status,
				 status == new_state, 10, 100000);
	if (err)
		return err;

	return 0;
}

/**
 * tegra_powergate_set() - set the state of a partition
 * @pmc: power management controller
@@ -526,7 +608,6 @@ static int tegra_powergate_lookup(struct tegra_pmc *pmc, const char *name)
static int tegra_powergate_set(struct tegra_pmc *pmc, unsigned int id,
			       bool new_state)
{
	bool status;
	int err;

	if (id == TEGRA_POWERGATE_3D && pmc->soc->has_gpu_clamps)
@@ -539,10 +620,7 @@ static int tegra_powergate_set(struct tegra_pmc *pmc, unsigned int id,
		return 0;
	}

	tegra_pmc_writel(pmc, PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);

	err = readx_poll_timeout(tegra_powergate_state, id, status,
				 status == new_state, 10, 100000);
	err = pmc->soc->powergate_set(pmc, id, new_state);

	mutex_unlock(&pmc->powergates_lock);

@@ -586,6 +664,57 @@ static int __tegra_powergate_remove_clamping(struct tegra_pmc *pmc,
	return 0;
}

static int tegra_powergate_prepare_clocks(struct tegra_powergate *pg)
{
	unsigned long safe_rate = 100 * 1000 * 1000;
	unsigned int i;
	int err;

	for (i = 0; i < pg->num_clks; i++) {
		pg->clk_rates[i] = clk_get_rate(pg->clks[i]);

		if (!pg->clk_rates[i]) {
			err = -EINVAL;
			goto out;
		}

		if (pg->clk_rates[i] <= safe_rate)
			continue;

		/*
		 * We don't know whether voltage state is okay for the
		 * current clock rate, hence it's better to temporally
		 * switch clock to a safe rate which is suitable for
		 * all voltages, before enabling the clock.
		 */
		err = clk_set_rate(pg->clks[i], safe_rate);
		if (err)
			goto out;
	}

	return 0;

out:
	while (i--)
		clk_set_rate(pg->clks[i], pg->clk_rates[i]);

	return err;
}

static int tegra_powergate_unprepare_clocks(struct tegra_powergate *pg)
{
	unsigned int i;
	int err;

	for (i = 0; i < pg->num_clks; i++) {
		err = clk_set_rate(pg->clks[i], pg->clk_rates[i]);
		if (err)
			return err;
	}

	return 0;
}

static void tegra_powergate_disable_clocks(struct tegra_powergate *pg)
{
	unsigned int i;
@@ -636,9 +765,13 @@ static int tegra_powergate_power_up(struct tegra_powergate *pg,

	usleep_range(10, 20);

	err = tegra_powergate_prepare_clocks(pg);
	if (err)
		goto powergate_off;

	err = tegra_powergate_enable_clocks(pg);
	if (err)
		goto disable_clks;
		goto unprepare_clks;

	usleep_range(10, 20);

@@ -662,12 +795,19 @@ static int tegra_powergate_power_up(struct tegra_powergate *pg,
	if (disable_clocks)
		tegra_powergate_disable_clocks(pg);

	err = tegra_powergate_unprepare_clocks(pg);
	if (err)
		return err;

	return 0;

disable_clks:
	tegra_powergate_disable_clocks(pg);
	usleep_range(10, 20);

unprepare_clks:
	tegra_powergate_unprepare_clocks(pg);

powergate_off:
	tegra_powergate_set(pg->pmc, pg->id, false);

@@ -678,10 +818,14 @@ static int tegra_powergate_power_down(struct tegra_powergate *pg)
{
	int err;

	err = tegra_powergate_enable_clocks(pg);
	err = tegra_powergate_prepare_clocks(pg);
	if (err)
		return err;

	err = tegra_powergate_enable_clocks(pg);
	if (err)
		goto unprepare_clks;

	usleep_range(10, 20);

	err = reset_control_assert(pg->reset);
@@ -698,6 +842,10 @@ static int tegra_powergate_power_down(struct tegra_powergate *pg)
	if (err)
		goto assert_resets;

	err = tegra_powergate_unprepare_clocks(pg);
	if (err)
		return err;

	return 0;

assert_resets:
@@ -709,6 +857,9 @@ static int tegra_powergate_power_down(struct tegra_powergate *pg)
disable_clks:
	tegra_powergate_disable_clocks(pg);

unprepare_clks:
	tegra_powergate_unprepare_clocks(pg);

	return err;
}

@@ -739,7 +890,8 @@ static int tegra_genpd_power_off(struct generic_pm_domain *domain)

	err = reset_control_acquire(pg->reset);
	if (err < 0) {
		pr_err("failed to acquire resets: %d\n", err);
		dev_err(dev, "failed to acquire resets for PM domain %s: %d\n",
			pg->genpd.name, err);
		return err;
	}

@@ -826,6 +978,12 @@ int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk,
	if (!pg)
		return -ENOMEM;

	pg->clk_rates = kzalloc(sizeof(*pg->clk_rates), GFP_KERNEL);
	if (!pg->clk_rates) {
		kfree(pg->clks);
		return -ENOMEM;
	}

	pg->id = id;
	pg->clks = &clk;
	pg->num_clks = 1;
@@ -837,6 +995,7 @@ int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk,
		dev_err(pmc->dev, "failed to turn on partition %d: %d\n", id,
			err);

	kfree(pg->clk_rates);
	kfree(pg);

	return err;
@@ -987,6 +1146,12 @@ static int tegra_powergate_of_get_clks(struct tegra_powergate *pg,
	if (!pg->clks)
		return -ENOMEM;

	pg->clk_rates = kcalloc(count, sizeof(*pg->clk_rates), GFP_KERNEL);
	if (!pg->clk_rates) {
		kfree(pg->clks);
		return -ENOMEM;
	}

	for (i = 0; i < count; i++) {
		pg->clks[i] = of_clk_get(np, i);
		if (IS_ERR(pg->clks[i])) {
@@ -1003,6 +1168,7 @@ static int tegra_powergate_of_get_clks(struct tegra_powergate *pg,
	while (i--)
		clk_put(pg->clks[i]);

	kfree(pg->clk_rates);
	kfree(pg->clks);

	return err;
@@ -2443,6 +2609,67 @@ static void tegra_pmc_clock_register(struct tegra_pmc *pmc,
			 err);
}

static const struct regmap_range pmc_usb_sleepwalk_ranges[] = {
	regmap_reg_range(PMC_USB_DEBOUNCE_DEL, PMC_USB_AO),
	regmap_reg_range(PMC_UTMIP_UHSIC_TRIGGERS, PMC_UTMIP_UHSIC_SAVED_STATE),
	regmap_reg_range(PMC_UTMIP_TERM_PAD_CFG, PMC_UTMIP_UHSIC_FAKE),
	regmap_reg_range(PMC_UTMIP_UHSIC_LINE_WAKEUP, PMC_UTMIP_UHSIC_LINE_WAKEUP),
	regmap_reg_range(PMC_UTMIP_BIAS_MASTER_CNTRL, PMC_UTMIP_MASTER_CONFIG),
	regmap_reg_range(PMC_UTMIP_UHSIC2_TRIGGERS, PMC_UTMIP_MASTER2_CONFIG),
	regmap_reg_range(PMC_UTMIP_PAD_CFG0, PMC_UTMIP_UHSIC_SLEEP_CFG1),
	regmap_reg_range(PMC_UTMIP_SLEEPWALK_P3, PMC_UTMIP_SLEEPWALK_P3),
};

static const struct regmap_access_table pmc_usb_sleepwalk_table = {
	.yes_ranges = pmc_usb_sleepwalk_ranges,
	.n_yes_ranges = ARRAY_SIZE(pmc_usb_sleepwalk_ranges),
};

static int tegra_pmc_regmap_readl(void *context, unsigned int offset, unsigned int *value)
{
	struct tegra_pmc *pmc = context;

	*value = tegra_pmc_readl(pmc, offset);
	return 0;
}

static int tegra_pmc_regmap_writel(void *context, unsigned int offset, unsigned int value)
{
	struct tegra_pmc *pmc = context;

	tegra_pmc_writel(pmc, value, offset);
	return 0;
}

static const struct regmap_config usb_sleepwalk_regmap_config = {
	.name = "usb_sleepwalk",
	.reg_bits = 32,
	.val_bits = 32,
	.reg_stride = 4,
	.fast_io = true,
	.rd_table = &pmc_usb_sleepwalk_table,
	.wr_table = &pmc_usb_sleepwalk_table,
	.reg_read = tegra_pmc_regmap_readl,
	.reg_write = tegra_pmc_regmap_writel,
};

static int tegra_pmc_regmap_init(struct tegra_pmc *pmc)
{
	struct regmap *regmap;
	int err;

	if (pmc->soc->has_usb_sleepwalk) {
		regmap = devm_regmap_init(pmc->dev, NULL, pmc, &usb_sleepwalk_regmap_config);
		if (IS_ERR(regmap)) {
			err = PTR_ERR(regmap);
			dev_err(pmc->dev, "failed to allocate register map (%d)\n", err);
			return err;
		}
	}

	return 0;
}

static int tegra_pmc_probe(struct platform_device *pdev)
{
	void __iomem *base;
@@ -2548,6 +2775,10 @@ static int tegra_pmc_probe(struct platform_device *pdev)
	if (err)
		goto cleanup_restart_handler;

	err = tegra_pmc_regmap_init(pmc);
	if (err < 0)
		goto cleanup_restart_handler;

	err = tegra_powergate_init(pmc, pdev->dev.of_node);
	if (err < 0)
		goto cleanup_powergates;
@@ -2699,6 +2930,7 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = {
	.regs = &tegra20_pmc_regs,
	.init = tegra20_pmc_init,
	.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
	.powergate_set = tegra20_powergate_set,
	.reset_sources = NULL,
	.num_reset_sources = 0,
	.reset_levels = NULL,
@@ -2706,6 +2938,7 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = {
	.pmc_clks_data = NULL,
	.num_pmc_clks = 0,
	.has_blink_output = true,
	.has_usb_sleepwalk = false,
};

static const char * const tegra30_powergates[] = {
@@ -2757,6 +2990,7 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = {
	.regs = &tegra20_pmc_regs,
	.init = tegra20_pmc_init,
	.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
	.powergate_set = tegra20_powergate_set,
	.reset_sources = tegra30_reset_sources,
	.num_reset_sources = ARRAY_SIZE(tegra30_reset_sources),
	.reset_levels = NULL,
@@ -2764,6 +2998,7 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = {
	.pmc_clks_data = tegra_pmc_clks_data,
	.num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
	.has_blink_output = true,
	.has_usb_sleepwalk = false,
};

static const char * const tegra114_powergates[] = {
@@ -2811,6 +3046,7 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = {
	.regs = &tegra20_pmc_regs,
	.init = tegra20_pmc_init,
	.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
	.powergate_set = tegra114_powergate_set,
	.reset_sources = tegra30_reset_sources,
	.num_reset_sources = ARRAY_SIZE(tegra30_reset_sources),
	.reset_levels = NULL,
@@ -2818,6 +3054,7 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = {
	.pmc_clks_data = tegra_pmc_clks_data,
	.num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
	.has_blink_output = true,
	.has_usb_sleepwalk = false,
};

static const char * const tegra124_powergates[] = {
@@ -2925,6 +3162,7 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
	.regs = &tegra20_pmc_regs,
	.init = tegra20_pmc_init,
	.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
	.powergate_set = tegra114_powergate_set,
	.reset_sources = tegra30_reset_sources,
	.num_reset_sources = ARRAY_SIZE(tegra30_reset_sources),
	.reset_levels = NULL,
@@ -2932,6 +3170,7 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
	.pmc_clks_data = tegra_pmc_clks_data,
	.num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
	.has_blink_output = true,
	.has_usb_sleepwalk = true,
};

static const char * const tegra210_powergates[] = {
@@ -3048,6 +3287,7 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
	.regs = &tegra20_pmc_regs,
	.init = tegra20_pmc_init,
	.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
	.powergate_set = tegra114_powergate_set,
	.irq_set_wake = tegra210_pmc_irq_set_wake,
	.irq_set_type = tegra210_pmc_irq_set_type,
	.reset_sources = tegra210_reset_sources,
@@ -3059,6 +3299,7 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
	.pmc_clks_data = tegra_pmc_clks_data,
	.num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
	.has_blink_output = true,
	.has_usb_sleepwalk = true,
};

#define TEGRA186_IO_PAD_TABLE(_pad)                                          \
@@ -3214,6 +3455,7 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = {
	.pmc_clks_data = NULL,
	.num_pmc_clks = 0,
	.has_blink_output = false,
	.has_usb_sleepwalk = false,
};

#define TEGRA194_IO_PAD_TABLE(_pad)                                              \
@@ -3347,6 +3589,7 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = {
	.pmc_clks_data = NULL,
	.num_pmc_clks = 0,
	.has_blink_output = false,
	.has_usb_sleepwalk = false,
};

static const struct tegra_pmc_regs tegra234_pmc_regs = {
+1 −1
Original line number Diff line number Diff line
@@ -178,7 +178,7 @@ static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra,
	 * survive the voltage drop if it's running on a higher frequency.
	 */
	if (!cpu_min_uV_consumers)
		cpu_min_uV = cpu_uV;
		cpu_min_uV = max(cpu_uV, cpu_min_uV);

	/*
	 * Bootloader shall set up voltages correctly, but if it