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 56static void 57mii_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 73static void 74mii_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 */ 95static int 96wb_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 170fail: 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 */ 185static int 186wb_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 225int 226wb_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 240void 241wb_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 260static void 261wb_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 297static void 298wb_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". */ 322static void 323wb_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 351void 352wb_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