/* * Copyright (c) 2015 Nuand LLC * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef BLADERF_NIOS_PKT_RETUNE_H_ #define BLADERF_NIOS_PKT_RETUNE_H_ #ifndef BLADERF_NIOS_BUILD # include #else # include "libbladeRF_nios_compat.h" #endif #include /* Specify this value instead of a timestamp to clear the retune queue */ #define NIOS_PKT_RETUNE_CLEAR_QUEUE ((uint64_t) -1) /* This file defines the Host <-> FPGA (NIOS II) packet formats for * retune messages. This packet is formatted, as follows. All values are * little-endian. * * Request * ---------------------- * * +================+=========================================================+ * | Byte offset | Description | * +================+=========================================================+ * | 0 | Magic Value | * +----------------+---------------------------------------------------------+ * | 1 | 64-bit timestamp denoting when to retune. (Note 1) | * +----------------+---------------------------------------------------------+ * | 9 | 32-bit LMS6002D n_int & n_frac register values (Note 2) | * +----------------+---------------------------------------------------------+ * | 13 | RX/TX bit, FREQSEL LMS6002D reg value (Note 3) | * +----------------+---------------------------------------------------------+ * | 14 | Bit 7: Band-selection (Note 4) | * | | Bit 6: 1=Quick tune, 0=Normal tune | * | | Bits [5:0] VCOCAP[5:0] Hint | * +----------------+---------------------------------------------------------+ * | 15 | 8-bit reserved word. Should be set to 0x00. | * +----------------+---------------------------------------------------------+ * * (Note 1) Special Timestamp Values: * * Tune "Now": 0x0000000000000000 * Clear Retune Queue: 0xffffffffffffffff * * When the "Clear Retune Queue" value is used, all of the other tuning * parameters are ignored. * * (Note 2) Packed as follows: * * +================+=======================+ * | Byte offset | (MSB) Value (LSB)| * +================+=======================+ * | 0 | NINT[8:1] | * +----------------+-----------------------+ * | 1 | NINT[0], NFRAC[22:16] | * +----------------+-----------------------+ * | 2 | NFRAC[15:8] | * +----------------+-----------------------+ * | 3 | NFRAC[7:0] | * +----------------+-----------------------+ * * (Note 3) Packed as follows: * * +================+=======================+ * | Bit(s) | Value | * +================+=======================+ * | 7 | TX | * +----------------+-----------------------+ * | 6 | RX | * +----------------+-----------------------+ * | [5:0] | FREQSEL | * +----------------+-----------------------+ * * (Notes 4) Band-selection bit = 1 implies "Low band". 0 = "High band" */ #define NIOS_PKT_RETUNE_IDX_MAGIC 0 #define NIOS_PKT_RETUNE_IDX_TIME 1 #define NIOS_PKT_RETUNE_IDX_INTFRAC 9 #define NIOS_PKT_RETUNE_IDX_FREQSEL 13 #define NIOS_PKT_RETUNE_IDX_BANDSEL 14 #define NIOS_PKT_RETUNE_IDX_RESV 15 #define NIOS_PKT_RETUNE_MAGIC 'T' #define FLAG_QUICK_TUNE (1 << 6) #define FLAG_RX (1 << 6) #define FLAG_TX (1 << 7) #define FLAG_LOW_BAND (1 << 7) /* Denotes no tune word is supplied. */ #define NIOS_PKT_RETUNE_NO_HINT 0xff /* Denotes that the retune should not be scheduled - it should occur "now" */ #define NIOS_PKT_RETUNE_NOW ((uint64_t) 0x00) #define PACK_TXRX_FREQSEL(module_, freqsel_) \ (freqsel_ & 0x3f) /* Pack the retune request buffer with the provided parameters */ static inline void nios_pkt_retune_pack(uint8_t *buf, bladerf_module module, uint64_t timestamp, uint16_t nint, uint32_t nfrac, uint8_t freqsel, uint8_t vcocap, bool low_band, uint8_t xb_gpio, bool quick_tune) { buf[NIOS_PKT_RETUNE_IDX_MAGIC] = NIOS_PKT_RETUNE_MAGIC; buf[NIOS_PKT_RETUNE_IDX_TIME + 0] = timestamp & 0xff; buf[NIOS_PKT_RETUNE_IDX_TIME + 1] = (timestamp >> 8) & 0xff; buf[NIOS_PKT_RETUNE_IDX_TIME + 2] = (timestamp >> 16) & 0xff; buf[NIOS_PKT_RETUNE_IDX_TIME + 3] = (timestamp >> 24) & 0xff; buf[NIOS_PKT_RETUNE_IDX_TIME + 4] = (timestamp >> 32) & 0xff; buf[NIOS_PKT_RETUNE_IDX_TIME + 5] = (timestamp >> 40) & 0xff; buf[NIOS_PKT_RETUNE_IDX_TIME + 6] = (timestamp >> 48) & 0xff; buf[NIOS_PKT_RETUNE_IDX_TIME + 7] = (timestamp >> 56) & 0xff; buf[NIOS_PKT_RETUNE_IDX_INTFRAC + 0] = (nint >> 1) & 0xff; buf[NIOS_PKT_RETUNE_IDX_INTFRAC + 1] = (nint & 0x1) << 7; buf[NIOS_PKT_RETUNE_IDX_INTFRAC + 1] |= ((nfrac >> 16) & 0x7f); buf[NIOS_PKT_RETUNE_IDX_INTFRAC + 2] = (nfrac >> 8) & 0xff; buf[NIOS_PKT_RETUNE_IDX_INTFRAC + 3] = nfrac & 0xff; buf[NIOS_PKT_RETUNE_IDX_FREQSEL] = freqsel & 0xff; switch (module) { case BLADERF_MODULE_TX: buf[NIOS_PKT_RETUNE_IDX_FREQSEL] |= FLAG_TX; break; case BLADERF_MODULE_RX: buf[NIOS_PKT_RETUNE_IDX_FREQSEL] |= FLAG_RX; break; default: /* Erroneous case - should not occur */ break; } if (low_band) { buf[NIOS_PKT_RETUNE_IDX_BANDSEL] = FLAG_LOW_BAND; } else { buf[NIOS_PKT_RETUNE_IDX_BANDSEL] = 0x00; } if (quick_tune) { buf[NIOS_PKT_RETUNE_IDX_BANDSEL] |= FLAG_QUICK_TUNE; } buf[NIOS_PKT_RETUNE_IDX_BANDSEL] |= vcocap; buf[NIOS_PKT_RETUNE_IDX_RESV] = xb_gpio; } /* Unpack a retune request */ static inline void nios_pkt_retune_unpack(const uint8_t *buf, bladerf_module *module, uint64_t *timestamp, uint16_t *nint, uint32_t *nfrac, uint8_t *freqsel, uint8_t *vcocap, bool *low_band, uint8_t *xb_gpio, bool *quick_tune) { *timestamp = ( ((uint64_t) buf[NIOS_PKT_RETUNE_IDX_TIME + 0]) << 0); *timestamp |= ( ((uint64_t) buf[NIOS_PKT_RETUNE_IDX_TIME + 1]) << 8); *timestamp |= ( ((uint64_t) buf[NIOS_PKT_RETUNE_IDX_TIME + 2]) << 16); *timestamp |= ( ((uint64_t) buf[NIOS_PKT_RETUNE_IDX_TIME + 3]) << 24); *timestamp |= ( ((uint64_t) buf[NIOS_PKT_RETUNE_IDX_TIME + 4]) << 32); *timestamp |= ( ((uint64_t) buf[NIOS_PKT_RETUNE_IDX_TIME + 5]) << 40); *timestamp |= ( ((uint64_t) buf[NIOS_PKT_RETUNE_IDX_TIME + 6]) << 48); *timestamp |= ( ((uint64_t) buf[NIOS_PKT_RETUNE_IDX_TIME + 7]) << 56); *nint = buf[NIOS_PKT_RETUNE_IDX_INTFRAC + 0] << 1; *nint |= buf[NIOS_PKT_RETUNE_IDX_INTFRAC + 1] >> 7; *nfrac = (buf[NIOS_PKT_RETUNE_IDX_INTFRAC + 1] & 0x7f) << 16; *nfrac |= buf[NIOS_PKT_RETUNE_IDX_INTFRAC + 2] << 8; *nfrac |= buf[NIOS_PKT_RETUNE_IDX_INTFRAC + 3]; *freqsel = buf[NIOS_PKT_RETUNE_IDX_FREQSEL] & 0x3f; *module = -1; if (buf[NIOS_PKT_RETUNE_IDX_FREQSEL] & FLAG_TX) { *module = BLADERF_MODULE_TX; } else if (buf[NIOS_PKT_RETUNE_IDX_FREQSEL] & FLAG_RX) { *module = BLADERF_MODULE_RX; } *low_band = (buf[NIOS_PKT_RETUNE_IDX_BANDSEL] & FLAG_LOW_BAND) != 0; *quick_tune = (buf[NIOS_PKT_RETUNE_IDX_BANDSEL] & FLAG_QUICK_TUNE) != 0; *vcocap = buf[NIOS_PKT_RETUNE_IDX_BANDSEL] & 0x3f; *xb_gpio = buf[NIOS_PKT_RETUNE_IDX_RESV]; } /* * Response * ---------------------- * * +================+=========================================================+ * | Byte offset | Description | * +================+=========================================================+ * | 0 | Magic Value | * +----------------+---------------------------------------------------------+ * | 1 | 64-bit duration denoting how long the operation took to | * | | complete, in units of timestamp ticks. (Note 1) | * +----------------+---------------------------------------------------------+ * | 9 | Bits [7:6] Reserved, set to 0. | * | | Bits [5:0] VCOCAP value used. (Note 2) | * +----------------+---------------------------------------------------------+ * | 10 | Status Flags (Note 3) | * +----------------+---------------------------------------------------------+ * | 11-15 | Reserved. All bits set to 0. | * +----------------+---------------------------------------------------------+ * * (Note 1) This value will be zero if timestamps are not running for the * associated module. * * (Note 2) This field's value should be ignored when reading a response for * a request to clear the retune queue. * * (Note 3) Description of Status Flags: * * flags[0]: 1 = Timestamp and VCOCAP are valid. This is only the case for * "Tune NOW" requests. It is not possible to return this * information for scheduled retunes, as the event generally * does not occur before the response is set. * * 0 = This was a scheduled retune. Timestamp and VCOCAP Fields * should be ignored. * * * flags[1]: 1 = Operation completed successfully. * 0 = Operation failed. * * For "Tune NOW" requests, a failure may occur as the result * of the tuning algorithm failing to occur, and such other * unexpected failurs. * * The scheduled tune request will failure if the retune queue * is full. * * flags[7:2] Reserved. Set to 0. */ #define NIOS_PKT_RETUNERESP_IDX_MAGIC 0 #define NIOS_PKT_RETUNERESP_IDX_TIME 1 #define NIOS_PKT_RETUNERESP_IDX_VCOCAP 9 #define NIOS_PKT_RETUNERESP_IDX_FLAGS 10 #define NIOS_PKT_RETUNERESP_IDX_RESV 11 #define NIOS_PKT_RETUNERESP_FLAG_TSVTUNE_VALID (1 << 0) #define NIOS_PKT_RETUNERESP_FLAG_SUCCESS (1 << 1) static inline void nios_pkt_retune_resp_pack(uint8_t *buf, uint64_t duration, uint8_t vcocap, uint8_t flags) { buf[NIOS_PKT_RETUNERESP_IDX_MAGIC] = NIOS_PKT_RETUNE_MAGIC; buf[NIOS_PKT_RETUNERESP_IDX_TIME + 0] = duration & 0xff; buf[NIOS_PKT_RETUNERESP_IDX_TIME + 1] = (duration >> 8) & 0xff; buf[NIOS_PKT_RETUNERESP_IDX_TIME + 2] = (duration >> 16) & 0xff; buf[NIOS_PKT_RETUNERESP_IDX_TIME + 3] = (duration >> 24) & 0xff; buf[NIOS_PKT_RETUNERESP_IDX_TIME + 4] = (duration >> 32) & 0xff; buf[NIOS_PKT_RETUNERESP_IDX_TIME + 5] = (duration >> 40) & 0xff; buf[NIOS_PKT_RETUNERESP_IDX_TIME + 6] = (duration >> 48) & 0xff; buf[NIOS_PKT_RETUNERESP_IDX_TIME + 7] = (duration >> 56) & 0xff; buf[NIOS_PKT_RETUNERESP_IDX_VCOCAP] = vcocap; buf[NIOS_PKT_RETUNERESP_IDX_FLAGS] = flags; buf[NIOS_PKT_RETUNERESP_IDX_RESV + 0] = 0x00; buf[NIOS_PKT_RETUNERESP_IDX_RESV + 1] = 0x00; buf[NIOS_PKT_RETUNERESP_IDX_RESV + 2] = 0x00; buf[NIOS_PKT_RETUNERESP_IDX_RESV + 3] = 0x00; buf[NIOS_PKT_RETUNERESP_IDX_RESV + 4] = 0x00; } static inline void nios_pkt_retune_resp_unpack(const uint8_t *buf, uint64_t *duration, uint8_t *vcocap, uint8_t *flags) { *duration = buf[NIOS_PKT_RETUNERESP_IDX_TIME + 0]; *duration |= ((uint64_t) buf[NIOS_PKT_RETUNERESP_IDX_TIME + 1]) << 8; *duration |= ((uint64_t) buf[NIOS_PKT_RETUNERESP_IDX_TIME + 2]) << 16; *duration |= ((uint64_t) buf[NIOS_PKT_RETUNERESP_IDX_TIME + 3]) << 24; *duration |= ((uint64_t) buf[NIOS_PKT_RETUNERESP_IDX_TIME + 4]) << 32; *duration |= ((uint64_t) buf[NIOS_PKT_RETUNERESP_IDX_TIME + 5]) << 40; *duration |= ((uint64_t) buf[NIOS_PKT_RETUNERESP_IDX_TIME + 6]) << 48; *duration |= ((uint64_t) buf[NIOS_PKT_RETUNERESP_IDX_TIME + 7]) << 56; *vcocap = buf[NIOS_PKT_RETUNERESP_IDX_VCOCAP]; *flags = buf[NIOS_PKT_RETUNERESP_IDX_FLAGS]; } #endif