162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Handle mapping of the NOR flash on implementa A7 boards
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2002 SYSGO Real-Time Solutions GmbH
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <linux/types.h>
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/init.h>
1262306a36Sopenharmony_ci#include <asm/io.h>
1362306a36Sopenharmony_ci#include <linux/mtd/mtd.h>
1462306a36Sopenharmony_ci#include <linux/mtd/map.h>
1562306a36Sopenharmony_ci#include <linux/mtd/partitions.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define WINDOW_ADDR0 0x00000000      /* physical properties of flash */
1862306a36Sopenharmony_ci#define WINDOW_SIZE0 0x00800000
1962306a36Sopenharmony_ci#define WINDOW_ADDR1 0x10000000      /* physical properties of flash */
2062306a36Sopenharmony_ci#define WINDOW_SIZE1 0x00800000
2162306a36Sopenharmony_ci#define NUM_FLASHBANKS 2
2262306a36Sopenharmony_ci#define BUSWIDTH     4
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define MSG_PREFIX "impA7:"   /* prefix for our printk()'s */
2562306a36Sopenharmony_ci#define MTDID      "impa7-%d"  /* for mtdparts= partitioning */
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic struct mtd_info *impa7_mtd[NUM_FLASHBANKS];
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic const char * const rom_probe_types[] = { "jedec_probe", NULL };
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic struct map_info impa7_map[NUM_FLASHBANKS] = {
3262306a36Sopenharmony_ci	{
3362306a36Sopenharmony_ci		.name = "impA7 NOR Flash Bank #0",
3462306a36Sopenharmony_ci		.size = WINDOW_SIZE0,
3562306a36Sopenharmony_ci		.bankwidth = BUSWIDTH,
3662306a36Sopenharmony_ci	},
3762306a36Sopenharmony_ci	{
3862306a36Sopenharmony_ci		.name = "impA7 NOR Flash Bank #1",
3962306a36Sopenharmony_ci		.size = WINDOW_SIZE1,
4062306a36Sopenharmony_ci		.bankwidth = BUSWIDTH,
4162306a36Sopenharmony_ci	},
4262306a36Sopenharmony_ci};
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci/*
4562306a36Sopenharmony_ci * MTD partitioning stuff
4662306a36Sopenharmony_ci */
4762306a36Sopenharmony_cistatic const struct mtd_partition partitions[] =
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	{
5062306a36Sopenharmony_ci		.name = "FileSystem",
5162306a36Sopenharmony_ci		.size = 0x800000,
5262306a36Sopenharmony_ci		.offset = 0x00000000
5362306a36Sopenharmony_ci	},
5462306a36Sopenharmony_ci};
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic int __init init_impa7(void)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	const char * const *type;
5962306a36Sopenharmony_ci	int i;
6062306a36Sopenharmony_ci	static struct { u_long addr; u_long size; } pt[NUM_FLASHBANKS] = {
6162306a36Sopenharmony_ci	  { WINDOW_ADDR0, WINDOW_SIZE0 },
6262306a36Sopenharmony_ci	  { WINDOW_ADDR1, WINDOW_SIZE1 },
6362306a36Sopenharmony_ci        };
6462306a36Sopenharmony_ci	int devicesfound = 0;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	for(i=0; i<NUM_FLASHBANKS; i++)
6762306a36Sopenharmony_ci	{
6862306a36Sopenharmony_ci		printk(KERN_NOTICE MSG_PREFIX "probing 0x%08lx at 0x%08lx\n",
6962306a36Sopenharmony_ci		       pt[i].size, pt[i].addr);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci		impa7_map[i].phys = pt[i].addr;
7262306a36Sopenharmony_ci		impa7_map[i].virt = ioremap(pt[i].addr, pt[i].size);
7362306a36Sopenharmony_ci		if (!impa7_map[i].virt) {
7462306a36Sopenharmony_ci			printk(MSG_PREFIX "failed to ioremap\n");
7562306a36Sopenharmony_ci			return -EIO;
7662306a36Sopenharmony_ci		}
7762306a36Sopenharmony_ci		simple_map_init(&impa7_map[i]);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci		impa7_mtd[i] = NULL;
8062306a36Sopenharmony_ci		type = rom_probe_types;
8162306a36Sopenharmony_ci		for(; !impa7_mtd[i] && *type; type++) {
8262306a36Sopenharmony_ci			impa7_mtd[i] = do_map_probe(*type, &impa7_map[i]);
8362306a36Sopenharmony_ci		}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci		if (impa7_mtd[i]) {
8662306a36Sopenharmony_ci			impa7_mtd[i]->owner = THIS_MODULE;
8762306a36Sopenharmony_ci			devicesfound++;
8862306a36Sopenharmony_ci			mtd_device_register(impa7_mtd[i], partitions,
8962306a36Sopenharmony_ci					    ARRAY_SIZE(partitions));
9062306a36Sopenharmony_ci		} else {
9162306a36Sopenharmony_ci			iounmap((void __iomem *)impa7_map[i].virt);
9262306a36Sopenharmony_ci		}
9362306a36Sopenharmony_ci	}
9462306a36Sopenharmony_ci	return devicesfound == 0 ? -ENXIO : 0;
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic void __exit cleanup_impa7(void)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	int i;
10062306a36Sopenharmony_ci	for (i=0; i<NUM_FLASHBANKS; i++) {
10162306a36Sopenharmony_ci		if (impa7_mtd[i]) {
10262306a36Sopenharmony_ci			mtd_device_unregister(impa7_mtd[i]);
10362306a36Sopenharmony_ci			map_destroy(impa7_mtd[i]);
10462306a36Sopenharmony_ci			iounmap((void __iomem *)impa7_map[i].virt);
10562306a36Sopenharmony_ci			impa7_map[i].virt = NULL;
10662306a36Sopenharmony_ci		}
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cimodule_init(init_impa7);
11162306a36Sopenharmony_cimodule_exit(cleanup_impa7);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ciMODULE_LICENSE("GPL");
11462306a36Sopenharmony_ciMODULE_AUTHOR("Pavel Bartusek <pba@sysgo.de>");
11562306a36Sopenharmony_ciMODULE_DESCRIPTION("MTD map driver for implementa impA7");
116