Correct BER calculation.
The current BER only displays the number of error bits, rather it should
be a ratio. In DVB-S, it should be error_bits/total_bits; in DVB-S2, it
should be error_frames/total/frames.
In linux DVB standard, there is no specification about the unit. Based
on the convention, 10^-9 is used as the unit since BER can only be set
as an 32 bit unsigned integer in DVB API.
Google-Bug-Id: 19734248
Change-Id: I7189535c3d8ac299d829baaf1ca0219810b4d2de
diff --git a/drivers/media/dvb/frontends/dvbsky_m88rs6000.c b/drivers/media/dvb/frontends/dvbsky_m88rs6000.c
index b23bca9..377d53e 100644
--- a/drivers/media/dvb/frontends/dvbsky_m88rs6000.c
+++ b/drivers/media/dvb/frontends/dvbsky_m88rs6000.c
@@ -11,6 +11,7 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/firmware.h>
+#include <asm/div64.h>
#include "dvb_frontend.h"
#include "dvbsky_m88rs6000.h"
@@ -292,11 +293,66 @@
return 0;
}
+static int m88rs6000_get_fec(struct dvb_frontend *fe)
+{
+ struct m88rs6000_state *state = fe->demodulator_priv;
+ u8 fec;
+ switch (state->delivery_system){
+ case SYS_DVBS:
+ fec = m88rs6000_readreg(state, 0xe6) >> 5;
+ switch(fec){
+ case 0:
+ return FEC_7_8;
+ case 1:
+ return FEC_5_6;
+ case 2:
+ return FEC_3_4;
+ case 3:
+ return FEC_2_3;
+ case 4:
+ return FEC_1_2;
+ default:
+ return FEC_NONE;
+ }
+ break;
+ case SYS_DVBS2:
+ fec = m88rs6000_readreg(state, 0x7e) & 0x0f;
+ switch(fec){
+ case 3:
+ return FEC_1_2;
+ case 4:
+ return FEC_3_5;
+ case 5:
+ return FEC_2_3;
+ case 6:
+ return FEC_3_4;
+ case 7:
+ return FEC_4_5;
+ case 8:
+ return FEC_5_6;
+ case 9:
+ return FEC_8_9;
+ case 10:
+ return FEC_9_10;
+ case 0: /* FEC_1_4 is not supported in this kernel */
+ case 1: /* FEC_1_3 is not supported in this kernel */
+ case 2: /* FEC_2_5 is not supported in this kernel */
+ default:
+ return FEC_NONE;
+ }
+ break;
+ default:
+ break;
+ }
+ return FEC_NONE;
+}
+
static int m88rs6000_read_ber(struct dvb_frontend *fe, u32* ber)
{
struct m88rs6000_state *state = fe->demodulator_priv;
u8 tmp1, tmp2, tmp3;
- u32 ldpc_frame_cnt, pre_err_packags;
+ u32 bch_payload = 0, ldpc_frame_cnt, pre_err_packages, pre_total_packages;
+ u64 tmp4;
dprintk("%s()\n", __func__);
@@ -304,30 +360,75 @@
case SYS_DVBS:
m88rs6000_writereg(state, 0xf9, 0x04);
tmp3 = m88rs6000_readreg(state, 0xf8);
+ if((tmp3&0x08) == 0) {
+ pre_total_packages = 0x800000;
+ } else {
+ pre_total_packages = 0x100000;
+ }
if ((tmp3&0x10) == 0){
tmp1 = m88rs6000_readreg(state, 0xf7);
tmp2 = m88rs6000_readreg(state, 0xf6);
tmp3 |= 0x10;
m88rs6000_writereg(state, 0xf8, tmp3);
- state->preBer = (tmp1<<8) | tmp2;
+ pre_err_packages = (tmp1<<8) | tmp2;
+ tmp4 = 1000000000ULL * pre_err_packages;
+ do_div(tmp4, pre_total_packages);
+ state->preBer = (u32)tmp4;
}
break;
case SYS_DVBS2:
+ switch (m88rs6000_get_fec(fe))
+ {
+ /* THe FEC coding equation:
+ * FEC length (64800b) * (LDPC ratio)
+ * = K(LDPC)
+ * = K(BCH) + T(BCH) * 16
+ * = BB Header (80b) + data + padding + T(BCH) * 16
+ * FEC Frame - LDPC - K(BCH) - K(LDPC) - T(BCH)
+ * 64800 - 1/4 - 16008 - 16200 - 12
+ * 64800 - 1/3 - 21408 - 21600 - 12
+ * 64800 - 2/5 - 25728 - 25920 - 12
+ * 64800 - 1/2 - 32208 - 32400 - 12
+ * 64800 - 3/5 - 38688 - 38880 - 12
+ * 64800 - 2/3 - 43040 - 43200 - 10
+ * 64800 - 3/4 - 48408 - 48600 - 12
+ * 64800 - 4/5 - 51648 - 51840 - 12
+ * 64800 - 5/6 - 53840 - 54000 - 10
+ * 64800 - 8/9 - 57472 - 57600 - 8
+ * 64800 - 9/10 - 58192 - 58320 - 8
+ */
+ case FEC_1_2: bch_payload = 32128; break;
+ case FEC_3_5: bch_payload = 38608; break;
+ case FEC_2_3: bch_payload = 42960; break;
+ case FEC_3_4: bch_payload = 48328; break;
+ case FEC_4_5: bch_payload = 51568; break;
+ case FEC_5_6: bch_payload = 53760; break;
+ case FEC_8_9: bch_payload = 57392; break;
+ case FEC_9_10: bch_payload = 58112; break;
+ /* FEC_1_4 is not supported in this kernel */
+ /* FEC_1_3 is not supported in this kernel */
+ /* FEC_2_5 is not supported in this kernel */
+ default: return -EINVAL;
+ }
+
tmp1 = m88rs6000_readreg(state, 0xd7) & 0xff;
tmp2 = m88rs6000_readreg(state, 0xd6) & 0xff;
tmp3 = m88rs6000_readreg(state, 0xd5) & 0xff;
ldpc_frame_cnt = (tmp1 << 16) | (tmp2 << 8) | tmp3;
+ pre_total_packages = bch_payload * ldpc_frame_cnt / (188 * 8);
tmp1 = m88rs6000_readreg(state, 0xf8) & 0xff;
tmp2 = m88rs6000_readreg(state, 0xf7) & 0xff;
- pre_err_packags = tmp1<<8 | tmp2;
+ pre_err_packages = tmp1<<8 | tmp2;
- if (ldpc_frame_cnt > 1000){
+ if (ldpc_frame_cnt > 3000){
m88rs6000_writereg(state, 0xd1, 0x01);
m88rs6000_writereg(state, 0xf9, 0x01);
m88rs6000_writereg(state, 0xf9, 0x00);
m88rs6000_writereg(state, 0xd1, 0x00);
- state->preBer = pre_err_packags;
+ tmp4 = 1000000000ULL * pre_err_packages;
+ do_div(tmp4, pre_total_packages);
+ state->preBer = (u32)tmp4;
}
break;
default:
@@ -1425,74 +1526,23 @@
{
struct m88rs6000_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- u8 fec;
u32 rate;
fe_status_t status;
dprintk("%s()\n", __func__);
rate = (m88rs6000_readreg(state, 0x6e) << 8) | m88rs6000_readreg(state, 0x6d);
params->u.qpsk.symbol_rate = rate * ((state->iMclkKHz * 1000) >> 16);
+ params->u.qpsk.fec_inner = m88rs6000_get_fec(fe);
+ if (params->u.qpsk.fec_inner == FEC_NONE) {
+ return -EINVAL;
+ }
switch (state->delivery_system){
case SYS_DVBS:
- fec = m88rs6000_readreg(state, 0xe6) >> 5;
- switch(fec){
- case 0:
- params->u.qpsk.fec_inner = FEC_7_8;
- break;
- case 1:
- params->u.qpsk.fec_inner = FEC_5_6;
- break;
- case 2:
- params->u.qpsk.fec_inner = FEC_3_4;
- break;
- case 3:
- params->u.qpsk.fec_inner = FEC_2_3;
- break;
- case 4:
- params->u.qpsk.fec_inner = FEC_1_2;
- break;
- default:
- return -EINVAL;
- }
-
params->inversion = m88rs6000_readreg(state, 0xe0) & 0x40 ?
INVERSION_ON : INVERSION_OFF;
break;
case SYS_DVBS2:
- fec = m88rs6000_readreg(state, 0x7e) & 0x0f;
- switch(fec){
- case 3:
- params->u.qpsk.fec_inner = FEC_1_2;
- break;
- case 4:
- params->u.qpsk.fec_inner = FEC_3_5;
- break;
- case 5:
- params->u.qpsk.fec_inner = FEC_2_3;
- break;
- case 6:
- params->u.qpsk.fec_inner = FEC_3_4;
- break;
- case 7:
- params->u.qpsk.fec_inner = FEC_4_5;
- break;
- case 8:
- params->u.qpsk.fec_inner = FEC_5_6;
- break;
- case 9:
- params->u.qpsk.fec_inner = FEC_8_9;
- break;
- case 10:
- params->u.qpsk.fec_inner = FEC_9_10;
- break;
- case 0: /* FEC_1_4 is not supported in this kernel */
- case 1: /* FEC_1_3 is not supported in this kernel */
- case 2: /* FEC_2_5 is not supported in this kernel */
- default:
- return -EINVAL;
- }
-
m88rs6000_read_status(fe, &status);
if (status & FE_HAS_LOCK)
params->inversion = m88rs6000_readreg(state, 0x89) & 0x80 ?