linux/arch/xtensa/variants/s6000/include/variant/dmac.h
<<
>>
Prefs
   1/*
   2 * include/asm-xtensa/variant-s6000/dmac.h
   3 *
   4 * This file is subject to the terms and conditions of the GNU General Public
   5 * License.  See the file "COPYING" in the main directory of this archive
   6 * for more details.
   7 *
   8 * Copyright (C) 2006 Tensilica Inc.
   9 * Copyright (C) 2008 Emlix GmbH <info@emlix.com>
  10 * Authors:     Fabian Godehardt <fg@emlix.com>
  11 *              Oskar Schirmer <os@emlix.com>
  12 *              Daniel Gloeckner <dg@emlix.com>
  13 */
  14
  15#ifndef __ASM_XTENSA_S6000_DMAC_H
  16#define __ASM_XTENSA_S6000_DMAC_H
  17#include <linux/io.h>
  18#include <variant/hardware.h>
  19
  20/* DMA global */
  21
  22#define S6_DMA_INTSTAT0         0x000
  23#define S6_DMA_INTSTAT1         0x004
  24#define S6_DMA_INTENABLE0       0x008
  25#define S6_DMA_INTENABLE1       0x00C
  26#define S6_DMA_INTRAW0          0x010
  27#define S6_DMA_INTRAW1          0x014
  28#define S6_DMA_INTCLEAR0        0x018
  29#define S6_DMA_INTCLEAR1        0x01C
  30#define S6_DMA_INTSET0          0x020
  31#define S6_DMA_INTSET1          0x024
  32#define S6_DMA_INT0_UNDER               0
  33#define S6_DMA_INT0_OVER                16
  34#define S6_DMA_INT1_CHANNEL             0
  35#define S6_DMA_INT1_MASTER              16
  36#define S6_DMA_INT1_MASTER_MASK                 7
  37#define S6_DMA_TERMCNTIRQSTAT   0x028
  38#define S6_DMA_TERMCNTIRQCLR    0x02C
  39#define S6_DMA_TERMCNTIRQSET    0x030
  40#define S6_DMA_PENDCNTIRQSTAT   0x034
  41#define S6_DMA_PENDCNTIRQCLR    0x038
  42#define S6_DMA_PENDCNTIRQSET    0x03C
  43#define S6_DMA_LOWWMRKIRQSTAT   0x040
  44#define S6_DMA_LOWWMRKIRQCLR    0x044
  45#define S6_DMA_LOWWMRKIRQSET    0x048
  46#define S6_DMA_MASTERERRINFO    0x04C
  47#define S6_DMA_MASTERERR_CHAN(n)        (4*(n))
  48#define S6_DMA_MASTERERR_CHAN_MASK              0xF
  49#define S6_DMA_DESCRFIFO0       0x050
  50#define S6_DMA_DESCRFIFO1       0x054
  51#define S6_DMA_DESCRFIFO2       0x058
  52#define S6_DMA_DESCRFIFO2_AUTODISABLE   24
  53#define S6_DMA_DESCRFIFO3       0x05C
  54#define S6_DMA_MASTER0START     0x060
  55#define S6_DMA_MASTER0END       0x064
  56#define S6_DMA_MASTER1START     0x068
  57#define S6_DMA_MASTER1END       0x06C
  58#define S6_DMA_NEXTFREE         0x070
  59#define S6_DMA_NEXTFREE_CHAN            0
  60#define S6_DMA_NEXTFREE_CHAN_MASK       0x1F
  61#define S6_DMA_NEXTFREE_ENA             16
  62#define S6_DMA_NEXTFREE_ENA_MASK        ((1 << 16) - 1)
  63#define S6_DMA_DPORTCTRLGRP(p)  ((p) * 4 + 0x074)
  64#define S6_DMA_DPORTCTRLGRP_FRAMEREP    0
  65#define S6_DMA_DPORTCTRLGRP_NRCHANS     1
  66#define S6_DMA_DPORTCTRLGRP_NRCHANS_1           0
  67#define S6_DMA_DPORTCTRLGRP_NRCHANS_3           1
  68#define S6_DMA_DPORTCTRLGRP_NRCHANS_4           2
  69#define S6_DMA_DPORTCTRLGRP_NRCHANS_2           3
  70#define S6_DMA_DPORTCTRLGRP_ENA         31
  71
  72
  73/* DMA per channel */
  74
  75#define DMA_CHNL(dmac, n)       ((dmac) + 0x1000 + (n) * 0x100)
  76#define DMA_INDEX_CHNL(addr)    (((addr) >> 8) & 0xF)
  77#define DMA_MASK_DMAC(addr)     ((addr) & 0xFFFF0000)
  78#define S6_DMA_CHNCTRL          0x000
  79#define S6_DMA_CHNCTRL_ENABLE           0
  80#define S6_DMA_CHNCTRL_PAUSE            1
  81#define S6_DMA_CHNCTRL_PRIO             2
  82#define S6_DMA_CHNCTRL_PRIO_MASK                3
  83#define S6_DMA_CHNCTRL_PERIPHXFER       4
  84#define S6_DMA_CHNCTRL_PERIPHENA        5
  85#define S6_DMA_CHNCTRL_SRCINC           6
  86#define S6_DMA_CHNCTRL_DSTINC           7
  87#define S6_DMA_CHNCTRL_BURSTLOG         8
  88#define S6_DMA_CHNCTRL_BURSTLOG_MASK            7
  89#define S6_DMA_CHNCTRL_DESCFIFODEPTH    12
  90#define S6_DMA_CHNCTRL_DESCFIFODEPTH_MASK       0x1F
  91#define S6_DMA_CHNCTRL_DESCFIFOFULL     17
  92#define S6_DMA_CHNCTRL_BWCONSEL         18
  93#define S6_DMA_CHNCTRL_BWCONENA         19
  94#define S6_DMA_CHNCTRL_PENDGCNTSTAT     20
  95#define S6_DMA_CHNCTRL_PENDGCNTSTAT_MASK        0x3F
  96#define S6_DMA_CHNCTRL_LOWWMARK         26
  97#define S6_DMA_CHNCTRL_LOWWMARK_MASK            0xF
  98#define S6_DMA_CHNCTRL_TSTAMP           30
  99#define S6_DMA_TERMCNTNB        0x004
 100#define S6_DMA_TERMCNTNB_MASK                   0xFFFF
 101#define S6_DMA_TERMCNTTMO       0x008
 102#define S6_DMA_TERMCNTSTAT      0x00C
 103#define S6_DMA_TERMCNTSTAT_MASK         0xFF
 104#define S6_DMA_CMONCHUNK        0x010
 105#define S6_DMA_SRCSKIP          0x014
 106#define S6_DMA_DSTSKIP          0x018
 107#define S6_DMA_CUR_SRC          0x024
 108#define S6_DMA_CUR_DST          0x028
 109#define S6_DMA_TIMESTAMP        0x030
 110
 111/* DMA channel lists */
 112
 113#define S6_DPDMA_CHAN(stream, channel)  (4 * (stream) + (channel))
 114#define S6_DPDMA_NB     16
 115
 116#define S6_HIFDMA_GMACTX        0
 117#define S6_HIFDMA_GMACRX        1
 118#define S6_HIFDMA_I2S0          2
 119#define S6_HIFDMA_I2S1          3
 120#define S6_HIFDMA_EGIB          4
 121#define S6_HIFDMA_PCITX         5
 122#define S6_HIFDMA_PCIRX         6
 123#define S6_HIFDMA_NB    7
 124
 125#define S6_NIDMA_NB     4
 126
 127#define S6_LMSDMA_NB    12
 128
 129/* controller access */
 130
 131#define S6_DMAC_NB      4
 132#define S6_DMAC_INDEX(dmac)     (((unsigned)(dmac) >> 18) % S6_DMAC_NB)
 133
 134struct s6dmac_ctrl {
 135        u32 dmac;
 136        spinlock_t lock;
 137        u8 chan_nb;
 138};
 139
 140extern struct s6dmac_ctrl s6dmac_ctrl[S6_DMAC_NB];
 141
 142
 143/* DMA control, per channel */
 144
 145static inline int s6dmac_fifo_full(u32 dmac, int chan)
 146{
 147        return (readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL)
 148                & (1 << S6_DMA_CHNCTRL_DESCFIFOFULL)) && 1;
 149}
 150
 151static inline int s6dmac_termcnt_irq(u32 dmac, int chan)
 152{
 153        u32 m = 1 << chan;
 154        int r = (readl(dmac + S6_DMA_TERMCNTIRQSTAT) & m) && 1;
 155        if (r)
 156                writel(m, dmac + S6_DMA_TERMCNTIRQCLR);
 157        return r;
 158}
 159
 160static inline int s6dmac_pendcnt_irq(u32 dmac, int chan)
 161{
 162        u32 m = 1 << chan;
 163        int r = (readl(dmac + S6_DMA_PENDCNTIRQSTAT) & m) && 1;
 164        if (r)
 165                writel(m, dmac + S6_DMA_PENDCNTIRQCLR);
 166        return r;
 167}
 168
 169static inline int s6dmac_lowwmark_irq(u32 dmac, int chan)
 170{
 171        int r = (readl(dmac + S6_DMA_LOWWMRKIRQSTAT) & (1 << chan)) ? 1 : 0;
 172        if (r)
 173                writel(1 << chan, dmac + S6_DMA_LOWWMRKIRQCLR);
 174        return r;
 175}
 176
 177static inline u32 s6dmac_pending_count(u32 dmac, int chan)
 178{
 179        return (readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL)
 180                        >> S6_DMA_CHNCTRL_PENDGCNTSTAT)
 181                & S6_DMA_CHNCTRL_PENDGCNTSTAT_MASK;
 182}
 183
 184static inline void s6dmac_set_terminal_count(u32 dmac, int chan, u32 n)
 185{
 186        n &= S6_DMA_TERMCNTNB_MASK;
 187        n |= readl(DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB)
 188              & ~S6_DMA_TERMCNTNB_MASK;
 189        writel(n, DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB);
 190}
 191
 192static inline u32 s6dmac_get_terminal_count(u32 dmac, int chan)
 193{
 194        return (readl(DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB))
 195                & S6_DMA_TERMCNTNB_MASK;
 196}
 197
 198static inline u32 s6dmac_timestamp(u32 dmac, int chan)
 199{
 200        return readl(DMA_CHNL(dmac, chan) + S6_DMA_TIMESTAMP);
 201}
 202
 203static inline u32 s6dmac_cur_src(u32 dmac, int chan)
 204{
 205        return readl(DMA_CHNL(dmac, chan) + S6_DMA_CUR_SRC);
 206}
 207
 208static inline u32 s6dmac_cur_dst(u32 dmac, int chan)
 209{
 210        return readl(DMA_CHNL(dmac, chan) + S6_DMA_CUR_DST);
 211}
 212
 213static inline void s6dmac_disable_chan(u32 dmac, int chan)
 214{
 215        u32 ctrl;
 216        writel(readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL)
 217                & ~(1 << S6_DMA_CHNCTRL_ENABLE),
 218                DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL);
 219        do
 220                ctrl = readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL);
 221        while (ctrl & (1 << S6_DMA_CHNCTRL_ENABLE));
 222}
 223
 224static inline void s6dmac_set_stride_skip(u32 dmac, int chan,
 225        int comchunk,           /* 0: disable scatter/gather */
 226        int srcskip, int dstskip)
 227{
 228        writel(comchunk, DMA_CHNL(dmac, chan) + S6_DMA_CMONCHUNK);
 229        writel(srcskip, DMA_CHNL(dmac, chan) + S6_DMA_SRCSKIP);
 230        writel(dstskip, DMA_CHNL(dmac, chan) + S6_DMA_DSTSKIP);
 231}
 232
 233static inline void s6dmac_enable_chan(u32 dmac, int chan,
 234        int prio,               /* 0 (highest) .. 3 (lowest) */
 235        int periphxfer,         /* <0: disable p.req.line, 0..1: mode */
 236        int srcinc, int dstinc, /* 0: dont increment src/dst address */
 237        int comchunk,           /* 0: disable scatter/gather */
 238        int srcskip, int dstskip,
 239        int burstsize,          /* 4 for I2S, 7 for everything else */
 240        int bandwidthconserve,  /* <0: disable, 0..1: select */
 241        int lowwmark,           /* 0..15 */
 242        int timestamp,          /* 0: disable timestamp */
 243        int enable)             /* 0: disable for now */
 244{
 245        writel(1, DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB);
 246        writel(0, DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTTMO);
 247        writel(lowwmark << S6_DMA_CHNCTRL_LOWWMARK,
 248                DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL);
 249        s6dmac_set_stride_skip(dmac, chan, comchunk, srcskip, dstskip);
 250        writel(((enable ? 1 : 0) << S6_DMA_CHNCTRL_ENABLE) |
 251                (prio << S6_DMA_CHNCTRL_PRIO) |
 252                (((periphxfer > 0) ? 1 : 0) << S6_DMA_CHNCTRL_PERIPHXFER) |
 253                (((periphxfer < 0) ? 0 : 1) << S6_DMA_CHNCTRL_PERIPHENA) |
 254                ((srcinc ? 1 : 0) << S6_DMA_CHNCTRL_SRCINC) |
 255                ((dstinc ? 1 : 0) << S6_DMA_CHNCTRL_DSTINC) |
 256                (burstsize << S6_DMA_CHNCTRL_BURSTLOG) |
 257                (((bandwidthconserve > 0) ? 1 : 0) << S6_DMA_CHNCTRL_BWCONSEL) |
 258                (((bandwidthconserve < 0) ? 0 : 1) << S6_DMA_CHNCTRL_BWCONENA) |
 259                (lowwmark << S6_DMA_CHNCTRL_LOWWMARK) |
 260                ((timestamp ? 1 : 0) << S6_DMA_CHNCTRL_TSTAMP),
 261                DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL);
 262}
 263
 264
 265/* DMA control, per engine */
 266
 267static inline unsigned _dmac_addr_index(u32 dmac)
 268{
 269        unsigned i = S6_DMAC_INDEX(dmac);
 270        if (s6dmac_ctrl[i].dmac != dmac)
 271                BUG();
 272        return i;
 273}
 274
 275static inline void _s6dmac_disable_error_irqs(u32 dmac, u32 mask)
 276{
 277        writel(mask, dmac + S6_DMA_TERMCNTIRQCLR);
 278        writel(mask, dmac + S6_DMA_PENDCNTIRQCLR);
 279        writel(mask, dmac + S6_DMA_LOWWMRKIRQCLR);
 280        writel(readl(dmac + S6_DMA_INTENABLE0)
 281                & ~((mask << S6_DMA_INT0_UNDER) | (mask << S6_DMA_INT0_OVER)),
 282                dmac + S6_DMA_INTENABLE0);
 283        writel(readl(dmac + S6_DMA_INTENABLE1) & ~(mask << S6_DMA_INT1_CHANNEL),
 284                dmac + S6_DMA_INTENABLE1);
 285        writel((mask << S6_DMA_INT0_UNDER) | (mask << S6_DMA_INT0_OVER),
 286                dmac + S6_DMA_INTCLEAR0);
 287        writel(mask << S6_DMA_INT1_CHANNEL, dmac + S6_DMA_INTCLEAR1);
 288}
 289
 290/*
 291 * request channel from specified engine
 292 * with chan<0, accept any channel
 293 * further parameters see s6dmac_enable_chan
 294 * returns < 0 upon error, channel nb otherwise
 295 */
 296static inline int s6dmac_request_chan(u32 dmac, int chan,
 297        int prio,
 298        int periphxfer,
 299        int srcinc, int dstinc,
 300        int comchunk,
 301        int srcskip, int dstskip,
 302        int burstsize,
 303        int bandwidthconserve,
 304        int lowwmark,
 305        int timestamp,
 306        int enable)
 307{
 308        int r = chan;
 309        unsigned long flags;
 310        spinlock_t *spinl = &s6dmac_ctrl[_dmac_addr_index(dmac)].lock;
 311        spin_lock_irqsave(spinl, flags);
 312        if (r < 0) {
 313                r = (readl(dmac + S6_DMA_NEXTFREE) >> S6_DMA_NEXTFREE_CHAN)
 314                        & S6_DMA_NEXTFREE_CHAN_MASK;
 315        }
 316        if (r >= s6dmac_ctrl[_dmac_addr_index(dmac)].chan_nb) {
 317                if (chan < 0)
 318                        r = -EBUSY;
 319                else
 320                        r = -ENXIO;
 321        } else if (((readl(dmac + S6_DMA_NEXTFREE) >> S6_DMA_NEXTFREE_ENA)
 322                        >> r) & 1) {
 323                r = -EBUSY;
 324        } else {
 325                s6dmac_enable_chan(dmac, r, prio, periphxfer,
 326                        srcinc, dstinc, comchunk, srcskip, dstskip, burstsize,
 327                        bandwidthconserve, lowwmark, timestamp, enable);
 328        }
 329        spin_unlock_irqrestore(spinl, flags);
 330        return r;
 331}
 332
 333static inline void s6dmac_put_fifo(u32 dmac, int chan,
 334        u32 src, u32 dst, u32 size)
 335{
 336        unsigned long flags;
 337        spinlock_t *spinl = &s6dmac_ctrl[_dmac_addr_index(dmac)].lock;
 338        spin_lock_irqsave(spinl, flags);
 339        writel(src, dmac + S6_DMA_DESCRFIFO0);
 340        writel(dst, dmac + S6_DMA_DESCRFIFO1);
 341        writel(size, dmac + S6_DMA_DESCRFIFO2);
 342        writel(chan, dmac + S6_DMA_DESCRFIFO3);
 343        spin_unlock_irqrestore(spinl, flags);
 344}
 345
 346static inline u32 s6dmac_channel_enabled(u32 dmac, int chan)
 347{
 348        return readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL) &
 349                        (1 << S6_DMA_CHNCTRL_ENABLE);
 350}
 351
 352/*
 353 * group 1-4 data port channels
 354 * with port=0..3, nrch=1-4 channels,
 355 * frrep=0/1 (dis- or enable frame repeat)
 356 */
 357static inline void s6dmac_dp_setup_group(u32 dmac, int port,
 358                        int nrch, int frrep)
 359{
 360        static const u8 mask[4] = {0, 3, 1, 2};
 361        BUG_ON(dmac != S6_REG_DPDMA);
 362        if ((port < 0) || (port > 3) || (nrch < 1) || (nrch > 4))
 363                return;
 364        writel((mask[nrch - 1] << S6_DMA_DPORTCTRLGRP_NRCHANS)
 365                | ((frrep ? 1 : 0) << S6_DMA_DPORTCTRLGRP_FRAMEREP),
 366                dmac + S6_DMA_DPORTCTRLGRP(port));
 367}
 368
 369static inline void s6dmac_dp_switch_group(u32 dmac, int port, int enable)
 370{
 371        u32 tmp;
 372        BUG_ON(dmac != S6_REG_DPDMA);
 373        tmp = readl(dmac + S6_DMA_DPORTCTRLGRP(port));
 374        if (enable)
 375                tmp |= (1 << S6_DMA_DPORTCTRLGRP_ENA);
 376        else
 377                tmp &= ~(1 << S6_DMA_DPORTCTRLGRP_ENA);
 378        writel(tmp, dmac + S6_DMA_DPORTCTRLGRP(port));
 379}
 380
 381extern void s6dmac_put_fifo_cache(u32 dmac, int chan,
 382        u32 src, u32 dst, u32 size);
 383extern void s6dmac_disable_error_irqs(u32 dmac, u32 mask);
 384extern u32 s6dmac_int_sources(u32 dmac, u32 channel);
 385extern void s6dmac_release_chan(u32 dmac, int chan);
 386
 387#endif /* __ASM_XTENSA_S6000_DMAC_H */
 388