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/fdt/fdt_common.h> 52f0583578SRuslan Bukin #include <dev/ofw/openfirm.h> 53f0583578SRuslan Bukin #include <dev/ofw/ofw_bus.h> 54f0583578SRuslan Bukin #include <dev/ofw/ofw_bus_subr.h> 55f0583578SRuslan Bukin 56f0583578SRuslan Bukin #include <machine/bus.h> 57f0583578SRuslan Bukin #include <machine/cpu.h> 58f0583578SRuslan Bukin #include <machine/intr.h> 59f0583578SRuslan Bukin 60f0583578SRuslan Bukin #include <arm/freescale/imx/imx6_sdma.h> 61f0583578SRuslan Bukin #include <arm/freescale/imx/imx6_anatopvar.h> 62f0583578SRuslan Bukin #include <arm/freescale/imx/imx_ccmvar.h> 63f0583578SRuslan Bukin 64f0583578SRuslan Bukin #define READ4(_sc, _reg) \ 65f0583578SRuslan Bukin bus_space_read_4(_sc->bst, _sc->bsh, _reg) 66f0583578SRuslan Bukin #define WRITE4(_sc, _reg, _val) \ 67f0583578SRuslan Bukin bus_space_write_4(_sc->bst, _sc->bsh, _reg, _val) 68f0583578SRuslan Bukin 69f0583578SRuslan Bukin #define SSI_NCHANNELS 1 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; 191f0583578SRuslan Bukin int sdma_ev_rx; 192f0583578SRuslan Bukin int 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 /* 284f0583578SRuslan Bukin * Channel interface. 285f0583578SRuslan Bukin */ 286f0583578SRuslan Bukin 287f0583578SRuslan Bukin static void * 288f0583578SRuslan Bukin ssichan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, 289f0583578SRuslan Bukin struct pcm_channel *c, int dir) 290f0583578SRuslan Bukin { 291f0583578SRuslan Bukin struct sc_pcminfo *scp; 292f0583578SRuslan Bukin struct sc_chinfo *ch; 293f0583578SRuslan Bukin struct sc_info *sc; 294f0583578SRuslan Bukin 295f0583578SRuslan Bukin scp = (struct sc_pcminfo *)devinfo; 296f0583578SRuslan Bukin sc = scp->sc; 297f0583578SRuslan Bukin 298f0583578SRuslan Bukin snd_mtxlock(sc->lock); 299f0583578SRuslan Bukin ch = &scp->chan[0]; 300f0583578SRuslan Bukin ch->dir = dir; 301f0583578SRuslan Bukin ch->run = 0; 302f0583578SRuslan Bukin ch->buffer = b; 303f0583578SRuslan Bukin ch->channel = c; 304f0583578SRuslan Bukin ch->parent = scp; 305f0583578SRuslan Bukin snd_mtxunlock(sc->lock); 306f0583578SRuslan Bukin 307f0583578SRuslan Bukin if (sndbuf_setup(ch->buffer, sc->buf_base, sc->dma_size) != 0) { 308f0583578SRuslan Bukin device_printf(scp->dev, "Can't setup sndbuf.\n"); 309f0583578SRuslan Bukin return NULL; 310f0583578SRuslan Bukin } 311f0583578SRuslan Bukin 312f0583578SRuslan Bukin return ch; 313f0583578SRuslan Bukin } 314f0583578SRuslan Bukin 315f0583578SRuslan Bukin static int 316f0583578SRuslan Bukin ssichan_free(kobj_t obj, void *data) 317f0583578SRuslan Bukin { 318f0583578SRuslan Bukin struct sc_chinfo *ch = data; 319f0583578SRuslan Bukin struct sc_pcminfo *scp = ch->parent; 320f0583578SRuslan Bukin struct sc_info *sc = scp->sc; 321f0583578SRuslan Bukin 322f0583578SRuslan Bukin #if 0 323f0583578SRuslan Bukin device_printf(scp->dev, "ssichan_free()\n"); 324f0583578SRuslan Bukin #endif 325f0583578SRuslan Bukin 326f0583578SRuslan Bukin snd_mtxlock(sc->lock); 327f0583578SRuslan Bukin /* TODO: free channel buffer */ 328f0583578SRuslan Bukin snd_mtxunlock(sc->lock); 329f0583578SRuslan Bukin 330f0583578SRuslan Bukin return (0); 331f0583578SRuslan Bukin } 332f0583578SRuslan Bukin 333f0583578SRuslan Bukin static int 334f0583578SRuslan Bukin ssichan_setformat(kobj_t obj, void *data, uint32_t format) 335f0583578SRuslan Bukin { 336f0583578SRuslan Bukin struct sc_chinfo *ch = data; 337f0583578SRuslan Bukin 338f0583578SRuslan Bukin ch->format = format; 339f0583578SRuslan Bukin 340f0583578SRuslan Bukin return (0); 341f0583578SRuslan Bukin } 342f0583578SRuslan Bukin 343f0583578SRuslan Bukin static uint32_t 344f0583578SRuslan Bukin ssichan_setspeed(kobj_t obj, void *data, uint32_t speed) 345f0583578SRuslan Bukin { 346f0583578SRuslan Bukin struct sc_pcminfo *scp; 347f0583578SRuslan Bukin struct sc_chinfo *ch; 348f0583578SRuslan Bukin struct ssi_rate *sr; 349f0583578SRuslan Bukin struct sc_info *sc; 350f0583578SRuslan Bukin int threshold; 351f0583578SRuslan Bukin int i; 352f0583578SRuslan Bukin 353f0583578SRuslan Bukin ch = data; 354f0583578SRuslan Bukin scp = ch->parent; 355f0583578SRuslan Bukin sc = scp->sc; 356f0583578SRuslan Bukin 357f0583578SRuslan Bukin sr = NULL; 358f0583578SRuslan Bukin 359f0583578SRuslan Bukin /* First look for equal frequency. */ 360f0583578SRuslan Bukin for (i = 0; rate_map[i].speed != 0; i++) { 361f0583578SRuslan Bukin if (rate_map[i].speed == speed) 362f0583578SRuslan Bukin sr = &rate_map[i]; 363f0583578SRuslan Bukin } 364f0583578SRuslan Bukin 365f0583578SRuslan Bukin /* If no match, just find nearest. */ 366f0583578SRuslan Bukin if (sr == NULL) { 367f0583578SRuslan Bukin for (i = 0; rate_map[i].speed != 0; i++) { 368f0583578SRuslan Bukin sr = &rate_map[i]; 369f0583578SRuslan Bukin threshold = sr->speed + ((rate_map[i + 1].speed != 0) ? 370f0583578SRuslan Bukin ((rate_map[i + 1].speed - sr->speed) >> 1) : 0); 371f0583578SRuslan Bukin if (speed < threshold) 372f0583578SRuslan Bukin break; 373f0583578SRuslan Bukin } 374f0583578SRuslan Bukin } 375f0583578SRuslan Bukin 376f0583578SRuslan Bukin sc->sr = sr; 377f0583578SRuslan Bukin 378f0583578SRuslan Bukin ssi_configure_clock(sc); 379f0583578SRuslan Bukin 380f0583578SRuslan Bukin return (sr->speed); 381f0583578SRuslan Bukin } 382f0583578SRuslan Bukin 383f0583578SRuslan Bukin static void 384f0583578SRuslan Bukin ssi_configure_clock(struct sc_info *sc) 385f0583578SRuslan Bukin { 386f0583578SRuslan Bukin struct ssi_rate *sr; 387f0583578SRuslan Bukin 388f0583578SRuslan Bukin sr = sc->sr; 389f0583578SRuslan Bukin 390f0583578SRuslan Bukin pll4_configure_output(sr->mfi, sr->mfn, sr->mfd); 391f0583578SRuslan Bukin 392f0583578SRuslan Bukin /* Configure other dividers here, if any */ 393f0583578SRuslan Bukin } 394f0583578SRuslan Bukin 395f0583578SRuslan Bukin static uint32_t 396f0583578SRuslan Bukin ssichan_setblocksize(kobj_t obj, void *data, uint32_t blocksize) 397f0583578SRuslan Bukin { 398f0583578SRuslan Bukin struct sc_chinfo *ch = data; 399f0583578SRuslan Bukin struct sc_pcminfo *scp = ch->parent; 400f0583578SRuslan Bukin struct sc_info *sc = scp->sc; 401f0583578SRuslan Bukin 402f0583578SRuslan Bukin sndbuf_resize(ch->buffer, sc->dma_size / blocksize, blocksize); 403f0583578SRuslan Bukin 404f0583578SRuslan Bukin setup_dma(scp); 405f0583578SRuslan Bukin 406f0583578SRuslan Bukin return (sndbuf_getblksz(ch->buffer)); 407f0583578SRuslan Bukin } 408f0583578SRuslan Bukin 409f0583578SRuslan Bukin uint32_t 410f0583578SRuslan Bukin ssi_dma_intr(void *arg, int chn) 411f0583578SRuslan Bukin { 412f0583578SRuslan Bukin struct sc_pcminfo *scp; 413f0583578SRuslan Bukin struct sdma_conf *conf; 414f0583578SRuslan Bukin struct sc_chinfo *ch; 415f0583578SRuslan Bukin struct sc_info *sc; 416f0583578SRuslan Bukin int bufsize; 417f0583578SRuslan Bukin 418f0583578SRuslan Bukin scp = arg; 419f0583578SRuslan Bukin ch = &scp->chan[0]; 420f0583578SRuslan Bukin sc = scp->sc; 421f0583578SRuslan Bukin conf = sc->conf; 422f0583578SRuslan Bukin 423f0583578SRuslan Bukin bufsize = sndbuf_getsize(ch->buffer); 424f0583578SRuslan Bukin 425f0583578SRuslan Bukin sc->pos += conf->period; 426f0583578SRuslan Bukin if (sc->pos >= bufsize) 427f0583578SRuslan Bukin sc->pos -= bufsize; 428f0583578SRuslan Bukin 429f0583578SRuslan Bukin if (ch->run) 430f0583578SRuslan Bukin chn_intr(ch->channel); 431f0583578SRuslan Bukin 432f0583578SRuslan Bukin return (0); 433f0583578SRuslan Bukin } 434f0583578SRuslan Bukin 435f0583578SRuslan Bukin static int 436f0583578SRuslan Bukin find_sdma_controller(struct sc_info *sc) 437f0583578SRuslan Bukin { 438f0583578SRuslan Bukin struct sdma_softc *sdma_sc; 439f0583578SRuslan Bukin phandle_t node, sdma_node; 440f0583578SRuslan Bukin device_t sdma_dev; 441f0583578SRuslan Bukin int dts_value[8]; 442f0583578SRuslan Bukin int len; 443f0583578SRuslan Bukin 444f0583578SRuslan Bukin if ((node = ofw_bus_get_node(sc->dev)) == -1) 445f0583578SRuslan Bukin return (ENXIO); 446f0583578SRuslan Bukin 447f0583578SRuslan Bukin if ((len = OF_getproplen(node, "dmas")) <= 0) 448f0583578SRuslan Bukin return (ENXIO); 449f0583578SRuslan Bukin 450f0583578SRuslan Bukin OF_getprop(node, "dmas", &dts_value, len); 451f0583578SRuslan Bukin 452f0583578SRuslan Bukin sc->sdma_ev_rx = fdt32_to_cpu(dts_value[1]); 453f0583578SRuslan Bukin sc->sdma_ev_tx = fdt32_to_cpu(dts_value[5]); 454f0583578SRuslan Bukin 455f0583578SRuslan Bukin sdma_node = OF_node_from_xref(fdt32_to_cpu(dts_value[0])); 456f0583578SRuslan Bukin 457f0583578SRuslan Bukin sdma_sc = NULL; 458f0583578SRuslan Bukin 459f0583578SRuslan Bukin sdma_dev = devclass_get_device(devclass_find("sdma"), 0); 460f0583578SRuslan Bukin if (sdma_dev) 461f0583578SRuslan Bukin sdma_sc = device_get_softc(sdma_dev); 462f0583578SRuslan Bukin 463f0583578SRuslan Bukin if (sdma_sc == NULL) { 464f0583578SRuslan Bukin device_printf(sc->dev, "No sDMA found. Can't operate\n"); 465f0583578SRuslan Bukin return (ENXIO); 466*74b8d63dSPedro F. Giffuni } 467f0583578SRuslan Bukin 468f0583578SRuslan Bukin sc->sdma_sc = sdma_sc; 469f0583578SRuslan Bukin 470f0583578SRuslan Bukin return (0); 471f0583578SRuslan Bukin }; 472f0583578SRuslan Bukin 473f0583578SRuslan Bukin static int 474f0583578SRuslan Bukin setup_dma(struct sc_pcminfo *scp) 475f0583578SRuslan Bukin { 476f0583578SRuslan Bukin struct sdma_conf *conf; 477f0583578SRuslan Bukin struct sc_chinfo *ch; 478f0583578SRuslan Bukin struct sc_info *sc; 479f0583578SRuslan Bukin int fmt; 480f0583578SRuslan Bukin 481f0583578SRuslan Bukin ch = &scp->chan[0]; 482f0583578SRuslan Bukin sc = scp->sc; 483f0583578SRuslan Bukin conf = sc->conf; 484f0583578SRuslan Bukin 485f0583578SRuslan Bukin conf->ih = ssi_dma_intr; 486f0583578SRuslan Bukin conf->ih_user = scp; 487f0583578SRuslan Bukin conf->saddr = sc->buf_base_phys; 488f0583578SRuslan Bukin conf->daddr = rman_get_start(sc->res[0]) + SSI_STX0; 489f0583578SRuslan Bukin conf->event = sc->sdma_ev_tx; /* SDMA TX event */ 490f0583578SRuslan Bukin conf->period = sndbuf_getblksz(ch->buffer); 491f0583578SRuslan Bukin conf->num_bd = sndbuf_getblkcnt(ch->buffer); 492f0583578SRuslan Bukin 493f0583578SRuslan Bukin /* 494f0583578SRuslan Bukin * Word Length 495f0583578SRuslan Bukin * Can be 32, 24, 16 or 8 for sDMA. 496f0583578SRuslan Bukin * 497f0583578SRuslan Bukin * SSI supports 24 at max. 498f0583578SRuslan Bukin */ 499f0583578SRuslan Bukin 500f0583578SRuslan Bukin fmt = sndbuf_getfmt(ch->buffer); 501f0583578SRuslan Bukin 502f0583578SRuslan Bukin if (fmt & AFMT_16BIT) { 503f0583578SRuslan Bukin conf->word_length = 16; 504f0583578SRuslan Bukin conf->command = CMD_2BYTES; 505f0583578SRuslan Bukin } else if (fmt & AFMT_24BIT) { 506f0583578SRuslan Bukin conf->word_length = 24; 507f0583578SRuslan Bukin conf->command = CMD_3BYTES; 508f0583578SRuslan Bukin } else { 509f0583578SRuslan Bukin device_printf(sc->dev, "Unknown format\n"); 510f0583578SRuslan Bukin return (-1); 511f0583578SRuslan Bukin } 512f0583578SRuslan Bukin 513f0583578SRuslan Bukin return (0); 514f0583578SRuslan Bukin } 515f0583578SRuslan Bukin 516f0583578SRuslan Bukin static int 517f0583578SRuslan Bukin ssi_start(struct sc_pcminfo *scp) 518f0583578SRuslan Bukin { 519f0583578SRuslan Bukin struct sc_info *sc; 520f0583578SRuslan Bukin int reg; 521f0583578SRuslan Bukin 522f0583578SRuslan Bukin sc = scp->sc; 523f0583578SRuslan Bukin 524f0583578SRuslan Bukin if (sdma_configure(sc->sdma_channel, sc->conf) != 0) { 525f0583578SRuslan Bukin device_printf(sc->dev, "Can't configure sDMA\n"); 526f0583578SRuslan Bukin return (-1); 527f0583578SRuslan Bukin } 528f0583578SRuslan Bukin 529f0583578SRuslan Bukin /* Enable DMA interrupt */ 530f0583578SRuslan Bukin reg = (SIER_TDMAE); 531f0583578SRuslan Bukin WRITE4(sc, SSI_SIER, reg); 532f0583578SRuslan Bukin 533f0583578SRuslan Bukin sdma_start(sc->sdma_channel); 534f0583578SRuslan Bukin 535f0583578SRuslan Bukin return (0); 536f0583578SRuslan Bukin } 537f0583578SRuslan Bukin 538f0583578SRuslan Bukin static int 539f0583578SRuslan Bukin ssi_stop(struct sc_pcminfo *scp) 540f0583578SRuslan Bukin { 541f0583578SRuslan Bukin struct sc_info *sc; 542f0583578SRuslan Bukin int reg; 543f0583578SRuslan Bukin 544f0583578SRuslan Bukin sc = scp->sc; 545f0583578SRuslan Bukin 546f0583578SRuslan Bukin reg = READ4(sc, SSI_SIER); 547f0583578SRuslan Bukin reg &= ~(SIER_TDMAE); 548f0583578SRuslan Bukin WRITE4(sc, SSI_SIER, reg); 549f0583578SRuslan Bukin 550f0583578SRuslan Bukin sdma_stop(sc->sdma_channel); 551f0583578SRuslan Bukin 552f0583578SRuslan Bukin bzero(sc->buf_base, sc->dma_size); 553f0583578SRuslan Bukin 554f0583578SRuslan Bukin return (0); 555f0583578SRuslan Bukin } 556f0583578SRuslan Bukin 557f0583578SRuslan Bukin static int 558f0583578SRuslan Bukin ssichan_trigger(kobj_t obj, void *data, int go) 559f0583578SRuslan Bukin { 560f0583578SRuslan Bukin struct sc_pcminfo *scp; 561f0583578SRuslan Bukin struct sc_chinfo *ch; 562f0583578SRuslan Bukin struct sc_info *sc; 563f0583578SRuslan Bukin 564f0583578SRuslan Bukin ch = data; 565f0583578SRuslan Bukin scp = ch->parent; 566f0583578SRuslan Bukin sc = scp->sc; 567f0583578SRuslan Bukin 568f0583578SRuslan Bukin snd_mtxlock(sc->lock); 569f0583578SRuslan Bukin 570f0583578SRuslan Bukin switch (go) { 571f0583578SRuslan Bukin case PCMTRIG_START: 572f0583578SRuslan Bukin #if 0 573f0583578SRuslan Bukin device_printf(scp->dev, "trigger start\n"); 574f0583578SRuslan Bukin #endif 575f0583578SRuslan Bukin ch->run = 1; 576f0583578SRuslan Bukin 577f0583578SRuslan Bukin ssi_start(scp); 578f0583578SRuslan Bukin 579f0583578SRuslan Bukin break; 580f0583578SRuslan Bukin 581f0583578SRuslan Bukin case PCMTRIG_STOP: 582f0583578SRuslan Bukin case PCMTRIG_ABORT: 583f0583578SRuslan Bukin #if 0 584f0583578SRuslan Bukin device_printf(scp->dev, "trigger stop or abort\n"); 585f0583578SRuslan Bukin #endif 586f0583578SRuslan Bukin ch->run = 0; 587f0583578SRuslan Bukin 588f0583578SRuslan Bukin ssi_stop(scp); 589f0583578SRuslan Bukin 590f0583578SRuslan Bukin break; 591f0583578SRuslan Bukin } 592f0583578SRuslan Bukin 593f0583578SRuslan Bukin snd_mtxunlock(sc->lock); 594f0583578SRuslan Bukin 595f0583578SRuslan Bukin return (0); 596f0583578SRuslan Bukin } 597f0583578SRuslan Bukin 598f0583578SRuslan Bukin static uint32_t 599f0583578SRuslan Bukin ssichan_getptr(kobj_t obj, void *data) 600f0583578SRuslan Bukin { 601f0583578SRuslan Bukin struct sc_pcminfo *scp; 602f0583578SRuslan Bukin struct sc_chinfo *ch; 603f0583578SRuslan Bukin struct sc_info *sc; 604f0583578SRuslan Bukin 605f0583578SRuslan Bukin ch = data; 606f0583578SRuslan Bukin scp = ch->parent; 607f0583578SRuslan Bukin sc = scp->sc; 608f0583578SRuslan Bukin 609f0583578SRuslan Bukin return (sc->pos); 610f0583578SRuslan Bukin } 611f0583578SRuslan Bukin 612f0583578SRuslan Bukin static uint32_t ssi_pfmt[] = { 613f0583578SRuslan Bukin SND_FORMAT(AFMT_S24_LE, 2, 0), 614f0583578SRuslan Bukin 0 615f0583578SRuslan Bukin }; 616f0583578SRuslan Bukin 617f0583578SRuslan Bukin static struct pcmchan_caps ssi_pcaps = {44100, 192000, ssi_pfmt, 0}; 618f0583578SRuslan Bukin 619f0583578SRuslan Bukin static struct pcmchan_caps * 620f0583578SRuslan Bukin ssichan_getcaps(kobj_t obj, void *data) 621f0583578SRuslan Bukin { 622f0583578SRuslan Bukin 623f0583578SRuslan Bukin return (&ssi_pcaps); 624f0583578SRuslan Bukin } 625f0583578SRuslan Bukin 626f0583578SRuslan Bukin static kobj_method_t ssichan_methods[] = { 627f0583578SRuslan Bukin KOBJMETHOD(channel_init, ssichan_init), 628f0583578SRuslan Bukin KOBJMETHOD(channel_free, ssichan_free), 629f0583578SRuslan Bukin KOBJMETHOD(channel_setformat, ssichan_setformat), 630f0583578SRuslan Bukin KOBJMETHOD(channel_setspeed, ssichan_setspeed), 631f0583578SRuslan Bukin KOBJMETHOD(channel_setblocksize, ssichan_setblocksize), 632f0583578SRuslan Bukin KOBJMETHOD(channel_trigger, ssichan_trigger), 633f0583578SRuslan Bukin KOBJMETHOD(channel_getptr, ssichan_getptr), 634f0583578SRuslan Bukin KOBJMETHOD(channel_getcaps, ssichan_getcaps), 635f0583578SRuslan Bukin KOBJMETHOD_END 636f0583578SRuslan Bukin }; 637f0583578SRuslan Bukin CHANNEL_DECLARE(ssichan); 638f0583578SRuslan Bukin 639f0583578SRuslan Bukin static int 640f0583578SRuslan Bukin ssi_probe(device_t dev) 641f0583578SRuslan Bukin { 642f0583578SRuslan Bukin 643f0583578SRuslan Bukin if (!ofw_bus_status_okay(dev)) 644f0583578SRuslan Bukin return (ENXIO); 645f0583578SRuslan Bukin 646f0583578SRuslan Bukin if (!ofw_bus_is_compatible(dev, "fsl,imx6q-ssi")) 647f0583578SRuslan Bukin return (ENXIO); 648f0583578SRuslan Bukin 649f0583578SRuslan Bukin device_set_desc(dev, "i.MX6 Synchronous Serial Interface (SSI)"); 650f0583578SRuslan Bukin return (BUS_PROBE_DEFAULT); 651f0583578SRuslan Bukin } 652f0583578SRuslan Bukin 653f0583578SRuslan Bukin static void 654f0583578SRuslan Bukin ssi_intr(void *arg) 655f0583578SRuslan Bukin { 656f0583578SRuslan Bukin struct sc_pcminfo *scp; 657f0583578SRuslan Bukin struct sc_chinfo *ch; 658f0583578SRuslan Bukin struct sc_info *sc; 659f0583578SRuslan Bukin 660f0583578SRuslan Bukin scp = arg; 661f0583578SRuslan Bukin sc = scp->sc; 662f0583578SRuslan Bukin ch = &scp->chan[0]; 663f0583578SRuslan Bukin 664f0583578SRuslan Bukin /* We don't use SSI interrupt */ 665f0583578SRuslan Bukin #if 0 666f0583578SRuslan Bukin device_printf(sc->dev, "SSI Intr 0x%08x\n", 667f0583578SRuslan Bukin READ4(sc, SSI_SISR)); 668f0583578SRuslan Bukin #endif 669f0583578SRuslan Bukin } 670f0583578SRuslan Bukin 671f0583578SRuslan Bukin static void 672f0583578SRuslan Bukin setup_ssi(struct sc_info *sc) 673f0583578SRuslan Bukin { 674f0583578SRuslan Bukin int reg; 675f0583578SRuslan Bukin 676f0583578SRuslan Bukin reg = READ4(sc, SSI_STCCR); 677f0583578SRuslan Bukin reg &= ~(WL3_WL0_M << WL3_WL0_S); 678f0583578SRuslan Bukin reg |= (0xb << WL3_WL0_S); /* 24 bit */ 679f0583578SRuslan Bukin reg &= ~(DC4_DC0_M << DC4_DC0_S); 680f0583578SRuslan Bukin reg |= (1 << DC4_DC0_S); /* 2 words per frame */ 681f0583578SRuslan Bukin reg &= ~(STCCR_DIV2); /* Divide by 1 */ 682f0583578SRuslan Bukin reg &= ~(STCCR_PSR); /* Divide by 1 */ 683f0583578SRuslan Bukin reg &= ~(PM7_PM0_M << PM7_PM0_S); 684f0583578SRuslan Bukin reg |= (1 << PM7_PM0_S); /* Divide by 2 */ 685f0583578SRuslan Bukin WRITE4(sc, SSI_STCCR, reg); 686f0583578SRuslan Bukin 687f0583578SRuslan Bukin reg = READ4(sc, SSI_SFCSR); 688f0583578SRuslan Bukin reg &= ~(SFCSR_TFWM0_M << SFCSR_TFWM0_S); 689f0583578SRuslan Bukin reg |= (8 << SFCSR_TFWM0_S); /* empty slots */ 690f0583578SRuslan Bukin WRITE4(sc, SSI_SFCSR, reg); 691f0583578SRuslan Bukin 692f0583578SRuslan Bukin reg = READ4(sc, SSI_STCR); 693f0583578SRuslan Bukin reg |= (STCR_TFEN0); 694f0583578SRuslan Bukin reg &= ~(STCR_TFEN1); 695f0583578SRuslan Bukin reg &= ~(STCR_TSHFD); /* MSB */ 696f0583578SRuslan Bukin reg |= (STCR_TXBIT0); 697f0583578SRuslan Bukin reg |= (STCR_TXDIR | STCR_TFDIR); 698f0583578SRuslan Bukin reg |= (STCR_TSCKP); /* falling edge */ 699f0583578SRuslan Bukin reg |= (STCR_TFSI); 700f0583578SRuslan Bukin reg &= ~(STCR_TFSI); /* active high frame sync */ 701f0583578SRuslan Bukin reg &= ~(STCR_TFSL); 702f0583578SRuslan Bukin reg |= STCR_TEFS; 703f0583578SRuslan Bukin WRITE4(sc, SSI_STCR, reg); 704f0583578SRuslan Bukin 705f0583578SRuslan Bukin reg = READ4(sc, SSI_SCR); 706f0583578SRuslan Bukin reg &= ~(SCR_I2S_MODE_M << SCR_I2S_MODE_S); /* Not master */ 707f0583578SRuslan Bukin reg |= (SCR_SSIEN | SCR_TE); 708f0583578SRuslan Bukin reg |= (SCR_NET); 709f0583578SRuslan Bukin reg |= (SCR_SYN); 710f0583578SRuslan Bukin WRITE4(sc, SSI_SCR, reg); 711f0583578SRuslan Bukin } 712f0583578SRuslan Bukin 713f0583578SRuslan Bukin static void 714f0583578SRuslan Bukin ssi_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) 715f0583578SRuslan Bukin { 716f0583578SRuslan Bukin bus_addr_t *addr; 717f0583578SRuslan Bukin 718f0583578SRuslan Bukin if (err) 719f0583578SRuslan Bukin return; 720f0583578SRuslan Bukin 721f0583578SRuslan Bukin addr = (bus_addr_t*)arg; 722f0583578SRuslan Bukin *addr = segs[0].ds_addr; 723f0583578SRuslan Bukin } 724f0583578SRuslan Bukin 725f0583578SRuslan Bukin static int 726f0583578SRuslan Bukin ssi_attach(device_t dev) 727f0583578SRuslan Bukin { 728f0583578SRuslan Bukin char status[SND_STATUSLEN]; 729f0583578SRuslan Bukin struct sc_pcminfo *scp; 730f0583578SRuslan Bukin struct sc_info *sc; 731f0583578SRuslan Bukin int err; 732f0583578SRuslan Bukin 733f0583578SRuslan Bukin sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 734f0583578SRuslan Bukin sc->dev = dev; 735f0583578SRuslan Bukin sc->sr = &rate_map[0]; 736f0583578SRuslan Bukin sc->pos = 0; 737f0583578SRuslan Bukin sc->conf = malloc(sizeof(struct sdma_conf), M_DEVBUF, M_WAITOK | M_ZERO); 738f0583578SRuslan Bukin 739f0583578SRuslan Bukin sc->lock = snd_mtxcreate(device_get_nameunit(dev), "ssi softc"); 740f0583578SRuslan Bukin if (sc->lock == NULL) { 741f0583578SRuslan Bukin device_printf(dev, "Cant create mtx\n"); 742f0583578SRuslan Bukin return (ENXIO); 743f0583578SRuslan Bukin } 744f0583578SRuslan Bukin 745f0583578SRuslan Bukin if (bus_alloc_resources(dev, ssi_spec, sc->res)) { 746f0583578SRuslan Bukin device_printf(dev, "could not allocate resources\n"); 747f0583578SRuslan Bukin return (ENXIO); 748f0583578SRuslan Bukin } 749f0583578SRuslan Bukin 750f0583578SRuslan Bukin /* Memory interface */ 751f0583578SRuslan Bukin sc->bst = rman_get_bustag(sc->res[0]); 752f0583578SRuslan Bukin sc->bsh = rman_get_bushandle(sc->res[0]); 753f0583578SRuslan Bukin 754f0583578SRuslan Bukin /* SDMA */ 755f0583578SRuslan Bukin if (find_sdma_controller(sc)) { 756f0583578SRuslan Bukin device_printf(dev, "could not find active SDMA\n"); 757f0583578SRuslan Bukin return (ENXIO); 758f0583578SRuslan Bukin } 759f0583578SRuslan Bukin 760f0583578SRuslan Bukin /* Setup PCM */ 761f0583578SRuslan Bukin scp = malloc(sizeof(struct sc_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO); 762f0583578SRuslan Bukin scp->sc = sc; 763f0583578SRuslan Bukin scp->dev = dev; 764f0583578SRuslan Bukin 765f0583578SRuslan Bukin /* 766f0583578SRuslan Bukin * Maximum possible DMA buffer. 767f0583578SRuslan Bukin * Will be used partialy to match 24 bit word. 768f0583578SRuslan Bukin */ 769f0583578SRuslan Bukin sc->dma_size = 131072; 770f0583578SRuslan Bukin 771f0583578SRuslan Bukin /* 772f0583578SRuslan Bukin * Must use dma_size boundary as modulo feature required. 773f0583578SRuslan Bukin * Modulo feature allows setup circular buffer. 774f0583578SRuslan Bukin */ 775f0583578SRuslan Bukin 776f0583578SRuslan Bukin err = bus_dma_tag_create( 777f0583578SRuslan Bukin bus_get_dma_tag(sc->dev), 778f0583578SRuslan Bukin 4, sc->dma_size, /* alignment, boundary */ 779f0583578SRuslan Bukin BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 780f0583578SRuslan Bukin BUS_SPACE_MAXADDR, /* highaddr */ 781f0583578SRuslan Bukin NULL, NULL, /* filter, filterarg */ 782f0583578SRuslan Bukin sc->dma_size, 1, /* maxsize, nsegments */ 783f0583578SRuslan Bukin sc->dma_size, 0, /* maxsegsize, flags */ 784f0583578SRuslan Bukin NULL, NULL, /* lockfunc, lockarg */ 785f0583578SRuslan Bukin &sc->dma_tag); 786f0583578SRuslan Bukin 787f0583578SRuslan Bukin err = bus_dmamem_alloc(sc->dma_tag, (void **)&sc->buf_base, 788f0583578SRuslan Bukin BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &sc->dma_map); 789f0583578SRuslan Bukin if (err) { 790f0583578SRuslan Bukin device_printf(dev, "cannot allocate framebuffer\n"); 791f0583578SRuslan Bukin return (ENXIO); 792f0583578SRuslan Bukin } 793f0583578SRuslan Bukin 794f0583578SRuslan Bukin err = bus_dmamap_load(sc->dma_tag, sc->dma_map, sc->buf_base, 795f0583578SRuslan Bukin sc->dma_size, ssi_dmamap_cb, &sc->buf_base_phys, BUS_DMA_NOWAIT); 796f0583578SRuslan Bukin if (err) { 797f0583578SRuslan Bukin device_printf(dev, "cannot load DMA map\n"); 798f0583578SRuslan Bukin return (ENXIO); 799f0583578SRuslan Bukin } 800f0583578SRuslan Bukin 801f0583578SRuslan Bukin bzero(sc->buf_base, sc->dma_size); 802f0583578SRuslan Bukin 803f0583578SRuslan Bukin /* Setup interrupt handler */ 804f0583578SRuslan Bukin err = bus_setup_intr(dev, sc->res[1], INTR_MPSAFE | INTR_TYPE_AV, 805f0583578SRuslan Bukin NULL, ssi_intr, scp, &sc->ih); 806f0583578SRuslan Bukin if (err) { 807f0583578SRuslan Bukin device_printf(dev, "Unable to alloc interrupt resource.\n"); 808f0583578SRuslan Bukin return (ENXIO); 809f0583578SRuslan Bukin } 810f0583578SRuslan Bukin 811f0583578SRuslan Bukin pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE); 812f0583578SRuslan Bukin 813f0583578SRuslan Bukin err = pcm_register(dev, scp, 1, 0); 814f0583578SRuslan Bukin if (err) { 815f0583578SRuslan Bukin device_printf(dev, "Can't register pcm.\n"); 816f0583578SRuslan Bukin return (ENXIO); 817f0583578SRuslan Bukin } 818f0583578SRuslan Bukin 819f0583578SRuslan Bukin scp->chnum = 0; 820f0583578SRuslan Bukin pcm_addchan(dev, PCMDIR_PLAY, &ssichan_class, scp); 821f0583578SRuslan Bukin scp->chnum++; 822f0583578SRuslan Bukin 823f0583578SRuslan Bukin snprintf(status, SND_STATUSLEN, "at simplebus"); 824f0583578SRuslan Bukin pcm_setstatus(dev, status); 825f0583578SRuslan Bukin 826f0583578SRuslan Bukin mixer_init(dev, &ssimixer_class, scp); 827f0583578SRuslan Bukin setup_ssi(sc); 828f0583578SRuslan Bukin 829f0583578SRuslan Bukin imx_ccm_ssi_configure(dev); 830f0583578SRuslan Bukin 831f0583578SRuslan Bukin sc->sdma_channel = sdma_alloc(); 832f0583578SRuslan Bukin if (sc->sdma_channel < 0) { 833f0583578SRuslan Bukin device_printf(sc->dev, "Can't get sDMA channel\n"); 834f0583578SRuslan Bukin return (1); 835f0583578SRuslan Bukin } 836f0583578SRuslan Bukin 837f0583578SRuslan Bukin return (0); 838f0583578SRuslan Bukin } 839f0583578SRuslan Bukin 840f0583578SRuslan Bukin static device_method_t ssi_pcm_methods[] = { 841f0583578SRuslan Bukin DEVMETHOD(device_probe, ssi_probe), 842f0583578SRuslan Bukin DEVMETHOD(device_attach, ssi_attach), 843f0583578SRuslan Bukin { 0, 0 } 844f0583578SRuslan Bukin }; 845f0583578SRuslan Bukin 846f0583578SRuslan Bukin static driver_t ssi_pcm_driver = { 847f0583578SRuslan Bukin "pcm", 848f0583578SRuslan Bukin ssi_pcm_methods, 849f0583578SRuslan Bukin PCM_SOFTC_SIZE, 850f0583578SRuslan Bukin }; 851f0583578SRuslan Bukin 852f0583578SRuslan Bukin DRIVER_MODULE(ssi, simplebus, ssi_pcm_driver, pcm_devclass, 0, 0); 853f0583578SRuslan Bukin MODULE_DEPEND(ssi, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 854f0583578SRuslan Bukin MODULE_VERSION(ssi, 1); 855