Subject: Boot ROMs
To: None <port-bebox@netbsd.org>
From: Scott Lindsey <wombat@gobe.com>
List: port-bebox
Date: 02/03/2000 01:39:43
--============_-1262551711==_============
Content-Type: text/plain; charset="us-ascii"
At the behest of someone on the be-linux mailing list, I got in touch with
Dominic Giampaolo at Be regarding the boot ROM on the BeBox. He had this
to say:
>Actually this stuff is kind of lost in the mists of time (i.e. Bob
>Herold is the one who really understood this stuff and he's long
>gone).
>
>Here's what I remember... there are two parts to the boot-rom. One
>part, the "nub", is not writable and about all it knows how to do is
>to read data off the floppy and write it to the writable part of the
>flash. The writable part is basically a copy of the bootmain.image
>that is loaded into memory by the nub and executed.
>
>A lot of this stuff is in our build process but I don't really have
>time to extricate it all. It's a pretty complicated build process
>and I really don't remember all the details. The only other tidbit
>I can find quickly is that the nub tries to load a pef image out of
>the boot image and put it at 0x00300000, then it will jump to the
>entry point for that pef image (which you can set with the
>metrowerks linker). That code is running on a very raw machine
>(no mmu, in supervisor mode, etc). The problem will of course
>be generating a pef image but you can probably do a two-stage sort of
>thing where you have a simple pef image that then loads an elf linux
>kernel or something.... the memory map of the bebox is all public so
>it shouldn't be too hard to figure out how to read the flash device.
>Actually, what the heck. I've attached the flash driver so you can
>use it if you need.
--============_-1262551711==_============
Content-Type: text/plain; name="fl_amd.h"; charset="us-ascii"
Content-Disposition: attachment; filename="fl_amd.h"
/* ++++++++++
FILE: fl_amd.h
REVS: $Revision: 1.2 $
NAME: herold
DATE: Feb 3, 1992
Copyright (c) 1992-96 by Be
Incorporated. All Rights Reserved.
Definitions for programming the
Advanced Micor Devices 29F010
and 29F040 flash roms.
For more
info, see the AMD 'Flash Memory Products' databook.
+++++ */
#ifndef
_FL_AMD_H
#define _FL_AMD_H
/* identification */
#define
FL_MANUFACTURER_amd 0x01
#define
FL_DEVICE_amd29f010 0x20
#define
FL_DEVICE_amd29f040 0xa4
/* sizes */
#define
FL_BLOCK_SIZE_amd29f010 0x4000
#define
FL_BLOCK_SIZE_amd29f040 0x10000
/* all commands start with
2 write operations to particular addresses */
#define
FLCMD_PREFIX1_ADDR_amd 0x5555
#define FLCMD_PREFIX1_DATA_amd
0xAA
#define FLCMD_PREFIX2_ADDR_amd 0x2AAA
#define
FLCMD_PREFIX2_DATA_amd 0x55
/* command codes for operating on a single
part */
#define FLCMD_READ_amd 0xF0
#define
FLCMD_AUTOSELECT_amd 0x90
#define FLCMD_ERASESETUP_amd
0x80
#define FLCMD_ERASECONFIRM_amd 0x30
#define
FLCMD_PROGRAMSETUP_amd 0xA0
/* status bits (single part) */
#define
FLST_DATA_amd 0x80 /* data polling */
#define
FLST_TOGGLE_amd 0x40 /* toggles while busy
*/
#define FLST_TIMEOUT_amd 0x20 /* pgm/erase
timeout */
#define FLST_SEQ_amd 0x10 /* if
timeout, 1=erase 0=pgm */
#define FLST_SECTOR_amd
0x08 /* 0=not yet, 1=erasing */
#endif
--============_-1262551711==_============
Content-Type: text/plain; name="flash.c"; charset="us-ascii"
Content-Disposition: attachment; filename="flash.c"
/* ++++++++++
FILE: joe/flash.c
REVS: $Revision: 1.26 $
NAME: herold
DATE: Tue Apr 18 18:02:17 PDT 1995
Copyright
(c) 1995-97 by Be Incorporated. All Rights Reserved.
+++++ */
#include
<OS.h>
#include <KernelExport.h>
#include <PCI.h>
#include
<Drivers.h>
#include <drivers_priv.h>
#include <flash_driver.h>
#include
<cpu.h>
#include <fl_amd.h>
#include <vm.h>
#include <eagle.h>
#undef
ANALYZE
#include <analyser.h>
#define ddprintf
/* -----
private
definitions
----- */
typedef struct {
ulong block_size;
ulong
num_blocks;
uchar manufacturer_code;
uchar
device_code;
} flash_type;
typedef struct {
area_id aid;
/* id of flash area */
int config; /* eagle
config reg contents */
} enable_state;
#define FL_ADDR(offset) ((vuchar
*)(flash + (offset))))
/* ----------
private globals
----- */
static
sem_id mapping_sem = -1; /* mutex for mapping */
static
vchar *flash; /* -> mapped flash
*/
static area_id flash_area = -1; /* area that maps
the flash */
static pci_info eagle; /*
pci info for MPC105 */
static flash_type types[2] = {
{
FL_BLOCK_SIZE_amd29f010, 8, FL_MANUFACTURER_amd, FL_DEVICE_amd29f010 },
{ FL_BLOCK_SIZE_amd29f040, 8, FL_MANUFACTURER_amd,
FL_DEVICE_amd29f040 }
};
/* ----------
inp - read a byte from
flash
----- */
static vuchar
inp (int offset)
{
uchar val;
val
= * (vuchar *) (flash + offset);
__eieio();
return
val;
}
/* ----------
outp - write a byte to flash
-----
*/
static void
outp (int offset, uchar val)
{
* (vuchar *) (flash +
offset) = val;
__eieio();
}
/* ----------
find_eagle - looks for the
Eagle chip
----- */
static bool
find_eagle (void)
{
int i;
for
(i = 0; ; i++) {
if (get_nth_pci_info (i, &eagle) !=
B_NO_ERROR)
break;
if
(eagle.class_base == PCI_bridge &&
eagle.class_sub ==
PCI_host &&
eagle.vendor_id == 0x1057 && /* motorola */
eagle.device_id == 0x0001) /* MPC105 */
return TRUE;
}
return FALSE;
}
/* ----------
init_hardware - check for Eagle chip, fail if not there
-----
*/
status_t
init_hardware (void)
{
return find_eagle() ? B_NO_ERROR :
B_ERROR;
}
/* ----------
init_driver - check for Eagle chip, fail if
not there
----- */
status_t
init_driver (void)
{
if (!find_eagle())
return B_ERROR;
mapping_sem = create_sem
(1, "flash driver open");
return (mapping_sem < 0) ? B_ERROR :
B_NO_ERROR;
}
/* ----------
uninit_driver - clean up resources used by
driver
----- */
void
uninit_driver (void)
{
#if !BOOT
if
(flash_area >= 0)
delete_area (flash_area);
mapping_sem
= -1;
#endif
}
/* ----------
map_flash - make flash rom
accessible by mapping it into virtual space
----- */
static bool
map_flash
(bool writing)
{
#if BOOT
flash = (vchar *) HOST_FLASH;
return TRUE;
#else
acquire_sem (mapping_sem);
if
(flash_area < 0)
flash_area = map_physical_memory (
"flash",
(void *) HOST_FLASH,
512*1024,
B_ANY_KERNEL_BLOCK_ADDRESS,
writing ?
B_WRITE_AREA + B_READ_AREA : B_READ_AREA,
(void**)&flash
);
release_sem (mapping_sem);
return (flash_area < 0) ? FALSE : TRUE;
#endif
}
/*
----------
enable_flash_writes
----- */
static int
enable_flash_writes
(enable_state *s)
{
/* make the flash writeable */
#ifdef
FLASH_UPDATER
disable_dcache();
#endif
/* set up Eagle to
enable flash updates */
s->config = read_pci_config (eagle.bus,
eagle.device, eagle.function, EGL_config_1, 4);
write_pci_config
(eagle.bus, eagle.device, eagle.function, EGL_config_1, 4, s->config |
0x1000);
return B_NO_ERROR;
}
/* ----------
disable_flash_writes
----- */
static void
disable_flash_writes
(enable_state *s)
{
/* restore the flash to read only */
write_pci_config (eagle.bus, eagle.device, eagle.function,
EGL_config_1, 4, s->config);
#ifdef FLASH_UPDATER
inval_lock_enable_dcache();
#endif
}
/* ----------
write_cmd writes the passed command, along with the common
command prefix.
----- */
static void
write_cmd (char cmd)
{
outp (FLCMD_PREFIX1_ADDR_amd, FLCMD_PREFIX1_DATA_amd);
outp
(FLCMD_PREFIX2_ADDR_amd, FLCMD_PREFIX2_DATA_amd);
outp
(FLCMD_PREFIX1_ADDR_amd, cmd);
}
/* ----------
reset_amd returns
the roms to read mode.
----- */
static void
reset_amd (void)
{
write_cmd (FLCMD_READ_amd);
}
/* ----------
is_sector_protected
returns true if sector is write-protected.
----- */
static
status_t
is_sector_protected (flash_type *f, long sector)
{
enable_state s;
int i;
uchar prot;
int
err;
if (sector < 0 || sector > 8)
return B_ERROR;
err = enable_flash_writes (&s);
if (err != B_NO_ERROR)
return B_ERROR;
write_cmd (FLCMD_AUTOSELECT_amd);
prot = inp ((sector * f->block_size) + 2); /* addr 2:
protection */
reset_amd();
disable_flash_writes (&s);
return prot
& 0x01;
}
/* ----------
get_flash_type figures out what kind of
flash is installed.
----- */
static flash_type *
get_flash_type (void)
{
enable_state s;
int i;
uchar mfg, dev;
int
err;
/* ---
rwh 4/1/97
There is some sort
of cache coherency problem here. If the
dprintf lines w/
"fix#1" are removed, this routines fails on a
133 603e. This
should be investigated ASAP. In the meantime,
the lines stay.
--- */
err = enable_flash_writes (&s);
dprintf
("get_flash_type: fix #1\n");
if (err != B_NO_ERROR)
return
NULL;
write_cmd (FLCMD_AUTOSELECT_amd);
mfg = inp (0); /* addr 0:
manufacturer code */
dev = inp (1); /* addr 1: device code */
reset_amd();
dprintf ("get_flash_type: fix #1\n");
disable_flash_writes (&s);
/* search supported devices to get
device type */
for (i = 0; i < sizeof (types) / sizeof (types[0]);
i++)
if ((types[i].manufacturer_code) == mfg &&
(types[i].device_code == dev))
return types + i;
return NULL;
}
/* -----
poll_status polls the device until
the operation is complete.
The 'data polling' and 'operation timeout'
bits are checked
until the data bits equals the passed value
(operation complete)
or the operation times out.
----- */
static
int
poll_status (ulong addr, uchar value)
{
uchar status;
for
(;;) {
status = inp (addr);
if ((status &
FLST_DATA_amd) == (value & FLST_DATA_amd))
break;
if (status & FLST_TIMEOUT_amd)
return B_ERROR;
}
return B_NO_ERROR;
}
/* ----------
erase_amd erases
the flash blocks intersecting with the passed
offset/size.
It
is assumed that the offset is flash-block aligned, and that the
size is a multiple of the flash block size
----- */
static
int
erase_amd (ulong addr, ulong size, ulong block_size)
{
int
err;
cpu_status ps;
ulong save_addr;
ulong save_size;
int retry;
const int max_retry = 50;
ddprintf
("erase_amd: addr=%.8x size=%.8x block_size=%.8x\n", addr, size,
block_size);
save_addr = addr;
save_size = size;
for (retry
= 0; retry < max_retry; retry++) {
addr = save_addr;
size = save_size;
ps = disable_interrupts ();
write_cmd (FLCMD_ERASESETUP_amd);
outp
(FLCMD_PREFIX1_ADDR_amd, FLCMD_PREFIX1_DATA_amd);
outp
(FLCMD_PREFIX2_ADDR_amd, FLCMD_PREFIX2_DATA_amd);
/* write
erase cmd for each sector. These must all happen within
100 uSec of each other, so we disable interrupts while doing it */
while (size > 0) {
outp (addr,
FLCMD_ERASECONFIRM_amd);
addr += block_size;
size -= block_size;
}
restore_interrupts (ps);
/* wait till erase complete
*/
if ((err = poll_status (save_addr, 0x80)) == B_NO_ERROR)
break;
}
if (err != B_NO_ERROR)
dprintf("erase_amd: erase failed\n");
reset_amd ();
/* back to read mode */
return err;
}
/* ----------
write_amd writes stuff to the flash rom.
----- */
static
int
write_amd (uchar *data, ulong addr, ulong size)
{
const int
max_retry = 50;
int retry;
int
err;
ddprintf ("write_amd: data=%.8x addr=%.8x
size=%.8x\n", data, addr, size);
while (size) {
for
(retry = 0; retry < max_retry; retry++) {
write_cmd
(FLCMD_PROGRAMSETUP_amd); /* setup... */
outp (addr, *data);
/* program! */
err = poll_status (addr, *data);
/* check */
if (err ==
B_NO_ERROR)
break;
}
if
(err != B_NO_ERROR) {
dprintf ("fl_amd, write_amd: error
writing flash at offset %.8x\n", addr);
break;
}
data++;
addr++;
size--;
}
reset_amd (); /* back to read mode */
return err;
}
/*
----------
flash_open
----- */
static status_t
flash_open (const char
*name, uint32 flags, void **cookie)
{
bool writing;
writing = (flags &
(O_RDWR | O_WRONLY)) ? TRUE : FALSE;
#if 0
/* O_EXCLOPEN is a no-op.
*/
/* if writing, better be exclusive */
if (writing && !(flags &
O_EXCLOPEN))
return B_PERMISSION_DENIED;
#endif
if
(!find_eagle())
return B_ERROR;
if
(!map_flash(writing))
return B_ERROR;
if ((*cookie =
get_flash_type()) == NULL) {
dprintf("flash_open: could not
determine device type!\n");
return B_ERROR;
}
return B_NO_ERROR;
}
/* ----------
flash_close
-----
*/
static status_t
flash_close (void *cookie)
{
return
B_NO_ERROR;
}
/* ----------
flash_free
----- */
static
status_t
flash_free (void *cookie)
{
#if !BOOT
if (flash_area)
delete_area (flash_area);
#endif
return
B_NO_ERROR;
}
/* ----------
flash_control
----- */
static
status_t
flash_control(void *_f, uint32 msg, void *buf, size_t len)
{
flash_type *f = (flash_type *) _f;
switch (msg) {
case
B_GET_DEVICE_SIZE:
*(size_t *)buf = f->block_size *
f->num_blocks;
return B_NO_ERROR;
case
B_IS_FLASH_SECTOR_PROTECTED:
*(long *)buf = is_sector_protected
(f, * (long *) buf);
return B_NO_ERROR;
case
B_GET_FLASH_SECTOR_SIZE:
*(long *)buf = f->block_size;
return B_NO_ERROR;
}
return B_ERROR;
}
/* ----------
flash_read
----- */
static status_t
flash_read (void *_f, off_t
pos, void *buf, size_t *len)
{
flash_type *f = (flash_type *) _f;
size_t count;
count = *len;
if ((count + pos) >
(f->block_size * f->num_blocks)) {
dprintf ("flash_write:
attempt to write beyond end\n");
return B_ERROR;
}
memcpy (buf, flash + pos, count);
return 0;
}
/*
----------
flash_write
----- */
static status_t
flash_write (void
*_f, off_t pos, const void *buf, size_t *len)
{
flash_type *f =
(flash_type *) _f;
size_t count;
enable_state s;
int err;
ulong
blksize;
uchar *mbuf = NULL;
uchar
*pr_buf; /* -> data to be programmed this
time */
ulong src_count; /* # source
bytes being programmed */
ulong pr_dev_count; /*
# device bytes being programmed */
ulong pr_pos;
/* device positon to start erase/pgm */
count =
*len;
ddprintf ("flash_write: buf=%.8x count=%.8x pos=%.8x\n", buf,
count, pos);
if ((count + pos) > (f->block_size * f->num_blocks)) {
dprintf ("flash_write: attempt to write beyond end\n");
return B_ERROR;
}
/* get a buffer for
non-block-aligned writes */
blksize = f->block_size;
if
((pos % blksize) || (count % blksize))
if (!(mbuf = (uchar
*) malloc (blksize)))
return B_ERROR;
err = enable_flash_writes (&s);
if (err != B_NO_ERROR)
goto exit;
while (count > 0) {
/* if not starting
and ending on block boundary, we must merge
with what is
already there */
if ((pos % blksize) || (count < blksize))
{
pr_pos = (pos/blksize) * blksize;
memcpy (mbuf, flash + pr_pos, blksize);
pr_dev_count = blksize;
src_count = blksize
- (pos % blksize);
if (count < src_count)
src_count = count;
memcpy (mbuf + (pos
% blksize), buf, src_count);
pr_buf = mbuf;
}
else {
pr_pos = pos;
pr_dev_count =
src_count = (count / blksize) * blksize;
pr_buf =
(uchar *) buf;
}
if ((err = erase_amd(pr_pos,
pr_dev_count, blksize)) == B_NO_ERROR)
err = write_amd
(pr_buf, pr_pos, pr_dev_count);
if (err !=
B_NO_ERROR)
break;
pos += src_count;
buf = (char *) buf + src_count;
count -=
src_count;
}
disable_flash_writes (&s);
exit:
if
(mbuf)
free (mbuf);
return err;
}
/* ----------
driver-related structures
----- */
static device_hooks
flash_device = {
flash_open, /* -> open entry point */
flash_close, /* -> close entry point */
flash_free,
/* -> free cookie entry point */
flash_control, /* ->
control entry point */
flash_read, /* -> read entry point */
flash_write /* -> write entry point */
};
static const
char *flash_name[] = { "flash", NULL };
const char
**
publish_devices()
{
return flash_name;
}
device_hooks
*
find_device(const char *name)
{
return &flash_device;
}
fixed_driver_info flash_driver_info = {
"flash",
B_CUR_DRIVER
_API_VERSION,
NULL,
&publish_devices,
&find_device,
NULL,
NULL
};
--============_-1262551711==_============
Content-Type: text/plain; charset="us-ascii"
--
Scott Lindsey <wombat@gobe.com>
--============_-1262551711==_============--