1/* MII, MDIO and EEPROM interface of SiS 900 2 * 3 * Copyright 2001-2005 pinc Software. All Rights Reserved. 4 * Distributed under the terms of the MIT license. 5 */ 6 7 8#include <OS.h> 9#include <KernelExport.h> 10#include <SupportDefs.h> 11#include <PCI.h> 12 13#include <stdlib.h> 14#include <stdio.h> 15#include <string.h> 16#include <malloc.h> 17 18#include "ether_driver.h" 19#include "driver.h" 20#include "device.h" 21#include "interface.h" 22#include "sis900.h" 23 24 25// EEPROM access definitions 26#define EEPROM_DELAY() read32(eepromAccess) 27#define EEPROM_READ32() read32(eepromAccess) 28#define EEPROM_WRITE8(value) write8(eepromAccess,value) 29#define EEPROM_WRITE32(value) write32(eepromAccess,value) 30 31 32uint16 33eeprom_read(struct sis_info *info, int address) 34{ 35 long eepromAccess = (long)info->registers + SiS900_MAC_EEPROM_ACCESS; 36 uint32 readCmd = SiS900_EEPROM_CMD_READ | address; 37 uint16 returnValue = 0; 38 int i; 39 40 EEPROM_WRITE32(0); 41 EEPROM_DELAY(); 42 EEPROM_WRITE32(SiS900_EEPROM_CLOCK); 43 EEPROM_DELAY(); 44 45 // Shift the read command (9) bits out. 46 for (i = 8; i >= 0; i--) { 47 uint32 value = (readCmd & (1 << i)) ? SiS900_EEPROM_DATA_IN | SiS900_EEPROM_SELECT 48 : SiS900_EEPROM_SELECT; 49 50 EEPROM_WRITE32(value); 51 EEPROM_DELAY(); 52 EEPROM_WRITE32(value | SiS900_EEPROM_CLOCK); 53 EEPROM_DELAY(); 54 } 55 56 EEPROM_WRITE8(SiS900_EEPROM_SELECT); 57 EEPROM_DELAY(); 58 59 // read in the 16 bit data 60 for (i = 16; i > 0; i--) { 61 EEPROM_WRITE32(SiS900_EEPROM_SELECT); 62 EEPROM_DELAY(); 63 EEPROM_WRITE32(SiS900_EEPROM_SELECT | SiS900_EEPROM_CLOCK); 64 EEPROM_DELAY(); 65 returnValue = (returnValue << 1) | ((EEPROM_READ32() & SiS900_EEPROM_DATA_OUT) ? 1 : 0); 66 EEPROM_DELAY(); 67 } 68 69 EEPROM_WRITE32(0); 70 EEPROM_DELAY(); 71 EEPROM_WRITE32(SiS900_EEPROM_CLOCK); 72 73 return returnValue; 74} 75 76 77/**************************** MII/MDIO ****************************/ 78// #pragma mark - 79 80 81static inline uint32 82mdio_delay(addr_t address) 83{ 84 return read32(address); 85} 86 87 88static void 89mdio_idle(uint32 address) 90{ 91 write32(address, SiS900_MII_MDIO | SiS900_MII_MDDIR); 92 mdio_delay(address); 93 write32(address, SiS900_MII_MDIO | SiS900_MII_MDDIR | SiS900_MII_MDC); 94} 95 96 97static void 98mdio_reset(uint32 address) 99{ 100 int32 i; 101 102 for (i = 32; i-- > 0;) { 103 write32(address, SiS900_MII_MDIO | SiS900_MII_MDDIR); 104 mdio_delay(address); 105 write32(address, SiS900_MII_MDIO | SiS900_MII_MDDIR | SiS900_MII_MDC); 106 mdio_delay(address); 107 } 108} 109 110 111void 112mdio_writeToPHY(struct sis_info *info, uint16 phy, uint16 reg, uint16 value) 113{ 114 uint32 address = info->registers + SiS900_MAC_EEPROM_ACCESS; 115 int32 cmd = MII_CMD_WRITE | (phy << MII_PHY_SHIFT) | (reg << MII_REG_SHIFT); 116 int i; 117 118 mdio_reset(address); 119 mdio_idle(address); 120 121 // issue the command 122 for (i = 16; i-- > 0;) { 123 int32 data = SiS900_MII_MDDIR | (cmd & (1 << i) ? SiS900_MII_MDIO : 0); 124 125 write8(address, data); 126 mdio_delay(address); 127 write8(address, data | SiS900_MII_MDC); 128 mdio_delay(address); 129 } 130 mdio_delay(address); 131 132 // write the value 133 for (i = 16; i-- > 0;) { 134 int32 data = SiS900_MII_MDDIR | (value & (1 << i) ? SiS900_MII_MDIO : 0); 135 136 write32(address, data); 137 mdio_delay(address); 138 write32(address, data | SiS900_MII_MDC); 139 mdio_delay(address); 140 } 141 mdio_delay(address); 142 143 // clear extra bits 144 for (i = 2; i-- > 0;) { 145 write8(address, 0); 146 mdio_delay(address); 147 write8(address, SiS900_MII_MDC); 148 mdio_delay(address); 149 } 150 151 write32(address, 0); 152} 153 154 155uint16 156mdio_readFromPHY(struct sis_info *info, uint16 phy, uint16 reg) 157{ 158 uint32 address = info->registers + SiS900_MAC_EEPROM_ACCESS; 159 int32 cmd = MII_CMD_READ | (phy << MII_PHY_SHIFT) | (reg << MII_REG_SHIFT); 160 uint16 value = 0; 161 int i; 162 163 mdio_reset(address); 164 mdio_idle(address); 165 166 for (i = 16; i-- > 0;) { 167 int32 data = SiS900_MII_MDDIR | (cmd & (1 << i) ? SiS900_MII_MDIO : 0); 168 169 write32(address, data); 170 mdio_delay(address); 171 write32(address, data | SiS900_MII_MDC); 172 mdio_delay(address); 173 } 174 175 // read the value 176 for (i = 16; i-- > 0;) { 177 write32(address, 0); 178 mdio_delay(address); 179 value = (value << 1) | (read32(address) & SiS900_MII_MDIO ? 1 : 0); 180 write32(address, SiS900_MII_MDC); 181 mdio_delay(address); 182 } 183 write32(address, 0); 184 185 return value; 186} 187 188 189uint16 190mdio_read(struct sis_info *info, uint16 reg) 191{ 192 return mdio_readFromPHY(info, info->phy, reg); 193} 194 195 196void 197mdio_write(struct sis_info *info, uint16 reg, uint16 value) 198{ 199 mdio_writeToPHY(info,info->phy,reg,value); 200} 201 202 203uint16 204mdio_statusFromPHY(struct sis_info *info, uint16 phy) 205{ 206 uint16 status; 207 int i = 0; 208 209 // the status must be retrieved two times, because the first 210 // one may not work on some PHYs (notably ICS 1893) 211 while (i++ < 2) 212 status = mdio_readFromPHY(info, phy, MII_STATUS); 213 214 return status; 215} 216 217 218uint16 219mdio_status(struct sis_info *info) 220{ 221 return mdio_statusFromPHY(info, info->phy); 222} 223 224