Message ID | 20151225134013.C56016121B@mail.nwl.cc |
---|---|
State | Accepted |
Delegated to: | Stefan Roese |
Headers | show |
Hi Phil, I'm preparing a branch for Luka to pull from. With all the pending mvebu patches included. And noticed a small issue with this patch. See below... On 25.12.2015 14:41, Phil Sutter wrote: > 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> > --- > board/Synology/common/Makefile | 7 ++ > board/Synology/common/cmd_syno.c | 227 +++++++++++++++++++++++++++++++++++++++ > 2 files changed, 234 insertions(+) > create mode 100644 board/Synology/common/Makefile > create mode 100644 board/Synology/common/cmd_syno.c > > diff --git a/board/Synology/common/Makefile b/board/Synology/common/Makefile > new file mode 100644 > index 0000000..e66aeb8 > --- /dev/null > +++ b/board/Synology/common/Makefile > @@ -0,0 +1,7 @@ > +# > +# Copyright (C) 2015 Phil Sutter <phil@nwl.cc> > +# > +# SPDX-License-Identifier: GPL-2.0+ > +# > + > +obj-y := cmd_syno.o > diff --git a/board/Synology/common/cmd_syno.c b/board/Synology/common/cmd_syno.c > new file mode 100644 > index 0000000..4a1918d > --- /dev/null > +++ b/board/Synology/common/cmd_syno.c > @@ -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; > + > + 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; Here I get this warning: board/Synology/common/cmd_syno.c: In function 'do_syno': board/Synology/common/cmd_syno.c:216:5: warning: 'ret' may be used uninitialized in this function [-Wmaybe-uninitialized] if (ret != -1) ^ I've changed this to init ret to 0 in my branch. Let me know if this is okay with you. Thanks, Stefan
Hi Stefan, On Wed, Jan 13, 2016 at 09:17:54AM +0100, Stefan Roese wrote: > I'm preparing a branch for Luka to pull from. With all the pending > mvebu patches included. And noticed a small issue with this patch. > See below... > > On 25.12.2015 14:41, Phil Sutter wrote: [...] > > +static int do_syno(cmd_tbl_t *cmdtp, int flag, > > + int argc, char * const argv[]) > > +{ > > + const char *cmd; > > + int ret; > > + > > + 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; > > Here I get this warning: > > board/Synology/common/cmd_syno.c: In function 'do_syno': > board/Synology/common/cmd_syno.c:216:5: warning: 'ret' may be used uninitialized in this function [-Wmaybe-uninitialized] > if (ret != -1) > ^ > > I've changed this to init ret to 0 in my branch. Let me know if this > is okay with you. Yes, sure! I have to admit, I didn't spend much time on this file. It was always merely for fixing the "real" issues. Thanks, Phil
On Fri, Dec 25, 2015 at 02:41:26PM +0100, Phil Sutter wrote: > 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> Reviewed-by: Tom Rini <trini@konsulko.com>
diff --git a/board/Synology/common/Makefile b/board/Synology/common/Makefile new file mode 100644 index 0000000..e66aeb8 --- /dev/null +++ b/board/Synology/common/Makefile @@ -0,0 +1,7 @@ +# +# Copyright (C) 2015 Phil Sutter <phil@nwl.cc> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y := cmd_syno.o diff --git a/board/Synology/common/cmd_syno.c b/board/Synology/common/cmd_syno.c new file mode 100644 index 0000000..4a1918d --- /dev/null +++ b/board/Synology/common/cmd_syno.c @@ -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; + + 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" +);
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> --- board/Synology/common/Makefile | 7 ++ board/Synology/common/cmd_syno.c | 227 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 234 insertions(+) create mode 100644 board/Synology/common/Makefile create mode 100644 board/Synology/common/cmd_syno.c