Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/pci Add cxdtv(4), a dtv(4) driver for Conexant CX238...



details:   https://anonhg.NetBSD.org/src/rev/d64bb15f32b4
branches:  trunk
changeset: 767196:d64bb15f32b4
user:      jakllsch <jakllsch%NetBSD.org@localhost>
date:      Mon Jul 11 00:46:03 2011 +0000

description:
Add cxdtv(4), a dtv(4) driver for Conexant CX23880-series DTV interface chips.

Initially supports digital reception on ATI HDTV Wonder card.

diffstat:

 sys/dev/pci/cxdtv.c        |  1071 ++++++++++++++++++++++++++++++++++++++++++++
 sys/dev/pci/cxdtv_boards.c |    72 ++
 sys/dev/pci/cxdtv_boards.h |    53 ++
 sys/dev/pci/cxdtvreg.h     |   150 ++++++
 sys/dev/pci/cxdtvvar.h     |   108 ++++
 sys/dev/pci/files.pci      |     8 +-
 6 files changed, 1461 insertions(+), 1 deletions(-)

diffs (truncated from 1493 to 300 lines):

diff -r 15c0724e11f3 -r d64bb15f32b4 sys/dev/pci/cxdtv.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/dev/pci/cxdtv.c       Mon Jul 11 00:46:03 2011 +0000
@@ -0,0 +1,1071 @@
+/* $NetBSD: cxdtv.c,v 1.1 2011/07/11 00:46:03 jakllsch Exp $ */
+
+/*
+ * Copyright (c) 2008, 2011 Jonathan A. Kollasch
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: cxdtv.c,v 1.1 2011/07/11 00:46:03 jakllsch Exp $");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/kmem.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+
+#include <sys/bus.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcidevs.h>
+#include <dev/i2c/i2cvar.h>
+#include <dev/i2c/i2c_bitbang.h>
+
+#include <dev/i2c/tvpllvar.h>
+#include <dev/i2c/tvpll_tuners.h>
+
+#include <dev/i2c/nxt2kvar.h>
+
+#include <dev/pci/cxdtvreg.h>
+#include <dev/pci/cxdtvvar.h>
+#include <dev/pci/cxdtv_boards.h>
+
+#include <dev/dtv/dtvif.h>
+
+#define CXDTV_MMBASE           0x10
+
+#define CXDTV_SRAM_CH_MPEG     0
+#define CXDTV_TS_PKTSIZE       (188 * 8)
+
+
+static int cxdtv_match(struct device *, struct cfdata *, void *);
+static void cxdtv_attach(struct device *, struct device *, void *);
+static int cxdtv_intr(void *);
+
+static bool cxdtv_resume(device_t, const pmf_qual_t *);
+
+static int     cxdtv_iic_acquire_bus(void *, int);
+static void    cxdtv_iic_release_bus(void *, int);
+static int     cxdtv_iic_send_start(void *, int);
+static int     cxdtv_iic_send_stop(void *, int);
+static int     cxdtv_iic_initiate_xfer(void *, i2c_addr_t, int);
+static int     cxdtv_iic_read_byte(void *, uint8_t *, int);
+static int     cxdtv_iic_write_byte(void *, uint8_t, int);
+
+static void    cxdtv_i2cbb_set_bits(void *, uint32_t);
+static void    cxdtv_i2cbb_set_dir(void *, uint32_t);
+static uint32_t        cxdtv_i2cbb_read_bits(void *);
+
+static int     cxdtv_sram_ch_setup(struct cxdtv_softc *,
+                                   struct cxdtv_sram_ch *, uint32_t);
+static int     cxdtv_allocmem(struct cxdtv_softc *, size_t, size_t,
+    struct cxdtv_dma *);
+static int     cxdtv_freemem(struct cxdtv_softc *, struct cxdtv_dma *);
+static int     cxdtv_risc_buffer(struct cxdtv_softc *, uint32_t, uint32_t);
+static int     cxdtv_risc_field(struct cxdtv_softc *, uint32_t *, uint32_t);
+
+static int     cxdtv_mpeg_attach(struct cxdtv_softc *);
+static int     cxdtv_mpeg_intr(struct cxdtv_softc *);
+static int     cxdtv_mpeg_reset(struct cxdtv_softc *);
+
+static int     cxdtv_mpeg_trigger(struct cxdtv_softc *, void *);
+static int     cxdtv_mpeg_halt(struct cxdtv_softc *);
+static void *  cxdtv_mpeg_malloc(struct cxdtv_softc *, size_t);
+static void    cxdtv_mpeg_free(struct cxdtv_softc *, void *);
+
+static void cxdtv_card_init_hd5500(struct cxdtv_softc *);
+static void cxdtv_card_init_hdtvwonder(struct cxdtv_softc *);
+
+const struct i2c_bitbang_ops cxdtv_i2cbb_ops = {
+       cxdtv_i2cbb_set_bits,
+       cxdtv_i2cbb_set_dir,
+       cxdtv_i2cbb_read_bits,
+       { CXDTV_I2C_C_DATACONTROL_SDA, CXDTV_I2C_C_DATACONTROL_SCL, 0, 0 }
+};
+
+/* Maybe make this dynamically allocated. */
+static struct cxdtv_sram_ch cxdtv_sram_chs[] = {
+       [CXDTV_SRAM_CH_MPEG] = {
+               .csc_cmds = 0x180200, /* CMDS for ch. 28 */
+               .csc_iq = 0x180340, /* after last CMDS */
+               .csc_iqsz = 0x40, /* 16 dwords */
+               .csc_cdt = 0x180380, /* after iq */
+               .csc_cdtsz = 0x40, /* cluster discriptor space */
+               .csc_fifo = 0x180400, /* after cdt */
+               .csc_fifosz = 0x001C00, /* let's just align this up */
+               .csc_risc = 0x182000, /* after fifo */
+               .csc_riscsz = 0x6000, /* room for dma programs */
+               .csc_ptr1 = CXDTV_DMA28_PTR1,
+               .csc_ptr2 = CXDTV_DMA28_PTR2,
+               .csc_cnt1 = CXDTV_DMA28_CNT1,
+               .csc_cnt2 = CXDTV_DMA28_CNT2,
+       },
+};
+
+CFATTACH_DECL_NEW(cxdtv, sizeof(struct cxdtv_softc),
+    cxdtv_match, cxdtv_attach, NULL, NULL);
+
+static int
+cxdtv_match(device_t parent, cfdata_t match, void *aux)
+{
+       const struct pci_attach_args *pa;
+
+       pa = aux;
+
+       if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_CONEXANT)
+               return 0;
+
+       switch (PCI_PRODUCT(pa->pa_id)) {
+       case PCI_PRODUCT_CONEXANT_CX2388XMPEG:
+               return 1;
+       }
+
+       /* XXX only match supported boards */
+
+       return 0;
+}
+
+static void
+cxdtv_attach(device_t parent, device_t self, void *aux)
+{
+       struct cxdtv_softc *sc;
+       const struct pci_attach_args *pa = aux;
+       pci_intr_handle_t ih;
+       pcireg_t reg;
+       const char *intrstr;
+       char devinfo[76];
+       struct i2cbus_attach_args iba;
+
+       sc = device_private(self);
+
+       sc->sc_dev = self;
+
+       aprint_naive("\n");
+
+       reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
+
+       sc->sc_vendor = PCI_VENDOR(reg);
+       sc->sc_product = PCI_PRODUCT(reg);
+
+       sc->sc_board = cxdtv_board_lookup(sc->sc_vendor, sc->sc_product);
+
+       if (sc->sc_board == NULL) {
+               aprint_error_dev(self ,"unsupported device 0x%08x\n", reg);
+               return;
+       }
+
+       pci_devinfo(reg, pa->pa_class, 0, devinfo, sizeof(devinfo));
+       aprint_normal(": %s (rev. 0x%02x)\n", devinfo, PCI_REVISION(pa->pa_class));
+
+       if (pci_mapreg_map(pa, CXDTV_MMBASE, PCI_MAPREG_TYPE_MEM, 0,
+                          &sc->sc_memt, &sc->sc_memh, NULL, &sc->sc_mems)) {
+               aprint_error_dev(self, "couldn't map memory space\n");
+               return;
+       }
+
+       sc->sc_dmat = pa->pa_dmat;
+
+       if (pci_intr_map(pa, &ih)) {
+               aprint_error_dev(self, "couldn't map interrupt\n");
+               return;
+       }
+       intrstr = pci_intr_string(pa->pa_pc, ih);
+       sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_VM, cxdtv_intr, sc);
+       if (sc->sc_ih == NULL) {
+               aprint_error_dev(self, "couldn't establish interrupt");
+               if (intrstr != NULL)
+                       aprint_error(" at %s", intrstr);
+               aprint_error("\n");
+               return;
+       }
+       aprint_normal_dev(self, "interrupting at %s\n", intrstr);
+
+       /* set master */
+       reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
+       reg |= PCI_COMMAND_MASTER_ENABLE;
+       pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, reg);
+
+       mutex_init(&sc->sc_delaylock, MUTEX_DEFAULT, IPL_NONE);
+       cv_init(&sc->sc_delaycv, "cxdtvwait");
+
+       mutex_init(&sc->sc_i2c_buslock, MUTEX_DRIVER, IPL_NONE);
+       sc->sc_i2c.ic_cookie = sc;
+       sc->sc_i2c.ic_exec = NULL;
+       sc->sc_i2c.ic_acquire_bus = cxdtv_iic_acquire_bus;
+       sc->sc_i2c.ic_release_bus = cxdtv_iic_release_bus;
+       sc->sc_i2c.ic_send_start = cxdtv_iic_send_start;
+       sc->sc_i2c.ic_send_stop = cxdtv_iic_send_stop;
+       sc->sc_i2c.ic_initiate_xfer = cxdtv_iic_initiate_xfer;
+       sc->sc_i2c.ic_read_byte = cxdtv_iic_read_byte;
+       sc->sc_i2c.ic_write_byte = cxdtv_iic_write_byte;
+
+#if notyet
+       /* enable i2c compatible software mode */
+       val = bus_space_read_4(sc->sc_memt, sc->sc_memh,
+           CXDTV_I2C_C_DATACONTROL);
+       val = CXDTV_I2C_C_DATACONTROL_SCL | CXDTV_I2C_C_DATACONTROL_SDA;
+       bus_space_write_4(sc->sc_memt, sc->sc_memh,
+           CXDTV_I2C_C_DATACONTROL, val);
+#endif
+
+       cxdtv_mpeg_attach(sc);
+
+       /* attach other devices to iic(4) */
+       memset(&iba, 0, sizeof(iba));
+       iba.iba_tag = &sc->sc_i2c;
+       config_found_ia(self, "i2cbus", &iba, iicbus_print);
+
+       if (!pmf_device_register(self, NULL, cxdtv_resume))
+               aprint_error_dev(self, "couldn't establish power handler\n");
+
+       return;
+}
+
+static bool
+cxdtv_resume(device_t dv, const pmf_qual_t *qual)
+{
+       struct cxdtv_softc *sc;
+       sc = device_private(dv);
+
+       /* XXX revisit */
+
+       aprint_debug_dev(dv, "%s\n", __func__);
+
+       return true;
+}
+
+static int
+cxdtv_intr(void *intarg)
+{
+       struct cxdtv_softc *sc = intarg;
+       uint32_t val;
+
+       val = bus_space_read_4(sc->sc_memt, sc->sc_memh, CXDTV_PCI_INT_MSTAT);
+       if (val == 0) {
+               return 0; /* not ours */
+       }
+
+       if (val & CXT_PI_TS_INT) {
+               cxdtv_mpeg_intr(sc);
+       }
+
+       if (val & ~CXT_PI_TS_INT) {
+               device_printf(sc->sc_dev, "%s, %08x\n", __func__, val);
+       }
+
+       bus_space_write_4(sc->sc_memt, sc->sc_memh, CXDTV_PCI_INT_STAT, val);
+
+       return 1;
+}
+
+/* I2C interface */
+
+static void
+cxdtv_i2cbb_set_bits(void *cookie, uint32_t bits)
+{
+       struct cxdtv_softc *sc = cookie;
+       uint32_t value;
+
+       bus_space_write_4(sc->sc_memt, sc->sc_memh,
+           CXDTV_I2C_C_DATACONTROL, bits);
+       value = bus_space_read_4(sc->sc_memt, sc->sc_memh,
+           CXDTV_I2C_C_DATACONTROL);
+



Home | Main Index | Thread Index | Old Index