From patchwork Mon Sep 8 12:08:45 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Machek X-Patchwork-Id: 386904 X-Patchwork-Delegate: marek.vasut@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id AA60614017B for ; Mon, 8 Sep 2014 22:09:15 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id A45B8A7405; Mon, 8 Sep 2014 14:09:12 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id atLG+cw965lM; Mon, 8 Sep 2014 14:09:12 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id EF05BA7406; Mon, 8 Sep 2014 14:09:07 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id DF3FEA73FA; Mon, 8 Sep 2014 14:09:00 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id WyWW9uQ+g+-k; Mon, 8 Sep 2014 14:08:56 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from atrey.karlin.mff.cuni.cz (atrey.karlin.mff.cuni.cz [195.113.26.193]) by theia.denx.de (Postfix) with ESMTP id 76EF3A73E8; Mon, 8 Sep 2014 14:08:48 +0200 (CEST) Received: by atrey.karlin.mff.cuni.cz (Postfix, from userid 512) id 021AB81D7C; Mon, 8 Sep 2014 14:08:46 +0200 (CEST) Date: Mon, 8 Sep 2014 14:08:45 +0200 From: Pavel Machek To: socfpga@lists.denx.de, u-boot@lists.denx.de, clsee@altera.com, marex@denx.de Message-ID: <20140908120845.GA19660@amd> References: <20140903193420.GA18388@amd> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20140903193420.GA18388@amd> User-Agent: Mutt/1.5.23 (2014-03-12) Subject: [U-Boot] [RFCv2] mainline u-boot on socfpga X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de Hi! I know coding style leaves something to be desired. But.. it recognizes MMC/ethernet, and can load linux kernel. Unfortunately, 1MB of memory at 0 is not available for some reason; but linux works ok if you avoid that area. "fpga load 0" now seems to work. For some reason, I had to rewrite fpgamgr_axi_write(). There's some bug in assembly version, causing code to get confused after it is executed. If some ARM expert could take a look, that would be great; bug is likely also present in rocketboards version of u-boot. Best regards, Pavel diff --git a/arch/arm/cpu/armv7/socfpga/Makefile b/arch/arm/cpu/armv7/socfpga/Makefile index eb33f2c..c36e0d0 100644 --- a/arch/arm/cpu/armv7/socfpga/Makefile +++ b/arch/arm/cpu/armv7/socfpga/Makefile @@ -10,3 +10,4 @@ obj-y := lowlevel_init.o obj-y += misc.o timer.o reset_manager.o system_manager.o clock_manager.o obj-$(CONFIG_SPL_BUILD) += spl.o freeze_controller.o scan_manager.o +obj-y += fpga_manager.o diff --git a/arch/arm/cpu/armv7/socfpga/clock_manager.c b/arch/arm/cpu/armv7/socfpga/clock_manager.c index 158501a..fae5724 100644 --- a/arch/arm/cpu/armv7/socfpga/clock_manager.c +++ b/arch/arm/cpu/armv7/socfpga/clock_manager.c @@ -30,6 +30,10 @@ static const struct socfpga_clock_manager *clock_manager_base = CLKMGR_MAINPLLGRP_VCO_EN_SET(1)| \ CLKMGR_MAINPLLGRP_VCO_BGPWRDN_SET(0)) +unsigned long cm_l4_sp_clock; +unsigned long cm_sdmmc_clock; +unsigned long cm_qspi_clock; + static inline void cm_wait_for_lock(uint32_t mask) { register uint32_t inter_val; @@ -358,3 +362,219 @@ void cm_basic_init(const cm_config_t *cfg) writel(~0, &clock_manager_base->per_pll.en); writel(~0, &clock_manager_base->sdr_pll.en); } + +#define CLKMGR_CTRL_ADDRESS 0x0 +#define CLKMGR_BYPASS_ADDRESS 0x4 +#define CLKMGR_INTER_ADDRESS 0x8 +#define CLKMGR_INTREN_ADDRESS 0xc +#define CLKMGR_DBCTRL_ADDRESS 0x10 +#define CLKMGR_STAT_ADDRESS 0x14 +#define CLKMGR_MAINPLLGRP_ADDRESS 0x40 +#define CLKMGR_MAINPLLGRP_VCO_ADDRESS 0x40 +#define CLKMGR_MAINPLLGRP_MISC_ADDRESS 0x44 +#define CLKMGR_MAINPLLGRP_MPUCLK_ADDRESS 0x48 +#define CLKMGR_MAINPLLGRP_MAINCLK_ADDRESS 0x4c +#define CLKMGR_MAINPLLGRP_DBGATCLK_ADDRESS 0x50 +#define CLKMGR_MAINPLLGRP_MAINQSPICLK_ADDRESS 0x54 +#define CLKMGR_MAINPLLGRP_MAINNANDSDMMCCLK_ADDRESS 0x58 +#define CLKMGR_MAINPLLGRP_CFGS2FUSER0CLK_ADDRESS 0x5c +#define CLKMGR_MAINPLLGRP_EN_ADDRESS 0x60 +#define CLKMGR_MAINPLLGRP_MAINDIV_ADDRESS 0x64 +#define CLKMGR_MAINPLLGRP_DBGDIV_ADDRESS 0x68 +#define CLKMGR_MAINPLLGRP_TRACEDIV_ADDRESS 0x6c +#define CLKMGR_MAINPLLGRP_L4SRC_ADDRESS 0x70 +#define CLKMGR_PERPLLGRP_ADDRESS 0x80 +#define CLKMGR_PERPLLGRP_VCO_ADDRESS 0x80 +#define CLKMGR_PERPLLGRP_MISC_ADDRESS 0x84 +#define CLKMGR_PERPLLGRP_EMAC0CLK_ADDRESS 0x88 +#define CLKMGR_PERPLLGRP_EMAC1CLK_ADDRESS 0x8c +#define CLKMGR_PERPLLGRP_PERQSPICLK_ADDRESS 0x90 +#define CLKMGR_PERPLLGRP_PERNANDSDMMCCLK_ADDRESS 0x94 +#define CLKMGR_PERPLLGRP_PERBASECLK_ADDRESS 0x98 +#define CLKMGR_PERPLLGRP_S2FUSER1CLK_ADDRESS 0x9c +#define CLKMGR_PERPLLGRP_EN_ADDRESS 0xa0 +#define CLKMGR_PERPLLGRP_DIV_ADDRESS 0xa4 +#define CLKMGR_PERPLLGRP_GPIODIV_ADDRESS 0xa8 +#define CLKMGR_PERPLLGRP_SRC_ADDRESS 0xac +#define CLKMGR_SDRPLLGRP_ADDRESS 0xc0 +#define CLKMGR_SDRPLLGRP_VCO_ADDRESS 0xc0 +#define CLKMGR_SDRPLLGRP_CTRL_ADDRESS 0xc4 +#define CLKMGR_SDRPLLGRP_DDRDQSCLK_ADDRESS 0xc8 +#define CLKMGR_SDRPLLGRP_DDR2XDQSCLK_ADDRESS 0xcc +#define CLKMGR_SDRPLLGRP_DDRDQCLK_ADDRESS 0xd0 +#define CLKMGR_SDRPLLGRP_S2FUSER2CLK_ADDRESS 0xd4 +#define CLKMGR_SDRPLLGRP_EN_ADDRESS 0xd8 +#define CLKMGR_ALTERAGRP_MPUCLK 0xe0 +#define CLKMGR_ALTERAGRP_MAINCLK 0xe4 + +#define CLKMGR_MAINPLLGRP_VCO_DENOM_GET(x) (((x) & 0x003f0000) >> 16) +#define CLKMGR_MAINPLLGRP_VCO_NUMER_GET(x) (((x) & 0x0000fff8) >> 3) +#define CLKMGR_MAINPLLGRP_L4SRC_L4SP_GET(x) (((x) & 0x00000002) >> 1) +#define CLKMGR_MAINPLLGRP_MAINDIV_L4SPCLK_GET(x) (((x) & 0x00000380) >> 7) +#define CLKMGR_SDRPLLGRP_VCO_SSRC_GET(x) (((x) & 0x00c00000) >> 22) +#define CLKMGR_SDRPLLGRP_VCO_DENOM_GET(x) (((x) & 0x003f0000) >> 16) +#define CLKMGR_SDRPLLGRP_VCO_NUMER_GET(x) (((x) & 0x0000fff8) >> 3) +#define CLKMGR_SDRPLLGRP_DDRDQSCLK_CNT_GET(x) (((x) & 0x000001ff) >> 0) +#define CLKMGR_PERPLLGRP_VCO_SSRC_GET(x) (((x) & 0x00c00000) >> 22) +#define CLKMGR_PERPLLGRP_VCO_DENOM_GET(x) (((x) & 0x003f0000) >> 16) +#define CLKMGR_PERPLLGRP_VCO_NUMER_GET(x) (((x) & 0x0000fff8) >> 3) +#define CLKMGR_PERPLLGRP_SRC_QSPI_GET(x) (((x) & 0x00000030) >> 4) +#define CLKMGR_PERPLLGRP_SRC_SDMMC_GET(x) (((x) & 0x00000003) >> 0) + +#define CLKMGR_VCO_SSRC_EOSC1 0x0 +#define CLKMGR_VCO_SSRC_EOSC2 0x1 +#define CLKMGR_VCO_SSRC_F2S 0x2 +#define CLKMGR_L4_SP_CLK_SRC_MAINPLL 0x0 +#define CLKMGR_L4_SP_CLK_SRC_PERPLL 0x1 +#define CLKMGR_SDMMC_CLK_SRC_F2S 0x0 +#define CLKMGR_SDMMC_CLK_SRC_MAIN 0x1 +#define CLKMGR_SDMMC_CLK_SRC_PER 0x2 +#define CLKMGR_QSPI_CLK_SRC_F2S 0x0 +#define CLKMGR_QSPI_CLK_SRC_MAIN 0x1 +#define CLKMGR_QSPI_CLK_SRC_PER 0x2 + +#define CLKMGR_L4_SP_CLK_SRC_MAINPLL 0x0 +#define CLKMGR_L4_SP_CLK_SRC_PERPLL 0x1 +#define CLKMGR_SDMMC_CLK_SRC_F2S 0x0 +#define CLKMGR_SDMMC_CLK_SRC_MAIN 0x1 +#define CLKMGR_SDMMC_CLK_SRC_PER 0x2 +#define CLKMGR_QSPI_CLK_SRC_F2S 0x0 +#define CLKMGR_QSPI_CLK_SRC_MAIN 0x1 +#define CLKMGR_QSPI_CLK_SRC_PER 0x2 + +#define CONFIG_HPS_CLK_OSC2_HZ (0) +#define CONFIG_HPS_CLK_F2S_SDR_REF_HZ (0) +#define CONFIG_HPS_CLK_F2S_PER_REF_HZ (0) + +unsigned long cm_get_l4_sp_clk_hz(void) +{ + uint32_t reg, clock = 0; + + /* identify the source of L4 SP clock */ + reg = readl(SOCFPGA_CLKMGR_ADDRESS + CLKMGR_MAINPLLGRP_L4SRC_ADDRESS); + reg = CLKMGR_MAINPLLGRP_L4SRC_L4SP_GET(reg); + + if (reg == CLKMGR_L4_SP_CLK_SRC_MAINPLL) { + /* get the main VCO clock */ + reg = readl(SOCFPGA_CLKMGR_ADDRESS + + CLKMGR_MAINPLLGRP_VCO_ADDRESS); + clock = CONFIG_HPS_CLK_OSC1_HZ / + (CLKMGR_MAINPLLGRP_VCO_DENOM_GET(reg) + 1); + clock *= (CLKMGR_MAINPLLGRP_VCO_NUMER_GET(reg) + 1); + + /* get the clock prior L4 SP divider (main clk) */ + reg = readl(SOCFPGA_CLKMGR_ADDRESS + + CLKMGR_ALTERAGRP_MAINCLK); + clock /= (reg + 1); + reg = readl(SOCFPGA_CLKMGR_ADDRESS + + CLKMGR_MAINPLLGRP_MAINCLK_ADDRESS); + clock /= (reg + 1); + } else if (reg == CLKMGR_L4_SP_CLK_SRC_PERPLL) { + /* identify PER PLL clock source */ + reg = readl(SOCFPGA_CLKMGR_ADDRESS + + CLKMGR_PERPLLGRP_VCO_ADDRESS); + reg = CLKMGR_PERPLLGRP_VCO_SSRC_GET(reg); + if (reg == CLKMGR_VCO_SSRC_EOSC1) + clock = CONFIG_HPS_CLK_OSC1_HZ; + else if (reg == CLKMGR_VCO_SSRC_EOSC2) + clock = CONFIG_HPS_CLK_OSC2_HZ; + else if (reg == CLKMGR_VCO_SSRC_F2S) + clock = CONFIG_HPS_CLK_F2S_PER_REF_HZ; + + /* get the PER VCO clock */ + reg = readl(SOCFPGA_CLKMGR_ADDRESS + + CLKMGR_PERPLLGRP_VCO_ADDRESS); + clock /= (CLKMGR_PERPLLGRP_VCO_DENOM_GET(reg) + 1); + clock *= (CLKMGR_PERPLLGRP_VCO_NUMER_GET(reg) + 1); + + /* get the clock prior L4 SP divider (periph_base_clk) */ + reg = readl(SOCFPGA_CLKMGR_ADDRESS + + CLKMGR_PERPLLGRP_PERBASECLK_ADDRESS); + clock /= (reg + 1); + } + + /* get the L4 SP clock which supplied to UART */ + reg = readl(SOCFPGA_CLKMGR_ADDRESS + CLKMGR_MAINPLLGRP_MAINDIV_ADDRESS); + reg = CLKMGR_MAINPLLGRP_MAINDIV_L4SPCLK_GET(reg); + clock = clock / (reg + 1); + + return clock; +} + +void cm_print_clock_quick_summary(void) +{ + printf("CLOCK: EOSC1 clock %d KHz\n", + (CONFIG_HPS_CLK_OSC1_HZ / 1000)); + printf("CLOCK: EOSC2 clock %d KHz\n", + (CONFIG_HPS_CLK_OSC2_HZ / 1000)); + printf("CLOCK: F2S_SDR_REF clock %d KHz\n", + (CONFIG_HPS_CLK_F2S_SDR_REF_HZ / 1000)); + printf("CLOCK: F2S_PER_REF clock %d KHz\n", + (CONFIG_HPS_CLK_F2S_PER_REF_HZ / 1000)); + printf("CLOCK: UART clock %ld KHz\n", + (cm_get_l4_sp_clk_hz() / 1000)); + +} + +unsigned long cm_get_mmc_controller_clk_hz(void) +{ + uint32_t reg, clock = 0; + + /* identify the source of MMC clock */ + reg = readl(SOCFPGA_CLKMGR_ADDRESS + CLKMGR_PERPLLGRP_SRC_ADDRESS); + reg = CLKMGR_PERPLLGRP_SRC_SDMMC_GET(reg); + + if (reg == CLKMGR_SDMMC_CLK_SRC_F2S) + clock = CONFIG_HPS_CLK_F2S_PER_REF_HZ; + else if (reg == CLKMGR_SDMMC_CLK_SRC_MAIN) { + /* get the main VCO clock */ + reg = readl(SOCFPGA_CLKMGR_ADDRESS + + CLKMGR_MAINPLLGRP_VCO_ADDRESS); + clock = CONFIG_HPS_CLK_OSC1_HZ / + (CLKMGR_MAINPLLGRP_VCO_DENOM_GET(reg) + 1); + clock *= (CLKMGR_MAINPLLGRP_VCO_NUMER_GET(reg) + 1); + + /* get the SDMMC clock */ + reg = readl(SOCFPGA_CLKMGR_ADDRESS + + CLKMGR_MAINPLLGRP_MAINNANDSDMMCCLK_ADDRESS); + clock /= (reg + 1); + } else if (reg == CLKMGR_SDMMC_CLK_SRC_PER) { + /* identify PER PLL clock source */ + reg = readl(SOCFPGA_CLKMGR_ADDRESS + + CLKMGR_PERPLLGRP_VCO_ADDRESS); + reg = CLKMGR_PERPLLGRP_VCO_SSRC_GET(reg); + if (reg == CLKMGR_VCO_SSRC_EOSC1) + clock = CONFIG_HPS_CLK_OSC1_HZ; + else if (reg == CLKMGR_VCO_SSRC_EOSC2) + clock = CONFIG_HPS_CLK_OSC2_HZ; + else if (reg == CLKMGR_VCO_SSRC_F2S) + clock = CONFIG_HPS_CLK_F2S_PER_REF_HZ; + + /* get the PER VCO clock */ + reg = readl(SOCFPGA_CLKMGR_ADDRESS + + CLKMGR_PERPLLGRP_VCO_ADDRESS); + clock /= (CLKMGR_PERPLLGRP_VCO_DENOM_GET(reg) + 1); + clock *= (CLKMGR_PERPLLGRP_VCO_NUMER_GET(reg) + 1); + + /* get the SDMMC clock */ + reg = readl(SOCFPGA_CLKMGR_ADDRESS + + CLKMGR_PERPLLGRP_PERNANDSDMMCCLK_ADDRESS); + clock /= (reg + 1); + } + + /* further divide by 4 as we have fixed divider at wrapper */ + clock /= 4; + return clock; +} + +void cm_derive_clocks_for_drivers(void) +{ + cm_l4_sp_clock = cm_get_l4_sp_clk_hz(); + cm_sdmmc_clock = cm_get_mmc_controller_clk_hz(); + + cm_print_clock_quick_summary(); + printf("sdmmc_clock: %d\n", cm_sdmmc_clock); +#if 0 + cm_qspi_clock = cm_get_qspi_controller_clk_hz(); +#endif +} diff --git a/arch/arm/cpu/armv7/socfpga/fpga_manager.c b/arch/arm/cpu/armv7/socfpga/fpga_manager.c new file mode 100644 index 0000000..19e4eea --- /dev/null +++ b/arch/arm/cpu/armv7/socfpga/fpga_manager.c @@ -0,0 +1,378 @@ +/* + * + * Copyright (C) 2012 Altera Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the Altera Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL ALTERA CORPORATION BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +static const struct socfpga_fpga_manager *fpga_manager_base = + (void *)SOCFPGA_FPGAMGRREGS_ADDRESS; + +#define DEBUG_MEMORY printf("%s\n", __func__ ); +#define SDR_CTRLGRP_FPGAPORTRST_ADDRESS 0x5080 + +/* Check whether FPGA Init_Done signal is high */ +static int is_fpgamgr_initdone_high(void) +{ + unsigned long val; + DEBUG_MEMORY + val = readl(SOCFPGA_FPGAMGRREGS_ADDRESS + + FPGAMGRREGS_MON_GPIO_EXT_PORTA_ADDRESS); + if (val & FPGAMGRREGS_MON_GPIO_EXT_PORTA_ID_MASK) + return 1; + else + return 0; +} + +/* Get the FPGA mode */ +static int fpgamgr_get_mode(void) +{ + unsigned long val; + //DEBUG_MEMORY + printf("get_mode "); + val = readl(&fpga_manager_base->stat); + val = val & FPGAMGRREGS_STAT_MODE_MASK; + return val; +} + +/* Check whether FPGA is ready to be accessed */ +int is_fpgamgr_fpga_ready(void) +{ + /* check for init done signal */ + if (is_fpgamgr_initdone_high() == 0) + return 0; + /* check again to avoid false glitches */ + if (is_fpgamgr_initdone_high() == 0) + return 0; + if (fpgamgr_get_mode() != FPGAMGRREGS_MODE_USERMODE) + return 0; + return 1; +} + +/* Poll until FPGA is ready to be accessed or timeout occurred */ +int poll_fpgamgr_fpga_ready(void) +{ + unsigned long i; + DEBUG_MEMORY + /* If FPGA is blank, wait till WD invoke warm reset */ + for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { + /* check for init done signal */ + if (is_fpgamgr_initdone_high() == 0) + continue; + /* check again to avoid false glitches */ + if (is_fpgamgr_initdone_high() == 0) + continue; + return 1; + } + DEBUG_MEMORY + return 0; +} + +/* set CD ratio */ +static void fpgamgr_set_cd_ratio(unsigned long ratio) +{ + unsigned long reg; + reg = readl(&fpga_manager_base->ctrl); + reg = (reg & ~(0x3 << FPGAMGRREGS_CTRL_CDRATIO_LSB)) | + ((ratio & 0x3) << FPGAMGRREGS_CTRL_CDRATIO_LSB); + writel(reg, &fpga_manager_base->ctrl); +} + +static int fpgamgr_dclkcnt_set(unsigned long cnt) +{ + unsigned long i; + + /* clear any existing done status */ + if (readl(&fpga_manager_base->dclkstat)) + writel(0x1, &fpga_manager_base->dclkstat); + /* write the dclkcnt */ + writel(cnt, &fpga_manager_base->dclkcnt); + /* + * wait till the dclkcnt done + */ + for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { + if (readl(&fpga_manager_base->dclkstat)) { + writel(0x1, &fpga_manager_base->dclkstat); + return 0; + } + } + return -1; +} + +/* Start the FPGA programming by initialize the FPGA Manager */ +int fpgamgr_program_init(void) +{ + unsigned long reg, i; + + debug("fpga: program_init\n"); + /* get the MSEL value */ + reg = readl(&fpga_manager_base->stat); + reg = ((reg & FPGAMGRREGS_STAT_MSEL_MASK) >> FPGAMGRREGS_STAT_MSEL_LSB); + + /* + * Set the cfg width + * If MSEL[3] = 1, cfg width = 32 bit + */ + if (reg & 0x8) + setbits_le32(&fpga_manager_base->ctrl, + FPGAMGRREGS_CTRL_CFGWDTH_MASK); + else + clrbits_le32(&fpga_manager_base->ctrl, + FPGAMGRREGS_CTRL_CFGWDTH_MASK); + + /* To determine the CD ratio */ + /* MSEL[3] = 1 & MSEL[1:0] = 0, CD Ratio = 1 */ + if ((reg & 0xb) == 0x8) + fpgamgr_set_cd_ratio(CDRATIO_x1); + /* MSEL[3] = 1 & MSEL[1:0] = 1, CD Ratio = 4 */ + else if ((reg & 0xb) == 0x9) + fpgamgr_set_cd_ratio(CDRATIO_x4); + /* MSEL[3] = 1 & MSEL[1:0] = 2, CD Ratio = 8 */ + else if ((reg & 0xb) == 0xa) + fpgamgr_set_cd_ratio(CDRATIO_x8); + /* MSEL[3] = 0 & MSEL[1:0] = 0, CD Ratio = 1 */ + else if ((reg & 0xb) == 0x0) + fpgamgr_set_cd_ratio(CDRATIO_x1); + /* MSEL[3] = 0 & MSEL[1:0] = 1, CD Ratio = 2 */ + else if ((reg & 0xb) == 0x1) + fpgamgr_set_cd_ratio(CDRATIO_x2); + /* MSEL[3] = 0 & MSEL[1:0] = 2, CD Ratio = 4 */ + else if ((reg & 0xb) == 0x2) + fpgamgr_set_cd_ratio(CDRATIO_x4); + + debug("fpga: enable config\n"); + + /* to enable FPGA Manager configuration */ + clrbits_le32(&fpga_manager_base->ctrl, FPGAMGRREGS_CTRL_NCE_MASK); + + /* to enable FPGA Manager drive over configuration line */ + setbits_le32(&fpga_manager_base->ctrl, FPGAMGRREGS_CTRL_EN_MASK); + + /* put FPGA into reset phase */ + setbits_le32(&fpga_manager_base->ctrl, + FPGAMGRREGS_CTRL_NCONFIGPULL_MASK); + + debug("fpga: wait for reset\n"); + + /* (1) wait until FPGA enter reset phase */ + for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { + if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_RESETPHASE) + break; + } + /* if not in reset state, return error */ + if (fpgamgr_get_mode() != FPGAMGRREGS_MODE_RESETPHASE) { + printf("fpga: could not reset\n"); + return -1; + } + + /* release FPGA from reset phase */ + clrbits_le32(&fpga_manager_base->ctrl, + FPGAMGRREGS_CTRL_NCONFIGPULL_MASK); + + debug("fpga: wait for config\n"); + + /* (2) wait until FPGA enter configuration phase */ + for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { + if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_CFGPHASE) + break; + } + /* if not in configuration state, return error */ + if (fpgamgr_get_mode() != FPGAMGRREGS_MODE_CFGPHASE) + return -2; + + /* clear all interrupts in CB Monitor */ + writel(0xFFF, (SOCFPGA_FPGAMGRREGS_ADDRESS + + FPGAMGRREGS_MON_GPIO_PORTA_EOI_ADDRESS)); + + /* enable AXI configuration */ + setbits_le32(&fpga_manager_base->ctrl, FPGAMGRREGS_CTRL_AXICFGEN_MASK); + + debug("fpga: prepare done\n"); + + return 0; +} + +/* Write the RBF data to FPGA Manager */ +void fpgamgr_program_write(const unsigned long *rbf_data, + unsigned long rbf_size) +{ + printf("copying from %lx to %lx, %d bytes\n", rbf_data, SOCFPGA_FPGAMGRDATA_ADDRESS, rbf_size); + + printf("_axi_write\n"); + // fpgamgr_axi_write(rbf_data, SOCFPGA_FPGAMGRDATA_ADDRESS, rbf_size); + { + long i; + for (i=0; i<(rbf_size/4); i++) { + volatile long *data = SOCFPGA_FPGAMGRDATA_ADDRESS; + *data = rbf_data[i]; + } + } + + printf("_axi_done\n"); + + printf("copying done.\n"); +} + +/* Ensure the FPGA entering config done */ +int fpgamgr_program_poll_cd(void) +{ + unsigned long reg, i; + + printf("poll_cd, %d\n", FPGA_TIMEOUT_CNT); + /* (3) wait until full config done */ + for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { + if (!(i % 1000)) + printf("reading %d/%d.\n", i, FPGA_TIMEOUT_CNT); + reg = readl(SOCFPGA_FPGAMGRREGS_ADDRESS + + FPGAMGRREGS_MON_GPIO_EXT_PORTA_ADDRESS); + /* config error */ + if (!(reg & FPGAMGRREGS_MON_GPIO_EXT_PORTA_NS_MASK) && + !(reg & FPGAMGRREGS_MON_GPIO_EXT_PORTA_CD_MASK)) + return -3; + /* config done without error */ + if ((reg & FPGAMGRREGS_MON_GPIO_EXT_PORTA_NS_MASK) && + (reg & FPGAMGRREGS_MON_GPIO_EXT_PORTA_CD_MASK)) + break; + } + + /* tiemout happen, return error */ + if (i == FPGA_TIMEOUT_CNT) { + printf("fpga: timeout waiting for program.\n"); + return -4; + } + + /* disable AXI configuration */ + clrbits_le32(&fpga_manager_base->ctrl, FPGAMGRREGS_CTRL_AXICFGEN_MASK); + return 0; +} + +/* Ensure the FPGA entering init phase */ +int fpgamgr_program_poll_initphase(void) +{ + unsigned long i; + + /* additional clocks for the CB to enter initialization phase */ + if (fpgamgr_dclkcnt_set(0x4) != 0) + return -5; + + /* (4) wait until FPGA enter init phase or user mode */ + for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { + if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_INITPHASE) + break; + if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_USERMODE) + break; + } + /* if not in configuration state, return error */ + if (i == FPGA_TIMEOUT_CNT) + return -6; + + return 0; +} + +/* Ensure the FPGA entering user mode */ +int fpgamgr_program_poll_usermode(void) +{ + unsigned long i; + + /* additional clocks for the CB to exit initialization phase */ + if (fpgamgr_dclkcnt_set(0x5000) != 0) + return -7; + + /* (5) wait until FPGA enter user mode */ + for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { + if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_USERMODE) + break; + } + /* if not in configuration state, return error */ + if (i == FPGA_TIMEOUT_CNT) + return -8; + + /* to release FPGA Manager drive over configuration line */ + clrbits_le32(&fpga_manager_base->ctrl, FPGAMGRREGS_CTRL_EN_MASK); + + return 0; +} + +/* + * Using FPGA Manager to program the FPGA + * Return 0 for sucess + */ +int fpgamgr_program_fpga(const unsigned long *rbf_data, + unsigned long rbf_size) +{ + unsigned long status; + + printf("program: 1\n"); + /* prior programming the FPGA, all bridges need to be shut off */ + + /* disable all signals from hps peripheral controller to fpga */ + writel(0, SYSMGR_FPGAINTF_MODULE); + + printf("program: 1a\n"); + /* disable all signals from fpga to hps sdram */ + writel(0, (SOCFPGA_SDR_ADDRESS + SDR_CTRLGRP_FPGAPORTRST_ADDRESS)); + + printf("program: 2\n"); + /* disable all axi bridge (hps2fpga, lwhps2fpga & fpga2hps) */ + reset_assert_all_bridges(); + /* unmap the bridges from NIC-301 */ + writel(0x1, SOCFPGA_L3REGS_ADDRESS); + + printf("program: 3\n"); + /* initialize the FPGA Manager */ + status = fpgamgr_program_init(); + if (status) + return status; + + printf("program: 4\n"); + /* Write the RBF data to FPGA Manager */ + fpgamgr_program_write(rbf_data, rbf_size); + + printf("...here!\n"); + + printf("program: 5\n"); + /* Ensure the FPGA entering config done */ + status = fpgamgr_program_poll_cd(); + if (status) + return status; + + printf("program: 6\n"); + + /* Ensure the FPGA entering init phase */ + status = fpgamgr_program_poll_initphase(); + if (status) + return status; + + printf("program: 7\n"); + /* Ensure the FPGA entering user mode */ + return fpgamgr_program_poll_usermode(); +} diff --git a/arch/arm/cpu/armv7/socfpga/lowlevel_init.S b/arch/arm/cpu/armv7/socfpga/lowlevel_init.S index 2f2e9fc..4b5865a 100644 --- a/arch/arm/cpu/armv7/socfpga/lowlevel_init.S +++ b/arch/arm/cpu/armv7/socfpga/lowlevel_init.S @@ -6,6 +6,7 @@ #include #include +#include /* Save the parameter pass in by previous boot loader */ .global save_boot_params @@ -51,3 +52,112 @@ lowlevel_init: str r2, [r1] #endif /* #ifdef CONFIG_SPL_BUILD */ mov pc, lr + +/* + * Write RBF data in burst form to FPGA Manager + * [r0] RBF binary source address + * [r1] FPGA Manager data address + * [r2] RBF data length + */ + + +//ENTRY(fpgamgr_axi_write) +.globl fpgamgr_axi_write +fpgamgr_axi_write: + PUSH {r4-r11, lr} /* save registers per AAPCS */ + +write_burst: + cmp r2,#32 + beq write_burst_cont + bls write_word +write_burst_cont: + ldmia r0!, {r4-r11} + stmia r1, {r4-r11} + subs r2, r2, #32 + b write_burst + +write_word: + cmp r2,#4 + beq write_word_cont + bls write_byte +write_word_cont: + ldmia r0!, {r4} + stmia r1, {r4} + subs r2, r2, #4 + b write_word + + /* FIXME: this is wrong, right? It will copy just one byte when copy of 3 + is requested */ +write_byte: + cmp r2,#0 + beq write_end + ldr r3, [r0] + str r3, [r1] +write_end: + POP {r4-r11, pc} +//ENDPROC(fpgamgr_axi_write) + +#define SDR_CTRLGRP_STATICCFG_ADDRESS 0x505c +#define SDR_CTRLGRP_STATICCFG_APPLYCFG_MASK 0x00000008 + +/* + * Configure the fpga2sdram register + * For U-Boot only and this code need to run on OCRAM + * No stack activity or function call to avoid access to SDRAM + * + * Note that sdram_applycfg_uboot copies fixed ammount of memory; + * be careful if you make this function longer. + */ + +.global sdram_applycfg_ocram +sdram_applycfg_ocram: + mrc p15, 0, r0, c1, c0, 0 @ Read CP15 SCTRL Register + bic r0, #CR_Z @ Disable branch predictor + bic r0, #CR_I @ Disable i-cache + mcr p15, 0, r0, c1, c0, 0 @ Write CP15 SCTRL Register + dsb + isb + + ldr r1, SDR_CTRL + ldr r2, SDR_STATICCFG + add r1, r1, r2 + ldr r0, [r1] + ldr r3, SDR_APPLYCFG_MASK + orr r0, r0, r3 + str r0, [r1] + dsb + isb + + mrc p15, 0, r4, c1, c0, 0 @ Read CP15 SCTRL Register + orr r4, r4, #CR_Z @ Enable back branch predictor + orr r4, r4, #CR_I @ Enable back i-cache + mcr p15, 0, r4, c1, c0, 0 @ Write CP15 SCTRL Register + + mov r0, #0 + mov pc, lr + +SDR_CTRL: .word SOCFPGA_SDR_ADDRESS +SDR_STATICCFG: .word SDR_CTRLGRP_STATICCFG_ADDRESS +SDR_APPLYCFG_MASK: .word SDR_CTRLGRP_STATICCFG_APPLYCFG_MASK + +/* + * Relocate the sdram_applycfg_ocram function to OCRAM and call it + */ +.globl sdram_applycfg_uboot +sdram_applycfg_uboot: + PUSH {r4-r11, lr} /* save registers per AAPCS */ + + ldr r1, =sdram_applycfg_ocram + ldr r2, =CONFIG_SYS_INIT_RAM_ADDR + mov r3, r2 + ldmia r1!, {r4 - r11} + stmia r3!, {r4 - r11} + ldmia r1!, {r4 - r11} /* copy more in case code added */ + stmia r3!, {r4 - r11} /* in the future */ + ldmia r1!, {r4 - r11} /* copy more in case code added */ + stmia r3!, {r4 - r11} /* in the future */ + dsb + isb + blx r2 /* jump to OCRAM */ + POP {r4-r11, pc} + diff --git a/arch/arm/cpu/armv7/socfpga/misc.c b/arch/arm/cpu/armv7/socfpga/misc.c index ecae393..5842734 100644 --- a/arch/arm/cpu/armv7/socfpga/misc.c +++ b/arch/arm/cpu/armv7/socfpga/misc.c @@ -8,6 +8,10 @@ #include #include #include +#include +#include +#include + DECLARE_GLOBAL_DATA_PTR; @@ -17,6 +21,117 @@ int dram_init(void) return 0; } +#define L3REGS_SECGRP_LWHPS2FPGAREGS_ADDRESS 0x20 +#define L3REGS_SECGRP_HPS2FPGAREGS_ADDRESS 0x90 +#define L3REGS_SECGRP_ACP_ADDRESS 0x94 +#define L3REGS_SECGRP_ROM_ADDRESS 0x98 +#define L3REGS_SECGRP_OCRAM_ADDRESS 0x9c +#define L3REGS_SECGRP_SDRDATA_ADDRESS 0xa0 + +#define L3REGS_REMAP_LWHPS2FPGA_MASK 0x00000010 +#define L3REGS_REMAP_HPS2FPGA_MASK 0x00000008 +#define L3REGS_REMAP_OCRAM_MASK 0x00000001 + +/* + * Convert all slave from secure to non secure + */ +void nic301_slave_ns(void) +{ + writel(0x1, (SOCFPGA_L3REGS_ADDRESS + + L3REGS_SECGRP_LWHPS2FPGAREGS_ADDRESS)); + writel(0x1, (SOCFPGA_L3REGS_ADDRESS + + L3REGS_SECGRP_HPS2FPGAREGS_ADDRESS)); + writel(0x1, (SOCFPGA_L3REGS_ADDRESS + + L3REGS_SECGRP_ACP_ADDRESS)); + writel(0x1, (SOCFPGA_L3REGS_ADDRESS + + L3REGS_SECGRP_ROM_ADDRESS)); + writel(0x1, (SOCFPGA_L3REGS_ADDRESS + + L3REGS_SECGRP_OCRAM_ADDRESS)); + writel(0x1, (SOCFPGA_L3REGS_ADDRESS + + L3REGS_SECGRP_SDRDATA_ADDRESS)); + return; +} + + +static const struct socfpga_reset_manager *reset_manager_base = + (void *)SOCFPGA_RSTMGR_ADDRESS; + +#define CONFIG_SYSMGR_EMAC_CTRL (SOCFPGA_SYSMGR_ADDRESS + 0x60) + +/* Enumeration: sysmgr::emacgrp::ctrl::physel::enum */ +#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0 +#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1 +#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII 0x2 +#define SYSMGR_EMACGRP_CTRL_PHYSEL0_LSB 0 +#define SYSMGR_EMACGRP_CTRL_PHYSEL1_LSB 2 +#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK 0x00000003 + +/* EMAC controller and PHY used */ +#define CONFIG_EPHY_PHY_ADDR CONFIG_EPHY1_PHY_ADDR + +#define SYSMGR_FPGAINTF_MODULE (SOCFPGA_SYSMGR_ADDRESS + 0x28) + +/* Preloader handoff to bootloader register */ +#define SYSMGR_ISWGRP_HANDOFF0 (SOCFPGA_SYSMGR_ADDRESS + 0x80) +#define SYSMGR_ISWGRP_HANDOFF1 (SOCFPGA_SYSMGR_ADDRESS + 0x84) +#define SYSMGR_ISWGRP_HANDOFF2 (SOCFPGA_SYSMGR_ADDRESS + 0x88) +#define SYSMGR_ISWGRP_HANDOFF3 (SOCFPGA_SYSMGR_ADDRESS + 0x8C) +#define SYSMGR_ISWGRP_HANDOFF4 (SOCFPGA_SYSMGR_ADDRESS + 0x90) +#define SYSMGR_ISWGRP_HANDOFF5 (SOCFPGA_SYSMGR_ADDRESS + 0x94) +#define SYSMGR_ISWGRP_HANDOFF6 (SOCFPGA_SYSMGR_ADDRESS + 0x98) +#define SYSMGR_ISWGRP_HANDOFF7 (SOCFPGA_SYSMGR_ADDRESS + 0x9C) + +#define ISWGRP_HANDOFF_AXIBRIDGE SYSMGR_ISWGRP_HANDOFF0 +#define ISWGRP_HANDOFF_L3REMAP SYSMGR_ISWGRP_HANDOFF1 +#define ISWGRP_HANDOFF_FPGAINTF SYSMGR_ISWGRP_HANDOFF2 +#define ISWGRP_HANDOFF_FPGA2SDR SYSMGR_ISWGRP_HANDOFF3 + +#define SDR_CTRLGRP_FPGAPORTRST_ADDRESS 0x5080 + +/* + * DesignWare Ethernet initialization + */ +#ifdef CONFIG_DESIGNWARE_ETH +int cpu_eth_init(bd_t *bis) +{ + /* Initialize EMAC. This needs to be done at least once per boot. */ + + /* + * Putting the EMAC controller to reset when configuring the PHY + * interface select at System Manager + */ + emac0_reset_enable(1); + emac1_reset_enable(1); + + /* Clearing emac0 PHY interface select to 0 */ + clrbits_le32(CONFIG_SYSMGR_EMAC_CTRL, + (SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << + SYSMGR_EMACGRP_CTRL_PHYSEL1_LSB)); + + /* configure to PHY interface select choosed */ + setbits_le32(CONFIG_SYSMGR_EMAC_CTRL, + (SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII << + SYSMGR_EMACGRP_CTRL_PHYSEL1_LSB)); + /* Release the EMAC controller from reset */ + emac1_reset_enable(0); + + /* initialize and register the emac */ + return designware_initialize(CONFIG_EMAC_BASE, + CONFIG_PHY_INTERFACE_MODE); +} +#endif + +#ifdef CONFIG_DWMMC +/* + * Initializes MMC controllers. + * to override, implement board_mmc_init() + */ +int cpu_mmc_init(bd_t *bis) +{ + return socfpga_dwmmc_init(SOCFPGA_SDMMC_ADDRESS, 4, 0); +} +#endif + #if defined(CONFIG_DISPLAY_CPUINFO) /* * Print CPU information @@ -36,22 +151,123 @@ int overwrite_console(void) } #endif -int misc_init_r(void) +#ifdef CONFIG_FPGA +/* + * FPGA programming support for SoC FPGA Cyclone V + */ +/* currently only single FPGA device avaiable on dev kit */ +Altera_desc altera_fpga[CONFIG_FPGA_COUNT] = { + {Altera_SoCFPGA, /* family */ + fast_passive_parallel, /* interface type */ + -1, /* no limitation as + additional data will be ignored */ + NULL, /* no device function table */ + NULL, /* base interface address specified in driver */ + 0} /* no cookie implementation */ +}; + +/* add device descriptor to FPGA device table */ +void socfpga_fpga_add(void) { - return 0; + int i; + fpga_init(); + for (i = 0; i < CONFIG_FPGA_COUNT; i++) + fpga_add(fpga_altera, &altera_fpga[i]); +} +#endif + +void sdram_applycfg_uboot(void); + +#define SOCFPGA_MPUL2_ADDRESS 0xfffef000 +#define SOCFPGA_MPUL2_ADRFLTR_START (0xC00) + +/* create environment for bridges and handoff */ +static void prepare_environment(void) +{ + char buf[32]; + + /* hps peripheral controller to fgpa */ + setenv_addr("fpgaintf", (void *)SYSMGR_FPGAINTF_MODULE); + sprintf(buf, "0x%08x", readl(ISWGRP_HANDOFF_FPGAINTF)); + setenv("fpgaintf_handoff", buf); + + /* fpga2sdram port */ + setenv_addr("fpga2sdram", (void *)(SOCFPGA_SDR_ADDRESS + + SDR_CTRLGRP_FPGAPORTRST_ADDRESS)); + sprintf(buf, "0x%08x", readl(ISWGRP_HANDOFF_FPGA2SDR)); + setenv("fpga2sdram_handoff", buf); + setenv_addr("fpga2sdram_apply", (void *)sdram_applycfg_uboot); + + /* axi bridges (hps2fpga, lwhps2fpga and fpga2hps) */ + setenv_addr("axibridge", (void *)&reset_manager_base->brg_mod_reset); + sprintf(buf, "0x%08x", readl(ISWGRP_HANDOFF_AXIBRIDGE)); + setenv("axibridge_handoff", buf); + + /* l3 remap register */ + setenv_addr("l3remap", (void *)SOCFPGA_L3REGS_ADDRESS); + sprintf(buf, "0x%08x", readl(ISWGRP_HANDOFF_L3REMAP)); + setenv("l3remap_handoff", buf); + + /* add signle command to enable all bridges based on handoff */ + setenv("bridge_enable_handoff", + "mw $fpgaintf ${fpgaintf_handoff}; " + "go $fpga2sdram_apply; " + "mw $fpga2sdram ${fpga2sdram_handoff}; " + "mw $axibridge ${axibridge_handoff}; " + "mw $l3remap ${l3remap_handoff} "); + + /* add signle command to disable all bridges */ + setenv("bridge_disable", + "mw $fpgaintf 0; " + "mw $fpga2sdram 0; " + "go $fpga2sdram_apply; " + "mw $axibridge 0; " + "mw $l3remap 0x1 "); } +int misc_init_r(void) +{ +#if 1 /* FIXME */ + printf("Turning off all the bridges\n"); + reset_assert_all_bridges(); + /* reset_deassert_all_bridges(); <- original code never does that */ + printf("non-secure access to everyone\n"); + nic301_slave_ns(); +#endif + +#if 1 /* FIXME */ +#define SOCFPGA_MPUSCU_ADDRESS 0xfffec000 /* - * DesignWare Ethernet initialization + * SCU Non-secure Access Control */ -int cpu_eth_init(bd_t *bis) -{ -#if !defined(CONFIG_SOCFPGA_VIRTUAL_TARGET) && !defined(CONFIG_SPL_BUILD) - /* initialize and register the emac */ - return designware_initialize(CONFIG_EMAC_BASE, - CONFIG_PHY_INTERFACE_MODE); +#define SOCFPGA_SCU_SNSAC (SOCFPGA_MPUSCU_ADDRESS + 0x54) + + /* + * Private components security + * U-Boot : configure private timer, global timer and cpu + * component access as non secure for kernel stage (as required + * by kernel) + */ + setbits_le32(SOCFPGA_SCU_SNSAC, 0xfff); +#endif + + /* Configure the L2 controller to make SDRAM start at 0 */ +#ifdef CONFIG_SOCFPGA_VIRTUAL_TARGET + writel(0x2, SOCFPGA_L3REGS_ADDRESS); #else - return 0; + writel(0x1, (SOCFPGA_MPUL2_ADDRESS + SOCFPGA_MPUL2_ADRFLTR_START)); #endif + +#ifdef CONFIG_FPGA + /* add device descriptor to FPGA device table */ + socfpga_fpga_add(); +#endif + + /* This is needed, otherwise kernel is rebooted by watchdog. */ + watchdog_disable(); + + if (1) /* FIXME */ + prepare_environment(); + return 0; } diff --git a/arch/arm/cpu/armv7/socfpga/reset_manager.c b/arch/arm/cpu/armv7/socfpga/reset_manager.c index e320c01..afc179b 100644 --- a/arch/arm/cpu/armv7/socfpga/reset_manager.c +++ b/arch/arm/cpu/armv7/socfpga/reset_manager.c @@ -14,6 +14,22 @@ DECLARE_GLOBAL_DATA_PTR; static const struct socfpga_reset_manager *reset_manager_base = (void *)SOCFPGA_RSTMGR_ADDRESS; +#define RSTMGR_PERMODRST_L4WD0_LSB 6 + +#define RSTMGR_PERMODRST_EMAC0_LSB 0 +#define RSTMGR_PERMODRST_EMAC1_LSB 1 + +/* Disable the watchdog (toggle reset to watchdog) */ +void watchdog_disable(void) +{ + /* assert reset for watchdog */ + setbits_le32(&reset_manager_base->per_mod_reset, + (1<per_mod_reset, + (1<per_mod_reset); } + +/* Assert reset to all bridges through reset manager */ +void reset_assert_all_bridges(void) +{ +#if !defined(CONFIG_SOCFPGA_VIRTUAL_TARGET) + writel(~0, &reset_manager_base->brg_mod_reset); +#endif +} + +/* Change the reset state for EMAC0 */ +void emac0_reset_enable(uint state) +{ + if (state) + setbits_le32(&reset_manager_base->per_mod_reset, + (1 << RSTMGR_PERMODRST_EMAC0_LSB)); + else + clrbits_le32(&reset_manager_base->per_mod_reset, + (1 << RSTMGR_PERMODRST_EMAC0_LSB)); +} + +/* Change the reset state for EMAC1 */ +void emac1_reset_enable(uint state) +{ + if (state) + setbits_le32(&reset_manager_base->per_mod_reset, + (1 << RSTMGR_PERMODRST_EMAC1_LSB)); + else + clrbits_le32(&reset_manager_base->per_mod_reset, + (1 << RSTMGR_PERMODRST_EMAC1_LSB)); +} + +#define L3REGS_REMAP_LWHPS2FPGA_MASK 0x00000010 +#define L3REGS_REMAP_HPS2FPGA_MASK 0x00000008 +#define L3REGS_REMAP_OCRAM_MASK 0x00000001 + +void reset_deassert_all_bridges(void) +{ +#if !defined(CONFIG_SOCFPGA_VIRTUAL_TARGET) +#if 1 /* FIXME */ + printf("wait for fpga\n"); + /* check signal from FPGA */ + if (poll_fpgamgr_fpga_ready() == 0) { + /* FPGA not ready. Not much can be done but let WD timeout */ + printf("reset_deassert_all_bridges: fpga not ready, hanging.\n"); + for (;;) + ; + } + + printf("modrst\n"); + /* brdmodrst */ + writel(0, &reset_manager_base->brg_mod_reset); +#endif + + printf("bridges\n"); + /* remap the bridges into memory map */ + writel((L3REGS_REMAP_LWHPS2FPGA_MASK | L3REGS_REMAP_HPS2FPGA_MASK | + L3REGS_REMAP_OCRAM_MASK), SOCFPGA_L3REGS_ADDRESS); +#endif +} diff --git a/arch/arm/cpu/armv7/socfpga/system_manager.c b/arch/arm/cpu/armv7/socfpga/system_manager.c index d96521b..0659407 100644 --- a/arch/arm/cpu/armv7/socfpga/system_manager.c +++ b/arch/arm/cpu/armv7/socfpga/system_manager.c @@ -7,8 +7,45 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; +/* + * Populate the value for SYSMGR.FPGAINTF.MODULE based on pinmux setting. + * The value is not wrote to SYSMGR.FPGAINTF.MODULE but + * CONFIG_SYSMGR_ISWGRP_HANDOFF. + */ +static unsigned long populate_sysmgr_fpgaintf_module(void) +{ + writel(0, ISWGRP_HANDOFF_FPGAINTF); + + /* enable the signal for those hps peripheral use fpga */ + if (readl(SYSMGR_PINMUXGRP_NANDUSEFPGA) == SYSMGR_FPGAINTF_USEFPGA) + setbits_le32(ISWGRP_HANDOFF_FPGAINTF, + SYSMGR_FPGAINTF_NAND); + + if (readl(SYSMGR_PINMUXGRP_EMAC1USEFPGA) == SYSMGR_FPGAINTF_USEFPGA) + setbits_le32(ISWGRP_HANDOFF_FPGAINTF, + SYSMGR_FPGAINTF_EMAC1); + + if (readl(SYSMGR_PINMUXGRP_SDMMCUSEFPGA) == SYSMGR_FPGAINTF_USEFPGA) + setbits_le32(ISWGRP_HANDOFF_FPGAINTF, + SYSMGR_FPGAINTF_SDMMC); + + if (readl(SYSMGR_PINMUXGRP_EMAC0USEFPGA) == SYSMGR_FPGAINTF_USEFPGA) + setbits_le32(ISWGRP_HANDOFF_FPGAINTF, + SYSMGR_FPGAINTF_EMAC0); + + if (readl(SYSMGR_PINMUXGRP_SPIM1USEFPGA) == SYSMGR_FPGAINTF_USEFPGA) + setbits_le32(ISWGRP_HANDOFF_FPGAINTF, + SYSMGR_FPGAINTF_SPIM1); + + if (readl(SYSMGR_PINMUXGRP_SPIM0USEFPGA) == SYSMGR_FPGAINTF_USEFPGA) + setbits_le32(ISWGRP_HANDOFF_FPGAINTF, + SYSMGR_FPGAINTF_SPIM0); + + return readl(ISWGRP_HANDOFF_FPGAINTF); +} /* * Configure all the pin muxes @@ -18,10 +55,19 @@ void sysmgr_pinmux_init(void) unsigned long offset = CONFIG_SYSMGR_PINMUXGRP_OFFSET; const unsigned long *pval = sys_mgr_init_table; - unsigned long i; + unsigned long i, reg_value; for (i = 0; i < ARRAY_SIZE(sys_mgr_init_table); i++, offset += sizeof(unsigned long)) { writel(*pval++, (SOCFPGA_SYSMGR_ADDRESS + offset)); } + + /* populate (not writing) the value for SYSMGR.FPGAINTF.MODULE + based on pinmux setting */ + reg_value = populate_sysmgr_fpgaintf_module(); + + if (is_fpgamgr_fpga_ready()) { + /* enable the required signals only */ + writel(reg_value, SYSMGR_FPGAINTF_MODULE); + } } diff --git a/arch/arm/include/asm/arch-socfpga/clock_manager.h b/arch/arm/include/asm/arch-socfpga/clock_manager.h index babac0e..d7c87199 100644 --- a/arch/arm/include/asm/arch-socfpga/clock_manager.h +++ b/arch/arm/include/asm/arch-socfpga/clock_manager.h @@ -208,4 +208,9 @@ struct socfpga_clock_manager { CLKMGR_SDRPLLGRP_VCO_DENOM_SET(CONFIG_HPS_SDRPLLGRP_VCO_DENOM) | \ CLKMGR_SDRPLLGRP_VCO_NUMER_SET(CONFIG_HPS_SDRPLLGRP_VCO_NUMER)) +/* global variable which consume by drivers */ +extern unsigned long cm_l4_sp_clock; +extern unsigned long cm_sdmmc_clock; +extern unsigned long cm_qspi_clock; + #endif /* _CLOCK_MANAGER_H_ */ diff --git a/arch/arm/include/asm/arch-socfpga/fpga_manager.h b/arch/arm/include/asm/arch-socfpga/fpga_manager.h new file mode 100644 index 0000000..8e410c5 --- /dev/null +++ b/arch/arm/include/asm/arch-socfpga/fpga_manager.h @@ -0,0 +1,92 @@ +/* + * + * Copyright (C) 2012 Altera Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the Altera Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL ALTERA CORPORATION BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _FPGA_MANAGER_H_ +#define _FPGA_MANAGER_H_ + +struct socfpga_fpga_manager { + u32 stat; + u32 ctrl; + u32 dclkcnt; + u32 dclkstat; + u32 gpo; + u32 gpi; + u32 misci; +}; + +#define FPGAMGRREGS_MON_GPIO_PORTA_EOI_ADDRESS 0x84c +#define FPGAMGRREGS_MON_GPIO_EXT_PORTA_ADDRESS 0x850 + +#define FPGAMGRREGS_CTRL_CFGWDTH_MASK 0x200 +#define FPGAMGRREGS_CTRL_AXICFGEN_MASK 0x100 +#define FPGAMGRREGS_CTRL_NCONFIGPULL_MASK 0x4 +#define FPGAMGRREGS_CTRL_NCE_MASK 0x2 +#define FPGAMGRREGS_CTRL_EN_MASK 0x1 +#define FPGAMGRREGS_CTRL_CDRATIO_LSB 6 + +#define FPGAMGRREGS_STAT_MODE_MASK 0x7 +#define FPGAMGRREGS_STAT_MSEL_MASK 0xf8 +#define FPGAMGRREGS_STAT_MSEL_LSB 3 + +#define FPGAMGRREGS_MON_GPIO_EXT_PORTA_CRC_MASK 0x8 +#define FPGAMGRREGS_MON_GPIO_EXT_PORTA_ID_MASK 0x4 +#define FPGAMGRREGS_MON_GPIO_EXT_PORTA_CD_MASK 0x2 +#define FPGAMGRREGS_MON_GPIO_EXT_PORTA_NS_MASK 0x1 + +/* Timeout counter */ +#define FPGA_TIMEOUT_CNT 0x1000000 + +/* FPGA Mode */ +#define FPGAMGRREGS_MODE_FPGAOFF 0x0 +#define FPGAMGRREGS_MODE_RESETPHASE 0x1 +#define FPGAMGRREGS_MODE_CFGPHASE 0x2 +#define FPGAMGRREGS_MODE_INITPHASE 0x3 +#define FPGAMGRREGS_MODE_USERMODE 0x4 +#define FPGAMGRREGS_MODE_UNKNOWN 0x5 + +/* FPGA CD Ratio Value */ +#define CDRATIO_x1 0x0 +#define CDRATIO_x2 0x1 +#define CDRATIO_x4 0x2 +#define CDRATIO_x8 0x3 + +/* Functions */ +int is_fpgamgr_fpga_ready(void); +int poll_fpgamgr_fpga_ready(void); +int fpgamgr_program_init(void); +void fpgamgr_program_write(const unsigned long *rbf_data, + unsigned long rbf_size); +int fpgamgr_program_poll_cd(void); +int fpgamgr_program_poll_initphase(void); +int fpgamgr_program_poll_usermode(void); +int fpgamgr_program_fpga(const unsigned long *rbf_data, + unsigned long rbf_size); +void fpgamgr_axi_write(const unsigned long *rbf_data, + const unsigned long fpgamgr_data_addr, unsigned long rbf_size); + +#endif /* _FPGA_MANAGER_H_ */ diff --git a/arch/arm/include/asm/arch-socfpga/reset_manager.h b/arch/arm/include/asm/arch-socfpga/reset_manager.h index 3e95476..eb95c5b 100644 --- a/arch/arm/include/asm/arch-socfpga/reset_manager.h +++ b/arch/arm/include/asm/arch-socfpga/reset_manager.h @@ -10,6 +10,14 @@ void reset_cpu(ulong addr); void reset_deassert_peripherals_handoff(void); +void reset_deassert_all_bridges(void); +void reset_assert_all_bridges(void); + +void emac0_reset_enable(uint state); +void emac1_reset_enable(uint state); + +void watchdog_disable(void); + struct socfpga_reset_manager { u32 status; u32 ctrl; diff --git a/arch/arm/include/asm/arch-socfpga/socfpga_base_addrs.h b/arch/arm/include/asm/arch-socfpga/socfpga_base_addrs.h index 2d3152d..39a7874 100644 --- a/arch/arm/include/asm/arch-socfpga/socfpga_base_addrs.h +++ b/arch/arm/include/asm/arch-socfpga/socfpga_base_addrs.h @@ -7,9 +7,15 @@ #ifndef _SOCFPGA_BASE_ADDRS_H_ #define _SOCFPGA_BASE_ADDRS_H_ +#define SOCFPGA_EMAC0_ADDRESS 0xff700000 +#define SOCFPGA_EMAC1_ADDRESS 0xff702000 +#define SOCFPGA_SDMMC_ADDRESS 0xff704000 +#define SOCFPGA_FPGAMGRREGS_ADDRESS 0xff706000 #define SOCFPGA_L3REGS_ADDRESS 0xff800000 +#define SOCFPGA_FPGAMGRDATA_ADDRESS 0xffb90000 #define SOCFPGA_UART0_ADDRESS 0xffc02000 #define SOCFPGA_UART1_ADDRESS 0xffc03000 +#define SOCFPGA_SDR_ADDRESS 0xffc20000 #define SOCFPGA_OSC1TIMER0_ADDRESS 0xffd00000 #define SOCFPGA_L4WD0_ADDRESS 0xffd02000 #define SOCFPGA_CLKMGR_ADDRESS 0xffd04000 diff --git a/arch/arm/include/asm/arch-socfpga/system_manager.h b/arch/arm/include/asm/arch-socfpga/system_manager.h index 838d210..38b5598 100644 --- a/arch/arm/include/asm/arch-socfpga/system_manager.h +++ b/arch/arm/include/asm/arch-socfpga/system_manager.h @@ -84,4 +84,49 @@ struct socfpga_system_manager { u32 eccgrp_sdmmc; }; +/* FPGA interface group */ +#define SYSMGR_FPGAINTF_MODULE (SOCFPGA_SYSMGR_ADDRESS + 0x28) +/* EMAC interface selection */ +#define CONFIG_SYSMGR_EMAC_CTRL (SOCFPGA_SYSMGR_ADDRESS + 0x60) + +/* Preloader handoff to bootloader register */ +#define SYSMGR_ISWGRP_HANDOFF0 (SOCFPGA_SYSMGR_ADDRESS + 0x80) +#define SYSMGR_ISWGRP_HANDOFF1 (SOCFPGA_SYSMGR_ADDRESS + 0x84) +#define SYSMGR_ISWGRP_HANDOFF2 (SOCFPGA_SYSMGR_ADDRESS + 0x88) +#define SYSMGR_ISWGRP_HANDOFF3 (SOCFPGA_SYSMGR_ADDRESS + 0x8C) +#define SYSMGR_ISWGRP_HANDOFF4 (SOCFPGA_SYSMGR_ADDRESS + 0x90) +#define SYSMGR_ISWGRP_HANDOFF5 (SOCFPGA_SYSMGR_ADDRESS + 0x94) +#define SYSMGR_ISWGRP_HANDOFF6 (SOCFPGA_SYSMGR_ADDRESS + 0x98) +#define SYSMGR_ISWGRP_HANDOFF7 (SOCFPGA_SYSMGR_ADDRESS + 0x9C) + +#define ISWGRP_HANDOFF_AXIBRIDGE SYSMGR_ISWGRP_HANDOFF0 +#define ISWGRP_HANDOFF_L3REMAP SYSMGR_ISWGRP_HANDOFF1 +#define ISWGRP_HANDOFF_FPGAINTF SYSMGR_ISWGRP_HANDOFF2 +#define ISWGRP_HANDOFF_FPGA2SDR SYSMGR_ISWGRP_HANDOFF3 + +/* bit fields */ +#define CONFIG_SYSMGR_PINMUXGRP_OFFSET (0x400) +#define SYSMGR_ROMCODEGRP_CTRL_WARMRSTCFGPINMUX (1<<0) +#define SYSMGR_ROMCODEGRP_CTRL_WARMRSTCFGIO (1<<1) +#define SYSMGR_ECC_OCRAM_EN (1<<0) +#define SYSMGR_ECC_OCRAM_SERR (1<<3) +#define SYSMGR_ECC_OCRAM_DERR (1<<4) +#define SYSMGR_FPGAINTF_USEFPGA 0x1 +#define SYSMGR_FPGAINTF_SPIM0 (1<<0) +#define SYSMGR_FPGAINTF_SPIM1 (1<<1) +#define SYSMGR_FPGAINTF_EMAC0 (1<<2) +#define SYSMGR_FPGAINTF_EMAC1 (1<<3) +#define SYSMGR_FPGAINTF_NAND (1<<4) +#define SYSMGR_FPGAINTF_SDMMC (1<<5) + +/* pin mux */ +#define SYSMGR_PINMUXGRP (SOCFPGA_SYSMGR_ADDRESS + 0x400) +#define SYSMGR_PINMUXGRP_FLASHIO1 (SYSMGR_PINMUXGRP + 0x54) +#define SYSMGR_PINMUXGRP_NANDUSEFPGA (SYSMGR_PINMUXGRP + 0x2F0) +#define SYSMGR_PINMUXGRP_EMAC1USEFPGA (SYSMGR_PINMUXGRP + 0x2F8) +#define SYSMGR_PINMUXGRP_SDMMCUSEFPGA (SYSMGR_PINMUXGRP + 0x308) +#define SYSMGR_PINMUXGRP_EMAC0USEFPGA (SYSMGR_PINMUXGRP + 0x314) +#define SYSMGR_PINMUXGRP_SPIM1USEFPGA (SYSMGR_PINMUXGRP + 0x330) +#define SYSMGR_PINMUXGRP_SPIM0USEFPGA (SYSMGR_PINMUXGRP + 0x338) + #endif /* _SYSTEM_MANAGER_H_ */ diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index d51ba66..f0dcbd7 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -185,6 +185,7 @@ enum dcache_option { DCACHE_OFF = 0x12, DCACHE_WRITETHROUGH = 0x1a, DCACHE_WRITEBACK = 0x1e, + DCACHE_WRITEBACK_WRITEALLOCATE = 0x16, }; /* Size of an MMU section */ diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c index 3e62d58..3227e5d 100644 --- a/arch/arm/lib/cache-cp15.c +++ b/arch/arm/lib/cache-cp15.c @@ -73,6 +73,8 @@ __weak void dram_bank_mmu_setup(int bank) i++) { #if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH) set_section_dcache(i, DCACHE_WRITETHROUGH); +#elif defined(CONFIG_SYS_ARM_CACHE_WRITEBACK_WRITEALLOCATE) + set_section_dcache(i, DCACHE_WRITEBACK_WRITEALLOCATE); #else set_section_dcache(i, DCACHE_WRITEBACK); #endif diff --git a/board/altera/socfpga/socfpga_cyclone5.c b/board/altera/socfpga/socfpga_cyclone5.c index fb92852..6b74997d 100644 --- a/board/altera/socfpga/socfpga_cyclone5.c +++ b/board/altera/socfpga/socfpga_cyclone5.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2012 Altera Corporation + * Copyright (C) 2014 Pavel Machek, pavel@denx.de * * SPDX-License-Identifier: GPL-2.0+ */ @@ -8,8 +9,6 @@ #include #include -#include - DECLARE_GLOBAL_DATA_PTR; /* @@ -34,6 +33,17 @@ int board_early_init_f(void) */ int board_init(void) { - icache_enable(); + // icache_enable(); + puts("derive_clocks_for_drivers... \n"); +#if 1 + /* calculate the clock frequencies required for drivers */ + cm_derive_clocks_for_drivers(); + + puts("derive_clocks_for_drivers... done\n"); +#endif + + /* adress of boot parameters for ATAG (if ATAG is used) */ + gd->bd->bi_boot_params = 0x00000100; + return 0; } diff --git a/common/cmd_fpga.c b/common/cmd_fpga.c index 8c5bf44..884c61a 100644 --- a/common/cmd_fpga.c +++ b/common/cmd_fpga.c @@ -43,6 +43,7 @@ int do_fpga(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) void *fpga_data = NULL; char *devstr = getenv("fpga"); char *datastr = getenv("fpgadata"); + char *devsizestr = getenv("fpgadatasize"); int rc = FPGA_FAIL; int wrong_parms = 0; #if defined(CONFIG_FIT) @@ -57,7 +58,9 @@ int do_fpga(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) if (devstr) dev = (int) simple_strtoul(devstr, NULL, 16); if (datastr) - fpga_data = (void *)simple_strtoul(datastr, NULL, 16); + fpga_data = (void *) simple_strtoul(datastr, NULL, 16); + if (devsizestr) + data_size = (size_t) simple_strtoul(devsizestr, NULL, 16); switch (argc) { #if defined(CONFIG_CMD_FPGA_LOADFS) diff --git a/common/memsize.c b/common/memsize.c index 589400d..0cae738 100644 --- a/common/memsize.c +++ b/common/memsize.c @@ -33,6 +33,8 @@ long get_ram_size(long *base, long maxsize) long size; int i = 0; + return maxsize; + for (cnt = (maxsize / sizeof (long)) >> 1; cnt > 0; cnt >>= 1) { addr = base + cnt; /* pointer arith! */ sync (); diff --git a/drivers/fpga/altera.c b/drivers/fpga/altera.c index 6e34a8e..36d8826 100644 --- a/drivers/fpga/altera.c +++ b/drivers/fpga/altera.c @@ -1,4 +1,7 @@ /* + * (C) Copyright 2013 + * Altera Corporation + * * (C) Copyright 2003 * Steven Scholz, imc Measurement & Control, steven.scholz@imc-berlin.de * @@ -14,6 +17,9 @@ #include #include #include +#if defined(CONFIG_FPGA_SOCFPGA) +#include +#endif /* Define FPGA_DEBUG to get debug printf's */ /* #define FPGA_DEBUG */ @@ -59,6 +65,18 @@ int altera_load(Altera_desc *desc, const void *buf, size_t bsize) ret_val = StratixII_load (desc, buf, bsize); break; #endif +#if defined(CONFIG_FPGA_SOCFPGA) + case Altera_SoCFPGA: + PRINTF("%s: Launching the SoC FPGA Loader...\n", + __func__); + ret_val = fpgamgr_program_fpga(buf, bsize); + if (ret_val) { + printf("%s: Failed with error code %d\n", + __func__, ret_val); + ret_val = 1; + } + break; +#endif default: printf ("%s: Unsupported family type, %d\n", __FUNCTION__, desc->family); @@ -94,6 +112,11 @@ int altera_dump(Altera_desc *desc, const void *buf, size_t bsize) ret_val = StratixII_dump (desc, buf, bsize); break; #endif + case Altera_SoCFPGA: + printf("%s: Unsupported due to security reason, %d\n", + __func__, desc->family); + ret_val = FPGA_SUCCESS; + break; default: printf ("%s: Unsupported family type, %d\n", __FUNCTION__, desc->family); @@ -119,6 +142,9 @@ int altera_info( Altera_desc *desc ) case Altera_StratixII: printf ("Stratix II\n"); break; + case Altera_SoCFPGA: + printf("SoC FPGA\n"); + break; /* Add new family types here */ default: printf ("Unknown family type, %d\n", desc->family); diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index 0df30bc..4c16e7f 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -177,14 +177,16 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, } } - if (i == retry) + if (i == retry) { + printf("dwmci_send_cmd: timeout..\n"); return TIMEOUT; + } if (mask & DWMCI_INTMSK_RTO) { - debug("Response Timeout..\n"); + printf("dwmci_send_cmd: Response Timeout..\n"); return TIMEOUT; } else if (mask & DWMCI_INTMSK_RE) { - debug("Response Error..\n"); + printf("dwmci_send_cmd: Response Error..\n"); return -1; } @@ -204,7 +206,7 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, do { mask = dwmci_readl(host, DWMCI_RINTSTS); if (mask & (DWMCI_DATA_ERR | DWMCI_DATA_TOUT)) { - debug("DATA ERROR!\n"); + printf("dwmci_send_cmd: DATA ERROR!\n"); return -1; } } while (!(mask & DWMCI_INTMSK_DTO)); @@ -232,16 +234,16 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) if ((freq == host->clock) || (freq == 0)) return 0; /* - * If host->get_mmc_clk didn't define, + * If host->get_mmc_clk isn't defined, * then assume that host->bus_hz is source clock value. - * host->bus_hz should be set from user. + * host->bus_hz should be set by user. */ if (host->get_mmc_clk) sclk = host->get_mmc_clk(host); else if (host->bus_hz) sclk = host->bus_hz; else { - printf("Didn't get source clock value..\n"); + printf("dwmci_setup_bus: Didn't get source clock value..\n"); return -EINVAL; } @@ -260,7 +262,7 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) do { status = dwmci_readl(host, DWMCI_CMD); if (timeout-- < 0) { - printf("TIMEOUT error!!\n"); + printf("dwmci_setup_bus: timeout!\n"); return -ETIMEDOUT; } } while (status & DWMCI_CMD_START); @@ -275,7 +277,7 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) do { status = dwmci_readl(host, DWMCI_CMD); if (timeout-- < 0) { - printf("TIMEOUT error!!\n"); + printf("dwmci_setup_bus: timeout!\n"); return -ETIMEDOUT; } } while (status & DWMCI_CMD_START); @@ -290,7 +292,7 @@ static void dwmci_set_ios(struct mmc *mmc) struct dwmci_host *host = (struct dwmci_host *)mmc->priv; u32 ctype, regs; - debug("Buswidth = %d, clock: %d\n",mmc->bus_width, mmc->clock); + debug("Buswidth = %d, clock: %d\n", mmc->bus_width, mmc->clock); dwmci_setup_bus(host, mmc->clock); switch (mmc->bus_width) { @@ -329,7 +331,7 @@ static int dwmci_init(struct mmc *mmc) dwmci_writel(host, DWMCI_PWREN, 1); if (!dwmci_wait_reset(host, DWMCI_RESET_ALL)) { - debug("%s[%d] Fail-reset!!\n",__func__,__LINE__); + printf("%s[%d] Fail-reset!!\n", __func__, __LINE__); return -1; } diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c index 1f96382..d8da7f5 100644 --- a/drivers/mmc/socfpga_dw_mmc.c +++ b/drivers/mmc/socfpga_dw_mmc.c @@ -16,6 +16,8 @@ static const struct socfpga_clock_manager *clock_manager_base = static const struct socfpga_system_manager *system_manager_base = (void *)SOCFPGA_SYSMGR_ADDRESS; +#define CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK (1 << 8) + static void socfpga_dwmci_clksel(struct dwmci_host *host) { unsigned int drvsel; @@ -58,7 +60,8 @@ int socfpga_dwmmc_init(u32 regbase, int bus_width, int index) host->clksel = socfpga_dwmci_clksel; host->dev_index = index; /* fixed clock divide by 4 which due to the SDMMC wrapper */ - host->bus_hz = CONFIG_SOCFPGA_DWMMC_BUS_HZ; + host->bus_hz = cm_sdmmc_clock; + printf("bus_hz: %ld\n", host->bus_hz); host->fifoth_val = MSIZE(0x2) | RX_WMARK(CONFIG_SOCFPGA_DWMMC_FIFO_DEPTH / 2 - 1) | TX_WMARK(CONFIG_SOCFPGA_DWMMC_FIFO_DEPTH / 2); diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 5d7e3be..06a31b0 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -25,8 +25,7 @@ static struct phy_driver KSZ804_driver = { #ifndef CONFIG_PHY_MICREL_KSZ9021 /* * I can't believe Micrel used the exact same part number - * for the KSZ9021 - * Shame Micrel, Shame!!!!! + * for the KSZ9021. Shame Micrel, Shame! */ static struct phy_driver KS8721_driver = { .name = "Micrel KS8721BL", @@ -40,7 +39,7 @@ static struct phy_driver KS8721_driver = { #endif -/** +/* * KSZ9021 - KSZ9031 common */ @@ -69,8 +68,8 @@ static int ksz90xx_startup(struct phy_device *phydev) phydev->speed = SPEED_10; return 0; } -#ifdef CONFIG_PHY_MICREL_KSZ9021 +#ifdef CONFIG_PHY_MICREL_KSZ9021 /* * KSZ9021 */ @@ -113,17 +112,46 @@ static int ksz9021_phy_extwrite(struct phy_device *phydev, int addr, return ksz9021_phy_extended_write(phydev, regnum, val); } +/* FIXME: disable_giga is probably what we want to do */ + /* Micrel ksz9021 */ static int ksz9021_config(struct phy_device *phydev) { unsigned ctrl1000 = 0; const unsigned master = CTRL1000_PREFER_MASTER | - CTRL1000_CONFIG_MASTER | CTRL1000_MANUAL_CONFIG; + CTRL1000_CONFIG_MASTER | CTRL1000_MANUAL_CONFIG; unsigned features = phydev->drv->features; + printf("ksz9021: configuring\n"); + + printf("Configuring PHY skew timing for %s\n", + phydev->drv->name); + + /* min rx data delay */ + if (ksz9021_phy_extended_write(phydev, + MII_KSZ9021_EXT_RGMII_RX_DATA_SKEW, + getenv_ulong(CONFIG_KSZ9021_DATA_SKEW_ENV, 16, + CONFIG_KSZ9021_DATA_SKEW_VAL)) < 0) + return -1; + /* min tx data delay */ + if (ksz9021_phy_extended_write(phydev, + MII_KSZ9021_EXT_RGMII_TX_DATA_SKEW, + getenv_ulong(CONFIG_KSZ9021_DATA_SKEW_ENV, 16, + CONFIG_KSZ9021_DATA_SKEW_VAL)) < 0) + return -1; + /* max rx/tx clock delay, min rx/tx control */ + if (ksz9021_phy_extended_write(phydev, + MII_KSZ9021_EXT_RGMII_CLOCK_SKEW, + getenv_ulong(CONFIG_KSZ9021_CLK_SKEW_ENV, 16, + CONFIG_KSZ9021_CLK_SKEW_VAL)) < 0) + return -1; + + printf("ksz9021: skew ok\n"); + + if (getenv("disable_giga")) features &= ~(SUPPORTED_1000baseT_Half | - SUPPORTED_1000baseT_Full); + SUPPORTED_1000baseT_Full); /* force master mode for 1000BaseT due to chip errata */ if (features & SUPPORTED_1000baseT_Half) ctrl1000 |= ADVERTISE_1000HALF | master; diff --git a/examples/standalone/Makefile b/examples/standalone/Makefile index 2dacba2..163672f 100644 --- a/examples/standalone/Makefile +++ b/examples/standalone/Makefile @@ -5,7 +5,8 @@ # SPDX-License-Identifier: GPL-2.0+ # -extra-y := hello_world +extra-y := +#extra-y := hello_world extra-$(CONFIG_SMC91111) += smc91111_eeprom extra-$(CONFIG_SMC911X) += smc911x_eeprom extra-$(CONFIG_SPI_FLASH_ATMEL) += atmel_df_pow2 diff --git a/include/altera.h b/include/altera.h index ae5f7ee..c7f78fc 100644 --- a/include/altera.h +++ b/include/altera.h @@ -27,6 +27,7 @@ typedef enum { /* typedef Altera_Family */ Altera_ACEX1K, /* ACEX1K Family */ Altera_CYC2, /* CYCLONII Family */ Altera_StratixII, /* StratixII Family */ + Altera_SoCFPGA, /* SoCFPGA Family */ /* Add new models here */ max_altera_type /* insert all new types before this */ } Altera_Family; /* end, typedef Altera_Family */ diff --git a/include/configs/axs101.h b/include/configs/axs101.h index c22d6d0..1bf83907 100644 --- a/include/configs/axs101.h +++ b/include/configs/axs101.h @@ -125,7 +125,6 @@ */ #define CONFIG_DESIGNWARE_ETH #define CONFIG_DW_AUTONEG -#define CONFIG_DW_SEARCH_PHY #define CONFIG_NET_MULTI /* diff --git a/include/configs/socfpga_cyclone5.h b/include/configs/socfpga_cyclone5.h index 5d145cd..d3d1e48 100644 --- a/include/configs/socfpga_cyclone5.h +++ b/include/configs/socfpga_cyclone5.h @@ -11,6 +11,8 @@ #include "../../board/altera/socfpga/iocsr_config.h" #include "../../board/altera/socfpga/pll_config.h" +#define CONFIG_SYS_GENERIC_BOARD + /* * High level configuration */ @@ -23,6 +25,12 @@ #define CONFIG_MISC_INIT_R #define CONFIG_SINGLE_BOOTLOADER + +/* Enable THUMB2 mode to reduce software size which yield better boot time */ +#define CONFIG_SYS_THUMB_BUILD + +#define CONFIG_SYS_ARM_CACHE_WRITEBACK_WRITEALLOCATE + #define CONFIG_SOCFPGA /* base address for .text section */ @@ -31,7 +39,7 @@ #else #define CONFIG_SYS_TEXT_BASE 0x01000040 #endif -#define CONFIG_SYS_LOAD_ADDR 0x7fc0 +#define CONFIG_SYS_LOAD_ADDR 0x8000 /* Console I/O Buffer Size */ #define CONFIG_SYS_CBSIZE 256 @@ -56,7 +64,8 @@ /* skip updating the FDT blob */ #define CONFIG_FDT_BLOB_SKIP_UPDATE /* Initial Memory map size for Linux, minus 4k alignment for DFT blob */ -#define CONFIG_SYS_BOOTMAPSZ ((256*1024*1024) - (4*1024)) +#define CONFIG_SYS_BOOTMAPSZ (64 * 1024 * 1024) + #define CONFIG_SPL_RAM_DEVICE #define CONFIG_SPL_STACK CONFIG_SYS_INIT_SP_ADDR @@ -67,9 +76,9 @@ * Memory allocation (MALLOC) */ /* Room required on the stack for the environment data */ -#define CONFIG_ENV_SIZE 1024 +#define CONFIG_ENV_SIZE 4096 /* Size of DRAM reserved for malloc() use */ -#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + 128*1024) +#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + 256*1024) /* SP location before relocation, must use scratch RAM */ #define CONFIG_SYS_INIT_RAM_ADDR 0xFFFF0000 @@ -119,7 +128,7 @@ * CONFIG_BOOTARGS goes into the environment value "bootargs". * Do note the value will overide also the chosen node in FDT blob. */ -#define CONFIG_BOOTARGS "console=ttyS0,57600,mem=256M@0x0" +#define CONFIG_BOOTARGS "console=ttyS0,115200,mem=256M@0x0" #define CONFIG_EXTRA_ENV_SETTINGS \ "verify=n\0" \ @@ -134,7 +143,8 @@ "qspirootfstype=jffs2\0" \ "qspiboot=setenv bootargs " CONFIG_BOOTARGS \ " root=${qspiroot} rw rootfstype=${qspirootfstype};"\ - "bootm ${loadaddr} - ${fdt_addr}\0" + "bootm ${loadaddr} - ${fdt_addr}\0" \ + "ethaddr=12:23:34:46:56:60\0" /* using environment setting for stdin, stdout, stderr */ #define CONFIG_SYS_CONSOLE_IS_IN_ENV @@ -159,13 +169,30 @@ /* SDRAM Bank #1 */ #define CONFIG_SYS_SDRAM_BASE 0x00000000 /* SDRAM memory size */ -#define PHYS_SDRAM_1_SIZE 0x40000000 +/* FIXME: rocketboards uses different version */ +#define PHYS_SDRAM_1_SIZE 0x20000000 #define PHYS_SDRAM_1 CONFIG_SYS_SDRAM_BASE #define CONFIG_SYS_MEMTEST_START 0x00000000 #define CONFIG_SYS_MEMTEST_END PHYS_SDRAM_1_SIZE /* + * FPGA support + */ +/* Enables FPGA subsystem */ +#define CONFIG_FPGA +#ifdef CONFIG_FPGA +/* Altera FPGA */ +#define CONFIG_FPGA_ALTERA +/* Family type */ +#define CONFIG_FPGA_SOCFPGA +/* Only support single device */ +#define CONFIG_FPGA_COUNT (1) +/* Enable FPGA command at console */ +#define CONFIG_CMD_FPGA +#endif + +/* * NS16550 Configuration */ #define UART0_BASE SOCFPGA_UART0_ADDRESS @@ -188,6 +215,25 @@ */ #define CONFIG_SYS_NO_FLASH + +/* + * MMC support + */ +#define CONFIG_MMC +#ifdef CONFIG_MMC +#define CONFIG_CMD_MMC + +#define CONFIG_BOUNCE_BUFFER +#define CONFIG_GENERIC_MMC 1 +#define CONFIG_DWMMC 1 +#define CONFIG_SOCFPGA_DWMMC 1 +#define CONFIG_SOCFPGA_DWMMC_FIFO_DEPTH 1024 +#define CONFIG_SOCFPGA_DWMMC_DRVSEL 3 +#define CONFIG_SOCFPGA_DWMMC_SMPSEL 0 +/* using smaller max blk cnt to avoid flooding the limited stack we have */ +#define CONFIG_SYS_MMC_MAX_BLK_COUNT 256 +#endif /* CONFIG_MMC */ + /* * L4 OSC1 Timer 0 */ @@ -225,31 +271,41 @@ /* designware */ #define CONFIG_NET_MULTI #define CONFIG_DW_ALTDESCRIPTOR -#define CONFIG_DW_SEARCH_PHY #define CONFIG_MII #define CONFIG_PHY_GIGE -#define CONFIG_DW_AUTONEG #define CONFIG_AUTONEG_TIMEOUT (15 * CONFIG_SYS_HZ) #define CONFIG_PHYLIB #define CONFIG_PHY_MICREL #define CONFIG_PHY_MICREL_KSZ9021 /* EMAC controller and PHY used */ -#define CONFIG_EMAC_BASE CONFIG_EMAC1_BASE -#define CONFIG_EPHY_PHY_ADDR CONFIG_EPHY1_PHY_ADDR +#define CONFIG_EMAC_BASE SOCFPGA_EMAC1_ADDRESS #define CONFIG_PHY_INTERFACE_MODE PHY_INTERFACE_MODE_RGMII + +/* phy */ +#define CONFIG_EPHY0_PHY_ADDR 0 +#define CONFIG_EPHY1_PHY_ADDR 4 +#define CONFIG_KSZ9021_CLK_SKEW_ENV "micrel-ksz9021-clk-skew" +#define CONFIG_KSZ9021_CLK_SKEW_VAL 0xf0f0 +#define CONFIG_KSZ9021_DATA_SKEW_ENV "micrel-ksz9021-data-skew" +#define CONFIG_KSZ9021_DATA_SKEW_VAL 0x0 +/* Type of PHY available */ +#define SOCFPGA_PHYSEL_ENUM_GMII 0x0 +#define SOCFPGA_PHYSEL_ENUM_MII 0x1 +#define SOCFPGA_PHYSEL_ENUM_RGMII 0x2 +#define SOCFPGA_PHYSEL_ENUM_RMII 0x3 + #endif /* CONFIG_DESIGNWARE_ETH */ /* * L4 Watchdog */ #define CONFIG_HW_WATCHDOG -#define CONFIG_HW_WATCHDOG_TIMEOUT_MS 2000 +#define CONFIG_HW_WATCHDOG_TIMEOUT_MS 12000 #define CONFIG_DESIGNWARE_WATCHDOG #define CONFIG_DW_WDT_BASE SOCFPGA_L4WD0_ADDRESS /* Clocks source frequency to watchdog timer */ #define CONFIG_DW_WDT_CLOCK_KHZ 25000 - /* * SPL "Second Program Loader" aka Initial Software */