18b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/*
28b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * QEMU DMA emulation
38b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
48b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Copyright (c) 2003-2004 Vassili Karpov (malc)
58b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
68b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Permission is hereby granted, free of charge, to any person obtaining a copy
78b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * of this software and associated documentation files (the "Software"), to deal
88b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * in the Software without restriction, including without limitation the rights
98b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * copies of the Software, and to permit persons to whom the Software is
118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * furnished to do so, subject to the following conditions:
128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * The above copyright notice and this permission notice shall be included in
148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * all copies or substantial portions of the Software.
158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * THE SOFTWARE.
238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "hw.h"
258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "isa.h"
268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* #define DEBUG_DMA */
288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define dolog(...) fprintf (stderr, "dma: " __VA_ARGS__)
308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG_DMA
318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__)
328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define ldebug(...) fprintf (stderr, "dma: " __VA_ARGS__)
338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else
348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define linfo(...)
358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define ldebug(...)
368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstruct dma_regs {
398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int now[2];
408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint16_t base[2];
418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t mode;
428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t page;
438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t pageh;
448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t dack;
458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t eop;
468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    DMA_transfer_handler transfer_handler;
478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    void *opaque;
488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define ADDR 0
518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define COUNT 1
528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic struct dma_cont {
548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t status;
558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t command;
568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t mask;
578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t flip_flop;
588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int dshift;
598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_regs regs[4];
608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} dma_controllers[2];
618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectenum {
638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CMD_MEMORY_TO_MEMORY = 0x01,
648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CMD_FIXED_ADDRESS    = 0x02,
658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CMD_BLOCK_CONTROLLER = 0x04,
668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CMD_COMPRESSED_TIME  = 0x08,
678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CMD_CYCLIC_PRIORITY  = 0x10,
688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CMD_EXTENDED_WRITE   = 0x20,
698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CMD_LOW_DREQ         = 0x40,
708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CMD_LOW_DACK         = 0x80,
718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CMD_NOT_SUPPORTED    = CMD_MEMORY_TO_MEMORY | CMD_FIXED_ADDRESS
728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    | CMD_COMPRESSED_TIME | CMD_CYCLIC_PRIORITY | CMD_EXTENDED_WRITE
738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    | CMD_LOW_DREQ | CMD_LOW_DACK
748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void DMA_run (void);
785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0};
808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void write_page (void *opaque, uint32_t nport, uint32_t data)
828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_cont *d = opaque;
848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ichan;
858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ichan = channels[nport & 7];
878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (-1 == ichan) {
888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dolog ("invalid channel %#x %#x\n", nport, data);
898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    d->regs[ichan].page = data;
928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void write_pageh (void *opaque, uint32_t nport, uint32_t data)
958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_cont *d = opaque;
978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ichan;
988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ichan = channels[nport & 7];
1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (-1 == ichan) {
1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dolog ("invalid channel %#x %#x\n", nport, data);
1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    d->regs[ichan].pageh = data;
1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint32_t read_page (void *opaque, uint32_t nport)
1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_cont *d = opaque;
1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ichan;
1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ichan = channels[nport & 7];
1138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (-1 == ichan) {
1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dolog ("invalid channel read %#x\n", nport);
1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return d->regs[ichan].page;
1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint32_t read_pageh (void *opaque, uint32_t nport)
1218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_cont *d = opaque;
1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ichan;
1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ichan = channels[nport & 7];
1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (-1 == ichan) {
1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dolog ("invalid channel read %#x\n", nport);
1288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return d->regs[ichan].pageh;
1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline void init_chan (struct dma_cont *d, int ichan)
1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_regs *r;
1368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    r = d->regs + ichan;
1388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    r->now[ADDR] = r->base[ADDR] << d->dshift;
1398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    r->now[COUNT] = 0;
1408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline int getff (struct dma_cont *d)
1438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ff;
1458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ff = d->flip_flop;
1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    d->flip_flop = !ff;
1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return ff;
1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint32_t read_chan (void *opaque, uint32_t nport)
1528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_cont *d = opaque;
1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ichan, nreg, iport, ff, val, dir;
1558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_regs *r;
1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    iport = (nport >> d->dshift) & 0x0f;
1588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ichan = iport >> 1;
1598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    nreg = iport & 1;
1608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    r = d->regs + ichan;
1618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dir = ((r->mode >> 5) & 1) ? -1 : 1;
1638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ff = getff (d);
1648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (nreg)
1658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        val = (r->base[COUNT] << d->dshift) - r->now[COUNT];
1668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    else
1678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        val = r->now[ADDR] + r->now[COUNT] * dir;
1688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ldebug ("read_chan %#x -> %d\n", iport, val);
1708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return (val >> (d->dshift + (ff << 3))) & 0xff;
1718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void write_chan (void *opaque, uint32_t nport, uint32_t data)
1748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_cont *d = opaque;
1768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int iport, ichan, nreg;
1778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_regs *r;
1788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    iport = (nport >> d->dshift) & 0x0f;
1808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ichan = iport >> 1;
1818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    nreg = iport & 1;
1828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    r = d->regs + ichan;
1838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (getff (d)) {
1848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        r->base[nreg] = (r->base[nreg] & 0xff) | ((data << 8) & 0xff00);
1858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        init_chan (d, ichan);
1868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
1878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        r->base[nreg] = (r->base[nreg] & 0xff00) | (data & 0xff);
1888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void write_cont (void *opaque, uint32_t nport, uint32_t data)
1928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_cont *d = opaque;
1948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int iport, ichan = 0;
1958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    iport = (nport >> d->dshift) & 0x0f;
1978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    switch (iport) {
1988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x08:                  /* command */
1998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if ((data != 0) && (data & CMD_NOT_SUPPORTED)) {
2008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            dolog ("command %#x not supported\n", data);
2018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return;
2028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
2038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        d->command = data;
2048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
2058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x09:
2078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ichan = data & 3;
2088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (data & 4) {
2098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            d->status |= 1 << (ichan + 4);
2108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
2118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        else {
2128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            d->status &= ~(1 << (ichan + 4));
2138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
2148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        d->status &= ~(1 << ichan);
2155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        DMA_run();
2168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
2178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x0a:                  /* single mask */
2198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (data & 4)
2208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            d->mask |= 1 << (data & 3);
2218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        else
2228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            d->mask &= ~(1 << (data & 3));
2235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        DMA_run();
2248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
2258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x0b:                  /* mode */
2278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        {
2288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ichan = data & 3;
2298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG_DMA
2308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            {
2318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                int op, ai, dir, opmode;
2328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                op = (data >> 2) & 3;
2338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                ai = (data >> 4) & 1;
2348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                dir = (data >> 5) & 1;
2358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                opmode = (data >> 6) & 3;
2368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n",
2388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                       ichan, op, ai, dir, opmode);
2398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
2408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
2418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            d->regs[ichan].mode = data;
2428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
2438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
2448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x0c:                  /* clear flip flop */
2468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        d->flip_flop = 0;
2478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
2488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x0d:                  /* reset */
2508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        d->flip_flop = 0;
2518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        d->mask = ~0;
2528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        d->status = 0;
2538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        d->command = 0;
2548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
2558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x0e:                  /* clear mask for all channels */
2578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        d->mask = 0;
2585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        DMA_run();
2598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
2608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x0f:                  /* write mask for all channels */
2628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        d->mask = data;
2635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        DMA_run();
2648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
2658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    default:
2678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dolog ("unknown iport %#x\n", iport);
2688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
2698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
2708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG_DMA
2728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (0xc != iport) {
2738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        linfo ("write_cont: nport %#06x, ichan % 2d, val %#06x\n",
2748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project               nport, ichan, data);
2758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
2768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
2778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
2788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint32_t read_cont (void *opaque, uint32_t nport)
2808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
2818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_cont *d = opaque;
2828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int iport, val;
2838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    iport = (nport >> d->dshift) & 0x0f;
2858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    switch (iport) {
2868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x08:                  /* status */
2878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        val = d->status;
2888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        d->status &= 0xf0;
2898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
2908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x0f:                  /* mask */
2918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        val = d->mask;
2928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
2938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    default:
2948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        val = 0;
2958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
2968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
2978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ldebug ("read_cont: nport %#06x, iport %#04x val %#x\n", nport, iport, val);
2998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return val;
3008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint DMA_get_channel_mode (int nchan)
3038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return dma_controllers[nchan > 3].regs[nchan & 3].mode;
3058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid DMA_hold_DREQ (int nchan)
3088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ncont, ichan;
3108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ncont = nchan > 3;
3128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ichan = nchan & 3;
3138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    linfo ("held cont=%d chan=%d\n", ncont, ichan);
3148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dma_controllers[ncont].status |= 1 << (ichan + 4);
3155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DMA_run();
3168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid DMA_release_DREQ (int nchan)
3198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ncont, ichan;
3218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ncont = nchan > 3;
3238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ichan = nchan & 3;
3248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    linfo ("released cont=%d chan=%d\n", ncont, ichan);
3258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dma_controllers[ncont].status &= ~(1 << (ichan + 4));
3265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DMA_run();
3278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void channel_run (int ncont, int ichan)
3308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int n;
3328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_regs *r = &dma_controllers[ncont].regs[ichan];
3338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG_DMA
3348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int dir, opmode;
3358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dir = (r->mode >> 5) & 1;
3378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    opmode = (r->mode >> 6) & 3;
3388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (dir) {
3408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dolog ("DMA in address decrement mode\n");
3418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
3428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (opmode != 1) {
3438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dolog ("DMA not in single mode select %#x\n", opmode);
3448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
3458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
3468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    r = dma_controllers[ncont].regs + ichan;
3482091a098485fb6d386827aef3fb4732ae1cfac83rich cannings    if (r->transfer_handler) {
3492091a098485fb6d386827aef3fb4732ae1cfac83rich cannings        n = r->transfer_handler (r->opaque, ichan + (ncont << 2),
3502091a098485fb6d386827aef3fb4732ae1cfac83rich cannings                                 r->now[COUNT], (r->base[COUNT] + 1) << ncont);
3512091a098485fb6d386827aef3fb4732ae1cfac83rich cannings        r->now[COUNT] = n;
3522091a098485fb6d386827aef3fb4732ae1cfac83rich cannings    }
3538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ldebug ("dma_pos %d size %d\n", n, (r->base[COUNT] + 1) << ncont);
3548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic QEMUBH *dma_bh;
3575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void DMA_run (void)
3598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_cont *d;
3618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int icont, ichan;
3625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int rearm = 0;
3638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    d = dma_controllers;
3658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (icont = 0; icont < 2; icont++, d++) {
3678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (ichan = 0; ichan < 4; ichan++) {
3688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            int mask;
3698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            mask = 1 << ichan;
3718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4)))) {
3738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                channel_run (icont, ichan);
3745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                rearm = 1;
3755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
3768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
3778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
3785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (rearm)
3805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_bh_schedule_idle(dma_bh);
3815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void DMA_run_bh(void *unused)
3845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DMA_run();
3868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid DMA_register_channel (int nchan,
3898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                           DMA_transfer_handler transfer_handler,
3908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                           void *opaque)
3918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_regs *r;
3938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ichan, ncont;
3948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ncont = nchan > 3;
3968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ichan = nchan & 3;
3978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    r = dma_controllers[ncont].regs + ichan;
3998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    r->transfer_handler = transfer_handler;
4008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    r->opaque = opaque;
4018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint DMA_read_memory (int nchan, void *buf, int pos, int len)
4048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3];
4068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    target_phys_addr_t addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
4078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (r->mode & 0x20) {
4098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        int i;
4108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        uint8_t *p = buf;
4118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        cpu_physical_memory_read (addr - pos - len, buf, len);
4138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* What about 16bit transfers? */
4148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (i = 0; i < len >> 1; i++) {
4158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            uint8_t b = p[len - i - 1];
4168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            p[i] = b;
4178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
4188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    else
4208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        cpu_physical_memory_read (addr + pos, buf, len);
4218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return len;
4238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint DMA_write_memory (int nchan, void *buf, int pos, int len)
4268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3];
4288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    target_phys_addr_t addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
4298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (r->mode & 0x20) {
4318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        int i;
4328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        uint8_t *p = buf;
4338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        cpu_physical_memory_write (addr - pos - len, buf, len);
4358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* What about 16bit transfers? */
4368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (i = 0; i < len; i++) {
4378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            uint8_t b = p[len - i - 1];
4388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            p[i] = b;
4398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
4408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    else
4428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        cpu_physical_memory_write (addr + pos, buf, len);
4438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return len;
4458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* request the emulator to transfer a new DMA memory block ASAP */
4488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid DMA_schedule(int nchan)
4498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CPUState *env = cpu_single_env;
4518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (env)
4525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        cpu_exit(env);
4538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void dma_reset(void *opaque)
4568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_cont *d = opaque;
4588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    write_cont (d, (0x0d << d->dshift), 0);
4598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int dma_phony_handler (void *opaque, int nchan, int dma_pos, int dma_len)
4628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dolog ("unregistered DMA channel used nchan=%d dma_pos=%d dma_len=%d\n",
4648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           nchan, dma_pos, dma_len);
4658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return dma_pos;
4668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */
4698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void dma_init2(struct dma_cont *d, int base, int dshift,
4708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                      int page_base, int pageh_base)
4718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    static const int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 };
4738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
4748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    d->dshift = dshift;
4768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < 8; i++) {
4778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        register_ioport_write (base + (i << dshift), 1, 1, write_chan, d);
4788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        register_ioport_read (base + (i << dshift), 1, 1, read_chan, d);
4798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0; i < ARRAY_SIZE (page_port_list); i++) {
4818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        register_ioport_write (page_base + page_port_list[i], 1, 1,
4828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                               write_page, d);
4838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        register_ioport_read (page_base + page_port_list[i], 1, 1,
4848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                              read_page, d);
4858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (pageh_base >= 0) {
4868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            register_ioport_write (pageh_base + page_port_list[i], 1, 1,
4878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                                   write_pageh, d);
4888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            register_ioport_read (pageh_base + page_port_list[i], 1, 1,
4898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                                  read_pageh, d);
4908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
4918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < 8; i++) {
4938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        register_ioport_write (base + ((i + 8) << dshift), 1, 1,
4948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                               write_cont, d);
4958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        register_ioport_read (base + ((i + 8) << dshift), 1, 1,
4968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                              read_cont, d);
4978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_register_reset(dma_reset, 0, d);
4998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dma_reset(d);
5005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0; i < ARRAY_SIZE (d->regs); ++i) {
5018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        d->regs[i].transfer_handler = dma_phony_handler;
5028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
5038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void dma_save (QEMUFile *f, void *opaque)
5068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_cont *d = opaque;
5088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
5098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* qemu_put_8s (f, &d->status); */
5118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_put_8s (f, &d->command);
5128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_put_8s (f, &d->mask);
5138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_put_8s (f, &d->flip_flop);
5148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_put_be32 (f, d->dshift);
5158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < 4; ++i) {
5178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        struct dma_regs *r = &d->regs[i];
5188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_be32 (f, r->now[0]);
5198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_be32 (f, r->now[1]);
5208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_be16s (f, &r->base[0]);
5218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_be16s (f, &r->base[1]);
5228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_8s (f, &r->mode);
5238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_8s (f, &r->page);
5248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_8s (f, &r->pageh);
5258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_8s (f, &r->dack);
5268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_8s (f, &r->eop);
5278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
5288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int dma_load (QEMUFile *f, void *opaque, int version_id)
5318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_cont *d = opaque;
5338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
5348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (version_id != 1)
5368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return -EINVAL;
5378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* qemu_get_8s (f, &d->status); */
5398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_get_8s (f, &d->command);
5408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_get_8s (f, &d->mask);
5418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_get_8s (f, &d->flip_flop);
5428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    d->dshift=qemu_get_be32 (f);
5438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < 4; ++i) {
5458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        struct dma_regs *r = &d->regs[i];
5468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        r->now[0]=qemu_get_be32 (f);
5478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        r->now[1]=qemu_get_be32 (f);
5488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_get_be16s (f, &r->base[0]);
5498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_get_be16s (f, &r->base[1]);
5508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_get_8s (f, &r->mode);
5518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_get_8s (f, &r->page);
5528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_get_8s (f, &r->pageh);
5538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_get_8s (f, &r->dack);
5548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_get_8s (f, &r->eop);
5558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
5565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DMA_run();
5585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
5608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid DMA_init (int high_page_enable)
5638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dma_init2(&dma_controllers[0], 0x00, 0, 0x80,
5658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project              high_page_enable ? 0x480 : -1);
5668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dma_init2(&dma_controllers[1], 0xc0, 1, 0x88,
5678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project              high_page_enable ? 0x488 : -1);
5688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    register_savevm ("dma", 0, 1, dma_save, dma_load, &dma_controllers[0]);
5698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    register_savevm ("dma", 1, 1, dma_save, dma_load, &dma_controllers[1]);
5705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    dma_bh = qemu_bh_new(DMA_run_bh, NULL);
5728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
573