1/* 2 * Flash mapping for BCM947XX boards 3 * 4 * Copyright 2006, Broadcom Corporation 5 * All Rights Reserved. 6 * 7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY 8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM 9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS 10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. 11 * 12 * $Id: bcm947xx-flash.c,v 1.1.1.1 2008/10/15 03:26:35 james26_jang Exp $ 13 */ 14 15#include <linux/module.h> 16#include <linux/types.h> 17#include <linux/kernel.h> 18#include <asm/io.h> 19#include <linux/mtd/mtd.h> 20#include <linux/mtd/map.h> 21#include <linux/mtd/partitions.h> 22#include <linux/config.h> 23 24#include <typedefs.h> 25#include <bcmnvram.h> 26#include <bcmutils.h> 27#include <sbconfig.h> 28#include <sbchipc.h> 29#include <sbutils.h> 30#include <trxhdr.h> 31 32/* Global SB handle */ 33extern void *bcm947xx_sbh; 34extern spinlock_t bcm947xx_sbh_lock; 35 36/* Convenience */ 37#define sbh bcm947xx_sbh 38#define sbh_lock bcm947xx_sbh_lock 39 40#ifdef CONFIG_MTD_PARTITIONS 41extern struct mtd_partition * init_mtd_partitions(struct mtd_info *mtd, size_t size); 42#endif 43 44#define WINDOW_ADDR 0x1fc00000 45#define WINDOW_SIZE 0x400000 46#define BUSWIDTH 2 47 48/* e.g., flash=2M or flash=4M */ 49static int flash = 0; 50MODULE_PARM(flash, "i"); 51static int __init 52bcm947xx_setup(char *str) 53{ 54 flash = memparse(str, &str); 55 return 1; 56} 57__setup("flash=", bcm947xx_setup); 58 59static struct mtd_info *bcm947xx_mtd; 60 61__u8 bcm947xx_map_read8(struct map_info *map, unsigned long ofs) 62{ 63 if (map->map_priv_2 == 1) 64 return __raw_readb(map->map_priv_1 + ofs); 65 66 u16 val = __raw_readw(map->map_priv_1 + (ofs & ~1)); 67 if (ofs & 1) 68 return ((val >> 8) & 0xff); 69 else 70 return (val & 0xff); 71} 72 73__u16 bcm947xx_map_read16(struct map_info *map, unsigned long ofs) 74{ 75 return __raw_readw(map->map_priv_1 + ofs); 76} 77 78__u32 bcm947xx_map_read32(struct map_info *map, unsigned long ofs) 79{ 80 return __raw_readl(map->map_priv_1 + ofs); 81} 82 83void bcm947xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) 84{ 85 memcpy_fromio(to, map->map_priv_1 + from, len); 86} 87 88void bcm947xx_map_write8(struct map_info *map, __u8 d, unsigned long adr) 89{ 90 __raw_writeb(d, map->map_priv_1 + adr); 91 mb(); 92} 93 94void bcm947xx_map_write16(struct map_info *map, __u16 d, unsigned long adr) 95{ 96 __raw_writew(d, map->map_priv_1 + adr); 97 mb(); 98} 99 100void bcm947xx_map_write32(struct map_info *map, __u32 d, unsigned long adr) 101{ 102 __raw_writel(d, map->map_priv_1 + adr); 103 mb(); 104} 105 106void bcm947xx_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) 107{ 108 memcpy_toio(map->map_priv_1 + to, from, len); 109} 110 111struct map_info bcm947xx_map = { 112 name: "Physically mapped flash", 113 size: WINDOW_SIZE, 114 buswidth: BUSWIDTH, 115 read8: bcm947xx_map_read8, 116 read16: bcm947xx_map_read16, 117 read32: bcm947xx_map_read32, 118 copy_from: bcm947xx_map_copy_from, 119 write8: bcm947xx_map_write8, 120 write16: bcm947xx_map_write16, 121 write32: bcm947xx_map_write32, 122 copy_to: bcm947xx_map_copy_to 123}; 124 125#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE) 126#define init_bcm947xx_map init_module 127#define cleanup_bcm947xx_map cleanup_module 128#endif 129 130mod_init_t init_bcm947xx_map(void) 131{ 132 ulong flags; 133 uint coreidx; 134 chipcregs_t *cc; 135 uint32 fltype; 136 uint window_addr = 0, window_size = 0; 137 size_t size; 138 int ret = 0; 139#ifdef CONFIG_MTD_PARTITIONS 140 struct mtd_partition *parts; 141 int i; 142#endif 143 144 spin_lock_irqsave(&sbh_lock, flags); 145 coreidx = sb_coreidx(sbh); 146 147 /* Check strapping option if chipcommon exists */ 148 if ((cc = sb_setcore(sbh, SB_CC, 0))) { 149 fltype = readl(&cc->capabilities) & CC_CAP_FLASH_MASK; 150 if (fltype == PFLASH) { 151 bcm947xx_map.map_priv_2 = 1; 152 window_addr = 0x1c000000; 153 bcm947xx_map.size = window_size = 32 * 1024 * 1024; 154 if ((readl(&cc->flash_config) & CC_CFG_DS) == 0) 155 bcm947xx_map.buswidth = 1; 156 } 157 } else { 158 fltype = PFLASH; 159 bcm947xx_map.map_priv_2 = 0; 160 window_addr = WINDOW_ADDR; 161 window_size = WINDOW_SIZE; 162 } 163 164 sb_setcoreidx(sbh, coreidx); 165 spin_unlock_irqrestore(&sbh_lock, flags); 166 167 if (fltype != PFLASH) { 168 printk(KERN_ERR "pflash: found no supported devices\n"); 169 ret = -ENODEV; 170 goto fail; 171 } 172 173 bcm947xx_map.map_priv_1 = (unsigned long) ioremap(window_addr, window_size); 174 if (!bcm947xx_map.map_priv_1) { 175 printk(KERN_ERR "pflash: ioremap failed\n"); 176 ret = -EIO; 177 goto fail; 178 } 179 180 if (!(bcm947xx_mtd = do_map_probe("cfi_probe", &bcm947xx_map))) { 181 printk(KERN_ERR "pflash: cfi_probe failed\n"); 182 ret = -ENXIO; 183 goto fail; 184 } 185 186 bcm947xx_mtd->module = THIS_MODULE; 187 188 /* Allow size override for testing */ 189 size = flash ? : bcm947xx_mtd->size; 190 191 printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", size, window_addr); 192 193#ifdef CONFIG_MTD_PARTITIONS 194 parts = init_mtd_partitions(bcm947xx_mtd, size); 195 for (i = 0; parts[i].name; i++); 196 ret = add_mtd_partitions(bcm947xx_mtd, parts, i); 197 if (ret) { 198 printk(KERN_ERR "pflash: add_mtd_partitions failed\n"); 199 goto fail; 200 } 201#endif 202 203 return 0; 204 205 fail: 206 if (bcm947xx_mtd) 207 map_destroy(bcm947xx_mtd); 208 if (bcm947xx_map.map_priv_1) 209 iounmap((void *) bcm947xx_map.map_priv_1); 210 bcm947xx_map.map_priv_1 = 0; 211 return ret; 212} 213 214mod_exit_t cleanup_bcm947xx_map(void) 215{ 216#ifdef CONFIG_MTD_PARTITIONS 217 del_mtd_partitions(bcm947xx_mtd); 218#endif 219 map_destroy(bcm947xx_mtd); 220 iounmap((void *) bcm947xx_map.map_priv_1); 221 bcm947xx_map.map_priv_1 = 0; 222} 223 224module_init(init_bcm947xx_map); 225module_exit(cleanup_bcm947xx_map); 226