Moved from freebios
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@862 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
This commit is contained in:
parent
fd958cea68
commit
0322115932
|
@ -0,0 +1,83 @@
|
||||||
|
#include <ip_checksum.h>
|
||||||
|
#include <boot/elf.h>
|
||||||
|
#include <boot/elf_boot.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <printk.h>
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef CMD_LINE
|
||||||
|
#define CMD_LINE ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define UPSZ(X) ((sizeof(X) + 3) &~3)
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
Elf_Bhdr hdr;
|
||||||
|
Elf_Nhdr ft_hdr;
|
||||||
|
unsigned char ft_desc[UPSZ(FIRMWARE_TYPE)];
|
||||||
|
Elf_Nhdr bl_hdr;
|
||||||
|
unsigned char bl_desc[UPSZ(BOOTLOADER)];
|
||||||
|
Elf_Nhdr blv_hdr;
|
||||||
|
unsigned char blv_desc[UPSZ(BOOTLOADER_VERSION)];
|
||||||
|
Elf_Nhdr cmd_hdr;
|
||||||
|
unsigned char cmd_desc[UPSZ(CMD_LINE)];
|
||||||
|
} elf_boot_notes = {
|
||||||
|
.hdr = {
|
||||||
|
.b_signature = 0x0E1FB007,
|
||||||
|
.b_size = sizeof(elf_boot_notes),
|
||||||
|
.b_checksum = 0,
|
||||||
|
.b_records = 4,
|
||||||
|
},
|
||||||
|
.ft_hdr = {
|
||||||
|
.n_namesz = 0,
|
||||||
|
.n_descsz = sizeof(FIRMWARE_TYPE),
|
||||||
|
.n_type = EBN_FIRMWARE_TYPE,
|
||||||
|
},
|
||||||
|
.ft_desc = FIRMWARE_TYPE,
|
||||||
|
.bl_hdr = {
|
||||||
|
.n_namesz = 0,
|
||||||
|
.n_descsz = sizeof(BOOTLOADER),
|
||||||
|
.n_type = EBN_BOOTLOADER_NAME,
|
||||||
|
},
|
||||||
|
.bl_desc = BOOTLOADER,
|
||||||
|
.blv_hdr = {
|
||||||
|
.n_namesz = 0,
|
||||||
|
.n_descsz = sizeof(BOOTLOADER_VERSION),
|
||||||
|
.n_type = EBN_BOOTLOADER_VERSION,
|
||||||
|
},
|
||||||
|
.blv_desc = BOOTLOADER_VERSION,
|
||||||
|
.cmd_hdr = {
|
||||||
|
.n_namesz = 0,
|
||||||
|
.n_descsz = sizeof(CMD_LINE),
|
||||||
|
.n_type = EBN_COMMAND_LINE,
|
||||||
|
},
|
||||||
|
.cmd_desc = CMD_LINE,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int elf_check_arch(Elf_ehdr *ehdr)
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
(ehdr->e_machine == EM_PPC) &&
|
||||||
|
(ehdr->e_ident[EI_CLASS] == ELFCLASS32) &&
|
||||||
|
(ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void jmp_to_elf_entry(void *entry, unsigned long buffer)
|
||||||
|
{
|
||||||
|
void (*kernel_entry)(void);
|
||||||
|
kernel_entry = entry;
|
||||||
|
|
||||||
|
/* On ppc we don't currently support loading over LinuxBIOS.
|
||||||
|
* So ignore the buffer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Jump to kernel */
|
||||||
|
kernel_entry();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,285 @@
|
||||||
|
#include <mem.h>
|
||||||
|
#include <ip_checksum.h>
|
||||||
|
#include <boot/linuxbios_tables.h>
|
||||||
|
#include <boot/linuxbios_table.h>
|
||||||
|
#include <printk.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <version.h>
|
||||||
|
|
||||||
|
|
||||||
|
struct lb_header *lb_table_init(unsigned long addr)
|
||||||
|
{
|
||||||
|
struct lb_header *header;
|
||||||
|
|
||||||
|
/* 16 byte align the address */
|
||||||
|
addr += 15;
|
||||||
|
addr &= ~15;
|
||||||
|
|
||||||
|
header = (void *)addr;
|
||||||
|
header->signature[0] = 'L';
|
||||||
|
header->signature[1] = 'B';
|
||||||
|
header->signature[2] = 'I';
|
||||||
|
header->signature[3] = 'O';
|
||||||
|
header->header_bytes = sizeof(*header);
|
||||||
|
header->header_checksum = 0;
|
||||||
|
header->table_bytes = 0;
|
||||||
|
header->table_checksum = 0;
|
||||||
|
header->table_entries = 0;
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lb_record *lb_first_record(struct lb_header *header)
|
||||||
|
{
|
||||||
|
struct lb_record *rec;
|
||||||
|
rec = (void *)(((char *)header) + sizeof(*header));
|
||||||
|
return rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lb_record *lb_last_record(struct lb_header *header)
|
||||||
|
{
|
||||||
|
struct lb_record *rec;
|
||||||
|
rec = (void *)(((char *)header) + sizeof(*header) + header->table_bytes);
|
||||||
|
return rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lb_record *lb_next_record(struct lb_record *rec)
|
||||||
|
{
|
||||||
|
rec = (void *)(((char *)rec) + rec->size);
|
||||||
|
return rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lb_record *lb_new_record(struct lb_header *header)
|
||||||
|
{
|
||||||
|
struct lb_record *rec;
|
||||||
|
rec = lb_last_record(header);
|
||||||
|
if (header->table_entries) {
|
||||||
|
header->table_bytes += rec->size;
|
||||||
|
}
|
||||||
|
rec = lb_last_record(header);
|
||||||
|
header->table_entries++;
|
||||||
|
rec->tag = LB_TAG_UNUSED;
|
||||||
|
rec->size = sizeof(*rec);
|
||||||
|
return rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct lb_memory *lb_memory(struct lb_header *header)
|
||||||
|
{
|
||||||
|
struct lb_record *rec;
|
||||||
|
struct lb_memory *mem;
|
||||||
|
rec = lb_new_record(header);
|
||||||
|
mem = (struct lb_memory *)rec;
|
||||||
|
mem->tag = LB_TAG_MEMORY;
|
||||||
|
mem->size = sizeof(*mem);
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lb_mainboard *lb_mainboard(struct lb_header *header)
|
||||||
|
{
|
||||||
|
struct lb_record *rec;
|
||||||
|
struct lb_mainboard *mainboard;
|
||||||
|
rec = lb_new_record(header);
|
||||||
|
mainboard = (struct lb_mainboard *)rec;
|
||||||
|
mainboard->tag = LB_TAG_MAINBOARD;
|
||||||
|
|
||||||
|
mainboard->size = (sizeof(*mainboard) +
|
||||||
|
strlen(mainboard_vendor) + 1 +
|
||||||
|
strlen(mainboard_part_number) + 1 +
|
||||||
|
3) & ~3;
|
||||||
|
|
||||||
|
mainboard->vendor_idx = 0;
|
||||||
|
mainboard->part_number_idx = strlen(mainboard_vendor) + 1;
|
||||||
|
|
||||||
|
memcpy(mainboard->strings + mainboard->vendor_idx,
|
||||||
|
mainboard_vendor, strlen(mainboard_vendor) + 1);
|
||||||
|
memcpy(mainboard->strings + mainboard->part_number_idx,
|
||||||
|
mainboard_part_number, strlen(mainboard_part_number) + 1);
|
||||||
|
|
||||||
|
return mainboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lb_strings(struct lb_header *header)
|
||||||
|
{
|
||||||
|
static const struct {
|
||||||
|
uint32_t tag;
|
||||||
|
const uint8_t *string;
|
||||||
|
} strings[] = {
|
||||||
|
{ LB_TAG_VERSION, linuxbios_version, },
|
||||||
|
{ LB_TAG_EXTRA_VERSION, linuxbios_extra_version, },
|
||||||
|
{ LB_TAG_BUILD, linuxbios_build, },
|
||||||
|
{ LB_TAG_COMPILE_TIME, linuxbios_compile_time, },
|
||||||
|
{ LB_TAG_COMPILE_BY, linuxbios_compile_by, },
|
||||||
|
{ LB_TAG_COMPILE_HOST, linuxbios_compile_host, },
|
||||||
|
{ LB_TAG_COMPILE_DOMAIN, linuxbios_compile_domain, },
|
||||||
|
{ LB_TAG_COMPILER, linuxbios_compiler, },
|
||||||
|
{ LB_TAG_LINKER, linuxbios_linker, },
|
||||||
|
{ LB_TAG_ASSEMBLER, linuxbios_assembler, },
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < sizeof(strings)/sizeof(strings[0]); i++) {
|
||||||
|
struct lb_record *rec;
|
||||||
|
struct lb_string *str;
|
||||||
|
size_t len;
|
||||||
|
rec = lb_new_record(header);
|
||||||
|
str = (struct lb_string *)rec;
|
||||||
|
len = strlen(strings[i].string);
|
||||||
|
str->tag = strings[i].tag;
|
||||||
|
str->size = (sizeof(*rec) + len + 1 + 3) & ~3;
|
||||||
|
memcpy(str->string, strings[i].string, len+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Some version of gcc have problems with 64 bit types so
|
||||||
|
* take an unsigned long instead of a uint64_t for now.
|
||||||
|
*/
|
||||||
|
void lb_memory_range(struct lb_memory *mem,
|
||||||
|
uint32_t type, unsigned long start, unsigned long size)
|
||||||
|
{
|
||||||
|
int entries;
|
||||||
|
entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
|
||||||
|
mem->map[entries].start = start;
|
||||||
|
mem->map[entries].size = size;
|
||||||
|
mem->map[entries].type = type;
|
||||||
|
mem->size += sizeof(mem->map[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lb_memory_rangek(struct lb_memory *mem,
|
||||||
|
uint32_t type, unsigned long startk, unsigned long endk)
|
||||||
|
{
|
||||||
|
int entries;
|
||||||
|
entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
|
||||||
|
mem->map[entries].start = startk;
|
||||||
|
mem->map[entries].start <<= 10;
|
||||||
|
mem->map[entries].size = endk - startk;
|
||||||
|
mem->map[entries].size <<= 10;
|
||||||
|
mem->map[entries].type = type;
|
||||||
|
mem->size += sizeof(mem->map[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lb_reserve_table_memory(struct lb_header *head)
|
||||||
|
{
|
||||||
|
struct lb_record *last_rec;
|
||||||
|
struct lb_memory *mem;
|
||||||
|
uint64_t start;
|
||||||
|
uint64_t end;
|
||||||
|
int i, entries;
|
||||||
|
|
||||||
|
last_rec = lb_last_record(head);
|
||||||
|
mem = get_lb_mem();
|
||||||
|
start = (unsigned long)head;
|
||||||
|
end = (unsigned long)last_rec;
|
||||||
|
entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
|
||||||
|
/* Resize the right two memory areas so this table is in
|
||||||
|
* a reserved area of memory. Everything has been carefully
|
||||||
|
* setup so that is all we need to do.
|
||||||
|
*/
|
||||||
|
for(i = 0; i < entries; i++ ) {
|
||||||
|
uint64_t map_start = mem->map[i].start;
|
||||||
|
uint64_t map_end = map_start + mem->map[i].size;
|
||||||
|
/* Does this area need to be expanded? */
|
||||||
|
if (map_end == start) {
|
||||||
|
mem->map[i].size = end - map_start;
|
||||||
|
}
|
||||||
|
/* Does this area need to be contracted? */
|
||||||
|
else if (map_start == start) {
|
||||||
|
mem->map[i].start = end;
|
||||||
|
mem->map[i].size = map_end - end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned long lb_table_fini(struct lb_header *head)
|
||||||
|
{
|
||||||
|
struct lb_record *rec, *first_rec;
|
||||||
|
rec = lb_last_record(head);
|
||||||
|
if (head->table_entries) {
|
||||||
|
head->table_bytes += rec->size;
|
||||||
|
}
|
||||||
|
lb_reserve_table_memory(head);
|
||||||
|
first_rec = lb_first_record(head);
|
||||||
|
head->table_checksum = compute_ip_checksum(first_rec, head->table_bytes);
|
||||||
|
head->header_checksum = 0;
|
||||||
|
head->header_checksum = compute_ip_checksum(head, sizeof(*head));
|
||||||
|
printk_debug("Wrote linuxbios table at: %p - %p checksum %lx\n",
|
||||||
|
head, rec, head->table_checksum);
|
||||||
|
return (unsigned long)rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Routines to extract part so the linuxBIOS table or
|
||||||
|
* information from the linuxBIOS table after we have written it.
|
||||||
|
* Currently get_lb_mem relies on a global we can change the
|
||||||
|
* implementaiton.
|
||||||
|
*/
|
||||||
|
static struct lb_memory *mem_ranges = 0;
|
||||||
|
struct lb_memory *get_lb_mem(void)
|
||||||
|
{
|
||||||
|
return mem_ranges;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long write_linuxbios_table(
|
||||||
|
unsigned long *processor_map,
|
||||||
|
struct mem_range *ram,
|
||||||
|
unsigned long low_table_start, unsigned long low_table_end,
|
||||||
|
unsigned long rom_table_startk, unsigned long rom_table_endk)
|
||||||
|
{
|
||||||
|
unsigned long table_size;
|
||||||
|
struct mem_range *ramp;
|
||||||
|
struct lb_header *head;
|
||||||
|
struct lb_memory *mem;
|
||||||
|
#if HAVE_OPTION_TABLE == 1
|
||||||
|
struct lb_record *rec_dest, *rec_src;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
head = lb_table_init(low_table_end);
|
||||||
|
low_table_end = (unsigned long)head;
|
||||||
|
#if HAVE_OPTION_TABLE == 1
|
||||||
|
/* Write the option config table... */
|
||||||
|
rec_dest = lb_new_record(head);
|
||||||
|
rec_src = (struct lb_record *)&option_table;
|
||||||
|
memcpy(rec_dest, rec_src, rec_src->size);
|
||||||
|
#endif
|
||||||
|
mem = lb_memory(head);
|
||||||
|
mem_ranges = mem;
|
||||||
|
/* I assume there is always ram at address 0 */
|
||||||
|
/* Reserve our tables in low memory */
|
||||||
|
table_size = (low_table_end - low_table_start);
|
||||||
|
lb_memory_range(mem, LB_MEM_TABLE, 0, table_size);
|
||||||
|
lb_memory_range(mem, LB_MEM_RAM, table_size, (ram[0].sizek << 10) - table_size);
|
||||||
|
/* Reserving pci memory mapped space will keep the kernel from booting seeing
|
||||||
|
* any pci resources.
|
||||||
|
*/
|
||||||
|
for(ramp = &ram[1]; ramp->sizek; ramp++) {
|
||||||
|
unsigned long startk, endk;
|
||||||
|
startk = ramp->basek;
|
||||||
|
endk = startk + ramp->sizek;
|
||||||
|
if ((startk < rom_table_startk) && (endk > rom_table_startk)) {
|
||||||
|
lb_memory_rangek(mem, LB_MEM_RAM, startk, rom_table_startk);
|
||||||
|
startk = rom_table_startk;
|
||||||
|
}
|
||||||
|
if ((startk == rom_table_startk) && (endk > startk)) {
|
||||||
|
unsigned long tend;
|
||||||
|
tend = rom_table_endk;
|
||||||
|
if (tend > endk) {
|
||||||
|
tend = endk;
|
||||||
|
}
|
||||||
|
lb_memory_rangek(mem, LB_MEM_TABLE, rom_table_startk, tend);
|
||||||
|
startk = tend;
|
||||||
|
}
|
||||||
|
if (endk > startk) {
|
||||||
|
lb_memory_rangek(mem, LB_MEM_RAM, startk, endk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Record our motheboard */
|
||||||
|
lb_mainboard(head);
|
||||||
|
/* Record our various random string information */
|
||||||
|
lb_strings(head);
|
||||||
|
|
||||||
|
low_table_end = lb_table_fini(head);
|
||||||
|
|
||||||
|
/* Remember where my valid memory ranges are */
|
||||||
|
return low_table_end;
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef ASM_I386_BOOT_H
|
||||||
|
#define ASM_I386_BOOT_H
|
||||||
|
|
||||||
|
#define ELF_CLASS ELFCLASS32
|
||||||
|
#define ELF_DATA ELFDATA2MSB
|
||||||
|
#define ELF_ARCH EM_PPC
|
||||||
|
|
||||||
|
#endif /* ASM_I386_BOOT_H */
|
|
@ -0,0 +1,192 @@
|
||||||
|
/*
|
||||||
|
* BK Id: SCCS/s.io.h 1.14 10/16/01 15:58:42 trini
|
||||||
|
*/
|
||||||
|
#ifndef _PPC_IO_H
|
||||||
|
#define _PPC_IO_H
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
#define SIO_CONFIG_RA 0x398
|
||||||
|
#define SIO_CONFIG_RD 0x399
|
||||||
|
|
||||||
|
#define SLOW_DOWN_IO
|
||||||
|
|
||||||
|
#define PMAC_ISA_MEM_BASE 0
|
||||||
|
#define PMAC_PCI_DRAM_OFFSET 0
|
||||||
|
#define CHRP_ISA_IO_BASE 0xf8000000
|
||||||
|
#define CHRP_ISA_MEM_BASE 0xf7000000
|
||||||
|
#define CHRP_PCI_DRAM_OFFSET 0
|
||||||
|
#define PREP_ISA_IO_BASE 0x80000000
|
||||||
|
#define PREP_ISA_MEM_BASE 0xc0000000
|
||||||
|
#define PREP_PCI_DRAM_OFFSET 0x80000000
|
||||||
|
|
||||||
|
#define _IO_BASE 0xfe000000
|
||||||
|
|
||||||
|
#define readb(addr) in_8((volatile u8 *)(addr))
|
||||||
|
#define writeb(b,addr) out_8((volatile u8 *)(addr), (b))
|
||||||
|
#define readw(addr) in_le16((volatile u16 *)(addr))
|
||||||
|
#define readl(addr) in_le32((volatile u32 *)(addr))
|
||||||
|
#define writew(b,addr) out_le16((volatile u16 *)(addr),(b))
|
||||||
|
#define writel(b,addr) out_le32((volatile u32 *)(addr),(b))
|
||||||
|
|
||||||
|
|
||||||
|
#define __raw_readb(addr) (*(volatile unsigned char *)(addr))
|
||||||
|
#define __raw_readw(addr) (*(volatile unsigned short *)(addr))
|
||||||
|
#define __raw_readl(addr) (*(volatile unsigned int *)(addr))
|
||||||
|
#define __raw_writeb(v, addr) (*(volatile unsigned char *)(addr) = (v))
|
||||||
|
#define __raw_writew(v, addr) (*(volatile unsigned short *)(addr) = (v))
|
||||||
|
#define __raw_writel(v, addr) (*(volatile unsigned int *)(addr) = (v))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The insw/outsw/insl/outsl macros don't do byte-swapping.
|
||||||
|
* They are only used in practice for transferring buffers which
|
||||||
|
* are arrays of bytes, and byte-swapping is not appropriate in
|
||||||
|
* that case. - paulus
|
||||||
|
*/
|
||||||
|
#define insb(port, buf, ns) _insb((u8 *)((port)+_IO_BASE), (buf), (ns))
|
||||||
|
#define outsb(port, buf, ns) _outsb((u8 *)((port)+_IO_BASE), (buf), (ns))
|
||||||
|
#define insw(port, buf, ns) _insw_ns((u16 *)((port)+_IO_BASE), (buf), (ns))
|
||||||
|
#define outsw(port, buf, ns) _outsw_ns((u16 *)((port)+_IO_BASE), (buf), (ns))
|
||||||
|
#define insl(port, buf, nl) _insl_ns((u32 *)((port)+_IO_BASE), (buf), (nl))
|
||||||
|
#define outsl(port, buf, nl) _outsl_ns((u32 *)((port)+_IO_BASE), (buf), (nl))
|
||||||
|
|
||||||
|
#define inb(port) in_8((u8 *)((port)+_IO_BASE))
|
||||||
|
#define outb(val, port) out_8((u8 *)((port)+_IO_BASE), (val))
|
||||||
|
#define inw(port) in_le16((u16 *)((port)+_IO_BASE))
|
||||||
|
#define outw(val, port) out_le16((u16 *)((port)+_IO_BASE), (val))
|
||||||
|
#define inl(port) in_le32((u32 *)((port)+_IO_BASE))
|
||||||
|
#define outl(val, port) out_le32((u32 *)((port)+_IO_BASE), (val))
|
||||||
|
|
||||||
|
#define inb_p(port) inb((port))
|
||||||
|
#define outb_p(val, port) outb((val), (port))
|
||||||
|
#define inw_p(port) inw((port))
|
||||||
|
#define outw_p(val, port) outw((val), (port))
|
||||||
|
#define inl_p(port) inl((port))
|
||||||
|
#define outl_p(val, port) outl((val), (port))
|
||||||
|
|
||||||
|
extern void _insb(volatile u8 *port, void *buf, int ns);
|
||||||
|
extern void _outsb(volatile u8 *port, const void *buf, int ns);
|
||||||
|
extern void _insw(volatile u16 *port, void *buf, int ns);
|
||||||
|
extern void _outsw(volatile u16 *port, const void *buf, int ns);
|
||||||
|
extern void _insl(volatile u32 *port, void *buf, int nl);
|
||||||
|
extern void _outsl(volatile u32 *port, const void *buf, int nl);
|
||||||
|
extern void _insw_ns(volatile u16 *port, void *buf, int ns);
|
||||||
|
extern void _outsw_ns(volatile u16 *port, const void *buf, int ns);
|
||||||
|
extern void _insl_ns(volatile u32 *port, void *buf, int nl);
|
||||||
|
extern void _outsl_ns(volatile u32 *port, const void *buf, int nl);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The *_ns versions below don't do byte-swapping.
|
||||||
|
* Neither do the standard versions now, these are just here
|
||||||
|
* for older code.
|
||||||
|
*/
|
||||||
|
#define insw_ns(port, buf, ns) _insw_ns((u16 *)((port)+_IO_BASE), (buf), (ns))
|
||||||
|
#define outsw_ns(port, buf, ns) _outsw_ns((u16 *)((port)+_IO_BASE), (buf), (ns))
|
||||||
|
#define insl_ns(port, buf, nl) _insl_ns((u32 *)((port)+_IO_BASE), (buf), (nl))
|
||||||
|
#define outsl_ns(port, buf, nl) _outsl_ns((u32 *)((port)+_IO_BASE), (buf), (nl))
|
||||||
|
|
||||||
|
|
||||||
|
#define IO_SPACE_LIMIT ~0
|
||||||
|
|
||||||
|
#define memset_io(a,b,c) memset((void *)(a),(b),(c))
|
||||||
|
#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c))
|
||||||
|
#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enforce In-order Execution of I/O:
|
||||||
|
* Acts as a barrier to ensure all previous I/O accesses have
|
||||||
|
* completed before any further ones are issued.
|
||||||
|
*/
|
||||||
|
extern inline void eieio(void)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__ ("eieio" : : : "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enforce in-order execution of data I/O.
|
||||||
|
* No distinction between read/write on PPC; use eieio for all three.
|
||||||
|
*/
|
||||||
|
#define iobarrier_rw() eieio()
|
||||||
|
#define iobarrier_r() eieio()
|
||||||
|
#define iobarrier_w() eieio()
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 8, 16 and 32 bit, big and little endian I/O operations, with barrier.
|
||||||
|
*/
|
||||||
|
extern inline int in_8(volatile unsigned char *addr)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
__asm__ __volatile__("lbz%U1%X1 %0,%1; eieio" : "=r" (ret) : "m" (*addr));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern inline void out_8(volatile unsigned char *addr, int val)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__("stb%U0%X0 %1,%0; eieio" : "=m" (*addr) : "r" (val));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern inline int in_le16(volatile unsigned short *addr)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
__asm__ __volatile__("lhbrx %0,0,%1; eieio" : "=r" (ret) :
|
||||||
|
"r" (addr), "m" (*addr));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern inline int in_be16(volatile unsigned short *addr)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
__asm__ __volatile__("lhz%U1%X1 %0,%1; eieio" : "=r" (ret) : "m" (*addr));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern inline void out_le16(volatile unsigned short *addr, int val)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__("sthbrx %1,0,%2; eieio" : "=m" (*addr) :
|
||||||
|
"r" (val), "r" (addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern inline void out_be16(volatile unsigned short *addr, int val)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__("sth%U0%X0 %1,%0; eieio" : "=m" (*addr) : "r" (val));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern inline unsigned in_le32(volatile unsigned *addr)
|
||||||
|
{
|
||||||
|
unsigned ret;
|
||||||
|
|
||||||
|
__asm__ __volatile__("lwbrx %0,0,%1; eieio" : "=r" (ret) :
|
||||||
|
"r" (addr), "m" (*addr));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern inline unsigned in_be32(volatile unsigned *addr)
|
||||||
|
{
|
||||||
|
unsigned ret;
|
||||||
|
|
||||||
|
__asm__ __volatile__("lwz%U1%X1 %0,%1; eieio" : "=r" (ret) : "m" (*addr));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern inline void out_le32(volatile unsigned *addr, int val)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__("stwbrx %1,0,%2; eieio" : "=m" (*addr) :
|
||||||
|
"r" (val), "r" (addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern inline void out_be32(volatile unsigned *addr, int val)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__("stw%U0%X0 %1,%0; eieio" : "=m" (*addr) : "r" (val));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern inline void _insw_ns(volatile u16 *port, void *buf, int ns)
|
||||||
|
{
|
||||||
|
u16 * b = (u16 *)buf;
|
||||||
|
|
||||||
|
while (ns > 0) {
|
||||||
|
*b++ = readw(port);
|
||||||
|
ns--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,54 @@
|
||||||
|
#ifndef ARCH_PIRQ_ROUTING_H
|
||||||
|
#define ARCH_PIRQ_ROUTING_H
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
#define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
|
||||||
|
#define PIRQ_VERSION 0x0100
|
||||||
|
|
||||||
|
struct irq_info {
|
||||||
|
u8 bus, devfn; /* Bus, device and function */
|
||||||
|
struct {
|
||||||
|
u8 link; /* IRQ line ID, chipset dependent, 0=not routed */
|
||||||
|
u16 bitmap; /* Available IRQs */
|
||||||
|
} __attribute__((packed)) irq[4];
|
||||||
|
u8 slot; /* Slot number, 0=onboard */
|
||||||
|
u8 rfu;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
#if defined(IRQ_SLOT_COUNT)
|
||||||
|
#define IRQ_SLOTS_COUNT IRQ_SLOT_COUNT
|
||||||
|
#elif (__GNUC__ < 3)
|
||||||
|
#define IRQ_SLOTS_COUNT 1
|
||||||
|
#else
|
||||||
|
#define IRQ_SLOTS_COUNT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct irq_routing_table {
|
||||||
|
u32 signature; /* PIRQ_SIGNATURE should be here */
|
||||||
|
u16 version; /* PIRQ_VERSION */
|
||||||
|
u16 size; /* Table size in bytes */
|
||||||
|
u8 rtr_bus, rtr_devfn; /* Where the interrupt router lies */
|
||||||
|
u16 exclusive_irqs; /* IRQs devoted exclusively to PCI usage */
|
||||||
|
u16 rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */
|
||||||
|
u32 miniport_data; /* Crap */
|
||||||
|
u8 rfu[11];
|
||||||
|
u8 checksum; /* Modulo 256 checksum must give zero */
|
||||||
|
struct irq_info slots[IRQ_SLOTS_COUNT];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
extern const struct irq_routing_table intel_irq_routing_table;
|
||||||
|
|
||||||
|
#if defined(DEBUG) && defined(HAVE_PIRQ_TABLE)
|
||||||
|
void check_pirq_routing_table(void);
|
||||||
|
#else
|
||||||
|
#define check_pirq_routing_table() do {} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_PIRQ_TABLE)
|
||||||
|
unsigned long copy_pirq_routing_table(unsigned long start);
|
||||||
|
#else
|
||||||
|
#define copy_pirq_routing_table(start) (start)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ARCH_PIRQ_ROUTING_H */
|
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef I386_BITOPS_H
|
||||||
|
#define I386_BITOPS_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* log2 - Find the truncated log base 2 of x
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline unsigned long log2(unsigned long x)
|
||||||
|
{
|
||||||
|
unsigned long r = 0;
|
||||||
|
/*
|
||||||
|
__asm__(
|
||||||
|
"bsrl %1, %0\n\t"
|
||||||
|
"jnz 1f\n\t"
|
||||||
|
"movl $-1, %0\n\t"
|
||||||
|
"1:\n\t"
|
||||||
|
: "=r" (r) : "r" (x));
|
||||||
|
*/
|
||||||
|
return r;
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif /* I386_BITOPS_H */
|
|
@ -0,0 +1,21 @@
|
||||||
|
/* $Id$ */
|
||||||
|
/* Copyright 2000 AG Electronics Ltd. */
|
||||||
|
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
|
||||||
|
|
||||||
|
#ifndef _PPC_H
|
||||||
|
#define _PPC_H
|
||||||
|
|
||||||
|
#define BIG_ENDIAN
|
||||||
|
#define RODATA __attribute__ ((__section__ (".rodata")))
|
||||||
|
|
||||||
|
/* Do CPU specific setup, with optional icache */
|
||||||
|
void ppc_setup_cpu(int icache);
|
||||||
|
|
||||||
|
void ppc_enable_dcache(void);
|
||||||
|
void ppc_disable_dcache(void);
|
||||||
|
void ppc_enable_mmu(void);
|
||||||
|
|
||||||
|
/* Describe which sort of ppc CPU I am */
|
||||||
|
void ppc_identify(void);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,293 @@
|
||||||
|
/*
|
||||||
|
* (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
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file contains all the macros and symbols which define
|
||||||
|
* a PowerPC assembly language environment.
|
||||||
|
*/
|
||||||
|
#ifndef __PPC_ASM_TMPL__
|
||||||
|
#define __PPC_ASM_TMPL__
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
*
|
||||||
|
* These definitions simplify the ugly declarations necessary for GOT
|
||||||
|
* definitions.
|
||||||
|
*
|
||||||
|
* Stolen from prepboot/bootldr.h, (C) 1998 Gabriel Paubert, paubert@iram.es
|
||||||
|
*
|
||||||
|
* Uses r14 to access the GOT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define START_GOT \
|
||||||
|
.section ".got2","aw"; \
|
||||||
|
.LCTOC1 = .+32768
|
||||||
|
|
||||||
|
#define END_GOT \
|
||||||
|
.text
|
||||||
|
|
||||||
|
#define GET_GOT \
|
||||||
|
bl 1f ; \
|
||||||
|
.text 2 ; \
|
||||||
|
0: .long .LCTOC1-1f ; \
|
||||||
|
.text ; \
|
||||||
|
1: mflr r14 ; \
|
||||||
|
lwz r0,0b-1b(r14) ; \
|
||||||
|
add r14,r0,r14 ;
|
||||||
|
|
||||||
|
#define GOT_ENTRY(NAME) .L_ ## NAME = . - .LCTOC1 ; .long NAME
|
||||||
|
|
||||||
|
#define GOT(NAME) .L_ ## NAME (r14)
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* Register names
|
||||||
|
*/
|
||||||
|
#define r0 0
|
||||||
|
#define r1 1
|
||||||
|
#define r2 2
|
||||||
|
#define r3 3
|
||||||
|
#define r4 4
|
||||||
|
#define r5 5
|
||||||
|
#define r6 6
|
||||||
|
#define r7 7
|
||||||
|
#define r8 8
|
||||||
|
#define r9 9
|
||||||
|
#define r10 10
|
||||||
|
#define r11 11
|
||||||
|
#define r12 12
|
||||||
|
#define r13 13
|
||||||
|
#define r14 14
|
||||||
|
#define r15 15
|
||||||
|
#define r16 16
|
||||||
|
#define r17 17
|
||||||
|
#define r18 18
|
||||||
|
#define r19 19
|
||||||
|
#define r20 20
|
||||||
|
#define r21 21
|
||||||
|
#define r22 22
|
||||||
|
#define r23 23
|
||||||
|
#define r24 24
|
||||||
|
#define r25 25
|
||||||
|
#define r26 26
|
||||||
|
#define r27 27
|
||||||
|
#define r28 28
|
||||||
|
#define r29 29
|
||||||
|
#define r30 30
|
||||||
|
#define r31 31
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FP register names
|
||||||
|
*/
|
||||||
|
#define fr0 0
|
||||||
|
#define fr1 1
|
||||||
|
#define fr2 2
|
||||||
|
#define fr3 3
|
||||||
|
#define fr4 4
|
||||||
|
#define fr5 5
|
||||||
|
#define fr6 6
|
||||||
|
#define fr7 7
|
||||||
|
#define fr8 8
|
||||||
|
#define fr9 9
|
||||||
|
#define fr10 10
|
||||||
|
#define fr11 11
|
||||||
|
#define fr12 12
|
||||||
|
#define fr13 13
|
||||||
|
#define fr14 14
|
||||||
|
#define fr15 15
|
||||||
|
#define fr16 16
|
||||||
|
#define fr17 17
|
||||||
|
#define fr18 18
|
||||||
|
#define fr19 19
|
||||||
|
#define fr20 20
|
||||||
|
#define fr21 21
|
||||||
|
#define fr22 22
|
||||||
|
#define fr23 23
|
||||||
|
#define fr24 24
|
||||||
|
#define fr25 25
|
||||||
|
#define fr26 26
|
||||||
|
#define fr27 27
|
||||||
|
#define fr28 28
|
||||||
|
#define fr29 29
|
||||||
|
#define fr30 30
|
||||||
|
#define fr31 31
|
||||||
|
|
||||||
|
/* Some special registers */
|
||||||
|
|
||||||
|
#define TBRU 269 /* Time base Upper/Lower (Reading) */
|
||||||
|
#define TBRL 268
|
||||||
|
#define TBWU 284 /* Time base Upper/Lower (Writing) */
|
||||||
|
#define TBWL 285
|
||||||
|
#define XER 1
|
||||||
|
#define LR 8
|
||||||
|
#define CTR 9
|
||||||
|
#define HID0 1008 /* Hardware Implementation */
|
||||||
|
#define PVR 287 /* Processor Version */
|
||||||
|
#define SDR1 25 /* MMU hash base register */
|
||||||
|
#define DAR 19 /* Data Address Register */
|
||||||
|
#define SPR0 272 /* Supervisor Private Registers */
|
||||||
|
#define SPRG0 272
|
||||||
|
#define SPR1 273
|
||||||
|
#define SPRG1 273
|
||||||
|
#define SPR2 274
|
||||||
|
#define SPRG2 274
|
||||||
|
#define SPR3 275
|
||||||
|
#define SPRG3 275
|
||||||
|
#define DSISR 18
|
||||||
|
#define SRR0 26 /* Saved Registers (exception) */
|
||||||
|
#define SRR1 27
|
||||||
|
#define DEC 22 /* Decrementer */
|
||||||
|
#define EAR 282 /* External Address Register */
|
||||||
|
#define ICR 148 /* Interrupt Cause Register (37-44) */
|
||||||
|
#define DER 149
|
||||||
|
#define COUNTA 150 /* Breakpoint Counter (37-44) */
|
||||||
|
#define COUNTB 151 /* Breakpoint Counter (37-44) */
|
||||||
|
#define LCTRL1 156 /* Load/Store Support (37-40) */
|
||||||
|
#define LCTRL2 157 /* Load/Store Support (37-41) */
|
||||||
|
#define ICTRL 158
|
||||||
|
|
||||||
|
/* Registers in the processor's internal memory map that we use.
|
||||||
|
*/
|
||||||
|
#define IMMR 0xff000000
|
||||||
|
|
||||||
|
#define SYPCR 0x00000004
|
||||||
|
#define BR0 0x00000100
|
||||||
|
#define OR0 0x00000104
|
||||||
|
#define BR1 0x00000108
|
||||||
|
#define OR1 0x0000010c
|
||||||
|
#define BR2 0x00000110
|
||||||
|
#define OR2 0x00000114
|
||||||
|
#define BR3 0x00000118
|
||||||
|
#define OR3 0x0000011c
|
||||||
|
#define BR4 0x00000120
|
||||||
|
#define OR4 0x00000124
|
||||||
|
|
||||||
|
#define MAR 0x00000164
|
||||||
|
#define MCR 0x00000168
|
||||||
|
#define MAMR 0x00000170
|
||||||
|
#define MBMR 0x00000174
|
||||||
|
#define MSTAT 0x00000178
|
||||||
|
#define MPTPR 0x0000017a
|
||||||
|
#define MDR 0x0000017c
|
||||||
|
|
||||||
|
#define TBSCR 0x00000200
|
||||||
|
#define TBREFF0 0x00000204
|
||||||
|
|
||||||
|
#define PLPRCR 0x00000284
|
||||||
|
|
||||||
|
#define curptr r2
|
||||||
|
|
||||||
|
#define SYNC \
|
||||||
|
sync; \
|
||||||
|
isync
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Macros for storing registers into and loading registers from
|
||||||
|
* exception frames.
|
||||||
|
*/
|
||||||
|
#define SAVE_GPR(n, base) stw n,GPR0+4*(n)(base)
|
||||||
|
#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base)
|
||||||
|
#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
|
||||||
|
#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
|
||||||
|
#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
|
||||||
|
#define REST_GPR(n, base) lwz n,GPR0+4*(n)(base)
|
||||||
|
#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base)
|
||||||
|
#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base)
|
||||||
|
#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base)
|
||||||
|
#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GCC sometimes accesses words at negative offsets from the stack
|
||||||
|
* pointer, although the SysV ABI says it shouldn't. To cope with
|
||||||
|
* this, we leave this much untouched space on the stack on exception
|
||||||
|
* entry.
|
||||||
|
*/
|
||||||
|
#define STACK_UNDERHEAD 64
|
||||||
|
|
||||||
|
#if 0 /* we don't use virtual addresses in PPCBOOT */
|
||||||
|
#define tophys(rd,rs,rt) addis rd,rs,-KERNELBASE@h
|
||||||
|
#define tovirt(rd,rs,rt) addis rd,rs,KERNELBASE@h
|
||||||
|
#else
|
||||||
|
#define tophys(rd,rs,rt) mr rd,rs
|
||||||
|
#define tovirt(rd,rs,rt) mr rd,rs
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Exception entry code. This code runs with address translation
|
||||||
|
* turned off, i.e. using physical addresses.
|
||||||
|
* We assume sprg3 has the physical address of the current
|
||||||
|
* task's thread_struct.
|
||||||
|
*/
|
||||||
|
#define EXCEPTION_PROLOG \
|
||||||
|
mtspr SPRG0,r20; \
|
||||||
|
mtspr SPRG1,r21; \
|
||||||
|
mfcr r20; \
|
||||||
|
tophys(r21,r1,r21); /* use tophys(kernel sp) otherwise */ \
|
||||||
|
subi r21,r21,INT_FRAME_SIZE+STACK_UNDERHEAD; /* alloc exc. frame */\
|
||||||
|
1: stw r20,_CCR(r21); /* save registers */ \
|
||||||
|
stw r22,GPR22(r21); \
|
||||||
|
stw r23,GPR23(r21); \
|
||||||
|
mfspr r20,SPRG0; \
|
||||||
|
stw r20,GPR20(r21); \
|
||||||
|
mfspr r22,SPRG1; \
|
||||||
|
stw r22,GPR21(r21); \
|
||||||
|
mflr r20; \
|
||||||
|
stw r20,_LINK(r21); \
|
||||||
|
mfctr r22; \
|
||||||
|
stw r22,_CTR(r21); \
|
||||||
|
mfspr r20,XER; \
|
||||||
|
stw r20,_XER(r21); \
|
||||||
|
mfspr r22,SRR0; \
|
||||||
|
mfspr r23,SRR1; \
|
||||||
|
stw r0,GPR0(r21); \
|
||||||
|
stw r1,GPR1(r21); \
|
||||||
|
stw r2,GPR2(r21); \
|
||||||
|
stw r1,0(r21); \
|
||||||
|
tovirt(r1,r21,r1); /* set new kernel sp */ \
|
||||||
|
SAVE_4GPRS(3, r21);
|
||||||
|
/*
|
||||||
|
* Note: code which follows this uses cr0.eq (set if from kernel),
|
||||||
|
* r21, r22 (SRR0), and r23 (SRR1).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Exception vectors.
|
||||||
|
*
|
||||||
|
* The data words for `hdlr' and `int_return' are initialized with
|
||||||
|
* OFFSET values only; they must be relocated first before they can
|
||||||
|
* be used!
|
||||||
|
*/
|
||||||
|
#define STD_EXCEPTION(n, label, hdlr) \
|
||||||
|
. = n; \
|
||||||
|
label: \
|
||||||
|
EXCEPTION_PROLOG; \
|
||||||
|
lwz r3,GOT(transfer_to_handler); \
|
||||||
|
mtlr r3; \
|
||||||
|
addi r3,r1,STACK_FRAME_OVERHEAD; \
|
||||||
|
li r20,MSR_KERNEL; \
|
||||||
|
blrl ; \
|
||||||
|
.L_ ## label : \
|
||||||
|
.long hdlr - _start + EXC_OFF_SYS_RESET; \
|
||||||
|
.long int_return - _start + EXC_OFF_SYS_RESET
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __PPC_ASM_TMPL__ */
|
|
@ -0,0 +1,128 @@
|
||||||
|
/* $Id$ */
|
||||||
|
/* Copyright 2000 AG Electronics Ltd. */
|
||||||
|
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
|
||||||
|
|
||||||
|
/* In the MSR, not all bits are interesting to us
|
||||||
|
13 - POW - Power management
|
||||||
|
14 - TGPR - temporary registers for page table routines
|
||||||
|
15 - ILE - Exception little endian
|
||||||
|
16 - EE - External interrupts
|
||||||
|
17 - PR - Privilege level
|
||||||
|
18 - FP - Floating Point available
|
||||||
|
19 - ME - Machine check exception enable
|
||||||
|
20 - FE0 - Floating exception mode 0
|
||||||
|
21 - SE - Single step trace mode
|
||||||
|
22 - BE - Branch trace enable
|
||||||
|
23 - FE1 - Floating exception mode 1
|
||||||
|
25 - IP - Exception prefix
|
||||||
|
26 - IR - Instruction address translation
|
||||||
|
27 - DR - Data address translation
|
||||||
|
30 - RI - Recoverable exception
|
||||||
|
31 - LE - Little endian mode
|
||||||
|
MSR_MASK is the bits we do not change.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MSR_MASK 0xfff8008c
|
||||||
|
#define MSR_POW 0x00040000
|
||||||
|
#define MSR_TGPR 0x00020000
|
||||||
|
#define MSR_ILE 0x00010000
|
||||||
|
#define MSR_EE 0x00008000
|
||||||
|
#define MSR_PR 0x00004000
|
||||||
|
#define MSR_FP 0x00002000
|
||||||
|
#define MSR_ME 0x00001000
|
||||||
|
#define MSR_FE0 0x00000800
|
||||||
|
#define MSR_SE 0x00000400
|
||||||
|
#define MSR_BE 0x00000200
|
||||||
|
#define MSR_FE1 0x00000100
|
||||||
|
#define MSR_IP 0x00000040
|
||||||
|
#define MSR_IR 0x00000020
|
||||||
|
#define MSR_DR 0x00000010
|
||||||
|
#define MSR_RI 0x00000002
|
||||||
|
#define MSR_LE 0x00000001
|
||||||
|
|
||||||
|
#define MSR_DEFAULT (MSR_FP | MSR_IR | MSR_DR)
|
||||||
|
|
||||||
|
/* We are interested in the following hid0 bits:
|
||||||
|
6 - ECLK - Enable external test clock (603 only)
|
||||||
|
11 - DPM - Turn on dynamic power management (603 only)
|
||||||
|
15 - NHR - Not hard reset
|
||||||
|
16 - ICE - Instruction cache enable
|
||||||
|
17 - DCE - Data cache enable
|
||||||
|
18 - ILOCK - Instruction cache lock
|
||||||
|
19 - DLOCK - Data cache lock
|
||||||
|
20 - ICFI - Instruction cache invalidate
|
||||||
|
21 - DCFI - Data cache invalidate
|
||||||
|
24 - NOSER - Serial execution disable (604 only - turbo mode)
|
||||||
|
24 - SGE - Store gathering enable (7410 only)
|
||||||
|
29 - BHT - Branch history table (604 only)
|
||||||
|
|
||||||
|
I made up the tags for the 604 specific bits, as they aren't
|
||||||
|
named in the 604 book. The 603 book calls the invalidate bits
|
||||||
|
ICFI and DCI, and I have no idea why it isn't DCFI. Maybe IBM named
|
||||||
|
one, and Motorola named the other. */
|
||||||
|
|
||||||
|
#define HID0_ECLK 0x02000000
|
||||||
|
#define HID0_DPM 0x00100000
|
||||||
|
#define HID0_NHR 0x00010000
|
||||||
|
#define HID0_ICE 0x00008000
|
||||||
|
#define HID0_DCE 0x00004000
|
||||||
|
#define HID0_ILOCK 0x00002000
|
||||||
|
#define HID0_DLOCK 0x00001000
|
||||||
|
#define HID0_ICFI 0x00000800
|
||||||
|
#define HID0_DCFI 0x00000400
|
||||||
|
#define HID0_NOSER 0x00000080
|
||||||
|
#define HID0_SGE 0x00000080
|
||||||
|
#define HID0_BTIC 0x00000020
|
||||||
|
#define HID0_BHT 0x00000004
|
||||||
|
|
||||||
|
/*
|
||||||
|
* BAT defines
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* BL field in upper BAT register
|
||||||
|
*/
|
||||||
|
#define BAT_BL_128K 0x00000000
|
||||||
|
#define BAT_BL_256K 0x00000004
|
||||||
|
#define BAT_BL_512K 0x0000000C
|
||||||
|
#define BAT_BL_1M 0x0000001C
|
||||||
|
#define BAT_BL_2M 0x0000003C
|
||||||
|
#define BAT_BL_4M 0x0000007C
|
||||||
|
#define BAT_BL_8M 0x000000FC
|
||||||
|
#define BAT_BL_16M 0x000001FC
|
||||||
|
#define BAT_BL_32M 0x000003FC
|
||||||
|
#define BAT_BL_64M 0x000007FC
|
||||||
|
#define BAT_BL_128M 0x00000FFC
|
||||||
|
#define BAT_BL_256M 0x00001FFC
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Supervisor/user valid mode in upper BAT register
|
||||||
|
*/
|
||||||
|
#define BAT_VALID_SUPERVISOR 0x00000002
|
||||||
|
#define BAT_VALID_USER 0x00000001
|
||||||
|
#define BAT_INVALID 0x00000000
|
||||||
|
|
||||||
|
/*
|
||||||
|
* WIMG bit setting in lower BAT register
|
||||||
|
*/
|
||||||
|
#define BAT_WRITE_THROUGH 0x00000040
|
||||||
|
#define BAT_CACHE_INHIBITED 0x00000020
|
||||||
|
#define BAT_COHERENT 0x00000010
|
||||||
|
#define BAT_GUARDED 0x00000008
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Protection bits in lower BAT register
|
||||||
|
*/
|
||||||
|
#define BAT_NO_ACCESS 0x00000000
|
||||||
|
#define BAT_READ_ONLY 0x00000001
|
||||||
|
#define BAT_READ_WRITE 0x00000002
|
||||||
|
|
||||||
|
#ifndef ASM
|
||||||
|
unsigned __getmsr(void);
|
||||||
|
void __setmsr(unsigned value);
|
||||||
|
unsigned __gethid0(void);
|
||||||
|
unsigned __gethid1(void);
|
||||||
|
void __sethid0(unsigned value);
|
||||||
|
unsigned __getpvr(void);
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef PPC_STDDEF_H
|
||||||
|
#define PPC_STDDEF_H
|
||||||
|
|
||||||
|
typedef long ptrdiff_t;
|
||||||
|
typedef unsigned long size_t;
|
||||||
|
typedef long ssize_t;
|
||||||
|
|
||||||
|
typedef int wchar_t;
|
||||||
|
typedef unsigned int wint_t;
|
||||||
|
|
||||||
|
#define NULL 0
|
||||||
|
|
||||||
|
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||||
|
|
||||||
|
#endif /* PPC_STDDEF_H */
|
|
@ -0,0 +1,52 @@
|
||||||
|
#ifndef PPC_STDINT_H
|
||||||
|
#define PPC_STDINT_H
|
||||||
|
|
||||||
|
/* Exact integral types */
|
||||||
|
typedef unsigned char uint8_t;
|
||||||
|
typedef signed char int8_t;
|
||||||
|
|
||||||
|
typedef unsigned short uint16_t;
|
||||||
|
typedef signed short int16_t;
|
||||||
|
|
||||||
|
typedef unsigned int uint32_t;
|
||||||
|
typedef signed int int32_t;
|
||||||
|
|
||||||
|
typedef unsigned long long uint64_t;
|
||||||
|
typedef signed long long int64_t;
|
||||||
|
|
||||||
|
/* Small types */
|
||||||
|
typedef unsigned char uint_least8_t;
|
||||||
|
typedef signed char int_least8_t;
|
||||||
|
|
||||||
|
typedef unsigned short uint_least16_t;
|
||||||
|
typedef signed short int_least16_t;
|
||||||
|
|
||||||
|
typedef unsigned int uint_least32_t;
|
||||||
|
typedef signed int int_least32_t;
|
||||||
|
|
||||||
|
typedef unsigned long long uint_least64_t;
|
||||||
|
typedef signed long long int_least64_t;
|
||||||
|
|
||||||
|
/* Fast Types */
|
||||||
|
typedef unsigned char uint_fast8_t;
|
||||||
|
typedef signed char int_fast8_t;
|
||||||
|
|
||||||
|
typedef unsigned int uint_fast16_t;
|
||||||
|
typedef signed int int_fast16_t;
|
||||||
|
|
||||||
|
typedef unsigned int uint_fast32_t;
|
||||||
|
typedef signed int int_fast32_t;
|
||||||
|
|
||||||
|
typedef unsigned long long uint_fast64_t;
|
||||||
|
typedef signed long long int_fast64_t;
|
||||||
|
|
||||||
|
/* Types for `void *' pointers. */
|
||||||
|
typedef int intptr_t;
|
||||||
|
typedef unsigned int uintptr_t;
|
||||||
|
|
||||||
|
/* Largest integral types */
|
||||||
|
typedef long long int intmax_t;
|
||||||
|
typedef unsigned long long uintmax_t;
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* PPC_STDINT_H */
|
|
@ -0,0 +1,13 @@
|
||||||
|
/* $Id$ */
|
||||||
|
/* Copyright 2000 AG Electronics Ltd. */
|
||||||
|
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
|
||||||
|
|
||||||
|
#ifndef _TIMER_H
|
||||||
|
#define __TIMER_H
|
||||||
|
|
||||||
|
unsigned get_hz(void);
|
||||||
|
unsigned ticks_since_boot(void);
|
||||||
|
void sleep_ticks(unsigned);
|
||||||
|
void udelay(int);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,109 @@
|
||||||
|
/* $Id$ */
|
||||||
|
/* Copyright 2000 AG Electronics Ltd. */
|
||||||
|
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The assumption is that we're located in ROM and we have a fake stack
|
||||||
|
* located in cache. Our task is to turn on memory proper, the finish
|
||||||
|
* configuring the machine.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ASM
|
||||||
|
#include "ppcreg.h"
|
||||||
|
#include <ppc_asm.tmpl>
|
||||||
|
|
||||||
|
.section ".text"
|
||||||
|
.globl _start
|
||||||
|
|
||||||
|
_start:
|
||||||
|
/*
|
||||||
|
* init stack pointer to real ram now that memory is on
|
||||||
|
*/
|
||||||
|
lis r1, _estack@ha
|
||||||
|
addi r1, r1, _estack@l
|
||||||
|
stwu r0,-64(r1)
|
||||||
|
stwu r1,-24(r1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear stack
|
||||||
|
*/
|
||||||
|
lis r4, _stack@ha
|
||||||
|
addi r4, r4, _stack@l
|
||||||
|
lis r7, _estack@ha
|
||||||
|
addi r7, r7, _estack@l
|
||||||
|
lis r5, 0
|
||||||
|
1: stwx r5, 0, r4
|
||||||
|
addi r4, r4, 4
|
||||||
|
cmp 0, 0, r4, r7
|
||||||
|
ble 1b
|
||||||
|
sync
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear bss
|
||||||
|
*/
|
||||||
|
lis r4, _bss@ha
|
||||||
|
addi r4, r4, _bss@l
|
||||||
|
lis r7, _ebss@ha
|
||||||
|
addi r7, r7, _ebss@l
|
||||||
|
lis r5, 0
|
||||||
|
1: stwx r5, 0, r4
|
||||||
|
addi r4, r4, 4
|
||||||
|
cmp 0, 0, r4, r7
|
||||||
|
ble 1b
|
||||||
|
sync
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up the EABI pointers, before we enter any C code
|
||||||
|
*/
|
||||||
|
lis r13, _SDA_BASE_@ha
|
||||||
|
addi r13, r13, _SDA_BASE_@l
|
||||||
|
lis r2, _SDA2_BASE_@ha
|
||||||
|
addi r2, r2, _SDA2_BASE_@l
|
||||||
|
|
||||||
|
/*
|
||||||
|
* load start address into SRR0 for rfi
|
||||||
|
*/
|
||||||
|
lis r3, hardwaremain@ha
|
||||||
|
addi r3, r3, hardwaremain@l
|
||||||
|
mtspr SRR0, r3
|
||||||
|
|
||||||
|
/*
|
||||||
|
* load the current MSR into SRR1 so that it will be copied
|
||||||
|
* back into MSR on rfi
|
||||||
|
*/
|
||||||
|
mfmsr r4
|
||||||
|
mtspr SRR1, r4 // load SRR1 with r4
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If something returns after rfi then die
|
||||||
|
*/
|
||||||
|
lis r3, dead@ha
|
||||||
|
addi r3, r3, dead@l
|
||||||
|
mtlr r3
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Complete rest of initialization in C (hardwaremain)
|
||||||
|
*/
|
||||||
|
rfi
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stop here if something goes wrong
|
||||||
|
*/
|
||||||
|
dead:
|
||||||
|
b dead
|
||||||
|
/*NOTREACHED*/
|
||||||
|
|
||||||
|
/* Remove need for ecrti.o and ectrn.o */
|
||||||
|
.globl __init
|
||||||
|
__init:
|
||||||
|
.globl __fini
|
||||||
|
__fini:
|
||||||
|
.globl __CTOR_LIST__
|
||||||
|
__CTOR_LIST__:
|
||||||
|
.globl __CTOR_END__
|
||||||
|
__CTOR_END__:
|
||||||
|
.globl __DTOR_LIST__
|
||||||
|
__DTOR_LIST__:
|
||||||
|
.globl __DTOR_END__
|
||||||
|
__DTOR_END__:
|
||||||
|
blr
|
|
@ -0,0 +1,45 @@
|
||||||
|
/* $Id$ */
|
||||||
|
/* Copyright 1999-2000 AG Electronics Ltd. */
|
||||||
|
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
|
||||||
|
|
||||||
|
#include <ppc_asm.tmpl>
|
||||||
|
|
||||||
|
.globl _init_float_registers
|
||||||
|
|
||||||
|
_init_float_registers:
|
||||||
|
lfd fr0, 0(r3)
|
||||||
|
lfd fr1, 0(r3)
|
||||||
|
lfd fr2, 0(r3)
|
||||||
|
lfd fr3, 0(r3)
|
||||||
|
lfd fr4, 0(r3)
|
||||||
|
lfd fr5, 0(r3)
|
||||||
|
lfd fr6, 0(r3)
|
||||||
|
lfd fr7, 0(r3)
|
||||||
|
lfd fr8, 0(r3)
|
||||||
|
lfd fr9, 0(r3)
|
||||||
|
lfd fr10, 0(r3)
|
||||||
|
lfd fr11, 0(r3)
|
||||||
|
lfd fr12, 0(r3)
|
||||||
|
lfd fr13, 0(r3)
|
||||||
|
lfd fr14, 0(r3)
|
||||||
|
lfd fr15, 0(r3)
|
||||||
|
lfd fr16, 0(r3)
|
||||||
|
lfd fr17, 0(r3)
|
||||||
|
lfd fr18, 0(r3)
|
||||||
|
lfd fr19, 0(r3)
|
||||||
|
lfd fr20, 0(r3)
|
||||||
|
lfd fr21, 0(r3)
|
||||||
|
lfd fr22, 0(r3)
|
||||||
|
lfd fr23, 0(r3)
|
||||||
|
lfd fr24, 0(r3)
|
||||||
|
lfd fr25, 0(r3)
|
||||||
|
lfd fr26, 0(r3)
|
||||||
|
lfd fr27, 0(r3)
|
||||||
|
lfd fr28, 0(r3)
|
||||||
|
lfd fr29, 0(r3)
|
||||||
|
lfd fr30, 0(r3)
|
||||||
|
lfd fr31, 0(r3)
|
||||||
|
blr
|
||||||
|
|
||||||
|
.end
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
/* $Id$ */
|
||||||
|
/* Copyright 1999-2000 AG Electronics Ltd. */
|
||||||
|
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
|
||||||
|
|
||||||
|
/* .text*/
|
||||||
|
.globl _init_float_registers
|
||||||
|
|
||||||
|
_init_float_registers:
|
||||||
|
lfd 0, 0(3)
|
||||||
|
lfd 1, 0(3)
|
||||||
|
lfd 2, 0(3)
|
||||||
|
lfd 3, 0(3)
|
||||||
|
lfd 4, 0(3)
|
||||||
|
lfd 5, 0(3)
|
||||||
|
lfd 6, 0(3)
|
||||||
|
lfd 7, 0(3)
|
||||||
|
lfd 8, 0(3)
|
||||||
|
lfd 9, 0(3)
|
||||||
|
lfd 10, 0(3)
|
||||||
|
lfd 11, 0(3)
|
||||||
|
lfd 12, 0(3)
|
||||||
|
lfd 13, 0(3)
|
||||||
|
lfd 14, 0(3)
|
||||||
|
lfd 15, 0(3)
|
||||||
|
lfd 16, 0(3)
|
||||||
|
lfd 17, 0(3)
|
||||||
|
lfd 18, 0(3)
|
||||||
|
lfd 19, 0(3)
|
||||||
|
lfd 20, 0(3)
|
||||||
|
lfd 21, 0(3)
|
||||||
|
lfd 22, 0(3)
|
||||||
|
lfd 23, 0(3)
|
||||||
|
lfd 24, 0(3)
|
||||||
|
lfd 25, 0(3)
|
||||||
|
lfd 26, 0(3)
|
||||||
|
lfd 27, 0(3)
|
||||||
|
lfd 28, 0(3)
|
||||||
|
lfd 29, 0(3)
|
||||||
|
lfd 30, 0(3)
|
||||||
|
lfd 31, 0(3)
|
||||||
|
blr
|
||||||
|
.end
|
||||||
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
/* $Id$ */
|
||||||
|
/* Copyright 2000 AG Electronics Ltd. */
|
||||||
|
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
|
||||||
|
|
||||||
|
#include "ppc.h"
|
||||||
|
#include "ppcreg.h"
|
||||||
|
|
||||||
|
unsigned __getmsr(void)
|
||||||
|
{
|
||||||
|
unsigned result;
|
||||||
|
__asm__ volatile ("mfmsr %0" : "=r" (result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned __gethid0(void)
|
||||||
|
{
|
||||||
|
unsigned result;
|
||||||
|
__asm__ volatile ("mfspr %0,1008" : "=r" (result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned __gethid1(void)
|
||||||
|
{
|
||||||
|
unsigned result;
|
||||||
|
__asm__ volatile ("mfspr %0,1009" : "=r" (result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __sethid0(unsigned value)
|
||||||
|
{
|
||||||
|
__asm__ volatile ("mtspr 1008,%0" : : "r" (value));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned __getpvr(void)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
__asm__("mfspr %0, 287" : "=r" (result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __setmsr(unsigned value)
|
||||||
|
{
|
||||||
|
__asm__ volatile ("mtmsr %0; sync" :: "r" (value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void __set1015(unsigned value)
|
||||||
|
{
|
||||||
|
__asm__ volatile ("mtspr 1015,%0" : : "r" (value));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void _init_float_registers(const double *);
|
||||||
|
/*RODATA static const double dummy_float = 1.0;*/
|
||||||
|
static const double dummy_float = 1.0;
|
||||||
|
|
||||||
|
#define HID0_DCACHE HID0_DCE
|
||||||
|
#define MSR_DATA MSR_DR
|
||||||
|
|
||||||
|
void ppc_setup_cpu(int icache)
|
||||||
|
{
|
||||||
|
int type = __getpvr() >> 16;
|
||||||
|
int version = __getpvr() & 0xffff;
|
||||||
|
|
||||||
|
if (type == 0xc)
|
||||||
|
{
|
||||||
|
if (version == 0x0200)
|
||||||
|
__set1015(0x19000004);
|
||||||
|
else if (((version & 0xff00) == 0x0200) &&
|
||||||
|
(version != 0x0209))
|
||||||
|
__set1015(0x01000000);
|
||||||
|
}
|
||||||
|
if (icache)
|
||||||
|
{
|
||||||
|
__sethid0(HID0_NHR | HID0_BHT | HID0_ICE | HID0_ICFI | HID0_BTIC
|
||||||
|
| HID0_DCACHE);
|
||||||
|
__sethid0(HID0_DPM | HID0_NHR | HID0_BHT | HID0_ICE | HID0_BTIC
|
||||||
|
| HID0_DCACHE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
__sethid0(HID0_DPM | HID0_NHR | HID0_BHT | HID0_BTIC | HID0_DCACHE);
|
||||||
|
}
|
||||||
|
#if 1
|
||||||
|
/* if (type == 8 || type == 12) */
|
||||||
|
{
|
||||||
|
__setmsr(MSR_FP | MSR_DATA);
|
||||||
|
_init_float_registers(&dummy_float);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ppc_enable_dcache(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Already enabled in crt0.S
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
unsigned hid0 = __gethid0();
|
||||||
|
__sethid0(hid0 | HID0_DCFI | HID0_DCE);
|
||||||
|
__sethid0(hid0 | HID0_DCE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ppc_disable_dcache(void)
|
||||||
|
{
|
||||||
|
unsigned hid0 = __gethid0();
|
||||||
|
__sethid0(hid0 & ~HID0_DCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ppc_enable_mmu(void)
|
||||||
|
{
|
||||||
|
unsigned msr = __getmsr();
|
||||||
|
__setmsr(msr | MSR_DR | MSR_IR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void make_coherent(void *base, unsigned length)
|
||||||
|
{
|
||||||
|
unsigned hid0 = __gethid0();
|
||||||
|
|
||||||
|
if (hid0 & HID0_DCE)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
unsigned offset = 0x1f & (unsigned) base;
|
||||||
|
unsigned adjusted_base = (unsigned) base & ~0x1f;
|
||||||
|
for(i = 0; i < length + offset; i+= 32)
|
||||||
|
__asm__ volatile ("dcbf %1,%0" : : "r" (adjusted_base), "r" (i));
|
||||||
|
if (hid0 & HID0_ICE)
|
||||||
|
for(i = 0; i < length + offset; i+= 32)
|
||||||
|
__asm__ volatile ("icbi %1,%0" : : "r" (adjusted_base), "r" (i));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
/* $Id$ */
|
||||||
|
/* Copyright 1999-2000 AG Electronics Ltd. */
|
||||||
|
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
|
||||||
|
|
||||||
|
.text
|
||||||
|
.globl _timebase
|
||||||
|
_timebase:
|
||||||
|
mftbu 3
|
||||||
|
mftb 4
|
||||||
|
mftbu 5
|
||||||
|
cmpw 3, 5
|
||||||
|
bne _timebase
|
||||||
|
blr
|
|
@ -0,0 +1,31 @@
|
||||||
|
/* $Id$ */
|
||||||
|
/* Copyright 2000 AG Electronics Ltd. */
|
||||||
|
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
|
||||||
|
|
||||||
|
#include <timer.h>
|
||||||
|
#include <bsp.h>
|
||||||
|
|
||||||
|
unsigned get_hz(void)
|
||||||
|
{
|
||||||
|
return bsp_clock_speed();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned ticks_since_boot(void)
|
||||||
|
{
|
||||||
|
extern unsigned long long _timebase(void);
|
||||||
|
return (unsigned) (_timebase());
|
||||||
|
}
|
||||||
|
|
||||||
|
void sleep_ticks(unsigned ticks)
|
||||||
|
{
|
||||||
|
unsigned then = ticks + ticks_since_boot();
|
||||||
|
while(ticks_since_boot() < then)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
void udelay(int usecs)
|
||||||
|
{
|
||||||
|
unsigned ticksperusec = get_hz() / 1000000;
|
||||||
|
|
||||||
|
sleep_ticks(ticksperusec * usecs);
|
||||||
|
}
|
|
@ -0,0 +1,210 @@
|
||||||
|
/*
|
||||||
|
* UBL, The Universal Talkware Boot Loader
|
||||||
|
* Copyright (C) 2000 Universal Talkware Inc.
|
||||||
|
* Copyright (C) 2002 Eric Biederman
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef uint64_t sector_t;
|
||||||
|
|
||||||
|
struct controller {
|
||||||
|
uint16_t cmd_base;
|
||||||
|
uint16_t ctrl_base;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct harddisk_info {
|
||||||
|
struct controller *ctrl;
|
||||||
|
uint16_t heads;
|
||||||
|
uint16_t cylinders;
|
||||||
|
uint16_t sectors_per_track;
|
||||||
|
uint8_t model_number[41];
|
||||||
|
uint8_t slave;
|
||||||
|
sector_t sectors;
|
||||||
|
int address_mode; /* am i lba (0x40) or chs (0x00) */
|
||||||
|
#define ADDRESS_MODE_CHS 0
|
||||||
|
#define ADDRESS_MODE_LBA 1
|
||||||
|
#define ADDRESS_MODE_LBA48 2
|
||||||
|
int drive_exists;
|
||||||
|
int slave_absent;
|
||||||
|
int basedrive;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define IDE_SECTOR_SIZE 0x200
|
||||||
|
|
||||||
|
#define IDE_BASE0 (0x1F0u) /* primary controller */
|
||||||
|
#define IDE_BASE1 (0x170u) /* secondary */
|
||||||
|
#define IDE_BASE2 (0x0F0u) /* third */
|
||||||
|
#define IDE_BASE3 (0x070u) /* fourth */
|
||||||
|
|
||||||
|
#define IDE_REG_EXTENDED_OFFSET (0x204u)
|
||||||
|
|
||||||
|
#define IDE_REG_DATA(ctrl) ((ctrl)->cmd_base + 0u) /* word register */
|
||||||
|
#define IDE_REG_ERROR(ctrl) ((ctrl)->cmd_base + 1u)
|
||||||
|
#define IDE_REG_PRECOMP(ctrl) ((ctrl)->cmd_base + 1u)
|
||||||
|
#define IDE_REG_FEATURE(ctrl) ((ctrl)->cmd_base + 1u)
|
||||||
|
#define IDE_REG_SECTOR_COUNT(ctrl) ((ctrl)->cmd_base + 2u)
|
||||||
|
#define IDE_REG_SECTOR_NUMBER(ctrl) ((ctrl)->cmd_base + 3u)
|
||||||
|
#define IDE_REG_LBA_LOW(ctrl) ((ctrl)->cmd_base + 3u)
|
||||||
|
#define IDE_REG_CYLINDER_LSB(ctrl) ((ctrl)->cmd_base + 4u)
|
||||||
|
#define IDE_REG_LBA_MID(ctrl) ((ctrl)->cmd_base + 4u)
|
||||||
|
#define IDE_REG_CYLINDER_MSB(ctrl) ((ctrl)->cmd_base + 5u)
|
||||||
|
#define IDE_REG_LBA_HIGH(ctrl) ((ctrl)->cmd_base + 5u)
|
||||||
|
#define IDE_REG_DRIVEHEAD(ctrl) ((ctrl)->cmd_base + 6u)
|
||||||
|
#define IDE_REG_DEVICE(ctrl) ((ctrl)->cmd_base + 6u)
|
||||||
|
#define IDE_REG_STATUS(ctrl) ((ctrl)->cmd_base + 7u)
|
||||||
|
#define IDE_REG_COMMAND(ctrl) ((ctrl)->cmd_base + 7u)
|
||||||
|
#define IDE_REG_ALTSTATUS(ctrl) ((ctrl)->ctrl_base + 2u)
|
||||||
|
#define IDE_REG_DEVICE_CONTROL(ctrl) ((ctrl)->ctrl_base + 2u)
|
||||||
|
|
||||||
|
struct ide_pio_command
|
||||||
|
{
|
||||||
|
uint8_t feature;
|
||||||
|
uint8_t sector_count;
|
||||||
|
uint8_t lba_low;
|
||||||
|
uint8_t lba_mid;
|
||||||
|
uint8_t lba_high;
|
||||||
|
uint8_t device;
|
||||||
|
# define IDE_DH_DEFAULT (0xA0)
|
||||||
|
# define IDE_DH_HEAD(x) ((x) & 0x0F)
|
||||||
|
# define IDE_DH_MASTER (0x00)
|
||||||
|
# define IDE_DH_SLAVE (0x10)
|
||||||
|
# define IDE_DH_LBA (0x40)
|
||||||
|
# define IDE_DH_CHS (0x00)
|
||||||
|
uint8_t command;
|
||||||
|
uint8_t sector_count2;
|
||||||
|
uint8_t lba_low2;
|
||||||
|
uint8_t lba_mid2;
|
||||||
|
uint8_t lba_high2;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define IDE_DEFAULT_COMMAND { 0xFFu, 0x01, 0x00, 0x0000, IDE_DH_DEFAULT }
|
||||||
|
|
||||||
|
#define IDE_ERR_ICRC 0x80 /* ATA Ultra DMA bad CRC */
|
||||||
|
#define IDE_ERR_BBK 0x80 /* ATA bad block */
|
||||||
|
#define IDE_ERR_UNC 0x40 /* ATA uncorrected error */
|
||||||
|
#define IDE_ERR_MC 0x20 /* ATA media change */
|
||||||
|
#define IDE_ERR_IDNF 0x10 /* ATA id not found */
|
||||||
|
#define IDE_ERR_MCR 0x08 /* ATA media change request */
|
||||||
|
#define IDE_ERR_ABRT 0x04 /* ATA command aborted */
|
||||||
|
#define IDE_ERR_NTK0 0x02 /* ATA track 0 not found */
|
||||||
|
#define IDE_ERR_NDAM 0x01 /* ATA address mark not found */
|
||||||
|
|
||||||
|
#define IDE_STATUS_BSY 0x80 /* busy */
|
||||||
|
#define IDE_STATUS_RDY 0x40 /* ready */
|
||||||
|
#define IDE_STATUS_DF 0x20 /* device fault */
|
||||||
|
#define IDE_STATUS_WFT 0x20 /* write fault (old name) */
|
||||||
|
#define IDE_STATUS_SKC 0x10 /* seek complete */
|
||||||
|
#define IDE_STATUS_DRQ 0x08 /* data request */
|
||||||
|
#define IDE_STATUS_CORR 0x04 /* corrected */
|
||||||
|
#define IDE_STATUS_IDX 0x02 /* index */
|
||||||
|
#define IDE_STATUS_ERR 0x01 /* error (ATA) */
|
||||||
|
#define IDE_STATUS_CHK 0x01 /* check (ATAPI) */
|
||||||
|
|
||||||
|
#define IDE_CTRL_HD15 0x08 /* bit should always be set to one */
|
||||||
|
#define IDE_CTRL_SRST 0x04 /* soft reset */
|
||||||
|
#define IDE_CTRL_NIEN 0x02 /* disable interrupts */
|
||||||
|
|
||||||
|
|
||||||
|
/* Most mandtory and optional ATA commands (from ATA-3), */
|
||||||
|
|
||||||
|
#define IDE_CMD_CFA_ERASE_SECTORS 0xC0
|
||||||
|
#define IDE_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
|
||||||
|
#define IDE_CMD_CFA_TRANSLATE_SECTOR 0x87
|
||||||
|
#define IDE_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
|
||||||
|
#define IDE_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
|
||||||
|
#define IDE_CMD_CHECK_POWER_MODE1 0xE5
|
||||||
|
#define IDE_CMD_CHECK_POWER_MODE2 0x98
|
||||||
|
#define IDE_CMD_DEVICE_RESET 0x08
|
||||||
|
#define IDE_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
|
||||||
|
#define IDE_CMD_FLUSH_CACHE 0xE7
|
||||||
|
#define IDE_CMD_FORMAT_TRACK 0x50
|
||||||
|
#define IDE_CMD_IDENTIFY_DEVICE 0xEC
|
||||||
|
#define IDE_CMD_IDENTIFY_DEVICE_PACKET 0xA1
|
||||||
|
#define IDE_CMD_IDENTIFY_PACKET_DEVICE 0xA1
|
||||||
|
#define IDE_CMD_IDLE1 0xE3
|
||||||
|
#define IDE_CMD_IDLE2 0x97
|
||||||
|
#define IDE_CMD_IDLE_IMMEDIATE1 0xE1
|
||||||
|
#define IDE_CMD_IDLE_IMMEDIATE2 0x95
|
||||||
|
#define IDE_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
|
||||||
|
#define IDE_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
|
||||||
|
#define IDE_CMD_NOP 0x00
|
||||||
|
#define IDE_CMD_PACKET 0xA0
|
||||||
|
#define IDE_CMD_READ_BUFFER 0xE4
|
||||||
|
#define IDE_CMD_READ_DMA 0xC8
|
||||||
|
#define IDE_CMD_READ_DMA_QUEUED 0xC7
|
||||||
|
#define IDE_CMD_READ_MULTIPLE 0xC4
|
||||||
|
#define IDE_CMD_READ_SECTORS 0x20
|
||||||
|
#define IDE_CMD_READ_SECTORS_EXT 0x24
|
||||||
|
#define IDE_CMD_READ_VERIFY_SECTORS 0x40
|
||||||
|
#define IDE_CMD_RECALIBRATE 0x10
|
||||||
|
#define IDE_CMD_SEEK 0x70
|
||||||
|
#define IDE_CMD_SET_FEATURES 0xEF
|
||||||
|
#define IDE_CMD_SET_MAX_ADDR_EXT 0x24
|
||||||
|
#define IDE_CMD_SET_MULTIPLE_MODE 0xC6
|
||||||
|
#define IDE_CMD_SLEEP1 0xE6
|
||||||
|
#define IDE_CMD_SLEEP2 0x99
|
||||||
|
#define IDE_CMD_STANDBY1 0xE2
|
||||||
|
#define IDE_CMD_STANDBY2 0x96
|
||||||
|
#define IDE_CMD_STANDBY_IMMEDIATE1 0xE0
|
||||||
|
#define IDE_CMD_STANDBY_IMMEDIATE2 0x94
|
||||||
|
#define IDE_CMD_WRITE_BUFFER 0xE8
|
||||||
|
#define IDE_CMD_WRITE_DMA 0xCA
|
||||||
|
#define IDE_CMD_WRITE_DMA_QUEUED 0xCC
|
||||||
|
#define IDE_CMD_WRITE_MULTIPLE 0xC5
|
||||||
|
#define IDE_CMD_WRITE_SECTORS 0x30
|
||||||
|
#define IDE_CMD_WRITE_VERIFY 0x3C
|
||||||
|
|
||||||
|
/* IDE_CMD_SET_FEATURE sub commands */
|
||||||
|
#define IDE_FEATURE_CFA_ENABLE_8BIT_PIO 0x01
|
||||||
|
#define IDE_FEATURE_ENABLE_WRITE_CACHE 0x02
|
||||||
|
#define IDE_FEATURE_SET_TRANSFER_MODE 0x03
|
||||||
|
#define IDE_FEATURE_ENABLE_POWER_MANAGEMENT 0x05
|
||||||
|
#define IDE_FEATURE_ENABLE_POWERUP_IN_STANDBY 0x06
|
||||||
|
#define IDE_FEATURE_STANDBY_SPINUP_DRIVE 0x07
|
||||||
|
#define IDE_FEATURE_CFA_ENABLE_POWER_MODE1 0x0A
|
||||||
|
#define IDE_FEATURE_DISABLE_MEDIA_STATUS_NOTIFICATION 0x31
|
||||||
|
#define IDE_FEATURE_ENABLE_AUTOMATIC_ACOUSTIC_MANAGEMENT 0x42
|
||||||
|
#define IDE_FEATURE_SET_MAXIMUM_HOST_INTERFACE_SECTOR_TIMES 0x43
|
||||||
|
#define IDE_FEATURE_DISABLE_READ_LOOKAHEAD 0x55
|
||||||
|
#define IDE_FEATURE_ENABLE_RELEASE_INTERRUPT 0x5D
|
||||||
|
#define IDE_FEATURE_ENABLE_SERVICE_INTERRUPT 0x5E
|
||||||
|
#define IDE_FEATURE_DISABLE_REVERTING_TO_POWERON_DEFAULTS 0x66
|
||||||
|
#define IDE_FEATURE_CFA_DISABLE_8BIT_PIO 0x81
|
||||||
|
#define IDE_FEATURE_DISABLE_WRITE_CACHE 0x82
|
||||||
|
#define IDE_FEATURE_DISABLE_POWER_MANAGEMENT 0x85
|
||||||
|
#define IDE_FEATURE_DISABLE_POWERUP_IN_STANDBY 0x86
|
||||||
|
#define IDE_FEATURE_CFA_DISABLE_POWER_MODE1 0x8A
|
||||||
|
#define IDE_FEATURE_ENABLE_MEDIA_STATUS_NOTIFICATION 0x95
|
||||||
|
#define IDE_FEATURE_ENABLE_READ_LOOKAHEAD 0xAA
|
||||||
|
#define IDE_FEATURE_DISABLE_AUTOMATIC_ACOUSTIC_MANAGEMENT 0xC2
|
||||||
|
#define IDE_FEATURE_ENABLE_REVERTING_TO_POWERON_DEFAULTS 0xCC
|
||||||
|
#define IDE_FEATURE_DISABLE_SERVICE_INTERRUPT 0xDE
|
||||||
|
|
||||||
|
#define NUM_HD (4)
|
||||||
|
#define SECTOR_SIZE 512
|
||||||
|
#define SECTOR_SHIFT 9
|
||||||
|
|
||||||
|
/* Maximum block_size that may be set. */
|
||||||
|
#define DISK_BUFFER_SIZE (18 * SECTOR_SIZE)
|
||||||
|
|
||||||
|
extern struct harddisk_info harddisk_info[NUM_HD];
|
||||||
|
|
||||||
|
extern int ide_init(void);
|
||||||
|
extern int ide_read_sector(int driveno, void * buf, unsigned int sector,
|
||||||
|
int byte_offset, int n_bytes);
|
|
@ -0,0 +1,27 @@
|
||||||
|
# These are keyword-value pairs.
|
||||||
|
# a : separates the keyword from the value
|
||||||
|
# the value is arbitrary text delimited by newline.
|
||||||
|
# continuation, if needed, will be via the \ at the end of a line
|
||||||
|
# comments are indicated by a '#' as the first character.
|
||||||
|
# the keywords are case-INSENSITIVE
|
||||||
|
owner: Greg Watson
|
||||||
|
email: gwatson@lanl.gov
|
||||||
|
#status: One of unsupported, unstable, stable
|
||||||
|
status: unstable
|
||||||
|
explanation: currently under development
|
||||||
|
flash-types:
|
||||||
|
payload-types:
|
||||||
|
# e.g. linux, plan 9, wince, etc.
|
||||||
|
OS-types: linux
|
||||||
|
# e.g. "Plan 9 interrupts don't work on this chipset"
|
||||||
|
OS-issues:
|
||||||
|
console-types: serial
|
||||||
|
# vga is unsupported, unstable, or stable
|
||||||
|
vga: unsupported
|
||||||
|
# Last-known-good follows the internationl date standard: day/month/year
|
||||||
|
last-known-good: 19/04/2003
|
||||||
|
Comments:
|
||||||
|
Links:
|
||||||
|
Mainboard-revision:
|
||||||
|
# What other mainboards are like this one? List them here.
|
||||||
|
AKA:
|
|
@ -0,0 +1,36 @@
|
||||||
|
/* $Id$ */
|
||||||
|
/* Copyright 2000 AG Electronics Ltd. */
|
||||||
|
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
|
||||||
|
|
||||||
|
#ifndef _FLASH_H
|
||||||
|
#define _FLASH_H
|
||||||
|
|
||||||
|
struct flash_device;
|
||||||
|
|
||||||
|
typedef struct flash_fn
|
||||||
|
{
|
||||||
|
const char *(* identify)(struct flash_device *flash);
|
||||||
|
void *(* ptr)(void *data);
|
||||||
|
int (* erase_all)(void *data);
|
||||||
|
int (* erase)(void *data, unsigned offset, unsigned length);
|
||||||
|
int (* program)(void *data, unsigned offset, const void *source, unsigned length);
|
||||||
|
u8 ( *read_byte)(void *data, unsigned offset);
|
||||||
|
} flash_fn;
|
||||||
|
|
||||||
|
typedef struct flash_device
|
||||||
|
{
|
||||||
|
const flash_fn *fn;
|
||||||
|
char *tag;
|
||||||
|
void *data;
|
||||||
|
unsigned long base;
|
||||||
|
unsigned size;
|
||||||
|
unsigned erase_size;
|
||||||
|
unsigned store_size;
|
||||||
|
struct flash_device *next;
|
||||||
|
} flash_device;
|
||||||
|
|
||||||
|
int register_flash_device(const flash_fn *fn, char *tag, void *data);
|
||||||
|
flash_device *find_flash_device(const char *tag);
|
||||||
|
int init_flash_amd800(char *tag, unsigned base, unsigned spacing);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,37 @@
|
||||||
|
/* $Id$ */
|
||||||
|
/* Copyright 2000 AG Electronics Ltd. */
|
||||||
|
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
|
||||||
|
/* Definitions for nvram devices - these are flash or eeprom devices used to
|
||||||
|
store information across power cycles and resets. Though they are byte
|
||||||
|
addressable, writes must be committed to allow flash devices to write
|
||||||
|
complete sectors. */
|
||||||
|
|
||||||
|
#ifndef _NVRAM_H
|
||||||
|
#define _NVRAM_H
|
||||||
|
|
||||||
|
typedef struct nvram_device
|
||||||
|
{
|
||||||
|
unsigned (*size)(struct nvram_device *data);
|
||||||
|
int (*read_block)(struct nvram_device *dev, unsigned offset,
|
||||||
|
unsigned char *data, unsigned length);
|
||||||
|
int (*write_byte)(struct nvram_device *dev, unsigned offset, unsigned char byte);
|
||||||
|
void (*commit)(struct nvram_device *data);
|
||||||
|
void *data;
|
||||||
|
} nvram_device;
|
||||||
|
|
||||||
|
int nvram_init (nvram_device *dev);
|
||||||
|
void nvram_clear(void);
|
||||||
|
|
||||||
|
extern nvram_device pcrtc_nvram;
|
||||||
|
extern void nvram_putenv(const char *name, const char *value);
|
||||||
|
extern int nvram_getenv(const char *name, char *buffer, unsigned size);
|
||||||
|
|
||||||
|
typedef const struct nvram_constant
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
const char *value;
|
||||||
|
} nvram_constant;
|
||||||
|
|
||||||
|
extern nvram_constant hardcoded_environment[];
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,517 @@
|
||||||
|
/**************************************************
|
||||||
|
*
|
||||||
|
* copyright @ motorola, 1999
|
||||||
|
*
|
||||||
|
*************************************************/
|
||||||
|
#include <pci.h>
|
||||||
|
#include <printk.h>
|
||||||
|
#include <northbridge/motorola/mpc107/epic.h>
|
||||||
|
|
||||||
|
extern struct pci_ops pci_direct_ppc;
|
||||||
|
|
||||||
|
typedef void (*VOIDFUNCPTR) (void); /* ptr to function returning void */
|
||||||
|
struct SrcVecTable SrcVecTable[MAXVEC] = /* Addr/Vector cross-reference tbl */
|
||||||
|
{
|
||||||
|
{ EPIC_EX_INT0_VEC_REG, "External Direct/Serial Source 0"},
|
||||||
|
{ EPIC_EX_INT1_VEC_REG, "External Direct/Serial Source 1"},
|
||||||
|
{ EPIC_EX_INT2_VEC_REG, "External Direct/Serial Source 2"},
|
||||||
|
{ EPIC_EX_INT3_VEC_REG, "External Direct/Serial Source 3"},
|
||||||
|
{ EPIC_EX_INT4_VEC_REG, "External Direct/Serial Source 4"},
|
||||||
|
|
||||||
|
{ EPIC_SR_INT5_VEC_REG, "External Serial Source 5"},
|
||||||
|
{ EPIC_SR_INT6_VEC_REG, "External Serial Source 6"},
|
||||||
|
{ EPIC_SR_INT7_VEC_REG, "External Serial Source 7"},
|
||||||
|
{ EPIC_SR_INT8_VEC_REG, "External Serial Source 8"},
|
||||||
|
{ EPIC_SR_INT9_VEC_REG, "External Serial Source 9"},
|
||||||
|
{ EPIC_SR_INT10_VEC_REG, "External Serial Source 10"},
|
||||||
|
{ EPIC_SR_INT11_VEC_REG, "External Serial Source 11"},
|
||||||
|
{ EPIC_SR_INT12_VEC_REG, "External Serial Source 12"},
|
||||||
|
{ EPIC_SR_INT13_VEC_REG, "External Serial Source 13"},
|
||||||
|
{ EPIC_SR_INT14_VEC_REG, "External Serial Source 14"},
|
||||||
|
{ EPIC_SR_INT15_VEC_REG, "External Serial Source 15"},
|
||||||
|
|
||||||
|
{ EPIC_I2C_INT_VEC_REG, "Internal I2C Source"},
|
||||||
|
{ EPIC_DMA0_INT_VEC_REG, "Internal DMA0 Source"},
|
||||||
|
{ EPIC_DMA1_INT_VEC_REG, "Internal DMA1 Source"},
|
||||||
|
{ EPIC_MSG_INT_VEC_REG, "Internal Message Source"},
|
||||||
|
};
|
||||||
|
|
||||||
|
VOIDFUNCPTR intVecTbl[MAXVEC]; /* Interrupt vector table */
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* epicInit - Initialize the EPIC registers
|
||||||
|
*
|
||||||
|
* This routine resets the Global Configuration Register, thus it:
|
||||||
|
* - Disables all interrupts
|
||||||
|
* - Sets epic registers to reset values
|
||||||
|
* - Sets the value of the Processor Current Task Priority to the
|
||||||
|
* highest priority (0xF).
|
||||||
|
* epicInit then sets the EPIC operation mode to Mixed Mode (vs. Pass
|
||||||
|
* Through or 8259 compatible mode).
|
||||||
|
*
|
||||||
|
* If IRQType (input) is Direct IRQs:
|
||||||
|
* - IRQType is written to the SIE bit of the EPIC Interrupt
|
||||||
|
* Configuration register (ICR).
|
||||||
|
* - clkRatio is ignored.
|
||||||
|
* If IRQType is Serial IRQs:
|
||||||
|
* - both IRQType and clkRatio will be written to the ICR register
|
||||||
|
*/
|
||||||
|
|
||||||
|
void epicInit
|
||||||
|
(
|
||||||
|
unsigned int IRQType, /* Direct or Serial */
|
||||||
|
unsigned int clkRatio /* Clk Ratio for Serial IRQs */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ULONG tmp;
|
||||||
|
|
||||||
|
tmp = sysEUMBBARRead(EPIC_GLOBAL_REG);
|
||||||
|
tmp |= 0xa0000000; /* Set the Global Conf. register */
|
||||||
|
sysEUMBBARWrite(EPIC_GLOBAL_REG, tmp);
|
||||||
|
/*
|
||||||
|
* Wait for EPIC to reset - CLH
|
||||||
|
*/
|
||||||
|
while( (sysEUMBBARRead(EPIC_GLOBAL_REG) & 0x80000000) == 1);
|
||||||
|
sysEUMBBARWrite(EPIC_GLOBAL_REG, 0x20000000);
|
||||||
|
tmp = sysEUMBBARRead(EPIC_INT_CONF_REG); /* Read interrupt conf. reg */
|
||||||
|
|
||||||
|
if (IRQType == EPIC_DIRECT_IRQ) /* direct mode */
|
||||||
|
sysEUMBBARWrite(EPIC_INT_CONF_REG, tmp & 0xf7ffffff);
|
||||||
|
else /* Serial mode */
|
||||||
|
{
|
||||||
|
tmp = (clkRatio << 28) | 0x08000000; /* Set clock ratio */
|
||||||
|
sysEUMBBARWrite(EPIC_INT_CONF_REG, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (epicIntAck() != 0xff) /* Clear all pending interrupts */
|
||||||
|
epicEOI();
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* epicIntEnable - Enable an interrupt source
|
||||||
|
*
|
||||||
|
* This routine clears the mask bit of an external, an internal or
|
||||||
|
* a Timer register to enable the interrupt.
|
||||||
|
*
|
||||||
|
* RETURNS: None
|
||||||
|
*/
|
||||||
|
void epicIntEnable(int intVec)
|
||||||
|
{
|
||||||
|
ULONG tmp;
|
||||||
|
ULONG srAddr;
|
||||||
|
|
||||||
|
srAddr = SrcVecTable[intVec].srcAddr; /* Retrieve src Vec/Prio register */
|
||||||
|
tmp = sysEUMBBARRead(srAddr);
|
||||||
|
tmp &= ~EPIC_VEC_PRI_MASK; /* Clear the mask bit */
|
||||||
|
tmp |= (EPIC_VEC_PRI_DFLT_PRI << 16); /* Set priority to Default - CLH */
|
||||||
|
tmp |= intVec; /* Set Vector number */
|
||||||
|
sysEUMBBARWrite(srAddr, tmp);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* epicIntDisable - Disable an interrupt source
|
||||||
|
*
|
||||||
|
* This routine sets the mask bit of an external, an internal or
|
||||||
|
* a Timer register to disable the interrupt.
|
||||||
|
*
|
||||||
|
* RETURNS: OK or ERROR
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void epicIntDisable
|
||||||
|
(
|
||||||
|
int intVec /* Interrupt vector number */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
|
||||||
|
ULONG tmp, srAddr;
|
||||||
|
|
||||||
|
srAddr = SrcVecTable[intVec].srcAddr;
|
||||||
|
tmp = sysEUMBBARRead(srAddr);
|
||||||
|
tmp |= 0x80000000; /* Set the mask bit */
|
||||||
|
sysEUMBBARWrite(srAddr, tmp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* epicIntSourceConfig - Set properties of an interrupt source
|
||||||
|
*
|
||||||
|
* This function sets interrupt properites (Polarity, Sense, Interrupt
|
||||||
|
* Prority, and Interrupt Vector) of an Interrupt Source. The properties
|
||||||
|
* can be set when the current source is not in-request or in-service,
|
||||||
|
* which is determined by the Activity bit. This routine return ERROR
|
||||||
|
* if the the Activity bit is 1 (in-request or in-service).
|
||||||
|
*
|
||||||
|
* This function assumes that the Source Vector/Priority register (input)
|
||||||
|
* is a valid address.
|
||||||
|
*
|
||||||
|
* RETURNS: OK or ERROR
|
||||||
|
*/
|
||||||
|
|
||||||
|
int epicIntSourceConfig
|
||||||
|
(
|
||||||
|
int Vect, /* interrupt source vector number */
|
||||||
|
int Polarity, /* interrupt source polarity */
|
||||||
|
int Sense, /* interrupt source Sense */
|
||||||
|
int Prio /* interrupt source priority */
|
||||||
|
)
|
||||||
|
|
||||||
|
{
|
||||||
|
ULONG tmp, newVal;
|
||||||
|
ULONG actBit, srAddr;
|
||||||
|
|
||||||
|
srAddr = SrcVecTable[Vect].srcAddr;
|
||||||
|
tmp = sysEUMBBARRead(srAddr);
|
||||||
|
actBit = (tmp & 40000000) >> 30; /* retrieve activity bit - bit 30 */
|
||||||
|
if (actBit == 1)
|
||||||
|
return ERROR;
|
||||||
|
|
||||||
|
tmp &= 0xff30ff00; /* Erase previously set P,S,Prio,Vector bits */
|
||||||
|
newVal = (Polarity << 23) | (Sense << 22) | (Prio << 16) | Vect;
|
||||||
|
sysEUMBBARWrite(srAddr, tmp | newVal );
|
||||||
|
return (OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* epicIntAck - acknowledge an interrupt
|
||||||
|
*
|
||||||
|
* This function reads the Interrupt acknowldge register and return
|
||||||
|
* the vector number of the highest pending interrupt.
|
||||||
|
*
|
||||||
|
* RETURNS: Interrupt Vector number.
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned int epicIntAck(void)
|
||||||
|
{
|
||||||
|
return(sysEUMBBARRead( EPIC_PROC_INT_ACK_REG ));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* epicEOI - signal an end of interrupt
|
||||||
|
*
|
||||||
|
* This function writes 0x0 to the EOI register to signal end of interrupt.
|
||||||
|
* It is usually called after an interrupt routine is served.
|
||||||
|
*
|
||||||
|
* RETURNS: None
|
||||||
|
*/
|
||||||
|
|
||||||
|
void epicEOI(void)
|
||||||
|
{
|
||||||
|
sysEUMBBARWrite(EPIC_PROC_EOI_REG, 0x0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* epicCurTaskPrioSet - sets the priority of the Processor Current Task
|
||||||
|
*
|
||||||
|
* This function should be called after epicInit() to lower the priority
|
||||||
|
* of the processor current task.
|
||||||
|
*
|
||||||
|
* RETURNS: OK or ERROR
|
||||||
|
*/
|
||||||
|
|
||||||
|
int epicCurTaskPrioSet
|
||||||
|
(
|
||||||
|
int prioNum /* New priority value */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ( (prioNum < 0) || (prioNum > 0xF))
|
||||||
|
return ERROR;
|
||||||
|
sysEUMBBARWrite(EPIC_PROC_CTASK_PRI_REG, prioNum);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
* function: epicIntTaskGet
|
||||||
|
*
|
||||||
|
* description: Get value of processor current interrupt task priority register
|
||||||
|
*
|
||||||
|
* note:
|
||||||
|
***********************************************************************/
|
||||||
|
unsigned char epicIntTaskGet()
|
||||||
|
{
|
||||||
|
/* get the interrupt task priority register */
|
||||||
|
ULONG reg;
|
||||||
|
unsigned char rec;
|
||||||
|
|
||||||
|
reg = sysEUMBBARRead( EPIC_PROC_CTASK_PRI_REG );
|
||||||
|
rec = ( reg & 0x0F );
|
||||||
|
return rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
* function: epicISR
|
||||||
|
*
|
||||||
|
* description: EPIC service routine called by the core exception
|
||||||
|
* at 0x500
|
||||||
|
*
|
||||||
|
* note:
|
||||||
|
**************************************************************/
|
||||||
|
unsigned int epicISR(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* function: epicModeGet
|
||||||
|
*
|
||||||
|
* description: query EPIC mode, return 0 if pass through mode
|
||||||
|
* return 1 if mixed mode
|
||||||
|
*
|
||||||
|
* note:
|
||||||
|
*************************************************************/
|
||||||
|
unsigned int epicModeGet(void)
|
||||||
|
{
|
||||||
|
ULONG val;
|
||||||
|
|
||||||
|
val = sysEUMBBARRead( EPIC_GLOBAL_REG );
|
||||||
|
return (( val & 0x20000000 ) >> 29);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************************
|
||||||
|
* function: epicConfigGet
|
||||||
|
*
|
||||||
|
* description: Get the EPIC interrupt Configuration
|
||||||
|
* return 0 if not error, otherwise return 1
|
||||||
|
*
|
||||||
|
* note:
|
||||||
|
********************************************/
|
||||||
|
void epicConfigGet( unsigned int *clkRatio, unsigned int *serEnable)
|
||||||
|
{
|
||||||
|
ULONG val;
|
||||||
|
|
||||||
|
val = sysEUMBBARRead( EPIC_INT_CONF_REG );
|
||||||
|
*clkRatio = ( val & 0x70000000 ) >> 28;
|
||||||
|
*serEnable = ( val & 0x8000000 ) >> 27;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************
|
||||||
|
* sysEUMBBARRead - Read a 32-bit EUMBBAR register
|
||||||
|
*
|
||||||
|
* This routine reads the content of a register in the Embedded
|
||||||
|
* Utilities Memory Block, and swaps to big endian before returning
|
||||||
|
* the value.
|
||||||
|
*
|
||||||
|
* RETURNS: The content of the specified EUMBBAR register.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ULONG sysEUMBBARRead
|
||||||
|
(
|
||||||
|
ULONG regNum
|
||||||
|
)
|
||||||
|
{
|
||||||
|
u32 temp;
|
||||||
|
|
||||||
|
pci_direct_ppc.read_dword(0, 0, regNum, &temp);
|
||||||
|
return ( temp );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************
|
||||||
|
* sysEUMBBARWrite - Write a 32-bit EUMBBAR register
|
||||||
|
*
|
||||||
|
* This routine swaps the value to little endian then writes it to
|
||||||
|
* a register in the Embedded Utilities Memory Block address space.
|
||||||
|
*
|
||||||
|
* RETURNS: N/A
|
||||||
|
*/
|
||||||
|
|
||||||
|
void sysEUMBBARWrite
|
||||||
|
(
|
||||||
|
ULONG regNum, /* EUMBBAR register address */
|
||||||
|
u32 regVal /* Value to be written */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
|
||||||
|
pci_direct_ppc.read_dword(0, 0, regNum, ®Val);
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************
|
||||||
|
* function: epicVendorId
|
||||||
|
*
|
||||||
|
* description: return the EPIC Vendor Identification
|
||||||
|
* register:
|
||||||
|
*
|
||||||
|
* siliccon version, device id, and vendor id
|
||||||
|
*
|
||||||
|
* note:
|
||||||
|
********************************************************/
|
||||||
|
void epicVendorId
|
||||||
|
(
|
||||||
|
unsigned int *step,
|
||||||
|
unsigned int *devId,
|
||||||
|
unsigned int *venId
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ULONG val;
|
||||||
|
val = sysEUMBBARRead( EPIC_VENDOR_ID_REG );
|
||||||
|
*step = ( val & 0x00FF0000 ) >> 16;
|
||||||
|
*devId = ( val & 0x0000FF00 ) >> 8;
|
||||||
|
*venId = ( val & 0x000000FF );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************
|
||||||
|
* function: epicFeatures
|
||||||
|
*
|
||||||
|
* description: return the number of IRQ supported,
|
||||||
|
* number of CPU, and the version of the
|
||||||
|
* OpenEPIC
|
||||||
|
*
|
||||||
|
* note:
|
||||||
|
*************************************************/
|
||||||
|
void epicFeatures
|
||||||
|
(
|
||||||
|
unsigned int *noIRQs,
|
||||||
|
unsigned int *noCPUs,
|
||||||
|
unsigned int *verId
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ULONG val;
|
||||||
|
|
||||||
|
val = sysEUMBBARRead( EPIC_FEATURES_REG );
|
||||||
|
*noIRQs = ( val & 0x07FF0000 ) >> 16;
|
||||||
|
*noCPUs = ( val & 0x00001F00 ) >> 8;
|
||||||
|
*verId = ( val & 0x000000FF );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************************************
|
||||||
|
* function: epciTmFrequncySet
|
||||||
|
*
|
||||||
|
* description: Set the timer frequency reporting register
|
||||||
|
********************************************************/
|
||||||
|
void epicTmFrequencySet( unsigned int frq )
|
||||||
|
{
|
||||||
|
sysEUMBBARWrite(EPIC_TM_FREQ_REG, frq);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************
|
||||||
|
* function: epicTmFrequncyGet
|
||||||
|
*
|
||||||
|
* description: Get the current value of the Timer Frequency
|
||||||
|
* Reporting register
|
||||||
|
*
|
||||||
|
******************************************************/
|
||||||
|
unsigned int epicTmFrequencyGet(void)
|
||||||
|
{
|
||||||
|
return( sysEUMBBARRead(EPIC_TM_FREQ_REG)) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************
|
||||||
|
* function: epicTmBaseSet
|
||||||
|
*
|
||||||
|
* description: Set the #n global timer base count register
|
||||||
|
* return 0 if no error, otherwise return 1.
|
||||||
|
*
|
||||||
|
* note:
|
||||||
|
****************************************************/
|
||||||
|
unsigned int epicTmBaseSet
|
||||||
|
(
|
||||||
|
ULONG srcAddr, /* Address of the Timer Base register */
|
||||||
|
unsigned int cnt, /* Base count */
|
||||||
|
unsigned int inhibit /* 1 - count inhibit */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
|
||||||
|
unsigned int val = 0x80000000;
|
||||||
|
/* First inhibit counting the timer */
|
||||||
|
sysEUMBBARWrite(srcAddr, val) ;
|
||||||
|
|
||||||
|
/* set the new value */
|
||||||
|
val = (cnt & 0x7fffffff) | ((inhibit & 0x1) << 31);
|
||||||
|
sysEUMBBARWrite(srcAddr, val) ;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* function: epicTmBaseGet
|
||||||
|
*
|
||||||
|
* description: Get the current value of the global timer base count register
|
||||||
|
* return 0 if no error, otherwise return 1.
|
||||||
|
*
|
||||||
|
* note:
|
||||||
|
***********************************************************************/
|
||||||
|
unsigned int epicTmBaseGet( ULONG srcAddr, unsigned int *val )
|
||||||
|
{
|
||||||
|
*val = sysEUMBBARRead( srcAddr );
|
||||||
|
*val = *val & 0x7fffffff;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************
|
||||||
|
* function: epicTmCountGet
|
||||||
|
*
|
||||||
|
* description: Get the value of a given global timer
|
||||||
|
* current count register
|
||||||
|
* return 0 if no error, otherwise return 1
|
||||||
|
* note:
|
||||||
|
**********************************************************/
|
||||||
|
unsigned int epicTmCountGet( ULONG srcAddr, unsigned int *val )
|
||||||
|
{
|
||||||
|
*val = sysEUMBBARRead( srcAddr );
|
||||||
|
*val = *val & 0x7fffffff;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************
|
||||||
|
* function: epicTmInhibit
|
||||||
|
*
|
||||||
|
* description: Stop counting of a given global timer
|
||||||
|
* return 0 if no error, otherwise return 1
|
||||||
|
*
|
||||||
|
* note:
|
||||||
|
***********************************************************/
|
||||||
|
unsigned int epicTmInhibit( unsigned int srcAddr )
|
||||||
|
{
|
||||||
|
ULONG val;
|
||||||
|
|
||||||
|
val = sysEUMBBARRead( srcAddr );
|
||||||
|
val |= 0x80000000;
|
||||||
|
sysEUMBBARWrite( srcAddr, val );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* function: epicTmEnable
|
||||||
|
*
|
||||||
|
* description: Enable counting of a given global timer
|
||||||
|
* return 0 if no error, otherwise return 1
|
||||||
|
*
|
||||||
|
* note:
|
||||||
|
*****************************************************************/
|
||||||
|
unsigned int epicTmEnable( ULONG srcAddr )
|
||||||
|
{
|
||||||
|
ULONG val;
|
||||||
|
|
||||||
|
val = sysEUMBBARRead( srcAddr );
|
||||||
|
val &= 0x7fffffff;
|
||||||
|
sysEUMBBARWrite( srcAddr, val );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void epicSourcePrint(int Vect)
|
||||||
|
{
|
||||||
|
ULONG srcVal;
|
||||||
|
|
||||||
|
srcVal = sysEUMBBARRead(SrcVecTable[Vect].srcAddr);
|
||||||
|
printk_info("%s\n", SrcVecTable[Vect].srcName);
|
||||||
|
printk_info("Address = 0x%lx\n", SrcVecTable[Vect].srcAddr);
|
||||||
|
printk_info("Vector = %ld\n", (srcVal & 0x000000FF) );
|
||||||
|
printk_info("Mask = %ld\n", srcVal >> 31);
|
||||||
|
printk_info("Activitiy = %ld\n", (srcVal & 40000000) >> 30);
|
||||||
|
printk_info("Polarity = %ld\n", (srcVal & 0x00800000) >> 23);
|
||||||
|
printk_info("Sense = %ld\n", (srcVal & 0x00400000) >> 22);
|
||||||
|
printk_info("Priority = %ld\n", (srcVal & 0x000F0000) >> 16);
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
/* $Id$
|
||||||
|
* (C) Copyright 2002
|
||||||
|
* Humboldt Solutions Ltd, <adrian@humboldt.co.uk>
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "i2c.h"
|
||||||
|
|
||||||
|
static i2c_bus *first_i2c = NULL;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
int register_i2c_bus(const i2c_fn *fn, char *tag, void *data)
|
||||||
|
{
|
||||||
|
i2c_bus *bus = malloc (sizeof (i2c_bus));
|
||||||
|
|
||||||
|
if (bus)
|
||||||
|
{
|
||||||
|
bus->fn = fn;
|
||||||
|
bus->tag = tag;
|
||||||
|
bus->data = data;
|
||||||
|
bus->next = first_i2c;
|
||||||
|
first_i2c = bus;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
i2c_bus *find_i2c_bus(const char *name)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if (! name)
|
||||||
|
return first_i2c;
|
||||||
|
|
||||||
|
if (first_i2c)
|
||||||
|
{
|
||||||
|
i2c_bus *i2c;
|
||||||
|
|
||||||
|
len = strlen(name);
|
||||||
|
|
||||||
|
for (i2c = first_i2c; i2c; i2c = i2c->next)
|
||||||
|
if (strlen(i2c->tag) == len && memcmp (name, i2c->tag, len) == 0)
|
||||||
|
return i2c;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void i2c_start(struct i2c_bus *bus)
|
||||||
|
{
|
||||||
|
if (! bus)
|
||||||
|
bus = first_i2c;
|
||||||
|
|
||||||
|
bus->fn->start(bus);
|
||||||
|
}
|
||||||
|
|
||||||
|
void i2c_stop(struct i2c_bus *bus)
|
||||||
|
{
|
||||||
|
if (! bus)
|
||||||
|
bus = first_i2c;
|
||||||
|
|
||||||
|
bus->fn->stop(bus);
|
||||||
|
}
|
||||||
|
|
||||||
|
int i2c_master_write(struct i2c_bus *bus, int target, int address,
|
||||||
|
const u8 *data, int length)
|
||||||
|
{
|
||||||
|
if (! bus)
|
||||||
|
bus = first_i2c;
|
||||||
|
|
||||||
|
return bus->fn->master_write(bus, target, address, data, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
int i2c_master_read(struct i2c_bus *bus, int target, int address,
|
||||||
|
u8 *data, int length)
|
||||||
|
{
|
||||||
|
if (! bus)
|
||||||
|
bus = first_i2c;
|
||||||
|
|
||||||
|
return bus->fn->master_read(bus, target, address, data, length);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
/* $Id$
|
||||||
|
* (C) Copyright 2002
|
||||||
|
* Humboldt Solutions Ltd, <adrian@humboldt.co.uk>
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _I2C_H
|
||||||
|
#define _I2C_H
|
||||||
|
|
||||||
|
struct i2c_bus;
|
||||||
|
|
||||||
|
typedef struct i2c_fn
|
||||||
|
{
|
||||||
|
void (* start)(struct i2c_bus *bus);
|
||||||
|
void (* stop)(struct i2c_bus *bus);
|
||||||
|
int (* master_write)(struct i2c_bus *bus, int target, int address,
|
||||||
|
const u8 *data, int length);
|
||||||
|
int (* master_read)(struct i2c_bus *bus, int target, int address,
|
||||||
|
u8 *data, int length);
|
||||||
|
} i2c_fn;
|
||||||
|
|
||||||
|
typedef struct i2c_bus
|
||||||
|
{
|
||||||
|
const i2c_fn *fn;
|
||||||
|
char *tag;
|
||||||
|
void *data;
|
||||||
|
struct i2c_bus *next;
|
||||||
|
} i2c_bus;
|
||||||
|
|
||||||
|
i2c_bus *find_i2c_bus(const char *name);
|
||||||
|
int register_i2c_bus(const i2c_fn *fn, char *tag, void *data);
|
||||||
|
|
||||||
|
void i2c_start(struct i2c_bus *bus);
|
||||||
|
void i2c_stop(struct i2c_bus *bus);
|
||||||
|
int i2c_master_write(struct i2c_bus *bus, int target, int address,
|
||||||
|
const u8 *data, int length);
|
||||||
|
int i2c_master_read(struct i2c_bus *bus, int target, int address,
|
||||||
|
u8 *data, int length);
|
||||||
|
void init_i2c_nvram(const char *i2c_tag);
|
||||||
|
|
||||||
|
extern i2c_fn mpc107_i2c_fn;
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,202 @@
|
||||||
|
/*
|
||||||
|
* (C) Copyright 2001
|
||||||
|
* Humboldt Solutions Ltd, adrian@humboldt.co.uk.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <printk.h>
|
||||||
|
#include "mpc107.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
sdram_dimm_to_bank_info(const char *data, sdram_dimm_info *dimm, int verbose)
|
||||||
|
{
|
||||||
|
sdram_bank_info *bank1 = dimm->bank1;
|
||||||
|
sdram_bank_info *bank2 = dimm->bank2;
|
||||||
|
unsigned char csum = 0;
|
||||||
|
unsigned char x;
|
||||||
|
int i;
|
||||||
|
int no_cas_latencies = 0;
|
||||||
|
char latency[3];
|
||||||
|
|
||||||
|
/* Mark banks initially broken */
|
||||||
|
bank1->size = 0;
|
||||||
|
bank2->size = 0;
|
||||||
|
|
||||||
|
if (data[0] < 64)
|
||||||
|
{
|
||||||
|
if (verbose)
|
||||||
|
printk_info("SPD data too short\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < 63; i++)
|
||||||
|
csum += data[i];
|
||||||
|
|
||||||
|
if (csum != data[63])
|
||||||
|
{
|
||||||
|
if (verbose)
|
||||||
|
printk_info("Broken checksum\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[2] != 0x04)
|
||||||
|
{
|
||||||
|
if (verbose)
|
||||||
|
printk_info("SDRAM Only\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bank1->row_bits = data[3] & 0x0f;
|
||||||
|
if (data[3] >> 4)
|
||||||
|
bank2->row_bits = data[3] >> 4;
|
||||||
|
else
|
||||||
|
bank2->row_bits = bank1->row_bits;
|
||||||
|
|
||||||
|
bank1->internal_banks = bank2->internal_banks = data[17];
|
||||||
|
|
||||||
|
bank1->col_bits = data[4] & 0x0f;
|
||||||
|
if (data[4] >> 4)
|
||||||
|
bank2->col_bits = data[4] >> 4;
|
||||||
|
else
|
||||||
|
bank2->col_bits = bank1->col_bits;
|
||||||
|
|
||||||
|
if (data[7] || (data[6] != 80 && data[6] != 72 && data[6] != 64))
|
||||||
|
{
|
||||||
|
if (verbose)
|
||||||
|
printk_info("Data width incorrect\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[8] != 0x01)
|
||||||
|
{
|
||||||
|
if (verbose)
|
||||||
|
printk_info("3.3V TTL DIMMS only\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extract CAS latencies in reverse order, as we only get info on
|
||||||
|
the highest ones. */
|
||||||
|
x = data[18];
|
||||||
|
for(i = 7; i > 0; i--)
|
||||||
|
{
|
||||||
|
if (x & 0x40)
|
||||||
|
{
|
||||||
|
if (no_cas_latencies < 3)
|
||||||
|
latency[no_cas_latencies] = i;
|
||||||
|
no_cas_latencies++;
|
||||||
|
}
|
||||||
|
x <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now fill in other timings - we're most interested in the lowest
|
||||||
|
CAS latency, so we shuffle data to put that first. */
|
||||||
|
for(i = no_cas_latencies; i >= 0; i--)
|
||||||
|
bank1->cas_latency[no_cas_latencies - i - 1] =
|
||||||
|
bank2->cas_latency[no_cas_latencies - i - 1] =
|
||||||
|
latency[i];
|
||||||
|
for(i = no_cas_latencies; i < 3; i++)
|
||||||
|
bank1->cas_latency[i] = bank2->cas_latency[i] = 0;
|
||||||
|
|
||||||
|
/* Store values for the highest cas latency */
|
||||||
|
bank1->cycle_time[no_cas_latencies - 1] =
|
||||||
|
bank2->cycle_time[no_cas_latencies- 1] =
|
||||||
|
100 * (data[9] >> 4) + 10 * (data[9] & 0xf);
|
||||||
|
bank1->access_time[no_cas_latencies - 1] =
|
||||||
|
bank2->access_time[no_cas_latencies - 1] =
|
||||||
|
100 * (data[10] >> 4) + 10 * (data[10] & 0xf);
|
||||||
|
/* Then the second highest */
|
||||||
|
if (no_cas_latencies > 1)
|
||||||
|
{
|
||||||
|
bank1->cycle_time[no_cas_latencies - 2] =
|
||||||
|
bank2->cycle_time[no_cas_latencies- 2] =
|
||||||
|
100 * (data[23] >> 4) + 10 * (data[23] & 0xf);
|
||||||
|
bank1->access_time[no_cas_latencies - 2] =
|
||||||
|
bank2->access_time[no_cas_latencies - 2] =
|
||||||
|
100 * (data[24] >> 4) + 10 * (data[24] & 0xf);
|
||||||
|
}
|
||||||
|
/* Then the third highest */
|
||||||
|
if (no_cas_latencies > 2)
|
||||||
|
{
|
||||||
|
bank1->cycle_time[no_cas_latencies - 3] =
|
||||||
|
bank2->cycle_time[no_cas_latencies- 3] =
|
||||||
|
100 * (data[25] >> 2) + 25 * (data[25] & 0x3);
|
||||||
|
bank1->access_time[no_cas_latencies - 3] =
|
||||||
|
bank2->access_time[no_cas_latencies - 3] =
|
||||||
|
100 * (data[26] >> 2) + 25 * (data[26] & 0x3);
|
||||||
|
}
|
||||||
|
if (verbose)
|
||||||
|
for(i = 0; i < no_cas_latencies; i++)
|
||||||
|
printk_info("CL %d: cycle %dns access %dns\n",
|
||||||
|
bank1->cas_latency[i], bank1->cycle_time[i] / 100,
|
||||||
|
bank1->access_time[i] / 100);
|
||||||
|
|
||||||
|
/* Other timings */
|
||||||
|
bank1->min_back_to_back = bank2->min_back_to_back = data[15];
|
||||||
|
bank1->min_row_precharge = bank2->min_row_precharge = data[27];
|
||||||
|
bank1->min_active_to_active = bank2->min_active_to_active = data[28];
|
||||||
|
bank1->min_ras_to_cas = bank2->min_ras_to_cas = data[29];
|
||||||
|
bank1->min_ras = bank2->min_ras = data[30];
|
||||||
|
|
||||||
|
/* Error detection type */
|
||||||
|
bank1->error_detect = bank2->error_detect = data[11];
|
||||||
|
|
||||||
|
/* Crucial row sizes - these mark the data as valid */
|
||||||
|
for(i = 7; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (data[31] & (1 << i))
|
||||||
|
{
|
||||||
|
bank1->size = (4*1024*1024) << i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (data[5] > 1)
|
||||||
|
{
|
||||||
|
for(i-- ; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (data[31] & (1 << i))
|
||||||
|
{
|
||||||
|
bank2->size = (4*1024*1024) << i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (! bank2->size)
|
||||||
|
bank2->size = bank1->size;
|
||||||
|
}
|
||||||
|
dimm->size = bank1->size + bank2->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
print_sdram_bank_info(const sdram_bank_info *bank)
|
||||||
|
{
|
||||||
|
printk_info("Bank %d: %dMB\n", bank->number, bank->size / (1024*1024));
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *error_types[] = {"", "Parity ", "ECC "};
|
||||||
|
|
||||||
|
void
|
||||||
|
print_sdram_dimm_info(const sdram_dimm_info *dimm)
|
||||||
|
{
|
||||||
|
printk_info("Dimm %d: ", dimm->number);
|
||||||
|
if (dimm->size)
|
||||||
|
printk_info("%dMB CL%d (%s): Running at CL%d %s\n",
|
||||||
|
dimm->size / (1024*1024), dimm->bank1->cas_latency[0],
|
||||||
|
dimm->part_number,
|
||||||
|
dimm->bank1->actual_cas,
|
||||||
|
error_types[dimm->bank1->actual_detect]);
|
||||||
|
else
|
||||||
|
printk_info("(none)\n");
|
||||||
|
}
|
|
@ -0,0 +1,487 @@
|
||||||
|
/*
|
||||||
|
* (C) Copyright 2001
|
||||||
|
* Humboldt Solutions Ltd, adrian@humboldt.co.uk.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
#include <bsp.h>
|
||||||
|
#include <ppc.h>
|
||||||
|
#include <pci.h>
|
||||||
|
#include <mem.h>
|
||||||
|
#include <types.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <printk.h>
|
||||||
|
#include <arch/io.h>
|
||||||
|
#include "i2c.h"
|
||||||
|
#include "mpc107.h"
|
||||||
|
#include <timer.h>
|
||||||
|
|
||||||
|
#define NUM_DIMMS 1
|
||||||
|
#define NUM_BANKS 2
|
||||||
|
|
||||||
|
extern struct pci_ops pci_direct_ppc;
|
||||||
|
|
||||||
|
struct mem_range *
|
||||||
|
getmeminfo(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
sdram_dimm_info dimm[NUM_DIMMS];
|
||||||
|
sdram_bank_info bank[NUM_BANKS];
|
||||||
|
static struct mem_range meminfo;
|
||||||
|
|
||||||
|
hostbridge_probe_dimms(NUM_DIMMS, dimm, bank);
|
||||||
|
|
||||||
|
meminfo.basek = 0;
|
||||||
|
meminfo.sizek = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_BANKS; i++) {
|
||||||
|
meminfo.sizek += bank[i].size;
|
||||||
|
}
|
||||||
|
|
||||||
|
meminfo.sizek >>= 10;
|
||||||
|
|
||||||
|
return &meminfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Memory is already turned on, but with pessimistic settings. Now
|
||||||
|
* we optimize settings to the actual memory configuration.
|
||||||
|
*/
|
||||||
|
unsigned
|
||||||
|
mpc107_config_memory(void)
|
||||||
|
{
|
||||||
|
sdram_dimm_info sdram_dimms[NUM_DIMMS];
|
||||||
|
sdram_bank_info sdram_banks[NUM_BANKS];
|
||||||
|
|
||||||
|
hostbridge_probe_dimms(NUM_DIMMS, sdram_dimms, sdram_banks);
|
||||||
|
return hostbridge_config_memory(NUM_BANKS, sdram_banks, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configure memory settings.
|
||||||
|
*/
|
||||||
|
unsigned long
|
||||||
|
hostbridge_config_memory(int no_banks, sdram_bank_info * bank, int for_real)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
char ignore[8];
|
||||||
|
/* Convert bus clock to cycle time in 100ns units */
|
||||||
|
unsigned cycle_time = 10 * (2500000000U / bsp_clock_speed());
|
||||||
|
/* Approximate */
|
||||||
|
unsigned access_time = cycle_time - 300;
|
||||||
|
unsigned cas_latency = 0;
|
||||||
|
unsigned rdlat;
|
||||||
|
unsigned refint;
|
||||||
|
unsigned refrec;
|
||||||
|
unsigned acttorw, acttopre;
|
||||||
|
unsigned pretoact, bstopre;
|
||||||
|
enum sdram_error_detect error_detect;
|
||||||
|
u32 mccr1;
|
||||||
|
u32 mccr2;
|
||||||
|
u32 mccr3;
|
||||||
|
u32 mccr4;
|
||||||
|
u8 bank_enable;
|
||||||
|
u32 memstart1, memstart2;
|
||||||
|
u32 extmemstart1, extmemstart2;
|
||||||
|
u32 memend1, memend2;
|
||||||
|
u32 extmemend1, extmemend2;
|
||||||
|
u32 address;
|
||||||
|
|
||||||
|
/* Set up the ignore mask */
|
||||||
|
for(i = 0; i < no_banks; i++)
|
||||||
|
ignore[i] = (bank[i].size == 0);
|
||||||
|
|
||||||
|
/* Pick best CAS latency possible */
|
||||||
|
for (i = 0; i < no_banks; i++)
|
||||||
|
{
|
||||||
|
if (! ignore[i])
|
||||||
|
{
|
||||||
|
for (j = 0; j < 3; j++)
|
||||||
|
{
|
||||||
|
if (cycle_time >= bank[i].cycle_time[j] &&
|
||||||
|
access_time >= bank[i].access_time[j])
|
||||||
|
{
|
||||||
|
cas_latency = bank[i].cas_latency[j];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!cas_latency)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* For various parameters there is a risk of clashing between banks */
|
||||||
|
error_detect = (for_real > 1) ? ERRORS_ECC : ERRORS_NONE;
|
||||||
|
for (i = 0; i < no_banks; i++)
|
||||||
|
{
|
||||||
|
if (! ignore[i])
|
||||||
|
{
|
||||||
|
{
|
||||||
|
for (j = 0; j < 3; j++)
|
||||||
|
if (bank[i].cas_latency[j] == cas_latency)
|
||||||
|
break;
|
||||||
|
if (j == 3)
|
||||||
|
{
|
||||||
|
ignore[i] = 1;
|
||||||
|
if (! for_real)
|
||||||
|
printk_info("Disabling memory bank %d (cas latency)\n", i);
|
||||||
|
}
|
||||||
|
if (bank[i].error_detect < error_detect)
|
||||||
|
error_detect = bank[i].error_detect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read in configuration of port X */
|
||||||
|
pci_direct_ppc.read_dword(0, 0, 0xf0, &mccr1);
|
||||||
|
pci_direct_ppc.read_dword(0, 0, 0xf4, &mccr2);
|
||||||
|
pci_direct_ppc.read_dword(0, 0, 0xfc, &mccr4);
|
||||||
|
mccr1 &= 0xfff00000;
|
||||||
|
mccr2 &= 0xffe00000;
|
||||||
|
mccr3 = 0;
|
||||||
|
mccr4 &= 0x00230000;
|
||||||
|
|
||||||
|
pretoact = 0;
|
||||||
|
acttorw = 0;
|
||||||
|
acttopre = 0;
|
||||||
|
for (i = 0; i < no_banks; i++)
|
||||||
|
if (! ignore[i])
|
||||||
|
{
|
||||||
|
int rowcode = -1;
|
||||||
|
if (for_real)
|
||||||
|
{
|
||||||
|
bank[i].actual_detect = error_detect;
|
||||||
|
bank[i].actual_cas = cas_latency;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (bank[i].row_bits) {
|
||||||
|
case 13:
|
||||||
|
if (bank[i].internal_banks == 4)
|
||||||
|
rowcode = 2;
|
||||||
|
else if (bank[i].internal_banks == 2)
|
||||||
|
rowcode = 1;
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
if (bank[i].internal_banks == 4)
|
||||||
|
rowcode = 0;
|
||||||
|
else if (bank[i].internal_banks == 2)
|
||||||
|
rowcode = 1;
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
if (bank[i].internal_banks == 4)
|
||||||
|
rowcode = 0;
|
||||||
|
else if (bank[i].internal_banks == 2)
|
||||||
|
rowcode = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (rowcode == -1) {
|
||||||
|
ignore[i] = 1;
|
||||||
|
if (! for_real)
|
||||||
|
printk_info("Memory bank %d disabled: row bits %d and banks %d not supported\n", i, bank[i].row_bits, bank[i].internal_banks);
|
||||||
|
} else
|
||||||
|
mccr1 |= rowcode << (2 * i);
|
||||||
|
|
||||||
|
/* Update worst case settings */
|
||||||
|
if (! ignore[i]) {
|
||||||
|
if (bank[i].min_row_precharge > pretoact)
|
||||||
|
pretoact = bank[i].min_row_precharge;
|
||||||
|
if (bank[i].min_ras_to_cas > acttorw)
|
||||||
|
acttorw = bank[i].min_ras_to_cas;
|
||||||
|
if (bank[i].min_ras > acttopre)
|
||||||
|
acttopre = bank[i].min_ras;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now convert to clock cycles, rounding up */
|
||||||
|
pretoact = (100 * pretoact + cycle_time - 1) / cycle_time;
|
||||||
|
acttopre = (100 * acttopre + cycle_time - 1) / cycle_time;
|
||||||
|
acttorw = (100 * acttorw + cycle_time - 1) / cycle_time;
|
||||||
|
refrec = acttopre;
|
||||||
|
bstopre = 0x240; /* Set conservative values, because we can't derive */
|
||||||
|
refint = 1000;
|
||||||
|
|
||||||
|
if (error_detect == ERRORS_ECC)
|
||||||
|
{
|
||||||
|
rdlat = cas_latency + 2;
|
||||||
|
mccr4 |= 0x00400000;
|
||||||
|
mccr2 |= 0x000c0001;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rdlat = cas_latency + 1;
|
||||||
|
mccr4 |= 0x00100000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pretoact > 16 || acttopre > 16 || acttorw > 16)
|
||||||
|
if (! for_real)
|
||||||
|
printk_info("Timings out of range\n");
|
||||||
|
mccr4 |= ((pretoact & 0x0f) << 28) | ((acttopre & 0xf) << 24) |
|
||||||
|
((acttorw & 0x0f) << 4) |
|
||||||
|
((bstopre & 0x003) << 18) | ((bstopre & 0x3c0) >> 6) |
|
||||||
|
(cas_latency << 12) | 0x00000200 /* burst length */ ;
|
||||||
|
mccr3 |= ((bstopre & 0x03c) << 26) |
|
||||||
|
((refrec & 0x0f) << 24) | (rdlat << 20);
|
||||||
|
mccr2 |= refint << 2;
|
||||||
|
mccr1 |= 0x00080000; /* memgo */
|
||||||
|
|
||||||
|
address = 0;
|
||||||
|
memstart1 = memstart2 = 0;
|
||||||
|
extmemstart1 = extmemstart2 = 0;
|
||||||
|
memend1 = memend2 = 0;
|
||||||
|
extmemend1 = extmemend2 = 0;
|
||||||
|
bank_enable = 0;
|
||||||
|
for (i = 0; i < no_banks; i++) {
|
||||||
|
if (! ignore[i]) {
|
||||||
|
u32 end = address + bank[i].size - 1;
|
||||||
|
bank_enable |= 1 << i;
|
||||||
|
if (i < 4) {
|
||||||
|
memstart1 |= ((address >> 20) & 0xff) << (8 * i);
|
||||||
|
extmemstart1 |= ((address >> 28) & 0x03) << (8 * i);
|
||||||
|
memend1 |= ((end >> 20) & 0xff) << (8 * i);
|
||||||
|
extmemend1 |= ((end >> 28) & 0x03) << (8 * i);
|
||||||
|
} else {
|
||||||
|
int k = i - 4;
|
||||||
|
memstart2 |= ((address >> 20) & 0xff) << (8 * k);
|
||||||
|
extmemstart2 |= ((address >> 28) & 0x03) << (8 * k);
|
||||||
|
memend2 |= ((end >> 20) & 0xff) << (8 * k);
|
||||||
|
extmemend2 |= ((end >> 28) & 0x03) << (8 * k);
|
||||||
|
}
|
||||||
|
address += bank[i].size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (for_real)
|
||||||
|
{
|
||||||
|
pci_direct_ppc.write_byte(0, 0, 0xa0, bank_enable);
|
||||||
|
pci_direct_ppc.write_dword(0, 0, 0x80, memstart1);
|
||||||
|
pci_direct_ppc.write_dword(0, 0, 0x84, memstart2);
|
||||||
|
pci_direct_ppc.write_dword(0, 0, 0x88, extmemstart1);
|
||||||
|
pci_direct_ppc.write_dword(0, 0, 0x8c, extmemstart2);
|
||||||
|
pci_direct_ppc.write_dword(0, 0, 0x90, memend1);
|
||||||
|
pci_direct_ppc.write_dword(0, 0, 0x94, memend2);
|
||||||
|
pci_direct_ppc.write_dword(0, 0, 0x98, extmemend1);
|
||||||
|
pci_direct_ppc.write_dword(0, 0, 0x9c, extmemend2);
|
||||||
|
|
||||||
|
pci_direct_ppc.write_dword(0, 0, 0xfc, mccr4);
|
||||||
|
pci_direct_ppc.write_dword(0, 0, 0xf8, mccr3);
|
||||||
|
pci_direct_ppc.write_dword(0, 0, 0xf4, mccr2);
|
||||||
|
pci_direct_ppc.write_dword(0, 0, 0xf0, mccr1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
i2c_wait(unsigned timeout, int writing)
|
||||||
|
{
|
||||||
|
u32 x;
|
||||||
|
while (((x = readl(MPC107_BASE + MPC107_I2CSR)) & (MPC107_I2C_CSR_MCF | MPC107_I2C_CSR_MIF))
|
||||||
|
!= (MPC107_I2C_CSR_MCF | MPC107_I2C_CSR_MIF)) {
|
||||||
|
if (ticks_since_boot() > timeout)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x & MPC107_I2C_CSR_MAL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (writing && (x & MPC107_I2C_CSR_RXAK)) {
|
||||||
|
printk_info("No RXAK\n");
|
||||||
|
/* generate stop */
|
||||||
|
writel(MPC107_I2C_CCR_MEN, MPC107_BASE + MPC107_I2CCR);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
writel(0, MPC107_BASE + MPC107_I2CSR);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mpc107_i2c_start(struct i2c_bus *bus)
|
||||||
|
{
|
||||||
|
/* Set clock */
|
||||||
|
writel(0x1031, MPC107_BASE + MPC107_I2CFDR);
|
||||||
|
/* Clear arbitration */
|
||||||
|
writel(0, MPC107_BASE + MPC107_I2CSR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mpc107_i2c_stop(struct i2c_bus *bus)
|
||||||
|
{
|
||||||
|
/* After last DIMM shut down I2C */
|
||||||
|
writel(0x0, MPC107_BASE + MPC107_I2CCR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mpc107_i2c_byte_write(struct i2c_bus *bus, int target, int address, u8 data)
|
||||||
|
{
|
||||||
|
unsigned timeout = ticks_since_boot() + 3 * get_hz();
|
||||||
|
|
||||||
|
/* Must wait here for clocks to start */
|
||||||
|
sleep_ticks(get_hz() / 40);
|
||||||
|
/* Start with MEN */
|
||||||
|
writel(MPC107_I2C_CCR_MEN, MPC107_BASE + MPC107_I2CCR);
|
||||||
|
/* Start as master */
|
||||||
|
writel(MPC107_I2C_CCR_MEN | MPC107_I2C_CCR_MSTA | MPC107_I2C_CCR_MTX, MPC107_BASE + MPC107_I2CCR);
|
||||||
|
/* Write target byte */
|
||||||
|
writel(target, MPC107_BASE + MPC107_I2CDR);
|
||||||
|
|
||||||
|
if (i2c_wait(timeout, 1) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Write data address byte */
|
||||||
|
writel(address, MPC107_BASE + MPC107_I2CDR);
|
||||||
|
|
||||||
|
if (i2c_wait(timeout, 1) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Write data byte */
|
||||||
|
writel(data, MPC107_BASE + MPC107_I2CDR);
|
||||||
|
|
||||||
|
if (i2c_wait(timeout, 1) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* generate stop */
|
||||||
|
writel(MPC107_I2C_CCR_MEN, MPC107_BASE + MPC107_I2CCR);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mpc107_i2c_master_write(struct i2c_bus *bus, int target, int address, const u8 *data, int length)
|
||||||
|
{
|
||||||
|
unsigned count;
|
||||||
|
for(count = 0; count < length; count++)
|
||||||
|
{
|
||||||
|
if (mpc107_i2c_byte_write(bus, target, address, data[count]) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DIMM_LENGTH 0xfff
|
||||||
|
|
||||||
|
static int
|
||||||
|
mpc107_i2c_master_read(struct i2c_bus *bus, int target, int address,
|
||||||
|
u8 *data, int length)
|
||||||
|
{
|
||||||
|
unsigned timeout = ticks_since_boot() + 3 * get_hz();
|
||||||
|
unsigned count;
|
||||||
|
|
||||||
|
/* Must wait here for clocks to start */
|
||||||
|
sleep_ticks(get_hz() / 40);
|
||||||
|
/* Start with MEN */
|
||||||
|
writel(MPC107_I2C_CCR_MEN, MPC107_BASE + MPC107_I2CCR);
|
||||||
|
/* Start as master */
|
||||||
|
writel(MPC107_I2C_CCR_MEN | MPC107_I2C_CCR_MSTA | MPC107_I2C_CCR_MTX, MPC107_BASE + MPC107_I2CCR);
|
||||||
|
/* Write target byte */
|
||||||
|
writel(target, MPC107_BASE + MPC107_I2CDR);
|
||||||
|
|
||||||
|
if (i2c_wait(timeout, 1) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Write data address byte */
|
||||||
|
writel(address, MPC107_BASE + MPC107_I2CDR);
|
||||||
|
|
||||||
|
if (i2c_wait(timeout, 1) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Switch to read - restart */
|
||||||
|
writel(MPC107_I2C_CCR_MEN | MPC107_I2C_CCR_MSTA | MPC107_I2C_CCR_MTX | MPC107_I2C_CCR_RSTA, MPC107_BASE + MPC107_I2CCR);
|
||||||
|
/* Write target address byte - this time with the read flag set */
|
||||||
|
writel(target | 1, MPC107_BASE + MPC107_I2CDR);
|
||||||
|
|
||||||
|
if (i2c_wait(timeout, 0) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (length == 1)
|
||||||
|
writel(MPC107_I2C_CCR_MEN | MPC107_I2C_CCR_MSTA | MPC107_I2C_CCR_TXAK, MPC107_BASE + MPC107_I2CCR);
|
||||||
|
else
|
||||||
|
writel(MPC107_I2C_CCR_MEN | MPC107_I2C_CCR_MSTA, MPC107_BASE + MPC107_I2CCR);
|
||||||
|
/* Dummy read */
|
||||||
|
readl(MPC107_BASE + MPC107_I2CDR);
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
while (count < length) {
|
||||||
|
|
||||||
|
if (i2c_wait(timeout, 0) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Generate txack on next to last byte */
|
||||||
|
if (count == length - 2)
|
||||||
|
writel(MPC107_I2C_CCR_MEN | MPC107_I2C_CCR_MSTA | MPC107_I2C_CCR_TXAK, MPC107_BASE + MPC107_I2CCR);
|
||||||
|
/* Generate stop on last byte */
|
||||||
|
if (count == length - 1)
|
||||||
|
writel(MPC107_I2C_CCR_MEN | MPC107_I2C_CCR_TXAK, MPC107_BASE + MPC107_I2CCR);
|
||||||
|
data[count] = readl(MPC107_BASE + MPC107_I2CDR);
|
||||||
|
if (count == 0 && length == DIMM_LENGTH) {
|
||||||
|
if (data[0] == 0xff) {
|
||||||
|
printk_debug("I2C device not present\n");
|
||||||
|
length = 3;
|
||||||
|
} else {
|
||||||
|
length = data[0];
|
||||||
|
if (length < 3)
|
||||||
|
length = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finish with disable master */
|
||||||
|
writel(MPC107_I2C_CCR_MEN, MPC107_BASE + MPC107_I2CCR);
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_fn mpc107_i2c_fn = {
|
||||||
|
mpc107_i2c_start, mpc107_i2c_stop,
|
||||||
|
mpc107_i2c_master_write, mpc107_i2c_master_read
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find dimm information.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
hostbridge_probe_dimms(int no_dimms, sdram_dimm_info *dimms, sdram_bank_info * bank)
|
||||||
|
{
|
||||||
|
unsigned char data[256];
|
||||||
|
unsigned dimm;
|
||||||
|
|
||||||
|
printk_debug("i2c testing\n");
|
||||||
|
mpc107_i2c_start(NULL);
|
||||||
|
|
||||||
|
for(dimm = 0; dimm < no_dimms; dimm++)
|
||||||
|
{
|
||||||
|
dimms[dimm].number = dimm;
|
||||||
|
dimms[dimm].bank1 = bank + dimm*2;
|
||||||
|
dimms[dimm].bank2 = bank + dimm*2 + 1;
|
||||||
|
bank[dimm*2].size = 0;
|
||||||
|
bank[dimm*2+1].size = 0;
|
||||||
|
bank[dimm*2].number = 0;
|
||||||
|
bank[dimm*2+1].number = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (dimm = 0; dimm < no_dimms; dimm ++) {
|
||||||
|
unsigned limit = mpc107_i2c_master_read(NULL, 0xa0 + 2*dimm, 0,
|
||||||
|
data, DIMM_LENGTH);
|
||||||
|
|
||||||
|
if (limit > 3) {
|
||||||
|
sdram_dimm_to_bank_info(data, dimms + dimm, 0);
|
||||||
|
memcpy(dimms[dimm].part_number, data + 73, 18);
|
||||||
|
dimms[dimm].part_number[18] = 0;
|
||||||
|
printk_debug("Part Number: %s\n", dimms[dimm].part_number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mpc107_i2c_stop(NULL);
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
* (C) Copyright 2001
|
||||||
|
* Humboldt Solutions Ltd, adrian@humboldt.co.uk.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MPC107_H
|
||||||
|
#define _MPC107_H
|
||||||
|
|
||||||
|
#ifdef ASM
|
||||||
|
#define BMC_BASE 0x8000 /* Bridge memory controller base address */
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define MPC107_BASE 0xfc000000
|
||||||
|
|
||||||
|
#define MPC107_EUMBBAR 0x78
|
||||||
|
|
||||||
|
#define MPC107_PIC1 0xa8
|
||||||
|
#define MPC107_PIC1_CF_MP 0x000003
|
||||||
|
#define MPC107_PIC1_SPEC_PCI 0x000004
|
||||||
|
#define MPC107_PIC1_CF_APARK 0x000008
|
||||||
|
#define MPC107_PIC1_CF_LOOP_SNOOP 0x000010
|
||||||
|
#define MPC107_PIC1_LE_MODE 0x000020
|
||||||
|
#define MPC107_PIC1_ST_GATH_EN 0x000040
|
||||||
|
#define MPC107_PIC1_NO_BUS_WIDTH_CHECK 0x000080
|
||||||
|
#define MPC107_PIC1_TEA_EN 0x000400
|
||||||
|
#define MPC107_PIC1_MCP_EN 0x000800
|
||||||
|
#define MPC107_PIC1_FLASH_WR_EN 0x001000
|
||||||
|
#define MPC107_PIC1_CF_LBA_EN 0x002000
|
||||||
|
#define MPC107_PIC1_CF_MP_ID 0x00c000
|
||||||
|
#define MPC107_PIC1_ADDRESS_MAP 0x010000
|
||||||
|
#define MPC107_PIC1_PROC_TYPE 0x050000
|
||||||
|
#define MPC107_PIC1_RCS0 0x100000
|
||||||
|
#define MPC107_PIC1_CF_BREAD_WS 0xc00000
|
||||||
|
|
||||||
|
#define MPC107_I2CADR 0x3000
|
||||||
|
#define MPC107_I2CFDR 0x3004
|
||||||
|
#define MPC107_I2CCR 0x3008
|
||||||
|
#define MPC107_I2CSR 0x300c
|
||||||
|
#define MPC107_I2CDR 0x3010
|
||||||
|
|
||||||
|
#define MPC107_I2C_CCR_MEN 0x80
|
||||||
|
#define MPC107_I2C_CCR_MIEN 0x40
|
||||||
|
#define MPC107_I2C_CCR_MSTA 0x20
|
||||||
|
#define MPC107_I2C_CCR_MTX 0x10
|
||||||
|
#define MPC107_I2C_CCR_TXAK 0x08
|
||||||
|
#define MPC107_I2C_CCR_RSTA 0x04
|
||||||
|
|
||||||
|
#define MPC107_I2C_CSR_MCF 0x80
|
||||||
|
#define MPC107_I2C_CSR_MAAS 0x40
|
||||||
|
#define MPC107_I2C_CSR_MBB 0x20
|
||||||
|
#define MPC107_I2C_CSR_MAL 0x10
|
||||||
|
#define MPC107_I2C_CSR_SRW 0x04
|
||||||
|
#define MPC107_I2C_CSR_MIF 0x02
|
||||||
|
#define MPC107_I2C_CSR_RXAK 0x01
|
||||||
|
|
||||||
|
enum sdram_error_detect {
|
||||||
|
ERRORS_NONE, ERRORS_PARITY, ERRORS_ECC
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct sdram_dimm_info
|
||||||
|
{
|
||||||
|
unsigned size;
|
||||||
|
unsigned number;
|
||||||
|
char part_number[20];
|
||||||
|
struct sdram_bank_info *bank1;
|
||||||
|
struct sdram_bank_info *bank2;
|
||||||
|
} sdram_dimm_info;
|
||||||
|
|
||||||
|
typedef struct sdram_bank_info
|
||||||
|
{
|
||||||
|
unsigned number;
|
||||||
|
unsigned char row_bits;
|
||||||
|
unsigned char internal_banks;
|
||||||
|
unsigned char col_bits;
|
||||||
|
unsigned char data_width;
|
||||||
|
/* Cycle and access times are stored with lowest CAS latency first. Units
|
||||||
|
are 0.01ns */
|
||||||
|
unsigned short cycle_time[3];
|
||||||
|
unsigned short access_time[3];
|
||||||
|
/* Best CAS latencies */
|
||||||
|
unsigned char cas_latency[3];
|
||||||
|
unsigned char cs_latency;
|
||||||
|
unsigned char we_latency;
|
||||||
|
unsigned char min_back_to_back;
|
||||||
|
unsigned char min_row_precharge;
|
||||||
|
unsigned char min_active_to_active;
|
||||||
|
unsigned char min_ras_to_cas;
|
||||||
|
unsigned char min_ras;
|
||||||
|
unsigned char burst_mask;
|
||||||
|
enum sdram_error_detect error_detect;
|
||||||
|
/* Bank size */
|
||||||
|
unsigned size;
|
||||||
|
unsigned long start;
|
||||||
|
unsigned long end;
|
||||||
|
enum sdram_error_detect actual_detect;
|
||||||
|
unsigned char actual_cas;
|
||||||
|
} sdram_bank_info;
|
||||||
|
|
||||||
|
void sdram_dimm_to_bank_info(const char *dimm_data, sdram_dimm_info *dimm, int verbose);
|
||||||
|
void print_sdram_dimm_info(const sdram_dimm_info *dimm);
|
||||||
|
void print_sdram_bank_info(const sdram_bank_info *bank);
|
||||||
|
|
||||||
|
unsigned long hostbridge_config_memory(int no_banks, sdram_bank_info *bank, int for_real);
|
||||||
|
void hostbridge_probe_dimms(int no_dimms, sdram_dimm_info *dimm, sdram_bank_info * bank);
|
||||||
|
unsigned mpc107_config_memory(void);
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,27 @@
|
||||||
|
#include <pci.h>
|
||||||
|
#include "mpc107.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
wait_for_other_cpus(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long
|
||||||
|
this_processors_id(void)
|
||||||
|
{
|
||||||
|
u32 pic1;
|
||||||
|
|
||||||
|
pcibios_read_config_dword(0, 0, MPC107_PIC1, &pic1);
|
||||||
|
return (pic1 & MPC107_PIC1_CF_MP_ID) >> 14;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long
|
||||||
|
processor_index(unsigned long id)
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
startup_other_cpus(unsigned long *map)
|
||||||
|
{
|
||||||
|
}
|
|
@ -0,0 +1,513 @@
|
||||||
|
#define BSY_SET_DURING_SPINUP 1
|
||||||
|
/*
|
||||||
|
* UBL, The Universal Talkware Boot Loader
|
||||||
|
* Copyright (C) 2000 Universal Talkware Inc.
|
||||||
|
* Copyright (C) 2002 Eric Biederman
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <arch/io.h>
|
||||||
|
#include <printk.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <delay.h>
|
||||||
|
#include <pci.h>
|
||||||
|
#include <pc80/ide.h>
|
||||||
|
#include <arch/io.h>
|
||||||
|
|
||||||
|
struct controller controller;
|
||||||
|
struct harddisk_info harddisk_info[NUM_HD];
|
||||||
|
|
||||||
|
static int await_ide(int (*done)(struct controller *ctrl),
|
||||||
|
struct controller *ctrl, unsigned long timeout)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
for(;;) {
|
||||||
|
result = done(ctrl);
|
||||||
|
if (result) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (timeout-- <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
udelay(1000); /* Added to avoid spinning GRW */
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The maximum time any IDE command can last 31 seconds,
|
||||||
|
* So if any IDE commands takes this long we know we have problems.
|
||||||
|
*/
|
||||||
|
#define IDE_TIMEOUT (32*1000)
|
||||||
|
|
||||||
|
static int not_bsy(struct controller *ctrl)
|
||||||
|
{
|
||||||
|
return !(inb(IDE_REG_STATUS(ctrl)) & IDE_STATUS_BSY);
|
||||||
|
}
|
||||||
|
#if !BSY_SET_DURING_SPINUP
|
||||||
|
static int timeout(struct controller *ctrl)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int ide_software_reset(struct controller *ctrl)
|
||||||
|
{
|
||||||
|
/* Wait a little bit in case this is immediately after
|
||||||
|
* hardware reset.
|
||||||
|
*/
|
||||||
|
udelay(2000);
|
||||||
|
/* A software reset should not be delivered while the bsy bit
|
||||||
|
* is set. If the bsy bit does not clear in a reasonable
|
||||||
|
* amount of time give up.
|
||||||
|
*/
|
||||||
|
if (await_ide(not_bsy, ctrl, IDE_TIMEOUT) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable Interrupts and reset the ide bus */
|
||||||
|
outb(IDE_CTRL_HD15 | IDE_CTRL_SRST | IDE_CTRL_NIEN,
|
||||||
|
IDE_REG_DEVICE_CONTROL(ctrl));
|
||||||
|
udelay(5);
|
||||||
|
outb(IDE_CTRL_HD15 | IDE_CTRL_NIEN, IDE_REG_DEVICE_CONTROL(ctrl));
|
||||||
|
udelay(2000);
|
||||||
|
if (await_ide(not_bsy, ctrl, IDE_TIMEOUT) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pio_set_registers(
|
||||||
|
struct controller *ctrl, const struct ide_pio_command *cmd)
|
||||||
|
{
|
||||||
|
uint8_t device;
|
||||||
|
/* Disable Interrupts */
|
||||||
|
outb(IDE_CTRL_HD15 | IDE_CTRL_NIEN, IDE_REG_DEVICE_CONTROL(ctrl));
|
||||||
|
|
||||||
|
/* Possibly switch selected device */
|
||||||
|
device = inb(IDE_REG_DEVICE(ctrl));
|
||||||
|
outb(cmd->device, IDE_REG_DEVICE(ctrl));
|
||||||
|
if ((device & (1UL << 4)) != (cmd->device & (1UL << 4))) {
|
||||||
|
/* Allow time for the selected drive to switch,
|
||||||
|
* The linux ide code suggests 50ms is the right
|
||||||
|
* amount of time to use here.
|
||||||
|
*/
|
||||||
|
udelay(50000);
|
||||||
|
}
|
||||||
|
outb(cmd->feature, IDE_REG_FEATURE(ctrl));
|
||||||
|
outb(cmd->sector_count2, IDE_REG_SECTOR_COUNT(ctrl));
|
||||||
|
outb(cmd->sector_count, IDE_REG_SECTOR_COUNT(ctrl));
|
||||||
|
outb(cmd->lba_low2, IDE_REG_LBA_LOW(ctrl));
|
||||||
|
outb(cmd->lba_low, IDE_REG_LBA_LOW(ctrl));
|
||||||
|
outb(cmd->lba_mid2, IDE_REG_LBA_MID(ctrl));
|
||||||
|
outb(cmd->lba_mid, IDE_REG_LBA_MID(ctrl));
|
||||||
|
outb(cmd->lba_high2, IDE_REG_LBA_HIGH(ctrl));
|
||||||
|
outb(cmd->lba_high, IDE_REG_LBA_HIGH(ctrl));
|
||||||
|
outb(cmd->command, IDE_REG_COMMAND(ctrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int pio_non_data(struct controller *ctrl, const struct ide_pio_command *cmd)
|
||||||
|
{
|
||||||
|
/* Wait until the busy bit is clear */
|
||||||
|
if (await_ide(not_bsy, ctrl, IDE_TIMEOUT) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pio_set_registers(ctrl, cmd);
|
||||||
|
if (await_ide(not_bsy, ctrl, IDE_TIMEOUT) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* FIXME is there more error checking I could do here? */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pio_data_in(struct controller *ctrl, const struct ide_pio_command *cmd,
|
||||||
|
void *buffer, size_t bytes)
|
||||||
|
{
|
||||||
|
unsigned int status;
|
||||||
|
|
||||||
|
/* FIXME handle commands with multiple blocks */
|
||||||
|
/* Wait until the busy bit is clear */
|
||||||
|
if (await_ide(not_bsy, ctrl, IDE_TIMEOUT) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* How do I tell if INTRQ is asserted? */
|
||||||
|
pio_set_registers(ctrl, cmd);
|
||||||
|
if (await_ide(not_bsy, ctrl, IDE_TIMEOUT) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
status = inb(IDE_REG_STATUS(ctrl));
|
||||||
|
if (!(status & IDE_STATUS_DRQ)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
insw(IDE_REG_DATA(ctrl), buffer, bytes/2);
|
||||||
|
status = inb(IDE_REG_STATUS(ctrl));
|
||||||
|
if (status & IDE_STATUS_ERR) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int ide_read_sector_chs(
|
||||||
|
struct harddisk_info *info, void *buffer, unsigned long sector)
|
||||||
|
{
|
||||||
|
struct ide_pio_command cmd;
|
||||||
|
unsigned int track;
|
||||||
|
unsigned int offset;
|
||||||
|
unsigned int cylinder;
|
||||||
|
|
||||||
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
|
cmd.sector_count = 1;
|
||||||
|
|
||||||
|
track = sector / info->sectors_per_track;
|
||||||
|
/* Sector number */
|
||||||
|
offset = 1 + (sector % info->sectors_per_track);
|
||||||
|
cylinder = track / info->heads;
|
||||||
|
cmd.lba_low = offset;
|
||||||
|
cmd.lba_mid = cylinder & 0xff;
|
||||||
|
cmd.lba_high = (cylinder >> 8) & 0xff;
|
||||||
|
cmd.device = IDE_DH_DEFAULT |
|
||||||
|
IDE_DH_HEAD(track % info->heads) |
|
||||||
|
info->slave |
|
||||||
|
IDE_DH_CHS;
|
||||||
|
cmd.command = IDE_CMD_READ_SECTORS;
|
||||||
|
return pio_data_in(info->ctrl, &cmd, buffer, IDE_SECTOR_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int ide_read_sector_lba(
|
||||||
|
struct harddisk_info *info, void *buffer, unsigned long sector)
|
||||||
|
{
|
||||||
|
struct ide_pio_command cmd;
|
||||||
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
|
|
||||||
|
cmd.sector_count = 1;
|
||||||
|
cmd.lba_low = sector & 0xff;
|
||||||
|
cmd.lba_mid = (sector >> 8) & 0xff;
|
||||||
|
cmd.lba_high = (sector >> 16) & 0xff;
|
||||||
|
cmd.device = IDE_DH_DEFAULT |
|
||||||
|
((sector >> 24) & 0x0f) |
|
||||||
|
info->slave |
|
||||||
|
IDE_DH_LBA;
|
||||||
|
cmd.command = IDE_CMD_READ_SECTORS;
|
||||||
|
return pio_data_in(info->ctrl, &cmd, buffer, IDE_SECTOR_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int ide_read_sector_lba48(
|
||||||
|
struct harddisk_info *info, void *buffer, sector_t sector)
|
||||||
|
{
|
||||||
|
struct ide_pio_command cmd;
|
||||||
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
|
|
||||||
|
cmd.sector_count = 1;
|
||||||
|
cmd.lba_low = sector & 0xff;
|
||||||
|
cmd.lba_mid = (sector >> 8) & 0xff;
|
||||||
|
cmd.lba_high = (sector >> 16) & 0xff;
|
||||||
|
cmd.lba_low2 = (sector >> 24) & 0xff;
|
||||||
|
cmd.lba_mid2 = (sector >> 32) & 0xff;
|
||||||
|
cmd.lba_high2 = (sector >> 40) & 0xff;
|
||||||
|
cmd.device = info->slave | IDE_DH_LBA;
|
||||||
|
cmd.command = IDE_CMD_READ_SECTORS_EXT;
|
||||||
|
return pio_data_in(info->ctrl, &cmd, buffer, IDE_SECTOR_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ide_read_sector(int driveno, void * buf, unsigned int sector,
|
||||||
|
int byte_offset, int n_bytes)
|
||||||
|
{
|
||||||
|
struct harddisk_info *info = &harddisk_info[driveno];
|
||||||
|
int result;
|
||||||
|
|
||||||
|
/* Report the buffer is empty */
|
||||||
|
if (sector > info->sectors) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (info->address_mode == ADDRESS_MODE_CHS) {
|
||||||
|
result = ide_read_sector_chs(info, buf, sector);
|
||||||
|
}
|
||||||
|
else if (info->address_mode == ADDRESS_MODE_LBA) {
|
||||||
|
result = ide_read_sector_lba(info, buf, sector);
|
||||||
|
}
|
||||||
|
else if (info->address_mode == ADDRESS_MODE_LBA48) {
|
||||||
|
result = ide_read_sector_lba48(info, buf, sector);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = -1;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int init_drive(struct harddisk_info *info, struct controller *ctrl, int slave, int basedrive)
|
||||||
|
{
|
||||||
|
uint16_t* drive_info;
|
||||||
|
struct ide_pio_command cmd;
|
||||||
|
unsigned char disk_buffer[DISK_BUFFER_SIZE];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
info->ctrl = ctrl;
|
||||||
|
info->heads = 0u;
|
||||||
|
info->cylinders = 0u;
|
||||||
|
info->sectors_per_track = 0u;
|
||||||
|
info->address_mode = IDE_DH_CHS;
|
||||||
|
info->sectors = 0ul;
|
||||||
|
info->drive_exists = 0;
|
||||||
|
info->slave_absent = 0;
|
||||||
|
info->slave = slave?IDE_DH_SLAVE: IDE_DH_MASTER;
|
||||||
|
info->basedrive = basedrive;
|
||||||
|
|
||||||
|
printk_info("Testing for disk %d\n", info->basedrive);
|
||||||
|
|
||||||
|
/* Select the drive that we are testing */
|
||||||
|
outb(IDE_DH_DEFAULT | IDE_DH_HEAD(0) | IDE_DH_CHS | info->slave,
|
||||||
|
IDE_REG_DEVICE(ctrl));
|
||||||
|
udelay(50000);
|
||||||
|
|
||||||
|
/* Test to see if the drive registers exist,
|
||||||
|
* In many cases this quickly rules out a missing drive.
|
||||||
|
*/
|
||||||
|
for(i = 0; i < 4; i++) {
|
||||||
|
outb(0xaa + i, (ctrl->cmd_base) + 2 + i);
|
||||||
|
}
|
||||||
|
for(i = 0; i < 4; i++) {
|
||||||
|
if (inb((ctrl->cmd_base) + 2 + i) != 0xaa + i) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(i = 0; i < 4; i++) {
|
||||||
|
outb(0x55 + i, (ctrl->cmd_base) + 2 + i);
|
||||||
|
}
|
||||||
|
for(i = 0; i < 4; i++) {
|
||||||
|
if (inb((ctrl->cmd_base) + 2 + i) != 0x55 + i) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printk_info("Probing for disk %d\n", info->basedrive);
|
||||||
|
|
||||||
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
|
cmd.device = IDE_DH_DEFAULT | IDE_DH_HEAD(0) | IDE_DH_CHS | info->slave;
|
||||||
|
cmd.command = IDE_CMD_IDENTIFY_DEVICE;
|
||||||
|
|
||||||
|
|
||||||
|
if (pio_data_in(ctrl, &cmd, disk_buffer, IDE_SECTOR_SIZE) < 0) {
|
||||||
|
/* Well, if that command didn't work, we probably don't have drive. */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Now suck the data out */
|
||||||
|
drive_info = (uint16_t *)disk_buffer;
|
||||||
|
if (drive_info[2] == 0x37C8) {
|
||||||
|
/* If the response is incomplete spin up the drive... */
|
||||||
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
|
cmd.device = IDE_DH_DEFAULT | IDE_DH_HEAD(0) | IDE_DH_CHS |
|
||||||
|
info->slave;
|
||||||
|
cmd.feature = IDE_FEATURE_STANDBY_SPINUP_DRIVE;
|
||||||
|
if (pio_non_data(ctrl, &cmd) < 0) {
|
||||||
|
/* If the command doesn't work give up on the drive */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if ((drive_info[2] == 0x37C8) || (drive_info[2] == 0x8C73)) {
|
||||||
|
/* The response is incomplete retry the drive info command */
|
||||||
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
|
cmd.device = IDE_DH_DEFAULT | IDE_DH_HEAD(0) | IDE_DH_CHS |
|
||||||
|
info->slave;
|
||||||
|
cmd.command = IDE_CMD_IDENTIFY_DEVICE;
|
||||||
|
if(pio_data_in(ctrl, &cmd, disk_buffer, IDE_SECTOR_SIZE) < 0) {
|
||||||
|
/* If the command didn't work give up on the drive. */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((drive_info[2] != 0x37C8) &&
|
||||||
|
(drive_info[2] != 0x738C) &&
|
||||||
|
(drive_info[2] != 0x8C73) &&
|
||||||
|
(drive_info[2] != 0xC837) &&
|
||||||
|
(drive_info[2] != 0x0000)) {
|
||||||
|
printk_info("Invalid IDE Configuration: %hx\n", drive_info[2]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
for(i = 27; i < 47; i++) {
|
||||||
|
info->model_number[((i-27)<< 1)] = (drive_info[i] >> 8) & 0xff;
|
||||||
|
info->model_number[((i-27)<< 1)+1] = drive_info[i] & 0xff;
|
||||||
|
}
|
||||||
|
info->model_number[40] = '\0';
|
||||||
|
info->drive_exists = 1;
|
||||||
|
|
||||||
|
/* See if LBA is supported */
|
||||||
|
if (drive_info[49] & (1 << 9)) {
|
||||||
|
info->address_mode = ADDRESS_MODE_LBA;
|
||||||
|
info->sectors = (drive_info[61] << 16) | (drive_info[60]);
|
||||||
|
/* Enable LBA48 mode if it is present */
|
||||||
|
if (drive_info[83] & (1 <<10)) {
|
||||||
|
/* Should LBA48 depend on LBA? */
|
||||||
|
printk_info("LBA48 mode\n");
|
||||||
|
info->address_mode = ADDRESS_MODE_LBA48;
|
||||||
|
info->sectors =
|
||||||
|
(((sector_t)drive_info[103]) << 48) |
|
||||||
|
(((sector_t)drive_info[102]) << 32) |
|
||||||
|
(((sector_t)drive_info[101]) << 16) |
|
||||||
|
(((sector_t)drive_info[100]) << 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
info->address_mode = ADDRESS_MODE_CHS;
|
||||||
|
info->heads = drive_info[3];
|
||||||
|
info->cylinders = drive_info[1];
|
||||||
|
info->sectors_per_track = drive_info[6];
|
||||||
|
info->sectors =
|
||||||
|
info->sectors_per_track *
|
||||||
|
info->heads *
|
||||||
|
info->cylinders;
|
||||||
|
printk_info("%s sectors_per_track=[%d], heads=[%d], cylinders=[%d]\n",
|
||||||
|
__FUNCTION__,
|
||||||
|
info->sectors_per_track,
|
||||||
|
info->heads,
|
||||||
|
info->cylinders);
|
||||||
|
}
|
||||||
|
/* See if we have a slave */
|
||||||
|
if (!info->slave && (((drive_info[93] >> 14) & 3) == 1)) {
|
||||||
|
info->slave_absent = !(drive_info[93] & (1 << 5));
|
||||||
|
}
|
||||||
|
/* See if we need to put the device in CFA power mode 1 */
|
||||||
|
if ((drive_info[160] & ((1 << 15) | (1 << 13)| (1 << 12))) ==
|
||||||
|
((1 << 15) | (1 << 13)| (1 << 12))) {
|
||||||
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
|
cmd.device = IDE_DH_DEFAULT | IDE_DH_HEAD(0) | IDE_DH_CHS | info->slave;
|
||||||
|
cmd.feature = IDE_FEATURE_CFA_ENABLE_POWER_MODE1;
|
||||||
|
if (pio_non_data(ctrl, &cmd) < 0) {
|
||||||
|
/* If I need to power up the drive, and I can't
|
||||||
|
* give up.
|
||||||
|
*/
|
||||||
|
printk_info("Cannot power up CFA device\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printk_info("disk%d %dk cap: %hx\n",
|
||||||
|
info->basedrive,
|
||||||
|
(unsigned long)(info->sectors >> 1),
|
||||||
|
drive_info[49]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int init_controller(struct controller *ctrl, int basedrive)
|
||||||
|
{
|
||||||
|
struct harddisk_info *info;
|
||||||
|
|
||||||
|
/* Put the drives ide channel in a know state and wait
|
||||||
|
* for the drives to spinup.
|
||||||
|
*
|
||||||
|
* In practice IDE disks tend not to respond to commands until
|
||||||
|
* they have spun up. This makes IDE hard to deal with
|
||||||
|
* immediately after power up, as the delays can be quite
|
||||||
|
* long, so we must be very careful here.
|
||||||
|
*
|
||||||
|
* There are two pathological cases that must be dealt with:
|
||||||
|
*
|
||||||
|
* - The BSY bit not being set while the IDE drives spin up.
|
||||||
|
* In this cases only a hard coded delay will work. As
|
||||||
|
* I have not reproduced it, and this is out of spec for
|
||||||
|
* IDE drives the work around can be enabled by setting
|
||||||
|
* BSY_SET_DURING_SPINUP to 0.
|
||||||
|
*
|
||||||
|
* - The BSY bit floats high when no drives are plugged in.
|
||||||
|
* This case will not be detected except by timing out but
|
||||||
|
* we avoid the problems by only probing devices we are
|
||||||
|
* supposed to boot from. If we don't do the probe we
|
||||||
|
* will not experience the problem.
|
||||||
|
*
|
||||||
|
* So speed wise I am only slow if the BSY bit is not set
|
||||||
|
* or not reported by the IDE controller during spinup, which
|
||||||
|
* is quite rare.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#if !BSY_SET_DURING_SPINUP
|
||||||
|
if (await_ide(timeout, ctrl, IDE_TIMEOUT) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (ide_software_reset(ctrl) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note: I have just done a software reset. It may be
|
||||||
|
* reasonable to just read the boot time signatures
|
||||||
|
* off of the drives to see if they are present.
|
||||||
|
*
|
||||||
|
* For now I will go with just sending commands to the drives
|
||||||
|
* and assuming filtering out missing drives by detecting registers
|
||||||
|
* that won't set and commands that fail to execute properly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Now initialize the individual drives */
|
||||||
|
info = &harddisk_info[basedrive];
|
||||||
|
init_drive(info, ctrl, 0, basedrive & 1);
|
||||||
|
|
||||||
|
/* at the moment this only works for the first drive */
|
||||||
|
#if 0
|
||||||
|
if (info->drive_exists && !info->slave_absent) {
|
||||||
|
basedrive++;
|
||||||
|
info++;
|
||||||
|
init_drive(info, ctrl, 1, basedrive & 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ide_init(void)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
int drives = 0;
|
||||||
|
|
||||||
|
/* Intialize the harddisk_info structures */
|
||||||
|
memset(harddisk_info, 0, sizeof(harddisk_info));
|
||||||
|
|
||||||
|
for(index = 0; index < 1; index++) {
|
||||||
|
#if 0
|
||||||
|
/* IDE normal pci mode */
|
||||||
|
unsigned cmd_reg, ctrl_reg;
|
||||||
|
uint32_t cmd_base, ctrl_base;
|
||||||
|
if (index < 2) {
|
||||||
|
cmd_reg = PCI_BASE_ADDRESS_0;
|
||||||
|
ctrl_reg = PCI_BASE_ADDRESS_1;
|
||||||
|
} else {
|
||||||
|
cmd_reg = PCI_BASE_ADDRESS_2;
|
||||||
|
ctrl_reg = PCI_BASE_ADDRESS_3;
|
||||||
|
}
|
||||||
|
pcibios_read_config_dword(0, 0, cmd_reg, &cmd_base);
|
||||||
|
pcibios_read_config_dword(0, 0, ctrl_reg, &ctrl_base);
|
||||||
|
controller.cmd_base = cmd_base & ~3;
|
||||||
|
controller.ctrl_base = ctrl_base & ~3;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
uint16_t base;
|
||||||
|
base = (index < 1)?IDE_BASE0:IDE_BASE1;
|
||||||
|
controller.cmd_base = base;
|
||||||
|
controller.ctrl_base = base + IDE_REG_EXTENDED_OFFSET;
|
||||||
|
|
||||||
|
printk_info("init_controller %d at (%x, %x)\n", index, controller.cmd_base, controller.ctrl_base);
|
||||||
|
|
||||||
|
if (init_controller(&controller, index << 1) < 0) {
|
||||||
|
/* nothing behind the controller */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
drives++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return drives > 0 ? 0 : -1;
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/* $Id$ */
|
||||||
|
/* Copyright 2000 AG Electronics Ltd. */
|
||||||
|
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
|
||||||
|
|
||||||
|
#include <ppc.h>
|
||||||
|
#include <ppcreg.h>
|
||||||
|
#include <types.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <pci.h>
|
||||||
|
#include <printk.h>
|
||||||
|
|
||||||
|
#define ONEMEG 0x00100000
|
||||||
|
#define HALFMEG 0x00080000
|
||||||
|
|
||||||
|
unsigned long memory_base = 0;
|
||||||
|
unsigned long memory_top = 0;
|
||||||
|
unsigned long memory_size = 0;
|
||||||
|
|
||||||
|
//extern char __heap_end[];
|
||||||
|
extern unsigned mpc107_config_memory(void);
|
||||||
|
|
||||||
|
unsigned config_memory(unsigned offset)
|
||||||
|
{
|
||||||
|
//extern char __start[];
|
||||||
|
//extern char __bss_start[];
|
||||||
|
//unsigned rom_image = (unsigned) __start & 0xfff00000;
|
||||||
|
//unsigned physical = rom_image + offset;
|
||||||
|
//unsigned codesize = (unsigned) __bss_start - rom_image;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* At this point, DBAT 0 is memory, 1 is variable, 2 is the rom image,
|
||||||
|
and 3 is IO. */
|
||||||
|
ppc_set_io_dbat_reloc(2, rom_image, physical, ONEMEG);
|
||||||
|
ppc_set_io_dbat (3, 0xf0000000, 0x10000000);
|
||||||
|
if ( rom_image != physical )
|
||||||
|
ppc_set_ibats_reloc(rom_image, physical, ONEMEG);
|
||||||
|
else
|
||||||
|
ppc_set_ibats(physical, ONEMEG);
|
||||||
|
|
||||||
|
printk_debug("bsp_init_memory...\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ppc_setup_cpu(1); /* icache enable = 1 */
|
||||||
|
//ppc_enable_mmu();
|
||||||
|
|
||||||
|
memory_size = mpc107_config_memory();
|
||||||
|
|
||||||
|
/* If we have some working RAM, we copy the code and rodata into it.
|
||||||
|
* This allows us to reprogram the flash later. */
|
||||||
|
#if 0
|
||||||
|
if (memory_size)
|
||||||
|
{
|
||||||
|
unsigned onemeg = memory_size - ONEMEG;
|
||||||
|
ppc_set_mem_dbat_reloc(1, onemeg, onemeg, ONEMEG);
|
||||||
|
memcpy((void *)onemeg, (void *)rom_image, codesize);
|
||||||
|
memset((void *)(onemeg + codesize), 0, ONEMEG - codesize);
|
||||||
|
ppc_set_ibats_reloc2(rom_image, physical, onemeg, ONEMEG);
|
||||||
|
ppc_set_mem_dbat_reloc(2, rom_image, onemeg, ONEMEG);
|
||||||
|
make_coherent((void *)onemeg, ONEMEG);
|
||||||
|
}
|
||||||
|
|
||||||
|
ppc_set_memory_dbat (memory_size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//ppc_enable_dcache ();
|
||||||
|
|
||||||
|
return memory_size;
|
||||||
|
}
|
Loading…
Reference in New Issue