aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/char/Kconfig28
-rw-r--r--drivers/char/Makefile1
-rw-r--r--drivers/char/bfin-otp.c189
3 files changed, 218 insertions, 0 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index a87b89db08e9..2906ee7bd298 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -481,6 +481,34 @@ config BRIQ_PANEL
481 481
482 It's safe to say N here. 482 It's safe to say N here.
483 483
484config BFIN_OTP
485 tristate "Blackfin On-Chip OTP Memory Support"
486 depends on BLACKFIN && (BF52x || BF54x)
487 default y
488 help
489 If you say Y here, you will get support for a character device
490 interface into the One Time Programmable memory pages that are
491 stored on the Blackfin processor. This will not get you access
492 to the secure memory pages however. You will need to write your
493 own secure code and reader for that.
494
495 To compile this driver as a module, choose M here: the module
496 will be called bfin-otp.
497
498 If unsure, it is safe to say Y.
499
500config BFIN_OTP_WRITE_ENABLE
501 bool "Enable writing support of OTP pages"
502 depends on BFIN_OTP
503 default n
504 help
505 If you say Y here, you will enable support for writing of the
506 OTP pages. This is dangerous by nature as you can only program
507 the pages once, so only enable this option when you actually
508 need it so as to not inadvertently clobber data.
509
510 If unsure, say N.
511
484config PRINTER 512config PRINTER
485 tristate "Parallel printer support" 513 tristate "Parallel printer support"
486 depends on PARPORT 514 depends on PARPORT
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 5407b7615614..4c1c584e9eb6 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -59,6 +59,7 @@ obj-$(CONFIG_VIOTAPE) += viotape.o
59obj-$(CONFIG_HVCS) += hvcs.o 59obj-$(CONFIG_HVCS) += hvcs.o
60obj-$(CONFIG_SGI_MBCS) += mbcs.o 60obj-$(CONFIG_SGI_MBCS) += mbcs.o
61obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o 61obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o
62obj-$(CONFIG_BFIN_OTP) += bfin-otp.o
62 63
63obj-$(CONFIG_PRINTER) += lp.o 64obj-$(CONFIG_PRINTER) += lp.o
64obj-$(CONFIG_TIPAR) += tipar.o 65obj-$(CONFIG_TIPAR) += tipar.o
diff --git a/drivers/char/bfin-otp.c b/drivers/char/bfin-otp.c
new file mode 100644
index 000000000000..0a01329451e4
--- /dev/null
+++ b/drivers/char/bfin-otp.c
@@ -0,0 +1,189 @@
1/*
2 * Blackfin On-Chip OTP Memory Interface
3 * Supports BF52x/BF54x
4 *
5 * Copyright 2007-2008 Analog Devices Inc.
6 *
7 * Enter bugs at http://blackfin.uclinux.org/
8 *
9 * Licensed under the GPL-2 or later.
10 */
11
12#include <linux/device.h>
13#include <linux/errno.h>
14#include <linux/fs.h>
15#include <linux/init.h>
16#include <linux/miscdevice.h>
17#include <linux/module.h>
18#include <linux/mutex.h>
19#include <linux/types.h>
20
21#include <asm/blackfin.h>
22#include <asm/uaccess.h>
23
24#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
25#define stampit() stamp("here i am")
26#define pr_init(fmt, args...) ({ static const __initconst char __fmt[] = fmt; printk(__fmt, ## args); })
27
28#define DRIVER_NAME "bfin-otp"
29#define PFX DRIVER_NAME ": "
30
31static DEFINE_MUTEX(bfin_otp_lock);
32
33/* OTP Boot ROM functions */
34#define _BOOTROM_OTP_COMMAND 0xEF000018
35#define _BOOTROM_OTP_READ 0xEF00001A
36#define _BOOTROM_OTP_WRITE 0xEF00001C
37
38static u32 (* const otp_command)(u32 command, u32 value) = (void *)_BOOTROM_OTP_COMMAND;
39static u32 (* const otp_read)(u32 page, u32 flags, u64 *page_content) = (void *)_BOOTROM_OTP_READ;
40static u32 (* const otp_write)(u32 page, u32 flags, u64 *page_content) = (void *)_BOOTROM_OTP_WRITE;
41
42/* otp_command(): defines for "command" */
43#define OTP_INIT 0x00000001
44#define OTP_CLOSE 0x00000002
45
46/* otp_{read,write}(): defines for "flags" */
47#define OTP_LOWER_HALF 0x00000000 /* select upper/lower 64-bit half (bit 0) */
48#define OTP_UPPER_HALF 0x00000001
49#define OTP_NO_ECC 0x00000010 /* do not use ECC */
50#define OTP_LOCK 0x00000020 /* sets page protection bit for page */
51#define OTP_ACCESS_READ 0x00001000
52#define OTP_ACCESS_READWRITE 0x00002000
53
54/* Return values for all functions */
55#define OTP_SUCCESS 0x00000000
56#define OTP_MASTER_ERROR 0x001
57#define OTP_WRITE_ERROR 0x003
58#define OTP_READ_ERROR 0x005
59#define OTP_ACC_VIO_ERROR 0x009
60#define OTP_DATA_MULT_ERROR 0x011
61#define OTP_ECC_MULT_ERROR 0x021
62#define OTP_PREV_WR_ERROR 0x041
63#define OTP_DATA_SB_WARN 0x100
64#define OTP_ECC_SB_WARN 0x200
65
66/**
67 * bfin_otp_read - Read OTP pages
68 *
69 * All reads must be in half page chunks (half page == 64 bits).
70 */
71static ssize_t bfin_otp_read(struct file *file, char __user *buff, size_t count, loff_t *pos)
72{
73 ssize_t bytes_done;
74 u32 page, flags, ret;
75 u64 content;
76
77 stampit();
78
79 if (count % sizeof(u64))
80 return -EMSGSIZE;
81
82 if (mutex_lock_interruptible(&bfin_otp_lock))
83 return -ERESTARTSYS;
84
85 bytes_done = 0;
86 page = *pos / (sizeof(u64) * 2);
87 while (bytes_done < count) {
88 flags = (*pos % (sizeof(u64) * 2) ? OTP_UPPER_HALF : OTP_LOWER_HALF);
89 stamp("processing page %i (%s)", page, (flags == OTP_UPPER_HALF ? "upper" : "lower"));
90 ret = otp_read(page, flags, &content);
91 if (ret & OTP_MASTER_ERROR) {
92 bytes_done = -EIO;
93 break;
94 }
95 if (copy_to_user(buff + bytes_done, &content, sizeof(content))) {
96 bytes_done = -EFAULT;
97 break;
98 }
99 if (flags == OTP_UPPER_HALF)
100 ++page;
101 bytes_done += sizeof(content);
102 *pos += sizeof(content);
103 }
104
105 mutex_unlock(&bfin_otp_lock);
106
107 return bytes_done;
108}
109
110#ifdef CONFIG_BFIN_OTP_WRITE_ENABLE
111/**
112 * bfin_otp_write - Write OTP pages
113 *
114 * All writes must be in half page chunks (half page == 64 bits).
115 */
116static ssize_t bfin_otp_write(struct file *filp, const char __user *buff, size_t count, loff_t *pos)
117{
118 stampit();
119
120 if (count % sizeof(u64))
121 return -EMSGSIZE;
122
123 if (mutex_lock_interruptible(&bfin_otp_lock))
124 return -ERESTARTSYS;
125
126 /* need otp_init() documentation before this can be implemented */
127
128 mutex_unlock(&bfin_otp_lock);
129
130 return -EINVAL;
131}
132#else
133# define bfin_otp_write NULL
134#endif
135
136static struct file_operations bfin_otp_fops = {
137 .owner = THIS_MODULE,
138 .read = bfin_otp_read,
139 .write = bfin_otp_write,
140};
141
142static struct miscdevice bfin_otp_misc_device = {
143 .minor = MISC_DYNAMIC_MINOR,
144 .name = DRIVER_NAME,
145 .fops = &bfin_otp_fops,
146};
147
148/**
149 * bfin_otp_init - Initialize module
150 *
151 * Registers the device and notifier handler. Actual device
152 * initialization is handled by bfin_otp_open().
153 */
154static int __init bfin_otp_init(void)
155{
156 int ret;
157
158 stampit();
159
160 ret = misc_register(&bfin_otp_misc_device);
161 if (ret) {
162 pr_init(KERN_ERR PFX "unable to register a misc device\n");
163 return ret;
164 }
165
166 pr_init(KERN_INFO PFX "initialized\n");
167
168 return 0;
169}
170
171/**
172 * bfin_otp_exit - Deinitialize module
173 *
174 * Unregisters the device and notifier handler. Actual device
175 * deinitialization is handled by bfin_otp_close().
176 */
177static void __exit bfin_otp_exit(void)
178{
179 stampit();
180
181 misc_deregister(&bfin_otp_misc_device);
182}
183
184module_init(bfin_otp_init);
185module_exit(bfin_otp_exit);
186
187MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>");
188MODULE_DESCRIPTION("Blackfin OTP Memory Interface");
189MODULE_LICENSE("GPL");