From: JawaharBalaji Thirumalaisamy <jawaharb@xxxxxxxxxxx> 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@xxxxxxxxxxx> Signed-off-by: JawaharBalaji Thirumalaisamy <jawaharb@xxxxxxxxxxx> [Ported from Juniper kernel] Signed-off-by: Pantelis Antoniou <pantelis.antoniou@xxxxxxxxxxxx> --- 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 --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@xxxxxxxxxxx> + * + * 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@xxxxxxxxxxx>"); +MODULE_DESCRIPTION("EVO PTXPMB CPLD NVRAM Driver"); +MODULE_ALIAS("platform:ngpmb-nvram"); -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-i2c" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html