xref: /openbmc/u-boot/board/Synology/ds414/cmd_syno.c (revision cf033e04)
1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2d08fedf6STom Rini /*
3d08fedf6STom Rini  * Commands to deal with Synology specifics.
4d08fedf6STom Rini  *
5d08fedf6STom Rini  * Copyright (C) 2015  Phil Sutter <phil@nwl.cc>
6d08fedf6STom Rini  */
7d08fedf6STom Rini 
8d08fedf6STom Rini #include <common.h>
9d08fedf6STom Rini #include <div64.h>
10d08fedf6STom Rini #include <spi.h>
11d08fedf6STom Rini #include <spi_flash.h>
12d08fedf6STom Rini #include <linux/mtd/mtd.h>
13d08fedf6STom Rini 
14d08fedf6STom Rini #include <asm/io.h>
15d08fedf6STom Rini #include "../drivers/ddr/marvell/axp/ddr3_init.h"
16d08fedf6STom Rini 
17d08fedf6STom Rini #define ETHADDR_MAX		4
18d08fedf6STom Rini #define SYNO_SN_TAG		"SN="
19d08fedf6STom Rini #define SYNO_CHKSUM_TAG		"CHK="
20d08fedf6STom Rini 
21d08fedf6STom Rini 
do_syno_populate(int argc,char * const argv[])22d08fedf6STom Rini static int do_syno_populate(int argc, char * const argv[])
23d08fedf6STom Rini {
24d08fedf6STom Rini 	unsigned int bus = CONFIG_SF_DEFAULT_BUS;
25d08fedf6STom Rini 	unsigned int cs = CONFIG_SF_DEFAULT_CS;
26d08fedf6STom Rini 	unsigned int speed = CONFIG_SF_DEFAULT_SPEED;
27d08fedf6STom Rini 	unsigned int mode = CONFIG_SF_DEFAULT_MODE;
28d08fedf6STom Rini 	struct spi_flash *flash;
29d08fedf6STom Rini 	unsigned long addr = 0x80000; /* XXX: parameterize this? */
30d08fedf6STom Rini 	loff_t offset = 0x007d0000;
31d08fedf6STom Rini 	loff_t len = 0x00010000;
32d08fedf6STom Rini 	char *buf, *bufp;
33d08fedf6STom Rini 	char var[128];
34d08fedf6STom Rini 	char val[128];
35d08fedf6STom Rini 	int ret, n;
36d08fedf6STom Rini 
37d08fedf6STom Rini 	/* XXX: arg parsing to select flash here? */
38d08fedf6STom Rini 
39d08fedf6STom Rini 	flash = spi_flash_probe(bus, cs, speed, mode);
40d08fedf6STom Rini 	if (!flash) {
41d08fedf6STom Rini 		printf("Failed to initialize SPI flash at %u:%u\n", bus, cs);
42d08fedf6STom Rini 		return 1;
43d08fedf6STom Rini 	}
44d08fedf6STom Rini 
45d08fedf6STom Rini 	buf = map_physmem(addr, len, MAP_WRBACK);
46d08fedf6STom Rini 	if (!buf) {
47d08fedf6STom Rini 		puts("Failed to map physical memory\n");
48d08fedf6STom Rini 		return 1;
49d08fedf6STom Rini 	}
50d08fedf6STom Rini 
51d08fedf6STom Rini 	ret = spi_flash_read(flash, offset, len, buf);
52d08fedf6STom Rini 	if (ret) {
53d08fedf6STom Rini 		puts("Failed to read from SPI flash\n");
54d08fedf6STom Rini 		goto out_unmap;
55d08fedf6STom Rini 	}
56d08fedf6STom Rini 
57d08fedf6STom Rini 	for (n = 0; n < ETHADDR_MAX; n++) {
58d08fedf6STom Rini 		char ethaddr[ETH_ALEN];
59d08fedf6STom Rini 		int i, sum = 0;
60d08fedf6STom Rini 		unsigned char csum = 0;
61d08fedf6STom Rini 
62d08fedf6STom Rini 		for (i = 0, bufp = buf + n * 7; i < ETH_ALEN; i++) {
63d08fedf6STom Rini 			sum += bufp[i];
64d08fedf6STom Rini 			csum += bufp[i];
65d08fedf6STom Rini 			ethaddr[i] = bufp[i];
66d08fedf6STom Rini 		}
67d08fedf6STom Rini 		if (!sum)		/* MAC address empty */
68d08fedf6STom Rini 			continue;
69d08fedf6STom Rini 		if (csum != bufp[i]) {	/* seventh byte is checksum value */
70d08fedf6STom Rini 			printf("Invalid MAC address for interface %d!\n", n);
71d08fedf6STom Rini 			continue;
72d08fedf6STom Rini 		}
73d08fedf6STom Rini 		if (n == 0)
74d08fedf6STom Rini 			sprintf(var, "ethaddr");
75d08fedf6STom Rini 		else
76d08fedf6STom Rini 			sprintf(var, "eth%daddr", n);
77d08fedf6STom Rini 		snprintf(val, sizeof(val) - 1,
78d08fedf6STom Rini 		         "%02x:%02x:%02x:%02x:%02x:%02x",
79d08fedf6STom Rini 		         ethaddr[0], ethaddr[1], ethaddr[2],
80d08fedf6STom Rini 			 ethaddr[3], ethaddr[4], ethaddr[5]);
81d08fedf6STom Rini 		printf("parsed %s = %s\n", var, val);
82382bee57SSimon Glass 		env_set(var, val);
83d08fedf6STom Rini 	}
84d08fedf6STom Rini 	if (!strncmp(buf + 32, SYNO_SN_TAG, strlen(SYNO_SN_TAG))) {
85d08fedf6STom Rini 		char *snp, *csump;
86d08fedf6STom Rini 		int csum = 0;
87d08fedf6STom Rini 		unsigned long c;
88d08fedf6STom Rini 
89d08fedf6STom Rini 		snp = bufp = buf + 32 + strlen(SYNO_SN_TAG);
90d08fedf6STom Rini 		for (n = 0; bufp[n] && bufp[n] != ','; n++)
91d08fedf6STom Rini 			csum += bufp[n];
92d08fedf6STom Rini 		bufp[n] = '\0';
93d08fedf6STom Rini 
94d08fedf6STom Rini 		/* should come right after, but you never know */
95d08fedf6STom Rini 		bufp = strstr(bufp + n + 1, SYNO_CHKSUM_TAG);
96d08fedf6STom Rini 		if (!bufp) {
97d08fedf6STom Rini 			printf("Serial number checksum tag missing!\n");
98d08fedf6STom Rini 			goto out_unmap;
99d08fedf6STom Rini 		}
100d08fedf6STom Rini 
101d08fedf6STom Rini 		csump = bufp += strlen(SYNO_CHKSUM_TAG);
102d08fedf6STom Rini 		for (n = 0; bufp[n] && bufp[n] != ','; n++)
103d08fedf6STom Rini 			;
104d08fedf6STom Rini 		bufp[n] = '\0';
105d08fedf6STom Rini 
106d08fedf6STom Rini 		if (strict_strtoul(csump, 10, &c) || c != csum) {
107d08fedf6STom Rini 			puts("Invalid serial number found!\n");
108d08fedf6STom Rini 			ret = 1;
109d08fedf6STom Rini 			goto out_unmap;
110d08fedf6STom Rini 		}
111d08fedf6STom Rini 		printf("parsed SN = %s\n", snp);
112382bee57SSimon Glass 		env_set("SN", snp);
113d08fedf6STom Rini 	} else {	/* old style format */
114d08fedf6STom Rini 		unsigned char csum = 0;
115d08fedf6STom Rini 
116d08fedf6STom Rini 		for (n = 0, bufp = buf + 32; n < 10; n++)
117d08fedf6STom Rini 			csum += bufp[n];
118d08fedf6STom Rini 
119d08fedf6STom Rini 		if (csum != bufp[n]) {
120d08fedf6STom Rini 			puts("Invalid serial number found!\n");
121d08fedf6STom Rini 			ret = 1;
122d08fedf6STom Rini 			goto out_unmap;
123d08fedf6STom Rini 		}
124d08fedf6STom Rini 		bufp[n] = '\0';
125d08fedf6STom Rini 		printf("parsed SN = %s\n", buf + 32);
126382bee57SSimon Glass 		env_set("SN", buf + 32);
127d08fedf6STom Rini 	}
128d08fedf6STom Rini out_unmap:
129d08fedf6STom Rini 	unmap_physmem(buf, len);
130d08fedf6STom Rini 	return ret;
131d08fedf6STom Rini }
132d08fedf6STom Rini 
133d08fedf6STom Rini /* map bit position to function in POWER_MNG_CTRL_REG */
134d08fedf6STom Rini static const char * const pwr_mng_bit_func[] = {
135d08fedf6STom Rini 	"audio",
136d08fedf6STom Rini 	"ge3", "ge2", "ge1", "ge0",
137d08fedf6STom Rini 	"pcie00", "pcie01", "pcie02", "pcie03",
138d08fedf6STom Rini 	"pcie10", "pcie11", "pcie12", "pcie13",
139d08fedf6STom Rini 	"bp",
140d08fedf6STom Rini 	"sata0_link", "sata0_core",
141d08fedf6STom Rini 	"lcd",
142d08fedf6STom Rini 	"sdio",
143d08fedf6STom Rini 	"usb0", "usb1", "usb2",
144d08fedf6STom Rini 	"idma", "xor0", "crypto",
145d08fedf6STom Rini 	NULL,
146d08fedf6STom Rini 	"tdm",
147d08fedf6STom Rini 	"pcie20", "pcie30",
148d08fedf6STom Rini 	"xor1",
149d08fedf6STom Rini 	"sata1_link", "sata1_core",
150d08fedf6STom Rini 	NULL,
151d08fedf6STom Rini };
152d08fedf6STom Rini 
do_syno_clk_gate(int argc,char * const argv[])153d08fedf6STom Rini static int do_syno_clk_gate(int argc, char * const argv[])
154d08fedf6STom Rini {
155d08fedf6STom Rini 	u32 pwr_mng_ctrl_reg = reg_read(POWER_MNG_CTRL_REG);
156d08fedf6STom Rini 	const char *func, *state;
157d08fedf6STom Rini 	int i, val;
158d08fedf6STom Rini 
159d08fedf6STom Rini 	if (argc < 2)
160d08fedf6STom Rini 		return -1;
161d08fedf6STom Rini 
162d08fedf6STom Rini 	if (!strcmp(argv[1], "get")) {
163d08fedf6STom Rini 		puts("Clock Gating:\n");
164d08fedf6STom Rini 		for (i = 0; i < 32; i++) {
165d08fedf6STom Rini 			func = pwr_mng_bit_func[i];
166d08fedf6STom Rini 			if (!func)
167d08fedf6STom Rini 				continue;
168d08fedf6STom Rini 			state = pwr_mng_ctrl_reg & (1 << i) ?  "ON" : "OFF";
169d08fedf6STom Rini 			printf("%s:\t\t%s\n", func, state);
170d08fedf6STom Rini 		}
171d08fedf6STom Rini 		return 0;
172d08fedf6STom Rini 	}
173d08fedf6STom Rini 	if (argc < 4)
174d08fedf6STom Rini 		return -1;
175d08fedf6STom Rini 	if (!strcmp(argv[1], "set")) {
176d08fedf6STom Rini 		func = argv[2];
177d08fedf6STom Rini 		state = argv[3];
178d08fedf6STom Rini 		for (i = 0; i < 32; i++) {
179d08fedf6STom Rini 			if (!pwr_mng_bit_func[i])
180d08fedf6STom Rini 				continue;
181d08fedf6STom Rini 			if (!strcmp(func, pwr_mng_bit_func[i]))
182d08fedf6STom Rini 				break;
183d08fedf6STom Rini 		}
184d08fedf6STom Rini 		if (i == 32) {
185d08fedf6STom Rini 			printf("Error: name '%s' not known\n", func);
186d08fedf6STom Rini 			return -1;
187d08fedf6STom Rini 		}
188d08fedf6STom Rini 		val = state[0] != '0';
189d08fedf6STom Rini 		pwr_mng_ctrl_reg |= (val << i);
190d08fedf6STom Rini 		pwr_mng_ctrl_reg &= ~(!val << i);
191d08fedf6STom Rini 		reg_write(POWER_MNG_CTRL_REG, pwr_mng_ctrl_reg);
192d08fedf6STom Rini 	}
193d08fedf6STom Rini 	return 0;
194d08fedf6STom Rini }
195d08fedf6STom Rini 
do_syno(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])196d08fedf6STom Rini static int do_syno(cmd_tbl_t *cmdtp, int flag,
197d08fedf6STom Rini                    int argc, char * const argv[])
198d08fedf6STom Rini {
199d08fedf6STom Rini 	const char *cmd;
200d08fedf6STom Rini 	int ret = 0;
201d08fedf6STom Rini 
202d08fedf6STom Rini 	if (argc < 2)
203d08fedf6STom Rini 		goto usage;
204d08fedf6STom Rini 
205d08fedf6STom Rini 	cmd = argv[1];
206d08fedf6STom Rini 	--argc;
207d08fedf6STom Rini 	++argv;
208d08fedf6STom Rini 
209d08fedf6STom Rini 	if (!strcmp(cmd, "populate_env"))
210d08fedf6STom Rini 		ret = do_syno_populate(argc, argv);
211d08fedf6STom Rini 	else if (!strcmp(cmd, "clk_gate"))
212d08fedf6STom Rini 		ret = do_syno_clk_gate(argc, argv);
213d08fedf6STom Rini 
214d08fedf6STom Rini 	if (ret != -1)
215d08fedf6STom Rini 		return ret;
216d08fedf6STom Rini usage:
217d08fedf6STom Rini 	return CMD_RET_USAGE;
218d08fedf6STom Rini }
219d08fedf6STom Rini 
220d08fedf6STom Rini U_BOOT_CMD(
221d08fedf6STom Rini 	syno, 5, 1, do_syno,
222d08fedf6STom Rini 	"Synology specific commands",
223d08fedf6STom Rini 	"populate_env                 - Read vendor data from SPI flash into environment\n"
224d08fedf6STom Rini 	"clk_gate (get|set name 1|0)  - Manage clock gating\n"
225d08fedf6STom Rini );
226