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