diff options
Diffstat (limited to 'drivers/soc/tegra/fuse')
-rw-r--r-- | drivers/soc/tegra/fuse/fuse-tegra.c | 203 | ||||
-rw-r--r-- | drivers/soc/tegra/fuse/fuse-tegra30.c | 186 | ||||
-rw-r--r-- | drivers/soc/tegra/fuse/fuse.h | 12 | ||||
-rw-r--r-- | drivers/soc/tegra/fuse/tegra-apbmisc.c | 38 |
4 files changed, 369 insertions, 70 deletions
diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c index 3eb44e65b326..802717b9f6a3 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra.c +++ b/drivers/soc/tegra/fuse/fuse-tegra.c @@ -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", }, @@ -91,6 +49,9 @@ static struct tegra_fuse *fuse = &(struct tegra_fuse) { }; static const struct of_device_id tegra_fuse_match[] = { +#ifdef CONFIG_ARCH_TEGRA_194_SOC + { .compatible = "nvidia,tegra194-efuse", .data = &tegra194_fuse_soc }, +#endif #ifdef CONFIG_ARCH_TEGRA_186_SOC { .compatible = "nvidia,tegra186-efuse", .data = &tegra186_fuse_soc }, #endif @@ -115,9 +76,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 +209,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 +271,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; @@ -323,7 +411,7 @@ static int __init tegra_init_fuse(void) } } - fuse->base = ioremap_nocache(regs.start, resource_size(®s)); + fuse->base = ioremap(regs.start, resource_size(®s)); if (!fuse->base) { pr_err("failed to map FUSE registers\n"); return -ENXIO; @@ -338,6 +426,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; } diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c index be9424a87173..e6037f900fb7 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra30.c +++ b/drivers/soc/tegra/fuse/fuse-tegra30.c @@ -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> @@ -35,7 +36,8 @@ defined(CONFIG_ARCH_TEGRA_124_SOC) || \ defined(CONFIG_ARCH_TEGRA_132_SOC) || \ defined(CONFIG_ARCH_TEGRA_210_SOC) || \ - defined(CONFIG_ARCH_TEGRA_186_SOC) + defined(CONFIG_ARCH_TEGRA_186_SOC) || \ + defined(CONFIG_ARCH_TEGRA_194_SOC) static u32 tegra30_fuse_read_early(struct tegra_fuse *fuse, unsigned int offset) { if (WARN_ON(!fuse->base)) @@ -127,6 +129,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 +203,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 +288,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 +317,36 @@ 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 + +#if defined(CONFIG_ARCH_TEGRA_194_SOC) +static const struct nvmem_cell_lookup tegra194_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 tegra194_fuse_info = { + .read = tegra30_fuse_read, + .size = 0x300, + .spare = 0x280, +}; + +const struct tegra_fuse_soc tegra194_fuse_soc = { + .init = tegra30_fuse_init, + .info = &tegra194_fuse_info, + .lookups = tegra194_fuse_lookups, + .num_lookups = ARRAY_SIZE(tegra194_fuse_lookups), }; #endif diff --git a/drivers/soc/tegra/fuse/fuse.h b/drivers/soc/tegra/fuse/fuse.h index 7230cb330503..94a059e577a1 100644 --- a/drivers/soc/tegra/fuse/fuse.h +++ b/drivers/soc/tegra/fuse/fuse.h @@ -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); @@ -100,4 +108,8 @@ extern const struct tegra_fuse_soc tegra210_fuse_soc; extern const struct tegra_fuse_soc tegra186_fuse_soc; #endif +#ifdef CONFIG_ARCH_TEGRA_194_SOC +extern const struct tegra_fuse_soc tegra194_fuse_soc; +#endif + #endif diff --git a/drivers/soc/tegra/fuse/tegra-apbmisc.c b/drivers/soc/tegra/fuse/tegra-apbmisc.c index df76778af601..089d9340564b 100644 --- a/drivers/soc/tegra/fuse/tegra-apbmisc.c +++ b/drivers/soc/tegra/fuse/tegra-apbmisc.c @@ -21,18 +21,15 @@ #define PMC_STRAPPING_OPT_A_RAM_CODE_MASK_SHORT \ (0x3 << PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT) -static void __iomem *apbmisc_base; -static void __iomem *strapping_base; static bool long_ram_code; +static u32 strapping; +static u32 chipid; u32 tegra_read_chipid(void) { - if (!apbmisc_base) { - WARN(1, "Tegra Chip ID not yet available\n"); - return 0; - } + WARN(!chipid, "Tegra ABP MISC not yet available\n"); - return readl_relaxed(apbmisc_base + 4); + return chipid; } u8 tegra_get_chip_id(void) @@ -42,10 +39,9 @@ u8 tegra_get_chip_id(void) u32 tegra_read_straps(void) { - if (strapping_base) - return readl_relaxed(strapping_base); - else - return 0; + WARN(!chipid, "Tegra ABP MISC not yet available\n"); + + return strapping; } u32 tegra_read_ram_code(void) @@ -63,6 +59,7 @@ u32 tegra_read_ram_code(void) static const struct of_device_id apbmisc_match[] __initconst = { { .compatible = "nvidia,tegra20-apbmisc", }, { .compatible = "nvidia,tegra186-misc", }, + { .compatible = "nvidia,tegra194-misc", }, {}, }; @@ -103,6 +100,7 @@ void __init tegra_init_revision(void) void __init tegra_init_apbmisc(void) { + void __iomem *apbmisc_base, *strapping_base; struct resource apbmisc, straps; struct device_node *np; @@ -123,7 +121,7 @@ void __init tegra_init_apbmisc(void) apbmisc.flags = IORESOURCE_MEM; /* strapping options */ - if (tegra_get_chip_id() == TEGRA124) { + if (of_machine_is_compatible("nvidia,tegra124")) { straps.start = 0x7000e864; straps.end = 0x7000e867; } else { @@ -159,13 +157,21 @@ void __init tegra_init_apbmisc(void) } } - apbmisc_base = ioremap_nocache(apbmisc.start, resource_size(&apbmisc)); - if (!apbmisc_base) + apbmisc_base = ioremap(apbmisc.start, resource_size(&apbmisc)); + if (!apbmisc_base) { pr_err("failed to map APBMISC registers\n"); + } else { + chipid = readl_relaxed(apbmisc_base + 4); + iounmap(apbmisc_base); + } - strapping_base = ioremap_nocache(straps.start, resource_size(&straps)); - if (!strapping_base) + strapping_base = ioremap(straps.start, resource_size(&straps)); + if (!strapping_base) { pr_err("failed to map strapping options registers\n"); + } else { + strapping = readl_relaxed(strapping_base); + iounmap(strapping_base); + } long_ram_code = of_property_read_bool(np, "nvidia,long-ram-code"); } |