parent
0799e77a8b
commit
49edb3c342
@ -0,0 +1,474 @@ |
||||
/*
|
||||
* Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> |
||||
* Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org> |
||||
* Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) |
||||
* |
||||
* original functions for finding root filesystem from Mike Baker
|
||||
* |
||||
* This program is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU General Public License as published by the |
||||
* Free Software Foundation; either version 2 of the License, or (at your |
||||
* option) any later version. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN |
||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
* You should have received a copy of the GNU General Public License along |
||||
* with this program; if not, write to the Free Software Foundation, Inc., |
||||
* 675 Mass Ave, Cambridge, MA 02139, USA. |
||||
*
|
||||
* Copyright 2001-2003, Broadcom Corporation |
||||
* All Rights Reserved. |
||||
*
|
||||
* THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY |
||||
* KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM |
||||
* SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS |
||||
* FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. |
||||
* |
||||
* Flash mapping for BCM947XX boards |
||||
*/ |
||||
|
||||
#include <linux/init.h> |
||||
#include <linux/module.h> |
||||
#include <linux/types.h> |
||||
#include <linux/kernel.h> |
||||
#include <linux/sched.h> |
||||
#include <linux/wait.h> |
||||
#include <linux/mtd/mtd.h> |
||||
#include <linux/mtd/map.h> |
||||
#ifdef CONFIG_MTD_PARTITIONS |
||||
#include <linux/mtd/partitions.h> |
||||
#endif |
||||
#include <linux/crc32.h> |
||||
#ifdef CONFIG_SSB |
||||
#include <linux/ssb/ssb.h> |
||||
#endif |
||||
#include <asm/io.h> |
||||
|
||||
|
||||
#define TRX_MAGIC 0x30524448 /* "HDR0" */ |
||||
#define TRX_VERSION 1 |
||||
#define TRX_MAX_LEN 0x3A0000 |
||||
#define TRX_NO_HEADER 1 /* Do not write TRX header */ |
||||
#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */ |
||||
#define TRX_MAX_OFFSET 3 |
||||
|
||||
struct trx_header { |
||||
u32 magic; /* "HDR0" */ |
||||
u32 len; /* Length of file including header */ |
||||
u32 crc32; /* 32-bit CRC from flag_version to end of file */ |
||||
u32 flag_version; /* 0:15 flags, 16:31 version */ |
||||
u32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */ |
||||
}; |
||||
|
||||
#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y)) |
||||
#define NVRAM_SPACE 0x8000 |
||||
#define WINDOW_ADDR 0x1fc00000 |
||||
#define WINDOW_SIZE 0x400000 |
||||
#define BUSWIDTH 2 |
||||
|
||||
#ifdef CONFIG_SSB |
||||
extern struct ssb_bus ssb_bcm47xx; |
||||
#endif |
||||
static struct mtd_info *bcm47xx_mtd; |
||||
|
||||
static void bcm47xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) |
||||
{ |
||||
if (len==1) { |
||||
memcpy_fromio(to, map->virt + from, len); |
||||
} else { |
||||
int i; |
||||
u16 *dest = (u16 *) to; |
||||
u16 *src = (u16 *) (map->virt + from); |
||||
for (i = 0; i < (len / 2); i++) { |
||||
dest[i] = src[i]; |
||||
} |
||||
if (len & 1) |
||||
*((u8 *)dest+len-1) = src[i] & 0xff; |
||||
} |
||||
} |
||||
|
||||
static struct map_info bcm47xx_map = { |
||||
name: "Physically mapped flash", |
||||
size: WINDOW_SIZE, |
||||
bankwidth: BUSWIDTH, |
||||
phys: WINDOW_ADDR, |
||||
}; |
||||
|
||||
#ifdef CONFIG_MTD_PARTITIONS |
||||
|
||||
static struct mtd_partition bcm47xx_parts[] = { |
||||
{ name: "cfe", offset: 0, size: 0, mask_flags: MTD_WRITEABLE, }, |
||||
{ name: "linux", offset: 0, size: 0, }, |
||||
{ name: "rootfs", offset: 0, size: 0, }, |
||||
{ name: "nvram", offset: 0, size: 0, }, |
||||
{ name: NULL, }, |
||||
}; |
||||
|
||||
static int __init |
||||
find_cfe_size(struct mtd_info *mtd, size_t size) |
||||
{ |
||||
struct trx_header *trx; |
||||
unsigned char buf[512]; |
||||
int off; |
||||
size_t len; |
||||
int blocksize; |
||||
|
||||
trx = (struct trx_header *) buf; |
||||
|
||||
blocksize = mtd->erasesize; |
||||
if (blocksize < 0x10000) |
||||
blocksize = 0x10000; |
||||
|
||||
for (off = (128*1024); off < size; off += blocksize) { |
||||
memset(buf, 0xe5, sizeof(buf)); |
||||
|
||||
/*
|
||||
* Read into buffer
|
||||
*/ |
||||
if (mtd->read(mtd, off, sizeof(buf), &len, buf) || |
||||
len != sizeof(buf)) |
||||
continue; |
||||
|
||||
/* found a TRX header */ |
||||
if (le32_to_cpu(trx->magic) == TRX_MAGIC) { |
||||
goto found; |
||||
} |
||||
} |
||||
|
||||
printk(KERN_NOTICE |
||||
"%s: Couldn't find bootloader size\n", |
||||
mtd->name); |
||||
return -1; |
||||
|
||||
found: |
||||
printk(KERN_NOTICE "bootloader size: %d\n", off); |
||||
return off; |
||||
|
||||
} |
||||
|
||||
/*
|
||||
* Copied from mtdblock.c |
||||
* |
||||
* Cache stuff... |
||||
*
|
||||
* Since typical flash erasable sectors are much larger than what Linux's |
||||
* buffer cache can handle, we must implement read-modify-write on flash |
||||
* sectors for each block write requests. To avoid over-erasing flash sectors |
||||
* and to speed things up, we locally cache a whole flash sector while it is |
||||
* being written to until a different sector is required. |
||||
*/ |
||||
|
||||
static void erase_callback(struct erase_info *done) |
||||
{ |
||||
wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv; |
||||
wake_up(wait_q); |
||||
} |
||||
|
||||
static int erase_write (struct mtd_info *mtd, unsigned long pos,
|
||||
int len, const char *buf) |
||||
{ |
||||
struct erase_info erase; |
||||
DECLARE_WAITQUEUE(wait, current); |
||||
wait_queue_head_t wait_q; |
||||
size_t retlen; |
||||
int ret; |
||||
|
||||
/*
|
||||
* First, let's erase the flash block. |
||||
*/ |
||||
|
||||
init_waitqueue_head(&wait_q); |
||||
erase.mtd = mtd; |
||||
erase.callback = erase_callback; |
||||
erase.addr = pos; |
||||
erase.len = len; |
||||
erase.priv = (u_long)&wait_q; |
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE); |
||||
add_wait_queue(&wait_q, &wait); |
||||
|
||||
ret = mtd->erase(mtd, &erase); |
||||
if (ret) { |
||||
set_current_state(TASK_RUNNING); |
||||
remove_wait_queue(&wait_q, &wait); |
||||
printk (KERN_WARNING "erase of region [0x%lx, 0x%x] " |
||||
"on \"%s\" failed\n", |
||||
pos, len, mtd->name); |
||||
return ret; |
||||
} |
||||
|
||||
schedule(); /* Wait for erase to finish. */ |
||||
remove_wait_queue(&wait_q, &wait); |
||||
|
||||
/*
|
||||
* Next, writhe data to flash. |
||||
*/ |
||||
|
||||
ret = mtd->write (mtd, pos, len, &retlen, buf); |
||||
if (ret) |
||||
return ret; |
||||
if (retlen != len) |
||||
return -EIO; |
||||
return 0; |
||||
} |
||||
|
||||
|
||||
static int __init |
||||
find_dual_image_off (struct mtd_info *mtd, size_t size) |
||||
{ |
||||
struct trx_header trx; |
||||
int off, blocksize; |
||||
size_t len; |
||||
|
||||
blocksize = mtd->erasesize; |
||||
if (blocksize < 0x10000) |
||||
blocksize = 0x10000; |
||||
|
||||
for (off = (128*1024); off < size; off += blocksize) { |
||||
memset(&trx, 0xe5, sizeof(trx)); |
||||
/*
|
||||
* Read into buffer
|
||||
*/ |
||||
if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) || |
||||
len != sizeof(trx)) |
||||
continue; |
||||
/* found last TRX header */ |
||||
if (le32_to_cpu(trx.magic) == TRX_MAGIC){
|
||||
if (le32_to_cpu(trx.flag_version >> 16)==2){ |
||||
printk("dual image TRX header found\n"); |
||||
return size/2; |
||||
} else { |
||||
return 0; |
||||
} |
||||
} |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
|
||||
static int __init |
||||
find_root(struct mtd_info *mtd, size_t size, struct mtd_partition *part) |
||||
{ |
||||
struct trx_header trx, *trx2; |
||||
unsigned char buf[512], *block; |
||||
int off, blocksize; |
||||
u32 i, crc = ~0; |
||||
size_t len; |
||||
|
||||
blocksize = mtd->erasesize; |
||||
if (blocksize < 0x10000) |
||||
blocksize = 0x10000; |
||||
|
||||
for (off = (128*1024); off < size; off += blocksize) { |
||||
memset(&trx, 0xe5, sizeof(trx)); |
||||
|
||||
/*
|
||||
* Read into buffer
|
||||
*/ |
||||
if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) || |
||||
len != sizeof(trx)) |
||||
continue; |
||||
|
||||
/* found a TRX header */ |
||||
if (le32_to_cpu(trx.magic) == TRX_MAGIC) { |
||||
part->offset = le32_to_cpu(trx.offsets[2]) ? :
|
||||
le32_to_cpu(trx.offsets[1]); |
||||
part->size = le32_to_cpu(trx.len);
|
||||
|
||||
part->size -= part->offset; |
||||
part->offset += off; |
||||
|
||||
goto found; |
||||
} |
||||
} |
||||
|
||||
printk(KERN_NOTICE |
||||
"%s: Couldn't find root filesystem\n", |
||||
mtd->name); |
||||
return -1; |
||||
|
||||
found: |
||||
if (part->size == 0) |
||||
return 0; |
||||
|
||||
if (mtd->read(mtd, part->offset, sizeof(buf), &len, buf) || len != sizeof(buf)) |
||||
return 0; |
||||
|
||||
/* Move the fs outside of the trx */ |
||||
part->size = 0; |
||||
|
||||
if (trx.len != part->offset + part->size - off) { |
||||
/* Update the trx offsets and length */ |
||||
trx.len = part->offset + part->size - off; |
||||
|
||||
/* Update the trx crc32 */ |
||||
for (i = (u32) &(((struct trx_header *)NULL)->flag_version); i <= trx.len; i += sizeof(buf)) { |
||||
if (mtd->read(mtd, off + i, sizeof(buf), &len, buf) || len != sizeof(buf)) |
||||
return 0; |
||||
crc = crc32_le(crc, buf, min(sizeof(buf), trx.len - i)); |
||||
} |
||||
trx.crc32 = crc; |
||||
|
||||
/* read first eraseblock from the trx */ |
||||
block = kmalloc(mtd->erasesize, GFP_KERNEL); |
||||
trx2 = (struct trx_header *) block; |
||||
if (mtd->read(mtd, off, mtd->erasesize, &len, block) || len != mtd->erasesize) { |
||||
printk("Error accessing the first trx eraseblock\n"); |
||||
return 0; |
||||
} |
||||
|
||||
printk("Updating TRX offsets and length:\n"); |
||||
printk("old trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx2->offsets[0], trx2->offsets[1], trx2->offsets[2], trx2->len, trx2->crc32); |
||||
printk("new trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx.offsets[0], trx.offsets[1], trx.offsets[2], trx.len, trx.crc32); |
||||
|
||||
/* Write updated trx header to the flash */ |
||||
memcpy(block, &trx, sizeof(trx)); |
||||
if (mtd->unlock) |
||||
mtd->unlock(mtd, off, mtd->erasesize); |
||||
erase_write(mtd, off, mtd->erasesize, block); |
||||
if (mtd->sync) |
||||
mtd->sync(mtd); |
||||
kfree(block); |
||||
printk("Done\n"); |
||||
} |
||||
|
||||
return part->size; |
||||
} |
||||
|
||||
struct mtd_partition * __init |
||||
init_mtd_partitions(struct mtd_info *mtd, size_t size) |
||||
{ |
||||
int cfe_size; |
||||
int dual_image_offset = 0; |
||||
|
||||
if ((cfe_size = find_cfe_size(mtd,size)) < 0) |
||||
return NULL; |
||||
|
||||
/* boot loader */ |
||||
bcm47xx_parts[0].offset = 0; |
||||
bcm47xx_parts[0].size = cfe_size; |
||||
|
||||
/* nvram */ |
||||
if (cfe_size != 384 * 1024) { |
||||
bcm47xx_parts[3].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize); |
||||
bcm47xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize); |
||||
} else { |
||||
/* nvram (old 128kb config partition on netgear wgt634u) */ |
||||
bcm47xx_parts[3].offset = bcm47xx_parts[0].size; |
||||
bcm47xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize); |
||||
} |
||||
|
||||
/* dual image offset*/ |
||||
printk("Looking for dual image\n"); |
||||
dual_image_offset=find_dual_image_off(mtd,size); |
||||
/* linux (kernel and rootfs) */ |
||||
if (cfe_size != 384 * 1024) { |
||||
bcm47xx_parts[1].offset = bcm47xx_parts[0].size; |
||||
bcm47xx_parts[1].size = bcm47xx_parts[3].offset - dual_image_offset - |
||||
bcm47xx_parts[1].offset; |
||||
} else { |
||||
/* do not count the elf loader, which is on one block */ |
||||
bcm47xx_parts[1].offset = bcm47xx_parts[0].size +
|
||||
bcm47xx_parts[3].size + mtd->erasesize; |
||||
bcm47xx_parts[1].size = size -
|
||||
bcm47xx_parts[0].size -
|
||||
(2*bcm47xx_parts[3].size) -
|
||||
mtd->erasesize; |
||||
} |
||||
|
||||
/* find and size rootfs */ |
||||
find_root(mtd,size,&bcm47xx_parts[2]); |
||||
bcm47xx_parts[2].size = size - dual_image_offset - bcm47xx_parts[2].offset - bcm47xx_parts[3].size; |
||||
|
||||
return bcm47xx_parts; |
||||
} |
||||
#endif |
||||
|
||||
int __init init_bcm47xx_map(void) |
||||
{ |
||||
#ifdef CONFIG_SSB |
||||
struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore; |
||||
#endif |
||||
size_t size; |
||||
int ret = 0; |
||||
#ifdef CONFIG_MTD_PARTITIONS |
||||
struct mtd_partition *parts; |
||||
int i; |
||||
#endif |
||||
|
||||
#ifdef CONFIG_SSB |
||||
u32 window = mcore->flash_window; |
||||
u32 window_size = mcore->flash_window_size; |
||||
|
||||
printk("flash init: 0x%08x 0x%08x\n", window, window_size); |
||||
bcm47xx_map.phys = window; |
||||
bcm47xx_map.size = window_size; |
||||
bcm47xx_map.bankwidth = mcore->flash_buswidth; |
||||
bcm47xx_map.virt = ioremap_nocache(window, window_size); |
||||
#else |
||||
printk("flash init: 0x%08x 0x%08x\n", WINDOW_ADDR, WINDOW_SIZE); |
||||
bcm47xx_map.virt = ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE); |
||||
#endif |
||||
|
||||
if (!bcm47xx_map.virt) { |
||||
printk("Failed to ioremap\n"); |
||||
return -EIO; |
||||
} |
||||
|
||||
simple_map_init(&bcm47xx_map); |
||||
|
||||
if (!(bcm47xx_mtd = do_map_probe("cfi_probe", &bcm47xx_map))) { |
||||
printk("Failed to do_map_probe\n"); |
||||
iounmap((void *)bcm47xx_map.virt); |
||||
return -ENXIO; |
||||
} |
||||
|
||||
/* override copy_from routine */ |
||||
bcm47xx_map.copy_from = bcm47xx_map_copy_from; |
||||
|
||||
bcm47xx_mtd->owner = THIS_MODULE; |
||||
|
||||
size = bcm47xx_mtd->size; |
||||
|
||||
printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", size, WINDOW_ADDR); |
||||
|
||||
#ifdef CONFIG_MTD_PARTITIONS |
||||
parts = init_mtd_partitions(bcm47xx_mtd, size); |
||||
for (i = 0; parts[i].name; i++); |
||||
ret = add_mtd_partitions(bcm47xx_mtd, parts, i); |
||||
if (ret) { |
||||
printk(KERN_ERR "Flash: add_mtd_partitions failed\n"); |
||||
goto fail; |
||||
} |
||||
#endif |
||||
return 0; |
||||
|
||||
fail: |
||||
if (bcm47xx_mtd) |
||||
map_destroy(bcm47xx_mtd); |
||||
if (bcm47xx_map.virt) |
||||
iounmap((void *)bcm47xx_map.virt); |
||||
bcm47xx_map.virt = 0; |
||||
return ret; |
||||
} |
||||
|
||||
void __exit cleanup_bcm47xx_map(void) |
||||
{ |
||||
#ifdef CONFIG_MTD_PARTITIONS |
||||
del_mtd_partitions(bcm47xx_mtd); |
||||
#endif |
||||
map_destroy(bcm47xx_mtd); |
||||
iounmap((void *)bcm47xx_map.virt); |
||||
} |
||||
|
||||
module_init(init_bcm47xx_map); |
||||
module_exit(cleanup_bcm47xx_map); |
@ -0,0 +1,474 @@ |
||||
/*
|
||||
* Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> |
||||
* Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org> |
||||
* Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) |
||||
* |
||||
* original functions for finding root filesystem from Mike Baker
|
||||
* |
||||
* This program is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU General Public License as published by the |
||||
* Free Software Foundation; either version 2 of the License, or (at your |
||||
* option) any later version. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN |
||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
* You should have received a copy of the GNU General Public License along |
||||
* with this program; if not, write to the Free Software Foundation, Inc., |
||||
* 675 Mass Ave, Cambridge, MA 02139, USA. |
||||
*
|
||||
* Copyright 2001-2003, Broadcom Corporation |
||||
* All Rights Reserved. |
||||
*
|
||||
* THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY |
||||
* KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM |
||||
* SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS |
||||
* FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. |
||||
* |
||||
* Flash mapping for BCM947XX boards |
||||
*/ |
||||
|
||||
#include <linux/init.h> |
||||
#include <linux/module.h> |
||||
#include <linux/types.h> |
||||
#include <linux/kernel.h> |
||||
#include <linux/sched.h> |
||||
#include <linux/wait.h> |
||||
#include <linux/mtd/mtd.h> |
||||
#include <linux/mtd/map.h> |
||||
#ifdef CONFIG_MTD_PARTITIONS |
||||
#include <linux/mtd/partitions.h> |
||||
#endif |
||||
#include <linux/crc32.h> |
||||
#ifdef CONFIG_SSB |
||||
#include <linux/ssb/ssb.h> |
||||
#endif |
||||
#include <asm/io.h> |
||||
|
||||
|
||||
#define TRX_MAGIC 0x30524448 /* "HDR0" */ |
||||
#define TRX_VERSION 1 |
||||
#define TRX_MAX_LEN 0x3A0000 |
||||
#define TRX_NO_HEADER 1 /* Do not write TRX header */ |
||||
#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */ |
||||
#define TRX_MAX_OFFSET 3 |
||||
|
||||
struct trx_header { |
||||
u32 magic; /* "HDR0" */ |
||||
u32 len; /* Length of file including header */ |
||||
u32 crc32; /* 32-bit CRC from flag_version to end of file */ |
||||
u32 flag_version; /* 0:15 flags, 16:31 version */ |
||||
u32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */ |
||||
}; |
||||
|
||||
#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y)) |
||||
#define NVRAM_SPACE 0x8000 |
||||
#define WINDOW_ADDR 0x1fc00000 |
||||
#define WINDOW_SIZE 0x400000 |
||||
#define BUSWIDTH 2 |
||||
|
||||
#ifdef CONFIG_SSB |
||||
extern struct ssb_bus ssb_bcm47xx; |
||||
#endif |
||||
static struct mtd_info *bcm47xx_mtd; |
||||
|
||||
static void bcm47xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) |
||||
{ |
||||
if (len==1) { |
||||
memcpy_fromio(to, map->virt + from, len); |
||||
} else { |
||||
int i; |
||||
u16 *dest = (u16 *) to; |
||||
u16 *src = (u16 *) (map->virt + from); |
||||
for (i = 0; i < (len / 2); i++) { |
||||
dest[i] = src[i]; |
||||
} |
||||
if (len & 1) |
||||
*((u8 *)dest+len-1) = src[i] & 0xff; |
||||
} |
||||
} |
||||
|
||||
static struct map_info bcm47xx_map = { |
||||
name: "Physically mapped flash", |
||||
size: WINDOW_SIZE, |
||||
bankwidth: BUSWIDTH, |
||||
phys: WINDOW_ADDR, |
||||
}; |
||||
|
||||
#ifdef CONFIG_MTD_PARTITIONS |
||||
|
||||
static struct mtd_partition bcm47xx_parts[] = { |
||||
{ name: "cfe", offset: 0, size: 0, mask_flags: MTD_WRITEABLE, }, |
||||
{ name: "linux", offset: 0, size: 0, }, |
||||
{ name: "rootfs", offset: 0, size: 0, }, |
||||
{ name: "nvram", offset: 0, size: 0, }, |
||||
{ name: NULL, }, |
||||
}; |
||||
|
||||
static int __init |
||||
find_cfe_size(struct mtd_info *mtd, size_t size) |
||||
{ |
||||
struct trx_header *trx; |
||||
unsigned char buf[512]; |
||||
int off; |
||||
size_t len; |
||||
int blocksize; |
||||
|
||||
trx = (struct trx_header *) buf; |
||||
|
||||
blocksize = mtd->erasesize; |
||||
if (blocksize < 0x10000) |
||||
blocksize = 0x10000; |
||||
|
||||
for (off = (128*1024); off < size; off += blocksize) { |
||||
memset(buf, 0xe5, sizeof(buf)); |
||||
|
||||
/*
|
||||
* Read into buffer
|
||||
*/ |
||||
if (mtd->read(mtd, off, sizeof(buf), &len, buf) || |
||||
len != sizeof(buf)) |
||||
continue; |
||||
|
||||
/* found a TRX header */ |
||||
if (le32_to_cpu(trx->magic) == TRX_MAGIC) { |
||||
goto found; |
||||
} |
||||
} |
||||
|
||||
printk(KERN_NOTICE |
||||
"%s: Couldn't find bootloader size\n", |
||||
mtd->name); |
||||
return -1; |
||||
|
||||
found: |
||||
printk(KERN_NOTICE "bootloader size: %d\n", off); |
||||
return off; |
||||
|
||||
} |
||||
|
||||
/*
|
||||
* Copied from mtdblock.c |
||||
* |
||||
* Cache stuff... |
||||
*
|
||||
* Since typical flash erasable sectors are much larger than what Linux's |
||||
* buffer cache can handle, we must implement read-modify-write on flash |
||||
* sectors for each block write requests. To avoid over-erasing flash sectors |
||||
* and to speed things up, we locally cache a whole flash sector while it is |
||||
* being written to until a different sector is required. |
||||
*/ |
||||
|
||||
static void erase_callback(struct erase_info *done) |
||||
{ |
||||
wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv; |
||||
wake_up(wait_q); |
||||
} |
||||
|
||||
static int erase_write (struct mtd_info *mtd, unsigned long pos,
|
||||
int len, const char *buf) |
||||
{ |
||||
struct erase_info erase; |
||||
DECLARE_WAITQUEUE(wait, current); |
||||
wait_queue_head_t wait_q; |
||||
size_t retlen; |
||||
int ret; |
||||
|
||||
/*
|
||||
* First, let's erase the flash block. |
||||
*/ |
||||
|
||||
init_waitqueue_head(&wait_q); |
||||
erase.mtd = mtd; |
||||
erase.callback = erase_callback; |
||||
erase.addr = pos; |
||||
erase.len = len; |
||||
erase.priv = (u_long)&wait_q; |
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE); |
||||
add_wait_queue(&wait_q, &wait); |
||||
|
||||
ret = mtd->erase(mtd, &erase); |
||||
if (ret) { |
||||
set_current_state(TASK_RUNNING); |
||||
remove_wait_queue(&wait_q, &wait); |
||||
printk (KERN_WARNING "erase of region [0x%lx, 0x%x] " |
||||
"on \"%s\" failed\n", |
||||
pos, len, mtd->name); |
||||
return ret; |
||||
} |
||||
|
||||
schedule(); /* Wait for erase to finish. */ |
||||
remove_wait_queue(&wait_q, &wait); |
||||
|
||||
/*
|
||||
* Next, writhe data to flash. |
||||
*/ |
||||
|
||||
ret = mtd->write (mtd, pos, len, &retlen, buf); |
||||
if (ret) |
||||
return ret; |
||||
if (retlen != len) |
||||
return -EIO; |
||||
return 0; |
||||
} |
||||
|
||||
|
||||
static int __init |
||||
find_dual_image_off (struct mtd_info *mtd, size_t size) |
||||
{ |
||||
struct trx_header trx; |
||||
int off, blocksize; |
||||
size_t len; |
||||
|
||||
blocksize = mtd->erasesize; |
||||
if (blocksize < 0x10000) |
||||
blocksize = 0x10000; |
||||
|
||||
for (off = (128*1024); off < size; off += blocksize) { |
||||
memset(&trx, 0xe5, sizeof(trx)); |
||||
/*
|
||||
* Read into buffer
|
||||
*/ |
||||
if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) || |
||||
len != sizeof(trx)) |
||||
continue; |
||||
/* found last TRX header */ |
||||
if (le32_to_cpu(trx.magic) == TRX_MAGIC){
|
||||
if (le32_to_cpu(trx.flag_version >> 16)==2){ |
||||
printk("dual image TRX header found\n"); |
||||
return size/2; |
||||
} else { |
||||
return 0; |
||||
} |
||||
} |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
|
||||
static int __init |
||||
find_root(struct mtd_info *mtd, size_t size, struct mtd_partition *part) |
||||
{ |
||||
struct trx_header trx, *trx2; |
||||
unsigned char buf[512], *block; |
||||
int off, blocksize; |
||||
u32 i, crc = ~0; |
||||
size_t len; |
||||
|
||||
blocksize = mtd->erasesize; |
||||
if (blocksize < 0x10000) |
||||
blocksize = 0x10000; |
||||
|
||||
for (off = (128*1024); off < size; off += blocksize) { |
||||
memset(&trx, 0xe5, sizeof(trx)); |
||||
|
||||
/*
|
||||
* Read into buffer
|
||||
*/ |
||||
if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) || |
||||
len != sizeof(trx)) |
||||
continue; |
||||
|
||||
/* found a TRX header */ |
||||
if (le32_to_cpu(trx.magic) == TRX_MAGIC) { |
||||
part->offset = le32_to_cpu(trx.offsets[2]) ? :
|
||||
le32_to_cpu(trx.offsets[1]); |
||||
part->size = le32_to_cpu(trx.len);
|
||||
|
||||
part->size -= part->offset; |
||||
part->offset += off; |
||||
|
||||
goto found; |
||||
} |
||||
} |
||||
|
||||
printk(KERN_NOTICE |
||||
"%s: Couldn't find root filesystem\n", |
||||
mtd->name); |
||||
return -1; |
||||
|
||||
found: |
||||
if (part->size == 0) |
||||
return 0; |
||||
|
||||
if (mtd->read(mtd, part->offset, sizeof(buf), &len, buf) || len != sizeof(buf)) |
||||
return 0; |
||||
|
||||
/* Move the fs outside of the trx */ |
||||
part->size = 0; |
||||
|
||||
if (trx.len != part->offset + part->size - off) { |
||||
/* Update the trx offsets and length */ |
||||
trx.len = part->offset + part->size - off; |
||||
|
||||
/* Update the trx crc32 */ |
||||
for (i = (u32) &(((struct trx_header *)NULL)->flag_version); i <= trx.len; i += sizeof(buf)) { |
||||
if (mtd->read(mtd, off + i, sizeof(buf), &len, buf) || len != sizeof(buf)) |
||||
return 0; |
||||
crc = crc32_le(crc, buf, min(sizeof(buf), trx.len - i)); |
||||
} |
||||
trx.crc32 = crc; |
||||
|
||||
/* read first eraseblock from the trx */ |
||||
block = kmalloc(mtd->erasesize, GFP_KERNEL); |
||||
trx2 = (struct trx_header *) block; |
||||
if (mtd->read(mtd, off, mtd->erasesize, &len, block) || len != mtd->erasesize) { |
||||
printk("Error accessing the first trx eraseblock\n"); |
||||
return 0; |
||||
} |
||||
|
||||
printk("Updating TRX offsets and length:\n"); |
||||
printk("old trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx2->offsets[0], trx2->offsets[1], trx2->offsets[2], trx2->len, trx2->crc32); |
||||
printk("new trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx.offsets[0], trx.offsets[1], trx.offsets[2], trx.len, trx.crc32); |
||||
|
||||
/* Write updated trx header to the flash */ |
||||
memcpy(block, &trx, sizeof(trx)); |
||||
if (mtd->unlock) |
||||
mtd->unlock(mtd, off, mtd->erasesize); |
||||
erase_write(mtd, off, mtd->erasesize, block); |
||||
if (mtd->sync) |
||||
mtd->sync(mtd); |
||||
kfree(block); |
||||
printk("Done\n"); |
||||
} |
||||
|
||||
return part->size; |
||||
} |
||||
|
||||
struct mtd_partition * __init |
||||
init_mtd_partitions(struct mtd_info *mtd, size_t size) |
||||
{ |
||||
int cfe_size; |
||||
int dual_image_offset = 0; |
||||
|
||||
if ((cfe_size = find_cfe_size(mtd,size)) < 0) |
||||
return NULL; |
||||
|
||||
/* boot loader */ |
||||
bcm47xx_parts[0].offset = 0; |
||||
bcm47xx_parts[0].size = cfe_size; |
||||
|
||||
/* nvram */ |
||||
if (cfe_size != 384 * 1024) { |
||||
bcm47xx_parts[3].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize); |
||||
bcm47xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize); |
||||
} else { |
||||
/* nvram (old 128kb config partition on netgear wgt634u) */ |
||||
bcm47xx_parts[3].offset = bcm47xx_parts[0].size; |
||||
bcm47xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize); |
||||
} |
||||
|
||||
/* dual image offset*/ |
||||
printk("Looking for dual image\n"); |
||||
dual_image_offset=find_dual_image_off(mtd,size); |
||||
/* linux (kernel and rootfs) */ |
||||
if (cfe_size != 384 * 1024) { |
||||
bcm47xx_parts[1].offset = bcm47xx_parts[0].size; |
||||
bcm47xx_parts[1].size = bcm47xx_parts[3].offset - dual_image_offset - |
||||
bcm47xx_parts[1].offset; |
||||
} else { |
||||
/* do not count the elf loader, which is on one block */ |
||||
bcm47xx_parts[1].offset = bcm47xx_parts[0].size +
|
||||
bcm47xx_parts[3].size + mtd->erasesize; |
||||
bcm47xx_parts[1].size = size -
|
||||
bcm47xx_parts[0].size -
|
||||
(2*bcm47xx_parts[3].size) -
|
||||
mtd->erasesize; |
||||
} |
||||
|
||||
/* find and size rootfs */ |
||||
find_root(mtd,size,&bcm47xx_parts[2]); |
||||
bcm47xx_parts[2].size = size - dual_image_offset - bcm47xx_parts[2].offset - bcm47xx_parts[3].size; |
||||
|
||||
return bcm47xx_parts; |
||||
} |
||||
#endif |
||||
|
||||
int __init init_bcm47xx_map(void) |
||||
{ |
||||
#ifdef CONFIG_SSB |
||||
struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore; |
||||
#endif |
||||
size_t size; |
||||
int ret = 0; |
||||
#ifdef CONFIG_MTD_PARTITIONS |
||||
struct mtd_partition *parts; |
||||
int i; |
||||
#endif |
||||
|
||||
#ifdef CONFIG_SSB |
||||
u32 window = mcore->flash_window; |
||||
u32 window_size = mcore->flash_window_size; |
||||
|
||||
printk("flash init: 0x%08x 0x%08x\n", window, window_size); |
||||
bcm47xx_map.phys = window; |
||||
bcm47xx_map.size = window_size; |
||||
bcm47xx_map.bankwidth = mcore->flash_buswidth; |
||||
bcm47xx_map.virt = ioremap_nocache(window, window_size); |
||||
#else |
||||
printk("flash init: 0x%08x 0x%08x\n", WINDOW_ADDR, WINDOW_SIZE); |
||||
bcm47xx_map.virt = ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE); |
||||
#endif |
||||
|
||||
if (!bcm47xx_map.virt) { |
||||
printk("Failed to ioremap\n"); |
||||
return -EIO; |
||||
} |
||||
|
||||
simple_map_init(&bcm47xx_map); |
||||
|
||||
if (!(bcm47xx_mtd = do_map_probe("cfi_probe", &bcm47xx_map))) { |
||||
printk("Failed to do_map_probe\n"); |
||||
iounmap((void *)bcm47xx_map.virt); |
||||
return -ENXIO; |
||||
} |
||||
|
||||
/* override copy_from routine */ |
||||
bcm47xx_map.copy_from = bcm47xx_map_copy_from; |
||||
|
||||
bcm47xx_mtd->owner = THIS_MODULE; |
||||
|
||||
size = bcm47xx_mtd->size; |
||||
|
||||
printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", size, WINDOW_ADDR); |
||||
|
||||
#ifdef CONFIG_MTD_PARTITIONS |
||||
parts = init_mtd_partitions(bcm47xx_mtd, size); |
||||
for (i = 0; parts[i].name; i++); |
||||
ret = add_mtd_partitions(bcm47xx_mtd, parts, i); |
||||
if (ret) { |
||||
printk(KERN_ERR "Flash: add_mtd_partitions failed\n"); |
||||
goto fail; |
||||
} |
||||
#endif |
||||
return 0; |
||||
|
||||
fail: |
||||
if (bcm47xx_mtd) |
||||
map_destroy(bcm47xx_mtd); |
||||
if (bcm47xx_map.virt) |
||||
iounmap((void *)bcm47xx_map.virt); |
||||
bcm47xx_map.virt = 0; |
||||
return ret; |
||||
} |
||||
|
||||
void __exit cleanup_bcm47xx_map(void) |
||||
{ |
||||
#ifdef CONFIG_MTD_PARTITIONS |
||||
del_mtd_partitions(bcm47xx_mtd); |
||||
#endif |
||||
map_destroy(bcm47xx_mtd); |
||||
iounmap((void *)bcm47xx_map.virt); |
||||
} |
||||
|
||||
module_init(init_bcm47xx_map); |
||||
module_exit(cleanup_bcm47xx_map); |
@ -0,0 +1,254 @@ |
||||
commit 121915c4ee0812a14bc8d752bc210d0238d755c1
|
||||
Author: Waldemar Brodkorb <mips@waldemar-brodkorb.de>
|
||||
Date: Tue Jun 8 19:06:01 2010 +0200
|
||||
|
||||
MIPS: BCM47xx: Add NVRAM support devices
|
||||
|
||||
When trying to netboot a Linksys WRT54GS WLAN router, the bootup fails,
|
||||
because of following error message:
|
||||
|
||||
...
|
||||
[ 0.424000] b44: b44.c:v2.0
|
||||
[ 0.424000] b44: Invalid MAC address found in EEPROM
|
||||
[ 0.432000] b44 ssb0:1: Problem fetching invariants of chip,aborting
|
||||
[ 0.436000] b44: probe of ssb0:1 failed with error -22
|
||||
...
|
||||
|
||||
The router uses a CFE bootloader, but most of the needed environment
|
||||
variables for network card initialization, are not available from CFE
|
||||
via printenv and even though not via cfe_getenv().
|
||||
The required environment variables are saved in a special partition
|
||||
in flash memory. The attached patch implement nvram_getenv and enables
|
||||
bootup via NFS root on my router.
|
||||
|
||||
Most of the patch is extracted from the OpenWrt subversion repository and
|
||||
stripped down and cleaned up to just fix this issue.
|
||||
|
||||
[Ralf: sorted out header file inclusions. Lots of unneded headers and such
|
||||
that should have been included.]
|
||||
|
||||
Signed-off-by: Waldemar Brodkorb <wbx@openadk.org>
|
||||
Reviewed-by: Phil Sutter <phil@nwl.cc>
|
||||
To: linux-mips@linux-mips.org
|
||||
Cc: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
Patchwork: http://patchwork.linux-mips.org/patch/1359/
|
||||
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
|
||||
|
||||
--- a/arch/mips/bcm47xx/Makefile
|
||||
+++ b/arch/mips/bcm47xx/Makefile
|
||||
@@ -3,4 +3,4 @@
|
||||
# under Linux.
|
||||
#
|
||||
|
||||
-obj-y := gpio.o irq.o prom.o serial.o setup.o time.o wgt634u.o
|
||||
+obj-y := gpio.o irq.o nvram.o prom.o serial.o setup.o time.o wgt634u.o
|
||||
--- /dev/null
|
||||
+++ b/arch/mips/bcm47xx/nvram.c
|
||||
@@ -0,0 +1,94 @@
|
||||
+/*
|
||||
+ * BCM947xx nvram variable access
|
||||
+ *
|
||||
+ * Copyright (C) 2005 Broadcom Corporation
|
||||
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it
|
||||
+ * under the terms of the GNU General Public License as published by the
|
||||
+ * Free Software Foundation; either version 2 of the License, or (at your
|
||||
+ * option) any later version.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/types.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/ssb/ssb.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/string.h>
|
||||
+#include <asm/addrspace.h>
|
||||
+#include <asm/mach-bcm47xx/nvram.h>
|
||||
+#include <asm/mach-bcm47xx/bcm47xx.h>
|
||||
+
|
||||
+static char nvram_buf[NVRAM_SPACE];
|
||||
+
|
||||
+/* Probe for NVRAM header */
|
||||
+static void __init early_nvram_init(void)
|
||||
+{
|
||||
+ struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
|
||||
+ struct nvram_header *header;
|
||||
+ int i;
|
||||
+ u32 base, lim, off;
|
||||
+ u32 *src, *dst;
|
||||
+
|
||||
+ base = mcore->flash_window;
|
||||
+ lim = mcore->flash_window_size;
|
||||
+
|
||||
+ off = FLASH_MIN;
|
||||
+ while (off <= lim) {
|
||||
+ /* Windowed flash access */
|
||||
+ header = (struct nvram_header *)
|
||||
+ KSEG1ADDR(base + off - NVRAM_SPACE);
|
||||
+ if (header->magic == NVRAM_HEADER)
|
||||
+ goto found;
|
||||
+ off <<= 1;
|
||||
+ }
|
||||
+
|
||||
+ /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
|
||||
+ header = (struct nvram_header *) KSEG1ADDR(base + 4096);
|
||||
+ if (header->magic == NVRAM_HEADER)
|
||||
+ goto found;
|
||||
+
|
||||
+ header = (struct nvram_header *) KSEG1ADDR(base + 1024);
|
||||
+ if (header->magic == NVRAM_HEADER)
|
||||
+ goto found;
|
||||
+
|
||||
+ return;
|
||||
+
|
||||
+found:
|
||||
+ src = (u32 *) header;
|
||||
+ dst = (u32 *) nvram_buf;
|
||||
+ for (i = 0; i < sizeof(struct nvram_header); i += 4)
|
||||
+ *dst++ = *src++;
|
||||
+ for (; i < header->len && i < NVRAM_SPACE; i += 4)
|
||||
+ *dst++ = le32_to_cpu(*src++);
|
||||
+}
|
||||
+
|
||||
+int nvram_getenv(char *name, char *val, size_t val_len)
|
||||
+{
|
||||
+ char *var, *value, *end, *eq;
|
||||
+
|
||||
+ if (!name)
|
||||
+ return 1;
|
||||
+
|
||||
+ if (!nvram_buf[0])
|
||||
+ early_nvram_init();
|
||||
+
|
||||
+ /* Look for name=value and return value */
|
||||
+ var = &nvram_buf[sizeof(struct nvram_header)];
|
||||
+ end = nvram_buf + sizeof(nvram_buf) - 2;
|
||||
+ end[0] = end[1] = '\0';
|
||||
+ for (; *var; var = value + strlen(value) + 1) {
|
||||
+ eq = strchr(var, '=');
|
||||
+ if (!eq)
|
||||
+ break;
|
||||
+ value = eq + 1;
|
||||
+ if ((eq - var) == strlen(name) &&
|
||||
+ strncmp(var, name, (eq - var)) == 0) {
|
||||
+ snprintf(val, val_len, "%s", value);
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+ return 1;
|
||||
+}
|
||||
+EXPORT_SYMBOL(nvram_getenv);
|
||||
--- a/arch/mips/bcm47xx/setup.c
|
||||
+++ b/arch/mips/bcm47xx/setup.c
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org>
|
||||
- * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org>
|
||||
* Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
|
||||
* Copyright (C) 2006 Michael Buesch <mb@bu3sch.de>
|
||||
+ * Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <asm/time.h>
|
||||
#include <bcm47xx.h>
|
||||
#include <asm/fw/cfe/cfe_api.h>
|
||||
+#include <asm/mach-bcm47xx/nvram.h>
|
||||
|
||||
struct ssb_bus ssb_bcm47xx;
|
||||
EXPORT_SYMBOL(ssb_bcm47xx);
|
||||
@@ -81,28 +82,42 @@ static int bcm47xx_get_invariants(struct
|
||||
/* Fill boardinfo structure */
|
||||
memset(&(iv->boardinfo), 0 , sizeof(struct ssb_boardinfo));
|
||||
|
||||
- if (cfe_getenv("boardvendor", buf, sizeof(buf)) >= 0)
|
||||
+ if (cfe_getenv("boardvendor", buf, sizeof(buf)) >= 0 ||
|
||||
+ nvram_getenv("boardvendor", buf, sizeof(buf)) >= 0)
|
||||
iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0);
|
||||
- if (cfe_getenv("boardtype", buf, sizeof(buf)) >= 0)
|
||||
+ if (cfe_getenv("boardtype", buf, sizeof(buf)) >= 0 ||
|
||||
+ nvram_getenv("boardtype", buf, sizeof(buf)) >= 0)
|
||||
iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0);
|
||||
- if (cfe_getenv("boardrev", buf, sizeof(buf)) >= 0)
|
||||
+ if (cfe_getenv("boardrev", buf, sizeof(buf)) >= 0 ||
|
||||
+ nvram_getenv("boardrev", buf, sizeof(buf)) >= 0)
|
||||
iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0);
|
||||
|
||||
/* Fill sprom structure */
|
||||
memset(&(iv->sprom), 0, sizeof(struct ssb_sprom));
|
||||
iv->sprom.revision = 3;
|
||||
|
||||
- if (cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0)
|
||||
+ if (cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0 ||
|
||||
+ nvram_getenv("et0macaddr", buf, sizeof(buf)) >= 0)
|
||||
str2eaddr(buf, iv->sprom.et0mac);
|
||||
- if (cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0)
|
||||
+
|
||||
+ if (cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0 ||
|
||||
+ nvram_getenv("et1macaddr", buf, sizeof(buf)) >= 0)
|
||||
str2eaddr(buf, iv->sprom.et1mac);
|
||||
- if (cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0)
|
||||
- iv->sprom.et0phyaddr = simple_strtoul(buf, NULL, 10);
|
||||
- if (cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0)
|
||||
- iv->sprom.et1phyaddr = simple_strtoul(buf, NULL, 10);
|
||||
- if (cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0)
|
||||
+
|
||||
+ if (cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0 ||
|
||||
+ nvram_getenv("et0phyaddr", buf, sizeof(buf)) >= 0)
|
||||
+ iv->sprom.et0phyaddr = simple_strtoul(buf, NULL, 0);
|
||||
+
|
||||
+ if (cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0 ||
|
||||
+ nvram_getenv("et1phyaddr", buf, sizeof(buf)) >= 0)
|
||||
+ iv->sprom.et1phyaddr = simple_strtoul(buf, NULL, 0);
|
||||
+
|
||||
+ if (cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0 ||
|
||||
+ nvram_getenv("et0mdcport", buf, sizeof(buf)) >= 0)
|
||||
iv->sprom.et0mdcport = simple_strtoul(buf, NULL, 10);
|
||||
- if (cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0)
|
||||
+
|
||||
+ if (cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0 ||
|
||||
+ nvram_getenv("et1mdcport", buf, sizeof(buf)) >= 0)
|
||||
iv->sprom.et1mdcport = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
return 0;
|
||||
--- /dev/null
|
||||
+++ b/arch/mips/include/asm/mach-bcm47xx/nvram.h
|
||||
@@ -0,0 +1,36 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2005, Broadcom Corporation
|
||||
+ * Copyright (C) 2006, Felix Fietkau <nbd@openwrt.org>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it
|
||||
+ * under the terms of the GNU General Public License as published by the
|
||||
+ * Free Software Foundation; either version 2 of the License, or (at your
|
||||
+ * option) any later version.
|
||||
+ */
|
||||
+
|
||||
+#ifndef __NVRAM_H
|
||||
+#define __NVRAM_H
|
||||
+
|
||||
+#include <linux/types.h>
|
||||
+
|
||||
+struct nvram_header {
|
||||
+ u32 magic;
|
||||
+ u32 len;
|
||||
+ u32 crc_ver_init; /* 0:7 crc, 8:15 ver, 16:31 sdram_init */
|
||||
+ u32 config_refresh; /* 0:15 sdram_config, 16:31 sdram_refresh */
|
||||
+ u32 config_ncdl; /* ncdl values for memc */
|
||||
+};
|
||||
+
|
||||
+#define NVRAM_HEADER 0x48534C46 /* 'FLSH' */
|
||||
+#define NVRAM_VERSION 1
|
||||
+#define NVRAM_HEADER_SIZE 20
|
||||
+#define NVRAM_SPACE 0x8000
|
||||
+
|
||||
+#define FLASH_MIN 0x00020000 /* Minimum flash size */
|
||||
+
|
||||
+#define NVRAM_MAX_VALUE_LEN 255
|
||||
+#define NVRAM_MAX_PARAM_LEN 64
|
||||
+
|
||||
+extern int nvram_getenv(char *name, char *val, size_t val_len);
|
||||
+
|
||||
+#endif
|
@ -1,3 +1,24 @@ |
||||
From b6d850fe4035d6bee7199119358e06f802aa19ed Mon Sep 17 00:00:00 2001
|
||||
From: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
Date: Sun, 18 Jul 2010 12:49:41 +0200
|
||||
Subject: [PATCH 1/5] MIPS: BCM47xx: Really fix 128MB RAM problem
|
||||
|
||||
The previews patch 84a6fcb368a080620d12fc4d79e07902dbee7335 was wrong,
|
||||
I got wrong success reports.
|
||||
|
||||
The bcm47xx architecture maps the ram into a 128MB address space. It
|
||||
will be paced there as often as goes into the 128MB. The detection
|
||||
tries to find the position where the same memory is found. When reading
|
||||
over 128MB the processor will throw an exception. If 128MB ram is
|
||||
installed, it will not find the same memory because it tries to read
|
||||
over the 128MB boarder. Now it just assumes 128MB installed ram if it
|
||||
can not find that the ram is repeating.
|
||||
|
||||
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
---
|
||||
arch/mips/bcm47xx/prom.c | 22 ++++++++++++++--------
|
||||
1 files changed, 14 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/arch/mips/bcm47xx/prom.c
|
||||
+++ b/arch/mips/bcm47xx/prom.c
|
||||
@@ -126,6 +126,7 @@ static __init void prom_init_cmdline(voi
|
@ -0,0 +1,158 @@ |
||||
From d6c049e08568aac29fff854ea0385e63c7150e09 Mon Sep 17 00:00:00 2001
|
||||
From: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
Date: Sun, 18 Jul 2010 13:34:32 +0200
|
||||
Subject: [PATCH 2/5] MIPS: BCM47xx: Fill more values into ssb sprom
|
||||
|
||||
Most of the values are stored in the nvram and not in the CFE. At first
|
||||
the nvram should be read and if there is no value it should look into
|
||||
the CFE. Now more values are read out because the b43 and b43legacy
|
||||
drivers needs them.
|
||||
|
||||
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
---
|
||||
arch/mips/bcm47xx/setup.c | 122 +++++++++++++++++++++++++++++++++------------
|
||||
1 files changed, 89 insertions(+), 33 deletions(-)
|
||||
|
||||
--- a/arch/mips/bcm47xx/setup.c
|
||||
+++ b/arch/mips/bcm47xx/setup.c
|
||||
@@ -74,6 +74,86 @@ static void str2eaddr(char *str, char *d
|
||||
}
|
||||
}
|
||||
|
||||
+static void bcm47xx_fill_sprom(struct ssb_sprom *sprom)
|
||||
+{
|
||||
+ char buf[100];
|
||||
+
|
||||
+ memset(sprom, 0, sizeof(struct ssb_sprom));
|
||||
+
|
||||
+ sprom->revision = 3;
|
||||
+ if (nvram_getenv("il0macaddr", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("il0macaddr", buf, sizeof(buf)) >= 0)
|
||||
+ str2eaddr(buf, sprom->il0mac);
|
||||
+ if (nvram_getenv("et0macaddr", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0)
|
||||
+ str2eaddr(buf, sprom->et0mac);
|
||||
+ if (nvram_getenv("et1macaddr", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0)
|
||||
+ str2eaddr(buf, sprom->et1mac);
|
||||
+ if (nvram_getenv("et0phyaddr", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->et0phyaddr = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("et1phyaddr", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->et1phyaddr = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("et0mdcport", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->et0mdcport = !!simple_strtoul(buf, NULL, 10);
|
||||
+ if (nvram_getenv("et1mdcport", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->et1mdcport = !!simple_strtoul(buf, NULL, 10);
|
||||
+ if (nvram_getenv("pa0b0", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("pa0b0", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->pa0b0 = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("pa0b1", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("pa0b1", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->pa0b1 = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("pa0b2", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("pa0b2", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->pa0b2 = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("pa1b0", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("pa1b0", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->pa1b0 = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("pa1b1", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("pa1b1", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->pa1b1 = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("pa1b2", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("pa1b2", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->pa1b2 = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("wl0gpio0", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("wl0gpio0", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->gpio0 = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("wl0gpio1", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("wl0gpio1", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->gpio1 = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("wl0gpio2", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("wl0gpio2", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->gpio2 = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("wl0gpio3", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("wl0gpio3", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->gpio3 = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("pa0maxpwr", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("pa0maxpwr", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->maxpwr_bg = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("pa1maxpwr", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("pa1maxpwr", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->maxpwr_a = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("pa0itssit", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("pa0itssit", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->itssi_bg = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("pa1itssit", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("pa1itssit", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->itssi_a = simple_strtoul(buf, NULL, 0);
|
||||
+ sprom->boardflags_lo = 0;
|
||||
+ if (nvram_getenv("boardflags", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("boardflags", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->boardflags_lo = simple_strtoul(buf, NULL, 0);
|
||||
+ sprom->boardflags_hi = 0;
|
||||
+ if (nvram_getenv("boardflags", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("boardflags", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->boardflags_hi = simple_strtoul(buf, NULL, 0);
|
||||
+}
|
||||
+
|
||||
static int bcm47xx_get_invariants(struct ssb_bus *bus,
|
||||
struct ssb_init_invariants *iv)
|
||||
{
|
||||
@@ -82,43 +162,19 @@ static int bcm47xx_get_invariants(struct
|
||||
/* Fill boardinfo structure */
|
||||
memset(&(iv->boardinfo), 0 , sizeof(struct ssb_boardinfo));
|
||||
|
||||
- if (cfe_getenv("boardvendor", buf, sizeof(buf)) >= 0 ||
|
||||
- nvram_getenv("boardvendor", buf, sizeof(buf)) >= 0)
|
||||
+ iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM;
|
||||
+ if (nvram_getenv("boardtype", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("boardtype", buf, sizeof(buf)) >= 0)
|
||||
iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0);
|
||||
- if (cfe_getenv("boardtype", buf, sizeof(buf)) >= 0 ||
|
||||
- nvram_getenv("boardtype", buf, sizeof(buf)) >= 0)
|
||||
- iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0);
|
||||
- if (cfe_getenv("boardrev", buf, sizeof(buf)) >= 0 ||
|
||||
- nvram_getenv("boardrev", buf, sizeof(buf)) >= 0)
|
||||
+ if (nvram_getenv("boardrev", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("boardrev", buf, sizeof(buf)) >= 0)
|
||||
iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0);
|
||||
|
||||
- /* Fill sprom structure */
|
||||
- memset(&(iv->sprom), 0, sizeof(struct ssb_sprom));
|
||||
- iv->sprom.revision = 3;
|
||||
-
|
||||
- if (cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0 ||
|
||||
- nvram_getenv("et0macaddr", buf, sizeof(buf)) >= 0)
|
||||
- str2eaddr(buf, iv->sprom.et0mac);
|
||||
-
|
||||
- if (cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0 ||
|
||||
- nvram_getenv("et1macaddr", buf, sizeof(buf)) >= 0)
|
||||
- str2eaddr(buf, iv->sprom.et1mac);
|
||||
-
|
||||
- if (cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0 ||
|
||||
- nvram_getenv("et0phyaddr", buf, sizeof(buf)) >= 0)
|
||||
- iv->sprom.et0phyaddr = simple_strtoul(buf, NULL, 0);
|
||||
-
|
||||
- if (cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0 ||
|
||||
- nvram_getenv("et1phyaddr", buf, sizeof(buf)) >= 0)
|
||||
- iv->sprom.et1phyaddr = simple_strtoul(buf, NULL, 0);
|
||||
-
|
||||
- if (cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0 ||
|
||||
- nvram_getenv("et0mdcport", buf, sizeof(buf)) >= 0)
|
||||
- iv->sprom.et0mdcport = simple_strtoul(buf, NULL, 10);
|
||||
-
|
||||
- if (cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0 ||
|
||||
- nvram_getenv("et1mdcport", buf, sizeof(buf)) >= 0)
|
||||
- iv->sprom.et1mdcport = simple_strtoul(buf, NULL, 10);
|
||||
+ bcm47xx_fill_sprom(&iv->sprom);
|
||||
+
|
||||
+ if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("cardbus", buf, sizeof(buf)) >= 0)
|
||||
+ iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10);
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,23 @@ |
||||
From b1a0abc936bf61689d1e8a56c423b232cff24da5 Mon Sep 17 00:00:00 2001
|
||||
From: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
Date: Sun, 18 Jul 2010 13:58:09 +0200
|
||||
Subject: [PATCH 3/5] MIPS: BCM47xx: Activate SSB_B43_PCI_BRIDGE by default
|
||||
|
||||
The b43_pci_bridge is needed to use the b43 driver with brcm47xx.
|
||||
Activate it by default if pci is available.
|
||||
|
||||
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
---
|
||||
arch/mips/Kconfig | 1 +
|
||||
1 files changed, 1 insertions(+), 0 deletions(-)
|
||||
|
||||
--- a/arch/mips/Kconfig
|
||||
+++ b/arch/mips/Kconfig
|
||||
@@ -62,6 +62,7 @@ config BCM47XX
|
||||
select SSB_DRIVER_MIPS
|
||||
select SSB_DRIVER_EXTIF
|
||||
select SSB_EMBEDDED
|
||||
+ select SSB_B43_PCI_BRIDGE if PCI
|
||||
select SSB_PCICORE_HOSTMODE if PCI
|
||||
select GENERIC_GPIO
|
||||
select SYS_HAS_EARLY_PRINTK
|
@ -0,0 +1,81 @@ |
||||
From 4c6a515310f29c89f25a54a115cde905f97330f8 Mon Sep 17 00:00:00 2001
|
||||
From: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
Date: Sun, 18 Jul 2010 14:59:24 +0200
|
||||
Subject: [PATCH 4/5] MIPS: BCM47xx: Setup and register serial early
|
||||
|
||||
Swap the first and second serial if console=ttyS1 was set.
|
||||
Set it up and register it for early serial support.
|
||||
|
||||
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
---
|
||||
arch/mips/Kconfig | 1 -
|
||||
arch/mips/bcm47xx/setup.c | 36 +++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 35 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/arch/mips/Kconfig
|
||||
+++ b/arch/mips/Kconfig
|
||||
@@ -65,7 +65,6 @@ config BCM47XX
|
||||
select SSB_B43_PCI_BRIDGE if PCI
|
||||
select SSB_PCICORE_HOSTMODE if PCI
|
||||
select GENERIC_GPIO
|
||||
- select SYS_HAS_EARLY_PRINTK
|
||||
select CFE
|
||||
help
|
||||
Support for BCM47XX based boards
|
||||
--- a/arch/mips/bcm47xx/setup.c
|
||||
+++ b/arch/mips/bcm47xx/setup.c
|
||||
@@ -28,6 +28,8 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/ssb/ssb.h>
|
||||
#include <linux/ssb/ssb_embedded.h>
|
||||
+#include <linux/serial.h>
|
||||
+#include <linux/serial_8250.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/reboot.h>
|
||||
#include <asm/time.h>
|
||||
@@ -181,12 +183,44 @@ static int bcm47xx_get_invariants(struct
|
||||
|
||||
void __init plat_mem_setup(void)
|
||||
{
|
||||
- int err;
|
||||
+ int i, err;
|
||||
+ char buf[100];
|
||||
+ struct ssb_mipscore *mcore;
|
||||
|
||||
err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE,
|
||||
bcm47xx_get_invariants);
|
||||
if (err)
|
||||
panic("Failed to initialize SSB bus (err %d)\n", err);
|
||||
+ mcore = &ssb_bcm47xx.mipscore;
|
||||
+
|
||||
+ nvram_getenv("kernel_args", buf, sizeof(buf));
|
||||
+ if (!strncmp(buf, "console=ttyS1", 13)) {
|
||||
+ struct ssb_serial_port port;
|
||||
+
|
||||
+ printk("Swapping serial ports!\n");
|
||||
+ /* swap serial ports */
|
||||
+ memcpy(&port, &mcore->serial_ports[0], sizeof(port));
|
||||
+ memcpy(&mcore->serial_ports[0], &mcore->serial_ports[1], sizeof(port));
|
||||
+ memcpy(&mcore->serial_ports[1], &port, sizeof(port));
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < mcore->nr_serial_ports; i++) {
|
||||
+ struct ssb_serial_port *port = &(mcore->serial_ports[i]);
|
||||
+ struct uart_port s;
|
||||
+
|
||||
+ memset(&s, 0, sizeof(s));
|
||||
+ s.line = i;
|
||||
+ s.mapbase = (unsigned int) port->regs;
|
||||
+ s.membase = port->regs;
|
||||
+ s.irq = port->irq + 2;
|
||||
+ s.uartclk = port->baud_base;
|
||||
+ s.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
|
||||
+ s.iotype = SERIAL_IO_MEM;
|
||||
+ s.regshift = port->reg_shift;
|
||||
+
|
||||
+ early_serial_setup(&s);
|
||||
+ }
|
||||
+ printk("Serial init done.\n");
|
||||
|
||||
_machine_restart = bcm47xx_machine_restart;
|
||||
_machine_halt = bcm47xx_machine_halt;
|
@ -0,0 +1,130 @@ |
||||
From 6bd2c73ed31a2dfe7eab04d32c17318a5c62f9d4 Mon Sep 17 00:00:00 2001
|
||||
From: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
Date: Sun, 18 Jul 2010 15:11:26 +0200
|
||||
Subject: [PATCH 5/5] MIPS: BCM47xx: Remove CFE console
|
||||
|
||||
Do not use the CFE console. It causes hangs on some devices like the
|
||||
Buffalo WHR-HP-G54.
|
||||
This was reported in https://dev.openwrt.org/ticket/4061 and
|
||||
https://forum.openwrt.org/viewtopic.php?id=17063
|
||||
|
||||
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
---
|
||||
arch/mips/bcm47xx/prom.c | 82 +++------------------------------------------
|
||||
1 files changed, 6 insertions(+), 76 deletions(-)
|
||||
|
||||
--- a/arch/mips/bcm47xx/prom.c
|
||||
+++ b/arch/mips/bcm47xx/prom.c
|
||||
@@ -31,96 +31,28 @@
|
||||
#include <asm/fw/cfe/cfe_api.h>
|
||||
#include <asm/fw/cfe/cfe_error.h>
|
||||
|
||||
-static int cfe_cons_handle;
|
||||
-
|
||||
const char *get_system_type(void)
|
||||
{
|
||||
return "Broadcom BCM47XX";
|
||||
}
|
||||
|
||||
-void prom_putchar(char c)
|
||||
-{
|
||||
- while (cfe_write(cfe_cons_handle, &c, 1) == 0)
|
||||
- ;
|
||||
-}
|
||||
-
|
||||
-static __init void prom_init_cfe(void)
|
||||
+static __init int prom_init_cfe(void)
|
||||
{
|
||||
uint32_t cfe_ept;
|
||||
uint32_t cfe_handle;
|
||||
uint32_t cfe_eptseal;
|
||||
- int argc = fw_arg0;
|
||||
- char **envp = (char **) fw_arg2;
|
||||
- int *prom_vec = (int *) fw_arg3;
|
||||
-
|
||||
- /*
|
||||
- * Check if a loader was used; if NOT, the 4 arguments are
|
||||
- * what CFE gives us (handle, 0, EPT and EPTSEAL)
|
||||
- */
|
||||
- if (argc < 0) {
|
||||
- cfe_handle = (uint32_t)argc;
|
||||
- cfe_ept = (uint32_t)envp;
|
||||
- cfe_eptseal = (uint32_t)prom_vec;
|
||||
- } else {
|
||||
- if ((int)prom_vec < 0) {
|
||||
- /*
|
||||
- * Old loader; all it gives us is the handle,
|
||||
- * so use the "known" entrypoint and assume
|
||||
- * the seal.
|
||||
- */
|
||||
- cfe_handle = (uint32_t)prom_vec;
|
||||
- cfe_ept = 0xBFC00500;
|
||||
- cfe_eptseal = CFE_EPTSEAL;
|
||||
- } else {
|
||||
- /*
|
||||
- * Newer loaders bundle the handle/ept/eptseal
|
||||
- * Note: prom_vec is in the loader's useg
|
||||
- * which is still alive in the TLB.
|
||||
- */
|
||||
- cfe_handle = prom_vec[0];
|
||||
- cfe_ept = prom_vec[2];
|
||||
- cfe_eptseal = prom_vec[3];
|
||||
- }
|
||||
- }
|
||||
+
|
||||
+ cfe_eptseal = (uint32_t) fw_arg3;
|
||||
+ cfe_handle = (uint32_t) fw_arg0;
|
||||
+ cfe_ept = (uint32_t) fw_arg2;
|
||||
|
||||
if (cfe_eptseal != CFE_EPTSEAL) {
|
||||
- /* too early for panic to do any good */
|
||||
printk(KERN_ERR "CFE's entrypoint seal doesn't match.");
|
||||
- while (1) ;
|
||||
+ return -1;
|
||||
}
|
||||
|
||||
cfe_init(cfe_handle, cfe_ept);
|
||||
-}
|
||||
-
|
||||
-static __init void prom_init_console(void)
|
||||
-{
|
||||
- /* Initialize CFE console */
|
||||
- cfe_cons_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
|
||||
-}
|
||||
-
|
||||
-static __init void prom_init_cmdline(void)
|
||||
-{
|
||||
- static char buf[COMMAND_LINE_SIZE] __initdata;
|
||||
-
|
||||
- /* Get the kernel command line from CFE */
|
||||
- if (cfe_getenv("LINUX_CMDLINE", buf, COMMAND_LINE_SIZE) >= 0) {
|
||||
- buf[COMMAND_LINE_SIZE - 1] = 0;
|
||||
- strcpy(arcs_cmdline, buf);
|
||||
- }
|
||||
-
|
||||
- /* Force a console handover by adding a console= argument if needed,
|
||||
- * as CFE is not available anymore later in the boot process. */
|
||||
- if ((strstr(arcs_cmdline, "console=")) == NULL) {
|
||||
- /* Try to read the default serial port used by CFE */
|
||||
- if ((cfe_getenv("BOOT_CONSOLE", buf, COMMAND_LINE_SIZE) < 0)
|
||||
- || (strncmp("uart", buf, 4)))
|
||||
- /* Default to uart0 */
|
||||
- strcpy(buf, "uart0");
|
||||
-
|
||||
- /* Compute the new command line */
|
||||
- snprintf(arcs_cmdline, COMMAND_LINE_SIZE, "%s console=ttyS%c,115200",
|
||||
- arcs_cmdline, buf[4]);
|
||||
- }
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static __init void prom_init_mem(void)
|
||||
@@ -161,8 +93,6 @@ static __init void prom_init_mem(void)
|
||||
void __init prom_init(void)
|
||||
{
|
||||
prom_init_cfe();
|
||||
- prom_init_console();
|
||||
- prom_init_cmdline();
|
||||
prom_init_mem();
|
||||
}
|
||||
|
@ -0,0 +1,95 @@ |
||||
From cb33ffbdd8491c58b35958ec74c39b3a5c7fabe8 Mon Sep 17 00:00:00 2001
|
||||
From: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
Date: Sun, 18 Jul 2010 21:25:03 +0200
|
||||
Subject: [PATCH 1/2] USB: Add USB 2.0 to ssb ohci driver
|
||||
|
||||
This adds USB 2.0 support to ssb ohci driver.
|
||||
This work was done based on Braodcom source code in the OpenWRT project.
|
||||
|
||||
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
---
|
||||
drivers/usb/host/ohci-ssb.c | 55 ++++++++++++++++++++++++++++++++++++++++--
|
||||
1 files changed, 52 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/usb/host/ohci-ssb.c
|
||||
+++ b/drivers/usb/host/ohci-ssb.c
|
||||
@@ -92,9 +92,12 @@ static const struct hc_driver ssb_ohci_h
|
||||
static void ssb_ohci_detach(struct ssb_device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = ssb_get_drvdata(dev);
|
||||
+ if (hcd->driver->shutdown)
|
||||
+ hcd->driver->shutdown(hcd);
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
iounmap(hcd->regs);
|
||||
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
usb_put_hcd(hcd);
|
||||
ssb_device_disable(dev, 0);
|
||||
}
|
||||
@@ -106,10 +109,55 @@ static int ssb_ohci_attach(struct ssb_de
|
||||
int err = -ENOMEM;
|
||||
u32 tmp, flags = 0;
|
||||
|
||||
- if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV)
|
||||
- flags |= SSB_OHCI_TMSLOW_HOSTMODE;
|
||||
+ if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) ||
|
||||
+ dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32)))
|
||||
+ return -EOPNOTSUPP;
|
||||
|
||||
- ssb_device_enable(dev, flags);
|
||||
+ if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) {
|
||||
+ /* Put the device into host-mode. */
|
||||
+ flags |= SSB_OHCI_TMSLOW_HOSTMODE;
|
||||
+ ssb_device_enable(dev, flags);
|
||||
+ } else if (dev->id.coreid == SSB_DEV_USB20_HOST) {
|
||||
+ /*
|
||||
+ * USB 2.0 special considerations:
|
||||
+ *
|
||||
+ * 1. Since the core supports both ehci and EHCI functions, it must
|
||||
+ * only be reset once.
|
||||
+ *
|
||||
+ * 2. In addition to the standard SSB reset sequence, the Host Control
|
||||
+ * Register must be programmed to bring the USB core and various
|
||||
+ * phy components out of reset.
|
||||
+ */
|
||||
+ ssb_device_enable(dev, 0);
|
||||
+ ssb_write32(dev, 0x200, 0x7ff);
|
||||
+
|
||||
+ /* Change Flush control reg */
|
||||
+ tmp = ssb_read32(dev, 0x400);
|
||||
+ tmp &= ~8;
|
||||
+ ssb_write32(dev, 0x400, tmp);
|
||||
+ tmp = ssb_read32(dev, 0x400);
|
||||
+
|
||||
+ /* Change Shim control reg */
|
||||
+ tmp = ssb_read32(dev, 0x304);
|
||||
+ tmp &= ~0x100;
|
||||
+ ssb_write32(dev, 0x304, tmp);
|
||||
+ tmp = ssb_read32(dev, 0x304);
|
||||
+
|
||||
+ udelay(1);
|
||||
+
|
||||
+ /* Work around for 5354 failures */
|
||||
+ if ((dev->id.revision == 2) && (dev->bus->chip_id == 0x5354)) {
|
||||
+ /* Change syn01 reg */
|
||||
+ tmp = 0x00fe00fe;
|
||||
+ ssb_write32(dev, 0x894, tmp);
|
||||
+
|
||||
+ /* Change syn03 reg */
|
||||
+ tmp = ssb_read32(dev, 0x89c);
|
||||
+ tmp |= 0x1;
|
||||
+ ssb_write32(dev, 0x89c, tmp);
|
||||
+ }
|
||||
+ } else
|
||||
+ ssb_device_enable(dev, 0);
|
||||
|
||||
hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
|
||||
dev_name(dev->dev));
|
||||
@@ -200,6 +248,7 @@ static int ssb_ohci_resume(struct ssb_de
|
||||
static const struct ssb_device_id ssb_ohci_table[] = {
|
||||
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
|
||||
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
|
||||
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
|
||||
SSB_DEVTABLE_END
|
||||
};
|
||||
MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);
|
@ -1,89 +0,0 @@ |
||||
--- a/arch/mips/Kconfig
|
||||
+++ b/arch/mips/Kconfig
|
||||
@@ -205,7 +205,6 @@ config MIPS_MALTA
|
||||
select I8259
|
||||
select MIPS_BOARDS_GEN
|
||||
select MIPS_BONITO64
|
||||
- select MIPS_CPU_SCACHE
|
||||
select PCI_GT64XXX_PCI0
|
||||
select MIPS_MSC
|
||||
select SWAP_IO_SPACE
|
||||
@@ -1589,13 +1588,6 @@ config IP22_CPU_SCACHE
|
||||
bool
|
||||
select BOARD_SCACHE
|
||||
|
||||
-#
|
||||
-# Support for a MIPS32 / MIPS64 style S-caches
|
||||
-#
|
||||
-config MIPS_CPU_SCACHE
|
||||
- bool
|
||||
- select BOARD_SCACHE
|
||||
-
|
||||
config R5000_CPU_SCACHE
|
||||
bool
|
||||
select BOARD_SCACHE
|
||||
--- a/arch/mips/kernel/cpu-probe.c
|
||||
+++ b/arch/mips/kernel/cpu-probe.c
|
||||
@@ -772,6 +772,8 @@ static inline void cpu_probe_mips(struct
|
||||
case PRID_IMP_25KF:
|
||||
c->cputype = CPU_25KF;
|
||||
__cpu_name[cpu] = "MIPS 25Kc";
|
||||
+ /* Probe for L2 cache */
|
||||
+ c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT;
|
||||
break;
|
||||
case PRID_IMP_34K:
|
||||
c->cputype = CPU_34K;
|
||||
--- a/arch/mips/mm/Makefile
|
||||
+++ b/arch/mips/mm/Makefile
|
||||
@@ -33,6 +33,5 @@ obj-$(CONFIG_CPU_CAVIUM_OCTEON) += c-oct
|
||||
obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o
|
||||
obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o
|
||||
obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o
|
||||
-obj-$(CONFIG_MIPS_CPU_SCACHE) += sc-mips.o
|
||||
|
||||
EXTRA_CFLAGS += -Werror
|
||||
--- a/arch/mips/mm/c-r4k.c
|
||||
+++ b/arch/mips/mm/c-r4k.c
|
||||
@@ -1148,7 +1148,6 @@ static void __init loongson2_sc_init(voi
|
||||
|
||||
extern int r5k_sc_init(void);
|
||||
extern int rm7k_sc_init(void);
|
||||
-extern int mips_sc_init(void);
|
||||
|
||||
static void __cpuinit setup_scache(void)
|
||||
{
|
||||
@@ -1202,29 +1201,17 @@ static void __cpuinit setup_scache(void)
|
||||
#endif
|
||||
|
||||
default:
|
||||
- if (c->isa_level == MIPS_CPU_ISA_M32R1 ||
|
||||
- c->isa_level == MIPS_CPU_ISA_M32R2 ||
|
||||
- c->isa_level == MIPS_CPU_ISA_M64R1 ||
|
||||
- c->isa_level == MIPS_CPU_ISA_M64R2) {
|
||||
-#ifdef CONFIG_MIPS_CPU_SCACHE
|
||||
- if (mips_sc_init ()) {
|
||||
- scache_size = c->scache.ways * c->scache.sets * c->scache.linesz;
|
||||
- printk("MIPS secondary cache %ldkB, %s, linesize %d bytes.\n",
|
||||
- scache_size >> 10,
|
||||
- way_string[c->scache.ways], c->scache.linesz);
|
||||
- }
|
||||
-#else
|
||||
- if (!(c->scache.flags & MIPS_CACHE_NOT_PRESENT))
|
||||
- panic("Dunno how to handle MIPS32 / MIPS64 second level cache");
|
||||
-#endif
|
||||
- return;
|
||||
- }
|
||||
sc_present = 0;
|
||||
}
|
||||
|
||||
if (!sc_present)
|
||||
return;
|
||||
|
||||
+ if ((c->isa_level == MIPS_CPU_ISA_M32R1 ||
|
||||
+ c->isa_level == MIPS_CPU_ISA_M64R1) &&
|
||||
+ !(c->scache.flags & MIPS_CACHE_NOT_PRESENT))
|
||||
+ panic("Dunno how to handle MIPS32 / MIPS64 second level cache");
|
||||
+
|
||||
/* compute a couple of other cache variables */
|
||||
c->scache.waysize = scache_size / c->scache.ways;
|
||||
|
@ -1,60 +0,0 @@ |
||||
---
|
||||
drivers/usb/host/ohci-ssb.c | 39 ++++++++++++++++++++++++++++++++++++---
|
||||
1 file changed, 36 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/usb/host/ohci-ssb.c
|
||||
+++ b/drivers/usb/host/ohci-ssb.c
|
||||
@@ -106,10 +106,42 @@ static int ssb_ohci_attach(struct ssb_de
|
||||
int err = -ENOMEM;
|
||||
u32 tmp, flags = 0;
|
||||
|
||||
- if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV)
|
||||
+ if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) {
|
||||
+ /* Put the device into host-mode. */
|
||||
flags |= SSB_OHCI_TMSLOW_HOSTMODE;
|
||||
-
|
||||
- ssb_device_enable(dev, flags);
|
||||
+ ssb_device_enable(dev, flags);
|
||||
+ } else if (dev->id.coreid == SSB_DEV_USB20_HOST) {
|
||||
+ /*
|
||||
+ * USB 2.0 special considerations:
|
||||
+ *
|
||||
+ * 1. Since the core supports both OHCI and EHCI functions, it must
|
||||
+ * only be reset once.
|
||||
+ *
|
||||
+ * 2. In addition to the standard SSB reset sequence, the Host Control
|
||||
+ * Register must be programmed to bring the USB core and various
|
||||
+ * phy components out of reset.
|
||||
+ */
|
||||
+ ssb_device_enable(dev, 0);
|
||||
+ ssb_write32(dev, 0x200, 0x7ff);
|
||||
+ udelay(1);
|
||||
+ if (dev->id.revision == 1) { // bug in rev 1
|
||||
+
|
||||
+ /* Change Flush control reg */
|
||||
+ tmp = ssb_read32(dev, 0x400);
|
||||
+ tmp &= ~8;
|
||||
+ ssb_write32(dev, 0x400, tmp);
|
||||
+ tmp = ssb_read32(dev, 0x400);
|
||||
+ printk("USB20H fcr: 0x%0x\n", tmp);
|
||||
+
|
||||
+ /* Change Shim control reg */
|
||||
+ tmp = ssb_read32(dev, 0x304);
|
||||
+ tmp &= ~0x100;
|
||||
+ ssb_write32(dev, 0x304, tmp);
|
||||
+ tmp = ssb_read32(dev, 0x304);
|
||||
+ printk("USB20H shim: 0x%0x\n", tmp);
|
||||
+ }
|
||||
+ } else
|
||||
+ ssb_device_enable(dev, 0);
|
||||
|
||||
hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
|
||||
dev_name(dev->dev));
|
||||
@@ -200,6 +232,7 @@ static int ssb_ohci_resume(struct ssb_de
|
||||
static const struct ssb_device_id ssb_ohci_table[] = {
|
||||
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
|
||||
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
|
||||
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
|
||||
SSB_DEVTABLE_END
|
||||
};
|
||||
MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);
|
@ -1,16 +0,0 @@ |
||||
---
|
||||
drivers/usb/host/ohci-ssb.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
--- a/drivers/usb/host/ohci-ssb.c
|
||||
+++ b/drivers/usb/host/ohci-ssb.c
|
||||
@@ -106,6 +106,9 @@ static int ssb_ohci_attach(struct ssb_de
|
||||
int err = -ENOMEM;
|
||||
u32 tmp, flags = 0;
|
||||
|
||||
+ if (ssb_dma_set_mask(dev, DMA_BIT_MASK(32)))
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) {
|
||||
/* Put the device into host-mode. */
|
||||
flags |= SSB_OHCI_TMSLOW_HOSTMODE;
|
@ -1,63 +0,0 @@ |
||||
This patch significantly improves the reliability of high speed
|
||||
usb writes on the bcm5354. It implements a work around for version 2
|
||||
of the usb20 core that was cribbed from the GPL sources for the
|
||||
Asus wl500gpv2 and verified against the wl520gu sources.
|
||||
|
||||
Reference:
|
||||
GPL/WL-520gu-NewUI/src/linux/linux/arch/mips/brcm-boards/bcm947xx/pcibios.c
|
||||
GPL/WL-500gPV2-NewUI/src/linux/linux/arch/mips/brcm-boards/bcm947xx/pcibios.c
|
||||
|
||||
Signed-off-by: Steve Brown <sbrown@cortland.com>
|
||||
|
||||
---
|
||||
drivers/usb/host/ohci-ssb.c | 37 +++++++++++++++++++++++--------------
|
||||
1 file changed, 23 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/drivers/usb/host/ohci-ssb.c
|
||||
+++ b/drivers/usb/host/ohci-ssb.c
|
||||
@@ -141,22 +141,31 @@ static int ssb_ohci_attach(struct ssb_de
|
||||
*/
|
||||
ssb_device_enable(dev, 0);
|
||||
ssb_write32(dev, 0x200, 0x7ff);
|
||||
+
|
||||
+ /* Change Flush control reg */
|
||||
+ tmp = ssb_read32(dev, 0x400);
|
||||
+ tmp &= ~8;
|
||||
+ ssb_write32(dev, 0x400, tmp);
|
||||
+ tmp = ssb_read32(dev, 0x400);
|
||||
+
|
||||
+ /* Change Shim control reg */
|
||||
+ tmp = ssb_read32(dev, 0x304);
|
||||
+ tmp &= ~0x100;
|
||||
+ ssb_write32(dev, 0x304, tmp);
|
||||
+ tmp = ssb_read32(dev, 0x304);
|
||||
+
|
||||
udelay(1);
|
||||
- if (dev->id.revision == 1) { // bug in rev 1
|
||||
|
||||
- /* Change Flush control reg */
|
||||
- tmp = ssb_read32(dev, 0x400);
|
||||
- tmp &= ~8;
|
||||
- ssb_write32(dev, 0x400, tmp);
|
||||
- tmp = ssb_read32(dev, 0x400);
|
||||
- printk("USB20H fcr: 0x%0x\n", tmp);
|
||||
-
|
||||
- /* Change Shim control reg */
|
||||
- tmp = ssb_read32(dev, 0x304);
|
||||
- tmp &= ~0x100;
|
||||
- ssb_write32(dev, 0x304, tmp);
|
||||
- tmp = ssb_read32(dev, 0x304);
|
||||
- printk("USB20H shim: 0x%0x\n", tmp);
|
||||
+ /* Work around for 5354 failures */
|
||||
+ if ((dev->id.revision == 2) && (dev->bus->chip_id == 0x5354)) {
|
||||
+ /* Change syn01 reg */
|
||||
+ tmp = 0x00fe00fe;
|
||||
+ ssb_write32(dev, 0x894, tmp);
|
||||
+
|
||||
+ /* Change syn03 reg */
|
||||
+ tmp = ssb_read32(dev, 0x89c);
|
||||
+ tmp |= 0x1;
|
||||
+ ssb_write32(dev, 0x89c, tmp);
|
||||
}
|
||||
} else
|
||||
ssb_device_enable(dev, 0);
|
@ -1,108 +0,0 @@ |
||||
--- a/arch/mips/bcm47xx/prom.c
|
||||
+++ b/arch/mips/bcm47xx/prom.c
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <asm/fw/cfe/cfe_error.h>
|
||||
|
||||
static int cfe_cons_handle;
|
||||
+static void (* __prom_putchar)(char c);
|
||||
|
||||
const char *get_system_type(void)
|
||||
{
|
||||
@@ -40,65 +41,40 @@ const char *get_system_type(void)
|
||||
|
||||
void prom_putchar(char c)
|
||||
{
|
||||
+ if (__prom_putchar)
|
||||
+ __prom_putchar(c);
|
||||
+}
|
||||
+
|
||||
+void prom_putchar_cfe(char c)
|
||||
+{
|
||||
while (cfe_write(cfe_cons_handle, &c, 1) == 0)
|
||||
;
|
||||
}
|
||||
|
||||
-static __init void prom_init_cfe(void)
|
||||
+static __init int prom_init_cfe(void)
|
||||
{
|
||||
uint32_t cfe_ept;
|
||||
uint32_t cfe_handle;
|
||||
uint32_t cfe_eptseal;
|
||||
- int argc = fw_arg0;
|
||||
- char **envp = (char **) fw_arg2;
|
||||
- int *prom_vec = (int *) fw_arg3;
|
||||
-
|
||||
- /*
|
||||
- * Check if a loader was used; if NOT, the 4 arguments are
|
||||
- * what CFE gives us (handle, 0, EPT and EPTSEAL)
|
||||
- */
|
||||
- if (argc < 0) {
|
||||
- cfe_handle = (uint32_t)argc;
|
||||
- cfe_ept = (uint32_t)envp;
|
||||
- cfe_eptseal = (uint32_t)prom_vec;
|
||||
- } else {
|
||||
- if ((int)prom_vec < 0) {
|
||||
- /*
|
||||
- * Old loader; all it gives us is the handle,
|
||||
- * so use the "known" entrypoint and assume
|
||||
- * the seal.
|
||||
- */
|
||||
- cfe_handle = (uint32_t)prom_vec;
|
||||
- cfe_ept = 0xBFC00500;
|
||||
- cfe_eptseal = CFE_EPTSEAL;
|
||||
- } else {
|
||||
- /*
|
||||
- * Newer loaders bundle the handle/ept/eptseal
|
||||
- * Note: prom_vec is in the loader's useg
|
||||
- * which is still alive in the TLB.
|
||||
- */
|
||||
- cfe_handle = prom_vec[0];
|
||||
- cfe_ept = prom_vec[2];
|
||||
- cfe_eptseal = prom_vec[3];
|
||||
- }
|
||||
- }
|
||||
|
||||
- if (cfe_eptseal != CFE_EPTSEAL) {
|
||||
- /* too early for panic to do any good */
|
||||
- printk(KERN_ERR "CFE's entrypoint seal doesn't match.");
|
||||
- while (1) ;
|
||||
- }
|
||||
+ cfe_eptseal = (uint32_t) fw_arg3;
|
||||
+ cfe_handle = (uint32_t) fw_arg0;
|
||||
+ cfe_ept = (uint32_t) fw_arg2;
|
||||
+
|
||||
+ if (cfe_eptseal != CFE_EPTSEAL)
|
||||
+ return -1;
|
||||
|
||||
cfe_init(cfe_handle, cfe_ept);
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
-static __init void prom_init_console(void)
|
||||
+static __init void prom_init_console_cfe(void)
|
||||
{
|
||||
/* Initialize CFE console */
|
||||
cfe_cons_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
|
||||
}
|
||||
|
||||
-static __init void prom_init_cmdline(void)
|
||||
+static __init void prom_init_cmdline_cfe(void)
|
||||
{
|
||||
static char buf[COMMAND_LINE_SIZE] __initdata;
|
||||
|
||||
@@ -160,9 +136,12 @@ static __init void prom_init_mem(void)
|
||||
|
||||
void __init prom_init(void)
|
||||
{
|
||||
- prom_init_cfe();
|
||||
- prom_init_console();
|
||||
- prom_init_cmdline();
|
||||
+ if (prom_init_cfe() == 0) {
|
||||
+ //prom_init_console_cfe();
|
||||
+ //prom_init_cmdline_cfe();
|
||||
+ __prom_putchar = prom_putchar_cfe;
|
||||
+ }
|
||||
+
|
||||
prom_init_mem();
|
||||
}
|
||||
|
@ -1,10 +0,0 @@ |
||||
--- a/arch/mips/Kconfig
|
||||
+++ b/arch/mips/Kconfig
|
||||
@@ -65,7 +65,6 @@ config BCM47XX
|
||||
select SSB_B43_PCI_BRIDGE if PCI
|
||||
select SSB_PCICORE_HOSTMODE if PCI
|
||||
select GENERIC_GPIO
|
||||
- select SYS_HAS_EARLY_PRINTK
|
||||
select CFE
|
||||
help
|
||||
Support for BCM47XX based boards
|
@ -1,3 +1,24 @@ |
||||
From b6d850fe4035d6bee7199119358e06f802aa19ed Mon Sep 17 00:00:00 2001
|
||||
From: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
Date: Sun, 18 Jul 2010 12:49:41 +0200
|
||||
Subject: [PATCH 1/5] MIPS: BCM47xx: Really fix 128MB RAM problem
|
||||
|
||||
The previews patch 84a6fcb368a080620d12fc4d79e07902dbee7335 was wrong,
|
||||
I got wrong success reports.
|
||||
|
||||
The bcm47xx architecture maps the ram into a 128MB address space. It
|
||||
will be paced there as often as goes into the 128MB. The detection
|
||||
tries to find the position where the same memory is found. When reading
|
||||
over 128MB the processor will throw an exception. If 128MB ram is
|
||||
installed, it will not find the same memory because it tries to read
|
||||
over the 128MB boarder. Now it just assumes 128MB installed ram if it
|
||||
can not find that the ram is repeating.
|
||||
|
||||
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
---
|
||||
arch/mips/bcm47xx/prom.c | 22 ++++++++++++++--------
|
||||
1 files changed, 14 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/arch/mips/bcm47xx/prom.c
|
||||
+++ b/arch/mips/bcm47xx/prom.c
|
||||
@@ -126,6 +126,7 @@ static __init void prom_init_cmdline(voi
|
@ -0,0 +1,158 @@ |
||||
From d6c049e08568aac29fff854ea0385e63c7150e09 Mon Sep 17 00:00:00 2001
|
||||
From: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
Date: Sun, 18 Jul 2010 13:34:32 +0200
|
||||
Subject: [PATCH 2/5] MIPS: BCM47xx: Fill more values into ssb sprom
|
||||
|
||||
Most of the values are stored in the nvram and not in the CFE. At first
|
||||
the nvram should be read and if there is no value it should look into
|
||||
the CFE. Now more values are read out because the b43 and b43legacy
|
||||
drivers needs them.
|
||||
|
||||
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
---
|
||||
arch/mips/bcm47xx/setup.c | 122 +++++++++++++++++++++++++++++++++------------
|
||||
1 files changed, 89 insertions(+), 33 deletions(-)
|
||||
|
||||
--- a/arch/mips/bcm47xx/setup.c
|
||||
+++ b/arch/mips/bcm47xx/setup.c
|
||||
@@ -74,6 +74,86 @@ static void str2eaddr(char *str, char *d
|
||||
}
|
||||
}
|
||||
|
||||
+static void bcm47xx_fill_sprom(struct ssb_sprom *sprom)
|
||||
+{
|
||||
+ char buf[100];
|
||||
+
|
||||
+ memset(sprom, 0, sizeof(struct ssb_sprom));
|
||||
+
|
||||
+ sprom->revision = 3;
|
||||
+ if (nvram_getenv("il0macaddr", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("il0macaddr", buf, sizeof(buf)) >= 0)
|
||||
+ str2eaddr(buf, sprom->il0mac);
|
||||
+ if (nvram_getenv("et0macaddr", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0)
|
||||
+ str2eaddr(buf, sprom->et0mac);
|
||||
+ if (nvram_getenv("et1macaddr", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0)
|
||||
+ str2eaddr(buf, sprom->et1mac);
|
||||
+ if (nvram_getenv("et0phyaddr", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->et0phyaddr = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("et1phyaddr", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->et1phyaddr = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("et0mdcport", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->et0mdcport = !!simple_strtoul(buf, NULL, 10);
|
||||
+ if (nvram_getenv("et1mdcport", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->et1mdcport = !!simple_strtoul(buf, NULL, 10);
|
||||
+ if (nvram_getenv("pa0b0", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("pa0b0", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->pa0b0 = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("pa0b1", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("pa0b1", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->pa0b1 = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("pa0b2", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("pa0b2", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->pa0b2 = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("pa1b0", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("pa1b0", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->pa1b0 = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("pa1b1", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("pa1b1", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->pa1b1 = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("pa1b2", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("pa1b2", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->pa1b2 = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("wl0gpio0", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("wl0gpio0", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->gpio0 = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("wl0gpio1", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("wl0gpio1", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->gpio1 = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("wl0gpio2", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("wl0gpio2", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->gpio2 = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("wl0gpio3", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("wl0gpio3", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->gpio3 = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("pa0maxpwr", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("pa0maxpwr", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->maxpwr_bg = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("pa1maxpwr", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("pa1maxpwr", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->maxpwr_a = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("pa0itssit", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("pa0itssit", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->itssi_bg = simple_strtoul(buf, NULL, 0);
|
||||
+ if (nvram_getenv("pa1itssit", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("pa1itssit", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->itssi_a = simple_strtoul(buf, NULL, 0);
|
||||
+ sprom->boardflags_lo = 0;
|
||||
+ if (nvram_getenv("boardflags", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("boardflags", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->boardflags_lo = simple_strtoul(buf, NULL, 0);
|
||||
+ sprom->boardflags_hi = 0;
|
||||
+ if (nvram_getenv("boardflags", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("boardflags", buf, sizeof(buf)) >= 0)
|
||||
+ sprom->boardflags_hi = simple_strtoul(buf, NULL, 0);
|
||||
+}
|
||||
+
|
||||
static int bcm47xx_get_invariants(struct ssb_bus *bus,
|
||||
struct ssb_init_invariants *iv)
|
||||
{
|
||||
@@ -82,43 +162,19 @@ static int bcm47xx_get_invariants(struct
|
||||
/* Fill boardinfo structure */
|
||||
memset(&(iv->boardinfo), 0 , sizeof(struct ssb_boardinfo));
|
||||
|
||||
- if (cfe_getenv("boardvendor", buf, sizeof(buf)) >= 0 ||
|
||||
- nvram_getenv("boardvendor", buf, sizeof(buf)) >= 0)
|
||||
+ iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM;
|
||||
+ if (nvram_getenv("boardtype", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("boardtype", buf, sizeof(buf)) >= 0)
|
||||
iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0);
|
||||
- if (cfe_getenv("boardtype", buf, sizeof(buf)) >= 0 ||
|
||||
- nvram_getenv("boardtype", buf, sizeof(buf)) >= 0)
|
||||
- iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0);
|
||||
- if (cfe_getenv("boardrev", buf, sizeof(buf)) >= 0 ||
|
||||
- nvram_getenv("boardrev", buf, sizeof(buf)) >= 0)
|
||||
+ if (nvram_getenv("boardrev", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("boardrev", buf, sizeof(buf)) >= 0)
|
||||
iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0);
|
||||
|
||||
- /* Fill sprom structure */
|
||||
- memset(&(iv->sprom), 0, sizeof(struct ssb_sprom));
|
||||
- iv->sprom.revision = 3;
|
||||
-
|
||||
- if (cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0 ||
|
||||
- nvram_getenv("et0macaddr", buf, sizeof(buf)) >= 0)
|
||||
- str2eaddr(buf, iv->sprom.et0mac);
|
||||
-
|
||||
- if (cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0 ||
|
||||
- nvram_getenv("et1macaddr", buf, sizeof(buf)) >= 0)
|
||||
- str2eaddr(buf, iv->sprom.et1mac);
|
||||
-
|
||||
- if (cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0 ||
|
||||
- nvram_getenv("et0phyaddr", buf, sizeof(buf)) >= 0)
|
||||
- iv->sprom.et0phyaddr = simple_strtoul(buf, NULL, 0);
|
||||
-
|
||||
- if (cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0 ||
|
||||
- nvram_getenv("et1phyaddr", buf, sizeof(buf)) >= 0)
|
||||
- iv->sprom.et1phyaddr = simple_strtoul(buf, NULL, 0);
|
||||
-
|
||||
- if (cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0 ||
|
||||
- nvram_getenv("et0mdcport", buf, sizeof(buf)) >= 0)
|
||||
- iv->sprom.et0mdcport = simple_strtoul(buf, NULL, 10);
|
||||
-
|
||||
- if (cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0 ||
|
||||
- nvram_getenv("et1mdcport", buf, sizeof(buf)) >= 0)
|
||||
- iv->sprom.et1mdcport = simple_strtoul(buf, NULL, 10);
|
||||
+ bcm47xx_fill_sprom(&iv->sprom);
|
||||
+
|
||||
+ if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0 ||
|
||||
+ cfe_getenv("cardbus", buf, sizeof(buf)) >= 0)
|
||||
+ iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10);
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,23 @@ |
||||
From b1a0abc936bf61689d1e8a56c423b232cff24da5 Mon Sep 17 00:00:00 2001
|
||||
From: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
Date: Sun, 18 Jul 2010 13:58:09 +0200
|
||||
Subject: [PATCH 3/5] MIPS: BCM47xx: Activate SSB_B43_PCI_BRIDGE by default
|
||||
|
||||
The b43_pci_bridge is needed to use the b43 driver with brcm47xx.
|
||||
Activate it by default if pci is available.
|
||||
|
||||
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
---
|
||||
arch/mips/Kconfig | 1 +
|
||||
1 files changed, 1 insertions(+), 0 deletions(-)
|
||||
|
||||
--- a/arch/mips/Kconfig
|
||||
+++ b/arch/mips/Kconfig
|
||||
@@ -62,6 +62,7 @@ config BCM47XX
|
||||
select SSB_DRIVER_MIPS
|
||||
select SSB_DRIVER_EXTIF
|
||||
select SSB_EMBEDDED
|
||||
+ select SSB_B43_PCI_BRIDGE if PCI
|
||||
select SSB_PCICORE_HOSTMODE if PCI
|
||||
select GENERIC_GPIO
|
||||
select SYS_HAS_EARLY_PRINTK
|
@ -0,0 +1,81 @@ |
||||
From 4c6a515310f29c89f25a54a115cde905f97330f8 Mon Sep 17 00:00:00 2001
|
||||
From: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
Date: Sun, 18 Jul 2010 14:59:24 +0200
|
||||
Subject: [PATCH 4/5] MIPS: BCM47xx: Setup and register serial early
|
||||
|
||||
Swap the first and second serial if console=ttyS1 was set.
|
||||
Set it up and register it for early serial support.
|
||||
|
||||
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
---
|
||||
arch/mips/Kconfig | 1 -
|
||||
arch/mips/bcm47xx/setup.c | 36 +++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 35 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/arch/mips/Kconfig
|
||||
+++ b/arch/mips/Kconfig
|
||||
@@ -65,7 +65,6 @@ config BCM47XX
|
||||
select SSB_B43_PCI_BRIDGE if PCI
|
||||
select SSB_PCICORE_HOSTMODE if PCI
|
||||
select GENERIC_GPIO
|
||||
- select SYS_HAS_EARLY_PRINTK
|
||||
select CFE
|
||||
help
|
||||
Support for BCM47XX based boards
|
||||
--- a/arch/mips/bcm47xx/setup.c
|
||||
+++ b/arch/mips/bcm47xx/setup.c
|
||||
@@ -28,6 +28,8 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/ssb/ssb.h>
|
||||
#include <linux/ssb/ssb_embedded.h>
|
||||
+#include <linux/serial.h>
|
||||
+#include <linux/serial_8250.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/reboot.h>
|
||||
#include <asm/time.h>
|
||||
@@ -181,12 +183,44 @@ static int bcm47xx_get_invariants(struct
|
||||
|
||||
void __init plat_mem_setup(void)
|
||||
{
|
||||
- int err;
|
||||
+ int i, err;
|
||||
+ char buf[100];
|
||||
+ struct ssb_mipscore *mcore;
|
||||
|
||||
err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE,
|
||||
bcm47xx_get_invariants);
|
||||
if (err)
|
||||
panic("Failed to initialize SSB bus (err %d)\n", err);
|
||||
+ mcore = &ssb_bcm47xx.mipscore;
|
||||
+
|
||||
+ nvram_getenv("kernel_args", buf, sizeof(buf));
|
||||
+ if (!strncmp(buf, "console=ttyS1", 13)) {
|
||||
+ struct ssb_serial_port port;
|
||||
+
|
||||
+ printk("Swapping serial ports!\n");
|
||||
+ /* swap serial ports */
|
||||
+ memcpy(&port, &mcore->serial_ports[0], sizeof(port));
|
||||
+ memcpy(&mcore->serial_ports[0], &mcore->serial_ports[1], sizeof(port));
|
||||
+ memcpy(&mcore->serial_ports[1], &port, sizeof(port));
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < mcore->nr_serial_ports; i++) {
|
||||
+ struct ssb_serial_port *port = &(mcore->serial_ports[i]);
|
||||
+ struct uart_port s;
|
||||
+
|
||||
+ memset(&s, 0, sizeof(s));
|
||||
+ s.line = i;
|
||||
+ s.mapbase = (unsigned int) port->regs;
|
||||
+ s.membase = port->regs;
|
||||
+ s.irq = port->irq + 2;
|
||||
+ s.uartclk = port->baud_base;
|
||||
+ s.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
|
||||
+ s.iotype = SERIAL_IO_MEM;
|
||||
+ s.regshift = port->reg_shift;
|
||||
+
|
||||
+ early_serial_setup(&s);
|
||||
+ }
|
||||
+ printk("Serial init done.\n");
|
||||
|
||||
_machine_restart = bcm47xx_machine_restart;
|
||||
_machine_halt = bcm47xx_machine_halt;
|
@ -0,0 +1,130 @@ |
||||
From 6bd2c73ed31a2dfe7eab04d32c17318a5c62f9d4 Mon Sep 17 00:00:00 2001
|
||||
From: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
Date: Sun, 18 Jul 2010 15:11:26 +0200
|
||||
Subject: [PATCH 5/5] MIPS: BCM47xx: Remove CFE console
|
||||
|
||||
Do not use the CFE console. It causes hangs on some devices like the
|
||||
Buffalo WHR-HP-G54.
|
||||
This was reported in https://dev.openwrt.org/ticket/4061 and
|
||||
https://forum.openwrt.org/viewtopic.php?id=17063
|
||||
|
||||
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
---
|
||||
arch/mips/bcm47xx/prom.c | 82 +++------------------------------------------
|
||||
1 files changed, 6 insertions(+), 76 deletions(-)
|
||||
|
||||
--- a/arch/mips/bcm47xx/prom.c
|
||||
+++ b/arch/mips/bcm47xx/prom.c
|
||||
@@ -31,96 +31,28 @@
|
||||
#include <asm/fw/cfe/cfe_api.h>
|
||||
#include <asm/fw/cfe/cfe_error.h>
|
||||
|
||||
-static int cfe_cons_handle;
|
||||
-
|
||||
const char *get_system_type(void)
|
||||
{
|
||||
return "Broadcom BCM47XX";
|
||||
}
|
||||
|
||||
-void prom_putchar(char c)
|
||||
-{
|
||||
- while (cfe_write(cfe_cons_handle, &c, 1) == 0)
|
||||
- ;
|
||||
-}
|
||||
-
|
||||
-static __init void prom_init_cfe(void)
|
||||
+static __init int prom_init_cfe(void)
|
||||
{
|
||||
uint32_t cfe_ept;
|
||||
uint32_t cfe_handle;
|
||||
uint32_t cfe_eptseal;
|
||||
- int argc = fw_arg0;
|
||||
- char **envp = (char **) fw_arg2;
|
||||
- int *prom_vec = (int *) fw_arg3;
|
||||
-
|
||||
- /*
|
||||
- * Check if a loader was used; if NOT, the 4 arguments are
|
||||
- * what CFE gives us (handle, 0, EPT and EPTSEAL)
|
||||
- */
|
||||
- if (argc < 0) {
|
||||
- cfe_handle = (uint32_t)argc;
|
||||
- cfe_ept = (uint32_t)envp;
|
||||
- cfe_eptseal = (uint32_t)prom_vec;
|
||||
- } else {
|
||||
- if ((int)prom_vec < 0) {
|
||||
- /*
|
||||
- * Old loader; all it gives us is the handle,
|
||||
- * so use the "known" entrypoint and assume
|
||||
- * the seal.
|
||||
- */
|
||||
- cfe_handle = (uint32_t)prom_vec;
|
||||
- cfe_ept = 0xBFC00500;
|
||||
- cfe_eptseal = CFE_EPTSEAL;
|
||||
- } else {
|
||||
- /*
|
||||
- * Newer loaders bundle the handle/ept/eptseal
|
||||
- * Note: prom_vec is in the loader's useg
|
||||
- * which is still alive in the TLB.
|
||||
- */
|
||||
- cfe_handle = prom_vec[0];
|
||||
- cfe_ept = prom_vec[2];
|
||||
- cfe_eptseal = prom_vec[3];
|
||||
- }
|
||||
- }
|
||||
+
|
||||
+ cfe_eptseal = (uint32_t) fw_arg3;
|
||||
+ cfe_handle = (uint32_t) fw_arg0;
|
||||
+ cfe_ept = (uint32_t) fw_arg2;
|
||||
|
||||
if (cfe_eptseal != CFE_EPTSEAL) {
|
||||
- /* too early for panic to do any good */
|
||||
printk(KERN_ERR "CFE's entrypoint seal doesn't match.");
|
||||
- while (1) ;
|
||||
+ return -1;
|
||||
}
|
||||
|
||||
cfe_init(cfe_handle, cfe_ept);
|
||||
-}
|
||||
-
|
||||
-static __init void prom_init_console(void)
|
||||
-{
|
||||
- /* Initialize CFE console */
|
||||
- cfe_cons_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
|
||||
-}
|
||||
-
|
||||
-static __init void prom_init_cmdline(void)
|
||||
-{
|
||||
- static char buf[COMMAND_LINE_SIZE] __initdata;
|
||||
-
|
||||
- /* Get the kernel command line from CFE */
|
||||
- if (cfe_getenv("LINUX_CMDLINE", buf, COMMAND_LINE_SIZE) >= 0) {
|
||||
- buf[COMMAND_LINE_SIZE - 1] = 0;
|
||||
- strcpy(arcs_cmdline, buf);
|
||||
- }
|
||||
-
|
||||
- /* Force a console handover by adding a console= argument if needed,
|
||||
- * as CFE is not available anymore later in the boot process. */
|
||||
- if ((strstr(arcs_cmdline, "console=")) == NULL) {
|
||||
- /* Try to read the default serial port used by CFE */
|
||||
- if ((cfe_getenv("BOOT_CONSOLE", buf, COMMAND_LINE_SIZE) < 0)
|
||||
- || (strncmp("uart", buf, 4)))
|
||||
- /* Default to uart0 */
|
||||
- strcpy(buf, "uart0");
|
||||
-
|
||||
- /* Compute the new command line */
|
||||
- snprintf(arcs_cmdline, COMMAND_LINE_SIZE, "%s console=ttyS%c,115200",
|
||||
- arcs_cmdline, buf[4]);
|
||||
- }
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static __init void prom_init_mem(void)
|
||||
@@ -161,8 +93,6 @@ static __init void prom_init_mem(void)
|
||||
void __init prom_init(void)
|
||||
{
|
||||
prom_init_cfe();
|
||||
- prom_init_console();
|
||||
- prom_init_cmdline();
|
||||
prom_init_mem();
|
||||
}
|
||||
|
@ -0,0 +1,95 @@ |
||||
From cb33ffbdd8491c58b35958ec74c39b3a5c7fabe8 Mon Sep 17 00:00:00 2001
|
||||
From: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
Date: Sun, 18 Jul 2010 21:25:03 +0200
|
||||
Subject: [PATCH 1/2] USB: Add USB 2.0 to ssb ohci driver
|
||||
|
||||
This adds USB 2.0 support to ssb ohci driver.
|
||||
This work was done based on Braodcom source code in the OpenWRT project.
|
||||
|
||||
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
---
|
||||
drivers/usb/host/ohci-ssb.c | 55 ++++++++++++++++++++++++++++++++++++++++--
|
||||
1 files changed, 52 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/usb/host/ohci-ssb.c
|
||||
+++ b/drivers/usb/host/ohci-ssb.c
|
||||
@@ -92,9 +92,12 @@ static const struct hc_driver ssb_ohci_h
|
||||
static void ssb_ohci_detach(struct ssb_device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = ssb_get_drvdata(dev);
|
||||
+ if (hcd->driver->shutdown)
|
||||
+ hcd->driver->shutdown(hcd);
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
iounmap(hcd->regs);
|
||||
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
usb_put_hcd(hcd);
|
||||
ssb_device_disable(dev, 0);
|
||||
}
|
||||
@@ -106,10 +109,55 @@ static int ssb_ohci_attach(struct ssb_de
|
||||
int err = -ENOMEM;
|
||||
u32 tmp, flags = 0;
|
||||
|
||||
- if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV)
|
||||
- flags |= SSB_OHCI_TMSLOW_HOSTMODE;
|
||||
+ if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) ||
|
||||
+ dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32)))
|
||||
+ return -EOPNOTSUPP;
|
||||
|
||||
- ssb_device_enable(dev, flags);
|
||||
+ if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) {
|
||||
+ /* Put the device into host-mode. */
|
||||
+ flags |= SSB_OHCI_TMSLOW_HOSTMODE;
|
||||
+ ssb_device_enable(dev, flags);
|
||||
+ } else if (dev->id.coreid == SSB_DEV_USB20_HOST) {
|
||||
+ /*
|
||||
+ * USB 2.0 special considerations:
|
||||
+ *
|
||||
+ * 1. Since the core supports both ehci and EHCI functions, it must
|
||||
+ * only be reset once.
|
||||
+ *
|
||||
+ * 2. In addition to the standard SSB reset sequence, the Host Control
|
||||
+ * Register must be programmed to bring the USB core and various
|
||||
+ * phy components out of reset.
|
||||
+ */
|
||||
+ ssb_device_enable(dev, 0);
|
||||
+ ssb_write32(dev, 0x200, 0x7ff);
|
||||
+
|
||||
+ /* Change Flush control reg */
|
||||
+ tmp = ssb_read32(dev, 0x400);
|
||||
+ tmp &= ~8;
|
||||
+ ssb_write32(dev, 0x400, tmp);
|
||||
+ tmp = ssb_read32(dev, 0x400);
|
||||
+
|
||||
+ /* Change Shim control reg */
|
||||
+ tmp = ssb_read32(dev, 0x304);
|
||||
+ tmp &= ~0x100;
|
||||
+ ssb_write32(dev, 0x304, tmp);
|
||||
+ tmp = ssb_read32(dev, 0x304);
|
||||
+
|
||||
+ udelay(1);
|
||||
+
|
||||
+ /* Work around for 5354 failures */
|
||||
+ if ((dev->id.revision == 2) && (dev->bus->chip_id == 0x5354)) {
|
||||
+ /* Change syn01 reg */
|
||||
+ tmp = 0x00fe00fe;
|
||||
+ ssb_write32(dev, 0x894, tmp);
|
||||
+
|
||||
+ /* Change syn03 reg */
|
||||
+ tmp = ssb_read32(dev, 0x89c);
|
||||
+ tmp |= 0x1;
|
||||
+ ssb_write32(dev, 0x89c, tmp);
|
||||
+ }
|
||||
+ } else
|
||||
+ ssb_device_enable(dev, 0);
|
||||
|
||||
hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
|
||||
dev_name(dev->dev));
|
||||
@@ -200,6 +248,7 @@ static int ssb_ohci_resume(struct ssb_de
|
||||
static const struct ssb_device_id ssb_ohci_table[] = {
|
||||
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
|
||||
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
|
||||
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
|
||||
SSB_DEVTABLE_END
|
||||
};
|
||||
MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);
|
@ -1,89 +0,0 @@ |
||||
--- a/arch/mips/Kconfig
|
||||
+++ b/arch/mips/Kconfig
|
||||
@@ -205,7 +205,6 @@ config MIPS_MALTA
|
||||
select I8259
|
||||
select MIPS_BOARDS_GEN
|
||||
select MIPS_BONITO64
|
||||
- select MIPS_CPU_SCACHE
|
||||
select PCI_GT64XXX_PCI0
|
||||
select MIPS_MSC
|
||||
select SWAP_IO_SPACE
|
||||
@@ -1589,13 +1588,6 @@ config IP22_CPU_SCACHE
|
||||
bool
|
||||
select BOARD_SCACHE
|
||||
|
||||
-#
|
||||
-# Support for a MIPS32 / MIPS64 style S-caches
|
||||
-#
|
||||
-config MIPS_CPU_SCACHE
|
||||
- bool
|
||||
- select BOARD_SCACHE
|
||||
-
|
||||
config R5000_CPU_SCACHE
|
||||
bool
|
||||
select BOARD_SCACHE
|
||||
--- a/arch/mips/kernel/cpu-probe.c
|
||||
+++ b/arch/mips/kernel/cpu-probe.c
|
||||
@@ -772,6 +772,8 @@ static inline void cpu_probe_mips(struct
|
||||
case PRID_IMP_25KF:
|
||||
c->cputype = CPU_25KF;
|
||||
__cpu_name[cpu] = "MIPS 25Kc";
|
||||
+ /* Probe for L2 cache */
|
||||
+ c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT;
|
||||
break;
|
||||
case PRID_IMP_34K:
|
||||
c->cputype = CPU_34K;
|
||||
--- a/arch/mips/mm/Makefile
|
||||
+++ b/arch/mips/mm/Makefile
|
||||
@@ -33,6 +33,5 @@ obj-$(CONFIG_CPU_CAVIUM_OCTEON) += c-oct
|
||||
obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o
|
||||
obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o
|
||||
obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o
|
||||
-obj-$(CONFIG_MIPS_CPU_SCACHE) += sc-mips.o
|
||||
|
||||
EXTRA_CFLAGS += -Werror
|
||||
--- a/arch/mips/mm/c-r4k.c
|
||||
+++ b/arch/mips/mm/c-r4k.c
|
||||
@@ -1148,7 +1148,6 @@ static void __init loongson2_sc_init(voi
|
||||
|
||||
extern int r5k_sc_init(void);
|
||||
extern int rm7k_sc_init(void);
|
||||
-extern int mips_sc_init(void);
|
||||
|
||||
static void __cpuinit setup_scache(void)
|
||||
{
|
||||
@@ -1202,29 +1201,17 @@ static void __cpuinit setup_scache(void)
|
||||
#endif
|
||||
|
||||
default:
|
||||
- if (c->isa_level == MIPS_CPU_ISA_M32R1 ||
|
||||
- c->isa_level == MIPS_CPU_ISA_M32R2 ||
|
||||
- c->isa_level == MIPS_CPU_ISA_M64R1 ||
|
||||
- c->isa_level == MIPS_CPU_ISA_M64R2) {
|
||||
-#ifdef CONFIG_MIPS_CPU_SCACHE
|
||||
- if (mips_sc_init ()) {
|
||||
- scache_size = c->scache.ways * c->scache.sets * c->scache.linesz;
|
||||
- printk("MIPS secondary cache %ldkB, %s, linesize %d bytes.\n",
|
||||
- scache_size >> 10,
|
||||
- way_string[c->scache.ways], c->scache.linesz);
|
||||
- }
|
||||
-#else
|
||||
- if (!(c->scache.flags & MIPS_CACHE_NOT_PRESENT))
|
||||
- panic("Dunno how to handle MIPS32 / MIPS64 second level cache");
|
||||
-#endif
|
||||
- return;
|
||||
- }
|
||||
sc_present = 0;
|
||||
}
|
||||
|
||||
if (!sc_present)
|
||||
return;
|
||||
|
||||
+ if ((c->isa_level == MIPS_CPU_ISA_M32R1 ||
|
||||
+ c->isa_level == MIPS_CPU_ISA_M64R1) &&
|
||||
+ !(c->scache.flags & MIPS_CACHE_NOT_PRESENT))
|
||||
+ panic("Dunno how to handle MIPS32 / MIPS64 second level cache");
|
||||
+
|
||||
/* compute a couple of other cache variables */
|
||||
c->scache.waysize = scache_size / c->scache.ways;
|
||||
|
@ -1,60 +0,0 @@ |
||||
---
|
||||
drivers/usb/host/ohci-ssb.c | 39 ++++++++++++++++++++++++++++++++++++---
|
||||
1 file changed, 36 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/usb/host/ohci-ssb.c
|
||||
+++ b/drivers/usb/host/ohci-ssb.c
|
||||
@@ -106,10 +106,42 @@ static int ssb_ohci_attach(struct ssb_de
|
||||
int err = -ENOMEM;
|
||||
u32 tmp, flags = 0;
|
||||
|
||||
- if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV)
|
||||
+ if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) {
|
||||
+ /* Put the device into host-mode. */
|
||||
flags |= SSB_OHCI_TMSLOW_HOSTMODE;
|
||||
-
|
||||
- ssb_device_enable(dev, flags);
|
||||
+ ssb_device_enable(dev, flags);
|
||||
+ } else if (dev->id.coreid == SSB_DEV_USB20_HOST) {
|
||||
+ /*
|
||||
+ * USB 2.0 special considerations:
|
||||
+ *
|
||||
+ * 1. Since the core supports both OHCI and EHCI functions, it must
|
||||
+ * only be reset once.
|
||||
+ *
|
||||
+ * 2. In addition to the standard SSB reset sequence, the Host Control
|
||||
+ * Register must be programmed to bring the USB core and various
|
||||
+ * phy components out of reset.
|
||||
+ */
|
||||
+ ssb_device_enable(dev, 0);
|
||||
+ ssb_write32(dev, 0x200, 0x7ff);
|
||||
+ udelay(1);
|
||||
+ if (dev->id.revision == 1) { // bug in rev 1
|
||||
+
|
||||
+ /* Change Flush control reg */
|
||||
+ tmp = ssb_read32(dev, 0x400);
|
||||
+ tmp &= ~8;
|
||||
+ ssb_write32(dev, 0x400, tmp);
|
||||
+ tmp = ssb_read32(dev, 0x400);
|
||||
+ printk("USB20H fcr: 0x%0x\n", tmp);
|
||||
+
|
||||
+ /* Change Shim control reg */
|
||||
+ tmp = ssb_read32(dev, 0x304);
|
||||
+ tmp &= ~0x100;
|
||||
+ ssb_write32(dev, 0x304, tmp);
|
||||
+ tmp = ssb_read32(dev, 0x304);
|
||||
+ printk("USB20H shim: 0x%0x\n", tmp);
|
||||
+ }
|
||||
+ } else
|
||||
+ ssb_device_enable(dev, 0);
|
||||
|
||||
hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
|
||||
dev_name(dev->dev));
|
||||
@@ -200,6 +232,7 @@ static int ssb_ohci_resume(struct ssb_de
|
||||
static const struct ssb_device_id ssb_ohci_table[] = {
|
||||
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
|
||||
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
|
||||
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
|
||||
SSB_DEVTABLE_END
|
||||
};
|
||||
MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);
|
@ -1,16 +0,0 @@ |
||||
---
|
||||
drivers/usb/host/ohci-ssb.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
--- a/drivers/usb/host/ohci-ssb.c
|
||||
+++ b/drivers/usb/host/ohci-ssb.c
|
||||
@@ -106,6 +106,9 @@ static int ssb_ohci_attach(struct ssb_de
|
||||
int err = -ENOMEM;
|
||||
u32 tmp, flags = 0;
|
||||
|
||||
+ if (ssb_dma_set_mask(dev, DMA_BIT_MASK(32)))
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) {
|
||||
/* Put the device into host-mode. */
|
||||
flags |= SSB_OHCI_TMSLOW_HOSTMODE;
|
@ -1,63 +0,0 @@ |
||||
This patch significantly improves the reliability of high speed
|
||||
usb writes on the bcm5354. It implements a work around for version 2
|
||||
of the usb20 core that was cribbed from the GPL sources for the
|
||||
Asus wl500gpv2 and verified against the wl520gu sources.
|
||||
|
||||
Reference:
|
||||
GPL/WL-520gu-NewUI/src/linux/linux/arch/mips/brcm-boards/bcm947xx/pcibios.c
|
||||
GPL/WL-500gPV2-NewUI/src/linux/linux/arch/mips/brcm-boards/bcm947xx/pcibios.c
|
||||
|
||||
Signed-off-by: Steve Brown <sbrown@cortland.com>
|
||||
|
||||
---
|
||||
drivers/usb/host/ohci-ssb.c | 37 +++++++++++++++++++++++--------------
|
||||
1 file changed, 23 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/drivers/usb/host/ohci-ssb.c
|
||||
+++ b/drivers/usb/host/ohci-ssb.c
|
||||
@@ -141,22 +141,31 @@ static int ssb_ohci_attach(struct ssb_de
|
||||
*/
|
||||
ssb_device_enable(dev, 0);
|
||||
ssb_write32(dev, 0x200, 0x7ff);
|
||||
+
|
||||
+ /* Change Flush control reg */
|
||||
+ tmp = ssb_read32(dev, 0x400);
|
||||
+ tmp &= ~8;
|
||||
+ ssb_write32(dev, 0x400, tmp);
|
||||
+ tmp = ssb_read32(dev, 0x400);
|
||||
+
|
||||
+ /* Change Shim control reg */
|
||||
+ tmp = ssb_read32(dev, 0x304);
|
||||
+ tmp &= ~0x100;
|
||||
+ ssb_write32(dev, 0x304, tmp);
|
||||
+ tmp = ssb_read32(dev, 0x304);
|
||||
+
|
||||
udelay(1);
|
||||
- if (dev->id.revision == 1) { // bug in rev 1
|
||||
|
||||
- /* Change Flush control reg */
|
||||
- tmp = ssb_read32(dev, 0x400);
|
||||
- tmp &= ~8;
|
||||
- ssb_write32(dev, 0x400, tmp);
|
||||
- tmp = ssb_read32(dev, 0x400);
|
||||
- printk("USB20H fcr: 0x%0x\n", tmp);
|
||||
-
|
||||
- /* Change Shim control reg */
|
||||
- tmp = ssb_read32(dev, 0x304);
|
||||
- tmp &= ~0x100;
|
||||
- ssb_write32(dev, 0x304, tmp);
|
||||
- tmp = ssb_read32(dev, 0x304);
|
||||
- printk("USB20H shim: 0x%0x\n", tmp);
|
||||
+ /* Work around for 5354 failures */
|
||||
+ if ((dev->id.revision == 2) && (dev->bus->chip_id == 0x5354)) {
|
||||
+ /* Change syn01 reg */
|
||||
+ tmp = 0x00fe00fe;
|
||||
+ ssb_write32(dev, 0x894, tmp);
|
||||
+
|
||||
+ /* Change syn03 reg */
|
||||
+ tmp = ssb_read32(dev, 0x89c);
|
||||
+ tmp |= 0x1;
|
||||
+ ssb_write32(dev, 0x89c, tmp);
|
||||
}
|
||||
} else
|
||||
ssb_device_enable(dev, 0);
|
@ -1,108 +0,0 @@ |
||||
--- a/arch/mips/bcm47xx/prom.c
|
||||
+++ b/arch/mips/bcm47xx/prom.c
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <asm/fw/cfe/cfe_error.h>
|
||||
|
||||
static int cfe_cons_handle;
|
||||
+static void (* __prom_putchar)(char c);
|
||||
|
||||
const char *get_system_type(void)
|
||||
{
|
||||
@@ -40,65 +41,40 @@ const char *get_system_type(void)
|
||||
|
||||
void prom_putchar(char c)
|
||||
{
|
||||
+ if (__prom_putchar)
|
||||
+ __prom_putchar(c);
|
||||
+}
|
||||
+
|
||||
+void prom_putchar_cfe(char c)
|
||||
+{
|
||||
while (cfe_write(cfe_cons_handle, &c, 1) == 0)
|
||||
;
|
||||
}
|
||||
|
||||
-static __init void prom_init_cfe(void)
|
||||
+static __init int prom_init_cfe(void)
|
||||
{
|
||||
uint32_t cfe_ept;
|
||||
uint32_t cfe_handle;
|
||||
uint32_t cfe_eptseal;
|
||||
- int argc = fw_arg0;
|
||||
- char **envp = (char **) fw_arg2;
|
||||
- int *prom_vec = (int *) fw_arg3;
|
||||
-
|
||||
- /*
|
||||
- * Check if a loader was used; if NOT, the 4 arguments are
|
||||
- * what CFE gives us (handle, 0, EPT and EPTSEAL)
|
||||
- */
|
||||
- if (argc < 0) {
|
||||
- cfe_handle = (uint32_t)argc;
|
||||
- cfe_ept = (uint32_t)envp;
|
||||
- cfe_eptseal = (uint32_t)prom_vec;
|
||||
- } else {
|
||||
- if ((int)prom_vec < 0) {
|
||||
- /*
|
||||
- * Old loader; all it gives us is the handle,
|
||||
- * so use the "known" entrypoint and assume
|
||||
- * the seal.
|
||||
- */
|
||||
- cfe_handle = (uint32_t)prom_vec;
|
||||
- cfe_ept = 0xBFC00500;
|
||||
- cfe_eptseal = CFE_EPTSEAL;
|
||||
- } else {
|
||||
- /*
|
||||
- * Newer loaders bundle the handle/ept/eptseal
|
||||
- * Note: prom_vec is in the loader's useg
|
||||
- * which is still alive in the TLB.
|
||||
- */
|
||||
- cfe_handle = prom_vec[0];
|
||||
- cfe_ept = prom_vec[2];
|
||||
- cfe_eptseal = prom_vec[3];
|
||||
- }
|
||||
- }
|
||||
|
||||
- if (cfe_eptseal != CFE_EPTSEAL) {
|
||||
- /* too early for panic to do any good */
|
||||
- printk(KERN_ERR "CFE's entrypoint seal doesn't match.");
|
||||
- while (1) ;
|
||||
- }
|
||||
+ cfe_eptseal = (uint32_t) fw_arg3;
|
||||
+ cfe_handle = (uint32_t) fw_arg0;
|
||||
+ cfe_ept = (uint32_t) fw_arg2;
|
||||
+
|
||||
+ if (cfe_eptseal != CFE_EPTSEAL)
|
||||
+ return -1;
|
||||
|
||||
cfe_init(cfe_handle, cfe_ept);
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
-static __init void prom_init_console(void)
|
||||
+static __init void prom_init_console_cfe(void)
|
||||
{
|
||||
/* Initialize CFE console */
|
||||
cfe_cons_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
|
||||
}
|
||||
|
||||
-static __init void prom_init_cmdline(void)
|
||||
+static __init void prom_init_cmdline_cfe(void)
|
||||
{
|
||||
static char buf[COMMAND_LINE_SIZE] __initdata;
|
||||
|
||||
@@ -160,9 +136,12 @@ static __init void prom_init_mem(void)
|
||||
|
||||
void __init prom_init(void)
|
||||
{
|
||||
- prom_init_cfe();
|
||||
- prom_init_console();
|
||||
- prom_init_cmdline();
|
||||
+ if (prom_init_cfe() == 0) {
|
||||
+ //prom_init_console_cfe();
|
||||
+ //prom_init_cmdline_cfe();
|
||||
+ __prom_putchar = prom_putchar_cfe;
|
||||
+ }
|
||||
+
|
||||
prom_init_mem();
|
||||
}
|
||||
|
@ -1,10 +0,0 @@ |
||||
--- a/arch/mips/Kconfig
|
||||
+++ b/arch/mips/Kconfig
|
||||
@@ -65,7 +65,6 @@ config BCM47XX
|
||||
select SSB_B43_PCI_BRIDGE if PCI
|
||||
select SSB_PCICORE_HOSTMODE if PCI
|
||||
select GENERIC_GPIO
|
||||
- select SYS_HAS_EARLY_PRINTK
|
||||
select CFE
|
||||
help
|
||||
Support for BCM47XX based boards
|
@ -1,52 +0,0 @@ |
||||
From: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
|
||||
|
||||
Add dma_dev, a pointer to struct device, to struct ssb_device. We pass it
|
||||
to the generic DMA API with SSB_BUSTYPE_PCI and SSB_BUSTYPE_SSB.
|
||||
ssb_devices_register() sets up it properly.
|
||||
|
||||
This is preparation for replacing the ssb bus specific DMA API (ssb_dma_*)
|
||||
with the generic DMA API.
|
||||
|
||||
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
|
||||
Acked-by: Michael Buesch <mb@bu3sch.de>
|
||||
Cc: Gary Zambrano <zambrano@broadcom.com>
|
||||
Cc: Stefano Brivio <stefano.brivio@polimi.it>
|
||||
Cc: Larry Finger <Larry.Finger@lwfinger.net>
|
||||
Cc: John W. Linville <linville@tuxdriver.com>
|
||||
Acked-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
|
||||
---
|
||||
|
||||
drivers/ssb/main.c | 2 ++
|
||||
include/linux/ssb/ssb.h | 2 +-
|
||||
2 files changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/ssb/main.c
|
||||
+++ b/drivers/ssb/main.c
|
||||
@@ -486,6 +486,7 @@ static int ssb_devices_register(struct s
|
||||
#ifdef CONFIG_SSB_PCIHOST
|
||||
sdev->irq = bus->host_pci->irq;
|
||||
dev->parent = &bus->host_pci->dev;
|
||||
+ sdev->dma_dev = dev->parent;
|
||||
#endif
|
||||
break;
|
||||
case SSB_BUSTYPE_PCMCIA:
|
||||
@@ -501,6 +502,7 @@ static int ssb_devices_register(struct s
|
||||
break;
|
||||
case SSB_BUSTYPE_SSB:
|
||||
dev->dma_mask = &dev->coherent_dma_mask;
|
||||
+ sdev->dma_dev = dev;
|
||||
break;
|
||||
}
|
||||
|
||||
--- a/include/linux/ssb/ssb.h
|
||||
+++ b/include/linux/ssb/ssb.h
|
||||
@@ -167,7 +167,7 @@ struct ssb_device {
|
||||
* is an optimization. */
|
||||
const struct ssb_bus_ops *ops;
|
||||
|
||||
- struct device *dev;
|
||||
+ struct device *dev, *dma_dev;
|
||||
|
||||
struct ssb_bus *bus;
|
||||
struct ssb_device_id id;
|
@ -0,0 +1,708 @@ |
||||
--- a/drivers/net/b44.c
|
||||
+++ b/drivers/net/b44.c
|
||||
@@ -135,7 +135,6 @@ static void b44_init_rings(struct b44 *)
|
||||
|
||||
static void b44_init_hw(struct b44 *, int);
|
||||
|
||||
-static int dma_desc_align_mask;
|
||||
static int dma_desc_sync_size;
|
||||
static int instance;
|
||||
|
||||
@@ -150,9 +149,8 @@ static inline void b44_sync_dma_desc_for
|
||||
unsigned long offset,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
- ssb_dma_sync_single_range_for_device(sdev, dma_base,
|
||||
- offset & dma_desc_align_mask,
|
||||
- dma_desc_sync_size, dir);
|
||||
+ dma_sync_single_for_device(sdev->dma_dev, dma_base + offset,
|
||||
+ dma_desc_sync_size, dir);
|
||||
}
|
||||
|
||||
static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev,
|
||||
@@ -160,9 +158,8 @@ static inline void b44_sync_dma_desc_for
|
||||
unsigned long offset,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
- ssb_dma_sync_single_range_for_cpu(sdev, dma_base,
|
||||
- offset & dma_desc_align_mask,
|
||||
- dma_desc_sync_size, dir);
|
||||
+ dma_sync_single_for_cpu(sdev->dma_dev, dma_base + offset,
|
||||
+ dma_desc_sync_size, dir);
|
||||
}
|
||||
|
||||
static inline unsigned long br32(const struct b44 *bp, unsigned long reg)
|
||||
@@ -608,10 +605,10 @@ static void b44_tx(struct b44 *bp)
|
||||
|
||||
BUG_ON(skb == NULL);
|
||||
|
||||
- ssb_dma_unmap_single(bp->sdev,
|
||||
- rp->mapping,
|
||||
- skb->len,
|
||||
- DMA_TO_DEVICE);
|
||||
+ dma_unmap_single(bp->sdev->dma_dev,
|
||||
+ rp->mapping,
|
||||
+ skb->len,
|
||||
+ DMA_TO_DEVICE);
|
||||
rp->skb = NULL;
|
||||
dev_kfree_skb_irq(skb);
|
||||
}
|
||||
@@ -648,29 +645,29 @@ static int b44_alloc_rx_skb(struct b44 *
|
||||
if (skb == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
- mapping = ssb_dma_map_single(bp->sdev, skb->data,
|
||||
- RX_PKT_BUF_SZ,
|
||||
- DMA_FROM_DEVICE);
|
||||
+ mapping = dma_map_single(bp->sdev->dma_dev, skb->data,
|
||||
+ RX_PKT_BUF_SZ,
|
||||
+ DMA_FROM_DEVICE);
|
||||
|
||||
/* Hardware bug work-around, the chip is unable to do PCI DMA
|
||||
to/from anything above 1GB :-( */
|
||||
- if (ssb_dma_mapping_error(bp->sdev, mapping) ||
|
||||
+ if (dma_mapping_error(bp->sdev->dma_dev, mapping) ||
|
||||
mapping + RX_PKT_BUF_SZ > DMA_BIT_MASK(30)) {
|
||||
/* Sigh... */
|
||||
- if (!ssb_dma_mapping_error(bp->sdev, mapping))
|
||||
- ssb_dma_unmap_single(bp->sdev, mapping,
|
||||
+ if (!dma_mapping_error(bp->sdev->dma_dev, mapping))
|
||||
+ dma_unmap_single(bp->sdev->dma_dev, mapping,
|
||||
RX_PKT_BUF_SZ, DMA_FROM_DEVICE);
|
||||
dev_kfree_skb_any(skb);
|
||||
skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA);
|
||||
if (skb == NULL)
|
||||
return -ENOMEM;
|
||||
- mapping = ssb_dma_map_single(bp->sdev, skb->data,
|
||||
- RX_PKT_BUF_SZ,
|
||||
- DMA_FROM_DEVICE);
|
||||
- if (ssb_dma_mapping_error(bp->sdev, mapping) ||
|
||||
- mapping + RX_PKT_BUF_SZ > DMA_BIT_MASK(30)) {
|
||||
- if (!ssb_dma_mapping_error(bp->sdev, mapping))
|
||||
- ssb_dma_unmap_single(bp->sdev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
|
||||
+ mapping = dma_map_single(bp->sdev->dma_dev, skb->data,
|
||||
+ RX_PKT_BUF_SZ,
|
||||
+ DMA_FROM_DEVICE);
|
||||
+ if (dma_mapping_error(bp->sdev->dma_dev, mapping) ||
|
||||
+ mapping + RX_PKT_BUF_SZ > DMA_BIT_MASK(30)) {
|
||||
+ if (!dma_mapping_error(bp->sdev->dma_dev, mapping))
|
||||
+ dma_unmap_single(bp->sdev->dma_dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
|
||||
dev_kfree_skb_any(skb);
|
||||
return -ENOMEM;
|
||||
}
|
||||
@@ -745,9 +742,9 @@ static void b44_recycle_rx(struct b44 *b
|
||||
dest_idx * sizeof(*dest_desc),
|
||||
DMA_BIDIRECTIONAL);
|
||||
|
||||
- ssb_dma_sync_single_for_device(bp->sdev, dest_map->mapping,
|
||||
- RX_PKT_BUF_SZ,
|
||||
- DMA_FROM_DEVICE);
|
||||
+ dma_sync_single_for_device(bp->sdev->dma_dev, dest_map->mapping,
|
||||
+ RX_PKT_BUF_SZ,
|
||||
+ DMA_FROM_DEVICE);
|
||||
}
|
||||
|
||||
static int b44_rx(struct b44 *bp, int budget)
|
||||
@@ -767,9 +764,9 @@ static int b44_rx(struct b44 *bp, int bu
|
||||
struct rx_header *rh;
|
||||
u16 len;
|
||||
|
||||
- ssb_dma_sync_single_for_cpu(bp->sdev, map,
|
||||
- RX_PKT_BUF_SZ,
|
||||
- DMA_FROM_DEVICE);
|
||||
+ dma_sync_single_for_cpu(bp->sdev->dma_dev, map,
|
||||
+ RX_PKT_BUF_SZ,
|
||||
+ DMA_FROM_DEVICE);
|
||||
rh = (struct rx_header *) skb->data;
|
||||
len = le16_to_cpu(rh->len);
|
||||
if ((len > (RX_PKT_BUF_SZ - RX_PKT_OFFSET)) ||
|
||||
@@ -801,8 +798,8 @@ static int b44_rx(struct b44 *bp, int bu
|
||||
skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod);
|
||||
if (skb_size < 0)
|
||||
goto drop_it;
|
||||
- ssb_dma_unmap_single(bp->sdev, map,
|
||||
- skb_size, DMA_FROM_DEVICE);
|
||||
+ dma_unmap_single(bp->sdev->dma_dev, map,
|
||||
+ skb_size, DMA_FROM_DEVICE);
|
||||
/* Leave out rx_header */
|
||||
skb_put(skb, len + RX_PKT_OFFSET);
|
||||
skb_pull(skb, RX_PKT_OFFSET);
|
||||
@@ -954,24 +951,24 @@ static netdev_tx_t b44_start_xmit(struct
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
- mapping = ssb_dma_map_single(bp->sdev, skb->data, len, DMA_TO_DEVICE);
|
||||
- if (ssb_dma_mapping_error(bp->sdev, mapping) || mapping + len > DMA_BIT_MASK(30)) {
|
||||
+ mapping = dma_map_single(bp->sdev->dma_dev, skb->data, len, DMA_TO_DEVICE);
|
||||
+ if (dma_mapping_error(bp->sdev->dma_dev, mapping) || mapping + len > DMA_BIT_MASK(30)) {
|
||||
struct sk_buff *bounce_skb;
|
||||
|
||||
/* Chip can't handle DMA to/from >1GB, use bounce buffer */
|
||||
- if (!ssb_dma_mapping_error(bp->sdev, mapping))
|
||||
- ssb_dma_unmap_single(bp->sdev, mapping, len,
|
||||
+ if (!dma_mapping_error(bp->sdev->dma_dev, mapping))
|
||||
+ dma_unmap_single(bp->sdev->dma_dev, mapping, len,
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
bounce_skb = __netdev_alloc_skb(dev, len, GFP_ATOMIC | GFP_DMA);
|
||||
if (!bounce_skb)
|
||||
goto err_out;
|
||||
|
||||
- mapping = ssb_dma_map_single(bp->sdev, bounce_skb->data,
|
||||
- len, DMA_TO_DEVICE);
|
||||
- if (ssb_dma_mapping_error(bp->sdev, mapping) || mapping + len > DMA_BIT_MASK(30)) {
|
||||
- if (!ssb_dma_mapping_error(bp->sdev, mapping))
|
||||
- ssb_dma_unmap_single(bp->sdev, mapping,
|
||||
+ mapping = dma_map_single(bp->sdev->dma_dev, bounce_skb->data,
|
||||
+ len, DMA_TO_DEVICE);
|
||||
+ if (dma_mapping_error(bp->sdev->dma_dev, mapping) || mapping + len > DMA_BIT_MASK(30)) {
|
||||
+ if (!dma_mapping_error(bp->sdev->dma_dev, mapping))
|
||||
+ dma_unmap_single(bp->sdev->dma_dev, mapping,
|
||||
len, DMA_TO_DEVICE);
|
||||
dev_kfree_skb_any(bounce_skb);
|
||||
goto err_out;
|
||||
@@ -1068,8 +1065,8 @@ static void b44_free_rings(struct b44 *b
|
||||
|
||||
if (rp->skb == NULL)
|
||||
continue;
|
||||
- ssb_dma_unmap_single(bp->sdev, rp->mapping, RX_PKT_BUF_SZ,
|
||||
- DMA_FROM_DEVICE);
|
||||
+ dma_unmap_single(bp->sdev->dma_dev, rp->mapping, RX_PKT_BUF_SZ,
|
||||
+ DMA_FROM_DEVICE);
|
||||
dev_kfree_skb_any(rp->skb);
|
||||
rp->skb = NULL;
|
||||
}
|
||||
@@ -1080,8 +1077,8 @@ static void b44_free_rings(struct b44 *b
|
||||
|
||||
if (rp->skb == NULL)
|
||||
continue;
|
||||
- ssb_dma_unmap_single(bp->sdev, rp->mapping, rp->skb->len,
|
||||
- DMA_TO_DEVICE);
|
||||
+ dma_unmap_single(bp->sdev->dma_dev, rp->mapping, rp->skb->len,
|
||||
+ DMA_TO_DEVICE);
|
||||
dev_kfree_skb_any(rp->skb);
|
||||
rp->skb = NULL;
|
||||
}
|
||||
@@ -1103,14 +1100,12 @@ static void b44_init_rings(struct b44 *b
|
||||
memset(bp->tx_ring, 0, B44_TX_RING_BYTES);
|
||||
|
||||
if (bp->flags & B44_FLAG_RX_RING_HACK)
|
||||
- ssb_dma_sync_single_for_device(bp->sdev, bp->rx_ring_dma,
|
||||
- DMA_TABLE_BYTES,
|
||||
- DMA_BIDIRECTIONAL);
|
||||
+ dma_sync_single_for_device(bp->sdev->dma_dev, bp->rx_ring_dma,
|
||||
+ DMA_TABLE_BYTES, DMA_BIDIRECTIONAL);
|
||||
|
||||
if (bp->flags & B44_FLAG_TX_RING_HACK)
|
||||
- ssb_dma_sync_single_for_device(bp->sdev, bp->tx_ring_dma,
|
||||
- DMA_TABLE_BYTES,
|
||||
- DMA_TO_DEVICE);
|
||||
+ dma_sync_single_for_device(bp->sdev->dma_dev, bp->tx_ring_dma,
|
||||
+ DMA_TABLE_BYTES, DMA_TO_DEVICE);
|
||||
|
||||
for (i = 0; i < bp->rx_pending; i++) {
|
||||
if (b44_alloc_rx_skb(bp, -1, i) < 0)
|
||||
@@ -1130,27 +1125,23 @@ static void b44_free_consistent(struct b
|
||||
bp->tx_buffers = NULL;
|
||||
if (bp->rx_ring) {
|
||||
if (bp->flags & B44_FLAG_RX_RING_HACK) {
|
||||
- ssb_dma_unmap_single(bp->sdev, bp->rx_ring_dma,
|
||||
- DMA_TABLE_BYTES,
|
||||
- DMA_BIDIRECTIONAL);
|
||||
+ dma_unmap_single(bp->sdev->dma_dev, bp->rx_ring_dma,
|
||||
+ DMA_TABLE_BYTES, DMA_BIDIRECTIONAL);
|
||||
kfree(bp->rx_ring);
|
||||
} else
|
||||
- ssb_dma_free_consistent(bp->sdev, DMA_TABLE_BYTES,
|
||||
- bp->rx_ring, bp->rx_ring_dma,
|
||||
- GFP_KERNEL);
|
||||
+ dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES,
|
||||
+ bp->rx_ring, bp->rx_ring_dma);
|
||||
bp->rx_ring = NULL;
|
||||
bp->flags &= ~B44_FLAG_RX_RING_HACK;
|
||||
}
|
||||
if (bp->tx_ring) {
|
||||
if (bp->flags & B44_FLAG_TX_RING_HACK) {
|
||||
- ssb_dma_unmap_single(bp->sdev, bp->tx_ring_dma,
|
||||
- DMA_TABLE_BYTES,
|
||||
- DMA_TO_DEVICE);
|
||||
+ dma_unmap_single(bp->sdev->dma_dev, bp->tx_ring_dma,
|
||||
+ DMA_TABLE_BYTES, DMA_TO_DEVICE);
|
||||
kfree(bp->tx_ring);
|
||||
} else
|
||||
- ssb_dma_free_consistent(bp->sdev, DMA_TABLE_BYTES,
|
||||
- bp->tx_ring, bp->tx_ring_dma,
|
||||
- GFP_KERNEL);
|
||||
+ dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES,
|
||||
+ bp->tx_ring, bp->tx_ring_dma);
|
||||
bp->tx_ring = NULL;
|
||||
bp->flags &= ~B44_FLAG_TX_RING_HACK;
|
||||
}
|
||||
@@ -1175,7 +1166,8 @@ static int b44_alloc_consistent(struct b
|
||||
goto out_err;
|
||||
|
||||
size = DMA_TABLE_BYTES;
|
||||
- bp->rx_ring = ssb_dma_alloc_consistent(bp->sdev, size, &bp->rx_ring_dma, gfp);
|
||||
+ bp->rx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size,
|
||||
+ &bp->rx_ring_dma, gfp);
|
||||
if (!bp->rx_ring) {
|
||||
/* Allocation may have failed due to pci_alloc_consistent
|
||||
insisting on use of GFP_DMA, which is more restrictive
|
||||
@@ -1187,11 +1179,11 @@ static int b44_alloc_consistent(struct b
|
||||
if (!rx_ring)
|
||||
goto out_err;
|
||||
|
||||
- rx_ring_dma = ssb_dma_map_single(bp->sdev, rx_ring,
|
||||
- DMA_TABLE_BYTES,
|
||||
- DMA_BIDIRECTIONAL);
|
||||
+ rx_ring_dma = dma_map_single(bp->sdev->dma_dev, rx_ring,
|
||||
+ DMA_TABLE_BYTES,
|
||||
+ DMA_BIDIRECTIONAL);
|
||||
|
||||
- if (ssb_dma_mapping_error(bp->sdev, rx_ring_dma) ||
|
||||
+ if (dma_mapping_error(bp->sdev->dma_dev, rx_ring_dma) ||
|
||||
rx_ring_dma + size > DMA_BIT_MASK(30)) {
|
||||
kfree(rx_ring);
|
||||
goto out_err;
|
||||
@@ -1202,7 +1194,8 @@ static int b44_alloc_consistent(struct b
|
||||
bp->flags |= B44_FLAG_RX_RING_HACK;
|
||||
}
|
||||
|
||||
- bp->tx_ring = ssb_dma_alloc_consistent(bp->sdev, size, &bp->tx_ring_dma, gfp);
|
||||
+ bp->tx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size,
|
||||
+ &bp->tx_ring_dma, gfp);
|
||||
if (!bp->tx_ring) {
|
||||
/* Allocation may have failed due to ssb_dma_alloc_consistent
|
||||
insisting on use of GFP_DMA, which is more restrictive
|
||||
@@ -1214,11 +1207,11 @@ static int b44_alloc_consistent(struct b
|
||||
if (!tx_ring)
|
||||
goto out_err;
|
||||
|
||||
- tx_ring_dma = ssb_dma_map_single(bp->sdev, tx_ring,
|
||||
- DMA_TABLE_BYTES,
|
||||
- DMA_TO_DEVICE);
|
||||
+ tx_ring_dma = dma_map_single(bp->sdev->dma_dev, tx_ring,
|
||||
+ DMA_TABLE_BYTES,
|
||||
+ DMA_TO_DEVICE);
|
||||
|
||||
- if (ssb_dma_mapping_error(bp->sdev, tx_ring_dma) ||
|
||||
+ if (dma_mapping_error(bp->sdev->dma_dev, tx_ring_dma) ||
|
||||
tx_ring_dma + size > DMA_BIT_MASK(30)) {
|
||||
kfree(tx_ring);
|
||||
goto out_err;
|
||||
@@ -2176,12 +2169,14 @@ static int __devinit b44_init_one(struct
|
||||
"Failed to powerup the bus\n");
|
||||
goto err_out_free_dev;
|
||||
}
|
||||
- err = ssb_dma_set_mask(sdev, DMA_BIT_MASK(30));
|
||||
- if (err) {
|
||||
+
|
||||
+ if (dma_set_mask(sdev->dma_dev, DMA_BIT_MASK(30)) ||
|
||||
+ dma_set_coherent_mask(sdev->dma_dev, DMA_BIT_MASK(30))) {
|
||||
dev_err(sdev->dev,
|
||||
"Required 30BIT DMA mask unsupported by the system\n");
|
||||
goto err_out_powerdown;
|
||||
}
|
||||
+
|
||||
err = b44_get_invariants(bp);
|
||||
if (err) {
|
||||
dev_err(sdev->dev,
|
||||
@@ -2344,7 +2339,6 @@ static int __init b44_init(void)
|
||||
int err;
|
||||
|
||||
/* Setup paramaters for syncing RX/TX DMA descriptors */
|
||||
- dma_desc_align_mask = ~(dma_desc_align_size - 1);
|
||||
dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc));
|
||||
|
||||
err = b44_pci_init();
|
||||
--- a/drivers/ssb/driver_chipcommon.c
|
||||
+++ b/drivers/ssb/driver_chipcommon.c
|
||||
@@ -209,6 +209,24 @@ static void chipco_powercontrol_init(str
|
||||
}
|
||||
}
|
||||
|
||||
+/* http://bcm-v4.sipsolutions.net/802.11/PmuFastPwrupDelay */
|
||||
+static u16 pmu_fast_powerup_delay(struct ssb_chipcommon *cc)
|
||||
+{
|
||||
+ struct ssb_bus *bus = cc->dev->bus;
|
||||
+
|
||||
+ switch (bus->chip_id) {
|
||||
+ case 0x4312:
|
||||
+ case 0x4322:
|
||||
+ case 0x4328:
|
||||
+ return 7000;
|
||||
+ case 0x4325:
|
||||
+ /* TODO: */
|
||||
+ default:
|
||||
+ return 15000;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* http://bcm-v4.sipsolutions.net/802.11/ClkctlFastPwrupDelay */
|
||||
static void calc_fast_powerup_delay(struct ssb_chipcommon *cc)
|
||||
{
|
||||
struct ssb_bus *bus = cc->dev->bus;
|
||||
@@ -218,6 +236,12 @@ static void calc_fast_powerup_delay(stru
|
||||
|
||||
if (bus->bustype != SSB_BUSTYPE_PCI)
|
||||
return;
|
||||
+
|
||||
+ if (cc->capabilities & SSB_CHIPCO_CAP_PMU) {
|
||||
+ cc->fast_pwrup_delay = pmu_fast_powerup_delay(cc);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL))
|
||||
return;
|
||||
|
||||
@@ -235,6 +259,7 @@ void ssb_chipcommon_init(struct ssb_chip
|
||||
return; /* We don't have a ChipCommon */
|
||||
if (cc->dev->id.revision >= 11)
|
||||
cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT);
|
||||
+ ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status);
|
||||
ssb_pmu_init(cc);
|
||||
chipco_powercontrol_init(cc);
|
||||
ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
|
||||
--- a/drivers/ssb/driver_chipcommon_pmu.c
|
||||
+++ b/drivers/ssb/driver_chipcommon_pmu.c
|
||||
@@ -502,9 +502,9 @@ static void ssb_pmu_resources_init(struc
|
||||
chipco_write32(cc, SSB_CHIPCO_PMU_MAXRES_MSK, max_msk);
|
||||
}
|
||||
|
||||
+/* http://bcm-v4.sipsolutions.net/802.11/SSB/PmuInit */
|
||||
void ssb_pmu_init(struct ssb_chipcommon *cc)
|
||||
{
|
||||
- struct ssb_bus *bus = cc->dev->bus;
|
||||
u32 pmucap;
|
||||
|
||||
if (!(cc->capabilities & SSB_CHIPCO_CAP_PMU))
|
||||
@@ -516,15 +516,12 @@ void ssb_pmu_init(struct ssb_chipcommon
|
||||
ssb_dprintk(KERN_DEBUG PFX "Found rev %u PMU (capabilities 0x%08X)\n",
|
||||
cc->pmu.rev, pmucap);
|
||||
|
||||
- if (cc->pmu.rev >= 1) {
|
||||
- if ((bus->chip_id == 0x4325) && (bus->chip_rev < 2)) {
|
||||
- chipco_mask32(cc, SSB_CHIPCO_PMU_CTL,
|
||||
- ~SSB_CHIPCO_PMU_CTL_NOILPONW);
|
||||
- } else {
|
||||
- chipco_set32(cc, SSB_CHIPCO_PMU_CTL,
|
||||
- SSB_CHIPCO_PMU_CTL_NOILPONW);
|
||||
- }
|
||||
- }
|
||||
+ if (cc->pmu.rev == 1)
|
||||
+ chipco_mask32(cc, SSB_CHIPCO_PMU_CTL,
|
||||
+ ~SSB_CHIPCO_PMU_CTL_NOILPONW);
|
||||
+ else
|
||||
+ chipco_set32(cc, SSB_CHIPCO_PMU_CTL,
|
||||
+ SSB_CHIPCO_PMU_CTL_NOILPONW);
|
||||
ssb_pmu_pll_init(cc);
|
||||
ssb_pmu_resources_init(cc);
|
||||
}
|
||||
--- a/drivers/ssb/main.c
|
||||
+++ b/drivers/ssb/main.c
|
||||
@@ -486,6 +486,7 @@ static int ssb_devices_register(struct s
|
||||
#ifdef CONFIG_SSB_PCIHOST
|
||||
sdev->irq = bus->host_pci->irq;
|
||||
dev->parent = &bus->host_pci->dev;
|
||||
+ sdev->dma_dev = dev->parent;
|
||||
#endif
|
||||
break;
|
||||
case SSB_BUSTYPE_PCMCIA:
|
||||
@@ -501,6 +502,7 @@ static int ssb_devices_register(struct s
|
||||
break;
|
||||
case SSB_BUSTYPE_SSB:
|
||||
dev->dma_mask = &dev->coherent_dma_mask;
|
||||
+ sdev->dma_dev = dev;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1226,80 +1228,6 @@ u32 ssb_dma_translation(struct ssb_devic
|
||||
}
|
||||
EXPORT_SYMBOL(ssb_dma_translation);
|
||||
|
||||
-int ssb_dma_set_mask(struct ssb_device *dev, u64 mask)
|
||||
-{
|
||||
-#ifdef CONFIG_SSB_PCIHOST
|
||||
- int err;
|
||||
-#endif
|
||||
-
|
||||
- switch (dev->bus->bustype) {
|
||||
- case SSB_BUSTYPE_PCI:
|
||||
-#ifdef CONFIG_SSB_PCIHOST
|
||||
- err = pci_set_dma_mask(dev->bus->host_pci, mask);
|
||||
- if (err)
|
||||
- return err;
|
||||
- err = pci_set_consistent_dma_mask(dev->bus->host_pci, mask);
|
||||
- return err;
|
||||
-#endif
|
||||
- case SSB_BUSTYPE_SSB:
|
||||
- return dma_set_mask(dev->dev, mask);
|
||||
- default:
|
||||
- __ssb_dma_not_implemented(dev);
|
||||
- }
|
||||
- return -ENOSYS;
|
||||
-}
|
||||
-EXPORT_SYMBOL(ssb_dma_set_mask);
|
||||
-
|
||||
-void * ssb_dma_alloc_consistent(struct ssb_device *dev, size_t size,
|
||||
- dma_addr_t *dma_handle, gfp_t gfp_flags)
|
||||
-{
|
||||
- switch (dev->bus->bustype) {
|
||||
- case SSB_BUSTYPE_PCI:
|
||||
-#ifdef CONFIG_SSB_PCIHOST
|
||||
- if (gfp_flags & GFP_DMA) {
|
||||
- /* Workaround: The PCI API does not support passing
|
||||
- * a GFP flag. */
|
||||
- return dma_alloc_coherent(&dev->bus->host_pci->dev,
|
||||
- size, dma_handle, gfp_flags);
|
||||
- }
|
||||
- return pci_alloc_consistent(dev->bus->host_pci, size, dma_handle);
|
||||
-#endif
|
||||
- case SSB_BUSTYPE_SSB:
|
||||
- return dma_alloc_coherent(dev->dev, size, dma_handle, gfp_flags);
|
||||
- default:
|
||||
- __ssb_dma_not_implemented(dev);
|
||||
- }
|
||||
- return NULL;
|
||||
-}
|
||||
-EXPORT_SYMBOL(ssb_dma_alloc_consistent);
|
||||
-
|
||||
-void ssb_dma_free_consistent(struct ssb_device *dev, size_t size,
|
||||
- void *vaddr, dma_addr_t dma_handle,
|
||||
- gfp_t gfp_flags)
|
||||
-{
|
||||
- switch (dev->bus->bustype) {
|
||||
- case SSB_BUSTYPE_PCI:
|
||||
-#ifdef CONFIG_SSB_PCIHOST
|
||||
- if (gfp_flags & GFP_DMA) {
|
||||
- /* Workaround: The PCI API does not support passing
|
||||
- * a GFP flag. */
|
||||
- dma_free_coherent(&dev->bus->host_pci->dev,
|
||||
- size, vaddr, dma_handle);
|
||||
- return;
|
||||
- }
|
||||
- pci_free_consistent(dev->bus->host_pci, size,
|
||||
- vaddr, dma_handle);
|
||||
- return;
|
||||
-#endif
|
||||
- case SSB_BUSTYPE_SSB:
|
||||
- dma_free_coherent(dev->dev, size, vaddr, dma_handle);
|
||||
- return;
|
||||
- default:
|
||||
- __ssb_dma_not_implemented(dev);
|
||||
- }
|
||||
-}
|
||||
-EXPORT_SYMBOL(ssb_dma_free_consistent);
|
||||
-
|
||||
int ssb_bus_may_powerdown(struct ssb_bus *bus)
|
||||
{
|
||||
struct ssb_chipcommon *cc;
|
||||
--- a/drivers/ssb/pci.c
|
||||
+++ b/drivers/ssb/pci.c
|
||||
@@ -626,11 +626,22 @@ static int ssb_pci_sprom_get(struct ssb_
|
||||
return -ENODEV;
|
||||
}
|
||||
if (bus->chipco.dev) { /* can be unavailible! */
|
||||
- bus->sprom_offset = (bus->chipco.dev->id.revision < 31) ?
|
||||
- SSB_SPROM_BASE1 : SSB_SPROM_BASE31;
|
||||
+ /*
|
||||
+ * get SPROM offset: SSB_SPROM_BASE1 except for
|
||||
+ * chipcommon rev >= 31 or chip ID is 0x4312 and
|
||||
+ * chipcommon status & 3 == 2
|
||||
+ */
|
||||
+ if (bus->chipco.dev->id.revision >= 31)
|
||||
+ bus->sprom_offset = SSB_SPROM_BASE31;
|
||||
+ else if (bus->chip_id == 0x4312 &&
|
||||
+ (bus->chipco.status & 0x03) == 2)
|
||||
+ bus->sprom_offset = SSB_SPROM_BASE31;
|
||||
+ else
|
||||
+ bus->sprom_offset = SSB_SPROM_BASE1;
|
||||
} else {
|
||||
bus->sprom_offset = SSB_SPROM_BASE1;
|
||||
}
|
||||
+ ssb_dprintk(KERN_INFO PFX "SPROM offset is 0x%x\n", bus->sprom_offset);
|
||||
|
||||
buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
|
||||
if (!buf)
|
||||
--- a/include/linux/ssb/ssb.h
|
||||
+++ b/include/linux/ssb/ssb.h
|
||||
@@ -167,7 +167,7 @@ struct ssb_device {
|
||||
* is an optimization. */
|
||||
const struct ssb_bus_ops *ops;
|
||||
|
||||
- struct device *dev;
|
||||
+ struct device *dev, *dma_dev;
|
||||
|
||||
struct ssb_bus *bus;
|
||||
struct ssb_device_id id;
|
||||
@@ -470,14 +470,6 @@ extern u32 ssb_dma_translation(struct ss
|
||||
#define SSB_DMA_TRANSLATION_MASK 0xC0000000
|
||||
#define SSB_DMA_TRANSLATION_SHIFT 30
|
||||
|
||||
-extern int ssb_dma_set_mask(struct ssb_device *dev, u64 mask);
|
||||
-
|
||||
-extern void * ssb_dma_alloc_consistent(struct ssb_device *dev, size_t size,
|
||||
- dma_addr_t *dma_handle, gfp_t gfp_flags);
|
||||
-extern void ssb_dma_free_consistent(struct ssb_device *dev, size_t size,
|
||||
- void *vaddr, dma_addr_t dma_handle,
|
||||
- gfp_t gfp_flags);
|
||||
-
|
||||
static inline void __cold __ssb_dma_not_implemented(struct ssb_device *dev)
|
||||
{
|
||||
#ifdef CONFIG_SSB_DEBUG
|
||||
@@ -486,155 +478,6 @@ static inline void __cold __ssb_dma_not_
|
||||
#endif /* DEBUG */
|
||||
}
|
||||
|
||||
-static inline int ssb_dma_mapping_error(struct ssb_device *dev, dma_addr_t addr)
|
||||
-{
|
||||
- switch (dev->bus->bustype) {
|
||||
- case SSB_BUSTYPE_PCI:
|
||||
-#ifdef CONFIG_SSB_PCIHOST
|
||||
- return pci_dma_mapping_error(dev->bus->host_pci, addr);
|
||||
-#endif
|
||||
- break;
|
||||
- case SSB_BUSTYPE_SSB:
|
||||
- return dma_mapping_error(dev->dev, addr);
|
||||
- default:
|
||||
- break;
|
||||
- }
|
||||
- __ssb_dma_not_implemented(dev);
|
||||
- return -ENOSYS;
|
||||
-}
|
||||
-
|
||||
-static inline dma_addr_t ssb_dma_map_single(struct ssb_device *dev, void *p,
|
||||
- size_t size, enum dma_data_direction dir)
|
||||
-{
|
||||
- switch (dev->bus->bustype) {
|
||||
- case SSB_BUSTYPE_PCI:
|
||||
-#ifdef CONFIG_SSB_PCIHOST
|
||||
- return pci_map_single(dev->bus->host_pci, p, size, dir);
|
||||
-#endif
|
||||
- break;
|
||||
- case SSB_BUSTYPE_SSB:
|
||||
- return dma_map_single(dev->dev, p, size, dir);
|
||||
- default:
|
||||
- break;
|
||||
- }
|
||||
- __ssb_dma_not_implemented(dev);
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static inline void ssb_dma_unmap_single(struct ssb_device *dev, dma_addr_t dma_addr,
|
||||
- size_t size, enum dma_data_direction dir)
|
||||
-{
|
||||
- switch (dev->bus->bustype) {
|
||||
- case SSB_BUSTYPE_PCI:
|
||||
-#ifdef CONFIG_SSB_PCIHOST
|
||||
- pci_unmap_single(dev->bus->host_pci, dma_addr, size, dir);
|
||||
- return;
|
||||
-#endif
|
||||
- break;
|
||||
- case SSB_BUSTYPE_SSB:
|
||||
- dma_unmap_single(dev->dev, dma_addr, size, dir);
|
||||
- return;
|
||||
- default:
|
||||
- break;
|
||||
- }
|
||||
- __ssb_dma_not_implemented(dev);
|
||||
-}
|
||||
-
|
||||
-static inline void ssb_dma_sync_single_for_cpu(struct ssb_device *dev,
|
||||
- dma_addr_t dma_addr,
|
||||
- size_t size,
|
||||
- enum dma_data_direction dir)
|
||||
-{
|
||||
- switch (dev->bus->bustype) {
|
||||
- case SSB_BUSTYPE_PCI:
|
||||
-#ifdef CONFIG_SSB_PCIHOST
|
||||
- pci_dma_sync_single_for_cpu(dev->bus->host_pci, dma_addr,
|
||||
- size, dir);
|
||||
- return;
|
||||
-#endif
|
||||
- break;
|
||||
- case SSB_BUSTYPE_SSB:
|
||||
- dma_sync_single_for_cpu(dev->dev, dma_addr, size, dir);
|
||||
- return;
|
||||
- default:
|
||||
- break;
|
||||
- }
|
||||
- __ssb_dma_not_implemented(dev);
|
||||
-}
|
||||
-
|
||||
-static inline void ssb_dma_sync_single_for_device(struct ssb_device *dev,
|
||||
- dma_addr_t dma_addr,
|
||||
- size_t size,
|
||||
- enum dma_data_direction dir)
|
||||
-{
|
||||
- switch (dev->bus->bustype) {
|
||||
- case SSB_BUSTYPE_PCI:
|
||||
-#ifdef CONFIG_SSB_PCIHOST
|
||||
- pci_dma_sync_single_for_device(dev->bus->host_pci, dma_addr,
|
||||
- size, dir);
|
||||
- return;
|
||||
-#endif
|
||||
- break;
|
||||
- case SSB_BUSTYPE_SSB:
|
||||
- dma_sync_single_for_device(dev->dev, dma_addr, size, dir);
|
||||
- return;
|
||||
- default:
|
||||
- break;
|
||||
- }
|
||||
- __ssb_dma_not_implemented(dev);
|
||||
-}
|
||||
-
|
||||
-static inline void ssb_dma_sync_single_range_for_cpu(struct ssb_device *dev,
|
||||
- dma_addr_t dma_addr,
|
||||
- unsigned long offset,
|
||||
- size_t size,
|
||||
- enum dma_data_direction dir)
|
||||
-{
|
||||
- switch (dev->bus->bustype) {
|
||||
- case SSB_BUSTYPE_PCI:
|
||||
-#ifdef CONFIG_SSB_PCIHOST
|
||||
- /* Just sync everything. That's all the PCI API can do. */
|
||||
- pci_dma_sync_single_for_cpu(dev->bus->host_pci, dma_addr,
|
||||
- offset + size, dir);
|
||||
- return;
|
||||
-#endif
|
||||
- break;
|
||||
- case SSB_BUSTYPE_SSB:
|
||||
- dma_sync_single_range_for_cpu(dev->dev, dma_addr, offset,
|
||||
- size, dir);
|
||||
- return;
|
||||
- default:
|
||||
- break;
|
||||
- }
|
||||
- __ssb_dma_not_implemented(dev);
|
||||
-}
|
||||
-
|
||||
-static inline void ssb_dma_sync_single_range_for_device(struct ssb_device *dev,
|
||||
- dma_addr_t dma_addr,
|
||||
- unsigned long offset,
|
||||
- size_t size,
|
||||
- enum dma_data_direction dir)
|
||||
-{
|
||||
- switch (dev->bus->bustype) {
|
||||
- case SSB_BUSTYPE_PCI:
|
||||
-#ifdef CONFIG_SSB_PCIHOST
|
||||
- /* Just sync everything. That's all the PCI API can do. */
|
||||
- pci_dma_sync_single_for_device(dev->bus->host_pci, dma_addr,
|
||||
- offset + size, dir);
|
||||
- return;
|
||||
-#endif
|
||||
- break;
|
||||
- case SSB_BUSTYPE_SSB:
|
||||
- dma_sync_single_range_for_device(dev->dev, dma_addr, offset,
|
||||
- size, dir);
|
||||
- return;
|
||||
- default:
|
||||
- break;
|
||||
- }
|
||||
- __ssb_dma_not_implemented(dev);
|
||||
-}
|
||||
-
|
||||
-
|
||||
#ifdef CONFIG_SSB_PCIHOST
|
||||
/* PCI-host wrapper driver */
|
||||
extern int ssb_pcihost_register(struct pci_driver *driver);
|
@ -1,52 +0,0 @@ |
||||
From: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
|
||||
|
||||
Add dma_dev, a pointer to struct device, to struct ssb_device. We pass it
|
||||
to the generic DMA API with SSB_BUSTYPE_PCI and SSB_BUSTYPE_SSB.
|
||||
ssb_devices_register() sets up it properly.
|
||||
|
||||
This is preparation for replacing the ssb bus specific DMA API (ssb_dma_*)
|
||||
with the generic DMA API.
|
||||
|
||||
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
|
||||
Acked-by: Michael Buesch <mb@bu3sch.de>
|
||||
Cc: Gary Zambrano <zambrano@broadcom.com>
|
||||
Cc: Stefano Brivio <stefano.brivio@polimi.it>
|
||||
Cc: Larry Finger <Larry.Finger@lwfinger.net>
|
||||
Cc: John W. Linville <linville@tuxdriver.com>
|
||||
Acked-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
|
||||
---
|
||||
|
||||
drivers/ssb/main.c | 2 ++
|
||||
include/linux/ssb/ssb.h | 2 +-
|
||||
2 files changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/ssb/main.c
|
||||
+++ b/drivers/ssb/main.c
|
||||
@@ -486,6 +486,7 @@ static int ssb_devices_register(struct s
|
||||
#ifdef CONFIG_SSB_PCIHOST
|
||||
sdev->irq = bus->host_pci->irq;
|
||||
dev->parent = &bus->host_pci->dev;
|
||||
+ sdev->dma_dev = dev->parent;
|
||||
#endif
|
||||
break;
|
||||
case SSB_BUSTYPE_PCMCIA:
|
||||
@@ -501,6 +502,7 @@ static int ssb_devices_register(struct s
|
||||
break;
|
||||
case SSB_BUSTYPE_SSB:
|
||||
dev->dma_mask = &dev->coherent_dma_mask;
|
||||
+ sdev->dma_dev = dev;
|
||||
break;
|
||||
}
|
||||
|
||||
--- a/include/linux/ssb/ssb.h
|
||||
+++ b/include/linux/ssb/ssb.h
|
||||
@@ -167,7 +167,7 @@ struct ssb_device {
|
||||
* is an optimization. */
|
||||
const struct ssb_bus_ops *ops;
|
||||
|
||||
- struct device *dev;
|
||||
+ struct device *dev, *dma_dev;
|
||||
|
||||
struct ssb_bus *bus;
|
||||
struct ssb_device_id id;
|
Loading…
Reference in new issue