| 1 | /* |
| 2 | * (C) Copyright 2010 |
| 3 | * Michael Kurz <michi.kurz@googlemail.com>. |
| 4 | * |
| 5 | * See file CREDITS for list of people who contributed to this |
| 6 | * project. |
| 7 | * |
| 8 | * This program is free software; you can redistribute it and/or |
| 9 | * modify it under the terms of the GNU General Public License as |
| 10 | * published by the Free Software Foundation; either version 2 of |
| 11 | * the License, or (at your option) any later version. |
| 12 | * |
| 13 | * This program is distributed in the hope that it will be useful, |
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | * GNU General Public License for more details. |
| 17 | * |
| 18 | * You should have received a copy of the GNU General Public License |
| 19 | * along with this program; if not, write to the Free Software |
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
| 21 | * MA 02111-1307 USA |
| 22 | */ |
| 23 | |
| 24 | |
| 25 | #include <common.h> |
| 26 | #include <net.h> |
| 27 | #include <netdev.h> |
| 28 | #include <miiphy.h> |
| 29 | #include MII_GPIOINCLUDE |
| 30 | |
| 31 | #include "rtl8366.h" |
| 32 | |
| 33 | #ifdef DEBUG_RTL8366 |
| 34 | #define DBG(fmt,args...) printf (fmt ,##args) |
| 35 | #else |
| 36 | #define DBG(fmt,args...) |
| 37 | #endif |
| 38 | |
| 39 | |
| 40 | //------------------------------------------------------------------- |
| 41 | // Soft SMI functions |
| 42 | //------------------------------------------------------------------- |
| 43 | |
| 44 | #define DELAY 2 |
| 45 | |
| 46 | static void smi_init(void) |
| 47 | { |
| 48 | MII_SDAINPUT; |
| 49 | MII_SCKINPUT; |
| 50 | |
| 51 | MII_SETSDA(1); |
| 52 | MII_SETSCK(1); |
| 53 | |
| 54 | udelay(20); |
| 55 | } |
| 56 | |
| 57 | static void smi_start(void) |
| 58 | { |
| 59 | /* |
| 60 | * rtl8366 chip needs a extra clock with |
| 61 | * SDA high before start condition |
| 62 | */ |
| 63 | |
| 64 | /* set gpio pins output */ |
| 65 | MII_SDAOUTPUT; |
| 66 | MII_SCKOUTPUT; |
| 67 | udelay(DELAY); |
| 68 | |
| 69 | /* set initial state: SCK:0, SDA:1 */ |
| 70 | MII_SETSCK(0); |
| 71 | MII_SETSDA(1); |
| 72 | udelay(DELAY); |
| 73 | |
| 74 | /* toggle clock */ |
| 75 | MII_SETSCK(1); |
| 76 | udelay(DELAY); |
| 77 | MII_SETSCK(0); |
| 78 | udelay(DELAY); |
| 79 | |
| 80 | /* start condition */ |
| 81 | MII_SETSCK(1); |
| 82 | udelay(DELAY); |
| 83 | MII_SETSDA(0); |
| 84 | udelay(DELAY); |
| 85 | MII_SETSCK(0); |
| 86 | udelay(DELAY); |
| 87 | MII_SETSDA(1); |
| 88 | } |
| 89 | |
| 90 | static void smi_stop(void) |
| 91 | { |
| 92 | /* |
| 93 | * rtl8366 chip needs a extra clock with |
| 94 | * SDA high after stop condition |
| 95 | */ |
| 96 | |
| 97 | /* stop condition */ |
| 98 | udelay(DELAY); |
| 99 | MII_SETSDA(0); |
| 100 | MII_SETSCK(1); |
| 101 | udelay(DELAY); |
| 102 | MII_SETSDA(1); |
| 103 | udelay(DELAY); |
| 104 | MII_SETSCK(1); |
| 105 | udelay(DELAY); |
| 106 | MII_SETSCK(0); |
| 107 | udelay(DELAY); |
| 108 | |
| 109 | /* toggle clock */ |
| 110 | MII_SETSCK(1); |
| 111 | udelay(DELAY); |
| 112 | MII_SETSCK(0); |
| 113 | udelay(DELAY); |
| 114 | MII_SETSCK(1); |
| 115 | |
| 116 | /* set gpio pins input */ |
| 117 | MII_SDAINPUT; |
| 118 | MII_SCKINPUT; |
| 119 | } |
| 120 | |
| 121 | static void smi_writeBits(uint32_t data, uint8_t length) |
| 122 | { |
| 123 | uint8_t test; |
| 124 | |
| 125 | for( ; length > 0; length--) { |
| 126 | udelay(DELAY); |
| 127 | |
| 128 | /* output data */ |
| 129 | test = (((data & (1 << (length - 1))) != 0) ? 1 : 0); |
| 130 | MII_SETSDA(test); |
| 131 | udelay(DELAY); |
| 132 | |
| 133 | /* toogle clock */ |
| 134 | MII_SETSCK(1); |
| 135 | udelay(DELAY); |
| 136 | MII_SETSCK(0); |
| 137 | } |
| 138 | } |
| 139 | |
| 140 | static uint32_t smi_readBits(uint8_t length) |
| 141 | { |
| 142 | uint32_t ret; |
| 143 | |
| 144 | MII_SDAINPUT; |
| 145 | |
| 146 | for(ret = 0 ; length > 0; length--) { |
| 147 | udelay(DELAY); |
| 148 | |
| 149 | ret <<= 1; |
| 150 | |
| 151 | /* toogle clock */ |
| 152 | MII_SETSCK(1); |
| 153 | udelay(DELAY); |
| 154 | ret |= MII_GETSDA; |
| 155 | MII_SETSCK(0); |
| 156 | } |
| 157 | |
| 158 | MII_SDAOUTPUT; |
| 159 | |
| 160 | return ret; |
| 161 | } |
| 162 | |
| 163 | static int smi_waitAck(void) |
| 164 | { |
| 165 | uint32_t retry = 0; |
| 166 | |
| 167 | while (smi_readBits(1)) { |
| 168 | if (retry++ == 5) |
| 169 | return -1; |
| 170 | } |
| 171 | |
| 172 | return 0; |
| 173 | |
| 174 | } |
| 175 | |
| 176 | static int smi_read(uint32_t reg, uint32_t *data) |
| 177 | { |
| 178 | uint32_t rawData; |
| 179 | |
| 180 | /* send start condition */ |
| 181 | smi_start(); |
| 182 | /* send CTRL1 code: 0b1010*/ |
| 183 | smi_writeBits(0x0a, 4); |
| 184 | /* send CTRL2 code: 0b100 */ |
| 185 | smi_writeBits(0x04, 3); |
| 186 | /* send READ command */ |
| 187 | smi_writeBits(0x01, 1); |
| 188 | |
| 189 | /* wait for ACK */ |
| 190 | if (smi_waitAck()) |
| 191 | return -1; |
| 192 | |
| 193 | /* send address low */ |
| 194 | smi_writeBits(reg & 0xFF, 8); |
| 195 | /* wait for ACK */ |
| 196 | if (smi_waitAck()) |
| 197 | return -1; |
| 198 | /* send address high */ |
| 199 | smi_writeBits((reg & 0xFF00) >> 8, 8); |
| 200 | /* wait for ACK */ |
| 201 | if (smi_waitAck()) |
| 202 | return -1; |
| 203 | |
| 204 | /* read data low */ |
| 205 | rawData = (smi_readBits(8) & 0xFF); |
| 206 | /* send ACK */ |
| 207 | smi_writeBits(0, 1); |
| 208 | /* read data high */ |
| 209 | rawData |= (smi_readBits(8) & 0xFF) << 8; |
| 210 | /* send NACK */ |
| 211 | smi_writeBits(1, 1); |
| 212 | |
| 213 | /* send stop condition */ |
| 214 | smi_stop(); |
| 215 | |
| 216 | if (data) |
| 217 | *data = rawData; |
| 218 | |
| 219 | return 0; |
| 220 | } |
| 221 | |
| 222 | static int smi_write(uint32_t reg, uint32_t data) |
| 223 | { |
| 224 | /* send start condition */ |
| 225 | smi_start(); |
| 226 | /* send CTRL1 code: 0b1010*/ |
| 227 | smi_writeBits(0x0a, 4); |
| 228 | /* send CTRL2 code: 0b100 */ |
| 229 | smi_writeBits(0x04, 3); |
| 230 | /* send WRITE command */ |
| 231 | smi_writeBits(0x00, 1); |
| 232 | |
| 233 | /* wait for ACK */ |
| 234 | if (smi_waitAck()) |
| 235 | return -1; |
| 236 | |
| 237 | /* send address low */ |
| 238 | smi_writeBits(reg & 0xFF, 8); |
| 239 | /* wait for ACK */ |
| 240 | if (smi_waitAck()) |
| 241 | return -1; |
| 242 | /* send address high */ |
| 243 | smi_writeBits((reg & 0xFF00) >> 8, 8); |
| 244 | /* wait for ACK */ |
| 245 | if (smi_waitAck()) |
| 246 | return -1; |
| 247 | |
| 248 | /* send data low */ |
| 249 | smi_writeBits(data & 0xFF, 8); |
| 250 | /* wait for ACK */ |
| 251 | if (smi_waitAck()) |
| 252 | return -1; |
| 253 | /* send data high */ |
| 254 | smi_writeBits((data & 0xFF00) >> 8, 8); |
| 255 | /* wait for ACK */ |
| 256 | if (smi_waitAck()) |
| 257 | return -1; |
| 258 | |
| 259 | /* send stop condition */ |
| 260 | smi_stop(); |
| 261 | |
| 262 | return 0; |
| 263 | } |
| 264 | |
| 265 | |
| 266 | //------------------------------------------------------------------- |
| 267 | // Switch register read / write functions |
| 268 | //------------------------------------------------------------------- |
| 269 | static int rtl8366_readRegister(uint32_t reg, uint16_t *data) |
| 270 | { |
| 271 | uint32_t regData; |
| 272 | |
| 273 | DBG("rtl8366: read register=%#04x, data=", reg); |
| 274 | |
| 275 | if (smi_read(reg, ®Data)) { |
| 276 | printf("\nrtl8366 smi read failed!\n"); |
| 277 | return -1; |
| 278 | } |
| 279 | |
| 280 | if (data) |
| 281 | *data = regData; |
| 282 | |
| 283 | DBG("%#04x\n", regData); |
| 284 | |
| 285 | return 0; |
| 286 | } |
| 287 | |
| 288 | static int rtl8366_writeRegister(uint32_t reg, uint16_t data) |
| 289 | { |
| 290 | DBG("rtl8366: write register=%#04x, data=%#04x\n", reg, data); |
| 291 | |
| 292 | if (smi_write(reg, data)) { |
| 293 | printf("rtl8366 smi write failed!\n"); |
| 294 | return -1; |
| 295 | } |
| 296 | |
| 297 | return 0; |
| 298 | } |
| 299 | |
| 300 | static int rtl8366_setRegisterBit(uint32_t reg, uint32_t bitNum, uint32_t value) |
| 301 | { |
| 302 | uint16_t regData; |
| 303 | |
| 304 | if (bitNum >= 16) |
| 305 | return -1; |
| 306 | |
| 307 | if (rtl8366_readRegister(reg, ®Data)) |
| 308 | return -1; |
| 309 | |
| 310 | if (value) |
| 311 | regData |= (1 << bitNum); |
| 312 | else |
| 313 | regData &= ~(1 << bitNum); |
| 314 | |
| 315 | if (rtl8366_writeRegister(reg, regData)) |
| 316 | return -1; |
| 317 | |
| 318 | return 0; |
| 319 | } |
| 320 | |
| 321 | //------------------------------------------------------------------- |
| 322 | // MII PHY read / write functions |
| 323 | //------------------------------------------------------------------- |
| 324 | static int rtl8366_getPhyReg(uint32_t phyNum, uint32_t reg, uint16_t *data) |
| 325 | { |
| 326 | uint16_t phyAddr, regData; |
| 327 | |
| 328 | if (phyNum > RTL8366S_PHY_NO_MAX) { |
| 329 | printf("rtl8366s: invalid phy number!\n"); |
| 330 | return -1; |
| 331 | } |
| 332 | |
| 333 | if (phyNum > RTL8366S_PHY_ADDR_MAX) { |
| 334 | printf("rtl8366s: invalid phy register number!\n"); |
| 335 | return -1; |
| 336 | } |
| 337 | |
| 338 | if (rtl8366_writeRegister(RTL8366S_PHY_ACCESS_CTRL_REG, |
| 339 | RTL8366S_PHY_CTRL_READ)) |
| 340 | return -1; |
| 341 | |
| 342 | phyAddr = 0x8000 | (1 << (phyNum + RTL8366S_PHY_NO_OFFSET)) |
| 343 | | (reg & RTL8366S_PHY_REG_MASK); |
| 344 | if (rtl8366_writeRegister(phyAddr, 0)) |
| 345 | return -1; |
| 346 | |
| 347 | if (rtl8366_readRegister(RTL8366S_PHY_ACCESS_DATA_REG, ®Data)) |
| 348 | return -1; |
| 349 | |
| 350 | if (data) |
| 351 | *data = regData; |
| 352 | |
| 353 | return 0; |
| 354 | } |
| 355 | |
| 356 | static int rtl8366_setPhyReg(uint32_t phyNum, uint32_t reg, uint16_t data) |
| 357 | { |
| 358 | uint16_t phyAddr; |
| 359 | |
| 360 | if (phyNum > RTL8366S_PHY_NO_MAX) { |
| 361 | printf("rtl8366s: invalid phy number!\n"); |
| 362 | return -1; |
| 363 | } |
| 364 | |
| 365 | if (phyNum > RTL8366S_PHY_ADDR_MAX) { |
| 366 | printf("rtl8366s: invalid phy register number!\n"); |
| 367 | return -1; |
| 368 | } |
| 369 | |
| 370 | if (rtl8366_writeRegister(RTL8366S_PHY_ACCESS_CTRL_REG, |
| 371 | RTL8366S_PHY_CTRL_WRITE)) |
| 372 | return -1; |
| 373 | |
| 374 | phyAddr = 0x8000 | (1 << (phyNum + RTL8366S_PHY_NO_OFFSET)) |
| 375 | | (reg & RTL8366S_PHY_REG_MASK); |
| 376 | if (rtl8366_writeRegister(phyAddr, data)) |
| 377 | return -1; |
| 378 | |
| 379 | return 0; |
| 380 | } |
| 381 | |
| 382 | static int rtl8366_miiread(char *devname, uchar phy_adr, uchar reg, ushort *data) |
| 383 | { |
| 384 | uint16_t regData; |
| 385 | |
| 386 | DBG("rtl8366_miiread: devname=%s, addr=%#02x, reg=%#02x\n", |
| 387 | devname, phy_adr, reg); |
| 388 | |
| 389 | if (strcmp(devname, RTL8366_DEVNAME) != 0) |
| 390 | return -1; |
| 391 | |
| 392 | if (rtl8366_getPhyReg(phy_adr, reg, ®Data)) { |
| 393 | printf("rtl8366_miiread: write failed!\n"); |
| 394 | return -1; |
| 395 | } |
| 396 | |
| 397 | if (data) |
| 398 | *data = regData; |
| 399 | |
| 400 | return 0; |
| 401 | } |
| 402 | |
| 403 | static int rtl8366_miiwrite(char *devname, uchar phy_adr, uchar reg, ushort data) |
| 404 | { |
| 405 | DBG("rtl8366_miiwrite: devname=%s, addr=%#02x, reg=%#02x, data=%#04x\n", |
| 406 | devname, phy_adr, reg, data); |
| 407 | |
| 408 | if (strcmp(devname, RTL8366_DEVNAME) != 0) |
| 409 | return -1; |
| 410 | |
| 411 | if (rtl8366_setPhyReg(phy_adr, reg, data)) { |
| 412 | printf("rtl8366_miiwrite: write failed!\n"); |
| 413 | return -1; |
| 414 | } |
| 415 | |
| 416 | return 0; |
| 417 | } |
| 418 | |
| 419 | int rtl8366_mii_register(bd_t *bis) |
| 420 | { |
| 421 | miiphy_register(strdup(RTL8366_DEVNAME), rtl8366_miiread, |
| 422 | rtl8366_miiwrite); |
| 423 | |
| 424 | return 0; |
| 425 | } |
| 426 | |
| 427 | |
| 428 | //------------------------------------------------------------------- |
| 429 | // Switch management functions |
| 430 | //------------------------------------------------------------------- |
| 431 | |
| 432 | int rtl8366s_setGreenFeature(uint32_t tx, uint32_t rx) |
| 433 | { |
| 434 | if (rtl8366_setRegisterBit(RTL8366S_GREEN_FEATURE_REG, |
| 435 | RTL8366S_GREEN_FEATURE_TX_BIT, tx)) |
| 436 | return -1; |
| 437 | |
| 438 | if (rtl8366_setRegisterBit(RTL8366S_GREEN_FEATURE_REG, |
| 439 | RTL8366S_GREEN_FEATURE_RX_BIT, rx)) |
| 440 | return -1; |
| 441 | |
| 442 | return 0; |
| 443 | } |
| 444 | |
| 445 | int rtl8366s_setPowerSaving(uint32_t phyNum, uint32_t enabled) |
| 446 | { |
| 447 | uint16_t regData; |
| 448 | |
| 449 | if (phyNum > RTL8366S_PHY_NO_MAX) |
| 450 | return -1; |
| 451 | |
| 452 | if (rtl8366_getPhyReg(phyNum, 12, ®Data)) |
| 453 | return -1; |
| 454 | |
| 455 | if (enabled) |
| 456 | regData |= (1 << 12); |
| 457 | else |
| 458 | regData &= ~(1 << 12); |
| 459 | |
| 460 | if (rtl8366_setPhyReg(phyNum, 12, regData)) |
| 461 | return -1; |
| 462 | |
| 463 | return 0; |
| 464 | } |
| 465 | |
| 466 | int rtl8366s_setGreenEthernet(uint32_t greenFeature, uint32_t powerSaving) |
| 467 | { |
| 468 | uint32_t phyNum, i; |
| 469 | uint16_t regData; |
| 470 | |
| 471 | const uint16_t greenSettings[][2] = |
| 472 | { |
| 473 | {0xBE5B,0x3500}, |
| 474 | {0xBE5C,0xB975}, |
| 475 | {0xBE5D,0xB9B9}, |
| 476 | {0xBE77,0xA500}, |
| 477 | {0xBE78,0x5A78}, |
| 478 | {0xBE79,0x6478} |
| 479 | }; |
| 480 | |
| 481 | if (rtl8366_readRegister(RTL8366S_MODEL_ID_REG, ®Data)) |
| 482 | return -1; |
| 483 | |
| 484 | switch (regData) |
| 485 | { |
| 486 | case 0x0000: |
| 487 | for (i = 0; i < 6; i++) { |
| 488 | if (rtl8366_writeRegister(RTL8366S_PHY_ACCESS_CTRL_REG, RTL8366S_PHY_CTRL_WRITE)) |
| 489 | return -1; |
| 490 | if (rtl8366_writeRegister(greenSettings[i][0], greenSettings[i][1])) |
| 491 | return -1; |
| 492 | } |
| 493 | break; |
| 494 | |
| 495 | case RTL8366S_MODEL_8366SR: |
| 496 | if (rtl8366_writeRegister(RTL8366S_PHY_ACCESS_CTRL_REG, RTL8366S_PHY_CTRL_WRITE)) |
| 497 | return -1; |
| 498 | if (rtl8366_writeRegister(greenSettings[0][0], greenSettings[0][1])) |
| 499 | return -1; |
| 500 | break; |
| 501 | |
| 502 | default: |
| 503 | printf("rtl8366s_initChip: unsupported chip found!\n"); |
| 504 | return -1; |
| 505 | } |
| 506 | |
| 507 | if (rtl8366s_setGreenFeature(greenFeature, powerSaving)) |
| 508 | return -1; |
| 509 | |
| 510 | for (phyNum = 0; phyNum <= RTL8366S_PHY_NO_MAX; phyNum++) { |
| 511 | if (rtl8366s_setPowerSaving(phyNum, powerSaving)) |
| 512 | return -1; |
| 513 | } |
| 514 | |
| 515 | return 0; |
| 516 | } |
| 517 | |
| 518 | int rtl8366s_setCPUPortMask(uint8_t port, uint32_t enabled) |
| 519 | { |
| 520 | if(port >= 6){ |
| 521 | printf("rtl8366s_setCPUPortMask: invalid port number\n"); |
| 522 | return -1; |
| 523 | } |
| 524 | |
| 525 | return rtl8366_setRegisterBit(RTL8366S_CPU_CTRL_REG, port, enabled); |
| 526 | } |
| 527 | |
| 528 | int rtl8366s_setCPUDisableInsTag(uint32_t enable) |
| 529 | { |
| 530 | return rtl8366_setRegisterBit(RTL8366S_CPU_CTRL_REG, |
| 531 | RTL8366S_CPU_INSTAG_BIT, enable); |
| 532 | } |
| 533 | |
| 534 | int rtl8366s_setCPUDropUnda(uint32_t enable) |
| 535 | { |
| 536 | return rtl8366_setRegisterBit(RTL8366S_CPU_CTRL_REG, |
| 537 | RTL8366S_CPU_DRP_BIT, enable); |
| 538 | } |
| 539 | |
| 540 | int rtl8366s_setCPUPort(uint8_t port, uint32_t noTag, uint32_t dropUnda) |
| 541 | { |
| 542 | uint32_t i; |
| 543 | |
| 544 | if(port >= 6){ |
| 545 | printf("rtl8366s_setCPUPort: invalid port number\n"); |
| 546 | return -1; |
| 547 | } |
| 548 | |
| 549 | /* reset register */ |
| 550 | for(i = 0; i < 6; i++) |
| 551 | { |
| 552 | if(rtl8366s_setCPUPortMask(i, 0)){ |
| 553 | printf("rtl8366s_setCPUPort: rtl8366s_setCPUPortMask failed\n"); |
| 554 | return -1; |
| 555 | } |
| 556 | } |
| 557 | |
| 558 | if(rtl8366s_setCPUPortMask(port, 1)){ |
| 559 | printf("rtl8366s_setCPUPort: rtl8366s_setCPUPortMask failed\n"); |
| 560 | return -1; |
| 561 | } |
| 562 | |
| 563 | if(rtl8366s_setCPUDisableInsTag(noTag)){ |
| 564 | printf("rtl8366s_setCPUPort: rtl8366s_setCPUDisableInsTag fail\n"); |
| 565 | return -1; |
| 566 | } |
| 567 | |
| 568 | if(rtl8366s_setCPUDropUnda(dropUnda)){ |
| 569 | printf("rtl8366s_setCPUPort: rtl8366s_setCPUDropUnda fail\n"); |
| 570 | return -1; |
| 571 | } |
| 572 | |
| 573 | return 0; |
| 574 | } |
| 575 | |
| 576 | int rtl8366s_setLedConfig(uint32_t ledNum, uint8_t config) |
| 577 | { |
| 578 | uint16_t regData; |
| 579 | |
| 580 | if(ledNum >= RTL8366S_LED_GROUP_MAX) { |
| 581 | DBG("rtl8366s_setLedConfig: invalid led group\n"); |
| 582 | return -1; |
| 583 | } |
| 584 | |
| 585 | if(config > RTL8366S_LEDCONF_LEDFORCE) { |
| 586 | DBG("rtl8366s_setLedConfig: invalid led config\n"); |
| 587 | return -1; |
| 588 | } |
| 589 | |
| 590 | if (rtl8366_readRegister(RTL8366S_LED_INDICATED_CONF_REG, ®Data)) { |
| 591 | printf("rtl8366s_setLedConfig: failed to get led register!\n"); |
| 592 | return -1; |
| 593 | } |
| 594 | |
| 595 | regData &= ~(0xF << (ledNum * 4)); |
| 596 | regData |= config << (ledNum * 4); |
| 597 | |
| 598 | if (rtl8366_writeRegister(RTL8366S_LED_INDICATED_CONF_REG, regData)) { |
| 599 | printf("rtl8366s_setLedConfig: failed to set led register!\n"); |
| 600 | return -1; |
| 601 | } |
| 602 | |
| 603 | return 0; |
| 604 | } |
| 605 | |
| 606 | int rtl8366s_getLedConfig(uint32_t ledNum, uint8_t *config) |
| 607 | { |
| 608 | uint16_t regData; |
| 609 | |
| 610 | if(ledNum >= RTL8366S_LED_GROUP_MAX) { |
| 611 | DBG("rtl8366s_getLedConfig: invalid led group\n"); |
| 612 | return -1; |
| 613 | } |
| 614 | |
| 615 | if (rtl8366_readRegister(RTL8366S_LED_INDICATED_CONF_REG, ®Data)) { |
| 616 | printf("rtl8366s_getLedConfig: failed to get led register!\n"); |
| 617 | return -1; |
| 618 | } |
| 619 | |
| 620 | if (config) |
| 621 | *config = (regData >> (ledNum * 4)) & 0xF; |
| 622 | |
| 623 | return 0; |
| 624 | } |
| 625 | |
| 626 | int rtl8366s_setLedForceValue(uint32_t group0, uint32_t group1, |
| 627 | uint32_t group2, uint32_t group3) |
| 628 | { |
| 629 | uint16_t regData; |
| 630 | |
| 631 | regData = (group0 & 0x3F) | ((group1 & 0x3F) << 6); |
| 632 | if (rtl8366_writeRegister(RTL8366S_LED_0_1_FORCE_REG, regData)) { |
| 633 | printf("rtl8366s_setLedForceValue: failed to set led register!\n"); |
| 634 | return -1; |
| 635 | } |
| 636 | |
| 637 | regData = (group2 & 0x3F) | ((group3 & 0x3F) << 6); |
| 638 | if (rtl8366_writeRegister(RTL8366S_LED_2_3_FORCE_REG, regData)) { |
| 639 | printf("rtl8366s_setLedForceValue: failed to set led register!\n"); |
| 640 | return -1; |
| 641 | } |
| 642 | |
| 643 | return 0; |
| 644 | } |
| 645 | |
| 646 | int rtl8366s_initChip(void) |
| 647 | { |
| 648 | uint32_t ledGroup, i = 0; |
| 649 | uint16_t regData; |
| 650 | uint8_t ledData[RTL8366S_LED_GROUP_MAX]; |
| 651 | const uint16_t (*chipData)[2]; |
| 652 | |
| 653 | const uint16_t chipB[][2] = |
| 654 | { |
| 655 | {0x0000, 0x0038},{0x8100, 0x1B37},{0xBE2E, 0x7B9F},{0xBE2B, 0xA4C8}, |
| 656 | {0xBE74, 0xAD14},{0xBE2C, 0xDC00},{0xBE69, 0xD20F},{0xBE3B, 0xB414}, |
| 657 | {0xBE24, 0x0000},{0xBE23, 0x00A1},{0xBE22, 0x0008},{0xBE21, 0x0120}, |
| 658 | {0xBE20, 0x1000},{0xBE24, 0x0800},{0xBE24, 0x0000},{0xBE24, 0xF000}, |
| 659 | {0xBE23, 0xDF01},{0xBE22, 0xDF20},{0xBE21, 0x101A},{0xBE20, 0xA0FF}, |
| 660 | {0xBE24, 0xF800},{0xBE24, 0xF000},{0x0242, 0x02BF},{0x0245, 0x02BF}, |
| 661 | {0x0248, 0x02BF},{0x024B, 0x02BF},{0x024E, 0x02BF},{0x0251, 0x02BF}, |
| 662 | {0x0230, 0x0A32},{0x0233, 0x0A32},{0x0236, 0x0A32},{0x0239, 0x0A32}, |
| 663 | {0x023C, 0x0A32},{0x023F, 0x0A32},{0x0254, 0x0A3F},{0x0255, 0x0064}, |
| 664 | {0x0256, 0x0A3F},{0x0257, 0x0064},{0x0258, 0x0A3F},{0x0259, 0x0064}, |
| 665 | {0x025A, 0x0A3F},{0x025B, 0x0064},{0x025C, 0x0A3F},{0x025D, 0x0064}, |
| 666 | {0x025E, 0x0A3F},{0x025F, 0x0064},{0x0260, 0x0178},{0x0261, 0x01F4}, |
| 667 | {0x0262, 0x0320},{0x0263, 0x0014},{0x021D, 0x9249},{0x021E, 0x0000}, |
| 668 | {0x0100, 0x0004},{0xBE4A, 0xA0B4},{0xBE40, 0x9C00},{0xBE41, 0x501D}, |
| 669 | {0xBE48, 0x3602},{0xBE47, 0x8051},{0xBE4C, 0x6465},{0x8000, 0x1F00}, |
| 670 | {0x8001, 0x000C},{0x8008, 0x0000},{0x8007, 0x0000},{0x800C, 0x00A5}, |
| 671 | {0x8101, 0x02BC},{0xBE53, 0x0005},{0x8E45, 0xAFE8},{0x8013, 0x0005}, |
| 672 | {0xBE4B, 0x6700},{0x800B, 0x7000},{0xBE09, 0x0E00}, |
| 673 | {0xFFFF, 0xABCD} |
| 674 | }; |
| 675 | |
| 676 | const uint16_t chipDefault[][2] = |
| 677 | { |
| 678 | {0x0242, 0x02BF},{0x0245, 0x02BF},{0x0248, 0x02BF},{0x024B, 0x02BF}, |
| 679 | {0x024E, 0x02BF},{0x0251, 0x02BF}, |
| 680 | {0x0254, 0x0A3F},{0x0256, 0x0A3F},{0x0258, 0x0A3F},{0x025A, 0x0A3F}, |
| 681 | {0x025C, 0x0A3F},{0x025E, 0x0A3F}, |
| 682 | {0x0263, 0x007C},{0x0100, 0x0004}, |
| 683 | {0xBE5B, 0x3500},{0x800E, 0x200F},{0xBE1D, 0x0F00},{0x8001, 0x5011}, |
| 684 | {0x800A, 0xA2F4},{0x800B, 0x17A3},{0xBE4B, 0x17A3},{0xBE41, 0x5011}, |
| 685 | {0xBE17, 0x2100},{0x8000, 0x8304},{0xBE40, 0x8304},{0xBE4A, 0xA2F4}, |
| 686 | {0x800C, 0xA8D5},{0x8014, 0x5500},{0x8015, 0x0004},{0xBE4C, 0xA8D5}, |
| 687 | {0xBE59, 0x0008},{0xBE09, 0x0E00},{0xBE36, 0x1036},{0xBE37, 0x1036}, |
| 688 | {0x800D, 0x00FF},{0xBE4D, 0x00FF}, |
| 689 | {0xFFFF, 0xABCD} |
| 690 | }; |
| 691 | |
| 692 | DBG("rtl8366s_initChip\n"); |
| 693 | |
| 694 | /* save current led config and set to led force */ |
| 695 | for (ledGroup = 0; ledGroup < RTL8366S_LED_GROUP_MAX; ledGroup++) { |
| 696 | if (rtl8366s_getLedConfig(ledGroup, &ledData[ledGroup])) |
| 697 | return -1; |
| 698 | |
| 699 | if (rtl8366s_setLedConfig(ledGroup, RTL8366S_LEDCONF_LEDFORCE)) |
| 700 | return -1; |
| 701 | } |
| 702 | |
| 703 | if (rtl8366s_setLedForceValue(0,0,0,0)) |
| 704 | return -1; |
| 705 | |
| 706 | if (rtl8366_readRegister(RTL8366S_MODEL_ID_REG, ®Data)) |
| 707 | return -1; |
| 708 | |
| 709 | switch (regData) |
| 710 | { |
| 711 | case 0x0000: |
| 712 | chipData = chipB; |
| 713 | break; |
| 714 | |
| 715 | case RTL8366S_MODEL_8366SR: |
| 716 | chipData = chipDefault; |
| 717 | break; |
| 718 | |
| 719 | default: |
| 720 | printf("rtl8366s_initChip: unsupported chip found!\n"); |
| 721 | return -1; |
| 722 | } |
| 723 | |
| 724 | DBG("rtl8366s_initChip: found %x chip\n", regData); |
| 725 | |
| 726 | while ((chipData[i][0] != 0xFFFF) && (chipData[i][1] != 0xABCD)) { |
| 727 | |
| 728 | /* phy settings*/ |
| 729 | if ((chipData[i][0] & 0xBE00) == 0xBE00) { |
| 730 | if (rtl8366_writeRegister(RTL8366S_PHY_ACCESS_CTRL_REG, |
| 731 | RTL8366S_PHY_CTRL_WRITE)) |
| 732 | return -1; |
| 733 | } |
| 734 | |
| 735 | if (rtl8366_writeRegister(chipData[i][0], chipData[i][1])) |
| 736 | return -1; |
| 737 | |
| 738 | i++; |
| 739 | } |
| 740 | |
| 741 | /* chip needs some time */ |
| 742 | udelay(100 * 1000); |
| 743 | |
| 744 | /* restore led config */ |
| 745 | for (ledGroup = 0; ledGroup < RTL8366S_LED_GROUP_MAX; ledGroup++) { |
| 746 | if (rtl8366s_setLedConfig(ledGroup, ledData[ledGroup])) |
| 747 | return -1; |
| 748 | } |
| 749 | |
| 750 | return 0; |
| 751 | } |
| 752 | |
| 753 | int rtl8366s_initialize(void) |
| 754 | { |
| 755 | uint16_t regData; |
| 756 | |
| 757 | DBG("rtl8366s_initialize: start setup\n"); |
| 758 | |
| 759 | smi_init(); |
| 760 | |
| 761 | rtl8366_readRegister(RTL8366S_CHIP_ID_REG, ®Data); |
| 762 | DBG("Realtek 8366SR switch ID %#04x\n", regData); |
| 763 | |
| 764 | if (regData != 0x8366) { |
| 765 | printf("rtl8366s_initialize: found unsupported switch\n"); |
| 766 | return -1; |
| 767 | } |
| 768 | |
| 769 | if (rtl8366s_initChip()) { |
| 770 | printf("rtl8366s_initialize: init chip failed\n"); |
| 771 | return -1; |
| 772 | } |
| 773 | |
| 774 | if (rtl8366s_setGreenEthernet(1, 1)) { |
| 775 | printf("rtl8366s_initialize: set green ethernet failed\n"); |
| 776 | return -1; |
| 777 | } |
| 778 | |
| 779 | /* Set port 5 noTag and don't dropUnda */ |
| 780 | if (rtl8366s_setCPUPort(5, 1, 0)) { |
| 781 | printf("rtl8366s_initialize: set CPU port failed\n"); |
| 782 | return -1; |
| 783 | } |
| 784 | |
| 785 | return 0; |
| 786 | } |
| 787 | |