summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-mxs
diff options
context:
space:
mode:
authorWolfram Sang <w.sang@pengutronix.de>2012-04-05 11:05:39 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2012-04-05 18:26:18 +0200
commit4be0faccd722a74e7cf7aa20b446c7057938d6df (patch)
tree9d788adfe2250f7ce4960c39b40cd947752c746c /arch/arm/mach-mxs
parent68ce5a3b03e4cc68e25e6f828d6947dac6beb69b (diff)
downloadbarebox-4be0faccd722a74e7cf7aa20b446c7057938d6df.tar.gz
barebox-4be0faccd722a74e7cf7aa20b446c7057938d6df.tar.xz
arm: mxs: add ocotp driver
Read-only support for now to get MAC addresses. Signed-off-by: Wolfram Sang <w.sang@pengutronix.de> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'arch/arm/mach-mxs')
-rw-r--r--arch/arm/mach-mxs/Kconfig14
-rw-r--r--arch/arm/mach-mxs/Makefile1
-rw-r--r--arch/arm/mach-mxs/include/mach/imx23-regs.h1
-rw-r--r--arch/arm/mach-mxs/include/mach/imx28-regs.h1
-rw-r--r--arch/arm/mach-mxs/include/mach/ocotp.h12
-rw-r--r--arch/arm/mach-mxs/ocotp.c139
6 files changed, 168 insertions, 0 deletions
diff --git a/arch/arm/mach-mxs/Kconfig b/arch/arm/mach-mxs/Kconfig
index 15f7c74315..4c869dc0f7 100644
--- a/arch/arm/mach-mxs/Kconfig
+++ b/arch/arm/mach-mxs/Kconfig
@@ -68,6 +68,20 @@ endchoice
endif
+menu "i.MX specific settings "
+
+config MXS_OCOTP
+ tristate "OCOTP device"
+ help
+ Device driver for the On-Chip One Time Programmable (OCOTP). Use the
+ regular md/mw commands to read and write (if write is supported).
+
+ Note that the OCOTP words are grouped consecutively (allocation
+ internal view). Don't use register offsets here, the SET, CLR and
+ TGL registers are not mapped!
+
+endmenu
+
menu "Board specific settings "
if MACH_TX28
diff --git a/arch/arm/mach-mxs/Makefile b/arch/arm/mach-mxs/Makefile
index f70a9944cf..172d928128 100644
--- a/arch/arm/mach-mxs/Makefile
+++ b/arch/arm/mach-mxs/Makefile
@@ -2,3 +2,4 @@ obj-y += imx.o iomux-imx.o reset-imx.o
obj-$(CONFIG_DRIVER_VIDEO_STM) += imx_lcd_clk.o
obj-$(CONFIG_ARCH_IMX23) += speed-imx23.o clocksource-imx23.o usb.o
obj-$(CONFIG_ARCH_IMX28) += speed-imx28.o clocksource-imx28.o
+obj-$(CONFIG_MXS_OCOTP) += ocotp.o
diff --git a/arch/arm/mach-mxs/include/mach/imx23-regs.h b/arch/arm/mach-mxs/include/mach/imx23-regs.h
index cc8c03e8bb..60f5bf9d6f 100644
--- a/arch/arm/mach-mxs/include/mach/imx23-regs.h
+++ b/arch/arm/mach-mxs/include/mach/imx23-regs.h
@@ -32,6 +32,7 @@
#define IMX_DBGUART_BASE 0x80070000
#define IMX_TIM1_BASE 0x80068000
#define IMX_IOMUXC_BASE 0x80018000
+#define IMX_OCOTP_BASE 0x8002c000
#define IMX_WDT_BASE 0x8005c000
#define IMX_CCM_BASE 0x80040000
#define IMX_I2C1_BASE 0x80058000
diff --git a/arch/arm/mach-mxs/include/mach/imx28-regs.h b/arch/arm/mach-mxs/include/mach/imx28-regs.h
index 0c97c4c2f2..9a2052c159 100644
--- a/arch/arm/mach-mxs/include/mach/imx28-regs.h
+++ b/arch/arm/mach-mxs/include/mach/imx28-regs.h
@@ -29,6 +29,7 @@
#define IMX_SSP2_BASE 0x80014000
#define IMX_SSP3_BASE 0x80016000
#define IMX_IOMUXC_BASE 0x80018000
+#define IMX_OCOTP_BASE 0x8002c000
#define IMX_FB_BASE 0x80030000
#define IMX_CCM_BASE 0x80040000
#define IMX_WDT_BASE 0x80056000
diff --git a/arch/arm/mach-mxs/include/mach/ocotp.h b/arch/arm/mach-mxs/include/mach/ocotp.h
new file mode 100644
index 0000000000..86b30c96e1
--- /dev/null
+++ b/arch/arm/mach-mxs/include/mach/ocotp.h
@@ -0,0 +1,12 @@
+/*
+ * Header file for mxs ocotp driver - same license as driver
+ *
+ * Copyright (C) 2012 by Wolfram Sang, Pengutronix e.K.
+ */
+
+#ifndef __MACH_OCOTP_H
+#define __MACH_OCOTP_H
+
+int mxs_ocotp_read(void *buf, int count, int offset);
+
+#endif /* __MACH_OCOTP_H */
diff --git a/arch/arm/mach-mxs/ocotp.c b/arch/arm/mach-mxs/ocotp.c
new file mode 100644
index 0000000000..38f9ffde16
--- /dev/null
+++ b/arch/arm/mach-mxs/ocotp.c
@@ -0,0 +1,139 @@
+/*
+ * ocotp.c - barebox driver for the On-Chip One Time Programmable for MXS
+ *
+ * Copyright (C) 2012 by Wolfram Sang, Pengutronix e.K.
+ * based on the kernel driver which is
+ * Copyright 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <xfuncs.h>
+#include <errno.h>
+#include <param.h>
+#include <fcntl.h>
+#include <malloc.h>
+#include <io.h>
+#include <clock.h>
+
+#include <mach/generic.h>
+#include <mach/ocotp.h>
+#include <mach/imx-regs.h>
+
+#define DRIVERNAME "ocotp"
+
+#define OCOTP_WORD_OFFSET 0x20
+
+#define BM_OCOTP_CTRL_BUSY (1 << 8)
+#define BM_OCOTP_CTRL_ERROR (1 << 9)
+#define BM_OCOTP_CTRL_RD_BANK_OPEN (1 << 12)
+
+struct ocotp_priv {
+ struct cdev cdev;
+ void __iomem *base;
+};
+
+static ssize_t mxs_ocotp_cdev_read(struct cdev *cdev, void *buf, size_t count,
+ ulong offset, ulong flags)
+{
+ struct ocotp_priv *priv = cdev->priv;
+ void __iomem *base = priv->base;
+ size_t size = min((ulong)count, cdev->size - offset);
+ uint64_t start;
+ int i;
+
+ /*
+ * clk_enable(hbus_clk) for ocotp can be skipped
+ * as it must be on when system is running.
+ */
+
+ /* try to clear ERROR bit */
+ writel(BM_OCOTP_CTRL_ERROR, base + BIT_CLR);
+
+ /* check both BUSY and ERROR cleared */
+ start = get_time_ns();
+ while (readl(base) & (BM_OCOTP_CTRL_BUSY | BM_OCOTP_CTRL_ERROR))
+ if (is_timeout(start, MSECOND))
+ return -ETIMEDOUT;
+
+ /* open OCOTP banks for read */
+ writel(BM_OCOTP_CTRL_RD_BANK_OPEN, base + BIT_SET);
+
+ /* approximately wait 32 hclk cycles */
+ udelay(1);
+
+ /* poll BUSY bit becoming cleared */
+ start = get_time_ns();
+ while (readl(base) & BM_OCOTP_CTRL_BUSY)
+ if (is_timeout(start, MSECOND))
+ return -ETIMEDOUT;
+
+ for (i = 0; i < size; i++)
+ /* When reading bytewise, we need to hop over the SET/CLR/TGL regs */
+ ((u8 *)buf)[i] = readb(base + OCOTP_WORD_OFFSET +
+ (((i + offset) & 0xfc) << 2) + ((i + offset) & 3));
+
+ /* close banks for power saving */
+ writel(BM_OCOTP_CTRL_RD_BANK_OPEN, base + BIT_CLR);
+
+ return size;
+}
+
+static struct file_operations mxs_ocotp_ops = {
+ .read = mxs_ocotp_cdev_read,
+ .lseek = dev_lseek_default,
+};
+
+static int mxs_ocotp_probe(struct device_d *dev)
+{
+ int err;
+ struct ocotp_priv *priv = xzalloc(sizeof (*priv));
+
+ priv->base = dev_request_mem_region(dev, 0);
+ priv->cdev.dev = dev;
+ priv->cdev.ops = &mxs_ocotp_ops;
+ priv->cdev.priv = priv;
+ priv->cdev.size = cpu_is_mx23() ? 128 : 160;
+ priv->cdev.name = DRIVERNAME;
+
+ err = devfs_create(&priv->cdev);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static struct driver_d mxs_ocotp_driver = {
+ .name = DRIVERNAME,
+ .probe = mxs_ocotp_probe,
+};
+
+static int mxs_ocotp_init(void)
+{
+ register_driver(&mxs_ocotp_driver);
+
+ return 0;
+}
+coredevice_initcall(mxs_ocotp_init);
+
+int mxs_ocotp_read(void *buf, int count, int offset)
+{
+ struct cdev *cdev;
+ int ret;
+
+ cdev = cdev_open(DRIVERNAME, O_RDONLY);
+ if (!cdev)
+ return -ENODEV;
+
+ ret = cdev_read(cdev, buf, count, offset, 0);
+
+ cdev_close(cdev);
+
+ return ret;
+}