summaryrefslogtreecommitdiffstats
path: root/target/linux/amazon/files/drivers/mtd/maps/amazon.c
blob: 8c311418982925b1c75217ffa58a32f0fe9df600 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/*
 * Handle mapping of the flash memory access routines
 * on Amazon  based devices.
 *
 * Copyright(C) 2004 peng.liu@infineon.com
 *
 * This code is GPLed
 *
 */
// 000005:fchang 2005/6/2 Modified by Bingtao to double check if the EBU is enabled/disabled
// 506231:tc.chen 2005/06/23 increase firmware partition size form 192KB to 256KB
// 050701:linmars 2005/07/01 fix flash size wrong alignment after increase firmware partition
// 165001:henryhsu 2005/8/18 Remove the support for Intel flash because of 2.1 not enough rootfs partition size
// 165001:henryhsu 2005/9/7 Rolback to support INtel flash
// 509071:tc.chen 2005/09/07 Reduced flash writing time
// 511046:linmars 2005/11/04 change bootloader size from 128 into 64
// 511241:linmars 2005/11/24 merge TaiChen's IRM patch 

// copyright 2005 infineon

// copyright 2007 john crispin <blogic@openwrt.org>
// copyright 2007 felix fietkau <nbd@openwrt.org>

#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <asm/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/mutex.h>
#include <asm/amazon/amazon.h>

#define AMAZON_PCI_ARB_CTL_ALT 0xb100205c
#define AMAZON_MTD_REG32( addr )          (*(volatile u32 *)(addr))


static struct map_info amazon_map = {
	.name = "AMAZON_FLASH",
	.bankwidth = 2,
	.size = 0x1000000,
};

static map_word amazon_read16(struct map_info * map, unsigned long ofs)
{
	map_word temp;
	ofs ^= 2;
	temp.x[0] = *((__u16 *) (map->virt + ofs));
	return temp;
}

static void amazon_write16(struct map_info *map, map_word d, unsigned long adr)
{
	adr ^= 2;
	*((__u16 *) (map->virt + adr)) = d.x[0];
}

void amazon_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
{
	u8 *p;
	u8 *to_8;
	ssize_t l = len;
	from = (unsigned long) (from + map->virt);
	p = (u8 *) from;
	to_8 = (u8 *) to;
	while(len--){
		*to_8++ = *p++;
	}
}

void amazon_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
{
	u8 *p =  (u8*) from;
	u8 *to_8;
	to += (unsigned long) map->virt;
	to_8 = (u8*)to;
	while(len--){
		*p++ = *to_8++;
	}
}

#define UBOOT_SIZE		0x40000

static struct mtd_partition	amazon_partitions[3] = {
	 {
		  name:"U-Boot",		/* U-Boot firmware */
		  offset:0x00000000,
		  size:UBOOT_SIZE ,		/* 128k */
	  },
	 {
		  name:"kernel",		/* firmware */
		  offset:UBOOT_SIZE,
		  size:0x00100000,		/* 192K */
	  },
	 {
		  name:"rootfs",		/* default partition */
		  offset:0x00200000,
		  size:0x00200000,
	  },
};


unsigned long flash_start = 0x13000000;
unsigned long flash_size = 0x800000;
unsigned long uImage_size = 0x10000d;

int find_uImage_size(unsigned long start_offset)
{
	unsigned long magic;
	unsigned long temp;
	amazon_copy_from(&amazon_map, &magic, start_offset, 4);
	if (!(ntohl(magic) == 0x27051956)) {
		printk(KERN_INFO "amazon_mtd: invalid magic (0x%08X) of kernel at 0x%08lx \n", ntohl(magic), start_offset);
		return 0;
	}
	amazon_copy_from(&amazon_map, &temp, start_offset + 12, 4);
	printk(KERN_INFO "amazon_mtd: kernel size is %ld \n", temp + 0x40);
	return temp + 0x40;
}

int __init init_amazon_mtd(void)
{
	int ret = 0;
	unsigned long uimage_size;
	struct mtd_info *mymtd = NULL;
	struct mtd_partition *parts = NULL;

	*AMAZON_EBU_BUSCON0 = 0x1d7ff;
	
	amazon_map.read = amazon_read16;
	amazon_map.write = amazon_write16;
	amazon_map.copy_from = amazon_copy_from;
	amazon_map.copy_to = amazon_copy_to;

	amazon_map.phys = flash_start;
	amazon_map.virt = ioremap_nocache(flash_start, flash_size);
	
	if (!amazon_map.virt) {
		printk(KERN_WARNING "Failed to ioremap!\n");
		return -EIO;
	}
	
	mymtd = (struct mtd_info *) do_map_probe("cfi_probe", &amazon_map);
	if (!mymtd) {
		iounmap(amazon_map.virt);
		printk("probing failed\n");
		return -ENXIO;
	}

	mymtd->owner = THIS_MODULE;
	parts = &amazon_partitions[0];

	/* Some Samsung devices are containing a 16 MB flash chip with a bigger U-Boot partition. */
	if(mymtd->size == 0x01000000 && mymtd->erasesize == 0x00020000) {
		printk(KERN_INFO "amazon_mtd: Found big flash chip!\n");
		amazon_partitions[0].size = 0x60000;
		amazon_partitions[1].offset = 0x60000;
		uimage_size = find_uImage_size(amazon_partitions[1].offset);
		amazon_partitions[1].size = uimage_size;
		amazon_partitions[2].offset = 0x60000 + uimage_size;
		amazon_partitions[2].size = mymtd->size - amazon_partitions[2].offset - mymtd->erasesize;
	} else {
		printk(KERN_INFO "amazon_mtd: Found small flash chip!\n");
		uimage_size = find_uImage_size(amazon_partitions[1].offset);
		amazon_partitions[1].size = uimage_size;
		amazon_partitions[2].offset = UBOOT_SIZE + uimage_size;
		amazon_partitions[2].size = mymtd->size - amazon_partitions[2].offset - (2 * mymtd->erasesize);
	}

	add_mtd_partitions(mymtd, parts, 3);

	printk(KERN_INFO "amazon_mtd: added %s flash with %dMB\n",
		amazon_map.name, mymtd->size >> 20);
	return 0;
}

static void __exit cleanup_amazon_mtd(void)
{
	/* FIXME! */
}

module_init(init_amazon_mtd);
module_exit(cleanup_amazon_mtd);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("john crispin blogic@openwrt.org");
MODULE_DESCRIPTION("MTD map driver for AMAZON boards");