Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 165699
b: refs/heads/master
c: 156dd63
h: refs/heads/master
i:
  165697: d556ffd
  165695: 97c7950
v: v3
  • Loading branch information
Mike Frysinger authored and Linus Torvalds committed Sep 24, 2009
1 parent 827e7f3 commit 01f4cc9
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 45 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: fbd8ae106850b6a0215c2776e70a75a1b93cafc2
refs/heads/master: 156dd635e26ab2b356be139ec4b5651afd3805e2
173 changes: 129 additions & 44 deletions trunk/drivers/char/bfin-otp.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
/*
* Blackfin On-Chip OTP Memory Interface
* Supports BF52x/BF54x
*
* Copyright 2007-2008 Analog Devices Inc.
* Copyright 2007-2009 Analog Devices Inc.
*
* Enter bugs at http://blackfin.uclinux.org/
*
Expand All @@ -17,8 +16,10 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/types.h>
#include <mtd/mtd-abi.h>

#include <asm/blackfin.h>
#include <asm/bfrom.h>
#include <asm/uaccess.h>

#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
Expand All @@ -30,39 +31,6 @@

static DEFINE_MUTEX(bfin_otp_lock);

/* OTP Boot ROM functions */
#define _BOOTROM_OTP_COMMAND 0xEF000018
#define _BOOTROM_OTP_READ 0xEF00001A
#define _BOOTROM_OTP_WRITE 0xEF00001C

static u32 (* const otp_command)(u32 command, u32 value) = (void *)_BOOTROM_OTP_COMMAND;
static u32 (* const otp_read)(u32 page, u32 flags, u64 *page_content) = (void *)_BOOTROM_OTP_READ;
static u32 (* const otp_write)(u32 page, u32 flags, u64 *page_content) = (void *)_BOOTROM_OTP_WRITE;

/* otp_command(): defines for "command" */
#define OTP_INIT 0x00000001
#define OTP_CLOSE 0x00000002

/* otp_{read,write}(): defines for "flags" */
#define OTP_LOWER_HALF 0x00000000 /* select upper/lower 64-bit half (bit 0) */
#define OTP_UPPER_HALF 0x00000001
#define OTP_NO_ECC 0x00000010 /* do not use ECC */
#define OTP_LOCK 0x00000020 /* sets page protection bit for page */
#define OTP_ACCESS_READ 0x00001000
#define OTP_ACCESS_READWRITE 0x00002000

/* Return values for all functions */
#define OTP_SUCCESS 0x00000000
#define OTP_MASTER_ERROR 0x001
#define OTP_WRITE_ERROR 0x003
#define OTP_READ_ERROR 0x005
#define OTP_ACC_VIO_ERROR 0x009
#define OTP_DATA_MULT_ERROR 0x011
#define OTP_ECC_MULT_ERROR 0x021
#define OTP_PREV_WR_ERROR 0x041
#define OTP_DATA_SB_WARN 0x100
#define OTP_ECC_SB_WARN 0x200

/**
* bfin_otp_read - Read OTP pages
*
Expand All @@ -86,17 +54,19 @@ static ssize_t bfin_otp_read(struct file *file, char __user *buff, size_t count,
page = *pos / (sizeof(u64) * 2);
while (bytes_done < count) {
flags = (*pos % (sizeof(u64) * 2) ? OTP_UPPER_HALF : OTP_LOWER_HALF);
stamp("processing page %i (%s)", page, (flags == OTP_UPPER_HALF ? "upper" : "lower"));
ret = otp_read(page, flags, &content);
stamp("processing page %i (0x%x:%s)", page, flags,
(flags & OTP_UPPER_HALF ? "upper" : "lower"));
ret = bfrom_OtpRead(page, flags, &content);
if (ret & OTP_MASTER_ERROR) {
stamp("error from otp: 0x%x", ret);
bytes_done = -EIO;
break;
}
if (copy_to_user(buff + bytes_done, &content, sizeof(content))) {
bytes_done = -EFAULT;
break;
}
if (flags == OTP_UPPER_HALF)
if (flags & OTP_UPPER_HALF)
++page;
bytes_done += sizeof(content);
*pos += sizeof(content);
Expand All @@ -108,35 +78,150 @@ static ssize_t bfin_otp_read(struct file *file, char __user *buff, size_t count,
}

#ifdef CONFIG_BFIN_OTP_WRITE_ENABLE
static bool allow_writes;

/**
* bfin_otp_init_timing - setup OTP timing parameters
*
* Required before doing any write operation. Algorithms from HRM.
*/
static u32 bfin_otp_init_timing(void)
{
u32 tp1, tp2, tp3, timing;

tp1 = get_sclk() / 1000000;
tp2 = (2 * get_sclk() / 10000000) << 8;
tp3 = (0x1401) << 15;
timing = tp1 | tp2 | tp3;
if (bfrom_OtpCommand(OTP_INIT, timing))
return 0;

return timing;
}

/**
* bfin_otp_deinit_timing - set timings to only allow reads
*
* Should be called after all writes are done.
*/
static void bfin_otp_deinit_timing(u32 timing)
{
/* mask bits [31:15] so that any attempts to write fail */
bfrom_OtpCommand(OTP_CLOSE, 0);
bfrom_OtpCommand(OTP_INIT, timing & ~(-1 << 15));
bfrom_OtpCommand(OTP_CLOSE, 0);
}

/**
* bfin_otp_write - Write OTP pages
* bfin_otp_write - write OTP pages
*
* All writes must be in half page chunks (half page == 64 bits).
*/
static ssize_t bfin_otp_write(struct file *filp, const char __user *buff, size_t count, loff_t *pos)
{
stampit();
ssize_t bytes_done;
u32 timing, page, base_flags, flags, ret;
u64 content;

if (!allow_writes)
return -EACCES;

if (count % sizeof(u64))
return -EMSGSIZE;

if (mutex_lock_interruptible(&bfin_otp_lock))
return -ERESTARTSYS;

/* need otp_init() documentation before this can be implemented */
stampit();

timing = bfin_otp_init_timing();
if (timing == 0) {
mutex_unlock(&bfin_otp_lock);
return -EIO;
}

base_flags = OTP_CHECK_FOR_PREV_WRITE;

bytes_done = 0;
page = *pos / (sizeof(u64) * 2);
while (bytes_done < count) {
flags = base_flags | (*pos % (sizeof(u64) * 2) ? OTP_UPPER_HALF : OTP_LOWER_HALF);
stamp("processing page %i (0x%x:%s) from %p", page, flags,
(flags & OTP_UPPER_HALF ? "upper" : "lower"), buff + bytes_done);
if (copy_from_user(&content, buff + bytes_done, sizeof(content))) {
bytes_done = -EFAULT;
break;
}
ret = bfrom_OtpWrite(page, flags, &content);
if (ret & OTP_MASTER_ERROR) {
stamp("error from otp: 0x%x", ret);
bytes_done = -EIO;
break;
}
if (flags & OTP_UPPER_HALF)
++page;
bytes_done += sizeof(content);
*pos += sizeof(content);
}

bfin_otp_deinit_timing(timing);

mutex_unlock(&bfin_otp_lock);

return bytes_done;
}

static long bfin_otp_ioctl(struct file *filp, unsigned cmd, unsigned long arg)
{
stampit();

switch (cmd) {
case OTPLOCK: {
u32 timing;
int ret = -EIO;

if (!allow_writes)
return -EACCES;

if (mutex_lock_interruptible(&bfin_otp_lock))
return -ERESTARTSYS;

timing = bfin_otp_init_timing();
if (timing) {
u32 otp_result = bfrom_OtpWrite(arg, OTP_LOCK, NULL);
stamp("locking page %lu resulted in 0x%x", arg, otp_result);
if (!(otp_result & OTP_MASTER_ERROR))
ret = 0;

bfin_otp_deinit_timing(timing);
}

mutex_unlock(&bfin_otp_lock);

return ret;
}

case MEMLOCK:
allow_writes = false;
return 0;

case MEMUNLOCK:
allow_writes = true;
return 0;
}

return -EINVAL;
}
#else
# define bfin_otp_write NULL
# define bfin_otp_ioctl NULL
#endif

static struct file_operations bfin_otp_fops = {
.owner = THIS_MODULE,
.read = bfin_otp_read,
.write = bfin_otp_write,
.owner = THIS_MODULE,
.unlocked_ioctl = bfin_otp_ioctl,
.read = bfin_otp_read,
.write = bfin_otp_write,
};

static struct miscdevice bfin_otp_misc_device = {
Expand Down

0 comments on commit 01f4cc9

Please sign in to comment.