3 * Copyright 2007,2008,2009 Free Software Foundation, Inc.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "app_common_v2.h"
24 #include "buffer_pool.h"
25 #include "memcpy_wa.h"
28 #include "print_rmon_regs.h"
34 //#include "db_init.h"
35 #include "usrp2_i2c_addr.h"
37 volatile bool link_is_up = false; // eth handler sets this
38 int cpu_tx_buf_dest_port = PORT_ETH;
40 // If this is non-zero, this dbsm could be writing to the ethernet
41 dbsm_t *ac_could_be_sending_to_eth;
43 static unsigned char exp_seqno __attribute__((unused)) = 0;
46 sync_to_pps(const op_generic_t *p)
48 timesync_regs->sync_on_next_pps = 1;
49 //putstr("SYNC to PPS\n");
54 sync_every_pps(const op_generic_t *p)
57 timesync_regs->tick_control |= TSC_TRIGGER_EVERYPPS;
59 timesync_regs->tick_control &= ~TSC_TRIGGER_EVERYPPS;
65 config_mimo_cmd(const op_config_mimo_t *p)
67 clocks_mimo_config(p->flags);
72 set_reply_hdr(u2_eth_packet_t *reply_pkt, u2_eth_packet_t const *cmd_pkt)
74 reply_pkt->ehdr.dst = cmd_pkt->ehdr.src;
75 reply_pkt->ehdr.src = *ethernet_mac_addr();
76 reply_pkt->ehdr.ethertype = U2_ETHERTYPE;
77 reply_pkt->thdr.flags = 0;
78 reply_pkt->thdr.fifo_status = 0; // written by protocol engine
79 reply_pkt->thdr.seqno = 0; // written by protocol engine
80 reply_pkt->thdr.ack = 0; // written by protocol engine
81 u2p_set_word0(&reply_pkt->fixed, 0, CONTROL_CHAN);
82 reply_pkt->fixed.timestamp = timer_regs->time;
86 send_reply(unsigned char *reply, size_t reply_len)
91 // wait for buffer to become idle
92 hal_set_leds(0x4, 0x4);
93 while((buffer_pool_status->status & BPS_IDLE(CPU_TX_BUF)) == 0)
95 hal_set_leds(0x0, 0x4);
97 // copy reply into CPU_TX_BUF
98 memcpy_wa(buffer_ram(CPU_TX_BUF), reply, reply_len);
100 // wait until nobody else is sending to the ethernet
101 if (ac_could_be_sending_to_eth){
102 hal_set_leds(0x8, 0x8);
103 dbsm_wait_for_opening(ac_could_be_sending_to_eth);
104 hal_set_leds(0x0, 0x8);
108 printf("sending_reply to port %d, len = %d\n", cpu_tx_buf_dest_port, (int)reply_len);
109 print_buffer(buffer_ram(CPU_TX_BUF), reply_len/4);
113 bp_send_from_buf(CPU_TX_BUF, cpu_tx_buf_dest_port, 1, 0, reply_len/4);
115 // wait for it to complete (not long, it's a small pkt)
116 while((buffer_pool_status->status & (BPS_DONE(CPU_TX_BUF) | BPS_ERROR(CPU_TX_BUF))) == 0)
119 bp_clear_buf(CPU_TX_BUF);
124 op_id_cmd(const op_generic_t *p,
125 void *reply_payload, size_t reply_payload_space)
127 op_id_reply_t *r = (op_id_reply_t *) reply_payload;
128 if (reply_payload_space < sizeof(*r)) // no room
131 // Build reply subpacket
133 r->opcode = OP_ID_REPLY;
134 r->len = sizeof(op_id_reply_t);
136 r->addr = *ethernet_mac_addr();
137 r->hw_rev = (u2_hw_rev_major << 8) | u2_hw_rev_minor;
138 // r->fpga_md5sum = ; // FIXME
139 // r->sw_md5sum = ; // FIXME
146 config_tx_v2_cmd(const op_config_tx_v2_t *p,
147 void *reply_payload, size_t reply_payload_space)
149 op_config_tx_reply_v2_t *r = (op_config_tx_reply_v2_t *) reply_payload;
150 if (reply_payload_space < sizeof(*r))
153 struct tune_result tune_result;
154 memset(&tune_result, 0, sizeof(tune_result));
158 if (p->valid & CFGV_GAIN){
159 ok &= db_set_gain(tx_dboard, p->gain);
162 if (p->valid & CFGV_FREQ){
163 bool was_streaming = is_streaming();
167 u2_fxpt_freq_t f = u2_fxpt_freq_from_hilo(p->freq_hi, p->freq_lo);
168 bool tune_ok = db_tune(tx_dboard, f, &tune_result);
170 print_tune_result("Tx", tune_ok, f, &tune_result);
176 if (p->valid & CFGV_INTERP_DECIM){
177 int interp = p->interp;
183 interp = interp >> 1;
188 interp = interp >> 1;
191 if (interp < MIN_CIC_INTERP || interp > MAX_CIC_INTERP)
194 dsp_tx_regs->interp_rate = (hb1<<9) | (hb2<<8) | interp;
195 // printf("Interp: %d, register %d\n", p->interp, (hb1<<9) | (hb2<<8) | interp);
199 if (p->valid & CFGV_SCALE_IQ){
200 dsp_tx_regs->scale_iq = p->scale_iq;
203 // Build reply subpacket
205 r->opcode = OP_CONFIG_TX_REPLY_V2;
209 r->inverted = tune_result.inverted;
210 r->baseband_freq_hi = u2_fxpt_freq_hi(tune_result.baseband_freq);
211 r->baseband_freq_lo = u2_fxpt_freq_lo(tune_result.baseband_freq);
212 r->duc_freq_hi = u2_fxpt_freq_hi(tune_result.dxc_freq);
213 r->duc_freq_lo = u2_fxpt_freq_lo(tune_result.dxc_freq);
214 r->residual_freq_hi = u2_fxpt_freq_hi(tune_result.residual_freq);
215 r->residual_freq_lo = u2_fxpt_freq_lo(tune_result.residual_freq);
220 config_rx_v2_cmd(const op_config_rx_v2_t *p,
221 void *reply_payload, size_t reply_payload_space)
223 op_config_rx_reply_v2_t *r = (op_config_rx_reply_v2_t *) reply_payload;
224 if (reply_payload_space < sizeof(*r))
227 struct tune_result tune_result;
228 memset(&tune_result, 0, sizeof(tune_result));
232 if (p->valid & CFGV_GAIN){
233 ok &= db_set_gain(rx_dboard, p->gain);
236 if (p->valid & CFGV_FREQ){
237 bool was_streaming = is_streaming();
241 u2_fxpt_freq_t f = u2_fxpt_freq_from_hilo(p->freq_hi, p->freq_lo);
242 bool tune_ok = db_tune(rx_dboard, f, &tune_result);
244 print_tune_result("Rx", tune_ok, f, &tune_result);
250 if (p->valid & CFGV_INTERP_DECIM){
251 int decim = p->decim;
265 if (decim < MIN_CIC_DECIM || decim > MAX_CIC_DECIM)
268 dsp_rx_regs->decim_rate = (hb1<<9) | (hb2<<8) | decim;
269 // printf("Decim: %d, register %d\n", p->decim, (hb1<<9) | (hb2<<8) | decim);
273 if (p->valid & CFGV_SCALE_IQ){
274 dsp_rx_regs->scale_iq = p->scale_iq;
277 // Build reply subpacket
279 r->opcode = OP_CONFIG_RX_REPLY_V2;
283 r->inverted = tune_result.inverted;
284 r->baseband_freq_hi = u2_fxpt_freq_hi(tune_result.baseband_freq);
285 r->baseband_freq_lo = u2_fxpt_freq_lo(tune_result.baseband_freq);
286 r->ddc_freq_hi = u2_fxpt_freq_hi(tune_result.dxc_freq);
287 r->ddc_freq_lo = u2_fxpt_freq_lo(tune_result.dxc_freq);
288 r->residual_freq_hi = u2_fxpt_freq_hi(tune_result.residual_freq);
289 r->residual_freq_lo = u2_fxpt_freq_lo(tune_result.residual_freq);
295 read_time_cmd(const op_generic_t *p,
296 void *reply_payload, size_t reply_payload_space)
298 op_read_time_reply_t *r = (op_read_time_reply_t *) reply_payload;
299 if (reply_payload_space < sizeof(*r))
302 r->opcode = OP_READ_TIME_REPLY;
305 r->time = timer_regs->time;
311 fill_db_info(u2_db_info_t *p, const struct db_base *db)
313 //p->dbid = db->dbid;
314 p->freq_min_hi = u2_fxpt_freq_hi(db->freq_min);
315 p->freq_min_lo = u2_fxpt_freq_lo(db->freq_min);
316 p->freq_max_hi = u2_fxpt_freq_hi(db->freq_max);
317 p->freq_max_lo = u2_fxpt_freq_lo(db->freq_max);
318 p->gain_min = db->gain_min;
319 p->gain_max = db->gain_max;
320 p->gain_step_size = db->gain_step_size;
324 dboard_info_cmd(const op_generic_t *p,
325 void *reply_payload, size_t reply_payload_space)
327 op_dboard_info_reply_t *r = (op_dboard_info_reply_t *) reply_payload;
328 if (reply_payload_space < sizeof(*r))
331 r->opcode = OP_DBOARD_INFO_REPLY;
336 fill_db_info(&r->tx_db_info, tx_dboard);
337 fill_db_info(&r->rx_db_info, rx_dboard);
339 r->tx_db_info.dbid = read_dboard_eeprom(I2C_ADDR_TX_A);
340 r->rx_db_info.dbid = read_dboard_eeprom(I2C_ADDR_RX_A);
346 peek_cmd(const op_peek_t *p,
347 void *reply_payload, size_t reply_payload_space)
349 op_generic_t *r = (op_generic_t *) reply_payload;
351 //putstr("peek: addr="); puthex32(p->addr);
352 //printf(" bytes=%u\n", p->bytes);
354 if ((reply_payload_space < (sizeof(*r) + p->bytes)) ||
355 p->bytes > MAX_SUBPKT_LEN - sizeof(op_generic_t)) {
356 putstr("peek: insufficient reply packet space\n");
357 return 0; // FIXME do partial read?
360 r->opcode = OP_PEEK_REPLY;
361 r->len = sizeof(*r)+p->bytes;
365 memcpy_wa(reply_payload+sizeof(*r), (void *)p->addr, p->bytes);
371 poke_cmd(const op_poke_t *p)
373 int bytes = p->len - sizeof(*p);
374 //putstr("poke: addr="); puthex32(p->addr);
375 //printf(" bytes=%u\n", bytes);
377 uint8_t *src = (uint8_t *)p + sizeof(*p);
378 memcpy_wa((void *)p->addr, src, bytes);
384 set_lo_offset_cmd(const op_freq_t *p)
386 u2_fxpt_freq_t f = u2_fxpt_freq_from_hilo(p->freq_hi, p->freq_lo);
387 if (p->opcode == OP_SET_TX_LO_OFFSET)
388 return db_set_lo_offset(tx_dboard, f);
390 return db_set_lo_offset(rx_dboard, f);
394 gpio_read_cmd(const op_gpio_t *p,
395 void *reply_payload, size_t reply_payload_space)
397 op_gpio_read_reply_t *r = (op_gpio_read_reply_t *) reply_payload;
398 if (reply_payload_space < sizeof(*r)) // no room
401 // Build reply subpacket
403 r->opcode = OP_GPIO_READ_REPLY;
404 r->len = sizeof(op_gpio_read_reply_t);
408 r->value = hal_gpio_read(p->bank);
414 generic_reply(const op_generic_t *p,
415 void *reply_payload, size_t reply_payload_space,
418 op_generic_t *r = (op_generic_t *) reply_payload;
419 if (reply_payload_space < sizeof(*r))
422 r->opcode = p->opcode | OP_REPLY_BIT;
431 add_eop(void *reply_payload, size_t reply_payload_space)
433 op_generic_t *r = (op_generic_t *) reply_payload;
434 if (reply_payload_space < sizeof(*r))
446 handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len)
448 unsigned char reply[sizeof(u2_eth_packet_t) + 4 * sizeof(u2_subpkt_t)] _AL4;
449 unsigned char *reply_payload = &reply[sizeof(u2_eth_packet_t)];
450 int reply_payload_space = sizeof(reply) - sizeof(u2_eth_packet_t);
453 memset(reply, 0, sizeof(reply));
454 set_reply_hdr((u2_eth_packet_t *) reply, pkt);
456 // point to beginning of payload (subpackets)
457 unsigned char *payload = ((unsigned char *) pkt) + sizeof(u2_eth_packet_t);
458 int payload_len = len - sizeof(u2_eth_packet_t);
460 size_t subpktlen = 0;
463 while (payload_len >= sizeof(op_generic_t)){
464 const op_generic_t *gp = (const op_generic_t *) payload;
467 // printf("\nopcode = %d\n", gp->opcode);
470 case OP_EOP: // end of subpackets
471 goto end_of_subpackets;
474 subpktlen = op_id_cmd(gp, reply_payload, reply_payload_space);
477 case OP_CONFIG_TX_V2:
478 subpktlen = config_tx_v2_cmd((op_config_tx_v2_t *) payload, reply_payload, reply_payload_space);
481 case OP_CONFIG_RX_V2:
482 subpktlen = config_rx_v2_cmd((op_config_rx_v2_t *) payload, reply_payload, reply_payload_space);
485 case OP_START_RX_STREAMING:
486 if (pkt->fixed.timestamp == -1) // Start now (default)
487 start_rx_streaming_cmd(&pkt->ehdr.src, (op_start_rx_streaming_t *) payload);
489 start_rx_streaming_at_cmd(&pkt->ehdr.src, (op_start_rx_streaming_t *)payload, pkt->fixed.timestamp);
498 case OP_BURN_MAC_ADDR:
499 ok = ethernet_set_mac_addr(&((op_burn_mac_addr_t *)payload)->addr);
503 ok = config_mimo_cmd((op_config_mimo_t *) payload);
507 subpktlen = read_time_cmd(gp, reply_payload, reply_payload_space);
511 subpktlen = dboard_info_cmd(gp, reply_payload, reply_payload_space);
515 sync_to_pps((op_generic_t *) payload);
520 subpktlen = peek_cmd((op_peek_t *)payload, reply_payload, reply_payload_space);
524 ok = poke_cmd((op_poke_t *)payload);
527 case OP_SET_TX_LO_OFFSET:
528 case OP_SET_RX_LO_OFFSET:
529 ok = set_lo_offset_cmd((op_freq_t *)payload);
537 case OP_SYNC_EVERY_PPS:
538 ok = sync_every_pps((op_generic_t *) payload);
541 case OP_GPIO_SET_DDR:
543 hal_gpio_set_ddr(((op_gpio_t *)payload)->bank,
544 ((op_gpio_t *)payload)->value,
545 ((op_gpio_t *)payload)->mask);
548 case OP_GPIO_SET_SELS:
550 hal_gpio_set_sels(((op_gpio_set_sels_t *)payload)->bank,
551 (char *)(&((op_gpio_set_sels_t *)payload)->sels));
555 subpktlen = gpio_read_cmd((op_gpio_t *) payload, reply_payload, reply_payload_space);
560 hal_gpio_write(((op_gpio_t *)payload)->bank,
561 ((op_gpio_t *)payload)->value,
562 ((op_gpio_t *)payload)->mask);
567 dsp_rx_regs->gpio_stream_enable = (uint32_t)((op_gpio_t *)payload)->value;
570 // Add new opcode handlers here
573 subpktlen = generic_reply(gp, reply_payload, reply_payload_space, ok);
577 printf("app_common_v2: unhandled opcode = %d\n", gp->opcode);
581 int t = (gp->len + 3) & ~3; // bump to a multiple of 4
585 subpktlen = (subpktlen + 3) & ~3; // bump to a multiple of 4
586 reply_payload += subpktlen;
587 reply_payload_space -= subpktlen;
592 // add the EOP marker
593 subpktlen = add_eop(reply_payload, reply_payload_space);
594 subpktlen = (subpktlen + 3) & ~3; // bump to a multiple of 4
595 reply_payload += subpktlen;
596 reply_payload_space -= subpktlen;
598 send_reply(reply, reply_payload - reply);
603 * Called when an ethernet packet is received.
604 * Return true if we handled it here, otherwise
605 * it'll be passed on to the DSP Tx pipe
608 eth_pkt_inspector(dbsm_t *sm, int bufno)
610 u2_eth_packet_t *pkt = (u2_eth_packet_t *) buffer_ram(bufno);
611 size_t byte_len = (buffer_pool_status->last_line[bufno] - 1) * 4;
613 //static size_t last_len = 0;
615 // hal_toggle_leds(0x1);
617 // inspect rcvd frame and figure out what do do.
619 if (pkt->ehdr.ethertype != U2_ETHERTYPE)
620 return true; // ignore, probably bogus PAUSE frame from MAC
622 int chan = u2p_chan(&pkt->fixed);
626 handle_control_chan_frame(pkt, byte_len);
627 return true; // we handled the packet
634 if (byte_len != last_len){
635 printf("Len: %d last: %d\n", byte_len, last_len);
640 if((pkt->thdr.seqno) == exp_seqno){
646 //printf("S%d %d ",exp_seqno,pkt->thdr.seqno);
647 exp_seqno = pkt->thdr.seqno + 1;
650 return false; // pass it on to Tx DSP
656 * Called when eth phy state changes (w/ interrupts disabled)
659 link_changed_callback(int speed)
661 link_is_up = speed != 0;
662 hal_set_leds(link_is_up ? LED_RJ45 : 0x0, LED_RJ45);
663 printf("\neth link changed: speed = %d\n", speed);
668 print_tune_result(char *msg, bool tune_ok,
669 u2_fxpt_freq_t target_freq, struct tune_result *r)
672 printf("db_tune %s %s\n", msg, tune_ok ? "true" : "false");
673 putstr(" target_freq "); print_fxpt_freq(target_freq); newline();
674 putstr(" baseband_freq "); print_fxpt_freq(r->baseband_freq); newline();
675 putstr(" dxc_freq "); print_fxpt_freq(r->dxc_freq); newline();
676 putstr(" residual_freq "); print_fxpt_freq(r->residual_freq); newline();
677 printf(" inverted %s\n", r->inverted ? "true" : "false");