1 /* 2 * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms and conditions of the GNU General Public License, 6 * version 2, as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 * more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 * 16 * Based on drivers/misc/eeprom/sunxi_sid.c 17 */ 18 19 #include <linux/device.h> 20 #include <linux/clk.h> 21 #include <linux/completion.h> 22 #include <linux/dmaengine.h> 23 #include <linux/dma-mapping.h> 24 #include <linux/err.h> 25 #include <linux/io.h> 26 #include <linux/kernel.h> 27 #include <linux/kobject.h> 28 #include <linux/of_device.h> 29 #include <linux/platform_device.h> 30 #include <linux/random.h> 31 32 #include <soc/tegra/fuse.h> 33 34 #include "fuse.h" 35 36 #define FUSE_BEGIN 0x100 37 #define FUSE_UID_LOW 0x08 38 #define FUSE_UID_HIGH 0x0c 39 40 static u32 tegra20_fuse_read_early(struct tegra_fuse *fuse, unsigned int offset) 41 { 42 return readl_relaxed(fuse->base + FUSE_BEGIN + offset); 43 } 44 45 static void apb_dma_complete(void *args) 46 { 47 struct tegra_fuse *fuse = args; 48 49 complete(&fuse->apbdma.wait); 50 } 51 52 static u32 tegra20_fuse_read(struct tegra_fuse *fuse, unsigned int offset) 53 { 54 unsigned long flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK; 55 struct dma_async_tx_descriptor *dma_desc; 56 unsigned long time_left; 57 u32 value = 0; 58 int err; 59 60 mutex_lock(&fuse->apbdma.lock); 61 62 fuse->apbdma.config.src_addr = fuse->apbdma.phys + FUSE_BEGIN + offset; 63 64 err = dmaengine_slave_config(fuse->apbdma.chan, &fuse->apbdma.config); 65 if (err) 66 goto out; 67 68 dma_desc = dmaengine_prep_slave_single(fuse->apbdma.chan, 69 fuse->apbdma.phys, 70 sizeof(u32), DMA_DEV_TO_MEM, 71 flags); 72 if (!dma_desc) 73 goto out; 74 75 dma_desc->callback = apb_dma_complete; 76 dma_desc->callback_param = fuse; 77 78 reinit_completion(&fuse->apbdma.wait); 79 80 clk_prepare_enable(fuse->clk); 81 82 dmaengine_submit(dma_desc); 83 dma_async_issue_pending(fuse->apbdma.chan); 84 time_left = wait_for_completion_timeout(&fuse->apbdma.wait, 85 msecs_to_jiffies(50)); 86 87 if (WARN(time_left == 0, "apb read dma timed out")) 88 dmaengine_terminate_all(fuse->apbdma.chan); 89 else 90 value = *fuse->apbdma.virt; 91 92 clk_disable_unprepare(fuse->clk); 93 94 out: 95 mutex_unlock(&fuse->apbdma.lock); 96 return value; 97 } 98 99 static int tegra20_fuse_probe(struct tegra_fuse *fuse) 100 { 101 dma_cap_mask_t mask; 102 103 dma_cap_zero(mask); 104 dma_cap_set(DMA_SLAVE, mask); 105 106 fuse->apbdma.chan = dma_request_channel(mask, NULL, NULL); 107 if (!fuse->apbdma.chan) 108 return -EPROBE_DEFER; 109 110 fuse->apbdma.virt = dma_alloc_coherent(fuse->dev, sizeof(u32), 111 &fuse->apbdma.phys, 112 GFP_KERNEL); 113 if (!fuse->apbdma.virt) { 114 dma_release_channel(fuse->apbdma.chan); 115 return -ENOMEM; 116 } 117 118 fuse->apbdma.config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 119 fuse->apbdma.config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 120 fuse->apbdma.config.src_maxburst = 1; 121 fuse->apbdma.config.dst_maxburst = 1; 122 123 init_completion(&fuse->apbdma.wait); 124 mutex_init(&fuse->apbdma.lock); 125 fuse->read = tegra20_fuse_read; 126 127 return 0; 128 } 129 130 static const struct tegra_fuse_info tegra20_fuse_info = { 131 .read = tegra20_fuse_read, 132 .size = 0x1f8, 133 .spare = 0x100, 134 }; 135 136 /* Early boot code. This code is called before the devices are created */ 137 138 static void __init tegra20_fuse_add_randomness(void) 139 { 140 u32 randomness[7]; 141 142 randomness[0] = tegra_sku_info.sku_id; 143 randomness[1] = tegra_read_straps(); 144 randomness[2] = tegra_read_chipid(); 145 randomness[3] = tegra_sku_info.cpu_process_id << 16; 146 randomness[3] |= tegra_sku_info.soc_process_id; 147 randomness[4] = tegra_sku_info.cpu_speedo_id << 16; 148 randomness[4] |= tegra_sku_info.soc_speedo_id; 149 randomness[5] = tegra_fuse_read_early(FUSE_UID_LOW); 150 randomness[6] = tegra_fuse_read_early(FUSE_UID_HIGH); 151 152 add_device_randomness(randomness, sizeof(randomness)); 153 } 154 155 static void __init tegra20_fuse_init(struct tegra_fuse *fuse) 156 { 157 fuse->read_early = tegra20_fuse_read_early; 158 159 tegra_init_revision(); 160 fuse->soc->speedo_init(&tegra_sku_info); 161 tegra20_fuse_add_randomness(); 162 } 163 164 const struct tegra_fuse_soc tegra20_fuse_soc = { 165 .init = tegra20_fuse_init, 166 .speedo_init = tegra20_init_speedo_data, 167 .probe = tegra20_fuse_probe, 168 .info = &tegra20_fuse_info, 169 }; 170