1*bb6df0b9Sphx /* $NetBSD: skg.c,v 1.5 2017/08/03 19:51:00 phx Exp $ */
2b75de019Snisimura
3b75de019Snisimura /*-
4b75de019Snisimura * Copyright (c) 2010 Frank Wille.
5b75de019Snisimura * All rights reserved.
6b75de019Snisimura *
7b75de019Snisimura * Written by Frank Wille for The NetBSD Project.
8b75de019Snisimura *
9b75de019Snisimura * Redistribution and use in source and binary forms, with or without
10b75de019Snisimura * modification, are permitted provided that the following conditions
11b75de019Snisimura * are met:
12b75de019Snisimura * 1. Redistributions of source code must retain the above copyright
13b75de019Snisimura * notice, this list of conditions and the following disclaimer.
14b75de019Snisimura * 2. Redistributions in binary form must reproduce the above copyright
15b75de019Snisimura * notice, this list of conditions and the following disclaimer in the
16b75de019Snisimura * documentation and/or other materials provided with the distribution.
17b75de019Snisimura *
18b75de019Snisimura * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19b75de019Snisimura * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20b75de019Snisimura * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21b75de019Snisimura * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22b75de019Snisimura * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23b75de019Snisimura * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24b75de019Snisimura * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25b75de019Snisimura * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26b75de019Snisimura * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27b75de019Snisimura * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28b75de019Snisimura * POSSIBILITY OF SUCH DAMAGE.
29b75de019Snisimura */
30b75de019Snisimura
31b75de019Snisimura #include <sys/param.h>
32b75de019Snisimura
33b75de019Snisimura #include <netinet/in.h>
34b75de019Snisimura #include <netinet/in_systm.h>
35b75de019Snisimura
36b75de019Snisimura #include <lib/libsa/stand.h>
37b75de019Snisimura #include <lib/libsa/net.h>
38b75de019Snisimura
39b75de019Snisimura #include "globals.h"
40b75de019Snisimura
41b75de019Snisimura /*
42b75de019Snisimura * - reverse endian access every CSR.
43b75de019Snisimura * - no vtophys() translation, vaddr_t == paddr_t.
44b75de019Snisimura * - PIPT writeback cache aware.
45b75de019Snisimura */
46767f3b03Sphx #define CSR_WRITE_1(l, r, v) out8((l)->csr+(r), (v))
47767f3b03Sphx #define CSR_READ_1(l, r) in8((l)->csr+(r))
48b75de019Snisimura #define CSR_WRITE_2(l, r, v) out16rb((l)->csr+(r), (v))
49b75de019Snisimura #define CSR_READ_2(l, r) in16rb((l)->csr+(r))
50b75de019Snisimura #define CSR_WRITE_4(l, r, v) out32rb((l)->csr+(r), (v))
51b75de019Snisimura #define CSR_READ_4(l, r) in32rb((l)->csr+(r))
52b75de019Snisimura #define VTOPHYS(va) (uint32_t)(va)
53b75de019Snisimura #define DEVTOV(pa) (uint32_t)(pa)
54b75de019Snisimura #define wbinv(adr, siz) _wbinv(VTOPHYS(adr), (uint32_t)(siz))
55b75de019Snisimura #define inv(adr, siz) _inv(VTOPHYS(adr), (uint32_t)(siz))
56b75de019Snisimura #define DELAY(n) delay(n)
57b75de019Snisimura #define ALLOC(T,A) (T *)allocaligned(sizeof(T),(A))
58b75de019Snisimura
59b75de019Snisimura struct desc {
60b75de019Snisimura uint32_t xd0, xd1, xd2, xd3, xd4;
61b75de019Snisimura uint32_t rsrvd[3];
62b75de019Snisimura };
63b75de019Snisimura #define CTL_LS 0x20000000
64b75de019Snisimura #define CTL_FS 0x40000000
65b75de019Snisimura #define CTL_OWN 0x80000000
66b75de019Snisimura #define CTL_DEFOPC 0x00550000
67b75de019Snisimura #define FRAMEMASK 0x0000ffff
68b75de019Snisimura #define RXSTAT_RXOK 0x00000100
69b75de019Snisimura
70b75de019Snisimura #define SK_CSR 0x0004
71b75de019Snisimura #define CSR_SW_RESET 0x0001
72b75de019Snisimura #define CSR_SW_UNRESET 0x0002
73b75de019Snisimura #define CSR_MASTER_RESET 0x0004
74b75de019Snisimura #define CSR_MASTER_UNRESET 0x0008
75b75de019Snisimura #define SK_IMR 0x000c
76b75de019Snisimura #define SK_BMU_RX_CSR0 0x0060
77b75de019Snisimura #define SK_BMU_TXS_CSR0 0x0068
78b75de019Snisimura #define SK_MAC0 0x0100
79b75de019Snisimura #define SK_MAC1 0x0108
80b75de019Snisimura #define SK_GPIO 0x015c
81b75de019Snisimura #define SK_RAMCTL 0x01a0
82b75de019Snisimura #define SK_TXAR1_COUNTERCTL 0x0210
83b75de019Snisimura #define TXARCTL_ON 0x02
84b75de019Snisimura #define TXARCTL_FSYNC_ON 0x80
85b75de019Snisimura #define SK_RXQ1_CURADDR_LO 0x0420
86b75de019Snisimura #define SK_RXQ1_CURADDR_HI 0x0424
87b75de019Snisimura #define SK_RXQ1_BMU_CSR 0x0434
88b75de019Snisimura #define RXBMU_CLR_IRQ_EOF 0x00000002
89b75de019Snisimura #define RXBMU_RX_START 0x00000010
90b75de019Snisimura #define RXBMU_RX_STOP 0x00000020
91b75de019Snisimura #define RXBMU_POLL_ON 0x00000080
92b75de019Snisimura #define RXBMU_TRANSFER_SM_UNRESET 0x00000200
93b75de019Snisimura #define RXBMU_DESCWR_SM_UNRESET 0x00000800
94b75de019Snisimura #define RXBMU_DESCRD_SM_UNRESET 0x00002000
95b75de019Snisimura #define RXBMU_SUPERVISOR_SM_UNRESET 0x00008000
96b75de019Snisimura #define RXBMU_PFI_SM_UNRESET 0x00020000
97b75de019Snisimura #define RXBMU_FIFO_UNRESET 0x00080000
98b75de019Snisimura #define RXBMU_DESC_UNRESET 0x00200000
99b75de019Snisimura #define SK_TXQS1_CURADDR_LO 0x0620
100b75de019Snisimura #define SK_TXQS1_CURADDR_HI 0x0624
101b75de019Snisimura #define SK_TXQS1_BMU_CSR 0x0634
102b75de019Snisimura #define TXBMU_CLR_IRQ_EOF 0x00000002
103b75de019Snisimura #define TXBMU_TX_START 0x00000010
104b75de019Snisimura #define TXBMU_TX_STOP 0x00000020
105b75de019Snisimura #define TXBMU_POLL_ON 0x00000080
106b75de019Snisimura #define TXBMU_TRANSFER_SM_UNRESET 0x00000200
107b75de019Snisimura #define TXBMU_DESCWR_SM_UNRESET 0x00000800
108b75de019Snisimura #define TXBMU_DESCRD_SM_UNRESET 0x00002000
109b75de019Snisimura #define TXBMU_SUPERVISOR_SM_UNRESET 0x00008000
110b75de019Snisimura #define TXBMU_PFI_SM_UNRESET 0x00020000
111b75de019Snisimura #define TXBMU_FIFO_UNRESET 0x00080000
112b75de019Snisimura #define TXBMU_DESC_UNRESET 0x00200000
113b75de019Snisimura #define SK_RXRB1_START 0x0800
114b75de019Snisimura #define SK_RXRB1_END 0x0804
115b75de019Snisimura #define SK_RXRB1_WR_PTR 0x0808
116b75de019Snisimura #define SK_RXRB1_RD_PTR 0x080c
117b75de019Snisimura #define SK_RXRB1_CTLTST 0x0828
118b75de019Snisimura #define RBCTL_UNRESET 0x02
119b75de019Snisimura #define RBCTL_ON 0x08
120b75de019Snisimura #define RBCTL_STORENFWD_ON 0x20
121b75de019Snisimura #define SK_TXRBS1_START 0x0a00
122b75de019Snisimura #define SK_TXRBS1_END 0x0a04
123b75de019Snisimura #define SK_TXRBS1_WR_PTR 0x0a08
124b75de019Snisimura #define SK_TXRBS1_RD_PTR 0x0a0c
125b75de019Snisimura #define SK_TXRBS1_CTLTST 0x0a28
126b75de019Snisimura #define SK_RXMF1_CTRL_TEST 0x0c48
127b75de019Snisimura #define RFCTL_OPERATION_ON 0x00000008
128b75de019Snisimura #define RFCTL_RESET_CLEAR 0x00000002
129b75de019Snisimura #define SK_TXMF1_CTRL_TEST 0x0D48
130b75de019Snisimura #define TFCTL_OPERATION_ON 0x00000008
131b75de019Snisimura #define TFCTL_RESET_CLEAR 0x00000002
132b75de019Snisimura #define SK_GMAC_CTRL 0x0f00
133b75de019Snisimura #define GMAC_LOOP_OFF 0x00000010
134b75de019Snisimura #define GMAC_PAUSE_ON 0x00000008
135b75de019Snisimura #define GMAC_RESET_CLEAR 0x00000002
136b75de019Snisimura #define GMAC_RESET_SET 0x00000001
137b75de019Snisimura #define SK_GPHY_CTRL 0x0f04
138b75de019Snisimura #define GPHY_INT_POL_HI 0x08000000
139b75de019Snisimura #define GPHY_DIS_FC 0x02000000
140b75de019Snisimura #define GPHY_DIS_SLEEP 0x01000000
141b75de019Snisimura #define GPHY_ENA_XC 0x00040000
142b75de019Snisimura #define GPHY_ENA_PAUSE 0x00002000
143b75de019Snisimura #define GPHY_RESET_CLEAR 0x00000002
144b75de019Snisimura #define GPHY_RESET_SET 0x00000001
145b75de019Snisimura #define GPHY_ANEG_ALL 0x0009c000
146b75de019Snisimura #define GPHY_COPPER 0x00f00000
147b75de019Snisimura #define SK_LINK_CTRL 0x0f10
148b75de019Snisimura #define LINK_RESET_CLEAR 0x0002
149b75de019Snisimura #define LINK_RESET_SET 0x0001
150b75de019Snisimura
151b75de019Snisimura #define YUKON_GPCR 0x2804
152b75de019Snisimura #define GPCR_TXEN 0x1000
153b75de019Snisimura #define GPCR_RXEN 0x0800
154b75de019Snisimura #define YUKON_SA1 0x281c
155b75de019Snisimura #define YUKON_SA2 0x2828
156b75de019Snisimura #define YUKON_SMICR 0x2880
157b75de019Snisimura #define SMICR_PHYAD(x) (((x) & 0x1f) << 11)
158b75de019Snisimura #define SMICR_REGAD(x) (((x) & 0x1f) << 6)
159b75de019Snisimura #define SMICR_OP_READ 0x0020
160b75de019Snisimura #define SMICR_OP_WRITE 0x0000
161b75de019Snisimura #define SMICR_READ_VALID 0x0010
162b75de019Snisimura #define SMICR_BUSY 0x0008
163b75de019Snisimura #define YUKON_SMIDR 0x2884
164b75de019Snisimura
165b75de019Snisimura #define MII_PSSR 0x11 /* MAKPHY status register */
166b75de019Snisimura #define PSSR_DUPLEX 0x2000 /* FDX */
167b75de019Snisimura #define PSSR_RESOLVED 0x0800 /* speed and duplex resolved */
168b75de019Snisimura #define PSSR_LINK 0x0400 /* link indication */
169b75de019Snisimura #define PSSR_SPEED(x) (((x) >> 14) & 0x3)
170b75de019Snisimura #define SPEED10 0
171b75de019Snisimura #define SPEED100 1
172b75de019Snisimura #define SPEED1000 2
173b75de019Snisimura
174b75de019Snisimura #define FRAMESIZE 1536
175b75de019Snisimura
176b75de019Snisimura struct local {
177b75de019Snisimura struct desc txd[2];
178b75de019Snisimura struct desc rxd[2];
179b75de019Snisimura uint8_t rxstore[2][FRAMESIZE];
180b75de019Snisimura unsigned csr, rx, tx, phy;
181b75de019Snisimura uint16_t pssr, anlpar;
182b75de019Snisimura };
183b75de019Snisimura
184b75de019Snisimura static int mii_read(struct local *, int, int);
185b75de019Snisimura static void mii_write(struct local *, int, int, int);
186b75de019Snisimura static void mii_initphy(struct local *);
187b75de019Snisimura static void mii_dealan(struct local *, unsigned);
188b75de019Snisimura
189b75de019Snisimura int
skg_match(unsigned tag,void * data)190b75de019Snisimura skg_match(unsigned tag, void *data)
191b75de019Snisimura {
192b75de019Snisimura unsigned v;
193b75de019Snisimura
194b75de019Snisimura v = pcicfgread(tag, PCI_ID_REG);
195b75de019Snisimura switch (v) {
196*bb6df0b9Sphx case PCI_DEVICE(0x1148, 0x4320):
197b75de019Snisimura case PCI_DEVICE(0x11ab, 0x4320):
198b75de019Snisimura return 1;
199b75de019Snisimura }
200b75de019Snisimura return 0;
201b75de019Snisimura }
202b75de019Snisimura
203b75de019Snisimura void *
skg_init(unsigned tag,void * data)204b75de019Snisimura skg_init(unsigned tag, void *data)
205b75de019Snisimura {
206b75de019Snisimura struct local *l;
207b75de019Snisimura struct desc *txd, *rxd;
208b75de019Snisimura uint8_t *en;
209b75de019Snisimura unsigned i;
210b75de019Snisimura uint16_t reg;
211b75de019Snisimura
212b75de019Snisimura l = ALLOC(struct local, 32); /* desc alignment */
213b75de019Snisimura memset(l, 0, sizeof(struct local));
214b75de019Snisimura l->csr = DEVTOV(pcicfgread(tag, 0x10)); /* use mem space */
215b75de019Snisimura
216fd66150eSphx /* make sure the descriptor bytes are not reversed */
217fd66150eSphx i = pcicfgread(tag, 0x44);
218fd66150eSphx pcicfgwrite(tag, 0x44, i & ~4);
219fd66150eSphx
220b75de019Snisimura /* reset the chip */
221b75de019Snisimura CSR_WRITE_2(l, SK_CSR, CSR_SW_RESET);
222b75de019Snisimura CSR_WRITE_2(l, SK_CSR, CSR_MASTER_RESET);
223b75de019Snisimura CSR_WRITE_2(l, SK_LINK_CTRL, LINK_RESET_SET);
224b75de019Snisimura DELAY(1000);
225b75de019Snisimura CSR_WRITE_2(l, SK_CSR, CSR_SW_UNRESET);
226b75de019Snisimura DELAY(2);
227b75de019Snisimura CSR_WRITE_2(l, SK_CSR, CSR_MASTER_UNRESET);
228b75de019Snisimura CSR_WRITE_2(l, SK_LINK_CTRL, LINK_RESET_CLEAR);
229b75de019Snisimura CSR_WRITE_4(l, SK_RAMCTL, 2); /* enable RAM interface */
230b75de019Snisimura
231b75de019Snisimura mii_initphy(l);
232b75de019Snisimura
233b75de019Snisimura /* read ethernet address */
234b75de019Snisimura en = data;
235b75de019Snisimura if (brdtype == BRD_SYNOLOGY)
236b75de019Snisimura read_mac_from_flash(en);
237b75de019Snisimura else
238b75de019Snisimura for (i = 0; i < 6; i++)
239b75de019Snisimura en[i] = CSR_READ_1(l, SK_MAC0 + i);
240b75de019Snisimura printf("MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
241b75de019Snisimura en[0], en[1], en[2], en[3], en[4], en[5]);
242f752ef75Sphx DPRINTF(("PHY %d (%04x.%04x)\n", l->phy,
243f752ef75Sphx mii_read(l, l->phy, 2), mii_read(l, l->phy, 3)));
244b75de019Snisimura
245b75de019Snisimura /* set station address */
246b75de019Snisimura for (i = 0; i < 3; i++)
247b75de019Snisimura CSR_WRITE_2(l, YUKON_SA1 + i * 4,
248b75de019Snisimura (en[i * 2] << 8) | en[i * 2 + 1]);
249b75de019Snisimura
250b75de019Snisimura /* configure RX and TX MAC FIFO */
251b75de019Snisimura CSR_WRITE_1(l, SK_RXMF1_CTRL_TEST, RFCTL_RESET_CLEAR);
252b75de019Snisimura CSR_WRITE_4(l, SK_RXMF1_CTRL_TEST, RFCTL_OPERATION_ON);
253b75de019Snisimura CSR_WRITE_1(l, SK_TXMF1_CTRL_TEST, TFCTL_RESET_CLEAR);
254b75de019Snisimura CSR_WRITE_4(l, SK_TXMF1_CTRL_TEST, TFCTL_OPERATION_ON);
255b75de019Snisimura
256b75de019Snisimura mii_dealan(l, 5);
257b75de019Snisimura
258b75de019Snisimura switch (PSSR_SPEED(l->pssr)) {
259b75de019Snisimura case SPEED1000:
260b75de019Snisimura printf("1000Mbps");
261b75de019Snisimura break;
262b75de019Snisimura case SPEED100:
263b75de019Snisimura printf("100Mbps");
264b75de019Snisimura break;
265b75de019Snisimura case SPEED10:
266b75de019Snisimura printf("10Mbps");
267b75de019Snisimura break;
268b75de019Snisimura }
269b75de019Snisimura if (l->pssr & PSSR_DUPLEX)
270b75de019Snisimura printf("-FDX");
271b75de019Snisimura printf("\n");
272b75de019Snisimura
273b75de019Snisimura /* configure RAM buffers, assuming 64k RAM */
274b75de019Snisimura CSR_WRITE_4(l, SK_RXRB1_CTLTST, RBCTL_UNRESET);
275b75de019Snisimura CSR_WRITE_4(l, SK_RXRB1_START, 0);
276b75de019Snisimura CSR_WRITE_4(l, SK_RXRB1_WR_PTR, 0);
277b75de019Snisimura CSR_WRITE_4(l, SK_RXRB1_RD_PTR, 0);
278b75de019Snisimura CSR_WRITE_4(l, SK_RXRB1_END, 0xfff);
279b75de019Snisimura CSR_WRITE_4(l, SK_RXRB1_CTLTST, RBCTL_ON);
280b75de019Snisimura CSR_WRITE_4(l, SK_TXRBS1_CTLTST, RBCTL_UNRESET);
281b75de019Snisimura CSR_WRITE_4(l, SK_TXRBS1_CTLTST, RBCTL_STORENFWD_ON);
282b75de019Snisimura CSR_WRITE_4(l, SK_TXRBS1_START, 0x1000);
283b75de019Snisimura CSR_WRITE_4(l, SK_TXRBS1_WR_PTR, 0x1000);
284b75de019Snisimura CSR_WRITE_4(l, SK_TXRBS1_RD_PTR, 0x1000);
285b75de019Snisimura CSR_WRITE_4(l, SK_TXRBS1_END, 0x1fff);
286b75de019Snisimura CSR_WRITE_4(l, SK_TXRBS1_CTLTST, RBCTL_ON);
287b75de019Snisimura
288b75de019Snisimura /* setup descriptors and BMU */
289b75de019Snisimura CSR_WRITE_1(l, SK_TXAR1_COUNTERCTL, TXARCTL_ON|TXARCTL_FSYNC_ON);
290b75de019Snisimura
291b75de019Snisimura txd = &l->txd[0];
292b75de019Snisimura txd[0].xd1 = htole32(VTOPHYS(&txd[1]));
293b75de019Snisimura txd[1].xd1 = htole32(VTOPHYS(&txd[0]));
294b75de019Snisimura rxd = &l->rxd[0];
295b75de019Snisimura rxd[0].xd0 = htole32(FRAMESIZE|CTL_DEFOPC|CTL_LS|CTL_FS|CTL_OWN);
296b75de019Snisimura rxd[0].xd1 = htole32(VTOPHYS(&rxd[1]));
297b75de019Snisimura rxd[0].xd2 = htole32(VTOPHYS(l->rxstore[0]));
298b75de019Snisimura rxd[1].xd0 = htole32(FRAMESIZE|CTL_DEFOPC|CTL_LS|CTL_FS|CTL_OWN);
299b75de019Snisimura rxd[1].xd1 = htole32(VTOPHYS(&rxd[0]));
300b75de019Snisimura rxd[1].xd2 = htole32(VTOPHYS(l->rxstore[1]));
301b75de019Snisimura wbinv(l, sizeof(struct local));
302b75de019Snisimura
303b75de019Snisimura CSR_WRITE_4(l, SK_RXQ1_BMU_CSR,
304b75de019Snisimura RXBMU_TRANSFER_SM_UNRESET|RXBMU_DESCWR_SM_UNRESET|
305b75de019Snisimura RXBMU_DESCRD_SM_UNRESET|RXBMU_SUPERVISOR_SM_UNRESET|
306b75de019Snisimura RXBMU_PFI_SM_UNRESET|RXBMU_FIFO_UNRESET|
307b75de019Snisimura RXBMU_DESC_UNRESET);
308b75de019Snisimura CSR_WRITE_4(l, SK_RXQ1_CURADDR_LO, VTOPHYS(rxd));
309b75de019Snisimura CSR_WRITE_4(l, SK_RXQ1_CURADDR_HI, 0);
310b75de019Snisimura
311b75de019Snisimura CSR_WRITE_4(l, SK_TXQS1_BMU_CSR,
312b75de019Snisimura TXBMU_TRANSFER_SM_UNRESET|TXBMU_DESCWR_SM_UNRESET|
313b75de019Snisimura TXBMU_DESCRD_SM_UNRESET|TXBMU_SUPERVISOR_SM_UNRESET|
314b75de019Snisimura TXBMU_PFI_SM_UNRESET|TXBMU_FIFO_UNRESET|
315b75de019Snisimura TXBMU_DESC_UNRESET|TXBMU_POLL_ON);
316b75de019Snisimura CSR_WRITE_4(l, SK_TXQS1_CURADDR_LO, VTOPHYS(txd));
317b75de019Snisimura CSR_WRITE_4(l, SK_TXQS1_CURADDR_HI, 0);
318b75de019Snisimura
319b75de019Snisimura CSR_WRITE_4(l, SK_IMR, 0);
320b75de019Snisimura CSR_WRITE_4(l, SK_RXQ1_BMU_CSR, RXBMU_RX_START);
321b75de019Snisimura reg = CSR_READ_2(l, YUKON_GPCR);
322b75de019Snisimura reg |= GPCR_TXEN | GPCR_RXEN;
323b75de019Snisimura CSR_WRITE_2(l, YUKON_GPCR, reg);
324b75de019Snisimura
325b75de019Snisimura return l;
326b75de019Snisimura }
327b75de019Snisimura
328b75de019Snisimura int
skg_send(void * dev,char * buf,unsigned len)329b75de019Snisimura skg_send(void *dev, char *buf, unsigned len)
330b75de019Snisimura {
331b75de019Snisimura struct local *l = dev;
332b75de019Snisimura volatile struct desc *txd;
333b75de019Snisimura unsigned loop;
334b75de019Snisimura
335b75de019Snisimura wbinv(buf, len);
336b75de019Snisimura txd = &l->txd[l->tx];
337b75de019Snisimura txd->xd2 = htole32(VTOPHYS(buf));
338b75de019Snisimura txd->xd0 = htole32((len & FRAMEMASK)|CTL_DEFOPC|CTL_FS|CTL_LS|CTL_OWN);
339b75de019Snisimura wbinv(txd, sizeof(struct desc));
340b75de019Snisimura CSR_WRITE_4(l, SK_BMU_TXS_CSR0, TXBMU_TX_START);
341b75de019Snisimura loop = 100;
342b75de019Snisimura do {
343b75de019Snisimura if ((le32toh(txd->xd0) & CTL_OWN) == 0)
344b75de019Snisimura goto done;
345b75de019Snisimura DELAY(10);
346b75de019Snisimura inv(txd, sizeof(struct desc));
347b75de019Snisimura } while (--loop > 0);
348b75de019Snisimura printf("xmit failed\n");
349b75de019Snisimura return -1;
350b75de019Snisimura done:
351b75de019Snisimura l->tx ^= 1;
352b75de019Snisimura return len;
353b75de019Snisimura }
354b75de019Snisimura
355b75de019Snisimura int
skg_recv(void * dev,char * buf,unsigned maxlen,unsigned timo)356b75de019Snisimura skg_recv(void *dev, char *buf, unsigned maxlen, unsigned timo)
357b75de019Snisimura {
358b75de019Snisimura struct local *l = dev;
359b75de019Snisimura volatile struct desc *rxd;
360b75de019Snisimura unsigned bound, ctl, rxstat, len;
361b75de019Snisimura uint8_t *ptr;
362b75de019Snisimura
363b75de019Snisimura bound = 1000 * timo;
364b75de019Snisimura #if 0
365b75de019Snisimura printf("recving with %u sec. timeout\n", timo);
366b75de019Snisimura #endif
367b75de019Snisimura again:
368b75de019Snisimura rxd = &l->rxd[l->rx];
369b75de019Snisimura do {
370b75de019Snisimura inv(rxd, sizeof(struct desc));
371b75de019Snisimura ctl = le32toh(rxd->xd0);
372b75de019Snisimura if ((ctl & CTL_OWN) == 0)
373b75de019Snisimura goto gotone;
374b75de019Snisimura DELAY(1000); /* 1 milli second */
375b75de019Snisimura } while (--bound > 0);
376b75de019Snisimura errno = 0;
377b75de019Snisimura return -1;
378b75de019Snisimura gotone:
379b75de019Snisimura rxstat = le32toh(rxd->xd4);
380b75de019Snisimura if ((rxstat & RXSTAT_RXOK) == 0) {
381b75de019Snisimura rxd->xd0 = htole32(FRAMESIZE|CTL_DEFOPC|CTL_LS|CTL_FS|CTL_OWN);
382b75de019Snisimura wbinv(rxd, sizeof(struct desc));
383b75de019Snisimura l->rx ^= 1;
384b75de019Snisimura goto again;
385b75de019Snisimura }
386b75de019Snisimura len = ctl & FRAMEMASK;
387b75de019Snisimura if (len > maxlen)
388b75de019Snisimura len = maxlen;
389b75de019Snisimura ptr = l->rxstore[l->rx];
390b75de019Snisimura inv(ptr, len);
391b75de019Snisimura memcpy(buf, ptr, len);
392b75de019Snisimura rxd->xd0 = htole32(FRAMESIZE|CTL_DEFOPC|CTL_LS|CTL_FS|CTL_OWN);
393b75de019Snisimura wbinv(rxd, sizeof(struct desc));
394b75de019Snisimura l->rx ^= 1;
395b75de019Snisimura return len;
396b75de019Snisimura }
397b75de019Snisimura
398b75de019Snisimura static int
mii_read(struct local * l,int phy,int reg)399b75de019Snisimura mii_read(struct local *l, int phy, int reg)
400b75de019Snisimura {
401b75de019Snisimura unsigned loop, v;
402b75de019Snisimura
403b75de019Snisimura CSR_WRITE_2(l, YUKON_SMICR, SMICR_PHYAD(phy) | SMICR_REGAD(reg) |
404b75de019Snisimura SMICR_OP_READ);
405b75de019Snisimura loop = 1000;
406b75de019Snisimura do {
407b75de019Snisimura DELAY(1);
408b75de019Snisimura v = CSR_READ_2(l, YUKON_SMICR);
409b75de019Snisimura } while ((v & SMICR_READ_VALID) == 0 && --loop);
410b75de019Snisimura if (loop == 0) {
411b75de019Snisimura printf("mii_read timeout!\n");
412b75de019Snisimura return 0;
413b75de019Snisimura }
414b75de019Snisimura return CSR_READ_2(l, YUKON_SMIDR);
415b75de019Snisimura }
416b75de019Snisimura
417b75de019Snisimura static void
mii_write(struct local * l,int phy,int reg,int data)418b75de019Snisimura mii_write(struct local *l, int phy, int reg, int data)
419b75de019Snisimura {
420b75de019Snisimura unsigned loop, v;
421b75de019Snisimura
422b75de019Snisimura CSR_WRITE_2(l, YUKON_SMIDR, data);
423b75de019Snisimura CSR_WRITE_2(l, YUKON_SMICR, SMICR_PHYAD(phy) | SMICR_REGAD(reg) |
424b75de019Snisimura SMICR_OP_WRITE);
425b75de019Snisimura loop = 1000;
426b75de019Snisimura do {
427b75de019Snisimura DELAY(1);
428b75de019Snisimura v = CSR_READ_2(l, YUKON_SMICR);
429b75de019Snisimura } while ((v & SMICR_BUSY) != 0 && --loop);
430b75de019Snisimura if (loop == 0)
431b75de019Snisimura printf("mii_write timeout!\n");
432b75de019Snisimura }
433b75de019Snisimura
434b75de019Snisimura #define MII_BMCR 0x00 /* Basic mode control register (rw) */
435b75de019Snisimura #define BMCR_AUTOEN 0x1000 /* autonegotiation enable */
436b75de019Snisimura #define BMCR_STARTNEG 0x0200 /* restart autonegotiation */
437b75de019Snisimura #define MII_BMSR 0x01 /* Basic mode status register (ro) */
438b75de019Snisimura #define BMSR_ACOMP 0x0020 /* Autonegotiation complete */
439b75de019Snisimura #define BMSR_LINK 0x0004 /* Link status */
440b75de019Snisimura #define MII_ANAR 0x04 /* Autonegotiation advertisement (rw) */
441b75de019Snisimura #define ANAR_FC 0x0400 /* local device supports PAUSE */
442b75de019Snisimura #define ANAR_TX_FD 0x0100 /* local device supports 100bTx FD */
443b75de019Snisimura #define ANAR_TX 0x0080 /* local device supports 100bTx */
444b75de019Snisimura #define ANAR_10_FD 0x0040 /* local device supports 10bT FD */
445b75de019Snisimura #define ANAR_10 0x0020 /* local device supports 10bT */
446b75de019Snisimura #define ANAR_CSMA 0x0001 /* protocol selector CSMA/CD */
447b75de019Snisimura #define MII_ANLPAR 0x05 /* Autonegotiation lnk partner abilities (rw) */
448b75de019Snisimura #define MII_GTCR 0x09 /* 1000baseT control */
449b75de019Snisimura #define GANA_1000TFDX 0x0200 /* advertise 1000baseT FDX */
450b75de019Snisimura #define GANA_1000THDX 0x0100 /* advertise 1000baseT HDX */
451b75de019Snisimura #define MII_GTSR 0x0a /* 1000baseT status */
452b75de019Snisimura #define GLPA_1000TFDX 0x0800 /* link partner 1000baseT FDX capable */
453b75de019Snisimura #define GLPA_1000THDX 0x0400 /* link partner 1000baseT HDX capable */
454b75de019Snisimura
455b75de019Snisimura static void
mii_initphy(struct local * l)456b75de019Snisimura mii_initphy(struct local *l)
457b75de019Snisimura {
458b75de019Snisimura unsigned val;
459b75de019Snisimura
460b75de019Snisimura l->phy = 0;
461b75de019Snisimura
462b75de019Snisimura /* take PHY out of reset */
463b75de019Snisimura val = CSR_READ_4(l, SK_GPIO);
464b75de019Snisimura CSR_WRITE_4(l, SK_GPIO, (val | 0x2000000) & ~0x200);
465b75de019Snisimura
466b75de019Snisimura /* GMAC and GPHY reset */
467b75de019Snisimura CSR_WRITE_4(l, SK_GPHY_CTRL, GPHY_RESET_SET);
468b75de019Snisimura CSR_WRITE_4(l, SK_GMAC_CTRL, GMAC_RESET_SET);
469b75de019Snisimura DELAY(1000);
470b75de019Snisimura CSR_WRITE_4(l, SK_GMAC_CTRL, GMAC_RESET_CLEAR);
471b75de019Snisimura CSR_WRITE_4(l, SK_GMAC_CTRL, GMAC_RESET_SET);
472b75de019Snisimura DELAY(1000);
473b75de019Snisimura
474b75de019Snisimura val = GPHY_INT_POL_HI | GPHY_DIS_FC | GPHY_DIS_SLEEP | GPHY_ENA_XC |
475b75de019Snisimura GPHY_ANEG_ALL | GPHY_ENA_PAUSE | GPHY_COPPER;
476b75de019Snisimura CSR_WRITE_4(l, SK_GPHY_CTRL, val | GPHY_RESET_SET);
477b75de019Snisimura DELAY(1000);
478b75de019Snisimura CSR_WRITE_4(l, SK_GPHY_CTRL, val | GPHY_RESET_CLEAR);
479b75de019Snisimura CSR_WRITE_4(l, SK_GMAC_CTRL, GMAC_LOOP_OFF | GMAC_PAUSE_ON |
480b75de019Snisimura GMAC_RESET_CLEAR);
481b75de019Snisimura }
482b75de019Snisimura
483b75de019Snisimura static void
mii_dealan(struct local * l,unsigned timo)484b75de019Snisimura mii_dealan(struct local *l, unsigned timo)
485b75de019Snisimura {
486b75de019Snisimura unsigned bmsr, bound;
487b75de019Snisimura
488b75de019Snisimura mii_write(l, l->phy, MII_ANAR, ANAR_TX_FD | ANAR_TX | ANAR_10_FD |
489b75de019Snisimura ANAR_10 | ANAR_CSMA | ANAR_FC);
490b75de019Snisimura mii_write(l, l->phy, MII_GTCR, GANA_1000TFDX | GANA_1000THDX);
491b75de019Snisimura mii_write(l, l->phy, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
492b75de019Snisimura l->anlpar = 0;
493b75de019Snisimura bound = getsecs() + timo;
494b75de019Snisimura do {
495b75de019Snisimura bmsr = mii_read(l, l->phy, MII_BMSR) |
496b75de019Snisimura mii_read(l, l->phy, MII_BMSR); /* read twice */
497b75de019Snisimura if ((bmsr & BMSR_LINK) && (bmsr & BMSR_ACOMP)) {
498b75de019Snisimura l->pssr = mii_read(l, l->phy, MII_PSSR);
499b75de019Snisimura l->anlpar = mii_read(l, l->phy, MII_ANLPAR);
500b75de019Snisimura if ((l->pssr & PSSR_RESOLVED) == 0)
501b75de019Snisimura continue;
502b75de019Snisimura break;
503b75de019Snisimura }
504b75de019Snisimura DELAY(10 * 1000);
505b75de019Snisimura } while (getsecs() < bound);
506b75de019Snisimura }
507