mirror of
https://github.com/fpganinja/taxi.git
synced 2026-02-27 21:45:09 -08:00
pyrite: Initial commit of pyrite flashing utility
Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
1
src/pyrite/lib/taxi
Symbolic link
1
src/pyrite/lib/taxi
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../
|
||||
40
src/pyrite/utils/Makefile
Normal file
40
src/pyrite/utils/Makefile
Normal file
@@ -0,0 +1,40 @@
|
||||
# SPDX-License-Identifier: GPL
|
||||
# Copyright (c) 2026 FPGA Ninja
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
BINDIR = $(DESTDIR)$(PREFIX)/bin
|
||||
|
||||
CC ?= gcc
|
||||
CFLAGS ?= -O3
|
||||
|
||||
CFLAGS += -Wall
|
||||
CPPFLAGS +=
|
||||
LDFLAGS +=
|
||||
LDLIBS +=
|
||||
|
||||
BIN = pyrite
|
||||
|
||||
GENDEPFLAGS = -MD -MP -MF .$(@F).d
|
||||
|
||||
ALL_CFLAGS = $(CFLAGS) $(CPPFLAGS) $(GENDEPFLAGS)
|
||||
|
||||
all: $(BIN)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(ALL_CFLAGS) -c -o $@ $<
|
||||
|
||||
pyrite: pyrite.o flash.o flash_spi.o flash_bpi.o bitfile.o reg_block.o reg_if.o fpga_id.o
|
||||
$(CC) $(ALL_CFLAGS) $(LDFLAGS) $^ -o $@ $(LDLIBS)
|
||||
|
||||
install:
|
||||
install -d $(BINDIR)
|
||||
install -m 0755 $(BIN) $(BINDIR)
|
||||
|
||||
clean:
|
||||
rm -f $(BIN)
|
||||
rm -f *.o
|
||||
rm -f .*.d
|
||||
|
||||
-include $(wildcard .*.d)
|
||||
|
||||
.PHONY: all install clean
|
||||
149
src/pyrite/utils/bitfile.c
Normal file
149
src/pyrite/utils/bitfile.c
Normal file
@@ -0,0 +1,149 @@
|
||||
// SPDX-License-Identifier: GPL
|
||||
/*
|
||||
|
||||
Copyright (c) 2026 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "bitfile.h"
|
||||
|
||||
struct bitfile *bitfile_create_from_file(const char *bit_file_name)
|
||||
{
|
||||
struct bitfile *bf;
|
||||
FILE *fp;
|
||||
char *buffer;
|
||||
char *data;
|
||||
size_t len;
|
||||
|
||||
fp = fopen(bit_file_name, "rb");
|
||||
|
||||
if (!fp) {
|
||||
fprintf(stderr, "Failed to open file\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
len = ftell(fp);
|
||||
rewind(fp);
|
||||
|
||||
buffer = calloc(len + sizeof(struct bitfile), 1);
|
||||
|
||||
if (!buffer) {
|
||||
fprintf(stderr, "Failed to allocate memory\n");
|
||||
goto fail_file;
|
||||
}
|
||||
|
||||
bf = (struct bitfile *)buffer;
|
||||
data = buffer + sizeof(struct bitfile);
|
||||
|
||||
if (fread(data, 1, len, fp) < len) {
|
||||
fprintf(stderr, "Error reading file\n");
|
||||
goto fail_buffer;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if (bitfile_parse(bf, data, len)) {
|
||||
fprintf(stderr, "Failed to parse bitfile\n");
|
||||
goto fail_buffer;
|
||||
}
|
||||
|
||||
return bf;
|
||||
|
||||
fail_buffer:
|
||||
free(buffer);
|
||||
fail_file:
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct bitfile *bitfile_create_from_buffer(char *buffer, size_t len)
|
||||
{
|
||||
struct bitfile *bf;
|
||||
|
||||
bf = calloc(1, sizeof(struct bitfile));
|
||||
|
||||
if (!bf) {
|
||||
fprintf(stderr, "Failed to allocate memory\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bitfile_parse(bf, buffer, len)) {
|
||||
fprintf(stderr, "Failed to parse bitfile\n");
|
||||
free(bf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return bf;
|
||||
}
|
||||
|
||||
int bitfile_parse(struct bitfile *bf, char *buffer, size_t len)
|
||||
{
|
||||
char *ptr;
|
||||
size_t l;
|
||||
|
||||
ptr = buffer;
|
||||
|
||||
bf->header = ptr;
|
||||
|
||||
// drop unknown field
|
||||
l = be16toh(*((uint16_t *)ptr));
|
||||
ptr += 2+l;
|
||||
|
||||
// drop unknown field
|
||||
ptr += 2;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int field_type = *ptr;
|
||||
ptr += 1;
|
||||
|
||||
if (field_type == 'e') {
|
||||
l = be32toh(*((uint32_t *)ptr));
|
||||
bf->data_len = l;
|
||||
bf->data = ptr+4;
|
||||
return 0;
|
||||
} else {
|
||||
l = be16toh(*((uint16_t *)ptr));
|
||||
ptr += 2;
|
||||
}
|
||||
|
||||
switch (field_type)
|
||||
{
|
||||
case 'a':
|
||||
bf->name = ptr;
|
||||
break;
|
||||
case 'b':
|
||||
bf->part = ptr;
|
||||
break;
|
||||
case 'c':
|
||||
bf->date = ptr;
|
||||
break;
|
||||
case 'd':
|
||||
bf->time = ptr;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown field type 0x%02x\n", field_type);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ptr += l;
|
||||
}
|
||||
|
||||
fail:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void bitfile_close(struct bitfile *bf)
|
||||
{
|
||||
if (bf) {
|
||||
free(bf);
|
||||
}
|
||||
}
|
||||
35
src/pyrite/utils/bitfile.h
Normal file
35
src/pyrite/utils/bitfile.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/* SPDX-License-Identifier: GPL */
|
||||
/*
|
||||
|
||||
Copyright (c) 2026 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BITFILE_H
|
||||
#define BITFILE_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
struct bitfile {
|
||||
char *header;
|
||||
char *name;
|
||||
char *part;
|
||||
char *date;
|
||||
char *time;
|
||||
|
||||
size_t data_len;
|
||||
char *data;
|
||||
};
|
||||
|
||||
struct bitfile *bitfile_create_from_file(const char *bit_file_name);
|
||||
|
||||
struct bitfile *bitfile_create_from_buffer(char *buffer, size_t len);
|
||||
|
||||
int bitfile_parse(struct bitfile *bf, char *buffer, size_t len);
|
||||
|
||||
void bitfile_close(struct bitfile *bf);
|
||||
|
||||
#endif // BITFILE_H
|
||||
112
src/pyrite/utils/flash.c
Normal file
112
src/pyrite/utils/flash.c
Normal file
@@ -0,0 +1,112 @@
|
||||
// SPDX-License-Identifier: GPL
|
||||
/*
|
||||
|
||||
Copyright (c) 2026 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
#include "flash.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
extern const struct flash_driver spi_flash_driver;
|
||||
extern const struct flash_driver bpi_flash_driver;
|
||||
|
||||
struct flash_device *flash_open_spi(int data_width, const struct reg_if *reg, size_t ctrl_reg_offset)
|
||||
{
|
||||
struct flash_device *fdev;
|
||||
|
||||
if (!reg)
|
||||
return NULL;
|
||||
|
||||
fdev = calloc(1, sizeof(struct flash_device));
|
||||
|
||||
if (!fdev)
|
||||
return NULL;
|
||||
|
||||
fdev->driver = &spi_flash_driver;
|
||||
|
||||
fdev->data_width = data_width;
|
||||
|
||||
fdev->reg = reg;
|
||||
fdev->ctrl_reg_offset = ctrl_reg_offset;
|
||||
|
||||
if (fdev->driver->init(fdev)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
return fdev;
|
||||
|
||||
err:
|
||||
flash_release(fdev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct flash_device *flash_open_bpi(int data_width, const struct reg_if *reg, size_t ctrl_reg_offset, size_t addr_reg_offset, size_t data_reg_offset)
|
||||
{
|
||||
struct flash_device *fdev;
|
||||
|
||||
if (!reg)
|
||||
return NULL;
|
||||
|
||||
fdev = calloc(1, sizeof(struct flash_device));
|
||||
|
||||
if (!fdev)
|
||||
return NULL;
|
||||
|
||||
fdev->driver = &bpi_flash_driver;
|
||||
|
||||
fdev->data_width = data_width;
|
||||
|
||||
fdev->reg = reg;
|
||||
fdev->ctrl_reg_offset = ctrl_reg_offset;
|
||||
fdev->addr_reg_offset = addr_reg_offset;
|
||||
fdev->data_reg_offset = data_reg_offset;
|
||||
|
||||
if (fdev->driver->init(fdev)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
return fdev;
|
||||
|
||||
err:
|
||||
flash_release(fdev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void flash_release(struct flash_device *fdev)
|
||||
{
|
||||
if (!fdev)
|
||||
return;
|
||||
|
||||
fdev->driver->release(fdev);
|
||||
|
||||
free(fdev);
|
||||
}
|
||||
|
||||
int flash_read(struct flash_device *fdev, size_t addr, size_t len, void *dest)
|
||||
{
|
||||
if (!fdev)
|
||||
return -1;
|
||||
|
||||
return fdev->driver->read(fdev, addr, len, dest);
|
||||
}
|
||||
|
||||
int flash_write(struct flash_device *fdev, size_t addr, size_t len, const void *src)
|
||||
{
|
||||
if (!fdev)
|
||||
return -1;
|
||||
|
||||
return fdev->driver->write(fdev, addr, len, src);
|
||||
}
|
||||
|
||||
int flash_erase(struct flash_device *fdev, size_t addr, size_t len)
|
||||
{
|
||||
if (!fdev)
|
||||
return -1;
|
||||
|
||||
return fdev->driver->erase(fdev, addr, len);
|
||||
}
|
||||
77
src/pyrite/utils/flash.h
Normal file
77
src/pyrite/utils/flash.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/* SPDX-License-Identifier: GPL */
|
||||
/*
|
||||
|
||||
Copyright (c) 2026 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
#ifndef FLASH_H
|
||||
#define FLASH_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "reg_if.h"
|
||||
|
||||
#define FLASH_ERASE_REGIONS 2
|
||||
|
||||
struct flash_driver;
|
||||
struct flash_ops;
|
||||
|
||||
struct flash_erase_region_info {
|
||||
size_t block_count;
|
||||
size_t block_size;
|
||||
size_t region_start;
|
||||
size_t region_end;
|
||||
};
|
||||
|
||||
struct flash_device {
|
||||
const struct flash_driver *driver;
|
||||
const struct flash_ops *ops;
|
||||
|
||||
const struct reg_if *reg;
|
||||
|
||||
size_t ctrl_reg_offset;
|
||||
size_t addr_reg_offset;
|
||||
size_t data_reg_offset;
|
||||
|
||||
size_t size;
|
||||
int data_width;
|
||||
|
||||
size_t write_buffer_size;
|
||||
size_t erase_block_size;
|
||||
|
||||
int protocol;
|
||||
int bulk_protocol;
|
||||
|
||||
int read_dummy_cycles;
|
||||
|
||||
int erase_region_count;
|
||||
struct flash_erase_region_info erase_region[FLASH_ERASE_REGIONS];
|
||||
};
|
||||
|
||||
struct flash_ops {
|
||||
void (*init)(struct flash_device *fdev);
|
||||
int (*sector_erase)(struct flash_device *fdev, size_t addr);
|
||||
int (*buffered_program)(struct flash_device *fdev, size_t addr, size_t len, const void *src);
|
||||
};
|
||||
|
||||
struct flash_driver {
|
||||
int (*init)(struct flash_device *fdev);
|
||||
void (*release)(struct flash_device *fdev);
|
||||
int (*read)(struct flash_device *fdev, size_t addr, size_t len, void *dest);
|
||||
int (*write)(struct flash_device *fdev, size_t addr, size_t len, const void *src);
|
||||
int (*erase)(struct flash_device *fdev, size_t addr, size_t len);
|
||||
};
|
||||
|
||||
struct flash_device *flash_open_spi(int data_width, const struct reg_if *reg, size_t ctrl_reg_offset);
|
||||
struct flash_device *flash_open_bpi(int data_width, const struct reg_if *reg, size_t ctrl_reg_offset, size_t addr_reg_offset, size_t data_reg_offset);
|
||||
void flash_release(struct flash_device *fdev);
|
||||
int flash_read(struct flash_device *fdev, size_t addr, size_t len, void *dest);
|
||||
int flash_write(struct flash_device *fdev, size_t addr, size_t len, const void *src);
|
||||
int flash_erase(struct flash_device *fdev, size_t addr, size_t len);
|
||||
|
||||
#endif /* FLASH_H */
|
||||
612
src/pyrite/utils/flash_bpi.c
Normal file
612
src/pyrite/utils/flash_bpi.c
Normal file
@@ -0,0 +1,612 @@
|
||||
// SPDX-License-Identifier: GPL
|
||||
/*
|
||||
|
||||
Copyright (c) 2026 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
#include "flash.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define reg_read32(reg) (*((volatile uint32_t *)(reg)))
|
||||
#define reg_write32(reg, val) (*((volatile uint32_t *)(reg))) = (val)
|
||||
|
||||
#define CFI_QUERY_ADDR 0x55
|
||||
#define CFI_QUERY_DATA 0x98
|
||||
#define CFI_READ_ARRAY 0xFF
|
||||
#define CFI_READ_ARRAY_ALT 0xF0
|
||||
#define CFI_ID_0 0x10
|
||||
#define CFI_ID_1 0x11
|
||||
#define CFI_ID_2 0x12
|
||||
#define CFI_PRI_CMD_SET_0 0x13
|
||||
#define CFI_PRI_CMD_SET_1 0x14
|
||||
#define CFI_DEVICE_SIZE 0x27
|
||||
#define CFI_WRITE_BUFFER_SIZE_0 0x2A
|
||||
#define CFI_WRITE_BUFFER_SIZE_1 0x2B
|
||||
#define CFI_ERASE_REGION_COUNT 0x2C
|
||||
#define CFI_ERASE_REGION_1_INFO_0 0x2D
|
||||
#define CFI_ERASE_REGION_1_INFO_1 0x2E
|
||||
#define CFI_ERASE_REGION_1_INFO_2 0x2F
|
||||
#define CFI_ERASE_REGION_1_INFO_3 0x30
|
||||
#define CFI_ERASE_REGION_2_INFO_0 0x31
|
||||
#define CFI_ERASE_REGION_2_INFO_1 0x32
|
||||
#define CFI_ERASE_REGION_2_INFO_2 0x33
|
||||
#define CFI_ERASE_REGION_2_INFO_3 0x34
|
||||
|
||||
#define BPI_INTEL_READ_ARRAY 0xFF
|
||||
#define BPI_INTEL_READ_STATUS_REG 0x70
|
||||
#define BPI_INTEL_READ_ID 0x90
|
||||
#define BPI_INTEL_CLEAR_STATUS_REG 0x50
|
||||
#define BPI_INTEL_READ_CONFIG_REG_SETUP 0x60
|
||||
#define BPI_INTEL_SET_READ_CONFIG_REG 0x03
|
||||
#define BPI_INTEL_BLOCK_LOCK_SETUP 0x60
|
||||
#define BPI_INTEL_BLOCK_LOCK 0x01
|
||||
#define BPI_INTEL_BLOCK_UNLOCK 0xD0
|
||||
#define BPI_INTEL_BLOCK_ERASE_SETUP 0x20
|
||||
#define BPI_INTEL_BLOCK_ERASE_CONFIRM 0xD0
|
||||
#define BPI_INTEL_BUFFERED_PROGRAM_SETUP 0xE8
|
||||
#define BPI_INTEL_BUFFERED_PROGRAM_CONFIRM 0xD0
|
||||
|
||||
#define BPI_AMD_UNLOCK_ADDR_1 0x555
|
||||
#define BPI_AMD_UNLOCK_DATA_1 0xAA
|
||||
#define BPI_AMD_UNLOCK_ADDR_2 0x2AA
|
||||
#define BPI_AMD_UNLOCK_DATA_2 0x55
|
||||
#define BPI_AMD_UNLOCK_BYPASS_ENTER_ADDR 0x555
|
||||
#define BPI_AMD_UNLOCK_BYPASS_ENTER_DATA 0x20
|
||||
#define BPI_AMD_UNLOCK_BYPASS_RESET_1 0x90
|
||||
#define BPI_AMD_UNLOCK_BYPASS_RESET_2 0x00
|
||||
#define BPI_AMD_BLOCK_ERASE_SETUP 0x80
|
||||
#define BPI_AMD_BLOCK_ERASE_CONFIRM 0x30
|
||||
#define BPI_AMD_BUFFERED_PROGRAM_SETUP 0x25
|
||||
#define BPI_AMD_BUFFERED_PROGRAM_CONFIRM 0x29
|
||||
#define BPI_AMD_READ_ARRAY 0xF0
|
||||
|
||||
#define BPI_MICRON_READ_ARRAY 0xFF
|
||||
#define BPI_MICRON_READ_STATUS_REG 0x70
|
||||
#define BPI_MICRON_READ_ID 0x90
|
||||
#define BPI_MICRON_CLEAR_STATUS_REG 0x50
|
||||
#define BPI_MICRON_READ_CONFIG_REG_SETUP 0x60
|
||||
#define BPI_MICRON_SET_READ_CONFIG_REG 0x03
|
||||
#define BPI_MICRON_BLOCK_LOCK_SETUP 0x60
|
||||
#define BPI_MICRON_BLOCK_LOCK 0x01
|
||||
#define BPI_MICRON_BLOCK_UNLOCK 0xD0
|
||||
#define BPI_MICRON_BLOCK_ERASE_SETUP 0x20
|
||||
#define BPI_MICRON_BLOCK_ERASE_CONFIRM 0xD0
|
||||
#define BPI_MICRON_BUFFERED_PROGRAM_SETUP 0xE9
|
||||
#define BPI_MICRON_BUFFERED_PROGRAM_CONFIRM 0xD0
|
||||
|
||||
#define FLASH_CE_N (1 << 0)
|
||||
#define FLASH_OE_N (1 << 1)
|
||||
#define FLASH_WE_N (1 << 2)
|
||||
#define FLASH_ADV_N (1 << 3)
|
||||
#define FLASH_DQ_OE (1 << 8)
|
||||
#define FLASH_REGION_OE (1 << 16)
|
||||
|
||||
void bpi_flash_set_addr(struct flash_device *fdev, size_t addr)
|
||||
{
|
||||
reg_if_write32(fdev->reg, fdev->addr_reg_offset, addr);
|
||||
}
|
||||
|
||||
uint16_t bpi_flash_read_cur(struct flash_device *fdev)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
reg_if_write32(fdev->reg, fdev->ctrl_reg_offset, FLASH_REGION_OE | FLASH_WE_N);
|
||||
reg_if_read32(fdev->reg, fdev->ctrl_reg_offset, &val); // dummy read
|
||||
reg_if_read32(fdev->reg, fdev->data_reg_offset, &val);
|
||||
reg_if_write32(fdev->reg, fdev->ctrl_reg_offset, FLASH_OE_N | FLASH_WE_N | FLASH_ADV_N);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
uint16_t bpi_flash_read_word(struct flash_device *fdev, size_t addr)
|
||||
{
|
||||
bpi_flash_set_addr(fdev, addr);
|
||||
return bpi_flash_read_cur(fdev);
|
||||
}
|
||||
|
||||
void bpi_flash_write_cur(struct flash_device *fdev, uint16_t data)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
reg_if_write32(fdev->reg, fdev->data_reg_offset, data);
|
||||
reg_if_write32(fdev->reg, fdev->ctrl_reg_offset, FLASH_REGION_OE | FLASH_DQ_OE | FLASH_OE_N);
|
||||
reg_if_read32(fdev->reg, fdev->ctrl_reg_offset, &val); // dummy read
|
||||
reg_if_write32(fdev->reg, fdev->ctrl_reg_offset, FLASH_OE_N | FLASH_WE_N | FLASH_ADV_N);
|
||||
}
|
||||
|
||||
void bpi_flash_write_word(struct flash_device *fdev, size_t addr, uint16_t data)
|
||||
{
|
||||
bpi_flash_set_addr(fdev, addr);
|
||||
bpi_flash_write_cur(fdev, data);
|
||||
}
|
||||
|
||||
void bpi_flash_deselect(struct flash_device *fdev)
|
||||
{
|
||||
bpi_flash_write_word(fdev, 0, CFI_READ_ARRAY);
|
||||
reg_if_write32(fdev->reg, fdev->ctrl_reg_offset, FLASH_CE_N | FLASH_OE_N | FLASH_WE_N | FLASH_ADV_N);
|
||||
}
|
||||
|
||||
// Intel flash ops (0x0001)
|
||||
|
||||
uint16_t bpi_flash_intel_read_status_register(struct flash_device *fdev)
|
||||
{
|
||||
bpi_flash_write_cur(fdev, BPI_INTEL_READ_STATUS_REG);
|
||||
return bpi_flash_read_cur(fdev);
|
||||
}
|
||||
|
||||
void bpi_flash_intel_clear_status_register(struct flash_device *fdev)
|
||||
{
|
||||
bpi_flash_write_cur(fdev, BPI_INTEL_CLEAR_STATUS_REG);
|
||||
}
|
||||
|
||||
void bpi_flash_intel_init(struct flash_device *fdev)
|
||||
{
|
||||
bpi_flash_intel_clear_status_register(fdev);
|
||||
}
|
||||
|
||||
int bpi_flash_intel_sector_erase(struct flash_device *fdev, size_t addr)
|
||||
{
|
||||
bpi_flash_set_addr(fdev, addr);
|
||||
bpi_flash_write_cur(fdev, BPI_INTEL_BLOCK_LOCK_SETUP);
|
||||
bpi_flash_write_cur(fdev, BPI_INTEL_BLOCK_UNLOCK);
|
||||
|
||||
if (bpi_flash_intel_read_status_register(fdev) & 0x30) {
|
||||
fprintf(stderr, "Failed to unlock block\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bpi_flash_write_cur(fdev, BPI_INTEL_BLOCK_ERASE_SETUP);
|
||||
bpi_flash_write_cur(fdev, BPI_INTEL_BLOCK_ERASE_CONFIRM);
|
||||
|
||||
while (!(bpi_flash_intel_read_status_register(fdev) & 0x80)) {};
|
||||
|
||||
if (bpi_flash_intel_read_status_register(fdev) & 0x30){
|
||||
fprintf(stderr, "Failed to erase block\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpi_flash_intel_buffered_program(struct flash_device *fdev, size_t addr, size_t len, const void *src)
|
||||
{
|
||||
const uint8_t *s = (const uint8_t *)src;
|
||||
|
||||
bpi_flash_set_addr(fdev, addr);
|
||||
bpi_flash_write_cur(fdev, BPI_INTEL_BUFFERED_PROGRAM_SETUP);
|
||||
bpi_flash_write_cur(fdev, len-1);
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
bpi_flash_write_word(fdev, addr+i, s[0] | (s[1] << 8));
|
||||
s += 2;
|
||||
}
|
||||
|
||||
bpi_flash_set_addr(fdev, addr);
|
||||
bpi_flash_write_cur(fdev, BPI_INTEL_BUFFERED_PROGRAM_CONFIRM);
|
||||
|
||||
while (!(bpi_flash_intel_read_status_register(fdev) & 0x80)) {};
|
||||
|
||||
if (bpi_flash_intel_read_status_register(fdev) & 0x30) {
|
||||
fprintf(stderr, "Failed to write block\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct flash_ops bpi_flash_intel_ops = {
|
||||
.init = bpi_flash_intel_init,
|
||||
.sector_erase = bpi_flash_intel_sector_erase,
|
||||
.buffered_program = bpi_flash_intel_buffered_program
|
||||
};
|
||||
|
||||
// AMD flash ops (0x0002)
|
||||
|
||||
void bpi_flash_amd_unlock(struct flash_device *fdev)
|
||||
{
|
||||
bpi_flash_write_word(fdev, BPI_AMD_UNLOCK_ADDR_1, BPI_AMD_UNLOCK_DATA_1);
|
||||
bpi_flash_write_word(fdev, BPI_AMD_UNLOCK_ADDR_2, BPI_AMD_UNLOCK_DATA_2);
|
||||
}
|
||||
|
||||
void bpi_flash_amd_write_buffer_abort_reset(struct flash_device *fdev)
|
||||
{
|
||||
bpi_flash_amd_unlock(fdev);
|
||||
bpi_flash_write_word(fdev, BPI_AMD_UNLOCK_ADDR_1, BPI_AMD_READ_ARRAY);
|
||||
}
|
||||
|
||||
void bpi_flash_amd_init(struct flash_device *fdev)
|
||||
{
|
||||
// write-to-buffer-abort reset (just in case)
|
||||
bpi_flash_amd_write_buffer_abort_reset(fdev);
|
||||
}
|
||||
|
||||
int bpi_flash_amd_wait_for_operation(struct flash_device *fdev, uint16_t stop_mask)
|
||||
{
|
||||
uint16_t read_1, read_2, read_3;
|
||||
|
||||
while (1) {
|
||||
read_1 = bpi_flash_read_cur(fdev);
|
||||
read_2 = bpi_flash_read_cur(fdev);
|
||||
read_3 = bpi_flash_read_cur(fdev);
|
||||
|
||||
if ((read_1 ^ read_2) & (read_2 ^ read_3) & 0x40) {
|
||||
if (read_1 & stop_mask) {
|
||||
return read_1;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int bpi_flash_amd_sector_erase(struct flash_device *fdev, size_t addr)
|
||||
{
|
||||
bpi_flash_amd_unlock(fdev);
|
||||
bpi_flash_write_word(fdev, BPI_AMD_UNLOCK_ADDR_1, BPI_AMD_BLOCK_ERASE_SETUP);
|
||||
bpi_flash_amd_unlock(fdev);
|
||||
bpi_flash_write_word(fdev, addr, BPI_AMD_BLOCK_ERASE_CONFIRM);
|
||||
|
||||
while (!(bpi_flash_read_cur(fdev) & 0x08)) {};
|
||||
|
||||
if (bpi_flash_amd_wait_for_operation(fdev, 0x20) & 0x20) {
|
||||
// write-to-buffer-abort reset
|
||||
bpi_flash_amd_write_buffer_abort_reset(fdev);
|
||||
|
||||
fprintf(stderr, "Failed to erase block\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpi_flash_amd_buffered_program(struct flash_device *fdev, size_t addr, size_t len, const void *src)
|
||||
{
|
||||
const uint8_t *s = (const uint8_t *)src;
|
||||
|
||||
bpi_flash_amd_unlock(fdev);
|
||||
bpi_flash_write_word(fdev, addr, BPI_AMD_BUFFERED_PROGRAM_SETUP);
|
||||
bpi_flash_write_cur(fdev, len-1);
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
bpi_flash_write_word(fdev, addr+i, s[0] | (s[1] << 8));
|
||||
s += 2;
|
||||
}
|
||||
|
||||
bpi_flash_set_addr(fdev, addr);
|
||||
bpi_flash_write_cur(fdev, BPI_AMD_BUFFERED_PROGRAM_CONFIRM);
|
||||
|
||||
if (bpi_flash_amd_wait_for_operation(fdev, 0x22) & 0x22) {
|
||||
// write-to-buffer-abort reset
|
||||
bpi_flash_amd_write_buffer_abort_reset(fdev);
|
||||
|
||||
fprintf(stderr, "Failed to write block\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct flash_ops bpi_flash_amd_ops = {
|
||||
.init = bpi_flash_amd_init,
|
||||
.sector_erase = bpi_flash_amd_sector_erase,
|
||||
.buffered_program = bpi_flash_amd_buffered_program
|
||||
};
|
||||
|
||||
// Micron flash ops (0x0002)
|
||||
|
||||
uint16_t bpi_flash_micron_read_status_register(struct flash_device *fdev)
|
||||
{
|
||||
bpi_flash_write_cur(fdev, BPI_MICRON_READ_STATUS_REG);
|
||||
return bpi_flash_read_cur(fdev);
|
||||
}
|
||||
|
||||
void bpi_flash_micron_clear_status_register(struct flash_device *fdev)
|
||||
{
|
||||
bpi_flash_write_cur(fdev, BPI_MICRON_CLEAR_STATUS_REG);
|
||||
}
|
||||
|
||||
void bpi_flash_micron_init(struct flash_device *fdev)
|
||||
{
|
||||
bpi_flash_micron_clear_status_register(fdev);
|
||||
}
|
||||
|
||||
int bpi_flash_micron_sector_erase(struct flash_device *fdev, size_t addr)
|
||||
{
|
||||
bpi_flash_set_addr(fdev, addr);
|
||||
bpi_flash_write_cur(fdev, BPI_MICRON_BLOCK_LOCK_SETUP);
|
||||
bpi_flash_write_cur(fdev, BPI_MICRON_BLOCK_UNLOCK);
|
||||
|
||||
if (bpi_flash_micron_read_status_register(fdev) & 0x30) {
|
||||
fprintf(stderr, "Failed to unlock block\n");
|
||||
bpi_flash_write_cur(fdev, CFI_READ_ARRAY);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bpi_flash_write_cur(fdev, BPI_MICRON_BLOCK_ERASE_SETUP);
|
||||
bpi_flash_write_cur(fdev, BPI_MICRON_BLOCK_ERASE_CONFIRM);
|
||||
|
||||
while (!(bpi_flash_micron_read_status_register(fdev) & 0x80)) {};
|
||||
|
||||
if (bpi_flash_micron_read_status_register(fdev) & 0x30) {
|
||||
fprintf(stderr, "Failed to erase block\n");
|
||||
bpi_flash_write_cur(fdev, CFI_READ_ARRAY);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bpi_flash_write_cur(fdev, CFI_READ_ARRAY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpi_flash_micron_buffered_program(struct flash_device *fdev, size_t addr, size_t len, const void *src)
|
||||
{
|
||||
const uint8_t *s = (const uint8_t *)src;
|
||||
|
||||
bpi_flash_set_addr(fdev, addr);
|
||||
bpi_flash_write_cur(fdev, BPI_MICRON_BUFFERED_PROGRAM_SETUP);
|
||||
bpi_flash_write_cur(fdev, len-1);
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
bpi_flash_write_word(fdev, addr+i, s[0] | (s[1] << 8));
|
||||
s += 2;
|
||||
}
|
||||
|
||||
bpi_flash_set_addr(fdev, addr);
|
||||
bpi_flash_write_cur(fdev, BPI_MICRON_BUFFERED_PROGRAM_CONFIRM);
|
||||
|
||||
while (!(bpi_flash_micron_read_status_register(fdev) & 0x80)) {};
|
||||
|
||||
if (bpi_flash_micron_read_status_register(fdev) & 0x30) {
|
||||
fprintf(stderr, "Failed to write block\n");
|
||||
bpi_flash_write_cur(fdev, CFI_READ_ARRAY);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bpi_flash_write_cur(fdev, CFI_READ_ARRAY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct flash_ops bpi_flash_micron_ops = {
|
||||
.init = bpi_flash_micron_init,
|
||||
.sector_erase = bpi_flash_micron_sector_erase,
|
||||
.buffered_program = bpi_flash_micron_buffered_program
|
||||
};
|
||||
|
||||
|
||||
void bpi_flash_release(struct flash_device *fdev)
|
||||
{
|
||||
bpi_flash_deselect(fdev);
|
||||
}
|
||||
|
||||
int bpi_flash_init(struct flash_device *fdev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!fdev)
|
||||
return -1;
|
||||
|
||||
// CFI query
|
||||
bpi_flash_write_word(fdev, CFI_QUERY_ADDR, CFI_QUERY_DATA);
|
||||
|
||||
if (bpi_flash_read_word(fdev, CFI_ID_0) != 'Q') {
|
||||
// may be Intel flash in sync read mode; attempt switch to async
|
||||
bpi_flash_write_word(fdev, 0xf94f, BPI_INTEL_READ_CONFIG_REG_SETUP);
|
||||
bpi_flash_write_word(fdev, 0xf94f, BPI_INTEL_SET_READ_CONFIG_REG);
|
||||
bpi_flash_write_word(fdev, CFI_QUERY_ADDR, CFI_QUERY_DATA);
|
||||
}
|
||||
|
||||
if (bpi_flash_read_word(fdev, CFI_ID_0) != 'Q' && ((bpi_flash_read_cur(fdev) ^ bpi_flash_read_cur(fdev)) & 0x44)) {
|
||||
// may be AMD flash in write buffer abort; perform write buffer abort reset
|
||||
bpi_flash_amd_write_buffer_abort_reset(fdev);
|
||||
bpi_flash_write_word(fdev, CFI_QUERY_ADDR, CFI_QUERY_DATA);
|
||||
}
|
||||
|
||||
if (bpi_flash_read_word(fdev, CFI_ID_0) != 'Q' ||
|
||||
bpi_flash_read_word(fdev, CFI_ID_1) != 'R' ||
|
||||
bpi_flash_read_word(fdev, CFI_ID_2) != 'Y') {
|
||||
fprintf(stderr, "Failed to read flash ID\n");
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
fdev->protocol = bpi_flash_read_word(fdev, CFI_PRI_CMD_SET_0) | (bpi_flash_read_word(fdev, CFI_PRI_CMD_SET_1) << 8);
|
||||
|
||||
printf("Command set: %d\n", fdev->protocol);
|
||||
|
||||
switch (fdev->protocol) {
|
||||
case 0x0001:
|
||||
// Intel command set (P30)
|
||||
fdev->ops = &bpi_flash_intel_ops;
|
||||
break;
|
||||
case 0x0002:
|
||||
// AMD command set (S29, MT28)
|
||||
fdev->ops = &bpi_flash_amd_ops;
|
||||
break;
|
||||
case 0x0200:
|
||||
// Micron
|
||||
fdev->ops = &bpi_flash_micron_ops;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown command set: %d\n", fdev->protocol);
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
uint8_t flash_size = bpi_flash_read_word(fdev, CFI_DEVICE_SIZE);
|
||||
fdev->size = ((size_t)1) << flash_size;
|
||||
|
||||
printf("Flash size: %d MB\n", 1 << (flash_size-20));
|
||||
|
||||
uint16_t write_buffer_size = bpi_flash_read_word(fdev, CFI_WRITE_BUFFER_SIZE_0) | (bpi_flash_read_word(fdev, CFI_WRITE_BUFFER_SIZE_1) << 8);
|
||||
fdev->write_buffer_size = ((size_t)1) << write_buffer_size;
|
||||
|
||||
printf("Write buffer size: %ld B\n", fdev->write_buffer_size);
|
||||
|
||||
fdev->erase_region_count = bpi_flash_read_word(fdev, CFI_ERASE_REGION_COUNT);
|
||||
|
||||
printf("Erase regions: %d\n", fdev->erase_region_count);
|
||||
|
||||
if (fdev->erase_region_count > 0) {
|
||||
fdev->erase_region[0].block_count = (bpi_flash_read_word(fdev, CFI_ERASE_REGION_1_INFO_0) | (bpi_flash_read_word(fdev, CFI_ERASE_REGION_1_INFO_1) << 8)) + 1;
|
||||
fdev->erase_region[0].block_size = (bpi_flash_read_word(fdev, CFI_ERASE_REGION_1_INFO_2) | (bpi_flash_read_word(fdev, CFI_ERASE_REGION_1_INFO_3) << 8)) * 256;
|
||||
fdev->erase_region[0].region_start = 0;
|
||||
fdev->erase_region[0].region_end = fdev->erase_region[0].region_start + fdev->erase_region[0].block_count * fdev->erase_region[0].block_size;
|
||||
|
||||
fdev->erase_block_size = fdev->erase_region[0].block_size;
|
||||
|
||||
printf("Erase region 0 block count: %ld\n", fdev->erase_region[0].block_count);
|
||||
printf("Erase region 0 block size: %ld B\n", fdev->erase_region[0].block_size);
|
||||
printf("Erase region 0 start: 0x%08lx\n", fdev->erase_region[0].region_start);
|
||||
printf("Erase region 0 end: 0x%08lx\n", fdev->erase_region[0].region_end);
|
||||
} else {
|
||||
fprintf(stderr, "No erase regions found!\n");
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (fdev->erase_region_count > 1) {
|
||||
fdev->erase_region[1].block_count = (bpi_flash_read_word(fdev, CFI_ERASE_REGION_2_INFO_0) | (bpi_flash_read_word(fdev, CFI_ERASE_REGION_2_INFO_1) << 8)) + 1;
|
||||
fdev->erase_region[1].block_size = (bpi_flash_read_word(fdev, CFI_ERASE_REGION_2_INFO_2) | (bpi_flash_read_word(fdev, CFI_ERASE_REGION_2_INFO_3) << 8)) * 256;
|
||||
fdev->erase_region[1].region_start = fdev->erase_region[0].region_end;
|
||||
fdev->erase_region[1].region_end = fdev->erase_region[1].region_start + fdev->erase_region[1].block_count * fdev->erase_region[1].block_size;
|
||||
|
||||
if (fdev->erase_region[1].block_size > fdev->erase_block_size) {
|
||||
fdev->erase_block_size = fdev->erase_region[1].block_size;
|
||||
}
|
||||
|
||||
printf("Erase region 1 block count: %ld\n", fdev->erase_region[1].block_count);
|
||||
printf("Erase region 1 block size: %ld B\n", fdev->erase_region[1].block_size);
|
||||
printf("Erase region 1 start: 0x%08lx\n", fdev->erase_region[1].region_start);
|
||||
printf("Erase region 1 end: 0x%08lx\n", fdev->erase_region[1].region_end);
|
||||
}
|
||||
|
||||
printf("Erase block size: %ld B\n", fdev->erase_block_size);
|
||||
|
||||
fdev->ops->init(fdev);
|
||||
|
||||
err:
|
||||
bpi_flash_release(fdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bpi_flash_read(struct flash_device *fdev, size_t addr, size_t len, void *dest)
|
||||
{
|
||||
char *d = dest;
|
||||
|
||||
bpi_flash_write_word(fdev, 0, CFI_READ_ARRAY);
|
||||
|
||||
if (addr & 1) {
|
||||
*d = bpi_flash_read_word(fdev, addr >> 1) >> 8;
|
||||
addr++;
|
||||
len--;
|
||||
d++;
|
||||
}
|
||||
|
||||
while (len > 1) {
|
||||
*((uint16_t *)d) = bpi_flash_read_word(fdev, addr >> 1);
|
||||
addr += 2;
|
||||
len -= 2;
|
||||
d += 2;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
*d = bpi_flash_read_word(fdev, addr >> 1);
|
||||
addr++;
|
||||
len--;
|
||||
d++;
|
||||
}
|
||||
|
||||
bpi_flash_deselect(fdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpi_flash_write(struct flash_device *fdev, size_t addr, size_t len, const void *src)
|
||||
{
|
||||
const char *s = src;
|
||||
|
||||
while (len > 0) {
|
||||
size_t seg = len;
|
||||
|
||||
// align to buffer size
|
||||
if (seg > fdev->write_buffer_size - (addr & (fdev->write_buffer_size-1))) {
|
||||
seg = fdev->write_buffer_size - (addr & (fdev->write_buffer_size-1));
|
||||
}
|
||||
|
||||
if (fdev->ops->buffered_program(fdev, addr >> 1, seg >> 1, s)) {
|
||||
fprintf(stderr, "Buffered write failed\n");
|
||||
bpi_flash_deselect(fdev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr += seg;
|
||||
len -= seg;
|
||||
s += seg;
|
||||
}
|
||||
|
||||
bpi_flash_deselect(fdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpi_flash_erase(struct flash_device *fdev, size_t addr, size_t len)
|
||||
{
|
||||
size_t erase_block_size = fdev->erase_block_size;
|
||||
|
||||
while (len > 0) {
|
||||
// determine sector size
|
||||
erase_block_size = 0;
|
||||
|
||||
for (int k = 0; k < fdev->erase_region_count; k++) {
|
||||
if (addr >= fdev->erase_region[k].region_start && addr < fdev->erase_region[k].region_end) {
|
||||
erase_block_size = fdev->erase_region[k].block_size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!erase_block_size) {
|
||||
fprintf(stderr, "Address does not match an erase region\n");
|
||||
bpi_flash_deselect(fdev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// check size and alignment
|
||||
if (addr & (erase_block_size-1) || len < erase_block_size) {
|
||||
fprintf(stderr, "Invalid erase request\n");
|
||||
bpi_flash_deselect(fdev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// block erase
|
||||
if (fdev->ops->sector_erase(fdev, addr >> 1)) {
|
||||
fprintf(stderr, "Failed to erase sector\n");
|
||||
bpi_flash_deselect(fdev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len <= erase_block_size)
|
||||
break;
|
||||
|
||||
addr += erase_block_size;
|
||||
len -= erase_block_size;
|
||||
}
|
||||
|
||||
bpi_flash_deselect(fdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct flash_driver bpi_flash_driver = {
|
||||
.init = bpi_flash_init,
|
||||
.release = bpi_flash_release,
|
||||
.read = bpi_flash_read,
|
||||
.write = bpi_flash_write,
|
||||
.erase = bpi_flash_erase
|
||||
};
|
||||
670
src/pyrite/utils/flash_spi.c
Normal file
670
src/pyrite/utils/flash_spi.c
Normal file
@@ -0,0 +1,670 @@
|
||||
// SPDX-License-Identifier: GPL
|
||||
/*
|
||||
|
||||
Copyright (c) 2026 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
#include "flash.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define SPI_CMD_RESET_ENABLE 0x66
|
||||
#define SPI_CMD_RESET_MEMORY 0x99
|
||||
#define SPI_CMD_READ_ID 0x9F
|
||||
#define SPI_CMD_READ 0x03
|
||||
#define SPI_CMD_FAST_READ 0x0B
|
||||
#define SPI_CMD_FAST_READ_DUAL_OUT 0x3B
|
||||
#define SPI_CMD_FAST_READ_DUAL_IO 0xBB
|
||||
#define SPI_CMD_FAST_READ_QUAD_OUT 0x6B
|
||||
#define SPI_CMD_FAST_READ_QUAD_IO 0xEB
|
||||
#define SPI_CMD_DTR_FAST_READ 0x0D
|
||||
#define SPI_CMD_DTR_FAST_READ_DUAL_OUT 0x3D
|
||||
#define SPI_CMD_DTR_FAST_READ_DUAL_IO 0xBD
|
||||
#define SPI_CMD_DTR_FAST_READ_QUAD_OUT 0x6D
|
||||
#define SPI_CMD_DTR_FAST_READ_QUAD_IO 0xED
|
||||
#define SPI_CMD_4B_READ 0x13
|
||||
#define SPI_CMD_4B_FAST_READ 0x0C
|
||||
#define SPI_CMD_4B_FAST_READ_DUAL_OUT 0x3C
|
||||
#define SPI_CMD_4B_FAST_READ_DUAL_IO 0xBC
|
||||
#define SPI_CMD_4B_FAST_READ_QUAD_OUT 0x6C
|
||||
#define SPI_CMD_4B_FAST_READ_QUAD_IO 0xEC
|
||||
#define SPI_CMD_4B_DTR_FAST_READ 0x0E
|
||||
#define SPI_CMD_4B_DTR_FAST_READ_DUAL_IO 0xBE
|
||||
#define SPI_CMD_4B_DTR_FAST_READ_QUAD_IO 0xEE
|
||||
#define SPI_CMD_WRITE_ENABLE 0x06
|
||||
#define SPI_CMD_WRITE_DISABLE 0x04
|
||||
#define SPI_CMD_READ_STATUS_REG 0x05
|
||||
#define SPI_CMD_READ_FLAG_STATUS_REG 0x70
|
||||
#define SPI_CMD_READ_NV_CONFIG_REG 0xB5
|
||||
#define SPI_CMD_READ_V_CONFIG_REG 0x85
|
||||
#define SPI_CMD_READ_EV_CONFIG_REG 0x65
|
||||
#define SPI_CMD_READ_EXT_ADDR_REG 0xC8
|
||||
#define SPI_CMD_WRITE_STATUS_REG 0x01
|
||||
#define SPI_CMD_WRITE_NV_CONFIG_REG 0xB1
|
||||
#define SPI_CMD_WRITE_V_CONFIG_REG 0x81
|
||||
#define SPI_CMD_WRITE_EV_CONFIG_REG 0x61
|
||||
#define SPI_CMD_WRITE_EXT_ADDR_REG 0xC5
|
||||
#define SPI_CMD_CLEAR_FLAG_STATUS_REG 0x50
|
||||
#define SPI_CMD_PAGE_PROGRAM 0x02
|
||||
#define SPI_CMD_PAGE_PROGRAM_DUAL_IN 0xA2
|
||||
#define SPI_CMD_PAGE_PROGRAM_DUAL_IN_EXT 0xD2
|
||||
#define SPI_CMD_PAGE_PROGRAM_QUAD_IN 0x32
|
||||
#define SPI_CMD_PAGE_PROGRAM_QUAD_IN_EXT 0x38
|
||||
#define SPI_CMD_4B_PAGE_PROGRAM 0x12
|
||||
#define SPI_CMD_4B_PAGE_PROGRAM_QUAD_IN 0x34
|
||||
#define SPI_CMD_4B_PAGE_PROGRAM_QUAD_IN_EXT 0x3E
|
||||
#define SPI_CMD_32KB_SUBSECTOR_ERASE 0x52
|
||||
#define SPI_CMD_4KB_SUBSECTOR_ERASE 0x20
|
||||
#define SPI_CMD_SECTOR_ERASE 0xD8
|
||||
#define SPI_CMD_BULK_ERASE 0xC7
|
||||
#define SPI_CMD_4B_4KB_SUBSECTOR_ERASE 0x21
|
||||
#define SPI_CMD_4B_SECTOR_ERASE 0xDC
|
||||
#define SPI_CMD_PROGRAM_SUSPEND 0x75
|
||||
#define SPI_CMD_PROGRAM_RESUME 0x7A
|
||||
#define SPI_CMD_READ_OTP_ARRAY 0x4B
|
||||
#define SPI_CMD_PROGRAM_OTP_ARRAY 0x42
|
||||
#define SPI_CMD_ENTER_4B_ADDR_MODE 0xB7
|
||||
#define SPI_CMD_EXIT_4B_ADDR_MODE 0xE9
|
||||
#define SPI_CMD_ENTER_QUAD_IO_MODE 0x35
|
||||
#define SPI_CMD_EXIT_QUAD_IO_MODE 0xF5
|
||||
#define SPI_CMD_ENTER_DEEP_POWER_DOWN 0xB9
|
||||
#define SPI_CMD_EXIT_DEEP_POWER_DOWN 0xAB
|
||||
#define SPI_CMD_READ_SECTOR_PROTECTION 0x2D
|
||||
#define SPI_CMD_PRGM_SECTOR_PROTECTION 0x2C
|
||||
#define SPI_CMD_READ_V_LOCK_BITS 0xE8
|
||||
#define SPI_CMD_WRITE_V_LOCK_BITS 0xE5
|
||||
#define SPI_CMD_4B_READ_V_LOCK_BITS 0xE0
|
||||
#define SPI_CMD_4B_WRITE_V_LOCK_BITS 0xE1
|
||||
#define SPI_CMD_READ_NV_LOCK_BITS 0xE2
|
||||
#define SPI_CMD_PRGM_NV_LOCK_BITS 0xE3
|
||||
#define SPI_CMD_ERASE_NV_LOCK_BITS 0xE4
|
||||
#define SPI_CMD_READ_GLOBAL_FREEZE_BIT 0xA7
|
||||
#define SPI_CMD_WRITE_GLOBAL_FREEZE_BIT 0xA6
|
||||
#define SPI_CMD_READ_PASSWORD 0x27
|
||||
#define SPI_CMD_WRITE_PASSWORD 0x28
|
||||
#define SPI_CMD_UNLOCK_PASSWORD 0x29
|
||||
|
||||
// Macronix
|
||||
#define SPI_MXIC_CMD_RDCR 0x15
|
||||
#define SPI_MXIC_CMD_RDSCUR 0x2B
|
||||
#define SPI_MXIC_CMD_WRSCUR 0x2F
|
||||
#define SPI_MXIC_CMD_GBLK 0x7E
|
||||
#define SPI_MXIC_CMD_GBULK 0x98
|
||||
#define SPI_MXIC_CMD_WRLR 0x2C
|
||||
#define SPI_MXIC_CMD_RDLR 0x2D
|
||||
#define SPI_MXIC_CMD_WRSPB 0xE3
|
||||
#define SPI_MXIC_CMD_ESSPB 0xE4
|
||||
#define SPI_MXIC_CMD_RDSPB 0xE2
|
||||
#define SPI_MXIC_CMD_WRDPB 0xE1
|
||||
#define SPI_MXIC_CMD_RDDPB 0xE0
|
||||
|
||||
#define SPI_PROTO_STR 0
|
||||
#define SPI_PROTO_DTR 1
|
||||
#define SPI_PROTO_DUAL_STR 2
|
||||
#define SPI_PROTO_DUAL_DTR 3
|
||||
#define SPI_PROTO_QUAD_STR 4
|
||||
#define SPI_PROTO_QUAD_DTR 5
|
||||
|
||||
#define SPI_PAGE_SIZE 0x100
|
||||
#define SPI_SUBSECTOR_SIZE 0x1000
|
||||
#define SPI_SECTOR_SIZE 0x10000
|
||||
|
||||
#define FLASH_D_0 (1 << 0)
|
||||
#define FLASH_D_1 (1 << 1)
|
||||
#define FLASH_D_2 (1 << 2)
|
||||
#define FLASH_D_3 (1 << 3)
|
||||
#define FLASH_D_01 (FLASH_D_0 | FLASH_D_1)
|
||||
#define FLASH_D_0123 (FLASH_D_0 | FLASH_D_1 | FLASH_D_2 | FLASH_D_3)
|
||||
#define FLASH_OE_0 (1 << 8)
|
||||
#define FLASH_OE_1 (1 << 9)
|
||||
#define FLASH_OE_2 (1 << 10)
|
||||
#define FLASH_OE_3 (1 << 11)
|
||||
#define FLASH_OE_01 (FLASH_OE_0 | FLASH_OE_1)
|
||||
#define FLASH_OE_0123 (FLASH_OE_0 | FLASH_OE_1 | FLASH_OE_2 | FLASH_OE_3)
|
||||
#define FLASH_CLK (1 << 16)
|
||||
#define FLASH_CS_N (1 << 17)
|
||||
|
||||
static uint32_t ctrl_reg_read(struct flash_device *fdev)
|
||||
{
|
||||
uint32_t reg_val = 0;
|
||||
reg_if_read32(fdev->reg, fdev->ctrl_reg_offset, ®_val);
|
||||
return reg_val;
|
||||
}
|
||||
|
||||
static void ctrl_reg_write(struct flash_device *fdev, uint32_t val)
|
||||
{
|
||||
reg_if_write32(fdev->reg, fdev->ctrl_reg_offset, val);
|
||||
}
|
||||
|
||||
void spi_flash_select(struct flash_device *fdev)
|
||||
{
|
||||
ctrl_reg_write(fdev, 0);
|
||||
}
|
||||
|
||||
void spi_flash_deselect(struct flash_device *fdev)
|
||||
{
|
||||
ctrl_reg_write(fdev, FLASH_CS_N);
|
||||
}
|
||||
|
||||
uint8_t spi_flash_read_byte(struct flash_device *fdev, int protocol)
|
||||
{
|
||||
uint8_t val = 0;
|
||||
|
||||
switch (protocol){
|
||||
case SPI_PROTO_STR:
|
||||
for (int i = 7; i >= 0; i--) {
|
||||
ctrl_reg_write(fdev, 0);
|
||||
ctrl_reg_read(fdev); // dummy read
|
||||
val |= ((ctrl_reg_read(fdev) & FLASH_D_1) != 0) << i;
|
||||
ctrl_reg_write(fdev, FLASH_CLK);
|
||||
ctrl_reg_read(fdev); // dummy read
|
||||
}
|
||||
break;
|
||||
case SPI_PROTO_DTR:
|
||||
break;
|
||||
case SPI_PROTO_DUAL_STR:
|
||||
for (int i = 6; i >= 0; i -= 2) {
|
||||
ctrl_reg_write(fdev, 0);
|
||||
ctrl_reg_read(fdev); // dummy read
|
||||
val |= (ctrl_reg_read(fdev) & FLASH_D_01) << i;
|
||||
ctrl_reg_write(fdev, FLASH_CLK);
|
||||
ctrl_reg_read(fdev); // dummy read
|
||||
}
|
||||
break;
|
||||
case SPI_PROTO_DUAL_DTR:
|
||||
break;
|
||||
case SPI_PROTO_QUAD_STR:
|
||||
for (int i = 4; i >= 0; i -= 4) {
|
||||
ctrl_reg_write(fdev, 0);
|
||||
ctrl_reg_read(fdev); // dummy read
|
||||
val |= (ctrl_reg_read(fdev) & FLASH_D_0123) << i;
|
||||
ctrl_reg_write(fdev, FLASH_CLK);
|
||||
ctrl_reg_read(fdev); // dummy read
|
||||
}
|
||||
break;
|
||||
case SPI_PROTO_QUAD_DTR:
|
||||
break;
|
||||
}
|
||||
|
||||
ctrl_reg_write(fdev, 0);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void spi_flash_write_byte(struct flash_device *fdev, uint8_t val, int protocol)
|
||||
{
|
||||
uint8_t bit;
|
||||
|
||||
switch (protocol){
|
||||
case SPI_PROTO_STR:
|
||||
for (int i = 7; i >= 0; i--) {
|
||||
bit = (val >> i) & 0x1;
|
||||
ctrl_reg_write(fdev, bit | FLASH_OE_0);
|
||||
ctrl_reg_read(fdev); // dummy read
|
||||
ctrl_reg_write(fdev, bit | FLASH_OE_0 | FLASH_CLK);
|
||||
ctrl_reg_read(fdev); // dummy read
|
||||
}
|
||||
break;
|
||||
case SPI_PROTO_DTR:
|
||||
break;
|
||||
case SPI_PROTO_DUAL_STR:
|
||||
for (int i = 6; i >= 0; i -= 2) {
|
||||
bit = (val >> i) & 0x3;
|
||||
ctrl_reg_write(fdev, bit | FLASH_OE_01);
|
||||
ctrl_reg_read(fdev); // dummy read
|
||||
ctrl_reg_write(fdev, bit | FLASH_OE_01 | FLASH_CLK);
|
||||
ctrl_reg_read(fdev); // dummy read
|
||||
}
|
||||
break;
|
||||
case SPI_PROTO_DUAL_DTR:
|
||||
break;
|
||||
case SPI_PROTO_QUAD_STR:
|
||||
for (int i = 4; i >= 0; i -= 4) {
|
||||
bit = (val >> i) & 0xf;
|
||||
ctrl_reg_write(fdev, bit | FLASH_OE_0123);
|
||||
ctrl_reg_read(fdev); // dummy read
|
||||
ctrl_reg_write(fdev, bit | FLASH_OE_0123 | FLASH_CLK);
|
||||
ctrl_reg_read(fdev); // dummy read
|
||||
}
|
||||
break;
|
||||
case SPI_PROTO_QUAD_DTR:
|
||||
break;
|
||||
}
|
||||
|
||||
ctrl_reg_write(fdev, 0);
|
||||
}
|
||||
|
||||
void spi_flash_write_addr(struct flash_device *fdev, size_t addr, int protocol)
|
||||
{
|
||||
spi_flash_write_byte(fdev, (addr >> 16) & 0xff, protocol);
|
||||
spi_flash_write_byte(fdev, (addr >> 8) & 0xff, protocol);
|
||||
spi_flash_write_byte(fdev, (addr >> 0) & 0xff, protocol);
|
||||
}
|
||||
|
||||
void spi_flash_write_addr_4b(struct flash_device *fdev, size_t addr, int protocol)
|
||||
{
|
||||
spi_flash_write_byte(fdev, (addr >> 24) & 0xff, protocol);
|
||||
spi_flash_write_byte(fdev, (addr >> 16) & 0xff, protocol);
|
||||
spi_flash_write_byte(fdev, (addr >> 8) & 0xff, protocol);
|
||||
spi_flash_write_byte(fdev, (addr >> 0) & 0xff, protocol);
|
||||
}
|
||||
|
||||
void spi_flash_write_enable(struct flash_device *fdev, int protocol)
|
||||
{
|
||||
spi_flash_write_byte(fdev, SPI_CMD_WRITE_ENABLE, protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
}
|
||||
|
||||
void spi_flash_write_disable(struct flash_device *fdev, int protocol)
|
||||
{
|
||||
spi_flash_write_byte(fdev, SPI_CMD_WRITE_DISABLE, protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
}
|
||||
|
||||
uint8_t spi_flash_read_status_reg(struct flash_device *fdev, int protocol)
|
||||
{
|
||||
uint8_t val;
|
||||
spi_flash_write_byte(fdev, SPI_CMD_READ_STATUS_REG, protocol);
|
||||
val = spi_flash_read_byte(fdev, protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
return val;
|
||||
}
|
||||
|
||||
void spi_flash_write_status_reg(struct flash_device *fdev, uint8_t val, int protocol)
|
||||
{
|
||||
spi_flash_write_byte(fdev, SPI_CMD_WRITE_STATUS_REG, protocol);
|
||||
spi_flash_write_byte(fdev, val, protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
}
|
||||
|
||||
void spi_mxic_flash_write_status_cfg_reg(struct flash_device *fdev, uint8_t status, uint8_t cfg, int protocol)
|
||||
{
|
||||
spi_flash_write_byte(fdev, SPI_CMD_WRITE_STATUS_REG, protocol);
|
||||
spi_flash_write_byte(fdev, status, protocol);
|
||||
spi_flash_write_byte(fdev, cfg, protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
}
|
||||
|
||||
uint8_t spi_mxic_flash_read_cfg_reg(struct flash_device *fdev, int protocol)
|
||||
{
|
||||
uint8_t val;
|
||||
spi_flash_write_byte(fdev, SPI_MXIC_CMD_RDCR, protocol);
|
||||
val = spi_flash_read_byte(fdev, protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
return val;
|
||||
}
|
||||
|
||||
uint8_t spi_mxic_flash_read_security_reg(struct flash_device *fdev, int protocol)
|
||||
{
|
||||
uint8_t val;
|
||||
spi_flash_write_byte(fdev, SPI_MXIC_CMD_RDSCUR, protocol);
|
||||
val = spi_flash_read_byte(fdev, protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
return val;
|
||||
}
|
||||
|
||||
uint8_t spi_flash_read_flag_status_reg(struct flash_device *fdev, int protocol)
|
||||
{
|
||||
uint8_t val;
|
||||
spi_flash_write_byte(fdev, SPI_CMD_READ_FLAG_STATUS_REG, protocol);
|
||||
val = spi_flash_read_byte(fdev, protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
return val;
|
||||
}
|
||||
|
||||
void spi_flash_clear_flag_status_reg(struct flash_device *fdev, int protocol)
|
||||
{
|
||||
spi_flash_write_byte(fdev, SPI_CMD_CLEAR_FLAG_STATUS_REG, protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
}
|
||||
|
||||
uint8_t spi_flash_read_volatile_cfg_reg(struct flash_device *fdev, int protocol)
|
||||
{
|
||||
uint8_t val;
|
||||
spi_flash_write_byte(fdev, SPI_CMD_READ_V_CONFIG_REG, protocol);
|
||||
val = spi_flash_read_byte(fdev, protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
return val;
|
||||
}
|
||||
|
||||
void spi_flash_write_volatile_config_reg(struct flash_device *fdev, uint8_t val, int protocol)
|
||||
{
|
||||
spi_flash_write_byte(fdev, SPI_CMD_WRITE_V_CONFIG_REG, protocol);
|
||||
spi_flash_write_byte(fdev, val, protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
}
|
||||
|
||||
uint16_t spi_flash_read_sector_protection_reg(struct flash_device *fdev, int protocol)
|
||||
{
|
||||
uint16_t val;
|
||||
spi_flash_write_byte(fdev, SPI_CMD_READ_SECTOR_PROTECTION, protocol);
|
||||
val = spi_flash_read_byte(fdev, protocol);
|
||||
val |= (uint16_t)spi_flash_read_byte(fdev, protocol) << 8;
|
||||
spi_flash_deselect(fdev);
|
||||
return val;
|
||||
}
|
||||
|
||||
uint8_t spi_flash_read_global_freeze_bit(struct flash_device *fdev, int protocol)
|
||||
{
|
||||
uint8_t val;
|
||||
spi_flash_write_byte(fdev, SPI_CMD_READ_GLOBAL_FREEZE_BIT, protocol);
|
||||
val = spi_flash_read_byte(fdev, protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
return val;
|
||||
}
|
||||
|
||||
uint8_t spi_flash_read_nv_lock_bits(struct flash_device *fdev, size_t addr, int protocol)
|
||||
{
|
||||
uint8_t val;
|
||||
spi_flash_write_byte(fdev, SPI_CMD_READ_NV_LOCK_BITS, protocol);
|
||||
spi_flash_write_addr_4b(fdev, addr, protocol);
|
||||
val = spi_flash_read_byte(fdev, protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
return val;
|
||||
}
|
||||
|
||||
void spi_flash_unlock_password(struct flash_device *fdev, char *val, int protocol)
|
||||
{
|
||||
spi_flash_write_byte(fdev, SPI_CMD_UNLOCK_PASSWORD, protocol);
|
||||
for (int k = 0; k < 8; k++)
|
||||
spi_flash_write_byte(fdev, val[k], protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
}
|
||||
|
||||
void spi_flash_reset(struct flash_device *fdev, int protocol)
|
||||
{
|
||||
spi_flash_deselect(fdev);
|
||||
spi_flash_write_byte(fdev, SPI_CMD_RESET_ENABLE, protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
ctrl_reg_read(fdev); // dummy read
|
||||
ctrl_reg_read(fdev); // dummy read
|
||||
spi_flash_write_byte(fdev, SPI_CMD_RESET_MEMORY, protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
ctrl_reg_read(fdev); // dummy read
|
||||
ctrl_reg_read(fdev); // dummy read
|
||||
}
|
||||
|
||||
void spi_flash_release(struct flash_device *fdev)
|
||||
{
|
||||
spi_flash_deselect(fdev);
|
||||
}
|
||||
|
||||
int spi_flash_init(struct flash_device *fdev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!fdev)
|
||||
return -1;
|
||||
|
||||
spi_flash_reset(fdev, SPI_PROTO_STR);
|
||||
|
||||
spi_flash_write_byte(fdev, SPI_CMD_READ_ID, SPI_PROTO_STR);
|
||||
int mfr_id = spi_flash_read_byte(fdev, SPI_PROTO_STR);
|
||||
int mem_type = spi_flash_read_byte(fdev, SPI_PROTO_STR);
|
||||
int mem_capacity = spi_flash_read_byte(fdev, SPI_PROTO_STR);
|
||||
spi_flash_deselect(fdev);
|
||||
|
||||
printf("Manufacturer ID: 0x%02x\n", mfr_id);
|
||||
printf("Memory type: 0x%02x\n", mem_type);
|
||||
printf("Memory capacity: 0x%02x\n", mem_capacity);
|
||||
|
||||
if (mfr_id == 0 || mfr_id == 0xff) {
|
||||
fprintf(stderr, "Failed to read flash ID\n");
|
||||
spi_flash_deselect(fdev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (mfr_id) {
|
||||
case 0x20:
|
||||
// Micron
|
||||
printf("Manufacturer: Micron\n");
|
||||
// convert from BCD
|
||||
mem_capacity = (mem_capacity & 0xf) + (((mem_capacity >> 4) & 0xf) * 10);
|
||||
fdev->size = ((size_t)1) << (mem_capacity+6);
|
||||
break;
|
||||
case 0xC2:
|
||||
// Macronix
|
||||
printf("Manufacturer: Macronix\n");
|
||||
fdev->size = ((size_t)1) << (mem_capacity-32);
|
||||
break;
|
||||
default:
|
||||
// unknown
|
||||
fprintf(stderr, "Unknown flash ID\n");
|
||||
spi_flash_deselect(fdev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Flash size: %ld MB\n", fdev->size / (1 << 20));
|
||||
|
||||
fdev->protocol = SPI_PROTO_STR;
|
||||
fdev->bulk_protocol = SPI_PROTO_STR;
|
||||
fdev->read_dummy_cycles = 0;
|
||||
fdev->write_buffer_size = SPI_PAGE_SIZE;
|
||||
fdev->erase_block_size = SPI_SUBSECTOR_SIZE;
|
||||
|
||||
printf("Write buffer size: %ld B\n", fdev->write_buffer_size);
|
||||
printf("Erase block size: %ld B\n", fdev->erase_block_size);
|
||||
|
||||
printf("Status register: 0x%02x\n", spi_flash_read_status_reg(fdev, SPI_PROTO_STR));
|
||||
|
||||
switch (mfr_id) {
|
||||
case 0x20:
|
||||
// Micron
|
||||
printf("Flag status register: 0x%02x\n", spi_flash_read_flag_status_reg(fdev, SPI_PROTO_STR));
|
||||
printf("Volatile config register: 0x%02x\n", spi_flash_read_volatile_cfg_reg(fdev, SPI_PROTO_STR));
|
||||
printf("Global freeze bit: 0x%02x\n", spi_flash_read_global_freeze_bit(fdev, SPI_PROTO_STR));
|
||||
printf("Sector protection register: 0x%04x\n", spi_flash_read_sector_protection_reg(fdev, SPI_PROTO_STR));
|
||||
|
||||
if (fdev->data_width == 4) {
|
||||
spi_flash_write_volatile_config_reg(fdev, 0xFB, SPI_PROTO_STR);
|
||||
fdev->bulk_protocol = SPI_PROTO_QUAD_STR;
|
||||
fdev->read_dummy_cycles = 10;
|
||||
}
|
||||
|
||||
break;
|
||||
case 0xC2:
|
||||
// Macronix
|
||||
printf("Config register: 0x%02x\n", spi_mxic_flash_read_cfg_reg(fdev, SPI_PROTO_STR));
|
||||
printf("Sector protection register: 0x%04x\n", spi_flash_read_sector_protection_reg(fdev, SPI_PROTO_STR));
|
||||
printf("Security register: 0x%02x\n", spi_mxic_flash_read_security_reg(fdev, SPI_PROTO_STR));
|
||||
|
||||
if (fdev->data_width == 4) {
|
||||
spi_mxic_flash_write_status_cfg_reg(fdev, 0x40, 0x07, SPI_PROTO_STR);
|
||||
fdev->bulk_protocol = SPI_PROTO_QUAD_STR;
|
||||
fdev->read_dummy_cycles = 6;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
spi_flash_release(fdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int spi_flash_read(struct flash_device *fdev, size_t addr, size_t len, void *dest)
|
||||
{
|
||||
char *d = dest;
|
||||
|
||||
int protocol = SPI_PROTO_STR;
|
||||
|
||||
if (fdev->data_width == 4) {
|
||||
protocol = SPI_PROTO_QUAD_STR;
|
||||
}
|
||||
|
||||
if (fdev->size > 0x1000000) {
|
||||
// four byte address read
|
||||
if (protocol == SPI_PROTO_QUAD_STR) {
|
||||
spi_flash_write_byte(fdev, SPI_CMD_4B_FAST_READ_QUAD_IO, SPI_PROTO_STR);
|
||||
} else {
|
||||
spi_flash_write_byte(fdev, SPI_CMD_4B_READ, SPI_PROTO_STR);
|
||||
}
|
||||
spi_flash_write_addr_4b(fdev, addr, protocol);
|
||||
} else {
|
||||
// normal read
|
||||
if (protocol == SPI_PROTO_QUAD_STR) {
|
||||
spi_flash_write_byte(fdev, SPI_CMD_FAST_READ_QUAD_IO, SPI_PROTO_STR);
|
||||
} else {
|
||||
spi_flash_write_byte(fdev, SPI_CMD_READ, SPI_PROTO_STR);
|
||||
}
|
||||
spi_flash_write_addr(fdev, addr, protocol);
|
||||
}
|
||||
|
||||
if (protocol != SPI_PROTO_STR) {
|
||||
// dummy cycles
|
||||
for (int i = 0; i < fdev->read_dummy_cycles; i++) {
|
||||
ctrl_reg_write(fdev, FLASH_CLK);
|
||||
ctrl_reg_write(fdev, 0);
|
||||
}
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
*d = spi_flash_read_byte(fdev, protocol);
|
||||
len--;
|
||||
d++;
|
||||
}
|
||||
|
||||
spi_flash_deselect(fdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_flash_write(struct flash_device *fdev, size_t addr, size_t len, const void *src)
|
||||
{
|
||||
const char *s = src;
|
||||
|
||||
int protocol = SPI_PROTO_STR;
|
||||
|
||||
if (fdev->data_width == 4) {
|
||||
protocol = SPI_PROTO_QUAD_STR;
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
spi_flash_write_enable(fdev, SPI_PROTO_STR);
|
||||
|
||||
if (!(spi_flash_read_status_reg(fdev, SPI_PROTO_STR) & 0x02)) {
|
||||
fprintf(stderr, "Failed to enable writing\n");
|
||||
spi_flash_deselect(fdev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fdev->size > 0x1000000) {
|
||||
// four byte address page program
|
||||
if (protocol == SPI_PROTO_QUAD_STR) {
|
||||
spi_flash_write_byte(fdev, SPI_CMD_4B_PAGE_PROGRAM_QUAD_IN_EXT, SPI_PROTO_STR);
|
||||
} else {
|
||||
spi_flash_write_byte(fdev, SPI_CMD_4B_PAGE_PROGRAM, SPI_PROTO_STR);
|
||||
}
|
||||
spi_flash_write_addr_4b(fdev, addr, protocol);
|
||||
} else {
|
||||
// normal page program
|
||||
if (protocol == SPI_PROTO_QUAD_STR) {
|
||||
spi_flash_write_byte(fdev, SPI_CMD_PAGE_PROGRAM_QUAD_IN_EXT, SPI_PROTO_STR);
|
||||
} else {
|
||||
spi_flash_write_byte(fdev, SPI_CMD_PAGE_PROGRAM, SPI_PROTO_STR);
|
||||
}
|
||||
spi_flash_write_addr(fdev, addr, protocol);
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
spi_flash_write_byte(fdev, *s, protocol);
|
||||
addr++;
|
||||
s++;
|
||||
len--;
|
||||
|
||||
if ((addr & 0xff) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
spi_flash_deselect(fdev);
|
||||
|
||||
// wait for operation to complete
|
||||
while (spi_flash_read_status_reg(fdev, SPI_PROTO_STR) & 0x01) {};
|
||||
}
|
||||
|
||||
spi_flash_deselect(fdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_flash_erase(struct flash_device *fdev, size_t addr, size_t len)
|
||||
{
|
||||
size_t erase_block_size = fdev->erase_block_size;
|
||||
|
||||
while (len > 0) {
|
||||
// determine sector size
|
||||
erase_block_size = 0;
|
||||
|
||||
if ((addr & (SPI_SECTOR_SIZE-1)) == 0 && len >= SPI_SECTOR_SIZE) {
|
||||
erase_block_size = SPI_SECTOR_SIZE;
|
||||
} else if ((addr & (SPI_SUBSECTOR_SIZE-1)) == 0 && len >= SPI_SUBSECTOR_SIZE) {
|
||||
erase_block_size = SPI_SUBSECTOR_SIZE;
|
||||
}
|
||||
|
||||
// check size and alignment
|
||||
if (!erase_block_size) {
|
||||
fprintf(stderr, "Invalid erase request\n");
|
||||
spi_flash_deselect(fdev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// enable writing
|
||||
spi_flash_write_enable(fdev, SPI_PROTO_STR);
|
||||
|
||||
if (!(spi_flash_read_status_reg(fdev, SPI_PROTO_STR) & 0x02)) {
|
||||
fprintf(stderr, "Failed to enable writing\n");
|
||||
spi_flash_deselect(fdev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// block erase
|
||||
if (fdev->size > 0x1000000) {
|
||||
if (erase_block_size == SPI_SECTOR_SIZE) {
|
||||
// four byte address sector erase
|
||||
spi_flash_write_byte(fdev, SPI_CMD_4B_SECTOR_ERASE, SPI_PROTO_STR);
|
||||
spi_flash_write_addr_4b(fdev, addr, SPI_PROTO_STR);
|
||||
} else if (erase_block_size == SPI_SUBSECTOR_SIZE) {
|
||||
// normal 4KB subsector erase
|
||||
spi_flash_write_byte(fdev, SPI_CMD_4B_4KB_SUBSECTOR_ERASE, SPI_PROTO_STR);
|
||||
spi_flash_write_addr_4b(fdev, addr, SPI_PROTO_STR);
|
||||
}
|
||||
} else {
|
||||
if (erase_block_size == SPI_SECTOR_SIZE) {
|
||||
// normal sector erase
|
||||
spi_flash_write_byte(fdev, SPI_CMD_SECTOR_ERASE, SPI_PROTO_STR);
|
||||
spi_flash_write_addr(fdev, addr, SPI_PROTO_STR);
|
||||
} else if (erase_block_size == SPI_SUBSECTOR_SIZE) {
|
||||
// normal 4KB subsector erase
|
||||
spi_flash_write_byte(fdev, SPI_CMD_4KB_SUBSECTOR_ERASE, SPI_PROTO_STR);
|
||||
spi_flash_write_addr(fdev, addr, SPI_PROTO_STR);
|
||||
}
|
||||
}
|
||||
|
||||
spi_flash_deselect(fdev);
|
||||
|
||||
// wait for operation to complete
|
||||
while (spi_flash_read_status_reg(fdev, SPI_PROTO_STR) & 0x01) {};
|
||||
|
||||
if (len <= erase_block_size)
|
||||
break;
|
||||
|
||||
addr += erase_block_size;
|
||||
len -= erase_block_size;
|
||||
}
|
||||
|
||||
spi_flash_deselect(fdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct flash_driver spi_flash_driver = {
|
||||
.init = spi_flash_init,
|
||||
.release = spi_flash_release,
|
||||
.read = spi_flash_read,
|
||||
.write = spi_flash_write,
|
||||
.erase = spi_flash_erase
|
||||
};
|
||||
323
src/pyrite/utils/fpga_id.c
Normal file
323
src/pyrite/utils/fpga_id.c
Normal file
@@ -0,0 +1,323 @@
|
||||
// SPDX-License-Identifier: GPL
|
||||
/*
|
||||
|
||||
Copyright (c) 2026 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
#include "fpga_id.h"
|
||||
|
||||
struct fpga_id {
|
||||
int id;
|
||||
int mask;
|
||||
char part[16];
|
||||
};
|
||||
|
||||
const struct fpga_id fpga_id_list[] =
|
||||
{
|
||||
// Xilinx
|
||||
// Spartan 7
|
||||
{FPGA_ID_XC7S6, FPGA_ID_MASK_NOVER, "XC7S6"},
|
||||
{FPGA_ID_XC7S15, FPGA_ID_MASK_NOVER, "XC7S15"},
|
||||
{FPGA_ID_XC7S25, FPGA_ID_MASK_NOVER, "XC7S25"},
|
||||
{FPGA_ID_XC7S50, FPGA_ID_MASK_NOVER, "XC7S50"},
|
||||
{FPGA_ID_XC7S75, FPGA_ID_MASK_NOVER, "XC7S75"},
|
||||
{FPGA_ID_XC7S100, FPGA_ID_MASK_NOVER, "XC7S100"},
|
||||
// Artix 7
|
||||
{FPGA_ID_XC7A15T, FPGA_ID_MASK_NOVER, "XC7A15T"},
|
||||
{FPGA_ID_XC7A35T, FPGA_ID_MASK_NOVER, "XC7A35T"},
|
||||
{FPGA_ID_XC7A50T, FPGA_ID_MASK_NOVER, "XC7A50T"},
|
||||
{FPGA_ID_XC7A75T, FPGA_ID_MASK_NOVER, "XC7A75T"},
|
||||
{FPGA_ID_XC7A100T, FPGA_ID_MASK_NOVER, "XC7A100T"},
|
||||
{FPGA_ID_XC7A200T, FPGA_ID_MASK_NOVER, "XC7A200T"},
|
||||
// Kintex 7
|
||||
{FPGA_ID_XC7K70T, FPGA_ID_MASK_NOVER, "XC7K70T"},
|
||||
{FPGA_ID_XC7K160T, FPGA_ID_MASK_NOVER, "XC7K160T"},
|
||||
{FPGA_ID_XC7K325T, FPGA_ID_MASK_NOVER, "XC7K325T"},
|
||||
{FPGA_ID_XC7K355T, FPGA_ID_MASK_NOVER, "XC7K355T"},
|
||||
{FPGA_ID_XC7K410T, FPGA_ID_MASK_NOVER, "XC7K410T"},
|
||||
{FPGA_ID_XC7K420T, FPGA_ID_MASK_NOVER, "XC7K420T"},
|
||||
{FPGA_ID_XC7K480T, FPGA_ID_MASK_NOVER, "XC7K480T"},
|
||||
// Virtex 7
|
||||
{FPGA_ID_XC7V585T, FPGA_ID_MASK_NOVER, "XC7V585T"},
|
||||
{FPGA_ID_XC7V2000T, FPGA_ID_MASK_NOVER, "XC7V2000T"},
|
||||
{FPGA_ID_XC7VX330T, FPGA_ID_MASK_NOVER, "XC7VX330T"},
|
||||
{FPGA_ID_XC7VX415T, FPGA_ID_MASK_NOVER, "XC7VX415T"},
|
||||
{FPGA_ID_XC7VX485T, FPGA_ID_MASK_NOVER, "XC7VX485T"},
|
||||
{FPGA_ID_XC7VX550T, FPGA_ID_MASK_NOVER, "XC7VX550T"},
|
||||
{FPGA_ID_XC7VX690T, FPGA_ID_MASK_NOVER, "XC7VX690T"},
|
||||
{FPGA_ID_XC7VX980T, FPGA_ID_MASK_NOVER, "XC7VX980T"},
|
||||
{FPGA_ID_XC7VX1140T, FPGA_ID_MASK_NOVER, "XC7VX1140T"},
|
||||
{FPGA_ID_XC7VH580T, FPGA_ID_MASK_NOVER, "XC7VH580T"},
|
||||
{FPGA_ID_XC7VH870T, FPGA_ID_MASK_NOVER, "XC7VH870T"},
|
||||
// Zynq 7000
|
||||
{FPGA_ID_XC7Z007, FPGA_ID_MASK_NOVER, "XC7Z007"},
|
||||
{FPGA_ID_XC7Z010, FPGA_ID_MASK_NOVER, "XC7Z010"},
|
||||
{FPGA_ID_XC7Z012, FPGA_ID_MASK_NOVER, "XC7Z012"},
|
||||
{FPGA_ID_XC7Z014, FPGA_ID_MASK_NOVER, "XC7Z014"},
|
||||
{FPGA_ID_XC7Z015, FPGA_ID_MASK_NOVER, "XC7Z015"},
|
||||
{FPGA_ID_XC7Z020, FPGA_ID_MASK_NOVER, "XC7Z020"},
|
||||
{FPGA_ID_XC7Z030, FPGA_ID_MASK_NOVER, "XC7Z030"},
|
||||
{FPGA_ID_XC7Z035, FPGA_ID_MASK_NOVER, "XC7Z035"},
|
||||
{FPGA_ID_XC7Z045, FPGA_ID_MASK_NOVER, "XC7Z045"},
|
||||
{FPGA_ID_XC7Z100, FPGA_ID_MASK_NOVER, "XC7Z100"},
|
||||
// Kintex UltraScale
|
||||
{FPGA_ID_XCKU025, FPGA_ID_MASK_NOVER, "XCKU025"},
|
||||
{FPGA_ID_XCKU035, FPGA_ID_MASK_NOVER, "XCKU035"},
|
||||
{FPGA_ID_XCKU040, FPGA_ID_MASK_NOVER, "XCKU040"},
|
||||
{FPGA_ID_XCKU060, FPGA_ID_MASK_NOVER, "XCKU060"},
|
||||
{FPGA_ID_XCKU085, FPGA_ID_MASK_NOVER, "XCKU085"},
|
||||
{FPGA_ID_XCKU095, FPGA_ID_MASK_NOVER, "XCKU095"},
|
||||
{FPGA_ID_XCKU115, FPGA_ID_MASK_NOVER, "XCKU115"},
|
||||
// Virtex UltraScale
|
||||
{FPGA_ID_XCVU065, FPGA_ID_MASK_NOVER, "XCVU065"},
|
||||
{FPGA_ID_XCVU080, FPGA_ID_MASK_NOVER, "XCVU080"},
|
||||
{FPGA_ID_XCVU095, FPGA_ID_MASK_NOVER, "XCVU095"},
|
||||
{FPGA_ID_XCVU125, FPGA_ID_MASK_NOVER, "XCVU125"},
|
||||
{FPGA_ID_XCVU160, FPGA_ID_MASK_NOVER, "XCVU160"},
|
||||
{FPGA_ID_XCVU190, FPGA_ID_MASK_NOVER, "XCVU190"},
|
||||
{FPGA_ID_XCVU440, FPGA_ID_MASK_NOVER, "XCVU440"},
|
||||
// Artix UltraScale+
|
||||
{FPGA_ID_XCAU10P, FPGA_ID_MASK_NOVER, "XCAU10P"},
|
||||
{FPGA_ID_XCAU15P, FPGA_ID_MASK_NOVER, "XCAU15P"},
|
||||
{FPGA_ID_XCAU20P, FPGA_ID_MASK_NOVER, "XCAU20P"},
|
||||
{FPGA_ID_XCAU25P, FPGA_ID_MASK_NOVER, "XCAU25P"},
|
||||
// Kintex UltraScale+
|
||||
{FPGA_ID_XCKU3P, FPGA_ID_MASK_NOVER, "XCKU3P"},
|
||||
{FPGA_ID_XCKU5P, FPGA_ID_MASK_NOVER, "XCKU5P"},
|
||||
{FPGA_ID_XCKU9P, FPGA_ID_MASK_NOVER, "XCKU9P"},
|
||||
{FPGA_ID_XCKU11P, FPGA_ID_MASK_NOVER, "XCKU11P"},
|
||||
{FPGA_ID_XCKU13P, FPGA_ID_MASK_NOVER, "XCKU13P"},
|
||||
{FPGA_ID_XCKU15P, FPGA_ID_MASK_NOVER, "XCKU15P"},
|
||||
// Virtex UltraScale+
|
||||
{FPGA_ID_XCVU3P, FPGA_ID_MASK_NOVER, "XCVU3P"},
|
||||
{FPGA_ID_XCVU5P, FPGA_ID_MASK_NOVER, "XCVU5P"},
|
||||
{FPGA_ID_XCVU7P, FPGA_ID_MASK_NOVER, "XCVU7P"},
|
||||
{FPGA_ID_XCVU9P, FPGA_ID_MASK_NOVER, "XCVU9P"},
|
||||
{FPGA_ID_XCVU11P, FPGA_ID_MASK_NOVER, "XCVU11P"},
|
||||
{FPGA_ID_XCVU13P, FPGA_ID_MASK_NOVER, "XCVU13P"},
|
||||
{FPGA_ID_XCVU19P, FPGA_ID_MASK_NOVER, "XCVU19P"},
|
||||
{FPGA_ID_XCVU23P, FPGA_ID_MASK_NOVER, "XCVU23P"},
|
||||
{FPGA_ID_XCVU27P, FPGA_ID_MASK_NOVER, "XCVU27P"},
|
||||
{FPGA_ID_XCVU29P, FPGA_ID_MASK_NOVER, "XCVU29P"},
|
||||
{FPGA_ID_XCVU31P, FPGA_ID_MASK_NOVER, "XCVU31P"},
|
||||
{FPGA_ID_XCVU33P, FPGA_ID_MASK_NOVER, "XCVU33P"},
|
||||
{FPGA_ID_XCVU35P, FPGA_ID_MASK_NOVER, "XCVU35P"},
|
||||
{FPGA_ID_XCVU37P, FPGA_ID_MASK_NOVER, "XCVU37P"},
|
||||
{FPGA_ID_XCVU45P, FPGA_ID_MASK_NOVER, "XCVU45P"},
|
||||
{FPGA_ID_XCVU47P, FPGA_ID_MASK_NOVER, "XCVU47P"},
|
||||
{FPGA_ID_XCVU57P, FPGA_ID_MASK_NOVER, "XCVU57P"},
|
||||
// Zynq UltraScale+
|
||||
{FPGA_ID_XCZU1, FPGA_ID_MASK_NOVER, "XCZU1"},
|
||||
{FPGA_ID_XCZU2, FPGA_ID_MASK_NOVER, "XCZU2"},
|
||||
{FPGA_ID_XCZU3, FPGA_ID_MASK_NOVER, "XCZU3"},
|
||||
{FPGA_ID_XCZU4, FPGA_ID_MASK_NOVER, "XCZU4"},
|
||||
{FPGA_ID_XCZU5, FPGA_ID_MASK_NOVER, "XCZU5"},
|
||||
{FPGA_ID_XCZU6, FPGA_ID_MASK_NOVER, "XCZU6"},
|
||||
{FPGA_ID_XCZU7, FPGA_ID_MASK_NOVER, "XCZU7"},
|
||||
{FPGA_ID_XCZU9, FPGA_ID_MASK_NOVER, "XCZU9"},
|
||||
{FPGA_ID_XCZU11, FPGA_ID_MASK_NOVER, "XCZU11"},
|
||||
{FPGA_ID_XCZU15, FPGA_ID_MASK_NOVER, "XCZU15"},
|
||||
{FPGA_ID_XCZU17, FPGA_ID_MASK_NOVER, "XCZU17"},
|
||||
{FPGA_ID_XCZU19, FPGA_ID_MASK_NOVER, "XCZU19"},
|
||||
{FPGA_ID_XCZU21, FPGA_ID_MASK_NOVER, "XCZU21"},
|
||||
{FPGA_ID_XCZU25, FPGA_ID_MASK_NOVER, "XCZU25"},
|
||||
{FPGA_ID_XCZU27, FPGA_ID_MASK_NOVER, "XCZU27"},
|
||||
{FPGA_ID_XCZU28, FPGA_ID_MASK_NOVER, "XCZU28"},
|
||||
{FPGA_ID_XCZU29, FPGA_ID_MASK_NOVER, "XCZU29"},
|
||||
{FPGA_ID_XCZU39, FPGA_ID_MASK_NOVER, "XCZU39"},
|
||||
{FPGA_ID_XCZU43, FPGA_ID_MASK_NOVER, "XCZU43"},
|
||||
{FPGA_ID_XCZU46, FPGA_ID_MASK_NOVER, "XCZU46"},
|
||||
{FPGA_ID_XCZU47, FPGA_ID_MASK_NOVER, "XCZU47"},
|
||||
{FPGA_ID_XCZU48, FPGA_ID_MASK_NOVER, "XCZU48"},
|
||||
{FPGA_ID_XCZU49, FPGA_ID_MASK_NOVER, "XCZU49"},
|
||||
{FPGA_ID_XCZU65, FPGA_ID_MASK_NOVER, "XCZU65"},
|
||||
{FPGA_ID_XCZU67, FPGA_ID_MASK_NOVER, "XCZU67"},
|
||||
// Kria SoM (Zynq UltraScale+)
|
||||
{FPGA_ID_XCK26, FPGA_ID_MASK_NOVER, "XCK26"},
|
||||
// Alveo (Virtex UltraScale+)
|
||||
{FPGA_ID_XCU26_XCUX35, FPGA_ID_MASK_NOVER, "XCU26_XCUX35"},
|
||||
{FPGA_ID_XCU50_XCU55N, FPGA_ID_MASK_NOVER, "XCU50_XCU55N"},
|
||||
{FPGA_ID_XCU200, FPGA_ID_MASK_NOVER, "XCU200"},
|
||||
{FPGA_ID_XCU250, FPGA_ID_MASK_NOVER, "XCU250"},
|
||||
{FPGA_ID_XCU280_XCU55C, FPGA_ID_MASK_NOVER, "XCU280_XCU55C"},
|
||||
// Versal AI Edge
|
||||
{FPGA_ID_XCVE1752, FPGA_ID_MASK_NOVER, "XCVE1752"},
|
||||
{FPGA_ID_XCVE2002, FPGA_ID_MASK_NOVER, "XCVE2002"},
|
||||
{FPGA_ID_XCVE2102, FPGA_ID_MASK_NOVER, "XCVE2102"},
|
||||
{FPGA_ID_XCVE2202, FPGA_ID_MASK_NOVER, "XCVE2202"},
|
||||
{FPGA_ID_XCVE2302, FPGA_ID_MASK_NOVER, "XCVE2302"},
|
||||
{FPGA_ID_XCVE2602, FPGA_ID_MASK_NOVER, "XCVE2602"},
|
||||
{FPGA_ID_XCVE2802, FPGA_ID_MASK_NOVER, "XCVE2802"},
|
||||
// Versal AI Core
|
||||
{FPGA_ID_XCVC1352, FPGA_ID_MASK_NOVER, "XCVC1352"},
|
||||
{FPGA_ID_XCVC1502, FPGA_ID_MASK_NOVER, "XCVC1502"},
|
||||
{FPGA_ID_XCVC1702, FPGA_ID_MASK_NOVER, "XCVC1702"},
|
||||
{FPGA_ID_XCVC1802, FPGA_ID_MASK_NOVER, "XCVC1802"},
|
||||
{FPGA_ID_XCVC1902, FPGA_ID_MASK_NOVER, "XCVC1902"},
|
||||
{FPGA_ID_XCVC2602, FPGA_ID_MASK_NOVER, "XCVC2602"},
|
||||
{FPGA_ID_XCVC2802, FPGA_ID_MASK_NOVER, "XCVC2802"},
|
||||
// Versal Prime
|
||||
{FPGA_ID_XCVM1102, FPGA_ID_MASK_NOVER, "XCVM1102"},
|
||||
{FPGA_ID_XCVM1302, FPGA_ID_MASK_NOVER, "XCVM1302"},
|
||||
{FPGA_ID_XCVM1402, FPGA_ID_MASK_NOVER, "XCVM1402"},
|
||||
{FPGA_ID_XCVM1502, FPGA_ID_MASK_NOVER, "XCVM1502"},
|
||||
{FPGA_ID_XCVM1802, FPGA_ID_MASK_NOVER, "XCVM1802"},
|
||||
{FPGA_ID_XCVM2202, FPGA_ID_MASK_NOVER, "XCVM2202"},
|
||||
{FPGA_ID_XCVM2302, FPGA_ID_MASK_NOVER, "XCVM2302"},
|
||||
{FPGA_ID_XCVM2502, FPGA_ID_MASK_NOVER, "XCVM2502"},
|
||||
{FPGA_ID_XCVM2902, FPGA_ID_MASK_NOVER, "XCVM2902"},
|
||||
// Versal Premium
|
||||
{FPGA_ID_XCVP1002, FPGA_ID_MASK_NOVER, "XCVP1002"},
|
||||
{FPGA_ID_XCVP1052, FPGA_ID_MASK_NOVER, "XCVP1052"},
|
||||
{FPGA_ID_XCVP1102, FPGA_ID_MASK_NOVER, "XCVP1102"},
|
||||
{FPGA_ID_XCVP1202, FPGA_ID_MASK_NOVER, "XCVP1202"},
|
||||
{FPGA_ID_XCVP1402, FPGA_ID_MASK_NOVER, "XCVP1402"},
|
||||
{FPGA_ID_XCVP1502, FPGA_ID_MASK_NOVER, "XCVP1502"},
|
||||
{FPGA_ID_XCVP1552, FPGA_ID_MASK_NOVER, "XCVP1552"},
|
||||
{FPGA_ID_XCVP1702, FPGA_ID_MASK_NOVER, "XCVP1702"},
|
||||
{FPGA_ID_XCVP1802, FPGA_ID_MASK_NOVER, "XCVP1802"},
|
||||
{FPGA_ID_XCVP2502, FPGA_ID_MASK_NOVER, "XCVP2502"},
|
||||
{FPGA_ID_XCVP2802, FPGA_ID_MASK_NOVER, "XCVP2802"},
|
||||
|
||||
// Intel
|
||||
// Stratix 10
|
||||
{FPGA_ID_1SG10MH_U1, FPGA_ID_MASK_FULL, "1SG10MH_U1"},
|
||||
{FPGA_ID_1SG10MH_U2, FPGA_ID_MASK_FULL, "1SG10MH_U2"},
|
||||
{FPGA_ID_1SG040H, FPGA_ID_MASK_FULL, "1SG040H"},
|
||||
{FPGA_ID_1SG040H_NL, FPGA_ID_MASK_FULL, "1SG040H(NL)"},
|
||||
{FPGA_ID_1SG065H, FPGA_ID_MASK_FULL, "1SG065H"},
|
||||
{FPGA_ID_1SG065H_NL, FPGA_ID_MASK_FULL, "1SG065H(NL)"},
|
||||
{FPGA_ID_1SG085H, FPGA_ID_MASK_FULL, "1SG085H"},
|
||||
{FPGA_ID_1SG110H, FPGA_ID_MASK_FULL, "1SG110H"},
|
||||
{FPGA_ID_1SG110H_NL, FPGA_ID_MASK_FULL, "1SG110H(NL)"},
|
||||
{FPGA_ID_1SG165H, FPGA_ID_MASK_FULL, "1SG165H"},
|
||||
{FPGA_ID_1SG166H, FPGA_ID_MASK_FULL, "1SG166H"},
|
||||
{FPGA_ID_1SG166H_NL, FPGA_ID_MASK_FULL, "1SG166H(NL)"},
|
||||
{FPGA_ID_1SG210H, FPGA_ID_MASK_FULL, "1SG210H"},
|
||||
{FPGA_ID_1SG210H_ES1, FPGA_ID_MASK_FULL, "1SG210H(ES1)"},
|
||||
{FPGA_ID_1SG211H, FPGA_ID_MASK_FULL, "1SG211H"},
|
||||
{FPGA_ID_1SG250L, FPGA_ID_MASK_FULL, "1SG250L"},
|
||||
{FPGA_ID_1SG250H, FPGA_ID_MASK_FULL, "1SG250H"},
|
||||
{FPGA_ID_1SG280L, FPGA_ID_MASK_FULL, "1SG280L"},
|
||||
{FPGA_ID_1SG280L_NL, FPGA_ID_MASK_FULL, "1SG280L(NL)"},
|
||||
{FPGA_ID_1SG280L_ES1, FPGA_ID_MASK_FULL, "1SG280L(ES1)"},
|
||||
{FPGA_ID_1SG280L_ES2, FPGA_ID_MASK_FULL, "1SG280L(ES2)"},
|
||||
{FPGA_ID_1SG280L_ES3, FPGA_ID_MASK_FULL, "1SG280L(ES3)"},
|
||||
{FPGA_ID_1SG280H, FPGA_ID_MASK_FULL, "1SG280H"},
|
||||
{FPGA_ID_1SG280H_NL, FPGA_ID_MASK_FULL, "1SG280H(NL)"},
|
||||
{FPGA_ID_1SG280H_ES1, FPGA_ID_MASK_FULL, "1SG280H(ES1)"},
|
||||
{FPGA_ID_1SG280H_ES2, FPGA_ID_MASK_FULL, "1SG280H(ES2)"},
|
||||
{FPGA_ID_1SG280H_ES3, FPGA_ID_MASK_FULL, "1SG280H(ES3)"},
|
||||
{FPGA_ID_1SX040H, FPGA_ID_MASK_FULL, "1SX040H"},
|
||||
{FPGA_ID_1SX065H, FPGA_ID_MASK_FULL, "1SX065H"},
|
||||
{FPGA_ID_1SX085H, FPGA_ID_MASK_FULL, "1SX085H"},
|
||||
{FPGA_ID_1SX110H, FPGA_ID_MASK_FULL, "1SX110H"},
|
||||
{FPGA_ID_1SX165H, FPGA_ID_MASK_FULL, "1SX165H"},
|
||||
{FPGA_ID_1SX210H, FPGA_ID_MASK_FULL, "1SX210H"},
|
||||
{FPGA_ID_1SX250L, FPGA_ID_MASK_FULL, "1SX250L"},
|
||||
{FPGA_ID_1SX250H, FPGA_ID_MASK_FULL, "1SX250H"},
|
||||
{FPGA_ID_1SX280L, FPGA_ID_MASK_FULL, "1SX280L"},
|
||||
{FPGA_ID_1SX280L_ES1, FPGA_ID_MASK_FULL, "1SX280L(ES1)"},
|
||||
{FPGA_ID_1SX280L_ES2, FPGA_ID_MASK_FULL, "1SX280L(ES2)"},
|
||||
{FPGA_ID_1SX280H, FPGA_ID_MASK_FULL, "1SX280H"},
|
||||
{FPGA_ID_1SX280H_ES1, FPGA_ID_MASK_FULL, "1SX280H(ES1)"},
|
||||
{FPGA_ID_1SX280H_ES2, FPGA_ID_MASK_FULL, "1SX280H(ES2)"},
|
||||
{FPGA_ID_1ST040E, FPGA_ID_MASK_FULL, "1ST040E"},
|
||||
{FPGA_ID_1ST040E_NL, FPGA_ID_MASK_FULL, "1ST040E(NL)"},
|
||||
{FPGA_ID_1ST085E, FPGA_ID_MASK_FULL, "1ST085E"},
|
||||
{FPGA_ID_1ST110E, FPGA_ID_MASK_FULL, "1ST110E"},
|
||||
{FPGA_ID_1ST110E_NL, FPGA_ID_MASK_FULL, "1ST110E(NL)"},
|
||||
{FPGA_ID_1ST165E, FPGA_ID_MASK_FULL, "1ST165E"},
|
||||
{FPGA_ID_1ST210E, FPGA_ID_MASK_FULL, "1ST210E"},
|
||||
{FPGA_ID_1ST210E_ES1, FPGA_ID_MASK_FULL, "1ST210E(ES1)"},
|
||||
{FPGA_ID_1ST250E, FPGA_ID_MASK_FULL, "1ST250E"},
|
||||
{FPGA_ID_1ST280E, FPGA_ID_MASK_FULL, "1ST280E"},
|
||||
{FPGA_ID_1ST280E_ES1, FPGA_ID_MASK_FULL, "1ST280E(ES1)"},
|
||||
{FPGA_ID_1SM16BE, FPGA_ID_MASK_FULL, "1SM16BE"},
|
||||
{FPGA_ID_1SM16BE_ES1, FPGA_ID_MASK_FULL, "1SM16BE(ES1)"},
|
||||
{FPGA_ID_1SM16BH, FPGA_ID_MASK_FULL, "1SM16BH"},
|
||||
{FPGA_ID_1SM16BH_ES1, FPGA_ID_MASK_FULL, "1SM16BH(ES1)"},
|
||||
{FPGA_ID_1SM16CH, FPGA_ID_MASK_FULL, "1SM16CH"},
|
||||
{FPGA_ID_1SM16CH_ES1, FPGA_ID_MASK_FULL, "1SM16CH(ES1)"},
|
||||
{FPGA_ID_1SM21BE, FPGA_ID_MASK_FULL, "1SM21BE"},
|
||||
{FPGA_ID_1SM21BE_ES1, FPGA_ID_MASK_FULL, "1SM21BE(ES1)"},
|
||||
{FPGA_ID_1SM21BH, FPGA_ID_MASK_FULL, "1SM21BH"},
|
||||
{FPGA_ID_1SM21BH_ES1, FPGA_ID_MASK_FULL, "1SM21BH(ES1)"},
|
||||
{FPGA_ID_1SM21CH, FPGA_ID_MASK_FULL, "1SM21CH"},
|
||||
{FPGA_ID_1SM21CH_ES1, FPGA_ID_MASK_FULL, "1SM21CH(ES1)"},
|
||||
{FPGA_ID_1SD110P, FPGA_ID_MASK_FULL, "1SD110P"},
|
||||
{FPGA_ID_1SD110P_NL, FPGA_ID_MASK_FULL, "1SD110P(NL)"},
|
||||
{FPGA_ID_1SD21BP, FPGA_ID_MASK_FULL, "1SD21BP"},
|
||||
{FPGA_ID_1SD280P, FPGA_ID_MASK_FULL, "1SD280P"},
|
||||
// Agilex
|
||||
{FPGA_ID_AGFA006R16A, FPGA_ID_MASK_FULL, "AGFA006R16A"},
|
||||
{FPGA_ID_AGFA008R16A, FPGA_ID_MASK_FULL, "AGFA008R16A"},
|
||||
{FPGA_ID_AGFA012R24A, FPGA_ID_MASK_FULL, "AGFA012R24A"},
|
||||
{FPGA_ID_AGFA012R24B, FPGA_ID_MASK_FULL, "AGFA012R24B"},
|
||||
{FPGA_ID_AGFA014R24AR0, FPGA_ID_MASK_FULL, "AGFA014R24AR0"},
|
||||
{FPGA_ID_AGFA014R24A, FPGA_ID_MASK_FULL, "AGFA014R24A"},
|
||||
{FPGA_ID_AGFA014R24B, FPGA_ID_MASK_FULL, "AGFA014R24B"},
|
||||
{FPGA_ID_AGFA019R25A, FPGA_ID_MASK_FULL, "AGFA019R25A"},
|
||||
{FPGA_ID_AGFA022R24C, FPGA_ID_MASK_FULL, "AGFA022R24C"},
|
||||
{FPGA_ID_AGFA022R25A, FPGA_ID_MASK_FULL, "AGFA022R25A"},
|
||||
{FPGA_ID_AGFA022R31C, FPGA_ID_MASK_FULL, "AGFA022R31C"},
|
||||
{FPGA_ID_AGFA023R25AR0, FPGA_ID_MASK_FULL, "AGFA023R25AR0"},
|
||||
{FPGA_ID_AGFA023R25A, FPGA_ID_MASK_FULL, "AGFA023R25A"},
|
||||
{FPGA_ID_AGFA027R24CR0, FPGA_ID_MASK_FULL, "AGFA027R24CR0"},
|
||||
{FPGA_ID_AGFA027R24CR2, FPGA_ID_MASK_FULL, "AGFA027R24CR2"},
|
||||
{FPGA_ID_AGFA027R24C, FPGA_ID_MASK_FULL, "AGFA027R24C"},
|
||||
{FPGA_ID_AGFA027R25AR0, FPGA_ID_MASK_FULL, "AGFA027R25AR0"},
|
||||
{FPGA_ID_AGFA027R25A, FPGA_ID_MASK_FULL, "AGFA027R25A"},
|
||||
{FPGA_ID_AGFA027R31C, FPGA_ID_MASK_FULL, "AGFA027R31C"},
|
||||
{FPGA_ID_AGFB006R16A, FPGA_ID_MASK_FULL, "AGFB006R16A"},
|
||||
{FPGA_ID_AGFB008R16A, FPGA_ID_MASK_FULL, "AGFB008R16A"},
|
||||
{FPGA_ID_AGFB012R24A, FPGA_ID_MASK_FULL, "AGFB012R24A"},
|
||||
{FPGA_ID_AGFB012R24B, FPGA_ID_MASK_FULL, "AGFB012R24B"},
|
||||
{FPGA_ID_AGFB014R24AR0, FPGA_ID_MASK_FULL, "AGFB014R24AR0"},
|
||||
{FPGA_ID_AGFB014R24A, FPGA_ID_MASK_FULL, "AGFB014R24A"},
|
||||
{FPGA_ID_AGFB014R24B, FPGA_ID_MASK_FULL, "AGFB014R24B"},
|
||||
{FPGA_ID_AGFB019R25A, FPGA_ID_MASK_FULL, "AGFB019R25A"},
|
||||
{FPGA_ID_AGFB022R24C, FPGA_ID_MASK_FULL, "AGFB022R24C"},
|
||||
{FPGA_ID_AGFB022R25A, FPGA_ID_MASK_FULL, "AGFB022R25A"},
|
||||
{FPGA_ID_AGFB022R31C, FPGA_ID_MASK_FULL, "AGFB022R31C"},
|
||||
{FPGA_ID_AGFB023R25AR0, FPGA_ID_MASK_FULL, "AGFB023R25AR0"},
|
||||
{FPGA_ID_AGFB023R25A, FPGA_ID_MASK_FULL, "AGFB023R25A"},
|
||||
{FPGA_ID_AGFB027R24CR0, FPGA_ID_MASK_FULL, "AGFB027R24CR0"},
|
||||
{FPGA_ID_AGFB027R24CR2, FPGA_ID_MASK_FULL, "AGFB027R24CR2"},
|
||||
{FPGA_ID_AGFB027R24C, FPGA_ID_MASK_FULL, "AGFB027R24C"},
|
||||
{FPGA_ID_AGFB027R25AR0, FPGA_ID_MASK_FULL, "AGFB027R25AR0"},
|
||||
{FPGA_ID_AGFB027R25A, FPGA_ID_MASK_FULL, "AGFB027R25A"},
|
||||
{FPGA_ID_AGFB027R31C, FPGA_ID_MASK_FULL, "AGFB027R31C"},
|
||||
{FPGA_ID_AGFC019R25A, FPGA_ID_MASK_FULL, "AGFC019R25A"},
|
||||
{FPGA_ID_AGFC023R25AR0, FPGA_ID_MASK_FULL, "AGFC023R25AR0"},
|
||||
{FPGA_ID_AGFC023R25A, FPGA_ID_MASK_FULL, "AGFC023R25A"},
|
||||
{FPGA_ID_AGFD019R25A, FPGA_ID_MASK_FULL, "AGFD019R25A"},
|
||||
{FPGA_ID_AGFD023R25AR0, FPGA_ID_MASK_FULL, "AGFD023R25AR0"},
|
||||
{FPGA_ID_AGFD023R25A, FPGA_ID_MASK_FULL, "AGFD023R25A"},
|
||||
{FPGA_ID_AGIB022R29A, FPGA_ID_MASK_FULL, "AGIB022R29A"},
|
||||
{FPGA_ID_AGIB022R31B, FPGA_ID_MASK_FULL, "AGIB022R31B"},
|
||||
{FPGA_ID_AGIB027R29AR0, FPGA_ID_MASK_FULL, "AGIB027R29AR0"},
|
||||
{FPGA_ID_AGIB027R29AR1, FPGA_ID_MASK_FULL, "AGIB027R29AR1"},
|
||||
{FPGA_ID_AGIB027R29AR3, FPGA_ID_MASK_FULL, "AGIB027R29AR3"},
|
||||
{FPGA_ID_AGIB027R29A, FPGA_ID_MASK_FULL, "AGIB027R29A"},
|
||||
{FPGA_ID_AGIB027R31BR0, FPGA_ID_MASK_FULL, "AGIB027R31BR0"},
|
||||
{FPGA_ID_AGIB027R31B, FPGA_ID_MASK_FULL, "AGIB027R31B"},
|
||||
|
||||
// end of list
|
||||
{0, 0, ""}
|
||||
};
|
||||
|
||||
const char *get_fpga_part(int id)
|
||||
{
|
||||
const struct fpga_id *ptr = fpga_id_list;
|
||||
|
||||
while (ptr->id && ((ptr->id ^ id) & ptr->mask) != 0) {
|
||||
ptr++;
|
||||
}
|
||||
|
||||
return ptr->part;
|
||||
}
|
||||
312
src/pyrite/utils/fpga_id.h
Normal file
312
src/pyrite/utils/fpga_id.h
Normal file
@@ -0,0 +1,312 @@
|
||||
/* SPDX-License-Identifier: GPL */
|
||||
/*
|
||||
|
||||
Copyright (c) 2026 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
#ifndef FPGA_ID_H
|
||||
#define FPGA_ID_H
|
||||
|
||||
#define FPGA_ID_MASK_FULL 0xFFFFFFFF
|
||||
#define FPGA_ID_MASK_VER 0xF0000000
|
||||
#define FPGA_ID_MASK_PART 0x0FFFF000
|
||||
#define FPGA_ID_MASK_MFR 0x00000FFE
|
||||
#define FPGA_ID_MASK_NOVER 0x0FFFFFFF
|
||||
|
||||
// Xilinx
|
||||
// Spartan 7
|
||||
#define FPGA_ID_XC7S6 0x3622093
|
||||
#define FPGA_ID_XC7S15 0x3620093
|
||||
#define FPGA_ID_XC7S25 0x37C4093
|
||||
#define FPGA_ID_XC7S50 0x362F093
|
||||
#define FPGA_ID_XC7S75 0x37C8093
|
||||
#define FPGA_ID_XC7S100 0x37C7093
|
||||
// Artix 7
|
||||
#define FPGA_ID_XC7A15T 0x362D093
|
||||
#define FPGA_ID_XC7A35T 0x362D093
|
||||
#define FPGA_ID_XC7A50T 0x362C093
|
||||
#define FPGA_ID_XC7A75T 0x3632093
|
||||
#define FPGA_ID_XC7A100T 0x3631093
|
||||
#define FPGA_ID_XC7A200T 0x3636093
|
||||
// Kintex 7
|
||||
#define FPGA_ID_XC7K70T 0x3647093
|
||||
#define FPGA_ID_XC7K160T 0x364C093
|
||||
#define FPGA_ID_XC7K325T 0x3651093
|
||||
#define FPGA_ID_XC7K355T 0x3747093
|
||||
#define FPGA_ID_XC7K410T 0x3656093
|
||||
#define FPGA_ID_XC7K420T 0x3752093
|
||||
#define FPGA_ID_XC7K480T 0x3751093
|
||||
// Virtex 7
|
||||
#define FPGA_ID_XC7V585T 0x3671093
|
||||
#define FPGA_ID_XC7V2000T 0x36B3093
|
||||
#define FPGA_ID_XC7VX330T 0x3667093
|
||||
#define FPGA_ID_XC7VX415T 0x3682093
|
||||
#define FPGA_ID_XC7VX485T 0x3687093
|
||||
#define FPGA_ID_XC7VX550T 0x3692093
|
||||
#define FPGA_ID_XC7VX690T 0x3691093
|
||||
#define FPGA_ID_XC7VX980T 0x3696093
|
||||
#define FPGA_ID_XC7VX1140T 0x36D5093
|
||||
#define FPGA_ID_XC7VH580T 0x36D9093
|
||||
#define FPGA_ID_XC7VH870T 0x36DB093
|
||||
// Zynq 7000
|
||||
#define FPGA_ID_XC7Z007 0x3723093
|
||||
#define FPGA_ID_XC7Z010 0x3722093
|
||||
#define FPGA_ID_XC7Z012 0x373C093
|
||||
#define FPGA_ID_XC7Z014 0x3728093
|
||||
#define FPGA_ID_XC7Z015 0x373B093
|
||||
#define FPGA_ID_XC7Z020 0x3727093
|
||||
#define FPGA_ID_XC7Z030 0x372C093
|
||||
#define FPGA_ID_XC7Z035 0x3732093
|
||||
#define FPGA_ID_XC7Z045 0x3731093
|
||||
#define FPGA_ID_XC7Z100 0x3736093
|
||||
// Kintex UltraScale
|
||||
#define FPGA_ID_XCKU025 0x3824093
|
||||
#define FPGA_ID_XCKU035 0x3823093
|
||||
#define FPGA_ID_XCKU040 0x3822093
|
||||
#define FPGA_ID_XCKU060 0x3919093
|
||||
#define FPGA_ID_XCKU085 0x380F093
|
||||
#define FPGA_ID_XCKU095 0x3844093
|
||||
#define FPGA_ID_XCKU115 0x390D093
|
||||
// Virtex UltraScale
|
||||
#define FPGA_ID_XCVU065 0x3939093
|
||||
#define FPGA_ID_XCVU080 0x3843093
|
||||
#define FPGA_ID_XCVU095 0x3842093
|
||||
#define FPGA_ID_XCVU125 0x392D093
|
||||
#define FPGA_ID_XCVU160 0x3933093
|
||||
#define FPGA_ID_XCVU190 0x3931093
|
||||
#define FPGA_ID_XCVU440 0x396D093
|
||||
// Artix UltraScale+
|
||||
#define FPGA_ID_XCAU10P 0x4AC5093
|
||||
#define FPGA_ID_XCAU15P 0x4AC4093
|
||||
#define FPGA_ID_XCAU20P 0x4A65093
|
||||
#define FPGA_ID_XCAU25P 0x4A64093
|
||||
// Kintex UltraScale+
|
||||
#define FPGA_ID_XCKU3P 0x4A63093
|
||||
#define FPGA_ID_XCKU5P 0x4A62093
|
||||
#define FPGA_ID_XCKU9P 0x484A093
|
||||
#define FPGA_ID_XCKU11P 0x4A4E093
|
||||
#define FPGA_ID_XCKU13P 0x4A52093
|
||||
#define FPGA_ID_XCKU15P 0x4A56093
|
||||
#define FPGA_ID_XCKU19P 0x4ACF093
|
||||
// Virtex UltraScale+
|
||||
#define FPGA_ID_XCVU3P 0x4B39093
|
||||
#define FPGA_ID_XCVU5P 0x4B2B093
|
||||
#define FPGA_ID_XCVU7P 0x4B29093
|
||||
#define FPGA_ID_XCVU9P 0x4B31093
|
||||
#define FPGA_ID_XCVU11P 0x4B49093
|
||||
#define FPGA_ID_XCVU13P 0x4B51093
|
||||
#define FPGA_ID_XCVU19P 0x4BA1093
|
||||
#define FPGA_ID_XCVU23P 0x4ACE093
|
||||
#define FPGA_ID_XCVU27P 0x4B43093
|
||||
#define FPGA_ID_XCVU29P 0x4B41093
|
||||
#define FPGA_ID_XCVU31P 0x4B6B093
|
||||
#define FPGA_ID_XCVU33P 0x4B69093
|
||||
#define FPGA_ID_XCVU35P 0x4B71093
|
||||
#define FPGA_ID_XCVU37P 0x4B79093
|
||||
#define FPGA_ID_XCVU45P 0x4B73093
|
||||
#define FPGA_ID_XCVU47P 0x4B7B093
|
||||
#define FPGA_ID_XCVU57P 0x4B61093
|
||||
// Zynq UltraScale+
|
||||
#define FPGA_ID_XCZU1 0x4688093
|
||||
#define FPGA_ID_XCZU2 0x4711093
|
||||
#define FPGA_ID_XCZU3 0x4710093
|
||||
#define FPGA_ID_XCZU4 0x4721093
|
||||
#define FPGA_ID_XCZU5 0x4720093
|
||||
#define FPGA_ID_XCZU6 0x4739093
|
||||
#define FPGA_ID_XCZU7 0x4730093
|
||||
#define FPGA_ID_XCZU9 0x4738093
|
||||
#define FPGA_ID_XCZU11 0x4740093
|
||||
#define FPGA_ID_XCZU15 0x4750093
|
||||
#define FPGA_ID_XCZU17 0x4759093
|
||||
#define FPGA_ID_XCZU19 0x4758093
|
||||
#define FPGA_ID_XCZU21 0x47E1093
|
||||
#define FPGA_ID_XCZU25 0x47E5093
|
||||
#define FPGA_ID_XCZU27 0x47E4093
|
||||
#define FPGA_ID_XCZU28 0x47E0093
|
||||
#define FPGA_ID_XCZU29 0x47E2093
|
||||
#define FPGA_ID_XCZU39 0x47E6093
|
||||
#define FPGA_ID_XCZU43 0x47FD093
|
||||
#define FPGA_ID_XCZU46 0x47F8093
|
||||
#define FPGA_ID_XCZU47 0x47FF093
|
||||
#define FPGA_ID_XCZU48 0x47FB093
|
||||
#define FPGA_ID_XCZU49 0x47FE093
|
||||
#define FPGA_ID_XCZU65 0x46D1093
|
||||
#define FPGA_ID_XCZU67 0x46D0093
|
||||
// Kria SoM (Zynq UltraScale+)
|
||||
#define FPGA_ID_XCK26 0x4A49093
|
||||
// Alveo (Virtex UltraScale+)
|
||||
#define FPGA_ID_XCU26_XCUX35 0x4AD5093
|
||||
#define FPGA_ID_XCU50_XCU55N 0x4B77093
|
||||
#define FPGA_ID_XCU200 0x4B37093
|
||||
#define FPGA_ID_XCU250 0x4B57093
|
||||
#define FPGA_ID_XCU280_XCU55C 0x4B7D093
|
||||
// Versal AI Edge
|
||||
#define FPGA_ID_XCVE1752 0x4C9A093
|
||||
#define FPGA_ID_XCVE2002 0x4CC1093
|
||||
#define FPGA_ID_XCVE2102 0x4CC0093
|
||||
#define FPGA_ID_XCVE2202 0x4CC9093
|
||||
#define FPGA_ID_XCVE2302 0x4CC8093
|
||||
#define FPGA_ID_XCVE2602 0x4CD3093
|
||||
#define FPGA_ID_XCVE2802 0x4CD1093
|
||||
// Versal AI Core
|
||||
#define FPGA_ID_XCVC1352 0x4C93093
|
||||
#define FPGA_ID_XCVC1502 0x4C9B093
|
||||
#define FPGA_ID_XCVC1702 0x4C98093
|
||||
#define FPGA_ID_XCVC1802 0x4CA9093
|
||||
#define FPGA_ID_XCVC1902 0x4CA8093
|
||||
#define FPGA_ID_XCVC2602 0x4CD2093
|
||||
#define FPGA_ID_XCVC2802 0x4CD0093
|
||||
// Versal Prime
|
||||
#define FPGA_ID_XCVM1102 0x4CCA093
|
||||
#define FPGA_ID_XCVM1302 0x4C09093
|
||||
#define FPGA_ID_XCVM1402 0x4C08093
|
||||
#define FPGA_ID_XCVM1502 0x4C99093
|
||||
#define FPGA_ID_XCVM1802 0x4CAA093
|
||||
#define FPGA_ID_XCVM2202 0x4CD4093
|
||||
#define FPGA_ID_XCVM2302 0x4C24093
|
||||
#define FPGA_ID_XCVM2502 0x4D01093
|
||||
#define FPGA_ID_XCVM2902 0x4C23093
|
||||
// Versal Premium
|
||||
#define FPGA_ID_XCVP1002 0x4C1B093
|
||||
#define FPGA_ID_XCVP1052 0x4C18093
|
||||
#define FPGA_ID_XCVP1102 0x4C22093
|
||||
#define FPGA_ID_XCVP1202 0x4D00093
|
||||
#define FPGA_ID_XCVP1402 0x4C20093
|
||||
#define FPGA_ID_XCVP1502 0x4D08093
|
||||
#define FPGA_ID_XCVP1552 0x4D34093
|
||||
#define FPGA_ID_XCVP1702 0x4D10093
|
||||
#define FPGA_ID_XCVP1802 0x4D14093
|
||||
#define FPGA_ID_XCVP2502 0x4D1C093
|
||||
#define FPGA_ID_XCVP2802 0x4D20093
|
||||
|
||||
// Intel
|
||||
// Stratix 10
|
||||
#define FPGA_ID_1SG10MH_U1 0x032270DD
|
||||
#define FPGA_ID_1SG10MH_U2 0x0322F0DD
|
||||
#define FPGA_ID_1SG040H 0x032200DD
|
||||
#define FPGA_ID_1SG040H_NL 0x032A00DD
|
||||
#define FPGA_ID_1SG065H 0x032210DD
|
||||
#define FPGA_ID_1SG065H_NL 0x032A10DD
|
||||
#define FPGA_ID_1SG085H 0x132220DD
|
||||
#define FPGA_ID_1SG110H 0x032220DD
|
||||
#define FPGA_ID_1SG110H_NL 0x032A20DD
|
||||
#define FPGA_ID_1SG165H 0xF32250DD
|
||||
#define FPGA_ID_1SG166H 0x532240DD
|
||||
#define FPGA_ID_1SG166H_NL 0x5322C0DD
|
||||
#define FPGA_ID_1SG210H 0xE32250DD
|
||||
#define FPGA_ID_1SG210H_ES1 0x232250DD
|
||||
#define FPGA_ID_1SG211H 0x432240DD
|
||||
#define FPGA_ID_1SG250L 0xD32150DD
|
||||
#define FPGA_ID_1SG250H 0xD32250DD
|
||||
#define FPGA_ID_1SG280L 0xC32150DD
|
||||
#define FPGA_ID_1SG280L_NL 0xC32950DD
|
||||
#define FPGA_ID_1SG280L_ES1 0x032150DD
|
||||
#define FPGA_ID_1SG280L_ES2 0x032250DD
|
||||
#define FPGA_ID_1SG280L_ES3 0xC32150DD
|
||||
#define FPGA_ID_1SG280H 0xC32250DD
|
||||
#define FPGA_ID_1SG280H_NL 0xC32A50DD
|
||||
#define FPGA_ID_1SG280H_ES1 0x032250DD
|
||||
#define FPGA_ID_1SG280H_ES2 0xC32150DD
|
||||
#define FPGA_ID_1SG280H_ES3 0xC32250DD
|
||||
#define FPGA_ID_1SX040H 0x032280DD
|
||||
#define FPGA_ID_1SX065H 0x032290DD
|
||||
#define FPGA_ID_1SX085H 0x1322A0DD
|
||||
#define FPGA_ID_1SX110H 0x0322A0DD
|
||||
#define FPGA_ID_1SX165H 0xF322D0DD
|
||||
#define FPGA_ID_1SX210H 0xE322D0DD
|
||||
#define FPGA_ID_1SX250L 0xD321D0DD
|
||||
#define FPGA_ID_1SX250H 0xD322D0DD
|
||||
#define FPGA_ID_1SX280L 0xC321D0DD
|
||||
#define FPGA_ID_1SX280L_ES1 0x4321D0DD
|
||||
#define FPGA_ID_1SX280L_ES2 0x4321D0DD
|
||||
#define FPGA_ID_1SX280H 0xC322D0DD
|
||||
#define FPGA_ID_1SX280H_ES1 0x4322D0DD
|
||||
#define FPGA_ID_1SX280H_ES2 0xC322D0DD
|
||||
#define FPGA_ID_1ST040E 0x032380DD
|
||||
#define FPGA_ID_1ST040E_NL 0x032B00DD
|
||||
#define FPGA_ID_1ST085E 0x1323A0DD
|
||||
#define FPGA_ID_1ST110E 0x0323A0DD
|
||||
#define FPGA_ID_1ST110E_NL 0x032B20DD
|
||||
#define FPGA_ID_1ST165E 0x532340DD
|
||||
#define FPGA_ID_1ST210E 0x432340DD
|
||||
#define FPGA_ID_1ST210E_ES1 0x032340DD
|
||||
#define FPGA_ID_1ST250E 0xD323D0DD
|
||||
#define FPGA_ID_1ST280E 0xC323D0DD
|
||||
#define FPGA_ID_1ST280E_ES1 0xC323D0DD
|
||||
#define FPGA_ID_1SM16BE 0x732BC0DD
|
||||
#define FPGA_ID_1SM16BE_ES1 0x732BC0DD
|
||||
#define FPGA_ID_1SM16BH 0x732AC0DD
|
||||
#define FPGA_ID_1SM16BH_ES1 0x332AC0DD
|
||||
#define FPGA_ID_1SM16CH 0x532AC0DD
|
||||
#define FPGA_ID_1SM16CH_ES1 0x132AC0DD
|
||||
#define FPGA_ID_1SM21BE 0x632BC0DD
|
||||
#define FPGA_ID_1SM21BE_ES1 0x632BC0DD
|
||||
#define FPGA_ID_1SM21BH 0x632AC0DD
|
||||
#define FPGA_ID_1SM21BH_ES1 0x232AC0DD
|
||||
#define FPGA_ID_1SM21CH 0x432AC0DD
|
||||
#define FPGA_ID_1SM21CH_ES1 0x032AC0DD
|
||||
#define FPGA_ID_1SD110P 0x0324A0DD
|
||||
#define FPGA_ID_1SD110P_NL 0x032C20DD
|
||||
#define FPGA_ID_1SD21BP 0x632CC0DD
|
||||
#define FPGA_ID_1SD280P 0xC32450DD
|
||||
// Agilex
|
||||
#define FPGA_ID_AGFA006R16A 0x134310DD
|
||||
#define FPGA_ID_AGFA008R16A 0x034310DD
|
||||
#define FPGA_ID_AGFA012R24A 0x534120DD
|
||||
#define FPGA_ID_AGFA012R24B 0xD34120DD
|
||||
#define FPGA_ID_AGFA014R24AR0 0x034120DD
|
||||
#define FPGA_ID_AGFA014R24A 0x434120DD
|
||||
#define FPGA_ID_AGFA014R24B 0xC34120DD
|
||||
#define FPGA_ID_AGFA019R25A 0x134150DD
|
||||
#define FPGA_ID_AGFA022R24C 0x134330DD
|
||||
#define FPGA_ID_AGFA022R25A 0x134130DD
|
||||
#define FPGA_ID_AGFA022R31C 0x134330DD
|
||||
#define FPGA_ID_AGFA023R25AR0 0x034150DD
|
||||
#define FPGA_ID_AGFA023R25A 0x034150DD
|
||||
#define FPGA_ID_AGFA027R24CR0 0x034330DD
|
||||
#define FPGA_ID_AGFA027R24CR2 0x034330DD
|
||||
#define FPGA_ID_AGFA027R24C 0x034330DD
|
||||
#define FPGA_ID_AGFA027R25AR0 0x034130DD
|
||||
#define FPGA_ID_AGFA027R25A 0x034130DD
|
||||
#define FPGA_ID_AGFA027R31C 0x034330DD
|
||||
#define FPGA_ID_AGFB006R16A 0x134390DD
|
||||
#define FPGA_ID_AGFB008R16A 0x034390DD
|
||||
#define FPGA_ID_AGFB012R24A 0x5341A0DD
|
||||
#define FPGA_ID_AGFB012R24B 0xD341A0DD
|
||||
#define FPGA_ID_AGFB014R24AR0 0x0341A0DD
|
||||
#define FPGA_ID_AGFB014R24A 0x4341A0DD
|
||||
#define FPGA_ID_AGFB014R24B 0xC341A0DD
|
||||
#define FPGA_ID_AGFB019R25A 0x1341D0DD
|
||||
#define FPGA_ID_AGFB022R24C 0x1343B0DD
|
||||
#define FPGA_ID_AGFB022R25A 0x1341B0DD
|
||||
#define FPGA_ID_AGFB022R31C 0x1343B0DD
|
||||
#define FPGA_ID_AGFB023R25AR0 0x0341D0DD
|
||||
#define FPGA_ID_AGFB023R25A 0x0341D0DD
|
||||
#define FPGA_ID_AGFB027R24CR0 0x0343B0DD
|
||||
#define FPGA_ID_AGFB027R24CR2 0x0343B0DD
|
||||
#define FPGA_ID_AGFB027R24C 0x0343B0DD
|
||||
#define FPGA_ID_AGFB027R25AR0 0x0341B0DD
|
||||
#define FPGA_ID_AGFB027R25A 0x0341B0DD
|
||||
#define FPGA_ID_AGFB027R31C 0x0343B0DD
|
||||
#define FPGA_ID_AGFC019R25A 0x334150DD
|
||||
#define FPGA_ID_AGFC023R25AR0 0x234150DD
|
||||
#define FPGA_ID_AGFC023R25A 0x234150DD
|
||||
#define FPGA_ID_AGFD019R25A 0x3341D0DD
|
||||
#define FPGA_ID_AGFD023R25AR0 0x2341D0DD
|
||||
#define FPGA_ID_AGFD023R25A 0x2341D0DD
|
||||
#define FPGA_ID_AGIB022R29A 0x134BB0DD
|
||||
#define FPGA_ID_AGIB022R31B 0x1343B0DD
|
||||
#define FPGA_ID_AGIB027R29AR0 0x034BB0DD
|
||||
#define FPGA_ID_AGIB027R29AR1 0x034BB0DD
|
||||
#define FPGA_ID_AGIB027R29AR3 0x034BB0DD
|
||||
#define FPGA_ID_AGIB027R29A 0x034BB0DD
|
||||
#define FPGA_ID_AGIB027R31BR0 0x0343B0DD
|
||||
#define FPGA_ID_AGIB027R31B 0x0343B0DD
|
||||
|
||||
const char *get_fpga_part(int id);
|
||||
|
||||
#endif /* FPGA_ID_H */
|
||||
1491
src/pyrite/utils/pyrite.c
Normal file
1491
src/pyrite/utils/pyrite.c
Normal file
File diff suppressed because it is too large
Load Diff
108
src/pyrite/utils/reg_block.c
Normal file
108
src/pyrite/utils/reg_block.c
Normal file
@@ -0,0 +1,108 @@
|
||||
// SPDX-License-Identifier: GPL
|
||||
/*
|
||||
|
||||
Copyright (c) 2026 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
#include "reg_block.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct reg_block *enumerate_reg_block_list(struct reg_if *regs, size_t base, size_t offset, size_t size)
|
||||
{
|
||||
int max_count = 8;
|
||||
struct reg_block *reg_block_list = calloc(max_count, sizeof(struct reg_block));
|
||||
int count = 0;
|
||||
|
||||
size_t ptr;
|
||||
|
||||
uint32_t rb_type;
|
||||
uint32_t rb_version;
|
||||
uint32_t val;
|
||||
|
||||
if (!reg_block_list)
|
||||
return NULL;
|
||||
|
||||
while (1) {
|
||||
reg_block_list[count].type = 0;
|
||||
reg_block_list[count].version = 0;
|
||||
reg_block_list[count].regs = NULL;
|
||||
|
||||
if ((offset == 0 && count != 0) || offset >= size)
|
||||
break;
|
||||
|
||||
ptr = base + offset;
|
||||
|
||||
for (int k = 0; k < count; k++) {
|
||||
if (ptr == reg_block_list[k].offset) {
|
||||
fprintf(stderr, "Register blocks form a loop\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
reg_if_read32(regs, ptr+0x00, &rb_type);
|
||||
reg_if_read32(regs, ptr+0x04, &rb_version);
|
||||
reg_if_read32(regs, ptr+0x08, &val);
|
||||
|
||||
reg_block_list[count].type = rb_type;
|
||||
reg_block_list[count].version = rb_version;
|
||||
reg_block_list[count].offset = ptr;
|
||||
reg_block_list[count].regs = reg_if_open_offset(regs, ptr, size-offset);
|
||||
|
||||
offset = val;
|
||||
|
||||
count++;
|
||||
|
||||
if (count >= max_count) {
|
||||
struct reg_block *tmp;
|
||||
max_count += 4;
|
||||
tmp = realloc(reg_block_list, max_count * sizeof(struct reg_block));
|
||||
if (!tmp)
|
||||
goto fail;
|
||||
reg_block_list = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return reg_block_list;
|
||||
fail:
|
||||
free_reg_block_list(reg_block_list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct reg_block *find_reg_block(struct reg_block *list, uint32_t type, uint32_t version, int index)
|
||||
{
|
||||
struct reg_block *rb = list;
|
||||
|
||||
while (rb->regs) {
|
||||
if (rb->type == type && (!version || rb->version == version)) {
|
||||
if (index > 0) {
|
||||
index--;
|
||||
} else {
|
||||
return rb;
|
||||
}
|
||||
}
|
||||
|
||||
rb++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void free_reg_block_list(struct reg_block *list)
|
||||
{
|
||||
struct reg_block *rb = list;
|
||||
|
||||
while (rb->regs) {
|
||||
reg_if_close(rb->regs);
|
||||
rb->regs = NULL;
|
||||
|
||||
rb++;
|
||||
}
|
||||
|
||||
free(list);
|
||||
}
|
||||
30
src/pyrite/utils/reg_block.h
Normal file
30
src/pyrite/utils/reg_block.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/* SPDX-License-Identifier: GPL */
|
||||
/*
|
||||
|
||||
Copyright (c) 2026 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
#ifndef REG_BLOCK_H
|
||||
#define REG_BLOCK_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "reg_if.h"
|
||||
|
||||
struct reg_block {
|
||||
uint32_t type;
|
||||
uint32_t version;
|
||||
size_t offset;
|
||||
struct reg_if *regs;
|
||||
};
|
||||
|
||||
struct reg_block *enumerate_reg_block_list(struct reg_if *regs, size_t base, size_t offset, size_t size);
|
||||
struct reg_block *find_reg_block(struct reg_block *list, uint32_t type, uint32_t version, int index);
|
||||
void free_reg_block_list(struct reg_block *list);
|
||||
|
||||
#endif /* REG_BLOCK_H */
|
||||
259
src/pyrite/utils/reg_if.c
Normal file
259
src/pyrite/utils/reg_if.c
Normal file
@@ -0,0 +1,259 @@
|
||||
// SPDX-License-Identifier: GPL
|
||||
/*
|
||||
|
||||
Copyright (c) 2026 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "reg_if.h"
|
||||
|
||||
int reg_if_read8(const struct reg_if *reg, size_t offset, uint8_t *value)
|
||||
{
|
||||
if (!reg || !reg->ops || !reg->ops->read8)
|
||||
return -1;
|
||||
if (reg->size && offset >= reg->size)
|
||||
return -1;
|
||||
return reg->ops->read8(reg, offset, value);
|
||||
}
|
||||
|
||||
int reg_if_write8(const struct reg_if *reg, size_t offset, uint8_t value)
|
||||
{
|
||||
if (!reg || !reg->ops || !reg->ops->write8)
|
||||
return -1;
|
||||
if (reg->size && offset >= reg->size)
|
||||
return -1;
|
||||
return reg->ops->write8(reg, offset, value);
|
||||
}
|
||||
|
||||
int reg_if_read16(const struct reg_if *reg, size_t offset, uint16_t *value)
|
||||
{
|
||||
if (!reg || !reg->ops || !reg->ops->read16)
|
||||
return -1;
|
||||
if (reg->size && offset >= reg->size)
|
||||
return -1;
|
||||
return reg->ops->read16(reg, offset, value);
|
||||
}
|
||||
|
||||
int reg_if_write16(const struct reg_if *reg, size_t offset, uint16_t value)
|
||||
{
|
||||
if (!reg || !reg->ops || !reg->ops->write16)
|
||||
return -1;
|
||||
if (reg->size && offset >= reg->size)
|
||||
return -1;
|
||||
return reg->ops->write16(reg, offset, value);
|
||||
}
|
||||
|
||||
int reg_if_read32(const struct reg_if *reg, size_t offset, uint32_t *value)
|
||||
{
|
||||
if (!reg || !reg->ops || !reg->ops->read32)
|
||||
return -1;
|
||||
if (reg->size && offset >= reg->size)
|
||||
return -1;
|
||||
return reg->ops->read32(reg, offset, value);
|
||||
}
|
||||
|
||||
int reg_if_write32(const struct reg_if *reg, size_t offset, uint32_t value)
|
||||
{
|
||||
if (!reg || !reg->ops || !reg->ops->write32)
|
||||
return -1;
|
||||
if (reg->size && offset >= reg->size)
|
||||
return -1;
|
||||
return reg->ops->write32(reg, offset, value);
|
||||
}
|
||||
|
||||
int reg_if_read64(const struct reg_if *reg, size_t offset, uint64_t *value)
|
||||
{
|
||||
if (!reg || !reg->ops || !reg->ops->read64)
|
||||
return -1;
|
||||
if (reg->size && offset >= reg->size)
|
||||
return -1;
|
||||
return reg->ops->read64(reg, offset, value);
|
||||
}
|
||||
|
||||
int reg_if_write64(const struct reg_if *reg, size_t offset, uint64_t value)
|
||||
{
|
||||
if (!reg || !reg->ops || !reg->ops->write64)
|
||||
return -1;
|
||||
if (reg->size && offset >= reg->size)
|
||||
return -1;
|
||||
return reg->ops->write64(reg, offset, value);
|
||||
}
|
||||
|
||||
void reg_if_close(struct reg_if *reg)
|
||||
{
|
||||
if (!reg)
|
||||
return;
|
||||
if (reg->ops && reg->ops->close)
|
||||
reg->ops->close(reg);
|
||||
free(reg);
|
||||
}
|
||||
|
||||
static int reg_if_raw_read8(const struct reg_if *reg, size_t offset, uint8_t *value)
|
||||
{
|
||||
uint8_t *regs = reg->priv;
|
||||
*value = *(volatile uint8_t *)(regs+offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reg_if_raw_write8(const struct reg_if *reg, size_t offset, uint8_t value)
|
||||
{
|
||||
uint8_t *regs = reg->priv;
|
||||
*(volatile uint8_t *)(regs+offset) = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reg_if_raw_read16(const struct reg_if *reg, size_t offset, uint16_t *value)
|
||||
{
|
||||
uint8_t *regs = reg->priv;
|
||||
*value = *(volatile uint16_t *)(regs+offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reg_if_raw_write16(const struct reg_if *reg, size_t offset, uint16_t value)
|
||||
{
|
||||
uint8_t *regs = reg->priv;
|
||||
*(volatile uint16_t *)(regs+offset) = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reg_if_raw_read32(const struct reg_if *reg, size_t offset, uint32_t *value)
|
||||
{
|
||||
uint8_t *regs = reg->priv;
|
||||
*value = *(volatile uint32_t *)(regs+offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reg_if_raw_write32(const struct reg_if *reg, size_t offset, uint32_t value)
|
||||
{
|
||||
uint8_t *regs = reg->priv;
|
||||
*(volatile uint32_t *)(regs+offset) = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reg_if_raw_read64(const struct reg_if *reg, size_t offset, uint64_t *value)
|
||||
{
|
||||
uint8_t *regs = reg->priv;
|
||||
*value = *(volatile uint64_t *)(regs+offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reg_if_raw_write64(const struct reg_if *reg, size_t offset, uint64_t value)
|
||||
{
|
||||
uint8_t *regs = reg->priv;
|
||||
*(volatile uint64_t *)(regs+offset) = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct reg_if_ops reg_if_raw_ops = {
|
||||
.read8 = reg_if_raw_read8,
|
||||
.write8 = reg_if_raw_write8,
|
||||
.read16 = reg_if_raw_read16,
|
||||
.write16 = reg_if_raw_write16,
|
||||
.read32 = reg_if_raw_read32,
|
||||
.write32 = reg_if_raw_write32,
|
||||
.read64 = reg_if_raw_read64,
|
||||
.write64 = reg_if_raw_write64,
|
||||
};
|
||||
|
||||
struct reg_if *reg_if_open_raw(void *regs, size_t size)
|
||||
{
|
||||
struct reg_if *reg = calloc(sizeof(struct reg_if), 1);
|
||||
|
||||
if (!reg)
|
||||
return NULL;
|
||||
|
||||
reg->ops = ®_if_raw_ops;
|
||||
reg->priv = regs;
|
||||
reg->size = size;
|
||||
reg->offset = 0;
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
static int reg_if_offset_read8(const struct reg_if *reg, size_t offset, uint8_t *value)
|
||||
{
|
||||
const struct reg_if *regs = reg->priv;
|
||||
return reg_if_read8(regs, reg->offset+offset, value);
|
||||
}
|
||||
|
||||
static int reg_if_offset_write8(const struct reg_if *reg, size_t offset, uint8_t value)
|
||||
{
|
||||
const struct reg_if *regs = reg->priv;
|
||||
return reg_if_write8(regs, reg->offset+offset, value);
|
||||
}
|
||||
|
||||
static int reg_if_offset_read16(const struct reg_if *reg, size_t offset, uint16_t *value)
|
||||
{
|
||||
const struct reg_if *regs = reg->priv;
|
||||
return reg_if_read16(regs, reg->offset+offset, value);
|
||||
}
|
||||
|
||||
static int reg_if_offset_write16(const struct reg_if *reg, size_t offset, uint16_t value)
|
||||
{
|
||||
const struct reg_if *regs = reg->priv;
|
||||
return reg_if_write16(regs, reg->offset+offset, value);
|
||||
}
|
||||
|
||||
static int reg_if_offset_read32(const struct reg_if *reg, size_t offset, uint32_t *value)
|
||||
{
|
||||
const struct reg_if *regs = reg->priv;
|
||||
return reg_if_read32(regs, reg->offset+offset, value);
|
||||
}
|
||||
|
||||
static int reg_if_offset_write32(const struct reg_if *reg, size_t offset, uint32_t value)
|
||||
{
|
||||
const struct reg_if *regs = reg->priv;
|
||||
return reg_if_write32(regs, reg->offset+offset, value);
|
||||
}
|
||||
|
||||
static int reg_if_offset_read64(const struct reg_if *reg, size_t offset, uint64_t *value)
|
||||
{
|
||||
const struct reg_if *regs = reg->priv;
|
||||
return reg_if_read64(regs, reg->offset+offset, value);
|
||||
}
|
||||
|
||||
static int reg_if_offset_write64(const struct reg_if *reg, size_t offset, uint64_t value)
|
||||
{
|
||||
const struct reg_if *regs = reg->priv;
|
||||
return reg_if_write64(regs, reg->offset+offset, value);
|
||||
}
|
||||
|
||||
static const struct reg_if_ops reg_if_offset_ops = {
|
||||
.read8 = reg_if_offset_read8,
|
||||
.write8 = reg_if_offset_write8,
|
||||
.read16 = reg_if_offset_read16,
|
||||
.write16 = reg_if_offset_write16,
|
||||
.read32 = reg_if_offset_read32,
|
||||
.write32 = reg_if_offset_write32,
|
||||
.read64 = reg_if_offset_read64,
|
||||
.write64 = reg_if_offset_write64,
|
||||
};
|
||||
|
||||
struct reg_if *reg_if_open_offset(struct reg_if *regs, size_t offset, size_t size)
|
||||
{
|
||||
if (!regs)
|
||||
return NULL;
|
||||
|
||||
if (regs->size && offset >= regs->size)
|
||||
return NULL;
|
||||
|
||||
if (regs->size && (!size || size >= regs->size))
|
||||
size = regs->size - offset;
|
||||
|
||||
struct reg_if *reg = calloc(sizeof(struct reg_if), 1);
|
||||
|
||||
if (!reg)
|
||||
return NULL;
|
||||
|
||||
reg->ops = ®_if_offset_ops;
|
||||
reg->priv = regs;
|
||||
reg->size = size;
|
||||
reg->offset = offset;
|
||||
|
||||
return reg;
|
||||
}
|
||||
50
src/pyrite/utils/reg_if.h
Normal file
50
src/pyrite/utils/reg_if.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/* SPDX-License-Identifier: GPL */
|
||||
/*
|
||||
|
||||
Copyright (c) 2026 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
#ifndef REG_IF_H
|
||||
#define REG_IF_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
struct reg_if {
|
||||
const struct reg_if_ops *ops;
|
||||
void *priv;
|
||||
size_t size;
|
||||
size_t offset;
|
||||
};
|
||||
|
||||
struct reg_if_ops {
|
||||
int (*read8)(const struct reg_if *reg, size_t offset, uint8_t *value);
|
||||
int (*write8)(const struct reg_if *reg, size_t offset, uint8_t value);
|
||||
int (*read16)(const struct reg_if *reg, size_t offset, uint16_t *value);
|
||||
int (*write16)(const struct reg_if *reg, size_t offset, uint16_t value);
|
||||
int (*read32)(const struct reg_if *reg, size_t offset, uint32_t *value);
|
||||
int (*write32)(const struct reg_if *reg, size_t offset, uint32_t value);
|
||||
int (*read64)(const struct reg_if *reg, size_t offset, uint64_t *value);
|
||||
int (*write64)(const struct reg_if *reg, size_t offset, uint64_t value);
|
||||
void (*close)(const struct reg_if *reg);
|
||||
};
|
||||
|
||||
int reg_if_read8(const struct reg_if *reg, size_t offset, uint8_t *value);
|
||||
int reg_if_write8(const struct reg_if *reg, size_t offset, uint8_t value);
|
||||
int reg_if_read16(const struct reg_if *reg, size_t offset, uint16_t *value);
|
||||
int reg_if_write16(const struct reg_if *reg, size_t offset, uint16_t value);
|
||||
int reg_if_read32(const struct reg_if *reg, size_t offset, uint32_t *value);
|
||||
int reg_if_write32(const struct reg_if *reg, size_t offset, uint32_t value);
|
||||
int reg_if_read64(const struct reg_if *reg, size_t offset, uint64_t *value);
|
||||
int reg_if_write64(const struct reg_if *reg, size_t offset, uint64_t value);
|
||||
void reg_if_close(struct reg_if *reg);
|
||||
|
||||
struct reg_if *reg_if_open_raw(void *regs, size_t size);
|
||||
|
||||
struct reg_if *reg_if_open_offset(struct reg_if *reg, size_t offset, size_t size);
|
||||
|
||||
#endif /* REG_IF_H */
|
||||
Reference in New Issue
Block a user