Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * XGE PCSR module initialisation
0004  *
0005  * Copyright (C) 2014 Texas Instruments Incorporated
0006  * Authors: Sandeep Nair <sandeep_n@ti.com>
0007  *      WingMan Kwok <w-kwok2@ti.com>
0008  *
0009  */
0010 #include "netcp.h"
0011 
0012 /* XGBE registers */
0013 #define XGBE_CTRL_OFFSET        0x0c
0014 #define XGBE_SGMII_1_OFFSET     0x0114
0015 #define XGBE_SGMII_2_OFFSET     0x0214
0016 
0017 /* PCS-R registers */
0018 #define PCSR_CPU_CTRL_OFFSET        0x1fd0
0019 #define POR_EN              BIT(29)
0020 
0021 #define reg_rmw(addr, value, mask) \
0022     writel(((readl(addr) & (~(mask))) | \
0023             (value & (mask))), (addr))
0024 
0025 /* bit mask of width w at offset s */
0026 #define MASK_WID_SH(w, s)       (((1 << w) - 1) << s)
0027 
0028 /* shift value v to offset s */
0029 #define VAL_SH(v, s)            (v << s)
0030 
0031 #define PHY_A(serdes)           0
0032 
0033 struct serdes_cfg {
0034     u32 ofs;
0035     u32 val;
0036     u32 mask;
0037 };
0038 
0039 static struct serdes_cfg cfg_phyb_1p25g_156p25mhz_cmu0[] = {
0040     {0x0000, 0x00800002, 0x00ff00ff},
0041     {0x0014, 0x00003838, 0x0000ffff},
0042     {0x0060, 0x1c44e438, 0xffffffff},
0043     {0x0064, 0x00c18400, 0x00ffffff},
0044     {0x0068, 0x17078200, 0xffffff00},
0045     {0x006c, 0x00000014, 0x000000ff},
0046     {0x0078, 0x0000c000, 0x0000ff00},
0047     {0x0000, 0x00000003, 0x000000ff},
0048 };
0049 
0050 static struct serdes_cfg cfg_phyb_10p3125g_156p25mhz_cmu1[] = {
0051     {0x0c00, 0x00030002, 0x00ff00ff},
0052     {0x0c14, 0x00005252, 0x0000ffff},
0053     {0x0c28, 0x80000000, 0xff000000},
0054     {0x0c2c, 0x000000f6, 0x000000ff},
0055     {0x0c3c, 0x04000405, 0xff00ffff},
0056     {0x0c40, 0xc0800000, 0xffff0000},
0057     {0x0c44, 0x5a202062, 0xffffffff},
0058     {0x0c48, 0x40040424, 0xffffffff},
0059     {0x0c4c, 0x00004002, 0x0000ffff},
0060     {0x0c50, 0x19001c00, 0xff00ff00},
0061     {0x0c54, 0x00002100, 0x0000ff00},
0062     {0x0c58, 0x00000060, 0x000000ff},
0063     {0x0c60, 0x80131e7c, 0xffffffff},
0064     {0x0c64, 0x8400cb02, 0xff00ffff},
0065     {0x0c68, 0x17078200, 0xffffff00},
0066     {0x0c6c, 0x00000016, 0x000000ff},
0067     {0x0c74, 0x00000400, 0x0000ff00},
0068     {0x0c78, 0x0000c000, 0x0000ff00},
0069     {0x0c00, 0x00000003, 0x000000ff},
0070 };
0071 
0072 static struct serdes_cfg cfg_phyb_10p3125g_16bit_lane[] = {
0073     {0x0204, 0x00000080, 0x000000ff},
0074     {0x0208, 0x0000920d, 0x0000ffff},
0075     {0x0204, 0xfc000000, 0xff000000},
0076     {0x0208, 0x00009104, 0x0000ffff},
0077     {0x0210, 0x1a000000, 0xff000000},
0078     {0x0214, 0x00006b58, 0x00ffffff},
0079     {0x0218, 0x75800084, 0xffff00ff},
0080     {0x022c, 0x00300000, 0x00ff0000},
0081     {0x0230, 0x00003800, 0x0000ff00},
0082     {0x024c, 0x008f0000, 0x00ff0000},
0083     {0x0250, 0x30000000, 0xff000000},
0084     {0x0260, 0x00000002, 0x000000ff},
0085     {0x0264, 0x00000057, 0x000000ff},
0086     {0x0268, 0x00575700, 0x00ffff00},
0087     {0x0278, 0xff000000, 0xff000000},
0088     {0x0280, 0x00500050, 0x00ff00ff},
0089     {0x0284, 0x00001f15, 0x0000ffff},
0090     {0x028c, 0x00006f00, 0x0000ff00},
0091     {0x0294, 0x00000000, 0xffffff00},
0092     {0x0298, 0x00002640, 0xff00ffff},
0093     {0x029c, 0x00000003, 0x000000ff},
0094     {0x02a4, 0x00000f13, 0x0000ffff},
0095     {0x02a8, 0x0001b600, 0x00ffff00},
0096     {0x0380, 0x00000030, 0x000000ff},
0097     {0x03c0, 0x00000200, 0x0000ff00},
0098     {0x03cc, 0x00000018, 0x000000ff},
0099     {0x03cc, 0x00000000, 0x000000ff},
0100 };
0101 
0102 static struct serdes_cfg cfg_phyb_10p3125g_comlane[] = {
0103     {0x0a00, 0x00000800, 0x0000ff00},
0104     {0x0a84, 0x00000000, 0x000000ff},
0105     {0x0a8c, 0x00130000, 0x00ff0000},
0106     {0x0a90, 0x77a00000, 0xffff0000},
0107     {0x0a94, 0x00007777, 0x0000ffff},
0108     {0x0b08, 0x000f0000, 0xffff0000},
0109     {0x0b0c, 0x000f0000, 0x00ffffff},
0110     {0x0b10, 0xbe000000, 0xff000000},
0111     {0x0b14, 0x000000ff, 0x000000ff},
0112     {0x0b18, 0x00000014, 0x000000ff},
0113     {0x0b5c, 0x981b0000, 0xffff0000},
0114     {0x0b64, 0x00001100, 0x0000ff00},
0115     {0x0b78, 0x00000c00, 0x0000ff00},
0116     {0x0abc, 0xff000000, 0xff000000},
0117     {0x0ac0, 0x0000008b, 0x000000ff},
0118 };
0119 
0120 static struct serdes_cfg cfg_cm_c1_c2[] = {
0121     {0x0208, 0x00000000, 0x00000f00},
0122     {0x0208, 0x00000000, 0x0000001f},
0123     {0x0204, 0x00000000, 0x00040000},
0124     {0x0208, 0x000000a0, 0x000000e0},
0125 };
0126 
0127 static void netcp_xgbe_serdes_cmu_init(void __iomem *serdes_regs)
0128 {
0129     int i;
0130 
0131     /* cmu0 setup */
0132     for (i = 0; i < ARRAY_SIZE(cfg_phyb_1p25g_156p25mhz_cmu0); i++) {
0133         reg_rmw(serdes_regs + cfg_phyb_1p25g_156p25mhz_cmu0[i].ofs,
0134             cfg_phyb_1p25g_156p25mhz_cmu0[i].val,
0135             cfg_phyb_1p25g_156p25mhz_cmu0[i].mask);
0136     }
0137 
0138     /* cmu1 setup */
0139     for (i = 0; i < ARRAY_SIZE(cfg_phyb_10p3125g_156p25mhz_cmu1); i++) {
0140         reg_rmw(serdes_regs + cfg_phyb_10p3125g_156p25mhz_cmu1[i].ofs,
0141             cfg_phyb_10p3125g_156p25mhz_cmu1[i].val,
0142             cfg_phyb_10p3125g_156p25mhz_cmu1[i].mask);
0143     }
0144 }
0145 
0146 /* lane is 0 based */
0147 static void netcp_xgbe_serdes_lane_config(
0148             void __iomem *serdes_regs, int lane)
0149 {
0150     int i;
0151 
0152     /* lane setup */
0153     for (i = 0; i < ARRAY_SIZE(cfg_phyb_10p3125g_16bit_lane); i++) {
0154         reg_rmw(serdes_regs +
0155                 cfg_phyb_10p3125g_16bit_lane[i].ofs +
0156                 (0x200 * lane),
0157             cfg_phyb_10p3125g_16bit_lane[i].val,
0158             cfg_phyb_10p3125g_16bit_lane[i].mask);
0159     }
0160 
0161     /* disable auto negotiation*/
0162     reg_rmw(serdes_regs + (0x200 * lane) + 0x0380,
0163         0x00000000, 0x00000010);
0164 
0165     /* disable link training */
0166     reg_rmw(serdes_regs + (0x200 * lane) + 0x03c0,
0167         0x00000000, 0x00000200);
0168 }
0169 
0170 static void netcp_xgbe_serdes_com_enable(void __iomem *serdes_regs)
0171 {
0172     int i;
0173 
0174     for (i = 0; i < ARRAY_SIZE(cfg_phyb_10p3125g_comlane); i++) {
0175         reg_rmw(serdes_regs + cfg_phyb_10p3125g_comlane[i].ofs,
0176             cfg_phyb_10p3125g_comlane[i].val,
0177             cfg_phyb_10p3125g_comlane[i].mask);
0178     }
0179 }
0180 
0181 static void netcp_xgbe_serdes_lane_enable(
0182             void __iomem *serdes_regs, int lane)
0183 {
0184     /* Set Lane Control Rate */
0185     writel(0xe0e9e038, serdes_regs + 0x1fe0 + (4 * lane));
0186 }
0187 
0188 static void netcp_xgbe_serdes_phyb_rst_clr(void __iomem *serdes_regs)
0189 {
0190     reg_rmw(serdes_regs + 0x0a00, 0x0000001f, 0x000000ff);
0191 }
0192 
0193 static void netcp_xgbe_serdes_pll_disable(void __iomem *serdes_regs)
0194 {
0195     writel(0x88000000, serdes_regs + 0x1ff4);
0196 }
0197 
0198 static void netcp_xgbe_serdes_pll_enable(void __iomem *serdes_regs)
0199 {
0200     netcp_xgbe_serdes_phyb_rst_clr(serdes_regs);
0201     writel(0xee000000, serdes_regs + 0x1ff4);
0202 }
0203 
0204 static int netcp_xgbe_wait_pll_locked(void __iomem *sw_regs)
0205 {
0206     unsigned long timeout;
0207     int ret = 0;
0208     u32 val_1, val_0;
0209 
0210     timeout = jiffies + msecs_to_jiffies(500);
0211     do {
0212         val_0 = (readl(sw_regs + XGBE_SGMII_1_OFFSET) & BIT(4));
0213         val_1 = (readl(sw_regs + XGBE_SGMII_2_OFFSET) & BIT(4));
0214 
0215         if (val_1 && val_0)
0216             return 0;
0217 
0218         if (time_after(jiffies, timeout)) {
0219             ret = -ETIMEDOUT;
0220             break;
0221         }
0222 
0223         cpu_relax();
0224     } while (true);
0225 
0226     pr_err("XGBE serdes not locked: time out.\n");
0227     return ret;
0228 }
0229 
0230 static void netcp_xgbe_serdes_enable_xgmii_port(void __iomem *sw_regs)
0231 {
0232     writel(0x03, sw_regs + XGBE_CTRL_OFFSET);
0233 }
0234 
0235 static u32 netcp_xgbe_serdes_read_tbus_val(void __iomem *serdes_regs)
0236 {
0237     u32 tmp;
0238 
0239     if (PHY_A(serdes_regs)) {
0240         tmp  = (readl(serdes_regs + 0x0ec) >> 24) & 0x0ff;
0241         tmp |= ((readl(serdes_regs + 0x0fc) >> 16) & 0x00f00);
0242     } else {
0243         tmp  = (readl(serdes_regs + 0x0f8) >> 16) & 0x0fff;
0244     }
0245 
0246     return tmp;
0247 }
0248 
0249 static void netcp_xgbe_serdes_write_tbus_addr(void __iomem *serdes_regs,
0250                           int select, int ofs)
0251 {
0252     if (PHY_A(serdes_regs)) {
0253         reg_rmw(serdes_regs + 0x0008, ((select << 5) + ofs) << 24,
0254             ~0x00ffffff);
0255         return;
0256     }
0257 
0258     /* For 2 lane Phy-B, lane0 is actually lane1 */
0259     switch (select) {
0260     case 1:
0261         select = 2;
0262         break;
0263     case 2:
0264         select = 3;
0265         break;
0266     default:
0267         return;
0268     }
0269 
0270     reg_rmw(serdes_regs + 0x00fc, ((select << 8) + ofs) << 16, ~0xf800ffff);
0271 }
0272 
0273 static u32 netcp_xgbe_serdes_read_select_tbus(void __iomem *serdes_regs,
0274                           int select, int ofs)
0275 {
0276     /* Set tbus address */
0277     netcp_xgbe_serdes_write_tbus_addr(serdes_regs, select, ofs);
0278     /* Get TBUS Value */
0279     return netcp_xgbe_serdes_read_tbus_val(serdes_regs);
0280 }
0281 
0282 static void netcp_xgbe_serdes_reset_cdr(void __iomem *serdes_regs,
0283                     void __iomem *sig_detect_reg, int lane)
0284 {
0285     u32 tmp, dlpf, tbus;
0286 
0287     /*Get the DLPF values */
0288     tmp = netcp_xgbe_serdes_read_select_tbus(
0289             serdes_regs, lane + 1, 5);
0290 
0291     dlpf = tmp >> 2;
0292 
0293     if (dlpf < 400 || dlpf > 700) {
0294         reg_rmw(sig_detect_reg, VAL_SH(2, 1), MASK_WID_SH(2, 1));
0295         mdelay(1);
0296         reg_rmw(sig_detect_reg, VAL_SH(0, 1), MASK_WID_SH(2, 1));
0297     } else {
0298         tbus = netcp_xgbe_serdes_read_select_tbus(serdes_regs, lane +
0299                               1, 0xe);
0300 
0301         pr_debug("XGBE: CDR centered, DLPF: %4d,%d,%d.\n",
0302              tmp >> 2, tmp & 3, (tbus >> 2) & 3);
0303     }
0304 }
0305 
0306 /* Call every 100 ms */
0307 static int netcp_xgbe_check_link_status(void __iomem *serdes_regs,
0308                     void __iomem *sw_regs, u32 lanes,
0309                     u32 *current_state, u32 *lane_down)
0310 {
0311     void __iomem *pcsr_base = sw_regs + 0x0600;
0312     void __iomem *sig_detect_reg;
0313     u32 pcsr_rx_stat, blk_lock, blk_errs;
0314     int loss, i, status = 1;
0315 
0316     for (i = 0; i < lanes; i++) {
0317         /* Get the Loss bit */
0318         loss = readl(serdes_regs + 0x1fc0 + 0x20 + (i * 0x04)) & 0x1;
0319 
0320         /* Get Block Errors and Block Lock bits */
0321         pcsr_rx_stat = readl(pcsr_base + 0x0c + (i * 0x80));
0322         blk_lock = (pcsr_rx_stat >> 30) & 0x1;
0323         blk_errs = (pcsr_rx_stat >> 16) & 0x0ff;
0324 
0325         /* Get Signal Detect Overlay Address */
0326         sig_detect_reg = serdes_regs + (i * 0x200) + 0x200 + 0x04;
0327 
0328         /* If Block errors maxed out, attempt recovery! */
0329         if (blk_errs == 0x0ff)
0330             blk_lock = 0;
0331 
0332         switch (current_state[i]) {
0333         case 0:
0334             /* if good link lock the signal detect ON! */
0335             if (!loss && blk_lock) {
0336                 pr_debug("XGBE PCSR Linked Lane: %d\n", i);
0337                 reg_rmw(sig_detect_reg, VAL_SH(3, 1),
0338                     MASK_WID_SH(2, 1));
0339                 current_state[i] = 1;
0340             } else if (!blk_lock) {
0341                 /* if no lock, then reset CDR */
0342                 pr_debug("XGBE PCSR Recover Lane: %d\n", i);
0343                 netcp_xgbe_serdes_reset_cdr(serdes_regs,
0344                                 sig_detect_reg, i);
0345             }
0346             break;
0347 
0348         case 1:
0349             if (!blk_lock) {
0350                 /* Link Lost? */
0351                 lane_down[i] = 1;
0352                 current_state[i] = 2;
0353             }
0354             break;
0355 
0356         case 2:
0357             if (blk_lock)
0358                 /* Nope just noise */
0359                 current_state[i] = 1;
0360             else {
0361                 /* Lost the block lock, reset CDR if it is
0362                  * not centered and go back to sync state
0363                  */
0364                 netcp_xgbe_serdes_reset_cdr(serdes_regs,
0365                                 sig_detect_reg, i);
0366                 current_state[i] = 0;
0367             }
0368             break;
0369 
0370         default:
0371             pr_err("XGBE: unknown current_state[%d] %d\n",
0372                    i, current_state[i]);
0373             break;
0374         }
0375 
0376         if (blk_errs > 0) {
0377             /* Reset the Error counts! */
0378             reg_rmw(pcsr_base + 0x08 + (i * 0x80), VAL_SH(0x19, 0),
0379                 MASK_WID_SH(8, 0));
0380 
0381             reg_rmw(pcsr_base + 0x08 + (i * 0x80), VAL_SH(0x00, 0),
0382                 MASK_WID_SH(8, 0));
0383         }
0384 
0385         status &= (current_state[i] == 1);
0386     }
0387 
0388     return status;
0389 }
0390 
0391 static int netcp_xgbe_serdes_check_lane(void __iomem *serdes_regs,
0392                     void __iomem *sw_regs)
0393 {
0394     u32 current_state[2] = {0, 0};
0395     int retries = 0, link_up;
0396     u32 lane_down[2];
0397 
0398     do {
0399         lane_down[0] = 0;
0400         lane_down[1] = 0;
0401 
0402         link_up = netcp_xgbe_check_link_status(serdes_regs, sw_regs, 2,
0403                                current_state,
0404                                lane_down);
0405 
0406         /* if we did not get link up then wait 100ms before calling
0407          * it again
0408          */
0409         if (link_up)
0410             break;
0411 
0412         if (lane_down[0])
0413             pr_debug("XGBE: detected link down on lane 0\n");
0414 
0415         if (lane_down[1])
0416             pr_debug("XGBE: detected link down on lane 1\n");
0417 
0418         if (++retries > 1) {
0419             pr_debug("XGBE: timeout waiting for serdes link up\n");
0420             return -ETIMEDOUT;
0421         }
0422         mdelay(100);
0423     } while (!link_up);
0424 
0425     pr_debug("XGBE: PCSR link is up\n");
0426     return 0;
0427 }
0428 
0429 static void netcp_xgbe_serdes_setup_cm_c1_c2(void __iomem *serdes_regs,
0430                          int lane, int cm, int c1, int c2)
0431 {
0432     int i;
0433 
0434     for (i = 0; i < ARRAY_SIZE(cfg_cm_c1_c2); i++) {
0435         reg_rmw(serdes_regs + cfg_cm_c1_c2[i].ofs + (0x200 * lane),
0436             cfg_cm_c1_c2[i].val,
0437             cfg_cm_c1_c2[i].mask);
0438     }
0439 }
0440 
0441 static void netcp_xgbe_reset_serdes(void __iomem *serdes_regs)
0442 {
0443     /* Toggle the POR_EN bit in CONFIG.CPU_CTRL */
0444     /* enable POR_EN bit */
0445     reg_rmw(serdes_regs + PCSR_CPU_CTRL_OFFSET, POR_EN, POR_EN);
0446     usleep_range(10, 100);
0447 
0448     /* disable POR_EN bit */
0449     reg_rmw(serdes_regs + PCSR_CPU_CTRL_OFFSET, 0, POR_EN);
0450     usleep_range(10, 100);
0451 }
0452 
0453 static int netcp_xgbe_serdes_config(void __iomem *serdes_regs,
0454                     void __iomem *sw_regs)
0455 {
0456     u32 ret, i;
0457 
0458     netcp_xgbe_serdes_pll_disable(serdes_regs);
0459     netcp_xgbe_serdes_cmu_init(serdes_regs);
0460 
0461     for (i = 0; i < 2; i++)
0462         netcp_xgbe_serdes_lane_config(serdes_regs, i);
0463 
0464     netcp_xgbe_serdes_com_enable(serdes_regs);
0465     /* This is EVM + RTM-BOC specific */
0466     for (i = 0; i < 2; i++)
0467         netcp_xgbe_serdes_setup_cm_c1_c2(serdes_regs, i, 0, 0, 5);
0468 
0469     netcp_xgbe_serdes_pll_enable(serdes_regs);
0470     for (i = 0; i < 2; i++)
0471         netcp_xgbe_serdes_lane_enable(serdes_regs, i);
0472 
0473     /* SB PLL Status Poll */
0474     ret = netcp_xgbe_wait_pll_locked(sw_regs);
0475     if (ret)
0476         return ret;
0477 
0478     netcp_xgbe_serdes_enable_xgmii_port(sw_regs);
0479     netcp_xgbe_serdes_check_lane(serdes_regs, sw_regs);
0480     return ret;
0481 }
0482 
0483 int netcp_xgbe_serdes_init(void __iomem *serdes_regs, void __iomem *xgbe_regs)
0484 {
0485     u32 val;
0486 
0487     /* read COMLANE bits 4:0 */
0488     val = readl(serdes_regs + 0xa00);
0489     if (val & 0x1f) {
0490         pr_debug("XGBE: serdes already in operation - reset\n");
0491         netcp_xgbe_reset_serdes(serdes_regs);
0492     }
0493     return netcp_xgbe_serdes_config(serdes_regs, xgbe_regs);
0494 }