168349Sobrien/*	$NetBSD: if_le.c,v 1.18 2010/01/19 22:06:21 pooka Exp $	*/
268349Sobrien
368349Sobrien/*-
468349Sobrien * Copyright (c) 1996 The NetBSD Foundation, Inc.
568349Sobrien * All rights reserved.
668349Sobrien *
768349Sobrien * This code is derived from software contributed to The NetBSD Foundation
868349Sobrien * by Adam Glass and Gordon W. Ross.
968349Sobrien *
1068349Sobrien * Redistribution and use in source and binary forms, with or without
11133359Sobrien * modification, are permitted provided that the following conditions
1268349Sobrien * are met:
1368349Sobrien * 1. Redistributions of source code must retain the above copyright
1468349Sobrien *    notice, this list of conditions and the following disclaimer.
1568349Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1668349Sobrien *    notice, this list of conditions and the following disclaimer in the
1768349Sobrien *    documentation and/or other materials provided with the distribution.
18133359Sobrien *
19133359Sobrien * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20133359Sobrien * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21133359Sobrien * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22133359Sobrien * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23133359Sobrien * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24133359Sobrien * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25133359Sobrien * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26133359Sobrien * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27133359Sobrien * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28169942Sobrien * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29133359Sobrien * POSSIBILITY OF SUCH DAMAGE.
30133359Sobrien */
31133359Sobrien
32133359Sobrien/*
3368349Sobrien * news68k/dev/if_le.c - based on newsmips/dev/if_le.c
3468349Sobrien */
3568349Sobrien
3668349Sobrien#include <sys/cdefs.h>
3768349Sobrien__KERNEL_RCSID(0, "$NetBSD: if_le.c,v 1.18 2010/01/19 22:06:21 pooka Exp $");
3868349Sobrien
3968349Sobrien#include "opt_inet.h"
4068349Sobrien
41133359Sobrien#include <sys/param.h>
4268349Sobrien#include <sys/systm.h>
4368349Sobrien#include <sys/mbuf.h>
4468349Sobrien#include <sys/socket.h>
4568349Sobrien#include <sys/device.h>
4668349Sobrien
4768349Sobrien#include <net/if.h>
48133359Sobrien#include <net/if_ether.h>
49133359Sobrien#include <net/if_media.h>
50133359Sobrien
51133359Sobrien#ifdef INET
52133359Sobrien#include <netinet/in.h>
53133359Sobrien#include <netinet/if_inarp.h>
54133359Sobrien#endif
55133359Sobrien
56133359Sobrien#include <machine/cpu.h>
57133359Sobrien
58169942Sobrien#include <news68k/dev/hbvar.h>
59133359Sobrien
60133359Sobrien#include <dev/ic/lancereg.h>
61133359Sobrien#include <dev/ic/lancevar.h>
62133359Sobrien#include <dev/ic/am7990reg.h>
6368349Sobrien#include <dev/ic/am7990var.h>
6468349Sobrien
6568349Sobrien#include "ioconf.h"
6668349Sobrien
6768349Sobrien/*
6868349Sobrien * LANCE registers.
6968349Sobrien * The real stuff is in dev/ic/am7990reg.h
70133359Sobrien */
71133359Sobrienstruct lereg1 {
72133359Sobrien	volatile uint16_t	ler1_rdp;	/* data port */
73133359Sobrien	volatile uint16_t	ler1_rap;	/* register select port */
74133359Sobrien};
75133359Sobrien
7668349Sobrien/*
7768349Sobrien * Ethernet software status per interface.
7868349Sobrien * The real stuff is in dev/ic/am7990var.h
7968349Sobrien */
8068349Sobrienstruct	le_softc {
8168349Sobrien	struct	am7990_softc sc_am7990;	/* glue to MI code */
8268349Sobrien
8368349Sobrien	struct	lereg1 *sc_r1;		/* LANCE registers */
8468349Sobrien};
8568349Sobrien
8668349Sobrienstatic int  le_match(device_t, cfdata_t, void *);
8768349Sobrienstatic void le_attach(device_t, device_t, void *);
8868349Sobrien
8968349SobrienCFATTACH_DECL_NEW(le, sizeof(struct le_softc),
9068349Sobrien    le_match, le_attach, NULL, NULL);
9168349Sobrien
9268349Sobrienextern const uint8_t *idrom_addr;
9368349Sobrienextern uint32_t lance_mem_phys;
9468349Sobrien
9568349Sobrien#if defined(_KERNEL_OPT)
9668349Sobrien#include "opt_ddb.h"
9768349Sobrien#endif
9868349Sobrien
9968349Sobrien#ifdef DDB
10068349Sobrien#define	integrate
10168349Sobrien#define hide
10268349Sobrien#else
103133359Sobrien#define	integrate	static inline
104133359Sobrien#define hide		static
105133359Sobrien#endif
10668349Sobrien
107133359Sobrienhide void lewrcsr(struct lance_softc *, uint16_t, uint16_t);
10868349Sobrienhide uint16_t lerdcsr(struct lance_softc *, uint16_t);
109133359Sobrienint leintr(int);
110133359Sobrien
111133359Sobrienhide void
112133359Sobrienlewrcsr(struct lance_softc *sc, uint16_t port, uint16_t val)
11368349Sobrien{
114133359Sobrien	struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1;
11568349Sobrien
11668349Sobrien	ler1->ler1_rap = port;
11768349Sobrien	ler1->ler1_rdp = val;
11868349Sobrien}
11968349Sobrien
12068349Sobrienhide uint16_t
12168349Sobrienlerdcsr(struct lance_softc *sc, uint16_t port)
12268349Sobrien{
12368349Sobrien	struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1;
12468349Sobrien	uint16_t val;
125133359Sobrien
12668349Sobrien	ler1->ler1_rap = port;
12768349Sobrien	val = ler1->ler1_rdp;
128133359Sobrien	return val;
12968349Sobrien}
130133359Sobrien
13168349Sobrienint
132133359Sobrienle_match(device_t parent, cfdata_t cf, void *aux)
133133359Sobrien{
134159764Sobrien	struct hb_attach_args *ha = aux;
135133359Sobrien	int addr;
13668349Sobrien
137133359Sobrien	if (strcmp(ha->ha_name, "le"))
13868349Sobrien		return 0;
139133359Sobrien
14068349Sobrien	addr = (ha->ha_address);
141133359Sobrien
142133359Sobrien	if (badaddr((void *)addr, 1))
143133359Sobrien		return 0;
14468349Sobrien
145133359Sobrien	return 1;
14668349Sobrien}
147133359Sobrien
14868349Sobrienvoid
149133359Sobrienle_attach(device_t parent, device_t self, void *aux)
150133359Sobrien{
151133359Sobrien	struct le_softc *lesc = device_private(self);
15268349Sobrien	struct lance_softc *sc = &lesc->sc_am7990.lsc;
153133359Sobrien	struct hb_attach_args *ha = aux;
15469216Sobrien	const uint8_t *p;
15569216Sobrien
15669216Sobrien	sc->sc_dev = self;
15768349Sobrien	lesc->sc_r1 = (void *)(ha->ha_address);
158133359Sobrien
15968349Sobrien	if (ISIIOPA(ha->ha_address)) {
160133359Sobrien		sc->sc_mem = (u_char *)(lance_mem_phys);
16168349Sobrien		p = idrom_addr + 0x10;
16268349Sobrien	} else {
16368349Sobrien		sc->sc_mem = lesc->sc_r1 - 0x10000;
16468349Sobrien		p = (const uint8_t *)(lesc->sc_r1 + 0x8010);
16568349Sobrien	}
16668349Sobrien
167133359Sobrien	sc->sc_memsize = 0x4000;	/* 16K */
16868349Sobrien	sc->sc_addr = lance_mem_phys & 0x00ffffff;
169133359Sobrien	sc->sc_conf3 = LE_C3_BSWP|LE_C3_BCON;
17068349Sobrien
17168349Sobrien	sc->sc_enaddr[0] = (*p++ << 4);
17268349Sobrien	sc->sc_enaddr[0] |= *p++ & 0x0f;
17368349Sobrien	sc->sc_enaddr[1] = (*p++ << 4);
17468349Sobrien	sc->sc_enaddr[1] |= *p++ & 0x0f;
175133359Sobrien	sc->sc_enaddr[2] = (*p++ << 4);
176133359Sobrien	sc->sc_enaddr[2] |= *p++ & 0x0f;
177133359Sobrien	sc->sc_enaddr[3] = (*p++ << 4);
17869216Sobrien	sc->sc_enaddr[3] |= *p++ & 0x0f;
179133359Sobrien	sc->sc_enaddr[4] = (*p++ << 4);
180133359Sobrien	sc->sc_enaddr[4] |= *p++ & 0x0f;
181133359Sobrien	sc->sc_enaddr[5] = (*p++ << 4);
182133359Sobrien	sc->sc_enaddr[5] |= *p++ & 0x0f;
183133359Sobrien
184133359Sobrien	sc->sc_copytodesc = lance_copytobuf_contig;
185133359Sobrien	sc->sc_copyfromdesc = lance_copyfrombuf_contig;
186133359Sobrien	sc->sc_copytobuf = lance_copytobuf_contig;
187133359Sobrien	sc->sc_copyfrombuf = lance_copyfrombuf_contig;
18869216Sobrien	sc->sc_zerobuf = lance_zerobuf_contig;
18980588Sobrien
19080588Sobrien	sc->sc_rdcsr = lerdcsr;
19169216Sobrien	sc->sc_wrcsr = lewrcsr;
19269216Sobrien	sc->sc_hwinit = NULL;
19380588Sobrien
19469216Sobrien	am7990_config(&lesc->sc_am7990);
19569216Sobrien}
19669216Sobrien
19769216Sobrienint
19869216Sobrienleintr(int unit)
19969216Sobrien{
20069216Sobrien	struct am7990_softc *sc;
201133359Sobrien
202133359Sobrien	if (unit >= le_cd.cd_ndevs)	/* XXX */
203133359Sobrien		return 0;
204133359Sobrien
205133359Sobrien	sc = device_lookup_private(&le_cd, unit);
206133359Sobrien	return am7990_intr(sc);
207133359Sobrien}
208133359Sobrien