1 /* 2 * XGE PCSR module initialisation 3 * 4 * Copyright (C) 2014 Texas Instruments Incorporated 5 * Authors: Sandeep Nair <sandeep_n@ti.com> 6 * WingMan Kwok <w-kwok2@ti.com> 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 version 2. 11 * 12 * This program is distributed "as is" WITHOUT ANY WARRANTY of any 13 * kind, whether express or implied; without even the implied warranty 14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 */ 17 #include "netcp.h" 18 19 /* XGBE registers */ 20 #define XGBE_CTRL_OFFSET 0x0c 21 #define XGBE_SGMII_1_OFFSET 0x0114 22 #define XGBE_SGMII_2_OFFSET 0x0214 23 24 /* PCS-R registers */ 25 #define PCSR_CPU_CTRL_OFFSET 0x1fd0 26 #define POR_EN BIT(29) 27 28 #define reg_rmw(addr, value, mask) \ 29 writel(((readl(addr) & (~(mask))) | \ 30 (value & (mask))), (addr)) 31 32 /* bit mask of width w at offset s */ 33 #define MASK_WID_SH(w, s) (((1 << w) - 1) << s) 34 35 /* shift value v to offset s */ 36 #define VAL_SH(v, s) (v << s) 37 38 #define PHY_A(serdes) 0 39 40 struct serdes_cfg { 41 u32 ofs; 42 u32 val; 43 u32 mask; 44 }; 45 46 static struct serdes_cfg cfg_phyb_1p25g_156p25mhz_cmu0[] = { 47 {0x0000, 0x00800002, 0x00ff00ff}, 48 {0x0014, 0x00003838, 0x0000ffff}, 49 {0x0060, 0x1c44e438, 0xffffffff}, 50 {0x0064, 0x00c18400, 0x00ffffff}, 51 {0x0068, 0x17078200, 0xffffff00}, 52 {0x006c, 0x00000014, 0x000000ff}, 53 {0x0078, 0x0000c000, 0x0000ff00}, 54 {0x0000, 0x00000003, 0x000000ff}, 55 }; 56 57 static struct serdes_cfg cfg_phyb_10p3125g_156p25mhz_cmu1[] = { 58 {0x0c00, 0x00030002, 0x00ff00ff}, 59 {0x0c14, 0x00005252, 0x0000ffff}, 60 {0x0c28, 0x80000000, 0xff000000}, 61 {0x0c2c, 0x000000f6, 0x000000ff}, 62 {0x0c3c, 0x04000405, 0xff00ffff}, 63 {0x0c40, 0xc0800000, 0xffff0000}, 64 {0x0c44, 0x5a202062, 0xffffffff}, 65 {0x0c48, 0x40040424, 0xffffffff}, 66 {0x0c4c, 0x00004002, 0x0000ffff}, 67 {0x0c50, 0x19001c00, 0xff00ff00}, 68 {0x0c54, 0x00002100, 0x0000ff00}, 69 {0x0c58, 0x00000060, 0x000000ff}, 70 {0x0c60, 0x80131e7c, 0xffffffff}, 71 {0x0c64, 0x8400cb02, 0xff00ffff}, 72 {0x0c68, 0x17078200, 0xffffff00}, 73 {0x0c6c, 0x00000016, 0x000000ff}, 74 {0x0c74, 0x00000400, 0x0000ff00}, 75 {0x0c78, 0x0000c000, 0x0000ff00}, 76 {0x0c00, 0x00000003, 0x000000ff}, 77 }; 78 79 static struct serdes_cfg cfg_phyb_10p3125g_16bit_lane[] = { 80 {0x0204, 0x00000080, 0x000000ff}, 81 {0x0208, 0x0000920d, 0x0000ffff}, 82 {0x0204, 0xfc000000, 0xff000000}, 83 {0x0208, 0x00009104, 0x0000ffff}, 84 {0x0210, 0x1a000000, 0xff000000}, 85 {0x0214, 0x00006b58, 0x00ffffff}, 86 {0x0218, 0x75800084, 0xffff00ff}, 87 {0x022c, 0x00300000, 0x00ff0000}, 88 {0x0230, 0x00003800, 0x0000ff00}, 89 {0x024c, 0x008f0000, 0x00ff0000}, 90 {0x0250, 0x30000000, 0xff000000}, 91 {0x0260, 0x00000002, 0x000000ff}, 92 {0x0264, 0x00000057, 0x000000ff}, 93 {0x0268, 0x00575700, 0x00ffff00}, 94 {0x0278, 0xff000000, 0xff000000}, 95 {0x0280, 0x00500050, 0x00ff00ff}, 96 {0x0284, 0x00001f15, 0x0000ffff}, 97 {0x028c, 0x00006f00, 0x0000ff00}, 98 {0x0294, 0x00000000, 0xffffff00}, 99 {0x0298, 0x00002640, 0xff00ffff}, 100 {0x029c, 0x00000003, 0x000000ff}, 101 {0x02a4, 0x00000f13, 0x0000ffff}, 102 {0x02a8, 0x0001b600, 0x00ffff00}, 103 {0x0380, 0x00000030, 0x000000ff}, 104 {0x03c0, 0x00000200, 0x0000ff00}, 105 {0x03cc, 0x00000018, 0x000000ff}, 106 {0x03cc, 0x00000000, 0x000000ff}, 107 }; 108 109 static struct serdes_cfg cfg_phyb_10p3125g_comlane[] = { 110 {0x0a00, 0x00000800, 0x0000ff00}, 111 {0x0a84, 0x00000000, 0x000000ff}, 112 {0x0a8c, 0x00130000, 0x00ff0000}, 113 {0x0a90, 0x77a00000, 0xffff0000}, 114 {0x0a94, 0x00007777, 0x0000ffff}, 115 {0x0b08, 0x000f0000, 0xffff0000}, 116 {0x0b0c, 0x000f0000, 0x00ffffff}, 117 {0x0b10, 0xbe000000, 0xff000000}, 118 {0x0b14, 0x000000ff, 0x000000ff}, 119 {0x0b18, 0x00000014, 0x000000ff}, 120 {0x0b5c, 0x981b0000, 0xffff0000}, 121 {0x0b64, 0x00001100, 0x0000ff00}, 122 {0x0b78, 0x00000c00, 0x0000ff00}, 123 {0x0abc, 0xff000000, 0xff000000}, 124 {0x0ac0, 0x0000008b, 0x000000ff}, 125 }; 126 127 static struct serdes_cfg cfg_cm_c1_c2[] = { 128 {0x0208, 0x00000000, 0x00000f00}, 129 {0x0208, 0x00000000, 0x0000001f}, 130 {0x0204, 0x00000000, 0x00040000}, 131 {0x0208, 0x000000a0, 0x000000e0}, 132 }; 133 134 static void netcp_xgbe_serdes_cmu_init(void __iomem *serdes_regs) 135 { 136 int i; 137 138 /* cmu0 setup */ 139 for (i = 0; i < ARRAY_SIZE(cfg_phyb_1p25g_156p25mhz_cmu0); i++) { 140 reg_rmw(serdes_regs + cfg_phyb_1p25g_156p25mhz_cmu0[i].ofs, 141 cfg_phyb_1p25g_156p25mhz_cmu0[i].val, 142 cfg_phyb_1p25g_156p25mhz_cmu0[i].mask); 143 } 144 145 /* cmu1 setup */ 146 for (i = 0; i < ARRAY_SIZE(cfg_phyb_10p3125g_156p25mhz_cmu1); i++) { 147 reg_rmw(serdes_regs + cfg_phyb_10p3125g_156p25mhz_cmu1[i].ofs, 148 cfg_phyb_10p3125g_156p25mhz_cmu1[i].val, 149 cfg_phyb_10p3125g_156p25mhz_cmu1[i].mask); 150 } 151 } 152 153 /* lane is 0 based */ 154 static void netcp_xgbe_serdes_lane_config( 155 void __iomem *serdes_regs, int lane) 156 { 157 int i; 158 159 /* lane setup */ 160 for (i = 0; i < ARRAY_SIZE(cfg_phyb_10p3125g_16bit_lane); i++) { 161 reg_rmw(serdes_regs + 162 cfg_phyb_10p3125g_16bit_lane[i].ofs + 163 (0x200 * lane), 164 cfg_phyb_10p3125g_16bit_lane[i].val, 165 cfg_phyb_10p3125g_16bit_lane[i].mask); 166 } 167 168 /* disable auto negotiation*/ 169 reg_rmw(serdes_regs + (0x200 * lane) + 0x0380, 170 0x00000000, 0x00000010); 171 172 /* disable link training */ 173 reg_rmw(serdes_regs + (0x200 * lane) + 0x03c0, 174 0x00000000, 0x00000200); 175 } 176 177 static void netcp_xgbe_serdes_com_enable(void __iomem *serdes_regs) 178 { 179 int i; 180 181 for (i = 0; i < ARRAY_SIZE(cfg_phyb_10p3125g_comlane); i++) { 182 reg_rmw(serdes_regs + cfg_phyb_10p3125g_comlane[i].ofs, 183 cfg_phyb_10p3125g_comlane[i].val, 184 cfg_phyb_10p3125g_comlane[i].mask); 185 } 186 } 187 188 static void netcp_xgbe_serdes_lane_enable( 189 void __iomem *serdes_regs, int lane) 190 { 191 /* Set Lane Control Rate */ 192 writel(0xe0e9e038, serdes_regs + 0x1fe0 + (4 * lane)); 193 } 194 195 static void netcp_xgbe_serdes_phyb_rst_clr(void __iomem *serdes_regs) 196 { 197 reg_rmw(serdes_regs + 0x0a00, 0x0000001f, 0x000000ff); 198 } 199 200 static void netcp_xgbe_serdes_pll_disable(void __iomem *serdes_regs) 201 { 202 writel(0x88000000, serdes_regs + 0x1ff4); 203 } 204 205 static void netcp_xgbe_serdes_pll_enable(void __iomem *serdes_regs) 206 { 207 netcp_xgbe_serdes_phyb_rst_clr(serdes_regs); 208 writel(0xee000000, serdes_regs + 0x1ff4); 209 } 210 211 static int netcp_xgbe_wait_pll_locked(void __iomem *sw_regs) 212 { 213 unsigned long timeout; 214 int ret = 0; 215 u32 val_1, val_0; 216 217 timeout = jiffies + msecs_to_jiffies(500); 218 do { 219 val_0 = (readl(sw_regs + XGBE_SGMII_1_OFFSET) & BIT(4)); 220 val_1 = (readl(sw_regs + XGBE_SGMII_2_OFFSET) & BIT(4)); 221 222 if (val_1 && val_0) 223 return 0; 224 225 if (time_after(jiffies, timeout)) { 226 ret = -ETIMEDOUT; 227 break; 228 } 229 230 cpu_relax(); 231 } while (true); 232 233 pr_err("XGBE serdes not locked: time out.\n"); 234 return ret; 235 } 236 237 static void netcp_xgbe_serdes_enable_xgmii_port(void __iomem *sw_regs) 238 { 239 writel(0x03, sw_regs + XGBE_CTRL_OFFSET); 240 } 241 242 static u32 netcp_xgbe_serdes_read_tbus_val(void __iomem *serdes_regs) 243 { 244 u32 tmp; 245 246 if (PHY_A(serdes_regs)) { 247 tmp = (readl(serdes_regs + 0x0ec) >> 24) & 0x0ff; 248 tmp |= ((readl(serdes_regs + 0x0fc) >> 16) & 0x00f00); 249 } else { 250 tmp = (readl(serdes_regs + 0x0f8) >> 16) & 0x0fff; 251 } 252 253 return tmp; 254 } 255 256 static void netcp_xgbe_serdes_write_tbus_addr(void __iomem *serdes_regs, 257 int select, int ofs) 258 { 259 if (PHY_A(serdes_regs)) { 260 reg_rmw(serdes_regs + 0x0008, ((select << 5) + ofs) << 24, 261 ~0x00ffffff); 262 return; 263 } 264 265 /* For 2 lane Phy-B, lane0 is actually lane1 */ 266 switch (select) { 267 case 1: 268 select = 2; 269 break; 270 case 2: 271 select = 3; 272 break; 273 default: 274 return; 275 } 276 277 reg_rmw(serdes_regs + 0x00fc, ((select << 8) + ofs) << 16, ~0xf800ffff); 278 } 279 280 static u32 netcp_xgbe_serdes_read_select_tbus(void __iomem *serdes_regs, 281 int select, int ofs) 282 { 283 /* Set tbus address */ 284 netcp_xgbe_serdes_write_tbus_addr(serdes_regs, select, ofs); 285 /* Get TBUS Value */ 286 return netcp_xgbe_serdes_read_tbus_val(serdes_regs); 287 } 288 289 static void netcp_xgbe_serdes_reset_cdr(void __iomem *serdes_regs, 290 void __iomem *sig_detect_reg, int lane) 291 { 292 u32 tmp, dlpf, tbus; 293 294 /*Get the DLPF values */ 295 tmp = netcp_xgbe_serdes_read_select_tbus( 296 serdes_regs, lane + 1, 5); 297 298 dlpf = tmp >> 2; 299 300 if (dlpf < 400 || dlpf > 700) { 301 reg_rmw(sig_detect_reg, VAL_SH(2, 1), MASK_WID_SH(2, 1)); 302 mdelay(1); 303 reg_rmw(sig_detect_reg, VAL_SH(0, 1), MASK_WID_SH(2, 1)); 304 } else { 305 tbus = netcp_xgbe_serdes_read_select_tbus(serdes_regs, lane + 306 1, 0xe); 307 308 pr_debug("XGBE: CDR centered, DLPF: %4d,%d,%d.\n", 309 tmp >> 2, tmp & 3, (tbus >> 2) & 3); 310 } 311 } 312 313 /* Call every 100 ms */ 314 static int netcp_xgbe_check_link_status(void __iomem *serdes_regs, 315 void __iomem *sw_regs, u32 lanes, 316 u32 *current_state, u32 *lane_down) 317 { 318 void __iomem *pcsr_base = sw_regs + 0x0600; 319 void __iomem *sig_detect_reg; 320 u32 pcsr_rx_stat, blk_lock, blk_errs; 321 int loss, i, status = 1; 322 323 for (i = 0; i < lanes; i++) { 324 /* Get the Loss bit */ 325 loss = readl(serdes_regs + 0x1fc0 + 0x20 + (i * 0x04)) & 0x1; 326 327 /* Get Block Errors and Block Lock bits */ 328 pcsr_rx_stat = readl(pcsr_base + 0x0c + (i * 0x80)); 329 blk_lock = (pcsr_rx_stat >> 30) & 0x1; 330 blk_errs = (pcsr_rx_stat >> 16) & 0x0ff; 331 332 /* Get Signal Detect Overlay Address */ 333 sig_detect_reg = serdes_regs + (i * 0x200) + 0x200 + 0x04; 334 335 /* If Block errors maxed out, attempt recovery! */ 336 if (blk_errs == 0x0ff) 337 blk_lock = 0; 338 339 switch (current_state[i]) { 340 case 0: 341 /* if good link lock the signal detect ON! */ 342 if (!loss && blk_lock) { 343 pr_debug("XGBE PCSR Linked Lane: %d\n", i); 344 reg_rmw(sig_detect_reg, VAL_SH(3, 1), 345 MASK_WID_SH(2, 1)); 346 current_state[i] = 1; 347 } else if (!blk_lock) { 348 /* if no lock, then reset CDR */ 349 pr_debug("XGBE PCSR Recover Lane: %d\n", i); 350 netcp_xgbe_serdes_reset_cdr(serdes_regs, 351 sig_detect_reg, i); 352 } 353 break; 354 355 case 1: 356 if (!blk_lock) { 357 /* Link Lost? */ 358 lane_down[i] = 1; 359 current_state[i] = 2; 360 } 361 break; 362 363 case 2: 364 if (blk_lock) 365 /* Nope just noise */ 366 current_state[i] = 1; 367 else { 368 /* Lost the block lock, reset CDR if it is 369 * not centered and go back to sync state 370 */ 371 netcp_xgbe_serdes_reset_cdr(serdes_regs, 372 sig_detect_reg, i); 373 current_state[i] = 0; 374 } 375 break; 376 377 default: 378 pr_err("XGBE: unknown current_state[%d] %d\n", 379 i, current_state[i]); 380 break; 381 } 382 383 if (blk_errs > 0) { 384 /* Reset the Error counts! */ 385 reg_rmw(pcsr_base + 0x08 + (i * 0x80), VAL_SH(0x19, 0), 386 MASK_WID_SH(8, 0)); 387 388 reg_rmw(pcsr_base + 0x08 + (i * 0x80), VAL_SH(0x00, 0), 389 MASK_WID_SH(8, 0)); 390 } 391 392 status &= (current_state[i] == 1); 393 } 394 395 return status; 396 } 397 398 static int netcp_xgbe_serdes_check_lane(void __iomem *serdes_regs, 399 void __iomem *sw_regs) 400 { 401 u32 current_state[2] = {0, 0}; 402 int retries = 0, link_up; 403 u32 lane_down[2]; 404 405 do { 406 lane_down[0] = 0; 407 lane_down[1] = 0; 408 409 link_up = netcp_xgbe_check_link_status(serdes_regs, sw_regs, 2, 410 current_state, 411 lane_down); 412 413 /* if we did not get link up then wait 100ms before calling 414 * it again 415 */ 416 if (link_up) 417 break; 418 419 if (lane_down[0]) 420 pr_debug("XGBE: detected link down on lane 0\n"); 421 422 if (lane_down[1]) 423 pr_debug("XGBE: detected link down on lane 1\n"); 424 425 if (++retries > 1) { 426 pr_debug("XGBE: timeout waiting for serdes link up\n"); 427 return -ETIMEDOUT; 428 } 429 mdelay(100); 430 } while (!link_up); 431 432 pr_debug("XGBE: PCSR link is up\n"); 433 return 0; 434 } 435 436 static void netcp_xgbe_serdes_setup_cm_c1_c2(void __iomem *serdes_regs, 437 int lane, int cm, int c1, int c2) 438 { 439 int i; 440 441 for (i = 0; i < ARRAY_SIZE(cfg_cm_c1_c2); i++) { 442 reg_rmw(serdes_regs + cfg_cm_c1_c2[i].ofs + (0x200 * lane), 443 cfg_cm_c1_c2[i].val, 444 cfg_cm_c1_c2[i].mask); 445 } 446 } 447 448 static void netcp_xgbe_reset_serdes(void __iomem *serdes_regs) 449 { 450 /* Toggle the POR_EN bit in CONFIG.CPU_CTRL */ 451 /* enable POR_EN bit */ 452 reg_rmw(serdes_regs + PCSR_CPU_CTRL_OFFSET, POR_EN, POR_EN); 453 usleep_range(10, 100); 454 455 /* disable POR_EN bit */ 456 reg_rmw(serdes_regs + PCSR_CPU_CTRL_OFFSET, 0, POR_EN); 457 usleep_range(10, 100); 458 } 459 460 static int netcp_xgbe_serdes_config(void __iomem *serdes_regs, 461 void __iomem *sw_regs) 462 { 463 u32 ret, i; 464 465 netcp_xgbe_serdes_pll_disable(serdes_regs); 466 netcp_xgbe_serdes_cmu_init(serdes_regs); 467 468 for (i = 0; i < 2; i++) 469 netcp_xgbe_serdes_lane_config(serdes_regs, i); 470 471 netcp_xgbe_serdes_com_enable(serdes_regs); 472 /* This is EVM + RTM-BOC specific */ 473 for (i = 0; i < 2; i++) 474 netcp_xgbe_serdes_setup_cm_c1_c2(serdes_regs, i, 0, 0, 5); 475 476 netcp_xgbe_serdes_pll_enable(serdes_regs); 477 for (i = 0; i < 2; i++) 478 netcp_xgbe_serdes_lane_enable(serdes_regs, i); 479 480 /* SB PLL Status Poll */ 481 ret = netcp_xgbe_wait_pll_locked(sw_regs); 482 if (ret) 483 return ret; 484 485 netcp_xgbe_serdes_enable_xgmii_port(sw_regs); 486 netcp_xgbe_serdes_check_lane(serdes_regs, sw_regs); 487 return ret; 488 } 489 490 int netcp_xgbe_serdes_init(void __iomem *serdes_regs, void __iomem *xgbe_regs) 491 { 492 u32 val; 493 494 /* read COMLANE bits 4:0 */ 495 val = readl(serdes_regs + 0xa00); 496 if (val & 0x1f) { 497 pr_debug("XGBE: serdes already in operation - reset\n"); 498 netcp_xgbe_reset_serdes(serdes_regs); 499 } 500 return netcp_xgbe_serdes_config(serdes_regs, xgbe_regs); 501 } 502