initial commit with v2.6.9
[linux-2.6.9-moxart.git] / drivers / media / dvb / ttpci / av7110_hw.c
blob054018b3fe782c18a67b4ce3a6e8a4225a992ad7
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 #define DEBUG_VARIABLE av7110_debug
42 extern int av7110_debug;
44 #include "av7110.h"
45 #include "av7110_hw.h"
46 #include "dvb_functions.h"
48 /****************************************************************************
49 * DEBI functions
50 ****************************************************************************/
52 /* This DEBI code is based on the Stradis driver
53 by Nathan Laredo <laredo@gnu.org> */
55 int av7110_debiwrite(struct av7110 *av7110, u32 config,
56 int addr, u32 val, int count)
58 struct saa7146_dev *dev = av7110->dev;
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;
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 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));
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;
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 IER_DISABLE(av7110->dev, (MASK_19 | MASK_03));
106 saa7146_write(av7110->dev, ISR, (MASK_19 | MASK_03));
108 saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTHI);
109 dvb_delay(30); /* the firmware needs some time to initialize */
111 ARM_ResetMailBox(av7110);
113 saa7146_write(av7110->dev, ISR, (MASK_19 | MASK_03));
114 IER_ENABLE(av7110->dev, MASK_03);
116 av7110->arm_ready = 1;
117 printk("av7110: ARM RESET\n");
121 static int waitdebi(struct av7110 *av7110, int adr, int state)
123 int k;
125 DEB_EE(("av7110: %p\n", av7110));
127 for (k = 0; k < 100; k++) {
128 if (irdebi(av7110, DEBINOSWAP, adr, 0, 2) == state)
129 return 0;
130 udelay(5);
132 return -1;
135 static int load_dram(struct av7110 *av7110, u32 *data, int len)
137 int i;
138 int blocks, rest;
139 u32 base, bootblock = BOOT_BLOCK;
141 DEB_EE(("av7110: %p\n", av7110));
143 blocks = len / BOOT_MAX_SIZE;
144 rest = len % BOOT_MAX_SIZE;
145 base = DRAM_START_CODE;
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;
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);
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);
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;
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
207 int av7110_bootarm(struct av7110 *av7110)
209 struct saa7146_dev *dev = av7110->dev;
210 u32 ret;
211 int i;
213 DEB_EE(("av7110: %p\n", av7110));
215 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
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));
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));
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;
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"));
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);
244 mwdebi(av7110, DEBISWAB, DPRAM_BASE, bootcode, sizeof(bootcode));
245 iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
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;
252 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
253 mdelay(1);
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;
259 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
260 mdelay(1);
262 DEB_D(("av7110_bootarm: load dpram code\n"));
263 mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram);
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;
270 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
271 dvb_delay(30); /* the firmware needs some time to initialize */
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);
278 av7110->arm_errors = 0;
279 av7110->arm_ready = 1;
280 return 0;
284 /****************************************************************************
285 * DEBI command polling
286 ****************************************************************************/
288 int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
290 int i;
291 unsigned long start;
292 #ifdef COM_DEBUG
293 u32 stat;
294 #endif
296 // DEB_EE(("av7110: %p\n", av7110));
298 if (!av7110->arm_ready) {
299 DEB_D(("arm not ready.\n"));
300 return -1;
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;
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;
321 #endif
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;
331 for (i = 2; i < length; i++)
332 wdebi(av7110, DEBINOSWAP, COMMAND + 2 * i, (u32) buf[i], 2);
334 if (length)
335 wdebi(av7110, DEBINOSWAP, COMMAND + 2, (u32) buf[1], 2);
336 else
337 wdebi(av7110, DEBINOSWAP, COMMAND + 2, 0, 2);
339 wdebi(av7110, DEBINOSWAP, COMMAND, (u32) buf[0], 2);
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;
352 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
353 if (stat & GPMQOver) {
354 printk(KERN_ERR "%s: GPMQOver\n", __FUNCTION__);
355 return -1;
357 else if (stat & OSDQOver) {
358 printk(KERN_ERR "%s: OSDQOver\n", __FUNCTION__);
359 return -1;
361 #endif
363 return 0;
366 int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
368 int ret;
370 // DEB_EE(("av7110: %p\n", av7110));
372 if (!av7110->arm_ready) {
373 DEB_D(("arm not ready.\n"));
374 return -1;
376 if (down_interruptible(&av7110->dcomlock))
377 return -ERESTARTSYS;
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;
386 int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...)
388 va_list args;
389 u16 buf[num + 2];
390 int i, ret;
392 // DEB_EE(("av7110: %p\n",av7110));
394 buf[0] = ((type << 8) | com);
395 buf[1] = num;
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);
404 ret = av7110_send_fw_cmd(av7110, buf, num + 2);
405 if (ret)
406 printk("av7110_fw_cmd error\n");
407 return ret;
410 int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len)
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 };
416 DEB_EE(("av7110: %p\n", av7110));
418 for(i = 0; i < len && i < 32; i++)
420 if(i % 2 == 0)
421 cmd[(i / 2) + 2] = (u16)(buf[i]) << 8;
422 else
423 cmd[(i / 2) + 2] |= buf[i];
426 ret = av7110_send_fw_cmd(av7110, cmd, 18);
427 if (ret)
428 printk("av7110_send_ci_cmd error\n");
429 return ret;
432 int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
433 int request_buf_len, u16 *reply_buf, int reply_buf_len)
435 int err;
436 s16 i;
437 unsigned long start;
438 #ifdef COM_DEBUG
439 u32 stat;
440 #endif
442 DEB_EE(("av7110: %p\n", av7110));
444 if (!av7110->arm_ready) {
445 DEB_D(("arm not ready.\n"));
446 return -1;
449 if (down_interruptible(&av7110->dcomlock))
450 return -ERESTARTSYS;
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;
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;
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;
480 #endif
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;
489 else if (stat & OSDQOver) {
490 printk(KERN_ERR "%s: OSDQOver\n", __FUNCTION__);
491 up(&av7110->dcomlock);
492 return -1;
494 #endif
496 for (i = 0; i < reply_buf_len; i++)
497 reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2);
499 up(&av7110->dcomlock);
500 return 0;
503 int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length)
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;
513 /****************************************************************************
514 * Firmware commands
515 ****************************************************************************/
517 /* get version of the firmware ROM, RTSL, video ucode and ARM application */
518 int av7110_firmversion(struct av7110 *av7110)
520 u16 buf[20];
521 u16 tag = ((COMTYPE_REQUEST << 8) + ReqVersion);
523 DEB_EE(("av7110: %p\n", av7110));
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;
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];
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);
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);
549 return 0;
553 int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst)
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 };
559 DEB_EE(("av7110: %p\n", av7110));
561 if (len > 10)
562 len = 10;
564 buf[1] = len + 2;
565 buf[2] = len;
567 if (burst != -1)
568 buf[3] = burst ? 0x01 : 0x00;
569 else
570 buf[3] = 0xffff;
572 for (i = 0; i < len; i++)
573 buf[i + 4] = msg[i];
575 if (av7110_send_fw_cmd(av7110, buf, 18))
576 printk("av7110_diseqc_send error\n");
578 return 0;
582 #ifdef CONFIG_DVB_AV7110_OSD
584 static inline int ResetBlend(struct av7110 *av7110, u8 windownr)
586 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetNonBlend, 1, windownr);
589 static inline int SetColorBlend(struct av7110 *av7110, u8 windownr)
591 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetCBlend, 1, windownr);
594 static inline int SetWindowBlend(struct av7110 *av7110, u8 windownr, u8 blending)
596 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetWBlend, 2, windownr, blending);
599 static inline int SetBlend_(struct av7110 *av7110, u8 windownr,
600 enum av7110_osd_palette_type colordepth, u16 index, u8 blending)
602 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetBlend, 4,
603 windownr, colordepth, index, blending);
606 static inline int SetColor_(struct av7110 *av7110, u8 windownr,
607 enum av7110_osd_palette_type colordepth, u16 index, u16 colorhi, u16 colorlo)
609 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetColor, 5,
610 windownr, colordepth, index, colorhi, colorlo);
613 static inline int BringToTop(struct av7110 *av7110, u8 windownr)
615 return av7110_fw_cmd(av7110, COMTYPE_OSD, WTop, 1, windownr);
618 static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize,
619 u16 colorfg, u16 colorbg)
621 return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Font, 4,
622 windownr, fontsize, colorfg, colorbg);
625 static int FlushText(struct av7110 *av7110)
627 unsigned long start;
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;
641 up(&av7110->dcomlock);
642 return 0;
645 static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
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 };
652 if (down_interruptible(&av7110->dcomlock))
653 return -ERESTARTSYS;
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;
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;
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;
689 static inline int DrawLine(struct av7110 *av7110, u8 windownr,
690 u16 x, u16 y, u16 dx, u16 dy, u16 color)
692 return av7110_fw_cmd(av7110, COMTYPE_OSD, DLine, 6,
693 windownr, x, y, dx, dy, color);
696 static inline int DrawBlock(struct av7110 *av7110, u8 windownr,
697 u16 x, u16 y, u16 dx, u16 dy, u16 color)
699 return av7110_fw_cmd(av7110, COMTYPE_OSD, DBox, 6,
700 windownr, x, y, dx, dy, color);
703 static inline int HideWindow(struct av7110 *av7110, u8 windownr)
705 return av7110_fw_cmd(av7110, COMTYPE_OSD, WHide, 1, windownr);
708 static inline int MoveWindowRel(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
710 return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveD, 3, windownr, x, y);
713 static inline int MoveWindowAbs(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
715 return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveA, 3, windownr, x, y);
718 static inline int DestroyOSDWindow(struct av7110 *av7110, u8 windownr)
720 return av7110_fw_cmd(av7110, COMTYPE_OSD, WDestroy, 1, windownr);
723 static inline int CreateOSDWindow(struct av7110 *av7110, u8 windownr,
724 enum av7110_window_display_type disptype,
725 u16 width, u16 height)
727 return av7110_fw_cmd(av7110, COMTYPE_OSD, WCreate, 4,
728 windownr, disptype, width, height);
732 static enum av7110_osd_palette_type bpp2pal[8] = {
733 Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit
735 static enum av7110_window_display_type bpp2bit[8] = {
736 BITMAP1, BITMAP2, 0, BITMAP4, 0, 0, 0, BITMAP8
739 static inline int LoadBitmap(struct av7110 *av7110, u16 format,
740 u16 dx, u16 dy, int inc, u8 __user * data)
742 int bpp;
743 int i;
744 int d, delta;
745 u8 c;
746 DECLARE_WAITQUEUE(wait, current);
748 DEB_EE(("av7110: %p\n", av7110));
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();
759 set_current_state(TASK_RUNNING);
760 remove_wait_queue(&av7110->bmpq, &wait);
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;
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;
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;
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;
799 av7110->bmplen += 1024;
800 return av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
803 static int BlitBitmap(struct av7110 *av7110, u16 win, u16 x, u16 y, u16 trans)
805 DECLARE_WAITQUEUE(wait, current);
807 DEB_EE(("av7110: %p\n", av7110));
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();
820 set_current_state(TASK_RUNNING);
821 remove_wait_queue(&av7110->bmpq, &wait);
823 if (av7110->bmp_state == BMP_LOADED)
824 return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, win, x, y, trans);
825 return -1;
828 static inline int ReleaseBitmap(struct av7110 *av7110)
830 DEB_EE(("av7110: %p\n",av7110));
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);
838 static u32 RGB2YUV(u16 R, u16 G, u16 B)
840 u16 y, u, v;
841 u16 Y, Cr, Cb;
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 */
847 Y = y / 256;
848 Cb = u / 16;
849 Cr = v / 16;
851 return Cr | (Cb << 16) | (Y << 8);
854 static void OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
856 u16 ch, cl;
857 u32 yuv;
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));
868 static int OSDSetPalette(struct av7110 *av7110, u32 *colors, u8 first, u8 last)
870 int i;
871 int length = last - first + 1;
873 if (length * 4 > DATA_BUFF3_SIZE)
874 return -1;
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);
883 return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4,
884 av7110->osdwin,
885 bpp2pal[av7110->osdbpp[av7110->osdwin]],
886 first, last);
889 static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
890 int x1, int y1, int inc, u8 __user *data)
892 uint w, h, bpp, bpl, size, lpb, bnum, brest;
893 int i;
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;
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;
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);
919 ReleaseBitmap(av7110);
920 return 0;
923 int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
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);
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:
956 int len = dc->x0-dc->color+1;
957 void *buf;
958 if (len <= 0)
959 return 0;
961 buf = kmalloc(len * 4, GFP_KERNEL);
962 if (!buf)
963 return -ENOMEM;
965 if (copy_from_user(buf, dc->data, len * 4)) {
966 kfree(buf);
967 return -EFAULT;
970 if (FW_VERSION(av7110->arm_app) >= 0x2618)
971 OSDSetPalette(av7110, buf, dc->color, dc->x0);
972 else {
973 int i;
974 u8 *colors = buf;
976 for (i = 0; i<len; i++)
977 OSDSetColor(av7110, dc->color + i,
978 colors[i * 4], colors[i * 4 + 1],
979 colors[i * 4 + 2], colors[i * 4 + 3]);
981 kfree(buf);
982 return 0;
984 case OSD_SetTrans:
985 return 0;
986 case OSD_SetPixel:
987 DrawLine(av7110, av7110->osdwin,
988 dc->x0, dc->y0, 0, 0, dc->color);
989 return 0;
990 case OSD_GetPixel:
991 return 0;
993 case OSD_SetRow:
994 dc->y1 = dc->y0;
995 /* fall through */
996 case OSD_SetBlock:
997 OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data);
998 return 0;
1000 case OSD_FillRow:
1001 DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
1002 dc->x1-dc->x0+1, dc->y1, dc->color);
1003 return 0;
1004 case OSD_FillBlock:
1005 DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
1006 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color);
1007 return 0;
1008 case OSD_Line:
1009 DrawLine(av7110, av7110->osdwin,
1010 dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color);
1011 return 0;
1012 case OSD_Query:
1013 return 0;
1014 case OSD_Test:
1015 return 0;
1016 case OSD_Text:
1018 char textbuf[240];
1020 if (strncpy_from_user(textbuf, dc->data, 240) < 0)
1021 return -EFAULT;
1022 textbuf[239] = 0;
1023 if (dc->x1 > 3)
1024 dc->x1 = 3;
1025 SetFont(av7110, av7110->osdwin, dc->x1,
1026 (u16) (dc->color & 0xffff), (u16) (dc->color >> 16));
1027 FlushText(av7110);
1028 WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
1029 return 0;
1031 case OSD_SetWindow:
1032 if (dc->x0 < 1 || dc->x0 > 7)
1033 return -EINVAL;
1034 av7110->osdwin = dc->x0;
1035 return 0;
1036 case OSD_MoveWindow:
1037 MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1038 SetColorBlend(av7110, av7110->osdwin);
1039 return 0;
1040 default:
1041 return -EINVAL;
1044 #endif /* CONFIG_DVB_AV7110_OSD */