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