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 */
249b3a4b03315af9bcdf282243059e8fd1ce1c5c70David 'Digit' Turner#include "cpu.h"
259b3a4b03315af9bcdf282243059e8fd1ce1c5c70David 'Digit' Turner#include "exec/cpu-common.h"
262ec695af7284adbedcdbc08a22d818b6bdd8990cDavid 'Digit' Turner#include "hw/hw.h"
272ec695af7284adbedcdbc08a22d818b6bdd8990cDavid 'Digit' Turner#include "hw/isa/isa.h"
288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* #define DEBUG_DMA */
308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define dolog(...) fprintf (stderr, "dma: " __VA_ARGS__)
328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG_DMA
338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__)
348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define ldebug(...) fprintf (stderr, "dma: " __VA_ARGS__)
358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else
368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define linfo(...)
378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define ldebug(...)
388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstruct dma_regs {
418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int now[2];
428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint16_t base[2];
438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t mode;
448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t page;
458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t pageh;
468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t dack;
478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t eop;
488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    DMA_transfer_handler transfer_handler;
498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    void *opaque;
508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define ADDR 0
538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define COUNT 1
548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic struct dma_cont {
568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t status;
578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t command;
588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t mask;
598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t flip_flop;
608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int dshift;
618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_regs regs[4];
628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} dma_controllers[2];
638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectenum {
658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CMD_MEMORY_TO_MEMORY = 0x01,
668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CMD_FIXED_ADDRESS    = 0x02,
678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CMD_BLOCK_CONTROLLER = 0x04,
688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CMD_COMPRESSED_TIME  = 0x08,
698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CMD_CYCLIC_PRIORITY  = 0x10,
708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CMD_EXTENDED_WRITE   = 0x20,
718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CMD_LOW_DREQ         = 0x40,
728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CMD_LOW_DACK         = 0x80,
738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CMD_NOT_SUPPORTED    = CMD_MEMORY_TO_MEMORY | CMD_FIXED_ADDRESS
748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    | CMD_COMPRESSED_TIME | CMD_CYCLIC_PRIORITY | CMD_EXTENDED_WRITE
758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    | CMD_LOW_DREQ | CMD_LOW_DACK
768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void DMA_run (void);
805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0};
828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void write_page (void *opaque, uint32_t nport, uint32_t data)
848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_cont *d = opaque;
868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ichan;
878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ichan = channels[nport & 7];
898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (-1 == ichan) {
908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dolog ("invalid channel %#x %#x\n", nport, data);
918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    d->regs[ichan].page = data;
948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void write_pageh (void *opaque, uint32_t nport, uint32_t data)
978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_cont *d = opaque;
998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ichan;
1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ichan = channels[nport & 7];
1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (-1 == ichan) {
1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dolog ("invalid channel %#x %#x\n", nport, data);
1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    d->regs[ichan].pageh = data;
1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint32_t read_page (void *opaque, uint32_t nport)
1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_cont *d = opaque;
1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ichan;
1138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ichan = channels[nport & 7];
1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (-1 == ichan) {
1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dolog ("invalid channel read %#x\n", nport);
1178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return d->regs[ichan].page;
1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint32_t read_pageh (void *opaque, uint32_t nport)
1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_cont *d = opaque;
1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ichan;
1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ichan = channels[nport & 7];
1288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (-1 == ichan) {
1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dolog ("invalid channel read %#x\n", nport);
1308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return d->regs[ichan].pageh;
1338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline void init_chan (struct dma_cont *d, int ichan)
1368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_regs *r;
1388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    r = d->regs + ichan;
1408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    r->now[ADDR] = r->base[ADDR] << d->dshift;
1418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    r->now[COUNT] = 0;
1428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline int getff (struct dma_cont *d)
1458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ff;
1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ff = d->flip_flop;
1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    d->flip_flop = !ff;
1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return ff;
1518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint32_t read_chan (void *opaque, uint32_t nport)
1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_cont *d = opaque;
1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ichan, nreg, iport, ff, val, dir;
1578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_regs *r;
1588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    iport = (nport >> d->dshift) & 0x0f;
1608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ichan = iport >> 1;
1618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    nreg = iport & 1;
1628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    r = d->regs + ichan;
1638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dir = ((r->mode >> 5) & 1) ? -1 : 1;
1658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ff = getff (d);
1668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (nreg)
1678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        val = (r->base[COUNT] << d->dshift) - r->now[COUNT];
1688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    else
1698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        val = r->now[ADDR] + r->now[COUNT] * dir;
1708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ldebug ("read_chan %#x -> %d\n", iport, val);
1728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return (val >> (d->dshift + (ff << 3))) & 0xff;
1738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void write_chan (void *opaque, uint32_t nport, uint32_t data)
1768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_cont *d = opaque;
1788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int iport, ichan, nreg;
1798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_regs *r;
1808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    iport = (nport >> d->dshift) & 0x0f;
1828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ichan = iport >> 1;
1838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    nreg = iport & 1;
1848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    r = d->regs + ichan;
1858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (getff (d)) {
1868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        r->base[nreg] = (r->base[nreg] & 0xff) | ((data << 8) & 0xff00);
1878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        init_chan (d, ichan);
1888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
1898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        r->base[nreg] = (r->base[nreg] & 0xff00) | (data & 0xff);
1908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void write_cont (void *opaque, uint32_t nport, uint32_t data)
1948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_cont *d = opaque;
1968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int iport, ichan = 0;
1978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    iport = (nport >> d->dshift) & 0x0f;
1998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    switch (iport) {
2008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x08:                  /* command */
2018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if ((data != 0) && (data & CMD_NOT_SUPPORTED)) {
2028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            dolog ("command %#x not supported\n", data);
2038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return;
2048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
2058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        d->command = data;
2068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
2078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x09:
2098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ichan = data & 3;
2108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (data & 4) {
2118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            d->status |= 1 << (ichan + 4);
2128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
2138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        else {
2148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            d->status &= ~(1 << (ichan + 4));
2158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
2168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        d->status &= ~(1 << ichan);
2175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        DMA_run();
2188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
2198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x0a:                  /* single mask */
2218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (data & 4)
2228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            d->mask |= 1 << (data & 3);
2238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        else
2248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            d->mask &= ~(1 << (data & 3));
2255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        DMA_run();
2268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
2278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x0b:                  /* mode */
2298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        {
2308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ichan = data & 3;
2318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG_DMA
2328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            {
2338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                int op, ai, dir, opmode;
2348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                op = (data >> 2) & 3;
2358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                ai = (data >> 4) & 1;
2368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                dir = (data >> 5) & 1;
2378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                opmode = (data >> 6) & 3;
2388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n",
2408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                       ichan, op, ai, dir, opmode);
2418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
2428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
2438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            d->regs[ichan].mode = data;
2448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
2458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
2468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x0c:                  /* clear flip flop */
2488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        d->flip_flop = 0;
2498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
2508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x0d:                  /* reset */
2528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        d->flip_flop = 0;
2538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        d->mask = ~0;
2548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        d->status = 0;
2558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        d->command = 0;
2568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
2578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x0e:                  /* clear mask for all channels */
2598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        d->mask = 0;
2605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        DMA_run();
2618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
2628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x0f:                  /* write mask for all channels */
2648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        d->mask = data;
2655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        DMA_run();
2668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
2678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    default:
2698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dolog ("unknown iport %#x\n", iport);
2708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
2718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
2728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG_DMA
2748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (0xc != iport) {
2758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        linfo ("write_cont: nport %#06x, ichan % 2d, val %#06x\n",
2768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project               nport, ichan, data);
2778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
2788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
2798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
2808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint32_t read_cont (void *opaque, uint32_t nport)
2828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
2838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_cont *d = opaque;
2848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int iport, val;
2858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    iport = (nport >> d->dshift) & 0x0f;
2878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    switch (iport) {
2888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x08:                  /* status */
2898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        val = d->status;
2908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        d->status &= 0xf0;
2918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
2928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x0f:                  /* mask */
2938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        val = d->mask;
2948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
2958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    default:
2968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        val = 0;
2978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
2988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
2998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ldebug ("read_cont: nport %#06x, iport %#04x val %#x\n", nport, iport, val);
3018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return val;
3028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint DMA_get_channel_mode (int nchan)
3058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return dma_controllers[nchan > 3].regs[nchan & 3].mode;
3078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid DMA_hold_DREQ (int nchan)
3108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ncont, ichan;
3128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ncont = nchan > 3;
3148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ichan = nchan & 3;
3158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    linfo ("held cont=%d chan=%d\n", ncont, ichan);
3168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dma_controllers[ncont].status |= 1 << (ichan + 4);
3175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DMA_run();
3188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid DMA_release_DREQ (int nchan)
3218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ncont, ichan;
3238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ncont = nchan > 3;
3258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ichan = nchan & 3;
3268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    linfo ("released cont=%d chan=%d\n", ncont, ichan);
3278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dma_controllers[ncont].status &= ~(1 << (ichan + 4));
3285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DMA_run();
3298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void channel_run (int ncont, int ichan)
3328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int n;
3348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_regs *r = &dma_controllers[ncont].regs[ichan];
3358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG_DMA
3368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int dir, opmode;
3378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dir = (r->mode >> 5) & 1;
3398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    opmode = (r->mode >> 6) & 3;
3408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (dir) {
3428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dolog ("DMA in address decrement mode\n");
3438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
3448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (opmode != 1) {
3458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dolog ("DMA not in single mode select %#x\n", opmode);
3468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
3478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
3488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    r = dma_controllers[ncont].regs + ichan;
3502091a098485fb6d386827aef3fb4732ae1cfac83rich cannings    if (r->transfer_handler) {
3512091a098485fb6d386827aef3fb4732ae1cfac83rich cannings        n = r->transfer_handler (r->opaque, ichan + (ncont << 2),
3522091a098485fb6d386827aef3fb4732ae1cfac83rich cannings                                 r->now[COUNT], (r->base[COUNT] + 1) << ncont);
3532091a098485fb6d386827aef3fb4732ae1cfac83rich cannings        r->now[COUNT] = n;
3542091a098485fb6d386827aef3fb4732ae1cfac83rich cannings    }
3558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ldebug ("dma_pos %d size %d\n", n, (r->base[COUNT] + 1) << ncont);
3568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic QEMUBH *dma_bh;
3595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void DMA_run (void)
3618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_cont *d;
3638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int icont, ichan;
3645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int rearm = 0;
3658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    d = dma_controllers;
3678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (icont = 0; icont < 2; icont++, d++) {
3698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (ichan = 0; ichan < 4; ichan++) {
3708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            int mask;
3718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            mask = 1 << ichan;
3738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4)))) {
3758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                channel_run (icont, ichan);
3765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                rearm = 1;
3775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
3788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
3798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
3805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (rearm)
3825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_bh_schedule_idle(dma_bh);
3835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void DMA_run_bh(void *unused)
3865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DMA_run();
3888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid DMA_register_channel (int nchan,
3918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                           DMA_transfer_handler transfer_handler,
3928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                           void *opaque)
3938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_regs *r;
3958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ichan, ncont;
3968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ncont = nchan > 3;
3988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ichan = nchan & 3;
3998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    r = dma_controllers[ncont].regs + ichan;
4018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    r->transfer_handler = transfer_handler;
4028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    r->opaque = opaque;
4038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint DMA_read_memory (int nchan, void *buf, int pos, int len)
4068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3];
408bcde1092aca184dbd7860078af020de7d1e4e22fDavid 'Digit' Turner    hwaddr addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
4098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (r->mode & 0x20) {
4118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        int i;
4128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        uint8_t *p = buf;
4138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        cpu_physical_memory_read (addr - pos - len, buf, len);
4158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* What about 16bit transfers? */
4168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (i = 0; i < len >> 1; i++) {
4178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            uint8_t b = p[len - i - 1];
4188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            p[i] = b;
4198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
4208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    else
4228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        cpu_physical_memory_read (addr + pos, buf, len);
4238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return len;
4258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint DMA_write_memory (int nchan, void *buf, int pos, int len)
4288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3];
430bcde1092aca184dbd7860078af020de7d1e4e22fDavid 'Digit' Turner    hwaddr addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
4318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (r->mode & 0x20) {
4338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        int i;
4348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        uint8_t *p = buf;
4358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        cpu_physical_memory_write (addr - pos - len, buf, len);
4378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* What about 16bit transfers? */
4388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (i = 0; i < len; i++) {
4398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            uint8_t b = p[len - i - 1];
4408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            p[i] = b;
4418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
4428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    else
4448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        cpu_physical_memory_write (addr + pos, buf, len);
4458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return len;
4478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* request the emulator to transfer a new DMA memory block ASAP */
4508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid DMA_schedule(int nchan)
4518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
452bf7a22f3a6c38d359d2e933dec4706d1c7375f0aDavid 'Digit' Turner    CPUState *cpu = current_cpu;
453bf7a22f3a6c38d359d2e933dec4706d1c7375f0aDavid 'Digit' Turner    if (cpu)
454bf7a22f3a6c38d359d2e933dec4706d1c7375f0aDavid 'Digit' Turner        cpu_exit(cpu);
4558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void dma_reset(void *opaque)
4588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_cont *d = opaque;
4608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    write_cont (d, (0x0d << d->dshift), 0);
4618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int dma_phony_handler (void *opaque, int nchan, int dma_pos, int dma_len)
4648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dolog ("unregistered DMA channel used nchan=%d dma_pos=%d dma_len=%d\n",
4668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           nchan, dma_pos, dma_len);
4678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return dma_pos;
4688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */
4718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void dma_init2(struct dma_cont *d, int base, int dshift,
4728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                      int page_base, int pageh_base)
4738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    static const int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 };
4758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
4768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    d->dshift = dshift;
4788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < 8; i++) {
4798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        register_ioport_write (base + (i << dshift), 1, 1, write_chan, d);
4808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        register_ioport_read (base + (i << dshift), 1, 1, read_chan, d);
4818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0; i < ARRAY_SIZE (page_port_list); i++) {
4838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        register_ioport_write (page_base + page_port_list[i], 1, 1,
4848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                               write_page, d);
4858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        register_ioport_read (page_base + page_port_list[i], 1, 1,
4868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                              read_page, d);
4878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (pageh_base >= 0) {
4888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            register_ioport_write (pageh_base + page_port_list[i], 1, 1,
4898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                                   write_pageh, d);
4908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            register_ioport_read (pageh_base + page_port_list[i], 1, 1,
4918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                                  read_pageh, d);
4928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
4938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < 8; i++) {
4958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        register_ioport_write (base + ((i + 8) << dshift), 1, 1,
4968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                               write_cont, d);
4978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        register_ioport_read (base + ((i + 8) << dshift), 1, 1,
4988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                              read_cont, d);
4998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
5005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_register_reset(dma_reset, 0, d);
5018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dma_reset(d);
5025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0; i < ARRAY_SIZE (d->regs); ++i) {
5038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        d->regs[i].transfer_handler = dma_phony_handler;
5048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
5058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void dma_save (QEMUFile *f, void *opaque)
5088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_cont *d = opaque;
5108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
5118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* qemu_put_8s (f, &d->status); */
5138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_put_8s (f, &d->command);
5148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_put_8s (f, &d->mask);
5158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_put_8s (f, &d->flip_flop);
5168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_put_be32 (f, d->dshift);
5178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < 4; ++i) {
5198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        struct dma_regs *r = &d->regs[i];
5208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_be32 (f, r->now[0]);
5218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_be32 (f, r->now[1]);
5228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_be16s (f, &r->base[0]);
5238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_be16s (f, &r->base[1]);
5248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_8s (f, &r->mode);
5258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_8s (f, &r->page);
5268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_8s (f, &r->pageh);
5278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_8s (f, &r->dack);
5288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_8s (f, &r->eop);
5298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
5308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int dma_load (QEMUFile *f, void *opaque, int version_id)
5338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dma_cont *d = opaque;
5358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
5368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (version_id != 1)
5388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return -EINVAL;
5398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* qemu_get_8s (f, &d->status); */
5418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_get_8s (f, &d->command);
5428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_get_8s (f, &d->mask);
5438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_get_8s (f, &d->flip_flop);
5448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    d->dshift=qemu_get_be32 (f);
5458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < 4; ++i) {
5478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        struct dma_regs *r = &d->regs[i];
5488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        r->now[0]=qemu_get_be32 (f);
5498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        r->now[1]=qemu_get_be32 (f);
5508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_get_be16s (f, &r->base[0]);
5518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_get_be16s (f, &r->base[1]);
5528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_get_8s (f, &r->mode);
5538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_get_8s (f, &r->page);
5548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_get_8s (f, &r->pageh);
5558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_get_8s (f, &r->dack);
5568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_get_8s (f, &r->eop);
5578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
5585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DMA_run();
5605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
5628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid DMA_init (int high_page_enable)
5658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dma_init2(&dma_controllers[0], 0x00, 0, 0x80,
5678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project              high_page_enable ? 0x480 : -1);
5688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dma_init2(&dma_controllers[1], 0xc0, 1, 0x88,
5698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project              high_page_enable ? 0x488 : -1);
5705cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner    register_savevm(NULL,
5715cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner                    "dma",
5725cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner                    0,
5735cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner                    1,
5745cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner                    dma_save,
5755cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner                    dma_load,
5765cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner                    &dma_controllers[0]);
5775cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner
5785cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner    register_savevm(NULL,
5795cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner                    "dma",
5805cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner                    1,
5815cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner                    1,
5825cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner                    dma_save,
5835cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner                    dma_load,
5845cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner                    &dma_controllers[1]);
5855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    dma_bh = qemu_bh_new(DMA_run_bh, NULL);
5878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
588