Skip to content

Commit 93b4e49

Browse files
Ravi Kumar Bokkagregkh
authored andcommitted
nvmem: qfprom: Add fuse blowing support
This patch adds support for blowing fuses to the qfprom driver if the required properties are defined in the device tree. [Srini: Fixed merge conflict with AUTO ID] Signed-off-by: Ravi Kumar Bokka <[email protected]> Signed-off-by: Douglas Anderson <[email protected]> Signed-off-by: Srinivas Kandagatla <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent a37a15f commit 93b4e49

File tree

1 file changed

+304
-12
lines changed

1 file changed

+304
-12
lines changed

drivers/nvmem/qfprom.c

Lines changed: 304 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,58 +3,350 @@
33
* Copyright (C) 2015 Srinivas Kandagatla <[email protected]>
44
*/
55

6+
#include <linux/clk.h>
67
#include <linux/device.h>
8+
#include <linux/io.h>
9+
#include <linux/iopoll.h>
10+
#include <linux/kernel.h>
711
#include <linux/module.h>
812
#include <linux/mod_devicetable.h>
9-
#include <linux/io.h>
1013
#include <linux/nvmem-provider.h>
1114
#include <linux/platform_device.h>
15+
#include <linux/regulator/consumer.h>
16+
17+
/* Blow timer clock frequency in Mhz */
18+
#define QFPROM_BLOW_TIMER_OFFSET 0x03c
19+
20+
/* Amount of time required to hold charge to blow fuse in micro-seconds */
21+
#define QFPROM_FUSE_BLOW_POLL_US 100
22+
#define QFPROM_FUSE_BLOW_TIMEOUT_US 1000
23+
24+
#define QFPROM_BLOW_STATUS_OFFSET 0x048
25+
#define QFPROM_BLOW_STATUS_BUSY 0x1
26+
#define QFPROM_BLOW_STATUS_READY 0x0
27+
28+
#define QFPROM_ACCEL_OFFSET 0x044
29+
30+
#define QFPROM_VERSION_OFFSET 0x0
31+
#define QFPROM_MAJOR_VERSION_SHIFT 28
32+
#define QFPROM_MAJOR_VERSION_MASK GENMASK(31, QFPROM_MAJOR_VERSION_SHIFT)
33+
#define QFPROM_MINOR_VERSION_SHIFT 16
34+
#define QFPROM_MINOR_VERSION_MASK GENMASK(27, QFPROM_MINOR_VERSION_SHIFT)
35+
36+
static bool read_raw_data;
37+
module_param(read_raw_data, bool, 0644);
38+
MODULE_PARM_DESC(read_raw_data, "Read raw instead of corrected data");
1239

40+
/**
41+
* struct qfprom_soc_data - config that varies from SoC to SoC.
42+
*
43+
* @accel_value: Should contain qfprom accel value.
44+
* @qfprom_blow_timer_value: The timer value of qfprom when doing efuse blow.
45+
* @qfprom_blow_set_freq: The frequency required to set when we start the
46+
* fuse blowing.
47+
*/
48+
struct qfprom_soc_data {
49+
u32 accel_value;
50+
u32 qfprom_blow_timer_value;
51+
u32 qfprom_blow_set_freq;
52+
};
53+
54+
/**
55+
* struct qfprom_priv - structure holding qfprom attributes
56+
*
57+
* @qfpraw: iomapped memory space for qfprom-efuse raw address space.
58+
* @qfpconf: iomapped memory space for qfprom-efuse configuration address
59+
* space.
60+
* @qfpcorrected: iomapped memory space for qfprom corrected address space.
61+
* @qfpsecurity: iomapped memory space for qfprom security control space.
62+
* @dev: qfprom device structure.
63+
* @secclk: Clock supply.
64+
* @vcc: Regulator supply.
65+
* @soc_data: Data that for things that varies from SoC to SoC.
66+
*/
1367
struct qfprom_priv {
14-
void __iomem *base;
68+
void __iomem *qfpraw;
69+
void __iomem *qfpconf;
70+
void __iomem *qfpcorrected;
71+
void __iomem *qfpsecurity;
72+
struct device *dev;
73+
struct clk *secclk;
74+
struct regulator *vcc;
75+
const struct qfprom_soc_data *soc_data;
76+
};
77+
78+
/**
79+
* struct qfprom_touched_values - saved values to restore after blowing
80+
*
81+
* @clk_rate: The rate the clock was at before blowing.
82+
* @accel_val: The value of the accel reg before blowing.
83+
* @timer_val: The value of the timer before blowing.
84+
*/
85+
struct qfprom_touched_values {
86+
unsigned long clk_rate;
87+
u32 accel_val;
88+
u32 timer_val;
1589
};
1690

91+
/**
92+
* qfprom_disable_fuse_blowing() - Undo enabling of fuse blowing.
93+
* @priv: Our driver data.
94+
* @old: The data that was stashed from before fuse blowing.
95+
*
96+
* Resets the value of the blow timer, accel register and the clock
97+
* and voltage settings.
98+
*
99+
* Prints messages if there are errors but doesn't return an error code
100+
* since there's not much we can do upon failure.
101+
*/
102+
static void qfprom_disable_fuse_blowing(const struct qfprom_priv *priv,
103+
const struct qfprom_touched_values *old)
104+
{
105+
int ret;
106+
107+
ret = regulator_disable(priv->vcc);
108+
if (ret)
109+
dev_warn(priv->dev, "Failed to disable regulator (ignoring)\n");
110+
111+
ret = clk_set_rate(priv->secclk, old->clk_rate);
112+
if (ret)
113+
dev_warn(priv->dev,
114+
"Failed to set clock rate for disable (ignoring)\n");
115+
116+
clk_disable_unprepare(priv->secclk);
117+
118+
writel(old->timer_val, priv->qfpconf + QFPROM_BLOW_TIMER_OFFSET);
119+
writel(old->accel_val, priv->qfpconf + QFPROM_ACCEL_OFFSET);
120+
}
121+
122+
/**
123+
* qfprom_enable_fuse_blowing() - Enable fuse blowing.
124+
* @priv: Our driver data.
125+
* @old: We'll stash stuff here to use when disabling.
126+
*
127+
* Sets the value of the blow timer, accel register and the clock
128+
* and voltage settings.
129+
*
130+
* Prints messages if there are errors so caller doesn't need to.
131+
*
132+
* Return: 0 or -err.
133+
*/
134+
static int qfprom_enable_fuse_blowing(const struct qfprom_priv *priv,
135+
struct qfprom_touched_values *old)
136+
{
137+
int ret;
138+
139+
ret = clk_prepare_enable(priv->secclk);
140+
if (ret) {
141+
dev_err(priv->dev, "Failed to enable clock\n");
142+
return ret;
143+
}
144+
145+
old->clk_rate = clk_get_rate(priv->secclk);
146+
ret = clk_set_rate(priv->secclk, priv->soc_data->qfprom_blow_set_freq);
147+
if (ret) {
148+
dev_err(priv->dev, "Failed to set clock rate for enable\n");
149+
goto err_clk_prepared;
150+
}
151+
152+
ret = regulator_enable(priv->vcc);
153+
if (ret) {
154+
dev_err(priv->dev, "Failed to enable regulator\n");
155+
goto err_clk_rate_set;
156+
}
157+
158+
old->timer_val = readl(priv->qfpconf + QFPROM_BLOW_TIMER_OFFSET);
159+
old->accel_val = readl(priv->qfpconf + QFPROM_ACCEL_OFFSET);
160+
writel(priv->soc_data->qfprom_blow_timer_value,
161+
priv->qfpconf + QFPROM_BLOW_TIMER_OFFSET);
162+
writel(priv->soc_data->accel_value,
163+
priv->qfpconf + QFPROM_ACCEL_OFFSET);
164+
165+
return 0;
166+
167+
err_clk_rate_set:
168+
clk_set_rate(priv->secclk, old->clk_rate);
169+
err_clk_prepared:
170+
clk_disable_unprepare(priv->secclk);
171+
return ret;
172+
}
173+
174+
/**
175+
* qfprom_efuse_reg_write() - Write to fuses.
176+
* @context: Our driver data.
177+
* @reg: The offset to write at.
178+
* @_val: Pointer to data to write.
179+
* @bytes: The number of bytes to write.
180+
*
181+
* Writes to fuses. WARNING: THIS IS PERMANENT.
182+
*
183+
* Return: 0 or -err.
184+
*/
185+
static int qfprom_reg_write(void *context, unsigned int reg, void *_val,
186+
size_t bytes)
187+
{
188+
struct qfprom_priv *priv = context;
189+
struct qfprom_touched_values old;
190+
int words = bytes / 4;
191+
u32 *value = _val;
192+
u32 blow_status;
193+
int ret;
194+
int i;
195+
196+
dev_dbg(priv->dev,
197+
"Writing to raw qfprom region : %#010x of size: %zu\n",
198+
reg, bytes);
199+
200+
/*
201+
* The hardware only allows us to write word at a time, but we can
202+
* read byte at a time. Until the nvmem framework allows a separate
203+
* word_size and stride for reading vs. writing, we'll enforce here.
204+
*/
205+
if (bytes % 4) {
206+
dev_err(priv->dev,
207+
"%zu is not an integral number of words\n", bytes);
208+
return -EINVAL;
209+
}
210+
if (reg % 4) {
211+
dev_err(priv->dev,
212+
"Invalid offset: %#x. Must be word aligned\n", reg);
213+
return -EINVAL;
214+
}
215+
216+
ret = qfprom_enable_fuse_blowing(priv, &old);
217+
if (ret)
218+
return ret;
219+
220+
ret = readl_relaxed_poll_timeout(
221+
priv->qfpconf + QFPROM_BLOW_STATUS_OFFSET,
222+
blow_status, blow_status == QFPROM_BLOW_STATUS_READY,
223+
QFPROM_FUSE_BLOW_POLL_US, QFPROM_FUSE_BLOW_TIMEOUT_US);
224+
225+
if (ret) {
226+
dev_err(priv->dev,
227+
"Timeout waiting for initial ready; aborting.\n");
228+
goto exit_enabled_fuse_blowing;
229+
}
230+
231+
for (i = 0; i < words; i++)
232+
writel(value[i], priv->qfpraw + reg + (i * 4));
233+
234+
ret = readl_relaxed_poll_timeout(
235+
priv->qfpconf + QFPROM_BLOW_STATUS_OFFSET,
236+
blow_status, blow_status == QFPROM_BLOW_STATUS_READY,
237+
QFPROM_FUSE_BLOW_POLL_US, QFPROM_FUSE_BLOW_TIMEOUT_US);
238+
239+
/* Give an error, but not much we can do in this case */
240+
if (ret)
241+
dev_err(priv->dev, "Timeout waiting for finish.\n");
242+
243+
exit_enabled_fuse_blowing:
244+
qfprom_disable_fuse_blowing(priv, &old);
245+
246+
return ret;
247+
}
248+
17249
static int qfprom_reg_read(void *context,
18250
unsigned int reg, void *_val, size_t bytes)
19251
{
20252
struct qfprom_priv *priv = context;
21253
u8 *val = _val;
22254
int i = 0, words = bytes;
255+
void __iomem *base = priv->qfpcorrected;
256+
257+
if (read_raw_data && priv->qfpraw)
258+
base = priv->qfpraw;
23259

24260
while (words--)
25-
*val++ = readb(priv->base + reg + i++);
261+
*val++ = readb(base + reg + i++);
26262

27263
return 0;
28264
}
29265

30-
static struct nvmem_config econfig = {
31-
.name = "qfprom",
32-
.stride = 1,
33-
.word_size = 1,
34-
.id = NVMEM_DEVID_AUTO,
35-
.reg_read = qfprom_reg_read,
266+
static const struct qfprom_soc_data qfprom_7_8_data = {
267+
.accel_value = 0xD10,
268+
.qfprom_blow_timer_value = 25,
269+
.qfprom_blow_set_freq = 4800000,
36270
};
37271

38272
static int qfprom_probe(struct platform_device *pdev)
39273
{
274+
struct nvmem_config econfig = {
275+
.name = "qfprom",
276+
.stride = 1,
277+
.word_size = 1,
278+
.id = NVMEM_DEVID_AUTO,
279+
.reg_read = qfprom_reg_read,
280+
};
40281
struct device *dev = &pdev->dev;
41282
struct resource *res;
42283
struct nvmem_device *nvmem;
43284
struct qfprom_priv *priv;
285+
int ret;
44286

45287
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
46288
if (!priv)
47289
return -ENOMEM;
48290

291+
/* The corrected section is always provided */
49292
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
50-
priv->base = devm_ioremap_resource(dev, res);
51-
if (IS_ERR(priv->base))
52-
return PTR_ERR(priv->base);
293+
priv->qfpcorrected = devm_ioremap_resource(dev, res);
294+
if (IS_ERR(priv->qfpcorrected))
295+
return PTR_ERR(priv->qfpcorrected);
53296

54297
econfig.size = resource_size(res);
55298
econfig.dev = dev;
56299
econfig.priv = priv;
57300

301+
priv->dev = dev;
302+
303+
/*
304+
* If more than one region is provided then the OS has the ability
305+
* to write.
306+
*/
307+
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
308+
if (res) {
309+
u32 version;
310+
int major_version, minor_version;
311+
312+
priv->qfpraw = devm_ioremap_resource(dev, res);
313+
if (IS_ERR(priv->qfpraw))
314+
return PTR_ERR(priv->qfpraw);
315+
res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
316+
priv->qfpconf = devm_ioremap_resource(dev, res);
317+
if (IS_ERR(priv->qfpconf))
318+
return PTR_ERR(priv->qfpconf);
319+
res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
320+
priv->qfpsecurity = devm_ioremap_resource(dev, res);
321+
if (IS_ERR(priv->qfpsecurity))
322+
return PTR_ERR(priv->qfpsecurity);
323+
324+
version = readl(priv->qfpsecurity + QFPROM_VERSION_OFFSET);
325+
major_version = (version & QFPROM_MAJOR_VERSION_MASK) >>
326+
QFPROM_MAJOR_VERSION_SHIFT;
327+
minor_version = (version & QFPROM_MINOR_VERSION_MASK) >>
328+
QFPROM_MINOR_VERSION_SHIFT;
329+
330+
if (major_version == 7 && minor_version == 8)
331+
priv->soc_data = &qfprom_7_8_data;
332+
333+
priv->vcc = devm_regulator_get(&pdev->dev, "vcc");
334+
if (IS_ERR(priv->vcc))
335+
return PTR_ERR(priv->vcc);
336+
337+
priv->secclk = devm_clk_get(dev, "core");
338+
if (IS_ERR(priv->secclk)) {
339+
ret = PTR_ERR(priv->secclk);
340+
if (ret != -EPROBE_DEFER)
341+
dev_err(dev, "Error getting clock: %d\n", ret);
342+
return ret;
343+
}
344+
345+
/* Only enable writing if we have SoC data. */
346+
if (priv->soc_data)
347+
econfig.reg_write = qfprom_reg_write;
348+
}
349+
58350
nvmem = devm_nvmem_register(dev, &econfig);
59351

60352
return PTR_ERR_OR_ZERO(nvmem);

0 commit comments

Comments
 (0)