* [PATCH 0/5] Improve DRX-K statistics
@ 2013-03-20 14:02 Mauro Carvalho Chehab
2013-03-20 14:02 ` [PATCH 1/5] [media] drxk: remove dummy BER read code Mauro Carvalho Chehab
` (4 more replies)
0 siblings, 5 replies; 7+ messages in thread
From: Mauro Carvalho Chehab @ 2013-03-20 14:02 UTC (permalink / raw)
Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Jean Delvare
As reported by Jean, the drxk statistics are not ok.
While we don't have enough documentation about this device, it is possible
to do better, by using what's available. In particular, the AZ6007 driver
released a few years ago by Terratec, with served as the basis for the
Kernel's driver has a version of the drxk driver with some statistics code
on it.
Import the needed bits from it, in order to provide a better set of
statistics.
After this change, the stats looks nicer, especially if used with a
dvbv5 stats application:
Lock (0x1f) Quality= Good Signal= 100.00% C/N= 3.55dB UCB= 135 postBER= 22.3x10^-6 PER= 0
Yet:
- Signal is a relative measure. Didn't find a way to convert it to
a real scale, and that would also depend on a proper tuner setting;
- Carrier S/N ratio seems too low for DVB-C. I suspect that it is not
being measured ok.
However, this seems better than before.
Mauro Carvalho Chehab (5):
[media] drxk: remove dummy BER read code
[media] drxk: Add pre/post BER and PER/UCB stats
[media] drxk: use a better calculus for RF strength
[media] drxk: Fix bogus signal strength indicator
[media] dvb-core: don't clear stats at DTV_CLEAR
drivers/media/dvb-core/dvb_frontend.c | 2 +-
drivers/media/dvb-frontends/drxk_hard.c | 302 ++++++++++++++++++++++++++------
drivers/media/dvb-frontends/drxk_hard.h | 2 +
drivers/media/dvb-frontends/drxk_map.h | 3 +
4 files changed, 259 insertions(+), 50 deletions(-)
--
1.8.1.4
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/5] [media] drxk: remove dummy BER read code
2013-03-20 14:02 [PATCH 0/5] Improve DRX-K statistics Mauro Carvalho Chehab
@ 2013-03-20 14:02 ` Mauro Carvalho Chehab
2013-03-20 14:02 ` [PATCH 2/5] [media] drxk: Add pre/post BER and PER/UCB stats Mauro Carvalho Chehab
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Mauro Carvalho Chehab @ 2013-03-20 14:02 UTC (permalink / raw)
Cc: Mauro Carvalho Chehab, Linux Media Mailing List
The BER code does nothing but filling it with zero. Remove it.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
---
drivers/media/dvb-frontends/drxk_hard.c | 16 ----------------
1 file changed, 16 deletions(-)
diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c
index c2fc7da0d..0e40832 100644
--- a/drivers/media/dvb-frontends/drxk_hard.c
+++ b/drivers/media/dvb-frontends/drxk_hard.c
@@ -6408,21 +6408,6 @@ static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status)
return 0;
}
-static int drxk_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
- struct drxk_state *state = fe->demodulator_priv;
-
- dprintk(1, "\n");
-
- if (state->m_DrxkState == DRXK_NO_DEV)
- return -ENODEV;
- if (state->m_DrxkState == DRXK_UNINITIALIZED)
- return -EAGAIN;
-
- *ber = 0;
- return 0;
-}
-
static int drxk_read_signal_strength(struct dvb_frontend *fe,
u16 *strength)
{
@@ -6529,7 +6514,6 @@ static struct dvb_frontend_ops drxk_ops = {
.get_tune_settings = drxk_get_tune_settings,
.read_status = drxk_read_status,
- .read_ber = drxk_read_ber,
.read_signal_strength = drxk_read_signal_strength,
.read_snr = drxk_read_snr,
.read_ucblocks = drxk_read_ucblocks,
--
1.8.1.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/5] [media] drxk: Add pre/post BER and PER/UCB stats
2013-03-20 14:02 [PATCH 0/5] Improve DRX-K statistics Mauro Carvalho Chehab
2013-03-20 14:02 ` [PATCH 1/5] [media] drxk: remove dummy BER read code Mauro Carvalho Chehab
@ 2013-03-20 14:02 ` Mauro Carvalho Chehab
2013-03-20 15:07 ` Mauro Carvalho Chehab
2013-03-20 14:02 ` [PATCH 3/5] [media] drxk: use a better calculus for RF strength Mauro Carvalho Chehab
` (2 subsequent siblings)
4 siblings, 1 reply; 7+ messages in thread
From: Mauro Carvalho Chehab @ 2013-03-20 14:02 UTC (permalink / raw)
Cc: Mauro Carvalho Chehab, Linux Media Mailing List
The original az6007 driver has the code to calculate such
stats. Add it to the driver, reporting them via DVBv5
stats API.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
---
drivers/media/dvb-frontends/drxk_hard.c | 179 +++++++++++++++++++++++++++++---
drivers/media/dvb-frontends/drxk_hard.h | 2 +
drivers/media/dvb-frontends/drxk_map.h | 3 +
3 files changed, 172 insertions(+), 12 deletions(-)
diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c
index 0e40832..cd5084b 100644
--- a/drivers/media/dvb-frontends/drxk_hard.c
+++ b/drivers/media/dvb-frontends/drxk_hard.c
@@ -2655,11 +2655,6 @@ static int GetDVBTSignalToNoise(struct drxk_state *state,
c = Log10Times100(SqrErrIQ);
iMER = a + b;
- /* No negative MER, clip to zero */
- if (iMER > c)
- iMER -= c;
- else
- iMER = 0;
}
*pSignalToNoise = iMER;
@@ -6380,31 +6375,165 @@ static int drxk_set_parameters(struct dvb_frontend *fe)
fe->ops.tuner_ops.get_if_frequency(fe, &IF);
Start(state, 0, IF);
+ /* After set_frontend, stats aren't avaliable */
+ p->strength.stat[0].scale = FE_SCALE_RELATIVE;
+ p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
/* printk(KERN_DEBUG "drxk: %s IF=%d done\n", __func__, IF); */
return 0;
}
-static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status)
+static int drxk_get_stats(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct drxk_state *state = fe->demodulator_priv;
+ int status;
u32 stat;
-
- dprintk(1, "\n");
+ u16 reg16;
+ u32 post_bit_count;
+ u32 post_bit_err_count;
+ u32 post_bit_error_scale;
+ u32 pre_bit_err_count;
+ u32 pre_bit_count;
+ u32 pkt_count;
+ u32 pkt_error_count;
+ s32 cnr, gain;
if (state->m_DrxkState == DRXK_NO_DEV)
return -ENODEV;
if (state->m_DrxkState == DRXK_UNINITIALIZED)
return -EAGAIN;
- *status = 0;
+ /* get status */
+ state->fe_status = 0;
GetLockStatus(state, &stat, 0);
if (stat == MPEG_LOCK)
- *status |= 0x1f;
+ state->fe_status |= 0x1f;
if (stat == FEC_LOCK)
- *status |= 0x0f;
+ state->fe_status |= 0x0f;
if (stat == DEMOD_LOCK)
- *status |= 0x07;
+ state->fe_status |= 0x07;
+
+ if (stat >= DEMOD_LOCK) {
+ GetSignalToNoise(state, &cnr);
+ c->cnr.stat[0].svalue = cnr * 10;
+ c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+ } else {
+ c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ }
+
+ if (stat < FEC_LOCK) {
+ c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->pre_bit_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;
+ return 0;
+ }
+
+ /* Get post BER */
+
+ /* BER measurement is valid if at least FEC lock is achieved */
+
+ /* OFDM_EC_VD_REQ_SMB_CNT__A and/or OFDM_EC_VD_REQ_BIT_CNT can be written
+ to set nr of symbols or bits over which
+ to measure EC_VD_REG_ERR_BIT_CNT__A . See CtrlSetCfg(). */
+
+ /* Read registers for post/preViterbi BER calculation */
+ status = read16(state, OFDM_EC_VD_ERR_BIT_CNT__A, ®16);
+ if (status < 0)
+ goto error;
+ pre_bit_err_count = reg16;
+
+ status = read16(state, OFDM_EC_VD_IN_BIT_CNT__A , ®16);
+ if (status < 0)
+ goto error;
+ pre_bit_count = reg16;
+
+ /* Number of bit-errors */
+ status = read16(state, FEC_RS_NR_BIT_ERRORS__A, ®16);
+ if (status < 0)
+ goto error;
+ post_bit_err_count = reg16;
+
+ status = read16(state, FEC_RS_MEASUREMENT_PRESCALE__A, ®16);
+ if (status < 0)
+ goto error;
+ post_bit_error_scale = reg16;
+
+ status = read16(state, FEC_RS_MEASUREMENT_PERIOD__A, ®16);
+ if (status < 0)
+ goto error;
+ pkt_count = reg16;
+
+ status = read16(state, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A, ®16);
+ if (status < 0)
+ goto error;
+ pkt_error_count = reg16;
+ write16(state, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A, 0);
+
+ post_bit_err_count *= post_bit_error_scale;
+
+ post_bit_count = pkt_count * 204 * 8;
+
+ /* Store the results */
+ c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_error.stat[0].uvalue += pkt_error_count;
+ c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_count.stat[0].uvalue += pkt_count;
+
+ c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->pre_bit_error.stat[0].uvalue += pre_bit_err_count;
+ c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->pre_bit_count.stat[0].uvalue += pre_bit_count;
+
+ c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_error.stat[0].uvalue += post_bit_err_count;
+ c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_count.stat[0].uvalue += post_bit_count;
+
+ /*
+ * Read AGC gain
+ *
+ * IFgain = (IQM_AF_AGC_IF__A * 26.75) (nA)
+ */
+ status = read16(state, IQM_AF_AGC_IF__A, ®16);
+ if (status < 0) {
+ printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ return status;
+ }
+ gain = 2675 * (reg16 - DRXK_AGC_DAC_OFFSET) / 100;
+
+ /* FIXME: it makes sense to fix the scale here to dBm */
+ c->strength.stat[0].scale = FE_SCALE_RELATIVE;
+ c->strength.stat[0].uvalue = gain;
+
+error:
+ return status;
+}
+
+
+static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct drxk_state *state = fe->demodulator_priv;
+ int rc;
+
+ dprintk(1, "\n");
+
+ rc = drxk_get_stats(fe);
+ if (rc < 0)
+ return rc;
+
+ *status = state->fe_status;
+
return 0;
}
@@ -6439,6 +6568,10 @@ static int drxk_read_snr(struct dvb_frontend *fe, u16 *snr)
return -EAGAIN;
GetSignalToNoise(state, &snr2);
+
+ /* No negative SNR, clip to zero */
+ if (snr2 < 0)
+ snr2 = 0;
*snr = snr2 & 0xffff;
return 0;
}
@@ -6522,6 +6655,7 @@ static struct dvb_frontend_ops drxk_ops = {
struct dvb_frontend *drxk_attach(const struct drxk_config *config,
struct i2c_adapter *i2c)
{
+ struct dtv_frontend_properties *p;
struct drxk_state *state = NULL;
u8 adr = config->adr;
int status;
@@ -6602,6 +6736,27 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config,
} else if (init_drxk(state) < 0)
goto error;
+
+ /* Initialize stats */
+ p = &state->frontend.dtv_property_cache;
+ p->strength.len = 1;
+ p->cnr.len = 1;
+ p->block_error.len = 1;
+ p->block_count.len = 1;
+ p->pre_bit_error.len = 1;
+ p->pre_bit_count.len = 1;
+ p->post_bit_error.len = 1;
+ p->post_bit_count.len = 1;
+
+ p->strength.stat[0].scale = FE_SCALE_RELATIVE;
+ p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
printk(KERN_INFO "drxk: frontend initialized.\n");
return &state->frontend;
diff --git a/drivers/media/dvb-frontends/drxk_hard.h b/drivers/media/dvb-frontends/drxk_hard.h
index d18a896..b8424f1 100644
--- a/drivers/media/dvb-frontends/drxk_hard.h
+++ b/drivers/media/dvb-frontends/drxk_hard.h
@@ -345,6 +345,8 @@ struct drxk_state {
bool antenna_dvbt;
u16 antenna_gpio;
+ fe_status_t fe_status;
+
/* Firmware */
const char *microcode_name;
struct completion fw_wait_load;
diff --git a/drivers/media/dvb-frontends/drxk_map.h b/drivers/media/dvb-frontends/drxk_map.h
index 23e16c1..761613f 100644
--- a/drivers/media/dvb-frontends/drxk_map.h
+++ b/drivers/media/dvb-frontends/drxk_map.h
@@ -10,6 +10,7 @@
#define FEC_RS_COMM_EXEC_STOP 0x0
#define FEC_RS_MEASUREMENT_PERIOD__A 0x1C30012
#define FEC_RS_MEASUREMENT_PRESCALE__A 0x1C30013
+#define FEC_RS_NR_BIT_ERRORS__A 0x1C30014
#define FEC_OC_MODE__A 0x1C40011
#define FEC_OC_MODE_PARITY__M 0x1
#define FEC_OC_DTO_MODE__A 0x1C40014
@@ -129,6 +130,8 @@
#define OFDM_EC_SB_PRIOR__A 0x3410013
#define OFDM_EC_SB_PRIOR_HI 0x0
#define OFDM_EC_SB_PRIOR_LO 0x1
+#define OFDM_EC_VD_ERR_BIT_CNT__A 0x3420017
+#define OFDM_EC_VD_IN_BIT_CNT__A 0x3420018
#define OFDM_EQ_TOP_TD_TPS_CONST__A 0x3010054
#define OFDM_EQ_TOP_TD_TPS_CONST__M 0x3
#define OFDM_EQ_TOP_TD_TPS_CONST_64QAM 0x2
--
1.8.1.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 3/5] [media] drxk: use a better calculus for RF strength
2013-03-20 14:02 [PATCH 0/5] Improve DRX-K statistics Mauro Carvalho Chehab
2013-03-20 14:02 ` [PATCH 1/5] [media] drxk: remove dummy BER read code Mauro Carvalho Chehab
2013-03-20 14:02 ` [PATCH 2/5] [media] drxk: Add pre/post BER and PER/UCB stats Mauro Carvalho Chehab
@ 2013-03-20 14:02 ` Mauro Carvalho Chehab
2013-03-20 14:02 ` [PATCH 4/5] [media] drxk: Fix bogus signal strength indicator Mauro Carvalho Chehab
2013-03-20 14:02 ` [PATCH 5/5] [media] dvb-core: don't clear stats at DTV_CLEAR Mauro Carvalho Chehab
4 siblings, 0 replies; 7+ messages in thread
From: Mauro Carvalho Chehab @ 2013-03-20 14:02 UTC (permalink / raw)
Cc: Mauro Carvalho Chehab, Linux Media Mailing List
The AZ6007 driver released by Terratec has a better way to
estimate the signal strength, at CtrlSigStrength(). Port it
to the driver.
It should be noticed that there are two parameters there that
are tuner-specific.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
---
drivers/media/dvb-frontends/drxk_hard.c | 126 +++++++++++++++++++++++++++-----
1 file changed, 109 insertions(+), 17 deletions(-)
diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c
index cd5084b..8a5b2cc 100644
--- a/drivers/media/dvb-frontends/drxk_hard.c
+++ b/drivers/media/dvb-frontends/drxk_hard.c
@@ -6390,6 +6390,107 @@ static int drxk_set_parameters(struct dvb_frontend *fe)
return 0;
}
+static int get_strength(struct drxk_state *state, u64 *strength)
+{
+ int status;
+ struct SCfgAgc rfAgc, ifAgc;
+ u32 totalGain = 0;
+ u32 atten = 0;
+ u32 agcRange = 0;
+ u16 scu_lvl = 0;
+ u16 scu_coc = 0;
+ /* FIXME: those are part of the tuner presets */
+ u16 tunerRfGain = 50; /* Default value on az6007 driver */
+ u16 tunerIfGain = 40; /* Default value on az6007 driver */
+
+ *strength = 0;
+
+ if (IsDVBT(state)) {
+ rfAgc = state->m_dvbtRfAgcCfg;
+ ifAgc = state->m_dvbtIfAgcCfg;
+ } else if (IsQAM(state)) {
+ rfAgc = state->m_qamRfAgcCfg;
+ ifAgc = state->m_qamIfAgcCfg;
+ } else {
+ rfAgc = state->m_atvRfAgcCfg;
+ ifAgc = state->m_atvIfAgcCfg;
+ }
+
+ if (rfAgc.ctrlMode == DRXK_AGC_CTRL_AUTO) {
+ /* SCU outputLevel */
+ status = read16(state, SCU_RAM_AGC_RF_IACCU_HI__A, &scu_lvl);
+ if (status < 0)
+ return status;
+
+ /* SCU c.o.c. */
+ read16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A, &scu_coc);
+ if (status < 0)
+ return status;
+
+ if (((u32) scu_lvl + (u32) scu_coc) < 0xffff)
+ rfAgc.outputLevel = scu_lvl + scu_coc;
+ else
+ rfAgc.outputLevel = 0xffff;
+
+ /* Take RF gain into account */
+ totalGain += tunerRfGain;
+
+ /* clip output value */
+ if (rfAgc.outputLevel < rfAgc.minOutputLevel)
+ rfAgc.outputLevel = rfAgc.minOutputLevel;
+ if (rfAgc.outputLevel > rfAgc.maxOutputLevel)
+ rfAgc.outputLevel = rfAgc.maxOutputLevel;
+
+ agcRange = (u32) (rfAgc.maxOutputLevel - rfAgc.minOutputLevel);
+ if (agcRange > 0) {
+ atten += 100UL *
+ ((u32)(tunerRfGain)) *
+ ((u32)(rfAgc.outputLevel - rfAgc.minOutputLevel))
+ / agcRange;
+ }
+ }
+
+ if (ifAgc.ctrlMode == DRXK_AGC_CTRL_AUTO) {
+ status = read16(state, SCU_RAM_AGC_IF_IACCU_HI__A,
+ &ifAgc.outputLevel);
+ if (status < 0)
+ return status;
+
+ status = read16(state, SCU_RAM_AGC_INGAIN_TGT_MIN__A,
+ &ifAgc.top);
+ if (status < 0)
+ return status;
+
+ /* Take IF gain into account */
+ totalGain += (u32) tunerIfGain;
+
+ /* clip output value */
+ if (ifAgc.outputLevel < ifAgc.minOutputLevel)
+ ifAgc.outputLevel = ifAgc.minOutputLevel;
+ if (ifAgc.outputLevel > ifAgc.maxOutputLevel)
+ ifAgc.outputLevel = ifAgc.maxOutputLevel;
+
+ agcRange = (u32) (ifAgc.maxOutputLevel - ifAgc.minOutputLevel);
+ if (agcRange > 0) {
+ atten += 100UL *
+ ((u32)(tunerIfGain)) *
+ ((u32)(ifAgc.outputLevel - ifAgc.minOutputLevel))
+ / agcRange;
+ }
+ }
+
+ /*
+ * Convert to 0..65535 scale.
+ * If it can't be measured (AGC is disabled), just show 100%.
+ */
+ if (totalGain > 0)
+ *strength = (65535UL * atten / totalGain);
+ else
+ *strength = 65535;
+
+ return 0;
+}
+
static int drxk_get_stats(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
@@ -6404,7 +6505,7 @@ static int drxk_get_stats(struct dvb_frontend *fe)
u32 pre_bit_count;
u32 pkt_count;
u32 pkt_error_count;
- s32 cnr, gain;
+ s32 cnr;
if (state->m_DrxkState == DRXK_NO_DEV)
return -ENODEV;
@@ -6421,6 +6522,13 @@ static int drxk_get_stats(struct dvb_frontend *fe)
if (stat == DEMOD_LOCK)
state->fe_status |= 0x07;
+ /*
+ * Estimate signal strength from AGC
+ */
+ get_strength(state, &c->strength.stat[0].uvalue);
+ c->strength.stat[0].scale = FE_SCALE_RELATIVE;
+
+
if (stat >= DEMOD_LOCK) {
GetSignalToNoise(state, &cnr);
c->cnr.stat[0].svalue = cnr * 10;
@@ -6500,22 +6608,6 @@ static int drxk_get_stats(struct dvb_frontend *fe)
c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
c->post_bit_count.stat[0].uvalue += post_bit_count;
- /*
- * Read AGC gain
- *
- * IFgain = (IQM_AF_AGC_IF__A * 26.75) (nA)
- */
- status = read16(state, IQM_AF_AGC_IF__A, ®16);
- if (status < 0) {
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
- return status;
- }
- gain = 2675 * (reg16 - DRXK_AGC_DAC_OFFSET) / 100;
-
- /* FIXME: it makes sense to fix the scale here to dBm */
- c->strength.stat[0].scale = FE_SCALE_RELATIVE;
- c->strength.stat[0].uvalue = gain;
-
error:
return status;
}
--
1.8.1.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 4/5] [media] drxk: Fix bogus signal strength indicator
2013-03-20 14:02 [PATCH 0/5] Improve DRX-K statistics Mauro Carvalho Chehab
` (2 preceding siblings ...)
2013-03-20 14:02 ` [PATCH 3/5] [media] drxk: use a better calculus for RF strength Mauro Carvalho Chehab
@ 2013-03-20 14:02 ` Mauro Carvalho Chehab
2013-03-20 14:02 ` [PATCH 5/5] [media] dvb-core: don't clear stats at DTV_CLEAR Mauro Carvalho Chehab
4 siblings, 0 replies; 7+ messages in thread
From: Mauro Carvalho Chehab @ 2013-03-20 14:02 UTC (permalink / raw)
Cc: Mauro Carvalho Chehab, Linux Media Mailing List
The DVBv3 signal strength indicator is bogus: it doesn't range
from 0 to 65535 as it would be expected. Also, 0 means the max
signal strength.
Now that a better way to estimate it was added, use the new
way.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
---
drivers/media/dvb-frontends/drxk_hard.c | 33 +++------------------------------
1 file changed, 3 insertions(+), 30 deletions(-)
diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c
index 8a5b2cc..fbd11e4 100644
--- a/drivers/media/dvb-frontends/drxk_hard.c
+++ b/drivers/media/dvb-frontends/drxk_hard.c
@@ -2490,32 +2490,6 @@ error:
return status;
}
-static int ReadIFAgc(struct drxk_state *state, u32 *pValue)
-{
- u16 agcDacLvl;
- int status;
- u16 Level = 0;
-
- dprintk(1, "\n");
-
- status = read16(state, IQM_AF_AGC_IF__A, &agcDacLvl);
- if (status < 0) {
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
- return status;
- }
-
- *pValue = 0;
-
- if (agcDacLvl > DRXK_AGC_DAC_OFFSET)
- Level = agcDacLvl - DRXK_AGC_DAC_OFFSET;
- if (Level < 14000)
- *pValue = (14000 - Level) / 4;
- else
- *pValue = 0;
-
- return status;
-}
-
static int GetQAMSignalToNoise(struct drxk_state *state,
s32 *pSignalToNoise)
{
@@ -6484,7 +6458,7 @@ static int get_strength(struct drxk_state *state, u64 *strength)
* If it can't be measured (AGC is disabled), just show 100%.
*/
if (totalGain > 0)
- *strength = (65535UL * atten / totalGain);
+ *strength = (65535UL * atten / totalGain / 100);
else
*strength = 65535;
@@ -6633,7 +6607,7 @@ static int drxk_read_signal_strength(struct dvb_frontend *fe,
u16 *strength)
{
struct drxk_state *state = fe->demodulator_priv;
- u32 val = 0;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
dprintk(1, "\n");
@@ -6642,8 +6616,7 @@ static int drxk_read_signal_strength(struct dvb_frontend *fe,
if (state->m_DrxkState == DRXK_UNINITIALIZED)
return -EAGAIN;
- ReadIFAgc(state, &val);
- *strength = val & 0xffff;
+ *strength = c->strength.stat[0].uvalue;
return 0;
}
--
1.8.1.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 5/5] [media] dvb-core: don't clear stats at DTV_CLEAR
2013-03-20 14:02 [PATCH 0/5] Improve DRX-K statistics Mauro Carvalho Chehab
` (3 preceding siblings ...)
2013-03-20 14:02 ` [PATCH 4/5] [media] drxk: Fix bogus signal strength indicator Mauro Carvalho Chehab
@ 2013-03-20 14:02 ` Mauro Carvalho Chehab
4 siblings, 0 replies; 7+ messages in thread
From: Mauro Carvalho Chehab @ 2013-03-20 14:02 UTC (permalink / raw)
Cc: Mauro Carvalho Chehab, Linux Media Mailing List
The stats are cleared by the frontend. Don't do it at DTV_CLEAR.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
---
drivers/media/dvb-core/dvb_frontend.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index a7317ae..b009b10 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -920,7 +920,7 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
u32 delsys;
delsys = c->delivery_system;
- memset(c, 0, sizeof(struct dtv_frontend_properties));
+ memset(c, 0, offsetof(struct dtv_frontend_properties, strength));
c->delivery_system = delsys;
c->state = DTV_CLEAR;
--
1.8.1.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 2/5] [media] drxk: Add pre/post BER and PER/UCB stats
2013-03-20 14:02 ` [PATCH 2/5] [media] drxk: Add pre/post BER and PER/UCB stats Mauro Carvalho Chehab
@ 2013-03-20 15:07 ` Mauro Carvalho Chehab
0 siblings, 0 replies; 7+ messages in thread
From: Mauro Carvalho Chehab @ 2013-03-20 15:07 UTC (permalink / raw)
To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List
Em Wed, 20 Mar 2013 11:02:13 -0300
Mauro Carvalho Chehab <mchehab@redhat.com> escreveu:
> The original az6007 driver has the code to calculate such
> stats. Add it to the driver, reporting them via DVBv5
> stats API.
There's an scale problem with this patch for S/N ratio at carrier.
Fix patch enclosed.
Regards,
Mauro
-
From: Mauro Carvalho Chehab <mchehab@redhat.com>
Date: Wed, 20 Mar 2013 06:15:45 -0300
[PATCHv2] [media] drxk: Add pre/post BER and PER/UCB stats
The original az6007 driver has the code to calculate such
stats. Add it to the driver, reporting them via DVBv5
stats API.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c
index 0e40832..8c4de7c 100644
--- a/drivers/media/dvb-frontends/drxk_hard.c
+++ b/drivers/media/dvb-frontends/drxk_hard.c
@@ -2655,11 +2655,6 @@ static int GetDVBTSignalToNoise(struct drxk_state *state,
c = Log10Times100(SqrErrIQ);
iMER = a + b;
- /* No negative MER, clip to zero */
- if (iMER > c)
- iMER -= c;
- else
- iMER = 0;
}
*pSignalToNoise = iMER;
@@ -6380,31 +6375,165 @@ static int drxk_set_parameters(struct dvb_frontend *fe)
fe->ops.tuner_ops.get_if_frequency(fe, &IF);
Start(state, 0, IF);
+ /* After set_frontend, stats aren't avaliable */
+ p->strength.stat[0].scale = FE_SCALE_RELATIVE;
+ p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
/* printk(KERN_DEBUG "drxk: %s IF=%d done\n", __func__, IF); */
return 0;
}
-static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status)
+static int drxk_get_stats(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct drxk_state *state = fe->demodulator_priv;
+ int status;
u32 stat;
-
- dprintk(1, "\n");
+ u16 reg16;
+ u32 post_bit_count;
+ u32 post_bit_err_count;
+ u32 post_bit_error_scale;
+ u32 pre_bit_err_count;
+ u32 pre_bit_count;
+ u32 pkt_count;
+ u32 pkt_error_count;
+ s32 cnr, gain;
if (state->m_DrxkState == DRXK_NO_DEV)
return -ENODEV;
if (state->m_DrxkState == DRXK_UNINITIALIZED)
return -EAGAIN;
- *status = 0;
+ /* get status */
+ state->fe_status = 0;
GetLockStatus(state, &stat, 0);
if (stat == MPEG_LOCK)
- *status |= 0x1f;
+ state->fe_status |= 0x1f;
if (stat == FEC_LOCK)
- *status |= 0x0f;
+ state->fe_status |= 0x0f;
if (stat == DEMOD_LOCK)
- *status |= 0x07;
+ state->fe_status |= 0x07;
+
+ if (stat >= DEMOD_LOCK) {
+ GetSignalToNoise(state, &cnr);
+ c->cnr.stat[0].svalue = cnr * 100;
+ c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+ } else {
+ c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ }
+
+ if (stat < FEC_LOCK) {
+ c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->pre_bit_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;
+ return 0;
+ }
+
+ /* Get post BER */
+
+ /* BER measurement is valid if at least FEC lock is achieved */
+
+ /* OFDM_EC_VD_REQ_SMB_CNT__A and/or OFDM_EC_VD_REQ_BIT_CNT can be written
+ to set nr of symbols or bits over which
+ to measure EC_VD_REG_ERR_BIT_CNT__A . See CtrlSetCfg(). */
+
+ /* Read registers for post/preViterbi BER calculation */
+ status = read16(state, OFDM_EC_VD_ERR_BIT_CNT__A, ®16);
+ if (status < 0)
+ goto error;
+ pre_bit_err_count = reg16;
+
+ status = read16(state, OFDM_EC_VD_IN_BIT_CNT__A , ®16);
+ if (status < 0)
+ goto error;
+ pre_bit_count = reg16;
+
+ /* Number of bit-errors */
+ status = read16(state, FEC_RS_NR_BIT_ERRORS__A, ®16);
+ if (status < 0)
+ goto error;
+ post_bit_err_count = reg16;
+
+ status = read16(state, FEC_RS_MEASUREMENT_PRESCALE__A, ®16);
+ if (status < 0)
+ goto error;
+ post_bit_error_scale = reg16;
+
+ status = read16(state, FEC_RS_MEASUREMENT_PERIOD__A, ®16);
+ if (status < 0)
+ goto error;
+ pkt_count = reg16;
+
+ status = read16(state, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A, ®16);
+ if (status < 0)
+ goto error;
+ pkt_error_count = reg16;
+ write16(state, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A, 0);
+
+ post_bit_err_count *= post_bit_error_scale;
+
+ post_bit_count = pkt_count * 204 * 8;
+
+ /* Store the results */
+ c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_error.stat[0].uvalue += pkt_error_count;
+ c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_count.stat[0].uvalue += pkt_count;
+
+ c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->pre_bit_error.stat[0].uvalue += pre_bit_err_count;
+ c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->pre_bit_count.stat[0].uvalue += pre_bit_count;
+
+ c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_error.stat[0].uvalue += post_bit_err_count;
+ c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_count.stat[0].uvalue += post_bit_count;
+
+ /*
+ * Read AGC gain
+ *
+ * IFgain = (IQM_AF_AGC_IF__A * 26.75) (nA)
+ */
+ status = read16(state, IQM_AF_AGC_IF__A, ®16);
+ if (status < 0) {
+ printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+ return status;
+ }
+ gain = 2675 * (reg16 - DRXK_AGC_DAC_OFFSET) / 100;
+
+ /* FIXME: it makes sense to fix the scale here to dBm */
+ c->strength.stat[0].scale = FE_SCALE_RELATIVE;
+ c->strength.stat[0].uvalue = gain;
+
+error:
+ return status;
+}
+
+
+static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct drxk_state *state = fe->demodulator_priv;
+ int rc;
+
+ dprintk(1, "\n");
+
+ rc = drxk_get_stats(fe);
+ if (rc < 0)
+ return rc;
+
+ *status = state->fe_status;
+
return 0;
}
@@ -6439,6 +6568,10 @@ static int drxk_read_snr(struct dvb_frontend *fe, u16 *snr)
return -EAGAIN;
GetSignalToNoise(state, &snr2);
+
+ /* No negative SNR, clip to zero */
+ if (snr2 < 0)
+ snr2 = 0;
*snr = snr2 & 0xffff;
return 0;
}
@@ -6522,6 +6655,7 @@ static struct dvb_frontend_ops drxk_ops = {
struct dvb_frontend *drxk_attach(const struct drxk_config *config,
struct i2c_adapter *i2c)
{
+ struct dtv_frontend_properties *p;
struct drxk_state *state = NULL;
u8 adr = config->adr;
int status;
@@ -6602,6 +6736,27 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config,
} else if (init_drxk(state) < 0)
goto error;
+
+ /* Initialize stats */
+ p = &state->frontend.dtv_property_cache;
+ p->strength.len = 1;
+ p->cnr.len = 1;
+ p->block_error.len = 1;
+ p->block_count.len = 1;
+ p->pre_bit_error.len = 1;
+ p->pre_bit_count.len = 1;
+ p->post_bit_error.len = 1;
+ p->post_bit_count.len = 1;
+
+ p->strength.stat[0].scale = FE_SCALE_RELATIVE;
+ p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
printk(KERN_INFO "drxk: frontend initialized.\n");
return &state->frontend;
diff --git a/drivers/media/dvb-frontends/drxk_hard.h b/drivers/media/dvb-frontends/drxk_hard.h
index d18a896..b8424f1 100644
--- a/drivers/media/dvb-frontends/drxk_hard.h
+++ b/drivers/media/dvb-frontends/drxk_hard.h
@@ -345,6 +345,8 @@ struct drxk_state {
bool antenna_dvbt;
u16 antenna_gpio;
+ fe_status_t fe_status;
+
/* Firmware */
const char *microcode_name;
struct completion fw_wait_load;
diff --git a/drivers/media/dvb-frontends/drxk_map.h b/drivers/media/dvb-frontends/drxk_map.h
index 23e16c1..761613f 100644
--- a/drivers/media/dvb-frontends/drxk_map.h
+++ b/drivers/media/dvb-frontends/drxk_map.h
@@ -10,6 +10,7 @@
#define FEC_RS_COMM_EXEC_STOP 0x0
#define FEC_RS_MEASUREMENT_PERIOD__A 0x1C30012
#define FEC_RS_MEASUREMENT_PRESCALE__A 0x1C30013
+#define FEC_RS_NR_BIT_ERRORS__A 0x1C30014
#define FEC_OC_MODE__A 0x1C40011
#define FEC_OC_MODE_PARITY__M 0x1
#define FEC_OC_DTO_MODE__A 0x1C40014
@@ -129,6 +130,8 @@
#define OFDM_EC_SB_PRIOR__A 0x3410013
#define OFDM_EC_SB_PRIOR_HI 0x0
#define OFDM_EC_SB_PRIOR_LO 0x1
+#define OFDM_EC_VD_ERR_BIT_CNT__A 0x3420017
+#define OFDM_EC_VD_IN_BIT_CNT__A 0x3420018
#define OFDM_EQ_TOP_TD_TPS_CONST__A 0x3010054
#define OFDM_EQ_TOP_TD_TPS_CONST__M 0x3
#define OFDM_EQ_TOP_TD_TPS_CONST_64QAM 0x2
^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2013-03-20 15:07 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-03-20 14:02 [PATCH 0/5] Improve DRX-K statistics Mauro Carvalho Chehab
2013-03-20 14:02 ` [PATCH 1/5] [media] drxk: remove dummy BER read code Mauro Carvalho Chehab
2013-03-20 14:02 ` [PATCH 2/5] [media] drxk: Add pre/post BER and PER/UCB stats Mauro Carvalho Chehab
2013-03-20 15:07 ` Mauro Carvalho Chehab
2013-03-20 14:02 ` [PATCH 3/5] [media] drxk: use a better calculus for RF strength Mauro Carvalho Chehab
2013-03-20 14:02 ` [PATCH 4/5] [media] drxk: Fix bogus signal strength indicator Mauro Carvalho Chehab
2013-03-20 14:02 ` [PATCH 5/5] [media] dvb-core: don't clear stats at DTV_CLEAR Mauro Carvalho Chehab
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).