📄 ide.c
字号:
/***************************************** Copyright (c) 2003-2004 Sigma Designs, Inc. All Rights Reserved Proprietary and Confidential *****************************************//* This file is part of the EM86XX boot loader *//* * ide.c * * IDE controller * * by Ho Lee 03/12/2003 */#include "config.h"#include "uart.h"#include "io.h"#include "util.h"#include "hardware.h"#include "em86xxapi.h"#include "irqs.h"#include "timer.h"#include "ide.h"#include "atapi.h"#ifdef CONFIG_ENABLE_FIP#include "fip.h"extern const char *fiptext;#endif#define IDE_VERBOSE 0/* CDROM try status, only for drive 0 */int cdrom0_tray_state = 0;int ide_init(void){ // Peripheral Bus interface // 0x00080000 is optimal for both of PIO and DMA for recent HDDs#if 0 // use timing 1 : normal transfer __raw_writel(DEFAULT_PB_TIMING1, REG_BASE_HOST + PB_timing1); __raw_writel(DEFAULT_PB_USE_TIMING1, REG_BASE_HOST + PB_use_timing1); // use timing 2 : DMA transfer __raw_writel(DEFAULT_PB_TIMING2, REG_BASE_HOST + PB_timing2); __raw_writel(DEFAULT_PB_USE_TIMING2, REG_BASE_HOST + PB_use_timing2);#endif#if 0 // use timing 1, 2 : normal transfer R/W __raw_writel(0x00080000, REG_BASE_HOST + PB_timing1); __raw_writel(0x000001e3, REG_BASE_HOST + PB_use_timing1); __raw_writel(0x00030000, REG_BASE_HOST + PB_timing2); __raw_writel(0x000001d3, REG_BASE_HOST + PB_use_timing2); // use timing 3, 4 : DMA transfer R/W __raw_writel(0x00080000, REG_BASE_HOST + PB_timing3); __raw_writel(0x000002e3, REG_BASE_HOST + PB_use_timing3); __raw_writel(0x00050000, REG_BASE_HOST + PB_timing4); __raw_writel(0x000002d3, REG_BASE_HOST + PB_use_timing4);#endif return 0;}#ifdef CONFIG_ENABLE_IDEunsigned long g_ide_reg_base = #ifdef CONFIG_ENABLE_IDE_ISA REG_BASE_HOST_ISAIDE;#else REG_BASE_HOST_BMIDE;#endif//// IDE Initialize//static int g_ide_dsinited = 0;static ide_info_t g_ideinfo[MAX_DRIVES];int ide_dsinit(void){ int i; for (i = 0; i < MAX_DRIVES; ++i) g_ideinfo[i].select.all = ((i << 4) | 0xa0); g_ide_dsinited = 1; return 0;}int ide_found(int mask){ int drive, found = 0; ide_info_t *pideinfo; if (!g_ide_dsinited) ide_dsinit(); for (drive = 0; drive < MAX_DRIVES; ++drive) { pideinfo = g_ideinfo + drive; if (pideinfo->type & mask) found |= (1 << drive); } return found;}#ifdef CONFIG_ENABLE_IDE_BMstatic void em86xx_ide_config_drive(int drive, ide_info_t *pideinfo){ ide_id_t *id = &pideinfo->id; int speed=0; int mode=0; int set_mode; if ((__raw_readl(REG_BASE_host_interface + IDECTRL_idestatus) & 0x02) == 0x02) mode = 1; // 40 donductor cable (UDMA33) : Mode 0/1/2 else mode = 4; // 80 conductor cable : Mode 0/1/2/3/4/5/6 switch(mode) { case 0x04: if (id->dma_ultra & 0x0040) { speed = XFER_UDMA_6; break; } case 0x03: if (id->dma_ultra & 0x0020) { speed = XFER_UDMA_5; break; } case 0x02: if (id->dma_ultra & 0x0010) { speed = XFER_UDMA_4; break; } if (id->dma_ultra & 0x0008) { speed = XFER_UDMA_3; break; } case 0x01: if (id->dma_ultra & 0x0004) { speed = XFER_UDMA_2; break; } if (id->dma_ultra & 0x0002) { speed = XFER_UDMA_1; break; } if (id->dma_ultra & 0x0001) { speed = XFER_UDMA_0; break; } case 0x00: if (id->dma_mword & 0x0004) { speed = XFER_MW_DMA_2; break; } if (id->dma_mword & 0x0002) { speed = XFER_MW_DMA_1; break; } if (id->dma_mword & 0x0001) { speed = XFER_MW_DMA_0; break; } if (id->dma_1word & 0x0004) { speed = XFER_SW_DMA_2; break; } if (id->dma_1word & 0x0002) { speed = XFER_SW_DMA_1; break; } if (id->dma_1word & 0x0001) { speed = XFER_SW_DMA_0; break; } } /* For CDROM, we do the max. MDMA mode 2 */ if ((speed > XFER_MW_DMA_2) && (pideinfo->type == IDE_ATAPI)) speed = XFER_MW_DMA_2; if (speed == 0) //PIO mode speed = id->pio_modes; set_mode = speed & 0x0f; if (pideinfo->cap_udma && (speed >= XFER_UDMA_0 && speed <= XFER_UDMA_7)) { // setup UDMA mode // setup timing for Ultra DMA static unsigned int s_udma_tim1[] = {#if 0 0x33331f17, 0x3333180f, 0x3333130b, 0x33331308, 0x33331305, 0x33331003, 0x11110202,#endif 0x33332016, 0x3333190e, 0x3333140a, 0x33331407, 0x33331404, 0x33331103, 0x33331102, 0x11110202 }; static unsigned int s_udma_tim2[] = {#if 0 0x0000020d, 0x00000209, 0x00000206, 0x00000203, 0x00000201, 0x00000201, 0x00000201,#endif 0x0000010d, 0x00000109, 0x00000106, 0x00000103, 0x00000101, 0x00000101, 0x00000101, 0x00000101 }; uart_printf(" Set drive %d to Ultra DMA set_mode %d\n", drive, set_mode); // set drive speed ide_set_drive_speed(drive, XFER_UDMA_0 | set_mode); pideinfo->use_udma = 1; // enable Ultra DMA __raw_writel(__raw_readl(REG_BASE_host_interface + IDECTRL_udmactl) | ((drive == 0) ? 0x01 : 0x02), REG_BASE_host_interface + IDECTRL_udmactl); // set timing register __raw_writel(s_udma_tim1[set_mode], REG_BASE_host_interface + ((drive == 0) ? IDECTRL_pri_drv0udmatim1 : IDECTRL_pri_drv1udmatim1)); __raw_writel(s_udma_tim2[set_mode], REG_BASE_host_interface + ((drive == 0) ? IDECTRL_pri_drv0udmatim2 : IDECTRL_pri_drv1udmatim2)); } else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) { // setup DMA mode uart_printf(" Set drive %d to Multi-word DMA set_mode %d\n", drive, set_mode); // set drive speed ide_set_drive_speed(drive, XFER_MW_DMA_0 | set_mode); pideinfo->use_dma = 1; { // setup timing for Multi-word DMA static unsigned int s_dma_tim[] = {#if 0 0xdf2a2a93, 0x9d0f0952, 0x970d0441, 0x82020211 #endif 0xdf2a2a93, 0x9d0f0952, 0x970d0441 }; static unsigned int s_udma_tim1[] = {#if 0 0x35440b08, 0x35440a06, 0x35440804, 0x11110202#endif 0x35440b08, 0x35440a06, 0x35440804 }; static unsigned int s_udma_tim2[] = {#if 0 0x00000208, 0x00000206, 0x00000204, 0x00000202#endif 0x00000208, 0x00000206, 0x00000204 }; __raw_writel(s_dma_tim[set_mode], REG_BASE_host_interface + ((drive == 0) ? IDECTRL_pri_drv0tim : IDECTRL_pri_drv1tim)); __raw_writel(s_udma_tim1[set_mode], REG_BASE_host_interface + ((drive == 0) ? IDECTRL_pri_drv0udmatim1 : IDECTRL_pri_drv1udmatim1)); __raw_writel(s_udma_tim2[set_mode], REG_BASE_host_interface + ((drive == 0) ? IDECTRL_pri_drv0udmatim2 : IDECTRL_pri_drv1udmatim2)); } } else if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { // setup timing for PIO set_mode static unsigned int s_pio_tim[] = {#if 0 0xf73900d5, 0xcb2f0093, 0xaf280052, 0xa30f0d51, 0x970d0441#endif 0xf7200dd5, 0xcc180d93, 0xaf130d52, 0xa30f0d51, 0x970d0441 }; set_mode -= 8; uart_printf(" Set drive %d to PIO set_mode %d\n", drive, set_mode); __raw_writel(s_pio_tim[set_mode], REG_BASE_host_interface + ((drive == 0) ? IDECTRL_pri_drv0tim : IDECTRL_pri_drv1tim)); } return;}#endifint ide_probe(int drivemask, int verbose){ int i, drive, nfound; ide_info_t *pideinfo; if (!g_ide_dsinited) ide_dsinit(); for (drive = 0, nfound = 0; drive < MAX_DRIVES; ++drive) { if (drivemask & (1 << drive)) { if (verbose) uart_printf("Probing drive %d :\n", drive); pideinfo = ide_identify(drive); if (pideinfo->type != IDE_NONE) { if (verbose) uart_printf(" Found %s device : ", (pideinfo->type == IDE_ATA) ? "ATA" : "ATAPI"); else uart_printf("IDE %d (%s) : ", drive, (pideinfo->type == IDE_ATA) ? "ATA" : "ATAPI"); } if (pideinfo->type != IDE_NONE) { ++nfound; pideinfo->use_dma = 0; pideinfo->use_udma = 0; uart_printf("%s, %dMB, %s, %s\n", pideinfo->id.model_num, pideinfo->size, pideinfo->lba ? "LBA" : "CHS", pideinfo->cap_udma ? "UDMA" : (pideinfo->cap_dma ? "DMA" : "No DMA")); if (!pideinfo->lba && verbose) uart_printf(" cylinders = %d, heads = %d, sectors = %d\n", pideinfo->cyls, pideinfo->heads, pideinfo->sectors); if (verbose) { uart_puts(" "); if (pideinfo->cap_udma) uart_printf("UDMA = 0x%04x, ", pideinfo->id.dma_ultra); uart_printf("MDMA = 0x%04x, PIO = 0x%04x\n", pideinfo->id.dma_mword, pideinfo->id.pio_modes); uart_printf(" PIO mode support :"); if (pideinfo->id.pio_modes & 0x01) uart_puts(" 3"); if (pideinfo->id.pio_modes & 0x02) uart_puts(" 4"); uart_puts("\n"); uart_printf(" Major Rev = 0x%04x, Minor Rev = 0x%04x\n", pideinfo->id.major_ver, pideinfo->id.minor_ver); }#ifdef CONFIG_ENABLE_IDE_BM em86xx_ide_config_drive(drive, pideinfo);#else // setup DMA mode if (!pideinfo->use_udma && pideinfo->id.dma_mword & 0x0f) { ide_id_t *id = &pideinfo->id; int speed=0, set_mode; if (id->dma_mword & 0x0004) speed = XFER_MW_DMA_2; else if (id->dma_mword & 0x0002) speed = XFER_MW_DMA_1; else if (id->dma_mword & 0x0001) speed = XFER_MW_DMA_0; if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) { // setup DMA mode set_mode = speed & 0x0f; uart_printf(" Set drive %d to Multi-word DMA set_mode %d\n", drive, set_mode); // set drive speed ide_set_drive_speed(drive, XFER_MW_DMA_0 | set_mode); pideinfo->use_dma = 1; } }#endif // read partition table if (pideinfo->type == IDE_ATA) { pideinfo->npart = ide_read_partition(drive, pideinfo->part, 0); if (verbose) { uart_puts(" Partitions : "); for (i = 0; i < pideinfo->npart; ++i) if (pideinfo->part[i].valid) uart_printf("p%d ", i); uart_puts("\n"); } } else pideinfo->npart = 0; } } } return nfound;}//// IDE command//static int ide_command(int cmd, int drive, int feature, int cyl, int head, int sector, int nsector, void *buf, int buflen);static void ide_fixstring(unsigned char *s, const int bytecount, const int byteswap);// ide_command : sends command to ATA/ATAPI device and then read or write data// cmd : ATACMD_// drive : 0/1 (master/slave)// feature, cyl, head, sector, nsector : IDE registers// buf : buffer for read or write// buflen : buffer length in bytesint ide_command(int cmd, int drive, int feature, int cyl, int head, int sector, int nsector, void *buf, int buflen){#if IDE_VERBOSE static struct { int cmd; char *name; } s_cmdnamelist[] = { { ATACMD_NOP, "NOP" }, { ATACMD_DEVICERESET, "Device Reset" }, { ATACMD_READ, "Read Sector" }, { ATACMD_WRITE, "Write Sector" }, { ATACMD_FORMAT, "Format Sector" }, { ATACMD_SEEK, "Seek" }, { ATACMD_DIAGNOSE, "Diagnose" }, { ATACMD_PIDENTIFY, "ATAPI Identify" }, { ATACMD_READDMA, "Read Sector by DMA" }, { ATACMD_WRITEDMA, "Write Sector by DMA" }, { ATACMD_IDENTIFY, "ATA Identify" }, { -1, NULL }, }; int i;#endif int status; // Selecting drive#if IDE_VERBOSE uart_puts(" Select, ");#endif if (ide_select_drive(drive, (cmd == ATACMD_IDENTIFY || cmd == ATACMD_PIDENTIFY) ? 0 : 1)) {#if IDE_VERBOSE uart_puts("No device\n");#endif return 1; } // Sending command ide_outb(feature, IDE_FEATURE_REG); ide_outb(nsector, IDE_NSECTOR_REG); ide_outb(sector, IDE_SECTOR_REG); ide_outb((cyl & 0xff), IDE_LCYL_REG); ide_outb((cyl >> 8) & 0xff, IDE_HCYL_REG); ide_outb(head | g_ideinfo[drive].select.all, IDE_SELECT_REG); #if IDE_VERBOSE for (i = 0; s_cmdnamelist[i].cmd >= 0; ++i) { if (cmd == s_cmdnamelist[i].cmd) { uart_printf("%s, ", s_cmdnamelist[i].name); break; } } if (s_cmdnamelist[i].cmd < 0) uart_printf("Command 0x%02x, ", cmd);#endif ide_outb(cmd, IDE_COMMAND_REG); // Reading or Writing data if (buf && buflen > 0) { if (cmd == ATACMD_WRITE) { while (buflen > 0) {#if IDE_VERBOSE uart_puts("Writing\n"); if (buflen > SECTOR_SIZE) uart_puts(", "); else uart_puts("\n");#endif ide_wait_stat(IDESTAT_DRQ, IDESTAT_DRQ, 0); ide_output_data((unsigned short *) buf, SECTOR_SIZE / 2); buf = (unsigned char *) buf + SECTOR_SIZE; buflen -= SECTOR_SIZE; ide_wait_stat(IDESTAT_BUSY, 0, 0); } } else { memset(buf, 0xbe, buflen); while (buflen > 0) { ide_wait_stat(IDESTAT_BUSY, 0, 0); status = ide_inb(IDE_STATUS_REG); if (status & IDESTAT_DRQ) {#if IDE_VERBOSE uart_puts("Reading"); if (buflen > SECTOR_SIZE) uart_puts(", "); else uart_puts("\n");#endif ide_input_data((unsigned short *) buf, SECTOR_SIZE / 2); buf = (unsigned char *) buf + SECTOR_SIZE; buflen -= SECTOR_SIZE; } else {#if IDE_VERBOSE uart_puts("No Data\n"); #endif return 2; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -