diff options
author | Sylvain Munaut <tnt@246tNt.com> | 2011-04-23 23:00:24 +0200 |
---|---|---|
committer | Sylvain Munaut <tnt@246tNt.com> | 2011-05-29 19:51:54 +0200 |
commit | 4684c75a668c7d25a5f6ebf2224a92982fdb500b (patch) | |
tree | 7d255610fd6ba7b8a7bfea465785c126a730b5e9 /src/target/firmware/rf | |
parent | a78316c8315fc075e8253fd8678e6a7b5c8bf1d8 (diff) |
fw/trf6151: Better PLL settings routines
* We actually support TX 850/1900 now
* We try to find the better settings for a given frequency,
no matter if it's in spec or not ...
(for e.g. TXin in DCS downlink is better done with PCS config)
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
Diffstat (limited to 'src/target/firmware/rf')
-rw-r--r-- | src/target/firmware/rf/trf6151.c | 244 |
1 files changed, 155 insertions, 89 deletions
diff --git a/src/target/firmware/rf/trf6151.c b/src/target/firmware/rf/trf6151.c index 7391ef82..9191d0cd 100644 --- a/src/target/firmware/rf/trf6151.c +++ b/src/target/firmware/rf/trf6151.c @@ -92,6 +92,23 @@ enum trf6151_reg { #define TRF6151_RX_PLL_DELAY 184 /* 170 us */ #define TRF6151_TX_PLL_DELAY 260 /* 240 us */ + +enum trf6151_pwr_unit { + TRF1651_PACTLR_APC, + TRF6151_PACTRL_APCEN, + TRF6151_TRANSMITTER, + TRF6151_REGULATORS, +}; + +enum trf6151_gsm_band { + GSM900 = 1, + GSM1800 = 2, + GSM850_LOW = 4, + GSM850_HIGH = 5, + GSM1900 = 6, +}; + + uint16_t rf_arfcn = 871; /* TODO: this needs to be private */ static uint16_t rf_band; @@ -140,99 +157,155 @@ int trf6151_set_gain(uint8_t dbm, int high) #define SCALE_100KHZ 100 -/* Compute TRF6151 PLL valuese for all 4 RX bands */ -static uint16_t trf6151_pll_rx(uint32_t freq_khz) +/* Compute TRF6151 PLL valuese */ +static void trf6151_pll_rx(uint32_t freq_khz, + uint16_t *pll_config, enum trf6151_gsm_band *band) { - uint32_t freq_100khz = freq_khz / SCALE_100KHZ; /* Scale from *1000 (k) to *100000 (0.1M) */ - uint32_t fb_100khz; /* frequency of B alone, without A (units of 100kHz) */ - uint32_t l; - uint32_t a, b; /* The PLL multipliers we want to compute */ - - /* L = 4 for low band, 2 for high band */ - if (freq_khz < 1000000) - l = 4; - else - l = 2; + const uint32_t p=64, r=65; + uint32_t freq_100khz, vco_freq_100khz; + uint32_t l, n; + uint32_t a, b; - /* To compute B, we assume A is zero */ - b = (freq_100khz * 65 * l) / (64 * 26 * 10); + /* Scale into 100kHz unit (avoid overflow in intermediates) */ + freq_100khz = freq_khz / SCALE_100KHZ; - if ((l == 4 && (b < 135 || b > 150)) || - (l == 2 && (b < 141 || b > 155))) - printf("Frequency %u kHz is out of spec\n", freq_khz); + /* L selects hi/lo band */ + l = (freq_khz > 1350000) ? 2 : 4; /* cut at mid point :) */ - /* Compute PLL frequency assuming A == 0 */ - fb_100khz = (b * 64 * 26 * 10) / (65 * l); + /* VCO frequency */ + vco_freq_100khz = freq_100khz * l; - /* Compute how many 100kHz units A needs to add */ - a = freq_100khz - fb_100khz; + /* vco_freq = 26MHz / R * N with R=65 and N=B*P+A */ + n = (vco_freq_100khz * r) / 260; + a = n % p; + b = n / p; - if (l == 2) - a = a / 2; + *pll_config = PLL_VAL(a, b); - /* since all frequencies are expanded a factor of 10, we don't need to multiply A */ - printd("Freq %u kHz => A = %u, B = %u\n", freq_khz, a, b); + /* Out-of-spec tuning warning */ + if ((l == 4 && (b < 135 || b > 150)) || + (l == 2 && (b < 141 || b > 155))) + printf("Frequency %u kHz is out of spec\n", (unsigned int)freq_khz); + + /* Select band */ + if (l==4) { + /* If in the low band, same port for both GSM850/GSM900, so we + * choose the best VCO (VCOMAIN1=3.37GHz, VCOMAIN2=3.8GHz) */ + if (vco_freq_100khz < 35850) /* midpoint */ + *band = GSM850_LOW; + else + *band = GSM900; + + /* Out-of-spec freq check */ + if (!(freq_khz >= 869000 && freq_khz <= 894000) && + !(freq_khz >= 921000 && freq_khz <= 960000)) /* include GSM-R */ + printf("Frequency %u outside normal filter range for selected port\n", (unsigned int)freq_khz); + } else { + /* In the high band, different ports for DCS/PCS, so + * take what's best and available */ + /* We're stuck to VCOMAIN2=3.8GHz though ... */ + uint32_t rx_ports = rffe_get_rx_ports(); + uint32_t port; + + /* Select port */ + port = (freq_khz < 1905000) ? (1 << PORT_DCS1800) : (1 << PORT_PCS1900); + port = (port & rx_ports) ? port : rx_ports; + + /* Select band */ + *band = (port & (1 << PORT_DCS1800)) ? GSM1800 : GSM1900; + + /* Out-of-spec freq check */ + if ((*band == GSM1800 && (freq_khz < 1805000 || freq_khz > 1880000)) || + (*band == GSM1900 && (freq_khz < 1930000 || freq_khz > 1990000))) + printf("Frequency %u outside normal filter range for selected port\n", (unsigned int)freq_khz); + } + + /* Debug */ + printd("RX Freq %u kHz => A = %u, B = %u, band = %d, vco_freq = %u kHz\n", freq_khz, a, b, *band, vco_freq_100khz*100); - /* return value in trf6151 register layout form */ - return PLL_VAL(a, b); + /* All done */ + return; } -/* Compute TRF6151 PLL TX values for GSM900 and GSM1800 only! */ -static uint16_t trf6151_pll_tx(uint32_t freq_khz) +/* Compute TRF6151 PLL TX values */ +static void trf6151_pll_tx(uint32_t freq_khz, + uint16_t *pll_config, enum trf6151_gsm_band *band) { - uint32_t freq_100khz = freq_khz / SCALE_100KHZ; /* Scale from *1000 (k) to *100000 (0.1M) */ - uint32_t fb_100khz; /* frequency of B alone, without A (units of 100kHz) */ - uint32_t l, r, m; - uint32_t a, b; /* The PLL multipliers we want to compute */ - - /* L = 4 for low band, 2 for high band */ - if (freq_khz < 1000000) { - r = 35; - l = 4; - m = 52; - } else { + const uint32_t p=64; + uint32_t r, l, m, m_op_l; /* m_op_l = m +/- l depending on mode */ + uint32_t freq_100khz; + uint32_t n, a, b, b_min, b_max; + + /* Scale into 100kHz unit (avoid overflow in intermediates) */ + freq_100khz = freq_khz / SCALE_100KHZ; + + /* Select band (and PLL mode) */ + if (freq_khz > 1350000) { + /* High band, so only 1 real PLL mode. band doesn't matter + * that much (or at all) but we still do it :p */ + *band = (freq_khz < 1817500) ? GSM1800 : GSM1900; r = 70; l = 2; m = 26; + m_op_l = m + l; + b_min = 133; + b_max = 149; + } else { + /* Low band. We have 3 possible PLL modes that output on + * the right port: GSM900, GSM850_HIGH, GSM850_LOW. + * + * The transistion points have been chosen looking at the VCO + * and IF frequencies for various frequencies for theses modes + */ + if (freq_khz < 837100) { + /* GSM850_LOW */ + *band = GSM850_LOW; + r = 55; + l = 4; + m = 26; + m_op_l = m - l; + b_min = 128; + b_max = 130; + } else if (freq_khz < 850000) { + /* GSM850_HIGH */ + *band = GSM850_HIGH; + r = 30; + l = 4; + m = 52; + m_op_l = m - l; + b_min = 65; + b_max = 66; + } else { + /* GSM900 */ + *band = GSM900; + r = 35; + l = 4; + m = 52; + m_op_l = m + l; + b_min = 68; + b_max = 71; + } } - /* To compute B, we assume A is zero */ - b = (freq_100khz * r * l * m) / (64 * 26 * 10 * (m + l)); - - if ((l == 4 && (b < 68 || b > 71)) || - (l == 2 && (b < 133 || b > 149))) - printf("Frequency %u kHz is out of spec\n", freq_khz); - - /* Compute PLL frequency assuming A == 0 */ - fb_100khz = (b * 64 * 26 * 10 * (m + l)) / (r * l * m); + /* vco_freq = f * M * L / (M +- L) */ + /* = 26MHz / R * N with R=65 and N=B*P+A */ + n = (freq_100khz * m * l * r) / (m_op_l * 260); + a = n % p; + b = n / p; - /* Compute how many 100kHz units A needs to add */ - a = freq_100khz - fb_100khz; + *pll_config = PLL_VAL(a, b); - a = a / 2; + /* Debug */ + printd("TX Freq %u kHz => A = %u, B = %u, band = %d\n", freq_khz, a, b, *band); - /* since all frequencies are expanded a factor of 10, we don't need to multiply A */ - printd("Freq %u kHz => A = %u, B = %u\n", freq_khz, a, b); + /* Out-of-spec tuning warning */ + if (b < b_min || b > b_max) + printf("Frequency %u kHz is out of spec\n", (unsigned int)freq_khz); - /* return value in trf6151 register layout form */ - return PLL_VAL(a, b); + /* All done */ + return; } -enum trf6151_pwr_unit { - TRF1651_PACTLR_APC, - TRF6151_PACTRL_APCEN, - TRF6151_TRANSMITTER, - TRF6151_REGULATORS, -}; - -enum trf6151_gsm_band { - GSM900 = 1, - GSM1800 = 2, - GSM850_LOW = 4, - GSM850_HIGH = 5, - GSM1900 = 6, -}; - static inline void trf6151_reset(uint16_t reset_id) { /* pull the nRESET line low */ @@ -310,43 +383,36 @@ static void trf6151_band_select(enum trf6151_gsm_band band) void trf6151_set_arfcn(uint16_t arfcn, int uplink) { uint32_t freq_khz; + uint16_t pll_config; + enum trf6151_gsm_band pll_band; switch (gsm_arfcn2band(arfcn)) { case GSM_BAND_850: - rf_band = GSM850_LOW; /* FIXME: what about HIGH */ - break; case GSM_BAND_900: - rf_band = GSM900; - break; case GSM_BAND_1800: - rf_band = GSM1800; - break; case GSM_BAND_1900: - rf_band = GSM1900; + /* Supported */ break; case GSM_BAND_450: case GSM_BAND_480: case GSM_BAND_750: case GSM_BAND_810: - printf("Unsupported rf_band.\n"); + printf("Unsupported band ! YMMV.\n"); break; } - trf6151_band_select(rf_band); - freq_khz = gsm_arfcn2freq10(arfcn, uplink) * 100; printd("ARFCN %u -> %u kHz\n", arfcn, freq_khz); if (uplink == 0) - trf6151_reg_write(REG_PLL, trf6151_pll_rx(freq_khz)); - else { - if (rf_band != GSM900 && rf_band != GSM1800) { - printf("TX only supports GSM900/1800\n"); - return; - } - trf6151_reg_write(REG_PLL, trf6151_pll_tx(freq_khz)); - } + trf6151_pll_rx(freq_khz, &pll_config, &pll_band); + else + trf6151_pll_tx(freq_khz, &pll_config, &pll_band); + + trf6151_band_select(pll_band); + trf6151_reg_write(REG_PLL, pll_config); + rf_band = pll_band; rf_arfcn = arfcn; // TODO: arfcn is referenced at other places } |