[PATCH 06/10] MIPS: lantiq: add NOR flash support

Daniel Schwierzeck daniel.schwierzeck at googlemail.com
Mon Jan 10 21:59:19 EST 2011


Hi John,

the EBU doesn't allow unaligned read or write access thus Lantiq added 
this alignment hack directly in hardware. The addr^=2 is only needed 
during CFI probe because odd addresses are accessed. A simple solution 
is inside your patch.

The spin_lock_irqsave(&ebu_lock, flags); is actually not needed because 
the EBU does access arbitration and protection already in hardware.

Daniel

On 01/05/2011 08:56 PM, John Crispin wrote:
> NOR flash is attached to the same EBU (External Bus Unit) as PCI. As described
> in the PCI patch, the EBU is a little obscure, resulting in the upper and lower
> 16 bit of the data on a 32 bit read are swapped. (essentially we have a addr^=2)
> This only happens on the read of data. In order to not have to high an impact
> on the read performance from the EBU we store all data on the flash with
> addr^=2. This allows us to do generic reads without having to do any swapping.
> For the write to now work we need to swizzle the the 0x2 bit of the addr.
> However this write swizzle needs to only happen when doing a CMD and not a DATA
> write.
>
> As the MTD layer currently makes no difference between a CMD and DATA read when
> using complex maps, the map driver does not know when the swizzle and when not
> to swizzle. The next patch in the series adds a hack to the MTD to workaround
> this problem. I am sending these 2 patches to the mtd list aswell. There are
> several ways to solve this generically in the mtd layer in a much better way.
> This will have minor impact on the actual map code provided in this patch.
>
> Signed-off-by: John Crispin<blogic at openwrt.org>
> Signed-off-by: Ralph Hempel<ralph.hempel at lantiq.com>
> Cc: David Woodhouse<dwmw2 at infradead.org>
> Cc: linux-mips at linux-mips.org
> Cc: linux-mtd at lists.infradead.org
> ---
>   drivers/mtd/maps/Kconfig  |    7 ++
>   drivers/mtd/maps/Makefile |    1 +
>   drivers/mtd/maps/lantiq.c |  169 +++++++++++++++++++++++++++++++++++++++++++++
>   3 files changed, 177 insertions(+), 0 deletions(-)
>   create mode 100644 drivers/mtd/maps/lantiq.c
>
> diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
> index a0dd7bb..ca69a7f 100644
> --- a/drivers/mtd/maps/Kconfig
> +++ b/drivers/mtd/maps/Kconfig
> @@ -260,6 +260,13 @@ config MTD_BCM963XX
>   	  Support for parsing CFE image tag and creating MTD partitions on
>   	  Broadcom BCM63xx boards.
>
> +config MTD_LANTIQ
> +	bool "Lantiq SoC NOR support"
> +	depends on LANTIQ&&  MTD_PARTITIONS
> +	help
> +	  Support for NOR flash chips on Lantiq SoC. The Chips are connected
> +	  to the SoCs EBU (External Bus Unit)
> +
>   config MTD_DILNETPC
>   	tristate "CFI Flash device mapped on DIL/Net PC"
>   	depends on X86&&  MTD_CONCAT&&  MTD_PARTITIONS&&  MTD_CFI_INTELEXT&&  BROKEN
> diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
> index c7869c7..bb2ce2f 100644
> --- a/drivers/mtd/maps/Makefile
> +++ b/drivers/mtd/maps/Makefile
> @@ -59,3 +59,4 @@ obj-$(CONFIG_MTD_RBTX4939)	+= rbtx4939-flash.o
>   obj-$(CONFIG_MTD_VMU)		+= vmu-flash.o
>   obj-$(CONFIG_MTD_GPIO_ADDR)	+= gpio-addr-flash.o
>   obj-$(CONFIG_MTD_BCM963XX)	+= bcm963xx-flash.o
> +obj-$(CONFIG_MTD_LANTIQ)	+= lantiq.o
> diff --git a/drivers/mtd/maps/lantiq.c b/drivers/mtd/maps/lantiq.c
> new file mode 100644
> index 0000000..e5a361e
> --- /dev/null
> +++ b/drivers/mtd/maps/lantiq.c
> @@ -0,0 +1,169 @@
> +/*
> + *  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.
> + *
> + *  Copyright (C) 2004 Liu Peng Infineon IFAP DC COM CPE
> + *  Copyright (C) 2010 John Crispin<blogic at openwrt.org>
> + */
> +
> +#include<linux/module.h>
> +#include<linux/types.h>
> +#include<linux/kernel.h>
> +#include<linux/io.h>
> +#include<linux/init.h>
> +#include<linux/mtd/mtd.h>
> +#include<linux/mtd/map.h>
> +#include<linux/mtd/partitions.h>
> +#include<linux/mtd/cfi.h>
> +#include<linux/magic.h>
> +#include<linux/platform_device.h>
> +#include<linux/mtd/physmap.h>
> +
> +#include<lantiq_soc.h>
> +#include<lantiq_platform.h>
> +
static int ltq_probing = 0;

> +static map_word
> +ltq_read16(struct map_info *map, unsigned long adr)
> +{
> +	unsigned long flags;
> +	map_word temp;
> +	spin_lock_irqsave(&ebu_lock, flags);
	if (ltq_probing)
		adr ^= 2;
> +	temp.x[0] = *((__u16 *)(map->virt + adr));
> +	spin_unlock_irqrestore(&ebu_lock, flags);
> +	return temp;
> +}
> +
> +static void
> +ltq_write16(struct map_info *map, map_word d, unsigned long adr)
> +{
> +	unsigned long flags;
> +	spin_lock_irqsave(&ebu_lock, flags);
	if (ltq_probing)
		adr ^= 2;
> +	*((__u16 *)(map->virt + adr)) = d.x[0];
> +	spin_unlock_irqrestore(&ebu_lock, flags);
> +}
> +
> +void
> +ltq_copy_from(struct map_info *map, void *to,
> +	unsigned long from, ssize_t len)
> +{
> +	unsigned char *p;
> +	unsigned char *to_8;
> +	unsigned long flags;
> +	spin_lock_irqsave(&ebu_lock, flags);
> +	from = (unsigned long)(from + map->virt);
> +	p = (unsigned char *) from;
> +	to_8 = (unsigned char *) to;
> +	while (len--)
> +		*to_8++ = *p++;
> +	spin_unlock_irqrestore(&ebu_lock, flags);
> +}
> +
> +void
> +ltq_copy_to(struct map_info *map, unsigned long to,
> +	const void *from, ssize_t len)
> +{
> +	unsigned char *p =  (unsigned char *)from;
> +	unsigned char *to_8;
> +	unsigned long flags;
> +	spin_lock_irqsave(&ebu_lock, flags);
> +	to += (unsigned long) map->virt;
> +	to_8 = (unsigned char *)to;
> +	while (len--)
> +		*p++ = *to_8++;
> +	spin_unlock_irqrestore(&ebu_lock, flags);
> +}
> +
> +static const char * const part_probe_types[] = {
> +	"cmdlinepart", NULL };
> +
> +static struct map_info ltq_map = {
> +	.name = "ltq_nor",
> +	.bankwidth = 2,
> +	.read = ltq_read16,
> +	.write = ltq_write16,
> +	.copy_from = ltq_copy_from,
> +	.copy_to = ltq_copy_to,
> +};
> +
> +static int
> +ltq_mtd_probe(struct platform_device *pdev)
> +{
> +	struct physmap_flash_data *ltq_mtd_data =
> +		(struct physmap_flash_data *) dev_get_platdata(&pdev->dev);
> +	struct mtd_info *ltq_mtd = NULL;
> +	struct mtd_partition *parts = NULL;
> +	struct resource *res = 0;
> +	int nr_parts = 0;
> +
> +#ifdef CONFIG_SOC_TYPE_XWAY
> +	ltq_w32(ltq_r32(LTQ_EBU_BUSCON0)&  ~EBU_WRDIS, LTQ_EBU_BUSCON0);
> +#endif
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res) {
> +		dev_err(&pdev->dev, "failed to get memory resource");
> +		return -ENOENT;
> +	}
> +	res = request_mem_region(res->start, resource_size(res),
> +		dev_name(&pdev->dev));
> +	if (!res) {
> +		dev_err(&pdev->dev, "failed to request mem resource");
> +		return -EBUSY;
> +	}
> +
> +	ltq_map.phys = res->start;
> +	ltq_map.size = resource_size(res);
> +	ltq_map.virt = ioremap_nocache(ltq_map.phys, ltq_map.size);
> +
> +	if (!ltq_map.virt) {
> +		dev_err(&pdev->dev, "failed to ioremap!\n");
> +		return -EIO;
> +	}
> +
	ltq_probing = 1;
> +	ltq_mtd = (struct mtd_info *) do_map_probe("cfi_probe",&ltq_map);
	ltq_probing = 0;
> +	if (!ltq_mtd) {
> +		iounmap(ltq_map.virt);
> +		dev_err(&pdev->dev, "probing failed\n");
> +		return -ENXIO;
> +	}
> +
> +	ltq_mtd->owner = THIS_MODULE;
> +
> +	nr_parts = parse_mtd_partitions(ltq_mtd, part_probe_types,&parts, 0);
> +	if (nr_parts>  0) {
> +		dev_info(&pdev->dev,
> +			"using %d partitions from cmdline", nr_parts);
> +	} else {
> +		nr_parts = ltq_mtd_data->nr_parts;
> +		parts = ltq_mtd_data->parts;
> +	}
> +
> +	add_mtd_partitions(ltq_mtd, parts, nr_parts);
> +	return 0;
> +}
> +
> +static struct platform_driver ltq_mtd_driver = {
> +	.probe = ltq_mtd_probe,
> +	.driver = {
> +		.name = "ltq_nor",
> +		.owner = THIS_MODULE,
> +	},
> +};
> +
> +int __init
> +init_ltq_mtd(void)
> +{
> +	int ret = platform_driver_register(&ltq_mtd_driver);
> +	if (ret)
> +		printk(KERN_INFO "ltq_nor: error registering platfom driver");
> +	return ret;
> +}
> +
> +module_init(init_ltq_mtd);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("John Crispin<blogic at openwrt.org>");
> +MODULE_DESCRIPTION("Lantiq SoC NOR");



More information about the linux-mtd mailing list