aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <m.chehab@samsung.com>2014-05-29 13:44:56 -0400
committerMauro Carvalho Chehab <m.chehab@samsung.com>2014-06-17 11:04:50 -0400
commit041ad449683bb2d54a7f082d78ec15bbc958a175 (patch)
tree66b2c1687a0cc80046185500f51acb5abd536a7f
parentd44913c1e547df19b2dc0b527f92a4b4354be23a (diff)
[media] dib7000p: Add DVBv5 stats support
Adds DVBv5 stats support. For now, just mimic whatever dib8000 does, as they're very similar, with regards to statistics. However, dib7000p_get_time_us() likely require some adjustments, as I didn't actually reviewed the formula for it to work with DVB-T. Still, better than nothing, as latter patches can improve it. This patch also doesn't show the signal strength in dB yet. The code is already there, but it requires to be callibrated. A latter patch will do the calibration. It seems that this patch is also a bug fix: Before this patch, the frontend were not tuning with some userspace tools. I suspect that dib7000p firmware or hardware internally expects that the statistics to be collected, in order for it to work. With this patch, the DVB core will always retrive statistics, even if userspace doesn't request. So, it makes the device work on all tested apps. Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
-rw-r--r--drivers/media/dvb-frontends/dib7000p.c321
1 files changed, 320 insertions, 1 deletions
diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c
index d36fa0d74259..c41f90da6e1a 100644
--- a/drivers/media/dvb-frontends/dib7000p.c
+++ b/drivers/media/dvb-frontends/dib7000p.c
@@ -11,6 +11,7 @@
11#include <linux/slab.h> 11#include <linux/slab.h>
12#include <linux/i2c.h> 12#include <linux/i2c.h>
13#include <linux/mutex.h> 13#include <linux/mutex.h>
14#include <asm/div64.h>
14 15
15#include "dvb_math.h" 16#include "dvb_math.h"
16#include "dvb_frontend.h" 17#include "dvb_frontend.h"
@@ -72,6 +73,12 @@ struct dib7000p_state {
72 struct mutex i2c_buffer_lock; 73 struct mutex i2c_buffer_lock;
73 74
74 u8 input_mode_mpeg; 75 u8 input_mode_mpeg;
76
77 /* for DVBv5 stats */
78 s64 old_ucb;
79 unsigned long per_jiffies_stats;
80 unsigned long ber_jiffies_stats;
81 unsigned long get_stats_time;
75}; 82};
76 83
77enum dib7000p_power_mode { 84enum dib7000p_power_mode {
@@ -631,6 +638,8 @@ static u16 dib7000p_defaults[] = {
631 0, 638 0,
632}; 639};
633 640
641static void dib7000p_reset_stats(struct dvb_frontend *fe);
642
634static int dib7000p_demod_reset(struct dib7000p_state *state) 643static int dib7000p_demod_reset(struct dib7000p_state *state)
635{ 644{
636 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); 645 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
@@ -1354,6 +1363,9 @@ static int dib7000p_tune(struct dvb_frontend *demod)
1354 dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->bandwidth_hz)); 1363 dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
1355 1364
1356 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz)); 1365 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
1366
1367 dib7000p_reset_stats(demod);
1368
1357 return 0; 1369 return 0;
1358} 1370}
1359 1371
@@ -1546,6 +1558,8 @@ static int dib7000p_set_frontend(struct dvb_frontend *fe)
1546 return ret; 1558 return ret;
1547} 1559}
1548 1560
1561static int dib7000p_get_stats(struct dvb_frontend *fe, fe_status_t stat);
1562
1549static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat) 1563static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat)
1550{ 1564{
1551 struct dib7000p_state *state = fe->demodulator_priv; 1565 struct dib7000p_state *state = fe->demodulator_priv;
@@ -1564,6 +1578,8 @@ static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat)
1564 if ((lock & 0x0038) == 0x38) 1578 if ((lock & 0x0038) == 0x38)
1565 *stat |= FE_HAS_LOCK; 1579 *stat |= FE_HAS_LOCK;
1566 1580
1581 dib7000p_get_stats(fe, *stat);
1582
1567 return 0; 1583 return 0;
1568} 1584}
1569 1585
@@ -1589,7 +1605,7 @@ static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength
1589 return 0; 1605 return 0;
1590} 1606}
1591 1607
1592static int dib7000p_read_snr(struct dvb_frontend *fe, u16 * snr) 1608static u32 dib7000p_get_snr(struct dvb_frontend *fe)
1593{ 1609{
1594 struct dib7000p_state *state = fe->demodulator_priv; 1610 struct dib7000p_state *state = fe->demodulator_priv;
1595 u16 val; 1611 u16 val;
@@ -1619,10 +1635,311 @@ static int dib7000p_read_snr(struct dvb_frontend *fe, u16 * snr)
1619 else 1635 else
1620 result -= intlog10(2) * 10 * noise_exp - 100; 1636 result -= intlog10(2) * 10 * noise_exp - 100;
1621 1637
1638 return result;
1639}
1640
1641static int dib7000p_read_snr(struct dvb_frontend *fe, u16 *snr)
1642{
1643 u32 result;
1644
1645 result = dib7000p_get_snr(fe);
1646
1622 *snr = result / ((1 << 24) / 10); 1647 *snr = result / ((1 << 24) / 10);
1623 return 0; 1648 return 0;
1624} 1649}
1625 1650
1651static void dib7000p_reset_stats(struct dvb_frontend *demod)
1652{
1653 struct dib7000p_state *state = demod->demodulator_priv;
1654 struct dtv_frontend_properties *c = &demod->dtv_property_cache;
1655 u32 ucb;
1656
1657 memset(&c->strength, 0, sizeof(c->strength));
1658 memset(&c->cnr, 0, sizeof(c->cnr));
1659 memset(&c->post_bit_error, 0, sizeof(c->post_bit_error));
1660 memset(&c->post_bit_count, 0, sizeof(c->post_bit_count));
1661 memset(&c->block_error, 0, sizeof(c->block_error));
1662
1663 c->strength.len = 1;
1664 c->cnr.len = 1;
1665 c->block_error.len = 1;
1666 c->block_count.len = 1;
1667 c->post_bit_error.len = 1;
1668 c->post_bit_count.len = 1;
1669
1670 c->strength.stat[0].scale = FE_SCALE_DECIBEL;
1671 c->strength.stat[0].uvalue = 0;
1672
1673 c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1674 c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1675 c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1676 c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1677 c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1678
1679 dib7000p_read_unc_blocks(demod, &ucb);
1680
1681 state->old_ucb = ucb;
1682 state->ber_jiffies_stats = 0;
1683 state->per_jiffies_stats = 0;
1684}
1685
1686struct linear_segments {
1687 unsigned x;
1688 signed y;
1689};
1690
1691/*
1692 * Table to estimate signal strength in dBm.
1693 * This table should be empirically determinated by measuring the signal
1694 * strength generated by a RF generator directly connected into
1695 * a device.
1696 */
1697/* FIXME: Calibrate the table */
1698
1699#define DB_OFFSET 0
1700
1701static struct linear_segments strength_to_db_table[] = {
1702 { 65535, 65535},
1703 { 0, 0},
1704};
1705
1706static u32 interpolate_value(u32 value, struct linear_segments *segments,
1707 unsigned len)
1708{
1709 u64 tmp64;
1710 u32 dx;
1711 s32 dy;
1712 int i, ret;
1713
1714 if (value >= segments[0].x)
1715 return segments[0].y;
1716 if (value < segments[len-1].x)
1717 return segments[len-1].y;
1718
1719 for (i = 1; i < len - 1; i++) {
1720 /* If value is identical, no need to interpolate */
1721 if (value == segments[i].x)
1722 return segments[i].y;
1723 if (value > segments[i].x)
1724 break;
1725 }
1726
1727 /* Linear interpolation between the two (x,y) points */
1728 dy = segments[i - 1].y - segments[i].y;
1729 dx = segments[i - 1].x - segments[i].x;
1730
1731 tmp64 = value - segments[i].x;
1732 tmp64 *= dy;
1733 do_div(tmp64, dx);
1734 ret = segments[i].y + tmp64;
1735
1736 return ret;
1737}
1738
1739/* FIXME: may require changes - this one was borrowed from dib8000 */
1740static u32 dib7000p_get_time_us(struct dvb_frontend *demod, int layer)
1741{
1742 struct dtv_frontend_properties *c = &demod->dtv_property_cache;
1743 u64 time_us, tmp64;
1744 u32 tmp, denom;
1745 int guard, rate_num, rate_denum = 1, bits_per_symbol;
1746 int interleaving = 0, fft_div;
1747
1748 switch (c->guard_interval) {
1749 case GUARD_INTERVAL_1_4:
1750 guard = 4;
1751 break;
1752 case GUARD_INTERVAL_1_8:
1753 guard = 8;
1754 break;
1755 case GUARD_INTERVAL_1_16:
1756 guard = 16;
1757 break;
1758 default:
1759 case GUARD_INTERVAL_1_32:
1760 guard = 32;
1761 break;
1762 }
1763
1764 switch (c->transmission_mode) {
1765 case TRANSMISSION_MODE_2K:
1766 fft_div = 4;
1767 break;
1768 case TRANSMISSION_MODE_4K:
1769 fft_div = 2;
1770 break;
1771 default:
1772 case TRANSMISSION_MODE_8K:
1773 fft_div = 1;
1774 break;
1775 }
1776
1777 switch (c->modulation) {
1778 case DQPSK:
1779 case QPSK:
1780 bits_per_symbol = 2;
1781 break;
1782 case QAM_16:
1783 bits_per_symbol = 4;
1784 break;
1785 default:
1786 case QAM_64:
1787 bits_per_symbol = 6;
1788 break;
1789 }
1790
1791 switch ((c->hierarchy == 0 || 1 == 1) ? c->code_rate_HP : c->code_rate_LP) {
1792 case FEC_1_2:
1793 rate_num = 1;
1794 rate_denum = 2;
1795 break;
1796 case FEC_2_3:
1797 rate_num = 2;
1798 rate_denum = 3;
1799 break;
1800 case FEC_3_4:
1801 rate_num = 3;
1802 rate_denum = 4;
1803 break;
1804 case FEC_5_6:
1805 rate_num = 5;
1806 rate_denum = 6;
1807 break;
1808 default:
1809 case FEC_7_8:
1810 rate_num = 7;
1811 rate_denum = 8;
1812 break;
1813 }
1814
1815 interleaving = interleaving;
1816
1817 denom = bits_per_symbol * rate_num * fft_div * 384;
1818
1819 /* If calculus gets wrong, wait for 1s for the next stats */
1820 if (!denom)
1821 return 0;
1822
1823 /* Estimate the period for the total bit rate */
1824 time_us = rate_denum * (1008 * 1562500L);
1825 tmp64 = time_us;
1826 do_div(tmp64, guard);
1827 time_us = time_us + tmp64;
1828 time_us += denom / 2;
1829 do_div(time_us, denom);
1830
1831 tmp = 1008 * 96 * interleaving;
1832 time_us += tmp + tmp / guard;
1833
1834 return time_us;
1835}
1836
1837static int dib7000p_get_stats(struct dvb_frontend *demod, fe_status_t stat)
1838{
1839 struct dib7000p_state *state = demod->demodulator_priv;
1840 struct dtv_frontend_properties *c = &demod->dtv_property_cache;
1841 int i;
1842 int show_per_stats = 0;
1843 u32 time_us = 0, val, snr;
1844 u64 blocks, ucb;
1845 s32 db;
1846 u16 strength;
1847
1848 /* Get Signal strength */
1849 dib7000p_read_signal_strength(demod, &strength);
1850 val = strength;
1851 db = interpolate_value(val,
1852 strength_to_db_table,
1853 ARRAY_SIZE(strength_to_db_table)) - DB_OFFSET;
1854 c->strength.stat[0].svalue = db;
1855
1856 /* FIXME: Remove this when calibrated to DB */
1857 c->strength.stat[0].scale = FE_SCALE_COUNTER;
1858
1859 /* UCB/BER/CNR measures require lock */
1860 if (!(stat & FE_HAS_LOCK)) {
1861 c->cnr.len = 1;
1862 c->block_count.len = 1;
1863 c->block_error.len = 1;
1864 c->post_bit_error.len = 1;
1865 c->post_bit_count.len = 1;
1866 c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1867 c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1868 c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1869 c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1870 c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1871 return 0;
1872 }
1873
1874 /* Check if time for stats was elapsed */
1875 if (time_after(jiffies, state->per_jiffies_stats)) {
1876 state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
1877
1878 /* Get SNR */
1879 snr = dib7000p_get_snr(demod);
1880 if (snr)
1881 snr = (1000L * snr) >> 24;
1882 else
1883 snr = 0;
1884 c->cnr.stat[0].svalue = snr;
1885 c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
1886
1887 /* Get UCB measures */
1888 dib7000p_read_unc_blocks(demod, &val);
1889 ucb = val - state->old_ucb;
1890 if (val < state->old_ucb)
1891 ucb += 0x100000000LL;
1892
1893 c->block_error.stat[0].scale = FE_SCALE_COUNTER;
1894 c->block_error.stat[0].uvalue = ucb;
1895
1896 /* Estimate the number of packets based on bitrate */
1897 if (!time_us)
1898 time_us = dib7000p_get_time_us(demod, -1);
1899
1900 if (time_us) {
1901 blocks = 1250000ULL * 1000000ULL;
1902 do_div(blocks, time_us * 8 * 204);
1903 c->block_count.stat[0].scale = FE_SCALE_COUNTER;
1904 c->block_count.stat[0].uvalue += blocks;
1905 }
1906
1907 show_per_stats = 1;
1908 }
1909
1910 /* Get post-BER measures */
1911 if (time_after(jiffies, state->ber_jiffies_stats)) {
1912 time_us = dib7000p_get_time_us(demod, -1);
1913 state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
1914
1915 dprintk("Next all layers stats available in %u us.", time_us);
1916
1917 dib7000p_read_ber(demod, &val);
1918 c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
1919 c->post_bit_error.stat[0].uvalue += val;
1920
1921 c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
1922 c->post_bit_count.stat[0].uvalue += 100000000;
1923 }
1924
1925 /* Get PER measures */
1926 if (show_per_stats) {
1927 dib7000p_read_unc_blocks(demod, &val);
1928
1929 c->block_error.stat[0].scale = FE_SCALE_COUNTER;
1930 c->block_error.stat[0].uvalue += val;
1931
1932 time_us = dib7000p_get_time_us(demod, i);
1933 if (time_us) {
1934 blocks = 1250000ULL * 1000000ULL;
1935 do_div(blocks, time_us * 8 * 204);
1936 c->block_count.stat[0].scale = FE_SCALE_COUNTER;
1937 c->block_count.stat[0].uvalue += blocks;
1938 }
1939 }
1940 return 0;
1941}
1942
1626static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) 1943static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
1627{ 1944{
1628 tune->min_delay_ms = 1000; 1945 tune->min_delay_ms = 1000;
@@ -2408,6 +2725,8 @@ static struct dvb_frontend *dib7000p_init(struct i2c_adapter *i2c_adap, u8 i2c_a
2408 2725
2409 dib7000p_demod_reset(st); 2726 dib7000p_demod_reset(st);
2410 2727
2728 dib7000p_reset_stats(demod);
2729
2411 if (st->version == SOC7090) { 2730 if (st->version == SOC7090) {
2412 dib7090_set_output_mode(demod, st->cfg.output_mode); 2731 dib7090_set_output_mode(demod, st->cfg.output_mode);
2413 dib7090_set_diversity_in(demod, 0); 2732 dib7090_set_diversity_in(demod, 0);