summaryrefslogtreecommitdiff
path: root/target/linux/brcm47xx/patches-3.2/700-ssb-gigabit-ethernet-driver.patch
blob: d07511ceae820251ff3670ce567317bd4d90f1ee (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -44,6 +44,7 @@
 #include <linux/prefetch.h>
 #include <linux/dma-mapping.h>
 #include <linux/firmware.h>
+#include <linux/ssb/ssb_driver_gige.h>
 
 #include <net/checksum.h>
 #include <net/ip.h>
@@ -530,7 +531,8 @@ static void _tw32_flush(struct tg3 *tp,
 static inline void tw32_mailbox_flush(struct tg3 *tp, u32 off, u32 val)
 {
 	tp->write32_mbox(tp, off, val);
-	if (!tg3_flag(tp, MBOX_WRITE_REORDER) && !tg3_flag(tp, ICH_WORKAROUND))
+	if (tg3_flag(tp, FLUSH_POSTED_WRITES) ||
+	    (!tg3_flag(tp, MBOX_WRITE_REORDER) && !tg3_flag(tp, ICH_WORKAROUND)))
 		tp->read32_mbox(tp, off);
 }
 
@@ -540,7 +542,7 @@ static void tg3_write32_tx_mbox(struct t
 	writel(val, mbox);
 	if (tg3_flag(tp, TXD_MBOX_HWBUG))
 		writel(val, mbox);
-	if (tg3_flag(tp, MBOX_WRITE_REORDER))
+	if (tg3_flag(tp, MBOX_WRITE_REORDER) || tg3_flag(tp, FLUSH_POSTED_WRITES))
 		readl(mbox);
 }
 
@@ -943,7 +945,7 @@ static void tg3_switch_clocks(struct tg3
 
 #define PHY_BUSY_LOOPS	5000
 
-static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
+static int __tg3_readphy(struct tg3 *tp, unsigned int phy_addr, int reg, u32 *val)
 {
 	u32 frame_val;
 	unsigned int loops;
@@ -957,7 +959,7 @@ static int tg3_readphy(struct tg3 *tp, i
 
 	*val = 0x0;
 
-	frame_val  = ((tp->phy_addr << MI_COM_PHY_ADDR_SHIFT) &
+	frame_val  = ((phy_addr << MI_COM_PHY_ADDR_SHIFT) &
 		      MI_COM_PHY_ADDR_MASK);
 	frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
 		      MI_COM_REG_ADDR_MASK);
@@ -992,7 +994,12 @@ static int tg3_readphy(struct tg3 *tp, i
 	return ret;
 }
 
-static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
+static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
+{
+	return __tg3_readphy(tp, tp->phy_addr, reg, val);
+}
+
+static int __tg3_writephy(struct tg3 *tp, unsigned int phy_addr, int reg, u32 val)
 {
 	u32 frame_val;
 	unsigned int loops;
@@ -1008,7 +1015,7 @@ static int tg3_writephy(struct tg3 *tp,
 		udelay(80);
 	}
 
-	frame_val  = ((tp->phy_addr << MI_COM_PHY_ADDR_SHIFT) &
+	frame_val  = ((phy_addr << MI_COM_PHY_ADDR_SHIFT) &
 		      MI_COM_PHY_ADDR_MASK);
 	frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
 		      MI_COM_REG_ADDR_MASK);
@@ -1041,6 +1048,11 @@ static int tg3_writephy(struct tg3 *tp,
 	return ret;
 }
 
+static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
+{
+	return __tg3_writephy(tp, tp->phy_addr, reg, val);
+}
+
 static int tg3_phy_cl45_write(struct tg3 *tp, u32 devad, u32 addr, u32 val)
 {
 	int err;
@@ -2965,6 +2977,9 @@ static int tg3_nvram_read(struct tg3 *tp
 {
 	int ret;
 
+	if (tg3_flag(tp, IS_SSB_CORE))
+		return -ENODEV;
+
 	if (!tg3_flag(tp, NVRAM))
 		return tg3_nvram_read_using_eeprom(tp, offset, val);
 
@@ -3047,9 +3062,12 @@ static int tg3_halt_cpu(struct tg3 *tp,
 		return -ENODEV;
 	}
 
-	/* Clear firmware's nvram arbitration. */
-	if (tg3_flag(tp, NVRAM))
-		tw32(NVRAM_SWARB, SWARB_REQ_CLR0);
+	if (!tg3_flag(tp, IS_SSB_CORE)) {
+		/* Clear firmware's nvram arbitration. */
+		if (tg3_flag(tp, NVRAM))
+			tw32(NVRAM_SWARB, SWARB_REQ_CLR0);
+	}
+
 	return 0;
 }
 
@@ -3168,6 +3186,11 @@ static int tg3_load_tso_firmware(struct
 	unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size;
 	int err, i;
 
+	if (tg3_flag(tp, IS_SSB_CORE)) {
+		/* We don't use firmware. */
+		return 0;
+	}
+
 	if (tg3_flag(tp, HW_TSO_1) ||
 	    tg3_flag(tp, HW_TSO_2) ||
 	    tg3_flag(tp, HW_TSO_3))
@@ -3514,8 +3537,10 @@ static int tg3_power_down_prepare(struct
 	tg3_frob_aux_power(tp, true);
 
 	/* Workaround for unstable PLL clock */
-	if ((GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX) ||
-	    (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_BX)) {
+	if ((tp->phy_id & TG3_PHY_ID_MASK) != TG3_PHY_ID_BCM5750_2 &&
+				/* !!! FIXME !!! */
+	    ((GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX) ||
+	    (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_BX))) {
 		u32 val = tr32(0x7d00);
 
 		val &= ~((1 << 16) | (1 << 4) | (1 << 2) | (1 << 1) | 1);
@@ -4043,6 +4068,14 @@ relink:
 	if (current_link_up == 0 || (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) {
 		tg3_phy_copper_begin(tp);
 
+		if (tg3_flag(tp, ROBOSWITCH)) {
+			current_link_up = 1;
+			current_speed = SPEED_1000; /* FIXME */
+			current_duplex = DUPLEX_FULL;
+			tp->link_config.active_speed = current_speed;
+			tp->link_config.active_duplex = current_duplex;
+		}
+
 		tg3_readphy(tp, MII_BMSR, &bmsr);
 		if ((!tg3_readphy(tp, MII_BMSR, &bmsr) && (bmsr & BMSR_LSTATUS)) ||
 		    (tp->mac_mode & MAC_MODE_PORT_INT_LPBACK))
@@ -7749,6 +7782,11 @@ static int tg3_chip_reset(struct tg3 *tp
 		}
 	}
 
+	if (tg3_flag(tp, IS_SSB_CORE)) {
+		/* We don't use firmware. */
+		return 0;
+	}
+
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
 		tw32(VCPU_STATUS, tr32(VCPU_STATUS) | VCPU_STATUS_DRV_RESET);
 		tw32(GRC_VCPU_EXT_CTRL,
@@ -7847,6 +7885,14 @@ static int tg3_chip_reset(struct tg3 *tp
 		tw32(0x5000, 0x400);
 	}
 
+	if (tg3_flag(tp, IS_SSB_CORE)) {
+		/* BCM4785: In order to avoid repercussions from using potentially
+		 * defective internal ROM, stop the Rx RISC CPU, which is not
+		 * required. */
+		tg3_stop_fw(tp);
+		tg3_halt_cpu(tp, RX_CPU_BASE);
+	}
+
 	tw32(GRC_MODE, tp->grc_mode);
 
 	if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0) {
@@ -9222,6 +9268,11 @@ static void tg3_timer(unsigned long __op
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
 		tg3_chk_missed_msi(tp);
 
+	if (tg3_flag(tp, FLUSH_POSTED_WRITES)) {
+		/* BCM4785: Flush posted writes from GbE to host memory. */
+		tr32(HOSTCC_MODE);
+	}
+
 	if (!tg3_flag(tp, TAGGED_STATUS)) {
 		/* All of this garbage is because when using non-tagged
 		 * IRQ status the mailbox/status_block protocol the chip
@@ -9511,6 +9562,11 @@ static int tg3_request_firmware(struct t
 		return -ENOENT;
 	}
 
+	if (tg3_flag(tp, IS_SSB_CORE)) {
+		/* We don't use firmware. */
+		return 0;
+	}
+
 	fw_data = (void *)tp->fw->data;
 
 	/* Firmware blob starts with version numbers, followed by
@@ -10869,6 +10925,11 @@ static int tg3_test_nvram(struct tg3 *tp
 	if (tg3_flag(tp, NO_NVRAM))
 		return 0;
 
+	if (tg3_flag(tp, IS_SSB_CORE)) {
+		/* We don't have NVRAM. */
+		return 0;
+	}
+
 	if (tg3_nvram_read(tp, 0, &magic) != 0)
 		return -EIO;
 
@@ -11829,7 +11890,7 @@ static int tg3_ioctl(struct net_device *
 			return -EAGAIN;
 
 		spin_lock_bh(&tp->lock);
-		err = tg3_readphy(tp, data->reg_num & 0x1f, &mii_regval);
+		err = __tg3_readphy(tp, data->phy_id & 0x1f, data->reg_num & 0x1f, &mii_regval);
 		spin_unlock_bh(&tp->lock);
 
 		data->val_out = mii_regval;
@@ -11845,7 +11906,7 @@ static int tg3_ioctl(struct net_device *
 			return -EAGAIN;
 
 		spin_lock_bh(&tp->lock);
-		err = tg3_writephy(tp, data->reg_num & 0x1f, data->val_in);
+		err = __tg3_writephy(tp, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
 		spin_unlock_bh(&tp->lock);
 
 		return err;
@@ -12575,6 +12636,13 @@ static void __devinit tg3_get_5720_nvram
 /* Chips other than 5700/5701 use the NVRAM for fetching info. */
 static void __devinit tg3_nvram_init(struct tg3 *tp)
 {
+	if (tg3_flag(tp, IS_SSB_CORE)) {
+		/* No NVRAM and EEPROM on the SSB Broadcom GigE core. */
+		tg3_flag_clear(tp, NVRAM);
+		tg3_flag_clear(tp, NVRAM_BUFFERED);
+		return;
+	}
+
 	tw32_f(GRC_EEPROM_ADDR,
 	     (EEPROM_ADDR_FSM_RESET |
 	      (EEPROM_DEFAULT_CLOCK_PERIOD <<
@@ -12841,6 +12909,9 @@ static int tg3_nvram_write_block(struct
 {
 	int ret;
 
+	if (tg3_flag(tp, IS_SSB_CORE))
+		return -ENODEV;
+
 	if (tg3_flag(tp, EEPROM_WRITE_PROT)) {
 		tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl &
 		       ~GRC_LCLCTRL_GPIO_OUTPUT1);
@@ -14265,6 +14336,11 @@ static int __devinit tg3_get_invariants(
 		}
 	}
 
+	if (tg3_flag(tp, FLUSH_POSTED_WRITES)) {
+		tp->write32_tx_mbox = tg3_write_flush_reg32;
+		tp->write32_rx_mbox = tg3_write_flush_reg32;
+	}
+
 	/* Get eeprom hw config before calling tg3_set_power_state().
 	 * In particular, the TG3_FLAG_IS_NIC flag must be
 	 * determined before calling tg3_set_power_state() so that
@@ -14675,6 +14751,8 @@ static int __devinit tg3_get_device_addr
 	}
 
 	if (!is_valid_ether_addr(&dev->dev_addr[0])) {
+		if (tg3_flag(tp, IS_SSB_CORE))
+			ssb_gige_get_macaddr(tp->pdev, &dev->dev_addr[0]);
 #ifdef CONFIG_SPARC
 		if (!tg3_get_default_macaddr_sparc(tp))
 			return 0;
@@ -15173,6 +15251,7 @@ static char * __devinit tg3_phy_string(s
 	case TG3_PHY_ID_BCM5704:	return "5704";
 	case TG3_PHY_ID_BCM5705:	return "5705";
 	case TG3_PHY_ID_BCM5750:	return "5750";
+	case TG3_PHY_ID_BCM5750_2:	return "5750-2";
 	case TG3_PHY_ID_BCM5752:	return "5752";
 	case TG3_PHY_ID_BCM5714:	return "5714";
 	case TG3_PHY_ID_BCM5780:	return "5780";
@@ -15368,6 +15447,13 @@ static int __devinit tg3_init_one(struct
 		tp->msg_enable = tg3_debug;
 	else
 		tp->msg_enable = TG3_DEF_MSG_ENABLE;
+	if (pdev_is_ssb_gige_core(pdev)) {
+		tg3_flag_set(tp, IS_SSB_CORE);
+		if (ssb_gige_must_flush_posted_writes(pdev))
+			tg3_flag_set(tp, FLUSH_POSTED_WRITES);
+		if (ssb_gige_have_roboswitch(pdev))
+			tg3_flag_set(tp, ROBOSWITCH);
+	}
 
 	/* The word/byte swap controls here control register access byte
 	 * swapping.  DMA data byte swapping is controlled in the GRC_MODE
--- a/drivers/net/ethernet/broadcom/tg3.h
+++ b/drivers/net/ethernet/broadcom/tg3.h
@@ -2922,6 +2922,9 @@ enum TG3_FLAGS {
 	TG3_FLAG_5717_PLUS,
 	TG3_FLAG_4K_FIFO_LIMIT,
 	TG3_FLAG_RESET_TASK_PENDING,
+	TG3_FLAG_IS_SSB_CORE,
+	TG3_FLAG_FLUSH_POSTED_WRITES,
+	TG3_FLAG_ROBOSWITCH,
 
 	/* Add new flags before this comment and TG3_FLAG_NUMBER_OF_FLAGS */
 	TG3_FLAG_NUMBER_OF_FLAGS,	/* Last entry in enum TG3_FLAGS */
@@ -3071,6 +3074,7 @@ struct tg3 {
 #define TG3_PHY_ID_BCM5704		0x60008190
 #define TG3_PHY_ID_BCM5705		0x600081a0
 #define TG3_PHY_ID_BCM5750		0x60008180
+#define TG3_PHY_ID_BCM5750_2		0xbc050cd0
 #define TG3_PHY_ID_BCM5752		0x60008100
 #define TG3_PHY_ID_BCM5714		0x60008340
 #define TG3_PHY_ID_BCM5780		0x60008350
@@ -3108,7 +3112,7 @@ struct tg3 {
 	 (X) == TG3_PHY_ID_BCM5906 || (X) == TG3_PHY_ID_BCM5761 || \
 	 (X) == TG3_PHY_ID_BCM5718C || (X) == TG3_PHY_ID_BCM5718S || \
 	 (X) == TG3_PHY_ID_BCM57765 || (X) == TG3_PHY_ID_BCM5719C || \
-	 (X) == TG3_PHY_ID_BCM8002)
+	 (X) == TG3_PHY_ID_BCM8002 || (X) == TG3_PHY_ID_BCM5750_2)
 
 	u32				phy_flags;
 #define TG3_PHYFLG_IS_LOW_POWER		0x00000001