Xilinx changes for v2021.01-v2

common:
- Add support for 64bit loadables from SPL

xilinx:
- Update documentation and record ownership
- Enable eeprom board detection based legacy and fru formats
- Add support for FRU format

microblaze:
- Optimize low level ASM code
- Enable SPI/I2C
- Enable distro boot

zynq:
- Add support for Zturn V5

zynqmp:
- Improve silicon detection code
- Enable several kconfig options
- Align DT with the latest state
- Enabling security commands
- Enable and support FPGA loading from SPL
- Optimize xilinx_pm_request() calling

versal:
- Some DTs/Kconfig/defconfig alignments
- Add binding header for clock and power

zynq-sdhci:
- Add support for tap delay programming

zynq-spi/zynq-qspi:
- Use clock framework for getting clocks

xilinx-spi:
- Fix some code issues (unused variables)

serial:
- Check return value from clock functions in pl01x
This commit is contained in:
Tom Rini
2020-10-29 11:30:15 -04:00
74 changed files with 2992 additions and 566 deletions

View File

@@ -50,9 +50,34 @@ config XILINX_OF_BOARD_DTB_ADDR
config BOOT_SCRIPT_OFFSET
hex "Boot script offset"
depends on ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_VERSAL
default 0xFC0000 if ARCH_ZYNQ
depends on ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_VERSAL || MICROBLAZE
default 0xFC0000 if ARCH_ZYNQ || MICROBLAZE
default 0x3E80000 if ARCH_ZYNQMP
default 0x7F80000 if ARCH_VERSAL
help
Specifies distro boot script offset in NAND/NOR flash.
Specifies distro boot script offset in NAND/QSPI/NOR flash.
config ZYNQ_MAC_IN_EEPROM
bool "Reading MAC address from EEPROM"
help
Enable this option if your MAC address is saved in eeprom and
xlnx,eeprom DT property in chosen node points to it.
if ZYNQ_MAC_IN_EEPROM
config ZYNQ_GEM_I2C_MAC_OFFSET
hex "Set the I2C MAC offset"
default 0x0
depends on DM_I2C
help
Set the MAC offset for i2C.
endif
config CMD_FRU
bool "FRU information for product"
help
This option enables FRU commands to capture and display FRU
information present in the device. The FRU Information is used
to primarily to provide "inventory" information about the boards
that the FRU Information Device is located on.

View File

@@ -0,0 +1,10 @@
# SPDX-License-Identifier: GPL-2.0
#
# (C) Copyright 2020 Xilinx, Inc.
# Michal Simek <michal.simek@xilinx.com>
#
obj-y += board.o
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_CMD_FRU) += fru.o fru_ops.o
endif

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2014 - 2019 Xilinx, Inc.
* (C) Copyright 2014 - 2020 Xilinx, Inc.
* Michal Simek <michal.simek@xilinx.com>
*/
@@ -11,7 +11,14 @@
#include <dm/uclass.h>
#include <i2c.h>
#include <linux/sizes.h>
#include <malloc.h>
#include "board.h"
#include <dm.h>
#include <i2c_eeprom.h>
#include <net.h>
#include <generated/dt.h>
#include "fru.h"
#if defined(CONFIG_ZYNQ_GEM_I2C_MAC_OFFSET)
int zynq_board_read_rom_ethaddr(unsigned char *ethaddr)
@@ -41,6 +48,277 @@ int zynq_board_read_rom_ethaddr(unsigned char *ethaddr)
}
#endif
#define EEPROM_HEADER_MAGIC 0xdaaddeed
#define EEPROM_HDR_MANUFACTURER_LEN 16
#define EEPROM_HDR_NAME_LEN 16
#define EEPROM_HDR_REV_LEN 8
#define EEPROM_HDR_SERIAL_LEN 20
#define EEPROM_HDR_NO_OF_MAC_ADDR 4
#define EEPROM_HDR_ETH_ALEN ETH_ALEN
struct xilinx_board_description {
u32 header;
char manufacturer[EEPROM_HDR_MANUFACTURER_LEN + 1];
char name[EEPROM_HDR_NAME_LEN + 1];
char revision[EEPROM_HDR_REV_LEN + 1];
char serial[EEPROM_HDR_SERIAL_LEN + 1];
u8 mac_addr[EEPROM_HDR_NO_OF_MAC_ADDR][EEPROM_HDR_ETH_ALEN + 1];
};
static int highest_id = -1;
static struct xilinx_board_description **board_info;
#define XILINX_I2C_DETECTION_BITS sizeof(struct fru_common_hdr)
/* Variable which stores pointer to array which stores eeprom content */
struct xilinx_legacy_format {
char board_sn[18]; /* 0x0 */
char unused0[14]; /* 0x12 */
char eth_mac[6]; /* 0x20 */
char unused1[170]; /* 0x26 */
char board_name[11]; /* 0xd0 */
char unused2[5]; /* 0xdc */
char board_revision[3]; /* 0xe0 */
char unused3[29]; /* 0xe3 */
};
static void xilinx_eeprom_legacy_cleanup(char *eeprom, int size)
{
int i;
char byte;
for (i = 0; i < size; i++) {
byte = eeprom[i];
/* Remove all ffs and spaces */
if (byte == 0xff || byte == ' ')
eeprom[i] = 0;
/* Convert strings to lower case */
if (byte >= 'A' && byte <= 'Z')
eeprom[i] = byte + 'a' - 'A';
}
}
static int xilinx_read_eeprom_legacy(struct udevice *dev, char *name,
struct xilinx_board_description *desc)
{
int ret, size;
struct xilinx_legacy_format *eeprom_content;
bool eth_valid = false;
size = sizeof(*eeprom_content);
eeprom_content = calloc(1, size);
if (!eeprom_content)
return -ENOMEM;
debug("%s: I2C EEPROM read pass data at %p\n", __func__,
eeprom_content);
ret = dm_i2c_read(dev, 0, (uchar *)eeprom_content, size);
if (ret) {
debug("%s: I2C EEPROM read failed\n", __func__);
free(eeprom_content);
return ret;
}
xilinx_eeprom_legacy_cleanup((char *)eeprom_content, size);
printf("Xilinx I2C Legacy format at %s:\n", name);
printf(" Board name:\t%s\n", eeprom_content->board_name);
printf(" Board rev:\t%s\n", eeprom_content->board_revision);
printf(" Board SN:\t%s\n", eeprom_content->board_sn);
eth_valid = is_valid_ethaddr((const u8 *)eeprom_content->eth_mac);
if (eth_valid)
printf(" Ethernet mac:\t%pM\n", eeprom_content->eth_mac);
/* Terminating \0 chars ensure end of string */
strcpy(desc->name, eeprom_content->board_name);
strcpy(desc->revision, eeprom_content->board_revision);
strcpy(desc->serial, eeprom_content->board_sn);
if (eth_valid)
memcpy(desc->mac_addr[0], eeprom_content->eth_mac, ETH_ALEN);
desc->header = EEPROM_HEADER_MAGIC;
free(eeprom_content);
return ret;
}
static bool xilinx_detect_legacy(u8 *buffer)
{
int i;
char c;
for (i = 0; i < XILINX_I2C_DETECTION_BITS; i++) {
c = buffer[i];
if (c < '0' || c > '9')
return false;
}
return true;
}
static int xilinx_read_eeprom_fru(struct udevice *dev, char *name,
struct xilinx_board_description *desc)
{
int ret, eeprom_size;
u8 *fru_content;
/* FIXME this is shortcut - if eeprom type is wrong it will fail */
eeprom_size = i2c_eeprom_size(dev);
fru_content = calloc(1, eeprom_size);
if (!fru_content)
return -ENOMEM;
debug("%s: I2C EEPROM read pass data at %p\n", __func__,
fru_content);
ret = dm_i2c_read(dev, 0, (uchar *)fru_content,
eeprom_size);
if (ret) {
debug("%s: I2C EEPROM read failed\n", __func__);
free(fru_content);
return ret;
}
printf("Xilinx I2C FRU format at %s:\n", name);
fru_capture((unsigned long)fru_content);
ret = fru_display(0);
if (ret) {
printf("FRU format decoding failed.\n");
return ret;
}
if (desc->header == EEPROM_HEADER_MAGIC) {
debug("Information already filled\n");
return -EINVAL;
}
/* It is clear that FRU was captured and structures were filled */
strncpy(desc->manufacturer, (char *)fru_data.brd.manufacturer_name,
sizeof(desc->manufacturer));
strncpy(desc->name, (char *)fru_data.brd.product_name,
sizeof(desc->name));
strncpy(desc->revision, (char *)fru_data.brd.rev,
sizeof(desc->revision));
strncpy(desc->serial, (char *)fru_data.brd.serial_number,
sizeof(desc->serial));
desc->header = EEPROM_HEADER_MAGIC;
return 0;
}
static bool xilinx_detect_fru(u8 *buffer)
{
u8 checksum = 0;
int i;
checksum = fru_checksum((u8 *)buffer, sizeof(struct fru_common_hdr));
if (checksum) {
debug("%s Common header CRC FAIL\n", __func__);
return false;
}
bool all_zeros = true;
/* Checksum over all zeros is also zero that's why detect this case */
for (i = 0; i < sizeof(struct fru_common_hdr); i++) {
if (buffer[i] != 0)
all_zeros = false;
}
if (all_zeros)
return false;
debug("%s Common header CRC PASS\n", __func__);
return true;
}
static int xilinx_read_eeprom_single(char *name,
struct xilinx_board_description *desc)
{
int ret;
struct udevice *dev;
ofnode eeprom;
u8 buffer[XILINX_I2C_DETECTION_BITS];
eeprom = ofnode_get_aliases_node(name);
if (!ofnode_valid(eeprom))
return -ENODEV;
ret = uclass_get_device_by_ofnode(UCLASS_I2C_EEPROM, eeprom, &dev);
if (ret)
return ret;
ret = dm_i2c_read(dev, 0, buffer, sizeof(buffer));
if (ret) {
debug("%s: I2C EEPROM read failed\n", __func__);
return ret;
}
debug("%s: i2c memory detected: %s\n", __func__, name);
if (CONFIG_IS_ENABLED(CMD_FRU) && xilinx_detect_fru(buffer))
return xilinx_read_eeprom_fru(dev, name, desc);
if (xilinx_detect_legacy(buffer))
return xilinx_read_eeprom_legacy(dev, name, desc);
return -ENODEV;
}
__maybe_unused int xilinx_read_eeprom(void)
{
int id, ret;
char name_buf[8]; /* 8 bytes should be enough for nvmem+number */
struct xilinx_board_description *desc;
highest_id = dev_read_alias_highest_id("nvmem");
/* No nvmem aliases present */
if (highest_id < 0)
return -EINVAL;
board_info = calloc(1, sizeof(desc) * highest_id);
if (!board_info)
return -ENOMEM;
debug("%s: Highest ID %d, board_info %p\n", __func__,
highest_id, board_info);
for (id = 0; id <= highest_id; id++) {
snprintf(name_buf, sizeof(name_buf), "nvmem%d", id);
/* Alloc structure */
desc = board_info[id];
if (!desc) {
desc = calloc(1, sizeof(*desc));
if (!desc)
return -ENOMEM;
board_info[id] = desc;
}
/* Ignoring return value for supporting multiple chips */
ret = xilinx_read_eeprom_single(name_buf, desc);
if (ret) {
free(desc);
board_info[id] = NULL;
}
}
/*
* Consider to clean board_info structure when board/cards are not
* detected.
*/
return 0;
}
#if defined(CONFIG_OF_BOARD) || defined(CONFIG_OF_SEPARATE)
void *board_fdt_blob_setup(void)
{
@@ -75,12 +353,36 @@ void *board_fdt_blob_setup(void)
}
#endif
#if defined(CONFIG_BOARD_LATE_INIT)
static int env_set_by_index(const char *name, int index, char *data)
{
char var[32];
if (!index)
sprintf(var, "board_%s", name);
else
sprintf(var, "card%d_%s", index, name);
return env_set(var, data);
}
int board_late_init_xilinx(void)
{
u32 ret = 0;
int i, id, macid = 0;
struct xilinx_board_description *desc;
phys_size_t bootm_size = gd->ram_size;
struct bd_info *bd = gd->bd;
if (CONFIG_IS_ENABLED(ARCH_ZYNQ))
if (!CONFIG_IS_ENABLED(MICROBLAZE) && bd->bi_dram[0].start) {
ulong scriptaddr;
scriptaddr = env_get_hex("scriptaddr", 0);
ret |= env_set_hex("scriptaddr",
bd->bi_dram[0].start + scriptaddr);
}
if (CONFIG_IS_ENABLED(ARCH_ZYNQ) || CONFIG_IS_ENABLED(MICROBLAZE))
bootm_size = min(bootm_size, (phys_size_t)(SZ_512M + SZ_256M));
ret |= env_set_hex("script_offset_f", CONFIG_BOOT_SCRIPT_OFFSET);
@@ -88,8 +390,49 @@ int board_late_init_xilinx(void)
ret |= env_set_addr("bootm_low", (void *)gd->ram_base);
ret |= env_set_addr("bootm_size", (void *)bootm_size);
for (id = 0; id <= highest_id; id++) {
desc = board_info[id];
if (desc && desc->header == EEPROM_HEADER_MAGIC) {
if (desc->manufacturer[0])
ret |= env_set_by_index("manufacturer", id,
desc->manufacturer);
if (desc->name[0])
ret |= env_set_by_index("name", id,
desc->name);
if (desc->revision[0])
ret |= env_set_by_index("rev", id,
desc->revision);
if (desc->serial[0])
ret |= env_set_by_index("serial", id,
desc->serial);
if (!CONFIG_IS_ENABLED(NET))
continue;
for (i = 0; i < EEPROM_HDR_NO_OF_MAC_ADDR; i++) {
if (!desc->mac_addr[i])
continue;
if (is_valid_ethaddr((const u8 *)desc->mac_addr[i]))
ret |= eth_env_set_enetaddr_by_index("eth",
macid++, desc->mac_addr[i]);
}
}
}
if (ret)
printf("%s: Saving run time variables FAILED\n", __func__);
return 0;
}
#endif
int __maybe_unused board_fit_config_name_match(const char *name)
{
debug("%s: Check %s, default %s\n", __func__, name, DEVICE_TREE);
if (!strcmp(name, DEVICE_TREE))
return 0;
return -1;
}

View File

@@ -9,4 +9,6 @@
int board_late_init_xilinx(void);
int xilinx_read_eeprom(void);
#endif /* BOARD_XILINX_COMMON_BOARD_H */

91
board/xilinx/common/fru.c Normal file
View File

@@ -0,0 +1,91 @@
// SPDX-License-Identifier: GPL-2.0
/*
* (C) Copyright 2019 - 2020 Xilinx, Inc.
*/
#include <common.h>
#include <command.h>
#include <fdtdec.h>
#include <malloc.h>
#include "fru.h"
static int do_fru_capture(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
unsigned long addr;
char *endp;
if (argc < cmdtp->maxargs)
return CMD_RET_USAGE;
addr = simple_strtoul(argv[2], &endp, 16);
if (*argv[1] == 0 || *endp != 0)
return -1;
return fru_capture(addr);
}
static int do_fru_display(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
fru_display(1);
return CMD_RET_SUCCESS;
}
static int do_fru_generate(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
unsigned long addr;
if (argc < cmdtp->maxargs)
return CMD_RET_USAGE;
addr = simple_strtoul(argv[2], NULL, 16);
return fru_generate(addr, argv[3], argv[4], argv[5], argv[6], argv[7]);
}
static struct cmd_tbl cmd_fru_sub[] = {
U_BOOT_CMD_MKENT(capture, 3, 0, do_fru_capture, "", ""),
U_BOOT_CMD_MKENT(display, 2, 0, do_fru_display, "", ""),
U_BOOT_CMD_MKENT(board_gen, 8, 0, do_fru_generate, "", ""),
};
static int do_fru(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
struct cmd_tbl *c;
int ret;
if (argc < 2)
return CMD_RET_USAGE;
c = find_cmd_tbl(argv[1], &cmd_fru_sub[0],
ARRAY_SIZE(cmd_fru_sub));
if (!c)
return CMD_RET_USAGE;
ret = c->cmd(c, flag, argc, argv);
return cmd_process_error(c, ret);
}
/***************************************************/
#ifdef CONFIG_SYS_LONGHELP
static char fru_help_text[] =
"capture <addr> - Parse and capture FRU table present at address.\n"
"fru display - Displays content of FRU table that was captured using\n"
" fru capture command\n"
"fru board_gen <addr> <manufacturer> <board name> <serial number>\n"
" <part number> <revision> - Generate FRU format with\n"
" board info area filled based on parameters. <addr> is\n"
" pointing to place where FRU is generated.\n"
;
#endif
U_BOOT_CMD(
fru, 8, 1, do_fru,
"FRU table info",
fru_help_text
)

83
board/xilinx/common/fru.h Normal file
View File

@@ -0,0 +1,83 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* (C) Copyright 2019 Xilinx, Inc.
* Siva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com>
*/
#ifndef __FRU_H
#define __FRU_H
struct fru_common_hdr {
u8 version;
u8 off_internal;
u8 off_chassis;
u8 off_board;
u8 off_product;
u8 off_multirec;
u8 pad;
u8 crc;
};
#define FRU_BOARD_MAX_LEN 32
struct __packed fru_board_info_header {
u8 ver;
u8 len;
u8 lang_code;
u8 time[3];
};
struct __packed fru_board_info_member {
u8 type_len;
u8 *name;
};
struct fru_board_data {
u8 ver;
u8 len;
u8 lang_code;
u8 time[3];
u8 manufacturer_type_len;
u8 manufacturer_name[FRU_BOARD_MAX_LEN];
u8 product_name_type_len;
u8 product_name[FRU_BOARD_MAX_LEN];
u8 serial_number_type_len;
u8 serial_number[FRU_BOARD_MAX_LEN];
u8 part_number_type_len;
u8 part_number[FRU_BOARD_MAX_LEN];
u8 file_id_type_len;
u8 file_id[FRU_BOARD_MAX_LEN];
/* Xilinx custom fields */
u8 rev_type_len;
u8 rev[FRU_BOARD_MAX_LEN];
};
struct fru_table {
bool captured;
struct fru_common_hdr hdr;
struct fru_board_data brd;
};
#define FRU_TYPELEN_CODE_MASK 0xC0
#define FRU_TYPELEN_LEN_MASK 0x3F
#define FRU_COMMON_HDR_VER_MASK 0xF
#define FRU_COMMON_HDR_LEN_MULTIPLIER 8
#define FRU_LANG_CODE_ENGLISH 0
#define FRU_LANG_CODE_ENGLISH_1 25
#define FRU_TYPELEN_EOF 0xC1
/* This should be minimum of fields */
#define FRU_BOARD_AREA_TOTAL_FIELDS 5
#define FRU_TYPELEN_TYPE_SHIFT 6
#define FRU_TYPELEN_TYPE_BINARY 0
#define FRU_TYPELEN_TYPE_ASCII8 3
int fru_display(int verbose);
int fru_capture(unsigned long addr);
int fru_generate(unsigned long addr, char *manufacturer, char *board_name,
char *serial_no, char *part_no, char *revision);
u8 fru_checksum(u8 *addr, u8 len);
extern struct fru_table fru_data;
#endif /* FRU_H */

View File

@@ -0,0 +1,362 @@
// SPDX-License-Identifier: GPL-2.0
/*
* (C) Copyright 2019 - 2020 Xilinx, Inc.
*/
#include <common.h>
#include <cpu_func.h>
#include <env.h>
#include <fdtdec.h>
#include <log.h>
#include <malloc.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include "fru.h"
struct fru_table fru_data __section(.data);
static u16 fru_cal_area_len(u8 len)
{
return len * FRU_COMMON_HDR_LEN_MULTIPLIER;
}
static u8 fru_version(u8 ver)
{
return ver & FRU_COMMON_HDR_VER_MASK;
}
static int fru_check_language(u8 code)
{
if (code != FRU_LANG_CODE_ENGLISH && code != FRU_LANG_CODE_ENGLISH_1) {
printf("FRU_ERROR: Only English Language is supported\n");
return -EINVAL;
}
return 0;
}
u8 fru_checksum(u8 *addr, u8 len)
{
u8 checksum = 0;
while (len--) {
checksum += *addr;
addr++;
}
return checksum;
}
static int fru_check_type_len(u8 type_len, u8 language, u8 *type)
{
int len;
if (type_len == FRU_TYPELEN_EOF)
return -EINVAL;
*type = (type_len & FRU_TYPELEN_CODE_MASK) >> FRU_TYPELEN_TYPE_SHIFT;
len = type_len & FRU_TYPELEN_LEN_MASK;
return len;
}
/* Return len */
static u8 fru_gen_type_len(u8 *addr, char *name)
{
int len = strlen(name);
struct fru_board_info_member *member;
member = (struct fru_board_info_member *)addr;
member->type_len = FRU_TYPELEN_TYPE_ASCII8 << FRU_TYPELEN_TYPE_SHIFT;
member->type_len |= len;
debug("%lx/%lx: Add %s to 0x%lx (len 0x%x)\n", (ulong)addr,
(ulong)&member->type_len, name, (ulong)&member->name, len);
memcpy(&member->name, name, len);
/* Add +1 for type_len parameter */
return 1 + len;
}
int fru_generate(unsigned long addr, char *manufacturer, char *board_name,
char *serial_no, char *part_no, char *revision)
{
struct fru_common_hdr *header = (struct fru_common_hdr *)addr;
struct fru_board_info_header *board_info;
u8 *member;
u8 len, pad, modulo;
header->version = 1; /* Only version 1.0 is supported now */
header->off_internal = 0; /* not present */
header->off_chassis = 0; /* not present */
header->off_board = (sizeof(*header)) / 8; /* Starting offset 8 */
header->off_product = 0; /* not present */
header->off_multirec = 0; /* not present */
header->pad = 0;
/*
* This unsigned byte can be used to calculate a zero checksum
* for the data area following the header. I.e. the modulo 256 sum of
* the record data bytes plus the checksum byte equals zero.
*/
header->crc = 0; /* Clear before calculation */
header->crc = 0 - fru_checksum((u8 *)header, sizeof(*header));
/* board info is just right after header */
board_info = (void *)((u8 *)header + sizeof(*header));
debug("header %lx, board_info %lx\n", (ulong)header, (ulong)board_info);
board_info->ver = 1; /* 1.0 spec */
board_info->lang_code = 0; /* English */
board_info->time[0] = 0; /* unspecified */
board_info->time[1] = 0; /* unspecified */
board_info->time[2] = 0; /* unspecified */
/* Member fields are just after board_info header */
member = (u8 *)board_info + sizeof(*board_info);
len = fru_gen_type_len(member, manufacturer); /* Board Manufacturer */
member += len;
len = fru_gen_type_len(member, board_name); /* Board Product name */
member += len;
len = fru_gen_type_len(member, serial_no); /* Board Serial number */
member += len;
len = fru_gen_type_len(member, part_no); /* Board part number */
member += len;
len = fru_gen_type_len(member, "U-Boot generator"); /* File ID */
member += len;
len = fru_gen_type_len(member, revision); /* Revision */
member += len;
*member++ = 0xc1; /* Indication of no more fields */
len = member - (u8 *)board_info; /* Find current length */
len += 1; /* Add checksum there too for calculation */
modulo = len % 8;
if (modulo) {
/* Do not fill last item which is checksum */
for (pad = 0; pad < 8 - modulo; pad++)
*member++ = 0;
/* Increase structure size */
len += 8 - modulo;
}
board_info->len = len / 8; /* Size in multiples of 8 bytes */
*member = 0; /* Clear before calculation */
*member = 0 - fru_checksum((u8 *)board_info, len);
debug("checksum %x(addr %x)\n", *member, len);
env_set_hex("fru_addr", addr);
env_set_hex("filesize", (unsigned long)member - addr + 1);
return 0;
}
static int fru_parse_board(unsigned long addr)
{
u8 i, type;
int len;
u8 *data, *term;
memcpy(&fru_data.brd.ver, (void *)addr, 6);
addr += 6;
data = (u8 *)&fru_data.brd.manufacturer_type_len;
for (i = 0; ; i++, data += FRU_BOARD_MAX_LEN) {
len = fru_check_type_len(*(u8 *)addr, fru_data.brd.lang_code,
&type);
/*
* Stop cature if it end of fields
*/
if (len == -EINVAL)
break;
/* This record type/len field */
*data++ = *(u8 *)addr;
/* Add offset to match data */
addr += 1;
/* If len is 0 it means empty field that's why skip writing */
if (!len)
continue;
/* Record data field */
memcpy(data, (u8 *)addr, len);
term = data + (u8)len;
*term = 0;
addr += len;
}
if (i < FRU_BOARD_AREA_TOTAL_FIELDS) {
printf("Board area require minimum %d fields\n",
FRU_BOARD_AREA_TOTAL_FIELDS);
return -EINVAL;
}
return 0;
}
int fru_capture(unsigned long addr)
{
struct fru_common_hdr *hdr;
u8 checksum = 0;
checksum = fru_checksum((u8 *)addr, sizeof(struct fru_common_hdr));
if (checksum) {
printf("%s Common header CRC error\n", __func__);
return -EINVAL;
}
hdr = (struct fru_common_hdr *)addr;
memcpy((void *)&fru_data.hdr, (void *)hdr,
sizeof(struct fru_common_hdr));
fru_data.captured = true;
if (hdr->off_board) {
addr += fru_cal_area_len(hdr->off_board);
fru_parse_board(addr);
}
env_set_hex("fru_addr", addr);
return 0;
}
static int fru_display_board(struct fru_board_data *brd, int verbose)
{
u32 time = 0;
u8 type;
int len;
u8 *data;
static const char * const typecode[] = {
"Binary/Unspecified",
"BCD plus",
"6-bit ASCII",
"8-bit ASCII",
"2-byte UNICODE"
};
static const char * const boardinfo[] = {
"Manufacturer Name",
"Product Name",
"Serial No",
"Part Number",
"File ID",
/* Xilinx spec */
"Revision Number",
};
if (verbose) {
printf("*****BOARD INFO*****\n");
printf("Version:%d\n", fru_version(brd->ver));
printf("Board Area Length:%d\n", fru_cal_area_len(brd->len));
}
if (fru_check_language(brd->lang_code))
return -EINVAL;
time = brd->time[2] << 16 | brd->time[1] << 8 |
brd->time[0];
if (verbose)
printf("Time in Minutes from 0:00hrs 1/1/96: %d\n", time);
data = (u8 *)&brd->manufacturer_type_len;
for (u8 i = 0; i < (sizeof(boardinfo) / sizeof(*boardinfo)); i++) {
len = fru_check_type_len(*data++, brd->lang_code,
&type);
if (len == -EINVAL) {
printf("**** EOF for Board Area ****\n");
break;
}
if (type <= FRU_TYPELEN_TYPE_ASCII8 &&
(brd->lang_code == FRU_LANG_CODE_ENGLISH ||
brd->lang_code == FRU_LANG_CODE_ENGLISH_1))
debug("Type code: %s\n", typecode[type]);
else
debug("Type code: %s\n", typecode[type + 1]);
if (!len) {
debug("%s not found\n", boardinfo[i]);
continue;
}
switch (type) {
case FRU_TYPELEN_TYPE_BINARY:
debug("Length: %d\n", len);
printf(" %s: 0x%x\n", boardinfo[i], *data);
break;
case FRU_TYPELEN_TYPE_ASCII8:
debug("Length: %d\n", len);
printf(" %s: %s\n", boardinfo[i], data);
break;
default:
debug("Unsupported type %x\n", type);
}
data += FRU_BOARD_MAX_LEN;
}
return 0;
}
static void fru_display_common_hdr(struct fru_common_hdr *hdr, int verbose)
{
if (!verbose)
return;
printf("*****COMMON HEADER*****\n");
printf("Version:%d\n", fru_version(hdr->version));
if (hdr->off_internal)
printf("Internal Use Area Offset:%d\n",
fru_cal_area_len(hdr->off_internal));
else
printf("*** No Internal Area ***\n");
if (hdr->off_chassis)
printf("Chassis Info Area Offset:%d\n",
fru_cal_area_len(hdr->off_chassis));
else
printf("*** No Chassis Info Area ***\n");
if (hdr->off_board)
printf("Board Area Offset:%d\n",
fru_cal_area_len(hdr->off_board));
else
printf("*** No Board Area ***\n");
if (hdr->off_product)
printf("Product Info Area Offset:%d\n",
fru_cal_area_len(hdr->off_product));
else
printf("*** No Product Info Area ***\n");
if (hdr->off_multirec)
printf("MultiRecord Area Offset:%d\n",
fru_cal_area_len(hdr->off_multirec));
else
printf("*** No MultiRecord Area ***\n");
}
int fru_display(int verbose)
{
if (!fru_data.captured) {
printf("FRU data not available please run fru parse\n");
return -EINVAL;
}
fru_display_common_hdr(&fru_data.hdr, verbose);
return fru_display_board(&fru_data.brd, verbose);
}

View File

@@ -18,6 +18,7 @@
#include <dm/lists.h>
#include <fdtdec.h>
#include <linux/sizes.h>
#include "../common/board.h"
DECLARE_GLOBAL_DATA_PTR;
@@ -36,7 +37,8 @@ int dram_init(void)
int board_late_init(void)
{
ulong max_size, lowmem_size;
ulong max_size;
u32 status = 0;
#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_SYSRESET_MICROBLAZE)
int ret;
@@ -55,12 +57,19 @@ int board_late_init(void)
max_size = gd->start_addr_sp - CONFIG_STACK_SIZE;
max_size = round_down(max_size, SZ_16M);
/* Linux default LOWMEM_SIZE is 0x30000000 = 768MB */
lowmem_size = gd->ram_base + 768 * 1024 * 1024;
status |= env_set_hex("scriptaddr", max_size + SZ_2M);
env_set_addr("initrd_high", (void *)min_t(ulong, max_size,
lowmem_size));
env_set_addr("fdt_high", (void *)min_t(ulong, max_size, lowmem_size));
status |= env_set_hex("pxefile_addr_r", max_size + SZ_1M);
return 0;
status |= env_set_hex("kernel_addr_r", gd->ram_base + SZ_32M);
status |= env_set_hex("fdt_addr_r", gd->ram_base + SZ_32M - SZ_1M);
status |= env_set_hex("ramdisk_addr_r",
gd->ram_base + SZ_32M + SZ_4M + SZ_2M);
if (status)
printf("%s: Saving run time variables FAILED\n", __func__);
return board_late_init_xilinx();
}

View File

@@ -6,4 +6,3 @@
obj-y := board.o
obj-$(CONFIG_CMD_VERSAL) += cmds.o
obj-y += ../common/board.o

View File

@@ -36,6 +36,9 @@ int board_init(void)
fpga_add(fpga_xilinx, &versalpl);
#endif
if (CONFIG_IS_ENABLED(DM_I2C) && CONFIG_IS_ENABLED(I2C_EEPROM))
xilinx_read_eeprom();
return 0;
}

View File

@@ -4,7 +4,6 @@
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
obj-y := board.o
obj-y += ../common/board.o
ifneq ($(CONFIG_XILINX_PS_INIT_FILE),"")
PS_INIT_FILE := $(shell cd $(srctree); readlink -f $(CONFIG_XILINX_PS_INIT_FILE))

View File

@@ -0,0 +1,273 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) Xilinx, Inc.
*/
#include <asm/arch/ps7_init_gpl.h>
static unsigned long ps7_pll_init_data[] = {
EMIT_WRITE(0xF8000008, 0x0000DF0DU),
EMIT_MASKWRITE(0xF8000110, 0x003FFFF0U, 0x000FA220U),
EMIT_MASKWRITE(0xF8000100, 0x0007F000U, 0x00028000U),
EMIT_MASKWRITE(0xF8000100, 0x00000010U, 0x00000010U),
EMIT_MASKWRITE(0xF8000100, 0x00000001U, 0x00000001U),
EMIT_MASKWRITE(0xF8000100, 0x00000001U, 0x00000000U),
EMIT_MASKPOLL(0xF800010C, 0x00000001U),
EMIT_MASKWRITE(0xF8000100, 0x00000010U, 0x00000000U),
EMIT_MASKWRITE(0xF8000120, 0x1F003F30U, 0x1F000200U),
EMIT_MASKWRITE(0xF8000114, 0x003FFFF0U, 0x0012C220U),
EMIT_MASKWRITE(0xF8000104, 0x0007F000U, 0x00020000U),
EMIT_MASKWRITE(0xF8000104, 0x00000010U, 0x00000010U),
EMIT_MASKWRITE(0xF8000104, 0x00000001U, 0x00000001U),
EMIT_MASKWRITE(0xF8000104, 0x00000001U, 0x00000000U),
EMIT_MASKPOLL(0xF800010C, 0x00000002U),
EMIT_MASKWRITE(0xF8000104, 0x00000010U, 0x00000000U),
EMIT_MASKWRITE(0xF8000124, 0xFFF00003U, 0x0C200003U),
EMIT_MASKWRITE(0xF8000118, 0x003FFFF0U, 0x001452C0U),
EMIT_MASKWRITE(0xF8000108, 0x0007F000U, 0x0001E000U),
EMIT_MASKWRITE(0xF8000108, 0x00000010U, 0x00000010U),
EMIT_MASKWRITE(0xF8000108, 0x00000001U, 0x00000001U),
EMIT_MASKWRITE(0xF8000108, 0x00000001U, 0x00000000U),
EMIT_MASKPOLL(0xF800010C, 0x00000004U),
EMIT_MASKWRITE(0xF8000108, 0x00000010U, 0x00000000U),
EMIT_WRITE(0xF8000004, 0x0000767BU),
EMIT_EXIT(),
};
static unsigned long ps7_clock_init_data[] = {
EMIT_WRITE(0xF8000008, 0x0000DF0DU),
EMIT_MASKWRITE(0xF8000128, 0x03F03F01U, 0x00700F01U),
EMIT_MASKWRITE(0xF8000138, 0x00000011U, 0x00000001U),
EMIT_MASKWRITE(0xF8000140, 0x03F03F71U, 0x00100801U),
EMIT_MASKWRITE(0xF800014C, 0x00003F31U, 0x00000501U),
EMIT_MASKWRITE(0xF8000150, 0x00003F33U, 0x00001401U),
EMIT_MASKWRITE(0xF8000154, 0x00003F33U, 0x00000A03U),
EMIT_MASKWRITE(0xF800015C, 0x03F03F33U, 0x00200501U),
EMIT_MASKWRITE(0xF8000160, 0x007F007FU, 0x00000000U),
EMIT_MASKWRITE(0xF8000168, 0x00003F31U, 0x00000501U),
EMIT_MASKWRITE(0xF8000170, 0x03F03F30U, 0x00200500U),
EMIT_MASKWRITE(0xF8000180, 0x03F03F30U, 0x00400500U),
EMIT_MASKWRITE(0xF80001C4, 0x00000001U, 0x00000001U),
EMIT_MASKWRITE(0xF800012C, 0x01FFCCCDU, 0x01FD044DU),
EMIT_WRITE(0xF8000004, 0x0000767BU),
EMIT_EXIT(),
};
static unsigned long ps7_ddr_init_data[] = {
EMIT_MASKWRITE(0xF8006000, 0x0001FFFFU, 0x00000080U),
EMIT_MASKWRITE(0xF8006004, 0x0007FFFFU, 0x00001082U),
EMIT_MASKWRITE(0xF8006008, 0x03FFFFFFU, 0x03C0780FU),
EMIT_MASKWRITE(0xF800600C, 0x03FFFFFFU, 0x02001001U),
EMIT_MASKWRITE(0xF8006010, 0x03FFFFFFU, 0x00014001U),
EMIT_MASKWRITE(0xF8006014, 0x001FFFFFU, 0x0004285BU),
EMIT_MASKWRITE(0xF8006018, 0xF7FFFFFFU, 0x44E458D3U),
EMIT_MASKWRITE(0xF800601C, 0xFFFFFFFFU, 0x7282BCE5U),
EMIT_MASKWRITE(0xF8006020, 0x7FDFFFFCU, 0x270872D0U),
EMIT_MASKWRITE(0xF8006024, 0x0FFFFFC3U, 0x00000000U),
EMIT_MASKWRITE(0xF8006028, 0x00003FFFU, 0x00002007U),
EMIT_MASKWRITE(0xF800602C, 0xFFFFFFFFU, 0x00000008U),
EMIT_MASKWRITE(0xF8006030, 0xFFFFFFFFU, 0x00040B30U),
EMIT_MASKWRITE(0xF8006034, 0x13FF3FFFU, 0x000116D4U),
EMIT_MASKWRITE(0xF8006038, 0x00000003U, 0x00000000U),
EMIT_MASKWRITE(0xF800603C, 0x000FFFFFU, 0x00000777U),
EMIT_MASKWRITE(0xF8006040, 0xFFFFFFFFU, 0xFFF00000U),
EMIT_MASKWRITE(0xF8006044, 0x0FFFFFFFU, 0x0F666666U),
EMIT_MASKWRITE(0xF8006048, 0x0003F03FU, 0x0003C008U),
EMIT_MASKWRITE(0xF8006050, 0xFF0F8FFFU, 0x77010800U),
EMIT_MASKWRITE(0xF8006058, 0x00010000U, 0x00000000U),
EMIT_MASKWRITE(0xF800605C, 0x0000FFFFU, 0x00005003U),
EMIT_MASKWRITE(0xF8006060, 0x000017FFU, 0x0000003EU),
EMIT_MASKWRITE(0xF8006064, 0x00021FE0U, 0x00020000U),
EMIT_MASKWRITE(0xF8006068, 0x03FFFFFFU, 0x00284141U),
EMIT_MASKWRITE(0xF800606C, 0x0000FFFFU, 0x00001610U),
EMIT_MASKWRITE(0xF8006078, 0x03FFFFFFU, 0x00466111U),
EMIT_MASKWRITE(0xF800607C, 0x000FFFFFU, 0x00032222U),
EMIT_MASKWRITE(0xF80060A4, 0xFFFFFFFFU, 0x10200802U),
EMIT_MASKWRITE(0xF80060A8, 0x0FFFFFFFU, 0x0690CB73U),
EMIT_MASKWRITE(0xF80060AC, 0x000001FFU, 0x000001FEU),
EMIT_MASKWRITE(0xF80060B0, 0x1FFFFFFFU, 0x1CFFFFFFU),
EMIT_MASKWRITE(0xF80060B4, 0x00000200U, 0x00000200U),
EMIT_MASKWRITE(0xF80060B8, 0x01FFFFFFU, 0x00200066U),
EMIT_MASKWRITE(0xF80060C4, 0x00000003U, 0x00000000U),
EMIT_MASKWRITE(0xF80060C8, 0x000000FFU, 0x00000000U),
EMIT_MASKWRITE(0xF80060DC, 0x00000001U, 0x00000000U),
EMIT_MASKWRITE(0xF80060F0, 0x0000FFFFU, 0x00000000U),
EMIT_MASKWRITE(0xF80060F4, 0x0000000FU, 0x00000008U),
EMIT_MASKWRITE(0xF8006114, 0x000000FFU, 0x00000000U),
EMIT_MASKWRITE(0xF8006118, 0x7FFFFFCFU, 0x40000001U),
EMIT_MASKWRITE(0xF800611C, 0x7FFFFFCFU, 0x40000001U),
EMIT_MASKWRITE(0xF8006120, 0x7FFFFFCFU, 0x40000001U),
EMIT_MASKWRITE(0xF8006124, 0x7FFFFFCFU, 0x40000001U),
EMIT_MASKWRITE(0xF800612C, 0x000FFFFFU, 0x0002A81FU),
EMIT_MASKWRITE(0xF8006130, 0x000FFFFFU, 0x00029822U),
EMIT_MASKWRITE(0xF8006134, 0x000FFFFFU, 0x00026C10U),
EMIT_MASKWRITE(0xF8006138, 0x000FFFFFU, 0x00026013U),
EMIT_MASKWRITE(0xF8006140, 0x000FFFFFU, 0x00000035U),
EMIT_MASKWRITE(0xF8006144, 0x000FFFFFU, 0x00000035U),
EMIT_MASKWRITE(0xF8006148, 0x000FFFFFU, 0x00000035U),
EMIT_MASKWRITE(0xF800614C, 0x000FFFFFU, 0x00000035U),
EMIT_MASKWRITE(0xF8006154, 0x000FFFFFU, 0x0000009FU),
EMIT_MASKWRITE(0xF8006158, 0x000FFFFFU, 0x000000A2U),
EMIT_MASKWRITE(0xF800615C, 0x000FFFFFU, 0x00000090U),
EMIT_MASKWRITE(0xF8006160, 0x000FFFFFU, 0x00000093U),
EMIT_MASKWRITE(0xF8006168, 0x001FFFFFU, 0x000000FFU),
EMIT_MASKWRITE(0xF800616C, 0x001FFFFFU, 0x000000FBU),
EMIT_MASKWRITE(0xF8006170, 0x001FFFFFU, 0x000000F0U),
EMIT_MASKWRITE(0xF8006174, 0x001FFFFFU, 0x000000EDU),
EMIT_MASKWRITE(0xF800617C, 0x000FFFFFU, 0x000000DFU),
EMIT_MASKWRITE(0xF8006180, 0x000FFFFFU, 0x000000E2U),
EMIT_MASKWRITE(0xF8006184, 0x000FFFFFU, 0x000000D0U),
EMIT_MASKWRITE(0xF8006188, 0x000FFFFFU, 0x000000D3U),
EMIT_MASKWRITE(0xF8006190, 0x6FFFFEFEU, 0x00040080U),
EMIT_MASKWRITE(0xF8006194, 0x000FFFFFU, 0x0001FC82U),
EMIT_MASKWRITE(0xF8006204, 0xFFFFFFFFU, 0x00000000U),
EMIT_MASKWRITE(0xF8006208, 0x000703FFU, 0x000003FFU),
EMIT_MASKWRITE(0xF800620C, 0x000703FFU, 0x000003FFU),
EMIT_MASKWRITE(0xF8006210, 0x000703FFU, 0x000003FFU),
EMIT_MASKWRITE(0xF8006214, 0x000703FFU, 0x000003FFU),
EMIT_MASKWRITE(0xF8006218, 0x000F03FFU, 0x000003FFU),
EMIT_MASKWRITE(0xF800621C, 0x000F03FFU, 0x000003FFU),
EMIT_MASKWRITE(0xF8006220, 0x000F03FFU, 0x000003FFU),
EMIT_MASKWRITE(0xF8006224, 0x000F03FFU, 0x000003FFU),
EMIT_MASKWRITE(0xF80062A8, 0x00000FF5U, 0x00000000U),
EMIT_MASKWRITE(0xF80062AC, 0xFFFFFFFFU, 0x00000000U),
EMIT_MASKWRITE(0xF80062B0, 0x003FFFFFU, 0x00005125U),
EMIT_MASKWRITE(0xF80062B4, 0x0003FFFFU, 0x000012A8U),
EMIT_MASKPOLL(0xF8000B74, 0x00002000U),
EMIT_MASKWRITE(0xF8006000, 0x0001FFFFU, 0x00000081U),
EMIT_MASKPOLL(0xF8006054, 0x00000007U),
EMIT_EXIT(),
};
static unsigned long ps7_mio_init_data[] = {
EMIT_WRITE(0xF8000008, 0x0000DF0DU),
EMIT_MASKWRITE(0xF8000B40, 0x00000FFFU, 0x00000600U),
EMIT_MASKWRITE(0xF8000B44, 0x00000FFFU, 0x00000600U),
EMIT_MASKWRITE(0xF8000B48, 0x00000FFFU, 0x00000672U),
EMIT_MASKWRITE(0xF8000B4C, 0x00000FFFU, 0x00000672U),
EMIT_MASKWRITE(0xF8000B50, 0x00000FFFU, 0x00000674U),
EMIT_MASKWRITE(0xF8000B54, 0x00000FFFU, 0x00000674U),
EMIT_MASKWRITE(0xF8000B58, 0x00000FFFU, 0x00000600U),
EMIT_MASKWRITE(0xF8000B5C, 0xFFFFFFFFU, 0x0018C61CU),
EMIT_MASKWRITE(0xF8000B60, 0xFFFFFFFFU, 0x00F9861CU),
EMIT_MASKWRITE(0xF8000B64, 0xFFFFFFFFU, 0x00F9861CU),
EMIT_MASKWRITE(0xF8000B68, 0xFFFFFFFFU, 0x00F9861CU),
EMIT_MASKWRITE(0xF8000B6C, 0x00007FFFU, 0x00000260U),
EMIT_MASKWRITE(0xF8000B70, 0x00000001U, 0x00000001U),
EMIT_MASKWRITE(0xF8000B70, 0x00000021U, 0x00000020U),
EMIT_MASKWRITE(0xF8000B70, 0x07FEFFFFU, 0x00000823U),
EMIT_MASKWRITE(0xF8000700, 0x00003FFFU, 0x00001600U),
EMIT_MASKWRITE(0xF8000704, 0x00003FFFU, 0x00000602U),
EMIT_MASKWRITE(0xF8000708, 0x00003FFFU, 0x00000602U),
EMIT_MASKWRITE(0xF800070C, 0x00003FFFU, 0x00000602U),
EMIT_MASKWRITE(0xF8000710, 0x00003FFFU, 0x00000602U),
EMIT_MASKWRITE(0xF8000714, 0x00003FFFU, 0x00000602U),
EMIT_MASKWRITE(0xF8000718, 0x00003FFFU, 0x00000602U),
EMIT_MASKWRITE(0xF800071C, 0x00003FFFU, 0x00000600U),
EMIT_MASKWRITE(0xF8000720, 0x00003FFFU, 0x00000602U),
EMIT_MASKWRITE(0xF8000724, 0x00003FFFU, 0x00000600U),
EMIT_MASKWRITE(0xF8000728, 0x00003FFFU, 0x000016E1U),
EMIT_MASKWRITE(0xF800072C, 0x00003FFFU, 0x000016E0U),
EMIT_MASKWRITE(0xF8000730, 0x00003FFFU, 0x00001640U),
EMIT_MASKWRITE(0xF8000734, 0x00003FFFU, 0x00001640U),
EMIT_MASKWRITE(0xF8000738, 0x00003FFFU, 0x00001621U),
EMIT_MASKWRITE(0xF800073C, 0x00003FFFU, 0x00001620U),
EMIT_MASKWRITE(0xF8000740, 0x00003FFFU, 0x00001202U),
EMIT_MASKWRITE(0xF8000744, 0x00003FFFU, 0x00001202U),
EMIT_MASKWRITE(0xF8000748, 0x00003FFFU, 0x00001202U),
EMIT_MASKWRITE(0xF800074C, 0x00003FFFU, 0x00001202U),
EMIT_MASKWRITE(0xF8000750, 0x00003FFFU, 0x00001202U),
EMIT_MASKWRITE(0xF8000754, 0x00003FFFU, 0x00001202U),
EMIT_MASKWRITE(0xF8000758, 0x00003FFFU, 0x00001203U),
EMIT_MASKWRITE(0xF800075C, 0x00003FFFU, 0x00001203U),
EMIT_MASKWRITE(0xF8000760, 0x00003FFFU, 0x00001203U),
EMIT_MASKWRITE(0xF8000764, 0x00003FFFU, 0x00001203U),
EMIT_MASKWRITE(0xF8000768, 0x00003FFFU, 0x00001203U),
EMIT_MASKWRITE(0xF800076C, 0x00003FFFU, 0x00001203U),
EMIT_MASKWRITE(0xF8000770, 0x00003FFFU, 0x00001204U),
EMIT_MASKWRITE(0xF8000774, 0x00003FFFU, 0x00001205U),
EMIT_MASKWRITE(0xF8000778, 0x00003FFFU, 0x00001204U),
EMIT_MASKWRITE(0xF800077C, 0x00003FFFU, 0x00001205U),
EMIT_MASKWRITE(0xF8000780, 0x00003FFFU, 0x00001204U),
EMIT_MASKWRITE(0xF8000784, 0x00003FFFU, 0x00001204U),
EMIT_MASKWRITE(0xF8000788, 0x00003FFFU, 0x00001204U),
EMIT_MASKWRITE(0xF800078C, 0x00003FFFU, 0x00001204U),
EMIT_MASKWRITE(0xF8000790, 0x00003FFFU, 0x00001205U),
EMIT_MASKWRITE(0xF8000794, 0x00003FFFU, 0x00001204U),
EMIT_MASKWRITE(0xF8000798, 0x00003FFFU, 0x00001204U),
EMIT_MASKWRITE(0xF800079C, 0x00003FFFU, 0x00001204U),
EMIT_MASKWRITE(0xF80007A0, 0x00003FFFU, 0x00001280U),
EMIT_MASKWRITE(0xF80007A4, 0x00003FFFU, 0x00001280U),
EMIT_MASKWRITE(0xF80007A8, 0x00003FFFU, 0x00001280U),
EMIT_MASKWRITE(0xF80007AC, 0x00003FFFU, 0x00001280U),
EMIT_MASKWRITE(0xF80007B0, 0x00003FFFU, 0x00001280U),
EMIT_MASKWRITE(0xF80007B4, 0x00003FFFU, 0x00001280U),
EMIT_MASKWRITE(0xF80007B8, 0x00003F01U, 0x00000201U),
EMIT_MASKWRITE(0xF80007BC, 0x00003F01U, 0x00000201U),
EMIT_MASKWRITE(0xF80007C0, 0x00003FFFU, 0x000012E0U),
EMIT_MASKWRITE(0xF80007C4, 0x00003FFFU, 0x000012E1U),
EMIT_MASKWRITE(0xF80007C8, 0x00003FFFU, 0x00000200U),
EMIT_MASKWRITE(0xF80007CC, 0x00003FFFU, 0x00000200U),
EMIT_MASKWRITE(0xF80007D0, 0x00003FFFU, 0x00001280U),
EMIT_MASKWRITE(0xF80007D4, 0x00003FFFU, 0x00001280U),
EMIT_MASKWRITE(0xF8000830, 0x003F003FU, 0x002E002FU),
EMIT_WRITE(0xF8000004, 0x0000767BU),
EMIT_EXIT(),
};
static unsigned long ps7_peripherals_init_data[] = {
EMIT_WRITE(0xF8000008, 0x0000DF0DU),
EMIT_MASKWRITE(0xF8000B48, 0x00000180U, 0x00000180U),
EMIT_MASKWRITE(0xF8000B4C, 0x00000180U, 0x00000180U),
EMIT_MASKWRITE(0xF8000B50, 0x00000180U, 0x00000180U),
EMIT_MASKWRITE(0xF8000B54, 0x00000180U, 0x00000180U),
EMIT_WRITE(0xF8000004, 0x0000767BU),
EMIT_MASKWRITE(0xE000D000, 0x00080000U, 0x00080000U),
EMIT_MASKWRITE(0xF8007000, 0x20000000U, 0x00000000U),
EMIT_MASKWRITE(0xE000A244, 0x003FFFFFU, 0x00080000U),
EMIT_MASKWRITE(0xE000A00C, 0x003F003FU, 0x00370008U),
EMIT_MASKWRITE(0xE000A248, 0x003FFFFFU, 0x00080000U),
EMIT_MASKWRITE(0xE000A00C, 0x003F003FU, 0x00370000U),
EMIT_MASKDELAY(0xF8F00200, 1),
EMIT_MASKWRITE(0xE000A00C, 0x003F003FU, 0x00370008U),
EMIT_EXIT(),
};
static unsigned long ps7_post_config_0[] = {
EMIT_WRITE(0xF8000008, 0x0000DF0DU),
EMIT_MASKWRITE(0xF8000900, 0x0000000FU, 0x0000000FU),
EMIT_MASKWRITE(0xF8000240, 0xFFFFFFFFU, 0x00000000U),
EMIT_WRITE(0xF8000004, 0x0000767BU),
EMIT_EXIT(),
};
int ps7_post_config(void)
{
return ps7_config(ps7_post_config_0);
}
int ps7_init(void)
{
int ret;
ret = ps7_config(ps7_mio_init_data);
if (ret != PS7_INIT_SUCCESS)
return ret;
ret = ps7_config(ps7_pll_init_data);
if (ret != PS7_INIT_SUCCESS)
return ret;
ret = ps7_config(ps7_clock_init_data);
if (ret != PS7_INIT_SUCCESS)
return ret;
ret = ps7_config(ps7_ddr_init_data);
if (ret != PS7_INIT_SUCCESS)
return ret;
ret = ps7_config(ps7_peripherals_init_data);
if (ret != PS7_INIT_SUCCESS)
return ret;
return PS7_INIT_SUCCESS;
}

View File

@@ -3,6 +3,7 @@ M: Michal Simek <michal.simek@xilinx.com>
S: Maintained
F: arch/arm/dts/zynqmp-*
F: arch/arm/dts/avnet-ultra96*
F: board/xilinx/common/
F: board/xilinx/zynqmp/
F: include/configs/xilinx_zynqmp*
F: configs/xilinx_zynqmp*

View File

@@ -4,7 +4,6 @@
# Michal Simek <michal.simek@xilinx.com>
obj-y := zynqmp.o
obj-y += ../common/board.o
ifneq ($(CONFIG_XILINX_PS_INIT_FILE),"")
PS_INIT_FILE := $(shell cd $(srctree); readlink -f $(CONFIG_XILINX_PS_INIT_FILE))

View File

@@ -9,11 +9,22 @@
#include <cpu_func.h>
#include <env.h>
#include <malloc.h>
#include <memalign.h>
#include <zynqmp_firmware.h>
#include <asm/arch/hardware.h>
#include <asm/arch/sys_proto.h>
#include <asm/io.h>
struct aes {
u64 srcaddr;
u64 ivaddr;
u64 keyaddr;
u64 dstaddr;
u64 len;
u64 op;
u64 keysrc;
};
static int do_zynqmp_verify_secure(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
@@ -107,6 +118,66 @@ static int do_zynqmp_mmio_write(struct cmd_tbl *cmdtp, int flag, int argc,
return ret;
}
static int do_zynqmp_aes(struct cmd_tbl *cmdtp, int flag, int argc,
char * const argv[])
{
ALLOC_CACHE_ALIGN_BUFFER(struct aes, aes, 1);
int ret;
u32 ret_payload[PAYLOAD_ARG_CNT];
if (zynqmp_firmware_version() <= PMUFW_V1_0) {
puts("ERR: PMUFW v1.0 or less is detected\n");
puts("ERR: Encrypt/Decrypt feature is not supported\n");
puts("ERR: Please upgrade PMUFW\n");
return CMD_RET_FAILURE;
}
if (argc < cmdtp->maxargs - 1)
return CMD_RET_USAGE;
aes->srcaddr = simple_strtoul(argv[2], NULL, 16);
aes->ivaddr = simple_strtoul(argv[3], NULL, 16);
aes->len = simple_strtoul(argv[4], NULL, 16);
aes->op = simple_strtoul(argv[5], NULL, 16);
aes->keysrc = simple_strtoul(argv[6], NULL, 16);
aes->dstaddr = simple_strtoul(argv[7], NULL, 16);
flush_dcache_range((ulong)aes, (ulong)(aes) +
roundup(sizeof(struct aes), ARCH_DMA_MINALIGN));
if (aes->srcaddr && aes->ivaddr && aes->dstaddr) {
flush_dcache_range(aes->srcaddr,
(aes->srcaddr +
roundup(aes->len, ARCH_DMA_MINALIGN)));
flush_dcache_range(aes->ivaddr,
(aes->ivaddr +
roundup(IV_SIZE, ARCH_DMA_MINALIGN)));
flush_dcache_range(aes->dstaddr,
(aes->dstaddr +
roundup(aes->len, ARCH_DMA_MINALIGN)));
}
if (aes->keysrc == 0) {
if (argc < cmdtp->maxargs)
return CMD_RET_USAGE;
aes->keyaddr = simple_strtoul(argv[8], NULL, 16);
if (aes->keyaddr)
flush_dcache_range(aes->keyaddr,
(aes->keyaddr +
roundup(KEY_PTR_LEN,
ARCH_DMA_MINALIGN)));
}
ret = xilinx_pm_request(PM_SECURE_AES, upper_32_bits((ulong)aes),
lower_32_bits((ulong)aes), 0, 0, ret_payload);
if (ret || ret_payload[1])
printf("Failed: AES op status:0x%x, errcode:0x%x\n",
ret, ret_payload[1]);
return ret;
}
#ifdef CONFIG_DEFINE_TCM_OCM_MMAP
static int do_zynqmp_tcm_init(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
@@ -148,11 +219,145 @@ static int do_zynqmp_pmufw(struct cmd_tbl *cmdtp, int flag, int argc,
return 0;
}
static int do_zynqmp_rsa(struct cmd_tbl *cmdtp, int flag, int argc,
char * const argv[])
{
u64 srcaddr, mod, exp;
u32 srclen, rsaop, size, ret_payload[PAYLOAD_ARG_CNT];
int ret;
if (argc != cmdtp->maxargs)
return CMD_RET_USAGE;
if (zynqmp_firmware_version() <= PMUFW_V1_0) {
puts("ERR: PMUFW v1.0 or less is detected\n");
puts("ERR: Encrypt/Decrypt feature is not supported\n");
puts("ERR: Please upgrade PMUFW\n");
return CMD_RET_FAILURE;
}
srcaddr = simple_strtoul(argv[2], NULL, 16);
srclen = simple_strtoul(argv[3], NULL, 16);
if (srclen != RSA_KEY_SIZE) {
puts("ERR: srclen should be equal to 0x200(512 bytes)\n");
return CMD_RET_USAGE;
}
mod = simple_strtoul(argv[4], NULL, 16);
exp = simple_strtoul(argv[5], NULL, 16);
rsaop = simple_strtoul(argv[6], NULL, 16);
if (!(rsaop == 0 || rsaop == 1)) {
puts("ERR: rsaop should be either 0 or 1\n");
return CMD_RET_USAGE;
}
memcpy((void *)srcaddr + srclen, (void *)mod, MODULUS_LEN);
/*
* For encryption we load public exponent (key size 4096-bits),
* for decryption we load private exponent (32-bits)
*/
if (rsaop) {
memcpy((void *)srcaddr + srclen + MODULUS_LEN,
(void *)exp, PUB_EXPO_LEN);
size = srclen + MODULUS_LEN + PUB_EXPO_LEN;
} else {
memcpy((void *)srcaddr + srclen + MODULUS_LEN,
(void *)exp, PRIV_EXPO_LEN);
size = srclen + MODULUS_LEN + PRIV_EXPO_LEN;
}
flush_dcache_range((ulong)srcaddr,
(ulong)(srcaddr) + roundup(size, ARCH_DMA_MINALIGN));
ret = xilinx_pm_request(PM_SECURE_RSA, upper_32_bits((ulong)srcaddr),
lower_32_bits((ulong)srcaddr), srclen, rsaop,
ret_payload);
if (ret || ret_payload[1]) {
printf("Failed: RSA status:0x%x, errcode:0x%x\n",
ret, ret_payload[1]);
return CMD_RET_FAILURE;
}
return CMD_RET_SUCCESS;
}
static int do_zynqmp_sha3(struct cmd_tbl *cmdtp, int flag,
int argc, char * const argv[])
{
u64 srcaddr, hashaddr;
u32 srclen, ret_payload[PAYLOAD_ARG_CNT];
int ret;
if (argc > cmdtp->maxargs || argc < (cmdtp->maxargs - 1))
return CMD_RET_USAGE;
if (zynqmp_firmware_version() <= PMUFW_V1_0) {
puts("ERR: PMUFW v1.0 or less is detected\n");
puts("ERR: Encrypt/Decrypt feature is not supported\n");
puts("ERR: Please upgrade PMUFW\n");
return CMD_RET_FAILURE;
}
srcaddr = simple_strtoul(argv[2], NULL, 16);
srclen = simple_strtoul(argv[3], NULL, 16);
if (argc == 5) {
hashaddr = simple_strtoul(argv[4], NULL, 16);
flush_dcache_range(hashaddr,
hashaddr + roundup(ZYNQMP_SHA3_SIZE,
ARCH_DMA_MINALIGN));
} else {
hashaddr = srcaddr;
}
/* Check srcaddr or srclen != 0 */
if (!srcaddr || !srclen) {
puts("ERR: srcaddr & srclen should not be 0\n");
return CMD_RET_USAGE;
}
flush_dcache_range(srcaddr,
srcaddr + roundup(srclen, ARCH_DMA_MINALIGN));
ret = xilinx_pm_request(PM_SECURE_SHA, 0, 0, 0,
ZYNQMP_SHA3_INIT, ret_payload);
if (ret || ret_payload[1]) {
printf("Failed: SHA INIT status:0x%x, errcode:0x%x\n",
ret, ret_payload[1]);
return CMD_RET_FAILURE;
}
ret = xilinx_pm_request(PM_SECURE_SHA, upper_32_bits((ulong)srcaddr),
lower_32_bits((ulong)srcaddr),
srclen, ZYNQMP_SHA3_UPDATE, ret_payload);
if (ret || ret_payload[1]) {
printf("Failed: SHA UPDATE status:0x%x, errcode:0x%x\n",
ret, ret_payload[1]);
return CMD_RET_FAILURE;
}
ret = xilinx_pm_request(PM_SECURE_SHA, upper_32_bits((ulong)hashaddr),
lower_32_bits((ulong)hashaddr),
ZYNQMP_SHA3_SIZE, ZYNQMP_SHA3_FINAL,
ret_payload);
if (ret || ret_payload[1]) {
printf("Failed: SHA FINAL status:0x%x, errcode:0x%x\n",
ret, ret_payload[1]);
return CMD_RET_FAILURE;
}
return CMD_RET_SUCCESS;
}
static struct cmd_tbl cmd_zynqmp_sub[] = {
U_BOOT_CMD_MKENT(secure, 5, 0, do_zynqmp_verify_secure, "", ""),
U_BOOT_CMD_MKENT(pmufw, 4, 0, do_zynqmp_pmufw, "", ""),
U_BOOT_CMD_MKENT(mmio_read, 3, 0, do_zynqmp_mmio_read, "", ""),
U_BOOT_CMD_MKENT(mmio_write, 5, 0, do_zynqmp_mmio_write, "", ""),
U_BOOT_CMD_MKENT(aes, 9, 0, do_zynqmp_aes, "", ""),
U_BOOT_CMD_MKENT(rsa, 7, 0, do_zynqmp_rsa, "", ""),
U_BOOT_CMD_MKENT(sha3, 5, 0, do_zynqmp_sha3, "", ""),
#ifdef CONFIG_DEFINE_TCM_OCM_MMAP
U_BOOT_CMD_MKENT(tcminit, 3, 0, do_zynqmp_tcm_init, "", ""),
#endif
@@ -196,6 +401,14 @@ static char zynqmp_help_text[] =
"zynqmp mmio_read address - read from address\n"
"zynqmp mmio_write address mask value - write value after masking to\n"
" address\n"
"zynqmp aes srcaddr ivaddr len aesop keysrc dstaddr [keyaddr] -\n"
" Encrypts or decrypts blob of data at src address and puts it\n"
" back to dstaddr using key and iv at keyaddr and ivaddr\n"
" respectively. keysrc value specifies from which source key\n"
" has to be used, it can be User/Device/PUF key. A value of 0\n"
" for KUP(user key),1 for DeviceKey and 2 for PUF key. The\n"
" aesop value specifies the operation which can be 0 for\n"
" decrypt and 1 for encrypt operation\n"
#ifdef CONFIG_DEFINE_TCM_OCM_MMAP
"zynqmp tcminit mode - Initialize the TCM with zeros. TCM needs to be\n"
" initialized before accessing to avoid ECC\n"
@@ -204,11 +417,24 @@ static char zynqmp_help_text[] =
" lock(0)/split(1)\n"
#endif
"zynqmp pmufw address size - load PMU FW configuration object\n"
"zynqmp rsa srcaddr srclen mod exp rsaop -\n"
" Performs RSA encryption and RSA decryption on blob of data\n"
" at srcaddr and puts it back in srcaddr using modulus and\n"
" public or private exponent\n"
" srclen : must be key size(4096 bits)\n"
" exp : private key exponent for RSA decryption(4096 bits)\n"
" public key exponent for RSA encryption(32 bits)\n"
" rsaop : 0 for RSA Decryption, 1 for RSA Encryption\n"
"zynqmp sha3 srcaddr srclen [key_addr] -\n"
" Generates sha3 hash value for data blob at srcaddr and puts\n"
" 48 bytes hash value into srcaddr\n"
" Optional key_addr can be specified for saving sha3 hash value\n"
" Note: srcaddr/srclen should not be 0\n"
;
#endif
U_BOOT_CMD(
zynqmp, 5, 1, do_zynqmp,
zynqmp, 9, 1, do_zynqmp,
"ZynqMP sub-system",
zynqmp_help_text
)

View File

@@ -6,8 +6,10 @@
*/
#include <common.h>
#include <zynqmp_tap_delay.h>
#include <asm/arch/sys_proto.h>
#include <linux/delay.h>
#include <mmc.h>
#define SD_DLL_CTRL 0xFF180358
#define SD_ITAP_DLY 0xFF180314
@@ -25,43 +27,9 @@
#define SD1_ITAPDLYENA_MASK 0x01000000
#define SD1_ITAPDLYENA 0x01000000
#define SD0_ITAPDLYSEL_MASK 0x000000FF
#define SD0_ITAPDLYSEL_HSD 0x00000015
#define SD0_ITAPDLYSEL_SD_DDR50 0x0000003D
#define SD0_ITAPDLYSEL_MMC_DDR50 0x00000012
#define SD1_ITAPDLYSEL_MASK 0x00FF0000
#define SD1_ITAPDLYSEL_HSD 0x00150000
#define SD1_ITAPDLYSEL_SD_DDR50 0x003D0000
#define SD1_ITAPDLYSEL_MMC_DDR50 0x00120000
#define SD0_OTAPDLYSEL_MASK 0x0000003F
#define SD0_OTAPDLYSEL_MMC_HSD 0x00000006
#define SD0_OTAPDLYSEL_SD_HSD 0x00000005
#define SD0_OTAPDLYSEL_SDR50 0x00000003
#define SD0_OTAPDLYSEL_SDR104_B0 0x00000003
#define SD0_OTAPDLYSEL_SDR104_B2 0x00000002
#define SD0_OTAPDLYSEL_SD_DDR50 0x00000004
#define SD0_OTAPDLYSEL_MMC_DDR50 0x00000006
#define SD1_OTAPDLYSEL_MASK 0x003F0000
#define SD1_OTAPDLYSEL_MMC_HSD 0x00060000
#define SD1_OTAPDLYSEL_SD_HSD 0x00050000
#define SD1_OTAPDLYSEL_SDR50 0x00030000
#define SD1_OTAPDLYSEL_SDR104_B0 0x00030000
#define SD1_OTAPDLYSEL_SDR104_B2 0x00020000
#define SD1_OTAPDLYSEL_SD_DDR50 0x00040000
#define SD1_OTAPDLYSEL_MMC_DDR50 0x00060000
#define MMC_BANK2 0x2
#define MMC_TIMING_UHS_SDR25 1
#define MMC_TIMING_UHS_SDR50 2
#define MMC_TIMING_UHS_SDR104 3
#define MMC_TIMING_UHS_DDR50 4
#define MMC_TIMING_MMC_HS200 5
#define MMC_TIMING_SD_HS 6
#define MMC_TIMING_MMC_DDR52 7
#define MMC_TIMING_MMC_HS 8
void zynqmp_dll_reset(u8 deviceid)
{
@@ -82,149 +50,49 @@ void zynqmp_dll_reset(u8 deviceid)
zynqmp_mmio_write(SD_DLL_CTRL, SD1_DLL_RST_MASK, 0x0);
}
static void arasan_zynqmp_tap_sdr104(u8 deviceid, u8 timing, u8 bank)
void arasan_zynqmp_set_tapdelay(u8 deviceid, u32 itap_delay, u32 otap_delay)
{
if (deviceid == 0) {
/* Program OTAP */
if (bank == MMC_BANK2)
zynqmp_mmio_write(SD_OTAP_DLY, SD0_OTAPDLYSEL_MASK,
SD0_OTAPDLYSEL_SDR104_B2);
else
zynqmp_mmio_write(SD_OTAP_DLY, SD0_OTAPDLYSEL_MASK,
SD0_OTAPDLYSEL_SDR104_B0);
} else {
/* Program OTAP */
if (bank == MMC_BANK2)
zynqmp_mmio_write(SD_OTAP_DLY, SD1_OTAPDLYSEL_MASK,
SD1_OTAPDLYSEL_SDR104_B2);
else
zynqmp_mmio_write(SD_OTAP_DLY, SD1_OTAPDLYSEL_MASK,
SD1_OTAPDLYSEL_SDR104_B0);
}
}
static void arasan_zynqmp_tap_hs(u8 deviceid, u8 timing, u8 bank)
{
if (deviceid == 0) {
/* Program ITAP */
zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN_MASK,
SD0_ITAPCHGWIN);
zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPDLYENA_MASK,
SD0_ITAPDLYENA);
zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPDLYSEL_MASK,
SD0_ITAPDLYSEL_HSD);
zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN_MASK, 0x0);
/* Program OTAP */
if (timing == MMC_TIMING_MMC_HS)
zynqmp_mmio_write(SD_OTAP_DLY, SD0_OTAPDLYSEL_MASK,
SD0_OTAPDLYSEL_MMC_HSD);
else
zynqmp_mmio_write(SD_OTAP_DLY, SD0_OTAPDLYSEL_MASK,
SD0_OTAPDLYSEL_SD_HSD);
} else {
/* Program ITAP */
zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPCHGWIN_MASK,
SD1_ITAPCHGWIN);
zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPDLYENA_MASK,
SD1_ITAPDLYENA);
zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPDLYSEL_MASK,
SD1_ITAPDLYSEL_HSD);
zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPCHGWIN_MASK, 0x0);
/* Program OTAP */
if (timing == MMC_TIMING_MMC_HS)
zynqmp_mmio_write(SD_OTAP_DLY, SD1_OTAPDLYSEL_MASK,
SD1_OTAPDLYSEL_MMC_HSD);
else
zynqmp_mmio_write(SD_OTAP_DLY, SD1_OTAPDLYSEL_MASK,
SD1_OTAPDLYSEL_SD_HSD);
}
}
static void arasan_zynqmp_tap_ddr50(u8 deviceid, u8 timing, u8 bank)
{
if (deviceid == 0) {
/* Program ITAP */
zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN_MASK,
SD0_ITAPCHGWIN);
zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPDLYENA_MASK,
SD0_ITAPDLYENA);
if (timing == MMC_TIMING_UHS_DDR50)
zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPDLYSEL_MASK,
SD0_ITAPDLYSEL_SD_DDR50);
else
zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPDLYSEL_MASK,
SD0_ITAPDLYSEL_MMC_DDR50);
zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN_MASK, 0x0);
/* Program OTAP */
if (timing == MMC_TIMING_UHS_DDR50)
zynqmp_mmio_write(SD_OTAP_DLY, SD0_OTAPDLYSEL_MASK,
SD0_OTAPDLYSEL_SD_DDR50);
else
zynqmp_mmio_write(SD_OTAP_DLY, SD0_OTAPDLYSEL_MASK,
SD0_OTAPDLYSEL_MMC_DDR50);
} else {
/* Program ITAP */
zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPCHGWIN_MASK,
SD1_ITAPCHGWIN);
zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPDLYENA_MASK,
SD1_ITAPDLYENA);
if (timing == MMC_TIMING_UHS_DDR50)
zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPDLYSEL_MASK,
SD1_ITAPDLYSEL_SD_DDR50);
else
zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPDLYSEL_MASK,
SD1_ITAPDLYSEL_MMC_DDR50);
zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPCHGWIN_MASK, 0x0);
/* Program OTAP */
if (timing == MMC_TIMING_UHS_DDR50)
zynqmp_mmio_write(SD_OTAP_DLY, SD1_OTAPDLYSEL_MASK,
SD1_OTAPDLYSEL_SD_DDR50);
else
zynqmp_mmio_write(SD_OTAP_DLY, SD1_OTAPDLYSEL_MASK,
SD1_OTAPDLYSEL_MMC_DDR50);
}
}
static void arasan_zynqmp_tap_sdr50(u8 deviceid, u8 timing, u8 bank)
{
if (deviceid == 0) {
/* Program OTAP */
zynqmp_mmio_write(SD_OTAP_DLY, SD0_OTAPDLYSEL_MASK,
SD0_OTAPDLYSEL_SDR50);
} else {
/* Program OTAP */
zynqmp_mmio_write(SD_OTAP_DLY, SD1_OTAPDLYSEL_MASK,
SD1_OTAPDLYSEL_SDR50);
}
}
void arasan_zynqmp_set_tapdelay(u8 deviceid, u8 timing, u8 bank)
{
if (deviceid == 0)
zynqmp_mmio_write(SD_DLL_CTRL, SD0_DLL_RST_MASK,
SD0_DLL_RST);
else
/* Program ITAP */
if (itap_delay) {
zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN_MASK,
SD0_ITAPCHGWIN);
zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPDLYENA_MASK,
SD0_ITAPDLYENA);
zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPDLYSEL_MASK,
itap_delay);
zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN_MASK,
0x0);
}
/* Program OTAP */
if (otap_delay)
zynqmp_mmio_write(SD_OTAP_DLY, SD0_OTAPDLYSEL_MASK,
otap_delay);
zynqmp_mmio_write(SD_DLL_CTRL, SD0_DLL_RST_MASK, 0x0);
} else {
zynqmp_mmio_write(SD_DLL_CTRL, SD1_DLL_RST_MASK,
SD1_DLL_RST);
/* Program ITAP */
if (itap_delay) {
zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPCHGWIN_MASK,
SD1_ITAPCHGWIN);
zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPDLYENA_MASK,
SD1_ITAPDLYENA);
zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPDLYSEL_MASK,
(itap_delay << 16));
zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPCHGWIN_MASK,
0x0);
}
switch (timing) {
case MMC_TIMING_UHS_SDR25:
arasan_zynqmp_tap_hs(deviceid, timing, bank);
break;
case MMC_TIMING_UHS_SDR50:
arasan_zynqmp_tap_sdr50(deviceid, timing, bank);
break;
case MMC_TIMING_UHS_SDR104:
case MMC_TIMING_MMC_HS200:
arasan_zynqmp_tap_sdr104(deviceid, timing, bank);
break;
case MMC_TIMING_UHS_DDR50:
arasan_zynqmp_tap_ddr50(deviceid, timing, bank);
break;
}
/* Program OTAP */
if (otap_delay)
zynqmp_mmio_write(SD_OTAP_DLY, SD1_OTAPDLYSEL_MASK,
(otap_delay << 16));
if (deviceid == 0)
zynqmp_mmio_write(SD_DLL_CTRL, SD0_DLL_RST_MASK, 0x0);
else
zynqmp_mmio_write(SD_DLL_CTRL, SD1_DLL_RST_MASK, 0x0);
}
}

View File

@@ -40,12 +40,12 @@
#include "pm_cfg_obj.h"
#define ZYNQMP_VERSION_SIZE 7
#define EFUSE_VCU_DIS_MASK 0x100
#define EFUSE_VCU_DIS_SHIFT 8
#define EFUSE_GPU_DIS_MASK 0x20
#define EFUSE_GPU_DIS_SHIFT 5
#define IDCODE2_PL_INIT_MASK 0x200
#define IDCODE2_PL_INIT_SHIFT 9
#define EFUSE_VCU_DIS_MASK 0x100
#define EFUSE_VCU_DIS_SHIFT 8
#define EFUSE_GPU_DIS_MASK 0x20
#define EFUSE_GPU_DIS_SHIFT 5
#define IDCODE2_PL_INIT_MASK 0x200
#define IDCODE2_PL_INIT_SHIFT 9
DECLARE_GLOBAL_DATA_PTR;
@@ -100,7 +100,7 @@ static const struct {
{
.id = 0x04738093,
.device = 9,
.variants = ZYNQMP_VARIANT_EG,
.variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG,
},
{
.id = 0x04740093,
@@ -190,8 +190,13 @@ static char *zynqmp_get_silicon_idcode_name(void)
u32 idcode, idcode2;
char name[ZYNQMP_VERSION_SIZE];
u32 ret_payload[PAYLOAD_ARG_CNT];
int ret;
xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0, ret_payload);
ret = xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0, ret_payload);
if (ret) {
debug("%s: Getting chipid failed\n", __func__);
return "unknown";
}
/*
* Firmware returns:
@@ -204,7 +209,7 @@ static char *zynqmp_get_silicon_idcode_name(void)
idcode = ret_payload[1];
idcode2 = ret_payload[2] >> ZYNQMP_CSU_VERSION_EMPTY_SHIFT;
debug("%s, IDCODE: 0x%0X, IDCODE2: 0x%0X\r\n", __func__, idcode,
debug("%s, IDCODE: 0x%0x, IDCODE2: 0x%0x\r\n", __func__, idcode,
idcode2);
for (i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) {
@@ -216,8 +221,10 @@ static char *zynqmp_get_silicon_idcode_name(void)
return "unknown";
/* Add device prefix to the name */
strncpy(name, "zu", ZYNQMP_VERSION_SIZE);
strncat(&name[2], simple_itoa(zynqmp_devices[i].device), 2);
ret = snprintf(name, ZYNQMP_VERSION_SIZE, "zu%d",
zynqmp_devices[i].device);
if (ret < 0)
return "unknown";
if (zynqmp_devices[i].variants & ZYNQMP_VARIANT_EV) {
/* Devices with EV variant might be EG/CG/EV family */
@@ -321,6 +328,9 @@ int board_init(void)
if (sizeof(CONFIG_ZYNQMP_SPL_PM_CFG_OBJ_FILE) > 1)
zynqmp_pmufw_load_config_object(zynqmp_pm_cfg_obj,
zynqmp_pm_cfg_obj_size);
#else
if (CONFIG_IS_ENABLED(DM_I2C) && CONFIG_IS_ENABLED(I2C_EEPROM))
xilinx_read_eeprom();
#endif
printf("EL Level:\tEL%d\n", current_el());