Init DDR2 controller
This commit is contained in:
parent
7517048135
commit
813a5f2d33
4 changed files with 307 additions and 35 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue