Merge branch 'broadcom_drops' into HEAD
Merge broadcom_drops after the fact to simplify merging later releases
from Broadcom.
diff --git a/3.3/bmoca.c b/3.3/bmoca.c
index 0e55484..4d9a906 100644
--- a/3.3/bmoca.c
+++ b/3.3/bmoca.c
@@ -38,6 +38,8 @@
#include <linux/scatterlist.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/slab.h>
+#include <net/net_namespace.h>
#define DRV_VERSION 0x00040000
#define DRV_BUILD_NUMBER 0x20110831
@@ -46,6 +48,8 @@
#if defined(CONFIG_BRCMSTB)
#define MOCA6816 0
+#undef DSL_MOCA
+#undef CONFIG_BCM_6802_MoCA
#include <linux/bmoca.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
@@ -58,14 +62,14 @@
#define MOCA6816 1
#include "bmoca.h"
-#include <boardparms.h>
-#include <bcm3450.h>
+//#include <boardparms.h>
+//#include <bcm3450.h>
/* board.h cannot declare spinlock, so do it here */
extern spinlock_t bcm_gpio_spinlock;
#include <linux/netdevice.h>
#if defined(CONFIG_BCM_6802_MoCA)
-#include <board.h>
+//#include <board.h>
#endif
#else
@@ -565,6 +569,11 @@
#define I2C_RD(x) MOCA_RD(x)
#define I2C_WR(x, y) MOCA_WR(x, y)
+static int hw_specific_init(struct moca_priv_data *priv)
+{
+ return 0;
+}
+
static void moca_hw_reset(struct moca_priv_data *priv)
{
/* disable and clear all interrupts */
@@ -666,6 +675,8 @@
static void moca_enable_irq(struct moca_priv_data *priv)
{
+ if (!priv->enabled) return;
+
/* unmask everything */
u32 mask = M2H_REQ | M2H_RESP | M2H_ASSERT | M2H_WDT_CPU1 |
M2H_NEXTCHUNK | M2H_DMA;
@@ -1168,6 +1179,7 @@
}
}
if (data & 3) {
+ printk("ie=%08X\n", data);
msg = "IE is not a multiple of 4 bytes";
goto bad;
}
@@ -1563,10 +1575,17 @@
static irqreturn_t moca_interrupt(int irq, void *arg)
{
struct moca_priv_data *priv = arg;
+ struct moca_platform_data *pd;
+
+ if (!priv || !priv->enabled || !priv->pdev ||
+ !priv->pdev->dev.platform_data) {
+ printk("moca_interrupt: can't go yet.\n");
+ moca_disable_irq(priv);
+ return IRQ_HANDLED;
+ }
#if MOCA6816
- struct moca_platform_data *pd =
- (struct moca_platform_data *)priv->pdev->dev.platform_data;
+ pd = (struct moca_platform_data *)priv->pdev->dev.platform_data;
/*
* If the driver is for an external chip then the work function needs
@@ -1728,6 +1747,7 @@
/* verify chip ID */
data = moca_3450_read(priv, BCM3450_CHIP_ID);
+ pr_info("bcm3450 chip id is: %08x\n", data);
if (data != 0x3450)
printk(KERN_WARNING "%s: invalid 3450 chip ID 0x%08x\n",
__func__, data);
@@ -1823,8 +1843,10 @@
if (copy_from_user(&x, (void __user *)xfer_uaddr, sizeof(x)))
return -EFAULT;
+#if !DSL_MOCA
if (moca_range_ok(priv, x.moca_addr, x.len) < 0)
return -EINVAL;
+#endif
src = (uintptr_t)priv->base + x.moca_addr;
dst = (void *)(unsigned long)x.buf;
@@ -1847,8 +1869,10 @@
if (copy_from_user(&x, (void __user *)xfer_uaddr, sizeof(x)))
return -EFAULT;
+#if !DSL_MOCA
if (moca_range_ok(priv, x.moca_addr, x.len) < 0)
return -EINVAL;
+#endif
dst = (uintptr_t)priv->base + x.moca_addr;
src = (void *)(unsigned long)x.buf;
@@ -2071,12 +2095,10 @@
ret = 0;
break;
case MOCA_IOCTL_READMEM:
- if (priv->running)
- ret = moca_ioctl_readmem(priv, arg);
+ ret = moca_ioctl_readmem(priv, arg);
break;
case MOCA_IOCTL_WRITEMEM:
- if (priv->running)
- ret = moca_ioctl_writemem(priv, arg);
+ ret = moca_ioctl_writemem(priv, arg);
break;
case MOCA_IOCTL_GET_DRV_INFO_V2:
ret = moca_ioctl_get_drv_info_v2(priv, arg);
@@ -2114,6 +2136,9 @@
case MOCA_IOCTL_SET_3450_REG:
ret = moca_3450_set_reg(priv, (unsigned int *)arg);
break;
+ default:
+ pr_warn("moca_ioctl: unrecognized cmd\n");
+ break;
}
mutex_unlock(&priv->dev_mutex);
@@ -2357,10 +2382,18 @@
static int moca_probe(struct platform_device *pdev)
{
struct moca_priv_data *priv;
+#if !defined(CONFIG_BCM_6802_MoCA)
struct resource *mres, *ires = NULL;
+#endif
+ unsigned long long base;
int minor, err = 0;
struct moca_platform_data *pd = pdev->dev.platform_data;
+ if (pd->use_spi && !pd->spi) {
+ pr_err("moca: use_spi=1, but no bmoca SPI device found.\n");
+ return -EINVAL;
+ }
+
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
printk(KERN_ERR "%s: out of memory\n", __func__);
@@ -2431,6 +2464,12 @@
goto bad;
}
+#if defined(CONFIG_BCM_6802_MoCA)
+ base = pd->spi_base;
+ priv->base = (void *)pd->spi_base;
+ priv->irq = pd->spi->irq;
+ priv->i2c_base = (void *)pd->bcm3450_i2c_base;
+#else
mres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
@@ -2440,12 +2479,7 @@
goto bad;
}
-
-#if defined(CONFIG_BCM_6802_MoCA)
- priv->base = (void *)mres->start;
- priv->irq = ires->start;
- priv->i2c_base = (void *)pd->bcm3450_i2c_base;
-#else
+ base = mres->start;
priv->base = ioremap(mres->start, mres->end - mres->start + 1);
priv->irq = ires->start;
priv->i2c_base = ioremap(pd->bcm3450_i2c_base, sizeof(struct bsc_regs));
@@ -2453,25 +2487,12 @@
#if MOCA6816
moca_read_mac_addr(priv, &pd->macaddr_hi, &pd->macaddr_lo);
+#endif
if (hw_specific_init(priv))
goto bad;
-#endif
/* leave core in reset until we get an ioctl */
- moca_hw_reset(priv);
-
-#if defined(CONFIG_BCM_6802_MoCA)
- kerSysRegisterMocaHostIntrCallback(
- (MocaHostIntrCallback) moca_interrupt,
- (void *)priv, pd->devId);
-#else
- if (request_irq(priv->irq, moca_interrupt, 0, "moca", priv) < 0) {
- printk(KERN_WARNING "%s: can't request interrupt\n",
- __func__);
- err = -EIO;
- goto bad2;
- }
-#endif
+ //moca_hw_reset(priv); // moca_hw_init(MOCA_ENABLE) does this anyway
moca_hw_init(priv, MOCA_ENABLE);
moca_disable_irq(priv);
@@ -2480,7 +2501,7 @@
printk(KERN_INFO "bmoca: adding minor #%d at base 0x%08llx, IRQ %d, "
"I2C 0x%08llx/0x%02x\n", priv->minor,
- (unsigned long long)mres->start, ires->start,
+ base, priv->irq,
(unsigned long long)pd->bcm3450_i2c_base, pd->bcm3450_i2c_addr);
minor_tbl[priv->minor] = priv;
@@ -2491,16 +2512,26 @@
priv->dev = NULL;
}
+ moca_enable_irq(priv);
+ if (request_irq(priv->irq, moca_interrupt, 0, "moca", priv) < 0) {
+ printk(KERN_WARNING "%s: can't request interrupt\n",
+ __func__);
+ err = -EIO;
+ goto bad2;
+ }
+
if (err)
goto bad2;
return 0;
bad2:
- if (priv->base)
- iounmap(priv->base);
- if (priv->i2c_base)
- iounmap(priv->i2c_base);
+ if (!pd->use_spi) {
+ if (priv->base)
+ iounmap(priv->base);
+ if (priv->i2c_base)
+ iounmap(priv->i2c_base);
+ }
bad:
kfree(priv);
return err;
@@ -2509,6 +2540,7 @@
static int moca_remove(struct platform_device *pdev)
{
struct moca_priv_data *priv = dev_get_drvdata(&pdev->dev);
+ struct moca_platform_data *pd = pdev->dev.platform_data;
struct clk *clk = priv->clk;
struct clk *phy_clk = priv->phy_clk;
struct clk *cpu_clk = priv->cpu_clk;
@@ -2521,8 +2553,10 @@
if (priv->irq)
free_irq(priv->irq, priv);
- iounmap(priv->i2c_base);
- iounmap(priv->base);
+ if (!pd->use_spi) {
+ iounmap(priv->i2c_base);
+ iounmap(priv->base);
+ }
kfree(priv);
clk_put(clk);
@@ -2611,13 +2645,12 @@
static void moca_exit(void)
{
- class_destroy(moca_class);
unregister_chrdev(MOCA_MAJOR, MOCA_CLASS);
platform_driver_unregister(&moca_plat_drv);
#if MOCA6816
moca_platform_dev_unregister();
#endif
-
+ class_destroy(moca_class);
}
module_init(moca_init);
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..6538114
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,5 @@
+override EXTRA_CFLAGS += -I$M/../include -DCONFIG_BCM_6802_MoCA=1 -DDSL_MOCA=1
+
+all: modules
+
+obj-m += bmoca.o
diff --git a/bbsi.h b/bbsi.h
new file mode 100644
index 0000000..7907864
--- /dev/null
+++ b/bbsi.h
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2013 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#ifndef __BBSI_H
+#define __BBSI_H
+
+#include <linux/netdevice.h>
+#include <linux/spi/spi.h>
+#include <linux/vmalloc.h>
+
+#ifndef KSEG1
+#define KSEG1 0 // just to appease non-MIPS CPUs. Not really used.
+#endif
+
+#define BP_MOCA_MAX_NUM 1
+
+/*
+ * The exact values here don't matter, as they're translated into "real"
+ * values before talking to mocad. This is just for the device registration
+ * tables.
+ */
+enum {
+ BP_MOCA_TYPE_WAN,
+ BP_MOCA_TYPE_LAN,
+};
+
+enum {
+ BP_MOCA_RF_BAND_D_LOW,
+ BP_MOCA_RF_BAND_D_HIGH,
+ BP_MOCA_RF_BAND_EXT_D,
+ BP_MOCA_RF_BAND_E,
+ BP_MOCA_RF_BAND_F,
+};
+
+typedef struct BpMocaInfo {
+ int type;
+ int rfBand;
+} BP_MOCA_INFO;
+
+static void BpGetMocaInfo(BP_MOCA_INFO *chips, int *nchips) {
+ if (*nchips >= 1) {
+ *nchips = 1;
+ chips[0].type = BP_MOCA_TYPE_LAN;
+ chips[0].rfBand = BP_MOCA_RF_BAND_E;
+ }
+}
+
+static uint32_t _spi_read32(struct spi_device *spi, uint32_t addr);
+
+
+// TODO(apenwarr): don't make this global.
+// Or fix the driver to just only enable/disable interrupts at the right
+// times.
+static int irq_disabled = 0;
+
+static void kerSysMocaHostIntrEnable(struct spi_device *spi) {
+ if (irq_disabled == 1) {
+ irq_disabled = 0;
+ enable_irq(spi->irq);
+ }
+}
+
+static void kerSysMocaHostIntrDisable(struct spi_device *spi) {
+ if (irq_disabled == 0) {
+ disable_irq_nosync(spi->irq);
+ irq_disabled = 1;
+ }
+}
+
+static uint8_t __pollstatus(struct spi_device *spi) {
+ uint8_t wclear[] = { 0x80, 0x06 };
+ uint8_t rdata[1] = { 0 };
+ struct spi_transfer t[2] = {
+ { .tx_buf = wclear, .len = sizeof(wclear) },
+ { .rx_buf = rdata, .len = sizeof(rdata) },
+ };
+ struct spi_message m;
+ int i;
+
+ spi_message_init(&m);
+ spi_message_add_tail(&t[0], &m);
+ spi_message_add_tail(&t[1], &m);
+
+ for (i = 0; i < 10; i++) {
+ if (spi_sync_locked(spi, &m) < 0) {
+ pr_warn("spi _pollstatus: SPI error\n");
+ return 0x01; // error code
+ }
+ if (rdata[0] & 0x01) {
+ pr_warn("spi _pollstatus: rbus error: %02X\n", rdata[0]);
+ return 0x01; // error result; stop polling now
+ }
+ if (!(rdata[0] & 0x10)) return 0; // transaction finished
+ }
+ // if we get here, the transaction still isn't finished: weird
+ pr_warn("spi _pollstatus: still busy: %02X\n", rdata[0]);
+ return rdata[0];
+}
+
+static uint32_t __spi_read32a(struct spi_device *spi, uint32_t addr,
+ int speculative) {
+ uint8_t waddr[] = {
+ 0x81, 0x07,
+ 0x01 | (speculative ? 0x02 : 0),
+ 0, 0, 0, 0 };
+ struct spi_transfer addrt[1] = {
+ { .tx_buf = waddr, .len = sizeof(waddr) },
+ };
+ struct spi_message addrm;
+ int j, st;
+
+ spi_message_init(&addrm);
+ spi_message_add_tail(&addrt[0], &addrm);
+
+ __pollstatus(spi);
+ for (j = 0; j < 10; j++) {
+ // write address reg, which triggers the read
+ writel(cpu_to_be32(addr), waddr + sizeof(waddr) - 4);
+ if (spi_sync_locked(spi, &addrm) < 0) {
+ pr_warn("spi_read_addr: error\n");
+ }
+ st = __pollstatus(spi);
+ if (!st) break;
+ }
+ return st;
+}
+
+static uint32_t __spi_read32d_noswap(struct spi_device *spi) {
+ uint8_t wdata[] = { 0x80, 0x0c };
+ uint8_t rdata[4];
+ struct spi_transfer datat[2] = {
+ { .tx_buf = wdata, .len = sizeof(wdata) },
+ { .rx_buf = rdata, .len = sizeof(rdata) },
+ };
+ struct spi_message datam;
+
+ spi_message_init(&datam);
+ spi_message_add_tail(&datat[0], &datam);
+ spi_message_add_tail(&datat[1], &datam);
+
+ // retrieve actual data bits
+ if (spi_sync_locked(spi, &datam) < 0) {
+ pr_warn("spi_read_data: error\n");
+ }
+ return readl(rdata);
+}
+
+static uint32_t _spi_read32(struct spi_device *spi, uint32_t addr) {
+ int st;
+ uint32_t retval;
+
+ spi_bus_lock(spi->master);
+
+ st = __spi_read32a(spi, addr, 0);
+ if (st) {
+ retval = 0x00000000; // error
+ } else {
+ retval = be32_to_cpu(__spi_read32d_noswap(spi));
+ }
+ spi_bus_unlock(spi->master);
+ return retval;
+}
+
+static void __spi_write32a(struct spi_device *spi, uint32_t addr) {
+ uint8_t waddr[] = { 0x81, 0x07, 0x00, 0, 0, 0, 0 };
+ struct spi_transfer t[1] = {
+ { .tx_buf = waddr, .len = sizeof(waddr) },
+ };
+ struct spi_message m;
+
+ spi_message_init(&m);
+ spi_message_add_tail(&t[0], &m);
+
+ // write address reg
+ writel(cpu_to_be32(addr), waddr + sizeof(waddr) - 4);
+ if (spi_sync_locked(spi, &m) < 0) {
+ pr_warn("spi_write: error\n");
+ }
+}
+
+static void __spi_write32d_noswap(struct spi_device *spi, uint32_t value) {
+ uint8_t wdata[] = { 0x81, 0x0c, 0, 0, 0, 0 };
+ struct spi_transfer t[1] = {
+ { .tx_buf = wdata, .len = sizeof(wdata) },
+ };
+ struct spi_message m;
+
+ spi_message_init(&m);
+ spi_message_add_tail(&t[0], &m);
+
+ // write data reg
+ writel(value, wdata + sizeof(wdata) - 4);
+ if (spi_sync_locked(spi, &m) < 0) {
+ pr_warn("spi_write: error\n");
+ }
+}
+
+
+static void _spi_write32(struct spi_device *spi, uint32_t addr, uint32_t value) {
+ spi_bus_lock(spi->master);
+ __pollstatus(spi);
+ __spi_write32a(spi, addr);
+ __spi_write32d_noswap(spi, cpu_to_be32(value));
+ __pollstatus(spi);
+ spi_bus_unlock(spi->master);
+}
+
+static uint32_t kerSysBcmSpiSlaveReadReg32(struct spi_device *spi, uint32_t addr) {
+ return _spi_read32(spi, addr);
+}
+
+static void kerSysBcmSpiSlaveWriteReg32(struct spi_device *spi, uint32_t addr, uint32_t value) {
+ _spi_write32(spi, addr, value);
+}
+
+static void kerSysBcmSpiSlaveReadBuf(struct spi_device *spi, uint32_t addr, void *dst, int len, int wordsize) {
+ int i;
+ uint32_t *buf = dst;
+
+ spi_bus_lock(spi->master);
+
+ if (wordsize != 4) {
+ pr_info("SPI readbuf: only word size == 4 bytes is supported!\n");
+ return;
+ }
+ __spi_read32a(spi, addr, 1);
+ for (i = 0; i < len; i += wordsize) {
+ buf[i/4] = __spi_read32d_noswap(spi);
+ __pollstatus(spi);
+ }
+
+ spi_bus_unlock(spi->master);
+}
+
+static void kerSysBcmSpiSlaveWriteBuf(struct spi_device *spi, uint32_t addr, const void *src, int len, int wordsize) {
+ int i, nelems = len/4;
+ const uint32_t *buf = src;
+ uint8_t wdata[] = { 0x81, 0x0c };
+ struct spi_transfer *t, *tp;
+ struct spi_message m;
+
+ if (len > 8192) {
+ pr_warn("spi writebuf: buffer size %d is too large\n", len);
+ return;
+ }
+ if (wordsize != 4) {
+ pr_err("SPI writebuf: only word size == 4 bytes is supported!\n");
+ return;
+ }
+
+ t = vmalloc(nelems * sizeof(struct spi_transfer) * 2);
+ if (!t) {
+ pr_warn("spi writebuf: out of memory\n");
+ return;
+ }
+
+ memset(t, 0, nelems * sizeof(struct spi_transfer) * 2);
+ spi_message_init(&m);
+
+ for (i = 0, tp = t; i < nelems; i++) {
+ tp->tx_buf = wdata;
+ tp->len = sizeof(wdata);
+ spi_message_add_tail(tp, &m);
+ tp++;
+
+ tp->tx_buf = &buf[i];
+ tp->len = 4;
+ tp->cs_change = 1;
+ spi_message_add_tail(tp, &m);
+ tp++;
+ }
+
+ spi_bus_lock(spi->master);
+
+ __pollstatus(spi);
+ writel(cpu_to_be32(addr), wdata + 2);
+ __spi_write32a(spi, addr);
+ spi_sync_locked(spi, &m);
+ __pollstatus(spi);
+
+ spi_bus_unlock(spi->master);
+ vfree(t);
+}
+
+#endif // __BBSI_H
diff --git a/bmoca-6802.c b/bmoca-6802.c
index dafbfc2..78910ae 100644
--- a/bmoca-6802.c
+++ b/bmoca-6802.c
@@ -29,6 +29,7 @@
*/
#include "bbsi.h"
+#include <linux/spi/spi.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
#else
@@ -37,26 +38,26 @@
#define MOCA_RD(x) ((((struct moca_platform_data *)priv->pdev->dev.platform_data)->use_spi == 0) ? \
(*((volatile uint32_t *)((unsigned long)(x)))) : \
- ((uint32_t)kerSysBcmSpiSlaveReadReg32(((struct moca_platform_data *)priv->pdev->dev.platform_data)->devId, (uint32_t)(x))))
+ ((uint32_t)kerSysBcmSpiSlaveReadReg32(((struct moca_platform_data *)priv->pdev->dev.platform_data)->spi, (uint32_t)(x))))
#define MOCA_RD8(x, y) ((((struct moca_platform_data *)priv->pdev->dev.platform_data)->use_spi == 0) ? \
(*(y) = *((volatile unsigned char *)((unsigned long)(x)))) : \
- (kerSysBcmSpiSlaveRead(((struct moca_platform_data *)priv->pdev->dev.platform_data)->devId, (unsigned long)(x), y, 1)))
+ (kerSysBcmSpiSlaveRead(((struct moca_platform_data *)priv->pdev->dev.platform_data)->spi, (unsigned long)(x), y, 1)))
#define MOCA_WR(x,y) do { ((((struct moca_platform_data *)priv->pdev->dev.platform_data)->use_spi == 0) ? \
(*((volatile uint32_t *)((unsigned long)(x)))) = (y) : \
- kerSysBcmSpiSlaveWriteReg32(((struct moca_platform_data *)priv->pdev->dev.platform_data)->devId, (uint32_t)(x), (y))); } while(0)
+ kerSysBcmSpiSlaveWriteReg32(((struct moca_platform_data *)priv->pdev->dev.platform_data)->spi, (uint32_t)(x), (y))); } while(0)
#define MOCA_WR8(x,y) do { ((((struct moca_platform_data *)priv->pdev->dev.platform_data)->use_spi == 0) ? \
(*((volatile unsigned char *)((unsigned long)(x)))) = (unsigned char)(y) : \
- kerSysBcmSpiSlaveWrite(((struct moca_platform_data *)priv->pdev->dev.platform_data)->devId, (unsigned long)(x), (y), 1)); } while(0)
+ kerSysBcmSpiSlaveWrite(((struct moca_platform_data *)priv->pdev->dev.platform_data)->spi, (unsigned long)(x), (y), 1)); } while(0)
#define MOCA_WR16(x,y) do { ((((struct moca_platform_data *)priv->pdev->dev.platform_data)->use_spi == 0) ? \
(*((volatile unsigned short *)((unsigned long)(x)))) = (unsigned short)(y) : \
- kerSysBcmSpiSlaveWrite(((struct moca_platform_data *)priv->pdev->dev.platform_data)->devId, (unsigned long)(x), (y), 2)); } while(0)
+ kerSysBcmSpiSlaveWrite(((struct moca_platform_data *)priv->pdev->dev.platform_data)->spi, (unsigned long)(x), (y), 2)); } while(0)
-#define MOCA_WR_BLOCK(addr, src, len) do { kerSysBcmSpiSlaveWriteBuf(((struct moca_platform_data *)priv->pdev->dev.platform_data)->devId, addr, src, len, 4); } while(0)
-#define MOCA_RD_BLOCK(addr, dst, len) do { kerSysBcmSpiSlaveReadBuf(((struct moca_platform_data *)priv->pdev->dev.platform_data)->devId, addr, dst, len, 4); } while(0)
+#define MOCA_WR_BLOCK(addr, src, len) do { kerSysBcmSpiSlaveWriteBuf(((struct moca_platform_data *)priv->pdev->dev.platform_data)->spi, addr, src, len, 4); } while(0)
+#define MOCA_RD_BLOCK(addr, dst, len) do { kerSysBcmSpiSlaveReadBuf(((struct moca_platform_data *)priv->pdev->dev.platform_data)->spi, addr, dst, len, 4); } while(0)
#define I2C_RD(x) MOCA_RD(x)
@@ -86,6 +87,7 @@
.bcm3450_i2c_base = 0x10406200,
.bcm3450_i2c_addr = 0x70,
+ .spi_base = 0x10600000,
.hw_rev = HWREV_MOCA_20_GEN22,
.rf_band = MOCA_BAND_EXT_D,
.chip_id = 0,
@@ -97,24 +99,11 @@
#endif
};
-static struct resource moca_lan_resources[] = {
- [0] = {
- .start = 0x10600000,
- .end = 0x107ffd97,
- .flags = IORESOURCE_MEM,
- },
- [1] = { /* Not used for 6802, define for bmoca */
- .start = 0,
- .end = 0,
- .flags = IORESOURCE_IRQ,
- }
-};
-
static struct platform_device moca_lan_plat_dev = {
.name = "bmoca",
.id = 0,
- .num_resources = ARRAY_SIZE(moca_lan_resources),
- .resource = moca_lan_resources,
+ .num_resources = 0,
+ .resource = NULL,
.dev = {
.platform_data = &moca_lan_data,
.release = bogus_release,
@@ -127,6 +116,7 @@
.bcm3450_i2c_base = 0x10406200,
.bcm3450_i2c_addr = 0x70,
+ .spi_base = 0x10600000,
.hw_rev = HWREV_MOCA_20_GEN22,
.chip_id = 0,
@@ -141,24 +131,11 @@
#endif
};
-static struct resource moca_wan_resources[] = {
- [0] = {
- .start = 0x10600000,
- .end = 0x107ffd97,
- .flags = IORESOURCE_MEM,
- },
- [1] = { /* Not used for 6802, define for bmoca */
- .start = 0,
- .end = 0,
- .flags = IORESOURCE_IRQ,
- }
-};
-
static struct platform_device moca_wan_plat_dev = {
.name = "bmoca",
.id = 1,
- .num_resources = ARRAY_SIZE(moca_wan_resources),
- .resource = moca_wan_resources,
+ .num_resources = 0,
+ .resource = NULL,
.dev = {
.platform_data = &moca_wan_data,
.release = bogus_release,
@@ -167,12 +144,12 @@
static void moca_enable_irq(struct moca_priv_data *priv)
{
- kerSysMocaHostIntrEnable(((struct moca_platform_data *)priv->pdev->dev.platform_data)->devId);
+ kerSysMocaHostIntrEnable(((struct moca_platform_data *)priv->pdev->dev.platform_data)->spi);
}
static void moca_disable_irq(struct moca_priv_data *priv)
{
- kerSysMocaHostIntrDisable(((struct moca_platform_data *)priv->pdev->dev.platform_data)->devId);
+ kerSysMocaHostIntrDisable(((struct moca_platform_data *)priv->pdev->dev.platform_data)->spi);
}
static void moca_pmb_busy_wait(struct moca_priv_data *priv)
@@ -288,7 +265,7 @@
x = (x >> 1) & 0xFF; // Get the MDIV_CH2 field
- return( 2400 / x);
+ return( x ? 2400 / x : 0);
}
/* called any time we start/restart/stop MoCA */
@@ -303,6 +280,8 @@
if (action == MOCA_ENABLE && !priv->enabled) {
clk_enable(priv->clk);
+ MOCA_WR(0x10404318, 0xfffffffd); // SUN_TOP_CTRL_SW_INIT_0_SET
+ udelay(20);
MOCA_WR(0x1040431c, 0xffffffff); // SUN_TOP_CTRL_SW_INIT_0_CLEAR --> Do this at start of sequence
udelay(20);
@@ -316,6 +295,14 @@
moca_hw_reset(priv);
udelay(1);
+ MOCA_WR(0x10800000, 0x03); // EMUX_CNTRL
+ MOCA_WR(0x1080000c, 0x11); // RGMII_0_CNTRL
+ MOCA_WR(0x10800014, 0xc0); // RGMII_0_RX_CLK_DELAY_CNTRL
+
+ MOCA_WR(0x104040a4, 0x01); // GENERAL_CTRL_NO_SCAN_0
+ MOCA_WR(0x10404100, 0x11110011); // PIN_MUX_CTRL_0
+ MOCA_WR(0x10404104, 0x11111111); // PIN_MUX_CTRL_1
+
if (action == MOCA_ENABLE) {
/* Power up all zones */
@@ -708,6 +695,36 @@
#endif /* DSL_MOCA */
+static int __devinit bmoca_spi_probe(struct spi_device *spi) {
+ // TODO(apenwarr): match one spi device to one moca device struct.
+ // I happen to know that right now the system only registers one of
+ // moca_lan or moca_wan, never both, and there is never more than
+ // one moca chip present on our systems, so this is okay for now.
+ uint32_t val = kerSysBcmSpiSlaveReadReg32(spi, 0x10404000);
+ pr_info("bmoca_spi_probe bus=%d chip_select=%d: id=%08x %s\n",
+ spi->master->bus_num, spi->chip_select, val,
+ val != 0 ? "yes" : "no");
+ if (val == 0) return -ENODEV;
+ moca_lan_data.spi = spi;
+ moca_wan_data.spi = spi;
+ return 0; // success
+}
+
+static int __devexit bmoca_spi_remove(struct spi_device *spi) {
+ pr_info("bmoca_spi_remove\n");
+ if (moca_lan_data.spi == spi) moca_lan_data.spi = NULL;
+ if (moca_wan_data.spi == spi) moca_wan_data.spi = NULL;
+ return 0; // success
+}
+
+static struct spi_driver bmoca_spi_driver = {
+ .driver = {
+ .name = "bmoca",
+ .owner = THIS_MODULE,
+ },
+ .probe = bmoca_spi_probe,
+ .remove = __devexit_p(bmoca_spi_remove),
+};
//extern void bcmenet_register_moca_fc_bits_cb(void cb(void *, unsigned long *), int isWan, void * arg);
@@ -720,6 +737,7 @@
/* fill in the hw_rev field */
pMocaData->chip_id = MOCA_RD(0x10404004) + 0xA0;
+ pr_info("read moca chip id: %08x\n", pMocaData->chip_id);
pMocaData->hw_rev = HWREV_MOCA_20_GEN22;
@@ -751,6 +769,9 @@
BpGetMocaInfo(mocaInfo, &mocaChipNum);
+ ret = spi_register_driver(&bmoca_spi_driver);
+ if (ret < 0) return ret;
+
for (i = 0; i < mocaChipNum; i++) {
switch (mocaInfo[i].type) {
case BP_MOCA_TYPE_WAN:
@@ -772,6 +793,7 @@
ret = platform_device_register(pPlatformDev);
if (ret < 0) {
+ spi_unregister_driver(&bmoca_spi_driver);
return(ret);
}
else {
@@ -809,6 +831,8 @@
static void moca_platform_dev_unregister(void)
{
+ spi_unregister_driver(&bmoca_spi_driver);
+
if (moca_lan_data.devId != MOCA_DEVICE_ID_UNREGISTERED)
platform_device_unregister(&moca_lan_plat_dev);
diff --git a/bmoca.h b/bmoca.h
index d182f35..3014df6 100644
--- a/bmoca.h
+++ b/bmoca.h
@@ -160,12 +160,16 @@
phys_addr_t bcm3450_i2c_base;
int bcm3450_i2c_addr;
+ u32 spi_base;
+
u32 hw_rev; /* this is the chip_id */
u32 rf_band;
int use_dma;
int use_spi;
int devId;
+ struct spi_device *spi;
+
u32 chip_id;
#ifdef CONFIG_SMP
diff --git a/linux b/linux
new file mode 120000
index 0000000..945c9b4
--- /dev/null
+++ b/linux
@@ -0,0 +1 @@
+.
\ No newline at end of file