0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 #include <asm/octeon/octeon.h>
0034
0035 #include <asm/octeon/cvmx-config.h>
0036
0037 #include <asm/octeon/cvmx-helper.h>
0038 #include <asm/octeon/cvmx-helper-board.h>
0039
0040 #include <asm/octeon/cvmx-gmxx-defs.h>
0041 #include <asm/octeon/cvmx-pcsx-defs.h>
0042 #include <asm/octeon/cvmx-pcsxx-defs.h>
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052 static int __cvmx_helper_sgmii_hardware_init_one_time(int interface, int index)
0053 {
0054 const uint64_t clock_mhz = cvmx_sysinfo_get()->cpu_clock_hz / 1000000;
0055 union cvmx_pcsx_miscx_ctl_reg pcs_misc_ctl_reg;
0056 union cvmx_pcsx_linkx_timer_count_reg pcsx_linkx_timer_count_reg;
0057 union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
0058
0059
0060 gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
0061 gmxx_prtx_cfg.s.en = 0;
0062 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
0063
0064
0065
0066
0067
0068
0069 pcs_misc_ctl_reg.u64 =
0070 cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
0071 pcsx_linkx_timer_count_reg.u64 =
0072 cvmx_read_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface));
0073 if (pcs_misc_ctl_reg.s.mode) {
0074
0075 pcsx_linkx_timer_count_reg.s.count =
0076 (10000ull * clock_mhz) >> 10;
0077 } else {
0078
0079 pcsx_linkx_timer_count_reg.s.count =
0080 (1600ull * clock_mhz) >> 10;
0081 }
0082 cvmx_write_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface),
0083 pcsx_linkx_timer_count_reg.u64);
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094 if (pcs_misc_ctl_reg.s.mode) {
0095
0096 union cvmx_pcsx_anx_adv_reg pcsx_anx_adv_reg;
0097 pcsx_anx_adv_reg.u64 =
0098 cvmx_read_csr(CVMX_PCSX_ANX_ADV_REG(index, interface));
0099 pcsx_anx_adv_reg.s.rem_flt = 0;
0100 pcsx_anx_adv_reg.s.pause = 3;
0101 pcsx_anx_adv_reg.s.hfd = 1;
0102 pcsx_anx_adv_reg.s.fd = 1;
0103 cvmx_write_csr(CVMX_PCSX_ANX_ADV_REG(index, interface),
0104 pcsx_anx_adv_reg.u64);
0105 } else {
0106 union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
0107 pcsx_miscx_ctl_reg.u64 =
0108 cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
0109 if (pcsx_miscx_ctl_reg.s.mac_phy) {
0110
0111 union cvmx_pcsx_sgmx_an_adv_reg pcsx_sgmx_an_adv_reg;
0112 pcsx_sgmx_an_adv_reg.u64 =
0113 cvmx_read_csr(CVMX_PCSX_SGMX_AN_ADV_REG
0114 (index, interface));
0115 pcsx_sgmx_an_adv_reg.s.link = 1;
0116 pcsx_sgmx_an_adv_reg.s.dup = 1;
0117 pcsx_sgmx_an_adv_reg.s.speed = 2;
0118 cvmx_write_csr(CVMX_PCSX_SGMX_AN_ADV_REG
0119 (index, interface),
0120 pcsx_sgmx_an_adv_reg.u64);
0121 } else {
0122
0123 }
0124 }
0125 return 0;
0126 }
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137 static int __cvmx_helper_sgmii_hardware_init_link(int interface, int index)
0138 {
0139 union cvmx_pcsx_mrx_control_reg control_reg;
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149 control_reg.u64 =
0150 cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
0151 if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) {
0152 control_reg.s.reset = 1;
0153 cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface),
0154 control_reg.u64);
0155 if (CVMX_WAIT_FOR_FIELD64
0156 (CVMX_PCSX_MRX_CONTROL_REG(index, interface),
0157 union cvmx_pcsx_mrx_control_reg, reset, ==, 0, 10000)) {
0158 cvmx_dprintf("SGMII%d: Timeout waiting for port %d "
0159 "to finish reset\n",
0160 interface, index);
0161 return -1;
0162 }
0163 }
0164
0165
0166
0167
0168
0169 control_reg.s.rst_an = 1;
0170 control_reg.s.an_en = 1;
0171 control_reg.s.pwr_dn = 0;
0172 cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface),
0173 control_reg.u64);
0174
0175
0176
0177
0178
0179
0180
0181 if ((cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) &&
0182 CVMX_WAIT_FOR_FIELD64(CVMX_PCSX_MRX_STATUS_REG(index, interface),
0183 union cvmx_pcsx_mrx_status_reg, an_cpt, ==, 1,
0184 10000)) {
0185
0186 return -1;
0187 }
0188 return 0;
0189 }
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201 static int __cvmx_helper_sgmii_hardware_init_link_speed(int interface,
0202 int index,
0203 union cvmx_helper_link_info
0204 link_info)
0205 {
0206 int is_enabled;
0207 union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
0208 union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
0209
0210
0211 gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
0212 is_enabled = gmxx_prtx_cfg.s.en;
0213 gmxx_prtx_cfg.s.en = 0;
0214 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
0215
0216
0217 if (CVMX_WAIT_FOR_FIELD64
0218 (CVMX_GMXX_PRTX_CFG(index, interface), union cvmx_gmxx_prtx_cfg,
0219 rx_idle, ==, 1, 10000)
0220 || CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index, interface),
0221 union cvmx_gmxx_prtx_cfg, tx_idle, ==, 1,
0222 10000)) {
0223 cvmx_dprintf
0224 ("SGMII%d: Timeout waiting for port %d to be idle\n",
0225 interface, index);
0226 return -1;
0227 }
0228
0229
0230 gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
0231
0232
0233
0234
0235
0236 pcsx_miscx_ctl_reg.u64 =
0237 cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
0238
0239
0240
0241
0242
0243 pcsx_miscx_ctl_reg.s.gmxeno = !link_info.s.link_up;
0244
0245
0246 if (link_info.s.link_up)
0247 gmxx_prtx_cfg.s.duplex = link_info.s.full_duplex;
0248
0249
0250 switch (link_info.s.speed) {
0251 case 10:
0252 gmxx_prtx_cfg.s.speed = 0;
0253 gmxx_prtx_cfg.s.speed_msb = 1;
0254 gmxx_prtx_cfg.s.slottime = 0;
0255
0256 pcsx_miscx_ctl_reg.s.samp_pt = 25;
0257 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64);
0258 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
0259 break;
0260 case 100:
0261 gmxx_prtx_cfg.s.speed = 0;
0262 gmxx_prtx_cfg.s.speed_msb = 0;
0263 gmxx_prtx_cfg.s.slottime = 0;
0264 pcsx_miscx_ctl_reg.s.samp_pt = 0x5;
0265 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64);
0266 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
0267 break;
0268 case 1000:
0269 gmxx_prtx_cfg.s.speed = 1;
0270 gmxx_prtx_cfg.s.speed_msb = 0;
0271 gmxx_prtx_cfg.s.slottime = 1;
0272 pcsx_miscx_ctl_reg.s.samp_pt = 1;
0273 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 512);
0274 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 8192);
0275 break;
0276 default:
0277 break;
0278 }
0279
0280
0281 cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface),
0282 pcsx_miscx_ctl_reg.u64);
0283
0284
0285 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
0286
0287
0288 gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
0289
0290
0291 gmxx_prtx_cfg.s.en = is_enabled;
0292 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
0293
0294 return 0;
0295 }
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307 static int __cvmx_helper_sgmii_hardware_init(int interface, int num_ports)
0308 {
0309 int index;
0310
0311 __cvmx_helper_setup_gmx(interface, num_ports);
0312
0313 for (index = 0; index < num_ports; index++) {
0314 int ipd_port = cvmx_helper_get_ipd_port(interface, index);
0315 __cvmx_helper_sgmii_hardware_init_one_time(interface, index);
0316
0317
0318
0319
0320
0321 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
0322 __cvmx_helper_sgmii_link_set(ipd_port,
0323 __cvmx_helper_sgmii_link_get(ipd_port));
0324 }
0325
0326 return 0;
0327 }
0328
0329 int __cvmx_helper_sgmii_enumerate(int interface)
0330 {
0331 return 4;
0332 }
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342 int __cvmx_helper_sgmii_probe(int interface)
0343 {
0344 union cvmx_gmxx_inf_mode mode;
0345
0346
0347
0348
0349
0350
0351 mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
0352 mode.s.en = 1;
0353 cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64);
0354 return __cvmx_helper_sgmii_enumerate(interface);
0355 }
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366 int __cvmx_helper_sgmii_enable(int interface)
0367 {
0368 int num_ports = cvmx_helper_ports_on_interface(interface);
0369 int index;
0370
0371 __cvmx_helper_sgmii_hardware_init(interface, num_ports);
0372
0373 for (index = 0; index < num_ports; index++) {
0374 union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
0375 gmxx_prtx_cfg.u64 =
0376 cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
0377 gmxx_prtx_cfg.s.en = 1;
0378 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
0379 gmxx_prtx_cfg.u64);
0380 __cvmx_interrupt_pcsx_intx_en_reg_enable(index, interface);
0381 }
0382 __cvmx_interrupt_pcsxx_int_en_reg_enable(interface);
0383 __cvmx_interrupt_gmxx_enable(interface);
0384 return 0;
0385 }
0386
0387
0388
0389
0390
0391
0392
0393
0394
0395
0396
0397 union cvmx_helper_link_info __cvmx_helper_sgmii_link_get(int ipd_port)
0398 {
0399 union cvmx_helper_link_info result;
0400 union cvmx_pcsx_miscx_ctl_reg pcs_misc_ctl_reg;
0401 int interface = cvmx_helper_get_interface_num(ipd_port);
0402 int index = cvmx_helper_get_interface_index_num(ipd_port);
0403 union cvmx_pcsx_mrx_control_reg pcsx_mrx_control_reg;
0404
0405 result.u64 = 0;
0406
0407 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) {
0408
0409 result.s.link_up = 1;
0410 result.s.full_duplex = 1;
0411 result.s.speed = 1000;
0412 return result;
0413 }
0414
0415 pcsx_mrx_control_reg.u64 =
0416 cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
0417 if (pcsx_mrx_control_reg.s.loopbck1) {
0418
0419 result.s.link_up = 1;
0420 result.s.full_duplex = 1;
0421 result.s.speed = 1000;
0422 return result;
0423 }
0424
0425 pcs_misc_ctl_reg.u64 =
0426 cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
0427 if (pcs_misc_ctl_reg.s.mode) {
0428
0429
0430 } else {
0431 union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
0432 pcsx_miscx_ctl_reg.u64 =
0433 cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
0434 if (pcsx_miscx_ctl_reg.s.mac_phy) {
0435
0436 union cvmx_pcsx_mrx_status_reg pcsx_mrx_status_reg;
0437 union cvmx_pcsx_anx_results_reg pcsx_anx_results_reg;
0438
0439
0440
0441
0442
0443 pcsx_mrx_status_reg.u64 =
0444 cvmx_read_csr(CVMX_PCSX_MRX_STATUS_REG
0445 (index, interface));
0446 if (pcsx_mrx_status_reg.s.lnk_st == 0) {
0447 if (__cvmx_helper_sgmii_hardware_init_link
0448 (interface, index) != 0)
0449 return result;
0450 }
0451
0452
0453 pcsx_anx_results_reg.u64 =
0454 cvmx_read_csr(CVMX_PCSX_ANX_RESULTS_REG
0455 (index, interface));
0456 if (pcsx_anx_results_reg.s.an_cpt) {
0457
0458
0459
0460
0461 result.s.full_duplex =
0462 pcsx_anx_results_reg.s.dup;
0463 result.s.link_up =
0464 pcsx_anx_results_reg.s.link_ok;
0465 switch (pcsx_anx_results_reg.s.spd) {
0466 case 0:
0467 result.s.speed = 10;
0468 break;
0469 case 1:
0470 result.s.speed = 100;
0471 break;
0472 case 2:
0473 result.s.speed = 1000;
0474 break;
0475 default:
0476 result.s.speed = 0;
0477 result.s.link_up = 0;
0478 break;
0479 }
0480 } else {
0481
0482
0483
0484
0485 result.s.speed = 0;
0486 result.s.link_up = 0;
0487 }
0488 } else {
0489
0490 result = __cvmx_helper_board_link_get(ipd_port);
0491 }
0492 }
0493 return result;
0494 }
0495
0496
0497
0498
0499
0500
0501
0502
0503
0504
0505
0506
0507 int __cvmx_helper_sgmii_link_set(int ipd_port,
0508 union cvmx_helper_link_info link_info)
0509 {
0510 int interface = cvmx_helper_get_interface_num(ipd_port);
0511 int index = cvmx_helper_get_interface_index_num(ipd_port);
0512 __cvmx_helper_sgmii_hardware_init_link(interface, index);
0513 return __cvmx_helper_sgmii_hardware_init_link_speed(interface, index,
0514 link_info);
0515 }