1277644Sbr/*- 2277644Sbr * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com> 3277644Sbr * All rights reserved. 4277644Sbr * 5277644Sbr * Redistribution and use in source and binary forms, with or without 6277644Sbr * modification, are permitted provided that the following conditions 7277644Sbr * are met: 8277644Sbr * 1. Redistributions of source code must retain the above copyright 9277644Sbr * notice, this list of conditions and the following disclaimer. 10277644Sbr * 2. Redistributions in binary form must reproduce the above copyright 11277644Sbr * notice, this list of conditions and the following disclaimer in the 12277644Sbr * documentation and/or other materials provided with the distribution. 13277644Sbr * 14277644Sbr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15277644Sbr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16277644Sbr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17277644Sbr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18277644Sbr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19277644Sbr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20277644Sbr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21277644Sbr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22277644Sbr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23277644Sbr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24277644Sbr * SUCH DAMAGE. 25277644Sbr */ 26277644Sbr 27277644Sbr/* 28277644Sbr * i.MX6 Synchronous Serial Interface (SSI) 29277644Sbr * 30277644Sbr * Chapter 61, i.MX 6Dual/6Quad Applications Processor Reference Manual, 31277644Sbr * Rev. 1, 04/2013 32277644Sbr */ 33277644Sbr 34277644Sbr#include <sys/cdefs.h> 35277644Sbr__FBSDID("$FreeBSD: releng/10.3/sys/arm/freescale/imx/imx6_ssi.c 283500 2015-05-24 18:59:45Z ian $"); 36277644Sbr 37277644Sbr#include <sys/param.h> 38277644Sbr#include <sys/systm.h> 39277644Sbr#include <sys/bus.h> 40277644Sbr#include <sys/kernel.h> 41277644Sbr#include <sys/module.h> 42277644Sbr#include <sys/malloc.h> 43277644Sbr#include <sys/rman.h> 44277644Sbr#include <sys/timeet.h> 45277644Sbr#include <sys/timetc.h> 46277644Sbr 47277644Sbr#include <dev/sound/pcm/sound.h> 48277644Sbr#include <dev/sound/chip.h> 49277644Sbr#include <mixer_if.h> 50277644Sbr 51277644Sbr#include <dev/fdt/fdt_common.h> 52277644Sbr#include <dev/ofw/openfirm.h> 53277644Sbr#include <dev/ofw/ofw_bus.h> 54277644Sbr#include <dev/ofw/ofw_bus_subr.h> 55277644Sbr 56277644Sbr#include <machine/bus.h> 57277644Sbr#include <machine/fdt.h> 58277644Sbr#include <machine/cpu.h> 59277644Sbr#include <machine/intr.h> 60277644Sbr 61277644Sbr#include <arm/freescale/imx/imx6_sdma.h> 62277644Sbr#include <arm/freescale/imx/imx6_anatopvar.h> 63277644Sbr#include <arm/freescale/imx/imx_ccmvar.h> 64277644Sbr 65277644Sbr#define READ4(_sc, _reg) \ 66277644Sbr bus_space_read_4(_sc->bst, _sc->bsh, _reg) 67277644Sbr#define WRITE4(_sc, _reg, _val) \ 68277644Sbr bus_space_write_4(_sc->bst, _sc->bsh, _reg, _val) 69277644Sbr 70277644Sbr#define SSI_NCHANNELS 1 71277644Sbr 72277644Sbr/* i.MX6 SSI registers */ 73277644Sbr 74277644Sbr#define SSI_STX0 0x00 /* Transmit Data Register n */ 75277644Sbr#define SSI_STX1 0x04 /* Transmit Data Register n */ 76277644Sbr#define SSI_SRX0 0x08 /* Receive Data Register n */ 77277644Sbr#define SSI_SRX1 0x0C /* Receive Data Register n */ 78277644Sbr#define SSI_SCR 0x10 /* Control Register */ 79277644Sbr#define SCR_I2S_MODE_S 5 /* I2S Mode Select. */ 80277644Sbr#define SCR_I2S_MODE_M 0x3 81277644Sbr#define SCR_SYN (1 << 4) 82277644Sbr#define SCR_NET (1 << 3) /* Network mode */ 83277644Sbr#define SCR_RE (1 << 2) /* Receive Enable. */ 84277644Sbr#define SCR_TE (1 << 1) /* Transmit Enable. */ 85277644Sbr#define SCR_SSIEN (1 << 0) /* SSI Enable */ 86277644Sbr#define SSI_SISR 0x14 /* Interrupt Status Register */ 87277644Sbr#define SSI_SIER 0x18 /* Interrupt Enable Register */ 88277644Sbr#define SIER_RDMAE (1 << 22) /* Receive DMA Enable. */ 89277644Sbr#define SIER_RIE (1 << 21) /* Receive Interrupt Enable. */ 90277644Sbr#define SIER_TDMAE (1 << 20) /* Transmit DMA Enable. */ 91277644Sbr#define SIER_TIE (1 << 19) /* Transmit Interrupt Enable. */ 92277644Sbr#define SIER_TDE0IE (1 << 12) /* Transmit Data Register Empty 0. */ 93277644Sbr#define SIER_TUE0IE (1 << 8) /* Transmitter Underrun Error 0. */ 94277644Sbr#define SIER_TFE0IE (1 << 0) /* Transmit FIFO Empty 0 IE. */ 95277644Sbr#define SSI_STCR 0x1C /* Transmit Configuration Register */ 96277644Sbr#define STCR_TXBIT0 (1 << 9) /* Transmit Bit 0 shift MSB/LSB */ 97277644Sbr#define STCR_TFEN1 (1 << 8) /* Transmit FIFO Enable 1. */ 98277644Sbr#define STCR_TFEN0 (1 << 7) /* Transmit FIFO Enable 0. */ 99277644Sbr#define STCR_TFDIR (1 << 6) /* Transmit Frame Direction. */ 100277644Sbr#define STCR_TXDIR (1 << 5) /* Transmit Clock Direction. */ 101277644Sbr#define STCR_TSHFD (1 << 4) /* Transmit Shift Direction. */ 102277644Sbr#define STCR_TSCKP (1 << 3) /* Transmit Clock Polarity. */ 103277644Sbr#define STCR_TFSI (1 << 2) /* Transmit Frame Sync Invert. */ 104277644Sbr#define STCR_TFSL (1 << 1) /* Transmit Frame Sync Length. */ 105277644Sbr#define STCR_TEFS (1 << 0) /* Transmit Early Frame Sync. */ 106277644Sbr#define SSI_SRCR 0x20 /* Receive Configuration Register */ 107277644Sbr#define SSI_STCCR 0x24 /* Transmit Clock Control Register */ 108277644Sbr#define STCCR_DIV2 (1 << 18) /* Divide By 2. */ 109277644Sbr#define STCCR_PSR (1 << 17) /* Divide clock by 8. */ 110277644Sbr#define WL3_WL0_S 13 111277644Sbr#define WL3_WL0_M 0xf 112277644Sbr#define DC4_DC0_S 8 113277644Sbr#define DC4_DC0_M 0x1f 114277644Sbr#define PM7_PM0_S 0 115277644Sbr#define PM7_PM0_M 0xff 116277644Sbr#define SSI_SRCCR 0x28 /* Receive Clock Control Register */ 117277644Sbr#define SSI_SFCSR 0x2C /* FIFO Control/Status Register */ 118277644Sbr#define SFCSR_RFWM1_S 20 /* Receive FIFO Empty WaterMark 1 */ 119277644Sbr#define SFCSR_RFWM1_M 0xf 120277644Sbr#define SFCSR_TFWM1_S 16 /* Transmit FIFO Empty WaterMark 1 */ 121277644Sbr#define SFCSR_TFWM1_M 0xf 122277644Sbr#define SFCSR_RFWM0_S 4 /* Receive FIFO Empty WaterMark 0 */ 123277644Sbr#define SFCSR_RFWM0_M 0xf 124277644Sbr#define SFCSR_TFWM0_S 0 /* Transmit FIFO Empty WaterMark 0 */ 125277644Sbr#define SFCSR_TFWM0_M 0xf 126277644Sbr#define SSI_SACNT 0x38 /* AC97 Control Register */ 127277644Sbr#define SSI_SACADD 0x3C /* AC97 Command Address Register */ 128277644Sbr#define SSI_SACDAT 0x40 /* AC97 Command Data Register */ 129277644Sbr#define SSI_SATAG 0x44 /* AC97 Tag Register */ 130277644Sbr#define SSI_STMSK 0x48 /* Transmit Time Slot Mask Register */ 131277644Sbr#define SSI_SRMSK 0x4C /* Receive Time Slot Mask Register */ 132277644Sbr#define SSI_SACCST 0x50 /* AC97 Channel Status Register */ 133277644Sbr#define SSI_SACCEN 0x54 /* AC97 Channel Enable Register */ 134277644Sbr#define SSI_SACCDIS 0x58 /* AC97 Channel Disable Register */ 135277644Sbr 136277644Sbrstatic MALLOC_DEFINE(M_SSI, "ssi", "ssi audio"); 137277644Sbr 138277644Sbruint32_t ssi_dma_intr(void *arg, int chn); 139277644Sbr 140277644Sbrstruct ssi_rate { 141277644Sbr uint32_t speed; 142277644Sbr uint32_t mfi; /* PLL4 Multiplication Factor Integer */ 143277644Sbr uint32_t mfn; /* PLL4 Multiplication Factor Numerator */ 144277644Sbr uint32_t mfd; /* PLL4 Multiplication Factor Denominator */ 145277644Sbr /* More dividers to configure can be added here */ 146277644Sbr}; 147277644Sbr 148277644Sbrstatic struct ssi_rate rate_map[] = { 149277644Sbr { 192000, 49, 152, 1000 }, /* PLL4 49.152 Mhz */ 150277644Sbr /* TODO: add more frequences */ 151277644Sbr { 0, 0 }, 152277644Sbr}; 153277644Sbr 154277644Sbr/* 155277644Sbr * i.MX6 example bit clock formula 156277644Sbr * 157277644Sbr * BCLK = 2 channels * 192000 hz * 24 bit = 9216000 hz = 158277644Sbr * (24000000 * (49 + 152/1000.0) / 4 / 4 / 2 / 2 / 2 / 1 / 1) 159277644Sbr * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ 160277644Sbr * | | | | | | | | | | | 161277644Sbr * Fref ------/ | | | | | | | | | | 162277644Sbr * PLL4 div select -/ | | | | | | | | | 163277644Sbr * PLL4 num --------------/ | | | | | | | | 164277644Sbr * PLL4 denom -------------------/ | | | | | | | 165277644Sbr * PLL4 post div ---------------------/ | | | | | | 166277644Sbr * CCM ssi pre div (CCM_CS1CDR) ----------/ | | | | | 167277644Sbr * CCM ssi post div (CCM_CS1CDR) -------------/ | | | | 168277644Sbr * SSI PM7_PM0_S ---------------------------------/ | | | 169277644Sbr * SSI Fixed divider ---------------------------------/ | | 170277644Sbr * SSI DIV2 ----------------------------------------------/ | 171277644Sbr * SSI PSR (prescaler /1 or /8) ------------------------------/ 172277644Sbr * 173277644Sbr * MCLK (Master clock) depends on DAC, usually BCLK * 4 174277644Sbr */ 175277644Sbr 176277644Sbrstruct sc_info { 177277644Sbr struct resource *res[2]; 178277644Sbr bus_space_tag_t bst; 179277644Sbr bus_space_handle_t bsh; 180277644Sbr device_t dev; 181277644Sbr struct mtx *lock; 182277644Sbr void *ih; 183277644Sbr int pos; 184277644Sbr int dma_size; 185277644Sbr bus_dma_tag_t dma_tag; 186277644Sbr bus_dmamap_t dma_map; 187277644Sbr bus_addr_t buf_base_phys; 188277644Sbr uint32_t *buf_base; 189277644Sbr struct sdma_conf *conf; 190277644Sbr struct ssi_rate *sr; 191277644Sbr struct sdma_softc *sdma_sc; 192277644Sbr int sdma_ev_rx; 193277644Sbr int sdma_ev_tx; 194277644Sbr int sdma_channel; 195277644Sbr}; 196277644Sbr 197277644Sbr/* Channel registers */ 198277644Sbrstruct sc_chinfo { 199277644Sbr struct snd_dbuf *buffer; 200277644Sbr struct pcm_channel *channel; 201277644Sbr struct sc_pcminfo *parent; 202277644Sbr 203277644Sbr /* Channel information */ 204277644Sbr uint32_t dir; 205277644Sbr uint32_t format; 206277644Sbr 207277644Sbr /* Flags */ 208277644Sbr uint32_t run; 209277644Sbr}; 210277644Sbr 211277644Sbr/* PCM device private data */ 212277644Sbrstruct sc_pcminfo { 213277644Sbr device_t dev; 214277644Sbr uint32_t (*ih)(struct sc_pcminfo *scp); 215277644Sbr uint32_t chnum; 216277644Sbr struct sc_chinfo chan[SSI_NCHANNELS]; 217277644Sbr struct sc_info *sc; 218277644Sbr}; 219277644Sbr 220277644Sbrstatic struct resource_spec ssi_spec[] = { 221277644Sbr { SYS_RES_MEMORY, 0, RF_ACTIVE }, 222277644Sbr { SYS_RES_IRQ, 0, RF_ACTIVE }, 223277644Sbr { -1, 0 } 224277644Sbr}; 225277644Sbr 226277644Sbrstatic int setup_dma(struct sc_pcminfo *scp); 227277644Sbrstatic void setup_ssi(struct sc_info *); 228277644Sbrstatic void ssi_configure_clock(struct sc_info *); 229277644Sbr 230277644Sbr/* 231277644Sbr * Mixer interface. 232277644Sbr */ 233277644Sbr 234277644Sbrstatic int 235277644Sbrssimixer_init(struct snd_mixer *m) 236277644Sbr{ 237277644Sbr struct sc_pcminfo *scp; 238277644Sbr struct sc_info *sc; 239277644Sbr int mask; 240277644Sbr 241277644Sbr scp = mix_getdevinfo(m); 242277644Sbr sc = scp->sc; 243277644Sbr 244277644Sbr if (sc == NULL) 245277644Sbr return -1; 246277644Sbr 247277644Sbr mask = SOUND_MASK_PCM; 248277644Sbr mask |= SOUND_MASK_VOLUME; 249277644Sbr 250277644Sbr snd_mtxlock(sc->lock); 251277644Sbr pcm_setflags(scp->dev, pcm_getflags(scp->dev) | SD_F_SOFTPCMVOL); 252277644Sbr mix_setdevs(m, mask); 253277644Sbr snd_mtxunlock(sc->lock); 254277644Sbr 255277644Sbr return (0); 256277644Sbr} 257277644Sbr 258277644Sbrstatic int 259277644Sbrssimixer_set(struct snd_mixer *m, unsigned dev, 260277644Sbr unsigned left, unsigned right) 261277644Sbr{ 262277644Sbr struct sc_pcminfo *scp; 263277644Sbr 264277644Sbr scp = mix_getdevinfo(m); 265277644Sbr 266277644Sbr /* Here we can configure hardware volume on our DAC */ 267277644Sbr 268277644Sbr#if 1 269277644Sbr device_printf(scp->dev, "ssimixer_set() %d %d\n", 270277644Sbr left, right); 271277644Sbr#endif 272277644Sbr 273277644Sbr return (0); 274277644Sbr} 275277644Sbr 276277644Sbrstatic kobj_method_t ssimixer_methods[] = { 277277644Sbr KOBJMETHOD(mixer_init, ssimixer_init), 278277644Sbr KOBJMETHOD(mixer_set, ssimixer_set), 279277644Sbr KOBJMETHOD_END 280277644Sbr}; 281277644SbrMIXER_DECLARE(ssimixer); 282277644Sbr 283277644Sbr 284277644Sbr/* 285277644Sbr * Channel interface. 286277644Sbr */ 287277644Sbr 288277644Sbrstatic void * 289277644Sbrssichan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, 290277644Sbr struct pcm_channel *c, int dir) 291277644Sbr{ 292277644Sbr struct sc_pcminfo *scp; 293277644Sbr struct sc_chinfo *ch; 294277644Sbr struct sc_info *sc; 295277644Sbr 296277644Sbr scp = (struct sc_pcminfo *)devinfo; 297277644Sbr sc = scp->sc; 298277644Sbr 299277644Sbr snd_mtxlock(sc->lock); 300277644Sbr ch = &scp->chan[0]; 301277644Sbr ch->dir = dir; 302277644Sbr ch->run = 0; 303277644Sbr ch->buffer = b; 304277644Sbr ch->channel = c; 305277644Sbr ch->parent = scp; 306277644Sbr snd_mtxunlock(sc->lock); 307277644Sbr 308277644Sbr if (sndbuf_setup(ch->buffer, sc->buf_base, sc->dma_size) != 0) { 309277644Sbr device_printf(scp->dev, "Can't setup sndbuf.\n"); 310277644Sbr return NULL; 311277644Sbr } 312277644Sbr 313277644Sbr return ch; 314277644Sbr} 315277644Sbr 316277644Sbrstatic int 317277644Sbrssichan_free(kobj_t obj, void *data) 318277644Sbr{ 319277644Sbr struct sc_chinfo *ch = data; 320277644Sbr struct sc_pcminfo *scp = ch->parent; 321277644Sbr struct sc_info *sc = scp->sc; 322277644Sbr 323277644Sbr#if 0 324277644Sbr device_printf(scp->dev, "ssichan_free()\n"); 325277644Sbr#endif 326277644Sbr 327277644Sbr snd_mtxlock(sc->lock); 328277644Sbr /* TODO: free channel buffer */ 329277644Sbr snd_mtxunlock(sc->lock); 330277644Sbr 331277644Sbr return (0); 332277644Sbr} 333277644Sbr 334277644Sbrstatic int 335277644Sbrssichan_setformat(kobj_t obj, void *data, uint32_t format) 336277644Sbr{ 337277644Sbr struct sc_chinfo *ch = data; 338277644Sbr 339277644Sbr ch->format = format; 340277644Sbr 341277644Sbr return (0); 342277644Sbr} 343277644Sbr 344277644Sbrstatic uint32_t 345277644Sbrssichan_setspeed(kobj_t obj, void *data, uint32_t speed) 346277644Sbr{ 347277644Sbr struct sc_pcminfo *scp; 348277644Sbr struct sc_chinfo *ch; 349277644Sbr struct ssi_rate *sr; 350277644Sbr struct sc_info *sc; 351277644Sbr int threshold; 352277644Sbr int i; 353277644Sbr 354277644Sbr ch = data; 355277644Sbr scp = ch->parent; 356277644Sbr sc = scp->sc; 357277644Sbr 358277644Sbr sr = NULL; 359277644Sbr 360277644Sbr /* First look for equal frequency. */ 361277644Sbr for (i = 0; rate_map[i].speed != 0; i++) { 362277644Sbr if (rate_map[i].speed == speed) 363277644Sbr sr = &rate_map[i]; 364277644Sbr } 365277644Sbr 366277644Sbr /* If no match, just find nearest. */ 367277644Sbr if (sr == NULL) { 368277644Sbr for (i = 0; rate_map[i].speed != 0; i++) { 369277644Sbr sr = &rate_map[i]; 370277644Sbr threshold = sr->speed + ((rate_map[i + 1].speed != 0) ? 371277644Sbr ((rate_map[i + 1].speed - sr->speed) >> 1) : 0); 372277644Sbr if (speed < threshold) 373277644Sbr break; 374277644Sbr } 375277644Sbr } 376277644Sbr 377277644Sbr sc->sr = sr; 378277644Sbr 379277644Sbr ssi_configure_clock(sc); 380277644Sbr 381277644Sbr return (sr->speed); 382277644Sbr} 383277644Sbr 384277644Sbrstatic void 385277644Sbrssi_configure_clock(struct sc_info *sc) 386277644Sbr{ 387277644Sbr struct ssi_rate *sr; 388277644Sbr 389277644Sbr sr = sc->sr; 390277644Sbr 391277644Sbr pll4_configure_output(sr->mfi, sr->mfn, sr->mfd); 392277644Sbr 393277644Sbr /* Configure other dividers here, if any */ 394277644Sbr} 395277644Sbr 396277644Sbrstatic uint32_t 397277644Sbrssichan_setblocksize(kobj_t obj, void *data, uint32_t blocksize) 398277644Sbr{ 399277644Sbr struct sc_chinfo *ch = data; 400277644Sbr struct sc_pcminfo *scp = ch->parent; 401277644Sbr struct sc_info *sc = scp->sc; 402277644Sbr 403277644Sbr sndbuf_resize(ch->buffer, sc->dma_size / blocksize, blocksize); 404277644Sbr 405277644Sbr setup_dma(scp); 406277644Sbr 407277644Sbr return (sndbuf_getblksz(ch->buffer)); 408277644Sbr} 409277644Sbr 410277644Sbruint32_t 411277644Sbrssi_dma_intr(void *arg, int chn) 412277644Sbr{ 413277644Sbr struct sc_pcminfo *scp; 414277644Sbr struct sdma_conf *conf; 415277644Sbr struct sc_chinfo *ch; 416277644Sbr struct sc_info *sc; 417277644Sbr int bufsize; 418277644Sbr 419277644Sbr scp = arg; 420277644Sbr ch = &scp->chan[0]; 421277644Sbr sc = scp->sc; 422277644Sbr conf = sc->conf; 423277644Sbr 424277644Sbr bufsize = sndbuf_getsize(ch->buffer); 425277644Sbr 426277644Sbr sc->pos += conf->period; 427277644Sbr if (sc->pos >= bufsize) 428277644Sbr sc->pos -= bufsize; 429277644Sbr 430277644Sbr if (ch->run) 431277644Sbr chn_intr(ch->channel); 432277644Sbr 433277644Sbr return (0); 434277644Sbr} 435277644Sbr 436277644Sbrstatic int 437277644Sbrfind_sdma_controller(struct sc_info *sc) 438277644Sbr{ 439277644Sbr struct sdma_softc *sdma_sc; 440277644Sbr phandle_t node, sdma_node; 441277644Sbr device_t sdma_dev; 442277644Sbr int dts_value[8]; 443277644Sbr int len; 444277644Sbr 445277644Sbr if ((node = ofw_bus_get_node(sc->dev)) == -1) 446277644Sbr return (ENXIO); 447277644Sbr 448277644Sbr if ((len = OF_getproplen(node, "dmas")) <= 0) 449277644Sbr return (ENXIO); 450277644Sbr 451277644Sbr OF_getprop(node, "dmas", &dts_value, len); 452277644Sbr 453277644Sbr sc->sdma_ev_rx = fdt32_to_cpu(dts_value[1]); 454277644Sbr sc->sdma_ev_tx = fdt32_to_cpu(dts_value[5]); 455277644Sbr 456277644Sbr sdma_node = OF_node_from_xref(fdt32_to_cpu(dts_value[0])); 457277644Sbr 458277644Sbr sdma_sc = NULL; 459277644Sbr 460277644Sbr sdma_dev = devclass_get_device(devclass_find("sdma"), 0); 461277644Sbr if (sdma_dev) 462277644Sbr sdma_sc = device_get_softc(sdma_dev); 463277644Sbr 464277644Sbr if (sdma_sc == NULL) { 465277644Sbr device_printf(sc->dev, "No sDMA found. Can't operate\n"); 466277644Sbr return (ENXIO); 467277644Sbr }; 468277644Sbr 469277644Sbr sc->sdma_sc = sdma_sc; 470277644Sbr 471277644Sbr return (0); 472277644Sbr}; 473277644Sbr 474277644Sbrstatic int 475277644Sbrsetup_dma(struct sc_pcminfo *scp) 476277644Sbr{ 477277644Sbr struct sdma_conf *conf; 478277644Sbr struct sc_chinfo *ch; 479277644Sbr struct sc_info *sc; 480277644Sbr int fmt; 481277644Sbr 482277644Sbr ch = &scp->chan[0]; 483277644Sbr sc = scp->sc; 484277644Sbr conf = sc->conf; 485277644Sbr 486277644Sbr conf->ih = ssi_dma_intr; 487277644Sbr conf->ih_user = scp; 488277644Sbr conf->saddr = sc->buf_base_phys; 489277644Sbr conf->daddr = rman_get_start(sc->res[0]) + SSI_STX0; 490277644Sbr conf->event = sc->sdma_ev_tx; /* SDMA TX event */ 491277644Sbr conf->period = sndbuf_getblksz(ch->buffer); 492277644Sbr conf->num_bd = sndbuf_getblkcnt(ch->buffer); 493277644Sbr 494277644Sbr /* 495277644Sbr * Word Length 496277644Sbr * Can be 32, 24, 16 or 8 for sDMA. 497277644Sbr * 498277644Sbr * SSI supports 24 at max. 499277644Sbr */ 500277644Sbr 501277644Sbr fmt = sndbuf_getfmt(ch->buffer); 502277644Sbr 503277644Sbr if (fmt & AFMT_16BIT) { 504277644Sbr conf->word_length = 16; 505277644Sbr conf->command = CMD_2BYTES; 506277644Sbr } else if (fmt & AFMT_24BIT) { 507277644Sbr conf->word_length = 24; 508277644Sbr conf->command = CMD_3BYTES; 509277644Sbr } else { 510277644Sbr device_printf(sc->dev, "Unknown format\n"); 511277644Sbr return (-1); 512277644Sbr } 513277644Sbr 514277644Sbr return (0); 515277644Sbr} 516277644Sbr 517277644Sbrstatic int 518277644Sbrssi_start(struct sc_pcminfo *scp) 519277644Sbr{ 520277644Sbr struct sc_info *sc; 521277644Sbr int reg; 522277644Sbr 523277644Sbr sc = scp->sc; 524277644Sbr 525277644Sbr if (sdma_configure(sc->sdma_channel, sc->conf) != 0) { 526277644Sbr device_printf(sc->dev, "Can't configure sDMA\n"); 527277644Sbr return (-1); 528277644Sbr } 529277644Sbr 530277644Sbr /* Enable DMA interrupt */ 531277644Sbr reg = (SIER_TDMAE); 532277644Sbr WRITE4(sc, SSI_SIER, reg); 533277644Sbr 534277644Sbr sdma_start(sc->sdma_channel); 535277644Sbr 536277644Sbr return (0); 537277644Sbr} 538277644Sbr 539277644Sbrstatic int 540277644Sbrssi_stop(struct sc_pcminfo *scp) 541277644Sbr{ 542277644Sbr struct sc_info *sc; 543277644Sbr int reg; 544277644Sbr 545277644Sbr sc = scp->sc; 546277644Sbr 547277644Sbr reg = READ4(sc, SSI_SIER); 548277644Sbr reg &= ~(SIER_TDMAE); 549277644Sbr WRITE4(sc, SSI_SIER, reg); 550277644Sbr 551277644Sbr sdma_stop(sc->sdma_channel); 552277644Sbr 553277644Sbr bzero(sc->buf_base, sc->dma_size); 554277644Sbr 555277644Sbr return (0); 556277644Sbr} 557277644Sbr 558277644Sbrstatic int 559277644Sbrssichan_trigger(kobj_t obj, void *data, int go) 560277644Sbr{ 561277644Sbr struct sc_pcminfo *scp; 562277644Sbr struct sc_chinfo *ch; 563277644Sbr struct sc_info *sc; 564277644Sbr 565277644Sbr ch = data; 566277644Sbr scp = ch->parent; 567277644Sbr sc = scp->sc; 568277644Sbr 569277644Sbr snd_mtxlock(sc->lock); 570277644Sbr 571277644Sbr switch (go) { 572277644Sbr case PCMTRIG_START: 573277644Sbr#if 0 574277644Sbr device_printf(scp->dev, "trigger start\n"); 575277644Sbr#endif 576277644Sbr ch->run = 1; 577277644Sbr 578277644Sbr ssi_start(scp); 579277644Sbr 580277644Sbr break; 581277644Sbr 582277644Sbr case PCMTRIG_STOP: 583277644Sbr case PCMTRIG_ABORT: 584277644Sbr#if 0 585277644Sbr device_printf(scp->dev, "trigger stop or abort\n"); 586277644Sbr#endif 587277644Sbr ch->run = 0; 588277644Sbr 589277644Sbr ssi_stop(scp); 590277644Sbr 591277644Sbr break; 592277644Sbr } 593277644Sbr 594277644Sbr snd_mtxunlock(sc->lock); 595277644Sbr 596277644Sbr return (0); 597277644Sbr} 598277644Sbr 599277644Sbrstatic uint32_t 600277644Sbrssichan_getptr(kobj_t obj, void *data) 601277644Sbr{ 602277644Sbr struct sc_pcminfo *scp; 603277644Sbr struct sc_chinfo *ch; 604277644Sbr struct sc_info *sc; 605277644Sbr 606277644Sbr ch = data; 607277644Sbr scp = ch->parent; 608277644Sbr sc = scp->sc; 609277644Sbr 610277644Sbr return (sc->pos); 611277644Sbr} 612277644Sbr 613277644Sbrstatic uint32_t ssi_pfmt[] = { 614277644Sbr SND_FORMAT(AFMT_S24_LE, 2, 0), 615277644Sbr 0 616277644Sbr}; 617277644Sbr 618277644Sbrstatic struct pcmchan_caps ssi_pcaps = {44100, 192000, ssi_pfmt, 0}; 619277644Sbr 620277644Sbrstatic struct pcmchan_caps * 621277644Sbrssichan_getcaps(kobj_t obj, void *data) 622277644Sbr{ 623277644Sbr 624277644Sbr return (&ssi_pcaps); 625277644Sbr} 626277644Sbr 627277644Sbrstatic kobj_method_t ssichan_methods[] = { 628277644Sbr KOBJMETHOD(channel_init, ssichan_init), 629277644Sbr KOBJMETHOD(channel_free, ssichan_free), 630277644Sbr KOBJMETHOD(channel_setformat, ssichan_setformat), 631277644Sbr KOBJMETHOD(channel_setspeed, ssichan_setspeed), 632277644Sbr KOBJMETHOD(channel_setblocksize, ssichan_setblocksize), 633277644Sbr KOBJMETHOD(channel_trigger, ssichan_trigger), 634277644Sbr KOBJMETHOD(channel_getptr, ssichan_getptr), 635277644Sbr KOBJMETHOD(channel_getcaps, ssichan_getcaps), 636277644Sbr KOBJMETHOD_END 637277644Sbr}; 638277644SbrCHANNEL_DECLARE(ssichan); 639277644Sbr 640277644Sbrstatic int 641277644Sbrssi_probe(device_t dev) 642277644Sbr{ 643277644Sbr 644277644Sbr if (!ofw_bus_status_okay(dev)) 645277644Sbr return (ENXIO); 646277644Sbr 647277644Sbr if (!ofw_bus_is_compatible(dev, "fsl,imx6q-ssi")) 648277644Sbr return (ENXIO); 649277644Sbr 650277644Sbr device_set_desc(dev, "i.MX6 Synchronous Serial Interface (SSI)"); 651277644Sbr return (BUS_PROBE_DEFAULT); 652277644Sbr} 653277644Sbr 654277644Sbrstatic void 655277644Sbrssi_intr(void *arg) 656277644Sbr{ 657277644Sbr struct sc_pcminfo *scp; 658277644Sbr struct sc_chinfo *ch; 659277644Sbr struct sc_info *sc; 660277644Sbr 661277644Sbr scp = arg; 662277644Sbr sc = scp->sc; 663277644Sbr ch = &scp->chan[0]; 664277644Sbr 665277644Sbr /* We don't use SSI interrupt */ 666277644Sbr#if 0 667277644Sbr device_printf(sc->dev, "SSI Intr 0x%08x\n", 668277644Sbr READ4(sc, SSI_SISR)); 669277644Sbr#endif 670277644Sbr} 671277644Sbr 672277644Sbrstatic void 673277644Sbrsetup_ssi(struct sc_info *sc) 674277644Sbr{ 675277644Sbr int reg; 676277644Sbr 677277644Sbr reg = READ4(sc, SSI_STCCR); 678277644Sbr reg &= ~(WL3_WL0_M << WL3_WL0_S); 679277644Sbr reg |= (0xb << WL3_WL0_S); /* 24 bit */ 680277644Sbr reg &= ~(DC4_DC0_M << DC4_DC0_S); 681277644Sbr reg |= (1 << DC4_DC0_S); /* 2 words per frame */ 682277644Sbr reg &= ~(STCCR_DIV2); /* Divide by 1 */ 683277644Sbr reg &= ~(STCCR_PSR); /* Divide by 1 */ 684277644Sbr reg &= ~(PM7_PM0_M << PM7_PM0_S); 685277644Sbr reg |= (1 << PM7_PM0_S); /* Divide by 2 */ 686277644Sbr WRITE4(sc, SSI_STCCR, reg); 687277644Sbr 688277644Sbr reg = READ4(sc, SSI_SFCSR); 689277644Sbr reg &= ~(SFCSR_TFWM0_M << SFCSR_TFWM0_S); 690277644Sbr reg |= (8 << SFCSR_TFWM0_S); /* empty slots */ 691277644Sbr WRITE4(sc, SSI_SFCSR, reg); 692277644Sbr 693277644Sbr reg = READ4(sc, SSI_STCR); 694277644Sbr reg |= (STCR_TFEN0); 695277644Sbr reg &= ~(STCR_TFEN1); 696277644Sbr reg &= ~(STCR_TSHFD); /* MSB */ 697277644Sbr reg |= (STCR_TXBIT0); 698277644Sbr reg |= (STCR_TXDIR | STCR_TFDIR); 699277644Sbr reg |= (STCR_TSCKP); /* falling edge */ 700277644Sbr reg |= (STCR_TFSI); 701277644Sbr reg &= ~(STCR_TFSI); /* active high frame sync */ 702277644Sbr reg &= ~(STCR_TFSL); 703277644Sbr reg |= STCR_TEFS; 704277644Sbr WRITE4(sc, SSI_STCR, reg); 705277644Sbr 706277644Sbr reg = READ4(sc, SSI_SCR); 707277644Sbr reg &= ~(SCR_I2S_MODE_M << SCR_I2S_MODE_S); /* Not master */ 708277644Sbr reg |= (SCR_SSIEN | SCR_TE); 709277644Sbr reg |= (SCR_NET); 710277644Sbr reg |= (SCR_SYN); 711277644Sbr WRITE4(sc, SSI_SCR, reg); 712277644Sbr} 713277644Sbr 714277644Sbrstatic void 715277644Sbrssi_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) 716277644Sbr{ 717277644Sbr bus_addr_t *addr; 718277644Sbr 719277644Sbr if (err) 720277644Sbr return; 721277644Sbr 722277644Sbr addr = (bus_addr_t*)arg; 723277644Sbr *addr = segs[0].ds_addr; 724277644Sbr} 725277644Sbr 726277644Sbrstatic int 727277644Sbrssi_attach(device_t dev) 728277644Sbr{ 729277644Sbr char status[SND_STATUSLEN]; 730277644Sbr struct sc_pcminfo *scp; 731277644Sbr struct sc_info *sc; 732277644Sbr int err; 733277644Sbr 734277644Sbr sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 735277644Sbr sc->dev = dev; 736277644Sbr sc->sr = &rate_map[0]; 737277644Sbr sc->pos = 0; 738277644Sbr sc->conf = malloc(sizeof(struct sdma_conf), M_DEVBUF, M_WAITOK | M_ZERO); 739277644Sbr 740277644Sbr sc->lock = snd_mtxcreate(device_get_nameunit(dev), "ssi softc"); 741277644Sbr if (sc->lock == NULL) { 742277644Sbr device_printf(dev, "Cant create mtx\n"); 743277644Sbr return (ENXIO); 744277644Sbr } 745277644Sbr 746277644Sbr if (bus_alloc_resources(dev, ssi_spec, sc->res)) { 747277644Sbr device_printf(dev, "could not allocate resources\n"); 748277644Sbr return (ENXIO); 749277644Sbr } 750277644Sbr 751277644Sbr /* Memory interface */ 752277644Sbr sc->bst = rman_get_bustag(sc->res[0]); 753277644Sbr sc->bsh = rman_get_bushandle(sc->res[0]); 754277644Sbr 755277644Sbr /* SDMA */ 756277644Sbr if (find_sdma_controller(sc)) { 757277644Sbr device_printf(dev, "could not find active SDMA\n"); 758277644Sbr return (ENXIO); 759277644Sbr } 760277644Sbr 761277644Sbr /* Setup PCM */ 762277644Sbr scp = malloc(sizeof(struct sc_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO); 763277644Sbr scp->sc = sc; 764277644Sbr scp->dev = dev; 765277644Sbr 766277644Sbr /* 767277644Sbr * Maximum possible DMA buffer. 768277644Sbr * Will be used partialy to match 24 bit word. 769277644Sbr */ 770277644Sbr sc->dma_size = 131072; 771277644Sbr 772277644Sbr /* 773277644Sbr * Must use dma_size boundary as modulo feature required. 774277644Sbr * Modulo feature allows setup circular buffer. 775277644Sbr */ 776277644Sbr 777277644Sbr err = bus_dma_tag_create( 778277644Sbr bus_get_dma_tag(sc->dev), 779277644Sbr 4, sc->dma_size, /* alignment, boundary */ 780277644Sbr BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 781277644Sbr BUS_SPACE_MAXADDR, /* highaddr */ 782277644Sbr NULL, NULL, /* filter, filterarg */ 783277644Sbr sc->dma_size, 1, /* maxsize, nsegments */ 784277644Sbr sc->dma_size, 0, /* maxsegsize, flags */ 785277644Sbr NULL, NULL, /* lockfunc, lockarg */ 786277644Sbr &sc->dma_tag); 787277644Sbr 788277644Sbr err = bus_dmamem_alloc(sc->dma_tag, (void **)&sc->buf_base, 789277644Sbr BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &sc->dma_map); 790277644Sbr if (err) { 791277644Sbr device_printf(dev, "cannot allocate framebuffer\n"); 792277644Sbr return (ENXIO); 793277644Sbr } 794277644Sbr 795277644Sbr err = bus_dmamap_load(sc->dma_tag, sc->dma_map, sc->buf_base, 796277644Sbr sc->dma_size, ssi_dmamap_cb, &sc->buf_base_phys, BUS_DMA_NOWAIT); 797277644Sbr if (err) { 798277644Sbr device_printf(dev, "cannot load DMA map\n"); 799277644Sbr return (ENXIO); 800277644Sbr } 801277644Sbr 802277644Sbr bzero(sc->buf_base, sc->dma_size); 803277644Sbr 804277644Sbr /* Setup interrupt handler */ 805277644Sbr err = bus_setup_intr(dev, sc->res[1], INTR_MPSAFE | INTR_TYPE_AV, 806277644Sbr NULL, ssi_intr, scp, &sc->ih); 807277644Sbr if (err) { 808277644Sbr device_printf(dev, "Unable to alloc interrupt resource.\n"); 809277644Sbr return (ENXIO); 810277644Sbr } 811277644Sbr 812277644Sbr pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE); 813277644Sbr 814277644Sbr err = pcm_register(dev, scp, 1, 0); 815277644Sbr if (err) { 816277644Sbr device_printf(dev, "Can't register pcm.\n"); 817277644Sbr return (ENXIO); 818277644Sbr } 819277644Sbr 820277644Sbr scp->chnum = 0; 821277644Sbr pcm_addchan(dev, PCMDIR_PLAY, &ssichan_class, scp); 822277644Sbr scp->chnum++; 823277644Sbr 824277644Sbr snprintf(status, SND_STATUSLEN, "at simplebus"); 825277644Sbr pcm_setstatus(dev, status); 826277644Sbr 827277644Sbr mixer_init(dev, &ssimixer_class, scp); 828277644Sbr setup_ssi(sc); 829277644Sbr 830277644Sbr imx_ccm_ssi_configure(dev); 831277644Sbr 832277644Sbr sc->sdma_channel = sdma_alloc(); 833277644Sbr if (sc->sdma_channel < 0) { 834277644Sbr device_printf(sc->dev, "Can't get sDMA channel\n"); 835277644Sbr return (1); 836277644Sbr } 837277644Sbr 838277644Sbr return (0); 839277644Sbr} 840277644Sbr 841277644Sbrstatic device_method_t ssi_pcm_methods[] = { 842277644Sbr DEVMETHOD(device_probe, ssi_probe), 843277644Sbr DEVMETHOD(device_attach, ssi_attach), 844277644Sbr { 0, 0 } 845277644Sbr}; 846277644Sbr 847277644Sbrstatic driver_t ssi_pcm_driver = { 848277644Sbr "pcm", 849277644Sbr ssi_pcm_methods, 850277644Sbr PCM_SOFTC_SIZE, 851277644Sbr}; 852277644Sbr 853277644SbrDRIVER_MODULE(ssi, simplebus, ssi_pcm_driver, pcm_devclass, 0, 0); 854277644SbrMODULE_DEPEND(ssi, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 855277644SbrMODULE_VERSION(ssi, 1); 856