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: */
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>
42 #include "av7110_hw.h"
44 /****************************************************************************
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);
60 if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
61 printk("%s: wait_for_debi_done failed\n", __FUNCTION__);
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);
74 u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, int count)
76 struct saa7146_dev *dev = av7110->dev;
79 if (count > 32764 || count <= 0) {
80 printk("%s: invalid count %d\n", __FUNCTION__, count);
83 if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
84 printk("%s: wait_for_debi_done #1 failed\n", __FUNCTION__);
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);
94 if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
95 printk("%s: wait_for_debi_done #2 failed\n", __FUNCTION__);
99 result = saa7146_read(dev, DEBI_AD);
100 result &= (0xffffffffUL >> ((4 - count) * 8));
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)
133 dprintk(4, "%p\n", av7110);
135 for (k = 0; k < 100; k++) {
136 if (irdebi(av7110, DEBINOSWAP, adr, 0, 2) == state)
143 static int load_dram(struct av7110 *av7110, u32 *data, int len)
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);
160 dprintk(4, "writing DRAM block %d\n", i);
161 mwdebi(av7110, DEBISWAB, bootblock,
162 ((char*)data) + i * BOOT_MAX_SIZE, BOOT_MAX_SIZE);
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;
171 if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
172 printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n");
176 mwdebi(av7110, DEBISWAB, bootblock,
177 ((char*)data) + i * BOOT_MAX_SIZE, rest);
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");
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");
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;
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);
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));
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",
250 for (i = 0; i < 8192; i += 4)
251 iwdebi(av7110, DEBISWAP, DPRAM_BASE + i, 0x00, 4);
252 dprintk(2, "debi test OK\n");
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");
268 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
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");
278 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
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");
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;
303 /****************************************************************************
304 * DEBI command polling
305 ****************************************************************************/
307 int av7110_wait_msgstate(struct av7110 *av7110, u16 flags)
312 if (FW_VERSION(av7110->arm_app) <= 0x261c) {
313 /* not supported by old firmware */
321 if (down_interruptible(&av7110->dcomlock))
323 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
324 up(&av7110->dcomlock);
325 if ((stat & flags) == 0) {
328 if (time_after(jiffies, start + ARM_WAIT_FREE)) {
329 printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n",
330 __FUNCTION__, stat & flags);
338 static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
343 u16 flags[2] = {0, 0};
346 // dprintk(4, "%p\n", av7110);
348 if (!av7110->arm_ready) {
349 dprintk(1, "arm not ready.\n");
354 while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) {
356 if (time_after(jiffies, start + ARM_WAIT_FREE)) {
357 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__);
362 wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2);
366 while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) {
368 if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
369 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
375 switch ((buf[0] >> 8) & 0xff) {
376 case COMTYPE_PIDFILTER:
377 case COMTYPE_ENCODER:
378 case COMTYPE_REC_PLAY:
379 case COMTYPE_MPEGDECODER:
390 if (FW_VERSION(av7110->arm_app) >= 0x261d) {
401 /* non-immediate COMMAND type */
404 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
405 if (stat & flags[0]) {
406 printk(KERN_ERR "%s: %s QUEUE overflow\n",
410 if ((stat & flags[1]) == 0)
412 if (time_after(jiffies, start + ARM_WAIT_FREE)) {
413 printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n",
421 for (i = 2; i < length; i++)
422 wdebi(av7110, DEBINOSWAP, COMMAND + 2 * i, (u32) buf[i], 2);
425 wdebi(av7110, DEBINOSWAP, COMMAND + 2, (u32) buf[1], 2);
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);
435 while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) {
437 if (time_after(jiffies, start + ARM_WAIT_FREE)) {
438 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND to complete\n",
444 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
445 if (stat & GPMQOver) {
446 printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __FUNCTION__);
449 else if (stat & OSDQOver) {
450 printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __FUNCTION__);
458 static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
462 // dprintk(4, "%p\n", av7110);
464 if (!av7110->arm_ready) {
465 dprintk(1, "arm not ready.\n");
468 if (down_interruptible(&av7110->dcomlock))
471 ret = __av7110_send_fw_cmd(av7110, buf, length);
472 up(&av7110->dcomlock);
474 printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
479 int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...)
485 // dprintk(4, "%p\n", av7110);
487 buf[0] = ((type << 8) | com);
492 for (i = 0; i < num; i++)
493 buf[i + 2] = va_arg(args, u32);
497 ret = av7110_send_fw_cmd(av7110, buf, num + 2);
499 printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret);
504 int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len)
507 u16 cmd[18] = { ((COMTYPE_COMMON_IF << 8) + subcom),
508 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
510 dprintk(4, "%p\n", av7110);
512 for(i = 0; i < len && i < 32; i++)
515 cmd[(i / 2) + 2] = (u16)(buf[i]) << 8;
517 cmd[(i / 2) + 2] |= buf[i];
520 ret = av7110_send_fw_cmd(av7110, cmd, 18);
522 printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret);
527 int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
528 int request_buf_len, u16 *reply_buf, int reply_buf_len)
537 dprintk(4, "%p\n", av7110);
539 if (!av7110->arm_ready) {
540 dprintk(1, "arm not ready.\n");
544 if (down_interruptible(&av7110->dcomlock))
547 if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) {
548 up(&av7110->dcomlock);
549 printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err);
554 while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2)) {
558 if (time_after(jiffies, start + ARM_WAIT_FREE)) {
559 printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __FUNCTION__);
560 up(&av7110->dcomlock);
567 while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) {
569 if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
570 printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
571 up(&av7110->dcomlock);
578 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
579 if (stat & GPMQOver) {
580 printk(KERN_ERR "%s: GPMQOver\n", __FUNCTION__);
581 up(&av7110->dcomlock);
584 else if (stat & OSDQOver) {
585 printk(KERN_ERR "%s: OSDQOver\n", __FUNCTION__);
586 up(&av7110->dcomlock);
591 for (i = 0; i < reply_buf_len; i++)
592 reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2);
594 up(&av7110->dcomlock);
598 static int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length)
601 ret = av7110_fw_request(av7110, &tag, 0, buf, length);
603 printk(KERN_ERR "dvb-ttpci: av7110_fw_query error %d\n", ret);
608 /****************************************************************************
610 ****************************************************************************/
612 /* get version of the firmware ROM, RTSL, video ucode and ARM application */
613 int av7110_firmversion(struct av7110 *av7110)
616 u16 tag = ((COMTYPE_REQUEST << 8) + ReqVersion);
618 dprintk(4, "%p\n", av7110);
620 if (av7110_fw_query(av7110, tag, buf, 16)) {
621 printk("dvb-ttpci: failed to boot firmware @ card %d\n",
622 av7110->dvb_adapter.num);
626 av7110->arm_fw = (buf[0] << 16) + buf[1];
627 av7110->arm_rtsl = (buf[2] << 16) + buf[3];
628 av7110->arm_vid = (buf[4] << 16) + buf[5];
629 av7110->arm_app = (buf[6] << 16) + buf[7];
630 av7110->avtype = (buf[8] << 16) + buf[9];
632 printk("dvb-ttpci: info @ card %d: firm %08x, rtsl %08x, vid %08x, app %08x\n",
633 av7110->dvb_adapter.num, av7110->arm_fw,
634 av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app);
636 /* print firmware capabilities */
637 if (FW_CI_LL_SUPPORT(av7110->arm_app))
638 printk("dvb-ttpci: firmware @ card %d supports CI link layer interface\n",
639 av7110->dvb_adapter.num);
641 printk("dvb-ttpci: no firmware support for CI link layer interface @ card %d\n",
642 av7110->dvb_adapter.num);
648 int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst)
651 u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) + SendDiSEqC),
652 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
654 dprintk(4, "%p\n", av7110);
663 buf[3] = burst ? 0x01 : 0x00;
667 for (i = 0; i < len; i++)
670 if ((ret = av7110_send_fw_cmd(av7110, buf, 18)))
671 printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret);
677 #ifdef CONFIG_DVB_AV7110_OSD
679 static inline int SetColorBlend(struct av7110 *av7110, u8 windownr)
681 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetCBlend, 1, windownr);
684 static inline int SetBlend_(struct av7110 *av7110, u8 windownr,
685 enum av7110_osd_palette_type colordepth, u16 index, u8 blending)
687 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetBlend, 4,
688 windownr, colordepth, index, blending);
691 static inline int SetColor_(struct av7110 *av7110, u8 windownr,
692 enum av7110_osd_palette_type colordepth, u16 index, u16 colorhi, u16 colorlo)
694 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetColor, 5,
695 windownr, colordepth, index, colorhi, colorlo);
698 static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize,
699 u16 colorfg, u16 colorbg)
701 return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Font, 4,
702 windownr, fontsize, colorfg, colorbg);
705 static int FlushText(struct av7110 *av7110)
709 if (down_interruptible(&av7110->dcomlock))
712 while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) {
714 if (time_after(jiffies, start + ARM_WAIT_OSD)) {
715 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n",
717 up(&av7110->dcomlock);
721 up(&av7110->dcomlock);
725 static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
729 int length = strlen(buf) + 1;
730 u16 cbuf[5] = { (COMTYPE_OSD << 8) + DText, 3, win, x, y };
732 if (down_interruptible(&av7110->dcomlock))
736 while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) {
738 if (time_after(jiffies, start + ARM_WAIT_OSD)) {
739 printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n",
741 up(&av7110->dcomlock);
747 while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2)) {
749 if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
750 printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n",
752 up(&av7110->dcomlock);
757 for (i = 0; i < length / 2; i++)
758 wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2,
759 swab16(*(u16 *)(buf + 2 * i)), 2);
761 wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2);
762 ret = __av7110_send_fw_cmd(av7110, cbuf, 5);
763 up(&av7110->dcomlock);
765 printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret);
769 static inline int DrawLine(struct av7110 *av7110, u8 windownr,
770 u16 x, u16 y, u16 dx, u16 dy, u16 color)
772 return av7110_fw_cmd(av7110, COMTYPE_OSD, DLine, 6,
773 windownr, x, y, dx, dy, color);
776 static inline int DrawBlock(struct av7110 *av7110, u8 windownr,
777 u16 x, u16 y, u16 dx, u16 dy, u16 color)
779 return av7110_fw_cmd(av7110, COMTYPE_OSD, DBox, 6,
780 windownr, x, y, dx, dy, color);
783 static inline int HideWindow(struct av7110 *av7110, u8 windownr)
785 return av7110_fw_cmd(av7110, COMTYPE_OSD, WHide, 1, windownr);
788 static inline int MoveWindowRel(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
790 return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveD, 3, windownr, x, y);
793 static inline int MoveWindowAbs(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
795 return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveA, 3, windownr, x, y);
798 static inline int DestroyOSDWindow(struct av7110 *av7110, u8 windownr)
800 return av7110_fw_cmd(av7110, COMTYPE_OSD, WDestroy, 1, windownr);
803 static inline int CreateOSDWindow(struct av7110 *av7110, u8 windownr,
804 osd_raw_window_t disptype,
805 u16 width, u16 height)
807 return av7110_fw_cmd(av7110, COMTYPE_OSD, WCreate, 4,
808 windownr, disptype, width, height);
812 static enum av7110_osd_palette_type bpp2pal[8] = {
813 Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit
815 static osd_raw_window_t bpp2bit[8] = {
816 OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8
819 static inline int LoadBitmap(struct av7110 *av7110, u16 format,
820 u16 dx, u16 dy, int inc, u8 __user * data)
828 dprintk(4, "%p\n", av7110);
830 ret = wait_event_interruptible_timeout(av7110->bmpq, av7110->bmp_state != BMP_LOADING, HZ);
831 if (ret == -ERESTARTSYS || ret == 0) {
832 printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n",
833 ret, av7110->bmp_state);
834 av7110->bmp_state = BMP_NONE;
837 BUG_ON (av7110->bmp_state == BMP_LOADING);
839 av7110->bmp_state = BMP_LOADING;
840 if (format == OSD_BITMAP8) {
842 } else if (format == OSD_BITMAP4) {
844 } else if (format == OSD_BITMAP2) {
846 } else if (format == OSD_BITMAP1) {
849 av7110->bmp_state = BMP_NONE;
852 av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8;
854 if (av7110->bmplen > 32768) {
855 av7110->bmp_state = BMP_NONE;
858 for (i = 0; i < dy; i++) {
859 if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) {
860 av7110->bmp_state = BMP_NONE;
864 if (format != OSD_BITMAP8) {
865 for (i = 0; i < dx * dy / delta; i++) {
866 c = ((u8 *)av7110->bmpbuf)[1024 + i * delta + delta - 1];
867 for (d = delta - 2; d >= 0; d--) {
868 c |= (((u8 *)av7110->bmpbuf)[1024 + i * delta + d]
869 << ((delta - d - 1) * bpp));
870 ((u8 *)av7110->bmpbuf)[1024 + i] = c;
874 av7110->bmplen += 1024;
875 dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen);
876 return av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
879 static int BlitBitmap(struct av7110 *av7110, u16 win, u16 x, u16 y, u16 trans)
883 dprintk(4, "%p\n", av7110);
885 BUG_ON (av7110->bmp_state == BMP_NONE);
887 ret = wait_event_interruptible_timeout(av7110->bmpq,
888 av7110->bmp_state != BMP_LOADING, 10*HZ);
889 if (ret == -ERESTARTSYS || ret == 0) {
890 printk("dvb-ttpci: warning: timeout waiting in BlitBitmap: %d, %d\n",
891 ret, av7110->bmp_state);
892 av7110->bmp_state = BMP_NONE;
893 return (ret == 0) ? -ETIMEDOUT : ret;
896 BUG_ON (av7110->bmp_state != BMP_LOADED);
898 return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, win, x, y, trans);
901 static inline int ReleaseBitmap(struct av7110 *av7110)
903 dprintk(4, "%p\n", av7110);
905 if (av7110->bmp_state != BMP_LOADED)
907 av7110->bmp_state = BMP_NONE;
908 return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0);
911 static u32 RGB2YUV(u16 R, u16 G, u16 B)
916 y = R * 77 + G * 150 + B * 29; /* Luma=0.299R+0.587G+0.114B 0..65535 */
917 u = 2048 + B * 8 -(y >> 5); /* Cr 0..4095 */
918 v = 2048 + R * 8 -(y >> 5); /* Cb 0..4095 */
924 return Cr | (Cb << 16) | (Y << 8);
927 static void OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
932 yuv = blend ? RGB2YUV(r,g,b) : 0;
934 ch = ((yuv >> 16) & 0xffff);
935 SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
937 SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
938 color, ((blend >> 4) & 0x0f));
941 static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last)
944 int length = last - first + 1;
946 if (length * 4 > DATA_BUFF3_SIZE)
949 for (i = 0; i < length; i++) {
950 u32 color, blend, yuv;
952 if (get_user(color, colors + i))
954 blend = (color & 0xF0000000) >> 4;
955 yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF,
956 (color >> 16) & 0xFF) | blend : 0;
957 yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16);
958 wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4);
960 return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4,
962 bpp2pal[av7110->osdbpp[av7110->osdwin]],
966 static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
967 int x1, int y1, int inc, u8 __user * data)
969 uint w, h, bpp, bpl, size, lpb, bnum, brest;
977 if (w <= 0 || w > 720 || h <= 0 || h > 576)
979 bpp = av7110->osdbpp[av7110->osdwin] + 1;
980 bpl = ((w * bpp + 7) & ~7) / 8;
982 lpb = (32 * 1024) / bpl;
983 bnum = size / (lpb * bpl);
984 brest = size - bnum * lpb * bpl;
986 for (i = 0; i < bnum; i++) {
987 rc = LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]],
991 rc = BlitBitmap(av7110, av7110->osdwin, x0, y0 + i * lpb, 0);
997 rc = LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]],
998 w, brest / bpl, inc, data);
1001 rc = BlitBitmap(av7110, av7110->osdwin, x0, y0 + bnum * lpb, 0);
1005 ReleaseBitmap(av7110);
1009 int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
1013 ret = down_interruptible(&av7110->osd_sema);
1015 return -ERESTARTSYS;
1017 /* stupid, but OSD functions don't provide a return code anyway */
1022 DestroyOSDWindow(av7110, av7110->osdwin);
1025 av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7;
1026 CreateOSDWindow(av7110, av7110->osdwin,
1027 bpp2bit[av7110->osdbpp[av7110->osdwin]],
1028 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
1030 MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1031 SetColorBlend(av7110, av7110->osdwin);
1035 MoveWindowRel(av7110, av7110->osdwin, 0, 0);
1038 HideWindow(av7110, av7110->osdwin);
1041 DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
1044 DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
1047 OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
1049 case OSD_SetPalette:
1051 if (FW_VERSION(av7110->arm_app) >= 0x2618) {
1052 ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0);
1055 int i, len = dc->x0-dc->color+1;
1056 u8 __user *colors = (u8 __user *)dc->data;
1059 for (i = 0; i<len; i++) {
1060 if (get_user(r, colors + i * 4) ||
1061 get_user(g, colors + i * 4 + 1) ||
1062 get_user(b, colors + i * 4 + 2) ||
1063 get_user(blend, colors + i * 4 + 3)) {
1067 OSDSetColor(av7110, dc->color + i, r, g, b, blend);
1076 DrawLine(av7110, av7110->osdwin,
1077 dc->x0, dc->y0, 0, 0, dc->color);
1085 ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data);
1088 DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
1089 dc->x1-dc->x0+1, dc->y1, dc->color);
1092 DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
1093 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color);
1096 DrawLine(av7110, av7110->osdwin,
1097 dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color);
1107 if (strncpy_from_user(textbuf, dc->data, 240) < 0) {
1114 SetFont(av7110, av7110->osdwin, dc->x1,
1115 (u16) (dc->color & 0xffff), (u16) (dc->color >> 16));
1117 WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
1121 if (dc->x0 < 1 || dc->x0 > 7) {
1125 av7110->osdwin = dc->x0;
1127 case OSD_MoveWindow:
1128 MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1129 SetColorBlend(av7110, av7110->osdwin);
1132 if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) {
1136 if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR) {
1137 av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1;
1140 av7110->osdbpp[av7110->osdwin] = 0;
1142 CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color,
1143 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
1145 MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1146 SetColorBlend(av7110, av7110->osdwin);
1155 up(&av7110->osd_sema);
1159 int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap)
1162 case OSD_CAP_MEMSIZE:
1163 if (FW_4M_SDRAM(av7110->arm_app))
1172 #endif /* CONFIG_DVB_AV7110_OSD */