Browse Source

[smscusb] Add ability to read MAC address from OTP

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 7 years ago
parent
commit
d4df9f573f
2 changed files with 251 additions and 1 deletions
  1. 207
    1
      src/drivers/net/smscusb.c
  2. 44
    0
      src/drivers/net/smscusb.h

+ 207
- 1
src/drivers/net/smscusb.c View File

@@ -166,7 +166,7 @@ int smscusb_eeprom_fetch_mac ( struct smscusb_device *smscusb,
166 166
 
167 167
 	/* Check that EEPROM is physically present */
168 168
 	if ( ! is_valid_ether_addr ( netdev->hw_addr ) ) {
169
-		DBGC ( smscusb, "SMSCUSB %p has no EEPROM (%s)\n",
169
+		DBGC ( smscusb, "SMSCUSB %p has no EEPROM MAC (%s)\n",
170 170
 		       smscusb, eth_ntoa ( netdev->hw_addr ) );
171 171
 		return -ENODEV;
172 172
 	}
@@ -176,6 +176,212 @@ int smscusb_eeprom_fetch_mac ( struct smscusb_device *smscusb,
176 176
 	return 0;
177 177
 }
178 178
 
179
+/******************************************************************************
180
+ *
181
+ * OTP access
182
+ *
183
+ ******************************************************************************
184
+ */
185
+
186
+/**
187
+ * Power up OTP
188
+ *
189
+ * @v smscusb		SMSC USB device
190
+ * @v otp_base		OTP register base
191
+ * @ret rc		Return status code
192
+ */
193
+static int smscusb_otp_power_up ( struct smscusb_device *smscusb,
194
+				  unsigned int otp_base ) {
195
+	uint32_t otp_power;
196
+	unsigned int i;
197
+	int rc;
198
+
199
+	/* Power up OTP */
200
+	if ( ( rc = smscusb_writel ( smscusb, ( otp_base + SMSCUSB_OTP_POWER ),
201
+				     0 ) ) != 0 )
202
+		return rc;
203
+
204
+	/* Wait for OTP_POWER_DOWN to become clear */
205
+	for ( i = 0 ; i < SMSCUSB_OTP_MAX_WAIT_MS ; i++ ) {
206
+
207
+		/* Read OTP_POWER and check OTP_POWER_DOWN */
208
+		if ( ( rc = smscusb_readl ( smscusb,
209
+					    ( otp_base + SMSCUSB_OTP_POWER ),
210
+					    &otp_power ) ) != 0 )
211
+			return rc;
212
+		if ( ! ( otp_power & SMSCUSB_OTP_POWER_DOWN ) )
213
+			return 0;
214
+
215
+		/* Delay */
216
+		mdelay ( 1 );
217
+	}
218
+
219
+	DBGC ( smscusb, "SMSCUSB %p timed out waiting for OTP power up\n",
220
+	       smscusb );
221
+	return -ETIMEDOUT;
222
+}
223
+
224
+/**
225
+ * Wait for OTP to become idle
226
+ *
227
+ * @v smscusb		SMSC USB device
228
+ * @v otp_base		OTP register base
229
+ * @ret rc		Return status code
230
+ */
231
+static int smscusb_otp_wait ( struct smscusb_device *smscusb,
232
+			      unsigned int otp_base ) {
233
+	uint32_t otp_status;
234
+	unsigned int i;
235
+	int rc;
236
+
237
+	/* Wait for OTP_STATUS_BUSY to become clear */
238
+	for ( i = 0 ; i < SMSCUSB_OTP_MAX_WAIT_MS ; i++ ) {
239
+
240
+		/* Read OTP_STATUS and check OTP_STATUS_BUSY */
241
+		if ( ( rc = smscusb_readl ( smscusb,
242
+					    ( otp_base + SMSCUSB_OTP_STATUS ),
243
+					    &otp_status ) ) != 0 )
244
+			return rc;
245
+		if ( ! ( otp_status & SMSCUSB_OTP_STATUS_BUSY ) )
246
+			return 0;
247
+
248
+		/* Delay */
249
+		mdelay ( 1 );
250
+	}
251
+
252
+	DBGC ( smscusb, "SMSCUSB %p timed out waiting for OTP\n",
253
+	       smscusb );
254
+	return -ETIMEDOUT;
255
+}
256
+
257
+/**
258
+ * Read byte from OTP
259
+ *
260
+ * @v smscusb		SMSC USB device
261
+ * @v otp_base		OTP register base
262
+ * @v address		OTP address
263
+ * @ret byte		Byte read, or negative error
264
+ */
265
+static int smscusb_otp_read_byte ( struct smscusb_device *smscusb,
266
+				   unsigned int otp_base,
267
+				   unsigned int address ) {
268
+	uint8_t addrh = ( address >> 8 );
269
+	uint8_t addrl = ( address >> 0 );
270
+	uint32_t otp_data;
271
+	int rc;
272
+
273
+	/* Wait for OTP to become idle */
274
+	if ( ( rc = smscusb_otp_wait ( smscusb, otp_base ) ) != 0 )
275
+		return rc;
276
+
277
+	/* Initiate read command */
278
+	if ( ( rc = smscusb_writel ( smscusb, ( otp_base + SMSCUSB_OTP_ADDRH ),
279
+				     addrh ) ) != 0 )
280
+		return rc;
281
+	if ( ( rc = smscusb_writel ( smscusb, ( otp_base + SMSCUSB_OTP_ADDRL ),
282
+				     addrl ) ) != 0 )
283
+		return rc;
284
+	if ( ( rc = smscusb_writel ( smscusb, ( otp_base + SMSCUSB_OTP_CMD ),
285
+				     SMSCUSB_OTP_CMD_READ ) ) != 0 )
286
+		return rc;
287
+	if ( ( rc = smscusb_writel ( smscusb, ( otp_base + SMSCUSB_OTP_GO ),
288
+				     SMSCUSB_OTP_GO_GO ) ) != 0 )
289
+		return rc;
290
+
291
+	/* Wait for command to complete */
292
+	if ( ( rc = smscusb_otp_wait ( smscusb, otp_base ) ) != 0 )
293
+		return rc;
294
+
295
+	/* Read OTP data */
296
+	if ( ( rc = smscusb_readl ( smscusb, ( otp_base + SMSCUSB_OTP_DATA ),
297
+				    &otp_data ) ) != 0 )
298
+		return rc;
299
+
300
+	return SMSCUSB_OTP_DATA_GET ( otp_data );
301
+}
302
+
303
+/**
304
+ * Read data from OTP
305
+ *
306
+ * @v smscusb		SMSC USB device
307
+ * @v otp_base		OTP register base
308
+ * @v address		OTP address
309
+ * @v data		Data buffer
310
+ * @v len		Length of data
311
+ * @ret rc		Return status code
312
+ */
313
+static int smscusb_otp_read ( struct smscusb_device *smscusb,
314
+			      unsigned int otp_base, unsigned int address,
315
+			      void *data, size_t len ) {
316
+	uint8_t *bytes;
317
+	int byte;
318
+	int rc;
319
+
320
+	/* Power up OTP */
321
+	if ( ( rc = smscusb_otp_power_up ( smscusb, otp_base ) ) != 0 )
322
+		return rc;
323
+
324
+	/* Read bytes */
325
+	for ( bytes = data ; len-- ; address++, bytes++ ) {
326
+		byte = smscusb_otp_read_byte ( smscusb, otp_base, address );
327
+		if ( byte < 0 )
328
+			return byte;
329
+		*bytes = byte;
330
+	}
331
+
332
+	return 0;
333
+}
334
+
335
+/**
336
+ * Fetch MAC address from OTP
337
+ *
338
+ * @v smscusb		SMSC USB device
339
+ * @v otp_base		OTP register base
340
+ * @ret rc		Return status code
341
+ */
342
+int smscusb_otp_fetch_mac ( struct smscusb_device *smscusb,
343
+			    unsigned int otp_base ) {
344
+	struct net_device *netdev = smscusb->netdev;
345
+	uint8_t signature;
346
+	unsigned int address;
347
+	int rc;
348
+
349
+	/* Read OTP signature byte */
350
+	if ( ( rc = smscusb_otp_read ( smscusb, otp_base, 0, &signature,
351
+				       sizeof ( signature ) ) ) != 0 )
352
+		return rc;
353
+
354
+	/* Determine location of MAC address */
355
+	switch ( signature ) {
356
+	case SMSCUSB_OTP_1_SIG:
357
+		address = SMSCUSB_OTP_1_MAC;
358
+		break;
359
+	case SMSCUSB_OTP_2_SIG:
360
+		address = SMSCUSB_OTP_2_MAC;
361
+		break;
362
+	default:
363
+		DBGC ( smscusb, "SMSCUSB %p unknown OTP signature %#02x\n",
364
+		       smscusb, signature );
365
+		return -ENOTSUP;
366
+	}
367
+
368
+	/* Read MAC address from OTP */
369
+	if ( ( rc = smscusb_otp_read ( smscusb, otp_base, address,
370
+				       netdev->hw_addr, ETH_ALEN ) ) != 0 )
371
+		return rc;
372
+
373
+	/* Check that OTP is valid */
374
+	if ( ! is_valid_ether_addr ( netdev->hw_addr ) ) {
375
+		DBGC ( smscusb, "SMSCUSB %p has no layout %#02x OTP MAC (%s)\n",
376
+		       smscusb, signature, eth_ntoa ( netdev->hw_addr ) );
377
+		return -ENODEV;
378
+	}
379
+
380
+	DBGC ( smscusb, "SMSCUSB %p using layout %#02x OTP MAC %s\n",
381
+	       smscusb, signature, eth_ntoa ( netdev->hw_addr ) );
382
+	return 0;
383
+}
384
+
179 385
 /******************************************************************************
180 386
  *
181 387
  * MII access

+ 44
- 0
src/drivers/net/smscusb.h View File

@@ -50,6 +50,48 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
50 50
 /** Maximum time to wait for EEPROM (in milliseconds) */
51 51
 #define SMSCUSB_EEPROM_MAX_WAIT_MS 100
52 52
 
53
+/** OTP power register offset */
54
+#define SMSCUSB_OTP_POWER 0x000
55
+#define SMSCUSB_OTP_POWER_DOWN		0x00000001UL	/**< OTP power down */
56
+
57
+/** OTP address high byte register offset */
58
+#define SMSCUSB_OTP_ADDRH 0x004
59
+
60
+/** OTP address low byte register offset */
61
+#define SMSCUSB_OTP_ADDRL 0x008
62
+
63
+/** OTP data register offset */
64
+#define SMSCUSB_OTP_DATA 0x018
65
+#define SMSCUSB_OTP_DATA_GET(otp_data) \
66
+	( ( (otp_data) >> 0 ) & 0xff )			/**< OTP data */
67
+
68
+/** OTP command selection register offset */
69
+#define SMSCUSB_OTP_CMD 0x020
70
+#define SMSCUSB_OTP_CMD_READ		0x00000001UL	/**< Read command */
71
+
72
+/** OTP command initiation register offset */
73
+#define SMSCUSB_OTP_GO 0x028
74
+#define SMSCUSB_OTP_GO_GO		0x00000001UL	/**< Initiate command */
75
+
76
+/** OTP status register offset */
77
+#define SMSCUSB_OTP_STATUS 0x030
78
+#define SMSCUSB_OTP_STATUS_BUSY		0x00000001UL	/**< OTP busy */
79
+
80
+/** Maximum time to wait for OTP (in milliseconds) */
81
+#define SMSCUSB_OTP_MAX_WAIT_MS 100
82
+
83
+/** OTP layout 1 signature */
84
+#define SMSCUSB_OTP_1_SIG 0xf3
85
+
86
+/** OTP layout 1 MAC address offset */
87
+#define SMSCUSB_OTP_1_MAC 0x001
88
+
89
+/** OTP layout 2 signature */
90
+#define SMSCUSB_OTP_2_SIG 0xf7
91
+
92
+/** OTP layout 2 MAC address offset */
93
+#define SMSCUSB_OTP_2_MAC 0x101
94
+
53 95
 /** MII access register offset */
54 96
 #define SMSCUSB_MII_ACCESS 0x000
55 97
 #define SMSCUSB_MII_ACCESS_PHY_ADDRESS	0x00000800UL	/**< PHY address */
@@ -292,6 +334,8 @@ smscusb_mii_init ( struct smscusb_device *smscusb, unsigned int mii_base ) {
292 334
 
293 335
 extern int smscusb_eeprom_fetch_mac ( struct smscusb_device *smscusb,
294 336
 				      unsigned int e2p_base );
337
+extern int smscusb_otp_fetch_mac ( struct smscusb_device *smscusb,
338
+				   unsigned int otp_base );
295 339
 extern int smscusb_mii_check_link ( struct smscusb_device *smscusb );
296 340
 extern int smscusb_mii_open ( struct smscusb_device *smscusb );
297 341
 extern int smscusb_set_address ( struct smscusb_device *smscusb,

Loading…
Cancel
Save