18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * av7110_hw.c: av7110 low level hardware access and firmware interface 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1999-2002 Ralph Metzler 68c2ecf20Sopenharmony_ci * & Marcus Metzler for convergence integrated media GmbH 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * originally based on code by: 98c2ecf20Sopenharmony_ci * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * the project's page is at https://linuxtv.org 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/* for debugging ARM communication: */ 158c2ecf20Sopenharmony_ci//#define COM_DEBUG 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/types.h> 188c2ecf20Sopenharmony_ci#include <linux/kernel.h> 198c2ecf20Sopenharmony_ci#include <linux/string.h> 208c2ecf20Sopenharmony_ci#include <linux/delay.h> 218c2ecf20Sopenharmony_ci#include <linux/fs.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "av7110.h" 248c2ecf20Sopenharmony_ci#include "av7110_hw.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define _NOHANDSHAKE 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* 298c2ecf20Sopenharmony_ci * Max transfer size done by av7110_fw_cmd() 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * The maximum size passed to this function is 6 bytes. The buffer also 328c2ecf20Sopenharmony_ci * uses two additional ones for type and size. So, 8 bytes is enough. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci#define MAX_XFER_SIZE 8 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/**************************************************************************** 378c2ecf20Sopenharmony_ci * DEBI functions 388c2ecf20Sopenharmony_ci ****************************************************************************/ 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* This DEBI code is based on the Stradis driver 418c2ecf20Sopenharmony_ci by Nathan Laredo <laredo@gnu.org> */ 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ciint av7110_debiwrite(struct av7110 *av7110, u32 config, 448c2ecf20Sopenharmony_ci int addr, u32 val, unsigned int count) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci struct saa7146_dev *dev = av7110->dev; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci if (count > 32764) { 498c2ecf20Sopenharmony_ci printk("%s: invalid count %d\n", __func__, count); 508c2ecf20Sopenharmony_ci return -1; 518c2ecf20Sopenharmony_ci } 528c2ecf20Sopenharmony_ci if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) { 538c2ecf20Sopenharmony_ci printk("%s: wait_for_debi_done failed\n", __func__); 548c2ecf20Sopenharmony_ci return -1; 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci saa7146_write(dev, DEBI_CONFIG, config); 578c2ecf20Sopenharmony_ci if (count <= 4) /* immediate transfer */ 588c2ecf20Sopenharmony_ci saa7146_write(dev, DEBI_AD, val); 598c2ecf20Sopenharmony_ci else /* block transfer */ 608c2ecf20Sopenharmony_ci saa7146_write(dev, DEBI_AD, av7110->debi_bus); 618c2ecf20Sopenharmony_ci saa7146_write(dev, DEBI_COMMAND, (count << 17) | (addr & 0xffff)); 628c2ecf20Sopenharmony_ci saa7146_write(dev, MC2, (2 << 16) | 2); 638c2ecf20Sopenharmony_ci return 0; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ciu32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, unsigned int count) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci struct saa7146_dev *dev = av7110->dev; 698c2ecf20Sopenharmony_ci u32 result = 0; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci if (count > 32764) { 728c2ecf20Sopenharmony_ci printk("%s: invalid count %d\n", __func__, count); 738c2ecf20Sopenharmony_ci return 0; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) { 768c2ecf20Sopenharmony_ci printk("%s: wait_for_debi_done #1 failed\n", __func__); 778c2ecf20Sopenharmony_ci return 0; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci saa7146_write(dev, DEBI_AD, av7110->debi_bus); 808c2ecf20Sopenharmony_ci saa7146_write(dev, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff)); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci saa7146_write(dev, DEBI_CONFIG, config); 838c2ecf20Sopenharmony_ci saa7146_write(dev, MC2, (2 << 16) | 2); 848c2ecf20Sopenharmony_ci if (count > 4) 858c2ecf20Sopenharmony_ci return count; 868c2ecf20Sopenharmony_ci if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) { 878c2ecf20Sopenharmony_ci printk("%s: wait_for_debi_done #2 failed\n", __func__); 888c2ecf20Sopenharmony_ci return 0; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci result = saa7146_read(dev, DEBI_AD); 928c2ecf20Sopenharmony_ci result &= (0xffffffffUL >> ((4 - count) * 8)); 938c2ecf20Sopenharmony_ci return result; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/* av7110 ARM core boot stuff */ 998c2ecf20Sopenharmony_ci#if 0 1008c2ecf20Sopenharmony_civoid av7110_reset_arm(struct av7110 *av7110) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTLO); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci /* Disable DEBI and GPIO irq */ 1058c2ecf20Sopenharmony_ci SAA7146_IER_DISABLE(av7110->dev, MASK_19 | MASK_03); 1068c2ecf20Sopenharmony_ci SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTHI); 1098c2ecf20Sopenharmony_ci msleep(30); /* the firmware needs some time to initialize */ 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci ARM_ResetMailBox(av7110); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03); 1148c2ecf20Sopenharmony_ci SAA7146_IER_ENABLE(av7110->dev, MASK_03); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci av7110->arm_ready = 1; 1178c2ecf20Sopenharmony_ci dprintk(1, "reset ARM\n"); 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci#endif /* 0 */ 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic int waitdebi(struct av7110 *av7110, int adr, int state) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci int k; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci dprintk(4, "%p\n", av7110); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci for (k = 0; k < 100; k++) { 1288c2ecf20Sopenharmony_ci if (irdebi(av7110, DEBINOSWAP, adr, 0, 2) == state) 1298c2ecf20Sopenharmony_ci return 0; 1308c2ecf20Sopenharmony_ci udelay(5); 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci return -ETIMEDOUT; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int load_dram(struct av7110 *av7110, u32 *data, int len) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci int i; 1388c2ecf20Sopenharmony_ci int blocks, rest; 1398c2ecf20Sopenharmony_ci u32 base, bootblock = AV7110_BOOT_BLOCK; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci dprintk(4, "%p\n", av7110); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci blocks = len / AV7110_BOOT_MAX_SIZE; 1448c2ecf20Sopenharmony_ci rest = len % AV7110_BOOT_MAX_SIZE; 1458c2ecf20Sopenharmony_ci base = DRAM_START_CODE; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci for (i = 0; i < blocks; i++) { 1488c2ecf20Sopenharmony_ci if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { 1498c2ecf20Sopenharmony_ci printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i); 1508c2ecf20Sopenharmony_ci return -ETIMEDOUT; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci dprintk(4, "writing DRAM block %d\n", i); 1538c2ecf20Sopenharmony_ci mwdebi(av7110, DEBISWAB, bootblock, 1548c2ecf20Sopenharmony_ci ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE); 1558c2ecf20Sopenharmony_ci bootblock ^= 0x1400; 1568c2ecf20Sopenharmony_ci iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4); 1578c2ecf20Sopenharmony_ci iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2); 1588c2ecf20Sopenharmony_ci iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); 1598c2ecf20Sopenharmony_ci base += AV7110_BOOT_MAX_SIZE; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (rest > 0) { 1638c2ecf20Sopenharmony_ci if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { 1648c2ecf20Sopenharmony_ci printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n"); 1658c2ecf20Sopenharmony_ci return -ETIMEDOUT; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci if (rest > 4) 1688c2ecf20Sopenharmony_ci mwdebi(av7110, DEBISWAB, bootblock, 1698c2ecf20Sopenharmony_ci ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, rest); 1708c2ecf20Sopenharmony_ci else 1718c2ecf20Sopenharmony_ci mwdebi(av7110, DEBISWAB, bootblock, 1728c2ecf20Sopenharmony_ci ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4); 1758c2ecf20Sopenharmony_ci iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2); 1768c2ecf20Sopenharmony_ci iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { 1798c2ecf20Sopenharmony_ci printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n"); 1808c2ecf20Sopenharmony_ci return -ETIMEDOUT; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, 0, 2); 1838c2ecf20Sopenharmony_ci iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); 1848c2ecf20Sopenharmony_ci if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_AV7110_BOOT_COMPLETE) < 0) { 1858c2ecf20Sopenharmony_ci printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n"); 1868c2ecf20Sopenharmony_ci return -ETIMEDOUT; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci return 0; 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/* we cannot write av7110 DRAM directly, so load a bootloader into 1938c2ecf20Sopenharmony_ci * the DPRAM which implements a simple boot protocol */ 1948c2ecf20Sopenharmony_ciint av7110_bootarm(struct av7110 *av7110) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci const struct firmware *fw; 1978c2ecf20Sopenharmony_ci const char *fw_name = "av7110/bootcode.bin"; 1988c2ecf20Sopenharmony_ci struct saa7146_dev *dev = av7110->dev; 1998c2ecf20Sopenharmony_ci u32 ret; 2008c2ecf20Sopenharmony_ci int i; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci dprintk(4, "%p\n", av7110); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci av7110->arm_ready = 0; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* Disable DEBI and GPIO irq */ 2098c2ecf20Sopenharmony_ci SAA7146_IER_DISABLE(av7110->dev, MASK_03 | MASK_19); 2108c2ecf20Sopenharmony_ci SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci /* enable DEBI */ 2138c2ecf20Sopenharmony_ci saa7146_write(av7110->dev, MC1, 0x08800880); 2148c2ecf20Sopenharmony_ci saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000); 2158c2ecf20Sopenharmony_ci saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci /* test DEBI */ 2188c2ecf20Sopenharmony_ci iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4); 2198c2ecf20Sopenharmony_ci /* FIXME: Why does Nexus CA require 2x iwdebi for first init? */ 2208c2ecf20Sopenharmony_ci iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if ((ret=irdebi(av7110, DEBINOSWAP, DPRAM_BASE, 0, 4)) != 0x10325476) { 2238c2ecf20Sopenharmony_ci printk(KERN_ERR "dvb-ttpci: debi test in av7110_bootarm() failed: %08x != %08x (check your BIOS 'Plug&Play OS' settings)\n", 2248c2ecf20Sopenharmony_ci ret, 0x10325476); 2258c2ecf20Sopenharmony_ci return -1; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci for (i = 0; i < 8192; i += 4) 2288c2ecf20Sopenharmony_ci iwdebi(av7110, DEBISWAP, DPRAM_BASE + i, 0x00, 4); 2298c2ecf20Sopenharmony_ci dprintk(2, "debi test OK\n"); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci /* boot */ 2328c2ecf20Sopenharmony_ci dprintk(1, "load boot code\n"); 2338c2ecf20Sopenharmony_ci saa7146_setgpio(dev, ARM_IRQ_LINE, SAA7146_GPIO_IRQLO); 2348c2ecf20Sopenharmony_ci //saa7146_setgpio(dev, DEBI_DONE_LINE, SAA7146_GPIO_INPUT); 2358c2ecf20Sopenharmony_ci //saa7146_setgpio(dev, 3, SAA7146_GPIO_INPUT); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci ret = request_firmware(&fw, fw_name, &dev->pci->dev); 2388c2ecf20Sopenharmony_ci if (ret) { 2398c2ecf20Sopenharmony_ci printk(KERN_ERR "dvb-ttpci: Failed to load firmware \"%s\"\n", 2408c2ecf20Sopenharmony_ci fw_name); 2418c2ecf20Sopenharmony_ci return ret; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci mwdebi(av7110, DEBISWAB, DPRAM_BASE, fw->data, fw->size); 2458c2ecf20Sopenharmony_ci release_firmware(fw); 2468c2ecf20Sopenharmony_ci iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (saa7146_wait_for_debi_done(av7110->dev, 1)) { 2498c2ecf20Sopenharmony_ci printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): saa7146_wait_for_debi_done() timed out\n"); 2508c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI); 2538c2ecf20Sopenharmony_ci mdelay(1); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci dprintk(1, "load dram code\n"); 2568c2ecf20Sopenharmony_ci if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0) { 2578c2ecf20Sopenharmony_ci printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): load_dram() failed\n"); 2588c2ecf20Sopenharmony_ci return -1; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO); 2628c2ecf20Sopenharmony_ci mdelay(1); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci dprintk(1, "load dpram code\n"); 2658c2ecf20Sopenharmony_ci mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (saa7146_wait_for_debi_done(av7110->dev, 1)) { 2688c2ecf20Sopenharmony_ci printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): saa7146_wait_for_debi_done() timed out after loading DRAM\n"); 2698c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI); 2728c2ecf20Sopenharmony_ci msleep(30); /* the firmware needs some time to initialize */ 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci //ARM_ClearIrq(av7110); 2758c2ecf20Sopenharmony_ci ARM_ResetMailBox(av7110); 2768c2ecf20Sopenharmony_ci SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03); 2778c2ecf20Sopenharmony_ci SAA7146_IER_ENABLE(av7110->dev, MASK_03); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci av7110->arm_errors = 0; 2808c2ecf20Sopenharmony_ci av7110->arm_ready = 1; 2818c2ecf20Sopenharmony_ci return 0; 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ciMODULE_FIRMWARE("av7110/bootcode.bin"); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci/**************************************************************************** 2868c2ecf20Sopenharmony_ci * DEBI command polling 2878c2ecf20Sopenharmony_ci ****************************************************************************/ 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ciint av7110_wait_msgstate(struct av7110 *av7110, u16 flags) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci unsigned long start; 2928c2ecf20Sopenharmony_ci u32 stat; 2938c2ecf20Sopenharmony_ci int err; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (FW_VERSION(av7110->arm_app) <= 0x261c) { 2968c2ecf20Sopenharmony_ci /* not supported by old firmware */ 2978c2ecf20Sopenharmony_ci msleep(50); 2988c2ecf20Sopenharmony_ci return 0; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci /* new firmware */ 3028c2ecf20Sopenharmony_ci start = jiffies; 3038c2ecf20Sopenharmony_ci for (;;) { 3048c2ecf20Sopenharmony_ci err = time_after(jiffies, start + ARM_WAIT_FREE); 3058c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&av7110->dcomlock)) 3068c2ecf20Sopenharmony_ci return -ERESTARTSYS; 3078c2ecf20Sopenharmony_ci stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); 3088c2ecf20Sopenharmony_ci mutex_unlock(&av7110->dcomlock); 3098c2ecf20Sopenharmony_ci if ((stat & flags) == 0) 3108c2ecf20Sopenharmony_ci break; 3118c2ecf20Sopenharmony_ci if (err) { 3128c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n", 3138c2ecf20Sopenharmony_ci __func__, stat & flags); 3148c2ecf20Sopenharmony_ci return -ETIMEDOUT; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci msleep(1); 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci return 0; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci int i; 3248c2ecf20Sopenharmony_ci unsigned long start; 3258c2ecf20Sopenharmony_ci char *type = NULL; 3268c2ecf20Sopenharmony_ci u16 flags[2] = {0, 0}; 3278c2ecf20Sopenharmony_ci u32 stat; 3288c2ecf20Sopenharmony_ci int err; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci// dprintk(4, "%p\n", av7110); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (!av7110->arm_ready) { 3338c2ecf20Sopenharmony_ci dprintk(1, "arm not ready.\n"); 3348c2ecf20Sopenharmony_ci return -ENXIO; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci start = jiffies; 3388c2ecf20Sopenharmony_ci while (1) { 3398c2ecf20Sopenharmony_ci err = time_after(jiffies, start + ARM_WAIT_FREE); 3408c2ecf20Sopenharmony_ci if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0) 3418c2ecf20Sopenharmony_ci break; 3428c2ecf20Sopenharmony_ci if (err) { 3438c2ecf20Sopenharmony_ci printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __func__); 3448c2ecf20Sopenharmony_ci av7110->arm_errors++; 3458c2ecf20Sopenharmony_ci return -ETIMEDOUT; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci msleep(1); 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (FW_VERSION(av7110->arm_app) <= 0x261f) 3518c2ecf20Sopenharmony_ci wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci#ifndef _NOHANDSHAKE 3548c2ecf20Sopenharmony_ci start = jiffies; 3558c2ecf20Sopenharmony_ci while (1) { 3568c2ecf20Sopenharmony_ci err = time_after(jiffies, start + ARM_WAIT_SHAKE); 3578c2ecf20Sopenharmony_ci if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0) 3588c2ecf20Sopenharmony_ci break; 3598c2ecf20Sopenharmony_ci if (err) { 3608c2ecf20Sopenharmony_ci printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __func__); 3618c2ecf20Sopenharmony_ci return -ETIMEDOUT; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci msleep(1); 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci#endif 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci switch ((buf[0] >> 8) & 0xff) { 3688c2ecf20Sopenharmony_ci case COMTYPE_PIDFILTER: 3698c2ecf20Sopenharmony_ci case COMTYPE_ENCODER: 3708c2ecf20Sopenharmony_ci case COMTYPE_REC_PLAY: 3718c2ecf20Sopenharmony_ci case COMTYPE_MPEGDECODER: 3728c2ecf20Sopenharmony_ci type = "MSG"; 3738c2ecf20Sopenharmony_ci flags[0] = GPMQOver; 3748c2ecf20Sopenharmony_ci flags[1] = GPMQFull; 3758c2ecf20Sopenharmony_ci break; 3768c2ecf20Sopenharmony_ci case COMTYPE_OSD: 3778c2ecf20Sopenharmony_ci type = "OSD"; 3788c2ecf20Sopenharmony_ci flags[0] = OSDQOver; 3798c2ecf20Sopenharmony_ci flags[1] = OSDQFull; 3808c2ecf20Sopenharmony_ci break; 3818c2ecf20Sopenharmony_ci case COMTYPE_MISC: 3828c2ecf20Sopenharmony_ci if (FW_VERSION(av7110->arm_app) >= 0x261d) { 3838c2ecf20Sopenharmony_ci type = "MSG"; 3848c2ecf20Sopenharmony_ci flags[0] = GPMQOver; 3858c2ecf20Sopenharmony_ci flags[1] = GPMQBusy; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci break; 3888c2ecf20Sopenharmony_ci default: 3898c2ecf20Sopenharmony_ci break; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci if (type != NULL) { 3938c2ecf20Sopenharmony_ci /* non-immediate COMMAND type */ 3948c2ecf20Sopenharmony_ci start = jiffies; 3958c2ecf20Sopenharmony_ci for (;;) { 3968c2ecf20Sopenharmony_ci err = time_after(jiffies, start + ARM_WAIT_FREE); 3978c2ecf20Sopenharmony_ci stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); 3988c2ecf20Sopenharmony_ci if (stat & flags[0]) { 3998c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: %s QUEUE overflow\n", 4008c2ecf20Sopenharmony_ci __func__, type); 4018c2ecf20Sopenharmony_ci return -1; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci if ((stat & flags[1]) == 0) 4048c2ecf20Sopenharmony_ci break; 4058c2ecf20Sopenharmony_ci if (err) { 4068c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n", 4078c2ecf20Sopenharmony_ci __func__, type); 4088c2ecf20Sopenharmony_ci av7110->arm_errors++; 4098c2ecf20Sopenharmony_ci return -ETIMEDOUT; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci msleep(1); 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci for (i = 2; i < length; i++) 4168c2ecf20Sopenharmony_ci wdebi(av7110, DEBINOSWAP, COMMAND + 2 * i, (u32) buf[i], 2); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (length) 4198c2ecf20Sopenharmony_ci wdebi(av7110, DEBINOSWAP, COMMAND + 2, (u32) buf[1], 2); 4208c2ecf20Sopenharmony_ci else 4218c2ecf20Sopenharmony_ci wdebi(av7110, DEBINOSWAP, COMMAND + 2, 0, 2); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci wdebi(av7110, DEBINOSWAP, COMMAND, (u32) buf[0], 2); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (FW_VERSION(av7110->arm_app) <= 0x261f) 4268c2ecf20Sopenharmony_ci wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci#ifdef COM_DEBUG 4298c2ecf20Sopenharmony_ci start = jiffies; 4308c2ecf20Sopenharmony_ci while (1) { 4318c2ecf20Sopenharmony_ci err = time_after(jiffies, start + ARM_WAIT_FREE); 4328c2ecf20Sopenharmony_ci if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0) 4338c2ecf20Sopenharmony_ci break; 4348c2ecf20Sopenharmony_ci if (err) { 4358c2ecf20Sopenharmony_ci printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n", 4368c2ecf20Sopenharmony_ci __func__, (buf[0] >> 8) & 0xff); 4378c2ecf20Sopenharmony_ci return -ETIMEDOUT; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci msleep(1); 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); 4438c2ecf20Sopenharmony_ci if (stat & GPMQOver) { 4448c2ecf20Sopenharmony_ci printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __func__); 4458c2ecf20Sopenharmony_ci return -ENOSPC; 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci else if (stat & OSDQOver) { 4488c2ecf20Sopenharmony_ci printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __func__); 4498c2ecf20Sopenharmony_ci return -ENOSPC; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci#endif 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci return 0; 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cistatic int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci int ret; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci// dprintk(4, "%p\n", av7110); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci if (!av7110->arm_ready) { 4638c2ecf20Sopenharmony_ci dprintk(1, "arm not ready.\n"); 4648c2ecf20Sopenharmony_ci return -1; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&av7110->dcomlock)) 4678c2ecf20Sopenharmony_ci return -ERESTARTSYS; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci ret = __av7110_send_fw_cmd(av7110, buf, length); 4708c2ecf20Sopenharmony_ci mutex_unlock(&av7110->dcomlock); 4718c2ecf20Sopenharmony_ci if (ret && ret!=-ERESTARTSYS) 4728c2ecf20Sopenharmony_ci printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n", 4738c2ecf20Sopenharmony_ci __func__, ret); 4748c2ecf20Sopenharmony_ci return ret; 4758c2ecf20Sopenharmony_ci} 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ciint av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci va_list args; 4808c2ecf20Sopenharmony_ci u16 buf[MAX_XFER_SIZE]; 4818c2ecf20Sopenharmony_ci int i, ret; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci// dprintk(4, "%p\n", av7110); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci if (2 + num > ARRAY_SIZE(buf)) { 4868c2ecf20Sopenharmony_ci printk(KERN_WARNING 4878c2ecf20Sopenharmony_ci "%s: %s len=%d is too big!\n", 4888c2ecf20Sopenharmony_ci KBUILD_MODNAME, __func__, num); 4898c2ecf20Sopenharmony_ci return -EINVAL; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci buf[0] = ((type << 8) | com); 4938c2ecf20Sopenharmony_ci buf[1] = num; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci if (num) { 4968c2ecf20Sopenharmony_ci va_start(args, num); 4978c2ecf20Sopenharmony_ci for (i = 0; i < num; i++) 4988c2ecf20Sopenharmony_ci buf[i + 2] = va_arg(args, u32); 4998c2ecf20Sopenharmony_ci va_end(args); 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci ret = av7110_send_fw_cmd(av7110, buf, num + 2); 5038c2ecf20Sopenharmony_ci if (ret && ret != -ERESTARTSYS) 5048c2ecf20Sopenharmony_ci printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret); 5058c2ecf20Sopenharmony_ci return ret; 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci#if 0 5098c2ecf20Sopenharmony_ciint av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len) 5108c2ecf20Sopenharmony_ci{ 5118c2ecf20Sopenharmony_ci int i, ret; 5128c2ecf20Sopenharmony_ci u16 cmd[18] = { ((COMTYPE_COMMON_IF << 8) + subcom), 5138c2ecf20Sopenharmony_ci 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci dprintk(4, "%p\n", av7110); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci for(i = 0; i < len && i < 32; i++) 5188c2ecf20Sopenharmony_ci { 5198c2ecf20Sopenharmony_ci if(i % 2 == 0) 5208c2ecf20Sopenharmony_ci cmd[(i / 2) + 2] = (u16)(buf[i]) << 8; 5218c2ecf20Sopenharmony_ci else 5228c2ecf20Sopenharmony_ci cmd[(i / 2) + 2] |= buf[i]; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci ret = av7110_send_fw_cmd(av7110, cmd, 18); 5268c2ecf20Sopenharmony_ci if (ret && ret != -ERESTARTSYS) 5278c2ecf20Sopenharmony_ci printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret); 5288c2ecf20Sopenharmony_ci return ret; 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci#endif /* 0 */ 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ciint av7110_fw_request(struct av7110 *av7110, u16 *request_buf, 5338c2ecf20Sopenharmony_ci int request_buf_len, u16 *reply_buf, int reply_buf_len) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci int err; 5368c2ecf20Sopenharmony_ci s16 i; 5378c2ecf20Sopenharmony_ci unsigned long start; 5388c2ecf20Sopenharmony_ci#ifdef COM_DEBUG 5398c2ecf20Sopenharmony_ci u32 stat; 5408c2ecf20Sopenharmony_ci#endif 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci dprintk(4, "%p\n", av7110); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci if (!av7110->arm_ready) { 5458c2ecf20Sopenharmony_ci dprintk(1, "arm not ready.\n"); 5468c2ecf20Sopenharmony_ci return -1; 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&av7110->dcomlock)) 5508c2ecf20Sopenharmony_ci return -ERESTARTSYS; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) { 5538c2ecf20Sopenharmony_ci mutex_unlock(&av7110->dcomlock); 5548c2ecf20Sopenharmony_ci printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err); 5558c2ecf20Sopenharmony_ci return err; 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci start = jiffies; 5598c2ecf20Sopenharmony_ci while (1) { 5608c2ecf20Sopenharmony_ci err = time_after(jiffies, start + ARM_WAIT_FREE); 5618c2ecf20Sopenharmony_ci if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0) 5628c2ecf20Sopenharmony_ci break; 5638c2ecf20Sopenharmony_ci if (err) { 5648c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __func__); 5658c2ecf20Sopenharmony_ci mutex_unlock(&av7110->dcomlock); 5668c2ecf20Sopenharmony_ci return -ETIMEDOUT; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci#ifdef _NOHANDSHAKE 5698c2ecf20Sopenharmony_ci msleep(1); 5708c2ecf20Sopenharmony_ci#endif 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci#ifndef _NOHANDSHAKE 5748c2ecf20Sopenharmony_ci start = jiffies; 5758c2ecf20Sopenharmony_ci while (1) { 5768c2ecf20Sopenharmony_ci err = time_after(jiffies, start + ARM_WAIT_SHAKE); 5778c2ecf20Sopenharmony_ci if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0) 5788c2ecf20Sopenharmony_ci break; 5798c2ecf20Sopenharmony_ci if (err) { 5808c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __func__); 5818c2ecf20Sopenharmony_ci mutex_unlock(&av7110->dcomlock); 5828c2ecf20Sopenharmony_ci return -ETIMEDOUT; 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci msleep(1); 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci#endif 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci#ifdef COM_DEBUG 5898c2ecf20Sopenharmony_ci stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); 5908c2ecf20Sopenharmony_ci if (stat & GPMQOver) { 5918c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: GPMQOver\n", __func__); 5928c2ecf20Sopenharmony_ci mutex_unlock(&av7110->dcomlock); 5938c2ecf20Sopenharmony_ci return -1; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci else if (stat & OSDQOver) { 5968c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: OSDQOver\n", __func__); 5978c2ecf20Sopenharmony_ci mutex_unlock(&av7110->dcomlock); 5988c2ecf20Sopenharmony_ci return -1; 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci#endif 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci for (i = 0; i < reply_buf_len; i++) 6038c2ecf20Sopenharmony_ci reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci mutex_unlock(&av7110->dcomlock); 6068c2ecf20Sopenharmony_ci return 0; 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_cistatic int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length) 6108c2ecf20Sopenharmony_ci{ 6118c2ecf20Sopenharmony_ci int ret; 6128c2ecf20Sopenharmony_ci ret = av7110_fw_request(av7110, &tag, 0, buf, length); 6138c2ecf20Sopenharmony_ci if (ret) 6148c2ecf20Sopenharmony_ci printk(KERN_ERR "dvb-ttpci: av7110_fw_query error %d\n", ret); 6158c2ecf20Sopenharmony_ci return ret; 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci/**************************************************************************** 6208c2ecf20Sopenharmony_ci * Firmware commands 6218c2ecf20Sopenharmony_ci ****************************************************************************/ 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci/* get version of the firmware ROM, RTSL, video ucode and ARM application */ 6248c2ecf20Sopenharmony_ciint av7110_firmversion(struct av7110 *av7110) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci u16 buf[20]; 6278c2ecf20Sopenharmony_ci u16 tag = ((COMTYPE_REQUEST << 8) + ReqVersion); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci dprintk(4, "%p\n", av7110); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci if (av7110_fw_query(av7110, tag, buf, 16)) { 6328c2ecf20Sopenharmony_ci printk("dvb-ttpci: failed to boot firmware @ card %d\n", 6338c2ecf20Sopenharmony_ci av7110->dvb_adapter.num); 6348c2ecf20Sopenharmony_ci return -EIO; 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci av7110->arm_fw = (buf[0] << 16) + buf[1]; 6388c2ecf20Sopenharmony_ci av7110->arm_rtsl = (buf[2] << 16) + buf[3]; 6398c2ecf20Sopenharmony_ci av7110->arm_vid = (buf[4] << 16) + buf[5]; 6408c2ecf20Sopenharmony_ci av7110->arm_app = (buf[6] << 16) + buf[7]; 6418c2ecf20Sopenharmony_ci av7110->avtype = (buf[8] << 16) + buf[9]; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci printk("dvb-ttpci: info @ card %d: firm %08x, rtsl %08x, vid %08x, app %08x\n", 6448c2ecf20Sopenharmony_ci av7110->dvb_adapter.num, av7110->arm_fw, 6458c2ecf20Sopenharmony_ci av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /* print firmware capabilities */ 6488c2ecf20Sopenharmony_ci if (FW_CI_LL_SUPPORT(av7110->arm_app)) 6498c2ecf20Sopenharmony_ci printk("dvb-ttpci: firmware @ card %d supports CI link layer interface\n", 6508c2ecf20Sopenharmony_ci av7110->dvb_adapter.num); 6518c2ecf20Sopenharmony_ci else 6528c2ecf20Sopenharmony_ci printk("dvb-ttpci: no firmware support for CI link layer interface @ card %d\n", 6538c2ecf20Sopenharmony_ci av7110->dvb_adapter.num); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci return 0; 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ciint av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst) 6608c2ecf20Sopenharmony_ci{ 6618c2ecf20Sopenharmony_ci int i, ret; 6628c2ecf20Sopenharmony_ci u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) + SendDiSEqC), 6638c2ecf20Sopenharmony_ci 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci dprintk(4, "%p\n", av7110); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci if (len > 10) 6688c2ecf20Sopenharmony_ci len = 10; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci buf[1] = len + 2; 6718c2ecf20Sopenharmony_ci buf[2] = len; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci if (burst != -1) 6748c2ecf20Sopenharmony_ci buf[3] = burst ? 0x01 : 0x00; 6758c2ecf20Sopenharmony_ci else 6768c2ecf20Sopenharmony_ci buf[3] = 0xffff; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) 6798c2ecf20Sopenharmony_ci buf[i + 4] = msg[i]; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci ret = av7110_send_fw_cmd(av7110, buf, 18); 6828c2ecf20Sopenharmony_ci if (ret && ret!=-ERESTARTSYS) 6838c2ecf20Sopenharmony_ci printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret); 6848c2ecf20Sopenharmony_ci return ret; 6858c2ecf20Sopenharmony_ci} 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci#ifdef CONFIG_DVB_AV7110_OSD 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_cistatic inline int SetColorBlend(struct av7110 *av7110, u8 windownr) 6918c2ecf20Sopenharmony_ci{ 6928c2ecf20Sopenharmony_ci return av7110_fw_cmd(av7110, COMTYPE_OSD, SetCBlend, 1, windownr); 6938c2ecf20Sopenharmony_ci} 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_cistatic inline int SetBlend_(struct av7110 *av7110, u8 windownr, 6968c2ecf20Sopenharmony_ci enum av7110_osd_palette_type colordepth, u16 index, u8 blending) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci return av7110_fw_cmd(av7110, COMTYPE_OSD, SetBlend, 4, 6998c2ecf20Sopenharmony_ci windownr, colordepth, index, blending); 7008c2ecf20Sopenharmony_ci} 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_cistatic inline int SetColor_(struct av7110 *av7110, u8 windownr, 7038c2ecf20Sopenharmony_ci enum av7110_osd_palette_type colordepth, u16 index, u16 colorhi, u16 colorlo) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci return av7110_fw_cmd(av7110, COMTYPE_OSD, SetColor, 5, 7068c2ecf20Sopenharmony_ci windownr, colordepth, index, colorhi, colorlo); 7078c2ecf20Sopenharmony_ci} 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_cistatic inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize, 7108c2ecf20Sopenharmony_ci u16 colorfg, u16 colorbg) 7118c2ecf20Sopenharmony_ci{ 7128c2ecf20Sopenharmony_ci return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Font, 4, 7138c2ecf20Sopenharmony_ci windownr, fontsize, colorfg, colorbg); 7148c2ecf20Sopenharmony_ci} 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_cistatic int FlushText(struct av7110 *av7110) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci unsigned long start; 7198c2ecf20Sopenharmony_ci int err; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&av7110->dcomlock)) 7228c2ecf20Sopenharmony_ci return -ERESTARTSYS; 7238c2ecf20Sopenharmony_ci start = jiffies; 7248c2ecf20Sopenharmony_ci while (1) { 7258c2ecf20Sopenharmony_ci err = time_after(jiffies, start + ARM_WAIT_OSD); 7268c2ecf20Sopenharmony_ci if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0) 7278c2ecf20Sopenharmony_ci break; 7288c2ecf20Sopenharmony_ci if (err) { 7298c2ecf20Sopenharmony_ci printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n", 7308c2ecf20Sopenharmony_ci __func__); 7318c2ecf20Sopenharmony_ci mutex_unlock(&av7110->dcomlock); 7328c2ecf20Sopenharmony_ci return -ETIMEDOUT; 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci msleep(1); 7358c2ecf20Sopenharmony_ci } 7368c2ecf20Sopenharmony_ci mutex_unlock(&av7110->dcomlock); 7378c2ecf20Sopenharmony_ci return 0; 7388c2ecf20Sopenharmony_ci} 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_cistatic int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, char *buf) 7418c2ecf20Sopenharmony_ci{ 7428c2ecf20Sopenharmony_ci int i, ret; 7438c2ecf20Sopenharmony_ci unsigned long start; 7448c2ecf20Sopenharmony_ci int length = strlen(buf) + 1; 7458c2ecf20Sopenharmony_ci u16 cbuf[5] = { (COMTYPE_OSD << 8) + DText, 3, win, x, y }; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&av7110->dcomlock)) 7488c2ecf20Sopenharmony_ci return -ERESTARTSYS; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci start = jiffies; 7518c2ecf20Sopenharmony_ci while (1) { 7528c2ecf20Sopenharmony_ci ret = time_after(jiffies, start + ARM_WAIT_OSD); 7538c2ecf20Sopenharmony_ci if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0) 7548c2ecf20Sopenharmony_ci break; 7558c2ecf20Sopenharmony_ci if (ret) { 7568c2ecf20Sopenharmony_ci printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n", 7578c2ecf20Sopenharmony_ci __func__); 7588c2ecf20Sopenharmony_ci mutex_unlock(&av7110->dcomlock); 7598c2ecf20Sopenharmony_ci return -ETIMEDOUT; 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci msleep(1); 7628c2ecf20Sopenharmony_ci } 7638c2ecf20Sopenharmony_ci#ifndef _NOHANDSHAKE 7648c2ecf20Sopenharmony_ci start = jiffies; 7658c2ecf20Sopenharmony_ci while (1) { 7668c2ecf20Sopenharmony_ci ret = time_after(jiffies, start + ARM_WAIT_SHAKE); 7678c2ecf20Sopenharmony_ci if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0) 7688c2ecf20Sopenharmony_ci break; 7698c2ecf20Sopenharmony_ci if (ret) { 7708c2ecf20Sopenharmony_ci printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n", 7718c2ecf20Sopenharmony_ci __func__); 7728c2ecf20Sopenharmony_ci mutex_unlock(&av7110->dcomlock); 7738c2ecf20Sopenharmony_ci return -ETIMEDOUT; 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci msleep(1); 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci#endif 7788c2ecf20Sopenharmony_ci for (i = 0; i < length / 2; i++) 7798c2ecf20Sopenharmony_ci wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 7808c2ecf20Sopenharmony_ci swab16(*(u16 *)(buf + 2 * i)), 2); 7818c2ecf20Sopenharmony_ci if (length & 1) 7828c2ecf20Sopenharmony_ci wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2); 7838c2ecf20Sopenharmony_ci ret = __av7110_send_fw_cmd(av7110, cbuf, 5); 7848c2ecf20Sopenharmony_ci mutex_unlock(&av7110->dcomlock); 7858c2ecf20Sopenharmony_ci if (ret && ret!=-ERESTARTSYS) 7868c2ecf20Sopenharmony_ci printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret); 7878c2ecf20Sopenharmony_ci return ret; 7888c2ecf20Sopenharmony_ci} 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_cistatic inline int DrawLine(struct av7110 *av7110, u8 windownr, 7918c2ecf20Sopenharmony_ci u16 x, u16 y, u16 dx, u16 dy, u16 color) 7928c2ecf20Sopenharmony_ci{ 7938c2ecf20Sopenharmony_ci return av7110_fw_cmd(av7110, COMTYPE_OSD, DLine, 6, 7948c2ecf20Sopenharmony_ci windownr, x, y, dx, dy, color); 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_cistatic inline int DrawBlock(struct av7110 *av7110, u8 windownr, 7988c2ecf20Sopenharmony_ci u16 x, u16 y, u16 dx, u16 dy, u16 color) 7998c2ecf20Sopenharmony_ci{ 8008c2ecf20Sopenharmony_ci return av7110_fw_cmd(av7110, COMTYPE_OSD, DBox, 6, 8018c2ecf20Sopenharmony_ci windownr, x, y, dx, dy, color); 8028c2ecf20Sopenharmony_ci} 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_cistatic inline int HideWindow(struct av7110 *av7110, u8 windownr) 8058c2ecf20Sopenharmony_ci{ 8068c2ecf20Sopenharmony_ci return av7110_fw_cmd(av7110, COMTYPE_OSD, WHide, 1, windownr); 8078c2ecf20Sopenharmony_ci} 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_cistatic inline int MoveWindowRel(struct av7110 *av7110, u8 windownr, u16 x, u16 y) 8108c2ecf20Sopenharmony_ci{ 8118c2ecf20Sopenharmony_ci return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveD, 3, windownr, x, y); 8128c2ecf20Sopenharmony_ci} 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_cistatic inline int MoveWindowAbs(struct av7110 *av7110, u8 windownr, u16 x, u16 y) 8158c2ecf20Sopenharmony_ci{ 8168c2ecf20Sopenharmony_ci return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveA, 3, windownr, x, y); 8178c2ecf20Sopenharmony_ci} 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_cistatic inline int DestroyOSDWindow(struct av7110 *av7110, u8 windownr) 8208c2ecf20Sopenharmony_ci{ 8218c2ecf20Sopenharmony_ci return av7110_fw_cmd(av7110, COMTYPE_OSD, WDestroy, 1, windownr); 8228c2ecf20Sopenharmony_ci} 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_cistatic inline int CreateOSDWindow(struct av7110 *av7110, u8 windownr, 8258c2ecf20Sopenharmony_ci osd_raw_window_t disptype, 8268c2ecf20Sopenharmony_ci u16 width, u16 height) 8278c2ecf20Sopenharmony_ci{ 8288c2ecf20Sopenharmony_ci return av7110_fw_cmd(av7110, COMTYPE_OSD, WCreate, 4, 8298c2ecf20Sopenharmony_ci windownr, disptype, width, height); 8308c2ecf20Sopenharmony_ci} 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_cistatic enum av7110_osd_palette_type bpp2pal[8] = { 8348c2ecf20Sopenharmony_ci Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit 8358c2ecf20Sopenharmony_ci}; 8368c2ecf20Sopenharmony_cistatic osd_raw_window_t bpp2bit[8] = { 8378c2ecf20Sopenharmony_ci OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8 8388c2ecf20Sopenharmony_ci}; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_cistatic inline int WaitUntilBmpLoaded(struct av7110 *av7110) 8418c2ecf20Sopenharmony_ci{ 8428c2ecf20Sopenharmony_ci int ret = wait_event_timeout(av7110->bmpq, 8438c2ecf20Sopenharmony_ci av7110->bmp_state != BMP_LOADING, 10*HZ); 8448c2ecf20Sopenharmony_ci if (ret == 0) { 8458c2ecf20Sopenharmony_ci printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n", 8468c2ecf20Sopenharmony_ci ret, av7110->bmp_state); 8478c2ecf20Sopenharmony_ci av7110->bmp_state = BMP_NONE; 8488c2ecf20Sopenharmony_ci return -ETIMEDOUT; 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci return 0; 8518c2ecf20Sopenharmony_ci} 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_cistatic inline int LoadBitmap(struct av7110 *av7110, 8548c2ecf20Sopenharmony_ci u16 dx, u16 dy, int inc, u8 __user * data) 8558c2ecf20Sopenharmony_ci{ 8568c2ecf20Sopenharmony_ci u16 format; 8578c2ecf20Sopenharmony_ci int bpp; 8588c2ecf20Sopenharmony_ci int i; 8598c2ecf20Sopenharmony_ci int d, delta; 8608c2ecf20Sopenharmony_ci u8 c; 8618c2ecf20Sopenharmony_ci int ret; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci dprintk(4, "%p\n", av7110); 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci format = bpp2bit[av7110->osdbpp[av7110->osdwin]]; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci av7110->bmp_state = BMP_LOADING; 8688c2ecf20Sopenharmony_ci if (format == OSD_BITMAP8) { 8698c2ecf20Sopenharmony_ci bpp=8; delta = 1; 8708c2ecf20Sopenharmony_ci } else if (format == OSD_BITMAP4) { 8718c2ecf20Sopenharmony_ci bpp=4; delta = 2; 8728c2ecf20Sopenharmony_ci } else if (format == OSD_BITMAP2) { 8738c2ecf20Sopenharmony_ci bpp=2; delta = 4; 8748c2ecf20Sopenharmony_ci } else if (format == OSD_BITMAP1) { 8758c2ecf20Sopenharmony_ci bpp=1; delta = 8; 8768c2ecf20Sopenharmony_ci } else { 8778c2ecf20Sopenharmony_ci av7110->bmp_state = BMP_NONE; 8788c2ecf20Sopenharmony_ci return -EINVAL; 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8; 8818c2ecf20Sopenharmony_ci av7110->bmpp = 0; 8828c2ecf20Sopenharmony_ci if (av7110->bmplen > 32768) { 8838c2ecf20Sopenharmony_ci av7110->bmp_state = BMP_NONE; 8848c2ecf20Sopenharmony_ci return -EINVAL; 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci for (i = 0; i < dy; i++) { 8878c2ecf20Sopenharmony_ci if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) { 8888c2ecf20Sopenharmony_ci av7110->bmp_state = BMP_NONE; 8898c2ecf20Sopenharmony_ci return -EINVAL; 8908c2ecf20Sopenharmony_ci } 8918c2ecf20Sopenharmony_ci } 8928c2ecf20Sopenharmony_ci if (format != OSD_BITMAP8) { 8938c2ecf20Sopenharmony_ci for (i = 0; i < dx * dy / delta; i++) { 8948c2ecf20Sopenharmony_ci c = ((u8 *)av7110->bmpbuf)[1024 + i * delta + delta - 1]; 8958c2ecf20Sopenharmony_ci for (d = delta - 2; d >= 0; d--) { 8968c2ecf20Sopenharmony_ci c |= (((u8 *)av7110->bmpbuf)[1024 + i * delta + d] 8978c2ecf20Sopenharmony_ci << ((delta - d - 1) * bpp)); 8988c2ecf20Sopenharmony_ci ((u8 *)av7110->bmpbuf)[1024 + i] = c; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci av7110->bmplen += 1024; 9038c2ecf20Sopenharmony_ci dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen); 9048c2ecf20Sopenharmony_ci ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy); 9058c2ecf20Sopenharmony_ci if (!ret) 9068c2ecf20Sopenharmony_ci ret = WaitUntilBmpLoaded(av7110); 9078c2ecf20Sopenharmony_ci return ret; 9088c2ecf20Sopenharmony_ci} 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_cistatic int BlitBitmap(struct av7110 *av7110, u16 x, u16 y) 9118c2ecf20Sopenharmony_ci{ 9128c2ecf20Sopenharmony_ci dprintk(4, "%p\n", av7110); 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, av7110->osdwin, x, y, 0); 9158c2ecf20Sopenharmony_ci} 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_cistatic inline int ReleaseBitmap(struct av7110 *av7110) 9188c2ecf20Sopenharmony_ci{ 9198c2ecf20Sopenharmony_ci dprintk(4, "%p\n", av7110); 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e) 9228c2ecf20Sopenharmony_ci return -1; 9238c2ecf20Sopenharmony_ci if (av7110->bmp_state == BMP_LOADING) 9248c2ecf20Sopenharmony_ci dprintk(1,"ReleaseBitmap called while BMP_LOADING\n"); 9258c2ecf20Sopenharmony_ci av7110->bmp_state = BMP_NONE; 9268c2ecf20Sopenharmony_ci return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0); 9278c2ecf20Sopenharmony_ci} 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_cistatic u32 RGB2YUV(u16 R, u16 G, u16 B) 9308c2ecf20Sopenharmony_ci{ 9318c2ecf20Sopenharmony_ci u16 y, u, v; 9328c2ecf20Sopenharmony_ci u16 Y, Cr, Cb; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci y = R * 77 + G * 150 + B * 29; /* Luma=0.299R+0.587G+0.114B 0..65535 */ 9358c2ecf20Sopenharmony_ci u = 2048 + B * 8 -(y >> 5); /* Cr 0..4095 */ 9368c2ecf20Sopenharmony_ci v = 2048 + R * 8 -(y >> 5); /* Cb 0..4095 */ 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci Y = y / 256; 9398c2ecf20Sopenharmony_ci Cb = u / 16; 9408c2ecf20Sopenharmony_ci Cr = v / 16; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci return Cr | (Cb << 16) | (Y << 8); 9438c2ecf20Sopenharmony_ci} 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_cistatic int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend) 9468c2ecf20Sopenharmony_ci{ 9478c2ecf20Sopenharmony_ci int ret; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci u16 ch, cl; 9508c2ecf20Sopenharmony_ci u32 yuv; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci yuv = blend ? RGB2YUV(r,g,b) : 0; 9538c2ecf20Sopenharmony_ci cl = (yuv & 0xffff); 9548c2ecf20Sopenharmony_ci ch = ((yuv >> 16) & 0xffff); 9558c2ecf20Sopenharmony_ci ret = SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], 9568c2ecf20Sopenharmony_ci color, ch, cl); 9578c2ecf20Sopenharmony_ci if (!ret) 9588c2ecf20Sopenharmony_ci ret = SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], 9598c2ecf20Sopenharmony_ci color, ((blend >> 4) & 0x0f)); 9608c2ecf20Sopenharmony_ci return ret; 9618c2ecf20Sopenharmony_ci} 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_cistatic int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last) 9648c2ecf20Sopenharmony_ci{ 9658c2ecf20Sopenharmony_ci int i; 9668c2ecf20Sopenharmony_ci int length = last - first + 1; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci if (length * 4 > DATA_BUFF3_SIZE) 9698c2ecf20Sopenharmony_ci return -EINVAL; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci for (i = 0; i < length; i++) { 9728c2ecf20Sopenharmony_ci u32 color, blend, yuv; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci if (get_user(color, colors + i)) 9758c2ecf20Sopenharmony_ci return -EFAULT; 9768c2ecf20Sopenharmony_ci blend = (color & 0xF0000000) >> 4; 9778c2ecf20Sopenharmony_ci yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF, 9788c2ecf20Sopenharmony_ci (color >> 16) & 0xFF) | blend : 0; 9798c2ecf20Sopenharmony_ci yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16); 9808c2ecf20Sopenharmony_ci wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4); 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4, 9838c2ecf20Sopenharmony_ci av7110->osdwin, 9848c2ecf20Sopenharmony_ci bpp2pal[av7110->osdbpp[av7110->osdwin]], 9858c2ecf20Sopenharmony_ci first, last); 9868c2ecf20Sopenharmony_ci} 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_cistatic int OSDSetBlock(struct av7110 *av7110, int x0, int y0, 9898c2ecf20Sopenharmony_ci int x1, int y1, int inc, u8 __user * data) 9908c2ecf20Sopenharmony_ci{ 9918c2ecf20Sopenharmony_ci uint w, h, bpp, bpl, size, lpb, bnum, brest; 9928c2ecf20Sopenharmony_ci int i; 9938c2ecf20Sopenharmony_ci int rc,release_rc; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci w = x1 - x0 + 1; 9968c2ecf20Sopenharmony_ci h = y1 - y0 + 1; 9978c2ecf20Sopenharmony_ci if (inc <= 0) 9988c2ecf20Sopenharmony_ci inc = w; 9998c2ecf20Sopenharmony_ci if (w <= 0 || w > 720 || h <= 0 || h > 576) 10008c2ecf20Sopenharmony_ci return -EINVAL; 10018c2ecf20Sopenharmony_ci bpp = av7110->osdbpp[av7110->osdwin] + 1; 10028c2ecf20Sopenharmony_ci bpl = ((w * bpp + 7) & ~7) / 8; 10038c2ecf20Sopenharmony_ci size = h * bpl; 10048c2ecf20Sopenharmony_ci lpb = (32 * 1024) / bpl; 10058c2ecf20Sopenharmony_ci bnum = size / (lpb * bpl); 10068c2ecf20Sopenharmony_ci brest = size - bnum * lpb * bpl; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci if (av7110->bmp_state == BMP_LOADING) { 10098c2ecf20Sopenharmony_ci /* possible if syscall is repeated by -ERESTARTSYS and if firmware cannot abort */ 10108c2ecf20Sopenharmony_ci BUG_ON (FW_VERSION(av7110->arm_app) >= 0x261e); 10118c2ecf20Sopenharmony_ci rc = WaitUntilBmpLoaded(av7110); 10128c2ecf20Sopenharmony_ci if (rc) 10138c2ecf20Sopenharmony_ci return rc; 10148c2ecf20Sopenharmony_ci /* just continue. This should work for all fw versions 10158c2ecf20Sopenharmony_ci * if bnum==1 && !brest && LoadBitmap was successful 10168c2ecf20Sopenharmony_ci */ 10178c2ecf20Sopenharmony_ci } 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci rc = 0; 10208c2ecf20Sopenharmony_ci for (i = 0; i < bnum; i++) { 10218c2ecf20Sopenharmony_ci rc = LoadBitmap(av7110, w, lpb, inc, data); 10228c2ecf20Sopenharmony_ci if (rc) 10238c2ecf20Sopenharmony_ci break; 10248c2ecf20Sopenharmony_ci rc = BlitBitmap(av7110, x0, y0 + i * lpb); 10258c2ecf20Sopenharmony_ci if (rc) 10268c2ecf20Sopenharmony_ci break; 10278c2ecf20Sopenharmony_ci data += lpb * inc; 10288c2ecf20Sopenharmony_ci } 10298c2ecf20Sopenharmony_ci if (!rc && brest) { 10308c2ecf20Sopenharmony_ci rc = LoadBitmap(av7110, w, brest / bpl, inc, data); 10318c2ecf20Sopenharmony_ci if (!rc) 10328c2ecf20Sopenharmony_ci rc = BlitBitmap(av7110, x0, y0 + bnum * lpb); 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci release_rc = ReleaseBitmap(av7110); 10358c2ecf20Sopenharmony_ci if (!rc) 10368c2ecf20Sopenharmony_ci rc = release_rc; 10378c2ecf20Sopenharmony_ci if (rc) 10388c2ecf20Sopenharmony_ci dprintk(1,"returns %d\n",rc); 10398c2ecf20Sopenharmony_ci return rc; 10408c2ecf20Sopenharmony_ci} 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ciint av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc) 10438c2ecf20Sopenharmony_ci{ 10448c2ecf20Sopenharmony_ci int ret; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&av7110->osd_mutex)) 10478c2ecf20Sopenharmony_ci return -ERESTARTSYS; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci switch (dc->cmd) { 10508c2ecf20Sopenharmony_ci case OSD_Close: 10518c2ecf20Sopenharmony_ci ret = DestroyOSDWindow(av7110, av7110->osdwin); 10528c2ecf20Sopenharmony_ci break; 10538c2ecf20Sopenharmony_ci case OSD_Open: 10548c2ecf20Sopenharmony_ci av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7; 10558c2ecf20Sopenharmony_ci ret = CreateOSDWindow(av7110, av7110->osdwin, 10568c2ecf20Sopenharmony_ci bpp2bit[av7110->osdbpp[av7110->osdwin]], 10578c2ecf20Sopenharmony_ci dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1); 10588c2ecf20Sopenharmony_ci if (ret) 10598c2ecf20Sopenharmony_ci break; 10608c2ecf20Sopenharmony_ci if (!dc->data) { 10618c2ecf20Sopenharmony_ci ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); 10628c2ecf20Sopenharmony_ci if (ret) 10638c2ecf20Sopenharmony_ci break; 10648c2ecf20Sopenharmony_ci ret = SetColorBlend(av7110, av7110->osdwin); 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci break; 10678c2ecf20Sopenharmony_ci case OSD_Show: 10688c2ecf20Sopenharmony_ci ret = MoveWindowRel(av7110, av7110->osdwin, 0, 0); 10698c2ecf20Sopenharmony_ci break; 10708c2ecf20Sopenharmony_ci case OSD_Hide: 10718c2ecf20Sopenharmony_ci ret = HideWindow(av7110, av7110->osdwin); 10728c2ecf20Sopenharmony_ci break; 10738c2ecf20Sopenharmony_ci case OSD_Clear: 10748c2ecf20Sopenharmony_ci ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0); 10758c2ecf20Sopenharmony_ci break; 10768c2ecf20Sopenharmony_ci case OSD_Fill: 10778c2ecf20Sopenharmony_ci ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color); 10788c2ecf20Sopenharmony_ci break; 10798c2ecf20Sopenharmony_ci case OSD_SetColor: 10808c2ecf20Sopenharmony_ci ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1); 10818c2ecf20Sopenharmony_ci break; 10828c2ecf20Sopenharmony_ci case OSD_SetPalette: 10838c2ecf20Sopenharmony_ci if (FW_VERSION(av7110->arm_app) >= 0x2618) 10848c2ecf20Sopenharmony_ci ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0); 10858c2ecf20Sopenharmony_ci else { 10868c2ecf20Sopenharmony_ci int i, len = dc->x0-dc->color+1; 10878c2ecf20Sopenharmony_ci u8 __user *colors = (u8 __user *)dc->data; 10888c2ecf20Sopenharmony_ci u8 r, g = 0, b = 0, blend = 0; 10898c2ecf20Sopenharmony_ci ret = 0; 10908c2ecf20Sopenharmony_ci for (i = 0; i<len; i++) { 10918c2ecf20Sopenharmony_ci if (get_user(r, colors + i * 4) || 10928c2ecf20Sopenharmony_ci get_user(g, colors + i * 4 + 1) || 10938c2ecf20Sopenharmony_ci get_user(b, colors + i * 4 + 2) || 10948c2ecf20Sopenharmony_ci get_user(blend, colors + i * 4 + 3)) { 10958c2ecf20Sopenharmony_ci ret = -EFAULT; 10968c2ecf20Sopenharmony_ci break; 10978c2ecf20Sopenharmony_ci } 10988c2ecf20Sopenharmony_ci ret = OSDSetColor(av7110, dc->color + i, r, g, b, blend); 10998c2ecf20Sopenharmony_ci if (ret) 11008c2ecf20Sopenharmony_ci break; 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci break; 11048c2ecf20Sopenharmony_ci case OSD_SetPixel: 11058c2ecf20Sopenharmony_ci ret = DrawLine(av7110, av7110->osdwin, 11068c2ecf20Sopenharmony_ci dc->x0, dc->y0, 0, 0, dc->color); 11078c2ecf20Sopenharmony_ci break; 11088c2ecf20Sopenharmony_ci case OSD_SetRow: 11098c2ecf20Sopenharmony_ci dc->y1 = dc->y0; 11108c2ecf20Sopenharmony_ci fallthrough; 11118c2ecf20Sopenharmony_ci case OSD_SetBlock: 11128c2ecf20Sopenharmony_ci ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data); 11138c2ecf20Sopenharmony_ci break; 11148c2ecf20Sopenharmony_ci case OSD_FillRow: 11158c2ecf20Sopenharmony_ci ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0, 11168c2ecf20Sopenharmony_ci dc->x1-dc->x0+1, dc->y1, dc->color); 11178c2ecf20Sopenharmony_ci break; 11188c2ecf20Sopenharmony_ci case OSD_FillBlock: 11198c2ecf20Sopenharmony_ci ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0, 11208c2ecf20Sopenharmony_ci dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color); 11218c2ecf20Sopenharmony_ci break; 11228c2ecf20Sopenharmony_ci case OSD_Line: 11238c2ecf20Sopenharmony_ci ret = DrawLine(av7110, av7110->osdwin, 11248c2ecf20Sopenharmony_ci dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color); 11258c2ecf20Sopenharmony_ci break; 11268c2ecf20Sopenharmony_ci case OSD_Text: 11278c2ecf20Sopenharmony_ci { 11288c2ecf20Sopenharmony_ci char textbuf[240]; 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci if (strncpy_from_user(textbuf, dc->data, 240) < 0) { 11318c2ecf20Sopenharmony_ci ret = -EFAULT; 11328c2ecf20Sopenharmony_ci break; 11338c2ecf20Sopenharmony_ci } 11348c2ecf20Sopenharmony_ci textbuf[239] = 0; 11358c2ecf20Sopenharmony_ci if (dc->x1 > 3) 11368c2ecf20Sopenharmony_ci dc->x1 = 3; 11378c2ecf20Sopenharmony_ci ret = SetFont(av7110, av7110->osdwin, dc->x1, 11388c2ecf20Sopenharmony_ci (u16) (dc->color & 0xffff), (u16) (dc->color >> 16)); 11398c2ecf20Sopenharmony_ci if (!ret) 11408c2ecf20Sopenharmony_ci ret = FlushText(av7110); 11418c2ecf20Sopenharmony_ci if (!ret) 11428c2ecf20Sopenharmony_ci ret = WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf); 11438c2ecf20Sopenharmony_ci break; 11448c2ecf20Sopenharmony_ci } 11458c2ecf20Sopenharmony_ci case OSD_SetWindow: 11468c2ecf20Sopenharmony_ci if (dc->x0 < 1 || dc->x0 > 7) 11478c2ecf20Sopenharmony_ci ret = -EINVAL; 11488c2ecf20Sopenharmony_ci else { 11498c2ecf20Sopenharmony_ci av7110->osdwin = dc->x0; 11508c2ecf20Sopenharmony_ci ret = 0; 11518c2ecf20Sopenharmony_ci } 11528c2ecf20Sopenharmony_ci break; 11538c2ecf20Sopenharmony_ci case OSD_MoveWindow: 11548c2ecf20Sopenharmony_ci ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); 11558c2ecf20Sopenharmony_ci if (!ret) 11568c2ecf20Sopenharmony_ci ret = SetColorBlend(av7110, av7110->osdwin); 11578c2ecf20Sopenharmony_ci break; 11588c2ecf20Sopenharmony_ci case OSD_OpenRaw: 11598c2ecf20Sopenharmony_ci if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) { 11608c2ecf20Sopenharmony_ci ret = -EINVAL; 11618c2ecf20Sopenharmony_ci break; 11628c2ecf20Sopenharmony_ci } 11638c2ecf20Sopenharmony_ci if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR) 11648c2ecf20Sopenharmony_ci av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1; 11658c2ecf20Sopenharmony_ci else 11668c2ecf20Sopenharmony_ci av7110->osdbpp[av7110->osdwin] = 0; 11678c2ecf20Sopenharmony_ci ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color, 11688c2ecf20Sopenharmony_ci dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1); 11698c2ecf20Sopenharmony_ci if (ret) 11708c2ecf20Sopenharmony_ci break; 11718c2ecf20Sopenharmony_ci if (!dc->data) { 11728c2ecf20Sopenharmony_ci ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); 11738c2ecf20Sopenharmony_ci if (!ret) 11748c2ecf20Sopenharmony_ci ret = SetColorBlend(av7110, av7110->osdwin); 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci break; 11778c2ecf20Sopenharmony_ci default: 11788c2ecf20Sopenharmony_ci ret = -EINVAL; 11798c2ecf20Sopenharmony_ci break; 11808c2ecf20Sopenharmony_ci } 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci mutex_unlock(&av7110->osd_mutex); 11838c2ecf20Sopenharmony_ci if (ret==-ERESTARTSYS) 11848c2ecf20Sopenharmony_ci dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd); 11858c2ecf20Sopenharmony_ci else if (ret) 11868c2ecf20Sopenharmony_ci dprintk(1, "av7110_osd_cmd(%d) returns with %d\n",dc->cmd,ret); 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci return ret; 11898c2ecf20Sopenharmony_ci} 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ciint av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap) 11928c2ecf20Sopenharmony_ci{ 11938c2ecf20Sopenharmony_ci switch (cap->cmd) { 11948c2ecf20Sopenharmony_ci case OSD_CAP_MEMSIZE: 11958c2ecf20Sopenharmony_ci if (FW_4M_SDRAM(av7110->arm_app)) 11968c2ecf20Sopenharmony_ci cap->val = 1000000; 11978c2ecf20Sopenharmony_ci else 11988c2ecf20Sopenharmony_ci cap->val = 92000; 11998c2ecf20Sopenharmony_ci return 0; 12008c2ecf20Sopenharmony_ci default: 12018c2ecf20Sopenharmony_ci return -EINVAL; 12028c2ecf20Sopenharmony_ci } 12038c2ecf20Sopenharmony_ci} 12048c2ecf20Sopenharmony_ci#endif /* CONFIG_DVB_AV7110_OSD */ 1205