ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / media / dvb / ttpci / av7110_hw.c
1 /*
2  * av7110_hw.c: av7110 low level hardware access and firmware interface
3  *
4  * Copyright (C) 1999-2002 Ralph  Metzler
5  *                       & Marcus Metzler for convergence integrated media GmbH
6  *
7  * originally based on code by:
8  * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
24  *
25  * the project's page is at http://www.linuxtv.org/dvb/
26  */
27
28 /* for debugging ARM communication: */
29 //#define COM_DEBUG
30
31 #include <stdarg.h>
32 #include <linux/types.h>
33 #include <linux/kernel.h>
34 #include <linux/string.h>
35 #include <linux/sched.h>
36 #include <linux/delay.h>
37 #include <linux/byteorder/swabb.h>
38 #include <linux/smp_lock.h>
39 #include <linux/fs.h>
40
41 #define DEBUG_VARIABLE av7110_debug
42 extern int av7110_debug;
43
44 #include "av7110.h"
45 #include "av7110_hw.h"
46 #include "dvb_functions.h"
47
48 /****************************************************************************
49  * DEBI functions
50  ****************************************************************************/
51
52 /* This DEBI code is based on the Stradis driver
53    by Nathan Laredo <laredo@gnu.org> */
54
55 int av7110_debiwrite(struct av7110 *av7110, u32 config,
56                      int addr, u32 val, int count)
57 {
58         struct saa7146_dev *dev = av7110->dev;
59
60         if (count <= 0 || count > 32764)
61                 return -1;
62         if (saa7146_wait_for_debi_done(av7110->dev) < 0)
63                 return -1;
64         saa7146_write(dev, DEBI_CONFIG, config);
65         if (count <= 4)         /* immediate transfer */
66                 saa7146_write(dev, DEBI_AD, val);
67         else                    /* block transfer */
68                 saa7146_write(dev, DEBI_AD, av7110->debi_bus);
69         saa7146_write(dev, DEBI_COMMAND, (count << 17) | (addr & 0xffff));
70         saa7146_write(dev, MC2, (2 << 16) | 2);
71         return 0;
72 }
73
74 u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, int count)
75 {
76         struct saa7146_dev *dev = av7110->dev;
77         u32 result = 0;
78
79         if (count > 32764 || count <= 0)
80                 return 0;
81         if (saa7146_wait_for_debi_done(av7110->dev) < 0)
82                 return 0;
83         saa7146_write(dev, DEBI_AD, av7110->debi_bus);
84         saa7146_write(dev, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
85
86         saa7146_write(dev, DEBI_CONFIG, config);
87         saa7146_write(dev, MC2, (2 << 16) | 2);
88         if (count > 4)
89                 return count;
90         saa7146_wait_for_debi_done(av7110->dev);
91         result = saa7146_read(dev, DEBI_AD);
92         result &= (0xffffffffUL >> ((4 - count) * 8));
93         return result;
94 }
95
96
97
98 /* av7110 ARM core boot stuff */
99
100 void av7110_reset_arm(struct av7110 *av7110)
101 {
102         saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTLO);
103
104         /* Disable DEBI and GPIO irq */
105         IER_DISABLE(av7110->dev, (MASK_19 | MASK_03));
106         saa7146_write(av7110->dev, ISR, (MASK_19 | MASK_03));
107
108         saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTHI);
109         dvb_delay(30);  /* the firmware needs some time to initialize */
110
111         ARM_ResetMailBox(av7110);
112
113         saa7146_write(av7110->dev, ISR, (MASK_19 | MASK_03));
114         IER_ENABLE(av7110->dev, MASK_03);
115
116         av7110->arm_ready = 1;
117         printk("av7110: ARM RESET\n");
118 }
119
120
121 static int waitdebi(struct av7110 *av7110, int adr, int state)
122 {
123         int k;
124
125         DEB_EE(("av7110: %p\n", av7110));
126
127         for (k = 0; k < 100; k++) {
128                 if (irdebi(av7110, DEBINOSWAP, adr, 0, 2) == state)
129                         return 0;
130                 udelay(5);
131         }
132         return -1;
133 }
134
135 static int load_dram(struct av7110 *av7110, u32 *data, int len)
136 {
137         int i;
138         int blocks, rest;
139         u32 base, bootblock = BOOT_BLOCK;
140
141         DEB_EE(("av7110: %p\n", av7110));
142
143         blocks = len / BOOT_MAX_SIZE;
144         rest = len % BOOT_MAX_SIZE;
145         base = DRAM_START_CODE;
146
147         for (i = 0; i < blocks; i++) {
148                 if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0)
149                         return -1;
150                 DEB_D(("Writing DRAM block %d\n", i));
151                 mwdebi(av7110, DEBISWAB, bootblock,
152                        ((char*)data) + i * BOOT_MAX_SIZE, BOOT_MAX_SIZE);
153                 bootblock ^= 0x1400;
154                 iwdebi(av7110, DEBISWAB, BOOT_BASE, swab32(base), 4);
155                 iwdebi(av7110, DEBINOSWAP, BOOT_SIZE, BOOT_MAX_SIZE, 2);
156                 iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
157                 base += BOOT_MAX_SIZE;
158         }
159
160         if (rest > 0) {
161                 if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0)
162                         return -1;
163                 if (rest > 4)
164                         mwdebi(av7110, DEBISWAB, bootblock,
165                                ((char*)data) + i * BOOT_MAX_SIZE, rest);
166                 else
167                         mwdebi(av7110, DEBISWAB, bootblock,
168                                ((char*)data) + i * BOOT_MAX_SIZE - 4, rest + 4);
169
170                 iwdebi(av7110, DEBISWAB, BOOT_BASE, swab32(base), 4);
171                 iwdebi(av7110, DEBINOSWAP, BOOT_SIZE, rest, 2);
172                 iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
173         }
174         if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0)
175                 return -1;
176         iwdebi(av7110, DEBINOSWAP, BOOT_SIZE, 0, 2);
177         iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
178         if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BOOT_COMPLETE) < 0)
179                 return -1;
180         return 0;
181 }
182
183
184 /* we cannot write av7110 DRAM directly, so load a bootloader into
185  * the DPRAM which implements a simple boot protocol */
186 static u8 bootcode[] = {
187   0xea, 0x00, 0x00, 0x0e, 0xe1, 0xb0, 0xf0, 0x0e, 0xe2, 0x5e, 0xf0, 0x04,
188   0xe2, 0x5e, 0xf0, 0x04, 0xe2, 0x5e, 0xf0, 0x08, 0xe2, 0x5e, 0xf0, 0x04,
189   0xe2, 0x5e, 0xf0, 0x04, 0xe2, 0x5e, 0xf0, 0x04, 0x2c, 0x00, 0x00, 0x24,
190   0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x34,
191   0x00, 0x00, 0x00, 0x00, 0xa5, 0xa5, 0x5a, 0x5a, 0x00, 0x1f, 0x15, 0x55,
192   0x00, 0x00, 0x00, 0x09, 0xe5, 0x9f, 0xd0, 0x7c, 0xe5, 0x9f, 0x40, 0x74,
193   0xe3, 0xa0, 0x00, 0x00, 0xe5, 0x84, 0x00, 0x00, 0xe5, 0x84, 0x00, 0x04,
194   0xe5, 0x9f, 0x10, 0x70, 0xe5, 0x9f, 0x20, 0x70, 0xe5, 0x9f, 0x30, 0x64,
195   0xe8, 0xb1, 0x1f, 0xe0, 0xe8, 0xa3, 0x1f, 0xe0, 0xe1, 0x51, 0x00, 0x02,
196   0xda, 0xff, 0xff, 0xfb, 0xe5, 0x9f, 0xf0, 0x50, 0xe1, 0xd4, 0x10, 0xb0,
197   0xe3, 0x51, 0x00, 0x00, 0x0a, 0xff, 0xff, 0xfc, 0xe1, 0xa0, 0x10, 0x0d,
198   0xe5, 0x94, 0x30, 0x04, 0xe1, 0xd4, 0x20, 0xb2, 0xe2, 0x82, 0x20, 0x3f,
199   0xe1, 0xb0, 0x23, 0x22, 0x03, 0xa0, 0x00, 0x02, 0xe1, 0xc4, 0x00, 0xb0,
200   0x0a, 0xff, 0xff, 0xf4, 0xe8, 0xb1, 0x1f, 0xe0, 0xe8, 0xa3, 0x1f, 0xe0,
201   0xe8, 0xb1, 0x1f, 0xe0, 0xe8, 0xa3, 0x1f, 0xe0, 0xe2, 0x52, 0x20, 0x01,
202   0x1a, 0xff, 0xff, 0xf9, 0xe2, 0x2d, 0xdb, 0x05, 0xea, 0xff, 0xff, 0xec,
203   0x2c, 0x00, 0x03, 0xf8, 0x2c, 0x00, 0x04, 0x00, 0x9e, 0x00, 0x08, 0x00,
204   0x2c, 0x00, 0x00, 0x74, 0x2c, 0x00, 0x00, 0xc0
205 };
206
207 int av7110_bootarm(struct av7110 *av7110)
208 {
209         struct saa7146_dev *dev = av7110->dev;
210         u32 ret;
211         int i;
212
213         DEB_EE(("av7110: %p\n", av7110));
214
215         saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
216
217         /* Disable DEBI and GPIO irq */
218         IER_DISABLE(av7110->dev, MASK_03 | MASK_19);
219         saa7146_write(av7110->dev, ISR, (MASK_19 | MASK_03));
220
221         /* enable DEBI */
222         saa7146_write(av7110->dev, MC1, 0x08800880);
223         saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000);
224         saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
225
226         /* test DEBI */
227         iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
228         if ((ret=irdebi(av7110, DEBINOSWAP, DPRAM_BASE, 0, 4)) != 0x10325476) {
229                 printk(KERN_ERR "dvb: debi test in av7110_bootarm() failed: "
230                        "%08x != %08x (check your BIOS hotplug settings)\n",
231                        ret, 0x10325476);
232                 return -1;
233         }
234         for (i = 0; i < 8192; i += 4)
235                 iwdebi(av7110, DEBISWAP, DPRAM_BASE + i, 0x00, 4);
236         DEB_D(("av7110_bootarm: debi test OK\n"));
237
238         /* boot */
239         DEB_D(("av7110_bootarm: load boot code\n"));
240         saa7146_setgpio(dev, ARM_IRQ_LINE, SAA7146_GPIO_IRQLO);
241         //saa7146_setgpio(dev, DEBI_DONE_LINE, SAA7146_GPIO_INPUT);
242         //saa7146_setgpio(dev, 3, SAA7146_GPIO_INPUT);
243
244         mwdebi(av7110, DEBISWAB, DPRAM_BASE, bootcode, sizeof(bootcode));
245         iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
246
247         if (saa7146_wait_for_debi_done(av7110->dev)) {
248                 printk(KERN_ERR "dvb: av7110_bootarm(): "
249                        "saa7146_wait_for_debi_done() timed out\n");
250                 return -1;
251         }
252         saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
253         mdelay(1);
254
255         DEB_D(("av7110_bootarm: load dram code\n"));
256         if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0)
257                 return -1;
258
259         saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
260         mdelay(1);
261
262         DEB_D(("av7110_bootarm: load dpram code\n"));
263         mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram);
264
265         if (saa7146_wait_for_debi_done(av7110->dev)) {
266                 printk(KERN_ERR "dvb: av7110_bootarm(): "
267                        "saa7146_wait_for_debi_done() timed out after loading DRAM\n");
268                 return -1;
269         }
270         saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
271         dvb_delay(30);  /* the firmware needs some time to initialize */
272
273         //ARM_ClearIrq(av7110);
274         ARM_ResetMailBox(av7110);
275         saa7146_write(av7110->dev, ISR, (MASK_19 | MASK_03));
276         IER_ENABLE(av7110->dev, MASK_03);
277
278         av7110->arm_errors = 0;
279         av7110->arm_ready = 1;
280         return 0;
281 }
282
283
284 /****************************************************************************
285  * DEBI command polling
286  ****************************************************************************/
287
288 int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
289 {
290         int i;
291         unsigned long start;
292 #ifdef COM_DEBUG
293         u32 stat;
294 #endif
295
296 //      DEB_EE(("av7110: %p\n", av7110));
297
298         if (!av7110->arm_ready) {
299                 DEB_D(("arm not ready.\n"));
300                 return -1;
301         }
302
303         start = jiffies;
304         while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) {
305                 dvb_delay(1);
306                 if (time_after(jiffies, start + ARM_WAIT_FREE)) {
307                         printk(KERN_ERR "%s: timeout waiting for COMMAND idle\n", __FUNCTION__);
308                         return -1;
309                 }
310         }
311
312 #ifndef _NOHANDSHAKE
313         start = jiffies;
314         while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) {
315                 dvb_delay(1);
316                 if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
317                         printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
318                         return -1;
319                 }
320         }
321 #endif
322
323         start = jiffies;
324         while (rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2) & OSDQFull) {
325                 dvb_delay(1);
326                 if (time_after(jiffies, start + ARM_WAIT_OSD)) {
327                         printk(KERN_ERR "%s: timeout waiting for !OSDQFull\n", __FUNCTION__);
328                         return -1;
329                 }
330         }
331         for (i = 2; i < length; i++)
332                 wdebi(av7110, DEBINOSWAP, COMMAND + 2 * i, (u32) buf[i], 2);
333
334         if (length)
335                 wdebi(av7110, DEBINOSWAP, COMMAND + 2, (u32) buf[1], 2);
336         else
337                 wdebi(av7110, DEBINOSWAP, COMMAND + 2, 0, 2);
338
339         wdebi(av7110, DEBINOSWAP, COMMAND, (u32) buf[0], 2);
340
341 #ifdef COM_DEBUG
342         start = jiffies;
343         while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) {
344                 dvb_delay(1);
345                 if (time_after(jiffies, start + ARM_WAIT_FREE)) {
346                         printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n",
347                                __FUNCTION__);
348                         return -1;
349                 }
350         }
351
352         stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
353         if (stat & GPMQOver) {
354                 printk(KERN_ERR "%s: GPMQOver\n", __FUNCTION__);
355                 return -1;
356         }
357         else if (stat & OSDQOver) {
358                 printk(KERN_ERR "%s: OSDQOver\n", __FUNCTION__);
359                 return -1;
360         }
361 #endif
362
363         return 0;
364 }
365
366 int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
367 {
368         int ret;
369
370 //      DEB_EE(("av7110: %p\n", av7110));
371
372         if (!av7110->arm_ready) {
373                 DEB_D(("arm not ready.\n"));
374                 return -1;
375         }
376         if (down_interruptible(&av7110->dcomlock))
377                 return -ERESTARTSYS;
378
379         ret = __av7110_send_fw_cmd(av7110, buf, length);
380         up(&av7110->dcomlock);
381         if (ret)
382                 printk("av7110_send_fw_cmd error\n");
383         return ret;
384 }
385
386 int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...)
387 {
388         va_list args;
389         u16 buf[num + 2];
390         int i, ret;
391
392 //      DEB_EE(("av7110: %p\n",av7110));
393
394         buf[0] = ((type << 8) | com);
395         buf[1] = num;
396
397         if (num) {
398                 va_start(args, num);
399                 for (i = 0; i < num; i++)
400                         buf[i + 2] = va_arg(args, u32);
401                 va_end(args);
402         }
403
404         ret = av7110_send_fw_cmd(av7110, buf, num + 2);
405         if (ret)
406                 printk("av7110_fw_cmd error\n");
407         return ret;
408 }
409
410 int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len)
411 {
412         int i, ret;
413         u16 cmd[18] = { ((COMTYPE_COMMON_IF << 8) + subcom),
414                 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
415
416         DEB_EE(("av7110: %p\n", av7110));
417
418         for(i = 0; i < len && i < 32; i++)
419         {
420                 if(i % 2 == 0)
421                         cmd[(i / 2) + 2] = (u16)(buf[i]) << 8;
422                 else
423                         cmd[(i / 2) + 2] |= buf[i];
424         }
425
426         ret = av7110_send_fw_cmd(av7110, cmd, 18);
427         if (ret)
428                 printk("av7110_send_ci_cmd error\n");
429         return ret;
430 }
431
432 int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
433                       int request_buf_len, u16 *reply_buf, int reply_buf_len)
434 {
435         int err;
436         s16 i;
437         unsigned long start;
438 #ifdef COM_DEBUG
439         u32 stat;
440 #endif
441
442         DEB_EE(("av7110: %p\n", av7110));
443
444         if (!av7110->arm_ready) {
445                 DEB_D(("arm not ready.\n"));
446                 return -1;
447         }
448
449         if (down_interruptible(&av7110->dcomlock))
450                 return -ERESTARTSYS;
451
452         if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) {
453                 up(&av7110->dcomlock);
454                 printk("av7110_fw_request error\n");
455                 return err;
456         }
457
458         start = jiffies;
459         while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2)) {
460 #ifdef _NOHANDSHAKE
461                 dvb_delay(1);
462 #endif
463                 if (time_after(jiffies, start + ARM_WAIT_FREE)) {
464                         printk("%s: timeout waiting for COMMAND to complete\n", __FUNCTION__);
465                         up(&av7110->dcomlock);
466                         return -1;
467                 }
468         }
469
470 #ifndef _NOHANDSHAKE
471         start = jiffies;
472         while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) {
473                 dvb_delay(1);
474                 if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
475                         printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
476                         up(&av7110->dcomlock);
477                         return -1;
478                 }
479         }
480 #endif
481
482 #ifdef COM_DEBUG
483         stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
484         if (stat & GPMQOver) {
485                 printk(KERN_ERR "%s: GPMQOver\n", __FUNCTION__);
486                 up(&av7110->dcomlock);
487                 return -1;
488         }
489         else if (stat & OSDQOver) {
490                 printk(KERN_ERR "%s: OSDQOver\n", __FUNCTION__);
491                 up(&av7110->dcomlock);
492                 return -1;
493         }
494 #endif
495
496         for (i = 0; i < reply_buf_len; i++)
497                 reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2);
498
499         up(&av7110->dcomlock);
500         return 0;
501 }
502
503 int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length)
504 {
505         int ret;
506         ret = av7110_fw_request(av7110, &tag, 0, buf, length);
507         if (ret)
508                 printk("av7110_fw_query error\n");
509         return ret;
510 }
511
512
513 /****************************************************************************
514  * Firmware commands
515  ****************************************************************************/
516
517 /* get version of the firmware ROM, RTSL, video ucode and ARM application  */
518 int av7110_firmversion(struct av7110 *av7110)
519 {
520         u16 buf[20];
521         u16 tag = ((COMTYPE_REQUEST << 8) + ReqVersion);
522
523         DEB_EE(("av7110: %p\n", av7110));
524
525         if (av7110_fw_query(av7110, tag, buf, 16)) {
526                 printk("DVB: AV7110-%d: ERROR: Failed to boot firmware\n",
527                        av7110->dvb_adapter->num);
528                 return -EIO;
529         }
530
531         av7110->arm_fw = (buf[0] << 16) + buf[1];
532         av7110->arm_rtsl = (buf[2] << 16) + buf[3];
533         av7110->arm_vid = (buf[4] << 16) + buf[5];
534         av7110->arm_app = (buf[6] << 16) + buf[7];
535         av7110->avtype = (buf[8] << 16) + buf[9];
536
537         printk("DVB: AV711%d(%d) - firm %08x, rtsl %08x, vid %08x, app %08x\n",
538                av7110->avtype, av7110->dvb_adapter->num, av7110->arm_fw,
539                av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app);
540
541         /* print firmware capabilities */
542         if (FW_CI_LL_SUPPORT(av7110->arm_app))
543                 printk("DVB: AV711%d(%d) - firmware supports CI link layer interface\n",
544                        av7110->avtype, av7110->dvb_adapter->num);
545         else
546                 printk("DVB: AV711%d(%d) - no firmware support for CI link layer interface\n",
547                        av7110->avtype, av7110->dvb_adapter->num);
548
549         return 0;
550 }
551
552
553 int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst)
554 {
555         int i;
556         u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) + SendDiSEqC),
557                         16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
558
559         DEB_EE(("av7110: %p\n", av7110));
560
561         if (len > 10)
562                 len = 10;
563
564         buf[1] = len + 2;
565         buf[2] = len;
566
567         if (burst != -1)
568                 buf[3] = burst ? 0x01 : 0x00;
569         else
570                 buf[3] = 0xffff;
571
572         for (i = 0; i < len; i++)
573                 buf[i + 4] = msg[i];
574
575         if (av7110_send_fw_cmd(av7110, buf, 18))
576                 printk("av7110_diseqc_send error\n");
577
578         return 0;
579 }
580
581
582 #ifdef CONFIG_DVB_AV7110_OSD
583
584 static inline int ResetBlend(struct av7110 *av7110, u8 windownr)
585 {
586         return av7110_fw_cmd(av7110, COMTYPE_OSD, SetNonBlend, 1, windownr);
587 }
588
589 static inline int SetColorBlend(struct av7110 *av7110, u8 windownr)
590 {
591         return av7110_fw_cmd(av7110, COMTYPE_OSD, SetCBlend, 1, windownr);
592 }
593
594 static inline int SetWindowBlend(struct av7110 *av7110, u8 windownr, u8 blending)
595 {
596         return av7110_fw_cmd(av7110, COMTYPE_OSD, SetWBlend, 2, windownr, blending);
597 }
598
599 static inline int SetBlend_(struct av7110 *av7110, u8 windownr,
600                      enum av7110_osd_palette_type colordepth, u16 index, u8 blending)
601 {
602         return av7110_fw_cmd(av7110, COMTYPE_OSD, SetBlend, 4,
603                              windownr, colordepth, index, blending);
604 }
605
606 static inline int SetColor_(struct av7110 *av7110, u8 windownr,
607                      enum av7110_osd_palette_type colordepth, u16 index, u16 colorhi, u16 colorlo)
608 {
609         return av7110_fw_cmd(av7110, COMTYPE_OSD, SetColor, 5,
610                              windownr, colordepth, index, colorhi, colorlo);
611 }
612
613 static inline int BringToTop(struct av7110 *av7110, u8 windownr)
614 {
615         return av7110_fw_cmd(av7110, COMTYPE_OSD, WTop, 1, windownr);
616 }
617
618 static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize,
619                           u16 colorfg, u16 colorbg)
620 {
621         return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Font, 4,
622                              windownr, fontsize, colorfg, colorbg);
623 }
624
625 static int FlushText(struct av7110 *av7110)
626 {
627         unsigned long start;
628
629         if (down_interruptible(&av7110->dcomlock))
630                 return -ERESTARTSYS;
631         start = jiffies;
632         while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) {
633                 dvb_delay(1);
634                 if (time_after(jiffies, start + ARM_WAIT_OSD)) {
635                         printk(KERN_ERR "%s: timeout waiting for BUFF1_BASE == 0\n",
636                                __FUNCTION__);
637                         up(&av7110->dcomlock);
638                         return -1;
639                 }
640         }
641         up(&av7110->dcomlock);
642         return 0;
643 }
644
645 static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
646 {
647         int i, ret;
648         unsigned long start;
649         int length = strlen(buf) + 1;
650         u16 cbuf[5] = { (COMTYPE_OSD << 8) + DText, 3, win, x, y };
651
652         if (down_interruptible(&av7110->dcomlock))
653                 return -ERESTARTSYS;
654
655         start = jiffies;
656         while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) {
657                 dvb_delay(1);
658                 if (time_after(jiffies, start + ARM_WAIT_OSD)) {
659                         printk(KERN_ERR "%s: timeout waiting for BUFF1_BASE == 0\n",
660                                __FUNCTION__);
661                         up(&av7110->dcomlock);
662                         return -1;
663                 }
664         }
665 #ifndef _NOHANDSHAKE
666         start = jiffies;
667         while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2)) {
668                 dvb_delay(1);
669                 if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
670                         printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n",
671                                __FUNCTION__);
672                         up(&av7110->dcomlock);
673                         return -1;
674                 }
675         }
676 #endif
677         for (i = 0; i < length / 2; i++)
678                 wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2,
679                       swab16(*(u16 *)(buf + 2 * i)), 2);
680         if (length & 1)
681                 wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2);
682         ret = __av7110_send_fw_cmd(av7110, cbuf, 5);
683         up(&av7110->dcomlock);
684         if (ret)
685                 printk("WriteText error\n");
686         return ret;
687 }
688
689 static inline int DrawLine(struct av7110 *av7110, u8 windownr,
690                            u16 x, u16 y, u16 dx, u16 dy, u16 color)
691 {
692         return av7110_fw_cmd(av7110, COMTYPE_OSD, DLine, 6,
693                              windownr, x, y, dx, dy, color);
694 }
695
696 static inline int DrawBlock(struct av7110 *av7110, u8 windownr,
697                             u16 x, u16 y, u16 dx, u16 dy, u16 color)
698 {
699         return av7110_fw_cmd(av7110, COMTYPE_OSD, DBox, 6,
700                              windownr, x, y, dx, dy, color);
701 }
702
703 static inline int HideWindow(struct av7110 *av7110, u8 windownr)
704 {
705         return av7110_fw_cmd(av7110, COMTYPE_OSD, WHide, 1, windownr);
706 }
707
708 static inline int MoveWindowRel(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
709 {
710         return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveD, 3, windownr, x, y);
711 }
712
713 static inline int MoveWindowAbs(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
714 {
715         return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveA, 3, windownr, x, y);
716 }
717
718 static inline int DestroyOSDWindow(struct av7110 *av7110, u8 windownr)
719 {
720         return av7110_fw_cmd(av7110, COMTYPE_OSD, WDestroy, 1, windownr);
721 }
722
723 static inline int CreateOSDWindow(struct av7110 *av7110, u8 windownr,
724                                   enum av7110_window_display_type disptype,
725                                   u16 width, u16 height)
726 {
727         return av7110_fw_cmd(av7110, COMTYPE_OSD, WCreate, 4,
728                              windownr, disptype, width, height);
729 }
730
731
732 static enum av7110_osd_palette_type bpp2pal[8] = {
733         Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit
734 };
735 static enum av7110_window_display_type bpp2bit[8] = {
736         BITMAP1, BITMAP2, 0, BITMAP4, 0, 0, 0, BITMAP8
737 };
738
739 static inline int LoadBitmap(struct av7110 *av7110, u16 format,
740                              u16 dx, u16 dy, int inc, u8* data)
741 {
742         int bpp;
743         int i;
744         int d, delta;
745         u8 c;
746         DECLARE_WAITQUEUE(wait, current);
747
748         DEB_EE(("av7110: %p\n", av7110));
749
750         if (av7110->bmp_state == BMP_LOADING) {
751                 add_wait_queue(&av7110->bmpq, &wait);
752                 while (1) {
753                         set_current_state(TASK_INTERRUPTIBLE);
754                         if (av7110->bmp_state != BMP_LOADING
755                             || signal_pending(current))
756                                 break;
757                         schedule();
758                 }
759                 set_current_state(TASK_RUNNING);
760                 remove_wait_queue(&av7110->bmpq, &wait);
761         }
762         if (av7110->bmp_state == BMP_LOADING)
763                 return -1;
764         av7110->bmp_state = BMP_LOADING;
765         if      (format == BITMAP8) {
766                 bpp=8; delta = 1;
767         } else if (format == BITMAP4) {
768                 bpp=4; delta = 2;
769         } else if (format == BITMAP2) {
770                 bpp=2; delta = 4;
771         } else if (format == BITMAP1) {
772                 bpp=1; delta = 8;
773         } else {
774                 av7110->bmp_state = BMP_NONE;
775                 return -1;
776         }
777         av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8;
778         av7110->bmpp = 0;
779         if (av7110->bmplen > 32768) {
780                 av7110->bmp_state = BMP_NONE;
781                 return -1;
782         }
783         for (i = 0; i < dy; i++) {
784                 if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) {
785                         av7110->bmp_state = BMP_NONE;
786                         return -1;
787                 }
788         }
789         if (format != BITMAP8) {
790                 for (i = 0; i < dx * dy / delta; i++) {
791                         c = ((u8 *)av7110->bmpbuf)[1024 + i * delta + delta - 1];
792                         for (d = delta - 2; d >= 0; d--) {
793                                 c |= (((u8 *)av7110->bmpbuf)[1024 + i * delta + d]
794                                       << ((delta - d - 1) * bpp));
795                                 ((u8 *)av7110->bmpbuf)[1024 + i] = c;
796                         }
797                 }
798         }
799         av7110->bmplen += 1024;
800         return av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
801 }
802
803 static int BlitBitmap(struct av7110 *av7110, u16 win, u16 x, u16 y, u16 trans)
804 {
805         DECLARE_WAITQUEUE(wait, current);
806
807         DEB_EE(("av7110: %p\n", av7110));
808
809        if (av7110->bmp_state == BMP_NONE)
810                 return -1;
811         if (av7110->bmp_state == BMP_LOADING) {
812                 add_wait_queue(&av7110->bmpq, &wait);
813                 while (1) {
814                         set_current_state(TASK_INTERRUPTIBLE);
815                         if (av7110->bmp_state != BMP_LOADING
816                             || signal_pending(current))
817                                 break;
818                         schedule();
819                 }
820                 set_current_state(TASK_RUNNING);
821                 remove_wait_queue(&av7110->bmpq, &wait);
822         }
823         if (av7110->bmp_state == BMP_LOADED)
824                 return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, win, x, y, trans);
825         return -1;
826 }
827
828 static inline int ReleaseBitmap(struct av7110 *av7110)
829 {
830         DEB_EE(("av7110: %p\n",av7110));
831
832         if (av7110->bmp_state != BMP_LOADED)
833                 return -1;
834         av7110->bmp_state = BMP_NONE;
835         return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0);
836 }
837
838 static u32 RGB2YUV(u16 R, u16 G, u16 B)
839 {
840         u16 y, u, v;
841         u16 Y, Cr, Cb;
842
843         y = R * 77 + G * 150 + B * 29;  /* Luma=0.299R+0.587G+0.114B 0..65535 */
844         u = 2048 + B * 8 -(y >> 5);     /* Cr 0..4095 */
845         v = 2048 + R * 8 -(y >> 5);     /* Cb 0..4095 */
846
847         Y = y / 256;
848         Cb = u / 16;
849         Cr = v / 16;
850
851         return Cr | (Cb << 16) | (Y << 8);
852 }
853
854 static void OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
855 {
856         u16 ch, cl;
857         u32 yuv;
858
859         yuv = blend ? RGB2YUV(r,g,b) : 0;
860         cl = (yuv & 0xffff);
861         ch = ((yuv >> 16) & 0xffff);
862         SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
863                   color, ch, cl);
864         SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
865                   color, ((blend >> 4) & 0x0f));
866 }
867
868 static int OSDSetPalette(struct av7110 *av7110, u32 *colors, u8 first, u8 last)
869 {
870        int i;
871        int length = last - first + 1;
872
873        if (length * 4 > DATA_BUFF3_SIZE)
874                return -1;
875
876        for (i = 0; i < length; i++) {
877                u32 blend = (colors[i] & 0xF0000000) >> 4;
878                u32 yuv = blend ? RGB2YUV(colors[i] & 0xFF, (colors[i] >> 8) & 0xFF,
879                                          (colors[i] >> 16) & 0xFF) | blend : 0;
880                yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16);
881                wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4);
882        }
883        return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4,
884                             av7110->osdwin,
885                             bpp2pal[av7110->osdbpp[av7110->osdwin]],
886                             first, last);
887 }
888
889 static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
890                        int x1, int y1, int inc, u8 *data)
891 {
892         uint w, h, bpp, bpl, size, lpb, bnum, brest;
893         int i;
894
895         w = x1 - x0 + 1;
896         h = y1 - y0 + 1;
897         if (inc <= 0)
898                 inc = w;
899         if (w <= 0 || w > 720 || h <= 0 || h > 576)
900                 return -1;
901         bpp = av7110->osdbpp[av7110->osdwin] + 1;
902         bpl = ((w * bpp + 7) & ~7) / 8;
903         size = h * bpl;
904         lpb = (32 * 1024) / bpl;
905         bnum = size / (lpb * bpl);
906         brest = size - bnum * lpb * bpl;
907
908         for (i = 0; i < bnum; i++) {
909                 LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]],
910                            w, lpb, inc, data);
911                 BlitBitmap(av7110, av7110->osdwin, x0, y0 + i * lpb, 0);
912                 data += lpb * inc;
913         }
914         if (brest) {
915                 LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]],
916                            w, brest / bpl, inc, data);
917                 BlitBitmap(av7110, av7110->osdwin, x0, y0 + bnum * lpb, 0);
918         }
919         ReleaseBitmap(av7110);
920         return 0;
921 }
922
923 int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
924 {
925         switch (dc->cmd) {
926         case OSD_Close:
927                 DestroyOSDWindow(av7110, av7110->osdwin);
928                 return 0;
929         case OSD_Open:
930                 av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7;
931                 CreateOSDWindow(av7110, av7110->osdwin,
932                                 bpp2bit[av7110->osdbpp[av7110->osdwin]],
933                                 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
934                 if (!dc->data) {
935                         MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
936                         SetColorBlend(av7110, av7110->osdwin);
937                 }
938                 return 0;
939         case OSD_Show:
940                 MoveWindowRel(av7110, av7110->osdwin, 0, 0);
941                 return 0;
942         case OSD_Hide:
943                 HideWindow(av7110, av7110->osdwin);
944                 return 0;
945         case OSD_Clear:
946                 DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
947                 return 0;
948         case OSD_Fill:
949                 DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
950                 return 0;
951         case OSD_SetColor:
952                 OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
953                 return 0;
954         case OSD_SetPalette:
955         {
956                 if (FW_VERSION(av7110->arm_app) >= 0x2618)
957                         OSDSetPalette(av7110, (u32 *)dc->data, dc->color, dc->x0);
958                 else {
959                         int i, len = dc->x0-dc->color+1;
960                         u8 *colors = (u8 *)dc->data;
961
962                         for (i = 0; i<len; i++)
963                                 OSDSetColor(av7110, dc->color + i,
964                                         colors[i * 4], colors[i * 4 + 1],
965                                         colors[i * 4 + 2], colors[i * 4 + 3]);
966                 }
967                 return 0;
968         }
969         case OSD_SetTrans:
970                 return 0;
971         case OSD_SetPixel:
972                 DrawLine(av7110, av7110->osdwin,
973                          dc->x0, dc->y0, 0, 0, dc->color);
974                 return 0;
975         case OSD_GetPixel:
976                 return 0;
977
978         case OSD_SetRow:
979                 dc->y1 = dc->y0;
980                 /* fall through */
981         case OSD_SetBlock:
982                 OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data);
983                 return 0;
984
985         case OSD_FillRow:
986                 DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
987                           dc->x1-dc->x0+1, dc->y1, dc->color);
988                 return 0;
989         case OSD_FillBlock:
990                 DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
991                           dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color);
992                 return 0;
993         case OSD_Line:
994                 DrawLine(av7110, av7110->osdwin,
995                          dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color);
996                 return 0;
997         case OSD_Query:
998                 return 0;
999         case OSD_Test:
1000                 return 0;
1001         case OSD_Text:
1002         {
1003                 char textbuf[240];
1004
1005                 if (strncpy_from_user(textbuf, dc->data, 240) < 0)
1006                         return -EFAULT;
1007                 textbuf[239] = 0;
1008                 if (dc->x1 > 3)
1009                         dc->x1 = 3;
1010                 SetFont(av7110, av7110->osdwin, dc->x1,
1011                         (u16) (dc->color & 0xffff), (u16) (dc->color >> 16));
1012                 FlushText(av7110);
1013                 WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
1014                 return 0;
1015         }
1016         case OSD_SetWindow:
1017                 if (dc->x0 < 1 || dc->x0 > 7)
1018                         return -EINVAL;
1019                 av7110->osdwin = dc->x0;
1020                 return 0;
1021         case OSD_MoveWindow:
1022                 MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1023                 SetColorBlend(av7110, av7110->osdwin);
1024                 return 0;
1025         default:
1026                 return -EINVAL;
1027         }
1028 }
1029 #endif /* CONFIG_DVB_AV7110_OSD */