summaryrefslogtreecommitdiffstats
path: root/qemu/roms/ipxe/src/drivers/net/dm96xx.h
blob: 43a1a4e30db7b9a3ccb29db23ccbf3103f62c1bd (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
#ifndef _DM96XX_H
#define _DM96XX_H

/** @file
 *
 * Davicom DM96xx USB Ethernet driver
 *
 */

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );

#include <ipxe/usb.h>
#include <ipxe/usbnet.h>
#include <ipxe/if_ether.h>

/** Read register(s) */
#define DM96XX_READ_REGISTER					\
	( USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE |	\
	  USB_REQUEST_TYPE ( 0x00 ) )

/** Write register(s) */
#define DM96XX_WRITE_REGISTER					\
	( USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE |	\
	  USB_REQUEST_TYPE ( 0x01 ) )

/** Write single register */
#define DM96XX_WRITE1_REGISTER					\
	( USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE |	\
	  USB_REQUEST_TYPE ( 0x03 ) )

/** Network control register */
#define DM96XX_NCR 0x00
#define DM96XX_NCR_RST		0x01	/**< Software reset */

/** Network status register */
#define DM96XX_NSR 0x01
#define DM96XX_NSR_LINKST	0x40	/**< Link status */

/** Receive control register */
#define DM96XX_RCR 0x05
#define DM96XX_RCR_ALL		0x08	/**< Pass all multicast */
#define DM96XX_RCR_RUNT		0x04	/**< Pass runt packet */
#define DM96XX_RCR_PRMSC	0x02	/**< Promiscuous mode */
#define DM96XX_RCR_RXEN		0x01	/**< RX enable */

/** Receive status register */
#define DM96XX_RSR 0x06
#define DM96XX_RSR_MF		0x40	/**< Multicast frame */

/** PHY address registers */
#define DM96XX_PAR 0x10

/** Chip revision register */
#define DM96XX_CHIPR 0x2c
#define DM96XX_CHIPR_9601	0x00	/**< DM9601 */
#define DM96XX_CHIPR_9620	0x01	/**< DM9620 */

/** RX header control/status register (DM9620+ only) */
#define DM96XX_MODE_CTL 0x91
#define DM96XX_MODE_CTL_MODE	0x80	/**< 4-byte header mode */

/** DM96xx interrupt data */
struct dm96xx_interrupt {
	/** Network status register */
	uint8_t nsr;
	/** Transmit status registers */
	uint8_t tsr[2];
	/** Receive status register */
	uint8_t rsr;
	/** Receive overflow counter register */
	uint8_t rocr;
	/** Receive packet counter */
	uint8_t rxc;
	/** Transmit packet counter */
	uint8_t txc;
	/** General purpose register */
	uint8_t gpr;
} __attribute__ (( packed ));

/** DM96xx receive header */
struct dm96xx_rx_header {
	/** Packet status */
	uint8_t rsr;
	/** Packet length (excluding this header, including CRC) */
	uint16_t len;
} __attribute__ (( packed ));

/** DM96xx transmit header */
struct dm96xx_tx_header {
	/** Packet length (excluding this header) */
	uint16_t len;
} __attribute__ (( packed ));

/** A DM96xx network device */
struct dm96xx_device {
	/** USB device */
	struct usb_device *usb;
	/** USB bus */
	struct usb_bus *bus;
	/** Network device */
	struct net_device *netdev;
	/** USB network device */
	struct usbnet_device usbnet;
};

/**
 * Read registers
 *
 * @v dm96xx		DM96xx device
 * @v offset		Register offset
 * @v data		Data buffer
 * @v len		Length of data
 * @ret rc		Return status code
 */
static inline __attribute__ (( always_inline )) int
dm96xx_read_registers ( struct dm96xx_device *dm96xx, unsigned int offset,
			void *data, size_t len ) {

	return usb_control ( dm96xx->usb, DM96XX_READ_REGISTER, 0, offset,
			     data, len );
}

/**
 * Read register
 *
 * @v dm96xx		DM96xx device
 * @v offset		Register offset
 * @ret value		Register value, or negative error
 */
static inline __attribute__ (( always_inline )) int
dm96xx_read_register ( struct dm96xx_device *dm96xx, unsigned int offset ) {
	uint8_t value;
	int rc;

	if ( ( rc = dm96xx_read_registers ( dm96xx, offset, &value,
					    sizeof ( value ) ) ) != 0 )
		return rc;
	return value;
}

/**
 * Write registers
 *
 * @v dm96xx		DM96xx device
 * @v offset		Register offset
 * @v data		Data buffer
 * @v len		Length of data
 * @ret rc		Return status code
 */
static inline __attribute__ (( always_inline )) int
dm96xx_write_registers ( struct dm96xx_device *dm96xx, unsigned int offset,
			 void *data, size_t len ) {

	return usb_control ( dm96xx->usb, DM96XX_WRITE_REGISTER, 0, offset,
			     data, len );
}

/**
 * Write register
 *
 * @v dm96xx		DM96xx device
 * @v offset		Register offset
 * @v value		Register value
 * @ret rc		Return status code
 */
static inline __attribute__ (( always_inline )) int
dm96xx_write_register ( struct dm96xx_device *dm96xx, unsigned int offset,
			uint8_t value ) {

	return usb_control ( dm96xx->usb, DM96XX_WRITE1_REGISTER, value,
			     offset, NULL, 0 );
}

/** Reset delay (in microseconds) */
#define DM96XX_RESET_DELAY_US 10

/** Interrupt maximum fill level
 *
 * This is a policy decision.
 */
#define DM96XX_INTR_MAX_FILL 2

/** Bulk IN maximum fill level
 *
 * This is a policy decision.
 */
#define DM96XX_IN_MAX_FILL 8

/** Bulk IN buffer size */
#define DM96XX_IN_MTU					\
	( 4 /* DM96xx header */ + ETH_FRAME_LEN +	\
	  4 /* possible VLAN header */ + 4 /* CRC */ )

#endif /* _DM96XX_H */