diff --git a/board/imgtec/pistachio_bub/Makefile b/board/imgtec/pistachio_bub/Makefile index e9afe166c9..f202746fd7 100644 --- a/board/imgtec/pistachio_bub/Makefile +++ b/board/imgtec/pistachio_bub/Makefile @@ -19,3 +19,7 @@ endif ifdef CONFIG_CMD_PISTACHIO_SCRATCHPAD 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 new file mode 100644 index 0000000000..3b8111b117 --- /dev/null +++ b/board/imgtec/pistachio_bub/fdt.c @@ -0,0 +1,90 @@ +/* + * 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 +#include "otp.h" + +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)); + + 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 */ + 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; + 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 */ + 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; + } + + if (version_reg1 >= 1) + 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/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 7025304515..e0113028ca 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" +#include "otp.h" + DECLARE_GLOBAL_DATA_PTR; -const char *enet_dtb_macaddr = 0; int reloc_tlb_fixup(void) { @@ -109,22 +110,44 @@ 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_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 - 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/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/configs/pistachio_bub.h b/include/configs/pistachio_bub.h index d62a81ceb3..c8c21fa77c 100644 --- a/include/configs/pistachio_bub.h +++ b/include/configs/pistachio_bub.h @@ -22,8 +22,13 @@ #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 + +#ifdef CONFIG_WINBOND_OTP +#define CONFIG_OF_BOARD_SETUP +#endif + /* * CPU Configuration */ diff --git a/include/winbond-otp.h b/include/winbond-otp.h new file mode 100644 index 0000000000..93d51e958d --- /dev/null +++ b/include/winbond-otp.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2015 Imagination Technologies + * Author: Avinash Tahakik + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef WINBOND_OTP_H +#define WINBOND_OTP_H + +int read_otp_data(loff_t from, size_t len, char *data); + +#endif