X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=kernel%2Fdrivers%2Fmedia%2Fdvb-frontends%2Fstv0900_sw.c;fp=kernel%2Fdrivers%2Fmedia%2Fdvb-frontends%2Fstv0900_sw.c;h=a0a7b1664c5339f36e97a296230dced6c4500dfb;hb=9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00;hp=0000000000000000000000000000000000000000;hpb=98260f3884f4a202f9ca5eabed40b1354c489b29;p=kvmfornfv.git diff --git a/kernel/drivers/media/dvb-frontends/stv0900_sw.c b/kernel/drivers/media/dvb-frontends/stv0900_sw.c new file mode 100644 index 000000000..a0a7b1664 --- /dev/null +++ b/kernel/drivers/media/dvb-frontends/stv0900_sw.c @@ -0,0 +1,2030 @@ +/* + * stv0900_sw.c + * + * Driver for ST STV0900 satellite demodulator IC. + * + * Copyright (C) ST Microelectronics. + * Copyright (C) 2009 NetUP Inc. + * Copyright (C) 2009 Igor M. Liplianin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "stv0900.h" +#include "stv0900_reg.h" +#include "stv0900_priv.h" + +s32 shiftx(s32 x, int demod, s32 shift) +{ + if (demod == 1) + return x - shift; + + return x; +} + +int stv0900_check_signal_presence(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod) +{ + s32 carr_offset, + agc2_integr, + max_carrier; + + int no_signal = FALSE; + + carr_offset = (stv0900_read_reg(intp, CFR2) << 8) + | stv0900_read_reg(intp, CFR1); + carr_offset = ge2comp(carr_offset, 16); + agc2_integr = (stv0900_read_reg(intp, AGC2I1) << 8) + | stv0900_read_reg(intp, AGC2I0); + max_carrier = intp->srch_range[demod] / 1000; + + max_carrier += (max_carrier / 10); + max_carrier = 65536 * (max_carrier / 2); + max_carrier /= intp->mclk / 1000; + if (max_carrier > 0x4000) + max_carrier = 0x4000; + + if ((agc2_integr > 0x2000) + || (carr_offset > (2 * max_carrier)) + || (carr_offset < (-2 * max_carrier))) + no_signal = TRUE; + + return no_signal; +} + +static void stv0900_get_sw_loop_params(struct stv0900_internal *intp, + s32 *frequency_inc, s32 *sw_timeout, + s32 *steps, + enum fe_stv0900_demod_num demod) +{ + s32 timeout, freq_inc, max_steps, srate, max_carrier; + + enum fe_stv0900_search_standard standard; + + srate = intp->symbol_rate[demod]; + max_carrier = intp->srch_range[demod] / 1000; + max_carrier += max_carrier / 10; + standard = intp->srch_standard[demod]; + + max_carrier = 65536 * (max_carrier / 2); + max_carrier /= intp->mclk / 1000; + + if (max_carrier > 0x4000) + max_carrier = 0x4000; + + freq_inc = srate; + freq_inc /= intp->mclk >> 10; + freq_inc = freq_inc << 6; + + switch (standard) { + case STV0900_SEARCH_DVBS1: + case STV0900_SEARCH_DSS: + freq_inc *= 3; + timeout = 20; + break; + case STV0900_SEARCH_DVBS2: + freq_inc *= 4; + timeout = 25; + break; + case STV0900_AUTO_SEARCH: + default: + freq_inc *= 3; + timeout = 25; + break; + } + + freq_inc /= 100; + + if ((freq_inc > max_carrier) || (freq_inc < 0)) + freq_inc = max_carrier / 2; + + timeout *= 27500; + + if (srate > 0) + timeout /= srate / 1000; + + if ((timeout > 100) || (timeout < 0)) + timeout = 100; + + max_steps = (max_carrier / freq_inc) + 1; + + if ((max_steps > 100) || (max_steps < 0)) { + max_steps = 100; + freq_inc = max_carrier / max_steps; + } + + *frequency_inc = freq_inc; + *sw_timeout = timeout; + *steps = max_steps; + +} + +static int stv0900_search_carr_sw_loop(struct stv0900_internal *intp, + s32 FreqIncr, s32 Timeout, int zigzag, + s32 MaxStep, enum fe_stv0900_demod_num demod) +{ + int no_signal, + lock = FALSE; + s32 stepCpt, + freqOffset, + max_carrier; + + max_carrier = intp->srch_range[demod] / 1000; + max_carrier += (max_carrier / 10); + + max_carrier = 65536 * (max_carrier / 2); + max_carrier /= intp->mclk / 1000; + + if (max_carrier > 0x4000) + max_carrier = 0x4000; + + if (zigzag == TRUE) + freqOffset = 0; + else + freqOffset = -max_carrier + FreqIncr; + + stepCpt = 0; + + do { + stv0900_write_reg(intp, DMDISTATE, 0x1c); + stv0900_write_reg(intp, CFRINIT1, (freqOffset / 256) & 0xff); + stv0900_write_reg(intp, CFRINIT0, freqOffset & 0xff); + stv0900_write_reg(intp, DMDISTATE, 0x18); + stv0900_write_bits(intp, ALGOSWRST, 1); + + if (intp->chip_id == 0x12) { + stv0900_write_bits(intp, RST_HWARE, 1); + stv0900_write_bits(intp, RST_HWARE, 0); + } + + if (zigzag == TRUE) { + if (freqOffset >= 0) + freqOffset = -freqOffset - 2 * FreqIncr; + else + freqOffset = -freqOffset; + } else + freqOffset += + 2 * FreqIncr; + + stepCpt++; + lock = stv0900_get_demod_lock(intp, demod, Timeout); + no_signal = stv0900_check_signal_presence(intp, demod); + + } while ((lock == FALSE) + && (no_signal == FALSE) + && ((freqOffset - FreqIncr) < max_carrier) + && ((freqOffset + FreqIncr) > -max_carrier) + && (stepCpt < MaxStep)); + + stv0900_write_bits(intp, ALGOSWRST, 0); + + return lock; +} + +static int stv0900_sw_algo(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod) +{ + int lock = FALSE, + no_signal, + zigzag; + s32 s2fw, + fqc_inc, + sft_stp_tout, + trial_cntr, + max_steps; + + stv0900_get_sw_loop_params(intp, &fqc_inc, &sft_stp_tout, + &max_steps, demod); + switch (intp->srch_standard[demod]) { + case STV0900_SEARCH_DVBS1: + case STV0900_SEARCH_DSS: + if (intp->chip_id >= 0x20) + stv0900_write_reg(intp, CARFREQ, 0x3b); + else + stv0900_write_reg(intp, CARFREQ, 0xef); + + stv0900_write_reg(intp, DMDCFGMD, 0x49); + zigzag = FALSE; + break; + case STV0900_SEARCH_DVBS2: + if (intp->chip_id >= 0x20) + stv0900_write_reg(intp, CORRELABS, 0x79); + else + stv0900_write_reg(intp, CORRELABS, 0x68); + + stv0900_write_reg(intp, DMDCFGMD, 0x89); + + zigzag = TRUE; + break; + case STV0900_AUTO_SEARCH: + default: + if (intp->chip_id >= 0x20) { + stv0900_write_reg(intp, CARFREQ, 0x3b); + stv0900_write_reg(intp, CORRELABS, 0x79); + } else { + stv0900_write_reg(intp, CARFREQ, 0xef); + stv0900_write_reg(intp, CORRELABS, 0x68); + } + + stv0900_write_reg(intp, DMDCFGMD, 0xc9); + zigzag = FALSE; + break; + } + + trial_cntr = 0; + do { + lock = stv0900_search_carr_sw_loop(intp, + fqc_inc, + sft_stp_tout, + zigzag, + max_steps, + demod); + no_signal = stv0900_check_signal_presence(intp, demod); + trial_cntr++; + if ((lock == TRUE) + || (no_signal == TRUE) + || (trial_cntr == 2)) { + + if (intp->chip_id >= 0x20) { + stv0900_write_reg(intp, CARFREQ, 0x49); + stv0900_write_reg(intp, CORRELABS, 0x9e); + } else { + stv0900_write_reg(intp, CARFREQ, 0xed); + stv0900_write_reg(intp, CORRELABS, 0x88); + } + + if ((stv0900_get_bits(intp, HEADER_MODE) == + STV0900_DVBS2_FOUND) && + (lock == TRUE)) { + msleep(sft_stp_tout); + s2fw = stv0900_get_bits(intp, FLYWHEEL_CPT); + + if (s2fw < 0xd) { + msleep(sft_stp_tout); + s2fw = stv0900_get_bits(intp, + FLYWHEEL_CPT); + } + + if (s2fw < 0xd) { + lock = FALSE; + + if (trial_cntr < 2) { + if (intp->chip_id >= 0x20) + stv0900_write_reg(intp, + CORRELABS, + 0x79); + else + stv0900_write_reg(intp, + CORRELABS, + 0x68); + + stv0900_write_reg(intp, + DMDCFGMD, + 0x89); + } + } + } + } + + } while ((lock == FALSE) + && (trial_cntr < 2) + && (no_signal == FALSE)); + + return lock; +} + +static u32 stv0900_get_symbol_rate(struct stv0900_internal *intp, + u32 mclk, + enum fe_stv0900_demod_num demod) +{ + s32 rem1, rem2, intval1, intval2, srate; + + srate = (stv0900_get_bits(intp, SYMB_FREQ3) << 24) + + (stv0900_get_bits(intp, SYMB_FREQ2) << 16) + + (stv0900_get_bits(intp, SYMB_FREQ1) << 8) + + (stv0900_get_bits(intp, SYMB_FREQ0)); + dprintk("lock: srate=%d r0=0x%x r1=0x%x r2=0x%x r3=0x%x \n", + srate, stv0900_get_bits(intp, SYMB_FREQ0), + stv0900_get_bits(intp, SYMB_FREQ1), + stv0900_get_bits(intp, SYMB_FREQ2), + stv0900_get_bits(intp, SYMB_FREQ3)); + + intval1 = (mclk) >> 16; + intval2 = (srate) >> 16; + + rem1 = (mclk) % 0x10000; + rem2 = (srate) % 0x10000; + srate = (intval1 * intval2) + + ((intval1 * rem2) >> 16) + + ((intval2 * rem1) >> 16); + + return srate; +} + +static void stv0900_set_symbol_rate(struct stv0900_internal *intp, + u32 mclk, u32 srate, + enum fe_stv0900_demod_num demod) +{ + u32 symb; + + dprintk("%s: Mclk %d, SR %d, Dmd %d\n", __func__, mclk, + srate, demod); + + if (srate > 60000000) { + symb = srate << 4; + symb /= (mclk >> 12); + } else if (srate > 6000000) { + symb = srate << 6; + symb /= (mclk >> 10); + } else { + symb = srate << 9; + symb /= (mclk >> 7); + } + + stv0900_write_reg(intp, SFRINIT1, (symb >> 8) & 0x7f); + stv0900_write_reg(intp, SFRINIT1 + 1, (symb & 0xff)); +} + +static void stv0900_set_max_symbol_rate(struct stv0900_internal *intp, + u32 mclk, u32 srate, + enum fe_stv0900_demod_num demod) +{ + u32 symb; + + srate = 105 * (srate / 100); + + if (srate > 60000000) { + symb = srate << 4; + symb /= (mclk >> 12); + } else if (srate > 6000000) { + symb = srate << 6; + symb /= (mclk >> 10); + } else { + symb = srate << 9; + symb /= (mclk >> 7); + } + + if (symb < 0x7fff) { + stv0900_write_reg(intp, SFRUP1, (symb >> 8) & 0x7f); + stv0900_write_reg(intp, SFRUP1 + 1, (symb & 0xff)); + } else { + stv0900_write_reg(intp, SFRUP1, 0x7f); + stv0900_write_reg(intp, SFRUP1 + 1, 0xff); + } +} + +static void stv0900_set_min_symbol_rate(struct stv0900_internal *intp, + u32 mclk, u32 srate, + enum fe_stv0900_demod_num demod) +{ + u32 symb; + + srate = 95 * (srate / 100); + if (srate > 60000000) { + symb = srate << 4; + symb /= (mclk >> 12); + + } else if (srate > 6000000) { + symb = srate << 6; + symb /= (mclk >> 10); + + } else { + symb = srate << 9; + symb /= (mclk >> 7); + } + + stv0900_write_reg(intp, SFRLOW1, (symb >> 8) & 0xff); + stv0900_write_reg(intp, SFRLOW1 + 1, (symb & 0xff)); +} + +static s32 stv0900_get_timing_offst(struct stv0900_internal *intp, + u32 srate, + enum fe_stv0900_demod_num demod) +{ + s32 timingoffset; + + + timingoffset = (stv0900_read_reg(intp, TMGREG2) << 16) + + (stv0900_read_reg(intp, TMGREG2 + 1) << 8) + + (stv0900_read_reg(intp, TMGREG2 + 2)); + + timingoffset = ge2comp(timingoffset, 24); + + + if (timingoffset == 0) + timingoffset = 1; + + timingoffset = ((s32)srate * 10) / ((s32)0x1000000 / timingoffset); + timingoffset /= 320; + + return timingoffset; +} + +static void stv0900_set_dvbs2_rolloff(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod) +{ + s32 rolloff; + + if (intp->chip_id == 0x10) { + stv0900_write_bits(intp, MANUALSX_ROLLOFF, 1); + rolloff = stv0900_read_reg(intp, MATSTR1) & 0x03; + stv0900_write_bits(intp, ROLLOFF_CONTROL, rolloff); + } else if (intp->chip_id <= 0x20) + stv0900_write_bits(intp, MANUALSX_ROLLOFF, 0); + else /* cut 3.0 */ + stv0900_write_bits(intp, MANUALS2_ROLLOFF, 0); +} + +static u32 stv0900_carrier_width(u32 srate, enum fe_stv0900_rolloff ro) +{ + u32 rolloff; + + switch (ro) { + case STV0900_20: + rolloff = 20; + break; + case STV0900_25: + rolloff = 25; + break; + case STV0900_35: + default: + rolloff = 35; + break; + } + + return srate + (srate * rolloff) / 100; +} + +static int stv0900_check_timing_lock(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod) +{ + int timingLock = FALSE; + s32 i, + timingcpt = 0; + u8 car_freq, + tmg_th_high, + tmg_th_low; + + car_freq = stv0900_read_reg(intp, CARFREQ); + tmg_th_high = stv0900_read_reg(intp, TMGTHRISE); + tmg_th_low = stv0900_read_reg(intp, TMGTHFALL); + stv0900_write_reg(intp, TMGTHRISE, 0x20); + stv0900_write_reg(intp, TMGTHFALL, 0x0); + stv0900_write_bits(intp, CFR_AUTOSCAN, 0); + stv0900_write_reg(intp, RTC, 0x80); + stv0900_write_reg(intp, RTCS2, 0x40); + stv0900_write_reg(intp, CARFREQ, 0x0); + stv0900_write_reg(intp, CFRINIT1, 0x0); + stv0900_write_reg(intp, CFRINIT0, 0x0); + stv0900_write_reg(intp, AGC2REF, 0x65); + stv0900_write_reg(intp, DMDISTATE, 0x18); + msleep(7); + + for (i = 0; i < 10; i++) { + if (stv0900_get_bits(intp, TMGLOCK_QUALITY) >= 2) + timingcpt++; + + msleep(1); + } + + if (timingcpt >= 3) + timingLock = TRUE; + + stv0900_write_reg(intp, AGC2REF, 0x38); + stv0900_write_reg(intp, RTC, 0x88); + stv0900_write_reg(intp, RTCS2, 0x68); + stv0900_write_reg(intp, CARFREQ, car_freq); + stv0900_write_reg(intp, TMGTHRISE, tmg_th_high); + stv0900_write_reg(intp, TMGTHFALL, tmg_th_low); + + return timingLock; +} + +static int stv0900_get_demod_cold_lock(struct dvb_frontend *fe, + s32 demod_timeout) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + int lock = FALSE, + d = demod; + s32 srate, + search_range, + locktimeout, + currier_step, + nb_steps, + current_step, + direction, + tuner_freq, + timeout, + freq; + + srate = intp->symbol_rate[d]; + search_range = intp->srch_range[d]; + + if (srate >= 10000000) + locktimeout = demod_timeout / 3; + else + locktimeout = demod_timeout / 2; + + lock = stv0900_get_demod_lock(intp, d, locktimeout); + + if (lock != FALSE) + return lock; + + if (srate >= 10000000) { + if (stv0900_check_timing_lock(intp, d) == TRUE) { + stv0900_write_reg(intp, DMDISTATE, 0x1f); + stv0900_write_reg(intp, DMDISTATE, 0x15); + lock = stv0900_get_demod_lock(intp, d, demod_timeout); + } else + lock = FALSE; + + return lock; + } + + if (intp->chip_id <= 0x20) { + if (srate <= 1000000) + currier_step = 500; + else if (srate <= 4000000) + currier_step = 1000; + else if (srate <= 7000000) + currier_step = 2000; + else if (srate <= 10000000) + currier_step = 3000; + else + currier_step = 5000; + + if (srate >= 2000000) { + timeout = (demod_timeout / 3); + if (timeout > 1000) + timeout = 1000; + } else + timeout = (demod_timeout / 2); + } else { + /*cut 3.0 */ + currier_step = srate / 4000; + timeout = (demod_timeout * 3) / 4; + } + + nb_steps = ((search_range / 1000) / currier_step); + + if ((nb_steps % 2) != 0) + nb_steps += 1; + + if (nb_steps <= 0) + nb_steps = 2; + else if (nb_steps > 12) + nb_steps = 12; + + current_step = 1; + direction = 1; + + if (intp->chip_id <= 0x20) { + tuner_freq = intp->freq[d]; + intp->bw[d] = stv0900_carrier_width(intp->symbol_rate[d], + intp->rolloff) + intp->symbol_rate[d]; + } else + tuner_freq = 0; + + while ((current_step <= nb_steps) && (lock == FALSE)) { + if (direction > 0) + tuner_freq += (current_step * currier_step); + else + tuner_freq -= (current_step * currier_step); + + if (intp->chip_id <= 0x20) { + if (intp->tuner_type[d] == 3) + stv0900_set_tuner_auto(intp, tuner_freq, + intp->bw[d], demod); + else + stv0900_set_tuner(fe, tuner_freq, intp->bw[d]); + + stv0900_write_reg(intp, DMDISTATE, 0x1c); + stv0900_write_reg(intp, CFRINIT1, 0); + stv0900_write_reg(intp, CFRINIT0, 0); + stv0900_write_reg(intp, DMDISTATE, 0x1f); + stv0900_write_reg(intp, DMDISTATE, 0x15); + } else { + stv0900_write_reg(intp, DMDISTATE, 0x1c); + freq = (tuner_freq * 65536) / (intp->mclk / 1000); + stv0900_write_bits(intp, CFR_INIT1, MSB(freq)); + stv0900_write_bits(intp, CFR_INIT0, LSB(freq)); + stv0900_write_reg(intp, DMDISTATE, 0x1f); + stv0900_write_reg(intp, DMDISTATE, 0x05); + } + + lock = stv0900_get_demod_lock(intp, d, timeout); + direction *= -1; + current_step++; + } + + return lock; +} + +static void stv0900_get_lock_timeout(s32 *demod_timeout, s32 *fec_timeout, + s32 srate, + enum fe_stv0900_search_algo algo) +{ + switch (algo) { + case STV0900_BLIND_SEARCH: + if (srate <= 1500000) { + (*demod_timeout) = 1500; + (*fec_timeout) = 400; + } else if (srate <= 5000000) { + (*demod_timeout) = 1000; + (*fec_timeout) = 300; + } else { + (*demod_timeout) = 700; + (*fec_timeout) = 100; + } + + break; + case STV0900_COLD_START: + case STV0900_WARM_START: + default: + if (srate <= 1000000) { + (*demod_timeout) = 3000; + (*fec_timeout) = 1700; + } else if (srate <= 2000000) { + (*demod_timeout) = 2500; + (*fec_timeout) = 1100; + } else if (srate <= 5000000) { + (*demod_timeout) = 1000; + (*fec_timeout) = 550; + } else if (srate <= 10000000) { + (*demod_timeout) = 700; + (*fec_timeout) = 250; + } else if (srate <= 20000000) { + (*demod_timeout) = 400; + (*fec_timeout) = 130; + } else { + (*demod_timeout) = 300; + (*fec_timeout) = 100; + } + + break; + + } + + if (algo == STV0900_WARM_START) + (*demod_timeout) /= 2; +} + +static void stv0900_set_viterbi_tracq(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod) +{ + + s32 vth_reg = VTH12; + + dprintk("%s\n", __func__); + + stv0900_write_reg(intp, vth_reg++, 0xd0); + stv0900_write_reg(intp, vth_reg++, 0x7d); + stv0900_write_reg(intp, vth_reg++, 0x53); + stv0900_write_reg(intp, vth_reg++, 0x2f); + stv0900_write_reg(intp, vth_reg++, 0x24); + stv0900_write_reg(intp, vth_reg++, 0x1f); +} + +static void stv0900_set_viterbi_standard(struct stv0900_internal *intp, + enum fe_stv0900_search_standard standard, + enum fe_stv0900_fec fec, + enum fe_stv0900_demod_num demod) +{ + dprintk("%s: ViterbiStandard = ", __func__); + + switch (standard) { + case STV0900_AUTO_SEARCH: + dprintk("Auto\n"); + stv0900_write_reg(intp, FECM, 0x10); + stv0900_write_reg(intp, PRVIT, 0x3f); + break; + case STV0900_SEARCH_DVBS1: + dprintk("DVBS1\n"); + stv0900_write_reg(intp, FECM, 0x00); + switch (fec) { + case STV0900_FEC_UNKNOWN: + default: + stv0900_write_reg(intp, PRVIT, 0x2f); + break; + case STV0900_FEC_1_2: + stv0900_write_reg(intp, PRVIT, 0x01); + break; + case STV0900_FEC_2_3: + stv0900_write_reg(intp, PRVIT, 0x02); + break; + case STV0900_FEC_3_4: + stv0900_write_reg(intp, PRVIT, 0x04); + break; + case STV0900_FEC_5_6: + stv0900_write_reg(intp, PRVIT, 0x08); + break; + case STV0900_FEC_7_8: + stv0900_write_reg(intp, PRVIT, 0x20); + break; + } + + break; + case STV0900_SEARCH_DSS: + dprintk("DSS\n"); + stv0900_write_reg(intp, FECM, 0x80); + switch (fec) { + case STV0900_FEC_UNKNOWN: + default: + stv0900_write_reg(intp, PRVIT, 0x13); + break; + case STV0900_FEC_1_2: + stv0900_write_reg(intp, PRVIT, 0x01); + break; + case STV0900_FEC_2_3: + stv0900_write_reg(intp, PRVIT, 0x02); + break; + case STV0900_FEC_6_7: + stv0900_write_reg(intp, PRVIT, 0x10); + break; + } + break; + default: + break; + } +} + +static enum fe_stv0900_fec stv0900_get_vit_fec(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod) +{ + enum fe_stv0900_fec prate; + s32 rate_fld = stv0900_get_bits(intp, VIT_CURPUN); + + switch (rate_fld) { + case 13: + prate = STV0900_FEC_1_2; + break; + case 18: + prate = STV0900_FEC_2_3; + break; + case 21: + prate = STV0900_FEC_3_4; + break; + case 24: + prate = STV0900_FEC_5_6; + break; + case 25: + prate = STV0900_FEC_6_7; + break; + case 26: + prate = STV0900_FEC_7_8; + break; + default: + prate = STV0900_FEC_UNKNOWN; + break; + } + + return prate; +} + +static void stv0900_set_dvbs1_track_car_loop(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod, + u32 srate) +{ + if (intp->chip_id >= 0x30) { + if (srate >= 15000000) { + stv0900_write_reg(intp, ACLC, 0x2b); + stv0900_write_reg(intp, BCLC, 0x1a); + } else if ((srate >= 7000000) && (15000000 > srate)) { + stv0900_write_reg(intp, ACLC, 0x0c); + stv0900_write_reg(intp, BCLC, 0x1b); + } else if (srate < 7000000) { + stv0900_write_reg(intp, ACLC, 0x2c); + stv0900_write_reg(intp, BCLC, 0x1c); + } + + } else { /*cut 2.0 and 1.x*/ + stv0900_write_reg(intp, ACLC, 0x1a); + stv0900_write_reg(intp, BCLC, 0x09); + } + +} + +static void stv0900_track_optimization(struct dvb_frontend *fe) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + + s32 srate, + pilots, + aclc, + freq1, + freq0, + i = 0, + timed, + timef, + blind_tun_sw = 0, + modulation; + + enum fe_stv0900_modcode foundModcod; + + dprintk("%s\n", __func__); + + srate = stv0900_get_symbol_rate(intp, intp->mclk, demod); + srate += stv0900_get_timing_offst(intp, srate, demod); + + switch (intp->result[demod].standard) { + case STV0900_DVBS1_STANDARD: + case STV0900_DSS_STANDARD: + dprintk("%s: found DVB-S or DSS\n", __func__); + if (intp->srch_standard[demod] == STV0900_AUTO_SEARCH) { + stv0900_write_bits(intp, DVBS1_ENABLE, 1); + stv0900_write_bits(intp, DVBS2_ENABLE, 0); + } + + stv0900_write_bits(intp, ROLLOFF_CONTROL, intp->rolloff); + stv0900_write_bits(intp, MANUALSX_ROLLOFF, 1); + + if (intp->chip_id < 0x30) { + stv0900_write_reg(intp, ERRCTRL1, 0x75); + break; + } + + if (stv0900_get_vit_fec(intp, demod) == STV0900_FEC_1_2) { + stv0900_write_reg(intp, GAUSSR0, 0x98); + stv0900_write_reg(intp, CCIR0, 0x18); + } else { + stv0900_write_reg(intp, GAUSSR0, 0x18); + stv0900_write_reg(intp, CCIR0, 0x18); + } + + stv0900_write_reg(intp, ERRCTRL1, 0x75); + break; + case STV0900_DVBS2_STANDARD: + dprintk("%s: found DVB-S2\n", __func__); + stv0900_write_bits(intp, DVBS1_ENABLE, 0); + stv0900_write_bits(intp, DVBS2_ENABLE, 1); + stv0900_write_reg(intp, ACLC, 0); + stv0900_write_reg(intp, BCLC, 0); + if (intp->result[demod].frame_len == STV0900_LONG_FRAME) { + foundModcod = stv0900_get_bits(intp, DEMOD_MODCOD); + pilots = stv0900_get_bits(intp, DEMOD_TYPE) & 0x01; + aclc = stv0900_get_optim_carr_loop(srate, + foundModcod, + pilots, + intp->chip_id); + if (foundModcod <= STV0900_QPSK_910) + stv0900_write_reg(intp, ACLC2S2Q, aclc); + else if (foundModcod <= STV0900_8PSK_910) { + stv0900_write_reg(intp, ACLC2S2Q, 0x2a); + stv0900_write_reg(intp, ACLC2S28, aclc); + } + + if ((intp->demod_mode == STV0900_SINGLE) && + (foundModcod > STV0900_8PSK_910)) { + if (foundModcod <= STV0900_16APSK_910) { + stv0900_write_reg(intp, ACLC2S2Q, 0x2a); + stv0900_write_reg(intp, ACLC2S216A, + aclc); + } else if (foundModcod <= STV0900_32APSK_910) { + stv0900_write_reg(intp, ACLC2S2Q, 0x2a); + stv0900_write_reg(intp, ACLC2S232A, + aclc); + } + } + + } else { + modulation = intp->result[demod].modulation; + aclc = stv0900_get_optim_short_carr_loop(srate, + modulation, intp->chip_id); + if (modulation == STV0900_QPSK) + stv0900_write_reg(intp, ACLC2S2Q, aclc); + else if (modulation == STV0900_8PSK) { + stv0900_write_reg(intp, ACLC2S2Q, 0x2a); + stv0900_write_reg(intp, ACLC2S28, aclc); + } else if (modulation == STV0900_16APSK) { + stv0900_write_reg(intp, ACLC2S2Q, 0x2a); + stv0900_write_reg(intp, ACLC2S216A, aclc); + } else if (modulation == STV0900_32APSK) { + stv0900_write_reg(intp, ACLC2S2Q, 0x2a); + stv0900_write_reg(intp, ACLC2S232A, aclc); + } + + } + + if (intp->chip_id <= 0x11) { + if (intp->demod_mode != STV0900_SINGLE) + stv0900_activate_s2_modcod(intp, demod); + + } + + stv0900_write_reg(intp, ERRCTRL1, 0x67); + break; + case STV0900_UNKNOWN_STANDARD: + default: + dprintk("%s: found unknown standard\n", __func__); + stv0900_write_bits(intp, DVBS1_ENABLE, 1); + stv0900_write_bits(intp, DVBS2_ENABLE, 1); + break; + } + + freq1 = stv0900_read_reg(intp, CFR2); + freq0 = stv0900_read_reg(intp, CFR1); + if (intp->srch_algo[demod] == STV0900_BLIND_SEARCH) { + stv0900_write_reg(intp, SFRSTEP, 0x00); + stv0900_write_bits(intp, SCAN_ENABLE, 0); + stv0900_write_bits(intp, CFR_AUTOSCAN, 0); + stv0900_write_reg(intp, TMGCFG2, 0xc1); + stv0900_set_symbol_rate(intp, intp->mclk, srate, demod); + blind_tun_sw = 1; + if (intp->result[demod].standard != STV0900_DVBS2_STANDARD) + stv0900_set_dvbs1_track_car_loop(intp, demod, srate); + + } + + if (intp->chip_id >= 0x20) { + if ((intp->srch_standard[demod] == STV0900_SEARCH_DVBS1) || + (intp->srch_standard[demod] == + STV0900_SEARCH_DSS) || + (intp->srch_standard[demod] == + STV0900_AUTO_SEARCH)) { + stv0900_write_reg(intp, VAVSRVIT, 0x0a); + stv0900_write_reg(intp, VITSCALE, 0x0); + } + } + + if (intp->chip_id < 0x20) + stv0900_write_reg(intp, CARHDR, 0x08); + + if (intp->chip_id == 0x10) + stv0900_write_reg(intp, CORRELEXP, 0x0a); + + stv0900_write_reg(intp, AGC2REF, 0x38); + + if ((intp->chip_id >= 0x20) || + (blind_tun_sw == 1) || + (intp->symbol_rate[demod] < 10000000)) { + stv0900_write_reg(intp, CFRINIT1, freq1); + stv0900_write_reg(intp, CFRINIT0, freq0); + intp->bw[demod] = stv0900_carrier_width(srate, + intp->rolloff) + 10000000; + + if ((intp->chip_id >= 0x20) || (blind_tun_sw == 1)) { + if (intp->srch_algo[demod] != STV0900_WARM_START) { + if (intp->tuner_type[demod] == 3) + stv0900_set_tuner_auto(intp, + intp->freq[demod], + intp->bw[demod], + demod); + else + stv0900_set_bandwidth(fe, + intp->bw[demod]); + } + } + + if ((intp->srch_algo[demod] == STV0900_BLIND_SEARCH) || + (intp->symbol_rate[demod] < 10000000)) + msleep(50); + else + msleep(5); + + stv0900_get_lock_timeout(&timed, &timef, srate, + STV0900_WARM_START); + + if (stv0900_get_demod_lock(intp, demod, timed / 2) == FALSE) { + stv0900_write_reg(intp, DMDISTATE, 0x1f); + stv0900_write_reg(intp, CFRINIT1, freq1); + stv0900_write_reg(intp, CFRINIT0, freq0); + stv0900_write_reg(intp, DMDISTATE, 0x18); + i = 0; + while ((stv0900_get_demod_lock(intp, + demod, + timed / 2) == FALSE) && + (i <= 2)) { + stv0900_write_reg(intp, DMDISTATE, 0x1f); + stv0900_write_reg(intp, CFRINIT1, freq1); + stv0900_write_reg(intp, CFRINIT0, freq0); + stv0900_write_reg(intp, DMDISTATE, 0x18); + i++; + } + } + + } + + if (intp->chip_id >= 0x20) + stv0900_write_reg(intp, CARFREQ, 0x49); + + if ((intp->result[demod].standard == STV0900_DVBS1_STANDARD) || + (intp->result[demod].standard == STV0900_DSS_STANDARD)) + stv0900_set_viterbi_tracq(intp, demod); + +} + +static int stv0900_get_fec_lock(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod, s32 time_out) +{ + s32 timer = 0, lock = 0; + + enum fe_stv0900_search_state dmd_state; + + dprintk("%s\n", __func__); + + dmd_state = stv0900_get_bits(intp, HEADER_MODE); + + while ((timer < time_out) && (lock == 0)) { + switch (dmd_state) { + case STV0900_SEARCH: + case STV0900_PLH_DETECTED: + default: + lock = 0; + break; + case STV0900_DVBS2_FOUND: + lock = stv0900_get_bits(intp, PKTDELIN_LOCK); + break; + case STV0900_DVBS_FOUND: + lock = stv0900_get_bits(intp, LOCKEDVIT); + break; + } + + if (lock == 0) { + msleep(10); + timer += 10; + } + } + + if (lock) + dprintk("%s: DEMOD FEC LOCK OK\n", __func__); + else + dprintk("%s: DEMOD FEC LOCK FAIL\n", __func__); + + return lock; +} + +static int stv0900_wait_for_lock(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod, + s32 dmd_timeout, s32 fec_timeout) +{ + + s32 timer = 0, lock = 0; + + dprintk("%s\n", __func__); + + lock = stv0900_get_demod_lock(intp, demod, dmd_timeout); + + if (lock) + lock = stv0900_get_fec_lock(intp, demod, fec_timeout); + + if (lock) { + lock = 0; + + dprintk("%s: Timer = %d, time_out = %d\n", + __func__, timer, fec_timeout); + + while ((timer < fec_timeout) && (lock == 0)) { + lock = stv0900_get_bits(intp, TSFIFO_LINEOK); + msleep(1); + timer++; + } + } + + if (lock) + dprintk("%s: DEMOD LOCK OK\n", __func__); + else + dprintk("%s: DEMOD LOCK FAIL\n", __func__); + + if (lock) + return TRUE; + else + return FALSE; +} + +enum fe_stv0900_tracking_standard stv0900_get_standard(struct dvb_frontend *fe, + enum fe_stv0900_demod_num demod) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_tracking_standard fnd_standard; + + int hdr_mode = stv0900_get_bits(intp, HEADER_MODE); + + switch (hdr_mode) { + case 2: + fnd_standard = STV0900_DVBS2_STANDARD; + break; + case 3: + if (stv0900_get_bits(intp, DSS_DVB) == 1) + fnd_standard = STV0900_DSS_STANDARD; + else + fnd_standard = STV0900_DVBS1_STANDARD; + + break; + default: + fnd_standard = STV0900_UNKNOWN_STANDARD; + } + + dprintk("%s: standard %d\n", __func__, fnd_standard); + + return fnd_standard; +} + +static s32 stv0900_get_carr_freq(struct stv0900_internal *intp, u32 mclk, + enum fe_stv0900_demod_num demod) +{ + s32 derot, + rem1, + rem2, + intval1, + intval2; + + derot = (stv0900_get_bits(intp, CAR_FREQ2) << 16) + + (stv0900_get_bits(intp, CAR_FREQ1) << 8) + + (stv0900_get_bits(intp, CAR_FREQ0)); + + derot = ge2comp(derot, 24); + intval1 = mclk >> 12; + intval2 = derot >> 12; + rem1 = mclk % 0x1000; + rem2 = derot % 0x1000; + derot = (intval1 * intval2) + + ((intval1 * rem2) >> 12) + + ((intval2 * rem1) >> 12); + + return derot; +} + +static u32 stv0900_get_tuner_freq(struct dvb_frontend *fe) +{ + struct dvb_frontend_ops *frontend_ops = NULL; + struct dvb_tuner_ops *tuner_ops = NULL; + u32 freq = 0; + + frontend_ops = &fe->ops; + tuner_ops = &frontend_ops->tuner_ops; + + if (tuner_ops->get_frequency) { + if ((tuner_ops->get_frequency(fe, &freq)) < 0) + dprintk("%s: Invalid parameter\n", __func__); + else + dprintk("%s: Frequency=%d\n", __func__, freq); + + } + + return freq; +} + +static enum +fe_stv0900_signal_type stv0900_get_signal_params(struct dvb_frontend *fe) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + enum fe_stv0900_signal_type range = STV0900_OUTOFRANGE; + struct stv0900_signal_info *result = &intp->result[demod]; + s32 offsetFreq, + srate_offset; + int i = 0, + d = demod; + + u8 timing; + + msleep(5); + if (intp->srch_algo[d] == STV0900_BLIND_SEARCH) { + timing = stv0900_read_reg(intp, TMGREG2); + i = 0; + stv0900_write_reg(intp, SFRSTEP, 0x5c); + + while ((i <= 50) && (timing != 0) && (timing != 0xff)) { + timing = stv0900_read_reg(intp, TMGREG2); + msleep(5); + i += 5; + } + } + + result->standard = stv0900_get_standard(fe, d); + if (intp->tuner_type[demod] == 3) + result->frequency = stv0900_get_freq_auto(intp, d); + else + result->frequency = stv0900_get_tuner_freq(fe); + + offsetFreq = stv0900_get_carr_freq(intp, intp->mclk, d) / 1000; + result->frequency += offsetFreq; + result->symbol_rate = stv0900_get_symbol_rate(intp, intp->mclk, d); + srate_offset = stv0900_get_timing_offst(intp, result->symbol_rate, d); + result->symbol_rate += srate_offset; + result->fec = stv0900_get_vit_fec(intp, d); + result->modcode = stv0900_get_bits(intp, DEMOD_MODCOD); + result->pilot = stv0900_get_bits(intp, DEMOD_TYPE) & 0x01; + result->frame_len = ((u32)stv0900_get_bits(intp, DEMOD_TYPE)) >> 1; + result->rolloff = stv0900_get_bits(intp, ROLLOFF_STATUS); + + dprintk("%s: modcode=0x%x \n", __func__, result->modcode); + + switch (result->standard) { + case STV0900_DVBS2_STANDARD: + result->spectrum = stv0900_get_bits(intp, SPECINV_DEMOD); + if (result->modcode <= STV0900_QPSK_910) + result->modulation = STV0900_QPSK; + else if (result->modcode <= STV0900_8PSK_910) + result->modulation = STV0900_8PSK; + else if (result->modcode <= STV0900_16APSK_910) + result->modulation = STV0900_16APSK; + else if (result->modcode <= STV0900_32APSK_910) + result->modulation = STV0900_32APSK; + else + result->modulation = STV0900_UNKNOWN; + break; + case STV0900_DVBS1_STANDARD: + case STV0900_DSS_STANDARD: + result->spectrum = stv0900_get_bits(intp, IQINV); + result->modulation = STV0900_QPSK; + break; + default: + break; + } + + if ((intp->srch_algo[d] == STV0900_BLIND_SEARCH) || + (intp->symbol_rate[d] < 10000000)) { + offsetFreq = result->frequency - intp->freq[d]; + if (intp->tuner_type[demod] == 3) + intp->freq[d] = stv0900_get_freq_auto(intp, d); + else + intp->freq[d] = stv0900_get_tuner_freq(fe); + + if (ABS(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500)) + range = STV0900_RANGEOK; + else if (ABS(offsetFreq) <= + (stv0900_carrier_width(result->symbol_rate, + result->rolloff) / 2000)) + range = STV0900_RANGEOK; + + } else if (ABS(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500)) + range = STV0900_RANGEOK; + + dprintk("%s: range %d\n", __func__, range); + + return range; +} + +static enum +fe_stv0900_signal_type stv0900_dvbs1_acq_workaround(struct dvb_frontend *fe) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + enum fe_stv0900_signal_type signal_type = STV0900_NODATA; + + s32 srate, + demod_timeout, + fec_timeout, + freq1, + freq0; + + intp->result[demod].locked = FALSE; + + if (stv0900_get_bits(intp, HEADER_MODE) == STV0900_DVBS_FOUND) { + srate = stv0900_get_symbol_rate(intp, intp->mclk, demod); + srate += stv0900_get_timing_offst(intp, srate, demod); + if (intp->srch_algo[demod] == STV0900_BLIND_SEARCH) + stv0900_set_symbol_rate(intp, intp->mclk, srate, demod); + + stv0900_get_lock_timeout(&demod_timeout, &fec_timeout, + srate, STV0900_WARM_START); + freq1 = stv0900_read_reg(intp, CFR2); + freq0 = stv0900_read_reg(intp, CFR1); + stv0900_write_bits(intp, CFR_AUTOSCAN, 0); + stv0900_write_bits(intp, SPECINV_CONTROL, + STV0900_IQ_FORCE_SWAPPED); + stv0900_write_reg(intp, DMDISTATE, 0x1c); + stv0900_write_reg(intp, CFRINIT1, freq1); + stv0900_write_reg(intp, CFRINIT0, freq0); + stv0900_write_reg(intp, DMDISTATE, 0x18); + if (stv0900_wait_for_lock(intp, demod, + demod_timeout, fec_timeout) == TRUE) { + intp->result[demod].locked = TRUE; + signal_type = stv0900_get_signal_params(fe); + stv0900_track_optimization(fe); + } else { + stv0900_write_bits(intp, SPECINV_CONTROL, + STV0900_IQ_FORCE_NORMAL); + stv0900_write_reg(intp, DMDISTATE, 0x1c); + stv0900_write_reg(intp, CFRINIT1, freq1); + stv0900_write_reg(intp, CFRINIT0, freq0); + stv0900_write_reg(intp, DMDISTATE, 0x18); + if (stv0900_wait_for_lock(intp, demod, + demod_timeout, fec_timeout) == TRUE) { + intp->result[demod].locked = TRUE; + signal_type = stv0900_get_signal_params(fe); + stv0900_track_optimization(fe); + } + + } + + } else + intp->result[demod].locked = FALSE; + + return signal_type; +} + +static u16 stv0900_blind_check_agc2_min_level(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod) +{ + u32 minagc2level = 0xffff, + agc2level, + init_freq, freq_step; + + s32 i, j, nb_steps, direction; + + dprintk("%s\n", __func__); + + stv0900_write_reg(intp, AGC2REF, 0x38); + stv0900_write_bits(intp, SCAN_ENABLE, 0); + stv0900_write_bits(intp, CFR_AUTOSCAN, 0); + + stv0900_write_bits(intp, AUTO_GUP, 1); + stv0900_write_bits(intp, AUTO_GLOW, 1); + + stv0900_write_reg(intp, DMDT0M, 0x0); + + stv0900_set_symbol_rate(intp, intp->mclk, 1000000, demod); + nb_steps = -1 + (intp->srch_range[demod] / 1000000); + nb_steps /= 2; + nb_steps = (2 * nb_steps) + 1; + + if (nb_steps < 0) + nb_steps = 1; + + direction = 1; + + freq_step = (1000000 << 8) / (intp->mclk >> 8); + + init_freq = 0; + + for (i = 0; i < nb_steps; i++) { + if (direction > 0) + init_freq = init_freq + (freq_step * i); + else + init_freq = init_freq - (freq_step * i); + + direction *= -1; + stv0900_write_reg(intp, DMDISTATE, 0x5C); + stv0900_write_reg(intp, CFRINIT1, (init_freq >> 8) & 0xff); + stv0900_write_reg(intp, CFRINIT0, init_freq & 0xff); + stv0900_write_reg(intp, DMDISTATE, 0x58); + msleep(10); + agc2level = 0; + + for (j = 0; j < 10; j++) + agc2level += (stv0900_read_reg(intp, AGC2I1) << 8) + | stv0900_read_reg(intp, AGC2I0); + + agc2level /= 10; + + if (agc2level < minagc2level) + minagc2level = agc2level; + + } + + return (u16)minagc2level; +} + +static u32 stv0900_search_srate_coarse(struct dvb_frontend *fe) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + int timing_lck = FALSE; + s32 i, timingcpt = 0, + direction = 1, + nb_steps, + current_step = 0, + tuner_freq; + u32 agc2_th, + coarse_srate = 0, + agc2_integr = 0, + currier_step = 1200; + + if (intp->chip_id >= 0x30) + agc2_th = 0x2e00; + else + agc2_th = 0x1f00; + + stv0900_write_bits(intp, DEMOD_MODE, 0x1f); + stv0900_write_reg(intp, TMGCFG, 0x12); + stv0900_write_reg(intp, TMGTHRISE, 0xf0); + stv0900_write_reg(intp, TMGTHFALL, 0xe0); + stv0900_write_bits(intp, SCAN_ENABLE, 1); + stv0900_write_bits(intp, CFR_AUTOSCAN, 1); + stv0900_write_reg(intp, SFRUP1, 0x83); + stv0900_write_reg(intp, SFRUP0, 0xc0); + stv0900_write_reg(intp, SFRLOW1, 0x82); + stv0900_write_reg(intp, SFRLOW0, 0xa0); + stv0900_write_reg(intp, DMDT0M, 0x0); + stv0900_write_reg(intp, AGC2REF, 0x50); + + if (intp->chip_id >= 0x30) { + stv0900_write_reg(intp, CARFREQ, 0x99); + stv0900_write_reg(intp, SFRSTEP, 0x98); + } else if (intp->chip_id >= 0x20) { + stv0900_write_reg(intp, CARFREQ, 0x6a); + stv0900_write_reg(intp, SFRSTEP, 0x95); + } else { + stv0900_write_reg(intp, CARFREQ, 0xed); + stv0900_write_reg(intp, SFRSTEP, 0x73); + } + + if (intp->symbol_rate[demod] <= 2000000) + currier_step = 1000; + else if (intp->symbol_rate[demod] <= 5000000) + currier_step = 2000; + else if (intp->symbol_rate[demod] <= 12000000) + currier_step = 3000; + else + currier_step = 5000; + + nb_steps = -1 + ((intp->srch_range[demod] / 1000) / currier_step); + nb_steps /= 2; + nb_steps = (2 * nb_steps) + 1; + + if (nb_steps < 0) + nb_steps = 1; + else if (nb_steps > 10) { + nb_steps = 11; + currier_step = (intp->srch_range[demod] / 1000) / 10; + } + + current_step = 0; + direction = 1; + + tuner_freq = intp->freq[demod]; + + while ((timing_lck == FALSE) && (current_step < nb_steps)) { + stv0900_write_reg(intp, DMDISTATE, 0x5f); + stv0900_write_bits(intp, DEMOD_MODE, 0); + + msleep(50); + + for (i = 0; i < 10; i++) { + if (stv0900_get_bits(intp, TMGLOCK_QUALITY) >= 2) + timingcpt++; + + agc2_integr += (stv0900_read_reg(intp, AGC2I1) << 8) | + stv0900_read_reg(intp, AGC2I0); + } + + agc2_integr /= 10; + coarse_srate = stv0900_get_symbol_rate(intp, intp->mclk, demod); + current_step++; + direction *= -1; + + dprintk("lock: I2C_DEMOD_MODE_FIELD =0. Search started." + " tuner freq=%d agc2=0x%x srate_coarse=%d tmg_cpt=%d\n", + tuner_freq, agc2_integr, coarse_srate, timingcpt); + + if ((timingcpt >= 5) && + (agc2_integr < agc2_th) && + (coarse_srate < 55000000) && + (coarse_srate > 850000)) + timing_lck = TRUE; + else if (current_step < nb_steps) { + if (direction > 0) + tuner_freq += (current_step * currier_step); + else + tuner_freq -= (current_step * currier_step); + + if (intp->tuner_type[demod] == 3) + stv0900_set_tuner_auto(intp, tuner_freq, + intp->bw[demod], demod); + else + stv0900_set_tuner(fe, tuner_freq, + intp->bw[demod]); + } + } + + if (timing_lck == FALSE) + coarse_srate = 0; + else + coarse_srate = stv0900_get_symbol_rate(intp, intp->mclk, demod); + + return coarse_srate; +} + +static u32 stv0900_search_srate_fine(struct dvb_frontend *fe) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + u32 coarse_srate, + coarse_freq, + symb, + symbmax, + symbmin, + symbcomp; + + coarse_srate = stv0900_get_symbol_rate(intp, intp->mclk, demod); + + if (coarse_srate > 3000000) { + symbmax = 13 * (coarse_srate / 10); + symbmax = (symbmax / 1000) * 65536; + symbmax /= (intp->mclk / 1000); + + symbmin = 10 * (coarse_srate / 13); + symbmin = (symbmin / 1000)*65536; + symbmin /= (intp->mclk / 1000); + + symb = (coarse_srate / 1000) * 65536; + symb /= (intp->mclk / 1000); + } else { + symbmax = 13 * (coarse_srate / 10); + symbmax = (symbmax / 100) * 65536; + symbmax /= (intp->mclk / 100); + + symbmin = 10 * (coarse_srate / 14); + symbmin = (symbmin / 100) * 65536; + symbmin /= (intp->mclk / 100); + + symb = (coarse_srate / 100) * 65536; + symb /= (intp->mclk / 100); + } + + symbcomp = 13 * (coarse_srate / 10); + coarse_freq = (stv0900_read_reg(intp, CFR2) << 8) + | stv0900_read_reg(intp, CFR1); + + if (symbcomp < intp->symbol_rate[demod]) + coarse_srate = 0; + else { + stv0900_write_reg(intp, DMDISTATE, 0x1f); + stv0900_write_reg(intp, TMGCFG2, 0xc1); + stv0900_write_reg(intp, TMGTHRISE, 0x20); + stv0900_write_reg(intp, TMGTHFALL, 0x00); + stv0900_write_reg(intp, TMGCFG, 0xd2); + stv0900_write_bits(intp, CFR_AUTOSCAN, 0); + stv0900_write_reg(intp, AGC2REF, 0x38); + + if (intp->chip_id >= 0x30) + stv0900_write_reg(intp, CARFREQ, 0x79); + else if (intp->chip_id >= 0x20) + stv0900_write_reg(intp, CARFREQ, 0x49); + else + stv0900_write_reg(intp, CARFREQ, 0xed); + + stv0900_write_reg(intp, SFRUP1, (symbmax >> 8) & 0x7f); + stv0900_write_reg(intp, SFRUP0, (symbmax & 0xff)); + + stv0900_write_reg(intp, SFRLOW1, (symbmin >> 8) & 0x7f); + stv0900_write_reg(intp, SFRLOW0, (symbmin & 0xff)); + + stv0900_write_reg(intp, SFRINIT1, (symb >> 8) & 0xff); + stv0900_write_reg(intp, SFRINIT0, (symb & 0xff)); + + stv0900_write_reg(intp, DMDT0M, 0x20); + stv0900_write_reg(intp, CFRINIT1, (coarse_freq >> 8) & 0xff); + stv0900_write_reg(intp, CFRINIT0, coarse_freq & 0xff); + stv0900_write_reg(intp, DMDISTATE, 0x15); + } + + return coarse_srate; +} + +static int stv0900_blind_search_algo(struct dvb_frontend *fe) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + u8 k_ref_tmg, + k_ref_tmg_max, + k_ref_tmg_min; + u32 coarse_srate, + agc2_th; + int lock = FALSE, + coarse_fail = FALSE; + s32 demod_timeout = 500, + fec_timeout = 50, + fail_cpt, + i, + agc2_overflow; + u16 agc2_int; + u8 dstatus2; + + dprintk("%s\n", __func__); + + if (intp->chip_id < 0x20) { + k_ref_tmg_max = 233; + k_ref_tmg_min = 143; + } else { + k_ref_tmg_max = 110; + k_ref_tmg_min = 10; + } + + if (intp->chip_id <= 0x20) + agc2_th = STV0900_BLIND_SEARCH_AGC2_TH; + else + agc2_th = STV0900_BLIND_SEARCH_AGC2_TH_CUT30; + + agc2_int = stv0900_blind_check_agc2_min_level(intp, demod); + + dprintk("%s agc2_int=%d agc2_th=%d \n", __func__, agc2_int, agc2_th); + if (agc2_int > agc2_th) + return FALSE; + + if (intp->chip_id == 0x10) + stv0900_write_reg(intp, CORRELEXP, 0xaa); + + if (intp->chip_id < 0x20) + stv0900_write_reg(intp, CARHDR, 0x55); + else + stv0900_write_reg(intp, CARHDR, 0x20); + + if (intp->chip_id <= 0x20) + stv0900_write_reg(intp, CARCFG, 0xc4); + else + stv0900_write_reg(intp, CARCFG, 0x6); + + stv0900_write_reg(intp, RTCS2, 0x44); + + if (intp->chip_id >= 0x20) { + stv0900_write_reg(intp, EQUALCFG, 0x41); + stv0900_write_reg(intp, FFECFG, 0x41); + stv0900_write_reg(intp, VITSCALE, 0x82); + stv0900_write_reg(intp, VAVSRVIT, 0x0); + } + + k_ref_tmg = k_ref_tmg_max; + + do { + stv0900_write_reg(intp, KREFTMG, k_ref_tmg); + if (stv0900_search_srate_coarse(fe) != 0) { + coarse_srate = stv0900_search_srate_fine(fe); + + if (coarse_srate != 0) { + stv0900_get_lock_timeout(&demod_timeout, + &fec_timeout, + coarse_srate, + STV0900_BLIND_SEARCH); + lock = stv0900_get_demod_lock(intp, + demod, + demod_timeout); + } else + lock = FALSE; + } else { + fail_cpt = 0; + agc2_overflow = 0; + + for (i = 0; i < 10; i++) { + agc2_int = (stv0900_read_reg(intp, AGC2I1) << 8) + | stv0900_read_reg(intp, AGC2I0); + + if (agc2_int >= 0xff00) + agc2_overflow++; + + dstatus2 = stv0900_read_reg(intp, DSTATUS2); + + if (((dstatus2 & 0x1) == 0x1) && + ((dstatus2 >> 7) == 1)) + fail_cpt++; + } + + if ((fail_cpt > 7) || (agc2_overflow > 7)) + coarse_fail = TRUE; + + lock = FALSE; + } + k_ref_tmg -= 30; + } while ((k_ref_tmg >= k_ref_tmg_min) && + (lock == FALSE) && + (coarse_fail == FALSE)); + + return lock; +} + +static void stv0900_set_viterbi_acq(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod) +{ + s32 vth_reg = VTH12; + + dprintk("%s\n", __func__); + + stv0900_write_reg(intp, vth_reg++, 0x96); + stv0900_write_reg(intp, vth_reg++, 0x64); + stv0900_write_reg(intp, vth_reg++, 0x36); + stv0900_write_reg(intp, vth_reg++, 0x23); + stv0900_write_reg(intp, vth_reg++, 0x1e); + stv0900_write_reg(intp, vth_reg++, 0x19); +} + +static void stv0900_set_search_standard(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod) +{ + + dprintk("%s\n", __func__); + + switch (intp->srch_standard[demod]) { + case STV0900_SEARCH_DVBS1: + dprintk("Search Standard = DVBS1\n"); + break; + case STV0900_SEARCH_DSS: + dprintk("Search Standard = DSS\n"); + break; + case STV0900_SEARCH_DVBS2: + dprintk("Search Standard = DVBS2\n"); + break; + case STV0900_AUTO_SEARCH: + default: + dprintk("Search Standard = AUTO\n"); + break; + } + + switch (intp->srch_standard[demod]) { + case STV0900_SEARCH_DVBS1: + case STV0900_SEARCH_DSS: + stv0900_write_bits(intp, DVBS1_ENABLE, 1); + stv0900_write_bits(intp, DVBS2_ENABLE, 0); + stv0900_write_bits(intp, STOP_CLKVIT, 0); + stv0900_set_dvbs1_track_car_loop(intp, + demod, + intp->symbol_rate[demod]); + stv0900_write_reg(intp, CAR2CFG, 0x22); + + stv0900_set_viterbi_acq(intp, demod); + stv0900_set_viterbi_standard(intp, + intp->srch_standard[demod], + intp->fec[demod], demod); + + break; + case STV0900_SEARCH_DVBS2: + stv0900_write_bits(intp, DVBS1_ENABLE, 0); + stv0900_write_bits(intp, DVBS2_ENABLE, 1); + stv0900_write_bits(intp, STOP_CLKVIT, 1); + stv0900_write_reg(intp, ACLC, 0x1a); + stv0900_write_reg(intp, BCLC, 0x09); + if (intp->chip_id <= 0x20) /*cut 1.x and 2.0*/ + stv0900_write_reg(intp, CAR2CFG, 0x26); + else + stv0900_write_reg(intp, CAR2CFG, 0x66); + + if (intp->demod_mode != STV0900_SINGLE) { + if (intp->chip_id <= 0x11) + stv0900_stop_all_s2_modcod(intp, demod); + else + stv0900_activate_s2_modcod(intp, demod); + + } else + stv0900_activate_s2_modcod_single(intp, demod); + + stv0900_set_viterbi_tracq(intp, demod); + + break; + case STV0900_AUTO_SEARCH: + default: + stv0900_write_bits(intp, DVBS1_ENABLE, 1); + stv0900_write_bits(intp, DVBS2_ENABLE, 1); + stv0900_write_bits(intp, STOP_CLKVIT, 0); + stv0900_write_reg(intp, ACLC, 0x1a); + stv0900_write_reg(intp, BCLC, 0x09); + stv0900_set_dvbs1_track_car_loop(intp, + demod, + intp->symbol_rate[demod]); + if (intp->chip_id <= 0x20) /*cut 1.x and 2.0*/ + stv0900_write_reg(intp, CAR2CFG, 0x26); + else + stv0900_write_reg(intp, CAR2CFG, 0x66); + + if (intp->demod_mode != STV0900_SINGLE) { + if (intp->chip_id <= 0x11) + stv0900_stop_all_s2_modcod(intp, demod); + else + stv0900_activate_s2_modcod(intp, demod); + + } else + stv0900_activate_s2_modcod_single(intp, demod); + + stv0900_set_viterbi_tracq(intp, demod); + stv0900_set_viterbi_standard(intp, + intp->srch_standard[demod], + intp->fec[demod], demod); + + break; + } +} + +enum fe_stv0900_signal_type stv0900_algo(struct dvb_frontend *fe) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + + s32 demod_timeout = 500, fec_timeout = 50; + s32 aq_power, agc1_power, i; + + int lock = FALSE, low_sr = FALSE; + + enum fe_stv0900_signal_type signal_type = STV0900_NOCARRIER; + enum fe_stv0900_search_algo algo; + int no_signal = FALSE; + + dprintk("%s\n", __func__); + + algo = intp->srch_algo[demod]; + stv0900_write_bits(intp, RST_HWARE, 1); + stv0900_write_reg(intp, DMDISTATE, 0x5c); + if (intp->chip_id >= 0x20) { + if (intp->symbol_rate[demod] > 5000000) + stv0900_write_reg(intp, CORRELABS, 0x9e); + else + stv0900_write_reg(intp, CORRELABS, 0x82); + } else + stv0900_write_reg(intp, CORRELABS, 0x88); + + stv0900_get_lock_timeout(&demod_timeout, &fec_timeout, + intp->symbol_rate[demod], + intp->srch_algo[demod]); + + if (intp->srch_algo[demod] == STV0900_BLIND_SEARCH) { + intp->bw[demod] = 2 * 36000000; + + stv0900_write_reg(intp, TMGCFG2, 0xc0); + stv0900_write_reg(intp, CORRELMANT, 0x70); + + stv0900_set_symbol_rate(intp, intp->mclk, 1000000, demod); + } else { + stv0900_write_reg(intp, DMDT0M, 0x20); + stv0900_write_reg(intp, TMGCFG, 0xd2); + + if (intp->symbol_rate[demod] < 2000000) + stv0900_write_reg(intp, CORRELMANT, 0x63); + else + stv0900_write_reg(intp, CORRELMANT, 0x70); + + stv0900_write_reg(intp, AGC2REF, 0x38); + + intp->bw[demod] = + stv0900_carrier_width(intp->symbol_rate[demod], + intp->rolloff); + if (intp->chip_id >= 0x20) { + stv0900_write_reg(intp, KREFTMG, 0x5a); + + if (intp->srch_algo[demod] == STV0900_COLD_START) { + intp->bw[demod] += 10000000; + intp->bw[demod] *= 15; + intp->bw[demod] /= 10; + } else if (intp->srch_algo[demod] == STV0900_WARM_START) + intp->bw[demod] += 10000000; + + } else { + stv0900_write_reg(intp, KREFTMG, 0xc1); + intp->bw[demod] += 10000000; + intp->bw[demod] *= 15; + intp->bw[demod] /= 10; + } + + stv0900_write_reg(intp, TMGCFG2, 0xc1); + + stv0900_set_symbol_rate(intp, intp->mclk, + intp->symbol_rate[demod], demod); + stv0900_set_max_symbol_rate(intp, intp->mclk, + intp->symbol_rate[demod], demod); + stv0900_set_min_symbol_rate(intp, intp->mclk, + intp->symbol_rate[demod], demod); + if (intp->symbol_rate[demod] >= 10000000) + low_sr = FALSE; + else + low_sr = TRUE; + + } + + if (intp->tuner_type[demod] == 3) + stv0900_set_tuner_auto(intp, intp->freq[demod], + intp->bw[demod], demod); + else + stv0900_set_tuner(fe, intp->freq[demod], intp->bw[demod]); + + agc1_power = MAKEWORD(stv0900_get_bits(intp, AGCIQ_VALUE1), + stv0900_get_bits(intp, AGCIQ_VALUE0)); + + aq_power = 0; + + if (agc1_power == 0) { + for (i = 0; i < 5; i++) + aq_power += (stv0900_get_bits(intp, POWER_I) + + stv0900_get_bits(intp, POWER_Q)) / 2; + + aq_power /= 5; + } + + if ((agc1_power == 0) && (aq_power < IQPOWER_THRESHOLD)) { + intp->result[demod].locked = FALSE; + signal_type = STV0900_NOAGC1; + dprintk("%s: NO AGC1, POWERI, POWERQ\n", __func__); + } else { + stv0900_write_bits(intp, SPECINV_CONTROL, + intp->srch_iq_inv[demod]); + if (intp->chip_id <= 0x20) /*cut 2.0*/ + stv0900_write_bits(intp, MANUALSX_ROLLOFF, 1); + else /*cut 3.0*/ + stv0900_write_bits(intp, MANUALS2_ROLLOFF, 1); + + stv0900_set_search_standard(intp, demod); + + if (intp->srch_algo[demod] != STV0900_BLIND_SEARCH) + stv0900_start_search(intp, demod); + } + + if (signal_type == STV0900_NOAGC1) + return signal_type; + + if (intp->chip_id == 0x12) { + stv0900_write_bits(intp, RST_HWARE, 0); + msleep(3); + stv0900_write_bits(intp, RST_HWARE, 1); + stv0900_write_bits(intp, RST_HWARE, 0); + } + + if (algo == STV0900_BLIND_SEARCH) + lock = stv0900_blind_search_algo(fe); + else if (algo == STV0900_COLD_START) + lock = stv0900_get_demod_cold_lock(fe, demod_timeout); + else if (algo == STV0900_WARM_START) + lock = stv0900_get_demod_lock(intp, demod, demod_timeout); + + if ((lock == FALSE) && (algo == STV0900_COLD_START)) { + if (low_sr == FALSE) { + if (stv0900_check_timing_lock(intp, demod) == TRUE) + lock = stv0900_sw_algo(intp, demod); + } + } + + if (lock == TRUE) + signal_type = stv0900_get_signal_params(fe); + + if ((lock == TRUE) && (signal_type == STV0900_RANGEOK)) { + stv0900_track_optimization(fe); + if (intp->chip_id <= 0x11) { + if ((stv0900_get_standard(fe, 0) == + STV0900_DVBS1_STANDARD) && + (stv0900_get_standard(fe, 1) == + STV0900_DVBS1_STANDARD)) { + msleep(20); + stv0900_write_bits(intp, RST_HWARE, 0); + } else { + stv0900_write_bits(intp, RST_HWARE, 0); + msleep(3); + stv0900_write_bits(intp, RST_HWARE, 1); + stv0900_write_bits(intp, RST_HWARE, 0); + } + + } else if (intp->chip_id >= 0x20) { + stv0900_write_bits(intp, RST_HWARE, 0); + msleep(3); + stv0900_write_bits(intp, RST_HWARE, 1); + stv0900_write_bits(intp, RST_HWARE, 0); + } + + if (stv0900_wait_for_lock(intp, demod, + fec_timeout, fec_timeout) == TRUE) { + lock = TRUE; + intp->result[demod].locked = TRUE; + if (intp->result[demod].standard == + STV0900_DVBS2_STANDARD) { + stv0900_set_dvbs2_rolloff(intp, demod); + stv0900_write_bits(intp, RESET_UPKO_COUNT, 1); + stv0900_write_bits(intp, RESET_UPKO_COUNT, 0); + stv0900_write_reg(intp, ERRCTRL1, 0x67); + } else { + stv0900_write_reg(intp, ERRCTRL1, 0x75); + } + + stv0900_write_reg(intp, FBERCPT4, 0); + stv0900_write_reg(intp, ERRCTRL2, 0xc1); + } else { + lock = FALSE; + signal_type = STV0900_NODATA; + no_signal = stv0900_check_signal_presence(intp, demod); + + intp->result[demod].locked = FALSE; + } + } + + if ((signal_type != STV0900_NODATA) || (no_signal != FALSE)) + return signal_type; + + if (intp->chip_id > 0x11) { + intp->result[demod].locked = FALSE; + return signal_type; + } + + if ((stv0900_get_bits(intp, HEADER_MODE) == STV0900_DVBS_FOUND) && + (intp->srch_iq_inv[demod] <= STV0900_IQ_AUTO_NORMAL_FIRST)) + signal_type = stv0900_dvbs1_acq_workaround(fe); + + return signal_type; +} +