1/*
2 * Handle mapping of the flash memory access routines
3 * on Amazon  based devices.
4 *
5 * Copyright(C) 2004 peng.liu@infineon.com
6 *
7 * This code is GPLed
8 *
9 */
10// 000005:fchang 2005/6/2 Modified by Bingtao to double check if the EBU is enabled/disabled
11// 506231:tc.chen 2005/06/23 increase firmware partition size form 192KB to 256KB
12// 050701:linmars 2005/07/01 fix flash size wrong alignment after increase firmware partition
13// 165001:henryhsu 2005/8/18 Remove the support for Intel flash because of 2.1 not enough rootfs partition size
14// 165001:henryhsu 2005/9/7 Rolback to support INtel flash
15// 509071:tc.chen 2005/09/07 Reduced flash writing time
16// 511046:linmars 2005/11/04 change bootloader size from 128 into 64
17// 511241:linmars 2005/11/24 merge TaiChen's IRM patch
18
19// copyright 2005 infineon
20
21// copyright 2007 john crispin <blogic@openwrt.org>
22// copyright 2007 felix fietkau <nbd@openwrt.org>
23// copyright 2009 hauke mehrtens <hauke@hauke-m.de>
24
25#include <linux/module.h>
26#include <linux/types.h>
27#include <linux/kernel.h>
28#include <asm/io.h>
29
30#include <linux/init.h>
31#include <linux/mtd/mtd.h>
32#include <linux/mtd/map.h>
33#include <linux/mtd/partitions.h>
34#include <linux/mtd/cfi.h>
35#include <linux/mutex.h>
36#include <linux/platform_device.h>
37#include <asm/amazon/amazon.h>
38
39#define AMAZON_PCI_ARB_CTL_ALT 0xb100205c
40#define AMAZON_MTD_REG32( addr )          (*(volatile u32 *)(addr))
41
42
43static struct map_info amazon_map = {
44	.name = "AMAZON_FLASH",
45	.bankwidth = 2,
46};
47
48static map_word amazon_read16(struct map_info * map, unsigned long ofs)
49{
50	map_word temp;
51	ofs ^= 2;
52	temp.x[0] = *((__u16 *) (map->virt + ofs));
53	return temp;
54}
55
56static void amazon_write16(struct map_info *map, map_word d, unsigned long adr)
57{
58	adr ^= 2;
59	*((__u16 *) (map->virt + adr)) = d.x[0];
60}
61
62void amazon_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
63{
64	u8 *p;
65	u8 *to_8;
66	from = (unsigned long) (from + map->virt);
67	p = (u8 *) from;
68	to_8 = (u8 *) to;
69	while(len--){
70		*to_8++ = *p++;
71	}
72}
73
74void amazon_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
75{
76	u8 *p =  (u8*) from;
77	u8 *to_8;
78	to += (unsigned long) map->virt;
79	to_8 = (u8*)to;
80	while(len--){
81		*p++ = *to_8++;
82	}
83}
84
85#define UBOOT_SIZE		0x40000
86
87static struct mtd_partition	amazon_partitions[3] = {
88	 {
89		  name:"U-Boot",		/* U-Boot firmware */
90		  offset:0x00000000,
91		  size:UBOOT_SIZE ,		/* 128k */
92	  },
93	 {
94		  name:"kernel",		/* firmware */
95		  offset:UBOOT_SIZE,
96		  size:0x00100000,		/* 192K */
97	  },
98	 {
99		  name:"rootfs",		/* default partition */
100		  offset:0x00200000,
101		  size:0x00200000,
102	  },
103};
104
105unsigned long uImage_size = 0x10000d;
106
107int find_uImage_size(unsigned long start_offset)
108{
109	unsigned long magic;
110	unsigned long temp;
111	amazon_copy_from(&amazon_map, &magic, start_offset, 4);
112	if (!(ntohl(magic) == 0x27051956)) {
113		printk(KERN_INFO "amazon_mtd: invalid magic (0x%08X) of kernel at 0x%08lx \n", ntohl(magic), start_offset);
114		return 0;
115	}
116	amazon_copy_from(&amazon_map, &temp, start_offset + 12, 4);
117	printk(KERN_INFO "amazon_mtd: kernel size is %ld \n", temp + 0x40);
118	return temp + 0x40;
119}
120
121static int amazon_mtd_probe(struct platform_device *dev)
122{
123	unsigned long uimage_size;
124	struct mtd_info *mymtd = NULL;
125	struct mtd_partition *parts = NULL;
126
127	*AMAZON_EBU_BUSCON0 = 0x1d7ff;
128
129	amazon_map.read = amazon_read16;
130	amazon_map.write = amazon_write16;
131	amazon_map.copy_from = amazon_copy_from;
132	amazon_map.copy_to = amazon_copy_to;
133
134	amazon_map.phys = dev->resource->start;
135	amazon_map.size = dev->resource->end - amazon_map.phys + 1;
136	amazon_map.virt = ioremap_nocache(amazon_map.phys, amazon_map.size);
137
138	if (!amazon_map.virt) {
139		printk(KERN_WARNING "amazon_mtd: Failed to ioremap!\n");
140		return -EIO;
141	}
142
143	mymtd = (struct mtd_info *) do_map_probe("cfi_probe", &amazon_map);
144	if (!mymtd) {
145		iounmap(amazon_map.virt);
146		printk(KERN_WARNING "amazon_mtd: probing failed\n");
147		return -ENXIO;
148	}
149
150	mymtd->owner = THIS_MODULE;
151	parts = &amazon_partitions[0];
152
153	/* Some Samsung devices are containing a 16 MB flash chip with a bigger U-Boot partition. */
154	if(mymtd->size == 0x01000000 && mymtd->erasesize == 0x00020000) {
155		printk(KERN_INFO "amazon_mtd: Found big flash chip!\n");
156		amazon_partitions[0].size = 0x60000;
157		amazon_partitions[1].offset = 0x60000;
158		uimage_size = find_uImage_size(amazon_partitions[1].offset);
159		amazon_partitions[1].size = uimage_size;
160		amazon_partitions[2].offset = 0x60000 + uimage_size;
161		amazon_partitions[2].size = mymtd->size - amazon_partitions[2].offset - mymtd->erasesize;
162	} else {
163		printk(KERN_INFO "amazon_mtd: Found small flash chip!\n");
164		uimage_size = find_uImage_size(amazon_partitions[1].offset);
165		amazon_partitions[1].size = uimage_size;
166		amazon_partitions[2].offset = UBOOT_SIZE + uimage_size;
167		amazon_partitions[2].size = mymtd->size - amazon_partitions[2].offset - (2 * mymtd->erasesize);
168	}
169
170	mtd_device_register(mymtd, parts, 3);
171
172	printk(KERN_INFO "amazon_mtd: added %s flash with %dMB\n",
173		amazon_map.name, ((int)mymtd->size) >> 20);
174	return 0;
175}
176
177static struct platform_driver amazon_mtd_driver = {
178	.probe = amazon_mtd_probe,
179	.driver = {
180		.name = "amazon_mtd",
181		.owner = THIS_MODULE,
182	},
183};
184
185static int __init amazon_mtd_init(void)
186{
187	int ret = platform_driver_register(&amazon_mtd_driver);
188	if (ret)
189		printk(KERN_WARNING "amazon_mtd: error registering platfom driver!\n");
190	return ret;
191}
192
193static void __exit amazon_mtd_cleanup(void)
194{
195	platform_driver_unregister(&amazon_mtd_driver);
196}
197
198module_init(amazon_mtd_init);
199module_exit(amazon_mtd_cleanup);
200
201MODULE_LICENSE("GPL");
202MODULE_AUTHOR("john crispin blogic@openwrt.org");
203MODULE_DESCRIPTION("MTD map driver for AMAZON boards");
204
205