iPXE
smscusb.h
Go to the documentation of this file.
00001 #ifndef _SMSCUSB_H
00002 #define _SMSCUSB_H
00003 
00004 /** @file
00005  *
00006  * SMSC USB Ethernet drivers
00007  *
00008  */
00009 
00010 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00011 
00012 #include <stdint.h>
00013 #include <string.h>
00014 #include <byteswap.h>
00015 #include <ipxe/usb.h>
00016 #include <ipxe/usbnet.h>
00017 #include <ipxe/netdevice.h>
00018 #include <ipxe/mii.h>
00019 #include <ipxe/if_ether.h>
00020 
00021 /** Register write command */
00022 #define SMSCUSB_REGISTER_WRITE                                  \
00023         ( USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE |    \
00024           USB_REQUEST_TYPE ( 0xa0 ) )
00025 
00026 /** Register read command */
00027 #define SMSCUSB_REGISTER_READ                                   \
00028         ( USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE |     \
00029           USB_REQUEST_TYPE ( 0xa1 ) )
00030 
00031 /** Get statistics command */
00032 #define SMSCUSB_GET_STATISTICS                                  \
00033         ( USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE |     \
00034           USB_REQUEST_TYPE ( 0xa2 ) )
00035 
00036 /** EEPROM command register offset */
00037 #define SMSCUSB_E2P_CMD 0x000
00038 #define SMSCUSB_E2P_CMD_EPC_BSY         0x80000000UL    /**< EPC busy */
00039 #define SMSCUSB_E2P_CMD_EPC_CMD_READ    0x00000000UL    /**< READ command */
00040 #define SMSCUSB_E2P_CMD_EPC_ADDR(addr) ( (addr) << 0 )  /**< EPC address */
00041 
00042 /** EEPROM data register offset */
00043 #define SMSCUSB_E2P_DATA 0x004
00044 #define SMSCUSB_E2P_DATA_GET(e2p_data) \
00045         ( ( (e2p_data) >> 0 ) & 0xff )                  /**< EEPROM data */
00046 
00047 /** MAC address EEPROM address */
00048 #define SMSCUSB_EEPROM_MAC 0x01
00049 
00050 /** Maximum time to wait for EEPROM (in milliseconds) */
00051 #define SMSCUSB_EEPROM_MAX_WAIT_MS 100
00052 
00053 /** OTP power register offset */
00054 #define SMSCUSB_OTP_POWER 0x000
00055 #define SMSCUSB_OTP_POWER_DOWN          0x00000001UL    /**< OTP power down */
00056 
00057 /** OTP address high byte register offset */
00058 #define SMSCUSB_OTP_ADDRH 0x004
00059 
00060 /** OTP address low byte register offset */
00061 #define SMSCUSB_OTP_ADDRL 0x008
00062 
00063 /** OTP data register offset */
00064 #define SMSCUSB_OTP_DATA 0x018
00065 #define SMSCUSB_OTP_DATA_GET(otp_data) \
00066         ( ( (otp_data) >> 0 ) & 0xff )                  /**< OTP data */
00067 
00068 /** OTP command selection register offset */
00069 #define SMSCUSB_OTP_CMD 0x020
00070 #define SMSCUSB_OTP_CMD_READ            0x00000001UL    /**< Read command */
00071 
00072 /** OTP command initiation register offset */
00073 #define SMSCUSB_OTP_GO 0x028
00074 #define SMSCUSB_OTP_GO_GO               0x00000001UL    /**< Initiate command */
00075 
00076 /** OTP status register offset */
00077 #define SMSCUSB_OTP_STATUS 0x030
00078 #define SMSCUSB_OTP_STATUS_BUSY         0x00000001UL    /**< OTP busy */
00079 
00080 /** Maximum time to wait for OTP (in milliseconds) */
00081 #define SMSCUSB_OTP_MAX_WAIT_MS 100
00082 
00083 /** OTP layout 1 signature */
00084 #define SMSCUSB_OTP_1_SIG 0xf3
00085 
00086 /** OTP layout 1 MAC address offset */
00087 #define SMSCUSB_OTP_1_MAC 0x001
00088 
00089 /** OTP layout 2 signature */
00090 #define SMSCUSB_OTP_2_SIG 0xf7
00091 
00092 /** OTP layout 2 MAC address offset */
00093 #define SMSCUSB_OTP_2_MAC 0x101
00094 
00095 /** MII access register offset */
00096 #define SMSCUSB_MII_ACCESS 0x000
00097 #define SMSCUSB_MII_ACCESS_PHY_ADDRESS  0x00000800UL    /**< PHY address */
00098 #define SMSCUSB_MII_ACCESS_MIIRINDA(addr) ( (addr) << 6 ) /**< MII register */
00099 #define SMSCUSB_MII_ACCESS_MIIWNR       0x00000002UL    /**< MII write */
00100 #define SMSCUSB_MII_ACCESS_MIIBZY       0x00000001UL    /**< MII busy */
00101 
00102 /** MII data register offset */
00103 #define SMSCUSB_MII_DATA 0x004
00104 #define SMSCUSB_MII_DATA_SET(data)      ( (data) << 0 ) /**< Set data */
00105 #define SMSCUSB_MII_DATA_GET(mii_data) \
00106         ( ( (mii_data) >> 0 ) & 0xffff )                /**< Get data */
00107 
00108 /** Maximum time to wait for MII (in milliseconds) */
00109 #define SMSCUSB_MII_MAX_WAIT_MS 100
00110 
00111 /** MAC address */
00112 union smscusb_mac {
00113         /** MAC receive address registers */
00114         struct {
00115                 /** MAC receive address low register */
00116                 uint32_t l;
00117                 /** MAC receive address high register */
00118                 uint32_t h;
00119         } __attribute__ (( packed )) addr;
00120         /** Raw MAC address */
00121         uint8_t raw[ETH_ALEN];
00122 };
00123 
00124 /** MAC receive address high register offset */
00125 #define SMSCUSB_RX_ADDRH 0x000
00126 
00127 /** MAC receive address low register offset */
00128 #define SMSCUSB_RX_ADDRL 0x004
00129 
00130 /** MAC address perfect filter N high register offset */
00131 #define SMSCUSB_ADDR_FILTH(n) ( 0x000 + ( 8 * (n) ) )
00132 #define SMSCUSB_ADDR_FILTH_VALID        0x80000000UL    /**< Address valid */
00133 
00134 /** MAC address perfect filter N low register offset */
00135 #define SMSCUSB_ADDR_FILTL(n) ( 0x004 + ( 8 * (n) ) )
00136 
00137 /** Interrupt packet format */
00138 struct smscusb_interrupt {
00139         /** Current value of INT_STS register */
00140         uint32_t int_sts;
00141 } __attribute__ (( packed ));
00142 
00143 /** An SMSC USB device */
00144 struct smscusb_device {
00145         /** USB device */
00146         struct usb_device *usb;
00147         /** USB bus */
00148         struct usb_bus *bus;
00149         /** Network device */
00150         struct net_device *netdev;
00151         /** USB network device */
00152         struct usbnet_device usbnet;
00153         /** MII interface */
00154         struct mii_interface mdio;
00155         /** MII device */
00156         struct mii_device mii;
00157         /** MII register base */
00158         uint16_t mii_base;
00159         /** PHY interrupt source register */
00160         uint16_t phy_source;
00161         /** Interrupt status */
00162         uint32_t int_sts;
00163 };
00164 
00165 extern int smscusb_raw_writel ( struct smscusb_device *smscusb,
00166                                 unsigned int address, uint32_t value );
00167 extern int smscusb_raw_readl ( struct smscusb_device *smscusb,
00168                                unsigned int address, uint32_t *value );
00169 
00170 /**
00171  * Write register
00172  *
00173  * @v smscusb           SMSC USB device
00174  * @v address           Register address
00175  * @v value             Register value
00176  * @ret rc              Return status code
00177  */
00178 static inline __attribute__ (( always_inline )) int
00179 smscusb_writel ( struct smscusb_device *smscusb, unsigned int address,
00180                  uint32_t value ) {
00181         int rc;
00182 
00183         /* Write register */
00184         if ( ( rc = smscusb_raw_writel ( smscusb, address,
00185                                          cpu_to_le32 ( value ) ) ) != 0 )
00186                 return rc;
00187 
00188         return 0;
00189 }
00190 
00191 /**
00192  * Read register
00193  *
00194  * @v smscusb           SMSC USB device
00195  * @v address           Register address
00196  * @ret value           Register value
00197  * @ret rc              Return status code
00198  */
00199 static inline __attribute__ (( always_inline )) int
00200 smscusb_readl ( struct smscusb_device *smscusb, unsigned int address,
00201                 uint32_t *value ) {
00202         int rc;
00203 
00204         /* Read register */
00205         if ( ( rc = smscusb_raw_readl ( smscusb, address, value ) ) != 0 )
00206                 return rc;
00207         le32_to_cpus ( value );
00208 
00209         return 0;
00210 }
00211 
00212 /**
00213  * Get statistics
00214  *
00215  * @v smscusb           SMSC USB device
00216  * @v index             Statistics set index
00217  * @v data              Statistics data to fill in
00218  * @v len               Length of statistics data
00219  * @ret rc              Return status code
00220  */
00221 static inline __attribute__ (( always_inline )) int
00222 smscusb_get_statistics ( struct smscusb_device *smscusb, unsigned int index,
00223                          void *data, size_t len ) {
00224         int rc;
00225 
00226         /* Read statistics */
00227         if ( ( rc = usb_control ( smscusb->usb, SMSCUSB_GET_STATISTICS, 0,
00228                                   index, data, len ) ) != 0 ) {
00229                 DBGC ( smscusb, "SMSCUSB %p could not get statistics set %d: "
00230                        "%s\n", smscusb, index, strerror ( rc ) );
00231                 return rc;
00232         }
00233 
00234         return 0;
00235 }
00236 
00237 /** Interrupt maximum fill level
00238  *
00239  * This is a policy decision.
00240  */
00241 #define SMSCUSB_INTR_MAX_FILL 2
00242 
00243 extern struct usb_endpoint_driver_operations smscusb_intr_operations;
00244 extern struct usb_endpoint_driver_operations smscusb_out_operations;
00245 extern struct mii_operations smscusb_mii_operations;
00246 
00247 /**
00248  * Initialise SMSC USB device
00249  *
00250  * @v smscusb           SMSC USB device
00251  * @v netdev            Network device
00252  * @v func              USB function
00253  * @v in                Bulk IN endpoint operations
00254  */
00255 static inline __attribute__ (( always_inline )) void
00256 smscusb_init ( struct smscusb_device *smscusb, struct net_device *netdev,
00257                struct usb_function *func,
00258                struct usb_endpoint_driver_operations *in ) {
00259         struct usb_device *usb = func->usb;
00260 
00261         smscusb->usb = usb;
00262         smscusb->bus = usb->port->hub->bus;
00263         smscusb->netdev = netdev;
00264         usbnet_init ( &smscusb->usbnet, func, &smscusb_intr_operations, in,
00265                       &smscusb_out_operations );
00266         usb_refill_init ( &smscusb->usbnet.intr, 0, 0, SMSCUSB_INTR_MAX_FILL );
00267 }
00268 
00269 /**
00270  * Initialise SMSC USB device MII interface
00271  *
00272  * @v smscusb           SMSC USB device
00273  * @v mii_base          MII register base
00274  * @v phy_source        Interrupt source PHY register
00275  */
00276 static inline __attribute__ (( always_inline )) void
00277 smscusb_mii_init ( struct smscusb_device *smscusb, unsigned int mii_base,
00278                    unsigned int phy_source ) {
00279 
00280         mdio_init ( &smscusb->mdio, &smscusb_mii_operations );
00281         mii_init ( &smscusb->mii, &smscusb->mdio, 0 );
00282         smscusb->mii_base = mii_base;
00283         smscusb->phy_source = phy_source;
00284 }
00285 
00286 extern int smscusb_eeprom_fetch_mac ( struct smscusb_device *smscusb,
00287                                       unsigned int e2p_base );
00288 extern int smscusb_otp_fetch_mac ( struct smscusb_device *smscusb,
00289                                    unsigned int otp_base );
00290 extern int smscusb_mii_check_link ( struct smscusb_device *smscusb );
00291 extern int smscusb_mii_open ( struct smscusb_device *smscusb,
00292                               unsigned int phy_mask, unsigned int intrs );
00293 extern int smscusb_set_address ( struct smscusb_device *smscusb,
00294                                  unsigned int addr_base );
00295 extern int smscusb_set_filter ( struct smscusb_device *smscusb,
00296                                 unsigned int filt_base );
00297 
00298 #endif /* _SMSCUSB_H */