0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030 #include "cphy.h"
0031 #include "elmer0.h"
0032
0033
0034
0035
0036
0037
0038 #define MV88x2010_LINK_STATUS_BUGS 1
0039
0040 static int led_init(struct cphy *cphy)
0041 {
0042
0043
0044
0045
0046 cphy_mdio_write(cphy, MDIO_MMD_PCS, 0x8304, 0xdddd);
0047 return 0;
0048 }
0049
0050 static int led_link(struct cphy *cphy, u32 do_enable)
0051 {
0052 u32 led = 0;
0053 #define LINK_ENABLE_BIT 0x1
0054
0055 cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_CTRL2, &led);
0056
0057 if (do_enable & LINK_ENABLE_BIT) {
0058 led |= LINK_ENABLE_BIT;
0059 cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, MDIO_CTRL2, led);
0060 } else {
0061 led &= ~LINK_ENABLE_BIT;
0062 cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, MDIO_CTRL2, led);
0063 }
0064 return 0;
0065 }
0066
0067
0068 static int mv88x201x_reset(struct cphy *cphy, int wait)
0069 {
0070
0071
0072
0073 return 0;
0074 }
0075
0076 static int mv88x201x_interrupt_enable(struct cphy *cphy)
0077 {
0078
0079 cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL,
0080 MDIO_PMA_LASI_LSALARM);
0081
0082
0083 if (t1_is_asic(cphy->adapter)) {
0084 u32 elmer;
0085
0086 t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
0087 elmer |= ELMER0_GP_BIT6;
0088 t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
0089 }
0090 return 0;
0091 }
0092
0093 static int mv88x201x_interrupt_disable(struct cphy *cphy)
0094 {
0095
0096 cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, 0x0);
0097
0098
0099 if (t1_is_asic(cphy->adapter)) {
0100 u32 elmer;
0101
0102 t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
0103 elmer &= ~ELMER0_GP_BIT6;
0104 t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
0105 }
0106 return 0;
0107 }
0108
0109 static int mv88x201x_interrupt_clear(struct cphy *cphy)
0110 {
0111 u32 elmer;
0112 u32 val;
0113
0114 #ifdef MV88x2010_LINK_STATUS_BUGS
0115
0116 cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_RXSTAT, &val);
0117 cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_TXSTAT, &val);
0118 cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT, &val);
0119
0120
0121
0122
0123 cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val);
0124 #endif
0125
0126
0127 cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val);
0128
0129 cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT, &val);
0130
0131 #ifdef MV88x2010_LINK_STATUS_BUGS
0132
0133 cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_RXSTAT, &val);
0134 cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_TXSTAT, &val);
0135 #endif
0136
0137
0138 if (t1_is_asic(cphy->adapter)) {
0139 t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
0140 elmer |= ELMER0_GP_BIT6;
0141 t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
0142 }
0143 return 0;
0144 }
0145
0146 static int mv88x201x_interrupt_handler(struct cphy *cphy)
0147 {
0148
0149 mv88x201x_interrupt_clear(cphy);
0150
0151
0152
0153
0154 return cphy_cause_link_change;
0155 }
0156
0157 static int mv88x201x_set_loopback(struct cphy *cphy, int on)
0158 {
0159 return 0;
0160 }
0161
0162 static int mv88x201x_get_link_status(struct cphy *cphy, int *link_ok,
0163 int *speed, int *duplex, int *fc)
0164 {
0165 u32 val = 0;
0166
0167 if (link_ok) {
0168
0169 cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val);
0170 val &= MDIO_STAT1_LSTATUS;
0171 *link_ok = (val == MDIO_STAT1_LSTATUS);
0172
0173 led_link(cphy, *link_ok);
0174 }
0175 if (speed)
0176 *speed = SPEED_10000;
0177 if (duplex)
0178 *duplex = DUPLEX_FULL;
0179 if (fc)
0180 *fc = PAUSE_RX | PAUSE_TX;
0181 return 0;
0182 }
0183
0184 static void mv88x201x_destroy(struct cphy *cphy)
0185 {
0186 kfree(cphy);
0187 }
0188
0189 static const struct cphy_ops mv88x201x_ops = {
0190 .destroy = mv88x201x_destroy,
0191 .reset = mv88x201x_reset,
0192 .interrupt_enable = mv88x201x_interrupt_enable,
0193 .interrupt_disable = mv88x201x_interrupt_disable,
0194 .interrupt_clear = mv88x201x_interrupt_clear,
0195 .interrupt_handler = mv88x201x_interrupt_handler,
0196 .get_link_status = mv88x201x_get_link_status,
0197 .set_loopback = mv88x201x_set_loopback,
0198 .mmds = (MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS |
0199 MDIO_DEVS_PHYXS | MDIO_DEVS_WIS),
0200 };
0201
0202 static struct cphy *mv88x201x_phy_create(struct net_device *dev, int phy_addr,
0203 const struct mdio_ops *mdio_ops)
0204 {
0205 u32 val;
0206 struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
0207
0208 if (!cphy)
0209 return NULL;
0210
0211 cphy_init(cphy, dev, phy_addr, &mv88x201x_ops, mdio_ops);
0212
0213
0214 cphy_mdio_read(cphy, MDIO_MMD_PCS, 0x8300, &val);
0215 cphy_mdio_write(cphy, MDIO_MMD_PCS, 0x8300, val | 1);
0216
0217
0218 cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT2, &val);
0219 cphy_mdio_read(cphy, MDIO_MMD_PCS, MDIO_STAT2, &val);
0220
0221
0222 led_init(cphy);
0223 return cphy;
0224 }
0225
0226
0227 static int mv88x201x_phy_reset(adapter_t *adapter)
0228 {
0229 u32 val;
0230
0231 t1_tpi_read(adapter, A_ELMER0_GPO, &val);
0232 val &= ~4;
0233 t1_tpi_write(adapter, A_ELMER0_GPO, val);
0234 msleep(100);
0235
0236 t1_tpi_write(adapter, A_ELMER0_GPO, val | 4);
0237 msleep(1000);
0238
0239
0240 t1_tpi_read(adapter, A_ELMER0_GPO, &val);
0241 val |= 0x8000;
0242 t1_tpi_write(adapter, A_ELMER0_GPO, val);
0243 udelay(100);
0244 return 0;
0245 }
0246
0247 const struct gphy t1_mv88x201x_ops = {
0248 .create = mv88x201x_phy_create,
0249 .reset = mv88x201x_phy_reset
0250 };