1e4afd792SAlexander Motin /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3718cf2ccSPedro F. Giffuni * 420a9f771SRuslan Bukin * Copyright (c) 2012-2016 Ruslan Bukin <br@bsdpad.com> 5e4afd792SAlexander Motin * All rights reserved. 6e4afd792SAlexander Motin * 7e4afd792SAlexander Motin * Redistribution and use in source and binary forms, with or without 8e4afd792SAlexander Motin * modification, are permitted provided that the following conditions 9e4afd792SAlexander Motin * are met: 10e4afd792SAlexander Motin * 1. Redistributions of source code must retain the above copyright 11e4afd792SAlexander Motin * notice, this list of conditions and the following disclaimer. 12e4afd792SAlexander Motin * 2. Redistributions in binary form must reproduce the above copyright 13e4afd792SAlexander Motin * notice, this list of conditions and the following disclaimer in the 14e4afd792SAlexander Motin * documentation and/or other materials provided with the distribution. 15e4afd792SAlexander Motin * 16e4afd792SAlexander Motin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17e4afd792SAlexander Motin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18e4afd792SAlexander Motin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19e4afd792SAlexander Motin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20e4afd792SAlexander Motin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21e4afd792SAlexander Motin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22e4afd792SAlexander Motin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23e4afd792SAlexander Motin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24e4afd792SAlexander Motin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25e4afd792SAlexander Motin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26e4afd792SAlexander Motin * SUCH DAMAGE. 27e4afd792SAlexander Motin */ 28e4afd792SAlexander Motin 29e4afd792SAlexander Motin /* 30e4afd792SAlexander Motin * RME HDSPe driver for FreeBSD. 31e4afd792SAlexander Motin * Supported cards: AIO, RayDAT. 32e4afd792SAlexander Motin */ 33e4afd792SAlexander Motin 34*b6052c10SRuslan Bukin #include <sys/types.h> 35*b6052c10SRuslan Bukin #include <sys/sysctl.h> 36*b6052c10SRuslan Bukin 37e4afd792SAlexander Motin #include <dev/sound/pcm/sound.h> 38e4afd792SAlexander Motin #include <dev/sound/pci/hdspe.h> 39e4afd792SAlexander Motin #include <dev/sound/chip.h> 40e4afd792SAlexander Motin 41e4afd792SAlexander Motin #include <dev/pci/pcireg.h> 42e4afd792SAlexander Motin #include <dev/pci/pcivar.h> 43e4afd792SAlexander Motin 44e4afd792SAlexander Motin #include <mixer_if.h> 45e4afd792SAlexander Motin 46*b6052c10SRuslan Bukin static struct hdspe_clock_source hdspe_clock_source_table_rd[] = { 47*b6052c10SRuslan Bukin { "internal", 0 << 1 | 1, HDSPE_STATUS1_CLOCK(15), 0, 0 }, 48*b6052c10SRuslan Bukin { "word", 0 << 1 | 0, HDSPE_STATUS1_CLOCK( 0), 1 << 24, 1 << 25 }, 49*b6052c10SRuslan Bukin { "aes", 1 << 1 | 0, HDSPE_STATUS1_CLOCK( 1), 1 << 0, 1 << 8 }, 50*b6052c10SRuslan Bukin { "spdif", 2 << 1 | 0, HDSPE_STATUS1_CLOCK( 2), 1 << 1, 1 << 9 }, 51*b6052c10SRuslan Bukin { "adat1", 3 << 1 | 0, HDSPE_STATUS1_CLOCK( 3), 1 << 2, 1 << 10 }, 52*b6052c10SRuslan Bukin { "adat2", 4 << 1 | 0, HDSPE_STATUS1_CLOCK( 4), 1 << 3, 1 << 11 }, 53*b6052c10SRuslan Bukin { "adat3", 5 << 1 | 0, HDSPE_STATUS1_CLOCK( 5), 1 << 4, 1 << 12 }, 54*b6052c10SRuslan Bukin { "adat4", 6 << 1 | 0, HDSPE_STATUS1_CLOCK( 6), 1 << 5, 1 << 13 }, 55*b6052c10SRuslan Bukin { "tco", 9 << 1 | 0, HDSPE_STATUS1_CLOCK( 9), 1 << 26, 1 << 27 }, 56*b6052c10SRuslan Bukin { "sync_in", 10 << 1 | 0, HDSPE_STATUS1_CLOCK(10), 0, 0 }, 57*b6052c10SRuslan Bukin { NULL, 0 << 1 | 0, HDSPE_STATUS1_CLOCK( 0), 0, 0 }, 58*b6052c10SRuslan Bukin }; 59*b6052c10SRuslan Bukin 60*b6052c10SRuslan Bukin static struct hdspe_clock_source hdspe_clock_source_table_aio[] = { 61*b6052c10SRuslan Bukin { "internal", 0 << 1 | 1, HDSPE_STATUS1_CLOCK(15), 0, 0 }, 62*b6052c10SRuslan Bukin { "word", 0 << 1 | 0, HDSPE_STATUS1_CLOCK( 0), 1 << 24, 1 << 25 }, 63*b6052c10SRuslan Bukin { "aes", 1 << 1 | 0, HDSPE_STATUS1_CLOCK( 1), 1 << 0, 1 << 8 }, 64*b6052c10SRuslan Bukin { "spdif", 2 << 1 | 0, HDSPE_STATUS1_CLOCK( 2), 1 << 1, 1 << 9 }, 65*b6052c10SRuslan Bukin { "adat", 3 << 1 | 0, HDSPE_STATUS1_CLOCK( 3), 1 << 2, 1 << 10 }, 66*b6052c10SRuslan Bukin { "tco", 9 << 1 | 0, HDSPE_STATUS1_CLOCK( 9), 1 << 26, 1 << 27 }, 67*b6052c10SRuslan Bukin { "sync_in", 10 << 1 | 0, HDSPE_STATUS1_CLOCK(10), 0, 0 }, 68*b6052c10SRuslan Bukin { NULL, 0 << 1 | 0, HDSPE_STATUS1_CLOCK( 0), 0, 0 }, 69*b6052c10SRuslan Bukin }; 70*b6052c10SRuslan Bukin 71e4afd792SAlexander Motin static struct hdspe_channel chan_map_aio[] = { 72e4afd792SAlexander Motin { 0, 1, "line", 1, 1 }, 73e4afd792SAlexander Motin { 6, 7, "phone", 1, 0 }, 74e4afd792SAlexander Motin { 8, 9, "aes", 1, 1 }, 75e4afd792SAlexander Motin { 10, 11, "s/pdif", 1, 1 }, 76e4afd792SAlexander Motin { 12, 16, "adat", 1, 1 }, 77e4afd792SAlexander Motin 78e4afd792SAlexander Motin /* Single or double speed. */ 79e4afd792SAlexander Motin { 14, 18, "adat", 1, 1 }, 80e4afd792SAlexander Motin 81e4afd792SAlexander Motin /* Single speed only. */ 82e4afd792SAlexander Motin { 13, 15, "adat", 1, 1 }, 83e4afd792SAlexander Motin { 17, 19, "adat", 1, 1 }, 84e4afd792SAlexander Motin 85e4afd792SAlexander Motin { 0, 0, NULL, 0, 0 }, 86e4afd792SAlexander Motin }; 87e4afd792SAlexander Motin 88e4afd792SAlexander Motin static struct hdspe_channel chan_map_rd[] = { 89e4afd792SAlexander Motin { 0, 1, "aes", 1, 1 }, 90e4afd792SAlexander Motin { 2, 3, "s/pdif", 1, 1 }, 91e4afd792SAlexander Motin { 4, 5, "adat", 1, 1 }, 92e4afd792SAlexander Motin { 6, 7, "adat", 1, 1 }, 93e4afd792SAlexander Motin { 8, 9, "adat", 1, 1 }, 94e4afd792SAlexander Motin { 10, 11, "adat", 1, 1 }, 95e4afd792SAlexander Motin 96e4afd792SAlexander Motin /* Single or double speed. */ 97e4afd792SAlexander Motin { 12, 13, "adat", 1, 1 }, 98e4afd792SAlexander Motin { 14, 15, "adat", 1, 1 }, 99e4afd792SAlexander Motin { 16, 17, "adat", 1, 1 }, 100e4afd792SAlexander Motin { 18, 19, "adat", 1, 1 }, 101e4afd792SAlexander Motin 102e4afd792SAlexander Motin /* Single speed only. */ 103e4afd792SAlexander Motin { 20, 21, "adat", 1, 1 }, 104e4afd792SAlexander Motin { 22, 23, "adat", 1, 1 }, 105e4afd792SAlexander Motin { 24, 25, "adat", 1, 1 }, 106e4afd792SAlexander Motin { 26, 27, "adat", 1, 1 }, 107e4afd792SAlexander Motin { 28, 29, "adat", 1, 1 }, 108e4afd792SAlexander Motin { 30, 31, "adat", 1, 1 }, 109e4afd792SAlexander Motin { 32, 33, "adat", 1, 1 }, 110e4afd792SAlexander Motin { 34, 35, "adat", 1, 1 }, 111e4afd792SAlexander Motin 112e4afd792SAlexander Motin { 0, 0, NULL, 0, 0 }, 113e4afd792SAlexander Motin }; 114e4afd792SAlexander Motin 115e4afd792SAlexander Motin static void 116e4afd792SAlexander Motin hdspe_intr(void *p) 117e4afd792SAlexander Motin { 118e4afd792SAlexander Motin struct sc_pcminfo *scp; 11920a9f771SRuslan Bukin struct sc_info *sc; 120e4afd792SAlexander Motin device_t *devlist; 12120a9f771SRuslan Bukin int devcount; 12220a9f771SRuslan Bukin int status; 12320a9f771SRuslan Bukin int err; 12420a9f771SRuslan Bukin int i; 12520a9f771SRuslan Bukin 12620a9f771SRuslan Bukin sc = (struct sc_info *)p; 127e4afd792SAlexander Motin 128e4afd792SAlexander Motin snd_mtxlock(sc->lock); 129e4afd792SAlexander Motin 130e4afd792SAlexander Motin status = hdspe_read_1(sc, HDSPE_STATUS_REG); 131e4afd792SAlexander Motin if (status & HDSPE_AUDIO_IRQ_PENDING) { 132e4afd792SAlexander Motin if ((err = device_get_children(sc->dev, &devlist, &devcount)) != 0) 133e4afd792SAlexander Motin return; 134e4afd792SAlexander Motin 135e4afd792SAlexander Motin for (i = 0; i < devcount; i++) { 136e4afd792SAlexander Motin scp = device_get_ivars(devlist[i]); 137e4afd792SAlexander Motin if (scp->ih != NULL) 138e4afd792SAlexander Motin scp->ih(scp); 139e4afd792SAlexander Motin } 140e4afd792SAlexander Motin 141e4afd792SAlexander Motin hdspe_write_1(sc, HDSPE_INTERRUPT_ACK, 0); 142b5db12bfSKevin Lo free(devlist, M_TEMP); 143e4afd792SAlexander Motin } 144e4afd792SAlexander Motin 145e4afd792SAlexander Motin snd_mtxunlock(sc->lock); 146e4afd792SAlexander Motin } 147e4afd792SAlexander Motin 148e4afd792SAlexander Motin static void 149e4afd792SAlexander Motin hdspe_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 150e4afd792SAlexander Motin { 151e4afd792SAlexander Motin #if 0 152e4afd792SAlexander Motin device_printf(sc->dev, "hdspe_dmapsetmap()\n"); 153e4afd792SAlexander Motin #endif 154e4afd792SAlexander Motin } 155e4afd792SAlexander Motin 156e4afd792SAlexander Motin static int 157e4afd792SAlexander Motin hdspe_alloc_resources(struct sc_info *sc) 158e4afd792SAlexander Motin { 159e4afd792SAlexander Motin 160e4afd792SAlexander Motin /* Allocate resource. */ 161e4afd792SAlexander Motin sc->csid = PCIR_BAR(0); 16243cd6160SJustin Hibbits sc->cs = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 16343cd6160SJustin Hibbits &sc->csid, RF_ACTIVE); 164e4afd792SAlexander Motin 165e4afd792SAlexander Motin if (!sc->cs) { 166e4afd792SAlexander Motin device_printf(sc->dev, "Unable to map SYS_RES_MEMORY.\n"); 167e4afd792SAlexander Motin return (ENXIO); 168e4afd792SAlexander Motin } 16920a9f771SRuslan Bukin 170e4afd792SAlexander Motin sc->cst = rman_get_bustag(sc->cs); 171e4afd792SAlexander Motin sc->csh = rman_get_bushandle(sc->cs); 172e4afd792SAlexander Motin 173e4afd792SAlexander Motin /* Allocate interrupt resource. */ 174e4afd792SAlexander Motin sc->irqid = 0; 17543cd6160SJustin Hibbits sc->irq = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &sc->irqid, 17643cd6160SJustin Hibbits RF_ACTIVE | RF_SHAREABLE); 177e4afd792SAlexander Motin 178e4afd792SAlexander Motin if (!sc->irq || 179e4afd792SAlexander Motin bus_setup_intr(sc->dev, sc->irq, INTR_MPSAFE | INTR_TYPE_AV, 180e4afd792SAlexander Motin NULL, hdspe_intr, sc, &sc->ih)) { 181e4afd792SAlexander Motin device_printf(sc->dev, "Unable to alloc interrupt resource.\n"); 182e4afd792SAlexander Motin return (ENXIO); 183e4afd792SAlexander Motin } 184e4afd792SAlexander Motin 185e4afd792SAlexander Motin /* Allocate DMA resources. */ 186e4afd792SAlexander Motin if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev), 187e4afd792SAlexander Motin /*alignment*/4, 188e4afd792SAlexander Motin /*boundary*/0, 189e4afd792SAlexander Motin /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 190e4afd792SAlexander Motin /*highaddr*/BUS_SPACE_MAXADDR, 191e4afd792SAlexander Motin /*filter*/NULL, 192e4afd792SAlexander Motin /*filterarg*/NULL, 193e4afd792SAlexander Motin /*maxsize*/2 * HDSPE_DMASEGSIZE, 194e4afd792SAlexander Motin /*nsegments*/2, 195e4afd792SAlexander Motin /*maxsegsz*/HDSPE_DMASEGSIZE, 196e4afd792SAlexander Motin /*flags*/0, 1971f7a6325SAlexander Motin /*lockfunc*/NULL, 1981f7a6325SAlexander Motin /*lockarg*/NULL, 199e4afd792SAlexander Motin /*dmatag*/&sc->dmat) != 0) { 200e4afd792SAlexander Motin device_printf(sc->dev, "Unable to create dma tag.\n"); 201e4afd792SAlexander Motin return (ENXIO); 202e4afd792SAlexander Motin } 203e4afd792SAlexander Motin 204e4afd792SAlexander Motin sc->bufsize = HDSPE_DMASEGSIZE; 205e4afd792SAlexander Motin 206e4afd792SAlexander Motin /* pbuf (play buffer). */ 2071f7a6325SAlexander Motin if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_WAITOK, 2081f7a6325SAlexander Motin &sc->pmap)) { 209e4afd792SAlexander Motin device_printf(sc->dev, "Can't alloc pbuf.\n"); 210e4afd792SAlexander Motin return (ENXIO); 211e4afd792SAlexander Motin } 212e4afd792SAlexander Motin 213e4afd792SAlexander Motin if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->bufsize, 2141f7a6325SAlexander Motin hdspe_dmapsetmap, sc, BUS_DMA_NOWAIT)) { 215e4afd792SAlexander Motin device_printf(sc->dev, "Can't load pbuf.\n"); 216e4afd792SAlexander Motin return (ENXIO); 217e4afd792SAlexander Motin } 218e4afd792SAlexander Motin 219e4afd792SAlexander Motin /* rbuf (rec buffer). */ 2201f7a6325SAlexander Motin if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_WAITOK, 2211f7a6325SAlexander Motin &sc->rmap)) { 222e4afd792SAlexander Motin device_printf(sc->dev, "Can't alloc rbuf.\n"); 223e4afd792SAlexander Motin return (ENXIO); 224e4afd792SAlexander Motin } 225e4afd792SAlexander Motin 226e4afd792SAlexander Motin if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->bufsize, 2271f7a6325SAlexander Motin hdspe_dmapsetmap, sc, BUS_DMA_NOWAIT)) { 228e4afd792SAlexander Motin device_printf(sc->dev, "Can't load rbuf.\n"); 229e4afd792SAlexander Motin return (ENXIO); 230e4afd792SAlexander Motin } 231e4afd792SAlexander Motin 232e4afd792SAlexander Motin bzero(sc->pbuf, sc->bufsize); 233e4afd792SAlexander Motin bzero(sc->rbuf, sc->bufsize); 234e4afd792SAlexander Motin 235e4afd792SAlexander Motin return (0); 236e4afd792SAlexander Motin } 237e4afd792SAlexander Motin 238e4afd792SAlexander Motin static void 239e4afd792SAlexander Motin hdspe_map_dmabuf(struct sc_info *sc) 240e4afd792SAlexander Motin { 241e4afd792SAlexander Motin uint32_t paddr, raddr; 242e4afd792SAlexander Motin int i; 243e4afd792SAlexander Motin 244e4afd792SAlexander Motin paddr = vtophys(sc->pbuf); 245e4afd792SAlexander Motin raddr = vtophys(sc->rbuf); 246e4afd792SAlexander Motin 247e4afd792SAlexander Motin for (i = 0; i < HDSPE_MAX_SLOTS * 16; i++) { 248e4afd792SAlexander Motin hdspe_write_4(sc, HDSPE_PAGE_ADDR_BUF_OUT + 4 * i, 249e4afd792SAlexander Motin paddr + i * 4096); 250e4afd792SAlexander Motin hdspe_write_4(sc, HDSPE_PAGE_ADDR_BUF_IN + 4 * i, 251e4afd792SAlexander Motin raddr + i * 4096); 252e4afd792SAlexander Motin } 253e4afd792SAlexander Motin } 254e4afd792SAlexander Motin 255e4afd792SAlexander Motin static int 256*b6052c10SRuslan Bukin hdspe_sysctl_clock_preference(SYSCTL_HANDLER_ARGS) 257*b6052c10SRuslan Bukin { 258*b6052c10SRuslan Bukin struct sc_info *sc; 259*b6052c10SRuslan Bukin struct hdspe_clock_source *clock_table, *clock; 260*b6052c10SRuslan Bukin char buf[16] = "invalid"; 261*b6052c10SRuslan Bukin int error; 262*b6052c10SRuslan Bukin uint32_t setting; 263*b6052c10SRuslan Bukin 264*b6052c10SRuslan Bukin sc = oidp->oid_arg1; 265*b6052c10SRuslan Bukin 266*b6052c10SRuslan Bukin /* Select sync ports table for device type. */ 267*b6052c10SRuslan Bukin if (sc->type == HDSPE_AIO) 268*b6052c10SRuslan Bukin clock_table = hdspe_clock_source_table_aio; 269*b6052c10SRuslan Bukin else if (sc->type == HDSPE_RAYDAT) 270*b6052c10SRuslan Bukin clock_table = hdspe_clock_source_table_rd; 271*b6052c10SRuslan Bukin else 272*b6052c10SRuslan Bukin return (ENXIO); 273*b6052c10SRuslan Bukin 274*b6052c10SRuslan Bukin /* Extract preferred clock source from settings register. */ 275*b6052c10SRuslan Bukin setting = sc->settings_register & HDSPE_SETTING_CLOCK_MASK; 276*b6052c10SRuslan Bukin for (clock = clock_table; clock->name != NULL; ++clock) { 277*b6052c10SRuslan Bukin if (clock->setting == setting) 278*b6052c10SRuslan Bukin break; 279*b6052c10SRuslan Bukin } 280*b6052c10SRuslan Bukin if (clock->name != NULL) 281*b6052c10SRuslan Bukin strlcpy(buf, clock->name, sizeof(buf)); 282*b6052c10SRuslan Bukin 283*b6052c10SRuslan Bukin /* Process sysctl string request. */ 284*b6052c10SRuslan Bukin error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 285*b6052c10SRuslan Bukin if (error != 0 || req->newptr == NULL) 286*b6052c10SRuslan Bukin return (error); 287*b6052c10SRuslan Bukin 288*b6052c10SRuslan Bukin /* Find clock source matching the sysctl string. */ 289*b6052c10SRuslan Bukin for (clock = clock_table; clock->name != NULL; ++clock) { 290*b6052c10SRuslan Bukin if (strncasecmp(buf, clock->name, sizeof(buf)) == 0) 291*b6052c10SRuslan Bukin break; 292*b6052c10SRuslan Bukin } 293*b6052c10SRuslan Bukin 294*b6052c10SRuslan Bukin /* Set preferred clock source in settings register. */ 295*b6052c10SRuslan Bukin if (clock->name != NULL) { 296*b6052c10SRuslan Bukin setting = clock->setting & HDSPE_SETTING_CLOCK_MASK; 297*b6052c10SRuslan Bukin snd_mtxlock(sc->lock); 298*b6052c10SRuslan Bukin sc->settings_register &= ~HDSPE_SETTING_CLOCK_MASK; 299*b6052c10SRuslan Bukin sc->settings_register |= setting; 300*b6052c10SRuslan Bukin hdspe_write_4(sc, HDSPE_SETTINGS_REG, sc->settings_register); 301*b6052c10SRuslan Bukin snd_mtxunlock(sc->lock); 302*b6052c10SRuslan Bukin } 303*b6052c10SRuslan Bukin return (0); 304*b6052c10SRuslan Bukin } 305*b6052c10SRuslan Bukin 306*b6052c10SRuslan Bukin static int 307*b6052c10SRuslan Bukin hdspe_sysctl_clock_source(SYSCTL_HANDLER_ARGS) 308*b6052c10SRuslan Bukin { 309*b6052c10SRuslan Bukin struct sc_info *sc; 310*b6052c10SRuslan Bukin struct hdspe_clock_source *clock_table, *clock; 311*b6052c10SRuslan Bukin char buf[16] = "invalid"; 312*b6052c10SRuslan Bukin uint32_t status; 313*b6052c10SRuslan Bukin 314*b6052c10SRuslan Bukin sc = oidp->oid_arg1; 315*b6052c10SRuslan Bukin 316*b6052c10SRuslan Bukin /* Select sync ports table for device type. */ 317*b6052c10SRuslan Bukin if (sc->type == HDSPE_AIO) 318*b6052c10SRuslan Bukin clock_table = hdspe_clock_source_table_aio; 319*b6052c10SRuslan Bukin else if (sc->type == HDSPE_RAYDAT) 320*b6052c10SRuslan Bukin clock_table = hdspe_clock_source_table_rd; 321*b6052c10SRuslan Bukin else 322*b6052c10SRuslan Bukin return (ENXIO); 323*b6052c10SRuslan Bukin 324*b6052c10SRuslan Bukin /* Read current (autosync) clock source from status register. */ 325*b6052c10SRuslan Bukin snd_mtxlock(sc->lock); 326*b6052c10SRuslan Bukin status = hdspe_read_4(sc, HDSPE_STATUS1_REG); 327*b6052c10SRuslan Bukin status &= HDSPE_STATUS1_CLOCK_MASK; 328*b6052c10SRuslan Bukin snd_mtxunlock(sc->lock); 329*b6052c10SRuslan Bukin 330*b6052c10SRuslan Bukin /* Translate status register value to clock source. */ 331*b6052c10SRuslan Bukin for (clock = clock_table; clock->name != NULL; ++clock) { 332*b6052c10SRuslan Bukin /* In clock master mode, override with internal clock source. */ 333*b6052c10SRuslan Bukin if (sc->settings_register & HDSPE_SETTING_MASTER) { 334*b6052c10SRuslan Bukin if (clock->setting & HDSPE_SETTING_MASTER) 335*b6052c10SRuslan Bukin break; 336*b6052c10SRuslan Bukin } else if (clock->status == status) 337*b6052c10SRuslan Bukin break; 338*b6052c10SRuslan Bukin } 339*b6052c10SRuslan Bukin 340*b6052c10SRuslan Bukin /* Process sysctl string request. */ 341*b6052c10SRuslan Bukin if (clock->name != NULL) 342*b6052c10SRuslan Bukin strlcpy(buf, clock->name, sizeof(buf)); 343*b6052c10SRuslan Bukin return (sysctl_handle_string(oidp, buf, sizeof(buf), req)); 344*b6052c10SRuslan Bukin } 345*b6052c10SRuslan Bukin 346*b6052c10SRuslan Bukin static int 347*b6052c10SRuslan Bukin hdspe_sysctl_clock_list(SYSCTL_HANDLER_ARGS) 348*b6052c10SRuslan Bukin { 349*b6052c10SRuslan Bukin struct sc_info *sc; 350*b6052c10SRuslan Bukin struct hdspe_clock_source *clock_table, *clock; 351*b6052c10SRuslan Bukin char buf[256]; 352*b6052c10SRuslan Bukin int n; 353*b6052c10SRuslan Bukin 354*b6052c10SRuslan Bukin sc = oidp->oid_arg1; 355*b6052c10SRuslan Bukin n = 0; 356*b6052c10SRuslan Bukin 357*b6052c10SRuslan Bukin /* Select clock source table for device type. */ 358*b6052c10SRuslan Bukin if (sc->type == HDSPE_AIO) 359*b6052c10SRuslan Bukin clock_table = hdspe_clock_source_table_aio; 360*b6052c10SRuslan Bukin else if (sc->type == HDSPE_RAYDAT) 361*b6052c10SRuslan Bukin clock_table = hdspe_clock_source_table_rd; 362*b6052c10SRuslan Bukin else 363*b6052c10SRuslan Bukin return (ENXIO); 364*b6052c10SRuslan Bukin 365*b6052c10SRuslan Bukin /* List available clock sources. */ 366*b6052c10SRuslan Bukin buf[0] = 0; 367*b6052c10SRuslan Bukin for (clock = clock_table; clock->name != NULL; ++clock) { 368*b6052c10SRuslan Bukin if (n > 0) 369*b6052c10SRuslan Bukin n += strlcpy(buf + n, ",", sizeof(buf) - n); 370*b6052c10SRuslan Bukin n += strlcpy(buf + n, clock->name, sizeof(buf) - n); 371*b6052c10SRuslan Bukin } 372*b6052c10SRuslan Bukin return (sysctl_handle_string(oidp, buf, sizeof(buf), req)); 373*b6052c10SRuslan Bukin } 374*b6052c10SRuslan Bukin 375*b6052c10SRuslan Bukin static int 376*b6052c10SRuslan Bukin hdspe_sysctl_sync_status(SYSCTL_HANDLER_ARGS) 377*b6052c10SRuslan Bukin { 378*b6052c10SRuslan Bukin struct sc_info *sc; 379*b6052c10SRuslan Bukin struct hdspe_clock_source *clock_table, *clock; 380*b6052c10SRuslan Bukin char buf[256]; 381*b6052c10SRuslan Bukin char *state; 382*b6052c10SRuslan Bukin int n; 383*b6052c10SRuslan Bukin uint32_t status; 384*b6052c10SRuslan Bukin 385*b6052c10SRuslan Bukin sc = oidp->oid_arg1; 386*b6052c10SRuslan Bukin n = 0; 387*b6052c10SRuslan Bukin 388*b6052c10SRuslan Bukin /* Select sync ports table for device type. */ 389*b6052c10SRuslan Bukin if (sc->type == HDSPE_AIO) 390*b6052c10SRuslan Bukin clock_table = hdspe_clock_source_table_aio; 391*b6052c10SRuslan Bukin else if (sc->type == HDSPE_RAYDAT) 392*b6052c10SRuslan Bukin clock_table = hdspe_clock_source_table_rd; 393*b6052c10SRuslan Bukin else 394*b6052c10SRuslan Bukin return (ENXIO); 395*b6052c10SRuslan Bukin 396*b6052c10SRuslan Bukin /* Read current lock and sync bits from status register. */ 397*b6052c10SRuslan Bukin snd_mtxlock(sc->lock); 398*b6052c10SRuslan Bukin status = hdspe_read_4(sc, HDSPE_STATUS1_REG); 399*b6052c10SRuslan Bukin snd_mtxunlock(sc->lock); 400*b6052c10SRuslan Bukin 401*b6052c10SRuslan Bukin /* List clock sources with lock and sync state. */ 402*b6052c10SRuslan Bukin for (clock = clock_table; clock->name != NULL; ++clock) { 403*b6052c10SRuslan Bukin if (clock->sync_bit != 0) { 404*b6052c10SRuslan Bukin if (n > 0) 405*b6052c10SRuslan Bukin n += strlcpy(buf + n, ",", sizeof(buf) - n); 406*b6052c10SRuslan Bukin state = "none"; 407*b6052c10SRuslan Bukin if ((clock->sync_bit & status) != 0) 408*b6052c10SRuslan Bukin state = "sync"; 409*b6052c10SRuslan Bukin else if ((clock->lock_bit & status) != 0) 410*b6052c10SRuslan Bukin state = "lock"; 411*b6052c10SRuslan Bukin n += snprintf(buf + n, sizeof(buf) - n, "%s(%s)", 412*b6052c10SRuslan Bukin clock->name, state); 413*b6052c10SRuslan Bukin } 414*b6052c10SRuslan Bukin } 415*b6052c10SRuslan Bukin return (sysctl_handle_string(oidp, buf, sizeof(buf), req)); 416*b6052c10SRuslan Bukin } 417*b6052c10SRuslan Bukin 418*b6052c10SRuslan Bukin static int 419e4afd792SAlexander Motin hdspe_probe(device_t dev) 420e4afd792SAlexander Motin { 421e4afd792SAlexander Motin uint32_t rev; 422e4afd792SAlexander Motin 423e4afd792SAlexander Motin if (pci_get_vendor(dev) == PCI_VENDOR_XILINX && 424e4afd792SAlexander Motin pci_get_device(dev) == PCI_DEVICE_XILINX_HDSPE) { 425e4afd792SAlexander Motin rev = pci_get_revid(dev); 426e4afd792SAlexander Motin switch (rev) { 427e4afd792SAlexander Motin case PCI_REVISION_AIO: 428e4afd792SAlexander Motin device_set_desc(dev, "RME HDSPe AIO"); 42920a9f771SRuslan Bukin return (0); 430e4afd792SAlexander Motin case PCI_REVISION_RAYDAT: 431e4afd792SAlexander Motin device_set_desc(dev, "RME HDSPe RayDAT"); 43220a9f771SRuslan Bukin return (0); 433e4afd792SAlexander Motin } 434e4afd792SAlexander Motin } 435e4afd792SAlexander Motin 436e4afd792SAlexander Motin return (ENXIO); 437e4afd792SAlexander Motin } 438e4afd792SAlexander Motin 439e4afd792SAlexander Motin static int 440e4afd792SAlexander Motin hdspe_init(struct sc_info *sc) 441e4afd792SAlexander Motin { 442e4afd792SAlexander Motin long long period; 443e4afd792SAlexander Motin 444e4afd792SAlexander Motin /* Set latency. */ 445e4afd792SAlexander Motin sc->period = 32; 446e4afd792SAlexander Motin sc->ctrl_register = hdspe_encode_latency(7); 447e4afd792SAlexander Motin 448e4afd792SAlexander Motin /* Set rate. */ 449e4afd792SAlexander Motin sc->speed = HDSPE_SPEED_DEFAULT; 450e4afd792SAlexander Motin sc->ctrl_register &= ~HDSPE_FREQ_MASK; 451e4afd792SAlexander Motin sc->ctrl_register |= HDSPE_FREQ_MASK_DEFAULT; 452e4afd792SAlexander Motin hdspe_write_4(sc, HDSPE_CONTROL_REG, sc->ctrl_register); 453e4afd792SAlexander Motin 454e4afd792SAlexander Motin switch (sc->type) { 455*b6052c10SRuslan Bukin case HDSPE_RAYDAT: 456*b6052c10SRuslan Bukin case HDSPE_AIO: 457e4afd792SAlexander Motin period = HDSPE_FREQ_AIO; 458e4afd792SAlexander Motin break; 459e4afd792SAlexander Motin default: 460e4afd792SAlexander Motin return (ENXIO); 461e4afd792SAlexander Motin } 462e4afd792SAlexander Motin 463e4afd792SAlexander Motin /* Set DDS value. */ 464e4afd792SAlexander Motin period /= sc->speed; 465e4afd792SAlexander Motin hdspe_write_4(sc, HDSPE_FREQ_REG, period); 466e4afd792SAlexander Motin 467e4afd792SAlexander Motin /* Other settings. */ 468e4afd792SAlexander Motin sc->settings_register = 0; 469e4afd792SAlexander Motin hdspe_write_4(sc, HDSPE_SETTINGS_REG, sc->settings_register); 470e4afd792SAlexander Motin 47120a9f771SRuslan Bukin return (0); 472e4afd792SAlexander Motin } 473e4afd792SAlexander Motin 474e4afd792SAlexander Motin static int 475e4afd792SAlexander Motin hdspe_attach(device_t dev) 476e4afd792SAlexander Motin { 477e4afd792SAlexander Motin struct hdspe_channel *chan_map; 47820a9f771SRuslan Bukin struct sc_pcminfo *scp; 47920a9f771SRuslan Bukin struct sc_info *sc; 480e4afd792SAlexander Motin uint32_t rev; 481e4afd792SAlexander Motin int i, err; 482e4afd792SAlexander Motin 483e4afd792SAlexander Motin #if 0 484e4afd792SAlexander Motin device_printf(dev, "hdspe_attach()\n"); 485e4afd792SAlexander Motin #endif 486e4afd792SAlexander Motin 487e4afd792SAlexander Motin sc = device_get_softc(dev); 488e4afd792SAlexander Motin sc->lock = snd_mtxcreate(device_get_nameunit(dev), 489e4afd792SAlexander Motin "snd_hdspe softc"); 490e4afd792SAlexander Motin sc->dev = dev; 491e4afd792SAlexander Motin 492c68534f1SScott Long pci_enable_busmaster(dev); 493e4afd792SAlexander Motin rev = pci_get_revid(dev); 494e4afd792SAlexander Motin switch (rev) { 495e4afd792SAlexander Motin case PCI_REVISION_AIO: 496*b6052c10SRuslan Bukin sc->type = HDSPE_AIO; 497e4afd792SAlexander Motin chan_map = chan_map_aio; 498e4afd792SAlexander Motin break; 499e4afd792SAlexander Motin case PCI_REVISION_RAYDAT: 500*b6052c10SRuslan Bukin sc->type = HDSPE_RAYDAT; 501e4afd792SAlexander Motin chan_map = chan_map_rd; 502e4afd792SAlexander Motin break; 503e4afd792SAlexander Motin default: 50420a9f771SRuslan Bukin return (ENXIO); 505e4afd792SAlexander Motin } 506e4afd792SAlexander Motin 507e4afd792SAlexander Motin /* Allocate resources. */ 508e4afd792SAlexander Motin err = hdspe_alloc_resources(sc); 509e4afd792SAlexander Motin if (err) { 510e4afd792SAlexander Motin device_printf(dev, "Unable to allocate system resources.\n"); 51120a9f771SRuslan Bukin return (ENXIO); 512e4afd792SAlexander Motin } 513e4afd792SAlexander Motin 514e4afd792SAlexander Motin if (hdspe_init(sc) != 0) 51520a9f771SRuslan Bukin return (ENXIO); 516e4afd792SAlexander Motin 517e4afd792SAlexander Motin for (i = 0; i < HDSPE_MAX_CHANS && chan_map[i].descr != NULL; i++) { 518e4afd792SAlexander Motin scp = malloc(sizeof(struct sc_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO); 519e4afd792SAlexander Motin scp->hc = &chan_map[i]; 520e4afd792SAlexander Motin scp->sc = sc; 521e4afd792SAlexander Motin scp->dev = device_add_child(dev, "pcm", -1); 522e4afd792SAlexander Motin device_set_ivars(scp->dev, scp); 523e4afd792SAlexander Motin } 524e4afd792SAlexander Motin 525e4afd792SAlexander Motin hdspe_map_dmabuf(sc); 526e4afd792SAlexander Motin 527*b6052c10SRuslan Bukin SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 528*b6052c10SRuslan Bukin SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 529*b6052c10SRuslan Bukin "sync_status", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 530*b6052c10SRuslan Bukin sc, 0, hdspe_sysctl_sync_status, "A", 531*b6052c10SRuslan Bukin "List clock source signal lock and sync status"); 532*b6052c10SRuslan Bukin 533*b6052c10SRuslan Bukin SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 534*b6052c10SRuslan Bukin SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 535*b6052c10SRuslan Bukin "clock_source", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 536*b6052c10SRuslan Bukin sc, 0, hdspe_sysctl_clock_source, "A", 537*b6052c10SRuslan Bukin "Currently effective clock source"); 538*b6052c10SRuslan Bukin 539*b6052c10SRuslan Bukin SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 540*b6052c10SRuslan Bukin SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 541*b6052c10SRuslan Bukin "clock_preference", CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, 542*b6052c10SRuslan Bukin sc, 0, hdspe_sysctl_clock_preference, "A", 543*b6052c10SRuslan Bukin "Set 'internal' (master) or preferred autosync clock source"); 544*b6052c10SRuslan Bukin 545*b6052c10SRuslan Bukin SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 546*b6052c10SRuslan Bukin SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 547*b6052c10SRuslan Bukin "clock_list", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 548*b6052c10SRuslan Bukin sc, 0, hdspe_sysctl_clock_list, "A", 549*b6052c10SRuslan Bukin "List of supported clock sources"); 550*b6052c10SRuslan Bukin 55135d393bfSGleb Smirnoff return (bus_generic_attach(dev)); 552e4afd792SAlexander Motin } 553e4afd792SAlexander Motin 554e4afd792SAlexander Motin static void 555e4afd792SAlexander Motin hdspe_dmafree(struct sc_info *sc) 556e4afd792SAlexander Motin { 557e4afd792SAlexander Motin 558e4afd792SAlexander Motin bus_dmamap_unload(sc->dmat, sc->rmap); 559e4afd792SAlexander Motin bus_dmamap_unload(sc->dmat, sc->pmap); 560e4afd792SAlexander Motin bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap); 561e4afd792SAlexander Motin bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap); 562e4afd792SAlexander Motin sc->rbuf = sc->pbuf = NULL; 563e4afd792SAlexander Motin } 564e4afd792SAlexander Motin 565e4afd792SAlexander Motin static int 566e4afd792SAlexander Motin hdspe_detach(device_t dev) 567e4afd792SAlexander Motin { 568e4afd792SAlexander Motin struct sc_info *sc; 569e4afd792SAlexander Motin int err; 570e4afd792SAlexander Motin 571e4afd792SAlexander Motin sc = device_get_softc(dev); 572e4afd792SAlexander Motin if (sc == NULL) { 573e4afd792SAlexander Motin device_printf(dev,"Can't detach: softc is null.\n"); 57420a9f771SRuslan Bukin return (0); 575e4afd792SAlexander Motin } 576e4afd792SAlexander Motin 577e4afd792SAlexander Motin err = device_delete_children(dev); 578e4afd792SAlexander Motin if (err) 579e4afd792SAlexander Motin return (err); 580e4afd792SAlexander Motin 581e4afd792SAlexander Motin hdspe_dmafree(sc); 582e4afd792SAlexander Motin 583e4afd792SAlexander Motin if (sc->ih) 584e4afd792SAlexander Motin bus_teardown_intr(dev, sc->irq, sc->ih); 585e4afd792SAlexander Motin if (sc->dmat) 586e4afd792SAlexander Motin bus_dma_tag_destroy(sc->dmat); 587e4afd792SAlexander Motin if (sc->irq) 588e4afd792SAlexander Motin bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq); 589e4afd792SAlexander Motin if (sc->cs) 590e4afd792SAlexander Motin bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0), sc->cs); 591e4afd792SAlexander Motin if (sc->lock) 592e4afd792SAlexander Motin snd_mtxfree(sc->lock); 593e4afd792SAlexander Motin 59420a9f771SRuslan Bukin return (0); 595e4afd792SAlexander Motin } 596e4afd792SAlexander Motin 597e4afd792SAlexander Motin static device_method_t hdspe_methods[] = { 598e4afd792SAlexander Motin DEVMETHOD(device_probe, hdspe_probe), 599e4afd792SAlexander Motin DEVMETHOD(device_attach, hdspe_attach), 600e4afd792SAlexander Motin DEVMETHOD(device_detach, hdspe_detach), 601e4afd792SAlexander Motin { 0, 0 } 602e4afd792SAlexander Motin }; 603e4afd792SAlexander Motin 604e4afd792SAlexander Motin static driver_t hdspe_driver = { 605e4afd792SAlexander Motin "hdspe", 606e4afd792SAlexander Motin hdspe_methods, 607e4afd792SAlexander Motin PCM_SOFTC_SIZE, 608e4afd792SAlexander Motin }; 609e4afd792SAlexander Motin 6103390adfeSJohn Baldwin DRIVER_MODULE(snd_hdspe, pci, hdspe_driver, 0, 0); 611