mirror of
https://github.com/openhwgroup/cvw
synced 2025-02-11 06:05:49 +00:00
New bootloader now works. Added special print functions and print messages. sdclk is set to 3MHz after initialization currently.
This commit is contained in:
parent
3fde6c13f7
commit
1edd5bb39e
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.");
|
||||
}
|
||||
|
||||
|
@ -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); */
|
||||
/* } */
|
||||
|
@ -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();
|
||||
|
@ -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; */
|
||||
|
@ -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("] ") */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user