Exemplo n.º 1
2
static inline void phy_reg_set_bits(ec_priv_t * ecp, unsigned short reg_addr, int bits)
{
	unsigned short reg_val;
	reg_val = read_phy_reg(ecp, reg_addr);
	reg_val |= (unsigned short)bits;
	printk(KERN_DEBUG" %s %d write reg_val:0x%x\n", __FUNCTION__,__LINE__,reg_val);
	write_phy_reg(ecp, reg_addr, reg_val);
	reg_val = read_phy_reg(ecp, reg_addr);
	printk(KERN_DEBUG" %s %d write after read reg_val:0x%x\n", __FUNCTION__,__LINE__,reg_val);
}
Exemplo n.º 2
2
/**
 * fdp110_setup_loopback -- setup or disable loopback
 * return 0 if success, negative value if fail
 */
static int fdp110_setup_loopback(ec_priv_t * ecp, bool loopback)
{
    int     bmcr;
    int     err = 0;
    bool    changed = false;

    bmcr = read_phy_reg(ecp, MII_BMCR);
    if (bmcr < 0) {
        return (bmcr);
    }

    if (loopback) {
        if (!(bmcr & BMCR_LOOPBACK)) {
            bmcr |= BMCR_LOOPBACK;
            changed = true;
        }
    } else {
        if (bmcr & BMCR_LOOPBACK) {
            bmcr &= ~BMCR_LOOPBACK;
            changed = true;
        }
    }

    if (changed) {
        err = write_phy_reg(ecp, MII_BMCR, bmcr);
    }
    printk(KERN_INFO"changed - %s \n", changed ? "true" : "false");

    return (err);
}
Exemplo n.º 3
2
/**
 * fdp110_setup_forced -- configure phy work on @speed and @duplex mode forciblly
 * NOTE: this will close auto-neg function
 * return 0 if success, negative value if fail
 */
static int fdp110_setup_forced(ec_priv_t * ecp, int speed, int duplex)
{
    int     err = 0;
    int     eval;
    int     bmcr;

    bmcr = read_phy_reg(ecp, MII_BMCR);
    if (bmcr < 0) {
        printk(KERN_ERR"error read bmcr\n");
        return (-1);
    }

    eval = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX);
    if (ETH_SPEED_100M == speed) {
        eval |= BMCR_SPEED100;
    }
    if (ETH_DUP_FULL == duplex) {
        eval |= BMCR_FULLDPLX;
    }
    if (eval != bmcr) {
        err = write_phy_reg(ecp, MII_BMCR, eval);
    }

    return (err);
}
Exemplo n.º 4
2
/**
 * fdp110_setup_advert -- set auto-negotiation advertisement
 * return positive value wrote to ANAR reg if success, negative value if fail 
 */
static int fdp110_setup_advert(ec_priv_t * ecp, int advertising)
{
    int     adv;
    int     err;
    const int supported = ADVERTISE_ALL | ADVERTISE_PAUSE_CAP;

    adv = read_phy_reg(ecp, MII_ADVERTISE);
    if (adv < 0) {
        return (adv);
    }

    /* remove old supported features, but maintain others bit */
    adv &= ~supported;
    if (!(advertising & supported)) {
        return (-1);
    }
    adv |= (advertising & supported);
    err = write_phy_reg(ecp, MII_ADVERTISE, adv);
    if (err < 0) {
        return (err);
    }

    /* in fact, when we set new value to phy's advertisement reg, phy will auto-neg again,
     * but some times it don't, so we manually force it auto-neg again.
     * we don't wait for auto-neg completion, link change interrupt will capture it
     */
    err = restart_autoneg(ecp);

    return (err < 0 ? err : adv);
}
Exemplo n.º 5
0
/**
 * fdp110_setup_aneg - setup  or disable  auto-negotiation;
 * if enable auto-neg, we enable and restart auto-neg, don't wait for it completion
 * link change interrupt can capture it
 * if disable auto-neg, but auto-neg is already disabled, then nothing to do, 
 * else disable auto-neg
 * return 0 if success, negative value if fail
 */
static int fdp110_setup_aneg(ec_priv_t * ecp, bool autoneg)
{
    int     bmcr;
    int     err;

    bmcr = read_phy_reg(ecp, MII_BMCR);
    if (bmcr < 0) {
        return (bmcr);
    }

    if (autoneg) {
        bmcr |= BMCR_ANENABLE | BMCR_ANRESTART;
        err = write_phy_reg(ecp, MII_BMCR, bmcr);
        if (err < 0)
            return (err);
    } else if (bmcr & BMCR_ANENABLE) {
        printk(KERN_INFO"disable auto-neg\n");
        bmcr &= ~BMCR_ANENABLE;
        err = write_phy_reg(ecp, MII_BMCR, bmcr);
        if (err < 0)
            return (err);
    }

    return (0);
}
Exemplo n.º 6
0
static void check_phy_register(u64 regbase, u32 addr, u32 physel, u8 xdata)
{
	u8 data;

	data = read_phy_reg(regbase, addr, physel);
	pr_info("PHY read addr = 0x%x physel = %d data = 0x%x %s\n",
		addr, physel, data, data == xdata ? "TRUE" : "FALSE");
}
Exemplo n.º 7
0
static inline void phy_reg_clear_bits(ec_priv_t * ecp, unsigned short reg_addr, int bits)
{
	unsigned short reg_val;

	reg_val = read_phy_reg(ecp, reg_addr);
	reg_val &= ~(unsigned short)bits;
	write_phy_reg(ecp, reg_addr, reg_val);
}
Exemplo n.º 8
0
/**
 * fdp110_get_link - get link state;
 * we alse can get link status from MAC_CSR5[LCIS]
 * return 0 if link not established, 1 if established, negative value if fail
 */
static int fdp110_get_link(ec_priv_t * ecp)
{
    int     bmsr;

    bmsr = read_phy_reg(ecp, MII_BMSR);
    if (bmsr < 0) {
        return (bmsr);
    }

    return (!!(bmsr & BMSR_LSTATUS));
}
Exemplo n.º 9
0
static inline int restart_autoneg(ec_priv_t * ecp)
{
    int     bmcr_val;

    bmcr_val = read_phy_reg(ecp, MII_BMCR);
    if (bmcr_val < 0) {
        return (bmcr_val);
    }

    bmcr_val |= BMCR_ANENABLE | BMCR_ANRESTART;
    return (write_phy_reg(ecp, MII_BMCR, bmcr_val));
}
Exemplo n.º 10
0
/**
 * fdp110_suspend -- power down or power on the phy
 * return 0 if success, negative if fail
 */
static int fdp110_suspend(ec_priv_t * ecp, bool power_down)
{
    int     reg_val;

    reg_val = read_phy_reg(ecp, MII_BMCR);
    if (reg_val < 0) {
        return (reg_val);
    }

    if (power_down) {
        reg_val |= BMCR_PDOWN;
    } else {
        reg_val &= ~BMCR_PDOWN;
    }

    return (write_phy_reg(ecp, MII_BMCR, reg_val));

}
Exemplo n.º 11
0
// Speed = 0: AUTO 1: 100M 2: 10M
int set_network_speed(unsigned char *net_device, int net_speed)
{
  unsigned int reg_num, reg_val;
  reg_num = 0;
  int speed;
  
  if ((net_speed==ETH_10MHD)||(net_speed==ETH_10MFD))
      speed=2;
  else if ((net_speed==ETH_100MHD)||(net_speed==ETH_100MFD))
      speed=1;
  else
      speed=0;
  
  if (read_phy_reg(net_device, reg_num, &reg_val) == -1)
    return -1;

  if (speed)
    reg_val &= ~BMCR_ANENABLE;
  else
    reg_val |= BMCR_ANENABLE;

  if (write_phy_reg(net_device, reg_num, reg_val) == -1)
    return -1;

  switch (speed)
  {
    case 0:
      return 0;
    case 1:
      reg_val &= ~BMCR_ANENABLE;
      reg_val |= BMCR_SPEED100;
      break;
    case 2:
      reg_val &= ~(BMCR_ANENABLE|BMCR_SPEED100);
      break;
    default:
      return -1;
  }

  if (write_phy_reg(net_device, reg_num, reg_val) == -1)
    return -1;

  return 0;
}
Exemplo n.º 12
0
static inline int wait_for_aneg_completion(ec_priv_t * ecp)
{
    int     wait;
    int     reg_val;
    for (wait = PHY_AUTONEG_TIME_OUT; wait > 0; wait--) {
        if (suspend_flag == 1) {
            suspend_flag = 0;
            break;
        }
        reg_val = read_phy_reg(ecp, MII_BMSR);
        if (reg_val & BMSR_ANEGCOMPLETE)
            break;

        mdelay(100);
        printk(KERN_DEBUG"%s", (wait % 200) ? "*" : "\n");
    }
    printk(KERN_DEBUG"exit\n");

    return (!wait);
}
Exemplo n.º 13
0
static int atc2605_hw_init(ec_priv_t *ecp)
{
	unsigned short atc260x_temp;
	struct atc260x_dev *atc260x = ecp->atc260x;

	/*ethernet mfp0 RMII 1st*/
	//hw_rmii_get_pin();
	//mac_rmii_get_pin();
	/************************phy init*****************************/
	/*enable phy clock*/
	atc260x_reg_setbits(atc260x, atc2603_CMU_DEVRST, 0x200, 0x200);
	udelay(100);

	/*ethernet wrapper rest*/
	atc260x_reg_setbits(atc260x, atc2603_CMU_DEVRST, 0x08, 0x0);
	udelay(100);
	atc260x_reg_setbits(atc260x, atc2603_CMU_DEVRST, 0x08, 0x08);
	udelay(100);

	/*GL5302 PHY avoid reboot bug, reset PLL*/
	atc260x_reg_setbits(atc260x, atc2603_PHY_PLL_CTL0, 0x03, 0x02); //25Mhz
	mdelay(5);
	atc260x_reg_setbits(atc260x, atc2603_PHY_PLL_CTL1, 0x200, 0x200);//bit9=1,enetpll ALV LDO enable
	mdelay(200);

	atc260x_reg_setbits(atc260x, atc2603_PHY_PLL_CTL0, 0x03, 0x01); //bit0=1,bit1=0,ethernet pll enable ,24Mhz
	mdelay(1);
	/* 5203 PAD_CLKO_25M output 25MHz clock to 2605 */
	atc260x_reg_setbits(atc260x, atc2603_PHY_PLL_CTL0, 0x03, 0x03); //25Mhz
	mdelay(5);

	atc260x_reg_write(atc260x, atc2603_PHY_CONFIG, 0x00);	    //auto, phy power on
	atc260x_reg_write(atc260x, atc2603_PHY_ADDR, 0x01);		    //set phy address=  0x01
	atc260x_reg_write(atc260x, atc2603_PHY_CTRL, 0x01);	        //rmii,100Mbps

	//add  modify
	atc260x_reg_write(atc260x, atc2603_PHY_HW_RST, 0x01);	    //reset the phy
	udelay(100);
	do
	{
		atc260x_temp = atc260x_reg_read(atc260x, atc2603_PHY_HW_RST);
	}while(atc260x_temp & 0x1); //waite for reset process completion

	/*enable RMII_REF_CLK and EXTIRQ pad and disable the other 6 RMII pad, gl5302 bug amend*/
	atc260x_reg_setbits(atc260x, atc2603_PAD_EN, 0xff, 0x81);
	udelay(100);

	//pad_drv level 3 for fpga test
	atc260x_reg_setbits(atc260x, atc2603_PAD_DRV1, 0xfff, 0x145);
	//atc260x_reg_setbits(atc260x, atc2603_PAD_DRV1, 0xfff, 0x28a); //level 4
	printk("5302 PAD_EN: 0x%x\n", (uint)atc260x_reg_read(atc260x, atc2603_PAD_EN));
	printk("5302 PAD_DRV1: 0x%x\n", (uint)atc260x_reg_read(atc260x, atc2603_PAD_DRV1));

	atc260x_reg_setbits(atc260x, atc2603_PHY_INT_CTRL, 0xf, 0xf);   //enable phy int control

	/*clear phy INT_STAT*/
	atc260x_reg_write(ecp->atc260x, atc2603_PHY_INT_STAT, 0xff);
	//printk("1f.atc2603_PHY_INT_STAT:0x%x\n", atc260x_reg_read(atc260x, gl5302_PHY_INT_STAT));
	udelay(100);

	printk("5302 MFP_CTL0: 0x%x\n", (uint)atc260x_reg_read(atc260x, atc2603_MFP_CTL0));

#ifdef ETHENRET_PHY_LOOP_BACK
	/* phy loopback */
	//atc260x_reg_setbits(atc260x, atc2603_PHY_CONFIG, 0x1 << 11, 0x1 << 11);
	printk("phy config: 0x%x\n", (uint)atc260x_reg_read(atc260x, atc2603_PHY_CONFIG));
	{
		/* shut auto-negoiation */
		ushort bmcr = read_phy_reg(ecp, MII_BMCR);
		bmcr &= ~BMCR_ANENABLE;
		write_phy_reg(ecp, MII_BMCR, bmcr);

		bmcr = read_phy_reg(ecp, MII_BMCR);
		bmcr |= BMCR_LOOPBACK;
		write_phy_reg(ecp, MII_BMCR, bmcr);
		printk("phy bmcr: 0x%x\n", (uint)read_phy_reg(ecp, MII_BMCR));
	}
#endif
	return 0;
}
Exemplo n.º 14
0
/**
 * fdp110_read_status -- read phy's status, according phy ancr, anar & anlpar regs
 * return 0 if success, negative value if fail
 */
static int fdp110_read_status(ec_priv_t * ecp)
{
    int     adv;
    int     lpa;
    //int     bmsr;
    int     bmcr;
    //int     aner;
    int speed;
    int duplex;

    if (wait_for_aneg_completion(ecp)) {
        printk(KERN_INFO"MII_BMCR:0x%x\n", read_phy_reg(ecp, MII_BMCR));
        printk(KERN_INFO"auto-negotiation is timeout.\n");
        return (-1);
    }

    bmcr = read_phy_reg(ecp, MII_BMCR);
    if (bmcr < 0)
        return (bmcr);

#if 0 /* FIXME: should check if both side have auto-negotiation ability */
    bmsr = read_phy_reg(ecp, MII_BMSR);
    if (bmsr < 0)
        return (bmsr);

    aner = read_phy_reg(ecp, MII_EXPANSION);
    if (aner < 0)
        return (aner);

    ecp->autoneg = aner & EXPANSION_NWAY ? true : false;
#else
    ecp->autoneg = bmcr & BMCR_ANENABLE ? true : false;
#endif
    printk(KERN_DEBUG"ecp->autoneg:%d", (int)ecp->autoneg);

    if (ecp->autoneg) {
        lpa = read_phy_reg(ecp, MII_LPA);
        if (lpa < 0) {
            printk(KERN_ERR"lpa error : 0x%x\n", lpa);
            return (lpa);
        }

        adv = read_phy_reg(ecp, MII_ADVERTISE);
        if (adv < 0) {
            printk(KERN_ERR"adv error : 0x%x\n", adv);
            return (adv);
        }

        /* mii anar and'd anlpar to get mii abilities
         * there is a priority order according to ieee 802.3u, as follow
         * 100M-full, 100MbaseT4, 100M-half, 10M-full and last 10M-half
         * fdp110 don't support 100MbaseT4
         */
        lpa &= adv;
        ecp->speed = ETH_SPEED_10M;
        ecp->duplex = ETH_DUP_HALF;

        if ((lpa & (LPA_100FULL | LPA_100HALF))) {
            ecp->speed = ETH_SPEED_100M;
            if (lpa & LPA_100FULL)
                ecp->duplex = ETH_DUP_FULL;
        } else if ((lpa & LPA_10FULL)) {
            ecp->duplex = ETH_DUP_FULL;
        }

        if (bmcr & BMCR_FULLDPLX) {
            duplex = ETH_DUP_FULL;
        } else {
            duplex = ETH_DUP_HALF;
        }
        if (duplex != ecp->duplex) {
            ecp->duplex = duplex;
            printk(KERN_INFO"BMCR & ANLPAR duplex conflicts!!!\n");
        }

        if (bmcr & BMCR_SPEED100) {
            speed = ETH_SPEED_100M;
        } else {
            speed = ETH_SPEED_10M;
        }
        if (speed != ecp->speed) {
            ecp->speed = speed;
            printk(KERN_INFO"BMCR & ANLPAR speed conflicts!!!\n");
        }

        if (ETH_DUP_FULL == ecp->duplex)
            ecp->pause = (lpa & LPA_PAUSE_CAP) ? true : false;
    } else {
        ecp->duplex = (BMCR_FULLDPLX & bmcr) ? ETH_DUP_FULL : ETH_DUP_HALF;
        ecp->speed = (BMCR_SPEED100 & bmcr) ? ETH_SPEED_100M : ETH_SPEED_10M;
        ecp->pause = false;
    }

    printk(VT_GREEN "\n%s -> speed:%d, duplex:%s, pause: %s\n" VT_NORMAL,
           ecp->autoneg ? "autoneg" : "forced", ecp->speed,
           (ETH_DUP_FULL == ecp->duplex) ? "full" : "half",
           ecp->pause ? "supported" : "non-supported");

    return (0);
}
Exemplo n.º 15
0
/**
 * phy_init -- initialize phy - ATC2605 or KSZ8041
 * return 0 if success, else fail
 */
static int phy_init(ec_priv_t * ecp)
{
	int     reg_val;
	//u16 temp;
	unsigned int cnt = 0;	
	phy_reg_set_bits(ecp, MII_BMCR, BMCR_RESET);
	do {
		reg_val = read_phy_reg(ecp, MII_BMCR);
		if (cnt++ > 1000) {
			printk(KERN_ERR"ethernet phy BMCR_RESET timeout!!!\n");
			break;
		}
	} while (reg_val & BMCR_RESET);

	if (ecp->phy_model == ETH_PHY_MODEL_ATC2605) {
		phy_reg_set_bits(ecp, PHY_REG_FTC1, PHY_FTC_PRL);
		phy_reg_set_bits(ecp, PHY_REG_FTC2, PHY_FTC_CMPT);
	} else if (ecp->phy_model == ETH_PHY_MODEL_KSZ8041TL) {
		/* only turn on link up/down phy interrupt */
		write_phy_reg(ecp, MII_ICSR, ICSR_LINKUP_EN | ICSR_LINKDOWN_EN);
		printk(KERN_DEBUG"MII_ICSR:0x%x\n", (unsigned)read_phy_reg(ecp, MII_ICSR));
		phy_reg_set_bits(ecp, MII_PHY_CTL2, PHY_CTL2_INT_LEVEL);
		printk(KERN_DEBUG"MII_PHY_CTL2:0x%x\n", (unsigned)read_phy_reg(ecp, MII_PHY_CTL2));
	} else if (ecp->phy_model == ETH_PHY_MODEL_RTL8201) {
		write_phy_reg(ecp, PHY_RTL8201F_REG_PAGE_SELECT, PHY_RTL8201F_REG_PAGE_SELECT_SEVEN);
#ifndef CONFIG_POLL_PHY_STATE
		/* only turn on link up/down phy interrupt */
		write_phy_reg(ecp, PHY_RTL8201F_REG_INT_LED_FUNC, PHY_RTL8201F_PIN_LINK_STATE_CHANGE);
#endif
		/*As datasheet says tx&rx offset's default value is 0xF but be zero in fact.Reset them*/
		write_phy_reg(ecp, PHY_RTL8201F_REG_RMSR, 
			PHY_RTL8201F_RMSR_CLK_DIR_INPUT | PHY_RTL8201F_RMSR_RMII_MODE|PHY_RTL8201F_RMSR_RMII_RX_OFFSET|PHY_RTL8201F_RMSR_RMII_TX_OFFSET);
		write_phy_reg(ecp, PHY_RTL8201F_REG_PAGE_SELECT, PHY_RTL8201F_REG_PAGE_SELECT_ZERO);
	} else if (ecp->phy_model == ETH_PHY_MODEL_SR8201G) {
		write_phy_reg(ecp, PHY_SR8201G_REG_PAGE_SELECT, PHY_SR8201G_REG_PAGE_SELECT_SEVEN);
#ifndef CONFIG_POLL_PHY_STATE
		/* only turn on link up/down phy interrupt */
		write_phy_reg(ecp, PHY_SR8201G_REG_INT_LED_FUNC, PHY_SR8201G_INT_PIN_SELECT | PHY_SR8201G_INT_PIN_LINK_STATE_CHANGE);
#endif
		write_phy_reg(ecp, PHY_SR8201G_REG_RMSR, PHY_SR8201G_CLK_DIR_INPUT);
		write_phy_reg(ecp, PHY_SR8201G_REG_PAGE_SELECT, PHY_SR8201G_REG_PAGE_SELECT_ZERO);
	}else {
		printk(KERN_ERR"NOT supported phy model: %u\n", ecp->phy_model);
	}
#if 0
	/* adjust tx current */
	temp = read_phy_reg(ecp, 0x12);
	temp  &= ~0x780;
	//temp	|= 0x600; //1100, add 50+100uA
	//temp	|= 0x680; //1101
	//temp  |= 0x480; //1001
	//temp	|= 0x280; //0101
	//temp	|= 0x80; //0001
	temp	|= 0x180; //0011, minus 50uA  max 2.57V
	//temp	|= 0x780; //1111
	write_phy_reg(ecp, 0x12, temp);
	printk("PHY_REG_TXPN = 0x%x\n", (u32)read_phy_reg(ecp, 0x12));
#endif
#ifdef WORK_IN_10M_MODE
	/* limit to 10M for 5203 MAC bug */
	phy_reg_clear_bits(ecp, MII_ADVERTISE, ADVERTISE_100HALF | ADVERTISE_100FULL);
#endif
	printk(KERN_DEBUG"MII_ADVERTISE: 0x%04x\n", (uint)read_phy_reg(ecp, MII_ADVERTISE));
	printk(KERN_DEBUG"%s %d MII_BMCR: 0x%04x\n", __FUNCTION__,__LINE__,(uint)read_phy_reg(ecp, MII_BMCR));

	/* auto-negotiate and wait for completion, then get link status */
	phy_reg_set_bits(ecp, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
	printk(KERN_DEBUG"start aneg...\n");
	printk(KERN_DEBUG"%s %d MII_BMCR: 0x%04x\n",  __FUNCTION__,__LINE__,(uint)read_phy_reg(ecp, MII_BMCR));

	/* wait_for_aneg_completion(ecp) sleep(), so it shall not be invoked in
	 * ec_netdev_transmit_timeout() which runs in interrupt bottom half. */
#if 0
	printk("wait for aneg...\n");
	if (wait_for_aneg_completion(ecp)) {
		printk("MII_BMCR:0x%x\n", read_phy_reg(ecp, MII_BMCR));
		printk("auto-negotiation is timeout.\n");
		return (1);
	}
   int i = 0 ;
	for (i = 0; i < MII_TIME_OUT; i++) {
		reg_val = read_phy_reg(ecp, MII_BMSR);
		if (reg_val & BMSR_LSTATUS) {
			ecp->linked = true;
			break;
		}
		udelay(1);
	}
	if (MII_TIME_OUT == i) {
		ecp->linked = false;
		printk("link fail.\n");
		return (1);
	}
#else
	/* not wait, set link status not connected and return*/
	ecp->linked = false;
#endif

	printk(KERN_INFO"link status is: %s\n", ecp->linked ? "true" : "false");
	return (0);
}