/* * Copyright : (C) 2022 Phytium Information Technology, Inc. * All Rights Reserved. * * This program is OPEN SOURCE software: you can redistribute it and/or modify it * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd, * either version 1.0 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the Phytium Public License for more details. * * * FilePath: fxmac_options.c * Date: 2022-04-06 14:46:52 * LastEditTime: 2022-04-06 14:46:58 * Description:  This file is for * * Modify History: * Ver   Who        Date         Changes * ----- ------     --------    -------------------------------------- */ #include "fxmac_hw.h" #include "fxmac.h" #include "fassert.h" /** * @name: FXmacSetMacAddress * * @msg: Set the MAC address for this driver/device. The address is a 48-bit value. * The device must be stopped before calling this function. * * @param {FXmac *}: instance_p is a pointer to the instance to be worked on. * @param address_ptr is a pointer to a 6-byte MAC address. * @param index plus 1 is a index to which MAC (1-4) address. * * @return * - FT_SUCCESS if the MAC address was set successfully * - FXMAC_ERR_MAC_IS_PROCESSING if the device has not yet been stopped * */ FError FXmacSetMacAddress(FXmac *instance_p, u8 *address_ptr, u8 index) { u32 mac_addr; u8 *aptr = (u8 *)(void *)address_ptr; u8 index_loc = index; FError status; FASSERT(instance_p != NULL); FASSERT(aptr != NULL); FASSERT(instance_p->is_ready == (u32)FT_COMPONENT_IS_READY); FASSERT((index_loc < (u8)FXMAC_MAX_MAC_ADDR)); /* Be sure device has been stopped */ if (instance_p->is_started == (u32)FT_COMPONENT_IS_STARTED) { status = (FError)(FXMAC_ERR_MAC_IS_PROCESSING); } else { /* Set the MAC bits [31:0] in BOT */ mac_addr = *(aptr); mac_addr |= ((u32)(*(aptr + 1)) << 8U); mac_addr |= ((u32)(*(aptr + 2)) << 16U); mac_addr |= ((u32)(*(aptr + 3)) << 24U); FXMAC_WRITEREG32(instance_p->config.base_address, ((u32)FXMAC_GEM_SA1B + ((u32)index_loc * (u32)8)), mac_addr); /* There are reserved bits in TOP so don't affect them */ mac_addr = FXMAC_READREG32(instance_p->config.base_address, ((u32)FXMAC_GEM_SA1T + ((u32)index_loc * (u32)8))); mac_addr &= (u32)(~FXMAC_GEM_SAB_MASK); /* Set MAC bits [47:32] in TOP */ mac_addr |= (u32)(*(aptr + 4)); mac_addr |= (u32)(*(aptr + 5)) << 8U; FXMAC_WRITEREG32(instance_p->config.base_address, ((u32)FXMAC_GEM_SA1T + ((u32)index_loc * (u32)8)), mac_addr); status = (FError)(FT_SUCCESS); } return status; } /** * @name: FXmacGetMacAddress * @msg: Set the MAC address according to index * @param {FXmac} *mac is a pointer to the instance to be worked on. * @param {void} *address_ptr is an output parameter, and is a pointer to a buffer into * which the current MAC address will be copied. * @param {u8} index is a index to which MAC (0-3) address. */ void FXmacGetMacAddress(FXmac *instance_p, u8 *address_ptr, u8 index) { u32 reg_value; u8 *ptr = (u8 *)address_ptr; FASSERT(instance_p != NULL); FASSERT(ptr != NULL); FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY); FASSERT((index < FXMAC_MAX_MAC_ADDR)); reg_value = FXMAC_READREG32(instance_p->config.base_address, FXMAC_GEM_SA1B + ((u32)index * (u32)8)); *ptr = (u8)reg_value; *(ptr + 1) = (u8)(reg_value >> 8U); *(ptr + 2) = (u8)(reg_value >> 16U); *(ptr + 3) = (u8)(reg_value >> 24U); reg_value = FXMAC_READREG32(instance_p->config.base_address, FXMAC_GEM_SA1T + ((u32)index * (u32)8)); *(ptr + 4) = (u8)(reg_value); *(ptr + 5) = (u8)(reg_value >> 8U); } /** * Set the Type ID match for this driver/device. The register is a 32-bit * value. The device must be stopped before calling this function. * * @param instance_p is a pointer to the instance to be worked on. * @param id_check is type ID to be configured. * @param index plus 1 is a index to which Type ID (1-4). * * @return * - FT_SUCCESS if the MAC address was set successfully * - FXMAC_ERR_MAC_IS_PROCESSING if the device has not yet been stopped * */ FError FXmacSetTypeIdCheck(FXmac *instance_p, u32 id_check, u8 index) { u8 index_loc = index; FError status; FASSERT(instance_p != NULL); FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY); FASSERT((index_loc < (u8)FXMAC_MAX_TYPE_ID)); /* Be sure device has been stopped */ if (instance_p->is_started == (u32)FT_COMPONENT_IS_STARTED) { status = (FError)(FXMAC_ERR_MAC_IS_PROCESSING); } else { /* Set the ID bits in MATCHx register */ FXMAC_WRITEREG32(instance_p->config.base_address, ((u32)FXMAC_MATCH1_OFFSET + ((u32)index_loc * (u32)4)), id_check); status = (FError)(FT_SUCCESS); } return status; } /** * Set options for the driver/device. The driver should be stopped with * FXmacStop() before changing options. * * @param instance_p is a pointer to the instance to be worked on. * @param options are the options to set. Multiple options can be set by OR'ing * FXMAC_*_OPTIONS constants together. options not specified are not * affected. * @param queue_num is the Buffer Queue Index ,Used for jumbo frames only * * @return * - FT_SUCCESS if the options were set successfully * - FXMAC_ERR_MAC_IS_PROCESSING if the device has not yet been stopped * * @note * See fxmac.h for a description of the available options. * */ FError FXmacSetOptions(FXmac *instance_p, u32 options, u32 queue_num) { u32 reg; /* Generic register contents */ u32 reg_netcfg; /* Reflects original contents of NET_CONFIG */ u32 reg_new_netcfg; /* Reflects new contents of NET_CONFIG */ FError status; FXmacConfig *config_p; FASSERT(instance_p != NULL); FASSERT(instance_p->is_ready == (u32)FT_COMPONENT_IS_READY); config_p = &instance_p->config; /* Be sure device has been stopped */ if (instance_p->is_started == (u32)FT_COMPONENT_IS_STARTED) { status = (FError)(FXMAC_ERR_MAC_IS_PROCESSING); } else { /* Many of these options will change the NET_CONFIG registers. * To reduce the amount of IO to the device, group these options here * and change them all at once. */ /* Grab current register contents */ reg_netcfg = FXMAC_READREG32(config_p->base_address, FXMAC_NWCFG_OFFSET); reg_new_netcfg = reg_netcfg; /* * It is configured to max 1536. */ if ((options & FXMAC_FRAME1536_OPTION) != 0x00000000U) { reg_new_netcfg |= (FXMAC_NWCFG_1536RXEN_MASK); } /* Turn on VLAN packet only, only VLAN tagged will be accepted */ if ((options & FXMAC_VLAN_OPTION) != 0x00000000U) { reg_new_netcfg |= FXMAC_NWCFG_NVLANDISC_MASK; } /* Turn on FCS stripping on receive packets */ if ((options & FXMAC_FCS_STRIP_OPTION) != 0x00000000U) { reg_new_netcfg |= FXMAC_NWCFG_FCSREM_MASK; } /* Turn on length/type field checking on receive packets */ if ((options & FXMAC_LENTYPE_ERR_OPTION) != 0x00000000U) { reg_new_netcfg |= FXMAC_NWCFG_LENERRDSCRD_MASK; } /* Turn on flow control */ if ((options & FXMAC_FLOW_CONTROL_OPTION) != 0x00000000U) { reg_new_netcfg |= FXMAC_NWCFG_PAUSEEN_MASK; } /* Turn on promiscuous frame filtering (all frames are received) */ if ((options & FXMAC_PROMISC_OPTION) != 0x00000000U) { reg_new_netcfg |= FXMAC_NWCFG_COPYALLEN_MASK; } /* Allow broadcast address reception */ if ((options & FXMAC_BROADCAST_OPTION) != 0x00000000U) { reg_new_netcfg &= (u32)(~FXMAC_NWCFG_BCASTDI_MASK); } /* Allow multicast address filtering */ if ((options & FXMAC_MULTICAST_OPTION) != 0x00000000U) { reg_new_netcfg |= FXMAC_NWCFG_MCASTHASHEN_MASK; } /* enable RX checksum offload */ if ((options & FXMAC_RX_CHKSUM_ENABLE_OPTION) != 0x00000000U) { reg_new_netcfg |= FXMAC_NWCFG_RXCHKSUMEN_MASK; } /* Enable jumbo frames */ if ((options & FXMAC_JUMBO_ENABLE_OPTION) != 0x00000000U) { instance_p->max_mtu_size = FXMAC_MTU_JUMBO; instance_p->max_frame_size = FXMAC_MTU_JUMBO + FXMAC_HDR_SIZE + FXMAC_TRL_SIZE; reg_new_netcfg |= FXMAC_NWCFG_JUMBO_MASK; FXMAC_WRITEREG32(config_p->base_address, FXMAC_JUMBOMAXLEN_OFFSET, FXMAC_MTU_JUMBO); if (queue_num == 0) { u32 rx_buf_size = 0; reg = FXMAC_READREG32(config_p->base_address, FXMAC_DMACR_OFFSET); reg &= ~FXMAC_DMACR_RXBUF_MASK; rx_buf_size = ((u32)instance_p->max_mtu_size / (u32)FXMAC_RX_BUF_UNIT); rx_buf_size += (((u32)instance_p->max_mtu_size % (u32)FXMAC_RX_BUF_UNIT) != (u32)0) ? 1U : 0U; reg |= ((rx_buf_size << (u32)(FXMAC_DMACR_RXBUF_SHIFT)) & (u32)(FXMAC_DMACR_RXBUF_MASK)); FXMAC_WRITEREG32(config_p->base_address, FXMAC_DMACR_OFFSET, reg); } else if (queue_num < instance_p->config.max_queue_num) { u32 rx_buf_size = 0; rx_buf_size = ((u32)instance_p->max_mtu_size / (u32)FXMAC_RX_BUF_UNIT); rx_buf_size += (((u32)instance_p->max_mtu_size % (u32)FXMAC_RX_BUF_UNIT) != (u32)0) ? 1U : 0U; FXMAC_WRITEREG32(config_p->base_address, FXMAC_RXBUFQX_SIZE_OFFSET(queue_num), rx_buf_size & FXMAC_RXBUFQX_SIZE_MASK); } } if (((options & FXMAC_SGMII_ENABLE_OPTION) != 0x00000000U)) { reg_new_netcfg |= (FXMAC_NWCFG_SGMIIEN_MASK | FXMAC_NWCFG_PCSSEL_MASK); } if ((options & FXMAC_LOOPBACK_NO_MII_OPTION) != 0x00000000U) { reg = FXMAC_READREG32(config_p->base_address, FXMAC_NWCTRL_OFFSET); reg |= FXMAC_NWCFG_LOOPBACK_LOCAL_MASK; FXMAC_WRITEREG32(config_p->base_address, FXMAC_NWCTRL_OFFSET, reg); } if ((options & FXMAC_LOOPBACK_USXGMII_OPTION) != 0x00000000U) { FXMAC_WRITEREG32(config_p->base_address, FXMAC_TEST_CONTROL_OFFSET, 2); } /* Officially change the NET_CONFIG registers if it needs to be * modified. */ if (reg_netcfg != reg_new_netcfg) { FXMAC_WRITEREG32(config_p->base_address, FXMAC_NWCFG_OFFSET, reg_new_netcfg); } /* Enable TX checksum offload */ if ((options & FXMAC_TX_CHKSUM_ENABLE_OPTION) != 0x00000000U) { reg = FXMAC_READREG32(config_p->base_address, FXMAC_DMACR_OFFSET); reg |= FXMAC_DMACR_TCPCKSUM_MASK; FXMAC_WRITEREG32(config_p->base_address, FXMAC_DMACR_OFFSET, reg); } /* Enable transmitter */ if ((options & FXMAC_TRANSMITTER_ENABLE_OPTION) != 0x00000000U) { reg = FXMAC_READREG32(config_p->base_address, FXMAC_NWCTRL_OFFSET); reg |= FXMAC_NWCTRL_TXEN_MASK; FXMAC_WRITEREG32(config_p->base_address, FXMAC_NWCTRL_OFFSET, reg); } /* Enable receiver */ if ((options & FXMAC_RECEIVER_ENABLE_OPTION) != 0x00000000U) { reg = FXMAC_READREG32(config_p->base_address, FXMAC_NWCTRL_OFFSET); reg |= FXMAC_NWCTRL_RXEN_MASK; FXMAC_WRITEREG32(config_p->base_address, FXMAC_NWCTRL_OFFSET, reg); } /* The remaining options not handled here are managed elsewhere in the * driver. No register modifications are needed at this time. Reflecting * the option in instance_p->options is good enough for now. */ /* Set options word to its new value */ instance_p->options |= options; status = (FError)(FT_SUCCESS); } return status; } /** * Clear options for the driver/device * * @param instance_p is a pointer to the instance to be worked on. * @param options are the options to clear. Multiple options can be cleared by * OR'ing FXMAC_*_options constants together. options not specified * are not affected. * @param queue_num is the Buffer Queue Index ,Used for jumbo frames only * @return * - FT_SUCCESS if the options were set successfully * - FXMAC_ERR_MAC_IS_PROCESSING if the device has not yet been stopped * * @note * See fxmac.h for a description of the available options. */ FError FXmacClearOptions(FXmac *instance_p, u32 options, u32 queue_num) { u32 reg; /* Generic */ u32 reg_net_cfg; /* Reflects original contents of NET_CONFIG */ u32 reg_new_net_cfg; /* Reflects new contents of NET_CONFIG */ FError status; FXmacConfig *config_p; FASSERT(instance_p != NULL); FASSERT(instance_p->is_ready == (u32)FT_COMPONENT_IS_READY); config_p = &instance_p->config; /* Be sure device has been stopped */ if (instance_p->is_started == (u32)FT_COMPONENT_IS_STARTED) { status = (FError)(FXMAC_ERR_MAC_IS_PROCESSING); } else { /* Many of these options will change the NET_CONFIG registers. * To reduce the amount of IO to the device, group these options here * and change them all at once. */ /* Grab current register contents */ reg_net_cfg = FXMAC_READREG32(instance_p->config.base_address, FXMAC_NWCFG_OFFSET); reg_new_net_cfg = reg_net_cfg; /* There is only RX configuration!? * It is configured in two different length, up to 1536 and 10240 bytes */ if ((options & FXMAC_FRAME1536_OPTION) != 0x00000000U) { reg_new_net_cfg &= (u32)(~FXMAC_NWCFG_1536RXEN_MASK); } /* Turn off VLAN packet only */ if ((options & FXMAC_VLAN_OPTION) != 0x00000000U) { reg_new_net_cfg &= (u32)(~FXMAC_NWCFG_NVLANDISC_MASK); } /* Turn off FCS stripping on receive packets */ if ((options & FXMAC_FCS_STRIP_OPTION) != 0x00000000U) { reg_new_net_cfg &= (u32)(~FXMAC_NWCFG_FCSREM_MASK); } /* Turn off length/type field checking on receive packets */ if ((options & FXMAC_LENTYPE_ERR_OPTION) != 0x00000000U) { reg_new_net_cfg &= (u32)(~FXMAC_NWCFG_LENERRDSCRD_MASK); } /* Turn off flow control */ if ((options & FXMAC_FLOW_CONTROL_OPTION) != 0x00000000U) { reg_new_net_cfg &= (u32)(~FXMAC_NWCFG_PAUSEEN_MASK); } /* Turn off promiscuous frame filtering (all frames are received) */ if ((options & FXMAC_PROMISC_OPTION) != 0x00000000U) { reg_new_net_cfg &= (u32)(~FXMAC_NWCFG_COPYALLEN_MASK); } /* Disallow broadcast address filtering => broadcast reception */ if ((options & FXMAC_BROADCAST_OPTION) != 0x00000000U) { reg_new_net_cfg |= FXMAC_NWCFG_BCASTDI_MASK; } /* Disallow multicast address filtering */ if ((options & FXMAC_MULTICAST_OPTION) != 0x00000000U) { reg_new_net_cfg &= (u32)(~FXMAC_NWCFG_MCASTHASHEN_MASK); } /* Disable RX checksum offload */ if ((options & FXMAC_RX_CHKSUM_ENABLE_OPTION) != 0x00000000U) { reg_new_net_cfg &= (u32)(~FXMAC_NWCFG_RXCHKSUMEN_MASK); } /* Disable jumbo frames */ if (((options & FXMAC_JUMBO_ENABLE_OPTION) != 0x00000000U)) /* 恢复之前buffer 容量 */ { instance_p->max_mtu_size = FXMAC_MTU; instance_p->max_frame_size = FXMAC_MTU + FXMAC_HDR_SIZE + FXMAC_TRL_SIZE; reg_new_net_cfg &= (u32)(~FXMAC_NWCFG_JUMBO_MASK); reg = FXMAC_READREG32(instance_p->config.base_address, FXMAC_DMACR_OFFSET); reg &= ~FXMAC_DMACR_RXBUF_MASK; if (queue_num == 0) { u32 rx_buf_size = 0; reg = FXMAC_READREG32(instance_p->config.base_address, FXMAC_DMACR_OFFSET); reg &= ~FXMAC_DMACR_RXBUF_MASK; rx_buf_size = ((u32)instance_p->max_mtu_size / (u32)FXMAC_RX_BUF_UNIT); rx_buf_size += ((u32)instance_p->max_mtu_size % ((u32)FXMAC_RX_BUF_UNIT) != (u32)0) ? 1U : 0U; reg |= ((rx_buf_size << (u32)(FXMAC_DMACR_RXBUF_SHIFT)) & (u32)(FXMAC_DMACR_RXBUF_MASK)); FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_DMACR_OFFSET, reg); } else if (queue_num < instance_p->config.max_queue_num) { u32 rx_buf_size = 0; rx_buf_size = ((u32)instance_p->max_mtu_size / (u32)FXMAC_RX_BUF_UNIT); rx_buf_size += (((u32)instance_p->max_mtu_size % (u32)FXMAC_RX_BUF_UNIT) != (u32)0) ? 1U : 0U; FXMAC_WRITEREG32(config_p->base_address, FXMAC_RXBUFQX_SIZE_OFFSET(queue_num), rx_buf_size & FXMAC_RXBUFQX_SIZE_MASK); } } if (((options & FXMAC_SGMII_ENABLE_OPTION) != 0x00000000U)) { reg_new_net_cfg &= (u32)(~(FXMAC_NWCFG_SGMIIEN_MASK | FXMAC_NWCFG_PCSSEL_MASK)); } if ((options & FXMAC_LOOPBACK_NO_MII_OPTION) != 0x00000000U) { reg = FXMAC_READREG32(config_p->base_address, FXMAC_NWCTRL_OFFSET); reg &= (u32)(~FXMAC_NWCFG_LOOPBACK_LOCAL_MASK); FXMAC_WRITEREG32(config_p->base_address, FXMAC_NWCTRL_OFFSET, reg); } if ((options & FXMAC_LOOPBACK_USXGMII_OPTION) != 0x00000000U) { FXMAC_WRITEREG32(config_p->base_address, FXMAC_TEST_CONTROL_OFFSET, (FXMAC_READREG32(config_p->base_address, FXMAC_TEST_CONTROL_OFFSET) & ~2)); } /* Officially change the NET_CONFIG registers if it needs to be * modified. */ if (reg_net_cfg != reg_new_net_cfg) { FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_NWCFG_OFFSET, reg_new_net_cfg); } /* Disable TX checksum offload */ if ((options & FXMAC_TX_CHKSUM_ENABLE_OPTION) != 0x00000000U) { reg = FXMAC_READREG32(instance_p->config.base_address, FXMAC_DMACR_OFFSET); reg &= (u32)(~FXMAC_DMACR_TCPCKSUM_MASK); FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_DMACR_OFFSET, reg); } /* Disable transmitter */ if ((options & FXMAC_TRANSMITTER_ENABLE_OPTION) != 0x00000000U) { reg = FXMAC_READREG32(instance_p->config.base_address, FXMAC_NWCTRL_OFFSET); reg &= (u32)(~FXMAC_NWCTRL_TXEN_MASK); FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_NWCTRL_OFFSET, reg); } /* Disable receiver */ if ((options & FXMAC_RECEIVER_ENABLE_OPTION) != 0x00000000U) { reg = FXMAC_READREG32(instance_p->config.base_address, FXMAC_NWCTRL_OFFSET); reg &= (u32)(~FXMAC_NWCTRL_RXEN_MASK); FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_NWCTRL_OFFSET, reg); } /* The remaining options not handled here are managed elsewhere in the * driver. No register modifications are needed at this time. Reflecting * option in instance_p->options is good enough for now. */ /* Set options word to its new value */ instance_p->options &= ~options; status = (FError)(FT_SUCCESS); } return status; } /** * Clear the Hash registers for the mac address pointed by address_ptr. * * @param instance_p is a pointer to the instance to be worked on. * */ void FXmacClearHash(FXmac *instance_p) { FASSERT(instance_p != NULL); FASSERT(instance_p->is_ready == (u32)FT_COMPONENT_IS_READY); FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_HASHL_OFFSET, 0x0U); /* write bits [63:32] in TOP */ FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_HASHH_OFFSET, 0x0U); } /** * Write data to the specified PHY register. The Ethernet driver does not * require the device to be stopped before writing to the PHY. Although it is * probably a good idea to stop the device, it is the responsibility of the * application to deem this necessary. The MAC provides the driver with the * ability to talk to a PHY that adheres to the Media Independent Interface * (MII) as defined in the IEEE 802.3 standard. * * Prior to PHY access with this function, the user should have setup the MDIO * clock with FXmacSetMdioDivisor(). * * @param instance_p is a pointer to the FXmac instance to be worked on. * @param phy_address is the address of the PHY to be written (supports multiple * PHYs) * @param register_num is the register number, 0-31, of the specific PHY register * to write * @param phy_data is the 16-bit value that will be written to the register * * @return * * - FT_SUCCESS if the PHY was written to successfully. Since there is no error * status from the MAC on a write, the user should read the PHY to verify the * write was successful. * - FXMAC_ERR_PHY_BUSY if there is another PHY operation in progress * * @note * * This function is not thread-safe. The user must provide mutually exclusive * access to this function if there are to be multiple threads that can call it. * * There is the possibility that this function will not return if the hardware * is broken (i.e., it never sets the status bit indicating that the write is * done). If this is of concern to the user, the user should provide a mechanism * suitable to their needs for recovery. * * For the duration of this function, all host interface reads and writes are * blocked to the current FXmac instance. * ******************************************************************************/ FError FXmacPhyWrite(FXmac *instance_p, u32 phy_address, u32 register_num, u16 phy_data) { u32 mgtcr; volatile u32 ipisr; u32 ip_write_temp; FError status; FASSERT(instance_p != NULL); /* Make sure no other PHY operation is currently in progress */ if ((!(FXMAC_READREG32(instance_p->config.base_address, FXMAC_NWSR_OFFSET) & FXMAC_NWSR_MDIOIDLE_MASK)) == TRUE) { status = (FError)(FXMAC_ERR_PHY_BUSY); } else { /* Construct mgtcr mask for the operation */ mgtcr = FXMAC_PHYMNTNC_OP_MASK | FXMAC_PHYMNTNC_OP_W_MASK | (phy_address << FXMAC_PHYMNTNC_PHAD_SHFT_MSK) | (register_num << FXMAC_PHYMNTNC_PREG_SHFT_MSK) | (u32)phy_data; /* Write mgtcr and wait for completion */ FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_PHYMNTNC_OFFSET, mgtcr); do { ipisr = FXMAC_READREG32(instance_p->config.base_address, FXMAC_NWSR_OFFSET); ip_write_temp = ipisr; } while ((ip_write_temp & FXMAC_NWSR_MDIOIDLE_MASK) == 0x00000000U); status = (FError)(FT_SUCCESS); } return status; } /** * Read the current value of the PHY register indicated by the phy_address and * the register_num parameters. The MAC provides the driver with the ability to * talk to a PHY that adheres to the Media Independent Interface (MII) as * defined in the IEEE 802.3 standard. * * * @param instance_p is a pointer to the FXmac instance to be worked on. * @param phy_address is the address of the PHY to be read (supports multiple * PHYs) * @param register_num is the register number, 0-31, of the specific PHY register * to read * @param phydat_aptr is an output parameter, and points to a 16-bit buffer into * which the current value of the register will be copied. * * @return * * - FT_SUCCESS if the PHY was read from successfully * - FXMAC_ERR_PHY_BUSY if there is another PHY operation in progress * * @note * * This function is not thread-safe. The user must provide mutually exclusive * access to this function if there are to be multiple threads that can call it. * * There is the possibility that this function will not return if the hardware * is broken (i.e., it never sets the status bit indicating that the read is * done). If this is of concern to the user, the user should provide a mechanism * suitable to their needs for recovery. * * For the duration of this function, all host interface reads and writes are * blocked to the current FXmac instance. * ******************************************************************************/ FError FXmacPhyRead(FXmac *instance_p, u32 phy_address, u32 register_num, u16 *phydat_aptr) { u32 mgtcr; volatile u32 ipisr; u32 IpReadTemp; FError status; FASSERT(instance_p != NULL); /* Make sure no other PHY operation is currently in progress */ if ((!(FXMAC_READREG32(instance_p->config.base_address, FXMAC_NWSR_OFFSET) & FXMAC_NWSR_MDIOIDLE_MASK)) == TRUE) { status = (FError)(FXMAC_ERR_PHY_BUSY); } else { /* Construct mgtcr mask for the operation */ mgtcr = FXMAC_PHYMNTNC_OP_MASK | FXMAC_PHYMNTNC_OP_R_MASK | (phy_address << FXMAC_PHYMNTNC_PHAD_SHFT_MSK) | (register_num << FXMAC_PHYMNTNC_PREG_SHFT_MSK); /* Write mgtcr and wait for completion */ FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_PHYMNTNC_OFFSET, mgtcr); do { ipisr = FXMAC_READREG32(instance_p->config.base_address, FXMAC_NWSR_OFFSET); IpReadTemp = ipisr; } while ((IpReadTemp & FXMAC_NWSR_MDIOIDLE_MASK) == 0x00000000U); /* Read data */ *phydat_aptr = (u16)FXMAC_READREG32(instance_p->config.base_address, FXMAC_PHYMNTNC_OFFSET); status = (FError)(FT_SUCCESS); } return status; }