1 /* 2 * Copyright (c) 2003-2004 Stefano Ceccherini (burton666@libero.it) 3 * Copyright (c) 1997, 1998 4 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Bill Paul. 17 * 4. Neither the name of the author nor the names of any co-contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31 * THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 */ 34 35 #include "wb840.h" 36 #include "device.h" 37 #include "interface.h" 38 39 #include <ByteOrder.h> 40 #include <KernelExport.h> 41 42 #include <string.h> 43 44 45 #define SIO_SET(x) \ 46 write32(device->reg_base + WB_SIO, \ 47 read32(device->reg_base + WB_SIO) | x) 48 49 #define SIO_CLR(x) \ 50 write32(device->reg_base + WB_SIO, \ 51 read32(device->reg_base + WB_SIO) & ~x) 52 53 #define MII_DELAY(x) read32(x->reg_base + WB_SIO) 54 55 56 static void 57 mii_sync(struct wb_device *device) 58 { 59 // Set data bit and strobe the clock 32 times 60 int bits = 32; 61 62 SIO_SET(WB_SIO_MII_DIR|WB_SIO_MII_DATAIN); 63 64 while (--bits >= 0) { 65 SIO_SET(WB_SIO_MII_CLK); 66 MII_DELAY(device); 67 SIO_CLR(WB_SIO_MII_CLK); 68 MII_DELAY(device); 69 } 70 } 71 72 73 static void 74 mii_send(wb_device *device, uint32 bits, int count) 75 { 76 int i; 77 78 SIO_CLR(WB_SIO_MII_CLK); 79 80 for (i = (0x1 << (count - 1)); i; i >>= 1) { 81 if (bits & i) 82 SIO_SET(WB_SIO_MII_DATAIN); 83 else 84 SIO_CLR(WB_SIO_MII_DATAIN); 85 MII_DELAY(device); 86 SIO_CLR(WB_SIO_MII_CLK); 87 MII_DELAY(device); 88 SIO_SET(WB_SIO_MII_CLK); 89 } 90 } 91 92 /* 93 * Read an PHY register through the MII. 94 */ 95 static int 96 wb_mii_readreg(wb_device *device, wb_mii_frame *frame) 97 { 98 int i, ack; 99 100 /* 101 * Set up frame for RX. 102 */ 103 frame->mii_stdelim = WB_MII_STARTDELIM; 104 frame->mii_opcode = WB_MII_READOP; 105 frame->mii_turnaround = 0; 106 frame->mii_data = 0; 107 108 write32(device->reg_base + WB_SIO, 0); 109 110 /* 111 * Turn on data xmit. 112 */ 113 SIO_SET(WB_SIO_MII_DIR); 114 115 mii_sync(device); 116 117 /* 118 * Send command/address info. 119 */ 120 mii_send(device, frame->mii_stdelim, 2); 121 mii_send(device, frame->mii_opcode, 2); 122 mii_send(device, frame->mii_phyaddr, 5); 123 mii_send(device, frame->mii_regaddr, 5); 124 125 /* Idle bit */ 126 SIO_CLR((WB_SIO_MII_CLK|WB_SIO_MII_DATAIN)); 127 MII_DELAY(device); 128 SIO_SET(WB_SIO_MII_CLK); 129 MII_DELAY(device); 130 131 /* Turn off xmit. */ 132 SIO_CLR(WB_SIO_MII_DIR); 133 /* Check for ack */ 134 SIO_CLR(WB_SIO_MII_CLK); 135 MII_DELAY(device); 136 ack = read32(device->reg_base + WB_SIO) & WB_SIO_MII_DATAOUT; 137 SIO_SET(WB_SIO_MII_CLK); 138 MII_DELAY(device); 139 SIO_CLR(WB_SIO_MII_CLK); 140 MII_DELAY(device); 141 SIO_SET(WB_SIO_MII_CLK); 142 MII_DELAY(device); 143 144 /* 145 * Now try reading data bits. If the ack failed, we still 146 * need to clock through 16 cycles to keep the PHY(s) in sync. 147 */ 148 if (ack) { 149 for(i = 0; i < 16; i++) { 150 SIO_CLR(WB_SIO_MII_CLK); 151 MII_DELAY(device); 152 SIO_SET(WB_SIO_MII_CLK); 153 MII_DELAY(device); 154 } 155 goto fail; 156 } 157 158 for (i = 0x8000; i; i >>= 1) { 159 SIO_CLR(WB_SIO_MII_CLK); 160 MII_DELAY(device); 161 if (!ack) { 162 if (read32(device->reg_base + WB_SIO) & WB_SIO_MII_DATAOUT) 163 frame->mii_data |= i; 164 MII_DELAY(device); 165 } 166 SIO_SET(WB_SIO_MII_CLK); 167 MII_DELAY(device); 168 } 169 170 fail: 171 172 SIO_CLR(WB_SIO_MII_CLK); 173 MII_DELAY(device); 174 SIO_SET(WB_SIO_MII_CLK); 175 MII_DELAY(device); 176 177 if (ack) 178 return 1; 179 return 0; 180 } 181 182 /* 183 * Write to a PHY register through the MII. 184 */ 185 static int 186 wb_mii_writereg(wb_device *device, wb_mii_frame *frame) 187 { 188 /* 189 * Set up frame for TX. 190 */ 191 192 frame->mii_stdelim = WB_MII_STARTDELIM; 193 frame->mii_opcode = WB_MII_WRITEOP; 194 frame->mii_turnaround = WB_MII_TURNAROUND; 195 196 /* 197 * Turn on data output. 198 */ 199 SIO_SET(WB_SIO_MII_DIR); 200 201 mii_sync(device); 202 203 mii_send(device, frame->mii_stdelim, 2); 204 mii_send(device, frame->mii_opcode, 2); 205 mii_send(device, frame->mii_phyaddr, 5); 206 mii_send(device, frame->mii_regaddr, 5); 207 mii_send(device, frame->mii_turnaround, 2); 208 mii_send(device, frame->mii_data, 16); 209 210 /* Idle bit. */ 211 SIO_SET(WB_SIO_MII_CLK); 212 MII_DELAY(device); 213 SIO_CLR(WB_SIO_MII_CLK); 214 MII_DELAY(device); 215 216 /* 217 * Turn off xmit. 218 */ 219 SIO_CLR(WB_SIO_MII_DIR); 220 221 return 0; 222 } 223 224 225 int 226 wb_miibus_readreg(wb_device *device, int phy, int reg) 227 { 228 struct wb_mii_frame frame; 229 230 memset(&frame, 0, sizeof(frame)); 231 232 frame.mii_phyaddr = phy; 233 frame.mii_regaddr = reg; 234 wb_mii_readreg(device, &frame); 235 236 return frame.mii_data; 237 } 238 239 240 void 241 wb_miibus_writereg(wb_device *device, int phy, int reg, int data) 242 { 243 struct wb_mii_frame frame; 244 245 memset(&frame, 0, sizeof(frame)); 246 247 frame.mii_phyaddr = phy; 248 frame.mii_regaddr = reg; 249 frame.mii_data = data; 250 251 wb_mii_writereg(device, &frame); 252 253 return; 254 } 255 256 257 #define EEPROM_DELAY(x) read32(x->reg_base + WB_SIO) 258 259 #if 0 260 static void 261 wb_eeprom_putbyte(wb_device *device, int addr) 262 { 263 int d, i; 264 int delay; 265 266 d = addr | WB_EECMD_READ; 267 268 /* 269 * Feed in each bit and strobe the clock. 270 */ 271 for (i = 0x400; i; i >>= 1) { 272 if (d & i) { 273 SIO_SET(WB_SIO_EE_DATAIN); 274 } else { 275 SIO_CLR(WB_SIO_EE_DATAIN); 276 } 277 for (delay = 0; delay < 100; delay++) 278 MII_DELAY(device); 279 280 SIO_SET(WB_SIO_EE_CLK); 281 282 for (delay = 0; delay < 150; delay++) 283 MII_DELAY(device); 284 285 SIO_CLR(WB_SIO_EE_CLK); 286 287 for (delay = 0; delay < 100; delay++) 288 MII_DELAY(device); 289 290 } 291 292 return; 293 } 294 #endif 295 296 297 static void 298 wb_eeprom_askdata(wb_device *device, int addr) 299 { 300 int command, i; 301 int delay; 302 303 command = addr | WB_EECMD_READ; 304 305 /* Feed in each bit and strobe the clock. */ 306 for(i = 0x400; i; i >>= 1) { 307 if (command & i) 308 SIO_SET(WB_SIO_EE_DATAIN); 309 else 310 SIO_CLR(WB_SIO_EE_DATAIN); 311 312 SIO_SET(WB_SIO_EE_CLK); 313 314 SIO_CLR(WB_SIO_EE_CLK); 315 for (delay = 0; delay < 100; delay++) 316 EEPROM_DELAY(device); 317 } 318 } 319 320 321 /* Read a word of data stored in the EEPROM at address "addr". */ 322 static void 323 wb_eeprom_getword(wb_device *device, int addr, uint16 *dest) 324 { 325 int i; 326 uint16 word = 0; 327 328 /* Enter EEPROM access mode */ 329 write32(device->reg_base + WB_SIO, WB_SIO_EESEL|WB_SIO_EE_CS); 330 331 /* Send address of word we want to read. */ 332 wb_eeprom_askdata(device, addr); 333 334 write32(device->reg_base + WB_SIO, WB_SIO_EESEL|WB_SIO_EE_CS); 335 336 /* Start reading bits from EEPROM */ 337 for (i = 0x8000; i > 0; i >>= 1) { 338 SIO_SET(WB_SIO_EE_CLK); 339 if (read32(device->reg_base + WB_SIO) & WB_SIO_EE_DATAOUT) 340 word |= i; 341 SIO_CLR(WB_SIO_EE_CLK); 342 } 343 344 /* Turn off EEPROM access mode */ 345 write32(device->reg_base + WB_SIO, 0); 346 347 *dest = word; 348 } 349 350 351 void 352 wb_read_eeprom(wb_device *device, void* dest, 353 int offset, int count, bool swap) 354 { 355 int i; 356 uint16 word = 0, *ptr; 357 358 for (i = 0; i < count; i++) { 359 wb_eeprom_getword(device, offset + i, &word); 360 ptr = (uint16 *)((uint8 *)dest + (i * 2)); 361 if (swap) 362 *ptr = B_BENDIAN_TO_HOST_INT16(word); 363 else 364 *ptr = word; 365 } 366 } 367