nkeynes@185: #include nkeynes@185: #include nkeynes@185: #include "ide.h" nkeynes@185: #include "lib.h" nkeynes@185: nkeynes@185: #define IDE_BASE 0xA05F7000 nkeynes@185: nkeynes@185: #define IDE_ALTSTATUS IDE_BASE+0x018 nkeynes@185: #define IDE_UNKNOWN IDE_BASE+0x01C nkeynes@185: #define IDE_DATA IDE_BASE+0x080 /* 16 bits */ nkeynes@185: #define IDE_FEATURE IDE_BASE+0x084 nkeynes@185: #define IDE_COUNT IDE_BASE+0x088 nkeynes@185: #define IDE_LBA0 IDE_BASE+0x08C nkeynes@185: #define IDE_LBA1 IDE_BASE+0x090 nkeynes@185: #define IDE_LBA2 IDE_BASE+0x094 nkeynes@185: #define IDE_DEVICE IDE_BASE+0x098 nkeynes@185: #define IDE_COMMAND IDE_BASE+0x09C nkeynes@185: #define IDE_ACTIVATE IDE_BASE+0x4E4 nkeynes@185: nkeynes@185: #define IDE_DEVCONTROL IDE_ALTSTATUS nkeynes@185: #define IDE_ERROR IDE_FEATURE nkeynes@185: #define IDE_STATUS IDE_COMMAND nkeynes@185: nkeynes@185: #define IDE_DMA_ADDR IDE_BASE+0x404 nkeynes@185: #define IDE_DMA_SIZE IDE_BASE+0x408 nkeynes@185: #define IDE_DMA_DIR IDE_BASE+0x40C nkeynes@185: #define IDE_DMA_CTL1 IDE_BASE+0x414 nkeynes@185: #define IDE_DMA_CTL2 IDE_BASE+0x418 nkeynes@185: #define IDE_DMA_MAGIC IDE_BASE+0x4B8 nkeynes@185: #define IDE_DMA_STATUS IDE_BASE+0x4F8 nkeynes@185: nkeynes@185: #define DMA_BASE 0xFFA00000 nkeynes@185: #define DMA_SAR1 DMA_BASE+0x010 nkeynes@185: #define DMA_DAR1 DMA_BASE+0x014 nkeynes@185: #define DMA_TCR1 DMA_BASE+0x018 nkeynes@185: #define DMA_CHCR1 DMA_BASE+0x01C nkeynes@185: #define DMA_SAR2 DMA_BASE+0x020 nkeynes@185: #define DMA_DAR2 DMA_BASE+0x024 nkeynes@185: #define DMA_TCR2 DMA_BASE+0x028 nkeynes@185: #define DMA_CHCR2 DMA_BASE+0x02C nkeynes@185: #define DMA_SAR3 DMA_BASE+0x030 nkeynes@185: #define DMA_DAR3 DMA_BASE+0x034 nkeynes@185: #define DMA_TCR3 DMA_BASE+0x038 nkeynes@185: #define DMA_CHCR3 DMA_BASE+0x03C nkeynes@185: #define DMA_DMAOR DMA_BASE+0x040 nkeynes@185: #define QUEUECR0 0xFF000038 nkeynes@185: #define QUEUECR1 0xFF00003C nkeynes@185: nkeynes@185: #define IDE_CMD_RESET 0x08 nkeynes@185: #define IDE_CMD_PACKET 0xA0 nkeynes@185: #define IDE_CMD_IDENTIFY_PACKET_DEVICE 0xA1 nkeynes@185: #define IDE_CMD_IDENTIFY_DEVICE 0xEC nkeynes@185: nkeynes@185: #define MMC_CMD_GET_CONFIGURATION 0x46 nkeynes@185: #define GD_CMD_IDENTIFY 0x11 /* guessing */ nkeynes@185: nkeynes@185: nkeynes@185: #define IDE_DMA_MAGIC_VALUE 0x8843407F nkeynes@185: nkeynes@185: nkeynes@185: #define MAX_WAIT 10000000 nkeynes@185: #define MAX_IRQ_WAIT 1000000000 nkeynes@185: nkeynes@185: /** nkeynes@185: * Dump all ide registers to stdout. nkeynes@185: */ nkeynes@185: void ide_dump_registers() { nkeynes@185: int i,j; nkeynes@185: printf( "IDE registers:\n"); nkeynes@185: printf( "Stats: %02X ", byte_read(IDE_ALTSTATUS) ); nkeynes@185: printf( "Error: %02X ", byte_read(IDE_ERROR) ); nkeynes@185: printf( "Count: %02X ", byte_read(IDE_COUNT) ); nkeynes@185: printf( "Dvice: %02X ", byte_read(IDE_DEVICE) ); nkeynes@185: if( long_read(ASIC_STATUS1)&1 ) { nkeynes@185: printf( "INTRQ! " ); nkeynes@185: } nkeynes@185: if( (long_read(ASIC_STATUS0)>>14)&1 ) { nkeynes@185: printf( "DMARQ! " ); nkeynes@185: } nkeynes@185: printf( "\nLBA 0: %02X ", byte_read(IDE_LBA0) ); nkeynes@185: printf( "LBA 1: %02X ", byte_read(IDE_LBA1) ); nkeynes@185: printf( "LBA 2: %02X ", byte_read(IDE_LBA2) ); nkeynes@185: printf( "0x01C: %02X\n", byte_read(IDE_UNKNOWN) ); nkeynes@185: printf( "DAddr: %08X ", long_read(IDE_DMA_ADDR) ); nkeynes@185: printf( "DSize: %08X ", long_read(IDE_DMA_SIZE) ); nkeynes@185: printf( "DDir : %08X ", long_read(IDE_DMA_DIR) ); nkeynes@185: printf( "DCtl1: %08X ", long_read(IDE_DMA_CTL1) ); nkeynes@185: printf( "DCtl2: %08X\n", long_read(IDE_DMA_CTL2) ); nkeynes@185: printf( "DStat: %08X\n", long_read(IDE_DMA_STATUS) ); nkeynes@185: printf( "ASIC: " ); nkeynes@185: for( i=0; i<12; i+=4 ) { nkeynes@185: unsigned int val = long_read(ASIC_STATUS0+i); nkeynes@185: for( j=0; j<32; j++ ) { nkeynes@185: if( val & (1<>8)&0xFF ); nkeynes@185: byte_write( IDE_DEVICE, 0 ); nkeynes@185: byte_write( IDE_COMMAND, IDE_CMD_PACKET ); nkeynes@185: status = byte_read(IDE_ALTSTATUS); /* delay 1 PIO cycle as per spec */ nkeynes@185: /* Wait until device is ready to accept command */ nkeynes@185: if( ide_wait_ready() ) nkeynes@185: return 1; nkeynes@185: nkeynes@185: /* Write the command */ nkeynes@185: for( i=0; i<6; i++ ) { nkeynes@185: word_write( IDE_DATA, spkt[i] ); nkeynes@185: } nkeynes@185: } nkeynes@185: nkeynes@185: int ide_read_pio( char *buf, int buflen ) { nkeynes@185: int i; nkeynes@185: unsigned short *bufptr = (unsigned short *)buf; nkeynes@185: unsigned int length = 0, avail; nkeynes@185: int status; nkeynes@185: nkeynes@185: while(1) { nkeynes@185: if( ide_wait_ready() ) nkeynes@185: return -1; nkeynes@185: status = byte_read( IDE_STATUS ); nkeynes@185: if( (status & 0xE9) == 0x48 ) { nkeynes@185: /* Bytes available */ nkeynes@185: avail = (byte_read( IDE_LBA1 )) | (byte_read(IDE_LBA2)<<8); nkeynes@185: for( i=0; i 0 ) { nkeynes@185: *bufptr++ = word_read(IDE_DATA); nkeynes@185: buflen-=2; nkeynes@185: } nkeynes@185: } nkeynes@185: length += avail; nkeynes@185: if( avail == 0 ) { nkeynes@185: /* Should never happen */ nkeynes@185: printf( "[IDE] Unexpected read length 0\n" ); nkeynes@185: return -1; nkeynes@185: } nkeynes@185: } else { nkeynes@185: if( status&0x01 ) { nkeynes@185: printf( "[IDE] ERROR! (%02X)\n", status ); nkeynes@243: return -1; nkeynes@185: } else if( (status&0x08) == 0 ) { nkeynes@185: /* No more data */ nkeynes@185: return length; nkeynes@185: } else { nkeynes@185: printf( "[IDE] Unexpected status result: %02X\n", status ); nkeynes@185: return -1; nkeynes@185: } nkeynes@185: } nkeynes@185: } nkeynes@185: } nkeynes@185: nkeynes@185: int ide_read_dma( char *buf, int buflen ) nkeynes@185: { nkeynes@185: int status; nkeynes@185: nkeynes@185: long_write( IDE_DMA_CTL1, 1 ); nkeynes@185: long_write( IDE_DMA_CTL2, 1 ); nkeynes@185: nkeynes@185: printf( "Started DMA\n" ); nkeynes@185: ide_dump_registers(); nkeynes@185: nkeynes@185: ide_wait_irq(); nkeynes@185: printf( "After IRQ\n" ); nkeynes@185: ide_dump_registers(); nkeynes@185: long_write( IDE_DMA_CTL1, 0 ); nkeynes@185: status = ide_wait_dma(); nkeynes@185: printf( "After DMA finished\n"); nkeynes@185: ide_dump_registers(); nkeynes@185: if( status != 0 ) { nkeynes@185: return -1; nkeynes@185: } nkeynes@185: status = long_read(ASIC_STATUS0); nkeynes@185: if( (status & (1<<14)) == 0 ) { nkeynes@185: printf( "DMARQ cleared already\n"); nkeynes@185: } else { nkeynes@185: /* nkeynes@185: status &= ~(1<<14); nkeynes@185: long_write(ASIC_STATUS0, status); nkeynes@185: status = long_read(ASIC_STATUS0); nkeynes@185: */ nkeynes@185: byte_read(IDE_STATUS ); nkeynes@185: if( (status & (1<<14)) == 0 ) { nkeynes@185: printf( "DMARQ cleared successfully\n" ); nkeynes@185: } else { nkeynes@185: printf( "DMARQ not cleared: %08X\n", long_read(ASIC_STATUS0) ); nkeynes@185: } nkeynes@185: } nkeynes@185: status = ide_wait_ready(); nkeynes@185: printf( "After IDE ready\n"); nkeynes@185: ide_dump_registers(); nkeynes@185: if( status != 0 ) { nkeynes@185: return -1; nkeynes@185: } nkeynes@185: return long_read( IDE_DMA_STATUS ); nkeynes@185: } nkeynes@185: nkeynes@185: int ide_do_packet_command_pio( char *cmd, char *buf, int length ) nkeynes@185: { nkeynes@185: ide_write_command_packet( cmd, 0 ); nkeynes@185: length = ide_read_pio( buf, length ); nkeynes@185: return length; nkeynes@185: } nkeynes@185: nkeynes@185: int ide_do_packet_command_dma( char *cmd, char *buf, int length ) nkeynes@185: { nkeynes@185: long_write( QUEUECR0, 0x10 ); nkeynes@185: long_write( QUEUECR1, 0x10 ); nkeynes@185: long_write( IDE_DMA_MAGIC, IDE_DMA_MAGIC_VALUE ); nkeynes@185: long_write( IDE_DMA_ADDR, (unsigned int)buf ); nkeynes@185: long_write( IDE_DMA_SIZE, length ); nkeynes@185: long_write( IDE_DMA_DIR, 1 ); nkeynes@185: ide_write_command_packet( cmd, 1 ); nkeynes@185: length = ide_read_dma( buf, length ); nkeynes@185: return length; nkeynes@185: } nkeynes@185: nkeynes@243: void ide_activate() { nkeynes@243: register unsigned long p, x; nkeynes@243: nkeynes@243: /* Reactivate GD-ROM drive */ nkeynes@243: nkeynes@243: *((volatile unsigned long *)0xa05f74e4) = 0x1fffff; nkeynes@243: for(p=0; p<0x200000/4; p++) nkeynes@243: x = ((volatile unsigned long *)0xa0000000)[p]; nkeynes@243: } nkeynes@243: nkeynes@243: nkeynes@185: int ide_init() nkeynes@185: { nkeynes@243: ide_activate(); nkeynes@243: nkeynes@185: if( ide_wait_ready() ) nkeynes@185: return -1; nkeynes@185: nkeynes@185: /** Set Default PIO mode */ nkeynes@185: byte_write( IDE_FEATURE, 0x03 ); nkeynes@185: byte_write( IDE_COUNT, 0x0B ); nkeynes@185: byte_write( IDE_COMMAND, 0xEF ); nkeynes@185: nkeynes@185: if( ide_wait_ready() ) nkeynes@185: return -1; nkeynes@185: nkeynes@185: /** Set Multi-word DMA mode 2 */ nkeynes@185: long_write( 0xA05F7490, 0x222 ); nkeynes@185: long_write( 0xA05F7494, 0x222 ); nkeynes@185: byte_write( IDE_FEATURE, 0x03 ); nkeynes@185: byte_write( IDE_COUNT, 0x22 ); nkeynes@185: byte_write( IDE_COMMAND, 0xEF ); nkeynes@185: if( ide_wait_ready() ) nkeynes@185: return -1; nkeynes@185: nkeynes@185: word_write( 0xA05F7480, 0x400 ); nkeynes@185: long_write( 0xA05F7488, 0x200 ); nkeynes@185: long_write( 0xA05F748C, 0x200 ); nkeynes@185: long_write( 0xA05F74A0, 0x2001 ); nkeynes@185: long_write( 0xA05F74A4, 0x2001 ); nkeynes@185: long_write( 0xA05F74B4, 0x0001 ); nkeynes@185: } nkeynes@185: nkeynes@185: int ide_sense_error( char *buf ) nkeynes@185: { nkeynes@185: char cmd[12] = { 0x13,0,0,0, 10,0,0,0, 0,0,0,0 }; nkeynes@185: return ide_do_packet_command_pio( cmd, buf, 10 ); nkeynes@185: } nkeynes@185: nkeynes@251: int ide_get_sense_code() nkeynes@251: { nkeynes@251: char buf[10]; nkeynes@251: int len = ide_sense_error( buf ); nkeynes@251: if( len != 10 ) { nkeynes@251: printf( "ERROR: Sense request failed!\n" ); nkeynes@251: return -1; nkeynes@251: } nkeynes@251: return ((int)buf[8] << 8) | buf[2]; nkeynes@251: } nkeynes@251: nkeynes@185: void ide_print_sense_error() nkeynes@185: { nkeynes@185: char buf[10]; nkeynes@185: if( ide_sense_error(buf) != 10 ) { nkeynes@185: printf( "ERROR - Sense error failed!\n" ); nkeynes@185: return; nkeynes@185: } nkeynes@185: int major = buf[2] & 0xFF; nkeynes@185: int minor = buf[8] & 0xFF; nkeynes@185: printf( "[IDE] Error code %02X,%02X\n", major, minor ); nkeynes@185: } nkeynes@185: nkeynes@185: int ide_test_ready() nkeynes@185: { nkeynes@185: char cmd[12] = { 0,0,0,0, 0,0,0,0, 0,0,0,0 }; nkeynes@185: int length = ide_do_packet_command_pio( cmd, NULL, 0 ); nkeynes@185: return length; nkeynes@185: } nkeynes@185: nkeynes@185: int ide_read_toc( char *buf, int length ) nkeynes@185: { nkeynes@185: char cmd[12] = { 0x14,0,0,0, 0x98,0,0,0, 0,0,0,0 }; nkeynes@185: return ide_do_packet_command_pio( cmd, buf, length ); nkeynes@185: } nkeynes@185: nkeynes@185: int ide_get_session( int session, struct gdrom_session *session_data ) nkeynes@185: { nkeynes@185: char cmd[12] = {0x15, 0, session, 0, 6,0,0,0, 0,0,0,0 }; nkeynes@185: char buf[6]; nkeynes@185: int length = ide_do_packet_command_pio( cmd, buf, sizeof(buf) ); nkeynes@185: if( length < 0 ) nkeynes@185: return length; nkeynes@185: if( length != 6 ) nkeynes@185: return -1; nkeynes@185: assert(length == 6); nkeynes@185: session_data->track = ((int)buf[2])&0xFF; nkeynes@185: session_data->lba = (((int)buf[3])&0xFF) << 16 | nkeynes@185: (((int)buf[4])&0xFF) << 8 | nkeynes@185: (((int)buf[5])&0xFF); nkeynes@185: return 0; nkeynes@185: } nkeynes@185: nkeynes@185: int ide_spinup( ) nkeynes@185: { nkeynes@185: char cmd[12] = {0x70,0x1F,0,0, 0,0,0,0, 0,0,0,0}; nkeynes@185: int length = ide_do_packet_command_pio( cmd, NULL, 0 ); nkeynes@185: return length; nkeynes@185: } nkeynes@185: nkeynes@185: int ide_unknown71( char *buf, int length ) nkeynes@185: { nkeynes@185: char cmd[12] = {0x71,0,0,0, 0,0,0,0, 0,0,0,0}; nkeynes@185: return ide_do_packet_command_pio( cmd, buf, length ); nkeynes@185: } nkeynes@185: nkeynes@185: int ide_read_sector_pio( uint32_t sector, uint32_t count, int mode, nkeynes@185: char *buf, int length ) nkeynes@185: { nkeynes@185: char cmd[12] = { 0x30,0,0,0, 0,0,0,0, 0,0,0,0 }; nkeynes@185: nkeynes@185: cmd[1] = mode; nkeynes@185: cmd[2] = (sector>>16)&0xFF; nkeynes@185: cmd[3] = (sector>>8)&0xFF; nkeynes@185: cmd[4] = sector&0xFF; nkeynes@185: cmd[8] = (count>>16)&0xFF; nkeynes@185: cmd[9] = (count>>8)&0xFF; nkeynes@185: cmd[10] = count&0xFF; nkeynes@185: return ide_do_packet_command_pio( cmd, buf, length ); nkeynes@185: } nkeynes@185: nkeynes@185: nkeynes@185: int ide_read_sector_dma( uint32_t sector, uint32_t count, int mode, nkeynes@185: char *buf, int length ) nkeynes@185: { nkeynes@185: char cmd[12] = { 0x30,0,0,0, 0,0,0,0, 0,0,0,0 }; nkeynes@185: nkeynes@185: cmd[1] = mode; nkeynes@185: cmd[2] = (sector>>16)&0xFF; nkeynes@185: cmd[3] = (sector>>8)&0xFF; nkeynes@185: cmd[4] = sector&0xFF; nkeynes@185: cmd[8] = (count>>16)&0xFF; nkeynes@185: cmd[9] = (count>>8)&0xFF; nkeynes@185: cmd[10] = count&0xFF; nkeynes@185: return ide_do_packet_command_dma( cmd, buf, length ); nkeynes@185: } nkeynes@185: nkeynes@185: int ide_read_something( ) nkeynes@185: { nkeynes@185: char cmd[12] = { 0x12,0,0,0, 0x0a,0,0,0, 0,0,0,0 }; nkeynes@185: char result[10]; nkeynes@185: ide_do_packet_command_pio( cmd, result, 10 ); nkeynes@185: return 0; nkeynes@243: } nkeynes@243: nkeynes@251: int ide_read_status( char *buf, int length, int type ) nkeynes@243: { nkeynes@243: char cmd[12] = { 0x40,0,0,0, 0xFF,0,0,0, 0,0,0,0 }; nkeynes@243: nkeynes@251: cmd[1] = type; nkeynes@243: return ide_do_packet_command_pio( cmd, buf, length ); nkeynes@243: } nkeynes@243: nkeynes@243: int ide_play_cd( char *buf, int length ) nkeynes@243: { nkeynes@243: char cmd[12] = { 0x21, 0x04,0,0, 0,0,0,0, 0,0,0,0 }; nkeynes@243: return ide_do_packet_command_pio( cmd, buf, length ); nkeynes@243: }