Remove imgtec/pistachio SoC

After removing urara no board still uses this SoC, and there are no
plans to add any in the future (I'm not sure if the chip really exists
tbh...).

Change-Id: Ic4628fdfacc9fb19b6210394d96431fdb5f8e8f1
Signed-off-by: Julius Werner <jwerner@chromium.org>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/36491
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Julius Werner 2019-10-30 16:12:24 -07:00 committed by Patrick Georgi
parent 5027ecfb19
commit 63c444a69b
29 changed files with 1 additions and 3704 deletions

1
.gitignore vendored
View File

@ -85,7 +85,6 @@ util/*/.dependencies
util/*/.test
util/amdfwtool/amdfwtool
util/archive/archive
util/bimgtool/bimgtool
util/bincfg/bincfg
util/board_status/board-status
util/bucts/bucts

View File

@ -14,9 +14,6 @@ settings. `Perl`
platform. `C`
* __autoport__ - Automated porting coreboot to Sandy Bridge/Ivy Bridge
platforms `Go`
* __bimgtool__ - A simple tool which generates and verifies boot images
in the BIMG format, used in systems designed by Imagination
Technologies, for example the Pistachio SoC. `C`
* __bincfg__ - Compiler/Decompiler for data blobs with specs `Lex`
`Yacc`
* __board_status__ - Tools to collect logs and upload them to the board

View File

@ -488,7 +488,7 @@ endif
additional-dirs := $(objutil)/cbfstool $(objutil)/romcc $(objutil)/ifdtool \
$(objutil)/options $(objutil)/amdfwtool \
$(objutil)/cbootimage $(objutil)/bimgtool
$(objutil)/cbootimage
export $(COREBOOT_EXPORTS)
@ -581,11 +581,6 @@ FUTILITY?=$(objutil)/futility/futility
subdirs-y += util/nvidia
BIMGTOOL:=$(objutil)/bimgtool/bimgtool
$(BIMGTOOL): $(top)/util/bimgtool/bimgtool.c
@printf " HOSTCC $(subst $(obj)/,,$(@))\n"
$(HOSTCC) $(HOSTCFLAGS) -o $@ $<
$(obj)/config.h: $(objutil)/kconfig/conf
#######################################################################

View File

@ -54,7 +54,6 @@ ifneq ($(CONFIG_LP_TIMER_GENERIC_HZ),0)
libc-y += timer/generic.c
endif
libc-$(CONFIG_LP_TIMER_RDTSC) += timer/rdtsc.c
libc-$(CONFIG_LP_TIMER_IMG_PISTACHIO) += timer/img_pistachio.c
libc-$(CONFIG_LP_TIMER_ARM64_ARCH) += timer/arm64_arch_timer.c
# Video console drivers

View File

@ -50,9 +50,6 @@ config TIMER_RK3288
config TIMER_RK3399
bool "Timer for Rockchip RK3399"
config TIMER_IMG_PISTACHIO
bool "Timer for IMG Pistachio"
config TIMER_MTK
bool "Timer for MediaTek"

View File

@ -1,2 +0,0 @@
# Load all chipsets
source "src/soc/imgtec/*/Kconfig"

View File

@ -1,34 +0,0 @@
#
# This file is part of the coreboot project.
#
# Copyright (C) 2014 Imagination Technologies
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; version 2 of
# the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
config CPU_IMGTEC_PISTACHIO
select ARCH_MIPS
select ARCH_BOOTBLOCK_MIPS
select ARCH_VERSTAGE_MIPS
select ARCH_ROMSTAGE_MIPS
select ARCH_RAMSTAGE_MIPS
select HAVE_UART_SPECIAL
select GENERIC_GPIO_LIB
select UART_OVERRIDE_REFCLK
bool
if CPU_IMGTEC_PISTACHIO
config BOOTBLOCK_CPU_INIT
string
default "soc/imgtec/pistachio/bootblock.c"
endif

View File

@ -1,48 +0,0 @@
#
# This file is part of the coreboot project.
#
# Copyright (C) 2014 Imagination Technologies
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; version 2 of
# the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
ifeq ($(CONFIG_CPU_IMGTEC_PISTACHIO),y)
# We enable CBFS_SPI_WRAPPER for Pistachio targets.
bootblock-y += clocks.c
bootblock-y += spi.c
romstage-y += spi.c
ramstage-y += spi.c
bootblock-y += uart.c
romstage-y += uart.c
ramstage-y += uart.c
bootblock-y += monotonic_timer.c
ramstage-y += monotonic_timer.c
ramstage-y += soc.c
ramstage-y += reset.c
romstage-y += cbmem.c
romstage-y += ddr2_init.c
romstage-y += ddr3_init.c
romstage-y += romstage.c
romstage-y += monotonic_timer.c
CPPFLAGS_common += -Isrc/soc/imgtec/pistachio/include/
# Create a complete bootblock which will start up the system
$(objcbfs)/bootblock.bin: $(objcbfs)/bootblock.raw.bin $(BIMGTOOL)
@printf " BIMGTOOL $(subst $(obj)/,,$(@))\n"
$(BIMGTOOL) $< $@ $(call loadaddr,bootblock)
endif

View File

@ -1,62 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2014 Imagination Technologies
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; version 2 of
* the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <arch/cpu.h>
#include <arch/mmu.h>
#include <assert.h>
#include <stdint.h>
#include <symbols.h>
static void bootblock_cpu_init(void)
{
uint32_t cause;
/*
* Make sure the count register is counting by clearing the "Disable
* Counter" bit, in case it is set.
*/
cause = read_c0_cause();
if (cause & C0_CAUSE_DC)
write_c0_cause(cause & ~(C0_CAUSE_DC));
/* And make sure that it starts from zero. */
write_c0_count(0);
}
static void bootblock_mmu_init(void)
{
uint32_t null_guard_size = 1 * MiB;
uint32_t dram_base, dram_size;
write_c0_wired(0);
dram_base = (uint32_t)_dram;
dram_size = CONFIG_DRAM_SIZE_MB * MiB;
/*
* To be able to catch NULL pointer dereference attempts, lets not map
* memory close to zero.
*/
if (dram_base < null_guard_size) {
dram_base += null_guard_size;
dram_size -= null_guard_size;
}
assert(!identity_map((uint32_t)_sram, REGION_SIZE(sram),
C0_ENTRYLO_COHERENCY_WB));
assert(!identity_map(dram_base, dram_size, C0_ENTRYLO_COHERENCY_WB));
assert(!identity_map((uint32_t)_soc_registers,
REGION_SIZE(soc_registers), C0_ENTRYLO_COHERENCY_UC));
}

View File

@ -1,24 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2014 Imagination Technologies
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; version 2 of
* the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <cbmem.h>
#include <stdlib.h>
#include <symbols.h>
void *cbmem_top_chipset(void)
{
return _dram + (CONFIG_DRAM_SIZE_MB << 20);
}

View File

@ -1,513 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2014 Imagination Technologies
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; version 2 of
* the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <device/mmio.h>
#include <assert.h>
#include <delay.h>
#include <soc/clocks.h>
#include <timer.h>
/* Definitions for PLL enable */
#define PISTACHIO_CLOCK_SWITCH 0xB8144200
#define SYS_EXTERN_PLL_BYPASS_MASK 0x00002000
#define SYS_PLL_CTRL4_ADDR 0xB8144048
#define SYS_INTERNAL_PLL_BYPASS_MASK 0x10000000
#define SYS_PLL_PD_CTRL_ADDR 0xB8144044
#define SYS_PLL_PD_CTRL_PD_MASK 0x00000039
#define SYS_PLL_DACPD_ADDR 0xB8144044
#define SYS_PLL_DACPD_MASK 0x00000002
#define SYS_PLL_DSMPD_ADDR 0xB8144044
#define SYS_PLL_DSMPD_MASK 0x00000004
#define MIPS_EXTERN_PLL_BYPASS_MASK 0x00000002
#define MIPS_PLL_CTRL2_ADDR 0xB8144008
#define MIPS_INTERNAL_PLL_BYPASS_MASK 0x10000000
#define MIPS_PLL_PD_CTRL_ADDR 0xB8144004
#define MIPS_PLL_PD_CTRL_PD_MASK 0x0D000000
#define MIPS_PLL_DSMPD_ADDR 0xB8144004
#define MIPS_PLL_DSMPD_MASK 0x02000000
/* Definitions for PLL dividers */
#define SYS_PLL_POSTDIV_ADDR 0xB8144040
#define SYS_PLL_POSTDIV1_MASK 0x07000000
#define SYS_PLL_POSTDIV1_SHIFT 24
#define SYS_PLL_POSTDIV2_MASK 0x38000000
#define SYS_PLL_POSTDIV2_SHIFT 27
#define SYS_PLL_STATUS_ADDR 0xB8144038
#define SYS_PLL_STATUS_LOCK_MASK 0x00000001
#define SYS_PLL_REFDIV_ADDR 0xB814403C
#define SYS_PLL_REFDIV_MASK 0x0000003F
#define SYS_PLL_REFDIV_SHIFT 0
#define SYS_PLL_FEEDBACK_ADDR 0xB814403C
#define SYS_PLL_FEEDBACK_MASK 0x0003FFC0
#define SYS_PLL_FEEDBACK_SHIFT 6
#define MIPS_PLL_POSTDIV_ADDR 0xB8144004
#define MIPS_PLL_POSTDIV1_MASK 0x001C0000
#define MIPS_PLL_POSTDIV1_SHIFT 18
#define MIPS_PLL_POSTDIV2_MASK 0x00E00000
#define MIPS_PLL_POSTDIV2_SHIFT 21
#define MIPS_PLL_STATUS_ADDR 0xB8144000
#define MIPS_PLL_STATUS_LOCK_MASK 0x00000001
#define MIPS_REFDIV_ADDR 0xB8144004
#define MIPS_REFDIV_MASK 0x0000003F
#define MIPS_REFDIV_SHIFT 0
#define MIPS_FEEDBACK_ADDR 0xB8144004
#define MIPS_FEEDBACK_MASK 0x0003FFC0
#define MIPS_FEEDBACK_SHIFT 6
/* Definitions for system clock setup */
#define SYSCLKINTERNAL_CTRL_ADDR 0xB8144244
#define SYSCLKINTERNAL_MASK 0X00000007
/* Definitions for MIPS clock setup */
#define MIPSCLKINTERNAL_CTRL_ADDR 0xB8144204
#define MIPSCLKINTERNAL_MASK 0x00000003
#define MIPSCLKOUT_CTRL_ADDR 0xB8144208
#define MIPSCLKOUT_MASK 0x000000FF
/* Peripheral Clock gate reg */
#define MIPS_CLOCK_GATE_ADDR 0xB8144900
#define RPU_CLOCK_GATE_ADDR 0xB8144904
#define MIPS_CLOCK_GATE_ALL_ON 0x3fff
#define RPU_CLOCK_GATE_ALL_OFF 0x0
/* Definitions for USB clock setup */
#define USBPHYCLKOUT_CTRL_ADDR 0xB814422C
#define USBPHYCLKOUT_MASK 0X0000003F
#define USBPHYCONTROL1_ADDR 0xB8149004
#define USBPHYCONTROL1_FSEL_SHIFT 2
#define USBPHYCONTROL1_FSEL_MASK 0x1C
#define USBPHYSTRAPCTRL_ADDR 0xB8149010
#define USBPHYSTRAPCTRL_REFCLKSEL_SHIFT 4
#define USBPHYSTRAPCTRL_REFCLKSEL_MASK 0x30
#define USBPHYSTATUS_ADDR 0xB8149014
#define USBPHYSTATUS_RX_PHY_CLK_MASK 0x200
#define USBPHYSTATUS_RX_UTMI_CLK_MASK 0x100
#define USBPHYSTATUS_VBUS_FAULT_MASK 0x80
/* Definitions for UART0/1 setup */
#define UART0CLKINTERNAL_CTRL_ADDR 0xB8144234
#define UART0CLKINTERNAL_MASK 0x00000007
#define UART0CLKOUT_CTRL_ADDR 0xB8144238
#define UART0CLKOUT_MASK 0x000003FF
#define UART1CLKINTERNAL_CTRL_ADDR 0xB814423C
#define UART1CLKINTERNAL_MASK 0x00000007
#define UART1CLKOUT_CTRL_ADDR 0xB8144240
#define UART1CLKOUT_MASK 0x000003FF
/* Definitions for I2C setup */
#define I2CCLKDIV1_CTRL_ADDR(i) (0xB8144800 + 0x013C + (2*(i)*4))
#define I2CCLKDIV1_MASK 0x0000007F
#define I2CCLKOUT_CTRL_ADDR(i) (0xB8144800 + 0x0140 + (2*(i)*4))
#define I2CCLKOUT_MASK 0x0000007F
/* Definitions for ROM clock setup */
#define ROMCLKOUT_CTRL_ADDR 0xB814490C
#define ROMCLKOUT_MASK 0x0000007F
/* Definitions for ETH clock setup */
#define ENETCLKMUX_MASK 0x00004000
#define ENETCLKDIV_CTRL_ADDR 0xB8144230
#define ENETCLKDIV_MASK 0x0000003F
/* Definitions for timeout values */
#define PLL_TIMEOUT_VALUE_US 20000
#define USB_TIMEOUT_VALUE_US 200000
#define SYS_CLK_LOCK_DELAY 3
struct pll_parameters {
u32 external_bypass_mask;
u32 ctrl_addr;
u32 internal_bypass_mask;
u32 power_down_ctrl_addr;
u32 power_down_ctrl_mask;
u32 dacpd_addr;
u32 dacpd_mask;
u32 dsmpd_addr;
u32 dsmpd_mask;
u32 postdiv_addr;
u32 postdiv1_shift;
u32 postdiv1_mask;
u32 postdiv2_shift;
u32 postdiv2_mask;
u32 status_addr;
u32 status_lock_mask;
u32 refdivider;
u32 refdiv_addr;
u32 refdiv_shift;
u32 refdiv_mask;
u32 feedback;
u32 feedback_addr;
u32 feedback_shift;
u32 feedback_mask;
};
enum plls {
SYS_PLL = 0,
MIPS_PLL = 1
};
static struct pll_parameters pll_params[] = {
[SYS_PLL] = {
.external_bypass_mask = SYS_EXTERN_PLL_BYPASS_MASK,
.ctrl_addr = SYS_PLL_CTRL4_ADDR,
.internal_bypass_mask = SYS_INTERNAL_PLL_BYPASS_MASK,
.power_down_ctrl_addr = SYS_PLL_PD_CTRL_ADDR,
.power_down_ctrl_mask = SYS_PLL_PD_CTRL_PD_MASK,
/* Noise cancellation */
.dacpd_addr = SYS_PLL_DACPD_ADDR,
.dacpd_mask = SYS_PLL_DACPD_MASK,
.dsmpd_addr = SYS_PLL_DSMPD_ADDR,
/* 0 - Integer mode
* SYS_PLL_DSMPD_MASK - Fractional mode
*/
.dsmpd_mask = 0,
.postdiv_addr = SYS_PLL_POSTDIV_ADDR,
.postdiv1_shift = SYS_PLL_POSTDIV1_SHIFT,
.postdiv1_mask = SYS_PLL_POSTDIV1_MASK,
.postdiv2_shift = SYS_PLL_POSTDIV2_SHIFT,
.postdiv2_mask = SYS_PLL_POSTDIV2_MASK,
.status_addr = SYS_PLL_STATUS_ADDR,
.status_lock_mask = SYS_PLL_STATUS_LOCK_MASK,
.refdivider = 0, /* Not defined yet */
.refdiv_addr = SYS_PLL_REFDIV_ADDR,
.refdiv_shift = SYS_PLL_REFDIV_SHIFT,
.refdiv_mask = SYS_PLL_REFDIV_MASK,
.feedback = 0, /* Not defined yet */
.feedback_addr = SYS_PLL_FEEDBACK_ADDR,
.feedback_shift = SYS_PLL_FEEDBACK_SHIFT,
.feedback_mask = SYS_PLL_FEEDBACK_MASK
},
[MIPS_PLL] = {
.external_bypass_mask = MIPS_EXTERN_PLL_BYPASS_MASK,
.ctrl_addr = MIPS_PLL_CTRL2_ADDR,
.internal_bypass_mask = MIPS_INTERNAL_PLL_BYPASS_MASK,
.power_down_ctrl_addr = MIPS_PLL_PD_CTRL_ADDR,
.power_down_ctrl_mask = MIPS_PLL_PD_CTRL_PD_MASK,
.dacpd_addr = 0,
.dacpd_mask = 0,
.dsmpd_addr = MIPS_PLL_DSMPD_ADDR,
.dsmpd_mask = MIPS_PLL_DSMPD_MASK,
.postdiv_addr = MIPS_PLL_POSTDIV_ADDR,
.postdiv1_shift = MIPS_PLL_POSTDIV1_SHIFT,
.postdiv1_mask = MIPS_PLL_POSTDIV1_MASK,
.postdiv2_shift = MIPS_PLL_POSTDIV2_SHIFT,
.postdiv2_mask = MIPS_PLL_POSTDIV2_MASK,
.status_addr = MIPS_PLL_STATUS_ADDR,
.status_lock_mask = MIPS_PLL_STATUS_LOCK_MASK,
.refdivider = 0, /* Not defined yet */
.refdiv_addr = MIPS_REFDIV_ADDR,
.refdiv_shift = MIPS_REFDIV_SHIFT,
.refdiv_mask = MIPS_REFDIV_MASK,
.feedback = 0, /* Not defined yet */
.feedback_addr = MIPS_FEEDBACK_ADDR,
.feedback_shift = MIPS_FEEDBACK_SHIFT,
.feedback_mask = MIPS_FEEDBACK_MASK
}
};
static int pll_setup(struct pll_parameters *param, u8 divider1, u8 divider2)
{
u32 reg;
struct stopwatch sw;
/* Check input parameters */
assert(!((divider1 << param->postdiv1_shift) &
~(param->postdiv1_mask)));
assert(!((divider2 << param->postdiv2_shift) &
~(param->postdiv2_mask)));
/* Temporary bypass PLL (select XTAL as clock input) */
reg = read32_x(PISTACHIO_CLOCK_SWITCH);
reg &= ~(param->external_bypass_mask);
write32_x(PISTACHIO_CLOCK_SWITCH, reg);
/* Un-bypass PLL's internal bypass */
reg = read32_x(param->ctrl_addr);
reg &= ~(param->internal_bypass_mask);
write32_x(param->ctrl_addr, reg);
/* Disable power down */
reg = read32_x(param->power_down_ctrl_addr);
reg &= ~(param->power_down_ctrl_mask);
write32_x(param->power_down_ctrl_addr, reg);
/* Noise cancellation */
if (param->dacpd_addr) {
reg = read32_x(param->dacpd_addr);
reg &= ~(param->dacpd_mask);
write32_x(param->dacpd_addr, reg);
}
/* Functional mode */
if (param->dsmpd_addr) {
reg = read32_x(param->dsmpd_addr);
reg &= ~(param->dsmpd_mask);
write32_x(param->dsmpd_addr, reg);
}
if (param->feedback_addr) {
assert(!((param->feedback << param->feedback_shift) &
~(param->feedback_mask)));
reg = read32_x(param->feedback_addr);
reg &= ~(param->feedback_mask);
reg |= (param->feedback << param->feedback_shift) &
param->feedback_mask;
write32_x(param->feedback_addr, reg);
}
if (param->refdiv_addr) {
assert(!((param->refdivider << param->refdiv_shift) &
~(param->refdiv_mask)));
reg = read32_x(param->refdiv_addr);
reg &= ~(param->refdiv_mask);
reg |= (param->refdivider << param->refdiv_shift) &
param->refdiv_mask;
write32_x(param->refdiv_addr, reg);
}
/* Read postdivider register value */
reg = read32_x(param->postdiv_addr);
/* Set divider 1 */
reg &= ~(param->postdiv1_mask);
reg |= (divider1 << param->postdiv1_shift) &
param->postdiv1_mask;
/* Set divider 2 */
reg &= ~(param->postdiv2_mask);
reg |= (divider2 << param->postdiv2_shift) &
param->postdiv2_mask;
/* Write back to register */
write32_x(param->postdiv_addr, reg);
/* Waiting for PLL to lock*/
stopwatch_init_usecs_expire(&sw, PLL_TIMEOUT_VALUE_US);
while (!(read32_x(param->status_addr) & param->status_lock_mask)) {
if (stopwatch_expired(&sw))
return PLL_TIMEOUT;
}
/* Start using PLL */
reg = read32_x(PISTACHIO_CLOCK_SWITCH);
reg |= param->external_bypass_mask;
write32_x(PISTACHIO_CLOCK_SWITCH, reg);
return CLOCKS_OK;
}
int sys_pll_setup(u8 divider1, u8 divider2, u8 refdivider, u32 feedback)
{
pll_params[SYS_PLL].refdivider = refdivider;
pll_params[SYS_PLL].feedback = feedback;
return pll_setup(&(pll_params[SYS_PLL]), divider1, divider2);
}
int mips_pll_setup(u8 divider1, u8 divider2, u8 refdivider, u32 feedback)
{
pll_params[MIPS_PLL].refdivider = refdivider;
pll_params[MIPS_PLL].feedback = feedback;
return pll_setup(&(pll_params[MIPS_PLL]), divider1, divider2);
}
/*
* uart1_clk_setup: sets up clocks for UART1
* divider1: 3-bit divider value
* divider2: 10-bit divider value
*/
void uart1_clk_setup(u8 divider1, u16 divider2)
{
u32 reg;
/* Check input parameters */
assert(!(divider1 & ~(UART1CLKINTERNAL_MASK)));
assert(!(divider2 & ~(UART1CLKOUT_MASK)));
/* Set divider 1 */
reg = read32_x(UART1CLKINTERNAL_CTRL_ADDR);
reg &= ~UART1CLKINTERNAL_MASK;
reg |= divider1 & UART1CLKINTERNAL_MASK;
write32_x(UART1CLKINTERNAL_CTRL_ADDR, reg);
/* Set divider 2 */
reg = read32_x(UART1CLKOUT_CTRL_ADDR);
reg &= ~UART1CLKOUT_MASK;
reg |= divider2 & UART1CLKOUT_MASK;
write32_x(UART1CLKOUT_CTRL_ADDR, reg);
}
/*
* i2c_clk_setup: sets up clocks for I2C
* divider1: 7-bit divider value
* divider2: 7-bit divider value
*/
void i2c_clk_setup(u8 divider1, u16 divider2, u8 interface)
{
u32 reg;
/* Check input parameters */
assert(!(divider1 & ~(I2CCLKDIV1_MASK)));
assert(!(divider2 & ~(I2CCLKOUT_MASK)));
assert(interface < 4);
/* Set divider 1 */
reg = read32_x(I2CCLKDIV1_CTRL_ADDR(interface));
reg &= ~I2CCLKDIV1_MASK;
reg |= divider1 & I2CCLKDIV1_MASK;
write32_x(I2CCLKDIV1_CTRL_ADDR(interface), reg);
/* Set divider 2 */
reg = read32_x(I2CCLKOUT_CTRL_ADDR(interface));
reg &= ~I2CCLKOUT_MASK;
reg |= divider2 & I2CCLKOUT_MASK;
write32_x(I2CCLKOUT_CTRL_ADDR(interface), reg);
}
/* system_clk_setup: sets up the system (peripheral) clock */
void system_clk_setup(u8 divider)
{
u32 reg;
/* Check input parameters */
assert(!(divider & ~(SYSCLKINTERNAL_MASK)));
/* Set system clock divider */
reg = read32_x(SYSCLKINTERNAL_CTRL_ADDR);
reg &= ~SYSCLKINTERNAL_MASK;
reg |= divider & SYSCLKINTERNAL_MASK;
write32_x(SYSCLKINTERNAL_CTRL_ADDR, reg);
/* Small delay to cover a maximum lock time of 1500 cycles */
udelay(SYS_CLK_LOCK_DELAY);
}
void mips_clk_setup(u8 divider1, u8 divider2)
{
u32 reg;
/* Check input parameters */
assert(!(divider1 & ~(MIPSCLKINTERNAL_MASK)));
assert(!(divider2 & ~(MIPSCLKOUT_MASK)));
/* Set divider 1 */
reg = read32_x(MIPSCLKINTERNAL_CTRL_ADDR);
reg &= ~MIPSCLKINTERNAL_MASK;
reg |= divider1 & MIPSCLKINTERNAL_MASK;
write32_x(MIPSCLKINTERNAL_CTRL_ADDR, reg);
/* Set divider 2 */
reg = read32_x(MIPSCLKOUT_CTRL_ADDR);
reg &= ~MIPSCLKOUT_MASK;
reg |= divider2 & MIPSCLKOUT_MASK;
write32_x(MIPSCLKOUT_CTRL_ADDR, reg);
}
/* usb_clk_setup: sets up USB clock */
int usb_clk_setup(u8 divider, u8 refclksel, u8 fsel)
{
u32 reg;
struct stopwatch sw;
/* Check input parameters */
assert(!(divider & ~(USBPHYCLKOUT_MASK)));
assert(!((refclksel << USBPHYSTRAPCTRL_REFCLKSEL_SHIFT) &
~(USBPHYSTRAPCTRL_REFCLKSEL_MASK)));
assert(!((fsel << USBPHYCONTROL1_FSEL_SHIFT) &
~(USBPHYCONTROL1_FSEL_MASK)));
/* Set USB divider */
reg = read32_x(USBPHYCLKOUT_CTRL_ADDR);
reg &= ~USBPHYCLKOUT_MASK;
reg |= divider & USBPHYCLKOUT_MASK;
write32_x(USBPHYCLKOUT_CTRL_ADDR, reg);
/* Set REFCLKSEL */
reg = read32_x(USBPHYSTRAPCTRL_ADDR);
reg &= ~USBPHYSTRAPCTRL_REFCLKSEL_MASK;
reg |= (refclksel << USBPHYSTRAPCTRL_REFCLKSEL_SHIFT) &
USBPHYSTRAPCTRL_REFCLKSEL_MASK;
write32_x(USBPHYSTRAPCTRL_ADDR, reg);
/* Set FSEL */
reg = read32_x(USBPHYCONTROL1_ADDR);
reg &= ~USBPHYCONTROL1_FSEL_MASK;
reg |= (fsel << USBPHYCONTROL1_FSEL_SHIFT) &
USBPHYCONTROL1_FSEL_MASK;
write32_x(USBPHYCONTROL1_ADDR, reg);
/* Waiting for USB clock status */
stopwatch_init_usecs_expire(&sw, USB_TIMEOUT_VALUE_US);
while (1) {
reg = read32_x(USBPHYSTATUS_ADDR);
if (reg & USBPHYSTATUS_VBUS_FAULT_MASK)
return USB_VBUS_FAULT;
if (stopwatch_expired(&sw))
return USB_TIMEOUT;
/* Check if USB is set up properly */
if ((reg & USBPHYSTATUS_RX_PHY_CLK_MASK) &&
(reg & USBPHYSTATUS_RX_UTMI_CLK_MASK))
break;
}
return CLOCKS_OK;
}
void rom_clk_setup(u8 divider)
{
u32 reg;
/* Check input parameter */
assert(!(divider & ~(ROMCLKOUT_MASK)));
/* Set ROM divider */
reg = read32_x(ROMCLKOUT_CTRL_ADDR);
reg &= ~ROMCLKOUT_MASK;
reg |= divider & ROMCLKOUT_MASK;
write32_x(ROMCLKOUT_CTRL_ADDR, reg);
}
void eth_clk_setup(u8 mux, u8 divider)
{
u32 reg;
/* Check input parameters */
assert(!(divider & ~(ENETCLKDIV_MASK)));
/* This can be either 0 or 1, selecting between
* ENET and system clock as clocksource */
assert(!(mux & ~(0x1)));
/* Set ETH divider */
reg = read32_x(ENETCLKDIV_CTRL_ADDR);
reg &= ~ENETCLKDIV_MASK;
reg |= divider & ENETCLKDIV_MASK;
write32_x(ENETCLKDIV_CTRL_ADDR, reg);
/* Select source */
if (mux) {
reg = read32_x(PISTACHIO_CLOCK_SWITCH);
reg |= ENETCLKMUX_MASK;
write32_x(PISTACHIO_CLOCK_SWITCH, reg);
}
}
void setup_clk_gate_defaults(void)
{
write32_x(MIPS_CLOCK_GATE_ADDR, MIPS_CLOCK_GATE_ALL_ON);
write32_x(RPU_CLOCK_GATE_ADDR, RPU_CLOCK_GATE_ALL_OFF);
}

View File

@ -1,443 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2014 Imagination Technologies
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; version 2 of
* the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <device/mmio.h>
#include <soc/ddr_init.h>
#include <soc/ddr_private_reg.h>
#include <stdint.h>
#define BL8 0
/*
* Configuration for the Winbond W972GG6JB-25 part using
* Synopsys DDR uMCTL and DDR Phy
*/
int init_ddr2(void)
{
/*
* Reset the AXI bridge and DDR Controller in case any spurious
* writes have already happened to DDR - note must be done together,
* not sequentially
*/
write32_x(TOPLEVEL_REGS + DDR_CTRL_OFFSET, 0x00000000);
write32_x(TOPLEVEL_REGS + DDR_CTRL_OFFSET, 0x0000000F);
/*
* Dummy read to fence the access between the reset above
* and thw DDR controller writes below
*/
read32_x(TOPLEVEL_REGS + DDR_CTRL_OFFSET);
/* Timings for 400MHz
* therefore 200MHz (5ns) uMCTL (Internal) Rate
*/
/* TOGCNT1U: Toggle Counter 1U Register: 1us 200h C8h */
write32_x(DDR_PCTL + DDR_PCTL_TOGCNT1U_OFFSET, 0x000000C8);
/* TINIT: t_init Timing Register: at least 200us 200h C8h */
write32_x(DDR_PCTL + DDR_PCTL_TINIT_OFFSET, 0x000000C8);
/* TRSTH: Reset High Time Register DDR3 ONLY */
write32_x(DDR_PCTL + DDR_PCTL_TRSTH_OFFSET, 0x00000000);
/* TOGCNT100N: Toggle Counter 100N Register: 20d, 14h*/
write32_x(DDR_PCTL + DDR_PCTL_TOGG_CNTR_100NS_OFFSET, 0x00000014);
/* DTUAWDT DTU Address Width Register
* 1:0 column_addr_width Def 10 - 7 3 10 bits
* 4:3 bank_addr_width Def 3 - 2 1 3 bits (8 bank)
* 7:6 row_addr_width Def 14 - 13 1 3 bits
* 10:9 number_ranks Def 1 - 1 0 0 1 Rank
*/
write32_x(DDR_PCTL + DDR_PCTL_DTUAWDT_OFFSET, 0x0000004B);
/* MCFG
* 0 BL 0 = 4 1 = 8
* 1 RDRIMM 0
* 2 BL8 Burst Terminate 0
* 3 2T = 0
* 4 Multi Rank 0
* 5 DDR3 En 0
* 6 LPDDR S4 En
* 7 BST En 0, 1 for LPDDR2/3
* 15:8 Power down Idle, passed by argument
* 16 Power Down Type, passed by argument
* 17 Power Down Exit 0 = slow, 1 = fast, pba
* 19:18 tFAW 45ns = 9 clk 5*2 -1 1h
* 21:20 mDDR/LPDDR2 BL 0
* 23:22 mDDR/LPDDR2 Enable 0
* 31:24 mDDR/LPDDR2/3 Dynamic Clock Stop 0
*/
write32_x(DDR_PCTL + DDR_PCTL_MCFG_OFFSET,
0x00060000 | (BL8 ? 0x1 : 0x0));
/* MCFG1: Memory Configuration-1 Register
* c7:0 sr_idle Self Refresh Idle Entery 32 * nclks 14h, set 0 for BUB
* 10:8 Fine tune MCFG.19:18 -1
* 15:11 Reserved
* 23:16 Hardware Idle Period NA 0
* 30:24 Reserved
* 31 c_active_in_pin exit auto clk stop NA 0
*/
write32_x(DDR_PCTL + DDR_PCTL_MCFG1_OFFSET, 0x00000100);
/* DCR DRAM Config
* 2:0 SDRAM => DDR2 2
* 3 DDR 8 Bank 1
* 6:4 Primary DQ DDR3 Only 0
* 7 Multi-Purpose Register DDR3 Only 0
* 9:8 DDRTYPE LPDDR2 00
* 26:10 Reserved
* 27 NOSRA No Simultaneous Rank Access 0
* 28 DDR 2T 0
* 29 UDIMM NA 0
* 30 RDIMM NA 0
* 31 TPD LPDDR2 0
*/
write32_x(DDR_PHY + DDRPHY_DCR_OFFSET, 0x0000000A);
/* Generate to use with PHY and PCTL
* MR0 : MR Register, bits 12:0 imported dfrom MR
* 2:0 BL 8 011
* 3 BT Sequential 0 Interleaved 1 = 0
* 6:4 CL 6
* 7 TM Normal 0
* 8 DLL Reset 1 (self Clearing)
* 11:9 WR 15 ns 6 (101)
* 12 PD Slow 1 Fast 0 0
* 15:13 RSVD RSVD
* 31:16 Reserved
*/
write32_x(DDR_PHY + DDRPHY_MR_OFFSET, 0x00000B62 | (BL8 ? 0x1 : 0x0));
/* MR1 : EMR Register
* Generate to use with PHY and PCTL
* 0 DE DLL Enable 0 Disable 1
* 1 DIC Output Driver Imp Ctl 0 Full, 1 Half
* 6,2 ODT 0 Disable, 1 75R, 2 150R, 3 50R; LSB: 2, MSB: 6
* 5:3 AL = 0
* 9:7 OCD = 0
* 10 DQS 0 diff, 1 single = 0
* 11 RDQS NA 0
* 12 QOFF Normal mode 0
* 15:13 RSVD
* 31:16 Reserved
*/
write32_x(DDR_PHY + DDRPHY_EMR_OFFSET, 0x00000044);
/* MR2 : EMR2 Register
* Generate to use with PHY and PCTL
* 2:0 PASR, NA 000
* 3 DDC NA 0
* 6:4 RSVD
* 7 SFR 0
* 15:8 RSVD
* 31:16 Reserved
*/
write32_x(DDR_PHY + DDRPHY_EMR2_OFFSET, 0x00000000);
/* DSGCR
* 0 PUREN Def 1
* 1 BDISEN Def 1
* 2 ZUEN Def 1
* 3 LPIOPD DEf 1 0
* 4 LPDLLPD DEf 1 0
* 7:5 DQSGX DQS Extention set to 1 - advised by Synopsys
* 10:8 DQSGE DQS Early Gate - 1 - advised by Sysnopsys
* 11 NOBUB No Bubbles, adds latency 1
* 12 FXDLAT Fixed Read Latency 0
* 15:13 Reserved
* 19:16 CKEPDD CKE Power Down 0000
* 23:20 ODTPDD ODT Power Down 0000
* 24 NL2PD Power Down Non LPDDR2 pins 0
* 25 NL2OE Output Enable Non LPDDR2 pins 1
* 26 TPDPD LPDDR Only 0
* 27 TPDOE LPDDR Only 0
* 28 CKOE Output Enable Clk's 1
* 29 ODTOE Output Enable ODT 1
* 30 RSTOE RST# Output Enable 1
* 31 CKEOE CKE Output Enable 1
*/
write32_x(DDR_PHY + DDRPHY_DSGCR_OFFSET, 0xF2000927);
/* Sysnopsys advised 500R pullup/pulldown DQS DQSN */
write32_x(DDR_PHY + DDRPHY_DXCCR_OFFSET, 0x00000C40);
/* DTPR0 : DRAM Timing Params 0
* 1:0 tMRD 2
* 4:2 tRTP 3
* 7:5 tWTR 3
* 11:8 tRP 6
* 15:12 tRCD 6
* 20:16 tRAS 18
* 24:21 tRRD 4
* 30:25 tRC 24 (23)
* 31 tCCD 0 BL/2 Cas to Cas
*/
write32_x(DDR_PHY + DDRPHY_DTPR0_OFFSET, 0x3092666E);
/* DTPR1 : DRAM Timing Params 1
* 1:0 ODT On/Off Del Std 0
* 2 tRTW Rd2Wr Del 0 std 1 +1 0
* 8:3 tFAW 4 Bank Act 45ns = 18 18
* 10:9 tMOD DDR3 Only 0
* 11 tRTODT DDR3 Only 0
* 15:12 Reserved
* 23:16 tRFC 195ns 78 def 131 78d
* 26:24 tDQSCK LPDDR2 only 1
* 29:27 tDQSCKmax 1
* 31:30 Reserved
*/
write32_x(DDR_PHY + DDRPHY_DTPR1_OFFSET, 0x094E0092);
/* DTPR2 : DRAM Timing Params 2
* 9:0 tXS exit SR def 200, 200d
* 14:10 tXP PD Exit Del 8 3
* 18:15 tCKE CKE Min pulse 3
* 28:19 tDLLK DLL Lock time 200d
* 32:29 Reserved
*/
write32_x(DDR_PHY + DDRPHY_DTPR2_OFFSET, 0x06418CC8);
/* PTR0 : PHY Timing Params 0
* 5:0 tDLLRST Def 27
* 17:6 tDLLLOCK Def 2750
* 21:18 tITMSRST Def 8
* 31:22 Reserved 0
*/
write32_x(DDR_PHY + DDRPHY_PTR0_OFFSET, 0x0022AF9B);
/* PTR1 : PHY Timing Params 1
* 18:0 : tDINITO DRAM Init time 200us 80,000 Dec 0x13880
* 29:19 : tDINIT1 DRAM Init time 400ns 160 Dec 0xA0
*/
write32_x(DDR_PHY + DDRPHY_PTR1_OFFSET, 0x05013880);
/* DQS gating configuration: passive windowing mode */
/*
* PGCR: PHY General cofiguration register
* 0 ITM DDR mode: 0
* 1 DQS gading configuration: passive windowing 1
* 2 DQS drift compensation: not supported in passive windowing 0
* 4:3 DQS drift limit 0
* 8:5 Digital test output select 0
* 11:9 CK Enable: one bit for each 3 CK pair: 0x7
* 13:12 CK Disable values: 0x2
* 14 CK Invert 0
* 15 IO loopback 0
* 17:16 I/O DDR mode 0
* 21:18 Ranks enable by training: 0xF
* 23:22 Impedance clock divider select 0x2
* 24 Power down disable 1
* 28:25 Refresh during training 0
* 29 loopback DQS shift 0
* 30 loopback DQS gating 0
* 31 loopback mode 0
*/
write32_x(DDR_PHY + DDRPHY_PGCR_OFFSET, 0x01BC2E02);
/* PGSR : Wait for INIT/DLL/Z Done from Power on Reset */
if (wait_for_completion(DDR_PHY + DDRPHY_PGSR_OFFSET, 0x00000007))
return DDR_TIMEOUT;
/* PIR : use PHY for DRAM Init */
write32_x(DDR_PHY + DDRPHY_PIR_OFFSET, 0x000001DF);
/* PGSR : Wait for DRAM Init Done */
if (wait_for_completion(DDR_PHY + DDRPHY_PGSR_OFFSET, 0x0000001F))
return DDR_TIMEOUT;
/* Disable Impedance Calibration */
write32_x(DDR_PHY + DDRPHY_ZQ0CR0_OFFSET, 0x3000014A);
write32_x(DDR_PHY + DDRPHY_ZQ1CR0_OFFSET, 0x3000014A);
/* DF1STAT0 : wait for DFI_INIT_COMPLETE */
if (wait_for_completion(DDR_PCTL + DDR_PCTL_DFISTAT0_OFFSET,
0x00000001))
return DDR_TIMEOUT;
/* POWCTL : Start the memory Power Up seq*/
write32_x(DDR_PCTL + DDR_PCTL_POWCTL_OFFSET, 0x00000001);
/* POWSTAT : wait for POWER_UP_DONE */
if (wait_for_completion(DDR_PCTL + DDR_PCTL_POWSTAT_OFFSET,
0x00000001))
return DDR_TIMEOUT;
/*
* TREFI : t_refi Timing Register 1X
* 12:0 t_refi 7.8us in 100ns 0x4E
* 15:13 Reserved 0
* 18:16 num_add_ref 0
* 30:19 Reserved 0
* 31 Update 1
*/
write32_x(DDR_PCTL + DDR_PCTL_TREFI_OFFSET, 0x8000004E);
/* TMRD : t_mrd Timing Register -- Range 2 to 3 */
write32_x(DDR_PCTL + DDR_PCTL_TMRD_OFFSET, 0x00000002);
/*
* TRFC : t_rfc Timing Register -- Range 15 to 131
* 195ns / 2.5ns 78 x4E
*/
write32_x(DDR_PCTL + DDR_PCTL_TRFC_OFFSET, 0x0000004E);
/* TRP : t_rp Timing Register -- Range 3 to 7
* 4:0 tRP 12.5 / 2.5 = 5 6 For Now 6-6-6
* 17:16 rpea_extra tRPall 8 bank 1
*/
write32_x(DDR_PCTL + DDR_PCTL_TRP_OFFSET, 0x00010006);
/* TAL : Additive Latency Register -- AL in MR1 */
write32_x(DDR_PCTL + DDR_PCTL_TAL_OFFSET, 0x00000000);
/* DFITPHYWRLAT : Write cmd to dfi_wrdata_en */
write32_x(DDR_PCTL + DDR_PCTL_DFIWRLAT_OFFSET, 0x00000002);
/* DFITRDDATAEN : Read cmd to dfi_rddata_en */
write32_x(DDR_PCTL + DDR_PCTL_DFITRDDATAEN_OFFSET, 0x00000002);
/* TCL : CAS Latency Timing Register -- CASL in MR0 6-6-6 */
write32_x(DDR_PCTL + DDR_PCTL_TCL_OFFSET, 0x00000006);
/* TCWL : CAS Write Latency Register --CASL-1 */
write32_x(DDR_PCTL + DDR_PCTL_TCWL_OFFSET, 0x00000005);
/*
* TRAS : Activate to Precharge cmd time
* Range 8 to 24: 45ns / 2.5ns = 18d
*/
write32_x(DDR_PCTL + DDR_PCTL_TRAS_OFFSET, 0x00000012);
/*
* TRC : Min. ROW cycle time
* Range 11 to 31: 57.5ns / 2.5ns = 23d Playing safe 24
*/
write32_x(DDR_PCTL + DDR_PCTL_TRC_OFFSET, 0x00000018);
/*
* TRCD : Row to Column Delay
* Range 3 to 7 (TCL = TRCD): 2.5ns / 2.5ns = 5 but running 6-6-6 6
*/
write32_x(DDR_PCTL + DDR_PCTL_TRCD_OFFSET, 0x00000006);
/* TRRD : Row to Row delay -- Range 2 to 6: 2K Page 10ns / 2.5ns = 4*/
write32_x(DDR_PCTL + DDR_PCTL_TRRD_OFFSET, 0x00000004);
/* TRTP : Read to Precharge time -- Range 2 to 4: 7.3ns / 2.5ns = 3 */
write32_x(DDR_PCTL + DDR_PCTL_TRTP_OFFSET, 0x00000003);
/* TWR : Write recovery time -- WR in MR0: 15ns / 2.5ns = 6
*/
write32_x(DDR_PCTL + DDR_PCTL_TWR_OFFSET, 0x00000006);
/*
* TWTR : Write to read turn around time
* Range 2 to 4: 7.3ns / 2.5ns = 3
*/
write32_x(DDR_PCTL + DDR_PCTL_TWTR_OFFSET, 0x00000003);
/* TEXSR : Exit Self Refresh to first valid cmd: tXS 200*/
write32_x(DDR_PCTL + DDR_PCTL_TEXSR_OFFSET, 0x000000C8);
/*
* TXP : Exit Power Down to first valid cmd
* tXP 2, Settingto 3 to match PHY
*/
write32_x(DDR_PCTL + DDR_PCTL_TXP_OFFSET, 0x00000003);
/*
* TDQS : t_dqs Timing Register
* DQS additional turn around Rank 2 Rank (1 Rank) Def 1
*/
write32_x(DDR_PCTL + DDR_PCTL_TDQS_OFFSET, 0x00000001);
/*TRTW : Read to Write turn around time Def 3
* Actual gap t_bl + t_rtw
*/
write32_x(DDR_PCTL + DDR_PCTL_TRTW_OFFSET, 0x00000003);
/* TCKE : CKE min pulse width DEf 3 */
write32_x(DDR_PCTL + DDR_PCTL_TCKE_OFFSET, 0x00000003);
/*
* TXPDLL : Slow Exit Power Down to first valid cmd delay
* tXARDS 10+AL = 10
*/
write32_x(DDR_PCTL + DDR_PCTL_TXPDLL_OFFSET, 0x0000000A);
/*
* TCKESR : Min CKE Low width for Self refresh entry to exit
* t_ckesr = 0 DDR2
*/
write32_x(DDR_PCTL + DDR_PCTL_TCKESR_OFFSET, 0x00000000);
/* SCFG : State Configuration Register (Enabling Self Refresh)
* 0 LP_en Leave Off for Bring Up 0
* 5:1 Reserved
* 6 Synopsys Internal Only 0
* 7 Enale PHY indication of LP Opportunity 1
* 11:8 bbflags_timing max UPCTL_TCU_SED_P - tRP (16 - 6) Use 4
* 16:12 Additional delay on accertion of ac_pdd 4
* 31:17 Reserved
*/
write32_x(DDR_PCTL + DDR_PCTL_SCFG_OFFSET, 0x00004480);
/*
* DFITPHYWRDATA : dfi_wrdata_en to drive wr data
* DFI Clks wrdata_en to wrdata Def 1
*/
write32_x(DDR_PCTL + DDR_PCTL_DFITPHYWRDATA_OFFSET, 0x00000000);
/*
* DFITPHYRDLAT : dfi_rddata_en to dfi_rddata_valid
* DFI clks max rddata_en to rddata_valid Def 15
*/
write32_x(DDR_PCTL + DDR_PCTL_DFITPHYRDLAT_OFFSET, 0x00000008);
/* MCMD : PREA, Addr 0 Bank 0 Rank 0 Del 0
* 3:0 cmd_opcode PREA 00001
* 16:4 cmd_addr 0
* 19:17 bank_addr 0
* 23:20 rank_sel 0 0001
* 27:24 cmddelay 0
* 30:24 Reserved
*/
write32_x(DDR_PCTL + DDR_PCTL_MCMD_OFFSET, 0x80100001);
/* MRS cmd wait for completion */
if (wait_for_completion(DDR_PCTL + DDR_PCTL_MCMD_OFFSET, 0x00100001))
return DDR_TIMEOUT;
/* SCTL : UPCTL switch INIT CONFIG State */
write32_x(DDR_PCTL + DDR_PCTL_SCTL_OFFSET, 0x00000001);
/* STAT : Wait for Switch INIT to Config State */
if (wait_for_completion(DDR_PCTL + DDR_PCTL_STAT_OFFSET, 0x00000001))
return DDR_TIMEOUT;
/* DFISTCFG0 : Drive various DFI signals appropriately
* 0 dfi_init_start 0
* 1 dfi_freq_ratio_en 1
* 2 dfi_data_byte_disable_en 1
*/
write32_x(DDR_PCTL + DDR_PCTL_DFISTCFG0_OFFSET, 0x00000003);
/* DFISTCFG1 : Enable various DFI support
* 0 dfi_dram_clk_disable_en 1
* 1 dfi_dram_clk_disable_en_pdp only lPDDR 0
*/
write32_x(DDR_PCTL + DDR_PCTL_DFISTCFG1_OFFSET, 0x00000001);
/* DFISTCFG2 : Enable Parity and asoc interrupt
* 0 dfi_parity_in Enable 1
* 1 Interrupt on dfi_parity_error 1
*/
write32_x(DDR_PCTL + DDR_PCTL_DFISTCFG2_OFFSET, 0x00000003);
/* DFILPCFG0 : DFI Low Power Interface Configuration
* 0 Enable DFI LP IF during PD 1
* 3:1 Reserved
* 7:4 DFI tlp_wakeup time 0
* 8 Enable DFI LP IF during SR 1
* 11:9 Reserved
* 15:12 dfi_lp_wakeup in SR 0
* 19:16 tlp_resp DFI 2.1 recomend 7
* 23:20 Reserved
* 24 Enable DFI LP in Deep Power Down 0
* 27:25 Reserved
* 31:28 DFI LP Deep Power Down Value 0
*/
write32_x(DDR_PCTL + DDR_PCTL_DFILPCFG0_OFFSET, 0x00070101);
/* DFIODTCFG : DFI ODT Configuration
* Only Enabled on Rank0 Writes
* 0 rank0_odt_read_nsel 0
* 1 rank0_odt_read_sel 0
* 2 rank0_odt_write_nsel 0
* 3 rank0_odt_write_sel 1
*/
write32_x(DDR_PCTL + DDR_PCTL_DFIODTCFG_OFFSET, 0x00000008);
/* DFIODTCFG1 : DFI ODT Configuration
* 4:0 odt_lat_w 4
* 12:8 odt_lat_r 0 Def
* 4:0 odt_len_bl8_w 6 Def
* 12:8 odt_len_bl8_r 6 Def
*/
write32_x(DDR_PCTL + DDR_PCTL_DFIODTCFG1_OFFSET, 0x06060004);
/* DCFG : DRAM Density 256 Mb 16 Bit IO Width
* 1:0 Devicw Width 1 x8, 2 x16, 3 x32 2
* 5:2 Density 2Gb = 5
* 6 Dram Type (MDDR/LPDDR2) Only 0
* 7 Reserved 0
* 10:8 Address Map R/B/C = 1
* 31:11 Reserved
*/
write32_x(DDR_PCTL + DDR_PCTL_DCFG_OFFSET, 0x00000116);
/* PCFG_0 : Port 0 AXI config */
if (BL8)
write32_x(DDR_PCTL + DDR_PCTL_PCFG0_OFFSET, 0x000800A0);
else
write32_x(DDR_PCTL + DDR_PCTL_PCFG0_OFFSET, 0x000400A0);
/* SCTL : UPCTL switch Config to ACCESS State */
write32_x(DDR_PCTL + DDR_PCTL_SCTL_OFFSET, 0x00000002);
/* STAT : Wait for switch CFG -> GO State */
if (wait_for_completion(DDR_PCTL + DDR_PCTL_STAT_OFFSET, 0x3))
return DDR_TIMEOUT;
return 0;
}

View File

@ -1,514 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2014 Imagination Technologies
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; version 2 of
* the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <stdint.h>
#include <device/mmio.h>
#include <soc/ddr_init.h>
#include <soc/ddr_private_reg.h>
/*
* Configuration for the Winbond W631GG6KB part using
* Synopsys DDR uMCTL and DDR Phy
*/
int init_ddr3(void)
{
uint32_t temp_rw_val;
temp_rw_val = read32_x(TOPLEVEL_REGS + DDR_CTRL_OFFSET);
/* Set CLK_EN = 1 */
temp_rw_val |= 0x2;
write32_x(TOPLEVEL_REGS + DDR_CTRL_OFFSET, temp_rw_val);
read32_x(TOPLEVEL_REGS + DDR_CTRL_OFFSET);
/*
* Reset the AXI bridge and DDR Controller in case any spurious
* writes have already happened to DDR
*/
/* Drive the 3 resets low */
write32_x(TOPLEVEL_REGS + DDR_CTRL_OFFSET, 0x00000002);
read32_x(TOPLEVEL_REGS + DDR_CTRL_OFFSET);
read32_x(TOPLEVEL_REGS + DDR_CTRL_OFFSET);
/* And release */
write32_x(TOPLEVEL_REGS + DDR_CTRL_OFFSET, 0x0000000F);
/* Dummy read to fence the access between the reset above and
* the DDR controller writes below
*/
read32_x(TOPLEVEL_REGS + DDR_CTRL_OFFSET);
/* Timings for 400MHz
* therefore 200MHz (5ns) uMCTL (Internal) Rate
*/
/* TOGCNT1U: Toggle Counter 1U Register: 1us 200h C8h */
write32_x(DDR_PCTL + DDR_PCTL_TOGCNT1U_OFFSET, 0x000000C8);
/* TINIT: t_init Timing Register: at least 200us 200h C8h */
write32_x(DDR_PCTL + DDR_PCTL_TINIT_OFFSET, 0x000000C8);
/* TRSTH: Reset High Time Register DDR3 ONLY */
write32_x(DDR_PCTL + DDR_PCTL_TRSTH_OFFSET, 0x000001F4);
/* TOGCNT100N: Toggle Counter 100N Register: 20d, 14h*/
write32_x(DDR_PCTL + DDR_PCTL_TOGG_CNTR_100NS_OFFSET, 0x00000014);
/* DTUAWDT DTU Address Width Register
* 1:0 column_addr_width Def 10 - 7 3 10 bits
* 4:3 bank_addr_width Def 3 - 2 1 3 bits (8 bank)
* 7:6 row_addr_width Def 14 - 13 1 3 bits
* 10:9 number_ranks Def 1 - 1 0 0 1 Rank
*/
write32_x(DDR_PCTL + DDR_PCTL_DTUAWDT_OFFSET, 0x0000004B);
/* MCFG
* 0 BL 1 -> 8 fixed
* 1 RDRIMM 0
* 2 BL8 Burst Terminate 0
* 3 2T = 0
* 4 Multi Rank 0
* 5 DDR3 En 1
* 6 LPDDR S4 En
* 7 BST En 0, 1 for LPDDR2/3
* 15:8 Power down Idle, passed by argument
* 16 Power Down Type, passed by argument
* 17 Power Down Exit 0 = slow, 1 = fast, pba
* 19:18 tFAW 45ns = 9 clk 5*2 -1 1h
* 21:20 mDDR/LPDDR2 BL 0
* 23:22 mDDR/LPDDR2 Enable 0
* 31:24 mDDR/LPDDR2/3 Dynamic Clock Stop 0
*/
write32_x(DDR_PCTL + DDR_PCTL_MCFG_OFFSET, 0x00060021);
/* MCFG1: Memory Configuration-1 Register
* c7:0 sr_idle Self Refresh Idle Entery 32 * nclks 14h, set 0 for BUB
* 10:8 Fine tune MCFG.19:18 -1
* 15:11 Reserved
* 23:16 Hardware Idle Period NA 0
* 30:24 Reserved
* 31 c_active_in_pin exit auto clk stop NA 0
*/
write32_x(DDR_PCTL + DDR_PCTL_MCFG1_OFFSET, 0x00000100);
/* DCR DRAM Config
* 2:0 SDRAM => DDR3 3
* 3 DDR 8 Bank 1
* 6:4 Primary DQ DDR3 Only 0
* 7 Multi-Purpose Register DDR3 Only 0
* 9:8 DDRTYPE LPDDR2 00
* 26:10 Reserved
* 27 NOSRA No Simultaneous Rank Access 0
* 28 DDR 2T 0
* 29 UDIMM NA 0
* 30 RDIMM NA 0
* 31 TPD LPDDR2 0
*/
write32_x(DDR_PHY + DDRPHY_DCR_OFFSET, 0x0000000B);
/* Generate to use with PHY and PCTL
* MR0 : DDR3 mode register 0
* 1:0 BL 8 fixed 00
* 3 BT Sequential 0 Interleaved 1 = 0
* 6:4,2 CL 6
* 7 TM Normal 0
* 8 DLL Reset 1 (self Clearing)
* 11:9 WR 15 ns 6 (010)
* 12 PD Slow 1 Fast 0 0
* 15:13 RSVD RSVD
* 31:16 Reserved
*/
write32_x(DDR_PHY + DDRPHY_MR_OFFSET, 0x00001520);
/* MR1 : DDR3 mode register 1
* Generate to use with PHY and PCTL
* 0 DE DLL Enable 0 Disable 1
* 5,1 DIC Output Driver RZQ/6
* 9,6,2 ODT RZQ/4
* 4:3 AL = 0
* 7 write leveling enabled 0
* 10 DQS 0 diff, 1 single = 0
* 11 TDQS NA 0
* 12 QOFF Normal mode 0
* 15:13 RSVD
* 31:16 Reserved
*/
write32_x(DDR_PHY + DDRPHY_EMR_OFFSET, 0x00000004);
/* MR2 : DDR3 mode register 2
* Generate to use with PHY and PCTL
* 2:0 PASR, NA 000
* 3 CWL 000 (5) tck = 22.5ns
* 6 auto self-refresh 1
* 7 SRT normal 0
* 8 RSVD
* 10:9 dynamic ODT 10 RZQ/2
* 31:11 Reserved
*/
write32_x(DDR_PHY + DDRPHY_EMR2_OFFSET, 0x00000440);
/* MR3: DDR3 mode register 3
* 1:0 MPRLOC 00
* 2 MPR 0
*/
write32_x(DDR_PHY + DDRPHY_EMR3_OFFSET, 0x00000000);
/* DTAR : Data Training Register
* 11:0 Data Training Column Address
* 27:12 Data Training Row Address
* 30:28 Data Training Bank Address
* 31 Data Training Use MPR (DDR3 Only)
*/
write32_x(DDR_PHY + DDRPHY_DTAR_OFFSET, 0x00000000);
/* DSGCR
* 0 PUREN Def 1
* 1 BDISEN Def 1
* 2 ZUEN Def 1
* 3 LPIOPD DEf 1 0
* 4 LPDLLPD DEf 1 0
* 7:5 DQSGX DQS Extention set to 1 - advised by Synopsys
* 10:8 DQSGE DQS Early Gate - 1 - advised by Sysnopsys
* 11 NOBUB No Bubbles, adds latency 1
* 12 FXDLAT Fixed Read Latency 0
* 15:13 Reserved
* 19:16 CKEPDD CKE Power Down 0000
* 23:20 ODTPDD ODT Power Down 0000
* 24 NL2PD Power Down Non LPDDR2 pins 0
* 25 NL2OE Output Enable Non LPDDR2 pins 1
* 26 TPDPD LPDDR Only 0
* 27 TPDOE LPDDR Only 1
* 28 CKOE Output Enable Clk's 1
* 29 ODTOE Output Enable ODT 1
* 30 RSTOE RST# Output Enable 1
* 31 CKEOE CKE Output Enable 1
*/
write32_x(DDR_PHY + DDRPHY_DSGCR_OFFSET, 0xFA000927);
/* Sysnopsys advised 500R pullup/pulldown DQS DQSN */
write32_x(DDR_PHY + DDRPHY_DXCCR_OFFSET, 0x00000C40);
/* DTPR0 : DRAM Timing Params 0
* 1:0 tMRD 0
* 4:2 tRTP 2
* 7:5 tWTR 4
* 11:8 tRP 6
* 15:12 tRCD 6
* 20:16 tRAS 15
* 24:21 tRRD 4 for x16
* 30:25 tRC 21
* 31 tCCD 0 BL/2 Cas to Cas
*/
write32_x(DDR_PHY + DDRPHY_DTPR0_OFFSET, 0x2A8F6688);
/* DTPR1 : DRAM Timing Params 1
* 1:0 ODT On/Off Del Std 0
* 2 tRTW Rd2Wr Del 0 std 1 +1 0
* 8:3 tFAW 20 Clk
* 10:9 tMOD DDR3 Only 15
* 11 tRTODT DDR3 Only 0
* 15:12 Reserved
* 23:16 tRFC 160ns 64 ref 131
* 26:24 tDQSCK LPDDR2 only 1
* 29:27 tDQSCKmax 1
* 31:30 Reserved
*/
write32_x(DDR_PHY + DDRPHY_DTPR1_OFFSET, 0x094006A0);
/* DTPR2 : DRAM Timing Params 2
* 9:0 tXS exit SR def 512d
* 14:10 tXP PD Exit Del 8 5
* 18:15 tCKE CKE Min pulse 5
* 28:19 tDLLK DLL Lock time 512d
* 32:29 Reserved
*/
write32_x(DDR_PHY + DDRPHY_DTPR2_OFFSET, 0x10029600);
/* PTR0 : PHY Timing Params 0
* 5:0 tDLLRST Def 27
* 17:6 tDLLLOCK Def 2750
* 21:18 tITMSRST Def 8
* 31:22 Reserved 0
*/
write32_x(DDR_PHY + DDRPHY_PTR0_OFFSET, 0x0022AF9B);
/* PTR1 : PHY Timing Params 1
* 18:0 : tDINITO DRAM Init time 500us 200,000 Dec 0x30D40
* 29:19 : tDINIT1 DRAM Init time tRFC + 10ns 68
*/
write32_x(DDR_PHY + DDRPHY_PTR1_OFFSET, 0x02230D40);
/* DQS gating configuration: passive windowing mode */
/*
* PGCR: PHY General cofiguration register
* 0 ITM DDR mode: 0
* 1 DQS gading configuration: passive windowing 1
* 2 DQS drift compensation: not supported in passive windowing 0
* 4:3 DQS drift limit 0
* 8:5 Digital test output select 0
* 11:9 CK Enable: one bit for each 3 CK pair: 0x7
* 13:12 CK Disable values: 0x2
* 14 CK Invert 0
* 15 IO loopback 0
* 17:16 I/O DDR mode 0
* 21:18 Ranks enable by training: 0xF
* 23:22 Impedance clock divider select 0x2
* 24 Power down disable 1
* 28:25 Refresh during training 0
* 29 loopback DQS shift 0
* 30 loopback DQS gating 0
* 31 loopback mode 0
*/
write32_x(DDR_PHY + DDRPHY_PGCR_OFFSET, 0x01BC2E02);
/* PGSR : Wait for INIT/DLL/Z Done from Power on Reset */
if (wait_for_completion(DDR_PHY + DDRPHY_PGSR_OFFSET, 0x00000007))
return DDR_TIMEOUT;
/* PIR : PHY controlled init */
write32_x(DDR_PHY + DDRPHY_PIR_OFFSET, 0x0000001F);
/* PGSR : Wait for DRAM Init Done */
if (wait_for_completion(DDR_PHY + DDRPHY_PGSR_OFFSET, 0x00000007))
return DDR_TIMEOUT;
/* PIR : controller DRAM initialization */
write32_x(DDR_PHY + DDRPHY_PIR_OFFSET, 0x00040001);
/* PGSR : Wait for DRAM Init Done */
if (wait_for_completion(DDR_PHY + DDRPHY_PGSR_OFFSET, 0x0000000F))
return DDR_TIMEOUT;
/********************************************************************/
/* DF1STAT0 : wait for DFI_INIT_COMPLETE */
if (wait_for_completion(DDR_PCTL + DDR_PCTL_DFISTAT0_OFFSET,
0x00000001))
return DDR_TIMEOUT;
/* POWCTL : Start the memory Power Up seq*/
write32_x(DDR_PCTL + DDR_PCTL_POWCTL_OFFSET, 0x80000001);
/* POWSTAT : wait for POWER_UP_DONE */
if (wait_for_completion(DDR_PCTL + DDR_PCTL_POWSTAT_OFFSET,
0x00000001))
return DDR_TIMEOUT;
/*
* TREFI : t_refi Timing Register 1X
* 12:0 t_refi 7.8us in 100ns 0x4E
* 15:13 Reserved 0
* 18:16 num_add_ref 0
* 30:19 Reserved 0
* 31 Update 1
*/
write32_x(DDR_PCTL + DDR_PCTL_TREFI_OFFSET, 0x8000004E);
/* TMRD : t_mrd Timing Register -- Range 2 to 4*/
write32_x(DDR_PCTL + DDR_PCTL_TMRD_OFFSET, 0x00000004);
/*
* TRFC : t_rfc Timing Register -- Range 15 to 131
* 195ns / 2.5ns 78 x4E
*/
write32_x(DDR_PCTL + DDR_PCTL_TRFC_OFFSET, 0x0000004E);
/* TRP : t_rp Timing Register -- Range 3 to 7
* 4:0 tRP 12.5 / 2.5 = 5 6 For Now 6-6-6
* 17:16 rpea_extra DDR3 - value 0
*/
write32_x(DDR_PCTL + DDR_PCTL_TRP_OFFSET, 0x00000006);
/* TAL : Additive Latency Register -- AL in MR1 */
write32_x(DDR_PCTL + DDR_PCTL_TAL_OFFSET, 0x00000000);
/* TCL : CAS Latency Timing Register -- CASL in MR0 6-6-6 */
write32_x(DDR_PCTL + DDR_PCTL_TCL_OFFSET, 0x00000006);
/* TCWL : CAS Write Latency Register --CASL-1 */
write32_x(DDR_PCTL + DDR_PCTL_TCWL_OFFSET, 0x00000005);
/* TRAS : Activate to Precharge cmd time 15 45ns / 2.5ns = 18d */
write32_x(DDR_PCTL + DDR_PCTL_TRAS_OFFSET, 0x0000000F);
/* TRC : Min. ROW cycle time 21
* 57.5ns / 2.5ns = 23d Playing safe 24
*/
write32_x(DDR_PCTL + DDR_PCTL_TRC_OFFSET, 0x00000015);
/* TRCD : Row to Column Delay # Range 3 to 7 (TCL = TRCD)
* 12.5ns / 2.5ns = 5 but running 6-6-6 6
*/
write32_x(DDR_PCTL + DDR_PCTL_TRCD_OFFSET, 0x00000006);
/* TRRD : Row to Row delay -- Range 2 to 6
* 2K Page 10ns / 2.5ns = 4
*/
write32_x(DDR_PCTL + DDR_PCTL_TRRD_OFFSET, 0x00000004);
/* TRTP : Read to Precharge time -- Range 2 to 4
* Largest 4 or 7.5ns / 2.5ns = 4
*/
write32_x(DDR_PCTL + DDR_PCTL_TRTP_OFFSET, 0x00000004);
/* TWR : Write recovery time -- WR in MR0: 15ns / 2.5ns = 6 */
write32_x(DDR_PCTL + DDR_PCTL_TWR_OFFSET, 0x00000006);
/* TWTR : Write to read turn around time -- Range 2 to 4
* Largest 4 or 7.5ns / 2.5ns = 4
*/
write32_x(DDR_PCTL + DDR_PCTL_TWTR_OFFSET, 0x00000004);
/* TEXSR : Exit Self Refresh to first valid cmd: tXS 512 */
write32_x(DDR_PCTL + DDR_PCTL_TEXSR_OFFSET, 0x00000200);
/* TXP : Exit Power Down to first valid cmd
* tXP 2, Settingto 3 to match PHY
*/
write32_x(DDR_PCTL + DDR_PCTL_TXP_OFFSET, 0x00000003);
/* TDQS : t_dqs Timing Register
* DQS additional turn around Rank 2 Rank (1 Rank) Def 1
*/
write32_x(DDR_PCTL + DDR_PCTL_TDQS_OFFSET, 0x00000001);
/* TRTW : Read to Write turn around time Def 3
* Actual gap t_bl + t_rtw
*/
write32_x(DDR_PCTL + DDR_PCTL_TRTW_OFFSET, 0x00000003);
/* TCKE : CKE min pulse width DEf 3 */
write32_x(DDR_PCTL + DDR_PCTL_TCKE_OFFSET, 0x00000003);
/* TXPDLL : Slow Exit Power Down to first valid cmd delay
* tXARDS 10+AL = 10
*/
write32_x(DDR_PCTL + DDR_PCTL_TXPDLL_OFFSET, 0x0000000A);
/* TCKESR : Min CKE Low width for Self refresh entry to exit
* t_ckesr = 0 DDR2
*/
write32_x(DDR_PCTL + DDR_PCTL_TCKESR_OFFSET, 0x00000004);
/* TMOD : MRS to any Non-MRS command -- Range 0 to 31 */
write32_x(DDR_PCTL + DDR_PCTL_TMOD_OFFSET, 0x0000000F);
/* TZQCS : SDRAM ZQ Calibration Short Period */
write32_x(DDR_PCTL + DDR_PCTL_TZQCS_OFFSET, 0x00000040);
/* TZQCL : SDRAM ZQ Calibration Long Period */
write32_x(DDR_PCTL + DDR_PCTL_TZQCL_OFFSET, 0x00000200);
/* SCFG : State Configuration Register (Enabling Self Refresh)
* 0 LP_en Leave Off for Bring Up 0
* 5:1 Reserved
* 6 Synopsys Internal Only 0
* 7 Enale PHY indication of LP Opportunity 1
* 11:8 bbflags_timing max UPCTL_TCU_SED_P - tRP (16 - 6) Use 4
* 16:12 Additional delay on accertion of ac_pdd 4
* 31:17 Reserved
*/
write32_x(DDR_PCTL + DDR_PCTL_SCFG_OFFSET, 0x00004480);
/* TREFI_MEM_DDR3 */
write32_x(DDR_PCTL + DDR_PCTL_TREFI_MEM_DDR3_OFFSET, 0x00000C30);
/* DFITPHYWRLAT : Write cmd to dfi_wrdata_en */
write32_x(DDR_PCTL + DDR_PCTL_DFIWRLAT_OFFSET, 0x00000002);
/* DFITRDDATAEN : Read cmd to dfi_rddata_en */
write32_x(DDR_PCTL + DDR_PCTL_DFITRDDATAEN_OFFSET, 0x00000002);
/*
* DFITPHYWRDATA : dfi_wrdata_en to drive wr data
* DFI Clks wrdata_en to wrdata Def 1
*/
write32_x(DDR_PCTL + DDR_PCTL_DFITPHYWRDATA_OFFSET, 0x00000000);
/*
* DFITPHYRDLAT : dfi_rddata_en to dfi_rddata_valid
* DFI clks max rddata_en to rddata_valid Def 15
*/
write32_x(DDR_PCTL + DDR_PCTL_DFITPHYRDLAT_OFFSET, 0x00000008);
/* DFISTCFG0 : Drive various DFI signals appropriately
* 0 dfi_init_start 1
* 1 dfi_freq_ratio_en 1
* 2 dfi_data_byte_disable_en 1
*/
write32_x(DDR_PCTL + DDR_PCTL_DFISTCFG0_OFFSET, 0x00000007);
/* DFISTCFG1 : Enable various DFI support
* 0 dfi_dram_clk_disable_en 1
* 1 dfi_dram_clk_disable_en_pdp only lPDDR 0
*/
write32_x(DDR_PCTL + DDR_PCTL_DFISTCFG1_OFFSET, 0x00000001);
/* DFISTCFG2 : Enable Parity and asoc interrupt
* 0 dfi_parity_in Enable 1
* 1 Interrupt on dfi_parity_error 1
*/
write32_x(DDR_PCTL + DDR_PCTL_DFISTCFG2_OFFSET, 0x00000003);
/* DFILPCFG0 : DFI Low Power Interface Configuration
* 0 Enable DFI LP IF during PD 1
* 3:1 Reserved
* 7:4 DFI tlp_wakeup time 0
* 8 Enable DFI LP IF during SR 1
* 11:9 Reserved
* 15:12 dfi_lp_wakeup in SR 0
* 19:16 tlp_resp DFI 2.1 recomend 7
* 23:20 Reserved
* 24 Enable DFI LP in Deep Power Down 0
* 27:25 Reserved
* 31:28 DFI LP Deep Power Down Value 0
*/
write32_x(DDR_PCTL + DDR_PCTL_DFILPCFG0_OFFSET, 0x00070101);
/* DFIODTCFG : DFI ODT Configuration
* Only Enabled on Rank0 Writes
* 0 rank0_odt_read_nsel 0
* 1 rank0_odt_read_sel 0
* 2 rank0_odt_write_nsel 0
* 3 rank0_odt_write_sel 1
*/
write32_x(DDR_PCTL + DDR_PCTL_DFIODTCFG_OFFSET, 0x00000008);
/* DFIODTCFG1 : DFI ODT Configuration
* 4:0 odt_lat_w 0
* 12:8 odt_lat_r 0 Def
* 4:0 odt_len_bl8_w 6 Def
* 12:8 odt_len_bl8_r 6 Def
*/
write32_x(DDR_PCTL + DDR_PCTL_DFIODTCFG1_OFFSET, 0x060600000);
/* Memory initialization */
/* MCMD : PREA, Addr 0 Bank 0 Rank 0 Del 0
* 3:0 cmd_opcode PREA 00001
* 16:4 cmd_addr 0
* 19:17 bank_addr 0
* 23:20 rank_sel 0 0001
* 27:24 cmddelay 0
* 30:24 Reserved
*/
/* MCMD: MR2 */
write32_x(DDR_PCTL + DDR_PCTL_MCMD_OFFSET, 0x80004403);
/* MRS cmd wait for completion */
if (wait_for_completion(DDR_PCTL + DDR_PCTL_MCMD_OFFSET, 0x00004403))
return DDR_TIMEOUT;
/* MCMD: MR3 */
write32_x(DDR_PCTL + DDR_PCTL_MCMD_OFFSET, 0x80000003);
/* MRS cmd wait for completion */
if (wait_for_completion(DDR_PCTL + DDR_PCTL_MCMD_OFFSET, 0x00000003))
return DDR_TIMEOUT;
/* MCMD: MR1 */
write32_x(DDR_PCTL + DDR_PCTL_MCMD_OFFSET, 0x80000043);
/* MRS cmd wait for completion */
if (wait_for_completion(DDR_PCTL + DDR_PCTL_MCMD_OFFSET, 0x00000043))
return DDR_TIMEOUT;
/* MCMD: MR0 */
write32_x(DDR_PCTL + DDR_PCTL_MCMD_OFFSET, 0x80015203);
/* MRS cmd wait for completion */
if (wait_for_completion(DDR_PCTL + DDR_PCTL_MCMD_OFFSET, 0x00015203))
return DDR_TIMEOUT;
/* MCMD: ZQS cmd, long 5 short 4 */
write32_x(DDR_PCTL + DDR_PCTL_MCMD_OFFSET, 0x80104005);
/* MRS cmd wait for completion */
if (wait_for_completion(DDR_PCTL + DDR_PCTL_MCMD_OFFSET, 0x00104005))
return DDR_TIMEOUT;
/* MCMD: deselect command */
write32_x(DDR_PCTL + DDR_PCTL_MCMD_OFFSET, 0x80100000);
/* MRS cmd wait for completion */
if (wait_for_completion(DDR_PCTL + DDR_PCTL_MCMD_OFFSET, 0x00100000))
return DDR_TIMEOUT;
/* MCMD: deselect command */
write32_x(DDR_PCTL + DDR_PCTL_MCMD_OFFSET, 0x8010000A);
/* MRS cmd wait for completion */
if (wait_for_completion(DDR_PCTL + DDR_PCTL_MCMD_OFFSET, 0x0010000A))
return DDR_TIMEOUT;
/* DCFG : DRAM Density 256 Mb 16 Bit IO Width
* 1:0 Devicw Width 1 x8, 2 x16, 3 x32 2
* 5:2 Density 2Gb = 5
* 6 Dram Type (MDDR/LPDDR2) Only 0
* 7 Reserved 0
* 10:8 Address Map R/B/C = 1
* 31:11 Reserved
*/
write32_x(DDR_PCTL + DDR_PCTL_DCFG_OFFSET, 0x00000116);
/* PCFG_0 : Port 0 AXI config */
write32_x(DDR_PCTL + DDR_PCTL_PCFG0_OFFSET, 0x000800A0);
/* SCTL : UPCTL switch INIT CONFIG State */
write32_x(DDR_PCTL + DDR_PCTL_SCTL_OFFSET, 0x00000001);
/* STAT : Wait for Switch INIT to Config State */
if (wait_for_completion(DDR_PCTL + DDR_PCTL_STAT_OFFSET, 0x00000001))
return DDR_TIMEOUT;
/* STAT : Wait for Switch INIT to Config State */
write32_x(DDR_PCTL + DDR_PCTL_CMDTSTATEN_OFFSET, 0x00000001);
/* STAT : Wait for Switch INIT to Config State */
if (wait_for_completion(DDR_PCTL + DDR_PCTL_CMDTSTAT_OFFSET,
0x00000001))
return DDR_TIMEOUT;
/* Use PHY for DRAM init */
write32_x(DDR_PHY + DDRPHY_PIR_OFFSET, 0x00000181);
/* STAT : Wait for Switch INIT to Config State */
if (wait_for_completion(DDR_PHY + DDRPHY_PGSR_OFFSET, 0x00000001F))
return DDR_TIMEOUT;
/* Disable Impedance Calibration */
write32_x(DDR_PHY + DDRPHY_ZQ0CR0_OFFSET, 0x3000014A);
write32_x(DDR_PHY + DDRPHY_ZQ1CR0_OFFSET, 0x3000014A);
/* SCTL : UPCTL switch Config to ACCESS State */
write32_x(DDR_PCTL + DDR_PCTL_SCTL_OFFSET, 0x00000002);
/* STAT : Wait for switch CFG -> GO State */
if (wait_for_completion(DDR_PCTL + DDR_PCTL_STAT_OFFSET, 0x3))
return DDR_TIMEOUT;
return 0;
}

View File

@ -1,43 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2014 Imagination Technologies
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; version 2 of
* the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __SOC_IMGTEC_PISTACHIO_CLOCKS_H__
#define __SOC_IMGTEC_PISTACHIO_CLOCKS_H__
#include <stdint.h>
/* Functions for PLL setting */
int sys_pll_setup(u8 divider1, u8 divider2, u8 predivider, u32 feedback);
int mips_pll_setup(u8 divider1, u8 divider2, u8 predivider, u32 feedback);
/* Peripheral divider setting */
void system_clk_setup(u8 divider);
void mips_clk_setup(u8 divider1, u8 divider2);
void uart1_clk_setup(u8 divider1, u16 divider2);
void i2c_clk_setup(u8 divider1, u16 divider2, u8 interface);
int usb_clk_setup(u8 divider, u8 refclksel, u8 fsel);
void rom_clk_setup(u8 divider);
void eth_clk_setup(u8 mux, u8 divider);
void setup_clk_gate_defaults(void);
enum {
CLOCKS_OK = 0,
PLL_TIMEOUT = -1,
USB_TIMEOUT = -2,
USB_VBUS_FAULT = -3
};
#endif

View File

@ -1,35 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2014 Imagination Technologies
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; version 2 of
* the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __SOC_IMGTEC_DANUBE_CPU_H__
#define __SOC_IMGTEC_DANUBE_CPU_H__
#include <device/mmio.h>
#define IMG_SPIM0_BASE_ADDRESS 0xB8100F00
#define IMG_SPIM1_BASE_ADDRESS 0xB8101000
/*
* This register holds the FPGA image version
* If we're not working on the FPGA this will be 0
*/
#define PRIMARY_FPGA_VERSION 0xB8149060
#define IMG_PLATFORM_ID() read32_x(PRIMARY_FPGA_VERSION)
#define IMG_PLATFORM_ID_FPGA 0xD1400003 /* Last FPGA image */
#define IMG_PLATFORM_ID_SILICON 0
#endif

View File

@ -1,26 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2014 Imagination Technologies
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; version 2 of
* the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __SOC_IMGTEC_PISTACHIO_DDR_INIT_H__
#define __SOC_IMGTEC_PISTACHIO_DDR_INIT_H__
#define DDR_TIMEOUT -1
int init_ddr2(void);
int init_ddr3(void);
#endif

View File

@ -1,142 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2014 Imagination Technologies
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; version 2 of
* the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __SOC_IMGTEC_PISTACHIO_DDR_PRIVATE_REG_H__
#define __SOC_IMGTEC_PISTACHIO_DDR_PRIVATE_REG_H__
#include <device/mmio.h>
#include <timer.h>
#define MAX_WAIT_MICROS 100000
#define TOPLEVEL_REGS 0xB8149000
#define DDR_CTRL_OFFSET (0x0020)
#define DDR_CLK_EN_MASK (0x00000002)
#define DDR_CLK_EN_SHIFT (1)
#define DDR_CLK_EN_LENGTH (1)
#define DDR_PCTL 0xB8180000
#define DDR_PCTL_SCFG_OFFSET (0x0000)
#define DDR_PCTL_SCTL_OFFSET (0x0004)
#define DDR_PCTL_STAT_OFFSET (0x0008)
#define DDR_PCTL_MCMD_OFFSET (0x0040)
#define DDR_PCTL_POWCTL_OFFSET (0x0044)
#define DDR_PCTL_POWSTAT_OFFSET (0x0048)
#define DDR_PCTL_CMDTSTAT_OFFSET (0x004C)
#define DDR_PCTL_CMDTSTATEN_OFFSET (0x0050)
#define DDR_PCTL_MCFG1_OFFSET (0x007C)
#define DDR_PCTL_MCFG_OFFSET (0x0080)
#define DDR_PCTL_MSTAT_OFFSET (0x0088)
#define DDR_PCTL_DTUAWDT_OFFSET (0x00B0)
#define DDR_PCTL_TOGCNT1U_OFFSET (0x00C0)
#define DDR_PCTL_TINIT_OFFSET (0x00C4)
#define DDR_PCTL_TRSTH_OFFSET (0x00C8)
#define DDR_PCTL_TOGG_CNTR_100NS_OFFSET (0x00CC)
#define DDR_PCTL_TREFI_OFFSET (0x00D0)
#define DDR_PCTL_TMRD_OFFSET (0x00D4)
#define DDR_PCTL_TRFC_OFFSET (0x00D8)
#define DDR_PCTL_TRP_OFFSET (0x00DC)
#define DDR_PCTL_TRTW_OFFSET (0x00E0)
#define DDR_PCTL_TAL_OFFSET (0x00E4)
#define DDR_PCTL_TCL_OFFSET (0x00E8)
#define DDR_PCTL_TCWL_OFFSET (0x00EC)
#define DDR_PCTL_TRAS_OFFSET (0x00F0)
#define DDR_PCTL_TRC_OFFSET (0x00F4)
#define DDR_PCTL_TRCD_OFFSET (0x00F8)
#define DDR_PCTL_TRRD_OFFSET (0x00FC)
#define DDR_PCTL_TRTP_OFFSET (0x0100)
#define DDR_PCTL_TWR_OFFSET (0x0104)
#define DDR_PCTL_TWTR_OFFSET (0x0108)
#define DDR_PCTL_TEXSR_OFFSET (0x010C)
#define DDR_PCTL_TXP_OFFSET (0x0110)
#define DDR_PCTL_TXPDLL_OFFSET (0x0114)
#define DDR_PCTL_TZQCS_OFFSET (0x0118)
#define DDR_PCTL_TDQS_OFFSET (0x0120)
#define DDR_PCTL_TCKE_OFFSET (0x012C)
#define DDR_PCTL_TMOD_OFFSET (0x0130)
#define DDR_PCTL_TZQCL_OFFSET (0x0138)
#define DDR_PCTL_TCKESR_OFFSET (0x0140)
#define DDR_PCTL_TREFI_MEM_DDR3_OFFSET (0x0148)
#define DDR_PCTL_DTUWACTL_OFFSET (0x0200)
#define DDR_PCTL_DTURACTL_OFFSET (0x0204)
#define DDR_PCTL_DTUCFG_OFFSET (0x0208)
#define DDR_PCTL_DTUECTL_OFFSET (0x020C)
#define DDR_PCTL_DTUWD0_OFFSET (0x0210)
#define DDR_PCTL_DTUWD1_OFFSET (0x0214)
#define DDR_PCTL_DTUWD2_OFFSET (0x0218)
#define DDR_PCTL_DTUWD3_OFFSET (0x021C)
#define DDR_PCTL_DFIODTCFG_OFFSET (0x0244)
#define DDR_PCTL_DFIODTCFG1_OFFSET (0x0248)
#define DDR_PCTL_DFITPHYWRDATA_OFFSET (0x0250)
#define DDR_PCTL_DFIWRLAT_OFFSET (0x0254)
#define DDR_PCTL_DFITRDDATAEN_OFFSET (0x0260)
#define DDR_PCTL_DFITPHYRDLAT_OFFSET (0x0264)
#define DDR_PCTL_DFIUPDCFG_OFFSET (0x0290)
#define DDR_PCTL_DFISTAT0_OFFSET (0x02C0)
#define DDR_PCTL_DFISTCFG0_OFFSET (0x02C4)
#define DDR_PCTL_DFISTCFG1_OFFSET (0x02C8)
#define DDR_PCTL_DFISTCFG2_OFFSET (0x02D8)
#define DDR_PCTL_DFILPCFG0_OFFSET (0x02F0)
#define DDR_PCTL_PCFG0_OFFSET (0x0400)
#define DDR_PCTL_CCFG_OFFSET (0x0480)
#define DDR_PCTL_DCFG_OFFSET (0x0484)
#define DDR_PCTL_CCFG1_OFFSET (0x048C)
#define DDR_PHY 0xB8180800
#define DDRPHY_PIR_OFFSET (0x0004)
#define DDRPHY_PGCR_OFFSET (0x0008)
#define DDRPHY_PGSR_OFFSET (0x000C)
#define DDRPHY_DLLGCR_OFFSET (0x0010)
#define DDRPHY_PTR0_OFFSET (0x0018)
#define DDRPHY_PTR1_OFFSET (0x001C)
#define DDRPHY_DXCCR_OFFSET (0x0028)
#define DDRPHY_DSGCR_OFFSET (0x002C)
#define DDRPHY_DCR_OFFSET (0x0030)
#define DDRPHY_DTPR0_OFFSET (0x0034)
#define DDRPHY_DTPR1_OFFSET (0x0038)
#define DDRPHY_DTPR2_OFFSET (0x003C)
#define DDRPHY_MR_OFFSET (0x0040)
#define DDRPHY_EMR_OFFSET (0x0044)
#define DDRPHY_EMR2_OFFSET (0x0048)
#define DDRPHY_EMR3_OFFSET (0x004C)
#define DDRPHY_DTAR_OFFSET (0x0054)
#define DDRPHY_BISTRR_OFFSET (0x0100)
#define DDRPHY_BISTWCR_OFFSET (0x010C)
#define DDRPHY_BISTAR0_OFFSET (0x0114)
#define DDRPHY_BISTAR1_OFFSET (0x0118)
#define DDRPHY_BISTAR2_OFFSET (0x011C)
#define DDRPHY_BISTUDPR_OFFSET (0x0120)
#define DDRPHY_BISTGSR_OFFSET (0x0124)
#define DDRPHY_ZQ0CR0_OFFSET (0x0180)
#define DDRPHY_ZQ1CR0_OFFSET (0x0190)
#define DDR_TIMEOUT_VALUE_US 100000
static int wait_for_completion(u32 reg, u32 exp_val)
{
struct stopwatch sw;
stopwatch_init_usecs_expire(&sw, DDR_TIMEOUT_VALUE_US);
while (read32_x(reg) != exp_val) {
if (stopwatch_expired(&sw))
return DDR_TIMEOUT;
}
return 0;
}
#endif

View File

@ -1,21 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright 2014 Google Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __SOC_IMGTECH_PISTACHIO_GPIO_H__
#define __SOC_IMGTECH_PISTACHIO_GPIO_H__
typedef unsigned int gpio_t;
#endif // __SOC_IMGTECH_PISTACHIO_GPIO_H__

View File

@ -1,70 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright 2014 Google Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <memlayout.h>
#include <arch/header.ld>
/* SRAM memory is mapped in two different locations. Define regions in both for
* full overlap checking and use this to guarantee they're kept in sync. */
#define ASSERT_MIRRORED(r1, r2) \
_ = ASSERT((_e##r1 - _##r1) == (_e##r2 - _##r2) && \
(_##r1 & 0x7fffffff) == (_##r2 & 0x7fffffff), \
STR(r1 and r2 do not match!));
SECTIONS
{
/*
* All of DRAM (other than the DMA coherent area) is accessed through
* the identity mapping.
*/
DRAM_START(0x00000000)
/* DMA coherent area: accessed via KSEG1. */
DMA_COHERENT(0x00100000, 1M)
POSTRAM_CBFS_CACHE(0x00200000, 512K)
RAMSTAGE(0x00280000, 128K)
/* 0x18100000 -> 0x18540000 */
SOC_REGISTERS(0x18100000, 0x440000)
/*
* GRAM becomes the SRAM. Accessed through KSEG0 in the bootblock
* and then through the identity mapping in ROM stage.
*/
SRAM_START(0x1a000000)
REGION(gram_bootblock, 0x1a000000, 28K, 1)
ROMSTAGE(0x1a007000, 60K)
VBOOT2_WORK(0x1a016000, 12K)
VBOOT2_TPM_LOG(0x1a019000, 2K)
PRERAM_CBFS_CACHE(0x1a019800, 46K)
SRAM_END(0x1a066000)
/* Bootblock executes out of KSEG0 and sets up the identity mapping.
* This is identical to SRAM above, and thus also limited 64K and
* needs to avoid conflicts with items set up above.
*/
BOOTBLOCK(0x9a000000, 28K)
REGION(kseg0_romstage, 0x9a007000, 60K, 1)
/*
* Let's use SRAM for stack and CBMEM console. Always accessed
* through KSEG0.
*/
STACK(0x9b000000, 8K)
PRERAM_CBMEM_CONSOLE(0x9b002000, 8K)
}
ASSERT_MIRRORED(bootblock, gram_bootblock)
ASSERT_MIRRORED(romstage, kseg0_romstage)

View File

@ -1,357 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2014 Imagination Technologies
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __SOC_IMGTEC_DANUBE_SPI_H__
#define __SOC_IMGTEC_DANUBE_SPI_H__
#include <arch/types.h>
#define spi_read_reg_field(regval, field) \
( \
((field##_MASK) == 0xFFFFFFFF) ? \
(regval) : \
(((regval) & (field##_MASK)) >> (field##_SHIFT))\
)
#define spi_write_reg_field(regval, field, val) \
( \
((field##_MASK) == 0xFFFFFFFF) ? \
(val) : \
(((regval) & ~(field##_MASK)) | \
(((val) << (field##_SHIFT)) & (field##_MASK))) \
)
/*
* Parameter register
* Each of these corresponds to a single port (ie CS line) in the interface
* Fields Name Description
* ====== ==== ===========
* b31:24 CLK_RATE Bit Clock rate = (24.576 * value / 512) MHz
* b23:16 CS_SETUP Chip Select setup = (40 * value) ns
* b15:8 CS_HOLD Chip Select hold = (40 * value) ns
* b7:0 CS_DELAY Chip Select delay = (40 * value) ns
*/
#define SPIM_CLK_DIVIDE_MASK (0xFF000000)
#define SPIM_CS_SETUP_MASK (0x00FF0000)
#define SPIM_CS_HOLD_MASK (0x0000FF00)
#define SPIM_CS_DELAY_MASK (0x000000FF)
#define SPIM_CS_PARAM_MASK (SPIM_CS_SETUP_MASK \
| SPIM_CS_HOLD_MASK \
| SPIM_CS_DELAY_MASK)
#define SPIM_CLK_DIVIDE_SHIFT (24)
#define SPIM_CS_SETUP_SHIFT (16)
#define SPIM_CS_HOLD_SHIFT (8)
#define SPIM_CS_DELAY_SHIFT (0)
#define SPIM_CS_PARAM_SHIFT (0)
/* Control register */
#define SPFI_DRIBBLE_COUNT_MASK (0x000e0000)
#define SPFI_MEMORY_IF_MASK (0x00008000)
#define SPIM_BYTE_DELAY_MASK (0x00004000)
#define SPIM_CS_DEASSERT_MASK (0x00002000)
#define SPIM_CONTINUE_MASK (0x00001000)
#define SPIM_SOFT_RESET_MASK (0x00000800)
#define SPIM_SEND_DMA_MASK (0x00000400)
#define SPIM_GET_DMA_MASK (0x00000200)
#define SPIM_EDGE_TX_RX_MASK (0x00000100)
#define SPFI_TRNSFR_MODE_MASK (0x000000e0)
#define SPFI_TRNSFR_MODE_DQ_MASK (0x0000001c)
#define SPFI_TX_RX_MASK (0x00000002)
#define SPFI_EN_MASK (0x00000001)
#define SPFI_DRIBBLE_COUNT_SHIFT (17)
#define SPFI_MEMORY_IF_SHIFT (15)
#define SPIM_BYTE_DELAY_SHIFT (14)
#define SPIM_CS_DEASSERT_SHIFT (13)
#define SPIM_CONTINUE_SHIFT (12)
#define SPIM_SOFT_RESET_SHIFT (11)
#define SPIM_SEND_DMA_SHIFT (10)
#define SPIM_GET_DMA_SHIFT (9)
#define SPIM_EDGE_TX_RX_SHIFT (8)
#define SPFI_TRNSFR_MODE_SHIFT (5)
#define SPFI_TRNSFR_MODE_DQ_SHIFT (2)
#define SPFI_TX_RX_SHIFT (1)
#define SPFI_EN_SHIFT (0)
/* Transaction register */
#define SPFI_TSIZE_MASK (0xffff0000)
#define SPFI_CMD_LENGTH_MASK (0x0000e000)
#define SPFI_ADDR_LENGTH_MASK (0x00001c00)
#define SPFI_DUMMY_LENGTH_MASK (0x000003e0)
#define SPFI_PI_LENGTH_MASK (0x0000001c)
#define SPFI_TSIZE_SHIFT (16)
#define SPFI_CMD_LENGTH_SHIFT (13)
#define SPFI_ADDR_LENGTH_SHIFT (10)
#define SPFI_DUMMY_LENGTH_SHIFT (5)
#define SPFI_PI_LENGTH_SHIFT (2)
/* Port state register */
#define SPFI_PORT_SELECT_MASK (0x00700000)
/* WARNING the following bits are reversed */
#define SPFI_CLOCK0_IDLE_MASK (0x000f8000)
#define SPFI_CLOCK0_PHASE_MASK (0x00007c00)
#define SPFI_CS0_IDLE_MASK (0x000003e0)
#define SPFI_DATA0_IDLE_MASK (0x0000001f)
#define SPIM_CLOCK0_IDLE_MASK (0x000f8000)
#define SPIM_CLOCK0_PHASE_MASK (0x00007c00)
#define SPIM_CS0_IDLE_MASK (0x000003e0)
#define SPIM_DATA0_IDLE_MASK (0x0000001f)
#define SPIM_PORT0_MASK (0x00084210)
#define SPFI_PORT_SELECT_SHIFT (20)
/* WARNING the following bits are reversed, bit 0 is highest */
#define SPFI_CLOCK0_IDLE_SHIFT (19)
#define SPFI_CLOCK0_PHASE_SHIFT (14)
#define SPFI_CS0_IDLE_SHIFT (9)
#define SPFI_DATA0_IDLE_SHIFT (4)
#define SPIM_CLOCK0_IDLE_SHIFT (19)
#define SPIM_CLOCK0_PHASE_SHIFT (14)
#define SPIM_CS0_IDLE_SHIFT (9)
#define SPIM_DATA0_IDLE_SHIFT (4)
/*
* Interrupt registers
* SPFI_GDOF_MASK means Rx buffer full, not an overflow, because clock stalls
* SPFI_SDUF_MASK means Tx buffer empty, not an underflow, because clock stalls
*/
#define SPFI_IACCESS_MASK (0x00001000)
#define SPFI_GDEX8BIT_MASK (0x00000800)
#define SPFI_ALLDONE_MASK (0x00000200)
#define SPFI_GDFUL_MASK (0x00000100)
#define SPFI_GDHF_MASK (0x00000080)
#define SPFI_GDEX32BIT_MASK (0x00000040)
#define SPFI_GDTRIG_MASK (0x00000020)
#define SPFI_SDFUL_MASK (0x00000008)
#define SPFI_SDHF_MASK (0x00000004)
#define SPFI_SDE_MASK (0x00000002)
#define SPFI_SDTRIG_MASK (0x00000001)
#define SPFI_IACCESS_SHIFT (12)
#define SPFI_GDEX8BIT_SHIFT (11)
#define SPFI_ALLDONE_SHIFT (9)
#define SPFI_GDFUL_SHIFT (8)
#define SPFI_GDHF_SHIFT (7)
#define SPFI_GDEX32BIT_SHIFT (6)
#define SPFI_GDTRIG_SHIFT (5)
#define SPFI_SDFUL_SHIFT (3)
#define SPFI_SDHF_SHIFT (2)
#define SPFI_SDE_SHIFT (1)
#define SPFI_SDTRIG_SHIFT (0)
/* SPFI register block */
#define SPFI_PORT_0_PARAM_REG_OFFSET (0x00)
#define SPFI_PORT_1_PARAM_REG_OFFSET (0x04)
#define SPFI_PORT_2_PARAM_REG_OFFSET (0x08)
#define SPFI_PORT_3_PARAM_REG_OFFSET (0x0C)
#define SPFI_PORT_4_PARAM_REG_OFFSET (0x10)
#define SPFI_CONTROL_REG_OFFSET (0x14)
#define SPFI_TRANSACTION_REG_OFFSET (0x18)
#define SPFI_PORT_STATE_REG_OFFSET (0x1C)
#define SPFI_SEND_LONG_REG_OFFSET (0x20)
#define SPFI_SEND_BYTE_REG_OFFSET (0x24)
#define SPFI_GET_LONG_REG_OFFSET (0x28)
#define SPFI_GET_BYTE_REG_OFFSET (0x2C)
#define SPFI_INT_STATUS_REG_OFFSET (0x30)
#define SPFI_INT_ENABLE_REG_OFFSET (0x34)
#define SPFI_INT_CLEAR_REG_OFFSET (0x38)
#define SPFI_IMMEDIATE_STATUS_REG_OFFSET (0x3c)
#define SPFI_FLASH_BASE_ADDRESS_REG_OFFSET (0x48)
#define SPFI_FLASH_STATUS_REG_OFFSET (0x4C)
#define IMG_FALSE 0
#define IMG_TRUE 1
/* Number of SPIM interfaces*/
#define SPIM_NUM_BLOCKS 2
/* Number of chip select lines supported by the SPI master port. */
#define SPIM_NUM_PORTS_PER_BLOCK (SPIM_DUMMY_CS)
/* Maximum transfer size (in bytes) for the SPI master port. */
#define SPIM_MAX_TRANSFER_BYTES (0xFFFF)
/* Maximum size of a flash command: command bytes+address_bytes. */
#define SPIM_MAX_FLASH_COMMAND_BYTES (0x8)
/* Write operation to fifo done in blocks of 16 words (64 bytes) */
#define SPIM_MAX_BLOCK_BYTES (0x40)
/* Number of tries until timeout error is returned*/
#define SPI_TIMEOUT_VALUE_US 500000
/* SPIM initialisation function return value.*/
enum spim_return {
/* Initialisation parameters are valid. */
SPIM_OK = 0,
/* Mode parameter is invalid. */
SPIM_INVALID_SPI_MODE,
/* Chip select idle level is invalid. */
SPIM_INVALID_CS_IDLE_LEVEL,
/* Data idle level is invalid. */
SPIM_INVALID_DATA_IDLE_LEVEL,
/* Chip select line parameter is invalid. */
SPIM_INVALID_CS_LINE,
/* Transfer size parameter is invalid. */
SPIM_INVALID_SIZE,
/* Read/write parameter is invalid. */
SPIM_INVALID_READ_WRITE,
/* Continue parameter is invalid. */
SPIM_INVALID_CONTINUE,
/* Invalid block index */
SPIM_INVALID_BLOCK_INDEX,
/* Extended error values */
/* Invalid bit rate */
SPIM_INVALID_BIT_RATE,
/* Invalid CS hold value */
SPIM_INVALID_CS_HOLD_VALUE,
/* API function called before API is initialised */
SPIM_API_NOT_INITIALISED,
/* SPI driver initialisation failed */
SPIM_DRIVER_INIT_ERROR,
/* Invalid transfer description */
SPIM_INVALID_TRANSFER_DESC,
/* Timeout */
SPIM_TIMEOUT
};
/* This type defines the SPI Mode.*/
enum spim_mode {
/* Mode 0 (clock idle low, data valid on first clock transition). */
SPIM_MODE_0 = 0,
/* Mode 1 (clock idle low, data valid on second clock transition). */
SPIM_MODE_1,
/* Mode 2 (clock idle high, data valid on first clock transition). */
SPIM_MODE_2,
/* Mode 3 (clock idle high, data valid on second clock transition). */
SPIM_MODE_3
};
/* This type defines the SPIM device numbers (chip select lines). */
enum spim_device {
/* Device 0 (CS0). */
SPIM_DEVICE0 = 0,
/* Device 1 (CS1). */
SPIM_DEVICE1,
/* Device 2 (CS2). */
SPIM_DEVICE2,
/* Device 3 (CS3). */
SPIM_DEVICE3,
/* Device 4 (CS4). */
SPIM_DEVICE4,
/* Dummy chip select. */
SPIM_DUMMY_CS
};
/* This structure defines communication parameters for a slave device */
struct spim_device_parameters {
/* Bit rate value.*/
unsigned char bitrate;
/*
* Chip select set up time.
* Time taken between chip select going active and activity occurring
* on the clock, calculated by dividing the desired set up time in ns
* by the Input clock period. (setup time / Input clock freq)
*/
unsigned char cs_setup;
/*
* Chip select hold time.
* Time after the last clock pulse before chip select goes inactive,
* calculated by dividing the desired hold time in ns by the
* Input clock period (hold time / Input clock freq).
*/
unsigned char cs_hold;
/*
* Chip select delay time (CS minimum inactive time).
* Minimum time after chip select goes inactive before chip select
* can go active again, calculated by dividing the desired delay time
* in ns by the Input clock period (delay time / Input clock freq).
*/
unsigned char cs_delay;
/* SPI Mode. */
enum spim_mode spi_mode;
/* Chip select idle level (0=low, 1=high, Others=invalid). */
unsigned int cs_idle_level;
/* Data idle level (0=low, 1=high, Others=invalid). */
unsigned int data_idle_level;
};
/* Command transfer mode */
enum command_mode {
/* Command, address, dummy and PI cycles are transferred on sio0 */
SPIM_CMD_MODE_0 = 0,
/*
* Command and Address are transferred on sio0 port only but dummy
* cycles and PI is transferred on all the interface ports.
*/
SPIM_CMD_MODE_1,
/*
* Command is transferred on sio0 port only but address, dummy
* and PI is transferred on all the interface portS
*/
SPIM_CMD_MODE_2,
/*
* Command, address, dummy and PI bytes are transferred on all
* the interfaces
*/
SPIM_CMD_MODE_3
};
/* Data transfer mode */
enum transfer_mode {
/* Transfer data in single mode */
SPIM_DMODE_SINGLE = 0,
/* Transfer data in dual mode */
SPIM_DMODE_DUAL,
/* Transfer data in quad mode */
SPIM_DMODE_QUAD
};
/* This structure contains parameters that describe an SPIM operation. */
struct spim_buffer {
/* The buffer to read from or write to. */
unsigned char *buffer;
/* Number of bytes to read/write. Valid range is 0 to 65536 bytes. */
unsigned int size;
/* Read/write select. TRUE for read, FALSE for write, Others-invalid.*/
int isread;
/*
* ByteDelay select.
* Selects whether or not a delay is inserted between bytes.
* 0 - Minimum inter-byte delay
* 1 - Inter-byte delay of (cs_hold/master_clk half period)*master_clk.
*/
int inter_byte_delay;
};
#endif /* __SOC_IMGTEC_DANUBE_SPI_H__ */

View File

@ -1,53 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright 2014 Google Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <arch/cpu.h>
#include <device/mmio.h>
#include <soc/cpu.h>
#include <stdint.h>
#include <timer.h>
#define PISTACHIO_CLOCK_SWITCH 0xB8144200
#define MIPS_EXTERN_PLL_BYPASS_MASK 0x00000002
static int get_count_mhz_freq(void)
{
static unsigned int count_mhz_freq;
if (!count_mhz_freq) {
if (IMG_PLATFORM_ID() != IMG_PLATFORM_ID_SILICON)
count_mhz_freq = 25; /* FPGA board */
else {
/* If MIPS PLL external bypass bit is set, it means
* that the MIPS PLL is already set up to work at a
* frequency of 550 MHz; otherwise, the crystal is
* used with a frequency of 52 MHz
*/
if (read32_x(PISTACHIO_CLOCK_SWITCH) &
MIPS_EXTERN_PLL_BYPASS_MASK)
/* Half MIPS PLL freq. */
count_mhz_freq = 275;
else
/* Half Xtal freq. */
count_mhz_freq = 26;
}
}
return count_mhz_freq;
}
void timer_monotonic_get(struct mono_time *mt)
{
mono_time_set_usecs(mt, read_c0_count() / get_count_mhz_freq());
}

View File

@ -1,26 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright 2014 Google Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <device/mmio.h>
#include <reset.h>
#define PISTACHIO_WD_ADDR 0xB8102100
#define PISTACHIO_WD_SW_RST_OFFSET 0x0000
void do_board_reset(void)
{
/* Generate system reset */
write32_x(PISTACHIO_WD_ADDR + PISTACHIO_WD_SW_RST_OFFSET, 0x1);
}

View File

@ -1,39 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2014 Imagination Technologies
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; version 2 of
* the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <cbmem.h>
#include <console/console.h>
#include <halt.h>
#include <program_loading.h>
#include <soc/ddr_init.h>
void main(void)
{
int error;
console_init();
error = init_ddr2();
if (!error) {
/*
* When romstage is running it's always on the reboot path and
* never a resume path where cbmem recovery is required.
* Therefore, always initialize the cbmem area to be empty.
*/
cbmem_initialize_empty();
run_ramstage();
}
halt();
}

View File

@ -1,44 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright 2014 The Chromium OS Authors.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <console/console.h>
#include <device/device.h>
#include <symbols.h>
static void soc_read_resources(struct device *dev)
{
ram_resource(dev, 0, (uintptr_t)_dram / KiB,
(CONFIG_DRAM_SIZE_MB * MiB) / KiB);
}
static void soc_init(struct device *dev)
{
printk(BIOS_INFO, "CPU: Imgtec Pistachio\n");
}
static struct device_operations soc_ops = {
.read_resources = soc_read_resources,
.init = soc_init,
};
static void enable_soc_dev(struct device *dev)
{
dev->ops = &soc_ops;
}
struct chip_operations soc_imgtec_pistachio_ops = {
CHIP_NAME("SOC: Imgtec Pistachio")
.enable_dev = enable_soc_dev,
};

View File

@ -1,587 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2014 Imagination Technologies
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <console/console.h>
#include <device/mmio.h>
#include <soc/cpu.h>
#include <soc/spi.h>
#include <spi_flash.h>
#include <spi-generic.h>
#include <stdlib.h>
#include <string.h>
#include <timer.h>
/* Imgtec controller uses 16 bit packet length. */
#define IMGTEC_SPI_MAX_TRANSFER_SIZE ((1 << 16) - 1)
struct img_spi_slave {
/* SPIM instance device parameters */
struct spim_device_parameters device_parameters;
/* SPIM instance base address */
u32 base;
/* Boolean property that is TRUE if API has been initialised */
int initialised;
};
/* Allocate memory for the maximum number of devices */
static struct
img_spi_slave img_spi_slaves[SPIM_NUM_BLOCKS*SPIM_NUM_PORTS_PER_BLOCK];
/*
* Wait for the bit at the shift position to be set in reg
* If the bit is not set in SPI_TIMEOUT_VALUE_US return with error
*/
static int wait_status(u32 reg, u32 shift)
{
struct stopwatch sw;
stopwatch_init_usecs_expire(&sw, SPI_TIMEOUT_VALUE_US);
while (!(read32_x(reg) & (1 << shift))) {
if (stopwatch_expired(&sw))
return -SPIM_TIMEOUT;
}
return SPIM_OK;
}
static struct img_spi_slave *get_img_slave(const struct spi_slave *slave)
{
return img_spi_slaves + slave->bus * SPIM_NUM_PORTS_PER_BLOCK +
slave->cs;
}
/* Transmitter function. Fills TX FIFO with data before enabling SPIM */
static int transmitdata(const struct spi_slave *slave, u8 *buffer, u32 size)
{
u32 blocksize, base, write_data;
int ret;
struct img_spi_slave *img_slave = get_img_slave(slave);
base = img_slave->base;
while (size) {
/* Wait until FIFO empty */
write32_x(base + SPFI_INT_CLEAR_REG_OFFSET, SPFI_SDE_MASK);
ret = wait_status(base + SPFI_INT_STATUS_REG_OFFSET,
SPFI_SDE_SHIFT);
if (ret)
return ret;
/*
* Write to FIFO in blocks of 16 words (64 bytes)
* Do 32bit writes first.
*/
blocksize = SPIM_MAX_BLOCK_BYTES;
while ((size >= sizeof(u32)) && blocksize) {
memcpy(&write_data, buffer, sizeof(u32));
write32_x(base + SPFI_SEND_LONG_REG_OFFSET, write_data);
buffer += sizeof(u32);
size -= sizeof(u32);
blocksize -= sizeof(u32);
}
while (size && blocksize) {
write32_x(base + SPFI_SEND_BYTE_REG_OFFSET, *buffer);
buffer++;
size--;
blocksize--;
}
}
return SPIM_OK;
}
/* Receiver function */
static int receivedata(const struct spi_slave *slave, u8 *buffer, u32 size)
{
u32 read_data, base;
int ret;
struct img_spi_slave *img_slave = get_img_slave(slave);
base = img_slave->base;
/*
* Do 32bit reads first. Clear status GDEX32BIT here so that the first
* status reg. read gets the actual bit state
*/
write32_x(base + SPFI_INT_CLEAR_REG_OFFSET, SPFI_GDEX32BIT_MASK);
while (size >= sizeof(u32)) {
ret = wait_status(base + SPFI_INT_STATUS_REG_OFFSET,
SPFI_GDEX32BIT_SHIFT);
if (ret)
return ret;
read_data = read32_x(base + SPFI_GET_LONG_REG_OFFSET);
memcpy(buffer, &read_data, sizeof(u32));
buffer += sizeof(u32);
size -= sizeof(u32);
/* Clear interrupt status on GDEX32BITL */
write32_x(base + SPFI_INT_CLEAR_REG_OFFSET, SPFI_GDEX32BIT_MASK);
}
/*
* Do the remaining 8bit reads. Clear status GDEX8BIT here so that
* the first status reg. read gets the actual bit state
*/
write32_x(base + SPFI_INT_CLEAR_REG_OFFSET, SPFI_GDEX8BIT_MASK);
while (size) {
ret = wait_status(base + SPFI_INT_STATUS_REG_OFFSET,
SPFI_GDEX8BIT_SHIFT);
if (ret)
return ret;
*buffer = read32_x(base + SPFI_GET_BYTE_REG_OFFSET);
buffer++;
size--;
/* Clear interrupt status on SPFI_GDEX8BIT */
write32_x(base + SPFI_INT_CLEAR_REG_OFFSET, SPFI_GDEX8BIT_MASK);
}
return SPIM_OK;
}
/* Sets port parameters in port state register. */
static void setparams(const struct spi_slave *slave, u32 port,
struct spim_device_parameters *params)
{
u32 spim_parameters, port_state, base;
struct img_spi_slave *img_slave = get_img_slave(slave);
base = img_slave->base;
spim_parameters = 0;
port_state = read32_x(base + SPFI_PORT_STATE_REG_OFFSET);
port_state &= ~((SPIM_PORT0_MASK>>port)|SPFI_PORT_SELECT_MASK);
port_state |= params->cs_idle_level<<(SPIM_CS0_IDLE_SHIFT-port);
port_state |=
params->data_idle_level<<(SPIM_DATA0_IDLE_SHIFT-port);
/* Clock idle level and phase */
switch (params->spi_mode) {
case SPIM_MODE_0:
break;
case SPIM_MODE_1:
port_state |= (1 << (SPIM_CLOCK0_PHASE_SHIFT - port));
break;
case SPIM_MODE_2:
port_state |= (1 << (SPIM_CLOCK0_IDLE_SHIFT - port));
break;
case SPIM_MODE_3:
port_state |= (1 << (SPIM_CLOCK0_IDLE_SHIFT - port)) |
(1 << (SPIM_CLOCK0_PHASE_SHIFT - port));
break;
}
/* Set port state register */
write32_x(base + SPFI_PORT_STATE_REG_OFFSET, port_state);
/* Set up values to be written to device parameter register */
spim_parameters |= params->bitrate << SPIM_CLK_DIVIDE_SHIFT;
spim_parameters |= params->cs_setup << SPIM_CS_SETUP_SHIFT;
spim_parameters |= params->cs_hold << SPIM_CS_HOLD_SHIFT;
spim_parameters |= params->cs_delay << SPIM_CS_DELAY_SHIFT;
write32_x(base + SPFI_PORT_0_PARAM_REG_OFFSET + 4 * port,
spim_parameters);
}
/* Sets up transaction register */
static u32 transaction_reg_setup(struct spim_buffer *first,
struct spim_buffer *second)
{
u32 reg = 0;
/* 2nd transfer exists? */
if (second) {
/*
* If second transfer exists, it's a "command followed by data"
* type of transfer and first transfer is defined by
* CMD_LENGTH, ADDR_LENGTH, DUMMY_LENGTH... fields of
* transaction register
*/
reg = spi_write_reg_field(reg, SPFI_CMD_LENGTH, 1);
reg = spi_write_reg_field(reg, SPFI_ADDR_LENGTH,
first->size - 1);
reg = spi_write_reg_field(reg, SPFI_DUMMY_LENGTH, 0);
/* Set data size (size of the second transfer) */
reg = spi_write_reg_field(reg, SPFI_TSIZE, second->size);
} else {
/* Set data size, in this case size of the 1st transfer */
reg = spi_write_reg_field(reg, SPFI_TSIZE, first->size);
}
return reg;
}
/* Sets up control register */
static u32 control_reg_setup(struct spim_buffer *first,
struct spim_buffer *second)
{
u32 reg;
/* Enable SPFI */
reg = SPFI_EN_MASK;
reg |= first->inter_byte_delay ? SPIM_BYTE_DELAY_MASK : 0;
/* Set up the transfer mode */
reg = spi_write_reg_field(reg, SPFI_TRNSFR_MODE_DQ, SPIM_CMD_MODE_0);
reg = spi_write_reg_field(reg, SPFI_TRNSFR_MODE, SPIM_DMODE_SINGLE);
reg = spi_write_reg_field(reg, SPIM_EDGE_TX_RX, 1);
if (second) {
/* Set TX bit if the 2nd transaction is 'send' */
reg = spi_write_reg_field(reg, SPFI_TX_RX,
second->isread ? 0 : 1);
/*
* Set send/get DMA for both transactions
* (first is always 'send')
*/
reg = spi_write_reg_field(reg, SPIM_SEND_DMA, 1);
if (second->isread)
reg = spi_write_reg_field(reg, SPIM_GET_DMA, 1);
} else {
/* Set TX bit if the 1st transaction is 'send' */
reg |= first->isread ? 0 : SPFI_TX_RX_MASK;
/* Set send/get DMA */
reg |= first->isread ? SPIM_GET_DMA_MASK : SPIM_SEND_DMA_MASK;
}
return reg;
}
/* Checks the given buffer information */
static int check_buffers(const struct spi_slave *slave, struct spim_buffer *first,
struct spim_buffer *second){
struct img_spi_slave *img_slave = get_img_slave(slave);
if (!(img_slave->initialised))
return -SPIM_API_NOT_INITIALISED;
/*
* First operation must always be defined
* It can be either a read or a write and its size cannot be bigge
* than SPIM_MAX_TANSFER_BYTES = 64KB - 1 (0xFFFF)
*/
if (!first)
return -SPIM_INVALID_READ_WRITE;
if (first->size > SPIM_MAX_TRANSFER_BYTES)
return -SPIM_INVALID_SIZE;
if (first->isread > 1)
return -SPIM_INVALID_READ_WRITE;
/* Check operation parameters for 'second' */
if (second) {
/*
* If the second operation is defined it must be a read
* operation and its size must not be bigger than
* SPIM_MAX_TANSFER_BYTES = 64KB - 1 (0xFFFF)
*/
if (second->size > SPIM_MAX_TRANSFER_BYTES)
return -SPIM_INVALID_SIZE;
if (!second->isread)
return -SPIM_INVALID_READ_WRITE;
/*
* If the second operations is defined, the first operation
* must be a write and its size cannot be bigger than
* SPIM_MAX_FLASH_COMMAND_BYTES(8): command size (1) +
* address size (7).
*/
if (first->isread)
return -SPIM_INVALID_READ_WRITE;
if (first->size > SPIM_MAX_FLASH_COMMAND_BYTES)
return -SPIM_INVALID_SIZE;
}
return SPIM_OK;
}
/* Checks the set bitrate */
static int check_bitrate(u32 rate)
{
/* Bitrate must be 1, 2, 4, 8, 16, 32, 64, or 128 */
switch (rate) {
case 1:
case 2:
case 4:
case 8:
case 16:
case 32:
case 64:
case 128:
return SPIM_OK;
default:
return -SPIM_INVALID_BIT_RATE;
}
return -SPIM_INVALID_BIT_RATE;
}
/* Checks device parameters for errors */
static int check_device_params(struct spim_device_parameters *pdev_param)
{
if (pdev_param->spi_mode < SPIM_MODE_0 ||
pdev_param->spi_mode > SPIM_MODE_3)
return -SPIM_INVALID_SPI_MODE;
if (check_bitrate(pdev_param->bitrate) != SPIM_OK)
return -SPIM_INVALID_BIT_RATE;
if (pdev_param->cs_idle_level > 1)
return -SPIM_INVALID_CS_IDLE_LEVEL;
if (pdev_param->data_idle_level > 1)
return -SPIM_INVALID_DATA_IDLE_LEVEL;
return SPIM_OK;
}
/* Function that carries out read/write operations */
static int spim_io(const struct spi_slave *slave, struct spim_buffer *first,
struct spim_buffer *second)
{
u32 reg, base;
int i, trans_count, ret;
struct spim_buffer *transaction[2];
struct img_spi_slave *img_slave = get_img_slave(slave);
base = img_slave->base;
ret = check_buffers(slave, first, second);
if (ret)
return ret;
/*
* Soft reset peripheral internals, this will terminate any
* pending transactions
*/
write32_x(base + SPFI_CONTROL_REG_OFFSET, SPIM_SOFT_RESET_MASK);
write32_x(base + SPFI_CONTROL_REG_OFFSET, 0);
/* Port state register */
reg = read32_x(base + SPFI_PORT_STATE_REG_OFFSET);
reg = spi_write_reg_field(reg, SPFI_PORT_SELECT, slave->cs);
write32_x(base + SPFI_PORT_STATE_REG_OFFSET, reg);
/* Set transaction register */
reg = transaction_reg_setup(first, second);
write32_x(base + SPFI_TRANSACTION_REG_OFFSET, reg);
/* Clear status */
write32_x(base + SPFI_INT_CLEAR_REG_OFFSET, 0xffffffff);
/* Set control register */
reg = control_reg_setup(first, second);
write32_x(base + SPFI_CONTROL_REG_OFFSET, reg);
/* First transaction always exists */
transaction[0] = first;
trans_count = 1;
/* Is there a second transaction? */
if (second) {
transaction[1] = second;
trans_count++;
}
/* Now write/read FIFO's */
for (i = 0; i < trans_count; i++)
/* Which transaction to execute, "Send" or "Get"? */
if (transaction[i]->isread) {
/* Get */
ret = receivedata(slave, transaction[i]->buffer,
transaction[i]->size);
if (ret) {
printk(BIOS_ERR,
"%s: Error: receive data failed.\n",
__func__);
return ret;
}
} else {
/* Send */
ret = transmitdata(slave, transaction[i]->buffer,
transaction[i]->size);
if (ret) {
printk(BIOS_ERR,
"%s: Error: transmit data failed.\n",
__func__);
return ret;
}
}
/* Wait for end of the transaction */
ret = wait_status(base + SPFI_INT_STATUS_REG_OFFSET,
SPFI_ALLDONE_SHIFT);
if (ret)
return ret;
/*
* Soft reset peripheral internals, this will terminate any
* pending transactions
*/
write32_x(base + SPFI_CONTROL_REG_OFFSET, SPIM_SOFT_RESET_MASK);
write32_x(base + SPFI_CONTROL_REG_OFFSET, 0);
return SPIM_OK;
}
/* Claim the bus and prepare it for communication */
static int spi_ctrlr_claim_bus(const struct spi_slave *slave)
{
int ret;
struct img_spi_slave *img_slave;
if (!slave) {
printk(BIOS_ERR, "%s: Error: slave was not set up.\n",
__func__);
return -SPIM_API_NOT_INITIALISED;
}
img_slave = get_img_slave(slave);
if (img_slave->initialised)
return SPIM_OK;
/* Check device parameters */
ret = check_device_params(&(img_slave->device_parameters));
if (ret) {
printk(BIOS_ERR, "%s: Error: incorrect device parameters.\n",
__func__);
return ret;
}
/* Set device parameters */
setparams(slave, slave->cs, &(img_slave->device_parameters));
/* Soft reset peripheral internals */
write32_x(img_slave->base + SPFI_CONTROL_REG_OFFSET,
SPIM_SOFT_RESET_MASK);
write32_x(img_slave->base + SPFI_CONTROL_REG_OFFSET, 0);
img_slave->initialised = IMG_TRUE;
return SPIM_OK;
}
/* Release the SPI bus */
static void spi_ctrlr_release_bus(const struct spi_slave *slave)
{
struct img_spi_slave *img_slave;
if (!slave) {
printk(BIOS_ERR, "%s: Error: slave was not set up.\n",
__func__);
return;
}
img_slave = get_img_slave(slave);
img_slave->initialised = IMG_FALSE;
/* Soft reset peripheral internals */
write32_x(img_slave->base + SPFI_CONTROL_REG_OFFSET,
SPIM_SOFT_RESET_MASK);
write32_x(img_slave->base + SPFI_CONTROL_REG_OFFSET, 0);
}
/* SPI transfer */
static int do_spi_xfer(const struct spi_slave *slave, const void *dout,
size_t bytesout, void *din, size_t bytesin)
{
struct spim_buffer buff_0;
struct spim_buffer buff_1;
/* If we only have a read or a write operation
* the parameters for it will be put in the first buffer
*/
buff_0.buffer = (dout) ? (void *)dout : (void *)din;
buff_0.size = (dout) ? bytesout : bytesin;
buff_0.isread = (dout) ? IMG_FALSE : IMG_TRUE;
buff_0.inter_byte_delay = 0;
if (dout && din) {
/* Set up the read buffer to receive our data */
buff_1.buffer = din;
buff_1.size = bytesin;
buff_1.isread = IMG_TRUE;
buff_1.inter_byte_delay = 0;
}
return spim_io(slave, &buff_0, (dout && din) ? &buff_1 : NULL);
}
static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,
size_t bytesout, void *din, size_t bytesin)
{
unsigned int in_sz, out_sz;
int ret;
if (!slave) {
printk(BIOS_ERR, "%s: Error: slave was not set up.\n",
__func__);
return -SPIM_API_NOT_INITIALISED;
}
if (!dout && !din) {
printk(BIOS_ERR, "%s: Error: both buffers are NULL.\n",
__func__);
return -SPIM_INVALID_TRANSFER_DESC;
}
while (bytesin || bytesout) {
in_sz = min(IMGTEC_SPI_MAX_TRANSFER_SIZE, bytesin);
out_sz = min(IMGTEC_SPI_MAX_TRANSFER_SIZE, bytesout);
ret = do_spi_xfer(slave, dout, out_sz, din, in_sz);
if (ret)
return ret;
bytesin -= in_sz;
bytesout -= out_sz;
if (bytesin)
din += in_sz;
else
din = NULL;
if (bytesout)
dout += out_sz;
else
dout = NULL;
}
return SPIM_OK;
}
static int spi_ctrlr_setup(const struct spi_slave *slave)
{
struct img_spi_slave *img_slave = NULL;
struct spim_device_parameters *device_parameters;
u32 base;
switch (slave->bus) {
case 0:
base = IMG_SPIM0_BASE_ADDRESS;
break;
case 1:
base = IMG_SPIM1_BASE_ADDRESS;
break;
default:
printk(BIOS_ERR, "%s: Error: unsupported bus.\n",
__func__);
return -1;
}
if (slave->cs > SPIM_DEVICE4) {
printk(BIOS_ERR, "%s: Error: unsupported chipselect.\n",
__func__);
return -1;
}
img_slave = get_img_slave(slave);
device_parameters = &(img_slave->device_parameters);
img_slave->base = base;
device_parameters->bitrate = 64;
device_parameters->cs_setup = 0;
device_parameters->cs_hold = 0;
device_parameters->cs_delay = 0;
device_parameters->spi_mode = SPIM_MODE_0;
device_parameters->cs_idle_level = 1;
device_parameters->data_idle_level = 0;
img_slave->initialised = IMG_FALSE;
return 0;
}
static const struct spi_ctrlr spi_ctrlr = {
.setup = spi_ctrlr_setup,
.claim_bus = spi_ctrlr_claim_bus,
.release_bus = spi_ctrlr_release_bus,
.xfer = spi_ctrlr_xfer,
.max_xfer_size = IMGTEC_SPI_MAX_TRANSFER_SIZE,
};
const struct spi_ctrlr_buses spi_ctrlr_bus_map[] = {
{
.ctrlr = &spi_ctrlr,
.bus_start = 0,
.bus_end = 1,
},
};
const size_t spi_ctrlr_bus_map_count = ARRAY_SIZE(spi_ctrlr_bus_map);

View File

@ -1,158 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2003 Eric Biederman
* Copyright (C) 2006-2010 coresystems GmbH
* Copyright (C) 2014 Imagination Technologies
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; version 2 of
* the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <device/mmio.h>
#include <boot/coreboot_tables.h>
#include <console/uart.h>
#include <device/device.h>
#include <delay.h>
#include <drivers/uart/uart8250reg.h>
/* Should support 8250, 16450, 16550, 16550A type UARTs */
/* Expected character delay at 1200bps is 9ms for a working UART
* and no flow-control. Assume UART as stuck if shift register
* or FIFO takes more than 50ms per character to appear empty.
*/
#define SINGLE_CHAR_TIMEOUT (50 * 1000)
#define FIFO_TIMEOUT (16 * SINGLE_CHAR_TIMEOUT)
#define UART_SHIFT 2
#define GEN_ACCESSOR(name, idx) \
static inline uint8_t read_##name(unsigned int base_port) \
{ \
return read8((void *)(base_port + (idx << UART_SHIFT))); \
} \
\
static inline void write_##name(unsigned int base_port, uint8_t val) \
{ \
write8((void *)(base_port + (idx << UART_SHIFT)), val); \
}
GEN_ACCESSOR(rbr, UART8250_RBR)
GEN_ACCESSOR(tbr, UART8250_TBR)
GEN_ACCESSOR(ier, UART8250_IER)
GEN_ACCESSOR(fcr, UART8250_FCR)
GEN_ACCESSOR(lcr, UART8250_LCR)
GEN_ACCESSOR(mcr, UART8250_MCR)
GEN_ACCESSOR(lsr, UART8250_LSR)
GEN_ACCESSOR(dll, UART8250_DLL)
GEN_ACCESSOR(dlm, UART8250_DLM)
static int uart8250_mem_can_tx_byte(unsigned int base_port)
{
return read_lsr(base_port) & UART8250_LSR_THRE;
}
static void uart8250_mem_tx_byte(unsigned int base_port, unsigned char data)
{
unsigned long int i = SINGLE_CHAR_TIMEOUT;
while (i-- && !uart8250_mem_can_tx_byte(base_port))
udelay(1);
write_tbr(base_port, data);
}
static void uart8250_mem_tx_flush(unsigned int base_port)
{
unsigned long int i = FIFO_TIMEOUT;
while (i-- && !(read_lsr(base_port) & UART8250_LSR_TEMT))
udelay(1);
}
static int uart8250_mem_can_rx_byte(unsigned int base_port)
{
return read_lsr(base_port) & UART8250_LSR_DR;
}
static unsigned char uart8250_mem_rx_byte(unsigned int base_port)
{
unsigned long int i = SINGLE_CHAR_TIMEOUT;
while (i-- && !uart8250_mem_can_rx_byte(base_port))
udelay(1);
if (i)
return read_rbr(base_port);
else
return 0x0;
}
static void uart8250_mem_init(unsigned int base_port, unsigned int divisor)
{
/* Disable interrupts */
write_ier(base_port, 0x0);
/* Enable FIFOs */
write_fcr(base_port, UART8250_FCR_FIFO_EN);
/* Assert DTR and RTS so the other end is happy */
write_mcr(base_port, UART8250_MCR_DTR | UART8250_MCR_RTS);
/* DLAB on */
write_lcr(base_port, UART8250_LCR_DLAB | CONFIG_TTYS0_LCS);
write_dll(base_port, divisor & 0xFF);
write_dlm(base_port, (divisor >> 8) & 0xFF);
/* Set to 3 for 8N1 */
write_lcr(base_port, CONFIG_TTYS0_LCS);
}
unsigned int uart_platform_refclk(void)
{
/* 1.8433179 MHz */
return 1843318;
}
void uart_init(int idx)
{
u32 base = CONFIG_CONSOLE_SERIAL_UART_ADDRESS;
if (!base)
return;
unsigned int div;
div = uart_baudrate_divisor(get_uart_baudrate(),
uart_platform_refclk(), 16);
uart8250_mem_init(base, div);
}
void uart_tx_byte(int idx, unsigned char data)
{
uart8250_mem_tx_byte(CONFIG_CONSOLE_SERIAL_UART_ADDRESS, data);
}
unsigned char uart_rx_byte(int idx)
{
return uart8250_mem_rx_byte(CONFIG_CONSOLE_SERIAL_UART_ADDRESS);
}
void uart_tx_flush(int idx)
{
uart8250_mem_tx_flush(CONFIG_CONSOLE_SERIAL_UART_ADDRESS);
}
void uart_fill_lb(void *data)
{
struct lb_serial serial;
serial.type = LB_SERIAL_TYPE_MEMORY_MAPPED;
serial.baseaddr = CONFIG_CONSOLE_SERIAL_UART_ADDRESS;
serial.baud = get_uart_baudrate();
serial.regwidth = 1 << UART_SHIFT;
serial.input_hertz = uart_platform_refclk();
serial.uart_pci_addr = CONFIG_UART_PCI_ADDR;
lb_add_serial(&serial, data);
lb_add_console(LB_TAG_CONSOLE_SERIAL8250MEM, data);
}

View File

@ -1,16 +0,0 @@
obj ?= $(CURDIR)
HOSTCC ?= gcc
CFLAGS ?= -g
CFLAGS += -D_7ZIP_ST
CFLAGS += -Wall -Wundef -Wstrict-prototypes -Wmissing-prototypes
CFLAGS += -Wwrite-strings -Wredundant-decls -Wno-trigraphs
CFLAGS += -Wstrict-aliasing -Wshadow -Werror
all: $(obj)/bimgtool
clean:
rm -f $(obj)/bimgtool
$(obj)/bimgtool: bimgtool.c
$(HOSTCC) $(CFLAGS) -o $@ $^

View File

@ -1,430 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright 2014 Imagination Technologies Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; version 2 of
* the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
struct bimg_header {
uint32_t magic;
uint16_t ver_major;
uint16_t ver_minor;
uint32_t data_size;
uint32_t entry_addr;
uint32_t flags;
uint32_t data_crc;
uint32_t crc;
} __attribute__((packed));
struct bimg_data_header {
uint32_t size;
uint32_t dest_addr;
uint16_t dummy;
uint16_t crc;
} __attribute__((packed));
struct crc_t {
uint16_t (*crc_f)(uint16_t crc, void *void_buf, size_t size);
uint32_t crc_init;
uint16_t ver_major;
uint16_t ver_minor;
};
#define BIMG_MAGIC /* y */ 0xabbadaba /* doo! */
#define BIMG_OP_MASK (0xf << 0)
#define BIMG_OP_EXEC_RETURN (0x1 << 0)
#define BIMG_OP_EXEC_NO_RETURN (0x2 << 0)
#define BIMG_DATA_CHECKSUM (0x1 << 4)
/* Typical use case for this utility. */
#define BIMG_FLAGS (BIMG_OP_EXEC_NO_RETURN | BIMG_DATA_CHECKSUM)
#define MAX_RECORD_BYTES 0x8000
#define CRC_16
#define error(msg...) fprintf(stderr, "ERROR: " msg)
#define error_ret(ret, msg...) { \
error(msg); \
return ret; \
}
#if defined(CRC_X25)
static uint16_t crc_x25(uint16_t crc, void *void_buf, size_t size)
{
static const uint16_t crc_table[16] = {
0x0000, 0x1021, 0x2042, 0x3063,
0x4084, 0x50a5, 0x60c6, 0x70e7,
0x8108, 0x9129, 0xa14a, 0xb16b,
0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
};
uint8_t *buf, data;
for (buf = void_buf; size; size--) {
data = *buf++;
crc = (crc << 4) ^ crc_table[((crc >> 12) ^ (data >> 4)) & 0xf];
crc = (crc << 4) ^ crc_table[((crc >> 12) ^ (data >> 0)) & 0xf];
}
return crc;
}
#endif
#if defined(CRC_16)
static uint16_t crc_16(uint16_t crc, void *void_buf, size_t size)
{
/*
* CRC table for the CRC-16.
* The poly is 0x8005 (x^16 + x^15 + x^2 + 1)
*/
static const uint16_t crc16_table[256] = {
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
};
uint8_t *buf, data;
for (buf = void_buf; size; size--) {
data = *buf++;
crc = (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
}
return crc;
}
#endif
static const struct crc_t crc_type = {
#if defined(CRC_16)
.crc_f = crc_16,
.crc_init = 0,
.ver_major = 2,
.ver_minor = 0
#elif defined(CRC_X25)
.crc_f = crc_x25,
.crc_init = 0xffff,
.ver_major = 1,
.ver_minor = 0
#endif
};
static int write_binary(FILE *out, FILE *in, struct bimg_header *hdr)
{
static uint8_t file_buf[MAX_RECORD_BYTES];
struct bimg_data_header data_hdr = { 0 };
size_t n_written;
data_hdr.dest_addr = hdr->entry_addr;
/*
* The read binary data has to be split in chunks of max 64KiB - 1 byte
* (SPI controller limitation). Each chunk will have its own header in
* order to respect the BIMG format.
*/
while ((data_hdr.size = fread(file_buf, 1, sizeof(file_buf), in))) {
data_hdr.crc = crc_type.crc_f(crc_type.crc_init, &data_hdr,
sizeof(data_hdr) - sizeof(data_hdr.crc));
if (fwrite(&data_hdr, sizeof(data_hdr), 1, out) != 1)
error_ret(-EIO, "Failed to write data header: %d\n",
errno);
n_written = fwrite(file_buf, 1, data_hdr.size, out);
if (n_written != data_hdr.size)
error_ret(-EIO, "Failed to write to output file: %d\n",
errno);
data_hdr.dest_addr += n_written;
hdr->data_size += sizeof(data_hdr) + n_written;
hdr->data_crc = crc_type.crc_f(hdr->data_crc,
file_buf, n_written);
}
if (ferror(in))
error_ret(-EIO, "Failed to read input file\n");
return 0;
}
static int write_final(FILE *out, struct bimg_header *hdr)
{
struct bimg_data_header data_hdr = {
.size = 0,
.dest_addr = ~0,
};
data_hdr.crc = crc_type.crc_f(crc_type.crc_init, &data_hdr,
sizeof(data_hdr) - sizeof(data_hdr.crc));
if (fwrite(&data_hdr, sizeof(data_hdr), 1, out) != 1)
error_ret(-EIO, "Failed to write data header: %d\n", errno);
hdr->data_size += sizeof(data_hdr);
return 0;
}
static const char *help_message =
"Usage: bimgtool <input> [<output> <base-address>]\n"
"\n"
"This is a simple tool which generates and verifies boot images in\n"
"the BIMG format, used in systems designed by Imagination\n"
"Technologies, for example the Pistachio SoC. This version of the\n"
"tool works with BIMG images version %d.\n"
"\n"
" input: The binary file to be converted to a BIMG\n"
" or verified\n"
" output: The name of the output BIMG file\n"
" base-address: The address in memory at which you wish the "
" input binary to be loaded.\n";
static void usage(FILE *f)
{
fprintf(f, help_message, crc_type.ver_major);
}
static int verify_file(FILE *f)
{
struct bimg_header file_header;
struct bimg_data_header data_header;
char *file_pointer;
char *file_data;
struct stat buf;
int data_size;
int fd = fileno(f);
uint32_t data_crc = crc_type.crc_init;
uint32_t crc_result;
if (fread(&file_header, 1, sizeof(struct bimg_header), f) !=
sizeof(struct bimg_header)) {
perror("Problems trying to read input file header\n");
return -1;
}
if (fstat(fd, &buf)) {
perror("Problems trying to stat input file\n");
return -1;
}
if (file_header.magic != BIMG_MAGIC) {
fprintf(stderr, "Wrong magic value %#x\n", file_header.magic);
return -1;
}
crc_result = crc_type.crc_f(crc_type.crc_init, &file_header,
sizeof(file_header) -
sizeof(file_header.crc));
if (file_header.crc != crc_result) {
fprintf(stderr, "File header CRC mismatch\n");
return -1;
}
if ((file_header.data_size + sizeof(struct bimg_header)) >
buf.st_size) {
fprintf(stderr, "Data size too big: %d > %zd\n",
file_header.data_size, buf.st_size);
return -1;
}
if (file_header.ver_major != crc_type.ver_major) {
fprintf(stderr, "Image version mismatch: %d\n",
file_header.ver_major);
return -1;
}
if ((file_header.flags & BIMG_FLAGS) != BIMG_FLAGS) {
fprintf(stderr, "Unexpected file header flags: %#x\n",
file_header.flags);
return -1;
}
if (file_header.ver_minor != crc_type.ver_minor) {
fprintf(stderr,
"Minor version mismatch: %d, will try anyways\n",
file_header.ver_minor);
}
data_size = file_header.data_size;
file_pointer = malloc(data_size);
if (!file_pointer) {
fprintf(stderr, "Failed to allocate %d bytes\n",
file_header.data_size);
return -1;
}
if (fread(file_pointer, 1, data_size, f) != data_size) {
fprintf(stderr, "Failed to read %d bytes\n", data_size);
free(file_pointer);
return -1;
}
file_data = file_pointer;
while (data_size > 0) {
memcpy(&data_header, file_data, sizeof(data_header));
/* Check the data block header integrity. */
crc_result = crc_type.crc_f(crc_type.crc_init, &data_header,
sizeof(data_header) -
sizeof(data_header.crc));
if (data_header.crc != crc_result) {
fprintf(stderr, "Data header CRC mismatch at %d\n",
file_header.data_size - data_size);
free(file_pointer);
return -1;
}
/*
* Add the block data to the CRC stream, the last block size
* will be zero.
*/
file_data += sizeof(data_header);
data_crc = crc_type.crc_f(data_crc,
file_data, data_header.size);
data_size -= data_header.size + sizeof(data_header);
file_data += data_header.size;
}
if (data_size) {
fprintf(stderr, "File size mismatch\n");
free(file_pointer);
return -1;
}
if (data_crc != file_header.data_crc) {
fprintf(stderr, "File data CRC mismatch\n");
free(file_pointer);
return -1;
}
free(file_pointer);
return 0;
}
int main(int argc, char *argv[])
{
const char *in_filename, *out_filename;
FILE *in_file, *out_file;
int err;
struct bimg_header hdr = {
.magic = BIMG_MAGIC,
.ver_major = crc_type.ver_major,
.ver_minor = crc_type.ver_minor,
.flags = BIMG_FLAGS,
.data_crc = crc_type.crc_init,
};
if ((argc != 4) && (argc != 2)) {
usage(stderr);
goto out_err;
}
in_filename = argv[1];
in_file = fopen(in_filename, "r");
if (!in_file) {
error("Failed to open input file '%s'\n", in_filename);
goto out_err;
}
if (argc == 2)
return verify_file(in_file);
out_filename = argv[2];
hdr.entry_addr = strtoul(argv[3], NULL, 16);
out_file = fopen(out_filename, "w");
if (!out_file) {
error("Failed to open output file '%s'\n", out_filename);
goto out_err_close_in;
}
if (fseek(out_file, sizeof(hdr), SEEK_SET)) {
error("Failed to seek past header: %d\n", errno);
goto out_err_close_out;
}
err = write_binary(out_file, in_file, &hdr);
if (err) {
error("Failed to write binary: %d\n", err);
goto out_err_close_out;
}
err = write_final(out_file, &hdr);
if (err) {
error("Failed to write final record: %d\n", err);
goto out_err_close_out;
}
hdr.crc = crc_type.crc_f(crc_type.crc_init, &hdr,
sizeof(hdr) - sizeof(hdr.crc));
if (fseek(out_file, 0, SEEK_SET)) {
error("Failed to seek to header: %d\n", errno);
goto out_err_close_out;
}
if (fwrite(&hdr, sizeof(hdr), 1, out_file) != 1) {
error("Failed to write header: %d\n", errno);
goto out_err_close_out;
}
fclose(in_file);
fclose(out_file);
return EXIT_SUCCESS;
out_err_close_out:
fclose(out_file);
out_err_close_in:
fclose(in_file);
out_err:
return EXIT_FAILURE;
}

View File

@ -1,3 +0,0 @@
A simple tool which generates and verifies boot images in the BIMG
format, used in systems designed by Imagination Technologies, for
example the Pistachio SoC. `C`