diff mbox

[09/10] mtd: devices: Add driver for memory mapped NVRAM on FPC

Message ID 1475853451-22121-10-git-send-email-pantelis.antoniou@konsulko.com
State Not Applicable
Headers show

Commit Message

Pantelis Antoniou Oct. 7, 2016, 3:17 p.m. UTC
From: JawaharBalaji Thirumalaisamy <jawaharb@juniper.net>

Add MTD driver for NVRAM on Juniper Gladiator FPC PMB. This driver uses
indirect memory-mapped access facilitated by bootcpld. Requires
cpld_ver >= 0XC6 and DT support.

Signed-off-by: Georgi Vlaev <gvlaev@juniper.net>
Signed-off-by: JawaharBalaji Thirumalaisamy <jawaharb@juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
---
 drivers/mtd/devices/Kconfig         |  11 +++
 drivers/mtd/devices/Makefile        |   1 +
 drivers/mtd/devices/jnx_pmb_nvram.c | 191 ++++++++++++++++++++++++++++++++++++
 3 files changed, 203 insertions(+)
 create mode 100644 drivers/mtd/devices/jnx_pmb_nvram.c
diff mbox

Patch

diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index 58329d2..d4255fb 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -144,6 +144,17 @@  config MTD_LART
 	  not need any mapping/chip driver for LART. This one does it all
 	  for you, so go disable all of those if you enabled some of them (:
 
+config JNX_PMB_NVRAM
+	tristate "Juniper FPC PMB NVRAM Driver"
+	depends on (PTXPMB_COMMON || JNX_PTX_NGPMB)
+	default y if (PTXPMB_COMMON || JNX_PTX_NGPMB)
+	help
+	  This driver adds support for NVRAM on Gladiator 3T FPC which is connected
+	  to the BOOTCPLD (cpld_version >= C6).
+
+	  This driver can also be built as a module. When it is so the name of
+	  the module is ngpmb-nvram.
+
 config MTD_MTDRAM
 	tristate "Test driver using RAM"
 	help
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index 7912d3a..b407c5fc 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -18,5 +18,6 @@  obj-$(CONFIG_MTD_BCM47XXSFLASH)	+= bcm47xxsflash.o
 obj-$(CONFIG_MTD_ST_SPI_FSM)    += st_spi_fsm.o
 obj-$(CONFIG_MTD_POWERNV_FLASH)	+= powernv_flash.o
 
+obj-$(CONFIG_JNX_PMB_NVRAM)     += jnx_pmb_nvram.o
 
 CFLAGS_docg3.o			+= -I$(src)
diff --git a/drivers/mtd/devices/jnx_pmb_nvram.c b/drivers/mtd/devices/jnx_pmb_nvram.c
new file mode 100644
index 0000000..8a1e812
--- /dev/null
+++ b/drivers/mtd/devices/jnx_pmb_nvram.c
@@ -0,0 +1,191 @@ 
+/*
+ * Juniper Networks PTX1K RCB I2CS Boot FPGA MTD driver
+ * FPGA upgrades of the Spartan3AN/XC3S700 based I2CS.
+ *
+ * Copyright (C) 2015 Juniper Networks. All rights reserved.
+ * Author:	JawaharBalaji Thirumalaisamy <jawaharb@juniper.net>
+ *
+ * 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.
+ */
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/delay.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mfd/ptxpmb_cpld.h>
+
+struct nvram_mtd {
+	void __iomem *base;
+	struct device *dev;
+	struct mtd_info mtd;
+	struct mutex lock;
+};
+
+
+static int ram_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	struct nvram_mtd *nvram = container_of(mtd, struct nvram_mtd, mtd);
+
+	memset((char *)nvram->base + instr->addr, 0xff, instr->len);
+	instr->state = MTD_ERASE_DONE;
+	mtd_erase_callback(instr);
+	return 0;
+}
+
+static int ram_point(struct mtd_info *mtd, loff_t from, size_t len,
+		     size_t *retlen, void **virt, resource_size_t *phys)
+{
+	struct nvram_mtd *nvram = container_of(mtd, struct nvram_mtd, mtd);
+
+	virt = nvram->base + from;
+	*retlen = len;
+	return 0;
+}
+
+static int ram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
+{
+	return 0;
+}
+
+static int ram_read(struct mtd_info *mtd, loff_t from, size_t len,
+		    size_t *retlen, u_char *buf)
+{
+	struct nvram_mtd *nvram = container_of(mtd, struct nvram_mtd, mtd);
+
+	memcpy(buf, nvram->base + from, len);
+	*retlen = len;
+	return 0;
+}
+
+static int ram_write(struct mtd_info *mtd, loff_t to, size_t len,
+		     size_t *retlen, const u_char *buf)
+{
+	struct nvram_mtd *nvram = container_of(mtd, struct nvram_mtd, mtd);
+
+	memcpy((char *)nvram->base + to, buf, len);
+	*retlen = len;
+	return 0;
+}
+
+int nvram_init_mtd_parse(struct platform_device *pdev, struct mtd_info *mtd)
+{
+	struct mtd_part_parser_data ppdata = {};
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	mtd->name = dev_name(dev);
+	mtd->type = MTD_RAM;
+	mtd->flags = MTD_CAP_RAM;
+	mtd->size = 0xFF00;
+	mtd->writesize = 1;
+	mtd->writebufsize = 64; /* Mimic CFI NOR flashes */
+	mtd->erasesize = 0x1000;
+	mtd->owner = THIS_MODULE;
+	mtd->_erase = ram_erase;
+	mtd->_point = ram_point;
+	mtd->_unpoint = ram_unpoint;
+	mtd->_read = ram_read;
+	mtd->_write = ram_write;
+	mtd->_panic_write = ram_write;
+
+	ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
+	if (ret) {
+		dev_err(dev, "mtd_device_parse_register returned %d\n", ret);
+		return ret;
+	}
+	return ret;
+}
+
+static int nvram_probe(struct platform_device *pdev)
+{
+	struct pmb_boot_cpld __iomem *cpld;
+	struct nvram_mtd *nvram;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	int ret;
+
+	nvram = devm_kzalloc(dev, sizeof(*nvram), GFP_KERNEL);
+	if (!nvram)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "Failed to get nvram mmio resource\n");
+		return -ENOENT;
+	}
+	nvram->base = devm_ioremap_nocache(dev, res->start, resource_size(res));
+	if (!nvram->base) {
+		dev_err(dev, "Cannot map nvram\n");
+		return -EADDRNOTAVAIL;
+	}
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		/* Always assume that we need cpld control */
+		dev_err(dev, "Failed to get cpld mmio resource\n");
+		return -ENOENT;
+	}
+	cpld = devm_ioremap_nocache(dev, res->start, resource_size(res));
+	if (!cpld) {
+		dev_err(dev, "Cannot map cpld\n");
+		return -EADDRNOTAVAIL;
+	}
+	nvram->dev = dev;
+	platform_set_drvdata(pdev, nvram);
+	ret = nvram_init_mtd_parse(pdev, &nvram->mtd);
+	if (ret)
+		return ret;
+
+	if (READ_ONCE(cpld->cpld_rev) < 0xC6)
+		dev_info(dev, "NVRAM requires atleast cpld_rev 0XC6\n");
+
+	/* Initialize the window register in the cpld*/
+	WRITE_ONCE(cpld->board.nvram.nv_win, 0x0);
+	dev_info(dev, "Initialized window:0x%x\n",
+			READ_ONCE(cpld->board.nvram.nv_win));
+	return ret;
+}
+
+static int nvram_remove(struct platform_device *pdev)
+{
+	struct nvram_mtd *nvram;
+
+	nvram = platform_get_drvdata(pdev);
+	mtd_device_unregister(&nvram->mtd);
+	return 0;
+}
+
+static const struct of_device_id ngpmb_mtd_ids[] = {
+	{ .compatible = "jnx,ngpmb-nvram", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, ngpmb_mtd_ids);
+
+static struct platform_driver nvram_driver = {
+	.probe  = nvram_probe,
+	.remove = nvram_remove,
+	.driver = {
+		.name = "ngpmb-nvram",
+		.owner = THIS_MODULE,
+		.of_match_table = ngpmb_mtd_ids,
+	},
+};
+
+module_platform_driver(nvram_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("JawaharBalaji Thirumalaisamy <jawaharb@juniper.net>");
+MODULE_DESCRIPTION("EVO PTXPMB CPLD NVRAM Driver");
+MODULE_ALIAS("platform:ngpmb-nvram");