nkeynes@185 | 1 | /**
|
nkeynes@561 | 2 | * $Id$
|
nkeynes@185 | 3 | *
|
nkeynes@185 | 4 | * DMA support code
|
nkeynes@185 | 5 | *
|
nkeynes@185 | 6 | * Copyright (c) 2006 Nathan Keynes.
|
nkeynes@185 | 7 | *
|
nkeynes@185 | 8 | * This program is free software; you can redistribute it and/or modify
|
nkeynes@185 | 9 | * it under the terms of the GNU General Public License as published by
|
nkeynes@185 | 10 | * the Free Software Foundation; either version 2 of the License, or
|
nkeynes@185 | 11 | * (at your option) any later version.
|
nkeynes@185 | 12 | *
|
nkeynes@185 | 13 | * This program is distributed in the hope that it will be useful,
|
nkeynes@185 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nkeynes@185 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nkeynes@185 | 16 | * GNU General Public License for more details.
|
nkeynes@185 | 17 | */
|
nkeynes@185 | 18 |
|
nkeynes@185 | 19 | #include "dma.h"
|
nkeynes@185 | 20 | #include "asic.h"
|
nkeynes@185 | 21 |
|
nkeynes@185 | 22 | #define DMA_BASE 0xFFA00000
|
nkeynes@185 | 23 |
|
nkeynes@185 | 24 | #define DMA_SAR(c) (DMA_BASE+0x00+(c<<4))
|
nkeynes@185 | 25 | #define DMA_DAR(c) (DMA_BASE+0x04+(c<<4))
|
nkeynes@185 | 26 | #define DMA_TCR(c) (DMA_BASE+0x08+(c<<4))
|
nkeynes@185 | 27 | #define DMA_CHCR(c) (DMA_BASE+0x0C+(c<<4))
|
nkeynes@185 | 28 | #define DMA_OR (DMA_BASE+0x40)
|
nkeynes@185 | 29 |
|
nkeynes@185 | 30 | #define ASIC_BASE 0xA05F6000
|
nkeynes@185 | 31 | #define PVR_DMA_DEST (ASIC_BASE+0x800)
|
nkeynes@185 | 32 | #define PVR_DMA_COUNT (ASIC_BASE+0x804)
|
nkeynes@185 | 33 | #define PVR_DMA_CTL (ASIC_BASE+0x808)
|
nkeynes@185 | 34 | #define PVR_DMA_REGION (ASIC_BASE+0x884)
|
nkeynes@185 | 35 |
|
nkeynes@753 | 36 | #define SORT_DMA_TABLE (ASIC_BASE+0x810)
|
nkeynes@753 | 37 | #define SORT_DMA_DATA (ASIC_BASE+0x814)
|
nkeynes@753 | 38 | #define SORT_DMA_TABLEBITS (ASIC_BASE+0x818)
|
nkeynes@753 | 39 | #define SORT_DMA_DATASIZE (ASIC_BASE+0x81C)
|
nkeynes@753 | 40 | #define SORT_DMA_CTL (ASIC_BASE+0x820)
|
nkeynes@753 | 41 | #define SORT_DMA_COUNT (ASIC_BASE+0x860)
|
nkeynes@753 | 42 |
|
nkeynes@185 | 43 | void dmac_dump_channel( FILE *f, unsigned int channel )
|
nkeynes@185 | 44 | {
|
nkeynes@185 | 45 | fprintf( f, "DMAC SAR: %08X Count: %08X Ctl: %08X OR: %08X\n",
|
nkeynes@185 | 46 | long_read(DMA_SAR(channel)), long_read(DMA_TCR(channel)),
|
nkeynes@185 | 47 | long_read(DMA_CHCR(channel)), long_read(DMA_OR) );
|
nkeynes@185 | 48 | }
|
nkeynes@185 | 49 |
|
nkeynes@185 | 50 |
|
nkeynes@185 | 51 | /**
|
nkeynes@185 | 52 | * Setup the DMAC for a transfer. Assumes 32-byte block transfer.
|
nkeynes@185 | 53 | * Caller is responsible for making sure no-one else is using the
|
nkeynes@185 | 54 | * channel already.
|
nkeynes@185 | 55 | *
|
nkeynes@185 | 56 | * @param channel DMA channel to use, 0 to 3
|
nkeynes@185 | 57 | * @param source source address (if a memory source)
|
nkeynes@185 | 58 | * @param dest destination address (if a memory destination)
|
nkeynes@185 | 59 | * @param length number of bytes to transfer (must be a multiple of
|
nkeynes@185 | 60 | * 32.
|
nkeynes@185 | 61 | * @param direction 0 = host to device, 1 = device to host
|
nkeynes@185 | 62 | */
|
nkeynes@185 | 63 | void dmac_prepare_channel( int channel, uint32_t source, uint32_t dest,
|
nkeynes@185 | 64 | uint32_t length, int direction )
|
nkeynes@185 | 65 | {
|
nkeynes@185 | 66 | uint32_t control;
|
nkeynes@185 | 67 |
|
nkeynes@185 | 68 | if( direction == 0 ) {
|
nkeynes@185 | 69 | /* DMA Disabled, IRQ disabled, 32 byte transfer, burst mode,
|
nkeynes@185 | 70 | * Memory => Device, Source addr increment, dest addr fixed
|
nkeynes@185 | 71 | */
|
nkeynes@185 | 72 | control = 0x000012C0;
|
nkeynes@185 | 73 | } else {
|
nkeynes@185 | 74 | /* DMA Disabled, IRQ disabled, 32 byte transfer, burst mode,
|
nkeynes@185 | 75 | * Device => Memory, Source addr fixed, dest addr increment
|
nkeynes@185 | 76 | */
|
nkeynes@185 | 77 | control = 0x000043C0;
|
nkeynes@185 | 78 | }
|
nkeynes@185 | 79 | long_write( DMA_CHCR(channel), control );
|
nkeynes@185 | 80 | long_write( DMA_SAR(channel), source );
|
nkeynes@185 | 81 | long_write( DMA_DAR(channel), dest );
|
nkeynes@185 | 82 | long_write( DMA_TCR(channel), (length >> 5) );
|
nkeynes@185 | 83 | control |= 0x0001;
|
nkeynes@185 | 84 | long_write( DMA_CHCR(channel), control ); /* Enable DMA channel */
|
nkeynes@185 | 85 | long_write( DMA_OR, 0x8201 ); /* Ensure the DMAC config is set */
|
nkeynes@185 | 86 | }
|
nkeynes@185 | 87 |
|
nkeynes@185 | 88 |
|
nkeynes@185 | 89 | int pvr_dma_write( unsigned int target, char *buf, int len, int region )
|
nkeynes@185 | 90 | {
|
nkeynes@185 | 91 | uint32_t addr =(uint32_t)buf;
|
nkeynes@185 | 92 | int result;
|
nkeynes@185 | 93 | if( (addr & 0xFFFFFFE0) != addr ) {
|
nkeynes@185 | 94 | fprintf( stderr, "Address error: Attempting DMA from %08X\n", addr );
|
nkeynes@185 | 95 | return -1;
|
nkeynes@185 | 96 | }
|
nkeynes@185 | 97 | long_write( PVR_DMA_CTL, 0 ); /* Stop PVR dma if it's already running */
|
nkeynes@185 | 98 | asic_clear();
|
nkeynes@185 | 99 |
|
nkeynes@185 | 100 | dmac_prepare_channel( 2, (uint32_t)buf, 0, len, 0 ); /* Allocate channel 2 */
|
nkeynes@185 | 101 | long_write( PVR_DMA_DEST, target );
|
nkeynes@185 | 102 | long_write( PVR_DMA_COUNT, len );
|
nkeynes@185 | 103 | long_write( PVR_DMA_REGION, region );
|
nkeynes@185 | 104 |
|
nkeynes@185 | 105 | CHECK_IEQUALS( target, long_read(PVR_DMA_DEST) );
|
nkeynes@185 | 106 | CHECK_IEQUALS( len, long_read(PVR_DMA_COUNT) );
|
nkeynes@185 | 107 | CHECK_IEQUALS( 0, long_read(PVR_DMA_REGION) );
|
nkeynes@185 | 108 | CHECK_IEQUALS( (uint32_t)buf, long_read(DMA_SAR(2)) );
|
nkeynes@185 | 109 | CHECK_IEQUALS( len/32, long_read(DMA_TCR(2)) );
|
nkeynes@185 | 110 | CHECK_IEQUALS( 0x12C1, long_read(DMA_CHCR(2)) );
|
nkeynes@185 | 111 |
|
nkeynes@185 | 112 | long_write( PVR_DMA_CTL, 1 );
|
nkeynes@185 | 113 | result = asic_wait(EVENT_PVR_DMA);
|
nkeynes@185 | 114 |
|
nkeynes@185 | 115 | if( result != 0 ) {
|
nkeynes@185 | 116 | fprintf( stderr, "PVR DMA failed (timeout)\n" );
|
nkeynes@185 | 117 | asic_dump(stderr);
|
nkeynes@185 | 118 | fprintf( stderr, "Dest: %08X Count: %08X Ctl: %08X\n", long_read(PVR_DMA_DEST),
|
nkeynes@185 | 119 | long_read(PVR_DMA_COUNT), long_read(PVR_DMA_CTL) );
|
nkeynes@185 | 120 | dmac_dump_channel(stderr, 2);
|
nkeynes@185 | 121 | long_write( PVR_DMA_CTL, 0 );
|
nkeynes@185 | 122 | }
|
nkeynes@185 | 123 |
|
nkeynes@185 | 124 | CHECK_IEQUALS( 0, long_read(PVR_DMA_CTL) );
|
nkeynes@185 | 125 | CHECK_IEQUALS( ((uint32_t)buf)+len, long_read(DMA_SAR(2)) );
|
nkeynes@185 | 126 | CHECK_IEQUALS( 0, long_read(DMA_TCR(2)) );
|
nkeynes@185 | 127 | CHECK_IEQUALS( 0x12C3, long_read(DMA_CHCR(2)) );
|
nkeynes@185 | 128 | CHECK_IEQUALS( target, long_read(PVR_DMA_DEST) );
|
nkeynes@185 | 129 | CHECK_IEQUALS( 0, long_read(PVR_DMA_COUNT) );
|
nkeynes@185 | 130 | CHECK_IEQUALS( 0, long_read(PVR_DMA_REGION) );
|
nkeynes@185 | 131 |
|
nkeynes@185 | 132 | return result;
|
nkeynes@185 | 133 | }
|
nkeynes@753 | 134 |
|
nkeynes@753 | 135 | int sort_dma_write( char *sorttable, int tablelen, char *data, int datalen, int bitwidth, int datasize )
|
nkeynes@753 | 136 | {
|
nkeynes@753 | 137 | int result;
|
nkeynes@753 | 138 | uint32_t tableaddr = (uint32_t)sorttable;
|
nkeynes@753 | 139 | uint32_t dataaddr = (uint32_t)data;
|
nkeynes@753 | 140 |
|
nkeynes@753 | 141 | long_write( SORT_DMA_CTL, 0 );
|
nkeynes@753 | 142 | asic_clear();
|
nkeynes@753 | 143 |
|
nkeynes@753 | 144 | long_write( SORT_DMA_TABLE, tableaddr );
|
nkeynes@753 | 145 | long_write( SORT_DMA_DATA, dataaddr );
|
nkeynes@753 | 146 | long_write( SORT_DMA_TABLEBITS, bitwidth );
|
nkeynes@753 | 147 | long_write( SORT_DMA_DATASIZE, datasize );
|
nkeynes@753 | 148 | long_write( SORT_DMA_CTL, 1 );
|
nkeynes@753 | 149 | result = asic_wait2(EVENT_SORT_DMA, EVENT_SORT_DMA_ERR);
|
nkeynes@753 | 150 | if( result == -1 ) {
|
nkeynes@753 | 151 | fprintf( stderr, "SORT DMA failed (timeout)\n" );
|
nkeynes@753 | 152 | asic_dump(stderr);
|
nkeynes@753 | 153 | fprintf( stderr, "Table: %08X Count: %08X Ctl: %08X\n", long_read(SORT_DMA_TABLE), long_read(SORT_DMA_COUNT),
|
nkeynes@753 | 154 | long_read(SORT_DMA_CTL) );
|
nkeynes@753 | 155 | long_write( SORT_DMA_CTL, 0 );
|
nkeynes@753 | 156 | }
|
nkeynes@753 | 157 | CHECK_IEQUALS( 0, long_read(SORT_DMA_CTL) );
|
nkeynes@753 | 158 | return result;
|
nkeynes@753 | 159 | }
|