xref: /netbsd-src/sys/arch/sandpoint/stand/altboot/skg.c (revision bb6df0b9c35e420f32a76cf78175fd7f3016a7bf)
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