flash: Enable read/write/erase access flash from firmware.
This commit is contained in:
parent
b4689cb3f1
commit
6f6fc652d5
@ -19,7 +19,7 @@ $(BUILD)/ec.rom: $(BUILD)/ec.ihx
|
||||
# Link object files into Intel Hex file
|
||||
$(BUILD)/ec.ihx: $(OBJ)
|
||||
@mkdir -p $(@D)
|
||||
$(CC) -o $@ $^
|
||||
$(CC) $(LDFLAGS) -o $@ $^
|
||||
|
||||
# Compile C files into object files
|
||||
$(OBJ): $(BUILD)/%.rel: src/%.c $(INCLUDE)
|
||||
|
@ -27,6 +27,9 @@ CFLAGS+=-I$(SYSTEM76_COMMON_DIR)/include
|
||||
# Add scratch ROM
|
||||
include $(SYSTEM76_COMMON_DIR)/scratch/scratch.mk
|
||||
|
||||
# Add scratch ROM for flash access
|
||||
include $(SYSTEM76_COMMON_DIR)/flash/flash.mk
|
||||
|
||||
console_internal:
|
||||
cargo build --manifest-path tool/Cargo.toml --release
|
||||
sudo tool/target/release/system76_ectool console
|
||||
|
55
src/board/system76/common/flash/flash.mk
Normal file
55
src/board/system76/common/flash/flash.mk
Normal file
@ -0,0 +1,55 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# Set flash ROM parameters
|
||||
FLASH_OFFSET=2048
|
||||
FLASH_SIZE=1024
|
||||
CFLAGS+=-DFLASH_OFFSET=$(FLASH_OFFSET) -DFLASH_SIZE=$(FLASH_SIZE)
|
||||
|
||||
# Copy parameters to use when compiling flash ROM
|
||||
FLASH_INCLUDE=$(INCLUDE)
|
||||
FLASH_CFLAGS=$(CFLAGS)
|
||||
|
||||
# Include flash source.
|
||||
FLASH_DIR=$(SYSTEM76_COMMON_DIR)/flash
|
||||
# Note: main.c *must* be first to ensure that flash_start is at the correct address
|
||||
FLASH_SRC=$(FLASH_DIR)/main.c
|
||||
FLASH_INCLUDE+=$(wildcard $(FLASH_DIR)/include/flash/*.h) $(FLASH_DIR)/flash.mk
|
||||
FLASH_CFLAGS+=-I$(FLASH_DIR)/include -D__FLASH__
|
||||
|
||||
FLASH_BUILD=$(BUILD)/flash
|
||||
FLASH_OBJ=$(patsubst src/%.c,$(FLASH_BUILD)/%.rel,$(FLASH_SRC))
|
||||
FLASH_CC=\
|
||||
sdcc \
|
||||
-mmcs51 \
|
||||
--model-large \
|
||||
--opt-code-size \
|
||||
--acall-ajmp \
|
||||
--code-loc $(FLASH_OFFSET) \
|
||||
--code-size $(FLASH_SIZE) \
|
||||
--Werror
|
||||
|
||||
# Convert from binary file to C header
|
||||
$(BUILD)/include/flash.h: $(FLASH_BUILD)/flash.rom
|
||||
@mkdir -p $(@D)
|
||||
xxd -s $(FLASH_OFFSET) --include < $< > $@
|
||||
|
||||
# Convert from Intel Hex file to binary file
|
||||
$(FLASH_BUILD)/flash.rom: $(FLASH_BUILD)/flash.ihx
|
||||
@mkdir -p $(@D)
|
||||
makebin -p < $< > $@
|
||||
|
||||
# Link object files into Intel Hex file
|
||||
$(FLASH_BUILD)/flash.ihx: $(FLASH_OBJ)
|
||||
@mkdir -p $(@D)
|
||||
$(FLASH_CC) -o $@ $^
|
||||
|
||||
# Compile C files into object files
|
||||
$(FLASH_OBJ): $(FLASH_BUILD)/%.rel: src/%.c $(FLASH_INCLUDE)
|
||||
@mkdir -p $(@D)
|
||||
$(FLASH_CC) $(FLASH_CFLAGS) -o $@ -c $<
|
||||
|
||||
# Include flash header in main firmware
|
||||
CFLAGS+=-I$(BUILD)/include
|
||||
LDFLAGS+=-Wl -g_flash_entry=$(FLASH_OFFSET)
|
||||
INCLUDE+=$(BUILD)/include/flash.h
|
||||
SRC+=$(FLASH_DIR)/wrapper.c
|
8
src/board/system76/common/flash/include/flash/entry.h
Normal file
8
src/board/system76/common/flash/include/flash/entry.h
Normal file
@ -0,0 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#ifndef _FLASH_ENTRY_H
|
||||
#define _FLASH_ENTRY_H
|
||||
|
||||
void flash_entry(uint32_t addr, uint8_t * data, uint32_t length, uint8_t command) __reentrant;
|
||||
|
||||
#endif // _FLASH_ENTRY_H
|
173
src/board/system76/common/flash/main.c
Normal file
173
src/board/system76/common/flash/main.c
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Evan Lojewski
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <board/flash.h>
|
||||
#include <flash/entry.h>
|
||||
|
||||
// EC indirect flash access
|
||||
volatile uint8_t __xdata __at(0x103B) ECINDAR0;
|
||||
volatile uint8_t __xdata __at(0x103C) ECINDAR1;
|
||||
volatile uint8_t __xdata __at(0x103D) ECINDAR2;
|
||||
volatile uint8_t __xdata __at(0x103E) ECINDAR3;
|
||||
volatile uint8_t __xdata __at(0x103F) ECINDDR;
|
||||
|
||||
#define SPI_DEVICE (0x70)
|
||||
#define SPI_FOLLOW_MODE (0x0F)
|
||||
#define SPI_CHIP_SELECT (0xFD)
|
||||
#define SPI_CHIP_DESELECT (0xFE)
|
||||
|
||||
#define SPI_READ_STATUS_COMMAND (0x05)
|
||||
#define SPI_READ_COMMAND (0x0B)
|
||||
#define SPI_WRITE_COMMAND (0x02)
|
||||
#define SPI_WRITE_ENABLE_COMMAND (0x06)
|
||||
#define SPI_READ_STATUS_COMMAND (0x05)
|
||||
|
||||
#define SPI_ERASE_SECTOR_COMMAND (0xD7)
|
||||
|
||||
#define SPI_STATUS_WIP (0x01)
|
||||
|
||||
void flash_enter_follow_mode(void);
|
||||
void flash_exit_follow_mode(void);
|
||||
void flash_wait(void);
|
||||
void flash_write_enable(void);
|
||||
|
||||
/**
|
||||
* Main flash API entry point.
|
||||
*
|
||||
* NOTE: This *must* be the first function in this file to ensure that it is placed
|
||||
* first in the resulting binary. This is required to ensure that address
|
||||
* matches the address (FLASH_OFFSET) for flash_entry in wrapper.c.
|
||||
* NOTE: __reentrant so that parameters and temperary vairables are placed on the
|
||||
* stack, ensuring the main application __data variables are not stomped on.
|
||||
* NOTE: __critical to ensure interrupts are disabled. This does mean that interrupt
|
||||
* such as the timer will be block until flash acccess is complete
|
||||
*/
|
||||
void flash_entry(uint32_t addr, uint8_t * data, uint32_t length, uint8_t command) __reentrant __critical {
|
||||
// Only allow access from 64KB to 128KB.
|
||||
if ((addr < 0x10000)
|
||||
|| (length > 0x10000)
|
||||
|| ((addr + length) > 0x20000))
|
||||
return;
|
||||
|
||||
if (command == FLASH_COMMAND_READ) {
|
||||
while (length) {
|
||||
// Fast read.
|
||||
ECINDAR3 = SPI_DEVICE;
|
||||
ECINDAR2 = addr >> 16;
|
||||
ECINDAR1 = addr >> 8;
|
||||
ECINDAR0 = addr;
|
||||
|
||||
*data = ECINDDR;
|
||||
|
||||
addr++;
|
||||
data++;
|
||||
length--;
|
||||
}
|
||||
} else if (command == FLASH_COMMAND_WRITE) {
|
||||
flash_enter_follow_mode();
|
||||
|
||||
while (length) {
|
||||
// Note, this is the slow way to do it, but it's simple and all bytes are written properly.
|
||||
flash_write_enable();
|
||||
|
||||
// Select the device
|
||||
ECINDAR1 = SPI_CHIP_SELECT;
|
||||
|
||||
// Send write command
|
||||
ECINDDR = SPI_WRITE_COMMAND;
|
||||
ECINDDR = addr >> 16;
|
||||
ECINDDR = addr >> 8;
|
||||
ECINDDR = addr;
|
||||
|
||||
ECINDDR = *data;
|
||||
|
||||
addr++;
|
||||
data++;
|
||||
length--;
|
||||
|
||||
// Deselect
|
||||
ECINDAR1 = SPI_CHIP_DESELECT;
|
||||
ECINDDR = 0x00;
|
||||
|
||||
|
||||
// Wait WIP to be cleared
|
||||
flash_wait();
|
||||
}
|
||||
|
||||
flash_exit_follow_mode();
|
||||
} else if (command == FLASH_COMMAND_ERASE_1K) {
|
||||
flash_enter_follow_mode();
|
||||
|
||||
flash_write_enable();
|
||||
|
||||
// Select the device
|
||||
ECINDAR1 = SPI_CHIP_SELECT;
|
||||
|
||||
// Send erase command
|
||||
ECINDDR = SPI_ERASE_SECTOR_COMMAND;
|
||||
ECINDDR = addr >> 16;
|
||||
ECINDDR = addr >> 8;
|
||||
ECINDDR = addr;
|
||||
|
||||
// Deselect
|
||||
ECINDAR1 = SPI_CHIP_DESELECT;
|
||||
ECINDDR = 0x00;
|
||||
|
||||
// Wait WIP to be cleared
|
||||
flash_wait();
|
||||
|
||||
flash_exit_follow_mode();
|
||||
}
|
||||
}
|
||||
|
||||
void flash_enter_follow_mode(void) {
|
||||
// Enter follow mode.
|
||||
ECINDAR3 = SPI_FOLLOW_MODE | SPI_DEVICE;
|
||||
ECINDAR2 = 0xFF;
|
||||
ECINDAR1 = SPI_CHIP_DESELECT;
|
||||
ECINDAR0 = 0x00;
|
||||
ECINDDR = 0x00;
|
||||
}
|
||||
|
||||
void flash_exit_follow_mode(void) {
|
||||
// Exit follow mode
|
||||
ECINDAR3 = SPI_DEVICE;
|
||||
ECINDAR2 = 0;
|
||||
ECINDAR1 = 0;
|
||||
ECINDAR0 = 0;
|
||||
}
|
||||
|
||||
void flash_wait(void) {
|
||||
uint8_t status;
|
||||
|
||||
do {
|
||||
// Select the device
|
||||
ECINDAR1 = SPI_CHIP_SELECT;
|
||||
|
||||
// Send command
|
||||
ECINDDR = SPI_READ_STATUS_COMMAND;
|
||||
|
||||
// read status
|
||||
status = ECINDDR;
|
||||
|
||||
// Deselect
|
||||
ECINDAR1 = SPI_CHIP_DESELECT;
|
||||
ECINDDR = 0x00;
|
||||
} while(status & SPI_STATUS_WIP);
|
||||
}
|
||||
|
||||
void flash_write_enable(void) {
|
||||
// Select the device
|
||||
ECINDAR1 = SPI_CHIP_SELECT;
|
||||
|
||||
// Send device id command
|
||||
ECINDDR = SPI_WRITE_ENABLE_COMMAND;
|
||||
|
||||
// Deselect
|
||||
ECINDAR1 = SPI_CHIP_DESELECT;
|
||||
ECINDDR = 0x00;
|
||||
}
|
78
src/board/system76/common/flash/wrapper.c
Normal file
78
src/board/system76/common/flash/wrapper.c
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Evan Lojewski
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <board/flash.h>
|
||||
#include <ec/scratch.h>
|
||||
#include "include/flash/entry.h"
|
||||
|
||||
// Include flash ROM
|
||||
uint8_t __code __at(FLASH_OFFSET) flash_rom[] = {
|
||||
#include <flash.h>
|
||||
};
|
||||
|
||||
static void flash_api(uint32_t addr, uint8_t * data, uint32_t length, uint8_t command) {
|
||||
// Use DMA mapping to copy flash ROM to scratch ROM
|
||||
SCARH = 0x80;
|
||||
SCARL = (uint8_t)(FLASH_OFFSET);
|
||||
SCARM = (uint8_t)(FLASH_OFFSET >> 8);
|
||||
SCARH = 0;
|
||||
|
||||
// Jump to flash ROM
|
||||
flash_entry(addr, data, length, command);
|
||||
|
||||
// Disable scratch ROM
|
||||
SCARH = 0x07;
|
||||
}
|
||||
|
||||
void flash_read(uint32_t addr, __xdata uint8_t * data, uint32_t length) {
|
||||
flash_api(addr, data, length, FLASH_COMMAND_READ);
|
||||
}
|
||||
|
||||
uint32_t flash_read_u32(uint32_t addr) {
|
||||
uint32_t data;
|
||||
|
||||
flash_api(addr, (uint8_t *)&data, sizeof(data), FLASH_COMMAND_READ);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
uint16_t flash_read_u16(uint32_t addr) {
|
||||
uint16_t data;
|
||||
|
||||
flash_api(addr, (uint8_t *)&data, sizeof(data), FLASH_COMMAND_READ);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
uint8_t flash_read_u8(uint32_t addr) {
|
||||
uint8_t data;
|
||||
|
||||
flash_api(addr, &data, sizeof(data), FLASH_COMMAND_READ);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void flash_write(uint32_t addr, __xdata uint8_t *data, uint32_t length) {
|
||||
flash_api(addr, data, length, FLASH_COMMAND_WRITE);
|
||||
}
|
||||
|
||||
void flash_write_u32(uint32_t addr, uint32_t data) {
|
||||
flash_api(addr, (uint8_t *)&data, sizeof(data), FLASH_COMMAND_WRITE);
|
||||
}
|
||||
|
||||
void flash_write_u16(uint32_t addr, uint16_t data) {
|
||||
flash_api(addr, (uint8_t *)&data, sizeof(data), FLASH_COMMAND_WRITE);
|
||||
}
|
||||
|
||||
void flash_write_u8(uint32_t addr, uint8_t data) {
|
||||
flash_api(addr, &data, sizeof(data), FLASH_COMMAND_WRITE);
|
||||
}
|
||||
|
||||
void flash_erase(uint32_t addr) {
|
||||
flash_api(addr, NULL, 0, FLASH_COMMAND_ERASE_1K);
|
||||
}
|
96
src/board/system76/common/include/board/flash.h
Normal file
96
src/board/system76/common/include/board/flash.h
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Evan Lojewski
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef _BOARD_FLASH_H
|
||||
#define _BOARD_FLASH_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** \cond INTERNAL
|
||||
* Internal defines
|
||||
*/
|
||||
#define FLASH_COMMAND_READ (0x0)
|
||||
#define FLASH_COMMAND_WRITE (0x1)
|
||||
#define FLASH_COMMAND_ERASE_1K (0x2)
|
||||
/** \endcond */
|
||||
|
||||
/**
|
||||
* Read data from flash to the specified buffer.
|
||||
*
|
||||
* \param[in] addr The flash address to read.
|
||||
* \param[out] data The memory area to copy to.
|
||||
* \param[in] length The number of bytes to copy.
|
||||
*/
|
||||
void flash_read(uint32_t addr, __xdata uint8_t * data, uint32_t length);
|
||||
|
||||
/**
|
||||
* Read a single byte from flash.
|
||||
*
|
||||
* \param[in] addr The flash address to read.
|
||||
*
|
||||
* \return The value read from flash.
|
||||
*/
|
||||
uint8_t flash_read_u8(uint32_t addr);
|
||||
|
||||
/**
|
||||
* Read two bytes from flash.
|
||||
*
|
||||
* \param[in] addr The flash address to read.
|
||||
*
|
||||
* \return The value read from flash.
|
||||
*/
|
||||
uint16_t flash_read_u16(uint32_t addr);
|
||||
|
||||
/**
|
||||
* Read four bytes from flash.
|
||||
*
|
||||
* \param[in] addr The flash address to read.
|
||||
*
|
||||
* \return The value read from flash.
|
||||
*/
|
||||
uint32_t flash_read_u32(uint32_t addr);
|
||||
|
||||
/**
|
||||
* Write data to flash from the specified buffer.
|
||||
*
|
||||
* \param[in] addr The flash address to read.
|
||||
* \param[in] data The memory area to copy from.
|
||||
* \param[in] length The number of bytes to copy.
|
||||
*/
|
||||
void flash_write(uint32_t addr, __xdata uint8_t * data, uint32_t length);
|
||||
|
||||
/**
|
||||
* Write a single byte to flash.
|
||||
*
|
||||
* \param[in] addr The flash address to read.
|
||||
* \param[in] data The value to write to flash.
|
||||
*/
|
||||
void flash_write_u8(uint32_t addr, uint8_t data);
|
||||
|
||||
/**
|
||||
* Write two bytes to flash.
|
||||
*
|
||||
* \param[in] addr The flash address to read.
|
||||
* \param[in] data The value to write to flash.
|
||||
*/
|
||||
void flash_write_u16(uint32_t addr, uint16_t data);
|
||||
|
||||
/**
|
||||
* Write two bytes to flash.
|
||||
*
|
||||
* \param[in] addr The flash address to read.
|
||||
* \param[in] data The value to write to flash.
|
||||
*/
|
||||
void flash_write_u32(uint32_t addr, uint32_t data);
|
||||
|
||||
/**
|
||||
* Erase a 1K block of flash.
|
||||
*
|
||||
* \param[in] addr The flash address contained in the 1K block.
|
||||
*/
|
||||
void flash_erase(uint32_t addr);
|
||||
|
||||
#endif // _BOARD_FLASH_H
|
Loading…
x
Reference in New Issue
Block a user