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