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