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