162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* $Date: 2006/04/28 19:20:06 $ $RCSfile: vsc7326.c,v $ $Revision: 1.19 $ */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci/* Driver for Vitesse VSC7326 (Schaumburg) MAC */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include "gmac.h" 762306a36Sopenharmony_ci#include "elmer0.h" 862306a36Sopenharmony_ci#include "vsc7326_reg.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* Update fast changing statistics every 15 seconds */ 1162306a36Sopenharmony_ci#define STATS_TICK_SECS 15 1262306a36Sopenharmony_ci/* 30 minutes for full statistics update */ 1362306a36Sopenharmony_ci#define MAJOR_UPDATE_TICKS (1800 / STATS_TICK_SECS) 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* The egress WM value 0x01a01fff should be used only when the 1662306a36Sopenharmony_ci * interface is down (MAC port disabled). This is a workaround 1762306a36Sopenharmony_ci * for disabling the T2/MAC flow-control. When the interface is 1862306a36Sopenharmony_ci * enabled, the WM value should be set to 0x014a03F0. 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ci#define WM_DISABLE 0x01a01fff 2162306a36Sopenharmony_ci#define WM_ENABLE 0x014a03F0 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistruct init_table { 2462306a36Sopenharmony_ci u32 addr; 2562306a36Sopenharmony_ci u32 data; 2662306a36Sopenharmony_ci}; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistruct _cmac_instance { 2962306a36Sopenharmony_ci u32 index; 3062306a36Sopenharmony_ci u32 ticks; 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define INITBLOCK_SLEEP 0xffffffff 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic void vsc_read(adapter_t *adapter, u32 addr, u32 *val) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci u32 status, vlo, vhi; 3862306a36Sopenharmony_ci int i; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci spin_lock_bh(&adapter->mac_lock); 4162306a36Sopenharmony_ci t1_tpi_read(adapter, (addr << 2) + 4, &vlo); 4262306a36Sopenharmony_ci i = 0; 4362306a36Sopenharmony_ci do { 4462306a36Sopenharmony_ci t1_tpi_read(adapter, (REG_LOCAL_STATUS << 2) + 4, &vlo); 4562306a36Sopenharmony_ci t1_tpi_read(adapter, REG_LOCAL_STATUS << 2, &vhi); 4662306a36Sopenharmony_ci status = (vhi << 16) | vlo; 4762306a36Sopenharmony_ci i++; 4862306a36Sopenharmony_ci } while (((status & 1) == 0) && (i < 50)); 4962306a36Sopenharmony_ci if (i == 50) 5062306a36Sopenharmony_ci pr_err("Invalid tpi read from MAC, breaking loop.\n"); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci t1_tpi_read(adapter, (REG_LOCAL_DATA << 2) + 4, &vlo); 5362306a36Sopenharmony_ci t1_tpi_read(adapter, REG_LOCAL_DATA << 2, &vhi); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci *val = (vhi << 16) | vlo; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci /* pr_err("rd: block: 0x%x sublock: 0x%x reg: 0x%x data: 0x%x\n", 5862306a36Sopenharmony_ci ((addr&0xe000)>>13), ((addr&0x1e00)>>9), 5962306a36Sopenharmony_ci ((addr&0x01fe)>>1), *val); */ 6062306a36Sopenharmony_ci spin_unlock_bh(&adapter->mac_lock); 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic void vsc_write(adapter_t *adapter, u32 addr, u32 data) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci spin_lock_bh(&adapter->mac_lock); 6662306a36Sopenharmony_ci t1_tpi_write(adapter, (addr << 2) + 4, data & 0xFFFF); 6762306a36Sopenharmony_ci t1_tpi_write(adapter, addr << 2, (data >> 16) & 0xFFFF); 6862306a36Sopenharmony_ci /* pr_err("wr: block: 0x%x sublock: 0x%x reg: 0x%x data: 0x%x\n", 6962306a36Sopenharmony_ci ((addr&0xe000)>>13), ((addr&0x1e00)>>9), 7062306a36Sopenharmony_ci ((addr&0x01fe)>>1), data); */ 7162306a36Sopenharmony_ci spin_unlock_bh(&adapter->mac_lock); 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* Hard reset the MAC. This wipes out *all* configuration. */ 7562306a36Sopenharmony_cistatic void vsc7326_full_reset(adapter_t* adapter) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci u32 val; 7862306a36Sopenharmony_ci u32 result = 0xffff; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci t1_tpi_read(adapter, A_ELMER0_GPO, &val); 8162306a36Sopenharmony_ci val &= ~1; 8262306a36Sopenharmony_ci t1_tpi_write(adapter, A_ELMER0_GPO, val); 8362306a36Sopenharmony_ci udelay(2); 8462306a36Sopenharmony_ci val |= 0x1; /* Enable mac MAC itself */ 8562306a36Sopenharmony_ci val |= 0x800; /* Turn off the red LED */ 8662306a36Sopenharmony_ci t1_tpi_write(adapter, A_ELMER0_GPO, val); 8762306a36Sopenharmony_ci mdelay(1); 8862306a36Sopenharmony_ci vsc_write(adapter, REG_SW_RESET, 0x80000001); 8962306a36Sopenharmony_ci do { 9062306a36Sopenharmony_ci mdelay(1); 9162306a36Sopenharmony_ci vsc_read(adapter, REG_SW_RESET, &result); 9262306a36Sopenharmony_ci } while (result != 0x0); 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic struct init_table vsc7326_reset[] = { 9662306a36Sopenharmony_ci { REG_IFACE_MODE, 0x00000000 }, 9762306a36Sopenharmony_ci { REG_CRC_CFG, 0x00000020 }, 9862306a36Sopenharmony_ci { REG_PLL_CLK_SPEED, 0x00050c00 }, 9962306a36Sopenharmony_ci { REG_PLL_CLK_SPEED, 0x00050c00 }, 10062306a36Sopenharmony_ci { REG_MSCH, 0x00002f14 }, 10162306a36Sopenharmony_ci { REG_SPI4_MISC, 0x00040409 }, 10262306a36Sopenharmony_ci { REG_SPI4_DESKEW, 0x00080000 }, 10362306a36Sopenharmony_ci { REG_SPI4_ING_SETUP2, 0x08080004 }, 10462306a36Sopenharmony_ci { REG_SPI4_ING_SETUP0, 0x04111004 }, 10562306a36Sopenharmony_ci { REG_SPI4_EGR_SETUP0, 0x80001a04 }, 10662306a36Sopenharmony_ci { REG_SPI4_ING_SETUP1, 0x02010000 }, 10762306a36Sopenharmony_ci { REG_AGE_INC(0), 0x00000000 }, 10862306a36Sopenharmony_ci { REG_AGE_INC(1), 0x00000000 }, 10962306a36Sopenharmony_ci { REG_ING_CONTROL, 0x0a200011 }, 11062306a36Sopenharmony_ci { REG_EGR_CONTROL, 0xa0010091 }, 11162306a36Sopenharmony_ci}; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic struct init_table vsc7326_portinit[4][22] = { 11462306a36Sopenharmony_ci { /* Port 0 */ 11562306a36Sopenharmony_ci /* FIFO setup */ 11662306a36Sopenharmony_ci { REG_DBG(0), 0x000004f0 }, 11762306a36Sopenharmony_ci { REG_HDX(0), 0x00073101 }, 11862306a36Sopenharmony_ci { REG_TEST(0,0), 0x00000022 }, 11962306a36Sopenharmony_ci { REG_TEST(1,0), 0x00000022 }, 12062306a36Sopenharmony_ci { REG_TOP_BOTTOM(0,0), 0x003f0000 }, 12162306a36Sopenharmony_ci { REG_TOP_BOTTOM(1,0), 0x00120000 }, 12262306a36Sopenharmony_ci { REG_HIGH_LOW_WM(0,0), 0x07460757 }, 12362306a36Sopenharmony_ci { REG_HIGH_LOW_WM(1,0), WM_DISABLE }, 12462306a36Sopenharmony_ci { REG_CT_THRHLD(0,0), 0x00000000 }, 12562306a36Sopenharmony_ci { REG_CT_THRHLD(1,0), 0x00000000 }, 12662306a36Sopenharmony_ci { REG_BUCKE(0), 0x0002ffff }, 12762306a36Sopenharmony_ci { REG_BUCKI(0), 0x0002ffff }, 12862306a36Sopenharmony_ci { REG_TEST(0,0), 0x00000020 }, 12962306a36Sopenharmony_ci { REG_TEST(1,0), 0x00000020 }, 13062306a36Sopenharmony_ci /* Port config */ 13162306a36Sopenharmony_ci { REG_MAX_LEN(0), 0x00002710 }, 13262306a36Sopenharmony_ci { REG_PORT_FAIL(0), 0x00000002 }, 13362306a36Sopenharmony_ci { REG_NORMALIZER(0), 0x00000a64 }, 13462306a36Sopenharmony_ci { REG_DENORM(0), 0x00000010 }, 13562306a36Sopenharmony_ci { REG_STICK_BIT(0), 0x03baa370 }, 13662306a36Sopenharmony_ci { REG_DEV_SETUP(0), 0x00000083 }, 13762306a36Sopenharmony_ci { REG_DEV_SETUP(0), 0x00000082 }, 13862306a36Sopenharmony_ci { REG_MODE_CFG(0), 0x0200259f }, 13962306a36Sopenharmony_ci }, 14062306a36Sopenharmony_ci { /* Port 1 */ 14162306a36Sopenharmony_ci /* FIFO setup */ 14262306a36Sopenharmony_ci { REG_DBG(1), 0x000004f0 }, 14362306a36Sopenharmony_ci { REG_HDX(1), 0x00073101 }, 14462306a36Sopenharmony_ci { REG_TEST(0,1), 0x00000022 }, 14562306a36Sopenharmony_ci { REG_TEST(1,1), 0x00000022 }, 14662306a36Sopenharmony_ci { REG_TOP_BOTTOM(0,1), 0x007e003f }, 14762306a36Sopenharmony_ci { REG_TOP_BOTTOM(1,1), 0x00240012 }, 14862306a36Sopenharmony_ci { REG_HIGH_LOW_WM(0,1), 0x07460757 }, 14962306a36Sopenharmony_ci { REG_HIGH_LOW_WM(1,1), WM_DISABLE }, 15062306a36Sopenharmony_ci { REG_CT_THRHLD(0,1), 0x00000000 }, 15162306a36Sopenharmony_ci { REG_CT_THRHLD(1,1), 0x00000000 }, 15262306a36Sopenharmony_ci { REG_BUCKE(1), 0x0002ffff }, 15362306a36Sopenharmony_ci { REG_BUCKI(1), 0x0002ffff }, 15462306a36Sopenharmony_ci { REG_TEST(0,1), 0x00000020 }, 15562306a36Sopenharmony_ci { REG_TEST(1,1), 0x00000020 }, 15662306a36Sopenharmony_ci /* Port config */ 15762306a36Sopenharmony_ci { REG_MAX_LEN(1), 0x00002710 }, 15862306a36Sopenharmony_ci { REG_PORT_FAIL(1), 0x00000002 }, 15962306a36Sopenharmony_ci { REG_NORMALIZER(1), 0x00000a64 }, 16062306a36Sopenharmony_ci { REG_DENORM(1), 0x00000010 }, 16162306a36Sopenharmony_ci { REG_STICK_BIT(1), 0x03baa370 }, 16262306a36Sopenharmony_ci { REG_DEV_SETUP(1), 0x00000083 }, 16362306a36Sopenharmony_ci { REG_DEV_SETUP(1), 0x00000082 }, 16462306a36Sopenharmony_ci { REG_MODE_CFG(1), 0x0200259f }, 16562306a36Sopenharmony_ci }, 16662306a36Sopenharmony_ci { /* Port 2 */ 16762306a36Sopenharmony_ci /* FIFO setup */ 16862306a36Sopenharmony_ci { REG_DBG(2), 0x000004f0 }, 16962306a36Sopenharmony_ci { REG_HDX(2), 0x00073101 }, 17062306a36Sopenharmony_ci { REG_TEST(0,2), 0x00000022 }, 17162306a36Sopenharmony_ci { REG_TEST(1,2), 0x00000022 }, 17262306a36Sopenharmony_ci { REG_TOP_BOTTOM(0,2), 0x00bd007e }, 17362306a36Sopenharmony_ci { REG_TOP_BOTTOM(1,2), 0x00360024 }, 17462306a36Sopenharmony_ci { REG_HIGH_LOW_WM(0,2), 0x07460757 }, 17562306a36Sopenharmony_ci { REG_HIGH_LOW_WM(1,2), WM_DISABLE }, 17662306a36Sopenharmony_ci { REG_CT_THRHLD(0,2), 0x00000000 }, 17762306a36Sopenharmony_ci { REG_CT_THRHLD(1,2), 0x00000000 }, 17862306a36Sopenharmony_ci { REG_BUCKE(2), 0x0002ffff }, 17962306a36Sopenharmony_ci { REG_BUCKI(2), 0x0002ffff }, 18062306a36Sopenharmony_ci { REG_TEST(0,2), 0x00000020 }, 18162306a36Sopenharmony_ci { REG_TEST(1,2), 0x00000020 }, 18262306a36Sopenharmony_ci /* Port config */ 18362306a36Sopenharmony_ci { REG_MAX_LEN(2), 0x00002710 }, 18462306a36Sopenharmony_ci { REG_PORT_FAIL(2), 0x00000002 }, 18562306a36Sopenharmony_ci { REG_NORMALIZER(2), 0x00000a64 }, 18662306a36Sopenharmony_ci { REG_DENORM(2), 0x00000010 }, 18762306a36Sopenharmony_ci { REG_STICK_BIT(2), 0x03baa370 }, 18862306a36Sopenharmony_ci { REG_DEV_SETUP(2), 0x00000083 }, 18962306a36Sopenharmony_ci { REG_DEV_SETUP(2), 0x00000082 }, 19062306a36Sopenharmony_ci { REG_MODE_CFG(2), 0x0200259f }, 19162306a36Sopenharmony_ci }, 19262306a36Sopenharmony_ci { /* Port 3 */ 19362306a36Sopenharmony_ci /* FIFO setup */ 19462306a36Sopenharmony_ci { REG_DBG(3), 0x000004f0 }, 19562306a36Sopenharmony_ci { REG_HDX(3), 0x00073101 }, 19662306a36Sopenharmony_ci { REG_TEST(0,3), 0x00000022 }, 19762306a36Sopenharmony_ci { REG_TEST(1,3), 0x00000022 }, 19862306a36Sopenharmony_ci { REG_TOP_BOTTOM(0,3), 0x00fc00bd }, 19962306a36Sopenharmony_ci { REG_TOP_BOTTOM(1,3), 0x00480036 }, 20062306a36Sopenharmony_ci { REG_HIGH_LOW_WM(0,3), 0x07460757 }, 20162306a36Sopenharmony_ci { REG_HIGH_LOW_WM(1,3), WM_DISABLE }, 20262306a36Sopenharmony_ci { REG_CT_THRHLD(0,3), 0x00000000 }, 20362306a36Sopenharmony_ci { REG_CT_THRHLD(1,3), 0x00000000 }, 20462306a36Sopenharmony_ci { REG_BUCKE(3), 0x0002ffff }, 20562306a36Sopenharmony_ci { REG_BUCKI(3), 0x0002ffff }, 20662306a36Sopenharmony_ci { REG_TEST(0,3), 0x00000020 }, 20762306a36Sopenharmony_ci { REG_TEST(1,3), 0x00000020 }, 20862306a36Sopenharmony_ci /* Port config */ 20962306a36Sopenharmony_ci { REG_MAX_LEN(3), 0x00002710 }, 21062306a36Sopenharmony_ci { REG_PORT_FAIL(3), 0x00000002 }, 21162306a36Sopenharmony_ci { REG_NORMALIZER(3), 0x00000a64 }, 21262306a36Sopenharmony_ci { REG_DENORM(3), 0x00000010 }, 21362306a36Sopenharmony_ci { REG_STICK_BIT(3), 0x03baa370 }, 21462306a36Sopenharmony_ci { REG_DEV_SETUP(3), 0x00000083 }, 21562306a36Sopenharmony_ci { REG_DEV_SETUP(3), 0x00000082 }, 21662306a36Sopenharmony_ci { REG_MODE_CFG(3), 0x0200259f }, 21762306a36Sopenharmony_ci }, 21862306a36Sopenharmony_ci}; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic void run_table(adapter_t *adapter, struct init_table *ib, int len) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci int i; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci for (i = 0; i < len; i++) { 22562306a36Sopenharmony_ci if (ib[i].addr == INITBLOCK_SLEEP) { 22662306a36Sopenharmony_ci udelay( ib[i].data ); 22762306a36Sopenharmony_ci pr_err("sleep %d us\n",ib[i].data); 22862306a36Sopenharmony_ci } else 22962306a36Sopenharmony_ci vsc_write( adapter, ib[i].addr, ib[i].data ); 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic int bist_rd(adapter_t *adapter, int moduleid, int address) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci int data = 0; 23662306a36Sopenharmony_ci u32 result = 0; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if ((address != 0x0) && 23962306a36Sopenharmony_ci (address != 0x1) && 24062306a36Sopenharmony_ci (address != 0x2) && 24162306a36Sopenharmony_ci (address != 0xd) && 24262306a36Sopenharmony_ci (address != 0xe)) 24362306a36Sopenharmony_ci pr_err("No bist address: 0x%x\n", address); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci data = ((0x00 << 24) | ((address & 0xff) << 16) | (0x00 << 8) | 24662306a36Sopenharmony_ci ((moduleid & 0xff) << 0)); 24762306a36Sopenharmony_ci vsc_write(adapter, REG_RAM_BIST_CMD, data); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci udelay(10); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci vsc_read(adapter, REG_RAM_BIST_RESULT, &result); 25262306a36Sopenharmony_ci if ((result & (1 << 9)) != 0x0) 25362306a36Sopenharmony_ci pr_err("Still in bist read: 0x%x\n", result); 25462306a36Sopenharmony_ci else if ((result & (1 << 8)) != 0x0) 25562306a36Sopenharmony_ci pr_err("bist read error: 0x%x\n", result); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci return result & 0xff; 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic int bist_wr(adapter_t *adapter, int moduleid, int address, int value) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci int data = 0; 26362306a36Sopenharmony_ci u32 result = 0; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if ((address != 0x0) && 26662306a36Sopenharmony_ci (address != 0x1) && 26762306a36Sopenharmony_ci (address != 0x2) && 26862306a36Sopenharmony_ci (address != 0xd) && 26962306a36Sopenharmony_ci (address != 0xe)) 27062306a36Sopenharmony_ci pr_err("No bist address: 0x%x\n", address); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (value > 255) 27362306a36Sopenharmony_ci pr_err("Suspicious write out of range value: 0x%x\n", value); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci data = ((0x01 << 24) | ((address & 0xff) << 16) | (value << 8) | 27662306a36Sopenharmony_ci ((moduleid & 0xff) << 0)); 27762306a36Sopenharmony_ci vsc_write(adapter, REG_RAM_BIST_CMD, data); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci udelay(5); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci vsc_read(adapter, REG_RAM_BIST_CMD, &result); 28262306a36Sopenharmony_ci if ((result & (1 << 27)) != 0x0) 28362306a36Sopenharmony_ci pr_err("Still in bist write: 0x%x\n", result); 28462306a36Sopenharmony_ci else if ((result & (1 << 26)) != 0x0) 28562306a36Sopenharmony_ci pr_err("bist write error: 0x%x\n", result); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci return 0; 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic int run_bist(adapter_t *adapter, int moduleid) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci /*run bist*/ 29362306a36Sopenharmony_ci (void) bist_wr(adapter,moduleid, 0x00, 0x02); 29462306a36Sopenharmony_ci (void) bist_wr(adapter,moduleid, 0x01, 0x01); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci return 0; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic int check_bist(adapter_t *adapter, int moduleid) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci int result=0; 30262306a36Sopenharmony_ci int column=0; 30362306a36Sopenharmony_ci /*check bist*/ 30462306a36Sopenharmony_ci result = bist_rd(adapter,moduleid, 0x02); 30562306a36Sopenharmony_ci column = ((bist_rd(adapter,moduleid, 0x0e)<<8) + 30662306a36Sopenharmony_ci (bist_rd(adapter,moduleid, 0x0d))); 30762306a36Sopenharmony_ci if ((result & 3) != 0x3) 30862306a36Sopenharmony_ci pr_err("Result: 0x%x BIST error in ram %d, column: 0x%04x\n", 30962306a36Sopenharmony_ci result, moduleid, column); 31062306a36Sopenharmony_ci return 0; 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic int enable_mem(adapter_t *adapter, int moduleid) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci /*enable mem*/ 31662306a36Sopenharmony_ci (void) bist_wr(adapter,moduleid, 0x00, 0x00); 31762306a36Sopenharmony_ci return 0; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic int run_bist_all(adapter_t *adapter) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci int port = 0; 32362306a36Sopenharmony_ci u32 val = 0; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci vsc_write(adapter, REG_MEM_BIST, 0x5); 32662306a36Sopenharmony_ci vsc_read(adapter, REG_MEM_BIST, &val); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci for (port = 0; port < 12; port++) 32962306a36Sopenharmony_ci vsc_write(adapter, REG_DEV_SETUP(port), 0x0); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci udelay(300); 33262306a36Sopenharmony_ci vsc_write(adapter, REG_SPI4_MISC, 0x00040409); 33362306a36Sopenharmony_ci udelay(300); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci (void) run_bist(adapter,13); 33662306a36Sopenharmony_ci (void) run_bist(adapter,14); 33762306a36Sopenharmony_ci (void) run_bist(adapter,20); 33862306a36Sopenharmony_ci (void) run_bist(adapter,21); 33962306a36Sopenharmony_ci mdelay(200); 34062306a36Sopenharmony_ci (void) check_bist(adapter,13); 34162306a36Sopenharmony_ci (void) check_bist(adapter,14); 34262306a36Sopenharmony_ci (void) check_bist(adapter,20); 34362306a36Sopenharmony_ci (void) check_bist(adapter,21); 34462306a36Sopenharmony_ci udelay(100); 34562306a36Sopenharmony_ci (void) enable_mem(adapter,13); 34662306a36Sopenharmony_ci (void) enable_mem(adapter,14); 34762306a36Sopenharmony_ci (void) enable_mem(adapter,20); 34862306a36Sopenharmony_ci (void) enable_mem(adapter,21); 34962306a36Sopenharmony_ci udelay(300); 35062306a36Sopenharmony_ci vsc_write(adapter, REG_SPI4_MISC, 0x60040400); 35162306a36Sopenharmony_ci udelay(300); 35262306a36Sopenharmony_ci for (port = 0; port < 12; port++) 35362306a36Sopenharmony_ci vsc_write(adapter, REG_DEV_SETUP(port), 0x1); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci udelay(300); 35662306a36Sopenharmony_ci vsc_write(adapter, REG_MEM_BIST, 0x0); 35762306a36Sopenharmony_ci mdelay(10); 35862306a36Sopenharmony_ci return 0; 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic int mac_intr_handler(struct cmac *mac) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci return 0; 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic int mac_intr_enable(struct cmac *mac) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci return 0; 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic int mac_intr_disable(struct cmac *mac) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci return 0; 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic int mac_intr_clear(struct cmac *mac) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci return 0; 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci/* Expect MAC address to be in network byte order. */ 38262306a36Sopenharmony_cistatic int mac_set_address(struct cmac* mac, const u8 addr[6]) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci u32 val; 38562306a36Sopenharmony_ci int port = mac->instance->index; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci vsc_write(mac->adapter, REG_MAC_LOW_ADDR(port), 38862306a36Sopenharmony_ci (addr[3] << 16) | (addr[4] << 8) | addr[5]); 38962306a36Sopenharmony_ci vsc_write(mac->adapter, REG_MAC_HIGH_ADDR(port), 39062306a36Sopenharmony_ci (addr[0] << 16) | (addr[1] << 8) | addr[2]); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci vsc_read(mac->adapter, REG_ING_FFILT_UM_EN, &val); 39362306a36Sopenharmony_ci val &= ~0xf0000000; 39462306a36Sopenharmony_ci vsc_write(mac->adapter, REG_ING_FFILT_UM_EN, val | (port << 28)); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci vsc_write(mac->adapter, REG_ING_FFILT_MASK0, 39762306a36Sopenharmony_ci 0xffff0000 | (addr[4] << 8) | addr[5]); 39862306a36Sopenharmony_ci vsc_write(mac->adapter, REG_ING_FFILT_MASK1, 39962306a36Sopenharmony_ci 0xffff0000 | (addr[2] << 8) | addr[3]); 40062306a36Sopenharmony_ci vsc_write(mac->adapter, REG_ING_FFILT_MASK2, 40162306a36Sopenharmony_ci 0xffff0000 | (addr[0] << 8) | addr[1]); 40262306a36Sopenharmony_ci return 0; 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cistatic int mac_get_address(struct cmac *mac, u8 addr[6]) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci u32 addr_lo, addr_hi; 40862306a36Sopenharmony_ci int port = mac->instance->index; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci vsc_read(mac->adapter, REG_MAC_LOW_ADDR(port), &addr_lo); 41162306a36Sopenharmony_ci vsc_read(mac->adapter, REG_MAC_HIGH_ADDR(port), &addr_hi); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci addr[0] = (u8) (addr_hi >> 16); 41462306a36Sopenharmony_ci addr[1] = (u8) (addr_hi >> 8); 41562306a36Sopenharmony_ci addr[2] = (u8) addr_hi; 41662306a36Sopenharmony_ci addr[3] = (u8) (addr_lo >> 16); 41762306a36Sopenharmony_ci addr[4] = (u8) (addr_lo >> 8); 41862306a36Sopenharmony_ci addr[5] = (u8) addr_lo; 41962306a36Sopenharmony_ci return 0; 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci/* This is intended to reset a port, not the whole MAC */ 42362306a36Sopenharmony_cistatic int mac_reset(struct cmac *mac) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci int index = mac->instance->index; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci run_table(mac->adapter, vsc7326_portinit[index], 42862306a36Sopenharmony_ci ARRAY_SIZE(vsc7326_portinit[index])); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci return 0; 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci u32 v; 43662306a36Sopenharmony_ci int port = mac->instance->index; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci vsc_read(mac->adapter, REG_ING_FFILT_UM_EN, &v); 43962306a36Sopenharmony_ci v |= 1 << 12; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci if (t1_rx_mode_promisc(rm)) 44262306a36Sopenharmony_ci v &= ~(1 << (port + 16)); 44362306a36Sopenharmony_ci else 44462306a36Sopenharmony_ci v |= 1 << (port + 16); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci vsc_write(mac->adapter, REG_ING_FFILT_UM_EN, v); 44762306a36Sopenharmony_ci return 0; 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic int mac_set_mtu(struct cmac *mac, int mtu) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci int port = mac->instance->index; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci /* max_len includes header and FCS */ 45562306a36Sopenharmony_ci vsc_write(mac->adapter, REG_MAX_LEN(port), mtu + 14 + 4); 45662306a36Sopenharmony_ci return 0; 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_cistatic int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, 46062306a36Sopenharmony_ci int fc) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci u32 v; 46362306a36Sopenharmony_ci int enable, port = mac->instance->index; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci if (speed >= 0 && speed != SPEED_10 && speed != SPEED_100 && 46662306a36Sopenharmony_ci speed != SPEED_1000) 46762306a36Sopenharmony_ci return -1; 46862306a36Sopenharmony_ci if (duplex > 0 && duplex != DUPLEX_FULL) 46962306a36Sopenharmony_ci return -1; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci if (speed >= 0) { 47262306a36Sopenharmony_ci vsc_read(mac->adapter, REG_MODE_CFG(port), &v); 47362306a36Sopenharmony_ci enable = v & 3; /* save tx/rx enables */ 47462306a36Sopenharmony_ci v &= ~0xf; 47562306a36Sopenharmony_ci v |= 4; /* full duplex */ 47662306a36Sopenharmony_ci if (speed == SPEED_1000) 47762306a36Sopenharmony_ci v |= 8; /* GigE */ 47862306a36Sopenharmony_ci enable |= v; 47962306a36Sopenharmony_ci vsc_write(mac->adapter, REG_MODE_CFG(port), v); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci if (speed == SPEED_1000) 48262306a36Sopenharmony_ci v = 0x82; 48362306a36Sopenharmony_ci else if (speed == SPEED_100) 48462306a36Sopenharmony_ci v = 0x84; 48562306a36Sopenharmony_ci else /* SPEED_10 */ 48662306a36Sopenharmony_ci v = 0x86; 48762306a36Sopenharmony_ci vsc_write(mac->adapter, REG_DEV_SETUP(port), v | 1); /* reset */ 48862306a36Sopenharmony_ci vsc_write(mac->adapter, REG_DEV_SETUP(port), v); 48962306a36Sopenharmony_ci vsc_read(mac->adapter, REG_DBG(port), &v); 49062306a36Sopenharmony_ci v &= ~0xff00; 49162306a36Sopenharmony_ci if (speed == SPEED_1000) 49262306a36Sopenharmony_ci v |= 0x400; 49362306a36Sopenharmony_ci else if (speed == SPEED_100) 49462306a36Sopenharmony_ci v |= 0x2000; 49562306a36Sopenharmony_ci else /* SPEED_10 */ 49662306a36Sopenharmony_ci v |= 0xff00; 49762306a36Sopenharmony_ci vsc_write(mac->adapter, REG_DBG(port), v); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci vsc_write(mac->adapter, REG_TX_IFG(port), 50062306a36Sopenharmony_ci speed == SPEED_1000 ? 5 : 0x11); 50162306a36Sopenharmony_ci if (duplex == DUPLEX_HALF) 50262306a36Sopenharmony_ci enable = 0x0; /* 100 or 10 */ 50362306a36Sopenharmony_ci else if (speed == SPEED_1000) 50462306a36Sopenharmony_ci enable = 0xc; 50562306a36Sopenharmony_ci else /* SPEED_100 or 10 */ 50662306a36Sopenharmony_ci enable = 0x4; 50762306a36Sopenharmony_ci enable |= 0x9 << 10; /* IFG1 */ 50862306a36Sopenharmony_ci enable |= 0x6 << 6; /* IFG2 */ 50962306a36Sopenharmony_ci enable |= 0x1 << 4; /* VLAN */ 51062306a36Sopenharmony_ci enable |= 0x3; /* RX/TX EN */ 51162306a36Sopenharmony_ci vsc_write(mac->adapter, REG_MODE_CFG(port), enable); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci vsc_read(mac->adapter, REG_PAUSE_CFG(port), &v); 51662306a36Sopenharmony_ci v &= 0xfff0ffff; 51762306a36Sopenharmony_ci v |= 0x20000; /* xon/xoff */ 51862306a36Sopenharmony_ci if (fc & PAUSE_RX) 51962306a36Sopenharmony_ci v |= 0x40000; 52062306a36Sopenharmony_ci if (fc & PAUSE_TX) 52162306a36Sopenharmony_ci v |= 0x80000; 52262306a36Sopenharmony_ci if (fc == (PAUSE_RX | PAUSE_TX)) 52362306a36Sopenharmony_ci v |= 0x10000; 52462306a36Sopenharmony_ci vsc_write(mac->adapter, REG_PAUSE_CFG(port), v); 52562306a36Sopenharmony_ci return 0; 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cistatic int mac_enable(struct cmac *mac, int which) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci u32 val; 53162306a36Sopenharmony_ci int port = mac->instance->index; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci /* Write the correct WM value when the port is enabled. */ 53462306a36Sopenharmony_ci vsc_write(mac->adapter, REG_HIGH_LOW_WM(1,port), WM_ENABLE); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci vsc_read(mac->adapter, REG_MODE_CFG(port), &val); 53762306a36Sopenharmony_ci if (which & MAC_DIRECTION_RX) 53862306a36Sopenharmony_ci val |= 0x2; 53962306a36Sopenharmony_ci if (which & MAC_DIRECTION_TX) 54062306a36Sopenharmony_ci val |= 1; 54162306a36Sopenharmony_ci vsc_write(mac->adapter, REG_MODE_CFG(port), val); 54262306a36Sopenharmony_ci return 0; 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_cistatic int mac_disable(struct cmac *mac, int which) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci u32 val; 54862306a36Sopenharmony_ci int i, port = mac->instance->index; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci /* Reset the port, this also writes the correct WM value */ 55162306a36Sopenharmony_ci mac_reset(mac); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci vsc_read(mac->adapter, REG_MODE_CFG(port), &val); 55462306a36Sopenharmony_ci if (which & MAC_DIRECTION_RX) 55562306a36Sopenharmony_ci val &= ~0x2; 55662306a36Sopenharmony_ci if (which & MAC_DIRECTION_TX) 55762306a36Sopenharmony_ci val &= ~0x1; 55862306a36Sopenharmony_ci vsc_write(mac->adapter, REG_MODE_CFG(port), val); 55962306a36Sopenharmony_ci vsc_read(mac->adapter, REG_MODE_CFG(port), &val); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci /* Clear stats */ 56262306a36Sopenharmony_ci for (i = 0; i <= 0x3a; ++i) 56362306a36Sopenharmony_ci vsc_write(mac->adapter, CRA(4, port, i), 0); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci /* Clear software counters */ 56662306a36Sopenharmony_ci memset(&mac->stats, 0, sizeof(struct cmac_statistics)); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci return 0; 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cistatic void rmon_update(struct cmac *mac, unsigned int addr, u64 *stat) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci u32 v, lo; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci vsc_read(mac->adapter, addr, &v); 57662306a36Sopenharmony_ci lo = *stat; 57762306a36Sopenharmony_ci *stat = *stat - lo + v; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci if (v == 0) 58062306a36Sopenharmony_ci return; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (v < lo) 58362306a36Sopenharmony_ci *stat += (1ULL << 32); 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_cistatic void port_stats_update(struct cmac *mac) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci struct { 58962306a36Sopenharmony_ci unsigned int reg; 59062306a36Sopenharmony_ci unsigned int offset; 59162306a36Sopenharmony_ci } hw_stats[] = { 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci#define HW_STAT(reg, stat_name) \ 59462306a36Sopenharmony_ci { reg, offsetof(struct cmac_statistics, stat_name) / sizeof(u64) } 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci /* Rx stats */ 59762306a36Sopenharmony_ci HW_STAT(RxUnicast, RxUnicastFramesOK), 59862306a36Sopenharmony_ci HW_STAT(RxMulticast, RxMulticastFramesOK), 59962306a36Sopenharmony_ci HW_STAT(RxBroadcast, RxBroadcastFramesOK), 60062306a36Sopenharmony_ci HW_STAT(Crc, RxFCSErrors), 60162306a36Sopenharmony_ci HW_STAT(RxAlignment, RxAlignErrors), 60262306a36Sopenharmony_ci HW_STAT(RxOversize, RxFrameTooLongErrors), 60362306a36Sopenharmony_ci HW_STAT(RxPause, RxPauseFrames), 60462306a36Sopenharmony_ci HW_STAT(RxJabbers, RxJabberErrors), 60562306a36Sopenharmony_ci HW_STAT(RxFragments, RxRuntErrors), 60662306a36Sopenharmony_ci HW_STAT(RxUndersize, RxRuntErrors), 60762306a36Sopenharmony_ci HW_STAT(RxSymbolCarrier, RxSymbolErrors), 60862306a36Sopenharmony_ci HW_STAT(RxSize1519ToMax, RxJumboFramesOK), 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci /* Tx stats (skip collision stats as we are full-duplex only) */ 61162306a36Sopenharmony_ci HW_STAT(TxUnicast, TxUnicastFramesOK), 61262306a36Sopenharmony_ci HW_STAT(TxMulticast, TxMulticastFramesOK), 61362306a36Sopenharmony_ci HW_STAT(TxBroadcast, TxBroadcastFramesOK), 61462306a36Sopenharmony_ci HW_STAT(TxPause, TxPauseFrames), 61562306a36Sopenharmony_ci HW_STAT(TxUnderrun, TxUnderrun), 61662306a36Sopenharmony_ci HW_STAT(TxSize1519ToMax, TxJumboFramesOK), 61762306a36Sopenharmony_ci }, *p = hw_stats; 61862306a36Sopenharmony_ci unsigned int port = mac->instance->index; 61962306a36Sopenharmony_ci u64 *stats = (u64 *)&mac->stats; 62062306a36Sopenharmony_ci unsigned int i; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hw_stats); i++) 62362306a36Sopenharmony_ci rmon_update(mac, CRA(0x4, port, p->reg), stats + p->offset); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci rmon_update(mac, REG_TX_OK_BYTES(port), &mac->stats.TxOctetsOK); 62662306a36Sopenharmony_ci rmon_update(mac, REG_RX_OK_BYTES(port), &mac->stats.RxOctetsOK); 62762306a36Sopenharmony_ci rmon_update(mac, REG_RX_BAD_BYTES(port), &mac->stats.RxOctetsBad); 62862306a36Sopenharmony_ci} 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci/* 63162306a36Sopenharmony_ci * This function is called periodically to accumulate the current values of the 63262306a36Sopenharmony_ci * RMON counters into the port statistics. Since the counters are only 32 bits 63362306a36Sopenharmony_ci * some of them can overflow in less than a minute at GigE speeds, so this 63462306a36Sopenharmony_ci * function should be called every 30 seconds or so. 63562306a36Sopenharmony_ci * 63662306a36Sopenharmony_ci * To cut down on reading costs we update only the octet counters at each tick 63762306a36Sopenharmony_ci * and do a full update at major ticks, which can be every 30 minutes or more. 63862306a36Sopenharmony_ci */ 63962306a36Sopenharmony_cistatic const struct cmac_statistics *mac_update_statistics(struct cmac *mac, 64062306a36Sopenharmony_ci int flag) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci if (flag == MAC_STATS_UPDATE_FULL || 64362306a36Sopenharmony_ci mac->instance->ticks >= MAJOR_UPDATE_TICKS) { 64462306a36Sopenharmony_ci port_stats_update(mac); 64562306a36Sopenharmony_ci mac->instance->ticks = 0; 64662306a36Sopenharmony_ci } else { 64762306a36Sopenharmony_ci int port = mac->instance->index; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci rmon_update(mac, REG_RX_OK_BYTES(port), 65062306a36Sopenharmony_ci &mac->stats.RxOctetsOK); 65162306a36Sopenharmony_ci rmon_update(mac, REG_RX_BAD_BYTES(port), 65262306a36Sopenharmony_ci &mac->stats.RxOctetsBad); 65362306a36Sopenharmony_ci rmon_update(mac, REG_TX_OK_BYTES(port), 65462306a36Sopenharmony_ci &mac->stats.TxOctetsOK); 65562306a36Sopenharmony_ci mac->instance->ticks++; 65662306a36Sopenharmony_ci } 65762306a36Sopenharmony_ci return &mac->stats; 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cistatic void mac_destroy(struct cmac *mac) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci kfree(mac); 66362306a36Sopenharmony_ci} 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_cistatic const struct cmac_ops vsc7326_ops = { 66662306a36Sopenharmony_ci .destroy = mac_destroy, 66762306a36Sopenharmony_ci .reset = mac_reset, 66862306a36Sopenharmony_ci .interrupt_handler = mac_intr_handler, 66962306a36Sopenharmony_ci .interrupt_enable = mac_intr_enable, 67062306a36Sopenharmony_ci .interrupt_disable = mac_intr_disable, 67162306a36Sopenharmony_ci .interrupt_clear = mac_intr_clear, 67262306a36Sopenharmony_ci .enable = mac_enable, 67362306a36Sopenharmony_ci .disable = mac_disable, 67462306a36Sopenharmony_ci .set_mtu = mac_set_mtu, 67562306a36Sopenharmony_ci .set_rx_mode = mac_set_rx_mode, 67662306a36Sopenharmony_ci .set_speed_duplex_fc = mac_set_speed_duplex_fc, 67762306a36Sopenharmony_ci .statistics_update = mac_update_statistics, 67862306a36Sopenharmony_ci .macaddress_get = mac_get_address, 67962306a36Sopenharmony_ci .macaddress_set = mac_set_address, 68062306a36Sopenharmony_ci}; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic struct cmac *vsc7326_mac_create(adapter_t *adapter, int index) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci struct cmac *mac; 68562306a36Sopenharmony_ci u32 val; 68662306a36Sopenharmony_ci int i; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL); 68962306a36Sopenharmony_ci if (!mac) 69062306a36Sopenharmony_ci return NULL; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci mac->ops = &vsc7326_ops; 69362306a36Sopenharmony_ci mac->instance = (cmac_instance *)(mac + 1); 69462306a36Sopenharmony_ci mac->adapter = adapter; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci mac->instance->index = index; 69762306a36Sopenharmony_ci mac->instance->ticks = 0; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci i = 0; 70062306a36Sopenharmony_ci do { 70162306a36Sopenharmony_ci u32 vhi, vlo; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci vhi = vlo = 0; 70462306a36Sopenharmony_ci t1_tpi_read(adapter, (REG_LOCAL_STATUS << 2) + 4, &vlo); 70562306a36Sopenharmony_ci udelay(1); 70662306a36Sopenharmony_ci t1_tpi_read(adapter, REG_LOCAL_STATUS << 2, &vhi); 70762306a36Sopenharmony_ci udelay(5); 70862306a36Sopenharmony_ci val = (vhi << 16) | vlo; 70962306a36Sopenharmony_ci } while ((++i < 10000) && (val == 0xffffffff)); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci return mac; 71262306a36Sopenharmony_ci} 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_cistatic int vsc7326_mac_reset(adapter_t *adapter) 71562306a36Sopenharmony_ci{ 71662306a36Sopenharmony_ci vsc7326_full_reset(adapter); 71762306a36Sopenharmony_ci (void) run_bist_all(adapter); 71862306a36Sopenharmony_ci run_table(adapter, vsc7326_reset, ARRAY_SIZE(vsc7326_reset)); 71962306a36Sopenharmony_ci return 0; 72062306a36Sopenharmony_ci} 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ciconst struct gmac t1_vsc7326_ops = { 72362306a36Sopenharmony_ci .stats_update_period = STATS_TICK_SECS, 72462306a36Sopenharmony_ci .create = vsc7326_mac_create, 72562306a36Sopenharmony_ci .reset = vsc7326_mac_reset, 72662306a36Sopenharmony_ci}; 727