xref: /openbmc/qemu/hw/dma/sifive_pdma.c (revision afe33262585565b64df706c62b4b0f6e0ad30c71)
197ba4223SBin Meng /*
297ba4223SBin Meng  * SiFive Platform DMA emulation
397ba4223SBin Meng  *
497ba4223SBin Meng  * Copyright (c) 2020 Wind River Systems, Inc.
597ba4223SBin Meng  *
697ba4223SBin Meng  * Author:
797ba4223SBin Meng  *   Bin Meng <bin.meng@windriver.com>
897ba4223SBin Meng  *
997ba4223SBin Meng  * This program is free software; you can redistribute it and/or
1097ba4223SBin Meng  * modify it under the terms of the GNU General Public License as
1197ba4223SBin Meng  * published by the Free Software Foundation; either version 2 or
1297ba4223SBin Meng  * (at your option) version 3 of the License.
1397ba4223SBin Meng  *
1497ba4223SBin Meng  * This program is distributed in the hope that it will be useful,
1597ba4223SBin Meng  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1697ba4223SBin Meng  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1797ba4223SBin Meng  * GNU General Public License for more details.
1897ba4223SBin Meng  *
1997ba4223SBin Meng  * You should have received a copy of the GNU General Public License along
2097ba4223SBin Meng  * with this program; if not, see <http://www.gnu.org/licenses/>.
2197ba4223SBin Meng  */
2297ba4223SBin Meng 
2397ba4223SBin Meng #include "qemu/osdep.h"
2497ba4223SBin Meng #include "qemu/bitops.h"
2597ba4223SBin Meng #include "qemu/log.h"
2697ba4223SBin Meng #include "qapi/error.h"
2797ba4223SBin Meng #include "hw/irq.h"
2897ba4223SBin Meng #include "hw/qdev-properties.h"
2997ba4223SBin Meng #include "hw/sysbus.h"
3097ba4223SBin Meng #include "migration/vmstate.h"
3197ba4223SBin Meng #include "sysemu/dma.h"
3297ba4223SBin Meng #include "hw/dma/sifive_pdma.h"
3397ba4223SBin Meng 
3497ba4223SBin Meng #define DMA_CONTROL         0x000
3597ba4223SBin Meng #define   CONTROL_CLAIM     BIT(0)
3697ba4223SBin Meng #define   CONTROL_RUN       BIT(1)
3797ba4223SBin Meng #define   CONTROL_DONE_IE   BIT(14)
3897ba4223SBin Meng #define   CONTROL_ERR_IE    BIT(15)
3997ba4223SBin Meng #define   CONTROL_DONE      BIT(30)
4097ba4223SBin Meng #define   CONTROL_ERR       BIT(31)
4197ba4223SBin Meng 
4297ba4223SBin Meng #define DMA_NEXT_CONFIG     0x004
4397ba4223SBin Meng #define   CONFIG_REPEAT     BIT(2)
4497ba4223SBin Meng #define   CONFIG_ORDER      BIT(3)
4597ba4223SBin Meng #define   CONFIG_WRSZ_SHIFT 24
4697ba4223SBin Meng #define   CONFIG_RDSZ_SHIFT 28
4797ba4223SBin Meng #define   CONFIG_SZ_MASK    0xf
4897ba4223SBin Meng 
4997ba4223SBin Meng #define DMA_NEXT_BYTES      0x008
5097ba4223SBin Meng #define DMA_NEXT_DST        0x010
5197ba4223SBin Meng #define DMA_NEXT_SRC        0x018
5297ba4223SBin Meng #define DMA_EXEC_CONFIG     0x104
5397ba4223SBin Meng #define DMA_EXEC_BYTES      0x108
5497ba4223SBin Meng #define DMA_EXEC_DST        0x110
5597ba4223SBin Meng #define DMA_EXEC_SRC        0x118
5697ba4223SBin Meng 
57de7c7988SFrank Chang /*
58de7c7988SFrank Chang  * FU540/FU740 docs are incorrect with NextConfig.wsize/rsize reset values.
59de7c7988SFrank Chang  * The reset values tested on Unleashed/Unmatched boards are 6 instead of 0.
60de7c7988SFrank Chang  */
61de7c7988SFrank Chang #define CONFIG_WRSZ_DEFAULT 6
62de7c7988SFrank Chang #define CONFIG_RDSZ_DEFAULT 6
63de7c7988SFrank Chang 
6497ba4223SBin Meng enum dma_chan_state {
6597ba4223SBin Meng     DMA_CHAN_STATE_IDLE,
6697ba4223SBin Meng     DMA_CHAN_STATE_STARTED,
6797ba4223SBin Meng     DMA_CHAN_STATE_ERROR,
6897ba4223SBin Meng     DMA_CHAN_STATE_DONE
6997ba4223SBin Meng };
7097ba4223SBin Meng 
sifive_pdma_run(SiFivePDMAState * s,int ch)7197ba4223SBin Meng static void sifive_pdma_run(SiFivePDMAState *s, int ch)
7297ba4223SBin Meng {
7397ba4223SBin Meng     uint64_t bytes = s->chan[ch].next_bytes;
7497ba4223SBin Meng     uint64_t dst = s->chan[ch].next_dst;
7597ba4223SBin Meng     uint64_t src = s->chan[ch].next_src;
7697ba4223SBin Meng     uint32_t config = s->chan[ch].next_config;
77e22d90f5SGreen Wan     int wsize, rsize, size, remainder;
7897ba4223SBin Meng     uint8_t buf[64];
7997ba4223SBin Meng     int n;
8097ba4223SBin Meng 
8197ba4223SBin Meng     /* do nothing if bytes to transfer is zero */
8297ba4223SBin Meng     if (!bytes) {
83ae000c5fSFrank Chang         goto done;
8497ba4223SBin Meng     }
8597ba4223SBin Meng 
8697ba4223SBin Meng     /*
8797ba4223SBin Meng      * The manual does not describe how the hardware behaviors when
8897ba4223SBin Meng      * config.wsize and config.rsize are given different values.
8997ba4223SBin Meng      * A common case is memory to memory DMA, and in this case they
9097ba4223SBin Meng      * are normally the same. Abort if this expectation fails.
9197ba4223SBin Meng      */
9297ba4223SBin Meng     wsize = (config >> CONFIG_WRSZ_SHIFT) & CONFIG_SZ_MASK;
9397ba4223SBin Meng     rsize = (config >> CONFIG_RDSZ_SHIFT) & CONFIG_SZ_MASK;
9497ba4223SBin Meng     if (wsize != rsize) {
9597ba4223SBin Meng         goto error;
9697ba4223SBin Meng     }
9797ba4223SBin Meng 
9897ba4223SBin Meng     /*
9997ba4223SBin Meng      * Calculate the transaction size
10097ba4223SBin Meng      *
10197ba4223SBin Meng      * size field is base 2 logarithm of DMA transaction size,
10297ba4223SBin Meng      * but there is an upper limit of 64 bytes per transaction.
10397ba4223SBin Meng      */
10497ba4223SBin Meng     size = wsize;
10597ba4223SBin Meng     if (size > 6) {
10697ba4223SBin Meng         size = 6;
10797ba4223SBin Meng     }
10897ba4223SBin Meng     size = 1 << size;
109e22d90f5SGreen Wan     remainder = bytes % size;
11097ba4223SBin Meng 
11197ba4223SBin Meng     /* indicate a DMA transfer is started */
11297ba4223SBin Meng     s->chan[ch].state = DMA_CHAN_STATE_STARTED;
11397ba4223SBin Meng     s->chan[ch].control &= ~CONTROL_DONE;
11497ba4223SBin Meng     s->chan[ch].control &= ~CONTROL_ERR;
11597ba4223SBin Meng 
11697ba4223SBin Meng     /* load the next_ registers into their exec_ counterparts */
11797ba4223SBin Meng     s->chan[ch].exec_config = config;
11897ba4223SBin Meng     s->chan[ch].exec_bytes = bytes;
11997ba4223SBin Meng     s->chan[ch].exec_dst = dst;
12097ba4223SBin Meng     s->chan[ch].exec_src = src;
12197ba4223SBin Meng 
12297ba4223SBin Meng     for (n = 0; n < bytes / size; n++) {
12397ba4223SBin Meng         cpu_physical_memory_read(s->chan[ch].exec_src, buf, size);
12497ba4223SBin Meng         cpu_physical_memory_write(s->chan[ch].exec_dst, buf, size);
12597ba4223SBin Meng         s->chan[ch].exec_src += size;
12697ba4223SBin Meng         s->chan[ch].exec_dst += size;
12797ba4223SBin Meng         s->chan[ch].exec_bytes -= size;
12897ba4223SBin Meng     }
12997ba4223SBin Meng 
130e22d90f5SGreen Wan     if (remainder) {
131e22d90f5SGreen Wan         cpu_physical_memory_read(s->chan[ch].exec_src, buf, remainder);
132e22d90f5SGreen Wan         cpu_physical_memory_write(s->chan[ch].exec_dst, buf, remainder);
133e22d90f5SGreen Wan         s->chan[ch].exec_src += remainder;
134e22d90f5SGreen Wan         s->chan[ch].exec_dst += remainder;
135e22d90f5SGreen Wan         s->chan[ch].exec_bytes -= remainder;
136e22d90f5SGreen Wan     }
137e22d90f5SGreen Wan 
13897ba4223SBin Meng     /* reload exec_ registers if repeat is required */
13997ba4223SBin Meng     if (s->chan[ch].next_config & CONFIG_REPEAT) {
14097ba4223SBin Meng         s->chan[ch].exec_bytes = bytes;
14197ba4223SBin Meng         s->chan[ch].exec_dst = dst;
14297ba4223SBin Meng         s->chan[ch].exec_src = src;
14397ba4223SBin Meng     }
14497ba4223SBin Meng 
145ae000c5fSFrank Chang done:
146ae000c5fSFrank Chang     /* indicate a DMA transfer is done */
147ae000c5fSFrank Chang     s->chan[ch].state = DMA_CHAN_STATE_DONE;
148ae000c5fSFrank Chang     s->chan[ch].control &= ~CONTROL_RUN;
149ae000c5fSFrank Chang     s->chan[ch].control |= CONTROL_DONE;
15097ba4223SBin Meng     return;
15197ba4223SBin Meng 
15297ba4223SBin Meng error:
15397ba4223SBin Meng     s->chan[ch].state = DMA_CHAN_STATE_ERROR;
15497ba4223SBin Meng     s->chan[ch].control |= CONTROL_ERR;
15597ba4223SBin Meng     return;
15697ba4223SBin Meng }
15797ba4223SBin Meng 
sifive_pdma_update_irq(SiFivePDMAState * s,int ch)15897ba4223SBin Meng static inline void sifive_pdma_update_irq(SiFivePDMAState *s, int ch)
15997ba4223SBin Meng {
16097ba4223SBin Meng     bool done_ie, err_ie;
16197ba4223SBin Meng 
16297ba4223SBin Meng     done_ie = !!(s->chan[ch].control & CONTROL_DONE_IE);
16397ba4223SBin Meng     err_ie = !!(s->chan[ch].control & CONTROL_ERR_IE);
16497ba4223SBin Meng 
16597ba4223SBin Meng     if (done_ie && (s->chan[ch].control & CONTROL_DONE)) {
16697ba4223SBin Meng         qemu_irq_raise(s->irq[ch * 2]);
16797ba4223SBin Meng     } else {
16897ba4223SBin Meng         qemu_irq_lower(s->irq[ch * 2]);
16997ba4223SBin Meng     }
17097ba4223SBin Meng 
17197ba4223SBin Meng     if (err_ie && (s->chan[ch].control & CONTROL_ERR)) {
17297ba4223SBin Meng         qemu_irq_raise(s->irq[ch * 2 + 1]);
17397ba4223SBin Meng     } else {
17497ba4223SBin Meng         qemu_irq_lower(s->irq[ch * 2 + 1]);
17597ba4223SBin Meng     }
17697ba4223SBin Meng 
17797ba4223SBin Meng     s->chan[ch].state = DMA_CHAN_STATE_IDLE;
17897ba4223SBin Meng }
17997ba4223SBin Meng 
sifive_pdma_readq(SiFivePDMAState * s,int ch,hwaddr offset)1806fd3f397SJim Shu static uint64_t sifive_pdma_readq(SiFivePDMAState *s, int ch, hwaddr offset)
1816fd3f397SJim Shu {
1826fd3f397SJim Shu     uint64_t val = 0;
1836fd3f397SJim Shu 
1846fd3f397SJim Shu     offset &= 0xfff;
1856fd3f397SJim Shu     switch (offset) {
1866fd3f397SJim Shu     case DMA_NEXT_BYTES:
1876fd3f397SJim Shu         val = s->chan[ch].next_bytes;
1886fd3f397SJim Shu         break;
1896fd3f397SJim Shu     case DMA_NEXT_DST:
1906fd3f397SJim Shu         val = s->chan[ch].next_dst;
1916fd3f397SJim Shu         break;
1926fd3f397SJim Shu     case DMA_NEXT_SRC:
1936fd3f397SJim Shu         val = s->chan[ch].next_src;
1946fd3f397SJim Shu         break;
1956fd3f397SJim Shu     case DMA_EXEC_BYTES:
1966fd3f397SJim Shu         val = s->chan[ch].exec_bytes;
1976fd3f397SJim Shu         break;
1986fd3f397SJim Shu     case DMA_EXEC_DST:
1996fd3f397SJim Shu         val = s->chan[ch].exec_dst;
2006fd3f397SJim Shu         break;
2016fd3f397SJim Shu     case DMA_EXEC_SRC:
2026fd3f397SJim Shu         val = s->chan[ch].exec_src;
2036fd3f397SJim Shu         break;
2046fd3f397SJim Shu     default:
2056fd3f397SJim Shu         qemu_log_mask(LOG_GUEST_ERROR,
2066fd3f397SJim Shu                       "%s: Unexpected 64-bit access to 0x%" HWADDR_PRIX "\n",
2076fd3f397SJim Shu                       __func__, offset);
2086fd3f397SJim Shu         break;
2096fd3f397SJim Shu     }
2106fd3f397SJim Shu 
2116fd3f397SJim Shu     return val;
2126fd3f397SJim Shu }
2136fd3f397SJim Shu 
sifive_pdma_readl(SiFivePDMAState * s,int ch,hwaddr offset)2146fd3f397SJim Shu static uint32_t sifive_pdma_readl(SiFivePDMAState *s, int ch, hwaddr offset)
2156fd3f397SJim Shu {
2166fd3f397SJim Shu     uint32_t val = 0;
2176fd3f397SJim Shu 
2186fd3f397SJim Shu     offset &= 0xfff;
2196fd3f397SJim Shu     switch (offset) {
2206fd3f397SJim Shu     case DMA_CONTROL:
2216fd3f397SJim Shu         val = s->chan[ch].control;
2226fd3f397SJim Shu         break;
2236fd3f397SJim Shu     case DMA_NEXT_CONFIG:
2246fd3f397SJim Shu         val = s->chan[ch].next_config;
2256fd3f397SJim Shu         break;
2266fd3f397SJim Shu     case DMA_NEXT_BYTES:
2276fd3f397SJim Shu         val = extract64(s->chan[ch].next_bytes, 0, 32);
2286fd3f397SJim Shu         break;
2296fd3f397SJim Shu     case DMA_NEXT_BYTES + 4:
2306fd3f397SJim Shu         val = extract64(s->chan[ch].next_bytes, 32, 32);
2316fd3f397SJim Shu         break;
2326fd3f397SJim Shu     case DMA_NEXT_DST:
2336fd3f397SJim Shu         val = extract64(s->chan[ch].next_dst, 0, 32);
2346fd3f397SJim Shu         break;
2356fd3f397SJim Shu     case DMA_NEXT_DST + 4:
2366fd3f397SJim Shu         val = extract64(s->chan[ch].next_dst, 32, 32);
2376fd3f397SJim Shu         break;
2386fd3f397SJim Shu     case DMA_NEXT_SRC:
2396fd3f397SJim Shu         val = extract64(s->chan[ch].next_src, 0, 32);
2406fd3f397SJim Shu         break;
2416fd3f397SJim Shu     case DMA_NEXT_SRC + 4:
2426fd3f397SJim Shu         val = extract64(s->chan[ch].next_src, 32, 32);
2436fd3f397SJim Shu         break;
2446fd3f397SJim Shu     case DMA_EXEC_CONFIG:
2456fd3f397SJim Shu         val = s->chan[ch].exec_config;
2466fd3f397SJim Shu         break;
2476fd3f397SJim Shu     case DMA_EXEC_BYTES:
2486fd3f397SJim Shu         val = extract64(s->chan[ch].exec_bytes, 0, 32);
2496fd3f397SJim Shu         break;
2506fd3f397SJim Shu     case DMA_EXEC_BYTES + 4:
2516fd3f397SJim Shu         val = extract64(s->chan[ch].exec_bytes, 32, 32);
2526fd3f397SJim Shu         break;
2536fd3f397SJim Shu     case DMA_EXEC_DST:
2546fd3f397SJim Shu         val = extract64(s->chan[ch].exec_dst, 0, 32);
2556fd3f397SJim Shu         break;
2566fd3f397SJim Shu     case DMA_EXEC_DST + 4:
2576fd3f397SJim Shu         val = extract64(s->chan[ch].exec_dst, 32, 32);
2586fd3f397SJim Shu         break;
2596fd3f397SJim Shu     case DMA_EXEC_SRC:
2606fd3f397SJim Shu         val = extract64(s->chan[ch].exec_src, 0, 32);
2616fd3f397SJim Shu         break;
2626fd3f397SJim Shu     case DMA_EXEC_SRC + 4:
2636fd3f397SJim Shu         val = extract64(s->chan[ch].exec_src, 32, 32);
2646fd3f397SJim Shu         break;
2656fd3f397SJim Shu     default:
2666fd3f397SJim Shu         qemu_log_mask(LOG_GUEST_ERROR,
2676fd3f397SJim Shu                       "%s: Unexpected 32-bit access to 0x%" HWADDR_PRIX "\n",
2686fd3f397SJim Shu                       __func__, offset);
2696fd3f397SJim Shu         break;
2706fd3f397SJim Shu     }
2716fd3f397SJim Shu 
2726fd3f397SJim Shu     return val;
2736fd3f397SJim Shu }
2746fd3f397SJim Shu 
sifive_pdma_read(void * opaque,hwaddr offset,unsigned size)27597ba4223SBin Meng static uint64_t sifive_pdma_read(void *opaque, hwaddr offset, unsigned size)
27697ba4223SBin Meng {
27797ba4223SBin Meng     SiFivePDMAState *s = opaque;
27897ba4223SBin Meng     int ch = SIFIVE_PDMA_CHAN_NO(offset);
27997ba4223SBin Meng     uint64_t val = 0;
28097ba4223SBin Meng 
28197ba4223SBin Meng     if (ch >= SIFIVE_PDMA_CHANS) {
28297ba4223SBin Meng         qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid channel no %d\n",
28397ba4223SBin Meng                       __func__, ch);
28497ba4223SBin Meng         return 0;
28597ba4223SBin Meng     }
28697ba4223SBin Meng 
2876fd3f397SJim Shu     switch (size) {
2886fd3f397SJim Shu     case 8:
2896fd3f397SJim Shu         val = sifive_pdma_readq(s, ch, offset);
29097ba4223SBin Meng         break;
2916fd3f397SJim Shu     case 4:
2926fd3f397SJim Shu         val = sifive_pdma_readl(s, ch, offset);
29397ba4223SBin Meng         break;
29497ba4223SBin Meng     default:
2956fd3f397SJim Shu         qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid read size %u to PDMA\n",
2966fd3f397SJim Shu                       __func__, size);
2976fd3f397SJim Shu         return 0;
29897ba4223SBin Meng     }
29997ba4223SBin Meng 
30097ba4223SBin Meng     return val;
30197ba4223SBin Meng }
30297ba4223SBin Meng 
sifive_pdma_writeq(SiFivePDMAState * s,int ch,hwaddr offset,uint64_t value)3036fd3f397SJim Shu static void sifive_pdma_writeq(SiFivePDMAState *s, int ch,
3046fd3f397SJim Shu                                hwaddr offset, uint64_t value)
30597ba4223SBin Meng {
3066fd3f397SJim Shu     offset &= 0xfff;
3076fd3f397SJim Shu     switch (offset) {
3086fd3f397SJim Shu     case DMA_NEXT_BYTES:
3096fd3f397SJim Shu         s->chan[ch].next_bytes = value;
3106fd3f397SJim Shu         break;
3116fd3f397SJim Shu     case DMA_NEXT_DST:
3126fd3f397SJim Shu         s->chan[ch].next_dst = value;
3136fd3f397SJim Shu         break;
3146fd3f397SJim Shu     case DMA_NEXT_SRC:
3156fd3f397SJim Shu         s->chan[ch].next_src = value;
3166fd3f397SJim Shu         break;
3176fd3f397SJim Shu     case DMA_EXEC_BYTES:
3186fd3f397SJim Shu     case DMA_EXEC_DST:
3196fd3f397SJim Shu     case DMA_EXEC_SRC:
3206fd3f397SJim Shu         /* these are read-only registers */
3216fd3f397SJim Shu         break;
3226fd3f397SJim Shu     default:
3236fd3f397SJim Shu         qemu_log_mask(LOG_GUEST_ERROR,
3246fd3f397SJim Shu                       "%s: Unexpected 64-bit access to 0x%" HWADDR_PRIX "\n",
3256fd3f397SJim Shu                       __func__, offset);
3266fd3f397SJim Shu         break;
32797ba4223SBin Meng     }
3286fd3f397SJim Shu }
3296fd3f397SJim Shu 
sifive_pdma_writel(SiFivePDMAState * s,int ch,hwaddr offset,uint32_t value)3306fd3f397SJim Shu static void sifive_pdma_writel(SiFivePDMAState *s, int ch,
3316fd3f397SJim Shu                                hwaddr offset, uint32_t value)
3326fd3f397SJim Shu {
3336fd3f397SJim Shu     bool claimed, run;
33497ba4223SBin Meng 
33597ba4223SBin Meng     offset &= 0xfff;
33697ba4223SBin Meng     switch (offset) {
33797ba4223SBin Meng     case DMA_CONTROL:
338b7af62aeSBin Meng         claimed = !!(s->chan[ch].control & CONTROL_CLAIM);
33947b5fbf5SBin Meng         run = !!(s->chan[ch].control & CONTROL_RUN);
340de7c7988SFrank Chang 
341de7c7988SFrank Chang         if (!claimed && (value & CONTROL_CLAIM)) {
342de7c7988SFrank Chang             /* reset Next* registers */
343de7c7988SFrank Chang             s->chan[ch].next_config = (CONFIG_RDSZ_DEFAULT << CONFIG_RDSZ_SHIFT) |
344de7c7988SFrank Chang                                       (CONFIG_WRSZ_DEFAULT << CONFIG_WRSZ_SHIFT);
345de7c7988SFrank Chang             s->chan[ch].next_bytes = 0;
346de7c7988SFrank Chang             s->chan[ch].next_dst = 0;
347de7c7988SFrank Chang             s->chan[ch].next_src = 0;
348de7c7988SFrank Chang         }
349de7c7988SFrank Chang 
35047b5fbf5SBin Meng         /* claim bit can only be cleared when run is low */
35147b5fbf5SBin Meng         if (run && !(value & CONTROL_CLAIM)) {
35247b5fbf5SBin Meng             value |= CONTROL_CLAIM;
35347b5fbf5SBin Meng         }
35447b5fbf5SBin Meng 
35597ba4223SBin Meng         s->chan[ch].control = value;
35697ba4223SBin Meng 
3579a8c26c0SFrank Chang         /*
3589a8c26c0SFrank Chang          * If channel was not claimed before run bit is set,
35947b5fbf5SBin Meng          * or if the channel is disclaimed when run was low,
3609a8c26c0SFrank Chang          * DMA won't run.
3619a8c26c0SFrank Chang          */
36247b5fbf5SBin Meng         if (!claimed || (!run && !(value & CONTROL_CLAIM))) {
3639a8c26c0SFrank Chang             s->chan[ch].control &= ~CONTROL_RUN;
3649a8c26c0SFrank Chang             return;
3659a8c26c0SFrank Chang         }
3669a8c26c0SFrank Chang 
36797ba4223SBin Meng         if (value & CONTROL_RUN) {
36897ba4223SBin Meng             sifive_pdma_run(s, ch);
36997ba4223SBin Meng         }
37097ba4223SBin Meng 
37197ba4223SBin Meng         sifive_pdma_update_irq(s, ch);
37297ba4223SBin Meng         break;
37397ba4223SBin Meng     case DMA_NEXT_CONFIG:
37497ba4223SBin Meng         s->chan[ch].next_config = value;
37597ba4223SBin Meng         break;
37697ba4223SBin Meng     case DMA_NEXT_BYTES:
3776fd3f397SJim Shu         s->chan[ch].next_bytes =
3786fd3f397SJim Shu             deposit64(s->chan[ch].next_bytes, 0, 32, value);
3796fd3f397SJim Shu         break;
3806fd3f397SJim Shu     case DMA_NEXT_BYTES + 4:
3816fd3f397SJim Shu         s->chan[ch].next_bytes =
3826fd3f397SJim Shu             deposit64(s->chan[ch].next_bytes, 32, 32, value);
38397ba4223SBin Meng         break;
38497ba4223SBin Meng     case DMA_NEXT_DST:
3856fd3f397SJim Shu         s->chan[ch].next_dst = deposit64(s->chan[ch].next_dst, 0, 32, value);
3866fd3f397SJim Shu         break;
3876fd3f397SJim Shu     case DMA_NEXT_DST + 4:
3886fd3f397SJim Shu         s->chan[ch].next_dst = deposit64(s->chan[ch].next_dst, 32, 32, value);
38997ba4223SBin Meng         break;
39097ba4223SBin Meng     case DMA_NEXT_SRC:
3916fd3f397SJim Shu         s->chan[ch].next_src = deposit64(s->chan[ch].next_src, 0, 32, value);
3926fd3f397SJim Shu         break;
3936fd3f397SJim Shu     case DMA_NEXT_SRC + 4:
3946fd3f397SJim Shu         s->chan[ch].next_src = deposit64(s->chan[ch].next_src, 32, 32, value);
39597ba4223SBin Meng         break;
39697ba4223SBin Meng     case DMA_EXEC_CONFIG:
39797ba4223SBin Meng     case DMA_EXEC_BYTES:
3986fd3f397SJim Shu     case DMA_EXEC_BYTES + 4:
39997ba4223SBin Meng     case DMA_EXEC_DST:
4006fd3f397SJim Shu     case DMA_EXEC_DST + 4:
40197ba4223SBin Meng     case DMA_EXEC_SRC:
4026fd3f397SJim Shu     case DMA_EXEC_SRC + 4:
40397ba4223SBin Meng         /* these are read-only registers */
40497ba4223SBin Meng         break;
40597ba4223SBin Meng     default:
4066fd3f397SJim Shu         qemu_log_mask(LOG_GUEST_ERROR,
4076fd3f397SJim Shu                       "%s: Unexpected 32-bit access to 0x%" HWADDR_PRIX "\n",
40897ba4223SBin Meng                       __func__, offset);
40997ba4223SBin Meng         break;
41097ba4223SBin Meng     }
41197ba4223SBin Meng }
41297ba4223SBin Meng 
sifive_pdma_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)4136fd3f397SJim Shu static void sifive_pdma_write(void *opaque, hwaddr offset,
4146fd3f397SJim Shu                               uint64_t value, unsigned size)
4156fd3f397SJim Shu {
4166fd3f397SJim Shu     SiFivePDMAState *s = opaque;
4176fd3f397SJim Shu     int ch = SIFIVE_PDMA_CHAN_NO(offset);
4186fd3f397SJim Shu 
4196fd3f397SJim Shu     if (ch >= SIFIVE_PDMA_CHANS) {
4206fd3f397SJim Shu         qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid channel no %d\n",
4216fd3f397SJim Shu                       __func__, ch);
4226fd3f397SJim Shu         return;
4236fd3f397SJim Shu     }
4246fd3f397SJim Shu 
4256fd3f397SJim Shu     switch (size) {
4266fd3f397SJim Shu     case 8:
4276fd3f397SJim Shu         sifive_pdma_writeq(s, ch, offset, value);
4286fd3f397SJim Shu         break;
4296fd3f397SJim Shu     case 4:
4306fd3f397SJim Shu         sifive_pdma_writel(s, ch, offset, (uint32_t) value);
4316fd3f397SJim Shu         break;
4326fd3f397SJim Shu     default:
4336fd3f397SJim Shu         qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid write size %u to PDMA\n",
4346fd3f397SJim Shu                       __func__, size);
4356fd3f397SJim Shu         break;
4366fd3f397SJim Shu     }
4376fd3f397SJim Shu }
4386fd3f397SJim Shu 
43997ba4223SBin Meng static const MemoryRegionOps sifive_pdma_ops = {
44097ba4223SBin Meng     .read = sifive_pdma_read,
44197ba4223SBin Meng     .write = sifive_pdma_write,
44297ba4223SBin Meng     .endianness = DEVICE_LITTLE_ENDIAN,
44397ba4223SBin Meng     /* there are 32-bit and 64-bit wide registers */
44497ba4223SBin Meng     .impl = {
44597ba4223SBin Meng         .min_access_size = 4,
44697ba4223SBin Meng         .max_access_size = 8,
447*e6b0408aSJim Shu     },
448*e6b0408aSJim Shu     .valid = {
449*e6b0408aSJim Shu         .min_access_size = 4,
450*e6b0408aSJim Shu         .max_access_size = 8,
45197ba4223SBin Meng     }
45297ba4223SBin Meng };
45397ba4223SBin Meng 
sifive_pdma_realize(DeviceState * dev,Error ** errp)45497ba4223SBin Meng static void sifive_pdma_realize(DeviceState *dev, Error **errp)
45597ba4223SBin Meng {
45697ba4223SBin Meng     SiFivePDMAState *s = SIFIVE_PDMA(dev);
45797ba4223SBin Meng     int i;
45897ba4223SBin Meng 
45997ba4223SBin Meng     memory_region_init_io(&s->iomem, OBJECT(dev), &sifive_pdma_ops, s,
46097ba4223SBin Meng                           TYPE_SIFIVE_PDMA, SIFIVE_PDMA_REG_SIZE);
46197ba4223SBin Meng     sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
46297ba4223SBin Meng 
46397ba4223SBin Meng     for (i = 0; i < SIFIVE_PDMA_IRQS; i++) {
46497ba4223SBin Meng         sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]);
46597ba4223SBin Meng     }
46697ba4223SBin Meng }
46797ba4223SBin Meng 
sifive_pdma_class_init(ObjectClass * klass,void * data)46897ba4223SBin Meng static void sifive_pdma_class_init(ObjectClass *klass, void *data)
46997ba4223SBin Meng {
47097ba4223SBin Meng     DeviceClass *dc = DEVICE_CLASS(klass);
47197ba4223SBin Meng 
47297ba4223SBin Meng     dc->desc = "SiFive Platform DMA controller";
47397ba4223SBin Meng     dc->realize = sifive_pdma_realize;
47497ba4223SBin Meng }
47597ba4223SBin Meng 
47697ba4223SBin Meng static const TypeInfo sifive_pdma_info = {
47797ba4223SBin Meng     .name          = TYPE_SIFIVE_PDMA,
47897ba4223SBin Meng     .parent        = TYPE_SYS_BUS_DEVICE,
47997ba4223SBin Meng     .instance_size = sizeof(SiFivePDMAState),
48097ba4223SBin Meng     .class_init    = sifive_pdma_class_init,
48197ba4223SBin Meng };
48297ba4223SBin Meng 
sifive_pdma_register_types(void)48397ba4223SBin Meng static void sifive_pdma_register_types(void)
48497ba4223SBin Meng {
48597ba4223SBin Meng     type_register_static(&sifive_pdma_info);
48697ba4223SBin Meng }
48797ba4223SBin Meng 
48897ba4223SBin Meng type_init(sifive_pdma_register_types)
489