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