diff --git a/ddbridge/ddbridge-mci.c b/ddbridge/ddbridge-mci.c index 6fd32b9..3f844a3 100644 --- a/ddbridge/ddbridge-mci.c +++ b/ddbridge/ddbridge-mci.c @@ -47,6 +47,7 @@ struct mci_base { u8 assigned_demod[8]; u32 used_ldpc_bitrate[8]; u8 demod_in_use[8]; + u32 iq_mode; }; struct mci { @@ -58,6 +59,8 @@ struct mci { int first_time_lock; int started; struct mci_result signal_info; + + u32 bb_mode; }; @@ -87,6 +90,17 @@ static int mci_reset(struct mci *state) return 0; } +static int mci_config(struct mci *state, u32 config) +{ + struct ddb_link *link = state->base->link; + + if (link->ids.device != 0x0009) + return -EINVAL; + ddblwritel(link, config, SX8_TSCONFIG); + return 0; +} + + static int _mci_cmd_unlocked(struct mci *state, u32 *cmd, u32 cmd_len, u32 *res, u32 res_len) @@ -217,7 +231,7 @@ static int get_info(struct dvb_frontend *fe) struct mci *state = fe->demodulator_priv; struct mci_command cmd; - cmd.command = SX8_CMD_GETSIGNALINFO; + cmd.command = MCI_CMD_GETSIGNALINFO; cmd.demod = state->demod; stat = mci_cmd(state, &cmd, &state->signal_info); return stat; @@ -231,7 +245,7 @@ static int read_status(struct dvb_frontend *fe, enum fe_status *status) u32 val; struct mci_result *res = (struct mci_result *)&val; - cmd.command = SX8_CMD_GETSTATUS; + cmd.command = MCI_CMD_GETSTATUS; cmd.demod = state->demod; stat = _mci_cmd(state, &cmd, 1, res, 1); if (stat) @@ -250,7 +264,7 @@ static int mci_set_tuner(struct dvb_frontend *fe, u32 tuner, u32 on) memset(&cmd, 0, sizeof(cmd)); cmd.tuner = state->tuner; - cmd.command = on ? SX8_CMD_TUNER_ENABLE : SX8_CMD_TUNER_DISABLE; + cmd.command = on ? SX8_CMD_INPUT_ENABLE : SX8_CMD_INPUT_DISABLE; return mci_cmd(state, &cmd, NULL); } @@ -260,11 +274,18 @@ static int stop(struct dvb_frontend *fe) struct mci_command cmd; u32 input = state->tuner; + memset(&cmd, 0, sizeof(cmd)); if (state->demod != 0xff) { - memset(&cmd, 0, sizeof(cmd)); + cmd.command = MCI_CMD_STOP; cmd.demod = state->demod; - cmd.command = SX8_CMD_STOP; mci_cmd(state, &cmd, NULL); + if (state->base->iq_mode) { + cmd.command = MCI_CMD_STOP; + cmd.demod = state->demod; + cmd.output = 0; + mci_cmd(state, &cmd, NULL); + mci_config(state, SX8_TSCONFIG_MODE_NORMAL); + } } mutex_lock(&state->base->tuner_lock); state->base->tuner_use_count[input]--; @@ -274,26 +295,52 @@ static int stop(struct dvb_frontend *fe) state->base->used_ldpc_bitrate[state->nr] = 0; state->demod = 0xff; state->base->assigned_demod[state->nr] = 0xff; + state->base->iq_mode = 0; mutex_unlock(&state->base->tuner_lock); state->started = 0; return 0; } -static int start(struct dvb_frontend *fe) +static int start(struct dvb_frontend *fe, u32 flags, u32 modmask, u32 ts_config) { struct mci *state = fe->demodulator_priv; struct dtv_frontend_properties *p = &fe->dtv_property_cache; static const u32 MAX_DEMOD_LDPC_BITRATE = (1550000000 / 6); u32 used_ldpc_bitrate = 0, free_ldpc_bitrate; + u32 used_demods = 0; struct mci_command cmd; u32 input = state->tuner; - u32 bits_per_symbol = 3; + u32 bits_per_symbol = 0; int i, stat = 0; + + if (p->symbol_rate >= MCLK / 2) + flags &= ~1; + if ((flags & 3) == 0) + return -EINVAL; + + if (flags & 2) { + u32 tmp = modmask; + + bits_per_symbol = 1; + while (tmp & 1) { + tmp >>= 1; + bits_per_symbol++; + } + } mutex_lock(&state->base->tuner_lock); - for (i = 0; i < 8; i++) + if (state->base->iq_mode) { + stat = -EBUSY; + goto unlock; + } + for (i = 0; i < 8; i++) { used_ldpc_bitrate += state->base->used_ldpc_bitrate[i]; - if (used_ldpc_bitrate >= MAX_LDPC_BITRATE) { + if (state->base->demod_in_use[i]) + used_demods++; + } + if ((used_ldpc_bitrate >= MAX_LDPC_BITRATE) || + ((ts_config & SX8_TSCONFIG_MODE_MASK) > + SX8_TSCONFIG_MODE_NORMAL && used_demods > 0)) { stat = -EBUSY; goto unlock; } @@ -301,10 +348,9 @@ static int start(struct dvb_frontend *fe) if (free_ldpc_bitrate > MAX_DEMOD_LDPC_BITRATE) free_ldpc_bitrate = MAX_DEMOD_LDPC_BITRATE; - while (p->symbol_rate * bits_per_symbol > MAX_DEMOD_LDPC_BITRATE) + while (p->symbol_rate * bits_per_symbol > free_ldpc_bitrate) bits_per_symbol--; - - if (bits_per_symbol < 2) { + if (bits_per_symbol < 2) { stat = -EBUSY; goto unlock; } @@ -322,28 +368,84 @@ static int start(struct dvb_frontend *fe) if (!state->base->tuner_use_count[input]) mci_set_tuner(fe, input, 1); state->base->tuner_use_count[input]++; + state->base->iq_mode = (ts_config > 1); unlock: mutex_unlock(&state->base->tuner_lock); if (stat) return stat; - + memset(&cmd, 0, sizeof(cmd)); + + if (state->base->iq_mode) { + cmd.command = SX8_CMD_SELECT_IQOUT; + cmd.demod = state->demod; + cmd.output = 0; + mci_cmd(state, &cmd, NULL); + mci_config(state, ts_config); + } printk("frontend %u: tuner=%u demod=%u\n", state->nr, state->tuner, state->demod); - cmd.command = SX8_CMD_SEARCH; - cmd.dvbs2_search.flags = 3; /* S1 + S2 */ -#if 1 - /* Enable all Modcods up to bits_per_symbol */ - cmd.dvbs2_search.s2_modulation_mask = (1 << (bits_per_symbol - 1)) - 1; -#else - /* Enable Modcods matching bits_per_symbol */ - cmd.dvbs2_search.s2_modulation_mask = (1 << (bits_per_symbol - 2)); -#endif + cmd.command = MCI_CMD_SEARCH_DVBS; + cmd.dvbs2_search.flags = flags; + cmd.dvbs2_search.s2_modulation_mask = modmask & ((1 << (bits_per_symbol - 1)) - 1); cmd.dvbs2_search.retry = 255; /* forever */ cmd.dvbs2_search.frequency = p->frequency * 1000; cmd.dvbs2_search.symbol_rate = p->symbol_rate; + cmd.dvbs2_search.scrambling_sequence_index = + (p->pls != NO_SCRAMBLING_CODE) ? p->pls : 0; + cmd.dvbs2_search.input_stream_id = + (p->stream_id != NO_STREAM_ID_FILTER) ? p->stream_id : 0; cmd.tuner = state->tuner; cmd.demod = state->demod; cmd.output = state->nr; stat = mci_cmd(state, &cmd, NULL); + if (stat) + stop(fe); + return stat; +} + + +static int start_iq(struct dvb_frontend *fe, u32 ts_config) +{ + struct mci *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + static const u32 MAX_DEMOD_LDPC_BITRATE = (1550000000 / 6); + u32 used_ldpc_bitrate = 0, free_ldpc_bitrate; + u32 used_demods = 0; + struct mci_command cmd; + u32 input = state->tuner; + int i, stat = 0; + + mutex_lock(&state->base->tuner_lock); + if (state->base->iq_mode) { + stat = -EBUSY; + goto unlock; + } + for (i = 0; i < 8; i++) + if (state->base->demod_in_use[i]) + used_demods++; + if (used_demods > 0) { + stat = -EBUSY; + goto unlock; + } + state->demod = state->base->assigned_demod[state->nr] = 0; + if (!state->base->tuner_use_count[input]) + mci_set_tuner(fe, input, 1); + state->base->tuner_use_count[input]++; + state->base->iq_mode = (ts_config > 1); +unlock: + mutex_unlock(&state->base->tuner_lock); + if (stat) + return stat; + + cmd.command = SX8_CMD_START_IQ; + cmd.dvbs2_search.frequency = p->frequency * 1000; + cmd.dvbs2_search.symbol_rate = p->symbol_rate; + cmd.tuner = state->tuner; + cmd.demod = state->demod; + cmd.output = 7; + mci_config(state, ts_config); + stat = mci_cmd(state, &cmd, NULL); + if (stat) + stop(fe); return stat; } @@ -351,10 +453,39 @@ static int set_parameters(struct dvb_frontend *fe) { int stat = 0; struct mci *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + u32 ts_config, iq_mode = 0, isi; if (state->started) stop(fe); - stat = start(fe); + isi = p->stream_id; + if (isi != NO_STREAM_ID_FILTER) { + iq_mode = (isi & 0x30000000) >> 28; + } + switch (iq_mode) { + case 1: + ts_config = (SX8_TSCONFIG_TSHEADER|SX8_TSCONFIG_MODE_IQ); + break; + case 2: + ts_config = (SX8_TSCONFIG_TSHEADER|SX8_TSCONFIG_MODE_IQ); + break; + default: + ts_config = SX8_TSCONFIG_MODE_NORMAL; + break; + } + if (iq_mode != 2) { + u32 flags = 3; + u32 mask = 3; + + if (p->modulation == APSK_16 || + p->modulation == APSK_32) { + flags = 2; + mask = 15; + } + stat = start(fe, flags, mask, ts_config); + } else { + stat = start_iq(fe, ts_config); + } if (!stat) { state->started = 1; state->first_time_lock = 1; diff --git a/ddbridge/ddbridge-mci.h b/ddbridge/ddbridge-mci.h index a287aae..85d5b5f 100644 --- a/ddbridge/ddbridge-mci.h +++ b/ddbridge/ddbridge-mci.h @@ -43,32 +43,49 @@ #define SX8_TSCONFIG_MODE_NORMAL (0x00000001) #define SX8_TSCONFIG_MODE_IQ (0x00000003) +#define SX8_TSCONFIG_TSHEADER (0x00000004) +#define SX8_TSCONFIG_BURST (0x00000008) + +#define SX8_TSCONFIG_BURSTSIZE_MASK (0x00000030) +#define SX8_TSCONFIG_BURSTSIZE_2K (0x00000000) +#define SX8_TSCONFIG_BURSTSIZE_4K (0x00000010) +#define SX8_TSCONFIG_BURSTSIZE_8K (0x00000020) +#define SX8_TSCONFIG_BURSTSIZE_16K (0x00000030) #define SX8_DEMOD_STOPPED (0) +#define SX8_DEMOD_IQ_MODE (1) #define SX8_DEMOD_WAIT_SIGNAL (2) +#define SX8_DEMOD_WAIT_MATYPE (3) #define SX8_DEMOD_TIMEOUT (14) #define SX8_DEMOD_LOCKED (15) -#define SX8_CMD_TUNER_ENABLE (0x01) -#define SX8_CMD_TUNER_DISABLE (0x02) -#define SX8_CMD_SEARCH (0x03) -#define SX8_CMD_GETSTATUS (0x04) -#define SX8_CMD_STOP (0x05) -#define SX8_CMD_GETSIGNALINFO (0x07) +#define MCI_CMD_STOP (0x01) +#define MCI_CMD_GETSTATUS (0x02) +#define MCI_CMD_GETSIGNALINFO (0x03) +#define MCI_CMD_RFPOWER (0x04) -#define SX8_CMD_SELECT_IQOUT (0x10) -#define SX8_CMD_SELECT_TSOUT (0x11) +#define MCI_CMD_SEARCH_DVBS (0x10) -#define SX8_CMD_GET_IQSYMBOL (0x30) +#define MCI_CMD_GET_IQSYMBOL (0x30) + +#define SX8_CMD_INPUT_ENABLE (0x40) +#define SX8_CMD_INPUT_DISABLE (0x41) +#define SX8_CMD_START_IQ (0x42) +#define SX8_CMD_STOP_IQ (0x43) +#define SX8_CMD_SELECT_IQOUT (0x44) +#define SX8_CMD_SELECT_TSOUT (0x45) + +#define SX8_ERROR_UNSUPPORTED (0x80) + +#define SX8_SUCCESS(status) (status < SX8_ERROR_UNSUPPORTED) #define SX8_CMD_DIAG_READ8 (0xE0) #define SX8_CMD_DIAG_READ32 (0xE1) #define SX8_CMD_DIAG_WRITE8 (0xE2) #define SX8_CMD_DIAG_WRITE32 (0xE3) -#define SX8_CMD_DIAG_READV (0xE8) -#define SX8_CMD_DIAG_WRITEV (0xE9) - +#define M4_CMD_DIAG_READRF (0xE8) +#define M4_CMD_DIAG_WRITERF (0xE9) #define M4_CMD_DIAG_READX (0xE0) #define M4_CMD_DIAG_READT (0xE1) @@ -79,9 +96,6 @@ #define M4_CMD_DIAG_WRITERF (0xE9) -#define SX8_ERROR_UNSUPPORTED (0x80) -#define SX8_SUCCESS(status) (status < SX8_ERROR_UNSUPPORTED) - struct mci_command { union { u32 command_word; @@ -97,10 +111,13 @@ struct mci_command { struct { u8 flags; u8 s2_modulation_mask; - u8 rsvd; + u8 rsvd1; u8 retry; u32 frequency; u32 symbol_rate; + u8 input_stream_id; + u8 rsvd2[3]; + u32 scrambling_sequence_index; } dvbs2_search; }; };