1*d39a76e7Sxw161283 /* 2*d39a76e7Sxw161283 * CDDL HEADER START 3*d39a76e7Sxw161283 * 4*d39a76e7Sxw161283 * The contents of this file are subject to the terms of the 5*d39a76e7Sxw161283 * Common Development and Distribution License (the "License"). 6*d39a76e7Sxw161283 * You may not use this file except in compliance with the License. 7*d39a76e7Sxw161283 * 8*d39a76e7Sxw161283 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*d39a76e7Sxw161283 * or http://www.opensolaris.org/os/licensing. 10*d39a76e7Sxw161283 * See the License for the specific language governing permissions 11*d39a76e7Sxw161283 * and limitations under the License. 12*d39a76e7Sxw161283 * 13*d39a76e7Sxw161283 * When distributing Covered Code, include this CDDL HEADER in each 14*d39a76e7Sxw161283 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*d39a76e7Sxw161283 * If applicable, add the following below this CDDL HEADER, with the 16*d39a76e7Sxw161283 * fields enclosed by brackets "[]" replaced with your own identifying 17*d39a76e7Sxw161283 * information: Portions Copyright [yyyy] [name of copyright owner] 18*d39a76e7Sxw161283 * 19*d39a76e7Sxw161283 * CDDL HEADER END 20*d39a76e7Sxw161283 */ 21*d39a76e7Sxw161283 22*d39a76e7Sxw161283 /* 23*d39a76e7Sxw161283 * Copyright (C) 2003-2005 Chelsio Communications. All rights reserved. 24*d39a76e7Sxw161283 */ 25*d39a76e7Sxw161283 26*d39a76e7Sxw161283 #pragma ident "%Z%%M% %I% %E% SMI" /* my3126.c */ 27*d39a76e7Sxw161283 28*d39a76e7Sxw161283 #include "cphy.h" 29*d39a76e7Sxw161283 #include "elmer0.h" 30*d39a76e7Sxw161283 #include "suni1x10gexp_regs.h" 31*d39a76e7Sxw161283 32*d39a76e7Sxw161283 /* Port Reset */ 33*d39a76e7Sxw161283 /* ARGSUSED */ 34*d39a76e7Sxw161283 static int my3126_reset(struct cphy *cphy, int wait) 35*d39a76e7Sxw161283 { 36*d39a76e7Sxw161283 /* 37*d39a76e7Sxw161283 * This can be done through registers. It is not required since 38*d39a76e7Sxw161283 * a full chip reset is used. 39*d39a76e7Sxw161283 */ 40*d39a76e7Sxw161283 return (0); 41*d39a76e7Sxw161283 } 42*d39a76e7Sxw161283 43*d39a76e7Sxw161283 /* ARGSUSED */ 44*d39a76e7Sxw161283 static int my3126_interrupt_enable(struct cphy *cphy) 45*d39a76e7Sxw161283 { 46*d39a76e7Sxw161283 /* T1 Elmer does not support link/act LED. */ 47*d39a76e7Sxw161283 if (!is_T2(cphy->adapter)) 48*d39a76e7Sxw161283 return (0); 49*d39a76e7Sxw161283 ch_start_cyclic(&cphy->phy_update_cyclic, 30); 50*d39a76e7Sxw161283 (void) t1_tpi_read(cphy->adapter, A_ELMER0_GPO, &cphy->elmer_gpo); 51*d39a76e7Sxw161283 return (0); 52*d39a76e7Sxw161283 } 53*d39a76e7Sxw161283 54*d39a76e7Sxw161283 /* ARGSUSED */ 55*d39a76e7Sxw161283 static int my3126_interrupt_disable(struct cphy *cphy) 56*d39a76e7Sxw161283 { 57*d39a76e7Sxw161283 /* T1 Elmer does not support link/act LED. */ 58*d39a76e7Sxw161283 if (is_T2(cphy->adapter)) 59*d39a76e7Sxw161283 ch_stop_cyclic(&cphy->phy_update_cyclic); 60*d39a76e7Sxw161283 return (0); 61*d39a76e7Sxw161283 } 62*d39a76e7Sxw161283 63*d39a76e7Sxw161283 /* ARGSUSED */ 64*d39a76e7Sxw161283 static int my3126_interrupt_clear(struct cphy *cphy) 65*d39a76e7Sxw161283 { 66*d39a76e7Sxw161283 return (0); 67*d39a76e7Sxw161283 } 68*d39a76e7Sxw161283 69*d39a76e7Sxw161283 #define OFFSET(REG_ADDR) (REG_ADDR << 2) 70*d39a76e7Sxw161283 71*d39a76e7Sxw161283 static int my3126_interrupt_handler(struct cphy *cphy) 72*d39a76e7Sxw161283 { 73*d39a76e7Sxw161283 u32 val; 74*d39a76e7Sxw161283 u16 val16; 75*d39a76e7Sxw161283 u16 status; 76*d39a76e7Sxw161283 u32 act_count; 77*d39a76e7Sxw161283 adapter_t *adapter; 78*d39a76e7Sxw161283 79*d39a76e7Sxw161283 /* T1 Elmer does not support link/act LED. */ 80*d39a76e7Sxw161283 if (!is_T2(cphy->adapter)) 81*d39a76e7Sxw161283 return (cphy_cause_link_change); 82*d39a76e7Sxw161283 83*d39a76e7Sxw161283 adapter = cphy->adapter; 84*d39a76e7Sxw161283 if (cphy->count == 50) { 85*d39a76e7Sxw161283 (void) mdio_read(cphy, 0x1, 0x1, &val); 86*d39a76e7Sxw161283 val16 = (u16) val; 87*d39a76e7Sxw161283 status = cphy->bmsr ^ val16; 88*d39a76e7Sxw161283 89*d39a76e7Sxw161283 if (status & BMSR_LSTATUS) { 90*d39a76e7Sxw161283 link_changed(adapter, 0); 91*d39a76e7Sxw161283 } 92*d39a76e7Sxw161283 cphy->bmsr = val16; 93*d39a76e7Sxw161283 94*d39a76e7Sxw161283 /* We have only enabled link change interrupts so it 95*d39a76e7Sxw161283 must be that 96*d39a76e7Sxw161283 */ 97*d39a76e7Sxw161283 cphy->count = 0; 98*d39a76e7Sxw161283 } 99*d39a76e7Sxw161283 (void) t1_tpi_write(adapter, OFFSET(SUNI1x10GEXP_REG_MSTAT_CONTROL), 100*d39a76e7Sxw161283 SUNI1x10GEXP_BITMSK_MSTAT_SNAP); 101*d39a76e7Sxw161283 (void) t1_tpi_read(adapter, 102*d39a76e7Sxw161283 OFFSET(SUNI1x10GEXP_REG_MSTAT_COUNTER_1_LOW), &act_count); 103*d39a76e7Sxw161283 (void) t1_tpi_read(adapter, 104*d39a76e7Sxw161283 OFFSET(SUNI1x10GEXP_REG_MSTAT_COUNTER_33_LOW), &val); 105*d39a76e7Sxw161283 act_count += val; 106*d39a76e7Sxw161283 val = cphy->elmer_gpo; 107*d39a76e7Sxw161283 if ((val & (1 << 8)) || 108*d39a76e7Sxw161283 (cphy->act_count == act_count) || (cphy->act_on)) { 109*d39a76e7Sxw161283 val |= (1 << 9); 110*d39a76e7Sxw161283 (void) t1_tpi_write(adapter, A_ELMER0_GPO, val); 111*d39a76e7Sxw161283 cphy->act_on = 0; 112*d39a76e7Sxw161283 } else { 113*d39a76e7Sxw161283 val &= ~(1 << 9); 114*d39a76e7Sxw161283 (void) t1_tpi_write(adapter, A_ELMER0_GPO, val); 115*d39a76e7Sxw161283 cphy->act_on = 1; 116*d39a76e7Sxw161283 } 117*d39a76e7Sxw161283 cphy->elmer_gpo = val; 118*d39a76e7Sxw161283 cphy->act_count = act_count; 119*d39a76e7Sxw161283 cphy->count++; 120*d39a76e7Sxw161283 121*d39a76e7Sxw161283 return (cphy_cause_link_change); 122*d39a76e7Sxw161283 } 123*d39a76e7Sxw161283 124*d39a76e7Sxw161283 /* ARGSUSED */ 125*d39a76e7Sxw161283 static int my3126_set_loopback(struct cphy *cphy, int on) 126*d39a76e7Sxw161283 { 127*d39a76e7Sxw161283 return (0); 128*d39a76e7Sxw161283 } 129*d39a76e7Sxw161283 130*d39a76e7Sxw161283 /* To check the activity LED */ 131*d39a76e7Sxw161283 static int my3126_get_link_status(struct cphy *cphy, 132*d39a76e7Sxw161283 int *link_ok, int *speed, int *duplex, int *fc) 133*d39a76e7Sxw161283 { 134*d39a76e7Sxw161283 u32 val; 135*d39a76e7Sxw161283 u16 val16; 136*d39a76e7Sxw161283 adapter_t *adapter; 137*d39a76e7Sxw161283 138*d39a76e7Sxw161283 /* T1 Elmer does not support link/act LED. */ 139*d39a76e7Sxw161283 if (!is_T2(cphy->adapter)) 140*d39a76e7Sxw161283 return (0); 141*d39a76e7Sxw161283 142*d39a76e7Sxw161283 adapter = cphy->adapter; 143*d39a76e7Sxw161283 (void) mdio_read(cphy, 0x1, 0x1, &val); 144*d39a76e7Sxw161283 val16 = (u16) val; 145*d39a76e7Sxw161283 val = cphy->elmer_gpo; 146*d39a76e7Sxw161283 *link_ok = (val16 & BMSR_LSTATUS); 147*d39a76e7Sxw161283 if (*link_ok) { 148*d39a76e7Sxw161283 // Light the LED. 149*d39a76e7Sxw161283 val &= ~(1 << 8); 150*d39a76e7Sxw161283 } else { 151*d39a76e7Sxw161283 // Turn off the LED. 152*d39a76e7Sxw161283 val |= (1 << 8); 153*d39a76e7Sxw161283 } 154*d39a76e7Sxw161283 (void) t1_tpi_write(adapter, A_ELMER0_GPO, val); 155*d39a76e7Sxw161283 cphy->elmer_gpo = val; 156*d39a76e7Sxw161283 *speed = SPEED_10000; 157*d39a76e7Sxw161283 *duplex = DUPLEX_FULL; 158*d39a76e7Sxw161283 /* need to add flow control */ 159*d39a76e7Sxw161283 if (fc) 160*d39a76e7Sxw161283 *fc = PAUSE_RX | PAUSE_TX; 161*d39a76e7Sxw161283 162*d39a76e7Sxw161283 return (0); 163*d39a76e7Sxw161283 } 164*d39a76e7Sxw161283 165*d39a76e7Sxw161283 static void my3126_destroy(struct cphy *cphy) 166*d39a76e7Sxw161283 { 167*d39a76e7Sxw161283 t1_os_free((void *) cphy, sizeof(*cphy)); 168*d39a76e7Sxw161283 } 169*d39a76e7Sxw161283 170*d39a76e7Sxw161283 #ifdef C99_NOT_SUPPORTED 171*d39a76e7Sxw161283 static struct cphy_ops my3126_ops = { 172*d39a76e7Sxw161283 my3126_destroy, 173*d39a76e7Sxw161283 my3126_reset, 174*d39a76e7Sxw161283 my3126_interrupt_enable, 175*d39a76e7Sxw161283 my3126_interrupt_disable, 176*d39a76e7Sxw161283 my3126_interrupt_clear, 177*d39a76e7Sxw161283 my3126_interrupt_handler, 178*d39a76e7Sxw161283 NULL, 179*d39a76e7Sxw161283 NULL, 180*d39a76e7Sxw161283 NULL, 181*d39a76e7Sxw161283 NULL, 182*d39a76e7Sxw161283 my3126_set_loopback, 183*d39a76e7Sxw161283 NULL, 184*d39a76e7Sxw161283 my3126_get_link_status, 185*d39a76e7Sxw161283 }; 186*d39a76e7Sxw161283 #else 187*d39a76e7Sxw161283 static struct cphy_ops my3126_ops = { 188*d39a76e7Sxw161283 .destroy = my3126_destroy, 189*d39a76e7Sxw161283 .reset = my3126_reset, 190*d39a76e7Sxw161283 .interrupt_enable = my3126_interrupt_enable, 191*d39a76e7Sxw161283 .interrupt_disable = my3126_interrupt_disable, 192*d39a76e7Sxw161283 .interrupt_clear = my3126_interrupt_clear, 193*d39a76e7Sxw161283 .interrupt_handler = my3126_interrupt_handler, 194*d39a76e7Sxw161283 .get_link_status = my3126_get_link_status, 195*d39a76e7Sxw161283 .set_loopback = my3126_set_loopback, 196*d39a76e7Sxw161283 }; 197*d39a76e7Sxw161283 #endif 198*d39a76e7Sxw161283 199*d39a76e7Sxw161283 static struct cphy *my3126_phy_create(adapter_t *adapter, int phy_addr, 200*d39a76e7Sxw161283 struct mdio_ops *mdio_ops) 201*d39a76e7Sxw161283 { 202*d39a76e7Sxw161283 struct cphy *cphy = t1_os_malloc_wait_zero(sizeof(*cphy)); 203*d39a76e7Sxw161283 204*d39a76e7Sxw161283 if (cphy) 205*d39a76e7Sxw161283 cphy_init(cphy, adapter, phy_addr, &my3126_ops, mdio_ops); 206*d39a76e7Sxw161283 207*d39a76e7Sxw161283 if (is_T2(adapter)) { 208*d39a76e7Sxw161283 ch_init_cyclic(adapter, &cphy->phy_update_cyclic, 209*d39a76e7Sxw161283 (void (*)(void *))my3126_interrupt_handler, 210*d39a76e7Sxw161283 cphy); 211*d39a76e7Sxw161283 cphy->bmsr = 0; 212*d39a76e7Sxw161283 } 213*d39a76e7Sxw161283 214*d39a76e7Sxw161283 return (cphy); 215*d39a76e7Sxw161283 } 216*d39a76e7Sxw161283 217*d39a76e7Sxw161283 /* Chip Reset */ 218*d39a76e7Sxw161283 static int my3126_phy_reset(adapter_t * adapter) 219*d39a76e7Sxw161283 { 220*d39a76e7Sxw161283 u32 val; 221*d39a76e7Sxw161283 222*d39a76e7Sxw161283 (void) t1_tpi_read(adapter, A_ELMER0_GPO, &val); 223*d39a76e7Sxw161283 val &= ~4; 224*d39a76e7Sxw161283 (void) t1_tpi_write(adapter, A_ELMER0_GPO, val); 225*d39a76e7Sxw161283 DELAY_MS(100); 226*d39a76e7Sxw161283 227*d39a76e7Sxw161283 (void) t1_tpi_write(adapter, A_ELMER0_GPO, val | 4); 228*d39a76e7Sxw161283 DELAY_MS(1000); 229*d39a76e7Sxw161283 230*d39a76e7Sxw161283 /* Now lets enable the Laser. Delay 100us */ 231*d39a76e7Sxw161283 (void) t1_tpi_read(adapter, A_ELMER0_GPO, &val); 232*d39a76e7Sxw161283 val |= 0x8000; 233*d39a76e7Sxw161283 (void) t1_tpi_write(adapter, A_ELMER0_GPO, val); 234*d39a76e7Sxw161283 DELAY_US(100); 235*d39a76e7Sxw161283 return (0); 236*d39a76e7Sxw161283 } 237*d39a76e7Sxw161283 238*d39a76e7Sxw161283 struct gphy t1_my3126_ops = { 239*d39a76e7Sxw161283 my3126_phy_create, 240*d39a76e7Sxw161283 my3126_phy_reset 241*d39a76e7Sxw161283 }; 242