cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

stb6100.c (15209B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3	STB6100 Silicon Tuner
      4	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
      5
      6	Copyright (C) ST Microelectronics
      7
      8*/
      9
     10#include <linux/init.h>
     11#include <linux/kernel.h>
     12#include <linux/module.h>
     13#include <linux/slab.h>
     14#include <linux/string.h>
     15
     16#include <media/dvb_frontend.h>
     17#include "stb6100.h"
     18
     19static unsigned int verbose;
     20module_param(verbose, int, 0644);
     21
     22/* Max transfer size done by I2C transfer functions */
     23#define MAX_XFER_SIZE  64
     24
     25#define FE_ERROR		0
     26#define FE_NOTICE		1
     27#define FE_INFO			2
     28#define FE_DEBUG		3
     29
     30#define dprintk(x, y, z, format, arg...) do {						\
     31	if (z) {									\
     32		if	((x > FE_ERROR) && (x > y))					\
     33			printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);		\
     34		else if	((x > FE_NOTICE) && (x > y))					\
     35			printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);	\
     36		else if ((x > FE_INFO) && (x > y))					\
     37			printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);		\
     38		else if ((x > FE_DEBUG) && (x > y))					\
     39			printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);	\
     40	} else {									\
     41		if (x > y)								\
     42			printk(format, ##arg);						\
     43	}										\
     44} while (0)
     45
     46struct stb6100_lkup {
     47	u32 val_low;
     48	u32 val_high;
     49	u8   reg;
     50};
     51
     52static void stb6100_release(struct dvb_frontend *fe);
     53
     54static const struct stb6100_lkup lkup[] = {
     55	{       0,  950000, 0x0a },
     56	{  950000, 1000000, 0x0a },
     57	{ 1000000, 1075000, 0x0c },
     58	{ 1075000, 1200000, 0x00 },
     59	{ 1200000, 1300000, 0x01 },
     60	{ 1300000, 1370000, 0x02 },
     61	{ 1370000, 1470000, 0x04 },
     62	{ 1470000, 1530000, 0x05 },
     63	{ 1530000, 1650000, 0x06 },
     64	{ 1650000, 1800000, 0x08 },
     65	{ 1800000, 1950000, 0x0a },
     66	{ 1950000, 2150000, 0x0c },
     67	{ 2150000, 9999999, 0x0c },
     68	{       0,       0, 0x00 }
     69};
     70
     71/* Register names for easy debugging.	*/
     72static const char *stb6100_regnames[] = {
     73	[STB6100_LD]		= "LD",
     74	[STB6100_VCO]		= "VCO",
     75	[STB6100_NI]		= "NI",
     76	[STB6100_NF_LSB]	= "NF",
     77	[STB6100_K]		= "K",
     78	[STB6100_G]		= "G",
     79	[STB6100_F]		= "F",
     80	[STB6100_DLB]		= "DLB",
     81	[STB6100_TEST1]		= "TEST1",
     82	[STB6100_FCCK]		= "FCCK",
     83	[STB6100_LPEN]		= "LPEN",
     84	[STB6100_TEST3]		= "TEST3",
     85};
     86
     87/* Template for normalisation, i.e. setting unused or undocumented
     88 * bits as required according to the documentation.
     89 */
     90struct stb6100_regmask {
     91	u8 mask;
     92	u8 set;
     93};
     94
     95static const struct stb6100_regmask stb6100_template[] = {
     96	[STB6100_LD]		= { 0xff, 0x00 },
     97	[STB6100_VCO]		= { 0xff, 0x00 },
     98	[STB6100_NI]		= { 0xff, 0x00 },
     99	[STB6100_NF_LSB]	= { 0xff, 0x00 },
    100	[STB6100_K]		= { 0xc7, 0x38 },
    101	[STB6100_G]		= { 0xef, 0x10 },
    102	[STB6100_F]		= { 0x1f, 0xc0 },
    103	[STB6100_DLB]		= { 0x38, 0xc4 },
    104	[STB6100_TEST1]		= { 0x00, 0x8f },
    105	[STB6100_FCCK]		= { 0x40, 0x0d },
    106	[STB6100_LPEN]		= { 0xf0, 0x0b },
    107	[STB6100_TEST3]		= { 0x00, 0xde },
    108};
    109
    110/*
    111 * Currently unused. Some boards might need it in the future
    112 */
    113static __always_unused inline void stb6100_normalise_regs(u8 regs[])
    114{
    115	int i;
    116
    117	for (i = 0; i < STB6100_NUMREGS; i++)
    118		regs[i] = (regs[i] & stb6100_template[i].mask) | stb6100_template[i].set;
    119}
    120
    121static int stb6100_read_regs(struct stb6100_state *state, u8 regs[])
    122{
    123	int rc;
    124	struct i2c_msg msg = {
    125		.addr	= state->config->tuner_address,
    126		.flags	= I2C_M_RD,
    127		.buf	= regs,
    128		.len	= STB6100_NUMREGS
    129	};
    130
    131	rc = i2c_transfer(state->i2c, &msg, 1);
    132	if (unlikely(rc != 1)) {
    133		dprintk(verbose, FE_ERROR, 1, "Read (0x%x) err, rc=[%d]",
    134			state->config->tuner_address, rc);
    135
    136		return -EREMOTEIO;
    137	}
    138	if (unlikely(verbose > FE_DEBUG)) {
    139		int i;
    140
    141		dprintk(verbose, FE_DEBUG, 1, "    Read from 0x%02x", state->config->tuner_address);
    142		for (i = 0; i < STB6100_NUMREGS; i++)
    143			dprintk(verbose, FE_DEBUG, 1, "        %s: 0x%02x", stb6100_regnames[i], regs[i]);
    144	}
    145	return 0;
    146}
    147
    148static int stb6100_read_reg(struct stb6100_state *state, u8 reg)
    149{
    150	u8 regs[STB6100_NUMREGS];
    151
    152	struct i2c_msg msg = {
    153		.addr	= state->config->tuner_address + reg,
    154		.flags	= I2C_M_RD,
    155		.buf	= regs,
    156		.len	= 1
    157	};
    158
    159	i2c_transfer(state->i2c, &msg, 1);
    160
    161	if (unlikely(reg >= STB6100_NUMREGS)) {
    162		dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg);
    163		return -EINVAL;
    164	}
    165	if (unlikely(verbose > FE_DEBUG)) {
    166		dprintk(verbose, FE_DEBUG, 1, "    Read from 0x%02x", state->config->tuner_address);
    167		dprintk(verbose, FE_DEBUG, 1, "        %s: 0x%02x", stb6100_regnames[reg], regs[0]);
    168	}
    169
    170	return (unsigned int)regs[0];
    171}
    172
    173static int stb6100_write_reg_range(struct stb6100_state *state, u8 buf[], int start, int len)
    174{
    175	int rc;
    176	u8 cmdbuf[MAX_XFER_SIZE];
    177	struct i2c_msg msg = {
    178		.addr	= state->config->tuner_address,
    179		.flags	= 0,
    180		.buf	= cmdbuf,
    181		.len	= len + 1
    182	};
    183
    184	if (1 + len > sizeof(cmdbuf)) {
    185		printk(KERN_WARNING
    186		       "%s: i2c wr: len=%d is too big!\n",
    187		       KBUILD_MODNAME, len);
    188		return -EINVAL;
    189	}
    190
    191	if (unlikely(start < 1 || start + len > STB6100_NUMREGS)) {
    192		dprintk(verbose, FE_ERROR, 1, "Invalid register range %d:%d",
    193			start, len);
    194		return -EINVAL;
    195	}
    196	memcpy(&cmdbuf[1], buf, len);
    197	cmdbuf[0] = start;
    198
    199	if (unlikely(verbose > FE_DEBUG)) {
    200		int i;
    201
    202		dprintk(verbose, FE_DEBUG, 1, "    Write @ 0x%02x: [%d:%d]", state->config->tuner_address, start, len);
    203		for (i = 0; i < len; i++)
    204			dprintk(verbose, FE_DEBUG, 1, "        %s: 0x%02x", stb6100_regnames[start + i], buf[i]);
    205	}
    206	rc = i2c_transfer(state->i2c, &msg, 1);
    207	if (unlikely(rc != 1)) {
    208		dprintk(verbose, FE_ERROR, 1, "(0x%x) write err [%d:%d], rc=[%d]",
    209			(unsigned int)state->config->tuner_address, start, len,	rc);
    210		return -EREMOTEIO;
    211	}
    212	return 0;
    213}
    214
    215static int stb6100_write_reg(struct stb6100_state *state, u8 reg, u8 data)
    216{
    217	u8 tmp = data; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
    218
    219	if (unlikely(reg >= STB6100_NUMREGS)) {
    220		dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg);
    221		return -EREMOTEIO;
    222	}
    223	tmp = (tmp & stb6100_template[reg].mask) | stb6100_template[reg].set;
    224	return stb6100_write_reg_range(state, &tmp, reg, 1);
    225}
    226
    227
    228static int stb6100_get_status(struct dvb_frontend *fe, u32 *status)
    229{
    230	int rc;
    231	struct stb6100_state *state = fe->tuner_priv;
    232
    233	rc = stb6100_read_reg(state, STB6100_LD);
    234	if (rc < 0) {
    235		dprintk(verbose, FE_ERROR, 1, "%s failed", __func__);
    236		return rc;
    237	}
    238	return (rc & STB6100_LD_LOCK) ? TUNER_STATUS_LOCKED : 0;
    239}
    240
    241static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
    242{
    243	int rc;
    244	u8 f;
    245	u32 bw;
    246	struct stb6100_state *state = fe->tuner_priv;
    247
    248	rc = stb6100_read_reg(state, STB6100_F);
    249	if (rc < 0)
    250		return rc;
    251	f = rc & STB6100_F_F;
    252
    253	bw = (f + 5) * 2000;	/* x2 for ZIF	*/
    254
    255	*bandwidth = state->bandwidth = bw * 1000;
    256	dprintk(verbose, FE_DEBUG, 1, "bandwidth = %u Hz", state->bandwidth);
    257	return 0;
    258}
    259
    260static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
    261{
    262	u32 tmp;
    263	int rc;
    264	struct stb6100_state *state = fe->tuner_priv;
    265
    266	dprintk(verbose, FE_DEBUG, 1, "set bandwidth to %u Hz", bandwidth);
    267
    268	bandwidth /= 2; /* ZIF */
    269
    270	if (bandwidth >= 36000000)	/* F[4:0] BW/2 max =31+5=36 mhz for F=31	*/
    271		tmp = 31;
    272	else if (bandwidth <= 5000000)	/* bw/2 min = 5Mhz for F=0			*/
    273		tmp = 0;
    274	else				/* if 5 < bw/2 < 36				*/
    275		tmp = (bandwidth + 500000) / 1000000 - 5;
    276
    277	/* Turn on LPF bandwidth setting clock control,
    278	 * set bandwidth, wait 10ms, turn off.
    279	 */
    280	rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d | STB6100_FCCK_FCCK);
    281	if (rc < 0)
    282		return rc;
    283	rc = stb6100_write_reg(state, STB6100_F, 0xc0 | tmp);
    284	if (rc < 0)
    285		return rc;
    286
    287	msleep(5);  /*  This is dangerous as another (related) thread may start */
    288
    289	rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d);
    290	if (rc < 0)
    291		return rc;
    292
    293	msleep(10);  /*  This is dangerous as another (related) thread may start */
    294
    295	return 0;
    296}
    297
    298static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
    299{
    300	int rc;
    301	u32 nint, nfrac, fvco;
    302	int psd2, odiv;
    303	struct stb6100_state *state = fe->tuner_priv;
    304	u8 regs[STB6100_NUMREGS];
    305
    306	rc = stb6100_read_regs(state, regs);
    307	if (rc < 0)
    308		return rc;
    309
    310	odiv = (regs[STB6100_VCO] & STB6100_VCO_ODIV) >> STB6100_VCO_ODIV_SHIFT;
    311	psd2 = (regs[STB6100_K] & STB6100_K_PSD2) >> STB6100_K_PSD2_SHIFT;
    312	nint = regs[STB6100_NI];
    313	nfrac = ((regs[STB6100_K] & STB6100_K_NF_MSB) << 8) | regs[STB6100_NF_LSB];
    314	fvco = (nfrac * state->reference >> (9 - psd2)) + (nint * state->reference << psd2);
    315	*frequency = state->frequency = fvco >> (odiv + 1);
    316
    317	dprintk(verbose, FE_DEBUG, 1,
    318		"frequency = %u kHz, odiv = %u, psd2 = %u, fxtal = %u kHz, fvco = %u kHz, N(I) = %u, N(F) = %u",
    319		state->frequency, odiv, psd2, state->reference,	fvco, nint, nfrac);
    320	return 0;
    321}
    322
    323
    324static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
    325{
    326	int rc;
    327	const struct stb6100_lkup *ptr;
    328	struct stb6100_state *state = fe->tuner_priv;
    329	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
    330
    331	u32 srate = 0, fvco, nint, nfrac;
    332	u8 regs[STB6100_NUMREGS];
    333	u8 g, psd2, odiv;
    334
    335	dprintk(verbose, FE_DEBUG, 1, "Version 2010-8-14 13:51");
    336
    337	if (fe->ops.get_frontend) {
    338		dprintk(verbose, FE_DEBUG, 1, "Get frontend parameters");
    339		fe->ops.get_frontend(fe, p);
    340	}
    341	srate = p->symbol_rate;
    342
    343	/* Set up tuner cleanly, LPF calibration on */
    344	rc = stb6100_write_reg(state, STB6100_FCCK, 0x4d | STB6100_FCCK_FCCK);
    345	if (rc < 0)
    346		return rc;  /* allow LPF calibration */
    347
    348	/* PLL Loop disabled, bias on, VCO on, synth on */
    349	regs[STB6100_LPEN] = 0xeb;
    350	rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN]);
    351	if (rc < 0)
    352		return rc;
    353
    354	/* Program the registers with their data values */
    355
    356	/* VCO divide ratio (LO divide ratio, VCO prescaler enable).	*/
    357	if (frequency <= 1075000)
    358		odiv = 1;
    359	else
    360		odiv = 0;
    361
    362	/* VCO enabled, search clock off as per LL3.7, 3.4.1 */
    363	regs[STB6100_VCO] = 0xe0 | (odiv << STB6100_VCO_ODIV_SHIFT);
    364
    365	/* OSM	*/
    366	for (ptr = lkup;
    367	     (ptr->val_high != 0) && !CHKRANGE(frequency, ptr->val_low, ptr->val_high);
    368	     ptr++);
    369
    370	if (ptr->val_high == 0) {
    371		printk(KERN_ERR "%s: frequency out of range: %u kHz\n", __func__, frequency);
    372		return -EINVAL;
    373	}
    374	regs[STB6100_VCO] = (regs[STB6100_VCO] & ~STB6100_VCO_OSM) | ptr->reg;
    375	rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]);
    376	if (rc < 0)
    377		return rc;
    378
    379	if ((frequency > 1075000) && (frequency <= 1325000))
    380		psd2 = 0;
    381	else
    382		psd2 = 1;
    383	/* F(VCO) = F(LO) * (ODIV == 0 ? 2 : 4)			*/
    384	fvco = frequency << (1 + odiv);
    385	/* N(I) = floor(f(VCO) / (f(XTAL) * (PSD2 ? 2 : 1)))	*/
    386	nint = fvco / (state->reference << psd2);
    387	/* N(F) = round(f(VCO) / f(XTAL) * (PSD2 ? 2 : 1) - N(I)) * 2 ^ 9	*/
    388	nfrac = DIV_ROUND_CLOSEST((fvco - (nint * state->reference << psd2))
    389					 << (9 - psd2), state->reference);
    390
    391	/* NI */
    392	regs[STB6100_NI] = nint;
    393	rc = stb6100_write_reg(state, STB6100_NI, regs[STB6100_NI]);
    394	if (rc < 0)
    395		return rc;
    396
    397	/* NF */
    398	regs[STB6100_NF_LSB] = nfrac;
    399	rc = stb6100_write_reg(state, STB6100_NF_LSB, regs[STB6100_NF_LSB]);
    400	if (rc < 0)
    401		return rc;
    402
    403	/* K */
    404	regs[STB6100_K] = (0x38 & ~STB6100_K_PSD2) | (psd2 << STB6100_K_PSD2_SHIFT);
    405	regs[STB6100_K] = (regs[STB6100_K] & ~STB6100_K_NF_MSB) | ((nfrac >> 8) & STB6100_K_NF_MSB);
    406	rc = stb6100_write_reg(state, STB6100_K, regs[STB6100_K]);
    407	if (rc < 0)
    408		return rc;
    409
    410	/* G Baseband gain. */
    411	if (srate >= 15000000)
    412		g = 9;  /*  +4 dB */
    413	else if (srate >= 5000000)
    414		g = 11; /*  +8 dB */
    415	else
    416		g = 14; /* +14 dB */
    417
    418	regs[STB6100_G] = (0x10 & ~STB6100_G_G) | g;
    419	regs[STB6100_G] &= ~STB6100_G_GCT; /* mask GCT */
    420	regs[STB6100_G] |= (1 << 5); /* 2Vp-p Mode */
    421	rc = stb6100_write_reg(state, STB6100_G, regs[STB6100_G]);
    422	if (rc < 0)
    423		return rc;
    424
    425	/* F we don't write as it is set up in BW set */
    426
    427	/* DLB set DC servo loop BW to 160Hz (LLA 3.8 / 2.1) */
    428	regs[STB6100_DLB] = 0xcc;
    429	rc = stb6100_write_reg(state, STB6100_DLB, regs[STB6100_DLB]);
    430	if (rc < 0)
    431		return rc;
    432
    433	dprintk(verbose, FE_DEBUG, 1,
    434		"frequency = %u, srate = %u, g = %u, odiv = %u, psd2 = %u, fxtal = %u, osm = %u, fvco = %u, N(I) = %u, N(F) = %u",
    435		frequency, srate, (unsigned int)g, (unsigned int)odiv,
    436		(unsigned int)psd2, state->reference,
    437		ptr->reg, fvco, nint, nfrac);
    438
    439	/* Set up the test registers */
    440	regs[STB6100_TEST1] = 0x8f;
    441	rc = stb6100_write_reg(state, STB6100_TEST1, regs[STB6100_TEST1]);
    442	if (rc < 0)
    443		return rc;
    444	regs[STB6100_TEST3] = 0xde;
    445	rc = stb6100_write_reg(state, STB6100_TEST3, regs[STB6100_TEST3]);
    446	if (rc < 0)
    447		return rc;
    448
    449	/* Bring up tuner according to LLA 3.7 3.4.1, step 2 */
    450	regs[STB6100_LPEN] = 0xfb; /* PLL Loop enabled, bias on, VCO on, synth on */
    451	rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN]);
    452	if (rc < 0)
    453		return rc;
    454
    455	msleep(2);
    456
    457	/* Bring up tuner according to LLA 3.7 3.4.1, step 3 */
    458	regs[STB6100_VCO] &= ~STB6100_VCO_OCK;		/* VCO fast search		*/
    459	rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]);
    460	if (rc < 0)
    461		return rc;
    462
    463	msleep(10);  /*  This is dangerous as another (related) thread may start */ /* wait for LO to lock */
    464
    465	regs[STB6100_VCO] &= ~STB6100_VCO_OSCH;		/* vco search disabled		*/
    466	regs[STB6100_VCO] |= STB6100_VCO_OCK;		/* search clock off		*/
    467	rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]);
    468	if (rc < 0)
    469		return rc;
    470
    471	rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d);
    472	if (rc < 0)
    473		return rc;  /* Stop LPF calibration */
    474
    475	msleep(10);  /*  This is dangerous as another (related) thread may start */
    476		     /* wait for stabilisation, (should not be necessary)		*/
    477	return 0;
    478}
    479
    480static int stb6100_sleep(struct dvb_frontend *fe)
    481{
    482	/* TODO: power down	*/
    483	return 0;
    484}
    485
    486static int stb6100_init(struct dvb_frontend *fe)
    487{
    488	struct stb6100_state *state = fe->tuner_priv;
    489	int refclk = 27000000; /* Hz */
    490
    491	/*
    492	 * iqsense = 1
    493	 * tunerstep = 125000
    494	 */
    495	state->bandwidth        = 36000000;		/* Hz	*/
    496	state->reference	= refclk / 1000;	/* kHz	*/
    497
    498	/* Set default bandwidth. Modified, PN 13-May-10	*/
    499	return 0;
    500}
    501
    502static int stb6100_set_params(struct dvb_frontend *fe)
    503{
    504	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
    505
    506	if (c->frequency > 0)
    507		stb6100_set_frequency(fe, c->frequency);
    508
    509	if (c->bandwidth_hz > 0)
    510		stb6100_set_bandwidth(fe, c->bandwidth_hz);
    511
    512	return 0;
    513}
    514
    515static const struct dvb_tuner_ops stb6100_ops = {
    516	.info = {
    517		.name			= "STB6100 Silicon Tuner",
    518		.frequency_min_hz	=  950 * MHz,
    519		.frequency_max_hz	= 2150 * MHz,
    520	},
    521
    522	.init		= stb6100_init,
    523	.sleep          = stb6100_sleep,
    524	.get_status	= stb6100_get_status,
    525	.set_params	= stb6100_set_params,
    526	.get_frequency  = stb6100_get_frequency,
    527	.get_bandwidth  = stb6100_get_bandwidth,
    528	.release	= stb6100_release
    529};
    530
    531struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
    532				    const struct stb6100_config *config,
    533				    struct i2c_adapter *i2c)
    534{
    535	struct stb6100_state *state = NULL;
    536
    537	state = kzalloc(sizeof (struct stb6100_state), GFP_KERNEL);
    538	if (!state)
    539		return NULL;
    540
    541	state->config		= config;
    542	state->i2c		= i2c;
    543	state->frontend		= fe;
    544	state->reference	= config->refclock / 1000; /* kHz */
    545	fe->tuner_priv		= state;
    546	fe->ops.tuner_ops	= stb6100_ops;
    547
    548	printk("%s: Attaching STB6100 \n", __func__);
    549	return fe;
    550}
    551
    552static void stb6100_release(struct dvb_frontend *fe)
    553{
    554	struct stb6100_state *state = fe->tuner_priv;
    555
    556	fe->tuner_priv = NULL;
    557	kfree(state);
    558}
    559
    560EXPORT_SYMBOL(stb6100_attach);
    561MODULE_PARM_DESC(verbose, "Set Verbosity level");
    562
    563MODULE_AUTHOR("Manu Abraham");
    564MODULE_DESCRIPTION("STB6100 Silicon tuner");
    565MODULE_LICENSE("GPL");