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)