Merge "ipq40xx: Adding ethernet init sequence" into eggplant
diff --git a/arch/arm/include/asm/arch-qcom-common/gpio.h b/arch/arm/include/asm/arch-qcom-common/gpio.h
index e6820b7..d82131a 100644
--- a/arch/arm/include/asm/arch-qcom-common/gpio.h
+++ b/arch/arm/include/asm/arch-qcom-common/gpio.h
@@ -31,6 +31,8 @@
 #ifndef GPIO_H
 #define GPIO_H
 
+#define GPIO_OUT	(1 << 1)
+
 struct qca_gpio_config {
 	unsigned int gpio;
 	unsigned int func;
diff --git a/board/qca/common/Makefile b/board/qca/common/Makefile
index 7dafe61..6349717 100644
--- a/board/qca/common/Makefile
+++ b/board/qca/common/Makefile
@@ -2,4 +2,5 @@
 obj-y += fdt_info.o
 obj-y += board_init.o
 obj-y += env.o
-obj-y += fdt_fixup.o
\ No newline at end of file
+obj-y += fdt_fixup.o
+obj-y += ethaddr.o
diff --git a/board/qca/common/ethaddr.c b/board/qca/common/ethaddr.c
new file mode 100644
index 0000000..cc5208f
--- /dev/null
+++ b/board/qca/common/ethaddr.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2016 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#include <common.h>
+#include <asm/errno.h>
+#include <nand.h>
+#include <part.h>
+#include <mmc.h>
+#include <asm/arch-qcom-common/smem.h>
+#include "qca_common.h"
+
+#ifdef CONFIG_QCA_MMC
+extern qca_mmc mmc_host;
+#endif
+
+/*
+ * Gets the ethernet address from the ART partition table and return the value
+ */
+int get_eth_mac_address(uchar *enetaddr, uint no_of_macs)
+{
+	s32 ret = 0 ;
+	u32 start_blocks;
+	u32 size_blocks;
+	u32 length = (6 * no_of_macs);
+	u32 flash_type;
+	loff_t art_offset;
+	qca_smem_flash_info_t *sfi = &qca_smem_flash_info;
+#ifdef CONFIG_QCA_MMC
+	block_dev_desc_t *blk_dev;
+	disk_partition_t disk_info;
+	struct mmc *mmc;
+	char mmc_blks[512];
+#endif
+	if (sfi->flash_type != SMEM_BOOT_MMC_FLASH) {
+		if (qca_smem_flash_info.flash_type == SMEM_BOOT_SPI_FLASH)
+			flash_type = CONFIG_IPQ_SPI_NOR_INFO_IDX;
+		else if (qca_smem_flash_info.flash_type == SMEM_BOOT_NAND_FLASH)
+			flash_type = CONFIG_IPQ_NAND_NAND_INFO_IDX;
+		else {
+			printf("Unknown flash type\n");
+			return -EINVAL;
+		}
+
+		ret = smem_getpart("0:ART", &start_blocks, &size_blocks);
+		if (ret < 0) {
+			printf("No ART partition found\n");
+			return ret;
+		}
+
+		/*
+		 * ART partition 0th position will contain Mac address.
+		 */
+		art_offset =
+		((loff_t) qca_smem_flash_info.flash_block_size * start_blocks);
+
+		ret = nand_read(&nand_info[flash_type],
+				art_offset, &length, enetaddr);
+		if (ret < 0)
+			printf("ART partition read failed..\n");
+#ifdef CONFIG_QCA_MMC
+	} else {
+		blk_dev = mmc_get_dev(mmc_host.dev_num);
+		ret = get_partition_info_efi_by_name(blk_dev, "0:ART", &disk_info);
+		/*
+		 * ART partition 0th position will contain MAC address.
+		 * Read 1 block.
+		 */
+		if (ret == 0) {
+			mmc = mmc_host.mmc;
+			ret = mmc->block_dev.block_read
+				(mmc_host.dev_num, disk_info.start,
+						1, mmc_blks);
+			memcpy(enetaddr, mmc_blks, length);
+                }
+		if (ret < 0)
+			printf("ART partition read failed..\n");
+#endif
+	}
+	return ret;
+}
+
+void set_ethmac_addr(void)
+{
+	int i, ret;
+	uchar enetaddr[CONFIG_IPQ_NO_MACS * 6];
+	uchar *mac_addr;
+	char ethaddr[16] = "ethaddr";
+	char mac[64];
+	/* Get the MAC address from ART partition */
+	ret = get_eth_mac_address(enetaddr, CONFIG_IPQ_NO_MACS);
+	for (i = 0; (ret >= 0) && (i < CONFIG_IPQ_NO_MACS); i++) {
+		mac_addr = &enetaddr[i * 6];
+		if (!is_valid_ethaddr(mac_addr)) {
+			printf("eth%d MAC Address from ART is not valid\n", i);
+		} else {
+			/*
+			 * U-Boot uses these to patch the 'local-mac-address'
+			 * dts entry for the ethernet entries, which in turn
+			 * will be picked up by the HLOS driver
+			 */
+			sprintf(mac, "%x:%x:%x:%x:%x:%x",
+					mac_addr[0], mac_addr[1],
+					mac_addr[2], mac_addr[3],
+					mac_addr[4], mac_addr[5]);
+			setenv(ethaddr, mac);
+		}
+		sprintf(ethaddr, "eth%daddr", (i + 1));
+	}
+}
diff --git a/board/qca/common/qca_common.h b/board/qca/common/qca_common.h
index 6762fab..666a1e5 100644
--- a/board/qca/common/qca_common.h
+++ b/board/qca/common/qca_common.h
@@ -25,6 +25,9 @@
 int qca_mmc_init(bd_t *, qca_mmc *);
 void board_mmc_deinit(void);
 
+int get_eth_mac_address(uchar *enetaddr, uint no_of_macs);
+void set_ethmac_addr(void);
+
 #define MSM_SDC1_BASE		0x7824000
 #define MMC_IDENTIFY_MODE	0
 #define MMC_DATA_TRANSFER_MODE	1
diff --git a/board/qca/ipq40xx/Makefile b/board/qca/ipq40xx/Makefile
index 2ad7af3..76e1f5e 100644
--- a/board/qca/ipq40xx/Makefile
+++ b/board/qca/ipq40xx/Makefile
@@ -1,4 +1,4 @@
-ccflags-y += -I$(srctree)/board/qca/common/
+ccflags-y += -I$(srctree)/board/qca/common/ -I$(srctree)/drivers/net/ipq40xx/
 
 obj-y	:= ipq40xx.o
 obj-y	+= clock.o
diff --git a/board/qca/ipq40xx/ipq40xx.c b/board/qca/ipq40xx/ipq40xx.c
index 861a071..746c348 100644
--- a/board/qca/ipq40xx/ipq40xx.c
+++ b/board/qca/ipq40xx/ipq40xx.c
@@ -26,6 +26,10 @@
 #include <fdtdec.h>
 #include <asm/arch-qcom-common/uart.h>
 #include "fdt_info.h"
+#include <asm/arch-ipq40xx/ess/ipq40xx_edma.h>
+#include <phy.h>
+#include "ipq40xx_edma_eth.h"
+#include "qca_common.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -54,6 +58,12 @@
 extern int mmc_env_init(void);
 extern void mmc_env_relocate_spec(void);
 
+extern int ipq40xx_edma_init(ipq40xx_edma_board_cfg_t *edma_cfg);
+extern int ipq40xx_qca8075_phy_init(struct ipq40xx_eth_dev *cfg);
+extern int ipq40xx_qca8033_phy_init(struct ipq40xx_eth_dev *cfg);
+extern void ipq40xx_register_switch(
+	int (*sw_init)(struct ipq40xx_eth_dev *cfg));
+
 void qca_serial_init(struct ipq_serial_platdata *plat)
 {
 	int node;
@@ -129,9 +139,85 @@
 #endif
 }
 
+static void ipq40xx_edma_common_init(void)
+{
+	writel(1, GCC_ESS_BCR);
+	mdelay(10);
+	writel(0, GCC_ESS_BCR);
+	mdelay(100);
+
+	writel(1, GCC_MDIO_AHB_CBCR);
+	writel(MDIO_CTRL_0_DIV(0xff) |
+		MDIO_CTRL_0_MDC_MODE |
+		MDIO_CTRL_0_GPHY(0xa), MDIO_CTRL_0_REG);
+}
+
 int board_eth_init(bd_t *bis)
 {
-	return 0;
+	u32 status;
+	int gpio_node, node, len;
+	ipq40xx_edma_board_cfg_t* edma_cfg =
+		(ipq40xx_edma_board_cfg_t*)malloc(sizeof(ipq40xx_edma_board_cfg_t));
+
+	gpio_node = fdt_path_offset(gd->fdt_blob, "/ess-switch/sw_gpio");
+	if (gpio_node >= 0)
+		qca_gpio_init(gpio_node);
+
+	ipq40xx_edma_common_init();
+	switch (gd->bd->bi_arch_number) {
+	case MACH_TYPE_IPQ40XX_AP_DK01_1_S1:
+	case MACH_TYPE_IPQ40XX_AP_DK01_1_C2:
+		/* 8075 out of reset */
+		mdelay(100);
+		gpio_set_value(62, 1);
+		ipq40xx_register_switch(ipq40xx_qca8075_phy_init);
+		break;
+	case MACH_TYPE_IPQ40XX_AP_DK01_1_C1:
+		/* 8075 out of reset */
+		mdelay(100);
+		gpio_set_value(59, 1);
+		ipq40xx_register_switch(ipq40xx_qca8075_phy_init);
+		break;
+	case MACH_TYPE_IPQ40XX_AP_DK04_1_C4:
+	case MACH_TYPE_IPQ40XX_AP_DK04_1_C1:
+	case MACH_TYPE_IPQ40XX_AP_DK04_1_C3:
+		/* 8075 out of reset */
+		mdelay(100);
+		gpio_set_value(47, 1);
+		ipq40xx_register_switch(ipq40xx_qca8075_phy_init);
+		break;
+	case MACH_TYPE_IPQ40XX_AP_DK04_1_C2:
+		/* 8075 out of reset */
+		mdelay(100);
+		gpio_set_value(67, 1);
+		ipq40xx_register_switch(ipq40xx_qca8075_phy_init);
+		break;
+	case MACH_TYPE_IPQ40XX_AP_DK06_1_C1:
+		/* 8075 out of reset */
+		mdelay(100);
+		gpio_set_value(19, 1);
+		ipq40xx_register_switch(ipq40xx_qca8075_phy_init);
+		break;
+	case MACH_TYPE_IPQ40XX_AP_DK07_1_C1:
+		/* 8075 out of reset */
+		mdelay(100);
+		gpio_set_value(41, 1);
+		ipq40xx_register_switch(ipq40xx_qca8075_phy_init);
+		break;
+	default:
+		break;
+	}
+	node = fdt_path_offset(gd->fdt_blob, "/edma_cfg");
+	if (node < 0) {
+		printf("Error: edma_cfg not specified in dts");
+		return -1;
+	}
+	edma_cfg->unit = fdtdec_get_uint(gd->fdt_blob, node, "unit", 0);
+	edma_cfg->phy = fdtdec_get_uint(gd->fdt_blob, node, "phy", 0);
+	strcpy(edma_cfg->phy_name, fdt_getprop(gd->fdt_blob, node, "phy_name", &len));
+
+	status = ipq40xx_edma_init(edma_cfg);
+	return status;
 }
 
 #ifdef CONFIG_QCA_MMC
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 150470c..edca474 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -5,6 +5,8 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
+ccflags-y += -I$(srctree)/board/qca/ipq40xx -I$(srctree)/board/qca/common
+
 obj-$(CONFIG_PPC4xx_EMAC) += 4xx_enet.o
 obj-$(CONFIG_ALTERA_TSE) += altera_tse.o
 obj-$(CONFIG_ARMADA100_FEC) += armada100_fec.o
@@ -72,3 +74,8 @@
 obj-$(CONFIG_FSL_MC_ENET) += ldpaa_eth/
 obj-$(CONFIG_FSL_MEMAC) += fm/memac_phy.o
 obj-$(CONFIG_VSC9953) += vsc9953.o
+obj-$(CONFIG_IPQ40XX_EDMA) += ipq40xx/ipq40xx_edma_eth.o
+obj-$(CONFIG_IPQ40XX_ESS) += ipq40xx/ipq40xx_ess_sw.o
+obj-$(CONFIG_QCA8075_PHY) += ipq40xx/ipq40xx_qca8075.o
+obj-$(CONFIG_QCA8033_PHY) += ipq40xx/ipq40xx_qca8033.o
+obj-$(CONFIG_IPQ40XX_MDIO) += ipq40xx/ipq40xx_mdio.o
diff --git a/drivers/net/ipq40xx/ipq40xx_edma_eth.c b/drivers/net/ipq40xx/ipq40xx_edma_eth.c
index d4b1743..bc4049f 100755
--- a/drivers/net/ipq40xx/ipq40xx_edma_eth.c
+++ b/drivers/net/ipq40xx/ipq40xx_edma_eth.c
@@ -22,6 +22,7 @@
 #include <asm/arch-ipq40xx/ess/ipq40xx_edma.h>
 #include "ipq40xx_edma_eth.h"
 #include "ipq40xx.h"
+#include "qca_common.h"
 #ifdef DEBUG
 #define debugf(fmt, args...) printf(fmt, ##args);
 #else
@@ -832,8 +833,8 @@
 	memset(c_info, 0, (sizeof(c_info) * IPQ40XX_EDMA_DEV));
 	memset(enet_addr, 0, sizeof(enet_addr));
 	/* Getting the MAC address from ART partition */
-	 ret = -1;
-	/* ret = get_eth_mac_address(enet_addr, IPQ40XX_EDMA_DEV); */
+	ret = get_eth_mac_address(enet_addr, IPQ40XX_EDMA_DEV);
+
 	/*
 	 * Register EDMA as single ethernet
 	 * interface.
diff --git a/drivers/net/ipq40xx/ipq40xx_ess_sw.c b/drivers/net/ipq40xx/ipq40xx_ess_sw.c
index feea90d..95c9693 100644
--- a/drivers/net/ipq40xx/ipq40xx_ess_sw.c
+++ b/drivers/net/ipq40xx/ipq40xx_ess_sw.c
@@ -19,7 +19,8 @@
 #include "ipq40xx_ess_sw.h"
 #include "ipq40xx.h"
 
-extern board_ipq40xx_params_t *gboard_param;
+DECLARE_GLOBAL_DATA_PTR;
+
 static inline void ipq40xx_ess_sw_rd(u32 addr, u32 * data)
 {
 	*data = readl((void __iomem *)(IPQ40XX_NSS_BASE + addr));
@@ -65,7 +66,7 @@
 					S17_TX_FLOW_EN |
 					S17_RX_FLOW_EN);
 
-	switch(gboard_param->machid) {
+	switch(gd->bd->bi_arch_number) {
 	case MACH_TYPE_IPQ40XX_AP_DK01_1_S1:
 	case MACH_TYPE_IPQ40XX_AP_DK01_1_C1:
 	case MACH_TYPE_IPQ40XX_AP_DK01_1_C2:
@@ -132,7 +133,7 @@
 		break;
 	default:
 		printf("ess cfg not supported for %x machid\n",
-						gboard_param->machid);
+					gd->bd->bi_arch_number);
 		return -1;
 	}
 	mdelay(1);
diff --git a/include/configs/ipq40xx.h b/include/configs/ipq40xx.h
index 0a3b486..2dbb33b 100644
--- a/include/configs/ipq40xx.h
+++ b/include/configs/ipq40xx.h
@@ -191,6 +191,10 @@
 #define CONFIG_SF_DEFAULT_SPEED	(48 * 1000 * 1000)
 #define CONFIG_SPI_FLASH_BAR    1
 
+#define CONFIG_ENV_OVERWRITE
+#define CONFIG_CMD_PING
+#define CONFIG_CMD_DHCP
+#define CONFIG_IPQ40XX_ESS	1
 #define CONFIG_IPQ40XX_EDMA     1
 #define CONFIG_NET_RETRY_COUNT          5
 #define CONFIG_SYS_RX_ETH_BUFFER        16