15687c71dSFlorian Walpen /*- 25687c71dSFlorian Walpen * SPDX-License-Identifier: BSD-2-Clause 35687c71dSFlorian Walpen * 45687c71dSFlorian Walpen * Copyright (c) 2012-2016 Ruslan Bukin <br@bsdpad.com> 55687c71dSFlorian Walpen * Copyright (c) 2023-2024 Florian Walpen <dev@submerge.ch> 65687c71dSFlorian Walpen * All rights reserved. 75687c71dSFlorian Walpen * 85687c71dSFlorian Walpen * Redistribution and use in source and binary forms, with or without 95687c71dSFlorian Walpen * modification, are permitted provided that the following conditions 105687c71dSFlorian Walpen * are met: 115687c71dSFlorian Walpen * 1. Redistributions of source code must retain the above copyright 125687c71dSFlorian Walpen * notice, this list of conditions and the following disclaimer. 135687c71dSFlorian Walpen * 2. Redistributions in binary form must reproduce the above copyright 145687c71dSFlorian Walpen * notice, this list of conditions and the following disclaimer in the 155687c71dSFlorian Walpen * documentation and/or other materials provided with the distribution. 165687c71dSFlorian Walpen * 175687c71dSFlorian Walpen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 185687c71dSFlorian Walpen * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 195687c71dSFlorian Walpen * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 205687c71dSFlorian Walpen * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 215687c71dSFlorian Walpen * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 225687c71dSFlorian Walpen * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 235687c71dSFlorian Walpen * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 245687c71dSFlorian Walpen * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 255687c71dSFlorian Walpen * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 265687c71dSFlorian Walpen * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 275687c71dSFlorian Walpen * SUCH DAMAGE. 285687c71dSFlorian Walpen */ 295687c71dSFlorian Walpen 305687c71dSFlorian Walpen #define PCI_VENDOR_XILINX 0x10ee 315687c71dSFlorian Walpen #define PCI_DEVICE_XILINX_HDSP 0x3fc5 /* HDSP 9652 */ 325687c71dSFlorian Walpen #define PCI_REVISION_9632 0x9b 335687c71dSFlorian Walpen #define PCI_REVISION_9652 0x6c 345687c71dSFlorian Walpen 355687c71dSFlorian Walpen #define HDSP_9632 0 365687c71dSFlorian Walpen #define HDSP_9652 1 375687c71dSFlorian Walpen 385687c71dSFlorian Walpen /* Hardware mixer */ 395687c71dSFlorian Walpen #define HDSP_OUT_ENABLE_BASE 128 405687c71dSFlorian Walpen #define HDSP_IN_ENABLE_BASE 384 415687c71dSFlorian Walpen #define HDSP_MIXER_BASE 4096 425687c71dSFlorian Walpen #define HDSP_MAX_GAIN 32768 435687c71dSFlorian Walpen #define HDSP_MIN_GAIN 0 445687c71dSFlorian Walpen #define HDSP_MIX_SLOTS_9632 16 455687c71dSFlorian Walpen #define HDSP_MIX_SLOTS_9652 26 465687c71dSFlorian Walpen #define HDSP_CONTROL2_9652_MIXER (1 << 11) 475687c71dSFlorian Walpen 485687c71dSFlorian Walpen /* Buffer */ 495687c71dSFlorian Walpen #define HDSP_PAGE_ADDR_BUF_OUT 32 505687c71dSFlorian Walpen #define HDSP_PAGE_ADDR_BUF_IN 36 515687c71dSFlorian Walpen #define HDSP_BUF_POSITION_MASK 0x000FFC0 525687c71dSFlorian Walpen 535687c71dSFlorian Walpen /* Frequency */ 545687c71dSFlorian Walpen #define HDSP_FREQ_0 (1 << 6) 555687c71dSFlorian Walpen #define HDSP_FREQ_1 (1 << 7) 565687c71dSFlorian Walpen #define HDSP_FREQ_DOUBLE (1 << 8) 575687c71dSFlorian Walpen #define HDSP_FREQ_QUAD (1 << 31) 585687c71dSFlorian Walpen 595687c71dSFlorian Walpen #define HDSP_FREQ_32000 HDSP_FREQ_0 605687c71dSFlorian Walpen #define HDSP_FREQ_44100 HDSP_FREQ_1 615687c71dSFlorian Walpen #define HDSP_FREQ_48000 (HDSP_FREQ_0 | HDSP_FREQ_1) 625687c71dSFlorian Walpen #define HDSP_FREQ_MASK (HDSP_FREQ_0 | HDSP_FREQ_1 | \ 635687c71dSFlorian Walpen HDSP_FREQ_DOUBLE | HDSP_FREQ_QUAD) 645687c71dSFlorian Walpen #define HDSP_FREQ_MASK_DEFAULT HDSP_FREQ_48000 655687c71dSFlorian Walpen #define HDSP_FREQ_REG 0 665687c71dSFlorian Walpen #define HDSP_FREQ_9632 104857600000000ULL 675687c71dSFlorian Walpen #define hdsp_freq_multiplier(s) (((s) > 96000) ? 4 : \ 685687c71dSFlorian Walpen (((s) > 48000) ? 2 : 1)) 695687c71dSFlorian Walpen #define hdsp_freq_single(s) ((s) / hdsp_freq_multiplier(s)) 705687c71dSFlorian Walpen #define hdsp_freq_reg_value(s) (HDSP_FREQ_9632 / hdsp_freq_single(s)) 715687c71dSFlorian Walpen 725687c71dSFlorian Walpen #define HDSP_SPEED_DEFAULT 48000 735687c71dSFlorian Walpen 745687c71dSFlorian Walpen /* Latency */ 755687c71dSFlorian Walpen #define HDSP_LAT_0 (1 << 1) 765687c71dSFlorian Walpen #define HDSP_LAT_1 (1 << 2) 775687c71dSFlorian Walpen #define HDSP_LAT_2 (1 << 3) 785687c71dSFlorian Walpen #define HDSP_LAT_MASK (HDSP_LAT_0 | HDSP_LAT_1 | HDSP_LAT_2) 795687c71dSFlorian Walpen #define HDSP_LAT_BYTES_MAX (4096 * 4) 805687c71dSFlorian Walpen #define HDSP_LAT_BYTES_MIN (32 * 4) 815687c71dSFlorian Walpen #define hdsp_encode_latency(x) (((x)<<1) & HDSP_LAT_MASK) 825687c71dSFlorian Walpen 83*14457cf7SFlorian Walpen /* Register addresses */ 845687c71dSFlorian Walpen #define HDSP_RESET_POINTER 0 855687c71dSFlorian Walpen #define HDSP_CONTROL_REG 64 865687c71dSFlorian Walpen #define HDSP_CONTROL2_REG 256 875687c71dSFlorian Walpen #define HDSP_STATUS_REG 0 885687c71dSFlorian Walpen #define HDSP_STATUS2_REG 192 895687c71dSFlorian Walpen 90*14457cf7SFlorian Walpen /* Control register flags */ 915687c71dSFlorian Walpen #define HDSP_ENABLE (1 << 0) 925687c71dSFlorian Walpen #define HDSP_CONTROL_SPDIF_COAX (1 << 14) 935687c71dSFlorian Walpen #define HDSP_CONTROL_LINE_OUT (1 << 24) 94*14457cf7SFlorian Walpen #define HDSP_CONTROL_INPUT_GAIN0 (1 << 25) 95*14457cf7SFlorian Walpen #define HDSP_CONTROL_INPUT_GAIN1 (1 << 26) 96*14457cf7SFlorian Walpen #define HDSP_CONTROL_OUTPUT_GAIN0 (1 << 27) 97*14457cf7SFlorian Walpen #define HDSP_CONTROL_OUTPUT_GAIN1 (1 << 28) 98*14457cf7SFlorian Walpen #define HDSP_CONTROL_PHONES_GAIN0 (1 << 29) 99*14457cf7SFlorian Walpen #define HDSP_CONTROL_PHONES_GAIN1 (1 << 30) 100*14457cf7SFlorian Walpen 101*14457cf7SFlorian Walpen /* Analog input gain level */ 102*14457cf7SFlorian Walpen #define HDSP_INPUT_LEVEL_MASK (HDSP_CONTROL_INPUT_GAIN0 | \ 103*14457cf7SFlorian Walpen HDSP_CONTROL_INPUT_GAIN1) 104*14457cf7SFlorian Walpen #define HDSP_INPUT_LEVEL_LOWGAIN 0 105*14457cf7SFlorian Walpen #define HDSP_INPUT_LEVEL_PLUS4DBU (HDSP_CONTROL_INPUT_GAIN0) 106*14457cf7SFlorian Walpen #define HDSP_INPUT_LEVEL_MINUS10DBV (HDSP_CONTROL_INPUT_GAIN0 | \ 107*14457cf7SFlorian Walpen HDSP_CONTROL_INPUT_GAIN1) 108*14457cf7SFlorian Walpen 109*14457cf7SFlorian Walpen /* Analog output gain level */ 110*14457cf7SFlorian Walpen #define HDSP_OUTPUT_LEVEL_MASK (HDSP_CONTROL_OUTPUT_GAIN0 | \ 111*14457cf7SFlorian Walpen HDSP_CONTROL_OUTPUT_GAIN1) 112*14457cf7SFlorian Walpen #define HDSP_OUTPUT_LEVEL_MINUS10DBV 0 113*14457cf7SFlorian Walpen #define HDSP_OUTPUT_LEVEL_PLUS4DBU (HDSP_CONTROL_OUTPUT_GAIN0) 114*14457cf7SFlorian Walpen #define HDSP_OUTPUT_LEVEL_HIGHGAIN (HDSP_CONTROL_OUTPUT_GAIN0 | \ 115*14457cf7SFlorian Walpen HDSP_CONTROL_OUTPUT_GAIN1) 116*14457cf7SFlorian Walpen 117*14457cf7SFlorian Walpen /* Phones output gain level */ 118*14457cf7SFlorian Walpen #define HDSP_PHONES_LEVEL_MASK (HDSP_CONTROL_PHONES_GAIN0 | \ 119*14457cf7SFlorian Walpen HDSP_CONTROL_PHONES_GAIN1) 120*14457cf7SFlorian Walpen #define HDSP_PHONES_LEVEL_MINUS12DB 0 121*14457cf7SFlorian Walpen #define HDSP_PHONES_LEVEL_MINUS6DB (HDSP_CONTROL_PHONES_GAIN0) 122*14457cf7SFlorian Walpen #define HDSP_PHONES_LEVEL_0DB (HDSP_CONTROL_PHONES_GAIN0 | \ 123*14457cf7SFlorian Walpen HDSP_CONTROL_PHONES_GAIN1) 1245687c71dSFlorian Walpen 1255687c71dSFlorian Walpen /* Interrupts */ 1265687c71dSFlorian Walpen #define HDSP_AUDIO_IRQ_PENDING (1 << 0) 1275687c71dSFlorian Walpen #define HDSP_AUDIO_INT_ENABLE (1 << 5) 1285687c71dSFlorian Walpen #define HDSP_INTERRUPT_ACK 96 1295687c71dSFlorian Walpen 1305687c71dSFlorian Walpen /* Channels */ 1315687c71dSFlorian Walpen #define HDSP_MAX_SLOTS 64 /* Mono channels */ 1325687c71dSFlorian Walpen #define HDSP_MAX_CHANS (HDSP_MAX_SLOTS / 2) /* Stereo pairs */ 1335687c71dSFlorian Walpen 1345687c71dSFlorian Walpen #define HDSP_CHANBUF_SAMPLES (16 * 1024) 1355687c71dSFlorian Walpen #define HDSP_CHANBUF_SIZE (4 * HDSP_CHANBUF_SAMPLES) 1365687c71dSFlorian Walpen #define HDSP_DMASEGSIZE (HDSP_CHANBUF_SIZE * HDSP_MAX_SLOTS) 1375687c71dSFlorian Walpen 1385687c71dSFlorian Walpen #define HDSP_CHAN_9632_ADAT (1 << 0) 1395687c71dSFlorian Walpen #define HDSP_CHAN_9632_SPDIF (1 << 1) 1405687c71dSFlorian Walpen #define HDSP_CHAN_9632_LINE (1 << 2) 141e0c37c16SFlorian Walpen #define HDSP_CHAN_9632_EXT (1 << 3) /* Extension boards */ 1425687c71dSFlorian Walpen #define HDSP_CHAN_9632_ALL (HDSP_CHAN_9632_ADAT | \ 1435687c71dSFlorian Walpen HDSP_CHAN_9632_SPDIF | \ 144e0c37c16SFlorian Walpen HDSP_CHAN_9632_LINE | \ 145e0c37c16SFlorian Walpen HDSP_CHAN_9632_EXT) 1465687c71dSFlorian Walpen 1475687c71dSFlorian Walpen #define HDSP_CHAN_9652_ADAT1 (1 << 5) 1485687c71dSFlorian Walpen #define HDSP_CHAN_9652_ADAT2 (1 << 6) 1495687c71dSFlorian Walpen #define HDSP_CHAN_9652_ADAT3 (1 << 7) 1505687c71dSFlorian Walpen #define HDSP_CHAN_9652_ADAT_ALL (HDSP_CHAN_9652_ADAT1 | \ 1515687c71dSFlorian Walpen HDSP_CHAN_9652_ADAT2 | \ 1525687c71dSFlorian Walpen HDSP_CHAN_9652_ADAT3) 1535687c71dSFlorian Walpen #define HDSP_CHAN_9652_SPDIF (1 << 8) 1545687c71dSFlorian Walpen #define HDSP_CHAN_9652_ALL (HDSP_CHAN_9652_ADAT_ALL | \ 1555687c71dSFlorian Walpen HDSP_CHAN_9652_SPDIF) 1565687c71dSFlorian Walpen 1575687c71dSFlorian Walpen struct hdsp_channel { 1585687c71dSFlorian Walpen uint32_t ports; 1595687c71dSFlorian Walpen char *descr; 1605687c71dSFlorian Walpen }; 1615687c71dSFlorian Walpen 1625687c71dSFlorian Walpen enum hdsp_clock_type { 1635687c71dSFlorian Walpen HDSP_CLOCK_INTERNAL, 1645687c71dSFlorian Walpen HDSP_CLOCK_ADAT1, 1655687c71dSFlorian Walpen HDSP_CLOCK_ADAT2, 1665687c71dSFlorian Walpen HDSP_CLOCK_ADAT3, 1675687c71dSFlorian Walpen HDSP_CLOCK_SPDIF, 1685687c71dSFlorian Walpen HDSP_CLOCK_WORD, 1695687c71dSFlorian Walpen HDSP_CLOCK_ADAT_SYNC 1705687c71dSFlorian Walpen }; 1715687c71dSFlorian Walpen 1725687c71dSFlorian Walpen /* Preferred clock source. */ 1735687c71dSFlorian Walpen #define HDSP_CONTROL_MASTER (1 << 4) 1745687c71dSFlorian Walpen #define HDSP_CONTROL_CLOCK_MASK (HDSP_CONTROL_MASTER | (1 << 13) | \ 1755687c71dSFlorian Walpen (1 << 16) | (1 << 17)) 1765687c71dSFlorian Walpen #define HDSP_CONTROL_CLOCK(n) (((n & 0x04) << 11) | ((n & 0x03) << 16)) 1775687c71dSFlorian Walpen 1785687c71dSFlorian Walpen /* Autosync selected clock source. */ 1795687c71dSFlorian Walpen #define HDSP_STATUS2_CLOCK(n) ((n & 0x07) << 8) 1805687c71dSFlorian Walpen #define HDSP_STATUS2_CLOCK_MASK HDSP_STATUS2_CLOCK(0x07); 1815687c71dSFlorian Walpen 1825687c71dSFlorian Walpen struct hdsp_clock_source { 1835687c71dSFlorian Walpen char *name; 1845687c71dSFlorian Walpen enum hdsp_clock_type type; 1855687c71dSFlorian Walpen }; 1865687c71dSFlorian Walpen 1875687c71dSFlorian Walpen static MALLOC_DEFINE(M_HDSP, "hdsp", "hdsp audio"); 1885687c71dSFlorian Walpen 1895687c71dSFlorian Walpen /* Channel registers */ 1905687c71dSFlorian Walpen struct sc_chinfo { 1915687c71dSFlorian Walpen struct snd_dbuf *buffer; 1925687c71dSFlorian Walpen struct pcm_channel *channel; 1935687c71dSFlorian Walpen struct sc_pcminfo *parent; 1945687c71dSFlorian Walpen 1955687c71dSFlorian Walpen /* Channel information */ 1965687c71dSFlorian Walpen struct pcmchan_caps *caps; 1975687c71dSFlorian Walpen uint32_t cap_fmts[4]; 1985687c71dSFlorian Walpen uint32_t dir; 1995687c71dSFlorian Walpen uint32_t format; 2005687c71dSFlorian Walpen uint32_t ports; 2015687c71dSFlorian Walpen uint32_t lvol; 2025687c71dSFlorian Walpen uint32_t rvol; 2035687c71dSFlorian Walpen 2045687c71dSFlorian Walpen /* Buffer */ 2055687c71dSFlorian Walpen uint32_t *data; 2065687c71dSFlorian Walpen uint32_t size; 2075687c71dSFlorian Walpen uint32_t position; 2085687c71dSFlorian Walpen 2095687c71dSFlorian Walpen /* Flags */ 2105687c71dSFlorian Walpen uint32_t run; 2115687c71dSFlorian Walpen }; 2125687c71dSFlorian Walpen 2135687c71dSFlorian Walpen /* PCM device private data */ 2145687c71dSFlorian Walpen struct sc_pcminfo { 2155687c71dSFlorian Walpen device_t dev; 2165687c71dSFlorian Walpen uint32_t (*ih) (struct sc_pcminfo *scp); 2175687c71dSFlorian Walpen uint32_t chnum; 2185687c71dSFlorian Walpen struct sc_chinfo chan[HDSP_MAX_CHANS]; 2195687c71dSFlorian Walpen struct sc_info *sc; 2205687c71dSFlorian Walpen struct hdsp_channel *hc; 2215687c71dSFlorian Walpen }; 2225687c71dSFlorian Walpen 2235687c71dSFlorian Walpen /* HDSP device private data */ 2245687c71dSFlorian Walpen struct sc_info { 2255687c71dSFlorian Walpen device_t dev; 2265687c71dSFlorian Walpen struct mtx *lock; 2275687c71dSFlorian Walpen 2285687c71dSFlorian Walpen uint32_t ctrl_register; 2295687c71dSFlorian Walpen uint32_t type; 2305687c71dSFlorian Walpen 2315687c71dSFlorian Walpen /* Control/Status register */ 2325687c71dSFlorian Walpen struct resource *cs; 2335687c71dSFlorian Walpen int csid; 2345687c71dSFlorian Walpen bus_space_tag_t cst; 2355687c71dSFlorian Walpen bus_space_handle_t csh; 2365687c71dSFlorian Walpen 2375687c71dSFlorian Walpen struct resource *irq; 2385687c71dSFlorian Walpen int irqid; 2395687c71dSFlorian Walpen void *ih; 2405687c71dSFlorian Walpen bus_dma_tag_t dmat; 2415687c71dSFlorian Walpen 2425687c71dSFlorian Walpen /* Play/Record DMA buffers */ 2435687c71dSFlorian Walpen uint32_t *pbuf; 2445687c71dSFlorian Walpen uint32_t *rbuf; 2455687c71dSFlorian Walpen uint32_t bufsize; 2465687c71dSFlorian Walpen bus_dmamap_t pmap; 2475687c71dSFlorian Walpen bus_dmamap_t rmap; 2485687c71dSFlorian Walpen uint32_t period; 2495687c71dSFlorian Walpen uint32_t speed; 2505687c71dSFlorian Walpen uint32_t force_period; 2515687c71dSFlorian Walpen uint32_t force_speed; 2525687c71dSFlorian Walpen }; 2535687c71dSFlorian Walpen 2545687c71dSFlorian Walpen #define hdsp_read_1(sc, regno) \ 2555687c71dSFlorian Walpen bus_space_read_1((sc)->cst, (sc)->csh, (regno)) 2565687c71dSFlorian Walpen #define hdsp_read_2(sc, regno) \ 2575687c71dSFlorian Walpen bus_space_read_2((sc)->cst, (sc)->csh, (regno)) 2585687c71dSFlorian Walpen #define hdsp_read_4(sc, regno) \ 2595687c71dSFlorian Walpen bus_space_read_4((sc)->cst, (sc)->csh, (regno)) 2605687c71dSFlorian Walpen 2615687c71dSFlorian Walpen #define hdsp_write_1(sc, regno, data) \ 2625687c71dSFlorian Walpen bus_space_write_1((sc)->cst, (sc)->csh, (regno), (data)) 2635687c71dSFlorian Walpen #define hdsp_write_2(sc, regno, data) \ 2645687c71dSFlorian Walpen bus_space_write_2((sc)->cst, (sc)->csh, (regno), (data)) 2655687c71dSFlorian Walpen #define hdsp_write_4(sc, regno, data) \ 2665687c71dSFlorian Walpen bus_space_write_4((sc)->cst, (sc)->csh, (regno), (data)) 267