put together coldboot startup firmware
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sat, 19 Feb 2022 15:32:17 +0000 (15:32 +0000)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sat, 19 Feb 2022 15:32:17 +0000 (15:32 +0000)
coldboot/Makefile [new file with mode: 0644]
coldboot/coldboot.c [new file with mode: 0644]
coldboot/head.S [new file with mode: 0644]
coldboot/powerpc.lds [new file with mode: 0644]
libgram/include/gram.h [new file with mode: 0644]
libgram/src/calibration.c [new file with mode: 0644]
libgram/src/dfii.c [new file with mode: 0644]
libgram/src/dfii.h [new file with mode: 0644]
libgram/src/helpers.h [new file with mode: 0644]
libgram/src/hw_regs.h [new file with mode: 0644]
libgram/src/init.c [new file with mode: 0644]

diff --git a/coldboot/Makefile b/coldboot/Makefile
new file mode 100644 (file)
index 0000000..ef71b65
--- /dev/null
@@ -0,0 +1,56 @@
+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 *~
+
diff --git a/coldboot/coldboot.c b/coldboot/coldboot.c
new file mode 100644 (file)
index 0000000..3026442
--- /dev/null
@@ -0,0 +1,157 @@
+#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;
+}
+
diff --git a/coldboot/head.S b/coldboot/head.S
new file mode 100644 (file)
index 0000000..104cb7e
--- /dev/null
@@ -0,0 +1,107 @@
+/* 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
diff --git a/coldboot/powerpc.lds b/coldboot/powerpc.lds
new file mode 100644 (file)
index 0000000..5e2f317
--- /dev/null
@@ -0,0 +1,13 @@
+SECTIONS
+{
+       _start = .;
+       . = 0;
+       .head : {
+               KEEP(*(.head))
+       }
+       . = 0x1000;
+       .text : { *(.text) }
+       . = 0x2c00;
+       .data : { *(.data) }
+       .bss : { *(.bss) }
+}
diff --git a/libgram/include/gram.h b/libgram/include/gram.h
new file mode 100644 (file)
index 0000000..401713e
--- /dev/null
@@ -0,0 +1,41 @@
+#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 */
diff --git a/libgram/src/calibration.c b/libgram/src/calibration.c
new file mode 100644 (file)
index 0000000..a77c44a
--- /dev/null
@@ -0,0 +1,137 @@
+#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);
+}
diff --git a/libgram/src/dfii.c b/libgram/src/dfii.c
new file mode 100644 (file)
index 0000000..58519bd
--- /dev/null
@@ -0,0 +1,93 @@
+#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);
+}
diff --git a/libgram/src/dfii.h b/libgram/src/dfii.h
new file mode 100644 (file)
index 0000000..3e84f8c
--- /dev/null
@@ -0,0 +1,23 @@
+#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 */
diff --git a/libgram/src/helpers.h b/libgram/src/helpers.h
new file mode 100644 (file)
index 0000000..e0f6b0f
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef HELPERS_H
+#define HELPERS_H
+
+__attribute__((unused)) static inline void cdelay(int i) {
+       while(i > 0) {
+               __asm__ volatile("nop");
+               i--;
+       }
+}
+
+#endif /* HELPERS_H */
diff --git a/libgram/src/hw_regs.h b/libgram/src/hw_regs.h
new file mode 100644 (file)
index 0000000..ac0457e
--- /dev/null
@@ -0,0 +1,24 @@
+#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
diff --git a/libgram/src/init.c b/libgram/src/init.c
new file mode 100644 (file)
index 0000000..d869f0e
--- /dev/null
@@ -0,0 +1,15 @@
+#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;
+}