1aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch/*
2aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch * Sonics Silicon Backplane
3aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch * Broadcom Gigabit Ethernet core driver
4aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch *
5aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch * Copyright 2008, Broadcom Corporation
6eb032b9837a958e21ca000358a5bde5e17192ddbMichael Buesch * Copyright 2008, Michael Buesch <m@bues.ch>
7aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch *
8aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch * Licensed under the GNU/GPL. See COPYING for details.
9aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch */
10aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
11aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch#include <linux/ssb/ssb.h>
12aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch#include <linux/ssb/ssb_driver_gige.h>
131014c22e42a6692660d1a77888d07f4811b2914dPaul Gortmaker#include <linux/export.h>
14aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch#include <linux/pci.h>
15aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch#include <linux/pci_regs.h>
165a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
17aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
18aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
19aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch/*
20aab547ce0d1493d400b6468c521a0137cd8c1edfMichael BueschMODULE_DESCRIPTION("SSB Broadcom Gigabit Ethernet driver");
21aab547ce0d1493d400b6468c521a0137cd8c1edfMichael BueschMODULE_AUTHOR("Michael Buesch");
22aab547ce0d1493d400b6468c521a0137cd8c1edfMichael BueschMODULE_LICENSE("GPL");
23aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch*/
24aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
25aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic const struct ssb_device_id ssb_gige_tbl[] = {
26aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_ETHERNET_GBIT, SSB_ANY_REV),
27aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	SSB_DEVTABLE_END
28aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch};
29aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch/* MODULE_DEVICE_TABLE(ssb, ssb_gige_tbl); */
30aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
31aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
32aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic inline u8 gige_read8(struct ssb_gige *dev, u16 offset)
33aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
34aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return ssb_read8(dev->dev, offset);
35aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
36aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
37aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic inline u16 gige_read16(struct ssb_gige *dev, u16 offset)
38aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
39aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return ssb_read16(dev->dev, offset);
40aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
41aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
42aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic inline u32 gige_read32(struct ssb_gige *dev, u16 offset)
43aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
44aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return ssb_read32(dev->dev, offset);
45aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
46aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
47aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic inline void gige_write8(struct ssb_gige *dev,
48aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch			       u16 offset, u8 value)
49aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
50aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	ssb_write8(dev->dev, offset, value);
51aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
52aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
53aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic inline void gige_write16(struct ssb_gige *dev,
54aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch				u16 offset, u16 value)
55aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
56aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	ssb_write16(dev->dev, offset, value);
57aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
58aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
59aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic inline void gige_write32(struct ssb_gige *dev,
60aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch				u16 offset, u32 value)
61aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
62aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	ssb_write32(dev->dev, offset, value);
63aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
64aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
65aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic inline
66aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschu8 gige_pcicfg_read8(struct ssb_gige *dev, unsigned int offset)
67aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
68aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	BUG_ON(offset >= 256);
69aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return gige_read8(dev, SSB_GIGE_PCICFG + offset);
70aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
71aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
72aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic inline
73aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschu16 gige_pcicfg_read16(struct ssb_gige *dev, unsigned int offset)
74aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
75aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	BUG_ON(offset >= 256);
76aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return gige_read16(dev, SSB_GIGE_PCICFG + offset);
77aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
78aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
79aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic inline
80aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschu32 gige_pcicfg_read32(struct ssb_gige *dev, unsigned int offset)
81aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
82aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	BUG_ON(offset >= 256);
83aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return gige_read32(dev, SSB_GIGE_PCICFG + offset);
84aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
85aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
86aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic inline
87aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschvoid gige_pcicfg_write8(struct ssb_gige *dev,
88aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch			unsigned int offset, u8 value)
89aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
90aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	BUG_ON(offset >= 256);
91aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	gige_write8(dev, SSB_GIGE_PCICFG + offset, value);
92aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
93aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
94aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic inline
95aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschvoid gige_pcicfg_write16(struct ssb_gige *dev,
96aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch			 unsigned int offset, u16 value)
97aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
98aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	BUG_ON(offset >= 256);
99aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	gige_write16(dev, SSB_GIGE_PCICFG + offset, value);
100aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
101aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
102aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic inline
103aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschvoid gige_pcicfg_write32(struct ssb_gige *dev,
104aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch			 unsigned int offset, u32 value)
105aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
106aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	BUG_ON(offset >= 256);
107aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	gige_write32(dev, SSB_GIGE_PCICFG + offset, value);
108aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
109aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
110cd15598707aff52da4302d9b6a3fc878bca27383Hauke Mehrtensstatic int __devinit ssb_gige_pci_read_config(struct pci_bus *bus,
111cd15598707aff52da4302d9b6a3fc878bca27383Hauke Mehrtens					      unsigned int devfn, int reg,
112cd15598707aff52da4302d9b6a3fc878bca27383Hauke Mehrtens					      int size, u32 *val)
113aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
114aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	struct ssb_gige *dev = container_of(bus->ops, struct ssb_gige, pci_ops);
115aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	unsigned long flags;
116aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
117aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	if ((PCI_SLOT(devfn) > 0) || (PCI_FUNC(devfn) > 0))
118aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		return PCIBIOS_DEVICE_NOT_FOUND;
119aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	if (reg >= 256)
120aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		return PCIBIOS_DEVICE_NOT_FOUND;
121aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
122aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	spin_lock_irqsave(&dev->lock, flags);
123aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	switch (size) {
124aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	case 1:
125aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		*val = gige_pcicfg_read8(dev, reg);
126aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		break;
127aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	case 2:
128aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		*val = gige_pcicfg_read16(dev, reg);
129aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		break;
130aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	case 4:
131aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		*val = gige_pcicfg_read32(dev, reg);
132aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		break;
133aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	default:
134aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		WARN_ON(1);
135aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	}
136aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	spin_unlock_irqrestore(&dev->lock, flags);
137aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
138aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return PCIBIOS_SUCCESSFUL;
139aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
140aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
141cd15598707aff52da4302d9b6a3fc878bca27383Hauke Mehrtensstatic int __devinit ssb_gige_pci_write_config(struct pci_bus *bus,
142cd15598707aff52da4302d9b6a3fc878bca27383Hauke Mehrtens					       unsigned int devfn, int reg,
143cd15598707aff52da4302d9b6a3fc878bca27383Hauke Mehrtens					       int size, u32 val)
144aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
145aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	struct ssb_gige *dev = container_of(bus->ops, struct ssb_gige, pci_ops);
146aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	unsigned long flags;
147aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
148aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	if ((PCI_SLOT(devfn) > 0) || (PCI_FUNC(devfn) > 0))
149aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		return PCIBIOS_DEVICE_NOT_FOUND;
150aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	if (reg >= 256)
151aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		return PCIBIOS_DEVICE_NOT_FOUND;
152aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
153aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	spin_lock_irqsave(&dev->lock, flags);
154aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	switch (size) {
155aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	case 1:
156aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		gige_pcicfg_write8(dev, reg, val);
157aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		break;
158aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	case 2:
159aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		gige_pcicfg_write16(dev, reg, val);
160aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		break;
161aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	case 4:
162aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		gige_pcicfg_write32(dev, reg, val);
163aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		break;
164aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	default:
165aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		WARN_ON(1);
166aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	}
167aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	spin_unlock_irqrestore(&dev->lock, flags);
168aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
169aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return PCIBIOS_SUCCESSFUL;
170aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
171aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
172cd15598707aff52da4302d9b6a3fc878bca27383Hauke Mehrtensstatic int __devinit ssb_gige_probe(struct ssb_device *sdev,
173cd15598707aff52da4302d9b6a3fc878bca27383Hauke Mehrtens				    const struct ssb_device_id *id)
174aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
175aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	struct ssb_gige *dev;
176aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	u32 base, tmslow, tmshigh;
177aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
178aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
179aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	if (!dev)
180aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		return -ENOMEM;
181aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->dev = sdev;
182aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
183aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	spin_lock_init(&dev->lock);
184aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->pci_controller.pci_ops = &dev->pci_ops;
185aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->pci_controller.io_resource = &dev->io_resource;
186aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->pci_controller.mem_resource = &dev->mem_resource;
187aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->pci_controller.io_map_base = 0x800;
188aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->pci_ops.read = ssb_gige_pci_read_config;
189aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->pci_ops.write = ssb_gige_pci_write_config;
190aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
191aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->io_resource.name = SSB_GIGE_IO_RES_NAME;
192aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->io_resource.start = 0x800;
193aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->io_resource.end = 0x8FF;
194aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->io_resource.flags = IORESOURCE_IO | IORESOURCE_PCI_FIXED;
195aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
196aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	if (!ssb_device_is_enabled(sdev))
197aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		ssb_device_enable(sdev, 0);
198aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
199aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	/* Setup BAR0. This is a 64k MMIO region. */
200aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	base = ssb_admatch_base(ssb_read32(sdev, SSB_ADMATCH1));
201aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	gige_pcicfg_write32(dev, PCI_BASE_ADDRESS_0, base);
202aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	gige_pcicfg_write32(dev, PCI_BASE_ADDRESS_1, 0);
203aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
204aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->mem_resource.name = SSB_GIGE_MEM_RES_NAME;
205aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->mem_resource.start = base;
206aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->mem_resource.end = base + 0x10000 - 1;
207aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->mem_resource.flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED;
208aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
209aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	/* Enable the memory region. */
210aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	gige_pcicfg_write16(dev, PCI_COMMAND,
211aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch			    gige_pcicfg_read16(dev, PCI_COMMAND)
212aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch			    | PCI_COMMAND_MEMORY);
213aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
214aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	/* Write flushing is controlled by the Flush Status Control register.
215aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	 * We want to flush every register write with a timeout and we want
216aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	 * to disable the IRQ mask while flushing to avoid concurrency.
217aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	 * Note that automatic write flushing does _not_ work from
218aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	 * an IRQ handler. The driver must flush manually by reading a register.
219aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	 */
220aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	gige_write32(dev, SSB_GIGE_SHIM_FLUSHSTAT, 0x00000068);
221aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
222aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	/* Check if we have an RGMII or GMII PHY-bus.
223aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	 * On RGMII do not bypass the DLLs */
224aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	tmslow = ssb_read32(sdev, SSB_TMSLOW);
225aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	tmshigh = ssb_read32(sdev, SSB_TMSHIGH);
226aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	if (tmshigh & SSB_GIGE_TMSHIGH_RGMII) {
227aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		tmslow &= ~SSB_GIGE_TMSLOW_TXBYPASS;
228aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		tmslow &= ~SSB_GIGE_TMSLOW_RXBYPASS;
229aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		dev->has_rgmii = 1;
230aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	} else {
231aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		tmslow |= SSB_GIGE_TMSLOW_TXBYPASS;
232aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		tmslow |= SSB_GIGE_TMSLOW_RXBYPASS;
233aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		dev->has_rgmii = 0;
234aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	}
235aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	tmslow |= SSB_GIGE_TMSLOW_DLLEN;
236aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	ssb_write32(sdev, SSB_TMSLOW, tmslow);
237aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
238aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	ssb_set_drvdata(sdev, dev);
239aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	register_pci_controller(&dev->pci_controller);
240aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
241aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return 0;
242aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
243aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
244aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschbool pdev_is_ssb_gige_core(struct pci_dev *pdev)
245aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
246aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	if (!pdev->resource[0].name)
247aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		return 0;
248aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return (strcmp(pdev->resource[0].name, SSB_GIGE_MEM_RES_NAME) == 0);
249aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
250aab547ce0d1493d400b6468c521a0137cd8c1edfMichael BueschEXPORT_SYMBOL(pdev_is_ssb_gige_core);
251aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
252aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschint ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev,
253aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch				   struct pci_dev *pdev)
254aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
255aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	struct ssb_gige *dev = ssb_get_drvdata(sdev);
256aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	struct resource *res;
257aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
258aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	if (pdev->bus->ops != &dev->pci_ops) {
259aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		/* The PCI device is not on this SSB GigE bridge device. */
260aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		return -ENODEV;
261aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	}
262aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
263aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	/* Fixup the PCI resources. */
264aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	res = &(pdev->resource[0]);
265aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	res->flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED;
266aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	res->name = dev->mem_resource.name;
267aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	res->start = dev->mem_resource.start;
268aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	res->end = dev->mem_resource.end;
269aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
270aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	/* Fixup interrupt lines. */
271aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	pdev->irq = ssb_mips_irq(sdev) + 2;
272aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, pdev->irq);
273aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
274aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return 0;
275aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
276aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
277aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschint ssb_gige_map_irq(struct ssb_device *sdev,
278aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		     const struct pci_dev *pdev)
279aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
280aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	struct ssb_gige *dev = ssb_get_drvdata(sdev);
281aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
282aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	if (pdev->bus->ops != &dev->pci_ops) {
283aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		/* The PCI device is not on this SSB GigE bridge device. */
284aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		return -ENODEV;
285aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	}
286aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
287aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return ssb_mips_irq(sdev) + 2;
288aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
289aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
290aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic struct ssb_driver ssb_gige_driver = {
291aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	.name		= "BCM-GigE",
292aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	.id_table	= ssb_gige_tbl,
293aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	.probe		= ssb_gige_probe,
294aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch};
295aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
296aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschint ssb_gige_init(void)
297aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
298aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return ssb_driver_register(&ssb_gige_driver);
299aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
300