FreeBSD/Linux Kernel Cross Reference
sys/pc/devtv.c
1 /*
2 * Driver for Bt848 TV tuner.
3 *
4 */
5 #include "u.h"
6 #include "../port/lib.h"
7 #include "mem.h"
8 #include "dat.h"
9 #include "fns.h"
10 #include "../port/error.h"
11 #include "io.h"
12 #include "hcwAMC.h"
13
14 #define max(a, b) (((a) > (b))? (a): (b))
15
16 enum {
17 Qdir = 0,
18 Qsubdir,
19 Qsubbase,
20 Qvdata = Qsubbase,
21 Qadata,
22 Qctl,
23 Qregs,
24
25 Brooktree_vid = 0x109e,
26 Brooktree_848_did = 0x0350,
27 Brooktree_878_did = 0x036E,
28 Intel_vid = 0x8086,
29 Intel_82437_did = 0x122d,
30
31 K = 1024,
32 M = K * K,
33
34 Ntvs = 4,
35
36 Numring = 16,
37
38 ntsc_rawpixels = 910,
39 ntsc_sqpixels = 780, /* Including blanking & inactive */
40 ntsc_hactive = 640,
41 ntsc_vactive = 480,
42 ntsc_clkx1delay = 135, /* Clock ticks. */
43 ntsc_clkx1hactive = 754,
44 ntsc_vdelay = 26, /* # of scan lines. */
45 ntsc_vscale = 0,
46
47 i2c_nostop = 1 << 5,
48 i2c_nos1b = 1 << 4,
49 i2c_timing = 7 << 4,
50 i2c_bt848w3b = 1 << 2,
51 i2c_bt848scl = 1 << 1,
52 i2c_bt848sda = 1 << 0,
53 i2c_scl = i2c_bt848scl,
54 i2c_sda = i2c_bt848sda,
55
56 i2c_miroproee = 0x80, /* MIRO PRO EEPROM */
57 i2c_tea6300 = 0x80,
58 i2c_tda8425 = 0x82,
59 i2c_tda9840 = 0x84,
60 i2c_tda9850 = 0xb6,
61 i2c_haupee = 0xa0, /* Hauppage EEPROM */
62 i2c_stbee = 0xae, /* STB EEPROM */
63 i2c_msp3400 = 0x80,
64
65 i2c_timeout = 1000,
66 i2c_delay = 10,
67
68 Bt848_miropro = 0,
69 Bt848_miro,
70 Bt878_hauppauge,
71
72 /* Bit fields. */
73 iform_muxsel1 = 3 << 5, /* 004 */
74 iform_muxsel0 = 2 << 5,
75 iform_xtselmask = 3 << 3,
76 iform_xtauto = 3 << 3,
77 iform_formatmask = 7 << 0,
78 iform_ntsc = 1 << 0,
79
80 control_ldec = 1 << 5, /* 02C */
81 contrast_100percent = 0xd8, /* 030 */
82
83 vscale_interlaced = 1 << 5, /* 04C */
84
85 adelay_ntsc = 104, /* 060 */
86 bdelay_ntsc = 93, /* 064 */
87 adc_crush = 1 << 0, /* 068 */
88
89 colorfmt_rgb16 = 2 << 4 | 2 << 0, /* 0D4 */
90 colorfmt_YCbCr422 = 8 << 4 | 8 << 0,
91 colorfmt_YCbCr411 = 9 << 4 | 9 << 0,
92 colorctl_gamma = 1 << 4, /* 0D8 */
93 capctl_fullframe = 1 << 4, /* 0DC */
94 capctl_captureodd = 1 << 1,
95 capctl_captureeven = 1 << 0,
96 vbipacksize = 0x190, /* 0E0 */
97
98 intstat_riscstatshift = 28, /* 100 */
99 intstat_i2crack = 1 << 25,
100 intstat_scerr = 1 << 19,
101 intstat_ocerr = 1 << 18,
102 intstat_pabort = 1 << 17,
103 intstat_riperr = 1 << 16,
104 intstat_pperr = 1 << 15,
105 intstat_fdsr = 1 << 14,
106 intstat_ftrgt = 1 << 13,
107 intstat_fbus = 1 << 12,
108 intstat_risci = 1 << 11,
109 intstat_i2cdone = 1 << 8,
110 intstat_vpress = 1 << 5,
111 intstat_hlock = 1 << 4,
112 intstat_vsync = 1 << 1,
113 intstat_fmtchg = 1 << 0,
114 intmask_etbf = 1 << 23, /* 104 */
115
116 gpiodmactl_apwrdn = 1 << 26, /* 10C */
117 gpiodmactl_daes2 = 1 << 13,
118 gpiodmactl_daiomda = 1 << 6,
119 gpiodmactl_pltp23_16 = 2 << 6,
120 gpiodmactl_pltp23_0 = 0 << 6,
121 gpiodmactl_pltp1_16 = 2 << 4,
122 gpiodmactl_pltp1_0 = 0 << 4,
123 gpiodmactl_acapenable = 1 << 4,
124 gpiodmactl_pktp_32 = 3 << 2,
125 gpiodmactl_pktp_0 = 0 << 2,
126 gpiodmactl_riscenable = 1 << 1,
127 gpiodmactl_fifoenable = 1 << 0,
128
129 /* RISC instructions and parameters. */
130 fifo_vre = 0x4,
131 fifo_vro = 0xc,
132 fifo_fm1 = 0x6,
133 fifo_fm3 = 0xe,
134
135 riscirq = 1 << 24,
136 riscwrite = 1 << 28,
137 riscwrite123 = 9 << 28,
138 riscwrite1s23 = 11 << 28,
139 riscwrite_sol = 1 << 27,
140 riscwrite_eol = 1 << 26,
141 riscskip = 0x2 << 28,
142 riscjmp = 0x7 << 28,
143 riscsync = 0x8 << 28,
144 riscsync_resync = 1 << 15,
145 riscsync_vre = fifo_vre << 0,
146 riscsync_vro = fifo_vro << 0,
147 riscsync_fm1 = fifo_fm1 << 0,
148 riscsync_fm3 = fifo_fm3 << 0,
149 risclabelshift_set = 16,
150 risclabelshift_reset = 20,
151
152 AudioTuner = 0,
153 AudioRadio,
154 AudioExtern,
155 AudioIntern,
156 AudioOff,
157 AudioOn,
158
159 asel_tv = 0,
160 asel_radio,
161 asel_mic,
162 asel_smxc,
163
164 Hwbase_ad = 448000,
165
166 msp_dem = 0x10,
167 msp_bbp = 0x12,
168
169 /* Altera definitions. */
170 gpio_altera_data = 1 << 0,
171 gpio_altera_clock = 1 << 20,
172 gpio_altera_nconfig = 1 << 23,
173
174 Ial = 0x140001,
175 Idma = 0x100002,
176
177 Adsp = 0x7fd8,
178 Adsp_verifysystem = 1,
179 Adsp_querysupportplay,
180 Adsp_setstyle,
181 Adsp_setsrate,
182 Adsp_setchannels,
183 Adsp_setresolution,
184 Adsp_setcrcoptions,
185 Adsp_bufenqfor,
186 Adsp_logbuffer,
187 Adsp_startplay,
188 Adsp_stopplay,
189 Adsp_autostop,
190 Adsp_startrecord,
191 Adsp_stoprecord,
192 Adsp_getlastprocessed,
193 Adsp_pause,
194 Adsp_resume,
195 Adsp_setvolume,
196 Adsp_querysupportrecord,
197 Adsp_generalbufenq,
198 Adsp_setdownmixtype,
199 Adsp_setigain,
200 Adsp_setlineout,
201 Adsp_setlangmixtype,
202
203 Kfir_gc = 0,
204 Kfir_dsp_riscmc,
205 Kfir_dsp_risccram,
206 Kfir_dsp_unitmc,
207 Kfir_bsm_mc,
208 Kfir_mux_mc,
209
210 Kfir_devid_gc = 7,
211 Kfir_devid_dsp = 4,
212 Kfir_devid_bsm = 5,
213 Kfir_devid_mux = 8,
214
215 Kfir_200 = 200,
216 Kfir_dev_inst = Kfir_200,
217 Kfir_201 = 201,
218 Kfir_exec = Kfir_201,
219 Kfir_202 = 202,
220 Kfir_adr_eready = 254,
221
222 Kfir_d_eready_encoding = 0,
223 Kfir_d_eready_ready,
224 Kfir_d_eready_test,
225 Kfir_d_eready_stopdetect,
226 Kfir_d_eready_seqend,
227
228 VT_KFIR_OFF = 0,
229 VT_KFIR_ON,
230
231 VT_KFIR_LAYER_II = 1,
232 VT_KFIR_STEREO = 1,
233
234 Gpioinit = 0,
235 Gpiooutput,
236 Gpioinput,
237
238 Srate_5512 = 0,
239 Srate_11025 = 2,
240 Srate_16000 = 3,
241 Srate_22050 = 4,
242 Srate_32000 = 5,
243 Srate_44100 = 6,
244 Srate_48000 = 7,
245
246 };
247
248 typedef struct Variant Variant;
249 struct Variant {
250 ushort vid;
251 ushort did;
252 char *name;
253 };
254
255 typedef struct Bt848 Bt848;
256 struct Bt848 {
257 ulong devstat; /* 000 */
258 ulong iform; /* 004 */
259 ulong tdec; /* 008 */
260 ulong ecrop; /* 00C */
261 ulong evdelaylo; /* 010 */
262 ulong evactivelo; /* 014 */
263 ulong ehdelaylo; /* 018 */
264 ulong ehactivelo; /* 01C */
265 ulong ehscalehi; /* 020 */
266 ulong ehscalelo; /* 024 */
267 ulong bright; /* 028 */
268 ulong econtrol; /* 02C */
269 ulong contrastlo; /* 030 */
270 ulong satulo; /* 034 */
271 ulong satvlo; /* 038 */
272 ulong hue; /* 03C */
273 ulong escloop; /* 040 */
274 ulong pad0; /* 044 */
275 ulong oform; /* 048 */
276 ulong evscalehi; /* 04C */
277 ulong evscalelo; /* 050 */
278 ulong test; /* 054 */
279 ulong pad1[2]; /* 058-05C */
280 ulong adelay; /* 060 */
281 ulong bdelay; /* 064 */
282 ulong adc; /* 068 */
283 ulong evtc; /* 06C */
284 ulong pad2[3]; /* 070-078 */
285 ulong sreset; /* 07C */
286 ulong tglb; /* 080 */
287 ulong tgctrl; /* 084 */
288 ulong pad3; /* 088 */
289 ulong ocrop; /* 08C */
290 ulong ovdelaylo; /* 090 */
291 ulong ovactivelo; /* 094 */
292 ulong ohdelaylo; /* 098 */
293 ulong ohactivelo; /* 09C */
294 ulong ohscalehi; /* 0A0 */
295 ulong ohscalelo; /* 0A4 */
296 ulong pad4; /* 0A8 */
297 ulong ocontrol; /* 0AC */
298 ulong pad5[4]; /* 0B0-0BC */
299 ulong oscloop; /* 0C0 */
300 ulong pad6[2]; /* 0C4-0C8 */
301 ulong ovscalehi; /* 0CC */
302 ulong ovscalelo; /* 0D0 */
303 ulong colorfmt; /* 0D4 */
304 ulong colorctl; /* 0D8 */
305 ulong capctl; /* 0DC */
306 ulong vbipacksize; /* 0E0 */
307 ulong vbipackdel; /* 0E4 */
308 ulong fcap; /* 0E8 */
309 ulong ovtc; /* 0EC */
310 ulong pllflo; /* 0F0 */
311 ulong pllfhi; /* 0F4 */
312 ulong pllxci; /* 0F8 */
313 ulong dvsif; /* 0FC */
314 ulong intstat; /* 100 */
315 ulong intmask; /* 104 */
316 ulong pad7; /* 108 */
317 ulong gpiodmactl; /* 10C */
318 ulong i2c; /* 110 */
319 ulong riscstrtadd; /* 114 */
320 ulong gpioouten; /* 118 */
321 ulong gpioreginp; /* 11C */
322 ulong risccount; /* 120 */
323 ulong pad8[55]; /* 124-1FC */
324 ulong gpiodata[64]; /* 200-2FC */
325 };
326
327 #define packetlen i2c
328
329 typedef struct Tuner Tuner;
330 struct Tuner {
331 char *name;
332 ushort freq_vhfh; /* Start frequency */
333 ushort freq_uhf;
334 uchar VHF_L;
335 uchar VHF_H;
336 uchar UHF;
337 uchar cfg;
338 ushort offs;
339 };
340
341 typedef struct Frame Frame;
342 struct Frame {
343 ulong *fstart;
344 ulong *fjmp;
345 uchar *fbase;
346 };
347
348 typedef struct Tv Tv;
349 struct Tv {
350 Lock;
351 Rendez;
352 Bt848 *bt848;
353 Bt848 *bt878; /* Really only audio control registers */
354 Variant *variant;
355 Tuner *tuner;
356 Pcidev *pci;
357 uchar i2ctuneraddr;
358 uchar i2ccmd; /* I2C command */
359 int board; /* What board is this? */
360 ulong cfmt; /* Current color format. */
361 int channel; /* Current channel */
362 Ref fref; /* Copying images? */
363 int nframes; /* Number of frames to capture. */
364 Frame *frames; /* DMA program */
365 int lvframe; /* Last video frame DMAed */
366 uchar *amux; /* Audio multiplexer. */
367 int nablocks; /* Number of audio blocks allocated */
368 int absize; /* Audio block size */
369 int narblocks; /* Number of audio blocks received */
370 ulong *arisc; /* Audio risc bloc */
371 uchar *abuf; /* Audio data buffers */
372 char ainfo[128];
373
374 /* WinTV/PVR stuff. */
375 int msp;
376 Lock kfirlock;
377 ulong i2cstate; /* Last i2c state. */
378 int gpiostate; /* Current GPIO state */
379 ulong alterareg; /* Last used altera register */
380 ulong alteraclock; /* Used to clock the altera */
381 int asrate; /* Audio sample rate */
382 uchar aleft, aright; /* Left and right audio volume */
383 ulong kfirclock;
384 Ref aref; /* Copying audio? */
385 };
386
387 enum {
388 TemicPAL = 0,
389 PhilipsPAL,
390 PhilipsNTSC,
391 PhilipsSECAM,
392 Notuner,
393 PhilipsPALI,
394 TemicNTSC,
395 TemicPALI,
396 Temic4036,
397 AlpsTSBH1,
398 AlpsTSBE1,
399
400 Freqmultiplier = 16,
401 };
402
403 static Tuner tuners[] = {
404 {"Temic PAL", Freqmultiplier * 140.25, Freqmultiplier * 463.25,
405 0x02, 0x04, 0x01, 0x8e, 623 },
406 {"Philips PAL_I", Freqmultiplier * 140.25, Freqmultiplier * 463.25,
407 0xa0, 0x90, 0x30, 0x8e, 623 },
408 {"Philips NTSC", Freqmultiplier * 157.25, Freqmultiplier * 451.25,
409 0xA0, 0x90, 0x30, 0x8e, 732 },
410 {"Philips SECAM", Freqmultiplier * 168.25, Freqmultiplier * 447.25,
411 0xA7, 0x97, 0x37, 0x8e, 623 },
412 {"NoTuner", 0, 0,
413 0x00, 0x00, 0x00, 0x00, 0 },
414 {"Philips PAL", Freqmultiplier * 168.25, Freqmultiplier * 447.25,
415 0xA0, 0x90, 0x30, 0x8e, 623 },
416 {"Temic NTSC", Freqmultiplier * 157.25, Freqmultiplier * 463.25,
417 0x02, 0x04, 0x01, 0x8e, 732 },
418 {"TEMIC PAL_I", Freqmultiplier * 170.00, Freqmultiplier * 450.00,
419 0x02, 0x04, 0x01, 0x8e, 623 },
420 {"Temic 4036 FY5 NTSC", Freqmultiplier * 157.25, Freqmultiplier * 463.25,
421 0xa0, 0x90, 0x30, 0x8e, 732 },
422 {"Alps TSBH1", Freqmultiplier * 137.25, Freqmultiplier * 385.25,
423 0x01, 0x02, 0x08, 0x8e, 732 },
424 {"Alps TSBE1", Freqmultiplier * 137.25, Freqmultiplier * 385.25,
425 0x01, 0x02, 0x08, 0x8e, 732 },
426 };
427
428 static int hp_tuners[] = {
429 Notuner,
430 Notuner,
431 Notuner,
432 Notuner,
433 Notuner,
434 PhilipsNTSC,
435 Notuner,
436 Notuner,
437 PhilipsPAL,
438 PhilipsSECAM,
439 PhilipsNTSC,
440 PhilipsPALI,
441 Notuner,
442 Notuner,
443 TemicPAL,
444 TemicPALI,
445 Notuner,
446 PhilipsSECAM,
447 PhilipsNTSC,
448 PhilipsPALI,
449 Notuner,
450 PhilipsPAL,
451 Notuner,
452 PhilipsNTSC,
453 };
454
455 enum {
456 CMvstart,
457 CMastart,
458 CMastop,
459 CMvgastart,
460 CMvstop,
461 CMchannel,
462 CMcolormode,
463 CMvolume,
464 CMmute,
465 };
466
467 static Cmdtab tvctlmsg[] = {
468 CMvstart, "vstart", 2,
469 CMastart, "astart", 5,
470 CMastop, "astop", 1,
471 CMvgastart, "vgastart", 3,
472 CMvstop, "vstop", 1,
473 CMchannel, "channel", 3,
474 CMcolormode, "colormode", 2,
475 CMvolume, "volume", 3,
476 CMmute, "mute", 1,
477 };
478
479 static Variant variant[] = {
480 { Brooktree_vid, Brooktree_848_did, "Brooktree 848 TV tuner", },
481 { Brooktree_vid, Brooktree_878_did, "Brooktree 878 TV tuner", },
482 };
483
484 static char *boards[] = {
485 "MIRO PRO",
486 "MIRO",
487 "Hauppauge Bt878",
488 };
489
490 static ushort Adspfsample[] = {
491 0x500, 0x700, 0x400, 0x600, 0x300, 0x200, 0x000, 0x100
492 };
493 static ushort Adspstereorates[] = {
494 64, 96, 112, 128, 160, 192, 224, 256, 320, 384
495 };
496
497 static uchar miroamux[] = { 2, 0, 0, 0, 10, 0 };
498 static uchar hauppaugeamux[] = { 0, 1, 2, 3, 4, 0 };
499 static char *nicamstate[] = {
500 "analog", "???", "digital", "bad digital receiption"
501 };
502
503
504 static Tv tvs[Ntvs];
505 static int ntvs;
506
507 static int i2cread(Tv *, uchar, uchar *);
508 static int i2cwrite(Tv *, uchar, uchar, uchar, int);
509 static void tvinterrupt(Ureg *, Tv *);
510 static void vgastart(Tv *, ulong, int);
511 static void vstart(Tv *, int, int, int, int);
512 static void astart(Tv *, char *, uint, uint, uint);
513 static void vstop(Tv *);
514 static void astop(Tv *);
515 static void colormode(Tv *, char *);
516 static void frequency(Tv *, int, int);
517 static int getbitspp(Tv *);
518 static char *getcolormode(ulong);
519 static int mspreset(Tv *);
520 static void i2cscan(Tv *);
521 static int kfirinitialize(Tv *);
522 static void msptune(Tv *);
523 static void mspvolume(Tv *, int, int, int);
524 static void gpioenable(Tv *, ulong, ulong);
525 static void gpiowrite(Tv *, ulong, ulong);
526
527 static void
528 tvinit(void)
529 {
530 Pcidev *pci;
531 ulong intmask;
532
533 /* Test for a triton memory controller. */
534 intmask = 0;
535 if (pcimatch(nil, Intel_vid, Intel_82437_did))
536 intmask = intmask_etbf;
537
538 pci = nil;
539 while ((pci = pcimatch(pci, 0, 0)) != nil) {
540 int i, t;
541 Tv *tv;
542 Bt848 *bt848;
543 ushort hscale, hdelay;
544 uchar v;
545
546 for (i = 0; i != nelem(variant); i++)
547 if (pci->vid == variant[i].vid && pci->did == variant[i].did)
548 break;
549 if (i == nelem(variant))
550 continue;
551
552 if (ntvs >= Ntvs) {
553 print("#V: Too many TV cards found\n");
554 continue;
555 }
556
557 tv = &tvs[ntvs++];
558 tv->variant = &variant[i];
559 tv->pci = pci;
560 tv->bt848 = (Bt848 *)vmap(pci->mem[0].bar & ~0x0F, 4 * K);
561 if (tv->bt848 == nil)
562 panic("#V: Cannot allocate memory for Bt848");
563 bt848 = tv->bt848;
564
565 /* i2c stuff. */
566 if (pci->did >= 878)
567 tv->i2ccmd = 0x83;
568 else
569 tv->i2ccmd = i2c_timing | i2c_bt848scl | i2c_bt848sda;
570
571 t = 0;
572 if (i2cread(tv, i2c_haupee, &v)) {
573 uchar ee[256];
574 Pcidev *pci878;
575 Bt848 *bt878;
576
577 tv->board = Bt878_hauppauge;
578 if (!i2cwrite(tv, i2c_haupee, 0, 0, 0))
579 panic("#V: Cannot write to Hauppauge EEPROM");
580 for (i = 0; i != sizeof ee; i++)
581 if (!i2cread(tv, i2c_haupee + 1, &ee[i]))
582 panic("#V: Cannot read from Hauppauge EEPROM");
583
584 if (ee[9] > sizeof hp_tuners / sizeof hp_tuners[0])
585 panic("#V: Tuner out of range (max %d, this %d)",
586 sizeof hp_tuners / sizeof hp_tuners[0], ee[9]);
587 t = hp_tuners[ee[9]];
588
589 /* Initialize the audio channel. */
590 if ((pci878 = pcimatch(nil, Brooktree_vid, 0x878)) == nil)
591 panic("#V: Unsupported Hauppage board");
592
593 tv->bt878 = bt878 =
594 (Bt848 *)vmap(pci878->mem[0].bar & ~0x0F, 4 * K);
595 if (bt878 == nil)
596 panic("#V: Cannot allocate memory for the Bt878");
597
598 kfirinitialize(tv);
599 // i2cscan(tv);
600 mspreset(tv);
601
602 bt878->gpiodmactl = 0;
603 bt878->intstat = (ulong)-1;
604 intrenable(pci878->intl, (void (*)(Ureg *, void *))tvinterrupt,
605 tv, pci878->tbdf, "tv");
606
607 tv->amux = hauppaugeamux;
608 }
609 else if (i2cread(tv, i2c_stbee, &v)) {
610 USED(t);
611 panic("#V: Cannot deal with STB cards\n");
612 }
613 else if (i2cread(tv, i2c_miroproee, &v)) {
614 tv->board = Bt848_miropro;
615 t = ((bt848->gpiodata[0] >> 10) - 1) & 7;
616 tv->amux = miroamux;
617 }
618 else {
619 tv->board = Bt848_miro;
620 tv->amux = miroamux;
621 t = ((bt848->gpiodata[0] >> 10) - 1) & 7;
622 }
623
624 if (t >= nelem(tuners))
625 t = 4;
626 tv->tuner = &tuners[t];
627 tv->i2ctuneraddr =
628 i2cread(tv, 0xc1, &v)? 0xc0:
629 i2cread(tv, 0xc3, &v)? 0xc2:
630 i2cread(tv, 0xc5, &v)? 0xc4:
631 i2cread(tv, 0xc7, &v)? 0xc6: -1;
632
633 bt848->capctl = capctl_fullframe;
634 bt848->adelay = adelay_ntsc;
635 bt848->bdelay = bdelay_ntsc;
636 bt848->iform = iform_muxsel0|iform_xtauto|iform_ntsc;
637 bt848->vbipacksize = vbipacksize & 0xff;
638 bt848->vbipackdel = (vbipacksize >> 8) & 1;
639
640 // setpll(bt848);
641
642 tv->cfmt = bt848->colorfmt = colorfmt_rgb16;
643
644 hscale = (ntsc_rawpixels * 4096) / ntsc_sqpixels - 4096;
645 hdelay = (ntsc_clkx1delay * ntsc_hactive) / ntsc_clkx1hactive;
646
647 bt848->ovtc = bt848->evtc = 0;
648 bt848->ehscalehi = bt848->ohscalehi = (hscale >> 8) & 0xff;
649 bt848->ehscalelo = bt848->ohscalelo = hscale & 0xff;
650 bt848->evscalehi &= ~0x1f;
651 bt848->ovscalehi &= ~0x1f;
652 bt848->evscalehi |= vscale_interlaced | ((ntsc_vscale >> 8) & 0x1f);
653 bt848->ovscalehi |= vscale_interlaced | (ntsc_vscale >> 8) & 0x1f;
654 bt848->evscalelo = bt848->ovscalelo = ntsc_vscale & 0xff;
655 bt848->ehactivelo = bt848->ohactivelo = ntsc_hactive & 0xff;
656 bt848->ehdelaylo = bt848->ohdelaylo = hdelay & 0xff;
657 bt848->evactivelo = bt848->ovactivelo = ntsc_vactive & 0xff;
658 bt848->evdelaylo = bt848->ovdelaylo = ntsc_vdelay & 0xff;
659 bt848->ecrop = bt848->ocrop =
660 ((ntsc_hactive >> 8) & 0x03) |
661 ((hdelay >> 6) & 0x0C) |
662 ((ntsc_vactive >> 4) & 0x30) |
663 ((ntsc_vdelay >> 2) & 0xC0);
664
665 bt848->colorctl = colorctl_gamma;
666 bt848->capctl = 0;
667 bt848->gpiodmactl = gpiodmactl_pltp23_16 |
668 gpiodmactl_pltp1_16 | gpiodmactl_pktp_32;
669 bt848->gpioreginp = 0;
670 bt848->contrastlo = contrast_100percent;
671 bt848->bright = 16;
672 bt848->adc = (2 << 6) | adc_crush;
673 bt848->econtrol = bt848->ocontrol = control_ldec;
674 bt848->escloop = bt848->oscloop = 0;
675 bt848->intstat = (ulong)-1;
676 bt848->intmask = intmask |
677 intstat_vsync | intstat_scerr | intstat_risci | intstat_ocerr |
678 intstat_vpress | intstat_fmtchg;
679
680
681 if (tv->amux) {
682 gpioenable(tv, ~0xfff, 0xfff);
683 gpiowrite(tv, ~0xfff, tv->amux[AudioRadio]);
684 }
685
686 print("#V%ld: %s (rev %d) (%s/%s) intl %d\n",
687 tv - tvs, tv->variant->name, pci->rid, boards[tv->board],
688 tv->tuner->name, pci->intl);
689
690 intrenable(pci->intl, (void (*)(Ureg *, void *))tvinterrupt,
691 tv, pci->tbdf, "tv");
692 }
693 }
694
695 static Chan*
696 tvattach(char *spec)
697 {
698 return devattach('V', spec);
699 }
700
701 #define TYPE(q) ((int)((q).path & 0xff))
702 #define DEV(q) ((int)(((q).path >> 8) & 0xff))
703 #define QID(d, t) ((((d) & 0xff) << 8) | (t))
704
705 static int
706 tv1gen(Chan *c, int i, Dir *dp)
707 {
708 Qid qid;
709
710 switch (i) {
711 case Qvdata:
712 mkqid(&qid, QID(DEV(c->qid), Qvdata), 0, QTFILE);
713 devdir(c, qid, "video", 0, eve, 0444, dp);
714 return 1;
715 case Qadata:
716 mkqid(&qid, QID(DEV(c->qid), Qadata), 0, QTFILE);
717 devdir(c, qid, "audio", 0, eve, 0444, dp);
718 return 1;
719 case Qctl:
720 mkqid(&qid, QID(DEV(c->qid), Qctl), 0, QTFILE);
721 devdir(c, qid, "ctl", 0, eve, 0444, dp);
722 return 1;
723 case Qregs:
724 mkqid(&qid, QID(DEV(c->qid), Qregs), 0, QTFILE);
725 devdir(c, qid, "regs", 0, eve, 0444, dp);
726 return 1;
727 }
728 return -1;
729 }
730
731 static int
732 tvgen(Chan *c, char *, Dirtab *, int, int i, Dir *dp)
733 {
734 Qid qid;
735 int dev;
736
737 dev = DEV(c->qid);
738 switch (TYPE(c->qid)) {
739 case Qdir:
740 if (i == DEVDOTDOT) {
741 mkqid(&qid, Qdir, 0, QTDIR);
742 devdir(c, qid, "#V", 0, eve, 0555, dp);
743 return 1;
744 }
745
746 if (i >= ntvs)
747 return -1;
748
749 mkqid(&qid, QID(i, Qsubdir), 0, QTDIR);
750 snprint(up->genbuf, sizeof(up->genbuf), "tv%d", i);
751 devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
752 return 1;
753
754 case Qsubdir:
755 if (i == DEVDOTDOT) {
756 mkqid(&qid, QID(dev, Qdir), 0, QTDIR);
757 snprint(up->genbuf, sizeof(up->genbuf), "tv%d", dev);
758 devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
759 return 1;
760 }
761
762 return tv1gen(c, i + Qsubbase, dp);
763
764 case Qvdata:
765 case Qadata:
766 case Qctl:
767 case Qregs:
768 return tv1gen(c, TYPE(c->qid), dp);
769
770 default:
771 return -1;
772 }
773 }
774
775 static Walkqid *
776 tvwalk(Chan *c, Chan *nc, char **name, int nname)
777 {
778 return devwalk(c, nc, name, nname, 0, 0, tvgen);
779 }
780
781 static int
782 tvstat(Chan *c, uchar *db, int n)
783 {
784 return devstat(c, db, n, 0, 0, tvgen);
785 }
786
787 static Chan*
788 tvopen(Chan *c, int omode)
789 {
790 if (omode != OREAD &&
791 TYPE(c->qid) != Qctl && TYPE(c->qid) != Qvdata)
792 error(Eperm);
793
794 switch (TYPE(c->qid)) {
795 case Qdir:
796 return devopen(c, omode, nil, 0, tvgen);
797 case Qadata:
798 if (tvs[DEV(c->qid)].bt878 == nil)
799 error(Enonexist);
800 break;
801 }
802
803 c->mode = openmode(omode);
804 c->flag |= COPEN;
805 c->offset = 0;
806
807 if (TYPE(c->qid) == Qadata)
808 c->aux = nil;
809 return c;
810 }
811
812 static void
813 tvclose(Chan *)
814 {
815 }
816
817 static int
818 audioblock(void *)
819 {
820 return 1;
821 }
822
823 static long
824 tvread(Chan *c, void *a, long n, vlong offset)
825 {
826 static char regs[10 * K];
827 static int regslen;
828 Tv *tv;
829 char *e, *p;
830 uchar *src;
831
832 USED(offset);
833
834 switch(TYPE(c->qid)) {
835 case Qdir:
836 case Qsubdir:
837 return devdirread(c, a, n, 0, 0, tvgen);
838
839 case Qvdata: {
840 int bpf, nb;
841
842 tv = &tvs[DEV(c->qid)];
843 bpf = ntsc_hactive * ntsc_vactive * getbitspp(tv) / 8;
844
845 if (offset >= bpf)
846 return 0;
847
848 nb = n;
849 if (offset + nb > bpf)
850 nb = bpf - offset;
851
852 ilock(tv);
853 if (tv->frames == nil || tv->lvframe >= tv->nframes ||
854 tv->frames[tv->lvframe].fbase == nil) {
855 iunlock(tv);
856 return 0;
857 }
858
859 src = tv->frames[tv->lvframe].fbase;
860 incref(&tv->fref);
861 iunlock(tv);
862
863 memmove(a, src + offset, nb);
864 decref(&tv->fref);
865 return nb;
866 }
867
868 case Qadata: {
869 ulong uablock = (ulong)c->aux, bnum, tvablock;
870 int boffs, nbytes;
871
872 tv = &tvs[DEV(c->qid)];
873 if (tv->bt878 == nil)
874 error("#V: No audio device");
875 if (tv->absize == 0)
876 error("#V: audio not initialized");
877
878 bnum = offset / tv->absize;
879 boffs = offset % tv->absize;
880 nbytes = tv->absize - boffs;
881
882 incref(&tv->aref);
883 for (;;) {
884 tvablock = tv->narblocks; /* Current tv block. */
885
886 if (uablock == 0)
887 uablock = tvablock - 1;
888
889 if (tvablock >= uablock + bnum + tv->narblocks)
890 uablock = tvablock - 1 - bnum;
891
892 if (uablock + bnum == tvablock) {
893 sleep(tv, audioblock, nil);
894 continue;
895 }
896 break;
897 }
898
899 print("uablock %ld, bnum %ld, boffs %d, nbytes %d, tvablock %ld\n",
900 uablock, bnum, boffs, nbytes, tvablock);
901 src = tv->abuf + ((uablock + bnum) % tv->nablocks) * tv->absize;
902 print("copying from %#p (abuf %#p), nbytes %d (block %ld.%ld)\n",
903 src + boffs, tv->abuf, nbytes, uablock, bnum);
904
905 memmove(a, src + boffs, nbytes);
906 decref(&tv->aref);
907
908 uablock += (boffs + nbytes) % tv->absize;
909 c->aux = (void*)uablock;
910
911 return nbytes;
912 }
913
914 case Qctl: {
915 char str[128];
916
917 tv = &tvs[DEV(c->qid)];
918 snprint(str, sizeof str, "%dx%dx%d %s channel %d %s\n",
919 ntsc_hactive, ntsc_vactive, getbitspp(tv),
920 getcolormode(tv->cfmt), tv->channel, tv->ainfo);
921 return readstr(offset, a, strlen(str) + 1, str);
922 }
923
924 case Qregs:
925 if (offset == 0) {
926 Bt848 *bt848;
927 int i;
928
929 tv = &tvs[DEV(c->qid)];
930 bt848 = tv->bt848;
931
932 e = regs + sizeof(regs);
933 p = regs;
934 for (i = 0; i < 0x300 >> 2; i++)
935 p = seprint(p, e, "%.3X %.8ulX\n", i << 2,
936 ((ulong *)bt848)[i]);
937 if (tv->bt878) {
938 bt848 = tv->bt878;
939
940 for (i = 0; i < 0x300 >> 2; i++)
941 p = seprint(p, e, "%.3X %.8ulX\n",
942 i << 2, ((ulong *)bt848)[i]);
943 }
944
945 regslen = p - regs;
946 }
947
948 if (offset >= regslen)
949 return 0;
950 if (offset + n > regslen)
951 n = regslen - offset;
952
953 return readstr(offset, a, n, ®s[offset]);
954
955 default:
956 n = 0;
957 break;
958 }
959 return n;
960 }
961
962 static long
963 tvwrite(Chan *c, void *a, long n, vlong)
964 {
965 Cmdbuf *cb;
966 Cmdtab *ct;
967 Tv *tv;
968
969 tv = &tvs[DEV(c->qid)];
970 switch(TYPE(c->qid)) {
971 case Qctl:
972 cb = parsecmd(a, n);
973 if(waserror()){
974 free(cb);
975 nexterror();
976 }
977 ct = lookupcmd(cb, tvctlmsg, nelem(tvctlmsg));
978 switch (ct->index) {
979 case CMvstart:
980 vstart(tv, (int)strtol(cb->f[1], (char **)nil, 0),
981 ntsc_hactive, ntsc_vactive, ntsc_hactive);
982 break;
983
984 case CMastart:
985 astart(tv, cb->f[1], (uint)strtol(cb->f[2], (char **)nil, 0),
986 (uint)strtol(cb->f[3], (char **)nil, 0),
987 (uint)strtol(cb->f[4], (char **)nil, 0));
988 break;
989
990 case CMastop:
991 astop(tv);
992 break;
993
994 case CMvgastart:
995 vgastart(tv, strtoul(cb->f[1], (char **)nil, 0),
996 (int)strtoul(cb->f[2], (char **)nil, 0));
997 break;
998
999 case CMvstop:
1000 vstop(tv);
1001 break;
1002
1003 case CMchannel:
1004 frequency(tv, (int)strtol(cb->f[1], (char **)nil, 0),
1005 (int)strtol(cb->f[2], (char **)nil, 0));
1006 break;
1007
1008 case CMcolormode:
1009 colormode(tv, cb->f[1]);
1010 break;
1011
1012 case CMvolume:
1013 if (!tv->msp)
1014 error("#V: No volume control");
1015
1016 mspvolume(tv, 0, (int)strtol(cb->f[1], (char **)nil, 0),
1017 (int)strtol(cb->f[2], (char **)nil, 0));
1018 break;
1019
1020 case CMmute:
1021 if (!tv->msp)
1022 error("#V: No volume control");
1023
1024 mspvolume(tv, 1, 0, 0);
1025 break;
1026 }
1027 poperror();
1028 free(cb);
1029 break;
1030
1031 default:
1032 error(Eio);
1033 }
1034 return n;
1035 }
1036
1037 Dev tvdevtab = {
1038 'V',
1039 "tv",
1040
1041 devreset,
1042 tvinit,
1043 devshutdown,
1044 tvattach,
1045 tvwalk,
1046 tvstat,
1047 tvopen,
1048 devcreate,
1049 tvclose,
1050 tvread,
1051 devbread,
1052 tvwrite,
1053 devbwrite,
1054 devremove,
1055 devwstat,
1056 };
1057
1058 static void
1059 tvinterrupt(Ureg *, Tv *tv)
1060 {
1061 Bt848 *bt848 = tv->bt848, *bt878 = tv->bt878;
1062
1063 for (;;) {
1064 ulong vstat, astat;
1065 uchar fnum;
1066
1067 vstat = bt848->intstat;
1068 fnum = (vstat >> intstat_riscstatshift) & 0xf;
1069 vstat &= bt848->intmask;
1070
1071 if (bt878)
1072 astat = bt878->intstat & bt878->intmask;
1073 else
1074 astat = 0;
1075
1076 if (vstat == 0 && astat == 0)
1077 break;
1078
1079 if (astat)
1080 print("vstat %.8luX, astat %.8luX\n", vstat, astat);
1081
1082 bt848->intstat = vstat;
1083 if (bt878)
1084 bt878->intstat = astat;
1085
1086 if ((vstat & intstat_fmtchg) == intstat_fmtchg) {
1087 iprint("int: fmtchg\n");
1088 vstat &= ~intstat_fmtchg;
1089 }
1090
1091 if ((vstat & intstat_vpress) == intstat_vpress) {
1092 // iprint("int: vpress\n");
1093 vstat &= ~intstat_vpress;
1094 }
1095
1096 if ((vstat & intstat_vsync) == intstat_vsync)
1097 vstat &= ~intstat_vsync;
1098
1099 if ((vstat & intstat_scerr) == intstat_scerr) {
1100 iprint("int: scerr\n");
1101 bt848->gpiodmactl &=
1102 ~(gpiodmactl_riscenable|gpiodmactl_fifoenable);
1103 bt848->gpiodmactl |= gpiodmactl_fifoenable;
1104 bt848->gpiodmactl |= gpiodmactl_riscenable;
1105 vstat &= ~intstat_scerr;
1106 }
1107
1108 if ((vstat & intstat_risci) == intstat_risci) {
1109 tv->lvframe = fnum;
1110 vstat &= ~intstat_risci;
1111 }
1112
1113 if ((vstat & intstat_ocerr) == intstat_ocerr) {
1114 iprint("int: ocerr\n");
1115 vstat &= ~intstat_ocerr;
1116 }
1117
1118 if ((vstat & intstat_fbus) == intstat_fbus) {
1119 iprint("int: fbus\n");
1120 vstat &= ~intstat_fbus;
1121 }
1122
1123 if (vstat)
1124 iprint("int: (v) ignored interrupts %.8ulX\n", vstat);
1125
1126 if ((astat & intstat_risci) == intstat_risci) {
1127 tv->narblocks++;
1128 if ((tv->narblocks % 100) == 0)
1129 print("a");
1130 wakeup(tv);
1131 astat &= ~intstat_risci;
1132 }
1133
1134 if ((astat & intstat_fdsr) == intstat_fdsr) {
1135 iprint("int: (a) fdsr\n");
1136 bt848->gpiodmactl &=
1137 ~(gpiodmactl_acapenable |
1138 gpiodmactl_riscenable | gpiodmactl_fifoenable);
1139 astat &= ~intstat_fdsr;
1140 }
1141
1142 if (astat)
1143 iprint("int: (a) ignored interrupts %.8ulX\n", astat);
1144 }
1145 }
1146
1147 static int
1148 i2cread(Tv *tv, uchar off, uchar *v)
1149 {
1150 Bt848 *bt848 = tv->bt848;
1151 ulong intstat;
1152 int i;
1153
1154 bt848->intstat = intstat_i2cdone;
1155 bt848->i2c = (off << 24) | tv->i2ccmd;
1156
1157 intstat = -1;
1158 for (i = 0; i != 1000; i++) {
1159 if ((intstat = bt848->intstat) & intstat_i2cdone)
1160 break;
1161 microdelay(1000);
1162 }
1163
1164 if (i == 1000) {
1165 print("i2cread: timeout\n");
1166 return 0;
1167 }
1168
1169 if ((intstat & intstat_i2crack) == 0)
1170 return 0;
1171
1172 *v = bt848->i2c >> 8;
1173 return 1;
1174 }
1175
1176 static int
1177 i2cwrite(Tv *tv, uchar addr, uchar sub, uchar data, int both)
1178 {
1179 Bt848 *bt848 = tv->bt848;
1180 ulong intstat, d;
1181 int i;
1182
1183 bt848->intstat = intstat_i2cdone;
1184 d = (addr << 24) | (sub << 16) | tv->i2ccmd;
1185 if (both)
1186 d |= (data << 8) | i2c_bt848w3b;
1187 bt848->i2c = d;
1188
1189 intstat = 0;
1190 for (i = 0; i != 1000; i++) {
1191 if ((intstat = bt848->intstat) & intstat_i2cdone)
1192 break;
1193 microdelay(1000);
1194 }
1195
1196 if (i == i2c_timeout) {
1197 print("i2cwrite: timeout\n");
1198 return 0;
1199 }
1200
1201 if ((intstat & intstat_i2crack) == 0)
1202 return 0;
1203
1204 return 1;
1205 }
1206
1207 static ulong *
1208 riscpacked(ulong pa, int fnum, int w, int h, int stride, ulong **lastjmp)
1209 {
1210 ulong *p, *pbase;
1211 int i;
1212
1213 pbase = p = (ulong *)malloc((h + 6) * 2 * sizeof(ulong));
1214 assert(p);
1215
1216 assert(w <= 0x7FF);
1217
1218 *p++ = riscsync | riscsync_resync | riscsync_vre;
1219 *p++ = 0;
1220
1221 *p++ = riscsync | riscsync_fm1;
1222 *p++ = 0;
1223
1224 for (i = 0; i != h / 2; i++) {
1225 *p++ = riscwrite | w | riscwrite_sol | riscwrite_eol;
1226 *p++ = pa + i * 2 * stride;
1227 }
1228
1229 *p++ = riscsync | riscsync_resync | riscsync_vro;
1230 *p++ = 0;
1231
1232 *p++ = riscsync | riscsync_fm1;
1233 *p++ = 0;
1234
1235 for (i = 0; i != h / 2; i++) {
1236 *p++ = riscwrite | w | riscwrite_sol | riscwrite_eol;
1237 *p++ = pa + (i * 2 + 1) * stride;
1238 }
1239
1240 /* reset status. you really need two instructions ;-(. */
1241 *p++ = riscjmp | (0xf << risclabelshift_reset);
1242 *p++ = PADDR(p);
1243 *p++ = riscjmp | riscirq | (fnum << risclabelshift_set);
1244 *lastjmp = p;
1245
1246 return pbase;
1247 }
1248
1249 static ulong *
1250 riscplanar411(ulong pa, int fnum, int w, int h, ulong **lastjmp)
1251 {
1252 ulong *p, *pbase, Cw, Yw, Ch;
1253 uchar *Ybase, *Cbbase, *Crbase;
1254 int i, bitspp;
1255
1256 bitspp = 6;
1257 assert(w * bitspp / 8 <= 0x7FF);
1258 pbase = p = (ulong *)malloc((h + 6) * 5 * sizeof(ulong));
1259 assert(p);
1260
1261 Yw = w;
1262 Ybase = (uchar *)pa;
1263 Cw = w >> 1;
1264 Ch = h >> 1;
1265 Cbbase = Ybase + Yw * h;
1266 Crbase = Cbbase + Cw * Ch;
1267
1268 *p++ = riscsync | riscsync_resync | riscsync_vre;
1269 *p++ = 0;
1270
1271 *p++ = riscsync | riscsync_fm3;
1272 *p++ = 0;
1273
1274 for (i = 0; i != h / 2; i++) {
1275 *p++ = riscwrite123 | Yw | riscwrite_sol | riscwrite_eol;
1276 *p++ = (Cw << 16) | Cw;
1277 *p++ = (ulong)(Ybase + i * 2 * Yw);
1278 *p++ = (ulong)(Cbbase + i * Cw); /* Do not interlace */
1279 *p++ = (ulong)(Crbase + i * Cw);
1280 }
1281
1282 *p++ = riscsync | riscsync_resync | riscsync_vro;
1283 *p++ = 0;
1284
1285 *p++ = riscsync | riscsync_fm3;
1286 *p++ = 0;
1287
1288 for (i = 0; i != h / 2; i++) {
1289 *p++ = riscwrite1s23 | Yw | riscwrite_sol | riscwrite_eol;
1290 *p++ = (Cw << 16) | Cw;
1291 *p++ = (ulong)(Ybase + (i * 2 + 1) * Yw);
1292 }
1293
1294 /* reset status. you really need two instructions ;-(. */
1295 *p++ = riscjmp | (0xf << risclabelshift_reset);
1296 *p++ = PADDR(p);
1297 *p++ = riscjmp | riscirq | (fnum << risclabelshift_set);
1298 *lastjmp = p;
1299
1300 return pbase;
1301 }
1302
1303 static ulong *
1304 riscplanar422(ulong pa, int fnum, int w, int h, ulong **lastjmp)
1305 {
1306 ulong *p, *pbase, Cw, Yw;
1307 uchar *Ybase, *Cbbase, *Crbase;
1308 int i, bpp;
1309
1310 bpp = 2;
1311 assert(w * bpp <= 0x7FF);
1312 pbase = p = (ulong *)malloc((h + 6) * 5 * sizeof(ulong));
1313 assert(p);
1314
1315 Yw = w;
1316 Ybase = (uchar *)pa;
1317 Cw = w >> 1;
1318 Cbbase = Ybase + Yw * h;
1319 Crbase = Cbbase + Cw * h;
1320
1321 *p++ = riscsync | riscsync_resync | riscsync_vre;
1322 *p++ = 0;
1323
1324 *p++ = riscsync | riscsync_fm3;
1325 *p++ = 0;
1326
1327 for (i = 0; i != h / 2; i++) {
1328 *p++ = riscwrite123 | Yw | riscwrite_sol | riscwrite_eol;
1329 *p++ = (Cw << 16) | Cw;
1330 *p++ = (ulong)(Ybase + i * 2 * Yw);
1331 *p++ = (ulong)(Cbbase + i * 2 * Cw);
1332 *p++ = (ulong)(Crbase + i * 2 * Cw);
1333 }
1334
1335 *p++ = riscsync | riscsync_resync | riscsync_vro;
1336 *p++ = 0;
1337
1338 *p++ = riscsync | riscsync_fm3;
1339 *p++ = 0;
1340
1341 for (i = 0; i != h / 2; i++) {
1342 *p++ = riscwrite123 | Yw | riscwrite_sol | riscwrite_eol;
1343 *p++ = (Cw << 16) | Cw;
1344 *p++ = (ulong)(Ybase + (i * 2 + 1) * Yw);
1345 *p++ = (ulong)(Cbbase + (i * 2 + 1) * Cw);
1346 *p++ = (ulong)(Crbase + (i * 2 + 1) * Cw);
1347 }
1348
1349 /* reset status. you really need two instructions ;-(. */
1350 *p++ = riscjmp | (0xf << risclabelshift_reset);
1351 *p++ = PADDR(p);
1352 *p++ = riscjmp | riscirq | (fnum << risclabelshift_set);
1353 *lastjmp = p;
1354
1355 return pbase;
1356 }
1357
1358 static ulong *
1359 riscaudio(ulong pa, int nblocks, int bsize)
1360 {
1361 ulong *p, *pbase;
1362 int i;
1363
1364 pbase = p = (ulong *)malloc((nblocks + 3) * 2 * sizeof(ulong));
1365 assert(p);
1366
1367 *p++ = riscsync|riscsync_fm1;
1368 *p++ = 0;
1369
1370 for (i = 0; i != nblocks; i++) {
1371 *p++ = riscwrite | riscwrite_sol | riscwrite_eol | bsize | riscirq |
1372 ((i & 0xf) << risclabelshift_set) |
1373 ((~i & 0xf) << risclabelshift_reset);
1374 *p++ = pa + i * bsize;
1375 }
1376
1377 *p++ = riscsync | riscsync_vro;
1378 *p++ = 0;
1379 *p++ = riscjmp;
1380 *p++ = PADDR(pbase);
1381 USED(p);
1382
1383 return pbase;
1384 }
1385
1386
1387 static void
1388 vactivate(Tv *tv, Frame *frames, int nframes)
1389 {
1390 Bt848 *bt848 = tv->bt848;
1391
1392 ilock(tv);
1393 if (tv->frames) {
1394 iunlock(tv);
1395 error(Einuse);
1396 }
1397 poperror();
1398
1399 tv->frames = frames;
1400 tv->nframes = nframes;
1401
1402 bt848->riscstrtadd = PADDR(tv->frames[0].fstart);
1403 bt848->capctl |= capctl_captureodd|capctl_captureeven;
1404 bt848->gpiodmactl |= gpiodmactl_fifoenable;
1405 bt848->gpiodmactl |= gpiodmactl_riscenable;
1406
1407 iunlock(tv);
1408 }
1409
1410 static void
1411 vstart(Tv *tv, int nframes, int w, int h, int stride)
1412 {
1413 Frame *frames;
1414 int bitspp, i, bpf;
1415
1416 if (nframes >= 0x10)
1417 error(Ebadarg);
1418
1419 bitspp = getbitspp(tv);
1420 bpf = w * h * bitspp / 8;
1421
1422 /* Add one as a spare. */
1423 frames = (Frame *)malloc(nframes * sizeof(Frame));
1424 assert(frames);
1425 if (waserror()) {
1426 for (i = 0; i != nframes; i++)
1427 if (frames[i].fbase)
1428 free(frames[i].fbase);
1429 free(frames);
1430 nexterror();
1431 }
1432 memset(frames, 0, nframes * sizeof(Frame));
1433
1434 for (i = 0; i != nframes; i++) {
1435 if ((frames[i].fbase = (uchar *)malloc(bpf)) == nil)
1436 error(Enomem);
1437
1438 switch (tv->cfmt) {
1439 case colorfmt_YCbCr422:
1440 frames[i].fstart = riscplanar422(PADDR(frames[i].fbase), i, w, h, &frames[i].fjmp);
1441 break;
1442 case colorfmt_YCbCr411:
1443 frames[i].fstart = riscplanar411(PADDR(frames[i].fbase),
1444 i, w, h, &frames[i].fjmp);
1445 break;
1446 case colorfmt_rgb16:
1447 frames[i].fstart = riscpacked(PADDR(frames[i].fbase), i,
1448 w * bitspp / 8, h, stride * bitspp / 8,
1449 &frames[i].fjmp);
1450 break;
1451 default:
1452 panic("vstart: Unsupport colorformat\n");
1453 }
1454 }
1455
1456 for (i = 0; i != nframes; i++)
1457 *frames[i].fjmp = PADDR(i == nframes - 1? frames[0].fstart:
1458 frames[i + 1].fstart);
1459
1460 vactivate(tv, frames, nframes);
1461 }
1462
1463 static void
1464 astart(Tv *tv, char *input, uint rate, uint nab, uint nasz)
1465 {
1466 Bt848 *bt878 = tv->bt878;
1467 ulong *arisc;
1468 int selector;
1469 uchar *abuf;
1470 int s, d;
1471
1472 if (bt878 == nil || tv->amux == nil)
1473 error("#V: Card does not support audio");
1474
1475 selector = 0;
1476 if (!strcmp(input, "tv"))
1477 selector = asel_tv;
1478 else if (!strcmp(input, "radio"))
1479 selector = asel_radio;
1480 else if (!strcmp(input, "mic"))
1481 selector = asel_mic;
1482 else if (!strcmp(input, "smxc"))
1483 selector = asel_smxc;
1484 else
1485 error("#V: Invalid input");
1486
1487 if (nasz > 0xfff)
1488 error("#V: Audio block size too big (max 0xfff)");
1489
1490 abuf = (uchar *)malloc(nab * nasz * sizeof(uchar));
1491 assert(abuf);
1492 arisc = riscaudio(PADDR(abuf), nab, nasz);
1493
1494 ilock(tv);
1495 if (tv->arisc) {
1496 iunlock(tv);
1497 free(abuf);
1498 free(arisc);
1499 error(Einuse);
1500 }
1501
1502 tv->arisc = arisc;
1503 tv->abuf = abuf;
1504 tv->nablocks = nab;
1505 tv->absize = nasz;
1506
1507 bt878->riscstrtadd = PADDR(tv->arisc);
1508 bt878->packetlen = (nab << 16) | nasz;
1509 bt878->intmask = intstat_scerr | intstat_ocerr | intstat_risci |
1510 intstat_pabort | intstat_riperr | intstat_pperr |
1511 intstat_fdsr | intstat_ftrgt | intstat_fbus;
1512
1513 /* Assume analog, 16bpp */
1514 for (s = 0; s < 16; s++)
1515 if (rate << s > Hwbase_ad * 4 / 15)
1516 break;
1517 for (d = 15; d >= 4; d--)
1518 if (rate << s < Hwbase_ad * 4 / d)
1519 break;
1520
1521 print("astart: sampleshift %d, decimation %d\n", s, d);
1522
1523 tv->narblocks = 0;
1524 bt878->gpiodmactl = gpiodmactl_fifoenable |
1525 gpiodmactl_riscenable | gpiodmactl_acapenable |
1526 gpiodmactl_daes2 | /* gpiodmactl_apwrdn | */
1527 gpiodmactl_daiomda | d << 8 | 9 << 28 | selector << 24;
1528 print("dmactl %.8ulX\n", bt878->gpiodmactl);
1529 iunlock(tv);
1530 }
1531
1532 static void
1533 astop(Tv *tv)
1534 {
1535 Bt848 *bt878 = tv->bt878;
1536
1537 ilock(tv);
1538 if (tv->aref.ref > 0) {
1539 iunlock(tv);
1540 error(Einuse);
1541 }
1542
1543 if (tv->abuf) {
1544 bt878->gpiodmactl &= ~gpiodmactl_riscenable;
1545 bt878->gpiodmactl &= ~gpiodmactl_fifoenable;
1546
1547 free(tv->abuf);
1548 tv->abuf = nil;
1549 free(tv->arisc);
1550 tv->arisc = nil;
1551 }
1552 iunlock(tv);
1553 }
1554
1555 static void
1556 vgastart(Tv *tv, ulong pa, int stride)
1557 {
1558 Frame *frame;
1559
1560 frame = (Frame *)malloc(sizeof(Frame));
1561 assert(frame);
1562 if (waserror()) {
1563 free(frame);
1564 nexterror();
1565 }
1566
1567 frame->fbase = nil;
1568 frame->fstart = riscpacked(pa, 0, ntsc_hactive * getbitspp(tv) / 8,
1569 ntsc_vactive, stride * getbitspp(tv) / 8, &frame->fjmp);
1570 *frame->fjmp = PADDR(frame->fstart);
1571
1572 vactivate(tv, frame, 1);
1573 }
1574
1575 static void
1576 vstop(Tv *tv)
1577 {
1578 Bt848 *bt848 = tv->bt848;
1579
1580 ilock(tv);
1581 if (tv->fref.ref > 0) {
1582 iunlock(tv);
1583 error(Einuse);
1584 }
1585
1586 if (tv->frames) {
1587 int i;
1588
1589 bt848->gpiodmactl &= ~gpiodmactl_riscenable;
1590 bt848->gpiodmactl &= ~gpiodmactl_fifoenable;
1591 bt848->capctl &= ~(capctl_captureodd|capctl_captureeven);
1592
1593 for (i = 0; i != tv->nframes; i++)
1594 if (tv->frames[i].fbase)
1595 free(tv->frames[i].fbase);
1596 free(tv->frames);
1597 tv->frames = nil;
1598 }
1599 iunlock(tv);
1600 }
1601
1602 static long hrcfreq[] = { /* HRC CATV frequencies */
1603 0, 7200, 5400, 6000, 6600, 7800, 8400, 17400,
1604 18000, 18600, 19200, 19800, 20400, 21000, 12000, 12600,
1605 13200, 13800, 14400, 15000, 15600, 16200, 16800, 21600,
1606 22200, 22800, 23400, 24000, 24600, 25200, 25800, 26400,
1607 27000, 27600, 28200, 28800, 29400, 30000, 30600, 31200,
1608 31800, 32400, 33000, 33600, 34200, 34800, 35400, 36000,
1609 36600, 37200, 37800, 38400, 39000, 39600, 40200, 40800,
1610 41400, 42000, 42600, 43200, 43800, 44400, 45000, 45600,
1611 46200, 46800, 47400, 48000, 48600, 49200, 49800, 50400,
1612 51000, 51600, 52200, 52800, 53400, 54000, 54600, 55200,
1613 55800, 56400, 57000, 57600, 58200, 58800, 59400, 60000,
1614 60600, 61200, 61800, 62400, 63000, 63600, 64200, 9000,
1615 9600, 10200, 10800, 11400, 64800, 65400, 66000, 66600,
1616 67200, 67800, 68400, 69000, 69600, 70200, 70800, 71400,
1617 72000, 72600, 73200, 73800, 74400, 75000, 75600, 76200,
1618 76800, 77400, 78000, 78600, 79200, 79800,
1619 };
1620
1621 static void
1622 frequency(Tv *tv, int channel, int finetune)
1623 {
1624 Tuner *tuner = tv->tuner;
1625 long freq;
1626 ushort div;
1627 uchar cfg;
1628
1629 if (channel < 0 || channel > nelem(hrcfreq))
1630 error(Ebadarg);
1631
1632 freq = (hrcfreq[channel] * Freqmultiplier) / 100;
1633
1634 if (freq < tuner->freq_vhfh)
1635 cfg = tuner->VHF_L;
1636 else if (freq < tuner->freq_uhf)
1637 cfg = tuner->VHF_H;
1638 else
1639 cfg = tuner->UHF;
1640
1641 div = (freq + tuner->offs + finetune) & 0x7fff;
1642
1643 if (!i2cwrite(tv, tv->i2ctuneraddr, (div >> 8) & 0x7f, div, 1))
1644 error(Eio);
1645
1646 if (!i2cwrite(tv, tv->i2ctuneraddr, tuner->cfg, cfg, 1))
1647 error(Eio);
1648
1649 tv->channel = channel;
1650 if (tv->msp)
1651 msptune(tv);
1652 }
1653
1654 static struct {
1655 char *cmode;
1656 ulong realmode;
1657 ulong cbits;
1658 } colormodes[] = {
1659 { "RGB16", colorfmt_rgb16, colorfmt_rgb16, },
1660 { "YCbCr422", colorfmt_YCbCr422, colorfmt_YCbCr422, },
1661 { "YCbCr411", colorfmt_YCbCr411, colorfmt_YCbCr422, },
1662 };
1663
1664 static void
1665 colormode(Tv *tv, char *colormode)
1666 {
1667 Bt848 *bt848 = tv->bt848;
1668 int i;
1669
1670 for (i = 0; i != nelem(colormodes); i++)
1671 if (!strcmp(colormodes[i].cmode, colormode))
1672 break;
1673
1674 if (i == nelem(colormodes))
1675 error(Ebadarg);
1676
1677 tv->cfmt = colormodes[i].realmode;
1678 bt848->colorfmt = colormodes[i].cbits;
1679 }
1680
1681 static int
1682 getbitspp(Tv *tv)
1683 {
1684 switch (tv->cfmt) {
1685 case colorfmt_rgb16:
1686 case colorfmt_YCbCr422:
1687 return 16;
1688 case colorfmt_YCbCr411:
1689 return 12;
1690 default:
1691 error("getbitspp: Unsupport color format\n");
1692 }
1693 return -1;
1694 }
1695
1696 static char *
1697 getcolormode(ulong cmode)
1698 {
1699 switch (cmode) {
1700 case colorfmt_rgb16:
1701 return "RGB16";
1702 case colorfmt_YCbCr411:
1703 return "YCbCr411";
1704 case colorfmt_YCbCr422:
1705 return (cmode == colorfmt_YCbCr422)? "YCbCr422": "YCbCr411";
1706 default:
1707 error("getcolormode: Unsupport color format\n");
1708 }
1709 return nil;
1710 }
1711
1712 static void
1713 i2c_set(Tv *tv, int scl, int sda)
1714 {
1715 Bt848 *bt848 = tv->bt848;
1716 ulong d;
1717
1718 bt848->i2c = (scl << 1) | sda;
1719 d = bt848->i2c;
1720 USED(d);
1721 microdelay(i2c_delay);
1722 }
1723
1724 static uchar
1725 i2c_getsda(Tv *tv)
1726 {
1727 Bt848 *bt848 = tv->bt848;
1728
1729 return bt848->i2c & i2c_sda;
1730 }
1731
1732 static void
1733 i2c_start(Tv *tv)
1734 {
1735 i2c_set(tv, 0, 1);
1736 i2c_set(tv, 1, 1);
1737 i2c_set(tv, 1, 0);
1738 i2c_set(tv, 0, 0);
1739 }
1740
1741 static void
1742 i2c_stop(Tv *tv)
1743 {
1744 i2c_set(tv, 0, 0);
1745 i2c_set(tv, 1, 0);
1746 i2c_set(tv, 1, 1);
1747 }
1748
1749 static void
1750 i2c_bit(Tv *tv, int sda)
1751 {
1752 i2c_set(tv, 0, sda);
1753 i2c_set(tv, 1, sda);
1754 i2c_set(tv, 0, sda);
1755 }
1756
1757 static int
1758 i2c_getack(Tv *tv)
1759 {
1760 int ack;
1761
1762 i2c_set(tv, 0, 1);
1763 i2c_set(tv, 1, 1);
1764 ack = i2c_getsda(tv);
1765 i2c_set(tv, 0, 1);
1766 return ack;
1767 }
1768
1769 static int
1770 i2c_wr8(Tv *tv, uchar d, int wait)
1771 {
1772 int i, ack;
1773
1774 i2c_set(tv, 0, 0);
1775 for (i = 0; i != 8; i++) {
1776 i2c_bit(tv, (d & 0x80)? 1: 0);
1777 d <<= 1;
1778 }
1779 if (wait)
1780 microdelay(wait);
1781
1782 ack = i2c_getack(tv);
1783 return ack == 0;
1784 }
1785
1786 static uchar
1787 i2c_rd8(Tv *tv, int lastbyte)
1788 {
1789 int i;
1790 uchar d;
1791
1792 d = 0;
1793 i2c_set(tv, 0, 1);
1794 for (i = 0; i != 8; i++) {
1795 i2c_set(tv, 1, 1);
1796 d <<= 1;
1797 if (i2c_getsda(tv))
1798 d |= 1;
1799 i2c_set(tv, 0, 1);
1800 }
1801
1802 i2c_bit(tv, lastbyte? 1: 0);
1803 return d;
1804 }
1805
1806 static int
1807 mspsend(Tv *tv, uchar *cmd, int ncmd)
1808 {
1809 int i, j, delay;
1810
1811 for (i = 0; i != 3; i++) {
1812 delay = 2000;
1813
1814 i2c_start(tv);
1815 for (j = 0; j != ncmd; j++) {
1816 if (!i2c_wr8(tv, cmd[j], delay))
1817 break;
1818 delay = 0;
1819 }
1820 i2c_stop(tv);
1821
1822 if (j == ncmd)
1823 return 1;
1824
1825 microdelay(10000);
1826 print("mspsend: retrying\n");
1827 }
1828
1829 return 0;
1830 }
1831
1832 static int
1833 mspwrite(Tv *tv, uchar sub, ushort reg, ushort v)
1834 {
1835 uchar b[6];
1836
1837 b[0] = i2c_msp3400;
1838 b[1] = sub;
1839 b[2] = reg >> 8;
1840 b[3] = reg;
1841 b[4] = v >> 8;
1842 b[5] = v;
1843 return mspsend(tv, b, sizeof b);
1844 }
1845
1846 static int
1847 mspread(Tv *tv, uchar sub, ushort reg, ushort *data)
1848 {
1849 uchar b[4];
1850 int i;
1851
1852 b[0] = i2c_msp3400;
1853 b[1] = sub;
1854 b[2] = reg >> 8;
1855 b[3] = reg;
1856
1857 for (i = 0; i != 3; i++) {
1858 i2c_start(tv);
1859 if (!i2c_wr8(tv, b[0], 2000) ||
1860 !i2c_wr8(tv, b[1] | 1, 0) ||
1861 !i2c_wr8(tv, b[2], 0) ||
1862 !i2c_wr8(tv, b[3], 0)) {
1863
1864 i2c_stop(tv);
1865 microdelay(10000);
1866 print("retrying\n");
1867 continue;
1868 }
1869
1870 i2c_start(tv);
1871
1872 if (!i2c_wr8(tv, b[0] | 1, 2000)) {
1873 i2c_stop(tv);
1874 continue;
1875 }
1876
1877 *data = i2c_rd8(tv, 0) << 8;
1878 *data |= i2c_rd8(tv, 1);
1879 i2c_stop(tv);
1880 return 1;
1881 }
1882 return 0;
1883 }
1884
1885 static uchar mspt_reset[] = { i2c_msp3400, 0, 0x80, 0 };
1886 static uchar mspt_on[] = { i2c_msp3400, 0, 0, 0 };
1887
1888 static int
1889 mspreset(Tv *tv)
1890 {
1891 ushort v, p;
1892 Bt848 *bt848 = tv->bt848;
1893 ulong b;
1894
1895 b = 1 << 5;
1896 gpioenable(tv, ~b, b);
1897 gpiowrite(tv, ~b, 0);
1898 microdelay(2500);
1899 gpiowrite(tv, ~b, b);
1900
1901 bt848->i2c = 0x80;
1902
1903 microdelay(2000);
1904 mspsend(tv, mspt_reset, sizeof mspt_reset);
1905
1906 microdelay(2000);
1907 if (!mspsend(tv, mspt_on, sizeof mspt_on)) {
1908 print("#V: Cannot find MSP34x5G on the I2C bus (on)\n");
1909 return 0;
1910 }
1911 microdelay(2000);
1912
1913 if (!mspread(tv, msp_bbp, 0x001e, &v)) {
1914 print("#V: Cannot read MSP34xG5 chip version\n");
1915 return 0;
1916 }
1917
1918 if (!mspread(tv, msp_bbp, 0x001f, &p)) {
1919 print("#V: Cannot read MSP34xG5 product code\n");
1920 return 0;
1921 }
1922
1923 print("#V: MSP34%dg ROM %.d, %d.%d\n",
1924 (uchar)(p >> 8), (uchar)p, (uchar)(v >> 8), (uchar)v);
1925
1926 tv->msp = 1;
1927 return 1;
1928 }
1929
1930 static void
1931 mspvolume(Tv *tv, int mute, int l, int r)
1932 {
1933 short v, d;
1934 ushort b;
1935
1936 if (mute) {
1937 v = 0;
1938 b = 0;
1939 }
1940 else {
1941 tv->aleft = l;
1942 tv->aright = r;
1943 d = v = max(l, r);
1944 if (d == 0)
1945 d++;
1946 b = ((r - l) * 0x7f) / d;
1947 }
1948
1949 mspwrite(tv, msp_bbp, 0, v << 8);
1950 mspwrite(tv, msp_bbp, 7, v? 0x4000: 0);
1951 mspwrite(tv, msp_bbp, 1, b << 8);
1952 }
1953
1954 static char *
1955 mspaformat(int f)
1956 {
1957 switch (f) {
1958 case 0:
1959 return "unknown";
1960 case 2:
1961 case 0x20:
1962 case 0x30:
1963 return "M-BTSC";
1964 case 3:
1965 return "B/G-FM";
1966 case 4:
1967 case 9:
1968 case 0xB:
1969 return "L-AM/NICAM D/Kn";
1970 case 8:
1971 return "B/G-NICAM";
1972 case 0xA:
1973 return "I";
1974 case 0x40:
1975 return "FM-Radio";
1976 }
1977 return "unknown format";
1978 }
1979
1980
1981 static void
1982 msptune(Tv *tv)
1983 {
1984 ushort d, s, nicam;
1985 int i;
1986
1987 mspvolume(tv, 1, 0, 0);
1988 if (!mspwrite(tv, msp_dem, 0x0030, 0x2033))
1989 error("#V: Cannot set MODUS register");
1990
1991 if (!mspwrite(tv, msp_bbp, 0x0008, 0x0320))
1992 error("#V: Cannot set loadspeaker input");
1993
1994 if (!mspwrite(tv, msp_dem, 0x0040, 0x0001))
1995 error("#V: Cannot set I2S clock freq");
1996 if (!mspwrite(tv, msp_bbp, 0x000d, 0x1900))
1997 error("#V: Cannot set SCART prescale");
1998 if (!mspwrite(tv, msp_bbp, 0x000e, 0x2403))
1999 error("#V: Cannot set FM/AM prescale");
2000 if (!mspwrite(tv, msp_bbp, 0x0010, 0x5a00))
2001 error("#V: Cannot set NICAM prescale");
2002 if (!mspwrite(tv, msp_dem, 0x0020, 0x0001))
2003 error("#V: Cannot start auto detect");
2004
2005 for (d = (ushort)-1, i = 0; i != 10; i++) {
2006 if (!mspread(tv, msp_dem, 0x007e, &d))
2007 error("#V: Cannot get autodetect info MSP34xG5");
2008
2009 if (d == 0 || d < 0x800)
2010 break;
2011 delay(50);
2012 }
2013
2014 if (!mspread(tv, msp_dem, 0x0200, &s))
2015 error("#V: Cannot get status info MSP34xG5");
2016
2017 mspvolume(tv, 0, tv->aleft, tv->aright);
2018
2019 nicam = ((s >> 4) & 2) | ((s >> 9) & 1);
2020 snprint(tv->ainfo, sizeof tv->ainfo, "%s %s %s",
2021 mspaformat(d), (s & (1 << 6))? "stereo": "mono",
2022 nicamstate[nicam]);
2023 }
2024
2025 static void
2026 i2cscan(Tv *tv)
2027 {
2028 int i, ack;
2029
2030 for (i = 0; i < 0x100; i += 2) {
2031 i2c_start(tv);
2032 ack = i2c_wr8(tv, i, 0);
2033 i2c_stop(tv);
2034 if (ack)
2035 print("i2c device @%.2uX\n", i);
2036 }
2037
2038 for (i = 0xf0; i != 0xff; i++) {
2039 i2c_start(tv);
2040 ack = i2c_wr8(tv, i, 0);
2041 i2c_stop(tv);
2042 if (ack)
2043 print("i2c device may be at @%.2uX\n", i);
2044 }
2045 }
2046
2047 static void
2048 gpioenable(Tv *tv, ulong mask, ulong data)
2049 {
2050 Bt848 *bt848 = tv->bt848;
2051
2052 bt848->gpioouten = (bt848->gpioouten & mask) | data;
2053 }
2054
2055 static void
2056 gpiowrite(Tv *tv, ulong mask, ulong data)
2057 {
2058 Bt848 *bt848 = tv->bt848;
2059
2060 bt848->gpiodata[0] = (bt848->gpiodata[0] & mask) | data;
2061 }
2062
2063 static void
2064 alteraoutput(Tv *tv)
2065 {
2066 if (tv->gpiostate == Gpiooutput)
2067 return;
2068
2069 gpioenable(tv, ~0xffffff, 0x56ffff);
2070 microdelay(10);
2071 tv->gpiostate = Gpiooutput;
2072 }
2073
2074 static void
2075 alterainput(Tv *tv)
2076 {
2077 if (tv->gpiostate == Gpioinput)
2078 return;
2079
2080 gpioenable(tv, ~0xffffff, 0x570000);
2081 microdelay(10);
2082 tv->gpiostate = Gpioinput;
2083 }
2084
2085 static void
2086 alterareg(Tv *tv, ulong reg)
2087 {
2088 if (tv->alterareg == reg)
2089 return;
2090
2091 gpiowrite(tv, ~0x56ffff, (reg & 0x54ffff) | tv->alteraclock);
2092 microdelay(10);
2093 tv->alterareg = reg;
2094 }
2095
2096 static void
2097 alterawrite(Tv *tv, ulong reg, ushort data)
2098 {
2099 alteraoutput(tv);
2100 alterareg(tv, reg);
2101
2102 tv->alteraclock ^= 0x20000;
2103 gpiowrite(tv, ~0x56ffff, (reg & 0x540000) | data | tv->alteraclock);
2104 microdelay(10);
2105 }
2106
2107 static void
2108 alteraread(Tv *tv, int reg, ushort *data)
2109 {
2110 Bt848 *bt848 = tv->bt848;
2111
2112 if (tv->alterareg != reg) {
2113 alteraoutput(tv);
2114 alterareg(tv, reg);
2115 }
2116 else {
2117 gpioenable(tv, ~0xffffff, 0x560000);
2118 microdelay(10);
2119 }
2120
2121 alterainput(tv);
2122 gpiowrite(tv, ~0x570000, (reg & 0x560000) | tv->alteraclock);
2123 microdelay(10);
2124 *data = (ushort)bt848->gpiodata[0];
2125 microdelay(10);
2126 }
2127
2128 static void
2129 kfirloadu(Tv *tv, uchar *u, int ulen)
2130 {
2131 Bt848 *bt848 = tv->bt848;
2132 int i, j;
2133
2134 ilock(&tv->kfirlock);
2135 bt848->gpioouten &= 0xff000000;
2136 bt848->gpioouten |= gpio_altera_data |
2137 gpio_altera_clock | gpio_altera_nconfig;
2138 bt848->gpiodata[0] &= 0xff000000;
2139 microdelay(10);
2140 bt848->gpiodata[0] |= gpio_altera_nconfig;
2141 microdelay(10);
2142
2143 /* Download the microcode */
2144 for (i = 0; i != ulen; i++)
2145 for (j = 0; j != 8; j++) {
2146 bt848->gpiodata[0] &= ~(gpio_altera_clock|gpio_altera_data);
2147 if (u[i] & 1)
2148 bt848->gpiodata[0] |= gpio_altera_data;
2149 bt848->gpiodata[0] |= gpio_altera_clock;
2150 u[i] >>= 1;
2151 }
2152 bt848->gpiodata[0] &= ~gpio_altera_clock;
2153 microdelay(100);
2154
2155 /* Initialize. */
2156 for (i = 0; i != 30; i++) {
2157 bt848->gpiodata[0] &= ~gpio_altera_clock;
2158 bt848->gpiodata[0] |= gpio_altera_clock;
2159 }
2160 bt848->gpiodata[0] &= ~(gpio_altera_clock|gpio_altera_data);
2161 iunlock(&tv->kfirlock);
2162
2163 tv->gpiostate = Gpioinit;
2164 }
2165
2166 static void
2167 kfirreset(Tv *tv)
2168 {
2169 alterawrite(tv, 0, 0);
2170 microdelay(10);
2171 alterawrite(tv, 0x40000, 0);
2172 microdelay(10);
2173 alterawrite(tv, 0x40006, 0x80);
2174 microdelay(10);
2175 alterawrite(tv, 8, 1);
2176 microdelay(10);
2177 alterawrite(tv, 0x40004, 2);
2178 microdelay(10);
2179 alterawrite(tv, 4, 3);
2180 microdelay(3);
2181 }
2182
2183 static int
2184 kfirinitialize(Tv *tv)
2185 {
2186 /* Initialize parameters? */
2187
2188 tv->gpiostate = Gpioinit;
2189 tv->alterareg = -1;
2190 tv->alteraclock = 0x20000;
2191 kfirloadu(tv, hcwAMC, sizeof hcwAMC);
2192 kfirreset(tv);
2193 return 1;
2194 }
Cache object: 942fc8f7d8a4f9d9abcc4bf86537485e
|