Linux-2.6.12-rc2
[linux-2.6/next.git] / drivers / media / dvb / ttpci / av7110_hw.c
blobbd6e5ea4aefe3768ab960bff0d1440c5190d6e18
1 /*
2 * av7110_hw.c: av7110 low level hardware access and firmware interface
4 * Copyright (C) 1999-2002 Ralph Metzler
5 * & Marcus Metzler for convergence integrated media GmbH
7 * originally based on code by:
8 * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
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.
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.
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
25 * the project's page is at http://www.linuxtv.org/dvb/
28 /* for debugging ARM communication: */
29 //#define COM_DEBUG
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>
41 #include "av7110.h"
42 #include "av7110_hw.h"
44 /****************************************************************************
45 * DEBI functions
46 ****************************************************************************/
48 /* This DEBI code is based on the Stradis driver
49 by Nathan Laredo <laredo@gnu.org> */
51 int av7110_debiwrite(struct av7110 *av7110, u32 config,
52 int addr, u32 val, int count)
54 struct saa7146_dev *dev = av7110->dev;
56 if (count <= 0 || count > 32764) {
57 printk("%s: invalid count %d\n", __FUNCTION__, count);
58 return -1;
60 if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
61 printk("%s: wait_for_debi_done failed\n", __FUNCTION__);
62 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;
74 u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, int count)
76 struct saa7146_dev *dev = av7110->dev;
77 u32 result = 0;
79 if (count > 32764 || count <= 0) {
80 printk("%s: invalid count %d\n", __FUNCTION__, count);
81 return 0;
83 if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
84 printk("%s: wait_for_debi_done #1 failed\n", __FUNCTION__);
85 return 0;
87 saa7146_write(dev, DEBI_AD, av7110->debi_bus);
88 saa7146_write(dev, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
90 saa7146_write(dev, DEBI_CONFIG, config);
91 saa7146_write(dev, MC2, (2 << 16) | 2);
92 if (count > 4)
93 return count;
94 if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
95 printk("%s: wait_for_debi_done #2 failed\n", __FUNCTION__);
96 return 0;
99 result = saa7146_read(dev, DEBI_AD);
100 result &= (0xffffffffUL >> ((4 - count) * 8));
101 return result;
106 /* av7110 ARM core boot stuff */
108 void av7110_reset_arm(struct av7110 *av7110)
110 saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTLO);
112 /* Disable DEBI and GPIO irq */
113 SAA7146_IER_DISABLE(av7110->dev, MASK_19 | MASK_03);
114 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
116 saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTHI);
117 msleep(30); /* the firmware needs some time to initialize */
119 ARM_ResetMailBox(av7110);
121 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
122 SAA7146_IER_ENABLE(av7110->dev, MASK_03);
124 av7110->arm_ready = 1;
125 dprintk(1, "reset ARM\n");
129 static int waitdebi(struct av7110 *av7110, int adr, int state)
131 int k;
133 dprintk(4, "%p\n", av7110);
135 for (k = 0; k < 100; k++) {
136 if (irdebi(av7110, DEBINOSWAP, adr, 0, 2) == state)
137 return 0;
138 udelay(5);
140 return -1;
143 static int load_dram(struct av7110 *av7110, u32 *data, int len)
145 int i;
146 int blocks, rest;
147 u32 base, bootblock = BOOT_BLOCK;
149 dprintk(4, "%p\n", av7110);
151 blocks = len / BOOT_MAX_SIZE;
152 rest = len % BOOT_MAX_SIZE;
153 base = DRAM_START_CODE;
155 for (i = 0; i < blocks; i++) {
156 if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
157 printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i);
158 return -1;
160 dprintk(4, "writing DRAM block %d\n", i);
161 mwdebi(av7110, DEBISWAB, bootblock,
162 ((char*)data) + i * BOOT_MAX_SIZE, BOOT_MAX_SIZE);
163 bootblock ^= 0x1400;
164 iwdebi(av7110, DEBISWAB, BOOT_BASE, swab32(base), 4);
165 iwdebi(av7110, DEBINOSWAP, BOOT_SIZE, BOOT_MAX_SIZE, 2);
166 iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
167 base += BOOT_MAX_SIZE;
170 if (rest > 0) {
171 if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
172 printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n");
173 return -1;
175 if (rest > 4)
176 mwdebi(av7110, DEBISWAB, bootblock,
177 ((char*)data) + i * BOOT_MAX_SIZE, rest);
178 else
179 mwdebi(av7110, DEBISWAB, bootblock,
180 ((char*)data) + i * BOOT_MAX_SIZE - 4, rest + 4);
182 iwdebi(av7110, DEBISWAB, BOOT_BASE, swab32(base), 4);
183 iwdebi(av7110, DEBINOSWAP, BOOT_SIZE, rest, 2);
184 iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
186 if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
187 printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n");
188 return -1;
190 iwdebi(av7110, DEBINOSWAP, BOOT_SIZE, 0, 2);
191 iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
192 if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BOOT_COMPLETE) < 0) {
193 printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n");
194 return -1;
196 return 0;
200 /* we cannot write av7110 DRAM directly, so load a bootloader into
201 * the DPRAM which implements a simple boot protocol */
202 static u8 bootcode[] = {
203 0xea, 0x00, 0x00, 0x0e, 0xe1, 0xb0, 0xf0, 0x0e, 0xe2, 0x5e, 0xf0, 0x04,
204 0xe2, 0x5e, 0xf0, 0x04, 0xe2, 0x5e, 0xf0, 0x08, 0xe2, 0x5e, 0xf0, 0x04,
205 0xe2, 0x5e, 0xf0, 0x04, 0xe2, 0x5e, 0xf0, 0x04, 0x2c, 0x00, 0x00, 0x24,
206 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x34,
207 0x00, 0x00, 0x00, 0x00, 0xa5, 0xa5, 0x5a, 0x5a, 0x00, 0x1f, 0x15, 0x55,
208 0x00, 0x00, 0x00, 0x09, 0xe5, 0x9f, 0xd0, 0x7c, 0xe5, 0x9f, 0x40, 0x74,
209 0xe3, 0xa0, 0x00, 0x00, 0xe5, 0x84, 0x00, 0x00, 0xe5, 0x84, 0x00, 0x04,
210 0xe5, 0x9f, 0x10, 0x70, 0xe5, 0x9f, 0x20, 0x70, 0xe5, 0x9f, 0x30, 0x64,
211 0xe8, 0xb1, 0x1f, 0xe0, 0xe8, 0xa3, 0x1f, 0xe0, 0xe1, 0x51, 0x00, 0x02,
212 0xda, 0xff, 0xff, 0xfb, 0xe5, 0x9f, 0xf0, 0x50, 0xe1, 0xd4, 0x10, 0xb0,
213 0xe3, 0x51, 0x00, 0x00, 0x0a, 0xff, 0xff, 0xfc, 0xe1, 0xa0, 0x10, 0x0d,
214 0xe5, 0x94, 0x30, 0x04, 0xe1, 0xd4, 0x20, 0xb2, 0xe2, 0x82, 0x20, 0x3f,
215 0xe1, 0xb0, 0x23, 0x22, 0x03, 0xa0, 0x00, 0x02, 0xe1, 0xc4, 0x00, 0xb0,
216 0x0a, 0xff, 0xff, 0xf4, 0xe8, 0xb1, 0x1f, 0xe0, 0xe8, 0xa3, 0x1f, 0xe0,
217 0xe8, 0xb1, 0x1f, 0xe0, 0xe8, 0xa3, 0x1f, 0xe0, 0xe2, 0x52, 0x20, 0x01,
218 0x1a, 0xff, 0xff, 0xf9, 0xe2, 0x2d, 0xdb, 0x05, 0xea, 0xff, 0xff, 0xec,
219 0x2c, 0x00, 0x03, 0xf8, 0x2c, 0x00, 0x04, 0x00, 0x9e, 0x00, 0x08, 0x00,
220 0x2c, 0x00, 0x00, 0x74, 0x2c, 0x00, 0x00, 0xc0
223 int av7110_bootarm(struct av7110 *av7110)
225 struct saa7146_dev *dev = av7110->dev;
226 u32 ret;
227 int i;
229 dprintk(4, "%p\n", av7110);
231 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
233 /* Disable DEBI and GPIO irq */
234 SAA7146_IER_DISABLE(av7110->dev, MASK_03 | MASK_19);
235 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
237 /* enable DEBI */
238 saa7146_write(av7110->dev, MC1, 0x08800880);
239 saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000);
240 saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
242 /* test DEBI */
243 iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
244 if ((ret=irdebi(av7110, DEBINOSWAP, DPRAM_BASE, 0, 4)) != 0x10325476) {
245 printk(KERN_ERR "dvb-ttpci: debi test in av7110_bootarm() failed: "
246 "%08x != %08x (check your BIOS 'Plug&Play OS' settings)\n",
247 ret, 0x10325476);
248 return -1;
250 for (i = 0; i < 8192; i += 4)
251 iwdebi(av7110, DEBISWAP, DPRAM_BASE + i, 0x00, 4);
252 dprintk(2, "debi test OK\n");
254 /* boot */
255 dprintk(1, "load boot code\n");
256 saa7146_setgpio(dev, ARM_IRQ_LINE, SAA7146_GPIO_IRQLO);
257 //saa7146_setgpio(dev, DEBI_DONE_LINE, SAA7146_GPIO_INPUT);
258 //saa7146_setgpio(dev, 3, SAA7146_GPIO_INPUT);
260 mwdebi(av7110, DEBISWAB, DPRAM_BASE, bootcode, sizeof(bootcode));
261 iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
263 if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
264 printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
265 "saa7146_wait_for_debi_done() timed out\n");
266 return -1;
268 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
269 mdelay(1);
271 dprintk(1, "load dram code\n");
272 if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0) {
273 printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
274 "load_dram() failed\n");
275 return -1;
278 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
279 mdelay(1);
281 dprintk(1, "load dpram code\n");
282 mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram);
284 if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
285 printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
286 "saa7146_wait_for_debi_done() timed out after loading DRAM\n");
287 return -1;
289 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
290 msleep(30); /* the firmware needs some time to initialize */
292 //ARM_ClearIrq(av7110);
293 ARM_ResetMailBox(av7110);
294 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
295 SAA7146_IER_ENABLE(av7110->dev, MASK_03);
297 av7110->arm_errors = 0;
298 av7110->arm_ready = 1;
299 return 0;
303 /****************************************************************************
304 * DEBI command polling
305 ****************************************************************************/
307 int av7110_wait_msgstate(struct av7110 *av7110, u16 flags)
309 unsigned long start;
310 u32 stat;
312 if (FW_VERSION(av7110->arm_app) <= 0x261c) {
313 /* not supported by old firmware */
314 msleep(50);
315 return 0;
318 /* new firmware */
319 start = jiffies;
320 for (;;) {
321 if (down_interruptible(&av7110->dcomlock))
322 return -ERESTARTSYS;
323 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
324 up(&av7110->dcomlock);
325 if ((stat & flags) == 0) {
326 break;
328 if (time_after(jiffies, start + ARM_WAIT_FREE)) {
329 printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n",
330 __FUNCTION__, stat & flags);
331 return -1;
333 msleep(1);
335 return 0;
338 int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
340 int i;
341 unsigned long start;
342 char *type = NULL;
343 u16 flags[2] = {0, 0};
344 u32 stat;
346 // dprintk(4, "%p\n", av7110);
348 if (!av7110->arm_ready) {
349 dprintk(1, "arm not ready.\n");
350 return -ENXIO;
353 start = jiffies;
354 while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) {
355 msleep(1);
356 if (time_after(jiffies, start + ARM_WAIT_FREE)) {
357 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__);
358 return -ETIMEDOUT;
362 wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2);
364 #ifndef _NOHANDSHAKE
365 start = jiffies;
366 while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) {
367 msleep(1);
368 if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
369 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
370 return -ETIMEDOUT;
373 #endif
375 switch ((buf[0] >> 8) & 0xff) {
376 case COMTYPE_PIDFILTER:
377 case COMTYPE_ENCODER:
378 case COMTYPE_REC_PLAY:
379 case COMTYPE_MPEGDECODER:
380 type = "MSG";
381 flags[0] = GPMQOver;
382 flags[1] = GPMQFull;
383 break;
384 case COMTYPE_OSD:
385 type = "OSD";
386 flags[0] = OSDQOver;
387 flags[1] = OSDQFull;
388 break;
389 case COMTYPE_MISC:
390 if (FW_VERSION(av7110->arm_app) >= 0x261d) {
391 type = "MSG";
392 flags[0] = GPMQOver;
393 flags[1] = GPMQBusy;
395 break;
396 default:
397 break;
400 if (type != NULL) {
401 /* non-immediate COMMAND type */
402 start = jiffies;
403 for (;;) {
404 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
405 if (stat & flags[0]) {
406 printk(KERN_ERR "%s: %s QUEUE overflow\n",
407 __FUNCTION__, type);
408 return -1;
410 if ((stat & flags[1]) == 0)
411 break;
412 if (time_after(jiffies, start + ARM_WAIT_FREE)) {
413 printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n",
414 __FUNCTION__, type);
415 return -1;
417 msleep(1);
421 for (i = 2; i < length; i++)
422 wdebi(av7110, DEBINOSWAP, COMMAND + 2 * i, (u32) buf[i], 2);
424 if (length)
425 wdebi(av7110, DEBINOSWAP, COMMAND + 2, (u32) buf[1], 2);
426 else
427 wdebi(av7110, DEBINOSWAP, COMMAND + 2, 0, 2);
429 wdebi(av7110, DEBINOSWAP, COMMAND, (u32) buf[0], 2);
431 wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2);
433 #ifdef COM_DEBUG
434 start = jiffies;
435 while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) {
436 msleep(1);
437 if (time_after(jiffies, start + ARM_WAIT_FREE)) {
438 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND to complete\n",
439 __FUNCTION__);
440 return -ETIMEDOUT;
444 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
445 if (stat & GPMQOver) {
446 printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __FUNCTION__);
447 return -ENOSPC;
449 else if (stat & OSDQOver) {
450 printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __FUNCTION__);
451 return -ENOSPC;
453 #endif
455 return 0;
458 int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
460 int ret;
462 // dprintk(4, "%p\n", av7110);
464 if (!av7110->arm_ready) {
465 dprintk(1, "arm not ready.\n");
466 return -1;
468 if (down_interruptible(&av7110->dcomlock))
469 return -ERESTARTSYS;
471 ret = __av7110_send_fw_cmd(av7110, buf, length);
472 up(&av7110->dcomlock);
473 if (ret)
474 printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
475 __FUNCTION__, ret);
476 return ret;
479 int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...)
481 va_list args;
482 u16 buf[num + 2];
483 int i, ret;
485 // dprintk(4, "%p\n", av7110);
487 buf[0] = ((type << 8) | com);
488 buf[1] = num;
490 if (num) {
491 va_start(args, num);
492 for (i = 0; i < num; i++)
493 buf[i + 2] = va_arg(args, u32);
494 va_end(args);
497 ret = av7110_send_fw_cmd(av7110, buf, num + 2);
498 if (ret)
499 printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret);
500 return ret;
503 int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len)
505 int i, ret;
506 u16 cmd[18] = { ((COMTYPE_COMMON_IF << 8) + subcom),
507 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
509 dprintk(4, "%p\n", av7110);
511 for(i = 0; i < len && i < 32; i++)
513 if(i % 2 == 0)
514 cmd[(i / 2) + 2] = (u16)(buf[i]) << 8;
515 else
516 cmd[(i / 2) + 2] |= buf[i];
519 ret = av7110_send_fw_cmd(av7110, cmd, 18);
520 if (ret)
521 printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret);
522 return ret;
525 int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
526 int request_buf_len, u16 *reply_buf, int reply_buf_len)
528 int err;
529 s16 i;
530 unsigned long start;
531 #ifdef COM_DEBUG
532 u32 stat;
533 #endif
535 dprintk(4, "%p\n", av7110);
537 if (!av7110->arm_ready) {
538 dprintk(1, "arm not ready.\n");
539 return -1;
542 if (down_interruptible(&av7110->dcomlock))
543 return -ERESTARTSYS;
545 if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) {
546 up(&av7110->dcomlock);
547 printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err);
548 return err;
551 start = jiffies;
552 while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2)) {
553 #ifdef _NOHANDSHAKE
554 msleep(1);
555 #endif
556 if (time_after(jiffies, start + ARM_WAIT_FREE)) {
557 printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __FUNCTION__);
558 up(&av7110->dcomlock);
559 return -1;
563 #ifndef _NOHANDSHAKE
564 start = jiffies;
565 while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) {
566 msleep(1);
567 if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
568 printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
569 up(&av7110->dcomlock);
570 return -1;
573 #endif
575 #ifdef COM_DEBUG
576 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
577 if (stat & GPMQOver) {
578 printk(KERN_ERR "%s: GPMQOver\n", __FUNCTION__);
579 up(&av7110->dcomlock);
580 return -1;
582 else if (stat & OSDQOver) {
583 printk(KERN_ERR "%s: OSDQOver\n", __FUNCTION__);
584 up(&av7110->dcomlock);
585 return -1;
587 #endif
589 for (i = 0; i < reply_buf_len; i++)
590 reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2);
592 up(&av7110->dcomlock);
593 return 0;
596 int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length)
598 int ret;
599 ret = av7110_fw_request(av7110, &tag, 0, buf, length);
600 if (ret)
601 printk(KERN_ERR "dvb-ttpci: av7110_fw_query error %d\n", ret);
602 return ret;
606 /****************************************************************************
607 * Firmware commands
608 ****************************************************************************/
610 /* get version of the firmware ROM, RTSL, video ucode and ARM application */
611 int av7110_firmversion(struct av7110 *av7110)
613 u16 buf[20];
614 u16 tag = ((COMTYPE_REQUEST << 8) + ReqVersion);
616 dprintk(4, "%p\n", av7110);
618 if (av7110_fw_query(av7110, tag, buf, 16)) {
619 printk("dvb-ttpci: failed to boot firmware @ card %d\n",
620 av7110->dvb_adapter->num);
621 return -EIO;
624 av7110->arm_fw = (buf[0] << 16) + buf[1];
625 av7110->arm_rtsl = (buf[2] << 16) + buf[3];
626 av7110->arm_vid = (buf[4] << 16) + buf[5];
627 av7110->arm_app = (buf[6] << 16) + buf[7];
628 av7110->avtype = (buf[8] << 16) + buf[9];
630 printk("dvb-ttpci: info @ card %d: firm %08x, rtsl %08x, vid %08x, app %08x\n",
631 av7110->dvb_adapter->num, av7110->arm_fw,
632 av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app);
634 /* print firmware capabilities */
635 if (FW_CI_LL_SUPPORT(av7110->arm_app))
636 printk("dvb-ttpci: firmware @ card %d supports CI link layer interface\n",
637 av7110->dvb_adapter->num);
638 else
639 printk("dvb-ttpci: no firmware support for CI link layer interface @ card %d\n",
640 av7110->dvb_adapter->num);
642 return 0;
646 int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst)
648 int i, ret;
649 u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) + SendDiSEqC),
650 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
652 dprintk(4, "%p\n", av7110);
654 if (len > 10)
655 len = 10;
657 buf[1] = len + 2;
658 buf[2] = len;
660 if (burst != -1)
661 buf[3] = burst ? 0x01 : 0x00;
662 else
663 buf[3] = 0xffff;
665 for (i = 0; i < len; i++)
666 buf[i + 4] = msg[i];
668 if ((ret = av7110_send_fw_cmd(av7110, buf, 18)))
669 printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret);
671 return 0;
675 #ifdef CONFIG_DVB_AV7110_OSD
677 static inline int SetColorBlend(struct av7110 *av7110, u8 windownr)
679 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetCBlend, 1, windownr);
682 static inline int SetBlend_(struct av7110 *av7110, u8 windownr,
683 enum av7110_osd_palette_type colordepth, u16 index, u8 blending)
685 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetBlend, 4,
686 windownr, colordepth, index, blending);
689 static inline int SetColor_(struct av7110 *av7110, u8 windownr,
690 enum av7110_osd_palette_type colordepth, u16 index, u16 colorhi, u16 colorlo)
692 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetColor, 5,
693 windownr, colordepth, index, colorhi, colorlo);
696 static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize,
697 u16 colorfg, u16 colorbg)
699 return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Font, 4,
700 windownr, fontsize, colorfg, colorbg);
703 static int FlushText(struct av7110 *av7110)
705 unsigned long start;
707 if (down_interruptible(&av7110->dcomlock))
708 return -ERESTARTSYS;
709 start = jiffies;
710 while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) {
711 msleep(1);
712 if (time_after(jiffies, start + ARM_WAIT_OSD)) {
713 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n",
714 __FUNCTION__);
715 up(&av7110->dcomlock);
716 return -1;
719 up(&av7110->dcomlock);
720 return 0;
723 static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
725 int i, ret;
726 unsigned long start;
727 int length = strlen(buf) + 1;
728 u16 cbuf[5] = { (COMTYPE_OSD << 8) + DText, 3, win, x, y };
730 if (down_interruptible(&av7110->dcomlock))
731 return -ERESTARTSYS;
733 start = jiffies;
734 while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) {
735 msleep(1);
736 if (time_after(jiffies, start + ARM_WAIT_OSD)) {
737 printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n",
738 __FUNCTION__);
739 up(&av7110->dcomlock);
740 return -1;
743 #ifndef _NOHANDSHAKE
744 start = jiffies;
745 while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2)) {
746 msleep(1);
747 if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
748 printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n",
749 __FUNCTION__);
750 up(&av7110->dcomlock);
751 return -1;
754 #endif
755 for (i = 0; i < length / 2; i++)
756 wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2,
757 swab16(*(u16 *)(buf + 2 * i)), 2);
758 if (length & 1)
759 wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2);
760 ret = __av7110_send_fw_cmd(av7110, cbuf, 5);
761 up(&av7110->dcomlock);
762 if (ret)
763 printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret);
764 return ret;
767 static inline int DrawLine(struct av7110 *av7110, u8 windownr,
768 u16 x, u16 y, u16 dx, u16 dy, u16 color)
770 return av7110_fw_cmd(av7110, COMTYPE_OSD, DLine, 6,
771 windownr, x, y, dx, dy, color);
774 static inline int DrawBlock(struct av7110 *av7110, u8 windownr,
775 u16 x, u16 y, u16 dx, u16 dy, u16 color)
777 return av7110_fw_cmd(av7110, COMTYPE_OSD, DBox, 6,
778 windownr, x, y, dx, dy, color);
781 static inline int HideWindow(struct av7110 *av7110, u8 windownr)
783 return av7110_fw_cmd(av7110, COMTYPE_OSD, WHide, 1, windownr);
786 static inline int MoveWindowRel(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
788 return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveD, 3, windownr, x, y);
791 static inline int MoveWindowAbs(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
793 return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveA, 3, windownr, x, y);
796 static inline int DestroyOSDWindow(struct av7110 *av7110, u8 windownr)
798 return av7110_fw_cmd(av7110, COMTYPE_OSD, WDestroy, 1, windownr);
801 static inline int CreateOSDWindow(struct av7110 *av7110, u8 windownr,
802 osd_raw_window_t disptype,
803 u16 width, u16 height)
805 return av7110_fw_cmd(av7110, COMTYPE_OSD, WCreate, 4,
806 windownr, disptype, width, height);
810 static enum av7110_osd_palette_type bpp2pal[8] = {
811 Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit
813 static osd_raw_window_t bpp2bit[8] = {
814 OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8
817 static inline int LoadBitmap(struct av7110 *av7110, u16 format,
818 u16 dx, u16 dy, int inc, u8 __user * data)
820 int bpp;
821 int i;
822 int d, delta;
823 u8 c;
824 int ret;
826 dprintk(4, "%p\n", av7110);
828 ret = wait_event_interruptible_timeout(av7110->bmpq, av7110->bmp_state != BMP_LOADING, HZ);
829 if (ret == -ERESTARTSYS || ret == 0) {
830 printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n",
831 ret, av7110->bmp_state);
832 av7110->bmp_state = BMP_NONE;
833 return -1;
835 BUG_ON (av7110->bmp_state == BMP_LOADING);
837 av7110->bmp_state = BMP_LOADING;
838 if (format == OSD_BITMAP8) {
839 bpp=8; delta = 1;
840 } else if (format == OSD_BITMAP4) {
841 bpp=4; delta = 2;
842 } else if (format == OSD_BITMAP2) {
843 bpp=2; delta = 4;
844 } else if (format == OSD_BITMAP1) {
845 bpp=1; delta = 8;
846 } else {
847 av7110->bmp_state = BMP_NONE;
848 return -1;
850 av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8;
851 av7110->bmpp = 0;
852 if (av7110->bmplen > 32768) {
853 av7110->bmp_state = BMP_NONE;
854 return -1;
856 for (i = 0; i < dy; i++) {
857 if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) {
858 av7110->bmp_state = BMP_NONE;
859 return -1;
862 if (format != OSD_BITMAP8) {
863 for (i = 0; i < dx * dy / delta; i++) {
864 c = ((u8 *)av7110->bmpbuf)[1024 + i * delta + delta - 1];
865 for (d = delta - 2; d >= 0; d--) {
866 c |= (((u8 *)av7110->bmpbuf)[1024 + i * delta + d]
867 << ((delta - d - 1) * bpp));
868 ((u8 *)av7110->bmpbuf)[1024 + i] = c;
872 av7110->bmplen += 1024;
873 dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen);
874 return av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
877 static int BlitBitmap(struct av7110 *av7110, u16 win, u16 x, u16 y, u16 trans)
879 int ret;
881 dprintk(4, "%p\n", av7110);
883 BUG_ON (av7110->bmp_state == BMP_NONE);
885 ret = wait_event_interruptible_timeout(av7110->bmpq,
886 av7110->bmp_state != BMP_LOADING, 10*HZ);
887 if (ret == -ERESTARTSYS || ret == 0) {
888 printk("dvb-ttpci: warning: timeout waiting in BlitBitmap: %d, %d\n",
889 ret, av7110->bmp_state);
890 av7110->bmp_state = BMP_NONE;
891 return (ret == 0) ? -ETIMEDOUT : ret;
894 BUG_ON (av7110->bmp_state != BMP_LOADED);
896 return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, win, x, y, trans);
899 static inline int ReleaseBitmap(struct av7110 *av7110)
901 dprintk(4, "%p\n", av7110);
903 if (av7110->bmp_state != BMP_LOADED)
904 return -1;
905 av7110->bmp_state = BMP_NONE;
906 return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0);
909 static u32 RGB2YUV(u16 R, u16 G, u16 B)
911 u16 y, u, v;
912 u16 Y, Cr, Cb;
914 y = R * 77 + G * 150 + B * 29; /* Luma=0.299R+0.587G+0.114B 0..65535 */
915 u = 2048 + B * 8 -(y >> 5); /* Cr 0..4095 */
916 v = 2048 + R * 8 -(y >> 5); /* Cb 0..4095 */
918 Y = y / 256;
919 Cb = u / 16;
920 Cr = v / 16;
922 return Cr | (Cb << 16) | (Y << 8);
925 static void OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
927 u16 ch, cl;
928 u32 yuv;
930 yuv = blend ? RGB2YUV(r,g,b) : 0;
931 cl = (yuv & 0xffff);
932 ch = ((yuv >> 16) & 0xffff);
933 SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
934 color, ch, cl);
935 SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
936 color, ((blend >> 4) & 0x0f));
939 static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last)
941 int i;
942 int length = last - first + 1;
944 if (length * 4 > DATA_BUFF3_SIZE)
945 return -EINVAL;
947 for (i = 0; i < length; i++) {
948 u32 color, blend, yuv;
950 if (get_user(color, colors + i))
951 return -EFAULT;
952 blend = (color & 0xF0000000) >> 4;
953 yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF,
954 (color >> 16) & 0xFF) | blend : 0;
955 yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16);
956 wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4);
958 return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4,
959 av7110->osdwin,
960 bpp2pal[av7110->osdbpp[av7110->osdwin]],
961 first, last);
964 static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
965 int x1, int y1, int inc, u8 __user * data)
967 uint w, h, bpp, bpl, size, lpb, bnum, brest;
968 int i;
969 int rc;
971 w = x1 - x0 + 1;
972 h = y1 - y0 + 1;
973 if (inc <= 0)
974 inc = w;
975 if (w <= 0 || w > 720 || h <= 0 || h > 576)
976 return -1;
977 bpp = av7110->osdbpp[av7110->osdwin] + 1;
978 bpl = ((w * bpp + 7) & ~7) / 8;
979 size = h * bpl;
980 lpb = (32 * 1024) / bpl;
981 bnum = size / (lpb * bpl);
982 brest = size - bnum * lpb * bpl;
984 for (i = 0; i < bnum; i++) {
985 rc = LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]],
986 w, lpb, inc, data);
987 if (rc)
988 return rc;
989 rc = BlitBitmap(av7110, av7110->osdwin, x0, y0 + i * lpb, 0);
990 if (rc)
991 return rc;
992 data += lpb * inc;
994 if (brest) {
995 rc = LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]],
996 w, brest / bpl, inc, data);
997 if (rc)
998 return rc;
999 rc = BlitBitmap(av7110, av7110->osdwin, x0, y0 + bnum * lpb, 0);
1000 if (rc)
1001 return rc;
1003 ReleaseBitmap(av7110);
1004 return 0;
1007 int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
1009 int ret;
1011 ret = down_interruptible(&av7110->osd_sema);
1012 if (ret)
1013 return -ERESTARTSYS;
1015 /* stupid, but OSD functions don't provide a return code anyway */
1016 ret = 0;
1018 switch (dc->cmd) {
1019 case OSD_Close:
1020 DestroyOSDWindow(av7110, av7110->osdwin);
1021 goto out;
1022 case OSD_Open:
1023 av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7;
1024 CreateOSDWindow(av7110, av7110->osdwin,
1025 bpp2bit[av7110->osdbpp[av7110->osdwin]],
1026 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
1027 if (!dc->data) {
1028 MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1029 SetColorBlend(av7110, av7110->osdwin);
1031 goto out;
1032 case OSD_Show:
1033 MoveWindowRel(av7110, av7110->osdwin, 0, 0);
1034 goto out;
1035 case OSD_Hide:
1036 HideWindow(av7110, av7110->osdwin);
1037 goto out;
1038 case OSD_Clear:
1039 DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
1040 goto out;
1041 case OSD_Fill:
1042 DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
1043 goto out;
1044 case OSD_SetColor:
1045 OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
1046 goto out;
1047 case OSD_SetPalette:
1049 if (FW_VERSION(av7110->arm_app) >= 0x2618) {
1050 ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0);
1051 goto out;
1052 } else {
1053 int i, len = dc->x0-dc->color+1;
1054 u8 __user *colors = (u8 __user *)dc->data;
1055 u8 r, g, b, blend;
1057 for (i = 0; i<len; i++) {
1058 if (get_user(r, colors + i * 4) ||
1059 get_user(g, colors + i * 4 + 1) ||
1060 get_user(b, colors + i * 4 + 2) ||
1061 get_user(blend, colors + i * 4 + 3)) {
1062 ret = -EFAULT;
1063 goto out;
1065 OSDSetColor(av7110, dc->color + i, r, g, b, blend);
1068 ret = 0;
1069 goto out;
1071 case OSD_SetTrans:
1072 goto out;
1073 case OSD_SetPixel:
1074 DrawLine(av7110, av7110->osdwin,
1075 dc->x0, dc->y0, 0, 0, dc->color);
1076 goto out;
1077 case OSD_GetPixel:
1078 goto out;
1079 case OSD_SetRow:
1080 dc->y1 = dc->y0;
1081 /* fall through */
1082 case OSD_SetBlock:
1083 ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data);
1084 goto out;
1085 case OSD_FillRow:
1086 DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
1087 dc->x1-dc->x0+1, dc->y1, dc->color);
1088 goto out;
1089 case OSD_FillBlock:
1090 DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
1091 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color);
1092 goto out;
1093 case OSD_Line:
1094 DrawLine(av7110, av7110->osdwin,
1095 dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color);
1096 goto out;
1097 case OSD_Query:
1098 goto out;
1099 case OSD_Test:
1100 goto out;
1101 case OSD_Text:
1103 char textbuf[240];
1105 if (strncpy_from_user(textbuf, dc->data, 240) < 0) {
1106 ret = -EFAULT;
1107 goto out;
1109 textbuf[239] = 0;
1110 if (dc->x1 > 3)
1111 dc->x1 = 3;
1112 SetFont(av7110, av7110->osdwin, dc->x1,
1113 (u16) (dc->color & 0xffff), (u16) (dc->color >> 16));
1114 FlushText(av7110);
1115 WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
1116 goto out;
1118 case OSD_SetWindow:
1119 if (dc->x0 < 1 || dc->x0 > 7) {
1120 ret = -EINVAL;
1121 goto out;
1123 av7110->osdwin = dc->x0;
1124 goto out;
1125 case OSD_MoveWindow:
1126 MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1127 SetColorBlend(av7110, av7110->osdwin);
1128 goto out;
1129 case OSD_OpenRaw:
1130 if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) {
1131 ret = -EINVAL;
1132 goto out;
1134 if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR) {
1135 av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1;
1137 else {
1138 av7110->osdbpp[av7110->osdwin] = 0;
1140 CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color,
1141 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
1142 if (!dc->data) {
1143 MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1144 SetColorBlend(av7110, av7110->osdwin);
1146 goto out;
1147 default:
1148 ret = -EINVAL;
1149 goto out;
1152 out:
1153 up(&av7110->osd_sema);
1154 return ret;
1157 int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap)
1159 switch (cap->cmd) {
1160 case OSD_CAP_MEMSIZE:
1161 if (FW_4M_SDRAM(av7110->arm_app))
1162 cap->val = 1000000;
1163 else
1164 cap->val = 92000;
1165 return 0;
1166 default:
1167 return -EINVAL;
1170 #endif /* CONFIG_DVB_AV7110_OSD */