1f0583578SRuslan Bukin /*- 2f0583578SRuslan Bukin * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com> 3f0583578SRuslan Bukin * All rights reserved. 4f0583578SRuslan Bukin * 5f0583578SRuslan Bukin * Redistribution and use in source and binary forms, with or without 6f0583578SRuslan Bukin * modification, are permitted provided that the following conditions 7f0583578SRuslan Bukin * are met: 8f0583578SRuslan Bukin * 1. Redistributions of source code must retain the above copyright 9f0583578SRuslan Bukin * notice, this list of conditions and the following disclaimer. 10f0583578SRuslan Bukin * 2. Redistributions in binary form must reproduce the above copyright 11f0583578SRuslan Bukin * notice, this list of conditions and the following disclaimer in the 12f0583578SRuslan Bukin * documentation and/or other materials provided with the distribution. 13f0583578SRuslan Bukin * 14f0583578SRuslan Bukin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15f0583578SRuslan Bukin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16f0583578SRuslan Bukin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17f0583578SRuslan Bukin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18f0583578SRuslan Bukin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19f0583578SRuslan Bukin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20f0583578SRuslan Bukin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21f0583578SRuslan Bukin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22f0583578SRuslan Bukin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23f0583578SRuslan Bukin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24f0583578SRuslan Bukin * SUCH DAMAGE. 25f0583578SRuslan Bukin */ 26f0583578SRuslan Bukin 27f0583578SRuslan Bukin /* 28f0583578SRuslan Bukin * i.MX6 Synchronous Serial Interface (SSI) 29f0583578SRuslan Bukin * 30f0583578SRuslan Bukin * Chapter 61, i.MX 6Dual/6Quad Applications Processor Reference Manual, 31f0583578SRuslan Bukin * Rev. 1, 04/2013 32f0583578SRuslan Bukin */ 33f0583578SRuslan Bukin 34f0583578SRuslan Bukin #include <sys/cdefs.h> 35f0583578SRuslan Bukin __FBSDID("$FreeBSD$"); 36f0583578SRuslan Bukin 37f0583578SRuslan Bukin #include <sys/param.h> 38f0583578SRuslan Bukin #include <sys/systm.h> 39f0583578SRuslan Bukin #include <sys/bus.h> 40f0583578SRuslan Bukin #include <sys/kernel.h> 41f0583578SRuslan Bukin #include <sys/module.h> 42f0583578SRuslan Bukin #include <sys/malloc.h> 43f0583578SRuslan Bukin #include <sys/rman.h> 44f0583578SRuslan Bukin #include <sys/timeet.h> 45f0583578SRuslan Bukin #include <sys/timetc.h> 46f0583578SRuslan Bukin 47f0583578SRuslan Bukin #include <dev/sound/pcm/sound.h> 48f0583578SRuslan Bukin #include <dev/sound/chip.h> 49f0583578SRuslan Bukin #include <mixer_if.h> 50f0583578SRuslan Bukin 51f0583578SRuslan Bukin #include <dev/ofw/openfirm.h> 52f0583578SRuslan Bukin #include <dev/ofw/ofw_bus.h> 53f0583578SRuslan Bukin #include <dev/ofw/ofw_bus_subr.h> 54f0583578SRuslan Bukin 55f0583578SRuslan Bukin #include <machine/bus.h> 56f0583578SRuslan Bukin #include <machine/cpu.h> 57f0583578SRuslan Bukin #include <machine/intr.h> 58f0583578SRuslan Bukin 59f0583578SRuslan Bukin #include <arm/freescale/imx/imx6_sdma.h> 60f0583578SRuslan Bukin #include <arm/freescale/imx/imx6_anatopvar.h> 61f0583578SRuslan Bukin #include <arm/freescale/imx/imx_ccmvar.h> 62f0583578SRuslan Bukin 63f0583578SRuslan Bukin #define READ4(_sc, _reg) \ 64f0583578SRuslan Bukin bus_space_read_4(_sc->bst, _sc->bsh, _reg) 65f0583578SRuslan Bukin #define WRITE4(_sc, _reg, _val) \ 66f0583578SRuslan Bukin bus_space_write_4(_sc->bst, _sc->bsh, _reg, _val) 67f0583578SRuslan Bukin 68f0583578SRuslan Bukin #define SSI_NCHANNELS 1 69bbcd5f00SOleksandr Tymoshenko #define DMAS_TOTAL 8 70f0583578SRuslan Bukin 71f0583578SRuslan Bukin /* i.MX6 SSI registers */ 72f0583578SRuslan Bukin 73f0583578SRuslan Bukin #define SSI_STX0 0x00 /* Transmit Data Register n */ 74f0583578SRuslan Bukin #define SSI_STX1 0x04 /* Transmit Data Register n */ 75f0583578SRuslan Bukin #define SSI_SRX0 0x08 /* Receive Data Register n */ 76f0583578SRuslan Bukin #define SSI_SRX1 0x0C /* Receive Data Register n */ 77f0583578SRuslan Bukin #define SSI_SCR 0x10 /* Control Register */ 78f0583578SRuslan Bukin #define SCR_I2S_MODE_S 5 /* I2S Mode Select. */ 79f0583578SRuslan Bukin #define SCR_I2S_MODE_M 0x3 80f0583578SRuslan Bukin #define SCR_SYN (1 << 4) 81f0583578SRuslan Bukin #define SCR_NET (1 << 3) /* Network mode */ 82f0583578SRuslan Bukin #define SCR_RE (1 << 2) /* Receive Enable. */ 83f0583578SRuslan Bukin #define SCR_TE (1 << 1) /* Transmit Enable. */ 84f0583578SRuslan Bukin #define SCR_SSIEN (1 << 0) /* SSI Enable */ 85f0583578SRuslan Bukin #define SSI_SISR 0x14 /* Interrupt Status Register */ 86f0583578SRuslan Bukin #define SSI_SIER 0x18 /* Interrupt Enable Register */ 87f0583578SRuslan Bukin #define SIER_RDMAE (1 << 22) /* Receive DMA Enable. */ 88f0583578SRuslan Bukin #define SIER_RIE (1 << 21) /* Receive Interrupt Enable. */ 89f0583578SRuslan Bukin #define SIER_TDMAE (1 << 20) /* Transmit DMA Enable. */ 90f0583578SRuslan Bukin #define SIER_TIE (1 << 19) /* Transmit Interrupt Enable. */ 91f0583578SRuslan Bukin #define SIER_TDE0IE (1 << 12) /* Transmit Data Register Empty 0. */ 92f0583578SRuslan Bukin #define SIER_TUE0IE (1 << 8) /* Transmitter Underrun Error 0. */ 93f0583578SRuslan Bukin #define SIER_TFE0IE (1 << 0) /* Transmit FIFO Empty 0 IE. */ 94f0583578SRuslan Bukin #define SSI_STCR 0x1C /* Transmit Configuration Register */ 95f0583578SRuslan Bukin #define STCR_TXBIT0 (1 << 9) /* Transmit Bit 0 shift MSB/LSB */ 96f0583578SRuslan Bukin #define STCR_TFEN1 (1 << 8) /* Transmit FIFO Enable 1. */ 97f0583578SRuslan Bukin #define STCR_TFEN0 (1 << 7) /* Transmit FIFO Enable 0. */ 98f0583578SRuslan Bukin #define STCR_TFDIR (1 << 6) /* Transmit Frame Direction. */ 99f0583578SRuslan Bukin #define STCR_TXDIR (1 << 5) /* Transmit Clock Direction. */ 100f0583578SRuslan Bukin #define STCR_TSHFD (1 << 4) /* Transmit Shift Direction. */ 101f0583578SRuslan Bukin #define STCR_TSCKP (1 << 3) /* Transmit Clock Polarity. */ 102f0583578SRuslan Bukin #define STCR_TFSI (1 << 2) /* Transmit Frame Sync Invert. */ 103f0583578SRuslan Bukin #define STCR_TFSL (1 << 1) /* Transmit Frame Sync Length. */ 104f0583578SRuslan Bukin #define STCR_TEFS (1 << 0) /* Transmit Early Frame Sync. */ 105f0583578SRuslan Bukin #define SSI_SRCR 0x20 /* Receive Configuration Register */ 106f0583578SRuslan Bukin #define SSI_STCCR 0x24 /* Transmit Clock Control Register */ 107f0583578SRuslan Bukin #define STCCR_DIV2 (1 << 18) /* Divide By 2. */ 108f0583578SRuslan Bukin #define STCCR_PSR (1 << 17) /* Divide clock by 8. */ 109f0583578SRuslan Bukin #define WL3_WL0_S 13 110f0583578SRuslan Bukin #define WL3_WL0_M 0xf 111f0583578SRuslan Bukin #define DC4_DC0_S 8 112f0583578SRuslan Bukin #define DC4_DC0_M 0x1f 113f0583578SRuslan Bukin #define PM7_PM0_S 0 114f0583578SRuslan Bukin #define PM7_PM0_M 0xff 115f0583578SRuslan Bukin #define SSI_SRCCR 0x28 /* Receive Clock Control Register */ 116f0583578SRuslan Bukin #define SSI_SFCSR 0x2C /* FIFO Control/Status Register */ 117f0583578SRuslan Bukin #define SFCSR_RFWM1_S 20 /* Receive FIFO Empty WaterMark 1 */ 118f0583578SRuslan Bukin #define SFCSR_RFWM1_M 0xf 119f0583578SRuslan Bukin #define SFCSR_TFWM1_S 16 /* Transmit FIFO Empty WaterMark 1 */ 120f0583578SRuslan Bukin #define SFCSR_TFWM1_M 0xf 121f0583578SRuslan Bukin #define SFCSR_RFWM0_S 4 /* Receive FIFO Empty WaterMark 0 */ 122f0583578SRuslan Bukin #define SFCSR_RFWM0_M 0xf 123f0583578SRuslan Bukin #define SFCSR_TFWM0_S 0 /* Transmit FIFO Empty WaterMark 0 */ 124f0583578SRuslan Bukin #define SFCSR_TFWM0_M 0xf 125f0583578SRuslan Bukin #define SSI_SACNT 0x38 /* AC97 Control Register */ 126f0583578SRuslan Bukin #define SSI_SACADD 0x3C /* AC97 Command Address Register */ 127f0583578SRuslan Bukin #define SSI_SACDAT 0x40 /* AC97 Command Data Register */ 128f0583578SRuslan Bukin #define SSI_SATAG 0x44 /* AC97 Tag Register */ 129f0583578SRuslan Bukin #define SSI_STMSK 0x48 /* Transmit Time Slot Mask Register */ 130f0583578SRuslan Bukin #define SSI_SRMSK 0x4C /* Receive Time Slot Mask Register */ 131f0583578SRuslan Bukin #define SSI_SACCST 0x50 /* AC97 Channel Status Register */ 132f0583578SRuslan Bukin #define SSI_SACCEN 0x54 /* AC97 Channel Enable Register */ 133f0583578SRuslan Bukin #define SSI_SACCDIS 0x58 /* AC97 Channel Disable Register */ 134f0583578SRuslan Bukin 135f0583578SRuslan Bukin static MALLOC_DEFINE(M_SSI, "ssi", "ssi audio"); 136f0583578SRuslan Bukin 137f0583578SRuslan Bukin uint32_t ssi_dma_intr(void *arg, int chn); 138f0583578SRuslan Bukin 139f0583578SRuslan Bukin struct ssi_rate { 140f0583578SRuslan Bukin uint32_t speed; 141f0583578SRuslan Bukin uint32_t mfi; /* PLL4 Multiplication Factor Integer */ 142f0583578SRuslan Bukin uint32_t mfn; /* PLL4 Multiplication Factor Numerator */ 143f0583578SRuslan Bukin uint32_t mfd; /* PLL4 Multiplication Factor Denominator */ 144f0583578SRuslan Bukin /* More dividers to configure can be added here */ 145f0583578SRuslan Bukin }; 146f0583578SRuslan Bukin 147f0583578SRuslan Bukin static struct ssi_rate rate_map[] = { 148f0583578SRuslan Bukin { 192000, 49, 152, 1000 }, /* PLL4 49.152 Mhz */ 149f0583578SRuslan Bukin /* TODO: add more frequences */ 150f0583578SRuslan Bukin { 0, 0 }, 151f0583578SRuslan Bukin }; 152f0583578SRuslan Bukin 153f0583578SRuslan Bukin /* 154f0583578SRuslan Bukin * i.MX6 example bit clock formula 155f0583578SRuslan Bukin * 156f0583578SRuslan Bukin * BCLK = 2 channels * 192000 hz * 24 bit = 9216000 hz = 157f0583578SRuslan Bukin * (24000000 * (49 + 152/1000.0) / 4 / 4 / 2 / 2 / 2 / 1 / 1) 158f0583578SRuslan Bukin * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ 159f0583578SRuslan Bukin * | | | | | | | | | | | 160f0583578SRuslan Bukin * Fref ------/ | | | | | | | | | | 161f0583578SRuslan Bukin * PLL4 div select -/ | | | | | | | | | 162f0583578SRuslan Bukin * PLL4 num --------------/ | | | | | | | | 163f0583578SRuslan Bukin * PLL4 denom -------------------/ | | | | | | | 164f0583578SRuslan Bukin * PLL4 post div ---------------------/ | | | | | | 165f0583578SRuslan Bukin * CCM ssi pre div (CCM_CS1CDR) ----------/ | | | | | 166f0583578SRuslan Bukin * CCM ssi post div (CCM_CS1CDR) -------------/ | | | | 167f0583578SRuslan Bukin * SSI PM7_PM0_S ---------------------------------/ | | | 168f0583578SRuslan Bukin * SSI Fixed divider ---------------------------------/ | | 169f0583578SRuslan Bukin * SSI DIV2 ----------------------------------------------/ | 170f0583578SRuslan Bukin * SSI PSR (prescaler /1 or /8) ------------------------------/ 171f0583578SRuslan Bukin * 172f0583578SRuslan Bukin * MCLK (Master clock) depends on DAC, usually BCLK * 4 173f0583578SRuslan Bukin */ 174f0583578SRuslan Bukin 175f0583578SRuslan Bukin struct sc_info { 176f0583578SRuslan Bukin struct resource *res[2]; 177f0583578SRuslan Bukin bus_space_tag_t bst; 178f0583578SRuslan Bukin bus_space_handle_t bsh; 179f0583578SRuslan Bukin device_t dev; 180f0583578SRuslan Bukin struct mtx *lock; 181f0583578SRuslan Bukin void *ih; 182f0583578SRuslan Bukin int pos; 183f0583578SRuslan Bukin int dma_size; 184f0583578SRuslan Bukin bus_dma_tag_t dma_tag; 185f0583578SRuslan Bukin bus_dmamap_t dma_map; 186f0583578SRuslan Bukin bus_addr_t buf_base_phys; 187f0583578SRuslan Bukin uint32_t *buf_base; 188f0583578SRuslan Bukin struct sdma_conf *conf; 189f0583578SRuslan Bukin struct ssi_rate *sr; 190f0583578SRuslan Bukin struct sdma_softc *sdma_sc; 191bbcd5f00SOleksandr Tymoshenko uint32_t sdma_ev_rx; 192bbcd5f00SOleksandr Tymoshenko uint32_t sdma_ev_tx; 193f0583578SRuslan Bukin int sdma_channel; 194f0583578SRuslan Bukin }; 195f0583578SRuslan Bukin 196f0583578SRuslan Bukin /* Channel registers */ 197f0583578SRuslan Bukin struct sc_chinfo { 198f0583578SRuslan Bukin struct snd_dbuf *buffer; 199f0583578SRuslan Bukin struct pcm_channel *channel; 200f0583578SRuslan Bukin struct sc_pcminfo *parent; 201f0583578SRuslan Bukin 202f0583578SRuslan Bukin /* Channel information */ 203f0583578SRuslan Bukin uint32_t dir; 204f0583578SRuslan Bukin uint32_t format; 205f0583578SRuslan Bukin 206f0583578SRuslan Bukin /* Flags */ 207f0583578SRuslan Bukin uint32_t run; 208f0583578SRuslan Bukin }; 209f0583578SRuslan Bukin 210f0583578SRuslan Bukin /* PCM device private data */ 211f0583578SRuslan Bukin struct sc_pcminfo { 212f0583578SRuslan Bukin device_t dev; 213f0583578SRuslan Bukin uint32_t (*ih)(struct sc_pcminfo *scp); 214f0583578SRuslan Bukin uint32_t chnum; 215f0583578SRuslan Bukin struct sc_chinfo chan[SSI_NCHANNELS]; 216f0583578SRuslan Bukin struct sc_info *sc; 217f0583578SRuslan Bukin }; 218f0583578SRuslan Bukin 219f0583578SRuslan Bukin static struct resource_spec ssi_spec[] = { 220f0583578SRuslan Bukin { SYS_RES_MEMORY, 0, RF_ACTIVE }, 221f0583578SRuslan Bukin { SYS_RES_IRQ, 0, RF_ACTIVE }, 222f0583578SRuslan Bukin { -1, 0 } 223f0583578SRuslan Bukin }; 224f0583578SRuslan Bukin 225f0583578SRuslan Bukin static int setup_dma(struct sc_pcminfo *scp); 226f0583578SRuslan Bukin static void setup_ssi(struct sc_info *); 227f0583578SRuslan Bukin static void ssi_configure_clock(struct sc_info *); 228f0583578SRuslan Bukin 229f0583578SRuslan Bukin /* 230f0583578SRuslan Bukin * Mixer interface. 231f0583578SRuslan Bukin */ 232f0583578SRuslan Bukin 233f0583578SRuslan Bukin static int 234f0583578SRuslan Bukin ssimixer_init(struct snd_mixer *m) 235f0583578SRuslan Bukin { 236f0583578SRuslan Bukin struct sc_pcminfo *scp; 237f0583578SRuslan Bukin struct sc_info *sc; 238f0583578SRuslan Bukin int mask; 239f0583578SRuslan Bukin 240f0583578SRuslan Bukin scp = mix_getdevinfo(m); 241f0583578SRuslan Bukin sc = scp->sc; 242f0583578SRuslan Bukin 243f0583578SRuslan Bukin if (sc == NULL) 244f0583578SRuslan Bukin return -1; 245f0583578SRuslan Bukin 246f0583578SRuslan Bukin mask = SOUND_MASK_PCM; 247f0583578SRuslan Bukin mask |= SOUND_MASK_VOLUME; 248f0583578SRuslan Bukin 249f0583578SRuslan Bukin snd_mtxlock(sc->lock); 250f0583578SRuslan Bukin pcm_setflags(scp->dev, pcm_getflags(scp->dev) | SD_F_SOFTPCMVOL); 251f0583578SRuslan Bukin mix_setdevs(m, mask); 252f0583578SRuslan Bukin snd_mtxunlock(sc->lock); 253f0583578SRuslan Bukin 254f0583578SRuslan Bukin return (0); 255f0583578SRuslan Bukin } 256f0583578SRuslan Bukin 257f0583578SRuslan Bukin static int 258f0583578SRuslan Bukin ssimixer_set(struct snd_mixer *m, unsigned dev, 259f0583578SRuslan Bukin unsigned left, unsigned right) 260f0583578SRuslan Bukin { 261f0583578SRuslan Bukin struct sc_pcminfo *scp; 262f0583578SRuslan Bukin 263f0583578SRuslan Bukin scp = mix_getdevinfo(m); 264f0583578SRuslan Bukin 265f0583578SRuslan Bukin /* Here we can configure hardware volume on our DAC */ 266f0583578SRuslan Bukin 267f0583578SRuslan Bukin #if 1 268f0583578SRuslan Bukin device_printf(scp->dev, "ssimixer_set() %d %d\n", 269f0583578SRuslan Bukin left, right); 270f0583578SRuslan Bukin #endif 271f0583578SRuslan Bukin 272f0583578SRuslan Bukin return (0); 273f0583578SRuslan Bukin } 274f0583578SRuslan Bukin 275f0583578SRuslan Bukin static kobj_method_t ssimixer_methods[] = { 276f0583578SRuslan Bukin KOBJMETHOD(mixer_init, ssimixer_init), 277f0583578SRuslan Bukin KOBJMETHOD(mixer_set, ssimixer_set), 278f0583578SRuslan Bukin KOBJMETHOD_END 279f0583578SRuslan Bukin }; 280f0583578SRuslan Bukin MIXER_DECLARE(ssimixer); 281f0583578SRuslan Bukin 282f0583578SRuslan Bukin /* 283f0583578SRuslan Bukin * Channel interface. 284f0583578SRuslan Bukin */ 285f0583578SRuslan Bukin 286f0583578SRuslan Bukin static void * 287f0583578SRuslan Bukin ssichan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, 288f0583578SRuslan Bukin struct pcm_channel *c, int dir) 289f0583578SRuslan Bukin { 290f0583578SRuslan Bukin struct sc_pcminfo *scp; 291f0583578SRuslan Bukin struct sc_chinfo *ch; 292f0583578SRuslan Bukin struct sc_info *sc; 293f0583578SRuslan Bukin 294f0583578SRuslan Bukin scp = (struct sc_pcminfo *)devinfo; 295f0583578SRuslan Bukin sc = scp->sc; 296f0583578SRuslan Bukin 297f0583578SRuslan Bukin snd_mtxlock(sc->lock); 298f0583578SRuslan Bukin ch = &scp->chan[0]; 299f0583578SRuslan Bukin ch->dir = dir; 300f0583578SRuslan Bukin ch->run = 0; 301f0583578SRuslan Bukin ch->buffer = b; 302f0583578SRuslan Bukin ch->channel = c; 303f0583578SRuslan Bukin ch->parent = scp; 304f0583578SRuslan Bukin snd_mtxunlock(sc->lock); 305f0583578SRuslan Bukin 306f0583578SRuslan Bukin if (sndbuf_setup(ch->buffer, sc->buf_base, sc->dma_size) != 0) { 307f0583578SRuslan Bukin device_printf(scp->dev, "Can't setup sndbuf.\n"); 308f0583578SRuslan Bukin return NULL; 309f0583578SRuslan Bukin } 310f0583578SRuslan Bukin 311f0583578SRuslan Bukin return ch; 312f0583578SRuslan Bukin } 313f0583578SRuslan Bukin 314f0583578SRuslan Bukin static int 315f0583578SRuslan Bukin ssichan_free(kobj_t obj, void *data) 316f0583578SRuslan Bukin { 317f0583578SRuslan Bukin struct sc_chinfo *ch = data; 318f0583578SRuslan Bukin struct sc_pcminfo *scp = ch->parent; 319f0583578SRuslan Bukin struct sc_info *sc = scp->sc; 320f0583578SRuslan Bukin 321f0583578SRuslan Bukin #if 0 322f0583578SRuslan Bukin device_printf(scp->dev, "ssichan_free()\n"); 323f0583578SRuslan Bukin #endif 324f0583578SRuslan Bukin 325f0583578SRuslan Bukin snd_mtxlock(sc->lock); 326f0583578SRuslan Bukin /* TODO: free channel buffer */ 327f0583578SRuslan Bukin snd_mtxunlock(sc->lock); 328f0583578SRuslan Bukin 329f0583578SRuslan Bukin return (0); 330f0583578SRuslan Bukin } 331f0583578SRuslan Bukin 332f0583578SRuslan Bukin static int 333f0583578SRuslan Bukin ssichan_setformat(kobj_t obj, void *data, uint32_t format) 334f0583578SRuslan Bukin { 335f0583578SRuslan Bukin struct sc_chinfo *ch = data; 336f0583578SRuslan Bukin 337f0583578SRuslan Bukin ch->format = format; 338f0583578SRuslan Bukin 339f0583578SRuslan Bukin return (0); 340f0583578SRuslan Bukin } 341f0583578SRuslan Bukin 342f0583578SRuslan Bukin static uint32_t 343f0583578SRuslan Bukin ssichan_setspeed(kobj_t obj, void *data, uint32_t speed) 344f0583578SRuslan Bukin { 345f0583578SRuslan Bukin struct sc_pcminfo *scp; 346f0583578SRuslan Bukin struct sc_chinfo *ch; 347f0583578SRuslan Bukin struct ssi_rate *sr; 348f0583578SRuslan Bukin struct sc_info *sc; 349f0583578SRuslan Bukin int threshold; 350f0583578SRuslan Bukin int i; 351f0583578SRuslan Bukin 352f0583578SRuslan Bukin ch = data; 353f0583578SRuslan Bukin scp = ch->parent; 354f0583578SRuslan Bukin sc = scp->sc; 355f0583578SRuslan Bukin 356f0583578SRuslan Bukin sr = NULL; 357f0583578SRuslan Bukin 358f0583578SRuslan Bukin /* First look for equal frequency. */ 359f0583578SRuslan Bukin for (i = 0; rate_map[i].speed != 0; i++) { 360f0583578SRuslan Bukin if (rate_map[i].speed == speed) 361f0583578SRuslan Bukin sr = &rate_map[i]; 362f0583578SRuslan Bukin } 363f0583578SRuslan Bukin 364f0583578SRuslan Bukin /* If no match, just find nearest. */ 365f0583578SRuslan Bukin if (sr == NULL) { 366f0583578SRuslan Bukin for (i = 0; rate_map[i].speed != 0; i++) { 367f0583578SRuslan Bukin sr = &rate_map[i]; 368f0583578SRuslan Bukin threshold = sr->speed + ((rate_map[i + 1].speed != 0) ? 369f0583578SRuslan Bukin ((rate_map[i + 1].speed - sr->speed) >> 1) : 0); 370f0583578SRuslan Bukin if (speed < threshold) 371f0583578SRuslan Bukin break; 372f0583578SRuslan Bukin } 373f0583578SRuslan Bukin } 374f0583578SRuslan Bukin 375f0583578SRuslan Bukin sc->sr = sr; 376f0583578SRuslan Bukin 377f0583578SRuslan Bukin ssi_configure_clock(sc); 378f0583578SRuslan Bukin 379f0583578SRuslan Bukin return (sr->speed); 380f0583578SRuslan Bukin } 381f0583578SRuslan Bukin 382f0583578SRuslan Bukin static void 383f0583578SRuslan Bukin ssi_configure_clock(struct sc_info *sc) 384f0583578SRuslan Bukin { 385f0583578SRuslan Bukin struct ssi_rate *sr; 386f0583578SRuslan Bukin 387f0583578SRuslan Bukin sr = sc->sr; 388f0583578SRuslan Bukin 389f0583578SRuslan Bukin pll4_configure_output(sr->mfi, sr->mfn, sr->mfd); 390f0583578SRuslan Bukin 391f0583578SRuslan Bukin /* Configure other dividers here, if any */ 392f0583578SRuslan Bukin } 393f0583578SRuslan Bukin 394f0583578SRuslan Bukin static uint32_t 395f0583578SRuslan Bukin ssichan_setblocksize(kobj_t obj, void *data, uint32_t blocksize) 396f0583578SRuslan Bukin { 397f0583578SRuslan Bukin struct sc_chinfo *ch = data; 398f0583578SRuslan Bukin struct sc_pcminfo *scp = ch->parent; 399f0583578SRuslan Bukin struct sc_info *sc = scp->sc; 400f0583578SRuslan Bukin 401f0583578SRuslan Bukin sndbuf_resize(ch->buffer, sc->dma_size / blocksize, blocksize); 402f0583578SRuslan Bukin 403f0583578SRuslan Bukin setup_dma(scp); 404f0583578SRuslan Bukin 405f0583578SRuslan Bukin return (sndbuf_getblksz(ch->buffer)); 406f0583578SRuslan Bukin } 407f0583578SRuslan Bukin 408f0583578SRuslan Bukin uint32_t 409f0583578SRuslan Bukin ssi_dma_intr(void *arg, int chn) 410f0583578SRuslan Bukin { 411f0583578SRuslan Bukin struct sc_pcminfo *scp; 412f0583578SRuslan Bukin struct sdma_conf *conf; 413f0583578SRuslan Bukin struct sc_chinfo *ch; 414f0583578SRuslan Bukin struct sc_info *sc; 415f0583578SRuslan Bukin int bufsize; 416f0583578SRuslan Bukin 417f0583578SRuslan Bukin scp = arg; 418f0583578SRuslan Bukin ch = &scp->chan[0]; 419f0583578SRuslan Bukin sc = scp->sc; 420f0583578SRuslan Bukin conf = sc->conf; 421f0583578SRuslan Bukin 422f0583578SRuslan Bukin bufsize = sndbuf_getsize(ch->buffer); 423f0583578SRuslan Bukin 424f0583578SRuslan Bukin sc->pos += conf->period; 425f0583578SRuslan Bukin if (sc->pos >= bufsize) 426f0583578SRuslan Bukin sc->pos -= bufsize; 427f0583578SRuslan Bukin 428f0583578SRuslan Bukin if (ch->run) 429f0583578SRuslan Bukin chn_intr(ch->channel); 430f0583578SRuslan Bukin 431f0583578SRuslan Bukin return (0); 432f0583578SRuslan Bukin } 433f0583578SRuslan Bukin 434f0583578SRuslan Bukin static int 435f0583578SRuslan Bukin find_sdma_controller(struct sc_info *sc) 436f0583578SRuslan Bukin { 437f0583578SRuslan Bukin struct sdma_softc *sdma_sc; 4381624badaSJohn Baldwin phandle_t node; 439f0583578SRuslan Bukin device_t sdma_dev; 440bbcd5f00SOleksandr Tymoshenko pcell_t dts_value[DMAS_TOTAL]; 441f0583578SRuslan Bukin int len; 442f0583578SRuslan Bukin 443f0583578SRuslan Bukin if ((node = ofw_bus_get_node(sc->dev)) == -1) 444f0583578SRuslan Bukin return (ENXIO); 445f0583578SRuslan Bukin 446f0583578SRuslan Bukin if ((len = OF_getproplen(node, "dmas")) <= 0) 447f0583578SRuslan Bukin return (ENXIO); 448f0583578SRuslan Bukin 449bbcd5f00SOleksandr Tymoshenko if (len != sizeof(dts_value)) { 450bbcd5f00SOleksandr Tymoshenko device_printf(sc->dev, 451bbcd5f00SOleksandr Tymoshenko "\"dmas\" property length is invalid: %d (expected %d)", 452bbcd5f00SOleksandr Tymoshenko len, sizeof(dts_value)); 453bbcd5f00SOleksandr Tymoshenko return (ENXIO); 454bbcd5f00SOleksandr Tymoshenko } 455bbcd5f00SOleksandr Tymoshenko 456bbcd5f00SOleksandr Tymoshenko OF_getencprop(node, "dmas", dts_value, sizeof(dts_value)); 457f0583578SRuslan Bukin 4589783ea5cSAndrew Turner sc->sdma_ev_rx = dts_value[1]; 4599783ea5cSAndrew Turner sc->sdma_ev_tx = dts_value[5]; 460f0583578SRuslan Bukin 461f0583578SRuslan Bukin sdma_sc = NULL; 462f0583578SRuslan Bukin 463f0583578SRuslan Bukin sdma_dev = devclass_get_device(devclass_find("sdma"), 0); 464f0583578SRuslan Bukin if (sdma_dev) 465f0583578SRuslan Bukin sdma_sc = device_get_softc(sdma_dev); 466f0583578SRuslan Bukin 467f0583578SRuslan Bukin if (sdma_sc == NULL) { 468f0583578SRuslan Bukin device_printf(sc->dev, "No sDMA found. Can't operate\n"); 469f0583578SRuslan Bukin return (ENXIO); 47074b8d63dSPedro F. Giffuni } 471f0583578SRuslan Bukin 472f0583578SRuslan Bukin sc->sdma_sc = sdma_sc; 473f0583578SRuslan Bukin 474f0583578SRuslan Bukin return (0); 475f0583578SRuslan Bukin }; 476f0583578SRuslan Bukin 477f0583578SRuslan Bukin static int 478f0583578SRuslan Bukin setup_dma(struct sc_pcminfo *scp) 479f0583578SRuslan Bukin { 480f0583578SRuslan Bukin struct sdma_conf *conf; 481f0583578SRuslan Bukin struct sc_chinfo *ch; 482f0583578SRuslan Bukin struct sc_info *sc; 483f0583578SRuslan Bukin int fmt; 484f0583578SRuslan Bukin 485f0583578SRuslan Bukin ch = &scp->chan[0]; 486f0583578SRuslan Bukin sc = scp->sc; 487f0583578SRuslan Bukin conf = sc->conf; 488f0583578SRuslan Bukin 489f0583578SRuslan Bukin conf->ih = ssi_dma_intr; 490f0583578SRuslan Bukin conf->ih_user = scp; 491f0583578SRuslan Bukin conf->saddr = sc->buf_base_phys; 492f0583578SRuslan Bukin conf->daddr = rman_get_start(sc->res[0]) + SSI_STX0; 493f0583578SRuslan Bukin conf->event = sc->sdma_ev_tx; /* SDMA TX event */ 494f0583578SRuslan Bukin conf->period = sndbuf_getblksz(ch->buffer); 495f0583578SRuslan Bukin conf->num_bd = sndbuf_getblkcnt(ch->buffer); 496f0583578SRuslan Bukin 497f0583578SRuslan Bukin /* 498f0583578SRuslan Bukin * Word Length 499f0583578SRuslan Bukin * Can be 32, 24, 16 or 8 for sDMA. 500f0583578SRuslan Bukin * 501f0583578SRuslan Bukin * SSI supports 24 at max. 502f0583578SRuslan Bukin */ 503f0583578SRuslan Bukin 504f0583578SRuslan Bukin fmt = sndbuf_getfmt(ch->buffer); 505f0583578SRuslan Bukin 506f0583578SRuslan Bukin if (fmt & AFMT_16BIT) { 507f0583578SRuslan Bukin conf->word_length = 16; 508f0583578SRuslan Bukin conf->command = CMD_2BYTES; 509f0583578SRuslan Bukin } else if (fmt & AFMT_24BIT) { 510f0583578SRuslan Bukin conf->word_length = 24; 511f0583578SRuslan Bukin conf->command = CMD_3BYTES; 512f0583578SRuslan Bukin } else { 513f0583578SRuslan Bukin device_printf(sc->dev, "Unknown format\n"); 514f0583578SRuslan Bukin return (-1); 515f0583578SRuslan Bukin } 516f0583578SRuslan Bukin 517f0583578SRuslan Bukin return (0); 518f0583578SRuslan Bukin } 519f0583578SRuslan Bukin 520f0583578SRuslan Bukin static int 521f0583578SRuslan Bukin ssi_start(struct sc_pcminfo *scp) 522f0583578SRuslan Bukin { 523f0583578SRuslan Bukin struct sc_info *sc; 524f0583578SRuslan Bukin int reg; 525f0583578SRuslan Bukin 526f0583578SRuslan Bukin sc = scp->sc; 527f0583578SRuslan Bukin 528f0583578SRuslan Bukin if (sdma_configure(sc->sdma_channel, sc->conf) != 0) { 529f0583578SRuslan Bukin device_printf(sc->dev, "Can't configure sDMA\n"); 530f0583578SRuslan Bukin return (-1); 531f0583578SRuslan Bukin } 532f0583578SRuslan Bukin 533f0583578SRuslan Bukin /* Enable DMA interrupt */ 534f0583578SRuslan Bukin reg = (SIER_TDMAE); 535f0583578SRuslan Bukin WRITE4(sc, SSI_SIER, reg); 536f0583578SRuslan Bukin 537f0583578SRuslan Bukin sdma_start(sc->sdma_channel); 538f0583578SRuslan Bukin 539f0583578SRuslan Bukin return (0); 540f0583578SRuslan Bukin } 541f0583578SRuslan Bukin 542f0583578SRuslan Bukin static int 543f0583578SRuslan Bukin ssi_stop(struct sc_pcminfo *scp) 544f0583578SRuslan Bukin { 545f0583578SRuslan Bukin struct sc_info *sc; 546f0583578SRuslan Bukin int reg; 547f0583578SRuslan Bukin 548f0583578SRuslan Bukin sc = scp->sc; 549f0583578SRuslan Bukin 550f0583578SRuslan Bukin reg = READ4(sc, SSI_SIER); 551f0583578SRuslan Bukin reg &= ~(SIER_TDMAE); 552f0583578SRuslan Bukin WRITE4(sc, SSI_SIER, reg); 553f0583578SRuslan Bukin 554f0583578SRuslan Bukin sdma_stop(sc->sdma_channel); 555f0583578SRuslan Bukin 556f0583578SRuslan Bukin bzero(sc->buf_base, sc->dma_size); 557f0583578SRuslan Bukin 558f0583578SRuslan Bukin return (0); 559f0583578SRuslan Bukin } 560f0583578SRuslan Bukin 561f0583578SRuslan Bukin static int 562f0583578SRuslan Bukin ssichan_trigger(kobj_t obj, void *data, int go) 563f0583578SRuslan Bukin { 564f0583578SRuslan Bukin struct sc_pcminfo *scp; 565f0583578SRuslan Bukin struct sc_chinfo *ch; 566f0583578SRuslan Bukin struct sc_info *sc; 567f0583578SRuslan Bukin 568f0583578SRuslan Bukin ch = data; 569f0583578SRuslan Bukin scp = ch->parent; 570f0583578SRuslan Bukin sc = scp->sc; 571f0583578SRuslan Bukin 572f0583578SRuslan Bukin snd_mtxlock(sc->lock); 573f0583578SRuslan Bukin 574f0583578SRuslan Bukin switch (go) { 575f0583578SRuslan Bukin case PCMTRIG_START: 576f0583578SRuslan Bukin #if 0 577f0583578SRuslan Bukin device_printf(scp->dev, "trigger start\n"); 578f0583578SRuslan Bukin #endif 579f0583578SRuslan Bukin ch->run = 1; 580f0583578SRuslan Bukin 581f0583578SRuslan Bukin ssi_start(scp); 582f0583578SRuslan Bukin 583f0583578SRuslan Bukin break; 584f0583578SRuslan Bukin 585f0583578SRuslan Bukin case PCMTRIG_STOP: 586f0583578SRuslan Bukin case PCMTRIG_ABORT: 587f0583578SRuslan Bukin #if 0 588f0583578SRuslan Bukin device_printf(scp->dev, "trigger stop or abort\n"); 589f0583578SRuslan Bukin #endif 590f0583578SRuslan Bukin ch->run = 0; 591f0583578SRuslan Bukin 592f0583578SRuslan Bukin ssi_stop(scp); 593f0583578SRuslan Bukin 594f0583578SRuslan Bukin break; 595f0583578SRuslan Bukin } 596f0583578SRuslan Bukin 597f0583578SRuslan Bukin snd_mtxunlock(sc->lock); 598f0583578SRuslan Bukin 599f0583578SRuslan Bukin return (0); 600f0583578SRuslan Bukin } 601f0583578SRuslan Bukin 602f0583578SRuslan Bukin static uint32_t 603f0583578SRuslan Bukin ssichan_getptr(kobj_t obj, void *data) 604f0583578SRuslan Bukin { 605f0583578SRuslan Bukin struct sc_pcminfo *scp; 606f0583578SRuslan Bukin struct sc_chinfo *ch; 607f0583578SRuslan Bukin struct sc_info *sc; 608f0583578SRuslan Bukin 609f0583578SRuslan Bukin ch = data; 610f0583578SRuslan Bukin scp = ch->parent; 611f0583578SRuslan Bukin sc = scp->sc; 612f0583578SRuslan Bukin 613f0583578SRuslan Bukin return (sc->pos); 614f0583578SRuslan Bukin } 615f0583578SRuslan Bukin 616f0583578SRuslan Bukin static uint32_t ssi_pfmt[] = { 617f0583578SRuslan Bukin SND_FORMAT(AFMT_S24_LE, 2, 0), 618f0583578SRuslan Bukin 0 619f0583578SRuslan Bukin }; 620f0583578SRuslan Bukin 621f0583578SRuslan Bukin static struct pcmchan_caps ssi_pcaps = {44100, 192000, ssi_pfmt, 0}; 622f0583578SRuslan Bukin 623f0583578SRuslan Bukin static struct pcmchan_caps * 624f0583578SRuslan Bukin ssichan_getcaps(kobj_t obj, void *data) 625f0583578SRuslan Bukin { 626f0583578SRuslan Bukin 627f0583578SRuslan Bukin return (&ssi_pcaps); 628f0583578SRuslan Bukin } 629f0583578SRuslan Bukin 630f0583578SRuslan Bukin static kobj_method_t ssichan_methods[] = { 631f0583578SRuslan Bukin KOBJMETHOD(channel_init, ssichan_init), 632f0583578SRuslan Bukin KOBJMETHOD(channel_free, ssichan_free), 633f0583578SRuslan Bukin KOBJMETHOD(channel_setformat, ssichan_setformat), 634f0583578SRuslan Bukin KOBJMETHOD(channel_setspeed, ssichan_setspeed), 635f0583578SRuslan Bukin KOBJMETHOD(channel_setblocksize, ssichan_setblocksize), 636f0583578SRuslan Bukin KOBJMETHOD(channel_trigger, ssichan_trigger), 637f0583578SRuslan Bukin KOBJMETHOD(channel_getptr, ssichan_getptr), 638f0583578SRuslan Bukin KOBJMETHOD(channel_getcaps, ssichan_getcaps), 639f0583578SRuslan Bukin KOBJMETHOD_END 640f0583578SRuslan Bukin }; 641f0583578SRuslan Bukin CHANNEL_DECLARE(ssichan); 642f0583578SRuslan Bukin 643f0583578SRuslan Bukin static int 644f0583578SRuslan Bukin ssi_probe(device_t dev) 645f0583578SRuslan Bukin { 646f0583578SRuslan Bukin 647f0583578SRuslan Bukin if (!ofw_bus_status_okay(dev)) 648f0583578SRuslan Bukin return (ENXIO); 649f0583578SRuslan Bukin 650f0583578SRuslan Bukin if (!ofw_bus_is_compatible(dev, "fsl,imx6q-ssi")) 651f0583578SRuslan Bukin return (ENXIO); 652f0583578SRuslan Bukin 653f0583578SRuslan Bukin device_set_desc(dev, "i.MX6 Synchronous Serial Interface (SSI)"); 654f0583578SRuslan Bukin return (BUS_PROBE_DEFAULT); 655f0583578SRuslan Bukin } 656f0583578SRuslan Bukin 657f0583578SRuslan Bukin static void 658f0583578SRuslan Bukin ssi_intr(void *arg) 659f0583578SRuslan Bukin { 6601624badaSJohn Baldwin #if 0 661f0583578SRuslan Bukin struct sc_pcminfo *scp; 662f0583578SRuslan Bukin struct sc_info *sc; 663f0583578SRuslan Bukin 664f0583578SRuslan Bukin scp = arg; 665f0583578SRuslan Bukin sc = scp->sc; 6661624badaSJohn Baldwin #endif 667f0583578SRuslan Bukin 668f0583578SRuslan Bukin /* We don't use SSI interrupt */ 669f0583578SRuslan Bukin #if 0 6701624badaSJohn Baldwin device_printf(scp->sc->dev, "SSI Intr 0x%08x\n", 671f0583578SRuslan Bukin READ4(sc, SSI_SISR)); 672f0583578SRuslan Bukin #endif 673f0583578SRuslan Bukin } 674f0583578SRuslan Bukin 675f0583578SRuslan Bukin static void 676f0583578SRuslan Bukin setup_ssi(struct sc_info *sc) 677f0583578SRuslan Bukin { 678f0583578SRuslan Bukin int reg; 679f0583578SRuslan Bukin 680f0583578SRuslan Bukin reg = READ4(sc, SSI_STCCR); 681f0583578SRuslan Bukin reg &= ~(WL3_WL0_M << WL3_WL0_S); 682f0583578SRuslan Bukin reg |= (0xb << WL3_WL0_S); /* 24 bit */ 683f0583578SRuslan Bukin reg &= ~(DC4_DC0_M << DC4_DC0_S); 684f0583578SRuslan Bukin reg |= (1 << DC4_DC0_S); /* 2 words per frame */ 685f0583578SRuslan Bukin reg &= ~(STCCR_DIV2); /* Divide by 1 */ 686f0583578SRuslan Bukin reg &= ~(STCCR_PSR); /* Divide by 1 */ 687f0583578SRuslan Bukin reg &= ~(PM7_PM0_M << PM7_PM0_S); 688f0583578SRuslan Bukin reg |= (1 << PM7_PM0_S); /* Divide by 2 */ 689f0583578SRuslan Bukin WRITE4(sc, SSI_STCCR, reg); 690f0583578SRuslan Bukin 691f0583578SRuslan Bukin reg = READ4(sc, SSI_SFCSR); 692f0583578SRuslan Bukin reg &= ~(SFCSR_TFWM0_M << SFCSR_TFWM0_S); 693f0583578SRuslan Bukin reg |= (8 << SFCSR_TFWM0_S); /* empty slots */ 694f0583578SRuslan Bukin WRITE4(sc, SSI_SFCSR, reg); 695f0583578SRuslan Bukin 696f0583578SRuslan Bukin reg = READ4(sc, SSI_STCR); 697f0583578SRuslan Bukin reg |= (STCR_TFEN0); 698f0583578SRuslan Bukin reg &= ~(STCR_TFEN1); 699f0583578SRuslan Bukin reg &= ~(STCR_TSHFD); /* MSB */ 700f0583578SRuslan Bukin reg |= (STCR_TXBIT0); 701f0583578SRuslan Bukin reg |= (STCR_TXDIR | STCR_TFDIR); 702f0583578SRuslan Bukin reg |= (STCR_TSCKP); /* falling edge */ 703f0583578SRuslan Bukin reg |= (STCR_TFSI); 704f0583578SRuslan Bukin reg &= ~(STCR_TFSI); /* active high frame sync */ 705f0583578SRuslan Bukin reg &= ~(STCR_TFSL); 706f0583578SRuslan Bukin reg |= STCR_TEFS; 707f0583578SRuslan Bukin WRITE4(sc, SSI_STCR, reg); 708f0583578SRuslan Bukin 709f0583578SRuslan Bukin reg = READ4(sc, SSI_SCR); 710f0583578SRuslan Bukin reg &= ~(SCR_I2S_MODE_M << SCR_I2S_MODE_S); /* Not master */ 711f0583578SRuslan Bukin reg |= (SCR_SSIEN | SCR_TE); 712f0583578SRuslan Bukin reg |= (SCR_NET); 713f0583578SRuslan Bukin reg |= (SCR_SYN); 714f0583578SRuslan Bukin WRITE4(sc, SSI_SCR, reg); 715f0583578SRuslan Bukin } 716f0583578SRuslan Bukin 717f0583578SRuslan Bukin static void 718f0583578SRuslan Bukin ssi_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) 719f0583578SRuslan Bukin { 720f0583578SRuslan Bukin bus_addr_t *addr; 721f0583578SRuslan Bukin 722f0583578SRuslan Bukin if (err) 723f0583578SRuslan Bukin return; 724f0583578SRuslan Bukin 725f0583578SRuslan Bukin addr = (bus_addr_t*)arg; 726f0583578SRuslan Bukin *addr = segs[0].ds_addr; 727f0583578SRuslan Bukin } 728f0583578SRuslan Bukin 729f0583578SRuslan Bukin static int 730f0583578SRuslan Bukin ssi_attach(device_t dev) 731f0583578SRuslan Bukin { 732f0583578SRuslan Bukin char status[SND_STATUSLEN]; 733f0583578SRuslan Bukin struct sc_pcminfo *scp; 734f0583578SRuslan Bukin struct sc_info *sc; 735f0583578SRuslan Bukin int err; 736f0583578SRuslan Bukin 737f0583578SRuslan Bukin sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 738f0583578SRuslan Bukin sc->dev = dev; 739f0583578SRuslan Bukin sc->sr = &rate_map[0]; 740f0583578SRuslan Bukin sc->pos = 0; 741f0583578SRuslan Bukin sc->conf = malloc(sizeof(struct sdma_conf), M_DEVBUF, M_WAITOK | M_ZERO); 742f0583578SRuslan Bukin 743f0583578SRuslan Bukin sc->lock = snd_mtxcreate(device_get_nameunit(dev), "ssi softc"); 744f0583578SRuslan Bukin if (sc->lock == NULL) { 745255eff3bSPedro F. Giffuni device_printf(dev, "Can't create mtx\n"); 746f0583578SRuslan Bukin return (ENXIO); 747f0583578SRuslan Bukin } 748f0583578SRuslan Bukin 749f0583578SRuslan Bukin if (bus_alloc_resources(dev, ssi_spec, sc->res)) { 750f0583578SRuslan Bukin device_printf(dev, "could not allocate resources\n"); 751f0583578SRuslan Bukin return (ENXIO); 752f0583578SRuslan Bukin } 753f0583578SRuslan Bukin 754f0583578SRuslan Bukin /* Memory interface */ 755f0583578SRuslan Bukin sc->bst = rman_get_bustag(sc->res[0]); 756f0583578SRuslan Bukin sc->bsh = rman_get_bushandle(sc->res[0]); 757f0583578SRuslan Bukin 758f0583578SRuslan Bukin /* SDMA */ 759f0583578SRuslan Bukin if (find_sdma_controller(sc)) { 760f0583578SRuslan Bukin device_printf(dev, "could not find active SDMA\n"); 761f0583578SRuslan Bukin return (ENXIO); 762f0583578SRuslan Bukin } 763f0583578SRuslan Bukin 764f0583578SRuslan Bukin /* Setup PCM */ 765f0583578SRuslan Bukin scp = malloc(sizeof(struct sc_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO); 766f0583578SRuslan Bukin scp->sc = sc; 767f0583578SRuslan Bukin scp->dev = dev; 768f0583578SRuslan Bukin 769f0583578SRuslan Bukin /* 770f0583578SRuslan Bukin * Maximum possible DMA buffer. 771255eff3bSPedro F. Giffuni * Will be used partially to match 24 bit word. 772f0583578SRuslan Bukin */ 773f0583578SRuslan Bukin sc->dma_size = 131072; 774f0583578SRuslan Bukin 775f0583578SRuslan Bukin /* 776f0583578SRuslan Bukin * Must use dma_size boundary as modulo feature required. 777f0583578SRuslan Bukin * Modulo feature allows setup circular buffer. 778f0583578SRuslan Bukin */ 779f0583578SRuslan Bukin 780f0583578SRuslan Bukin err = bus_dma_tag_create( 781f0583578SRuslan Bukin bus_get_dma_tag(sc->dev), 782f0583578SRuslan Bukin 4, sc->dma_size, /* alignment, boundary */ 783f0583578SRuslan Bukin BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 784f0583578SRuslan Bukin BUS_SPACE_MAXADDR, /* highaddr */ 785f0583578SRuslan Bukin NULL, NULL, /* filter, filterarg */ 786f0583578SRuslan Bukin sc->dma_size, 1, /* maxsize, nsegments */ 787f0583578SRuslan Bukin sc->dma_size, 0, /* maxsegsize, flags */ 788f0583578SRuslan Bukin NULL, NULL, /* lockfunc, lockarg */ 789f0583578SRuslan Bukin &sc->dma_tag); 790f0583578SRuslan Bukin 791f0583578SRuslan Bukin err = bus_dmamem_alloc(sc->dma_tag, (void **)&sc->buf_base, 792f0583578SRuslan Bukin BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &sc->dma_map); 793f0583578SRuslan Bukin if (err) { 794f0583578SRuslan Bukin device_printf(dev, "cannot allocate framebuffer\n"); 795f0583578SRuslan Bukin return (ENXIO); 796f0583578SRuslan Bukin } 797f0583578SRuslan Bukin 798f0583578SRuslan Bukin err = bus_dmamap_load(sc->dma_tag, sc->dma_map, sc->buf_base, 799f0583578SRuslan Bukin sc->dma_size, ssi_dmamap_cb, &sc->buf_base_phys, BUS_DMA_NOWAIT); 800f0583578SRuslan Bukin if (err) { 801f0583578SRuslan Bukin device_printf(dev, "cannot load DMA map\n"); 802f0583578SRuslan Bukin return (ENXIO); 803f0583578SRuslan Bukin } 804f0583578SRuslan Bukin 805f0583578SRuslan Bukin bzero(sc->buf_base, sc->dma_size); 806f0583578SRuslan Bukin 807f0583578SRuslan Bukin /* Setup interrupt handler */ 808f0583578SRuslan Bukin err = bus_setup_intr(dev, sc->res[1], INTR_MPSAFE | INTR_TYPE_AV, 809f0583578SRuslan Bukin NULL, ssi_intr, scp, &sc->ih); 810f0583578SRuslan Bukin if (err) { 811f0583578SRuslan Bukin device_printf(dev, "Unable to alloc interrupt resource.\n"); 812f0583578SRuslan Bukin return (ENXIO); 813f0583578SRuslan Bukin } 814f0583578SRuslan Bukin 815f0583578SRuslan Bukin pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE); 816f0583578SRuslan Bukin 817f0583578SRuslan Bukin err = pcm_register(dev, scp, 1, 0); 818f0583578SRuslan Bukin if (err) { 819f0583578SRuslan Bukin device_printf(dev, "Can't register pcm.\n"); 820f0583578SRuslan Bukin return (ENXIO); 821f0583578SRuslan Bukin } 822f0583578SRuslan Bukin 823f0583578SRuslan Bukin scp->chnum = 0; 824f0583578SRuslan Bukin pcm_addchan(dev, PCMDIR_PLAY, &ssichan_class, scp); 825f0583578SRuslan Bukin scp->chnum++; 826f0583578SRuslan Bukin 827f0583578SRuslan Bukin snprintf(status, SND_STATUSLEN, "at simplebus"); 828f0583578SRuslan Bukin pcm_setstatus(dev, status); 829f0583578SRuslan Bukin 830f0583578SRuslan Bukin mixer_init(dev, &ssimixer_class, scp); 831f0583578SRuslan Bukin setup_ssi(sc); 832f0583578SRuslan Bukin 833f0583578SRuslan Bukin imx_ccm_ssi_configure(dev); 834f0583578SRuslan Bukin 835f0583578SRuslan Bukin sc->sdma_channel = sdma_alloc(); 836f0583578SRuslan Bukin if (sc->sdma_channel < 0) { 837f0583578SRuslan Bukin device_printf(sc->dev, "Can't get sDMA channel\n"); 838f0583578SRuslan Bukin return (1); 839f0583578SRuslan Bukin } 840f0583578SRuslan Bukin 841f0583578SRuslan Bukin return (0); 842f0583578SRuslan Bukin } 843f0583578SRuslan Bukin 844f0583578SRuslan Bukin static device_method_t ssi_pcm_methods[] = { 845f0583578SRuslan Bukin DEVMETHOD(device_probe, ssi_probe), 846f0583578SRuslan Bukin DEVMETHOD(device_attach, ssi_attach), 847f0583578SRuslan Bukin { 0, 0 } 848f0583578SRuslan Bukin }; 849f0583578SRuslan Bukin 850f0583578SRuslan Bukin static driver_t ssi_pcm_driver = { 851f0583578SRuslan Bukin "pcm", 852f0583578SRuslan Bukin ssi_pcm_methods, 853f0583578SRuslan Bukin PCM_SOFTC_SIZE, 854f0583578SRuslan Bukin }; 855f0583578SRuslan Bukin 856*2287364eSJohn Baldwin DRIVER_MODULE(ssi, simplebus, ssi_pcm_driver, 0, 0); 857f0583578SRuslan Bukin MODULE_DEPEND(ssi, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 858bbcd5f00SOleksandr Tymoshenko MODULE_DEPEND(ssi, sdma, 0, 0, 0); 859f0583578SRuslan Bukin MODULE_VERSION(ssi, 1); 860