The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/arm/freescale/vybrid/vf_sai.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 /*
   28  * Vybrid Family Synchronous Audio Interface (SAI)
   29  * Chapter 51, Vybrid Reference Manual, Rev. 5, 07/2013
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __FBSDID("$FreeBSD: releng/11.0/sys/arm/freescale/vybrid/vf_sai.c 297793 2016-04-10 23:07:00Z pfg $");
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/bus.h>
   38 #include <sys/kernel.h>
   39 #include <sys/module.h>
   40 #include <sys/malloc.h>
   41 #include <sys/rman.h>
   42 #include <sys/timeet.h>
   43 #include <sys/timetc.h>
   44 #include <sys/watchdog.h>
   45 
   46 #include <dev/sound/pcm/sound.h>
   47 #include <dev/sound/chip.h>
   48 #include <mixer_if.h>
   49 
   50 #include <dev/fdt/fdt_common.h>
   51 #include <dev/ofw/openfirm.h>
   52 #include <dev/ofw/ofw_bus.h>
   53 #include <dev/ofw/ofw_bus_subr.h>
   54 
   55 #include <machine/bus.h>
   56 #include <machine/cpu.h>
   57 #include <machine/intr.h>
   58 
   59 #include <arm/freescale/vybrid/vf_common.h>
   60 #include <arm/freescale/vybrid/vf_dmamux.h>
   61 #include <arm/freescale/vybrid/vf_edma.h>
   62 
   63 #define I2S_TCSR        0x00    /* SAI Transmit Control */
   64 #define I2S_TCR1        0x04    /* SAI Transmit Configuration 1 */
   65 #define I2S_TCR2        0x08    /* SAI Transmit Configuration 2 */
   66 #define I2S_TCR3        0x0C    /* SAI Transmit Configuration 3 */
   67 #define I2S_TCR4        0x10    /* SAI Transmit Configuration 4 */
   68 #define I2S_TCR5        0x14    /* SAI Transmit Configuration 5 */
   69 #define I2S_TDR0        0x20    /* SAI Transmit Data */
   70 #define I2S_TFR0        0x40    /* SAI Transmit FIFO */
   71 #define I2S_TMR         0x60    /* SAI Transmit Mask */
   72 #define I2S_RCSR        0x80    /* SAI Receive Control */
   73 #define I2S_RCR1        0x84    /* SAI Receive Configuration 1 */
   74 #define I2S_RCR2        0x88    /* SAI Receive Configuration 2 */
   75 #define I2S_RCR3        0x8C    /* SAI Receive Configuration 3 */
   76 #define I2S_RCR4        0x90    /* SAI Receive Configuration 4 */
   77 #define I2S_RCR5        0x94    /* SAI Receive Configuration 5 */
   78 #define I2S_RDR0        0xA0    /* SAI Receive Data */
   79 #define I2S_RFR0        0xC0    /* SAI Receive FIFO */
   80 #define I2S_RMR         0xE0    /* SAI Receive Mask */
   81 
   82 #define TCR1_TFW_M      0x1f            /* Transmit FIFO Watermark Mask */
   83 #define TCR1_TFW_S      0               /* Transmit FIFO Watermark Shift */
   84 #define TCR2_MSEL_M     0x3             /* MCLK Select Mask*/
   85 #define TCR2_MSEL_S     26              /* MCLK Select Shift*/
   86 #define TCR2_BCP        (1 << 25)       /* Bit Clock Polarity */
   87 #define TCR2_BCD        (1 << 24)       /* Bit Clock Direction */
   88 #define TCR3_TCE        (1 << 16)       /* Transmit Channel Enable */
   89 #define TCR4_FRSZ_M     0x1f            /* Frame size Mask */
   90 #define TCR4_FRSZ_S     16              /* Frame size Shift */
   91 #define TCR4_SYWD_M     0x1f            /* Sync Width Mask */
   92 #define TCR4_SYWD_S     8               /* Sync Width Shift */
   93 #define TCR4_MF         (1 << 4)        /* MSB First */
   94 #define TCR4_FSE        (1 << 3)        /* Frame Sync Early */
   95 #define TCR4_FSP        (1 << 1)        /* Frame Sync Polarity Low */
   96 #define TCR4_FSD        (1 << 0)        /* Frame Sync Direction Master */
   97 #define TCR5_FBT_M      0x1f            /* First Bit Shifted */
   98 #define TCR5_FBT_S      8               /* First Bit Shifted */
   99 #define TCR5_W0W_M      0x1f            /* Word 0 Width */
  100 #define TCR5_W0W_S      16              /* Word 0 Width */
  101 #define TCR5_WNW_M      0x1f            /* Word N Width */
  102 #define TCR5_WNW_S      24              /* Word N Width */
  103 #define TCSR_TE         (1 << 31)       /* Transmitter Enable */
  104 #define TCSR_BCE        (1 << 28)       /* Bit Clock Enable */
  105 #define TCSR_FRDE       (1 << 0)        /* FIFO Request DMA Enable */
  106 
  107 #define SAI_NCHANNELS   1
  108 
  109 static MALLOC_DEFINE(M_SAI, "sai", "sai audio");
  110 
  111 struct sai_rate {
  112         uint32_t speed;
  113         uint32_t div; /* Bit Clock Divide. Division value is (div + 1) * 2. */
  114         uint32_t mfi; /* PLL4 Multiplication Factor Integer */
  115         uint32_t mfn; /* PLL4 Multiplication Factor Numerator */
  116         uint32_t mfd; /* PLL4 Multiplication Factor Denominator */
  117 };
  118 
  119 /*
  120  * Bit clock divider formula
  121  * (div + 1) * 2 = MCLK/(nch * LRCLK * bits/1000000),
  122  * where:
  123  *   MCLK - master clock
  124  *   nch - number of channels
  125  *   LRCLK - left right clock
  126  * e.g. (div + 1) * 2 = 16.9344/(2 * 44100 * 24/1000000)
  127  *
  128  * Example for 96khz, 24bit, 18.432 Mhz mclk (192fs)
  129  * { 96000, 1, 18, 40176000, 93000000 },
  130  */
  131 
  132 static struct sai_rate rate_map[] = {
  133         { 44100, 7, 33, 80798400, 93000000 }, /* 33.8688 Mhz */
  134         { 96000, 3, 36, 80352000, 93000000 }, /* 36.864 Mhz */
  135         { 192000, 1, 36, 80352000, 93000000 }, /* 36.864 Mhz */
  136         { 0, 0 },
  137 };
  138 
  139 struct sc_info {
  140         struct resource         *res[2];
  141         bus_space_tag_t         bst;
  142         bus_space_handle_t      bsh;
  143         device_t                dev;
  144         struct mtx              *lock;
  145         uint32_t                speed;
  146         uint32_t                period;
  147         void                    *ih;
  148         int                     pos;
  149         int                     dma_size;
  150         bus_dma_tag_t           dma_tag;
  151         bus_dmamap_t            dma_map;
  152         bus_addr_t              buf_base_phys;
  153         uint32_t                *buf_base;
  154         struct tcd_conf         *tcd;
  155         struct sai_rate         *sr;
  156         struct edma_softc       *edma_sc;
  157         int                     edma_chnum;
  158 };
  159 
  160 /* Channel registers */
  161 struct sc_chinfo {
  162         struct snd_dbuf         *buffer;
  163         struct pcm_channel      *channel;
  164         struct sc_pcminfo       *parent;
  165 
  166         /* Channel information */
  167         uint32_t        dir;
  168         uint32_t        format;
  169 
  170         /* Flags */
  171         uint32_t        run;
  172 };
  173 
  174 /* PCM device private data */
  175 struct sc_pcminfo {
  176         device_t                dev;
  177         uint32_t                (*ih) (struct sc_pcminfo *scp);
  178         uint32_t                chnum;
  179         struct sc_chinfo        chan[SAI_NCHANNELS];
  180         struct sc_info          *sc;
  181 };
  182 
  183 static struct resource_spec sai_spec[] = {
  184         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
  185         { SYS_RES_IRQ,          0,      RF_ACTIVE },
  186         { -1, 0 }
  187 };
  188 
  189 static int setup_dma(struct sc_pcminfo *scp);
  190 static void setup_sai(struct sc_info *);
  191 static void sai_configure_clock(struct sc_info *);
  192 
  193 /*
  194  * Mixer interface.
  195  */
  196 
  197 static int
  198 saimixer_init(struct snd_mixer *m)
  199 {
  200         struct sc_pcminfo *scp;
  201         struct sc_info *sc;
  202         int mask;
  203 
  204         scp = mix_getdevinfo(m);
  205         sc = scp->sc;
  206 
  207         if (sc == NULL)
  208                 return -1;
  209 
  210         mask = SOUND_MASK_PCM;
  211 
  212         snd_mtxlock(sc->lock);
  213         pcm_setflags(scp->dev, pcm_getflags(scp->dev) | SD_F_SOFTPCMVOL);
  214         mix_setdevs(m, mask);
  215         snd_mtxunlock(sc->lock);
  216 
  217         return (0);
  218 }
  219 
  220 static int
  221 saimixer_set(struct snd_mixer *m, unsigned dev,
  222     unsigned left, unsigned right)
  223 {
  224         struct sc_pcminfo *scp;
  225 
  226         scp = mix_getdevinfo(m);
  227 
  228 #if 0
  229         device_printf(scp->dev, "saimixer_set() %d %d\n",
  230             left, right);
  231 #endif
  232 
  233         return (0);
  234 }
  235 
  236 static kobj_method_t saimixer_methods[] = {
  237         KOBJMETHOD(mixer_init,      saimixer_init),
  238         KOBJMETHOD(mixer_set,       saimixer_set),
  239         KOBJMETHOD_END
  240 };
  241 MIXER_DECLARE(saimixer);
  242 
  243 /*
  244  * Channel interface.
  245  */
  246 
  247 static void *
  248 saichan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
  249     struct pcm_channel *c, int dir)
  250 {
  251         struct sc_pcminfo *scp;
  252         struct sc_chinfo *ch;
  253         struct sc_info *sc;
  254 
  255         scp = (struct sc_pcminfo *)devinfo;
  256         sc = scp->sc;
  257 
  258         snd_mtxlock(sc->lock);
  259         ch = &scp->chan[0];
  260         ch->dir = dir;
  261         ch->run = 0;
  262         ch->buffer = b;
  263         ch->channel = c;
  264         ch->parent = scp;
  265         snd_mtxunlock(sc->lock);
  266 
  267         if (sndbuf_setup(ch->buffer, sc->buf_base, sc->dma_size) != 0) {
  268                 device_printf(scp->dev, "Can't setup sndbuf.\n");
  269                 return NULL;
  270         }
  271 
  272         return ch;
  273 }
  274 
  275 static int
  276 saichan_free(kobj_t obj, void *data)
  277 {
  278         struct sc_chinfo *ch = data;
  279         struct sc_pcminfo *scp = ch->parent;
  280         struct sc_info *sc = scp->sc;
  281 
  282 #if 0
  283         device_printf(scp->dev, "saichan_free()\n");
  284 #endif
  285 
  286         snd_mtxlock(sc->lock);
  287         /* TODO: free channel buffer */
  288         snd_mtxunlock(sc->lock);
  289 
  290         return (0);
  291 }
  292 
  293 static int
  294 saichan_setformat(kobj_t obj, void *data, uint32_t format)
  295 {
  296         struct sc_chinfo *ch = data;
  297 
  298         ch->format = format;
  299 
  300         return (0);
  301 }
  302 
  303 static uint32_t
  304 saichan_setspeed(kobj_t obj, void *data, uint32_t speed)
  305 {
  306         struct sc_pcminfo *scp;
  307         struct sc_chinfo *ch;
  308         struct sai_rate *sr;
  309         struct sc_info *sc;
  310         int threshold;
  311         int i;
  312 
  313         ch = data;
  314         scp = ch->parent;
  315         sc = scp->sc;
  316 
  317         sr = NULL;
  318 
  319         /* First look for equal frequency. */
  320         for (i = 0; rate_map[i].speed != 0; i++) {
  321                 if (rate_map[i].speed == speed)
  322                         sr = &rate_map[i];
  323         }
  324 
  325         /* If no match, just find nearest. */
  326         if (sr == NULL) {
  327                 for (i = 0; rate_map[i].speed != 0; i++) {
  328                         sr = &rate_map[i];
  329                         threshold = sr->speed + ((rate_map[i + 1].speed != 0) ?
  330                             ((rate_map[i + 1].speed - sr->speed) >> 1) : 0);
  331                         if (speed < threshold)
  332                                 break;
  333                 }
  334         }
  335 
  336         sc->sr = sr;
  337 
  338         sai_configure_clock(sc);
  339 
  340         return (sr->speed);
  341 }
  342 
  343 static void
  344 sai_configure_clock(struct sc_info *sc)
  345 {
  346         struct sai_rate *sr;
  347         int reg;
  348 
  349         sr = sc->sr;
  350 
  351         /*
  352          * Manual says that TCR/RCR registers must not be
  353          * altered when TCSR[TE] is set.
  354          * We ignore it since we have problem sometimes
  355          * after re-enabling transmitter (DMA goes stall).
  356          */
  357 
  358         reg = READ4(sc, I2S_TCR2);
  359         reg &= ~(0xff << 0);
  360         reg |= (sr->div << 0);
  361         WRITE4(sc, I2S_TCR2, reg);
  362 
  363         pll4_configure_output(sr->mfi, sr->mfn, sr->mfd);
  364 }
  365 
  366 static uint32_t
  367 saichan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
  368 {
  369         struct sc_chinfo *ch = data;
  370         struct sc_pcminfo *scp = ch->parent;
  371         struct sc_info *sc = scp->sc;
  372 
  373         sndbuf_resize(ch->buffer, sc->dma_size / blocksize, blocksize);
  374 
  375         sc->period = sndbuf_getblksz(ch->buffer);
  376         return (sc->period);
  377 }
  378 
  379 uint32_t sai_dma_intr(void *arg, int chn);
  380 uint32_t
  381 sai_dma_intr(void *arg, int chn)
  382 {
  383         struct sc_pcminfo *scp;
  384         struct sc_chinfo *ch;
  385         struct sc_info *sc;
  386         struct tcd_conf *tcd;
  387 
  388         scp = arg;
  389         ch = &scp->chan[0];
  390 
  391         sc = scp->sc;
  392         tcd = sc->tcd;
  393 
  394         sc->pos += (tcd->nbytes * tcd->nmajor);
  395         if (sc->pos >= sc->dma_size)
  396                 sc->pos -= sc->dma_size;
  397 
  398         if (ch->run)
  399                 chn_intr(ch->channel);
  400 
  401         return (0);
  402 }
  403 
  404 static int
  405 find_edma_controller(struct sc_info *sc)
  406 {
  407         struct edma_softc *edma_sc;
  408         phandle_t node, edma_node;
  409         int edma_src_transmit;
  410         int edma_mux_group;
  411         int edma_device_id;
  412         device_t edma_dev;
  413         int dts_value;
  414         int len;
  415         int i;
  416 
  417         if ((node = ofw_bus_get_node(sc->dev)) == -1)
  418                 return (ENXIO);
  419 
  420         if ((len = OF_getproplen(node, "edma-controller")) <= 0)
  421                 return (ENXIO);
  422         if ((len = OF_getproplen(node, "edma-src-transmit")) <= 0)
  423                 return (ENXIO);
  424         if ((len = OF_getproplen(node, "edma-mux-group")) <= 0)
  425                 return (ENXIO);
  426 
  427         OF_getprop(node, "edma-src-transmit", &dts_value, len);
  428         edma_src_transmit = fdt32_to_cpu(dts_value);
  429         OF_getprop(node, "edma-mux-group", &dts_value, len);
  430         edma_mux_group = fdt32_to_cpu(dts_value);
  431         OF_getprop(node, "edma-controller", &dts_value, len);
  432         edma_node = OF_node_from_xref(fdt32_to_cpu(dts_value));
  433 
  434         if ((len = OF_getproplen(edma_node, "device-id")) <= 0) {
  435                 return (ENXIO);
  436         }
  437 
  438         OF_getprop(edma_node, "device-id", &dts_value, len);
  439         edma_device_id = fdt32_to_cpu(dts_value);
  440 
  441         edma_sc = NULL;
  442 
  443         for (i = 0; i < EDMA_NUM_DEVICES; i++) {
  444                 edma_dev = devclass_get_device(devclass_find("edma"), i);
  445                 if (edma_dev) {
  446                         edma_sc = device_get_softc(edma_dev);
  447                         if (edma_sc->device_id == edma_device_id) {
  448                                 /* found */
  449                                 break;
  450                         }
  451 
  452                         edma_sc = NULL;
  453                 }
  454         }
  455 
  456         if (edma_sc == NULL) {
  457                 device_printf(sc->dev, "no eDMA. can't operate\n");
  458                 return (ENXIO);
  459         }
  460 
  461         sc->edma_sc = edma_sc;
  462 
  463         sc->edma_chnum = edma_sc->channel_configure(edma_sc, edma_mux_group,
  464             edma_src_transmit);
  465         if (sc->edma_chnum < 0) {
  466                 /* cant setup eDMA */
  467                 return (ENXIO);
  468         }
  469 
  470         return (0);
  471 };
  472 
  473 static int
  474 setup_dma(struct sc_pcminfo *scp)
  475 {
  476         struct tcd_conf *tcd;
  477         struct sc_info *sc;
  478 
  479         sc = scp->sc;
  480 
  481         tcd = malloc(sizeof(struct tcd_conf), M_DEVBUF, M_WAITOK | M_ZERO);
  482         tcd->channel = sc->edma_chnum;
  483         tcd->ih = sai_dma_intr;
  484         tcd->ih_user = scp;
  485         tcd->saddr = sc->buf_base_phys;
  486         tcd->daddr = rman_get_start(sc->res[0]) + I2S_TDR0;
  487 
  488         /*
  489          * Bytes to transfer per each minor loop.
  490          * Hardware FIFO buffer size is 32x32bits.
  491          */
  492         tcd->nbytes = 64;
  493 
  494         tcd->nmajor = 512;
  495         tcd->smod = 17; /* dma_size range */
  496         tcd->dmod = 0;
  497         tcd->esg = 0;
  498         tcd->soff = 0x4;
  499         tcd->doff = 0;
  500         tcd->ssize = 0x2;
  501         tcd->dsize = 0x2;
  502         tcd->slast = 0;
  503         tcd->dlast_sga = 0;
  504 
  505         sc->tcd = tcd;
  506 
  507         sc->edma_sc->dma_setup(sc->edma_sc, sc->tcd);
  508 
  509         return (0);
  510 }
  511 
  512 static int
  513 saichan_trigger(kobj_t obj, void *data, int go)
  514 {
  515         struct sc_chinfo *ch = data;
  516         struct sc_pcminfo *scp = ch->parent;
  517         struct sc_info *sc = scp->sc;
  518 
  519         snd_mtxlock(sc->lock);
  520 
  521         switch (go) {
  522         case PCMTRIG_START:
  523 #if 0
  524                 device_printf(scp->dev, "trigger start\n");
  525 #endif
  526                 ch->run = 1;
  527                 break;
  528 
  529         case PCMTRIG_STOP:
  530         case PCMTRIG_ABORT:
  531 #if 0
  532                 device_printf(scp->dev, "trigger stop or abort\n");
  533 #endif
  534                 ch->run = 0;
  535                 break;
  536         }
  537 
  538         snd_mtxunlock(sc->lock);
  539 
  540         return (0);
  541 }
  542 
  543 static uint32_t
  544 saichan_getptr(kobj_t obj, void *data)
  545 {
  546         struct sc_pcminfo *scp;
  547         struct sc_chinfo *ch;
  548         struct sc_info *sc;
  549 
  550         ch = data;
  551         scp = ch->parent;
  552         sc = scp->sc;
  553 
  554         return (sc->pos);
  555 }
  556 
  557 static uint32_t sai_pfmt[] = {
  558         /*
  559          * eDMA doesn't allow 24-bit coping,
  560          * so we use 32.
  561          */
  562         SND_FORMAT(AFMT_S32_LE, 2, 0),
  563         0
  564 };
  565 
  566 static struct pcmchan_caps sai_pcaps = {44100, 192000, sai_pfmt, 0};
  567 
  568 static struct pcmchan_caps *
  569 saichan_getcaps(kobj_t obj, void *data)
  570 {
  571 
  572         return (&sai_pcaps);
  573 }
  574 
  575 static kobj_method_t saichan_methods[] = {
  576         KOBJMETHOD(channel_init,         saichan_init),
  577         KOBJMETHOD(channel_free,         saichan_free),
  578         KOBJMETHOD(channel_setformat,    saichan_setformat),
  579         KOBJMETHOD(channel_setspeed,     saichan_setspeed),
  580         KOBJMETHOD(channel_setblocksize, saichan_setblocksize),
  581         KOBJMETHOD(channel_trigger,      saichan_trigger),
  582         KOBJMETHOD(channel_getptr,       saichan_getptr),
  583         KOBJMETHOD(channel_getcaps,      saichan_getcaps),
  584         KOBJMETHOD_END
  585 };
  586 CHANNEL_DECLARE(saichan);
  587 
  588 static int
  589 sai_probe(device_t dev)
  590 {
  591 
  592         if (!ofw_bus_status_okay(dev))
  593                 return (ENXIO);
  594 
  595         if (!ofw_bus_is_compatible(dev, "fsl,mvf600-sai"))
  596                 return (ENXIO);
  597 
  598         device_set_desc(dev, "Vybrid Family Synchronous Audio Interface");
  599         return (BUS_PROBE_DEFAULT);
  600 }
  601 
  602 static void
  603 sai_intr(void *arg)
  604 {
  605         struct sc_pcminfo *scp;
  606         struct sc_info *sc;
  607 
  608         scp = arg;
  609         sc = scp->sc;
  610 
  611         device_printf(sc->dev, "Error I2S_TCSR == 0x%08x\n",
  612             READ4(sc, I2S_TCSR));
  613 }
  614 
  615 static void
  616 setup_sai(struct sc_info *sc)
  617 {
  618         int reg;
  619 
  620         /*
  621          * TCR/RCR registers must not be altered when TCSR[TE] is set.
  622          */
  623 
  624         reg = READ4(sc, I2S_TCSR);
  625         reg &= ~(TCSR_BCE | TCSR_TE | TCSR_FRDE);
  626         WRITE4(sc, I2S_TCSR, reg);
  627 
  628         reg = READ4(sc, I2S_TCR3);
  629         reg &= ~(TCR3_TCE);
  630         WRITE4(sc, I2S_TCR3, reg);
  631 
  632         reg = (64 << TCR1_TFW_S);
  633         WRITE4(sc, I2S_TCR1, reg);
  634 
  635         reg = READ4(sc, I2S_TCR2);
  636         reg &= ~(TCR2_MSEL_M << TCR2_MSEL_S);
  637         reg |= (1 << TCR2_MSEL_S);
  638         reg |= (TCR2_BCP | TCR2_BCD);
  639         WRITE4(sc, I2S_TCR2, reg);
  640 
  641         sai_configure_clock(sc);
  642 
  643         reg = READ4(sc, I2S_TCR3);
  644         reg |= (TCR3_TCE);
  645         WRITE4(sc, I2S_TCR3, reg);
  646 
  647         /* Configure to 32-bit I2S mode */
  648         reg = READ4(sc, I2S_TCR4);
  649         reg &= ~(TCR4_FRSZ_M << TCR4_FRSZ_S);
  650         reg |= (1 << TCR4_FRSZ_S); /* 2 words per frame */
  651         reg &= ~(TCR4_SYWD_M << TCR4_SYWD_S);
  652         reg |= (23 << TCR4_SYWD_S);
  653         reg |= (TCR4_MF | TCR4_FSE | TCR4_FSP | TCR4_FSD);
  654         WRITE4(sc, I2S_TCR4, reg);
  655 
  656         reg = READ4(sc, I2S_TCR5);
  657         reg &= ~(TCR5_W0W_M << TCR5_W0W_S);
  658         reg |= (23 << TCR5_W0W_S);
  659         reg &= ~(TCR5_WNW_M << TCR5_WNW_S);
  660         reg |= (23 << TCR5_WNW_S);
  661         reg &= ~(TCR5_FBT_M << TCR5_FBT_S);
  662         reg |= (31 << TCR5_FBT_S);
  663         WRITE4(sc, I2S_TCR5, reg);
  664 
  665         /* Enable transmitter */
  666         reg = READ4(sc, I2S_TCSR);
  667         reg |= (TCSR_BCE | TCSR_TE | TCSR_FRDE);
  668         reg |= (1 << 10); /* FEIE */
  669         WRITE4(sc, I2S_TCSR, reg);
  670 }
  671 
  672 
  673 static void
  674 sai_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
  675 {
  676         bus_addr_t *addr;
  677 
  678         if (err)
  679                 return;
  680 
  681         addr = (bus_addr_t*)arg;
  682         *addr = segs[0].ds_addr;
  683 }
  684 
  685 static int
  686 sai_attach(device_t dev)
  687 {
  688         char status[SND_STATUSLEN];
  689         struct sc_pcminfo *scp;
  690         struct sc_info *sc;
  691         int err;
  692 
  693         sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
  694         sc->dev = dev;
  695         sc->sr = &rate_map[0];
  696         sc->pos = 0;
  697 
  698         sc->lock = snd_mtxcreate(device_get_nameunit(dev), "sai softc");
  699         if (sc->lock == NULL) {
  700                 device_printf(dev, "Cant create mtx\n");
  701                 return (ENXIO);
  702         }
  703 
  704         if (bus_alloc_resources(dev, sai_spec, sc->res)) {
  705                 device_printf(dev, "could not allocate resources\n");
  706                 return (ENXIO);
  707         }
  708 
  709         /* Memory interface */
  710         sc->bst = rman_get_bustag(sc->res[0]);
  711         sc->bsh = rman_get_bushandle(sc->res[0]);
  712 
  713         /* eDMA */
  714         if (find_edma_controller(sc)) {
  715                 device_printf(dev, "could not find active eDMA\n");
  716                 return (ENXIO);
  717         }
  718 
  719         /* Setup PCM */
  720         scp = malloc(sizeof(struct sc_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO);
  721         scp->sc = sc;
  722         scp->dev = dev;
  723 
  724         /* DMA */
  725         sc->dma_size = 131072;
  726 
  727         /*
  728          * Must use dma_size boundary as modulo feature required.
  729          * Modulo feature allows setup circular buffer.
  730          */
  731 
  732         err = bus_dma_tag_create(
  733             bus_get_dma_tag(sc->dev),
  734             4, sc->dma_size,            /* alignment, boundary */
  735             BUS_SPACE_MAXADDR_32BIT,    /* lowaddr */
  736             BUS_SPACE_MAXADDR,          /* highaddr */
  737             NULL, NULL,                 /* filter, filterarg */
  738             sc->dma_size, 1,            /* maxsize, nsegments */
  739             sc->dma_size, 0,            /* maxsegsize, flags */
  740             NULL, NULL,                 /* lockfunc, lockarg */
  741             &sc->dma_tag);
  742 
  743         err = bus_dmamem_alloc(sc->dma_tag, (void **)&sc->buf_base,
  744             BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &sc->dma_map);
  745         if (err) {
  746                 device_printf(dev, "cannot allocate framebuffer\n");
  747                 return (ENXIO);
  748         }
  749 
  750         err = bus_dmamap_load(sc->dma_tag, sc->dma_map, sc->buf_base,
  751             sc->dma_size, sai_dmamap_cb, &sc->buf_base_phys, BUS_DMA_NOWAIT);
  752         if (err) {
  753                 device_printf(dev, "cannot load DMA map\n");
  754                 return (ENXIO);
  755         }
  756 
  757         bzero(sc->buf_base, sc->dma_size);
  758 
  759         /* Setup interrupt handler */
  760         err = bus_setup_intr(dev, sc->res[1], INTR_MPSAFE | INTR_TYPE_AV,
  761             NULL, sai_intr, scp, &sc->ih);
  762         if (err) {
  763                 device_printf(dev, "Unable to alloc interrupt resource.\n");
  764                 return (ENXIO);
  765         }
  766 
  767         pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE);
  768 
  769         err = pcm_register(dev, scp, 1, 0);
  770         if (err) {
  771                 device_printf(dev, "Can't register pcm.\n");
  772                 return (ENXIO);
  773         }
  774 
  775         scp->chnum = 0;
  776         pcm_addchan(dev, PCMDIR_PLAY, &saichan_class, scp);
  777         scp->chnum++;
  778 
  779         snprintf(status, SND_STATUSLEN, "at simplebus");
  780         pcm_setstatus(dev, status);
  781 
  782         mixer_init(dev, &saimixer_class, scp);
  783 
  784         setup_dma(scp);
  785         setup_sai(sc);
  786 
  787         return (0);
  788 }
  789 
  790 static device_method_t sai_pcm_methods[] = {
  791         DEVMETHOD(device_probe,         sai_probe),
  792         DEVMETHOD(device_attach,        sai_attach),
  793         { 0, 0 }
  794 };
  795 
  796 static driver_t sai_pcm_driver = {
  797         "pcm",
  798         sai_pcm_methods,
  799         PCM_SOFTC_SIZE,
  800 };
  801 
  802 DRIVER_MODULE(sai, simplebus, sai_pcm_driver, pcm_devclass, 0, 0);
  803 MODULE_DEPEND(sai, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
  804 MODULE_VERSION(sai, 1);

Cache object: 8e71ec480bb5b965fc1adac2abcde2c1


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.