New bootloader now works. Added special print functions and print messages. sdclk is set to 3MHz after initialization currently.

This commit is contained in:
Jacob Pease 2024-08-02 15:19:52 -05:00
parent 3fde6c13f7
commit 1edd5bb39e
8 changed files with 179 additions and 44 deletions

View File

@ -4,6 +4,9 @@
#include "uart.h"
#include "spi.h"
#include "sd.h"
#include "time.h"
#include "riscv.h"
#include "fail.h"
/* int disk_read(BYTE * buf, LBA_t sector, UINT count, BYTE card_type) { */
@ -34,11 +37,31 @@
/* return 0;; */
/* } */
#define SYSTEMCLOCK 20000000
// Need to convert this
/* void print_progress(size_t count, size_t max) { */
/* const int bar_width = 50; */
/* float progress = (float) count / max; */
/* int bar_length = progress * bar_width; */
/* printf("\r["); */
/* for (int i = 0; i < bar_length; ++i) { */
/* printf("#"); */
/* } */
/* for (int i = bar_length; i < bar_width; ++i) { */
/* printf("-"); */
/* } */
/* printf("] %.2f%%", progress * 100); */
/* fflush(stdout); */
/* } */
int disk_read(BYTE * buf, LBA_t sector, UINT count) {
uint64_t r;
UINT i;
volatile uint8_t *p = buf;
UINT modulus = count/50;
uint8_t crc = 0;
crc = crc7(crc, 0x40 | SD_CMD_READ_BLOCK_MULTIPLE);
@ -52,48 +75,69 @@ int disk_read(BYTE * buf, LBA_t sector, UINT count) {
print_uart("disk_read: CMD18 failed. r = 0x");
print_uart_byte(r);
print_uart("\r\n");
return -1;
fail();
// return -1;
}
print_uart("\r Blocks loaded: ");
print_uart("0");
print_uart("/");
print_uart_dec(count);
// write_reg(SPI_CSMODE, SIFIVE_SPI_CSMODE_MODE_HOLD);
// Begin reading blocks
for (i = 0; i < count; i++) {
uint16_t crc, crc_exp;
// Read the data token
r = spi_readbyte();
/* if (r != SD_DATA_TOKEN) { */
/* print_uart("Didn't receive data token first thing. Shoot: "); */
/* print_uart_byte(r & 0xff); */
/* print_uart("\r\n"); */
/* return -1; */
/* } */
uint64_t n = 0;
// Wait for data token
while((r & 0xff) != SD_DATA_TOKEN);
while((r = spi_dummy()) != SD_DATA_TOKEN);
// println_with_byte("Received data token: 0x", r & 0xff);
// println_with_dec("Block ", i);
// Read block into memory.
for (int j = 0; j < 8; j++) {
*buf = sd_read64(&crc);
buf = buf + 64;
}
/* for (int j = 0; j < 64; j++) { */
/* *buf = sd_read64(&crc); */
/* println_with_addr("0x", *buf); */
/* buf = buf + 64; */
/* } */
crc = 0;
n = 512;
do {
uint8_t x = spi_dummy();
*p++ = x;
crc = crc16(crc, x);
} while (--n > 0);
// Read CRC16 and check
crc_exp = ((uint16_t)spi_txrx(0xff) << 8);
crc_exp |= spi_txrx(0xff);
crc_exp = ((uint16_t)spi_dummy() << 8);
crc_exp |= spi_dummy();
if (crc != crc_exp) {
print_uart("Stinking CRC16 didn't match on block read.\r\n");
print_uart_int(i);
print_uart("\r\n");
return -1;
//return -1;
fail();
}
if ( (i % modulus) == 0 ) {
print_uart("\r Blocks loaded: ");
print_uart_dec(i);
print_uart("/");
print_uart_dec(count);
}
}
sd_cmd(SD_CMD_STOP_TRANSMISSION, 0, 0x01);
print_uart("\r Blocks loaded: ");
print_uart_dec(count);
print_uart("/");
print_uart_dec(count);
// write_reg(SPI_CSMODE, SIFIVE_SPI_CSMODE_MODE_AUTO);
//spi_txrx(0xff);
print_uart("\r\n");
return 0;
}
@ -106,7 +150,7 @@ void copyFlash(QWORD address, QWORD * Dst, DWORD numBlocks) {
// Initialize UART for messages
init_uart(20000000, 115200);
// Print the wally banner
print_uart(BANNER);
@ -114,10 +158,8 @@ void copyFlash(QWORD address, QWORD * Dst, DWORD numBlocks) {
/* print_uart_dec(SYSTEMCLOCK); */
/* print_uart("\r\n"); */
println_with_dec("Hello, does this work? Here's the clock: ", SYSTEMCLOCK);
// Intialize the SD card
init_sd(SYSTEMCLOCK, SYSTEMCLOCK/2);
init_sd(SYSTEMCLOCK, 3000000);
ret = gpt_load_partitions();
}

View File

@ -32,5 +32,7 @@ typedef QWORD LBA_t;
// Export disk_read
int disk_read(BYTE * buf, LBA_t sector, UINT count);
#define SYSTEMCLOCK 20000000
#endif // WALLYBOOT

View File

@ -11,11 +11,13 @@ int gpt_load_partitions() {
int ret = 0;
//ret = disk_read(/* BYTE * buf, LBA_t sector, UINT count, BYTE card_type */);
print_time();
println("Getting GPT information.");
ret = disk_read(lba1_buf, 1, 1);
gpt_pth_t *lba1 = (gpt_pth_t *)lba1_buf;
print_time();
println("Getting partition entries.");
BYTE lba2_buf[512];
ret = disk_read(lba2_buf, (LBA_t)lba1->partition_entries_lba, 1);
@ -26,6 +28,7 @@ int gpt_load_partitions() {
partition_entries_t *kernel = (partition_entries_t *)(lba2_buf + 256);
// Load device tree
print_time();
println_with_int("Loading device tree at: 0x", FDT_ADDRESS);
ret = disk_read((BYTE *)FDT_ADDRESS, fdt->first_lba, fdt->last_lba - fdt->first_lba + 1);
if (ret < 0) {
@ -34,6 +37,7 @@ int gpt_load_partitions() {
}
// Load OpenSBI
print_time();
println_with_int("Loading OpenSBI at: 0x", OPENSBI_ADDRESS);
ret = disk_read((BYTE *)OPENSBI_ADDRESS, opensbi->first_lba, opensbi->last_lba - opensbi->first_lba + 1);
if (ret < 0) {
@ -42,6 +46,7 @@ int gpt_load_partitions() {
}
// Load Linux
print_time();
println_with_int("Loading Linux Kernel at: 0x", KERNEL_ADDRESS);
ret = disk_read((BYTE *)KERNEL_ADDRESS, kernel->first_lba,kernel->last_lba - kernel->first_lba + 1);
if (ret < 0) {
@ -49,5 +54,8 @@ int gpt_load_partitions() {
return -1;
}
print_time();
println("Done! Flashing LEDs and jumping to OpenSBI...");
return 0;
}

View File

@ -1,6 +1,8 @@
#include "sd.h"
#include "spi.h"
#include "uart.h"
#include "fail.h"
#include "time.h"
// Parallel byte update CRC7-CCITT algorithm.
// The result is the CRC7 result, left shifted over by 1
@ -36,9 +38,11 @@ uint16_t crc16(uint16_t crc, uint8_t data) {
// watermark and interrupt features to determine when a
// transfer is complete. This should save on cycles since
// no arbitrary delays need to be added.
uint64_t sd_cmd(uint8_t cmd, uint32_t arg, uint8_t crc) {
uint8_t response_len;
uint8_t i;
uint8_t shiftAmnt;
uint64_t r;
uint8_t rbyte;
@ -53,6 +57,7 @@ uint64_t sd_cmd(uint8_t cmd, uint32_t arg, uint8_t crc) {
break;
case 12:
response_len = R1B_RESPONSE;
break;
default:
response_len = R1_RESPONSE;
break;
@ -70,6 +75,7 @@ uint64_t sd_cmd(uint8_t cmd, uint32_t arg, uint8_t crc) {
// Write all 7 bytes into transfer fifo
// spi_sendbyte(0xff);
spi_dummy();
spi_sendbyte(0x40 | cmd);
spi_sendbyte(arg >> 24);
spi_sendbyte(arg >> 16);
@ -89,30 +95,34 @@ uint64_t sd_cmd(uint8_t cmd, uint32_t arg, uint8_t crc) {
// Send "dummy signals". Since SPI is duplex,
// useless bytes must be transferred
for (i = 0; i < response_len; i++) {
spi_sendbyte(0xFF);
}
/* for (i = 0; i < response_len; i++) { */
/* spi_sendbyte(0xFF); */
/* } */
// Wait for transfer fifo again
waittx();
/* // Wait for transfer fifo again */
/* waittx(); */
// Wait for actual response from SD card
// All responses start with a 0. Output of SDCIn is high, unless
// a message is being transferred.
do {
rbyte = spi_txrx(0xff);
rbyte = spi_dummy();
} while ( (rbyte & 0x80) != 0 );
r = r | (rbyte << ((response_len - 1)*8));
// Note about the compiler. In order to compile as sll instead of
// sllw, the number to shift has to be a 64 bit number.
r = ((uint64_t)rbyte) << ((response_len - 1)*8);
// Read rxfifo response
for (i = 1; i < response_len; i++) {
rbyte = spi_readbyte();
r = r | (rbyte << ((response_len - 1 - i)*8));
rbyte = spi_dummy();
r = r | (((uint64_t)rbyte) << ((response_len - 1 - i)*8));
}
if (cmd != 18) {
write_reg(SPI_CSMODE, SIFIVE_SPI_CSMODE_MODE_AUTO);
} else {
spi_dummy();
}
return r;
} // sd_cmd
@ -122,16 +132,16 @@ uint64_t sd_read64(uint16_t * crc) {
uint8_t rbyte;
int i;
for (i = 0; i < 8; i++) {
spi_sendbyte(0xFF);
}
/* for (i = 0; i < 8; i++) { */
/* spi_sendbyte(0xFF); */
/* } */
waittx();
/* waittx(); */
for (i = 0; i < 8; i++) {
rbyte = spi_readbyte();
rbyte = spi_dummy();
*crc = crc16(*crc, rbyte);
r = r | (rbyte << ((8 - 1 - i)*8));
r = r | ((uint64_t)(rbyte) << ((8 - 1 - i)*8));
}
return r;
@ -147,11 +157,15 @@ uint64_t sd_read64(uint16_t * crc) {
// This first initializes the SPI peripheral then initializes the SD
// card itself. We use the uart to display anything that goes wrong.
int init_sd(uint32_t freq, uint32_t sdclk){
print_time();
println("Initializing SPI Controller.");
spi_init();
uint64_t r;
uint32_t newClockDiv;
int n;
print_time();
println("Initializing SD Card in SPI mode.");
// This is necessary. This is the card's pre-init state initialization.
write_reg(SPI_CSMODE, SIFIVE_SPI_CSMODE_MODE_OFF);
@ -165,31 +179,48 @@ int init_sd(uint32_t freq, uint32_t sdclk){
// Initializes SD card into SPI mode if CS is asserted '0'
// We expect to get the R1 response 0x01 which means that the
// card has been put into the idle state.
print_time();
print_uart("CMD0: ");
n = 0;
do {
r = CMD0();
n++;
if (n == 1000) {
fail();
}
} while ( r != 0x01 );
println_with_r1("Success, r = 0x", r & 0xff);
// CMD8 -------------------------------------------------------------
//
//
print_time();
print_uart("CMD8: ");
r = CMD8();
if ((r & 0x000000ff0000ffff) != 0x01000001aa) {
println_with_r7("Failed, 0x", r);
fail();
}
println_with_r7("Success, 0x", r);
// ACMD41 -----------------------------------------------------------
print_time();
print_uart("ACMD41: ");
n = 0;
do {
CMD55();
r = ACMD41();
n++;
if (n == 1000) {
fail();
}
} while (r == 0x1);
println_with_r1("Success, r = 0x", r & 0xff);
print_time();
println_with_dec("New clock frequency: ", (uint64_t)sdclk);
spi_set_clock(freq, sdclk);
print_time();
println("SD card is initialized.");
}

View File

@ -55,11 +55,15 @@
/* } */
uint8_t spi_txrx(uint8_t byte) {
spi_sendbyte(0xFF);
spi_sendbyte(byte);
waittx();
return spi_readbyte();
}
uint8_t spi_dummy() {
return spi_txrx(0xff);
}
/* inline uint8_t spi_readbyte() { */
/* return read_reg(SPI_RXDATA); */
/* } */

View File

@ -50,6 +50,7 @@
//inline void waittx();
//inline void waitrx();
uint8_t spi_txrx(uint8_t byte);
uint8_t spi_dummy();
//inline uint8_t spi_readbyte();
uint64_t spi_read64();
void spi_init();

View File

@ -1,6 +1,5 @@
#include "uart.h"
void write_reg_u8(uintptr_t addr, uint8_t value)
{
volatile uint8_t *loc_addr = (volatile uint8_t *)addr;
@ -78,7 +77,7 @@ void print_uart_dec(uint64_t addr) {
// floor(log(2^64)) = 19
char str[19] = {'\0'};
uint8_t length = 0;
uint8_t length = 1;
uint64_t cur = addr;
while (cur != 0) {
@ -94,6 +93,43 @@ void print_uart_dec(uint64_t addr) {
}
}
// Print a floating point number on the UART
void print_uart_float(float num, int precision) {
char str[32] = {'\0'};
char digit;
uint8_t length = precision + 1;
int i;
uint64_t cur;
str[precision] = '.';
int pow = 1;
// Calculate power for precision
for (i = 0; i < precision; i++) {
pow = pow * 10;
}
cur = (uint64_t)(num * pow);
for (i = 0; i < precision; i++) {
digit = bin_to_hex_table[cur % 10];
str[i] = digit;
cur = cur / 10;
}
cur = (uint64_t)num;
do {
digit = bin_to_hex_table[cur % 10];
str[length] = digit;
cur = cur/10;
length++;
} while (cur != 0);
for (i = length; i > -1; i--) {
write_serial(str[i]);
}
}
/* void print_uart_int(uint32_t addr) */
/* { */
/* int i; */

View File

@ -1,5 +1,7 @@
#pragma once
#include <stdint.h>
#include "riscv.h"
#include "time.h"
// UART register addresses
#define UART_BASE 0x10000000
@ -28,6 +30,8 @@ void print_uart_dec(uint64_t addr);
void print_uart_addr(uint64_t addr);
void print_uart_hex(uint64_t addr, int n);
void print_uart_byte(uint8_t byte);
void print_uart_float(float num, int precision);
// void print_time();
// Print numbers in hex with specified widths
#define print_uart_int(addr) print_uart_hex(addr, 4)
@ -44,4 +48,11 @@ void print_uart_byte(uint8_t byte);
#define println_with_addr(msg, num) print_uart(msg); print_uart_addr(num); print_uart("\r\n")
#define println_with_r1(msg, num) print_uart(msg); print_r1(num); print_uart("\r\n")
#define println_with_r7(msg, num) print_uart(msg); print_r7(num); print_uart("\r\n")
#define println_with_float(msg, num) print_uart(msg); set_status_fs(); print_uart_float(num,5); clear_status_fs(); print_uart("\r\n")
/* #define print_time() print_uart("["); \ */
/* set_status_fs(); \ */
/* print_uart_float(getTime(),5); \ */
/* clear_status_fs(); \ */
/* print_uart("] ") */