Skip to content

Commit

Permalink
solo6x10: Hello 6110 support (see notes below)
Browse files Browse the repository at this point in the history
- Also includes clipping to only allow access to upper 64 bytes of eeprom
- G.723 on 6110 not fully working yet

Signed-off-by: Ben Collins <bcollins@bluecherry.net>
  • Loading branch information
Ben Collins committed Feb 1, 2011
1 parent 9e2390f commit 7fac80b
Show file tree
Hide file tree
Showing 7 changed files with 222 additions and 34 deletions.
123 changes: 108 additions & 15 deletions solo6010-core.c
Expand Up @@ -43,6 +43,52 @@ void solo6010_irq_off(struct solo6010_dev *solo_dev, u32 mask)
solo_reg_write(solo_dev, SOLO_IRQ_ENABLE, solo_dev->irq_mask);
}

static void solo_set_time(struct solo6010_dev *solo_dev)
{
struct timeval tv;

do_gettimeofday(&tv);
solo_reg_write(solo_dev, SOLO_TIMER_SEC, tv.tv_sec);
solo_reg_write(solo_dev, SOLO_TIMER_USEC, tv.tv_usec);
}

static void solo_timer_sync(struct solo6010_dev *solo_dev)
{
u32 sec, usec;
struct timeval tv;
long diff;

if (solo_dev->type != SOLO_DEV_6110)
return;

solo_dev->time_sync++;

if (solo_dev->time_sync % 60)
return;

sec = solo_reg_read(solo_dev, SOLO_TIMER_SEC);
usec = solo_reg_read(solo_dev, SOLO_TIMER_USEC);
do_gettimeofday(&tv);

diff = (long)tv.tv_sec - (long)sec;
diff = (diff * 1000000) + ((long)tv.tv_usec - (long)usec);

if (diff > 1000 || diff < -1000) {
solo_set_time(solo_dev);
} else if (diff) {
long usec_lsb = solo_dev->usec_lsb;

usec_lsb -= diff / 4;
if (usec_lsb < 0)
usec_lsb = 0;
else if (usec_lsb > 255)
usec_lsb = 255;

solo_dev->usec_lsb = usec_lsb;
solo_reg_write(solo_dev, SOLO_TIMER_USEC_LSB, solo_dev->usec_lsb);
}
}

static irqreturn_t solo6010_isr(int irq, void *data)
{
struct solo6010_dev *solo_dev = data;
Expand Down Expand Up @@ -71,8 +117,10 @@ static irqreturn_t solo6010_isr(int irq, void *data)
if (status & SOLO_IRQ_IIC)
solo_i2c_isr(solo_dev);

if (status & SOLO_IRQ_VIDEO_IN)
if (status & SOLO_IRQ_VIDEO_IN) {
solo_video_in_isr(solo_dev);
solo_timer_sync(solo_dev);
}

if (status & SOLO_IRQ_ENCODER)
solo_enc_v4l2_isr(solo_dev);
Expand Down Expand Up @@ -138,14 +186,17 @@ static ssize_t solo_set_eeprom(struct device *dev, struct device_attribute *attr
unsigned short *p = (unsigned short *)buf;
int i;

if (count & 0x1)
if (count & 0x1) {
dev_warn(dev, "EEPROM Write is not short aligned\n");
if (count > 128)
dev_warn(dev, "EEPROM Write truncated to 128 bytes\n");
count &= ~0x1;
} if (count > 64) {
dev_warn(dev, "EEPROM Write truncated to 64 bytes\n");
count = 64;
}

solo_eeprom_ewen(solo_dev, 1);

for (i = 0; i < 64 && i < (count / 2); i++)
for (i = 32; i < 64 && i < (count / 2); i++)
solo_eeprom_write(solo_dev, i, p[i]);

solo_eeprom_ewen(solo_dev, 0);
Expand All @@ -160,10 +211,10 @@ static ssize_t solo_get_eeprom(struct device *dev, struct device_attribute *attr
unsigned short *p = (unsigned short *)buf;
int i;

for (i = 0; i < 64; i++)
for (i = 32; i < 64; i++)
p[i] = solo_eeprom_read(solo_dev, i);

return 128;
return 64;
}
static DEVICE_ATTR(eeprom, S_IWUSR | S_IRUGO, solo_get_eeprom, solo_set_eeprom);

Expand Down Expand Up @@ -207,7 +258,6 @@ static int __devinit solo6010_pci_probe(struct pci_dev *pdev,
{
struct solo6010_dev *solo_dev;
int ret;
int sdram;
u8 chip_id;

solo_dev = kzalloc(sizeof(*solo_dev), GFP_KERNEL);
Expand All @@ -223,6 +273,7 @@ static int __devinit solo6010_pci_probe(struct pci_dev *pdev,
solo_dev->pdev = pdev;
rwlock_init(&solo_dev->reg_io_lock);
pci_set_drvdata(pdev, solo_dev);
solo_dev->p2m_msecs = 100; /* Only for during init */

if ((ret = pci_enable_device(pdev)))
goto fail_probe;
Expand Down Expand Up @@ -265,11 +316,36 @@ static int __devinit solo6010_pci_probe(struct pci_dev *pdev,
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);
if (solo_dev->type == SOLO_DEV_6010) {
solo_dev->clock_mhz = 108;
solo_reg_write(solo_dev, SOLO_SYS_CFG, SOLO_SYS_CFG_SDRAM64BIT |
SOLO_SYS_CFG_INPUTDIV(25) |
SOLO_SYS_CFG_FEEDBACKDIV((solo_dev->clock_mhz * 2) - 2) |
SOLO_SYS_CFG_OUTDIV(3));
} else {
u32 divq, divf;

solo_dev->clock_mhz = 135;

if (solo_dev->clock_mhz < 125) {
divq = 3;
divf = (solo_dev->clock_mhz * 4) / 3 - 1;
} else {
divq = 2;
divf = (solo_dev->clock_mhz * 2) / 3 - 1;
}

solo_reg_write(solo_dev, SOLO_PLL_CONFIG,
(1 << 20) | /* PLL_RANGE */
(8 << 15) | /* PLL_DIVR */
(divq << 12 ) |
(divf << 4 ) |
(1 << 1) /* PLL_FSEN */ );

solo_reg_write(solo_dev, SOLO_SYS_CFG, SOLO_SYS_CFG_SDRAM64BIT);
}

solo_reg_write(solo_dev, SOLO_TIMER_CLOCK_NUM, solo_dev->clock_mhz - 1);

/* PLL locking time of 1ms */
mdelay(1);
Expand All @@ -286,14 +362,27 @@ static int __devinit solo6010_pci_probe(struct pci_dev *pdev,
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_SIZE(2) |
SOLO_DMA_CTRL_SDRAM_CLK_INVERT |
SOLO_DMA_CTRL_READ_CLK_SELECT |
SOLO_DMA_CTRL_LATENCY(1));

/* Undocumented crap */
if (solo_dev->type == SOLO_DEV_6010) {
solo_reg_write(solo_dev, SOLO_DMA_CTRL1, 1 << 8);
} else {
solo_reg_write(solo_dev, SOLO_DMA_CTRL1, 3 << 8);
solo_dev->usec_lsb = 0x3f;
solo_set_time(solo_dev);
}

/* Disable watchdog */
solo_reg_write(solo_dev, SOLO_TIMER_WATCHDOG, 0xff);

/* Initialize sub components */

if ((ret = solo_p2m_init(solo_dev)))
goto fail_probe;

Expand Down Expand Up @@ -321,6 +410,9 @@ static int __devinit solo6010_pci_probe(struct pci_dev *pdev,
if ((ret = solo_sysfs_init(solo_dev)))
goto fail_probe;

/* Now that init is over, set this lower */
solo_dev->p2m_msecs = 20;

return 0;

fail_probe:
Expand Down Expand Up @@ -358,6 +450,7 @@ static DEFINE_PCI_DEVICE_TABLE(solo6010_id_table) = {
.driver_data = SOLO_DEV_6110 },
{ PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_16),
.driver_data = SOLO_DEV_6110 },
{ PCI_DEVICE(0x0000, 0x0000), .driver_data = SOLO_DEV_6110 },
{0,}
};

Expand Down
7 changes: 6 additions & 1 deletion solo6010-disp.c
Expand Up @@ -74,7 +74,12 @@ static void solo_vin_config(struct solo6010_dev *solo_dev)
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);
/* On 6110, initialize mozaic darkness stength */
if (solo_dev->type == SOLO_DEV_6010)
solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 0);
else
solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 16 << 22);

solo_reg_write(solo_dev, SOLO_VI_PAGE_SW, 2);

if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
Expand Down
40 changes: 33 additions & 7 deletions solo6010-enc.c
Expand Up @@ -97,7 +97,11 @@ static void solo_capture_config(struct solo6010_dev *solo_dev)
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);

if (solo_dev->type == SOLO_DEV_6010)
solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, 0);
else
solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, SOLO_VE_OSD_V_DOUBLE);

/* Clear OSG buffer */
buf = kzalloc(SOLO_EOSD_EXT_SIZE, GFP_KERNEL);
Expand Down Expand Up @@ -164,7 +168,8 @@ int solo_osd_print(struct solo_enc_dev *solo_enc)
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));
(2 << 24) | (2 << 16) | (2 << 8) | 2);

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,
Expand All @@ -182,13 +187,23 @@ static void solo_mp4e_config(struct solo6010_dev *solo_dev)
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));
if (solo_dev->type == SOLO_DEV_6010) {
solo_reg_write(solo_dev, SOLO_VE_CFG1,
SOLO_VE_BYTE_ALIGN(2) |
SOLO_VE_INSERT_INDEX | SOLO_VE_MOTION_MODE(0));
} else {
solo_reg_write(solo_dev, SOLO_VE_CFG1,
(SOLO_VE_MPEG_SIZE_H(SOLO_MP4E_EXT_SIZE(solo_dev) >> 24) & 0x0f) |
(SOLO_VE_JPEG_SIZE_H(SOLO_JPEG_EXT_SIZE(solo_dev) >> 24) & 0x0f) |
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);
if (solo_dev->type == SOLO_DEV_6110)
solo_reg_write(solo_dev, SOLO_VE_WMRK_ENABLE, 0);
solo_reg_write(solo_dev, SOLO_VE_ENCRYP_POLY, 0);
solo_reg_write(solo_dev, SOLO_VE_ENCRYP_INIT, 0);

Expand All @@ -197,12 +212,23 @@ static void solo_mp4e_config(struct solo6010_dev *solo_dev)
SOLO_COMP_ATTR_FCODE(1) |
SOLO_COMP_TIME_INC(0) |
SOLO_COMP_TIME_WIDTH(15) |
SOLO_DCT_INTERVAL(36 / 4));
SOLO_DCT_INTERVAL(solo_dev->type == SOLO_DEV_6010 ? 9 : 10));

for (i = 0; i < solo_dev->nr_chans; i++)
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);
solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE_E(i),
(SOLO_EREF_EXT_ADDR(solo_dev) +
((i + 16) * SOLO_EREF_EXT_SIZE)) >> 16);
}

if (solo_dev->type == SOLO_DEV_6110) {
solo_reg_write(solo_dev, SOLO_VE_COMPT_MOT, 0x00040008);
} else {
for (i = 0; i < solo_dev->nr_chans; i++)
solo_reg_write(solo_dev, SOLO_VE_CH_MOT(i), 0x100);
}
}

int solo_enc_init(struct solo6010_dev *solo_dev)
Expand Down
2 changes: 1 addition & 1 deletion solo6010-g723.c
Expand Up @@ -62,7 +62,7 @@ static void solo_g723_config(struct solo6010_dev *solo_dev)
{
int clk_div;

clk_div = (SOLO_CLOCK_MHZ * 1000000) / (SAMPLERATE * (BITRATE * 2) * 2);
clk_div = (solo_dev->clock_mhz * 1000000) / (SAMPLERATE * (BITRATE * 2) * 2);

solo_reg_write(solo_dev, SOLO_AUDIO_SAMPLE,
SOLO_AUDIO_BITRATE(BITRATE) |
Expand Down
4 changes: 2 additions & 2 deletions solo6010-offsets.h
Expand Up @@ -50,10 +50,10 @@
#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 */
/* Double, for eref and extended eref */
#define SOLO_EREF_EXT_ADDR(__solo) \
(SOLO_CAP_EXT_ADDR(__solo) + \
(SOLO_CAP_EXT_SIZE * (__solo->nr_chans + 1)))
(SOLO_CAP_EXT_SIZE * (__solo->nr_chans * 2)))
#define SOLO_EREF_EXT_SIZE 0x00140000

#define SOLO_MP4E_EXT_ADDR(__solo) \
Expand Down
15 changes: 14 additions & 1 deletion solo6010-registers.h
Expand Up @@ -46,6 +46,9 @@
#define SOLO_DMA_CTRL_READ_CLK_SELECT (1<<2)
#define SOLO_DMA_CTRL_LATENCY(n) ((n)<<0)

/* Some things we set in this are undocumented. Why Softlogic?!?! */
#define SOLO_DMA_CTRL1 0x0008

#define SOLO_SYS_VCLK 0x000C
#define SOLO_VCLK_INVERT (1<<22)
/* 0=sys_clk/4, 1=sys_clk/2, 2=clk_in/2 of system input */
Expand Down Expand Up @@ -81,6 +84,8 @@
#define SOLO_CHIP_OPTION 0x001C
#define SOLO_CHIP_ID_MASK 0x00000007

#define SOLO_PLL_CONFIG 0x0020 /* 6110 Only */

#define SOLO_EEPROM_CTRL 0x0060
#define SOLO_EEPROM_ACCESS_EN (1<<7)
#define SOLO_EEPROM_CS (1<<3)
Expand Down Expand Up @@ -387,6 +392,9 @@
#define SOLO_VE_INSERT_INDEX (1<<18)
#define SOLO_VE_MOTION_MODE(n) ((n)<<16)
#define SOLO_VE_MOTION_BASE(n) ((n)<<0)
#define SOLO_VE_MPEG_SIZE_H(n) ((n)<<28) /* 6110 Only */
#define SOLO_VE_JPEG_SIZE_H(n) ((n)<<20) /* 6110 Only */
#define SOLO_VE_INSERT_INDEX_JPEG (1<<19) /* 6110 Only */

#define SOLO_VE_WMRK_POLY 0x061C
#define SOLO_VE_VMRK_INIT_KEY 0x0620
Expand All @@ -400,6 +408,7 @@
#define SOLO_COMP_TIME_INC(n) ((n)<<25)
#define SOLO_COMP_TIME_WIDTH(n) ((n)<<21)
#define SOLO_DCT_INTERVAL(n) ((n)<<16)
#define SOLO_VE_COMPT_MOT 0x0634 /* 6110 Only */

#define SOLO_VE_STATE(n) (0x0640+((n)*4))
struct videnc_status {
Expand Down Expand Up @@ -448,11 +457,14 @@ struct videnc_status {
#define SOLO_VE_JPEG_QP_CH_H 0x0678
#define SOLO_VE_JPEG_CFG 0x067C
#define SOLO_VE_JPEG_CTRL 0x0680

#define SOLO_VE_CODE_ENCRYPT 0x0684 /* 6110 Only */
#define SOLO_VE_JPEG_CFG1 0x0688 /* 6110 Only */
#define SOLO_VE_WMRK_ENABLE 0x068C /* 6110 Only */
#define SOLO_VE_OSD_CH 0x0690
#define SOLO_VE_OSD_BASE 0x0694
#define SOLO_VE_OSD_CLR 0x0698
#define SOLO_VE_OSD_OPT 0x069C
#define SOLO_VE_OSD_V_DOUBLE (1<<16) /* 6110 Only */

#define SOLO_VE_CH_INTL(ch) (0x0700+((ch)*4))
#define SOLO_VE_CH_MOT(ch) (0x0740+((ch)*4))
Expand Down Expand Up @@ -622,6 +634,7 @@ struct videnc_status {
#define SOLO_TIMER_WATCHDOG 0x0be4
#define SOLO_TIMER_USEC 0x0be8
#define SOLO_TIMER_SEC 0x0bec
#define SOLO_TIMER_USEC_LSB 0x0d20 /* 6110 Only */

#define SOLO_AUDIO_CONTROL 0x0D00
#define SOLO_AUDIO_ENABLE (1<<31)
Expand Down

0 comments on commit 7fac80b

Please sign in to comment.