Search
lxdream.org :: lxdream/test/dmac.c
lxdream 0.9.1
released Jun 29
Download Now
filename test/dmac.c
changeset 815:866c103d72cd
prev812:8cc61d5ea1f8
author nkeynes
date Mon Aug 18 12:20:28 2008 +0000 (13 years ago)
permissions -rw-r--r--
last change Implement memcpy_to_aica, still a work in progress though
file annotate diff log raw
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@815
    19
#include <assert.h>
nkeynes@185
    20
#include "dma.h"
nkeynes@185
    21
#include "asic.h"
nkeynes@185
    22
nkeynes@185
    23
#define DMA_BASE 0xFFA00000
nkeynes@185
    24
nkeynes@185
    25
#define DMA_SAR(c) (DMA_BASE+0x00+(c<<4))
nkeynes@185
    26
#define DMA_DAR(c) (DMA_BASE+0x04+(c<<4))
nkeynes@185
    27
#define DMA_TCR(c) (DMA_BASE+0x08+(c<<4))
nkeynes@185
    28
#define DMA_CHCR(c) (DMA_BASE+0x0C+(c<<4))
nkeynes@185
    29
#define DMA_OR (DMA_BASE+0x40)
nkeynes@185
    30
nkeynes@185
    31
#define ASIC_BASE 0xA05F6000
nkeynes@185
    32
#define PVR_DMA_DEST  (ASIC_BASE+0x800)
nkeynes@185
    33
#define PVR_DMA_COUNT (ASIC_BASE+0x804)
nkeynes@185
    34
#define PVR_DMA_CTL   (ASIC_BASE+0x808)
nkeynes@185
    35
#define PVR_DMA_REGION (ASIC_BASE+0x884)
nkeynes@185
    36
nkeynes@753
    37
#define SORT_DMA_TABLE (ASIC_BASE+0x810)
nkeynes@753
    38
#define SORT_DMA_DATA  (ASIC_BASE+0x814)
nkeynes@753
    39
#define SORT_DMA_TABLEBITS (ASIC_BASE+0x818)
nkeynes@753
    40
#define SORT_DMA_DATASIZE (ASIC_BASE+0x81C)
nkeynes@753
    41
#define SORT_DMA_CTL   (ASIC_BASE+0x820)
nkeynes@753
    42
#define SORT_DMA_COUNT (ASIC_BASE+0x860)
nkeynes@753
    43
nkeynes@815
    44
#define AICA_RAM_BASE 0xA0800000
nkeynes@815
    45
#define AICA_RAM_SIZE 0x00200000
nkeynes@812
    46
nkeynes@812
    47
#define G2DMABASE 0xA05F7800
nkeynes@812
    48
#define G2DMATIMEOUT (G2DMABASE+0x90)
nkeynes@812
    49
#define G2DMAMAGIC (G2DMABASE+0xBC)
nkeynes@812
    50
#define G2DMAEXT(x) (G2DMABASE+(0x20*(x)))
nkeynes@812
    51
#define G2DMAHOST(x) (G2DMABASE+(0x20*(x))+0x04)
nkeynes@812
    52
#define G2DMASIZE(x) (G2DMABASE+(0x20*(x))+0x08)
nkeynes@812
    53
#define G2DMADIR(x) (G2DMABASE+(0x20*(x))+0x0C)
nkeynes@812
    54
#define G2DMAMODE(x) (G2DMABASE+(0x20*(x))+0x10)
nkeynes@812
    55
#define G2DMACTL1(x) (G2DMABASE+(0x20*(x))+0x14)
nkeynes@812
    56
#define G2DMACTL2(x) (G2DMABASE+(0x20*(x))+0x18)
nkeynes@812
    57
#define G2DMASTOP(x) (G2DMABASE+(0x20*(x))+0x1C)
nkeynes@812
    58
nkeynes@185
    59
void dmac_dump_channel( FILE *f, unsigned int channel )
nkeynes@185
    60
{
nkeynes@185
    61
    fprintf( f, "DMAC SAR: %08X  Count: %08X  Ctl: %08X  OR: %08X\n",
nkeynes@185
    62
	     long_read(DMA_SAR(channel)), long_read(DMA_TCR(channel)), 
nkeynes@185
    63
	     long_read(DMA_CHCR(channel)), long_read(DMA_OR) );
nkeynes@185
    64
}
nkeynes@185
    65
nkeynes@185
    66
nkeynes@185
    67
/**
nkeynes@185
    68
 * Setup the DMAC for a transfer. Assumes 32-byte block transfer.
nkeynes@185
    69
 * Caller is responsible for making sure no-one else is using the
nkeynes@185
    70
 * channel already. 
nkeynes@185
    71
 *
nkeynes@185
    72
 * @param channel DMA channel to use, 0 to 3
nkeynes@185
    73
 * @param source source address (if a memory source)
nkeynes@185
    74
 * @param dest   destination address (if a memory destination)
nkeynes@185
    75
 * @param length number of bytes to transfer (must be a multiple of
nkeynes@185
    76
 *               32.
nkeynes@185
    77
 * @param direction 0 = host to device, 1 = device to host
nkeynes@185
    78
 */
nkeynes@185
    79
void dmac_prepare_channel( int channel, uint32_t source, uint32_t dest,
nkeynes@185
    80
			   uint32_t length, int direction )
nkeynes@185
    81
{
nkeynes@185
    82
    uint32_t control;
nkeynes@185
    83
nkeynes@185
    84
    if( direction == 0 ) {
nkeynes@185
    85
	/* DMA Disabled, IRQ disabled, 32 byte transfer, burst mode,
nkeynes@185
    86
	 * Memory => Device, Source addr increment, dest addr fixed
nkeynes@185
    87
	 */
nkeynes@185
    88
	control = 0x000012C0;
nkeynes@185
    89
    } else {
nkeynes@185
    90
	/* DMA Disabled, IRQ disabled, 32 byte transfer, burst mode,
nkeynes@185
    91
	 * Device => Memory, Source addr fixed, dest addr increment
nkeynes@185
    92
	 */
nkeynes@185
    93
	control = 0x000043C0;
nkeynes@185
    94
    }
nkeynes@185
    95
    long_write( DMA_CHCR(channel), control );
nkeynes@185
    96
    long_write( DMA_SAR(channel), source );
nkeynes@185
    97
    long_write( DMA_DAR(channel), dest );
nkeynes@185
    98
    long_write( DMA_TCR(channel), (length >> 5) );
nkeynes@185
    99
    control |= 0x0001;
nkeynes@185
   100
    long_write( DMA_CHCR(channel), control ); /* Enable DMA channel */
nkeynes@185
   101
    long_write( DMA_OR, 0x8201 ); /* Ensure the DMAC config is set */
nkeynes@185
   102
}
nkeynes@185
   103
nkeynes@185
   104
nkeynes@185
   105
int pvr_dma_write( unsigned int target, char *buf, int len, int region )
nkeynes@185
   106
{
nkeynes@185
   107
    uint32_t addr =(uint32_t)buf;
nkeynes@185
   108
    int result;
nkeynes@185
   109
    if( (addr & 0xFFFFFFE0) != addr ) {
nkeynes@185
   110
	fprintf( stderr, "Address error: Attempting DMA from %08X\n", addr );
nkeynes@185
   111
	return -1;
nkeynes@185
   112
    }
nkeynes@185
   113
    long_write( PVR_DMA_CTL, 0 ); /* Stop PVR dma if it's already running */
nkeynes@185
   114
    asic_clear();
nkeynes@185
   115
nkeynes@185
   116
    dmac_prepare_channel( 2, (uint32_t)buf, 0, len, 0 ); /* Allocate channel 2 */
nkeynes@185
   117
    long_write( PVR_DMA_DEST, target );
nkeynes@185
   118
    long_write( PVR_DMA_COUNT, len );
nkeynes@185
   119
    long_write( PVR_DMA_REGION, region );
nkeynes@185
   120
nkeynes@185
   121
    CHECK_IEQUALS( target, long_read(PVR_DMA_DEST) );
nkeynes@185
   122
    CHECK_IEQUALS( len, long_read(PVR_DMA_COUNT) );
nkeynes@185
   123
    CHECK_IEQUALS( 0, long_read(PVR_DMA_REGION) );
nkeynes@185
   124
    CHECK_IEQUALS( (uint32_t)buf, long_read(DMA_SAR(2)) );
nkeynes@185
   125
    CHECK_IEQUALS( len/32, long_read(DMA_TCR(2)) );
nkeynes@185
   126
    CHECK_IEQUALS( 0x12C1, long_read(DMA_CHCR(2)) );
nkeynes@185
   127
nkeynes@185
   128
    long_write( PVR_DMA_CTL, 1 );
nkeynes@185
   129
    result = asic_wait(EVENT_PVR_DMA);
nkeynes@185
   130
nkeynes@185
   131
    if( result != 0 ) {
nkeynes@185
   132
	fprintf( stderr, "PVR DMA failed (timeout)\n" );
nkeynes@185
   133
	asic_dump(stderr);
nkeynes@185
   134
	fprintf( stderr, "Dest: %08X  Count: %08X  Ctl: %08X\n", long_read(PVR_DMA_DEST),
nkeynes@185
   135
		 long_read(PVR_DMA_COUNT), long_read(PVR_DMA_CTL) );
nkeynes@185
   136
	dmac_dump_channel(stderr, 2);
nkeynes@185
   137
	long_write( PVR_DMA_CTL, 0 );
nkeynes@185
   138
    }
nkeynes@185
   139
nkeynes@185
   140
    CHECK_IEQUALS( 0, long_read(PVR_DMA_CTL) );
nkeynes@185
   141
    CHECK_IEQUALS( ((uint32_t)buf)+len, long_read(DMA_SAR(2))  );
nkeynes@185
   142
    CHECK_IEQUALS( 0, long_read(DMA_TCR(2)) );
nkeynes@185
   143
    CHECK_IEQUALS( 0x12C3, long_read(DMA_CHCR(2)) );
nkeynes@185
   144
    CHECK_IEQUALS( target, long_read(PVR_DMA_DEST) );
nkeynes@185
   145
    CHECK_IEQUALS( 0, long_read(PVR_DMA_COUNT) );
nkeynes@185
   146
    CHECK_IEQUALS( 0, long_read(PVR_DMA_REGION) );
nkeynes@185
   147
nkeynes@185
   148
    return result;
nkeynes@185
   149
}
nkeynes@753
   150
nkeynes@753
   151
int sort_dma_write( char *sorttable, int tablelen, char *data, int datalen, int bitwidth, int datasize )
nkeynes@753
   152
{
nkeynes@753
   153
    int result;
nkeynes@753
   154
    uint32_t tableaddr = (uint32_t)sorttable;
nkeynes@753
   155
    uint32_t dataaddr = (uint32_t)data;
nkeynes@753
   156
    
nkeynes@753
   157
    long_write( SORT_DMA_CTL, 0 );
nkeynes@753
   158
    asic_clear();
nkeynes@753
   159
    
nkeynes@753
   160
    long_write( SORT_DMA_TABLE, tableaddr );
nkeynes@753
   161
    long_write( SORT_DMA_DATA, dataaddr );
nkeynes@753
   162
    long_write( SORT_DMA_TABLEBITS, bitwidth );
nkeynes@753
   163
    long_write( SORT_DMA_DATASIZE, datasize );
nkeynes@753
   164
    long_write( SORT_DMA_CTL, 1 );
nkeynes@753
   165
    result = asic_wait2(EVENT_SORT_DMA, EVENT_SORT_DMA_ERR);
nkeynes@753
   166
    if( result == -1 ) {
nkeynes@753
   167
        fprintf( stderr, "SORT DMA failed (timeout)\n" );
nkeynes@753
   168
        asic_dump(stderr);
nkeynes@753
   169
        fprintf( stderr, "Table: %08X Count: %08X Ctl: %08X\n", long_read(SORT_DMA_TABLE), long_read(SORT_DMA_COUNT),
nkeynes@753
   170
                 long_read(SORT_DMA_CTL) );
nkeynes@753
   171
        long_write( SORT_DMA_CTL, 0 );
nkeynes@753
   172
    }
nkeynes@753
   173
    CHECK_IEQUALS( 0, long_read(SORT_DMA_CTL) );
nkeynes@753
   174
    return result;
nkeynes@753
   175
}
nkeynes@812
   176
nkeynes@812
   177
int aica_dma_transfer( uint32_t aica_addr, char *data, uint32_t size, int writeFlag )
nkeynes@812
   178
{
nkeynes@812
   179
    long_write( G2DMATIMEOUT, 0 );
nkeynes@812
   180
    long_write( G2DMAMAGIC, 0x4659404f );
nkeynes@812
   181
    long_write( G2DMACTL1(0), 0 );
nkeynes@812
   182
    long_write( G2DMAEXT(0), aica_addr );
nkeynes@812
   183
    long_write( G2DMAHOST(0), ((uint32_t)data) );
nkeynes@812
   184
    long_write( G2DMASIZE(0), ((size+31)&0x7FFFFFE0) | 0x80000000 );
nkeynes@812
   185
    long_write( G2DMADIR(0), (writeFlag ? 0 : 1) );
nkeynes@812
   186
    long_write( G2DMAMODE(0), 0 );
nkeynes@812
   187
    
nkeynes@812
   188
    long_write( G2DMACTL1(0), 1 );
nkeynes@812
   189
    long_write( G2DMACTL2(0), 1 );
nkeynes@812
   190
    if( asic_wait( EVENT_G2_DMA0 ) != 0 ) {
nkeynes@812
   191
        fprintf( stderr, "Timeout waiting for G2 DMA event\n" );
nkeynes@812
   192
        return -1;
nkeynes@812
   193
    }
nkeynes@812
   194
    // CHECK_IEQUALS( 0, long_read( G2DMACTL1(0) ) );
nkeynes@812
   195
    CHECK_IEQUALS( 0, long_read( G2DMACTL2(0) ) );
nkeynes@812
   196
    return 0;
nkeynes@812
   197
}
nkeynes@812
   198
nkeynes@812
   199
int aica_dma_write( uint32_t aica_addr, char *data, uint32_t size )
nkeynes@812
   200
{
nkeynes@812
   201
    return aica_dma_transfer( aica_addr, data, size, 1 );
nkeynes@812
   202
}
nkeynes@812
   203
nkeynes@812
   204
int aica_dma_read( char *data, uint32_t aica_addr, uint32_t size )
nkeynes@812
   205
{
nkeynes@812
   206
    return aica_dma_transfer( aica_addr, data, size, 0 );
nkeynes@812
   207
}
nkeynes@815
   208
nkeynes@815
   209
int memcpy_to_aica( uint32_t aica_addr, void *data, size_t size )
nkeynes@815
   210
{
nkeynes@815
   211
    assert( (aica_addr & 0x03) == 0 );
nkeynes@815
   212
    uint32_t *src = (uint32_t *)data;
nkeynes@815
   213
    uint32_t *dest = (uint32_t *)aica_addr;
nkeynes@815
   214
    while( size > 0 ) {
nkeynes@815
   215
        int i;
nkeynes@815
   216
        if( g2_fifo_wait() != 0 ) {
nkeynes@815
   217
            return -1;
nkeynes@815
   218
        }
nkeynes@815
   219
        irq_disable();
nkeynes@815
   220
        for( i=0; i<8 && size > 0; i++ ) {
nkeynes@815
   221
            *dest++ = *src++;
nkeynes@815
   222
            size -= 4;
nkeynes@815
   223
        }
nkeynes@815
   224
        irq_enable();
nkeynes@815
   225
    }
nkeynes@815
   226
    return 0;
nkeynes@815
   227
}
.