Commit d9b6f08a authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab

[media] mb86a20s: add a logic for post-BER measurement

The logic here is similar to the preBER.
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 313cf4ef
...@@ -104,13 +104,20 @@ static struct regdata mb86a20s_init[] = { ...@@ -104,13 +104,20 @@ static struct regdata mb86a20s_init[] = {
{ 0x50, 0xae }, { 0x51, 0xff }, { 0x50, 0xae }, { 0x51, 0xff },
{ 0x50, 0xaf }, { 0x51, 0xff }, { 0x50, 0xaf }, { 0x51, 0xff },
{ 0x5e, 0x00 }, /* Turn off BER after Viterbi */ /*
{ 0x50, 0xdc }, { 0x51, 0x01 }, * On this demod, post BER counts blocks. When the count reaches the
{ 0x50, 0xdd }, { 0x51, 0xf4 }, * value below, it collects the block error count. The block counters
{ 0x50, 0xde }, { 0x51, 0x01 }, * are initialized to 127 here. This warrants that all of them will be
{ 0x50, 0xdf }, { 0x51, 0xf4 }, * quickly calculated when device gets locked. As TMCC is parsed, the
{ 0x50, 0xe0 }, { 0x51, 0x01 }, * values will be adjusted later in the driver's code.
{ 0x50, 0xe1 }, { 0x51, 0xf4 }, */
{ 0x5e, 0x07 }, /* Turn on BER after Viterbi */
{ 0x50, 0xdc }, { 0x51, 0x00 },
{ 0x50, 0xdd }, { 0x51, 0x7f },
{ 0x50, 0xde }, { 0x51, 0x00 },
{ 0x50, 0xdf }, { 0x51, 0x7f },
{ 0x50, 0xe0 }, { 0x51, 0x00 },
{ 0x50, 0xe1 }, { 0x51, 0x7f },
/* /*
* On this demod, when the block count reaches the count below, * On this demod, when the block count reaches the count below,
...@@ -187,12 +194,13 @@ static struct regdata mb86a20s_reset_reception[] = { ...@@ -187,12 +194,13 @@ static struct regdata mb86a20s_reset_reception[] = {
{ 0x08, 0x00 }, { 0x08, 0x00 },
}; };
static struct regdata mb86a20s_vber_reset[] = { static struct regdata mb86a20s_per_ber_reset[] = {
{ 0x53, 0x00 }, /* VBER Counter reset */ { 0x53, 0x00 }, /* pre BER Counter reset */
{ 0x53, 0x07 }, { 0x53, 0x07 },
};
static struct regdata mb86a20s_per_reset[] = { { 0x5f, 0x00 }, /* post BER Counter reset */
{ 0x5f, 0x07 },
{ 0x50, 0xb1 }, /* PER Counter reset */ { 0x50, 0xb1 }, /* PER Counter reset */
{ 0x51, 0x07 }, { 0x51, 0x07 },
{ 0x51, 0x00 }, { 0x51, 0x00 },
...@@ -731,6 +739,8 @@ static int mb86a20s_reset_counters(struct dvb_frontend *fe) ...@@ -731,6 +739,8 @@ static int mb86a20s_reset_counters(struct dvb_frontend *fe)
memset(&c->cnr, 0, sizeof(c->cnr)); memset(&c->cnr, 0, sizeof(c->cnr));
memset(&c->pre_bit_error, 0, sizeof(c->pre_bit_error)); memset(&c->pre_bit_error, 0, sizeof(c->pre_bit_error));
memset(&c->pre_bit_count, 0, sizeof(c->pre_bit_count)); memset(&c->pre_bit_count, 0, sizeof(c->pre_bit_count));
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)); memset(&c->block_error, 0, sizeof(c->block_error));
memset(&c->block_count, 0, sizeof(c->block_count)); memset(&c->block_count, 0, sizeof(c->block_count));
...@@ -739,13 +749,8 @@ static int mb86a20s_reset_counters(struct dvb_frontend *fe) ...@@ -739,13 +749,8 @@ static int mb86a20s_reset_counters(struct dvb_frontend *fe)
/* Clear status for most stats */ /* Clear status for most stats */
/* BER counter reset */ /* BER/PER counter reset */
rc = mb86a20s_writeregdata(state, mb86a20s_vber_reset); rc = mb86a20s_writeregdata(state, mb86a20s_per_ber_reset);
if (rc < 0)
goto err;
/* MER, PER counter reset */
rc = mb86a20s_writeregdata(state, mb86a20s_per_reset);
if (rc < 0) if (rc < 0)
goto err; goto err;
...@@ -915,7 +920,124 @@ static int mb86a20s_get_pre_ber(struct dvb_frontend *fe, ...@@ -915,7 +920,124 @@ static int mb86a20s_get_pre_ber(struct dvb_frontend *fe,
rc = mb86a20s_writereg(state, 0x53, val | (1 << layer)); rc = mb86a20s_writereg(state, 0x53, val | (1 << layer));
} }
return rc;
}
static int mb86a20s_get_post_ber(struct dvb_frontend *fe,
unsigned layer,
u32 *error, u32 *count)
{
struct mb86a20s_state *state = fe->demodulator_priv;
u32 counter, collect_rate;
int rc, val;
dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
if (layer >= 3)
return -EINVAL;
/* Check if the BER measures are already available */
rc = mb86a20s_readreg(state, 0x60);
if (rc < 0)
return rc;
/* Check if data is available for that layer */
if (!(rc & (1 << layer))) {
dev_dbg(&state->i2c->dev,
"%s: post BER for layer %c is not available yet.\n",
__func__, 'A' + layer);
return -EBUSY;
}
/* Read Bit Error Count */
rc = mb86a20s_readreg(state, 0x64 + layer * 3);
if (rc < 0)
return rc;
*error = rc << 16;
rc = mb86a20s_readreg(state, 0x65 + layer * 3);
if (rc < 0)
return rc;
*error |= rc << 8;
rc = mb86a20s_readreg(state, 0x66 + layer * 3);
if (rc < 0)
return rc;
*error |= rc;
dev_dbg(&state->i2c->dev,
"%s: post bit error for layer %c: %d.\n",
__func__, 'A' + layer, *error);
/* Read Bit Count */
rc = mb86a20s_writereg(state, 0x50, 0xdc + layer * 2);
if (rc < 0)
return rc;
rc = mb86a20s_readreg(state, 0x51);
if (rc < 0)
return rc;
counter = rc << 8;
rc = mb86a20s_writereg(state, 0x50, 0xdd + layer * 2);
if (rc < 0)
return rc;
rc = mb86a20s_readreg(state, 0x51);
if (rc < 0)
return rc;
counter |= rc;
*count = counter * 204 * 8;
dev_dbg(&state->i2c->dev,
"%s: post bit count for layer %c: %d.\n",
__func__, 'A' + layer, *count);
/*
* As we get TMCC data from the frontend, we can better estimate the
* BER bit counters, in order to do the BER measure during a longer
* time. Use those data, if available, to update the bit count
* measure.
*/
if (!state->estimated_rate[layer])
goto reset_measurement;
collect_rate = state->estimated_rate[layer] / 204 / 8;
if (collect_rate < 32)
collect_rate = 32;
if (collect_rate > 65535)
collect_rate = 65535;
if (collect_rate != counter) {
dev_dbg(&state->i2c->dev,
"%s: updating postBER counter on layer %c to %d.\n",
__func__, 'A' + layer, collect_rate);
/* Turn off BER after Viterbi */
rc = mb86a20s_writereg(state, 0x5e, 0x00);
/* Update counter for this layer */
rc = mb86a20s_writereg(state, 0x50, 0xdc + layer * 2);
if (rc < 0)
return rc;
rc = mb86a20s_writereg(state, 0x51, collect_rate >> 8);
if (rc < 0)
return rc;
rc = mb86a20s_writereg(state, 0x50, 0xdd + layer * 2);
if (rc < 0)
return rc;
rc = mb86a20s_writereg(state, 0x51, collect_rate & 0xff);
if (rc < 0)
return rc;
/* Turn on BER after Viterbi */
rc = mb86a20s_writereg(state, 0x5e, 0x07);
/* Reset all preBER counters */
rc = mb86a20s_writereg(state, 0x5f, 0x00);
if (rc < 0)
return rc;
rc = mb86a20s_writereg(state, 0x5f, 0x07);
return rc;
}
reset_measurement:
/* Reset counter to collect new data */ /* Reset counter to collect new data */
rc = mb86a20s_readreg(state, 0x5f); rc = mb86a20s_readreg(state, 0x5f);
if (rc < 0) if (rc < 0)
...@@ -924,7 +1046,7 @@ static int mb86a20s_get_pre_ber(struct dvb_frontend *fe, ...@@ -924,7 +1046,7 @@ static int mb86a20s_get_pre_ber(struct dvb_frontend *fe,
rc = mb86a20s_writereg(state, 0x5f, val & ~(1 << layer)); rc = mb86a20s_writereg(state, 0x5f, val & ~(1 << layer));
if (rc < 0) if (rc < 0)
return rc; return rc;
rc = mb86a20s_writereg(state, 0x5f, val); rc = mb86a20s_writereg(state, 0x5f, val | (1 << layer));
return rc; return rc;
} }
...@@ -1417,6 +1539,8 @@ static void mb86a20s_stats_not_ready(struct dvb_frontend *fe) ...@@ -1417,6 +1539,8 @@ static void mb86a20s_stats_not_ready(struct dvb_frontend *fe)
c->cnr.len = 4; c->cnr.len = 4;
c->pre_bit_error.len = 4; c->pre_bit_error.len = 4;
c->pre_bit_count.len = 4; c->pre_bit_count.len = 4;
c->post_bit_error.len = 4;
c->post_bit_count.len = 4;
c->block_error.len = 4; c->block_error.len = 4;
c->block_count.len = 4; c->block_count.len = 4;
...@@ -1429,6 +1553,8 @@ static void mb86a20s_stats_not_ready(struct dvb_frontend *fe) ...@@ -1429,6 +1553,8 @@ static void mb86a20s_stats_not_ready(struct dvb_frontend *fe)
c->cnr.stat[i].scale = FE_SCALE_NOT_AVAILABLE; c->cnr.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
c->pre_bit_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE; c->pre_bit_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
c->pre_bit_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE; c->pre_bit_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
c->post_bit_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
c->post_bit_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
c->block_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE; c->block_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
c->block_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE; c->block_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
} }
...@@ -1441,9 +1567,11 @@ static int mb86a20s_get_stats(struct dvb_frontend *fe) ...@@ -1441,9 +1567,11 @@ static int mb86a20s_get_stats(struct dvb_frontend *fe)
int rc = 0, i; int rc = 0, i;
u32 bit_error = 0, bit_count = 0; u32 bit_error = 0, bit_count = 0;
u32 t_pre_bit_error = 0, t_pre_bit_count = 0; u32 t_pre_bit_error = 0, t_pre_bit_count = 0;
u32 t_post_bit_error = 0, t_post_bit_count = 0;
u32 block_error = 0, block_count = 0; u32 block_error = 0, block_count = 0;
u32 t_block_error = 0, t_block_count = 0; u32 t_block_error = 0, t_block_count = 0;
int active_layers = 0, ber_layers = 0, per_layers = 0; int active_layers = 0, pre_ber_layers = 0, post_ber_layers = 0;
int per_layers = 0;
dev_dbg(&state->i2c->dev, "%s called.\n", __func__); dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
...@@ -1457,7 +1585,6 @@ static int mb86a20s_get_stats(struct dvb_frontend *fe) ...@@ -1457,7 +1585,6 @@ static int mb86a20s_get_stats(struct dvb_frontend *fe)
/* Layer is active and has rc segments */ /* Layer is active and has rc segments */
active_layers++; active_layers++;
/* Read per-layer BER */
/* Handle BER before vterbi */ /* Handle BER before vterbi */
rc = mb86a20s_get_pre_ber(fe, i, rc = mb86a20s_get_pre_ber(fe, i,
&bit_error, &bit_count); &bit_error, &bit_count);
...@@ -1479,7 +1606,30 @@ static int mb86a20s_get_stats(struct dvb_frontend *fe) ...@@ -1479,7 +1606,30 @@ static int mb86a20s_get_stats(struct dvb_frontend *fe)
} }
if (c->block_error.stat[1 + i].scale != FE_SCALE_NOT_AVAILABLE) if (c->block_error.stat[1 + i].scale != FE_SCALE_NOT_AVAILABLE)
ber_layers++; pre_ber_layers++;
/* Handle BER post vterbi */
rc = mb86a20s_get_post_ber(fe, i,
&bit_error, &bit_count);
if (rc >= 0) {
c->post_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER;
c->post_bit_error.stat[1 + i].uvalue += bit_error;
c->post_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER;
c->post_bit_count.stat[1 + i].uvalue += bit_count;
} else if (rc != -EBUSY) {
/*
* If an I/O error happened,
* measures are now unavailable
*/
c->post_bit_error.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE;
c->post_bit_count.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE;
dev_err(&state->i2c->dev,
"%s: Can't get BER for layer %c (error %d).\n",
__func__, 'A' + i, rc);
}
if (c->block_error.stat[1 + i].scale != FE_SCALE_NOT_AVAILABLE)
post_ber_layers++;
/* Handle Block errors for PER/UCB reports */ /* Handle Block errors for PER/UCB reports */
rc = mb86a20s_get_blk_error(fe, i, rc = mb86a20s_get_blk_error(fe, i,
...@@ -1506,10 +1656,14 @@ static int mb86a20s_get_stats(struct dvb_frontend *fe) ...@@ -1506,10 +1656,14 @@ static int mb86a20s_get_stats(struct dvb_frontend *fe)
if (c->block_error.stat[1 + i].scale != FE_SCALE_NOT_AVAILABLE) if (c->block_error.stat[1 + i].scale != FE_SCALE_NOT_AVAILABLE)
per_layers++; per_layers++;
/* Update total BER */ /* Update total preBER */
t_pre_bit_error += c->pre_bit_error.stat[1 + i].uvalue; t_pre_bit_error += c->pre_bit_error.stat[1 + i].uvalue;
t_pre_bit_count += c->pre_bit_count.stat[1 + i].uvalue; t_pre_bit_count += c->pre_bit_count.stat[1 + i].uvalue;
/* Update total postBER */
t_post_bit_error += c->post_bit_error.stat[1 + i].uvalue;
t_post_bit_count += c->post_bit_count.stat[1 + i].uvalue;
/* Update total PER */ /* Update total PER */
t_block_error += c->block_error.stat[1 + i].uvalue; t_block_error += c->block_error.stat[1 + i].uvalue;
t_block_count += c->block_count.stat[1 + i].uvalue; t_block_count += c->block_count.stat[1 + i].uvalue;
...@@ -1520,7 +1674,7 @@ static int mb86a20s_get_stats(struct dvb_frontend *fe) ...@@ -1520,7 +1674,7 @@ static int mb86a20s_get_stats(struct dvb_frontend *fe)
* Start showing global count if at least one error count is * Start showing global count if at least one error count is
* available. * available.
*/ */
if (ber_layers) { if (pre_ber_layers) {
/* /*
* At least one per-layer BER measure was read. We can now * At least one per-layer BER measure was read. We can now
* calculate the total BER * calculate the total BER
...@@ -1534,6 +1688,24 @@ static int mb86a20s_get_stats(struct dvb_frontend *fe) ...@@ -1534,6 +1688,24 @@ static int mb86a20s_get_stats(struct dvb_frontend *fe)
c->pre_bit_count.stat[0].uvalue = t_pre_bit_count; c->pre_bit_count.stat[0].uvalue = t_pre_bit_count;
} }
/*
* Start showing global count if at least one error count is
* available.
*/
if (post_ber_layers) {
/*
* At least one per-layer BER measure was read. We can now
* calculate the total BER
*
* Total Bit Error/Count is calculated as the sum of the
* bit errors on all active layers.
*/
c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
c->post_bit_error.stat[0].uvalue = t_post_bit_error;
c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
c->post_bit_count.stat[0].uvalue = t_post_bit_count;
}
if (per_layers) { if (per_layers) {
/* /*
* At least one per-layer UCB measure was read. We can now * At least one per-layer UCB measure was read. We can now
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment