diff options
Diffstat (limited to 'board/Synology')
-rw-r--r-- | board/Synology/common/Makefile | 7 | ||||
-rw-r--r-- | board/Synology/common/cmd_syno.c | 227 | ||||
-rw-r--r-- | board/Synology/ds414/Makefile | 7 | ||||
-rw-r--r-- | board/Synology/ds414/ds414.c | 185 | ||||
-rw-r--r-- | board/Synology/ds414/kwbimage.cfg | 12 |
5 files changed, 438 insertions, 0 deletions
diff --git a/board/Synology/common/Makefile b/board/Synology/common/Makefile new file mode 100644 index 0000000..e66aeb8 --- /dev/null +++ b/board/Synology/common/Makefile @@ -0,0 +1,7 @@ +# +# Copyright (C) 2015 Phil Sutter <phil@nwl.cc> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y := cmd_syno.o diff --git a/board/Synology/common/cmd_syno.c b/board/Synology/common/cmd_syno.c new file mode 100644 index 0000000..20544e2 --- /dev/null +++ b/board/Synology/common/cmd_syno.c @@ -0,0 +1,227 @@ +/* + * Commands to deal with Synology specifics. + * + * Copyright (C) 2015 Phil Sutter <phil@nwl.cc> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <div64.h> +#include <spi.h> +#include <spi_flash.h> +#include <linux/mtd/mtd.h> + +#include <asm/io.h> +#include "../drivers/ddr/marvell/axp/ddr3_init.h" + +#define ETH_ALEN 6 +#define ETHADDR_MAX 4 +#define SYNO_SN_TAG "SN=" +#define SYNO_CHKSUM_TAG "CHK=" + + +static int do_syno_populate(int argc, char * const argv[]) +{ + unsigned int bus = CONFIG_SF_DEFAULT_BUS; + unsigned int cs = CONFIG_SF_DEFAULT_CS; + unsigned int speed = CONFIG_SF_DEFAULT_SPEED; + unsigned int mode = CONFIG_SF_DEFAULT_MODE; + struct spi_flash *flash; + unsigned long addr = 0x80000; /* XXX: parameterize this? */ + loff_t offset = 0x007d0000; + loff_t len = 0x00010000; + char *buf, *bufp; + char var[128]; + char val[128]; + int ret, n; + + /* XXX: arg parsing to select flash here? */ + + flash = spi_flash_probe(bus, cs, speed, mode); + if (!flash) { + printf("Failed to initialize SPI flash at %u:%u\n", bus, cs); + return 1; + } + + buf = map_physmem(addr, len, MAP_WRBACK); + if (!buf) { + puts("Failed to map physical memory\n"); + return 1; + } + + ret = spi_flash_read(flash, offset, len, buf); + if (ret) { + puts("Failed to read from SPI flash\n"); + goto out_unmap; + } + + for (n = 0; n < ETHADDR_MAX; n++) { + char ethaddr[ETH_ALEN]; + int i, sum = 0; + unsigned char csum = 0; + + for (i = 0, bufp = buf + n * 7; i < ETH_ALEN; i++) { + sum += bufp[i]; + csum += bufp[i]; + ethaddr[i] = bufp[i]; + } + if (!sum) /* MAC address empty */ + continue; + if (csum != bufp[i]) { /* seventh byte is checksum value */ + printf("Invalid MAC address for interface %d!\n", n); + continue; + } + if (n == 0) + sprintf(var, "ethaddr"); + else + sprintf(var, "eth%daddr", n); + snprintf(val, sizeof(val) - 1, + "%02x:%02x:%02x:%02x:%02x:%02x", + ethaddr[0], ethaddr[1], ethaddr[2], + ethaddr[3], ethaddr[4], ethaddr[5]); + printf("parsed %s = %s\n", var, val); + setenv(var, val); + } + if (!strncmp(buf + 32, SYNO_SN_TAG, strlen(SYNO_SN_TAG))) { + char *snp, *csump; + int csum = 0; + unsigned long c; + + snp = bufp = buf + 32 + strlen(SYNO_SN_TAG); + for (n = 0; bufp[n] && bufp[n] != ','; n++) + csum += bufp[n]; + bufp[n] = '\0'; + + /* should come right after, but you never know */ + bufp = strstr(bufp + n + 1, SYNO_CHKSUM_TAG); + if (!bufp) { + printf("Serial number checksum tag missing!\n"); + goto out_unmap; + } + + csump = bufp += strlen(SYNO_CHKSUM_TAG); + for (n = 0; bufp[n] && bufp[n] != ','; n++) + ; + bufp[n] = '\0'; + + if (strict_strtoul(csump, 10, &c) || c != csum) { + puts("Invalid serial number found!\n"); + ret = 1; + goto out_unmap; + } + printf("parsed SN = %s\n", snp); + setenv("SN", snp); + } else { /* old style format */ + unsigned char csum = 0; + + for (n = 0, bufp = buf + 32; n < 10; n++) + csum += bufp[n]; + + if (csum != bufp[n]) { + puts("Invalid serial number found!\n"); + ret = 1; + goto out_unmap; + } + bufp[n] = '\0'; + printf("parsed SN = %s\n", buf + 32); + setenv("SN", buf + 32); + } +out_unmap: + unmap_physmem(buf, len); + return ret; +} + +/* map bit position to function in POWER_MNG_CTRL_REG */ +static const char * const pwr_mng_bit_func[] = { + "audio", + "ge3", "ge2", "ge1", "ge0", + "pcie00", "pcie01", "pcie02", "pcie03", + "pcie10", "pcie11", "pcie12", "pcie13", + "bp", + "sata0_link", "sata0_core", + "lcd", + "sdio", + "usb0", "usb1", "usb2", + "idma", "xor0", "crypto", + NULL, + "tdm", + "pcie20", "pcie30", + "xor1", + "sata1_link", "sata1_core", + NULL, +}; + +static int do_syno_clk_gate(int argc, char * const argv[]) +{ + u32 pwr_mng_ctrl_reg = reg_read(POWER_MNG_CTRL_REG); + const char *func, *state; + int i, val; + + if (argc < 2) + return -1; + + if (!strcmp(argv[1], "get")) { + puts("Clock Gating:\n"); + for (i = 0; i < 32; i++) { + func = pwr_mng_bit_func[i]; + if (!func) + continue; + state = pwr_mng_ctrl_reg & (1 << i) ? "ON" : "OFF"; + printf("%s:\t\t%s\n", func, state); + } + return 0; + } + if (argc < 4) + return -1; + if (!strcmp(argv[1], "set")) { + func = argv[2]; + state = argv[3]; + for (i = 0; i < 32; i++) { + if (!pwr_mng_bit_func[i]) + continue; + if (!strcmp(func, pwr_mng_bit_func[i])) + break; + } + if (i == 32) { + printf("Error: name '%s' not known\n", func); + return -1; + } + val = state[0] != '0'; + pwr_mng_ctrl_reg |= (val << i); + pwr_mng_ctrl_reg &= ~(!val << i); + reg_write(POWER_MNG_CTRL_REG, pwr_mng_ctrl_reg); + } + return 0; +} + +static int do_syno(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + const char *cmd; + int ret = 0; + + if (argc < 2) + goto usage; + + cmd = argv[1]; + --argc; + ++argv; + + if (!strcmp(cmd, "populate_env")) + ret = do_syno_populate(argc, argv); + else if (!strcmp(cmd, "clk_gate")) + ret = do_syno_clk_gate(argc, argv); + + if (ret != -1) + return ret; +usage: + return CMD_RET_USAGE; +} + +U_BOOT_CMD( + syno, 5, 1, do_syno, + "Synology specific commands", + "populate_env - Read vendor data from SPI flash into environment\n" + "clk_gate (get|set name 1|0) - Manage clock gating\n" +); diff --git a/board/Synology/ds414/Makefile b/board/Synology/ds414/Makefile new file mode 100644 index 0000000..0f4c32d --- /dev/null +++ b/board/Synology/ds414/Makefile @@ -0,0 +1,7 @@ +# +# Copyright (C) 2015 Phil Sutter <phil@nwl.cc> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y := ds414.o diff --git a/board/Synology/ds414/ds414.c b/board/Synology/ds414/ds414.c new file mode 100644 index 0000000..d563e89 --- /dev/null +++ b/board/Synology/ds414/ds414.c @@ -0,0 +1,185 @@ +/* + * + * Copyright (C) 2015 Phil Sutter <phil@nwl.cc> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <miiphy.h> +#include <asm/io.h> +#include <asm/arch/cpu.h> +#include <asm/arch/soc.h> +#include <linux/mbus.h> + +#include "../drivers/ddr/marvell/axp/ddr3_hw_training.h" +#include "../arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.h" +#include "../arch/arm/mach-mvebu/serdes/axp/board_env_spec.h" + +DECLARE_GLOBAL_DATA_PTR; + +/* GPP and MPP settings as found in mvBoardEnvSpec.c of Synology's U-Boot */ + +#define DS414_GPP_OUT_VAL_LOW (BIT(25) | BIT(30)) +#define DS414_GPP_OUT_VAL_MID (BIT(10) | BIT(15)) +#define DS414_GPP_OUT_VAL_HIGH (0) + +#define DS414_GPP_OUT_POL_LOW (0) +#define DS414_GPP_OUT_POL_MID (0) +#define DS414_GPP_OUT_POL_HIGH (0) + +#define DS414_GPP_OUT_ENA_LOW (~(BIT(25) | BIT(30))) +#define DS414_GPP_OUT_ENA_MID (~(BIT(10) | BIT(12) | \ + BIT(13) | BIT(14) | BIT(15))) +#define DS414_GPP_OUT_ENA_HIGH (~0) + +static const u32 ds414_mpp_control[] = { + 0x11111111, + 0x22221111, + 0x22222222, + 0x00000000, + 0x11110000, + 0x00004000, + 0x00000000, + 0x00000000, + 0x00000000 +}; + +/* DDR3 static MC configuration */ + +/* 1G_v1 (4x2Gbits) adapted by DS414 */ +MV_DRAM_MC_INIT syno_ddr3_b0_667_1g_v1[MV_MAX_DDR3_STATIC_SIZE] = { + {0x00001400, 0x73014A28}, /*DDR SDRAM Configuration Register */ + {0x00001404, 0x30000800}, /*Dunit Control Low Register */ + {0x00001408, 0x44148887}, /*DDR SDRAM Timing (Low) Register */ + {0x0000140C, 0x3AD83FEA}, /*DDR SDRAM Timing (High) Register */ + + {0x00001410, 0x14000000}, /*DDR SDRAM Address Control Register */ + + {0x00001414, 0x00000000}, /*DDR SDRAM Open Pages Control Register */ + {0x00001418, 0x00000e00}, /*DDR SDRAM Operation Register */ + {0x00001420, 0x00000004}, /*DDR SDRAM Extended Mode Register */ + {0x00001424, 0x0000F3FF}, /*Dunit Control High Register */ + {0x00001428, 0x000F8830}, /*Dunit Control High Register */ + {0x0000142C, 0x054C36F4}, /*Dunit Control High Register */ + {0x0000147C, 0x0000C671}, + + {0x000014a0, 0x00000001}, + {0x000014a8, 0x00000100}, /*2:1 */ + {0x00020220, 0x00000006}, + + {0x00001494, 0x00010000}, /*DDR SDRAM ODT Control (Low) Register */ + {0x00001498, 0x00000000}, /*DDR SDRAM ODT Control (High) Register */ + {0x0000149C, 0x00000001}, /*DDR Dunit ODT Control Register */ + + {0x000014C0, 0x192424C9}, /* DRAM address and Control Driving Strenght */ + {0x000014C4, 0x0AAA24C9}, /* DRAM Data and DQS Driving Strenght */ + + {0x000200e8, 0x3FFF0E01}, /* DO NOT Modify - Open Mbus Window - 2G - Mbus is required for the training sequence*/ + {0x00020184, 0x3FFFFFE0}, /* DO NOT Modify - Close fast path Window to - 2G */ + + {0x0001504, 0x3FFFFFE1}, /* CS0 Size */ + {0x000150C, 0x00000000}, /* CS1 Size */ + {0x0001514, 0x00000000}, /* CS2 Size */ + {0x000151C, 0x00000000}, /* CS3 Size */ + + {0x00001538, 0x00000009}, /*Read Data Sample Delays Register */ + {0x0000153C, 0x00000009}, /*Read Data Ready Delay Register */ + + {0x000015D0, 0x00000650}, /*MR0 */ + {0x000015D4, 0x00000044}, /*MR1 */ + {0x000015D8, 0x00000010}, /*MR2 */ + {0x000015DC, 0x00000000}, /*MR3 */ + + {0x000015E4, 0x00203c18}, /*ZQC Configuration Register */ + {0x000015EC, 0xF800A225}, /*DDR PHY */ + + {0x0, 0x0} +}; + +MV_DRAM_MODES ds414_ddr_modes[MV_DDR3_MODES_NUMBER] = { + {"ds414_1333-667", 0x3, 0x5, 0x0, A0, syno_ddr3_b0_667_1g_v1, NULL}, +}; + +extern MV_SERDES_CHANGE_M_PHY serdes_change_m_phy[]; + +MV_BIN_SERDES_CFG ds414_serdes_cfg[] = { + { MV_PEX_ROOT_COMPLEX, 0x02011111, 0x00000000, + { PEX_BUS_MODE_X4, PEX_BUS_MODE_X1, PEX_BUS_DISABLED, + PEX_BUS_DISABLED }, + 0x0040, serdes_change_m_phy + } +}; + +MV_DRAM_MODES *ddr3_get_static_ddr_mode(void) +{ + return &ds414_ddr_modes[0]; +} + +MV_BIN_SERDES_CFG *board_serdes_cfg_get(u8 pex_mode) +{ + return &ds414_serdes_cfg[0]; +} + +u8 board_sat_r_get(u8 dev_num, u8 reg) +{ + return (0x1 << 1 | 1); +} + +int board_early_init_f(void) +{ + int i; + + /* Set GPP Out value */ + reg_write(GPP_DATA_OUT_REG(0), DS414_GPP_OUT_VAL_LOW); + reg_write(GPP_DATA_OUT_REG(1), DS414_GPP_OUT_VAL_MID); + reg_write(GPP_DATA_OUT_REG(2), DS414_GPP_OUT_VAL_HIGH); + + /* set GPP polarity */ + reg_write(GPP_DATA_IN_POL_REG(0), DS414_GPP_OUT_POL_LOW); + reg_write(GPP_DATA_IN_POL_REG(1), DS414_GPP_OUT_POL_MID); + reg_write(GPP_DATA_IN_POL_REG(2), DS414_GPP_OUT_POL_HIGH); + + /* Set GPP Out Enable */ + reg_write(GPP_DATA_OUT_EN_REG(0), DS414_GPP_OUT_ENA_LOW); + reg_write(GPP_DATA_OUT_EN_REG(1), DS414_GPP_OUT_ENA_MID); + reg_write(GPP_DATA_OUT_EN_REG(2), DS414_GPP_OUT_ENA_HIGH); + + for (i = 0; i < ARRAY_SIZE(ds414_mpp_control); i++) + reg_write(MPP_CONTROL_REG(i), ds414_mpp_control[i]); + + return 0; +} + +int board_init(void) +{ + u32 pwr_mng_ctrl_reg; + + /* Adress of boot parameters */ + gd->bd->bi_boot_params = mvebu_sdram_bar(0) + 0x100; + + /* Gate unused clocks + * + * Note: Disabling unused PCIe lanes will hang PCI bus scan. + * Once this is resolved, bits 10-12, 26 and 27 can be + * unset here as well. + */ + pwr_mng_ctrl_reg = reg_read(POWER_MNG_CTRL_REG); + pwr_mng_ctrl_reg &= ~(BIT(0)); /* Audio */ + pwr_mng_ctrl_reg &= ~(BIT(1) | BIT(2)); /* GE3, GE2 */ + pwr_mng_ctrl_reg &= ~(BIT(14) | BIT(15)); /* SATA0 link and core */ + pwr_mng_ctrl_reg &= ~(BIT(16)); /* LCD */ + pwr_mng_ctrl_reg &= ~(BIT(17)); /* SDIO */ + pwr_mng_ctrl_reg &= ~(BIT(19) | BIT(20)); /* USB1 and USB2 */ + pwr_mng_ctrl_reg &= ~(BIT(29) | BIT(30)); /* SATA1 link and core */ + reg_write(POWER_MNG_CTRL_REG, pwr_mng_ctrl_reg); + + return 0; +} + +int checkboard(void) +{ + puts("Board: DS414\n"); + + return 0; +} diff --git a/board/Synology/ds414/kwbimage.cfg b/board/Synology/ds414/kwbimage.cfg new file mode 100644 index 0000000..1f748db --- /dev/null +++ b/board/Synology/ds414/kwbimage.cfg @@ -0,0 +1,12 @@ +# +# Copyright (C) 2014 Stefan Roese <sr@denx.de> +# + +# Armada XP uses version 1 image format +VERSION 1 + +# Boot Media configurations +BOOT_FROM spi + +# Binary Header (bin_hdr) with DDR3 training code +BINARY spl/u-boot-spl-dtb.bin 0000005b 00000068 |