blob: fc416cf5253ca7dacee87fb17fb76d081f8b048e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * budget-patch.c: driver for Budget Patch,
3 * hardware modification of DVB-S cards enabling full TS
4 *
5 * Written by Emard <emard@softhome.net>
6 *
7 * Original idea by Roberto Deza <rdeza@unav.es>
8 *
9 * Special thanks to Holger Waechtler, Michael Hunold, Marian Durkovic
10 * and Metzlerbros
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
28 *
29 *
30 * the project's page is at http://www.linuxtv.org/dvb/
31 */
32
33#include "av7110.h"
34#include "av7110_hw.h"
35#include "budget.h"
36#include "stv0299.h"
37#include "ves1x93.h"
38#include "tda8083.h"
39
40#define budget_patch budget
41
42static struct saa7146_extension budget_extension;
43
44MAKE_BUDGET_INFO(ttbp, "TT-Budget/Patch DVB-S 1.x PCI", BUDGET_PATCH);
45//MAKE_BUDGET_INFO(satel,"TT-Budget/Patch SATELCO PCI", BUDGET_TT_HW_DISEQC);
46
47static struct pci_device_id pci_tbl[] = {
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -080048 MAKE_EXTENSION_PCI(ttbp,0x13c2, 0x0000),
Linus Torvalds1da177e2005-04-16 15:20:36 -070049// MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -080050 {
51 .vendor = 0,
52 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070053};
54
55/* those lines are for budget-patch to be tried
56** on a true budget card and observe the
57** behaviour of VSYNC generated by rps1.
58** this code was shamelessly copy/pasted from budget.c
59*/
60static void gpio_Set22K (struct budget *budget, int state)
61{
62 struct saa7146_dev *dev=budget->dev;
63 dprintk(2, "budget: %p\n", budget);
64 saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO));
65}
66
67/* Diseqc functions only for TT Budget card */
68/* taken from the Skyvision DVB driver by
69 Ralph Metzler <rjkm@metzlerbros.de> */
70
71static void DiseqcSendBit (struct budget *budget, int data)
72{
73 struct saa7146_dev *dev=budget->dev;
74 dprintk(2, "budget: %p\n", budget);
75
76 saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
77 udelay(data ? 500 : 1000);
78 saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
79 udelay(data ? 1000 : 500);
80}
81
82static void DiseqcSendByte (struct budget *budget, int data)
83{
84 int i, par=1, d;
85
86 dprintk(2, "budget: %p\n", budget);
87
88 for (i=7; i>=0; i--) {
89 d = (data>>i)&1;
90 par ^= d;
91 DiseqcSendBit(budget, d);
92 }
93
94 DiseqcSendBit(budget, par);
95}
96
97static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst)
98{
99 struct saa7146_dev *dev=budget->dev;
100 int i;
101
102 dprintk(2, "budget: %p\n", budget);
103
104 saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
105 mdelay(16);
106
107 for (i=0; i<len; i++)
108 DiseqcSendByte(budget, msg[i]);
109
110 mdelay(16);
111
112 if (burst!=-1) {
113 if (burst)
114 DiseqcSendByte(budget, 0xff);
115 else {
116 saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
117 udelay(12500);
118 saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
119 }
120 msleep(20);
121 }
122
123 return 0;
124}
125
126/* shamelessly copy/pasted from budget.c
127*/
128static int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
129{
130 struct budget* budget = (struct budget*) fe->dvb->priv;
131
132 switch (tone) {
133 case SEC_TONE_ON:
134 gpio_Set22K (budget, 1);
135 break;
136
137 case SEC_TONE_OFF:
138 gpio_Set22K (budget, 0);
139 break;
140
141 default:
142 return -EINVAL;
143 }
144
145 return 0;
146}
147
148static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
149{
150 struct budget* budget = (struct budget*) fe->dvb->priv;
151
152 SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0);
153
154 return 0;
155}
156
157static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
158{
159 struct budget* budget = (struct budget*) fe->dvb->priv;
160
161 SendDiSEqCMsg (budget, 0, NULL, minicmd);
162
163 return 0;
164}
165
166static int budget_av7110_send_fw_cmd(struct budget_patch *budget, u16* buf, int length)
167{
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800168 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800170 dprintk(2, "budget: %p\n", budget);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800172 for (i = 2; i < length; i++)
173 {
174 ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2*i, 2, (u32) buf[i], 0,0);
175 msleep(5);
176 }
177 if (length)
178 ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, (u32) buf[1], 0,0);
179 else
180 ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, 0, 0,0);
181 msleep(5);
182 ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND, 2, (u32) buf[0], 0,0);
183 msleep(5);
184 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185}
186
187static void av7110_set22k(struct budget_patch *budget, int state)
188{
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800189 u16 buf[2] = {( COMTYPE_AUDIODAC << 8) | (state ? ON22K : OFF22K), 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800191 dprintk(2, "budget: %p\n", budget);
192 budget_av7110_send_fw_cmd(budget, buf, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193}
194
195static int av7110_send_diseqc_msg(struct budget_patch *budget, int len, u8 *msg, int burst)
196{
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800197 int i;
198 u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) | SendDiSEqC),
199 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800201 dprintk(2, "budget: %p\n", budget);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800203 if (len>10)
204 len=10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800206 buf[1] = len+2;
207 buf[2] = len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800209 if (burst != -1)
210 buf[3]=burst ? 0x01 : 0x00;
211 else
212 buf[3]=0xffff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800214 for (i=0; i<len; i++)
215 buf[i+4]=msg[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800217 budget_av7110_send_fw_cmd(budget, buf, 18);
218 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219}
220
221static int budget_patch_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
222{
223 struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
224
225 switch (tone) {
226 case SEC_TONE_ON:
227 av7110_set22k (budget, 1);
228 break;
229
230 case SEC_TONE_OFF:
231 av7110_set22k (budget, 0);
232 break;
233
234 default:
235 return -EINVAL;
236 }
237
238 return 0;
239}
240
241static int budget_patch_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
242{
243 struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
244
245 av7110_send_diseqc_msg (budget, cmd->msg_len, cmd->msg, 0);
246
247 return 0;
248}
249
250static int budget_patch_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
251{
252 struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
253
254 av7110_send_diseqc_msg (budget, 0, NULL, minicmd);
255
256 return 0;
257}
258
259static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
260{
261 struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
262 u8 pwr = 0;
263 u8 buf[4];
264 struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
265 u32 div = (params->frequency + 479500) / 125;
266
267 if (params->frequency > 2000000) pwr = 3;
268 else if (params->frequency > 1800000) pwr = 2;
269 else if (params->frequency > 1600000) pwr = 1;
270 else if (params->frequency > 1200000) pwr = 0;
271 else if (params->frequency >= 1100000) pwr = 1;
272 else pwr = 2;
273
274 buf[0] = (div >> 8) & 0x7f;
275 buf[1] = div & 0xff;
276 buf[2] = ((div & 0x18000) >> 10) | 0x95;
277 buf[3] = (pwr << 6) | 0x30;
278
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800279 // NOTE: since we're using a prescaler of 2, we set the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 // divisor frequency to 62.5kHz and divide by 125 above
281
282 if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
283 return 0;
284}
285
286static struct ves1x93_config alps_bsrv2_config = {
287 .demod_address = 0x08,
288 .xin = 90100000UL,
289 .invert_pwm = 0,
290 .pll_set = alps_bsrv2_pll_set,
291};
292
293static u8 alps_bsru6_inittab[] = {
294 0x01, 0x15,
295 0x02, 0x00,
296 0x03, 0x00,
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800297 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
299 0x06, 0x40, /* DAC not used, set to high impendance mode */
300 0x07, 0x00, /* DAC LSB */
301 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
302 0x09, 0x00, /* FIFO */
303 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
304 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
305 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
306 0x10, 0x3f, // AGC2 0x3d
307 0x11, 0x84,
Oliver Endrissff29d062005-11-08 21:35:43 -0800308 0x12, 0xb9,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 0x15, 0xc9, // lock detector threshold
310 0x16, 0x00,
311 0x17, 0x00,
312 0x18, 0x00,
313 0x19, 0x00,
314 0x1a, 0x00,
315 0x1f, 0x50,
316 0x20, 0x00,
317 0x21, 0x00,
318 0x22, 0x00,
319 0x23, 0x00,
320 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
321 0x29, 0x1e, // 1/2 threshold
322 0x2a, 0x14, // 2/3 threshold
323 0x2b, 0x0f, // 3/4 threshold
324 0x2c, 0x09, // 5/6 threshold
325 0x2d, 0x05, // 7/8 threshold
326 0x2e, 0x01,
327 0x31, 0x1f, // test all FECs
328 0x32, 0x19, // viterbi and synchro search
329 0x33, 0xfc, // rs control
330 0x34, 0x93, // error control
331 0x0f, 0x52,
332 0xff, 0xff
333};
334
335static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
336{
337 u8 aclk = 0;
338 u8 bclk = 0;
339
340 if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
341 else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
342 else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
343 else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
344 else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
345 else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
346
347 stv0299_writereg (fe, 0x13, aclk);
348 stv0299_writereg (fe, 0x14, bclk);
349 stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
350 stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff);
351 stv0299_writereg (fe, 0x21, (ratio ) & 0xf0);
352
353 return 0;
354}
355
Andreas Oberrittercfbfce12005-09-09 13:02:30 -0700356static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 u8 data[4];
359 u32 div;
360 struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
361
362 if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL;
363
364 div = (params->frequency + (125 - 1)) / 125; // round correctly
365 data[0] = (div >> 8) & 0x7f;
366 data[1] = div & 0xff;
367 data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
368 data[3] = 0xC4;
369
370 if (params->frequency > 1530000) data[3] = 0xc0;
371
Andreas Oberrittercfbfce12005-09-09 13:02:30 -0700372 if (i2c_transfer(i2c, &msg, 1) != 1) return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 return 0;
374}
375
376static struct stv0299_config alps_bsru6_config = {
377
378 .demod_address = 0x68,
379 .inittab = alps_bsru6_inittab,
380 .mclk = 88000000UL,
381 .invert = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 .skip_reinit = 0,
383 .lock_output = STV0229_LOCKOUTPUT_1,
384 .volt13_op0_op1 = STV0299_VOLT13_OP1,
385 .min_delay_ms = 100,
386 .set_symbol_rate = alps_bsru6_set_symbol_rate,
387 .pll_set = alps_bsru6_pll_set,
388};
389
390static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
391{
392 struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
393 u32 div;
394 u8 data[4];
395 struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
396
397 div = params->frequency / 125;
398 data[0] = (div >> 8) & 0x7f;
399 data[1] = div & 0xff;
400 data[2] = 0x8e;
401 data[3] = 0x00;
402
403 if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
404 return 0;
405}
406
407static struct tda8083_config grundig_29504_451_config = {
408 .demod_address = 0x68,
409 .pll_set = grundig_29504_451_pll_set,
410};
411
412static void frontend_init(struct budget_patch* budget)
413{
414 switch(budget->dev->pci->subsystem_device) {
415 case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800416 case 0x1013: // SATELCO Multimedia PCI
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417
418 // try the ALPS BSRV2 first of all
419 budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
420 if (budget->dvb_frontend) {
421 budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
422 budget->dvb_frontend->ops->diseqc_send_burst = budget_patch_diseqc_send_burst;
423 budget->dvb_frontend->ops->set_tone = budget_patch_set_tone;
424 break;
425 }
426
427 // try the ALPS BSRU6 now
428 budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
429 if (budget->dvb_frontend) {
430 budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
431 budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
432 budget->dvb_frontend->ops->set_tone = budget_set_tone;
433 break;
434 }
435
436 // Try the grundig 29504-451
437 budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
438 if (budget->dvb_frontend) {
439 budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
440 budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
441 budget->dvb_frontend->ops->set_tone = budget_set_tone;
442 break;
443 }
444 break;
445 }
446
447 if (budget->dvb_frontend == NULL) {
448 printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
449 budget->dev->pci->vendor,
450 budget->dev->pci->device,
451 budget->dev->pci->subsystem_vendor,
452 budget->dev->pci->subsystem_device);
453 } else {
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700454 if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 printk("budget-av: Frontend registration failed!\n");
456 if (budget->dvb_frontend->ops->release)
457 budget->dvb_frontend->ops->release(budget->dvb_frontend);
458 budget->dvb_frontend = NULL;
459 }
460 }
461}
462
463/* written by Emard */
464static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
465{
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800466 struct budget_patch *budget;
467 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 int count = 0;
469 int detected = 0;
470
471#define PATCH_RESET 0
472#define RPS_IRQ 0
473#define HPS_SETUP 0
474#if PATCH_RESET
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800475 saa7146_write(dev, MC1, MASK_31);
476 msleep(40);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477#endif
478#if HPS_SETUP
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800479 // initialize registers. Better to have it like this
480 // than leaving something unconfigured
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 saa7146_write(dev, DD1_STREAM_B, 0);
482 // port B VSYNC at rising edge
483 saa7146_write(dev, DD1_INIT, 0x00000200); // have this in budget-core too!
484 saa7146_write(dev, BRS_CTRL, 0x00000000); // VBI
485
486 // debi config
487 // saa7146_write(dev, DEBI_CONFIG, MASK_30|MASK_28|MASK_18);
488
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800489 // zero all HPS registers
490 saa7146_write(dev, HPS_H_PRESCALE, 0); // r68
491 saa7146_write(dev, HPS_H_SCALE, 0); // r6c
492 saa7146_write(dev, BCS_CTRL, 0); // r70
493 saa7146_write(dev, HPS_V_SCALE, 0); // r60
494 saa7146_write(dev, HPS_V_GAIN, 0); // r64
495 saa7146_write(dev, CHROMA_KEY_RANGE, 0); // r74
496 saa7146_write(dev, CLIP_FORMAT_CTRL, 0); // r78
497 // Set HPS prescaler for port B input
498 saa7146_write(dev, HPS_CTRL, (1<<30) | (0<<29) | (1<<28) | (0<<12) );
499 saa7146_write(dev, MC2,
500 0 * (MASK_08 | MASK_24) | // BRS control
501 0 * (MASK_09 | MASK_25) | // a
502 0 * (MASK_10 | MASK_26) | // b
503 1 * (MASK_06 | MASK_22) | // HPS_CTRL1
504 1 * (MASK_05 | MASK_21) | // HPS_CTRL2
505 0 * (MASK_01 | MASK_15) // DEBI
506 );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507#endif
508 // Disable RPS1 and RPS0
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800509 saa7146_write(dev, MC1, ( MASK_29 | MASK_28));
510 // RPS1 timeout disable
511 saa7146_write(dev, RPS_TOV1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
513 // code for autodetection
514 // will wait for VBI_B event (vertical blank at port B)
515 // and will reset GPIO3 after VBI_B is detected.
516 // (GPIO3 should be raised high by CPU to
517 // test if GPIO3 will generate vertical blank signal
518 // in budget patch GPIO3 is connected to VSYNC_B
519 count = 0;
520#if 0
521 WRITE_RPS1(cpu_to_le32(CMD_UPLOAD |
522 MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 ));
523#endif
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800524 WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_VBI_B));
525 WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
526 WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
527 WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528#if RPS_IRQ
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800529 // issue RPS1 interrupt to increment counter
530 WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
531 // at least a NOP is neede between two interrupts
532 WRITE_RPS1(cpu_to_le32(CMD_NOP));
533 // interrupt again
534 WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535#endif
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800536 WRITE_RPS1(cpu_to_le32(CMD_STOP));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537
538#if RPS_IRQ
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800539 // set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53)
540 // use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled
541 // use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called
542 saa7146_write(dev, EC1SSR, (0x03<<2) | 3 );
543 // set event counter 1 treshold to maximum allowed value (rEC p55)
544 saa7146_write(dev, ECT1R, 0x3fff );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545#endif
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800546 // Fix VSYNC level
547 saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
548 // Set RPS1 Address register to point to RPS code (r108 p42)
549 saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
550 // Enable RPS1, (rFC p33)
551 saa7146_write(dev, MC1, (MASK_13 | MASK_29 ));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
553
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800554 mdelay(50);
555 saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 mdelay(150);
557
558
559 if( (saa7146_read(dev, GPIO_CTRL) & 0x10000000) == 0)
560 detected = 1;
561
562#if RPS_IRQ
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800563 printk("Event Counter 1 0x%04x\n", saa7146_read(dev, EC1R) & 0x3fff );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564#endif
565 // Disable RPS1
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800566 saa7146_write(dev, MC1, ( MASK_29 ));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
568 if(detected == 0)
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800569 printk("budget-patch not detected or saa7146 in non-default state.\n"
570 "try enabling ressetting of 7146 with MASK_31 in MC1 register\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571
572 else
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800573 printk("BUDGET-PATCH DETECTED.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
575
576/* OLD (Original design by Roberto Deza):
577** This code will setup the SAA7146_RPS1 to generate a square
578** wave on GPIO3, changing when a field (TS_HEIGHT/2 "lines" of
579** TS_WIDTH packets) has been acquired on SAA7146_D1B video port;
580** then, this GPIO3 output which is connected to the D1B_VSYNC
581** input, will trigger the acquisition of the alternate field
582** and so on.
583** Currently, the TT_budget / WinTV_Nova cards have two ICs
584** (74HCT4040, LVC74) for the generation of this VSYNC signal,
585** which seems that can be done perfectly without this :-)).
586*/
587
588/* New design (By Emard)
589** this rps1 code will copy internal HS event to GPIO3 pin.
590** GPIO3 is in budget-patch hardware connectd to port B VSYNC
591
592** HS is an internal event of 7146, accessible with RPS
593** and temporarily raised high every n lines
594** (n in defined in the RPS_THRESH1 counter threshold)
595** I think HS is raised high on the beginning of the n-th line
596** and remains high until this n-th line that triggered
597** it is completely received. When the receiption of n-th line
598** ends, HS is lowered.
599
600** To transmit data over DMA, 7146 needs changing state at
601** port B VSYNC pin. Any changing of port B VSYNC will
602** cause some DMA data transfer, with more or less packets loss.
603** It depends on the phase and frequency of VSYNC and
604** the way of 7146 is instructed to trigger on port B (defined
605** in DD1_INIT register, 3rd nibble from the right valid
606** numbers are 0-7, see datasheet)
607**
608** The correct triggering can minimize packet loss,
609** dvbtraffic should give this stable bandwidths:
610** 22k transponder = 33814 kbit/s
611** 27.5k transponder = 38045 kbit/s
612** by experiment it is found that the best results
613** (stable bandwidths and almost no packet loss)
614** are obtained using DD1_INIT triggering number 2
615** (Va at rising edge of VS Fa = HS x VS-failing forced toggle)
616** and a VSYNC phase that occurs in the middle of DMA transfer
617** (about byte 188*512=96256 in the DMA window).
618**
619** Phase of HS is still not clear to me how to control,
620** It just happens to be so. It can be seen if one enables
621** RPS_IRQ and print Event Counter 1 in vpeirq(). Every
622** time RPS_INTERRUPT is called, the Event Counter 1 will
623** increment. That's how the 7146 is programmed to do event
624** counting in this budget-patch.c
625** I *think* HPS setting has something to do with the phase
626** of HS but I cant be 100% sure in that.
627
628** hardware debug note: a working budget card (including budget patch)
629** with vpeirq() interrupt setup in mode "0x90" (every 64K) will
630** generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes
631** and that means 3*25=75 Hz of interrupt freqency, as seen by
632** watch cat /proc/interrupts
633**
634** If this frequency is 3x lower (and data received in the DMA
635** buffer don't start with 0x47, but in the middle of packets,
636** whose lengths appear to be like 188 292 188 104 etc.
637** this means VSYNC line is not connected in the hardware.
638** (check soldering pcb and pins)
639** The same behaviour of missing VSYNC can be duplicated on budget
640** cards, by seting DD1_INIT trigger mode 7 in 3rd nibble.
641*/
642
643 // Setup RPS1 "program" (p35)
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800644 count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645
646
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800647 // Wait Source Line Counter Threshold (p36)
648 WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_HS));
649 // Set GPIO3=1 (p42)
650 WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
651 WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
652 WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTHI<<24));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653#if RPS_IRQ
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800654 // issue RPS1 interrupt
655 WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656#endif
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800657 // Wait reset Source Line Counter Threshold (p36)
658 WRITE_RPS1(cpu_to_le32(CMD_PAUSE | RPS_INV | EVT_HS));
659 // Set GPIO3=0 (p42)
660 WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
661 WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
662 WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663#if RPS_IRQ
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800664 // issue RPS1 interrupt
665 WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666#endif
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800667 // Jump to begin of RPS program (p37)
668 WRITE_RPS1(cpu_to_le32(CMD_JUMP));
669 WRITE_RPS1(cpu_to_le32(dev->d_rps1.dma_handle));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800671 // Fix VSYNC level
672 saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
673 // Set RPS1 Address register to point to RPS code (r108 p42)
674 saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
675 // Set Source Line Counter Threshold, using BRS (rCC p43)
676 // It generates HS event every TS_HEIGHT lines
677 // this is related to TS_WIDTH set in register
678 // NUM_LINE_BYTE3 in budget-core.c. If NUM_LINE_BYTE
679 // low 16 bits are set to TS_WIDTH bytes (TS_WIDTH=2*188
680 //,then RPS_THRESH1
681 // should be set to trigger every TS_HEIGHT (512) lines.
682 //
683 saa7146_write(dev, RPS_THRESH1, (TS_HEIGHT*1) | MASK_12 );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800685 // saa7146_write(dev, RPS_THRESH0, ((TS_HEIGHT/2)<<16) |MASK_28| (TS_HEIGHT/2) |MASK_12 );
686 // Enable RPS1 (rFC p33)
687 saa7146_write(dev, MC1, (MASK_13 | MASK_29));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
689
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800690 if (!(budget = kmalloc (sizeof(struct budget_patch), GFP_KERNEL)))
691 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800693 dprintk(2, "budget: %p\n", budget);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800695 if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) {
696 kfree (budget);
697 return err;
698 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699
700
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800701 dev->ext_priv = budget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700703 budget->dvb_adapter.priv = budget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 frontend_init(budget);
705
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800706 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707}
708
709static int budget_patch_detach (struct saa7146_dev* dev)
710{
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800711 struct budget_patch *budget = (struct budget_patch*) dev->ext_priv;
712 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
714 if (budget->dvb_frontend) dvb_unregister_frontend(budget->dvb_frontend);
715
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800716 err = ttpci_budget_deinit (budget);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800718 kfree (budget);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800720 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721}
722
723static int __init budget_patch_init(void)
724{
725 return saa7146_register_extension(&budget_extension);
726}
727
728static void __exit budget_patch_exit(void)
729{
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800730 saa7146_unregister_extension(&budget_extension);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731}
732
733static struct saa7146_extension budget_extension = {
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800734 .name = "budget_patch dvb\0",
735 .flags = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800737 .module = THIS_MODULE,
738 .pci_tbl = pci_tbl,
739 .attach = budget_patch_attach,
740 .detach = budget_patch_detach,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800742 .irq_mask = MASK_10,
743 .irq_func = ttpci_budget_irq10_handler,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744};
745
746module_init(budget_patch_init);
747module_exit(budget_patch_exit);
748
749MODULE_LICENSE("GPL");
750MODULE_AUTHOR("Emard, Roberto Deza, Holger Waechtler, Michael Hunold, others");
751MODULE_DESCRIPTION("Driver for full TS modified DVB-S SAA7146+AV7110 "
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800752 "based so-called Budget Patch cards");