Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,29 @@
# SPDX-License-Identifier: GPL-2.0-only
config VIDEO_CX25821
tristate "Conexant cx25821 support"
depends on VIDEO_DEV && PCI && I2C
select I2C_ALGOBIT
select VIDEOBUF2_DMA_SG
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
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.
@@ -0,0 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
cx25821-y := cx25821-core.o cx25821-cards.o cx25821-i2c.o \
cx25821-gpio.o cx25821-medusa-video.o \
cx25821-video.o
obj-$(CONFIG_VIDEO_CX25821) += cx25821.o
obj-$(CONFIG_VIDEO_CX25821_ALSA) += cx25821-alsa.o
@@ -0,0 +1,820 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* 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
*/
#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 int devno;
struct cx25821_audio_buffer {
unsigned int bpl;
struct cx25821_riscmem risc;
void *vaddr;
struct scatterlist *sglist;
int sglen;
unsigned long nr_pages;
};
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 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] = SNDRV_DEFAULT_ENABLE_PNP;
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");
static unsigned int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable debug messages");
/****************************************************************************
Module specific functions
****************************************************************************/
/* 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)
static int cx25821_alsa_dma_init(struct cx25821_audio_dev *chip,
unsigned long nr_pages)
{
struct cx25821_audio_buffer *buf = chip->buf;
struct page *pg;
int i;
buf->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT);
if (NULL == buf->vaddr) {
dprintk(1, "vmalloc_32(%lu pages) failed\n", nr_pages);
return -ENOMEM;
}
dprintk(1, "vmalloc is at addr 0x%p, size=%lu\n",
buf->vaddr,
nr_pages << PAGE_SHIFT);
memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT);
buf->nr_pages = nr_pages;
buf->sglist = vzalloc(array_size(sizeof(*buf->sglist), buf->nr_pages));
if (NULL == buf->sglist)
goto vzalloc_err;
sg_init_table(buf->sglist, buf->nr_pages);
for (i = 0; i < buf->nr_pages; i++) {
pg = vmalloc_to_page(buf->vaddr + i * PAGE_SIZE);
if (NULL == pg)
goto vmalloc_to_page_err;
sg_set_page(&buf->sglist[i], pg, PAGE_SIZE, 0);
}
return 0;
vmalloc_to_page_err:
vfree(buf->sglist);
buf->sglist = NULL;
vzalloc_err:
vfree(buf->vaddr);
buf->vaddr = NULL;
return -ENOMEM;
}
static int cx25821_alsa_dma_map(struct cx25821_audio_dev *dev)
{
struct cx25821_audio_buffer *buf = dev->buf;
buf->sglen = dma_map_sg(&dev->pci->dev, buf->sglist,
buf->nr_pages, DMA_FROM_DEVICE);
if (0 == buf->sglen) {
pr_warn("%s: cx25821_alsa_map_sg failed\n", __func__);
return -ENOMEM;
}
return 0;
}
static int cx25821_alsa_dma_unmap(struct cx25821_audio_dev *dev)
{
struct cx25821_audio_buffer *buf = dev->buf;
if (!buf->sglen)
return 0;
dma_unmap_sg(&dev->pci->dev, buf->sglist, buf->nr_pages, DMA_FROM_DEVICE);
buf->sglen = 0;
return 0;
}
static int cx25821_alsa_dma_free(struct cx25821_audio_buffer *buf)
{
vfree(buf->sglist);
buf->sglist = NULL;
vfree(buf->vaddr);
buf->vaddr = NULL;
return 0;
}
/*
* 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;
const 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)
{
struct cx25821_riscmem *risc = &chip->buf->risc;
WARN_ON(!chip->dma_size);
dprintk(2, "Freeing buffer\n");
cx25821_alsa_dma_unmap(chip);
cx25821_alsa_dma_free(chip->buf);
dma_free_coherent(&chip->pci->dev, risc->size, risc->cpu, risc->dma);
kfree(chip->buf);
chip->buf = NULL;
chip->dma_size = 0;
return 0;
}
/****************************************************************************
ALSA PCM Interface
****************************************************************************/
/*
* Digital hardware definition
*/
#define DEFAULT_FIFO_SIZE 384
static const 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 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);
WARN_ON(!chip->dma_size);
WARN_ON(chip->num_periods & (chip->num_periods - 1));
buf = kzalloc_obj(*buf);
if (NULL == buf)
return -ENOMEM;
if (chip->period_size > AUDIO_LINE_SIZE)
chip->period_size = AUDIO_LINE_SIZE;
buf->bpl = chip->period_size;
chip->buf = buf;
ret = cx25821_alsa_dma_init(chip,
(PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT));
if (ret < 0)
goto error;
ret = cx25821_alsa_dma_map(chip);
if (ret < 0)
goto error;
ret = cx25821_risc_databuffer_audio(chip->pci, &buf->risc, buf->sglist,
chip->period_size, chip->num_periods, 1);
if (ret < 0) {
pr_info("DEBUG: ERROR after cx25821_risc_databuffer_audio()\n");
cx25821_alsa_dma_unmap(chip);
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 */
substream->runtime->dma_area = chip->buf->vaddr;
substream->runtime->dma_bytes = chip->dma_size;
substream->runtime->dma_addr = 0;
return 0;
error:
chip->buf = NULL;
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 const struct snd_pcm_ops snd_cx25821_pcm_ops = {
.open = snd_cx25821_pcm_open,
.close = snd_cx25821_close,
.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;
strscpy(pcm->name, name, sizeof(pcm->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 const struct pci_device_id __maybe_unused cx25821_audio_pci_tbl[] = {
{0x14f1, 0x0920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0,}
};
MODULE_DEVICE_TABLE(pci, cx25821_audio_pci_tbl);
/*
* 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_new(&dev->pci->dev, 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;
}
strscpy(card->driver, "cx25821", sizeof(card->driver));
/* Card "creation" */
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 = devm_request_irq(&dev->pci->dev, 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;
}
strscpy(card->shortname, "cx25821", sizeof(card->shortname));
sprintf(card->longname, "%s at 0x%lx irq %d", chip->dev->name,
chip->iobase, chip->irq);
strscpy(card->mixername, "CX25821", sizeof(card->mixername));
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;
}
dev->card = card;
devno++;
return 0;
error:
snd_card_free(card);
return err;
}
/****************************************************************************
LINUX MODULE INIT
****************************************************************************/
static int cx25821_alsa_exit_callback(struct device *dev, void *data)
{
struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
struct cx25821_dev *cxdev = get_cx25821(v4l2_dev);
snd_card_free(cxdev->card);
return 0;
}
static void cx25821_audio_fini(void)
{
struct device_driver *drv = driver_find("cx25821", &pci_bus_type);
int ret;
ret = driver_for_each_device(drv, NULL, NULL, cx25821_alsa_exit_callback);
if (ret)
pr_err("%s failed to find a cx25821 driver.\n", __func__);
}
static int cx25821_alsa_init_callback(struct device *dev, void *data)
{
struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
struct cx25821_dev *cxdev = get_cx25821(v4l2_dev);
cx25821_audio_initdev(cxdev);
return 0;
}
/*
* Module initializer
*
* Loops through present saa7134 cards, and assigns an ALSA device
* to each one
*
*/
static int cx25821_alsa_init(void)
{
struct device_driver *drv = driver_find("cx25821", &pci_bus_type);
return driver_for_each_device(drv, NULL, NULL, cx25821_alsa_init_callback);
}
late_initcall(cx25821_alsa_init);
module_exit(cx25821_audio_fini);
@@ -0,0 +1,48 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Driver for the Conexant CX25821 PCIe bridge
*
* Copyright (C) 2009 Conexant Systems Inc.
* Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
*/
#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
@@ -0,0 +1,31 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Driver for the Conexant CX25821 PCIe bridge
*
* Copyright (C) 2009 Conexant Systems Inc.
* Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
*/
#ifndef _BITFUNCS_H
#define _BITFUNCS_H
#define SetBit(Bit) (1 << Bit)
static inline u8 getBit(u32 sample, u8 index)
{
return (u8) ((sample >> index) & 1);
}
static inline u32 clearBitAtPos(u32 value, u8 bit)
{
return value & ~(1 << bit);
}
static inline u32 setBitAtPos(u32 sample, u8 bit)
{
sample |= (1 << bit);
return sample;
}
#endif
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* 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
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
#include "cx25821.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,
},
};
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,85 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Driver for the Conexant CX25821 PCIe bridge
*
* Copyright (C) 2009 Conexant Systems Inc.
* Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
*/
#include <linux/module.h>
#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);
msleep(20);
break;
}
}
@@ -0,0 +1,405 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* 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
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/i2c.h>
#include "cx25821.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 const 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 const struct i2c_adapter cx25821_i2c_adap_template = {
.name = "cx25821",
.owner = THIS_MODULE,
.algo = &cx25821_i2c_algo_template,
};
static const 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;
strscpy(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;
}
#if 0 /* Currently unused */
static 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);
}
#endif
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;
}
@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Driver for the Conexant CX25821 PCIe bridge
*
* Copyright (C) 2009 Conexant Systems Inc.
* Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
*/
#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
@@ -0,0 +1,441 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Driver for the Conexant CX25821 PCIe bridge
*
* Copyright (C) 2009 Conexant Systems Inc.
* Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
*/
#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 0x01E0
#define ABIST_CLAMP_A 0x01E4
#define ABIST_CLAMP_B 0x01E8
#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
@@ -0,0 +1,731 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Driver for the Conexant CX25821 PCIe bridge
*
* Copyright (C) 2009 Conexant Systems Inc.
* Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
*/
#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;
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);
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;
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);
return ret_val;
}
int medusa_set_videostandard(struct cx25821_dev *dev)
{
int status = 0;
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;
/* 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 = dev->_max_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);
}
}
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;
/* no support */
if (decoder < VDEC_A || decoder > VDEC_H) {
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;
}
/* 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);
}
/* 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;
if ((brightness > VIDEO_PROCAMP_MAX) ||
(brightness < VIDEO_PROCAMP_MIN)) {
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);
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;
if ((contrast > VIDEO_PROCAMP_MAX) || (contrast < VIDEO_PROCAMP_MIN)) {
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);
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;
if ((hue > VIDEO_PROCAMP_MAX) || (hue < VIDEO_PROCAMP_MIN)) {
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);
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;
if ((saturation > VIDEO_PROCAMP_MAX) ||
(saturation < VIDEO_PROCAMP_MIN)) {
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);
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;
/* 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;
/*
* FIXME: due to a coding bug the duration was always 0. It's
* likely that it really should be something else, but due to the
* lack of documentation I have no idea what it should be. For
* now just fill in 0 as the duration.
*/
for (i = 0; i < dev->_max_num_decoders; i++)
medusa_set_decoderduration(dev, i, 0);
/* 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 (dev->_max_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;
ret_val = medusa_set_videostandard(dev);
error:
return ret_val;
}
@@ -0,0 +1,29 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Driver for the Conexant CX25821 PCIe bridge
*
* Copyright (C) 2009 Conexant Systems Inc.
* Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
*/
#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
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,247 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Driver for the Conexant CX25821 PCIe bridge
*
* Copyright (C) 2009 Conexant Systems Inc.
* Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
*/
#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 usable 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
@@ -0,0 +1,774 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* 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> cx25821 driver
* Parts adapted/taken from Eduardo Moscoso Rubino
* Copyright (C) 2009 Eduardo Moscoso Rubino <moscoso@TopoLogica.com>
*/
#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 };
module_param_array(video_nr, int, NULL, 0444);
MODULE_PARM_DESC(video_nr, "video 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]");
#define FORMAT_FLAGS_PACKED 0x01
static const struct cx25821_fmt formats[] = {
{
.fourcc = V4L2_PIX_FMT_Y41P,
.depth = 12,
.flags = FORMAT_FLAGS_PACKED,
}, {
.fourcc = V4L2_PIX_FMT_YUYV,
.depth = 16,
.flags = FORMAT_FLAGS_PACKED,
},
};
static const struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(formats); i++)
if (formats[i].fourcc == fourcc)
return formats + i;
return NULL;
}
int cx25821_start_video_dma(struct cx25821_dev *dev,
struct cx25821_dmaqueue *q,
struct cx25821_buffer *buf,
const 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);
/* 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_video_irq(struct cx25821_dev *dev, int chan_num, u32 status)
{
int handled = 0;
u32 mask;
const 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) {
struct cx25821_dmaqueue *dmaq =
&dev->channels[channel->i].dma_vidq;
struct cx25821_buffer *buf;
spin_lock(&dev->slock);
if (!list_empty(&dmaq->active)) {
buf = list_entry(dmaq->active.next,
struct cx25821_buffer, queue);
buf->vb.vb2_buf.timestamp = ktime_get_ns();
buf->vb.sequence = dmaq->count++;
list_del(&buf->queue);
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
}
spin_unlock(&dev->slock);
handled++;
}
return handled;
}
static int cx25821_queue_setup(struct vb2_queue *q,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], struct device *alloc_devs[])
{
struct cx25821_channel *chan = q->drv_priv;
unsigned size = (chan->fmt->depth * chan->width * chan->height) >> 3;
if (*num_planes)
return sizes[0] < size ? -EINVAL : 0;
*num_planes = 1;
sizes[0] = size;
return 0;
}
static int cx25821_buffer_prepare(struct vb2_buffer *vb)
{
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct cx25821_channel *chan = vb->vb2_queue->drv_priv;
struct cx25821_dev *dev = chan->dev;
struct cx25821_buffer *buf =
container_of(vbuf, struct cx25821_buffer, vb);
struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
u32 line0_offset;
int bpl_local = LINE_SIZE_D1;
int ret;
if (chan->pixel_formats == PIXEL_FRMT_411)
buf->bpl = (chan->fmt->depth * chan->width) >> 3;
else
buf->bpl = (chan->fmt->depth >> 3) * chan->width;
if (vb2_plane_size(vb, 0) < chan->height * buf->bpl)
return -EINVAL;
vb2_set_plane_payload(vb, 0, chan->height * buf->bpl);
buf->vb.field = chan->field;
if (chan->pixel_formats == PIXEL_FRMT_411) {
bpl_local = buf->bpl;
} else {
bpl_local = buf->bpl; /* Default */
if (chan->use_cif_resolution) {
if (dev->tvnorm & V4L2_STD_625_50)
bpl_local = 352 << 1;
else
bpl_local = chan->cif_width << 1;
}
}
switch (chan->field) {
case V4L2_FIELD_TOP:
ret = cx25821_risc_buffer(dev->pci, &buf->risc,
sgt->sgl, 0, UNSET,
buf->bpl, 0, chan->height);
break;
case V4L2_FIELD_BOTTOM:
ret = cx25821_risc_buffer(dev->pci, &buf->risc,
sgt->sgl, UNSET, 0,
buf->bpl, 0, chan->height);
break;
case V4L2_FIELD_INTERLACED:
/* All other formats are top field first */
line0_offset = 0;
dprintk(1, "top field first\n");
ret = cx25821_risc_buffer(dev->pci, &buf->risc,
sgt->sgl, line0_offset,
bpl_local, bpl_local, bpl_local,
chan->height >> 1);
break;
case V4L2_FIELD_SEQ_TB:
ret = cx25821_risc_buffer(dev->pci, &buf->risc,
sgt->sgl,
0, buf->bpl * (chan->height >> 1),
buf->bpl, 0, chan->height >> 1);
break;
case V4L2_FIELD_SEQ_BT:
ret = cx25821_risc_buffer(dev->pci, &buf->risc,
sgt->sgl,
buf->bpl * (chan->height >> 1), 0,
buf->bpl, 0, chan->height >> 1);
break;
default:
WARN_ON(1);
ret = -EINVAL;
break;
}
dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp 0x%08x - dma=0x%08lx\n",
buf, buf->vb.vb2_buf.index, chan->width, chan->height,
chan->fmt->depth, chan->fmt->fourcc,
(unsigned long)buf->risc.dma);
return ret;
}
static void cx25821_buffer_finish(struct vb2_buffer *vb)
{
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct cx25821_buffer *buf =
container_of(vbuf, struct cx25821_buffer, vb);
struct cx25821_channel *chan = vb->vb2_queue->drv_priv;
struct cx25821_dev *dev = chan->dev;
cx25821_free_buffer(dev, buf);
}
static void cx25821_buffer_queue(struct vb2_buffer *vb)
{
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct cx25821_buffer *buf =
container_of(vbuf, struct cx25821_buffer, vb);
struct cx25821_channel *chan = vb->vb2_queue->drv_priv;
struct cx25821_dev *dev = chan->dev;
struct cx25821_buffer *prev;
struct cx25821_dmaqueue *q = &dev->channels[chan->id].dma_vidq;
buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12);
buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC);
buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12);
buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
if (list_empty(&q->active)) {
list_add_tail(&buf->queue, &q->active);
} else {
buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1);
prev = list_entry(q->active.prev, struct cx25821_buffer,
queue);
list_add_tail(&buf->queue, &q->active);
prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
}
}
static int cx25821_start_streaming(struct vb2_queue *q, unsigned int count)
{
struct cx25821_channel *chan = q->drv_priv;
struct cx25821_dev *dev = chan->dev;
struct cx25821_dmaqueue *dmaq = &dev->channels[chan->id].dma_vidq;
struct cx25821_buffer *buf = list_entry(dmaq->active.next,
struct cx25821_buffer, queue);
dmaq->count = 0;
cx25821_start_video_dma(dev, dmaq, buf, chan->sram_channels);
return 0;
}
static void cx25821_stop_streaming(struct vb2_queue *q)
{
struct cx25821_channel *chan = q->drv_priv;
struct cx25821_dev *dev = chan->dev;
struct cx25821_dmaqueue *dmaq = &dev->channels[chan->id].dma_vidq;
unsigned long flags;
cx_write(chan->sram_channels->dma_ctl, 0); /* FIFO and RISC disable */
spin_lock_irqsave(&dev->slock, flags);
while (!list_empty(&dmaq->active)) {
struct cx25821_buffer *buf = list_entry(dmaq->active.next,
struct cx25821_buffer, queue);
list_del(&buf->queue);
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
}
spin_unlock_irqrestore(&dev->slock, flags);
}
static const struct vb2_ops cx25821_video_qops = {
.queue_setup = cx25821_queue_setup,
.buf_prepare = cx25821_buffer_prepare,
.buf_finish = cx25821_buffer_finish,
.buf_queue = cx25821_buffer_queue,
.start_streaming = cx25821_start_streaming,
.stop_streaming = cx25821_stop_streaming,
};
/* VIDEO IOCTLS */
static 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;
f->pixelformat = formats[f->index].fourcc;
return 0;
}
static int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct cx25821_channel *chan = video_drvdata(file);
f->fmt.pix.width = chan->width;
f->fmt.pix.height = chan->height;
f->fmt.pix.field = chan->field;
f->fmt.pix.pixelformat = chan->fmt->fourcc;
f->fmt.pix.bytesperline = (chan->width * chan->fmt->depth) >> 3;
f->fmt.pix.sizeimage = chan->height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
return 0;
}
static int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct cx25821_channel *chan = video_drvdata(file);
struct cx25821_dev *dev = chan->dev;
const struct cx25821_fmt *fmt;
enum v4l2_field field = f->fmt.pix.field;
unsigned int maxh;
unsigned w;
fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
if (NULL == fmt)
return -EINVAL;
maxh = (dev->tvnorm & V4L2_STD_625_50) ? 576 : 480;
w = f->fmt.pix.width;
if (field != V4L2_FIELD_BOTTOM)
field = V4L2_FIELD_TOP;
if (w < 352) {
w = 176;
f->fmt.pix.height = maxh / 4;
} else if (w < 720) {
w = 352;
f->fmt.pix.height = maxh / 2;
} else {
w = 720;
f->fmt.pix.height = maxh;
field = V4L2_FIELD_INTERLACED;
}
f->fmt.pix.field = field;
f->fmt.pix.width = w;
f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
return 0;
}
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct cx25821_channel *chan = video_drvdata(file);
struct cx25821_dev *dev = chan->dev;
int pix_format = PIXEL_FRMT_422;
int err;
err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
if (0 != err)
return err;
chan->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
chan->field = f->fmt.pix.field;
chan->width = f->fmt.pix.width;
chan->height = f->fmt.pix.height;
if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
pix_format = PIXEL_FRMT_411;
else
pix_format = PIXEL_FRMT_422;
cx25821_set_pixel_format(dev, SRAM_CH00, pix_format);
/* check if cif resolution */
if (chan->width == 320 || chan->width == 352)
chan->use_cif_resolution = 1;
else
chan->use_cif_resolution = 0;
chan->cif_width = chan->width;
medusa_set_resolution(dev, chan->width, SRAM_CH00);
return 0;
}
static int vidioc_log_status(struct file *file, void *priv)
{
struct cx25821_channel *chan = video_drvdata(file);
struct cx25821_dev *dev = chan->dev;
const struct sram_channel *sram_ch = chan->sram_channels;
u32 tmp = 0;
tmp = cx_read(sram_ch->dma_ctl);
pr_info("Video input 0 is %s\n",
(tmp & 0x11) ? "streaming" : "stopped");
return 0;
}
static int cx25821_vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
struct cx25821_channel *chan = video_drvdata(file);
struct cx25821_dev *dev = chan->dev;
strscpy(cap->driver, "cx25821", sizeof(cap->driver));
strscpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card));
sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
V4L2_CAP_DEVICE_CAPS;
return 0;
}
static int cx25821_vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorms)
{
struct cx25821_channel *chan = video_drvdata(file);
*tvnorms = chan->dev->tvnorm;
return 0;
}
static int cx25821_vidioc_s_std(struct file *file, void *priv,
v4l2_std_id tvnorms)
{
struct cx25821_channel *chan = video_drvdata(file);
struct cx25821_dev *dev = chan->dev;
if (dev->tvnorm == tvnorms)
return 0;
dev->tvnorm = tvnorms;
chan->width = 720;
chan->height = (dev->tvnorm & V4L2_STD_625_50) ? 576 : 480;
medusa_set_videostandard(dev);
return 0;
}
static int cx25821_vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *i)
{
if (i->index)
return -EINVAL;
i->type = V4L2_INPUT_TYPE_CAMERA;
i->std = CX25821_NORMS;
strscpy(i->name, "Composite", sizeof(i->name));
return 0;
}
static int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i)
{
*i = 0;
return 0;
}
static int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i)
{
return i ? -EINVAL : 0;
}
static int cx25821_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct cx25821_channel *chan =
container_of(ctrl->handler, struct cx25821_channel, hdl);
struct cx25821_dev *dev = chan->dev;
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
medusa_set_brightness(dev, ctrl->val, chan->id);
break;
case V4L2_CID_HUE:
medusa_set_hue(dev, ctrl->val, chan->id);
break;
case V4L2_CID_CONTRAST:
medusa_set_contrast(dev, ctrl->val, chan->id);
break;
case V4L2_CID_SATURATION:
medusa_set_saturation(dev, ctrl->val, chan->id);
break;
default:
return -EINVAL;
}
return 0;
}
static int cx25821_vidioc_enum_output(struct file *file, void *priv,
struct v4l2_output *o)
{
if (o->index)
return -EINVAL;
o->type = V4L2_INPUT_TYPE_CAMERA;
o->std = CX25821_NORMS;
strscpy(o->name, "Composite", sizeof(o->name));
return 0;
}
static int cx25821_vidioc_g_output(struct file *file, void *priv, unsigned int *o)
{
*o = 0;
return 0;
}
static int cx25821_vidioc_s_output(struct file *file, void *priv, unsigned int o)
{
return o ? -EINVAL : 0;
}
static int cx25821_vidioc_try_fmt_vid_out(struct file *file, void *priv,
struct v4l2_format *f)
{
struct cx25821_channel *chan = video_drvdata(file);
struct cx25821_dev *dev = chan->dev;
const struct cx25821_fmt *fmt;
fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
if (NULL == fmt)
return -EINVAL;
f->fmt.pix.width = 720;
f->fmt.pix.height = (dev->tvnorm & V4L2_STD_625_50) ? 576 : 480;
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
return 0;
}
static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
struct v4l2_format *f)
{
struct cx25821_channel *chan = video_drvdata(file);
int err;
err = cx25821_vidioc_try_fmt_vid_out(file, priv, f);
if (0 != err)
return err;
chan->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
chan->field = f->fmt.pix.field;
chan->width = f->fmt.pix.width;
chan->height = f->fmt.pix.height;
if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
chan->pixel_formats = PIXEL_FRMT_411;
else
chan->pixel_formats = PIXEL_FRMT_422;
return 0;
}
static const struct v4l2_ctrl_ops cx25821_ctrl_ops = {
.s_ctrl = cx25821_s_ctrl,
};
static const struct v4l2_file_operations video_fops = {
.owner = THIS_MODULE,
.open = v4l2_fh_open,
.release = vb2_fop_release,
.read = vb2_fop_read,
.poll = vb2_fop_poll,
.unlocked_ioctl = video_ioctl2,
.mmap = vb2_fop_mmap,
};
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 = vb2_ioctl_reqbufs,
.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
.vidioc_create_bufs = vb2_ioctl_create_bufs,
.vidioc_querybuf = vb2_ioctl_querybuf,
.vidioc_qbuf = vb2_ioctl_qbuf,
.vidioc_dqbuf = vb2_ioctl_dqbuf,
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_g_std = cx25821_vidioc_g_std,
.vidioc_s_std = cx25821_vidioc_s_std,
.vidioc_enum_input = cx25821_vidioc_enum_input,
.vidioc_g_input = cx25821_vidioc_g_input,
.vidioc_s_input = cx25821_vidioc_s_input,
.vidioc_log_status = vidioc_log_status,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static const struct video_device cx25821_video_device = {
.name = "cx25821-video",
.fops = &video_fops,
.release = video_device_release_empty,
.minor = -1,
.ioctl_ops = &video_ioctl_ops,
.tvnorms = CX25821_NORMS,
.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING,
};
static const struct v4l2_file_operations video_out_fops = {
.owner = THIS_MODULE,
.open = v4l2_fh_open,
.release = vb2_fop_release,
.write = vb2_fop_write,
.poll = vb2_fop_poll,
.unlocked_ioctl = video_ioctl2,
.mmap = vb2_fop_mmap,
};
static const struct v4l2_ioctl_ops video_out_ioctl_ops = {
.vidioc_querycap = cx25821_vidioc_querycap,
.vidioc_enum_fmt_vid_out = cx25821_vidioc_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_out = cx25821_vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_out = cx25821_vidioc_try_fmt_vid_out,
.vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
.vidioc_g_std = cx25821_vidioc_g_std,
.vidioc_s_std = cx25821_vidioc_s_std,
.vidioc_enum_output = cx25821_vidioc_enum_output,
.vidioc_g_output = cx25821_vidioc_g_output,
.vidioc_s_output = cx25821_vidioc_s_output,
.vidioc_log_status = vidioc_log_status,
};
static const struct video_device cx25821_video_out_device = {
.name = "cx25821-video",
.fops = &video_out_fops,
.release = video_device_release_empty,
.minor = -1,
.ioctl_ops = &video_out_ioctl_ops,
.tvnorms = CX25821_NORMS,
.device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE,
};
void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num)
{
cx_clear(PCI_INT_MSK, 1);
if (video_is_registered(&dev->channels[chan_num].vdev)) {
video_unregister_device(&dev->channels[chan_num].vdev);
v4l2_ctrl_handler_free(&dev->channels[chan_num].hdl);
}
}
int cx25821_video_register(struct cx25821_dev *dev)
{
int err;
int i;
/* initial device configuration */
dev->tvnorm = V4L2_STD_NTSC_M;
spin_lock_init(&dev->slock);
for (i = 0; i < MAX_VID_CAP_CHANNEL_NUM - 1; ++i) {
struct cx25821_channel *chan = &dev->channels[i];
struct video_device *vdev = &chan->vdev;
struct v4l2_ctrl_handler *hdl = &chan->hdl;
struct vb2_queue *q;
bool is_output = i > SRAM_CH08;
if (i == SRAM_CH08) /* audio channel */
continue;
if (!is_output) {
v4l2_ctrl_handler_init(hdl, 4);
v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
V4L2_CID_BRIGHTNESS, 0, 10000, 1, 6200);
v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
V4L2_CID_CONTRAST, 0, 10000, 1, 5000);
v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
V4L2_CID_SATURATION, 0, 10000, 1, 5000);
v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
V4L2_CID_HUE, 0, 10000, 1, 5000);
if (hdl->error) {
err = hdl->error;
goto fail_unreg;
}
err = v4l2_ctrl_handler_setup(hdl);
if (err)
goto fail_unreg;
} else {
chan->out = &dev->vid_out_data[i - SRAM_CH09];
chan->out->chan = chan;
}
chan->sram_channels = &cx25821_sram_channels[i];
chan->width = 720;
chan->field = V4L2_FIELD_INTERLACED;
if (dev->tvnorm & V4L2_STD_625_50)
chan->height = 576;
else
chan->height = 480;
if (chan->pixel_formats == PIXEL_FRMT_411)
chan->fmt = cx25821_format_by_fourcc(V4L2_PIX_FMT_Y41P);
else
chan->fmt = cx25821_format_by_fourcc(V4L2_PIX_FMT_YUYV);
cx_write(chan->sram_channels->int_stat, 0xffffffff);
INIT_LIST_HEAD(&chan->dma_vidq.active);
q = &chan->vidq;
q->type = is_output ? V4L2_BUF_TYPE_VIDEO_OUTPUT :
V4L2_BUF_TYPE_VIDEO_CAPTURE;
q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
q->io_modes |= is_output ? VB2_WRITE : VB2_READ;
q->gfp_flags = GFP_DMA32;
q->min_queued_buffers = 2;
q->drv_priv = chan;
q->buf_struct_size = sizeof(struct cx25821_buffer);
q->ops = &cx25821_video_qops;
q->mem_ops = &vb2_dma_sg_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->lock = &dev->lock;
q->dev = &dev->pci->dev;
if (!is_output) {
err = vb2_queue_init(q);
if (err < 0)
goto fail_unreg;
}
/* register v4l devices */
*vdev = is_output ? cx25821_video_out_device : cx25821_video_device;
vdev->v4l2_dev = &dev->v4l2_dev;
if (!is_output)
vdev->ctrl_handler = hdl;
else
vdev->vfl_dir = VFL_DIR_TX;
vdev->lock = &dev->lock;
vdev->queue = q;
snprintf(vdev->name, sizeof(vdev->name), "%s #%d", dev->name, i);
video_set_drvdata(vdev, chan);
err = video_register_device(vdev, VFL_TYPE_VIDEO,
video_nr[dev->nr]);
if (err < 0)
goto fail_unreg;
}
/* set PCI interrupt */
cx_set(PCI_INT_MSK, 0xff);
return 0;
fail_unreg:
while (i >= 0)
cx25821_video_unregister(dev, i--);
return err;
}
@@ -0,0 +1,48 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* 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
*/
#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>
#include <media/v4l2-event.h>
#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)
#define FORMAT_FLAGS_PACKED 0x01
extern int cx25821_start_video_dma(struct cx25821_dev *dev,
struct cx25821_dmaqueue *q,
struct cx25821_buffer *buf,
const struct sram_channel *channel);
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);
#endif
@@ -0,0 +1,426 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* 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
*/
#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/v4l2-ctrls.h>
#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-dma-sg.h>
#include "cx25821-reg.h"
#include "cx25821-medusa-reg.h"
#include "cx25821-sram.h"
#include "cx25821-audio.h"
#include <linux/mutex.h>
#define UNSET (-1U)
#define NO_SYNC_LINE (-1U)
#define CX25821_MAXBOARDS 2
#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 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 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
/*
* Maximum capture-only channels. This can go away once video/audio output
* is fully supported in this driver.
*/
#define MAX_VID_CAP_CHANNEL_NUM 10
#define VID_CHANNEL_NUM 8
struct cx25821_fmt {
u32 fourcc; /* v4l2 format id */
int depth;
int flags;
u32 cxformat;
};
struct cx25821_tvnorm {
char *name;
v4l2_std_id id;
u32 cxiformat;
u32 cxoformat;
};
enum cx25821_src_sel_type {
CX25821_SRC_SEL_EXT_656_VIDEO = 0,
CX25821_SRC_SEL_PARALLEL_MPEG_VIDEO
};
struct cx25821_riscmem {
unsigned int size;
__le32 *cpu;
__le32 *jmp;
dma_addr_t dma;
};
/* buffer for one video frame */
struct cx25821_buffer {
/* common v4l buffer stuff -- must be first */
struct vb2_v4l2_buffer vb;
struct list_head queue;
/* cx25821 specific */
unsigned int bpl;
struct cx25821_riscmem risc;
const struct cx25821_fmt *fmt;
};
enum port {
CX25821_UNDEFINED = 0,
CX25821_RAW,
CX25821_264
};
struct cx25821_board {
const char *name;
enum port porta;
enum port portb;
enum port portc;
u32 clk_freq;
};
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 address */
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;
u32 count;
};
struct cx25821_dev;
struct cx25821_channel;
struct cx25821_video_out_data {
struct cx25821_channel *chan;
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;
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;
u32 upstream_riscbuf_size;
u32 upstream_databuf_size;
int is_60hz;
int _frame_index;
int cur_frame_index;
int curpos;
wait_queue_head_t waitq;
};
struct cx25821_channel {
unsigned id;
struct cx25821_dev *dev;
struct v4l2_ctrl_handler hdl;
struct video_device vdev;
struct cx25821_dmaqueue dma_vidq;
struct vb2_queue vidq;
const struct sram_channel *sram_channels;
const struct cx25821_fmt *fmt;
unsigned field;
unsigned int width, height;
int pixel_formats;
int use_cif_resolution;
int cif_width;
/* video output data for the video output channel */
struct cx25821_video_out_data *out;
};
struct snd_card;
struct cx25821_dev {
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;
/* used by cx25821-alsa */
struct snd_card *card;
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 */
unsigned int input;
v4l2_std_id tvnorm;
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;
u32 audio_upstream_riscbuf_size;
u32 audio_upstream_databuf_size;
int _audioframe_index;
struct work_struct _audio_work_entry;
char *input_audiofilename;
/* V4l */
spinlock_t slock;
/* Video Upstream */
struct cx25821_video_out_data vid_out_data[2];
};
static inline struct cx25821_dev *get_cx25821(struct v4l2_device *v4l2_dev)
{
return container_of(v4l2_dev, struct cx25821_dev, v4l2_dev);
}
extern struct cx25821_board cx25821_boards[];
#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
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 const struct sram_channel cx25821_sram_channels[];
#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 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,
const struct sram_channel *ch, unsigned int bpl,
u32 risc);
extern int cx25821_riscmem_alloc(struct pci_dev *pci,
struct cx25821_riscmem *risc,
unsigned int size);
extern int cx25821_risc_buffer(struct pci_dev *pci, struct cx25821_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 cx25821_riscmem *risc,
struct scatterlist *sglist,
unsigned int bpl,
unsigned int lines, unsigned int lpi);
extern void cx25821_free_buffer(struct cx25821_dev *dev,
struct cx25821_buffer *buf);
extern void cx25821_sram_channel_dump(struct cx25821_dev *dev,
const struct sram_channel *ch);
extern void cx25821_sram_channel_dump_audio(struct cx25821_dev *dev,
const 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,
const struct sram_channel *ch,
unsigned int bpl, u32 risc);
extern void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel,
u32 format);
#endif