From: Wolfram Sang <w.sang@pengutronix.de>
To: barebox@lists.infradead.org
Cc: Wolfram Sang <w.sang@pengutronix.de>
Subject: [PATCH V2 8/8] arm: mxs: add write support for ocotp
Date: Thu, 14 Jun 2012 15:21:05 +0200 [thread overview]
Message-ID: <1339680065-12169-9-git-send-email-w.sang@pengutronix.de> (raw)
In-Reply-To: <1339680065-12169-1-git-send-email-w.sang@pengutronix.de>
Since we now can change HCLK and VDDIO, we can now support writing to
OCOTP. Writing is done via a special data register. This is u32, so we
need to fill a temporary buffer when offset or count is not aligned. The
write is also protected by a special device variable.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
arch/arm/mach-mxs/Kconfig | 11 +++++
arch/arm/mach-mxs/ocotp.c | 109 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 120 insertions(+)
diff --git a/arch/arm/mach-mxs/Kconfig b/arch/arm/mach-mxs/Kconfig
index 57bd556..9ce7c7a 100644
--- a/arch/arm/mach-mxs/Kconfig
+++ b/arch/arm/mach-mxs/Kconfig
@@ -81,6 +81,17 @@ config MXS_OCOTP
internal view). Don't use register offsets here, the SET, CLR and
TGL registers are not mapped!
+config MXS_OCOTP_WRITABLE
+ bool "OCOTP write support"
+ depends on MXS_OCOTP
+ help
+ Enable this option to add writing to OCOTP.
+ Warning: blown bits can not be unblown. Use with care.
+
+ Before being actually able to blow the bits, you need to explicitely
+ enable writing:
+ ocotp0.permanent_write_enable=1
+
endmenu
menu "Board specific settings "
diff --git a/arch/arm/mach-mxs/ocotp.c b/arch/arm/mach-mxs/ocotp.c
index f18d066..92a287f 100644
--- a/arch/arm/mach-mxs/ocotp.c
+++ b/arch/arm/mach-mxs/ocotp.c
@@ -25,13 +25,19 @@
#include <mach/generic.h>
#include <mach/ocotp.h>
#include <mach/imx-regs.h>
+#include <mach/clock-imx28.h>
+#include <mach/power.h>
#define DRIVERNAME "ocotp"
#define OCOTP_CTRL 0x0
+# define OCOTP_CTRL_ADDR_MASK 0x3f
# define OCOTP_CTRL_BUSY (1 << 8)
# define OCOTP_CTRL_ERROR (1 << 9)
# define OCOTP_CTRL_RD_BANK_OPEN (1 << 12)
+# define OCOTP_CTRL_WR_UNLOCK 0x3e770000
+
+#define OCOTP_DATA 0x10
#define OCOTP_WORD_OFFSET 0x20
@@ -92,11 +98,102 @@ static ssize_t mxs_ocotp_cdev_read(struct cdev *cdev, void *buf, size_t count,
return size;
}
+static ssize_t mxs_ocotp_cdev_write(struct cdev *cdev, const void *buf, size_t count,
+ ulong offset, ulong flags)
+{
+ struct ocotp_priv *priv = cdev->priv;
+ void __iomem *base = priv->base;
+ const char *write_param;
+ unsigned int write_enabled = 0;
+ unsigned long old_hclk, aligned_offset;
+ int old_vddio, num_words, num_bytes, i, ret = 0;
+ u8 *work_buf;
+ u32 reg;
+
+ write_param = dev_get_param(cdev->dev, "permanent_write_enable");
+ if (write_param)
+ write_enabled = simple_strtoul(write_param, NULL, 0);
+
+ if (!write_param || !write_enabled)
+ return -EPERM;
+
+ /* we can only work on u32, so calc some helpers */
+ aligned_offset = offset & ~3UL;
+ num_words = DIV_ROUND_UP(offset - aligned_offset + count, 4);
+ num_bytes = num_words << 2;
+
+ /* read in all words which will be modified */
+ work_buf = xmalloc(num_bytes);
+
+ i = mxs_ocotp_cdev_read(cdev, work_buf, num_bytes, aligned_offset, 0);
+ if (i != num_bytes) {
+ ret = -ENXIO;
+ goto free_mem;
+ }
+
+ /* modify read words with to be written data */
+ for (i = 0; i < count; i++)
+ work_buf[offset - aligned_offset + i] |= ((u8 *)buf)[i];
+
+ /* prepare system for OTP write */
+ old_hclk = imx_get_hclk();
+ old_vddio = imx_get_vddio();
+
+ imx_set_hclk(24000000);
+ imx_set_vddio(2800000);
+
+ writel(OCOTP_CTRL_RD_BANK_OPEN, base + OCOTP_CTRL + BIT_CLR);
+
+ if (mxs_ocotp_wait_busy(priv)) {
+ ret = -ETIMEDOUT;
+ goto restore_system;
+ }
+
+ /* write word for word via data register */
+ for (i = 0; i < num_words; i++) {
+ reg = readl(base + OCOTP_CTRL) & ~OCOTP_CTRL_ADDR_MASK;
+ reg |= OCOTP_CTRL_WR_UNLOCK | ((aligned_offset >> 2) + i);
+ writel(reg, base + OCOTP_CTRL);
+
+ writel(((u32 *)work_buf)[i], base + OCOTP_DATA);
+
+ if (mxs_ocotp_wait_busy(priv)) {
+ ret = -ETIMEDOUT;
+ goto restore_system;
+ }
+
+ mdelay(2);
+ }
+
+restore_system:
+ imx_set_vddio(old_vddio);
+ imx_set_hclk(old_hclk);
+free_mem:
+ free(work_buf);
+
+ return ret;
+}
+
static struct file_operations mxs_ocotp_ops = {
.read = mxs_ocotp_cdev_read,
.lseek = dev_lseek_default,
};
+static int mxs_ocotp_write_enable_set(struct device_d *dev, struct param_d *param,
+ const char *val)
+{
+ unsigned long write_enable;
+
+ if (!val)
+ return -EINVAL;
+
+ write_enable = simple_strtoul(val, NULL, 0);
+ if (write_enable > 1)
+ return -EINVAL;
+
+ return dev_param_set_generic(dev, param, write_enable ? "1" : "0");
+}
+
static int mxs_ocotp_probe(struct device_d *dev)
{
int err;
@@ -113,6 +210,18 @@ static int mxs_ocotp_probe(struct device_d *dev)
if (err < 0)
return err;
+ if (IS_ENABLED(CONFIG_MXS_OCOTP_WRITABLE)) {
+ mxs_ocotp_ops.write = mxs_ocotp_cdev_write;
+
+ err = dev_add_param(dev, "permanent_write_enable",
+ mxs_ocotp_write_enable_set, NULL, 0);
+ if (err < 0)
+ return err;
+ err = dev_set_param(dev, "permanent_write_enable", "0");
+ if (err < 0)
+ return err;
+ }
+
return 0;
}
--
1.7.10
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
prev parent reply other threads:[~2012-06-14 13:21 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-06-14 13:20 [PATCH V2 0/8] arm: mxs: add ocotp write support Wolfram Sang
2012-06-14 13:20 ` [PATCH V2 1/8] arm: mxs: make get_hclk result useable for upcoming set_hclk Wolfram Sang
2012-06-14 13:20 ` [PATCH V2 2/8] arm: mxs: add imx_set_hclk Wolfram Sang
2012-06-14 13:21 ` [PATCH V2 3/8] arm: mxs: refactor access to power domain Wolfram Sang
2012-06-14 13:21 ` [PATCH V2 4/8] arm: mxs: add POWER_BASE for MX28, too Wolfram Sang
2012-06-14 13:21 ` [PATCH V2 5/8] arm: mxs: add functions to get/set vddio Wolfram Sang
2012-06-14 13:21 ` [PATCH V2 6/8] arm: mxs: refactor timeout routine for ocotp Wolfram Sang
2012-06-14 13:21 ` [PATCH V2 7/8] arm: mxs: use consistent naming for #defines " Wolfram Sang
2012-06-14 13:21 ` Wolfram Sang [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1339680065-12169-9-git-send-email-w.sang@pengutronix.de \
--to=w.sang@pengutronix.de \
--cc=barebox@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox