^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Map driver for Intel XScale PXA2xx platforms.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Author: Nicolas Pitre
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright: (C) 2001 MontaVista Software Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/mtd/mtd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/mtd/map.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/mtd/partitions.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <mach/hardware.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <asm/mach/flash.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define CACHELINESIZE 32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static void pxa2xx_map_inval_cache(struct map_info *map, unsigned long from,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) ssize_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) unsigned long start = (unsigned long)map->cached + from;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) unsigned long end = start + len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) start &= ~(CACHELINESIZE - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) while (start < end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) /* invalidate D cache line */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) asm volatile ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) start += CACHELINESIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) struct pxa2xx_flash_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) struct mtd_info *mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) struct map_info map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) static const char * const probes[] = { "RedBoot", "cmdlinepart", NULL };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static int pxa2xx_flash_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) struct flash_platform_data *flash = dev_get_platdata(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) struct pxa2xx_flash_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) if (!res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) info = kzalloc(sizeof(struct pxa2xx_flash_info), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) info->map.name = flash->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) info->map.bankwidth = flash->width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) info->map.phys = res->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) info->map.size = resource_size(res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) info->map.virt = ioremap(info->map.phys, info->map.size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if (!info->map.virt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) printk(KERN_WARNING "Failed to ioremap %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) info->map.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) info->map.cached = ioremap_cache(info->map.phys, info->map.size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (!info->map.cached)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) printk(KERN_WARNING "Failed to ioremap cached %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) info->map.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) info->map.inval_cache = pxa2xx_map_inval_cache;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) simple_map_init(&info->map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) printk(KERN_NOTICE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) "Probing %s at physical address 0x%08lx"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) " (%d-bit bankwidth)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) info->map.name, (unsigned long)info->map.phys,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) info->map.bankwidth * 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) info->mtd = do_map_probe(flash->map_name, &info->map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (!info->mtd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) iounmap((void *)info->map.virt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (info->map.cached)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) iounmap(info->map.cached);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) info->mtd->dev.parent = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) mtd_device_parse_register(info->mtd, probes, NULL, flash->parts,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) flash->nr_parts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) platform_set_drvdata(pdev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) static int pxa2xx_flash_remove(struct platform_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) struct pxa2xx_flash_info *info = platform_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) mtd_device_unregister(info->mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) map_destroy(info->mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) iounmap(info->map.virt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (info->map.cached)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) iounmap(info->map.cached);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) kfree(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) static void pxa2xx_flash_shutdown(struct platform_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) struct pxa2xx_flash_info *info = platform_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (info && mtd_suspend(info->mtd) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) mtd_resume(info->mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) #define pxa2xx_flash_shutdown NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) static struct platform_driver pxa2xx_flash_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) .name = "pxa2xx-flash",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) .probe = pxa2xx_flash_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) .remove = pxa2xx_flash_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) .shutdown = pxa2xx_flash_shutdown,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) module_platform_driver(pxa2xx_flash_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) MODULE_AUTHOR("Nicolas Pitre <nico@fluxnic.net>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) MODULE_DESCRIPTION("MTD map driver for Intel XScale PXA2xx");