Init DDR2 controller

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2010-03-01 18:53:34 +01:00
parent 7517048135
commit 813a5f2d33
4 changed files with 307 additions and 35 deletions

View file

@ -24,4 +24,7 @@
#define GRUB_MACHINE_FLASH_CACHE_ERROR 0xbfc00300
#define GRUB_MACHINE_FLASH_OTHER_EXCEPTION 0xbfc00380
#define GRUB_MACHINE_DDR2_BASE 0xaffffe00
#define GRUB_MACHINE_DDR2_REG1_HI_8BANKS 0x00000001
#endif

View file

@ -22,21 +22,49 @@
#define GRUB_SMB_RAM_START_ADDR 0x50
#define GRUB_SMB_RAM_NUM_MAX 0x08
#define GRUB_SMBUS_SPD_MEMORY_TYPE_ADDR 2
#define GRUB_SMBUS_SPD_MEMORY_TYPE_DDR2 8
#define GRUB_SMBUS_SPD_MEMORY_NUM_BANKS_ADDR 17
#define GRUB_SMBUS_SPD_MEMORY_NUM_ROWS_ADDR 3
#define GRUB_SMBUS_SPD_MEMORY_NUM_COLUMNS_ADDR 4
#define GRUB_SMBUS_SPD_MEMORY_NUM_OF_RANKS_ADDR 5
#define GRUB_SMBUS_SPD_MEMORY_NUM_OF_RANKS_MASK 0x7
#define GRUB_SMBUS_SPD_MEMORY_CAS_LATENCY_ADDR 18
#define GRUB_SMBUS_SPD_MEMORY_CAS_LATENCY_MIN_VALUE 5
#define GRUB_SMBUS_SPD_MEMORY_TRAS_ADDR 30
#define GRUB_SMBUS_SPD_MEMORY_TRTP_ADDR 38
#ifndef ASM_FILE
struct grub_smbus_spd
{
grub_uint8_t written_size;
grub_uint8_t log_total_flash_size;
#define GRUB_SMBUS_SPD_MEMORY_TYPE_DDR2 8
grub_uint8_t memory_type;
union
{
grub_uint8_t unknown[253];
struct {
grub_uint8_t unused1[70];
grub_uint8_t num_rows;
grub_uint8_t num_columns;
grub_uint8_t num_of_ranks;
grub_uint8_t unused1[12];
grub_uint8_t num_of_banks;
grub_uint8_t unused2[2];
grub_uint8_t cas_latency;
grub_uint8_t unused3[9];
grub_uint8_t rank_capacity;
grub_uint8_t unused4[1];
grub_uint8_t tras;
grub_uint8_t unused5[7];
grub_uint8_t trtp;
grub_uint8_t unused6[31];
grub_uint8_t part_number[18];
grub_uint8_t unused2[165];
grub_uint8_t unused7[165];
} ddr2;
};
};
#endif
#endif

View file

@ -22,6 +22,7 @@
#include <grub/pci.h>
#include <grub/serial.h>
#include <grub/cs5536.h>
#include <grub/smbus.h>
.set noreorder
.set noat
@ -103,21 +104,102 @@ __start:
sb $t1, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL3) ($t0)
sb $t1, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL2) ($t0)
ori $a0, $zero, 0x50
/* Yeeloong has only one memory slot. */
/* Output first byte on serial for debugging. */
ori $a1, $zero, GRUB_SMB_RAM_START_ADDR
bal read_spd
move $a1, $zero
move $a0, $zero
bal printhex
move $a0, $v0
ori $a0, $zero, 0x50
bal read_spd
ori $a1, $zero, 2
ori $a0, $zero, 2
ori $t0, $zero, GRUB_SMBUS_SPD_MEMORY_TYPE_DDR2
lui $a0, %hi(unimplemented_memory_type)
bne $t0, $v0, fatal
addiu $a0, $a0, %hi(unimplemented_memory_type)
/* And here is our goal: DDR2 controller initialisation. */
lui $t0, 0xbfe0
ld $t1, 0x0180($t0)
andi $t1, $t1, 0x4ff
sd $t1, 0x0180($t0)
b continue
. = start + GRUB_MACHINE_FLASH_TLB_REFILL - GRUB_MACHINE_FLASH_START
tlb_refill:
mfc0 $s1, $14
mfc0 $s2, $8
move $s3, $ra
lui $a0, %hi(epc)
bal message
addiu $a0, $a0, %lo(epc)
bal printhex
move $a0, $v0
move $a0, $s1
lui $a0, %hi(badvaddr)
bal message
addiu $a0, $a0, %lo(badvaddr)
bal printhex
move $a0, $s2
lui $a0, %hi(return_msg)
bal message
addiu $a0, $a0, %lo(return_msg)
bal printhex
move $a0, $s3
lui $a0, %hi(not_implemented)
lui $a0, %hi(newline)
bal message
addiu $a0, $a0, %lo(newline)
lui $a0, %hi(unhandled_tlb_refill)
b fatal
addiu $a0, $a0, %lo(not_implemented)
addiu $a0, $a0, %lo(unhandled_tlb_refill)
. = start + GRUB_MACHINE_FLASH_CACHE_ERROR - GRUB_MACHINE_FLASH_START
cache_error:
lui $a0, %hi(unhandled_cache_error)
b fatal
addiu $a0, $a0, %lo(unhandled_cache_error)
. = start + GRUB_MACHINE_FLASH_OTHER_EXCEPTION - GRUB_MACHINE_FLASH_START
other_exception:
mfc0 $s0, $13
mfc0 $s1, $14
mfc0 $s2, $8
lui $a0, %hi(cause)
bal message
addiu $a0, $a0, %lo(cause)
bal printhex
move $a0, $s0
lui $a0, %hi(epc)
bal message
addiu $a0, $a0, %lo(epc)
bal printhex
move $a0, $s1
lui $a0, %hi(badvaddr)
bal message
addiu $a0, $a0, %lo(badvaddr)
bal printhex
move $a0, $s2
lui $a0, %hi(newline)
bal message
addiu $a0, $a0, %lo(newline)
lui $a0, %hi(unhandled_exception)
b fatal
addiu $a0, $a0, %lo(unhandled_exception)
/* Same as similarly named C function but in asm since
we need it early. */
@ -171,7 +253,7 @@ message:
addiu $a0, $a0, 1
jr $ra
nop
/* Print 32-bit hexadecimal on serial.
In: $a0. Out: None. Clobbered: $a0, $t0, $t1, $t2
*/
@ -202,25 +284,7 @@ fatal:
self:
b self
nop
. = start + GRUB_MACHINE_FLASH_TLB_REFILL - GRUB_MACHINE_FLASH_START
tlb_refill:
lui $a0, %hi(unhandled_tlb_refill)
b fatal
addiu $a0, $a0, %lo(unhandled_tlb_refill)
. = start + GRUB_MACHINE_FLASH_CACHE_ERROR - GRUB_MACHINE_FLASH_START
cache_error:
lui $a0, %hi(unhandled_cache_error)
b fatal
addiu $a0, $a0, %lo(unhandled_cache_error)
. = start + GRUB_MACHINE_FLASH_OTHER_EXCEPTION - GRUB_MACHINE_FLASH_START
other_exception:
lui $a0, %hi(unhandled_exception)
b fatal
addiu $a0, $a0, %lo(unhandled_exception)
/* Write CS5536 MSR.
In: $a0 address, $a1 lower word, $a2 upper word.
Out: None
@ -251,7 +315,7 @@ return:
jr $ra
nop
/* Read SPD byte. In: $a0 device, $a1 byte. Out: $v0 read byte (0x100 on failure).
/* Read SPD byte. In: $a0 byte, $a1 device. Out: $v0 read byte (0x100 on failure).
Clobbered: $t0, $t1, $t2, $t3, $a0. */
read_spd:
move $t2, $a0
@ -268,7 +332,7 @@ read_spd:
/* Send device address. */
lui $t0, %hi(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_DATA + GRUB_MACHINE_PCI_IO_BASE)
sll $t1, $t2, 1
sll $t1, $a1, 1
bal smbus_wait
sb $t1, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_DATA + GRUB_MACHINE_PCI_IO_BASE) ($t0)
@ -281,7 +345,7 @@ read_spd:
/* Send byte address. */
lui $t0, %hi(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_DATA + GRUB_MACHINE_PCI_IO_BASE)
bal smbus_wait
sb $a1, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_DATA + GRUB_MACHINE_PCI_IO_BASE) ($t0)
sb $t2, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_DATA + GRUB_MACHINE_PCI_IO_BASE) ($t0)
/* Send START. */
lui $t0, %hi(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1 + GRUB_MACHINE_PCI_IO_BASE)
@ -292,7 +356,7 @@ read_spd:
/* Send device address. */
lui $t0, %hi(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_DATA + GRUB_MACHINE_PCI_IO_BASE)
sll $t1, $t2, 1
sll $t1, $a1, 1
ori $t1, $t1, 1
bal smbus_wait
sb $t1, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_DATA + GRUB_MACHINE_PCI_IO_BASE) ($t0)
@ -321,3 +385,156 @@ unhandled_tlb_refill: .asciz "Unhandled TLB refill.\n\r"
unhandled_cache_error: .asciz "Unhandled cache error.\n\r"
unhandled_exception: .asciz "Unhandled exception.\n\r"
smbus_enabled: .asciz "SMBus controller enabled.\n\r"
unimplemented_memory_type: .asciz "non-DDR2 memory isn't supported.\n\r"
no_cas_latency: .asciz "Couldn't determine CAS latency.\n\r"
cause: .asciz "Cause: "
epc: .asciz "\n\rEPC: "
badvaddr: .asciz "\n\rBadVaddr: "
newline: .asciz "\n\r"
return_msg: .asciz "\n\rReturn address: "
.p2align 3
regdump:
.quad 0x0100010000000101 /* 0 */
.quad 0x0100010100000000 /* 2 */
.quad 0x0101000001000000 /* 3 */
.quad 0x0100020200010101 /* 4 */
.quad 0x0a04030603050203 /* 6 */
.quad 0x0f0e040000010a0b /* 7 */
.quad 0x0000010200000102 /* 8 */
.quad 0x0000060c00000000 /* 9 */
.quad 0x2323233f3f1f0200 /* a */
.quad 0x5f7f232323232323 /* b */
.quad 0x002a3c0615000000 /* c */
.quad 0x002a002a002a002a /* d */
.quad 0x002a002a002a002a /* e */
.quad 0x00b40020006d0004 /* f */
.quad 0x070007ff00000087 /* 10 */
.quad 0x000000000016101f /* 11 */
.quad 0x001c000000000000 /* 12 */
.quad 0x28e1000200c8006b /* 13 */
.quad 0x0000204200c8002f /* 14 */
.quad 0x0000000000030d40 /* 15 */
.quad 0 /* 16 */
.quad 0 /* 17 */
.quad 0 /* 18 */
.quad 0 /* 19 */
.quad 0 /* 1a */
.quad 0 /* 1b */
.quad 0 /* 1c */
.p2align
write_dumpreg:
ld $t2, 0($t6)
sd $t2, 0($t4)
addiu $t4, $t4, 0x10
jr $ra
addiu $t6, $t6, 0x8
continue:
lui $t4, %hi(GRUB_MACHINE_DDR2_BASE)
addiu $t4, $t4, %lo(GRUB_MACHINE_DDR2_BASE)
lui $t6, %hi(regdump)
/* 0 */
bal write_dumpreg
addiu $t6, $t6, %lo(regdump)
/* 1 */
ori $a1, $a1, 0x50
move $t8, $zero
lui $t5, 0x0001
bal read_spd
ori $a0, $zero, GRUB_SMBUS_SPD_MEMORY_NUM_BANKS_ADDR
ori $t7, $zero, 8
bne $v0, $t7, 1f
ori $t5, $t5, 0x0001
ori $t8, $t8, GRUB_MACHINE_DDR2_REG1_HI_8BANKS
1:
dsll $t8, $t8, 32
or $t5, $t5, $t8
sd $t5, 0 ($t4)
addiu $t4, $t4, 0x10
/* 2 */
bal write_dumpreg
nop
/* 3 */
bal write_dumpreg
nop
/* 4 */
bal write_dumpreg
nop
/* 5 */
/* FIXME: figure termination resistance. */
ori $t5, $zero, 0x2
bal read_spd
ori $a0, $zero, GRUB_SMBUS_SPD_MEMORY_NUM_ROWS_ADDR
/* $v0 = 15 - $v0. */
xori $v0, $v0, 0xf
andi $v0, $v0, 0x7
sll $v0, $v0, 8
or $t5, $t5, $v0
/* Find the fastest supported CAS latency. */
bal read_spd
ori $a0, $zero, GRUB_SMBUS_SPD_MEMORY_CAS_LATENCY_ADDR
ori $t0, $zero, GRUB_SMBUS_SPD_MEMORY_CAS_LATENCY_MIN_VALUE
ori $t1, $zero, (1 << GRUB_SMBUS_SPD_MEMORY_CAS_LATENCY_MIN_VALUE)
2:
and $t2, $t1, $v0
bne $t2, $zero, 1f
ori $t3, $zero, 8
lui $a0, %hi(no_cas_latency)
beq $t0, $t3, fatal
addiu $a0, $a0, %lo(no_cas_latency)
addiu $t0, $t0, 1
b 2b
sll $t1, $t1, 1
1:
sll $t0, $t0, 16
or $t5, $t5, $t0
bal read_spd
ori $a0, $zero, GRUB_SMBUS_SPD_MEMORY_NUM_COLUMNS_ADDR
/* $v0 = 15 - ($v0 + 1) = 14 - $v0. */
addiu $v0, $v0, 1
xori $v0, $v0, 0xf
andi $v0, $v0, 0x7
sll $v0, 24
or $t5, $t5, $v0
sd $t5, 0 ($t4)
addiu $t4, $t4, 0x10
ori $t7, $zero, 0x16
1:
ld $t2, 0($t6)
sd $t2, 0($t4)
addiu $t4, $t4, 0x10
addiu $t7, $t7, -1
bne $t7, $zero, 1b
addiu $t6, $t6, 0x8
lui $t4, %hi(GRUB_MACHINE_DDR2_BASE)
ld $t5, (%lo(GRUB_MACHINE_DDR2_BASE) + 0x30) ($t4)
ori $t0, $zero, 1
dsll $t0, $t0, 40
or $t5, $t5, $t0
sd $t5, (%lo(GRUB_MACHINE_DDR2_BASE) + 0x30) ($t4)
/* Desactivate DDR2 registers. */
lui $t0, 0xbfe0
ld $t1, 0x0180($t0)
ori $t1, $t1, 0x100
sd $t1, 0x0180($t0)
addiu $a0, $zero, -1
addiu $a1, $zero, -1
addiu $a2, $zero, -1

View file

@ -391,7 +391,31 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[],
free (core_img);
core_img = elf_img;
core_size = program_size + sizeof (*ehdr) + sizeof (*phdr);
}
}
else
{
char *rom_img;
size_t rom_size;
char *boot_path, *boot_img;
size_t boot_size;
boot_path = grub_util_get_path (dir, "fwstart.img");
boot_size = grub_util_get_image_size (boot_path);
boot_img = grub_util_read_image (boot_path);
rom_size = core_size + boot_size;
rom_img = xmalloc (rom_size);
memset (rom_img, 0, rom_size);
memcpy (rom_img, boot_img, boot_size);
memcpy (rom_img + boot_size, core_img, core_size);
free (core_img);
core_img = rom_img;
core_size = rom_size;
}
#endif
grub_util_write_image (core_img, core_size, out);