1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * av7110_hw.c: av7110 low level hardware access and firmware interface
5 * Copyright (C) 1999-2002 Ralph Metzler
6 * & Marcus Metzler for convergence integrated media GmbH
8 * originally based on code by:
9 * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
11 * the project's page is at https://linuxtv.org
14 /* for debugging ARM communication: */
17 #include <linux/types.h>
18 #include <linux/kernel.h>
19 #include <linux/string.h>
20 #include <linux/delay.h>
24 #include "av7110_hw.h"
29 * Max transfer size done by av7110_fw_cmd()
31 * The maximum size passed to this function is 6 bytes. The buffer also
32 * uses two additional ones for type and size. So, 8 bytes is enough.
34 #define MAX_XFER_SIZE 8
36 /****************************************************************************
38 ****************************************************************************/
40 /* This DEBI code is based on the Stradis driver
41 by Nathan Laredo <laredo@gnu.org> */
43 int av7110_debiwrite(struct av7110 *av7110, u32 config,
44 int addr, u32 val, unsigned int count)
46 struct saa7146_dev *dev = av7110->dev;
49 printk("%s: invalid count %d\n", __func__, count);
52 if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
53 printk("%s: wait_for_debi_done failed\n", __func__);
56 saa7146_write(dev, DEBI_CONFIG, config);
57 if (count <= 4) /* immediate transfer */
58 saa7146_write(dev, DEBI_AD, val);
59 else /* block transfer */
60 saa7146_write(dev, DEBI_AD, av7110->debi_bus);
61 saa7146_write(dev, DEBI_COMMAND, (count << 17) | (addr & 0xffff));
62 saa7146_write(dev, MC2, (2 << 16) | 2);
66 u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, unsigned int count)
68 struct saa7146_dev *dev = av7110->dev;
72 printk("%s: invalid count %d\n", __func__, count);
75 if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
76 printk("%s: wait_for_debi_done #1 failed\n", __func__);
79 saa7146_write(dev, DEBI_AD, av7110->debi_bus);
80 saa7146_write(dev, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
82 saa7146_write(dev, DEBI_CONFIG, config);
83 saa7146_write(dev, MC2, (2 << 16) | 2);
86 if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
87 printk("%s: wait_for_debi_done #2 failed\n", __func__);
91 result = saa7146_read(dev, DEBI_AD);
92 result &= (0xffffffffUL >> ((4 - count) * 8));
98 /* av7110 ARM core boot stuff */
100 void av7110_reset_arm(struct av7110 *av7110)
102 saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTLO);
104 /* Disable DEBI and GPIO irq */
105 SAA7146_IER_DISABLE(av7110->dev, MASK_19 | MASK_03);
106 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
108 saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTHI);
109 msleep(30); /* the firmware needs some time to initialize */
111 ARM_ResetMailBox(av7110);
113 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
114 SAA7146_IER_ENABLE(av7110->dev, MASK_03);
116 av7110->arm_ready = 1;
117 dprintk(1, "reset ARM\n");
121 static int waitdebi(struct av7110 *av7110, int adr, int state)
125 dprintk(4, "%p\n", av7110);
127 for (k = 0; k < 100; k++) {
128 if (irdebi(av7110, DEBINOSWAP, adr, 0, 2) == state)
135 static int load_dram(struct av7110 *av7110, u32 *data, int len)
139 u32 base, bootblock = AV7110_BOOT_BLOCK;
141 dprintk(4, "%p\n", av7110);
143 blocks = len / AV7110_BOOT_MAX_SIZE;
144 rest = len % AV7110_BOOT_MAX_SIZE;
145 base = DRAM_START_CODE;
147 for (i = 0; i < blocks; i++) {
148 if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
149 printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i);
152 dprintk(4, "writing DRAM block %d\n", i);
153 mwdebi(av7110, DEBISWAB, bootblock,
154 ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
156 iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
157 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2);
158 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
159 base += AV7110_BOOT_MAX_SIZE;
163 if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
164 printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n");
168 mwdebi(av7110, DEBISWAB, bootblock,
169 ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, rest);
171 mwdebi(av7110, DEBISWAB, bootblock,
172 ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);
174 iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
175 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2);
176 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
178 if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
179 printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n");
182 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, 0, 2);
183 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
184 if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_AV7110_BOOT_COMPLETE) < 0) {
185 printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n");
192 /* we cannot write av7110 DRAM directly, so load a bootloader into
193 * the DPRAM which implements a simple boot protocol */
194 int av7110_bootarm(struct av7110 *av7110)
196 const struct firmware *fw;
197 const char *fw_name = "av7110/bootcode.bin";
198 struct saa7146_dev *dev = av7110->dev;
202 dprintk(4, "%p\n", av7110);
204 av7110->arm_ready = 0;
206 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
208 /* Disable DEBI and GPIO irq */
209 SAA7146_IER_DISABLE(av7110->dev, MASK_03 | MASK_19);
210 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
213 saa7146_write(av7110->dev, MC1, 0x08800880);
214 saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000);
215 saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
218 iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
219 /* FIXME: Why does Nexus CA require 2x iwdebi for first init? */
220 iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
222 if ((ret=irdebi(av7110, DEBINOSWAP, DPRAM_BASE, 0, 4)) != 0x10325476) {
223 printk(KERN_ERR "dvb-ttpci: debi test in av7110_bootarm() failed: %08x != %08x (check your BIOS 'Plug&Play OS' settings)\n",
227 for (i = 0; i < 8192; i += 4)
228 iwdebi(av7110, DEBISWAP, DPRAM_BASE + i, 0x00, 4);
229 dprintk(2, "debi test OK\n");
232 dprintk(1, "load boot code\n");
233 saa7146_setgpio(dev, ARM_IRQ_LINE, SAA7146_GPIO_IRQLO);
234 //saa7146_setgpio(dev, DEBI_DONE_LINE, SAA7146_GPIO_INPUT);
235 //saa7146_setgpio(dev, 3, SAA7146_GPIO_INPUT);
237 ret = request_firmware(&fw, fw_name, &dev->pci->dev);
239 printk(KERN_ERR "dvb-ttpci: Failed to load firmware \"%s\"\n",
244 mwdebi(av7110, DEBISWAB, DPRAM_BASE, fw->data, fw->size);
245 release_firmware(fw);
246 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
248 if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
249 printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): saa7146_wait_for_debi_done() timed out\n");
252 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
255 dprintk(1, "load dram code\n");
256 if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0) {
257 printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): load_dram() failed\n");
261 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
264 dprintk(1, "load dpram code\n");
265 mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram);
267 if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
268 printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): saa7146_wait_for_debi_done() timed out after loading DRAM\n");
271 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
272 msleep(30); /* the firmware needs some time to initialize */
274 //ARM_ClearIrq(av7110);
275 ARM_ResetMailBox(av7110);
276 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
277 SAA7146_IER_ENABLE(av7110->dev, MASK_03);
279 av7110->arm_errors = 0;
280 av7110->arm_ready = 1;
283 MODULE_FIRMWARE("av7110/bootcode.bin");
285 /****************************************************************************
286 * DEBI command polling
287 ****************************************************************************/
289 int av7110_wait_msgstate(struct av7110 *av7110, u16 flags)
295 if (FW_VERSION(av7110->arm_app) <= 0x261c) {
296 /* not supported by old firmware */
304 err = time_after(jiffies, start + ARM_WAIT_FREE);
305 if (mutex_lock_interruptible(&av7110->dcomlock))
307 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
308 mutex_unlock(&av7110->dcomlock);
309 if ((stat & flags) == 0)
312 printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n",
313 __func__, stat & flags);
321 static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
326 u16 flags[2] = {0, 0};
330 // dprintk(4, "%p\n", av7110);
332 if (!av7110->arm_ready) {
333 dprintk(1, "arm not ready.\n");
339 err = time_after(jiffies, start + ARM_WAIT_FREE);
340 if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
343 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __func__);
344 av7110->arm_errors++;
350 if (FW_VERSION(av7110->arm_app) <= 0x261f)
351 wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2);
356 err = time_after(jiffies, start + ARM_WAIT_SHAKE);
357 if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
360 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __func__);
367 switch ((buf[0] >> 8) & 0xff) {
368 case COMTYPE_PIDFILTER:
369 case COMTYPE_ENCODER:
370 case COMTYPE_REC_PLAY:
371 case COMTYPE_MPEGDECODER:
382 if (FW_VERSION(av7110->arm_app) >= 0x261d) {
393 /* non-immediate COMMAND type */
396 err = time_after(jiffies, start + ARM_WAIT_FREE);
397 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
398 if (stat & flags[0]) {
399 printk(KERN_ERR "%s: %s QUEUE overflow\n",
403 if ((stat & flags[1]) == 0)
406 printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n",
408 av7110->arm_errors++;
415 for (i = 2; i < length; i++)
416 wdebi(av7110, DEBINOSWAP, COMMAND + 2 * i, (u32) buf[i], 2);
419 wdebi(av7110, DEBINOSWAP, COMMAND + 2, (u32) buf[1], 2);
421 wdebi(av7110, DEBINOSWAP, COMMAND + 2, 0, 2);
423 wdebi(av7110, DEBINOSWAP, COMMAND, (u32) buf[0], 2);
425 if (FW_VERSION(av7110->arm_app) <= 0x261f)
426 wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2);
431 err = time_after(jiffies, start + ARM_WAIT_FREE);
432 if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
435 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n",
436 __func__, (buf[0] >> 8) & 0xff);
442 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
443 if (stat & GPMQOver) {
444 printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __func__);
447 else if (stat & OSDQOver) {
448 printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __func__);
456 static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
460 // dprintk(4, "%p\n", av7110);
462 if (!av7110->arm_ready) {
463 dprintk(1, "arm not ready.\n");
466 if (mutex_lock_interruptible(&av7110->dcomlock))
469 ret = __av7110_send_fw_cmd(av7110, buf, length);
470 mutex_unlock(&av7110->dcomlock);
471 if (ret && ret!=-ERESTARTSYS)
472 printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
477 int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...)
480 u16 buf[MAX_XFER_SIZE];
483 // dprintk(4, "%p\n", av7110);
485 if (2 + num > ARRAY_SIZE(buf)) {
487 "%s: %s len=%d is too big!\n",
488 KBUILD_MODNAME, __func__, num);
492 buf[0] = ((type << 8) | com);
497 for (i = 0; i < num; i++)
498 buf[i + 2] = va_arg(args, u32);
502 ret = av7110_send_fw_cmd(av7110, buf, num + 2);
503 if (ret && ret != -ERESTARTSYS)
504 printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret);
509 int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len)
512 u16 cmd[18] = { ((COMTYPE_COMMON_IF << 8) + subcom),
513 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
515 dprintk(4, "%p\n", av7110);
517 for(i = 0; i < len && i < 32; i++)
520 cmd[(i / 2) + 2] = (u16)(buf[i]) << 8;
522 cmd[(i / 2) + 2] |= buf[i];
525 ret = av7110_send_fw_cmd(av7110, cmd, 18);
526 if (ret && ret != -ERESTARTSYS)
527 printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret);
532 int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
533 int request_buf_len, u16 *reply_buf, int reply_buf_len)
542 dprintk(4, "%p\n", av7110);
544 if (!av7110->arm_ready) {
545 dprintk(1, "arm not ready.\n");
549 if (mutex_lock_interruptible(&av7110->dcomlock))
552 if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) {
553 mutex_unlock(&av7110->dcomlock);
554 printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err);
560 err = time_after(jiffies, start + ARM_WAIT_FREE);
561 if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
564 printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __func__);
565 mutex_unlock(&av7110->dcomlock);
576 err = time_after(jiffies, start + ARM_WAIT_SHAKE);
577 if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
580 printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __func__);
581 mutex_unlock(&av7110->dcomlock);
589 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
590 if (stat & GPMQOver) {
591 printk(KERN_ERR "%s: GPMQOver\n", __func__);
592 mutex_unlock(&av7110->dcomlock);
595 else if (stat & OSDQOver) {
596 printk(KERN_ERR "%s: OSDQOver\n", __func__);
597 mutex_unlock(&av7110->dcomlock);
602 for (i = 0; i < reply_buf_len; i++)
603 reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2);
605 mutex_unlock(&av7110->dcomlock);
609 static int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length)
612 ret = av7110_fw_request(av7110, &tag, 0, buf, length);
614 printk(KERN_ERR "dvb-ttpci: av7110_fw_query error %d\n", ret);
619 /****************************************************************************
621 ****************************************************************************/
623 /* get version of the firmware ROM, RTSL, video ucode and ARM application */
624 int av7110_firmversion(struct av7110 *av7110)
627 u16 tag = ((COMTYPE_REQUEST << 8) + ReqVersion);
629 dprintk(4, "%p\n", av7110);
631 if (av7110_fw_query(av7110, tag, buf, 16)) {
632 printk("dvb-ttpci: failed to boot firmware @ card %d\n",
633 av7110->dvb_adapter.num);
637 av7110->arm_fw = (buf[0] << 16) + buf[1];
638 av7110->arm_rtsl = (buf[2] << 16) + buf[3];
639 av7110->arm_vid = (buf[4] << 16) + buf[5];
640 av7110->arm_app = (buf[6] << 16) + buf[7];
641 av7110->avtype = (buf[8] << 16) + buf[9];
643 printk("dvb-ttpci: info @ card %d: firm %08x, rtsl %08x, vid %08x, app %08x\n",
644 av7110->dvb_adapter.num, av7110->arm_fw,
645 av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app);
647 /* print firmware capabilities */
648 if (FW_CI_LL_SUPPORT(av7110->arm_app))
649 printk("dvb-ttpci: firmware @ card %d supports CI link layer interface\n",
650 av7110->dvb_adapter.num);
652 printk("dvb-ttpci: no firmware support for CI link layer interface @ card %d\n",
653 av7110->dvb_adapter.num);
659 int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst)
662 u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) + SendDiSEqC),
663 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
665 dprintk(4, "%p\n", av7110);
674 buf[3] = burst ? 0x01 : 0x00;
678 for (i = 0; i < len; i++)
681 ret = av7110_send_fw_cmd(av7110, buf, 18);
682 if (ret && ret!=-ERESTARTSYS)
683 printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret);
688 #ifdef CONFIG_DVB_AV7110_OSD
690 static inline int SetColorBlend(struct av7110 *av7110, u8 windownr)
692 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetCBlend, 1, windownr);
695 static inline int SetBlend_(struct av7110 *av7110, u8 windownr,
696 enum av7110_osd_palette_type colordepth, u16 index, u8 blending)
698 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetBlend, 4,
699 windownr, colordepth, index, blending);
702 static inline int SetColor_(struct av7110 *av7110, u8 windownr,
703 enum av7110_osd_palette_type colordepth, u16 index, u16 colorhi, u16 colorlo)
705 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetColor, 5,
706 windownr, colordepth, index, colorhi, colorlo);
709 static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize,
710 u16 colorfg, u16 colorbg)
712 return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Font, 4,
713 windownr, fontsize, colorfg, colorbg);
716 static int FlushText(struct av7110 *av7110)
721 if (mutex_lock_interruptible(&av7110->dcomlock))
725 err = time_after(jiffies, start + ARM_WAIT_OSD);
726 if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
729 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n",
731 mutex_unlock(&av7110->dcomlock);
736 mutex_unlock(&av7110->dcomlock);
740 static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, char *buf)
744 int length = strlen(buf) + 1;
745 u16 cbuf[5] = { (COMTYPE_OSD << 8) + DText, 3, win, x, y };
747 if (mutex_lock_interruptible(&av7110->dcomlock))
752 ret = time_after(jiffies, start + ARM_WAIT_OSD);
753 if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
756 printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n",
758 mutex_unlock(&av7110->dcomlock);
766 ret = time_after(jiffies, start + ARM_WAIT_SHAKE);
767 if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
770 printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n",
772 mutex_unlock(&av7110->dcomlock);
778 for (i = 0; i < length / 2; i++)
779 wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2,
780 swab16(*(u16 *)(buf + 2 * i)), 2);
782 wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2);
783 ret = __av7110_send_fw_cmd(av7110, cbuf, 5);
784 mutex_unlock(&av7110->dcomlock);
785 if (ret && ret!=-ERESTARTSYS)
786 printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret);
790 static inline int DrawLine(struct av7110 *av7110, u8 windownr,
791 u16 x, u16 y, u16 dx, u16 dy, u16 color)
793 return av7110_fw_cmd(av7110, COMTYPE_OSD, DLine, 6,
794 windownr, x, y, dx, dy, color);
797 static inline int DrawBlock(struct av7110 *av7110, u8 windownr,
798 u16 x, u16 y, u16 dx, u16 dy, u16 color)
800 return av7110_fw_cmd(av7110, COMTYPE_OSD, DBox, 6,
801 windownr, x, y, dx, dy, color);
804 static inline int HideWindow(struct av7110 *av7110, u8 windownr)
806 return av7110_fw_cmd(av7110, COMTYPE_OSD, WHide, 1, windownr);
809 static inline int MoveWindowRel(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
811 return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveD, 3, windownr, x, y);
814 static inline int MoveWindowAbs(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
816 return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveA, 3, windownr, x, y);
819 static inline int DestroyOSDWindow(struct av7110 *av7110, u8 windownr)
821 return av7110_fw_cmd(av7110, COMTYPE_OSD, WDestroy, 1, windownr);
824 static inline int CreateOSDWindow(struct av7110 *av7110, u8 windownr,
825 osd_raw_window_t disptype,
826 u16 width, u16 height)
828 return av7110_fw_cmd(av7110, COMTYPE_OSD, WCreate, 4,
829 windownr, disptype, width, height);
833 static enum av7110_osd_palette_type bpp2pal[8] = {
834 Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit
836 static osd_raw_window_t bpp2bit[8] = {
837 OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8
840 static inline int WaitUntilBmpLoaded(struct av7110 *av7110)
842 int ret = wait_event_timeout(av7110->bmpq,
843 av7110->bmp_state != BMP_LOADING, 10*HZ);
845 printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n",
846 ret, av7110->bmp_state);
847 av7110->bmp_state = BMP_NONE;
853 static inline int LoadBitmap(struct av7110 *av7110,
854 u16 dx, u16 dy, int inc, u8 __user * data)
863 dprintk(4, "%p\n", av7110);
865 format = bpp2bit[av7110->osdbpp[av7110->osdwin]];
867 av7110->bmp_state = BMP_LOADING;
868 if (format == OSD_BITMAP8) {
870 } else if (format == OSD_BITMAP4) {
872 } else if (format == OSD_BITMAP2) {
874 } else if (format == OSD_BITMAP1) {
877 av7110->bmp_state = BMP_NONE;
880 av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8;
882 if (av7110->bmplen > 32768) {
883 av7110->bmp_state = BMP_NONE;
886 for (i = 0; i < dy; i++) {
887 if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) {
888 av7110->bmp_state = BMP_NONE;
892 if (format != OSD_BITMAP8) {
893 for (i = 0; i < dx * dy / delta; i++) {
894 c = ((u8 *)av7110->bmpbuf)[1024 + i * delta + delta - 1];
895 for (d = delta - 2; d >= 0; d--) {
896 c |= (((u8 *)av7110->bmpbuf)[1024 + i * delta + d]
897 << ((delta - d - 1) * bpp));
898 ((u8 *)av7110->bmpbuf)[1024 + i] = c;
902 av7110->bmplen += 1024;
903 dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen);
904 ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
906 ret = WaitUntilBmpLoaded(av7110);
910 static int BlitBitmap(struct av7110 *av7110, u16 x, u16 y)
912 dprintk(4, "%p\n", av7110);
914 return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, av7110->osdwin, x, y, 0);
917 static inline int ReleaseBitmap(struct av7110 *av7110)
919 dprintk(4, "%p\n", av7110);
921 if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e)
923 if (av7110->bmp_state == BMP_LOADING)
924 dprintk(1,"ReleaseBitmap called while BMP_LOADING\n");
925 av7110->bmp_state = BMP_NONE;
926 return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0);
929 static u32 RGB2YUV(u16 R, u16 G, u16 B)
934 y = R * 77 + G * 150 + B * 29; /* Luma=0.299R+0.587G+0.114B 0..65535 */
935 u = 2048 + B * 8 -(y >> 5); /* Cr 0..4095 */
936 v = 2048 + R * 8 -(y >> 5); /* Cb 0..4095 */
942 return Cr | (Cb << 16) | (Y << 8);
945 static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
952 yuv = blend ? RGB2YUV(r,g,b) : 0;
954 ch = ((yuv >> 16) & 0xffff);
955 ret = SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
958 ret = SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
959 color, ((blend >> 4) & 0x0f));
963 static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last)
966 int length = last - first + 1;
968 if (length * 4 > DATA_BUFF3_SIZE)
971 for (i = 0; i < length; i++) {
972 u32 color, blend, yuv;
974 if (get_user(color, colors + i))
976 blend = (color & 0xF0000000) >> 4;
977 yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF,
978 (color >> 16) & 0xFF) | blend : 0;
979 yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16);
980 wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4);
982 return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4,
984 bpp2pal[av7110->osdbpp[av7110->osdwin]],
988 static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
989 int x1, int y1, int inc, u8 __user * data)
991 uint w, h, bpp, bpl, size, lpb, bnum, brest;
999 if (w <= 0 || w > 720 || h <= 0 || h > 576)
1001 bpp = av7110->osdbpp[av7110->osdwin] + 1;
1002 bpl = ((w * bpp + 7) & ~7) / 8;
1004 lpb = (32 * 1024) / bpl;
1005 bnum = size / (lpb * bpl);
1006 brest = size - bnum * lpb * bpl;
1008 if (av7110->bmp_state == BMP_LOADING) {
1009 /* possible if syscall is repeated by -ERESTARTSYS and if firmware cannot abort */
1010 BUG_ON (FW_VERSION(av7110->arm_app) >= 0x261e);
1011 rc = WaitUntilBmpLoaded(av7110);
1014 /* just continue. This should work for all fw versions
1015 * if bnum==1 && !brest && LoadBitmap was successful
1020 for (i = 0; i < bnum; i++) {
1021 rc = LoadBitmap(av7110, w, lpb, inc, data);
1024 rc = BlitBitmap(av7110, x0, y0 + i * lpb);
1030 rc = LoadBitmap(av7110, w, brest / bpl, inc, data);
1032 rc = BlitBitmap(av7110, x0, y0 + bnum * lpb);
1034 release_rc = ReleaseBitmap(av7110);
1038 dprintk(1,"returns %d\n",rc);
1042 int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
1046 if (mutex_lock_interruptible(&av7110->osd_mutex))
1047 return -ERESTARTSYS;
1051 ret = DestroyOSDWindow(av7110, av7110->osdwin);
1054 av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7;
1055 ret = CreateOSDWindow(av7110, av7110->osdwin,
1056 bpp2bit[av7110->osdbpp[av7110->osdwin]],
1057 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
1061 ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1064 ret = SetColorBlend(av7110, av7110->osdwin);
1068 ret = MoveWindowRel(av7110, av7110->osdwin, 0, 0);
1071 ret = HideWindow(av7110, av7110->osdwin);
1074 ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
1077 ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
1080 ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
1082 case OSD_SetPalette:
1083 if (FW_VERSION(av7110->arm_app) >= 0x2618)
1084 ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0);
1086 int i, len = dc->x0-dc->color+1;
1087 u8 __user *colors = (u8 __user *)dc->data;
1088 u8 r, g = 0, b = 0, blend = 0;
1090 for (i = 0; i<len; i++) {
1091 if (get_user(r, colors + i * 4) ||
1092 get_user(g, colors + i * 4 + 1) ||
1093 get_user(b, colors + i * 4 + 2) ||
1094 get_user(blend, colors + i * 4 + 3)) {
1098 ret = OSDSetColor(av7110, dc->color + i, r, g, b, blend);
1105 ret = DrawLine(av7110, av7110->osdwin,
1106 dc->x0, dc->y0, 0, 0, dc->color);
1112 ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data);
1115 ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
1116 dc->x1-dc->x0+1, dc->y1, dc->color);
1119 ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
1120 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color);
1123 ret = DrawLine(av7110, av7110->osdwin,
1124 dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color);
1130 if (strncpy_from_user(textbuf, dc->data, 240) < 0) {
1137 ret = SetFont(av7110, av7110->osdwin, dc->x1,
1138 (u16) (dc->color & 0xffff), (u16) (dc->color >> 16));
1140 ret = FlushText(av7110);
1142 ret = WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
1146 if (dc->x0 < 1 || dc->x0 > 7)
1149 av7110->osdwin = dc->x0;
1153 case OSD_MoveWindow:
1154 ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1156 ret = SetColorBlend(av7110, av7110->osdwin);
1159 if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) {
1163 if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR)
1164 av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1;
1166 av7110->osdbpp[av7110->osdwin] = 0;
1167 ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color,
1168 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
1172 ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1174 ret = SetColorBlend(av7110, av7110->osdwin);
1182 mutex_unlock(&av7110->osd_mutex);
1183 if (ret==-ERESTARTSYS)
1184 dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd);
1186 dprintk(1, "av7110_osd_cmd(%d) returns with %d\n",dc->cmd,ret);
1191 int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap)
1194 case OSD_CAP_MEMSIZE:
1195 if (FW_4M_SDRAM(av7110->arm_app))
1204 #endif /* CONFIG_DVB_AV7110_OSD */