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 #include <asm/octeon/octeon.h>
0033
0034 #include <asm/octeon/cvmx-config.h>
0035
0036 #include <asm/octeon/cvmx-pko.h>
0037 #include <asm/octeon/cvmx-helper.h>
0038 #include <asm/octeon/cvmx-helper-board.h>
0039
0040 #include <asm/octeon/cvmx-npi-defs.h>
0041 #include <asm/octeon/cvmx-gmxx-defs.h>
0042 #include <asm/octeon/cvmx-asxx-defs.h>
0043 #include <asm/octeon/cvmx-dbg-defs.h>
0044
0045
0046
0047
0048
0049
0050
0051
0052 int __cvmx_helper_rgmii_probe(int interface)
0053 {
0054 int num_ports = 0;
0055 union cvmx_gmxx_inf_mode mode;
0056 mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
0057
0058 if (mode.s.type) {
0059 if (OCTEON_IS_MODEL(OCTEON_CN38XX)
0060 || OCTEON_IS_MODEL(OCTEON_CN58XX)) {
0061 cvmx_dprintf("ERROR: RGMII initialize called in "
0062 "SPI interface\n");
0063 } else if (OCTEON_IS_MODEL(OCTEON_CN31XX)
0064 || OCTEON_IS_MODEL(OCTEON_CN30XX)
0065 || OCTEON_IS_MODEL(OCTEON_CN50XX)) {
0066
0067
0068
0069
0070 num_ports = 2;
0071 } else {
0072 cvmx_dprintf("ERROR: Unsupported Octeon model in %s\n",
0073 __func__);
0074 }
0075 } else {
0076 if (OCTEON_IS_MODEL(OCTEON_CN38XX)
0077 || OCTEON_IS_MODEL(OCTEON_CN58XX)) {
0078 num_ports = 4;
0079 } else if (OCTEON_IS_MODEL(OCTEON_CN31XX)
0080 || OCTEON_IS_MODEL(OCTEON_CN30XX)
0081 || OCTEON_IS_MODEL(OCTEON_CN50XX)) {
0082 num_ports = 3;
0083 } else {
0084 cvmx_dprintf("ERROR: Unsupported Octeon model in %s\n",
0085 __func__);
0086 }
0087 }
0088 return num_ports;
0089 }
0090
0091
0092
0093
0094
0095
0096
0097
0098 void cvmx_helper_rgmii_internal_loopback(int port)
0099 {
0100 int interface = (port >> 4) & 1;
0101 int index = port & 0xf;
0102 uint64_t tmp;
0103
0104 union cvmx_gmxx_prtx_cfg gmx_cfg;
0105 gmx_cfg.u64 = 0;
0106 gmx_cfg.s.duplex = 1;
0107 gmx_cfg.s.slottime = 1;
0108 gmx_cfg.s.speed = 1;
0109 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1);
0110 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200);
0111 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000);
0112 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
0113 tmp = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface));
0114 cvmx_write_csr(CVMX_ASXX_PRT_LOOP(interface), (1 << index) | tmp);
0115 tmp = cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(interface));
0116 cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), (1 << index) | tmp);
0117 tmp = cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface));
0118 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), (1 << index) | tmp);
0119 gmx_cfg.s.en = 1;
0120 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
0121 }
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133 static int __cvmx_helper_errata_asx_pass1(int interface, int port,
0134 int cpu_clock_hz)
0135 {
0136
0137 if (cpu_clock_hz >= 325000000 && cpu_clock_hz < 375000000)
0138 cvmx_write_csr(CVMX_ASXX_TX_HI_WATERX(port, interface), 12);
0139 else if (cpu_clock_hz >= 375000000 && cpu_clock_hz < 437000000)
0140 cvmx_write_csr(CVMX_ASXX_TX_HI_WATERX(port, interface), 11);
0141 else if (cpu_clock_hz >= 437000000 && cpu_clock_hz < 550000000)
0142 cvmx_write_csr(CVMX_ASXX_TX_HI_WATERX(port, interface), 10);
0143 else if (cpu_clock_hz >= 550000000 && cpu_clock_hz < 687000000)
0144 cvmx_write_csr(CVMX_ASXX_TX_HI_WATERX(port, interface), 9);
0145 else
0146 cvmx_dprintf("Illegal clock frequency (%d). "
0147 "CVMX_ASXX_TX_HI_WATERX not set\n", cpu_clock_hz);
0148 return 0;
0149 }
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159 int __cvmx_helper_rgmii_enable(int interface)
0160 {
0161 int num_ports = cvmx_helper_ports_on_interface(interface);
0162 int port;
0163 struct cvmx_sysinfo *sys_info_ptr = cvmx_sysinfo_get();
0164 union cvmx_gmxx_inf_mode mode;
0165 union cvmx_asxx_tx_prt_en asx_tx;
0166 union cvmx_asxx_rx_prt_en asx_rx;
0167
0168 mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
0169
0170 if (mode.s.en == 0)
0171 return -1;
0172 if ((OCTEON_IS_MODEL(OCTEON_CN38XX) ||
0173 OCTEON_IS_MODEL(OCTEON_CN58XX)) && mode.s.type == 1)
0174
0175 return -1;
0176
0177
0178 asx_tx.u64 = 0;
0179 asx_tx.s.prt_en = cvmx_build_mask(num_ports);
0180 cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), asx_tx.u64);
0181
0182 asx_rx.u64 = 0;
0183 asx_rx.s.prt_en = cvmx_build_mask(num_ports);
0184 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), asx_rx.u64);
0185
0186
0187 for (port = 0; port < num_ports; port++) {
0188
0189
0190
0191 if (cvmx_octeon_is_pass1())
0192 __cvmx_helper_errata_asx_pass1(interface, port,
0193 sys_info_ptr->
0194 cpu_clock_hz);
0195 else {
0196
0197
0198
0199
0200
0201 union cvmx_gmxx_rxx_frm_ctl frm_ctl;
0202 frm_ctl.u64 =
0203 cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL
0204 (port, interface));
0205
0206 frm_ctl.s.pre_free = 1;
0207 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(port, interface),
0208 frm_ctl.u64);
0209 }
0210
0211
0212
0213
0214
0215
0216
0217
0218 cvmx_write_csr(CVMX_GMXX_TXX_PAUSE_PKT_TIME(port, interface),
0219 20000);
0220 cvmx_write_csr(CVMX_GMXX_TXX_PAUSE_PKT_INTERVAL
0221 (port, interface), 19000);
0222
0223 if (OCTEON_IS_MODEL(OCTEON_CN50XX)) {
0224 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface),
0225 16);
0226 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface),
0227 16);
0228 } else {
0229 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface),
0230 24);
0231 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface),
0232 24);
0233 }
0234 }
0235
0236 __cvmx_helper_setup_gmx(interface, num_ports);
0237
0238
0239 for (port = 0; port < num_ports; port++) {
0240 union cvmx_gmxx_prtx_cfg gmx_cfg;
0241
0242 gmx_cfg.u64 =
0243 cvmx_read_csr(CVMX_GMXX_PRTX_CFG(port, interface));
0244 gmx_cfg.s.en = 1;
0245 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(port, interface),
0246 gmx_cfg.u64);
0247 }
0248 __cvmx_interrupt_asxx_enable(interface);
0249 __cvmx_interrupt_gmxx_enable(interface);
0250
0251 return 0;
0252 }
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264 union cvmx_helper_link_info __cvmx_helper_rgmii_link_get(int ipd_port)
0265 {
0266 int interface = cvmx_helper_get_interface_num(ipd_port);
0267 int index = cvmx_helper_get_interface_index_num(ipd_port);
0268 union cvmx_asxx_prt_loop asxx_prt_loop;
0269
0270 asxx_prt_loop.u64 = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface));
0271 if (asxx_prt_loop.s.int_loop & (1 << index)) {
0272
0273 union cvmx_helper_link_info result;
0274 result.u64 = 0;
0275 result.s.full_duplex = 1;
0276 result.s.link_up = 1;
0277 result.s.speed = 1000;
0278 return result;
0279 } else
0280 return __cvmx_helper_board_link_get(ipd_port);
0281 }
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294 int __cvmx_helper_rgmii_link_set(int ipd_port,
0295 union cvmx_helper_link_info link_info)
0296 {
0297 int result = 0;
0298 int interface = cvmx_helper_get_interface_num(ipd_port);
0299 int index = cvmx_helper_get_interface_index_num(ipd_port);
0300 union cvmx_gmxx_prtx_cfg original_gmx_cfg;
0301 union cvmx_gmxx_prtx_cfg new_gmx_cfg;
0302 union cvmx_pko_mem_queue_qos pko_mem_queue_qos;
0303 union cvmx_pko_mem_queue_qos pko_mem_queue_qos_save[16];
0304 union cvmx_gmxx_tx_ovr_bp gmx_tx_ovr_bp;
0305 union cvmx_gmxx_tx_ovr_bp gmx_tx_ovr_bp_save;
0306 int i;
0307
0308
0309 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
0310 return 0;
0311
0312
0313 original_gmx_cfg.u64 =
0314 cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
0315 new_gmx_cfg = original_gmx_cfg;
0316
0317
0318 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface),
0319 cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)) &
0320 ~(1 << index));
0321
0322 memset(pko_mem_queue_qos_save, 0, sizeof(pko_mem_queue_qos_save));
0323
0324 for (i = 0; i < cvmx_pko_get_num_queues(ipd_port); i++) {
0325 int queue = cvmx_pko_get_base_queue(ipd_port) + i;
0326 cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue);
0327 pko_mem_queue_qos.u64 = cvmx_read_csr(CVMX_PKO_MEM_QUEUE_QOS);
0328 pko_mem_queue_qos.s.pid = ipd_port;
0329 pko_mem_queue_qos.s.qid = queue;
0330 pko_mem_queue_qos_save[i] = pko_mem_queue_qos;
0331 pko_mem_queue_qos.s.qos_mask = 0;
0332 cvmx_write_csr(CVMX_PKO_MEM_QUEUE_QOS, pko_mem_queue_qos.u64);
0333 }
0334
0335
0336 gmx_tx_ovr_bp.u64 = cvmx_read_csr(CVMX_GMXX_TX_OVR_BP(interface));
0337 gmx_tx_ovr_bp_save = gmx_tx_ovr_bp;
0338 gmx_tx_ovr_bp.s.bp &= ~(1 << index);
0339 gmx_tx_ovr_bp.s.en |= 1 << index;
0340 cvmx_write_csr(CVMX_GMXX_TX_OVR_BP(interface), gmx_tx_ovr_bp.u64);
0341 cvmx_read_csr(CVMX_GMXX_TX_OVR_BP(interface));
0342
0343
0344
0345
0346
0347
0348
0349
0350 cvmx_write_csr(CVMX_NPI_DBG_SELECT,
0351 interface * 0x800 + index * 0x100 + 0x880);
0352 CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, union cvmx_dbg_data, data & 7,
0353 ==, 0, 10000);
0354 CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, union cvmx_dbg_data, data & 0xf,
0355 ==, 0, 10000);
0356
0357
0358 new_gmx_cfg.s.en = 0;
0359 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64);
0360 cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
0361
0362
0363 if (cvmx_octeon_is_pass1())
0364
0365 new_gmx_cfg.s.duplex = 1;
0366 else if (!link_info.s.link_up)
0367
0368 new_gmx_cfg.s.duplex = 1;
0369 else
0370 new_gmx_cfg.s.duplex = link_info.s.full_duplex;
0371
0372
0373 if (link_info.s.speed == 10) {
0374 new_gmx_cfg.s.slottime = 0;
0375 new_gmx_cfg.s.speed = 0;
0376 } else if (link_info.s.speed == 100) {
0377 new_gmx_cfg.s.slottime = 0;
0378 new_gmx_cfg.s.speed = 0;
0379 } else {
0380 new_gmx_cfg.s.slottime = 1;
0381 new_gmx_cfg.s.speed = 1;
0382 }
0383
0384
0385 if (link_info.s.speed == 10) {
0386 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 50);
0387 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x40);
0388 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
0389 } else if (link_info.s.speed == 100) {
0390 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 5);
0391 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x40);
0392 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
0393 } else {
0394 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1);
0395 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200);
0396 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000);
0397 }
0398
0399 if (OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) {
0400 if ((link_info.s.speed == 10) || (link_info.s.speed == 100)) {
0401 union cvmx_gmxx_inf_mode mode;
0402 mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416 if (((index == 0) && (mode.s.p0mii == 1))
0417 || ((index != 0) && (mode.s.type == 1))) {
0418 cvmx_write_csr(CVMX_GMXX_TXX_CLK
0419 (index, interface), 1);
0420 }
0421 }
0422 }
0423
0424
0425 cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
0426
0427
0428 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64);
0429
0430
0431 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface),
0432 cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)) | (1 <<
0433 index));
0434
0435
0436 for (i = 0; i < cvmx_pko_get_num_queues(ipd_port); i++) {
0437 int queue = cvmx_pko_get_base_queue(ipd_port) + i;
0438 cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue);
0439 cvmx_write_csr(CVMX_PKO_MEM_QUEUE_QOS,
0440 pko_mem_queue_qos_save[i].u64);
0441 }
0442
0443
0444 cvmx_write_csr(CVMX_GMXX_TX_OVR_BP(interface), gmx_tx_ovr_bp_save.u64);
0445
0446
0447 new_gmx_cfg.s.en = original_gmx_cfg.s.en;
0448 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64);
0449
0450 return result;
0451 }