diff mbox

[3/4] net: stmmac: add support for Intel Quark X1000

Message ID f90caab98bf8bcc975bb6ecea640668fdcd613d4.1409123378.git.hock.leong.kweh@intel.com
State Changes Requested, archived
Delegated to: David Miller
Headers show

Commit Message

Kweh Hock Leong Aug. 27, 2014, 10:32 a.m. UTC
From: "Kweh, Hock Leong" <hock.leong.kweh@intel.com>

The Intel Quark SoC X1000 provides two 10/100 Mbps Ethernet MAC
controllers which may or may not be connected to PHY on board.
This MAC controller only supports RMII PHY.

Besides adding Quark PCI ID to this driver, this patch introduces
run-time board detection through DMI and MAC-PHY configuration
function used by stmmac_default_data() during initialization.
It fills up the phy_address to -1 for Galileo and Galileo Gen2
boards to indicate that the 2nd Ethernet MAC controller is not
connected to any PHY.

The implementation takes into consideration for future expansion in
Quark series boards that may have different PHY address that is
linked to its MAC controllers.

This piece of work is derived from Bryan O'Donoghue's initial work for
Quark X1000 enabling.

Signed-off-by: Kweh, Hock Leong <hock.leong.kweh@intel.com>
Reviewed-by: Ong, Boon Leong <boon.leong.ong@intel.com>
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c |   86 ++++++++++++++++++++--
 1 file changed, 81 insertions(+), 5 deletions(-)
diff mbox

Patch

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
index 40290da..81e48f4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
@@ -24,16 +24,19 @@ 
 *******************************************************************************/
 
 #include <linux/pci.h>
+#include <linux/dmi.h>
 #include "stmmac.h"
 
 static int instance_id = 1;
+static void quark_run_time_config(int chip_id, struct pci_dev *pdev);
 
 enum chip {
 	CHIP_STMICRO = 0,
+	CHIP_QUARK_X1000,
 };
 
-/* A struct for platform specific information which will be
- * used in stmmac_default_data function for initialization
+/* A struct for platform specific information which is used
+ * in stmmac_default_data function for initialization
  */
 struct platform_data {
 	int phy_addr;
@@ -46,7 +49,9 @@  struct platform_data {
 	int (*phy_reset)(void *priv);
 	unsigned int phy_mask;
 	int pbl;
+	int fixed_burst;
 	int burst_len;
+	void (*rt_config)(int chip_id, struct pci_dev *pdev);
 };
 
 static struct platform_data platform_info[] = {
@@ -61,15 +66,76 @@  static struct platform_data platform_info[] = {
 		.phy_reset = NULL,
 		.phy_mask = 0,
 		.pbl = 32,
+		.fixed_burst = 0,
 		.burst_len = DMA_AXI_BLEN_256,
+		.rt_config = NULL,
 	},
+	[CHIP_QUARK_X1000] = {
+		.phy_addr = 1,
+		.interface = PHY_INTERFACE_MODE_RMII,
+		.clk_csr = 2,
+		.has_gmac = 1,
+		.force_sf_dma_mode = 1,
+		.multicast_filter_bins = HASH_TABLE_SIZE,
+		.unicast_filter_entries = 1,
+		.phy_reset = NULL,
+		.phy_mask = 0,
+		.pbl = 16,
+		.fixed_burst = 1,
+		.burst_len = DMA_AXI_BLEN_256,
+		.rt_config = &quark_run_time_config,
+	},
+};
+
+/* This struct is used to associate PCI Function ID of MAC controller
+ * on a board, discovered via DMI, with phy_address. It is also used
+ * to describe if that MAC controller is connected with PHY.
+ */
+struct intel_quark_platform {
+	int pci_func_num;
+	const char *board_name;
+	int phy_address;
 };
 
-static void stmmac_default_data(struct plat_stmmacenet_data *plat,
-				int chip_id)
+static struct intel_quark_platform quark_x1000_phy_info[] = {
+	{
+		.pci_func_num = 7,
+		.board_name = "Galileo",
+		/* Galileo ethernet port 2 does not connect to any PHY */
+		.phy_address = -1,
+	},
+	{
+		.pci_func_num = 7,
+		.board_name = "GalileoGen2",
+		/* Galileo Gen2 ethernet port 2 does not connect to any PHY */
+		.phy_address = -1,
+	},
+};
+
+static void quark_run_time_config(int chip_id, struct pci_dev *pdev)
+{
+	const char *board_name = dmi_get_system_info(DMI_BOARD_NAME);
+	int i;
+	int func_num = PCI_FUNC(pdev->devfn);
+
+	if (!board_name)
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(quark_x1000_phy_info); i++) {
+		if ((!strcmp(quark_x1000_phy_info[i].board_name, board_name)) &&
+		    quark_x1000_phy_info[i].pci_func_num == func_num)
+			platform_info[chip_id].phy_addr =
+				quark_x1000_phy_info[i].phy_address;
+	}
+}
+
+static int stmmac_default_data(struct plat_stmmacenet_data *plat,
+			       int chip_id, struct pci_dev *pdev)
 {
 	struct platform_data *chip_plat_dat = &platform_info[chip_id];
 
+	if (chip_plat_dat->rt_config)
+		chip_plat_dat->rt_config(chip_id, pdev);
 	plat->bus_id = instance_id++;
 	plat->phy_addr = chip_plat_dat->phy_addr;
 	plat->interface = chip_plat_dat->interface;
@@ -84,7 +150,13 @@  static void stmmac_default_data(struct plat_stmmacenet_data *plat,
 	plat->mdio_bus_data->phy_mask = chip_plat_dat->phy_mask;
 
 	plat->dma_cfg->pbl = chip_plat_dat->pbl;
+	plat->dma_cfg->fixed_burst = chip_plat_dat->fixed_burst;
 	plat->dma_cfg->burst_len = chip_plat_dat->burst_len;
+
+	/* Refuse to load the driver and register net device
+	 * if MAC controller does not connect to any PHY interface
+	 */
+	return (plat->phy_addr != -1) ? 0 : -ENODEV;
 }
 
 /**
@@ -158,7 +230,9 @@  static int stmmac_pci_probe(struct pci_dev *pdev,
 		goto err_out;
 	}
 
-	stmmac_default_data(plat_dat, id->driver_data);
+	ret = stmmac_default_data(plat_dat, id->driver_data, pdev);
+	if (ret)
+		goto err_out;
 
 	priv = stmmac_dvr_probe(&pdev->dev, plat_dat, addr);
 	if (IS_ERR(priv)) {
@@ -230,11 +304,13 @@  static int stmmac_pci_resume(struct pci_dev *pdev)
 
 #define STMMAC_VENDOR_ID 0x700
 #define STMMAC_DEVICE_ID 0x1108
+#define STMMAC_QUARK_X1000_ID 0x0937
 
 static const struct pci_device_id stmmac_id_table[] = {
 	{PCI_DEVICE(STMMAC_VENDOR_ID, STMMAC_DEVICE_ID), PCI_ANY_ID,
 			PCI_ANY_ID, CHIP_STMICRO},
 	{PCI_VDEVICE(STMICRO, PCI_DEVICE_ID_STMICRO_MAC), CHIP_STMICRO},
+	{PCI_VDEVICE(INTEL, STMMAC_QUARK_X1000_ID), CHIP_QUARK_X1000},
 	{}
 };