📄 cmd_ide.c
字号:
/*
* (C) Copyright 2000
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
*/
/*
* IDE support
*/
#include <mpc8xx_irq.h>
#include <ppcboot.h>
#include <config.h> /* for PIO mode selection */
#include <command.h>
#include <image.h>
#ifdef CONFIG_IDE_PCMCIA
#include <pcmcia.h>
#endif
#include <ide.h>
#include <ata.h>
#include <cmd_ide.h>
#include <cmd_disk.h>
#include <mpc8xx.h>
/* stdlib.h causes some compatibility problems; should fixe these! -- wd */
#ifndef __ldiv_t_defined
typedef struct {
long int quot; /* Quotient */
long int rem; /* Remainder */
} ldiv_t;
extern ldiv_t ldiv (long int __numer, long int __denom);
# define __ldiv_t_defined 1
#endif
#ifdef DEBUG
#define PRINTF(fmt,args...) do { \
printf (fmt ,##args); \
} while (0)
#else
#define PRINTF(fmt,args...)
#endif
#if (CONFIG_COMMANDS & CFG_CMD_IDE)
/* Timings for IDE Interface
*
* SETUP / LENGTH / HOLD - cycles valid for 50 MHz clk
* 70 165 30 PIO-Mode 0, [ns]
* 4 9 2 [Cycles]
* 50 125 20 PIO-Mode 1, [ns]
* 3 7 2 [Cycles]
* 30 100 15 PIO-Mode 2, [ns]
* 2 6 1 [Cycles]
* 30 80 10 PIO-Mode 3, [ns]
* 2 5 1 [Cycles]
* 25 70 10 PIO-Mode 4, [ns]
* 2 4 1 [Cycles]
*/
const static pio_config_t pio_config_ns [IDE_MAX_PIO_MODE+1] =
{
/* Setup Length Hold */
{ 70, 165, 30 }, /* PIO-Mode 0, [ns] */
{ 50, 125, 20 }, /* PIO-Mode 1, [ns] */
{ 30, 101, 15 }, /* PIO-Mode 2, [ns] */
{ 30, 80, 10 }, /* PIO-Mode 3, [ns] */
{ 25, 70, 10 }, /* PIO-Mode 4, [ns] */
};
static pio_config_t pio_config_clk [IDE_MAX_PIO_MODE+1];
#ifndef CFG_PIO_MODE
#define CFG_PIO_MODE 0 /* use a relaxed default */
#endif
static int pio_mode = CFG_PIO_MODE;
/* Make clock cycles and always round up */
#define PCMCIA_MK_CLKS( t, T ) (( (t) * (T) + 999U ) / 1000U )
/* ------------------------------------------------------------------------- */
#ifdef CONFIG_IDE_PCMCIA
/*
* Allow configuration to select PCMCIA slot,
* or try to generate a useful default
*/
#if !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B)
/* The RPX series use SLOT_B */
#if defined(CONFIG_RPXCLASSIC) || defined(CONFIG_RPXLITE)
# define CONFIG_PCMCIA_SLOT_B
#elif defined(CONFIG_ADS) /* The ADS board use SLOT_A */
# define CONFIG_PCMCIA_SLOT_A
#elif defined(CONFIG_FADS) /* The FADS series are a mess */
# if defined(CONFIG_MPC860T) || defined(CONFIG_MPC860) || defined(CONFIG_MPC821)
# define CONFIG_PCMCIA_SLOT_A
# else
# define CONFIG_PCMCIA_SLOT_B
# endif
#elif defined(CONFIG_TQM860L) || defined(CONFIG_TQM855L) /* The TQM8xxL modules */
# define CONFIG_PCMCIA_SLOT_A /* ... use SLOT_A on MPC860/855 */
#elif defined(CONFIG_TQM823L) || defined(CONFIG_TQM850L)
# define CONFIG_PCMCIA_SLOT_B /* ... and SLOT_B else */
#elif defined(CONFIG_SPD823TS) /* The SPD8xx use SLOT_B */
# define CONFIG_PCMCIA_SLOT_B
#else
# error "PCMCIA Slot not configured"
#endif
#endif /* !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B) */
/* Make sure exactly one slot is defined - we support only one for now */
#if !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B)
#error Neither CONFIG_PCMCIA_SLOT_A nor CONFIG_PCMCIA_SLOT_B configured
#endif
#if defined(CONFIG_PCMCIA_SLOT_A) && defined(CONFIG_PCMCIA_SLOT_B)
#error Both CONFIG_PCMCIA_SLOT_A and CONFIG_PCMCIA_SLOT_B configured
#endif
#define PCMCIA_SOCKETS_NO 1
#define PCMCIA_MEM_WIN_NO 4
#define PCMCIA_IO_WIN_NO 2
/* define _slot_ to be able to optimize macros */
#ifdef CONFIG_PCMCIA_SLOT_A
# define _slot_ 0
# define PCMCIA_SLOT_MSG "SLOT_A"
#else
# define _slot_ 1
# define PCMCIA_SLOT_MSG "SLOT_B"
#endif
/*
* The TQM850L hardware has two pins swapped! Grrrrgh!
*/
#ifdef CONFIG_TQM850L
#define __MY_PCMCIA_GCRX_CXRESET PCMCIA_GCRX_CXOE
#define __MY_PCMCIA_GCRX_CXOE PCMCIA_GCRX_CXRESET
#else
#define __MY_PCMCIA_GCRX_CXRESET PCMCIA_GCRX_CXRESET
#define __MY_PCMCIA_GCRX_CXOE PCMCIA_GCRX_CXOE
#endif
/* look up table for pgcrx registers */
#if 0
static u_int *pcmcia_pgcrx[2] = {
&((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pgcra,
&((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pgcrb,
};
#define PCMCIA_PGCRX(slot) (*pcmcia_pgcrx[slot])
#endif
/*
* This structure is used to address each window in the PCMCIA controller.
*
* Keep in mind that we assume that pcmcia_win_t[n+1] is mapped directly
* after pcmcia_win_t[n]...
*/
typedef struct {
ulong br;
ulong or;
} pcmcia_win_t;
/* ------------------------------------------------------------------------- */
/*
* Memory Map Information:
*
* BR0 / OR0: EPROM1 Base 0xFF000000 Size 512KB
* BR1 / OR1: EPROM2 Base 0xFF080000 Size 512KB
* BR2 / OR2: SRAM Base 0xFE200000 Size 2MB
* BR3 / OR3: SDRAM Base 0x00000000 Size 16MB (max. 64 MB used)
* BR4 / OR4: PER-8 Base 0xFE000000 Size 1MB
* BR5 / OR5: SHARC Base 0xFE400000 Size 4MB
*/
/* ------------------------------------------------------------------------- */
#endif /* CONFIG_IDE_PCMCIA */
/* Current I/O Device */
static int curr_device = -1;
/* Current offset for IDE0 / IDE1 bus access */
static ulong bus_offset[CFG_IDE_MAXBUS] = {
CFG_ATA_IDE0_OFFSET,
#ifdef CFG_ATA_IDE1_OFFSET
CFG_ATA_IDE1_OFFSET,
#endif
};
#define ATA_CURR_BASE(dev) (CFG_ATA_BASE_ADDR+bus_offset[IDE_BUS(dev)])
typedef struct ide_dev_id {
ulong size;
uchar model[40];
uchar serial_no[20];
} ide_dev_id_t;
static int ide_bus_ok[CFG_IDE_MAXBUS];
static ide_dev_id_t ide_device[CFG_IDE_MAXDEVICE];
/* ------------------------------------------------------------------------- */
#ifdef CONFIG_IDE_LED
static void ide_led (uchar led, uchar status);
#else
#define ide_led(a,b) /* dummy */
#endif
#ifdef CONFIG_IDE_RESET
static void ide_reset (void);
#else
#define ide_reset() /* dummy */
#endif
static void ide_ident (int device);
static void ide_print (int device);
static uchar ide_wait (int dev, ulong t);
static void __inline__ outb(int dev, int port, unsigned char val);
static unsigned char __inline__ inb(int dev, int port);
static void input_swap_data(int dev, ulong *sect_buf, int words);
static void input_data(int dev, ulong *sect_buf, int words);
static void output_data(int dev, ulong *sect_buf, int words);
static void trim_trail (unsigned char *str, unsigned int len);
#ifdef CONFIG_IDE_PCMCIA
static void set_pcmcia_timing (int pmode);
#else
#define set_pcmcia_timing(a) /* dummy */
#endif
/* ------------------------------------------------------------------------- */
void do_ide (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
{
switch (argc) {
case 0:
case 1:
printf ("Usage:\n%s\n", cmdtp->usage);
return;
case 2:
if (strncmp(argv[1],"res",3) == 0) {
puts ("\nReset IDE"
#ifdef CONFIG_IDE_PCMCIA
" on PCMCIA " PCMCIA_SLOT_MSG
#endif
": ");
ide_init(bd);
return;
} else if (strncmp(argv[1],"inf",3) == 0) {
int i;
putc ('\n');
for (i=0; i<CFG_IDE_MAXDEVICE; ++i) {
printf ("IDE device %d: ", i);
ide_print (i);
}
return;
} else if (strncmp(argv[1],"dev",3) == 0) {
if ((curr_device < 0) || (curr_device >= CFG_IDE_MAXDEVICE)) {
puts ("\nno IDE devices available\n");
return;
}
printf ("\nIDE device %d: ", curr_device);
ide_print (curr_device);
return;
} else if (strncmp(argv[1],"part",4) == 0) {
int dev, ok;
for (ok=0, dev=0; dev<CFG_IDE_MAXDEVICE; ++dev) {
if (ide_device[dev].size) {
++ok;
if (dev)
putc ('\n');
print_part_mac (dev);
}
}
if (!ok)
puts ("\nno IDE devices available\n");
return;
}
printf ("Usage:\n%s\n", cmdtp->usage);
return;
case 3:
if (strncmp(argv[1],"dev",3) == 0) {
int dev = (int)simple_strtoul(argv[2], NULL, 10);
printf ("\nIDE device %d: ", dev);
if (dev >= CFG_IDE_MAXDEVICE) {
puts ("unknown device\n");
return;
}
ide_print (dev);
if (ide_device[dev].size == 0) {
return;
}
curr_device = dev;
puts ("... is now current device\n");
return;
} else if (strncmp(argv[1],"part",4) == 0) {
int dev = (int)simple_strtoul(argv[2], NULL, 10);
if (ide_device[dev].size) {
print_part_mac (dev);
} else {
printf ("\nIDE device %d not available\n", dev);
}
return;
#if 0
} else if (strncmp(argv[1],"pio",4) == 0) {
int mode = (int)simple_strtoul(argv[2], NULL, 10);
if ((mode >= 0) && (mode <= IDE_MAX_PIO_MODE)) {
puts ("\nSetting ");
pio_mode = mode;
ide_init (bd);
} else {
printf ("\nInvalid PIO mode %d (0 ... %d only)\n",
mode, IDE_MAX_PIO_MODE);
}
return;
#endif
}
printf ("Usage:\n%s\n", cmdtp->usage);
return;
default:
/* at least 4 args */
if (strcmp(argv[1],"read") == 0) {
ulong addr = simple_strtoul(argv[2], NULL, 16);
ulong blk = simple_strtoul(argv[3], NULL, 16);
ulong cnt = simple_strtoul(argv[4], NULL, 16);
ulong n;
printf ("\nIDE read: device %d block # %ld, count %ld ... ",
curr_device, blk, cnt);
n = ide_read (curr_device, blk, cnt, (ulong *)addr);
printf ("%ld blocks read: %s\n",
n, (n==cnt) ? "OK" : "ERROR");
return;
} else if (strcmp(argv[1],"write") == 0) {
ulong addr = simple_strtoul(argv[2], NULL, 16);
ulong blk = simple_strtoul(argv[3], NULL, 16);
ulong cnt = simple_strtoul(argv[4], NULL, 16);
ulong n;
printf ("\nIDE write: device %d block # %ld, count %ld ... ",
curr_device, blk, cnt);
n = ide_write (curr_device, blk, cnt, (ulong *)addr);
printf ("%ld blocks written: %s\n",
n, (n==cnt) ? "OK" : "ERROR");
return;
} else {
printf ("Usage:\n%s\n", cmdtp->usage);
}
return;
}
}
void do_diskboot (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
{
char *boot_device = NULL;
char *ep;
int dev, part;
ulong cnt;
ulong addr;
disk_partition_t info;
image_header_t *hdr;
switch (argc) {
case 1:
addr = CFG_LOAD_ADDR;
boot_device = getenv ("bootdevice");
break;
case 2:
addr = simple_strtoul(argv[1], NULL, 16);
boot_device = getenv ("bootdevice");
break;
case 3:
addr = simple_strtoul(argv[1], NULL, 16);
boot_device = argv[2];
break;
default:
printf ("Usage:\n%s\n", cmdtp->usage);
return;
}
if (!boot_device) {
puts ("\n** No boot device **\n");
return;
}
dev = simple_strtoul(boot_device, &ep, 16);
if (ide_device[dev].size == 0) {
printf ("\n** Device %d not available\n", dev);
return;
}
if (*ep) {
if (*ep != ':') {
puts ("\n** Invalid boot device, use `dev[:part]' **\n");
return;
}
part = simple_strtoul(++ep, NULL, 16);
}
if (get_partition_info (dev, part, &info)) {
return;
}
if (strncmp(info.type, BOOT_PART_TYPE, sizeof(info.type)) != 0) {
printf ("\n** Invalid partition type \"%.32s\""
" (expect \"" BOOT_PART_TYPE "\")\n",
info.type);
return;
}
printf ("\nLoading from IDE device %d, partition %d: "
"Name: %.32s Type: %.32s\n",
dev, part, info.name, info.type);
PRINTF ("First Block: %ld, # of blocks: %ld, Block Size: %ld\n",
info.start, info.size, info.blksz);
if (ide_read (dev, info.start, 1, (ulong *)addr) != 1) {
printf ("** Read error on %d:%d\n", dev, part);
return;
}
hdr = (image_header_t *)addr;
if (hdr->ih_magic == IH_MAGIC) {
print_image_hdr (hdr);
cnt = (hdr->ih_size + sizeof(image_header_t));
cnt += info.blksz - 1;
cnt /= info.blksz;
cnt -= 1;
} else {
cnt = info.size - 1;
}
if (ide_read (dev, info.start+1, cnt,
(ulong *)(addr+info.blksz)) != cnt) {
printf ("** Read error on %d:%d\n", dev, part);
return;
}
/* Loading ok, update default load address */
load_addr = addr;
/* Check if we should attempt an auto-start */
if (((ep = getenv("autostart")) != NULL) && (strcmp(ep,"yes") == 0)) {
char *local_args[2];
extern void do_bootm (cmd_tbl_t *, bd_t *, int, int, char *[]);
local_args[0] = argv[0];
local_args[1] = NULL;
printf ("Automatic boot of image at addr 0x%08lX ...\n", addr);
do_bootm (cmdtp, bd, 0, 1, local_args);
}
}
/* ------------------------------------------------------------------------- */
void ide_init (bd_t *bd)
{
#ifdef CONFIG_IDE_PCMCIA
volatile immap_t *immr = (immap_t *)CFG_IMMR;
volatile pcmconf8xx_t *pcmp = &(immr->im_pcmcia);
#endif
unsigned char c;
int i, bus;
/* Initialize PIO timing tables */
for (i=0; i <= IDE_MAX_PIO_MODE; ++i) {
pio_config_clk[i].t_setup = PCMCIA_MK_CLKS(pio_config_ns[i].t_setup,
bd->bi_busfreq);
pio_config_clk[i].t_length = PCMCIA_MK_CLKS(pio_config_ns[i].t_length,
bd->bi_busfreq);
pio_config_clk[i].t_hold = PCMCIA_MK_CLKS(pio_config_ns[i].t_hold,
bd->bi_busfreq);
PRINTF ("PIO Mode %d: setup=%2d ns/%d clk"
" len=%3d ns/%d clk"
" hold=%2d ns/%d clk\n",
i,
pio_config_ns[i].t_setup, pio_config_clk[i].t_setup,
pio_config_ns[i].t_length, pio_config_clk[i].t_length,
pio_config_ns[i].t_hold, pio_config_clk[i].t_hold);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -