forked from mirrors/linux
		
	[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>
This commit is contained in:
		
							parent
							
								
									2b0e1f3afd
								
							
						
					
					
						commit
						8f3741e028
					
				
					 3 changed files with 172 additions and 12 deletions
				
			
		| 
						 | 
					@ -2655,11 +2655,6 @@ static int GetDVBTSignalToNoise(struct drxk_state *state,
 | 
				
			||||||
		c = Log10Times100(SqrErrIQ);
 | 
							c = Log10Times100(SqrErrIQ);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		iMER = a + b;
 | 
							iMER = a + b;
 | 
				
			||||||
		/* No negative MER, clip to zero */
 | 
					 | 
				
			||||||
		if (iMER > c)
 | 
					 | 
				
			||||||
			iMER -= c;
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			iMER = 0;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	*pSignalToNoise = iMER;
 | 
						*pSignalToNoise = iMER;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6380,31 +6375,165 @@ static int drxk_set_parameters(struct dvb_frontend *fe)
 | 
				
			||||||
	fe->ops.tuner_ops.get_if_frequency(fe, &IF);
 | 
						fe->ops.tuner_ops.get_if_frequency(fe, &IF);
 | 
				
			||||||
	Start(state, 0, 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); */
 | 
						/* printk(KERN_DEBUG "drxk: %s IF=%d done\n", __func__, IF); */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						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;
 | 
						struct drxk_state *state = fe->demodulator_priv;
 | 
				
			||||||
 | 
						int status;
 | 
				
			||||||
	u32 stat;
 | 
						u32 stat;
 | 
				
			||||||
 | 
						u16 reg16;
 | 
				
			||||||
	dprintk(1, "\n");
 | 
						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)
 | 
						if (state->m_DrxkState == DRXK_NO_DEV)
 | 
				
			||||||
		return -ENODEV;
 | 
							return -ENODEV;
 | 
				
			||||||
	if (state->m_DrxkState == DRXK_UNINITIALIZED)
 | 
						if (state->m_DrxkState == DRXK_UNINITIALIZED)
 | 
				
			||||||
		return -EAGAIN;
 | 
							return -EAGAIN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*status = 0;
 | 
						/* get status */
 | 
				
			||||||
 | 
						state->fe_status = 0;
 | 
				
			||||||
	GetLockStatus(state, &stat, 0);
 | 
						GetLockStatus(state, &stat, 0);
 | 
				
			||||||
	if (stat == MPEG_LOCK)
 | 
						if (stat == MPEG_LOCK)
 | 
				
			||||||
		*status |= 0x1f;
 | 
							state->fe_status |= 0x1f;
 | 
				
			||||||
	if (stat == FEC_LOCK)
 | 
						if (stat == FEC_LOCK)
 | 
				
			||||||
		*status |= 0x0f;
 | 
							state->fe_status |= 0x0f;
 | 
				
			||||||
	if (stat == DEMOD_LOCK)
 | 
						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;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6439,6 +6568,10 @@ static int drxk_read_snr(struct dvb_frontend *fe, u16 *snr)
 | 
				
			||||||
		return -EAGAIN;
 | 
							return -EAGAIN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	GetSignalToNoise(state, &snr2);
 | 
						GetSignalToNoise(state, &snr2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* No negative SNR, clip to zero */
 | 
				
			||||||
 | 
						if (snr2 < 0)
 | 
				
			||||||
 | 
							snr2 = 0;
 | 
				
			||||||
	*snr = snr2 & 0xffff;
 | 
						*snr = snr2 & 0xffff;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -6522,6 +6655,7 @@ static struct dvb_frontend_ops drxk_ops = {
 | 
				
			||||||
struct dvb_frontend *drxk_attach(const struct drxk_config *config,
 | 
					struct dvb_frontend *drxk_attach(const struct drxk_config *config,
 | 
				
			||||||
				 struct i2c_adapter *i2c)
 | 
									 struct i2c_adapter *i2c)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct dtv_frontend_properties *p;
 | 
				
			||||||
	struct drxk_state *state = NULL;
 | 
						struct drxk_state *state = NULL;
 | 
				
			||||||
	u8 adr = config->adr;
 | 
						u8 adr = config->adr;
 | 
				
			||||||
	int status;
 | 
						int status;
 | 
				
			||||||
| 
						 | 
					@ -6602,6 +6736,27 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config,
 | 
				
			||||||
	} else if (init_drxk(state) < 0)
 | 
						} else if (init_drxk(state) < 0)
 | 
				
			||||||
		goto error;
 | 
							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");
 | 
						printk(KERN_INFO "drxk: frontend initialized.\n");
 | 
				
			||||||
	return &state->frontend;
 | 
						return &state->frontend;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -345,6 +345,8 @@ struct drxk_state {
 | 
				
			||||||
	bool	antenna_dvbt;
 | 
						bool	antenna_dvbt;
 | 
				
			||||||
	u16	antenna_gpio;
 | 
						u16	antenna_gpio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fe_status_t fe_status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Firmware */
 | 
						/* Firmware */
 | 
				
			||||||
	const char *microcode_name;
 | 
						const char *microcode_name;
 | 
				
			||||||
	struct completion fw_wait_load;
 | 
						struct completion fw_wait_load;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,6 +10,7 @@
 | 
				
			||||||
#define    FEC_RS_COMM_EXEC_STOP                                           0x0
 | 
					#define    FEC_RS_COMM_EXEC_STOP                                           0x0
 | 
				
			||||||
#define  FEC_RS_MEASUREMENT_PERIOD__A                                      0x1C30012
 | 
					#define  FEC_RS_MEASUREMENT_PERIOD__A                                      0x1C30012
 | 
				
			||||||
#define  FEC_RS_MEASUREMENT_PRESCALE__A                                    0x1C30013
 | 
					#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__A                                                    0x1C40011
 | 
				
			||||||
#define    FEC_OC_MODE_PARITY__M                                           0x1
 | 
					#define    FEC_OC_MODE_PARITY__M                                           0x1
 | 
				
			||||||
#define  FEC_OC_DTO_MODE__A                                                0x1C40014
 | 
					#define  FEC_OC_DTO_MODE__A                                                0x1C40014
 | 
				
			||||||
| 
						 | 
					@ -129,6 +130,8 @@
 | 
				
			||||||
#define  OFDM_EC_SB_PRIOR__A                                               0x3410013
 | 
					#define  OFDM_EC_SB_PRIOR__A                                               0x3410013
 | 
				
			||||||
#define    OFDM_EC_SB_PRIOR_HI                                             0x0
 | 
					#define    OFDM_EC_SB_PRIOR_HI                                             0x0
 | 
				
			||||||
#define    OFDM_EC_SB_PRIOR_LO                                             0x1
 | 
					#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__A                                       0x3010054
 | 
				
			||||||
#define  OFDM_EQ_TOP_TD_TPS_CONST__M                                       0x3
 | 
					#define  OFDM_EQ_TOP_TD_TPS_CONST__M                                       0x3
 | 
				
			||||||
#define    OFDM_EQ_TOP_TD_TPS_CONST_64QAM                                  0x2
 | 
					#define    OFDM_EQ_TOP_TD_TPS_CONST_64QAM                                  0x2
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue