Hi,
Attached is the kernel patch to support Netgear WNR3500L. All changes
are made under CONFIG_WNR3500L.
I have used trunk source code of version number 21251 to create this
kernel patch.
Regards,
Tathagata <tathag...@alumnux.com>
diff -Naur a/arch/mips/bcm47xx/irq.c b/arch/mips/bcm47xx/irq.c
--- a/arch/mips/bcm47xx/irq.c 2010-05-13 18:22:34.000000000 +0530
+++ b/arch/mips/bcm47xx/irq.c 2010-05-13 18:19:35.000000000 +0530
@@ -30,6 +30,9 @@
#include <linux/irq.h>
#include <linux/pci.h>
#include <linux/ssb/ssb.h>
+#ifdef CONFIG_WNR3500L
+#include <linux/ssb/ssb_driver_mips.h>
+#endif
#include <asm/irq_cpu.h>
@@ -37,7 +40,11 @@
extern struct ssb_bus ssb_bcm47xx;
+#ifndef CONFIG_WNR3500L
void plat_irq_dispatch(void)
+#else
+void asmlinkage plat_irq_dispatch(void)
+#endif
{
u32 cause;
@@ -61,5 +68,12 @@
void __init arch_init_irq(void)
{
+#ifdef CONFIG_WNR3500L
+ if (ssb_bcm47xx.mipscore.dev->id.coreid == SSB_DEV_MIPS_74K) {
+ ssb_write32(ssb_bcm47xx.mipscore.dev,
SSB_MIPS74K_INT_CONTROL(5), 1 << 31);
+ }
+ /* the kernel reads the timer irq from some register and beleave it's
#5, but we route it to #7 */
+ cp0_compare_irq = 7;
+#endif
mips_cpu_irq_init();
}
diff -Naur a/arch/mips/include/asm/r4kcache.h b/arch/mips/include/asm/r4kcache.h
--- a/arch/mips/include/asm/r4kcache.h 2010-05-13 18:22:34.000000000 +0530
+++ b/arch/mips/include/asm/r4kcache.h 2010-05-13 18:19:36.000000000 +0530
@@ -22,9 +22,15 @@
#include <linux/ssb/ssb.h>
#define BCM4710_DUMMY_RREG() bcm4710_dummy_rreg()
+#ifndef CONFIG_WNR3500L
static inline unsigned long bcm4710_dummy_rreg(void) {
return (*(volatile unsigned long *)(KSEG1ADDR(SSB_ENUM_BASE +
SSB_IMSTATE)));
}
+#else
+static inline unsigned long bcm4710_dummy_rreg(void) {
+ return (*(volatile unsigned long *)(KSEG1ADDR(SSB_ENUM_BASE)));
+}
+#endif
#define BCM4710_FILL_TLB(addr) bcm4710_fill_tlb((void*)(addr))
diff -Naur a/arch/mips/Kconfig b/arch/mips/Kconfig
--- a/arch/mips/Kconfig 2010-05-13 18:22:35.000000000 +0530
+++ b/arch/mips/Kconfig 2010-05-13 18:19:37.000000000 +0530
@@ -9,6 +9,10 @@
select EMBEDDED
select RTC_LIB if !LEMOTE_FULOONG2E
+config WNR3500L
+ bool "Netgear WNR3500L"
+ default y
+
mainmenu "Linux/MIPS Kernel Configuration"
menu "Machine selection"
diff -Naur a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
--- a/drivers/mtd/devices/Kconfig 2010-05-13 18:23:09.000000000 +0530
+++ b/drivers/mtd/devices/Kconfig 2010-05-13 18:20:36.000000000 +0530
@@ -3,6 +3,9 @@
menu "Self-contained MTD device drivers"
depends on MTD!=n
+config MTD_SFLASH
+ bool "Broadcom Chipcommon Serial Flash support"
+
config MTD_PMC551
tristate "Ramix PMC551 PCI Mezzanine RAM card support"
depends on PCI
diff -Naur a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
--- a/drivers/mtd/devices/Makefile 2010-05-13 18:23:09.000000000 +0530
+++ b/drivers/mtd/devices/Makefile 2010-05-13 18:20:36.000000000 +0530
@@ -2,6 +2,7 @@
# linux/drivers/devices/Makefile
#
+obj-$(CONFIG_MTD_SFLASH) += sflash.o
obj-$(CONFIG_MTD_DOC2000) += doc2000.o
obj-$(CONFIG_MTD_DOC2001) += doc2001.o
obj-$(CONFIG_MTD_DOC2001PLUS) += doc2001plus.o
diff -Naur a/drivers/mtd/devices/sflash.c b/drivers/mtd/devices/sflash.c
--- a/drivers/mtd/devices/sflash.c 1970-01-01 05:30:00.000000000 +0530
+++ b/drivers/mtd/devices/sflash.c 2010-05-13 18:20:36.000000000 +0530
@@ -0,0 +1,925 @@
+/*
+ * Broadcom SiliconBackplane chipcommon serial flash interface
+ *
+ * Copyright 2007, 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/mtd/compatmac.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <linux/ssb/ssb.h>
+#include <linux/ssb/ssb_embedded.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+
+extern struct ssb_bus ssb_bcm47xx;
+#ifdef CONFIG_MTD_PARTITIONS
+extern struct mtd_partition * init_mtd_partitions(struct mtd_info *mtd, size_t
size);
+#endif
+
+struct sflash_mtd {
+ u32 *base_regs;
+ struct semaphore lock;
+ struct mtd_info mtd;
+ struct mtd_erase_region_info region;
+};
+
+struct sflash {
+ u32 blocksize; /* Block size */
+ u32 numblocks; /* Number of blocks */
+ u32 type; /* Type */
+ u32 size; /* Total size in bytes */
+};
+
+static struct sflash wnr3500l_sflash;
+
+/* Private global state */
+static struct sflash_mtd sflash;
+
+//extern unsigned long volatile __jiffy_data jiffies;
+
+#define CC_CORE_ID 0x800 /* chipcommon core */
+#define SB_FLASH2 0x1c000000 /* Flash Region 2 (region 1 shadowed here)
*/
+#define CC_CAP_FLASH_MASK 0x00000700 /* Type of flash */
+#define SFLASH_START 0x80000000
+#define SFLASH_BUSY SFLASH_START
+#define SFLASH_ST 0x100 /* ST serial flash */
+#define SFLASH_AT 0x200 /* Atmel serial flash */
+#define SFLASH_AT_STATUS 0x01d7
+#define SFLASH_ST_DP 0x00b9 /* Deep Power-down */
+#define SFLASH_ST_RES 0x03ab /* Read Electronic Signature */
+#define SFLASH_ST_RDSR 0x0105 /* Read Status Register */
+#define SFLASH_ST_WIP 0x01 /* Write In Progress */
+#define SFLASH_AT_READY 0x80
+
+#define OSL_UNCACHED(va) ((void *)KSEG1ADDR(va))
+#define OSL_CACHED(va) ((void *)KSEG0ADDR(va))
+
+typedef unsigned long long int uintptr;
+
+/* Issue a serial flash command */
+static inline void sflash_cmd(u32 opcode)
+{
+ u32 *regs;
+
+ regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 0x40,
SSB_CORE_SIZE);
+ writel(SFLASH_START | opcode, regs);
+ while ((readl(regs) & SFLASH_BUSY));
+
+ iounmap(regs);
+}
+
+int sflash_read(u32 offset, u32 len, unsigned char *buf)
+{
+ u8 *from, *to;
+ int cnt, i;
+
+ if (!len)
+ return 0;
+
+ if ((offset + len) > wnr3500l_sflash.size)
+ return -22;
+
+ if ((len >= 4) && (offset & 3))
+ cnt = 4 - (offset & 3);
+ else if ((len >= 4) && ((uintptr)buf & 3))
+ cnt = 4 - ((uintptr)buf & 3);
+ else
+ cnt = len;
+
+ if (ssb_bcm47xx.chipco.dev->id.revision == 12)
+ from = (u8 *)OSL_UNCACHED(SB_FLASH2 + offset);
+ else
+ from = (u8 *)OSL_CACHED(SB_FLASH2 + offset);
+ to = (u8 *)buf;
+
+ if (cnt < 4) {
+ for (i = 0; i < cnt; i ++) {
+ /* Cannot use R_REG because in bigendian that will
+ * xor the address and we don't want that here.
+ */
+ *to = *from;
+ from ++;
+ to ++;
+ }
+ return cnt;
+ }
+
+ while (cnt >= 4) {
+ *(u32 *)to = *(u32 *)from;
+ from += 4;
+ to += 4;
+ cnt -= 4;
+ }
+
+ return (len - cnt);
+}
+
+/* Poll for command completion. Returns zero when complete. */
+int sflash_poll(u32 offset)
+{
+ u32 *regs, val;
+
+ if (offset >= wnr3500l_sflash.size)
+ return -22;
+
+ switch (wnr3500l_sflash.type) {
+ case SFLASH_ST:
+ /* Check for ST Write In Progress bit */
+ sflash_cmd(SFLASH_ST_RDSR);
+ regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 0x48,
SSB_CORE_SIZE);
+ val = readl(regs) & SFLASH_ST_WIP;
+ iounmap(regs);
+ return val;
+ case SFLASH_AT:
+ /* Check for Atmel Ready bit */
+ sflash_cmd(SFLASH_AT_STATUS);
+ regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 0x48,
SSB_CORE_SIZE);
+ val = readl(regs) & SFLASH_AT_READY;
+ iounmap(regs);
+ return !val;
+ }
+
+ return 0;
+}
+
+#if 1
+#if 1 //Imran added
+#define BCM4712_CHIP_ID 0x4712 /* 4712 chipcommon chipid */
+
+/* flashcontrol action+opcodes for ST flashes */
+#define SFLASH_ST_WREN 0x0006 /* Write Enable */
+#define SFLASH_ST_WRDIS 0x0004 /* Write Disable */
+#define SFLASH_ST_RDSR 0x0105 /* Read Status Register */
+#define SFLASH_ST_WRSR 0x0101 /* Write Status Register */
+#define SFLASH_ST_READ 0x0303 /* Read Data Bytes */
+#define SFLASH_ST_PP 0x0302 /* Page Program */
+#define SFLASH_ST_SE 0x02d8 /* Sector Erase */
+#define SFLASH_ST_BE 0x00c7 /* Bulk Erase */
+#define SFLASH_ST_DP 0x00b9 /* Deep Power-down */
+#define SFLASH_ST_RES 0x03ab /* Read Electronic Signature */
+#define SFLASH_ST_CSA 0x1000 /* Keep chip select asserted */
+
+/* flashcontrol action+opcodes for Atmel flashes */
+#define SFLASH_AT_READ 0x07e8
+#define SFLASH_AT_PAGE_READ 0x07d2
+#define SFLASH_AT_BUF1_READ
+#define SFLASH_AT_BUF2_READ
+#define SFLASH_AT_STATUS 0x01d7
+#define SFLASH_AT_BUF1_WRITE 0x0384
+#define SFLASH_AT_BUF2_WRITE 0x0387
+#define SFLASH_AT_BUF1_ERASE_PROGRAM 0x0283
+#define SFLASH_AT_BUF2_ERASE_PROGRAM 0x0286
+#define SFLASH_AT_BUF1_PROGRAM 0x0288
+#define SFLASH_AT_BUF2_PROGRAM 0x0289
+#define SFLASH_AT_PAGE_ERASE 0x0281
+#define SFLASH_AT_BLOCK_ERASE 0x0250
+#define SFLASH_AT_BUF1_WRITE_ERASE_PROGRAM 0x0382
+#define SFLASH_AT_BUF2_WRITE_ERASE_PROGRAM 0x0385
+#define SFLASH_AT_BUF1_LOAD 0x0253
+#define SFLASH_AT_BUF2_LOAD 0x0255
+#define SFLASH_AT_BUF1_COMPARE 0x0260
+#define SFLASH_AT_BUF2_COMPARE 0x0261
+#define SFLASH_AT_BUF1_REPROGRAM 0x0258
+#define SFLASH_AT_BUF2_REPROGRAM 0x0259
+
+#ifndef MIN
+#define MIN(a, b) (((a) < (b))?(a):(b))
+#endif /* MIN */
+
+/*
+ * * Spin at most 'us' microseconds while 'exp' is true.
+ * * Caller should explicitly test 'exp' when this completes
+ * * and take appropriate error action if 'exp' is still true.
+ * */
+#define SPINWAIT(exp, us) { \
+ uint countdown = (us) + 9; \
+ while ((exp) && (countdown >= 10)) {\
+ osl_delay(10); \
+ countdown -= 10; \
+ } \
+}
+
+#endif
+/* Write len bytes starting at offset into buf. Returns number of bytes
+ * written. Caller should poll for completion.
+ */
+#define ST_RETRIES 3
+
+#define GET_BYTE(ptr) (*(u8 *)((u32)(ptr) ^ 7))
+
+void
+osl_delay(uint usec)
+{
+ uint d;
+
+ while (usec > 0) {
+ d = MIN(usec, 1000);
+ udelay(d);
+ usec -= d;
+ }
+}
+
+
+int sflash_write(u32 offset, u32 length, const unsigned char *buffer)
+{
+ struct sflash *sfl;
+ u32 off = offset, len = length;
+ const u8 *buf = buffer;
+ u8 data;
+ int ret = 0, ntry = 0;
+ bool is4712b0;
+ u32 page, byte, mask;
+ void *regs;
+
+ if (!len)
+ return 0;
+
+ sfl = &wnr3500l_sflash;
+ if ((off + len) > sfl->size)
+ return -22;
+
+ switch (sfl->type) {
+ case SFLASH_ST:
+ //is4712b0 = (ssb_bcm47xx.chipco.dev->id.chip_id ==
BCM4712_CHIP_ID) && (ssb_bcm47xx.chipco.dev->id.revision == 3);
+ is4712b0 = (ssb_bcm47xx.chip_id == BCM4712_CHIP_ID) &&
(ssb_bcm47xx.chipco.dev->id.revision == 3);
+ /* Enable writes */
+retry: sflash_cmd(SFLASH_ST_WREN);
+ off = offset;
+ len = length;
+ buf = buffer;
+ ntry++;
+ if (is4712b0) {
+ mask = 1 << 14;
+ regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr +
0x44, SSB_CORE_SIZE);
+ writel(off, regs);
+ iounmap(regs);
+ data = GET_BYTE(buf);
+ buf++;
+ //W_REG(osh, &cc->flashdata, data);
+ regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr +
0x48, SSB_CORE_SIZE);
+ writel(data, regs);
+ iounmap(regs);
+ /* Set chip select */
+ //OR_REG(osh, &cc->gpioout, mask);
+ regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr +
0x64, SSB_CORE_SIZE);
+ writel((mask | readl(regs)), regs);
+ iounmap(regs);
+ /* Issue a page program with the first byte */
+ sflash_cmd(SFLASH_ST_PP);
+ ret = 1;
+ off++;
+ len--;
+ while (len > 0) {
+ if ((off & 255) == 0) {
+ /* Page boundary, drop cs and return */
+ //AND_REG(osh, &cc->gpioout, ~mask);
+ regs =
ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 0x64, SSB_CORE_SIZE);
+ writel((~mask & readl(regs)), regs);
+ iounmap(regs);
+ osl_delay(1);
+ if (!sflash_poll(off)) {
+ /* Flash rejected command */
+ if (ntry <= ST_RETRIES)
+ goto retry;
+ else
+ return -11;
+ }
+ return ret;
+ } else {
+ /* Write single byte */
+ data = GET_BYTE(buf);
+ buf++;
+ sflash_cmd(data);
+ }
+ ret++;
+ off++;
+ len--;
+ }
+ /* All done, drop cs */
+ //AND_REG(osh, &cc->gpioout, ~mask);
+ regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr +
0x64, SSB_CORE_SIZE);
+ writel((~mask & readl(regs)), regs);
+ iounmap(regs);
+ osl_delay(1);
+ if (!sflash_poll(off)) {
+ /* Flash rejected command */
+ if (ntry <= ST_RETRIES)
+ goto retry;
+ else
+ return -12;
+ }
+ } else if (ssb_bcm47xx.chipco.dev->id.revision >= 20) {
+ //W_REG(osh, &cc->flashaddress, off);
+ regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr +
0x44, SSB_CORE_SIZE);
+ writel(off, regs);
+ iounmap(regs);
+ data = GET_BYTE(buf);
+ buf++;
+ //W_REG(osh, &cc->flashdata, data);
+ regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr +
0x48, SSB_CORE_SIZE);
+ writel(data, regs);
+ iounmap(regs);
+ /* Issue a page program with CSA bit set */
+ sflash_cmd(SFLASH_ST_CSA | SFLASH_ST_PP);
+ ret = 1;
+ off++;
+ len--;
+ while (len > 0) {
+ if ((off & 255) == 0) {
+ /* Page boundary, poll droping cs and
return */
+ //W_REG(NULL, &cc->flashcontrol, 0);
+ regs =
ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 0x40, SSB_CORE_SIZE);
+ writel(0, regs);
+ iounmap(regs);
+ osl_delay(1);
+ if (sflash_poll(off) == 0) {
+ /* Flash rejected command */
+ //SFL_MSG(("sflash: pp
rejected, ntry: %d,"
+ // " off: %d/%d, len:
%d/%d, ret:"
+ // "%d\n", ntry, off,
offset, len,
+ // length, ret));
+ if (ntry <= ST_RETRIES)
+ goto retry;
+ else
+ return -11;
+ }
+ return ret;
+ } else {
+ /* Write single byte */
+ data = GET_BYTE(buf);
+ buf++;
+ sflash_cmd(SFLASH_ST_CSA | data);
+ }
+ ret++;
+ off++;
+ len--;
+ }
+ /* All done, drop cs & poll */
+ //W_REG(NULL, &cc->flashcontrol, 0);
+ regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr +
0x40, SSB_CORE_SIZE);
+ writel(0, regs);
+ iounmap(regs);
+ osl_delay(1);
+ if (sflash_poll(off) == 0) {
+ /* Flash rejected command */
+ //SFL_MSG(("sflash: pp rejected, ntry: %d, off:
%d/%d,"
+ // " len: %d/%d, ret: %d\n",
+ // ntry, off, offset, len, length,
ret));
+ if (ntry <= ST_RETRIES)
+ goto retry;
+ else
+ return -12;
+ }
+ } else {
+ ret = 1;
+ //W_REG(osh, &cc->flashaddress, off);
+ regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr +
0x44, SSB_CORE_SIZE);
+ writel(off, regs);
+ iounmap(regs);
+ data = GET_BYTE(buf);
+ buf++;
+ //W_REG(osh, &cc->flashdata, data);
+ regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr +
0x48, SSB_CORE_SIZE);
+ writel(data, regs);
+ iounmap(regs);
+ /* Page program */
+ sflash_cmd(SFLASH_ST_PP);
+ }
+ break;
+ case SFLASH_AT:
+ mask = sfl->blocksize - 1;
+ page = (off & ~mask) << 1;
+ byte = off & mask;
+ /* Read main memory page into buffer 1 */
+ if (byte || (len < sfl->blocksize)) {
+ regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr +
0x44, SSB_CORE_SIZE);
+ writel(page, regs);
+ iounmap(regs);
+ sflash_cmd(SFLASH_AT_BUF1_LOAD);
+ /* 250 us for AT45DB321B */
+ SPINWAIT(sflash_poll(off), 1000);
+ }
+ /* Write into buffer 1 */
+ for (ret = 0; (ret < (int)len) && (byte < sfl->blocksize);
ret++) {
+ regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr +
0x44, SSB_CORE_SIZE);
+ writel(byte++, regs);
+ iounmap(regs);
+ regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr +
0x48, SSB_CORE_SIZE);
+ writel(*buf++, regs);
+ iounmap(regs);
+ sflash_cmd(SFLASH_AT_BUF1_WRITE);
+ }
+ /* Write buffer 1 into main memory page */
+ regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 0x44,
SSB_CORE_SIZE);
+ writel(page, regs);
+ iounmap(regs);
+ sflash_cmd(SFLASH_AT_BUF1_PROGRAM);
+ break;
+ }
+
+ return ret;
+}
+
+/* Erase a region. Returns number of bytes scheduled for erasure.
+ * Caller should poll for completion.
+ */
+int
+//sflash_erase(sb_t *sbh, chipcregs_t *cc, uint offset)
+sflash_erase(uint offset)
+{
+ struct sflash *sfl;
+ //osl_t *osh;
+ void *regs;
+ //ASSERT(sbh);
+
+ //osh = sb_osh(sbh);
+
+ sfl = &sflash;
+ if (offset >= sfl->size)
+ return -22;
+
+ switch (sfl->type) {
+ case SFLASH_ST:
+ sflash_cmd(SFLASH_ST_WREN);
+ //W_REG(osh, &cc->flashaddress, offset);
+ regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 0x44,
SSB_CORE_SIZE);
+ writel(offset, regs);
+ iounmap(regs);
+ sflash_cmd(SFLASH_ST_SE);
+ return sfl->blocksize;
+ case SFLASH_AT:
+ //W_REG(osh, &cc->flashaddress, offset << 1);
+ regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 0x44,
SSB_CORE_SIZE);
+ writel(offset << 1, regs);
+ iounmap(regs);
+ sflash_cmd(SFLASH_AT_PAGE_ERASE);
+ return sfl->blocksize;
+ }
+
+ return 0;
+}
+
+/*
+ * writes the appropriate range of flash, a NULL buf simply erases
+ * the region of flash
+ */
+int
+//sflash_commit(sb_t *sbh, chipcregs_t *cc, uint offset, uint len, const uchar
*buf)
+sflash_commit(uint offset, uint len, const u8 *buf)
+{
+ struct sflash *sfl;
+ u8 *block = NULL, *cur_ptr, *blk_ptr;
+ uint blocksize = 0, mask, cur_offset, cur_length, cur_retlen, remainder;
+ uint blk_offset, blk_len, copied;
+ int bytes, ret = 0;
+ //osl_t *osh;
+
+ //ASSERT(sbh);
+
+ //osh = sb_osh(sbh);
+
+ /* Check address range */
+ if (len <= 0)
+ return 0;
+
+ sfl = &sflash;
+ if ((offset + len) > sfl->size)
+ return -1;
+
+ blocksize = sfl->blocksize;
+ mask = blocksize - 1;
+
+ /* Allocate a block of mem */
+ //if (!(block = MALLOC(osh, blocksize)))
+ if (!(block = kmalloc(blocksize, GFP_ATOMIC)))
+ return -1;
+
+ while (len) {
+ /* Align offset */
+ cur_offset = offset & ~mask;
+ cur_length = blocksize;
+ cur_ptr = block;
+
+ remainder = blocksize - (offset & mask);
+ if (len < remainder)
+ cur_retlen = len;
+ else
+ cur_retlen = remainder;
+
+ /* buf == NULL means erase only */
+ if (buf) {
+ /* Copy existing data into holding block if necessary */
+ if ((offset & mask) || (len < blocksize)) {
+ blk_offset = cur_offset;
+ blk_len = cur_length;
+ blk_ptr = cur_ptr;
+
+ /* Copy entire block */
+ while (blk_len) {
+ //copied = sflash_read(sbh, cc,
blk_offset, blk_len, blk_ptr);
+ copied = sflash_read(blk_offset,
blk_len, blk_ptr);
+ blk_offset += copied;
+ blk_len -= copied;
+ blk_ptr += copied;
+ }
+ }
+
+ /* Copy input data into holding block */
+ memcpy(cur_ptr + (offset & mask), buf, cur_retlen);
+ }
+
+ /* Erase block */
+ //if ((ret = sflash_erase(sbh, cc, (uint) cur_offset)) < 0)
+ if ((ret = sflash_erase((uint) cur_offset)) < 0)
+ goto done;
+ //while (sflash_poll(sbh, cc, (uint) cur_offset));
+ while (sflash_poll((uint) cur_offset));
+
+ /* buf == NULL means erase only */
+ if (!buf) {
+ offset += cur_retlen;
+ len -= cur_retlen;
+ continue;
+ }
+
+ /* Write holding block */
+ while (cur_length > 0) {
+ if ((bytes = sflash_write((uint) cur_offset,
+ (uint) cur_length,
+ (u8 *) cur_ptr)) < 0) {
+ ret = bytes;
+ goto done;
+ }
+ //while (sflash_poll(sbh, cc, (uint) cur_offset));
+ while (sflash_poll((uint) cur_offset));
+ cur_offset += bytes;
+ cur_length -= bytes;
+ cur_ptr += bytes;
+ }
+
+ offset += cur_retlen;
+ len -= cur_retlen;
+ buf += cur_retlen;
+ }
+
+ ret = len;
+done:
+ if (block)
+ //MFREE(osh, block, blocksize);
+ kfree(block);
+ return ret;
+}
+#endif
+
+static int
+sflash_mtd_poll(struct sflash_mtd *sflash, unsigned int offset, int timeout)
+{
+ int now = jiffies;
+ int ret = 0;
+
+ for (;;) {
+ if (!sflash_poll(offset)) {
+ ret = 0;
+ break;
+ }
+ if (time_after((unsigned long)jiffies, (unsigned long)(now +
timeout))) {
+ printk(KERN_ERR "sflash: timeout\n");
+ ret = -ETIMEDOUT;
+ break;
+ }
+ udelay(1);
+ }
+
+ return ret;
+}
+
+static int
+sflash_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
u_char *buf)
+{
+ struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv;
+ int bytes, ret = 0;
+
+ if (retlen)
+ *retlen = 0;
+
+ /* Check address range */
+ if (!len)
+ return 0;
+ if ((from + len) > mtd->size)
+ return -EINVAL;
+
+ down(&sflash->lock);
+
+ while (len) {
+ if ((bytes = sflash_read((u32) from, len, buf)) < 0) {
+ ret = bytes;
+ break;
+ }
+ from += (loff_t) bytes;
+ len -= bytes;
+ buf += bytes;
+ if (retlen)
+ *retlen += bytes;
+ }
+
+ up(&sflash->lock);
+
+ return ret;
+}
+
+static int
+sflash_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
const u_char *buf)
+{
+ struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv;
+ int bytes, ret = 0;
+
+ if (retlen)
+ *retlen = 0;
+
+ /* Check address range */
+ if (!len)
+ return 0;
+ if ((to + len) > mtd->size)
+ return -EINVAL;
+
+ down(&sflash->lock);
+
+ while (len) {
+ if ((bytes = sflash_write((u32) to, len, buf)) < 0) {
+ ret = bytes;
+ break;
+ }
+ if ((ret = sflash_mtd_poll(sflash, (unsigned int) to, HZ / 10)))
+ break;
+ to += (loff_t) bytes;
+ len -= bytes;
+ buf += bytes;
+ if (retlen)
+ *retlen += bytes;
+ }
+
+ up(&sflash->lock);
+
+ return ret;
+}
+
+static int
+sflash_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
+{
+ struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv;
+ int i, j, ret = 0;
+ unsigned int addr, len;
+
+ /* Check address range */
+ if (!erase->len)
+ return 0;
+ if ((erase->addr + erase->len) > mtd->size)
+ return -EINVAL;
+
+ addr = erase->addr;
+ len = erase->len;
+
+ down(&sflash->lock);
+
+ /* Ensure that requested region is aligned */
+ for (i = 0; i < mtd->numeraseregions; i++) {
+ for (j = 0; j < mtd->eraseregions[i].numblocks; j++) {
+ if (addr == mtd->eraseregions[i].offset +
mtd->eraseregions[i].erasesize * j && len >= mtd->eraseregions[i].erasesize) {
+#if 1 /* Tatha */
+ //if ((ret = sflash_erase(sflash->sbh,
sflash->cc, addr)) < 0)
+ if ((ret = sflash_erase(addr)) < 0)
+ break;
+#endif
+ if ((ret = sflash_mtd_poll(sflash, addr, 10 *
HZ)))
+ break;
+ addr += mtd->eraseregions[i].erasesize;
+ len -= mtd->eraseregions[i].erasesize;
+ }
+ }
+ if (ret)
+ break;
+ }
+
+ up(&sflash->lock);
+
+ /* Set erase status */
+ if (ret)
+ erase->state = MTD_ERASE_FAILED;
+ else
+ erase->state = MTD_ERASE_DONE;
+
+ /* Call erase callback */
+ if (erase->callback)
+ erase->callback(erase);
+
+ return ret;
+}
+
+u32 sflash_init(void)
+{
+ u32 id, id2;
+ u32 *regs;
+
+ memset(&wnr3500l_sflash, 0, sizeof(wnr3500l_sflash));
+
+ wnr3500l_sflash.type = ssb_bcm47xx.chipco.capabilities &
CC_CAP_FLASH_MASK;
+
+ switch (wnr3500l_sflash.type) {
+ case SFLASH_ST:
+ /* Probe for ST chips */
+ sflash_cmd(SFLASH_ST_DP);
+ sflash_cmd(SFLASH_ST_RES);
+ regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 0x48,
SSB_CORE_SIZE);
+ id = readl(regs);
+ iounmap(regs);
+ switch (id) {
+ case 0x11:
+ /* ST M25P20 2 Mbit Serial Flash */
+ wnr3500l_sflash.blocksize = 64 * 1024;
+ wnr3500l_sflash.numblocks = 4;
+ break;
+ case 0x12:
+ /* ST M25P40 4 Mbit Serial Flash */
+ wnr3500l_sflash.blocksize = 64 * 1024;
+ wnr3500l_sflash.numblocks = 8;
+ break;
+ case 0x13:
+ /* ST M25P80 8 Mbit Serial Flash */
+ wnr3500l_sflash.blocksize = 64 * 1024;
+ wnr3500l_sflash.numblocks = 16;
+ break;
+ case 0x14:
+ /* ST M25P16 16 Mbit Serial Flash */
+ wnr3500l_sflash.blocksize = 64 * 1024;
+ wnr3500l_sflash.numblocks = 32;
+ break;
+ case 0x15:
+ /* ST M25P32 32 Mbit Serial Flash */
+ wnr3500l_sflash.blocksize = 64 * 1024;
+ wnr3500l_sflash.numblocks = 64;
+ break;
+ case 0x16:
+ /* ST M25P64 64 Mbit Serial Flash */
+ wnr3500l_sflash.blocksize = 64 * 1024;
+ wnr3500l_sflash.numblocks = 128;
+ break;
+ case 0xbf:
+ regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr +
0x44, SSB_CORE_SIZE);
+ writel(1, regs);
+ iounmap(regs);
+ sflash_cmd(SFLASH_ST_RES);
+ regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr +
0x48, SSB_CORE_SIZE);
+ id2 = readl(regs);
+ iounmap(regs);
+ if (id2 == 0x44) {
+ /* SST M25VF80 4 Mbit Serial Flash */
+ wnr3500l_sflash.blocksize = 64 * 1024;
+ wnr3500l_sflash.numblocks = 8;
+ }
+ break;
+ }
+ break;
+
+ case SFLASH_AT:
+ /* Probe for Atmel chips */
+ sflash_cmd(SFLASH_AT_STATUS);
+ regs = ioremap(ssb_bcm47xx.chipco.dev->dev_baseaddr + 0x48,
SSB_CORE_SIZE);
+ id = readl(regs) & 0x3C;
+ iounmap(regs);
+ switch (id) {
+ case 0xc:
+ /* Atmel AT45DB011 1Mbit Serial Flash */
+ wnr3500l_sflash.blocksize = 256;
+ wnr3500l_sflash.numblocks = 512;
+ break;
+ case 0x14:
+ /* Atmel AT45DB021 2Mbit Serial Flash */
+ wnr3500l_sflash.blocksize = 256;
+ wnr3500l_sflash.numblocks = 1024;
+ break;
+ case 0x1c:
+ /* Atmel AT45DB041 4Mbit Serial Flash */
+ wnr3500l_sflash.blocksize = 256;
+ wnr3500l_sflash.numblocks = 2048;
+ break;
+ case 0x24:
+ /* Atmel AT45DB081 8Mbit Serial Flash */
+ wnr3500l_sflash.blocksize = 256;
+ wnr3500l_sflash.numblocks = 4096;
+ break;
+ case 0x2c:
+ /* Atmel AT45DB161 16Mbit Serial Flash */
+ wnr3500l_sflash.blocksize = 512;
+ wnr3500l_sflash.numblocks = 4096;
+ break;
+ case 0x34:
+ /* Atmel AT45DB321 32Mbit Serial Flash */
+ wnr3500l_sflash.blocksize = 512;
+ wnr3500l_sflash.numblocks = 8192;
+ break;
+ case 0x3c:
+ /* Atmel AT45DB642 64Mbit Serial Flash */
+ wnr3500l_sflash.blocksize = 1024;
+ wnr3500l_sflash.numblocks = 8192;
+ break;
+ }
+ break;
+ }
+
+ wnr3500l_sflash.size = wnr3500l_sflash.blocksize *
wnr3500l_sflash.numblocks;
+ return wnr3500l_sflash.size;
+}
+
+int __init sflash_mtd_init(void)
+{
+ int ret = 0;
+ u32 i;
+#ifdef CONFIG_MTD_PARTITIONS
+ struct mtd_partition *parts;
+#endif
+
+ memset(&sflash, 0, sizeof(struct sflash_mtd));
+ init_MUTEX(&sflash.lock);
+
+ sflash.base_regs = ioremap(SSB_ENUM_BASE, SSB_CORE_SIZE);
+ if (sflash.base_regs == NULL) {
+ printk(KERN_ERR "sflash: error mapping registers\n");
+ ret = -EIO;
+ goto fail;
+ }
+
+ /* Initialize serial flash access */
+ if (0 == sflash_init()) {
+ printk(KERN_ERR "sflash: found no supported devices\n");
+ ret = -ENODEV;
+ goto fail;
+ }
+
+ /* Setup region info */
+ sflash.region.offset = 0;
+ sflash.region.erasesize = wnr3500l_sflash.blocksize;
+ sflash.region.numblocks = wnr3500l_sflash.numblocks;
+ if (sflash.region.erasesize > sflash.mtd.erasesize)
+ sflash.mtd.erasesize = sflash.region.erasesize;
+ sflash.mtd.size = wnr3500l_sflash.size;
+ sflash.mtd.numeraseregions = 1;
+
+ /* Register with MTD */
+ sflash.mtd.name = "sflash";
+ sflash.mtd.type = MTD_NORFLASH;
+ sflash.mtd.flags = MTD_CAP_NORFLASH;
+ sflash.mtd.eraseregions = &sflash.region;
+ sflash.mtd.erase = sflash_mtd_erase;
+ sflash.mtd.read = sflash_mtd_read;
+ sflash.mtd.write = sflash_mtd_write;
+ sflash.mtd.writesize = 1;
+ sflash.mtd.priv = &sflash;
+ sflash.mtd.owner = THIS_MODULE;
+
+#ifdef CONFIG_MTD_PARTITIONS
+ parts = init_mtd_partitions(&sflash.mtd, sflash.mtd.size);
+ for (i = 0; parts[i].name; i++);
+ ret = add_mtd_partitions(&sflash.mtd, parts, i);
+#else
+ ret = add_mtd_device(&sflash.mtd);
+#endif
+ if (ret) {
+ printk(KERN_ERR "sflash: add_mtd failed\n");
+ goto fail;
+ }
+
+ return 0;
+
+ fail:
+ if (sflash.base_regs)
+ iounmap((void *) sflash.base_regs);
+ return ret;
+}
+
+void __exit sflash_mtd_exit(void)
+{
+#ifdef CONFIG_MTD_PARTITIONS
+ del_mtd_partitions(&sflash.mtd);
+#else
+ del_mtd_device(&sflash.mtd);
+#endif
+ iounmap((void *) sflash.base_regs);
+}
+
+module_init(sflash_mtd_init);
+module_exit(sflash_mtd_exit);
diff -Naur a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c
--- a/drivers/ssb/driver_chipcommon.c 2010-05-13 18:23:29.000000000 +0530
+++ b/drivers/ssb/driver_chipcommon.c 2010-05-13 18:21:04.000000000 +0530
@@ -258,8 +258,10 @@
void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc,
u32 *plltype, u32 *n, u32 *m)
{
+#ifndef CONFIG_WNR3500L
if ((chipco_read32(cc, SSB_CHIPCO_CHIPID) & SSB_CHIPCO_IDMASK) ==
0x5354)
return;
+#endif
*n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N);
*plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
switch (*plltype) {
@@ -283,8 +285,10 @@
void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc,
u32 *plltype, u32 *n, u32 *m)
{
+#ifndef CONFIG_WNR3500L
if ((chipco_read32(cc, SSB_CHIPCO_CHIPID) & SSB_CHIPCO_IDMASK) ==
0x5354)
return;
+#endif
*n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N);
*plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
switch (*plltype) {
@@ -407,6 +411,7 @@
chipco_read32(cc,
SSB_CHIPCO_CLOCK_M2));
div = 1;
} else {
+#ifndef CONFIG_WNR3500L
if (ccrev == 20) {
/* BCM5354 uses constant 25MHz clock */
baud_base = 25000000;
@@ -439,7 +444,18 @@
chipco_read32(cc,
SSB_CHIPCO_CORECTL)
| SSB_CHIPCO_CORECTL_UARTCLKEN);
}
- } else if (ccrev >= 3) {
+ }
+#else
+ if ((ccrev >= 11) && (ccrev != 15)) {
+ baud_base = 20000000;
+ div = 1;
+ if (ccrev >= 21) {
+ /* Re-enable the UART clock. */
+ chipco_write32(cc, SSB_CHIPCO_CORECTL,
chipco_read32(cc, SSB_CHIPCO_CORECTL) | SSB_CHIPCO_CORECTL_UARTCLKEN);
+ }
+ }
+#endif
+ else if (ccrev >= 3) {
/* Internal backplane clock */
baud_base = ssb_clockspeed(bus);
div = chipco_read32(cc, SSB_CHIPCO_CLKDIV)
diff -Naur a/drivers/ssb/driver_chipcommon_pmu.c
b/drivers/ssb/driver_chipcommon_pmu.c
--- a/drivers/ssb/driver_chipcommon_pmu.c 2010-05-13 18:23:29.000000000
+0530
+++ b/drivers/ssb/driver_chipcommon_pmu.c 2010-05-13 18:21:04.000000000
+0530
@@ -508,7 +508,7 @@
ssb_dprintk(KERN_DEBUG PFX "Found rev %u PMU (capabilities 0x%08X)\n",
cc->pmu.rev, pmucap);
-
+#ifndef CONFIG_WNR3500L
if (cc->pmu.rev >= 1) {
if ((bus->chip_id == 0x4325) && (bus->chip_rev < 2)) {
chipco_mask32(cc, SSB_CHIPCO_PMU_CTL,
@@ -518,6 +518,13 @@
SSB_CHIPCO_PMU_CTL_NOILPONW);
}
}
+#else
+ 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);
+ }
+#endif
ssb_pmu_pll_init(cc);
ssb_pmu_resources_init(cc);
}
diff -Naur a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c
--- a/drivers/ssb/driver_mipscore.c 2010-05-13 18:23:29.000000000 +0530
+++ b/drivers/ssb/driver_mipscore.c 2010-05-14 12:02:40.000000000 +0530
@@ -49,12 +49,20 @@
static inline u32 ssb_irqflag(struct ssb_device *dev)
{
+#ifdef CONFIG_WNR3500L
+ if (dev->bus->is_ai_bus) {
+ return (ssb_ai_read32(dev, SSB_AI_oobselouta30) & 0x1f);
+ } else {
+#endif
u32 tpsflag = ssb_read32(dev, SSB_TPSFLAG);
if (tpsflag)
return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG;
else
/* not irq supported */
return 0x3f;
+#ifdef CONFIG_WNR3500L
+ }
+#endif
}
static struct ssb_device *find_device(struct ssb_device *rdev, int irqflag)
@@ -85,6 +93,16 @@
unsigned int irq;
irqflag = ssb_irqflag(dev);
+#ifdef CONFIG_WNR3500L
+ if (mdev->id.coreid == SSB_DEV_MIPS_74K) {
+ for (irq = 1; irq <= 4; irq++) {
+ if (ssb_read32(mdev, SSB_MIPS74K_INT_CONTROL(irq)) & (1
<< irqflag))
+ break;
+ }
+ if (irq == 5)
+ irq = 0;
+ } else {
+#endif
if (irqflag == 0x3f)
return 6;
ipsflag = ssb_read32(bus->mipscore.dev, SSB_IPSFLAG);
@@ -97,15 +115,32 @@
if ((1 << irqflag) & ssb_read32(mdev, SSB_INTVEC))
irq = 0;
}
+#ifdef CONFIG_WNR3500L
+ }
+#endif
return irq;
}
+#ifndef CONFIG_WNR3500L
static void clear_irq(struct ssb_bus *bus, unsigned int irq)
+#else
+static void clear_irq(struct ssb_bus *bus, unsigned int irq, u32 irqflag)
+#endif
{
struct ssb_device *dev = bus->mipscore.dev;
/* Clear the IRQ in the MIPScore backplane registers */
+#ifdef CONFIG_WNR3500L
+ if (dev->id.coreid == SSB_DEV_MIPS_74K) {
+ if (irq == 5)
+ return;
+ if (irq == 0)
+ ssb_write32(dev, SSB_MIPS74K_INT_CONTROL(0),
ssb_read32(dev, SSB_MIPS74K_INT_CONTROL(0)) & ~(1 << irqflag));
+ else
+ ssb_write32(dev, SSB_MIPS74K_INT_CONTROL(irq), 0);
+ } else {
+#endif
if (irq == 0) {
ssb_write32(dev, SSB_INTVEC, 0);
} else {
@@ -113,6 +148,9 @@
ssb_read32(dev, SSB_IPSFLAG) |
ipsflag_irq_mask[irq]);
}
+#ifdef CONFIG_WNR3500L
+ }
+#endif
}
static void set_irq(struct ssb_device *dev, unsigned int irq)
@@ -126,11 +164,38 @@
dev->irq = irq + 2;
+#ifndef CONFIG_WNR3500L
/* clear the old irq */
if (oldirq == 0)
ssb_write32(mdev, SSB_INTVEC, (~(1 << irqflag) &
ssb_read32(mdev, SSB_INTVEC)));
else if (oldirq != 5)
clear_irq(bus, oldirq);
+#else
+ if (irq == oldirq)
+ return;
+
+ clear_irq(bus, irq, irqflag);
+
+ /* make sure, the new irq is unused */
+ if (irq != 0) {
+ int i;
+ for (i = 0; i < bus->nr_devices; i++) {
+ struct ssb_device *olddev = &(bus->devices[i]);
+ if (ssb_mips_irq(olddev) == irq) {
+ set_irq(olddev, 0);
+ break;
+ }
+ }
+ }
+
+ /* set new irq */
+ if (mdev->id.coreid == SSB_DEV_MIPS_74K) {
+ if (irq == 0)
+ ssb_write32(mdev, SSB_MIPS74K_INT_CONTROL(0),
ssb_read32(mdev,SSB_MIPS74K_INT_CONTROL(0)) | 1 << irqflag);
+ else
+ ssb_write32(mdev, SSB_MIPS74K_INT_CONTROL(irq), 1 <<
irqflag);
+ } else {
+#endif
/* assign the new one */
if (irq == 0) {
@@ -147,6 +212,9 @@
irqflag |= (ipsflag & ~ipsflag_irq_mask[irq]);
ssb_write32(mdev, SSB_IPSFLAG, irqflag);
}
+#ifdef CONFIG_WNR3500L
+ }
+#endif
ssb_dprintk(KERN_INFO PFX
"set_irq: core 0x%04x, irq %d => %d\n",
dev->id.coreid, oldirq+2, irq+2);
@@ -208,6 +276,19 @@
struct ssb_bus *bus = mcore->dev->bus;
u32 pll_type, n, m, rate = 0;
+#ifdef CONFIG_WNR3500L
+ switch (bus->chip_id) {
+ case 0x5365:
+ return 200000000;
+ case 0x5354:
+ return 240000000;
+ case 0x4716:
+ rate = ai_pmu_clock_rate(SSB_ENUM_BASE,
SSB_PMU4716_MAINPLL_PLL0, SSB_PMU5_MAINPLL_SI);
+ printk("rate: %d\n", rate);
+ return rate;
+ }
+#endif
+
if (bus->extif.dev) {
ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m);
} else if (bus->chipco.dev) {
@@ -254,7 +335,17 @@
ssb_chipco_timing_init(&bus->chipco, ns);
/* Assign IRQs to all cores on the bus, start with irq line 2, because
serial usually takes 1 */
- for (irq = 2, i = 0; i < bus->nr_devices; i++) {
+#ifndef CONFIG_WNR3500L
+ for (irq = 2, i = 0; i < bus->nr_devices; i++)
+#else
+ if (bus->chip_id == 0x4716)
+ irq = 1;
+ else
+ irq = 2;
+
+ for (i = 0; i < bus->nr_devices; i++)
+#endif
+ {
int mips_irq;
dev = &(bus->devices[i]);
mips_irq = ssb_mips_irq(dev);
@@ -277,6 +368,9 @@
case SSB_DEV_ETHERNET_GBIT:
case SSB_DEV_80211:
case SSB_DEV_USB20_HOST:
+#ifdef CONFIG_WNR3500L
+ case SSB_DEV_ETHERNET_GBIT2:
+#endif
/* These devices get their own IRQ line if available,
the rest goes on IRQ0 */
if (irq <= 4) {
set_irq(dev, irq++);
diff -Naur a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c
--- a/drivers/ssb/driver_pcicore.c 2010-05-13 18:23:29.000000000 +0530
+++ b/drivers/ssb/driver_pcicore.c 2010-05-13 18:21:04.000000000 +0530
@@ -412,6 +412,10 @@
{
/* Disable PCI interrupts. */
ssb_write32(pc->dev, SSB_INTVEC, 0);
+
+#ifdef CONFIG_WNR3500L
+ ssb_device_disable(pc->dev, 0);
+#endif
}
void ssb_pcicore_init(struct ssb_pcicore *pc)
@@ -427,6 +431,12 @@
#ifdef CONFIG_SSB_PCICORE_HOSTMODE
pc->hostmode = pcicore_is_in_hostmode(pc);
+#ifdef CONFIG_WNR3500L
+ if (pc->hostmode && pc->dev->id.coreid == SSB_DEV_PCIE) {
+ printk(KERN_WARNING "Disabling SSB PCI-E host due to code
brokeness\n");
+ pc->hostmode = 0;
+ }
+#endif
if (pc->hostmode)
ssb_pcicore_init_hostmode(pc);
#endif /* CONFIG_SSB_PCICORE_HOSTMODE */
diff -Naur a/drivers/ssb/main.c b/drivers/ssb/main.c
--- a/drivers/ssb/main.c 2010-05-13 18:23:29.000000000 +0530
+++ b/drivers/ssb/main.c 2010-05-13 18:21:04.000000000 +0530
@@ -570,7 +570,10 @@
err = ssb_bus_powerup(bus, 0);
if (err)
goto error;
+ printk("[%s:%s:%d] TODO: Need to initialize pci core\n",
__FILE__, __func__, __LINE__);
+#ifndef CONFIG_WNR3500L
ssb_pcicore_init(&bus->pcicore);
+#endif
ssb_bus_may_powerdown(bus);
err = ssb_devices_register(bus);
@@ -746,6 +749,24 @@
#endif
};
+#ifdef CONFIG_WNR3500L
+void ssb_ai_write32(struct ssb_device *dev, u16 offset, u32 value)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ return writel(value, bus->ai_mmio + offset);
+}
+
+u32 ssb_ai_read32(struct ssb_device *dev, u16 offset)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ return readl(bus->ai_mmio + offset);
+}
+#endif
+
static int ssb_fetch_invariants(struct ssb_bus *bus,
ssb_invariants_func_t get_invariants)
{
@@ -1077,6 +1098,42 @@
return 0;
}
+#ifdef CONFIG_WNR3500L
+u32 ai_pmu_clock_rate(u32 baseaddr, u32 pll0, u32 m)
+{
+ u32 tmp, div, ndiv, p1, p2, fc, *tmp_mmio, rate;
+ u32 pllcontrol_addr = 0x660/sizeof(u32), pllcontrol_data =
0x664/sizeof(u32);
+
+ tmp_mmio = ioremap(baseaddr, SSB_CORE_SIZE);
+ writel(pll0 + SSB_PMU5_PLL_P1P2_OFF, tmp_mmio + pllcontrol_addr);
+ (void)readl(tmp_mmio + pllcontrol_addr);
+ tmp = readl(tmp_mmio + pllcontrol_data);
+ p1 = (tmp & SSB_PMU5_PLL_P1_MASK) >> SSB_PMU5_PLL_P1_SHIFT;
+ p2 = (tmp & SSB_PMU5_PLL_P2_MASK) >> SSB_PMU5_PLL_P2_SHIFT;
+
+ writel(pll0 + SSB_PMU5_PLL_M14_OFF, tmp_mmio + pllcontrol_addr);
+ (void)readl(tmp_mmio + pllcontrol_addr);
+ tmp = readl(tmp_mmio + pllcontrol_data);
+ div = (tmp >> ((m - 1) * SSB_PMU5_PLL_MDIV_WIDTH)) &
SSB_PMU5_PLL_MDIV_MASK;
+
+ writel(pll0 + SSB_PMU5_PLL_NM5_OFF, tmp_mmio + pllcontrol_addr);
+ (void)readl(tmp_mmio + pllcontrol_addr);
+ tmp = readl(tmp_mmio + pllcontrol_data);
+ ndiv = (tmp & SSB_PMU5_PLL_NDIV_MASK) >> SSB_PMU5_PLL_NDIV_SHIFT;
+
+ iounmap(tmp_mmio);
+
+ /* Do calculation in Mhz */
+ fc = (20000 * 1000) / 1000000;
+ fc = (p1 * ndiv * fc) / p2;
+
+ /* Return clock in Hertz */
+ rate = (fc / div) * 1000000;
+
+ return rate;
+}
+#endif
+
/* Get the current speed the backplane is running at */
u32 ssb_clockspeed(struct ssb_bus *bus)
{
@@ -1084,6 +1141,19 @@
u32 plltype;
u32 clkctl_n, clkctl_m;
+#ifdef CONFIG_WNR3500L
+ switch (bus->chip_id) {
+ case 0x5365:
+ return 100000000;
+ case 0x5354:
+ return 120000000;
+ case 0x4716:
+ rate = ai_pmu_clock_rate(SSB_ENUM_BASE,
SSB_PMU4716_MAINPLL_PLL0, SSB_PMU5_MAINPLL_SI);
+ printk("rate: %d\n", rate);
+ return rate;
+}
+#endif
+
if (ssb_extif_available(&bus->extif))
ssb_extif_get_clockcontrol(&bus->extif, &plltype,
&clkctl_n, &clkctl_m);
@@ -1132,6 +1202,11 @@
int ssb_device_is_enabled(struct ssb_device *dev)
{
+#ifdef CONFIG_WNR3500L
+ if (dev->bus->is_ai_bus) {
+ return (ssb_ai_read32(dev, SSB_AI_RESETCTRL) &
SSB_AI_RESETCTRL_RESET) == 0;
+ } else {
+#endif
u32 val;
u32 reject;
@@ -1140,9 +1215,23 @@
val &= SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET | reject;
return (val == SSB_TMSLOW_CLOCK);
+#ifdef CONFIG_WNR3500L
+ }
+#endif
}
EXPORT_SYMBOL(ssb_device_is_enabled);
+#ifdef CONFIG_WNR3500L
+static void ssb_ai_ioctl_write(struct ssb_device *dev, u32 flags)
+{
+ u32 dummy;
+
+ ssb_ai_write32(dev, SSB_AI_IOCTRL, flags);
+ dummy = ssb_ai_read32(dev, SSB_AI_IOCTRL);
+ udelay(1);
+}
+#endif
+
static void ssb_flush_tmslow(struct ssb_device *dev)
{
/* Make _really_ sure the device has finished the TMSLOW
@@ -1160,6 +1249,15 @@
u32 val;
ssb_device_disable(dev, core_specific_flags);
+#ifdef CONFIG_WNR3500L
+ if (dev->bus->is_ai_bus) {
+ ssb_ai_ioctl_write(dev, core_specific_flags | SSB_CF_FGC |
SSB_CF_CLOCK_EN);
+ ssb_ai_write32(dev, SSB_AI_RESETCTRL, 0);
+ udelay(1);
+
+ ssb_ai_ioctl_write(dev, core_specific_flags | SSB_CF_CLOCK_EN);
+ } else {
+#endif
ssb_write32(dev, SSB_TMSLOW,
SSB_TMSLOW_RESET | SSB_TMSLOW_CLOCK |
SSB_TMSLOW_FGC | core_specific_flags);
@@ -1183,6 +1281,9 @@
ssb_write32(dev, SSB_TMSLOW, SSB_TMSLOW_CLOCK |
core_specific_flags);
ssb_flush_tmslow(dev);
+#ifdef CONFIG_WNR3500L
+ }
+#endif
}
EXPORT_SYMBOL(ssb_device_enable);
diff -Naur a/drivers/ssb/scan.c b/drivers/ssb/scan.c
--- a/drivers/ssb/scan.c 2010-05-13 18:23:29.000000000 +0530
+++ b/drivers/ssb/scan.c 2010-05-13 18:21:04.000000000 +0530
@@ -216,6 +216,10 @@
case SSB_BUSTYPE_SSB:
case SSB_BUSTYPE_PCMCIA:
iounmap(bus->mmio);
+#ifdef CONFIG_WNR3500L
+ if (bus->ai_mmio)
+ iounmap(bus->ai_mmio);
+#endif
break;
case SSB_BUSTYPE_PCI:
#ifdef CONFIG_SSB_PCIHOST
@@ -276,15 +280,75 @@
return 0;
}
+#ifdef CONFIG_WNR3500L
+static u32
+get_erom_ent(struct ssb_bus *bus, u32 **eromptr, u32 mask, u32 match)
+{
+ u32 ent;
+
+ while (1) {
+ ent = readl(*eromptr);
+ (*eromptr)++;
+
+ if (mask == 0)
+ break;
+
+ if ((ent & SSB_EROM_VALID) == 0)
+ continue;
+
+ if (ent == (SSB_EROM_END | SSB_EROM_VALID))
+ break;
+
+ if ((ent & mask) == match)
+ break;
+ }
+ return ent;
+}
+
+static u32
+get_adress_space_descriptor(struct ssb_bus *bus, u32 **eromptr, uint st, u32
*addrl, u32 *sizel)
+{
+ u32 asd, sz, szd, expect;
+
+ expect = SSB_EROM_ASD | st;
+ if (st == SSB_EROM_ASD_ST_SWRAP)
+ expect |= 1 << SSB_EROM_ASD_SP_SHIFT;
+
+ asd = get_erom_ent(bus, eromptr, SSB_EROM_ASD_SP_MASK | SSB_EROM_TAG |
SSB_EROM_ASD_ST_MASK, expect);
+
+ *addrl = asd & SSB_EROM_ASD_ADDR_MASK;
+
+ BUG_ON(asd & SSB_EROM_ASD_AG32);
+
+ sz = asd & SSB_EROM_ASD_SZ_MASK;
+ if (sz == SSB_EROM_ASD_SZ_SZD) {
+ szd = get_erom_ent(bus, eromptr, 0, 0);
+ *sizel = szd & SSB_EROM_ASD_SZ_MASK;
+ } else
+ *sizel = SSB_EROM_ASD_SZ_BASE << (sz >> SSB_EROM_ASD_SZ_SHIFT);
+
+ return asd;
+}
+#endif
+
int ssb_bus_scan(struct ssb_bus *bus,
unsigned long baseaddr)
{
int err = -ENOMEM;
void __iomem *mmio;
+#ifndef CONFIG_WNR3500L
u32 idhi, cc, rev, tmp;
+#else
+ u32 idhi, tmp;
+#endif
int dev_i, i;
struct ssb_device *dev;
int nr_80211_cores = 0;
+#ifdef CONFIG_WNR3500L
+ bool have_chipcommon = true;
+ u32 __iomem *eromptr = NULL;
+ u32 __iomem *eromend = (void *) -1;
+#endif
mmio = ssb_ioremap(bus, baseaddr);
if (!mmio)
@@ -295,13 +359,29 @@
if (err)
goto err_unmap;
+#ifndef CONFIG_WNR3500L
idhi = scan_read32(bus, 0, SSB_IDHIGH);
cc = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT;
rev = (idhi & SSB_IDHIGH_RCLO);
rev |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT;
+#else
+ if (bus->bustype != SSB_BUSTYPE_SSB) {
+ idhi = scan_read32(bus, 0, SSB_IDHIGH);
+ if (((idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT) !=
SSB_DEV_CHIPCOMMON)
+ have_chipcommon = false;
+ }
+#endif
bus->nr_devices = 0;
- if (cc == SSB_DEV_CHIPCOMMON) {
+#ifndef CONFIG_WNR3500L
+ if (cc == SSB_DEV_CHIPCOMMON)
+#else
+ /* this may break, if the first core isn't a chipcommon core,
+ * but we need to know, if this is an ai bus or not. It should
+ * only fail for older SDIOs (?) */
+ if (have_chipcommon)
+#endif
+ {
tmp = scan_read32(bus, 0, SSB_CHIPCO_CHIPID);
bus->chip_id = (tmp & SSB_CHIPCO_IDMASK);
@@ -309,7 +389,13 @@
SSB_CHIPCO_REVSHIFT;
bus->chip_package = (tmp & SSB_CHIPCO_PACKMASK) >>
SSB_CHIPCO_PACKSHIFT;
- if (rev >= 4) {
+#ifndef CONFIG_WNR3500L
+ if (rev >= 4)
+#else
+ bus->is_ai_bus = !!(tmp & SSB_CHIPCO_TYPE_MASK);
+ if (bus->chip_rev >= 4)
+#endif
+ {
bus->nr_devices = (tmp & SSB_CHIPCO_NRCORESMASK) >>
SSB_CHIPCO_NRCORESSHIFT;
}
@@ -339,7 +425,9 @@
/* Now that we know the number of cores,
* remap the whole IO space for all cores.
*/
+#ifndef CONFIG_WNR3500L
err = -ENOMEM;
+#endif
iounmap(mmio);
mmio = ioremap(baseaddr, SSB_CORE_SIZE * bus->nr_devices);
if (!mmio)
@@ -347,27 +435,119 @@
bus->mmio = mmio;
}
+#ifdef CONFIG_WNR3500L
+ if (bus->is_ai_bus) {
+ mmio = ioremap(SSB_AI_BASE, SSB_CORE_SIZE * bus->nr_devices);
+ if (!mmio)
+ goto err_unmap;
+ bus->ai_mmio = mmio;
+
+ eromptr = ioremap(scan_read32(bus, 0, SSB_CHIPCO_EROM),
SSB_CORE_SIZE);
+ if (!eromptr)
+ goto err_unmap;
+
+ eromend = eromptr + SSB_CORE_SIZE / sizeof(u32);
+ }
+
+ err = -EIO;
+#endif
+
/* Fetch basic information about each core/device */
- for (i = 0, dev_i = 0; i < bus->nr_devices; i++) {
+#ifndef CONFIG_WNR3500L
+ for (i = 0, dev_i = 0; i < bus->nr_devices; i++)
+#else
+ i = 0;
+ dev_i = 0;
+ while ((i < bus->nr_devices) && (eromptr < eromend))
+#endif
+ {
err = scan_switchcore(bus, i);
if (err)
goto err_unmap;
dev = &(bus->devices[dev_i]);
+#ifdef CONFIG_WNR3500L
+ if (bus->is_ai_bus) {
+ u32 cia, cib, asd, sizel, addrl, nmw;
+
+ cia = get_erom_ent(bus, &eromptr, SSB_EROM_TAG,
SSB_EROM_CI);
+ if (cia == (SSB_EROM_END | SSB_EROM_VALID)) {
+ ssb_dprintk(KERN_INFO PFX "Found END of erom
after %d cores\n", dev_i);
+ if (dev_i != bus->nr_devices) {
+ ssb_printk(KERN_WARNING PFX "Expected
%d cores but got %d\n", bus->nr_devices, dev_i);
+ }
+ break;
+ }
+ cib = get_erom_ent(bus, &eromptr, 0, 0);
+ if ((cib & SSB_EROM_TAG) != SSB_EROM_CI) {
+ ssb_printk(KERN_ERR PFX "CIA not followed by
CIB\n");
+ goto error;
+ }
+
+ dev->id.coreid = (cia & SSB_EROM_CIA_CID_MASK) >>
SSB_EROM_CIA_CID_SHIFT;
+ dev->id.vendor = (cia & SSB_EROM_CIA_MFG_MASK) >>
SSB_EROM_CIA_MFG_SHIFT;
+ dev->id.revision = (cib & SSB_EROM_CIB_REV_MASK) >>
SSB_EROM_CIB_REV_SHIFT;
+ dev->core_index = dev_i;
+
+ nmw = cib & SSB_EROM_CIB_NMW_MASK;
+ if (((dev->id.coreid == SSB_DEV_DEFAULT) &&
(dev->id.vendor == SSB_VENDOR_ARM)) ||
+ (nmw == 0 && (cib &
SSB_EROM_CIB_NSW_MASK) == 0) || ((cib & SSB_EROM_CIB_NSP_MASK) == 0)) {
+ continue;
+ }
+
+ /* see if it is a bridge */
+ if ((SSB_EROM_ASD_ST_MASK & get_erom_ent(bus, &eromptr,
SSB_EROM_TAG, SSB_EROM_ASD)) == SSB_EROM_ASD_ST_BRIDGE)
+ continue;/* don't record bridges */
+ else
+ eromptr--;
+ /* First Slave Address Descriptor should be port 0:
+ * the main register space for the core
+ */
+ asd = get_adress_space_descriptor(bus, &eromptr,
SSB_EROM_ASD_ST_SLAVE, &addrl, &sizel);
+ if (sizel != SSB_CORE_SIZE || addrl != SSB_ENUM_BASE +
SSB_CORE_SIZE * dev_i) {
+ ssb_printk(KERN_ERR PFX "Malformed or
unsupported register address space descriptor for core %d:\n"
+ "\texpected 0x%x, got 0x%x, size
0x%x\n", dev_i, SSB_ENUM_BASE + SSB_CORE_SIZE * dev_i, addrl, sizel);
+ goto error;
+ }
+ dev->dev_baseaddr = addrl;
+ dev->dev_baseaddr_size = sizel;
+
+ if (nmw)
+ asd = get_adress_space_descriptor(bus,
&eromptr, SSB_EROM_ASD_ST_MWRAP, &addrl, &sizel);
+ else
+ asd = get_adress_space_descriptor(bus,
&eromptr, SSB_EROM_ASD_ST_SWRAP, &addrl, &sizel);
+
+ if (sizel != SSB_CORE_SIZE || addrl != SSB_AI_BASE +
SSB_CORE_SIZE * dev_i) {
+ ssb_printk(KERN_ERR PFX "Malformed or
unsupported ai address space descriptor for core %d:\n"
+ "\texpected 0x%x, got 0x%x, size
0x%x\n", dev_i, SSB_AI_BASE + SSB_CORE_SIZE * dev_i, addrl, sizel);
+ goto error;
+ }
+ } else {
+#endif
idhi = scan_read32(bus, i, SSB_IDHIGH);
dev->id.coreid = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT;
dev->id.revision = (idhi & SSB_IDHIGH_RCLO);
dev->id.revision |= (idhi & SSB_IDHIGH_RCHI) >>
SSB_IDHIGH_RCHI_SHIFT;
dev->id.vendor = (idhi & SSB_IDHIGH_VC) >> SSB_IDHIGH_VC_SHIFT;
dev->core_index = i;
+ i++;
+#ifdef CONFIG_WNR3500L
+ }
+
dev->bus = bus;
dev->ops = bus->ops;
-
+ ssb_printk(KERN_INFO PFX
+ "Core %d found: %s "
+ "(cc 0x%03X, rev 0x%02X, vendor 0x%04X)\n",
+ dev->core_index, ssb_core_name(dev->id.coreid),
+ dev->id.coreid, dev->id.revision,
dev->id.vendor);
+#else
ssb_dprintk(KERN_INFO PFX
"Core %d found: %s "
"(cc 0x%03X, rev 0x%02X, vendor 0x%04X)\n",
i, ssb_core_name(dev->id.coreid),
dev->id.coreid, dev->id.revision, dev->id.vendor);
+#endif
switch (dev->id.coreid) {
case SSB_DEV_80211:
@@ -400,6 +580,9 @@
break;
case SSB_DEV_MIPS:
case SSB_DEV_MIPS_3302:
+#ifdef CONFIG_WNR3500L
+ case SSB_DEV_MIPS_74K:
+#endif
#ifdef CONFIG_SSB_DRIVER_MIPS
if (bus->mipscore.dev) {
ssb_printk(KERN_WARNING PFX
@@ -439,10 +622,23 @@
}
bus->nr_devices = dev_i;
+#ifdef CONFIG_WNR3500L
+ if (bus->is_ai_bus && eromptr >= eromend)
+ ssb_printk(KERN_ERR PFX "Reached end of erom without finding
END");
+#endif
+
err = 0;
out:
return err;
+#ifdef CONFIG_WNR3500L
+error:
+ bus->nr_devices = 0;
+#endif
err_unmap:
ssb_iounmap(bus);
+#ifndef CONFIG_WNR3500L
goto out;
+#else
+ return err;
+#endif
}
diff -Naur a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h
--- a/drivers/ssb/ssb_private.h 2010-05-13 18:23:29.000000000 +0530
+++ b/drivers/ssb/ssb_private.h 2010-05-13 18:21:04.000000000 +0530
@@ -29,6 +29,14 @@
# define SSB_BUG_ON(x) __ssb_do_nothing(unlikely(!!(x)))
#endif
+#ifdef CONFIG_WNR3500L
+u32 ai_pmu_clock_rate(u32 baseaddr, u32 pll0, u32 m);
+#define SSB_PMU5_MAINPLL_SBB 3
+#define SSB_PMU5_MAINPLL_CPU 1
+
+void ssb_ai_write32(struct ssb_device *dev, u16 offset, u32 value);
+u32 ssb_ai_read32(struct ssb_device *dev, u16 offset);
+#endif
/* pci.c */
#ifdef CONFIG_SSB_PCIHOST
diff -Naur a/include/linux/ssb/ssb_driver_chipcommon.h
b/include/linux/ssb/ssb_driver_chipcommon.h
--- a/include/linux/ssb/ssb_driver_chipcommon.h 2010-05-13 18:23:48.000000000
+0530
+++ b/include/linux/ssb/ssb_driver_chipcommon.h 2010-05-13 18:21:36.000000000
+0530
@@ -549,6 +549,34 @@
#define SSB_CHIPCO_OTP_SIGNATURE 0x578A
#define SSB_CHIPCO_OTP_MAGIC 0x4E56
+#ifdef CONFIG_WNR3500L
+#define SSB_CHIPCO_TYPE_MASK 0xf0000000
+#define SSB_CHIPCO_EROM 0xFC
+/* PMU rev 5 (& 6) */
+#define SSB_PMU5_PLL_P1P2_OFF 0
+#define SSB_PMU5_PLL_P1_MASK 0x0f000000
+#define SSB_PMU5_PLL_P1_SHIFT 24
+#define SSB_PMU5_PLL_P2_MASK 0x00f00000
+#define SSB_PMU5_PLL_P2_SHIFT 20
+#define SSB_PMU5_PLL_M14_OFF 1
+#define SSB_PMU5_PLL_MDIV_MASK 0x000000ff
+#define SSB_PMU5_PLL_MDIV_WIDTH 8
+#define SSB_PMU5_PLL_NM5_OFF 2
+#define SSB_PMU5_PLL_NDIV_MASK 0xfff00000
+#define SSB_PMU5_PLL_NDIV_SHIFT 20
+#define SSB_PMU5_PLL_FMAB_OFF 3
+#define SSB_PMU5_PLL_MRAT_MASK 0xf0000000
+#define SSB_PMU5_PLL_MRAT_SHIFT 28
+#define SSB_PMU5_PLL_ABRAT_MASK 0x08000000
+#define SSB_PMU5_PLL_ABRAT_SHIFT 27
+#define SSB_PMU5_PLL_FDIV_MASK 0x07ffffff
+#define SSB_PMU5_PLL_PLLCTL_OFF 4
+#define SSB_PMU5_PLL_PCHI_OFF 5
+#define SSB_PMU5_PLL_PCHI_MASK 0x0000003f
+#define SSB_PMU4716_MAINPLL_PLL0 12
+#define SSB_PMU5_MAINPLL_SI 3
+#endif
+
struct ssb_device;
struct ssb_serial_port;
diff -Naur a/include/linux/ssb/ssb_driver_mips.h
b/include/linux/ssb/ssb_driver_mips.h
--- a/include/linux/ssb/ssb_driver_mips.h 2010-05-13 18:23:48.000000000
+0530
+++ b/include/linux/ssb/ssb_driver_mips.h 2010-05-13 18:21:36.000000000
+0530
@@ -30,6 +30,9 @@
extern unsigned int ssb_mips_irq(struct ssb_device *dev);
+#ifdef CONFIG_WNR3500L
+#define SSB_MIPS74K_INT_CONTROL(int) (0x14 + (int)*4)
+#endif
#else /* CONFIG_SSB_DRIVER_MIPS */
diff -Naur a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
--- a/include/linux/ssb/ssb.h 2010-05-13 18:23:48.000000000 +0530
+++ b/include/linux/ssb/ssb.h 2010-05-13 18:21:36.000000000 +0530
@@ -185,6 +185,11 @@
/* Internal-only stuff follows. */
void *drvdata; /* Per-device data */
void *devtypedata; /* Per-devicetype (eg 802.11) data */
+#ifdef CONFIG_WNR3500L
+ u32 dev_baseaddr;
+ u32 dev_baseaddr_size;
+ u32 wrapba;
+#endif
};
/* Go from struct device to struct ssb_device. */
@@ -273,6 +278,9 @@
struct ssb_bus {
/* The MMIO area. */
void __iomem *mmio;
+#ifdef CONFIG_WNR3500L
+ void __iomem *ai_mmio;
+#endif
const struct ssb_bus_ops *ops;
@@ -288,6 +296,10 @@
* On PCMCIA-host busses this is used to protect the whole MMIO access.
*/
spinlock_t bar_lock;
+#ifdef CONFIG_WNR3500L
+ bool is_ai_bus;
+#endif
+
/* The bus this backplane is running on. */
enum ssb_bustype bustype;
/* Pointer to the PCI bus (only valid if bustype == SSB_BUSTYPE_PCI). */
_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel