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