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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

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

Cache object: 57ff9e6108ce3ae1f66c0d614a800967


[ 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.