1/*
2 * Flash mapping for BCM947XX boards
3 *
4 * Copyright (C) 2010, Broadcom Corporation. All Rights Reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * $Id: bcm947xx-flash.c,v 1.6 2009-07-27 07:34:33 Exp $
19 */
20
21#include <linux/module.h>
22#include <linux/types.h>
23#include <linux/kernel.h>
24#include <linux/init.h>
25#include <asm/io.h>
26#include <linux/mtd/mtd.h>
27#include <linux/mtd/map.h>
28#include <linux/mtd/partitions.h>
29#include <linux/config.h>
30
31#include <typedefs.h>
32#include <bcmnvram.h>
33#include <bcmutils.h>
34#include <hndsoc.h>
35#include <sbchipc.h>
36#include <siutils.h>
37#include <trxhdr.h>
38
39/* Global SB handle */
40extern void *bcm947xx_sih;
41extern spinlock_t bcm947xx_sih_lock;
42
43/* Convenience */
44#define sih bcm947xx_sih
45#define sih_lock bcm947xx_sih_lock
46
47#ifdef CONFIG_MTD_PARTITIONS
48extern struct mtd_partition * init_mtd_partitions(struct mtd_info *mtd, size_t size);
49#endif
50
51#define WINDOW_ADDR 0x1fc00000
52#define WINDOW_SIZE 0x400000
53#define BUSWIDTH 2
54
55/* e.g., flash=2M or flash=4M */
56static int flash = 0;
57module_param(flash, int, 0);
58static int __init
59bcm947xx_setup(char *str)
60{
61	flash = memparse(str, &str);
62	return 1;
63}
64__setup("flash=", bcm947xx_setup);
65
66static struct mtd_info *bcm947xx_mtd;
67
68
69#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
70#define init_bcm947xx_map init_module
71#define cleanup_bcm947xx_map cleanup_module
72#endif
73
74struct map_info bcm947xx_map = {
75	.name = "Physically mapped flash",
76	.size = WINDOW_SIZE,
77	.bankwidth = BUSWIDTH
78};
79
80static int __init
81init_bcm947xx_map(void)
82{
83	ulong flags;
84 	uint coreidx;
85	chipcregs_t *cc;
86	uint32 fltype;
87	uint window_addr = 0, window_size = 0;
88	size_t size;
89	int ret = 0;
90#ifdef CONFIG_MTD_PARTITIONS
91	struct mtd_partition *parts;
92	int i;
93#endif
94
95	spin_lock_irqsave(&sih_lock, flags);
96	coreidx = si_coreidx(sih);
97
98	/* Check strapping option if chipcommon exists */
99	if ((cc = si_setcore(sih, CC_CORE_ID, 0))) {
100		fltype = readl(&cc->capabilities) & CC_CAP_FLASH_MASK;
101		if (fltype == PFLASH) {
102			bcm947xx_map.map_priv_2 = 1;
103			window_addr = 0x1c000000;
104			bcm947xx_map.size = window_size = 32 * 1024 * 1024;
105			if ((readl(&cc->flash_config) & CC_CFG_DS) == 0)
106				bcm947xx_map.bankwidth = 1;
107		}
108	} else {
109		fltype = PFLASH;
110		bcm947xx_map.map_priv_2 = 0;
111		window_addr = WINDOW_ADDR;
112		bcm947xx_map.size = window_size = WINDOW_SIZE;
113	}
114
115	si_setcoreidx(sih, coreidx);
116	spin_unlock_irqrestore(&sih_lock, flags);
117
118	if (fltype != PFLASH) {
119		printk(KERN_ERR "pflash: found no supported devices\n");
120		ret = -ENODEV;
121		goto fail;
122	}
123
124	bcm947xx_map.virt = ioremap(window_addr, window_size);
125	if (bcm947xx_map.virt == NULL) {
126		printk(KERN_ERR "pflash: ioremap failed\n");
127		ret = -EIO;
128		goto fail;
129	}
130
131	if ((bcm947xx_mtd = do_map_probe("cfi_probe", &bcm947xx_map)) == NULL) {
132		printk(KERN_ERR "pflash: cfi_probe failed\n");
133		ret = -ENXIO;
134		goto fail;
135	}
136
137	bcm947xx_mtd->owner = THIS_MODULE;
138	bcm947xx_mtd->mutex = partitions_mutex_init();
139
140	/* Allow size override for testing */
141	size = flash ? : bcm947xx_mtd->size;
142
143	printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", size, window_addr);
144
145#ifdef CONFIG_MTD_PARTITIONS
146	parts = init_mtd_partitions(bcm947xx_mtd, size);
147	for (i = 0; parts[i].name; i++);
148	ret = add_mtd_partitions(bcm947xx_mtd, parts, i);
149	if (ret) {
150		printk(KERN_ERR "pflash: add_mtd_partitions failed\n");
151		goto fail;
152	}
153#endif
154
155	return 0;
156
157 fail:
158	if (bcm947xx_mtd)
159		map_destroy(bcm947xx_mtd);
160	if (bcm947xx_map.map_priv_1)
161		iounmap((void *) bcm947xx_map.map_priv_1);
162	bcm947xx_map.map_priv_1 = 0;
163	return ret;
164}
165
166static void __exit
167cleanup_bcm947xx_map(void)
168{
169#ifdef CONFIG_MTD_PARTITIONS
170	del_mtd_partitions(bcm947xx_mtd);
171#endif
172	map_destroy(bcm947xx_mtd);
173	iounmap((void *) bcm947xx_map.map_priv_1);
174	bcm947xx_map.map_priv_1 = 0;
175}
176
177module_init(init_bcm947xx_map);
178module_exit(cleanup_bcm947xx_map);
179