2023-09-08 11:35:18 +02:00
|
|
|
/* AXI External Memory Controller (EMC)
|
2020-07-08 15:20:05 +02:00
|
|
|
*
|
2023-01-07 17:20:15 +01:00
|
|
|
* Author: Steffen Vogel <post@steffenvogel.de>
|
2023-01-07 17:32:48 +01:00
|
|
|
* SPDX-FileCopyrightText: 2017 Steffen Vogel <post@steffenvogel.de>
|
2023-01-07 17:20:15 +01:00
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
2023-09-08 11:35:18 +02:00
|
|
|
*/
|
2020-07-08 15:20:05 +02:00
|
|
|
|
2020-07-08 17:16:43 +02:00
|
|
|
#include <iostream>
|
2020-07-08 15:20:05 +02:00
|
|
|
|
|
|
|
#include <villas/fpga/ips/emc.hpp>
|
2024-02-29 19:34:27 +01:00
|
|
|
#include <villas/plugin.hpp>
|
2020-07-08 15:20:05 +02:00
|
|
|
|
|
|
|
using namespace villas::fpga::ip;
|
|
|
|
|
2024-02-29 19:34:27 +01:00
|
|
|
bool EMC::init() {
|
|
|
|
int ret;
|
|
|
|
const uintptr_t base = getBaseAddr(registerMemory);
|
2020-07-08 15:20:05 +02:00
|
|
|
|
2024-02-29 19:34:27 +01:00
|
|
|
const int busWidth = 2;
|
2022-08-30 12:01:47 -04:00
|
|
|
|
|
|
|
#if defined(XPAR_XFL_DEVICE_FAMILY_INTEL) && XFL_TO_ASYNCMODE
|
2024-02-29 19:34:27 +01:00
|
|
|
// Set Flash to Async mode.
|
|
|
|
if (busWidth == 1) {
|
|
|
|
WRITE_FLASH_8(base + ASYNC_ADDR, 0x60);
|
|
|
|
WRITE_FLASH_8(base + ASYNC_ADDR, 0x03);
|
|
|
|
} else if (busWidth == 2) {
|
|
|
|
WRITE_FLASH_16(base + ASYNC_ADDR, INTEL_CMD_CONFIG_REG_SETUP);
|
|
|
|
WRITE_FLASH_16(base + ASYNC_ADDR, INTEL_CMD_CONFIG_REG_CONFIRM);
|
|
|
|
}
|
2020-07-08 17:16:43 +02:00
|
|
|
#endif
|
|
|
|
|
2024-02-29 19:34:27 +01:00
|
|
|
ret = XFlash_Initialize(&xflash, base, busWidth, 0);
|
|
|
|
if (ret != XST_SUCCESS)
|
|
|
|
return false;
|
2020-07-08 17:16:43 +02:00
|
|
|
|
2024-02-29 19:34:27 +01:00
|
|
|
return XFlash_IsReady(&xflash);
|
2020-07-08 17:16:43 +02:00
|
|
|
}
|
|
|
|
|
2024-02-29 19:34:27 +01:00
|
|
|
bool EMC::read(uint32_t offset, uint32_t length, uint8_t *data) {
|
|
|
|
int ret;
|
2020-07-08 17:16:43 +02:00
|
|
|
|
2024-02-29 19:34:27 +01:00
|
|
|
/* Reset the Flash Device. This clears the ret registers and puts
|
2024-02-29 21:47:13 +01:00
|
|
|
* the device in Read mode.
|
|
|
|
*/
|
2024-02-29 19:34:27 +01:00
|
|
|
ret = XFlash_Reset(&xflash);
|
|
|
|
if (ret != XST_SUCCESS)
|
|
|
|
return false;
|
2020-07-08 17:16:43 +02:00
|
|
|
|
2024-02-29 19:34:27 +01:00
|
|
|
// Perform the read operation.
|
|
|
|
ret = XFlash_Read(&xflash, offset, length, data);
|
|
|
|
if (ret != XST_SUCCESS)
|
|
|
|
return false;
|
2020-07-08 17:16:43 +02:00
|
|
|
|
2024-02-29 19:34:27 +01:00
|
|
|
return false;
|
2020-07-08 15:20:05 +02:00
|
|
|
}
|
|
|
|
|
2020-07-08 17:16:43 +02:00
|
|
|
// objcopy -I ihex -O binary somefile.mcs somefile.bin
|
|
|
|
|
2024-02-29 19:34:27 +01:00
|
|
|
bool EMC::flash(uint32_t offset, const std::string &filename) {
|
|
|
|
bool result;
|
|
|
|
uint32_t length;
|
|
|
|
uint8_t *buffer;
|
2020-07-08 17:16:43 +02:00
|
|
|
|
2024-02-29 19:34:27 +01:00
|
|
|
std::ifstream is(filename, std::ios::binary);
|
2022-08-30 12:01:47 -04:00
|
|
|
|
2024-02-29 19:34:27 +01:00
|
|
|
// Get length of file:
|
|
|
|
is.seekg(0, std::ios::end);
|
|
|
|
length = is.tellg();
|
2022-08-30 12:01:47 -04:00
|
|
|
|
2024-02-29 19:34:27 +01:00
|
|
|
is.seekg(0, std::ios::beg);
|
|
|
|
// Allocate memory:
|
2022-08-30 12:01:47 -04:00
|
|
|
|
2024-02-29 19:34:27 +01:00
|
|
|
buffer = new uint8_t[length];
|
|
|
|
is.read(reinterpret_cast<char *>(buffer), length);
|
|
|
|
is.close();
|
2020-07-08 17:16:43 +02:00
|
|
|
|
2024-02-29 19:34:27 +01:00
|
|
|
result = flash(offset, length, buffer);
|
2020-07-08 17:16:43 +02:00
|
|
|
|
2024-02-29 19:34:27 +01:00
|
|
|
delete[] buffer;
|
2020-07-08 17:16:43 +02:00
|
|
|
|
2024-02-29 19:34:27 +01:00
|
|
|
return result;
|
2020-07-08 17:16:43 +02:00
|
|
|
}
|
|
|
|
|
2022-08-30 12:01:47 -04:00
|
|
|
// Based on xilflash_readwrite_example.c
|
2024-02-29 19:34:27 +01:00
|
|
|
bool EMC::flash(uint32_t offset, uint32_t length, uint8_t *data) {
|
|
|
|
int ret = XST_FAILURE;
|
|
|
|
uint32_t start = offset;
|
2020-07-08 17:16:43 +02:00
|
|
|
|
2024-02-29 19:34:27 +01:00
|
|
|
/* Reset the Flash Device. This clears the ret registers and puts
|
2024-02-29 21:47:13 +01:00
|
|
|
* the device in Read mode. */
|
2024-02-29 19:34:27 +01:00
|
|
|
ret = XFlash_Reset(&xflash);
|
|
|
|
if (ret != XST_SUCCESS) {
|
|
|
|
return false;
|
|
|
|
}
|
2020-07-08 17:16:43 +02:00
|
|
|
|
2024-02-29 19:34:27 +01:00
|
|
|
/* Perform an unlock operation before the erase operation for the Intel
|
2024-02-29 21:47:13 +01:00
|
|
|
* Flash. The erase operation will result in an error if the block is
|
|
|
|
* locked. */
|
2024-02-29 19:34:27 +01:00
|
|
|
if ((xflash.CommandSet == XFL_CMDSET_INTEL_STANDARD) ||
|
|
|
|
(xflash.CommandSet == XFL_CMDSET_INTEL_EXTENDED) ||
|
|
|
|
(xflash.CommandSet == XFL_CMDSET_INTEL_G18)) {
|
|
|
|
ret = XFlash_Unlock(&xflash, offset, 0);
|
|
|
|
if (ret != XST_SUCCESS) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Perform the Erase operation.
|
|
|
|
ret = XFlash_Erase(&xflash, start, length);
|
|
|
|
if (ret != XST_SUCCESS) {
|
|
|
|
;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Perform the Write operation.
|
|
|
|
ret = XFlash_Write(&xflash, start, length, data);
|
|
|
|
if (ret != XST_SUCCESS) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Perform the read operation.
|
|
|
|
uint8_t *verify_data = new uint8_t[length];
|
|
|
|
ret = XFlash_Read(&xflash, start, length, verify_data);
|
|
|
|
if (ret != XST_SUCCESS) {
|
|
|
|
delete[] verify_data;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compare the data read against the data Written.
|
|
|
|
for (unsigned i = 0; i < length; i++) {
|
|
|
|
if (verify_data[i] != data[i]) {
|
|
|
|
delete[] verify_data;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delete[] verify_data;
|
|
|
|
|
|
|
|
return true;
|
2020-07-08 17:16:43 +02:00
|
|
|
}
|
2022-12-02 18:46:00 +01:00
|
|
|
|
|
|
|
static char n[] = "emc";
|
|
|
|
static char d[] = "Xilinx's AXI External Memory Controller";
|
|
|
|
static char v[] = "xilinx.com:ip:axi_emc:";
|
|
|
|
static CorePlugin<EMC, n, d, v> f;
|