Commit a2777ecb authored by Marcel Ziswiler's avatar Marcel Ziswiler Committed by Tom Rini

toradex: config block handling

Add Toradex factory configuration block handling. The config block is a
data structure which gets stored to flash during production testing. The
structure holds such information as board resp. hardware revision,
product ID and serial number which is used as the NIC part of the
Ethernet MAC address as well. The config block will be read upon boot by
the show_board_info() function, displayed as part of the board
information and passed to Linux via device tree or ATAGs.
Signed-off-by: default avatarMarcel Ziswiler <marcel.ziswiler@toradex.com>
Acked-by: default avatarMax Krummenacher <max.krummenacher@toradex.com>
parent b05d6806
# Copyright (c) 2016 Toradex, Inc.
# SPDX-License-Identifier: GPL-2.0+
menuconfig TDX_CFG_BLOCK
bool "Enable Toradex config block support"
select OF_BOARD_SETUP
help
The Toradex config block stored production data on the on-module
flash device (NAND, NOR or eMMC). The area is normally preserved by
software and contains the serial number (out of which the MAC
address is generated) and the exact module type.
# Helper config to determine the correct default location of the cfg block
config TDX_HAVE_MMC
bool
config TDX_HAVE_NAND
bool
config TDX_HAVE_NOR
bool
if TDX_CFG_BLOCK
config TDX_CFG_BLOCK_IS_IN_MMC
bool
depends on TDX_HAVE_MMC
default y
config TDX_CFG_BLOCK_IS_IN_NAND
bool
depends on TDX_HAVE_NAND
default y
config TDX_CFG_BLOCK_IS_IN_NOR
bool
depends on TDX_HAVE_NOR
default y
config TDX_CFG_BLOCK_DEV
int "Toradex config block eMMC device ID"
depends on TDX_CFG_BLOCK_IS_IN_MMC
config TDX_CFG_BLOCK_PART
int "Toradex config block eMMC partition ID"
depends on TDX_CFG_BLOCK_IS_IN_MMC
config TDX_CFG_BLOCK_OFFSET
int "Toradex config block offset"
help
Specify the byte offset of the Toradex config block within the flash
device the config block is stored on.
config TDX_CFG_BLOCK_OFFSET2
int "Toradex config block offset, second instance"
default 0
help
Specify the byte offset of the 2nd instance of the Toradex config block
within the flash device the config block is stored on.
Set to 0 on modules which have no 2nd instance.
config TDX_CFG_BLOCK_2ND_ETHADDR
bool "Set the second Ethernet address"
help
For each serial number two Ethernet addresses are available for dual
Ethernet carrier boards. This options enables the code to set the
second Ethernet address as environment variable (eth1addr).
endif
# Copyright (c) 2016 Toradex, Inc.
# SPDX-License-Identifier: GPL-2.0+
# Common for all Toradex modules
ifeq ($(CONFIG_SPL_BUILD),y)
# Necessary to create built-in.o
obj- := __dummy__.o
else
obj-$(CONFIG_TDX_CFG_BLOCK) += tdx-cfg-block.o
obj-y += tdx-common.o
endif
This diff is collapsed.
/*
* Copyright (c) 2016 Toradex, Inc.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _TDX_CFG_BLOCK_H
#define _TDX_CFG_BLOCK_H
#include "tdx-common.h"
struct toradex_hw {
u16 ver_major;
u16 ver_minor;
u16 ver_assembly;
u16 prodid;
};
struct toradex_eth_addr {
u32 oui:24;
u32 nic:24;
} __attribute__((__packed__));
enum {
COLIBRI_PXA270_V1_312MHZ = 1,
COLIBRI_PXA270_V1_520MHZ,
COLIBRI_PXA320,
COLIBRI_PXA300,
COLIBRI_PXA310,
COLIBRI_PXA320_IT,
COLIBRI_PXA300_XT,
COLIBRI_PXA270_312MHZ,
COLIBRI_PXA270_520MHZ,
COLIBRI_VF50, /* not currently on sale */
COLIBRI_VF61,
COLIBRI_VF61_IT,
COLIBRI_VF50_IT,
COLIBRI_IMX6S,
COLIBRI_IMX6DL,
COLIBRI_IMX6S_IT,
COLIBRI_IMX6DL_IT,
COLIBRI_T20_256MB = 20,
COLIBRI_T20_512MB,
COLIBRI_T20_512MB_IT,
COLIBRI_T30,
COLIBRI_T20_256MB_IT,
APALIS_T30_2GB,
APALIS_T30_1GB,
APALIS_IMX6Q,
APALIS_IMX6Q_IT,
APALIS_IMX6D,
COLIBRI_T30_IT,
APALIS_T30_IT,
COLIBRI_IMX7S,
COLIBRI_IMX7D,
APALIS_TK1_2GB,
APALIS_IMX6D_IT,
};
extern const char * const toradex_modules[];
extern bool valid_cfgblock;
extern struct toradex_hw tdx_hw_tag;
extern struct toradex_eth_addr tdx_eth_addr;
extern u32 tdx_serial;
int read_tdx_cfg_block(void);
#endif /* _TDX_CFG_BLOCK_H */
/*
* Copyright (c) 2016 Toradex, Inc.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <g_dnl.h>
#include <libfdt.h>
#include "tdx-cfg-block.h"
#include "tdx-common.h"
#ifdef CONFIG_TDX_CFG_BLOCK
static char tdx_serial_str[9];
static char tdx_board_rev_str[6];
#ifdef CONFIG_REVISION_TAG
u32 get_board_rev(void)
{
/* Check validity */
if (!tdx_hw_tag.ver_major)
return 0;
return ((tdx_hw_tag.ver_major & 0xff) << 8) |
((tdx_hw_tag.ver_minor & 0xf) << 4) |
((tdx_hw_tag.ver_assembly & 0xf) + 0xa);
}
#endif /* CONFIG_TDX_CFG_BLOCK */
#ifdef CONFIG_SERIAL_TAG
void get_board_serial(struct tag_serialnr *serialnr)
{
int array[8];
unsigned int serial = tdx_serial;
int i;
serialnr->low = 0;
serialnr->high = 0;
/* Check validity */
if (serial) {
/*
* Convert to Linux serial number format (hexadecimal coded
* decimal)
*/
i = 7;
while (serial) {
array[i--] = serial % 10;
serial /= 10;
}
while (i >= 0)
array[i--] = 0;
serial = array[0];
for (i = 1; i < 8; i++) {
serial *= 16;
serial += array[i];
}
serialnr->low = serial;
}
}
#endif /* CONFIG_SERIAL_TAG */
int show_board_info(void)
{
unsigned char ethaddr[6];
if (read_tdx_cfg_block()) {
printf("Missing Toradex config block\n");
checkboard();
return 0;
}
/* board serial-number */
sprintf(tdx_serial_str, "%08u", tdx_serial);
sprintf(tdx_board_rev_str, "V%1d.%1d%c",
tdx_hw_tag.ver_major,
tdx_hw_tag.ver_minor,
(char)tdx_hw_tag.ver_assembly + 'A');
setenv("serial#", tdx_serial_str);
/*
* Check if environment contains a valid MAC address,
* set the one from config block if not
*/
if (!eth_getenv_enetaddr("ethaddr", ethaddr))
eth_setenv_enetaddr("ethaddr", (u8 *)&tdx_eth_addr);
#ifdef CONFIG_TDX_CFG_BLOCK_2ND_ETHADDR
if (!eth_getenv_enetaddr("eth1addr", ethaddr)) {
/*
* Secondary MAC address is allocated from block
* 0x100000 higher then the first MAC address
*/
memcpy(ethaddr, &tdx_eth_addr, 6);
ethaddr[3] += 0x10;
eth_setenv_enetaddr("eth1addr", ethaddr);
}
#endif
printf("Model: Toradex %s %s, Serial# %s\n",
toradex_modules[tdx_hw_tag.prodid],
tdx_board_rev_str,
tdx_serial_str);
return 0;
}
#ifdef CONFIG_USBDOWNLOAD_GADGET
int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
{
unsigned short usb_pid;
usb_pid = TORADEX_USB_PRODUCT_NUM_OFFSET + tdx_hw_tag.prodid;
put_unaligned(usb_pid, &dev->idProduct);
return 0;
}
#endif /* CONFIG_USBDOWNLOAD_GADGET */
#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
int ft_board_setup(void *blob, bd_t *bd)
{
if (tdx_serial) {
fdt_setprop(blob, 0, "serial-number", tdx_serial_str,
strlen(tdx_serial_str) + 1);
}
if (tdx_hw_tag.ver_major) {
char prod_id[5];
sprintf(prod_id, "%04u", tdx_hw_tag.prodid);
fdt_setprop(blob, 0, "toradex,product-id", prod_id, 5);
fdt_setprop(blob, 0, "toradex,board-rev", tdx_board_rev_str,
strlen(tdx_board_rev_str) + 1);
}
return 0;
}
#endif
#else /* CONFIG_TDX_CFG_BLOCK */
#ifdef CONFIG_REVISION_TAG
u32 get_board_rev(void)
{
return 0;
}
#endif /* CONFIG_REVISION_TAG */
#ifdef CONFIG_SERIAL_TAG
u32 get_board_serial(void)
{
return 0;
}
#endif /* CONFIG_SERIAL_TAG */
#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
int ft_board_setup(void *blob, bd_t *bd)
{
return 0;
}
#endif
#endif /* CONFIG_TDX_CFG_BLOCK */
/*
* Copyright (c) 2016 Toradex, Inc.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _TDX_COMMON_H
#define _TDX_COMMON_H
#define TORADEX_USB_PRODUCT_NUM_OFFSET 0x4000
#define TDX_USB_VID 0x1B67
#endif /* _TDX_COMMON_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment