Merge branch 'broadcom_drops' into HEAD
Merge 2.10.3.3
Conflicts:
bmoca-6802.c
Change-Id: I84a772d205a4fc59276bbbf6f59dfb186e17da3e
diff --git a/3.8/bmoca.c b/3.8/bmoca.c
index 6ca337e..08812d9 100644
--- a/3.8/bmoca.c
+++ b/3.8/bmoca.c
@@ -2267,7 +2267,12 @@
of_property_read_u32(of_node, "i2c-addr", &pd.bcm3450_i2c_addr);
of_property_read_u32(of_node, "use-dma", &pd.use_dma);
of_property_read_u32(of_node, "use-spi", &pd.use_spi);
+
+#if defined(CONFIG_BCM7145A0)
+ pd.chip_id = 0x714500a0;
+#else
pd.chip_id = (BRCM_CHIP_ID() << 16) | (BRCM_CHIP_REV() + 0xa0);
+#endif
status = platform_device_add_data(pdev, &pd, sizeof(pd));
err:
diff --git a/bmoca-6802.c b/bmoca-6802.c
index 5714cad..a06ad5b 100644
--- a/bmoca-6802.c
+++ b/bmoca-6802.c
@@ -66,16 +66,37 @@
#define MOCA_BPCM_NUM 5
#define MOCA_BPCM_ZONES_NUM 8
+#define MOCA_CPU_CLOCK_NUM 1
+#define MOCA_PHY_CLOCK_NUM 2
+
typedef enum _PMB_COMMAND_E_
{
- PMB_COMMAND_ALL_OFF = 0,
- PMB_COMMAND_ALL_ON,
+ PMB_COMMAND_PHY1_ON=0,
+ PMB_COMMAND_PARTIAL_ON,
+ PMB_COMMAND_PHY1_OFF,
+ PMB_COMMAND_ALL_OFF,
PMB_COMMAND_LAST
} PMB_COMMAND_E;
-static uint32_t zone_off_bitmask[MOCA_BPCM_NUM] = { 0xFF, 0x03, 0x30, 0x00, 0x00 };
-static uint32_t zone_on_bitmask[MOCA_BPCM_NUM] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+typedef enum _PMB_GIVE_OWNERSHIP_E_
+{
+ PMB_GIVE_OWNERSHIP_2_HOST = 0,
+ PMB_GIVE_OWNERSHIP_2_FW,
+
+ PMB_GET_OWNERSHIP_LAST
+} PMB_GIVE_OWNERSHIP_E;
+
+struct moca_680x_clk
+{
+ struct device *dev;
+ uint32_t clock_num;
+};
+
+static uint32_t zone_all_off_bitmask[MOCA_BPCM_NUM] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+static uint32_t zone_partial_on_bitmask[MOCA_BPCM_NUM] = { 0x41, 0xFC, 0xFF, 0xFF, 0x00 };
+static uint32_t zone_phy1_bitmask[MOCA_BPCM_NUM] = { 0x00, 0x00, 0x00, 0x00, 0xFF };
+
static void bogus_release(struct device *dev)
{
@@ -191,6 +212,24 @@
#endif
}
+void moca_pmb_delay(struct moca_priv_data *priv)
+{
+ unsigned int data;
+ int i, j;
+
+ MOCA_WR(priv->base + priv->regs->pmb_master_wdata_offset, 0xFF444000);
+
+ for (i = 0; i < MOCA_BPCM_NUM; i++)
+ {
+ for (j = 0; j < MOCA_BPCM_ZONES_NUM; j++)
+ {
+ data = 0x100012 + j*4 + i*0x1000; ;
+ MOCA_WR(priv->base + priv->regs->pmb_master_cmd_offset, data);
+ moca_pmb_busy_wait(priv);
+ }
+ }
+}
+
static void moca_pmb_control(struct moca_priv_data *priv, PMB_COMMAND_E cmd)
{
int i, j;
@@ -202,13 +241,28 @@
case PMB_COMMAND_ALL_OFF:
// Turn off zone command
MOCA_WR(priv->base + priv->regs->pmb_master_wdata_offset, 0xA00);
- p_zone_control = &zone_off_bitmask[0];
+ p_zone_control = &zone_all_off_bitmask[0];
break;
- case PMB_COMMAND_ALL_ON:
+
+ case PMB_COMMAND_PHY1_OFF:
+ // Turn off zone command
+ MOCA_WR(priv->base + priv->regs->pmb_master_wdata_offset, 0xA00);
+ p_zone_control = &zone_phy1_bitmask[0];
+ break;
+
+ case PMB_COMMAND_PHY1_ON:
// Turn on zone command
MOCA_WR(priv->base + priv->regs->pmb_master_wdata_offset, 0xC00);
- p_zone_control = &zone_on_bitmask[0];
+ p_zone_control = &zone_phy1_bitmask[0];
break;
+
+ case PMB_COMMAND_PARTIAL_ON:
+ // Turn on zone command
+ MOCA_WR(priv->base + priv->regs->pmb_master_wdata_offset, 0xC00);
+ p_zone_control = &zone_partial_on_bitmask[0];
+ break;
+
+
default:
printk(KERN_WARNING "%s: illegal cmd: %08x\n",
__FUNCTION__, cmd);
@@ -232,11 +286,19 @@
}
-static void moca_pmb_give_fw_cntrl(struct moca_priv_data *priv)
+static void moca_pmb_give_cntrl(struct moca_priv_data *priv, PMB_GIVE_OWNERSHIP_E cmd)
{
+ int i;
+ uint32_t data;
+
/* Pass control over the memories to the FW */
- MOCA_WR(priv->base + priv->regs->pmb_master_wdata_offset, 0x1);
- MOCA_WR(priv->base + priv->regs->pmb_master_cmd_offset, 0x100002);
+ MOCA_WR(priv->base + priv->regs->pmb_master_wdata_offset, cmd);
+ for (i = 0; i < 3; i++)
+ {
+ data = 0x100002 + i*0x1000;
+ MOCA_WR(priv->base + priv->regs->pmb_master_cmd_offset, data);
+ moca_pmb_busy_wait(priv);
+ }
moca_pmb_busy_wait(priv);
}
@@ -244,6 +306,7 @@
{
// unsigned long flags;
// uint32_t chipid;
+
/* disable and clear all interrupts */
MOCA_WR(priv->base + priv->regs->l2_mask_set_offset, 0xffffffff);
@@ -262,19 +325,22 @@
udelay(20);
/* reset everything else except clocks */
- MOCA_SET(priv->base + priv->regs->sw_reset_offset, ~((1 << 3) | (1 << 7)));
+ MOCA_SET(priv->base + priv->regs->sw_reset_offset,
+ ~((1 << 3) | (1 << 7) | (1 << 15) | (1 << 16)));
MOCA_RD(priv->base + priv->regs->sw_reset_offset);
udelay(20);
/* disable clocks */
- MOCA_SET(priv->base + priv->regs->sw_reset_offset, ~(1 << 3));
+ MOCA_SET(priv->base + priv->regs->sw_reset_offset,
+ ~((1 << 3) | (1 << 15) | (1 << 16)));
MOCA_RD(priv->base + priv->regs->sw_reset_offset);
MOCA_WR(priv->base + priv->regs->l2_clear_offset, 0xffffffff);
MOCA_RD(priv->base + priv->regs->l2_clear_offset);
/* Power down all zones */
+ // The host can't give to itself permission.
moca_pmb_control(priv, PMB_COMMAND_ALL_OFF);
/* Power down all SYS_CTRL memories */
@@ -292,6 +358,72 @@
return( x ? 2400 / x : 0);
}
+
+static void moca_ps_PowerCtrlPHY1(struct moca_priv_data *priv, PMB_COMMAND_E cmd)
+{
+ uint32_t pll_ctrl_3, pll_ctrl_5, sw_reset;
+ pll_ctrl_3 = MOCA_RD (0x10100048);
+ pll_ctrl_5 = MOCA_RD (0x10100050);
+ sw_reset = MOCA_RD (priv->base + priv->regs->sw_reset_offset);
+
+ // enable PLL
+ MOCA_UNSET(0x10100048, 1); // CLKGEN_PLL_SYS1_PLL_CHANNEL_CTRL_CH_3
+ MOCA_UNSET(0x10100050, 1); // CLKGEN_PLL_SYS1_PLL_CHANNEL_CTRL_CH_5
+
+ udelay(1);
+
+ // de assert moca_phy1_disable_clk
+ MOCA_UNSET(priv->base + priv->regs->sw_reset_offset, (1 << 9));
+
+ moca_pmb_control(priv, cmd);
+
+ MOCA_WR (0x10100048, pll_ctrl_3);
+ MOCA_WR (0x10100050, pll_ctrl_5);
+
+ udelay(1);
+
+ MOCA_WR (priv->base + priv->regs->sw_reset_offset, sw_reset);
+}
+
+
+static void moca_gphy_init(struct moca_priv_data *priv)
+{
+ struct moca_platform_data * pMocaData = (struct moca_platform_data *)priv->pdev->dev.platform_data;
+ u32 port_mode;
+ u32 rgmii0_on;
+ u32 rgmii1_on;
+ u32 gphy_enabled = 0;
+
+ port_mode = MOCA_RD(0x10800000) & 0x3;
+ rgmii0_on = MOCA_RD(0x1080000c) & 0x1;
+ rgmii1_on = MOCA_RD(0x10800018) & 0x1;
+
+ if ((pMocaData->chip_id & 0xFFFEFFF0) == 0x680200C0)
+ {
+ if ((port_mode == 0) ||
+ ((port_mode == 1) && rgmii0_on) ||
+ ((port_mode == 2) && rgmii1_on))
+ {
+ gphy_enabled = 1;
+ }
+ }
+ else
+ {
+ if ((port_mode == 0) ||
+ ((port_mode != 3) && rgmii1_on))
+ {
+ gphy_enabled = 1;
+ }
+ }
+
+ if (gphy_enabled)
+ {
+ MOCA_UNSET(0x10800004, 0xF);
+ msleep(10);
+ MOCA_WR(0x1040431c, 0xFFFFFFFF);
+ }
+}
+
/* called any time we start/restart/stop MoCA */
static void moca_hw_init(struct moca_priv_data *priv, int action)
{
@@ -306,8 +438,9 @@
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
+ MOCA_WR(0x1040431c, ~(1 << 26)); // SUN_TOP_CTRL_SW_INIT_0_CLEAR --> Do this at start of sequence, don't touch gphy_sw_init
udelay(20);
+ moca_gphy_init(priv);
priv->enabled = 1;
}
@@ -330,8 +463,7 @@
if (action == MOCA_ENABLE) {
/* Power up all zones */
- moca_pmb_control(priv, PMB_COMMAND_ALL_ON);
- moca_pmb_give_fw_cntrl(priv);
+ moca_pmb_control(priv, PMB_COMMAND_PARTIAL_ON);
MOCA_UNSET(0x1010000c, 1); // CLKGEN_PLL_SYS0_PLL_CHANNEL_CTRL_CH_3
@@ -357,7 +489,7 @@
}
udelay(1);
- /* deassert moca_sys_reset, system clock, phy0 and phy0 clock */
+ /* deassert moca_sys_reset, system clock, phy0, phy0 clock */
mask = (1 << 1) | (1 << 7) | (1 << 4) | (1 << 8);
/* deassert phy1 and phy1 clock in bonded mode */
@@ -366,8 +498,16 @@
MOCA_UNSET(priv->base + priv->regs->sw_reset_offset, mask);
MOCA_RD(priv->base + priv->regs->sw_reset_offset);
+
+ // Before power off the memories, moca_phy1_disable_clk.
+ if (priv->bonded_mode==0)
+ moca_ps_PowerCtrlPHY1(priv, PMB_COMMAND_PHY1_OFF);
+ else
+ moca_ps_PowerCtrlPHY1(priv, PMB_COMMAND_PHY1_ON);
-
+
+ moca_pmb_give_cntrl(priv, PMB_GIVE_OWNERSHIP_2_FW);
+
/* Check for 6802/6803 A0 chip only with Xtal mod */
if ((pMocaData->chip_id & 0xFFFEFFFF) == 0x680200A0)
{
@@ -429,8 +569,6 @@
// CLKGEN_PLL_SYS1_PLL_SSC_MODE_CONTROL_LOW
MOCA_SET(0x10100074, (1 << 22));
-
- printk("Set PLL SSC mode\n");
}
@@ -460,6 +598,14 @@
MOCA_UNSET(0x10404110, 0xF00000FF);
MOCA_SET(0x10404110, 0x10000022);
+ /* Set pinmuxing for MoCA IIC control */
+ if (((pMocaData->chip_id & 0xFFFFFFF0) == 0x680200C0) ||
+ ((pMocaData->chip_id & 0xFFFFFFF0) == 0x680300C0))
+ {
+ MOCA_UNSET(0x10404100, 0xFF); // pin muxing
+ MOCA_SET(0x10404100, 0x22); // pin muxing
+ }
+
MOCA_WR(0x100b0318, 2);
if (action == MOCA_DISABLE && priv->enabled) {
@@ -589,7 +735,7 @@
else
{
for(i = 0; i < len; i += 4, addr += 4, data++)
- *data = MOCA_RD((uintptr_t)priv->base + addr);
+ *data = MOCA_RD((uintptr_t)priv->base + addr);
}
mutex_unlock(&priv->copy_mutex);
}
@@ -752,6 +898,19 @@
//extern void bcmenet_register_moca_fc_bits_cb(void cb(void *, unsigned long *), int isWan, void * arg);
+static void moca_mem_init_680xC0( struct moca_priv_data *priv )
+{
+ // De-assert reset (all memories are OFF by default Force_SP_off =1, Force_Rf_off =1)
+ MOCA_UNSET(priv->base + priv->regs->sw_reset_offset, ((1 << 15) | (1 << 16)));
+
+ moca_pmb_delay(priv);
+ moca_pmb_control(priv, PMB_COMMAND_ALL_OFF);
+
+ //Write Force_SP_on =0, Force_SP_off =0, Force_RF_on =0, Force_RF_off =0
+ MOCA_UNSET(priv->base + 0x001ffd14, ((1 << 10) | (1 << 11)));
+ moca_pmb_control(priv, PMB_COMMAND_PARTIAL_ON);
+}
+
static int hw_specific_init( struct moca_priv_data *priv )
{
#ifdef DSL_MOCA
@@ -762,6 +921,18 @@
/* fill in the hw_rev field */
pMocaData->chip_id = MOCA_RD(0x10404004) + 0xA0;
pr_info("read moca chip id: %08x\n", pMocaData->chip_id);
+ if ((pMocaData->chip_id & 0xFFFE0000) != 0x68020000) { /* 6802 or 6803 */
+ printk(KERN_ERR "bmoca: No MoCA chip found\n");
+ return -EFAULT;
+ }
+
+ if (((pMocaData->chip_id & 0xFFFFFFF0) == 0x680200C0) || ((pMocaData->chip_id & 0xFFFFFFF0) == 0x680300C0))
+ {
+ priv->i2c_base = NULL;
+
+ /* Initialize 680x CO memory */
+ moca_mem_init_680xC0(priv);
+ }
pMocaData->hw_rev = HWREV_MOCA_20_GEN22;
@@ -872,7 +1043,10 @@
bcm3450_write_reg(addr, data);
else
#endif
- moca_3450_write_i2c(priv, addr, data);
+ {
+ if (priv->i2c_base != NULL)
+ moca_3450_write_i2c(priv, addr, data);
+ }
}
static u32 moca_3450_read(struct moca_priv_data *priv, u8 addr)
@@ -883,7 +1057,12 @@
return(bcm3450_read_reg(addr));
else
#endif
- return(moca_3450_read_i2c(priv, addr));
+ {
+ if (priv->i2c_base != NULL)
+ return(moca_3450_read_i2c(priv, addr));
+ else
+ return(0xffffffff);
+ }
}
/*
@@ -892,12 +1071,27 @@
struct clk *clk_get(struct device *dev, const char *id)
{
- return NULL;
+ // We're not actually using the "struct clk" for anything
+ // We'll use our own structure
+ struct moca_680x_clk * pclk = kzalloc(sizeof(struct moca_680x_clk), GFP_KERNEL);
+
+ pclk->dev = dev;
+
+ if (!strcmp(id, "moca-cpu"))
+ pclk->clock_num = MOCA_CPU_CLOCK_NUM;
+ else if (!strcmp(id, "moca-phy"))
+ pclk->clock_num = MOCA_PHY_CLOCK_NUM;
+ else
+ {
+ kfree(pclk);
+ return(NULL);
+ }
+
+ return((struct clk *)pclk);
}
int clk_enable(struct clk *clk)
{
-
return 0;
}
@@ -907,10 +1101,113 @@
void clk_put(struct clk *clk)
{
+ kfree((struct moca_680x_clk *)clk);
}
+struct moca_6802c0_clock_params
+{
+ uint32_t cpu_hz;
+ uint32_t pdiv;
+ uint32_t ndiv;
+ uint32_t pll_mdivs[6];
+};
+
+#define NUM_6802C0_CLOCK_OPTIONS 2
+struct moca_6802c0_clock_params moca_6802c0_clock_params[NUM_6802C0_CLOCK_OPTIONS] =
+{
+ { // VCO of 2100, default
+ 420000000, // cpu_hz
+ 1, // pdiv
+ 42, // ndiv
+ {5, 21, 7, 7, 42, 42} // pll_mdivs[6]
+ },
+ { // VCO of 2400
+ 400000000, // cpu_hz
+ 1, // pdiv
+ 48, // ndiv
+ {6, 24, 8, 8, 48, 48} // pll_mdivs[6]
+ },
+};
+
int clk_set_rate(struct clk *clk, unsigned long rate)
{
- return 0;
+ // The MOCA_RD/MOCA_WR macros need a valid 'priv->pdev->dev'
+ struct moca_priv_data dummy_priv;
+ struct platform_device dummy_pd;
+ struct moca_priv_data *priv = &dummy_priv;
+ struct moca_680x_clk * pclk = (struct moca_680x_clk *) clk;
+ struct moca_platform_data * pMocaData = (struct moca_platform_data *)pclk->dev->platform_data;
+ struct moca_6802c0_clock_params * p_clock_data = &moca_6802c0_clock_params[0];
+ uint32_t i;
+ uint32_t addr;
+ uint32_t data;
+ int ret = -1;
+
+ priv->pdev = &dummy_pd;
+ priv->pdev->dev = *pclk->dev;
+
+ if (pclk->clock_num == MOCA_CPU_CLOCK_NUM)
+ {
+ if ((pMocaData->chip_id & 0xFFFFFFF0) == 0x680200C0)
+ {
+ for (i = 0; i < NUM_6802C0_CLOCK_OPTIONS; i++)
+ {
+ if (moca_6802c0_clock_params[i].cpu_hz == rate)
+ {
+ p_clock_data = &moca_6802c0_clock_params[i];
+ ret = 0;
+ }
+ }
+
+ // 1. Set POST_DIVIDER_HOLD_CHx (bit [12] in each PLL_CHANNEL_CTRL_CH_x
+ // register) // this will zero the output channels
+ for (addr = 0x1010003c; addr <= 0x10100050; addr += 4)
+ {
+ MOCA_SET(addr, (1 << 12));
+ }
+
+ //2. Program new PDIV/NDIV value, this will lose lock and
+ // trigger a new PLL lock process for a new VCO frequency
+ MOCA_WR(0x10100058, ((p_clock_data->pdiv << 10) | p_clock_data->ndiv));
+
+ //3. Wait >10 usec for lock time // max lock time per data sheet is 460/Fref,
+ // Or alternatively monitor CLKGEN_PLL_SYS*_PLL_LOCK_STATUS to check if PLL has locked
+ data = 0;
+ i = 0;
+ while ((data & 0x1) == 0)
+ {
+ /* This typically is only read once */
+ data = MOCA_RD(0x10100060); // CLKGEN_PLL_SYS1_PLL_LOCK_STATUS
+
+ if (i++ > 10)
+ {
+ printk("MoCA SYS1 PLL NOT LOCKED!\n");
+ break;
+ }
+ }
+
+ //4. Configure new MDIV value along with set POST_DIVIDER_LOAD_EN_CHx
+ // (bit [13]=1, while keep bit[12]=1) in each PLL_CHANNEL_CTRL_CH_x register
+ i = 0;
+ for (addr = 0x1010003c; addr <= 0x10100050; addr += 4)
+ {
+ data = MOCA_RD(addr);
+ data |= (1 << 13);
+ data &= ~(0xFF << 1);
+ data |= (p_clock_data->pll_mdivs[i] << 1);
+ MOCA_WR(addr, data);
+ i++;
+ }
+
+ //5. Clear bits [12] and bit [13] in each PLL_CHANNEL_CTRL_CH_x
+ for (addr = 0x1010003c; addr <= 0x10100050; addr += 4)
+ {
+ MOCA_UNSET(addr, ((1 << 13) | (1 << 12)));
+ }
+
+ }
+ }
+
+ return(ret);
}
diff --git a/bmoca.h b/bmoca.h
index 0c238f5..57eeb27 100644
--- a/bmoca.h
+++ b/bmoca.h
@@ -42,7 +42,7 @@
#define MOCA_BAND_NAMES { \
"highrf", "midrf", "wanrf", \
"ext_d", "d_low", "d_high", \
- "e", "f", "g", \
+ "e", "f", "g", "h"\
}
#define MOCA_BOOT_FLAGS_BONDED (1 << 0)