0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/device.h>
0009 #include <linux/clk.h>
0010 #include <linux/completion.h>
0011 #include <linux/dmaengine.h>
0012 #include <linux/dma-mapping.h>
0013 #include <linux/err.h>
0014 #include <linux/io.h>
0015 #include <linux/kernel.h>
0016 #include <linux/kobject.h>
0017 #include <linux/of_device.h>
0018 #include <linux/platform_device.h>
0019 #include <linux/pm_runtime.h>
0020 #include <linux/random.h>
0021
0022 #include <soc/tegra/fuse.h>
0023
0024 #include "fuse.h"
0025
0026 #define FUSE_BEGIN 0x100
0027 #define FUSE_UID_LOW 0x08
0028 #define FUSE_UID_HIGH 0x0c
0029
0030 static u32 tegra20_fuse_read_early(struct tegra_fuse *fuse, unsigned int offset)
0031 {
0032 return readl_relaxed(fuse->base + FUSE_BEGIN + offset);
0033 }
0034
0035 static void apb_dma_complete(void *args)
0036 {
0037 struct tegra_fuse *fuse = args;
0038
0039 complete(&fuse->apbdma.wait);
0040 }
0041
0042 static u32 tegra20_fuse_read(struct tegra_fuse *fuse, unsigned int offset)
0043 {
0044 unsigned long flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
0045 struct dma_async_tx_descriptor *dma_desc;
0046 unsigned long time_left;
0047 u32 value = 0;
0048 int err;
0049
0050 err = pm_runtime_resume_and_get(fuse->dev);
0051 if (err)
0052 return err;
0053
0054 mutex_lock(&fuse->apbdma.lock);
0055
0056 fuse->apbdma.config.src_addr = fuse->phys + FUSE_BEGIN + offset;
0057
0058 err = dmaengine_slave_config(fuse->apbdma.chan, &fuse->apbdma.config);
0059 if (err)
0060 goto out;
0061
0062 dma_desc = dmaengine_prep_slave_single(fuse->apbdma.chan,
0063 fuse->apbdma.phys,
0064 sizeof(u32), DMA_DEV_TO_MEM,
0065 flags);
0066 if (!dma_desc)
0067 goto out;
0068
0069 dma_desc->callback = apb_dma_complete;
0070 dma_desc->callback_param = fuse;
0071
0072 reinit_completion(&fuse->apbdma.wait);
0073
0074 dmaengine_submit(dma_desc);
0075 dma_async_issue_pending(fuse->apbdma.chan);
0076 time_left = wait_for_completion_timeout(&fuse->apbdma.wait,
0077 msecs_to_jiffies(50));
0078
0079 if (WARN(time_left == 0, "apb read dma timed out"))
0080 dmaengine_terminate_all(fuse->apbdma.chan);
0081 else
0082 value = *fuse->apbdma.virt;
0083
0084 out:
0085 mutex_unlock(&fuse->apbdma.lock);
0086 pm_runtime_put(fuse->dev);
0087 return value;
0088 }
0089
0090 static bool dma_filter(struct dma_chan *chan, void *filter_param)
0091 {
0092 struct device_node *np = chan->device->dev->of_node;
0093
0094 return of_device_is_compatible(np, "nvidia,tegra20-apbdma");
0095 }
0096
0097 static void tegra20_fuse_release_channel(void *data)
0098 {
0099 struct tegra_fuse *fuse = data;
0100
0101 dma_release_channel(fuse->apbdma.chan);
0102 fuse->apbdma.chan = NULL;
0103 }
0104
0105 static void tegra20_fuse_free_coherent(void *data)
0106 {
0107 struct tegra_fuse *fuse = data;
0108
0109 dma_free_coherent(fuse->dev, sizeof(u32), fuse->apbdma.virt,
0110 fuse->apbdma.phys);
0111 fuse->apbdma.virt = NULL;
0112 fuse->apbdma.phys = 0x0;
0113 }
0114
0115 static int tegra20_fuse_probe(struct tegra_fuse *fuse)
0116 {
0117 dma_cap_mask_t mask;
0118 int err;
0119
0120 dma_cap_zero(mask);
0121 dma_cap_set(DMA_SLAVE, mask);
0122
0123 fuse->apbdma.chan = dma_request_channel(mask, dma_filter, NULL);
0124 if (!fuse->apbdma.chan)
0125 return -EPROBE_DEFER;
0126
0127 err = devm_add_action_or_reset(fuse->dev, tegra20_fuse_release_channel,
0128 fuse);
0129 if (err)
0130 return err;
0131
0132 fuse->apbdma.virt = dma_alloc_coherent(fuse->dev, sizeof(u32),
0133 &fuse->apbdma.phys,
0134 GFP_KERNEL);
0135 if (!fuse->apbdma.virt)
0136 return -ENOMEM;
0137
0138 err = devm_add_action_or_reset(fuse->dev, tegra20_fuse_free_coherent,
0139 fuse);
0140 if (err)
0141 return err;
0142
0143 fuse->apbdma.config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
0144 fuse->apbdma.config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
0145 fuse->apbdma.config.src_maxburst = 1;
0146 fuse->apbdma.config.dst_maxburst = 1;
0147 fuse->apbdma.config.direction = DMA_DEV_TO_MEM;
0148 fuse->apbdma.config.device_fc = false;
0149
0150 init_completion(&fuse->apbdma.wait);
0151 mutex_init(&fuse->apbdma.lock);
0152 fuse->read = tegra20_fuse_read;
0153
0154 return 0;
0155 }
0156
0157 static const struct tegra_fuse_info tegra20_fuse_info = {
0158 .read = tegra20_fuse_read,
0159 .size = 0x1f8,
0160 .spare = 0x100,
0161 };
0162
0163
0164
0165 static void __init tegra20_fuse_add_randomness(void)
0166 {
0167 u32 randomness[7];
0168
0169 randomness[0] = tegra_sku_info.sku_id;
0170 randomness[1] = tegra_read_straps();
0171 randomness[2] = tegra_read_chipid();
0172 randomness[3] = tegra_sku_info.cpu_process_id << 16;
0173 randomness[3] |= tegra_sku_info.soc_process_id;
0174 randomness[4] = tegra_sku_info.cpu_speedo_id << 16;
0175 randomness[4] |= tegra_sku_info.soc_speedo_id;
0176 randomness[5] = tegra_fuse_read_early(FUSE_UID_LOW);
0177 randomness[6] = tegra_fuse_read_early(FUSE_UID_HIGH);
0178
0179 add_device_randomness(randomness, sizeof(randomness));
0180 }
0181
0182 static void __init tegra20_fuse_init(struct tegra_fuse *fuse)
0183 {
0184 fuse->read_early = tegra20_fuse_read_early;
0185
0186 tegra_init_revision();
0187 fuse->soc->speedo_init(&tegra_sku_info);
0188 tegra20_fuse_add_randomness();
0189 }
0190
0191 const struct tegra_fuse_soc tegra20_fuse_soc = {
0192 .init = tegra20_fuse_init,
0193 .speedo_init = tegra20_init_speedo_data,
0194 .probe = tegra20_fuse_probe,
0195 .info = &tegra20_fuse_info,
0196 .soc_attr_group = &tegra_soc_attr_group,
0197 .clk_suspend_on = false,
0198 };