18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* $Date: 2005/11/12 02:13:49 $ $RCSfile: my3126.c,v $ $Revision: 1.15 $ */ 38c2ecf20Sopenharmony_ci#include "cphy.h" 48c2ecf20Sopenharmony_ci#include "elmer0.h" 58c2ecf20Sopenharmony_ci#include "suni1x10gexp_regs.h" 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci/* Port Reset */ 88c2ecf20Sopenharmony_cistatic int my3126_reset(struct cphy *cphy, int wait) 98c2ecf20Sopenharmony_ci{ 108c2ecf20Sopenharmony_ci /* 118c2ecf20Sopenharmony_ci * This can be done through registers. It is not required since 128c2ecf20Sopenharmony_ci * a full chip reset is used. 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci return 0; 158c2ecf20Sopenharmony_ci} 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistatic int my3126_interrupt_enable(struct cphy *cphy) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci schedule_delayed_work(&cphy->phy_update, HZ/30); 208c2ecf20Sopenharmony_ci t1_tpi_read(cphy->adapter, A_ELMER0_GPO, &cphy->elmer_gpo); 218c2ecf20Sopenharmony_ci return 0; 228c2ecf20Sopenharmony_ci} 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic int my3126_interrupt_disable(struct cphy *cphy) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&cphy->phy_update); 278c2ecf20Sopenharmony_ci return 0; 288c2ecf20Sopenharmony_ci} 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic int my3126_interrupt_clear(struct cphy *cphy) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci return 0; 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define OFFSET(REG_ADDR) (REG_ADDR << 2) 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic int my3126_interrupt_handler(struct cphy *cphy) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci u32 val; 408c2ecf20Sopenharmony_ci u16 val16; 418c2ecf20Sopenharmony_ci u16 status; 428c2ecf20Sopenharmony_ci u32 act_count; 438c2ecf20Sopenharmony_ci adapter_t *adapter; 448c2ecf20Sopenharmony_ci adapter = cphy->adapter; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci if (cphy->count == 50) { 478c2ecf20Sopenharmony_ci cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val); 488c2ecf20Sopenharmony_ci val16 = (u16) val; 498c2ecf20Sopenharmony_ci status = cphy->bmsr ^ val16; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (status & MDIO_STAT1_LSTATUS) 528c2ecf20Sopenharmony_ci t1_link_changed(adapter, 0); 538c2ecf20Sopenharmony_ci cphy->bmsr = val16; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci /* We have only enabled link change interrupts so it 568c2ecf20Sopenharmony_ci must be that 578c2ecf20Sopenharmony_ci */ 588c2ecf20Sopenharmony_ci cphy->count = 0; 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci t1_tpi_write(adapter, OFFSET(SUNI1x10GEXP_REG_MSTAT_CONTROL), 628c2ecf20Sopenharmony_ci SUNI1x10GEXP_BITMSK_MSTAT_SNAP); 638c2ecf20Sopenharmony_ci t1_tpi_read(adapter, 648c2ecf20Sopenharmony_ci OFFSET(SUNI1x10GEXP_REG_MSTAT_COUNTER_1_LOW), &act_count); 658c2ecf20Sopenharmony_ci t1_tpi_read(adapter, 668c2ecf20Sopenharmony_ci OFFSET(SUNI1x10GEXP_REG_MSTAT_COUNTER_33_LOW), &val); 678c2ecf20Sopenharmony_ci act_count += val; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* Populate elmer_gpo with the register value */ 708c2ecf20Sopenharmony_ci t1_tpi_read(adapter, A_ELMER0_GPO, &val); 718c2ecf20Sopenharmony_ci cphy->elmer_gpo = val; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci if ( (val & (1 << 8)) || (val & (1 << 19)) || 748c2ecf20Sopenharmony_ci (cphy->act_count == act_count) || cphy->act_on ) { 758c2ecf20Sopenharmony_ci if (is_T2(adapter)) 768c2ecf20Sopenharmony_ci val |= (1 << 9); 778c2ecf20Sopenharmony_ci else if (t1_is_T1B(adapter)) 788c2ecf20Sopenharmony_ci val |= (1 << 20); 798c2ecf20Sopenharmony_ci cphy->act_on = 0; 808c2ecf20Sopenharmony_ci } else { 818c2ecf20Sopenharmony_ci if (is_T2(adapter)) 828c2ecf20Sopenharmony_ci val &= ~(1 << 9); 838c2ecf20Sopenharmony_ci else if (t1_is_T1B(adapter)) 848c2ecf20Sopenharmony_ci val &= ~(1 << 20); 858c2ecf20Sopenharmony_ci cphy->act_on = 1; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci t1_tpi_write(adapter, A_ELMER0_GPO, val); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci cphy->elmer_gpo = val; 918c2ecf20Sopenharmony_ci cphy->act_count = act_count; 928c2ecf20Sopenharmony_ci cphy->count++; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci return cphy_cause_link_change; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic void my3126_poll(struct work_struct *work) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci struct cphy *cphy = container_of(work, struct cphy, phy_update.work); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci my3126_interrupt_handler(cphy); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic int my3126_set_loopback(struct cphy *cphy, int on) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci return 0; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/* To check the activity LED */ 1108c2ecf20Sopenharmony_cistatic int my3126_get_link_status(struct cphy *cphy, 1118c2ecf20Sopenharmony_ci int *link_ok, int *speed, int *duplex, int *fc) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci u32 val; 1148c2ecf20Sopenharmony_ci u16 val16; 1158c2ecf20Sopenharmony_ci adapter_t *adapter; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci adapter = cphy->adapter; 1188c2ecf20Sopenharmony_ci cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val); 1198c2ecf20Sopenharmony_ci val16 = (u16) val; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci /* Populate elmer_gpo with the register value */ 1228c2ecf20Sopenharmony_ci t1_tpi_read(adapter, A_ELMER0_GPO, &val); 1238c2ecf20Sopenharmony_ci cphy->elmer_gpo = val; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci *link_ok = (val16 & MDIO_STAT1_LSTATUS); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (*link_ok) { 1288c2ecf20Sopenharmony_ci /* Turn on the LED. */ 1298c2ecf20Sopenharmony_ci if (is_T2(adapter)) 1308c2ecf20Sopenharmony_ci val &= ~(1 << 8); 1318c2ecf20Sopenharmony_ci else if (t1_is_T1B(adapter)) 1328c2ecf20Sopenharmony_ci val &= ~(1 << 19); 1338c2ecf20Sopenharmony_ci } else { 1348c2ecf20Sopenharmony_ci /* Turn off the LED. */ 1358c2ecf20Sopenharmony_ci if (is_T2(adapter)) 1368c2ecf20Sopenharmony_ci val |= (1 << 8); 1378c2ecf20Sopenharmony_ci else if (t1_is_T1B(adapter)) 1388c2ecf20Sopenharmony_ci val |= (1 << 19); 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci t1_tpi_write(adapter, A_ELMER0_GPO, val); 1428c2ecf20Sopenharmony_ci cphy->elmer_gpo = val; 1438c2ecf20Sopenharmony_ci *speed = SPEED_10000; 1448c2ecf20Sopenharmony_ci *duplex = DUPLEX_FULL; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /* need to add flow control */ 1478c2ecf20Sopenharmony_ci if (fc) 1488c2ecf20Sopenharmony_ci *fc = PAUSE_RX | PAUSE_TX; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci return 0; 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic void my3126_destroy(struct cphy *cphy) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci kfree(cphy); 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic const struct cphy_ops my3126_ops = { 1598c2ecf20Sopenharmony_ci .destroy = my3126_destroy, 1608c2ecf20Sopenharmony_ci .reset = my3126_reset, 1618c2ecf20Sopenharmony_ci .interrupt_enable = my3126_interrupt_enable, 1628c2ecf20Sopenharmony_ci .interrupt_disable = my3126_interrupt_disable, 1638c2ecf20Sopenharmony_ci .interrupt_clear = my3126_interrupt_clear, 1648c2ecf20Sopenharmony_ci .interrupt_handler = my3126_interrupt_handler, 1658c2ecf20Sopenharmony_ci .get_link_status = my3126_get_link_status, 1668c2ecf20Sopenharmony_ci .set_loopback = my3126_set_loopback, 1678c2ecf20Sopenharmony_ci .mmds = (MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | 1688c2ecf20Sopenharmony_ci MDIO_DEVS_PHYXS), 1698c2ecf20Sopenharmony_ci}; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic struct cphy *my3126_phy_create(struct net_device *dev, 1728c2ecf20Sopenharmony_ci int phy_addr, const struct mdio_ops *mdio_ops) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci struct cphy *cphy = kzalloc(sizeof (*cphy), GFP_KERNEL); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci if (!cphy) 1778c2ecf20Sopenharmony_ci return NULL; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci cphy_init(cphy, dev, phy_addr, &my3126_ops, mdio_ops); 1808c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&cphy->phy_update, my3126_poll); 1818c2ecf20Sopenharmony_ci cphy->bmsr = 0; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci return cphy; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci/* Chip Reset */ 1878c2ecf20Sopenharmony_cistatic int my3126_phy_reset(adapter_t * adapter) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci u32 val; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci t1_tpi_read(adapter, A_ELMER0_GPO, &val); 1928c2ecf20Sopenharmony_ci val &= ~4; 1938c2ecf20Sopenharmony_ci t1_tpi_write(adapter, A_ELMER0_GPO, val); 1948c2ecf20Sopenharmony_ci msleep(100); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci t1_tpi_write(adapter, A_ELMER0_GPO, val | 4); 1978c2ecf20Sopenharmony_ci msleep(1000); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* Now lets enable the Laser. Delay 100us */ 2008c2ecf20Sopenharmony_ci t1_tpi_read(adapter, A_ELMER0_GPO, &val); 2018c2ecf20Sopenharmony_ci val |= 0x8000; 2028c2ecf20Sopenharmony_ci t1_tpi_write(adapter, A_ELMER0_GPO, val); 2038c2ecf20Sopenharmony_ci udelay(100); 2048c2ecf20Sopenharmony_ci return 0; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ciconst struct gphy t1_my3126_ops = { 2088c2ecf20Sopenharmony_ci .create = my3126_phy_create, 2098c2ecf20Sopenharmony_ci .reset = my3126_phy_reset 2108c2ecf20Sopenharmony_ci}; 211