1 /*******************************************************************************
2 This contains the functions to handle the pci driver.
4 Copyright (C) 2011-2012 Vayavya Labs Pvt Ltd
6 This program is free software; you can redistribute it and/or modify it
7 under the terms and conditions of the GNU General Public License,
8 version 2, as published by the Free Software Foundation.
10 This program is distributed in the hope it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 The full GNU General Public License is included in this distribution in
16 the file called "COPYING".
18 Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
19 Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
20 *******************************************************************************/
22 #include <linux/pci.h>
23 #include <linux/dmi.h>
28 * This struct is used to associate PCI Function of MAC controller on a board,
29 * discovered via DMI, with the address of PHY connected to the MAC. The
30 * negative value of the address means that MAC controller is not connected
33 struct stmmac_pci_func_data
{
38 struct stmmac_pci_dmi_data
{
39 const struct stmmac_pci_func_data
*func
;
43 struct stmmac_pci_info
{
44 int (*setup
)(struct pci_dev
*pdev
, struct plat_stmmacenet_data
*plat
);
47 static int stmmac_pci_find_phy_addr(struct pci_dev
*pdev
,
48 const struct dmi_system_id
*dmi_list
)
50 const struct stmmac_pci_func_data
*func_data
;
51 const struct stmmac_pci_dmi_data
*dmi_data
;
52 const struct dmi_system_id
*dmi_id
;
53 int func
= PCI_FUNC(pdev
->devfn
);
56 dmi_id
= dmi_first_match(dmi_list
);
60 dmi_data
= dmi_id
->driver_data
;
61 func_data
= dmi_data
->func
;
63 for (n
= 0; n
< dmi_data
->nfuncs
; n
++, func_data
++)
64 if (func_data
->func
== func
)
65 return func_data
->phy_addr
;
70 static void common_default_data(struct plat_stmmacenet_data
*plat
)
72 plat
->clk_csr
= 2; /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
74 plat
->force_sf_dma_mode
= 1;
76 plat
->mdio_bus_data
->phy_reset
= NULL
;
77 plat
->mdio_bus_data
->phy_mask
= 0;
79 /* Set default value for multicast hash bins */
80 plat
->multicast_filter_bins
= HASH_TABLE_SIZE
;
82 /* Set default value for unicast filter entries */
83 plat
->unicast_filter_entries
= 1;
85 /* Set the maxmtu to a default of JUMBO_LEN */
86 plat
->maxmtu
= JUMBO_LEN
;
88 /* Set default number of RX and TX queues to use */
89 plat
->tx_queues_to_use
= 1;
90 plat
->rx_queues_to_use
= 1;
92 /* Disable Priority config by default */
93 plat
->tx_queues_cfg
[0].use_prio
= false;
94 plat
->rx_queues_cfg
[0].use_prio
= false;
96 /* Disable RX queues routing by default */
97 plat
->rx_queues_cfg
[0].pkt_route
= 0x0;
100 static int stmmac_default_data(struct pci_dev
*pdev
,
101 struct plat_stmmacenet_data
*plat
)
103 /* Set common default data first */
104 common_default_data(plat
);
108 plat
->interface
= PHY_INTERFACE_MODE_GMII
;
110 plat
->dma_cfg
->pbl
= 32;
111 plat
->dma_cfg
->pblx8
= true;
117 static const struct stmmac_pci_info stmmac_pci_info
= {
118 .setup
= stmmac_default_data
,
121 static const struct stmmac_pci_func_data galileo_stmmac_func_data
[] = {
128 static const struct stmmac_pci_dmi_data galileo_stmmac_dmi_data
= {
129 .func
= galileo_stmmac_func_data
,
130 .nfuncs
= ARRAY_SIZE(galileo_stmmac_func_data
),
133 static const struct stmmac_pci_func_data iot2040_stmmac_func_data
[] = {
144 static const struct stmmac_pci_dmi_data iot2040_stmmac_dmi_data
= {
145 .func
= iot2040_stmmac_func_data
,
146 .nfuncs
= ARRAY_SIZE(iot2040_stmmac_func_data
),
149 static const struct dmi_system_id quark_pci_dmi
[] = {
152 DMI_EXACT_MATCH(DMI_BOARD_NAME
, "Galileo"),
154 .driver_data
= (void *)&galileo_stmmac_dmi_data
,
158 DMI_EXACT_MATCH(DMI_BOARD_NAME
, "GalileoGen2"),
160 .driver_data
= (void *)&galileo_stmmac_dmi_data
,
164 DMI_EXACT_MATCH(DMI_BOARD_NAME
, "SIMATIC IOT2000"),
165 DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG
,
166 "6ES7647-0AA00-0YA2"),
168 .driver_data
= (void *)&galileo_stmmac_dmi_data
,
172 DMI_EXACT_MATCH(DMI_BOARD_NAME
, "SIMATIC IOT2000"),
173 DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG
,
174 "6ES7647-0AA00-1YA2"),
176 .driver_data
= (void *)&iot2040_stmmac_dmi_data
,
181 static int quark_default_data(struct pci_dev
*pdev
,
182 struct plat_stmmacenet_data
*plat
)
186 /* Set common default data first */
187 common_default_data(plat
);
190 * Refuse to load the driver and register net device if MAC controller
191 * does not connect to any PHY interface.
193 ret
= stmmac_pci_find_phy_addr(pdev
, quark_pci_dmi
);
195 /* Return error to the caller on DMI enabled boards. */
196 if (dmi_get_system_info(DMI_BOARD_NAME
))
200 * Galileo boards with old firmware don't support DMI. We always
201 * use 1 here as PHY address, so at least the first found MAC
202 * controller would be probed.
207 plat
->bus_id
= PCI_DEVID(pdev
->bus
->number
, pdev
->devfn
);
208 plat
->phy_addr
= ret
;
209 plat
->interface
= PHY_INTERFACE_MODE_RMII
;
211 plat
->dma_cfg
->pbl
= 16;
212 plat
->dma_cfg
->pblx8
= true;
213 plat
->dma_cfg
->fixed_burst
= 1;
219 static const struct stmmac_pci_info quark_pci_info
= {
220 .setup
= quark_default_data
,
226 * @pdev: pci device pointer
227 * @id: pointer to table of device id/id's.
229 * Description: This probing function gets called for all PCI devices which
230 * match the ID table and are not "owned" by other driver yet. This function
231 * gets passed a "struct pci_dev *" for each device whose entry in the ID table
232 * matches the device. The probe functions returns zero when the driver choose
233 * to take "ownership" of the device or an error code(-ve no) otherwise.
235 static int stmmac_pci_probe(struct pci_dev
*pdev
,
236 const struct pci_device_id
*id
)
238 struct stmmac_pci_info
*info
= (struct stmmac_pci_info
*)id
->driver_data
;
239 struct plat_stmmacenet_data
*plat
;
240 struct stmmac_resources res
;
244 plat
= devm_kzalloc(&pdev
->dev
, sizeof(*plat
), GFP_KERNEL
);
248 plat
->mdio_bus_data
= devm_kzalloc(&pdev
->dev
,
249 sizeof(*plat
->mdio_bus_data
),
251 if (!plat
->mdio_bus_data
)
254 plat
->dma_cfg
= devm_kzalloc(&pdev
->dev
, sizeof(*plat
->dma_cfg
),
259 /* Enable pci device */
260 ret
= pcim_enable_device(pdev
);
262 dev_err(&pdev
->dev
, "%s: ERROR: failed to enable device\n",
267 /* Get the base address of device */
268 for (i
= 0; i
<= PCI_STD_RESOURCE_END
; i
++) {
269 if (pci_resource_len(pdev
, i
) == 0)
271 ret
= pcim_iomap_regions(pdev
, BIT(i
), pci_name(pdev
));
277 pci_set_master(pdev
);
279 ret
= info
->setup(pdev
, plat
);
283 pci_enable_msi(pdev
);
285 memset(&res
, 0, sizeof(res
));
286 res
.addr
= pcim_iomap_table(pdev
)[i
];
287 res
.wol_irq
= pdev
->irq
;
290 return stmmac_dvr_probe(&pdev
->dev
, plat
, &res
);
296 * @pdev: platform device pointer
297 * Description: this function calls the main to free the net resources
298 * and releases the PCI resources.
300 static void stmmac_pci_remove(struct pci_dev
*pdev
)
302 stmmac_dvr_remove(&pdev
->dev
);
305 static SIMPLE_DEV_PM_OPS(stmmac_pm_ops
, stmmac_suspend
, stmmac_resume
);
307 /* synthetic ID, no official vendor */
308 #define PCI_VENDOR_ID_STMMAC 0x700
310 #define STMMAC_QUARK_ID 0x0937
311 #define STMMAC_DEVICE_ID 0x1108
313 #define STMMAC_DEVICE(vendor_id, dev_id, info) { \
314 PCI_VDEVICE(vendor_id, dev_id), \
315 .driver_data = (kernel_ulong_t)&info \
318 static const struct pci_device_id stmmac_id_table
[] = {
319 STMMAC_DEVICE(STMMAC
, STMMAC_DEVICE_ID
, stmmac_pci_info
),
320 STMMAC_DEVICE(STMICRO
, PCI_DEVICE_ID_STMICRO_MAC
, stmmac_pci_info
),
321 STMMAC_DEVICE(INTEL
, STMMAC_QUARK_ID
, quark_pci_info
),
325 MODULE_DEVICE_TABLE(pci
, stmmac_id_table
);
327 static struct pci_driver stmmac_pci_driver
= {
328 .name
= STMMAC_RESOURCE_NAME
,
329 .id_table
= stmmac_id_table
,
330 .probe
= stmmac_pci_probe
,
331 .remove
= stmmac_pci_remove
,
333 .pm
= &stmmac_pm_ops
,
337 module_pci_driver(stmmac_pci_driver
);
339 MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet PCI driver");
340 MODULE_AUTHOR("Rayagond Kokatanur <rayagond.kokatanur@vayavyalabs.com>");
341 MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
342 MODULE_LICENSE("GPL");