/*-
* Copyright (c) 2011 Frank Wille.
* All rights reserved.
*
* Written by Frank Wille for The NetBSD Project.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
static void stg_reset(struct local *);
static int mii_read(struct local *, int, int);
static void mii_write(struct local *, int, int, int);
static void mii_initphy(struct local *);
static void mii_dealan(struct local *, unsigned);
static void mii_bitbang_sync(struct local *);
static void mii_bitbang_send(struct local *, uint32_t, int);
static void mii_bitbang_clk(struct local *, uint8_t);
static int eeprom_wait(struct local *);
int
stg_match(unsigned tag, void *data)
{
unsigned v;
v = pcicfgread(tag, PCI_ID_REG);
switch (v) {
case PCI_DEVICE(0x13f0, 0x1023): /* ST1023, IP1000A */
return 1;
}
return 0;
}
for (i = 0; i < 3; i++) {
if (eeprom_wait(l) != 0)
printf("NIC: serial EEPROM is not ready!\n");
CSR_WRITE_2(l, STGE_EepromCtrl,
EC_EepromAddress(STGE_EEPROM_SA0 + i) |
EC_EepromOpcode(EC_OP_RR));
if (eeprom_wait(l) != 0)
printf("NIC: serial EEPROM read time out!\n");
addr[i] = le16toh(CSR_READ_2(l, STGE_EepromData));
}
(void)memcpy(en, addr, 6);
/* try to read MAC from Flash, when EEPROM is empty/missing */
if (memcmp(en, bad[0], 6) == 0 || memcmp(en, bad[1], 6) == 0)
read_mac_from_flash(en);
/* set the station address now */
for (i = 0; i < 6; i++)
CSR_WRITE_1(l, STGE_StationAddress0 + i, en[i]);
}
/* auto negotiation, set the current media */
mii_dealan(l, 5);
reg = CSR_READ_1(l, STGE_PhyCtrl);
switch (PC_LinkSpeed(reg)) {
case PC_LinkSpeed_1000:
printf("1000Mbps");
break;
case PC_LinkSpeed_100:
printf("100Mbps");
break;
case PC_LinkSpeed_10:
printf("10Mbps");
break;
}
if (reg & PC_PhyDuplexStatus) {
macctl |= MC_DuplexSelect;
printf("-FDX");
}
printf("\n");
CSR_WRITE_4(l, STGE_MACCtrl, macctl);
return l;
}
void
stg_shutdown(void *dev)
{
struct local *l = dev;
/*
* We have to reset the chip, when we don't need it anymore,
* otherwise bad things will happen (e.g. the DSM-G600 will no
* longer be able to reboot).
*/
stg_reset(l);
}
int
stg_send(void *dev, char *buf, unsigned len)
{
struct local *l = dev;
volatile struct desc *txd;
unsigned loop;
/* switch direction to PHY->host */
v = l->phyctrl_saved;
CSR_WRITE_1(l, STGE_PhyCtrl, v);
/* read data */
data = 0;
for (i = 0; i < 18; i++) { /* 2TA + 16DATA */
data <<= 1;
data |= !!(CSR_READ_1(l, STGE_PhyCtrl) & PC_MgmtData);
mii_bitbang_clk(l, v);
}
return data & 0xffff;
}
/* write the MII by bitbanging STGE_PhyCtrl */
static void
mii_write(struct local *l, int phy, int reg, int val)
{
unsigned data;
data = (W0101 << 28) | (phy << 23) | (reg << 18) | (A10 << 16);
data |= val;