--- /dev/null
+ARCH = $(shell uname -m)
+ifneq ("$(ARCH)", "ppc64")
+ifneq ("$(ARCH)", "ppc64le")
+ CROSS_COMPILE ?= powerpc64le-linux-gnu-
+endif
+endif
+
+LIBGRAMDIR = ../libgram
+LIBGRAMINC = ../libgram/include
+
+GRAMOBJS := $(LIBGRAMDIR)/src/init.o \
+ $(LIBGRAMDIR)/src/dfii.o \
+ $(LIBGRAMDIR)/src/calibration.o
+
+CC = $(CROSS_COMPILE)gcc
+LD = $(CROSS_COMPILE)ld
+OBJCOPY = $(CROSS_COMPILE)objcopy
+
+CFLAGS = -Os -g -Wall -std=c99 -msoft-float -mno-string \
+ -mno-multiple -mno-vsx -mno-altivec -mlittle-endian \
+ -fno-stack-protector -mstrict-align -ffreestanding \
+ -fdata-sections -ffunction-sections -I../include \
+ -I $(LIBGRAMINC)
+ASFLAGS = $(CFLAGS)
+LDFLAGS = -T powerpc.lds
+
+all: coldboot.hex
+
+console.o: ../lib/console.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
+
+init.o: ../libgram/src/init.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
+
+dfii.o: ../libgram/src/dfii.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
+
+calibration.o: ../libgram/src/calibration.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
+
+coldboot.elf: coldboot.o head.o ../lib/console.o $(GRAMOBJS)
+ $(LD) $(LDFLAGS) -o $@ $^
+
+coldboot.bin: coldboot.elf
+ $(OBJCOPY) -O binary $^ $@
+
+coldboot.hex: coldboot.bin
+ ../scripts/bin2hex.py $^ > $@
+ powerpc64le-linux-gnu-objdump -D coldboot.elf > coldboot.as
+
+
+clean:
+ @rm -f *.o coldboot.elf coldboot.bin coldboot.hex coldboot.as
+distclean: clean
+ rm -f *~
+
--- /dev/null
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "console.h"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <gram.h>
+
+static inline uint32_t read32(const void *addr)
+{
+ return *(volatile uint32_t *)addr;
+}
+
+static inline void write32(void *addr, uint32_t value)
+{
+ *(volatile uint32_t *)addr = value;
+}
+
+struct uart_regs {
+ uint32_t divisor;
+ uint32_t rx_data;
+ uint32_t rx_rdy;
+ uint32_t rx_err;
+ uint32_t tx_data;
+ uint32_t tx_rdy;
+ uint32_t zero0; // reserved
+ uint32_t zero1; // reserved
+ uint32_t ev_status;
+ uint32_t ev_pending;
+ uint32_t ev_enable;
+};
+
+void memcpy(void *dest, void *src, size_t n) {
+ int i;
+ //cast src and dest to char*
+ char *src_char = (char *)src;
+ char *dest_char = (char *)dest;
+ for (i=0; i<n; i++)
+ dest_char[i] = src_char[i]; //copy contents byte by byte
+}
+
+void uart_writeuint32(uint32_t val) {
+ const char lut[] = { '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+ uint8_t *val_arr = &val;
+ size_t i;
+
+ for (i = 0; i < 4; i++) {
+ putchar(lut[(val_arr[3-i] >> 4) & 0xF]);
+ putchar(lut[val_arr[3-i] & 0xF]);
+ }
+}
+
+void isr(void) {
+
+}
+
+int main(void) {
+ const int kNumIterations = 65536;
+ int res, failcnt = 0;
+ uint32_t tmp;
+ volatile uint32_t *ram = 0x10000000;
+ console_init();
+ puts("Firmware launched...\n");
+
+ puts("DRAM init... ");
+ struct gramCtx ctx;
+ struct gramProfile profile = {
+ .mode_registers = {
+ 0x320, 0x6, 0x200, 0x0
+ },
+ .rdly_p0 = 2,
+ .rdly_p1 = 2,
+ };
+ struct gramProfile profile2;
+ gram_init(&ctx, &profile, (void*)0x10000000,
+ (void*)0x00009000,
+ (void*)0x00008000);
+ puts("done\n");
+
+ puts("Rdly\np0: ");
+ for (size_t i = 0; i < 8; i++) {
+ profile2.rdly_p0 = i;
+ gram_load_calibration(&ctx, &profile2);
+ gram_reset_burstdet(&ctx);
+ for (size_t j = 0; j < 128; j++) {
+ tmp = ram[j];
+ }
+ if (gram_read_burstdet(&ctx, 0)) {
+ puts("1");
+ } else {
+ puts("0");
+ }
+ }
+ puts("\n");
+
+ puts("Rdly\np1: ");
+ for (size_t i = 0; i < 8; i++) {
+ profile2.rdly_p1 = i;
+ gram_load_calibration(&ctx, &profile2);
+ gram_reset_burstdet(&ctx);
+ for (size_t j = 0; j < 128; j++) {
+ tmp = ram[j];
+ }
+ if (gram_read_burstdet(&ctx, 1)) {
+ puts("1");
+ } else {
+ puts("0");
+ }
+ }
+ puts("\n");
+
+ puts("Auto calibrating... ");
+ res = gram_generate_calibration(&ctx, &profile2);
+ if (res != GRAM_ERR_NONE) {
+ puts("failed\n");
+ gram_load_calibration(&ctx, &profile);
+ } else {
+ gram_load_calibration(&ctx, &profile2);
+ }
+ puts("done\n");
+
+ puts("Auto calibration profile:");
+ puts("p0 rdly:");
+ uart_writeuint32(profile2.rdly_p0);
+ puts(" p1 rdly:");
+ uart_writeuint32(profile2.rdly_p1);
+ puts("\n");
+
+ puts("DRAM test... \n");
+ for (size_t i = 0; i < kNumIterations; i++) {
+ ram[i] = 0xDEAF0000 | i*4;
+ }
+
+ for (size_t i = 0; i < kNumIterations; i++) {
+ if (ram[i] != (0xDEAF0000 | i*4)) {
+ puts("fail : *(0x");
+ uart_writeuint32(&ram[i]);
+ puts(") = ");
+ uart_writeuint32(ram[i]);
+ putchar('\n');
+ failcnt++;
+
+ if (failcnt > 10) {
+ puts("Test canceled (more than 10 errors)\n");
+ break;
+ }
+ }
+ }
+ puts("done\n");
+
+ while (1);
+
+ return 0;
+}
+
--- /dev/null
+/* Copyright 2013-2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define STACK_TOP 0x2900
+
+#define FIXUP_ENDIAN \
+ tdi 0,0,0x48; /* Reverse endian of b . + 8 */ \
+ b 191f; /* Skip trampoline if endian is good */ \
+ .long 0xa600607d; /* mfmsr r11 */ \
+ .long 0x01006b69; /* xori r11,r11,1 */ \
+ .long 0x05009f42; /* bcl 20,31,$+4 */ \
+ .long 0xa602487d; /* mflr r10 */ \
+ .long 0x14004a39; /* addi r10,r10,20 */ \
+ .long 0xa64b5a7d; /* mthsrr0 r10 */ \
+ .long 0xa64b7b7d; /* mthsrr1 r11 */ \
+ .long 0x2402004c; /* hrfid */ \
+191:
+
+
+/* Load an immediate 64-bit value into a register */
+#define LOAD_IMM64(r, e) \
+ lis r,(e)@highest; \
+ ori r,r,(e)@higher; \
+ rldicr r,r, 32, 31; \
+ oris r,r, (e)@h; \
+ ori r,r, (e)@l;
+
+ .section ".head","ax"
+
+ /*
+ * Microwatt currently enters in LE mode at 0x0, so we don't need to
+ * do any endian fix ups>
+ */
+ . = 0
+.global _start
+_start:
+ b boot_entry
+
+ /* QEMU enters at 0x10 */
+ . = 0x10
+ FIXUP_ENDIAN
+ b boot_entry
+
+ . = 0x100
+ FIXUP_ENDIAN
+ b boot_entry
+
+.global boot_entry
+boot_entry:
+ /* setup stack */
+ LOAD_IMM64(%r1, STACK_TOP - 0x100)
+ LOAD_IMM64(%r12, main)
+ mtctr %r12,
+ bctrl
+ b .
+
+#define EXCEPTION(nr) \
+ .= nr ;\
+ b .
+
+ /* More exception stubs */
+ EXCEPTION(0x300)
+ EXCEPTION(0x380)
+ EXCEPTION(0x400)
+ EXCEPTION(0x480)
+ EXCEPTION(0x500)
+ EXCEPTION(0x600)
+ EXCEPTION(0x700)
+ EXCEPTION(0x800)
+ EXCEPTION(0x900)
+ EXCEPTION(0x980)
+ EXCEPTION(0xa00)
+ EXCEPTION(0xb00)
+ EXCEPTION(0xc00)
+ EXCEPTION(0xd00)
+ EXCEPTION(0xe00)
+ EXCEPTION(0xe20)
+ EXCEPTION(0xe40)
+ EXCEPTION(0xe60)
+ EXCEPTION(0xe80)
+ EXCEPTION(0xf00)
+ EXCEPTION(0xf20)
+ EXCEPTION(0xf40)
+ EXCEPTION(0xf60)
+ EXCEPTION(0xf80)
+#if 0
+ EXCEPTION(0x1000)
+ EXCEPTION(0x1100)
+ EXCEPTION(0x1200)
+ EXCEPTION(0x1300)
+ EXCEPTION(0x1400)
+ EXCEPTION(0x1500)
+ EXCEPTION(0x1600)
+#endif
--- /dev/null
+SECTIONS
+{
+ _start = .;
+ . = 0;
+ .head : {
+ KEEP(*(.head))
+ }
+ . = 0x1000;
+ .text : { *(.text) }
+ . = 0x2c00;
+ .data : { *(.data) }
+ .bss : { *(.bss) }
+}
--- /dev/null
+#ifndef GRAM_H
+#define GRAM_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+enum GramError {
+ GRAM_ERR_NONE = 0,
+ GRAM_ERR_UNDOCUMENTED,
+ GRAM_ERR_RDLY_MAX,
+};
+
+struct gramCoreRegs;
+struct gramPHYRegs;
+struct gramCtx {
+ volatile void *ddr_base;
+ volatile struct gramCoreRegs *core;
+ volatile struct gramPHYRegs *phy;
+ void *user_data;
+};
+
+struct gramProfile {
+ uint8_t rdly_p0;
+ uint8_t rdly_p1;
+ uint32_t mode_registers[4];
+};
+
+extern __attribute__((visibility ("default"))) int gram_init(struct gramCtx *ctx, const struct gramProfile *profile, void *ddr_base, void *core_base, void *phy_base);
+extern __attribute__((visibility ("default"))) int gram_generate_calibration(const struct gramCtx *ctx, struct gramProfile *profile);
+extern __attribute__((visibility ("default"))) void gram_load_calibration(const struct gramCtx *ctx, const struct gramProfile *profile);
+
+extern __attribute__((visibility ("default"))) void gram_reset_burstdet(const struct gramCtx *ctx);
+extern __attribute__((visibility ("default"))) bool gram_read_burstdet(const struct gramCtx *ctx, int phase);
+
+#ifdef GRAM_RW_FUNC
+extern uint32_t gram_read(const struct gramCtx *ctx, void *addr);
+extern int gram_write(const struct gramCtx *ctx, void *addr, uint32_t value);
+#endif /* GRAM_RW_FUNC */
+
+#endif /* GRAM_H */
--- /dev/null
+#include <stdint.h>
+#include <stdio.h>
+
+#include "hw_regs.h"
+#include <gram.h>
+#include "dfii.h"
+#include "helpers.h"
+
+static void set_rdly(const struct gramCtx *ctx, unsigned int phase, unsigned int rdly) {
+#ifdef GRAM_RW_FUNC
+ if (phase == 0) {
+ gram_write(ctx, (void*)&(ctx->phy->rdly_p0), rdly);
+ } else if (phase == 1) {
+ gram_write(ctx, (void*)&(ctx->phy->rdly_p1), rdly);
+ }
+#else
+ if (phase == 0) {
+ ctx->phy->rdly_p0 = rdly;
+ } else if (phase == 1) {
+ ctx->phy->rdly_p1 = rdly;
+ }
+#endif
+}
+
+void gram_reset_burstdet(const struct gramCtx *ctx) {
+#ifdef GRAM_RW_FUNC
+ gram_write(ctx, (void*)&(ctx->phy->burstdet), 0);
+#else
+ ctx->phy->burstdet = 0;
+#endif
+}
+
+bool gram_read_burstdet(const struct gramCtx *ctx, int phase) {
+#ifdef GRAM_RW_FUNC
+ return !!(gram_read(ctx, (void*)&(ctx->phy->burstdet)) & (1 << phase));
+#else
+ return !!(ctx->phy->burstdet & (1 << phase));
+#endif
+}
+
+int gram_generate_calibration(const struct gramCtx *ctx, struct gramProfile *profile) {
+ unsigned char rdly;
+ unsigned char min_rdly_p0, min_rdly_p1;
+ unsigned char max_rdly_p0 = 7, max_rdly_p1 = 7;
+ uint32_t tmp;
+ volatile uint32_t *ram = ctx->ddr_base;
+ size_t i;
+
+ dfii_setsw(ctx, true);
+
+ (void)tmp;
+
+ // Find minimal rdly
+ for (rdly = 0; rdly < 8; rdly++) {
+ profile->rdly_p0 = rdly;
+ gram_load_calibration(ctx, profile);
+ gram_reset_burstdet(ctx);
+
+ for (i = 0; i < 128; i++) {
+ tmp = ram[i];
+ }
+
+ if (gram_read_burstdet(ctx, 0)) {
+ min_rdly_p0 = rdly;
+ break;
+ } else if (rdly == 7) {
+ return GRAM_ERR_RDLY_MAX;
+ }
+ }
+
+ for (rdly = 0; rdly < 8; rdly++) {
+ profile->rdly_p1 = rdly;
+ gram_load_calibration(ctx, profile);
+ gram_reset_burstdet(ctx);
+
+ for (i = 0; i < 128; i++) {
+ tmp = ram[i];
+ }
+
+ if (gram_read_burstdet(ctx, 1)) {
+ min_rdly_p1 = rdly;
+ break;
+ } else if (rdly == 7) {
+ return GRAM_ERR_RDLY_MAX;
+ }
+ }
+
+ // Find maximal rdly
+ for (rdly = min_rdly_p0+1; rdly < 8; rdly++) {
+ profile->rdly_p0 = rdly;
+ gram_load_calibration(ctx, profile);
+ gram_reset_burstdet(ctx);
+
+ for (i = 0; i < 128; i++) {
+ tmp = ram[i];
+ }
+
+ if (!gram_read_burstdet(ctx, 0)) {
+ max_rdly_p0 = rdly - 1;
+ break;
+ } else if (rdly == 7) {
+ return GRAM_ERR_RDLY_MAX;
+ }
+ }
+
+ for (rdly = min_rdly_p1+1; rdly < 8; rdly++) {
+ profile->rdly_p1 = rdly;
+ gram_load_calibration(ctx, profile);
+ gram_reset_burstdet(ctx);
+
+ for (i = 0; i < 128; i++) {
+ tmp = ram[i];
+ }
+
+ if (!gram_read_burstdet(ctx, 1)) {
+ max_rdly_p1 = rdly - 1;
+ break;
+ } else if (rdly == 7) {
+ return GRAM_ERR_RDLY_MAX;
+ }
+ }
+
+ dfii_setsw(ctx, false);
+
+ // Store average rdly value
+ profile->rdly_p0 = (min_rdly_p0+max_rdly_p0)/2;
+ profile->rdly_p1 = (min_rdly_p1+max_rdly_p1)/2;
+
+ return GRAM_ERR_NONE;
+}
+
+void gram_load_calibration(const struct gramCtx *ctx, const struct gramProfile *profile) {
+ dfii_setsw(ctx, true);
+ set_rdly(ctx, 0, profile->rdly_p0);
+ set_rdly(ctx, 1, profile->rdly_p1);
+ dfii_setsw(ctx, false);
+}
--- /dev/null
+#include <stdint.h>
+
+#include "hw_regs.h"
+#include <gram.h>
+#include "dfii.h"
+#include "helpers.h"
+
+static void dfii_setcontrol(const struct gramCtx *ctx, uint8_t val) {
+#ifdef GRAM_RW_FUNC
+ gram_write(ctx, (void*)&(ctx->core->control), val);
+#else
+ ctx->core->control = val;
+#endif
+}
+
+void dfii_setsw(const struct gramCtx *ctx, bool software_control) {
+ if (software_control) {
+ dfii_setcontrol(ctx, DFII_CONTROL_CKE|DFII_CONTROL_ODT);
+ } else {
+ dfii_setcontrol(ctx, DFII_CONTROL_SEL|DFII_CONTROL_RESET);
+ }
+}
+
+void dfii_set_p0_address(const struct gramCtx *ctx, uint32_t val) {
+#ifdef GRAM_RW_FUNC
+ gram_write(ctx, (void*)&(ctx->core->phases[0].address), val);
+#else
+ ctx->core->phases[0].address = val;
+#endif
+}
+
+void dfii_set_p0_baddress(const struct gramCtx *ctx, uint32_t val) {
+#ifdef GRAM_RW_FUNC
+ gram_write(ctx, (void*)&(ctx->core->phases[0].baddress), val);
+#else
+ ctx->core->phases[0].baddress = val;
+#endif
+}
+
+void dfii_p0_command(const struct gramCtx *ctx, uint32_t cmd) {
+#ifdef GRAM_RW_FUNC
+ gram_write(ctx, (void*)&(ctx->core->phases[0].command), cmd);
+ gram_write(ctx, (void*)&(ctx->core->phases[0].command_issue), 1);
+#else
+ ctx->core->phases[0].command = cmd;
+ ctx->core->phases[0].command_issue = 1;
+#endif
+}
+
+/* Set MRx register */
+static void dfii_set_mr(const struct gramCtx *ctx, uint8_t mr, uint16_t val) {
+ dfii_set_p0_address(ctx, val);
+ dfii_set_p0_baddress(ctx, mr);
+ dfii_p0_command(ctx, DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
+}
+
+#define MR0_DLL_RESET (1 << 8)
+void dfii_initseq(const struct gramCtx *ctx, const struct gramProfile *profile) {
+ /* Release reset */
+ dfii_set_p0_address(ctx, 0x0);
+ dfii_set_p0_baddress(ctx, 0);
+ dfii_setcontrol(ctx, DFII_CONTROL_ODT);
+ cdelay(50000);
+
+ /* Bring CKE high */
+ dfii_set_p0_address(ctx, 0x0);
+ dfii_set_p0_baddress(ctx, 0);
+ dfii_setcontrol(ctx, DFII_CONTROL_CKE|DFII_CONTROL_ODT);
+ cdelay(10000);
+
+ /* Load Mode Register 2, CWL=5 */
+ dfii_set_mr(ctx, 2, profile->mode_registers[2]);
+
+ /* Load Mode Register 3 */
+ dfii_set_mr(ctx, 3, profile->mode_registers[3]);
+
+ /* Load Mode Register 1 */
+ dfii_set_mr(ctx, 1, profile->mode_registers[1]);
+
+ /* Load Mode Register 0, CL=6, BL=8 */
+ dfii_set_mr(ctx, 0, profile->mode_registers[0]);
+ if (profile->mode_registers[0] & MR0_DLL_RESET) {
+ cdelay(100);
+ dfii_set_mr(ctx, 0, profile->mode_registers[0] & ~MR0_DLL_RESET);
+ }
+ cdelay(600);
+
+ /* ZQ Calibration */
+ dfii_set_p0_address(ctx, 0x400);
+ dfii_set_p0_baddress(ctx, 0);
+ dfii_p0_command(ctx, DFII_COMMAND_WE|DFII_COMMAND_CS);
+ cdelay(600);
+}
--- /dev/null
+#ifndef DFII_H
+#define DFII_H
+
+#include <stdbool.h>
+
+#define DFII_CONTROL_SEL (1 << 0)
+#define DFII_CONTROL_CKE (1 << 1)
+#define DFII_CONTROL_ODT (1 << 2)
+#define DFII_CONTROL_RESET (1 << 3)
+
+#define DFII_COMMAND_CS (1 << 0)
+#define DFII_COMMAND_WE (1 << 1)
+#define DFII_COMMAND_CAS (1 << 2)
+#define DFII_COMMAND_RAS (1 << 3)
+#define DFII_COMMAND_WRDATA (1 << 4)
+
+void dfii_setsw(const struct gramCtx *ctx, bool software_control);
+void dfii_initseq(const struct gramCtx *ctx, const struct gramProfile *profile);
+void dfii_set_p0_address(const struct gramCtx *ctx, uint32_t val);
+void dfii_set_p0_baddress(const struct gramCtx *ctx, uint32_t val);
+void dfii_p0_command(const struct gramCtx *ctx, uint32_t cmd);
+
+#endif /* DFII_H */
--- /dev/null
+#ifndef HELPERS_H
+#define HELPERS_H
+
+__attribute__((unused)) static inline void cdelay(int i) {
+ while(i > 0) {
+ __asm__ volatile("nop");
+ i--;
+ }
+}
+
+#endif /* HELPERS_H */
--- /dev/null
+#ifndef HW_REGS_H
+#define HW_REGS_H
+
+struct gramPHYRegs {
+ uint32_t burstdet;
+ uint32_t rdly_p0;
+ uint32_t rdly_p1;
+} __attribute__((packed));
+
+struct DFII_Phase {
+ uint32_t command;
+ uint32_t command_issue;
+ uint32_t address;
+ uint32_t baddress;
+ uint32_t wrdata;
+ uint32_t rddata;
+} __attribute__((packed));
+
+struct gramCoreRegs {
+ uint32_t control;
+ struct DFII_Phase phases[4];
+} __attribute__((packed));
+
+#endif /* HW_REGS_H */
\ No newline at end of file
--- /dev/null
+#include <gram.h>
+#include "dfii.h"
+
+int gram_init(struct gramCtx *ctx, const struct gramProfile *profile, void *ddr_base, void *core_base, void *phy_base) {
+ ctx->ddr_base = ddr_base;
+ ctx->core = core_base;
+ ctx->phy = phy_base;
+
+ dfii_setsw(ctx, true);
+ dfii_initseq(ctx, profile);
+ gram_load_calibration(ctx, profile);
+ dfii_setsw(ctx, false);
+
+ return GRAM_ERR_NONE;
+}