⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 e1000_phy.c

📁 Intel 82546系列lan driver源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* Disable AHT in Slave mode on channel A */	e1e_wphy(hw, 0x187A, 0x0800);	/*	 * Enable LPLU and disable AN to 1000 in non-D0a states,	 * Enable SPD+B2B	 */	e1e_wphy(hw, 0x0019, 0x008D);	/* Enable restart AN on an1000_dis change */	e1e_wphy(hw, 0x001B, 0x2080);	/* Enable wh_fifo read clock in 10/100 modes */	e1e_wphy(hw, 0x0014, 0x0045);	/* Restart AN, Speed selection is 1000 */	e1e_wphy(hw, 0x0000, 0x1340);	return E1000_SUCCESS;}/** *  e1000e_get_phy_type_from_id - Get PHY type from id *  @phy_id: phy_id read from the phy * *  Returns the phy type from the id. **/enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id){	enum e1000_phy_type phy_type = e1000_phy_unknown;	switch (phy_id)	{	case M88E1000_I_PHY_ID:	case M88E1000_E_PHY_ID:	case M88E1111_I_PHY_ID:	case M88E1011_I_PHY_ID:		phy_type = e1000_phy_m88;		break;	case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */		phy_type = e1000_phy_igp_2;		break;	case GG82563_E_PHY_ID:		phy_type = e1000_phy_gg82563;		break;	case IGP03E1000_E_PHY_ID:		phy_type = e1000_phy_igp_3;		break;	case IFE_E_PHY_ID:	case IFE_PLUS_E_PHY_ID:	case IFE_C_E_PHY_ID:		phy_type = e1000_phy_ife;		break;	case BME1000_E_PHY_ID:	case BME1000_E_PHY_ID_R2:		phy_type = e1000_phy_bm;		break;	default:		phy_type = e1000_phy_unknown;		break;	}	return phy_type;}/** *  e1000e_determine_phy_address - Determines PHY address. *  @hw: pointer to the HW structure * *  This uses a trial and error method to loop through possible PHY *  addresses. It tests each by reading the PHY ID registers and *  checking for a match. **/s32 e1000e_determine_phy_address(struct e1000_hw *hw){	s32 ret_val = -E1000_ERR_PHY_TYPE;	u32 phy_addr = 0;	u32 i;	enum e1000_phy_type phy_type = e1000_phy_unknown;	hw->phy.id = phy_type;	for (phy_addr = 0; phy_addr < E1000_MAX_PHY_ADDR; phy_addr++) {		hw->phy.addr = phy_addr;		i = 0;		do {			e1000e_get_phy_id(hw);			phy_type = e1000e_get_phy_type_from_id(hw->phy.id);			/*			 * If phy_type is valid, break - we found our			 * PHY address			 */			if (phy_type  != e1000_phy_unknown) {				ret_val = E1000_SUCCESS;				goto out;			}			msleep(1);			i++;		} while (i < 10);	}out:	return ret_val;}/** *  e1000_get_phy_addr_for_bm_page - Retrieve PHY page address *  @page: page to access * *  Returns the phy address for the page requested. **/static u32 e1000_get_phy_addr_for_bm_page(u32 page, u32 reg){	u32 phy_addr = 2;	if ((page >= 768) || (page == 0 && reg == 25) || (reg == 31))		phy_addr = 1;	return phy_addr;}/** *  e1000e_write_phy_reg_bm - Write BM PHY register *  @hw: pointer to the HW structure *  @offset: register offset to write to *  @data: data to write at register offset * *  Acquires semaphore, if necessary, then writes the data to PHY register *  at the offset.  Release any acquired semaphores before exiting. **/s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data){	s32 ret_val;	u32 page_select = 0;	u32 page = offset >> IGP_PAGE_SHIFT;	u32 page_shift = 0;	/* Page 800 works differently than the rest so it has its own func */	if (page == BM_WUC_PAGE) {		ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data,		                                         false);		goto out;	}	ret_val = hw->phy.ops.acquire(hw);	if (ret_val)		goto out;	hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset);	if (offset > MAX_PHY_MULTI_PAGE_REG) {		/*		 * Page select is register 31 for phy address 1 and 22 for		 * phy address 2 and 3. Page select is shifted only for		 * phy address 1.		 */		if (hw->phy.addr == 1) {			page_shift = IGP_PAGE_SHIFT;			page_select = IGP01E1000_PHY_PAGE_SELECT;		} else {			page_shift = 0;			page_select = BM_PHY_PAGE_SELECT;		}		/* Page is shifted left, PHY expects (page x 32) */		ret_val = e1000e_write_phy_reg_mdic(hw, page_select,		                                   (page << page_shift));		if (ret_val) {			hw->phy.ops.release(hw);			goto out;		}	}	ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,	                                   data);	hw->phy.ops.release(hw);out:	return ret_val;}/** *  e1000e_read_phy_reg_bm - Read BM PHY register *  @hw: pointer to the HW structure *  @offset: register offset to be read *  @data: pointer to the read data * *  Acquires semaphore, if necessary, then reads the PHY register at offset *  and storing the retrieved information in data.  Release any acquired *  semaphores before exiting. **/s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data){	s32 ret_val;	u32 page_select = 0;	u32 page = offset >> IGP_PAGE_SHIFT;	u32 page_shift = 0;	/* Page 800 works differently than the rest so it has its own func */	if (page == BM_WUC_PAGE) {		ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data,		                                         true);		goto out;	}	ret_val = hw->phy.ops.acquire(hw);	if (ret_val)		goto out;	hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset);	if (offset > MAX_PHY_MULTI_PAGE_REG) {		/*		 * Page select is register 31 for phy address 1 and 22 for		 * phy address 2 and 3. Page select is shifted only for		 * phy address 1.		 */		if (hw->phy.addr == 1) {			page_shift = IGP_PAGE_SHIFT;			page_select = IGP01E1000_PHY_PAGE_SELECT;		} else {			page_shift = 0;			page_select = BM_PHY_PAGE_SELECT;		}		/* Page is shifted left, PHY expects (page x 32) */		ret_val = e1000e_write_phy_reg_mdic(hw, page_select,		                                   (page << page_shift));		if (ret_val) {			hw->phy.ops.release(hw);			goto out;		}	}	ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,	                                  data);	hw->phy.ops.release(hw);out:	return ret_val;}/** *  e1000e_read_phy_reg_bm2 - Read BM PHY register *  @hw: pointer to the HW structure *  @offset: register offset to be read *  @data: pointer to the read data * *  Acquires semaphore, if necessary, then reads the PHY register at offset *  and storing the retrieved information in data.  Release any acquired *  semaphores before exiting. **/s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data){	s32 ret_val;	u16 page = (u16)(offset >> IGP_PAGE_SHIFT);	/* Page 800 works differently than the rest so it has its own func */	if (page == BM_WUC_PAGE) {		ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data,		                                         true);		goto out;	}	ret_val = hw->phy.ops.acquire(hw);	if (ret_val)		goto out;	hw->phy.addr = 1;	if (offset > MAX_PHY_MULTI_PAGE_REG) {		/* Page is shifted left, PHY expects (page x 32) */		ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,		                                   page);		if (ret_val) {			hw->phy.ops.release(hw);			goto out;		}	}	ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,	                                  data);	hw->phy.ops.release(hw);out:	return ret_val;}/** *  e1000e_write_phy_reg_bm2 - Write BM PHY register *  @hw: pointer to the HW structure *  @offset: register offset to write to *  @data: data to write at register offset * *  Acquires semaphore, if necessary, then writes the data to PHY register *  at the offset.  Release any acquired semaphores before exiting. **/s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data){	s32 ret_val;	u16 page = (u16)(offset >> IGP_PAGE_SHIFT);	/* Page 800 works differently than the rest so it has its own func */	if (page == BM_WUC_PAGE) {		ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data,		                                         false);		goto out;	}	ret_val = hw->phy.ops.acquire(hw);	if (ret_val)		goto out;	hw->phy.addr = 1;	if (offset > MAX_PHY_MULTI_PAGE_REG) {		/* Page is shifted left, PHY expects (page x 32) */		ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,		                                   page);		if (ret_val) {			hw->phy.ops.release(hw);			goto out;		}	}	ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,	                                   data);	hw->phy.ops.release(hw);out:	return ret_val;}/** *  e1000_access_phy_wakeup_reg_bm - Read BM PHY wakeup register *  @hw: pointer to the HW structure *  @offset: register offset to be read or written *  @data: pointer to the data to read or write *  @read: determines if operation is read or write * *  Acquires semaphore, if necessary, then reads the PHY register at offset *  and storing the retrieved information in data.  Release any acquired *  semaphores before exiting. Note that procedure to read the wakeup *  registers are different. It works as such: *  1) Set page 769, register 17, bit 2 = 1 *  2) Set page to 800 for host (801 if we were manageability) *  3) Write the address using the address opcode (0x11) *  4) Read or write the data using the data opcode (0x12) *  5) Restore 769_17.2 to its original value **/static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,                                          u16 *data, bool read){	s32 ret_val;	u16 reg = ((u16)offset);	u16 phy_reg = 0;	u8  phy_acquired = 1;	ret_val = hw->phy.ops.acquire(hw);	if (ret_val) {		e_dbg("Could not acquire PHY\n");		phy_acquired = 0;		goto out;	}	/* All operations in this function are phy address 1 */	hw->phy.addr = 1;	/* Set page 769 */	e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,	                         (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT));	ret_val = e1000e_read_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, &phy_reg);	if (ret_val) {		e_dbg("Could not read PHY page 769\n");		goto out;	}	/* First clear bit 4 to avoid a power state change */	phy_reg &= ~(BM_WUC_HOST_WU_BIT);	ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg);	if (ret_val) {		e_dbg("Could not clear PHY page 769 bit 4\n");		goto out;	}	/* Write bit 2 = 1, and clear bit 4 to 769_17 */	ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG,	                                   phy_reg | BM_WUC_ENABLE_BIT);	if (ret_val) {		e_dbg("Could not write PHY page 769 bit 2\n");		goto out;	}	/* Select page 800 */	ret_val = e1000e_write_phy_reg_mdic(hw,	                                   IGP01E1000_PHY_PAGE_SELECT,	                                   (BM_WUC_PAGE << IGP_PAGE_SHIFT));	/* Write the page 800 offset value using opcode 0x11 */	ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ADDRESS_OPCODE, reg);	if (ret_val) {		e_dbg("Could not write address opcode to page 800\n");		goto out;	}	if (read) {	        /* Read the page 800 value using opcode 0x12 */		ret_val = e1000e_read_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE,							data);	} else {	        /* Read the page 800 value using opcode 0x12 */		ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE,							*data);	}	if (ret_val) {		e_dbg("Could not read data value from page 800\n");		goto out;	}	/*	 * Restore 769_17.2 to its original value	 * Set page 769	 */	e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,	                         (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT));	/* Clear 769_17.2 */	ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg);	if (ret_val) {		e_dbg("Could not clear PHY page 769 bit 2\n");		goto out;	}out:	if (phy_acquired == 1)		hw->phy.ops.release(hw);	return ret_val;}/** * e1000_power_up_phy_copper - Restore copper link in case of PHY power down * @hw: pointer to the HW structure * * In the case of a PHY power down to save power, or to turn off link during a * driver unload, or wake on lan is not enabled, restore the link to previous * settings. **/void e1000_power_up_phy_copper(struct e1000_hw *hw){	u16 mii_reg = 0;	/* The PHY will retain its settings across a power down/up cycle */	e1e_rphy(hw, PHY_CONTROL, &mii_reg);	mii_reg &= ~MII_CR_POWER_DOWN;	e1e_wphy(hw, PHY_CONTROL, mii_reg);}/** * e1000_power_down_phy_copper - Restore copper link in case of PHY power down * @hw: pointer to the HW structure * * In the case of a PHY power down to save power, or to turn off link during a * driver unload, or wake on lan is not enabled, restore the link to previous * settings. **/void e1000_power_down_phy_copper(struct e1000_hw *hw){	u16 mii_reg = 0;	/* The PHY will retain its settings across a power down/up cycle */	e1e_rphy(hw, PHY_CONTROL, &mii_reg);	mii_reg |= MII_CR_POWER_DOWN;	e1e_wphy(hw, PHY_CONTROL, mii_reg);	msleep(1);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -