All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] Added support for On Chip OTP in i.MX23/28
@ 2013-07-03 12:39 Christoph G. Baumann
  2013-07-03 12:39 ` [PATCH 1/3] " Christoph G. Baumann
                   ` (4 more replies)
  0 siblings, 5 replies; 17+ messages in thread
From: Christoph G. Baumann @ 2013-07-03 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

From: "Christoph G. Baumann" <cb@sgoc.de>

This patch contains the ported driver from Freescale for the On Chip OTP
cells in the i.MX23 and i.MX28. The OTP cells can be read and written via
files in /sys/fsl_otp.

Christoph G. Baumann (3):
  Added support for On Chip OTP in i.MX23/28
  Added support for On Chip OTP in i.MX23/28
  Added support for On Chip OTP in i.MX23/28

 arch/arm/boot/dts/imx28.dtsi                |    1 -
 arch/arm/mach-mxs/include/mach/mx23-ocotp.h |  311 +++++++++++++++++++++++++++
 arch/arm/mach-mxs/include/mach/mx28-ocotp.h |  239 ++++++++++++++++++++
 drivers/clk/mxs/clk-imx23.c                 |    2 +
 drivers/clk/mxs/clk-imx28.c                 |    1 +
 drivers/misc/Kconfig                        |   14 ++
 drivers/misc/Makefile                       |    1 +
 drivers/misc/fsl_otp.c                      |  249 +++++++++++++++++++++
 drivers/misc/fsl_otp.h                      |  201 +++++++++++++++++
 9 files changed, 1018 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/mach-mxs/include/mach/mx23-ocotp.h
 create mode 100644 arch/arm/mach-mxs/include/mach/mx28-ocotp.h
 create mode 100644 drivers/misc/fsl_otp.c
 create mode 100644 drivers/misc/fsl_otp.h

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/3] Added support for On Chip OTP in i.MX23/28
  2013-07-03 12:39 [PATCH 0/3] Added support for On Chip OTP in i.MX23/28 Christoph G. Baumann
@ 2013-07-03 12:39 ` Christoph G. Baumann
  2013-07-05  8:03   ` Maxime Ripard
  2013-07-03 12:39 ` [PATCH 2/3] " Christoph G. Baumann
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 17+ messages in thread
From: Christoph G. Baumann @ 2013-07-03 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

From: "Christoph G. Baumann" <cb@sgoc.de>

Signed-off-by: Christoph G. Baumann <cb@sgoc.de>
---
 drivers/misc/fsl_otp.c |  249 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/misc/fsl_otp.h |  201 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 450 insertions(+)
 create mode 100644 drivers/misc/fsl_otp.c
 create mode 100644 drivers/misc/fsl_otp.h

diff --git a/drivers/misc/fsl_otp.c b/drivers/misc/fsl_otp.c
new file mode 100644
index 0000000..fd1941a
--- /dev/null
+++ b/drivers/misc/fsl_otp.c
@@ -0,0 +1,249 @@
+/*
+ * Freescale On-Chip OTP driver
+ *
+ * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Ported to 3.7 by Christoph G. Baumann <cgb@debian.org>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#include <linux/kobject.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/fcntl.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include "fsl_otp.h"
+
+static DEFINE_MUTEX(otp_mutex);
+static struct kobject *otp_kobj;
+static struct attribute **attrs;
+static struct kobj_attribute *kattr;
+static struct attribute_group attr_group;
+
+static inline unsigned int get_reg_index(struct kobj_attribute *tmp)
+{
+	return tmp - kattr;
+}
+
+static int otp_wait_busy(u32 flags)
+{
+	int count;
+	u32 c;
+
+	for (count = 10000; count >= 0; count--) {
+		c = __raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CTRL);
+		if (!(c & (BM_OCOTP_CTRL_BUSY | BM_OCOTP_CTRL_ERROR | flags)))
+			break;
+		cpu_relax();
+	}
+
+	if (count < 0)
+		return -ETIMEDOUT;
+	return 0;
+}
+
+static ssize_t otp_show(struct kobject *kobj, struct kobj_attribute *attr,
+		      char *buf)
+{
+	unsigned int index = get_reg_index(attr);
+	u32 value = 0;
+
+	/* sanity check */
+	if (index >= otp_data.fuse_num)
+		return 0;
+
+	mutex_lock(&otp_mutex);
+
+	if (otp_read_prepare()) {
+		mutex_unlock(&otp_mutex);
+		return 0;
+	}
+	value = __raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CUST_N(index));
+	otp_read_post();
+
+	mutex_unlock(&otp_mutex);
+	return sprintf(buf, "0x%x\n", value);
+}
+
+static int otp_write_bits(int addr, u32 data, u32 magic)
+{
+	u32 c; /* for control register */
+
+	/* init the control register */
+	c = __raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CTRL);
+	c &= ~BM_OCOTP_CTRL_ADDR;
+	c |= BF(addr, OCOTP_CTRL_ADDR);
+	c |= BF(magic, OCOTP_CTRL_WR_UNLOCK);
+	__raw_writel(c, REGS_OCOTP_BASE + HW_OCOTP_CTRL);
+
+	/* init the data register */
+	__raw_writel(data, REGS_OCOTP_BASE + HW_OCOTP_DATA);
+	otp_wait_busy(0);
+
+	mdelay(2); /* Write Postamble */
+	return 0;
+}
+
+static ssize_t otp_store(struct kobject *kobj, struct kobj_attribute *attr,
+		       const char *buf, size_t count)
+{
+	unsigned int index = get_reg_index(attr);
+	int value;
+
+	/* sanity check */
+	if (index >= otp_data.fuse_num)
+		return 0;
+
+	sscanf(buf, "0x%x", &value);
+
+	mutex_lock(&otp_mutex);
+	if (otp_write_prepare()) {
+		mutex_unlock(&otp_mutex);
+		return 0;
+	}
+	otp_write_bits(index, value, 0x3e77);
+	otp_write_post();
+	mutex_unlock(&otp_mutex);
+
+	return count;
+}
+
+static void free_otp_attr(void)
+{
+	kfree(attrs);
+	attrs = NULL;
+
+	kfree(kattr);
+	kattr = NULL;
+}
+
+static int alloc_otp_attr(void)
+{
+	int i;
+
+	/* The last one is NULL, which is used to detect the end */
+	attrs = kzalloc((otp_data.fuse_num + 1) * sizeof(attrs[0]),
+			GFP_KERNEL);
+	kattr = kzalloc(otp_data.fuse_num * sizeof(struct kobj_attribute),
+			GFP_KERNEL);
+
+	if (!attrs || !kattr)
+		goto error_out;
+
+	for (i = 0; i < otp_data.fuse_num; i++) {
+		kattr[i].attr.name = otp_data.fuse_name[i];
+		kattr[i].attr.mode = 0600;
+		kattr[i].show  = otp_show;
+		kattr[i].store = otp_store;
+		attrs[i] = &kattr[i].attr;
+		sysfs_attr_init(attrs[i]);
+	}
+	memset(&attr_group, 0, sizeof(attr_group));
+	attr_group.attrs = attrs;
+	return 0;
+
+error_out:
+	free_otp_attr();
+	return -ENOMEM;
+}
+
+static int fsl_otp_probe(struct platform_device *pdev)
+{
+	int retval;
+	struct fsl_otp_data *pdata;
+
+
+	pdata = &otp_data;
+	if (pdev->dev.platform_data == NULL)
+		pdev->dev.platform_data = &otp_data;
+
+	retval = alloc_otp_attr();
+	if (retval)
+		return retval;
+
+	retval = map_ocotp_addr(pdev);
+	if (retval)
+		goto error;
+
+	otp_kobj = kobject_create_and_add("fsl_otp", NULL);
+	if (!otp_kobj) {
+		retval = -ENOMEM;
+		goto error;
+	}
+
+	retval = sysfs_create_group(otp_kobj, &attr_group);
+	if (retval)
+		goto error;
+
+	mutex_init(&otp_mutex);
+	return 0;
+error:
+	kobject_put(otp_kobj);
+	otp_kobj = NULL;
+	free_otp_attr();
+	unmap_ocotp_addr();
+	return retval;
+}
+
+static int otp_remove(struct platform_device *pdev)
+{
+	kobject_put(otp_kobj);
+	otp_kobj = NULL;
+
+	free_otp_attr();
+	unmap_ocotp_addr();
+	return 0;
+}
+
+static const struct of_device_id mxs_otp_dt_ids[] = {
+	{ .compatible = "fsl,ocotp", .data = NULL, },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxs_otp_dt_ids);
+
+static struct platform_driver ocotp_driver = {
+	.probe		= fsl_otp_probe,
+	.remove		= otp_remove,
+	.driver		= {
+		.name   = "ocotp",
+		.owner	= THIS_MODULE,
+		.of_match_table = mxs_otp_dt_ids,
+	},
+};
+
+static int __init fsl_otp_init(void)
+{
+	return platform_driver_register(&ocotp_driver);
+}
+
+static void __exit fsl_otp_exit(void)
+{
+	platform_driver_unregister(&ocotp_driver);
+}
+module_init(fsl_otp_init);
+module_exit(fsl_otp_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Huang Shijie <b32955@freescale.com>");
+MODULE_DESCRIPTION("Common driver for OTP controller");
diff --git a/drivers/misc/fsl_otp.h b/drivers/misc/fsl_otp.h
new file mode 100644
index 0000000..b429479
--- /dev/null
+++ b/drivers/misc/fsl_otp.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Ported to 3.7 by Christoph G. Baumann <cgb@debian.org>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef __FREESCALE_OTP__
+#define __FREESCALE_OTP__
+
+
+static int otp_wait_busy(u32 flags);
+
+/* IMX23 and IMX28 share most of the defination ========================= */
+#if (defined(CONFIG_SOC_IMX23) || defined(CONFIG_SOC_IMX28))
+
+#if defined(CONFIG_SOC_IMX28) && defined(CONFIG_SOC_IMX23)
+#undef CONFIG_SOC_IMX23
+#endif
+
+#include <linux/regulator/consumer.h>
+#include <mach/hardware.h>
+#include <mach/mxs.h>
+
+#if defined(CONFIG_SOC_IMX23)
+#include <mach/mx23.h>
+#include <mach/mx23-ocotp.h>
+#else
+#include <mach/mx28.h>
+#include <mach/mx28-ocotp.h>
+#endif
+
+#define OCOTP_PHYS_ADDR         MXS_OCOTP_BASE_ADDR
+#define REGS_OCOTP_BASE		(MXS_IO_ADDRESS(OCOTP_PHYS_ADDR))
+#define BF(value, field)	(((value) << BP_##field) & BM_##field)
+
+#if defined(CONFIG_SOC_IMX28)
+/* Building up eight registers's names of a bank */
+#define MXS_OTP_BANK(a, b, c, d, e, f, g, h)	\
+	{\
+	("HW_OCOTP_"#a), ("HW_OCOTP_"#b), ("HW_OCOTP_"#c), ("HW_OCOTP_"#d), \
+	("HW_OCOTP_"#e), ("HW_OCOTP_"#f), ("HW_OCOTP_"#g), ("HW_OCOTP_"#h) \
+	}
+
+#define MXS_OTP_BANKS		(5)
+#define MXS_OTP_BANK_ITEMS	(8)
+static const char *bank_reg_desc[MXS_OTP_BANKS][MXS_OTP_BANK_ITEMS] = {
+MXS_OTP_BANK(CUST0, CUST1, CUST2, CUST3, CRYPTO0, CRYPTO1, CRYPTO2, CRYPTO3),
+MXS_OTP_BANK(HWCAP0, HWCAP1, HWCAP2, HWCAP3, HWCAP4, HWCAP5, SWCAP, CUSTCAP),
+MXS_OTP_BANK(LOCK, OPS0, OPS1, OPS2, OPS3, UN0, UN1, UN2),
+MXS_OTP_BANK(ROM0, ROM1, ROM2, ROM3, ROM4, ROM5, ROM6, ROM7),
+MXS_OTP_BANK(SRK0, SRK1, SRK2, SRK3, SRK4, SRK5, SRK6, SRK7),
+};
+#endif /* if defined(CONFIG_SOC_IMX28) */
+
+
+#if defined(CONFIG_SOC_IMX23)
+/* Building up eight registers's names of a bank */
+#define MXS_OTP_BANK(a, b, c, d, e, f, g, h)	\
+	{\
+	("HW_OCOTP_"#a), ("HW_OCOTP_"#b), ("HW_OCOTP_"#c), ("HW_OCOTP_"#d), \
+	("HW_OCOTP_"#e), ("HW_OCOTP_"#f), ("HW_OCOTP_"#g), ("HW_OCOTP_"#h) \
+	}
+
+#define MXS_OTP_BANKS		(4)
+#define MXS_OTP_BANK_ITEMS	(8)
+static const char *bank_reg_desc[MXS_OTP_BANKS][MXS_OTP_BANK_ITEMS] = {
+MXS_OTP_BANK(CUST0, CUST1, CUST2, CUST3, CRYPTO0, CRYPTO1, CRYPTO2, CRYPTO3),
+MXS_OTP_BANK(HWCAP0, HWCAP1, HWCAP2, HWCAP3, HWCAP4, HWCAP5, SWCAP, CUSTCAP),
+MXS_OTP_BANK(LOCK, OPS0, OPS1, OPS2, OPS3, UN0, UN1, UN2),
+MXS_OTP_BANK(ROM0, ROM1, ROM2, ROM3, ROM4, ROM5, ROM6, ROM7),
+};
+
+#endif/* if defined(CONFIG_SOC_IMX23) */
+
+static unsigned long otp_hclk_saved;
+static u32 otp_voltage_saved;
+struct regulator *regu;
+
+struct fsl_otp_data {
+	char		**fuse_name;
+	char		*regulator_name;
+	unsigned int	fuse_num;
+};
+
+static struct fsl_otp_data otp_data = {
+	.fuse_name	= (char **)bank_reg_desc,
+	.regulator_name	= "vddio-sd0",
+	.fuse_num	= MXS_OTP_BANKS * MXS_OTP_BANK_ITEMS,
+};
+
+/* open the bank for the imx23/imx28 */
+static int otp_read_prepare(void)
+{
+	int r;
+
+	/* [1] set the HCLK */
+	/* [2] check BUSY and ERROR bit */
+	r = otp_wait_busy(0);
+	if (r < 0)
+		goto error;
+
+	/* [3] open bank */
+	__raw_writel(BM_OCOTP_CTRL_RD_BANK_OPEN,
+		REGS_OCOTP_BASE + HW_OCOTP_CTRL_SET);
+	udelay(10);
+
+	/* [4] wait for BUSY */
+	r = otp_wait_busy(0);
+	return 0;
+error:
+	return r;
+}
+
+static int otp_read_post(void)
+{
+	/* [5] close bank */
+	__raw_writel(BM_OCOTP_CTRL_RD_BANK_OPEN,
+		REGS_OCOTP_BASE + HW_OCOTP_CTRL_CLR);
+	return 0;
+}
+
+static int otp_write_prepare(void)
+{
+	struct clk *hclk;
+	int err = 0;
+
+	/* [1] HCLK to 24MHz. */
+	hclk = clk_get_sys("hbus", NULL);
+	if (IS_ERR(hclk)) {
+		err = PTR_ERR(hclk);
+		goto out;
+	}
+	/*
+	   WARNING  ACHTUNG  UWAGA
+
+	   the code below changes HCLK clock rate to 24M. This is
+	   required to write OTP bits (7.2.2 in STMP378x Target
+	   Specification), and might affect LCD operation, for example.
+	   Moreover, this hacky code changes VDDIO to 2.8V; and resto-
+	   res it only on otp_close(). This may affect... anything.
+
+	   You are warned now.
+	 */
+	otp_hclk_saved = clk_get_rate(hclk);
+	clk_set_rate(hclk, 24000000);
+
+	/* [2] The voltage is set to 2.8V */
+	regu = regulator_get(NULL, otp_data.regulator_name);
+	otp_voltage_saved = regulator_get_voltage(regu);
+	regulator_set_voltage(regu, 2800000, 2800000);
+
+	/* [3] wait for BUSY and ERROR */
+	err = otp_wait_busy(BM_OCOTP_CTRL_RD_BANK_OPEN);
+out:
+	return err;
+}
+
+static int otp_write_post(void)
+{
+	struct clk *hclk;
+
+	hclk = clk_get_sys("hbus", NULL);
+	if (IS_ERR(hclk))
+		return PTR_ERR(hclk);
+
+	/* restore the clock and voltage */
+	clk_set_rate(hclk, otp_hclk_saved);
+	regulator_set_voltage(regu, otp_voltage_saved, otp_voltage_saved);
+	otp_wait_busy(0);
+
+	/* reset */
+	__raw_writel(BM_OCOTP_CTRL_RELOAD_SHADOWS,
+			REGS_OCOTP_BASE + HW_OCOTP_CTRL_SET);
+	otp_wait_busy(BM_OCOTP_CTRL_RELOAD_SHADOWS);
+	return 0;
+}
+
+static int __init map_ocotp_addr(struct platform_device *pdev)
+{
+	return 0;
+}
+static void unmap_ocotp_addr(void)
+{
+}
+
+
+#endif /* (defined(CONFIG_SOC_IMX23) || defined(CONFIG_SOC_IMX28)) */
+#endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 2/3] Added support for On Chip OTP in i.MX23/28
  2013-07-03 12:39 [PATCH 0/3] Added support for On Chip OTP in i.MX23/28 Christoph G. Baumann
  2013-07-03 12:39 ` [PATCH 1/3] " Christoph G. Baumann
@ 2013-07-03 12:39 ` Christoph G. Baumann
  2013-07-05  8:08   ` Maxime Ripard
  2013-07-03 12:39 ` [PATCH 3/3] " Christoph G. Baumann
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 17+ messages in thread
From: Christoph G. Baumann @ 2013-07-03 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

From: "Christoph G. Baumann" <cb@sgoc.de>

Signed-off-by: Christoph G. Baumann <cb@sgoc.de>
---
 arch/arm/mach-mxs/include/mach/mx23-ocotp.h |  311 +++++++++++++++++++++++++++
 arch/arm/mach-mxs/include/mach/mx28-ocotp.h |  239 ++++++++++++++++++++
 2 files changed, 550 insertions(+)
 create mode 100644 arch/arm/mach-mxs/include/mach/mx23-ocotp.h
 create mode 100644 arch/arm/mach-mxs/include/mach/mx28-ocotp.h

diff --git a/arch/arm/mach-mxs/include/mach/mx23-ocotp.h b/arch/arm/mach-mxs/include/mach/mx23-ocotp.h
new file mode 100644
index 0000000..b246ef2
--- /dev/null
+++ b/arch/arm/mach-mxs/include/mach/mx23-ocotp.h
@@ -0,0 +1,311 @@
+/*
+ * Freescale OCOTP Register Definitions
+ *
+ * Copyright 2008-2010 Freescale Semiconductor, Inc.
+ * Copyright 2008 Embedded Alley Solutions, 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ * This file is created by xml file. Don't Edit it.
+ *
+ * Xml Revision: 1.21
+ * Template revision: 26195
+ */
+
+#ifndef __ARCH_ARM___OCOTP_H
+#define __ARCH_ARM___OCOTP_H
+
+
+#define HW_OCOTP_CTRL	(0x00000000)
+#define HW_OCOTP_CTRL_SET	(0x00000004)
+#define HW_OCOTP_CTRL_CLR	(0x00000008)
+#define HW_OCOTP_CTRL_TOG	(0x0000000c)
+
+#define BP_OCOTP_CTRL_WR_UNLOCK	16
+#define BM_OCOTP_CTRL_WR_UNLOCK	0xFFFF0000
+#define BF_OCOTP_CTRL_WR_UNLOCK(v) \
+		(((v) << 16) & BM_OCOTP_CTRL_WR_UNLOCK)
+#define BV_OCOTP_CTRL_WR_UNLOCK__KEY 0x3E77
+#define BP_OCOTP_CTRL_RSRVD2	14
+#define BM_OCOTP_CTRL_RSRVD2	0x0000C000
+#define BF_OCOTP_CTRL_RSRVD2(v)  \
+		(((v) << 14) & BM_OCOTP_CTRL_RSRVD2)
+#define BM_OCOTP_CTRL_RELOAD_SHADOWS	0x00002000
+#define BM_OCOTP_CTRL_RD_BANK_OPEN	0x00001000
+#define BP_OCOTP_CTRL_RSRVD1	10
+#define BM_OCOTP_CTRL_RSRVD1	0x00000C00
+#define BF_OCOTP_CTRL_RSRVD1(v)  \
+		(((v) << 10) & BM_OCOTP_CTRL_RSRVD1)
+#define BM_OCOTP_CTRL_ERROR	0x00000200
+#define BM_OCOTP_CTRL_BUSY	0x00000100
+#define BP_OCOTP_CTRL_RSRVD0	5
+#define BM_OCOTP_CTRL_RSRVD0	0x000000E0
+#define BF_OCOTP_CTRL_RSRVD0(v)  \
+		(((v) << 5) & BM_OCOTP_CTRL_RSRVD0)
+#define BP_OCOTP_CTRL_ADDR	0
+#define BM_OCOTP_CTRL_ADDR	0x0000001F
+#define BF_OCOTP_CTRL_ADDR(v)  \
+		(((v) << 0) & BM_OCOTP_CTRL_ADDR)
+
+#define HW_OCOTP_DATA	(0x00000010)
+
+#define BP_OCOTP_DATA_DATA	0
+#define BM_OCOTP_DATA_DATA	0xFFFFFFFF
+#define BF_OCOTP_DATA_DATA(v)	(v)
+
+/*
+ *  multi-register-define name HW_OCOTP_CUST_N
+ *              base 0x00000020
+ *              count 4
+ *              offset 0x10
+ */
+#define HW_OCOTP_CUST_N(n)	(0x00000020 + (n) * 0x10)
+#define BP_OCOTP_CUST_N_BITS	0
+#define BM_OCOTP_CUST_N_BITS	0xFFFFFFFF
+#define BF_OCOTP_CUST_N_BITS(v)	(v)
+
+/*
+ *  multi-register-define name HW_OCOTP_CRYPTO_N
+ *              base 0x00000060
+ *              count 4
+ *              offset 0x10
+ */
+#define HW_OCOTP_CRYPTO_N(n)	(0x00000060 + (n) * 0x10)
+#define BP_OCOTP_CRYPTO_N_BITS	0
+#define BM_OCOTP_CRYPTO_N_BITS	0xFFFFFFFF
+#define BF_OCOTP_CRYPTO_N_BITS(v)	(v)
+
+/*
+ *  multi-register-define name HW_OCOTP_HWCAP_N
+ *              base 0x000000A0
+ *              count 6
+ *              offset 0x10
+ */
+#define HW_OCOTP_HWCAP_N(n)	(0x000000a0 + (n) * 0x10)
+#define BP_OCOTP_HWCAP_N_BITS	0
+#define BM_OCOTP_HWCAP_N_BITS	0xFFFFFFFF
+#define BF_OCOTP_HWCAP_N_BITS(v)	(v)
+
+#define HW_OCOTP_SWCAP	(0x00000100)
+
+#define BP_OCOTP_SWCAP_BITS	0
+#define BM_OCOTP_SWCAP_BITS	0xFFFFFFFF
+#define BF_OCOTP_SWCAP_BITS(v)	(v)
+
+#define HW_OCOTP_CUSTCAP	(0x00000110)
+
+#define BM_OCOTP_CUSTCAP_CUST_DISABLE_WMADRM9	0x80000000
+#define BM_OCOTP_CUSTCAP_CUST_DISABLE_JANUSDRM10	0x40000000
+#define BP_OCOTP_CUSTCAP_RSRVD1	5
+#define BM_OCOTP_CUSTCAP_RSRVD1	0x3FFFFFE0
+#define BF_OCOTP_CUSTCAP_RSRVD1(v)  \
+		(((v) << 5) & BM_OCOTP_CUSTCAP_RSRVD1)
+#define BM_OCOTP_CUSTCAP_ENABLE_SJTAG_12MA_DRIVE	0x00000010
+#define BM_OCOTP_CUSTCAP_USE_PARALLEL_JTAG	0x00000008
+#define BM_OCOTP_CUSTCAP_RTC_XTAL_32768_PRESENT	0x00000004
+#define BM_OCOTP_CUSTCAP_RTC_XTAL_32000_PRESENT	0x00000002
+#define BM_OCOTP_CUSTCAP_RSRVD0	0x00000001
+
+#define HW_OCOTP_LOCK	(0x00000120)
+
+#define BM_OCOTP_LOCK_ROM7	0x80000000
+#define BM_OCOTP_LOCK_ROM6	0x40000000
+#define BM_OCOTP_LOCK_ROM5	0x20000000
+#define BM_OCOTP_LOCK_ROM4	0x10000000
+#define BM_OCOTP_LOCK_ROM3	0x08000000
+#define BM_OCOTP_LOCK_ROM2	0x04000000
+#define BM_OCOTP_LOCK_ROM1	0x02000000
+#define BM_OCOTP_LOCK_ROM0	0x01000000
+#define BM_OCOTP_LOCK_HWSW_SHADOW_ALT	0x00800000
+#define BM_OCOTP_LOCK_CRYPTODCP_ALT	0x00400000
+#define BM_OCOTP_LOCK_CRYPTOKEY_ALT	0x00200000
+#define BM_OCOTP_LOCK_PIN	0x00100000
+#define BM_OCOTP_LOCK_OPS	0x00080000
+#define BM_OCOTP_LOCK_UN2	0x00040000
+#define BM_OCOTP_LOCK_UN1	0x00020000
+#define BM_OCOTP_LOCK_UN0	0x00010000
+#define BP_OCOTP_LOCK_UNALLOCATED	11
+#define BM_OCOTP_LOCK_UNALLOCATED	0x0000F800
+#define BF_OCOTP_LOCK_UNALLOCATED(v)  \
+		(((v) << 11) & BM_OCOTP_LOCK_UNALLOCATED)
+#define BM_OCOTP_LOCK_ROM_SHADOW	0x00000400
+#define BM_OCOTP_LOCK_CUSTCAP	0x00000200
+#define BM_OCOTP_LOCK_HWSW	0x00000100
+#define BM_OCOTP_LOCK_CUSTCAP_SHADOW	0x00000080
+#define BM_OCOTP_LOCK_HWSW_SHADOW	0x00000040
+#define BM_OCOTP_LOCK_CRYPTODCP	0x00000020
+#define BM_OCOTP_LOCK_CRYPTOKEY	0x00000010
+#define BM_OCOTP_LOCK_CUST3	0x00000008
+#define BM_OCOTP_LOCK_CUST2	0x00000004
+#define BM_OCOTP_LOCK_CUST1	0x00000002
+#define BM_OCOTP_LOCK_CUST0	0x00000001
+
+/*
+ *  multi-register-define name HW_OCOTP_OPS_N
+ *              base 0x00000130
+ *              count 4
+ *              offset 0x10
+ */
+#define HW_OCOTP_OPS_N(n)	(0x00000130 + (n) * 0x10)
+#define BP_OCOTP_OPS_N_BITS	0
+#define BM_OCOTP_OPS_N_BITS	0xFFFFFFFF
+#define BF_OCOTP_OPS_N_BITS(v)	(v)
+
+/*
+ *  multi-register-define name HW_OCOTP_UN_N
+ *              base 0x00000170
+ *              count 3
+ *              offset 0x10
+ */
+#define HW_OCOTP_UN_N(n)	(0x00000170 + (n) * 0x10)
+#define BP_OCOTP_UN_N_BITS	0
+#define BM_OCOTP_UN_N_BITS	0xFFFFFFFF
+#define BF_OCOTP_UN_N_BITS(v)	(v)
+
+#define HW_OCOTP_ROM0	(0x000001a0)
+
+#define BP_OCOTP_ROM0_BOOT_MODE	24
+#define BM_OCOTP_ROM0_BOOT_MODE	0xFF000000
+#define BF_OCOTP_ROM0_BOOT_MODE(v) \
+		(((v) << 24) & BM_OCOTP_ROM0_BOOT_MODE)
+#define BM_OCOTP_ROM0_ENABLE_PJTAG_12MA_DRIVE	0x00800000
+#define BM_OCOTP_ROM0_USE_PARALLEL_JTAG	0x00400000
+#define BP_OCOTP_ROM0_SD_POWER_GATE_GPIO	20
+#define BM_OCOTP_ROM0_SD_POWER_GATE_GPIO	0x00300000
+#define BF_OCOTP_ROM0_SD_POWER_GATE_GPIO(v)  \
+		(((v) << 20) & BM_OCOTP_ROM0_SD_POWER_GATE_GPIO)
+#define BP_OCOTP_ROM0_SD_POWER_UP_DELAY	14
+#define BM_OCOTP_ROM0_SD_POWER_UP_DELAY	0x000FC000
+#define BF_OCOTP_ROM0_SD_POWER_UP_DELAY(v)  \
+		(((v) << 14) & BM_OCOTP_ROM0_SD_POWER_UP_DELAY)
+#define BP_OCOTP_ROM0_SD_BUS_WIDTH	12
+#define BM_OCOTP_ROM0_SD_BUS_WIDTH	0x00003000
+#define BF_OCOTP_ROM0_SD_BUS_WIDTH(v)  \
+		(((v) << 12) & BM_OCOTP_ROM0_SD_BUS_WIDTH)
+#define BP_OCOTP_ROM0_SSP_SCK_INDEX	8
+#define BM_OCOTP_ROM0_SSP_SCK_INDEX	0x00000F00
+#define BF_OCOTP_ROM0_SSP_SCK_INDEX(v)  \
+		(((v) << 8) & BM_OCOTP_ROM0_SSP_SCK_INDEX)
+#define BM_OCOTP_ROM0_RSRVD3	0x00000080
+#define BM_OCOTP_ROM0_DISABLE_SPI_NOR_FAST_READ		0x00000040
+#define BM_OCOTP_ROM0_ENABLE_USB_BOOT_SERIAL_NUM	0x00000020
+#define BM_OCOTP_ROM0_ENABLE_UNENCRYPTED_BOOT		0x00000010
+#define BM_OCOTP_ROM0_SD_MBR_BOOT	0x00000008
+#define BM_OCOTP_ROM0_RSRVD2	0x00000004
+#define BM_OCOTP_ROM0_RSRVD1	0x00000002
+#define BM_OCOTP_ROM0_RSRVD0	0x00000001
+
+#define HW_OCOTP_ROM1	(0x000001b0)
+
+#define BP_OCOTP_ROM1_RSRVD1	30
+#define BM_OCOTP_ROM1_RSRVD1	0xC0000000
+#define BF_OCOTP_ROM1_RSRVD1(v) \
+		(((v) << 30) & BM_OCOTP_ROM1_RSRVD1)
+#define BP_OCOTP_ROM1_USE_ALT_GPMI_RDY3	28
+#define BM_OCOTP_ROM1_USE_ALT_GPMI_RDY3	0x30000000
+#define BF_OCOTP_ROM1_USE_ALT_GPMI_RDY3(v)  \
+		(((v) << 28) & BM_OCOTP_ROM1_USE_ALT_GPMI_RDY3)
+#define BP_OCOTP_ROM1_USE_ALT_GPMI_CE3	26
+#define BM_OCOTP_ROM1_USE_ALT_GPMI_CE3	0x0C000000
+#define BF_OCOTP_ROM1_USE_ALT_GPMI_CE3(v)  \
+		(((v) << 26) & BM_OCOTP_ROM1_USE_ALT_GPMI_CE3)
+#define BM_OCOTP_ROM1_USE_ALT_GPMI_RDY2	0x02000000
+#define BM_OCOTP_ROM1_USE_ALT_GPMI_CE2	0x01000000
+#define BM_OCOTP_ROM1_ENABLE_NAND3_CE_RDY_PULLUP	0x00800000
+#define BM_OCOTP_ROM1_ENABLE_NAND2_CE_RDY_PULLUP	0x00400000
+#define BM_OCOTP_ROM1_ENABLE_NAND1_CE_RDY_PULLUP	0x00200000
+#define BM_OCOTP_ROM1_ENABLE_NAND0_CE_RDY_PULLUP	0x00100000
+#define BM_OCOTP_ROM1_UNTOUCH_INTERNAL_SSP_PULLUP	0x00080000
+#define BM_OCOTP_ROM1_SSP2_EXT_PULLUP	0x00040000
+#define BM_OCOTP_ROM1_SSP1_EXT_PULLUP	0x00020000
+#define BM_OCOTP_ROM1_SD_INCREASE_INIT_SEQ_TIME	0x00010000
+#define BM_OCOTP_ROM1_SD_INIT_SEQ_2_ENABLE	0x00008000
+#define BM_OCOTP_ROM1_SD_CMD0_DISABLE	0x00004000
+#define BM_OCOTP_ROM1_SD_INIT_SEQ_1_DISABLE	0x00002000
+#define BM_OCOTP_ROM1_USE_ALT_SSP1_DATA4_7	0x00001000
+#define BP_OCOTP_ROM1_BOOT_SEARCH_COUNT	8
+#define BM_OCOTP_ROM1_BOOT_SEARCH_COUNT	0x00000F00
+#define BF_OCOTP_ROM1_BOOT_SEARCH_COUNT(v)  \
+		(((v) << 8) & BM_OCOTP_ROM1_BOOT_SEARCH_COUNT)
+#define BP_OCOTP_ROM1_RSRVD0	3
+#define BM_OCOTP_ROM1_RSRVD0	0x000000F8
+#define BF_OCOTP_ROM1_RSRVD0(v)  \
+		(((v) << 3) & BM_OCOTP_ROM1_RSRVD0)
+#define BP_OCOTP_ROM1_NUMBER_OF_NANDS	0
+#define BM_OCOTP_ROM1_NUMBER_OF_NANDS	0x00000007
+#define BF_OCOTP_ROM1_NUMBER_OF_NANDS(v)  \
+		(((v) << 0) & BM_OCOTP_ROM1_NUMBER_OF_NANDS)
+
+#define HW_OCOTP_ROM2	(0x000001c0)
+
+#define BP_OCOTP_ROM2_USB_VID	16
+#define BM_OCOTP_ROM2_USB_VID	0xFFFF0000
+#define BF_OCOTP_ROM2_USB_VID(v) \
+		(((v) << 16) & BM_OCOTP_ROM2_USB_VID)
+#define BP_OCOTP_ROM2_USB_PID	0
+#define BM_OCOTP_ROM2_USB_PID	0x0000FFFF
+#define BF_OCOTP_ROM2_USB_PID(v)  \
+		(((v) << 0) & BM_OCOTP_ROM2_USB_PID)
+
+#define HW_OCOTP_ROM3	(0x000001d0)
+
+#define BP_OCOTP_ROM3_RSRVD1	10
+#define BM_OCOTP_ROM3_RSRVD1	0xFFFFFC00
+#define BF_OCOTP_ROM3_RSRVD1(v) \
+		(((v) << 10) & BM_OCOTP_ROM3_RSRVD1)
+#define BP_OCOTP_ROM3_RSRVD0	0
+#define BM_OCOTP_ROM3_RSRVD0	0x000003FF
+#define BF_OCOTP_ROM3_RSRVD0(v)  \
+		(((v) << 0) & BM_OCOTP_ROM3_RSRVD0)
+
+#define HW_OCOTP_ROM4	(0x000001e0)
+
+#define BP_OCOTP_ROM4_BITS	0
+#define BM_OCOTP_ROM4_BITS	0xFFFFFFFF
+#define BF_OCOTP_ROM4_BITS(v)	(v)
+
+#define HW_OCOTP_ROM5	(0x000001f0)
+
+#define BP_OCOTP_ROM5_BITS	0
+#define BM_OCOTP_ROM5_BITS	0xFFFFFFFF
+#define BF_OCOTP_ROM5_BITS(v)	(v)
+
+#define HW_OCOTP_ROM6	(0x00000200)
+
+#define BP_OCOTP_ROM6_BITS	0
+#define BM_OCOTP_ROM6_BITS	0xFFFFFFFF
+#define BF_OCOTP_ROM6_BITS(v)	(v)
+
+#define HW_OCOTP_ROM7	(0x00000210)
+
+#define BP_OCOTP_ROM7_BITS	0
+#define BM_OCOTP_ROM7_BITS	0xFFFFFFFF
+#define BF_OCOTP_ROM7_BITS(v)	(v)
+
+#define HW_OCOTP_VERSION	(0x00000220)
+
+#define BP_OCOTP_VERSION_MAJOR	24
+#define BM_OCOTP_VERSION_MAJOR	0xFF000000
+#define BF_OCOTP_VERSION_MAJOR(v) \
+		(((v) << 24) & BM_OCOTP_VERSION_MAJOR)
+#define BP_OCOTP_VERSION_MINOR	16
+#define BM_OCOTP_VERSION_MINOR	0x00FF0000
+#define BF_OCOTP_VERSION_MINOR(v)  \
+		(((v) << 16) & BM_OCOTP_VERSION_MINOR)
+#define BP_OCOTP_VERSION_STEP	0
+#define BM_OCOTP_VERSION_STEP	0x0000FFFF
+#define BF_OCOTP_VERSION_STEP(v)  \
+		(((v) << 0) & BM_OCOTP_VERSION_STEP)
+#endif /* __ARCH_ARM___OCOTP_H */
diff --git a/arch/arm/mach-mxs/include/mach/mx28-ocotp.h b/arch/arm/mach-mxs/include/mach/mx28-ocotp.h
new file mode 100644
index 0000000..61fa3f7
--- /dev/null
+++ b/arch/arm/mach-mxs/include/mach/mx28-ocotp.h
@@ -0,0 +1,239 @@
+/*
+ * Freescale OCOTP Register Definitions
+ *
+ * Copyright 2008-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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ * This file is created by xml file. Don't Edit it.
+ *
+ * Xml Revision: 1.21
+ * Template revision: 26195
+ */
+
+#ifndef __ARCH_ARM___OCOTP_H
+#define __ARCH_ARM___OCOTP_H
+
+
+#define HW_OCOTP_CTRL	(0x00000000)
+#define HW_OCOTP_CTRL_SET	(0x00000004)
+#define HW_OCOTP_CTRL_CLR	(0x00000008)
+#define HW_OCOTP_CTRL_TOG	(0x0000000c)
+
+#define BP_OCOTP_CTRL_WR_UNLOCK	16
+#define BM_OCOTP_CTRL_WR_UNLOCK	0xFFFF0000
+#define BF_OCOTP_CTRL_WR_UNLOCK(v) \
+		(((v) << 16) & BM_OCOTP_CTRL_WR_UNLOCK)
+#define BV_OCOTP_CTRL_WR_UNLOCK__KEY 0x3E77
+#define BP_OCOTP_CTRL_RSRVD2	14
+#define BM_OCOTP_CTRL_RSRVD2	0x0000C000
+#define BF_OCOTP_CTRL_RSRVD2(v)  \
+		(((v) << 14) & BM_OCOTP_CTRL_RSRVD2)
+#define BM_OCOTP_CTRL_RELOAD_SHADOWS	0x00002000
+#define BM_OCOTP_CTRL_RD_BANK_OPEN	0x00001000
+#define BP_OCOTP_CTRL_RSRVD1	10
+#define BM_OCOTP_CTRL_RSRVD1	0x00000C00
+#define BF_OCOTP_CTRL_RSRVD1(v)  \
+		(((v) << 10) & BM_OCOTP_CTRL_RSRVD1)
+#define BM_OCOTP_CTRL_ERROR	0x00000200
+#define BM_OCOTP_CTRL_BUSY	0x00000100
+#define BP_OCOTP_CTRL_RSRVD0	6
+#define BM_OCOTP_CTRL_RSRVD0	0x000000C0
+#define BF_OCOTP_CTRL_RSRVD0(v)  \
+		(((v) << 6) & BM_OCOTP_CTRL_RSRVD0)
+#define BP_OCOTP_CTRL_ADDR	0
+#define BM_OCOTP_CTRL_ADDR	0x0000003F
+#define BF_OCOTP_CTRL_ADDR(v)  \
+		(((v) << 0) & BM_OCOTP_CTRL_ADDR)
+
+#define HW_OCOTP_DATA	(0x00000010)
+
+#define BP_OCOTP_DATA_DATA	0
+#define BM_OCOTP_DATA_DATA	0xFFFFFFFF
+#define BF_OCOTP_DATA_DATA(v)	(v)
+
+/*
+ *  multi-register-define name HW_OCOTP_CUST_N
+ *              base 0x00000020
+ *              count 4
+ *              offset 0x10
+ */
+#define HW_OCOTP_CUST_N(n)	(0x00000020 + (n) * 0x10)
+#define BP_OCOTP_CUST_N_BITS	0
+#define BM_OCOTP_CUST_N_BITS	0xFFFFFFFF
+#define BF_OCOTP_CUST_N_BITS(v)	(v)
+
+/*
+ *  multi-register-define name HW_OCOTP_CRYPTO_N
+ *              base 0x00000060
+ *              count 4
+ *              offset 0x10
+ */
+#define HW_OCOTP_CRYPTO_N(n)	(0x00000060 + (n) * 0x10)
+#define BP_OCOTP_CRYPTO_N_BITS	0
+#define BM_OCOTP_CRYPTO_N_BITS	0xFFFFFFFF
+#define BF_OCOTP_CRYPTO_N_BITS(v)	(v)
+
+/*
+ *  multi-register-define name HW_OCOTP_HWCAP_N
+ *              base 0x000000A0
+ *              count 6
+ *              offset 0x10
+ */
+#define HW_OCOTP_HWCAP_N(n)	(0x000000a0 + (n) * 0x10)
+#define BP_OCOTP_HWCAP_N_BITS	0
+#define BM_OCOTP_HWCAP_N_BITS	0xFFFFFFFF
+#define BF_OCOTP_HWCAP_N_BITS(v)	(v)
+
+#define HW_OCOTP_SWCAP	(0x00000100)
+
+#define BP_OCOTP_SWCAP_BITS	0
+#define BM_OCOTP_SWCAP_BITS	0xFFFFFFFF
+#define BF_OCOTP_SWCAP_BITS(v)	(v)
+
+#define HW_OCOTP_CUSTCAP	(0x00000110)
+
+#define BP_OCOTP_CUSTCAP_RSRVD1	3
+#define BM_OCOTP_CUSTCAP_RSRVD1	0xFFFFFFF8
+#define BF_OCOTP_CUSTCAP_RSRVD1(v) \
+		(((v) << 3) & BM_OCOTP_CUSTCAP_RSRVD1)
+#define BM_OCOTP_CUSTCAP_RTC_XTAL_32768_PRESENT	0x00000004
+#define BM_OCOTP_CUSTCAP_RTC_XTAL_32000_PRESENT	0x00000002
+#define BM_OCOTP_CUSTCAP_RSRVD0	0x00000001
+
+#define HW_OCOTP_LOCK	(0x00000120)
+
+#define BM_OCOTP_LOCK_ROM7	0x80000000
+#define BM_OCOTP_LOCK_ROM6	0x40000000
+#define BM_OCOTP_LOCK_ROM5	0x20000000
+#define BM_OCOTP_LOCK_ROM4	0x10000000
+#define BM_OCOTP_LOCK_ROM3	0x08000000
+#define BM_OCOTP_LOCK_ROM2	0x04000000
+#define BM_OCOTP_LOCK_ROM1	0x02000000
+#define BM_OCOTP_LOCK_ROM0	0x01000000
+#define BM_OCOTP_LOCK_HWSW_SHADOW_ALT	0x00800000
+#define BM_OCOTP_LOCK_CRYPTODCP_ALT	0x00400000
+#define BM_OCOTP_LOCK_CRYPTOKEY_ALT	0x00200000
+#define BM_OCOTP_LOCK_PIN	0x00100000
+#define BM_OCOTP_LOCK_OPS	0x00080000
+#define BM_OCOTP_LOCK_UN2	0x00040000
+#define BM_OCOTP_LOCK_UN1	0x00020000
+#define BM_OCOTP_LOCK_UN0	0x00010000
+#define BM_OCOTP_LOCK_SRK	0x00008000
+#define BP_OCOTP_LOCK_UNALLOCATED	12
+#define BM_OCOTP_LOCK_UNALLOCATED	0x00007000
+#define BF_OCOTP_LOCK_UNALLOCATED(v)  \
+		(((v) << 12) & BM_OCOTP_LOCK_UNALLOCATED)
+#define BM_OCOTP_LOCK_SRK_SHADOW	0x00000800
+#define BM_OCOTP_LOCK_ROM_SHADOW	0x00000400
+#define BM_OCOTP_LOCK_CUSTCAP	0x00000200
+#define BM_OCOTP_LOCK_HWSW	0x00000100
+#define BM_OCOTP_LOCK_CUSTCAP_SHADOW	0x00000080
+#define BM_OCOTP_LOCK_HWSW_SHADOW	0x00000040
+#define BM_OCOTP_LOCK_CRYPTODCP	0x00000020
+#define BM_OCOTP_LOCK_CRYPTOKEY	0x00000010
+#define BM_OCOTP_LOCK_CUST3	0x00000008
+#define BM_OCOTP_LOCK_CUST2	0x00000004
+#define BM_OCOTP_LOCK_CUST1	0x00000002
+#define BM_OCOTP_LOCK_CUST0	0x00000001
+
+/*
+ *  multi-register-define name HW_OCOTP_OPS_N
+ *              base 0x00000130
+ *              count 4
+ *              offset 0x10
+ */
+#define HW_OCOTP_OPS_N(n)	(0x00000130 + (n) * 0x10)
+#define BP_OCOTP_OPS_N_BITS	0
+#define BM_OCOTP_OPS_N_BITS	0xFFFFFFFF
+#define BF_OCOTP_OPS_N_BITS(v)	(v)
+
+/*
+ *  multi-register-define name HW_OCOTP_UN_N
+ *              base 0x00000170
+ *              count 3
+ *              offset 0x10
+ */
+#define HW_OCOTP_UN_N(n)	(0x00000170 + (n) * 0x10)
+#define BP_OCOTP_UN_N_BITS	0
+#define BM_OCOTP_UN_N_BITS	0xFFFFFFFF
+#define BF_OCOTP_UN_N_BITS(v)	(v)
+
+/*
+ *  multi-register-define name HW_OCOTP_ROM_N
+ *              base 0x000001A0
+ *              count 8
+ *              offset 0x10
+ */
+#define HW_OCOTP_ROM_N(n)	(0x000001a0 + (n) * 0x10)
+#define BP_OCOTP_ROM_N_BOOT_MODE	24
+#define BM_OCOTP_ROM_N_BOOT_MODE	0xFF000000
+#define BF_OCOTP_ROM_N_BOOT_MODE(v) \
+		(((v) << 24) & BM_OCOTP_ROM_N_BOOT_MODE)
+#define BP_OCOTP_ROM_N_SD_MMC_MODE	22
+#define BM_OCOTP_ROM_N_SD_MMC_MODE	0x00C00000
+#define BF_OCOTP_ROM_N_SD_MMC_MODE(v)  \
+		(((v) << 22) & BM_OCOTP_ROM_N_SD_MMC_MODE)
+#define BP_OCOTP_ROM_N_SD_POWER_GATE_GPIO	20
+#define BM_OCOTP_ROM_N_SD_POWER_GATE_GPIO	0x00300000
+#define BF_OCOTP_ROM_N_SD_POWER_GATE_GPIO(v)  \
+		(((v) << 20) & BM_OCOTP_ROM_N_SD_POWER_GATE_GPIO)
+#define BP_OCOTP_ROM_N_SD_POWER_UP_DELAY	14
+#define BM_OCOTP_ROM_N_SD_POWER_UP_DELAY	0x000FC000
+#define BF_OCOTP_ROM_N_SD_POWER_UP_DELAY(v)  \
+		(((v) << 14) & BM_OCOTP_ROM_N_SD_POWER_UP_DELAY)
+#define BP_OCOTP_ROM_N_SD_BUS_WIDTH	12
+#define BM_OCOTP_ROM_N_SD_BUS_WIDTH	0x00003000
+#define BF_OCOTP_ROM_N_SD_BUS_WIDTH(v)  \
+		(((v) << 12) & BM_OCOTP_ROM_N_SD_BUS_WIDTH)
+#define BP_OCOTP_ROM_N_SSP_SCK_INDEX	8
+#define BM_OCOTP_ROM_N_SSP_SCK_INDEX	0x00000F00
+#define BF_OCOTP_ROM_N_SSP_SCK_INDEX(v)  \
+		(((v) << 8) & BM_OCOTP_ROM_N_SSP_SCK_INDEX)
+#define BM_OCOTP_ROM_N_EMMC_USE_DDR	0x00000080
+#define BM_OCOTP_ROM_N_DISABLE_SPI_NOR_FAST_READ	0x00000040
+#define BM_OCOTP_ROM_N_ENABLE_USB_BOOT_SERIAL_NUM	0x00000020
+#define BM_OCOTP_ROM_N_ENABLE_UNENCRYPTED_BOOT	0x00000010
+#define BM_OCOTP_ROM_N_SD_MBR_BOOT	0x00000008
+#define BM_OCOTP_ROM_N_RSRVD2	0x00000004
+#define BM_OCOTP_ROM_N_RSRVD1	0x00000002
+#define BM_OCOTP_ROM_N_RSRVD0	0x00000001
+
+/*
+ *  multi-register-define name HW_OCOTP_SRK_N
+ *              base 0x00000220
+ *              count 8
+ *              offset 0x10
+ */
+#define HW_OCOTP_SRK_N(n)	(0x00000220 + (n) * 0x10)
+#define BP_OCOTP_SRK_N_BITS	0
+#define BM_OCOTP_SRK_N_BITS	0xFFFFFFFF
+#define BF_OCOTP_SRK_N_BITS(v)	(v)
+
+#define HW_OCOTP_VERSION	(0x000002a0)
+
+#define BP_OCOTP_VERSION_MAJOR	24
+#define BM_OCOTP_VERSION_MAJOR	0xFF000000
+#define BF_OCOTP_VERSION_MAJOR(v) \
+		(((v) << 24) & BM_OCOTP_VERSION_MAJOR)
+#define BP_OCOTP_VERSION_MINOR	16
+#define BM_OCOTP_VERSION_MINOR	0x00FF0000
+#define BF_OCOTP_VERSION_MINOR(v)  \
+		(((v) << 16) & BM_OCOTP_VERSION_MINOR)
+#define BP_OCOTP_VERSION_STEP	0
+#define BM_OCOTP_VERSION_STEP	0x0000FFFF
+#define BF_OCOTP_VERSION_STEP(v)  \
+		(((v) << 0) & BM_OCOTP_VERSION_STEP)
+#endif /* __ARCH_ARM___OCOTP_H */
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 3/3] Added support for On Chip OTP in i.MX23/28
  2013-07-03 12:39 [PATCH 0/3] Added support for On Chip OTP in i.MX23/28 Christoph G. Baumann
  2013-07-03 12:39 ` [PATCH 1/3] " Christoph G. Baumann
  2013-07-03 12:39 ` [PATCH 2/3] " Christoph G. Baumann
@ 2013-07-03 12:39 ` Christoph G. Baumann
  2013-07-05  8:14   ` Maxime Ripard
  2013-07-05  7:38 ` [PATCH 0/3] " Maxime Ripard
  2013-07-17 16:27 ` [PATCH v2 0/3] mxs: add driver for On Chip OTP Christoph G. Baumann
  4 siblings, 1 reply; 17+ messages in thread
From: Christoph G. Baumann @ 2013-07-03 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

From: "Christoph G. Baumann" <cb@sgoc.de>

Signed-off-by: Christoph G. Baumann <cb@sgoc.de>
---
 arch/arm/boot/dts/imx28.dtsi |    1 -
 drivers/clk/mxs/clk-imx23.c  |    2 ++
 drivers/clk/mxs/clk-imx28.c  |    1 +
 drivers/misc/Kconfig         |   14 ++++++++++++++
 drivers/misc/Makefile        |    1 +
 5 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi
index 600f7cb..e9de86b 100644
--- a/arch/arm/boot/dts/imx28.dtsi
+++ b/arch/arm/boot/dts/imx28.dtsi
@@ -711,7 +711,6 @@
 			ocotp at 8002c000 {
 				compatible = "fsl,ocotp";
 				reg = <0x8002c000 0x2000>;
-				status = "disabled";
 			};
 
 			axi-ahb at 8002e000 {
diff --git a/drivers/clk/mxs/clk-imx23.c b/drivers/clk/mxs/clk-imx23.c
index f6a7487..ec76d00 100644
--- a/drivers/clk/mxs/clk-imx23.c
+++ b/drivers/clk/mxs/clk-imx23.c
@@ -168,6 +168,8 @@ int __init mx23_clocks_init(void)
 	clk_data.clk_num = ARRAY_SIZE(clks);
 	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
 
+	clk_register_clkdev(clks[hbus], NULL, "hbus");
+
 	for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
 		clk_prepare_enable(clks[clks_init_on[i]]);
 
diff --git a/drivers/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c
index 4faf0af..792fcaf 100644
--- a/drivers/clk/mxs/clk-imx28.c
+++ b/drivers/clk/mxs/clk-imx28.c
@@ -247,6 +247,7 @@ int __init mx28_clocks_init(void)
 	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
 
 	clk_register_clkdev(clks[enet_out], NULL, "enet_out");
+	clk_register_clkdev(clks[hbus], NULL, "hbus");
 
 	for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
 		clk_prepare_enable(clks[clks_init_on[i]]);
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index c002d86..b44ef48 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -527,6 +527,20 @@ config SRAM
 	  the genalloc API. It is supposed to be used for small on-chip SRAM
 	  areas found on many SoCs.
 
+config FSL_OTP
+	tristate "Freescale On-Chip OTP Memory Support"
+	depends on SOC_IMX23 || SOC_IMX28
+	default n
+	help
+		If you say Y here, you will get support for a SysFS interface for
+		the One Time Programmable memory pages that are stored on the
+		iMX23/28 processor.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called fsl_otp.
+
+	  If unsure, it is safe to say N.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index c235d5b..e622e01 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -53,3 +53,4 @@ obj-$(CONFIG_INTEL_MEI)		+= mei/
 obj-$(CONFIG_VMWARE_VMCI)	+= vmw_vmci/
 obj-$(CONFIG_LATTICE_ECP3_CONFIG)	+= lattice-ecp3-config.o
 obj-$(CONFIG_SRAM)		+= sram.o
+obj-$(CONFIG_FSL_OTP)           += fsl_otp.o
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 0/3] Added support for On Chip OTP in i.MX23/28
  2013-07-03 12:39 [PATCH 0/3] Added support for On Chip OTP in i.MX23/28 Christoph G. Baumann
                   ` (2 preceding siblings ...)
  2013-07-03 12:39 ` [PATCH 3/3] " Christoph G. Baumann
@ 2013-07-05  7:38 ` Maxime Ripard
  2013-07-07 21:19   ` Christoph G. Baumann
  2013-07-17 16:27 ` [PATCH v2 0/3] mxs: add driver for On Chip OTP Christoph G. Baumann
  4 siblings, 1 reply; 17+ messages in thread
From: Maxime Ripard @ 2013-07-05  7:38 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Christoph,

On Wed, Jul 03, 2013 at 02:39:11PM +0200, Christoph G. Baumann wrote:
> From: "Christoph G. Baumann" <cb@sgoc.de>
> 
> This patch contains the ported driver from Freescale for the On Chip OTP
> cells in the i.MX23 and i.MX28. The OTP cells can be read and written via
> files in /sys/fsl_otp.
> 
> Christoph G. Baumann (3):
>   Added support for On Chip OTP in i.MX23/28
>   Added support for On Chip OTP in i.MX23/28
>   Added support for On Chip OTP in i.MX23/28

You should use better commit logs here. There's no way to get what each
patch actually does from only looking at those lines.

You should probably have something like:
  misc: Add Freescale mxs On Chip OTP driver
  ARM: mxs: dt: Enable the OTP in the DTSI
  ...

This has two advantages: the review is easier since the reviewer
actually knows what each patch is doing and what to review, and most of
all, you get a cleaner and more complete history, so that in a few
month/years, you can get (ideally) all the context of this patch and
what it's actually doing without having to look into the code.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130705/bf3a310e/attachment.sig>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/3] Added support for On Chip OTP in i.MX23/28
  2013-07-03 12:39 ` [PATCH 1/3] " Christoph G. Baumann
@ 2013-07-05  8:03   ` Maxime Ripard
  0 siblings, 0 replies; 17+ messages in thread
From: Maxime Ripard @ 2013-07-05  8:03 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Christoph,

On Wed, Jul 03, 2013 at 02:39:12PM +0200, Christoph G. Baumann wrote:
> From: "Christoph G. Baumann" <cb@sgoc.de>
> 
> Signed-off-by: Christoph G. Baumann <cb@sgoc.de>
> ---
>  drivers/misc/fsl_otp.c |  249 ++++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/misc/fsl_otp.h |  201 ++++++++++++++++++++++++++++++++++++++
>  2 files changed, 450 insertions(+)
>  create mode 100644 drivers/misc/fsl_otp.c
>  create mode 100644 drivers/misc/fsl_otp.h
> 
> diff --git a/drivers/misc/fsl_otp.c b/drivers/misc/fsl_otp.c
> new file mode 100644
> index 0000000..fd1941a
> --- /dev/null
> +++ b/drivers/misc/fsl_otp.c
> @@ -0,0 +1,249 @@
> +/*
> + * Freescale On-Chip OTP driver
> + *
> + * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
> + *
> + * Ported to 3.7 by Christoph G. Baumann <cgb@debian.org>

Maybe it's not worth mentionning the version here, since it's wrong
anyway.

> + * 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.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
> + */
> +#include <linux/kobject.h>
> +#include <linux/string.h>
> +#include <linux/sysfs.h>
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/delay.h>
> +#include <linux/fcntl.h>
> +#include <linux/mutex.h>
> +#include <linux/clk.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/slab.h>
> +#include <linux/platform_device.h>
> +
> +#include "fsl_otp.h"
> +
> +static DEFINE_MUTEX(otp_mutex);
> +static struct kobject *otp_kobj;
> +static struct attribute **attrs;
> +static struct kobj_attribute *kattr;
> +static struct attribute_group attr_group;
> +
> +static inline unsigned int get_reg_index(struct kobj_attribute *tmp)
> +{
> +	return tmp - kattr;
> +}
> +
> +static int otp_wait_busy(u32 flags)
> +{
> +	int count;
> +	u32 c;
> +
> +	for (count = 10000; count >= 0; count--) {
> +		c = __raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CTRL);
> +		if (!(c & (BM_OCOTP_CTRL_BUSY | BM_OCOTP_CTRL_ERROR | flags)))
> +			break;
> +		cpu_relax();
> +	}
> +
> +	if (count < 0)
> +		return -ETIMEDOUT;
> +	return 0;
> +}
> +
> +static ssize_t otp_show(struct kobject *kobj, struct kobj_attribute *attr,
> +		      char *buf)
> +{
> +	unsigned int index = get_reg_index(attr);
> +	u32 value = 0;
> +
> +	/* sanity check */
> +	if (index >= otp_data.fuse_num)
> +		return 0;
> +
> +	mutex_lock(&otp_mutex);
> +
> +	if (otp_read_prepare()) {
> +		mutex_unlock(&otp_mutex);
> +		return 0;
> +	}
> +	value = __raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CUST_N(index));
> +	otp_read_post();
> +
> +	mutex_unlock(&otp_mutex);
> +	return sprintf(buf, "0x%x\n", value);
> +}
> +
> +static int otp_write_bits(int addr, u32 data, u32 magic)
> +{
> +	u32 c; /* for control register */
> +
> +	/* init the control register */
> +	c = __raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CTRL);
> +	c &= ~BM_OCOTP_CTRL_ADDR;
> +	c |= BF(addr, OCOTP_CTRL_ADDR);
> +	c |= BF(magic, OCOTP_CTRL_WR_UNLOCK);
> +	__raw_writel(c, REGS_OCOTP_BASE + HW_OCOTP_CTRL);
> +
> +	/* init the data register */
> +	__raw_writel(data, REGS_OCOTP_BASE + HW_OCOTP_DATA);

You shouldn't use __raw_readl/__raw_writel directly here, but
readl/writel. The __raw_* functions lack the endianness conversions and
the memory barrier readl has.

> +	otp_wait_busy(0);
> +
> +	mdelay(2); /* Write Postamble */

Why do you need the mdelay after your call to otp_wait_busy ?

> +	return 0;
> +}
> +
> +static ssize_t otp_store(struct kobject *kobj, struct kobj_attribute *attr,
> +		       const char *buf, size_t count)
> +{
> +	unsigned int index = get_reg_index(attr);
> +	int value;
> +
> +	/* sanity check */
> +	if (index >= otp_data.fuse_num)
> +		return 0;
> +
> +	sscanf(buf, "0x%x", &value);
> +
> +	mutex_lock(&otp_mutex);
> +	if (otp_write_prepare()) {
> +		mutex_unlock(&otp_mutex);
> +		return 0;
> +	}
> +	otp_write_bits(index, value, 0x3e77);

What's that magic value?

> +	otp_write_post();
> +	mutex_unlock(&otp_mutex);
> +
> +	return count;
> +}
> +
> +static void free_otp_attr(void)
> +{
> +	kfree(attrs);
> +	attrs = NULL;
> +
> +	kfree(kattr);
> +	kattr = NULL;
> +}
> +
> +static int alloc_otp_attr(void)
> +{
> +	int i;
> +
> +	/* The last one is NULL, which is used to detect the end */
> +	attrs = kzalloc((otp_data.fuse_num + 1) * sizeof(attrs[0]),
> +			GFP_KERNEL);
> +	kattr = kzalloc(otp_data.fuse_num * sizeof(struct kobj_attribute),
> +			GFP_KERNEL);
> +
> +	if (!attrs || !kattr)
> +		goto error_out;
> +
> +	for (i = 0; i < otp_data.fuse_num; i++) {
> +		kattr[i].attr.name = otp_data.fuse_name[i];
> +		kattr[i].attr.mode = 0600;
> +		kattr[i].show  = otp_show;
> +		kattr[i].store = otp_store;
> +		attrs[i] = &kattr[i].attr;
> +		sysfs_attr_init(attrs[i]);
> +	}
> +	memset(&attr_group, 0, sizeof(attr_group));
> +	attr_group.attrs = attrs;
> +	return 0;
> +
> +error_out:
> +	free_otp_attr();
> +	return -ENOMEM;
> +}
> +
> +static int fsl_otp_probe(struct platform_device *pdev)

Your function names could use some common prefix, it's a bit messy for
now. You have:
  - free_otp_*
  - otp_*
  - fsl_otp_*

You could use the prefix mxs_otp for all your functions, for example.

> +{
> +	int retval;
> +	struct fsl_otp_data *pdata;
> +
> +
> +	pdata = &otp_data;
> +	if (pdev->dev.platform_data == NULL)
> +		pdev->dev.platform_data = &otp_data;

Where is that otp_data coming from?

> +
> +	retval = alloc_otp_attr();
> +	if (retval)
> +		return retval;
> +
> +	retval = map_ocotp_addr(pdev);
> +	if (retval)
> +		goto error;
> +
> +	otp_kobj = kobject_create_and_add("fsl_otp", NULL);
> +	if (!otp_kobj) {
> +		retval = -ENOMEM;
> +		goto error;
> +	}
> +
> +	retval = sysfs_create_group(otp_kobj, &attr_group);
> +	if (retval)
> +		goto error;
> +
> +	mutex_init(&otp_mutex);
> +	return 0;
> +error:
> +	kobject_put(otp_kobj);
> +	otp_kobj = NULL;
> +	free_otp_attr();
> +	unmap_ocotp_addr();

Where is that unmap_ocotp_addr function declared?

> +	return retval;
> +}
> +
> +static int otp_remove(struct platform_device *pdev)
> +{
> +	kobject_put(otp_kobj);
> +	otp_kobj = NULL;
> +
> +	free_otp_attr();
> +	unmap_ocotp_addr();

Ditto.

> +	return 0;
> +}
> +
> +static const struct of_device_id mxs_otp_dt_ids[] = {
> +	{ .compatible = "fsl,ocotp", .data = NULL, },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, mxs_otp_dt_ids);
> +
> +static struct platform_driver ocotp_driver = {
> +	.probe		= fsl_otp_probe,
> +	.remove		= otp_remove,
> +	.driver		= {
> +		.name   = "ocotp",
> +		.owner	= THIS_MODULE,
> +		.of_match_table = mxs_otp_dt_ids,
> +	},
> +};
> +
> +static int __init fsl_otp_init(void)
> +{
> +	return platform_driver_register(&ocotp_driver);
> +}
> +
> +static void __exit fsl_otp_exit(void)
> +{
> +	platform_driver_unregister(&ocotp_driver);
> +}
> +module_init(fsl_otp_init);
> +module_exit(fsl_otp_exit);

You can use module_platform_driver here to remove all this boilerplate
code.

> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Huang Shijie <b32955@freescale.com>");
> +MODULE_DESCRIPTION("Common driver for OTP controller");
> diff --git a/drivers/misc/fsl_otp.h b/drivers/misc/fsl_otp.h
> new file mode 100644
> index 0000000..b429479
> --- /dev/null
> +++ b/drivers/misc/fsl_otp.h
> @@ -0,0 +1,201 @@
> +/*
> + * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
> + *
> + * Ported to 3.7 by Christoph G. Baumann <cgb@debian.org>
> + *
> + * 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.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + */
> +#ifndef __FREESCALE_OTP__
> +#define __FREESCALE_OTP__
> +
> +
> +static int otp_wait_busy(u32 flags);
> +
> +/* IMX23 and IMX28 share most of the defination ========================= */
> +#if (defined(CONFIG_SOC_IMX23) || defined(CONFIG_SOC_IMX28))
> +
> +#if defined(CONFIG_SOC_IMX28) && defined(CONFIG_SOC_IMX23)
> +#undef CONFIG_SOC_IMX23
> +#endif
> +
> +#include <linux/regulator/consumer.h>
> +#include <mach/hardware.h>
> +#include <mach/mxs.h>
> +
> +#if defined(CONFIG_SOC_IMX23)
> +#include <mach/mx23.h>
> +#include <mach/mx23-ocotp.h>
> +#else
> +#include <mach/mx28.h>
> +#include <mach/mx28-ocotp.h>
> +#endif

Are you even sure it compiles? These headers don't exist.

Also, now that the mxs platform enabled multi-platform support, you have
to keep in mind that this driver can be used on both an imx23 *and* an
imx28 at run time, so all these compile-time options should be removed.

> +#define OCOTP_PHYS_ADDR         MXS_OCOTP_BASE_ADDR
> +#define REGS_OCOTP_BASE		(MXS_IO_ADDRESS(OCOTP_PHYS_ADDR))
> +#define BF(value, field)	(((value) << BP_##field) & BM_##field)
> +
> +#if defined(CONFIG_SOC_IMX28)
> +/* Building up eight registers's names of a bank */
> +#define MXS_OTP_BANK(a, b, c, d, e, f, g, h)	\
> +	{\
> +	("HW_OCOTP_"#a), ("HW_OCOTP_"#b), ("HW_OCOTP_"#c), ("HW_OCOTP_"#d), \
> +	("HW_OCOTP_"#e), ("HW_OCOTP_"#f), ("HW_OCOTP_"#g), ("HW_OCOTP_"#h) \
> +	}
> +
> +#define MXS_OTP_BANKS		(5)
> +#define MXS_OTP_BANK_ITEMS	(8)
> +static const char *bank_reg_desc[MXS_OTP_BANKS][MXS_OTP_BANK_ITEMS] = {
> +MXS_OTP_BANK(CUST0, CUST1, CUST2, CUST3, CRYPTO0, CRYPTO1, CRYPTO2, CRYPTO3),
> +MXS_OTP_BANK(HWCAP0, HWCAP1, HWCAP2, HWCAP3, HWCAP4, HWCAP5, SWCAP, CUSTCAP),
> +MXS_OTP_BANK(LOCK, OPS0, OPS1, OPS2, OPS3, UN0, UN1, UN2),
> +MXS_OTP_BANK(ROM0, ROM1, ROM2, ROM3, ROM4, ROM5, ROM6, ROM7),
> +MXS_OTP_BANK(SRK0, SRK1, SRK2, SRK3, SRK4, SRK5, SRK6, SRK7),
> +};
> +#endif /* if defined(CONFIG_SOC_IMX28) */
> +
> +
> +#if defined(CONFIG_SOC_IMX23)
> +/* Building up eight registers's names of a bank */
> +#define MXS_OTP_BANK(a, b, c, d, e, f, g, h)	\
> +	{\
> +	("HW_OCOTP_"#a), ("HW_OCOTP_"#b), ("HW_OCOTP_"#c), ("HW_OCOTP_"#d), \
> +	("HW_OCOTP_"#e), ("HW_OCOTP_"#f), ("HW_OCOTP_"#g), ("HW_OCOTP_"#h) \
> +	}
> +
> +#define MXS_OTP_BANKS		(4)
> +#define MXS_OTP_BANK_ITEMS	(8)
> +static const char *bank_reg_desc[MXS_OTP_BANKS][MXS_OTP_BANK_ITEMS] = {
> +MXS_OTP_BANK(CUST0, CUST1, CUST2, CUST3, CRYPTO0, CRYPTO1, CRYPTO2, CRYPTO3),
> +MXS_OTP_BANK(HWCAP0, HWCAP1, HWCAP2, HWCAP3, HWCAP4, HWCAP5, SWCAP, CUSTCAP),
> +MXS_OTP_BANK(LOCK, OPS0, OPS1, OPS2, OPS3, UN0, UN1, UN2),
> +MXS_OTP_BANK(ROM0, ROM1, ROM2, ROM3, ROM4, ROM5, ROM6, ROM7),
> +};
> +
> +#endif/* if defined(CONFIG_SOC_IMX23) */
> +
> +static unsigned long otp_hclk_saved;
> +static u32 otp_voltage_saved;
> +struct regulator *regu;
> +
> +struct fsl_otp_data {
> +	char		**fuse_name;
> +	char		*regulator_name;
> +	unsigned int	fuse_num;
> +};
> +
> +static struct fsl_otp_data otp_data = {
> +	.fuse_name	= (char **)bank_reg_desc,
> +	.regulator_name	= "vddio-sd0",
> +	.fuse_num	= MXS_OTP_BANKS * MXS_OTP_BANK_ITEMS,
> +};
> +
> +/* open the bank for the imx23/imx28 */
> +static int otp_read_prepare(void)
> +{
> +	int r;
> +
> +	/* [1] set the HCLK */
> +	/* [2] check BUSY and ERROR bit */
> +	r = otp_wait_busy(0);
> +	if (r < 0)
> +		goto error;
> +
> +	/* [3] open bank */
> +	__raw_writel(BM_OCOTP_CTRL_RD_BANK_OPEN,
> +		REGS_OCOTP_BASE + HW_OCOTP_CTRL_SET);
> +	udelay(10);
> +
> +	/* [4] wait for BUSY */
> +	r = otp_wait_busy(0);
> +	return 0;
> +error:
> +	return r;
> +}
> +
> +static int otp_read_post(void)
> +{
> +	/* [5] close bank */
> +	__raw_writel(BM_OCOTP_CTRL_RD_BANK_OPEN,
> +		REGS_OCOTP_BASE + HW_OCOTP_CTRL_CLR);
> +	return 0;
> +}
> +
> +static int otp_write_prepare(void)
> +{
> +	struct clk *hclk;
> +	int err = 0;
> +
> +	/* [1] HCLK to 24MHz. */
> +	hclk = clk_get_sys("hbus", NULL);
> +	if (IS_ERR(hclk)) {
> +		err = PTR_ERR(hclk);
> +		goto out;
> +	}
> +	/*
> +	   WARNING  ACHTUNG  UWAGA
> +
> +	   the code below changes HCLK clock rate to 24M. This is
> +	   required to write OTP bits (7.2.2 in STMP378x Target
> +	   Specification), and might affect LCD operation, for example.
> +	   Moreover, this hacky code changes VDDIO to 2.8V; and resto-
> +	   res it only on otp_close(). This may affect... anything.
> +
> +	   You are warned now.
> +	 */
> +	otp_hclk_saved = clk_get_rate(hclk);
> +	clk_set_rate(hclk, 24000000);
> +
> +	/* [2] The voltage is set to 2.8V */
> +	regu = regulator_get(NULL, otp_data.regulator_name);
> +	otp_voltage_saved = regulator_get_voltage(regu);
> +	regulator_set_voltage(regu, 2800000, 2800000);
> +
> +	/* [3] wait for BUSY and ERROR */
> +	err = otp_wait_busy(BM_OCOTP_CTRL_RD_BANK_OPEN);
> +out:
> +	return err;
> +}
> +
> +static int otp_write_post(void)
> +{
> +	struct clk *hclk;
> +
> +	hclk = clk_get_sys("hbus", NULL);
> +	if (IS_ERR(hclk))
> +		return PTR_ERR(hclk);
> +
> +	/* restore the clock and voltage */
> +	clk_set_rate(hclk, otp_hclk_saved);
> +	regulator_set_voltage(regu, otp_voltage_saved, otp_voltage_saved);
> +	otp_wait_busy(0);
> +
> +	/* reset */
> +	__raw_writel(BM_OCOTP_CTRL_RELOAD_SHADOWS,
> +			REGS_OCOTP_BASE + HW_OCOTP_CTRL_SET);
> +	otp_wait_busy(BM_OCOTP_CTRL_RELOAD_SHADOWS);
> +	return 0;
> +}
> +
> +static int __init map_ocotp_addr(struct platform_device *pdev)
> +{
> +	return 0;
> +}
> +static void unmap_ocotp_addr(void)
> +{
> +}

Ah, so here are your functions and structures. Putting !inline functions
in a header is considered a bad practice, so you should move them in the
driver directly.

Thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130705/4bca9dbb/attachment.sig>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 2/3] Added support for On Chip OTP in i.MX23/28
  2013-07-03 12:39 ` [PATCH 2/3] " Christoph G. Baumann
@ 2013-07-05  8:08   ` Maxime Ripard
  0 siblings, 0 replies; 17+ messages in thread
From: Maxime Ripard @ 2013-07-05  8:08 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Christoph,

On Wed, Jul 03, 2013 at 02:39:13PM +0200, Christoph G. Baumann wrote:
> From: "Christoph G. Baumann" <cb@sgoc.de>
> 
> Signed-off-by: Christoph G. Baumann <cb@sgoc.de>
> ---
>  arch/arm/mach-mxs/include/mach/mx23-ocotp.h |  311 +++++++++++++++++++++++++++
>  arch/arm/mach-mxs/include/mach/mx28-ocotp.h |  239 ++++++++++++++++++++
>  2 files changed, 550 insertions(+)
>  create mode 100644 arch/arm/mach-mxs/include/mach/mx23-ocotp.h
>  create mode 100644 arch/arm/mach-mxs/include/mach/mx28-ocotp.h

Ah. Here are your includes.

Two things then:
  - Like I said in my previous mail, the include/mach doesn't play well
    with the multi-platform kernels. How should you choose one header
    instead of another in this case, or even one mach/ directory or
    another if you have several platforms enabled.
  - From what I can recall, the OCOTP is only something like a few MMIO
    bytes to access, with a bit of logic when writing, but nothing more
    than a few registers and a few bits in there. Are you sure you
    actually need 550 lines of define for only a dozen defines or so?

Thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130705/db5ffe9a/attachment.sig>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 3/3] Added support for On Chip OTP in i.MX23/28
  2013-07-03 12:39 ` [PATCH 3/3] " Christoph G. Baumann
@ 2013-07-05  8:14   ` Maxime Ripard
  0 siblings, 0 replies; 17+ messages in thread
From: Maxime Ripard @ 2013-07-05  8:14 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Christoph,

On Wed, Jul 03, 2013 at 02:39:14PM +0200, Christoph G. Baumann wrote:
> From: "Christoph G. Baumann" <cb@sgoc.de>
> 
> Signed-off-by: Christoph G. Baumann <cb@sgoc.de>
> ---
>  arch/arm/boot/dts/imx28.dtsi |    1 -
>  drivers/clk/mxs/clk-imx23.c  |    2 ++
>  drivers/clk/mxs/clk-imx28.c  |    1 +
>  drivers/misc/Kconfig         |   14 ++++++++++++++
>  drivers/misc/Makefile        |    1 +
>  5 files changed, 18 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi
> index 600f7cb..e9de86b 100644
> --- a/arch/arm/boot/dts/imx28.dtsi
> +++ b/arch/arm/boot/dts/imx28.dtsi
> @@ -711,7 +711,6 @@
>  			ocotp at 8002c000 {
>  				compatible = "fsl,ocotp";
>  				reg = <0x8002c000 0x2000>;
> -				status = "disabled";
>  			};

Why do you enable it only for imx28?

>  			axi-ahb at 8002e000 {
> diff --git a/drivers/clk/mxs/clk-imx23.c b/drivers/clk/mxs/clk-imx23.c
> index f6a7487..ec76d00 100644
> --- a/drivers/clk/mxs/clk-imx23.c
> +++ b/drivers/clk/mxs/clk-imx23.c
> @@ -168,6 +168,8 @@ int __init mx23_clocks_init(void)
>  	clk_data.clk_num = ARRAY_SIZE(clks);
>  	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
>  
> +	clk_register_clkdev(clks[hbus], NULL, "hbus");
> +
>  	for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
>  		clk_prepare_enable(clks[clks_init_on[i]]);
>  
> diff --git a/drivers/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c
> index 4faf0af..792fcaf 100644
> --- a/drivers/clk/mxs/clk-imx28.c
> +++ b/drivers/clk/mxs/clk-imx28.c
> @@ -247,6 +247,7 @@ int __init mx28_clocks_init(void)
>  	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
>  
>  	clk_register_clkdev(clks[enet_out], NULL, "enet_out");
> +	clk_register_clkdev(clks[hbus], NULL, "hbus");
>  
>  	for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
>  		clk_prepare_enable(clks[clks_init_on[i]]);

These two should go in a separate patch (with details on why it's
needed).

> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
> index c002d86..b44ef48 100644
> --- a/drivers/misc/Kconfig
> +++ b/drivers/misc/Kconfig
> @@ -527,6 +527,20 @@ config SRAM
>  	  the genalloc API. It is supposed to be used for small on-chip SRAM
>  	  areas found on many SoCs.
>  
> +config FSL_OTP
> +	tristate "Freescale On-Chip OTP Memory Support"
> +	depends on SOC_IMX23 || SOC_IMX28
> +	default n
> +	help
> +		If you say Y here, you will get support for a SysFS interface for
> +		the One Time Programmable memory pages that are stored on the
> +		iMX23/28 processor.
> +
> +	  To compile this driver as a module, choose M here: the module
> +	  will be called fsl_otp.
> +
> +	  If unsure, it is safe to say N.
> +
>  source "drivers/misc/c2port/Kconfig"
>  source "drivers/misc/eeprom/Kconfig"
>  source "drivers/misc/cb710/Kconfig"
> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
> index c235d5b..e622e01 100644
> --- a/drivers/misc/Makefile
> +++ b/drivers/misc/Makefile
> @@ -53,3 +53,4 @@ obj-$(CONFIG_INTEL_MEI)		+= mei/
>  obj-$(CONFIG_VMWARE_VMCI)	+= vmw_vmci/
>  obj-$(CONFIG_LATTICE_ECP3_CONFIG)	+= lattice-ecp3-config.o
>  obj-$(CONFIG_SRAM)		+= sram.o
> +obj-$(CONFIG_FSL_OTP)           += fsl_otp.o

And this should be merged with the first patch.

Thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130705/b1828b3d/attachment.sig>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 0/3] Added support for On Chip OTP in i.MX23/28
  2013-07-05  7:38 ` [PATCH 0/3] " Maxime Ripard
@ 2013-07-07 21:19   ` Christoph G. Baumann
  0 siblings, 0 replies; 17+ messages in thread
From: Christoph G. Baumann @ 2013-07-07 21:19 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Maxime,

thanks for all your hints. My approach on porting the Freescale code may have
been a bit too straight forward.
I will do some refactoring and try to follow your comments.


Regards
Christoph

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v2 0/3] mxs: add driver for On Chip OTP
  2013-07-03 12:39 [PATCH 0/3] Added support for On Chip OTP in i.MX23/28 Christoph G. Baumann
                   ` (3 preceding siblings ...)
  2013-07-05  7:38 ` [PATCH 0/3] " Maxime Ripard
@ 2013-07-17 16:27 ` Christoph G. Baumann
  2013-07-17 16:27   ` [PATCH v2 1/3] mxs: enable ocotp in device tree Christoph G. Baumann
                     ` (2 more replies)
  4 siblings, 3 replies; 17+ messages in thread
From: Christoph G. Baumann @ 2013-07-17 16:27 UTC (permalink / raw)
  To: linux-arm-kernel

From: "Christoph G. Baumann" <cb@sgoc.de>

This patch brings read/write support for the On Chip OTP cells in the i.MX23
and i.MX28 processor. The driver uses files (one for each cell) in /sys/fsl_otp
as interface. The original code from Freescale was stripped down to the
required minimum and ported to 3.x kernels.

Christoph G. Baumann (3):
  mxs: enable ocotp in device tree
  mxs: register clkdev "hbus" as it is required by OCOTP driver
  mxs: added driver for OCOTP in i.MX23 and i.MX28

 arch/arm/boot/dts/imx23.dtsi |    1 -
 arch/arm/boot/dts/imx28.dtsi |    1 -
 drivers/clk/mxs/clk-imx23.c  |    2 +
 drivers/clk/mxs/clk-imx28.c  |    1 +
 drivers/misc/Kconfig         |   14 ++
 drivers/misc/Makefile        |    1 +
 drivers/misc/fsl_otp.c       |  363 ++++++++++++++++++++++++++++++++++++++++++
 drivers/misc/fsl_otp.h       |  126 +++++++++++++++
 8 files changed, 507 insertions(+), 2 deletions(-)
 create mode 100644 drivers/misc/fsl_otp.c
 create mode 100644 drivers/misc/fsl_otp.h

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v2 1/3] mxs: enable ocotp in device tree
  2013-07-17 16:27 ` [PATCH v2 0/3] mxs: add driver for On Chip OTP Christoph G. Baumann
@ 2013-07-17 16:27   ` Christoph G. Baumann
  2013-07-17 16:27   ` [PATCH v2 2/3] mxs: register clkdev "hbus" as it is required by OCOTP Christoph G. Baumann
  2013-07-17 16:27   ` [PATCH v2 3/3] mxs: added driver for OCOTP in i.MX23 and i.MX28 Christoph G. Baumann
  2 siblings, 0 replies; 17+ messages in thread
From: Christoph G. Baumann @ 2013-07-17 16:27 UTC (permalink / raw)
  To: linux-arm-kernel

From: "Christoph G. Baumann" <cb@sgoc.de>

Signed-off-by: "Christoph G. Baumann" <cb@sgoc.de>
---
 arch/arm/boot/dts/imx23.dtsi |    1 -
 arch/arm/boot/dts/imx28.dtsi |    1 -
 2 files changed, 2 deletions(-)

diff --git a/arch/arm/boot/dts/imx23.dtsi b/arch/arm/boot/dts/imx23.dtsi
index 587ceef..dc70ea9 100644
--- a/arch/arm/boot/dts/imx23.dtsi
+++ b/arch/arm/boot/dts/imx23.dtsi
@@ -348,7 +348,6 @@
 			ocotp at 8002c000 {
 				compatible = "fsl,ocotp";
 				reg = <0x8002c000 0x2000>;
-				status = "disabled";
 			};
 
 			axi-ahb at 8002e000 {
diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi
index 6a8acb0..968244a 100644
--- a/arch/arm/boot/dts/imx28.dtsi
+++ b/arch/arm/boot/dts/imx28.dtsi
@@ -748,7 +748,6 @@
 			ocotp at 8002c000 {
 				compatible = "fsl,ocotp";
 				reg = <0x8002c000 0x2000>;
-				status = "disabled";
 			};
 
 			axi-ahb at 8002e000 {
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 2/3] mxs: register clkdev "hbus" as it is required by OCOTP
  2013-07-17 16:27 ` [PATCH v2 0/3] mxs: add driver for On Chip OTP Christoph G. Baumann
  2013-07-17 16:27   ` [PATCH v2 1/3] mxs: enable ocotp in device tree Christoph G. Baumann
@ 2013-07-17 16:27   ` Christoph G. Baumann
  2013-07-17 16:27   ` [PATCH v2 3/3] mxs: added driver for OCOTP in i.MX23 and i.MX28 Christoph G. Baumann
  2 siblings, 0 replies; 17+ messages in thread
From: Christoph G. Baumann @ 2013-07-17 16:27 UTC (permalink / raw)
  To: linux-arm-kernel

From: "Christoph G. Baumann" <cb@sgoc.de>

The OCOTP driver needs to switch the HBUS clock when burning OTP bits.
For this purpose it uses the CLK-API and requests a handler for "hbus".
Trying to burn bits without registered "hbus" CLK results in a blocked user
process.

Signed-off-by: "Christoph G. Baumann" <cb@sgoc.de>
---
 drivers/clk/mxs/clk-imx23.c |    2 ++
 drivers/clk/mxs/clk-imx28.c |    1 +
 2 files changed, 3 insertions(+)

diff --git a/drivers/clk/mxs/clk-imx23.c b/drivers/clk/mxs/clk-imx23.c
index f6a7487..ec76d00 100644
--- a/drivers/clk/mxs/clk-imx23.c
+++ b/drivers/clk/mxs/clk-imx23.c
@@ -168,6 +168,8 @@ int __init mx23_clocks_init(void)
 	clk_data.clk_num = ARRAY_SIZE(clks);
 	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
 
+	clk_register_clkdev(clks[hbus], NULL, "hbus");
+
 	for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
 		clk_prepare_enable(clks[clks_init_on[i]]);
 
diff --git a/drivers/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c
index 4faf0af..792fcaf 100644
--- a/drivers/clk/mxs/clk-imx28.c
+++ b/drivers/clk/mxs/clk-imx28.c
@@ -247,6 +247,7 @@ int __init mx28_clocks_init(void)
 	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
 
 	clk_register_clkdev(clks[enet_out], NULL, "enet_out");
+	clk_register_clkdev(clks[hbus], NULL, "hbus");
 
 	for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
 		clk_prepare_enable(clks[clks_init_on[i]]);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 3/3] mxs: added driver for OCOTP in i.MX23 and i.MX28
  2013-07-17 16:27 ` [PATCH v2 0/3] mxs: add driver for On Chip OTP Christoph G. Baumann
  2013-07-17 16:27   ` [PATCH v2 1/3] mxs: enable ocotp in device tree Christoph G. Baumann
  2013-07-17 16:27   ` [PATCH v2 2/3] mxs: register clkdev "hbus" as it is required by OCOTP Christoph G. Baumann
@ 2013-07-17 16:27   ` Christoph G. Baumann
  2013-07-17 19:26     ` Sascha Hauer
  2 siblings, 1 reply; 17+ messages in thread
From: Christoph G. Baumann @ 2013-07-17 16:27 UTC (permalink / raw)
  To: linux-arm-kernel

From: "Christoph G. Baumann" <cb@sgoc.de>

Signed-off-by: "Christoph G. Baumann" <cb@sgoc.de>
---
 drivers/misc/Kconfig   |   14 ++
 drivers/misc/Makefile  |    1 +
 drivers/misc/fsl_otp.c |  363 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/misc/fsl_otp.h |  126 +++++++++++++++++
 4 files changed, 504 insertions(+)
 create mode 100644 drivers/misc/fsl_otp.c
 create mode 100644 drivers/misc/fsl_otp.h

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 8dacd4c..0740312 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -528,6 +528,20 @@ config SRAM
 	  the genalloc API. It is supposed to be used for small on-chip SRAM
 	  areas found on many SoCs.
 
+config FSL_OTP
+	tristate "Freescale On-Chip OTP Memory Support"
+	depends on SOC_IMX23 || SOC_IMX28
+	default n
+	help
+		If you say Y here, you will get support for a SysFS interface for
+		the One Time Programmable memory pages that are stored on the
+		iMX23/28 processor.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called fsl_otp.
+
+	  If unsure, it is safe to say N.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index c235d5b..e622e01 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -53,3 +53,4 @@ obj-$(CONFIG_INTEL_MEI)		+= mei/
 obj-$(CONFIG_VMWARE_VMCI)	+= vmw_vmci/
 obj-$(CONFIG_LATTICE_ECP3_CONFIG)	+= lattice-ecp3-config.o
 obj-$(CONFIG_SRAM)		+= sram.o
+obj-$(CONFIG_FSL_OTP)           += fsl_otp.o
diff --git a/drivers/misc/fsl_otp.c b/drivers/misc/fsl_otp.c
new file mode 100644
index 0000000..7ae6ea0
--- /dev/null
+++ b/drivers/misc/fsl_otp.c
@@ -0,0 +1,363 @@
+/*
+ * Freescale On-Chip OTP driver
+ *
+ * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Huang Shijie <b32955@freescale.com>
+ *
+ * Ported to 3.x by Christoph G. Baumann <cgb@debian.org>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#include <linux/kobject.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/fcntl.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
+#include "fsl_otp.h"
+
+static DEFINE_MUTEX(otp_mutex);
+static struct kobject *otp_kobj;
+static struct attribute **attrs;
+static struct kobj_attribute *kattr;
+static struct attribute_group attr_group;
+static unsigned long otp_hclk_saved;
+static u32 otp_voltage_saved;
+static resource_size_t otp_base_address;
+struct regulator *regu;
+
+static struct fsl_otp_data otp_data = {
+	.fuse_name	= (char **)bank_reg_desc,
+	.regulator_name	= "vddio-sd0",
+	.fuse_num	= MXS_OTP_BANKS * MXS_OTP_BANK_ITEMS,
+};
+
+
+/* forward declaration */
+static int otp_wait_busy(u32 flags);
+
+/* open the bank for the imx23/imx28 */
+static int otp_read_prepare(void)
+{
+	int r;
+
+	/* [1] set the HCLK */
+	/* [2] check BUSY and ERROR bit */
+	r = otp_wait_busy(0);
+	if (r < 0)
+		goto error;
+
+	/* [3] open bank */
+	__raw_writel(BM_OCOTP_CTRL_RD_BANK_OPEN,
+		REGS_OCOTP_BASE + HW_OCOTP_CTRL_SET);
+	udelay(10);
+
+	/* [4] wait for BUSY */
+	r = otp_wait_busy(0);
+	return 0;
+error:
+	return r;
+}
+
+static int otp_read_post(void)
+{
+	/* [5] close bank */
+	__raw_writel(BM_OCOTP_CTRL_RD_BANK_OPEN,
+		REGS_OCOTP_BASE + HW_OCOTP_CTRL_CLR);
+	return 0;
+}
+
+static int otp_write_prepare(void)
+{
+	struct clk *hclk;
+	int err = 0;
+
+	/* [1] HCLK to 24MHz. */
+	hclk = clk_get_sys("hbus", NULL);
+	if (IS_ERR(hclk)) {
+		err = PTR_ERR(hclk);
+		goto out;
+	}
+	/*
+	   WARNING  ACHTUNG  UWAGA
+
+	   the code below changes HCLK clock rate to 24M. This is
+	   required to write OTP bits (7.2.2 in STMP378x Target
+	   Specification), and might affect LCD operation, for example.
+	   Moreover, this hacky code changes VDDIO to 2.8V; and resto-
+	   res it only on otp_close(). This may affect... anything.
+
+	   You are warned now.
+	 */
+	otp_hclk_saved = clk_get_rate(hclk);
+	clk_set_rate(hclk, 24000000);
+
+	/* [2] The voltage is set to 2.8V */
+	regu = regulator_get(NULL, otp_data.regulator_name);
+	otp_voltage_saved = regulator_get_voltage(regu);
+	regulator_set_voltage(regu, 2800000, 2800000);
+
+	/* [3] wait for BUSY and ERROR */
+	err = otp_wait_busy(BM_OCOTP_CTRL_RD_BANK_OPEN);
+out:
+	return err;
+}
+
+static int otp_write_post(void)
+{
+	struct clk *hclk;
+
+	hclk = clk_get_sys("hbus", NULL);
+	if (IS_ERR(hclk))
+		return PTR_ERR(hclk);
+
+	/* restore the clock and voltage */
+	clk_set_rate(hclk, otp_hclk_saved);
+	regulator_set_voltage(regu, otp_voltage_saved, otp_voltage_saved);
+	otp_wait_busy(0);
+
+	/* reset */
+	__raw_writel(BM_OCOTP_CTRL_RELOAD_SHADOWS,
+			REGS_OCOTP_BASE + HW_OCOTP_CTRL_SET);
+	otp_wait_busy(BM_OCOTP_CTRL_RELOAD_SHADOWS);
+	return 0;
+}
+
+static int __init map_ocotp_addr(struct platform_device *pdev)
+{
+	return 0;
+}
+static void unmap_ocotp_addr(void)
+{
+}
+
+static inline unsigned int get_reg_index(struct kobj_attribute *tmp)
+{
+	return tmp - kattr;
+}
+
+static int otp_wait_busy(u32 flags)
+{
+	int count;
+	u32 c;
+
+	for (count = 10000; count >= 0; count--) {
+		c = __raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CTRL);
+		if (!(c & (BM_OCOTP_CTRL_BUSY | BM_OCOTP_CTRL_ERROR | flags)))
+			break;
+		cpu_relax();
+	}
+
+	if (count < 0)
+		return -ETIMEDOUT;
+	return 0;
+}
+
+static ssize_t otp_show(struct kobject *kobj, struct kobj_attribute *attr,
+		      char *buf)
+{
+	unsigned int index = get_reg_index(attr);
+	u32 value = 0;
+
+	/* sanity check */
+	if (index >= otp_data.fuse_num)
+		return 0;
+
+	mutex_lock(&otp_mutex);
+
+	if (otp_read_prepare()) {
+		mutex_unlock(&otp_mutex);
+		return 0;
+	}
+	value = __raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CUST_N(index));
+	otp_read_post();
+
+	mutex_unlock(&otp_mutex);
+	return sprintf(buf, "0x%x\n", value);
+}
+
+static int otp_write_bits(int addr, u32 data, u32 magic)
+{
+	u32 c; /* for control register */
+
+	/* init the control register */
+	c = __raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CTRL);
+	c &= ~BM_OCOTP_CTRL_ADDR;
+	c |= BF(addr, OCOTP_CTRL_ADDR);
+	c |= BF(magic, OCOTP_CTRL_WR_UNLOCK);
+	__raw_writel(c, REGS_OCOTP_BASE + HW_OCOTP_CTRL);
+
+	/* init the data register */
+	__raw_writel(data, REGS_OCOTP_BASE + HW_OCOTP_DATA);
+	otp_wait_busy(0);
+
+	mdelay(2); /* Write Postamble */
+	return 0;
+}
+
+static ssize_t otp_store(struct kobject *kobj, struct kobj_attribute *attr,
+		       const char *buf, size_t count)
+{
+	unsigned int index = get_reg_index(attr);
+	int value;
+
+	/* sanity check */
+	if (index >= otp_data.fuse_num)
+		return 0;
+
+	sscanf(buf, "0x%x", &value);
+
+	mutex_lock(&otp_mutex);
+	if (otp_write_prepare()) {
+		mutex_unlock(&otp_mutex);
+		return 0;
+	}
+	otp_write_bits(index, value, 0x3e77);
+	otp_write_post();
+	mutex_unlock(&otp_mutex);
+
+	return count;
+}
+
+static void free_otp_attr(void)
+{
+	kfree(attrs);
+	attrs = NULL;
+
+	kfree(kattr);
+	kattr = NULL;
+}
+
+static int alloc_otp_attr(void)
+{
+	int i;
+
+	/* The last one is NULL, which is used to detect the end */
+	attrs = kzalloc((otp_data.fuse_num + 1) * sizeof(attrs[0]),
+			GFP_KERNEL);
+	kattr = kzalloc(otp_data.fuse_num * sizeof(struct kobj_attribute),
+			GFP_KERNEL);
+
+	if (!attrs || !kattr)
+		goto error_out;
+
+	for (i = 0; i < otp_data.fuse_num; i++) {
+		kattr[i].attr.name = otp_data.fuse_name[i];
+		kattr[i].attr.mode = 0600;
+		kattr[i].show  = otp_show;
+		kattr[i].store = otp_store;
+		attrs[i] = &kattr[i].attr;
+		sysfs_attr_init(attrs[i]);
+	}
+	memset(&attr_group, 0, sizeof(attr_group));
+	attr_group.attrs = attrs;
+	return 0;
+
+error_out:
+	free_otp_attr();
+	return -ENOMEM;
+}
+
+static int fsl_otp_probe(struct platform_device *pdev)
+{
+	int retval;
+	struct fsl_otp_data *pdata;
+
+	/* get device base address */
+	otp_base_address = pdev->resource->start;
+	dev_info(&pdev->dev, "i.MX23/28 OCOTP at %p\n", otp_base_address);
+
+	pdata = &otp_data;
+	if (pdev->dev.platform_data == NULL)
+		pdev->dev.platform_data = &otp_data;
+
+	retval = alloc_otp_attr();
+	if (retval)
+		return retval;
+
+	retval = map_ocotp_addr(pdev);
+	if (retval)
+		goto error;
+
+	otp_kobj = kobject_create_and_add("fsl_otp", NULL);
+	if (!otp_kobj) {
+		retval = -ENOMEM;
+		goto error;
+	}
+
+	retval = sysfs_create_group(otp_kobj, &attr_group);
+	if (retval)
+		goto error;
+
+	mutex_init(&otp_mutex);
+	return 0;
+error:
+	kobject_put(otp_kobj);
+	otp_kobj = NULL;
+	free_otp_attr();
+	unmap_ocotp_addr();
+	return retval;
+}
+
+static int otp_remove(struct platform_device *pdev)
+{
+	kobject_put(otp_kobj);
+	otp_kobj = NULL;
+
+	free_otp_attr();
+	unmap_ocotp_addr();
+	return 0;
+}
+
+static const struct of_device_id mxs_otp_dt_ids[] = {
+	{ .compatible = "fsl,ocotp", .data = NULL, },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxs_otp_dt_ids);
+
+static struct platform_driver ocotp_driver = {
+	.probe		= fsl_otp_probe,
+	.remove		= otp_remove,
+	.driver		= {
+		.name   = "ocotp",
+		.owner	= THIS_MODULE,
+		.of_match_table = mxs_otp_dt_ids,
+	},
+};
+
+static int __init fsl_otp_init(void)
+{
+	return platform_driver_register(&ocotp_driver);
+}
+
+static void __exit fsl_otp_exit(void)
+{
+	platform_driver_unregister(&ocotp_driver);
+}
+module_init(fsl_otp_init);
+module_exit(fsl_otp_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Christoph G. Baumann <cgb@debian.org>");
+MODULE_DESCRIPTION("driver for OCOTP in i.MX23 and i.MX28");
diff --git a/drivers/misc/fsl_otp.h b/drivers/misc/fsl_otp.h
new file mode 100644
index 0000000..9449f94
--- /dev/null
+++ b/drivers/misc/fsl_otp.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Ported to 3.7 by Christoph G. Baumann <cgb@debian.org>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef __FREESCALE_OTP__
+#define __FREESCALE_OTP__
+
+
+/* IMX23 and IMX28 share most of the defination ========================= */
+#if (defined(CONFIG_SOC_IMX23) || defined(CONFIG_SOC_IMX28))
+
+#if defined(CONFIG_SOC_IMX28) && defined(CONFIG_SOC_IMX23)
+#undef CONFIG_SOC_IMX23
+#endif
+
+
+#define OCOTP_PHYS_ADDR         otp_base_address
+#define REGS_OCOTP_BASE		(MXS_IO_ADDRESS(OCOTP_PHYS_ADDR))
+#define BF(value, field)	(((value) << BP_##field) & BM_##field)
+
+/* MXS IO mappings */
+
+/*
+ * It maps the whole address space to [0xf4000000, 0xf50fffff].
+ *
+ *	OCRAM	0x00000000+0x020000	->	0xf4000000+0x020000
+ *	IO	0x80000000+0x100000	->	0xf5000000+0x100000
+ */
+#define MXS_IO_P2V(x)	(0xf4000000 +					\
+			(((x) & 0x80000000) >> 7) +			\
+			(((x) & 0x000fffff)))
+
+#define MXS_IO_ADDRESS(x)	IOMEM(MXS_IO_P2V(x))
+
+
+/* OCOTP registers and bits */
+#define HW_OCOTP_CTRL		(0x00000000)
+#define HW_OCOTP_CTRL_SET	(0x00000004)
+#define HW_OCOTP_CTRL_CLR	(0x00000008)
+#define HW_OCOTP_CTRL_TOG	(0x0000000c)
+
+#define BM_OCOTP_CTRL_RELOAD_SHADOWS	0x00002000
+#define BM_OCOTP_CTRL_RD_BANK_OPEN	0x00001000
+#define BM_OCOTP_CTRL_ERROR		0x00000200
+#define BM_OCOTP_CTRL_BUSY		0x00000100
+#define BP_OCOTP_CTRL_ADDR		0
+#if defined(CONFIG_SOC_IMX28)
+#define BM_OCOTP_CTRL_ADDR		0x0000003F
+#endif
+#if defined(CONFIG_SOC_IMX23)
+#define BM_OCOTP_CTRL_ADDR		0x0000001F
+#endif
+#define BP_OCOTP_CTRL_WR_UNLOCK		16
+#define BM_OCOTP_CTRL_WR_UNLOCK		0xFFFF0000
+
+#define HW_OCOTP_DATA	(0x00000010)
+
+#define HW_OCOTP_CUST_N(n)	(0x00000020 + (n) * 0x10)
+#define BP_OCOTP_CUST_N_BITS	0
+#define BM_OCOTP_CUST_N_BITS	0xFFFFFFFF
+#define BF_OCOTP_CUST_N_BITS(v)	(v)
+
+
+
+#if defined(CONFIG_SOC_IMX28)
+/* Building up eight registers's names of a bank */
+#define MXS_OTP_BANK(a, b, c, d, e, f, g, h)	\
+	{\
+	("HW_OCOTP_"#a), ("HW_OCOTP_"#b), ("HW_OCOTP_"#c), ("HW_OCOTP_"#d), \
+	("HW_OCOTP_"#e), ("HW_OCOTP_"#f), ("HW_OCOTP_"#g), ("HW_OCOTP_"#h) \
+	}
+
+#define MXS_OTP_BANKS		(5)
+#define MXS_OTP_BANK_ITEMS	(8)
+static const char *bank_reg_desc[MXS_OTP_BANKS][MXS_OTP_BANK_ITEMS] = {
+MXS_OTP_BANK(CUST0, CUST1, CUST2, CUST3, CRYPTO0, CRYPTO1, CRYPTO2, CRYPTO3),
+MXS_OTP_BANK(HWCAP0, HWCAP1, HWCAP2, HWCAP3, HWCAP4, HWCAP5, SWCAP, CUSTCAP),
+MXS_OTP_BANK(LOCK, OPS0, OPS1, OPS2, OPS3, UN0, UN1, UN2),
+MXS_OTP_BANK(ROM0, ROM1, ROM2, ROM3, ROM4, ROM5, ROM6, ROM7),
+MXS_OTP_BANK(SRK0, SRK1, SRK2, SRK3, SRK4, SRK5, SRK6, SRK7),
+};
+#endif /* if defined(CONFIG_SOC_IMX28) */
+
+
+#if defined(CONFIG_SOC_IMX23)
+/* Building up eight registers's names of a bank */
+#define MXS_OTP_BANK(a, b, c, d, e, f, g, h)	\
+	{\
+	("HW_OCOTP_"#a), ("HW_OCOTP_"#b), ("HW_OCOTP_"#c), ("HW_OCOTP_"#d), \
+	("HW_OCOTP_"#e), ("HW_OCOTP_"#f), ("HW_OCOTP_"#g), ("HW_OCOTP_"#h) \
+	}
+
+#define MXS_OTP_BANKS		(4)
+#define MXS_OTP_BANK_ITEMS	(8)
+static const char *bank_reg_desc[MXS_OTP_BANKS][MXS_OTP_BANK_ITEMS] = {
+MXS_OTP_BANK(CUST0, CUST1, CUST2, CUST3, CRYPTO0, CRYPTO1, CRYPTO2, CRYPTO3),
+MXS_OTP_BANK(HWCAP0, HWCAP1, HWCAP2, HWCAP3, HWCAP4, HWCAP5, SWCAP, CUSTCAP),
+MXS_OTP_BANK(LOCK, OPS0, OPS1, OPS2, OPS3, UN0, UN1, UN2),
+MXS_OTP_BANK(ROM0, ROM1, ROM2, ROM3, ROM4, ROM5, ROM6, ROM7),
+};
+
+#endif/* if defined(CONFIG_SOC_IMX23) */
+
+struct fsl_otp_data {
+	char		**fuse_name;
+	char		*regulator_name;
+	unsigned int	fuse_num;
+};
+
+#endif /* (defined(CONFIG_SOC_IMX23) || defined(CONFIG_SOC_IMX28)) */
+#endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 3/3] mxs: added driver for OCOTP in i.MX23 and i.MX28
  2013-07-17 16:27   ` [PATCH v2 3/3] mxs: added driver for OCOTP in i.MX23 and i.MX28 Christoph G. Baumann
@ 2013-07-17 19:26     ` Sascha Hauer
  2013-07-17 21:43       ` Christoph G. Baumann
  0 siblings, 1 reply; 17+ messages in thread
From: Sascha Hauer @ 2013-07-17 19:26 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Christoph,

Several comments inline.

On Wed, Jul 17, 2013 at 06:27:40PM +0200, Christoph G. Baumann wrote:
> From: "Christoph G. Baumann" <cb@sgoc.de>
> 
> Signed-off-by: "Christoph G. Baumann" <cb@sgoc.de>
> ---
>  drivers/misc/Kconfig   |   14 ++
>  drivers/misc/Makefile  |    1 +
>  drivers/misc/fsl_otp.c |  363 ++++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/misc/fsl_otp.h |  126 +++++++++++++++++
>  4 files changed, 504 insertions(+)
>  create mode 100644 drivers/misc/fsl_otp.c
>  create mode 100644 drivers/misc/fsl_otp.h
> 
> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
> index 8dacd4c..0740312 100644
> --- a/drivers/misc/Kconfig
> +++ b/drivers/misc/Kconfig
> @@ -528,6 +528,20 @@ config SRAM
>  	  the genalloc API. It is supposed to be used for small on-chip SRAM
>  	  areas found on many SoCs.
>  
> +config FSL_OTP
> +	tristate "Freescale On-Chip OTP Memory Support"
> +	depends on SOC_IMX23 || SOC_IMX28
> +	default n

default n is the default. You can drop this.

> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
> + */

Please drop the address. It's wrong already.

> +static DEFINE_MUTEX(otp_mutex);
> +static struct kobject *otp_kobj;
> +static struct attribute **attrs;
> +static struct kobj_attribute *kattr;
> +static struct attribute_group attr_group;
> +static unsigned long otp_hclk_saved;
> +static u32 otp_voltage_saved;
> +static resource_size_t otp_base_address;
> +struct regulator *regu;

Collect your driver data in a struct and pass it around in functions
calls. No need to limit this driver to a single instance.

> +/* forward declaration */

Who would have guessed that? Drop this, it contains no information.

> +static int otp_wait_busy(u32 flags);

You should reorder the functions so that forward declarations are not
necessary.

> +
> +/* open the bank for the imx23/imx28 */
> +static int otp_read_prepare(void)
> +{
> +	int r;
> +
> +	/* [1] set the HCLK */
> +	/* [2] check BUSY and ERROR bit */
> +	r = otp_wait_busy(0);
> +	if (r < 0)
> +		goto error;
> +
> +	/* [3] open bank */
> +	__raw_writel(BM_OCOTP_CTRL_RD_BANK_OPEN,
> +		REGS_OCOTP_BASE + HW_OCOTP_CTRL_SET);
> +	udelay(10);
> +
> +	/* [4] wait for BUSY */
> +	r = otp_wait_busy(0);
> +	return 0;
> +error:
> +	return r;
> +}
> +
> +static int otp_read_post(void)
> +{
> +	/* [5] close bank */
> +	__raw_writel(BM_OCOTP_CTRL_RD_BANK_OPEN,
> +		REGS_OCOTP_BASE + HW_OCOTP_CTRL_CLR);
> +	return 0;
> +}
> +
> +static int otp_write_prepare(void)
> +{
> +	struct clk *hclk;
> +	int err = 0;
> +
> +	/* [1] HCLK to 24MHz. */
> +	hclk = clk_get_sys("hbus", NULL);

This is a driver, so you should use regular clk_get, not clk_get_sys.
Besides, this has to be done during probe. clk_get takes a reference to
the clock which has to be released.

> +	if (IS_ERR(hclk)) {
> +		err = PTR_ERR(hclk);
> +		goto out;
> +	}
> +	/*
> +	   WARNING  ACHTUNG  UWAGA
> +
> +	   the code below changes HCLK clock rate to 24M. This is
> +	   required to write OTP bits (7.2.2 in STMP378x Target
> +	   Specification), and might affect LCD operation, for example.
> +	   Moreover, this hacky code changes VDDIO to 2.8V; and resto-
> +	   res it only on otp_close(). This may affect... anything.
> +
> +	   You are warned now.
> +	 */
> +	otp_hclk_saved = clk_get_rate(hclk);
> +	clk_set_rate(hclk, 24000000);

You should check the return value.

> +
> +	/* [2] The voltage is set to 2.8V */
> +	regu = regulator_get(NULL, otp_data.regulator_name);

Same as with clk_get. Do it during probe time.

> +	otp_voltage_saved = regulator_get_voltage(regu);
> +	regulator_set_voltage(regu, 2800000, 2800000);

Check the return value.

> +
> +	/* [3] wait for BUSY and ERROR */
> +	err = otp_wait_busy(BM_OCOTP_CTRL_RD_BANK_OPEN);
> +out:
> +	return err;
> +}
> +
> +static int otp_write_post(void)
> +{
> +	struct clk *hclk;
> +
> +	hclk = clk_get_sys("hbus", NULL);
> +	if (IS_ERR(hclk))
> +		return PTR_ERR(hclk);
> +
> +	/* restore the clock and voltage */
> +	clk_set_rate(hclk, otp_hclk_saved);
> +	regulator_set_voltage(regu, otp_voltage_saved, otp_voltage_saved);
> +	otp_wait_busy(0);
> +
> +	/* reset */
> +	__raw_writel(BM_OCOTP_CTRL_RELOAD_SHADOWS,
> +			REGS_OCOTP_BASE + HW_OCOTP_CTRL_SET);
> +	otp_wait_busy(BM_OCOTP_CTRL_RELOAD_SHADOWS);
> +	return 0;
> +}
> +
> +static int __init map_ocotp_addr(struct platform_device *pdev)
> +{
> +	return 0;
> +}

What's this? Drop this.

> +static void unmap_ocotp_addr(void)
> +{
> +}

ditto

> +
> +static inline unsigned int get_reg_index(struct kobj_attribute *tmp)
> +{
> +	return tmp - kattr;
> +}
> +
> +static int otp_wait_busy(u32 flags)
> +{
> +	int count;
> +	u32 c;
> +
> +	for (count = 10000; count >= 0; count--) {
> +		c = __raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CTRL);
> +		if (!(c & (BM_OCOTP_CTRL_BUSY | BM_OCOTP_CTRL_ERROR | flags)))
> +			break;
> +		cpu_relax();
> +	}
> +
> +	if (count < 0)
> +		return -ETIMEDOUT;
> +	return 0;
> +}
> +
> +static ssize_t otp_show(struct kobject *kobj, struct kobj_attribute *attr,
> +		      char *buf)
> +{
> +	unsigned int index = get_reg_index(attr);
> +	u32 value = 0;
> +
> +	/* sanity check */
> +	if (index >= otp_data.fuse_num)
> +		return 0;
> +
> +	mutex_lock(&otp_mutex);
> +
> +	if (otp_read_prepare()) {
> +		mutex_unlock(&otp_mutex);
> +		return 0;
> +	}
> +	value = __raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CUST_N(index));
> +	otp_read_post();
> +
> +	mutex_unlock(&otp_mutex);
> +	return sprintf(buf, "0x%x\n", value);
> +}
> +
> +static int otp_write_bits(int addr, u32 data, u32 magic)
> +{
> +	u32 c; /* for control register */
> +
> +	/* init the control register */
> +	c = __raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CTRL);
> +	c &= ~BM_OCOTP_CTRL_ADDR;
> +	c |= BF(addr, OCOTP_CTRL_ADDR);
> +	c |= BF(magic, OCOTP_CTRL_WR_UNLOCK);
> +	__raw_writel(c, REGS_OCOTP_BASE + HW_OCOTP_CTRL);
> +
> +	/* init the data register */
> +	__raw_writel(data, REGS_OCOTP_BASE + HW_OCOTP_DATA);
> +	otp_wait_busy(0);
> +
> +	mdelay(2); /* Write Postamble */
> +	return 0;
> +}
> +
> +static ssize_t otp_store(struct kobject *kobj, struct kobj_attribute *attr,
> +		       const char *buf, size_t count)
> +{
> +	unsigned int index = get_reg_index(attr);
> +	int value;
> +
> +	/* sanity check */
> +	if (index >= otp_data.fuse_num)
> +		return 0;
> +
> +	sscanf(buf, "0x%x", &value);
> +
> +	mutex_lock(&otp_mutex);
> +	if (otp_write_prepare()) {
> +		mutex_unlock(&otp_mutex);
> +		return 0;
> +	}
> +	otp_write_bits(index, value, 0x3e77);
> +	otp_write_post();
> +	mutex_unlock(&otp_mutex);
> +
> +	return count;
> +}
> +
> +static void free_otp_attr(void)
> +{
> +	kfree(attrs);
> +	attrs = NULL;
> +
> +	kfree(kattr);
> +	kattr = NULL;
> +}
> +
> +static int alloc_otp_attr(void)
> +{
> +	int i;
> +
> +	/* The last one is NULL, which is used to detect the end */
> +	attrs = kzalloc((otp_data.fuse_num + 1) * sizeof(attrs[0]),
> +			GFP_KERNEL);
> +	kattr = kzalloc(otp_data.fuse_num * sizeof(struct kobj_attribute),
> +			GFP_KERNEL);
> +
> +	if (!attrs || !kattr)
> +		goto error_out;
> +
> +	for (i = 0; i < otp_data.fuse_num; i++) {
> +		kattr[i].attr.name = otp_data.fuse_name[i];
> +		kattr[i].attr.mode = 0600;
> +		kattr[i].show  = otp_show;
> +		kattr[i].store = otp_store;
> +		attrs[i] = &kattr[i].attr;
> +		sysfs_attr_init(attrs[i]);
> +	}
> +	memset(&attr_group, 0, sizeof(attr_group));
> +	attr_group.attrs = attrs;
> +	return 0;
> +
> +error_out:
> +	free_otp_attr();
> +	return -ENOMEM;
> +}
> +
> +static int fsl_otp_probe(struct platform_device *pdev)
> +{
> +	int retval;
> +	struct fsl_otp_data *pdata;
> +
> +	/* get device base address */
> +	otp_base_address = pdev->resource->start;
> +	dev_info(&pdev->dev, "i.MX23/28 OCOTP at %p\n", otp_base_address);
> +
> +	pdata = &otp_data;
> +	if (pdev->dev.platform_data == NULL)
> +		pdev->dev.platform_data = &otp_data;

You shouldn't manipulate the platform_data pointer in the driver.
platform_data contains data passed to the driver.

> +
> +	retval = alloc_otp_attr();
> +	if (retval)
> +		return retval;
> +
> +	retval = map_ocotp_addr(pdev);
> +	if (retval)
> +		goto error;
> +
> +	otp_kobj = kobject_create_and_add("fsl_otp", NULL);
> +	if (!otp_kobj) {
> +		retval = -ENOMEM;
> +		goto error;
> +	}
> +
> +	retval = sysfs_create_group(otp_kobj, &attr_group);
> +	if (retval)
> +		goto error;
> +
> +	mutex_init(&otp_mutex);
> +	return 0;
> +error:
> +	kobject_put(otp_kobj);
> +	otp_kobj = NULL;
> +	free_otp_attr();
> +	unmap_ocotp_addr();
> +	return retval;
> +}
> +
> +static int otp_remove(struct platform_device *pdev)
> +{
> +	kobject_put(otp_kobj);
> +	otp_kobj = NULL;
> +
> +	free_otp_attr();
> +	unmap_ocotp_addr();
> +	return 0;
> +}
> +
> +static const struct of_device_id mxs_otp_dt_ids[] = {
> +	{ .compatible = "fsl,ocotp", .data = NULL, },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, mxs_otp_dt_ids);
> +
> +static struct platform_driver ocotp_driver = {
> +	.probe		= fsl_otp_probe,
> +	.remove		= otp_remove,
> +	.driver		= {
> +		.name   = "ocotp",
> +		.owner	= THIS_MODULE,
> +		.of_match_table = mxs_otp_dt_ids,
> +	},
> +};
> +
> +static int __init fsl_otp_init(void)
> +{
> +	return platform_driver_register(&ocotp_driver);
> +}
> +
> +static void __exit fsl_otp_exit(void)
> +{
> +	platform_driver_unregister(&ocotp_driver);
> +}
> +module_init(fsl_otp_init);
> +module_exit(fsl_otp_exit);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Christoph G. Baumann <cgb@debian.org>");
> +MODULE_DESCRIPTION("driver for OCOTP in i.MX23 and i.MX28");
> diff --git a/drivers/misc/fsl_otp.h b/drivers/misc/fsl_otp.h
> new file mode 100644
> index 0000000..9449f94
> --- /dev/null
> +++ b/drivers/misc/fsl_otp.h
> @@ -0,0 +1,126 @@
> +/*
> + * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
> + *
> + * Ported to 3.7 by Christoph G. Baumann <cgb@debian.org>
> + *
> + * 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.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

Here's another address of the FSF. That's the reason for not including
it.

> + */
> +#ifndef __FREESCALE_OTP__
> +#define __FREESCALE_OTP__
> +
> +
> +/* IMX23 and IMX28 share most of the defination ========================= */
> +#if (defined(CONFIG_SOC_IMX23) || defined(CONFIG_SOC_IMX28))
> +
> +#if defined(CONFIG_SOC_IMX28) && defined(CONFIG_SOC_IMX23)
> +#undef CONFIG_SOC_IMX23
> +#endif

So if the kernel supports both i.MX23 and i.MX28 you choose to make the
driver work on i.MX28 only. You have to make this a runtime decision.
See some other driver how this can be made, for example
drivers/spi/spi-imx.c. Look for the usage of of_match_device().

> +
> +
> +#define OCOTP_PHYS_ADDR         otp_base_address
> +#define REGS_OCOTP_BASE		(MXS_IO_ADDRESS(OCOTP_PHYS_ADDR))

Drop this and use ioremap in the driver.

> +#define BF(value, field)	(((value) << BP_##field) & BM_##field)
> +
> +/* MXS IO mappings */
> +
> +/*
> + * It maps the whole address space to [0xf4000000, 0xf50fffff].
> + *
> + *	OCRAM	0x00000000+0x020000	->	0xf4000000+0x020000
> + *	IO	0x80000000+0x100000	->	0xf5000000+0x100000
> + */
> +#define MXS_IO_P2V(x)	(0xf4000000 +					\
> +			(((x) & 0x80000000) >> 7) +			\
> +			(((x) & 0x000fffff)))
> +
> +#define MXS_IO_ADDRESS(x)	IOMEM(MXS_IO_P2V(x))

This also shouldn't be in a driver.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v2 3/3] mxs: added driver for OCOTP in i.MX23 and i.MX28
  2013-07-17 19:26     ` Sascha Hauer
@ 2013-07-17 21:43       ` Christoph G. Baumann
  2013-07-18  6:36         ` Sascha Hauer
  0 siblings, 1 reply; 17+ messages in thread
From: Christoph G. Baumann @ 2013-07-17 21:43 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Sascha,

thanks for your input. I must admit that I didn't do a thorough review of the
FSL code...


> Sascha Hauer <s.hauer@pengutronix.de> hat am 17. Juli 2013 um 21:26
> geschrieben:
> [...]
> > +static DEFINE_MUTEX(otp_mutex);
> > +static struct kobject *otp_kobj;
> > +static struct attribute **attrs;
> > +static struct kobj_attribute *kattr;
> > +static struct attribute_group attr_group;
> > +static unsigned long otp_hclk_saved;
> > +static u32 otp_voltage_saved;
> > +static resource_size_t otp_base_address;
> > +struct regulator *regu;
>
> Collect your driver data in a struct and pass it around in functions
> calls. No need to limit this driver to a single instance.

The OTP device is unique in the CPU and several instances i.e. potential
concurrent access is considered harmful. So I kept this construction
from FSL.


> > +static int otp_write_prepare(void)
> > +{
> > +? ? ?struct clk *hclk;
> > +? ? ?int err = 0;
> > +
> > +? ? ?/* [1] HCLK to 24MHz. */
> > +? ? ?hclk = clk_get_sys("hbus", NULL);
>
> This is a driver, so you should use regular clk_get, not clk_get_sys.
> Besides, this has to be done during probe. clk_get takes a reference to
> the clock which has to be released.

As far as I remember testing clk_get didn't work in this place.
In the API doc I only found the warning:
"clk_get_sys should not be called from within interrupt context.".


Regards,
Christoph

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v2 3/3] mxs: added driver for OCOTP in i.MX23 and i.MX28
  2013-07-17 21:43       ` Christoph G. Baumann
@ 2013-07-18  6:36         ` Sascha Hauer
  2013-07-18 15:14           ` Christoph G. Baumann
  0 siblings, 1 reply; 17+ messages in thread
From: Sascha Hauer @ 2013-07-18  6:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jul 17, 2013 at 11:43:12PM +0200, Christoph G. Baumann wrote:
> Hello Sascha,
> 
> thanks for your input. I must admit that I didn't do a thorough review of the
> FSL code...
> 
> 
> > Sascha Hauer <s.hauer@pengutronix.de> hat am 17. Juli 2013 um 21:26
> > geschrieben:
> > [...]
> > > +static DEFINE_MUTEX(otp_mutex);
> > > +static struct kobject *otp_kobj;
> > > +static struct attribute **attrs;
> > > +static struct kobj_attribute *kattr;
> > > +static struct attribute_group attr_group;
> > > +static unsigned long otp_hclk_saved;
> > > +static u32 otp_voltage_saved;
> > > +static resource_size_t otp_base_address;
> > > +struct regulator *regu;
> >
> > Collect your driver data in a struct and pass it around in functions
> > calls. No need to limit this driver to a single instance.
> 
> The OTP device is unique in the CPU and several instances i.e. potential
> concurrent access is considered harmful. So I kept this construction
> from FSL.

Yes, this is single instance only in current SoCs. This is no reason
though to make the driver single instance capabable only. It's not
much work to change and it raises less eyebrows if it's properly
written.
In the end I never thought that there ever would be two instances of
the i.MX graphics subsystem (IPU). Now the i.MX6 has two of them...

> 
> 
> > > +static int otp_write_prepare(void)
> > > +{
> > > +? ? ?struct clk *hclk;
> > > +? ? ?int err = 0;
> > > +
> > > +? ? ?/* [1] HCLK to 24MHz. */
> > > +? ? ?hclk = clk_get_sys("hbus", NULL);
> >
> > This is a driver, so you should use regular clk_get, not clk_get_sys.
> > Besides, this has to be done during probe. clk_get takes a reference to
> > the clock which has to be released.
> 
> As far as I remember testing clk_get didn't work in this place.

That is because the clk_register_clkdev() in your other patch is wrong.

Look at the 'clocks' and 'clock-names' properties in the devicetree.
Also look at Documentation/devicetree/bindings/clock/imx28-clock.txt.

In short you have to add a clock to your devicetree node and then use
clk_get(). The struct device * passed to clk_get will make the bridge
between the device and the devicenode and the id argument will be the
same name as in the devicetree.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v2 3/3] mxs: added driver for OCOTP in i.MX23 and i.MX28
  2013-07-18  6:36         ` Sascha Hauer
@ 2013-07-18 15:14           ` Christoph G. Baumann
  0 siblings, 0 replies; 17+ messages in thread
From: Christoph G. Baumann @ 2013-07-18 15:14 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Sascha,

unfortunately I don't have the time at the moment to further fix the FSL code.
Maybe someone else feels inclined?


Regards
Christoph

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2013-07-18 15:14 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-07-03 12:39 [PATCH 0/3] Added support for On Chip OTP in i.MX23/28 Christoph G. Baumann
2013-07-03 12:39 ` [PATCH 1/3] " Christoph G. Baumann
2013-07-05  8:03   ` Maxime Ripard
2013-07-03 12:39 ` [PATCH 2/3] " Christoph G. Baumann
2013-07-05  8:08   ` Maxime Ripard
2013-07-03 12:39 ` [PATCH 3/3] " Christoph G. Baumann
2013-07-05  8:14   ` Maxime Ripard
2013-07-05  7:38 ` [PATCH 0/3] " Maxime Ripard
2013-07-07 21:19   ` Christoph G. Baumann
2013-07-17 16:27 ` [PATCH v2 0/3] mxs: add driver for On Chip OTP Christoph G. Baumann
2013-07-17 16:27   ` [PATCH v2 1/3] mxs: enable ocotp in device tree Christoph G. Baumann
2013-07-17 16:27   ` [PATCH v2 2/3] mxs: register clkdev "hbus" as it is required by OCOTP Christoph G. Baumann
2013-07-17 16:27   ` [PATCH v2 3/3] mxs: added driver for OCOTP in i.MX23 and i.MX28 Christoph G. Baumann
2013-07-17 19:26     ` Sascha Hauer
2013-07-17 21:43       ` Christoph G. Baumann
2013-07-18  6:36         ` Sascha Hauer
2013-07-18 15:14           ` Christoph G. Baumann

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.