From 3be46f0885a00208629ab9394607bef545d1d5a6 Mon Sep 17 00:00:00 2001 From: Avinash Tahakik Date: Thu, 17 Nov 2016 15:16:45 +0530 Subject: [PATCH 1/4] Add driver to read OTP data Signed-off-by: Avinash Tahakik Signed-off-by: Francois Berder --- drivers/mtd/spi/Makefile | 1 + drivers/mtd/spi/winbond-otp.c | 56 +++++++++++++++++++++++++++++++++++ include/winbond-otp.h | 15 ++++++++++ 3 files changed, 72 insertions(+) create mode 100644 drivers/mtd/spi/winbond-otp.c create mode 100644 include/winbond-otp.h diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile index ff48b25f6f..bf17415409 100644 --- a/drivers/mtd/spi/Makefile +++ b/drivers/mtd/spi/Makefile @@ -16,6 +16,7 @@ endif obj-$(CONFIG_SPI_FLASH) += sf_probe.o #endif obj-$(CONFIG_CMD_SF) += sf.o +obj-$(CONFIG_WINBOND_OTP) += winbond-otp.o obj-$(CONFIG_SPI_FLASH) += sf_ops.o sf_params.o obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o obj-$(CONFIG_SPI_FLASH_MTD) += sf_mtd.o diff --git a/drivers/mtd/spi/winbond-otp.c b/drivers/mtd/spi/winbond-otp.c new file mode 100644 index 0000000000..1470e8c685 --- /dev/null +++ b/drivers/mtd/spi/winbond-otp.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * Author: Avinash Tahakik + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +#include "sf_internal.h" + +/* SPI FLASH opcodes */ + +#define SPINOR_OP_RD_SECURITY_REG 0x48 /* Read security register */ +#define SECURITY_REG_SIZE 256 /* bytes per security register */ + +#define REG1_START_ADDRESS 0X1000 +#define REG2_START_ADDRESS 0X2000 +#define REG3_START_ADDRESS 0X3000 + +#define REG1_END_ADDRESS 0X10FF +#define REG2_END_ADDRESS 0X20FF +#define REG3_END_ADDRESS 0X30FF + +static struct spi_flash *flash; + +static int check_addr_validity(loff_t from, size_t len) +{ + if ((REG1_START_ADDRESS <= from && from + len <= REG1_END_ADDRESS) + || (REG2_START_ADDRESS <= from && from + len <= REG2_END_ADDRESS) + || (REG3_START_ADDRESS <= from && from + len <= REG3_END_ADDRESS)) + return 0; + + return -1; +} + +int read_otp_data(loff_t from, size_t len, char *data) +{ + if (check_addr_validity(from, len)) + return -1; + + if (!flash) + flash = spi_flash_probe(1, 0, CONFIG_SF_DEFAULT_SPEED, + CONFIG_SF_DEFAULT_MODE); + + if (!flash) { + printf("Failed to initialize SPI flash at 1:0\n"); + return -1; + } + + flash->read_cmd = SPINOR_OP_RD_SECURITY_REG; + return spi_flash_cmd_read_ops(flash, from, len, data); +} diff --git a/include/winbond-otp.h b/include/winbond-otp.h new file mode 100644 index 0000000000..c802174047 --- /dev/null +++ b/include/winbond-otp.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2015 Imagination Technologies + * Author: Avinash Tahakik + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef WINBOND_OTP_H +#define WINBOND_OTP_H + +#define MAC_ADDR_LEN 6 + +int read_otp_data(loff_t from, size_t len, char *data); + +#endif From 20b07e3f3713b97a38665297982c4c523495a1dc Mon Sep 17 00:00:00 2001 From: Avinash Tahakik Date: Thu, 17 Nov 2016 15:17:45 +0530 Subject: [PATCH 2/4] Set ethernet mac address read from OTP ethernet MAC address is stored in the OTP, read it and write it into dtb, so kernel can use updated MAC address Signed-off-by: Avinash Tahakik Signed-off-by: Francois Berder --- board/imgtec/pistachio_bub/pistachio.c | 41 +++++++++++++++++++------- include/configs/pistachio_bub.h | 3 +- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/board/imgtec/pistachio_bub/pistachio.c b/board/imgtec/pistachio_bub/pistachio.c index 7025304515..262ddf30e6 100644 --- a/board/imgtec/pistachio_bub/pistachio.c +++ b/board/imgtec/pistachio_bub/pistachio.c @@ -21,11 +21,12 @@ #include #include #include - +#include #include "mfio.h" +#define ETH_MAC_ADDRESS_OFFSET 0x1015 /* Ethernet MAC address offset */ + DECLARE_GLOBAL_DATA_PTR; -const char *enet_dtb_macaddr = 0; int reloc_tlb_fixup(void) { @@ -109,22 +110,42 @@ static const char *get_dtb_macaddr(u32 ifno) if (mac && is_valid_ethaddr((u8 *)mac)) return mac; - return NULL; + return NULL; } #endif int board_eth_init(bd_t *bs) { + u_char mac_addr[MAC_ADDR_LEN]; + mfio_setup_ethernet(); - /* try to get a valid macaddr from dtb */ + /* Order of precedence: + * 1. Check for existing ethaddr environment variable + * 2. Read from OTP + * 3. Fallback on dtb + */ + memset(mac_addr, 0, MAC_ADDR_LEN); + eth_getenv_enetaddr("ethaddr", mac_addr); + +#ifdef CONFIG_WINBOND_OTP + if (!is_valid_ethaddr(mac_addr)) { + if (!read_otp_data(ETH_MAC_ADDRESS_OFFSET, MAC_ADDR_LEN, + (char *)mac_addr) + && is_valid_ethaddr(mac_addr)) + eth_setenv_enetaddr("ethaddr", (u8 *)mac_addr); + else + printf("Could not read MAC address from OTP\n"); + } +#endif #ifdef CONFIG_OF_CONTROL - enet_dtb_macaddr = get_dtb_macaddr(0); - - if (enet_dtb_macaddr) - eth_setenv_enetaddr("ethaddr", (u8 *)enet_dtb_macaddr); - else - printf("No valid Mac-addr found from dtb\n"); + if (!is_valid_ethaddr(mac_addr)) { + const char *enet_dtb_macaddr = get_dtb_macaddr(0); + if (enet_dtb_macaddr) + eth_setenv_enetaddr("ethaddr", (u8 *)enet_dtb_macaddr); + else + printf("No valid Mac-addr found from dtb\n"); + } #endif #ifndef CONFIG_DM_ETH diff --git a/include/configs/pistachio_bub.h b/include/configs/pistachio_bub.h index d62a81ceb3..5301c01191 100644 --- a/include/configs/pistachio_bub.h +++ b/include/configs/pistachio_bub.h @@ -22,8 +22,9 @@ #define PISTACHIO_BOARD_NAME CONFIG_SYS_CONFIG_NAME #define CONFIG_BOARD_EARLY_INIT_F #define CONFIG_DISPLAY_BOARDINFO - +#define CONFIG_WINBOND_OTP #define CONFIG_OF_LIBFDT + /* * CPU Configuration */ From b2af95e7e70c9918e3cf1b0477876cb031003cd3 Mon Sep 17 00:00:00 2001 From: Francois Berder Date: Wed, 30 Nov 2016 15:05:14 +0000 Subject: [PATCH 3/4] Set wifi mac address and dcxo in device tree The MAC address for Wifi STA and AP are read from the OTP, then written in the wifi driver node of the device-tree. Concerning calibration data, only DCXO is read from the OTP and overwrites the first byte of the calibration parameter in the device tree. Signed-off-by: Francois Berder --- board/imgtec/pistachio_bub/Makefile | 3 + board/imgtec/pistachio_bub/fdt.c | 86 +++++++++++++++++++++++++++++ include/configs/pistachio_bub.h | 4 ++ 3 files changed, 93 insertions(+) create mode 100644 board/imgtec/pistachio_bub/fdt.c diff --git a/board/imgtec/pistachio_bub/Makefile b/board/imgtec/pistachio_bub/Makefile index e9afe166c9..072b95c2d9 100644 --- a/board/imgtec/pistachio_bub/Makefile +++ b/board/imgtec/pistachio_bub/Makefile @@ -19,3 +19,6 @@ endif ifdef CONFIG_CMD_PISTACHIO_SCRATCHPAD obj-y += cmd_scratchpad.o endif +ifdef CONFIG_WINBOND_OTP +obj-y += fdt.o +endif diff --git a/board/imgtec/pistachio_bub/fdt.c b/board/imgtec/pistachio_bub/fdt.c new file mode 100644 index 0000000000..7f5c99a7bc --- /dev/null +++ b/board/imgtec/pistachio_bub/fdt.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * Author: Francois Berder + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include + +#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP) + +#include + +#define WIFI_STA_MAC_ADDRESS_OFFSET 0x1003 +#define WIFI_AP_MAC_ADDRESS_OFFSET 0x1009 +#define DCXO_OFFSET 0x2003 + +DECLARE_GLOBAL_DATA_PTR; + +static void fixup_wifi_mac(void *blob, int node) +{ + u_char wifi_sta_mac_addr[MAC_ADDR_LEN], wifi_ap_mac_addr[MAC_ADDR_LEN]; + + memset(wifi_sta_mac_addr, 0, sizeof(wifi_sta_mac_addr)); + memset(wifi_ap_mac_addr, 0, sizeof(wifi_ap_mac_addr)); + + /* Read MAC addresses from OTP */ + if (read_otp_data(WIFI_STA_MAC_ADDRESS_OFFSET, MAC_ADDR_LEN, + (char *)wifi_sta_mac_addr) + || read_otp_data(WIFI_AP_MAC_ADDRESS_OFFSET, MAC_ADDR_LEN, + (char *)wifi_ap_mac_addr)) { + printf("WARNING: Could not read Wifi MAC addresses from OTP\n"); + return; + } + + /* Set Wifi STA and AP MAC address in device tree */ + if (is_valid_ethaddr(wifi_sta_mac_addr)) + fdt_setprop(blob, node, "mac-address0", wifi_sta_mac_addr, + MAC_ADDR_LEN); + else + printf("WARNING: Invalid Wifi sta MAC address.\n"); + + if (is_valid_ethaddr(wifi_ap_mac_addr)) + fdt_setprop(blob, node, "mac-address1", wifi_ap_mac_addr, + MAC_ADDR_LEN); + else + printf("WARNING: Invalid Wifi ap MAC address.\n"); +} + +static void fixup_wifi_calibration(void *blob, int node) +{ + int len; + char dcxo; + char *rf_params_prop; + + /* Read calibration data from OTP */ + if (read_otp_data(DCXO_OFFSET, sizeof(dcxo), &dcxo)) { + printf("WARNING: Could not read dcxo from OTP\n"); + return; + } + + /* Overwrite first byte of rf-params property with DXCO */ + rf_params_prop = fdt_getprop_w(blob, node, "rf-params", &len); + if (!rf_params_prop) { + printf("WARNING: Could not find rf-params property.\n"); + return; + } + + rf_params_prop[0] = dcxo; + fdt_setprop(blob, node, "rf-params", rf_params_prop, len); +} + +int ft_board_setup(void *blob, bd_t *bd) +{ + int node = fdt_path_offset(blob, "wifi0"); + if (node < 0) { + printf("WARNING: can't find wifi0 alias\n"); + return -1; + } + + fixup_wifi_mac(blob, node); + fixup_wifi_calibration(blob, node); + + return 0; +} +#endif diff --git a/include/configs/pistachio_bub.h b/include/configs/pistachio_bub.h index 5301c01191..c8c21fa77c 100644 --- a/include/configs/pistachio_bub.h +++ b/include/configs/pistachio_bub.h @@ -25,6 +25,10 @@ #define CONFIG_WINBOND_OTP #define CONFIG_OF_LIBFDT +#ifdef CONFIG_WINBOND_OTP +#define CONFIG_OF_BOARD_SETUP +#endif + /* * CPU Configuration */ From 842f390d68d1b4ca1ce8dc94b5a526f363100472 Mon Sep 17 00:00:00 2001 From: Francois Berder Date: Wed, 30 Nov 2016 17:32:48 +0000 Subject: [PATCH 4/4] Check version register of the OTP The version of register 0 and 1 must be greater or equal to 1, otherwise do not attempt to read any data from the OTP. Signed-off-by: Francois Berder --- board/imgtec/pistachio_bub/Makefile | 1 + board/imgtec/pistachio_bub/fdt.c | 38 ++++++++++++++------------ board/imgtec/pistachio_bub/otp.c | 22 +++++++++++++++ board/imgtec/pistachio_bub/otp.h | 28 +++++++++++++++++++ board/imgtec/pistachio_bub/pistachio.c | 16 ++++++----- include/winbond-otp.h | 2 -- 6 files changed, 81 insertions(+), 26 deletions(-) create mode 100644 board/imgtec/pistachio_bub/otp.c create mode 100644 board/imgtec/pistachio_bub/otp.h diff --git a/board/imgtec/pistachio_bub/Makefile b/board/imgtec/pistachio_bub/Makefile index 072b95c2d9..f202746fd7 100644 --- a/board/imgtec/pistachio_bub/Makefile +++ b/board/imgtec/pistachio_bub/Makefile @@ -21,4 +21,5 @@ obj-y += cmd_scratchpad.o endif ifdef CONFIG_WINBOND_OTP obj-y += fdt.o +obj-y += otp.o endif diff --git a/board/imgtec/pistachio_bub/fdt.c b/board/imgtec/pistachio_bub/fdt.c index 7f5c99a7bc..3b8111b117 100644 --- a/board/imgtec/pistachio_bub/fdt.c +++ b/board/imgtec/pistachio_bub/fdt.c @@ -10,10 +10,7 @@ #if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP) #include - -#define WIFI_STA_MAC_ADDRESS_OFFSET 0x1003 -#define WIFI_AP_MAC_ADDRESS_OFFSET 0x1009 -#define DCXO_OFFSET 0x2003 +#include "otp.h" DECLARE_GLOBAL_DATA_PTR; @@ -24,13 +21,15 @@ static void fixup_wifi_mac(void *blob, int node) memset(wifi_sta_mac_addr, 0, sizeof(wifi_sta_mac_addr)); memset(wifi_ap_mac_addr, 0, sizeof(wifi_ap_mac_addr)); - /* Read MAC addresses from OTP */ - if (read_otp_data(WIFI_STA_MAC_ADDRESS_OFFSET, MAC_ADDR_LEN, - (char *)wifi_sta_mac_addr) - || read_otp_data(WIFI_AP_MAC_ADDRESS_OFFSET, MAC_ADDR_LEN, - (char *)wifi_ap_mac_addr)) { - printf("WARNING: Could not read Wifi MAC addresses from OTP\n"); - return; + if (read_otp_version(VERSION_REG0_OFFSET) >= 1) { + /* Read MAC addresses from OTP */ + if (read_otp_data(WIFI_STA_MAC_ADDRESS_OFFSET, MAC_ADDR_LEN, + (char *)wifi_sta_mac_addr) + || read_otp_data(WIFI_AP_MAC_ADDRESS_OFFSET, MAC_ADDR_LEN, + (char *)wifi_ap_mac_addr)) { + printf("WARNING: Could not read Wifi MAC addresses from OTP\n"); + return; + } } /* Set Wifi STA and AP MAC address in device tree */ @@ -52,11 +51,14 @@ static void fixup_wifi_calibration(void *blob, int node) int len; char dcxo; char *rf_params_prop; - - /* Read calibration data from OTP */ - if (read_otp_data(DCXO_OFFSET, sizeof(dcxo), &dcxo)) { - printf("WARNING: Could not read dcxo from OTP\n"); - return; + int version_reg1 = read_otp_version(VERSION_REG1_OFFSET); + + if (version_reg1 >= 1) { + /* Read calibration data from OTP */ + if (read_otp_data(DCXO_OFFSET, sizeof(dcxo), &dcxo)) { + printf("WARNING: Could not read dcxo from OTP\n"); + return; + } } /* Overwrite first byte of rf-params property with DXCO */ @@ -66,7 +68,9 @@ static void fixup_wifi_calibration(void *blob, int node) return; } - rf_params_prop[0] = dcxo; + if (version_reg1 >= 1) + rf_params_prop[0] = dcxo; + fdt_setprop(blob, node, "rf-params", rf_params_prop, len); } diff --git a/board/imgtec/pistachio_bub/otp.c b/board/imgtec/pistachio_bub/otp.c new file mode 100644 index 0000000000..307dec71a2 --- /dev/null +++ b/board/imgtec/pistachio_bub/otp.c @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * Author: Francois Berder + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include "otp.h" + +int read_otp_version(loff_t offset) +{ + u_char version; + + if (read_otp_data(offset, sizeof(version), (char *)&version)) { + printf("WARNING: Could not read register version from OTP.\n"); + return -1; + } + + return version; +} diff --git a/board/imgtec/pistachio_bub/otp.h b/board/imgtec/pistachio_bub/otp.h new file mode 100644 index 0000000000..32d586fd97 --- /dev/null +++ b/board/imgtec/pistachio_bub/otp.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * Author: Francois Berder + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _OTP_H +#define _OTP_H + +#define MAC_ADDR_LEN 6 + +#ifdef CONFIG_WINBOND_OTP + +#include + +#define VERSION_REG0_OFFSET 0x1002 +#define VERSION_REG1_OFFSET 0x2002 +#define WIFI_STA_MAC_ADDRESS_OFFSET 0x1003 +#define WIFI_AP_MAC_ADDRESS_OFFSET 0x1009 +#define ETH_MAC_ADDRESS_OFFSET 0x1015 +#define DCXO_OFFSET 0x2003 + +int read_otp_version(loff_t offset); + +#endif + +#endif diff --git a/board/imgtec/pistachio_bub/pistachio.c b/board/imgtec/pistachio_bub/pistachio.c index 262ddf30e6..e0113028ca 100644 --- a/board/imgtec/pistachio_bub/pistachio.c +++ b/board/imgtec/pistachio_bub/pistachio.c @@ -23,8 +23,8 @@ #include #include #include "mfio.h" +#include "otp.h" -#define ETH_MAC_ADDRESS_OFFSET 0x1015 /* Ethernet MAC address offset */ DECLARE_GLOBAL_DATA_PTR; @@ -130,12 +130,14 @@ int board_eth_init(bd_t *bs) #ifdef CONFIG_WINBOND_OTP if (!is_valid_ethaddr(mac_addr)) { - if (!read_otp_data(ETH_MAC_ADDRESS_OFFSET, MAC_ADDR_LEN, - (char *)mac_addr) - && is_valid_ethaddr(mac_addr)) - eth_setenv_enetaddr("ethaddr", (u8 *)mac_addr); - else - printf("Could not read MAC address from OTP\n"); + if (read_otp_version(VERSION_REG0_OFFSET) >= 1) { + if (!read_otp_data(ETH_MAC_ADDRESS_OFFSET, MAC_ADDR_LEN, + (char *)mac_addr) + && is_valid_ethaddr(mac_addr)) + eth_setenv_enetaddr("ethaddr", (u8 *)mac_addr); + else + printf("Could not read MAC address from OTP\n"); + } } #endif #ifdef CONFIG_OF_CONTROL diff --git a/include/winbond-otp.h b/include/winbond-otp.h index c802174047..93d51e958d 100644 --- a/include/winbond-otp.h +++ b/include/winbond-otp.h @@ -8,8 +8,6 @@ #ifndef WINBOND_OTP_H #define WINBOND_OTP_H -#define MAC_ADDR_LEN 6 - int read_otp_data(loff_t from, size_t len, char *data); #endif