stmmac_pci.c 7.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*******************************************************************************
  This contains the functions to handle the pci driver.

  Copyright (C) 2011-2012  Vayavya Labs Pvt Ltd

  This program is free software; you can redistribute it and/or modify it
  under the terms and conditions of the GNU General Public License,
  version 2, as published by the Free Software Foundation.

  This program is distributed in the hope 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.

  The full GNU General Public License is included in this distribution in
  the file called "COPYING".

  Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
  Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
*******************************************************************************/

#include <linux/pci.h>
23 24
#include <linux/dmi.h>

25 26
#include "stmmac.h"

27 28 29 30 31 32 33 34 35 36 37 38
/*
 * This struct is used to associate PCI Function of MAC controller on a board,
 * discovered via DMI, with the address of PHY connected to the MAC. The
 * negative value of the address means that MAC controller is not connected
 * with PHY.
 */
struct stmmac_pci_dmi_data {
	const char *name;
	unsigned int func;
	int phy_addr;
};

39 40 41 42
struct stmmac_pci_info {
	struct pci_dev *pdev;
	int (*setup)(struct plat_stmmacenet_data *plat,
		     struct stmmac_pci_info *info);
43
	struct stmmac_pci_dmi_data *dmi;
44 45
};

46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
static int stmmac_pci_find_phy_addr(struct stmmac_pci_info *info)
{
	const char *name = dmi_get_system_info(DMI_BOARD_NAME);
	unsigned int func = PCI_FUNC(info->pdev->devfn);
	struct stmmac_pci_dmi_data *dmi;

	/*
	 * Galileo boards with old firmware don't support DMI. We always return
	 * 1 here, so at least first found MAC controller would be probed.
	 */
	if (!name)
		return 1;

	for (dmi = info->dmi; dmi->name && *dmi->name; dmi++) {
		if (!strcmp(dmi->name, name) && dmi->func == func)
			return dmi->phy_addr;
	}

	return -ENODEV;
}

67
static void stmmac_default_data(struct plat_stmmacenet_data *plat)
68
{
69 70 71 72 73 74
	plat->bus_id = 1;
	plat->phy_addr = 0;
	plat->interface = PHY_INTERFACE_MODE_GMII;
	plat->clk_csr = 2;	/* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
	plat->has_gmac = 1;
	plat->force_sf_dma_mode = 1;
75

76 77
	plat->mdio_bus_data->phy_reset = NULL;
	plat->mdio_bus_data->phy_mask = 0;
78

79
	plat->dma_cfg->pbl = 32;
80
	plat->dma_cfg->pblx8 = true;
81
	/* TODO: AXI */
82 83

	/* Set default value for multicast hash bins */
84
	plat->multicast_filter_bins = HASH_TABLE_SIZE;
85 86

	/* Set default value for unicast filter entries */
87
	plat->unicast_filter_entries = 1;
88 89 90

	/* Set the maxmtu to a default of JUMBO_LEN */
	plat->maxmtu = JUMBO_LEN;
91 92 93 94

	/* Set default number of RX and TX queues to use */
	plat->tx_queues_to_use = 1;
	plat->rx_queues_to_use = 1;
95 96
}

97 98 99 100
static int quark_default_data(struct plat_stmmacenet_data *plat,
			      struct stmmac_pci_info *info)
{
	struct pci_dev *pdev = info->pdev;
101 102 103 104 105 106 107 108 109
	int ret;

	/*
	 * Refuse to load the driver and register net device if MAC controller
	 * does not connect to any PHY interface.
	 */
	ret = stmmac_pci_find_phy_addr(info);
	if (ret < 0)
		return ret;
110 111

	plat->bus_id = PCI_DEVID(pdev->bus->number, pdev->devfn);
112
	plat->phy_addr = ret;
113 114 115 116 117 118 119 120 121
	plat->interface = PHY_INTERFACE_MODE_RMII;
	plat->clk_csr = 2;
	plat->has_gmac = 1;
	plat->force_sf_dma_mode = 1;

	plat->mdio_bus_data->phy_reset = NULL;
	plat->mdio_bus_data->phy_mask = 0;

	plat->dma_cfg->pbl = 16;
122
	plat->dma_cfg->pblx8 = true;
123
	plat->dma_cfg->fixed_burst = 1;
124
	/* AXI (TODO) */
125 126 127 128 129 130 131

	/* Set default value for multicast hash bins */
	plat->multicast_filter_bins = HASH_TABLE_SIZE;

	/* Set default value for unicast filter entries */
	plat->unicast_filter_entries = 1;

132 133 134
	/* Set the maxmtu to a default of JUMBO_LEN */
	plat->maxmtu = JUMBO_LEN;

135 136 137
	return 0;
}

138 139 140 141 142 143 144 145 146 147 148 149 150 151
static struct stmmac_pci_dmi_data quark_pci_dmi_data[] = {
	{
		.name = "Galileo",
		.func = 6,
		.phy_addr = 1,
	},
	{
		.name = "GalileoGen2",
		.func = 6,
		.phy_addr = 1,
	},
	{}
};

152 153
static struct stmmac_pci_info quark_pci_info = {
	.setup = quark_default_data,
154
	.dmi = quark_pci_dmi_data,
155 156
};

157 158 159 160 161 162 163 164 165 166 167 168
/**
 * stmmac_pci_probe
 *
 * @pdev: pci device pointer
 * @id: pointer to table of device id/id's.
 *
 * Description: This probing function gets called for all PCI devices which
 * match the ID table and are not "owned" by other driver yet. This function
 * gets passed a "struct pci_dev *" for each device whose entry in the ID table
 * matches the device. The probe functions returns zero when the driver choose
 * to take "ownership" of the device or an error code(-ve no) otherwise.
 */
B
Bill Pemberton 已提交
169
static int stmmac_pci_probe(struct pci_dev *pdev,
170
			    const struct pci_device_id *id)
171
{
172
	struct stmmac_pci_info *info = (struct stmmac_pci_info *)id->driver_data;
173
	struct plat_stmmacenet_data *plat;
174
	struct stmmac_resources res;
175
	int i;
176
	int ret;
177

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
	plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);
	if (!plat)
		return -ENOMEM;

	plat->mdio_bus_data = devm_kzalloc(&pdev->dev,
					   sizeof(*plat->mdio_bus_data),
					   GFP_KERNEL);
	if (!plat->mdio_bus_data)
		return -ENOMEM;

	plat->dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*plat->dma_cfg),
				     GFP_KERNEL);
	if (!plat->dma_cfg)
		return -ENOMEM;

193
	/* Enable pci device */
194
	ret = pcim_enable_device(pdev);
195
	if (ret) {
196 197
		dev_err(&pdev->dev, "%s: ERROR: failed to enable device\n",
			__func__);
198 199 200 201
		return ret;
	}

	/* Get the base address of device */
202
	for (i = 0; i <= PCI_STD_RESOURCE_END; i++) {
203 204
		if (pci_resource_len(pdev, i) == 0)
			continue;
205 206 207
		ret = pcim_iomap_regions(pdev, BIT(i), pci_name(pdev));
		if (ret)
			return ret;
208 209
		break;
	}
210

211 212
	pci_set_master(pdev);

213 214 215 216 217 218 219 220 221
	if (info) {
		info->pdev = pdev;
		if (info->setup) {
			ret = info->setup(plat, info);
			if (ret)
				return ret;
		}
	} else
		stmmac_default_data(plat);
222

223 224
	pci_enable_msi(pdev);

225 226 227 228 229
	memset(&res, 0, sizeof(res));
	res.addr = pcim_iomap_table(pdev)[i];
	res.wol_irq = pdev->irq;
	res.irq = pdev->irq;

230
	return stmmac_dvr_probe(&pdev->dev, plat, &res);
231 232 233
}

/**
234
 * stmmac_pci_remove
235 236 237 238 239
 *
 * @pdev: platform device pointer
 * Description: this function calls the main to free the net resources
 * and releases the PCI resources.
 */
B
Bill Pemberton 已提交
240
static void stmmac_pci_remove(struct pci_dev *pdev)
241
{
242
	stmmac_dvr_remove(&pdev->dev);
243 244
}

245
static SIMPLE_DEV_PM_OPS(stmmac_pm_ops, stmmac_suspend, stmmac_resume);
246

247
#define STMMAC_VENDOR_ID 0x700
248
#define STMMAC_QUARK_ID  0x0937
249 250
#define STMMAC_DEVICE_ID 0x1108

251
static const struct pci_device_id stmmac_id_table[] = {
252 253
	{PCI_DEVICE(STMMAC_VENDOR_ID, STMMAC_DEVICE_ID)},
	{PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_MAC)},
254
	{PCI_VDEVICE(INTEL, STMMAC_QUARK_ID), (kernel_ulong_t)&quark_pci_info},
255
	{}
256 257 258 259
};

MODULE_DEVICE_TABLE(pci, stmmac_id_table);

260
static struct pci_driver stmmac_pci_driver = {
261 262 263
	.name = STMMAC_RESOURCE_NAME,
	.id_table = stmmac_id_table,
	.probe = stmmac_pci_probe,
B
Bill Pemberton 已提交
264
	.remove = stmmac_pci_remove,
265 266 267
	.driver         = {
		.pm     = &stmmac_pm_ops,
	},
268 269
};

270 271
module_pci_driver(stmmac_pci_driver);

272 273 274 275
MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet PCI driver");
MODULE_AUTHOR("Rayagond Kokatanur <rayagond.kokatanur@vayavyalabs.com>");
MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
MODULE_LICENSE("GPL");