]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/devtv.c
etheriwl: implement 4965 firmware bootstrap (untested)
[plan9front.git] / sys / src / 9 / 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");
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, &regs[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");
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 }