⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ide.c

📁 bootloader源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/***************************************** 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;}int 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);                }                // setup UDMA mode#ifdef CONFIG_ENABLE_IDE_BM                if (pideinfo->cap_udma && (pideinfo->id.dma_ultra & 0x3f) != 0) {                    // find the highest DMA mode                    static unsigned int s_udma_tim1[] = {                        0x33331f17, 0x3333180f, 0x3333130b, 0x33331308,                        0x33331305, 0x33331003, 0x11110202,                    };                    static unsigned int s_udma_tim2[] = {                        0x0000020d, 0x00000209, 0x00000206, 0x00000203,                         0x00000201, 0x00000201, 0x00000201,                    };                    for (i = 6; i >= 0; --i) {                        if (pideinfo->id.dma_ultra & (1 << i)) {                            // set drive speed                            ide_set_drive_speed(drive, TRANSFER_UDMA_0 | i);                            // set UDMA timing register#if 0                            uart_printf("drvudmatim1: 0x%08x\n", __raw_readl(REG_BASE_HOST + ((drive == 0) ? IDECTRL_pri_drv0udmatim1 : IDECTRL_pri_drv1udmatim1)));                            uart_printf("drvudmatim2: 0x%08x\n", __raw_readl(REG_BASE_HOST + ((drive == 0) ? IDECTRL_pri_drv0udmatim2 : IDECTRL_pri_drv1udmatim2)));#endif                            __raw_writel(s_udma_tim1[i], REG_BASE_HOST + ((drive == 0) ? IDECTRL_pri_drv0udmatim1 : IDECTRL_pri_drv1udmatim1));                            __raw_writel(s_udma_tim2[i], REG_BASE_HOST + ((drive == 0) ? IDECTRL_pri_drv0udmatim2 : IDECTRL_pri_drv1udmatim2));                            __raw_writel(__raw_readl(REG_BASE_HOST + IDECTRL_udmactl) | ((drive == 0) ? 0x01 : 0x02), REG_BASE_HOST + IDECTRL_udmactl);                            if (verbose)                                uart_printf("  Use UDMA mode %d\n", i);                            pideinfo->use_udma = 1;                            break;                        }                    }                }#endif                // setup DMA mode                if (!pideinfo->use_udma && pideinfo->id.dma_mword & 0x0f) {                    // find the highest DMA mode                    for (i = 2; i >= 0; --i) {                        if (pideinfo->id.dma_mword & (1 << i)) {                            ide_set_drive_speed(drive, TRANSFER_MWDMA_0 | i);                            if (verbose)                                uart_printf("  Use MDMA mode %d\n", i);                            pideinfo->use_dma = 1;#ifdef CONFIG_ENABLE_IDE_BM                            // setup timing for DMA                            {                                static unsigned int s_dma_tim[] = {                                    0xdf2a2a93, 0x9d0f0952, 0x970d0441, 0x82020211                                 };                                static unsigned int s_udma_tim1[] = {                                    0x35440b08, 0x35440a06, 0x35440804, 0x11110202                                };                                static unsigned int s_udma_tim2[] = {                                    0x00000208, 0x00000206, 0x00000204, 0x00000202                                };#if 0                                uart_printf("drvtim: 0x%08x\n", __raw_readl(REG_BASE_HOST + ((drive == 0) ? IDECTRL_pri_drv0tim : IDECTRL_pri_drv1tim)));                                uart_printf("drvudmatim1: 0x%08x\n", __raw_readl(REG_BASE_HOST + ((drive == 0) ? IDECTRL_pri_drv0udmatim1 : IDECTRL_pri_drv1udmatim1)));                                uart_printf("drvudmatim2: 0x%08x\n", __raw_readl(REG_BASE_HOST + ((drive == 0) ? IDECTRL_pri_drv0udmatim2 : IDECTRL_pri_drv1udmatim2)));#endif                                __raw_writel(s_dma_tim[i], REG_BASE_HOST + ((drive == 0) ? IDECTRL_pri_drv0tim : IDECTRL_pri_drv1tim));                                __raw_writel(s_udma_tim1[i], REG_BASE_HOST + ((drive == 0) ? IDECTRL_pri_drv0udmatim1 : IDECTRL_pri_drv1udmatim1));                                __raw_writel(s_udma_tim2[i], REG_BASE_HOST + ((drive == 0) ? IDECTRL_pri_drv0udmatim2 : IDECTRL_pri_drv1udmatim2));                            }#endif                            break;                        }                    }                }                                // 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;                }            }         }    } #if IDE_VERBOSE    else        uart_puts("\n");#endif        return 0;}#define IDE_WAIT_TIMEOUT        1000int ide_wait_stat(int mask, int waitmask, int btimeout){    int status;    int timeout = IDE_WAIT_TIMEOUT;        do {        status = ide_inb(IDE_STATUS_REG);        if (btimeout) {            if (timeout-- == 0) {#if IDE_VERBOSE                uart_puts("timeout ");#endif                return 1;            }            em86xx_msleep(1);        }    } while ((status & mask) != waitmask);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -