| // SPDX-License-Identifier: (GPL-2.0+ OR MIT) |
| /* |
| * Copyright (c) 2019 Amlogic, Inc. All rights reserved. |
| */ |
| |
| #define __DVB_CORE__ /*ary 2018-1-31*/ |
| |
| #include <linux/init.h> |
| #include <linux/kernel.h> |
| #include <linux/module.h> |
| #include <linux/string.h> |
| #include <linux/delay.h> |
| #include <linux/jiffies.h> |
| #include <linux/slab.h> |
| #include <linux/platform_device.h> |
| #include <linux/pm_runtime.h> |
| #include <linux/pm_domain.h> |
| #include <linux/firmware.h> |
| #include <linux/err.h> /*IS_ERR*/ |
| #include <linux/clk.h> /*clk tree*/ |
| #include <linux/of_device.h> |
| #include <linux/of_reserved_mem.h> |
| #include <linux/of_irq.h> |
| #include <linux/interrupt.h> |
| #include <linux/crc32.h> |
| |
| #ifdef ARC_700 |
| #include <asm/arch/am_regs.h> |
| #else |
| /* #include <mach/am_regs.h> */ |
| #endif |
| #include <linux/i2c.h> |
| #include <linux/gpio.h> |
| |
| #include "aml_demod.h" |
| #include "demod_func.h" |
| #include "demod_dbg.h" |
| #include "amlfrontend.h" |
| #include "dvbs_frontend.h" |
| #include "dvbs.h" |
| #include "dvbs_singlecable.h" |
| #include <linux/amlogic/aml_dtvdemod.h> |
| |
| static bool blind_scan_new = true; |
| module_param(blind_scan_new, bool, 0644); |
| MODULE_PARM_DESC(blind_scan_new, "blind_scan_new"); |
| |
| int dtvdemod_dvbs_read_ber(struct dvb_frontend *fe, u32 *ber) |
| { |
| struct aml_dtvdemod *demod = (struct aml_dtvdemod *)fe->demodulator_priv; |
| |
| /* x e10 */ |
| *ber = demod->real_para.ber; |
| |
| PR_DVBS("%s: ber %d E-10\n", __func__, *ber); |
| |
| return 0; |
| } |
| |
| int dtvdemod_dvbs_read_signal_strength(struct dvb_frontend *fe, s16 *strength) |
| { |
| struct aml_dtvdemod *demod = (struct aml_dtvdemod *)fe->demodulator_priv; |
| unsigned int agc_level = 0; |
| unsigned int i = 0, if_agc_value = 0; |
| u16 rf_strength = 0; |
| |
| if (demod->last_status != 0x1F) { |
| *strength = -100; |
| } else if (tuner_find_by_name(fe, "av2018") || |
| tuner_find_by_name(fe, "rda5815m")) { |
| agc_level = dvbs_rd_byte(DVBS_AGC_LEVEL_ADDR); |
| if (agc_level > 183) { |
| *strength = 0; |
| if (agc_level == 184) |
| *strength = -3; |
| if (agc_level == 185) |
| *strength = -1; |
| } else if (agc_level > 170 && agc_level <= 183) { |
| *strength = (s16)(agc_level * 120 / 13 - 1769) / 10; |
| } else if (agc_level >= 130 && agc_level <= 170) { |
| *strength = (s16)agc_level / 2 - 105; |
| } else if (agc_level >= 13 && agc_level < 130) { |
| *strength = (s16)(agc_level * 110 / 25 - 965) / 10; |
| if (*strength < -90) |
| *strength = -90; |
| } else { |
| *strength = -90; |
| if (agc_level == 0) |
| *strength = -95; |
| } |
| } else if (tuner_find_by_name(fe, "rt710") || |
| tuner_find_by_name(fe, "rt720")) { |
| for (i = 0; i < 10; i++) |
| //IF AGC1 integrator value |
| if_agc_value += |
| (unsigned int)MAKEWORD(dvbs_rd_byte(0x91a), dvbs_rd_byte(0x91b)); |
| |
| if_agc_value /= 10; |
| rf_strength = (u16)if_agc_value; |
| if (fe->ops.tuner_ops.get_rf_strength) |
| fe->ops.tuner_ops.get_rf_strength(fe, &rf_strength); |
| PR_DBGL("if_agc_code %d\n", if_agc_value); |
| |
| *strength = (s16)tuner_get_ch_power(fe); |
| } else { |
| *strength = (s16)tuner_get_ch_power(fe); |
| if (*strength <= -57) |
| *strength += (s16)dvbs_get_signal_strength_off(); |
| } |
| |
| PR_DVBS("demod [id %d] signal strength %d dBm\n", demod->id, *strength); |
| |
| return 0; |
| } |
| |
| int dvbs_read_snr(struct dvb_frontend *fe, u16 *snr) |
| { |
| struct aml_dtvdemod *demod = (struct aml_dtvdemod *)fe->demodulator_priv; |
| |
| *snr = (u16)demod->real_para.snr; |
| |
| PR_DVBS("demod[%d] snr %d dBx10\n", demod->id, *snr); |
| |
| return 0; |
| } |
| |
| /* |
| * in Unicable mode, when try signal or try lock TP, the actual IF freq |
| * should be moved to the specified user band freq first, |
| * then reset fe->dtv_property_cache.frequency with the target userband freq. |
| */ |
| int dtvdemod_dvbs_unicable_change_channel(struct dvb_frontend *fe) |
| { |
| struct aml_dtvdemod *demod = (struct aml_dtvdemod *)fe->demodulator_priv; |
| struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
| struct amldtvdemod_device_s *devp = (struct amldtvdemod_device_s *)demod->priv; |
| int ret = 0; |
| struct dvb_diseqc_master_cmd cmd; |
| u32 singlecable_freq_mhz = 0; |
| |
| PR_DVBS("%s: bank %d committed %d umcommitted %d IF_freq %d\n", __func__, |
| devp->singlecable_param.bank, devp->singlecable_param.committed, |
| devp->singlecable_param.uncommitted, c->frequency); |
| |
| if (devp->singlecable_param.version == SINGLECABLE_VERSION_1_EN50494) { |
| //set singlecable |
| ret = aml_singlecable_command_ODU_channel_change(&cmd, |
| (unsigned char)SINGLECABLE_ADDRESS_ALL_LNB_SMATV_SWITCHER, |
| devp->singlecable_param.userband, devp->singlecable_param.frequency, |
| devp->singlecable_param.bank, c->frequency); |
| if (ret != 0) { |
| PR_ERR("%s: singlecable ODU_channel_change failed %d\n", __func__, ret); |
| return ret; |
| } |
| } else if (devp->singlecable_param.version == SINGLECABLE_VERSION_2_EN50607) { |
| singlecable_freq_mhz = (c->frequency + 500) / 1000; |
| if (singlecable_freq_mhz > 2147) |
| singlecable_freq_mhz = 2147; |
| |
| ret = aml_singlecable2_command_ODU_channel_change(&cmd, |
| devp->singlecable_param.userband, singlecable_freq_mhz, |
| devp->singlecable_param.uncommitted, |
| devp->singlecable_param.committed); |
| if (ret != 0) { |
| PR_ERR("%s: singlecable2 ODU_channel_change failed %d\n", __func__, ret); |
| return ret; |
| } |
| } else { |
| PR_ERR("%s: not support singlecable ver %d !!!\n", __func__, |
| devp->singlecable_param.version); |
| return -EINVAL; |
| } |
| |
| ret = aml_diseqc_send_master_cmd(fe, &cmd); |
| if (ret < 0) { |
| PR_ERR("%s: aml_diseqc_send_master_cmd failed %d\n", __func__, ret); |
| return ret; |
| } |
| c->frequency = devp->singlecable_param.frequency; |
| |
| return ret; |
| } |
| |
| int dtvdemod_dvbs_blind_check_signal(struct dvb_frontend *fe, |
| unsigned int freq_khz, int *next_step_khz, int *signal_state) |
| { |
| struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
| struct aml_dtvdemod *demod = (struct aml_dtvdemod *)fe->demodulator_priv; |
| struct amldtvdemod_device_s *devp = (struct amldtvdemod_device_s *)demod->priv; |
| int ret = 0, next_step_khz1 = 0, asperity = 0; |
| |
| #ifdef DVBS_BLIND_SCAN_DEBUG |
| unsigned int fld_value[2] = { 0 }; |
| int i = 0; |
| int agc1_iq_amp = 0, agc1_iq_power = 0; |
| #endif |
| /* set tuner */ |
| c->frequency = freq_khz; // KHz |
| if (tuner_find_by_name(fe, "av2018")) { |
| c->bandwidth_hz = 40000000; |
| c->symbol_rate = 40000000; |
| } else { |
| c->bandwidth_hz = 45000000; |
| c->symbol_rate = 45000000; |
| } |
| |
| //in Unicable blind scan mode, when try signal, the actual IF freq |
| //should be moved to the specified user band freq first, |
| //then tuner_set_params with the specified user band freq. |
| if (!devp->blind_scan_stop && demod->demod_status.is_blind_scan && |
| demod->demod_status.is_singlecable) { |
| PR_DVBS("%s: IF_freq %d\n", __func__, c->frequency); |
| ret = dtvdemod_dvbs_unicable_change_channel(fe); |
| if (ret != 0) |
| return ret; |
| } |
| |
| tuner_set_params(fe); |
| |
| usleep_range(2 * 1000, 3 * 1000);//msleep(2); |
| |
| #ifdef DVBS_BLIND_SCAN_DEBUG |
| fld_value[0] = dvbs_rd_byte(0x91a); |
| fld_value[1] = dvbs_rd_byte(0x91b); |
| |
| agc1_iq_amp = (int)((fld_value[0] << 8) | fld_value[1]); |
| if (!agc1_iq_amp) { |
| for (i = 0; i < 5; i++) { |
| fld_value[0] = dvbs_rd_byte(0x916); |
| fld_value[1] = dvbs_rd_byte(0x917); |
| agc1_iq_power = agc1_iq_power + fld_value[0] + fld_value[1]; |
| } |
| |
| agc1_iq_power /= 5; |
| } |
| |
| PR_DVBS("agc1_iq_amp: %d, agc1_iq_power: %d.\n", agc1_iq_amp, agc1_iq_power); |
| #endif |
| |
| if (blind_scan_new) { |
| if (*signal_state == 0 || *signal_state == 1) { |
| asperity = dvbs_blind_check_AGC2_bandwidth_new(next_step_khz, |
| &next_step_khz1, signal_state); |
| if (*signal_state != 0) |
| *next_step_khz = next_step_khz1; |
| |
| return asperity; |
| } else if (*signal_state == 2) { |
| return 2; |
| } else { |
| return 0; |
| } |
| } else { |
| return dvbs_blind_check_AGC2_bandwidth_old(next_step_khz); |
| } |
| } |
| |
| int dtvdemod_dvbs_blind_set_frontend(struct dvb_frontend *fe, |
| struct fft_in_bw_result *in_bw_result, unsigned int fft_frc_range_min, |
| unsigned int fft_frc_range_max, unsigned int range_ini) |
| { |
| struct aml_dtvdemod *demod = (struct aml_dtvdemod *)fe->demodulator_priv; |
| struct amldtvdemod_device_s *devp = (struct amldtvdemod_device_s *)demod->priv; |
| struct fft_threadcontrols spectr_ana_data; |
| struct fft_search_result search_result; |
| unsigned int fft_reg_val[60] = {0}; |
| unsigned int reg_value[3]; |
| int frq = 0; |
| int ret = 0; |
| |
| reg_value[0] = dvbs_rd_byte(0x910);//AGC1CFG |
| reg_value[1] = dvbs_rd_byte(0x912);//AGC1CN |
| reg_value[2] = dvbs_rd_byte(0x913);//AGC1REF |
| |
| dvbs_fft_reg_init(fft_reg_val); |
| |
| spectr_ana_data.flow = fft_frc_range_min; |
| spectr_ana_data.fup = fft_frc_range_max; |
| spectr_ana_data.range = range_ini; |
| spectr_ana_data.mode = 0; |
| spectr_ana_data.acc = 1; |
| |
| //get center frc of the frc range |
| spectr_ana_data.in_bw_center_frc = (spectr_ana_data.flow + spectr_ana_data.fup) >> 1; |
| |
| fe->dtv_property_cache.frequency = spectr_ana_data.in_bw_center_frc * 1000; |
| if (tuner_find_by_name(fe, "av2018")) { |
| fe->dtv_property_cache.bandwidth_hz = 40000000; |
| fe->dtv_property_cache.symbol_rate = 40000000; |
| } else { |
| fe->dtv_property_cache.bandwidth_hz = 45000000; |
| fe->dtv_property_cache.symbol_rate = 45000000; |
| } |
| |
| if (!devp->blind_scan_stop && demod->demod_status.is_blind_scan && |
| demod->demod_status.is_singlecable) |
| fe->dtv_property_cache.frequency = devp->singlecable_param.frequency; |
| |
| tuner_set_params(fe); |
| msleep(20); |
| |
| for (frq = -22; frq <= 22;) { |
| if (devp->blind_scan_stop) |
| break; |
| /* modify range and central frequency to adjust*/ |
| /*the last acquisition to the wanted range */ |
| search_result.found_ok = 0; |
| search_result.result_bw = 0; |
| search_result.result_frc = 0; |
| |
| dvbs_blind_fft_work(&spectr_ana_data, frq, &search_result); |
| if (search_result.found_ok == 1) { |
| in_bw_result->freq[in_bw_result->tp_num] = |
| search_result.result_frc; |
| in_bw_result->bw[in_bw_result->tp_num] = |
| search_result.result_bw; |
| in_bw_result->tp_num++; |
| PR_DVBS("IN range:%d: find frc:%d,sr:%d\n", |
| spectr_ana_data.range, search_result.result_frc, |
| search_result.result_bw); |
| } |
| |
| frq = frq + (int)spectr_ana_data.range * 2 / 5; |
| } |
| |
| //fft reg reset |
| dvbs_fft_reg_term(fft_reg_val); |
| |
| dvbs_wr_byte(0x910, reg_value[0]); |
| dvbs_wr_byte(0x912, reg_value[1]); |
| dvbs_wr_byte(0x913, reg_value[2]); |
| |
| return ret; |
| } |
| |
| static struct fft_total_result total_result; |
| static struct fft_in_bw_result in_bw_result; |
| void dvbs_blind_scan_new_work(struct work_struct *work) |
| { |
| struct amldtvdemod_device_s *devp = container_of(work, |
| struct amldtvdemod_device_s, blind_scan_work); |
| struct aml_dtvdemod *demod = NULL, *tmp = NULL; |
| struct dvb_frontend *fe = NULL; |
| struct dtv_frontend_properties *c = NULL; |
| enum fe_status status = FE_NONE; |
| unsigned int last_locked_freq = 0, last_locked_sr = 0; |
| unsigned int cur_freq = 0, cur_sr = 0, cur_iq = dvbs_get_iq_swap(); |
| unsigned int freq_min = devp->blind_min_fre; |
| unsigned int freq_max = devp->blind_max_fre; |
| unsigned int freq_step = devp->blind_fre_step; |
| unsigned int freq = 0, srate = 45000000; |
| unsigned int range[4] = {22, 11, 6, 3}; |
| unsigned int fft_frc_range_min = 0; |
| unsigned int fft_frc_range_max = 0; |
| unsigned int freq_one_percent = 0; |
| unsigned int freq_offset = 0; |
| unsigned int range_ini = 0; |
| unsigned int polarity = 0; |
| unsigned int iq_swap_default = dvbs_get_iq_swap(); |
| int i = 0, j = 0, k = 0; |
| int asperity = 0, next_step_khz = 0, signal_state = 0, freq_add = 0, freq_add_dly = 0; |
| int scan_time = 1; |
| bool found_tp = false; |
| unsigned int last_step_num = 50, cur_step_num = 0, percent_base = 0; |
| |
| PR_INFO("a new blind scan thread\n"); |
| |
| list_for_each_entry(tmp, &devp->demod_list, list) { |
| if (tmp->id == 0) { |
| demod = tmp; |
| break; |
| } |
| } |
| |
| if (!demod) { |
| PR_INFO("%s: demod == NULL.\n", __func__); |
| return; |
| } |
| |
| fe = &demod->frontend; |
| |
| if (unlikely(!fe)) { |
| PR_ERR("%s err, fe is NULL\n", __func__); |
| return; |
| } |
| |
| timer_set_max(demod, D_TIMER_DETECT, 600); |
| fe->ops.info.type = FE_QPSK; |
| c = &fe->dtv_property_cache; |
| |
| if (fe->ops.tuner_ops.set_config) |
| fe->ops.tuner_ops.set_config(fe, NULL); |
| |
| demod->blind_result_frequency = 0; |
| demod->blind_result_symbol_rate = 0; |
| |
| c->symbol_rate = srate; |
| demod->demod_status.symb_rate = srate / 1000; |
| demod->demod_status.is_blind_scan = !devp->blind_scan_stop; |
| |
| if (devp->singlecable_param.version) { |
| demod->demod_status.is_singlecable = 1; |
| scan_time = 2; |
| PR_ERR("%s scan_time %d\n", __func__, scan_time); |
| //when blind scan started, reset the voltage for H/V polarization. |
| if (devp->singlecable_param.version != SINGLECABLE_VERSION_UNKNOWN) |
| aml_diseqc_set_voltage(fe, SEC_VOLTAGE_13); |
| else |
| PR_ERR("%s: invalid unicable ver %d\n", __func__, |
| devp->singlecable_param.version); |
| } |
| |
| demod->last_lock = -1; |
| //dvbs all reg init |
| dtvdemod_dvbs_set_ch(&demod->demod_status); |
| |
| if (devp->agc_direction) { |
| PR_DVBS("%s: DTV AGC direction: %d, Set dvbs agc pin reverse\n", |
| __func__, devp->agc_direction); |
| dvbs_wr_byte(0x118, 0x04); |
| } |
| |
| total_result.tp_num = 0; |
| if (blind_scan_new && freq_max == 2150000) |
| freq_max = freq_max + freq_step; |
| |
| //map blind scan fft process to 0% - 50% |
| freq_one_percent = |
| scan_time == 2 ? (freq_max - freq_min) / 25 : (freq_max - freq_min) / 50; |
| PR_DVBS("freq_one_percent: %d.\n", freq_one_percent); |
| |
| /* 950MHz ~ 2150MHz. */ |
| do { |
| for (freq = freq_min; freq <= freq_max;) { |
| if (devp->blind_scan_stop) |
| break; |
| PR_INFO("------Search From: [%d KHz to %d KHz]-----\n", |
| freq - 20000, freq + freq_step - 20000); |
| |
| asperity = dtvdemod_dvbs_blind_check_signal(fe, freq, |
| &next_step_khz, &signal_state); |
| |
| PR_INFO("get asperity: %d, next_step_khz %d, signal_state %d.\n", |
| asperity, next_step_khz, signal_state); |
| |
| fft_frc_range_min = (freq - 20000) / 1000; |
| fft_frc_range_max = ((freq - 20000) / 1000) + (freq_step / 1000); |
| for (i = 0; i < 4 && asperity; i++) { |
| if (devp->blind_scan_stop) |
| break; |
| range_ini = range[i]; |
| in_bw_result.tp_num = 0; |
| dtvdemod_dvbs_blind_set_frontend(fe, &in_bw_result, |
| fft_frc_range_min, fft_frc_range_max, range_ini); |
| |
| if (in_bw_result.tp_num != 0) |
| PR_INFO("------In Bw(range_ini %d) Find Tp Num:%d-----\n", |
| range_ini, in_bw_result.tp_num); |
| |
| for (j = 0; j < in_bw_result.tp_num; j++) { |
| total_result.freq[total_result.tp_num] = |
| in_bw_result.freq[j]; |
| total_result.bw[total_result.tp_num] = |
| in_bw_result.bw[j]; |
| total_result.iq_swap[total_result.tp_num] = |
| cur_iq; |
| total_result.tp_num++; |
| } |
| } |
| |
| cur_step_num = (freq - freq_min) / freq_one_percent + percent_base; |
| PR_DVBS("last %d cur_step_num %d\n", |
| demod->blind_result_frequency, cur_step_num); |
| if (freq <= freq_max && |
| cur_step_num > demod->blind_result_frequency && |
| cur_step_num <= (scan_time == 1 ? 50 : 25)) { |
| demod->blind_result_frequency = cur_step_num; |
| demod->blind_result_symbol_rate = 0; |
| |
| status = BLINDSCAN_UPDATEPROCESS | FE_HAS_LOCK; |
| PR_DVBS("FFT search: blind scan process: [%d%%].\n", |
| demod->blind_result_frequency); |
| dvb_frontend_add_event(fe, status); |
| } |
| |
| if (blind_scan_new) { |
| if (asperity == 2 && signal_state == 2) { |
| signal_state = 0; |
| next_step_khz = freq_add; |
| } |
| |
| if (signal_state == 1) { |
| freq = freq + freq_step; |
| freq_add_dly = next_step_khz; |
| } else if (signal_state == 2) { |
| freq_add = 40000 + 3000 + |
| (freq_add_dly + next_step_khz) / 2; |
| freq = freq - 20000 + next_step_khz / 2 - freq_add_dly / 2; |
| } else { |
| freq = freq + next_step_khz; |
| } |
| } else { |
| freq = freq + (freq_step - next_step_khz); |
| } |
| |
| PR_INFO("[signal_state %d], freq %d, next_step_khz %d", |
| signal_state, freq, next_step_khz); |
| PR_INFO("freq_add %d, freq_add_dly %d.\n", freq_add, freq_add_dly); |
| } |
| PR_ERR("%s scan_time %d\n", __func__, scan_time); |
| if (scan_time == 2) { |
| dvbs_set_iq_swap(iq_swap_default ? 0 : 1); |
| cur_iq = dvbs_get_iq_swap(); |
| PR_INFO("%s set dvbs_iq_swap %d.\n", __func__, cur_iq); |
| percent_base = 25; |
| } |
| scan_time--; |
| } while (scan_time && !devp->blind_scan_stop); |
| dvbs_set_iq_swap(iq_swap_default); |
| |
| PR_INFO("------TOTAL FIND TP NUM: %d-----\n", total_result.tp_num); |
| |
| if (total_result.tp_num > 0 && !devp->blind_scan_stop) { |
| // map blind scan try lock process to 51% ~ 99% |
| freq_one_percent = total_result.tp_num * 50 / 50; |
| |
| dvbs_blind_fft_result_handle(&total_result); |
| |
| PR_INFO("------Start Try To Lock Test-----\n"); |
| last_locked_freq = 0; |
| last_locked_sr = 0; |
| for (k = 0; k < total_result.tp_num; ++k) { |
| if (devp->blind_scan_stop) |
| break; |
| |
| cur_freq = total_result.freq[k] * 1000; |
| cur_sr = total_result.bw[k] * 1000; |
| cur_iq = total_result.iq_swap[k]; |
| |
| PR_INFO("Try TP: [%d KHz, %d bps].\n", |
| cur_freq, cur_sr); |
| |
| if ((abs(last_locked_freq - cur_freq) < 5000) || |
| (abs(last_locked_freq - cur_freq) < 10000 && |
| last_locked_sr >= 20000000) || |
| ((abs(last_locked_sr - cur_sr) <= 5000) && |
| (abs(last_locked_freq - cur_freq) <= 8000))) { |
| status = FE_TIMEDOUT; |
| PR_INFO("Skip tune: last[%d KHz, %d bps], cur[%d KHz, %d bps].\n", |
| last_locked_freq, last_locked_sr, |
| cur_freq, cur_sr); |
| } else { |
| c->frequency = cur_freq; |
| c->bandwidth_hz = cur_sr; |
| c->symbol_rate = cur_sr; |
| |
| if (demod->demod_status.is_singlecable) |
| dvbs_set_iq_swap(cur_iq); |
| //in Unicable blind scan mode, when try lock TP, the actual IF freq |
| //should be moved to the specified user band freq first |
| if (!devp->blind_scan_stop && demod->demod_status.is_singlecable) |
| dtvdemod_dvbs_unicable_change_channel(fe); |
| |
| dtvdemod_dvbs_set_frontend(fe); |
| timer_begain(demod, D_TIMER_DETECT); |
| |
| usleep_range(500000, 510000); |
| dtvdemod_dvbs_read_status(fe, &status, cur_freq, false); |
| } |
| |
| if (status == FE_TIMEDOUT || status == 0) { |
| found_tp = false; |
| } else { |
| freq_offset = dvbs_get_freq_offset(&polarity) / 1000; |
| |
| //if (demod->demod_status.is_singlecable) |
| // polarity = polarity ? 0 : 1; |
| |
| if (polarity) |
| cur_freq = cur_freq + freq_offset * 1000; |
| else |
| cur_freq = cur_freq - freq_offset * 1000; |
| |
| // cur_sr = dvbs_get_symbol_rate() * 1000; |
| |
| if ((abs(last_locked_freq - cur_freq) < 5000) || |
| (abs(last_locked_freq - cur_freq) < 10000 && |
| last_locked_sr >= 20000000)) { |
| status = BLINDSCAN_UPDATEPROCESS | FE_HAS_LOCK; |
| PR_INFO("Skip report: last[%d KHz, %d bps], cur[%d KHz, %d bps].\n", |
| last_locked_freq, last_locked_sr, |
| cur_freq, cur_sr); |
| found_tp = false; |
| } else { |
| found_tp = true; |
| } |
| } |
| |
| if (found_tp) { |
| found_tp = false; |
| c->symbol_rate = cur_sr; |
| c->delivery_system = demod->last_delsys; |
| c->bandwidth_hz = cur_sr; |
| c->frequency = cur_freq; |
| |
| if (demod->demod_status.is_singlecable && |
| !devp->blind_scan_stop) { |
| dtvdemod_dvbs_unicable_change_channel(fe); |
| dtvdemod_dvbs_set_frontend(fe); |
| timer_begain(demod, D_TIMER_DETECT); |
| usleep_range(500000, 510000); |
| dtvdemod_dvbs_read_status(fe, &status, |
| cur_freq, false); |
| |
| if (status == FE_TIMEDOUT || status == 0) { |
| status = BLINDSCAN_UPDATEPROCESS | FE_HAS_LOCK; |
| PR_INFO("Skip unlock TP: [%d KHz, %d bps].\n", |
| cur_freq, cur_sr); |
| continue; |
| } |
| |
| if (last_locked_sr == cur_sr && |
| (abs(last_locked_freq - cur_freq) <= 15000)) { |
| PR_INFO("Skip repo TP: l[%d, %d], c[%d, %d].\n", |
| last_locked_freq, last_locked_sr, |
| cur_freq, cur_sr); |
| status = BLINDSCAN_UPDATEPROCESS | FE_HAS_LOCK; |
| continue; |
| } |
| } |
| last_locked_sr = cur_sr; |
| last_locked_freq = cur_freq; |
| |
| demod->blind_result_frequency = cur_freq; |
| demod->blind_result_symbol_rate = cur_sr; |
| |
| status = BLINDSCAN_UPDATERESULTFREQ | |
| FE_HAS_LOCK; |
| |
| PR_INFO("Get actual TP: [%d KHz, %d bps].\n", |
| cur_freq, cur_sr); |
| |
| dvb_frontend_add_event(fe, status); |
| } |
| |
| //map trying lock process to 51% - 99% |
| cur_step_num = (k + 1) * 50 / freq_one_percent + 50; |
| PR_DVBS("last_step_num %d cur_step_num %d\n", |
| last_step_num, cur_step_num); |
| if (total_result.tp_num > 1 && cur_step_num < 100 && |
| cur_step_num > last_step_num) { |
| last_step_num = cur_step_num; |
| demod->blind_result_frequency = cur_step_num; |
| demod->blind_result_symbol_rate = 0; |
| |
| status = BLINDSCAN_UPDATEPROCESS | FE_HAS_LOCK; |
| PR_DVBS("Try lock: blind scan process: [%d%%].\n", |
| demod->blind_result_frequency); |
| dvb_frontend_add_event(fe, status); |
| } |
| } |
| } |
| dvbs_set_iq_swap(iq_swap_default); |
| if (!devp->blind_scan_stop) { |
| c->frequency = 100; |
| demod->blind_result_frequency = 100; |
| demod->blind_result_symbol_rate = 0; |
| status = BLINDSCAN_UPDATEPROCESS | FE_HAS_LOCK; |
| PR_INFO("%s:force 100%% to upper layer\n", __func__); |
| dvb_frontend_add_event(fe, status); |
| devp->blind_scan_stop = 1; |
| } |
| } |
| |
| int dtvdemod_dvbs_set_ch(struct aml_demod_sta *demod_sta) |
| { |
| int ret = 0; |
| |
| /* 0:16, 1:32, 2:64, 3:128, 4:256 */ |
| demod_sta->agc_mode = 1; |
| demod_sta->ch_bw = 8000; |
| if (demod_sta->ch_if == 0) |
| demod_sta->ch_if = DEMOD_5M_IF; |
| |
| dvbs2_reg_initial(demod_sta->symb_rate, demod_sta->is_blind_scan); |
| |
| return ret; |
| } |
| |
| unsigned int dvbs_get_bitrate(int sr) |
| { |
| unsigned int s2, cr_t = 1, cr_b, modu, modu_ratio = 1; |
| |
| s2 = dvbs_rd_byte(0x932) & 0x60; |
| modu = dvbs_rd_byte(0x930) >> 2; |
| if (s2 == 0x40) {//bit5.6 S2 |
| switch (modu) { |
| case 0x1://0x1~0xB:QPSK |
| modu_ratio = 2; |
| cr_t = 1; |
| cr_b = 4; |
| break; |
| |
| case 0x2: |
| modu_ratio = 2; |
| cr_t = 1; |
| cr_b = 3; |
| break; |
| |
| case 0x3: |
| modu_ratio = 2; |
| cr_t = 2; |
| cr_b = 5; |
| break; |
| |
| case 0x4: |
| modu_ratio = 2; |
| cr_t = 1; |
| cr_b = 2; |
| break; |
| |
| case 0x5: |
| modu_ratio = 2; |
| cr_t = 3; |
| cr_b = 5; |
| break; |
| |
| case 0x6: |
| modu_ratio = 2; |
| cr_t = 2; |
| cr_b = 3; |
| break; |
| |
| case 0x7: |
| modu_ratio = 2; |
| cr_t = 3; |
| cr_b = 4; |
| break; |
| |
| case 0x8: |
| modu_ratio = 2; |
| cr_t = 4; |
| cr_b = 5; |
| break; |
| |
| case 0x9: |
| modu_ratio = 2; |
| cr_t = 5; |
| cr_b = 6; |
| break; |
| |
| case 0xA: |
| modu_ratio = 2; |
| cr_t = 8; |
| cr_b = 9; |
| break; |
| |
| case 0xB: |
| modu_ratio = 2; |
| cr_t = 9; |
| cr_b = 10; |
| break; |
| |
| case 0xC://0xC~0x11:8PSK |
| modu_ratio = 3; |
| cr_t = 3; |
| cr_b = 5; |
| break; |
| |
| case 0xD: |
| modu_ratio = 3; |
| cr_t = 2; |
| cr_b = 3; |
| break; |
| |
| case 0xE: |
| modu_ratio = 3; |
| cr_t = 3; |
| cr_b = 4; |
| break; |
| |
| case 0xF: |
| modu_ratio = 3; |
| cr_t = 5; |
| cr_b = 6; |
| break; |
| |
| case 0x10: |
| modu_ratio = 3; |
| cr_t = 8; |
| cr_b = 9; |
| break; |
| |
| case 0x11: |
| modu_ratio = 3; |
| cr_t = 9; |
| cr_b = 10; |
| break; |
| |
| case 0x12://0x12~0x17:APSK_16 |
| modu_ratio = 4; |
| cr_t = 2; |
| cr_b = 3; |
| break; |
| |
| case 0x13: |
| modu_ratio = 4; |
| cr_t = 3; |
| cr_b = 4; |
| break; |
| |
| case 0x14: |
| modu_ratio = 4; |
| cr_t = 4; |
| cr_b = 5; |
| break; |
| |
| case 0x15: |
| modu_ratio = 4; |
| cr_t = 5; |
| cr_b = 6; |
| break; |
| |
| case 0x16: |
| modu_ratio = 4; |
| cr_t = 8; |
| cr_b = 9; |
| break; |
| |
| case 0x17: |
| modu_ratio = 4; |
| cr_t = 9; |
| cr_b = 10; |
| break; |
| |
| case 0x18://0x18~0x1C:APSK_32 |
| modu_ratio = 5; |
| cr_t = 3; |
| cr_b = 4; |
| break; |
| |
| case 0x19: |
| modu_ratio = 5; |
| cr_t = 4; |
| cr_b = 5; |
| break; |
| |
| case 0x1A: |
| modu_ratio = 5; |
| cr_t = 5; |
| cr_b = 6; |
| break; |
| |
| case 0x1B: |
| modu_ratio = 5; |
| cr_t = 8; |
| cr_b = 9; |
| break; |
| |
| case 0x1C: |
| modu_ratio = 5; |
| cr_t = 9; |
| cr_b = 10; |
| break; |
| |
| default: |
| return 20000000;//20M |
| }; |
| } else { |
| modu_ratio = 2; |
| switch (modu) { |
| case 0x20: |
| cr_t = 1; |
| cr_b = 2; |
| break; |
| |
| case 0x21: |
| cr_t = 2; |
| cr_b = 3; |
| break; |
| |
| case 0x22: |
| cr_t = 3; |
| cr_b = 4; |
| break; |
| |
| case 0x23: |
| cr_t = 5; |
| cr_b = 6; |
| break; |
| |
| case 0x24: |
| cr_t = 6; |
| cr_b = 7; |
| break; |
| |
| case 0x25: |
| cr_t = 7; |
| cr_b = 8; |
| break; |
| |
| default: |
| return 20000000;//20M |
| } |
| } |
| |
| PR_DVBS("DVBS%d modu_value=%d, modu=PSK_%d, cr=%d/%d\n", |
| s2 == 0x40 ? 2 : 1, modu, 1 << modu_ratio, cr_t, cr_b); |
| |
| return sr * cr_b / cr_t / modu_ratio; |
| } |
| |
| static int calc_ave(int *val_arr, int cnt, unsigned int mode, int par) |
| { |
| int i, j, k, tot, ave, *val, calc_cnt, *val_tmp, calc_cnt_tmp, need_order; |
| |
| need_order = (mode >> 31) & 1 ? 0 : 1; |
| mode = mode & 0x7FFFFFFF; |
| |
| if (!val_arr || cnt <= 0 || mode < 0 || mode > 2) |
| return 0; |
| |
| if (mode != 0 && par <= 0) |
| return 0; |
| |
| if (mode == 1 && (par * 2) >= cnt) |
| return 0; |
| |
| tot = 0; |
| calc_cnt = cnt; |
| if (need_order) { |
| val = kmalloc_array(calc_cnt, sizeof(int), GFP_KERNEL); |
| if (!val) |
| return 0; |
| |
| memset(val, 0, sizeof(int) * calc_cnt); |
| for (i = 0; i < calc_cnt; i++) { |
| tot += val_arr[i]; |
| for (j = 0; j < i; j++) { |
| if (val_arr[i] < val[j]) { |
| for (k = i; k > j; k--) |
| val[k] = val[k - 1]; |
| break; |
| } |
| } |
| val[j] = val_arr[i]; |
| } |
| } else { |
| for (i = 0; i < calc_cnt; i++) |
| tot += val_arr[i]; |
| val = val_arr; |
| } |
| |
| if (mode == 1) { |
| for (i = 0; i < par; i++) { |
| tot -= val[i]; |
| tot -= val[calc_cnt - 1 - i]; |
| } |
| calc_cnt -= par * 2; |
| } |
| |
| ave = tot / calc_cnt; |
| ave += (tot % calc_cnt) >= (calc_cnt / 2) ? 1 : 0; |
| |
| if (mode == 2) { |
| val_tmp = val; |
| calc_cnt_tmp = calc_cnt; |
| for (i = 0; i < calc_cnt; i++) { |
| if (val[i] < (ave - par)) { |
| val_tmp = &val[i + 1]; |
| calc_cnt_tmp--; |
| } else if (val[i] > (ave + par)) { |
| calc_cnt_tmp -= calc_cnt - i; |
| break; |
| } |
| } |
| if (calc_cnt_tmp < calc_cnt) |
| ave = calc_ave(val_tmp, calc_cnt_tmp, mode | 0x80000000, par); |
| } |
| |
| if (need_order) |
| kfree(val); |
| |
| return ave; |
| } |
| |
| int dtvdemod_dvbs_read_status(struct dvb_frontend *fe, enum fe_status *status, |
| unsigned int if_freq_khz, bool re_tune) |
| { |
| int ilock = 0; |
| unsigned char s = 0; |
| s16 strength = 0; |
| int offset = 0, polarity = 0; |
| struct aml_dtvdemod *demod = (struct aml_dtvdemod *)fe->demodulator_priv; |
| struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
| struct amldtvdemod_device_s *devp = |
| (struct amldtvdemod_device_s *)demod->priv; |
| char buf[32] = { 0 }; |
| char *polarity_name = NULL; |
| char *band = NULL; |
| unsigned int pkt_err_cnt, br; |
| static unsigned int pkt_err_cnt_last; |
| static unsigned int times, snr[8]; |
| |
| if (re_tune) { |
| pkt_err_cnt_last = 0; |
| real_para_clear(&demod->real_para); |
| *status = 0; |
| demod->last_status = 0; |
| times = 0; |
| memset(snr, 0, sizeof(unsigned int) * 8); |
| |
| return 0; |
| } |
| |
| dtvdemod_dvbs_read_signal_strength(fe, &strength); |
| // if (strength < THRD_TUNER_STRENGTH_DVBS) { |
| // *status = FE_TIMEDOUT; |
| // demod->last_lock = -1; |
| // PR_DVBS("%s: [id %d] tuner strength [%d] no signal(%d).\n", |
| // __func__, demod->id, strength, THRD_TUNER_STRENGTH_DVBS); |
| // return 0; |
| // } |
| |
| br = dvbs_get_bitrate(c->symbol_rate); |
| pkt_err_cnt = ((dvbs_rd_byte(0xe61) & 0x7f) << 16) + |
| ((dvbs_rd_byte(0xe62) & 0xff) << 8) + (dvbs_rd_byte(0xe63) & 0xff); |
| if (pkt_err_cnt < pkt_err_cnt_last) |
| pkt_err_cnt_last |= 0xff800000; |
| //250ms:errcnt * 10000000000 / (br / 4) >> errcnt * 10 * (4000000000 / br) |
| demod->real_para.ber = (pkt_err_cnt - pkt_err_cnt_last) * 10 * (400000000 / (br / 10)); |
| PR_DVBS("sr=%d, br=%d, ber=%d.%d E-8\n", c->symbol_rate, br, |
| demod->real_para.ber / 100, demod->real_para.ber % 100); |
| pkt_err_cnt_last = pkt_err_cnt; |
| //snr[times % 8] = dvbs_get_quality(); |
| //demod->real_para.snr = (snr[0] + snr[1] + snr[2] + snr[3] + |
| // snr[4] + snr[5] + snr[6] + snr[7]) / 8; |
| //PR_DVBS("==testSNR== snr=%d, ave8=%d, fun:ave8=%d, ave8-1-1=%d, ave8-1-2=%d," |
| // " ave8-2-1=%d, ave8-2-2=%d\n", snr[times % 8], demod->real_para.snr, |
| // calc_ave(snr, 8, 0, 0), calc_ave(snr, 8, 1, 1), calc_ave(snr, 8, 1, 2), |
| // calc_ave(snr, 8, 2, 1), calc_ave(snr, 8, 2, 2)); |
| //times++; |
| snr[times++ % 8] = dvbs_get_quality(); |
| //PR_DVBS("calc_ave cnt:%d ==>%d, %d, %d, %d, %d, %d, %d, %d<==\n", |
| // cnt, snr[0], snr[1], snr[2], snr[3], snr[4], snr[5], snr[6], snr[7]); |
| demod->real_para.snr = calc_ave(snr, 8, 1, 1); |
| PR_DVBS("calc snr = %d dBx10\n", demod->real_para.snr); |
| |
| demod->time_passed = jiffies_to_msecs(jiffies) - demod->time_start; |
| if (demod->time_passed >= 500) { |
| if (!dvbs_rd_byte(0x160)) { |
| // *status = FE_TIMEDOUT; |
| // demod->last_lock = -1; |
| // PR_DVBS("[id %d] not dvbs signal\n", demod->id); |
| // return 0; |
| } |
| } |
| |
| s = amdemod_stat_dvbs_islock(demod, SYS_DVBS); |
| if (s == 1) { |
| ilock = 1; |
| *status = |
| FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | |
| FE_HAS_VITERBI | FE_HAS_SYNC; |
| |
| if (devp->blind_scan_stop) { |
| /* limiting frequency offset is too large. */ |
| offset = dvbs_get_freq_offset(&polarity); |
| if ((offset > 6500 && c->symbol_rate < SR_LOW_THRD) || |
| (offset > 11500 && c->symbol_rate >= SR_LOW_THRD)) { |
| ilock = 0; |
| *status = FE_TIMEDOUT; |
| PR_INFO("%s [id %d]: offset %d KHz too large, sr %d.\n", |
| __func__, demod->id, |
| offset, c->symbol_rate); |
| } |
| } |
| } else { |
| if (timer_not_enough(demod, D_TIMER_DETECT)) { |
| ilock = 0; |
| *status = 0; |
| } else { |
| ilock = 0; |
| *status = FE_TIMEDOUT; |
| timer_disable(demod, D_TIMER_DETECT); |
| } |
| } |
| |
| demod->last_status = *status; |
| |
| if (demod->last_lock != ilock) { |
| memset(buf, 0, 32); |
| snprintf(buf, sizeof(buf), "%d", c->frequency); |
| |
| if (!devp->blind_scan_stop && !demod->demod_status.is_blind_scan && |
| demod->demod_status.is_singlecable) { |
| memset(buf, 0, 32); |
| snprintf(buf, sizeof(buf), "[%d, %d]", if_freq_khz, c->frequency); |
| |
| if (devp->singlecable_param.version == SINGLECABLE_VERSION_1_EN50494) { |
| band = (devp->singlecable_param.bank & 0x1) ? "H" : "L"; |
| polarity_name = (devp->singlecable_param.bank & 0x2) ? "H" : "V"; |
| } else if (devp->singlecable_param.version == |
| SINGLECABLE_VERSION_2_EN50607) { |
| band = (devp->singlecable_param.committed & 0x1) ? "H" : "L"; |
| polarity_name = |
| (devp->singlecable_param.committed & 0x2) ? "H" : "V"; |
| } |
| } |
| |
| PR_INFO("%s [id %d]: %s.freq: %s, sr: %d %s%s\n", __func__, demod->id, |
| ilock ? "!! >> LOCK << !!" : "!! >> UNLOCK << !!", |
| buf, c->symbol_rate, |
| polarity_name ? polarity_name : "", |
| band ? band : ""); |
| demod->last_lock = ilock; |
| /*add for DVBS2 QPSK 1/4 C/N worse*/ |
| if (ilock == 1) { |
| if (((dvbs_rd_byte(0x932) & 0x60) == 0x40) && |
| ((dvbs_rd_byte(0x930) >> 2) == 0x1)) { |
| dvbs_wr_byte(0x991, 0x24); |
| PR_INFO("DVBS2 QPSK 1/4 set 0x991 to 0x24\n"); |
| } |
| } else { |
| dvbs_wr_byte(0x991, 0x40); |
| } |
| } |
| |
| return 0; |
| } |
| |
| int dtvdemod_dvbs_set_frontend(struct dvb_frontend *fe) |
| { |
| struct aml_dtvdemod *demod = (struct aml_dtvdemod *)fe->demodulator_priv; |
| struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
| struct amldtvdemod_device_s *devp = (struct amldtvdemod_device_s *)demod->priv; |
| int ret = 0; |
| unsigned int tmp_sr = 0; |
| |
| if (devp->blind_same_frec == 0) |
| PR_INFO("%s [id %d]: delsys:%d, freq:%d, symbol_rate:%d, bw:%d.\n", |
| __func__, demod->id, c->delivery_system, c->frequency, c->symbol_rate, |
| c->bandwidth_hz); |
| |
| demod->demod_status.symb_rate = c->symbol_rate / 1000; |
| demod->demod_status.is_blind_scan = 0; /* The actual frequency lock normal mode */ |
| demod->last_lock = -1; |
| |
| /* for wider frequency offset when low SR. */ |
| tmp_sr = c->symbol_rate; |
| if (devp->blind_scan_stop && tmp_sr < SR_LOW_THRD) |
| c->symbol_rate = 2 * c->symbol_rate; |
| |
| tuner_set_params(fe); |
| |
| if (devp->blind_scan_stop && tmp_sr < SR_LOW_THRD) |
| c->symbol_rate = tmp_sr; |
| |
| dtvdemod_dvbs_set_ch(&demod->demod_status); |
| demod->time_start = jiffies_to_msecs(jiffies); |
| |
| if (devp->agc_direction) { |
| PR_DVBS("DTV AGC direction: %d, Set dvbs agc pin reverse\n", devp->agc_direction); |
| dvbs_wr_byte(0x118, 0x04); |
| } |
| |
| return ret; |
| } |
| |
| int dtvdemod_dvbs_tune(struct dvb_frontend *fe, bool re_tune, |
| unsigned int mode_flags, unsigned int *delay, enum fe_status *status) |
| { |
| int ret = 0; |
| struct aml_dtvdemod *demod = (struct aml_dtvdemod *)fe->demodulator_priv; |
| struct amldtvdemod_device_s *devp = |
| (struct amldtvdemod_device_s *)demod->priv; |
| |
| *delay = HZ / 8; |
| |
| if (!devp->blind_scan_stop) |
| return ret; |
| |
| if (re_tune) { |
| /*first*/ |
| demod->en_detect = 1; |
| dtvdemod_dvbs_set_frontend(fe); |
| timer_begain(demod, D_TIMER_DETECT); |
| dtvdemod_dvbs_read_status(fe, status, fe->dtv_property_cache.frequency, re_tune); |
| PR_DVBS("[id %d] tune finish!\n", demod->id); |
| return ret; |
| } |
| |
| if (!demod->en_detect) { |
| PR_DBGL("%s: [id %d] not enable.\n", __func__, demod->id); |
| return ret; |
| } |
| |
| dtvdemod_dvbs_read_status(fe, status, fe->dtv_property_cache.frequency, re_tune); |
| dvbs_check_status(NULL); |
| |
| return ret; |
| } |
| |
| int dtvdemod_dvbs2_init(struct aml_dtvdemod *demod) |
| { |
| int ret = 0; |
| struct aml_demod_sys sys; |
| struct amldtvdemod_device_s *devp = (struct amldtvdemod_device_s *)demod->priv; |
| struct ddemod_dig_clk_addr *dig_clk = &devp->data->dig_clk; |
| |
| memset(&sys, 0, sizeof(sys)); |
| memset(&demod->demod_status, 0, sizeof(demod->demod_status)); |
| memset(&devp->singlecable_param, 0, sizeof(devp->singlecable_param)); |
| |
| demod->demod_status.delsys = SYS_DVBS2; |
| sys.adc_clk = ADC_CLK_135M; |
| sys.demod_clk = DEMOD_CLK_270M; |
| demod->demod_status.tmp = CRY_MODE; |
| demod->demod_status.ch_if = DEMOD_5M_IF; |
| demod->demod_status.adc_freq = sys.adc_clk; |
| demod->demod_status.clk_freq = sys.demod_clk; |
| PR_DBG("[%s]adc_clk is %d,demod_clk is %d\n", __func__, sys.adc_clk, |
| sys.demod_clk); |
| demod->auto_flags_trig = 0; |
| demod->last_status = 0; |
| |
| if (devp->data->hw_ver == DTVDEMOD_HW_S4D) { |
| PR_DBG("[%s]S4D SET DEMOD CLK\n", __func__); |
| dd_hiu_reg_write(0x81, 0x702); |
| dd_hiu_reg_write(0x80, 0x501); |
| } else if (devp->data->hw_ver == DTVDEMOD_HW_S1A) { |
| PR_DBG("[%s]S1A SET DEMOD CLK\n", __func__); |
| dd_hiu_reg_write(dig_clk->demod_clk_ctl_1, 0x700); |
| dd_hiu_reg_write(dig_clk->demod_clk_ctl, 0x501); |
| } else { |
| dd_hiu_reg_write(dig_clk->demod_clk_ctl_1, 0x702); |
| dd_hiu_reg_write(dig_clk->demod_clk_ctl, 0x501); |
| } |
| |
| ret = demod_set_sys(demod, &sys); |
| |
| return ret; |
| } |
| |
| int amdemod_stat_dvbs_islock(struct aml_dtvdemod *demod, |
| enum fe_delivery_system delsys) |
| { |
| unsigned int ret = 0; |
| |
| ret = (dvbs_rd_byte(0x160) >> 3) & 0x1; |
| return ret; |
| } |
| |