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>
41 #define DEBUG_VARIABLE av7110_debug
42 extern int av7110_debug
;
45 #include "av7110_hw.h"
46 #include "dvb_functions.h"
48 /****************************************************************************
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)
62 if (saa7146_wait_for_debi_done(av7110
->dev
) < 0)
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)
81 if (saa7146_wait_for_debi_done(av7110
->dev
) < 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);
90 saa7146_wait_for_debi_done(av7110
->dev
);
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 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
)
125 DEB_EE(("av7110: %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
= 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)
150 DEB_D(("Writing DRAM block %d\n", i
));
151 mwdebi(av7110
, DEBISWAB
, bootblock
,
152 ((char*)data
) + i
* BOOT_MAX_SIZE
, BOOT_MAX_SIZE
);
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
;
161 if (waitdebi(av7110
, BOOT_STATE
, BOOTSTATE_BUFFER_EMPTY
) < 0)
164 mwdebi(av7110
, DEBISWAB
, bootblock
,
165 ((char*)data
) + i
* BOOT_MAX_SIZE
, rest
);
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)
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)
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
;
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
));
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
));
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",
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"));
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");
252 saa7146_setgpio(dev
, RESET_LINE
, SAA7146_GPIO_OUTHI
);
255 DEB_D(("av7110_bootarm: load dram code\n"));
256 if (load_dram(av7110
, (u32
*)av7110
->bin_root
, av7110
->size_root
) < 0)
259 saa7146_setgpio(dev
, RESET_LINE
, SAA7146_GPIO_OUTLO
);
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");
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;
284 /****************************************************************************
285 * DEBI command polling
286 ****************************************************************************/
288 int __av7110_send_fw_cmd(struct av7110
*av7110
, u16
* buf
, int length
)
296 // DEB_EE(("av7110: %p\n", av7110));
298 if (!av7110
->arm_ready
) {
299 DEB_D(("arm not ready.\n"));
304 while (rdebi(av7110
, DEBINOSWAP
, COMMAND
, 0, 2 )) {
306 if (time_after(jiffies
, start
+ ARM_WAIT_FREE
)) {
307 printk(KERN_ERR
"%s: timeout waiting for COMMAND idle\n", __FUNCTION__
);
314 while (rdebi(av7110
, DEBINOSWAP
, HANDSHAKE_REG
, 0, 2 )) {
316 if (time_after(jiffies
, start
+ ARM_WAIT_SHAKE
)) {
317 printk(KERN_ERR
"%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__
);
324 while (rdebi(av7110
, DEBINOSWAP
, MSGSTATE
, 0, 2) & OSDQFull
) {
326 if (time_after(jiffies
, start
+ ARM_WAIT_OSD
)) {
327 printk(KERN_ERR
"%s: timeout waiting for !OSDQFull\n", __FUNCTION__
);
331 for (i
= 2; i
< length
; i
++)
332 wdebi(av7110
, DEBINOSWAP
, COMMAND
+ 2 * i
, (u32
) buf
[i
], 2);
335 wdebi(av7110
, DEBINOSWAP
, COMMAND
+ 2, (u32
) buf
[1], 2);
337 wdebi(av7110
, DEBINOSWAP
, COMMAND
+ 2, 0, 2);
339 wdebi(av7110
, DEBINOSWAP
, COMMAND
, (u32
) buf
[0], 2);
343 while (rdebi(av7110
, DEBINOSWAP
, COMMAND
, 0, 2 )) {
345 if (time_after(jiffies
, start
+ ARM_WAIT_FREE
)) {
346 printk(KERN_ERR
"%s: timeout waiting for COMMAND to complete\n",
352 stat
= rdebi(av7110
, DEBINOSWAP
, MSGSTATE
, 0, 2);
353 if (stat
& GPMQOver
) {
354 printk(KERN_ERR
"%s: GPMQOver\n", __FUNCTION__
);
357 else if (stat
& OSDQOver
) {
358 printk(KERN_ERR
"%s: OSDQOver\n", __FUNCTION__
);
366 int av7110_send_fw_cmd(struct av7110
*av7110
, u16
* buf
, int length
)
370 // DEB_EE(("av7110: %p\n", av7110));
372 if (!av7110
->arm_ready
) {
373 DEB_D(("arm not ready.\n"));
376 if (down_interruptible(&av7110
->dcomlock
))
379 ret
= __av7110_send_fw_cmd(av7110
, buf
, length
);
380 up(&av7110
->dcomlock
);
382 printk("av7110_send_fw_cmd error\n");
386 int av7110_fw_cmd(struct av7110
*av7110
, int type
, int com
, int num
, ...)
392 // DEB_EE(("av7110: %p\n",av7110));
394 buf
[0] = ((type
<< 8) | com
);
399 for (i
= 0; i
< num
; i
++)
400 buf
[i
+ 2] = va_arg(args
, u32
);
404 ret
= av7110_send_fw_cmd(av7110
, buf
, num
+ 2);
406 printk("av7110_fw_cmd error\n");
410 int av7110_send_ci_cmd(struct av7110
*av7110
, u8 subcom
, u8
*buf
, u8 len
)
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
++)
421 cmd
[(i
/ 2) + 2] = (u16
)(buf
[i
]) << 8;
423 cmd
[(i
/ 2) + 2] |= buf
[i
];
426 ret
= av7110_send_fw_cmd(av7110
, cmd
, 18);
428 printk("av7110_send_ci_cmd error\n");
432 int av7110_fw_request(struct av7110
*av7110
, u16
*request_buf
,
433 int request_buf_len
, u16
*reply_buf
, int reply_buf_len
)
442 DEB_EE(("av7110: %p\n", av7110
));
444 if (!av7110
->arm_ready
) {
445 DEB_D(("arm not ready.\n"));
449 if (down_interruptible(&av7110
->dcomlock
))
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");
459 while (rdebi(av7110
, DEBINOSWAP
, COMMAND
, 0, 2)) {
463 if (time_after(jiffies
, start
+ ARM_WAIT_FREE
)) {
464 printk("%s: timeout waiting for COMMAND to complete\n", __FUNCTION__
);
465 up(&av7110
->dcomlock
);
472 while (rdebi(av7110
, DEBINOSWAP
, HANDSHAKE_REG
, 0, 2 )) {
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
);
483 stat
= rdebi(av7110
, DEBINOSWAP
, MSGSTATE
, 0, 2);
484 if (stat
& GPMQOver
) {
485 printk(KERN_ERR
"%s: GPMQOver\n", __FUNCTION__
);
486 up(&av7110
->dcomlock
);
489 else if (stat
& OSDQOver
) {
490 printk(KERN_ERR
"%s: OSDQOver\n", __FUNCTION__
);
491 up(&av7110
->dcomlock
);
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
);
503 int av7110_fw_query(struct av7110
*av7110
, u16 tag
, u16
* buf
, s16 length
)
506 ret
= av7110_fw_request(av7110
, &tag
, 0, buf
, length
);
508 printk("av7110_fw_query error\n");
513 /****************************************************************************
515 ****************************************************************************/
517 /* get version of the firmware ROM, RTSL, video ucode and ARM application */
518 int av7110_firmversion(struct av7110
*av7110
)
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
);
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
);
546 printk("DVB: AV711%d(%d) - no firmware support for CI link layer interface\n",
547 av7110
->avtype
, av7110
->dvb_adapter
->num
);
553 int av7110_diseqc_send(struct av7110
*av7110
, int len
, u8
*msg
, unsigned long burst
)
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
));
568 buf
[3] = burst
? 0x01 : 0x00;
572 for (i
= 0; i
< len
; i
++)
575 if (av7110_send_fw_cmd(av7110
, buf
, 18))
576 printk("av7110_diseqc_send error\n");
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
)
629 if (down_interruptible(&av7110
->dcomlock
))
632 while (rdebi(av7110
, DEBINOSWAP
, BUFF1_BASE
, 0, 2)) {
634 if (time_after(jiffies
, start
+ ARM_WAIT_OSD
)) {
635 printk(KERN_ERR
"%s: timeout waiting for BUFF1_BASE == 0\n",
637 up(&av7110
->dcomlock
);
641 up(&av7110
->dcomlock
);
645 static int WriteText(struct av7110
*av7110
, u8 win
, u16 x
, u16 y
, u8
* buf
)
649 int length
= strlen(buf
) + 1;
650 u16 cbuf
[5] = { (COMTYPE_OSD
<< 8) + DText
, 3, win
, x
, y
};
652 if (down_interruptible(&av7110
->dcomlock
))
656 while (rdebi(av7110
, DEBINOSWAP
, BUFF1_BASE
, 0, 2)) {
658 if (time_after(jiffies
, start
+ ARM_WAIT_OSD
)) {
659 printk(KERN_ERR
"%s: timeout waiting for BUFF1_BASE == 0\n",
661 up(&av7110
->dcomlock
);
667 while (rdebi(av7110
, DEBINOSWAP
, HANDSHAKE_REG
, 0, 2)) {
669 if (time_after(jiffies
, start
+ ARM_WAIT_SHAKE
)) {
670 printk(KERN_ERR
"%s: timeout waiting for HANDSHAKE_REG\n",
672 up(&av7110
->dcomlock
);
677 for (i
= 0; i
< length
/ 2; i
++)
678 wdebi(av7110
, DEBINOSWAP
, BUFF1_BASE
+ i
* 2,
679 swab16(*(u16
*)(buf
+ 2 * i
)), 2);
681 wdebi(av7110
, DEBINOSWAP
, BUFF1_BASE
+ i
* 2, 0, 2);
682 ret
= __av7110_send_fw_cmd(av7110
, cbuf
, 5);
683 up(&av7110
->dcomlock
);
685 printk("WriteText error\n");
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
)
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
);
753 set_current_state(TASK_INTERRUPTIBLE
);
754 if (av7110
->bmp_state
!= BMP_LOADING
755 || signal_pending(current
))
759 set_current_state(TASK_RUNNING
);
760 remove_wait_queue(&av7110
->bmpq
, &wait
);
762 if (av7110
->bmp_state
== BMP_LOADING
)
764 av7110
->bmp_state
= BMP_LOADING
;
765 if (format
== BITMAP8
) {
767 } else if (format
== BITMAP4
) {
769 } else if (format
== BITMAP2
) {
771 } else if (format
== BITMAP1
) {
774 av7110
->bmp_state
= BMP_NONE
;
777 av7110
->bmplen
= ((dx
* dy
* bpp
+ 7) & ~7) / 8;
779 if (av7110
->bmplen
> 32768) {
780 av7110
->bmp_state
= BMP_NONE
;
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
;
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
)
811 if (av7110
->bmp_state
== BMP_LOADING
) {
812 add_wait_queue(&av7110
->bmpq
, &wait
);
814 set_current_state(TASK_INTERRUPTIBLE
);
815 if (av7110
->bmp_state
!= BMP_LOADING
816 || signal_pending(current
))
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
);
828 static inline int ReleaseBitmap(struct av7110
*av7110
)
830 DEB_EE(("av7110: %p\n",av7110
));
832 if (av7110
->bmp_state
!= BMP_LOADED
)
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
)
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 */
851 return Cr
| (Cb
<< 16) | (Y
<< 8);
854 static void OSDSetColor(struct av7110
*av7110
, u8 color
, u8 r
, u8 g
, u8 b
, u8 blend
)
859 yuv
= blend
? RGB2YUV(r
,g
,b
) : 0;
861 ch
= ((yuv
>> 16) & 0xffff);
862 SetColor_(av7110
, av7110
->osdwin
, bpp2pal
[av7110
->osdbpp
[av7110
->osdwin
]],
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
)
871 int length
= last
- first
+ 1;
873 if (length
* 4 > DATA_BUFF3_SIZE
)
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,
885 bpp2pal
[av7110
->osdbpp
[av7110
->osdwin
]],
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
;
899 if (w
<= 0 || w
> 720 || h
<= 0 || h
> 576)
901 bpp
= av7110
->osdbpp
[av7110
->osdwin
] + 1;
902 bpl
= ((w
* bpp
+ 7) & ~7) / 8;
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
]],
911 BlitBitmap(av7110
, av7110
->osdwin
, x0
, y0
+ i
* lpb
, 0);
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
);
923 int av7110_osd_cmd(struct av7110
*av7110
, osd_cmd_t
*dc
)
927 DestroyOSDWindow(av7110
, av7110
->osdwin
);
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);
935 MoveWindowAbs(av7110
, av7110
->osdwin
, dc
->x0
, dc
->y0
);
936 SetColorBlend(av7110
, av7110
->osdwin
);
940 MoveWindowRel(av7110
, av7110
->osdwin
, 0, 0);
943 HideWindow(av7110
, av7110
->osdwin
);
946 DrawBlock(av7110
, av7110
->osdwin
, 0, 0, 720, 576, 0);
949 DrawBlock(av7110
, av7110
->osdwin
, 0, 0, 720, 576, dc
->color
);
952 OSDSetColor(av7110
, dc
->color
, dc
->x0
, dc
->y0
, dc
->x1
, dc
->y1
);
956 int len
= dc
->x0
-dc
->color
+1;
961 buf
= kmalloc(len
* 4, GFP_KERNEL
);
965 if (copy_from_user(buf
, dc
->data
, len
* 4)) {
970 if (FW_VERSION(av7110
->arm_app
) >= 0x2618)
971 OSDSetPalette(av7110
, buf
, dc
->color
, dc
->x0
);
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]);
987 DrawLine(av7110
, av7110
->osdwin
,
988 dc
->x0
, dc
->y0
, 0, 0, dc
->color
);
997 OSDSetBlock(av7110
, dc
->x0
, dc
->y0
, dc
->x1
, dc
->y1
, dc
->color
, dc
->data
);
1001 DrawBlock(av7110
, av7110
->osdwin
, dc
->x0
, dc
->y0
,
1002 dc
->x1
-dc
->x0
+1, dc
->y1
, dc
->color
);
1005 DrawBlock(av7110
, av7110
->osdwin
, dc
->x0
, dc
->y0
,
1006 dc
->x1
- dc
->x0
+ 1, dc
->y1
- dc
->y0
+ 1, dc
->color
);
1009 DrawLine(av7110
, av7110
->osdwin
,
1010 dc
->x0
, dc
->y0
, dc
->x1
- dc
->x0
, dc
->y1
- dc
->y0
, dc
->color
);
1020 if (strncpy_from_user(textbuf
, dc
->data
, 240) < 0)
1025 SetFont(av7110
, av7110
->osdwin
, dc
->x1
,
1026 (u16
) (dc
->color
& 0xffff), (u16
) (dc
->color
>> 16));
1028 WriteText(av7110
, av7110
->osdwin
, dc
->x0
, dc
->y0
, textbuf
);
1032 if (dc
->x0
< 1 || dc
->x0
> 7)
1034 av7110
->osdwin
= dc
->x0
;
1036 case OSD_MoveWindow
:
1037 MoveWindowAbs(av7110
, av7110
->osdwin
, dc
->x0
, dc
->y0
);
1038 SetColorBlend(av7110
, av7110
->osdwin
);
1044 #endif /* CONFIG_DVB_AV7110_OSD */