summaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb-frontends/dib8000.c
diff options
context:
space:
mode:
authorPatrick Boettcher <pboettcher@kernellabs.com>2013-04-22 12:45:52 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-04-22 16:58:16 -0300
commit173a64cb3fcff1993b2aa8113e53fd379f6a968f (patch)
treec1836b2c5208456f61cb7acfcf1771ac5bf444ad /drivers/media/dvb-frontends/dib8000.c
parent1552fb344d5ddd5178e8774a31fdb08765c668e1 (diff)
[media] dib8000: enhancement
The intend of this patch is to improve the support of the dib8000. Signed-off-by: Olivier Grenie <olivier.grenie@parrot.com> Signed-off-by: Patrick Boettcher <patrick.boettcher@parrot.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/dvb-frontends/dib8000.c')
-rw-r--r--drivers/media/dvb-frontends/dib8000.c2235
1 files changed, 1314 insertions, 921 deletions
diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c
index 1f3bcb5a1de8..1d719cce8995 100644
--- a/drivers/media/dvb-frontends/dib8000.c
+++ b/drivers/media/dvb-frontends/dib8000.c
@@ -23,8 +23,8 @@
#define LAYER_B 2
#define LAYER_C 3
-#define FE_CALLBACK_TIME_NEVER 0xffffffff
#define MAX_NUMBER_OF_FRONTENDS 6
+/* #define DIB8000_AGC_FREEZE */
static int debug;
module_param(debug, int, 0644);
@@ -32,8 +32,6 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0)
-#define FE_STATUS_TUNE_FAILED 0
-
struct i2c_device {
struct i2c_adapter *adap;
u8 addr;
@@ -42,6 +40,23 @@ struct i2c_device {
struct mutex *i2c_buffer_lock;
};
+enum param_loop_step {
+ LOOP_TUNE_1,
+ LOOP_TUNE_2
+};
+
+enum dib8000_autosearch_step {
+ AS_START = 0,
+ AS_SEARCHING_FFT,
+ AS_SEARCHING_GUARD,
+ AS_DONE = 100,
+};
+
+enum timeout_mode {
+ SYMBOL_DEPENDENT_OFF = 0,
+ SYMBOL_DEPENDENT_ON,
+};
+
struct dib8000_state {
struct dib8000_config cfg;
@@ -72,7 +87,7 @@ struct dib8000_state {
u16 revision;
u8 isdbt_cfg_loaded;
enum frontend_tune_state tune_state;
- u32 status;
+ s32 status;
struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
@@ -85,6 +100,30 @@ struct dib8000_state {
u16 tuner_enable;
struct i2c_adapter dib8096p_tuner_adap;
+ u16 current_demod_bw;
+
+ u16 seg_mask;
+ u16 seg_diff_mask;
+ u16 mode;
+ u8 layer_b_nb_seg;
+ u8 layer_c_nb_seg;
+
+ u8 channel_parameters_set;
+ u16 autosearch_state;
+ u16 found_nfft;
+ u16 found_guard;
+ u8 subchannel;
+ u8 symbol_duration;
+ u32 timeout;
+ u8 longest_intlv_layer;
+ u16 output_mode;
+
+#ifdef DIB8000_AGC_FREEZE
+ u16 agc1_max;
+ u16 agc1_min;
+ u16 agc2_max;
+ u16 agc2_min;
+#endif
};
enum dib8000_power_mode {
@@ -338,9 +377,9 @@ static void dib8000_set_acquisition_mode(struct dib8000_state *state)
static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode)
{
struct dib8000_state *state = fe->demodulator_priv;
-
u16 outreg, fifo_threshold, smo_mode, sram = 0x0205; /* by default SDRAM deintlv is enabled */
+ state->output_mode = mode;
outreg = 0;
fifo_threshold = 1792;
smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
@@ -399,8 +438,9 @@ static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode)
static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff)
{
struct dib8000_state *state = fe->demodulator_priv;
- u16 sync_wait = dib8000_read_word(state, 273) & 0xfff0;
+ u16 tmp, sync_wait = dib8000_read_word(state, 273) & 0xfff0;
+ dprintk("set diversity input to %i", onoff);
if (!state->differential_constellation) {
dib8000_write_word(state, 272, 1 << 9); //dvsy_off_lmod4 = 1
dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2); // sync_enable = 1; comb_mode = 2
@@ -424,6 +464,13 @@ static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff)
dib8000_write_word(state, 271, 1);
break;
}
+
+ if (state->revision == 0x8002) {
+ tmp = dib8000_read_word(state, 903);
+ dib8000_write_word(state, 903, tmp & ~(1 << 3));
+ msleep(30);
+ dib8000_write_word(state, 903, tmp | (1 << 3));
+ }
return 0;
}
@@ -468,27 +515,6 @@ static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_pow
dib8000_write_word(state, 1280, reg_1280);
}
-static int dib8000_init_sdram(struct dib8000_state *state)
-{
- u16 reg = 0;
- dprintk("Init sdram");
-
- reg = dib8000_read_word(state, 274)&0xfff0;
- /* P_dintlv_delay_ram = 7 because of MobileSdram */
- dib8000_write_word(state, 274, reg | 0x7);
-
- dib8000_write_word(state, 1803, (7<<2));
-
- reg = dib8000_read_word(state, 1280);
- /* force restart P_restart_sdram */
- dib8000_write_word(state, 1280, reg | (1<<2));
-
- /* release restart P_restart_sdram */
- dib8000_write_word(state, 1280, reg);
-
- return 0;
-}
-
static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no)
{
int ret = 0;
@@ -584,18 +610,23 @@ static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw)
static int dib8000_sad_calib(struct dib8000_state *state)
{
+ u8 sad_sel = 3;
+
if (state->revision == 0x8090) {
- dprintk("%s: the sad calibration is not needed for the dib8096P",
- __func__);
- return 0;
- }
- /* internal */
- dib8000_write_word(state, 923, (0 << 1) | (0 << 0));
- dib8000_write_word(state, 924, 776); // 0.625*3.3 / 4096
+ dib8000_write_word(state, 922, (sad_sel << 2));
+ dib8000_write_word(state, 923, 2048);
- /* do the calibration */
- dib8000_write_word(state, 923, (1 << 0));
- dib8000_write_word(state, 923, (0 << 0));
+ dib8000_write_word(state, 922, (sad_sel << 2) | 0x1);
+ dib8000_write_word(state, 922, (sad_sel << 2));
+ } else {
+ /* internal */
+ dib8000_write_word(state, 923, (0 << 1) | (0 << 0));
+ dib8000_write_word(state, 924, 776);
+
+ /* do the calibration */
+ dib8000_write_word(state, 923, (1 << 0));
+ dib8000_write_word(state, 923, (0 << 0));
+ }
msleep(1);
return 0;
@@ -609,8 +640,8 @@ int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
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)
{
dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25);
@@ -685,20 +716,23 @@ static void dib8000_reset_pll(struct dib8000_state *state)
}
int dib8000_update_pll(struct dvb_frontend *fe,
- struct dibx000_bandwidth_config *pll)
+ struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio)
{
struct dib8000_state *state = fe->demodulator_priv;
u16 reg_1857, reg_1856 = dib8000_read_word(state, 1856);
- u8 loopdiv, prediv;
+ u8 loopdiv, prediv, oldprediv = state->cfg.pll->pll_prediv ;
u32 internal, xtal;
/* get back old values */
prediv = reg_1856 & 0x3f;
loopdiv = (reg_1856 >> 6) & 0x3f;
- if ((pll != NULL) && (pll->pll_prediv != prediv ||
- pll->pll_ratio != loopdiv)) {
- dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio);
+ if ((pll == NULL) || (pll->pll_prediv == prediv &&
+ pll->pll_ratio == loopdiv))
+ return -EINVAL;
+
+ dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio);
+ if (state->revision == 0x8090) {
reg_1856 &= 0xf000;
reg_1857 = dib8000_read_word(state, 1857);
/* disable PLL */
@@ -729,10 +763,33 @@ int dib8000_update_pll(struct dvb_frontend *fe,
reg_1856 = dib8000_read_word(state, 1856);
dprintk("PLL Updated with prediv = %d and loopdiv = %d",
reg_1856&0x3f, (reg_1856>>6)&0x3f);
+ } else {
+ if (bw != state->current_demod_bw) {
+ /** Bandwidth change => force PLL update **/
+ dprintk("PLL: Bandwidth Change %d MHz -> %d MHz (prediv: %d->%d)", state->current_demod_bw / 1000, bw / 1000, oldprediv, state->cfg.pll->pll_prediv);
+
+ if (state->cfg.pll->pll_prediv != oldprediv) {
+ /** Full PLL change only if prediv is changed **/
+
+ /** full update => bypass and reconfigure **/
+ dprintk("PLL: New Setting for %d MHz Bandwidth (prediv: %d, ratio: %d)", bw/1000, state->cfg.pll->pll_prediv, state->cfg.pll->pll_ratio);
+ dib8000_write_word(state, 902, dib8000_read_word(state, 902) | (1<<3)); /* bypass PLL */
+ dib8000_reset_pll(state);
+ dib8000_write_word(state, 898, 0x0004); /* sad */
+ } else
+ ratio = state->cfg.pll->pll_ratio;
- return 0;
- }
- return -EINVAL;
+ state->current_demod_bw = bw;
+ }
+
+ if (ratio != 0) {
+ /** ratio update => only change ratio **/
+ 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);
@@ -928,7 +985,7 @@ static int dib8000_reset(struct dvb_frontend *fe)
dib8000_set_power_mode(state, DIB8000_POWER_ALL);
/* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
- dib8000_set_adc_state(state, DIBX000_VBG_ENABLE);
+ dib8000_set_adc_state(state, DIBX000_ADC_OFF);
/* restart all parts */
dib8000_write_word(state, 770, 0xffff);
@@ -992,12 +1049,11 @@ static int dib8000_reset(struct dvb_frontend *fe)
l = *n++;
}
}
- if (state->revision != 0x8090)
- dib8000_write_word(state, 903, (0 << 4) | 2);
+
state->isdbt_cfg_loaded = 0;
//div_cfg override for special configs
- if (state->cfg.div_cfg != 0)
+ if ((state->revision != 8090) && (state->cfg.div_cfg != 0))
dib8000_write_word(state, 903, state->cfg.div_cfg);
/* unforce divstr regardless whether i2c enumeration was done or not */
@@ -1006,10 +1062,12 @@ static int dib8000_reset(struct dvb_frontend *fe)
dib8000_set_bandwidth(fe, 6000);
dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);
- if (state->revision != 0x8090) {
- dib8000_sad_calib(state);
+ dib8000_sad_calib(state);
+ if (state->revision != 0x8090)
dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
- }
+
+ /* ber_rs_len = 3 */
+ dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));
dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
@@ -1441,6 +1499,7 @@ static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode)
u8 prefer_mpeg_mux_use = 1;
int ret = 0;
+ state->output_mode = mode;
dib8096p_host_bus_drive(state, 1);
fifo_threshold = 1792;
@@ -1879,782 +1938,637 @@ static const u16 adc_target_16dB[11] = {
};
static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
-static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
+static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 max_constellation)
{
- u16 mode, max_constellation, seg_diff_mask = 0, nbseg_diff = 0;
- u8 guard, crate, constellation, timeI;
- u16 i, coeff[4], P_cfr_left_edge = 0, P_cfr_right_edge = 0, seg_mask13 = 0x1fff; // All 13 segments enabled
- const s16 *ncoeff = NULL, *ana_fe;
- u16 tmcc_pow = 0;
- u16 coff_pow = 0x2800;
- u16 init_prbs = 0xfff;
- u16 ana_gain = 0;
-
- if (state->revision == 0x8090)
- dib8000_init_sdram(state);
-
- if (state->ber_monitored_layer != LAYER_ALL)
- dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & 0x60) | state->ber_monitored_layer);
- else
- dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
-
- i = dib8000_read_word(state, 26) & 1; // P_dds_invspec
- dib8000_write_word(state, 26, state->fe[0]->dtv_property_cache.inversion^i);
-
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
- //compute new dds_freq for the seg and adjust prbs
- int seg_offset =
- state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx -
- (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) -
- (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2);
- int clk = state->cfg.pll->internal;
- u32 segtodds = ((u32) (430 << 23) / clk) << 3; // segtodds = SegBW / Fclk * pow(2,26)
- int dds_offset = seg_offset * segtodds;
- int new_dds, sub_channel;
- if ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
- dds_offset -= (int)(segtodds / 2);
-
- if (state->cfg.pll->ifreq == 0) {
- if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0) {
- dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);
- new_dds = dds_offset;
- } else
- new_dds = dds_offset;
-
- // We shift tuning frequency if the wanted segment is :
- // - the segment of center frequency with an odd total number of segments
- // - the segment to the left of center frequency with an even total number of segments
- // - the segment to the right of center frequency with an even total number of segments
- if ((state->fe[0]->dtv_property_cache.delivery_system == SYS_ISDBT)
- && (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)
- && (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2)
- && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx ==
- ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
- || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
- && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx == (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2)))
- || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
- && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx ==
- ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
- )) {
- new_dds -= ((u32) (850 << 22) / clk) << 4; // new_dds = 850 (freq shift in KHz) / Fclk * pow(2,26)
- }
- } else {
- if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0)
- new_dds = state->cfg.pll->ifreq - dds_offset;
- else
- new_dds = state->cfg.pll->ifreq + dds_offset;
- }
- dib8000_write_word(state, 27, (u16) ((new_dds >> 16) & 0x01ff));
- dib8000_write_word(state, 28, (u16) (new_dds & 0xffff));
- if (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2)
- sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset) + 1) % 41) / 3;
- else
- sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset)) % 41) / 3;
- sub_channel -= 6;
-
- if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K
- || state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_4K) {
- dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); //adp_pass =1
- dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); //pha3_force_pha_shift = 1
- } else {
- dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); //adp_pass =0
- dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); //pha3_force_pha_shift = 0
- }
-
- switch (state->fe[0]->dtv_property_cache.transmission_mode) {
- case TRANSMISSION_MODE_2K:
- switch (sub_channel) {
- case -6:
- init_prbs = 0x0;
- break; // 41, 0, 1
- case -5:
- init_prbs = 0x423;
- break; // 02~04
- case -4:
- init_prbs = 0x9;
- break; // 05~07
- case -3:
- init_prbs = 0x5C7;
- break; // 08~10
- case -2:
- init_prbs = 0x7A6;
- break; // 11~13
- case -1:
- init_prbs = 0x3D8;
- break; // 14~16
- case 0:
- init_prbs = 0x527;
- break; // 17~19
- case 1:
- init_prbs = 0x7FF;
- break; // 20~22
- case 2:
- init_prbs = 0x79B;
- break; // 23~25
- case 3:
- init_prbs = 0x3D6;
- break; // 26~28
- case 4:
- init_prbs = 0x3A2;
- break; // 29~31
- case 5:
- init_prbs = 0x53B;
- break; // 32~34
- case 6:
- init_prbs = 0x2F4;
- break; // 35~37
- default:
- case 7:
- init_prbs = 0x213;
- break; // 38~40
- }
- break;
+ u8 cr, constellation, time_intlv;
- case TRANSMISSION_MODE_4K:
- switch (sub_channel) {
- case -6:
- init_prbs = 0x0;
- break; // 41, 0, 1
- case -5:
- init_prbs = 0x208;
- break; // 02~04
- case -4:
- init_prbs = 0xC3;
- break; // 05~07
- case -3:
- init_prbs = 0x7B9;
- break; // 08~10
- case -2:
- init_prbs = 0x423;
- break; // 11~13
- case -1:
- init_prbs = 0x5C7;
- break; // 14~16
- case 0:
- init_prbs = 0x3D8;
- break; // 17~19
- case 1:
- init_prbs = 0x7FF;
- break; // 20~22
- case 2:
- init_prbs = 0x3D6;
- break; // 23~25
- case 3:
- init_prbs = 0x53B;
- break; // 26~28
- case 4:
- init_prbs = 0x213;
- break; // 29~31
- case 5:
- init_prbs = 0x29;
- break; // 32~34
- case 6:
- init_prbs = 0xD0;
- break; // 35~37
- default:
- case 7:
- init_prbs = 0x48E;
- break; // 38~40
- }
- break;
-
- default:
- case TRANSMISSION_MODE_8K:
- switch (sub_channel) {
- case -6:
- init_prbs = 0x0;
- break; // 41, 0, 1
- case -5:
- init_prbs = 0x740;
- break; // 02~04
- case -4:
- init_prbs = 0x069;
- break; // 05~07
- case -3:
- init_prbs = 0x7DD;
- break; // 08~10
- case -2:
- init_prbs = 0x208;
- break; // 11~13
- case -1:
- init_prbs = 0x7B9;
- break; // 14~16
- case 0:
- init_prbs = 0x5C7;
- break; // 17~19
- case 1:
- init_prbs = 0x7FF;
- break; // 20~22
- case 2:
- init_prbs = 0x53B;
- break; // 23~25
- case 3:
- init_prbs = 0x29;
- break; // 26~28
- case 4:
- init_prbs = 0x48E;
- break; // 29~31
- case 5:
- init_prbs = 0x4C4;
- break; // 32~34
- case 6:
- init_prbs = 0x367;
- break; // 33~37
- default:
- case 7:
- init_prbs = 0x684;
- break; // 38~40
- }
- break;
- }
- } else {
- dib8000_write_word(state, 27, (u16) ((state->cfg.pll->ifreq >> 16) & 0x01ff));
- dib8000_write_word(state, 28, (u16) (state->cfg.pll->ifreq & 0xffff));
- dib8000_write_word(state, 26, (u16) ((state->cfg.pll->ifreq >> 25) & 0x0003));
- }
- /*P_mode == ?? */
- dib8000_write_word(state, 10, (seq << 4));
- // dib8000_write_word(state, 287, (dib8000_read_word(state, 287) & 0xe000) | 0x1000);
-
- switch (state->fe[0]->dtv_property_cache.guard_interval) {
- case GUARD_INTERVAL_1_32:
- guard = 0;
- break;
- case GUARD_INTERVAL_1_16:
- guard = 1;
- break;
- case GUARD_INTERVAL_1_8:
- guard = 2;
- break;
- case GUARD_INTERVAL_1_4:
- default:
- guard = 3;
- break;
- }
-
- dib8000_write_word(state, 1, (init_prbs << 2) | (guard & 0x3)); // ADDR 1
-
- max_constellation = DQPSK;
- for (i = 0; i < 3; i++) {
- switch (state->fe[0]->dtv_property_cache.layer[i].modulation) {
- case DQPSK:
+ switch (state->fe[0]->dtv_property_cache.layer[layer_index].modulation) {
+ case DQPSK:
constellation = 0;
break;
- case QPSK:
+ case QPSK:
constellation = 1;
break;
- case QAM_16:
+ case QAM_16:
constellation = 2;
break;
- case QAM_64:
- default:
+ case QAM_64:
+ default:
constellation = 3;
break;
- }
+ }
- switch (state->fe[0]->dtv_property_cache.layer[i].fec) {
- case FEC_1_2:
- crate = 1;
+ switch (state->fe[0]->dtv_property_cache.layer[layer_index].fec) {
+ case FEC_1_2:
+ cr = 1;
break;
- case FEC_2_3:
- crate = 2;
+ case FEC_2_3:
+ cr = 2;
break;
- case FEC_3_4:
- crate = 3;
+ case FEC_3_4:
+ cr = 3;
break;
- case FEC_5_6:
- crate = 5;
+ case FEC_5_6:
+ cr = 5;
break;
- case FEC_7_8:
- default:
- crate = 7;
+ case FEC_7_8:
+ default:
+ cr = 7;
break;
- }
+ }
- if ((state->fe[0]->dtv_property_cache.layer[i].interleaving > 0) &&
- ((state->fe[0]->dtv_property_cache.layer[i].interleaving <= 3) ||
- (state->fe[0]->dtv_property_cache.layer[i].interleaving == 4 && state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1))
- )
- timeI = state->fe[0]->dtv_property_cache.layer[i].interleaving;
- else
- timeI = 0;
- dib8000_write_word(state, 2 + i, (constellation << 10) | ((state->fe[0]->dtv_property_cache.layer[i].segment_count & 0xf) << 6) |
- (crate << 3) | timeI);
- if (state->fe[0]->dtv_property_cache.layer[i].segment_count > 0) {
- switch (max_constellation) {
- case DQPSK:
- case QPSK:
- if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_16 ||
- state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64)
- max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation;
+ if ((state->fe[0]->dtv_property_cache.layer[layer_index].interleaving > 0) && ((state->fe[0]->dtv_property_cache.layer[layer_index].interleaving <= 3) || (state->fe[0]->dtv_property_cache.layer[layer_index].interleaving == 4 && state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)))
+ time_intlv = state->fe[0]->dtv_property_cache.layer[layer_index].interleaving;
+ else
+ time_intlv = 0;
+
+ dib8000_write_word(state, 2 + layer_index, (constellation << 10) | ((state->fe[0]->dtv_property_cache.layer[layer_index].segment_count & 0xf) << 6) | (cr << 3) | time_intlv);
+ if (state->fe[0]->dtv_property_cache.layer[layer_index].segment_count > 0) {
+ switch (max_constellation) {
+ case DQPSK:
+ case QPSK:
+ if (state->fe[0]->dtv_property_cache.layer[layer_index].modulation == QAM_16 || state->fe[0]->dtv_property_cache.layer[layer_index].modulation == QAM_64)
+ max_constellation = state->fe[0]->dtv_property_cache.layer[layer_index].modulation;
break;
- case QAM_16:
- if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64)
- max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation;
+ case QAM_16:
+ if (state->fe[0]->dtv_property_cache.layer[layer_index].modulation == QAM_64)
+ max_constellation = state->fe[0]->dtv_property_cache.layer[layer_index].modulation;
break;
- }
}
}
- mode = fft_to_mode(state);
+ return max_constellation;
+}
- //dib8000_write_word(state, 5, 13); /*p_last_seg = 13*/
+static const u16 adp_Q64[4] = {0x0148, 0xfff0, 0x00a4, 0xfff8}; /* P_adp_regul_cnt 0.04, P_adp_noise_cnt -0.002, P_adp_regul_ext 0.02, P_adp_noise_ext -0.001 */
+static const u16 adp_Q16[4] = {0x023d, 0xffdf, 0x00a4, 0xfff0}; /* P_adp_regul_cnt 0.07, P_adp_noise_cnt -0.004, P_adp_regul_ext 0.02, P_adp_noise_ext -0.002 */
+static const u16 adp_Qdefault[4] = {0x099a, 0xffae, 0x0333, 0xfff8}; /* P_adp_regul_cnt 0.3, P_adp_noise_cnt -0.01, P_adp_regul_ext 0.1, P_adp_noise_ext -0.002 */
+static u16 dib8000_adp_fine_tune(struct dib8000_state *state, u16 max_constellation)
+{
+ u16 i, ana_gain = 0;
+ const u16 *adp;
- dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) |
- ((state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 5) | ((state->fe[0]->dtv_property_cache.
- isdbt_sb_mode & 1) << 4));
+ /* channel estimation fine configuration */
+ switch (max_constellation) {
+ case QAM_64:
+ ana_gain = 0x7;
+ adp = &adp_Q64[0];
+ break;
+ case QAM_16:
+ ana_gain = 0x7;
+ adp = &adp_Q16[0];
+ break;
+ default:
+ ana_gain = 0;
+ adp = &adp_Qdefault[0];
+ break;
+ }
- dprintk("mode = %d ; guard = %d", mode, state->fe[0]->dtv_property_cache.guard_interval);
+ for (i = 0; i < 4; i++)
+ dib8000_write_word(state, 215 + i, adp[i]);
- /* signal optimization parameter */
+ return ana_gain;
+}
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception) {
- seg_diff_mask = (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) << permu_seg[0];
- for (i = 1; i < 3; i++)
- nbseg_diff +=
- (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count;
- for (i = 0; i < nbseg_diff; i++)
- seg_diff_mask |= 1 << permu_seg[i + 1];
- } else {
- for (i = 0; i < 3; i++)
- nbseg_diff +=
- (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count;
- for (i = 0; i < nbseg_diff; i++)
- seg_diff_mask |= 1 << permu_seg[i];
+static void dib8000_update_ana_gain(struct dib8000_state *state, u16 ana_gain)
+{
+ u16 i;
+
+ dib8000_write_word(state, 116, ana_gain);
+
+ /* update ADC target depending on ana_gain */
+ if (ana_gain) { /* set -16dB ADC target for ana_gain=-1 */
+ for (i = 0; i < 10; i++)
+ dib8000_write_word(state, 80 + i, adc_target_16dB[i]);
+ } else { /* set -22dB ADC target for ana_gain=0 */
+ for (i = 0; i < 10; i++)
+ dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);
}
- dprintk("nbseg_diff = %X (%d)", seg_diff_mask, seg_diff_mask);
+}
- state->differential_constellation = (seg_diff_mask != 0);
- if (state->revision != 0x8090)
- dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
- else
- dib8096p_set_diversity_in(state->fe[0], state->diversity_onoff);
+static void dib8000_load_ana_fe_coefs(struct dib8000_state *state, const s16 *ana_fe)
+{
+ u16 mode = 0;
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1)
- seg_mask13 = 0x00E0;
- else // 1-segment
- seg_mask13 = 0x0040;
- } else
- seg_mask13 = 0x1fff;
+ if (state->isdbt_cfg_loaded == 0)
+ for (mode = 0; mode < 24; mode++)
+ dib8000_write_word(state, 117 + mode, ana_fe[mode]);
+}
+
+static const u16 lut_prbs_2k[14] = {
+ 0, 0x423, 0x009, 0x5C7, 0x7A6, 0x3D8, 0x527, 0x7FF, 0x79B, 0x3D6, 0x3A2, 0x53B, 0x2F4, 0x213
+};
+static const u16 lut_prbs_4k[14] = {
+ 0, 0x208, 0x0C3, 0x7B9, 0x423, 0x5C7, 0x3D8, 0x7FF, 0x3D6, 0x53B, 0x213, 0x029, 0x0D0, 0x48E
+};
+static const u16 lut_prbs_8k[14] = {
+ 0, 0x740, 0x069, 0x7DD, 0x208, 0x7B9, 0x5C7, 0x7FF, 0x53B, 0x029, 0x48E, 0x4C4, 0x367, 0x684
+};
- // WRITE: Mode & Diff mask
- dib8000_write_word(state, 0, (mode << 13) | seg_diff_mask);
+static u16 dib8000_get_init_prbs(struct dib8000_state *state, u16 subchannel)
+{
+ int sub_channel_prbs_group = 0;
- if ((seg_diff_mask) || (state->fe[0]->dtv_property_cache.isdbt_sb_mode))
- dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
- else
- dib8000_write_word(state, 268, (2 << 9) | 39); //init value
+ sub_channel_prbs_group = (subchannel / 3) + 1;
+ dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x", sub_channel_prbs_group, subchannel, lut_prbs_8k[sub_channel_prbs_group]);
+
+ switch (state->fe[0]->dtv_property_cache.transmission_mode) {
+ case TRANSMISSION_MODE_2K:
+ return lut_prbs_2k[sub_channel_prbs_group];
+ case TRANSMISSION_MODE_4K:
+ return lut_prbs_4k[sub_channel_prbs_group];
+ default:
+ case TRANSMISSION_MODE_8K:
+ return lut_prbs_8k[sub_channel_prbs_group];
+ }
+}
- // ---- SMALL ----
- // P_small_seg_diff
- dib8000_write_word(state, 352, seg_diff_mask); // ADDR 352
+static void dib8000_set_13seg_channel(struct dib8000_state *state)
+{
+ u16 i;
+ u16 coff_pow = 0x2800;
- dib8000_write_word(state, 353, seg_mask13); // ADDR 353
+ state->seg_mask = 0x1fff; /* All 13 segments enabled */
-/* // P_small_narrow_band=0, P_small_last_seg=13, P_small_offset_num_car=5 */
+ /* ---- COFF ---- Carloff, the most robust --- */
+ if (state->isdbt_cfg_loaded == 0) { /* if not Sound Broadcasting mode : put default values for 13 segments */
+ dib8000_write_word(state, 180, (16 << 6) | 9);
+ dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2);
+ coff_pow = 0x2800;
+ for (i = 0; i < 6; i++)
+ dib8000_write_word(state, 181+i, coff_pow);
+
+ /* P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1 */
+ /* P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 3, P_pre_freq_win_len=1 */
+ dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1);
+
+ /* P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6 */
+ dib8000_write_word(state, 340, (8 << 6) | (6 << 0));
+ /* P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1 */
+ dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
+
+ dib8000_write_word(state, 228, 0); /* default value */
+ dib8000_write_word(state, 265, 31); /* default value */
+ dib8000_write_word(state, 205, 0x200f); /* init value */
+ }
+
+ /*
+ * make the cpil_coff_lock more robust but slower p_coff_winlen
+ * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
+ */
+
+ if (state->cfg.pll->ifreq == 0)
+ dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */
+
+ dib8000_load_ana_fe_coefs(state, ana_fe_coeff_13seg);
+}
+
+static void dib8000_set_subchannel_prbs(struct dib8000_state *state, u16 init_prbs)
+{
+ u16 reg_1;
- // ---- SMALL ----
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
+ reg_1 = dib8000_read_word(state, 1);
+ dib8000_write_word(state, 1, (init_prbs << 2) | (reg_1 & 0x3)); /* ADDR 1 */
+}
+
+static void dib8000_small_fine_tune(struct dib8000_state *state)
+{
+ u16 i;
+ const s16 *ncoeff;
+
+ dib8000_write_word(state, 352, state->seg_diff_mask);
+ dib8000_write_word(state, 353, state->seg_mask);
+
+ /* P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5 */
+ dib8000_write_word(state, 351, (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 9) | (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 8) | (13 << 4) | 5);
+
+ if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
+ /* ---- SMALL ---- */
switch (state->fe[0]->dtv_property_cache.transmission_mode) {
case TRANSMISSION_MODE_2K:
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
- if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
- ncoeff = coeff_2k_sb_1seg_dqpsk;
- else // QPSK or QAM
- ncoeff = coeff_2k_sb_1seg;
- } else { // 3-segments
- if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
- if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK)
- ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;
- else // QPSK or QAM on external segments
- ncoeff = coeff_2k_sb_3seg_0dqpsk;
- } else { // QPSK or QAM on central segment
- if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK)
- ncoeff = coeff_2k_sb_3seg_1dqpsk;
- else // QPSK or QAM on external segments
- ncoeff = coeff_2k_sb_3seg;
+ if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { /* 1-seg */
+ if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) /* DQPSK */
+ ncoeff = coeff_2k_sb_1seg_dqpsk;
+ else /* QPSK or QAM */
+ ncoeff = coeff_2k_sb_1seg;
+ } else { /* 3-segments */
+ if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { /* DQPSK on central segment */
+ if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */
+ ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;
+ else /* QPSK or QAM on external segments */
+ ncoeff = coeff_2k_sb_3seg_0dqpsk;
+ } else { /* QPSK or QAM on central segment */
+ if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */
+ ncoeff = coeff_2k_sb_3seg_1dqpsk;
+ else /* QPSK or QAM on external segments */
+ ncoeff = coeff_2k_sb_3seg;
+ }
}
- }
- break;
-
+ break;
case TRANSMISSION_MODE_4K:
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
- if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
- ncoeff = coeff_4k_sb_1seg_dqpsk;
- else // QPSK or QAM
- ncoeff = coeff_4k_sb_1seg;
- } else { // 3-segments
- if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
- if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
- ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
- } else { // QPSK or QAM on external segments
- ncoeff = coeff_4k_sb_3seg_0dqpsk;
+ if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { /* 1-seg */
+ if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) /* DQPSK */
+ ncoeff = coeff_4k_sb_1seg_dqpsk;
+ else /* QPSK or QAM */
+ ncoeff = coeff_4k_sb_1seg;
+ } else { /* 3-segments */
+ if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { /* DQPSK on central segment */
+ if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */
+ ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
+ else /* QPSK or QAM on external segments */
+ ncoeff = coeff_4k_sb_3seg_0dqpsk;
+ } else { /* QPSK or QAM on central segment */
+ if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */
+ ncoeff = coeff_4k_sb_3seg_1dqpsk;
+ else /* QPSK or QAM on external segments */
+ ncoeff = coeff_4k_sb_3seg;
}
- } else { // QPSK or QAM on central segment
- if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
- ncoeff = coeff_4k_sb_3seg_1dqpsk;
- } else // QPSK or QAM on external segments
- ncoeff = coeff_4k_sb_3seg;
}
- }
- break;
-
+ break;
case TRANSMISSION_MODE_AUTO:
case TRANSMISSION_MODE_8K:
default:
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
- if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
- ncoeff = coeff_8k_sb_1seg_dqpsk;
- else // QPSK or QAM
- ncoeff = coeff_8k_sb_1seg;
- } else { // 3-segments
- if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
- if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
- ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
- } else { // QPSK or QAM on external segments
- ncoeff = coeff_8k_sb_3seg_0dqpsk;
+ if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { /* 1-seg */
+ if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) /* DQPSK */
+ ncoeff = coeff_8k_sb_1seg_dqpsk;
+ else /* QPSK or QAM */
+ ncoeff = coeff_8k_sb_1seg;
+ } else { /* 3-segments */
+ if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { /* DQPSK on central segment */
+ if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */
+ ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
+ else /* QPSK or QAM on external segments */
+ ncoeff = coeff_8k_sb_3seg_0dqpsk;
+ } else { /* QPSK or QAM on central segment */
+ if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */
+ ncoeff = coeff_8k_sb_3seg_1dqpsk;
+ else /* QPSK or QAM on external segments */
+ ncoeff = coeff_8k_sb_3seg;
}
- } else { // QPSK or QAM on central segment
- if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
- ncoeff = coeff_8k_sb_3seg_1dqpsk;
- } else // QPSK or QAM on external segments
- ncoeff = coeff_8k_sb_3seg;
}
- }
- break;
+ break;
}
+
for (i = 0; i < 8; i++)
dib8000_write_word(state, 343 + i, ncoeff[i]);
}
+}
- // P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5
- dib8000_write_word(sta