diff mbox series

[U-Boot,u-boot-marvell,v3,08/10] board: turris_mox: Read info (and ethaddrs) from OTP

Message ID 20181120120409.12822-8-marek.behun@nic.cz
State Superseded
Delegated to: Stefan Roese
Headers show
Series [U-Boot,u-boot-marvell,v3,01/10] board: turris_mox: Cosmetic restructurization | expand

Commit Message

Marek Behún Nov. 20, 2018, 12:04 p.m. UTC
Add support for reading One-Time Programmable memory via mailbox, which
communicates with CZ.NIC's firmware on the Secure Processor (Cortex-M3)
of Armada 3720.

Display product serial number and additional info, and also set MAC
addresses.

Signed-off-by: Marek Behún <marek.behun@nic.cz>
---
 board/CZ.NIC/turris_mox/Makefile     |   2 +-
 board/CZ.NIC/turris_mox/mox_sp.c     | 133 +++++++++++++++++++++++++++
 board/CZ.NIC/turris_mox/mox_sp.h     |  15 +++
 board/CZ.NIC/turris_mox/turris_mox.c |  54 ++++++++++-
 4 files changed, 201 insertions(+), 3 deletions(-)
 create mode 100644 board/CZ.NIC/turris_mox/mox_sp.c
 create mode 100644 board/CZ.NIC/turris_mox/mox_sp.h

Comments

Stefan Roese Nov. 29, 2018, 1:04 p.m. UTC | #1
On 20.11.18 13:04, Marek Behún wrote:
> Add support for reading One-Time Programmable memory via mailbox, which
> communicates with CZ.NIC's firmware on the Secure Processor (Cortex-M3)
> of Armada 3720.
> 
> Display product serial number and additional info, and also set MAC
> addresses.
> 
> Signed-off-by: Marek Behún <marek.behun@nic.cz>

Reviewed-by: Stefan Roese <sr@denx.de>

Thanks,
Stefan

> ---
>   board/CZ.NIC/turris_mox/Makefile     |   2 +-
>   board/CZ.NIC/turris_mox/mox_sp.c     | 133 +++++++++++++++++++++++++++
>   board/CZ.NIC/turris_mox/mox_sp.h     |  15 +++
>   board/CZ.NIC/turris_mox/turris_mox.c |  54 ++++++++++-
>   4 files changed, 201 insertions(+), 3 deletions(-)
>   create mode 100644 board/CZ.NIC/turris_mox/mox_sp.c
>   create mode 100644 board/CZ.NIC/turris_mox/mox_sp.h
> 
> diff --git a/board/CZ.NIC/turris_mox/Makefile b/board/CZ.NIC/turris_mox/Makefile
> index 619704288b..33a52b63d7 100644
> --- a/board/CZ.NIC/turris_mox/Makefile
> +++ b/board/CZ.NIC/turris_mox/Makefile
> @@ -2,4 +2,4 @@
>   #
>   # Copyright (C) 2018 Marek Behun <marek.behun@nic.cz>
>   
> -obj-y	:= turris_mox.o
> +obj-y	:= turris_mox.o mox_sp.o
> diff --git a/board/CZ.NIC/turris_mox/mox_sp.c b/board/CZ.NIC/turris_mox/mox_sp.c
> new file mode 100644
> index 0000000000..78438227dc
> --- /dev/null
> +++ b/board/CZ.NIC/turris_mox/mox_sp.c
> @@ -0,0 +1,133 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2018 Marek Behun <marek.behun@nic.cz>
> + */
> +
> +#include <common.h>
> +#include <asm/io.h>
> +
> +#define RWTM_CMD_PARAM(i)	(size_t)(0xd00b0000 + (i) * 4)
> +#define RWTM_CMD		0xd00b0040
> +#define RWTM_CMD_RETSTATUS	0xd00b0080
> +#define RWTM_CMD_STATUS(i)	(size_t)(0xd00b0084 + (i) * 4)
> +
> +#define RWTM_HOST_INT_RESET	0xd00b00c8
> +#define RWTM_HOST_INT_MASK	0xd00b00cc
> +#define SP_CMD_COMPLETE		BIT(0)
> +
> +#define MBOX_STS_SUCCESS		(0x0 << 30)
> +#define MBOX_STS_FAIL			(0x1 << 30)
> +#define MBOX_STS_BADCMD			(0x2 << 30)
> +#define MBOX_STS_LATER			(0x3 << 30)
> +#define MBOX_STS_ERROR(s)		((s) & (3 << 30))
> +#define MBOX_STS_VALUE(s)		(((s) >> 10) & 0xfffff)
> +#define MBOX_STS_CMD(s)			((s) & 0x3ff)
> +
> +enum mbox_cmd {
> +	MBOX_CMD_GET_RANDOM	= 1,
> +	MBOX_CMD_BOARD_INFO,
> +	MBOX_CMD_ECDSA_PUB_KEY,
> +	MBOX_CMD_ECDSA_SIGN,
> +
> +	MBOX_CMD_OTP_READ,
> +	MBOX_CMD_OTP_WRITE
> +};
> +
> +static int mbox_do_cmd(enum mbox_cmd cmd, u32 *out, int nout)
> +{
> +	int i;
> +	u32 status;
> +
> +	clrbits_le32(RWTM_HOST_INT_MASK, SP_CMD_COMPLETE);
> +
> +	writel(cmd, RWTM_CMD);
> +
> +	for (i = 0; i < 10; ++i) {
> +		mdelay(10);
> +		if (readl(RWTM_HOST_INT_RESET) & SP_CMD_COMPLETE)
> +			break;
> +	}
> +
> +	if (i == 10) {
> +		/* if timed out, don't read status */
> +		setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE);
> +		return -ETIMEDOUT;
> +	}
> +
> +	for (i = 0; i < nout; ++i)
> +		out[i] = readl(RWTM_CMD_STATUS(i));
> +	status = readl(RWTM_CMD_RETSTATUS);
> +
> +	setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE);
> +
> +	if (MBOX_STS_CMD(status) != cmd)
> +		return -EIO;
> +	else if (MBOX_STS_ERROR(status) == MBOX_STS_FAIL)
> +		return -(int)MBOX_STS_VALUE(status);
> +	else if (MBOX_STS_ERROR(status) != MBOX_STS_SUCCESS)
> +		return -EIO;
> +	else
> +		return MBOX_STS_VALUE(status);
> +}
> +
> +const char *mox_sp_get_ecdsa_public_key(void)
> +{
> +	static char public_key[135];
> +	u32 out[16];
> +	int res;
> +
> +	if (public_key[0])
> +		return public_key;
> +
> +	res = mbox_do_cmd(MBOX_CMD_ECDSA_PUB_KEY, out, 16);
> +	if (res < 0)
> +		return NULL;
> +
> +	sprintf(public_key,
> +		"%06x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x",
> +		(u32)res, out[0], out[1], out[2], out[3], out[4], out[5],
> +		out[6], out[7], out[8], out[9], out[10], out[11], out[12],
> +		out[13], out[14], out[15]);
> +
> +	return public_key;
> +}
> +
> +static inline void res_to_mac(u8 *mac, u32 t1, u32 t2)
> +{
> +	mac[0] = t1 >> 8;
> +	mac[1] = t1;
> +	mac[2] = t2 >> 24;
> +	mac[3] = t2 >> 16;
> +	mac[4] = t2 >> 8;
> +	mac[5] = t2;
> +}
> +
> +int mbox_sp_get_board_info(u64 *sn, u8 *mac1, u8 *mac2, int *bv, int *ram)
> +{
> +	u32 out[8];
> +	int res;
> +
> +	res = mbox_do_cmd(MBOX_CMD_BOARD_INFO, out, 8);
> +	if (res < 0)
> +		return res;
> +
> +	if (sn) {
> +		*sn = out[1];
> +		*sn <<= 32;
> +		*sn |= out[0];
> +	}
> +
> +	if (bv)
> +		*bv = out[2];
> +
> +	if (ram)
> +		*ram = out[3];
> +
> +	if (mac1)
> +		res_to_mac(mac1, out[4], out[5]);
> +
> +	if (mac2)
> +		res_to_mac(mac2, out[6], out[7]);
> +
> +	return 0;
> +}
> diff --git a/board/CZ.NIC/turris_mox/mox_sp.h b/board/CZ.NIC/turris_mox/mox_sp.h
> new file mode 100644
> index 0000000000..49a4ed80ea
> --- /dev/null
> +++ b/board/CZ.NIC/turris_mox/mox_sp.h
> @@ -0,0 +1,15 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (C) 2018 Marek Behun <marek.behun@nic.cz>
> + */
> +
> +#ifndef _BOARD_CZNIC_TURRIS_MOX_MOX_SP_H_
> +#define _BOARD_CZNIC_TURRIS_MOX_MOX_SP_H_
> +
> +#include <common.h>
> +
> +const char *mox_sp_get_ecdsa_public_key(void);
> +int mbox_sp_get_board_info(u64 *sn, u8 *mac1, u8 *mac2, int *bv,
> +			   int *ram);
> +
> +#endif /* _BOARD_CZNIC_TURRIS_MOX_MOX_SP_H_ */
> diff --git a/board/CZ.NIC/turris_mox/turris_mox.c b/board/CZ.NIC/turris_mox/turris_mox.c
> index 39c26416a7..89b3cd2ce0 100644
> --- a/board/CZ.NIC/turris_mox/turris_mox.c
> +++ b/board/CZ.NIC/turris_mox/turris_mox.c
> @@ -19,6 +19,8 @@
>   #include <wdt.h>
>   #endif
>   
> +#include "mox_sp.h"
> +
>   #define MAX_MOX_MODULES		10
>   
>   #define MOX_MODULE_SFP		0x1
> @@ -366,6 +368,49 @@ static int get_reset_gpio(struct gpio_desc *reset_gpio)
>   	return 0;
>   }
>   
> +int misc_init_r(void)
> +{
> +	int ret;
> +	u8 mac1[6], mac2[6];
> +
> +	ret = mbox_sp_get_board_info(NULL, mac1, mac2, NULL, NULL);
> +	if (ret < 0) {
> +		printf("Cannot read data from OTP!\n");
> +		return 0;
> +	}
> +
> +	if (is_valid_ethaddr(mac1) && !env_get("ethaddr"))
> +		eth_env_set_enetaddr("ethaddr", mac1);
> +
> +	if (is_valid_ethaddr(mac2) && !env_get("eth1addr"))
> +		eth_env_set_enetaddr("eth1addr", mac2);
> +
> +	return 0;
> +}
> +
> +static void mox_print_info(void)
> +{
> +	int ret, board_version, ram_size;
> +	u64 serial_number;
> +	const char *pub_key;
> +
> +	ret = mbox_sp_get_board_info(&serial_number, NULL, NULL, &board_version,
> +				     &ram_size);
> +	if (ret < 0)
> +		return;
> +
> +	printf("Turris Mox:\n");
> +	printf("  Board version: %i\n", board_version);
> +	printf("  RAM size: %i MiB\n", ram_size);
> +	printf("  Serial Number: %016llX\n", serial_number);
> +
> +	pub_key = mox_sp_get_ecdsa_public_key();
> +	if (pub_key)
> +		printf("  ECDSA Public Key: %s\n", pub_key);
> +	else
> +		printf("Cannot read ECDSA Public Key\n");
> +}
> +
>   int last_stage_init(void)
>   {
>   	int ret, i;
> @@ -374,14 +419,19 @@ int last_stage_init(void)
>   	struct mii_dev *bus;
>   	struct gpio_desc reset_gpio = {};
>   
> +	mox_print_info();
> +
>   	ret = mox_get_topology(&topology, &module_count, &is_sd);
>   	if (ret) {
>   		printf("Cannot read module topology!\n");
>   		return 0;
>   	}
>   
> -	printf("Found Turris Mox %s version\n", is_sd ? "SD" : "eMMC");
> -	printf("Module Topology:\n");
> +	printf("  SD/eMMC version: %s\n", is_sd ? "SD" : "eMMC");
> +
> +	if (module_count)
> +		printf("Module Topology:\n");
> +
>   	for (i = 0; i < module_count; ++i) {
>   		switch (topology[i]) {
>   		case MOX_MODULE_SFP:
> 

Viele Grüße,
Stefan
diff mbox series

Patch

diff --git a/board/CZ.NIC/turris_mox/Makefile b/board/CZ.NIC/turris_mox/Makefile
index 619704288b..33a52b63d7 100644
--- a/board/CZ.NIC/turris_mox/Makefile
+++ b/board/CZ.NIC/turris_mox/Makefile
@@ -2,4 +2,4 @@ 
 #
 # Copyright (C) 2018 Marek Behun <marek.behun@nic.cz>
 
-obj-y	:= turris_mox.o
+obj-y	:= turris_mox.o mox_sp.o
diff --git a/board/CZ.NIC/turris_mox/mox_sp.c b/board/CZ.NIC/turris_mox/mox_sp.c
new file mode 100644
index 0000000000..78438227dc
--- /dev/null
+++ b/board/CZ.NIC/turris_mox/mox_sp.c
@@ -0,0 +1,133 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Marek Behun <marek.behun@nic.cz>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#define RWTM_CMD_PARAM(i)	(size_t)(0xd00b0000 + (i) * 4)
+#define RWTM_CMD		0xd00b0040
+#define RWTM_CMD_RETSTATUS	0xd00b0080
+#define RWTM_CMD_STATUS(i)	(size_t)(0xd00b0084 + (i) * 4)
+
+#define RWTM_HOST_INT_RESET	0xd00b00c8
+#define RWTM_HOST_INT_MASK	0xd00b00cc
+#define SP_CMD_COMPLETE		BIT(0)
+
+#define MBOX_STS_SUCCESS		(0x0 << 30)
+#define MBOX_STS_FAIL			(0x1 << 30)
+#define MBOX_STS_BADCMD			(0x2 << 30)
+#define MBOX_STS_LATER			(0x3 << 30)
+#define MBOX_STS_ERROR(s)		((s) & (3 << 30))
+#define MBOX_STS_VALUE(s)		(((s) >> 10) & 0xfffff)
+#define MBOX_STS_CMD(s)			((s) & 0x3ff)
+
+enum mbox_cmd {
+	MBOX_CMD_GET_RANDOM	= 1,
+	MBOX_CMD_BOARD_INFO,
+	MBOX_CMD_ECDSA_PUB_KEY,
+	MBOX_CMD_ECDSA_SIGN,
+
+	MBOX_CMD_OTP_READ,
+	MBOX_CMD_OTP_WRITE
+};
+
+static int mbox_do_cmd(enum mbox_cmd cmd, u32 *out, int nout)
+{
+	int i;
+	u32 status;
+
+	clrbits_le32(RWTM_HOST_INT_MASK, SP_CMD_COMPLETE);
+
+	writel(cmd, RWTM_CMD);
+
+	for (i = 0; i < 10; ++i) {
+		mdelay(10);
+		if (readl(RWTM_HOST_INT_RESET) & SP_CMD_COMPLETE)
+			break;
+	}
+
+	if (i == 10) {
+		/* if timed out, don't read status */
+		setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE);
+		return -ETIMEDOUT;
+	}
+
+	for (i = 0; i < nout; ++i)
+		out[i] = readl(RWTM_CMD_STATUS(i));
+	status = readl(RWTM_CMD_RETSTATUS);
+
+	setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE);
+
+	if (MBOX_STS_CMD(status) != cmd)
+		return -EIO;
+	else if (MBOX_STS_ERROR(status) == MBOX_STS_FAIL)
+		return -(int)MBOX_STS_VALUE(status);
+	else if (MBOX_STS_ERROR(status) != MBOX_STS_SUCCESS)
+		return -EIO;
+	else
+		return MBOX_STS_VALUE(status);
+}
+
+const char *mox_sp_get_ecdsa_public_key(void)
+{
+	static char public_key[135];
+	u32 out[16];
+	int res;
+
+	if (public_key[0])
+		return public_key;
+
+	res = mbox_do_cmd(MBOX_CMD_ECDSA_PUB_KEY, out, 16);
+	if (res < 0)
+		return NULL;
+
+	sprintf(public_key,
+		"%06x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x",
+		(u32)res, out[0], out[1], out[2], out[3], out[4], out[5],
+		out[6], out[7], out[8], out[9], out[10], out[11], out[12],
+		out[13], out[14], out[15]);
+
+	return public_key;
+}
+
+static inline void res_to_mac(u8 *mac, u32 t1, u32 t2)
+{
+	mac[0] = t1 >> 8;
+	mac[1] = t1;
+	mac[2] = t2 >> 24;
+	mac[3] = t2 >> 16;
+	mac[4] = t2 >> 8;
+	mac[5] = t2;
+}
+
+int mbox_sp_get_board_info(u64 *sn, u8 *mac1, u8 *mac2, int *bv, int *ram)
+{
+	u32 out[8];
+	int res;
+
+	res = mbox_do_cmd(MBOX_CMD_BOARD_INFO, out, 8);
+	if (res < 0)
+		return res;
+
+	if (sn) {
+		*sn = out[1];
+		*sn <<= 32;
+		*sn |= out[0];
+	}
+
+	if (bv)
+		*bv = out[2];
+
+	if (ram)
+		*ram = out[3];
+
+	if (mac1)
+		res_to_mac(mac1, out[4], out[5]);
+
+	if (mac2)
+		res_to_mac(mac2, out[6], out[7]);
+
+	return 0;
+}
diff --git a/board/CZ.NIC/turris_mox/mox_sp.h b/board/CZ.NIC/turris_mox/mox_sp.h
new file mode 100644
index 0000000000..49a4ed80ea
--- /dev/null
+++ b/board/CZ.NIC/turris_mox/mox_sp.h
@@ -0,0 +1,15 @@ 
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 Marek Behun <marek.behun@nic.cz>
+ */
+
+#ifndef _BOARD_CZNIC_TURRIS_MOX_MOX_SP_H_
+#define _BOARD_CZNIC_TURRIS_MOX_MOX_SP_H_
+
+#include <common.h>
+
+const char *mox_sp_get_ecdsa_public_key(void);
+int mbox_sp_get_board_info(u64 *sn, u8 *mac1, u8 *mac2, int *bv,
+			   int *ram);
+
+#endif /* _BOARD_CZNIC_TURRIS_MOX_MOX_SP_H_ */
diff --git a/board/CZ.NIC/turris_mox/turris_mox.c b/board/CZ.NIC/turris_mox/turris_mox.c
index 39c26416a7..89b3cd2ce0 100644
--- a/board/CZ.NIC/turris_mox/turris_mox.c
+++ b/board/CZ.NIC/turris_mox/turris_mox.c
@@ -19,6 +19,8 @@ 
 #include <wdt.h>
 #endif
 
+#include "mox_sp.h"
+
 #define MAX_MOX_MODULES		10
 
 #define MOX_MODULE_SFP		0x1
@@ -366,6 +368,49 @@  static int get_reset_gpio(struct gpio_desc *reset_gpio)
 	return 0;
 }
 
+int misc_init_r(void)
+{
+	int ret;
+	u8 mac1[6], mac2[6];
+
+	ret = mbox_sp_get_board_info(NULL, mac1, mac2, NULL, NULL);
+	if (ret < 0) {
+		printf("Cannot read data from OTP!\n");
+		return 0;
+	}
+
+	if (is_valid_ethaddr(mac1) && !env_get("ethaddr"))
+		eth_env_set_enetaddr("ethaddr", mac1);
+
+	if (is_valid_ethaddr(mac2) && !env_get("eth1addr"))
+		eth_env_set_enetaddr("eth1addr", mac2);
+
+	return 0;
+}
+
+static void mox_print_info(void)
+{
+	int ret, board_version, ram_size;
+	u64 serial_number;
+	const char *pub_key;
+
+	ret = mbox_sp_get_board_info(&serial_number, NULL, NULL, &board_version,
+				     &ram_size);
+	if (ret < 0)
+		return;
+
+	printf("Turris Mox:\n");
+	printf("  Board version: %i\n", board_version);
+	printf("  RAM size: %i MiB\n", ram_size);
+	printf("  Serial Number: %016llX\n", serial_number);
+
+	pub_key = mox_sp_get_ecdsa_public_key();
+	if (pub_key)
+		printf("  ECDSA Public Key: %s\n", pub_key);
+	else
+		printf("Cannot read ECDSA Public Key\n");
+}
+
 int last_stage_init(void)
 {
 	int ret, i;
@@ -374,14 +419,19 @@  int last_stage_init(void)
 	struct mii_dev *bus;
 	struct gpio_desc reset_gpio = {};
 
+	mox_print_info();
+
 	ret = mox_get_topology(&topology, &module_count, &is_sd);
 	if (ret) {
 		printf("Cannot read module topology!\n");
 		return 0;
 	}
 
-	printf("Found Turris Mox %s version\n", is_sd ? "SD" : "eMMC");
-	printf("Module Topology:\n");
+	printf("  SD/eMMC version: %s\n", is_sd ? "SD" : "eMMC");
+
+	if (module_count)
+		printf("Module Topology:\n");
+
 	for (i = 0; i < module_count; ++i) {
 		switch (topology[i]) {
 		case MOX_MODULE_SFP: