1783c8f4cSPeter De Schrijver /* 2783c8f4cSPeter De Schrijver * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. 3783c8f4cSPeter De Schrijver * 4783c8f4cSPeter De Schrijver * This program is free software; you can redistribute it and/or modify it 5783c8f4cSPeter De Schrijver * under the terms and conditions of the GNU General Public License, 6783c8f4cSPeter De Schrijver * version 2, as published by the Free Software Foundation. 7783c8f4cSPeter De Schrijver * 8783c8f4cSPeter De Schrijver * This program is distributed in the hope it will be useful, but WITHOUT 9783c8f4cSPeter De Schrijver * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10783c8f4cSPeter De Schrijver * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11783c8f4cSPeter De Schrijver * more details. 12783c8f4cSPeter De Schrijver * 13783c8f4cSPeter De Schrijver * You should have received a copy of the GNU General Public License 14783c8f4cSPeter De Schrijver * along with this program. If not, see <http://www.gnu.org/licenses/>. 15783c8f4cSPeter De Schrijver * 16783c8f4cSPeter De Schrijver */ 17783c8f4cSPeter De Schrijver 18*7e939de1SThierry Reding #include <linux/clk.h> 19783c8f4cSPeter De Schrijver #include <linux/device.h> 20783c8f4cSPeter De Schrijver #include <linux/kobject.h> 21*7e939de1SThierry Reding #include <linux/module.h> 22783c8f4cSPeter De Schrijver #include <linux/platform_device.h> 23783c8f4cSPeter De Schrijver #include <linux/of.h> 24783c8f4cSPeter De Schrijver #include <linux/of_address.h> 25783c8f4cSPeter De Schrijver #include <linux/io.h> 26783c8f4cSPeter De Schrijver 2724fa5af8SThierry Reding #include <soc/tegra/common.h> 28783c8f4cSPeter De Schrijver #include <soc/tegra/fuse.h> 29783c8f4cSPeter De Schrijver 30783c8f4cSPeter De Schrijver #include "fuse.h" 31783c8f4cSPeter De Schrijver 32783c8f4cSPeter De Schrijver struct tegra_sku_info tegra_sku_info; 33f9fc3661SVince Hsu EXPORT_SYMBOL(tegra_sku_info); 34783c8f4cSPeter De Schrijver 35783c8f4cSPeter De Schrijver static const char *tegra_revision_name[TEGRA_REVISION_MAX] = { 36783c8f4cSPeter De Schrijver [TEGRA_REVISION_UNKNOWN] = "unknown", 37783c8f4cSPeter De Schrijver [TEGRA_REVISION_A01] = "A01", 38783c8f4cSPeter De Schrijver [TEGRA_REVISION_A02] = "A02", 39783c8f4cSPeter De Schrijver [TEGRA_REVISION_A03] = "A03", 40783c8f4cSPeter De Schrijver [TEGRA_REVISION_A03p] = "A03 prime", 41783c8f4cSPeter De Schrijver [TEGRA_REVISION_A04] = "A04", 42783c8f4cSPeter De Schrijver }; 43783c8f4cSPeter De Schrijver 44*7e939de1SThierry Reding static u8 fuse_readb(struct tegra_fuse *fuse, unsigned int offset) 45783c8f4cSPeter De Schrijver { 46783c8f4cSPeter De Schrijver u32 val; 47783c8f4cSPeter De Schrijver 48*7e939de1SThierry Reding val = fuse->read(fuse, round_down(offset, 4)); 49783c8f4cSPeter De Schrijver val >>= (offset % 4) * 8; 50783c8f4cSPeter De Schrijver val &= 0xff; 51783c8f4cSPeter De Schrijver 52783c8f4cSPeter De Schrijver return val; 53783c8f4cSPeter De Schrijver } 54783c8f4cSPeter De Schrijver 55783c8f4cSPeter De Schrijver static ssize_t fuse_read(struct file *fd, struct kobject *kobj, 56783c8f4cSPeter De Schrijver struct bin_attribute *attr, char *buf, 57783c8f4cSPeter De Schrijver loff_t pos, size_t size) 58783c8f4cSPeter De Schrijver { 59*7e939de1SThierry Reding struct device *dev = kobj_to_dev(kobj); 60*7e939de1SThierry Reding struct tegra_fuse *fuse = dev_get_drvdata(dev); 61783c8f4cSPeter De Schrijver int i; 62783c8f4cSPeter De Schrijver 63*7e939de1SThierry Reding if (pos < 0 || pos >= attr->size) 64783c8f4cSPeter De Schrijver return 0; 65783c8f4cSPeter De Schrijver 66*7e939de1SThierry Reding if (size > attr->size - pos) 67*7e939de1SThierry Reding size = attr->size - pos; 68783c8f4cSPeter De Schrijver 69783c8f4cSPeter De Schrijver for (i = 0; i < size; i++) 70*7e939de1SThierry Reding buf[i] = fuse_readb(fuse, pos + i); 71783c8f4cSPeter De Schrijver 72783c8f4cSPeter De Schrijver return i; 73783c8f4cSPeter De Schrijver } 74783c8f4cSPeter De Schrijver 75783c8f4cSPeter De Schrijver static struct bin_attribute fuse_bin_attr = { 76783c8f4cSPeter De Schrijver .attr = { .name = "fuse", .mode = S_IRUGO, }, 77783c8f4cSPeter De Schrijver .read = fuse_read, 78783c8f4cSPeter De Schrijver }; 79783c8f4cSPeter De Schrijver 80*7e939de1SThierry Reding static int tegra_fuse_create_sysfs(struct device *dev, unsigned int size, 81*7e939de1SThierry Reding const struct tegra_fuse_info *info) 82*7e939de1SThierry Reding { 83*7e939de1SThierry Reding fuse_bin_attr.size = size; 84*7e939de1SThierry Reding 85*7e939de1SThierry Reding return device_create_bin_file(dev, &fuse_bin_attr); 86*7e939de1SThierry Reding } 87*7e939de1SThierry Reding 88783c8f4cSPeter De Schrijver static const struct of_device_id car_match[] __initconst = { 89783c8f4cSPeter De Schrijver { .compatible = "nvidia,tegra20-car", }, 90783c8f4cSPeter De Schrijver { .compatible = "nvidia,tegra30-car", }, 91783c8f4cSPeter De Schrijver { .compatible = "nvidia,tegra114-car", }, 92783c8f4cSPeter De Schrijver { .compatible = "nvidia,tegra124-car", }, 939b07eb05SThierry Reding { .compatible = "nvidia,tegra132-car", }, 94783c8f4cSPeter De Schrijver {}, 95783c8f4cSPeter De Schrijver }; 96783c8f4cSPeter De Schrijver 97*7e939de1SThierry Reding static struct tegra_fuse *fuse = &(struct tegra_fuse) { 98*7e939de1SThierry Reding .base = NULL, 99*7e939de1SThierry Reding .soc = NULL, 100*7e939de1SThierry Reding }; 101*7e939de1SThierry Reding 102*7e939de1SThierry Reding static const struct of_device_id tegra_fuse_match[] = { 103*7e939de1SThierry Reding #ifdef CONFIG_ARCH_TEGRA_132_SOC 104*7e939de1SThierry Reding { .compatible = "nvidia,tegra132-efuse", .data = &tegra124_fuse_soc }, 105*7e939de1SThierry Reding #endif 106*7e939de1SThierry Reding #ifdef CONFIG_ARCH_TEGRA_124_SOC 107*7e939de1SThierry Reding { .compatible = "nvidia,tegra124-efuse", .data = &tegra124_fuse_soc }, 108*7e939de1SThierry Reding #endif 109*7e939de1SThierry Reding #ifdef CONFIG_ARCH_TEGRA_114_SOC 110*7e939de1SThierry Reding { .compatible = "nvidia,tegra114-efuse", .data = &tegra114_fuse_soc }, 111*7e939de1SThierry Reding #endif 112*7e939de1SThierry Reding #ifdef CONFIG_ARCH_TEGRA_3x_SOC 113*7e939de1SThierry Reding { .compatible = "nvidia,tegra30-efuse", .data = &tegra30_fuse_soc }, 114*7e939de1SThierry Reding #endif 115*7e939de1SThierry Reding #ifdef CONFIG_ARCH_TEGRA_2x_SOC 116*7e939de1SThierry Reding { .compatible = "nvidia,tegra20-efuse", .data = &tegra20_fuse_soc }, 117*7e939de1SThierry Reding #endif 118*7e939de1SThierry Reding { /* sentinel */ } 119*7e939de1SThierry Reding }; 120*7e939de1SThierry Reding 121*7e939de1SThierry Reding static int tegra_fuse_probe(struct platform_device *pdev) 122*7e939de1SThierry Reding { 123*7e939de1SThierry Reding void __iomem *base = fuse->base; 124*7e939de1SThierry Reding struct resource *res; 125*7e939de1SThierry Reding int err; 126*7e939de1SThierry Reding 127*7e939de1SThierry Reding /* take over the memory region from the early initialization */ 128*7e939de1SThierry Reding res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 129*7e939de1SThierry Reding fuse->base = devm_ioremap_resource(&pdev->dev, res); 130*7e939de1SThierry Reding if (IS_ERR(fuse->base)) 131*7e939de1SThierry Reding return PTR_ERR(fuse->base); 132*7e939de1SThierry Reding 133*7e939de1SThierry Reding fuse->clk = devm_clk_get(&pdev->dev, "fuse"); 134*7e939de1SThierry Reding if (IS_ERR(fuse->clk)) { 135*7e939de1SThierry Reding dev_err(&pdev->dev, "failed to get FUSE clock: %ld", 136*7e939de1SThierry Reding PTR_ERR(fuse->clk)); 137*7e939de1SThierry Reding return PTR_ERR(fuse->clk); 138*7e939de1SThierry Reding } 139*7e939de1SThierry Reding 140*7e939de1SThierry Reding platform_set_drvdata(pdev, fuse); 141*7e939de1SThierry Reding fuse->dev = &pdev->dev; 142*7e939de1SThierry Reding 143*7e939de1SThierry Reding if (fuse->soc->probe) { 144*7e939de1SThierry Reding err = fuse->soc->probe(fuse); 145*7e939de1SThierry Reding if (err < 0) 146*7e939de1SThierry Reding return err; 147*7e939de1SThierry Reding } 148*7e939de1SThierry Reding 149*7e939de1SThierry Reding if (tegra_fuse_create_sysfs(&pdev->dev, fuse->soc->info->size, 150*7e939de1SThierry Reding fuse->soc->info)) 151*7e939de1SThierry Reding return -ENODEV; 152*7e939de1SThierry Reding 153*7e939de1SThierry Reding /* release the early I/O memory mapping */ 154*7e939de1SThierry Reding iounmap(base); 155*7e939de1SThierry Reding 156*7e939de1SThierry Reding return 0; 157*7e939de1SThierry Reding } 158*7e939de1SThierry Reding 159*7e939de1SThierry Reding static struct platform_driver tegra_fuse_driver = { 160*7e939de1SThierry Reding .driver = { 161*7e939de1SThierry Reding .name = "tegra-fuse", 162*7e939de1SThierry Reding .of_match_table = tegra_fuse_match, 163*7e939de1SThierry Reding .suppress_bind_attrs = true, 164*7e939de1SThierry Reding }, 165*7e939de1SThierry Reding .probe = tegra_fuse_probe, 166*7e939de1SThierry Reding }; 167*7e939de1SThierry Reding module_platform_driver(tegra_fuse_driver); 168*7e939de1SThierry Reding 169*7e939de1SThierry Reding bool __init tegra_fuse_read_spare(unsigned int spare) 170*7e939de1SThierry Reding { 171*7e939de1SThierry Reding unsigned int offset = fuse->soc->info->spare + spare * 4; 172*7e939de1SThierry Reding 173*7e939de1SThierry Reding return fuse->read_early(fuse, offset) & 1; 174*7e939de1SThierry Reding } 175*7e939de1SThierry Reding 176*7e939de1SThierry Reding u32 __init tegra_fuse_read_early(unsigned int offset) 177*7e939de1SThierry Reding { 178*7e939de1SThierry Reding return fuse->read_early(fuse, offset); 179*7e939de1SThierry Reding } 180*7e939de1SThierry Reding 181*7e939de1SThierry Reding int tegra_fuse_readl(unsigned long offset, u32 *value) 182*7e939de1SThierry Reding { 183*7e939de1SThierry Reding if (!fuse->read) 184*7e939de1SThierry Reding return -EPROBE_DEFER; 185*7e939de1SThierry Reding 186*7e939de1SThierry Reding *value = fuse->read(fuse, offset); 187*7e939de1SThierry Reding 188*7e939de1SThierry Reding return 0; 189*7e939de1SThierry Reding } 190*7e939de1SThierry Reding EXPORT_SYMBOL(tegra_fuse_readl); 191*7e939de1SThierry Reding 192783c8f4cSPeter De Schrijver static void tegra_enable_fuse_clk(void __iomem *base) 193783c8f4cSPeter De Schrijver { 194783c8f4cSPeter De Schrijver u32 reg; 195783c8f4cSPeter De Schrijver 196783c8f4cSPeter De Schrijver reg = readl_relaxed(base + 0x48); 197783c8f4cSPeter De Schrijver reg |= 1 << 28; 198783c8f4cSPeter De Schrijver writel(reg, base + 0x48); 199783c8f4cSPeter De Schrijver 200783c8f4cSPeter De Schrijver /* 201783c8f4cSPeter De Schrijver * Enable FUSE clock. This needs to be hardcoded because the clock 202783c8f4cSPeter De Schrijver * subsystem is not active during early boot. 203783c8f4cSPeter De Schrijver */ 204783c8f4cSPeter De Schrijver reg = readl(base + 0x14); 205783c8f4cSPeter De Schrijver reg |= 1 << 7; 206783c8f4cSPeter De Schrijver writel(reg, base + 0x14); 207783c8f4cSPeter De Schrijver } 208783c8f4cSPeter De Schrijver 20924fa5af8SThierry Reding static int __init tegra_init_fuse(void) 210783c8f4cSPeter De Schrijver { 211*7e939de1SThierry Reding const struct of_device_id *match; 212783c8f4cSPeter De Schrijver struct device_node *np; 213*7e939de1SThierry Reding struct resource regs; 21424fa5af8SThierry Reding 215783c8f4cSPeter De Schrijver tegra_init_apbmisc(); 216783c8f4cSPeter De Schrijver 217*7e939de1SThierry Reding np = of_find_matching_node_and_match(NULL, tegra_fuse_match, &match); 218*7e939de1SThierry Reding if (!np) { 219*7e939de1SThierry Reding /* 220*7e939de1SThierry Reding * Fall back to legacy initialization for 32-bit ARM only. All 221*7e939de1SThierry Reding * 64-bit ARM device tree files for Tegra are required to have 222*7e939de1SThierry Reding * a FUSE node. 223*7e939de1SThierry Reding * 224*7e939de1SThierry Reding * This is for backwards-compatibility with old device trees 225*7e939de1SThierry Reding * that didn't contain a FUSE node. 226*7e939de1SThierry Reding */ 227*7e939de1SThierry Reding if (IS_ENABLED(CONFIG_ARM) && soc_is_tegra()) { 228*7e939de1SThierry Reding u8 chip = tegra_get_chip_id(); 229*7e939de1SThierry Reding 230*7e939de1SThierry Reding regs.start = 0x7000f800; 231*7e939de1SThierry Reding regs.end = 0x7000fbff; 232*7e939de1SThierry Reding regs.flags = IORESOURCE_MEM; 233*7e939de1SThierry Reding 234*7e939de1SThierry Reding switch (chip) { 235*7e939de1SThierry Reding #ifdef CONFIG_ARCH_TEGRA_2x_SOC 236*7e939de1SThierry Reding case TEGRA20: 237*7e939de1SThierry Reding fuse->soc = &tegra20_fuse_soc; 238*7e939de1SThierry Reding break; 239*7e939de1SThierry Reding #endif 240*7e939de1SThierry Reding 241*7e939de1SThierry Reding #ifdef CONFIG_ARCH_TEGRA_3x_SOC 242*7e939de1SThierry Reding case TEGRA30: 243*7e939de1SThierry Reding fuse->soc = &tegra30_fuse_soc; 244*7e939de1SThierry Reding break; 245*7e939de1SThierry Reding #endif 246*7e939de1SThierry Reding 247*7e939de1SThierry Reding #ifdef CONFIG_ARCH_TEGRA_114_SOC 248*7e939de1SThierry Reding case TEGRA114: 249*7e939de1SThierry Reding fuse->soc = &tegra114_fuse_soc; 250*7e939de1SThierry Reding break; 251*7e939de1SThierry Reding #endif 252*7e939de1SThierry Reding 253*7e939de1SThierry Reding #ifdef CONFIG_ARCH_TEGRA_124_SOC 254*7e939de1SThierry Reding case TEGRA124: 255*7e939de1SThierry Reding fuse->soc = &tegra124_fuse_soc; 256*7e939de1SThierry Reding break; 257*7e939de1SThierry Reding #endif 258*7e939de1SThierry Reding 259*7e939de1SThierry Reding default: 260*7e939de1SThierry Reding pr_warn("Unsupported SoC: %02x\n", chip); 261*7e939de1SThierry Reding break; 262*7e939de1SThierry Reding } 263783c8f4cSPeter De Schrijver } else { 264*7e939de1SThierry Reding /* 265*7e939de1SThierry Reding * At this point we're not running on Tegra, so play 266*7e939de1SThierry Reding * nice with multi-platform kernels. 267*7e939de1SThierry Reding */ 268*7e939de1SThierry Reding return 0; 269*7e939de1SThierry Reding } 270*7e939de1SThierry Reding } else { 271*7e939de1SThierry Reding /* 272*7e939de1SThierry Reding * Extract information from the device tree if we've found a 273*7e939de1SThierry Reding * matching node. 274*7e939de1SThierry Reding */ 275*7e939de1SThierry Reding if (of_address_to_resource(np, 0, ®s) < 0) { 276*7e939de1SThierry Reding pr_err("failed to get FUSE register\n"); 27724fa5af8SThierry Reding return -ENXIO; 278783c8f4cSPeter De Schrijver } 279783c8f4cSPeter De Schrijver 280*7e939de1SThierry Reding fuse->soc = match->data; 281*7e939de1SThierry Reding } 282*7e939de1SThierry Reding 283*7e939de1SThierry Reding np = of_find_matching_node(NULL, car_match); 284*7e939de1SThierry Reding if (np) { 285*7e939de1SThierry Reding void __iomem *base = of_iomap(np, 0); 286*7e939de1SThierry Reding if (base) { 287*7e939de1SThierry Reding tegra_enable_fuse_clk(base); 288*7e939de1SThierry Reding iounmap(base); 289*7e939de1SThierry Reding } else { 290*7e939de1SThierry Reding pr_err("failed to map clock registers\n"); 291*7e939de1SThierry Reding return -ENXIO; 292*7e939de1SThierry Reding } 293*7e939de1SThierry Reding } 294*7e939de1SThierry Reding 295*7e939de1SThierry Reding fuse->base = ioremap_nocache(regs.start, resource_size(®s)); 296*7e939de1SThierry Reding if (!fuse->base) { 297*7e939de1SThierry Reding pr_err("failed to map FUSE registers\n"); 298*7e939de1SThierry Reding return -ENXIO; 299*7e939de1SThierry Reding } 300*7e939de1SThierry Reding 301*7e939de1SThierry Reding fuse->soc->init(fuse); 302783c8f4cSPeter De Schrijver 303783c8f4cSPeter De Schrijver pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n", 304783c8f4cSPeter De Schrijver tegra_revision_name[tegra_sku_info.revision], 305783c8f4cSPeter De Schrijver tegra_sku_info.sku_id, tegra_sku_info.cpu_process_id, 306783c8f4cSPeter De Schrijver tegra_sku_info.core_process_id); 307783c8f4cSPeter De Schrijver pr_debug("Tegra CPU Speedo ID %d, Soc Speedo ID %d\n", 308783c8f4cSPeter De Schrijver tegra_sku_info.cpu_speedo_id, tegra_sku_info.soc_speedo_id); 30924fa5af8SThierry Reding 31024fa5af8SThierry Reding return 0; 311783c8f4cSPeter De Schrijver } 31224fa5af8SThierry Reding early_initcall(tegra_init_fuse); 313