Commit b4067b10 authored by Olof Johansson's avatar Olof Johansson
Browse files

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

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

soc/tegra: Changes for v5.5-rc1

Adds wake event support on Tegra210, implements the NVMEM API for the
Tegra FUSE block and adds coupled regulators support for Tegra20 and
Tegra30.

* tag 'tegra-for-5.5-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux:
  soc/tegra: pmc: Remove unnecessary memory barrier
  soc/tegra: pmc: Query PCLK clock rate at probe time
  soc/tegra: regulators: Add regulators coupler for Tegra30
  soc/tegra: regulators: Add regulators coupler for Tegra20
  soc/tegra: pmc: Configure deep sleep control settings
  soc/tegra: pmc: Configure core power request polarity
  soc/tegra: pmc: Add wake event support on Tegra210
  soc/tegra: pmc: Support wake events on more Tegra SoCs
  soc/tegra: fuse: Register cell lookups for compatibility
  soc/tegra: fuse: Add cell information
  soc/tegra: fuse: Implement nvmem device
  soc/tegra: fuse: Restore base on sysfs failure
  soc/tegra: pmc: Fix crashes for hierarchical interrupts
  soc/tegra: fuse: Add FUSE clock check in tegra_fuse_readl()

Link: https://lore.kernel.org/r/20191102144521.3863321-4-thierry.reding@gmail.com


Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
parents f76b6a4c 69dfb3d4
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@ config ARCH_TEGRA_2x_SOC
	select PL310_ERRATA_769419 if CACHE_L2X0
	select SOC_TEGRA_FLOWCTRL
	select SOC_TEGRA_PMC
	select SOC_TEGRA20_VOLTAGE_COUPLER
	select TEGRA_TIMER
	help
	  Support for NVIDIA Tegra AP20 and T20 processors, based on the
@@ -28,6 +29,7 @@ config ARCH_TEGRA_3x_SOC
	select PL310_ERRATA_769419 if CACHE_L2X0
	select SOC_TEGRA_FLOWCTRL
	select SOC_TEGRA_PMC
	select SOC_TEGRA30_VOLTAGE_COUPLER
	select TEGRA_TIMER
	help
	  Support for NVIDIA Tegra T30 processor family, based on the
@@ -135,3 +137,11 @@ config SOC_TEGRA_POWERGATE_BPMP
	def_bool y
	depends on PM_GENERIC_DOMAINS
	depends on TEGRA_BPMP

config SOC_TEGRA20_VOLTAGE_COUPLER
	bool "Voltage scaling support for Tegra20 SoCs"
	depends on ARCH_TEGRA_2x_SOC || COMPILE_TEST

config SOC_TEGRA30_VOLTAGE_COUPLER
	bool "Voltage scaling support for Tegra30 SoCs"
	depends on ARCH_TEGRA_3x_SOC || COMPILE_TEST
+2 −0
Original line number Diff line number Diff line
@@ -5,3 +5,5 @@ obj-y += common.o
obj-$(CONFIG_SOC_TEGRA_FLOWCTRL) += flowctrl.o
obj-$(CONFIG_SOC_TEGRA_PMC) += pmc.o
obj-$(CONFIG_SOC_TEGRA_POWERGATE_BPMP) += powergate-bpmp.o
obj-$(CONFIG_SOC_TEGRA20_VOLTAGE_COUPLER) += regulators-tegra20.o
obj-$(CONFIG_SOC_TEGRA30_VOLTAGE_COUPLER) += regulators-tegra30.o
+146 −52
Original line number Diff line number Diff line
@@ -8,6 +8,8 @@
#include <linux/kobject.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/nvmem-consumer.h>
#include <linux/nvmem-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
@@ -31,50 +33,6 @@ static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
	[TEGRA_REVISION_A04]     = "A04",
};

static u8 fuse_readb(struct tegra_fuse *fuse, unsigned int offset)
{
	u32 val;

	val = fuse->read(fuse, round_down(offset, 4));
	val >>= (offset % 4) * 8;
	val &= 0xff;

	return val;
}

static ssize_t fuse_read(struct file *fd, struct kobject *kobj,
			 struct bin_attribute *attr, char *buf,
			 loff_t pos, size_t size)
{
	struct device *dev = kobj_to_dev(kobj);
	struct tegra_fuse *fuse = dev_get_drvdata(dev);
	int i;

	if (pos < 0 || pos >= attr->size)
		return 0;

	if (size > attr->size - pos)
		size = attr->size - pos;

	for (i = 0; i < size; i++)
		buf[i] = fuse_readb(fuse, pos + i);

	return i;
}

static struct bin_attribute fuse_bin_attr = {
	.attr = { .name = "fuse", .mode = S_IRUGO, },
	.read = fuse_read,
};

static int tegra_fuse_create_sysfs(struct device *dev, unsigned int size,
				   const struct tegra_fuse_info *info)
{
	fuse_bin_attr.size = size;

	return device_create_bin_file(dev, &fuse_bin_attr);
}

static const struct of_device_id car_match[] __initconst = {
	{ .compatible = "nvidia,tegra20-car", },
	{ .compatible = "nvidia,tegra30-car", },
@@ -115,9 +73,111 @@ static const struct of_device_id tegra_fuse_match[] = {
	{ /* sentinel */ }
};

static int tegra_fuse_read(void *priv, unsigned int offset, void *value,
			   size_t bytes)
{
	unsigned int count = bytes / 4, i;
	struct tegra_fuse *fuse = priv;
	u32 *buffer = value;

	for (i = 0; i < count; i++)
		buffer[i] = fuse->read(fuse, offset + i * 4);

	return 0;
}

static const struct nvmem_cell_info tegra_fuse_cells[] = {
	{
		.name = "tsensor-cpu1",
		.offset = 0x084,
		.bytes = 4,
		.bit_offset = 0,
		.nbits = 32,
	}, {
		.name = "tsensor-cpu2",
		.offset = 0x088,
		.bytes = 4,
		.bit_offset = 0,
		.nbits = 32,
	}, {
		.name = "tsensor-cpu0",
		.offset = 0x098,
		.bytes = 4,
		.bit_offset = 0,
		.nbits = 32,
	}, {
		.name = "xusb-pad-calibration",
		.offset = 0x0f0,
		.bytes = 4,
		.bit_offset = 0,
		.nbits = 32,
	}, {
		.name = "tsensor-cpu3",
		.offset = 0x12c,
		.bytes = 4,
		.bit_offset = 0,
		.nbits = 32,
	}, {
		.name = "sata-calibration",
		.offset = 0x124,
		.bytes = 1,
		.bit_offset = 0,
		.nbits = 2,
	}, {
		.name = "tsensor-gpu",
		.offset = 0x154,
		.bytes = 4,
		.bit_offset = 0,
		.nbits = 32,
	}, {
		.name = "tsensor-mem0",
		.offset = 0x158,
		.bytes = 4,
		.bit_offset = 0,
		.nbits = 32,
	}, {
		.name = "tsensor-mem1",
		.offset = 0x15c,
		.bytes = 4,
		.bit_offset = 0,
		.nbits = 32,
	}, {
		.name = "tsensor-pllx",
		.offset = 0x160,
		.bytes = 4,
		.bit_offset = 0,
		.nbits = 32,
	}, {
		.name = "tsensor-common",
		.offset = 0x180,
		.bytes = 4,
		.bit_offset = 0,
		.nbits = 32,
	}, {
		.name = "tsensor-realignment",
		.offset = 0x1fc,
		.bytes = 4,
		.bit_offset = 0,
		.nbits = 32,
	}, {
		.name = "gpu-calibration",
		.offset = 0x204,
		.bytes = 4,
		.bit_offset = 0,
		.nbits = 32,
	}, {
		.name = "xusb-pad-calibration-ext",
		.offset = 0x250,
		.bytes = 4,
		.bit_offset = 0,
		.nbits = 32,
	},
};

static int tegra_fuse_probe(struct platform_device *pdev)
{
	void __iomem *base = fuse->base;
	struct nvmem_config nvmem;
	struct resource *res;
	int err;

@@ -146,20 +206,42 @@ static int tegra_fuse_probe(struct platform_device *pdev)

	if (fuse->soc->probe) {
		err = fuse->soc->probe(fuse);
		if (err < 0) {
			fuse->base = base;
			return err;
		}
		if (err < 0)
			goto restore;
	}

	if (tegra_fuse_create_sysfs(&pdev->dev, fuse->soc->info->size,
				    fuse->soc->info))
		return -ENODEV;
	memset(&nvmem, 0, sizeof(nvmem));
	nvmem.dev = &pdev->dev;
	nvmem.name = "fuse";
	nvmem.id = -1;
	nvmem.owner = THIS_MODULE;
	nvmem.cells = tegra_fuse_cells;
	nvmem.ncells = ARRAY_SIZE(tegra_fuse_cells);
	nvmem.type = NVMEM_TYPE_OTP;
	nvmem.read_only = true;
	nvmem.root_only = true;
	nvmem.reg_read = tegra_fuse_read;
	nvmem.size = fuse->soc->info->size;
	nvmem.word_size = 4;
	nvmem.stride = 4;
	nvmem.priv = fuse;

	fuse->nvmem = devm_nvmem_register(&pdev->dev, &nvmem);
	if (IS_ERR(fuse->nvmem)) {
		err = PTR_ERR(fuse->nvmem);
		dev_err(&pdev->dev, "failed to register NVMEM device: %d\n",
			err);
		goto restore;
	}

	/* release the early I/O memory mapping */
	iounmap(base);

	return 0;

restore:
	fuse->base = base;
	return err;
}

static struct platform_driver tegra_fuse_driver = {
@@ -186,9 +268,12 @@ u32 __init tegra_fuse_read_early(unsigned int offset)

int tegra_fuse_readl(unsigned long offset, u32 *value)
{
	if (!fuse->read)
	if (!fuse->read || !fuse->clk)
		return -EPROBE_DEFER;

	if (IS_ERR(fuse->clk))
		return PTR_ERR(fuse->clk);

	*value = fuse->read(fuse, offset);

	return 0;
@@ -338,6 +423,15 @@ static int __init tegra_init_fuse(void)
	pr_debug("Tegra CPU Speedo ID %d, SoC Speedo ID %d\n",
		 tegra_sku_info.cpu_speedo_id, tegra_sku_info.soc_speedo_id);

	if (fuse->soc->lookups) {
		size_t size = sizeof(*fuse->lookups) * fuse->soc->num_lookups;

		fuse->lookups = kmemdup(fuse->soc->lookups, size, GFP_KERNEL);
		if (!fuse->lookups)
			return -ENOMEM;

		nvmem_add_cell_lookups(fuse->lookups, fuse->soc->num_lookups);
	}

	return 0;
}
+154 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/nvmem-consumer.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
@@ -127,6 +128,70 @@ const struct tegra_fuse_soc tegra114_fuse_soc = {
#endif

#if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC)
static const struct nvmem_cell_lookup tegra124_fuse_lookups[] = {
	{
		.nvmem_name = "fuse",
		.cell_name = "xusb-pad-calibration",
		.dev_id = "7009f000.padctl",
		.con_id = "calibration",
	}, {
		.nvmem_name = "fuse",
		.cell_name = "sata-calibration",
		.dev_id = "70020000.sata",
		.con_id = "calibration",
	}, {
		.nvmem_name = "fuse",
		.cell_name = "tsensor-common",
		.dev_id = "700e2000.thermal-sensor",
		.con_id = "common",
	}, {
		.nvmem_name = "fuse",
		.cell_name = "tsensor-realignment",
		.dev_id = "700e2000.thermal-sensor",
		.con_id = "realignment",
	}, {
		.nvmem_name = "fuse",
		.cell_name = "tsensor-cpu0",
		.dev_id = "700e2000.thermal-sensor",
		.con_id = "cpu0",
	}, {
		.nvmem_name = "fuse",
		.cell_name = "tsensor-cpu1",
		.dev_id = "700e2000.thermal-sensor",
		.con_id = "cpu1",
	}, {
		.nvmem_name = "fuse",
		.cell_name = "tsensor-cpu2",
		.dev_id = "700e2000.thermal-sensor",
		.con_id = "cpu2",
	}, {
		.nvmem_name = "fuse",
		.cell_name = "tsensor-cpu3",
		.dev_id = "700e2000.thermal-sensor",
		.con_id = "cpu3",
	}, {
		.nvmem_name = "fuse",
		.cell_name = "tsensor-mem0",
		.dev_id = "700e2000.thermal-sensor",
		.con_id = "mem0",
	}, {
		.nvmem_name = "fuse",
		.cell_name = "tsensor-mem1",
		.dev_id = "700e2000.thermal-sensor",
		.con_id = "mem1",
	}, {
		.nvmem_name = "fuse",
		.cell_name = "tsensor-gpu",
		.dev_id = "700e2000.thermal-sensor",
		.con_id = "gpu",
	}, {
		.nvmem_name = "fuse",
		.cell_name = "tsensor-pllx",
		.dev_id = "700e2000.thermal-sensor",
		.con_id = "pllx",
	},
};

static const struct tegra_fuse_info tegra124_fuse_info = {
	.read = tegra30_fuse_read,
	.size = 0x300,
@@ -137,10 +202,81 @@ const struct tegra_fuse_soc tegra124_fuse_soc = {
	.init = tegra30_fuse_init,
	.speedo_init = tegra124_init_speedo_data,
	.info = &tegra124_fuse_info,
	.lookups = tegra124_fuse_lookups,
	.num_lookups = ARRAY_SIZE(tegra124_fuse_lookups),
};
#endif

#if defined(CONFIG_ARCH_TEGRA_210_SOC)
static const struct nvmem_cell_lookup tegra210_fuse_lookups[] = {
	{
		.nvmem_name = "fuse",
		.cell_name = "tsensor-cpu1",
		.dev_id = "700e2000.thermal-sensor",
		.con_id = "cpu1",
	}, {
		.nvmem_name = "fuse",
		.cell_name = "tsensor-cpu2",
		.dev_id = "700e2000.thermal-sensor",
		.con_id = "cpu2",
	}, {
		.nvmem_name = "fuse",
		.cell_name = "tsensor-cpu0",
		.dev_id = "700e2000.thermal-sensor",
		.con_id = "cpu0",
	}, {
		.nvmem_name = "fuse",
		.cell_name = "xusb-pad-calibration",
		.dev_id = "7009f000.padctl",
		.con_id = "calibration",
	}, {
		.nvmem_name = "fuse",
		.cell_name = "tsensor-cpu3",
		.dev_id = "700e2000.thermal-sensor",
		.con_id = "cpu3",
	}, {
		.nvmem_name = "fuse",
		.cell_name = "sata-calibration",
		.dev_id = "70020000.sata",
		.con_id = "calibration",
	}, {
		.nvmem_name = "fuse",
		.cell_name = "tsensor-gpu",
		.dev_id = "700e2000.thermal-sensor",
		.con_id = "gpu",
	}, {
		.nvmem_name = "fuse",
		.cell_name = "tsensor-mem0",
		.dev_id = "700e2000.thermal-sensor",
		.con_id = "mem0",
	}, {
		.nvmem_name = "fuse",
		.cell_name = "tsensor-mem1",
		.dev_id = "700e2000.thermal-sensor",
		.con_id = "mem1",
	}, {
		.nvmem_name = "fuse",
		.cell_name = "tsensor-pllx",
		.dev_id = "700e2000.thermal-sensor",
		.con_id = "pllx",
	}, {
		.nvmem_name = "fuse",
		.cell_name = "tsensor-common",
		.dev_id = "700e2000.thermal-sensor",
		.con_id = "common",
	}, {
		.nvmem_name = "fuse",
		.cell_name = "gpu-calibration",
		.dev_id = "57000000.gpu",
		.con_id = "calibration",
	}, {
		.nvmem_name = "fuse",
		.cell_name = "xusb-pad-calibration-ext",
		.dev_id = "7009f000.padctl",
		.con_id = "calibration-ext",
	},
};

static const struct tegra_fuse_info tegra210_fuse_info = {
	.read = tegra30_fuse_read,
	.size = 0x300,
@@ -151,10 +287,26 @@ const struct tegra_fuse_soc tegra210_fuse_soc = {
	.init = tegra30_fuse_init,
	.speedo_init = tegra210_init_speedo_data,
	.info = &tegra210_fuse_info,
	.lookups = tegra210_fuse_lookups,
	.num_lookups = ARRAY_SIZE(tegra210_fuse_lookups),
};
#endif

#if defined(CONFIG_ARCH_TEGRA_186_SOC)
static const struct nvmem_cell_lookup tegra186_fuse_lookups[] = {
	{
		.nvmem_name = "fuse",
		.cell_name = "xusb-pad-calibration",
		.dev_id = "3520000.padctl",
		.con_id = "calibration",
	}, {
		.nvmem_name = "fuse",
		.cell_name = "xusb-pad-calibration-ext",
		.dev_id = "3520000.padctl",
		.con_id = "calibration-ext",
	},
};

static const struct tegra_fuse_info tegra186_fuse_info = {
	.read = tegra30_fuse_read,
	.size = 0x300,
@@ -164,5 +316,7 @@ static const struct tegra_fuse_info tegra186_fuse_info = {
const struct tegra_fuse_soc tegra186_fuse_soc = {
	.init = tegra30_fuse_init,
	.info = &tegra186_fuse_info,
	.lookups = tegra186_fuse_lookups,
	.num_lookups = ARRAY_SIZE(tegra186_fuse_lookups),
};
#endif
+8 −0
Original line number Diff line number Diff line
@@ -13,6 +13,8 @@
#include <linux/dmaengine.h>
#include <linux/types.h>

struct nvmem_cell_lookup;
struct nvmem_device;
struct tegra_fuse;

struct tegra_fuse_info {
@@ -27,6 +29,9 @@ struct tegra_fuse_soc {
	int (*probe)(struct tegra_fuse *fuse);

	const struct tegra_fuse_info *info;

	const struct nvmem_cell_lookup *lookups;
	unsigned int num_lookups;
};

struct tegra_fuse {
@@ -48,6 +53,9 @@ struct tegra_fuse {
		dma_addr_t phys;
		u32 *virt;
	} apbdma;

	struct nvmem_device *nvmem;
	struct nvmem_cell_lookup *lookups;
};

void tegra_init_revision(void);
Loading