BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / drivers / network / sis900 / interface.c
blob28776bd6ac5fed076b78bd2bacb2feda65ccbcfb
1 /* MII, MDIO and EEPROM interface of SiS 900
3 * Copyright 2001-2005 pinc Software. All Rights Reserved.
4 * Distributed under the terms of the MIT license.
5 */
8 #include <OS.h>
9 #include <KernelExport.h>
10 #include <SupportDefs.h>
11 #include <PCI.h>
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <malloc.h>
18 #include "ether_driver.h"
19 #include "driver.h"
20 #include "device.h"
21 #include "interface.h"
22 #include "sis900.h"
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)
32 uint16
33 eeprom_read(struct sis_info *info, int address)
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;
40 EEPROM_WRITE32(0);
41 EEPROM_DELAY();
42 EEPROM_WRITE32(SiS900_EEPROM_CLOCK);
43 EEPROM_DELAY();
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;
50 EEPROM_WRITE32(value);
51 EEPROM_DELAY();
52 EEPROM_WRITE32(value | SiS900_EEPROM_CLOCK);
53 EEPROM_DELAY();
56 EEPROM_WRITE8(SiS900_EEPROM_SELECT);
57 EEPROM_DELAY();
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();
69 EEPROM_WRITE32(0);
70 EEPROM_DELAY();
71 EEPROM_WRITE32(SiS900_EEPROM_CLOCK);
73 return returnValue;
77 /**************************** MII/MDIO ****************************/
78 // #pragma mark -
81 static inline uint32
82 mdio_delay(addr_t address)
84 return read32(address);
88 static void
89 mdio_idle(uint32 address)
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);
97 static void
98 mdio_reset(uint32 address)
100 int32 i;
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);
111 void
112 mdio_writeToPHY(struct sis_info *info, uint16 phy, uint16 reg, uint16 value)
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;
118 mdio_reset(address);
119 mdio_idle(address);
121 // issue the command
122 for (i = 16; i-- > 0;) {
123 int32 data = SiS900_MII_MDDIR | (cmd & (1 << i) ? SiS900_MII_MDIO : 0);
125 write8(address, data);
126 mdio_delay(address);
127 write8(address, data | SiS900_MII_MDC);
128 mdio_delay(address);
130 mdio_delay(address);
132 // write the value
133 for (i = 16; i-- > 0;) {
134 int32 data = SiS900_MII_MDDIR | (value & (1 << i) ? SiS900_MII_MDIO : 0);
136 write32(address, data);
137 mdio_delay(address);
138 write32(address, data | SiS900_MII_MDC);
139 mdio_delay(address);
141 mdio_delay(address);
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);
151 write32(address, 0);
155 uint16
156 mdio_readFromPHY(struct sis_info *info, uint16 phy, uint16 reg)
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;
163 mdio_reset(address);
164 mdio_idle(address);
166 for (i = 16; i-- > 0;) {
167 int32 data = SiS900_MII_MDDIR | (cmd & (1 << i) ? SiS900_MII_MDIO : 0);
169 write32(address, data);
170 mdio_delay(address);
171 write32(address, data | SiS900_MII_MDC);
172 mdio_delay(address);
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);
183 write32(address, 0);
185 return value;
189 uint16
190 mdio_read(struct sis_info *info, uint16 reg)
192 return mdio_readFromPHY(info, info->phy, reg);
196 void
197 mdio_write(struct sis_info *info, uint16 reg, uint16 value)
199 mdio_writeToPHY(info,info->phy,reg,value);
203 uint16
204 mdio_statusFromPHY(struct sis_info *info, uint16 phy)
206 uint16 status;
207 int i = 0;
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);
214 return status;
218 uint16
219 mdio_status(struct sis_info *info)
221 return mdio_statusFromPHY(info, info->phy);