1 // SPDX-License-Identifier: GPL-2.0
3 * ddbridge-sx8.c: Digital Devices MAX SX8 driver
5 * Copyright (C) 2018 Digital Devices GmbH
6 * Marcus Metzler <mocm@metzlerbros.de>
7 * Ralph Metzler <rjkm@metzlerbros.de>
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.
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.
20 #include "ddbridge-io.h"
21 #include "ddbridge-mci.h"
23 static const u32 MCLK
= (1550000000 / 12);
24 static const u32 MAX_LDPC_BITRATE
= (720000000);
25 static const u32 MAX_DEMOD_LDPC_BITRATE
= (1550000000 / 6);
27 #define SX8_TUNER_NUM 4
28 #define SX8_DEMOD_NUM 8
29 #define SX8_DEMOD_NONE 0xff
32 struct mci_base mci_base
;
34 u8 tuner_use_count
[SX8_TUNER_NUM
];
35 u32 gain_mode
[SX8_TUNER_NUM
];
37 u32 used_ldpc_bitrate
[SX8_DEMOD_NUM
];
38 u8 demod_in_use
[SX8_DEMOD_NUM
];
49 struct mci_result signal_info
;
55 static void release(struct dvb_frontend
*fe
)
57 struct sx8
*state
= fe
->demodulator_priv
;
58 struct mci_base
*mci_base
= state
->mci
.base
;
61 if (mci_base
->count
== 0) {
62 list_del(&mci_base
->mci_list
);
68 static int get_info(struct dvb_frontend
*fe
)
71 struct sx8
*state
= fe
->demodulator_priv
;
72 struct mci_command cmd
;
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
);
81 static int get_snr(struct dvb_frontend
*fe
)
83 struct sx8
*state
= fe
->demodulator_priv
;
84 struct dtv_frontend_properties
*p
= &fe
->dtv_property_cache
;
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
94 static int get_strength(struct dvb_frontend
*fe
)
96 struct sx8
*state
= fe
->demodulator_priv
;
97 struct dtv_frontend_properties
*p
= &fe
->dtv_property_cache
;
101 (state
->signal_info
.dvbs2_signal_info
.channel_power
104 p
->strength
.stat
[0].scale
= FE_SCALE_DECIBEL
;
105 p
->strength
.stat
[0].svalue
= str
;
109 static int read_status(struct dvb_frontend
*fe
, enum fe_status
*status
)
112 struct sx8
*state
= fe
->demodulator_priv
;
113 struct mci_command cmd
;
114 struct mci_result res
;
116 cmd
.command
= MCI_CMD_GETSTATUS
;
117 cmd
.demod
= state
->mci
.demod
;
118 stat
= ddb_mci_cmd(&state
->mci
, &cmd
, &res
);
124 if (res
.status
== SX8_DEMOD_WAIT_MATYPE
)
126 if (res
.status
== SX8_DEMOD_LOCKED
) {
133 static int mci_set_tuner(struct dvb_frontend
*fe
, u32 tuner
, u32 on
)
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
;
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
);
147 static int stop(struct dvb_frontend
*fe
)
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
;
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
;
164 ddb_mci_cmd(&state
->mci
, &cmd
, NULL
);
165 ddb_mci_config(&state
->mci
, SX8_TSCONFIG_MODE_NORMAL
);
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
;
176 sx8_base
->used_ldpc_bitrate
[state
->mci
.nr
] = 0;
177 sx8_base
->iq_mode
= 0;
178 mutex_unlock(&mci_base
->tuner_lock
);
183 static int start(struct dvb_frontend
*fe
, u32 flags
, u32 modmask
, u32 ts_config
)
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
;
191 struct mci_command cmd
;
192 u32 input
= state
->mci
.tuner
;
193 u32 bits_per_symbol
= 0;
194 int i
= -1, stat
= 0;
196 if (p
->symbol_rate
>= (MCLK
/ 2))
198 if ((flags
& 3) == 0)
211 mutex_lock(&mci_base
->tuner_lock
);
212 if (sx8_base
->iq_mode
) {
217 if (sx8_base
->direct_mode
) {
218 if (p
->symbol_rate
>= MCLK
/ 2) {
219 if (state
->mci
.nr
< 4)
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
])
230 if (used_ldpc_bitrate
>= MAX_LDPC_BITRATE
||
231 ((ts_config
& SX8_TSCONFIG_MODE_MASK
) >
232 SX8_TSCONFIG_MODE_NORMAL
&& used_demods
> 0)) {
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
;
240 while (p
->symbol_rate
* bits_per_symbol
> free_ldpc_bitrate
)
242 if (bits_per_symbol
< 2) {
247 modmask
&= ((1 << (bits_per_symbol
- 1)) - 1);
248 if (((flags
& 0x02) != 0) && modmask
== 0) {
253 i
= (p
->symbol_rate
> (MCLK
/ 2)) ? 3 : 7;
254 while (i
>= 0 && sx8_base
->demod_in_use
[i
])
262 sx8_base
->demod_in_use
[i
] = 1;
263 sx8_base
->used_ldpc_bitrate
[state
->mci
.nr
] = p
->symbol_rate
265 state
->mci
.demod
= i
;
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);
272 mutex_unlock(&mci_base
->tuner_lock
);
275 memset(&cmd
, 0, sizeof(cmd
));
277 if (sx8_base
->iq_mode
) {
278 cmd
.command
= SX8_CMD_ENABLE_IQOUTPUT
;
279 cmd
.demod
= state
->mci
.demod
;
281 ddb_mci_cmd(&state
->mci
, &cmd
, NULL
);
282 ddb_mci_config(&state
->mci
, ts_config
);
284 if (p
->stream_id
!= NO_STREAM_ID_FILTER
&& p
->stream_id
!= 0x80000000)
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)
303 stat
= ddb_mci_cmd(&state
->mci
, &cmd
, NULL
);
309 static int start_iq(struct dvb_frontend
*fe
, u32 flags
, u32 roll_off
,
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
;
317 struct mci_command cmd
;
318 u32 input
= state
->mci
.tuner
;
321 mutex_lock(&mci_base
->tuner_lock
);
322 if (sx8_base
->iq_mode
) {
326 for (i
= 0; i
< SX8_DEMOD_NUM
; i
++)
327 if (sx8_base
->demod_in_use
[i
])
329 if (used_demods
> 0) {
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);
339 mutex_unlock(&mci_base
->tuner_lock
);
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
);
354 ddb_mci_config(&state
->mci
, ts_config
);
358 static int set_parameters(struct dvb_frontend
*fe
)
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
;
369 if (isi
!= NO_STREAM_ID_FILTER
)
370 iq_mode
= (isi
& 0x30000000) >> 28;
373 ts_config
= (SX8_TSCONFIG_TSHEADER
| SX8_TSCONFIG_MODE_IQ
);
377 switch (p
->modulation
) {
378 /* uncomment whenever these modulations hit the DVB API
399 stat
= start(fe
, 3, mask
, ts_config
);
401 u32 flags
= (iq_mode
== 2) ? 1 : 0;
403 stat
= start_iq(fe
, flags
, 4, ts_config
);
407 state
->first_time_lock
= 1;
408 state
->signal_info
.status
= SX8_DEMOD_WAIT_SIGNAL
;
414 static int tune(struct dvb_frontend
*fe
, bool re_tune
,
415 unsigned int mode_flags
,
416 unsigned int *delay
, enum fe_status
*status
)
421 r
= set_parameters(fe
);
425 r
= read_status(fe
, status
);
429 if (*status
& FE_HAS_LOCK
)
435 static enum dvbfe_algo
get_algo(struct dvb_frontend
*fe
)
437 return DVBFE_ALGO_HW
;
440 static int set_input(struct dvb_frontend
*fe
, int input
)
442 struct sx8
*state
= fe
->demodulator_priv
;
443 struct mci_base
*mci_base
= state
->mci
.base
;
445 if (input
>= SX8_TUNER_NUM
)
448 state
->mci
.tuner
= input
;
449 dev_dbg(mci_base
->dev
, "MCI-%d: input=%d\n", state
->mci
.nr
, input
);
453 static struct dvb_frontend_ops sx8_ops
= {
454 .delsys
= { SYS_DVBS
, SYS_DVBS2
},
456 .name
= "Digital Devices MaxSX8 MCI DVB-S/S2/S2X",
457 .frequency_min_hz
= 950 * MHz
,
458 .frequency_max_hz
= 2150 * MHz
,
459 .symbol_rate_min
= 100000,
460 .symbol_rate_max
= 100000000,
461 .caps
= FE_CAN_INVERSION_AUTO
|
464 FE_CAN_2G_MODULATION
|
467 .get_frontend_algo
= get_algo
,
470 .read_status
= read_status
,
473 static int init(struct mci
*mci
)
475 struct sx8
*state
= (struct sx8
*)mci
;
477 state
->mci
.demod
= SX8_DEMOD_NONE
;
481 const struct mci_cfg ddb_max_sx8_cfg
= {
484 .base_size
= sizeof(struct sx8_base
),
485 .state_size
= sizeof(struct sx8
),
487 .set_input
= set_input
,