From patchwork Sun Dec 1 06:26:17 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sergey Yanovich X-Patchwork-Id: 295638 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from casper.infradead.org (unknown [IPv6:2001:770:15f::2]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id E7D042C0090 for ; Sun, 1 Dec 2013 17:30:11 +1100 (EST) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Vn0Wn-0006eO-Po; Sun, 01 Dec 2013 06:29:15 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Vn0WO-0002P3-4T; Sun, 01 Dec 2013 06:28:48 +0000 Received: from mail-lb0-x22f.google.com ([2a00:1450:4010:c04::22f]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Vn0W1-0002MT-A3; Sun, 01 Dec 2013 06:28:26 +0000 Received: by mail-lb0-f175.google.com with SMTP id x18so7722039lbi.20 for ; Sat, 30 Nov 2013 22:28:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=RXWw85nPR8/koCvwykfNoEMv6JQ95qTGswHELiFrMwo=; b=l8iOo0Lf/4RLiLslh1FZThiVUGssyoTWNkZr50Ww0VB4NXhYC6VE4atsgAADn0PXfT cIcBLJrYxCwbVHh70WiZRAjmIhy64nVJTWcS8xgLtSb21tJz7LY8ynLFXv5FnxS5V7uT LCoHiRZXzIj8P5b8QsQ48REuHChpC0SJl4WTWN391P6hUWfpAHqhUjUT28yL21p7Ut5E lHyvAYCFQBwFwnn1NmLDtyP64jtPMhYRmPl36zptweQ7Tk53HNZnVN+UegYdksph5o2k 1OXke+cI1EaZpChi5mdKFARF4poQ0br34fFexA7ST5JkiqZbnq5UoYexpXSrqgj/awf7 tFFQ== X-Received: by 10.112.150.103 with SMTP id uh7mr59762lbb.34.1385879282872; Sat, 30 Nov 2013 22:28:02 -0800 (PST) Received: from host5.omatika.ru (0893675324.static.corbina.ru. [95.31.1.192]) by mx.google.com with ESMTPSA id e10sm82577921laa.6.2013.11.30.22.28.01 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 30 Nov 2013 22:28:02 -0800 (PST) From: Sergei Ianovich To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Subject: [PATCH 04/11] mtd: support BB SRAM on ICP DAS LP-8x4x Date: Sun, 1 Dec 2013 10:26:17 +0400 Message-Id: <1385879185-22455-5-git-send-email-ynvich@gmail.com> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1385879185-22455-1-git-send-email-ynvich@gmail.com> References: <1385879185-22455-1-git-send-email-ynvich@gmail.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20131201_012825_665840_88E01620 X-CRM114-Status: GOOD ( 27.91 ) X-Spam-Score: -1.9 (-) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-1.9 points) pts rule name description ---- ---------------------- -------------------------------------------------- 0.1 RCVD_IN_SBL RBL: Received via a relay in Spamhaus SBL [95.31.1.192 listed in zen.spamhaus.org] 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (ynvich[at]gmail.com) -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature Cc: Eric Miao , Kees Cook , Artem Bityutskiy , Robert Jarzmik , Randy Dunlap , Haojian Zhuang , Sergei Ianovich , Philip Avinash , "open list:MEMORY TECHNOLOGY..." , Russell King , David Woodhouse X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org This provides an MTD device driver for 512kB of battery backed up SRAM on ICPDAS LP-8X4X programmable automation controllers. SRAM chip is connected via FPGA and is not accessible without a driver, unlike flash memory which is wired to CPU MMU. This SRAM becomes an excellent persisent storage of volatile process data like counter values and sensor statuses. Storing those data in flash or mmc card is not a viable solution. Signed-off-by: Sergei Ianovich --- arch/arm/configs/lp8x4x_defconfig | 1 + arch/arm/mach-pxa/include/mach/lp8x4x.h | 2 + arch/arm/mach-pxa/lp8x4x.c | 26 ++++ drivers/mtd/devices/Kconfig | 13 ++ drivers/mtd/devices/Makefile | 1 + drivers/mtd/devices/lp8x4x_sram.c | 229 ++++++++++++++++++++++++++++++++ 6 files changed, 272 insertions(+) create mode 100644 drivers/mtd/devices/lp8x4x_sram.c diff --git a/arch/arm/configs/lp8x4x_defconfig b/arch/arm/configs/lp8x4x_defconfig index 27831e4..03c85bc 100644 --- a/arch/arm/configs/lp8x4x_defconfig +++ b/arch/arm/configs/lp8x4x_defconfig @@ -874,6 +874,7 @@ CONFIG_MTD_PXA2XX=y # Disk-On-Chip Device Drivers # # CONFIG_MTD_DOCG3 is not set +CONFIG_MTD_LP8X4X_SRAM=y # CONFIG_MTD_NAND is not set # CONFIG_MTD_ONENAND is not set diff --git a/arch/arm/mach-pxa/include/mach/lp8x4x.h b/arch/arm/mach-pxa/include/mach/lp8x4x.h index d8a1376..a49df22 100644 --- a/arch/arm/mach-pxa/include/mach/lp8x4x.h +++ b/arch/arm/mach-pxa/include/mach/lp8x4x.h @@ -49,6 +49,8 @@ #define LP8X4X_ENFALLINT LP8X4X_P2V(0x17009018) #define LP8X4X_CLRFALLINT LP8X4X_P2V(0x1700901a) #define LP8X4X_RWRTC LP8X4X_P2V(0x1700901c) +#define LP8X4X_SRAMBANK 0x1700901e +#define LP8X4X_SRAM 0x1700a000 /* board specific IRQs */ diff --git a/arch/arm/mach-pxa/lp8x4x.c b/arch/arm/mach-pxa/lp8x4x.c index a31b556..47a8776 100644 --- a/arch/arm/mach-pxa/lp8x4x.c +++ b/arch/arm/mach-pxa/lp8x4x.c @@ -234,6 +234,17 @@ static struct resource lp8x4x_flash_resources[] = { .end = PXA_CS1_PHYS + SZ_32M - 1, .flags = IORESOURCE_MEM, }, + [2] = { + .start = LP8X4X_SRAMBANK, + .end = LP8X4X_SRAMBANK + 1, + .flags = IORESOURCE_MEM, + }, + [3] = { + .start = LP8X4X_SRAM, + .end = LP8X4X_SRAM + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + }; static struct mtd_partition lp8x4x_flash0_partitions[] = { @@ -267,6 +278,10 @@ static struct flash_platform_data lp8x4x_flash_data[] = { .parts = NULL, .nr_parts = 0, .width = 2, + }, { + .parts = NULL, + .nr_parts = 0, + .width = 1, } }; @@ -289,6 +304,16 @@ static struct platform_device lp8x4x_flash_device[] = { .resource = &lp8x4x_flash_resources[1], .num_resources = 1, }, + { + .name = "lp8x4x-sram", + .id = 0, + .dev = { + .platform_data = &lp8x4x_flash_data[2], + }, + .resource = &lp8x4x_flash_resources[2], + .num_resources = 2, + }, + }; static struct pxafb_mode_info lp8x4x_vga_60_mode = { @@ -396,6 +421,7 @@ static struct platform_device lp8x4x_ds1302_device[] = { static struct platform_device *lp8x4x_devices[] __initdata = { &lp8x4x_flash_device[0], &lp8x4x_flash_device[1], + &lp8x4x_flash_device[2], &lp8x4x_dm9000_device[0], &lp8x4x_dm9000_device[1], &lp8x4x_ds1302_device[0], diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index 0128138..7da0c21 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -217,4 +217,17 @@ config BCH_CONST_T default 4 endif +config MTD_LP8X4X_SRAM + tristate "SRAM on ICPDAS LP-8X4X" + ---help--- + This provides an MTD device driver for 512kB of battery backed up SRAM + on ICPDAS LP-8X4X programmable automation controllers. + + SRAM chip is connected via FPGA and is not accessible without a driver, + unlike flash memory which is wired to CPU MMU. + + Say N, unless you plan to run this kernel on LP-8X4X. + + If you say M, the module will be called lp8x4x_sram. + endmenu diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile index d83bd73..8c5d9b0 100644 --- a/drivers/mtd/devices/Makefile +++ b/drivers/mtd/devices/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_MTD_NAND_OMAP_BCH) += elm.o obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o obj-$(CONFIG_MTD_SST25L) += sst25l.o obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47xxsflash.o +obj-$(CONFIG_MTD_LP8X4X_SRAM) += lp8x4x_sram.o CFLAGS_docg3.o += -I$(src) diff --git a/drivers/mtd/devices/lp8x4x_sram.c b/drivers/mtd/devices/lp8x4x_sram.c new file mode 100644 index 0000000..8fe625d --- /dev/null +++ b/drivers/mtd/devices/lp8x4x_sram.c @@ -0,0 +1,229 @@ +/* + * linux/drivers/mtd/devices/lp8x4x_sram.c + * + * MTD Driver for SRAM on ICPDAS LP-8x4x + * Copyright (C) 2013 Sergei Ianovich + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation or any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +struct lp8x4x_sram_info { + void __iomem *bank; + void __iomem *virt; + struct mutex lock; + unsigned active_bank; + struct mtd_info mtd; +}; + +static int +lp8x4x_sram_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + struct lp8x4x_sram_info *info = mtd->priv; + unsigned bank = instr->addr >> 11; + unsigned offset = (instr->addr & 0x7ff) << 1; + loff_t i; + + mutex_lock(&info->lock); + if (unlikely(bank != info->active_bank)) { + info->active_bank = bank; + iowrite8(bank, info->bank); + } + for (i = 0; i < instr->len; i++) { + iowrite8(0xff, info->virt + offset); + offset += 2; + if (unlikely(offset == 0)) { + info->active_bank++; + iowrite8(info->active_bank, info->bank); + } + } + mutex_unlock(&info->lock); + instr->state = MTD_ERASE_DONE; + mtd_erase_callback(instr); + + return 0; +} + +static int +lp8x4x_sram_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *b) +{ + struct lp8x4x_sram_info *info = mtd->priv; + unsigned bank = to >> 11; + unsigned offset = (to & 0x7ff) << 1; + loff_t i; + + mutex_lock(&info->lock); + if (unlikely(bank != info->active_bank)) { + info->active_bank = bank; + iowrite8(bank, info->bank); + } + for (i = 0; i < len; i++) { + iowrite8(b[i], info->virt + offset); + offset += 2; + if (unlikely(offset == 0)) { + info->active_bank++; + iowrite8(info->active_bank, info->bank); + } + } + mutex_unlock(&info->lock); + *retlen = len; + return 0; +} + +static int +lp8x4x_sram_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *b) +{ + struct lp8x4x_sram_info *info = mtd->priv; + unsigned bank = from >> 11; + unsigned offset = (from & 0x7ff) << 1; + loff_t i; + + mutex_lock(&info->lock); + if (unlikely(bank != info->active_bank)) { + info->active_bank = bank; + iowrite8(bank, info->bank); + } + for (i = 0; i < len; i++) { + b[i] = ioread8(info->virt + offset); + offset += 2; + if (unlikely(offset == 0)) { + info->active_bank++; + iowrite8(info->active_bank, info->bank); + } + } + mutex_unlock(&info->lock); + *retlen = len; + return 0; +} + +static void +lp8x4x_sram_sync(struct mtd_info *mtd) +{ +} + +static const char const *probes[] = { "RedBoot", "cmdlinepart", NULL }; + +static int +lp8x4x_sram_probe(struct platform_device *pdev) +{ + struct flash_platform_data *flash = pdev->dev.platform_data; + struct lp8x4x_sram_info *info; + struct resource *res; + char sz_str[16]; + int err = 0; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + err = -ENODEV; + goto err1; + } + + info->bank = ioremap(res->start, resource_size(res)); + if (!info->bank) { + dev_err(&pdev->dev, "Failed to ioremap %p\n", + info->bank); + err = -EFAULT; + goto err1; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) { + err = -ENODEV; + goto err2; + } + + info->virt = ioremap(res->start, resource_size(res)); + if (!info->virt) { + dev_err(&pdev->dev, "Failed to ioremap %p\n", + info->virt); + err = -EFAULT; + goto err2; + } + + info->mtd.priv = info; + info->mtd.name = "SRAM"; + info->mtd.type = MTD_RAM; + info->mtd.flags = MTD_CAP_RAM; + info->mtd.size = resource_size(res) << 7; + info->mtd.erasesize = 512; + info->mtd.writesize = 4; + info->mtd._erase = lp8x4x_sram_erase; + info->mtd._write = lp8x4x_sram_write; + info->mtd._read = lp8x4x_sram_read; + info->mtd._sync = lp8x4x_sram_sync; + info->mtd.owner = THIS_MODULE; + + err = mtd_device_parse_register(&info->mtd, probes, NULL, flash->parts, + flash->nr_parts); + if (err < 0) { + dev_err(&pdev->dev, "Failed to register device\n"); + goto err3; + } + + mutex_init(&info->lock); + iowrite8(info->active_bank, info->bank); + platform_set_drvdata(pdev, info); + string_get_size(info->mtd.size, STRING_UNITS_2, sz_str, + sizeof(sz_str)); + dev_info(&pdev->dev, "using %s SRAM on LP-8X4X as %s\n", sz_str, + dev_name(&info->mtd.dev)); + return 0; +err3: + iounmap(info->virt); +err2: + iounmap(info->bank); +err1: + kfree(info); + return err; +} + +static int +lp8x4x_sram_remove(struct platform_device *dev) +{ + struct lp8x4x_sram_info *info = platform_get_drvdata(dev); + + platform_set_drvdata(dev, NULL); + mtd_device_unregister(&info->mtd); + iounmap(info->virt); + iounmap(info->bank); + kfree(info); + return 0; +} + +static struct platform_driver lp8x4x_sram_driver = { + .driver = { + .name = "lp8x4x-sram", + .owner = THIS_MODULE, + }, + .probe = lp8x4x_sram_probe, + .remove = lp8x4x_sram_remove, +}; + +module_platform_driver(lp8x4x_sram_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sergei Ianovich "); +MODULE_DESCRIPTION("MTD driver for SRAM on ICPDAS LP-8x4x");