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

ddbridge-sx8.c (12251B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * ddbridge-sx8.c: Digital Devices MAX SX8 driver
      4 *
      5 * Copyright (C) 2018 Digital Devices GmbH
      6 *                    Marcus Metzler <mocm@metzlerbros.de>
      7 *                    Ralph Metzler <rjkm@metzlerbros.de>
      8 *
      9 * This program is free software; you can redistribute it and/or
     10 * modify it under the terms of the GNU General Public License
     11 * version 2 only, as published by the Free Software Foundation.
     12 *
     13 * This program is distributed in the hope that it will be useful,
     14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     16 * GNU General Public License for more details.
     17 */
     18
     19#include "ddbridge.h"
     20#include "ddbridge-io.h"
     21#include "ddbridge-mci.h"
     22
     23static const u32 MCLK = (1550000000 / 12);
     24static const u32 MAX_LDPC_BITRATE = (720000000);
     25static const u32 MAX_DEMOD_LDPC_BITRATE = (1550000000 / 6);
     26
     27#define SX8_TUNER_NUM 4
     28#define SX8_DEMOD_NUM 8
     29#define SX8_DEMOD_NONE 0xff
     30
     31struct sx8_base {
     32	struct mci_base      mci_base;
     33
     34	u8                   tuner_use_count[SX8_TUNER_NUM];
     35	u32                  gain_mode[SX8_TUNER_NUM];
     36
     37	u32                  used_ldpc_bitrate[SX8_DEMOD_NUM];
     38	u8                   demod_in_use[SX8_DEMOD_NUM];
     39	u32                  iq_mode;
     40	u32                  burst_size;
     41	u32                  direct_mode;
     42};
     43
     44struct sx8 {
     45	struct mci           mci;
     46
     47	int                  first_time_lock;
     48	int                  started;
     49	struct mci_result    signal_info;
     50
     51	u32                  bb_mode;
     52	u32                  local_frequency;
     53};
     54
     55static void release(struct dvb_frontend *fe)
     56{
     57	struct sx8 *state = fe->demodulator_priv;
     58	struct mci_base *mci_base = state->mci.base;
     59
     60	mci_base->count--;
     61	if (mci_base->count == 0) {
     62		list_del(&mci_base->mci_list);
     63		kfree(mci_base);
     64	}
     65	kfree(state);
     66}
     67
     68static int get_info(struct dvb_frontend *fe)
     69{
     70	int stat;
     71	struct sx8 *state = fe->demodulator_priv;
     72	struct mci_command cmd;
     73
     74	memset(&cmd, 0, sizeof(cmd));
     75	cmd.command = MCI_CMD_GETSIGNALINFO;
     76	cmd.demod = state->mci.demod;
     77	stat = ddb_mci_cmd(&state->mci, &cmd, &state->signal_info);
     78	return stat;
     79}
     80
     81static int get_snr(struct dvb_frontend *fe)
     82{
     83	struct sx8 *state = fe->demodulator_priv;
     84	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
     85
     86	p->cnr.len = 1;
     87	p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
     88	p->cnr.stat[0].svalue =
     89		(s64)state->signal_info.dvbs2_signal_info.signal_to_noise
     90		     * 10;
     91	return 0;
     92}
     93
     94static int get_strength(struct dvb_frontend *fe)
     95{
     96	struct sx8 *state = fe->demodulator_priv;
     97	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
     98	s32 str;
     99
    100	str = 100000 -
    101	      (state->signal_info.dvbs2_signal_info.channel_power
    102	       * 10 + 108750);
    103	p->strength.len = 1;
    104	p->strength.stat[0].scale = FE_SCALE_DECIBEL;
    105	p->strength.stat[0].svalue = str;
    106	return 0;
    107}
    108
    109static int read_status(struct dvb_frontend *fe, enum fe_status *status)
    110{
    111	int stat;
    112	struct sx8 *state = fe->demodulator_priv;
    113	struct mci_command cmd;
    114	struct mci_result res;
    115
    116	cmd.command = MCI_CMD_GETSTATUS;
    117	cmd.demod = state->mci.demod;
    118	stat = ddb_mci_cmd(&state->mci, &cmd, &res);
    119	if (stat)
    120		return stat;
    121	*status = 0x00;
    122	get_info(fe);
    123	get_strength(fe);
    124	if (res.status == SX8_DEMOD_WAIT_MATYPE)
    125		*status = 0x0f;
    126	if (res.status == SX8_DEMOD_LOCKED) {
    127		*status = 0x1f;
    128		get_snr(fe);
    129	}
    130	return stat;
    131}
    132
    133static int mci_set_tuner(struct dvb_frontend *fe, u32 tuner, u32 on)
    134{
    135	struct sx8 *state = fe->demodulator_priv;
    136	struct mci_base *mci_base = state->mci.base;
    137	struct sx8_base *sx8_base = (struct sx8_base *)mci_base;
    138	struct mci_command cmd;
    139
    140	memset(&cmd, 0, sizeof(cmd));
    141	cmd.tuner = state->mci.tuner;
    142	cmd.command = on ? SX8_CMD_INPUT_ENABLE : SX8_CMD_INPUT_DISABLE;
    143	cmd.sx8_input_enable.flags = sx8_base->gain_mode[state->mci.tuner];
    144	return ddb_mci_cmd(&state->mci, &cmd, NULL);
    145}
    146
    147static int stop(struct dvb_frontend *fe)
    148{
    149	struct sx8 *state = fe->demodulator_priv;
    150	struct mci_base *mci_base = state->mci.base;
    151	struct sx8_base *sx8_base = (struct sx8_base *)mci_base;
    152	struct mci_command cmd;
    153	u32 input = state->mci.tuner;
    154
    155	memset(&cmd, 0, sizeof(cmd));
    156	if (state->mci.demod != SX8_DEMOD_NONE) {
    157		cmd.command = MCI_CMD_STOP;
    158		cmd.demod = state->mci.demod;
    159		ddb_mci_cmd(&state->mci, &cmd, NULL);
    160		if (sx8_base->iq_mode) {
    161			cmd.command = SX8_CMD_DISABLE_IQOUTPUT;
    162			cmd.demod = state->mci.demod;
    163			cmd.output = 0;
    164			ddb_mci_cmd(&state->mci, &cmd, NULL);
    165			ddb_mci_config(&state->mci, SX8_TSCONFIG_MODE_NORMAL);
    166		}
    167	}
    168	mutex_lock(&mci_base->tuner_lock);
    169	sx8_base->tuner_use_count[input]--;
    170	if (!sx8_base->tuner_use_count[input])
    171		mci_set_tuner(fe, input, 0);
    172	if (state->mci.demod < SX8_DEMOD_NUM) {
    173		sx8_base->demod_in_use[state->mci.demod] = 0;
    174		state->mci.demod = SX8_DEMOD_NONE;
    175	}
    176	sx8_base->used_ldpc_bitrate[state->mci.nr] = 0;
    177	sx8_base->iq_mode = 0;
    178	mutex_unlock(&mci_base->tuner_lock);
    179	state->started = 0;
    180	return 0;
    181}
    182
    183static int start(struct dvb_frontend *fe, u32 flags, u32 modmask, u32 ts_config)
    184{
    185	struct sx8 *state = fe->demodulator_priv;
    186	struct mci_base *mci_base = state->mci.base;
    187	struct sx8_base *sx8_base = (struct sx8_base *)mci_base;
    188	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
    189	u32 used_ldpc_bitrate = 0, free_ldpc_bitrate;
    190	u32 used_demods = 0;
    191	struct mci_command cmd;
    192	u32 input = state->mci.tuner;
    193	u32 bits_per_symbol = 0;
    194	int i = -1, stat = 0;
    195
    196	if (p->symbol_rate >= (MCLK / 2))
    197		flags &= ~1;
    198	if ((flags & 3) == 0)
    199		return -EINVAL;
    200
    201	if (flags & 2) {
    202		u32 tmp = modmask;
    203
    204		bits_per_symbol = 1;
    205		while (tmp & 1) {
    206			tmp >>= 1;
    207			bits_per_symbol++;
    208		}
    209	}
    210
    211	mutex_lock(&mci_base->tuner_lock);
    212	if (sx8_base->iq_mode) {
    213		stat = -EBUSY;
    214		goto unlock;
    215	}
    216
    217	if (sx8_base->direct_mode) {
    218		if (p->symbol_rate >= MCLK / 2) {
    219			if (state->mci.nr < 4)
    220				i = state->mci.nr;
    221		} else {
    222			i = state->mci.nr;
    223		}
    224	} else {
    225		for (i = 0; i < SX8_DEMOD_NUM; i++) {
    226			used_ldpc_bitrate += sx8_base->used_ldpc_bitrate[i];
    227			if (sx8_base->demod_in_use[i])
    228				used_demods++;
    229		}
    230		if (used_ldpc_bitrate >= MAX_LDPC_BITRATE ||
    231		    ((ts_config & SX8_TSCONFIG_MODE_MASK) >
    232		     SX8_TSCONFIG_MODE_NORMAL && used_demods > 0)) {
    233			stat = -EBUSY;
    234			goto unlock;
    235		}
    236		free_ldpc_bitrate = MAX_LDPC_BITRATE - used_ldpc_bitrate;
    237		if (free_ldpc_bitrate > MAX_DEMOD_LDPC_BITRATE)
    238			free_ldpc_bitrate = MAX_DEMOD_LDPC_BITRATE;
    239
    240		while (p->symbol_rate * bits_per_symbol > free_ldpc_bitrate)
    241			bits_per_symbol--;
    242		if (bits_per_symbol < 2) {
    243			stat = -EBUSY;
    244			goto unlock;
    245		}
    246
    247		modmask &= ((1 << (bits_per_symbol - 1)) - 1);
    248		if (((flags & 0x02) != 0) && modmask == 0) {
    249			stat = -EBUSY;
    250			goto unlock;
    251		}
    252
    253		i = (p->symbol_rate > (MCLK / 2)) ? 3 : 7;
    254		while (i >= 0 && sx8_base->demod_in_use[i])
    255			i--;
    256	}
    257
    258	if (i < 0) {
    259		stat = -EBUSY;
    260		goto unlock;
    261	}
    262	sx8_base->demod_in_use[i] = 1;
    263	sx8_base->used_ldpc_bitrate[state->mci.nr] = p->symbol_rate
    264						     * bits_per_symbol;
    265	state->mci.demod = i;
    266
    267	if (!sx8_base->tuner_use_count[input])
    268		mci_set_tuner(fe, input, 1);
    269	sx8_base->tuner_use_count[input]++;
    270	sx8_base->iq_mode = (ts_config > 1);
    271unlock:
    272	mutex_unlock(&mci_base->tuner_lock);
    273	if (stat)
    274		return stat;
    275	memset(&cmd, 0, sizeof(cmd));
    276
    277	if (sx8_base->iq_mode) {
    278		cmd.command = SX8_CMD_ENABLE_IQOUTPUT;
    279		cmd.demod = state->mci.demod;
    280		cmd.output = 0;
    281		ddb_mci_cmd(&state->mci, &cmd, NULL);
    282		ddb_mci_config(&state->mci, ts_config);
    283	}
    284	if (p->stream_id != NO_STREAM_ID_FILTER && p->stream_id != 0x80000000)
    285		flags |= 0x80;
    286	dev_dbg(mci_base->dev, "MCI-%d: tuner=%d demod=%d\n",
    287		state->mci.nr, state->mci.tuner, state->mci.demod);
    288	cmd.command = MCI_CMD_SEARCH_DVBS;
    289	cmd.dvbs2_search.flags = flags;
    290	cmd.dvbs2_search.s2_modulation_mask = modmask;
    291	cmd.dvbs2_search.retry = 2;
    292	cmd.dvbs2_search.frequency = p->frequency * 1000;
    293	cmd.dvbs2_search.symbol_rate = p->symbol_rate;
    294	cmd.dvbs2_search.scrambling_sequence_index =
    295		p->scrambling_sequence_index | 0x80000000;
    296	cmd.dvbs2_search.input_stream_id =
    297		(p->stream_id != NO_STREAM_ID_FILTER) ? p->stream_id : 0;
    298	cmd.tuner = state->mci.tuner;
    299	cmd.demod = state->mci.demod;
    300	cmd.output = state->mci.nr;
    301	if (p->stream_id == 0x80000000)
    302		cmd.output |= 0x80;
    303	stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
    304	if (stat)
    305		stop(fe);
    306	return stat;
    307}
    308
    309static int start_iq(struct dvb_frontend *fe, u32 flags, u32 roll_off,
    310		    u32 ts_config)
    311{
    312	struct sx8 *state = fe->demodulator_priv;
    313	struct mci_base *mci_base = state->mci.base;
    314	struct sx8_base *sx8_base = (struct sx8_base *)mci_base;
    315	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
    316	u32 used_demods = 0;
    317	struct mci_command cmd;
    318	u32 input = state->mci.tuner;
    319	int i, stat = 0;
    320
    321	mutex_lock(&mci_base->tuner_lock);
    322	if (sx8_base->iq_mode) {
    323		stat = -EBUSY;
    324		goto unlock;
    325	}
    326	for (i = 0; i < SX8_DEMOD_NUM; i++)
    327		if (sx8_base->demod_in_use[i])
    328			used_demods++;
    329	if (used_demods > 0) {
    330		stat = -EBUSY;
    331		goto unlock;
    332	}
    333	state->mci.demod = 0;
    334	if (!sx8_base->tuner_use_count[input])
    335		mci_set_tuner(fe, input, 1);
    336	sx8_base->tuner_use_count[input]++;
    337	sx8_base->iq_mode = (ts_config > 1);
    338unlock:
    339	mutex_unlock(&mci_base->tuner_lock);
    340	if (stat)
    341		return stat;
    342
    343	memset(&cmd, 0, sizeof(cmd));
    344	cmd.command = SX8_CMD_START_IQ;
    345	cmd.sx8_start_iq.flags = flags;
    346	cmd.sx8_start_iq.roll_off = roll_off;
    347	cmd.sx8_start_iq.frequency = p->frequency * 1000;
    348	cmd.sx8_start_iq.symbol_rate = p->symbol_rate;
    349	cmd.tuner = state->mci.tuner;
    350	cmd.demod = state->mci.demod;
    351	stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
    352	if (stat)
    353		stop(fe);
    354	ddb_mci_config(&state->mci, ts_config);
    355	return stat;
    356}
    357
    358static int set_parameters(struct dvb_frontend *fe)
    359{
    360	int stat = 0;
    361	struct sx8 *state = fe->demodulator_priv;
    362	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
    363	u32 ts_config = SX8_TSCONFIG_MODE_NORMAL, iq_mode = 0, isi;
    364
    365	if (state->started)
    366		stop(fe);
    367
    368	isi = p->stream_id;
    369	if (isi != NO_STREAM_ID_FILTER)
    370		iq_mode = (isi & 0x30000000) >> 28;
    371
    372	if (iq_mode)
    373		ts_config = (SX8_TSCONFIG_TSHEADER | SX8_TSCONFIG_MODE_IQ);
    374	if (iq_mode < 3) {
    375		u32 mask;
    376
    377		switch (p->modulation) {
    378		/* uncomment whenever these modulations hit the DVB API
    379		 *	case APSK_256:
    380		 *		mask = 0x7f;
    381		 *		break;
    382		 *	case APSK_128:
    383		 *		mask = 0x3f;
    384		 *		break;
    385		 *	case APSK_64:
    386		 *		mask = 0x1f;
    387		 *		break;
    388		 */
    389		case APSK_32:
    390			mask = 0x0f;
    391			break;
    392		case APSK_16:
    393			mask = 0x07;
    394			break;
    395		default:
    396			mask = 0x03;
    397			break;
    398		}
    399		stat = start(fe, 3, mask, ts_config);
    400	} else {
    401		stat = start_iq(fe, 0, 4, ts_config);
    402	}
    403	if (!stat) {
    404		state->started = 1;
    405		state->first_time_lock = 1;
    406		state->signal_info.status = SX8_DEMOD_WAIT_SIGNAL;
    407	}
    408
    409	return stat;
    410}
    411
    412static int tune(struct dvb_frontend *fe, bool re_tune,
    413		unsigned int mode_flags,
    414		unsigned int *delay, enum fe_status *status)
    415{
    416	int r;
    417
    418	if (re_tune) {
    419		r = set_parameters(fe);
    420		if (r)
    421			return r;
    422	}
    423	r = read_status(fe, status);
    424	if (r)
    425		return r;
    426
    427	if (*status & FE_HAS_LOCK)
    428		return 0;
    429	*delay = HZ / 10;
    430	return 0;
    431}
    432
    433static enum dvbfe_algo get_algo(struct dvb_frontend *fe)
    434{
    435	return DVBFE_ALGO_HW;
    436}
    437
    438static int set_input(struct dvb_frontend *fe, int input)
    439{
    440	struct sx8 *state = fe->demodulator_priv;
    441	struct mci_base *mci_base = state->mci.base;
    442
    443	if (input >= SX8_TUNER_NUM)
    444		return -EINVAL;
    445
    446	state->mci.tuner = input;
    447	dev_dbg(mci_base->dev, "MCI-%d: input=%d\n", state->mci.nr, input);
    448	return 0;
    449}
    450
    451static struct dvb_frontend_ops sx8_ops = {
    452	.delsys = { SYS_DVBS, SYS_DVBS2 },
    453	.info = {
    454		.name			= "Digital Devices MaxSX8 MCI DVB-S/S2/S2X",
    455		.frequency_min_hz	=  950 * MHz,
    456		.frequency_max_hz	= 2150 * MHz,
    457		.symbol_rate_min	= 100000,
    458		.symbol_rate_max	= 100000000,
    459		.caps			= FE_CAN_INVERSION_AUTO |
    460					  FE_CAN_FEC_AUTO       |
    461					  FE_CAN_QPSK           |
    462					  FE_CAN_2G_MODULATION  |
    463					  FE_CAN_MULTISTREAM,
    464	},
    465	.get_frontend_algo		= get_algo,
    466	.tune				= tune,
    467	.release			= release,
    468	.read_status			= read_status,
    469};
    470
    471static int init(struct mci *mci)
    472{
    473	struct sx8 *state = (struct sx8 *)mci;
    474
    475	state->mci.demod = SX8_DEMOD_NONE;
    476	return 0;
    477}
    478
    479const struct mci_cfg ddb_max_sx8_cfg = {
    480	.type = 0,
    481	.fe_ops = &sx8_ops,
    482	.base_size = sizeof(struct sx8_base),
    483	.state_size = sizeof(struct sx8),
    484	.init = init,
    485	.set_input = set_input,
    486};