Synology keeps per item configuration in a dedicated 'partition' in SPI flash, namely the one named 'vendor' in DTS file. It contains the two NICs MAC addresses as well as the item's serial number. I didn't find a way to have this information extracted automatically, therefore implemented 'syno populate_env' command which extracts the three values and puts them into environment. To make things permanent though, one has to 'saveenv'. Another command is 'syno clk_gate', which allows to change the clock gating which is done in DS414 board file. Signed-off-by: Phil Sutter <phil@nwl.cc> Acked-by: Stefan Roese <sr@denx.de> Reviewed-by: Tom Rini <trini@konsulko.com>master
parent
aefb8f4c32
commit
a12d3e4c1e
@ -0,0 +1,7 @@ |
||||
#
|
||||
# Copyright (C) 2015 Phil Sutter <phil@nwl.cc>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y := cmd_syno.o
|
@ -0,0 +1,227 @@ |
||||
/*
|
||||
* Commands to deal with Synology specifics. |
||||
* |
||||
* Copyright (C) 2015 Phil Sutter <phil@nwl.cc> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <div64.h> |
||||
#include <spi.h> |
||||
#include <spi_flash.h> |
||||
#include <linux/mtd/mtd.h> |
||||
|
||||
#include <asm/io.h> |
||||
#include "../drivers/ddr/marvell/axp/ddr3_init.h" |
||||
|
||||
#define ETH_ALEN 6 |
||||
#define ETHADDR_MAX 4 |
||||
#define SYNO_SN_TAG "SN=" |
||||
#define SYNO_CHKSUM_TAG "CHK=" |
||||
|
||||
|
||||
static int do_syno_populate(int argc, char * const argv[]) |
||||
{ |
||||
unsigned int bus = CONFIG_SF_DEFAULT_BUS; |
||||
unsigned int cs = CONFIG_SF_DEFAULT_CS; |
||||
unsigned int speed = CONFIG_SF_DEFAULT_SPEED; |
||||
unsigned int mode = CONFIG_SF_DEFAULT_MODE; |
||||
struct spi_flash *flash; |
||||
unsigned long addr = 0x80000; /* XXX: parameterize this? */ |
||||
loff_t offset = 0x007d0000; |
||||
loff_t len = 0x00010000; |
||||
char *buf, *bufp; |
||||
char var[128]; |
||||
char val[128]; |
||||
int ret, n; |
||||
|
||||
/* XXX: arg parsing to select flash here? */ |
||||
|
||||
flash = spi_flash_probe(bus, cs, speed, mode); |
||||
if (!flash) { |
||||
printf("Failed to initialize SPI flash at %u:%u\n", bus, cs); |
||||
return 1; |
||||
} |
||||
|
||||
buf = map_physmem(addr, len, MAP_WRBACK); |
||||
if (!buf) { |
||||
puts("Failed to map physical memory\n"); |
||||
return 1; |
||||
} |
||||
|
||||
ret = spi_flash_read(flash, offset, len, buf); |
||||
if (ret) { |
||||
puts("Failed to read from SPI flash\n"); |
||||
goto out_unmap; |
||||
} |
||||
|
||||
for (n = 0; n < ETHADDR_MAX; n++) { |
||||
char ethaddr[ETH_ALEN]; |
||||
int i, sum = 0; |
||||
unsigned char csum = 0; |
||||
|
||||
for (i = 0, bufp = buf + n * 7; i < ETH_ALEN; i++) { |
||||
sum += bufp[i]; |
||||
csum += bufp[i]; |
||||
ethaddr[i] = bufp[i]; |
||||
} |
||||
if (!sum) /* MAC address empty */ |
||||
continue; |
||||
if (csum != bufp[i]) { /* seventh byte is checksum value */ |
||||
printf("Invalid MAC address for interface %d!\n", n); |
||||
continue; |
||||
} |
||||
if (n == 0) |
||||
sprintf(var, "ethaddr"); |
||||
else |
||||
sprintf(var, "eth%daddr", n); |
||||
snprintf(val, sizeof(val) - 1, |
||||
"%02x:%02x:%02x:%02x:%02x:%02x", |
||||
ethaddr[0], ethaddr[1], ethaddr[2], |
||||
ethaddr[3], ethaddr[4], ethaddr[5]); |
||||
printf("parsed %s = %s\n", var, val); |
||||
setenv(var, val); |
||||
} |
||||
if (!strncmp(buf + 32, SYNO_SN_TAG, strlen(SYNO_SN_TAG))) { |
||||
char *snp, *csump; |
||||
int csum = 0; |
||||
unsigned long c; |
||||
|
||||
snp = bufp = buf + 32 + strlen(SYNO_SN_TAG); |
||||
for (n = 0; bufp[n] && bufp[n] != ','; n++) |
||||
csum += bufp[n]; |
||||
bufp[n] = '\0'; |
||||
|
||||
/* should come right after, but you never know */ |
||||
bufp = strstr(bufp + n + 1, SYNO_CHKSUM_TAG); |
||||
if (!bufp) { |
||||
printf("Serial number checksum tag missing!\n"); |
||||
goto out_unmap; |
||||
} |
||||
|
||||
csump = bufp += strlen(SYNO_CHKSUM_TAG); |
||||
for (n = 0; bufp[n] && bufp[n] != ','; n++) |
||||
; |
||||
bufp[n] = '\0'; |
||||
|
||||
if (strict_strtoul(csump, 10, &c) || c != csum) { |
||||
puts("Invalid serial number found!\n"); |
||||
ret = 1; |
||||
goto out_unmap; |
||||
} |
||||
printf("parsed SN = %s\n", snp); |
||||
setenv("SN", snp); |
||||
} else { /* old style format */ |
||||
unsigned char csum = 0; |
||||
|
||||
for (n = 0, bufp = buf + 32; n < 10; n++) |
||||
csum += bufp[n]; |
||||
|
||||
if (csum != bufp[n]) { |
||||
puts("Invalid serial number found!\n"); |
||||
ret = 1; |
||||
goto out_unmap; |
||||
} |
||||
bufp[n] = '\0'; |
||||
printf("parsed SN = %s\n", buf + 32); |
||||
setenv("SN", buf + 32); |
||||
} |
||||
out_unmap: |
||||
unmap_physmem(buf, len); |
||||
return ret; |
||||
} |
||||
|
||||
/* map bit position to function in POWER_MNG_CTRL_REG */ |
||||
static const char * const pwr_mng_bit_func[] = { |
||||
"audio", |
||||
"ge3", "ge2", "ge1", "ge0", |
||||
"pcie00", "pcie01", "pcie02", "pcie03", |
||||
"pcie10", "pcie11", "pcie12", "pcie13", |
||||
"bp", |
||||
"sata0_link", "sata0_core", |
||||
"lcd", |
||||
"sdio", |
||||
"usb0", "usb1", "usb2", |
||||
"idma", "xor0", "crypto", |
||||
NULL, |
||||
"tdm", |
||||
"pcie20", "pcie30", |
||||
"xor1", |
||||
"sata1_link", "sata1_core", |
||||
NULL, |
||||
}; |
||||
|
||||
static int do_syno_clk_gate(int argc, char * const argv[]) |
||||
{ |
||||
u32 pwr_mng_ctrl_reg = reg_read(POWER_MNG_CTRL_REG); |
||||
const char *func, *state; |
||||
int i, val; |
||||
|
||||
if (argc < 2) |
||||
return -1; |
||||
|
||||
if (!strcmp(argv[1], "get")) { |
||||
puts("Clock Gating:\n"); |
||||
for (i = 0; i < 32; i++) { |
||||
func = pwr_mng_bit_func[i]; |
||||
if (!func) |
||||
continue; |
||||
state = pwr_mng_ctrl_reg & (1 << i) ? "ON" : "OFF"; |
||||
printf("%s:\t\t%s\n", func, state); |
||||
} |
||||
return 0; |
||||
} |
||||
if (argc < 4) |
||||
return -1; |
||||
if (!strcmp(argv[1], "set")) { |
||||
func = argv[2]; |
||||
state = argv[3]; |
||||
for (i = 0; i < 32; i++) { |
||||
if (!pwr_mng_bit_func[i]) |
||||
continue; |
||||
if (!strcmp(func, pwr_mng_bit_func[i])) |
||||
break; |
||||
} |
||||
if (i == 32) { |
||||
printf("Error: name '%s' not known\n", func); |
||||
return -1; |
||||
} |
||||
val = state[0] != '0'; |
||||
pwr_mng_ctrl_reg |= (val << i); |
||||
pwr_mng_ctrl_reg &= ~(!val << i); |
||||
reg_write(POWER_MNG_CTRL_REG, pwr_mng_ctrl_reg); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static int do_syno(cmd_tbl_t *cmdtp, int flag, |
||||
int argc, char * const argv[]) |
||||
{ |
||||
const char *cmd; |
||||
int ret = 0; |
||||
|
||||
if (argc < 2) |
||||
goto usage; |
||||
|
||||
cmd = argv[1]; |
||||
--argc; |
||||
++argv; |
||||
|
||||
if (!strcmp(cmd, "populate_env")) |
||||
ret = do_syno_populate(argc, argv); |
||||
else if (!strcmp(cmd, "clk_gate")) |
||||
ret = do_syno_clk_gate(argc, argv); |
||||
|
||||
if (ret != -1) |
||||
return ret; |
||||
usage: |
||||
return CMD_RET_USAGE; |
||||
} |
||||
|
||||
U_BOOT_CMD( |
||||
syno, 5, 1, do_syno, |
||||
"Synology specific commands", |
||||
"populate_env - Read vendor data from SPI flash into environment\n" |
||||
"clk_gate (get|set name 1|0) - Manage clock gating\n" |
||||
); |
Loading…
Reference in new issue