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