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