diff options
-rw-r--r-- | drivers/net/ethernet/wiznet/Kconfig | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/wiznet/w5100-spi.c | 174 | ||||
-rw-r--r-- | drivers/net/ethernet/wiznet/w5100.c | 155 | ||||
-rw-r--r-- | drivers/net/ethernet/wiznet/w5100.h | 6 |
4 files changed, 289 insertions, 48 deletions
diff --git a/drivers/net/ethernet/wiznet/Kconfig b/drivers/net/ethernet/wiznet/Kconfig index d1ab353790de..1f15376e9856 100644 --- a/drivers/net/ethernet/wiznet/Kconfig +++ b/drivers/net/ethernet/wiznet/Kconfig | |||
@@ -70,7 +70,7 @@ config WIZNET_BUS_ANY | |||
70 | endchoice | 70 | endchoice |
71 | 71 | ||
72 | config WIZNET_W5100_SPI | 72 | config WIZNET_W5100_SPI |
73 | tristate "WIZnet W5100 Ethernet support for SPI mode" | 73 | tristate "WIZnet W5100/W5200 Ethernet support for SPI mode" |
74 | depends on WIZNET_BUS_ANY | 74 | depends on WIZNET_BUS_ANY |
75 | depends on SPI | 75 | depends on SPI |
76 | ---help--- | 76 | ---help--- |
diff --git a/drivers/net/ethernet/wiznet/w5100-spi.c b/drivers/net/ethernet/wiznet/w5100-spi.c index 32f406cfce4b..598a7b00fdb9 100644 --- a/drivers/net/ethernet/wiznet/w5100-spi.c +++ b/drivers/net/ethernet/wiznet/w5100-spi.c | |||
@@ -1,9 +1,13 @@ | |||
1 | /* | 1 | /* |
2 | * Ethernet driver for the WIZnet W5100 chip. | 2 | * Ethernet driver for the WIZnet W5100/W5200 chip. |
3 | * | 3 | * |
4 | * Copyright (C) 2016 Akinobu Mita <akinobu.mita@gmail.com> | 4 | * Copyright (C) 2016 Akinobu Mita <akinobu.mita@gmail.com> |
5 | * | 5 | * |
6 | * Licensed under the GPL-2 or later. | 6 | * Licensed under the GPL-2 or later. |
7 | * | ||
8 | * Datasheet: | ||
9 | * http://www.wiznet.co.kr/wp-content/uploads/wiznethome/Chip/W5100/Document/W5100_Datasheet_v1.2.6.pdf | ||
10 | * http://wiznethome.cafe24.com/wp-content/uploads/wiznethome/Chip/W5200/Documents/W5200_DS_V140E.pdf | ||
7 | */ | 11 | */ |
8 | 12 | ||
9 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
@@ -95,6 +99,7 @@ static int w5100_spi_writebulk(struct net_device *ndev, u16 addr, const u8 *buf, | |||
95 | 99 | ||
96 | static const struct w5100_ops w5100_spi_ops = { | 100 | static const struct w5100_ops w5100_spi_ops = { |
97 | .may_sleep = true, | 101 | .may_sleep = true, |
102 | .chip_id = W5100, | ||
98 | .read = w5100_spi_read, | 103 | .read = w5100_spi_read, |
99 | .write = w5100_spi_write, | 104 | .write = w5100_spi_write, |
100 | .read16 = w5100_spi_read16, | 105 | .read16 = w5100_spi_read16, |
@@ -103,10 +108,168 @@ static const struct w5100_ops w5100_spi_ops = { | |||
103 | .writebulk = w5100_spi_writebulk, | 108 | .writebulk = w5100_spi_writebulk, |
104 | }; | 109 | }; |
105 | 110 | ||
111 | #define W5200_SPI_WRITE_OPCODE 0x80 | ||
112 | |||
113 | struct w5200_spi_priv { | ||
114 | /* Serialize access to cmd_buf */ | ||
115 | struct mutex cmd_lock; | ||
116 | |||
117 | /* DMA (thus cache coherency maintenance) requires the | ||
118 | * transfer buffers to live in their own cache lines. | ||
119 | */ | ||
120 | u8 cmd_buf[4] ____cacheline_aligned; | ||
121 | }; | ||
122 | |||
123 | static struct w5200_spi_priv *w5200_spi_priv(struct net_device *ndev) | ||
124 | { | ||
125 | return w5100_ops_priv(ndev); | ||
126 | } | ||
127 | |||
128 | static int w5200_spi_init(struct net_device *ndev) | ||
129 | { | ||
130 | struct w5200_spi_priv *spi_priv = w5200_spi_priv(ndev); | ||
131 | |||
132 | mutex_init(&spi_priv->cmd_lock); | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static int w5200_spi_read(struct net_device *ndev, u16 addr) | ||
138 | { | ||
139 | struct spi_device *spi = to_spi_device(ndev->dev.parent); | ||
140 | u8 cmd[4] = { addr >> 8, addr & 0xff, 0, 1 }; | ||
141 | u8 data; | ||
142 | int ret; | ||
143 | |||
144 | ret = spi_write_then_read(spi, cmd, sizeof(cmd), &data, 1); | ||
145 | |||
146 | return ret ? ret : data; | ||
147 | } | ||
148 | |||
149 | static int w5200_spi_write(struct net_device *ndev, u16 addr, u8 data) | ||
150 | { | ||
151 | struct spi_device *spi = to_spi_device(ndev->dev.parent); | ||
152 | u8 cmd[5] = { addr >> 8, addr & 0xff, W5200_SPI_WRITE_OPCODE, 1, data }; | ||
153 | |||
154 | return spi_write_then_read(spi, cmd, sizeof(cmd), NULL, 0); | ||
155 | } | ||
156 | |||
157 | static int w5200_spi_read16(struct net_device *ndev, u16 addr) | ||
158 | { | ||
159 | struct spi_device *spi = to_spi_device(ndev->dev.parent); | ||
160 | u8 cmd[4] = { addr >> 8, addr & 0xff, 0, 2 }; | ||
161 | __be16 data; | ||
162 | int ret; | ||
163 | |||
164 | ret = spi_write_then_read(spi, cmd, sizeof(cmd), &data, sizeof(data)); | ||
165 | |||
166 | return ret ? ret : be16_to_cpu(data); | ||
167 | } | ||
168 | |||
169 | static int w5200_spi_write16(struct net_device *ndev, u16 addr, u16 data) | ||
170 | { | ||
171 | struct spi_device *spi = to_spi_device(ndev->dev.parent); | ||
172 | u8 cmd[6] = { | ||
173 | addr >> 8, addr & 0xff, | ||
174 | W5200_SPI_WRITE_OPCODE, 2, | ||
175 | data >> 8, data & 0xff | ||
176 | }; | ||
177 | |||
178 | return spi_write_then_read(spi, cmd, sizeof(cmd), NULL, 0); | ||
179 | } | ||
180 | |||
181 | static int w5200_spi_readbulk(struct net_device *ndev, u16 addr, u8 *buf, | ||
182 | int len) | ||
183 | { | ||
184 | struct spi_device *spi = to_spi_device(ndev->dev.parent); | ||
185 | struct w5200_spi_priv *spi_priv = w5200_spi_priv(ndev); | ||
186 | struct spi_transfer xfer[] = { | ||
187 | { | ||
188 | .tx_buf = spi_priv->cmd_buf, | ||
189 | .len = sizeof(spi_priv->cmd_buf), | ||
190 | }, | ||
191 | { | ||
192 | .rx_buf = buf, | ||
193 | .len = len, | ||
194 | }, | ||
195 | }; | ||
196 | int ret; | ||
197 | |||
198 | mutex_lock(&spi_priv->cmd_lock); | ||
199 | |||
200 | spi_priv->cmd_buf[0] = addr >> 8; | ||
201 | spi_priv->cmd_buf[1] = addr; | ||
202 | spi_priv->cmd_buf[2] = len >> 8; | ||
203 | spi_priv->cmd_buf[3] = len; | ||
204 | ret = spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer)); | ||
205 | |||
206 | mutex_unlock(&spi_priv->cmd_lock); | ||
207 | |||
208 | return ret; | ||
209 | } | ||
210 | |||
211 | static int w5200_spi_writebulk(struct net_device *ndev, u16 addr, const u8 *buf, | ||
212 | int len) | ||
213 | { | ||
214 | struct spi_device *spi = to_spi_device(ndev->dev.parent); | ||
215 | struct w5200_spi_priv *spi_priv = w5200_spi_priv(ndev); | ||
216 | struct spi_transfer xfer[] = { | ||
217 | { | ||
218 | .tx_buf = spi_priv->cmd_buf, | ||
219 | .len = sizeof(spi_priv->cmd_buf), | ||
220 | }, | ||
221 | { | ||
222 | .tx_buf = buf, | ||
223 | .len = len, | ||
224 | }, | ||
225 | }; | ||
226 | int ret; | ||
227 | |||
228 | mutex_lock(&spi_priv->cmd_lock); | ||
229 | |||
230 | spi_priv->cmd_buf[0] = addr >> 8; | ||
231 | spi_priv->cmd_buf[1] = addr; | ||
232 | spi_priv->cmd_buf[2] = W5200_SPI_WRITE_OPCODE | (len >> 8); | ||
233 | spi_priv->cmd_buf[3] = len; | ||
234 | ret = spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer)); | ||
235 | |||
236 | mutex_unlock(&spi_priv->cmd_lock); | ||
237 | |||
238 | return ret; | ||
239 | } | ||
240 | |||
241 | static const struct w5100_ops w5200_ops = { | ||
242 | .may_sleep = true, | ||
243 | .chip_id = W5200, | ||
244 | .read = w5200_spi_read, | ||
245 | .write = w5200_spi_write, | ||
246 | .read16 = w5200_spi_read16, | ||
247 | .write16 = w5200_spi_write16, | ||
248 | .readbulk = w5200_spi_readbulk, | ||
249 | .writebulk = w5200_spi_writebulk, | ||
250 | .init = w5200_spi_init, | ||
251 | }; | ||
252 | |||
106 | static int w5100_spi_probe(struct spi_device *spi) | 253 | static int w5100_spi_probe(struct spi_device *spi) |
107 | { | 254 | { |
108 | return w5100_probe(&spi->dev, &w5100_spi_ops, 0, NULL, spi->irq, | 255 | const struct spi_device_id *id = spi_get_device_id(spi); |
109 | -EINVAL); | 256 | const struct w5100_ops *ops; |
257 | int priv_size; | ||
258 | |||
259 | switch (id->driver_data) { | ||
260 | case W5100: | ||
261 | ops = &w5100_spi_ops; | ||
262 | priv_size = 0; | ||
263 | break; | ||
264 | case W5200: | ||
265 | ops = &w5200_ops; | ||
266 | priv_size = sizeof(struct w5200_spi_priv); | ||
267 | break; | ||
268 | default: | ||
269 | return -EINVAL; | ||
270 | } | ||
271 | |||
272 | return w5100_probe(&spi->dev, ops, priv_size, NULL, spi->irq, -EINVAL); | ||
110 | } | 273 | } |
111 | 274 | ||
112 | static int w5100_spi_remove(struct spi_device *spi) | 275 | static int w5100_spi_remove(struct spi_device *spi) |
@@ -115,7 +278,8 @@ static int w5100_spi_remove(struct spi_device *spi) | |||
115 | } | 278 | } |
116 | 279 | ||
117 | static const struct spi_device_id w5100_spi_ids[] = { | 280 | static const struct spi_device_id w5100_spi_ids[] = { |
118 | { "w5100", 0 }, | 281 | { "w5100", W5100 }, |
282 | { "w5200", W5200 }, | ||
119 | {} | 283 | {} |
120 | }; | 284 | }; |
121 | MODULE_DEVICE_TABLE(spi, w5100_spi_ids); | 285 | MODULE_DEVICE_TABLE(spi, w5100_spi_ids); |
@@ -131,6 +295,6 @@ static struct spi_driver w5100_spi_driver = { | |||
131 | }; | 295 | }; |
132 | module_spi_driver(w5100_spi_driver); | 296 | module_spi_driver(w5100_spi_driver); |
133 | 297 | ||
134 | MODULE_DESCRIPTION("WIZnet W5100 Ethernet driver for SPI mode"); | 298 | MODULE_DESCRIPTION("WIZnet W5100/W5200 Ethernet driver for SPI mode"); |
135 | MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>"); | 299 | MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>"); |
136 | MODULE_LICENSE("GPL"); | 300 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/net/ethernet/wiznet/w5100.c b/drivers/net/ethernet/wiznet/w5100.c index 42a9de4a48b1..09149c9ebeff 100644 --- a/drivers/net/ethernet/wiznet/w5100.c +++ b/drivers/net/ethernet/wiznet/w5100.c | |||
@@ -38,7 +38,7 @@ MODULE_ALIAS("platform:"DRV_NAME); | |||
38 | MODULE_LICENSE("GPL"); | 38 | MODULE_LICENSE("GPL"); |
39 | 39 | ||
40 | /* | 40 | /* |
41 | * Registers | 41 | * W5100 and W5100 common registers |
42 | */ | 42 | */ |
43 | #define W5100_COMMON_REGS 0x0000 | 43 | #define W5100_COMMON_REGS 0x0000 |
44 | #define W5100_MR 0x0000 /* Mode Register */ | 44 | #define W5100_MR 0x0000 /* Mode Register */ |
@@ -52,37 +52,69 @@ MODULE_LICENSE("GPL"); | |||
52 | #define IR_S0 0x01 /* S0 interrupt */ | 52 | #define IR_S0 0x01 /* S0 interrupt */ |
53 | #define W5100_RTR 0x0017 /* Retry Time-value Register */ | 53 | #define W5100_RTR 0x0017 /* Retry Time-value Register */ |
54 | #define RTR_DEFAULT 2000 /* =0x07d0 (2000) */ | 54 | #define RTR_DEFAULT 2000 /* =0x07d0 (2000) */ |
55 | #define W5100_RMSR 0x001a /* Receive Memory Size */ | ||
56 | #define W5100_TMSR 0x001b /* Transmit Memory Size */ | ||
57 | #define W5100_COMMON_REGS_LEN 0x0040 | 55 | #define W5100_COMMON_REGS_LEN 0x0040 |
58 | 56 | ||
59 | #define W5100_S0_REGS 0x0400 | 57 | #define W5100_Sn_MR 0x0000 /* Sn Mode Register */ |
60 | #define W5100_S0_MR 0x0400 /* S0 Mode Register */ | 58 | #define W5100_Sn_CR 0x0001 /* Sn Command Register */ |
59 | #define W5100_Sn_IR 0x0002 /* Sn Interrupt Register */ | ||
60 | #define W5100_Sn_SR 0x0003 /* Sn Status Register */ | ||
61 | #define W5100_Sn_TX_FSR 0x0020 /* Sn Transmit free memory size */ | ||
62 | #define W5100_Sn_TX_RD 0x0022 /* Sn Transmit memory read pointer */ | ||
63 | #define W5100_Sn_TX_WR 0x0024 /* Sn Transmit memory write pointer */ | ||
64 | #define W5100_Sn_RX_RSR 0x0026 /* Sn Receive free memory size */ | ||
65 | #define W5100_Sn_RX_RD 0x0028 /* Sn Receive memory read pointer */ | ||
66 | |||
67 | #define S0_REGS(priv) (is_w5200(priv) ? W5200_S0_REGS : W5100_S0_REGS) | ||
68 | |||
69 | #define W5100_S0_MR(priv) (S0_REGS(priv) + W5100_Sn_MR) | ||
61 | #define S0_MR_MACRAW 0x04 /* MAC RAW mode (promiscuous) */ | 70 | #define S0_MR_MACRAW 0x04 /* MAC RAW mode (promiscuous) */ |
62 | #define S0_MR_MACRAW_MF 0x44 /* MAC RAW mode (filtered) */ | 71 | #define S0_MR_MACRAW_MF 0x44 /* MAC RAW mode (filtered) */ |
63 | #define W5100_S0_CR 0x0401 /* S0 Command Register */ | 72 | #define W5100_S0_CR(priv) (S0_REGS(priv) + W5100_Sn_CR) |
64 | #define S0_CR_OPEN 0x01 /* OPEN command */ | 73 | #define S0_CR_OPEN 0x01 /* OPEN command */ |
65 | #define S0_CR_CLOSE 0x10 /* CLOSE command */ | 74 | #define S0_CR_CLOSE 0x10 /* CLOSE command */ |
66 | #define S0_CR_SEND 0x20 /* SEND command */ | 75 | #define S0_CR_SEND 0x20 /* SEND command */ |
67 | #define S0_CR_RECV 0x40 /* RECV command */ | 76 | #define S0_CR_RECV 0x40 /* RECV command */ |
68 | #define W5100_S0_IR 0x0402 /* S0 Interrupt Register */ | 77 | #define W5100_S0_IR(priv) (S0_REGS(priv) + W5100_Sn_IR) |
69 | #define S0_IR_SENDOK 0x10 /* complete sending */ | 78 | #define S0_IR_SENDOK 0x10 /* complete sending */ |
70 | #define S0_IR_RECV 0x04 /* receiving data */ | 79 | #define S0_IR_RECV 0x04 /* receiving data */ |
71 | #define W5100_S0_SR 0x0403 /* S0 Status Register */ | 80 | #define W5100_S0_SR(priv) (S0_REGS(priv) + W5100_Sn_SR) |
72 | #define S0_SR_MACRAW 0x42 /* mac raw mode */ | 81 | #define S0_SR_MACRAW 0x42 /* mac raw mode */ |
73 | #define W5100_S0_TX_FSR 0x0420 /* S0 Transmit free memory size */ | 82 | #define W5100_S0_TX_FSR(priv) (S0_REGS(priv) + W5100_Sn_TX_FSR) |
74 | #define W5100_S0_TX_RD 0x0422 /* S0 Transmit memory read pointer */ | 83 | #define W5100_S0_TX_RD(priv) (S0_REGS(priv) + W5100_Sn_TX_RD) |
75 | #define W5100_S0_TX_WR 0x0424 /* S0 Transmit memory write pointer */ | 84 | #define W5100_S0_TX_WR(priv) (S0_REGS(priv) + W5100_Sn_TX_WR) |
76 | #define W5100_S0_RX_RSR 0x0426 /* S0 Receive free memory size */ | 85 | #define W5100_S0_RX_RSR(priv) (S0_REGS(priv) + W5100_Sn_RX_RSR) |
77 | #define W5100_S0_RX_RD 0x0428 /* S0 Receive memory read pointer */ | 86 | #define W5100_S0_RX_RD(priv) (S0_REGS(priv) + W5100_Sn_RX_RD) |
87 | |||
78 | #define W5100_S0_REGS_LEN 0x0040 | 88 | #define W5100_S0_REGS_LEN 0x0040 |
79 | 89 | ||
90 | /* | ||
91 | * W5100 specific registers | ||
92 | */ | ||
93 | #define W5100_RMSR 0x001a /* Receive Memory Size */ | ||
94 | #define W5100_TMSR 0x001b /* Transmit Memory Size */ | ||
95 | |||
96 | #define W5100_S0_REGS 0x0400 | ||
97 | |||
80 | #define W5100_TX_MEM_START 0x4000 | 98 | #define W5100_TX_MEM_START 0x4000 |
81 | #define W5100_TX_MEM_SIZE 0x2000 | 99 | #define W5100_TX_MEM_SIZE 0x2000 |
82 | #define W5100_RX_MEM_START 0x6000 | 100 | #define W5100_RX_MEM_START 0x6000 |
83 | #define W5100_RX_MEM_SIZE 0x2000 | 101 | #define W5100_RX_MEM_SIZE 0x2000 |
84 | 102 | ||
85 | /* | 103 | /* |
104 | * W5200 specific registers | ||
105 | */ | ||
106 | #define W5200_S0_REGS 0x4000 | ||
107 | |||
108 | #define W5200_Sn_RXMEM_SIZE(n) (0x401e + (n) * 0x0100) /* Sn RX Memory Size */ | ||
109 | #define W5200_Sn_TXMEM_SIZE(n) (0x401f + (n) * 0x0100) /* Sn TX Memory Size */ | ||
110 | #define W5200_S0_IMR 0x402c /* S0 Interrupt Mask Register */ | ||
111 | |||
112 | #define W5200_TX_MEM_START 0x8000 | ||
113 | #define W5200_TX_MEM_SIZE 0x4000 | ||
114 | #define W5200_RX_MEM_START 0xc000 | ||
115 | #define W5200_RX_MEM_SIZE 0x4000 | ||
116 | |||
117 | /* | ||
86 | * Device driver private data structure | 118 | * Device driver private data structure |
87 | */ | 119 | */ |
88 | 120 | ||
@@ -105,6 +137,11 @@ struct w5100_priv { | |||
105 | struct work_struct restart_work; | 137 | struct work_struct restart_work; |
106 | }; | 138 | }; |
107 | 139 | ||
140 | static inline bool is_w5200(struct w5100_priv *priv) | ||
141 | { | ||
142 | return priv->ops->chip_id == W5200; | ||
143 | } | ||
144 | |||
108 | /************************************************************************ | 145 | /************************************************************************ |
109 | * | 146 | * |
110 | * Lowlevel I/O functions | 147 | * Lowlevel I/O functions |
@@ -217,6 +254,7 @@ static int w5100_mmio_init(struct net_device *ndev) | |||
217 | } | 254 | } |
218 | 255 | ||
219 | static const struct w5100_ops w5100_mmio_direct_ops = { | 256 | static const struct w5100_ops w5100_mmio_direct_ops = { |
257 | .chip_id = W5100, | ||
220 | .read = w5100_read_direct, | 258 | .read = w5100_read_direct, |
221 | .write = w5100_write_direct, | 259 | .write = w5100_write_direct, |
222 | .read16 = w5100_read16_direct, | 260 | .read16 = w5100_read16_direct, |
@@ -341,6 +379,7 @@ static int w5100_reset_indirect(struct net_device *ndev) | |||
341 | } | 379 | } |
342 | 380 | ||
343 | static const struct w5100_ops w5100_mmio_indirect_ops = { | 381 | static const struct w5100_ops w5100_mmio_indirect_ops = { |
382 | .chip_id = W5100, | ||
344 | .read = w5100_read_indirect, | 383 | .read = w5100_read_indirect, |
345 | .write = w5100_write_indirect, | 384 | .write = w5100_write_indirect, |
346 | .read16 = w5100_read16_indirect, | 385 | .read16 = w5100_read16_indirect, |
@@ -457,20 +496,24 @@ static int w5100_readbuf(struct w5100_priv *priv, u16 offset, u8 *buf, int len) | |||
457 | u16 addr; | 496 | u16 addr; |
458 | int remain = 0; | 497 | int remain = 0; |
459 | int ret; | 498 | int ret; |
499 | const u16 mem_start = | ||
500 | is_w5200(priv) ? W5200_RX_MEM_START : W5100_RX_MEM_START; | ||
501 | const u16 mem_size = | ||
502 | is_w5200(priv) ? W5200_RX_MEM_SIZE : W5100_RX_MEM_SIZE; | ||
460 | 503 | ||
461 | offset %= W5100_RX_MEM_SIZE; | 504 | offset %= mem_size; |
462 | addr = W5100_RX_MEM_START + offset; | 505 | addr = mem_start + offset; |
463 | 506 | ||
464 | if (offset + len > W5100_RX_MEM_SIZE) { | 507 | if (offset + len > mem_size) { |
465 | remain = (offset + len) % W5100_RX_MEM_SIZE; | 508 | remain = (offset + len) % mem_size; |
466 | len = W5100_RX_MEM_SIZE - offset; | 509 | len = mem_size - offset; |
467 | } | 510 | } |
468 | 511 | ||
469 | ret = w5100_readbulk(priv, addr, buf, len); | 512 | ret = w5100_readbulk(priv, addr, buf, len); |
470 | if (ret || !remain) | 513 | if (ret || !remain) |
471 | return ret; | 514 | return ret; |
472 | 515 | ||
473 | return w5100_readbulk(priv, W5100_RX_MEM_START, buf + len, remain); | 516 | return w5100_readbulk(priv, mem_start, buf + len, remain); |
474 | } | 517 | } |
475 | 518 | ||
476 | static int w5100_writebuf(struct w5100_priv *priv, u16 offset, const u8 *buf, | 519 | static int w5100_writebuf(struct w5100_priv *priv, u16 offset, const u8 *buf, |
@@ -479,20 +522,24 @@ static int w5100_writebuf(struct w5100_priv *priv, u16 offset, const u8 *buf, | |||
479 | u16 addr; | 522 | u16 addr; |
480 | int ret; | 523 | int ret; |
481 | int remain = 0; | 524 | int remain = 0; |
525 | const u16 mem_start = | ||
526 | is_w5200(priv) ? W5200_TX_MEM_START : W5100_TX_MEM_START; | ||
527 | const u16 mem_size = | ||
528 | is_w5200(priv) ? W5200_TX_MEM_SIZE : W5100_TX_MEM_SIZE; | ||
482 | 529 | ||
483 | offset %= W5100_TX_MEM_SIZE; | 530 | offset %= mem_size; |
484 | addr = W5100_TX_MEM_START + offset; | 531 | addr = mem_start + offset; |
485 | 532 | ||
486 | if (offset + len > W5100_TX_MEM_SIZE) { | 533 | if (offset + len > mem_size) { |
487 | remain = (offset + len) % W5100_TX_MEM_SIZE; | 534 | remain = (offset + len) % mem_size; |
488 | len = W5100_TX_MEM_SIZE - offset; | 535 | len = mem_size - offset; |
489 | } | 536 | } |
490 | 537 | ||
491 | ret = w5100_writebulk(priv, addr, buf, len); | 538 | ret = w5100_writebulk(priv, addr, buf, len); |
492 | if (ret || !remain) | 539 | if (ret || !remain) |
493 | return ret; | 540 | return ret; |
494 | 541 | ||
495 | return w5100_writebulk(priv, W5100_TX_MEM_START, buf + len, remain); | 542 | return w5100_writebulk(priv, mem_start, buf + len, remain); |
496 | } | 543 | } |
497 | 544 | ||
498 | static int w5100_reset(struct w5100_priv *priv) | 545 | static int w5100_reset(struct w5100_priv *priv) |
@@ -511,11 +558,11 @@ static int w5100_command(struct w5100_priv *priv, u16 cmd) | |||
511 | { | 558 | { |
512 | unsigned long timeout; | 559 | unsigned long timeout; |
513 | 560 | ||
514 | w5100_write(priv, W5100_S0_CR, cmd); | 561 | w5100_write(priv, W5100_S0_CR(priv), cmd); |
515 | 562 | ||
516 | timeout = jiffies + msecs_to_jiffies(100); | 563 | timeout = jiffies + msecs_to_jiffies(100); |
517 | 564 | ||
518 | while (w5100_read(priv, W5100_S0_CR) != 0) { | 565 | while (w5100_read(priv, W5100_S0_CR(priv)) != 0) { |
519 | if (time_after(jiffies, timeout)) | 566 | if (time_after(jiffies, timeout)) |
520 | return -EIO; | 567 | return -EIO; |
521 | cpu_relax(); | 568 | cpu_relax(); |
@@ -531,6 +578,31 @@ static void w5100_write_macaddr(struct w5100_priv *priv) | |||
531 | w5100_writebulk(priv, W5100_SHAR, ndev->dev_addr, ETH_ALEN); | 578 | w5100_writebulk(priv, W5100_SHAR, ndev->dev_addr, ETH_ALEN); |
532 | } | 579 | } |
533 | 580 | ||
581 | static void w5100_memory_configure(struct w5100_priv *priv) | ||
582 | { | ||
583 | /* Configure 16K of internal memory | ||
584 | * as 8K RX buffer and 8K TX buffer | ||
585 | */ | ||
586 | w5100_write(priv, W5100_RMSR, 0x03); | ||
587 | w5100_write(priv, W5100_TMSR, 0x03); | ||
588 | } | ||
589 | |||
590 | static void w5200_memory_configure(struct w5100_priv *priv) | ||
591 | { | ||
592 | int i; | ||
593 | |||
594 | /* Configure internal RX memory as 16K RX buffer and | ||
595 | * internal TX memory as 16K TX buffer | ||
596 | */ | ||
597 | w5100_write(priv, W5200_Sn_RXMEM_SIZE(0), 0x10); | ||
598 | w5100_write(priv, W5200_Sn_TXMEM_SIZE(0), 0x10); | ||
599 | |||
600 | for (i = 1; i < 8; i++) { | ||
601 | w5100_write(priv, W5200_Sn_RXMEM_SIZE(i), 0); | ||
602 | w5100_write(priv, W5200_Sn_TXMEM_SIZE(i), 0); | ||
603 | } | ||
604 | } | ||
605 | |||
534 | static void w5100_hw_reset(struct w5100_priv *priv) | 606 | static void w5100_hw_reset(struct w5100_priv *priv) |
535 | { | 607 | { |
536 | w5100_reset(priv); | 608 | w5100_reset(priv); |
@@ -538,16 +610,15 @@ static void w5100_hw_reset(struct w5100_priv *priv) | |||
538 | w5100_write(priv, W5100_IMR, 0); | 610 | w5100_write(priv, W5100_IMR, 0); |
539 | w5100_write_macaddr(priv); | 611 | w5100_write_macaddr(priv); |
540 | 612 | ||
541 | /* Configure 16K of internal memory | 613 | if (is_w5200(priv)) |
542 | * as 8K RX buffer and 8K TX buffer | 614 | w5200_memory_configure(priv); |
543 | */ | 615 | else |
544 | w5100_write(priv, W5100_RMSR, 0x03); | 616 | w5100_memory_configure(priv); |
545 | w5100_write(priv, W5100_TMSR, 0x03); | ||
546 | } | 617 | } |
547 | 618 | ||
548 | static void w5100_hw_start(struct w5100_priv *priv) | 619 | static void w5100_hw_start(struct w5100_priv *priv) |
549 | { | 620 | { |
550 | w5100_write(priv, W5100_S0_MR, priv->promisc ? | 621 | w5100_write(priv, W5100_S0_MR(priv), priv->promisc ? |
551 | S0_MR_MACRAW : S0_MR_MACRAW_MF); | 622 | S0_MR_MACRAW : S0_MR_MACRAW_MF); |
552 | w5100_command(priv, S0_CR_OPEN); | 623 | w5100_command(priv, S0_CR_OPEN); |
553 | w5100_write(priv, W5100_IMR, IR_S0); | 624 | w5100_write(priv, W5100_IMR, IR_S0); |
@@ -611,7 +682,7 @@ static void w5100_get_regs(struct net_device *ndev, | |||
611 | regs->version = 1; | 682 | regs->version = 1; |
612 | w5100_readbulk(priv, W5100_COMMON_REGS, buf, W5100_COMMON_REGS_LEN); | 683 | w5100_readbulk(priv, W5100_COMMON_REGS, buf, W5100_COMMON_REGS_LEN); |
613 | buf += W5100_COMMON_REGS_LEN; | 684 | buf += W5100_COMMON_REGS_LEN; |
614 | w5100_readbulk(priv, W5100_S0_REGS, buf, W5100_S0_REGS_LEN); | 685 | w5100_readbulk(priv, S0_REGS(priv), buf, W5100_S0_REGS_LEN); |
615 | } | 686 | } |
616 | 687 | ||
617 | static void w5100_restart(struct net_device *ndev) | 688 | static void w5100_restart(struct net_device *ndev) |
@@ -649,9 +720,9 @@ static void w5100_tx_skb(struct net_device *ndev, struct sk_buff *skb) | |||
649 | struct w5100_priv *priv = netdev_priv(ndev); | 720 | struct w5100_priv *priv = netdev_priv(ndev); |
650 | u16 offset; | 721 | u16 offset; |
651 | 722 | ||
652 | offset = w5100_read16(priv, W5100_S0_TX_WR); | 723 | offset = w5100_read16(priv, W5100_S0_TX_WR(priv)); |
653 | w5100_writebuf(priv, offset, skb->data, skb->len); | 724 | w5100_writebuf(priv, offset, skb->data, skb->len); |
654 | w5100_write16(priv, W5100_S0_TX_WR, offset + skb->len); | 725 | w5100_write16(priv, W5100_S0_TX_WR(priv), offset + skb->len); |
655 | ndev->stats.tx_bytes += skb->len; | 726 | ndev->stats.tx_bytes += skb->len; |
656 | ndev->stats.tx_packets++; | 727 | ndev->stats.tx_packets++; |
657 | dev_kfree_skb(skb); | 728 | dev_kfree_skb(skb); |
@@ -696,18 +767,18 @@ static struct sk_buff *w5100_rx_skb(struct net_device *ndev) | |||
696 | u16 rx_len; | 767 | u16 rx_len; |
697 | u16 offset; | 768 | u16 offset; |
698 | u8 header[2]; | 769 | u8 header[2]; |
699 | u16 rx_buf_len = w5100_read16(priv, W5100_S0_RX_RSR); | 770 | u16 rx_buf_len = w5100_read16(priv, W5100_S0_RX_RSR(priv)); |
700 | 771 | ||
701 | if (rx_buf_len == 0) | 772 | if (rx_buf_len == 0) |
702 | return NULL; | 773 | return NULL; |
703 | 774 | ||
704 | offset = w5100_read16(priv, W5100_S0_RX_RD); | 775 | offset = w5100_read16(priv, W5100_S0_RX_RD(priv)); |
705 | w5100_readbuf(priv, offset, header, 2); | 776 | w5100_readbuf(priv, offset, header, 2); |
706 | rx_len = get_unaligned_be16(header) - 2; | 777 | rx_len = get_unaligned_be16(header) - 2; |
707 | 778 | ||
708 | skb = netdev_alloc_skb_ip_align(ndev, rx_len); | 779 | skb = netdev_alloc_skb_ip_align(ndev, rx_len); |
709 | if (unlikely(!skb)) { | 780 | if (unlikely(!skb)) { |
710 | w5100_write16(priv, W5100_S0_RX_RD, offset + rx_buf_len); | 781 | w5100_write16(priv, W5100_S0_RX_RD(priv), offset + rx_buf_len); |
711 | w5100_command(priv, S0_CR_RECV); | 782 | w5100_command(priv, S0_CR_RECV); |
712 | ndev->stats.rx_dropped++; | 783 | ndev->stats.rx_dropped++; |
713 | return NULL; | 784 | return NULL; |
@@ -715,7 +786,7 @@ static struct sk_buff *w5100_rx_skb(struct net_device *ndev) | |||
715 | 786 | ||
716 | skb_put(skb, rx_len); | 787 | skb_put(skb, rx_len); |
717 | w5100_readbuf(priv, offset + 2, skb->data, rx_len); | 788 | w5100_readbuf(priv, offset + 2, skb->data, rx_len); |
718 | w5100_write16(priv, W5100_S0_RX_RD, offset + 2 + rx_len); | 789 | w5100_write16(priv, W5100_S0_RX_RD(priv), offset + 2 + rx_len); |
719 | w5100_command(priv, S0_CR_RECV); | 790 | w5100_command(priv, S0_CR_RECV); |
720 | skb->protocol = eth_type_trans(skb, ndev); | 791 | skb->protocol = eth_type_trans(skb, ndev); |
721 | 792 | ||
@@ -764,10 +835,10 @@ static irqreturn_t w5100_interrupt(int irq, void *ndev_instance) | |||
764 | struct net_device *ndev = ndev_instance; | 835 | struct net_device *ndev = ndev_instance; |
765 | struct w5100_priv *priv = netdev_priv(ndev); | 836 | struct w5100_priv *priv = netdev_priv(ndev); |
766 | 837 | ||
767 | int ir = w5100_read(priv, W5100_S0_IR); | 838 | int ir = w5100_read(priv, W5100_S0_IR(priv)); |
768 | if (!ir) | 839 | if (!ir) |
769 | return IRQ_NONE; | 840 | return IRQ_NONE; |
770 | w5100_write(priv, W5100_S0_IR, ir); | 841 | w5100_write(priv, W5100_S0_IR(priv), ir); |
771 | 842 | ||
772 | if (ir & S0_IR_SENDOK) { | 843 | if (ir & S0_IR_SENDOK) { |
773 | netif_dbg(priv, tx_done, ndev, "tx done\n"); | 844 | netif_dbg(priv, tx_done, ndev, "tx done\n"); |
diff --git a/drivers/net/ethernet/wiznet/w5100.h b/drivers/net/ethernet/wiznet/w5100.h index 69045f0f9e10..9b1fa23b46fe 100644 --- a/drivers/net/ethernet/wiznet/w5100.h +++ b/drivers/net/ethernet/wiznet/w5100.h | |||
@@ -7,8 +7,14 @@ | |||
7 | * Licensed under the GPL-2 or later. | 7 | * Licensed under the GPL-2 or later. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | enum { | ||
11 | W5100, | ||
12 | W5200, | ||
13 | }; | ||
14 | |||
10 | struct w5100_ops { | 15 | struct w5100_ops { |
11 | bool may_sleep; | 16 | bool may_sleep; |
17 | int chip_id; | ||
12 | int (*read)(struct net_device *ndev, u16 addr); | 18 | int (*read)(struct net_device *ndev, u16 addr); |
13 | int (*write)(struct net_device *ndev, u16 addr, u8 data); | 19 | int (*write)(struct net_device *ndev, u16 addr, u8 data); |
14 | int (*read16)(struct net_device *ndev, u16 addr); | 20 | int (*read16)(struct net_device *ndev, u16 addr); |