diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-14 15:13:30 (GMT) |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-15 19:36:22 (GMT) |
commit | b285192a43f0432d82c2c10974204e78af0da596 (patch) | |
tree | 618aa87e760c9c949eca9e4df6ae0eeffa11dcfc /drivers/media/pci/cx25821 | |
parent | 68de959f773a1d49096835c411390bceff5d1549 (diff) | |
download | linux-b285192a43f0432d82c2c10974204e78af0da596.tar.xz |
[media] rename most media/video pci drivers to media/pci
Rename all PCI drivers with their own directory under
drivers/media/video into drivers/media/pci and update the
building system.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/pci/cx25821')
24 files changed, 11778 insertions, 0 deletions
diff --git a/drivers/media/pci/cx25821/Kconfig b/drivers/media/pci/cx25821/Kconfig new file mode 100644 index 0000000..5f6b542 --- /dev/null +++ b/drivers/media/pci/cx25821/Kconfig @@ -0,0 +1,34 @@ +config VIDEO_CX25821 + tristate "Conexant cx25821 support" + depends on DVB_CORE && VIDEO_DEV && PCI && I2C + select I2C_ALGOBIT + select VIDEO_BTCX + select VIDEO_TVEEPROM + depends on RC_CORE + select VIDEOBUF_DVB + select VIDEOBUF_DMA_SG + select VIDEO_CX25840 + select VIDEO_CX2341X + ---help--- + This is a video4linux driver for Conexant 25821 based + TV cards. + + To compile this driver as a module, choose M here: the + module will be called cx25821 + +config VIDEO_CX25821_ALSA + tristate "Conexant 25821 DMA audio support" + depends on VIDEO_CX25821 && SND && EXPERIMENTAL + select SND_PCM + ---help--- + This is a video4linux driver for direct (DMA) audio on + Conexant 25821 based capture cards using ALSA. + + It only works with boards with function 01 enabled. + To check if your board supports, use lspci -n. + If supported, you should see 14f1:8801 or 14f1:8811 + PCI device. + + To compile this driver as a module, choose M here: the + module will be called cx25821-alsa. + diff --git a/drivers/media/pci/cx25821/Makefile b/drivers/media/pci/cx25821/Makefile new file mode 100644 index 0000000..1434e80 --- /dev/null +++ b/drivers/media/pci/cx25821/Makefile @@ -0,0 +1,13 @@ +cx25821-y := cx25821-core.o cx25821-cards.o cx25821-i2c.o \ + cx25821-gpio.o cx25821-medusa-video.o \ + cx25821-video.o cx25821-video-upstream.o \ + cx25821-video-upstream-ch2.o \ + cx25821-audio-upstream.o + +obj-$(CONFIG_VIDEO_CX25821) += cx25821.o +obj-$(CONFIG_VIDEO_CX25821_ALSA) += cx25821-alsa.o + +ccflags-y := -Idrivers/media/video +ccflags-y += -Idrivers/media/tuners +ccflags-y += -Idrivers/media/dvb-core +ccflags-y += -Idrivers/media/dvb-frontends diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c new file mode 100644 index 0000000..1858a45d --- /dev/null +++ b/drivers/media/pci/cx25821/cx25821-alsa.c @@ -0,0 +1,784 @@ +/* + * Driver for the Conexant CX25821 PCIe bridge + * + * Copyright (C) 2009 Conexant Systems Inc. + * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> + * Based on SAA713x ALSA driver and CX88 driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/vmalloc.h> +#include <linux/dma-mapping.h> +#include <linux/pci.h> +#include <linux/slab.h> + +#include <linux/delay.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/control.h> +#include <sound/initval.h> +#include <sound/tlv.h> + +#include "cx25821.h" +#include "cx25821-reg.h" + +#define AUDIO_SRAM_CHANNEL SRAM_CH08 + +#define dprintk(level, fmt, arg...) \ +do { \ + if (debug >= level) \ + pr_info("%s/1: " fmt, chip->dev->name, ##arg); \ +} while (0) +#define dprintk_core(level, fmt, arg...) \ +do { \ + if (debug >= level) \ + printk(KERN_DEBUG "%s/1: " fmt, chip->dev->name, ##arg); \ +} while (0) + +/**************************************************************************** + Data type declarations - Can be moded to a header file later + ****************************************************************************/ + +static struct snd_card *snd_cx25821_cards[SNDRV_CARDS]; +static int devno; + +struct cx25821_audio_buffer { + unsigned int bpl; + struct btcx_riscmem risc; + struct videobuf_dmabuf dma; +}; + +struct cx25821_audio_dev { + struct cx25821_dev *dev; + struct cx25821_dmaqueue q; + + /* pci i/o */ + struct pci_dev *pci; + + /* audio controls */ + int irq; + + struct snd_card *card; + + unsigned long iobase; + spinlock_t reg_lock; + atomic_t count; + + unsigned int dma_size; + unsigned int period_size; + unsigned int num_periods; + + struct videobuf_dmabuf *dma_risc; + + struct cx25821_audio_buffer *buf; + + struct snd_pcm_substream *substream; +}; + + +/**************************************************************************** + Module global static vars + ****************************************************************************/ + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ +static bool enable[SNDRV_CARDS] = { 1, [1 ... (SNDRV_CARDS - 1)] = 1 }; + +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable cx25821 soundcard. default enabled."); + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for cx25821 capture interface(s)."); + +/**************************************************************************** + Module macros + ****************************************************************************/ + +MODULE_DESCRIPTION("ALSA driver module for cx25821 based capture cards"); +MODULE_AUTHOR("Hiep Huynh"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("{{Conexant,25821}"); /* "{{Conexant,23881}," */ + +static unsigned int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable debug messages"); + +/**************************************************************************** + Module specific funtions + ****************************************************************************/ +/* Constants taken from cx88-reg.h */ +#define AUD_INT_DN_RISCI1 (1 << 0) +#define AUD_INT_UP_RISCI1 (1 << 1) +#define AUD_INT_RDS_DN_RISCI1 (1 << 2) +#define AUD_INT_DN_RISCI2 (1 << 4) /* yes, 3 is skipped */ +#define AUD_INT_UP_RISCI2 (1 << 5) +#define AUD_INT_RDS_DN_RISCI2 (1 << 6) +#define AUD_INT_DN_SYNC (1 << 12) +#define AUD_INT_UP_SYNC (1 << 13) +#define AUD_INT_RDS_DN_SYNC (1 << 14) +#define AUD_INT_OPC_ERR (1 << 16) +#define AUD_INT_BER_IRQ (1 << 20) +#define AUD_INT_MCHG_IRQ (1 << 21) +#define GP_COUNT_CONTROL_RESET 0x3 + +#define PCI_MSK_AUD_EXT (1 << 4) +#define PCI_MSK_AUD_INT (1 << 3) +/* + * BOARD Specific: Sets audio DMA + */ + +static int _cx25821_start_audio_dma(struct cx25821_audio_dev *chip) +{ + struct cx25821_audio_buffer *buf = chip->buf; + struct cx25821_dev *dev = chip->dev; + struct sram_channel *audio_ch = + &cx25821_sram_channels[AUDIO_SRAM_CHANNEL]; + u32 tmp = 0; + + /* enable output on the GPIO 0 for the MCLK ADC (Audio) */ + cx25821_set_gpiopin_direction(chip->dev, 0, 0); + + /* Make sure RISC/FIFO are off before changing FIFO/RISC settings */ + cx_clear(AUD_INT_DMA_CTL, + FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN); + + /* setup fifo + format - out channel */ + cx25821_sram_channel_setup_audio(chip->dev, audio_ch, buf->bpl, + buf->risc.dma); + + /* sets bpl size */ + cx_write(AUD_A_LNGTH, buf->bpl); + + /* reset counter */ + /* GP_COUNT_CONTROL_RESET = 0x3 */ + cx_write(AUD_A_GPCNT_CTL, GP_COUNT_CONTROL_RESET); + atomic_set(&chip->count, 0); + + /* Set the input mode to 16-bit */ + tmp = cx_read(AUD_A_CFG); + cx_write(AUD_A_CFG, tmp | FLD_AUD_DST_PK_MODE | FLD_AUD_DST_ENABLE | + FLD_AUD_CLK_ENABLE); + + /* + pr_info("DEBUG: Start audio DMA, %d B/line, cmds_start(0x%x)= %d lines/FIFO, %d periods, %d byte buffer\n", + buf->bpl, audio_ch->cmds_start, + cx_read(audio_ch->cmds_start + 12)>>1, + chip->num_periods, buf->bpl * chip->num_periods); + */ + + /* Enables corresponding bits at AUD_INT_STAT */ + cx_write(AUD_A_INT_MSK, FLD_AUD_DST_RISCI1 | FLD_AUD_DST_OF | + FLD_AUD_DST_SYNC | FLD_AUD_DST_OPC_ERR); + + /* Clean any pending interrupt bits already set */ + cx_write(AUD_A_INT_STAT, ~0); + + /* enable audio irqs */ + cx_set(PCI_INT_MSK, chip->dev->pci_irqmask | PCI_MSK_AUD_INT); + + /* Turn on audio downstream fifo and risc enable 0x101 */ + tmp = cx_read(AUD_INT_DMA_CTL); + cx_set(AUD_INT_DMA_CTL, tmp | + (FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN)); + + mdelay(100); + return 0; +} + +/* + * BOARD Specific: Resets audio DMA + */ +static int _cx25821_stop_audio_dma(struct cx25821_audio_dev *chip) +{ + struct cx25821_dev *dev = chip->dev; + + /* stop dma */ + cx_clear(AUD_INT_DMA_CTL, + FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN); + + /* disable irqs */ + cx_clear(PCI_INT_MSK, PCI_MSK_AUD_INT); + cx_clear(AUD_A_INT_MSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | + AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1); + + return 0; +} + +#define MAX_IRQ_LOOP 50 + +/* + * BOARD Specific: IRQ dma bits + */ +static char *cx25821_aud_irqs[32] = { + "dn_risci1", "up_risci1", "rds_dn_risc1", /* 0-2 */ + NULL, /* reserved */ + "dn_risci2", "up_risci2", "rds_dn_risc2", /* 4-6 */ + NULL, /* reserved */ + "dnf_of", "upf_uf", "rds_dnf_uf", /* 8-10 */ + NULL, /* reserved */ + "dn_sync", "up_sync", "rds_dn_sync", /* 12-14 */ + NULL, /* reserved */ + "opc_err", "par_err", "rip_err", /* 16-18 */ + "pci_abort", "ber_irq", "mchg_irq" /* 19-21 */ +}; + +/* + * BOARD Specific: Threats IRQ audio specific calls + */ +static void cx25821_aud_irq(struct cx25821_audio_dev *chip, u32 status, + u32 mask) +{ + struct cx25821_dev *dev = chip->dev; + + if (0 == (status & mask)) + return; + + cx_write(AUD_A_INT_STAT, status); + if (debug > 1 || (status & mask & ~0xff)) + cx25821_print_irqbits(dev->name, "irq aud", cx25821_aud_irqs, + ARRAY_SIZE(cx25821_aud_irqs), status, mask); + + /* risc op code error */ + if (status & AUD_INT_OPC_ERR) { + pr_warn("WARNING %s/1: Audio risc op code error\n", dev->name); + + cx_clear(AUD_INT_DMA_CTL, + FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN); + cx25821_sram_channel_dump_audio(dev, + &cx25821_sram_channels[AUDIO_SRAM_CHANNEL]); + } + if (status & AUD_INT_DN_SYNC) { + pr_warn("WARNING %s: Downstream sync error!\n", dev->name); + cx_write(AUD_A_GPCNT_CTL, GP_COUNT_CONTROL_RESET); + return; + } + + /* risc1 downstream */ + if (status & AUD_INT_DN_RISCI1) { + atomic_set(&chip->count, cx_read(AUD_A_GPCNT)); + snd_pcm_period_elapsed(chip->substream); + } +} + +/* + * BOARD Specific: Handles IRQ calls + */ +static irqreturn_t cx25821_irq(int irq, void *dev_id) +{ + struct cx25821_audio_dev *chip = dev_id; + struct cx25821_dev *dev = chip->dev; + u32 status, pci_status; + u32 audint_status, audint_mask; + int loop, handled = 0; + + audint_status = cx_read(AUD_A_INT_STAT); + audint_mask = cx_read(AUD_A_INT_MSK); + status = cx_read(PCI_INT_STAT); + + for (loop = 0; loop < 1; loop++) { + status = cx_read(PCI_INT_STAT); + if (0 == status) { + status = cx_read(PCI_INT_STAT); + audint_status = cx_read(AUD_A_INT_STAT); + audint_mask = cx_read(AUD_A_INT_MSK); + + if (status) { + handled = 1; + cx_write(PCI_INT_STAT, status); + + cx25821_aud_irq(chip, audint_status, + audint_mask); + break; + } else { + goto out; + } + } + + handled = 1; + cx_write(PCI_INT_STAT, status); + + cx25821_aud_irq(chip, audint_status, audint_mask); + } + + pci_status = cx_read(PCI_INT_STAT); + + if (handled) + cx_write(PCI_INT_STAT, pci_status); + +out: + return IRQ_RETVAL(handled); +} + +static int dsp_buffer_free(struct cx25821_audio_dev *chip) +{ + BUG_ON(!chip->dma_size); + + dprintk(2, "Freeing buffer\n"); + videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc); + videobuf_dma_free(chip->dma_risc); + btcx_riscmem_free(chip->pci, &chip->buf->risc); + kfree(chip->buf); + + chip->dma_risc = NULL; + chip->dma_size = 0; + + return 0; +} + +/**************************************************************************** + ALSA PCM Interface + ****************************************************************************/ + +/* + * Digital hardware definition + */ +#define DEFAULT_FIFO_SIZE 384 +static struct snd_pcm_hardware snd_cx25821_digital_hw = { + .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + /* Analog audio output will be full of clicks and pops if there + are not exactly four lines in the SRAM FIFO buffer. */ + .period_bytes_min = DEFAULT_FIFO_SIZE / 3, + .period_bytes_max = DEFAULT_FIFO_SIZE / 3, + .periods_min = 1, + .periods_max = AUDIO_LINE_SIZE, + /* 128 * 128 = 16384 = 1024 * 16 */ + .buffer_bytes_max = (AUDIO_LINE_SIZE * AUDIO_LINE_SIZE), +}; + +/* + * audio pcm capture open callback + */ +static int snd_cx25821_pcm_open(struct snd_pcm_substream *substream) +{ + struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + int err; + unsigned int bpl = 0; + + if (!chip) { + pr_err("DEBUG: cx25821 can't find device struct. Can't proceed with open\n"); + return -ENODEV; + } + + err = snd_pcm_hw_constraint_pow2(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) + goto _error; + + chip->substream = substream; + + runtime->hw = snd_cx25821_digital_hw; + + if (cx25821_sram_channels[AUDIO_SRAM_CHANNEL].fifo_size != + DEFAULT_FIFO_SIZE) { + /* since there are 3 audio Clusters */ + bpl = cx25821_sram_channels[AUDIO_SRAM_CHANNEL].fifo_size / 3; + bpl &= ~7; /* must be multiple of 8 */ + + if (bpl > AUDIO_LINE_SIZE) + bpl = AUDIO_LINE_SIZE; + + runtime->hw.period_bytes_min = bpl; + runtime->hw.period_bytes_max = bpl; + } + + return 0; +_error: + dprintk(1, "Error opening PCM!\n"); + return err; +} + +/* + * audio close callback + */ +static int snd_cx25821_close(struct snd_pcm_substream *substream) +{ + return 0; +} + +/* + * hw_params callback + */ +static int snd_cx25821_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream); + struct videobuf_dmabuf *dma; + + struct cx25821_audio_buffer *buf; + int ret; + + if (substream->runtime->dma_area) { + dsp_buffer_free(chip); + substream->runtime->dma_area = NULL; + } + + chip->period_size = params_period_bytes(hw_params); + chip->num_periods = params_periods(hw_params); + chip->dma_size = chip->period_size * params_periods(hw_params); + + BUG_ON(!chip->dma_size); + BUG_ON(chip->num_periods & (chip->num_periods - 1)); + + buf = kzalloc(sizeof(*buf), GFP_KERNEL); + if (NULL == buf) + return -ENOMEM; + + if (chip->period_size > AUDIO_LINE_SIZE) + chip->period_size = AUDIO_LINE_SIZE; + + buf->bpl = chip->period_size; + + dma = &buf->dma; + videobuf_dma_init(dma); + ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE, + (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT)); + if (ret < 0) + goto error; + + ret = videobuf_dma_map(&chip->pci->dev, dma); + if (ret < 0) + goto error; + + ret = cx25821_risc_databuffer_audio(chip->pci, &buf->risc, dma->sglist, + chip->period_size, chip->num_periods, 1); + if (ret < 0) { + pr_info("DEBUG: ERROR after cx25821_risc_databuffer_audio()\n"); + goto error; + } + + /* Loop back to start of program */ + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ + + chip->buf = buf; + chip->dma_risc = dma; + + substream->runtime->dma_area = chip->dma_risc->vaddr; + substream->runtime->dma_bytes = chip->dma_size; + substream->runtime->dma_addr = 0; + + return 0; + +error: + kfree(buf); + return ret; +} + +/* + * hw free callback + */ +static int snd_cx25821_hw_free(struct snd_pcm_substream *substream) +{ + struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream); + + if (substream->runtime->dma_area) { + dsp_buffer_free(chip); + substream->runtime->dma_area = NULL; + } + + return 0; +} + +/* + * prepare callback + */ +static int snd_cx25821_prepare(struct snd_pcm_substream *substream) +{ + return 0; +} + +/* + * trigger callback + */ +static int snd_cx25821_card_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream); + int err = 0; + + /* Local interrupts are already disabled by ALSA */ + spin_lock(&chip->reg_lock); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + err = _cx25821_start_audio_dma(chip); + break; + case SNDRV_PCM_TRIGGER_STOP: + err = _cx25821_stop_audio_dma(chip); + break; + default: + err = -EINVAL; + break; + } + + spin_unlock(&chip->reg_lock); + + return err; +} + +/* + * pointer callback + */ +static snd_pcm_uframes_t snd_cx25821_pointer(struct snd_pcm_substream + *substream) +{ + struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + u16 count; + + count = atomic_read(&chip->count); + + return runtime->period_size * (count & (runtime->periods - 1)); +} + +/* + * page callback (needed for mmap) + */ +static struct page *snd_cx25821_page(struct snd_pcm_substream *substream, + unsigned long offset) +{ + void *pageptr = substream->runtime->dma_area + offset; + + return vmalloc_to_page(pageptr); +} + +/* + * operators + */ +static struct snd_pcm_ops snd_cx25821_pcm_ops = { + .open = snd_cx25821_pcm_open, + .close = snd_cx25821_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_cx25821_hw_params, + .hw_free = snd_cx25821_hw_free, + .prepare = snd_cx25821_prepare, + .trigger = snd_cx25821_card_trigger, + .pointer = snd_cx25821_pointer, + .page = snd_cx25821_page, +}; + +/* + * ALSA create a PCM device: Called when initializing the board. + * Sets up the name and hooks up the callbacks + */ +static int snd_cx25821_pcm(struct cx25821_audio_dev *chip, int device, + char *name) +{ + struct snd_pcm *pcm; + int err; + + err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm); + if (err < 0) { + pr_info("ERROR: FAILED snd_pcm_new() in %s\n", __func__); + return err; + } + pcm->private_data = chip; + pcm->info_flags = 0; + strcpy(pcm->name, name); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx25821_pcm_ops); + + return 0; +} + +/**************************************************************************** + Basic Flow for Sound Devices + ****************************************************************************/ + +/* + * PCI ID Table - 14f1:8801 and 14f1:8811 means function 1: Audio + * Only boards with eeprom and byte 1 at eeprom=1 have it + */ + +static DEFINE_PCI_DEVICE_TABLE(cx25821_audio_pci_tbl) = { + {0x14f1, 0x0920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, cx25821_audio_pci_tbl); + +/* + * Not used in the function snd_cx25821_dev_free so removing + * from the file. + */ +/* +static int snd_cx25821_free(struct cx25821_audio_dev *chip) +{ + if (chip->irq >= 0) + free_irq(chip->irq, chip); + + cx25821_dev_unregister(chip->dev); + pci_disable_device(chip->pci); + + return 0; +} +*/ + +/* + * Component Destructor + */ +static void snd_cx25821_dev_free(struct snd_card *card) +{ + struct cx25821_audio_dev *chip = card->private_data; + + /* snd_cx25821_free(chip); */ + snd_card_free(chip->card); +} + +/* + * Alsa Constructor - Component probe + */ +static int cx25821_audio_initdev(struct cx25821_dev *dev) +{ + struct snd_card *card; + struct cx25821_audio_dev *chip; + int err; + + if (devno >= SNDRV_CARDS) { + pr_info("DEBUG ERROR: devno >= SNDRV_CARDS %s\n", __func__); + return -ENODEV; + } + + if (!enable[devno]) { + ++devno; + pr_info("DEBUG ERROR: !enable[devno] %s\n", __func__); + return -ENOENT; + } + + err = snd_card_create(index[devno], id[devno], THIS_MODULE, + sizeof(struct cx25821_audio_dev), &card); + if (err < 0) { + pr_info("DEBUG ERROR: cannot create snd_card_new in %s\n", + __func__); + return err; + } + + strcpy(card->driver, "cx25821"); + + /* Card "creation" */ + card->private_free = snd_cx25821_dev_free; + chip = card->private_data; + spin_lock_init(&chip->reg_lock); + + chip->dev = dev; + chip->card = card; + chip->pci = dev->pci; + chip->iobase = pci_resource_start(dev->pci, 0); + + chip->irq = dev->pci->irq; + + err = request_irq(dev->pci->irq, cx25821_irq, + IRQF_SHARED, chip->dev->name, chip); + + if (err < 0) { + pr_err("ERROR %s: can't get IRQ %d for ALSA\n", chip->dev->name, + dev->pci->irq); + goto error; + } + + err = snd_cx25821_pcm(chip, 0, "cx25821 Digital"); + if (err < 0) { + pr_info("DEBUG ERROR: cannot create snd_cx25821_pcm %s\n", + __func__); + goto error; + } + + snd_card_set_dev(card, &chip->pci->dev); + + strcpy(card->shortname, "cx25821"); + sprintf(card->longname, "%s at 0x%lx irq %d", chip->dev->name, + chip->iobase, chip->irq); + strcpy(card->mixername, "CX25821"); + + pr_info("%s/%i: ALSA support for cx25821 boards\n", card->driver, + devno); + + err = snd_card_register(card); + if (err < 0) { + pr_info("DEBUG ERROR: cannot register sound card %s\n", + __func__); + goto error; + } + + snd_cx25821_cards[devno] = card; + + devno++; + return 0; + +error: + snd_card_free(card); + return err; +} + +/**************************************************************************** + LINUX MODULE INIT + ****************************************************************************/ +static void cx25821_audio_fini(void) +{ + snd_card_free(snd_cx25821_cards[0]); +} + +/* + * Module initializer + * + * Loops through present saa7134 cards, and assigns an ALSA device + * to each one + * + */ +static int cx25821_alsa_init(void) +{ + struct cx25821_dev *dev = NULL; + struct list_head *list; + + mutex_lock(&cx25821_devlist_mutex); + list_for_each(list, &cx25821_devlist) { + dev = list_entry(list, struct cx25821_dev, devlist); + cx25821_audio_initdev(dev); + } + mutex_unlock(&cx25821_devlist_mutex); + + if (dev == NULL) + pr_info("ERROR ALSA: no cx25821 cards found\n"); + + return 0; + +} + +late_initcall(cx25821_alsa_init); +module_exit(cx25821_audio_fini); + +/* ----------------------------------------------------------- */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/pci/cx25821/cx25821-audio-upstream.c b/drivers/media/pci/cx25821/cx25821-audio-upstream.c new file mode 100644 index 0000000..8b2a999 --- /dev/null +++ b/drivers/media/pci/cx25821/cx25821-audio-upstream.c @@ -0,0 +1,778 @@ +/* + * Driver for the Conexant CX25821 PCIe bridge + * + * Copyright (C) 2009 Conexant Systems Inc. + * Authors <hiep.huynh@conexant.com>, <shu.lin@conexant.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include "cx25821-video.h" +#include "cx25821-audio-upstream.h" + +#include <linux/fs.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/syscalls.h> +#include <linux/file.h> +#include <linux/fcntl.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/uaccess.h> + +MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards"); +MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>"); +MODULE_LICENSE("GPL"); + +static int _intr_msk = FLD_AUD_SRC_RISCI1 | FLD_AUD_SRC_OF | + FLD_AUD_SRC_SYNC | FLD_AUD_SRC_OPC_ERR; + +int cx25821_sram_channel_setup_upstream_audio(struct cx25821_dev *dev, + struct sram_channel *ch, + unsigned int bpl, u32 risc) +{ + unsigned int i, lines; + u32 cdt; + + if (ch->cmds_start == 0) { + cx_write(ch->ptr1_reg, 0); + cx_write(ch->ptr2_reg, 0); + cx_write(ch->cnt2_reg, 0); + cx_write(ch->cnt1_reg, 0); + return 0; + } + + bpl = (bpl + 7) & ~7; /* alignment */ + cdt = ch->cdt; + lines = ch->fifo_size / bpl; + + if (lines > 3) + lines = 3; + + BUG_ON(lines < 2); + + /* write CDT */ + for (i = 0; i < lines; i++) { + cx_write(cdt + 16 * i, ch->fifo_start + bpl * i); + cx_write(cdt + 16 * i + 4, 0); + cx_write(cdt + 16 * i + 8, 0); + cx_write(cdt + 16 * i + 12, 0); + } + + /* write CMDS */ + cx_write(ch->cmds_start + 0, risc); + + cx_write(ch->cmds_start + 4, 0); + cx_write(ch->cmds_start + 8, cdt); + cx_write(ch->cmds_start + 12, AUDIO_CDT_SIZE_QW); + cx_write(ch->cmds_start + 16, ch->ctrl_start); + + /* IQ size */ + cx_write(ch->cmds_start + 20, AUDIO_IQ_SIZE_DW); + + for (i = 24; i < 80; i += 4) + cx_write(ch->cmds_start + i, 0); + + /* fill registers */ + cx_write(ch->ptr1_reg, ch->fifo_start); + cx_write(ch->ptr2_reg, cdt); + cx_write(ch->cnt2_reg, AUDIO_CDT_SIZE_QW); + cx_write(ch->cnt1_reg, AUDIO_CLUSTER_SIZE_QW - 1); + + return 0; +} + +static __le32 *cx25821_risc_field_upstream_audio(struct cx25821_dev *dev, + __le32 *rp, + dma_addr_t databuf_phys_addr, + unsigned int bpl, + int fifo_enable) +{ + unsigned int line; + struct sram_channel *sram_ch = + dev->channels[dev->_audio_upstream_channel].sram_channels; + int offset = 0; + + /* scan lines */ + for (line = 0; line < LINES_PER_AUDIO_BUFFER; line++) { + *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); + *(rp++) = cpu_to_le32(databuf_phys_addr + offset); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + + /* Check if we need to enable the FIFO + * after the first 3 lines. + * For the upstream audio channel, + * the risc engine will enable the FIFO */ + if (fifo_enable && line == 2) { + *(rp++) = RISC_WRITECR; + *(rp++) = sram_ch->dma_ctl; + *(rp++) = sram_ch->fld_aud_fifo_en; + *(rp++) = 0x00000020; + } + + offset += AUDIO_LINE_SIZE; + } + + return rp; +} + +int cx25821_risc_buffer_upstream_audio(struct cx25821_dev *dev, + struct pci_dev *pci, + unsigned int bpl, unsigned int lines) +{ + __le32 *rp; + int fifo_enable = 0; + int frame = 0, i = 0; + int frame_size = AUDIO_DATA_BUF_SZ; + int databuf_offset = 0; + int risc_flag = RISC_CNT_INC; + dma_addr_t risc_phys_jump_addr; + + /* Virtual address of Risc buffer program */ + rp = dev->_risc_virt_addr; + + /* sync instruction */ + *(rp++) = cpu_to_le32(RISC_RESYNC | AUDIO_SYNC_LINE); + + for (frame = 0; frame < NUM_AUDIO_FRAMES; frame++) { + databuf_offset = frame_size * frame; + + if (frame == 0) { + fifo_enable = 1; + risc_flag = RISC_CNT_RESET; + } else { + fifo_enable = 0; + risc_flag = RISC_CNT_INC; + } + + /* Calculate physical jump address */ + if ((frame + 1) == NUM_AUDIO_FRAMES) { + risc_phys_jump_addr = + dev->_risc_phys_start_addr + + RISC_SYNC_INSTRUCTION_SIZE; + } else { + risc_phys_jump_addr = + dev->_risc_phys_start_addr + + RISC_SYNC_INSTRUCTION_SIZE + + AUDIO_RISC_DMA_BUF_SIZE * (frame + 1); + } + + rp = cx25821_risc_field_upstream_audio(dev, rp, + dev->_audiodata_buf_phys_addr + databuf_offset, + bpl, fifo_enable); + + if (USE_RISC_NOOP_AUDIO) { + for (i = 0; i < NUM_NO_OPS; i++) + *(rp++) = cpu_to_le32(RISC_NOOP); + } + + /* Loop to (Nth)FrameRISC or to Start of Risc program & + * generate IRQ */ + *(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag); + *(rp++) = cpu_to_le32(risc_phys_jump_addr); + *(rp++) = cpu_to_le32(0); + + /* Recalculate virtual address based on frame index */ + rp = dev->_risc_virt_addr + RISC_SYNC_INSTRUCTION_SIZE / 4 + + (AUDIO_RISC_DMA_BUF_SIZE * (frame + 1) / 4); + } + + return 0; +} + +void cx25821_free_memory_audio(struct cx25821_dev *dev) +{ + if (dev->_risc_virt_addr) { + pci_free_consistent(dev->pci, dev->_audiorisc_size, + dev->_risc_virt_addr, dev->_risc_phys_addr); + dev->_risc_virt_addr = NULL; + } + + if (dev->_audiodata_buf_virt_addr) { + pci_free_consistent(dev->pci, dev->_audiodata_buf_size, + dev->_audiodata_buf_virt_addr, + dev->_audiodata_buf_phys_addr); + dev->_audiodata_buf_virt_addr = NULL; + } +} + +void cx25821_stop_upstream_audio(struct cx25821_dev *dev) +{ + struct sram_channel *sram_ch = + dev->channels[AUDIO_UPSTREAM_SRAM_CHANNEL_B].sram_channels; + u32 tmp = 0; + + if (!dev->_audio_is_running) { + printk(KERN_DEBUG + pr_fmt("No audio file is currently running so return!\n")); + return; + } + /* Disable RISC interrupts */ + cx_write(sram_ch->int_msk, 0); + + /* Turn OFF risc and fifo enable in AUD_DMA_CNTRL */ + tmp = cx_read(sram_ch->dma_ctl); + cx_write(sram_ch->dma_ctl, + tmp & ~(sram_ch->fld_aud_fifo_en | sram_ch->fld_aud_risc_en)); + + /* Clear data buffer memory */ + if (dev->_audiodata_buf_virt_addr) + memset(dev->_audiodata_buf_virt_addr, 0, + dev->_audiodata_buf_size); + + dev->_audio_is_running = 0; + dev->_is_first_audio_frame = 0; + dev->_audioframe_count = 0; + dev->_audiofile_status = END_OF_FILE; + + kfree(dev->_irq_audio_queues); + dev->_irq_audio_queues = NULL; + + kfree(dev->_audiofilename); +} + +void cx25821_free_mem_upstream_audio(struct cx25821_dev *dev) +{ + if (dev->_audio_is_running) + cx25821_stop_upstream_audio(dev); + + cx25821_free_memory_audio(dev); +} + +int cx25821_get_audio_data(struct cx25821_dev *dev, + struct sram_channel *sram_ch) +{ + struct file *myfile; + int frame_index_temp = dev->_audioframe_index; + int i = 0; + int line_size = AUDIO_LINE_SIZE; + int frame_size = AUDIO_DATA_BUF_SZ; + int frame_offset = frame_size * frame_index_temp; + ssize_t vfs_read_retval = 0; + char mybuf[line_size]; + loff_t file_offset = dev->_audioframe_count * frame_size; + loff_t pos; + mm_segment_t old_fs; + + if (dev->_audiofile_status == END_OF_FILE) + return 0; + + myfile = filp_open(dev->_audiofilename, O_RDONLY | O_LARGEFILE, 0); + + if (IS_ERR(myfile)) { + const int open_errno = -PTR_ERR(myfile); + pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", + __func__, dev->_audiofilename, open_errno); + return PTR_ERR(myfile); + } else { + if (!(myfile->f_op)) { + pr_err("%s(): File has no file operations registered!\n", + __func__); + filp_close(myfile, NULL); + return -EIO; + } + + if (!myfile->f_op->read) { + pr_err("%s(): File has no READ operations registered!\n", + __func__); + filp_close(myfile, NULL); + return -EIO; + } + + pos = myfile->f_pos; + old_fs = get_fs(); + set_fs(KERNEL_DS); + + for (i = 0; i < dev->_audio_lines_count; i++) { + pos = file_offset; + + vfs_read_retval = vfs_read(myfile, mybuf, line_size, + &pos); + + if (vfs_read_retval > 0 && vfs_read_retval == line_size + && dev->_audiodata_buf_virt_addr != NULL) { + memcpy((void *)(dev->_audiodata_buf_virt_addr + + frame_offset / 4), mybuf, + vfs_read_retval); + } + + file_offset += vfs_read_retval; + frame_offset += vfs_read_retval; + + if (vfs_read_retval < line_size) { + pr_info("Done: exit %s() since no more bytes to read from Audio file\n", + __func__); + break; + } + } + + if (i > 0) + dev->_audioframe_count++; + + dev->_audiofile_status = (vfs_read_retval == line_size) ? + IN_PROGRESS : END_OF_FILE; + + set_fs(old_fs); + filp_close(myfile, NULL); + } + + return 0; +} + +static void cx25821_audioups_handler(struct work_struct *work) +{ + struct cx25821_dev *dev = container_of(work, struct cx25821_dev, + _audio_work_entry); + + if (!dev) { + pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n", + __func__); + return; + } + + cx25821_get_audio_data(dev, dev->channels[dev->_audio_upstream_channel]. + sram_channels); +} + +int cx25821_openfile_audio(struct cx25821_dev *dev, + struct sram_channel *sram_ch) +{ + struct file *myfile; + int i = 0, j = 0; + int line_size = AUDIO_LINE_SIZE; + ssize_t vfs_read_retval = 0; + char mybuf[line_size]; + loff_t pos; + loff_t offset = (unsigned long)0; + mm_segment_t old_fs; + + myfile = filp_open(dev->_audiofilename, O_RDONLY | O_LARGEFILE, 0); + + if (IS_ERR(myfile)) { + const int open_errno = -PTR_ERR(myfile); + pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", + __func__, dev->_audiofilename, open_errno); + return PTR_ERR(myfile); + } else { + if (!(myfile->f_op)) { + pr_err("%s(): File has no file operations registered!\n", + __func__); + filp_close(myfile, NULL); + return -EIO; + } + + if (!myfile->f_op->read) { + pr_err("%s(): File has no READ operations registered!\n", + __func__); + filp_close(myfile, NULL); + return -EIO; + } + + pos = myfile->f_pos; + old_fs = get_fs(); + set_fs(KERNEL_DS); + + for (j = 0; j < NUM_AUDIO_FRAMES; j++) { + for (i = 0; i < dev->_audio_lines_count; i++) { + pos = offset; + + vfs_read_retval = vfs_read(myfile, mybuf, + line_size, &pos); + + if (vfs_read_retval > 0 && + vfs_read_retval == line_size && + dev->_audiodata_buf_virt_addr != NULL) { + memcpy((void *)(dev-> + _audiodata_buf_virt_addr + + offset / 4), mybuf, + vfs_read_retval); + } + + offset += vfs_read_retval; + + if (vfs_read_retval < line_size) { + pr_info("Done: exit %s() since no more bytes to read from Audio file\n", + __func__); + break; + } + } + + if (i > 0) + dev->_audioframe_count++; + + if (vfs_read_retval < line_size) + break; + } + + dev->_audiofile_status = (vfs_read_retval == line_size) ? + IN_PROGRESS : END_OF_FILE; + + set_fs(old_fs); + myfile->f_pos = 0; + filp_close(myfile, NULL); + } + + return 0; +} + +static int cx25821_audio_upstream_buffer_prepare(struct cx25821_dev *dev, + struct sram_channel *sram_ch, + int bpl) +{ + int ret = 0; + dma_addr_t dma_addr; + dma_addr_t data_dma_addr; + + cx25821_free_memory_audio(dev); + + dev->_risc_virt_addr = pci_alloc_consistent(dev->pci, + dev->audio_upstream_riscbuf_size, &dma_addr); + dev->_risc_virt_start_addr = dev->_risc_virt_addr; + dev->_risc_phys_start_addr = dma_addr; + dev->_risc_phys_addr = dma_addr; + dev->_audiorisc_size = dev->audio_upstream_riscbuf_size; + + if (!dev->_risc_virt_addr) { + printk(KERN_DEBUG + pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for RISC program! Returning\n")); + return -ENOMEM; + } + /* Clear out memory at address */ + memset(dev->_risc_virt_addr, 0, dev->_audiorisc_size); + + /* For Audio Data buffer allocation */ + dev->_audiodata_buf_virt_addr = pci_alloc_consistent(dev->pci, + dev->audio_upstream_databuf_size, &data_dma_addr); + dev->_audiodata_buf_phys_addr = data_dma_addr; + dev->_audiodata_buf_size = dev->audio_upstream_databuf_size; + + if (!dev->_audiodata_buf_virt_addr) { + printk(KERN_DEBUG + pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for data buffer! Returning\n")); + return -ENOMEM; + } + /* Clear out memory at address */ + memset(dev->_audiodata_buf_virt_addr, 0, dev->_audiodata_buf_size); + + ret = cx25821_openfile_audio(dev, sram_ch); + if (ret < 0) + return ret; + + /* Creating RISC programs */ + ret = cx25821_risc_buffer_upstream_audio(dev, dev->pci, bpl, + dev->_audio_lines_count); + if (ret < 0) { + printk(KERN_DEBUG + pr_fmt("ERROR creating audio upstream RISC programs!\n")); + goto error; + } + + return 0; + +error: + return ret; +} + +int cx25821_audio_upstream_irq(struct cx25821_dev *dev, int chan_num, + u32 status) +{ + int i = 0; + u32 int_msk_tmp; + struct sram_channel *channel = dev->channels[chan_num].sram_channels; + dma_addr_t risc_phys_jump_addr; + __le32 *rp; + + if (status & FLD_AUD_SRC_RISCI1) { + /* Get interrupt_index of the program that interrupted */ + u32 prog_cnt = cx_read(channel->gpcnt); + + /* Since we've identified our IRQ, clear our bits from the + * interrupt mask and interrupt status registers */ + cx_write(channel->int_msk, 0); + cx_write(channel->int_stat, cx_read(channel->int_stat)); + + spin_lock(&dev->slock); + + while (prog_cnt != dev->_last_index_irq) { + /* Update _last_index_irq */ + if (dev->_last_index_irq < (NUMBER_OF_PROGRAMS - 1)) + dev->_last_index_irq++; + else + dev->_last_index_irq = 0; + + dev->_audioframe_index = dev->_last_index_irq; + + queue_work(dev->_irq_audio_queues, + &dev->_audio_work_entry); + } + + if (dev->_is_first_audio_frame) { + dev->_is_first_audio_frame = 0; + + if (dev->_risc_virt_start_addr != NULL) { + risc_phys_jump_addr = + dev->_risc_phys_start_addr + + RISC_SYNC_INSTRUCTION_SIZE + + AUDIO_RISC_DMA_BUF_SIZE; + + rp = cx25821_risc_field_upstream_audio(dev, + dev->_risc_virt_start_addr + 1, + dev->_audiodata_buf_phys_addr, + AUDIO_LINE_SIZE, FIFO_DISABLE); + + if (USE_RISC_NOOP_AUDIO) { + for (i = 0; i < NUM_NO_OPS; i++) { + *(rp++) = + cpu_to_le32(RISC_NOOP); + } + } + /* Jump to 2nd Audio Frame */ + *(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | + RISC_CNT_RESET); + *(rp++) = cpu_to_le32(risc_phys_jump_addr); + *(rp++) = cpu_to_le32(0); + } + } + + spin_unlock(&dev->slock); + } else { + if (status & FLD_AUD_SRC_OF) + pr_warn("%s(): Audio Received Overflow Error Interrupt!\n", + __func__); + + if (status & FLD_AUD_SRC_SYNC) + pr_warn("%s(): Audio Received Sync Error Interrupt!\n", + __func__); + + if (status & FLD_AUD_SRC_OPC_ERR) + pr_warn("%s(): Audio Received OpCode Error Interrupt!\n", + __func__); + + /* Read and write back the interrupt status register to clear + * our bits */ + cx_write(channel->int_stat, cx_read(channel->int_stat)); + } + + if (dev->_audiofile_status == END_OF_FILE) { + pr_warn("EOF Channel Audio Framecount = %d\n", + dev->_audioframe_count); + return -1; + } + /* ElSE, set the interrupt mask register, re-enable irq. */ + int_msk_tmp = cx_read(channel->int_msk); + cx_write(channel->int_msk, int_msk_tmp |= _intr_msk); + + return 0; +} + +static irqreturn_t cx25821_upstream_irq_audio(int irq, void *dev_id) +{ + struct cx25821_dev *dev = dev_id; + u32 audio_status; + int handled = 0; + struct sram_channel *sram_ch; + + if (!dev) + return -1; + + sram_ch = dev->channels[dev->_audio_upstream_channel].sram_channels; + + audio_status = cx_read(sram_ch->int_stat); + + /* Only deal with our interrupt */ + if (audio_status) { + handled = cx25821_audio_upstream_irq(dev, + dev->_audio_upstream_channel, audio_status); + } + + if (handled < 0) + cx25821_stop_upstream_audio(dev); + else + handled += handled; + + return IRQ_RETVAL(handled); +} + +static void cx25821_wait_fifo_enable(struct cx25821_dev *dev, + struct sram_channel *sram_ch) +{ + int count = 0; + u32 tmp; + + do { + /* Wait 10 microsecond before checking to see if the FIFO is + * turned ON. */ + udelay(10); + + tmp = cx_read(sram_ch->dma_ctl); + + /* 10 millisecond timeout */ + if (count++ > 1000) { + pr_err("ERROR: %s() fifo is NOT turned on. Timeout!\n", + __func__); + return; + } + + } while (!(tmp & sram_ch->fld_aud_fifo_en)); + +} + +int cx25821_start_audio_dma_upstream(struct cx25821_dev *dev, + struct sram_channel *sram_ch) +{ + u32 tmp = 0; + int err = 0; + + /* Set the physical start address of the RISC program in the initial + * program counter(IPC) member of the CMDS. */ + cx_write(sram_ch->cmds_start + 0, dev->_risc_phys_addr); + /* Risc IPC High 64 bits 63-32 */ + cx_write(sram_ch->cmds_start + 4, 0); + + /* reset counter */ + cx_write(sram_ch->gpcnt_ctl, 3); + + /* Set the line length (It looks like we do not need to set the + * line length) */ + cx_write(sram_ch->aud_length, AUDIO_LINE_SIZE & FLD_AUD_DST_LN_LNGTH); + + /* Set the input mode to 16-bit */ + tmp = cx_read(sram_ch->aud_cfg); + tmp |= FLD_AUD_SRC_ENABLE | FLD_AUD_DST_PK_MODE | FLD_AUD_CLK_ENABLE | + FLD_AUD_MASTER_MODE | FLD_AUD_CLK_SELECT_PLL_D | + FLD_AUD_SONY_MODE; + cx_write(sram_ch->aud_cfg, tmp); + + /* Read and write back the interrupt status register to clear it */ + tmp = cx_read(sram_ch->int_stat); + cx_write(sram_ch->int_stat, tmp); + + /* Clear our bits from the interrupt status register. */ + cx_write(sram_ch->int_stat, _intr_msk); + + /* Set the interrupt mask register, enable irq. */ + cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << sram_ch->irq_bit)); + tmp = cx_read(sram_ch->int_msk); + cx_write(sram_ch->int_msk, tmp |= _intr_msk); + + err = request_irq(dev->pci->irq, cx25821_upstream_irq_audio, + IRQF_SHARED, dev->name, dev); + if (err < 0) { + pr_err("%s: can't get upstream IRQ %d\n", dev->name, + dev->pci->irq); + goto fail_irq; + } + + /* Start the DMA engine */ + tmp = cx_read(sram_ch->dma_ctl); + cx_set(sram_ch->dma_ctl, tmp | sram_ch->fld_aud_risc_en); + + dev->_audio_is_running = 1; + dev->_is_first_audio_frame = 1; + + /* The fifo_en bit turns on by the first Risc program */ + cx25821_wait_fifo_enable(dev, sram_ch); + + return 0; + +fail_irq: + cx25821_dev_unregister(dev); + return err; +} + +int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select) +{ + struct sram_channel *sram_ch; + int retval = 0; + int err = 0; + int str_length = 0; + + if (dev->_audio_is_running) { + pr_warn("Audio Channel is still running so return!\n"); + return 0; + } + + dev->_audio_upstream_channel = channel_select; + sram_ch = dev->channels[channel_select].sram_channels; + + /* Work queue */ + INIT_WORK(&dev->_audio_work_entry, cx25821_audioups_handler); + dev->_irq_audio_queues = + create_singlethread_workqueue("cx25821_audioworkqueue"); + + if (!dev->_irq_audio_queues) { + printk(KERN_DEBUG + pr_fmt("ERROR: create_singlethread_workqueue() for Audio FAILED!\n")); + return -ENOMEM; + } + + dev->_last_index_irq = 0; + dev->_audio_is_running = 0; + dev->_audioframe_count = 0; + dev->_audiofile_status = RESET_STATUS; + dev->_audio_lines_count = LINES_PER_AUDIO_BUFFER; + _line_size = AUDIO_LINE_SIZE; + + if (dev->input_audiofilename) { + str_length = strlen(dev->input_audiofilename); + dev->_audiofilename = kmemdup(dev->input_audiofilename, + str_length + 1, GFP_KERNEL); + + if (!dev->_audiofilename) + goto error; + + /* Default if filename is empty string */ + if (strcmp(dev->input_audiofilename, "") == 0) + dev->_audiofilename = "/root/audioGOOD.wav"; + } else { + str_length = strlen(_defaultAudioName); + dev->_audiofilename = kmemdup(_defaultAudioName, + str_length + 1, GFP_KERNEL); + + if (!dev->_audiofilename) + goto error; + } + + retval = cx25821_sram_channel_setup_upstream_audio(dev, sram_ch, + _line_size, 0); + + dev->audio_upstream_riscbuf_size = + AUDIO_RISC_DMA_BUF_SIZE * NUM_AUDIO_PROGS + + RISC_SYNC_INSTRUCTION_SIZE; + dev->audio_upstream_databuf_size = AUDIO_DATA_BUF_SZ * NUM_AUDIO_PROGS; + + /* Allocating buffers and prepare RISC program */ + retval = cx25821_audio_upstream_buffer_prepare(dev, sram_ch, + _line_size); + if (retval < 0) { + pr_err("%s: Failed to set up Audio upstream buffers!\n", + dev->name); + goto error; + } + /* Start RISC engine */ + cx25821_start_audio_dma_upstream(dev, sram_ch); + + return 0; + +error: + cx25821_dev_unregister(dev); + + return err; +} diff --git a/drivers/media/pci/cx25821/cx25821-audio-upstream.h b/drivers/media/pci/cx25821/cx25821-audio-upstream.h new file mode 100644 index 0000000..af2ae7c --- /dev/null +++ b/drivers/media/pci/cx25821/cx25821-audio-upstream.h @@ -0,0 +1,62 @@ +/* + * Driver for the Conexant CX25821 PCIe bridge + * + * Copyright (C) 2009 Conexant Systems Inc. + * Authors <hiep.huynh@conexant.com>, <shu.lin@conexant.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/mutex.h> +#include <linux/workqueue.h> + +#define NUM_AUDIO_PROGS 8 +#define NUM_AUDIO_FRAMES 8 +#define END_OF_FILE 0 +#define IN_PROGRESS 1 +#define RESET_STATUS -1 +#define FIFO_DISABLE 0 +#define FIFO_ENABLE 1 +#define NUM_NO_OPS 4 + +#define RISC_READ_INSTRUCTION_SIZE 12 +#define RISC_JUMP_INSTRUCTION_SIZE 12 +#define RISC_WRITECR_INSTRUCTION_SIZE 16 +#define RISC_SYNC_INSTRUCTION_SIZE 4 +#define DWORD_SIZE 4 +#define AUDIO_SYNC_LINE 4 + +#define LINES_PER_AUDIO_BUFFER 15 +#define AUDIO_LINE_SIZE 128 +#define AUDIO_DATA_BUF_SZ (AUDIO_LINE_SIZE * LINES_PER_AUDIO_BUFFER) + +#define USE_RISC_NOOP_AUDIO 1 + +#ifdef USE_RISC_NOOP_AUDIO +#define AUDIO_RISC_DMA_BUF_SIZE \ + (LINES_PER_AUDIO_BUFFER * RISC_READ_INSTRUCTION_SIZE + \ + RISC_WRITECR_INSTRUCTION_SIZE + NUM_NO_OPS * DWORD_SIZE + \ + RISC_JUMP_INSTRUCTION_SIZE) +#endif + +#ifndef USE_RISC_NOOP_AUDIO +#define AUDIO_RISC_DMA_BUF_SIZE \ + (LINES_PER_AUDIO_BUFFER * RISC_READ_INSTRUCTION_SIZE + \ + RISC_WRITECR_INSTRUCTION_SIZE + RISC_JUMP_INSTRUCTION_SIZE) +#endif + +static int _line_size; +char *_defaultAudioName = "/root/audioGOOD.wav"; diff --git a/drivers/media/pci/cx25821/cx25821-audio.h b/drivers/media/pci/cx25821/cx25821-audio.h new file mode 100644 index 0000000..1fc2d24 --- /dev/null +++ b/drivers/media/pci/cx25821/cx25821-audio.h @@ -0,0 +1,62 @@ +/* + * Driver for the Conexant CX25821 PCIe bridge + * + * Copyright (C) 2009 Conexant Systems Inc. + * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __CX25821_AUDIO_H__ +#define __CX25821_AUDIO_H__ + +#define USE_RISC_NOOP 1 +#define LINES_PER_BUFFER 15 +#define AUDIO_LINE_SIZE 128 + +/* Number of buffer programs to use at once. */ +#define NUMBER_OF_PROGRAMS 8 + +/* + * Max size of the RISC program for a buffer. - worst case is 2 writes per line + * Space is also added for the 4 no-op instructions added on the end. + */ +#ifndef USE_RISC_NOOP +#define MAX_BUFFER_PROGRAM_SIZE \ + (2 * LINES_PER_BUFFER * RISC_WRITE_INSTRUCTION_SIZE + \ + RISC_WRITECR_INSTRUCTION_SIZE * 4) +#endif + +/* MAE 12 July 2005 Try to use NOOP RISC instruction instead */ +#ifdef USE_RISC_NOOP +#define MAX_BUFFER_PROGRAM_SIZE \ + (2 * LINES_PER_BUFFER * RISC_WRITE_INSTRUCTION_SIZE + \ + RISC_NOOP_INSTRUCTION_SIZE * 4) +#endif + +/* Sizes of various instructions in bytes. Used when adding instructions. */ +#define RISC_WRITE_INSTRUCTION_SIZE 12 +#define RISC_JUMP_INSTRUCTION_SIZE 12 +#define RISC_SKIP_INSTRUCTION_SIZE 4 +#define RISC_SYNC_INSTRUCTION_SIZE 4 +#define RISC_WRITECR_INSTRUCTION_SIZE 16 +#define RISC_NOOP_INSTRUCTION_SIZE 4 + +#define MAX_AUDIO_DMA_BUFFER_SIZE \ + (MAX_BUFFER_PROGRAM_SIZE * NUMBER_OF_PROGRAMS + \ + RISC_SYNC_INSTRUCTION_SIZE) + +#endif diff --git a/drivers/media/pci/cx25821/cx25821-biffuncs.h b/drivers/media/pci/cx25821/cx25821-biffuncs.h new file mode 100644 index 0000000..9326a7c --- /dev/null +++ b/drivers/media/pci/cx25821/cx25821-biffuncs.h @@ -0,0 +1,45 @@ +/* + * Driver for the Conexant CX25821 PCIe bridge + * + * Copyright (C) 2009 Conexant Systems Inc. + * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _BITFUNCS_H +#define _BITFUNCS_H + +#define SetBit(Bit) (1 << Bit) + +inline u8 getBit(u32 sample, u8 index) +{ + return (u8) ((sample >> index) & 1); +} + +inline u32 clearBitAtPos(u32 value, u8 bit) +{ + return value & ~(1 << bit); +} + +inline u32 setBitAtPos(u32 sample, u8 bit) +{ + sample |= (1 << bit); + return sample; + +} + +#endif diff --git a/drivers/media/pci/cx25821/cx25821-cards.c b/drivers/media/pci/cx25821/cx25821-cards.c new file mode 100644 index 0000000..99988c9 --- /dev/null +++ b/drivers/media/pci/cx25821/cx25821-cards.c @@ -0,0 +1,72 @@ +/* + * Driver for the Conexant CX25821 PCIe bridge + * + * Copyright (C) 2009 Conexant Systems Inc. + * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> + * Based on Steven Toth <stoth@linuxtv.org> cx23885 driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <media/cx25840.h> + +#include "cx25821.h" +#include "tuner-xc2028.h" + +/* board config info */ + +struct cx25821_board cx25821_boards[] = { + [UNKNOWN_BOARD] = { + .name = "UNKNOWN/GENERIC", + /* Ensure safe default for unknown boards */ + .clk_freq = 0, + }, + + [CX25821_BOARD] = { + .name = "CX25821", + .portb = CX25821_RAW, + .portc = CX25821_264, + .input[0].type = CX25821_VMUX_COMPOSITE, + }, + +}; + +const unsigned int cx25821_bcount = ARRAY_SIZE(cx25821_boards); + +struct cx25821_subid cx25821_subids[] = { + { + .subvendor = 0x14f1, + .subdevice = 0x0920, + .card = CX25821_BOARD, + }, +}; + +void cx25821_card_setup(struct cx25821_dev *dev) +{ + static u8 eeprom[256]; + + if (dev->i2c_bus[0].i2c_rc == 0) { + dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; + tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, + sizeof(eeprom)); + } +} diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c new file mode 100644 index 0000000..f11f6f0 --- /dev/null +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -0,0 +1,1502 @@ +/* + * Driver for the Conexant CX25821 PCIe bridge + * + * Copyright (C) 2009 Conexant Systems Inc. + * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> + * Based on Steven Toth <stoth@linuxtv.org> cx23885 driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/i2c.h> +#include <linux/slab.h> +#include "cx25821.h" +#include "cx25821-sram.h" +#include "cx25821-video.h" + +MODULE_DESCRIPTION("Driver for Athena cards"); +MODULE_AUTHOR("Shu Lin - Hiep Huynh"); +MODULE_LICENSE("GPL"); + +static unsigned int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable debug messages"); + +static unsigned int card[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET }; +module_param_array(card, int, NULL, 0444); +MODULE_PARM_DESC(card, "card type"); + +static unsigned int cx25821_devcount; + +DEFINE_MUTEX(cx25821_devlist_mutex); +EXPORT_SYMBOL(cx25821_devlist_mutex); +LIST_HEAD(cx25821_devlist); +EXPORT_SYMBOL(cx25821_devlist); + +struct sram_channel cx25821_sram_channels[] = { + [SRAM_CH00] = { + .i = SRAM_CH00, + .name = "VID A", + .cmds_start = VID_A_DOWN_CMDS, + .ctrl_start = VID_A_IQ, + .cdt = VID_A_CDT, + .fifo_start = VID_A_DOWN_CLUSTER_1, + .fifo_size = (VID_CLUSTER_SIZE << 2), + .ptr1_reg = DMA1_PTR1, + .ptr2_reg = DMA1_PTR2, + .cnt1_reg = DMA1_CNT1, + .cnt2_reg = DMA1_CNT2, + .int_msk = VID_A_INT_MSK, + .int_stat = VID_A_INT_STAT, + .int_mstat = VID_A_INT_MSTAT, + .dma_ctl = VID_DST_A_DMA_CTL, + .gpcnt_ctl = VID_DST_A_GPCNT_CTL, + .gpcnt = VID_DST_A_GPCNT, + .vip_ctl = VID_DST_A_VIP_CTL, + .pix_frmt = VID_DST_A_PIX_FRMT, + }, + + [SRAM_CH01] = { + .i = SRAM_CH01, + .name = "VID B", + .cmds_start = VID_B_DOWN_CMDS, + .ctrl_start = VID_B_IQ, + .cdt = VID_B_CDT, + .fifo_start = VID_B_DOWN_CLUSTER_1, + .fifo_size = (VID_CLUSTER_SIZE << 2), + .ptr1_reg = DMA2_PTR1, + .ptr2_reg = DMA2_PTR2, + .cnt1_reg = DMA2_CNT1, + .cnt2_reg = DMA2_CNT2, + .int_msk = VID_B_INT_MSK, + .int_stat = VID_B_INT_STAT, + .int_mstat = VID_B_INT_MSTAT, + .dma_ctl = VID_DST_B_DMA_CTL, + .gpcnt_ctl = VID_DST_B_GPCNT_CTL, + .gpcnt = VID_DST_B_GPCNT, + .vip_ctl = VID_DST_B_VIP_CTL, + .pix_frmt = VID_DST_B_PIX_FRMT, + }, + + [SRAM_CH02] = { + .i = SRAM_CH02, + .name = "VID C", + .cmds_start = VID_C_DOWN_CMDS, + .ctrl_start = VID_C_IQ, + .cdt = VID_C_CDT, + .fifo_start = VID_C_DOWN_CLUSTER_1, + .fifo_size = (VID_CLUSTER_SIZE << 2), + .ptr1_reg = DMA3_PTR1, + .ptr2_reg = DMA3_PTR2, + .cnt1_reg = DMA3_CNT1, + .cnt2_reg = DMA3_CNT2, + .int_msk = VID_C_INT_MSK, + .int_stat = VID_C_INT_STAT, + .int_mstat = VID_C_INT_MSTAT, + .dma_ctl = VID_DST_C_DMA_CTL, + .gpcnt_ctl = VID_DST_C_GPCNT_CTL, + .gpcnt = VID_DST_C_GPCNT, + .vip_ctl = VID_DST_C_VIP_CTL, + .pix_frmt = VID_DST_C_PIX_FRMT, + }, + + [SRAM_CH03] = { + .i = SRAM_CH03, + .name = "VID D", + .cmds_start = VID_D_DOWN_CMDS, + .ctrl_start = VID_D_IQ, + .cdt = VID_D_CDT, + .fifo_start = VID_D_DOWN_CLUSTER_1, + .fifo_size = (VID_CLUSTER_SIZE << 2), + .ptr1_reg = DMA4_PTR1, + .ptr2_reg = DMA4_PTR2, + .cnt1_reg = DMA4_CNT1, + .cnt2_reg = DMA4_CNT2, + .int_msk = VID_D_INT_MSK, + .int_stat = VID_D_INT_STAT, + .int_mstat = VID_D_INT_MSTAT, + .dma_ctl = VID_DST_D_DMA_CTL, + .gpcnt_ctl = VID_DST_D_GPCNT_CTL, + .gpcnt = VID_DST_D_GPCNT, + .vip_ctl = VID_DST_D_VIP_CTL, + .pix_frmt = VID_DST_D_PIX_FRMT, + }, + + [SRAM_CH04] = { + .i = SRAM_CH04, + .name = "VID E", + .cmds_start = VID_E_DOWN_CMDS, + .ctrl_start = VID_E_IQ, + .cdt = VID_E_CDT, + .fifo_start = VID_E_DOWN_CLUSTER_1, + .fifo_size = (VID_CLUSTER_SIZE << 2), + .ptr1_reg = DMA5_PTR1, + .ptr2_reg = DMA5_PTR2, + .cnt1_reg = DMA5_CNT1, + .cnt2_reg = DMA5_CNT2, + .int_msk = VID_E_INT_MSK, + .int_stat = VID_E_INT_STAT, + .int_mstat = VID_E_INT_MSTAT, + .dma_ctl = VID_DST_E_DMA_CTL, + .gpcnt_ctl = VID_DST_E_GPCNT_CTL, + .gpcnt = VID_DST_E_GPCNT, + .vip_ctl = VID_DST_E_VIP_CTL, + .pix_frmt = VID_DST_E_PIX_FRMT, + }, + + [SRAM_CH05] = { + .i = SRAM_CH05, + .name = "VID F", + .cmds_start = VID_F_DOWN_CMDS, + .ctrl_start = VID_F_IQ, + .cdt = VID_F_CDT, + .fifo_start = VID_F_DOWN_CLUSTER_1, + .fifo_size = (VID_CLUSTER_SIZE << 2), + .ptr1_reg = DMA6_PTR1, + .ptr2_reg = DMA6_PTR2, + .cnt1_reg = DMA6_CNT1, + .cnt2_reg = DMA6_CNT2, + .int_msk = VID_F_INT_MSK, + .int_stat = VID_F_INT_STAT, + .int_mstat = VID_F_INT_MSTAT, + .dma_ctl = VID_DST_F_DMA_CTL, + .gpcnt_ctl = VID_DST_F_GPCNT_CTL, + .gpcnt = VID_DST_F_GPCNT, + .vip_ctl = VID_DST_F_VIP_CTL, + .pix_frmt = VID_DST_F_PIX_FRMT, + }, + + [SRAM_CH06] = { + .i = SRAM_CH06, + .name = "VID G", + .cmds_start = VID_G_DOWN_CMDS, + .ctrl_start = VID_G_IQ, + .cdt = VID_G_CDT, + .fifo_start = VID_G_DOWN_CLUSTER_1, + .fifo_size = (VID_CLUSTER_SIZE << 2), + .ptr1_reg = DMA7_PTR1, + .ptr2_reg = DMA7_PTR2, + .cnt1_reg = DMA7_CNT1, + .cnt2_reg = DMA7_CNT2, + .int_msk = VID_G_INT_MSK, + .int_stat = VID_G_INT_STAT, + .int_mstat = VID_G_INT_MSTAT, + .dma_ctl = VID_DST_G_DMA_CTL, + .gpcnt_ctl = VID_DST_G_GPCNT_CTL, + .gpcnt = VID_DST_G_GPCNT, + .vip_ctl = VID_DST_G_VIP_CTL, + .pix_frmt = VID_DST_G_PIX_FRMT, + }, + + [SRAM_CH07] = { + .i = SRAM_CH07, + .name = "VID H", + .cmds_start = VID_H_DOWN_CMDS, + .ctrl_start = VID_H_IQ, + .cdt = VID_H_CDT, + .fifo_start = VID_H_DOWN_CLUSTER_1, + .fifo_size = (VID_CLUSTER_SIZE << 2), + .ptr1_reg = DMA8_PTR1, + .ptr2_reg = DMA8_PTR2, + .cnt1_reg = DMA8_CNT1, + .cnt2_reg = DMA8_CNT2, + .int_msk = VID_H_INT_MSK, + .int_stat = VID_H_INT_STAT, + .int_mstat = VID_H_INT_MSTAT, + .dma_ctl = VID_DST_H_DMA_CTL, + .gpcnt_ctl = VID_DST_H_GPCNT_CTL, + .gpcnt = VID_DST_H_GPCNT, + .vip_ctl = VID_DST_H_VIP_CTL, + .pix_frmt = VID_DST_H_PIX_FRMT, + }, + + [SRAM_CH08] = { + .name = "audio from", + .cmds_start = AUD_A_DOWN_CMDS, + .ctrl_start = AUD_A_IQ, + .cdt = AUD_A_CDT, + .fifo_start = AUD_A_DOWN_CLUSTER_1, + .fifo_size = AUDIO_CLUSTER_SIZE * 3, + .ptr1_reg = DMA17_PTR1, + .ptr2_reg = DMA17_PTR2, + .cnt1_reg = DMA17_CNT1, + .cnt2_reg = DMA17_CNT2, + }, + + [SRAM_CH09] = { + .i = SRAM_CH09, + .name = "VID Upstream I", + .cmds_start = VID_I_UP_CMDS, + .ctrl_start = VID_I_IQ, + .cdt = VID_I_CDT, + .fifo_start = VID_I_UP_CLUSTER_1, + .fifo_size = (VID_CLUSTER_SIZE << 2), + .ptr1_reg = DMA15_PTR1, + .ptr2_reg = DMA15_PTR2, + .cnt1_reg = DMA15_CNT1, + .cnt2_reg = DMA15_CNT2, + .int_msk = VID_I_INT_MSK, + .int_stat = VID_I_INT_STAT, + .int_mstat = VID_I_INT_MSTAT, + .dma_ctl = VID_SRC_I_DMA_CTL, + .gpcnt_ctl = VID_SRC_I_GPCNT_CTL, + .gpcnt = VID_SRC_I_GPCNT, + + .vid_fmt_ctl = VID_SRC_I_FMT_CTL, + .vid_active_ctl1 = VID_SRC_I_ACTIVE_CTL1, + .vid_active_ctl2 = VID_SRC_I_ACTIVE_CTL2, + .vid_cdt_size = VID_SRC_I_CDT_SZ, + .irq_bit = 8, + }, + + [SRAM_CH10] = { + .i = SRAM_CH10, + .name = "VID Upstream J", + .cmds_start = VID_J_UP_CMDS, + .ctrl_start = VID_J_IQ, + .cdt = VID_J_CDT, + .fifo_start = VID_J_UP_CLUSTER_1, + .fifo_size = (VID_CLUSTER_SIZE << 2), + .ptr1_reg = DMA16_PTR1, + .ptr2_reg = DMA16_PTR2, + .cnt1_reg = DMA16_CNT1, + .cnt2_reg = DMA16_CNT2, + .int_msk = VID_J_INT_MSK, + .int_stat = VID_J_INT_STAT, + .int_mstat = VID_J_INT_MSTAT, + .dma_ctl = VID_SRC_J_DMA_CTL, + .gpcnt_ctl = VID_SRC_J_GPCNT_CTL, + .gpcnt = VID_SRC_J_GPCNT, + + .vid_fmt_ctl = VID_SRC_J_FMT_CTL, + .vid_active_ctl1 = VID_SRC_J_ACTIVE_CTL1, + .vid_active_ctl2 = VID_SRC_J_ACTIVE_CTL2, + .vid_cdt_size = VID_SRC_J_CDT_SZ, + .irq_bit = 9, + }, + + [SRAM_CH11] = { + .i = SRAM_CH11, + .name = "Audio Upstream Channel B", + .cmds_start = AUD_B_UP_CMDS, + .ctrl_start = AUD_B_IQ, + .cdt = AUD_B_CDT, + .fifo_start = AUD_B_UP_CLUSTER_1, + .fifo_size = (AUDIO_CLUSTER_SIZE * 3), + .ptr1_reg = DMA22_PTR1, + .ptr2_reg = DMA22_PTR2, + .cnt1_reg = DMA22_CNT1, + .cnt2_reg = DMA22_CNT2, + .int_msk = AUD_B_INT_MSK, + .int_stat = AUD_B_INT_STAT, + .int_mstat = AUD_B_INT_MSTAT, + .dma_ctl = AUD_INT_DMA_CTL, + .gpcnt_ctl = AUD_B_GPCNT_CTL, + .gpcnt = AUD_B_GPCNT, + .aud_length = AUD_B_LNGTH, + .aud_cfg = AUD_B_CFG, + .fld_aud_fifo_en = FLD_AUD_SRC_B_FIFO_EN, + .fld_aud_risc_en = FLD_AUD_SRC_B_RISC_EN, + .irq_bit = 11, + }, +}; +EXPORT_SYMBOL(cx25821_sram_channels); + +struct sram_channel *channel0 = &cx25821_sram_channels[SRAM_CH00]; +struct sram_channel *channel1 = &cx25821_sram_channels[SRAM_CH01]; +struct sram_channel *channel2 = &cx25821_sram_channels[SRAM_CH02]; +struct sram_channel *channel3 = &cx25821_sram_channels[SRAM_CH03]; +struct sram_channel *channel4 = &cx25821_sram_channels[SRAM_CH04]; +struct sram_channel *channel5 = &cx25821_sram_channels[SRAM_CH05]; +struct sram_channel *channel6 = &cx25821_sram_channels[SRAM_CH06]; +struct sram_channel *channel7 = &cx25821_sram_channels[SRAM_CH07]; +struct sram_channel *channel9 = &cx25821_sram_channels[SRAM_CH09]; +struct sram_channel *channel10 = &cx25821_sram_channels[SRAM_CH10]; +struct sram_channel *channel11 = &cx25821_sram_channels[SRAM_CH11]; + +struct cx25821_dmaqueue mpegq; + +static int cx25821_risc_decode(u32 risc) +{ + static const char * const instr[16] = { + [RISC_SYNC >> 28] = "sync", + [RISC_WRITE >> 28] = "write", + [RISC_WRITEC >> 28] = "writec", + [RISC_READ >> 28] = "read", + [RISC_READC >> 28] = "readc", + [RISC_JUMP >> 28] = "jump", + [RISC_SKIP >> 28] = "skip", + [RISC_WRITERM >> 28] = "writerm", + [RISC_WRITECM >> 28] = "writecm", + [RISC_WRITECR >> 28] = "writecr", + }; + static const int incr[16] = { + [RISC_WRITE >> 28] = 3, + [RISC_JUMP >> 28] = 3, + [RISC_SKIP >> 28] = 1, + [RISC_SYNC >> 28] = 1, + [RISC_WRITERM >> 28] = 3, + [RISC_WRITECM >> 28] = 3, + [RISC_WRITECR >> 28] = 4, + }; + static const char * const bits[] = { + "12", "13", "14", "resync", + "cnt0", "cnt1", "18", "19", + "20", "21", "22", "23", + "irq1", "irq2", "eol", "sol", + }; + int i; + + pr_cont("0x%08x [ %s", + risc, instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); + for (i = ARRAY_SIZE(bits) - 1; i >= 0; i--) { + if (risc & (1 << (i + 12))) + pr_cont(" %s", bits[i]); + } + pr_cont(" count=%d ]\n", risc & 0xfff); + return incr[risc >> 28] ? incr[risc >> 28] : 1; +} + +static inline int i2c_slave_did_ack(struct i2c_adapter *i2c_adap) +{ + struct cx25821_i2c *bus = i2c_adap->algo_data; + struct cx25821_dev *dev = bus->dev; + return cx_read(bus->reg_stat) & 0x01; +} + +static void cx25821_registers_init(struct cx25821_dev *dev) +{ + u32 tmp; + + /* enable RUN_RISC in Pecos */ + cx_write(DEV_CNTRL2, 0x20); + + /* Set the master PCI interrupt masks to enable video, audio, MBIF, + * and GPIO interrupts + * I2C interrupt masking is handled by the I2C objects themselves. */ + cx_write(PCI_INT_MSK, 0x2001FFFF); + + tmp = cx_read(RDR_TLCTL0); + tmp &= ~FLD_CFG_RCB_CK_EN; /* Clear the RCB_CK_EN bit */ + cx_write(RDR_TLCTL0, tmp); + + /* PLL-A setting for the Audio Master Clock */ + cx_write(PLL_A_INT_FRAC, 0x9807A58B); + + /* PLL_A_POST = 0x1C, PLL_A_OUT_TO_PIN = 0x1 */ + cx_write(PLL_A_POST_STAT_BIST, 0x8000019C); + + /* clear reset bit [31] */ + tmp = cx_read(PLL_A_INT_FRAC); + cx_write(PLL_A_INT_FRAC, tmp & 0x7FFFFFFF); + + /* PLL-B setting for Mobilygen Host Bus Interface */ + cx_write(PLL_B_INT_FRAC, 0x9883A86F); + + /* PLL_B_POST = 0xD, PLL_B_OUT_TO_PIN = 0x0 */ + cx_write(PLL_B_POST_STAT_BIST, 0x8000018D); + + /* clear reset bit [31] */ + tmp = cx_read(PLL_B_INT_FRAC); + cx_write(PLL_B_INT_FRAC, tmp & 0x7FFFFFFF); + + /* PLL-C setting for video upstream channel */ + cx_write(PLL_C_INT_FRAC, 0x96A0EA3F); + + /* PLL_C_POST = 0x3, PLL_C_OUT_TO_PIN = 0x0 */ + cx_write(PLL_C_POST_STAT_BIST, 0x80000103); + + /* clear reset bit [31] */ + tmp = cx_read(PLL_C_INT_FRAC); + cx_write(PLL_C_INT_FRAC, tmp & 0x7FFFFFFF); + + /* PLL-D setting for audio upstream channel */ + cx_write(PLL_D_INT_FRAC, 0x98757F5B); + + /* PLL_D_POST = 0x13, PLL_D_OUT_TO_PIN = 0x0 */ + cx_write(PLL_D_POST_STAT_BIST, 0x80000113); + + /* clear reset bit [31] */ + tmp = cx_read(PLL_D_INT_FRAC); + cx_write(PLL_D_INT_FRAC, tmp & 0x7FFFFFFF); + + /* This selects the PLL C clock source for the video upstream channel + * I and J */ + tmp = cx_read(VID_CH_CLK_SEL); + cx_write(VID_CH_CLK_SEL, (tmp & 0x00FFFFFF) | 0x24000000); + + /* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for + * channel A-C + * select 656/VIP DST for downstream Channel A - C */ + tmp = cx_read(VID_CH_MODE_SEL); + /* cx_write( VID_CH_MODE_SEL, tmp | 0x1B0001FF); */ + cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00); + + /* enables 656 port I and J as output */ + tmp = cx_read(CLK_RST); + /* use external ALT_PLL_REF pin as its reference clock instead */ + tmp |= FLD_USE_ALT_PLL_REF; + cx_write(CLK_RST, tmp & ~(FLD_VID_I_CLK_NOE | FLD_VID_J_CLK_NOE)); + + mdelay(100); +} + +int cx25821_sram_channel_setup(struct cx25821_dev *dev, + struct sram_channel *ch, + unsigned int bpl, u32 risc) +{ + unsigned int i, lines; + u32 cdt; + + if (ch->cmds_start == 0) { + cx_write(ch->ptr1_reg, 0); + cx_write(ch->ptr2_reg, 0); + cx_write(ch->cnt2_reg, 0); + cx_write(ch->cnt1_reg, 0); + return 0; + } + + bpl = (bpl + 7) & ~7; /* alignment */ + cdt = ch->cdt; + lines = ch->fifo_size / bpl; + + if (lines > 4) + lines = 4; + + BUG_ON(lines < 2); + + cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); + cx_write(8 + 4, 8); + cx_write(8 + 8, 0); + + /* write CDT */ + for (i = 0; i < lines; i++) { + cx_write(cdt + 16 * i, ch->fifo_start + bpl * i); + cx_write(cdt + 16 * i + 4, 0); + cx_write(cdt + 16 * i + 8, 0); + cx_write(cdt + 16 * i + 12, 0); + } + + /* init the first cdt buffer */ + for (i = 0; i < 128; i++) + cx_write(ch->fifo_start + 4 * i, i); + + /* write CMDS */ + if (ch->jumponly) + cx_write(ch->cmds_start + 0, 8); + else + cx_write(ch->cmds_start + 0, risc); + + cx_write(ch->cmds_start + 4, 0); /* 64 bits 63-32 */ + cx_write(ch->cmds_start + 8, cdt); + cx_write(ch->cmds_start + 12, (lines * 16) >> 3); + cx_write(ch->cmds_start + 16, ch->ctrl_start); + + if (ch->jumponly) + cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2)); + else + cx_write(ch->cmds_start + 20, 64 >> 2); + + for (i = 24; i < 80; i += 4) + cx_write(ch->cmds_start + i, 0); + + /* fill registers */ + cx_write(ch->ptr1_reg, ch->fifo_start); + cx_write(ch->ptr2_reg, cdt); + cx_write(ch->cnt2_reg, (lines * 16) >> 3); + cx_write(ch->cnt1_reg, (bpl >> 3) - 1); + + return 0; +} +EXPORT_SYMBOL(cx25821_sram_channel_setup); + +int cx25821_sram_channel_setup_audio(struct cx25821_dev *dev, + struct sram_channel *ch, + unsigned int bpl, u32 risc) +{ + unsigned int i, lines; + u32 cdt; + + if (ch->cmds_start == 0) { + cx_write(ch->ptr1_reg, 0); + cx_write(ch->ptr2_reg, 0); + cx_write(ch->cnt2_reg, 0); + cx_write(ch->cnt1_reg, 0); + return 0; + } + + bpl = (bpl + 7) & ~7; /* alignment */ + cdt = ch->cdt; + lines = ch->fifo_size / bpl; + + if (lines > 3) + lines = 3; /* for AUDIO */ + + BUG_ON(lines < 2); + + cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); + cx_write(8 + 4, 8); + cx_write(8 + 8, 0); + + /* write CDT */ + for (i = 0; i < lines; i++) { + cx_write(cdt + 16 * i, ch->fifo_start + bpl * i); + cx_write(cdt + 16 * i + 4, 0); + cx_write(cdt + 16 * i + 8, 0); + cx_write(cdt + 16 * i + 12, 0); + } + + /* write CMDS */ + if (ch->jumponly) + cx_write(ch->cmds_start + 0, 8); + else + cx_write(ch->cmds_start + 0, risc); + + cx_write(ch->cmds_start + 4, 0); /* 64 bits 63-32 */ + cx_write(ch->cmds_start + 8, cdt); + cx_write(ch->cmds_start + 12, (lines * 16) >> 3); + cx_write(ch->cmds_start + 16, ch->ctrl_start); + + /* IQ size */ + if (ch->jumponly) + cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2)); + else + cx_write(ch->cmds_start + 20, 64 >> 2); + + /* zero out */ + for (i = 24; i < 80; i += 4) + cx_write(ch->cmds_start + i, 0); + + /* fill registers */ + cx_write(ch->ptr1_reg, ch->fifo_start); + cx_write(ch->ptr2_reg, cdt); + cx_write(ch->cnt2_reg, (lines * 16) >> 3); + cx_write(ch->cnt1_reg, (bpl >> 3) - 1); + + return 0; +} +EXPORT_SYMBOL(cx25821_sram_channel_setup_audio); + +void cx25821_sram_channel_dump(struct cx25821_dev *dev, struct sram_channel *ch) +{ + static char *name[] = { + "init risc lo", + "init risc hi", + "cdt base", + "cdt size", + "iq base", + "iq size", + "risc pc lo", + "risc pc hi", + "iq wr ptr", + "iq rd ptr", + "cdt current", + "pci target lo", + "pci target hi", + "line / byte", + }; + u32 risc; + unsigned int i, j, n; + + pr_warn("%s: %s - dma channel status dump\n", dev->name, ch->name); + for (i = 0; i < ARRAY_SIZE(name); i++) + pr_warn("cmds + 0x%2x: %-15s: 0x%08x\n", + i * 4, name[i], cx_read(ch->cmds_start + 4 * i)); + + j = i * 4; + for (i = 0; i < 4;) { + risc = cx_read(ch->cmds_start + 4 * (i + 14)); + pr_warn("cmds + 0x%2x: risc%d: ", j + i * 4, i); + i += cx25821_risc_decode(risc); + } + + for (i = 0; i < (64 >> 2); i += n) { + risc = cx_read(ch->ctrl_start + 4 * i); + /* No consideration for bits 63-32 */ + + pr_warn("ctrl + 0x%2x (0x%08x): iq %x: ", + i * 4, ch->ctrl_start + 4 * i, i); + n = cx25821_risc_decode(risc); + for (j = 1; j < n; j++) { + risc = cx_read(ch->ctrl_start + 4 * (i + j)); + pr_warn("ctrl + 0x%2x : iq %x: 0x%08x [ arg #%d ]\n", + 4 * (i + j), i + j, risc, j); + } + } + + pr_warn(" : fifo: 0x%08x -> 0x%x\n", + ch->fifo_start, ch->fifo_start + ch->fifo_size); + pr_warn(" : ctrl: 0x%08x -> 0x%x\n", + ch->ctrl_start, ch->ctrl_start + 6 * 16); + pr_warn(" : ptr1_reg: 0x%08x\n", + cx_read(ch->ptr1_reg)); + pr_warn(" : ptr2_reg: 0x%08x\n", + cx_read(ch->ptr2_reg)); + pr_warn(" : cnt1_reg: 0x%08x\n", + cx_read(ch->cnt1_reg)); + pr_warn(" : cnt2_reg: 0x%08x\n", + cx_read(ch->cnt2_reg)); +} +EXPORT_SYMBOL(cx25821_sram_channel_dump); + +void cx25821_sram_channel_dump_audio(struct cx25821_dev *dev, + struct sram_channel *ch) +{ + static const char * const name[] = { + "init risc lo", + "init risc hi", + "cdt base", + "cdt size", + "iq base", + "iq size", + "risc pc lo", + "risc pc hi", + "iq wr ptr", + "iq rd ptr", + "cdt current", + "pci target lo", + "pci target hi", + "line / byte", + }; + + u32 risc, value, tmp; + unsigned int i, j, n; + + pr_info("\n%s: %s - dma Audio channel status dump\n", + dev->name, ch->name); + + for (i = 0; i < ARRAY_SIZE(name); i++) + pr_info("%s: cmds + 0x%2x: %-15s: 0x%08x\n", + dev->name, i * 4, name[i], + cx_read(ch->cmds_start + 4 * i)); + + j = i * 4; + for (i = 0; i < 4;) { + risc = cx_read(ch->cmds_start + 4 * (i + 14)); + pr_warn("cmds + 0x%2x: risc%d: ", j + i * 4, i); + i += cx25821_risc_decode(risc); + } + + for (i = 0; i < (64 >> 2); i += n) { + risc = cx_read(ch->ctrl_start + 4 * i); + /* No consideration for bits 63-32 */ + + pr_warn("ctrl + 0x%2x (0x%08x): iq %x: ", + i * 4, ch->ctrl_start + 4 * i, i); + n = cx25821_risc_decode(risc); + + for (j = 1; j < n; j++) { + risc = cx_read(ch->ctrl_start + 4 * (i + j)); + pr_warn("ctrl + 0x%2x : iq %x: 0x%08x [ arg #%d ]\n", + 4 * (i + j), i + j, risc, j); + } + } + + pr_warn(" : fifo: 0x%08x -> 0x%x\n", + ch->fifo_start, ch->fifo_start + ch->fifo_size); + pr_warn(" : ctrl: 0x%08x -> 0x%x\n", + ch->ctrl_start, ch->ctrl_start + 6 * 16); + pr_warn(" : ptr1_reg: 0x%08x\n", + cx_read(ch->ptr1_reg)); + pr_warn(" : ptr2_reg: 0x%08x\n", + cx_read(ch->ptr2_reg)); + pr_warn(" : cnt1_reg: 0x%08x\n", + cx_read(ch->cnt1_reg)); + pr_warn(" : cnt2_reg: 0x%08x\n", + cx_read(ch->cnt2_reg)); + + for (i = 0; i < 4; i++) { + risc = cx_read(ch->cmds_start + 56 + (i * 4)); + pr_warn("instruction %d = 0x%x\n", i, risc); + } + + /* read data from the first cdt buffer */ + risc = cx_read(AUD_A_CDT); + pr_warn("\nread cdt loc=0x%x\n", risc); + for (i = 0; i < 8; i++) { + n = cx_read(risc + i * 4); + pr_cont("0x%x ", n); + } + pr_cont("\n\n"); + + value = cx_read(CLK_RST); + CX25821_INFO(" CLK_RST = 0x%x\n\n", value); + + value = cx_read(PLL_A_POST_STAT_BIST); + CX25821_INFO(" PLL_A_POST_STAT_BIST = 0x%x\n\n", value); + value = cx_read(PLL_A_INT_FRAC); + CX25821_INFO(" PLL_A_INT_FRAC = 0x%x\n\n", value); + + value = cx_read(PLL_B_POST_STAT_BIST); + CX25821_INFO(" PLL_B_POST_STAT_BIST = 0x%x\n\n", value); + value = cx_read(PLL_B_INT_FRAC); + CX25821_INFO(" PLL_B_INT_FRAC = 0x%x\n\n", value); + + value = cx_read(PLL_C_POST_STAT_BIST); + CX25821_INFO(" PLL_C_POST_STAT_BIST = 0x%x\n\n", value); + value = cx_read(PLL_C_INT_FRAC); + CX25821_INFO(" PLL_C_INT_FRAC = 0x%x\n\n", value); + + value = cx_read(PLL_D_POST_STAT_BIST); + CX25821_INFO(" PLL_D_POST_STAT_BIST = 0x%x\n\n", value); + value = cx_read(PLL_D_INT_FRAC); + CX25821_INFO(" PLL_D_INT_FRAC = 0x%x\n\n", value); + + value = cx25821_i2c_read(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, &tmp); + CX25821_INFO(" AFE_AB_DIAG_CTRL (0x10900090) = 0x%x\n\n", value); +} +EXPORT_SYMBOL(cx25821_sram_channel_dump_audio); + +static void cx25821_shutdown(struct cx25821_dev *dev) +{ + int i; + + /* disable RISC controller */ + cx_write(DEV_CNTRL2, 0); + + /* Disable Video A/B activity */ + for (i = 0; i < VID_CHANNEL_NUM; i++) { + cx_write(dev->channels[i].sram_channels->dma_ctl, 0); + cx_write(dev->channels[i].sram_channels->int_msk, 0); + } + + for (i = VID_UPSTREAM_SRAM_CHANNEL_I; + i <= VID_UPSTREAM_SRAM_CHANNEL_J; i++) { + cx_write(dev->channels[i].sram_channels->dma_ctl, 0); + cx_write(dev->channels[i].sram_channels->int_msk, 0); + } + + /* Disable Audio activity */ + cx_write(AUD_INT_DMA_CTL, 0); + + /* Disable Serial port */ + cx_write(UART_CTL, 0); + + /* Disable Interrupts */ + cx_write(PCI_INT_MSK, 0); + cx_write(AUD_A_INT_MSK, 0); +} + +void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel_select, + u32 format) +{ + if (channel_select <= 7 && channel_select >= 0) { + cx_write(dev->channels[channel_select].sram_channels->pix_frmt, + format); + dev->channels[channel_select].pixel_formats = format; + } +} + +static void cx25821_set_vip_mode(struct cx25821_dev *dev, + struct sram_channel *ch) +{ + cx_write(ch->pix_frmt, PIXEL_FRMT_422); + cx_write(ch->vip_ctl, PIXEL_ENGINE_VIP1); +} + +static void cx25821_initialize(struct cx25821_dev *dev) +{ + int i; + + dprintk(1, "%s()\n", __func__); + + cx25821_shutdown(dev); + cx_write(PCI_INT_STAT, 0xffffffff); + + for (i = 0; i < VID_CHANNEL_NUM; i++) + cx_write(dev->channels[i].sram_channels->int_stat, 0xffffffff); + + cx_write(AUD_A_INT_STAT, 0xffffffff); + cx_write(AUD_B_INT_STAT, 0xffffffff); + cx_write(AUD_C_INT_STAT, 0xffffffff); + cx_write(AUD_D_INT_STAT, 0xffffffff); + cx_write(AUD_E_INT_STAT, 0xffffffff); + + cx_write(CLK_DELAY, cx_read(CLK_DELAY) & 0x80000000); + cx_write(PAD_CTRL, 0x12); /* for I2C */ + cx25821_registers_init(dev); /* init Pecos registers */ + mdelay(100); + + for (i = 0; i < VID_CHANNEL_NUM; i++) { + cx25821_set_vip_mode(dev, dev->channels[i].sram_channels); + cx25821_sram_channel_setup(dev, dev->channels[i].sram_channels, + 1440, 0); + dev->channels[i].pixel_formats = PIXEL_FRMT_422; + dev->channels[i].use_cif_resolution = FALSE; + } + + /* Probably only affect Downstream */ + for (i = VID_UPSTREAM_SRAM_CHANNEL_I; + i <= VID_UPSTREAM_SRAM_CHANNEL_J; i++) { + cx25821_set_vip_mode(dev, dev->channels[i].sram_channels); + } + + cx25821_sram_channel_setup_audio(dev, + dev->channels[SRAM_CH08].sram_channels, 128, 0); + + cx25821_gpio_init(dev); +} + +static int cx25821_get_resources(struct cx25821_dev *dev) +{ + if (request_mem_region(pci_resource_start(dev->pci, 0), + pci_resource_len(dev->pci, 0), dev->name)) + return 0; + + pr_err("%s: can't get MMIO memory @ 0x%llx\n", + dev->name, (unsigned long long)pci_resource_start(dev->pci, 0)); + + return -EBUSY; +} + +static void cx25821_dev_checkrevision(struct cx25821_dev *dev) +{ + dev->hwrevision = cx_read(RDR_CFG2) & 0xff; + + pr_info("%s(): Hardware revision = 0x%02x\n", + __func__, dev->hwrevision); +} + +static void cx25821_iounmap(struct cx25821_dev *dev) +{ + if (dev == NULL) + return; + + /* Releasing IO memory */ + if (dev->lmmio != NULL) { + CX25821_INFO("Releasing lmmio.\n"); + iounmap(dev->lmmio); + dev->lmmio = NULL; + } +} + +static int cx25821_dev_setup(struct cx25821_dev *dev) +{ + int i; + + pr_info("\n***********************************\n"); + pr_info("cx25821 set up\n"); + pr_info("***********************************\n\n"); + + mutex_init(&dev->lock); + + atomic_inc(&dev->refcount); + + dev->nr = ++cx25821_devcount; + sprintf(dev->name, "cx25821[%d]", dev->nr); + + mutex_lock(&cx25821_devlist_mutex); + list_add_tail(&dev->devlist, &cx25821_devlist); + mutex_unlock(&cx25821_devlist_mutex); + + if (dev->pci->device != 0x8210) { + pr_info("%s(): Exiting. Incorrect Hardware device = 0x%02x\n", + __func__, dev->pci->device); + return -1; + } else { + pr_info("Athena Hardware device = 0x%02x\n", dev->pci->device); + } + + /* Apply a sensible clock frequency for the PCIe bridge */ + dev->clk_freq = 28000000; + for (i = 0; i < MAX_VID_CHANNEL_NUM; i++) + dev->channels[i].sram_channels = &cx25821_sram_channels[i]; + + if (dev->nr > 1) + CX25821_INFO("dev->nr > 1!"); + + /* board config */ + dev->board = 1; /* card[dev->nr]; */ + dev->_max_num_decoders = MAX_DECODERS; + + dev->pci_bus = dev->pci->bus->number; + dev->pci_slot = PCI_SLOT(dev->pci->devfn); + dev->pci_irqmask = 0x001f00; + + /* External Master 1 Bus */ + dev->i2c_bus[0].nr = 0; + dev->i2c_bus[0].dev = dev; + dev->i2c_bus[0].reg_stat = I2C1_STAT; + dev->i2c_bus[0].reg_ctrl = I2C1_CTRL; + dev->i2c_bus[0].reg_addr = I2C1_ADDR; + dev->i2c_bus[0].reg_rdata = I2C1_RDATA; + dev->i2c_bus[0].reg_wdata = I2C1_WDATA; + dev->i2c_bus[0].i2c_period = (0x07 << 24); /* 1.95MHz */ + + if (cx25821_get_resources(dev) < 0) { + pr_err("%s: No more PCIe resources for subsystem: %04x:%04x\n", + dev->name, dev->pci->subsystem_vendor, + dev->pci->subsystem_device); + + cx25821_devcount--; + return -EBUSY; + } + + /* PCIe stuff */ + dev->base_io_addr = pci_resource_start(dev->pci, 0); + + if (!dev->base_io_addr) { + CX25821_ERR("No PCI Memory resources, exiting!\n"); + return -ENODEV; + } + + dev->lmmio = ioremap(dev->base_io_addr, pci_resource_len(dev->pci, 0)); + + if (!dev->lmmio) { + CX25821_ERR("ioremap failed, maybe increasing __VMALLOC_RESERVE in page.h\n"); + cx25821_iounmap(dev); + return -ENOMEM; + } + + dev->bmmio = (u8 __iomem *) dev->lmmio; + + pr_info("%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", + dev->name, dev->pci->subsystem_vendor, + dev->pci->subsystem_device, cx25821_boards[dev->board].name, + dev->board, card[dev->nr] == dev->board ? + "insmod option" : "autodetected"); + + /* init hardware */ + cx25821_initialize(dev); + + cx25821_i2c_register(&dev->i2c_bus[0]); +/* cx25821_i2c_register(&dev->i2c_bus[1]); + * cx25821_i2c_register(&dev->i2c_bus[2]); */ + + CX25821_INFO("i2c register! bus->i2c_rc = %d\n", + dev->i2c_bus[0].i2c_rc); + + cx25821_card_setup(dev); + + if (medusa_video_init(dev) < 0) + CX25821_ERR("%s(): Failed to initialize medusa!\n", __func__); + + cx25821_video_register(dev); + + /* register IOCTL device */ + dev->ioctl_dev = cx25821_vdev_init(dev, dev->pci, + &cx25821_videoioctl_template, "video"); + + if (video_register_device + (dev->ioctl_dev, VFL_TYPE_GRABBER, VIDEO_IOCTL_CH) < 0) { + cx25821_videoioctl_unregister(dev); + pr_err("%s(): Failed to register video adapter for IOCTL, so unregistering videoioctl device\n", + __func__); + } + + cx25821_dev_checkrevision(dev); + CX25821_INFO("setup done!\n"); + + return 0; +} + +void cx25821_start_upstream_video_ch1(struct cx25821_dev *dev, + struct upstream_user_struct *up_data) +{ + dev->_isNTSC = !strcmp(dev->vid_stdname, "NTSC") ? 1 : 0; + + dev->tvnorm = !dev->_isNTSC ? V4L2_STD_PAL_BG : V4L2_STD_NTSC_M; + medusa_set_videostandard(dev); + + cx25821_vidupstream_init_ch1(dev, dev->channel_select, + dev->pixel_format); +} + +void cx25821_start_upstream_video_ch2(struct cx25821_dev *dev, + struct upstream_user_struct *up_data) +{ + dev->_isNTSC_ch2 = !strcmp(dev->vid_stdname_ch2, "NTSC") ? 1 : 0; + + dev->tvnorm = !dev->_isNTSC_ch2 ? V4L2_STD_PAL_BG : V4L2_STD_NTSC_M; + medusa_set_videostandard(dev); + + cx25821_vidupstream_init_ch2(dev, dev->channel_select_ch2, + dev->pixel_format_ch2); +} + +void cx25821_start_upstream_audio(struct cx25821_dev *dev, + struct upstream_user_struct *up_data) +{ + cx25821_audio_upstream_init(dev, AUDIO_UPSTREAM_SRAM_CHANNEL_B); +} + +void cx25821_dev_unregister(struct cx25821_dev *dev) +{ + int i; + + if (!dev->base_io_addr) + return; + + cx25821_free_mem_upstream_ch1(dev); + cx25821_free_mem_upstream_ch2(dev); + cx25821_free_mem_upstream_audio(dev); + + release_mem_region(dev->base_io_addr, pci_resource_len(dev->pci, 0)); + + if (!atomic_dec_and_test(&dev->refcount)) + return; + + for (i = 0; i < VID_CHANNEL_NUM; i++) + cx25821_video_unregister(dev, i); + + for (i = VID_UPSTREAM_SRAM_CHANNEL_I; + i <= AUDIO_UPSTREAM_SRAM_CHANNEL_B; i++) { + cx25821_video_unregister(dev, i); + } + + cx25821_videoioctl_unregister(dev); + + cx25821_i2c_unregister(&dev->i2c_bus[0]); + cx25821_iounmap(dev); +} +EXPORT_SYMBOL(cx25821_dev_unregister); + +static __le32 *cx25821_risc_field(__le32 * rp, struct scatterlist *sglist, + unsigned int offset, u32 sync_line, + unsigned int bpl, unsigned int padding, + unsigned int lines) +{ + struct scatterlist *sg; + unsigned int line, todo; + + /* sync instruction */ + if (sync_line != NO_SYNC_LINE) + *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); + + /* scan lines */ + sg = sglist; + for (line = 0; line < lines; line++) { + while (offset && offset >= sg_dma_len(sg)) { + offset -= sg_dma_len(sg); + sg++; + } + if (bpl <= sg_dma_len(sg) - offset) { + /* fits into current chunk */ + *(rp++) = cpu_to_le32(RISC_WRITE | RISC_SOL | RISC_EOL | + bpl); + *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + offset += bpl; + } else { + /* scanline needs to be split */ + todo = bpl; + *(rp++) = cpu_to_le32(RISC_WRITE | RISC_SOL | + (sg_dma_len(sg) - offset)); + *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + todo -= (sg_dma_len(sg) - offset); + offset = 0; + sg++; + while (todo > sg_dma_len(sg)) { + *(rp++) = cpu_to_le32(RISC_WRITE | + sg_dma_len(sg)); + *(rp++) = cpu_to_le32(sg_dma_address(sg)); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + todo -= sg_dma_len(sg); + sg++; + } + *(rp++) = cpu_to_le32(RISC_WRITE | RISC_EOL | todo); + *(rp++) = cpu_to_le32(sg_dma_address(sg)); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + offset += todo; + } + + offset += padding; + } + + return rp; +} + +int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, + struct scatterlist *sglist, unsigned int top_offset, + unsigned int bottom_offset, unsigned int bpl, + unsigned int padding, unsigned int lines) +{ + u32 instructions; + u32 fields; + __le32 *rp; + int rc; + + fields = 0; + if (UNSET != top_offset) + fields++; + if (UNSET != bottom_offset) + fields++; + + /* estimate risc mem: worst case is one write per page border + + one write per scan line + syncs + jump (all 2 dwords). Padding + can cause next bpl to start close to a page border. First DMA + region may be smaller than PAGE_SIZE */ + /* write and jump need and extra dword */ + instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + + lines); + instructions += 2; + rc = btcx_riscmem_alloc(pci, risc, instructions * 12); + + if (rc < 0) + return rc; + + /* write risc instructions */ + rp = risc->cpu; + + if (UNSET != top_offset) { + rp = cx25821_risc_field(rp, sglist, top_offset, 0, bpl, padding, + lines); + } + + if (UNSET != bottom_offset) { + rp = cx25821_risc_field(rp, sglist, bottom_offset, 0x200, bpl, + padding, lines); + } + + /* save pointer to jmp instruction address */ + risc->jmp = rp; + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); + + return 0; +} + +static __le32 *cx25821_risc_field_audio(__le32 * rp, struct scatterlist *sglist, + unsigned int offset, u32 sync_line, + unsigned int bpl, unsigned int padding, + unsigned int lines, unsigned int lpi) +{ + struct scatterlist *sg; + unsigned int line, todo, sol; + + /* sync instruction */ + if (sync_line != NO_SYNC_LINE) + *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); + + /* scan lines */ + sg = sglist; + for (line = 0; line < lines; line++) { + while (offset && offset >= sg_dma_len(sg)) { + offset -= sg_dma_len(sg); + sg++; + } + + if (lpi && line > 0 && !(line % lpi)) + sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC; + else + sol = RISC_SOL; + + if (bpl <= sg_dma_len(sg) - offset) { + /* fits into current chunk */ + *(rp++) = cpu_to_le32(RISC_WRITE | sol | RISC_EOL | + bpl); + *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + offset += bpl; + } else { + /* scanline needs to be split */ + todo = bpl; + *(rp++) = cpu_to_le32(RISC_WRITE | sol | + (sg_dma_len(sg) - offset)); + *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + todo -= (sg_dma_len(sg) - offset); + offset = 0; + sg++; + while (todo > sg_dma_len(sg)) { + *(rp++) = cpu_to_le32(RISC_WRITE | + sg_dma_len(sg)); + *(rp++) = cpu_to_le32(sg_dma_address(sg)); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + todo -= sg_dma_len(sg); + sg++; + } + *(rp++) = cpu_to_le32(RISC_WRITE | RISC_EOL | todo); + *(rp++) = cpu_to_le32(sg_dma_address(sg)); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + offset += todo; + } + offset += padding; + } + + return rp; +} + +int cx25821_risc_databuffer_audio(struct pci_dev *pci, + struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int bpl, + unsigned int lines, unsigned int lpi) +{ + u32 instructions; + __le32 *rp; + int rc; + + /* estimate risc mem: worst case is one write per page border + + one write per scan line + syncs + jump (all 2 dwords). Here + there is no padding and no sync. First DMA region may be smaller + than PAGE_SIZE */ + /* Jump and write need an extra dword */ + instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; + instructions += 1; + + rc = btcx_riscmem_alloc(pci, risc, instructions * 12); + if (rc < 0) + return rc; + + /* write risc instructions */ + rp = risc->cpu; + rp = cx25821_risc_field_audio(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, + lines, lpi); + + /* save pointer to jmp instruction address */ + risc->jmp = rp; + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); + return 0; +} +EXPORT_SYMBOL(cx25821_risc_databuffer_audio); + +int cx25821_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, + u32 reg, u32 mask, u32 value) +{ + __le32 *rp; + int rc; + + rc = btcx_riscmem_alloc(pci, risc, 4 * 16); + + if (rc < 0) + return rc; + + /* write risc instructions */ + rp = risc->cpu; + + *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ1); + *(rp++) = cpu_to_le32(reg); + *(rp++) = cpu_to_le32(value); + *(rp++) = cpu_to_le32(mask); + *(rp++) = cpu_to_le32(RISC_JUMP); + *(rp++) = cpu_to_le32(risc->dma); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + return 0; +} + +void cx25821_free_buffer(struct videobuf_queue *q, struct cx25821_buffer *buf) +{ + struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); + + BUG_ON(in_interrupt()); + videobuf_waiton(q, &buf->vb, 0, 0); + videobuf_dma_unmap(q->dev, dma); + videobuf_dma_free(dma); + btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); + buf->vb.state = VIDEOBUF_NEEDS_INIT; +} + +static irqreturn_t cx25821_irq(int irq, void *dev_id) +{ + struct cx25821_dev *dev = dev_id; + u32 pci_status; + u32 vid_status; + int i, handled = 0; + u32 mask[8] = { 1, 2, 4, 8, 16, 32, 64, 128 }; + + pci_status = cx_read(PCI_INT_STAT); + + if (pci_status == 0) + goto out; + + for (i = 0; i < VID_CHANNEL_NUM; i++) { + if (pci_status & mask[i]) { + vid_status = cx_read(dev->channels[i]. + sram_channels->int_stat); + + if (vid_status) + handled += cx25821_video_irq(dev, i, + vid_status); + + cx_write(PCI_INT_STAT, mask[i]); + } + } + +out: + return IRQ_RETVAL(handled); +} + +void cx25821_print_irqbits(char *name, char *tag, char **strings, + int len, u32 bits, u32 mask) +{ + unsigned int i; + + printk(KERN_DEBUG pr_fmt("%s: %s [0x%x]"), name, tag, bits); + + for (i = 0; i < len; i++) { + if (!(bits & (1 << i))) + continue; + if (strings[i]) + pr_cont(" %s", strings[i]); + else + pr_cont(" %d", i); + if (!(mask & (1 << i))) + continue; + pr_cont("*"); + } + pr_cont("\n"); +} +EXPORT_SYMBOL(cx25821_print_irqbits); + +struct cx25821_dev *cx25821_dev_get(struct pci_dev *pci) +{ + struct cx25821_dev *dev = pci_get_drvdata(pci); + return dev; +} +EXPORT_SYMBOL(cx25821_dev_get); + +static int __devinit cx25821_initdev(struct pci_dev *pci_dev, + const struct pci_device_id *pci_id) +{ + struct cx25821_dev *dev; + int err = 0; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (NULL == dev) + return -ENOMEM; + + err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev); + if (err < 0) + goto fail_free; + + /* pci init */ + dev->pci = pci_dev; + if (pci_enable_device(pci_dev)) { + err = -EIO; + + pr_info("pci enable failed!\n"); + + goto fail_unregister_device; + } + + pr_info("Athena pci enable !\n"); + + err = cx25821_dev_setup(dev); + if (err) { + if (err == -EBUSY) + goto fail_unregister_device; + else + goto fail_unregister_pci; + } + + /* print pci info */ + pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); + pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); + pr_info("%s/0: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n", + dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq, + dev->pci_lat, (unsigned long long)dev->base_io_addr); + + pci_set_master(pci_dev); + if (!pci_dma_supported(pci_dev, 0xffffffff)) { + pr_err("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name); + err = -EIO; + goto fail_irq; + } + + err = request_irq(pci_dev->irq, cx25821_irq, + IRQF_SHARED, dev->name, dev); + + if (err < 0) { + pr_err("%s: can't get IRQ %d\n", dev->name, pci_dev->irq); + goto fail_irq; + } + + return 0; + +fail_irq: + pr_info("cx25821_initdev() can't get IRQ !\n"); + cx25821_dev_unregister(dev); + +fail_unregister_pci: + pci_disable_device(pci_dev); +fail_unregister_device: + v4l2_device_unregister(&dev->v4l2_dev); + +fail_free: + kfree(dev); + return err; +} + +static void __devexit cx25821_finidev(struct pci_dev *pci_dev) +{ + struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct cx25821_dev *dev = get_cx25821(v4l2_dev); + + cx25821_shutdown(dev); + pci_disable_device(pci_dev); + + /* unregister stuff */ + if (pci_dev->irq) + free_irq(pci_dev->irq, dev); + + mutex_lock(&cx25821_devlist_mutex); + list_del(&dev->devlist); + mutex_unlock(&cx25821_devlist_mutex); + + cx25821_dev_unregister(dev); + v4l2_device_unregister(v4l2_dev); + kfree(dev); +} + +static DEFINE_PCI_DEVICE_TABLE(cx25821_pci_tbl) = { + { + /* CX25821 Athena */ + .vendor = 0x14f1, + .device = 0x8210, + .subvendor = 0x14f1, + .subdevice = 0x0920, + }, { + /* CX25821 No Brand */ + .vendor = 0x14f1, + .device = 0x8210, + .subvendor = 0x0000, + .subdevice = 0x0000, + }, { + /* --- end of list --- */ + } +}; + +MODULE_DEVICE_TABLE(pci, cx25821_pci_tbl); + +static struct pci_driver cx25821_pci_driver = { + .name = "cx25821", + .id_table = cx25821_pci_tbl, + .probe = cx25821_initdev, + .remove = __devexit_p(cx25821_finidev), + /* TODO */ + .suspend = NULL, + .resume = NULL, +}; + +static int __init cx25821_init(void) +{ + pr_info("driver version %d.%d.%d loaded\n", + (CX25821_VERSION_CODE >> 16) & 0xff, + (CX25821_VERSION_CODE >> 8) & 0xff, + CX25821_VERSION_CODE & 0xff); + return pci_register_driver(&cx25821_pci_driver); +} + +static void __exit cx25821_fini(void) +{ + pci_unregister_driver(&cx25821_pci_driver); +} + +module_init(cx25821_init); +module_exit(cx25821_fini); diff --git a/drivers/media/pci/cx25821/cx25821-gpio.c b/drivers/media/pci/cx25821/cx25821-gpio.c new file mode 100644 index 0000000..29e43b0 --- /dev/null +++ b/drivers/media/pci/cx25821/cx25821-gpio.c @@ -0,0 +1,98 @@ +/* + * Driver for the Conexant CX25821 PCIe bridge + * + * Copyright (C) 2009 Conexant Systems Inc. + * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "cx25821.h" + +/********************* GPIO stuffs *********************/ +void cx25821_set_gpiopin_direction(struct cx25821_dev *dev, + int pin_number, int pin_logic_value) +{ + int bit = pin_number; + u32 gpio_oe_reg = GPIO_LO_OE; + u32 gpio_register = 0; + u32 value = 0; + + /* Check for valid pinNumber */ + if (pin_number >= 47) + return; + + if (pin_number > 31) { + bit = pin_number - 31; + gpio_oe_reg = GPIO_HI_OE; + } + /* Here we will make sure that the GPIOs 0 and 1 are output. keep the + * rest as is */ + gpio_register = cx_read(gpio_oe_reg); + + if (pin_logic_value == 1) + value = gpio_register | Set_GPIO_Bit(bit); + else + value = gpio_register & Clear_GPIO_Bit(bit); + + cx_write(gpio_oe_reg, value); +} +EXPORT_SYMBOL(cx25821_set_gpiopin_direction); + +static void cx25821_set_gpiopin_logicvalue(struct cx25821_dev *dev, + int pin_number, int pin_logic_value) +{ + int bit = pin_number; + u32 gpio_reg = GPIO_LO; + u32 value = 0; + + /* Check for valid pinNumber */ + if (pin_number >= 47) + return; + + /* change to output direction */ + cx25821_set_gpiopin_direction(dev, pin_number, 0); + + if (pin_number > 31) { + bit = pin_number - 31; + gpio_reg = GPIO_HI; + } + + value = cx_read(gpio_reg); + + if (pin_logic_value == 0) + value &= Clear_GPIO_Bit(bit); + else + value |= Set_GPIO_Bit(bit); + + cx_write(gpio_reg, value); +} + +void cx25821_gpio_init(struct cx25821_dev *dev) +{ + if (dev == NULL) + return; + + switch (dev->board) { + case CX25821_BOARD_CONEXANT_ATHENA10: + default: + /* set GPIO 5 to select the path for Medusa/Athena */ + cx25821_set_gpiopin_logicvalue(dev, 5, 1); + mdelay(20); + break; + } + +} diff --git a/drivers/media/pci/cx25821/cx25821-i2c.c b/drivers/media/pci/cx25821/cx25821-i2c.c new file mode 100644 index 0000000..9844549 --- /dev/null +++ b/drivers/media/pci/cx25821/cx25821-i2c.c @@ -0,0 +1,416 @@ +/* + * Driver for the Conexant CX25821 PCIe bridge + * + * Copyright (C) 2009 Conexant Systems Inc. + * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> + * Based on Steven Toth <stoth@linuxtv.org> cx23885 driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include "cx25821.h" +#include <linux/i2c.h> + +static unsigned int i2c_debug; +module_param(i2c_debug, int, 0644); +MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); + +static unsigned int i2c_scan; +module_param(i2c_scan, int, 0444); +MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); + +#define dprintk(level, fmt, arg...) \ +do { \ + if (i2c_debug >= level) \ + printk(KERN_DEBUG "%s/0: " fmt, dev->name, ##arg); \ +} while (0) + +#define I2C_WAIT_DELAY 32 +#define I2C_WAIT_RETRY 64 + +#define I2C_EXTEND (1 << 3) +#define I2C_NOSTOP (1 << 4) + +static inline int i2c_slave_did_ack(struct i2c_adapter *i2c_adap) +{ + struct cx25821_i2c *bus = i2c_adap->algo_data; + struct cx25821_dev *dev = bus->dev; + return cx_read(bus->reg_stat) & 0x01; +} + +static inline int i2c_is_busy(struct i2c_adapter *i2c_adap) +{ + struct cx25821_i2c *bus = i2c_adap->algo_data; + struct cx25821_dev *dev = bus->dev; + return cx_read(bus->reg_stat) & 0x02 ? 1 : 0; +} + +static int i2c_wait_done(struct i2c_adapter *i2c_adap) +{ + int count; + + for (count = 0; count < I2C_WAIT_RETRY; count++) { + if (!i2c_is_busy(i2c_adap)) + break; + udelay(I2C_WAIT_DELAY); + } + + if (I2C_WAIT_RETRY == count) + return 0; + + return 1; +} + +static int i2c_sendbytes(struct i2c_adapter *i2c_adap, + const struct i2c_msg *msg, int joined_rlen) +{ + struct cx25821_i2c *bus = i2c_adap->algo_data; + struct cx25821_dev *dev = bus->dev; + u32 wdata, addr, ctrl; + int retval, cnt; + + if (joined_rlen) + dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n", __func__, + msg->len, joined_rlen); + else + dprintk(1, "%s(msg->len=%d)\n", __func__, msg->len); + + /* Deal with i2c probe functions with zero payload */ + if (msg->len == 0) { + cx_write(bus->reg_addr, msg->addr << 25); + cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2)); + + if (!i2c_wait_done(i2c_adap)) + return -EIO; + + if (!i2c_slave_did_ack(i2c_adap)) + return -EIO; + + dprintk(1, "%s(): returns 0\n", __func__); + return 0; + } + + /* dev, reg + first byte */ + addr = (msg->addr << 25) | msg->buf[0]; + wdata = msg->buf[0]; + + ctrl = bus->i2c_period | (1 << 12) | (1 << 2); + + if (msg->len > 1) + ctrl |= I2C_NOSTOP | I2C_EXTEND; + else if (joined_rlen) + ctrl |= I2C_NOSTOP; + + cx_write(bus->reg_addr, addr); + cx_write(bus->reg_wdata, wdata); + cx_write(bus->reg_ctrl, ctrl); + + retval = i2c_wait_done(i2c_adap); + if (retval < 0) + goto err; + + if (retval == 0) + goto eio; + + if (i2c_debug) { + if (!(ctrl & I2C_NOSTOP)) + printk(" >\n"); + } + + for (cnt = 1; cnt < msg->len; cnt++) { + /* following bytes */ + wdata = msg->buf[cnt]; + ctrl = bus->i2c_period | (1 << 12) | (1 << 2); + + if (cnt < msg->len - 1) + ctrl |= I2C_NOSTOP | I2C_EXTEND; + else if (joined_rlen) + ctrl |= I2C_NOSTOP; + + cx_write(bus->reg_addr, addr); + cx_write(bus->reg_wdata, wdata); + cx_write(bus->reg_ctrl, ctrl); + + retval = i2c_wait_done(i2c_adap); + if (retval < 0) + goto err; + + if (retval == 0) + goto eio; + + if (i2c_debug) { + dprintk(1, " %02x", msg->buf[cnt]); + if (!(ctrl & I2C_NOSTOP)) + dprintk(1, " >\n"); + } + } + + return msg->len; + +eio: + retval = -EIO; +err: + if (i2c_debug) + pr_err(" ERR: %d\n", retval); + return retval; +} + +static int i2c_readbytes(struct i2c_adapter *i2c_adap, + const struct i2c_msg *msg, int joined) +{ + struct cx25821_i2c *bus = i2c_adap->algo_data; + struct cx25821_dev *dev = bus->dev; + u32 ctrl, cnt; + int retval; + + if (i2c_debug && !joined) + dprintk(1, "6-%s(msg->len=%d)\n", __func__, msg->len); + + /* Deal with i2c probe functions with zero payload */ + if (msg->len == 0) { + cx_write(bus->reg_addr, msg->addr << 25); + cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2) | 1); + if (!i2c_wait_done(i2c_adap)) + return -EIO; + if (!i2c_slave_did_ack(i2c_adap)) + return -EIO; + + dprintk(1, "%s(): returns 0\n", __func__); + return 0; + } + + if (i2c_debug) { + if (joined) + dprintk(1, " R"); + else + dprintk(1, " <R %02x", (msg->addr << 1) + 1); + } + + for (cnt = 0; cnt < msg->len; cnt++) { + + ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1; + + if (cnt < msg->len - 1) + ctrl |= I2C_NOSTOP | I2C_EXTEND; + + cx_write(bus->reg_addr, msg->addr << 25); + cx_write(bus->reg_ctrl, ctrl); + + retval = i2c_wait_done(i2c_adap); + if (retval < 0) + goto err; + if (retval == 0) + goto eio; + msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff; + + if (i2c_debug) { + dprintk(1, " %02x", msg->buf[cnt]); + if (!(ctrl & I2C_NOSTOP)) + dprintk(1, " >\n"); + } + } + + return msg->len; +eio: + retval = -EIO; +err: + if (i2c_debug) + pr_err(" ERR: %d\n", retval); + return retval; +} + +static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) +{ + struct cx25821_i2c *bus = i2c_adap->algo_data; + struct cx25821_dev *dev = bus->dev; + int i, retval = 0; + + dprintk(1, "%s(num = %d)\n", __func__, num); + + for (i = 0; i < num; i++) { + dprintk(1, "%s(num = %d) addr = 0x%02x len = 0x%x\n", + __func__, num, msgs[i].addr, msgs[i].len); + + if (msgs[i].flags & I2C_M_RD) { + /* read */ + retval = i2c_readbytes(i2c_adap, &msgs[i], 0); + } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && + msgs[i].addr == msgs[i + 1].addr) { + /* write then read from same address */ + retval = i2c_sendbytes(i2c_adap, &msgs[i], + msgs[i + 1].len); + + if (retval < 0) + goto err; + i++; + retval = i2c_readbytes(i2c_adap, &msgs[i], 1); + } else { + /* write */ + retval = i2c_sendbytes(i2c_adap, &msgs[i], 0); + } + + if (retval < 0) + goto err; + } + return num; + +err: + return retval; +} + + +static u32 cx25821_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA; +} + +static struct i2c_algorithm cx25821_i2c_algo_template = { + .master_xfer = i2c_xfer, + .functionality = cx25821_functionality, +#ifdef NEED_ALGO_CONTROL + .algo_control = dummy_algo_control, +#endif +}; + +static struct i2c_adapter cx25821_i2c_adap_template = { + .name = "cx25821", + .owner = THIS_MODULE, + .algo = &cx25821_i2c_algo_template, +}; + +static struct i2c_client cx25821_i2c_client_template = { + .name = "cx25821 internal", +}; + +/* init + register i2c adapter */ +int cx25821_i2c_register(struct cx25821_i2c *bus) +{ + struct cx25821_dev *dev = bus->dev; + + dprintk(1, "%s(bus = %d)\n", __func__, bus->nr); + + bus->i2c_adap = cx25821_i2c_adap_template; + bus->i2c_client = cx25821_i2c_client_template; + bus->i2c_adap.dev.parent = &dev->pci->dev; + + strlcpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name)); + + bus->i2c_adap.algo_data = bus; + i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev); + i2c_add_adapter(&bus->i2c_adap); + + bus->i2c_client.adapter = &bus->i2c_adap; + + /* set up the I2c */ + bus->i2c_client.addr = (0x88 >> 1); + + return bus->i2c_rc; +} + +int cx25821_i2c_unregister(struct cx25821_i2c *bus) +{ + i2c_del_adapter(&bus->i2c_adap); + return 0; +} + +void cx25821_av_clk(struct cx25821_dev *dev, int enable) +{ + /* write 0 to bus 2 addr 0x144 via i2x_xfer() */ + char buffer[3]; + struct i2c_msg msg; + dprintk(1, "%s(enabled = %d)\n", __func__, enable); + + /* Register 0x144 */ + buffer[0] = 0x01; + buffer[1] = 0x44; + if (enable == 1) + buffer[2] = 0x05; + else + buffer[2] = 0x00; + + msg.addr = 0x44; + msg.flags = I2C_M_TEN; + msg.len = 3; + msg.buf = buffer; + + i2c_xfer(&dev->i2c_bus[0].i2c_adap, &msg, 1); +} + +int cx25821_i2c_read(struct cx25821_i2c *bus, u16 reg_addr, int *value) +{ + struct i2c_client *client = &bus->i2c_client; + int v = 0; + u8 addr[2] = { 0, 0 }; + u8 buf[4] = { 0, 0, 0, 0 }; + + struct i2c_msg msgs[2] = { + { + .addr = client->addr, + .flags = 0, + .len = 2, + .buf = addr, + }, { + .addr = client->addr, + .flags = I2C_M_RD, + .len = 4, + .buf = buf, + } + }; + + addr[0] = (reg_addr >> 8); + addr[1] = (reg_addr & 0xff); + msgs[0].addr = 0x44; + msgs[1].addr = 0x44; + + i2c_xfer(client->adapter, msgs, 2); + + v = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + *value = v; + + return v; +} + +int cx25821_i2c_write(struct cx25821_i2c *bus, u16 reg_addr, int value) +{ + struct i2c_client *client = &bus->i2c_client; + int retval = 0; + u8 buf[6] = { 0, 0, 0, 0, 0, 0 }; + + struct i2c_msg msgs[1] = { + { + .addr = client->addr, + .flags = 0, + .len = 6, + .buf = buf, + } + }; + + buf[0] = reg_addr >> 8; + buf[1] = reg_addr & 0xff; + buf[5] = (value >> 24) & 0xff; + buf[4] = (value >> 16) & 0xff; + buf[3] = (value >> 8) & 0xff; + buf[2] = value & 0xff; + client->flags = 0; + msgs[0].addr = 0x44; + + retval = i2c_xfer(client->adapter, msgs, 1); + + return retval; +} diff --git a/drivers/media/pci/cx25821/cx25821-medusa-defines.h b/drivers/media/pci/cx25821/cx25821-medusa-defines.h new file mode 100644 index 0000000..7a9e647 --- /dev/null +++ b/drivers/media/pci/cx25821/cx25821-medusa-defines.h @@ -0,0 +1,42 @@ +/* + * Driver for the Conexant CX25821 PCIe bridge + * + * Copyright (C) 2009 Conexant Systems Inc. + * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _MEDUSA_DEF_H_ +#define _MEDUSA_DEF_H_ + +/* Video decoder that we supported */ +#define VDEC_A 0 +#define VDEC_B 1 +#define VDEC_C 2 +#define VDEC_D 3 +#define VDEC_E 4 +#define VDEC_F 5 +#define VDEC_G 6 +#define VDEC_H 7 + +/* end of display sequence */ +#define END_OF_SEQ 0xF; + +/* registry string size */ +#define MAX_REGISTRY_SZ 40; + +#endif diff --git a/drivers/media/pci/cx25821/cx25821-medusa-reg.h b/drivers/media/pci/cx25821/cx25821-medusa-reg.h new file mode 100644 index 0000000..c98ac94 --- /dev/null +++ b/drivers/media/pci/cx25821/cx25821-medusa-reg.h @@ -0,0 +1,455 @@ +/* + * Driver for the Conexant CX25821 PCIe bridge + * + * Copyright (C) 2009 Conexant Systems Inc. + * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __MEDUSA_REGISTERS__ +#define __MEDUSA_REGISTERS__ + +/* Serial Slave Registers */ +#define HOST_REGISTER1 0x0000 +#define HOST_REGISTER2 0x0001 + +/* Chip Configuration Registers */ +#define CHIP_CTRL 0x0100 +#define AFE_AB_CTRL 0x0104 +#define AFE_CD_CTRL 0x0108 +#define AFE_EF_CTRL 0x010C +#define AFE_GH_CTRL 0x0110 +#define DENC_AB_CTRL 0x0114 +#define BYP_AB_CTRL 0x0118 +#define MON_A_CTRL 0x011C +#define DISP_SEQ_A 0x0120 +#define DISP_SEQ_B 0x0124 +#define DISP_AB_CNT 0x0128 +#define DISP_CD_CNT 0x012C +#define DISP_EF_CNT 0x0130 +#define DISP_GH_CNT 0x0134 +#define DISP_IJ_CNT 0x0138 +#define PIN_OE_CTRL 0x013C +#define PIN_SPD_CTRL 0x0140 +#define PIN_SPD_CTRL2 0x0144 +#define IRQ_STAT_CTRL 0x0148 +#define POWER_CTRL_AB 0x014C +#define POWER_CTRL_CD 0x0150 +#define POWER_CTRL_EF 0x0154 +#define POWER_CTRL_GH 0x0158 +#define TUNE_CTRL 0x015C +#define BIAS_CTRL 0x0160 +#define AFE_AB_DIAG_CTRL 0x0164 +#define AFE_CD_DIAG_CTRL 0x0168 +#define AFE_EF_DIAG_CTRL 0x016C +#define AFE_GH_DIAG_CTRL 0x0170 +#define PLL_AB_DIAG_CTRL 0x0174 +#define PLL_CD_DIAG_CTRL 0x0178 +#define PLL_EF_DIAG_CTRL 0x017C +#define PLL_GH_DIAG_CTRL 0x0180 +#define TEST_CTRL 0x0184 +#define BIST_STAT 0x0188 +#define BIST_STAT2 0x018C +#define BIST_VID_PLL_AB_STAT 0x0190 +#define BIST_VID_PLL_CD_STAT 0x0194 +#define BIST_VID_PLL_EF_STAT 0x0198 +#define BIST_VID_PLL_GH_STAT 0x019C +#define DLL_DIAG_CTRL 0x01A0 +#define DEV_CH_ID_CTRL 0x01A4 +#define ABIST_CTRL_STATUS 0x01A8 +#define ABIST_FREQ 0x01AC +#define ABIST_GOERT_SHIFT 0x01B0 +#define ABIST_COEF12 0x01B4 +#define ABIST_COEF34 0x01B8 +#define ABIST_COEF56 0x01BC +#define ABIST_COEF7_SNR 0x01C0 +#define ABIST_ADC_CAL 0x01C4 +#define ABIST_BIN1_VGA0 0x01C8 +#define ABIST_BIN2_VGA1 0x01CC +#define ABIST_BIN3_VGA2 0x01D0 +#define ABIST_BIN4_VGA3 0x01D4 +#define ABIST_BIN5_VGA4 0x01D8 +#define ABIST_BIN6_VGA5 0x01DC +#define ABIST_BIN7_VGA6 0x0x1E0 +#define ABIST_CLAMP_A 0x0x1E4 +#define ABIST_CLAMP_B 0x0x1E8 +#define ABIST_CLAMP_C 0x01EC +#define ABIST_CLAMP_D 0x01F0 +#define ABIST_CLAMP_E 0x01F4 +#define ABIST_CLAMP_F 0x01F8 + +/* Digital Video Encoder A Registers */ +#define DENC_A_REG_1 0x0200 +#define DENC_A_REG_2 0x0204 +#define DENC_A_REG_3 0x0208 +#define DENC_A_REG_4 0x020C +#define DENC_A_REG_5 0x0210 +#define DENC_A_REG_6 0x0214 +#define DENC_A_REG_7 0x0218 +#define DENC_A_REG_8 0x021C + +/* Digital Video Encoder B Registers */ +#define DENC_B_REG_1 0x0300 +#define DENC_B_REG_2 0x0304 +#define DENC_B_REG_3 0x0308 +#define DENC_B_REG_4 0x030C +#define DENC_B_REG_5 0x0310 +#define DENC_B_REG_6 0x0314 +#define DENC_B_REG_7 0x0318 +#define DENC_B_REG_8 0x031C + +/* Video Decoder A Registers */ +#define MODE_CTRL 0x1000 +#define OUT_CTRL1 0x1004 +#define OUT_CTRL_NS 0x1008 +#define GEN_STAT 0x100C +#define INT_STAT_MASK 0x1010 +#define LUMA_CTRL 0x1014 +#define CHROMA_CTRL 0x1018 +#define CRUSH_CTRL 0x101C +#define HORIZ_TIM_CTRL 0x1020 +#define VERT_TIM_CTRL 0x1024 +#define MISC_TIM_CTRL 0x1028 +#define FIELD_COUNT 0x102C +#define HSCALE_CTRL 0x1030 +#define VSCALE_CTRL 0x1034 +#define MAN_VGA_CTRL 0x1038 +#define MAN_AGC_CTRL 0x103C +#define DFE_CTRL1 0x1040 +#define DFE_CTRL2 0x1044 +#define DFE_CTRL3 0x1048 +#define PLL_CTRL 0x104C +#define PLL_CTRL_FAST 0x1050 +#define HTL_CTRL 0x1054 +#define SRC_CFG 0x1058 +#define SC_STEP_SIZE 0x105C +#define SC_CONVERGE_CTRL 0x1060 +#define SC_LOOP_CTRL 0x1064 +#define COMB_2D_HFS_CFG 0x1068 +#define COMB_2D_HFD_CFG 0x106C +#define COMB_2D_LF_CFG 0x1070 +#define COMB_2D_BLEND 0x1074 +#define COMB_MISC_CTRL 0x1078 +#define COMB_FLAT_THRESH_CTRL 0x107C +#define COMB_TEST 0x1080 +#define BP_MISC_CTRL 0x1084 +#define VCR_DET_CTRL 0x1088 +#define NOISE_DET_CTRL 0x108C +#define COMB_FLAT_NOISE_CTRL 0x1090 +#define VERSION 0x11F8 +#define SOFT_RST_CTRL 0x11FC + +/* Video Decoder B Registers */ +#define VDEC_B_MODE_CTRL 0x1200 +#define VDEC_B_OUT_CTRL1 0x1204 +#define VDEC_B_OUT_CTRL_NS 0x1208 +#define VDEC_B_GEN_STAT 0x120C +#define VDEC_B_INT_STAT_MASK 0x1210 +#define VDEC_B_LUMA_CTRL 0x1214 +#define VDEC_B_CHROMA_CTRL 0x1218 +#define VDEC_B_CRUSH_CTRL 0x121C +#define VDEC_B_HORIZ_TIM_CTRL 0x1220 +#define VDEC_B_VERT_TIM_CTRL 0x1224 +#define VDEC_B_MISC_TIM_CTRL 0x1228 +#define VDEC_B_FIELD_COUNT 0x122C +#define VDEC_B_HSCALE_CTRL 0x1230 +#define VDEC_B_VSCALE_CTRL 0x1234 +#define VDEC_B_MAN_VGA_CTRL 0x1238 +#define VDEC_B_MAN_AGC_CTRL 0x123C +#define VDEC_B_DFE_CTRL1 0x1240 +#define VDEC_B_DFE_CTRL2 0x1244 +#define VDEC_B_DFE_CTRL3 0x1248 +#define VDEC_B_PLL_CTRL 0x124C +#define VDEC_B_PLL_CTRL_FAST 0x1250 +#define VDEC_B_HTL_CTRL 0x1254 +#define VDEC_B_SRC_CFG 0x1258 +#define VDEC_B_SC_STEP_SIZE 0x125C +#define VDEC_B_SC_CONVERGE_CTRL 0x1260 +#define VDEC_B_SC_LOOP_CTRL 0x1264 +#define VDEC_B_COMB_2D_HFS_CFG 0x1268 +#define VDEC_B_COMB_2D_HFD_CFG 0x126C +#define VDEC_B_COMB_2D_LF_CFG 0x1270 +#define VDEC_B_COMB_2D_BLEND 0x1274 +#define VDEC_B_COMB_MISC_CTRL 0x1278 +#define VDEC_B_COMB_FLAT_THRESH_CTRL 0x127C +#define VDEC_B_COMB_TEST 0x1280 +#define VDEC_B_BP_MISC_CTRL 0x1284 +#define VDEC_B_VCR_DET_CTRL 0x1288 +#define VDEC_B_NOISE_DET_CTRL 0x128C +#define VDEC_B_COMB_FLAT_NOISE_CTRL 0x1290 +#define VDEC_B_VERSION 0x13F8 +#define VDEC_B_SOFT_RST_CTRL 0x13FC + +/* Video Decoder C Registers */ +#define VDEC_C_MODE_CTRL 0x1400 +#define VDEC_C_OUT_CTRL1 0x1404 +#define VDEC_C_OUT_CTRL_NS 0x1408 +#define VDEC_C_GEN_STAT 0x140C +#define VDEC_C_INT_STAT_MASK 0x1410 +#define VDEC_C_LUMA_CTRL 0x1414 +#define VDEC_C_CHROMA_CTRL 0x1418 +#define VDEC_C_CRUSH_CTRL 0x141C +#define VDEC_C_HORIZ_TIM_CTRL 0x1420 +#define VDEC_C_VERT_TIM_CTRL 0x1424 +#define VDEC_C_MISC_TIM_CTRL 0x1428 +#define VDEC_C_FIELD_COUNT 0x142C +#define VDEC_C_HSCALE_CTRL 0x1430 +#define VDEC_C_VSCALE_CTRL 0x1434 +#define VDEC_C_MAN_VGA_CTRL 0x1438 +#define VDEC_C_MAN_AGC_CTRL 0x143C +#define VDEC_C_DFE_CTRL1 0x1440 +#define VDEC_C_DFE_CTRL2 0x1444 +#define VDEC_C_DFE_CTRL3 0x1448 +#define VDEC_C_PLL_CTRL 0x144C +#define VDEC_C_PLL_CTRL_FAST 0x1450 +#define VDEC_C_HTL_CTRL 0x1454 +#define VDEC_C_SRC_CFG 0x1458 +#define VDEC_C_SC_STEP_SIZE 0x145C +#define VDEC_C_SC_CONVERGE_CTRL 0x1460 +#define VDEC_C_SC_LOOP_CTRL 0x1464 +#define VDEC_C_COMB_2D_HFS_CFG 0x1468 +#define VDEC_C_COMB_2D_HFD_CFG 0x146C +#define VDEC_C_COMB_2D_LF_CFG 0x1470 +#define VDEC_C_COMB_2D_BLEND 0x1474 +#define VDEC_C_COMB_MISC_CTRL 0x1478 +#define VDEC_C_COMB_FLAT_THRESH_CTRL 0x147C +#define VDEC_C_COMB_TEST 0x1480 +#define VDEC_C_BP_MISC_CTRL 0x1484 +#define VDEC_C_VCR_DET_CTRL 0x1488 +#define VDEC_C_NOISE_DET_CTRL 0x148C +#define VDEC_C_COMB_FLAT_NOISE_CTRL 0x1490 +#define VDEC_C_VERSION 0x15F8 +#define VDEC_C_SOFT_RST_CTRL 0x15FC + +/* Video Decoder D Registers */ +#define VDEC_D_MODE_CTRL 0x1600 +#define VDEC_D_OUT_CTRL1 0x1604 +#define VDEC_D_OUT_CTRL_NS 0x1608 +#define VDEC_D_GEN_STAT 0x160C +#define VDEC_D_INT_STAT_MASK 0x1610 +#define VDEC_D_LUMA_CTRL 0x1614 +#define VDEC_D_CHROMA_CTRL 0x1618 +#define VDEC_D_CRUSH_CTRL 0x161C +#define VDEC_D_HORIZ_TIM_CTRL 0x1620 +#define VDEC_D_VERT_TIM_CTRL 0x1624 +#define VDEC_D_MISC_TIM_CTRL 0x1628 +#define VDEC_D_FIELD_COUNT 0x162C +#define VDEC_D_HSCALE_CTRL 0x1630 +#define VDEC_D_VSCALE_CTRL 0x1634 +#define VDEC_D_MAN_VGA_CTRL 0x1638 +#define VDEC_D_MAN_AGC_CTRL 0x163C +#define VDEC_D_DFE_CTRL1 0x1640 +#define VDEC_D_DFE_CTRL2 0x1644 +#define VDEC_D_DFE_CTRL3 0x1648 +#define VDEC_D_PLL_CTRL 0x164C +#define VDEC_D_PLL_CTRL_FAST 0x1650 +#define VDEC_D_HTL_CTRL 0x1654 +#define VDEC_D_SRC_CFG 0x1658 +#define VDEC_D_SC_STEP_SIZE 0x165C +#define VDEC_D_SC_CONVERGE_CTRL 0x1660 +#define VDEC_D_SC_LOOP_CTRL 0x1664 +#define VDEC_D_COMB_2D_HFS_CFG 0x1668 +#define VDEC_D_COMB_2D_HFD_CFG 0x166C +#define VDEC_D_COMB_2D_LF_CFG 0x1670 +#define VDEC_D_COMB_2D_BLEND 0x1674 +#define VDEC_D_COMB_MISC_CTRL 0x1678 +#define VDEC_D_COMB_FLAT_THRESH_CTRL 0x167C +#define VDEC_D_COMB_TEST 0x1680 +#define VDEC_D_BP_MISC_CTRL 0x1684 +#define VDEC_D_VCR_DET_CTRL 0x1688 +#define VDEC_D_NOISE_DET_CTRL 0x168C +#define VDEC_D_COMB_FLAT_NOISE_CTRL 0x1690 +#define VDEC_D_VERSION 0x17F8 +#define VDEC_D_SOFT_RST_CTRL 0x17FC + +/* Video Decoder E Registers */ +#define VDEC_E_MODE_CTRL 0x1800 +#define VDEC_E_OUT_CTRL1 0x1804 +#define VDEC_E_OUT_CTRL_NS 0x1808 +#define VDEC_E_GEN_STAT 0x180C +#define VDEC_E_INT_STAT_MASK 0x1810 +#define VDEC_E_LUMA_CTRL 0x1814 +#define VDEC_E_CHROMA_CTRL 0x1818 +#define VDEC_E_CRUSH_CTRL 0x181C +#define VDEC_E_HORIZ_TIM_CTRL 0x1820 +#define VDEC_E_VERT_TIM_CTRL 0x1824 +#define VDEC_E_MISC_TIM_CTRL 0x1828 +#define VDEC_E_FIELD_COUNT 0x182C +#define VDEC_E_HSCALE_CTRL 0x1830 +#define VDEC_E_VSCALE_CTRL 0x1834 +#define VDEC_E_MAN_VGA_CTRL 0x1838 +#define VDEC_E_MAN_AGC_CTRL 0x183C +#define VDEC_E_DFE_CTRL1 0x1840 +#define VDEC_E_DFE_CTRL2 0x1844 +#define VDEC_E_DFE_CTRL3 0x1848 +#define VDEC_E_PLL_CTRL 0x184C +#define VDEC_E_PLL_CTRL_FAST 0x1850 +#define VDEC_E_HTL_CTRL 0x1854 +#define VDEC_E_SRC_CFG 0x1858 +#define VDEC_E_SC_STEP_SIZE 0x185C +#define VDEC_E_SC_CONVERGE_CTRL 0x1860 +#define VDEC_E_SC_LOOP_CTRL 0x1864 +#define VDEC_E_COMB_2D_HFS_CFG 0x1868 +#define VDEC_E_COMB_2D_HFD_CFG 0x186C +#define VDEC_E_COMB_2D_LF_CFG 0x1870 +#define VDEC_E_COMB_2D_BLEND 0x1874 +#define VDEC_E_COMB_MISC_CTRL 0x1878 +#define VDEC_E_COMB_FLAT_THRESH_CTRL 0x187C +#define VDEC_E_COMB_TEST 0x1880 +#define VDEC_E_BP_MISC_CTRL 0x1884 +#define VDEC_E_VCR_DET_CTRL 0x1888 +#define VDEC_E_NOISE_DET_CTRL 0x188C +#define VDEC_E_COMB_FLAT_NOISE_CTRL 0x1890 +#define VDEC_E_VERSION 0x19F8 +#define VDEC_E_SOFT_RST_CTRL 0x19FC + +/* Video Decoder F Registers */ +#define VDEC_F_MODE_CTRL 0x1A00 +#define VDEC_F_OUT_CTRL1 0x1A04 +#define VDEC_F_OUT_CTRL_NS 0x1A08 +#define VDEC_F_GEN_STAT 0x1A0C +#define VDEC_F_INT_STAT_MASK 0x1A10 +#define VDEC_F_LUMA_CTRL 0x1A14 +#define VDEC_F_CHROMA_CTRL 0x1A18 +#define VDEC_F_CRUSH_CTRL 0x1A1C +#define VDEC_F_HORIZ_TIM_CTRL 0x1A20 +#define VDEC_F_VERT_TIM_CTRL 0x1A24 +#define VDEC_F_MISC_TIM_CTRL 0x1A28 +#define VDEC_F_FIELD_COUNT 0x1A2C +#define VDEC_F_HSCALE_CTRL 0x1A30 +#define VDEC_F_VSCALE_CTRL 0x1A34 +#define VDEC_F_MAN_VGA_CTRL 0x1A38 +#define VDEC_F_MAN_AGC_CTRL 0x1A3C +#define VDEC_F_DFE_CTRL1 0x1A40 +#define VDEC_F_DFE_CTRL2 0x1A44 +#define VDEC_F_DFE_CTRL3 0x1A48 +#define VDEC_F_PLL_CTRL 0x1A4C +#define VDEC_F_PLL_CTRL_FAST 0x1A50 +#define VDEC_F_HTL_CTRL 0x1A54 +#define VDEC_F_SRC_CFG 0x1A58 +#define VDEC_F_SC_STEP_SIZE 0x1A5C +#define VDEC_F_SC_CONVERGE_CTRL 0x1A60 +#define VDEC_F_SC_LOOP_CTRL 0x1A64 +#define VDEC_F_COMB_2D_HFS_CFG 0x1A68 +#define VDEC_F_COMB_2D_HFD_CFG 0x1A6C +#define VDEC_F_COMB_2D_LF_CFG 0x1A70 +#define VDEC_F_COMB_2D_BLEND 0x1A74 +#define VDEC_F_COMB_MISC_CTRL 0x1A78 +#define VDEC_F_COMB_FLAT_THRESH_CTRL 0x1A7C +#define VDEC_F_COMB_TEST 0x1A80 +#define VDEC_F_BP_MISC_CTRL 0x1A84 +#define VDEC_F_VCR_DET_CTRL 0x1A88 +#define VDEC_F_NOISE_DET_CTRL 0x1A8C +#define VDEC_F_COMB_FLAT_NOISE_CTRL 0x1A90 +#define VDEC_F_VERSION 0x1BF8 +#define VDEC_F_SOFT_RST_CTRL 0x1BFC + +/* Video Decoder G Registers */ +#define VDEC_G_MODE_CTRL 0x1C00 +#define VDEC_G_OUT_CTRL1 0x1C04 +#define VDEC_G_OUT_CTRL_NS 0x1C08 +#define VDEC_G_GEN_STAT 0x1C0C +#define VDEC_G_INT_STAT_MASK 0x1C10 +#define VDEC_G_LUMA_CTRL 0x1C14 +#define VDEC_G_CHROMA_CTRL 0x1C18 +#define VDEC_G_CRUSH_CTRL 0x1C1C +#define VDEC_G_HORIZ_TIM_CTRL 0x1C20 +#define VDEC_G_VERT_TIM_CTRL 0x1C24 +#define VDEC_G_MISC_TIM_CTRL 0x1C28 +#define VDEC_G_FIELD_COUNT 0x1C2C +#define VDEC_G_HSCALE_CTRL 0x1C30 +#define VDEC_G_VSCALE_CTRL 0x1C34 +#define VDEC_G_MAN_VGA_CTRL 0x1C38 +#define VDEC_G_MAN_AGC_CTRL 0x1C3C +#define VDEC_G_DFE_CTRL1 0x1C40 +#define VDEC_G_DFE_CTRL2 0x1C44 +#define VDEC_G_DFE_CTRL3 0x1C48 +#define VDEC_G_PLL_CTRL 0x1C4C +#define VDEC_G_PLL_CTRL_FAST 0x1C50 +#define VDEC_G_HTL_CTRL 0x1C54 +#define VDEC_G_SRC_CFG 0x1C58 +#define VDEC_G_SC_STEP_SIZE 0x1C5C +#define VDEC_G_SC_CONVERGE_CTRL 0x1C60 +#define VDEC_G_SC_LOOP_CTRL 0x1C64 +#define VDEC_G_COMB_2D_HFS_CFG 0x1C68 +#define VDEC_G_COMB_2D_HFD_CFG 0x1C6C +#define VDEC_G_COMB_2D_LF_CFG 0x1C70 +#define VDEC_G_COMB_2D_BLEND 0x1C74 +#define VDEC_G_COMB_MISC_CTRL 0x1C78 +#define VDEC_G_COMB_FLAT_THRESH_CTRL 0x1C7C +#define VDEC_G_COMB_TEST 0x1C80 +#define VDEC_G_BP_MISC_CTRL 0x1C84 +#define VDEC_G_VCR_DET_CTRL 0x1C88 +#define VDEC_G_NOISE_DET_CTRL 0x1C8C +#define VDEC_G_COMB_FLAT_NOISE_CTRL 0x1C90 +#define VDEC_G_VERSION 0x1DF8 +#define VDEC_G_SOFT_RST_CTRL 0x1DFC + +/* Video Decoder H Registers */ +#define VDEC_H_MODE_CTRL 0x1E00 +#define VDEC_H_OUT_CTRL1 0x1E04 +#define VDEC_H_OUT_CTRL_NS 0x1E08 +#define VDEC_H_GEN_STAT 0x1E0C +#define VDEC_H_INT_STAT_MASK 0x1E1E +#define VDEC_H_LUMA_CTRL 0x1E14 +#define VDEC_H_CHROMA_CTRL 0x1E18 +#define VDEC_H_CRUSH_CTRL 0x1E1C +#define VDEC_H_HORIZ_TIM_CTRL 0x1E20 +#define VDEC_H_VERT_TIM_CTRL 0x1E24 +#define VDEC_H_MISC_TIM_CTRL 0x1E28 +#define VDEC_H_FIELD_COUNT 0x1E2C +#define VDEC_H_HSCALE_CTRL 0x1E30 +#define VDEC_H_VSCALE_CTRL 0x1E34 +#define VDEC_H_MAN_VGA_CTRL 0x1E38 +#define VDEC_H_MAN_AGC_CTRL 0x1E3C +#define VDEC_H_DFE_CTRL1 0x1E40 +#define VDEC_H_DFE_CTRL2 0x1E44 +#define VDEC_H_DFE_CTRL3 0x1E48 +#define VDEC_H_PLL_CTRL 0x1E4C +#define VDEC_H_PLL_CTRL_FAST 0x1E50 +#define VDEC_H_HTL_CTRL 0x1E54 +#define VDEC_H_SRC_CFG 0x1E58 +#define VDEC_H_SC_STEP_SIZE 0x1E5C +#define VDEC_H_SC_CONVERGE_CTRL 0x1E60 +#define VDEC_H_SC_LOOP_CTRL 0x1E64 +#define VDEC_H_COMB_2D_HFS_CFG 0x1E68 +#define VDEC_H_COMB_2D_HFD_CFG 0x1E6C +#define VDEC_H_COMB_2D_LF_CFG 0x1E70 +#define VDEC_H_COMB_2D_BLEND 0x1E74 +#define VDEC_H_COMB_MISC_CTRL 0x1E78 +#define VDEC_H_COMB_FLAT_THRESH_CTRL 0x1E7C +#define VDEC_H_COMB_TEST 0x1E80 +#define VDEC_H_BP_MISC_CTRL 0x1E84 +#define VDEC_H_VCR_DET_CTRL 0x1E88 +#define VDEC_H_NOISE_DET_CTRL 0x1E8C +#define VDEC_H_COMB_FLAT_NOISE_CTRL 0x1E90 +#define VDEC_H_VERSION 0x1FF8 +#define VDEC_H_SOFT_RST_CTRL 0x1FFC + +/*****************************************************************************/ +/* LUMA_CTRL register fields */ +#define VDEC_A_BRITE_CTRL 0x1014 +#define VDEC_A_CNTRST_CTRL 0x1015 +#define VDEC_A_PEAK_SEL 0x1016 + +/*****************************************************************************/ +/* CHROMA_CTRL register fields */ +#define VDEC_A_USAT_CTRL 0x1018 +#define VDEC_A_VSAT_CTRL 0x1019 +#define VDEC_A_HUE_CTRL 0x101A + +#endif diff --git a/drivers/media/pci/cx25821/cx25821-medusa-video.c b/drivers/media/pci/cx25821/cx25821-medusa-video.c new file mode 100644 index 0000000..6a92e5c --- /dev/null +++ b/drivers/media/pci/cx25821/cx25821-medusa-video.c @@ -0,0 +1,787 @@ +/* + * Driver for the Conexant CX25821 PCIe bridge + * + * Copyright (C) 2009 Conexant Systems Inc. + * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include "cx25821.h" +#include "cx25821-medusa-video.h" +#include "cx25821-biffuncs.h" + +/* + * medusa_enable_bluefield_output() + * + * Enable the generation of blue filed output if no video + * + */ +static void medusa_enable_bluefield_output(struct cx25821_dev *dev, int channel, + int enable) +{ + u32 value = 0; + u32 tmp = 0; + int out_ctrl = OUT_CTRL1; + int out_ctrl_ns = OUT_CTRL_NS; + + switch (channel) { + default: + case VDEC_A: + break; + case VDEC_B: + out_ctrl = VDEC_B_OUT_CTRL1; + out_ctrl_ns = VDEC_B_OUT_CTRL_NS; + break; + case VDEC_C: + out_ctrl = VDEC_C_OUT_CTRL1; + out_ctrl_ns = VDEC_C_OUT_CTRL_NS; + break; + case VDEC_D: + out_ctrl = VDEC_D_OUT_CTRL1; + out_ctrl_ns = VDEC_D_OUT_CTRL_NS; + break; + case VDEC_E: + out_ctrl = VDEC_E_OUT_CTRL1; + out_ctrl_ns = VDEC_E_OUT_CTRL_NS; + return; + case VDEC_F: + out_ctrl = VDEC_F_OUT_CTRL1; + out_ctrl_ns = VDEC_F_OUT_CTRL_NS; + return; + case VDEC_G: + out_ctrl = VDEC_G_OUT_CTRL1; + out_ctrl_ns = VDEC_G_OUT_CTRL_NS; + return; + case VDEC_H: + out_ctrl = VDEC_H_OUT_CTRL1; + out_ctrl_ns = VDEC_H_OUT_CTRL_NS; + return; + } + + value = cx25821_i2c_read(&dev->i2c_bus[0], out_ctrl, &tmp); + value &= 0xFFFFFF7F; /* clear BLUE_FIELD_EN */ + if (enable) + value |= 0x00000080; /* set BLUE_FIELD_EN */ + cx25821_i2c_write(&dev->i2c_bus[0], out_ctrl, value); + + value = cx25821_i2c_read(&dev->i2c_bus[0], out_ctrl_ns, &tmp); + value &= 0xFFFFFF7F; + if (enable) + value |= 0x00000080; /* set BLUE_FIELD_EN */ + cx25821_i2c_write(&dev->i2c_bus[0], out_ctrl_ns, value); +} + +static int medusa_initialize_ntsc(struct cx25821_dev *dev) +{ + int ret_val = 0; + int i = 0; + u32 value = 0; + u32 tmp = 0; + + mutex_lock(&dev->lock); + + for (i = 0; i < MAX_DECODERS; i++) { + /* set video format NTSC-M */ + value = cx25821_i2c_read(&dev->i2c_bus[0], + MODE_CTRL + (0x200 * i), &tmp); + value &= 0xFFFFFFF0; + /* enable the fast locking mode bit[16] */ + value |= 0x10001; + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + MODE_CTRL + (0x200 * i), value); + + /* resolution NTSC 720x480 */ + value = cx25821_i2c_read(&dev->i2c_bus[0], + HORIZ_TIM_CTRL + (0x200 * i), &tmp); + value &= 0x00C00C00; + value |= 0x612D0074; + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + HORIZ_TIM_CTRL + (0x200 * i), value); + + value = cx25821_i2c_read(&dev->i2c_bus[0], + VERT_TIM_CTRL + (0x200 * i), &tmp); + value &= 0x00C00C00; + value |= 0x1C1E001A; /* vblank_cnt + 2 to get camera ID */ + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + VERT_TIM_CTRL + (0x200 * i), value); + + /* chroma subcarrier step size */ + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + SC_STEP_SIZE + (0x200 * i), 0x43E00000); + + /* enable VIP optional active */ + value = cx25821_i2c_read(&dev->i2c_bus[0], + OUT_CTRL_NS + (0x200 * i), &tmp); + value &= 0xFFFBFFFF; + value |= 0x00040000; + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + OUT_CTRL_NS + (0x200 * i), value); + + /* enable VIP optional active (VIP_OPT_AL) for direct output. */ + value = cx25821_i2c_read(&dev->i2c_bus[0], + OUT_CTRL1 + (0x200 * i), &tmp); + value &= 0xFFFBFFFF; + value |= 0x00040000; + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + OUT_CTRL1 + (0x200 * i), value); + + /* + * clear VPRES_VERT_EN bit, fixes the chroma run away problem + * when the input switching rate < 16 fields + */ + value = cx25821_i2c_read(&dev->i2c_bus[0], + MISC_TIM_CTRL + (0x200 * i), &tmp); + /* disable special play detection */ + value = setBitAtPos(value, 14); + value = clearBitAtPos(value, 15); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + MISC_TIM_CTRL + (0x200 * i), value); + + /* set vbi_gate_en to 0 */ + value = cx25821_i2c_read(&dev->i2c_bus[0], + DFE_CTRL1 + (0x200 * i), &tmp); + value = clearBitAtPos(value, 29); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DFE_CTRL1 + (0x200 * i), value); + + /* Enable the generation of blue field output if no video */ + medusa_enable_bluefield_output(dev, i, 1); + } + + for (i = 0; i < MAX_ENCODERS; i++) { + /* NTSC hclock */ + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_1 + (0x100 * i), &tmp); + value &= 0xF000FC00; + value |= 0x06B402D0; + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_1 + (0x100 * i), value); + + /* burst begin and burst end */ + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_2 + (0x100 * i), &tmp); + value &= 0xFF000000; + value |= 0x007E9054; + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_2 + (0x100 * i), value); + + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_3 + (0x100 * i), &tmp); + value &= 0xFC00FE00; + value |= 0x00EC00F0; + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_3 + (0x100 * i), value); + + /* set NTSC vblank, no phase alternation, 7.5 IRE pedestal */ + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_4 + (0x100 * i), &tmp); + value &= 0x00FCFFFF; + value |= 0x13020000; + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_4 + (0x100 * i), value); + + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_5 + (0x100 * i), &tmp); + value &= 0xFFFF0000; + value |= 0x0000E575; + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_5 + (0x100 * i), value); + + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_6 + (0x100 * i), 0x009A89C1); + + /* Subcarrier Increment */ + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_7 + (0x100 * i), 0x21F07C1F); + } + + /* set picture resolutions */ + /* 0 - 720 */ + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], HSCALE_CTRL, 0x0); + /* 0 - 480 */ + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], VSCALE_CTRL, 0x0); + + /* set Bypass input format to NTSC 525 lines */ + value = cx25821_i2c_read(&dev->i2c_bus[0], BYP_AB_CTRL, &tmp); + value |= 0x00080200; + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], BYP_AB_CTRL, value); + + mutex_unlock(&dev->lock); + + return ret_val; +} + +static int medusa_PALCombInit(struct cx25821_dev *dev, int dec) +{ + int ret_val = -1; + u32 value = 0, tmp = 0; + + /* Setup for 2D threshold */ + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + COMB_2D_HFS_CFG + (0x200 * dec), 0x20002861); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + COMB_2D_HFD_CFG + (0x200 * dec), 0x20002861); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + COMB_2D_LF_CFG + (0x200 * dec), 0x200A1023); + + /* Setup flat chroma and luma thresholds */ + value = cx25821_i2c_read(&dev->i2c_bus[0], + COMB_FLAT_THRESH_CTRL + (0x200 * dec), &tmp); + value &= 0x06230000; + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + COMB_FLAT_THRESH_CTRL + (0x200 * dec), value); + + /* set comb 2D blend */ + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + COMB_2D_BLEND + (0x200 * dec), 0x210F0F0F); + + /* COMB MISC CONTROL */ + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + COMB_MISC_CTRL + (0x200 * dec), 0x41120A7F); + + return ret_val; +} + +static int medusa_initialize_pal(struct cx25821_dev *dev) +{ + int ret_val = 0; + int i = 0; + u32 value = 0; + u32 tmp = 0; + + mutex_lock(&dev->lock); + + for (i = 0; i < MAX_DECODERS; i++) { + /* set video format PAL-BDGHI */ + value = cx25821_i2c_read(&dev->i2c_bus[0], + MODE_CTRL + (0x200 * i), &tmp); + value &= 0xFFFFFFF0; + /* enable the fast locking mode bit[16] */ + value |= 0x10004; + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + MODE_CTRL + (0x200 * i), value); + + /* resolution PAL 720x576 */ + value = cx25821_i2c_read(&dev->i2c_bus[0], + HORIZ_TIM_CTRL + (0x200 * i), &tmp); + value &= 0x00C00C00; + value |= 0x632D007D; + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + HORIZ_TIM_CTRL + (0x200 * i), value); + + /* vblank656_cnt=x26, vactive_cnt=240h, vblank_cnt=x24 */ + value = cx25821_i2c_read(&dev->i2c_bus[0], + VERT_TIM_CTRL + (0x200 * i), &tmp); + value &= 0x00C00C00; + value |= 0x28240026; /* vblank_cnt + 2 to get camera ID */ + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + VERT_TIM_CTRL + (0x200 * i), value); + + /* chroma subcarrier step size */ + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + SC_STEP_SIZE + (0x200 * i), 0x5411E2D0); + + /* enable VIP optional active */ + value = cx25821_i2c_read(&dev->i2c_bus[0], + OUT_CTRL_NS + (0x200 * i), &tmp); + value &= 0xFFFBFFFF; + value |= 0x00040000; + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + OUT_CTRL_NS + (0x200 * i), value); + + /* enable VIP optional active (VIP_OPT_AL) for direct output. */ + value = cx25821_i2c_read(&dev->i2c_bus[0], + OUT_CTRL1 + (0x200 * i), &tmp); + value &= 0xFFFBFFFF; + value |= 0x00040000; + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + OUT_CTRL1 + (0x200 * i), value); + + /* + * clear VPRES_VERT_EN bit, fixes the chroma run away problem + * when the input switching rate < 16 fields + */ + value = cx25821_i2c_read(&dev->i2c_bus[0], + MISC_TIM_CTRL + (0x200 * i), &tmp); + /* disable special play detection */ + value = setBitAtPos(value, 14); + value = clearBitAtPos(value, 15); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + MISC_TIM_CTRL + (0x200 * i), value); + + /* set vbi_gate_en to 0 */ + value = cx25821_i2c_read(&dev->i2c_bus[0], + DFE_CTRL1 + (0x200 * i), &tmp); + value = clearBitAtPos(value, 29); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DFE_CTRL1 + (0x200 * i), value); + + medusa_PALCombInit(dev, i); + + /* Enable the generation of blue field output if no video */ + medusa_enable_bluefield_output(dev, i, 1); + } + + for (i = 0; i < MAX_ENCODERS; i++) { + /* PAL hclock */ + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_1 + (0x100 * i), &tmp); + value &= 0xF000FC00; + value |= 0x06C002D0; + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_1 + (0x100 * i), value); + + /* burst begin and burst end */ + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_2 + (0x100 * i), &tmp); + value &= 0xFF000000; + value |= 0x007E9754; + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_2 + (0x100 * i), value); + + /* hblank and vactive */ + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_3 + (0x100 * i), &tmp); + value &= 0xFC00FE00; + value |= 0x00FC0120; + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_3 + (0x100 * i), value); + + /* set PAL vblank, phase alternation, 0 IRE pedestal */ + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_4 + (0x100 * i), &tmp); + value &= 0x00FCFFFF; + value |= 0x14010000; + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_4 + (0x100 * i), value); + + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_5 + (0x100 * i), &tmp); + value &= 0xFFFF0000; + value |= 0x0000F078; + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_5 + (0x100 * i), value); + + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_6 + (0x100 * i), 0x00A493CF); + + /* Subcarrier Increment */ + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_7 + (0x100 * i), 0x2A098ACB); + } + + /* set picture resolutions */ + /* 0 - 720 */ + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], HSCALE_CTRL, 0x0); + /* 0 - 576 */ + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], VSCALE_CTRL, 0x0); + + /* set Bypass input format to PAL 625 lines */ + value = cx25821_i2c_read(&dev->i2c_bus[0], BYP_AB_CTRL, &tmp); + value &= 0xFFF7FDFF; + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], BYP_AB_CTRL, value); + + mutex_unlock(&dev->lock); + + return ret_val; +} + +int medusa_set_videostandard(struct cx25821_dev *dev) +{ + int status = STATUS_SUCCESS; + u32 value = 0, tmp = 0; + + if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK) + status = medusa_initialize_pal(dev); + else + status = medusa_initialize_ntsc(dev); + + /* Enable DENC_A output */ + value = cx25821_i2c_read(&dev->i2c_bus[0], DENC_A_REG_4, &tmp); + value = setBitAtPos(value, 4); + status = cx25821_i2c_write(&dev->i2c_bus[0], DENC_A_REG_4, value); + + /* Enable DENC_B output */ + value = cx25821_i2c_read(&dev->i2c_bus[0], DENC_B_REG_4, &tmp); + value = setBitAtPos(value, 4); + status = cx25821_i2c_write(&dev->i2c_bus[0], DENC_B_REG_4, value); + + return status; +} + +void medusa_set_resolution(struct cx25821_dev *dev, int width, + int decoder_select) +{ + int decoder = 0; + int decoder_count = 0; + u32 hscale = 0x0; + u32 vscale = 0x0; + const int MAX_WIDTH = 720; + + mutex_lock(&dev->lock); + + /* validate the width */ + if (width > MAX_WIDTH) { + pr_info("%s(): width %d > MAX_WIDTH %d ! resetting to MAX_WIDTH\n", + __func__, width, MAX_WIDTH); + width = MAX_WIDTH; + } + + if (decoder_select <= 7 && decoder_select >= 0) { + decoder = decoder_select; + decoder_count = decoder_select + 1; + } else { + decoder = 0; + decoder_count = _num_decoders; + } + + switch (width) { + case 320: + hscale = 0x13E34B; + vscale = 0x0; + break; + + case 352: + hscale = 0x10A273; + vscale = 0x0; + break; + + case 176: + hscale = 0x3115B2; + vscale = 0x1E00; + break; + + case 160: + hscale = 0x378D84; + vscale = 0x1E00; + break; + + default: /* 720 */ + hscale = 0x0; + vscale = 0x0; + break; + } + + for (; decoder < decoder_count; decoder++) { + /* write scaling values for each decoder */ + cx25821_i2c_write(&dev->i2c_bus[0], + HSCALE_CTRL + (0x200 * decoder), hscale); + cx25821_i2c_write(&dev->i2c_bus[0], + VSCALE_CTRL + (0x200 * decoder), vscale); + } + + mutex_unlock(&dev->lock); +} + +static void medusa_set_decoderduration(struct cx25821_dev *dev, int decoder, + int duration) +{ + u32 fld_cnt = 0; + u32 tmp = 0; + u32 disp_cnt_reg = DISP_AB_CNT; + + mutex_lock(&dev->lock); + + /* no support */ + if (decoder < VDEC_A || decoder > VDEC_H) { + mutex_unlock(&dev->lock); + return; + } + + switch (decoder) { + default: + break; + case VDEC_C: + case VDEC_D: + disp_cnt_reg = DISP_CD_CNT; + break; + case VDEC_E: + case VDEC_F: + disp_cnt_reg = DISP_EF_CNT; + break; + case VDEC_G: + case VDEC_H: + disp_cnt_reg = DISP_GH_CNT; + break; + } + + _display_field_cnt[decoder] = duration; + + /* update hardware */ + fld_cnt = cx25821_i2c_read(&dev->i2c_bus[0], disp_cnt_reg, &tmp); + + if (!(decoder % 2)) { /* EVEN decoder */ + fld_cnt &= 0xFFFF0000; + fld_cnt |= duration; + } else { + fld_cnt &= 0x0000FFFF; + fld_cnt |= ((u32) duration) << 16; + } + + cx25821_i2c_write(&dev->i2c_bus[0], disp_cnt_reg, fld_cnt); + + mutex_unlock(&dev->lock); +} + +/* Map to Medusa register setting */ +static int mapM(int srcMin, int srcMax, int srcVal, int dstMin, int dstMax, + int *dstVal) +{ + int numerator; + int denominator; + int quotient; + + if ((srcMin == srcMax) || (srcVal < srcMin) || (srcVal > srcMax)) + return -1; + /* + * This is the overall expression used: + * *dstVal = + * (srcVal - srcMin)*(dstMax - dstMin) / (srcMax - srcMin) + dstMin; + * but we need to account for rounding so below we use the modulus + * operator to find the remainder and increment if necessary. + */ + numerator = (srcVal - srcMin) * (dstMax - dstMin); + denominator = srcMax - srcMin; + quotient = numerator / denominator; + + if (2 * (numerator % denominator) >= denominator) + quotient++; + + *dstVal = quotient + dstMin; + + return 0; +} + +static unsigned long convert_to_twos(long numeric, unsigned long bits_len) +{ + unsigned char temp; + + if (numeric >= 0) + return numeric; + else { + temp = ~(abs(numeric) & 0xFF); + temp += 1; + return temp; + } +} + +int medusa_set_brightness(struct cx25821_dev *dev, int brightness, int decoder) +{ + int ret_val = 0; + int value = 0; + u32 val = 0, tmp = 0; + + mutex_lock(&dev->lock); + if ((brightness > VIDEO_PROCAMP_MAX) || + (brightness < VIDEO_PROCAMP_MIN)) { + mutex_unlock(&dev->lock); + return -1; + } + ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, brightness, + SIGNED_BYTE_MIN, SIGNED_BYTE_MAX, &value); + value = convert_to_twos(value, 8); + val = cx25821_i2c_read(&dev->i2c_bus[0], + VDEC_A_BRITE_CTRL + (0x200 * decoder), &tmp); + val &= 0xFFFFFF00; + ret_val |= cx25821_i2c_write(&dev->i2c_bus[0], + VDEC_A_BRITE_CTRL + (0x200 * decoder), val | value); + mutex_unlock(&dev->lock); + return ret_val; +} + +int medusa_set_contrast(struct cx25821_dev *dev, int contrast, int decoder) +{ + int ret_val = 0; + int value = 0; + u32 val = 0, tmp = 0; + + mutex_lock(&dev->lock); + + if ((contrast > VIDEO_PROCAMP_MAX) || (contrast < VIDEO_PROCAMP_MIN)) { + mutex_unlock(&dev->lock); + return -1; + } + + ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, contrast, + UNSIGNED_BYTE_MIN, UNSIGNED_BYTE_MAX, &value); + val = cx25821_i2c_read(&dev->i2c_bus[0], + VDEC_A_CNTRST_CTRL + (0x200 * decoder), &tmp); + val &= 0xFFFFFF00; + ret_val |= cx25821_i2c_write(&dev->i2c_bus[0], + VDEC_A_CNTRST_CTRL + (0x200 * decoder), val | value); + + mutex_unlock(&dev->lock); + return ret_val; +} + +int medusa_set_hue(struct cx25821_dev *dev, int hue, int decoder) +{ + int ret_val = 0; + int value = 0; + u32 val = 0, tmp = 0; + + mutex_lock(&dev->lock); + + if ((hue > VIDEO_PROCAMP_MAX) || (hue < VIDEO_PROCAMP_MIN)) { + mutex_unlock(&dev->lock); + return -1; + } + + ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, hue, + SIGNED_BYTE_MIN, SIGNED_BYTE_MAX, &value); + + value = convert_to_twos(value, 8); + val = cx25821_i2c_read(&dev->i2c_bus[0], + VDEC_A_HUE_CTRL + (0x200 * decoder), &tmp); + val &= 0xFFFFFF00; + + ret_val |= cx25821_i2c_write(&dev->i2c_bus[0], + VDEC_A_HUE_CTRL + (0x200 * decoder), val | value); + + mutex_unlock(&dev->lock); + return ret_val; +} + +int medusa_set_saturation(struct cx25821_dev *dev, int saturation, int decoder) +{ + int ret_val = 0; + int value = 0; + u32 val = 0, tmp = 0; + + mutex_lock(&dev->lock); + + if ((saturation > VIDEO_PROCAMP_MAX) || + (saturation < VIDEO_PROCAMP_MIN)) { + mutex_unlock(&dev->lock); + return -1; + } + + ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, saturation, + UNSIGNED_BYTE_MIN, UNSIGNED_BYTE_MAX, &value); + + val = cx25821_i2c_read(&dev->i2c_bus[0], + VDEC_A_USAT_CTRL + (0x200 * decoder), &tmp); + val &= 0xFFFFFF00; + ret_val |= cx25821_i2c_write(&dev->i2c_bus[0], + VDEC_A_USAT_CTRL + (0x200 * decoder), val | value); + + val = cx25821_i2c_read(&dev->i2c_bus[0], + VDEC_A_VSAT_CTRL + (0x200 * decoder), &tmp); + val &= 0xFFFFFF00; + ret_val |= cx25821_i2c_write(&dev->i2c_bus[0], + VDEC_A_VSAT_CTRL + (0x200 * decoder), val | value); + + mutex_unlock(&dev->lock); + return ret_val; +} + +/* Program the display sequence and monitor output. */ + +int medusa_video_init(struct cx25821_dev *dev) +{ + u32 value = 0, tmp = 0; + int ret_val = 0; + int i = 0; + + mutex_lock(&dev->lock); + + _num_decoders = dev->_max_num_decoders; + + /* disable Auto source selection on all video decoders */ + value = cx25821_i2c_read(&dev->i2c_bus[0], MON_A_CTRL, &tmp); + value &= 0xFFFFF0FF; + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], MON_A_CTRL, value); + + if (ret_val < 0) + goto error; + + /* Turn off Master source switch enable */ + value = cx25821_i2c_read(&dev->i2c_bus[0], MON_A_CTRL, &tmp); + value &= 0xFFFFFFDF; + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], MON_A_CTRL, value); + + if (ret_val < 0) + goto error; + + mutex_unlock(&dev->lock); + + for (i = 0; i < _num_decoders; i++) + medusa_set_decoderduration(dev, i, _display_field_cnt[i]); + + mutex_lock(&dev->lock); + + /* Select monitor as DENC A input, power up the DAC */ + value = cx25821_i2c_read(&dev->i2c_bus[0], DENC_AB_CTRL, &tmp); + value &= 0xFF70FF70; + value |= 0x00090008; /* set en_active */ + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], DENC_AB_CTRL, value); + + if (ret_val < 0) + goto error; + + /* enable input is VIP/656 */ + value = cx25821_i2c_read(&dev->i2c_bus[0], BYP_AB_CTRL, &tmp); + value |= 0x00040100; /* enable VIP */ + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], BYP_AB_CTRL, value); + + if (ret_val < 0) + goto error; + + /* select AFE clock to output mode */ + value = cx25821_i2c_read(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, &tmp); + value &= 0x83FFFFFF; + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, + value | 0x10000000); + + if (ret_val < 0) + goto error; + + /* Turn on all of the data out and control output pins. */ + value = cx25821_i2c_read(&dev->i2c_bus[0], PIN_OE_CTRL, &tmp); + value &= 0xFEF0FE00; + if (_num_decoders == MAX_DECODERS) { + /* + * Note: The octal board does not support control pins(bit16-19) + * These bits are ignored in the octal board. + * + * disable VDEC A-C port, default to Mobilygen Interface + */ + value |= 0x010001F8; + } else { + /* disable VDEC A-C port, default to Mobilygen Interface */ + value |= 0x010F0108; + } + + value |= 7; + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], PIN_OE_CTRL, value); + + if (ret_val < 0) + goto error; + + + mutex_unlock(&dev->lock); + + ret_val = medusa_set_videostandard(dev); + + return ret_val; + +error: + mutex_unlock(&dev->lock); + return ret_val; +} diff --git a/drivers/media/pci/cx25821/cx25821-medusa-video.h b/drivers/media/pci/cx25821/cx25821-medusa-video.h new file mode 100644 index 0000000..6175e09 --- /dev/null +++ b/drivers/media/pci/cx25821/cx25821-medusa-video.h @@ -0,0 +1,49 @@ +/* + * Driver for the Conexant CX25821 PCIe bridge + * + * Copyright (C) 2009 Conexant Systems Inc. + * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _MEDUSA_VIDEO_H +#define _MEDUSA_VIDEO_H + +#include "cx25821-medusa-defines.h" + +/* Color control constants */ +#define VIDEO_PROCAMP_MIN 0 +#define VIDEO_PROCAMP_MAX 10000 +#define UNSIGNED_BYTE_MIN 0 +#define UNSIGNED_BYTE_MAX 0xFF +#define SIGNED_BYTE_MIN -128 +#define SIGNED_BYTE_MAX 127 + +/* Default video color settings */ +#define SHARPNESS_DEFAULT 50 +#define SATURATION_DEFAULT 5000 +#define BRIGHTNESS_DEFAULT 6200 +#define CONTRAST_DEFAULT 5000 +#define HUE_DEFAULT 5000 + +unsigned short _num_decoders; +unsigned short _num_cameras; + +unsigned int _video_standard; +int _display_field_cnt[MAX_DECODERS]; + +#endif diff --git a/drivers/media/pci/cx25821/cx25821-reg.h b/drivers/media/pci/cx25821/cx25821-reg.h new file mode 100644 index 0000000..a3fc25a --- /dev/null +++ b/drivers/media/pci/cx25821/cx25821-reg.h @@ -0,0 +1,1592 @@ +/* + * Driver for the Conexant CX25821 PCIe bridge + * + * Copyright (C) 2009 Conexant Systems Inc. + * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __CX25821_REGISTERS__ +#define __CX25821_REGISTERS__ + +/* Risc Instructions */ +#define RISC_CNT_INC 0x00010000 +#define RISC_CNT_RESET 0x00030000 +#define RISC_IRQ1 0x01000000 +#define RISC_IRQ2 0x02000000 +#define RISC_EOL 0x04000000 +#define RISC_SOL 0x08000000 +#define RISC_WRITE 0x10000000 +#define RISC_SKIP 0x20000000 +#define RISC_JUMP 0x70000000 +#define RISC_SYNC 0x80000000 +#define RISC_RESYNC 0x80008000 +#define RISC_READ 0x90000000 +#define RISC_WRITERM 0xB0000000 +#define RISC_WRITECM 0xC0000000 +#define RISC_WRITECR 0xD0000000 +#define RISC_WRITEC 0x50000000 +#define RISC_READC 0xA0000000 + +#define RISC_SYNC_ODD 0x00000000 +#define RISC_SYNC_EVEN 0x00000200 +#define RISC_SYNC_ODD_VBI 0x00000006 +#define RISC_SYNC_EVEN_VBI 0x00000207 +#define RISC_NOOP 0xF0000000 + +/***************************************************************************** +* ASB SRAM + *****************************************************************************/ +#define TX_SRAM 0x000000 /* Transmit SRAM */ + +/*****************************************************************************/ +#define RX_RAM 0x010000 /* Receive SRAM */ + +/***************************************************************************** +* Application Layer (AL) + *****************************************************************************/ +#define DEV_CNTRL2 0x040000 /* Device control */ +#define FLD_RUN_RISC 0x00000020 + +/* ***************************************************************************** */ +#define PCI_INT_MSK 0x040010 /* PCI interrupt mask */ +#define PCI_INT_STAT 0x040014 /* PCI interrupt status */ +#define PCI_INT_MSTAT 0x040018 /* PCI interrupt masked status */ +#define FLD_HAMMERHEAD_INT (1 << 27) +#define FLD_UART_INT (1 << 26) +#define FLD_IRQN_INT (1 << 25) +#define FLD_TM_INT (1 << 28) +#define FLD_I2C_3_RACK (1 << 27) +#define FLD_I2C_3_INT (1 << 26) +#define FLD_I2C_2_RACK (1 << 25) +#define FLD_I2C_2_INT (1 << 24) +#define FLD_I2C_1_RACK (1 << 23) +#define FLD_I2C_1_INT (1 << 22) + +#define FLD_APB_DMA_BERR_INT (1 << 21) +#define FLD_AL_WR_BERR_INT (1 << 20) +#define FLD_AL_RD_BERR_INT (1 << 19) +#define FLD_RISC_WR_BERR_INT (1 << 18) +#define FLD_RISC_RD_BERR_INT (1 << 17) + +#define FLD_VID_I_INT (1 << 8) +#define FLD_VID_H_INT (1 << 7) +#define FLD_VID_G_INT (1 << 6) +#define FLD_VID_F_INT (1 << 5) +#define FLD_VID_E_INT (1 << 4) +#define FLD_VID_D_INT (1 << 3) +#define FLD_VID_C_INT (1 << 2) +#define FLD_VID_B_INT (1 << 1) +#define FLD_VID_A_INT (1 << 0) + +/* ***************************************************************************** */ +#define VID_A_INT_MSK 0x040020 /* Video A interrupt mask */ +#define VID_A_INT_STAT 0x040024 /* Video A interrupt status */ +#define VID_A_INT_MSTAT 0x040028 /* Video A interrupt masked status */ +#define VID_A_INT_SSTAT 0x04002C /* Video A interrupt set status */ + +/* ***************************************************************************** */ +#define VID_B_INT_MSK 0x040030 /* Video B interrupt mask */ +#define VID_B_INT_STAT 0x040034 /* Video B interrupt status */ +#define VID_B_INT_MSTAT 0x040038 /* Video B interrupt masked status */ +#define VID_B_INT_SSTAT 0x04003C /* Video B interrupt set status */ + +/* ***************************************************************************** */ +#define VID_C_INT_MSK 0x040040 /* Video C interrupt mask */ +#define VID_C_INT_STAT 0x040044 /* Video C interrupt status */ +#define VID_C_INT_MSTAT 0x040048 /* Video C interrupt masked status */ +#define VID_C_INT_SSTAT 0x04004C /* Video C interrupt set status */ + +/* ***************************************************************************** */ +#define VID_D_INT_MSK 0x040050 /* Video D interrupt mask */ +#define VID_D_INT_STAT 0x040054 /* Video D interrupt status */ +#define VID_D_INT_MSTAT 0x040058 /* Video D interrupt masked status */ +#define VID_D_INT_SSTAT 0x04005C /* Video D interrupt set status */ + +/* ***************************************************************************** */ +#define VID_E_INT_MSK 0x040060 /* Video E interrupt mask */ +#define VID_E_INT_STAT 0x040064 /* Video E interrupt status */ +#define VID_E_INT_MSTAT 0x040068 /* Video E interrupt masked status */ +#define VID_E_INT_SSTAT 0x04006C /* Video E interrupt set status */ + +/* ***************************************************************************** */ +#define VID_F_INT_MSK 0x040070 /* Video F interrupt mask */ +#define VID_F_INT_STAT 0x040074 /* Video F interrupt status */ +#define VID_F_INT_MSTAT 0x040078 /* Video F interrupt masked status */ +#define VID_F_INT_SSTAT 0x04007C /* Video F interrupt set status */ + +/* ***************************************************************************** */ +#define VID_G_INT_MSK 0x040080 /* Video G interrupt mask */ +#define VID_G_INT_STAT 0x040084 /* Video G interrupt status */ +#define VID_G_INT_MSTAT 0x040088 /* Video G interrupt masked status */ +#define VID_G_INT_SSTAT 0x04008C /* Video G interrupt set status */ + +/* ***************************************************************************** */ +#define VID_H_INT_MSK 0x040090 /* Video H interrupt mask */ +#define VID_H_INT_STAT 0x040094 /* Video H interrupt status */ +#define VID_H_INT_MSTAT 0x040098 /* Video H interrupt masked status */ +#define VID_H_INT_SSTAT 0x04009C /* Video H interrupt set status */ + +/* ***************************************************************************** */ +#define VID_I_INT_MSK 0x0400A0 /* Video I interrupt mask */ +#define VID_I_INT_STAT 0x0400A4 /* Video I interrupt status */ +#define VID_I_INT_MSTAT 0x0400A8 /* Video I interrupt masked status */ +#define VID_I_INT_SSTAT 0x0400AC /* Video I interrupt set status */ + +/* ***************************************************************************** */ +#define VID_J_INT_MSK 0x0400B0 /* Video J interrupt mask */ +#define VID_J_INT_STAT 0x0400B4 /* Video J interrupt status */ +#define VID_J_INT_MSTAT 0x0400B8 /* Video J interrupt masked status */ +#define VID_J_INT_SSTAT 0x0400BC /* Video J interrupt set status */ + +#define FLD_VID_SRC_OPC_ERR 0x00020000 +#define FLD_VID_DST_OPC_ERR 0x00010000 +#define FLD_VID_SRC_SYNC 0x00002000 +#define FLD_VID_DST_SYNC 0x00001000 +#define FLD_VID_SRC_UF 0x00000200 +#define FLD_VID_DST_OF 0x00000100 +#define FLD_VID_SRC_RISC2 0x00000020 +#define FLD_VID_DST_RISC2 0x00000010 +#define FLD_VID_SRC_RISC1 0x00000002 +#define FLD_VID_DST_RISC1 0x00000001 +#define FLD_VID_SRC_ERRORS (FLD_VID_SRC_OPC_ERR | FLD_VID_SRC_SYNC | FLD_VID_SRC_UF) +#define FLD_VID_DST_ERRORS (FLD_VID_DST_OPC_ERR | FLD_VID_DST_SYNC | FLD_VID_DST_OF) + +/* ***************************************************************************** */ +#define AUD_A_INT_MSK 0x0400C0 /* Audio Int interrupt mask */ +#define AUD_A_INT_STAT 0x0400C4 /* Audio Int interrupt status */ +#define AUD_A_INT_MSTAT 0x0400C8 /* Audio Int interrupt masked status */ +#define AUD_A_INT_SSTAT 0x0400CC /* Audio Int interrupt set status */ + +/* ***************************************************************************** */ +#define AUD_B_INT_MSK 0x0400D0 /* Audio Int interrupt mask */ +#define AUD_B_INT_STAT 0x0400D4 /* Audio Int interrupt status */ +#define AUD_B_INT_MSTAT 0x0400D8 /* Audio Int interrupt masked status */ +#define AUD_B_INT_SSTAT 0x0400DC /* Audio Int interrupt set status */ + +/* ***************************************************************************** */ +#define AUD_C_INT_MSK 0x0400E0 /* Audio Int interrupt mask */ +#define AUD_C_INT_STAT 0x0400E4 /* Audio Int interrupt status */ +#define AUD_C_INT_MSTAT 0x0400E8 /* Audio Int interrupt masked status */ +#define AUD_C_INT_SSTAT 0x0400EC /* Audio Int interrupt set status */ + +/* ***************************************************************************** */ +#define AUD_D_INT_MSK 0x0400F0 /* Audio Int interrupt mask */ +#define AUD_D_INT_STAT 0x0400F4 /* Audio Int interrupt status */ +#define AUD_D_INT_MSTAT 0x0400F8 /* Audio Int interrupt masked status */ +#define AUD_D_INT_SSTAT 0x0400FC /* Audio Int interrupt set status */ + +/* ***************************************************************************** */ +#define AUD_E_INT_MSK 0x040100 /* Audio Int interrupt mask */ +#define AUD_E_INT_STAT 0x040104 /* Audio Int interrupt status */ +#define AUD_E_INT_MSTAT 0x040108 /* Audio Int interrupt masked status */ +#define AUD_E_INT_SSTAT 0x04010C /* Audio Int interrupt set status */ + +#define FLD_AUD_SRC_OPC_ERR 0x00020000 +#define FLD_AUD_DST_OPC_ERR 0x00010000 +#define FLD_AUD_SRC_SYNC 0x00002000 +#define FLD_AUD_DST_SYNC 0x00001000 +#define FLD_AUD_SRC_OF 0x00000200 +#define FLD_AUD_DST_OF 0x00000100 +#define FLD_AUD_SRC_RISCI2 0x00000020 +#define FLD_AUD_DST_RISCI2 0x00000010 +#define FLD_AUD_SRC_RISCI1 0x00000002 +#define FLD_AUD_DST_RISCI1 0x00000001 + +/* ***************************************************************************** */ +#define MBIF_A_INT_MSK 0x040110 /* MBIF Int interrupt mask */ +#define MBIF_A_INT_STAT 0x040114 /* MBIF Int interrupt status */ +#define MBIF_A_INT_MSTAT 0x040118 /* MBIF Int interrupt masked status */ +#define MBIF_A_INT_SSTAT 0x04011C /* MBIF Int interrupt set status */ + +/* ***************************************************************************** */ +#define MBIF_B_INT_MSK 0x040120 /* MBIF Int interrupt mask */ +#define MBIF_B_INT_STAT 0x040124 /* MBIF Int interrupt status */ +#define MBIF_B_INT_MSTAT 0x040128 /* MBIF Int interrupt masked status */ +#define MBIF_B_INT_SSTAT 0x04012C /* MBIF Int interrupt set status */ + +#define FLD_MBIF_DST_OPC_ERR 0x00010000 +#define FLD_MBIF_DST_SYNC 0x00001000 +#define FLD_MBIF_DST_OF 0x00000100 +#define FLD_MBIF_DST_RISCI2 0x00000010 +#define FLD_MBIF_DST_RISCI1 0x00000001 + +/* ***************************************************************************** */ +#define AUD_EXT_INT_MSK 0x040060 /* Audio Ext interrupt mask */ +#define AUD_EXT_INT_STAT 0x040064 /* Audio Ext interrupt status */ +#define AUD_EXT_INT_MSTAT 0x040068 /* Audio Ext interrupt masked status */ +#define AUD_EXT_INT_SSTAT 0x04006C /* Audio Ext interrupt set status */ +#define FLD_AUD_EXT_OPC_ERR 0x00010000 +#define FLD_AUD_EXT_SYNC 0x00001000 +#define FLD_AUD_EXT_OF 0x00000100 +#define FLD_AUD_EXT_RISCI2 0x00000010 +#define FLD_AUD_EXT_RISCI1 0x00000001 + +/* ***************************************************************************** */ +#define GPIO_LO 0x110010 /* Lower of GPIO pins [31:0] */ +#define GPIO_HI 0x110014 /* Upper WORD of GPIO pins [47:31] */ + +#define GPIO_LO_OE 0x110018 /* Lower of GPIO output enable [31:0] */ +#define GPIO_HI_OE 0x11001C /* Upper word of GPIO output enable [47:32] */ + +#define GPIO_LO_INT_MSK 0x11003C /* GPIO interrupt mask */ +#define GPIO_LO_INT_STAT 0x110044 /* GPIO interrupt status */ +#define GPIO_LO_INT_MSTAT 0x11004C /* GPIO interrupt masked status */ +#define GPIO_LO_ISM_SNS 0x110054 /* GPIO interrupt sensitivity */ +#define GPIO_LO_ISM_POL 0x11005C /* GPIO interrupt polarity */ + +#define GPIO_HI_INT_MSK 0x110040 /* GPIO interrupt mask */ +#define GPIO_HI_INT_STAT 0x110048 /* GPIO interrupt status */ +#define GPIO_HI_INT_MSTAT 0x110050 /* GPIO interrupt masked status */ +#define GPIO_HI_ISM_SNS 0x110058 /* GPIO interrupt sensitivity */ +#define GPIO_HI_ISM_POL 0x110060 /* GPIO interrupt polarity */ + +#define FLD_GPIO43_INT (1 << 11) +#define FLD_GPIO42_INT (1 << 10) +#define FLD_GPIO41_INT (1 << 9) +#define FLD_GPIO40_INT (1 << 8) + +#define FLD_GPIO9_INT (1 << 9) +#define FLD_GPIO8_INT (1 << 8) +#define FLD_GPIO7_INT (1 << 7) +#define FLD_GPIO6_INT (1 << 6) +#define FLD_GPIO5_INT (1 << 5) +#define FLD_GPIO4_INT (1 << 4) +#define FLD_GPIO3_INT (1 << 3) +#define FLD_GPIO2_INT (1 << 2) +#define FLD_GPIO1_INT (1 << 1) +#define FLD_GPIO0_INT (1 << 0) + +/* ***************************************************************************** */ +#define TC_REQ 0x040090 /* Rider PCI Express traFFic class request */ + +/* ***************************************************************************** */ +#define TC_REQ_SET 0x040094 /* Rider PCI Express traFFic class request set */ + +/* ***************************************************************************** */ +/* Rider */ +/* ***************************************************************************** */ + +/* PCI Compatible Header */ +/* ***************************************************************************** */ +#define RDR_CFG0 0x050000 +#define RDR_VENDOR_DEVICE_ID_CFG 0x050000 + +/* ***************************************************************************** */ +#define RDR_CFG1 0x050004 + +/* ***************************************************************************** */ +#define RDR_CFG2 0x050008 + +/* ***************************************************************************** */ +#define RDR_CFG3 0x05000C + +/* ***************************************************************************** */ +#define RDR_CFG4 0x050010 + +/* ***************************************************************************** */ +#define RDR_CFG5 0x050014 + +/* ***************************************************************************** */ +#define RDR_CFG6 0x050018 + +/* ***************************************************************************** */ +#define RDR_CFG7 0x05001C + +/* ***************************************************************************** */ +#define RDR_CFG8 0x050020 + +/* ***************************************************************************** */ +#define RDR_CFG9 0x050024 + +/* ***************************************************************************** */ +#define RDR_CFGA 0x050028 + +/* ***************************************************************************** */ +#define RDR_CFGB 0x05002C +#define RDR_SUSSYSTEM_ID_CFG 0x05002C + +/* ***************************************************************************** */ +#define RDR_CFGC 0x050030 + +/* ***************************************************************************** */ +#define RDR_CFGD 0x050034 + +/* ***************************************************************************** */ +#define RDR_CFGE 0x050038 + +/* ***************************************************************************** */ +#define RDR_CFGF 0x05003C + +/* ***************************************************************************** */ +/* PCI-Express Capabilities */ +/* ***************************************************************************** */ +#define RDR_PECAP 0x050040 + +/* ***************************************************************************** */ +#define RDR_PEDEVCAP 0x050044 + +/* ***************************************************************************** */ +#define RDR_PEDEVSC 0x050048 + +/* ***************************************************************************** */ +#define RDR_PELINKCAP 0x05004C + +/* ***************************************************************************** */ +#define RDR_PELINKSC 0x050050 + +/* ***************************************************************************** */ +#define RDR_PMICAP 0x050080 + +/* ***************************************************************************** */ +#define RDR_PMCSR 0x050084 + +/* ***************************************************************************** */ +#define RDR_VPDCAP 0x050090 + +/* ***************************************************************************** */ +#define RDR_VPDDATA 0x050094 + +/* ***************************************************************************** */ +#define RDR_MSICAP 0x0500A0 + +/* ***************************************************************************** */ +#define RDR_MSIARL 0x0500A4 + +/* ***************************************************************************** */ +#define RDR_MSIARU 0x0500A8 + +/* ***************************************************************************** */ +#define RDR_MSIDATA 0x0500AC + +/* ***************************************************************************** */ +/* PCI Express Extended Capabilities */ +/* ***************************************************************************** */ +#define RDR_AERXCAP 0x050100 + +/* ***************************************************************************** */ +#define RDR_AERUESTA 0x050104 + +/* ***************************************************************************** */ +#define RDR_AERUEMSK 0x050108 + +/* ***************************************************************************** */ +#define RDR_AERUESEV 0x05010C + +/* ***************************************************************************** */ +#define RDR_AERCESTA 0x050110 + +/* ***************************************************************************** */ +#define RDR_AERCEMSK 0x050114 + +/* ***************************************************************************** */ +#define RDR_AERCC 0x050118 + +/* ***************************************************************************** */ +#define RDR_AERHL0 0x05011C + +/* ***************************************************************************** */ +#define RDR_AERHL1 0x050120 + +/* ***************************************************************************** */ +#define RDR_AERHL2 0x050124 + +/* ***************************************************************************** */ +#define RDR_AERHL3 0x050128 + +/* ***************************************************************************** */ +#define RDR_VCXCAP 0x050200 + +/* ***************************************************************************** */ +#define RDR_VCCAP1 0x050204 + +/* ***************************************************************************** */ +#define RDR_VCCAP2 0x050208 + +/* ***************************************************************************** */ +#define RDR_VCSC 0x05020C + +/* ***************************************************************************** */ +#define RDR_VCR0_CAP 0x050210 + +/* ***************************************************************************** */ +#define RDR_VCR0_CTRL 0x050214 + +/* ***************************************************************************** */ +#define RDR_VCR0_STAT 0x050218 + +/* ***************************************************************************** */ +#define RDR_VCR1_CAP 0x05021C + +/* ***************************************************************************** */ +#define RDR_VCR1_CTRL 0x050220 + +/* ***************************************************************************** */ +#define RDR_VCR1_STAT 0x050224 + +/* ***************************************************************************** */ +#define RDR_VCR2_CAP 0x050228 + +/* ***************************************************************************** */ +#define RDR_VCR2_CTRL 0x05022C + +/* ***************************************************************************** */ +#define RDR_VCR2_STAT 0x050230 + +/* ***************************************************************************** */ +#define RDR_VCR3_CAP 0x050234 + +/* ***************************************************************************** */ +#define RDR_VCR3_CTRL 0x050238 + +/* ***************************************************************************** */ +#define RDR_VCR3_STAT 0x05023C + +/* ***************************************************************************** */ +#define RDR_VCARB0 0x050240 + +/* ***************************************************************************** */ +#define RDR_VCARB1 0x050244 + +/* ***************************************************************************** */ +#define RDR_VCARB2 0x050248 + +/* ***************************************************************************** */ +#define RDR_VCARB3 0x05024C + +/* ***************************************************************************** */ +#define RDR_VCARB4 0x050250 + +/* ***************************************************************************** */ +#define RDR_VCARB5 0x050254 + +/* ***************************************************************************** */ +#define RDR_VCARB6 0x050258 + +/* ***************************************************************************** */ +#define RDR_VCARB7 0x05025C + +/* ***************************************************************************** */ +#define RDR_RDRSTAT0 0x050300 + +/* ***************************************************************************** */ +#define RDR_RDRSTAT1 0x050304 + +/* ***************************************************************************** */ +#define RDR_RDRCTL0 0x050308 + +/* ***************************************************************************** */ +#define RDR_RDRCTL1 0x05030C + +/* ***************************************************************************** */ +/* Transaction Layer Registers */ +/* ***************************************************************************** */ +#define RDR_TLSTAT0 0x050310 + +/* ***************************************************************************** */ +#define RDR_TLSTAT1 0x050314 + +/* ***************************************************************************** */ +#define RDR_TLCTL0 0x050318 +#define FLD_CFG_UR_CPL_MODE 0x00000040 +#define FLD_CFG_CORR_ERR_QUITE 0x00000020 +#define FLD_CFG_RCB_CK_EN 0x00000010 +#define FLD_CFG_BNDRY_CK_EN 0x00000008 +#define FLD_CFG_BYTE_EN_CK_EN 0x00000004 +#define FLD_CFG_RELAX_ORDER_MSK 0x00000002 +#define FLD_CFG_TAG_ORDER_EN 0x00000001 + +/* ***************************************************************************** */ +#define RDR_TLCTL1 0x05031C + +/* ***************************************************************************** */ +#define RDR_REQRCAL 0x050320 + +/* ***************************************************************************** */ +#define RDR_REQRCAU 0x050324 + +/* ***************************************************************************** */ +#define RDR_REQEPA 0x050328 + +/* ***************************************************************************** */ +#define RDR_REQCTRL 0x05032C + +/* ***************************************************************************** */ +#define RDR_REQSTAT 0x050330 + +/* ***************************************************************************** */ +#define RDR_TL_TEST 0x050334 + +/* ***************************************************************************** */ +#define RDR_VCR01_CTL 0x050348 + +/* ***************************************************************************** */ +#define RDR_VCR23_CTL 0x05034C + +/* ***************************************************************************** */ +#define RDR_RX_VCR0_FC 0x050350 + +/* ***************************************************************************** */ +#define RDR_RX_VCR1_FC 0x050354 + +/* ***************************************************************************** */ +#define RDR_RX_VCR2_FC 0x050358 + +/* ***************************************************************************** */ +#define RDR_RX_VCR3_FC 0x05035C + +/* ***************************************************************************** */ +/* Data Link Layer Registers */ +/* ***************************************************************************** */ +#define RDR_DLLSTAT 0x050360 + +/* ***************************************************************************** */ +#define RDR_DLLCTRL 0x050364 + +/* ***************************************************************************** */ +#define RDR_REPLAYTO 0x050368 + +/* ***************************************************************************** */ +#define RDR_ACKLATTO 0x05036C + +/* ***************************************************************************** */ +/* MAC Layer Registers */ +/* ***************************************************************************** */ +#define RDR_MACSTAT0 0x050380 + +/* ***************************************************************************** */ +#define RDR_MACSTAT1 0x050384 + +/* ***************************************************************************** */ +#define RDR_MACCTRL0 0x050388 + +/* ***************************************************************************** */ +#define RDR_MACCTRL1 0x05038C + +/* ***************************************************************************** */ +#define RDR_MACCTRL2 0x050390 + +/* ***************************************************************************** */ +#define RDR_MAC_LB_DATA 0x050394 + +/* ***************************************************************************** */ +#define RDR_L0S_EXIT_LAT 0x050398 + +/* ***************************************************************************** */ +/* DMAC */ +/* ***************************************************************************** */ +#define DMA1_PTR1 0x100000 /* DMA Current Ptr : Ch#1 */ + +/* ***************************************************************************** */ +#define DMA2_PTR1 0x100004 /* DMA Current Ptr : Ch#2 */ + +/* ***************************************************************************** */ +#define DMA3_PTR1 0x100008 /* DMA Current Ptr : Ch#3 */ + +/* ***************************************************************************** */ +#define DMA4_PTR1 0x10000C /* DMA Current Ptr : Ch#4 */ + +/* ***************************************************************************** */ +#define DMA5_PTR1 0x100010 /* DMA Current Ptr : Ch#5 */ + +/* ***************************************************************************** */ +#define DMA6_PTR1 0x100014 /* DMA Current Ptr : Ch#6 */ + +/* ***************************************************************************** */ +#define DMA7_PTR1 0x100018 /* DMA Current Ptr : Ch#7 */ + +/* ***************************************************************************** */ +#define DMA8_PTR1 0x10001C /* DMA Current Ptr : Ch#8 */ + +/* ***************************************************************************** */ +#define DMA9_PTR1 0x100020 /* DMA Current Ptr : Ch#9 */ + +/* ***************************************************************************** */ +#define DMA10_PTR1 0x100024 /* DMA Current Ptr : Ch#10 */ + +/* ***************************************************************************** */ +#define DMA11_PTR1 0x100028 /* DMA Current Ptr : Ch#11 */ + +/* ***************************************************************************** */ +#define DMA12_PTR1 0x10002C /* DMA Current Ptr : Ch#12 */ + +/* ***************************************************************************** */ +#define DMA13_PTR1 0x100030 /* DMA Current Ptr : Ch#13 */ + +/* ***************************************************************************** */ +#define DMA14_PTR1 0x100034 /* DMA Current Ptr : Ch#14 */ + +/* ***************************************************************************** */ +#define DMA15_PTR1 0x100038 /* DMA Current Ptr : Ch#15 */ + +/* ***************************************************************************** */ +#define DMA16_PTR1 0x10003C /* DMA Current Ptr : Ch#16 */ + +/* ***************************************************************************** */ +#define DMA17_PTR1 0x100040 /* DMA Current Ptr : Ch#17 */ + +/* ***************************************************************************** */ +#define DMA18_PTR1 0x100044 /* DMA Current Ptr : Ch#18 */ + +/* ***************************************************************************** */ +#define DMA19_PTR1 0x100048 /* DMA Current Ptr : Ch#19 */ + +/* ***************************************************************************** */ +#define DMA20_PTR1 0x10004C /* DMA Current Ptr : Ch#20 */ + +/* ***************************************************************************** */ +#define DMA21_PTR1 0x100050 /* DMA Current Ptr : Ch#21 */ + +/* ***************************************************************************** */ +#define DMA22_PTR1 0x100054 /* DMA Current Ptr : Ch#22 */ + +/* ***************************************************************************** */ +#define DMA23_PTR1 0x100058 /* DMA Current Ptr : Ch#23 */ + +/* ***************************************************************************** */ +#define DMA24_PTR1 0x10005C /* DMA Current Ptr : Ch#24 */ + +/* ***************************************************************************** */ +#define DMA25_PTR1 0x100060 /* DMA Current Ptr : Ch#25 */ + +/* ***************************************************************************** */ +#define DMA26_PTR1 0x100064 /* DMA Current Ptr : Ch#26 */ + +/* ***************************************************************************** */ +#define DMA1_PTR2 0x100080 /* DMA Tab Ptr : Ch#1 */ + +/* ***************************************************************************** */ +#define DMA2_PTR2 0x100084 /* DMA Tab Ptr : Ch#2 */ + +/* ***************************************************************************** */ +#define DMA3_PTR2 0x100088 /* DMA Tab Ptr : Ch#3 */ + +/* ***************************************************************************** */ +#define DMA4_PTR2 0x10008C /* DMA Tab Ptr : Ch#4 */ + +/* ***************************************************************************** */ +#define DMA5_PTR2 0x100090 /* DMA Tab Ptr : Ch#5 */ + +/* ***************************************************************************** */ +#define DMA6_PTR2 0x100094 /* DMA Tab Ptr : Ch#6 */ + +/* ***************************************************************************** */ +#define DMA7_PTR2 0x100098 /* DMA Tab Ptr : Ch#7 */ + +/* ***************************************************************************** */ +#define DMA8_PTR2 0x10009C /* DMA Tab Ptr : Ch#8 */ + +/* ***************************************************************************** */ +#define DMA9_PTR2 0x1000A0 /* DMA Tab Ptr : Ch#9 */ + +/* ***************************************************************************** */ +#define DMA10_PTR2 0x1000A4 /* DMA Tab Ptr : Ch#10 */ + +/* ***************************************************************************** */ +#define DMA11_PTR2 0x1000A8 /* DMA Tab Ptr : Ch#11 */ + +/* ***************************************************************************** */ +#define DMA12_PTR2 0x1000AC /* DMA Tab Ptr : Ch#12 */ + +/* ***************************************************************************** */ +#define DMA13_PTR2 0x1000B0 /* DMA Tab Ptr : Ch#13 */ + +/* ***************************************************************************** */ +#define DMA14_PTR2 0x1000B4 /* DMA Tab Ptr : Ch#14 */ + +/* ***************************************************************************** */ +#define DMA15_PTR2 0x1000B8 /* DMA Tab Ptr : Ch#15 */ + +/* ***************************************************************************** */ +#define DMA16_PTR2 0x1000BC /* DMA Tab Ptr : Ch#16 */ + +/* ***************************************************************************** */ +#define DMA17_PTR2 0x1000C0 /* DMA Tab Ptr : Ch#17 */ + +/* ***************************************************************************** */ +#define DMA18_PTR2 0x1000C4 /* DMA Tab Ptr : Ch#18 */ + +/* ***************************************************************************** */ +#define DMA19_PTR2 0x1000C8 /* DMA Tab Ptr : Ch#19 */ + +/* ***************************************************************************** */ +#define DMA20_PTR2 0x1000CC /* DMA Tab Ptr : Ch#20 */ + +/* ***************************************************************************** */ +#define DMA21_PTR2 0x1000D0 /* DMA Tab Ptr : Ch#21 */ + +/* ***************************************************************************** */ +#define DMA22_PTR2 0x1000D4 /* DMA Tab Ptr : Ch#22 */ + +/* ***************************************************************************** */ +#define DMA23_PTR2 0x1000D8 /* DMA Tab Ptr : Ch#23 */ + +/* ***************************************************************************** */ +#define DMA24_PTR2 0x1000DC /* DMA Tab Ptr : Ch#24 */ + +/* ***************************************************************************** */ +#define DMA25_PTR2 0x1000E0 /* DMA Tab Ptr : Ch#25 */ + +/* ***************************************************************************** */ +#define DMA26_PTR2 0x1000E4 /* DMA Tab Ptr : Ch#26 */ + +/* ***************************************************************************** */ +#define DMA1_CNT1 0x100100 /* DMA BuFFer Size : Ch#1 */ + +/* ***************************************************************************** */ +#define DMA2_CNT1 0x100104 /* DMA BuFFer Size : Ch#2 */ + +/* ***************************************************************************** */ +#define DMA3_CNT1 0x100108 /* DMA BuFFer Size : Ch#3 */ + +/* ***************************************************************************** */ +#define DMA4_CNT1 0x10010C /* DMA BuFFer Size : Ch#4 */ + +/* ***************************************************************************** */ +#define DMA5_CNT1 0x100110 /* DMA BuFFer Size : Ch#5 */ + +/* ***************************************************************************** */ +#define DMA6_CNT1 0x100114 /* DMA BuFFer Size : Ch#6 */ + +/* ***************************************************************************** */ +#define DMA7_CNT1 0x100118 /* DMA BuFFer Size : Ch#7 */ + +/* ***************************************************************************** */ +#define DMA8_CNT1 0x10011C /* DMA BuFFer Size : Ch#8 */ + +/* ***************************************************************************** */ +#define DMA9_CNT1 0x100120 /* DMA BuFFer Size : Ch#9 */ + +/* ***************************************************************************** */ +#define DMA10_CNT1 0x100124 /* DMA BuFFer Size : Ch#10 */ + +/* ***************************************************************************** */ +#define DMA11_CNT1 0x100128 /* DMA BuFFer Size : Ch#11 */ + +/* ***************************************************************************** */ +#define DMA12_CNT1 0x10012C /* DMA BuFFer Size : Ch#12 */ + +/* ***************************************************************************** */ +#define DMA13_CNT1 0x100130 /* DMA BuFFer Size : Ch#13 */ + +/* ***************************************************************************** */ +#define DMA14_CNT1 0x100134 /* DMA BuFFer Size : Ch#14 */ + +/* ***************************************************************************** */ +#define DMA15_CNT1 0x100138 /* DMA BuFFer Size : Ch#15 */ + +/* ***************************************************************************** */ +#define DMA16_CNT1 0x10013C /* DMA BuFFer Size : Ch#16 */ + +/* ***************************************************************************** */ +#define DMA17_CNT1 0x100140 /* DMA BuFFer Size : Ch#17 */ + +/* ***************************************************************************** */ +#define DMA18_CNT1 0x100144 /* DMA BuFFer Size : Ch#18 */ + +/* ***************************************************************************** */ +#define DMA19_CNT1 0x100148 /* DMA BuFFer Size : Ch#19 */ + +/* ***************************************************************************** */ +#define DMA20_CNT1 0x10014C /* DMA BuFFer Size : Ch#20 */ + +/* ***************************************************************************** */ +#define DMA21_CNT1 0x100150 /* DMA BuFFer Size : Ch#21 */ + +/* ***************************************************************************** */ +#define DMA22_CNT1 0x100154 /* DMA BuFFer Size : Ch#22 */ + +/* ***************************************************************************** */ +#define DMA23_CNT1 0x100158 /* DMA BuFFer Size : Ch#23 */ + +/* ***************************************************************************** */ +#define DMA24_CNT1 0x10015C /* DMA BuFFer Size : Ch#24 */ + +/* ***************************************************************************** */ +#define DMA25_CNT1 0x100160 /* DMA BuFFer Size : Ch#25 */ + +/* ***************************************************************************** */ +#define DMA26_CNT1 0x100164 /* DMA BuFFer Size : Ch#26 */ + +/* ***************************************************************************** */ +#define DMA1_CNT2 0x100180 /* DMA Table Size : Ch#1 */ + +/* ***************************************************************************** */ +#define DMA2_CNT2 0x100184 /* DMA Table Size : Ch#2 */ + +/* ***************************************************************************** */ +#define DMA3_CNT2 0x100188 /* DMA Table Size : Ch#3 */ + +/* ***************************************************************************** */ +#define DMA4_CNT2 0x10018C /* DMA Table Size : Ch#4 */ + +/* ***************************************************************************** */ +#define DMA5_CNT2 0x100190 /* DMA Table Size : Ch#5 */ + +/* ***************************************************************************** */ +#define DMA6_CNT2 0x100194 /* DMA Table Size : Ch#6 */ + +/* ***************************************************************************** */ +#define DMA7_CNT2 0x100198 /* DMA Table Size : Ch#7 */ + +/* ***************************************************************************** */ +#define DMA8_CNT2 0x10019C /* DMA Table Size : Ch#8 */ + +/* ***************************************************************************** */ +#define DMA9_CNT2 0x1001A0 /* DMA Table Size : Ch#9 */ + +/* ***************************************************************************** */ +#define DMA10_CNT2 0x1001A4 /* DMA Table Size : Ch#10 */ + +/* ***************************************************************************** */ +#define DMA11_CNT2 0x1001A8 /* DMA Table Size : Ch#11 */ + +/* ***************************************************************************** */ +#define DMA12_CNT2 0x1001AC /* DMA Table Size : Ch#12 */ + +/* ***************************************************************************** */ +#define DMA13_CNT2 0x1001B0 /* DMA Table Size : Ch#13 */ + +/* ***************************************************************************** */ +#define DMA14_CNT2 0x1001B4 /* DMA Table Size : Ch#14 */ + +/* ***************************************************************************** */ +#define DMA15_CNT2 0x1001B8 /* DMA Table Size : Ch#15 */ + +/* ***************************************************************************** */ +#define DMA16_CNT2 0x1001BC /* DMA Table Size : Ch#16 */ + +/* ***************************************************************************** */ +#define DMA17_CNT2 0x1001C0 /* DMA Table Size : Ch#17 */ + +/* ***************************************************************************** */ +#define DMA18_CNT2 0x1001C4 /* DMA Table Size : Ch#18 */ + +/* ***************************************************************************** */ +#define DMA19_CNT2 0x1001C8 /* DMA Table Size : Ch#19 */ + +/* ***************************************************************************** */ +#define DMA20_CNT2 0x1001CC /* DMA Table Size : Ch#20 */ + +/* ***************************************************************************** */ +#define DMA21_CNT2 0x1001D0 /* DMA Table Size : Ch#21 */ + +/* ***************************************************************************** */ +#define DMA22_CNT2 0x1001D4 /* DMA Table Size : Ch#22 */ + +/* ***************************************************************************** */ +#define DMA23_CNT2 0x1001D8 /* DMA Table Size : Ch#23 */ + +/* ***************************************************************************** */ +#define DMA24_CNT2 0x1001DC /* DMA Table Size : Ch#24 */ + +/* ***************************************************************************** */ +#define DMA25_CNT2 0x1001E0 /* DMA Table Size : Ch#25 */ + +/* ***************************************************************************** */ +#define DMA26_CNT2 0x1001E4 /* DMA Table Size : Ch#26 */ + +/* ***************************************************************************** */ + /* ITG */ +/* ***************************************************************************** */ +#define TM_CNT_LDW 0x110000 /* Timer : Counter low */ + +/* ***************************************************************************** */ +#define TM_CNT_UW 0x110004 /* Timer : Counter high word */ + +/* ***************************************************************************** */ +#define TM_LMT_LDW 0x110008 /* Timer : Limit low */ + +/* ***************************************************************************** */ +#define TM_LMT_UW 0x11000C /* Timer : Limit high word */ + +/* ***************************************************************************** */ +#define GP0_IO 0x110010 /* GPIO output enables data I/O */ +#define FLD_GP_OE 0x00FF0000 /* GPIO: GP_OE output enable */ +#define FLD_GP_IN 0x0000FF00 /* GPIO: GP_IN status */ +#define FLD_GP_OUT 0x000000FF /* GPIO: GP_OUT control */ + +/* ***************************************************************************** */ +#define GPIO_ISM 0x110014 /* GPIO interrupt sensitivity mode */ +#define FLD_GP_ISM_SNS 0x00000070 +#define FLD_GP_ISM_POL 0x00000007 + +/* ***************************************************************************** */ +#define SOFT_RESET 0x11001C /* Output system reset reg */ +#define FLD_PECOS_SOFT_RESET 0x00000001 + +/* ***************************************************************************** */ +#define MC416_RWD 0x110020 /* MC416 GPIO[18:3] pin */ +#define MC416_OEN 0x110024 /* Output enable of GPIO[18:3] */ +#define MC416_CTL 0x110028 + +/* ***************************************************************************** */ +#define ALT_PIN_OUT_SEL 0x11002C /* Alternate GPIO output select */ + +#define FLD_ALT_GPIO_OUT_SEL 0xF0000000 +/* 0 Disabled <-- default */ +/* 1 GPIO[0] */ +/* 2 GPIO[10] */ +/* 3 VIP_656_DATA_VAL */ +/* 4 VIP_656_DATA[0] */ +/* 5 VIP_656_CLK */ +/* 6 VIP_656_DATA_EXT[1] */ +/* 7 VIP_656_DATA_EXT[0] */ +/* 8 ATT_IF */ + +#define FLD_AUX_PLL_CLK_ALT_SEL 0x0F000000 +/* 0 AUX_PLL_CLK<-- default */ +/* 1 GPIO[2] */ +/* 2 GPIO[10] */ +/* 3 VIP_656_DATA_VAL */ +/* 4 VIP_656_DATA[0] */ +/* 5 VIP_656_CLK */ +/* 6 VIP_656_DATA_EXT[1] */ +/* 7 VIP_656_DATA_EXT[0] */ + +#define FLD_IR_TX_ALT_SEL 0x00F00000 +/* 0 IR_TX <-- default */ +/* 1 GPIO[1] */ +/* 2 GPIO[10] */ +/* 3 VIP_656_DATA_VAL */ +/* 4 VIP_656_DATA[0] */ +/* 5 VIP_656_CLK */ +/* 6 VIP_656_DATA_EXT[1] */ +/* 7 VIP_656_DATA_EXT[0] */ + +#define FLD_IR_RX_ALT_SEL 0x000F0000 +/* 0 IR_RX <-- default */ +/* 1 GPIO[0] */ +/* 2 GPIO[10] */ +/* 3 VIP_656_DATA_VAL */ +/* 4 VIP_656_DATA[0] */ +/* 5 VIP_656_CLK */ +/* 6 VIP_656_DATA_EXT[1] */ +/* 7 VIP_656_DATA_EXT[0] */ + +#define FLD_GPIO10_ALT_SEL 0x0000F000 +/* 0 GPIO[10] <-- default */ +/* 1 GPIO[0] */ +/* 2 GPIO[10] */ +/* 3 VIP_656_DATA_VAL */ +/* 4 VIP_656_DATA[0] */ +/* 5 VIP_656_CLK */ +/* 6 VIP_656_DATA_EXT[1] */ +/* 7 VIP_656_DATA_EXT[0] */ + +#define FLD_GPIO2_ALT_SEL 0x00000F00 +/* 0 GPIO[2] <-- default */ +/* 1 GPIO[1] */ +/* 2 GPIO[10] */ +/* 3 VIP_656_DATA_VAL */ +/* 4 VIP_656_DATA[0] */ +/* 5 VIP_656_CLK */ +/* 6 VIP_656_DATA_EXT[1] */ +/* 7 VIP_656_DATA_EXT[0] */ + +#define FLD_GPIO1_ALT_SEL 0x000000F0 +/* 0 GPIO[1] <-- default */ +/* 1 GPIO[0] */ +/* 2 GPIO[10] */ +/* 3 VIP_656_DATA_VAL */ +/* 4 VIP_656_DATA[0] */ +/* 5 VIP_656_CLK */ +/* 6 VIP_656_DATA_EXT[1] */ +/* 7 VIP_656_DATA_EXT[0] */ + +#define FLD_GPIO0_ALT_SEL 0x0000000F +/* 0 GPIO[0] <-- default */ +/* 1 GPIO[1] */ +/* 2 GPIO[10] */ +/* 3 VIP_656_DATA_VAL */ +/* 4 VIP_656_DATA[0] */ +/* 5 VIP_656_CLK */ +/* 6 VIP_656_DATA_EXT[1] */ +/* 7 VIP_656_DATA_EXT[0] */ + +#define ALT_PIN_IN_SEL 0x110030 /* Alternate GPIO input select */ + +#define FLD_GPIO10_ALT_IN_SEL 0x0000F000 +/* 0 GPIO[10] <-- default */ +/* 1 IR_RX */ +/* 2 IR_TX */ +/* 3 AUX_PLL_CLK */ +/* 4 IF_ATT_SEL */ +/* 5 GPIO[0] */ +/* 6 GPIO[1] */ +/* 7 GPIO[2] */ + +#define FLD_GPIO2_ALT_IN_SEL 0x00000F00 +/* 0 GPIO[2] <-- default */ +/* 1 IR_RX */ +/* 2 IR_TX */ +/* 3 AUX_PLL_CLK */ +/* 4 IF_ATT_SEL */ + +#define FLD_GPIO1_ALT_IN_SEL 0x000000F0 +/* 0 GPIO[1] <-- default */ +/* 1 IR_RX */ +/* 2 IR_TX */ +/* 3 AUX_PLL_CLK */ +/* 4 IF_ATT_SEL */ + +#define FLD_GPIO0_ALT_IN_SEL 0x0000000F +/* 0 GPIO[0] <-- default */ +/* 1 IR_RX */ +/* 2 IR_TX */ +/* 3 AUX_PLL_CLK */ +/* 4 IF_ATT_SEL */ + +/* ***************************************************************************** */ +#define TEST_BUS_CTL1 0x110040 /* Test bus control register #1 */ + +/* ***************************************************************************** */ +#define TEST_BUS_CTL2 0x110044 /* Test bus control register #2 */ + +/* ***************************************************************************** */ +#define CLK_DELAY 0x110048 /* Clock delay */ +#define FLD_MOE_CLK_DIS 0x80000000 /* Disable MoE clock */ + +/* ***************************************************************************** */ +#define PAD_CTRL 0x110068 /* Pad drive strength control */ + +/* ***************************************************************************** */ +#define MBIST_CTRL 0x110050 /* SRAM memory built-in self test control */ + +/* ***************************************************************************** */ +#define MBIST_STAT 0x110054 /* SRAM memory built-in self test status */ + +/* ***************************************************************************** */ +/* PLL registers */ +/* ***************************************************************************** */ +#define PLL_A_INT_FRAC 0x110088 +#define PLL_A_POST_STAT_BIST 0x11008C +#define PLL_B_INT_FRAC 0x110090 +#define PLL_B_POST_STAT_BIST 0x110094 +#define PLL_C_INT_FRAC 0x110098 +#define PLL_C_POST_STAT_BIST 0x11009C +#define PLL_D_INT_FRAC 0x1100A0 +#define PLL_D_POST_STAT_BIST 0x1100A4 + +#define CLK_RST 0x11002C +#define FLD_VID_I_CLK_NOE 0x00001000 +#define FLD_VID_J_CLK_NOE 0x00002000 +#define FLD_USE_ALT_PLL_REF 0x00004000 + +#define VID_CH_MODE_SEL 0x110078 +#define VID_CH_CLK_SEL 0x11007C + +/* ***************************************************************************** */ +#define VBI_A_DMA 0x130008 /* VBI A DMA data port */ + +/* ***************************************************************************** */ +#define VID_A_VIP_CTL 0x130080 /* Video A VIP format control */ +#define FLD_VIP_MODE 0x00000001 + +/* ***************************************************************************** */ +#define VID_A_PIXEL_FRMT 0x130084 /* Video A pixel format */ +#define FLD_VID_A_GAMMA_DIS 0x00000008 +#define FLD_VID_A_FORMAT 0x00000007 +#define FLD_VID_A_GAMMA_FACTOR 0x00000010 + +/* ***************************************************************************** */ +#define VID_A_VBI_CTL 0x130088 /* Video A VBI miscellaneous control */ +#define FLD_VID_A_VIP_EXT 0x00000003 + +/* ***************************************************************************** */ +#define VID_B_DMA 0x130100 /* Video B DMA data port */ + +/* ***************************************************************************** */ +#define VBI_B_DMA 0x130108 /* VBI B DMA data port */ + +/* ***************************************************************************** */ +#define VID_B_SRC_SEL 0x130144 /* Video B source select */ +#define FLD_VID_B_SRC_SEL 0x00000000 + +/* ***************************************************************************** */ +#define VID_B_LNGTH 0x130150 /* Video B line length */ +#define FLD_VID_B_LN_LNGTH 0x00000FFF + +/* ***************************************************************************** */ +#define VID_B_VIP_CTL 0x130180 /* Video B VIP format control */ + +/* ***************************************************************************** */ +#define VID_B_PIXEL_FRMT 0x130184 /* Video B pixel format */ +#define FLD_VID_B_GAMMA_DIS 0x00000008 +#define FLD_VID_B_FORMAT 0x00000007 +#define FLD_VID_B_GAMMA_FACTOR 0x00000010 + +/* ***************************************************************************** */ +#define VID_C_DMA 0x130200 /* Video C DMA data port */ + +/* ***************************************************************************** */ +#define VID_C_LNGTH 0x130250 /* Video C line length */ +#define FLD_VID_C_LN_LNGTH 0x00000FFF + +/* ***************************************************************************** */ +/* Video Destination Channels */ +/* ***************************************************************************** */ + +#define VID_DST_A_GPCNT 0x130020 /* Video A general purpose counter */ +#define VID_DST_B_GPCNT 0x130120 /* Video B general purpose counter */ +#define VID_DST_C_GPCNT 0x130220 /* Video C general purpose counter */ +#define VID_DST_D_GPCNT 0x130320 /* Video D general purpose counter */ +#define VID_DST_E_GPCNT 0x130420 /* Video E general purpose counter */ +#define VID_DST_F_GPCNT 0x130520 /* Video F general purpose counter */ +#define VID_DST_G_GPCNT 0x130620 /* Video G general purpose counter */ +#define VID_DST_H_GPCNT 0x130720 /* Video H general purpose counter */ + +/* ***************************************************************************** */ + +#define VID_DST_A_GPCNT_CTL 0x130030 /* Video A general purpose control */ +#define VID_DST_B_GPCNT_CTL 0x130130 /* Video B general purpose control */ +#define VID_DST_C_GPCNT_CTL 0x130230 /* Video C general purpose control */ +#define VID_DST_D_GPCNT_CTL 0x130330 /* Video D general purpose control */ +#define VID_DST_E_GPCNT_CTL 0x130430 /* Video E general purpose control */ +#define VID_DST_F_GPCNT_CTL 0x130530 /* Video F general purpose control */ +#define VID_DST_G_GPCNT_CTL 0x130630 /* Video G general purpose control */ +#define VID_DST_H_GPCNT_CTL 0x130730 /* Video H general purpose control */ + +/* ***************************************************************************** */ + +#define VID_DST_A_DMA_CTL 0x130040 /* Video A DMA control */ +#define VID_DST_B_DMA_CTL 0x130140 /* Video B DMA control */ +#define VID_DST_C_DMA_CTL 0x130240 /* Video C DMA control */ +#define VID_DST_D_DMA_CTL 0x130340 /* Video D DMA control */ +#define VID_DST_E_DMA_CTL 0x130440 /* Video E DMA control */ +#define VID_DST_F_DMA_CTL 0x130540 /* Video F DMA control */ +#define VID_DST_G_DMA_CTL 0x130640 /* Video G DMA control */ +#define VID_DST_H_DMA_CTL 0x130740 /* Video H DMA control */ + +#define FLD_VID_RISC_EN 0x00000010 +#define FLD_VID_FIFO_EN 0x00000001 + +/* ***************************************************************************** */ + +#define VID_DST_A_VIP_CTL 0x130080 /* Video A VIP control */ +#define VID_DST_B_VIP_CTL 0x130180 /* Video B VIP control */ +#define VID_DST_C_VIP_CTL 0x130280 /* Video C VIP control */ +#define VID_DST_D_VIP_CTL 0x130380 /* Video D VIP control */ +#define VID_DST_E_VIP_CTL 0x130480 /* Video E VIP control */ +#define VID_DST_F_VIP_CTL 0x130580 /* Video F VIP control */ +#define VID_DST_G_VIP_CTL 0x130680 /* Video G VIP control */ +#define VID_DST_H_VIP_CTL 0x130780 /* Video H VIP control */ + +/* ***************************************************************************** */ + +#define VID_DST_A_PIX_FRMT 0x130084 /* Video A Pixel format */ +#define VID_DST_B_PIX_FRMT 0x130184 /* Video B Pixel format */ +#define VID_DST_C_PIX_FRMT 0x130284 /* Video C Pixel format */ +#define VID_DST_D_PIX_FRMT 0x130384 /* Video D Pixel format */ +#define VID_DST_E_PIX_FRMT 0x130484 /* Video E Pixel format */ +#define VID_DST_F_PIX_FRMT 0x130584 /* Video F Pixel format */ +#define VID_DST_G_PIX_FRMT 0x130684 /* Video G Pixel format */ +#define VID_DST_H_PIX_FRMT 0x130784 /* Video H Pixel format */ + +/* ***************************************************************************** */ +/* Video Source Channels */ +/* ***************************************************************************** */ + +#define VID_SRC_A_GPCNT_CTL 0x130804 /* Video A general purpose control */ +#define VID_SRC_B_GPCNT_CTL 0x130904 /* Video B general purpose control */ +#define VID_SRC_C_GPCNT_CTL 0x130A04 /* Video C general purpose control */ +#define VID_SRC_D_GPCNT_CTL 0x130B04 /* Video D general purpose control */ +#define VID_SRC_E_GPCNT_CTL 0x130C04 /* Video E general purpose control */ +#define VID_SRC_F_GPCNT_CTL 0x130D04 /* Video F general purpose control */ +#define VID_SRC_I_GPCNT_CTL 0x130E04 /* Video I general purpose control */ +#define VID_SRC_J_GPCNT_CTL 0x130F04 /* Video J general purpose control */ + +/* ***************************************************************************** */ + +#define VID_SRC_A_GPCNT 0x130808 /* Video A general purpose counter */ +#define VID_SRC_B_GPCNT 0x130908 /* Video B general purpose counter */ +#define VID_SRC_C_GPCNT 0x130A08 /* Video C general purpose counter */ +#define VID_SRC_D_GPCNT 0x130B08 /* Video D general purpose counter */ +#define VID_SRC_E_GPCNT 0x130C08 /* Video E general purpose counter */ +#define VID_SRC_F_GPCNT 0x130D08 /* Video F general purpose counter */ +#define VID_SRC_I_GPCNT 0x130E08 /* Video I general purpose counter */ +#define VID_SRC_J_GPCNT 0x130F08 /* Video J general purpose counter */ + +/* ***************************************************************************** */ + +#define VID_SRC_A_DMA_CTL 0x13080C /* Video A DMA control */ +#define VID_SRC_B_DMA_CTL 0x13090C /* Video B DMA control */ +#define VID_SRC_C_DMA_CTL 0x130A0C /* Video C DMA control */ +#define VID_SRC_D_DMA_CTL 0x130B0C /* Video D DMA control */ +#define VID_SRC_E_DMA_CTL 0x130C0C /* Video E DMA control */ +#define VID_SRC_F_DMA_CTL 0x130D0C /* Video F DMA control */ +#define VID_SRC_I_DMA_CTL 0x130E0C /* Video I DMA control */ +#define VID_SRC_J_DMA_CTL 0x130F0C /* Video J DMA control */ + +#define FLD_APB_RISC_EN 0x00000010 +#define FLD_APB_FIFO_EN 0x00000001 + +/* ***************************************************************************** */ + +#define VID_SRC_A_FMT_CTL 0x130810 /* Video A format control */ +#define VID_SRC_B_FMT_CTL 0x130910 /* Video B format control */ +#define VID_SRC_C_FMT_CTL 0x130A10 /* Video C format control */ +#define VID_SRC_D_FMT_CTL 0x130B10 /* Video D format control */ +#define VID_SRC_E_FMT_CTL 0x130C10 /* Video E format control */ +#define VID_SRC_F_FMT_CTL 0x130D10 /* Video F format control */ +#define VID_SRC_I_FMT_CTL 0x130E10 /* Video I format control */ +#define VID_SRC_J_FMT_CTL 0x130F10 /* Video J format control */ + +/* ***************************************************************************** */ + +#define VID_SRC_A_ACTIVE_CTL1 0x130814 /* Video A active control 1 */ +#define VID_SRC_B_ACTIVE_CTL1 0x130914 /* Video B active control 1 */ +#define VID_SRC_C_ACTIVE_CTL1 0x130A14 /* Video C active control 1 */ +#define VID_SRC_D_ACTIVE_CTL1 0x130B14 /* Video D active control 1 */ +#define VID_SRC_E_ACTIVE_CTL1 0x130C14 /* Video E active control 1 */ +#define VID_SRC_F_ACTIVE_CTL1 0x130D14 /* Video F active control 1 */ +#define VID_SRC_I_ACTIVE_CTL1 0x130E14 /* Video I active control 1 */ +#define VID_SRC_J_ACTIVE_CTL1 0x130F14 /* Video J active control 1 */ + +/* ***************************************************************************** */ + +#define VID_SRC_A_ACTIVE_CTL2 0x130818 /* Video A active control 2 */ +#define VID_SRC_B_ACTIVE_CTL2 0x130918 /* Video B active control 2 */ +#define VID_SRC_C_ACTIVE_CTL2 0x130A18 /* Video C active control 2 */ +#define VID_SRC_D_ACTIVE_CTL2 0x130B18 /* Video D active control 2 */ +#define VID_SRC_E_ACTIVE_CTL2 0x130C18 /* Video E active control 2 */ +#define VID_SRC_F_ACTIVE_CTL2 0x130D18 /* Video F active control 2 */ +#define VID_SRC_I_ACTIVE_CTL2 0x130E18 /* Video I active control 2 */ +#define VID_SRC_J_ACTIVE_CTL2 0x130F18 /* Video J active control 2 */ + +/* ***************************************************************************** */ + +#define VID_SRC_A_CDT_SZ 0x13081C /* Video A CDT size */ +#define VID_SRC_B_CDT_SZ 0x13091C /* Video B CDT size */ +#define VID_SRC_C_CDT_SZ 0x130A1C /* Video C CDT size */ +#define VID_SRC_D_CDT_SZ 0x130B1C /* Video D CDT size */ +#define VID_SRC_E_CDT_SZ 0x130C1C /* Video E CDT size */ +#define VID_SRC_F_CDT_SZ 0x130D1C /* Video F CDT size */ +#define VID_SRC_I_CDT_SZ 0x130E1C /* Video I CDT size */ +#define VID_SRC_J_CDT_SZ 0x130F1C /* Video J CDT size */ + +/* ***************************************************************************** */ +/* Audio I/F */ +/* ***************************************************************************** */ +#define AUD_DST_A_DMA 0x140000 /* Audio Int A DMA data port */ +#define AUD_SRC_A_DMA 0x140008 /* Audio Int A DMA data port */ + +#define AUD_A_GPCNT 0x140010 /* Audio Int A gp counter */ +#define FLD_AUD_A_GP_CNT 0x0000FFFF + +#define AUD_A_GPCNT_CTL 0x140014 /* Audio Int A gp control */ + +#define AUD_A_LNGTH 0x140018 /* Audio Int A line length */ + +#define AUD_A_CFG 0x14001C /* Audio Int A configuration */ + +/* ***************************************************************************** */ +#define AUD_DST_B_DMA 0x140100 /* Audio Int B DMA data port */ +#define AUD_SRC_B_DMA 0x140108 /* Audio Int B DMA data port */ + +#define AUD_B_GPCNT 0x140110 /* Audio Int B gp counter */ +#define FLD_AUD_B_GP_CNT 0x0000FFFF + +#define AUD_B_GPCNT_CTL 0x140114 /* Audio Int B gp control */ + +#define AUD_B_LNGTH 0x140118 /* Audio Int B line length */ + +#define AUD_B_CFG 0x14011C /* Audio Int B configuration */ + +/* ***************************************************************************** */ +#define AUD_DST_C_DMA 0x140200 /* Audio Int C DMA data port */ +#define AUD_SRC_C_DMA 0x140208 /* Audio Int C DMA data port */ + +#define AUD_C_GPCNT 0x140210 /* Audio Int C gp counter */ +#define FLD_AUD_C_GP_CNT 0x0000FFFF + +#define AUD_C_GPCNT_CTL 0x140214 /* Audio Int C gp control */ + +#define AUD_C_LNGTH 0x140218 /* Audio Int C line length */ + +#define AUD_C_CFG 0x14021C /* Audio Int C configuration */ + +/* ***************************************************************************** */ +#define AUD_DST_D_DMA 0x140300 /* Audio Int D DMA data port */ +#define AUD_SRC_D_DMA 0x140308 /* Audio Int D DMA data port */ + +#define AUD_D_GPCNT 0x140310 /* Audio Int D gp counter */ +#define FLD_AUD_D_GP_CNT 0x0000FFFF + +#define AUD_D_GPCNT_CTL 0x140314 /* Audio Int D gp control */ + +#define AUD_D_LNGTH 0x140318 /* Audio Int D line length */ + +#define AUD_D_CFG 0x14031C /* Audio Int D configuration */ + +/* ***************************************************************************** */ +#define AUD_SRC_E_DMA 0x140400 /* Audio Int E DMA data port */ + +#define AUD_E_GPCNT 0x140410 /* Audio Int E gp counter */ +#define FLD_AUD_E_GP_CNT 0x0000FFFF + +#define AUD_E_GPCNT_CTL 0x140414 /* Audio Int E gp control */ + +#define AUD_E_CFG 0x14041C /* Audio Int E configuration */ + +/* ***************************************************************************** */ + +#define FLD_AUD_DST_LN_LNGTH 0x00000FFF + +#define FLD_AUD_DST_PK_MODE 0x00004000 + +#define FLD_AUD_CLK_ENABLE 0x00000200 + +#define FLD_AUD_MASTER_MODE 0x00000002 + +#define FLD_AUD_SONY_MODE 0x00000001 + +#define FLD_AUD_CLK_SELECT_PLL_D 0x00001800 + +#define FLD_AUD_DST_ENABLE 0x00020000 + +#define FLD_AUD_SRC_ENABLE 0x00010000 + +/* ***************************************************************************** */ +#define AUD_INT_DMA_CTL 0x140500 /* Audio Int DMA control */ + +#define FLD_AUD_SRC_E_RISC_EN 0x00008000 +#define FLD_AUD_SRC_C_RISC_EN 0x00004000 +#define FLD_AUD_SRC_B_RISC_EN 0x00002000 +#define FLD_AUD_SRC_A_RISC_EN 0x00001000 + +#define FLD_AUD_DST_D_RISC_EN 0x00000800 +#define FLD_AUD_DST_C_RISC_EN 0x00000400 +#define FLD_AUD_DST_B_RISC_EN 0x00000200 +#define FLD_AUD_DST_A_RISC_EN 0x00000100 + +#define FLD_AUD_SRC_E_FIFO_EN 0x00000080 +#define FLD_AUD_SRC_C_FIFO_EN 0x00000040 +#define FLD_AUD_SRC_B_FIFO_EN 0x00000020 +#define FLD_AUD_SRC_A_FIFO_EN 0x00000010 + +#define FLD_AUD_DST_D_FIFO_EN 0x00000008 +#define FLD_AUD_DST_C_FIFO_EN 0x00000004 +#define FLD_AUD_DST_B_FIFO_EN 0x00000002 +#define FLD_AUD_DST_A_FIFO_EN 0x00000001 + +/* ***************************************************************************** */ +/* */ +/* Mobilygen Interface Registers */ +/* */ +/* ***************************************************************************** */ +/* Mobilygen Interface A */ +/* ***************************************************************************** */ +#define MB_IF_A_DMA 0x150000 /* MBIF A DMA data port */ +#define MB_IF_A_GPCN 0x150008 /* MBIF A GP counter */ +#define MB_IF_A_GPCN_CTRL 0x15000C +#define MB_IF_A_DMA_CTRL 0x150010 +#define MB_IF_A_LENGTH 0x150014 +#define MB_IF_A_HDMA_XFER_SZ 0x150018 +#define MB_IF_A_HCMD 0x15001C +#define MB_IF_A_HCONFIG 0x150020 +#define MB_IF_A_DATA_STRUCT_0 0x150024 +#define MB_IF_A_DATA_STRUCT_1 0x150028 +#define MB_IF_A_DATA_STRUCT_2 0x15002C +#define MB_IF_A_DATA_STRUCT_3 0x150030 +#define MB_IF_A_DATA_STRUCT_4 0x150034 +#define MB_IF_A_DATA_STRUCT_5 0x150038 +#define MB_IF_A_DATA_STRUCT_6 0x15003C +#define MB_IF_A_DATA_STRUCT_7 0x150040 +#define MB_IF_A_DATA_STRUCT_8 0x150044 +#define MB_IF_A_DATA_STRUCT_9 0x150048 +#define MB_IF_A_DATA_STRUCT_A 0x15004C +#define MB_IF_A_DATA_STRUCT_B 0x150050 +#define MB_IF_A_DATA_STRUCT_C 0x150054 +#define MB_IF_A_DATA_STRUCT_D 0x150058 +#define MB_IF_A_DATA_STRUCT_E 0x15005C +#define MB_IF_A_DATA_STRUCT_F 0x150060 +/* ***************************************************************************** */ +/* Mobilygen Interface B */ +/* ***************************************************************************** */ +#define MB_IF_B_DMA 0x160000 /* MBIF A DMA data port */ +#define MB_IF_B_GPCN 0x160008 /* MBIF A GP counter */ +#define MB_IF_B_GPCN_CTRL 0x16000C +#define MB_IF_B_DMA_CTRL 0x160010 +#define MB_IF_B_LENGTH 0x160014 +#define MB_IF_B_HDMA_XFER_SZ 0x160018 +#define MB_IF_B_HCMD 0x16001C +#define MB_IF_B_HCONFIG 0x160020 +#define MB_IF_B_DATA_STRUCT_0 0x160024 +#define MB_IF_B_DATA_STRUCT_1 0x160028 +#define MB_IF_B_DATA_STRUCT_2 0x16002C +#define MB_IF_B_DATA_STRUCT_3 0x160030 +#define MB_IF_B_DATA_STRUCT_4 0x160034 +#define MB_IF_B_DATA_STRUCT_5 0x160038 +#define MB_IF_B_DATA_STRUCT_6 0x16003C +#define MB_IF_B_DATA_STRUCT_7 0x160040 +#define MB_IF_B_DATA_STRUCT_8 0x160044 +#define MB_IF_B_DATA_STRUCT_9 0x160048 +#define MB_IF_B_DATA_STRUCT_A 0x16004C +#define MB_IF_B_DATA_STRUCT_B 0x160050 +#define MB_IF_B_DATA_STRUCT_C 0x160054 +#define MB_IF_B_DATA_STRUCT_D 0x160058 +#define MB_IF_B_DATA_STRUCT_E 0x16005C +#define MB_IF_B_DATA_STRUCT_F 0x160060 + +/* MB_DMA_CTRL */ +#define FLD_MB_IF_RISC_EN 0x00000010 +#define FLD_MB_IF_FIFO_EN 0x00000001 + +/* MB_LENGTH */ +#define FLD_MB_IF_LN_LNGTH 0x00000FFF + +/* MB_HCMD register */ +#define FLD_MB_HCMD_H_GO 0x80000000 +#define FLD_MB_HCMD_H_BUSY 0x40000000 +#define FLD_MB_HCMD_H_DMA_HOLD 0x10000000 +#define FLD_MB_HCMD_H_DMA_BUSY 0x08000000 +#define FLD_MB_HCMD_H_DMA_TYPE 0x04000000 +#define FLD_MB_HCMD_H_DMA_XACT 0x02000000 +#define FLD_MB_HCMD_H_RW_N 0x01000000 +#define FLD_MB_HCMD_H_ADDR 0x00FF0000 +#define FLD_MB_HCMD_H_DATA 0x0000FFFF + +/* ***************************************************************************** */ +/* I2C #1 */ +/* ***************************************************************************** */ +#define I2C1_ADDR 0x180000 /* I2C #1 address */ +#define FLD_I2C_DADDR 0xfe000000 /* RW [31:25] I2C Device Address */ + /* RO [24] reserved */ +/* ***************************************************************************** */ +#define FLD_I2C_SADDR 0x00FFFFFF /* RW [23:0] I2C Sub-address */ + +/* ***************************************************************************** */ +#define I2C1_WDATA 0x180004 /* I2C #1 write data */ +#define FLD_I2C_WDATA 0xFFFFFFFF /* RW [31:0] */ + +/* ***************************************************************************** */ +#define I2C1_CTRL 0x180008 /* I2C #1 control */ +#define FLD_I2C_PERIOD 0xFF000000 /* RW [31:24] */ +#define FLD_I2C_SCL_IN 0x00200000 /* RW [21] */ +#define FLD_I2C_SDA_IN 0x00100000 /* RW [20] */ + /* RO [19:18] reserved */ +#define FLD_I2C_SCL_OUT 0x00020000 /* RW [17] */ +#define FLD_I2C_SDA_OUT 0x00010000 /* RW [16] */ + /* RO [15] reserved */ +#define FLD_I2C_DATA_LEN 0x00007000 /* RW [14:12] */ +#define FLD_I2C_SADDR_INC 0x00000800 /* RW [11] */ + /* RO [10:9] reserved */ +#define FLD_I2C_SADDR_LEN 0x00000300 /* RW [9:8] */ + /* RO [7:6] reserved */ +#define FLD_I2C_SOFT 0x00000020 /* RW [5] */ +#define FLD_I2C_NOSTOP 0x00000010 /* RW [4] */ +#define FLD_I2C_EXTEND 0x00000008 /* RW [3] */ +#define FLD_I2C_SYNC 0x00000004 /* RW [2] */ +#define FLD_I2C_READ_SA 0x00000002 /* RW [1] */ +#define FLD_I2C_READ_WRN 0x00000001 /* RW [0] */ + +/* ***************************************************************************** */ +#define I2C1_RDATA 0x18000C /* I2C #1 read data */ +#define FLD_I2C_RDATA 0xFFFFFFFF /* RO [31:0] */ + +/* ***************************************************************************** */ +#define I2C1_STAT 0x180010 /* I2C #1 status */ +#define FLD_I2C_XFER_IN_PROG 0x00000002 /* RO [1] */ +#define FLD_I2C_RACK 0x00000001 /* RO [0] */ + +/* ***************************************************************************** */ +/* I2C #2 */ +/* ***************************************************************************** */ +#define I2C2_ADDR 0x190000 /* I2C #2 address */ + +/* ***************************************************************************** */ +#define I2C2_WDATA 0x190004 /* I2C #2 write data */ + +/* ***************************************************************************** */ +#define I2C2_CTRL 0x190008 /* I2C #2 control */ + +/* ***************************************************************************** */ +#define I2C2_RDATA 0x19000C /* I2C #2 read data */ + +/* ***************************************************************************** */ +#define I2C2_STAT 0x190010 /* I2C #2 status */ + +/* ***************************************************************************** */ +/* I2C #3 */ +/* ***************************************************************************** */ +#define I2C3_ADDR 0x1A0000 /* I2C #3 address */ + +/* ***************************************************************************** */ +#define I2C3_WDATA 0x1A0004 /* I2C #3 write data */ + +/* ***************************************************************************** */ +#define I2C3_CTRL 0x1A0008 /* I2C #3 control */ + +/* ***************************************************************************** */ +#define I2C3_RDATA 0x1A000C /* I2C #3 read data */ + +/* ***************************************************************************** */ +#define I2C3_STAT 0x1A0010 /* I2C #3 status */ + +/* ***************************************************************************** */ +/* UART */ +/* ***************************************************************************** */ +#define UART_CTL 0x1B0000 /* UART Control Register */ +#define FLD_LOOP_BACK_EN (1 << 7) /* RW field - default 0 */ +#define FLD_RX_TRG_SZ (3 << 2) /* RW field - default 0 */ +#define FLD_RX_EN (1 << 1) /* RW field - default 0 */ +#define FLD_TX_EN (1 << 0) /* RW field - default 0 */ + +/* ***************************************************************************** */ +#define UART_BRD 0x1B0004 /* UART Baud Rate Divisor */ +#define FLD_BRD 0x0000FFFF /* RW field - default 0x197 */ + +/* ***************************************************************************** */ +#define UART_DBUF 0x1B0008 /* UART Tx/Rx Data BuFFer */ +#define FLD_DB 0xFFFFFFFF /* RW field - default 0 */ + +/* ***************************************************************************** */ +#define UART_ISR 0x1B000C /* UART Interrupt Status */ +#define FLD_RXD_TIMEOUT_EN (1 << 7) /* RW field - default 0 */ +#define FLD_FRM_ERR_EN (1 << 6) /* RW field - default 0 */ +#define FLD_RXD_RDY_EN (1 << 5) /* RW field - default 0 */ +#define FLD_TXD_EMPTY_EN (1 << 4) /* RW field - default 0 */ +#define FLD_RXD_OVERFLOW (1 << 3) /* RW field - default 0 */ +#define FLD_FRM_ERR (1 << 2) /* RW field - default 0 */ +#define FLD_RXD_RDY (1 << 1) /* RW field - default 0 */ +#define FLD_TXD_EMPTY (1 << 0) /* RW field - default 0 */ + +/* ***************************************************************************** */ +#define UART_CNT 0x1B0010 /* UART Tx/Rx FIFO Byte Count */ +#define FLD_TXD_CNT (0x1F << 8) /* RW field - default 0 */ +#define FLD_RXD_CNT (0x1F << 0) /* RW field - default 0 */ + +/* ***************************************************************************** */ +/* Motion Detection */ +#define MD_CH0_GRID_BLOCK_YCNT 0x170014 +#define MD_CH1_GRID_BLOCK_YCNT 0x170094 +#define MD_CH2_GRID_BLOCK_YCNT 0x170114 +#define MD_CH3_GRID_BLOCK_YCNT 0x170194 +#define MD_CH4_GRID_BLOCK_YCNT 0x170214 +#define MD_CH5_GRID_BLOCK_YCNT 0x170294 +#define MD_CH6_GRID_BLOCK_YCNT 0x170314 +#define MD_CH7_GRID_BLOCK_YCNT 0x170394 + +#define PIXEL_FRMT_422 4 +#define PIXEL_FRMT_411 5 +#define PIXEL_FRMT_Y8 6 + +#define PIXEL_ENGINE_VIP1 0 +#define PIXEL_ENGINE_VIP2 1 + +#endif /* Athena_REGISTERS */ diff --git a/drivers/media/pci/cx25821/cx25821-sram.h b/drivers/media/pci/cx25821/cx25821-sram.h new file mode 100644 index 0000000..5f05d15 --- /dev/null +++ b/drivers/media/pci/cx25821/cx25821-sram.h @@ -0,0 +1,261 @@ +/* + * Driver for the Conexant CX25821 PCIe bridge + * + * Copyright (C) 2009 Conexant Systems Inc. + * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __ATHENA_SRAM_H__ +#define __ATHENA_SRAM_H__ + +/* #define RX_SRAM_START_SIZE = 0; // Start of reserved SRAM */ +#define VID_CMDS_SIZE 80 /* Video CMDS size in bytes */ +#define AUDIO_CMDS_SIZE 80 /* AUDIO CMDS size in bytes */ +#define MBIF_CMDS_SIZE 80 /* MBIF CMDS size in bytes */ + +/* #define RX_SRAM_POOL_START_SIZE = 0; // Start of useable RX SRAM for buffers */ +#define VID_IQ_SIZE 64 /* VID instruction queue size in bytes */ +#define MBIF_IQ_SIZE 64 +#define AUDIO_IQ_SIZE 64 /* AUD instruction queue size in bytes */ + +#define VID_CDT_SIZE 64 /* VID cluster descriptor table size in bytes */ +#define MBIF_CDT_SIZE 64 /* MBIF/HBI cluster descriptor table size in bytes */ +#define AUDIO_CDT_SIZE 48 /* AUD cluster descriptor table size in bytes */ + +/* #define RX_SRAM_POOL_FREE_SIZE = 16; // Start of available RX SRAM */ +/* #define RX_SRAM_END_SIZE = 0; // End of RX SRAM */ + +/* #define TX_SRAM_POOL_START_SIZE = 0; // Start of transmit pool SRAM */ +/* #define MSI_DATA_SIZE = 64; // Reserved (MSI Data, RISC working stora */ + +#define VID_CLUSTER_SIZE 1440 /* VID cluster data line */ +#define AUDIO_CLUSTER_SIZE 128 /* AUDIO cluster data line */ +#define MBIF_CLUSTER_SIZE 1440 /* MBIF/HBI cluster data line */ + +/* #define TX_SRAM_POOL_FREE_SIZE = 704; // Start of available TX SRAM */ +/* #define TX_SRAM_END_SIZE = 0; // End of TX SRAM */ + +/* Receive SRAM */ +#define RX_SRAM_START 0x10000 +#define VID_A_DOWN_CMDS 0x10000 +#define VID_B_DOWN_CMDS 0x10050 +#define VID_C_DOWN_CMDS 0x100A0 +#define VID_D_DOWN_CMDS 0x100F0 +#define VID_E_DOWN_CMDS 0x10140 +#define VID_F_DOWN_CMDS 0x10190 +#define VID_G_DOWN_CMDS 0x101E0 +#define VID_H_DOWN_CMDS 0x10230 +#define VID_A_UP_CMDS 0x10280 +#define VID_B_UP_CMDS 0x102D0 +#define VID_C_UP_CMDS 0x10320 +#define VID_D_UP_CMDS 0x10370 +#define VID_E_UP_CMDS 0x103C0 +#define VID_F_UP_CMDS 0x10410 +#define VID_I_UP_CMDS 0x10460 +#define VID_J_UP_CMDS 0x104B0 +#define AUD_A_DOWN_CMDS 0x10500 +#define AUD_B_DOWN_CMDS 0x10550 +#define AUD_C_DOWN_CMDS 0x105A0 +#define AUD_D_DOWN_CMDS 0x105F0 +#define AUD_A_UP_CMDS 0x10640 +#define AUD_B_UP_CMDS 0x10690 +#define AUD_C_UP_CMDS 0x106E0 +#define AUD_E_UP_CMDS 0x10730 +#define MBIF_A_DOWN_CMDS 0x10780 +#define MBIF_B_DOWN_CMDS 0x107D0 +#define DMA_SCRATCH_PAD 0x10820 /* Scratch pad area from 0x10820 to 0x10B40 */ + +/* #define RX_SRAM_POOL_START = 0x105B0; */ + +#define VID_A_IQ 0x11000 +#define VID_B_IQ 0x11040 +#define VID_C_IQ 0x11080 +#define VID_D_IQ 0x110C0 +#define VID_E_IQ 0x11100 +#define VID_F_IQ 0x11140 +#define VID_G_IQ 0x11180 +#define VID_H_IQ 0x111C0 +#define VID_I_IQ 0x11200 +#define VID_J_IQ 0x11240 +#define AUD_A_IQ 0x11280 +#define AUD_B_IQ 0x112C0 +#define AUD_C_IQ 0x11300 +#define AUD_D_IQ 0x11340 +#define AUD_E_IQ 0x11380 +#define MBIF_A_IQ 0x11000 +#define MBIF_B_IQ 0x110C0 + +#define VID_A_CDT 0x10C00 +#define VID_B_CDT 0x10C40 +#define VID_C_CDT 0x10C80 +#define VID_D_CDT 0x10CC0 +#define VID_E_CDT 0x10D00 +#define VID_F_CDT 0x10D40 +#define VID_G_CDT 0x10D80 +#define VID_H_CDT 0x10DC0 +#define VID_I_CDT 0x10E00 +#define VID_J_CDT 0x10E40 +#define AUD_A_CDT 0x10E80 +#define AUD_B_CDT 0x10EB0 +#define AUD_C_CDT 0x10EE0 +#define AUD_D_CDT 0x10F10 +#define AUD_E_CDT 0x10F40 +#define MBIF_A_CDT 0x10C00 +#define MBIF_B_CDT 0x10CC0 + +/* Cluster Buffer for RX */ +#define VID_A_UP_CLUSTER_1 0x11400 +#define VID_A_UP_CLUSTER_2 0x119A0 +#define VID_A_UP_CLUSTER_3 0x11F40 +#define VID_A_UP_CLUSTER_4 0x124E0 + +#define VID_B_UP_CLUSTER_1 0x12A80 +#define VID_B_UP_CLUSTER_2 0x13020 +#define VID_B_UP_CLUSTER_3 0x135C0 +#define VID_B_UP_CLUSTER_4 0x13B60 + +#define VID_C_UP_CLUSTER_1 0x14100 +#define VID_C_UP_CLUSTER_2 0x146A0 +#define VID_C_UP_CLUSTER_3 0x14C40 +#define VID_C_UP_CLUSTER_4 0x151E0 + +#define VID_D_UP_CLUSTER_1 0x15780 +#define VID_D_UP_CLUSTER_2 0x15D20 +#define VID_D_UP_CLUSTER_3 0x162C0 +#define VID_D_UP_CLUSTER_4 0x16860 + +#define VID_E_UP_CLUSTER_1 0x16E00 +#define VID_E_UP_CLUSTER_2 0x173A0 +#define VID_E_UP_CLUSTER_3 0x17940 +#define VID_E_UP_CLUSTER_4 0x17EE0 + +#define VID_F_UP_CLUSTER_1 0x18480 +#define VID_F_UP_CLUSTER_2 0x18A20 +#define VID_F_UP_CLUSTER_3 0x18FC0 +#define VID_F_UP_CLUSTER_4 0x19560 + +#define VID_I_UP_CLUSTER_1 0x19B00 +#define VID_I_UP_CLUSTER_2 0x1A0A0 +#define VID_I_UP_CLUSTER_3 0x1A640 +#define VID_I_UP_CLUSTER_4 0x1ABE0 + +#define VID_J_UP_CLUSTER_1 0x1B180 +#define VID_J_UP_CLUSTER_2 0x1B720 +#define VID_J_UP_CLUSTER_3 0x1BCC0 +#define VID_J_UP_CLUSTER_4 0x1C260 + +#define AUD_A_UP_CLUSTER_1 0x1C800 +#define AUD_A_UP_CLUSTER_2 0x1C880 +#define AUD_A_UP_CLUSTER_3 0x1C900 + +#define AUD_B_UP_CLUSTER_1 0x1C980 +#define AUD_B_UP_CLUSTER_2 0x1CA00 +#define AUD_B_UP_CLUSTER_3 0x1CA80 + +#define AUD_C_UP_CLUSTER_1 0x1CB00 +#define AUD_C_UP_CLUSTER_2 0x1CB80 +#define AUD_C_UP_CLUSTER_3 0x1CC00 + +#define AUD_E_UP_CLUSTER_1 0x1CC80 +#define AUD_E_UP_CLUSTER_2 0x1CD00 +#define AUD_E_UP_CLUSTER_3 0x1CD80 + +#define RX_SRAM_POOL_FREE 0x1CE00 +#define RX_SRAM_END 0x1D000 + +/* Free Receive SRAM 144 Bytes */ + +/* Transmit SRAM */ +#define TX_SRAM_POOL_START 0x00000 + +#define VID_A_DOWN_CLUSTER_1 0x00040 +#define VID_A_DOWN_CLUSTER_2 0x005E0 +#define VID_A_DOWN_CLUSTER_3 0x00B80 +#define VID_A_DOWN_CLUSTER_4 0x01120 + +#define VID_B_DOWN_CLUSTER_1 0x016C0 +#define VID_B_DOWN_CLUSTER_2 0x01C60 +#define VID_B_DOWN_CLUSTER_3 0x02200 +#define VID_B_DOWN_CLUSTER_4 0x027A0 + +#define VID_C_DOWN_CLUSTER_1 0x02D40 +#define VID_C_DOWN_CLUSTER_2 0x032E0 +#define VID_C_DOWN_CLUSTER_3 0x03880 +#define VID_C_DOWN_CLUSTER_4 0x03E20 + +#define VID_D_DOWN_CLUSTER_1 0x043C0 +#define VID_D_DOWN_CLUSTER_2 0x04960 +#define VID_D_DOWN_CLUSTER_3 0x04F00 +#define VID_D_DOWN_CLUSTER_4 0x054A0 + +#define VID_E_DOWN_CLUSTER_1 0x05a40 +#define VID_E_DOWN_CLUSTER_2 0x05FE0 +#define VID_E_DOWN_CLUSTER_3 0x06580 +#define VID_E_DOWN_CLUSTER_4 0x06B20 + +#define VID_F_DOWN_CLUSTER_1 0x070C0 +#define VID_F_DOWN_CLUSTER_2 0x07660 +#define VID_F_DOWN_CLUSTER_3 0x07C00 +#define VID_F_DOWN_CLUSTER_4 0x081A0 + +#define VID_G_DOWN_CLUSTER_1 0x08740 +#define VID_G_DOWN_CLUSTER_2 0x08CE0 +#define VID_G_DOWN_CLUSTER_3 0x09280 +#define VID_G_DOWN_CLUSTER_4 0x09820 + +#define VID_H_DOWN_CLUSTER_1 0x09DC0 +#define VID_H_DOWN_CLUSTER_2 0x0A360 +#define VID_H_DOWN_CLUSTER_3 0x0A900 +#define VID_H_DOWN_CLUSTER_4 0x0AEA0 + +#define AUD_A_DOWN_CLUSTER_1 0x0B500 +#define AUD_A_DOWN_CLUSTER_2 0x0B580 +#define AUD_A_DOWN_CLUSTER_3 0x0B600 + +#define AUD_B_DOWN_CLUSTER_1 0x0B680 +#define AUD_B_DOWN_CLUSTER_2 0x0B700 +#define AUD_B_DOWN_CLUSTER_3 0x0B780 + +#define AUD_C_DOWN_CLUSTER_1 0x0B800 +#define AUD_C_DOWN_CLUSTER_2 0x0B880 +#define AUD_C_DOWN_CLUSTER_3 0x0B900 + +#define AUD_D_DOWN_CLUSTER_1 0x0B980 +#define AUD_D_DOWN_CLUSTER_2 0x0BA00 +#define AUD_D_DOWN_CLUSTER_3 0x0BA80 + +#define TX_SRAM_POOL_FREE 0x0BB00 +#define TX_SRAM_END 0x0C000 + +#define BYTES_TO_DWORDS(bcount) ((bcount) >> 2) +#define BYTES_TO_QWORDS(bcount) ((bcount) >> 3) +#define BYTES_TO_OWORDS(bcount) ((bcount) >> 4) + +#define VID_IQ_SIZE_DW BYTES_TO_DWORDS(VID_IQ_SIZE) +#define VID_CDT_SIZE_QW BYTES_TO_QWORDS(VID_CDT_SIZE) +#define VID_CLUSTER_SIZE_OW BYTES_TO_OWORDS(VID_CLUSTER_SIZE) + +#define AUDIO_IQ_SIZE_DW BYTES_TO_DWORDS(AUDIO_IQ_SIZE) +#define AUDIO_CDT_SIZE_QW BYTES_TO_QWORDS(AUDIO_CDT_SIZE) +#define AUDIO_CLUSTER_SIZE_QW BYTES_TO_QWORDS(AUDIO_CLUSTER_SIZE) + +#define MBIF_IQ_SIZE_DW BYTES_TO_DWORDS(MBIF_IQ_SIZE) +#define MBIF_CDT_SIZE_QW BYTES_TO_QWORDS(MBIF_CDT_SIZE) +#define MBIF_CLUSTER_SIZE_OW BYTES_TO_OWORDS(MBIF_CLUSTER_SIZE) + +#endif diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c new file mode 100644 index 0000000..c8c94fb --- /dev/null +++ b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c @@ -0,0 +1,802 @@ +/* + * Driver for the Conexant CX25821 PCIe bridge + * + * Copyright (C) 2009 Conexant Systems Inc. + * Authors <hiep.huynh@conexant.com>, <shu.lin@conexant.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include "cx25821-video.h" +#include "cx25821-video-upstream-ch2.h" + +#include <linux/fs.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/syscalls.h> +#include <linux/file.h> +#include <linux/fcntl.h> +#include <linux/slab.h> +#include <linux/uaccess.h> + +MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards"); +MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>"); +MODULE_LICENSE("GPL"); + +static int _intr_msk = FLD_VID_SRC_RISC1 | FLD_VID_SRC_UF | FLD_VID_SRC_SYNC | + FLD_VID_SRC_OPC_ERR; + +static __le32 *cx25821_update_riscprogram_ch2(struct cx25821_dev *dev, + __le32 *rp, unsigned int offset, + unsigned int bpl, u32 sync_line, + unsigned int lines, + int fifo_enable, int field_type) +{ + unsigned int line, i; + int dist_betwn_starts = bpl * 2; + + *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); + + if (USE_RISC_NOOP_VIDEO) { + for (i = 0; i < NUM_NO_OPS; i++) + *(rp++) = cpu_to_le32(RISC_NOOP); + } + + /* scan lines */ + for (line = 0; line < lines; line++) { + *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); + *(rp++) = cpu_to_le32(dev->_data_buf_phys_addr_ch2 + offset); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + + if ((lines <= NTSC_FIELD_HEIGHT) || + (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC_ch2)) { + offset += dist_betwn_starts; + } + } + + return rp; +} + +static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev, + __le32 *rp, + dma_addr_t databuf_phys_addr, + unsigned int offset, + u32 sync_line, unsigned int bpl, + unsigned int lines, + int fifo_enable, int field_type) +{ + unsigned int line, i; + struct sram_channel *sram_ch = + dev->channels[dev->_channel2_upstream_select].sram_channels; + int dist_betwn_starts = bpl * 2; + + /* sync instruction */ + if (sync_line != NO_SYNC_LINE) + *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); + + if (USE_RISC_NOOP_VIDEO) { + for (i = 0; i < NUM_NO_OPS; i++) + *(rp++) = cpu_to_le32(RISC_NOOP); + } + + /* scan lines */ + for (line = 0; line < lines; line++) { + *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); + *(rp++) = cpu_to_le32(databuf_phys_addr + offset); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + + if ((lines <= NTSC_FIELD_HEIGHT) || + (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC_ch2)) { + offset += dist_betwn_starts; + } + + /* + check if we need to enable the FIFO after the first 4 lines + For the upstream video channel, the risc engine will enable + the FIFO. + */ + if (fifo_enable && line == 3) { + *(rp++) = RISC_WRITECR; + *(rp++) = sram_ch->dma_ctl; + *(rp++) = FLD_VID_FIFO_EN; + *(rp++) = 0x00000001; + } + } + + return rp; +} + +int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev, + struct pci_dev *pci, + unsigned int top_offset, unsigned int bpl, + unsigned int lines) +{ + __le32 *rp; + int fifo_enable = 0; + int singlefield_lines = lines >> 1; /*get line count for single field */ + int odd_num_lines = singlefield_lines; + int frame = 0; + int frame_size = 0; + int databuf_offset = 0; + int risc_program_size = 0; + int risc_flag = RISC_CNT_RESET; + unsigned int bottom_offset = bpl; + dma_addr_t risc_phys_jump_addr; + + if (dev->_isNTSC_ch2) { + odd_num_lines = singlefield_lines + 1; + risc_program_size = FRAME1_VID_PROG_SIZE; + if (bpl == Y411_LINE_SZ) + frame_size = FRAME_SIZE_NTSC_Y411; + else + frame_size = FRAME_SIZE_NTSC_Y422; + } else { + risc_program_size = PAL_VID_PROG_SIZE; + if (bpl == Y411_LINE_SZ) + frame_size = FRAME_SIZE_PAL_Y411; + else + frame_size = FRAME_SIZE_PAL_Y422; + } + + /* Virtual address of Risc buffer program */ + rp = dev->_dma_virt_addr_ch2; + + for (frame = 0; frame < NUM_FRAMES; frame++) { + databuf_offset = frame_size * frame; + + if (UNSET != top_offset) { + fifo_enable = (frame == 0) ? FIFO_ENABLE : FIFO_DISABLE; + rp = cx25821_risc_field_upstream_ch2(dev, rp, + dev->_data_buf_phys_addr_ch2 + databuf_offset, + top_offset, 0, bpl, odd_num_lines, fifo_enable, + ODD_FIELD); + } + + fifo_enable = FIFO_DISABLE; + + /* Even field */ + rp = cx25821_risc_field_upstream_ch2(dev, rp, + dev->_data_buf_phys_addr_ch2 + databuf_offset, + bottom_offset, 0x200, bpl, singlefield_lines, + fifo_enable, EVEN_FIELD); + + if (frame == 0) { + risc_flag = RISC_CNT_RESET; + risc_phys_jump_addr = dev->_dma_phys_start_addr_ch2 + + risc_program_size; + } else { + risc_flag = RISC_CNT_INC; + risc_phys_jump_addr = dev->_dma_phys_start_addr_ch2; + } + + /* + * Loop to 2ndFrameRISC or to Start of + * Risc program & generate IRQ + */ + *(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag); + *(rp++) = cpu_to_le32(risc_phys_jump_addr); + *(rp++) = cpu_to_le32(0); + } + + return 0; +} + +void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev) +{ + struct sram_channel *sram_ch = + dev->channels[VID_UPSTREAM_SRAM_CHANNEL_J].sram_channels; + u32 tmp = 0; + + if (!dev->_is_running_ch2) { + pr_info("No video file is currently running so return!\n"); + return; + } + /* Disable RISC interrupts */ + tmp = cx_read(sram_ch->int_msk); + cx_write(sram_ch->int_msk, tmp & ~_intr_msk); + + /* Turn OFF risc and fifo */ + tmp = cx_read(sram_ch->dma_ctl); + cx_write(sram_ch->dma_ctl, tmp & ~(FLD_VID_FIFO_EN | FLD_VID_RISC_EN)); + + /* Clear data buffer memory */ + if (dev->_data_buf_virt_addr_ch2) + memset(dev->_data_buf_virt_addr_ch2, 0, + dev->_data_buf_size_ch2); + + dev->_is_running_ch2 = 0; + dev->_is_first_frame_ch2 = 0; + dev->_frame_count_ch2 = 0; + dev->_file_status_ch2 = END_OF_FILE; + + kfree(dev->_irq_queues_ch2); + dev->_irq_queues_ch2 = NULL; + + kfree(dev->_filename_ch2); + + tmp = cx_read(VID_CH_MODE_SEL); + cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00); +} + +void cx25821_free_mem_upstream_ch2(struct cx25821_dev *dev) +{ + if (dev->_is_running_ch2) + cx25821_stop_upstream_video_ch2(dev); + + if (dev->_dma_virt_addr_ch2) { + pci_free_consistent(dev->pci, dev->_risc_size_ch2, + dev->_dma_virt_addr_ch2, + dev->_dma_phys_addr_ch2); + dev->_dma_virt_addr_ch2 = NULL; + } + + if (dev->_data_buf_virt_addr_ch2) { + pci_free_consistent(dev->pci, dev->_data_buf_size_ch2, + dev->_data_buf_virt_addr_ch2, + dev->_data_buf_phys_addr_ch2); + dev->_data_buf_virt_addr_ch2 = NULL; + } +} + +int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) +{ + struct file *myfile; + int frame_index_temp = dev->_frame_index_ch2; + int i = 0; + int line_size = (dev->_pixel_format_ch2 == PIXEL_FRMT_411) ? + Y411_LINE_SZ : Y422_LINE_SZ; + int frame_size = 0; + int frame_offset = 0; + ssize_t vfs_read_retval = 0; + char mybuf[line_size]; + loff_t file_offset; + loff_t pos; + mm_segment_t old_fs; + + if (dev->_file_status_ch2 == END_OF_FILE) + return 0; + + if (dev->_isNTSC_ch2) { + frame_size = (line_size == Y411_LINE_SZ) ? + FRAME_SIZE_NTSC_Y411 : FRAME_SIZE_NTSC_Y422; + } else { + frame_size = (line_size == Y411_LINE_SZ) ? + FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; + } + + frame_offset = (frame_index_temp > 0) ? frame_size : 0; + file_offset = dev->_frame_count_ch2 * frame_size; + + myfile = filp_open(dev->_filename_ch2, O_RDONLY | O_LARGEFILE, 0); + if (IS_ERR(myfile)) { + const int open_errno = -PTR_ERR(myfile); + pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", + __func__, dev->_filename_ch2, open_errno); + return PTR_ERR(myfile); + } else { + if (!(myfile->f_op)) { + pr_err("%s(): File has no file operations registered!\n", + __func__); + filp_close(myfile, NULL); + return -EIO; + } + + if (!myfile->f_op->read) { + pr_err("%s(): File has no READ operations registered!\n", + __func__); + filp_close(myfile, NULL); + return -EIO; + } + + pos = myfile->f_pos; + old_fs = get_fs(); + set_fs(KERNEL_DS); + + for (i = 0; i < dev->_lines_count_ch2; i++) { + pos = file_offset; + + vfs_read_retval = vfs_read(myfile, mybuf, line_size, + &pos); + + if (vfs_read_retval > 0 && vfs_read_retval == line_size + && dev->_data_buf_virt_addr_ch2 != NULL) { + memcpy((void *)(dev->_data_buf_virt_addr_ch2 + + frame_offset / 4), mybuf, + vfs_read_retval); + } + + file_offset += vfs_read_retval; + frame_offset += vfs_read_retval; + + if (vfs_read_retval < line_size) { + pr_info("Done: exit %s() since no more bytes to read from Video file\n", + __func__); + break; + } + } + + if (i > 0) + dev->_frame_count_ch2++; + + dev->_file_status_ch2 = (vfs_read_retval == line_size) ? + IN_PROGRESS : END_OF_FILE; + + set_fs(old_fs); + filp_close(myfile, NULL); + } + + return 0; +} + +static void cx25821_vidups_handler_ch2(struct work_struct *work) +{ + struct cx25821_dev *dev = container_of(work, struct cx25821_dev, + _irq_work_entry_ch2); + + if (!dev) { + pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n", + __func__); + return; + } + + cx25821_get_frame_ch2(dev, dev->channels[dev-> + _channel2_upstream_select].sram_channels); +} + +int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) +{ + struct file *myfile; + int i = 0, j = 0; + int line_size = (dev->_pixel_format_ch2 == PIXEL_FRMT_411) ? + Y411_LINE_SZ : Y422_LINE_SZ; + ssize_t vfs_read_retval = 0; + char mybuf[line_size]; + loff_t pos; + loff_t offset = (unsigned long)0; + mm_segment_t old_fs; + + myfile = filp_open(dev->_filename_ch2, O_RDONLY | O_LARGEFILE, 0); + + if (IS_ERR(myfile)) { + const int open_errno = -PTR_ERR(myfile); + pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", + __func__, dev->_filename_ch2, open_errno); + return PTR_ERR(myfile); + } else { + if (!(myfile->f_op)) { + pr_err("%s(): File has no file operations registered!\n", + __func__); + filp_close(myfile, NULL); + return -EIO; + } + + if (!myfile->f_op->read) { + pr_err("%s(): File has no READ operations registered! Returning\n", + __func__); + filp_close(myfile, NULL); + return -EIO; + } + + pos = myfile->f_pos; + old_fs = get_fs(); + set_fs(KERNEL_DS); + + for (j = 0; j < NUM_FRAMES; j++) { + for (i = 0; i < dev->_lines_count_ch2; i++) { + pos = offset; + + vfs_read_retval = vfs_read(myfile, mybuf, + line_size, &pos); + + if (vfs_read_retval > 0 && + vfs_read_retval == line_size && + dev->_data_buf_virt_addr_ch2 != NULL) { + memcpy((void *)(dev-> + _data_buf_virt_addr_ch2 + + offset / 4), mybuf, + vfs_read_retval); + } + + offset += vfs_read_retval; + + if (vfs_read_retval < line_size) { + pr_info("Done: exit %s() since no more bytes to read from Video file\n", + __func__); + break; + } + } + + if (i > 0) + dev->_frame_count_ch2++; + + if (vfs_read_retval < line_size) + break; + } + + dev->_file_status_ch2 = (vfs_read_retval == line_size) ? + IN_PROGRESS : END_OF_FILE; + + set_fs(old_fs); + myfile->f_pos = 0; + filp_close(myfile, NULL); + } + + return 0; +} + +static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev, + struct sram_channel *sram_ch, + int bpl) +{ + int ret = 0; + dma_addr_t dma_addr; + dma_addr_t data_dma_addr; + + if (dev->_dma_virt_addr_ch2 != NULL) { + pci_free_consistent(dev->pci, dev->upstream_riscbuf_size_ch2, + dev->_dma_virt_addr_ch2, + dev->_dma_phys_addr_ch2); + } + + dev->_dma_virt_addr_ch2 = pci_alloc_consistent(dev->pci, + dev->upstream_riscbuf_size_ch2, &dma_addr); + dev->_dma_virt_start_addr_ch2 = dev->_dma_virt_addr_ch2; + dev->_dma_phys_start_addr_ch2 = dma_addr; + dev->_dma_phys_addr_ch2 = dma_addr; + dev->_risc_size_ch2 = dev->upstream_riscbuf_size_ch2; + + if (!dev->_dma_virt_addr_ch2) { + pr_err("FAILED to allocate memory for Risc buffer! Returning\n"); + return -ENOMEM; + } + + /* Iniitize at this address until n bytes to 0 */ + memset(dev->_dma_virt_addr_ch2, 0, dev->_risc_size_ch2); + + if (dev->_data_buf_virt_addr_ch2 != NULL) { + pci_free_consistent(dev->pci, dev->upstream_databuf_size_ch2, + dev->_data_buf_virt_addr_ch2, + dev->_data_buf_phys_addr_ch2); + } + /* For Video Data buffer allocation */ + dev->_data_buf_virt_addr_ch2 = pci_alloc_consistent(dev->pci, + dev->upstream_databuf_size_ch2, &data_dma_addr); + dev->_data_buf_phys_addr_ch2 = data_dma_addr; + dev->_data_buf_size_ch2 = dev->upstream_databuf_size_ch2; + + if (!dev->_data_buf_virt_addr_ch2) { + pr_err("FAILED to allocate memory for data buffer! Returning\n"); + return -ENOMEM; + } + + /* Initialize at this address until n bytes to 0 */ + memset(dev->_data_buf_virt_addr_ch2, 0, dev->_data_buf_size_ch2); + + ret = cx25821_openfile_ch2(dev, sram_ch); + if (ret < 0) + return ret; + + /* Creating RISC programs */ + ret = cx25821_risc_buffer_upstream_ch2(dev, dev->pci, 0, bpl, + dev->_lines_count_ch2); + if (ret < 0) { + pr_info("Failed creating Video Upstream Risc programs!\n"); + goto error; + } + + return 0; + +error: + return ret; +} + +int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, int chan_num, + u32 status) +{ + u32 int_msk_tmp; + struct sram_channel *channel = dev->channels[chan_num].sram_channels; + int singlefield_lines = NTSC_FIELD_HEIGHT; + int line_size_in_bytes = Y422_LINE_SZ; + int odd_risc_prog_size = 0; + dma_addr_t risc_phys_jump_addr; + __le32 *rp; + + if (status & FLD_VID_SRC_RISC1) { + /* We should only process one program per call */ + u32 prog_cnt = cx_read(channel->gpcnt); + + /* + * Since we've identified our IRQ, clear our bits from the + * interrupt mask and interrupt status registers + */ + int_msk_tmp = cx_read(channel->int_msk); + cx_write(channel->int_msk, int_msk_tmp & ~_intr_msk); + cx_write(channel->int_stat, _intr_msk); + + spin_lock(&dev->slock); + + dev->_frame_index_ch2 = prog_cnt; + + queue_work(dev->_irq_queues_ch2, &dev->_irq_work_entry_ch2); + + if (dev->_is_first_frame_ch2) { + dev->_is_first_frame_ch2 = 0; + + if (dev->_isNTSC_ch2) { + singlefield_lines += 1; + odd_risc_prog_size = ODD_FLD_NTSC_PROG_SIZE; + } else { + singlefield_lines = PAL_FIELD_HEIGHT; + odd_risc_prog_size = ODD_FLD_PAL_PROG_SIZE; + } + + if (dev->_dma_virt_start_addr_ch2 != NULL) { + if (dev->_pixel_format_ch2 == PIXEL_FRMT_411) + line_size_in_bytes = Y411_LINE_SZ; + else + line_size_in_bytes = Y422_LINE_SZ; + risc_phys_jump_addr = + dev->_dma_phys_start_addr_ch2 + + odd_risc_prog_size; + + rp = cx25821_update_riscprogram_ch2(dev, + dev->_dma_virt_start_addr_ch2, + TOP_OFFSET, line_size_in_bytes, + 0x0, singlefield_lines, + FIFO_DISABLE, ODD_FIELD); + + /* Jump to Even Risc program of 1st Frame */ + *(rp++) = cpu_to_le32(RISC_JUMP); + *(rp++) = cpu_to_le32(risc_phys_jump_addr); + *(rp++) = cpu_to_le32(0); + } + } + + spin_unlock(&dev->slock); + } + + if (dev->_file_status_ch2 == END_OF_FILE) { + pr_info("EOF Channel 2 Framecount = %d\n", + dev->_frame_count_ch2); + return -1; + } + /* ElSE, set the interrupt mask register, re-enable irq. */ + int_msk_tmp = cx_read(channel->int_msk); + cx_write(channel->int_msk, int_msk_tmp |= _intr_msk); + + return 0; +} + +static irqreturn_t cx25821_upstream_irq_ch2(int irq, void *dev_id) +{ + struct cx25821_dev *dev = dev_id; + u32 vid_status; + int handled = 0; + int channel_num = 0; + struct sram_channel *sram_ch; + + if (!dev) + return -1; + + channel_num = VID_UPSTREAM_SRAM_CHANNEL_J; + sram_ch = dev->channels[channel_num].sram_channels; + + vid_status = cx_read(sram_ch->int_stat); + + /* Only deal with our interrupt */ + if (vid_status) + handled = cx25821_video_upstream_irq_ch2(dev, channel_num, + vid_status); + + if (handled < 0) + cx25821_stop_upstream_video_ch2(dev); + else + handled += handled; + + return IRQ_RETVAL(handled); +} + +static void cx25821_set_pixelengine_ch2(struct cx25821_dev *dev, + struct sram_channel *ch, int pix_format) +{ + int width = WIDTH_D1; + int height = dev->_lines_count_ch2; + int num_lines, odd_num_lines; + u32 value; + int vip_mode = PIXEL_ENGINE_VIP1; + + value = ((pix_format & 0x3) << 12) | (vip_mode & 0x7); + value &= 0xFFFFFFEF; + value |= dev->_isNTSC_ch2 ? 0 : 0x10; + cx_write(ch->vid_fmt_ctl, value); + + /* + * set number of active pixels in each line. Default is 720 + * pixels in both NTSC and PAL format + */ + cx_write(ch->vid_active_ctl1, width); + + num_lines = (height / 2) & 0x3FF; + odd_num_lines = num_lines; + + if (dev->_isNTSC_ch2) + odd_num_lines += 1; + + value = (num_lines << 16) | odd_num_lines; + + /* set number of active lines in field 0 (top) and field 1 (bottom) */ + cx_write(ch->vid_active_ctl2, value); + + cx_write(ch->vid_cdt_size, VID_CDT_SIZE >> 3); +} + +int cx25821_start_video_dma_upstream_ch2(struct cx25821_dev *dev, + struct sram_channel *sram_ch) +{ + u32 tmp = 0; + int err = 0; + + /* + * 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface + * for channel A-C + */ + tmp = cx_read(VID_CH_MODE_SEL); + cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF); + + /* + * Set the physical start address of the RISC program in the initial + * program counter(IPC) member of the cmds. + */ + cx_write(sram_ch->cmds_start + 0, dev->_dma_phys_addr_ch2); + cx_write(sram_ch->cmds_start + 4, 0); /* Risc IPC High 64 bits 63-32 */ + + /* reset counter */ + cx_write(sram_ch->gpcnt_ctl, 3); + + /* Clear our bits from the interrupt status register. */ + cx_write(sram_ch->int_stat, _intr_msk); + + /* Set the interrupt mask register, enable irq. */ + cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << sram_ch->irq_bit)); + tmp = cx_read(sram_ch->int_msk); + cx_write(sram_ch->int_msk, tmp |= _intr_msk); + + err = request_irq(dev->pci->irq, cx25821_upstream_irq_ch2, + IRQF_SHARED, dev->name, dev); + if (err < 0) { + pr_err("%s: can't get upstream IRQ %d\n", + dev->name, dev->pci->irq); + goto fail_irq; + } + /* Start the DMA engine */ + tmp = cx_read(sram_ch->dma_ctl); + cx_set(sram_ch->dma_ctl, tmp | FLD_VID_RISC_EN); + + dev->_is_running_ch2 = 1; + dev->_is_first_frame_ch2 = 1; + + return 0; + +fail_irq: + cx25821_dev_unregister(dev); + return err; +} + +int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select, + int pixel_format) +{ + struct sram_channel *sram_ch; + u32 tmp; + int retval = 0; + int err = 0; + int data_frame_size = 0; + int risc_buffer_size = 0; + int str_length = 0; + + if (dev->_is_running_ch2) { + pr_info("Video Channel is still running so return!\n"); + return 0; + } + + dev->_channel2_upstream_select = channel_select; + sram_ch = dev->channels[channel_select].sram_channels; + + INIT_WORK(&dev->_irq_work_entry_ch2, cx25821_vidups_handler_ch2); + dev->_irq_queues_ch2 = + create_singlethread_workqueue("cx25821_workqueue2"); + + if (!dev->_irq_queues_ch2) { + pr_err("create_singlethread_workqueue() for Video FAILED!\n"); + return -ENOMEM; + } + /* + * 656/VIP SRC Upstream Channel I & J and 7 - + * Host Bus Interface for channel A-C + */ + tmp = cx_read(VID_CH_MODE_SEL); + cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF); + + dev->_is_running_ch2 = 0; + dev->_frame_count_ch2 = 0; + dev->_file_status_ch2 = RESET_STATUS; + dev->_lines_count_ch2 = dev->_isNTSC_ch2 ? 480 : 576; + dev->_pixel_format_ch2 = pixel_format; + dev->_line_size_ch2 = (dev->_pixel_format_ch2 == PIXEL_FRMT_422) ? + (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; + data_frame_size = dev->_isNTSC_ch2 ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ; + risc_buffer_size = dev->_isNTSC_ch2 ? + NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE; + + if (dev->input_filename_ch2) { + str_length = strlen(dev->input_filename_ch2); + dev->_filename_ch2 = kmemdup(dev->input_filename_ch2, + str_length + 1, GFP_KERNEL); + + if (!dev->_filename_ch2) + goto error; + } else { + str_length = strlen(dev->_defaultname_ch2); + dev->_filename_ch2 = kmemdup(dev->_defaultname_ch2, + str_length + 1, GFP_KERNEL); + + if (!dev->_filename_ch2) + goto error; + } + + /* Default if filename is empty string */ + if (strcmp(dev->input_filename_ch2, "") == 0) { + if (dev->_isNTSC_ch2) { + dev->_filename_ch2 = (dev->_pixel_format_ch2 == + PIXEL_FRMT_411) ? "/root/vid411.yuv" : + "/root/vidtest.yuv"; + } else { + dev->_filename_ch2 = (dev->_pixel_format_ch2 == + PIXEL_FRMT_411) ? "/root/pal411.yuv" : + "/root/pal422.yuv"; + } + } + + retval = cx25821_sram_channel_setup_upstream(dev, sram_ch, + dev->_line_size_ch2, 0); + + /* setup fifo + format */ + cx25821_set_pixelengine_ch2(dev, sram_ch, dev->_pixel_format_ch2); + + dev->upstream_riscbuf_size_ch2 = risc_buffer_size * 2; + dev->upstream_databuf_size_ch2 = data_frame_size * 2; + + /* Allocating buffers and prepare RISC program */ + retval = cx25821_upstream_buffer_prepare_ch2(dev, sram_ch, + dev->_line_size_ch2); + if (retval < 0) { + pr_err("%s: Failed to set up Video upstream buffers!\n", + dev->name); + goto error; + } + + cx25821_start_video_dma_upstream_ch2(dev, sram_ch); + + return 0; + +error: + cx25821_dev_unregister(dev); + + return err; +} diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.h b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.h new file mode 100644 index 0000000..d42dab5 --- /dev/null +++ b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.h @@ -0,0 +1,138 @@ +/* + * Driver for the Conexant CX25821 PCIe bridge + * + * Copyright (C) 2009 Conexant Systems Inc. + * Authors <hiep.huynh@conexant.com>, <shu.lin@conexant.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/mutex.h> +#include <linux/workqueue.h> + +#define OPEN_FILE_1 0 +#define NUM_PROGS 8 +#define NUM_FRAMES 2 +#define ODD_FIELD 0 +#define EVEN_FIELD 1 +#define TOP_OFFSET 0 +#define FIFO_DISABLE 0 +#define FIFO_ENABLE 1 +#define TEST_FRAMES 5 +#define END_OF_FILE 0 +#define IN_PROGRESS 1 +#define RESET_STATUS -1 +#define NUM_NO_OPS 5 + +/* PAL and NTSC line sizes and number of lines. */ +#define WIDTH_D1 720 +#define NTSC_LINES_PER_FRAME 480 +#define PAL_LINES_PER_FRAME 576 +#define PAL_LINE_SZ 1440 +#define Y422_LINE_SZ 1440 +#define Y411_LINE_SZ 1080 +#define NTSC_FIELD_HEIGHT 240 +#define NTSC_ODD_FLD_LINES 241 +#define PAL_FIELD_HEIGHT 288 + +#define FRAME_SIZE_NTSC_Y422 (NTSC_LINES_PER_FRAME * Y422_LINE_SZ) +#define FRAME_SIZE_NTSC_Y411 (NTSC_LINES_PER_FRAME * Y411_LINE_SZ) +#define FRAME_SIZE_PAL_Y422 (PAL_LINES_PER_FRAME * Y422_LINE_SZ) +#define FRAME_SIZE_PAL_Y411 (PAL_LINES_PER_FRAME * Y411_LINE_SZ) + +#define NTSC_DATA_BUF_SZ (Y422_LINE_SZ * NTSC_LINES_PER_FRAME) +#define PAL_DATA_BUF_SZ (Y422_LINE_SZ * PAL_LINES_PER_FRAME) + +#define RISC_WRITECR_INSTRUCTION_SIZE 16 +#define RISC_SYNC_INSTRUCTION_SIZE 4 +#define JUMP_INSTRUCTION_SIZE 12 +#define MAXSIZE_NO_OPS 36 +#define DWORD_SIZE 4 + +#define USE_RISC_NOOP_VIDEO 1 + +#ifdef USE_RISC_NOOP_VIDEO +#define PAL_US_VID_PROG_SIZE \ + (PAL_FIELD_HEIGHT * 3 * DWORD_SIZE + \ + RISC_WRITECR_INSTRUCTION_SIZE + RISC_SYNC_INSTRUCTION_SIZE + \ + NUM_NO_OPS * DWORD_SIZE) + +#define PAL_RISC_BUF_SIZE (2 * PAL_US_VID_PROG_SIZE) + +#define PAL_VID_PROG_SIZE \ + ((PAL_FIELD_HEIGHT * 2) * 3 * DWORD_SIZE + \ + 2 * RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ + JUMP_INSTRUCTION_SIZE + 2 * NUM_NO_OPS * DWORD_SIZE) + +#define ODD_FLD_PAL_PROG_SIZE \ + (PAL_FIELD_HEIGHT * 3 * DWORD_SIZE + \ + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ + NUM_NO_OPS * DWORD_SIZE) + +#define NTSC_US_VID_PROG_SIZE \ + ((NTSC_ODD_FLD_LINES + 1) * 3 * DWORD_SIZE + \ + RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE + \ + NUM_NO_OPS * DWORD_SIZE) + +#define NTSC_RISC_BUF_SIZE \ + (2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE)) + +#define FRAME1_VID_PROG_SIZE \ + ((NTSC_ODD_FLD_LINES + NTSC_FIELD_HEIGHT) * \ + 3 * DWORD_SIZE + 2 * RISC_SYNC_INSTRUCTION_SIZE + \ + RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE + \ + 2 * NUM_NO_OPS * DWORD_SIZE) + +#define ODD_FLD_NTSC_PROG_SIZE \ + (NTSC_ODD_FLD_LINES * 3 * DWORD_SIZE + \ + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ + NUM_NO_OPS * DWORD_SIZE) +#endif + +#ifndef USE_RISC_NOOP_VIDEO +#define PAL_US_VID_PROG_SIZE \ + ((PAL_FIELD_HEIGHT + 1) * 3 * DWORD_SIZE + \ + RISC_WRITECR_INSTRUCTION_SIZE) + +#define PAL_RISC_BUF_SIZE \ + (2 * (RISC_SYNC_INSTRUCTION_SIZE + PAL_US_VID_PROG_SIZE)) + +#define PAL_VID_PROG_SIZE \ + ((PAL_FIELD_HEIGHT * 2) * 3 * DWORD_SIZE + \ + 2 * RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ + JUMP_INSTRUCTION_SIZE) + +#define ODD_FLD_PAL_PROG_SIZE \ + (PAL_FIELD_HEIGHT * 3 * DWORD_SIZE + \ + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE) + +#define ODD_FLD_NTSC_PROG_SIZE \ + (NTSC_ODD_FLD_LINES * 3 * DWORD_SIZE + \ + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE) + +#define NTSC_US_VID_PROG_SIZE \ + ((NTSC_ODD_FLD_LINES + 1) * 3 * DWORD_SIZE + \ + RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE) + +#define NTSC_RISC_BUF_SIZE \ + (2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE)) + +#define FRAME1_VID_PROG_SIZE \ + ((NTSC_ODD_FLD_LINES + NTSC_FIELD_HEIGHT) * \ + 3 * DWORD_SIZE + 2 * RISC_SYNC_INSTRUCTION_SIZE + \ + RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE) + +#endif diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream.c b/drivers/media/pci/cx25821/cx25821-video-upstream.c new file mode 100644 index 0000000..52c13e0 --- /dev/null +++ b/drivers/media/pci/cx25821/cx25821-video-upstream.c @@ -0,0 +1,856 @@ +/* + * Driver for the Conexant CX25821 PCIe bridge + * + * Copyright (C) 2009 Conexant Systems Inc. + * Authors <hiep.huynh@conexant.com>, <shu.lin@conexant.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include "cx25821-video.h" +#include "cx25821-video-upstream.h" + +#include <linux/fs.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/syscalls.h> +#include <linux/file.h> +#include <linux/fcntl.h> +#include <linux/slab.h> +#include <linux/uaccess.h> + +MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards"); +MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>"); +MODULE_LICENSE("GPL"); + +static int _intr_msk = FLD_VID_SRC_RISC1 | FLD_VID_SRC_UF | FLD_VID_SRC_SYNC | + FLD_VID_SRC_OPC_ERR; + +int cx25821_sram_channel_setup_upstream(struct cx25821_dev *dev, + struct sram_channel *ch, + unsigned int bpl, u32 risc) +{ + unsigned int i, lines; + u32 cdt; + + if (ch->cmds_start == 0) { + cx_write(ch->ptr1_reg, 0); + cx_write(ch->ptr2_reg, 0); + cx_write(ch->cnt2_reg, 0); + cx_write(ch->cnt1_reg, 0); + return 0; + } + + bpl = (bpl + 7) & ~7; /* alignment */ + cdt = ch->cdt; + lines = ch->fifo_size / bpl; + + if (lines > 4) + lines = 4; + + BUG_ON(lines < 2); + + /* write CDT */ + for (i = 0; i < lines; i++) { + cx_write(cdt + 16 * i, ch->fifo_start + bpl * i); + cx_write(cdt + 16 * i + 4, 0); + cx_write(cdt + 16 * i + 8, 0); + cx_write(cdt + 16 * i + 12, 0); + } + + /* write CMDS */ + cx_write(ch->cmds_start + 0, risc); + + cx_write(ch->cmds_start + 4, 0); + cx_write(ch->cmds_start + 8, cdt); + cx_write(ch->cmds_start + 12, (lines * 16) >> 3); + cx_write(ch->cmds_start + 16, ch->ctrl_start); + + cx_write(ch->cmds_start + 20, VID_IQ_SIZE_DW); + + for (i = 24; i < 80; i += 4) + cx_write(ch->cmds_start + i, 0); + + /* fill registers */ + cx_write(ch->ptr1_reg, ch->fifo_start); + cx_write(ch->ptr2_reg, cdt); + cx_write(ch->cnt2_reg, (lines * 16) >> 3); + cx_write(ch->cnt1_reg, (bpl >> 3) - 1); + + return 0; +} + +static __le32 *cx25821_update_riscprogram(struct cx25821_dev *dev, + __le32 *rp, unsigned int offset, + unsigned int bpl, u32 sync_line, + unsigned int lines, int fifo_enable, + int field_type) +{ + unsigned int line, i; + int dist_betwn_starts = bpl * 2; + + *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); + + if (USE_RISC_NOOP_VIDEO) { + for (i = 0; i < NUM_NO_OPS; i++) + *(rp++) = cpu_to_le32(RISC_NOOP); + } + + /* scan lines */ + for (line = 0; line < lines; line++) { + *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); + *(rp++) = cpu_to_le32(dev->_data_buf_phys_addr + offset); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + + if ((lines <= NTSC_FIELD_HEIGHT) + || (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC)) { + offset += dist_betwn_starts; + } + } + + return rp; +} + +static __le32 *cx25821_risc_field_upstream(struct cx25821_dev *dev, __le32 * rp, + dma_addr_t databuf_phys_addr, + unsigned int offset, u32 sync_line, + unsigned int bpl, unsigned int lines, + int fifo_enable, int field_type) +{ + unsigned int line, i; + struct sram_channel *sram_ch = + dev->channels[dev->_channel_upstream_select].sram_channels; + int dist_betwn_starts = bpl * 2; + + /* sync instruction */ + if (sync_line != NO_SYNC_LINE) + *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); + + if (USE_RISC_NOOP_VIDEO) { + for (i = 0; i < NUM_NO_OPS; i++) + *(rp++) = cpu_to_le32(RISC_NOOP); + } + + /* scan lines */ + for (line = 0; line < lines; line++) { + *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); + *(rp++) = cpu_to_le32(databuf_phys_addr + offset); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + + if ((lines <= NTSC_FIELD_HEIGHT) + || (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC)) + /* to skip the other field line */ + offset += dist_betwn_starts; + + /* check if we need to enable the FIFO after the first 4 lines + * For the upstream video channel, the risc engine will enable + * the FIFO. */ + if (fifo_enable && line == 3) { + *(rp++) = RISC_WRITECR; + *(rp++) = sram_ch->dma_ctl; + *(rp++) = FLD_VID_FIFO_EN; + *(rp++) = 0x00000001; + } + } + + return rp; +} + +int cx25821_risc_buffer_upstream(struct cx25821_dev *dev, + struct pci_dev *pci, + unsigned int top_offset, + unsigned int bpl, unsigned int lines) +{ + __le32 *rp; + int fifo_enable = 0; + /* get line count for single field */ + int singlefield_lines = lines >> 1; + int odd_num_lines = singlefield_lines; + int frame = 0; + int frame_size = 0; + int databuf_offset = 0; + int risc_program_size = 0; + int risc_flag = RISC_CNT_RESET; + unsigned int bottom_offset = bpl; + dma_addr_t risc_phys_jump_addr; + + if (dev->_isNTSC) { + odd_num_lines = singlefield_lines + 1; + risc_program_size = FRAME1_VID_PROG_SIZE; + frame_size = (bpl == Y411_LINE_SZ) ? + FRAME_SIZE_NTSC_Y411 : FRAME_SIZE_NTSC_Y422; + } else { + risc_program_size = PAL_VID_PROG_SIZE; + frame_size = (bpl == Y411_LINE_SZ) ? + FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; + } + + /* Virtual address of Risc buffer program */ + rp = dev->_dma_virt_addr; + + for (frame = 0; frame < NUM_FRAMES; frame++) { + databuf_offset = frame_size * frame; + + if (UNSET != top_offset) { + fifo_enable = (frame == 0) ? FIFO_ENABLE : FIFO_DISABLE; + rp = cx25821_risc_field_upstream(dev, rp, + dev->_data_buf_phys_addr + + databuf_offset, top_offset, 0, bpl, + odd_num_lines, fifo_enable, ODD_FIELD); + } + + fifo_enable = FIFO_DISABLE; + + /* Even Field */ + rp = cx25821_risc_field_upstream(dev, rp, + dev->_data_buf_phys_addr + + databuf_offset, bottom_offset, + 0x200, bpl, singlefield_lines, + fifo_enable, EVEN_FIELD); + + if (frame == 0) { + risc_flag = RISC_CNT_RESET; + risc_phys_jump_addr = dev->_dma_phys_start_addr + + risc_program_size; + } else { + risc_phys_jump_addr = dev->_dma_phys_start_addr; + risc_flag = RISC_CNT_INC; + } + + /* Loop to 2ndFrameRISC or to Start of Risc + * program & generate IRQ + */ + *(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag); + *(rp++) = cpu_to_le32(risc_phys_jump_addr); + *(rp++) = cpu_to_le32(0); + } + + return 0; +} + +void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev) +{ + struct sram_channel *sram_ch = + dev->channels[VID_UPSTREAM_SRAM_CHANNEL_I].sram_channels; + u32 tmp = 0; + + if (!dev->_is_running) { + pr_info("No video file is currently running so return!\n"); + return; + } + /* Disable RISC interrupts */ + tmp = cx_read(sram_ch->int_msk); + cx_write(sram_ch->int_msk, tmp & ~_intr_msk); + + /* Turn OFF risc and fifo enable */ + tmp = cx_read(sram_ch->dma_ctl); + cx_write(sram_ch->dma_ctl, tmp & ~(FLD_VID_FIFO_EN | FLD_VID_RISC_EN)); + + /* Clear data buffer memory */ + if (dev->_data_buf_virt_addr) + memset(dev->_data_buf_virt_addr, 0, dev->_data_buf_size); + + dev->_is_running = 0; + dev->_is_first_frame = 0; + dev->_frame_count = 0; + dev->_file_status = END_OF_FILE; + + kfree(dev->_irq_queues); + dev->_irq_queues = NULL; + + kfree(dev->_filename); + + tmp = cx_read(VID_CH_MODE_SEL); + cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00); +} + +void cx25821_free_mem_upstream_ch1(struct cx25821_dev *dev) +{ + if (dev->_is_running) + cx25821_stop_upstream_video_ch1(dev); + + if (dev->_dma_virt_addr) { + pci_free_consistent(dev->pci, dev->_risc_size, + dev->_dma_virt_addr, dev->_dma_phys_addr); + dev->_dma_virt_addr = NULL; + } + + if (dev->_data_buf_virt_addr) { + pci_free_consistent(dev->pci, dev->_data_buf_size, + dev->_data_buf_virt_addr, + dev->_data_buf_phys_addr); + dev->_data_buf_virt_addr = NULL; + } +} + +int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch) +{ + struct file *myfile; + int frame_index_temp = dev->_frame_index; + int i = 0; + int line_size = (dev->_pixel_format == PIXEL_FRMT_411) ? + Y411_LINE_SZ : Y422_LINE_SZ; + int frame_size = 0; + int frame_offset = 0; + ssize_t vfs_read_retval = 0; + char mybuf[line_size]; + loff_t file_offset; + loff_t pos; + mm_segment_t old_fs; + + if (dev->_file_status == END_OF_FILE) + return 0; + + if (dev->_isNTSC) + frame_size = (line_size == Y411_LINE_SZ) ? + FRAME_SIZE_NTSC_Y411 : FRAME_SIZE_NTSC_Y422; + else + frame_size = (line_size == Y411_LINE_SZ) ? + FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; + + frame_offset = (frame_index_temp > 0) ? frame_size : 0; + file_offset = dev->_frame_count * frame_size; + + myfile = filp_open(dev->_filename, O_RDONLY | O_LARGEFILE, 0); + + if (IS_ERR(myfile)) { + const int open_errno = -PTR_ERR(myfile); + pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", + __func__, dev->_filename, open_errno); + return PTR_ERR(myfile); + } else { + if (!(myfile->f_op)) { + pr_err("%s(): File has no file operations registered!\n", + __func__); + filp_close(myfile, NULL); + return -EIO; + } + + if (!myfile->f_op->read) { + pr_err("%s(): File has no READ operations registered!\n", + __func__); + filp_close(myfile, NULL); + return -EIO; + } + + pos = myfile->f_pos; + old_fs = get_fs(); + set_fs(KERNEL_DS); + + for (i = 0; i < dev->_lines_count; i++) { + pos = file_offset; + + vfs_read_retval = vfs_read(myfile, mybuf, line_size, + &pos); + + if (vfs_read_retval > 0 && vfs_read_retval == line_size + && dev->_data_buf_virt_addr != NULL) { + memcpy((void *)(dev->_data_buf_virt_addr + + frame_offset / 4), mybuf, + vfs_read_retval); + } + + file_offset += vfs_read_retval; + frame_offset += vfs_read_retval; + + if (vfs_read_retval < line_size) { + pr_info("Done: exit %s() since no more bytes to read from Video file\n", + __func__); + break; + } + } + + if (i > 0) + dev->_frame_count++; + + dev->_file_status = (vfs_read_retval == line_size) ? + IN_PROGRESS : END_OF_FILE; + + set_fs(old_fs); + filp_close(myfile, NULL); + } + + return 0; +} + +static void cx25821_vidups_handler(struct work_struct *work) +{ + struct cx25821_dev *dev = container_of(work, struct cx25821_dev, + _irq_work_entry); + + if (!dev) { + pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n", + __func__); + return; + } + + cx25821_get_frame(dev, dev->channels[dev->_channel_upstream_select]. + sram_channels); +} + +int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch) +{ + struct file *myfile; + int i = 0, j = 0; + int line_size = (dev->_pixel_format == PIXEL_FRMT_411) ? + Y411_LINE_SZ : Y422_LINE_SZ; + ssize_t vfs_read_retval = 0; + char mybuf[line_size]; + loff_t pos; + loff_t offset = (unsigned long)0; + mm_segment_t old_fs; + + myfile = filp_open(dev->_filename, O_RDONLY | O_LARGEFILE, 0); + + if (IS_ERR(myfile)) { + const int open_errno = -PTR_ERR(myfile); + pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", + __func__, dev->_filename, open_errno); + return PTR_ERR(myfile); + } else { + if (!(myfile->f_op)) { + pr_err("%s(): File has no file operations registered!\n", + __func__); + filp_close(myfile, NULL); + return -EIO; + } + + if (!myfile->f_op->read) { + pr_err("%s(): File has no READ operations registered! Returning\n", + __func__); + filp_close(myfile, NULL); + return -EIO; + } + + pos = myfile->f_pos; + old_fs = get_fs(); + set_fs(KERNEL_DS); + + for (j = 0; j < NUM_FRAMES; j++) { + for (i = 0; i < dev->_lines_count; i++) { + pos = offset; + + vfs_read_retval = vfs_read(myfile, mybuf, + line_size, &pos); + + if (vfs_read_retval > 0 + && vfs_read_retval == line_size + && dev->_data_buf_virt_addr != NULL) { + memcpy((void *)(dev-> + _data_buf_virt_addr + + offset / 4), mybuf, + vfs_read_retval); + } + + offset += vfs_read_retval; + + if (vfs_read_retval < line_size) { + pr_info("Done: exit %s() since no more bytes to read from Video file\n", + __func__); + break; + } + } + + if (i > 0) + dev->_frame_count++; + + if (vfs_read_retval < line_size) + break; + } + + dev->_file_status = (vfs_read_retval == line_size) ? + IN_PROGRESS : END_OF_FILE; + + set_fs(old_fs); + myfile->f_pos = 0; + filp_close(myfile, NULL); + } + + return 0; +} + +int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev, + struct sram_channel *sram_ch, int bpl) +{ + int ret = 0; + dma_addr_t dma_addr; + dma_addr_t data_dma_addr; + + if (dev->_dma_virt_addr != NULL) + pci_free_consistent(dev->pci, dev->upstream_riscbuf_size, + dev->_dma_virt_addr, dev->_dma_phys_addr); + + dev->_dma_virt_addr = pci_alloc_consistent(dev->pci, + dev->upstream_riscbuf_size, &dma_addr); + dev->_dma_virt_start_addr = dev->_dma_virt_addr; + dev->_dma_phys_start_addr = dma_addr; + dev->_dma_phys_addr = dma_addr; + dev->_risc_size = dev->upstream_riscbuf_size; + + if (!dev->_dma_virt_addr) { + pr_err("FAILED to allocate memory for Risc buffer! Returning\n"); + return -ENOMEM; + } + + /* Clear memory at address */ + memset(dev->_dma_virt_addr, 0, dev->_risc_size); + + if (dev->_data_buf_virt_addr != NULL) + pci_free_consistent(dev->pci, dev->upstream_databuf_size, + dev->_data_buf_virt_addr, + dev->_data_buf_phys_addr); + /* For Video Data buffer allocation */ + dev->_data_buf_virt_addr = pci_alloc_consistent(dev->pci, + dev->upstream_databuf_size, &data_dma_addr); + dev->_data_buf_phys_addr = data_dma_addr; + dev->_data_buf_size = dev->upstream_databuf_size; + + if (!dev->_data_buf_virt_addr) { + pr_err("FAILED to allocate memory for data buffer! Returning\n"); + return -ENOMEM; + } + + /* Clear memory at address */ + memset(dev->_data_buf_virt_addr, 0, dev->_data_buf_size); + + ret = cx25821_openfile(dev, sram_ch); + if (ret < 0) + return ret; + + /* Create RISC programs */ + ret = cx25821_risc_buffer_upstream(dev, dev->pci, 0, bpl, + dev->_lines_count); + if (ret < 0) { + pr_info("Failed creating Video Upstream Risc programs!\n"); + goto error; + } + + return 0; + +error: + return ret; +} + +int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num, + u32 status) +{ + u32 int_msk_tmp; + struct sram_channel *channel = dev->channels[chan_num].sram_channels; + int singlefield_lines = NTSC_FIELD_HEIGHT; + int line_size_in_bytes = Y422_LINE_SZ; + int odd_risc_prog_size = 0; + dma_addr_t risc_phys_jump_addr; + __le32 *rp; + + if (status & FLD_VID_SRC_RISC1) { + /* We should only process one program per call */ + u32 prog_cnt = cx_read(channel->gpcnt); + + /* Since we've identified our IRQ, clear our bits from the + * interrupt mask and interrupt status registers */ + int_msk_tmp = cx_read(channel->int_msk); + cx_write(channel->int_msk, int_msk_tmp & ~_intr_msk); + cx_write(channel->int_stat, _intr_msk); + + spin_lock(&dev->slock); + + dev->_frame_index = prog_cnt; + + queue_work(dev->_irq_queues, &dev->_irq_work_entry); + + if (dev->_is_first_frame) { + dev->_is_first_frame = 0; + + if (dev->_isNTSC) { + singlefield_lines += 1; + odd_risc_prog_size = ODD_FLD_NTSC_PROG_SIZE; + } else { + singlefield_lines = PAL_FIELD_HEIGHT; + odd_risc_prog_size = ODD_FLD_PAL_PROG_SIZE; + } + + if (dev->_dma_virt_start_addr != NULL) { + line_size_in_bytes = + (dev->_pixel_format == + PIXEL_FRMT_411) ? Y411_LINE_SZ : + Y422_LINE_SZ; + risc_phys_jump_addr = + dev->_dma_phys_start_addr + + odd_risc_prog_size; + + rp = cx25821_update_riscprogram(dev, + dev->_dma_virt_start_addr, TOP_OFFSET, + line_size_in_bytes, 0x0, + singlefield_lines, FIFO_DISABLE, + ODD_FIELD); + + /* Jump to Even Risc program of 1st Frame */ + *(rp++) = cpu_to_le32(RISC_JUMP); + *(rp++) = cpu_to_le32(risc_phys_jump_addr); + *(rp++) = cpu_to_le32(0); + } + } + + spin_unlock(&dev->slock); + } else { + if (status & FLD_VID_SRC_UF) + pr_err("%s(): Video Received Underflow Error Interrupt!\n", + __func__); + + if (status & FLD_VID_SRC_SYNC) + pr_err("%s(): Video Received Sync Error Interrupt!\n", + __func__); + + if (status & FLD_VID_SRC_OPC_ERR) + pr_err("%s(): Video Received OpCode Error Interrupt!\n", + __func__); + } + + if (dev->_file_status == END_OF_FILE) { + pr_err("EOF Channel 1 Framecount = %d\n", dev->_frame_count); + return -1; + } + /* ElSE, set the interrupt mask register, re-enable irq. */ + int_msk_tmp = cx_read(channel->int_msk); + cx_write(channel->int_msk, int_msk_tmp |= _intr_msk); + + return 0; +} + +static irqreturn_t cx25821_upstream_irq(int irq, void *dev_id) +{ + struct cx25821_dev *dev = dev_id; + u32 vid_status; + int handled = 0; + int channel_num = 0; + struct sram_channel *sram_ch; + + if (!dev) + return -1; + + channel_num = VID_UPSTREAM_SRAM_CHANNEL_I; + + sram_ch = dev->channels[channel_num].sram_channels; + + vid_status = cx_read(sram_ch->int_stat); + + /* Only deal with our interrupt */ + if (vid_status) + handled = cx25821_video_upstream_irq(dev, channel_num, + vid_status); + + if (handled < 0) + cx25821_stop_upstream_video_ch1(dev); + else + handled += handled; + + return IRQ_RETVAL(handled); +} + +void cx25821_set_pixelengine(struct cx25821_dev *dev, struct sram_channel *ch, + int pix_format) +{ + int width = WIDTH_D1; + int height = dev->_lines_count; + int num_lines, odd_num_lines; + u32 value; + int vip_mode = OUTPUT_FRMT_656; + + value = ((pix_format & 0x3) << 12) | (vip_mode & 0x7); + value &= 0xFFFFFFEF; + value |= dev->_isNTSC ? 0 : 0x10; + cx_write(ch->vid_fmt_ctl, value); + + /* set number of active pixels in each line. + * Default is 720 pixels in both NTSC and PAL format */ + cx_write(ch->vid_active_ctl1, width); + + num_lines = (height / 2) & 0x3FF; + odd_num_lines = num_lines; + + if (dev->_isNTSC) + odd_num_lines += 1; + + value = (num_lines << 16) | odd_num_lines; + + /* set number of active lines in field 0 (top) and field 1 (bottom) */ + cx_write(ch->vid_active_ctl2, value); + + cx_write(ch->vid_cdt_size, VID_CDT_SIZE >> 3); +} + +int cx25821_start_video_dma_upstream(struct cx25821_dev *dev, + struct sram_channel *sram_ch) +{ + u32 tmp = 0; + int err = 0; + + /* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for + * channel A-C + */ + tmp = cx_read(VID_CH_MODE_SEL); + cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF); + + /* Set the physical start address of the RISC program in the initial + * program counter(IPC) member of the cmds. + */ + cx_write(sram_ch->cmds_start + 0, dev->_dma_phys_addr); + /* Risc IPC High 64 bits 63-32 */ + cx_write(sram_ch->cmds_start + 4, 0); + + /* reset counter */ + cx_write(sram_ch->gpcnt_ctl, 3); + + /* Clear our bits from the interrupt status register. */ + cx_write(sram_ch->int_stat, _intr_msk); + + /* Set the interrupt mask register, enable irq. */ + cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << sram_ch->irq_bit)); + tmp = cx_read(sram_ch->int_msk); + cx_write(sram_ch->int_msk, tmp |= _intr_msk); + + err = request_irq(dev->pci->irq, cx25821_upstream_irq, + IRQF_SHARED, dev->name, dev); + if (err < 0) { + pr_err("%s: can't get upstream IRQ %d\n", + dev->name, dev->pci->irq); + goto fail_irq; + } + + /* Start the DMA engine */ + tmp = cx_read(sram_ch->dma_ctl); + cx_set(sram_ch->dma_ctl, tmp | FLD_VID_RISC_EN); + + dev->_is_running = 1; + dev->_is_first_frame = 1; + + return 0; + +fail_irq: + cx25821_dev_unregister(dev); + return err; +} + +int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select, + int pixel_format) +{ + struct sram_channel *sram_ch; + u32 tmp; + int retval = 0; + int err = 0; + int data_frame_size = 0; + int risc_buffer_size = 0; + int str_length = 0; + + if (dev->_is_running) { + pr_info("Video Channel is still running so return!\n"); + return 0; + } + + dev->_channel_upstream_select = channel_select; + sram_ch = dev->channels[channel_select].sram_channels; + + INIT_WORK(&dev->_irq_work_entry, cx25821_vidups_handler); + dev->_irq_queues = create_singlethread_workqueue("cx25821_workqueue"); + + if (!dev->_irq_queues) { + pr_err("create_singlethread_workqueue() for Video FAILED!\n"); + return -ENOMEM; + } + /* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for + * channel A-C + */ + tmp = cx_read(VID_CH_MODE_SEL); + cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF); + + dev->_is_running = 0; + dev->_frame_count = 0; + dev->_file_status = RESET_STATUS; + dev->_lines_count = dev->_isNTSC ? 480 : 576; + dev->_pixel_format = pixel_format; + dev->_line_size = (dev->_pixel_format == PIXEL_FRMT_422) ? + (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; + data_frame_size = dev->_isNTSC ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ; + risc_buffer_size = dev->_isNTSC ? + NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE; + + if (dev->input_filename) { + str_length = strlen(dev->input_filename); + dev->_filename = kmemdup(dev->input_filename, str_length + 1, + GFP_KERNEL); + + if (!dev->_filename) + goto error; + } else { + str_length = strlen(dev->_defaultname); + dev->_filename = kmemdup(dev->_defaultname, str_length + 1, + GFP_KERNEL); + + if (!dev->_filename) + goto error; + } + + /* Default if filename is empty string */ + if (strcmp(dev->input_filename, "") == 0) { + if (dev->_isNTSC) { + dev->_filename = + (dev->_pixel_format == PIXEL_FRMT_411) ? + "/root/vid411.yuv" : "/root/vidtest.yuv"; + } else { + dev->_filename = + (dev->_pixel_format == PIXEL_FRMT_411) ? + "/root/pal411.yuv" : "/root/pal422.yuv"; + } + } + + dev->_is_running = 0; + dev->_frame_count = 0; + dev->_file_status = RESET_STATUS; + dev->_lines_count = dev->_isNTSC ? 480 : 576; + dev->_pixel_format = pixel_format; + dev->_line_size = (dev->_pixel_format == PIXEL_FRMT_422) ? + (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; + + retval = cx25821_sram_channel_setup_upstream(dev, sram_ch, + dev->_line_size, 0); + + /* setup fifo + format */ + cx25821_set_pixelengine(dev, sram_ch, dev->_pixel_format); + + dev->upstream_riscbuf_size = risc_buffer_size * 2; + dev->upstream_databuf_size = data_frame_size * 2; + + /* Allocating buffers and prepare RISC program */ + retval = cx25821_upstream_buffer_prepare(dev, sram_ch, dev->_line_size); + if (retval < 0) { + pr_err("%s: Failed to set up Video upstream buffers!\n", + dev->name); + goto error; + } + + cx25821_start_video_dma_upstream(dev, sram_ch); + + return 0; + +error: + cx25821_dev_unregister(dev); + + return err; +} diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream.h b/drivers/media/pci/cx25821/cx25821-video-upstream.h new file mode 100644 index 0000000..268ec8a --- /dev/null +++ b/drivers/media/pci/cx25821/cx25821-video-upstream.h @@ -0,0 +1,139 @@ +/* + * Driver for the Conexant CX25821 PCIe bridge + * + * Copyright (C) 2009 Conexant Systems Inc. + * Authors <hiep.huynh@conexant.com>, <shu.lin@conexant.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/mutex.h> +#include <linux/workqueue.h> + +#define OUTPUT_FRMT_656 0 +#define OPEN_FILE_1 0 +#define NUM_PROGS 8 +#define NUM_FRAMES 2 +#define ODD_FIELD 0 +#define EVEN_FIELD 1 +#define TOP_OFFSET 0 +#define FIFO_DISABLE 0 +#define FIFO_ENABLE 1 +#define TEST_FRAMES 5 +#define END_OF_FILE 0 +#define IN_PROGRESS 1 +#define RESET_STATUS -1 +#define NUM_NO_OPS 5 + +/* PAL and NTSC line sizes and number of lines. */ +#define WIDTH_D1 720 +#define NTSC_LINES_PER_FRAME 480 +#define PAL_LINES_PER_FRAME 576 +#define PAL_LINE_SZ 1440 +#define Y422_LINE_SZ 1440 +#define Y411_LINE_SZ 1080 +#define NTSC_FIELD_HEIGHT 240 +#define NTSC_ODD_FLD_LINES 241 +#define PAL_FIELD_HEIGHT 288 + +#define FRAME_SIZE_NTSC_Y422 (NTSC_LINES_PER_FRAME * Y422_LINE_SZ) +#define FRAME_SIZE_NTSC_Y411 (NTSC_LINES_PER_FRAME * Y411_LINE_SZ) +#define FRAME_SIZE_PAL_Y422 (PAL_LINES_PER_FRAME * Y422_LINE_SZ) +#define FRAME_SIZE_PAL_Y411 (PAL_LINES_PER_FRAME * Y411_LINE_SZ) + +#define NTSC_DATA_BUF_SZ (Y422_LINE_SZ * NTSC_LINES_PER_FRAME) +#define PAL_DATA_BUF_SZ (Y422_LINE_SZ * PAL_LINES_PER_FRAME) + +#define RISC_WRITECR_INSTRUCTION_SIZE 16 +#define RISC_SYNC_INSTRUCTION_SIZE 4 +#define JUMP_INSTRUCTION_SIZE 12 +#define MAXSIZE_NO_OPS 36 +#define DWORD_SIZE 4 + +#define USE_RISC_NOOP_VIDEO 1 + +#ifdef USE_RISC_NOOP_VIDEO +#define PAL_US_VID_PROG_SIZE \ + (PAL_FIELD_HEIGHT * 3 * DWORD_SIZE + \ + RISC_WRITECR_INSTRUCTION_SIZE + RISC_SYNC_INSTRUCTION_SIZE + \ + NUM_NO_OPS * DWORD_SIZE) + +#define PAL_RISC_BUF_SIZE (2 * PAL_US_VID_PROG_SIZE) + +#define PAL_VID_PROG_SIZE \ + ((PAL_FIELD_HEIGHT * 2) * 3 * DWORD_SIZE + \ + 2 * RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ + JUMP_INSTRUCTION_SIZE + 2 * NUM_NO_OPS * DWORD_SIZE) + +#define ODD_FLD_PAL_PROG_SIZE \ + (PAL_FIELD_HEIGHT * 3 * DWORD_SIZE + \ + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ + NUM_NO_OPS * DWORD_SIZE) + +#define ODD_FLD_NTSC_PROG_SIZE \ + (NTSC_ODD_FLD_LINES * 3 * DWORD_SIZE + \ + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ + NUM_NO_OPS * DWORD_SIZE) + +#define NTSC_US_VID_PROG_SIZE \ + ((NTSC_ODD_FLD_LINES + 1) * 3 * DWORD_SIZE + \ + RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE + \ + NUM_NO_OPS * DWORD_SIZE) + +#define NTSC_RISC_BUF_SIZE \ + (2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE)) + +#define FRAME1_VID_PROG_SIZE \ + ((NTSC_ODD_FLD_LINES + NTSC_FIELD_HEIGHT) * 3 * DWORD_SIZE + \ + 2 * RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ + JUMP_INSTRUCTION_SIZE + 2 * NUM_NO_OPS * DWORD_SIZE) + +#endif + +#ifndef USE_RISC_NOOP_VIDEO +#define PAL_US_VID_PROG_SIZE \ + (PAL_FIELD_HEIGHT * 3 * DWORD_SIZE + \ + RISC_WRITECR_INSTRUCTION_SIZE + RISC_SYNC_INSTRUCTION_SIZE + \ + JUMP_INSTRUCTION_SIZE) + +#define PAL_RISC_BUF_SIZE (2 * PAL_US_VID_PROG_SIZE) + +#define PAL_VID_PROG_SIZE \ + ((PAL_FIELD_HEIGHT * 2) * 3 * DWORD_SIZE + \ + 2 * RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ + JUMP_INSTRUCTION_SIZE) + +#define ODD_FLD_PAL_PROG_SIZE \ + (PAL_FIELD_HEIGHT * 3 * DWORD_SIZE + \ + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE) + +#define ODD_FLD_NTSC_PROG_SIZE \ + (NTSC_ODD_FLD_LINES * 3 * DWORD_SIZE + \ + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE) + +#define NTSC_US_VID_PROG_SIZE \ + ((NTSC_ODD_FLD_LINES + 1) * 3 * DWORD_SIZE + \ + RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE) + +#define NTSC_RISC_BUF_SIZE \ + (2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE)) + +#define FRAME1_VID_PROG_SIZE \ + ((NTSC_ODD_FLD_LINES + NTSC_FIELD_HEIGHT) * 3 * DWORD_SIZE + \ + 2 * RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ + JUMP_INSTRUCTION_SIZE) + +#endif diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c new file mode 100644 index 0000000..b38d437 --- /dev/null +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -0,0 +1,1990 @@ +/* + * Driver for the Conexant CX25821 PCIe bridge + * + * Copyright (C) 2009 Conexant Systems Inc. + * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> + * Based on Steven Toth <stoth@linuxtv.org> cx23885 driver + * Parts adapted/taken from Eduardo Moscoso Rubino + * Copyright (C) 2009 Eduardo Moscoso Rubino <moscoso@TopoLogica.com> + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include "cx25821-video.h" + +MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards"); +MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>"); +MODULE_LICENSE("GPL"); + +static unsigned int video_nr[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET }; +static unsigned int radio_nr[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET }; + +module_param_array(video_nr, int, NULL, 0444); +module_param_array(radio_nr, int, NULL, 0444); + +MODULE_PARM_DESC(video_nr, "video device numbers"); +MODULE_PARM_DESC(radio_nr, "radio device numbers"); + +static unsigned int video_debug = VIDEO_DEBUG; +module_param(video_debug, int, 0644); +MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); + +static unsigned int irq_debug; +module_param(irq_debug, int, 0644); +MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]"); + +unsigned int vid_limit = 16; +module_param(vid_limit, int, 0644); +MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); + +static void cx25821_init_controls(struct cx25821_dev *dev, int chan_num); + +static const struct v4l2_file_operations video_fops; +static const struct v4l2_ioctl_ops video_ioctl_ops; + +#define FORMAT_FLAGS_PACKED 0x01 + +struct cx25821_fmt formats[] = { + { + .name = "8 bpp, gray", + .fourcc = V4L2_PIX_FMT_GREY, + .depth = 8, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "4:1:1, packed, Y41P", + .fourcc = V4L2_PIX_FMT_Y41P, + .depth = 12, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "4:2:2, packed, YUYV", + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "4:2:2, packed, UYVY", + .fourcc = V4L2_PIX_FMT_UYVY, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "4:2:0, YUV", + .fourcc = V4L2_PIX_FMT_YUV420, + .depth = 12, + .flags = FORMAT_FLAGS_PACKED, + }, +}; + +int cx25821_get_format_size(void) +{ + return ARRAY_SIZE(formats); +} + +struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc) +{ + unsigned int i; + + if (fourcc == V4L2_PIX_FMT_Y41P || fourcc == V4L2_PIX_FMT_YUV411P) + return formats + 1; + + for (i = 0; i < ARRAY_SIZE(formats); i++) + if (formats[i].fourcc == fourcc) + return formats + i; + + pr_err("%s(0x%08x) NOT FOUND\n", __func__, fourcc); + return NULL; +} + +void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q, + u32 count) +{ + struct cx25821_buffer *buf; + int bc; + + for (bc = 0;; bc++) { + if (list_empty(&q->active)) { + dprintk(1, "bc=%d (=0: active empty)\n", bc); + break; + } + + buf = list_entry(q->active.next, struct cx25821_buffer, + vb.queue); + + /* count comes from the hw and it is 16bit wide -- + * this trick handles wrap-arounds correctly for + * up to 32767 buffers in flight... */ + if ((s16) (count - buf->count) < 0) + break; + + do_gettimeofday(&buf->vb.ts); + buf->vb.state = VIDEOBUF_DONE; + list_del(&buf->vb.queue); + wake_up(&buf->vb.done); + } + + if (list_empty(&q->active)) + del_timer(&q->timeout); + else + mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); + if (bc != 1) + pr_err("%s: %d buffers handled (should be 1)\n", __func__, bc); +} + +#ifdef TUNER_FLAG +int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm) +{ + dprintk(1, "%s(norm = 0x%08x) name: [%s]\n", + __func__, (unsigned int)norm, v4l2_norm_to_name(norm)); + + dev->tvnorm = norm; + + /* Tell the internal A/V decoder */ + cx25821_call_all(dev, core, s_std, norm); + + return 0; +} +#endif + +struct video_device *cx25821_vdev_init(struct cx25821_dev *dev, + struct pci_dev *pci, + struct video_device *template, + char *type) +{ + struct video_device *vfd; + dprintk(1, "%s()\n", __func__); + + vfd = video_device_alloc(); + if (NULL == vfd) + return NULL; + *vfd = *template; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->release = video_device_release; + snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, type, + cx25821_boards[dev->board].name); + video_set_drvdata(vfd, dev); + return vfd; +} + +/* +static int cx25821_ctrl_query(struct v4l2_queryctrl *qctrl) +{ + int i; + + if (qctrl->id < V4L2_CID_BASE || qctrl->id >= V4L2_CID_LASTP1) + return -EINVAL; + for (i = 0; i < CX25821_CTLS; i++) + if (cx25821_ctls[i].v.id == qctrl->id) + break; + if (i == CX25821_CTLS) { + *qctrl = no_ctl; + return 0; + } + *qctrl = cx25821_ctls[i].v; + return 0; +} +*/ + +/* resource management */ +int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh, + unsigned int bit) +{ + dprintk(1, "%s()\n", __func__); + if (fh->resources & bit) + /* have it already allocated */ + return 1; + + /* is it free? */ + mutex_lock(&dev->lock); + if (dev->channels[fh->channel_id].resources & bit) { + /* no, someone else uses it */ + mutex_unlock(&dev->lock); + return 0; + } + /* it's free, grab it */ + fh->resources |= bit; + dev->channels[fh->channel_id].resources |= bit; + dprintk(1, "res: get %d\n", bit); + mutex_unlock(&dev->lock); + return 1; +} + +int cx25821_res_check(struct cx25821_fh *fh, unsigned int bit) +{ + return fh->resources & bit; +} + +int cx25821_res_locked(struct cx25821_fh *fh, unsigned int bit) +{ + return fh->dev->channels[fh->channel_id].resources & bit; +} + +void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh, + unsigned int bits) +{ + BUG_ON((fh->resources & bits) != bits); + dprintk(1, "%s()\n", __func__); + + mutex_lock(&dev->lock); + fh->resources &= ~bits; + dev->channels[fh->channel_id].resources &= ~bits; + dprintk(1, "res: put %d\n", bits); + mutex_unlock(&dev->lock); +} + +int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input) +{ + struct v4l2_routing route; + memset(&route, 0, sizeof(route)); + + dprintk(1, "%s(): video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n", + __func__, input, INPUT(input)->vmux, INPUT(input)->gpio0, + INPUT(input)->gpio1, INPUT(input)->gpio2, INPUT(input)->gpio3); + dev->input = input; + + route.input = INPUT(input)->vmux; + + /* Tell the internal A/V decoder */ + cx25821_call_all(dev, video, s_routing, INPUT(input)->vmux, 0, 0); + + return 0; +} + +int cx25821_start_video_dma(struct cx25821_dev *dev, + struct cx25821_dmaqueue *q, + struct cx25821_buffer *buf, + struct sram_channel *channel) +{ + int tmp = 0; + + /* setup fifo + format */ + cx25821_sram_channel_setup(dev, channel, buf->bpl, buf->risc.dma); + + /* reset counter */ + cx_write(channel->gpcnt_ctl, 3); + q->count = 1; + + /* enable irq */ + cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << channel->i)); + cx_set(channel->int_msk, 0x11); + + /* start dma */ + cx_write(channel->dma_ctl, 0x11); /* FIFO and RISC enable */ + + /* make sure upstream setting if any is reversed */ + tmp = cx_read(VID_CH_MODE_SEL); + cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00); + + return 0; +} + +int cx25821_restart_video_queue(struct cx25821_dev *dev, + struct cx25821_dmaqueue *q, + struct sram_channel *channel) +{ + struct cx25821_buffer *buf, *prev; + struct list_head *item; + + if (!list_empty(&q->active)) { + buf = list_entry(q->active.next, struct cx25821_buffer, + vb.queue); + + cx25821_start_video_dma(dev, q, buf, channel); + + list_for_each(item, &q->active) { + buf = list_entry(item, struct cx25821_buffer, vb.queue); + buf->count = q->count++; + } + + mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); + return 0; + } + + prev = NULL; + for (;;) { + if (list_empty(&q->queued)) + return 0; + + buf = list_entry(q->queued.next, struct cx25821_buffer, + vb.queue); + + if (NULL == prev) { + list_move_tail(&buf->vb.queue, &q->active); + cx25821_start_video_dma(dev, q, buf, channel); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); + } else if (prev->vb.width == buf->vb.width && + prev->vb.height == buf->vb.height && + prev->fmt == buf->fmt) { + list_move_tail(&buf->vb.queue, &q->active); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */ + } else { + return 0; + } + prev = buf; + } +} + +void cx25821_vid_timeout(unsigned long data) +{ + struct cx25821_data *timeout_data = (struct cx25821_data *)data; + struct cx25821_dev *dev = timeout_data->dev; + struct sram_channel *channel = timeout_data->channel; + struct cx25821_dmaqueue *q = &dev->channels[channel->i].vidq; + struct cx25821_buffer *buf; + unsigned long flags; + + /* cx25821_sram_channel_dump(dev, channel); */ + cx_clear(channel->dma_ctl, 0x11); + + spin_lock_irqsave(&dev->slock, flags); + while (!list_empty(&q->active)) { + buf = list_entry(q->active.next, struct cx25821_buffer, + vb.queue); + list_del(&buf->vb.queue); + + buf->vb.state = VIDEOBUF_ERROR; + wake_up(&buf->vb.done); + } + + cx25821_restart_video_queue(dev, q, channel); + spin_unlock_irqrestore(&dev->slock, flags); +} + +int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status) +{ + u32 count = 0; + int handled = 0; + u32 mask; + struct sram_channel *channel = dev->channels[chan_num].sram_channels; + + mask = cx_read(channel->int_msk); + if (0 == (status & mask)) + return handled; + + cx_write(channel->int_stat, status); + + /* risc op code error */ + if (status & (1 << 16)) { + pr_warn("%s, %s: video risc op code error\n", + dev->name, channel->name); + cx_clear(channel->dma_ctl, 0x11); + cx25821_sram_channel_dump(dev, channel); + } + + /* risc1 y */ + if (status & FLD_VID_DST_RISC1) { + spin_lock(&dev->slock); + count = cx_read(channel->gpcnt); + cx25821_video_wakeup(dev, &dev->channels[channel->i].vidq, + count); + spin_unlock(&dev->slock); + handled++; + } + + /* risc2 y */ + if (status & 0x10) { + dprintk(2, "stopper video\n"); + spin_lock(&dev->slock); + cx25821_restart_video_queue(dev, + &dev->channels[channel->i].vidq, channel); + spin_unlock(&dev->slock); + handled++; + } + return handled; +} + +void cx25821_videoioctl_unregister(struct cx25821_dev *dev) +{ + if (dev->ioctl_dev) { + if (video_is_registered(dev->ioctl_dev)) + video_unregister_device(dev->ioctl_dev); + else + video_device_release(dev->ioctl_dev); + + dev->ioctl_dev = NULL; + } +} + +void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num) +{ + cx_clear(PCI_INT_MSK, 1); + + if (dev->channels[chan_num].video_dev) { + if (video_is_registered(dev->channels[chan_num].video_dev)) + video_unregister_device( + dev->channels[chan_num].video_dev); + else + video_device_release( + dev->channels[chan_num].video_dev); + + dev->channels[chan_num].video_dev = NULL; + + btcx_riscmem_free(dev->pci, + &dev->channels[chan_num].vidq.stopper); + + pr_warn("device %d released!\n", chan_num); + } + +} + +int cx25821_video_register(struct cx25821_dev *dev) +{ + int err; + int i; + + struct video_device cx25821_video_device = { + .name = "cx25821-video", + .fops = &video_fops, + .minor = -1, + .ioctl_ops = &video_ioctl_ops, + .tvnorms = CX25821_NORMS, + .current_norm = V4L2_STD_NTSC_M, + }; + + spin_lock_init(&dev->slock); + + for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; ++i) { + cx25821_init_controls(dev, i); + + cx25821_risc_stopper(dev->pci, &dev->channels[i].vidq.stopper, + dev->channels[i].sram_channels->dma_ctl, 0x11, 0); + + dev->channels[i].sram_channels = &cx25821_sram_channels[i]; + dev->channels[i].video_dev = NULL; + dev->channels[i].resources = 0; + + cx_write(dev->channels[i].sram_channels->int_stat, 0xffffffff); + + INIT_LIST_HEAD(&dev->channels[i].vidq.active); + INIT_LIST_HEAD(&dev->channels[i].vidq.queued); + + dev->channels[i].timeout_data.dev = dev; + dev->channels[i].timeout_data.channel = + &cx25821_sram_channels[i]; + dev->channels[i].vidq.timeout.function = cx25821_vid_timeout; + dev->channels[i].vidq.timeout.data = + (unsigned long)&dev->channels[i].timeout_data; + init_timer(&dev->channels[i].vidq.timeout); + + /* register v4l devices */ + dev->channels[i].video_dev = cx25821_vdev_init(dev, dev->pci, + &cx25821_video_device, "video"); + + err = video_register_device(dev->channels[i].video_dev, + VFL_TYPE_GRABBER, video_nr[dev->nr]); + + if (err < 0) + goto fail_unreg; + + } + + /* set PCI interrupt */ + cx_set(PCI_INT_MSK, 0xff); + + /* initial device configuration */ + mutex_lock(&dev->lock); +#ifdef TUNER_FLAG + dev->tvnorm = cx25821_video_device.current_norm; + cx25821_set_tvnorm(dev, dev->tvnorm); +#endif + mutex_unlock(&dev->lock); + + return 0; + +fail_unreg: + cx25821_video_unregister(dev, i); + return err; +} + +int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count, + unsigned int *size) +{ + struct cx25821_fh *fh = q->priv_data; + + *size = fh->fmt->depth * fh->width * fh->height >> 3; + + if (0 == *count) + *count = 32; + + if (*size * *count > vid_limit * 1024 * 1024) + *count = (vid_limit * 1024 * 1024) / *size; + + return 0; +} + +int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct cx25821_fh *fh = q->priv_data; + struct cx25821_dev *dev = fh->dev; + struct cx25821_buffer *buf = + container_of(vb, struct cx25821_buffer, vb); + int rc, init_buffer = 0; + u32 line0_offset; + struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); + int bpl_local = LINE_SIZE_D1; + int channel_opened = fh->channel_id; + + BUG_ON(NULL == fh->fmt); + if (fh->width < 48 || fh->width > 720 || + fh->height < 32 || fh->height > 576) + return -EINVAL; + + buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; + + if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + return -EINVAL; + + if (buf->fmt != fh->fmt || + buf->vb.width != fh->width || + buf->vb.height != fh->height || buf->vb.field != field) { + buf->fmt = fh->fmt; + buf->vb.width = fh->width; + buf->vb.height = fh->height; + buf->vb.field = field; + init_buffer = 1; + } + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + init_buffer = 1; + rc = videobuf_iolock(q, &buf->vb, NULL); + if (0 != rc) { + printk(KERN_DEBUG pr_fmt("videobuf_iolock failed!\n")); + goto fail; + } + } + + dprintk(1, "init_buffer=%d\n", init_buffer); + + if (init_buffer) { + + channel_opened = dev->channel_opened; + if (channel_opened < 0 || channel_opened > 7) + channel_opened = 7; + + if (dev->channels[channel_opened].pixel_formats == + PIXEL_FRMT_411) + buf->bpl = (buf->fmt->depth * buf->vb.width) >> 3; + else + buf->bpl = (buf->fmt->depth >> 3) * (buf->vb.width); + + if (dev->channels[channel_opened].pixel_formats == + PIXEL_FRMT_411) { + bpl_local = buf->bpl; + } else { + bpl_local = buf->bpl; /* Default */ + + if (channel_opened >= 0 && channel_opened <= 7) { + if (dev->channels[channel_opened] + .use_cif_resolution) { + if (dev->tvnorm & V4L2_STD_PAL_BG || + dev->tvnorm & V4L2_STD_PAL_DK) + bpl_local = 352 << 1; + else + bpl_local = dev->channels[ + channel_opened]. + cif_width << 1; + } + } + } + + switch (buf->vb.field) { + case V4L2_FIELD_TOP: + cx25821_risc_buffer(dev->pci, &buf->risc, + dma->sglist, 0, UNSET, + buf->bpl, 0, buf->vb.height); + break; + case V4L2_FIELD_BOTTOM: + cx25821_risc_buffer(dev->pci, &buf->risc, + dma->sglist, UNSET, 0, + buf->bpl, 0, buf->vb.height); + break; + case V4L2_FIELD_INTERLACED: + /* All other formats are top field first */ + line0_offset = 0; + dprintk(1, "top field first\n"); + + cx25821_risc_buffer(dev->pci, &buf->risc, + dma->sglist, line0_offset, + bpl_local, bpl_local, bpl_local, + buf->vb.height >> 1); + break; + case V4L2_FIELD_SEQ_TB: + cx25821_risc_buffer(dev->pci, &buf->risc, + dma->sglist, + 0, buf->bpl * (buf->vb.height >> 1), + buf->bpl, 0, buf->vb.height >> 1); + break; + case V4L2_FIELD_SEQ_BT: + cx25821_risc_buffer(dev->pci, &buf->risc, + dma->sglist, + buf->bpl * (buf->vb.height >> 1), 0, + buf->bpl, 0, buf->vb.height >> 1); + break; + default: + BUG(); + } + } + + dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", + buf, buf->vb.i, fh->width, fh->height, fh->fmt->depth, + fh->fmt->name, (unsigned long)buf->risc.dma); + + buf->vb.state = VIDEOBUF_PREPARED; + + return 0; + +fail: + cx25821_free_buffer(q, buf); + return rc; +} + +void cx25821_buffer_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + struct cx25821_buffer *buf = + container_of(vb, struct cx25821_buffer, vb); + + cx25821_free_buffer(q, buf); +} + +struct videobuf_queue *get_queue(struct cx25821_fh *fh) +{ + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return &fh->vidq; + default: + BUG(); + return NULL; + } +} + +int cx25821_get_resource(struct cx25821_fh *fh, int resource) +{ + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return resource; + default: + BUG(); + return 0; + } +} + +int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct cx25821_fh *fh = file->private_data; + + return videobuf_mmap_mapper(get_queue(fh), vma); +} + + +static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +{ + struct cx25821_buffer *buf = + container_of(vb, struct cx25821_buffer, vb); + struct cx25821_buffer *prev; + struct cx25821_fh *fh = vq->priv_data; + struct cx25821_dev *dev = fh->dev; + struct cx25821_dmaqueue *q = &dev->channels[fh->channel_id].vidq; + + /* add jump to stopper */ + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); + buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ + + dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]); + + if (!list_empty(&q->queued)) { + list_add_tail(&buf->vb.queue, &q->queued); + buf->vb.state = VIDEOBUF_QUEUED; + dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf, + buf->vb.i); + + } else if (list_empty(&q->active)) { + list_add_tail(&buf->vb.queue, &q->active); + cx25821_start_video_dma(dev, q, buf, + dev->channels[fh->channel_id].sram_channels); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); + dprintk(2, "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n", + buf, buf->vb.i, buf->count, q->count); + } else { + prev = list_entry(q->active.prev, struct cx25821_buffer, + vb.queue); + if (prev->vb.width == buf->vb.width + && prev->vb.height == buf->vb.height + && prev->fmt == buf->fmt) { + list_add_tail(&buf->vb.queue, &q->active); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + + /* 64 bit bits 63-32 */ + prev->risc.jmp[2] = cpu_to_le32(0); + dprintk(2, "[%p/%d] buffer_queue - append to active, buf->count=%d\n", + buf, buf->vb.i, buf->count); + + } else { + list_add_tail(&buf->vb.queue, &q->queued); + buf->vb.state = VIDEOBUF_QUEUED; + dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf, + buf->vb.i); + } + } + + if (list_empty(&q->active)) + dprintk(2, "active queue empty!\n"); +} + +static struct videobuf_queue_ops cx25821_video_qops = { + .buf_setup = cx25821_buffer_setup, + .buf_prepare = cx25821_buffer_prepare, + .buf_queue = buffer_queue, + .buf_release = cx25821_buffer_release, +}; + +static int video_open(struct file *file) +{ + struct video_device *vdev = video_devdata(file); + struct cx25821_dev *h, *dev = video_drvdata(file); + struct cx25821_fh *fh; + struct list_head *list; + int minor = video_devdata(file)->minor; + enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + u32 pix_format; + int ch_id = 0; + int i; + + dprintk(1, "open dev=%s type=%s\n", video_device_node_name(vdev), + v4l2_type_names[type]); + + /* allocate + initialize per filehandle data */ + fh = kzalloc(sizeof(*fh), GFP_KERNEL); + if (NULL == fh) + return -ENOMEM; + + mutex_lock(&cx25821_devlist_mutex); + + list_for_each(list, &cx25821_devlist) + { + h = list_entry(list, struct cx25821_dev, devlist); + + for (i = 0; i < MAX_VID_CHANNEL_NUM; i++) { + if (h->channels[i].video_dev && + h->channels[i].video_dev->minor == minor) { + dev = h; + ch_id = i; + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + } + } + } + + if (NULL == dev) { + mutex_unlock(&cx25821_devlist_mutex); + kfree(fh); + return -ENODEV; + } + + file->private_data = fh; + fh->dev = dev; + fh->type = type; + fh->width = 720; + fh->channel_id = ch_id; + + if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK) + fh->height = 576; + else + fh->height = 480; + + dev->channel_opened = fh->channel_id; + if (dev->channels[ch_id].pixel_formats == PIXEL_FRMT_411) + pix_format = V4L2_PIX_FMT_Y41P; + else + pix_format = V4L2_PIX_FMT_YUYV; + fh->fmt = cx25821_format_by_fourcc(pix_format); + + v4l2_prio_open(&dev->channels[ch_id].prio, &fh->prio); + + videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops, &dev->pci->dev, + &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_INTERLACED, sizeof(struct cx25821_buffer), + fh, NULL); + + dprintk(1, "post videobuf_queue_init()\n"); + mutex_unlock(&cx25821_devlist_mutex); + + return 0; +} + +static ssize_t video_read(struct file *file, char __user * data, size_t count, + loff_t *ppos) +{ + struct cx25821_fh *fh = file->private_data; + + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (cx25821_res_locked(fh, RESOURCE_VIDEO0)) + return -EBUSY; + + return videobuf_read_one(&fh->vidq, data, count, ppos, + file->f_flags & O_NONBLOCK); + + default: + BUG(); + return 0; + } +} + +static unsigned int video_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct cx25821_fh *fh = file->private_data; + struct cx25821_buffer *buf; + + if (cx25821_res_check(fh, RESOURCE_VIDEO0)) { + /* streaming capture */ + if (list_empty(&fh->vidq.stream)) + return POLLERR; + buf = list_entry(fh->vidq.stream.next, + struct cx25821_buffer, vb.stream); + } else { + /* read() capture */ + buf = (struct cx25821_buffer *)fh->vidq.read_buf; + if (NULL == buf) + return POLLERR; + } + + poll_wait(file, &buf->vb.done, wait); + if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) { + if (buf->vb.state == VIDEOBUF_DONE) { + struct cx25821_dev *dev = fh->dev; + + if (dev && dev->channels[fh->channel_id] + .use_cif_resolution) { + u8 cam_id = *((char *)buf->vb.baddr + 3); + memcpy((char *)buf->vb.baddr, + (char *)buf->vb.baddr + (fh->width * 2), + (fh->width * 2)); + *((char *)buf->vb.baddr + 3) = cam_id; + } + } + + return POLLIN | POLLRDNORM; + } + + return 0; +} + +static int video_release(struct file *file) +{ + struct cx25821_fh *fh = file->private_data; + struct cx25821_dev *dev = fh->dev; + + /* stop the risc engine and fifo */ + cx_write(channel0->dma_ctl, 0); /* FIFO and RISC disable */ + + /* stop video capture */ + if (cx25821_res_check(fh, RESOURCE_VIDEO0)) { + videobuf_queue_cancel(&fh->vidq); + cx25821_res_free(dev, fh, RESOURCE_VIDEO0); + } + + if (fh->vidq.read_buf) { + cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf); + kfree(fh->vidq.read_buf); + } + + videobuf_mmap_free(&fh->vidq); + + v4l2_prio_close(&dev->channels[fh->channel_id].prio, fh->prio); + file->private_data = NULL; + kfree(fh); + + return 0; +} + +static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct cx25821_fh *fh = priv; + struct cx25821_dev *dev = fh->dev; + + if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) + return -EINVAL; + + if (unlikely(i != fh->type)) + return -EINVAL; + + if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, + RESOURCE_VIDEO0)))) + return -EBUSY; + + return videobuf_streamon(get_queue(fh)); +} + +static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct cx25821_fh *fh = priv; + struct cx25821_dev *dev = fh->dev; + int err, res; + + if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (i != fh->type) + return -EINVAL; + + res = cx25821_get_resource(fh, RESOURCE_VIDEO0); + err = videobuf_streamoff(get_queue(fh)); + if (err < 0) + return err; + cx25821_res_free(dev, fh, res); + return 0; +} + +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx25821_fh *fh = priv; + struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; + struct v4l2_mbus_framefmt mbus_fmt; + int err; + int pix_format = PIXEL_FRMT_422; + + if (fh) { + err = v4l2_prio_check(&dev->channels[fh->channel_id].prio, + fh->prio); + if (0 != err) + return err; + } + + dprintk(2, "%s()\n", __func__); + err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f); + + if (0 != err) + return err; + + fh->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat); + fh->vidq.field = f->fmt.pix.field; + + /* check if width and height is valid based on set standard */ + if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) + fh->width = f->fmt.pix.width; + + if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) + fh->height = f->fmt.pix.height; + + if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P) + pix_format = PIXEL_FRMT_411; + else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) + pix_format = PIXEL_FRMT_422; + else + return -EINVAL; + + cx25821_set_pixel_format(dev, SRAM_CH00, pix_format); + + /* check if cif resolution */ + if (fh->width == 320 || fh->width == 352) + dev->channels[fh->channel_id].use_cif_resolution = 1; + else + dev->channels[fh->channel_id].use_cif_resolution = 0; + + dev->channels[fh->channel_id].cif_width = fh->width; + medusa_set_resolution(dev, fh->width, SRAM_CH00); + + dprintk(2, "%s(): width=%d height=%d field=%d\n", __func__, fh->width, + fh->height, fh->vidq.field); + v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); + cx25821_call_all(dev, video, s_mbus_fmt, &mbus_fmt); + + return 0; +} + +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) +{ + int ret_val = 0; + struct cx25821_fh *fh = priv; + struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; + + ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK); + + p->sequence = dev->channels[fh->channel_id].vidq.count; + + return ret_val; +} + +static int vidioc_log_status(struct file *file, void *priv) +{ + struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; + struct cx25821_fh *fh = priv; + char name[32 + 2]; + + struct sram_channel *sram_ch = dev->channels[fh->channel_id] + .sram_channels; + u32 tmp = 0; + + snprintf(name, sizeof(name), "%s/2", dev->name); + pr_info("%s/2: ============ START LOG STATUS ============\n", + dev->name); + cx25821_call_all(dev, core, log_status); + tmp = cx_read(sram_ch->dma_ctl); + pr_info("Video input 0 is %s\n", + (tmp & 0x11) ? "streaming" : "stopped"); + pr_info("%s/2: ============= END LOG STATUS =============\n", + dev->name); + return 0; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctl) +{ + struct cx25821_fh *fh = priv; + struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; + int err; + + if (fh) { + err = v4l2_prio_check(&dev->channels[fh->channel_id].prio, + fh->prio); + if (0 != err) + return err; + } + + return cx25821_set_control(dev, ctl, fh->channel_id); +} + +/* VIDEO IOCTLS */ +int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx25821_fh *fh = priv; + + f->fmt.pix.width = fh->width; + f->fmt.pix.height = fh->height; + f->fmt.pix.field = fh->vidq.field; + f->fmt.pix.pixelformat = fh->fmt->fourcc; + f->fmt.pix.bytesperline = (f->fmt.pix.width * fh->fmt->depth) >> 3; + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + + return 0; +} + +int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx25821_fmt *fmt; + enum v4l2_field field; + unsigned int maxw, maxh; + + fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat); + if (NULL == fmt) + return -EINVAL; + + field = f->fmt.pix.field; + maxw = 720; + maxh = 576; + + if (V4L2_FIELD_ANY == field) { + if (f->fmt.pix.height > maxh / 2) + field = V4L2_FIELD_INTERLACED; + else + field = V4L2_FIELD_TOP; + } + + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + maxh = maxh / 2; + break; + case V4L2_FIELD_INTERLACED: + break; + default: + return -EINVAL; + } + + f->fmt.pix.field = field; + if (f->fmt.pix.height < 32) + f->fmt.pix.height = 32; + if (f->fmt.pix.height > maxh) + f->fmt.pix.height = maxh; + if (f->fmt.pix.width < 48) + f->fmt.pix.width = 48; + if (f->fmt.pix.width > maxw) + f->fmt.pix.width = maxw; + f->fmt.pix.width &= ~0x03; + f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + + return 0; +} + +int cx25821_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; + + strcpy(cap->driver, "cx25821"); + strlcpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card)); + sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); + cap->version = CX25821_VERSION_CODE; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + if (UNSET != dev->tuner_type) + cap->capabilities |= V4L2_CAP_TUNER; + return 0; +} + +int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (unlikely(f->index >= ARRAY_SIZE(formats))) + return -EINVAL; + + strlcpy(f->description, formats[f->index].name, sizeof(f->description)); + f->pixelformat = formats[f->index].fourcc; + + return 0; +} + +int cx25821_vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct cx25821_fh *fh = priv; + return videobuf_reqbufs(get_queue(fh), p); +} + +int cx25821_vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct cx25821_fh *fh = priv; + return videobuf_querybuf(get_queue(fh), p); +} + +int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) +{ + struct cx25821_fh *fh = priv; + return videobuf_qbuf(get_queue(fh), p); +} + +int cx25821_vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p) +{ + struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev; + struct cx25821_fh *fh = f; + + *p = v4l2_prio_max(&dev->channels[fh->channel_id].prio); + + return 0; +} + +int cx25821_vidioc_s_priority(struct file *file, void *f, + enum v4l2_priority prio) +{ + struct cx25821_fh *fh = f; + struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev; + + return v4l2_prio_change(&dev->channels[fh->channel_id].prio, &fh->prio, + prio); +} + +#ifdef TUNER_FLAG +int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id * tvnorms) +{ + struct cx25821_fh *fh = priv; + struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; + int err; + + dprintk(1, "%s()\n", __func__); + + if (fh) { + err = v4l2_prio_check(&dev->channels[fh->channel_id].prio, + fh->prio); + if (0 != err) + return err; + } + + if (dev->tvnorm == *tvnorms) + return 0; + + mutex_lock(&dev->lock); + cx25821_set_tvnorm(dev, *tvnorms); + mutex_unlock(&dev->lock); + + medusa_set_videostandard(dev); + + return 0; +} +#endif + +int cx25821_enum_input(struct cx25821_dev *dev, struct v4l2_input *i) +{ + static const char * const iname[] = { + [CX25821_VMUX_COMPOSITE] = "Composite", + [CX25821_VMUX_SVIDEO] = "S-Video", + [CX25821_VMUX_DEBUG] = "for debug only", + }; + unsigned int n; + dprintk(1, "%s()\n", __func__); + + n = i->index; + if (n >= 2) + return -EINVAL; + + if (0 == INPUT(n)->type) + return -EINVAL; + + i->type = V4L2_INPUT_TYPE_CAMERA; + strcpy(i->name, iname[INPUT(n)->type]); + + i->std = CX25821_NORMS; + return 0; +} + +int cx25821_vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; + dprintk(1, "%s()\n", __func__); + return cx25821_enum_input(dev, i); +} + +int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; + + *i = dev->input; + dprintk(1, "%s(): returns %d\n", __func__, *i); + return 0; +} + +int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + struct cx25821_fh *fh = priv; + struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; + int err; + + dprintk(1, "%s(%d)\n", __func__, i); + + if (fh) { + err = v4l2_prio_check(&dev->channels[fh->channel_id].prio, + fh->prio); + if (0 != err) + return err; + } + + if (i >= CX25821_NR_INPUT) { + dprintk(1, "%s(): -EINVAL\n", __func__); + return -EINVAL; + } + + mutex_lock(&dev->lock); + cx25821_video_mux(dev, i); + mutex_unlock(&dev->lock); + return 0; +} + +#ifdef TUNER_FLAG +int cx25821_vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct cx25821_fh *fh = priv; + struct cx25821_dev *dev = fh->dev; + + f->frequency = dev->freq; + + cx25821_call_all(dev, tuner, g_frequency, f); + + return 0; +} + +int cx25821_set_freq(struct cx25821_dev *dev, struct v4l2_frequency *f) +{ + mutex_lock(&dev->lock); + dev->freq = f->frequency; + + cx25821_call_all(dev, tuner, s_frequency, f); + + /* When changing channels it is required to reset TVAUDIO */ + msleep(10); + + mutex_unlock(&dev->lock); + + return 0; +} + +int cx25821_vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct cx25821_fh *fh = priv; + struct cx25821_dev *dev; + int err; + + if (fh) { + dev = fh->dev; + err = v4l2_prio_check(&dev->channels[fh->channel_id].prio, + fh->prio); + if (0 != err) + return err; + } else { + pr_err("Invalid fh pointer!\n"); + return -EINVAL; + } + + return cx25821_set_freq(dev, f); +} +#endif + +#ifdef CONFIG_VIDEO_ADV_DEBUG +int cx25821_vidioc_g_register(struct file *file, void *fh, + struct v4l2_dbg_register *reg) +{ + struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev; + + if (!v4l2_chip_match_host(®->match)) + return -EINVAL; + + cx25821_call_all(dev, core, g_register, reg); + + return 0; +} + +int cx25821_vidioc_s_register(struct file *file, void *fh, + struct v4l2_dbg_register *reg) +{ + struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev; + + if (!v4l2_chip_match_host(®->match)) + return -EINVAL; + + cx25821_call_all(dev, core, s_register, reg); + + return 0; +} + +#endif + +#ifdef TUNER_FLAG +int cx25821_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) +{ + struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; + + if (unlikely(UNSET == dev->tuner_type)) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + + strcpy(t->name, "Television"); + t->type = V4L2_TUNER_ANALOG_TV; + t->capability = V4L2_TUNER_CAP_NORM; + t->rangehigh = 0xffffffffUL; + + t->signal = 0xffff; /* LOCKED */ + return 0; +} + +int cx25821_vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t) +{ + struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; + struct cx25821_fh *fh = priv; + int err; + + if (fh) { + err = v4l2_prio_check(&dev->channels[fh->channel_id].prio, + fh->prio); + if (0 != err) + return err; + } + + dprintk(1, "%s()\n", __func__); + if (UNSET == dev->tuner_type) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + + return 0; +} + +#endif +/*****************************************************************************/ +static const struct v4l2_queryctrl no_ctl = { + .name = "42", + .flags = V4L2_CTRL_FLAG_DISABLED, +}; + +static struct v4l2_queryctrl cx25821_ctls[] = { + /* --- video --- */ + { + .id = V4L2_CID_BRIGHTNESS, + .name = "Brightness", + .minimum = 0, + .maximum = 10000, + .step = 1, + .default_value = 6200, + .type = V4L2_CTRL_TYPE_INTEGER, + }, { + .id = V4L2_CID_CONTRAST, + .name = "Contrast", + .minimum = 0, + .maximum = 10000, + .step = 1, + .default_value = 5000, + .type = V4L2_CTRL_TYPE_INTEGER, + }, { + .id = V4L2_CID_SATURATION, + .name = "Saturation", + .minimum = 0, + .maximum = 10000, + .step = 1, + .default_value = 5000, + .type = V4L2_CTRL_TYPE_INTEGER, + }, { + .id = V4L2_CID_HUE, + .name = "Hue", + .minimum = 0, + .maximum = 10000, + .step = 1, + .default_value = 5000, + .type = V4L2_CTRL_TYPE_INTEGER, + } +}; +static const int CX25821_CTLS = ARRAY_SIZE(cx25821_ctls); + +static int cx25821_ctrl_query(struct v4l2_queryctrl *qctrl) +{ + int i; + + if (qctrl->id < V4L2_CID_BASE || qctrl->id >= V4L2_CID_LASTP1) + return -EINVAL; + for (i = 0; i < CX25821_CTLS; i++) + if (cx25821_ctls[i].id == qctrl->id) + break; + if (i == CX25821_CTLS) { + *qctrl = no_ctl; + return 0; + } + *qctrl = cx25821_ctls[i]; + return 0; +} + +int cx25821_vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qctrl) +{ + return cx25821_ctrl_query(qctrl); +} + +/* ------------------------------------------------------------------ */ +/* VIDEO CTRL IOCTLS */ + +static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id) +{ + unsigned int i; + + for (i = 0; i < CX25821_CTLS; i++) + if (cx25821_ctls[i].id == id) + return cx25821_ctls + i; + return NULL; +} + +int cx25821_vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctl) +{ + struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; + struct cx25821_fh *fh = priv; + + const struct v4l2_queryctrl *ctrl; + + ctrl = ctrl_by_id(ctl->id); + + if (NULL == ctrl) + return -EINVAL; + switch (ctl->id) { + case V4L2_CID_BRIGHTNESS: + ctl->value = dev->channels[fh->channel_id].ctl_bright; + break; + case V4L2_CID_HUE: + ctl->value = dev->channels[fh->channel_id].ctl_hue; + break; + case V4L2_CID_CONTRAST: + ctl->value = dev->channels[fh->channel_id].ctl_contrast; + break; + case V4L2_CID_SATURATION: + ctl->value = dev->channels[fh->channel_id].ctl_saturation; + break; + } + return 0; +} + +int cx25821_set_control(struct cx25821_dev *dev, + struct v4l2_control *ctl, int chan_num) +{ + int err; + const struct v4l2_queryctrl *ctrl; + + err = -EINVAL; + + ctrl = ctrl_by_id(ctl->id); + + if (NULL == ctrl) + return err; + + switch (ctrl->type) { + case V4L2_CTRL_TYPE_BOOLEAN: + case V4L2_CTRL_TYPE_MENU: + case V4L2_CTRL_TYPE_INTEGER: + if (ctl->value < ctrl->minimum) + ctl->value = ctrl->minimum; + if (ctl->value > ctrl->maximum) + ctl->value = ctrl->maximum; + break; + default: + /* nothing */ ; + } + + switch (ctl->id) { + case V4L2_CID_BRIGHTNESS: + dev->channels[chan_num].ctl_bright = ctl->value; + medusa_set_brightness(dev, ctl->value, chan_num); + break; + case V4L2_CID_HUE: + dev->channels[chan_num].ctl_hue = ctl->value; + medusa_set_hue(dev, ctl->value, chan_num); + break; + case V4L2_CID_CONTRAST: + dev->channels[chan_num].ctl_contrast = ctl->value; + medusa_set_contrast(dev, ctl->value, chan_num); + break; + case V4L2_CID_SATURATION: + dev->channels[chan_num].ctl_saturation = ctl->value; + medusa_set_saturation(dev, ctl->value, chan_num); + break; + } + + err = 0; + + return err; +} + +static void cx25821_init_controls(struct cx25821_dev *dev, int chan_num) +{ + struct v4l2_control ctrl; + int i; + for (i = 0; i < CX25821_CTLS; i++) { + ctrl.id = cx25821_ctls[i].id; + ctrl.value = cx25821_ctls[i].default_value; + + cx25821_set_control(dev, &ctrl, chan_num); + } +} + +int cx25821_vidioc_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cropcap) +{ + struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; + + if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + cropcap->bounds.top = 0; + cropcap->bounds.left = 0; + cropcap->bounds.width = 720; + cropcap->bounds.height = dev->tvnorm == V4L2_STD_PAL_BG ? 576 : 480; + cropcap->pixelaspect.numerator = + dev->tvnorm == V4L2_STD_PAL_BG ? 59 : 10; + cropcap->pixelaspect.denominator = + dev->tvnorm == V4L2_STD_PAL_BG ? 54 : 11; + cropcap->defrect = cropcap->bounds; + return 0; +} + +int cx25821_vidioc_s_crop(struct file *file, void *priv, struct v4l2_crop *crop) +{ + struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; + struct cx25821_fh *fh = priv; + int err; + + if (fh) { + err = v4l2_prio_check(&dev->channels[fh->channel_id].prio, + fh->prio); + if (0 != err) + return err; + } + /* cx25821_vidioc_s_crop not supported */ + return -EINVAL; +} + +int cx25821_vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop) +{ + /* cx25821_vidioc_g_crop not supported */ + return -EINVAL; +} + +int cx25821_vidioc_querystd(struct file *file, void *priv, v4l2_std_id * norm) +{ + /* medusa does not support video standard sensing of current input */ + *norm = CX25821_NORMS; + + return 0; +} + +int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm) +{ + if (tvnorm == V4L2_STD_PAL_BG) { + if (width == 352 || width == 720) + return 1; + else + return 0; + } + + if (tvnorm == V4L2_STD_NTSC_M) { + if (width == 320 || width == 352 || width == 720) + return 1; + else + return 0; + } + return 0; +} + +int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm) +{ + if (tvnorm == V4L2_STD_PAL_BG) { + if (height == 576 || height == 288) + return 1; + else + return 0; + } + + if (tvnorm == V4L2_STD_NTSC_M) { + if (height == 480 || height == 240) + return 1; + else + return 0; + } + + return 0; +} + +static long video_ioctl_upstream9(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct cx25821_fh *fh = file->private_data; + struct cx25821_dev *dev = fh->dev; + int command = 0; + struct upstream_user_struct *data_from_user; + + data_from_user = (struct upstream_user_struct *)arg; + + if (!data_from_user) { + pr_err("%s(): Upstream data is INVALID. Returning\n", __func__); + return 0; + } + + command = data_from_user->command; + + if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO) + return 0; + + dev->input_filename = data_from_user->input_filename; + dev->input_audiofilename = data_from_user->input_filename; + dev->vid_stdname = data_from_user->vid_stdname; + dev->pixel_format = data_from_user->pixel_format; + dev->channel_select = data_from_user->channel_select; + dev->command = data_from_user->command; + + switch (command) { + case UPSTREAM_START_VIDEO: + cx25821_start_upstream_video_ch1(dev, data_from_user); + break; + + case UPSTREAM_STOP_VIDEO: + cx25821_stop_upstream_video_ch1(dev); + break; + } + + return 0; +} + +static long video_ioctl_upstream10(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct cx25821_fh *fh = file->private_data; + struct cx25821_dev *dev = fh->dev; + int command = 0; + struct upstream_user_struct *data_from_user; + + data_from_user = (struct upstream_user_struct *)arg; + + if (!data_from_user) { + pr_err("%s(): Upstream data is INVALID. Returning\n", __func__); + return 0; + } + + command = data_from_user->command; + + if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO) + return 0; + + dev->input_filename_ch2 = data_from_user->input_filename; + dev->input_audiofilename = data_from_user->input_filename; + dev->vid_stdname_ch2 = data_from_user->vid_stdname; + dev->pixel_format_ch2 = data_from_user->pixel_format; + dev->channel_select_ch2 = data_from_user->channel_select; + dev->command_ch2 = data_from_user->command; + + switch (command) { + case UPSTREAM_START_VIDEO: + cx25821_start_upstream_video_ch2(dev, data_from_user); + break; + + case UPSTREAM_STOP_VIDEO: + cx25821_stop_upstream_video_ch2(dev); + break; + } + + return 0; +} + +static long video_ioctl_upstream11(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct cx25821_fh *fh = file->private_data; + struct cx25821_dev *dev = fh->dev; + int command = 0; + struct upstream_user_struct *data_from_user; + + data_from_user = (struct upstream_user_struct *)arg; + + if (!data_from_user) { + pr_err("%s(): Upstream data is INVALID. Returning\n", __func__); + return 0; + } + + command = data_from_user->command; + + if (command != UPSTREAM_START_AUDIO && command != UPSTREAM_STOP_AUDIO) + return 0; + + dev->input_filename = data_from_user->input_filename; + dev->input_audiofilename = data_from_user->input_filename; + dev->vid_stdname = data_from_user->vid_stdname; + dev->pixel_format = data_from_user->pixel_format; + dev->channel_select = data_from_user->channel_select; + dev->command = data_from_user->command; + + switch (command) { + case UPSTREAM_START_AUDIO: + cx25821_start_upstream_audio(dev, data_from_user); + break; + + case UPSTREAM_STOP_AUDIO: + cx25821_stop_upstream_audio(dev); + break; + } + + return 0; +} + +static long video_ioctl_set(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct cx25821_fh *fh = file->private_data; + struct cx25821_dev *dev = fh->dev; + struct downstream_user_struct *data_from_user; + int command; + int width = 720; + int selected_channel = 0; + int pix_format = 0; + int i = 0; + int cif_enable = 0; + int cif_width = 0; + + data_from_user = (struct downstream_user_struct *)arg; + + if (!data_from_user) { + pr_err("%s(): User data is INVALID. Returning\n", __func__); + return 0; + } + + command = data_from_user->command; + + if (command != SET_VIDEO_STD && command != SET_PIXEL_FORMAT + && command != ENABLE_CIF_RESOLUTION && command != REG_READ + && command != REG_WRITE && command != MEDUSA_READ + && command != MEDUSA_WRITE) { + return 0; + } + + switch (command) { + case SET_VIDEO_STD: + if (!strcmp(data_from_user->vid_stdname, "PAL")) + dev->tvnorm = V4L2_STD_PAL_BG; + else + dev->tvnorm = V4L2_STD_NTSC_M; + medusa_set_videostandard(dev); + break; + + case SET_PIXEL_FORMAT: + selected_channel = data_from_user->decoder_select; + pix_format = data_from_user->pixel_format; + + if (!(selected_channel <= 7 && selected_channel >= 0)) { + selected_channel -= 4; + selected_channel = selected_channel % 8; + } + + if (selected_channel >= 0) + cx25821_set_pixel_format(dev, selected_channel, + pix_format); + + break; + + case ENABLE_CIF_RESOLUTION: + selected_channel = data_from_user->decoder_select; + cif_enable = data_from_user->cif_resolution_enable; + cif_width = data_from_user->cif_width; + + if (cif_enable) { + if (dev->tvnorm & V4L2_STD_PAL_BG + || dev->tvnorm & V4L2_STD_PAL_DK) { + width = 352; + } else { + width = cif_width; + if (cif_width != 320 && cif_width != 352) + width = 320; + } + } + + if (!(selected_channel <= 7 && selected_channel >= 0)) { + selected_channel -= 4; + selected_channel = selected_channel % 8; + } + + if (selected_channel <= 7 && selected_channel >= 0) { + dev->channels[selected_channel].use_cif_resolution = + cif_enable; + dev->channels[selected_channel].cif_width = width; + } else { + for (i = 0; i < VID_CHANNEL_NUM; i++) { + dev->channels[i].use_cif_resolution = + cif_enable; + dev->channels[i].cif_width = width; + } + } + + medusa_set_resolution(dev, width, selected_channel); + break; + case REG_READ: + data_from_user->reg_data = cx_read(data_from_user->reg_address); + break; + case REG_WRITE: + cx_write(data_from_user->reg_address, data_from_user->reg_data); + break; + case MEDUSA_READ: + cx25821_i2c_read(&dev->i2c_bus[0], + (u16) data_from_user->reg_address, + &data_from_user->reg_data); + break; + case MEDUSA_WRITE: + cx25821_i2c_write(&dev->i2c_bus[0], + (u16) data_from_user->reg_address, + data_from_user->reg_data); + break; + } + + return 0; +} + +static long cx25821_video_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + + struct cx25821_fh *fh = file->private_data; + + /* check to see if it's the video upstream */ + if (fh->channel_id == SRAM_CH09) { + ret = video_ioctl_upstream9(file, cmd, arg); + return ret; + } else if (fh->channel_id == SRAM_CH10) { + ret = video_ioctl_upstream10(file, cmd, arg); + return ret; + } else if (fh->channel_id == SRAM_CH11) { + ret = video_ioctl_upstream11(file, cmd, arg); + ret = video_ioctl_set(file, cmd, arg); + return ret; + } + + return video_ioctl2(file, cmd, arg); +} + +/* exported stuff */ +static const struct v4l2_file_operations video_fops = { + .owner = THIS_MODULE, + .open = video_open, + .release = video_release, + .read = video_read, + .poll = video_poll, + .mmap = cx25821_video_mmap, + .ioctl = cx25821_video_ioctl, +}; + +static const struct v4l2_ioctl_ops video_ioctl_ops = { + .vidioc_querycap = cx25821_vidioc_querycap, + .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + .vidioc_reqbufs = cx25821_vidioc_reqbufs, + .vidioc_querybuf = cx25821_vidioc_querybuf, + .vidioc_qbuf = cx25821_vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, +#ifdef TUNER_FLAG + .vidioc_s_std = cx25821_vidioc_s_std, + .vidioc_querystd = cx25821_vidioc_querystd, +#endif + .vidioc_cropcap = cx25821_vidioc_cropcap, + .vidioc_s_crop = cx25821_vidioc_s_crop, + .vidioc_g_crop = cx25821_vidioc_g_crop, + .vidioc_enum_input = cx25821_vidioc_enum_input, + .vidioc_g_input = cx25821_vidioc_g_input, + .vidioc_s_input = cx25821_vidioc_s_input, + .vidioc_g_ctrl = cx25821_vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_queryctrl = cx25821_vidioc_queryctrl, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_log_status = vidioc_log_status, + .vidioc_g_priority = cx25821_vidioc_g_priority, + .vidioc_s_priority = cx25821_vidioc_s_priority, +#ifdef TUNER_FLAG + .vidioc_g_tuner = cx25821_vidioc_g_tuner, + .vidioc_s_tuner = cx25821_vidioc_s_tuner, + .vidioc_g_frequency = cx25821_vidioc_g_frequency, + .vidioc_s_frequency = cx25821_vidioc_s_frequency, +#endif +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = cx25821_vidioc_g_register, + .vidioc_s_register = cx25821_vidioc_s_register, +#endif +}; + +struct video_device cx25821_videoioctl_template = { + .name = "cx25821-videoioctl", + .fops = &video_fops, + .ioctl_ops = &video_ioctl_ops, + .tvnorms = CX25821_NORMS, + .current_norm = V4L2_STD_NTSC_M, +}; diff --git a/drivers/media/pci/cx25821/cx25821-video.h b/drivers/media/pci/cx25821/cx25821-video.h new file mode 100644 index 0000000..9652a5e --- /dev/null +++ b/drivers/media/pci/cx25821/cx25821-video.h @@ -0,0 +1,186 @@ +/* + * Driver for the Conexant CX25821 PCIe bridge + * + * Copyright (C) 2009 Conexant Systems Inc. + * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> + * Based on Steven Toth <stoth@linuxtv.org> cx23885 driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef CX25821_VIDEO_H_ +#define CX25821_VIDEO_H_ + +#include <linux/init.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kmod.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/kthread.h> +#include <asm/div64.h> + +#include "cx25821.h" +#include <media/v4l2-common.h> +#include <media/v4l2-ioctl.h> + +#define TUNER_FLAG + +#define VIDEO_DEBUG 0 + +#define dprintk(level, fmt, arg...) \ +do { \ + if (VIDEO_DEBUG >= level) \ + printk(KERN_DEBUG "%s/0: " fmt, dev->name, ##arg); \ +} while (0) + +/* For IOCTL to identify running upstream */ +#define UPSTREAM_START_VIDEO 700 +#define UPSTREAM_STOP_VIDEO 701 +#define UPSTREAM_START_AUDIO 702 +#define UPSTREAM_STOP_AUDIO 703 +#define UPSTREAM_DUMP_REGISTERS 702 +#define SET_VIDEO_STD 800 +#define SET_PIXEL_FORMAT 1000 +#define ENABLE_CIF_RESOLUTION 1001 + +#define REG_READ 900 +#define REG_WRITE 901 +#define MEDUSA_READ 910 +#define MEDUSA_WRITE 911 + +extern struct sram_channel *channel0; +extern struct sram_channel *channel1; +extern struct sram_channel *channel2; +extern struct sram_channel *channel3; +extern struct sram_channel *channel4; +extern struct sram_channel *channel5; +extern struct sram_channel *channel6; +extern struct sram_channel *channel7; +extern struct sram_channel *channel9; +extern struct sram_channel *channel10; +extern struct sram_channel *channel11; +extern struct video_device cx25821_videoioctl_template; +/* extern const u32 *ctrl_classes[]; */ + +extern unsigned int vid_limit; + +#define FORMAT_FLAGS_PACKED 0x01 +extern struct cx25821_fmt formats[]; +extern struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc); +extern struct cx25821_data timeout_data[MAX_VID_CHANNEL_NUM]; + +extern void cx25821_video_wakeup(struct cx25821_dev *dev, + struct cx25821_dmaqueue *q, u32 count); + +#ifdef TUNER_FLAG +extern int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm); +#endif + +extern int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh, + unsigned int bit); +extern int cx25821_res_check(struct cx25821_fh *fh, unsigned int bit); +extern int cx25821_res_locked(struct cx25821_fh *fh, unsigned int bit); +extern void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh, + unsigned int bits); +extern int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input); +extern int cx25821_start_video_dma(struct cx25821_dev *dev, + struct cx25821_dmaqueue *q, + struct cx25821_buffer *buf, + struct sram_channel *channel); + +extern int cx25821_set_scale(struct cx25821_dev *dev, unsigned int width, + unsigned int height, enum v4l2_field field); +extern int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status); +extern void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num); +extern int cx25821_video_register(struct cx25821_dev *dev); +extern int cx25821_get_format_size(void); + +extern int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count, + unsigned int *size); +extern int cx25821_buffer_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, + enum v4l2_field field); +extern void cx25821_buffer_release(struct videobuf_queue *q, + struct videobuf_buffer *vb); +extern struct videobuf_queue *get_queue(struct cx25821_fh *fh); +extern int cx25821_get_resource(struct cx25821_fh *fh, int resource); +extern int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma); +extern int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f); +extern int cx25821_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap); +extern int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f); +extern int cx25821_vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p); +extern int cx25821_vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *p); +extern int cx25821_vidioc_qbuf(struct file *file, void *priv, + struct v4l2_buffer *p); +extern int cx25821_vidioc_s_std(struct file *file, void *priv, + v4l2_std_id *tvnorms); +extern int cx25821_enum_input(struct cx25821_dev *dev, struct v4l2_input *i); +extern int cx25821_vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *i); +extern int cx25821_vidioc_g_input(struct file *file, void *priv, + unsigned int *i); +extern int cx25821_vidioc_s_input(struct file *file, void *priv, + unsigned int i); +extern int cx25821_vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctl); +extern int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f); +extern int cx25821_vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f); +extern int cx25821_set_freq(struct cx25821_dev *dev, struct v4l2_frequency *f); +extern int cx25821_vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f); +extern int cx25821_vidioc_g_register(struct file *file, void *fh, + struct v4l2_dbg_register *reg); +extern int cx25821_vidioc_s_register(struct file *file, void *fh, + struct v4l2_dbg_register *reg); +extern int cx25821_vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t); +extern int cx25821_vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t); + +extern int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm); +extern int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm); + +extern int cx25821_vidioc_g_priority(struct file *file, void *f, + enum v4l2_priority *p); +extern int cx25821_vidioc_s_priority(struct file *file, void *f, + enum v4l2_priority prio); + +extern int cx25821_vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qctrl); +extern int cx25821_set_control(struct cx25821_dev *dev, + struct v4l2_control *ctrl, int chan_num); + +extern int cx25821_vidioc_cropcap(struct file *file, void *fh, + struct v4l2_cropcap *cropcap); +extern int cx25821_vidioc_s_crop(struct file *file, void *priv, + struct v4l2_crop *crop); +extern int cx25821_vidioc_g_crop(struct file *file, void *priv, + struct v4l2_crop *crop); + +extern int cx25821_vidioc_querystd(struct file *file, void *priv, + v4l2_std_id *norm); +#endif diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h new file mode 100644 index 0000000..8a9c0c8 --- /dev/null +++ b/drivers/media/pci/cx25821/cx25821.h @@ -0,0 +1,615 @@ +/* + * Driver for the Conexant CX25821 PCIe bridge + * + * Copyright (C) 2009 Conexant Systems Inc. + * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> + * Based on Steven Toth <stoth@linuxtv.org> cx23885 driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef CX25821_H_ +#define CX25821_H_ + +#include <linux/pci.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/sched.h> +#include <linux/kdev_t.h> + +#include <media/v4l2-common.h> +#include <media/v4l2-device.h> +#include <media/tuner.h> +#include <media/tveeprom.h> +#include <media/videobuf-dma-sg.h> +#include <media/videobuf-dvb.h> + +#include "btcx-risc.h" +#include "cx25821-reg.h" +#include "cx25821-medusa-reg.h" +#include "cx25821-sram.h" +#include "cx25821-audio.h" +#include "media/cx2341x.h" + +#include <linux/version.h> +#include <linux/mutex.h> + +#define CX25821_VERSION_CODE KERNEL_VERSION(0, 0, 106) + +#define UNSET (-1U) +#define NO_SYNC_LINE (-1U) + +#define CX25821_MAXBOARDS 2 + +#define TRUE 1 +#define FALSE 0 +#define LINE_SIZE_D1 1440 + +/* Number of decoders and encoders */ +#define MAX_DECODERS 8 +#define MAX_ENCODERS 2 +#define QUAD_DECODERS 4 +#define MAX_CAMERAS 16 + +/* Max number of inputs by card */ +#define MAX_CX25821_INPUT 8 +#define INPUT(nr) (&cx25821_boards[dev->board].input[nr]) +#define RESOURCE_VIDEO0 1 +#define RESOURCE_VIDEO1 2 +#define RESOURCE_VIDEO2 4 +#define RESOURCE_VIDEO3 8 +#define RESOURCE_VIDEO4 16 +#define RESOURCE_VIDEO5 32 +#define RESOURCE_VIDEO6 64 +#define RESOURCE_VIDEO7 128 +#define RESOURCE_VIDEO8 256 +#define RESOURCE_VIDEO9 512 +#define RESOURCE_VIDEO10 1024 +#define RESOURCE_VIDEO11 2048 +#define RESOURCE_VIDEO_IOCTL 4096 + +#define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */ + +#define UNKNOWN_BOARD 0 +#define CX25821_BOARD 1 + +/* Currently supported by the driver */ +#define CX25821_NORMS (\ + V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_M_KR | \ + V4L2_STD_PAL_BG | V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \ + V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_H | \ + V4L2_STD_PAL_Nc) + +#define CX25821_BOARD_CONEXANT_ATHENA10 1 +#define MAX_VID_CHANNEL_NUM 12 +#define VID_CHANNEL_NUM 8 +#define CX25821_NR_INPUT 2 + +struct cx25821_fmt { + char *name; + u32 fourcc; /* v4l2 format id */ + int depth; + int flags; + u32 cxformat; +}; + +struct cx25821_ctrl { + struct v4l2_queryctrl v; + u32 off; + u32 reg; + u32 mask; + u32 shift; +}; + +struct cx25821_tvnorm { + char *name; + v4l2_std_id id; + u32 cxiformat; + u32 cxoformat; +}; + +struct cx25821_fh { + struct cx25821_dev *dev; + enum v4l2_buf_type type; + int radio; + u32 resources; + + enum v4l2_priority prio; + + /* video overlay */ + struct v4l2_window win; + struct v4l2_clip *clips; + unsigned int nclips; + + /* video capture */ + struct cx25821_fmt *fmt; + unsigned int width, height; + int channel_id; + + /* vbi capture */ + struct videobuf_queue vidq; + struct videobuf_queue vbiq; + + /* H264 Encoder specifics ONLY */ + struct videobuf_queue mpegq; + atomic_t v4l_reading; +}; + +enum cx25821_itype { + CX25821_VMUX_COMPOSITE = 1, + CX25821_VMUX_SVIDEO, + CX25821_VMUX_DEBUG, + CX25821_RADIO, +}; + +enum cx25821_src_sel_type { + CX25821_SRC_SEL_EXT_656_VIDEO = 0, + CX25821_SRC_SEL_PARALLEL_MPEG_VIDEO +}; + +/* buffer for one video frame */ +struct cx25821_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + + /* cx25821 specific */ + unsigned int bpl; + struct btcx_riscmem risc; + struct cx25821_fmt *fmt; + u32 count; +}; + +struct cx25821_input { + enum cx25821_itype type; + unsigned int vmux; + u32 gpio0, gpio1, gpio2, gpio3; +}; + +enum port { + CX25821_UNDEFINED = 0, + CX25821_RAW, + CX25821_264 +}; + +struct cx25821_board { + const char *name; + enum port porta; + enum port portb; + enum port portc; + unsigned int tuner_type; + unsigned int radio_type; + unsigned char tuner_addr; + unsigned char radio_addr; + + u32 clk_freq; + struct cx25821_input input[CX25821_NR_INPUT]; +}; + +struct cx25821_subid { + u16 subvendor; + u16 subdevice; + u32 card; +}; + +struct cx25821_i2c { + struct cx25821_dev *dev; + + int nr; + + /* i2c i/o */ + struct i2c_adapter i2c_adap; + struct i2c_client i2c_client; + u32 i2c_rc; + + /* cx25821 registers used for raw addess */ + u32 i2c_period; + u32 reg_ctrl; + u32 reg_stat; + u32 reg_addr; + u32 reg_rdata; + u32 reg_wdata; +}; + +struct cx25821_dmaqueue { + struct list_head active; + struct list_head queued; + struct timer_list timeout; + struct btcx_riscmem stopper; + u32 count; +}; + +struct cx25821_data { + struct cx25821_dev *dev; + struct sram_channel *channel; +}; + +struct cx25821_channel { + struct v4l2_prio_state prio; + + int ctl_bright; + int ctl_contrast; + int ctl_hue; + int ctl_saturation; + struct cx25821_data timeout_data; + + struct video_device *video_dev; + struct cx25821_dmaqueue vidq; + + struct sram_channel *sram_channels; + + struct mutex lock; + int resources; + + int pixel_formats; + int use_cif_resolution; + int cif_width; +}; + +struct cx25821_dev { + struct list_head devlist; + atomic_t refcount; + struct v4l2_device v4l2_dev; + + /* pci stuff */ + struct pci_dev *pci; + unsigned char pci_rev, pci_lat; + int pci_bus, pci_slot; + u32 base_io_addr; + u32 __iomem *lmmio; + u8 __iomem *bmmio; + int pci_irqmask; + int hwrevision; + + u32 clk_freq; + + /* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */ + struct cx25821_i2c i2c_bus[3]; + + int nr; + struct mutex lock; + + struct cx25821_channel channels[MAX_VID_CHANNEL_NUM]; + + /* board details */ + unsigned int board; + char name[32]; + + /* Analog video */ + u32 resources; + unsigned int input; + u32 tvaudio; + v4l2_std_id tvnorm; + unsigned int tuner_type; + unsigned char tuner_addr; + unsigned int radio_type; + unsigned char radio_addr; + unsigned int has_radio; + unsigned int videc_type; + unsigned char videc_addr; + unsigned short _max_num_decoders; + + /* Analog Audio Upstream */ + int _audio_is_running; + int _audiopixel_format; + int _is_first_audio_frame; + int _audiofile_status; + int _audio_lines_count; + int _audioframe_count; + int _audio_upstream_channel; + int _last_index_irq; /* The last interrupt index processed. */ + + __le32 *_risc_audio_jmp_addr; + __le32 *_risc_virt_start_addr; + __le32 *_risc_virt_addr; + dma_addr_t _risc_phys_addr; + dma_addr_t _risc_phys_start_addr; + + unsigned int _audiorisc_size; + unsigned int _audiodata_buf_size; + __le32 *_audiodata_buf_virt_addr; + dma_addr_t _audiodata_buf_phys_addr; + char *_audiofilename; + + /* V4l */ + u32 freq; + struct video_device *vbi_dev; + struct video_device *radio_dev; + struct video_device *ioctl_dev; + + spinlock_t slock; + + /* Video Upstream */ + int _line_size; + int _prog_cnt; + int _pixel_format; + int _is_first_frame; + int _is_running; + int _file_status; + int _lines_count; + int _frame_count; + int _channel_upstream_select; + unsigned int _risc_size; + + __le32 *_dma_virt_start_addr; + __le32 *_dma_virt_addr; + dma_addr_t _dma_phys_addr; + dma_addr_t _dma_phys_start_addr; + + unsigned int _data_buf_size; + __le32 *_data_buf_virt_addr; + dma_addr_t _data_buf_phys_addr; + char *_filename; + char *_defaultname; + + int _line_size_ch2; + int _prog_cnt_ch2; + int _pixel_format_ch2; + int _is_first_frame_ch2; + int _is_running_ch2; + int _file_status_ch2; + int _lines_count_ch2; + int _frame_count_ch2; + int _channel2_upstream_select; + unsigned int _risc_size_ch2; + + __le32 *_dma_virt_start_addr_ch2; + __le32 *_dma_virt_addr_ch2; + dma_addr_t _dma_phys_addr_ch2; + dma_addr_t _dma_phys_start_addr_ch2; + + unsigned int _data_buf_size_ch2; + __le32 *_data_buf_virt_addr_ch2; + dma_addr_t _data_buf_phys_addr_ch2; + char *_filename_ch2; + char *_defaultname_ch2; + + /* MPEG Encoder ONLY settings */ + u32 cx23417_mailbox; + struct cx2341x_mpeg_params mpeg_params; + struct video_device *v4l_device; + atomic_t v4l_reader_count; + struct cx25821_tvnorm encodernorm; + + u32 upstream_riscbuf_size; + u32 upstream_databuf_size; + u32 upstream_riscbuf_size_ch2; + u32 upstream_databuf_size_ch2; + u32 audio_upstream_riscbuf_size; + u32 audio_upstream_databuf_size; + int _isNTSC; + int _frame_index; + int _audioframe_index; + struct workqueue_struct *_irq_queues; + struct work_struct _irq_work_entry; + struct workqueue_struct *_irq_queues_ch2; + struct work_struct _irq_work_entry_ch2; + struct workqueue_struct *_irq_audio_queues; + struct work_struct _audio_work_entry; + char *input_filename; + char *input_filename_ch2; + int _frame_index_ch2; + int _isNTSC_ch2; + char *vid_stdname_ch2; + int pixel_format_ch2; + int channel_select_ch2; + int command_ch2; + char *input_audiofilename; + char *vid_stdname; + int pixel_format; + int channel_select; + int command; + int channel_opened; +}; + +struct upstream_user_struct { + char *input_filename; + char *vid_stdname; + int pixel_format; + int channel_select; + int command; +}; + +struct downstream_user_struct { + char *vid_stdname; + int pixel_format; + int cif_resolution_enable; + int cif_width; + int decoder_select; + int command; + int reg_address; + int reg_data; +}; + +extern struct upstream_user_struct *up_data; + +static inline struct cx25821_dev *get_cx25821(struct v4l2_device *v4l2_dev) +{ + return container_of(v4l2_dev, struct cx25821_dev, v4l2_dev); +} + +#define cx25821_call_all(dev, o, f, args...) \ + v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args) + +extern struct list_head cx25821_devlist; +extern struct mutex cx25821_devlist_mutex; + +extern struct cx25821_board cx25821_boards[]; +extern struct cx25821_subid cx25821_subids[]; + +#define SRAM_CH00 0 /* Video A */ +#define SRAM_CH01 1 /* Video B */ +#define SRAM_CH02 2 /* Video C */ +#define SRAM_CH03 3 /* Video D */ +#define SRAM_CH04 4 /* Video E */ +#define SRAM_CH05 5 /* Video F */ +#define SRAM_CH06 6 /* Video G */ +#define SRAM_CH07 7 /* Video H */ + +#define SRAM_CH08 8 /* Audio A */ +#define SRAM_CH09 9 /* Video Upstream I */ +#define SRAM_CH10 10 /* Video Upstream J */ +#define SRAM_CH11 11 /* Audio Upstream AUD_CHANNEL_B */ + +#define VID_UPSTREAM_SRAM_CHANNEL_I SRAM_CH09 +#define VID_UPSTREAM_SRAM_CHANNEL_J SRAM_CH10 +#define AUDIO_UPSTREAM_SRAM_CHANNEL_B SRAM_CH11 +#define VIDEO_IOCTL_CH 11 + +struct sram_channel { + char *name; + u32 i; + u32 cmds_start; + u32 ctrl_start; + u32 cdt; + u32 fifo_start; + u32 fifo_size; + u32 ptr1_reg; + u32 ptr2_reg; + u32 cnt1_reg; + u32 cnt2_reg; + u32 int_msk; + u32 int_stat; + u32 int_mstat; + u32 dma_ctl; + u32 gpcnt_ctl; + u32 gpcnt; + u32 aud_length; + u32 aud_cfg; + u32 fld_aud_fifo_en; + u32 fld_aud_risc_en; + + /* For Upstream Video */ + u32 vid_fmt_ctl; + u32 vid_active_ctl1; + u32 vid_active_ctl2; + u32 vid_cdt_size; + + u32 vip_ctl; + u32 pix_frmt; + u32 jumponly; + u32 irq_bit; +}; +extern struct sram_channel cx25821_sram_channels[]; + +#define STATUS_SUCCESS 0 +#define STATUS_UNSUCCESSFUL -1 + +#define cx_read(reg) readl(dev->lmmio + ((reg)>>2)) +#define cx_write(reg, value) writel((value), dev->lmmio + ((reg)>>2)) + +#define cx_andor(reg, mask, value) \ + writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\ + ((value) & (mask)), dev->lmmio+((reg)>>2)) + +#define cx_set(reg, bit) cx_andor((reg), (bit), (bit)) +#define cx_clear(reg, bit) cx_andor((reg), (bit), 0) + +#define Set_GPIO_Bit(Bit) (1 << Bit) +#define Clear_GPIO_Bit(Bit) (~(1 << Bit)) + +#define CX25821_ERR(fmt, args...) \ + pr_err("(%d): " fmt, dev->board, ##args) +#define CX25821_WARN(fmt, args...) \ + pr_warn("(%d): " fmt, dev->board, ##args) +#define CX25821_INFO(fmt, args...) \ + pr_info("(%d): " fmt, dev->board, ##args) + +extern int cx25821_i2c_register(struct cx25821_i2c *bus); +extern void cx25821_card_setup(struct cx25821_dev *dev); +extern int cx25821_ir_init(struct cx25821_dev *dev); +extern int cx25821_i2c_read(struct cx25821_i2c *bus, u16 reg_addr, int *value); +extern int cx25821_i2c_write(struct cx25821_i2c *bus, u16 reg_addr, int value); +extern int cx25821_i2c_unregister(struct cx25821_i2c *bus); +extern void cx25821_gpio_init(struct cx25821_dev *dev); +extern void cx25821_set_gpiopin_direction(struct cx25821_dev *dev, + int pin_number, int pin_logic_value); + +extern int medusa_video_init(struct cx25821_dev *dev); +extern int medusa_set_videostandard(struct cx25821_dev *dev); +extern void medusa_set_resolution(struct cx25821_dev *dev, int width, + int decoder_select); +extern int medusa_set_brightness(struct cx25821_dev *dev, int brightness, + int decoder); +extern int medusa_set_contrast(struct cx25821_dev *dev, int contrast, + int decoder); +extern int medusa_set_hue(struct cx25821_dev *dev, int hue, int decoder); +extern int medusa_set_saturation(struct cx25821_dev *dev, int saturation, + int decoder); + +extern int cx25821_sram_channel_setup(struct cx25821_dev *dev, + struct sram_channel *ch, unsigned int bpl, + u32 risc); + +extern int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int top_offset, + unsigned int bottom_offset, + unsigned int bpl, + unsigned int padding, unsigned int lines); +extern int cx25821_risc_databuffer_audio(struct pci_dev *pci, + struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int bpl, + unsigned int lines, unsigned int lpi); +extern void cx25821_free_buffer(struct videobuf_queue *q, + struct cx25821_buffer *buf); +extern int cx25821_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, + u32 reg, u32 mask, u32 value); +extern void cx25821_sram_channel_dump(struct cx25821_dev *dev, + struct sram_channel *ch); +extern void cx25821_sram_channel_dump_audio(struct cx25821_dev *dev, + struct sram_channel *ch); + +extern struct cx25821_dev *cx25821_dev_get(struct pci_dev *pci); +extern void cx25821_print_irqbits(char *name, char *tag, char **strings, + int len, u32 bits, u32 mask); +extern void cx25821_dev_unregister(struct cx25821_dev *dev); +extern int cx25821_sram_channel_setup_audio(struct cx25821_dev *dev, + struct sram_channel *ch, + unsigned int bpl, u32 risc); + +extern int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, + int channel_select, int pixel_format); +extern int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, + int channel_select, int pixel_format); +extern int cx25821_audio_upstream_init(struct cx25821_dev *dev, + int channel_select); +extern void cx25821_free_mem_upstream_ch1(struct cx25821_dev *dev); +extern void cx25821_free_mem_upstream_ch2(struct cx25821_dev *dev); +extern void cx25821_free_mem_upstream_audio(struct cx25821_dev *dev); +extern void cx25821_start_upstream_video_ch1(struct cx25821_dev *dev, + struct upstream_user_struct + *up_data); +extern void cx25821_start_upstream_video_ch2(struct cx25821_dev *dev, + struct upstream_user_struct + *up_data); +extern void cx25821_start_upstream_audio(struct cx25821_dev *dev, + struct upstream_user_struct *up_data); +extern void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev); +extern void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev); +extern void cx25821_stop_upstream_audio(struct cx25821_dev *dev); +extern int cx25821_sram_channel_setup_upstream(struct cx25821_dev *dev, + struct sram_channel *ch, + unsigned int bpl, u32 risc); +extern void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel, + u32 format); +extern void cx25821_videoioctl_unregister(struct cx25821_dev *dev); +extern struct video_device *cx25821_vdev_init(struct cx25821_dev *dev, + struct pci_dev *pci, + struct video_device *template, + char *type); +#endif |