1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * av7110_hw.c: av7110 low level hardware access and firmware interface
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 1999-2002 Ralph Metzler
6*4882a593Smuzhiyun * & Marcus Metzler for convergence integrated media GmbH
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * originally based on code by:
9*4882a593Smuzhiyun * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * the project's page is at https://linuxtv.org
12*4882a593Smuzhiyun */
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun /* for debugging ARM communication: */
15*4882a593Smuzhiyun //#define COM_DEBUG
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include <linux/types.h>
18*4882a593Smuzhiyun #include <linux/kernel.h>
19*4882a593Smuzhiyun #include <linux/string.h>
20*4882a593Smuzhiyun #include <linux/delay.h>
21*4882a593Smuzhiyun #include <linux/fs.h>
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #include "av7110.h"
24*4882a593Smuzhiyun #include "av7110_hw.h"
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #define _NOHANDSHAKE
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun /*
29*4882a593Smuzhiyun * Max transfer size done by av7110_fw_cmd()
30*4882a593Smuzhiyun *
31*4882a593Smuzhiyun * The maximum size passed to this function is 6 bytes. The buffer also
32*4882a593Smuzhiyun * uses two additional ones for type and size. So, 8 bytes is enough.
33*4882a593Smuzhiyun */
34*4882a593Smuzhiyun #define MAX_XFER_SIZE 8
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun /****************************************************************************
37*4882a593Smuzhiyun * DEBI functions
38*4882a593Smuzhiyun ****************************************************************************/
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun /* This DEBI code is based on the Stradis driver
41*4882a593Smuzhiyun by Nathan Laredo <laredo@gnu.org> */
42*4882a593Smuzhiyun
av7110_debiwrite(struct av7110 * av7110,u32 config,int addr,u32 val,unsigned int count)43*4882a593Smuzhiyun int av7110_debiwrite(struct av7110 *av7110, u32 config,
44*4882a593Smuzhiyun int addr, u32 val, unsigned int count)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun struct saa7146_dev *dev = av7110->dev;
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun if (count > 32764) {
49*4882a593Smuzhiyun printk("%s: invalid count %d\n", __func__, count);
50*4882a593Smuzhiyun return -1;
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
53*4882a593Smuzhiyun printk("%s: wait_for_debi_done failed\n", __func__);
54*4882a593Smuzhiyun return -1;
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun saa7146_write(dev, DEBI_CONFIG, config);
57*4882a593Smuzhiyun if (count <= 4) /* immediate transfer */
58*4882a593Smuzhiyun saa7146_write(dev, DEBI_AD, val);
59*4882a593Smuzhiyun else /* block transfer */
60*4882a593Smuzhiyun saa7146_write(dev, DEBI_AD, av7110->debi_bus);
61*4882a593Smuzhiyun saa7146_write(dev, DEBI_COMMAND, (count << 17) | (addr & 0xffff));
62*4882a593Smuzhiyun saa7146_write(dev, MC2, (2 << 16) | 2);
63*4882a593Smuzhiyun return 0;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun
av7110_debiread(struct av7110 * av7110,u32 config,int addr,unsigned int count)66*4882a593Smuzhiyun u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, unsigned int count)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun struct saa7146_dev *dev = av7110->dev;
69*4882a593Smuzhiyun u32 result = 0;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun if (count > 32764) {
72*4882a593Smuzhiyun printk("%s: invalid count %d\n", __func__, count);
73*4882a593Smuzhiyun return 0;
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
76*4882a593Smuzhiyun printk("%s: wait_for_debi_done #1 failed\n", __func__);
77*4882a593Smuzhiyun return 0;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun saa7146_write(dev, DEBI_AD, av7110->debi_bus);
80*4882a593Smuzhiyun saa7146_write(dev, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun saa7146_write(dev, DEBI_CONFIG, config);
83*4882a593Smuzhiyun saa7146_write(dev, MC2, (2 << 16) | 2);
84*4882a593Smuzhiyun if (count > 4)
85*4882a593Smuzhiyun return count;
86*4882a593Smuzhiyun if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
87*4882a593Smuzhiyun printk("%s: wait_for_debi_done #2 failed\n", __func__);
88*4882a593Smuzhiyun return 0;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun result = saa7146_read(dev, DEBI_AD);
92*4882a593Smuzhiyun result &= (0xffffffffUL >> ((4 - count) * 8));
93*4882a593Smuzhiyun return result;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun /* av7110 ARM core boot stuff */
99*4882a593Smuzhiyun #if 0
100*4882a593Smuzhiyun void av7110_reset_arm(struct av7110 *av7110)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTLO);
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun /* Disable DEBI and GPIO irq */
105*4882a593Smuzhiyun SAA7146_IER_DISABLE(av7110->dev, MASK_19 | MASK_03);
106*4882a593Smuzhiyun SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTHI);
109*4882a593Smuzhiyun msleep(30); /* the firmware needs some time to initialize */
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun ARM_ResetMailBox(av7110);
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
114*4882a593Smuzhiyun SAA7146_IER_ENABLE(av7110->dev, MASK_03);
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun av7110->arm_ready = 1;
117*4882a593Smuzhiyun dprintk(1, "reset ARM\n");
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun #endif /* 0 */
120*4882a593Smuzhiyun
waitdebi(struct av7110 * av7110,int adr,int state)121*4882a593Smuzhiyun static int waitdebi(struct av7110 *av7110, int adr, int state)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun int k;
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun dprintk(4, "%p\n", av7110);
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun for (k = 0; k < 100; k++) {
128*4882a593Smuzhiyun if (irdebi(av7110, DEBINOSWAP, adr, 0, 2) == state)
129*4882a593Smuzhiyun return 0;
130*4882a593Smuzhiyun udelay(5);
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun return -ETIMEDOUT;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun
load_dram(struct av7110 * av7110,u32 * data,int len)135*4882a593Smuzhiyun static int load_dram(struct av7110 *av7110, u32 *data, int len)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun int i;
138*4882a593Smuzhiyun int blocks, rest;
139*4882a593Smuzhiyun u32 base, bootblock = AV7110_BOOT_BLOCK;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun dprintk(4, "%p\n", av7110);
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun blocks = len / AV7110_BOOT_MAX_SIZE;
144*4882a593Smuzhiyun rest = len % AV7110_BOOT_MAX_SIZE;
145*4882a593Smuzhiyun base = DRAM_START_CODE;
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun for (i = 0; i < blocks; i++) {
148*4882a593Smuzhiyun if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
149*4882a593Smuzhiyun printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i);
150*4882a593Smuzhiyun return -ETIMEDOUT;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun dprintk(4, "writing DRAM block %d\n", i);
153*4882a593Smuzhiyun mwdebi(av7110, DEBISWAB, bootblock,
154*4882a593Smuzhiyun ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
155*4882a593Smuzhiyun bootblock ^= 0x1400;
156*4882a593Smuzhiyun iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
157*4882a593Smuzhiyun iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2);
158*4882a593Smuzhiyun iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
159*4882a593Smuzhiyun base += AV7110_BOOT_MAX_SIZE;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun if (rest > 0) {
163*4882a593Smuzhiyun if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
164*4882a593Smuzhiyun printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n");
165*4882a593Smuzhiyun return -ETIMEDOUT;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun if (rest > 4)
168*4882a593Smuzhiyun mwdebi(av7110, DEBISWAB, bootblock,
169*4882a593Smuzhiyun ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, rest);
170*4882a593Smuzhiyun else
171*4882a593Smuzhiyun mwdebi(av7110, DEBISWAB, bootblock,
172*4882a593Smuzhiyun ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
175*4882a593Smuzhiyun iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2);
176*4882a593Smuzhiyun iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
179*4882a593Smuzhiyun printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n");
180*4882a593Smuzhiyun return -ETIMEDOUT;
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, 0, 2);
183*4882a593Smuzhiyun iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
184*4882a593Smuzhiyun if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_AV7110_BOOT_COMPLETE) < 0) {
185*4882a593Smuzhiyun printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n");
186*4882a593Smuzhiyun return -ETIMEDOUT;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun return 0;
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun /* we cannot write av7110 DRAM directly, so load a bootloader into
193*4882a593Smuzhiyun * the DPRAM which implements a simple boot protocol */
av7110_bootarm(struct av7110 * av7110)194*4882a593Smuzhiyun int av7110_bootarm(struct av7110 *av7110)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun const struct firmware *fw;
197*4882a593Smuzhiyun const char *fw_name = "av7110/bootcode.bin";
198*4882a593Smuzhiyun struct saa7146_dev *dev = av7110->dev;
199*4882a593Smuzhiyun u32 ret;
200*4882a593Smuzhiyun int i;
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun dprintk(4, "%p\n", av7110);
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun av7110->arm_ready = 0;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun /* Disable DEBI and GPIO irq */
209*4882a593Smuzhiyun SAA7146_IER_DISABLE(av7110->dev, MASK_03 | MASK_19);
210*4882a593Smuzhiyun SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun /* enable DEBI */
213*4882a593Smuzhiyun saa7146_write(av7110->dev, MC1, 0x08800880);
214*4882a593Smuzhiyun saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000);
215*4882a593Smuzhiyun saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun /* test DEBI */
218*4882a593Smuzhiyun iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
219*4882a593Smuzhiyun /* FIXME: Why does Nexus CA require 2x iwdebi for first init? */
220*4882a593Smuzhiyun iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun if ((ret=irdebi(av7110, DEBINOSWAP, DPRAM_BASE, 0, 4)) != 0x10325476) {
223*4882a593Smuzhiyun printk(KERN_ERR "dvb-ttpci: debi test in av7110_bootarm() failed: %08x != %08x (check your BIOS 'Plug&Play OS' settings)\n",
224*4882a593Smuzhiyun ret, 0x10325476);
225*4882a593Smuzhiyun return -1;
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun for (i = 0; i < 8192; i += 4)
228*4882a593Smuzhiyun iwdebi(av7110, DEBISWAP, DPRAM_BASE + i, 0x00, 4);
229*4882a593Smuzhiyun dprintk(2, "debi test OK\n");
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun /* boot */
232*4882a593Smuzhiyun dprintk(1, "load boot code\n");
233*4882a593Smuzhiyun saa7146_setgpio(dev, ARM_IRQ_LINE, SAA7146_GPIO_IRQLO);
234*4882a593Smuzhiyun //saa7146_setgpio(dev, DEBI_DONE_LINE, SAA7146_GPIO_INPUT);
235*4882a593Smuzhiyun //saa7146_setgpio(dev, 3, SAA7146_GPIO_INPUT);
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun ret = request_firmware(&fw, fw_name, &dev->pci->dev);
238*4882a593Smuzhiyun if (ret) {
239*4882a593Smuzhiyun printk(KERN_ERR "dvb-ttpci: Failed to load firmware \"%s\"\n",
240*4882a593Smuzhiyun fw_name);
241*4882a593Smuzhiyun return ret;
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun mwdebi(av7110, DEBISWAB, DPRAM_BASE, fw->data, fw->size);
245*4882a593Smuzhiyun release_firmware(fw);
246*4882a593Smuzhiyun iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
249*4882a593Smuzhiyun printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): saa7146_wait_for_debi_done() timed out\n");
250*4882a593Smuzhiyun return -ETIMEDOUT;
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
253*4882a593Smuzhiyun mdelay(1);
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun dprintk(1, "load dram code\n");
256*4882a593Smuzhiyun if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0) {
257*4882a593Smuzhiyun printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): load_dram() failed\n");
258*4882a593Smuzhiyun return -1;
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
262*4882a593Smuzhiyun mdelay(1);
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun dprintk(1, "load dpram code\n");
265*4882a593Smuzhiyun mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram);
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
268*4882a593Smuzhiyun printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): saa7146_wait_for_debi_done() timed out after loading DRAM\n");
269*4882a593Smuzhiyun return -ETIMEDOUT;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
272*4882a593Smuzhiyun msleep(30); /* the firmware needs some time to initialize */
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun //ARM_ClearIrq(av7110);
275*4882a593Smuzhiyun ARM_ResetMailBox(av7110);
276*4882a593Smuzhiyun SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
277*4882a593Smuzhiyun SAA7146_IER_ENABLE(av7110->dev, MASK_03);
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun av7110->arm_errors = 0;
280*4882a593Smuzhiyun av7110->arm_ready = 1;
281*4882a593Smuzhiyun return 0;
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun MODULE_FIRMWARE("av7110/bootcode.bin");
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun /****************************************************************************
286*4882a593Smuzhiyun * DEBI command polling
287*4882a593Smuzhiyun ****************************************************************************/
288*4882a593Smuzhiyun
av7110_wait_msgstate(struct av7110 * av7110,u16 flags)289*4882a593Smuzhiyun int av7110_wait_msgstate(struct av7110 *av7110, u16 flags)
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun unsigned long start;
292*4882a593Smuzhiyun u32 stat;
293*4882a593Smuzhiyun int err;
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun if (FW_VERSION(av7110->arm_app) <= 0x261c) {
296*4882a593Smuzhiyun /* not supported by old firmware */
297*4882a593Smuzhiyun msleep(50);
298*4882a593Smuzhiyun return 0;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun /* new firmware */
302*4882a593Smuzhiyun start = jiffies;
303*4882a593Smuzhiyun for (;;) {
304*4882a593Smuzhiyun err = time_after(jiffies, start + ARM_WAIT_FREE);
305*4882a593Smuzhiyun if (mutex_lock_interruptible(&av7110->dcomlock))
306*4882a593Smuzhiyun return -ERESTARTSYS;
307*4882a593Smuzhiyun stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
308*4882a593Smuzhiyun mutex_unlock(&av7110->dcomlock);
309*4882a593Smuzhiyun if ((stat & flags) == 0)
310*4882a593Smuzhiyun break;
311*4882a593Smuzhiyun if (err) {
312*4882a593Smuzhiyun printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n",
313*4882a593Smuzhiyun __func__, stat & flags);
314*4882a593Smuzhiyun return -ETIMEDOUT;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun msleep(1);
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun return 0;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun
__av7110_send_fw_cmd(struct av7110 * av7110,u16 * buf,int length)321*4882a593Smuzhiyun static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
322*4882a593Smuzhiyun {
323*4882a593Smuzhiyun int i;
324*4882a593Smuzhiyun unsigned long start;
325*4882a593Smuzhiyun char *type = NULL;
326*4882a593Smuzhiyun u16 flags[2] = {0, 0};
327*4882a593Smuzhiyun u32 stat;
328*4882a593Smuzhiyun int err;
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun // dprintk(4, "%p\n", av7110);
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun if (!av7110->arm_ready) {
333*4882a593Smuzhiyun dprintk(1, "arm not ready.\n");
334*4882a593Smuzhiyun return -ENXIO;
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun start = jiffies;
338*4882a593Smuzhiyun while (1) {
339*4882a593Smuzhiyun err = time_after(jiffies, start + ARM_WAIT_FREE);
340*4882a593Smuzhiyun if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
341*4882a593Smuzhiyun break;
342*4882a593Smuzhiyun if (err) {
343*4882a593Smuzhiyun printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __func__);
344*4882a593Smuzhiyun av7110->arm_errors++;
345*4882a593Smuzhiyun return -ETIMEDOUT;
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun msleep(1);
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun if (FW_VERSION(av7110->arm_app) <= 0x261f)
351*4882a593Smuzhiyun wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2);
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun #ifndef _NOHANDSHAKE
354*4882a593Smuzhiyun start = jiffies;
355*4882a593Smuzhiyun while (1) {
356*4882a593Smuzhiyun err = time_after(jiffies, start + ARM_WAIT_SHAKE);
357*4882a593Smuzhiyun if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
358*4882a593Smuzhiyun break;
359*4882a593Smuzhiyun if (err) {
360*4882a593Smuzhiyun printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __func__);
361*4882a593Smuzhiyun return -ETIMEDOUT;
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun msleep(1);
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun #endif
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun switch ((buf[0] >> 8) & 0xff) {
368*4882a593Smuzhiyun case COMTYPE_PIDFILTER:
369*4882a593Smuzhiyun case COMTYPE_ENCODER:
370*4882a593Smuzhiyun case COMTYPE_REC_PLAY:
371*4882a593Smuzhiyun case COMTYPE_MPEGDECODER:
372*4882a593Smuzhiyun type = "MSG";
373*4882a593Smuzhiyun flags[0] = GPMQOver;
374*4882a593Smuzhiyun flags[1] = GPMQFull;
375*4882a593Smuzhiyun break;
376*4882a593Smuzhiyun case COMTYPE_OSD:
377*4882a593Smuzhiyun type = "OSD";
378*4882a593Smuzhiyun flags[0] = OSDQOver;
379*4882a593Smuzhiyun flags[1] = OSDQFull;
380*4882a593Smuzhiyun break;
381*4882a593Smuzhiyun case COMTYPE_MISC:
382*4882a593Smuzhiyun if (FW_VERSION(av7110->arm_app) >= 0x261d) {
383*4882a593Smuzhiyun type = "MSG";
384*4882a593Smuzhiyun flags[0] = GPMQOver;
385*4882a593Smuzhiyun flags[1] = GPMQBusy;
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun break;
388*4882a593Smuzhiyun default:
389*4882a593Smuzhiyun break;
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun if (type != NULL) {
393*4882a593Smuzhiyun /* non-immediate COMMAND type */
394*4882a593Smuzhiyun start = jiffies;
395*4882a593Smuzhiyun for (;;) {
396*4882a593Smuzhiyun err = time_after(jiffies, start + ARM_WAIT_FREE);
397*4882a593Smuzhiyun stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
398*4882a593Smuzhiyun if (stat & flags[0]) {
399*4882a593Smuzhiyun printk(KERN_ERR "%s: %s QUEUE overflow\n",
400*4882a593Smuzhiyun __func__, type);
401*4882a593Smuzhiyun return -1;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun if ((stat & flags[1]) == 0)
404*4882a593Smuzhiyun break;
405*4882a593Smuzhiyun if (err) {
406*4882a593Smuzhiyun printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n",
407*4882a593Smuzhiyun __func__, type);
408*4882a593Smuzhiyun av7110->arm_errors++;
409*4882a593Smuzhiyun return -ETIMEDOUT;
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun msleep(1);
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun for (i = 2; i < length; i++)
416*4882a593Smuzhiyun wdebi(av7110, DEBINOSWAP, COMMAND + 2 * i, (u32) buf[i], 2);
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun if (length)
419*4882a593Smuzhiyun wdebi(av7110, DEBINOSWAP, COMMAND + 2, (u32) buf[1], 2);
420*4882a593Smuzhiyun else
421*4882a593Smuzhiyun wdebi(av7110, DEBINOSWAP, COMMAND + 2, 0, 2);
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun wdebi(av7110, DEBINOSWAP, COMMAND, (u32) buf[0], 2);
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun if (FW_VERSION(av7110->arm_app) <= 0x261f)
426*4882a593Smuzhiyun wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2);
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun #ifdef COM_DEBUG
429*4882a593Smuzhiyun start = jiffies;
430*4882a593Smuzhiyun while (1) {
431*4882a593Smuzhiyun err = time_after(jiffies, start + ARM_WAIT_FREE);
432*4882a593Smuzhiyun if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
433*4882a593Smuzhiyun break;
434*4882a593Smuzhiyun if (err) {
435*4882a593Smuzhiyun printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n",
436*4882a593Smuzhiyun __func__, (buf[0] >> 8) & 0xff);
437*4882a593Smuzhiyun return -ETIMEDOUT;
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun msleep(1);
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
443*4882a593Smuzhiyun if (stat & GPMQOver) {
444*4882a593Smuzhiyun printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __func__);
445*4882a593Smuzhiyun return -ENOSPC;
446*4882a593Smuzhiyun }
447*4882a593Smuzhiyun else if (stat & OSDQOver) {
448*4882a593Smuzhiyun printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __func__);
449*4882a593Smuzhiyun return -ENOSPC;
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun #endif
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun return 0;
454*4882a593Smuzhiyun }
455*4882a593Smuzhiyun
av7110_send_fw_cmd(struct av7110 * av7110,u16 * buf,int length)456*4882a593Smuzhiyun static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
457*4882a593Smuzhiyun {
458*4882a593Smuzhiyun int ret;
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun // dprintk(4, "%p\n", av7110);
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun if (!av7110->arm_ready) {
463*4882a593Smuzhiyun dprintk(1, "arm not ready.\n");
464*4882a593Smuzhiyun return -1;
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun if (mutex_lock_interruptible(&av7110->dcomlock))
467*4882a593Smuzhiyun return -ERESTARTSYS;
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun ret = __av7110_send_fw_cmd(av7110, buf, length);
470*4882a593Smuzhiyun mutex_unlock(&av7110->dcomlock);
471*4882a593Smuzhiyun if (ret && ret!=-ERESTARTSYS)
472*4882a593Smuzhiyun printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
473*4882a593Smuzhiyun __func__, ret);
474*4882a593Smuzhiyun return ret;
475*4882a593Smuzhiyun }
476*4882a593Smuzhiyun
av7110_fw_cmd(struct av7110 * av7110,int type,int com,int num,...)477*4882a593Smuzhiyun int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...)
478*4882a593Smuzhiyun {
479*4882a593Smuzhiyun va_list args;
480*4882a593Smuzhiyun u16 buf[MAX_XFER_SIZE];
481*4882a593Smuzhiyun int i, ret;
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun // dprintk(4, "%p\n", av7110);
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun if (2 + num > ARRAY_SIZE(buf)) {
486*4882a593Smuzhiyun printk(KERN_WARNING
487*4882a593Smuzhiyun "%s: %s len=%d is too big!\n",
488*4882a593Smuzhiyun KBUILD_MODNAME, __func__, num);
489*4882a593Smuzhiyun return -EINVAL;
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun buf[0] = ((type << 8) | com);
493*4882a593Smuzhiyun buf[1] = num;
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun if (num) {
496*4882a593Smuzhiyun va_start(args, num);
497*4882a593Smuzhiyun for (i = 0; i < num; i++)
498*4882a593Smuzhiyun buf[i + 2] = va_arg(args, u32);
499*4882a593Smuzhiyun va_end(args);
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun ret = av7110_send_fw_cmd(av7110, buf, num + 2);
503*4882a593Smuzhiyun if (ret && ret != -ERESTARTSYS)
504*4882a593Smuzhiyun printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret);
505*4882a593Smuzhiyun return ret;
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun #if 0
509*4882a593Smuzhiyun int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len)
510*4882a593Smuzhiyun {
511*4882a593Smuzhiyun int i, ret;
512*4882a593Smuzhiyun u16 cmd[18] = { ((COMTYPE_COMMON_IF << 8) + subcom),
513*4882a593Smuzhiyun 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun dprintk(4, "%p\n", av7110);
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun for(i = 0; i < len && i < 32; i++)
518*4882a593Smuzhiyun {
519*4882a593Smuzhiyun if(i % 2 == 0)
520*4882a593Smuzhiyun cmd[(i / 2) + 2] = (u16)(buf[i]) << 8;
521*4882a593Smuzhiyun else
522*4882a593Smuzhiyun cmd[(i / 2) + 2] |= buf[i];
523*4882a593Smuzhiyun }
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun ret = av7110_send_fw_cmd(av7110, cmd, 18);
526*4882a593Smuzhiyun if (ret && ret != -ERESTARTSYS)
527*4882a593Smuzhiyun printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret);
528*4882a593Smuzhiyun return ret;
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun #endif /* 0 */
531*4882a593Smuzhiyun
av7110_fw_request(struct av7110 * av7110,u16 * request_buf,int request_buf_len,u16 * reply_buf,int reply_buf_len)532*4882a593Smuzhiyun int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
533*4882a593Smuzhiyun int request_buf_len, u16 *reply_buf, int reply_buf_len)
534*4882a593Smuzhiyun {
535*4882a593Smuzhiyun int err;
536*4882a593Smuzhiyun s16 i;
537*4882a593Smuzhiyun unsigned long start;
538*4882a593Smuzhiyun #ifdef COM_DEBUG
539*4882a593Smuzhiyun u32 stat;
540*4882a593Smuzhiyun #endif
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun dprintk(4, "%p\n", av7110);
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun if (!av7110->arm_ready) {
545*4882a593Smuzhiyun dprintk(1, "arm not ready.\n");
546*4882a593Smuzhiyun return -1;
547*4882a593Smuzhiyun }
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun if (mutex_lock_interruptible(&av7110->dcomlock))
550*4882a593Smuzhiyun return -ERESTARTSYS;
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) {
553*4882a593Smuzhiyun mutex_unlock(&av7110->dcomlock);
554*4882a593Smuzhiyun printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err);
555*4882a593Smuzhiyun return err;
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun start = jiffies;
559*4882a593Smuzhiyun while (1) {
560*4882a593Smuzhiyun err = time_after(jiffies, start + ARM_WAIT_FREE);
561*4882a593Smuzhiyun if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
562*4882a593Smuzhiyun break;
563*4882a593Smuzhiyun if (err) {
564*4882a593Smuzhiyun printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __func__);
565*4882a593Smuzhiyun mutex_unlock(&av7110->dcomlock);
566*4882a593Smuzhiyun return -ETIMEDOUT;
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun #ifdef _NOHANDSHAKE
569*4882a593Smuzhiyun msleep(1);
570*4882a593Smuzhiyun #endif
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun #ifndef _NOHANDSHAKE
574*4882a593Smuzhiyun start = jiffies;
575*4882a593Smuzhiyun while (1) {
576*4882a593Smuzhiyun err = time_after(jiffies, start + ARM_WAIT_SHAKE);
577*4882a593Smuzhiyun if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
578*4882a593Smuzhiyun break;
579*4882a593Smuzhiyun if (err) {
580*4882a593Smuzhiyun printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __func__);
581*4882a593Smuzhiyun mutex_unlock(&av7110->dcomlock);
582*4882a593Smuzhiyun return -ETIMEDOUT;
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun msleep(1);
585*4882a593Smuzhiyun }
586*4882a593Smuzhiyun #endif
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun #ifdef COM_DEBUG
589*4882a593Smuzhiyun stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
590*4882a593Smuzhiyun if (stat & GPMQOver) {
591*4882a593Smuzhiyun printk(KERN_ERR "%s: GPMQOver\n", __func__);
592*4882a593Smuzhiyun mutex_unlock(&av7110->dcomlock);
593*4882a593Smuzhiyun return -1;
594*4882a593Smuzhiyun }
595*4882a593Smuzhiyun else if (stat & OSDQOver) {
596*4882a593Smuzhiyun printk(KERN_ERR "%s: OSDQOver\n", __func__);
597*4882a593Smuzhiyun mutex_unlock(&av7110->dcomlock);
598*4882a593Smuzhiyun return -1;
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun #endif
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun for (i = 0; i < reply_buf_len; i++)
603*4882a593Smuzhiyun reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2);
604*4882a593Smuzhiyun
605*4882a593Smuzhiyun mutex_unlock(&av7110->dcomlock);
606*4882a593Smuzhiyun return 0;
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun
av7110_fw_query(struct av7110 * av7110,u16 tag,u16 * buf,s16 length)609*4882a593Smuzhiyun static int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length)
610*4882a593Smuzhiyun {
611*4882a593Smuzhiyun int ret;
612*4882a593Smuzhiyun ret = av7110_fw_request(av7110, &tag, 0, buf, length);
613*4882a593Smuzhiyun if (ret)
614*4882a593Smuzhiyun printk(KERN_ERR "dvb-ttpci: av7110_fw_query error %d\n", ret);
615*4882a593Smuzhiyun return ret;
616*4882a593Smuzhiyun }
617*4882a593Smuzhiyun
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun /****************************************************************************
620*4882a593Smuzhiyun * Firmware commands
621*4882a593Smuzhiyun ****************************************************************************/
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun /* get version of the firmware ROM, RTSL, video ucode and ARM application */
av7110_firmversion(struct av7110 * av7110)624*4882a593Smuzhiyun int av7110_firmversion(struct av7110 *av7110)
625*4882a593Smuzhiyun {
626*4882a593Smuzhiyun u16 buf[20];
627*4882a593Smuzhiyun u16 tag = ((COMTYPE_REQUEST << 8) + ReqVersion);
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun dprintk(4, "%p\n", av7110);
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun if (av7110_fw_query(av7110, tag, buf, 16)) {
632*4882a593Smuzhiyun printk("dvb-ttpci: failed to boot firmware @ card %d\n",
633*4882a593Smuzhiyun av7110->dvb_adapter.num);
634*4882a593Smuzhiyun return -EIO;
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun av7110->arm_fw = (buf[0] << 16) + buf[1];
638*4882a593Smuzhiyun av7110->arm_rtsl = (buf[2] << 16) + buf[3];
639*4882a593Smuzhiyun av7110->arm_vid = (buf[4] << 16) + buf[5];
640*4882a593Smuzhiyun av7110->arm_app = (buf[6] << 16) + buf[7];
641*4882a593Smuzhiyun av7110->avtype = (buf[8] << 16) + buf[9];
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun printk("dvb-ttpci: info @ card %d: firm %08x, rtsl %08x, vid %08x, app %08x\n",
644*4882a593Smuzhiyun av7110->dvb_adapter.num, av7110->arm_fw,
645*4882a593Smuzhiyun av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app);
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun /* print firmware capabilities */
648*4882a593Smuzhiyun if (FW_CI_LL_SUPPORT(av7110->arm_app))
649*4882a593Smuzhiyun printk("dvb-ttpci: firmware @ card %d supports CI link layer interface\n",
650*4882a593Smuzhiyun av7110->dvb_adapter.num);
651*4882a593Smuzhiyun else
652*4882a593Smuzhiyun printk("dvb-ttpci: no firmware support for CI link layer interface @ card %d\n",
653*4882a593Smuzhiyun av7110->dvb_adapter.num);
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun return 0;
656*4882a593Smuzhiyun }
657*4882a593Smuzhiyun
658*4882a593Smuzhiyun
av7110_diseqc_send(struct av7110 * av7110,int len,u8 * msg,unsigned long burst)659*4882a593Smuzhiyun int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst)
660*4882a593Smuzhiyun {
661*4882a593Smuzhiyun int i, ret;
662*4882a593Smuzhiyun u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) + SendDiSEqC),
663*4882a593Smuzhiyun 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun dprintk(4, "%p\n", av7110);
666*4882a593Smuzhiyun
667*4882a593Smuzhiyun if (len > 10)
668*4882a593Smuzhiyun len = 10;
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun buf[1] = len + 2;
671*4882a593Smuzhiyun buf[2] = len;
672*4882a593Smuzhiyun
673*4882a593Smuzhiyun if (burst != -1)
674*4882a593Smuzhiyun buf[3] = burst ? 0x01 : 0x00;
675*4882a593Smuzhiyun else
676*4882a593Smuzhiyun buf[3] = 0xffff;
677*4882a593Smuzhiyun
678*4882a593Smuzhiyun for (i = 0; i < len; i++)
679*4882a593Smuzhiyun buf[i + 4] = msg[i];
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun ret = av7110_send_fw_cmd(av7110, buf, 18);
682*4882a593Smuzhiyun if (ret && ret!=-ERESTARTSYS)
683*4882a593Smuzhiyun printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret);
684*4882a593Smuzhiyun return ret;
685*4882a593Smuzhiyun }
686*4882a593Smuzhiyun
687*4882a593Smuzhiyun
688*4882a593Smuzhiyun #ifdef CONFIG_DVB_AV7110_OSD
689*4882a593Smuzhiyun
SetColorBlend(struct av7110 * av7110,u8 windownr)690*4882a593Smuzhiyun static inline int SetColorBlend(struct av7110 *av7110, u8 windownr)
691*4882a593Smuzhiyun {
692*4882a593Smuzhiyun return av7110_fw_cmd(av7110, COMTYPE_OSD, SetCBlend, 1, windownr);
693*4882a593Smuzhiyun }
694*4882a593Smuzhiyun
SetBlend_(struct av7110 * av7110,u8 windownr,enum av7110_osd_palette_type colordepth,u16 index,u8 blending)695*4882a593Smuzhiyun static inline int SetBlend_(struct av7110 *av7110, u8 windownr,
696*4882a593Smuzhiyun enum av7110_osd_palette_type colordepth, u16 index, u8 blending)
697*4882a593Smuzhiyun {
698*4882a593Smuzhiyun return av7110_fw_cmd(av7110, COMTYPE_OSD, SetBlend, 4,
699*4882a593Smuzhiyun windownr, colordepth, index, blending);
700*4882a593Smuzhiyun }
701*4882a593Smuzhiyun
SetColor_(struct av7110 * av7110,u8 windownr,enum av7110_osd_palette_type colordepth,u16 index,u16 colorhi,u16 colorlo)702*4882a593Smuzhiyun static inline int SetColor_(struct av7110 *av7110, u8 windownr,
703*4882a593Smuzhiyun enum av7110_osd_palette_type colordepth, u16 index, u16 colorhi, u16 colorlo)
704*4882a593Smuzhiyun {
705*4882a593Smuzhiyun return av7110_fw_cmd(av7110, COMTYPE_OSD, SetColor, 5,
706*4882a593Smuzhiyun windownr, colordepth, index, colorhi, colorlo);
707*4882a593Smuzhiyun }
708*4882a593Smuzhiyun
SetFont(struct av7110 * av7110,u8 windownr,u8 fontsize,u16 colorfg,u16 colorbg)709*4882a593Smuzhiyun static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize,
710*4882a593Smuzhiyun u16 colorfg, u16 colorbg)
711*4882a593Smuzhiyun {
712*4882a593Smuzhiyun return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Font, 4,
713*4882a593Smuzhiyun windownr, fontsize, colorfg, colorbg);
714*4882a593Smuzhiyun }
715*4882a593Smuzhiyun
FlushText(struct av7110 * av7110)716*4882a593Smuzhiyun static int FlushText(struct av7110 *av7110)
717*4882a593Smuzhiyun {
718*4882a593Smuzhiyun unsigned long start;
719*4882a593Smuzhiyun int err;
720*4882a593Smuzhiyun
721*4882a593Smuzhiyun if (mutex_lock_interruptible(&av7110->dcomlock))
722*4882a593Smuzhiyun return -ERESTARTSYS;
723*4882a593Smuzhiyun start = jiffies;
724*4882a593Smuzhiyun while (1) {
725*4882a593Smuzhiyun err = time_after(jiffies, start + ARM_WAIT_OSD);
726*4882a593Smuzhiyun if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
727*4882a593Smuzhiyun break;
728*4882a593Smuzhiyun if (err) {
729*4882a593Smuzhiyun printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n",
730*4882a593Smuzhiyun __func__);
731*4882a593Smuzhiyun mutex_unlock(&av7110->dcomlock);
732*4882a593Smuzhiyun return -ETIMEDOUT;
733*4882a593Smuzhiyun }
734*4882a593Smuzhiyun msleep(1);
735*4882a593Smuzhiyun }
736*4882a593Smuzhiyun mutex_unlock(&av7110->dcomlock);
737*4882a593Smuzhiyun return 0;
738*4882a593Smuzhiyun }
739*4882a593Smuzhiyun
WriteText(struct av7110 * av7110,u8 win,u16 x,u16 y,char * buf)740*4882a593Smuzhiyun static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, char *buf)
741*4882a593Smuzhiyun {
742*4882a593Smuzhiyun int i, ret;
743*4882a593Smuzhiyun unsigned long start;
744*4882a593Smuzhiyun int length = strlen(buf) + 1;
745*4882a593Smuzhiyun u16 cbuf[5] = { (COMTYPE_OSD << 8) + DText, 3, win, x, y };
746*4882a593Smuzhiyun
747*4882a593Smuzhiyun if (mutex_lock_interruptible(&av7110->dcomlock))
748*4882a593Smuzhiyun return -ERESTARTSYS;
749*4882a593Smuzhiyun
750*4882a593Smuzhiyun start = jiffies;
751*4882a593Smuzhiyun while (1) {
752*4882a593Smuzhiyun ret = time_after(jiffies, start + ARM_WAIT_OSD);
753*4882a593Smuzhiyun if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
754*4882a593Smuzhiyun break;
755*4882a593Smuzhiyun if (ret) {
756*4882a593Smuzhiyun printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n",
757*4882a593Smuzhiyun __func__);
758*4882a593Smuzhiyun mutex_unlock(&av7110->dcomlock);
759*4882a593Smuzhiyun return -ETIMEDOUT;
760*4882a593Smuzhiyun }
761*4882a593Smuzhiyun msleep(1);
762*4882a593Smuzhiyun }
763*4882a593Smuzhiyun #ifndef _NOHANDSHAKE
764*4882a593Smuzhiyun start = jiffies;
765*4882a593Smuzhiyun while (1) {
766*4882a593Smuzhiyun ret = time_after(jiffies, start + ARM_WAIT_SHAKE);
767*4882a593Smuzhiyun if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
768*4882a593Smuzhiyun break;
769*4882a593Smuzhiyun if (ret) {
770*4882a593Smuzhiyun printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n",
771*4882a593Smuzhiyun __func__);
772*4882a593Smuzhiyun mutex_unlock(&av7110->dcomlock);
773*4882a593Smuzhiyun return -ETIMEDOUT;
774*4882a593Smuzhiyun }
775*4882a593Smuzhiyun msleep(1);
776*4882a593Smuzhiyun }
777*4882a593Smuzhiyun #endif
778*4882a593Smuzhiyun for (i = 0; i < length / 2; i++)
779*4882a593Smuzhiyun wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2,
780*4882a593Smuzhiyun swab16(*(u16 *)(buf + 2 * i)), 2);
781*4882a593Smuzhiyun if (length & 1)
782*4882a593Smuzhiyun wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2);
783*4882a593Smuzhiyun ret = __av7110_send_fw_cmd(av7110, cbuf, 5);
784*4882a593Smuzhiyun mutex_unlock(&av7110->dcomlock);
785*4882a593Smuzhiyun if (ret && ret!=-ERESTARTSYS)
786*4882a593Smuzhiyun printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret);
787*4882a593Smuzhiyun return ret;
788*4882a593Smuzhiyun }
789*4882a593Smuzhiyun
DrawLine(struct av7110 * av7110,u8 windownr,u16 x,u16 y,u16 dx,u16 dy,u16 color)790*4882a593Smuzhiyun static inline int DrawLine(struct av7110 *av7110, u8 windownr,
791*4882a593Smuzhiyun u16 x, u16 y, u16 dx, u16 dy, u16 color)
792*4882a593Smuzhiyun {
793*4882a593Smuzhiyun return av7110_fw_cmd(av7110, COMTYPE_OSD, DLine, 6,
794*4882a593Smuzhiyun windownr, x, y, dx, dy, color);
795*4882a593Smuzhiyun }
796*4882a593Smuzhiyun
DrawBlock(struct av7110 * av7110,u8 windownr,u16 x,u16 y,u16 dx,u16 dy,u16 color)797*4882a593Smuzhiyun static inline int DrawBlock(struct av7110 *av7110, u8 windownr,
798*4882a593Smuzhiyun u16 x, u16 y, u16 dx, u16 dy, u16 color)
799*4882a593Smuzhiyun {
800*4882a593Smuzhiyun return av7110_fw_cmd(av7110, COMTYPE_OSD, DBox, 6,
801*4882a593Smuzhiyun windownr, x, y, dx, dy, color);
802*4882a593Smuzhiyun }
803*4882a593Smuzhiyun
HideWindow(struct av7110 * av7110,u8 windownr)804*4882a593Smuzhiyun static inline int HideWindow(struct av7110 *av7110, u8 windownr)
805*4882a593Smuzhiyun {
806*4882a593Smuzhiyun return av7110_fw_cmd(av7110, COMTYPE_OSD, WHide, 1, windownr);
807*4882a593Smuzhiyun }
808*4882a593Smuzhiyun
MoveWindowRel(struct av7110 * av7110,u8 windownr,u16 x,u16 y)809*4882a593Smuzhiyun static inline int MoveWindowRel(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
810*4882a593Smuzhiyun {
811*4882a593Smuzhiyun return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveD, 3, windownr, x, y);
812*4882a593Smuzhiyun }
813*4882a593Smuzhiyun
MoveWindowAbs(struct av7110 * av7110,u8 windownr,u16 x,u16 y)814*4882a593Smuzhiyun static inline int MoveWindowAbs(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
815*4882a593Smuzhiyun {
816*4882a593Smuzhiyun return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveA, 3, windownr, x, y);
817*4882a593Smuzhiyun }
818*4882a593Smuzhiyun
DestroyOSDWindow(struct av7110 * av7110,u8 windownr)819*4882a593Smuzhiyun static inline int DestroyOSDWindow(struct av7110 *av7110, u8 windownr)
820*4882a593Smuzhiyun {
821*4882a593Smuzhiyun return av7110_fw_cmd(av7110, COMTYPE_OSD, WDestroy, 1, windownr);
822*4882a593Smuzhiyun }
823*4882a593Smuzhiyun
CreateOSDWindow(struct av7110 * av7110,u8 windownr,osd_raw_window_t disptype,u16 width,u16 height)824*4882a593Smuzhiyun static inline int CreateOSDWindow(struct av7110 *av7110, u8 windownr,
825*4882a593Smuzhiyun osd_raw_window_t disptype,
826*4882a593Smuzhiyun u16 width, u16 height)
827*4882a593Smuzhiyun {
828*4882a593Smuzhiyun return av7110_fw_cmd(av7110, COMTYPE_OSD, WCreate, 4,
829*4882a593Smuzhiyun windownr, disptype, width, height);
830*4882a593Smuzhiyun }
831*4882a593Smuzhiyun
832*4882a593Smuzhiyun
833*4882a593Smuzhiyun static enum av7110_osd_palette_type bpp2pal[8] = {
834*4882a593Smuzhiyun Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit
835*4882a593Smuzhiyun };
836*4882a593Smuzhiyun static osd_raw_window_t bpp2bit[8] = {
837*4882a593Smuzhiyun OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8
838*4882a593Smuzhiyun };
839*4882a593Smuzhiyun
WaitUntilBmpLoaded(struct av7110 * av7110)840*4882a593Smuzhiyun static inline int WaitUntilBmpLoaded(struct av7110 *av7110)
841*4882a593Smuzhiyun {
842*4882a593Smuzhiyun int ret = wait_event_timeout(av7110->bmpq,
843*4882a593Smuzhiyun av7110->bmp_state != BMP_LOADING, 10*HZ);
844*4882a593Smuzhiyun if (ret == 0) {
845*4882a593Smuzhiyun printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n",
846*4882a593Smuzhiyun ret, av7110->bmp_state);
847*4882a593Smuzhiyun av7110->bmp_state = BMP_NONE;
848*4882a593Smuzhiyun return -ETIMEDOUT;
849*4882a593Smuzhiyun }
850*4882a593Smuzhiyun return 0;
851*4882a593Smuzhiyun }
852*4882a593Smuzhiyun
LoadBitmap(struct av7110 * av7110,u16 dx,u16 dy,int inc,u8 __user * data)853*4882a593Smuzhiyun static inline int LoadBitmap(struct av7110 *av7110,
854*4882a593Smuzhiyun u16 dx, u16 dy, int inc, u8 __user * data)
855*4882a593Smuzhiyun {
856*4882a593Smuzhiyun u16 format;
857*4882a593Smuzhiyun int bpp;
858*4882a593Smuzhiyun int i;
859*4882a593Smuzhiyun int d, delta;
860*4882a593Smuzhiyun u8 c;
861*4882a593Smuzhiyun int ret;
862*4882a593Smuzhiyun
863*4882a593Smuzhiyun dprintk(4, "%p\n", av7110);
864*4882a593Smuzhiyun
865*4882a593Smuzhiyun format = bpp2bit[av7110->osdbpp[av7110->osdwin]];
866*4882a593Smuzhiyun
867*4882a593Smuzhiyun av7110->bmp_state = BMP_LOADING;
868*4882a593Smuzhiyun if (format == OSD_BITMAP8) {
869*4882a593Smuzhiyun bpp=8; delta = 1;
870*4882a593Smuzhiyun } else if (format == OSD_BITMAP4) {
871*4882a593Smuzhiyun bpp=4; delta = 2;
872*4882a593Smuzhiyun } else if (format == OSD_BITMAP2) {
873*4882a593Smuzhiyun bpp=2; delta = 4;
874*4882a593Smuzhiyun } else if (format == OSD_BITMAP1) {
875*4882a593Smuzhiyun bpp=1; delta = 8;
876*4882a593Smuzhiyun } else {
877*4882a593Smuzhiyun av7110->bmp_state = BMP_NONE;
878*4882a593Smuzhiyun return -EINVAL;
879*4882a593Smuzhiyun }
880*4882a593Smuzhiyun av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8;
881*4882a593Smuzhiyun av7110->bmpp = 0;
882*4882a593Smuzhiyun if (av7110->bmplen > 32768) {
883*4882a593Smuzhiyun av7110->bmp_state = BMP_NONE;
884*4882a593Smuzhiyun return -EINVAL;
885*4882a593Smuzhiyun }
886*4882a593Smuzhiyun for (i = 0; i < dy; i++) {
887*4882a593Smuzhiyun if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) {
888*4882a593Smuzhiyun av7110->bmp_state = BMP_NONE;
889*4882a593Smuzhiyun return -EINVAL;
890*4882a593Smuzhiyun }
891*4882a593Smuzhiyun }
892*4882a593Smuzhiyun if (format != OSD_BITMAP8) {
893*4882a593Smuzhiyun for (i = 0; i < dx * dy / delta; i++) {
894*4882a593Smuzhiyun c = ((u8 *)av7110->bmpbuf)[1024 + i * delta + delta - 1];
895*4882a593Smuzhiyun for (d = delta - 2; d >= 0; d--) {
896*4882a593Smuzhiyun c |= (((u8 *)av7110->bmpbuf)[1024 + i * delta + d]
897*4882a593Smuzhiyun << ((delta - d - 1) * bpp));
898*4882a593Smuzhiyun ((u8 *)av7110->bmpbuf)[1024 + i] = c;
899*4882a593Smuzhiyun }
900*4882a593Smuzhiyun }
901*4882a593Smuzhiyun }
902*4882a593Smuzhiyun av7110->bmplen += 1024;
903*4882a593Smuzhiyun dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen);
904*4882a593Smuzhiyun ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
905*4882a593Smuzhiyun if (!ret)
906*4882a593Smuzhiyun ret = WaitUntilBmpLoaded(av7110);
907*4882a593Smuzhiyun return ret;
908*4882a593Smuzhiyun }
909*4882a593Smuzhiyun
BlitBitmap(struct av7110 * av7110,u16 x,u16 y)910*4882a593Smuzhiyun static int BlitBitmap(struct av7110 *av7110, u16 x, u16 y)
911*4882a593Smuzhiyun {
912*4882a593Smuzhiyun dprintk(4, "%p\n", av7110);
913*4882a593Smuzhiyun
914*4882a593Smuzhiyun return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, av7110->osdwin, x, y, 0);
915*4882a593Smuzhiyun }
916*4882a593Smuzhiyun
ReleaseBitmap(struct av7110 * av7110)917*4882a593Smuzhiyun static inline int ReleaseBitmap(struct av7110 *av7110)
918*4882a593Smuzhiyun {
919*4882a593Smuzhiyun dprintk(4, "%p\n", av7110);
920*4882a593Smuzhiyun
921*4882a593Smuzhiyun if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e)
922*4882a593Smuzhiyun return -1;
923*4882a593Smuzhiyun if (av7110->bmp_state == BMP_LOADING)
924*4882a593Smuzhiyun dprintk(1,"ReleaseBitmap called while BMP_LOADING\n");
925*4882a593Smuzhiyun av7110->bmp_state = BMP_NONE;
926*4882a593Smuzhiyun return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0);
927*4882a593Smuzhiyun }
928*4882a593Smuzhiyun
RGB2YUV(u16 R,u16 G,u16 B)929*4882a593Smuzhiyun static u32 RGB2YUV(u16 R, u16 G, u16 B)
930*4882a593Smuzhiyun {
931*4882a593Smuzhiyun u16 y, u, v;
932*4882a593Smuzhiyun u16 Y, Cr, Cb;
933*4882a593Smuzhiyun
934*4882a593Smuzhiyun y = R * 77 + G * 150 + B * 29; /* Luma=0.299R+0.587G+0.114B 0..65535 */
935*4882a593Smuzhiyun u = 2048 + B * 8 -(y >> 5); /* Cr 0..4095 */
936*4882a593Smuzhiyun v = 2048 + R * 8 -(y >> 5); /* Cb 0..4095 */
937*4882a593Smuzhiyun
938*4882a593Smuzhiyun Y = y / 256;
939*4882a593Smuzhiyun Cb = u / 16;
940*4882a593Smuzhiyun Cr = v / 16;
941*4882a593Smuzhiyun
942*4882a593Smuzhiyun return Cr | (Cb << 16) | (Y << 8);
943*4882a593Smuzhiyun }
944*4882a593Smuzhiyun
OSDSetColor(struct av7110 * av7110,u8 color,u8 r,u8 g,u8 b,u8 blend)945*4882a593Smuzhiyun static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
946*4882a593Smuzhiyun {
947*4882a593Smuzhiyun int ret;
948*4882a593Smuzhiyun
949*4882a593Smuzhiyun u16 ch, cl;
950*4882a593Smuzhiyun u32 yuv;
951*4882a593Smuzhiyun
952*4882a593Smuzhiyun yuv = blend ? RGB2YUV(r,g,b) : 0;
953*4882a593Smuzhiyun cl = (yuv & 0xffff);
954*4882a593Smuzhiyun ch = ((yuv >> 16) & 0xffff);
955*4882a593Smuzhiyun ret = SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
956*4882a593Smuzhiyun color, ch, cl);
957*4882a593Smuzhiyun if (!ret)
958*4882a593Smuzhiyun ret = SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
959*4882a593Smuzhiyun color, ((blend >> 4) & 0x0f));
960*4882a593Smuzhiyun return ret;
961*4882a593Smuzhiyun }
962*4882a593Smuzhiyun
OSDSetPalette(struct av7110 * av7110,u32 __user * colors,u8 first,u8 last)963*4882a593Smuzhiyun static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last)
964*4882a593Smuzhiyun {
965*4882a593Smuzhiyun int i;
966*4882a593Smuzhiyun int length = last - first + 1;
967*4882a593Smuzhiyun
968*4882a593Smuzhiyun if (length * 4 > DATA_BUFF3_SIZE)
969*4882a593Smuzhiyun return -EINVAL;
970*4882a593Smuzhiyun
971*4882a593Smuzhiyun for (i = 0; i < length; i++) {
972*4882a593Smuzhiyun u32 color, blend, yuv;
973*4882a593Smuzhiyun
974*4882a593Smuzhiyun if (get_user(color, colors + i))
975*4882a593Smuzhiyun return -EFAULT;
976*4882a593Smuzhiyun blend = (color & 0xF0000000) >> 4;
977*4882a593Smuzhiyun yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF,
978*4882a593Smuzhiyun (color >> 16) & 0xFF) | blend : 0;
979*4882a593Smuzhiyun yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16);
980*4882a593Smuzhiyun wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4);
981*4882a593Smuzhiyun }
982*4882a593Smuzhiyun return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4,
983*4882a593Smuzhiyun av7110->osdwin,
984*4882a593Smuzhiyun bpp2pal[av7110->osdbpp[av7110->osdwin]],
985*4882a593Smuzhiyun first, last);
986*4882a593Smuzhiyun }
987*4882a593Smuzhiyun
OSDSetBlock(struct av7110 * av7110,int x0,int y0,int x1,int y1,int inc,u8 __user * data)988*4882a593Smuzhiyun static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
989*4882a593Smuzhiyun int x1, int y1, int inc, u8 __user * data)
990*4882a593Smuzhiyun {
991*4882a593Smuzhiyun uint w, h, bpp, bpl, size, lpb, bnum, brest;
992*4882a593Smuzhiyun int i;
993*4882a593Smuzhiyun int rc,release_rc;
994*4882a593Smuzhiyun
995*4882a593Smuzhiyun w = x1 - x0 + 1;
996*4882a593Smuzhiyun h = y1 - y0 + 1;
997*4882a593Smuzhiyun if (inc <= 0)
998*4882a593Smuzhiyun inc = w;
999*4882a593Smuzhiyun if (w <= 0 || w > 720 || h <= 0 || h > 576)
1000*4882a593Smuzhiyun return -EINVAL;
1001*4882a593Smuzhiyun bpp = av7110->osdbpp[av7110->osdwin] + 1;
1002*4882a593Smuzhiyun bpl = ((w * bpp + 7) & ~7) / 8;
1003*4882a593Smuzhiyun size = h * bpl;
1004*4882a593Smuzhiyun lpb = (32 * 1024) / bpl;
1005*4882a593Smuzhiyun bnum = size / (lpb * bpl);
1006*4882a593Smuzhiyun brest = size - bnum * lpb * bpl;
1007*4882a593Smuzhiyun
1008*4882a593Smuzhiyun if (av7110->bmp_state == BMP_LOADING) {
1009*4882a593Smuzhiyun /* possible if syscall is repeated by -ERESTARTSYS and if firmware cannot abort */
1010*4882a593Smuzhiyun BUG_ON (FW_VERSION(av7110->arm_app) >= 0x261e);
1011*4882a593Smuzhiyun rc = WaitUntilBmpLoaded(av7110);
1012*4882a593Smuzhiyun if (rc)
1013*4882a593Smuzhiyun return rc;
1014*4882a593Smuzhiyun /* just continue. This should work for all fw versions
1015*4882a593Smuzhiyun * if bnum==1 && !brest && LoadBitmap was successful
1016*4882a593Smuzhiyun */
1017*4882a593Smuzhiyun }
1018*4882a593Smuzhiyun
1019*4882a593Smuzhiyun rc = 0;
1020*4882a593Smuzhiyun for (i = 0; i < bnum; i++) {
1021*4882a593Smuzhiyun rc = LoadBitmap(av7110, w, lpb, inc, data);
1022*4882a593Smuzhiyun if (rc)
1023*4882a593Smuzhiyun break;
1024*4882a593Smuzhiyun rc = BlitBitmap(av7110, x0, y0 + i * lpb);
1025*4882a593Smuzhiyun if (rc)
1026*4882a593Smuzhiyun break;
1027*4882a593Smuzhiyun data += lpb * inc;
1028*4882a593Smuzhiyun }
1029*4882a593Smuzhiyun if (!rc && brest) {
1030*4882a593Smuzhiyun rc = LoadBitmap(av7110, w, brest / bpl, inc, data);
1031*4882a593Smuzhiyun if (!rc)
1032*4882a593Smuzhiyun rc = BlitBitmap(av7110, x0, y0 + bnum * lpb);
1033*4882a593Smuzhiyun }
1034*4882a593Smuzhiyun release_rc = ReleaseBitmap(av7110);
1035*4882a593Smuzhiyun if (!rc)
1036*4882a593Smuzhiyun rc = release_rc;
1037*4882a593Smuzhiyun if (rc)
1038*4882a593Smuzhiyun dprintk(1,"returns %d\n",rc);
1039*4882a593Smuzhiyun return rc;
1040*4882a593Smuzhiyun }
1041*4882a593Smuzhiyun
av7110_osd_cmd(struct av7110 * av7110,osd_cmd_t * dc)1042*4882a593Smuzhiyun int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
1043*4882a593Smuzhiyun {
1044*4882a593Smuzhiyun int ret;
1045*4882a593Smuzhiyun
1046*4882a593Smuzhiyun if (mutex_lock_interruptible(&av7110->osd_mutex))
1047*4882a593Smuzhiyun return -ERESTARTSYS;
1048*4882a593Smuzhiyun
1049*4882a593Smuzhiyun switch (dc->cmd) {
1050*4882a593Smuzhiyun case OSD_Close:
1051*4882a593Smuzhiyun ret = DestroyOSDWindow(av7110, av7110->osdwin);
1052*4882a593Smuzhiyun break;
1053*4882a593Smuzhiyun case OSD_Open:
1054*4882a593Smuzhiyun av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7;
1055*4882a593Smuzhiyun ret = CreateOSDWindow(av7110, av7110->osdwin,
1056*4882a593Smuzhiyun bpp2bit[av7110->osdbpp[av7110->osdwin]],
1057*4882a593Smuzhiyun dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
1058*4882a593Smuzhiyun if (ret)
1059*4882a593Smuzhiyun break;
1060*4882a593Smuzhiyun if (!dc->data) {
1061*4882a593Smuzhiyun ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1062*4882a593Smuzhiyun if (ret)
1063*4882a593Smuzhiyun break;
1064*4882a593Smuzhiyun ret = SetColorBlend(av7110, av7110->osdwin);
1065*4882a593Smuzhiyun }
1066*4882a593Smuzhiyun break;
1067*4882a593Smuzhiyun case OSD_Show:
1068*4882a593Smuzhiyun ret = MoveWindowRel(av7110, av7110->osdwin, 0, 0);
1069*4882a593Smuzhiyun break;
1070*4882a593Smuzhiyun case OSD_Hide:
1071*4882a593Smuzhiyun ret = HideWindow(av7110, av7110->osdwin);
1072*4882a593Smuzhiyun break;
1073*4882a593Smuzhiyun case OSD_Clear:
1074*4882a593Smuzhiyun ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
1075*4882a593Smuzhiyun break;
1076*4882a593Smuzhiyun case OSD_Fill:
1077*4882a593Smuzhiyun ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
1078*4882a593Smuzhiyun break;
1079*4882a593Smuzhiyun case OSD_SetColor:
1080*4882a593Smuzhiyun ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
1081*4882a593Smuzhiyun break;
1082*4882a593Smuzhiyun case OSD_SetPalette:
1083*4882a593Smuzhiyun if (FW_VERSION(av7110->arm_app) >= 0x2618)
1084*4882a593Smuzhiyun ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0);
1085*4882a593Smuzhiyun else {
1086*4882a593Smuzhiyun int i, len = dc->x0-dc->color+1;
1087*4882a593Smuzhiyun u8 __user *colors = (u8 __user *)dc->data;
1088*4882a593Smuzhiyun u8 r, g = 0, b = 0, blend = 0;
1089*4882a593Smuzhiyun ret = 0;
1090*4882a593Smuzhiyun for (i = 0; i<len; i++) {
1091*4882a593Smuzhiyun if (get_user(r, colors + i * 4) ||
1092*4882a593Smuzhiyun get_user(g, colors + i * 4 + 1) ||
1093*4882a593Smuzhiyun get_user(b, colors + i * 4 + 2) ||
1094*4882a593Smuzhiyun get_user(blend, colors + i * 4 + 3)) {
1095*4882a593Smuzhiyun ret = -EFAULT;
1096*4882a593Smuzhiyun break;
1097*4882a593Smuzhiyun }
1098*4882a593Smuzhiyun ret = OSDSetColor(av7110, dc->color + i, r, g, b, blend);
1099*4882a593Smuzhiyun if (ret)
1100*4882a593Smuzhiyun break;
1101*4882a593Smuzhiyun }
1102*4882a593Smuzhiyun }
1103*4882a593Smuzhiyun break;
1104*4882a593Smuzhiyun case OSD_SetPixel:
1105*4882a593Smuzhiyun ret = DrawLine(av7110, av7110->osdwin,
1106*4882a593Smuzhiyun dc->x0, dc->y0, 0, 0, dc->color);
1107*4882a593Smuzhiyun break;
1108*4882a593Smuzhiyun case OSD_SetRow:
1109*4882a593Smuzhiyun dc->y1 = dc->y0;
1110*4882a593Smuzhiyun fallthrough;
1111*4882a593Smuzhiyun case OSD_SetBlock:
1112*4882a593Smuzhiyun ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data);
1113*4882a593Smuzhiyun break;
1114*4882a593Smuzhiyun case OSD_FillRow:
1115*4882a593Smuzhiyun ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
1116*4882a593Smuzhiyun dc->x1-dc->x0+1, dc->y1, dc->color);
1117*4882a593Smuzhiyun break;
1118*4882a593Smuzhiyun case OSD_FillBlock:
1119*4882a593Smuzhiyun ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
1120*4882a593Smuzhiyun dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color);
1121*4882a593Smuzhiyun break;
1122*4882a593Smuzhiyun case OSD_Line:
1123*4882a593Smuzhiyun ret = DrawLine(av7110, av7110->osdwin,
1124*4882a593Smuzhiyun dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color);
1125*4882a593Smuzhiyun break;
1126*4882a593Smuzhiyun case OSD_Text:
1127*4882a593Smuzhiyun {
1128*4882a593Smuzhiyun char textbuf[240];
1129*4882a593Smuzhiyun
1130*4882a593Smuzhiyun if (strncpy_from_user(textbuf, dc->data, 240) < 0) {
1131*4882a593Smuzhiyun ret = -EFAULT;
1132*4882a593Smuzhiyun break;
1133*4882a593Smuzhiyun }
1134*4882a593Smuzhiyun textbuf[239] = 0;
1135*4882a593Smuzhiyun if (dc->x1 > 3)
1136*4882a593Smuzhiyun dc->x1 = 3;
1137*4882a593Smuzhiyun ret = SetFont(av7110, av7110->osdwin, dc->x1,
1138*4882a593Smuzhiyun (u16) (dc->color & 0xffff), (u16) (dc->color >> 16));
1139*4882a593Smuzhiyun if (!ret)
1140*4882a593Smuzhiyun ret = FlushText(av7110);
1141*4882a593Smuzhiyun if (!ret)
1142*4882a593Smuzhiyun ret = WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
1143*4882a593Smuzhiyun break;
1144*4882a593Smuzhiyun }
1145*4882a593Smuzhiyun case OSD_SetWindow:
1146*4882a593Smuzhiyun if (dc->x0 < 1 || dc->x0 > 7)
1147*4882a593Smuzhiyun ret = -EINVAL;
1148*4882a593Smuzhiyun else {
1149*4882a593Smuzhiyun av7110->osdwin = dc->x0;
1150*4882a593Smuzhiyun ret = 0;
1151*4882a593Smuzhiyun }
1152*4882a593Smuzhiyun break;
1153*4882a593Smuzhiyun case OSD_MoveWindow:
1154*4882a593Smuzhiyun ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1155*4882a593Smuzhiyun if (!ret)
1156*4882a593Smuzhiyun ret = SetColorBlend(av7110, av7110->osdwin);
1157*4882a593Smuzhiyun break;
1158*4882a593Smuzhiyun case OSD_OpenRaw:
1159*4882a593Smuzhiyun if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) {
1160*4882a593Smuzhiyun ret = -EINVAL;
1161*4882a593Smuzhiyun break;
1162*4882a593Smuzhiyun }
1163*4882a593Smuzhiyun if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR)
1164*4882a593Smuzhiyun av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1;
1165*4882a593Smuzhiyun else
1166*4882a593Smuzhiyun av7110->osdbpp[av7110->osdwin] = 0;
1167*4882a593Smuzhiyun ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color,
1168*4882a593Smuzhiyun dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
1169*4882a593Smuzhiyun if (ret)
1170*4882a593Smuzhiyun break;
1171*4882a593Smuzhiyun if (!dc->data) {
1172*4882a593Smuzhiyun ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1173*4882a593Smuzhiyun if (!ret)
1174*4882a593Smuzhiyun ret = SetColorBlend(av7110, av7110->osdwin);
1175*4882a593Smuzhiyun }
1176*4882a593Smuzhiyun break;
1177*4882a593Smuzhiyun default:
1178*4882a593Smuzhiyun ret = -EINVAL;
1179*4882a593Smuzhiyun break;
1180*4882a593Smuzhiyun }
1181*4882a593Smuzhiyun
1182*4882a593Smuzhiyun mutex_unlock(&av7110->osd_mutex);
1183*4882a593Smuzhiyun if (ret==-ERESTARTSYS)
1184*4882a593Smuzhiyun dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd);
1185*4882a593Smuzhiyun else if (ret)
1186*4882a593Smuzhiyun dprintk(1, "av7110_osd_cmd(%d) returns with %d\n",dc->cmd,ret);
1187*4882a593Smuzhiyun
1188*4882a593Smuzhiyun return ret;
1189*4882a593Smuzhiyun }
1190*4882a593Smuzhiyun
av7110_osd_capability(struct av7110 * av7110,osd_cap_t * cap)1191*4882a593Smuzhiyun int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap)
1192*4882a593Smuzhiyun {
1193*4882a593Smuzhiyun switch (cap->cmd) {
1194*4882a593Smuzhiyun case OSD_CAP_MEMSIZE:
1195*4882a593Smuzhiyun if (FW_4M_SDRAM(av7110->arm_app))
1196*4882a593Smuzhiyun cap->val = 1000000;
1197*4882a593Smuzhiyun else
1198*4882a593Smuzhiyun cap->val = 92000;
1199*4882a593Smuzhiyun return 0;
1200*4882a593Smuzhiyun default:
1201*4882a593Smuzhiyun return -EINVAL;
1202*4882a593Smuzhiyun }
1203*4882a593Smuzhiyun }
1204*4882a593Smuzhiyun #endif /* CONFIG_DVB_AV7110_OSD */
1205