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

sp8870.c (14092B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3    Driver for Spase SP8870 demodulator
      4
      5    Copyright (C) 1999 Juergen Peitz
      6
      7
      8*/
      9/*
     10 * This driver needs external firmware. Please use the command
     11 * "<kerneldir>/scripts/get_dvb_firmware alps_tdlb7" to
     12 * download/extract it, and then copy it to /usr/lib/hotplug/firmware
     13 * or /lib/firmware (depending on configuration of firmware hotplug).
     14 */
     15#define SP8870_DEFAULT_FIRMWARE "dvb-fe-sp8870.fw"
     16
     17#include <linux/init.h>
     18#include <linux/module.h>
     19#include <linux/device.h>
     20#include <linux/firmware.h>
     21#include <linux/delay.h>
     22#include <linux/string.h>
     23#include <linux/slab.h>
     24
     25#include <media/dvb_frontend.h>
     26#include "sp8870.h"
     27
     28
     29struct sp8870_state {
     30
     31	struct i2c_adapter* i2c;
     32
     33	const struct sp8870_config* config;
     34
     35	struct dvb_frontend frontend;
     36
     37	/* demodulator private data */
     38	u8 initialised:1;
     39};
     40
     41static int debug;
     42#define dprintk(args...) \
     43	do { \
     44		if (debug) printk(KERN_DEBUG "sp8870: " args); \
     45	} while (0)
     46
     47/* firmware size for sp8870 */
     48#define SP8870_FIRMWARE_SIZE 16382
     49
     50/* starting point for firmware in file 'Sc_main.mc' */
     51#define SP8870_FIRMWARE_OFFSET 0x0A
     52
     53static int sp8870_writereg (struct sp8870_state* state, u16 reg, u16 data)
     54{
     55	u8 buf [] = { reg >> 8, reg & 0xff, data >> 8, data & 0xff };
     56	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 4 };
     57	int err;
     58
     59	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
     60		dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data);
     61		return -EREMOTEIO;
     62	}
     63
     64	return 0;
     65}
     66
     67static int sp8870_readreg (struct sp8870_state* state, u16 reg)
     68{
     69	int ret;
     70	u8 b0 [] = { reg >> 8 , reg & 0xff };
     71	u8 b1 [] = { 0, 0 };
     72	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 },
     73			   { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 } };
     74
     75	ret = i2c_transfer (state->i2c, msg, 2);
     76
     77	if (ret != 2) {
     78		dprintk("%s: readreg error (ret == %i)\n", __func__, ret);
     79		return -1;
     80	}
     81
     82	return (b1[0] << 8 | b1[1]);
     83}
     84
     85static int sp8870_firmware_upload (struct sp8870_state* state, const struct firmware *fw)
     86{
     87	struct i2c_msg msg;
     88	const char *fw_buf = fw->data;
     89	int fw_pos;
     90	u8 tx_buf[255];
     91	int tx_len;
     92	int err = 0;
     93
     94	dprintk ("%s: ...\n", __func__);
     95
     96	if (fw->size < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET)
     97		return -EINVAL;
     98
     99	// system controller stop
    100	sp8870_writereg(state, 0x0F00, 0x0000);
    101
    102	// instruction RAM register hiword
    103	sp8870_writereg(state, 0x8F08, ((SP8870_FIRMWARE_SIZE / 2) & 0xFFFF));
    104
    105	// instruction RAM MWR
    106	sp8870_writereg(state, 0x8F0A, ((SP8870_FIRMWARE_SIZE / 2) >> 16));
    107
    108	// do firmware upload
    109	fw_pos = SP8870_FIRMWARE_OFFSET;
    110	while (fw_pos < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET){
    111		tx_len = (fw_pos <= SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - 252) ? 252 : SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - fw_pos;
    112		// write register 0xCF0A
    113		tx_buf[0] = 0xCF;
    114		tx_buf[1] = 0x0A;
    115		memcpy(&tx_buf[2], fw_buf + fw_pos, tx_len);
    116		msg.addr = state->config->demod_address;
    117		msg.flags = 0;
    118		msg.buf = tx_buf;
    119		msg.len = tx_len + 2;
    120		if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
    121			printk("%s: firmware upload failed!\n", __func__);
    122			printk ("%s: i2c error (err == %i)\n", __func__, err);
    123			return err;
    124		}
    125		fw_pos += tx_len;
    126	}
    127
    128	dprintk ("%s: done!\n", __func__);
    129	return 0;
    130};
    131
    132static void sp8870_microcontroller_stop (struct sp8870_state* state)
    133{
    134	sp8870_writereg(state, 0x0F08, 0x000);
    135	sp8870_writereg(state, 0x0F09, 0x000);
    136
    137	// microcontroller STOP
    138	sp8870_writereg(state, 0x0F00, 0x000);
    139}
    140
    141static void sp8870_microcontroller_start (struct sp8870_state* state)
    142{
    143	sp8870_writereg(state, 0x0F08, 0x000);
    144	sp8870_writereg(state, 0x0F09, 0x000);
    145
    146	// microcontroller START
    147	sp8870_writereg(state, 0x0F00, 0x001);
    148	// not documented but if we don't read 0x0D01 out here
    149	// we don't get a correct data valid signal
    150	sp8870_readreg(state, 0x0D01);
    151}
    152
    153static int sp8870_read_data_valid_signal(struct sp8870_state* state)
    154{
    155	return (sp8870_readreg(state, 0x0D02) > 0);
    156}
    157
    158static int configure_reg0xc05 (struct dtv_frontend_properties *p, u16 *reg0xc05)
    159{
    160	int known_parameters = 1;
    161
    162	*reg0xc05 = 0x000;
    163
    164	switch (p->modulation) {
    165	case QPSK:
    166		break;
    167	case QAM_16:
    168		*reg0xc05 |= (1 << 10);
    169		break;
    170	case QAM_64:
    171		*reg0xc05 |= (2 << 10);
    172		break;
    173	case QAM_AUTO:
    174		known_parameters = 0;
    175		break;
    176	default:
    177		return -EINVAL;
    178	}
    179
    180	switch (p->hierarchy) {
    181	case HIERARCHY_NONE:
    182		break;
    183	case HIERARCHY_1:
    184		*reg0xc05 |= (1 << 7);
    185		break;
    186	case HIERARCHY_2:
    187		*reg0xc05 |= (2 << 7);
    188		break;
    189	case HIERARCHY_4:
    190		*reg0xc05 |= (3 << 7);
    191		break;
    192	case HIERARCHY_AUTO:
    193		known_parameters = 0;
    194		break;
    195	default:
    196		return -EINVAL;
    197	}
    198
    199	switch (p->code_rate_HP) {
    200	case FEC_1_2:
    201		break;
    202	case FEC_2_3:
    203		*reg0xc05 |= (1 << 3);
    204		break;
    205	case FEC_3_4:
    206		*reg0xc05 |= (2 << 3);
    207		break;
    208	case FEC_5_6:
    209		*reg0xc05 |= (3 << 3);
    210		break;
    211	case FEC_7_8:
    212		*reg0xc05 |= (4 << 3);
    213		break;
    214	case FEC_AUTO:
    215		known_parameters = 0;
    216		break;
    217	default:
    218		return -EINVAL;
    219	}
    220
    221	if (known_parameters)
    222		*reg0xc05 |= (2 << 1);	/* use specified parameters */
    223	else
    224		*reg0xc05 |= (1 << 1);	/* enable autoprobing */
    225
    226	return 0;
    227}
    228
    229static int sp8870_wake_up(struct sp8870_state* state)
    230{
    231	// enable TS output and interface pins
    232	return sp8870_writereg(state, 0xC18, 0x00D);
    233}
    234
    235static int sp8870_set_frontend_parameters(struct dvb_frontend *fe)
    236{
    237	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
    238	struct sp8870_state* state = fe->demodulator_priv;
    239	int  err;
    240	u16 reg0xc05;
    241
    242	if ((err = configure_reg0xc05(p, &reg0xc05)))
    243		return err;
    244
    245	// system controller stop
    246	sp8870_microcontroller_stop(state);
    247
    248	// set tuner parameters
    249	if (fe->ops.tuner_ops.set_params) {
    250		fe->ops.tuner_ops.set_params(fe);
    251		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
    252	}
    253
    254	// sample rate correction bit [23..17]
    255	sp8870_writereg(state, 0x0319, 0x000A);
    256
    257	// sample rate correction bit [16..0]
    258	sp8870_writereg(state, 0x031A, 0x0AAB);
    259
    260	// integer carrier offset
    261	sp8870_writereg(state, 0x0309, 0x0400);
    262
    263	// fractional carrier offset
    264	sp8870_writereg(state, 0x030A, 0x0000);
    265
    266	// filter for 6/7/8 Mhz channel
    267	if (p->bandwidth_hz == 6000000)
    268		sp8870_writereg(state, 0x0311, 0x0002);
    269	else if (p->bandwidth_hz == 7000000)
    270		sp8870_writereg(state, 0x0311, 0x0001);
    271	else
    272		sp8870_writereg(state, 0x0311, 0x0000);
    273
    274	// scan order: 2k first = 0x0000, 8k first = 0x0001
    275	if (p->transmission_mode == TRANSMISSION_MODE_2K)
    276		sp8870_writereg(state, 0x0338, 0x0000);
    277	else
    278		sp8870_writereg(state, 0x0338, 0x0001);
    279
    280	sp8870_writereg(state, 0xc05, reg0xc05);
    281
    282	// read status reg in order to clear pending irqs
    283	err = sp8870_readreg(state, 0x200);
    284	if (err < 0)
    285		return err;
    286
    287	// system controller start
    288	sp8870_microcontroller_start(state);
    289
    290	return 0;
    291}
    292
    293static int sp8870_init (struct dvb_frontend* fe)
    294{
    295	struct sp8870_state* state = fe->demodulator_priv;
    296	const struct firmware *fw = NULL;
    297
    298	sp8870_wake_up(state);
    299	if (state->initialised) return 0;
    300	state->initialised = 1;
    301
    302	dprintk ("%s\n", __func__);
    303
    304
    305	/* request the firmware, this will block until someone uploads it */
    306	printk("sp8870: waiting for firmware upload (%s)...\n", SP8870_DEFAULT_FIRMWARE);
    307	if (state->config->request_firmware(fe, &fw, SP8870_DEFAULT_FIRMWARE)) {
    308		printk("sp8870: no firmware upload (timeout or file not found?)\n");
    309		return -EIO;
    310	}
    311
    312	if (sp8870_firmware_upload(state, fw)) {
    313		printk("sp8870: writing firmware to device failed\n");
    314		release_firmware(fw);
    315		return -EIO;
    316	}
    317	release_firmware(fw);
    318	printk("sp8870: firmware upload complete\n");
    319
    320	/* enable TS output and interface pins */
    321	sp8870_writereg(state, 0xc18, 0x00d);
    322
    323	// system controller stop
    324	sp8870_microcontroller_stop(state);
    325
    326	// ADC mode
    327	sp8870_writereg(state, 0x0301, 0x0003);
    328
    329	// Reed Solomon parity bytes passed to output
    330	sp8870_writereg(state, 0x0C13, 0x0001);
    331
    332	// MPEG clock is suppressed if no valid data
    333	sp8870_writereg(state, 0x0C14, 0x0001);
    334
    335	/* bit 0x010: enable data valid signal */
    336	sp8870_writereg(state, 0x0D00, 0x010);
    337	sp8870_writereg(state, 0x0D01, 0x000);
    338
    339	return 0;
    340}
    341
    342static int sp8870_read_status(struct dvb_frontend *fe,
    343			      enum fe_status *fe_status)
    344{
    345	struct sp8870_state* state = fe->demodulator_priv;
    346	int status;
    347	int signal;
    348
    349	*fe_status = 0;
    350
    351	status = sp8870_readreg (state, 0x0200);
    352	if (status < 0)
    353		return -EIO;
    354
    355	signal = sp8870_readreg (state, 0x0303);
    356	if (signal < 0)
    357		return -EIO;
    358
    359	if (signal > 0x0F)
    360		*fe_status |= FE_HAS_SIGNAL;
    361	if (status & 0x08)
    362		*fe_status |= FE_HAS_SYNC;
    363	if (status & 0x04)
    364		*fe_status |= FE_HAS_LOCK | FE_HAS_CARRIER | FE_HAS_VITERBI;
    365
    366	return 0;
    367}
    368
    369static int sp8870_read_ber (struct dvb_frontend* fe, u32 * ber)
    370{
    371	struct sp8870_state* state = fe->demodulator_priv;
    372	int ret;
    373	u32 tmp;
    374
    375	*ber = 0;
    376
    377	ret = sp8870_readreg(state, 0xC08);
    378	if (ret < 0)
    379		return -EIO;
    380
    381	tmp = ret & 0x3F;
    382
    383	ret = sp8870_readreg(state, 0xC07);
    384	if (ret < 0)
    385		return -EIO;
    386
    387	tmp = ret << 6;
    388	if (tmp >= 0x3FFF0)
    389		tmp = ~0;
    390
    391	*ber = tmp;
    392
    393	return 0;
    394}
    395
    396static int sp8870_read_signal_strength(struct dvb_frontend* fe,  u16 * signal)
    397{
    398	struct sp8870_state* state = fe->demodulator_priv;
    399	int ret;
    400	u16 tmp;
    401
    402	*signal = 0;
    403
    404	ret = sp8870_readreg (state, 0x306);
    405	if (ret < 0)
    406		return -EIO;
    407
    408	tmp = ret << 8;
    409
    410	ret = sp8870_readreg (state, 0x303);
    411	if (ret < 0)
    412		return -EIO;
    413
    414	tmp |= ret;
    415
    416	if (tmp)
    417		*signal = 0xFFFF - tmp;
    418
    419	return 0;
    420}
    421
    422static int sp8870_read_uncorrected_blocks (struct dvb_frontend* fe, u32* ublocks)
    423{
    424	struct sp8870_state* state = fe->demodulator_priv;
    425	int ret;
    426
    427	*ublocks = 0;
    428
    429	ret = sp8870_readreg(state, 0xC0C);
    430	if (ret < 0)
    431		return -EIO;
    432
    433	if (ret == 0xFFFF)
    434		ret = ~0;
    435
    436	*ublocks = ret;
    437
    438	return 0;
    439}
    440
    441/* number of trials to recover from lockup */
    442#define MAXTRIALS 5
    443/* maximum checks for data valid signal */
    444#define MAXCHECKS 100
    445
    446/* only for debugging: counter for detected lockups */
    447static int lockups;
    448/* only for debugging: counter for channel switches */
    449static int switches;
    450
    451static int sp8870_set_frontend(struct dvb_frontend *fe)
    452{
    453	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
    454	struct sp8870_state* state = fe->demodulator_priv;
    455
    456	/*
    457	    The firmware of the sp8870 sometimes locks up after setting frontend parameters.
    458	    We try to detect this by checking the data valid signal.
    459	    If it is not set after MAXCHECKS we try to recover the lockup by setting
    460	    the frontend parameters again.
    461	*/
    462
    463	int err = 0;
    464	int valid = 0;
    465	int trials = 0;
    466	int check_count = 0;
    467
    468	dprintk("%s: frequency = %i\n", __func__, p->frequency);
    469
    470	for (trials = 1; trials <= MAXTRIALS; trials++) {
    471
    472		err = sp8870_set_frontend_parameters(fe);
    473		if (err)
    474			return err;
    475
    476		for (check_count = 0; check_count < MAXCHECKS; check_count++) {
    477//			valid = ((sp8870_readreg(i2c, 0x0200) & 4) == 0);
    478			valid = sp8870_read_data_valid_signal(state);
    479			if (valid) {
    480				dprintk("%s: delay = %i usec\n",
    481					__func__, check_count * 10);
    482				break;
    483			}
    484			udelay(10);
    485		}
    486		if (valid)
    487			break;
    488	}
    489
    490	if (!valid) {
    491		printk("%s: firmware crash!!!!!!\n", __func__);
    492		return -EIO;
    493	}
    494
    495	if (debug) {
    496		if (valid) {
    497			if (trials > 1) {
    498				printk("%s: firmware lockup!!!\n", __func__);
    499				printk("%s: recovered after %i trial(s))\n",  __func__, trials - 1);
    500				lockups++;
    501			}
    502		}
    503		switches++;
    504		printk("%s: switches = %i lockups = %i\n", __func__, switches, lockups);
    505	}
    506
    507	return 0;
    508}
    509
    510static int sp8870_sleep(struct dvb_frontend* fe)
    511{
    512	struct sp8870_state* state = fe->demodulator_priv;
    513
    514	// tristate TS output and disable interface pins
    515	return sp8870_writereg(state, 0xC18, 0x000);
    516}
    517
    518static int sp8870_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
    519{
    520	fesettings->min_delay_ms = 350;
    521	fesettings->step_size = 0;
    522	fesettings->max_drift = 0;
    523	return 0;
    524}
    525
    526static int sp8870_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
    527{
    528	struct sp8870_state* state = fe->demodulator_priv;
    529
    530	if (enable) {
    531		return sp8870_writereg(state, 0x206, 0x001);
    532	} else {
    533		return sp8870_writereg(state, 0x206, 0x000);
    534	}
    535}
    536
    537static void sp8870_release(struct dvb_frontend* fe)
    538{
    539	struct sp8870_state* state = fe->demodulator_priv;
    540	kfree(state);
    541}
    542
    543static const struct dvb_frontend_ops sp8870_ops;
    544
    545struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
    546				   struct i2c_adapter* i2c)
    547{
    548	struct sp8870_state* state = NULL;
    549
    550	/* allocate memory for the internal state */
    551	state = kzalloc(sizeof(struct sp8870_state), GFP_KERNEL);
    552	if (state == NULL) goto error;
    553
    554	/* setup the state */
    555	state->config = config;
    556	state->i2c = i2c;
    557	state->initialised = 0;
    558
    559	/* check if the demod is there */
    560	if (sp8870_readreg(state, 0x0200) < 0) goto error;
    561
    562	/* create dvb_frontend */
    563	memcpy(&state->frontend.ops, &sp8870_ops, sizeof(struct dvb_frontend_ops));
    564	state->frontend.demodulator_priv = state;
    565	return &state->frontend;
    566
    567error:
    568	kfree(state);
    569	return NULL;
    570}
    571
    572static const struct dvb_frontend_ops sp8870_ops = {
    573	.delsys = { SYS_DVBT },
    574	.info = {
    575		.name			= "Spase SP8870 DVB-T",
    576		.frequency_min_hz	= 470 * MHz,
    577		.frequency_max_hz	= 860 * MHz,
    578		.frequency_stepsize_hz	= 166666,
    579		.caps			= FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
    580					  FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 |
    581					  FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
    582					  FE_CAN_QPSK | FE_CAN_QAM_16 |
    583					  FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
    584					  FE_CAN_HIERARCHY_AUTO |  FE_CAN_RECOVER
    585	},
    586
    587	.release = sp8870_release,
    588
    589	.init = sp8870_init,
    590	.sleep = sp8870_sleep,
    591	.i2c_gate_ctrl = sp8870_i2c_gate_ctrl,
    592
    593	.set_frontend = sp8870_set_frontend,
    594	.get_tune_settings = sp8870_get_tune_settings,
    595
    596	.read_status = sp8870_read_status,
    597	.read_ber = sp8870_read_ber,
    598	.read_signal_strength = sp8870_read_signal_strength,
    599	.read_ucblocks = sp8870_read_uncorrected_blocks,
    600};
    601
    602module_param(debug, int, 0644);
    603MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
    604
    605MODULE_DESCRIPTION("Spase SP8870 DVB-T Demodulator driver");
    606MODULE_AUTHOR("Juergen Peitz");
    607MODULE_LICENSE("GPL");
    608
    609EXPORT_SYMBOL(sp8870_attach);