--- zzzz-none-000/linux-3.10.107/drivers/media/dvb-frontends/dib8000.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/media/dvb-frontends/dib8000.c 2021-02-04 17:41:59.000000000 +0000 @@ -11,6 +11,7 @@ #include #include #include +#include #include "dvb_math.h" @@ -114,10 +115,16 @@ u16 found_guard; u8 subchannel; u8 symbol_duration; - u32 timeout; + unsigned long timeout; u8 longest_intlv_layer; u16 output_mode; + /* for DVBv5 stats */ + s64 init_ucb; + unsigned long per_jiffies_stats; + unsigned long ber_jiffies_stats; + unsigned long ber_jiffies_stats_layer[3]; + #ifdef DIB8000_AGC_FREEZE u16 agc1_max; u16 agc1_min; @@ -581,8 +588,8 @@ break; case DIBX000_ADC_OFF: // leave the VBG voltage on - reg_907 |= (1 << 14) | (1 << 13) | (1 << 12); - reg_908 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2); + reg_907 = (1 << 13) | (1 << 12); + reg_908 = (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 1); break; case DIBX000_VBG_ENABLE: @@ -649,7 +656,7 @@ return 0; } -int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value) +static int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value) { struct dib8000_state *state = fe->demodulator_priv; if (value > 4095) @@ -657,7 +664,6 @@ state->wbd_ref = value; return dib8000_write_word(state, 106, value); } -EXPORT_SYMBOL(dib8000_set_wbd_ref); static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw) { @@ -732,7 +738,7 @@ dib8000_reset_pll_common(state, pll); } -int dib8000_update_pll(struct dvb_frontend *fe, +static int dib8000_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio) { struct dib8000_state *state = fe->demodulator_priv; @@ -804,12 +810,10 @@ dprintk("PLL: Update ratio (prediv: %d, ratio: %d)", state->cfg.pll->pll_prediv, ratio); dib8000_write_word(state, 901, (state->cfg.pll->pll_prediv << 8) | (ratio << 0)); /* only the PLL ratio is updated. */ } -} + } return 0; } -EXPORT_SYMBOL(dib8000_update_pll); - static int dib8000_reset_gpio(struct dib8000_state *st) { @@ -842,13 +846,12 @@ return 0; } -int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) +static int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) { struct dib8000_state *state = fe->demodulator_priv; return dib8000_cfg_gpio(state, num, dir, val); } -EXPORT_SYMBOL(dib8000_set_gpio); static const u16 dib8000_defaults[] = { /* auto search configuration - lock0 by default waiting * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */ @@ -983,6 +986,45 @@ return value; } +static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 *unc); + +static void dib8000_reset_stats(struct dvb_frontend *fe) +{ + struct dib8000_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; + u32 ucb; + + memset(&c->strength, 0, sizeof(c->strength)); + memset(&c->cnr, 0, sizeof(c->cnr)); + memset(&c->post_bit_error, 0, sizeof(c->post_bit_error)); + memset(&c->post_bit_count, 0, sizeof(c->post_bit_count)); + memset(&c->block_error, 0, sizeof(c->block_error)); + + c->strength.len = 1; + c->cnr.len = 1; + c->block_error.len = 1; + c->block_count.len = 1; + c->post_bit_error.len = 1; + c->post_bit_count.len = 1; + + c->strength.stat[0].scale = FE_SCALE_DECIBEL; + c->strength.stat[0].uvalue = 0; + + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + + dib8000_read_unc_blocks(fe, &ucb); + + state->init_ucb = -ucb; + state->ber_jiffies_stats = 0; + state->per_jiffies_stats = 0; + memset(&state->ber_jiffies_stats_layer, 0, + sizeof(state->ber_jiffies_stats_layer)); +} + static int dib8000_reset(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; @@ -1008,6 +1050,7 @@ dib8000_write_word(state, 770, 0xffff); dib8000_write_word(state, 771, 0xffff); dib8000_write_word(state, 772, 0xfffc); + dib8000_write_word(state, 898, 0x000c); /* restart sad */ if (state->revision == 0x8090) dib8000_write_word(state, 1280, 0x0045); else @@ -1088,6 +1131,8 @@ dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY); + dib8000_reset_stats(fe); + return 0; } @@ -1180,20 +1225,19 @@ return 0; } -void dib8000_pwm_agc_reset(struct dvb_frontend *fe) +static void dib8000_pwm_agc_reset(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; dib8000_set_adc_state(state, DIBX000_ADC_ON); dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))); } -EXPORT_SYMBOL(dib8000_pwm_agc_reset); static int dib8000_agc_soft_split(struct dib8000_state *state) { u16 agc, split_offset; if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0) - return FE_CALLBACK_TIME_NEVER; + return 0; // n_agc_global agc = dib8000_read_word(state, 390); @@ -1219,7 +1263,8 @@ struct dib8000_state *state = fe->demodulator_priv; enum frontend_tune_state *tune_state = &state->tune_state; int ret = 0; - u16 reg, upd_demod_gain_period = 0x8000; + u16 reg; + u32 upd_demod_gain_period = 0x8000; switch (*tune_state) { case CT_AGC_START: @@ -1833,14 +1878,13 @@ .functionality = dib8096p_i2c_func, }; -struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe) +static struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe) { struct dib8000_state *st = fe->demodulator_priv; return &st->dib8096p_tuner_adap; } -EXPORT_SYMBOL(dib8096p_get_i2c_tuner); -int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff) +static int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff) { struct dib8000_state *state = fe->demodulator_priv; u16 en_cur_state; @@ -1864,14 +1908,13 @@ return 0; } -EXPORT_SYMBOL(dib8096p_tuner_sleep); static const s32 lut_1000ln_mant[] = { 908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600 }; -s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode) +static s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode) { struct dib8000_state *state = fe->demodulator_priv; u32 ix = 0, tmp_val = 0, exp = 0, mant = 0; @@ -1889,9 +1932,8 @@ } return val; } -EXPORT_SYMBOL(dib8000_get_adc_power); -int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ) +static int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ) { struct dib8000_state *state = fe->demodulator_priv; int val = 0; @@ -1909,7 +1951,6 @@ return val; } -EXPORT_SYMBOL(dib8090p_get_dc_power); static void dib8000_update_timf(struct dib8000_state *state) { @@ -1920,7 +1961,7 @@ dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default); } -u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf) +static u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf) { struct dib8000_state *state = fe->demodulator_priv; @@ -1938,21 +1979,11 @@ return state->timf; } -EXPORT_SYMBOL(dib8000_ctrl_timf); static const u16 adc_target_16dB[11] = { - (1 << 13) - 825 - 117, - (1 << 13) - 837 - 117, - (1 << 13) - 811 - 117, - (1 << 13) - 766 - 117, - (1 << 13) - 737 - 117, - (1 << 13) - 693 - 117, - (1 << 13) - 648 - 117, - (1 << 13) - 619 - 117, - (1 << 13) - 575 - 117, - (1 << 13) - 531 - 117, - (1 << 13) - 501 - 117 + 7250, 7238, 7264, 7309, 7338, 7382, 7427, 7456, 7500, 7544, 7574 }; + static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 }; static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 max_constellation) @@ -1995,9 +2026,8 @@ break; } - if ((c->layer[layer_index].interleaving > 0) && ((c->layer[layer_index].interleaving <= 3) || (c->layer[layer_index].interleaving == 4 && c->isdbt_sb_mode == 1))) - time_intlv = c->layer[layer_index].interleaving; - else + time_intlv = fls(c->layer[layer_index].interleaving); + if (time_intlv > 3 && !(time_intlv == 4 && c->isdbt_sb_mode == 1)) time_intlv = 0; dib8000_write_word(state, 2 + layer_index, (constellation << 10) | ((c->layer[layer_index].segment_count & 0xf) << 6) | (cr << 3) | time_intlv); @@ -2314,6 +2344,9 @@ int init_prbs; struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; + if (autosearching) + c->isdbt_partial_reception = 1; + /* P_mode */ dib8000_write_word(state, 10, (seq << 4)); @@ -2808,12 +2841,12 @@ dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | (sync_wait << 4)); } -static u32 dib8000_get_timeout(struct dib8000_state *state, u32 delay, enum timeout_mode mode) +static unsigned long dib8000_get_timeout(struct dib8000_state *state, u32 delay, enum timeout_mode mode) { if (mode == SYMBOL_DEPENDENT_ON) - return systime() + (delay * state->symbol_duration); - else - return systime() + delay; + delay *= state->symbol_duration; + + return jiffies + usecs_to_jiffies(delay * 100); } static s32 dib8000_get_status(struct dvb_frontend *fe) @@ -2822,21 +2855,19 @@ return state->status; } -enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe) +static enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; return state->tune_state; } -EXPORT_SYMBOL(dib8000_get_tune_state); -int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) +static int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) { struct dib8000_state *state = fe->demodulator_priv; state->tune_state = tune_state; return 0; } -EXPORT_SYMBOL(dib8000_set_tune_state); static int dib8000_tune_restart_from_demod(struct dvb_frontend *fe) { @@ -2873,6 +2904,91 @@ return 0; } +/** + * is_manual_mode - Check if TMCC should be used for parameters settings + * @c: struct dvb_frontend_properties + * + * By default, TMCC table should be used for parameter settings on most + * usercases. However, sometimes it is desirable to lock the demod to + * use the manual parameters. + * + * On manual mode, the current dib8000_tune state machine is very restrict: + * It requires that both per-layer and per-transponder parameters to be + * properly specified, otherwise the device won't lock. + * + * Check if all those conditions are properly satisfied before allowing + * the device to use the manual frequency lock mode. + */ +static int is_manual_mode(struct dtv_frontend_properties *c) +{ + int i, n_segs = 0; + + /* Use auto mode on DVB-T compat mode */ + if (c->delivery_system != SYS_ISDBT) + return 0; + + /* + * Transmission mode is only detected on auto mode, currently + */ + if (c->transmission_mode == TRANSMISSION_MODE_AUTO) { + dprintk("transmission mode auto"); + return 0; + } + + /* + * Guard interval is only detected on auto mode, currently + */ + if (c->guard_interval == GUARD_INTERVAL_AUTO) { + dprintk("guard interval auto"); + return 0; + } + + /* + * If no layer is enabled, assume auto mode, as at least one + * layer should be enabled + */ + if (!c->isdbt_layer_enabled) { + dprintk("no layer modulation specified"); + return 0; + } + + /* + * Check if the per-layer parameters aren't auto and + * disable a layer if segment count is 0 or invalid. + */ + for (i = 0; i < 3; i++) { + if (!(c->isdbt_layer_enabled & 1 << i)) + continue; + + if ((c->layer[i].segment_count > 13) || + (c->layer[i].segment_count == 0)) { + c->isdbt_layer_enabled &= ~(1 << i); + continue; + } + + n_segs += c->layer[i].segment_count; + + if ((c->layer[i].modulation == QAM_AUTO) || + (c->layer[i].fec == FEC_AUTO)) { + dprintk("layer %c has either modulation or FEC auto", + 'A' + i); + return 0; + } + } + + /* + * Userspace specified a wrong number of segments. + * fallback to auto mode. + */ + if (n_segs == 0 || n_segs > 13) { + dprintk("number of segments is invalid"); + return 0; + } + + /* Everything looks ok for manual mode */ + return 1; +} + static int dib8000_tune(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; @@ -2882,8 +2998,8 @@ u16 locks, deeper_interleaver = 0, i; int ret = 1; /* 1 symbol duration (in 100us unit) delay most of the time */ - u32 *timeout = &state->timeout; - u32 now = systime(); + unsigned long *timeout = &state->timeout; + unsigned long now = jiffies; #ifdef DIB8000_AGC_FREEZE u16 agc1, agc2; #endif @@ -2893,339 +3009,327 @@ #if 0 if (*tune_state < CT_DEMOD_STOP) - dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u systime = %u", state->channel_parameters_set, *tune_state, state->autosearch_state, now); + dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u jiffies = %lu", + state->channel_parameters_set, *tune_state, state->autosearch_state, now); #endif switch (*tune_state) { case CT_DEMOD_START: /* 30 */ - if (state->revision == 0x8090) - dib8090p_init_sdram(state); - state->status = FE_STATUS_TUNE_PENDING; - if ((c->delivery_system != SYS_ISDBT) || - (c->inversion == INVERSION_AUTO) || - (c->transmission_mode == TRANSMISSION_MODE_AUTO) || - (c->guard_interval == GUARD_INTERVAL_AUTO) || - (((c->isdbt_layer_enabled & (1 << 0)) != 0) && - (c->layer[0].segment_count != 0xff) && - (c->layer[0].segment_count != 0) && - ((c->layer[0].modulation == QAM_AUTO) || - (c->layer[0].fec == FEC_AUTO))) || - (((c->isdbt_layer_enabled & (1 << 1)) != 0) && - (c->layer[1].segment_count != 0xff) && - (c->layer[1].segment_count != 0) && - ((c->layer[1].modulation == QAM_AUTO) || - (c->layer[1].fec == FEC_AUTO))) || - (((c->isdbt_layer_enabled & (1 << 2)) != 0) && - (c->layer[2].segment_count != 0xff) && - (c->layer[2].segment_count != 0) && - ((c->layer[2].modulation == QAM_AUTO) || - (c->layer[2].fec == FEC_AUTO))) || - (((c->layer[0].segment_count == 0) || - ((c->isdbt_layer_enabled & (1 << 0)) == 0)) && - ((c->layer[1].segment_count == 0) || - ((c->isdbt_layer_enabled & (2 << 0)) == 0)) && - ((c->layer[2].segment_count == 0) || ((c->isdbt_layer_enabled & (3 << 0)) == 0)))) - state->channel_parameters_set = 0; /* auto search */ - else - state->channel_parameters_set = 1; /* channel parameters are known */ + dib8000_reset_stats(fe); + + if (state->revision == 0x8090) + dib8090p_init_sdram(state); + state->status = FE_STATUS_TUNE_PENDING; + state->channel_parameters_set = is_manual_mode(c); + + dprintk("Tuning channel on %s search mode", + state->channel_parameters_set ? "manual" : "auto"); - dib8000_viterbi_state(state, 0); /* force chan dec in restart */ + dib8000_viterbi_state(state, 0); /* force chan dec in restart */ - /* Layer monit */ - dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60); + /* Layer monitor */ + dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60); - dib8000_set_frequency_offset(state); - dib8000_set_bandwidth(fe, c->bandwidth_hz / 1000); + dib8000_set_frequency_offset(state); + dib8000_set_bandwidth(fe, c->bandwidth_hz / 1000); - if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */ + if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */ #ifdef DIB8000_AGC_FREEZE - if (state->revision != 0x8090) { - state->agc1_max = dib8000_read_word(state, 108); - state->agc1_min = dib8000_read_word(state, 109); - state->agc2_max = dib8000_read_word(state, 110); - state->agc2_min = dib8000_read_word(state, 111); - agc1 = dib8000_read_word(state, 388); - agc2 = dib8000_read_word(state, 389); - dib8000_write_word(state, 108, agc1); - dib8000_write_word(state, 109, agc1); - dib8000_write_word(state, 110, agc2); - dib8000_write_word(state, 111, agc2); - } -#endif - state->autosearch_state = AS_SEARCHING_FFT; - state->found_nfft = TRANSMISSION_MODE_AUTO; - state->found_guard = GUARD_INTERVAL_AUTO; - *tune_state = CT_DEMOD_SEARCH_NEXT; - } else { /* we already know the channel struct so TUNE only ! */ - state->autosearch_state = AS_DONE; - *tune_state = CT_DEMOD_STEP_3; + if (state->revision != 0x8090) { + state->agc1_max = dib8000_read_word(state, 108); + state->agc1_min = dib8000_read_word(state, 109); + state->agc2_max = dib8000_read_word(state, 110); + state->agc2_min = dib8000_read_word(state, 111); + agc1 = dib8000_read_word(state, 388); + agc2 = dib8000_read_word(state, 389); + dib8000_write_word(state, 108, agc1); + dib8000_write_word(state, 109, agc1); + dib8000_write_word(state, 110, agc2); + dib8000_write_word(state, 111, agc2); } - state->symbol_duration = dib8000_get_symbol_duration(state); - break; +#endif + state->autosearch_state = AS_SEARCHING_FFT; + state->found_nfft = TRANSMISSION_MODE_AUTO; + state->found_guard = GUARD_INTERVAL_AUTO; + *tune_state = CT_DEMOD_SEARCH_NEXT; + } else { /* we already know the channel struct so TUNE only ! */ + state->autosearch_state = AS_DONE; + *tune_state = CT_DEMOD_STEP_3; + } + state->symbol_duration = dib8000_get_symbol_duration(state); + break; case CT_DEMOD_SEARCH_NEXT: /* 51 */ - dib8000_autosearch_start(fe); - if (state->revision == 0x8090) - ret = 50; - else - ret = 15; - *tune_state = CT_DEMOD_STEP_1; - break; + dib8000_autosearch_start(fe); + if (state->revision == 0x8090) + ret = 50; + else + ret = 15; + *tune_state = CT_DEMOD_STEP_1; + break; case CT_DEMOD_STEP_1: /* 31 */ - switch (dib8000_autosearch_irq(fe)) { - case 1: /* fail */ - state->status = FE_STATUS_TUNE_FAILED; - state->autosearch_state = AS_DONE; - *tune_state = CT_DEMOD_STOP; /* else we are done here */ - break; - case 2: /* Succes */ - state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */ - *tune_state = CT_DEMOD_STEP_3; - if (state->autosearch_state == AS_SEARCHING_GUARD) - *tune_state = CT_DEMOD_STEP_2; - else - state->autosearch_state = AS_DONE; - break; - case 3: /* Autosearch FFT max correlation endded */ - *tune_state = CT_DEMOD_STEP_2; - break; - } + switch (dib8000_autosearch_irq(fe)) { + case 1: /* fail */ + state->status = FE_STATUS_TUNE_FAILED; + state->autosearch_state = AS_DONE; + *tune_state = CT_DEMOD_STOP; /* else we are done here */ + break; + case 2: /* Succes */ + state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */ + *tune_state = CT_DEMOD_STEP_3; + if (state->autosearch_state == AS_SEARCHING_GUARD) + *tune_state = CT_DEMOD_STEP_2; + else + state->autosearch_state = AS_DONE; break; + case 3: /* Autosearch FFT max correlation endded */ + *tune_state = CT_DEMOD_STEP_2; + break; + } + break; case CT_DEMOD_STEP_2: - switch (state->autosearch_state) { - case AS_SEARCHING_FFT: - /* searching for the correct FFT */ - if (state->revision == 0x8090) { - corm[2] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597)); - corm[1] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599)); - corm[0] = (dib8000_read_word(state, 600) << 16) | (dib8000_read_word(state, 601)); - } else { - corm[2] = (dib8000_read_word(state, 594) << 16) | (dib8000_read_word(state, 595)); - corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597)); - corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599)); - } - /* dprintk("corm fft: %u %u %u", corm[0], corm[1], corm[2]); */ - - max_value = 0; - for (find_index = 1 ; find_index < 3 ; find_index++) { - if (corm[max_value] < corm[find_index]) - max_value = find_index ; - } - - switch (max_value) { - case 0: - state->found_nfft = TRANSMISSION_MODE_2K; - break; - case 1: - state->found_nfft = TRANSMISSION_MODE_4K; - break; - case 2: - default: - state->found_nfft = TRANSMISSION_MODE_8K; - break; - } - /* dprintk("Autosearch FFT has found Mode %d", max_value + 1); */ + switch (state->autosearch_state) { + case AS_SEARCHING_FFT: + /* searching for the correct FFT */ + if (state->revision == 0x8090) { + corm[2] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597)); + corm[1] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599)); + corm[0] = (dib8000_read_word(state, 600) << 16) | (dib8000_read_word(state, 601)); + } else { + corm[2] = (dib8000_read_word(state, 594) << 16) | (dib8000_read_word(state, 595)); + corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597)); + corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599)); + } + /* dprintk("corm fft: %u %u %u", corm[0], corm[1], corm[2]); */ - *tune_state = CT_DEMOD_SEARCH_NEXT; - state->autosearch_state = AS_SEARCHING_GUARD; - if (state->revision == 0x8090) - ret = 50; - else - ret = 10; - break; - case AS_SEARCHING_GUARD: - /* searching for the correct guard interval */ - if (state->revision == 0x8090) - state->found_guard = dib8000_read_word(state, 572) & 0x3; - else - state->found_guard = dib8000_read_word(state, 570) & 0x3; - /* dprintk("guard interval found=%i", state->found_guard); */ + max_value = 0; + for (find_index = 1 ; find_index < 3 ; find_index++) { + if (corm[max_value] < corm[find_index]) + max_value = find_index ; + } - *tune_state = CT_DEMOD_STEP_3; - break; + switch (max_value) { + case 0: + state->found_nfft = TRANSMISSION_MODE_2K; + break; + case 1: + state->found_nfft = TRANSMISSION_MODE_4K; + break; + case 2: default: - /* the demod should never be in this state */ - state->status = FE_STATUS_TUNE_FAILED; - state->autosearch_state = AS_DONE; - *tune_state = CT_DEMOD_STOP; /* else we are done here */ - break; + state->found_nfft = TRANSMISSION_MODE_8K; + break; } + /* dprintk("Autosearch FFT has found Mode %d", max_value + 1); */ + + *tune_state = CT_DEMOD_SEARCH_NEXT; + state->autosearch_state = AS_SEARCHING_GUARD; + if (state->revision == 0x8090) + ret = 50; + else + ret = 10; break; + case AS_SEARCHING_GUARD: + /* searching for the correct guard interval */ + if (state->revision == 0x8090) + state->found_guard = dib8000_read_word(state, 572) & 0x3; + else + state->found_guard = dib8000_read_word(state, 570) & 0x3; + /* dprintk("guard interval found=%i", state->found_guard); */ - case CT_DEMOD_STEP_3: /* 33 */ - state->symbol_duration = dib8000_get_symbol_duration(state); - dib8000_set_isdbt_loop_params(state, LOOP_TUNE_1); - dib8000_set_isdbt_common_channel(state, 0, 0);/* setting the known channel parameters here */ - *tune_state = CT_DEMOD_STEP_4; + *tune_state = CT_DEMOD_STEP_3; + break; + default: + /* the demod should never be in this state */ + state->status = FE_STATUS_TUNE_FAILED; + state->autosearch_state = AS_DONE; + *tune_state = CT_DEMOD_STOP; /* else we are done here */ break; + } + break; + + case CT_DEMOD_STEP_3: /* 33 */ + dib8000_set_isdbt_loop_params(state, LOOP_TUNE_1); + dib8000_set_isdbt_common_channel(state, 0, 0);/* setting the known channel parameters here */ + *tune_state = CT_DEMOD_STEP_4; + break; case CT_DEMOD_STEP_4: /* (34) */ - dib8000_demod_restart(state); + dib8000_demod_restart(state); - dib8000_set_sync_wait(state); - dib8000_set_diversity_in(state->fe[0], state->diversity_onoff); + dib8000_set_sync_wait(state); + dib8000_set_diversity_in(state->fe[0], state->diversity_onoff); - locks = (dib8000_read_word(state, 180) >> 6) & 0x3f; /* P_coff_winlen ? */ - /* coff should lock over P_coff_winlen ofdm symbols : give 3 times this lenght to lock */ - *timeout = dib8000_get_timeout(state, 2 * locks, SYMBOL_DEPENDENT_ON); - *tune_state = CT_DEMOD_STEP_5; - break; + locks = (dib8000_read_word(state, 180) >> 6) & 0x3f; /* P_coff_winlen ? */ + /* coff should lock over P_coff_winlen ofdm symbols : give 3 times this length to lock */ + *timeout = dib8000_get_timeout(state, 2 * locks, SYMBOL_DEPENDENT_ON); + *tune_state = CT_DEMOD_STEP_5; + break; case CT_DEMOD_STEP_5: /* (35) */ - locks = dib8000_read_lock(fe); - if (locks & (0x3 << 11)) { /* coff-lock and off_cpil_lock achieved */ - dib8000_update_timf(state); /* we achieved a coff_cpil_lock - it's time to update the timf */ - if (!state->differential_constellation) { - /* 2 times lmod4_win_len + 10 symbols (pipe delay after coff + nb to compute a 1st correlation) */ - *timeout = dib8000_get_timeout(state, (20 * ((dib8000_read_word(state, 188)>>5)&0x1f)), SYMBOL_DEPENDENT_ON); - *tune_state = CT_DEMOD_STEP_7; - } else { - *tune_state = CT_DEMOD_STEP_8; - } - } else if (now > *timeout) { - *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */ + locks = dib8000_read_lock(fe); + if (locks & (0x3 << 11)) { /* coff-lock and off_cpil_lock achieved */ + dib8000_update_timf(state); /* we achieved a coff_cpil_lock - it's time to update the timf */ + if (!state->differential_constellation) { + /* 2 times lmod4_win_len + 10 symbols (pipe delay after coff + nb to compute a 1st correlation) */ + *timeout = dib8000_get_timeout(state, (20 * ((dib8000_read_word(state, 188)>>5)&0x1f)), SYMBOL_DEPENDENT_ON); + *tune_state = CT_DEMOD_STEP_7; + } else { + *tune_state = CT_DEMOD_STEP_8; } - break; + } else if (time_after(now, *timeout)) { + *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */ + } + break; case CT_DEMOD_STEP_6: /* (36) if there is an input (diversity) */ - if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) { - /* if there is a diversity fe in input and this fe is has not already failled : wait here until this this fe has succedeed or failled */ - if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */ - *tune_state = CT_DEMOD_STEP_8; /* go for mpeg */ - else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failled also, break the current one */ - *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */ - dib8000_viterbi_state(state, 1); /* start viterbi chandec */ - dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2); - state->status = FE_STATUS_TUNE_FAILED; - } - } else { + if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) { + /* if there is a diversity fe in input and this fe is has not already failled : wait here until this this fe has succedeed or failled */ + if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */ + *tune_state = CT_DEMOD_STEP_8; /* go for mpeg */ + else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failled also, break the current one */ + *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */ dib8000_viterbi_state(state, 1); /* start viterbi chandec */ dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2); - *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */ state->status = FE_STATUS_TUNE_FAILED; } - break; + } else { + dib8000_viterbi_state(state, 1); /* start viterbi chandec */ + dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2); + *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */ + state->status = FE_STATUS_TUNE_FAILED; + } + break; case CT_DEMOD_STEP_7: /* 37 */ - locks = dib8000_read_lock(fe); - if (locks & (1<<10)) { /* lmod4_lock */ - ret = 14; /* wait for 14 symbols */ - *tune_state = CT_DEMOD_STEP_8; - } else if (now > *timeout) - *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */ - break; + locks = dib8000_read_lock(fe); + if (locks & (1<<10)) { /* lmod4_lock */ + ret = 14; /* wait for 14 symbols */ + *tune_state = CT_DEMOD_STEP_8; + } else if (time_after(now, *timeout)) + *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */ + break; case CT_DEMOD_STEP_8: /* 38 */ - dib8000_viterbi_state(state, 1); /* start viterbi chandec */ - dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2); + dib8000_viterbi_state(state, 1); /* start viterbi chandec */ + dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2); - /* mpeg will never lock on this condition because init_prbs is not set : search for it !*/ - if (c->isdbt_sb_mode - && c->isdbt_sb_subchannel < 14 - && !state->differential_constellation) { - state->subchannel = 0; - *tune_state = CT_DEMOD_STEP_11; - } else { - *tune_state = CT_DEMOD_STEP_9; - state->status = FE_STATUS_LOCKED; - } - break; + /* mpeg will never lock on this condition because init_prbs is not set : search for it !*/ + if (c->isdbt_sb_mode + && c->isdbt_sb_subchannel < 14 + && !state->differential_constellation) { + state->subchannel = 0; + *tune_state = CT_DEMOD_STEP_11; + } else { + *tune_state = CT_DEMOD_STEP_9; + state->status = FE_STATUS_LOCKED; + } + break; case CT_DEMOD_STEP_9: /* 39 */ - if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */ - /* defines timeout for mpeg lock depending on interleaver lenght of longest layer */ - for (i = 0; i < 3; i++) { - if (c->layer[i].interleaving >= deeper_interleaver) { - dprintk("layer%i: time interleaver = %d ", i, c->layer[i].interleaving); - if (c->layer[i].segment_count > 0) { /* valid layer */ - deeper_interleaver = c->layer[0].interleaving; - state->longest_intlv_layer = i; - } + if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */ + /* defines timeout for mpeg lock depending on interleaver length of longest layer */ + for (i = 0; i < 3; i++) { + if (c->layer[i].interleaving >= deeper_interleaver) { + dprintk("layer%i: time interleaver = %d ", i, c->layer[i].interleaving); + if (c->layer[i].segment_count > 0) { /* valid layer */ + deeper_interleaver = c->layer[0].interleaving; + state->longest_intlv_layer = i; } } + } - if (deeper_interleaver == 0) - locks = 2; /* locks is the tmp local variable name */ - else if (deeper_interleaver == 3) - locks = 8; - else - locks = 2 * deeper_interleaver; + if (deeper_interleaver == 0) + locks = 2; /* locks is the tmp local variable name */ + else if (deeper_interleaver == 3) + locks = 8; + else + locks = 2 * deeper_interleaver; - if (state->diversity_onoff != 0) /* because of diversity sync */ - locks *= 2; + if (state->diversity_onoff != 0) /* because of diversity sync */ + locks *= 2; - *timeout = now + (2000 * locks); /* give the mpeg lock 800ms if sram is present */ - dprintk("Deeper interleaver mode = %d on layer %d : timeout mult factor = %d => will use timeout = %d", deeper_interleaver, state->longest_intlv_layer, locks, *timeout); + *timeout = now + msecs_to_jiffies(200 * locks); /* give the mpeg lock 800ms if sram is present */ + dprintk("Deeper interleaver mode = %d on layer %d : timeout mult factor = %d => will use timeout = %ld", + deeper_interleaver, state->longest_intlv_layer, locks, *timeout); - *tune_state = CT_DEMOD_STEP_10; - } else - *tune_state = CT_DEMOD_STOP; - break; + *tune_state = CT_DEMOD_STEP_10; + } else + *tune_state = CT_DEMOD_STOP; + break; case CT_DEMOD_STEP_10: /* 40 */ - locks = dib8000_read_lock(fe); - if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */ - dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1); - if (c->isdbt_sb_mode - && c->isdbt_sb_subchannel < 14 - && !state->differential_constellation) - /* signal to the upper layer, that there was a channel found and the parameters can be read */ - state->status = FE_STATUS_DEMOD_SUCCESS; - else + locks = dib8000_read_lock(fe); + if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */ + dprintk("ISDB-T layer locks: Layer A %s, Layer B %s, Layer C %s", + c->layer[0].segment_count ? (locks >> 7) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled", + c->layer[1].segment_count ? (locks >> 6) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled", + c->layer[2].segment_count ? (locks >> 5) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled"); + if (c->isdbt_sb_mode + && c->isdbt_sb_subchannel < 14 + && !state->differential_constellation) + /* signal to the upper layer, that there was a channel found and the parameters can be read */ + state->status = FE_STATUS_DEMOD_SUCCESS; + else + state->status = FE_STATUS_DATA_LOCKED; + *tune_state = CT_DEMOD_STOP; + } else if (time_after(now, *timeout)) { + if (c->isdbt_sb_mode + && c->isdbt_sb_subchannel < 14 + && !state->differential_constellation) { /* continue to try init prbs autosearch */ + state->subchannel += 3; + *tune_state = CT_DEMOD_STEP_11; + } else { /* we are done mpeg of the longest interleaver xas not locking but let's try if an other layer has locked in the same time */ + if (locks & (0x7 << 5)) { + dprintk("Not all ISDB-T layers locked in %d ms: Layer A %s, Layer B %s, Layer C %s", + jiffies_to_msecs(now - *timeout), + c->layer[0].segment_count ? (locks >> 7) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled", + c->layer[1].segment_count ? (locks >> 6) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled", + c->layer[2].segment_count ? (locks >> 5) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled"); + state->status = FE_STATUS_DATA_LOCKED; + } else + state->status = FE_STATUS_TUNE_FAILED; *tune_state = CT_DEMOD_STOP; - } else if (now > *timeout) { - if (c->isdbt_sb_mode - && c->isdbt_sb_subchannel < 14 - && !state->differential_constellation) { /* continue to try init prbs autosearch */ - state->subchannel += 3; - *tune_state = CT_DEMOD_STEP_11; - } else { /* we are done mpeg of the longest interleaver xas not locking but let's try if an other layer has locked in the same time */ - if (locks & (0x7<<5)) { - dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1); - state->status = FE_STATUS_DATA_LOCKED; - } else - state->status = FE_STATUS_TUNE_FAILED; - *tune_state = CT_DEMOD_STOP; - } } - break; + } + break; case CT_DEMOD_STEP_11: /* 41 : init prbs autosearch */ - if (state->subchannel <= 41) { - dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel)); - *tune_state = CT_DEMOD_STEP_9; - } else { - *tune_state = CT_DEMOD_STOP; - state->status = FE_STATUS_TUNE_FAILED; - } - break; + if (state->subchannel <= 41) { + dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel)); + *tune_state = CT_DEMOD_STEP_9; + } else { + *tune_state = CT_DEMOD_STOP; + state->status = FE_STATUS_TUNE_FAILED; + } + break; default: - break; + break; } /* tuning is finished - cleanup the demod */ switch (*tune_state) { case CT_DEMOD_STOP: /* (42) */ #ifdef DIB8000_AGC_FREEZE - if ((state->revision != 0x8090) && (state->agc1_max != 0)) { - dib8000_write_word(state, 108, state->agc1_max); - dib8000_write_word(state, 109, state->agc1_min); - dib8000_write_word(state, 110, state->agc2_max); - dib8000_write_word(state, 111, state->agc2_min); - state->agc1_max = 0; - state->agc1_min = 0; - state->agc2_max = 0; - state->agc2_min = 0; - } + if ((state->revision != 0x8090) && (state->agc1_max != 0)) { + dib8000_write_word(state, 108, state->agc1_max); + dib8000_write_word(state, 109, state->agc1_min); + dib8000_write_word(state, 110, state->agc2_max); + dib8000_write_word(state, 111, state->agc2_min); + state->agc1_max = 0; + state->agc1_min = 0; + state->agc2_max = 0; + state->agc2_min = 0; + } #endif - ret = FE_CALLBACK_TIME_NEVER; - break; + ret = 0; + break; default: - break; + break; } if ((ret > 0) && (*tune_state > CT_DEMOD_STEP_3)) @@ -3276,15 +3380,27 @@ return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF); } +static int dib8000_read_status(struct dvb_frontend *fe, enum fe_status *stat); + static int dib8000_get_frontend(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; u16 i, val = 0; - fe_status_t stat; + enum fe_status stat = 0; u8 index_frontend, sub_index_frontend; fe->dtv_property_cache.bandwidth_hz = 6000000; + /* + * If called to early, get_frontend makes dib8000_tune to either + * not lock or not sync. This causes dvbv5-scan/dvbv5-zap to fail. + * So, let's just return if frontend 0 has not locked. + */ + dib8000_read_status(fe, &stat); + if (!(stat & FE_HAS_SYNC)) + return 0; + + dprintk("dib8000_get_frontend: TMCC lock"); for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat); if (stat&FE_HAS_SYNC) { @@ -3320,87 +3436,117 @@ switch ((val & 0x30) >> 4) { case 1: fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K; + dprintk("dib8000_get_frontend: transmission mode 2K"); + break; + case 2: + fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_4K; + dprintk("dib8000_get_frontend: transmission mode 4K"); break; case 3: default: fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; + dprintk("dib8000_get_frontend: transmission mode 8K"); break; } switch (val & 0x3) { case 0: fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32; - dprintk("dib8000_get_frontend GI = 1/32 "); + dprintk("dib8000_get_frontend: Guard Interval = 1/32 "); break; case 1: fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16; - dprintk("dib8000_get_frontend GI = 1/16 "); + dprintk("dib8000_get_frontend: Guard Interval = 1/16 "); break; case 2: - dprintk("dib8000_get_frontend GI = 1/8 "); + dprintk("dib8000_get_frontend: Guard Interval = 1/8 "); fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; break; case 3: - dprintk("dib8000_get_frontend GI = 1/4 "); + dprintk("dib8000_get_frontend: Guard Interval = 1/4 "); fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4; break; } val = dib8000_read_word(state, 505); fe->dtv_property_cache.isdbt_partial_reception = val & 1; - dprintk("dib8000_get_frontend : partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception); + dprintk("dib8000_get_frontend: partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception); for (i = 0; i < 3; i++) { - val = dib8000_read_word(state, 493 + i); - fe->dtv_property_cache.layer[i].segment_count = val & 0x0F; - dprintk("dib8000_get_frontend : Layer %d segments = %d ", i, fe->dtv_property_cache.layer[i].segment_count); - - val = dib8000_read_word(state, 499 + i); - fe->dtv_property_cache.layer[i].interleaving = val & 0x3; - dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ", i, fe->dtv_property_cache.layer[i].interleaving); + int show; + + val = dib8000_read_word(state, 493 + i) & 0x0f; + fe->dtv_property_cache.layer[i].segment_count = val; + + if (val == 0 || val > 13) + show = 0; + else + show = 1; + + if (show) + dprintk("dib8000_get_frontend: Layer %d segments = %d ", + i, fe->dtv_property_cache.layer[i].segment_count); + + val = dib8000_read_word(state, 499 + i) & 0x3; + /* Interleaving can be 0, 1, 2 or 4 */ + if (val == 3) + val = 4; + fe->dtv_property_cache.layer[i].interleaving = val; + if (show) + dprintk("dib8000_get_frontend: Layer %d time_intlv = %d ", + i, fe->dtv_property_cache.layer[i].interleaving); val = dib8000_read_word(state, 481 + i); switch (val & 0x7) { case 1: fe->dtv_property_cache.layer[i].fec = FEC_1_2; - dprintk("dib8000_get_frontend : Layer %d Code Rate = 1/2 ", i); + if (show) + dprintk("dib8000_get_frontend: Layer %d Code Rate = 1/2 ", i); break; case 2: fe->dtv_property_cache.layer[i].fec = FEC_2_3; - dprintk("dib8000_get_frontend : Layer %d Code Rate = 2/3 ", i); + if (show) + dprintk("dib8000_get_frontend: Layer %d Code Rate = 2/3 ", i); break; case 3: fe->dtv_property_cache.layer[i].fec = FEC_3_4; - dprintk("dib8000_get_frontend : Layer %d Code Rate = 3/4 ", i); + if (show) + dprintk("dib8000_get_frontend: Layer %d Code Rate = 3/4 ", i); break; case 5: fe->dtv_property_cache.layer[i].fec = FEC_5_6; - dprintk("dib8000_get_frontend : Layer %d Code Rate = 5/6 ", i); + if (show) + dprintk("dib8000_get_frontend: Layer %d Code Rate = 5/6 ", i); break; default: fe->dtv_property_cache.layer[i].fec = FEC_7_8; - dprintk("dib8000_get_frontend : Layer %d Code Rate = 7/8 ", i); + if (show) + dprintk("dib8000_get_frontend: Layer %d Code Rate = 7/8 ", i); break; } val = dib8000_read_word(state, 487 + i); switch (val & 0x3) { case 0: - dprintk("dib8000_get_frontend : Layer %d DQPSK ", i); fe->dtv_property_cache.layer[i].modulation = DQPSK; + if (show) + dprintk("dib8000_get_frontend: Layer %d DQPSK ", i); break; case 1: fe->dtv_property_cache.layer[i].modulation = QPSK; - dprintk("dib8000_get_frontend : Layer %d QPSK ", i); + if (show) + dprintk("dib8000_get_frontend: Layer %d QPSK ", i); break; case 2: fe->dtv_property_cache.layer[i].modulation = QAM_16; - dprintk("dib8000_get_frontend : Layer %d QAM16 ", i); + if (show) + dprintk("dib8000_get_frontend: Layer %d QAM16 ", i); break; case 3: default: - dprintk("dib8000_get_frontend : Layer %d QAM64 ", i); fe->dtv_property_cache.layer[i].modulation = QAM_64; + if (show) + dprintk("dib8000_get_frontend: Layer %d QAM64 ", i); break; } } @@ -3426,9 +3572,9 @@ { struct dib8000_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; - int l, i, active, time, ret, time_slave = FE_CALLBACK_TIME_NEVER; + int l, i, active, time, time_slave = 0; u8 exit_condition, index_frontend; - u32 delay, callback_time; + unsigned long delay, callback_time; if (c->frequency == 0) { dprintk("dib8000: must at least specify frequency "); @@ -3480,15 +3626,24 @@ time = dib8000_agc_startup(state->fe[0]); for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { time_slave = dib8000_agc_startup(state->fe[index_frontend]); - if (time == FE_CALLBACK_TIME_NEVER) + if (time == 0) time = time_slave; - else if ((time_slave != FE_CALLBACK_TIME_NEVER) && (time_slave > time)) + else if ((time_slave != 0) && (time_slave > time)) time = time_slave; } - if (time != FE_CALLBACK_TIME_NEVER) - msleep(time / 10); - else + if (time == 0) break; + + /* + * Despite dib8000_agc_startup returns time at a 0.1 ms range, + * the actual sleep time depends on CONFIG_HZ. The worse case + * is when CONFIG_HZ=100. In such case, the minimum granularity + * is 10ms. On some real field tests, the tuner sometimes don't + * lock when this timer is lower than 10ms. So, enforce a 10ms + * granularity. + */ + time = 10 * (time + 99)/100; + usleep_range(time * 1000, (time + 1) * 1000); exit_condition = 1; for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) { @@ -3503,11 +3658,14 @@ active = 1; do { - callback_time = FE_CALLBACK_TIME_NEVER; + callback_time = 0; for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { delay = dib8000_tune(state->fe[index_frontend]); - if (delay != FE_CALLBACK_TIME_NEVER) - delay += systime(); + if (delay != 0) { + delay = jiffies + usecs_to_jiffies(100 * delay); + if (!callback_time || delay < callback_time) + callback_time = delay; + } /* we are in autosearch */ if (state->channel_parameters_set == 0) { /* searching */ @@ -3518,6 +3676,7 @@ for (l = 0; (l < MAX_NUMBER_OF_FRONTENDS) && (state->fe[l] != NULL); l++) { if (l != index_frontend) { /* and for all frontend except the successful one */ + dprintk("Restarting frontend %d\n", l); dib8000_tune_restart_from_demod(state->fe[l]); state->fe[l]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode; @@ -3536,8 +3695,6 @@ } } } - if (delay < callback_time) - callback_time = delay; } /* tuning is done when the master frontend is done (failed or success) */ if (dib8000_get_status(state->fe[0]) == FE_STATUS_TUNE_FAILED || @@ -3553,12 +3710,12 @@ dprintk("tuning done with status %d", dib8000_get_status(state->fe[0])); } - if ((active == 1) && (callback_time == FE_CALLBACK_TIME_NEVER)) { + if ((active == 1) && (callback_time == 0)) { dprintk("strange callback time something went wrong"); active = 0; } - while ((active == 1) && (systime() < callback_time)) + while ((active == 1) && (time_before(jiffies, callback_time))) msleep(100); } while (active); @@ -3573,10 +3730,12 @@ } } - return ret; + return 0; } -static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat) +static int dib8000_get_stats(struct dvb_frontend *fe, enum fe_status stat); + +static int dib8000_read_status(struct dvb_frontend *fe, enum fe_status *stat) { struct dib8000_state *state = fe->demodulator_priv; u16 lock_slave = 0, lock; @@ -3613,6 +3772,7 @@ if (lock & 0x01) *stat |= FE_HAS_VITERBI; } + dib8000_get_stats(fe, *stat); return 0; } @@ -3719,7 +3879,358 @@ return 0; } -int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave) +struct per_layer_regs { + u16 lock, ber, per; +}; + +static const struct per_layer_regs per_layer_regs[] = { + { 554, 560, 562 }, + { 555, 576, 578 }, + { 556, 581, 583 }, +}; + +struct linear_segments { + unsigned x; + signed y; +}; + +/* + * Table to estimate signal strength in dBm. + * This table was empirically determinated by measuring the signal + * strength generated by a DTA-2111 RF generator directly connected into + * a dib8076 device (a PixelView PV-D231U stick), using a good quality + * 3 meters RC6 cable and good RC6 connectors. + * The real value can actually be different on other devices, depending + * on several factors, like if LNA is enabled or not, if diversity is + * enabled, type of connectors, etc. + * Yet, it is better to use this measure in dB than a random non-linear + * percentage value, especially for antenna adjustments. + * On my tests, the precision of the measure using this table is about + * 0.5 dB, with sounds reasonable enough. + */ +static struct linear_segments strength_to_db_table[] = { + { 55953, 108500 }, /* -22.5 dBm */ + { 55394, 108000 }, + { 53834, 107000 }, + { 52863, 106000 }, + { 52239, 105000 }, + { 52012, 104000 }, + { 51803, 103000 }, + { 51566, 102000 }, + { 51356, 101000 }, + { 51112, 100000 }, + { 50869, 99000 }, + { 50600, 98000 }, + { 50363, 97000 }, + { 50117, 96000 }, /* -35 dBm */ + { 49889, 95000 }, + { 49680, 94000 }, + { 49493, 93000 }, + { 49302, 92000 }, + { 48929, 91000 }, + { 48416, 90000 }, + { 48035, 89000 }, + { 47593, 88000 }, + { 47282, 87000 }, + { 46953, 86000 }, + { 46698, 85000 }, + { 45617, 84000 }, + { 44773, 83000 }, + { 43845, 82000 }, + { 43020, 81000 }, + { 42010, 80000 }, /* -51 dBm */ + { 0, 0 }, +}; + +static u32 interpolate_value(u32 value, struct linear_segments *segments, + unsigned len) +{ + u64 tmp64; + u32 dx; + s32 dy; + int i, ret; + + if (value >= segments[0].x) + return segments[0].y; + if (value < segments[len-1].x) + return segments[len-1].y; + + for (i = 1; i < len - 1; i++) { + /* If value is identical, no need to interpolate */ + if (value == segments[i].x) + return segments[i].y; + if (value > segments[i].x) + break; + } + + /* Linear interpolation between the two (x,y) points */ + dy = segments[i - 1].y - segments[i].y; + dx = segments[i - 1].x - segments[i].x; + + tmp64 = value - segments[i].x; + tmp64 *= dy; + do_div(tmp64, dx); + ret = segments[i].y + tmp64; + + return ret; +} + +static u32 dib8000_get_time_us(struct dvb_frontend *fe, int layer) +{ + struct dib8000_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; + int ini_layer, end_layer, i; + u64 time_us, tmp64; + u32 tmp, denom; + int guard, rate_num, rate_denum = 1, bits_per_symbol, nsegs; + int interleaving = 0, fft_div; + + if (layer >= 0) { + ini_layer = layer; + end_layer = layer + 1; + } else { + ini_layer = 0; + end_layer = 3; + } + + switch (c->guard_interval) { + case GUARD_INTERVAL_1_4: + guard = 4; + break; + case GUARD_INTERVAL_1_8: + guard = 8; + break; + case GUARD_INTERVAL_1_16: + guard = 16; + break; + default: + case GUARD_INTERVAL_1_32: + guard = 32; + break; + } + + switch (c->transmission_mode) { + case TRANSMISSION_MODE_2K: + fft_div = 4; + break; + case TRANSMISSION_MODE_4K: + fft_div = 2; + break; + default: + case TRANSMISSION_MODE_8K: + fft_div = 1; + break; + } + + denom = 0; + for (i = ini_layer; i < end_layer; i++) { + nsegs = c->layer[i].segment_count; + if (nsegs == 0 || nsegs > 13) + continue; + + switch (c->layer[i].modulation) { + case DQPSK: + case QPSK: + bits_per_symbol = 2; + break; + case QAM_16: + bits_per_symbol = 4; + break; + default: + case QAM_64: + bits_per_symbol = 6; + break; + } + + switch (c->layer[i].fec) { + case FEC_1_2: + rate_num = 1; + rate_denum = 2; + break; + case FEC_2_3: + rate_num = 2; + rate_denum = 3; + break; + case FEC_3_4: + rate_num = 3; + rate_denum = 4; + break; + case FEC_5_6: + rate_num = 5; + rate_denum = 6; + break; + default: + case FEC_7_8: + rate_num = 7; + rate_denum = 8; + break; + } + + interleaving = c->layer[i].interleaving; + + denom += bits_per_symbol * rate_num * fft_div * nsegs * 384; + } + + /* If all goes wrong, wait for 1s for the next stats */ + if (!denom) + return 0; + + /* Estimate the period for the total bit rate */ + time_us = rate_denum * (1008 * 1562500L); + tmp64 = time_us; + do_div(tmp64, guard); + time_us = time_us + tmp64; + time_us += denom / 2; + do_div(time_us, denom); + + tmp = 1008 * 96 * interleaving; + time_us += tmp + tmp / guard; + + return time_us; +} + +static int dib8000_get_stats(struct dvb_frontend *fe, enum fe_status stat) +{ + struct dib8000_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; + int i; + int show_per_stats = 0; + u32 time_us = 0, snr, val; + u64 blocks; + s32 db; + u16 strength; + + /* Get Signal strength */ + dib8000_read_signal_strength(fe, &strength); + val = strength; + db = interpolate_value(val, + strength_to_db_table, + ARRAY_SIZE(strength_to_db_table)) - 131000; + c->strength.stat[0].svalue = db; + + /* UCB/BER/CNR measures require lock */ + if (!(stat & FE_HAS_LOCK)) { + c->cnr.len = 1; + c->block_count.len = 1; + c->block_error.len = 1; + c->post_bit_error.len = 1; + c->post_bit_count.len = 1; + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return 0; + } + + /* Check if time for stats was elapsed */ + if (time_after(jiffies, state->per_jiffies_stats)) { + state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000); + + /* Get SNR */ + snr = dib8000_get_snr(fe); + for (i = 1; i < MAX_NUMBER_OF_FRONTENDS; i++) { + if (state->fe[i]) + snr += dib8000_get_snr(state->fe[i]); + } + snr = snr >> 16; + + if (snr) { + snr = 10 * intlog10(snr); + snr = (1000L * snr) >> 24; + } else { + snr = 0; + } + c->cnr.stat[0].svalue = snr; + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + + /* Get UCB measures */ + dib8000_read_unc_blocks(fe, &val); + if (val < state->init_ucb) + state->init_ucb += 0x100000000LL; + + c->block_error.stat[0].scale = FE_SCALE_COUNTER; + c->block_error.stat[0].uvalue = val + state->init_ucb; + + /* Estimate the number of packets based on bitrate */ + if (!time_us) + time_us = dib8000_get_time_us(fe, -1); + + if (time_us) { + blocks = 1250000ULL * 1000000ULL; + do_div(blocks, time_us * 8 * 204); + c->block_count.stat[0].scale = FE_SCALE_COUNTER; + c->block_count.stat[0].uvalue += blocks; + } + + show_per_stats = 1; + } + + /* Get post-BER measures */ + if (time_after(jiffies, state->ber_jiffies_stats)) { + time_us = dib8000_get_time_us(fe, -1); + state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000); + + dprintk("Next all layers stats available in %u us.", time_us); + + dib8000_read_ber(fe, &val); + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue += val; + + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].uvalue += 100000000; + } + + if (state->revision < 0x8002) + return 0; + + c->block_error.len = 4; + c->post_bit_error.len = 4; + c->post_bit_count.len = 4; + + for (i = 0; i < 3; i++) { + unsigned nsegs = c->layer[i].segment_count; + + if (nsegs == 0 || nsegs > 13) + continue; + + time_us = 0; + + if (time_after(jiffies, state->ber_jiffies_stats_layer[i])) { + time_us = dib8000_get_time_us(fe, i); + + state->ber_jiffies_stats_layer[i] = jiffies + msecs_to_jiffies((time_us + 500) / 1000); + dprintk("Next layer %c stats will be available in %u us\n", + 'A' + i, time_us); + + val = dib8000_read_word(state, per_layer_regs[i].ber); + c->post_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[1 + i].uvalue += val; + + c->post_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[1 + i].uvalue += 100000000; + } + + if (show_per_stats) { + val = dib8000_read_word(state, per_layer_regs[i].per); + + c->block_error.stat[1 + i].scale = FE_SCALE_COUNTER; + c->block_error.stat[1 + i].uvalue += val; + + if (!time_us) + time_us = dib8000_get_time_us(fe, i); + if (time_us) { + blocks = 1250000ULL * 1000000ULL; + do_div(blocks, time_us * 8 * 204); + c->block_count.stat[0].scale = FE_SCALE_COUNTER; + c->block_count.stat[0].uvalue += blocks; + } + } + } + return 0; +} + +static int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave) { struct dib8000_state *state = fe->demodulator_priv; u8 index_frontend = 1; @@ -3735,9 +4246,8 @@ dprintk("too many slave frontend"); return -ENOMEM; } -EXPORT_SYMBOL(dib8000_set_slave_frontend); -int dib8000_remove_slave_frontend(struct dvb_frontend *fe) +static int dib8000_remove_slave_frontend(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; u8 index_frontend = 1; @@ -3753,9 +4263,8 @@ dprintk("no frontend to be removed"); return -ENODEV; } -EXPORT_SYMBOL(dib8000_remove_slave_frontend); -struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) +static struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) { struct dib8000_state *state = fe->demodulator_priv; @@ -3763,10 +4272,8 @@ return NULL; return state->fe[slave_index]; } -EXPORT_SYMBOL(dib8000_get_slave_frontend); - -int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, +static int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr, u8 is_dib8096p) { int k = 0, ret = 0; @@ -3843,7 +4350,6 @@ return ret; } -EXPORT_SYMBOL(dib8000_i2c_enumeration); static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) { tune->min_delay_ms = 1000; @@ -3866,15 +4372,13 @@ kfree(st); } -struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating) +static struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating) { struct dib8000_state *st = fe->demodulator_priv; return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating); } -EXPORT_SYMBOL(dib8000_get_i2c_master); - -int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) +static int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) { struct dib8000_state *st = fe->demodulator_priv; u16 val = dib8000_read_word(st, 299) & 0xffef; @@ -3883,15 +4387,13 @@ dprintk("pid filter enabled %d", onoff); return dib8000_write_word(st, 299, val); } -EXPORT_SYMBOL(dib8000_pid_filter_ctrl); -int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) +static int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) { struct dib8000_state *st = fe->demodulator_priv; dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff); return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0); } -EXPORT_SYMBOL(dib8000_pid_filter); static const struct dvb_frontend_ops dib8000_ops = { .delsys = { SYS_ISDBT }, @@ -3923,12 +4425,12 @@ .read_ucblocks = dib8000_read_unc_blocks, }; -struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg) +static struct dvb_frontend *dib8000_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg) { struct dvb_frontend *fe; struct dib8000_state *state; - dprintk("dib8000_attach"); + dprintk("dib8000_init"); state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL); if (state == NULL) @@ -3985,6 +4487,33 @@ return NULL; } +void *dib8000_attach(struct dib8000_ops *ops) +{ + if (!ops) + return NULL; + + ops->pwm_agc_reset = dib8000_pwm_agc_reset; + ops->get_dc_power = dib8090p_get_dc_power; + ops->set_gpio = dib8000_set_gpio; + ops->get_slave_frontend = dib8000_get_slave_frontend; + ops->set_tune_state = dib8000_set_tune_state; + ops->pid_filter_ctrl = dib8000_pid_filter_ctrl; + ops->remove_slave_frontend = dib8000_remove_slave_frontend; + ops->get_adc_power = dib8000_get_adc_power; + ops->update_pll = dib8000_update_pll; + ops->tuner_sleep = dib8096p_tuner_sleep; + ops->get_tune_state = dib8000_get_tune_state; + ops->get_i2c_tuner = dib8096p_get_i2c_tuner; + ops->set_slave_frontend = dib8000_set_slave_frontend; + ops->pid_filter = dib8000_pid_filter; + ops->ctrl_timf = dib8000_ctrl_timf; + ops->init = dib8000_init; + ops->get_i2c_master = dib8000_get_i2c_master; + ops->i2c_enumeration = dib8000_i2c_enumeration; + ops->set_wbd_ref = dib8000_set_wbd_ref; + + return ops; +} EXPORT_SYMBOL(dib8000_attach); MODULE_AUTHOR("Olivier Grenie ");