Commit faa4fd2a authored by Ben Collins's avatar Ben Collins Committed by Greg Kroah-Hartman

Staging: solo6x10: New driver (staging) for Softlogic 6x10

This driver supports Softlogic 6x10 based codec cards
Signed-off-by: default avatarBen Collins <bcollins@bluecherry.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 412b2d08
config SOLO6X10
tristate "Softlogic 6x10 MPEG codec cards"
depends on PCI && VIDEO_DEV
select VIDEOBUF_DMA_CONTIG
---help---
This driver supports the Softlogic based MPEG-4 and h.264 codec
codec cards.
solo6x10-objs := solo6010-core.o solo6010-i2c.o solo6010-p2m.o \
solo6010-v4l2.o solo6010-tw28.o solo6010-gpio.o \
solo6010-disp.o solo6010-enc.o solo6010-v4l2-enc.o \
solo6010-g723.o
obj-$(CONFIG_SOLO6X10) := solo6x10.o
/*
* Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
* Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/videodev2.h>
#include "solo6010.h"
#include "solo6010-tw28.h"
MODULE_DESCRIPTION("Softlogic 6010 MP4 Encoder/Decoder V4L2/ALSA Driver");
MODULE_AUTHOR("Ben Collins <bcollins@bluecherry.net>");
MODULE_VERSION(SOLO6010_VERSION);
MODULE_LICENSE("GPL");
void solo6010_irq_on(struct solo6010_dev *solo_dev, u32 mask)
{
solo_dev->irq_mask |= mask;
solo_reg_write(solo_dev, SOLO_IRQ_ENABLE, solo_dev->irq_mask);
}
void solo6010_irq_off(struct solo6010_dev *solo_dev, u32 mask)
{
solo_dev->irq_mask &= ~mask;
solo_reg_write(solo_dev, SOLO_IRQ_ENABLE, solo_dev->irq_mask);
}
/* XXX We should check the return value of the sub-device ISR's */
static irqreturn_t solo6010_isr(int irq, void *data)
{
struct solo6010_dev *solo_dev = data;
u32 status;
int i;
status = solo_reg_read(solo_dev, SOLO_IRQ_STAT);
if (!status)
return IRQ_NONE;
if (status & ~solo_dev->irq_mask) {
solo_reg_write(solo_dev, SOLO_IRQ_STAT,
status & ~solo_dev->irq_mask);
status &= solo_dev->irq_mask;
}
if (status & SOLO_IRQ_PCI_ERR) {
u32 err = solo_reg_read(solo_dev, SOLO_PCI_ERR);
solo_p2m_error_isr(solo_dev, err);
solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_PCI_ERR);
}
for (i = 0; i < SOLO_NR_P2M; i++)
if (status & SOLO_IRQ_P2M(i))
solo_p2m_isr(solo_dev, i);
if (status & SOLO_IRQ_IIC)
solo_i2c_isr(solo_dev);
if (status & SOLO_IRQ_VIDEO_IN)
solo_video_in_isr(solo_dev);
/* Call this first so enc gets detected flag set */
if (status & SOLO_IRQ_MOTION)
solo_motion_isr(solo_dev);
if (status & SOLO_IRQ_ENCODER)
solo_enc_v4l2_isr(solo_dev);
if (status & SOLO_IRQ_G723)
solo_g723_isr(solo_dev);
return IRQ_HANDLED;
}
static void free_solo_dev(struct solo6010_dev *solo_dev)
{
struct pci_dev *pdev;
if (!solo_dev)
return;
pdev = solo_dev->pdev;
/* If we never initialized the PCI device, then nothing else
* below here needs cleanup */
if (!pdev) {
kfree(solo_dev);
return;
}
/* Bring down the sub-devices first */
solo_g723_exit(solo_dev);
solo_enc_v4l2_exit(solo_dev);
solo_enc_exit(solo_dev);
solo_v4l2_exit(solo_dev);
solo_disp_exit(solo_dev);
solo_gpio_exit(solo_dev);
solo_p2m_exit(solo_dev);
solo_i2c_exit(solo_dev);
/* Now cleanup the PCI device */
if (solo_dev->reg_base) {
solo6010_irq_off(solo_dev, ~0);
pci_iounmap(pdev, solo_dev->reg_base);
free_irq(pdev->irq, solo_dev);
}
pci_release_regions(pdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
kfree(solo_dev);
}
static int __devinit solo6010_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct solo6010_dev *solo_dev;
int ret;
int sdram;
u8 chip_id;
if ((solo_dev = kzalloc(sizeof(*solo_dev), GFP_KERNEL)) == NULL)
return -ENOMEM;
solo_dev->pdev = pdev;
spin_lock_init(&solo_dev->reg_io_lock);
pci_set_drvdata(pdev, solo_dev);
if ((ret = pci_enable_device(pdev)))
goto fail_probe;
pci_set_master(pdev);
if ((ret = pci_request_regions(pdev, SOLO6010_NAME)))
goto fail_probe;
if ((solo_dev->reg_base = pci_ioremap_bar(pdev, 0)) == NULL) {
ret = -ENOMEM;
goto fail_probe;
}
chip_id = solo_reg_read(solo_dev, SOLO_CHIP_OPTION) &
SOLO_CHIP_ID_MASK;
switch (chip_id) {
case 7:
solo_dev->nr_chans = 16;
solo_dev->nr_ext = 5;
break;
case 6:
solo_dev->nr_chans = 8;
solo_dev->nr_ext = 2;
break;
default:
dev_warn(&pdev->dev, "Invalid chip_id 0x%02x, "
"defaulting to 4 channels\n",
chip_id);
case 5:
solo_dev->nr_chans = 4;
solo_dev->nr_ext = 1;
}
/* Disable all interrupts to start */
solo6010_irq_off(solo_dev, ~0);
/* Initial global settings */
solo_reg_write(solo_dev, SOLO_SYS_CFG, SOLO_SYS_CFG_SDRAM64BIT |
SOLO_SYS_CFG_INPUTDIV(25) |
SOLO_SYS_CFG_FEEDBACKDIV((SOLO_CLOCK_MHZ * 2) - 2) |
SOLO_SYS_CFG_OUTDIV(3));
solo_reg_write(solo_dev, SOLO_TIMER_CLOCK_NUM, SOLO_CLOCK_MHZ - 1);
/* PLL locking time of 1ms */
mdelay(1);
ret = request_irq(pdev->irq, solo6010_isr, IRQF_SHARED, SOLO6010_NAME,
solo_dev);
if (ret)
goto fail_probe;
/* Handle this from the start */
solo6010_irq_on(solo_dev, SOLO_IRQ_PCI_ERR);
if ((ret = solo_i2c_init(solo_dev)))
goto fail_probe;
/* Setup the DMA engine */
sdram = (solo_dev->nr_chans >= 8) ? 2 : 1;
solo_reg_write(solo_dev, SOLO_DMA_CTRL,
SOLO_DMA_CTRL_REFRESH_CYCLE(1) |
SOLO_DMA_CTRL_SDRAM_SIZE(sdram) |
SOLO_DMA_CTRL_SDRAM_CLK_INVERT |
SOLO_DMA_CTRL_READ_CLK_SELECT |
SOLO_DMA_CTRL_LATENCY(1));
if ((ret = solo_p2m_init(solo_dev)))
goto fail_probe;
if ((ret = solo_disp_init(solo_dev)))
goto fail_probe;
if ((ret = solo_gpio_init(solo_dev)))
goto fail_probe;
if ((ret = solo_tw28_init(solo_dev)))
goto fail_probe;
if ((ret = solo_v4l2_init(solo_dev)))
goto fail_probe;
if ((ret = solo_enc_init(solo_dev)))
goto fail_probe;
if ((ret = solo_enc_v4l2_init(solo_dev)))
goto fail_probe;
if ((ret = solo_g723_init(solo_dev)))
goto fail_probe;
return 0;
fail_probe:
free_solo_dev(solo_dev);
return ret;
}
static void __devexit solo6010_pci_remove(struct pci_dev *pdev)
{
struct solo6010_dev *solo_dev = pci_get_drvdata(pdev);
free_solo_dev(solo_dev);
}
static struct pci_device_id solo6010_id_table[] = {
{PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6010)},
{PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_4)},
{PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_9)},
{PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_16)},
{PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_COMMSOLO_4)},
{PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_COMMSOLO_9)},
{PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_COMMSOLO_16)},
{0,}
};
MODULE_DEVICE_TABLE(pci, solo6010_id_table);
static struct pci_driver solo6010_pci_driver = {
.name = SOLO6010_NAME,
.id_table = solo6010_id_table,
.probe = solo6010_pci_probe,
.remove = solo6010_pci_remove,
};
static int __init solo6010_module_init(void)
{
return pci_register_driver(&solo6010_pci_driver);
}
static void __exit solo6010_module_exit(void)
{
pci_unregister_driver(&solo6010_pci_driver);
}
module_init(solo6010_module_init);
module_exit(solo6010_module_exit);
/*
* Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
* Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/videodev2.h>
#include <media/v4l2-ioctl.h>
#include "solo6010.h"
#define SOLO_VCLK_DELAY 3
#define SOLO_PROGRESSIVE_VSIZE 1024
#define SOLO_MOT_THRESH_W 64
#define SOLO_MOT_THRESH_H 64
#define SOLO_MOT_THRESH_SIZE 8192
#define SOLO_MOT_THRESH_REAL (SOLO_MOT_THRESH_W * SOLO_MOT_THRESH_H)
#define SOLO_MOT_FLAG_SIZE 512
#define SOLO_MOT_FLAG_AREA (SOLO_MOT_FLAG_SIZE * 32)
static unsigned video_type;
module_param(video_type, uint, 0644);
MODULE_PARM_DESC(video_type, "video_type (0 = NTSC/Default, 1 = PAL)");
static void solo_vin_config(struct solo6010_dev *solo_dev)
{
solo_dev->vin_hstart = 8;
solo_dev->vin_vstart = 2;
solo_reg_write(solo_dev, SOLO_SYS_VCLK,
SOLO_VCLK_SELECT(2) |
SOLO_VCLK_VIN1415_DELAY(SOLO_VCLK_DELAY) |
SOLO_VCLK_VIN1213_DELAY(SOLO_VCLK_DELAY) |
SOLO_VCLK_VIN1011_DELAY(SOLO_VCLK_DELAY) |
SOLO_VCLK_VIN0809_DELAY(SOLO_VCLK_DELAY) |
SOLO_VCLK_VIN0607_DELAY(SOLO_VCLK_DELAY) |
SOLO_VCLK_VIN0405_DELAY(SOLO_VCLK_DELAY) |
SOLO_VCLK_VIN0203_DELAY(SOLO_VCLK_DELAY) |
SOLO_VCLK_VIN0001_DELAY(SOLO_VCLK_DELAY));
solo_reg_write(solo_dev, SOLO_VI_ACT_I_P,
SOLO_VI_H_START(solo_dev->vin_hstart) |
SOLO_VI_V_START(solo_dev->vin_vstart) |
SOLO_VI_V_STOP(solo_dev->vin_vstart +
solo_dev->video_vsize));
solo_reg_write(solo_dev, SOLO_VI_ACT_I_S,
SOLO_VI_H_START(solo_dev->vout_hstart) |
SOLO_VI_V_START(solo_dev->vout_vstart) |
SOLO_VI_V_STOP(solo_dev->vout_vstart +
solo_dev->video_vsize));
solo_reg_write(solo_dev, SOLO_VI_ACT_P,
SOLO_VI_H_START(0) |
SOLO_VI_V_START(1) |
SOLO_VI_V_STOP(SOLO_PROGRESSIVE_VSIZE));
solo_reg_write(solo_dev, SOLO_VI_CH_FORMAT,
SOLO_VI_FD_SEL_MASK(0) | SOLO_VI_PROG_MASK(0));
solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 0);
solo_reg_write(solo_dev, SOLO_VI_PAGE_SW, 2);
if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG,
SOLO_VI_PB_USER_MODE);
solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV,
SOLO_VI_PB_HSIZE(858) | SOLO_VI_PB_VSIZE(246));
solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V,
SOLO_VI_PB_VSTART(4) |
SOLO_VI_PB_VSTOP(4 + 240));
} else {
solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG,
SOLO_VI_PB_USER_MODE | SOLO_VI_PB_PAL);
solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV,
SOLO_VI_PB_HSIZE(864) | SOLO_VI_PB_VSIZE(294));
solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V,
SOLO_VI_PB_VSTART(4) |
SOLO_VI_PB_VSTOP(4 + 288));
}
solo_reg_write(solo_dev, SOLO_VI_PB_ACT_H, SOLO_VI_PB_HSTART(16) |
SOLO_VI_PB_HSTOP(16 + 720));
}
static void solo_disp_config(struct solo6010_dev *solo_dev)
{
solo_dev->vout_hstart = 6;
solo_dev->vout_vstart = 8;
solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_COLOR,
(0xa0 << 24) | (0x88 << 16) | (0xa0 << 8) | 0x88);
solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_COLOR,
(0x10 << 24) | (0x8f << 16) | (0x10 << 8) | 0x8f);
solo_reg_write(solo_dev, SOLO_VO_BKG_COLOR,
(16 << 24) | (128 << 16) | (16 << 8) | 128);
solo_reg_write(solo_dev, SOLO_VO_FMT_ENC,
solo_dev->video_type |
SOLO_VO_USER_COLOR_SET_NAV |
SOLO_VO_NA_COLOR_Y(0) |
SOLO_VO_NA_COLOR_CB(0) |
SOLO_VO_NA_COLOR_CR(0));
solo_reg_write(solo_dev, SOLO_VO_ACT_H,
SOLO_VO_H_START(solo_dev->vout_hstart) |
SOLO_VO_H_STOP(solo_dev->vout_hstart +
solo_dev->video_hsize));
solo_reg_write(solo_dev, SOLO_VO_ACT_V,
SOLO_VO_V_START(solo_dev->vout_vstart) |
SOLO_VO_V_STOP(solo_dev->vout_vstart +
solo_dev->video_vsize));
solo_reg_write(solo_dev, SOLO_VO_RANGE_HV,
SOLO_VO_H_LEN(solo_dev->video_hsize) |
SOLO_VO_V_LEN(solo_dev->video_vsize));
solo_reg_write(solo_dev, SOLO_VI_WIN_SW, 5);
solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, SOLO_VO_DISP_ON |
SOLO_VO_DISP_ERASE_COUNT(8) |
SOLO_VO_DISP_BASE(SOLO_DISP_EXT_ADDR(solo_dev)));
solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON);
/* Enable channels we support */
solo_reg_write(solo_dev, SOLO_VI_CH_ENA, (1 << solo_dev->nr_chans) - 1);
/* Disable the watchdog */
solo_reg_write(solo_dev, SOLO_WATCHDOG, 0);
}
static int solo_dma_vin_region(struct solo6010_dev *solo_dev, u32 off,
u16 val, int reg_size)
{
u16 buf[64];
int i;
int ret = 0;
for (i = 0; i < sizeof(buf) >> 1; i++)
buf[i] = val;
for (i = 0; i < reg_size; i += sizeof(buf))
ret |= solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_VIN, 1, buf,
SOLO_MOTION_EXT_ADDR(solo_dev) + off + i,
sizeof(buf));
return ret;
}
void solo_set_motion_threshold(struct solo6010_dev *solo_dev, u8 ch, u16 val)
{
if (ch > solo_dev->nr_chans)
return;
solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA +
(ch * SOLO_MOT_THRESH_SIZE * 2),
val, SOLO_MOT_THRESH_REAL);
}
/* First 8k is motion flag (512 bytes * 16). Following that is an 8k+8k
* threshold and working table for each channel. Atleast that's what the
* spec says. However, this code (take from rdk) has some mystery 8k
* block right after the flag area, before the first thresh table. */
static void solo_motion_config(struct solo6010_dev *solo_dev)
{
int i;
for (i = 0; i < solo_dev->nr_chans; i++) {
/* Clear motion flag area */
solo_dma_vin_region(solo_dev, i * SOLO_MOT_FLAG_SIZE, 0x0000,
SOLO_MOT_FLAG_SIZE);
/* Clear working cache table */
solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA +
SOLO_MOT_THRESH_SIZE +
(i * SOLO_MOT_THRESH_SIZE * 2),
0x0000, SOLO_MOT_THRESH_REAL);
/* Set default threshold table */
solo_set_motion_threshold(solo_dev, i, SOLO_DEF_MOT_THRESH);
}
/* Default motion settings */
solo_reg_write(solo_dev, SOLO_VI_MOT_ADR, SOLO_VI_MOTION_EN(0) |
(SOLO_MOTION_EXT_ADDR(solo_dev) >> 16));
solo_reg_write(solo_dev, SOLO_VI_MOT_CTRL,
SOLO_VI_MOTION_FRAME_COUNT(3) |
SOLO_VI_MOTION_SAMPLE_LENGTH(solo_dev->video_hsize / 16)
| //SOLO_VI_MOTION_INTR_START_STOP |
SOLO_VI_MOTION_SAMPLE_COUNT(10));
solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
}
int solo_disp_init(struct solo6010_dev *solo_dev)
{
int i;
solo_dev->video_hsize = 704;
if (video_type == 0) {
solo_dev->video_type = SOLO_VO_FMT_TYPE_NTSC;
solo_dev->video_vsize = 240;
solo_dev->fps = 30;
} else {
solo_dev->video_type = SOLO_VO_FMT_TYPE_PAL;
solo_dev->video_vsize = 288;
solo_dev->fps = 25;
}
solo_vin_config(solo_dev);
solo_motion_config(solo_dev);
solo_disp_config(solo_dev);
for (i = 0; i < solo_dev->nr_chans; i++)
solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 1);
return 0;
}
void solo_disp_exit(struct solo6010_dev *solo_dev)
{
int i;
solo6010_irq_off(solo_dev, SOLO_IRQ_MOTION);
solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, 0);
solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0);
solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0);
for (i = 0; i < solo_dev->nr_chans; i++) {
solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(i), 0);
solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(i), 0);
solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 0);
}
/* Set default border */
for (i = 0; i < 5; i++)
solo_reg_write(solo_dev, SOLO_VO_BORDER_X(i), 0);
for (i = 0; i < 5; i++)
solo_reg_write(solo_dev, SOLO_VO_BORDER_Y(i), 0);
solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_MASK, 0);
solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_MASK, 0);
solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(0), 0);
solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(0), 0);
solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(0), 0);
solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(1), 0);
solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(1), 0);
solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(1), 0);
}
/*
* Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
* Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/kernel.h>
#include "solo6010.h"
#include "solo6010-osd-font.h"
#define CAPTURE_MAX_BANDWIDTH 32 // D1 4channel (D1 == 4)
#define OSG_BUFFER_SIZE 1024
#define VI_PROG_HSIZE (1280 - 16)
#define VI_PROG_VSIZE (1024 - 16)
static void solo_capture_config(struct solo6010_dev *solo_dev)
{
int i, j;
unsigned long height;
unsigned long width;
unsigned char *buf;
solo_reg_write(solo_dev, SOLO_CAP_BASE,
SOLO_CAP_MAX_PAGE(SOLO_CAP_EXT_MAX_PAGE *
solo_dev->nr_chans) |
SOLO_CAP_BASE_ADDR(SOLO_CAP_EXT_ADDR(solo_dev) >> 16));
solo_reg_write(solo_dev, SOLO_CAP_BTW,
(1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) |
SOLO_CAP_MAX_BANDWIDTH(CAPTURE_MAX_BANDWIDTH));
/* Set scale 1, 9 dimension */
width = solo_dev->video_hsize;
height = solo_dev->video_vsize;
solo_reg_write(solo_dev, SOLO_DIM_SCALE1,
SOLO_DIM_H_MB_NUM(width / 16) |
SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
SOLO_DIM_V_MB_NUM_FIELD(height / 16));
/* Set scale 2, 10 dimension */
width = solo_dev->video_hsize / 2;
height = solo_dev->video_vsize;
solo_reg_write(solo_dev, SOLO_DIM_SCALE2,
SOLO_DIM_H_MB_NUM(width / 16) |
SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
SOLO_DIM_V_MB_NUM_FIELD(height / 16));
/* Set scale 3, 11 dimension */
width = solo_dev->video_hsize / 2;
height = solo_dev->video_vsize / 2;
solo_reg_write(solo_dev, SOLO_DIM_SCALE3,
SOLO_DIM_H_MB_NUM(width / 16) |
SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
SOLO_DIM_V_MB_NUM_FIELD(height / 16));
/* Set scale 4, 12 dimension */
width = solo_dev->video_hsize / 3;
height = solo_dev->video_vsize / 3;
solo_reg_write(solo_dev, SOLO_DIM_SCALE4,
SOLO_DIM_H_MB_NUM(width / 16) |
SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
SOLO_DIM_V_MB_NUM_FIELD(height / 16));
/* Set scale 5, 13 dimension */
width = solo_dev->video_hsize / 4;
height = solo_dev->video_vsize / 2;
solo_reg_write(solo_dev, SOLO_DIM_SCALE5,
SOLO_DIM_H_MB_NUM(width / 16) |
SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
SOLO_DIM_V_MB_NUM_FIELD(height / 16));
/* Progressive */
width = VI_PROG_HSIZE;
height = VI_PROG_VSIZE;
solo_reg_write(solo_dev, SOLO_DIM_PROG,
SOLO_DIM_H_MB_NUM(width / 16) |
SOLO_DIM_V_MB_NUM_FRAME(height / 16) |
SOLO_DIM_V_MB_NUM_FIELD(height / 16));
/* Clear OSD */
solo_reg_write(solo_dev, SOLO_VE_OSD_CH, 0);
solo_reg_write(solo_dev, SOLO_VE_OSD_BASE,
SOLO_EOSD_EXT_ADDR(solo_dev) >> 16);
solo_reg_write(solo_dev, SOLO_VE_OSD_CLR,
0xF0 << 16 | 0x80 << 8 | 0x80);
solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, 0);
/* Clear OSG buffer */
buf = kzalloc(OSG_BUFFER_SIZE, GFP_KERNEL);
if (!buf)
return;
for (i = 0; i < solo_dev->nr_chans; i++) {
for (j = 0; j < SOLO_EOSD_EXT_SIZE; j += OSG_BUFFER_SIZE) {
solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_MP4E, 1, buf,
SOLO_EOSD_EXT_ADDR(solo_dev) +
(i * SOLO_EOSD_EXT_SIZE) + j,
OSG_BUFFER_SIZE);
}
}
kfree(buf);
}
int solo_osd_print(struct solo_enc_dev *solo_enc)
{
struct solo6010_dev *solo_dev = solo_enc->solo_dev;
char *str = solo_enc->osd_text;
u8 *buf;
u32 reg = solo_reg_read(solo_dev, SOLO_VE_OSD_CH);
int len = strlen(str);
int i, j;
int x = 1, y = 1;
if (len == 0) {
reg &= ~(1 << solo_enc->ch);
solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg);
return 0;
}
buf = kzalloc(SOLO_EOSD_EXT_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
for (i = 0; i < len; i++) {
for (j = 0; j < 16; j++) {
buf[(j*2) + (i%2) + ((x + (i/2)) * 32) + (y * 2048)] =
(solo_osd_font[(str[i] * 4) + (j / 4)]
>> ((3 - (j % 4)) * 8)) & 0xff;
}
}
solo_p2m_dma(solo_dev, 0, 1, buf, SOLO_EOSD_EXT_ADDR(solo_dev) +
(solo_enc->ch * SOLO_EOSD_EXT_SIZE), SOLO_EOSD_EXT_SIZE);
reg |= (1 << solo_enc->ch);
solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg);
kfree(buf);
return 0;
}
static void solo_jpeg_config(struct solo6010_dev *solo_dev)
{
solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL,
(2 << 24) | (2 << 16) | (2 << 8) | (2 << 0));
solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_L, 0);
solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_H, 0);
solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG,
(SOLO_JPEG_EXT_SIZE(solo_dev) & 0xffff0000) |
((SOLO_JPEG_EXT_ADDR(solo_dev) >> 16) & 0x0000ffff));
solo_reg_write(solo_dev, SOLO_VE_JPEG_CTRL, 0xffffffff);
}
static void solo_mp4e_config(struct solo6010_dev *solo_dev)
{
int i;
/* We can only use VE_INTR_CTRL(0) if we want to support mjpeg */
solo_reg_write(solo_dev, SOLO_VE_CFG0,
SOLO_VE_INTR_CTRL(0) |
SOLO_VE_BLOCK_SIZE(SOLO_MP4E_EXT_SIZE(solo_dev) >> 16) |
SOLO_VE_BLOCK_BASE(SOLO_MP4E_EXT_ADDR(solo_dev) >> 16));
solo_reg_write(solo_dev, SOLO_VE_CFG1,
SOLO_VE_BYTE_ALIGN(2) |
SOLO_VE_INSERT_INDEX | SOLO_VE_MOTION_MODE(0));
solo_reg_write(solo_dev, SOLO_VE_WMRK_POLY, 0);
solo_reg_write(solo_dev, SOLO_VE_VMRK_INIT_KEY, 0);
solo_reg_write(solo_dev, SOLO_VE_WMRK_STRL, 0);
solo_reg_write(solo_dev, SOLO_VE_ENCRYP_POLY, 0);
solo_reg_write(solo_dev, SOLO_VE_ENCRYP_INIT, 0);
solo_reg_write(solo_dev, SOLO_VE_ATTR,
SOLO_VE_LITTLE_ENDIAN |
SOLO_COMP_ATTR_FCODE(1) |
SOLO_COMP_TIME_INC(0) |
SOLO_COMP_TIME_WIDTH(15) |
SOLO_DCT_INTERVAL(36 / 4));
for (i = 0; i < solo_dev->nr_chans; i++)
solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE(i),
(SOLO_EREF_EXT_ADDR(solo_dev) +
(i * SOLO_EREF_EXT_SIZE)) >> 16);
}
int solo_enc_init(struct solo6010_dev *solo_dev)
{
int i;
solo_capture_config(solo_dev);
solo_mp4e_config(solo_dev);
solo_jpeg_config(solo_dev);
for (i = 0; i < solo_dev->nr_chans; i++) {
solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0);
solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0);
}
solo6010_irq_on(solo_dev, SOLO_IRQ_ENCODER);
return 0;
}
void solo_enc_exit(struct solo6010_dev *solo_dev)
{
int i;
solo6010_irq_off(solo_dev, SOLO_IRQ_ENCODER);
for (i = 0; i < solo_dev->nr_chans; i++) {
solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0);
solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0);
}
}
This diff is collapsed.
/*
* Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
* Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include "solo6010.h"
static void solo_gpio_mode(struct solo6010_dev *solo_dev,
unsigned int port_mask, unsigned int mode)
{
int port;
unsigned int ret;
ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_0);
/* To set gpio */
for (port = 0; port < 16; port++) {
if (!((1 << port) & port_mask))
continue;
ret &= (~(3 << (port << 1)));
ret |= ((mode & 3) << (port << 1));
}
solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_0, ret);
/* To set extended gpio - sensor */
ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_1);
for (port = 0; port < 16; port++) {
if (!((1 << (port + 16)) & port_mask))
continue;
if (!mode)
ret &= ~(1 << port);
else
ret |= 1 << port;
}
solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_1, ret);
}
static void solo_gpio_set(struct solo6010_dev *solo_dev, unsigned int value)
{
solo_reg_write(solo_dev, SOLO_GPIO_DATA_OUT,
solo_reg_read(solo_dev, SOLO_GPIO_DATA_OUT) | value);
}
static void solo_gpio_clear(struct solo6010_dev *solo_dev, unsigned int value)
{
solo_reg_write(solo_dev, SOLO_GPIO_DATA_OUT,
solo_reg_read(solo_dev, SOLO_GPIO_DATA_OUT) & ~value);
}
static void solo_gpio_config(struct solo6010_dev *solo_dev)
{
/* Video reset */
solo_gpio_mode(solo_dev, 0x30, 1);
solo_gpio_clear(solo_dev, 0x30);
udelay(100);
solo_gpio_set(solo_dev, 0x30);
udelay(100);
/* Warning: Don't touch the next line unless you're sure of what
* you're doing: first four gpio [0-3] are used for video. */
solo_gpio_mode(solo_dev, 0x0f, 2);
/* We use bit 8-15 of SOLO_GPIO_CONFIG_0 for relay purposes */
solo_gpio_mode(solo_dev, 0xff00, 1);
/* Initially set relay status to 0 */
solo_gpio_clear(solo_dev, 0xff00);
}
int solo_gpio_init(struct solo6010_dev *solo_dev)
{
solo_gpio_config(solo_dev);
return 0;
}
void solo_gpio_exit(struct solo6010_dev *solo_dev)
{
solo_gpio_clear(solo_dev, 0x30);
solo_gpio_config(solo_dev);
}
/*
* Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
* Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* XXX: The SOLO6010 i2c does not have separate interrupts for each i2c
* channel. The bus can only handle one i2c event at a time. The below handles
* this all wrong. We should be using the status registers to see if the bus
* is in use, and have a global lock to check the status register. Also,
* the bulk of the work should be handled out-of-interrupt. The ugly loops
* that occur during interrupt scare me. The ISR should merely signal
* thread context, ACK the interrupt, and move on. -- BenC */
#include <linux/kernel.h>
#include "solo6010.h"
u8 solo_i2c_readbyte(struct solo6010_dev *solo_dev, int id, u8 addr, u8 off)
{
struct i2c_msg msgs[2];
u8 data;
msgs[0].flags = 0;
msgs[0].addr = addr;
msgs[0].len = 1;
msgs[0].buf = &off;
msgs[1].flags = I2C_M_RD;
msgs[1].addr = addr;
msgs[1].len = 1;
msgs[1].buf = &data;
i2c_transfer(&solo_dev->i2c_adap[id], msgs, 2);
return data;
}
void solo_i2c_writebyte(struct solo6010_dev *solo_dev, int id, u8 addr,
u8 off, u8 data)
{
struct i2c_msg msgs;
u8 buf[2];
buf[0] = off;
buf[1] = data;
msgs.flags = 0;
msgs.addr = addr;
msgs.len = 2;
msgs.buf = buf;
i2c_transfer(&solo_dev->i2c_adap[id], &msgs, 1);
}
static void solo_i2c_flush(struct solo6010_dev *solo_dev, int wr)
{
u32 ctrl;
ctrl = SOLO_IIC_CH_SET(solo_dev->i2c_id);
if (solo_dev->i2c_state == IIC_STATE_START)
ctrl |= SOLO_IIC_START;
if (wr) {
ctrl |= SOLO_IIC_WRITE;
} else {
ctrl |= SOLO_IIC_READ;
if (!(solo_dev->i2c_msg->flags & I2C_M_NO_RD_ACK))
ctrl |= SOLO_IIC_ACK_EN;
}
if (solo_dev->i2c_msg_ptr == solo_dev->i2c_msg->len)
ctrl |= SOLO_IIC_STOP;
solo_reg_write(solo_dev, SOLO_IIC_CTRL, ctrl);
}
static void solo_i2c_start(struct solo6010_dev *solo_dev)
{
u32 addr = solo_dev->i2c_msg->addr << 1;
if (solo_dev->i2c_msg->flags & I2C_M_RD)
addr |= 1;
solo_dev->i2c_state = IIC_STATE_START;
solo_reg_write(solo_dev, SOLO_IIC_TXD, addr);
solo_i2c_flush(solo_dev, 1);
}
static void solo_i2c_stop(struct solo6010_dev *solo_dev)
{
solo6010_irq_off(solo_dev, SOLO_IRQ_IIC);
solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0);
solo_dev->i2c_state = IIC_STATE_STOP;
wake_up(&solo_dev->i2c_wait);
}
static int solo_i2c_handle_read(struct solo6010_dev *solo_dev)
{
prepare_read:
if (solo_dev->i2c_msg_ptr != solo_dev->i2c_msg->len) {
solo_i2c_flush(solo_dev, 0);
return 0;
}
solo_dev->i2c_msg_ptr = 0;
solo_dev->i2c_msg++;
solo_dev->i2c_msg_num--;
if (solo_dev->i2c_msg_num == 0) {
solo_i2c_stop(solo_dev);
return 0;
}
if (!(solo_dev->i2c_msg->flags & I2C_M_NOSTART)) {
solo_i2c_start(solo_dev);
} else {
if (solo_dev->i2c_msg->flags & I2C_M_RD)
goto prepare_read;
else
solo_i2c_stop(solo_dev);
}
return 0;
}
static int solo_i2c_handle_write(struct solo6010_dev *solo_dev)
{
retry_write:
if (solo_dev->i2c_msg_ptr != solo_dev->i2c_msg->len) {
solo_reg_write(solo_dev, SOLO_IIC_TXD,
solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr]);
solo_dev->i2c_msg_ptr++;
solo_i2c_flush(solo_dev, 1);
return 0;
}
solo_dev->i2c_msg_ptr = 0;
solo_dev->i2c_msg++;
solo_dev->i2c_msg_num--;
if (solo_dev->i2c_msg_num == 0) {
solo_i2c_stop(solo_dev);
return 0;
}
if (!(solo_dev->i2c_msg->flags & I2C_M_NOSTART)) {
solo_i2c_start(solo_dev);
} else {
if (solo_dev->i2c_msg->flags & I2C_M_RD)
solo_i2c_stop(solo_dev);
else
goto retry_write;
}
return 0;
}
int solo_i2c_isr(struct solo6010_dev *solo_dev)
{
u32 status = solo_reg_read(solo_dev, SOLO_IIC_CTRL);
int ret = -EINVAL;
solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_IIC);
if (status & (SOLO_IIC_STATE_TRNS & SOLO_IIC_STATE_SIG_ERR) ||
solo_dev->i2c_id < 0) {
solo_i2c_stop(solo_dev);
return -ENXIO;
}
switch (solo_dev->i2c_state) {
case IIC_STATE_START:
if (solo_dev->i2c_msg->flags & I2C_M_RD) {
solo_dev->i2c_state = IIC_STATE_READ;
ret = solo_i2c_handle_read(solo_dev);
break;
}
solo_dev->i2c_state = IIC_STATE_WRITE;
case IIC_STATE_WRITE:
ret = solo_i2c_handle_write(solo_dev);
break;
case IIC_STATE_READ:
solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr] =
solo_reg_read(solo_dev, SOLO_IIC_RXD);
solo_dev->i2c_msg_ptr++;
ret = solo_i2c_handle_read(solo_dev);
break;
default:
solo_i2c_stop(solo_dev);
}
return ret;
}
static int solo_i2c_master_xfer(struct i2c_adapter *adap,
struct i2c_msg msgs[], int num)
{
struct solo6010_dev *solo_dev = adap->algo_data;
unsigned long timeout;
int ret;
int i;
DEFINE_WAIT(wait);
for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
if (&solo_dev->i2c_adap[i] == adap)
break;
}
if (i == SOLO_I2C_ADAPTERS)
return num; // XXX Right return value for failure?
down(&solo_dev->i2c_sem);
solo_dev->i2c_id = i;
solo_dev->i2c_msg = msgs;
solo_dev->i2c_msg_num = num;
solo_dev->i2c_msg_ptr = 0;
solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0);
solo6010_irq_on(solo_dev, SOLO_IRQ_IIC);
solo_i2c_start(solo_dev);
timeout = HZ / 2;
for (;;) {
prepare_to_wait(&solo_dev->i2c_wait, &wait, TASK_INTERRUPTIBLE);
if (solo_dev->i2c_state == IIC_STATE_STOP)
break;
timeout = schedule_timeout(timeout);
if (!timeout)
break;
if (signal_pending(current))
break;
}
finish_wait(&solo_dev->i2c_wait, &wait);
ret = num - solo_dev->i2c_msg_num;
solo_dev->i2c_state = IIC_STATE_IDLE;
solo_dev->i2c_id = -1;
up(&solo_dev->i2c_sem);
return ret;
}
static u32 solo_i2c_functionality(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C;
}
static struct i2c_algorithm solo_i2c_algo = {
.master_xfer = solo_i2c_master_xfer,
.functionality = solo_i2c_functionality,
};
int solo_i2c_init(struct solo6010_dev *solo_dev)
{
int i;
int ret;
solo_reg_write(solo_dev, SOLO_IIC_CFG,
SOLO_IIC_PRESCALE(8) | SOLO_IIC_ENABLE);
solo_dev->i2c_id = -1;
solo_dev->i2c_state = IIC_STATE_IDLE;
init_waitqueue_head(&solo_dev->i2c_wait);
init_MUTEX(&solo_dev->i2c_sem);
for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
struct i2c_adapter *adap = &solo_dev->i2c_adap[i];
snprintf(adap->name, I2C_NAME_SIZE, "%s I2C %d",
SOLO6010_NAME, i);
adap->algo = &solo_i2c_algo;
adap->algo_data = solo_dev;
adap->retries = 1;
adap->dev.parent = &solo_dev->pdev->dev;
if ((ret = i2c_add_adapter(adap))) {
adap->algo_data = NULL;
break;
}
}
if (ret) {
for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
if (!solo_dev->i2c_adap[i].algo_data)
break;
i2c_del_adapter(&solo_dev->i2c_adap[i]);
solo_dev->i2c_adap[i].algo_data = NULL;
}
return ret;
}
dev_info(&solo_dev->pdev->dev, "Enabled %d i2c adapters\n",
SOLO_I2C_ADAPTERS);
return 0;
}
void solo_i2c_exit(struct solo6010_dev *solo_dev)
{
int i;
for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
if (!solo_dev->i2c_adap[i].algo_data)
continue;
i2c_del_adapter(&solo_dev->i2c_adap[i]);
solo_dev->i2c_adap[i].algo_data = NULL;
}
}
/*
* Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
* Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __SOLO6010_JPEG_H
#define __SOLO6010_JPEG_H
static unsigned char jpeg_header[] = {
0xff, 0xd8, 0xff, 0xfe, 0x00, 0x0d, 0x42, 0x6c,
0x75, 0x65, 0x63, 0x68, 0x65, 0x72, 0x72, 0x79,
0x20, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x20, 0x16,
0x18, 0x1c, 0x18, 0x14, 0x20, 0x1c, 0x1a, 0x1c,
0x24, 0x22, 0x20, 0x26, 0x30, 0x50, 0x34, 0x30,
0x2c, 0x2c, 0x30, 0x62, 0x46, 0x4a, 0x3a, 0x50,
0x74, 0x66, 0x7a, 0x78, 0x72, 0x66, 0x70, 0x6e,
0x80, 0x90, 0xb8, 0x9c, 0x80, 0x88, 0xae, 0x8a,
0x6e, 0x70, 0xa0, 0xda, 0xa2, 0xae, 0xbe, 0xc4,
0xce, 0xd0, 0xce, 0x7c, 0x9a, 0xe2, 0xf2, 0xe0,
0xc8, 0xf0, 0xb8, 0xca, 0xce, 0xc6, 0xff, 0xdb,
0x00, 0x43, 0x01, 0x22, 0x24, 0x24, 0x30, 0x2a,
0x30, 0x5e, 0x34, 0x34, 0x5e, 0xc6, 0x84, 0x70,
0x84, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
0xc6, 0xc6, 0xc6, 0xff, 0xc4, 0x01, 0xa2, 0x00,
0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01,
0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04,
0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03,
0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41,
0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14,
0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1,
0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62,
0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19,
0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34,
0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44,
0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54,
0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74,
0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84,
0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93,
0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2,
0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5,
0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3,
0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x01,
0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x11, 0x00, 0x02, 0x01,
0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04,
0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02,
0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12,
0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32,
0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1,
0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72,
0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1,
0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29,
0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43,
0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53,
0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63,
0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73,
0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82,
0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6,
0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5,
0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4,
0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3,
0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff,
0xc0, 0x00, 0x11, 0x08, 0x00, 0xf0, 0x02, 0xc0,
0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03,
0x11, 0x01, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01,
0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
};
/* This is the byte marker for the start of SOF0: 0xffc0 marker */
#define SOF0_START 575
#endif /* __SOLO6010_JPEG_H */
/*
* Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
* Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __SOLO6010_OFFSETS_H
#define __SOLO6010_OFFSETS_H
/* Offsets and sizes of the external address */
#define SOLO_DISP_EXT_ADDR(__solo) 0x00000000
#define SOLO_DISP_EXT_SIZE 0x00480000
#define SOLO_DEC2LIVE_EXT_ADDR(__solo) \
(SOLO_DISP_EXT_ADDR(__solo) + SOLO_DISP_EXT_SIZE)
#define SOLO_DEC2LIVE_EXT_SIZE 0x00240000
#define SOLO_OSG_EXT_ADDR(__solo) \
(SOLO_DEC2LIVE_EXT_ADDR(__solo) + SOLO_DEC2LIVE_EXT_SIZE)
#define SOLO_OSG_EXT_SIZE 0x00120000
#define SOLO_EOSD_EXT_ADDR(__solo) \
(SOLO_OSG_EXT_ADDR(__solo) + SOLO_OSG_EXT_SIZE)
#define SOLO_EOSD_EXT_SIZE 0x00010000
#define SOLO_MOTION_EXT_ADDR(__solo) \
(SOLO_EOSD_EXT_ADDR(__solo) + \
(SOLO_EOSD_EXT_SIZE * __solo->nr_chans))
#define SOLO_MOTION_EXT_SIZE 0x00080000
#define SOLO_G723_EXT_ADDR(__solo) \
(SOLO_MOTION_EXT_ADDR(__solo) + SOLO_MOTION_EXT_SIZE)
#define SOLO_G723_EXT_SIZE 0x00010000
#define SOLO_CAP_EXT_ADDR(__solo) \
(SOLO_G723_EXT_ADDR(__solo) + SOLO_G723_EXT_SIZE)
#define SOLO_CAP_EXT_MAX_PAGE (18 + 15)
#define SOLO_CAP_EXT_SIZE (SOLO_CAP_EXT_MAX_PAGE * 65536)
/* This +1 is very important -- Why?! -- BenC */
#define SOLO_EREF_EXT_ADDR(__solo) \
(SOLO_CAP_EXT_ADDR(__solo) + \
(SOLO_CAP_EXT_SIZE * (__solo->nr_chans + 1)))
#define SOLO_EREF_EXT_SIZE 0x00140000
#define SOLO_MP4E_EXT_ADDR(__solo) \
(SOLO_EREF_EXT_ADDR(__solo) + \
(SOLO_EREF_EXT_SIZE * __solo->nr_chans))
#define SOLO_MP4E_EXT_SIZE(__solo) (0x00080000 * __solo->nr_chans)
#define SOLO_DREF_EXT_ADDR(__solo) \
(SOLO_MP4E_EXT_ADDR(__solo) + SOLO_MP4E_EXT_SIZE(__solo))
#define SOLO_DREF_EXT_SIZE 0x00140000
#define SOLO_MP4D_EXT_ADDR(__solo) \
(SOLO_DREF_EXT_ADDR(__solo) + \
(SOLO_DREF_EXT_SIZE * __solo->nr_chans))
#define SOLO_MP4D_EXT_SIZE 0x00080000
#define SOLO_JPEG_EXT_ADDR(__solo) \
(SOLO_MP4D_EXT_ADDR(__solo) + \
(SOLO_MP4D_EXT_SIZE * __solo->nr_chans))
#define SOLO_JPEG_EXT_SIZE(__solo) (0x00080000 * __solo->nr_chans)
#endif /* __SOLO6010_OFFSETS_H */
/*
* Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
* Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __SOLO6010_OSD_FONT_H
#define __SOLO6010_OSD_FONT_H
static const unsigned int solo_osd_font[] = {
0x00000000, 0x0000c0c8, 0xccfefe0c, 0x08000000,
0x00000000, 0x10103838, 0x7c7cfefe, 0x00000000, // 0
0x00000000, 0xfefe7c7c, 0x38381010, 0x10000000,
0x00000000, 0x7c82fefe, 0xfefefe7c, 0x00000000,
0x00000000, 0x00001038, 0x10000000, 0x00000000,
0x00000000, 0x0010387c, 0xfe7c3810, 0x00000000,
0x00000000, 0x00384444, 0x44380000, 0x00000000,
0x00000000, 0x38448282, 0x82443800, 0x00000000,
0x00000000, 0x007c7c7c, 0x7c7c0000, 0x00000000,
0x00000000, 0x6c6c6c6c, 0x6c6c6c6c, 0x00000000,
0x00000000, 0x061e7efe, 0xfe7e1e06, 0x00000000,
0x00000000, 0xc0f0fcfe, 0xfefcf0c0, 0x00000000,
0x00000000, 0xc6cedefe, 0xfedecec6, 0x00000000,
0x00000000, 0xc6e6f6fe, 0xfef6e6c6, 0x00000000,
0x00000000, 0x12367efe, 0xfe7e3612, 0x00000000,
0x00000000, 0x90d8fcfe, 0xfefcd890, 0x00000000,
0x00000038, 0x7cc692ba, 0x92c67c38, 0x00000000,
0x00000038, 0x7cc6aa92, 0xaac67c38, 0x00000000,
0x00000038, 0x7830107c, 0xbaa8680c, 0x00000000,
0x00000038, 0x3c18127c, 0xb8382c60, 0x00000000,
0x00000044, 0xaa6c8254, 0x38eec67c, 0x00000000,
0x00000082, 0x44288244, 0x38c6827c, 0x00000000,
0x00000038, 0x444444fe, 0xfeeec6fe, 0x00000000,
0x00000018, 0x78187818, 0x3c7e7e3c, 0x00000000,
0x00000000, 0x3854929a, 0x82443800, 0x00000000,
0x00000000, 0x00c0c8cc, 0xfefe0c08, 0x00000000,
0x0000e0a0, 0xe040e00e, 0x8a0ea40e, 0x00000000,
0x0000e0a0, 0xe040e00e, 0x0a8e440e, 0x00000000,
0x0000007c, 0x82829292, 0x929282fe, 0x00000000,
0x000000f8, 0xfc046494, 0x946404fc, 0x00000000,
0x0000003f, 0x7f404c52, 0x524c407f, 0x00000000,
0x0000007c, 0x82ba82ba, 0x82ba82fe, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x183c3c3c, 0x18180018, 0x18000000, // 32 !
0x00000066, 0x66240000, 0x00000000, 0x00000000,
0x00000000, 0x6c6cfe6c, 0x6c6cfe6c, 0x6c000000, // 34 " #
0x00001010, 0x7cd6d616, 0x7cd0d6d6, 0x7c101000,
0x00000000, 0x0086c660, 0x30180cc6, 0xc2000000, // 36 $ %
0x00000000, 0x386c6c38, 0xdc766666, 0xdc000000,
0x0000000c, 0x0c0c0600, 0x00000000, 0x00000000, // 38 & '
0x00000000, 0x30180c0c, 0x0c0c0c18, 0x30000000,
0x00000000, 0x0c183030, 0x30303018, 0x0c000000, // 40 ( )
0x00000000, 0x0000663c, 0xff3c6600, 0x00000000,
0x00000000, 0x00001818, 0x7e181800, 0x00000000, // 42 * +
0x00000000, 0x00000000, 0x00000e0e, 0x0c060000,
0x00000000, 0x00000000, 0x7e000000, 0x00000000, // 44 , -
0x00000000, 0x00000000, 0x00000006, 0x06000000,
0x00000000, 0x80c06030, 0x180c0602, 0x00000000, // 46 . /
0x0000007c, 0xc6e6f6de, 0xcec6c67c, 0x00000000,
0x00000030, 0x383c3030, 0x303030fc, 0x00000000, // 48 0 1
0x0000007c, 0xc6c06030, 0x180cc6fe, 0x00000000,
0x0000007c, 0xc6c0c07c, 0xc0c0c67c, 0x00000000, // 50 2 3
0x00000060, 0x70786c66, 0xfe6060f0, 0x00000000,
0x000000fe, 0x0606067e, 0xc0c0c67c, 0x00000000, // 52 4 5
0x00000038, 0x0c06067e, 0xc6c6c67c, 0x00000000,
0x000000fe, 0xc6c06030, 0x18181818, 0x00000000, // 54 6 7
0x0000007c, 0xc6c6c67c, 0xc6c6c67c, 0x00000000,
0x0000007c, 0xc6c6c6fc, 0xc0c06038, 0x00000000, // 56 8 9
0x00000000, 0x18180000, 0x00181800, 0x00000000,
0x00000000, 0x18180000, 0x0018180c, 0x00000000, // 58 : ;
0x00000060, 0x30180c06, 0x0c183060, 0x00000000,
0x00000000, 0x007e0000, 0x007e0000, 0x00000000,
0x00000006, 0x0c183060, 0x30180c06, 0x00000000,
0x0000007c, 0xc6c66030, 0x30003030, 0x00000000,
0x0000007c, 0xc6f6d6d6, 0x7606067c, 0x00000000,
0x00000010, 0x386cc6c6, 0xfec6c6c6, 0x00000000, // 64 @ A
0x0000007e, 0xc6c6c67e, 0xc6c6c67e, 0x00000000,
0x00000078, 0xcc060606, 0x0606cc78, 0x00000000, // 66
0x0000003e, 0x66c6c6c6, 0xc6c6663e, 0x00000000,
0x000000fe, 0x0606063e, 0x060606fe, 0x00000000, // 68
0x000000fe, 0x0606063e, 0x06060606, 0x00000000,
0x00000078, 0xcc060606, 0xf6c6ccb8, 0x00000000, // 70
0x000000c6, 0xc6c6c6fe, 0xc6c6c6c6, 0x00000000,
0x0000003c, 0x18181818, 0x1818183c, 0x00000000, // 72
0x00000060, 0x60606060, 0x6066663c, 0x00000000,
0x000000c6, 0xc666361e, 0x3666c6c6, 0x00000000, // 74
0x00000006, 0x06060606, 0x060606fe, 0x00000000,
0x000000c6, 0xeefed6c6, 0xc6c6c6c6, 0x00000000, // 76
0x000000c6, 0xcedefef6, 0xe6c6c6c6, 0x00000000,
0x00000038, 0x6cc6c6c6, 0xc6c66c38, 0x00000000, // 78
0x0000007e, 0xc6c6c67e, 0x06060606, 0x00000000,
0x00000038, 0x6cc6c6c6, 0xc6d67c38, 0x60000000, // 80
0x0000007e, 0xc6c6c67e, 0x66c6c6c6, 0x00000000,
0x0000007c, 0xc6c60c38, 0x60c6c67c, 0x00000000, // 82
0x0000007e, 0x18181818, 0x18181818, 0x00000000,
0x000000c6, 0xc6c6c6c6, 0xc6c6c67c, 0x00000000, // 84
0x000000c6, 0xc6c6c6c6, 0xc66c3810, 0x00000000,
0x000000c6, 0xc6c6c6c6, 0xd6d6fe6c, 0x00000000, // 86
0x000000c6, 0xc6c66c38, 0x6cc6c6c6, 0x00000000,
0x00000066, 0x66666666, 0x3c181818, 0x00000000, // 88
0x000000fe, 0xc0603018, 0x0c0606fe, 0x00000000,
0x0000003c, 0x0c0c0c0c, 0x0c0c0c3c, 0x00000000, // 90
0x00000002, 0x060c1830, 0x60c08000, 0x00000000,
0x0000003c, 0x30303030, 0x3030303c, 0x00000000, // 92
0x00001038, 0x6cc60000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00fe0000,
0x00001818, 0x30000000, 0x00000000, 0x00000000,
0x00000000, 0x00003c60, 0x7c66667c, 0x00000000,
0x0000000c, 0x0c0c7ccc, 0xcccccc7c, 0x00000000,
0x00000000, 0x00007cc6, 0x0606c67c, 0x00000000,
0x00000060, 0x60607c66, 0x6666667c, 0x00000000,
0x00000000, 0x00007cc6, 0xfe06c67c, 0x00000000,
0x00000078, 0x0c0c0c3e, 0x0c0c0c0c, 0x00000000,
0x00000000, 0x00007c66, 0x6666667c, 0x60603e00,
0x0000000c, 0x0c0c7ccc, 0xcccccccc, 0x00000000,
0x00000030, 0x30003830, 0x30303078, 0x00000000,
0x00000030, 0x30003c30, 0x30303030, 0x30301f00,
0x0000000c, 0x0c0ccc6c, 0x3c6ccccc, 0x00000000,
0x00000030, 0x30303030, 0x30303030, 0x00000000,
0x00000000, 0x000066fe, 0xd6d6d6d6, 0x00000000,
0x00000000, 0x000078cc, 0xcccccccc, 0x00000000,
0x00000000, 0x00007cc6, 0xc6c6c67c, 0x00000000,
0x00000000, 0x00007ccc, 0xcccccc7c, 0x0c0c0c00,
0x00000000, 0x00007c66, 0x6666667c, 0x60606000,
0x00000000, 0x000076dc, 0x0c0c0c0c, 0x00000000,
0x00000000, 0x00007cc6, 0x1c70c67c, 0x00000000,
0x00000000, 0x1818fe18, 0x18181870, 0x00000000,
0x00000000, 0x00006666, 0x6666663c, 0x00000000,
0x00000000, 0x0000c6c6, 0xc66c3810, 0x00000000,
0x00000000, 0x0000c6d6, 0xd6d6fe6c, 0x00000000,
0x00000000, 0x0000c66c, 0x38386cc6, 0x00000000,
0x00000000, 0x00006666, 0x6666667c, 0x60603e00,
0x00000000, 0x0000fe60, 0x30180cfe, 0x00000000,
0x00000070, 0x1818180e, 0x18181870, 0x00000000,
0x00000018, 0x18181800, 0x18181818, 0x00000000,
0x0000000e, 0x18181870, 0x1818180e, 0x00000000,
0x000000dc, 0x76000000, 0x00000000, 0x00000000,
0x00000000, 0x0010386c, 0xc6c6fe00, 0x00000000
};
#endif /* __SOLO6010_OSD_FONT_H */
/*
* Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
* Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/kernel.h>
#include "solo6010.h"
// #define SOLO_TEST_P2M
int solo_p2m_dma(struct solo6010_dev *solo_dev, u8 id, int wr,
void *sys_addr, u32 ext_addr, u32 size)
{
dma_addr_t dma_addr;
int ret;
WARN_ON(!size);
WARN_ON(id >= SOLO_NR_P2M);
if (!size || id >= SOLO_NR_P2M)
return -EINVAL;
dma_addr = pci_map_single(solo_dev->pdev, sys_addr, size,
wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
ret = solo_p2m_dma_t(solo_dev, id, wr, dma_addr, ext_addr, size);
pci_unmap_single(solo_dev->pdev, dma_addr, size,
wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
return ret;
}
int solo_p2m_dma_t(struct solo6010_dev *solo_dev, u8 id, int wr,
dma_addr_t dma_addr, u32 ext_addr, u32 size)
{
struct solo_p2m_dev *p2m_dev;
unsigned int timeout = 0;
WARN_ON(!size);
WARN_ON(id >= SOLO_NR_P2M);
if (!size || id >= SOLO_NR_P2M)
return -EINVAL;
p2m_dev = &solo_dev->p2m_dev[id];
down(&p2m_dev->sem);
start_dma:
INIT_COMPLETION(p2m_dev->completion);
p2m_dev->error = 0;
solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(id), dma_addr);
solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(id), ext_addr);
solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(id),
SOLO_P2M_COPY_SIZE(size >> 2));
solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id),
SOLO_P2M_BURST_SIZE(SOLO_P2M_BURST_256) |
(wr ? SOLO_P2M_WRITE : 0) | SOLO_P2M_TRANS_ON);
timeout = wait_for_completion_timeout(&p2m_dev->completion, HZ);
solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0);
/* XXX Really looks to me like we will get stuck here if a
* real PCI P2M error occurs */
if (p2m_dev->error)
goto start_dma;
up(&p2m_dev->sem);
return (timeout == 0) ? -EAGAIN : 0;
}
#ifdef SOLO_TEST_P2M
#define P2M_TEST_CHAR 0xbe
static unsigned long long p2m_test(struct solo6010_dev *solo_dev, u8 id,
u32 base, int size)
{
u8 *wr_buf;
u8 *rd_buf;
int i;
unsigned long long err_cnt = 0;
wr_buf = kmalloc(size, GFP_KERNEL);
if (!wr_buf) {
printk(SOLO6010_NAME ": Failed to malloc for p2m_test\n");
return size;
}
rd_buf = kmalloc(size, GFP_KERNEL);
if (!rd_buf) {
printk(SOLO6010_NAME ": Failed to malloc for p2m_test\n");
kfree(wr_buf);
return size;
}
memset(wr_buf, P2M_TEST_CHAR, size);
memset(rd_buf, P2M_TEST_CHAR + 1, size);
solo_p2m_dma(solo_dev, id, 1, wr_buf, base, size);
solo_p2m_dma(solo_dev, id, 0, rd_buf, base, size);
for (i = 0; i < size; i++)
if (wr_buf[i] != rd_buf[i])
err_cnt++;
kfree(wr_buf);
kfree(rd_buf);
return err_cnt;
}
#define TEST_CHUNK_SIZE (8 * 1024)
static void run_p2m_test(struct solo6010_dev *solo_dev)
{
unsigned long long errs = 0;
u32 size = SOLO_JPEG_EXT_ADDR(solo_dev) + SOLO_JPEG_EXT_SIZE(solo_dev);
int i, d;
printk(KERN_WARNING "%s: Testing %u bytes of external ram\n",
SOLO6010_NAME, size);
for (i = 0; i < size; i += TEST_CHUNK_SIZE)
for (d = 0; d < 4; d++)
errs += p2m_test(solo_dev, d, i, TEST_CHUNK_SIZE);
printk(KERN_WARNING "%s: Found %llu errors during p2m test\n",
SOLO6010_NAME, errs);
return;
}
#else
#define run_p2m_test(__solo) do{}while(0)
#endif
void solo_p2m_isr(struct solo6010_dev *solo_dev, int id)
{
solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_P2M(id));
complete(&solo_dev->p2m_dev[id].completion);
}
void solo_p2m_error_isr(struct solo6010_dev *solo_dev, u32 status)
{
struct solo_p2m_dev *p2m_dev;
int i;
if (!(status & SOLO_PCI_ERR_P2M))
return;
for (i = 0; i < SOLO_NR_P2M; i++) {
p2m_dev = &solo_dev->p2m_dev[i];
p2m_dev->error = 1;
solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
complete(&p2m_dev->completion);
}
}
void solo_p2m_exit(struct solo6010_dev *solo_dev)
{
int i;
for (i = 0; i < SOLO_NR_P2M; i++)
solo6010_irq_off(solo_dev, SOLO_IRQ_P2M(i));
}
int solo_p2m_init(struct solo6010_dev *solo_dev)
{
struct solo_p2m_dev *p2m_dev;
int i;
for (i = 0; i < SOLO_NR_P2M; i++) {
p2m_dev = &solo_dev->p2m_dev[i];
init_MUTEX(&p2m_dev->sem);
init_completion(&p2m_dev->completion);
solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(i),
__pa(p2m_dev->desc));
solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
solo_reg_write(solo_dev, SOLO_P2M_CONFIG(i),
SOLO_P2M_CSC_16BIT_565 |
SOLO_P2M_DMA_INTERVAL(0) |
SOLO_P2M_PCI_MASTER_MODE);
solo6010_irq_on(solo_dev, SOLO_IRQ_P2M(i));
}
run_p2m_test(solo_dev);
return 0;
}
This diff is collapsed.
This diff is collapsed.
/*
* Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
* Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __SOLO6010_TW28_H
#define __SOLO6010_TW28_H
#include "solo6010.h"
#define TW_NUM_CHIP 4
#define TW_BASE_ADDR 0x28
#define TW_CHIP_OFFSET_ADDR(n) (TW_BASE_ADDR + (n))
/* tw2815 */
#define TW_AV_STAT_ADDR 0x5a
#define TW_HUE_ADDR(n) (0x07 | ((n) << 4))
#define TW_SATURATION_ADDR(n) (0x08 | ((n) << 4))
#define TW_CONTRAST_ADDR(n) (0x09 | ((n) << 4))
#define TW_BRIGHTNESS_ADDR(n) (0x0a | ((n) << 4))
#define TW_AUDIO_OUTPUT_VOL_ADDR 0x70
#define TW_AUDIO_INPUT_GAIN_ADDR(n) (0x60 + ((n > 1) ? 1 : 0))
/* tw286x */
#define TW286X_AV_STAT_ADDR 0xfd
#define TW286x_HUE_ADDR(n) (0x06 | ((n) << 4))
#define TW286x_SATURATIONU_ADDR(n) (0x04 | ((n) << 4))
#define TW286x_SATURATIONV_ADDR(n) (0x05 | ((n) << 4))
#define TW286x_CONTRAST_ADDR(n) (0x02 | ((n) << 4))
#define TW286x_BRIGHTNESS_ADDR(n) (0x01 | ((n) << 4))
#define TW286x_SHARPNESS(n) (0x03 | ((n) << 4))
#define TW286x_AUDIO_OUTPUT_VOL_ADDR 0xdf
#define TW286x_AUDIO_INPUT_GAIN_ADDR(n) (0xD0 + ((n > 1) ? 1 : 0))
int solo_tw28_init(struct solo6010_dev *solo_dev);
int tw28_set_ctrl_val(struct solo6010_dev *solo_dev, u32 ctrl, u8 ch,
s32 val);
int tw28_get_ctrl_val(struct solo6010_dev *solo_dev, u32 ctrl, u8 ch,
s32 *val);
u8 tw28_get_audio_gain(struct solo6010_dev *solo_dev, u8 ch);
void tw28_set_audio_gain(struct solo6010_dev *solo_dev, u8 ch, u8 val);
int tw28_get_video_status(struct solo6010_dev *solo_dev, u8 ch);
#if 0
unsigned int tw2815_get_audio_status(struct SOLO6010 *solo6010);
void tw2815_Set_AudioOutVol(struct SOLO6010 *solo6010, unsigned int u_val);
#endif
#endif /* __SOLO6010_TW28_H */
This diff is collapsed.
This diff is collapsed.
/*
* Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
* Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __SOLO6010_H
#define __SOLO6010_H
#include <linux/version.h>
#include <linux/pci.h>
#include <linux/i2c.h>
#include <linux/semaphore.h>
#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/wait.h>
#include <asm/io.h>
#include <asm/atomic.h>
#include <linux/videodev2.h>
#include <media/v4l2-dev.h>
#include <media/videobuf-core.h>
#include "solo6010-registers.h"
#ifndef PCI_VENDOR_ID_SOFTLOGIC
#define PCI_VENDOR_ID_SOFTLOGIC 0x9413
#define PCI_DEVICE_ID_SOLO6010 0x6010
#endif
#ifndef PCI_VENDOR_ID_BLUECHERRY
#define PCI_VENDOR_ID_BLUECHERRY 0x1BB3
/* Neugent Softlogic 6010 based cards */
#define PCI_DEVICE_ID_NEUSOLO_4 0x4304
#define PCI_DEVICE_ID_NEUSOLO_9 0x4309
#define PCI_DEVICE_ID_NEUSOLO_16 0x4310
/* Commell Softlogic 6010 based cards */
#define PCI_DEVICE_ID_COMMSOLO_4 0x4E04
#define PCI_DEVICE_ID_COMMSOLO_9 0x4E09
#define PCI_DEVICE_ID_COMMSOLO_16 0x4E10
#endif /* Bluecherry */
#define SOLO6010_NAME "solo6010"
#define SOLO_MAX_CHANNELS 16
/* Make sure these two match */
#define SOLO6010_VERSION "2.0.0"
#define SOLO6010_VER_MAJOR 2
#define SOLO6010_VER_MINOR 0
#define SOLO6010_VER_SUB 0
#define SOLO6010_VER_NUM \
KERNEL_VERSION(SOLO6010_VER_MAJOR, SOLO6010_VER_MINOR, SOLO6010_VER_SUB)
/*
* The SOLO6010 actually has 8 i2c channels, but we only use 2.
* 0 - Techwell chip(s)
* 1 - SAA7128
*/
#define SOLO_I2C_ADAPTERS 2
#define SOLO_I2C_TW 0
#define SOLO_I2C_SAA 1
/* DMA Engine setup */
#define SOLO_NR_P2M 4
#define SOLO_NR_P2M_DESC 256
#define SOLO_P2M_DESC_SIZE (SOLO_NR_P2M_DESC * 16)
/* MPEG and JPEG share the same interrupt and locks so they must be together
* in the same dma channel. */
#define SOLO_P2M_DMA_ID_MP4E 0
#define SOLO_P2M_DMA_ID_JPEG 0
#define SOLO_P2M_DMA_ID_MP4D 1
#define SOLO_P2M_DMA_ID_G723D 1
#define SOLO_P2M_DMA_ID_DISP 2
#define SOLO_P2M_DMA_ID_OSG 2
#define SOLO_P2M_DMA_ID_G723E 3
#define SOLO_P2M_DMA_ID_VIN 3
/* Encoder standard modes */
#define SOLO_ENC_MODE_CIF 2
#define SOLO_ENC_MODE_HD1 1
#define SOLO_ENC_MODE_D1 9
#define SOLO_DEFAULT_GOP 30
#define SOLO_DEFAULT_QP 3
/* There is 8MB memory available for solo to buffer MPEG4 frames.
* This gives us 512 * 16kbyte queues. */
#define SOLO_NR_RING_BUFS 512
#define SOLO_CLOCK_MHZ 108
#ifndef V4L2_BUF_FLAG_MOTION_ON
#define V4L2_BUF_FLAG_MOTION_ON 0x0400
#define V4L2_BUF_FLAG_MOTION_DETECTED 0x0800
#endif
#ifndef V4L2_CID_MOTION_ENABLE
#define PRIVATE_CIDS
#define V4L2_CID_MOTION_ENABLE (V4L2_CID_PRIVATE_BASE+0)
#define V4L2_CID_MOTION_THRESHOLD (V4L2_CID_PRIVATE_BASE+1)
#define V4L2_CID_MOTION_TRACE (V4L2_CID_PRIVATE_BASE+2)
#endif
enum SOLO_I2C_STATE {
IIC_STATE_IDLE,
IIC_STATE_START,
IIC_STATE_READ,
IIC_STATE_WRITE,
IIC_STATE_STOP
};
struct solo_p2m_dev {
struct semaphore sem;
struct completion completion;
int error;
u8 desc[SOLO_P2M_DESC_SIZE];
};
#define OSD_TEXT_MAX 30
enum solo_enc_types {
SOLO_ENC_TYPE_STD,
SOLO_ENC_TYPE_EXT,
};
struct solo_enc_dev {
struct solo6010_dev *solo_dev;
/* V4L2 Items */
struct video_device *vfd;
/* General accounting */
wait_queue_head_t thread_wait;
spinlock_t lock;
atomic_t readers;
u8 ch;
u8 mode, gop, qp, interlaced, interval;
u8 reset_gop;
u8 bw_weight;
u8 motion_detected;
u16 motion_thresh;
u16 width;
u16 height;
char osd_text[OSD_TEXT_MAX + 1];
};
struct solo_enc_buf {
u8 vop;
u8 ch;
enum solo_enc_types type;
u32 off;
u32 size;
u32 jpeg_off;
u32 jpeg_size;
struct timeval ts;
};
/* The SOLO6010 PCI Device */
struct solo6010_dev {
/* General stuff */
struct pci_dev *pdev;
u8 __iomem *reg_base;
int nr_chans;
int nr_ext;
u32 irq_mask;
u32 motion_mask;
spinlock_t reg_io_lock;
/* tw28xx accounting */
u8 tw2864, tw2815;
u8 tw28_cnt;
/* i2c related items */
struct i2c_adapter i2c_adap[SOLO_I2C_ADAPTERS];
enum SOLO_I2C_STATE i2c_state;
struct semaphore i2c_sem;
int i2c_id;
wait_queue_head_t i2c_wait;
struct i2c_msg *i2c_msg;
unsigned int i2c_msg_num;
unsigned int i2c_msg_ptr;
/* P2M DMA Engine */
struct solo_p2m_dev p2m_dev[SOLO_NR_P2M];
/* V4L2 Display items */
struct video_device *vfd;
unsigned int erasing;
unsigned int frame_blank;
u8 cur_disp_ch;
wait_queue_head_t disp_thread_wait;
/* V4L2 Encoder items */
struct solo_enc_dev *v4l2_enc[SOLO_MAX_CHANNELS];
u16 enc_bw_remain;
/* IDX into hw mp4 encoder */
u8 enc_idx;
/* Our software ring of enc buf references */
u16 enc_wr_idx;
struct solo_enc_buf enc_buf[SOLO_NR_RING_BUFS];
/* Current video settings */
u32 video_type;
u16 video_hsize, video_vsize;
u16 vout_hstart, vout_vstart;
u16 vin_hstart, vin_vstart;
u8 fps;
/* Audio components */
struct snd_card *snd_card;
struct snd_pcm *snd_pcm;
atomic_t snd_users;
int g723_hw_idx;
};
static inline u32 solo_reg_read(struct solo6010_dev *solo_dev, int reg)
{
unsigned long flags;
u32 ret;
u16 val;
spin_lock_irqsave(&solo_dev->reg_io_lock, flags);
ret = readl(solo_dev->reg_base + reg);
rmb();
pci_read_config_word(solo_dev->pdev, PCI_STATUS, &val);
rmb();
spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags);
return ret;
}
static inline void solo_reg_write(struct solo6010_dev *solo_dev, int reg,
u32 data)
{
unsigned long flags;
u16 val;
spin_lock_irqsave(&solo_dev->reg_io_lock, flags);
writel(data, solo_dev->reg_base + reg);
wmb();
pci_read_config_word(solo_dev->pdev, PCI_STATUS, &val);
rmb();
spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags);
}
void solo6010_irq_on(struct solo6010_dev *solo_dev, u32 mask);
void solo6010_irq_off(struct solo6010_dev *solo_dev, u32 mask);
/* Init/exit routeines for subsystems */
int solo_disp_init(struct solo6010_dev *solo_dev);
void solo_disp_exit(struct solo6010_dev *solo_dev);
int solo_gpio_init(struct solo6010_dev *solo_dev);
void solo_gpio_exit(struct solo6010_dev *solo_dev);
int solo_i2c_init(struct solo6010_dev *solo_dev);
void solo_i2c_exit(struct solo6010_dev *solo_dev);
int solo_p2m_init(struct solo6010_dev *solo_dev);
void solo_p2m_exit(struct solo6010_dev *solo_dev);
int solo_v4l2_init(struct solo6010_dev *solo_dev);
void solo_v4l2_exit(struct solo6010_dev *solo_dev);
int solo_enc_init(struct solo6010_dev *solo_dev);
void solo_enc_exit(struct solo6010_dev *solo_dev);
int solo_enc_v4l2_init(struct solo6010_dev *solo_dev);
void solo_enc_v4l2_exit(struct solo6010_dev *solo_dev);
int solo_g723_init(struct solo6010_dev *solo_dev);
void solo_g723_exit(struct solo6010_dev *solo_dev);
/* ISR's */
int solo_i2c_isr(struct solo6010_dev *solo_dev);
void solo_p2m_isr(struct solo6010_dev *solo_dev, int id);
void solo_p2m_error_isr(struct solo6010_dev *solo_dev, u32 status);
void solo_enc_v4l2_isr(struct solo6010_dev *solo_dev);
void solo_g723_isr(struct solo6010_dev *solo_dev);
void solo_motion_isr(struct solo6010_dev *solo_dev);
void solo_video_in_isr(struct solo6010_dev *solo_dev);
/* i2c read/write */
u8 solo_i2c_readbyte(struct solo6010_dev *solo_dev, int id, u8 addr, u8 off);
void solo_i2c_writebyte(struct solo6010_dev *solo_dev, int id, u8 addr, u8 off,
u8 data);
/* P2M DMA */
int solo_p2m_dma_t(struct solo6010_dev *solo_dev, u8 id, int wr,
dma_addr_t dma_addr, u32 ext_addr, u32 size);
int solo_p2m_dma(struct solo6010_dev *solo_dev, u8 id, int wr,
void *sys_addr, u32 ext_addr, u32 size);
/* Set the threshold for motion detection */
void solo_set_motion_threshold(struct solo6010_dev *solo_dev, u8 ch, u16 val);
#define SOLO_DEF_MOT_THRESH 0x0300
/* Write text on OSD */
int solo_osd_print(struct solo_enc_dev *solo_enc);
#endif /* __SOLO6010_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment