/*
 * Copyright 2009 Freescale Semiconductor.
 *
 * (C) Copyright 2002 Scott McNutt <smcnutt@artesyncp.com>
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * 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; either version 2 of
 * the License, or (at your option) any later version.
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

#include <common.h>
#include <hwconfig.h>
#include <pci.h>
#include <asm/processor.h>
#include <asm/mmu.h>
#include <asm/immap_85xx.h>
#include <asm/cache.h>
#include <asm/fsl_pci.h>
#include <asm/fsl_ddr_sdram.h>
#include <asm/io.h>
#include <ioports.h>
#include <libfdt.h>
#include <fdt_support.h>
#include <i2c.h>
#include <epi3.h>
#include <w1.h>

extern flash_info_t  flash_info[];

phys_size_t fixed_sdram(void);

const qe_iop_conf_t qe_iop_conf_tab[] = {

	/* UART2 is muxed with QE PortF bit [9-12].*/
	{5, 12, 2, 0, 3}, /* UART2_RXD */
	{5, 9,  1, 0, 3}, /* UART2_TXD */
	{5, 10, 2, 0, 3}, /* UART2_CTS */
	{5, 11, 1, 0, 2}, /* UART2_RTS */

	{0,  0, 0, 0, QE_IOP_TAB_END} /* END of table */
};

void local_bus_init(void);

#define PLPPAR1_UART0_RTS_BIT_MASK		0x00000030
#define PLPPAR1_UART0_RTS_SHIFT			4

int board_early_init_f (void)
{
	volatile ccsr_gur_t	*gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);

	/*
	 * Initialize local bus.
	 */
	local_bus_init ();

	/* Bring Switch chips and PLD leds out of reset */
	*(((u8 *)CONFIG_SYS_CPLD_REG_BASE)+1) = 0x13;
	udelay(10000);

	/* Enable writing to flash */
	*(((u8 *)CONFIG_SYS_CPLD_REG_BASE)+6) = 0x02;

	/* Make sure UART0 RTS is an output */
	gur->plpdir1 &= ~PLPPAR1_UART0_RTS_BIT_MASK;
	gur->plpdir1 |= (0x01 << PLPPAR1_UART0_RTS_SHIFT);

	return 0;
}

int board_early_init_r(void)
{
	const u8 flash_esel = find_tlb_idx((void *)CONFIG_SYS_FLASH_BASE, 1);

	/*
	 * Remap Boot FLASH region to caching-inhibited
	 * so that FLASH can be erased properly.
	 */

	/* Flush d-cache and invalidate i-cache of any FLASH data */
	flush_dcache();
	invalidate_icache();

	/* Invalidate existing TLB entry for FLASH */
	disable_tlb(flash_esel);

	/* Setup *I*G* for FLASH entry */
	set_tlb(1, CONFIG_SYS_FLASH_BASE, CONFIG_SYS_FLASH_BASE_PHYS,
		MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,
		0, flash_esel, BOOKE_PAGESZ_64M, 1);

	return 0;
}

#ifdef CONFIG_CMD_W1
static int last_bus = -1;
static void rapier_w1_set_bus(int bus)
{
	volatile ccsr_gur_t	*gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
	volatile par_io_t	*par_io = (volatile par_io_t *)&(gur->qe_par_io);

	/* Check if we are already using this cs */
	if (bus == last_bus)
		return;
	last_bus = bus;

	/* Configure CS pins (F4-F7) */
	clrbits_be32(&par_io[5].cpdir1, 0x00FF0000);
	setbits_be32(&par_io[5].cpdir1, 0x00550000);
	clrbits_be32(&par_io[5].cppar1, 0x00FF0000);

	/* Disable all but required bus */
	clrbits_be32(&par_io[5].cpdat, 0x0F000000);
	setbits_be32(&par_io[5].cpdat, 1 << (32-8+bus));
}
static void rapier_w1_drive_low(int bus)
{
	/* Make sure the correct bus is set */
	rapier_w1_set_bus(bus);
	/* Drive pin low through PLD */
	*((volatile unsigned char*)(CONFIG_SYS_CPLD_REG_BASE+4)) = 0x02;
}
static void rapier_w1_drive_high(int bus)
{
	/* Make sure the correct bus is set */
	rapier_w1_set_bus(bus);
	/* Drive pin high through PLD */
	*((volatile unsigned char*)(CONFIG_SYS_CPLD_REG_BASE+4)) = 0x00;
}
static int rapier_w1_read_input(int bus)
{
	/* Make sure the correct bus is set */
	rapier_w1_set_bus(bus);
	/* Read value of pin from PLD */
	return *((volatile unsigned char*)(CONFIG_SYS_CPLD_REG_BASE+4)) & 0x01;
}
/* Out master configuration */
struct w1_master rapier48x_w1_master = {
	.num_bus = 4,
	.config_input = 0,
	.config_output = 0,
	.config_pullup = 0,
	.drive_low = rapier_w1_drive_low,
	.drive_high = rapier_w1_drive_high,
	.read_input = rapier_w1_read_input,
};
#endif /* CONFIG_CMD_W1 */

int misc_init_r (void)
{
	u8 dac = 0xff;

	/* Ensure the DAC is set within an acceptable range */
	dac = simple_strtoul(getenv("fancontrol"), NULL, 16);
	if (dac == 0 || dac > 0xff)
		dac = 0xff; /* 12v output on the DAC */
	else if (dac < 0x60)
		dac = 0x60; /* ~5v output on the DAC */

	/* Set fan control */
	i2c_set_bus_num(2); /* LM81 is on bus 2 */
	i2c_write (0x2c, 0x19, 1, &dac, sizeof(dac)); /* LM81 is at address 0x2c */

#ifdef CONFIG_CMD_W1
	/* Register the W1 Master configuration */
	w1_register_master(&rapier48x_w1_master);
#endif

#ifdef CONFIG_DIAG_EPI3
	epi3_setmacaddr();
#endif

	return 0;
}

int checkboard (void)
{
	printf ("Board: Rapier48x\n");
	return 0;
}

phys_size_t
initdram(int board_type)
{
	long dram_size = 0;

	puts("Initializing\n");

#if defined(CONFIG_DDR_DLL)
	/*
	 * Work around to stabilize DDR DLL MSYNC_IN.
	 * Errata DDR9 seems to have been fixed.
	 * This is now the workaround for Errata DDR11:
	 *    Override DLL = 1, Course Adj = 1, Tap Select = 0
	 */
	volatile ccsr_gur_t *gur =
			(void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);

	out_be32(&gur->ddrdllcr, 0x81000000);
	udelay(200);
#endif

	/* Fixed configuratiojn for SDRAM */
	dram_size = fixed_sdram();

	/* Setup TLB for SDRAM */
	dram_size = setup_ddr_tlbs(dram_size / 0x100000);
	dram_size *= 0x100000;

	puts("    DDR: ");
	return dram_size;
}

phys_size_t fixed_sdram(void)
{
	volatile ccsr_ddr_t *ddr = (void *)(CONFIG_SYS_MPC85xx_DDR_ADDR);

	u32 temp_sdram_cfg = CONFIG_SYS_DDR_SDRAM_CFG & ~SDRAM_CFG_MEM_EN;

	out_be32(&ddr->cs2_bnds, CONFIG_SYS_DDR_CS2_BNDS);
	out_be32(&ddr->cs2_config, CONFIG_SYS_DDR_CS2_CONFIG);

	out_be32(&ddr->timing_cfg_3, CONFIG_SYS_DDR_TIMING_3);
	out_be32(&ddr->timing_cfg_0, CONFIG_SYS_DDR_TIMING_0);
	out_be32(&ddr->timing_cfg_1, CONFIG_SYS_DDR_TIMING_1);
	out_be32(&ddr->timing_cfg_2, CONFIG_SYS_DDR_TIMING_2);

	out_be32(&ddr->sdram_cfg_2, CONFIG_SYS_DDR_SDRAM_CFG_2);
	out_be32(&ddr->sdram_mode, CONFIG_SYS_DDR_SDRAM_MODE);
	out_be32(&ddr->sdram_mode_2, CONFIG_SYS_DDR_SDRAM_MODE_2);
	out_be32(&ddr->sdram_interval, CONFIG_SYS_DDR_SDRAM_INTERVAL);
	out_be32(&ddr->sdram_data_init, CONFIG_SYS_DDR_DATA_INIT);
	out_be32(&ddr->sdram_clk_cntl, CONFIG_SYS_DDR_SDRAM_CLK_CNTL);

	out_be32(&ddr->timing_cfg_4, CONFIG_SYS_DDR_TIMING_4);
	out_be32(&ddr->timing_cfg_5, CONFIG_SYS_DDR_TIMING_5);
	out_be32(&ddr->ddr_zq_cntl, CONFIG_SYS_DDR_ZQ_CNTL);
	out_be32(&ddr->ddr_wrlvl_cntl, CONFIG_SYS_DDR_WRLVL_CNTL);
	out_be32(&ddr->sdram_cfg_2, CONFIG_SYS_DDR_SDRAM_CFG_2);
#if defined (CONFIG_DDR_ECC)
	out_be32(&ddr->err_int_en, CONFIG_SYS_DDR_ERR_INT_EN);
	out_be32(&ddr->err_disable, CONFIG_SYS_DDR_ERR_DIS);
	out_be32(&ddr->err_sbe, CONFIG_SYS_DDR_SBE);
	temp_sdram_cfg |= SDRAM_CFG_ECC_EN;
#endif
	/* Set, but do not enable the memory */
	out_be32(&ddr->sdram_cfg, temp_sdram_cfg);
	udelay(500);
	asm("sync;isync");

	/* Let the controller go */
	out_be32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_MEM_EN);

	/* Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done.  */
	while (in_be32(&ddr->sdram_cfg_2) & 0x10) {
		udelay(1000);		/* throttle polling rate */
	}

	return CONFIG_SYS_SDRAM_SIZE * 1024 * 1024;
}

/*
 * Initialize Local Bus
 */
void
local_bus_init(void)
{
	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
	volatile ccsr_lbc_t *lbc = (void *)(CONFIG_SYS_MPC85xx_LBC_ADDR);

	uint clkdiv;
	uint lbc_hz;
	sys_info_t sysinfo;

	get_sys_info(&sysinfo);
	clkdiv = (lbc->lcrr & LCRR_CLKDIV) * 2;
	lbc_hz = sysinfo.freqSystemBus / 1000000 / clkdiv;

	out_be32(&gur->lbiuiplldcr1, 0x00078080);
	if (clkdiv == 16)
		out_be32(&gur->lbiuiplldcr0, 0x7c0f1bf0);
	else if (clkdiv == 8)
		out_be32(&gur->lbiuiplldcr0, 0x6c0f1bf0);
	else if (clkdiv == 4)
		out_be32(&gur->lbiuiplldcr0, 0x5c0f1bf0);

	out_be32(&lbc->lcrr, (u32)in_be32(&lbc->lcrr)| 0x00030000);
}

#ifdef CONFIG_PCIE1
static struct pci_controller pcie1_hose;
#endif  /* CONFIG_PCIE1 */

#ifdef CONFIG_PCI
void pci_init_board(void)
{
	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
	struct fsl_pci_info pci_info[1];
	u32 devdisr, pordevsr, io_sel;
	int first_free_busno = 0;
	int num = 0;

	int pcie_ep, pcie_configured;

	devdisr = in_be32(&gur->devdisr);
	pordevsr = in_be32(&gur->pordevsr);
	io_sel = (pordevsr & MPC85xx_PORDEVSR_IO_SEL) >> 19;

	debug ("   pci_init_board: devdisr=%x, io_sel=%x\n", devdisr, io_sel);

#ifdef CONFIG_PCIE1
	pcie_configured = is_fsl_pci_cfg(LAW_TRGT_IF_PCIE_1, io_sel);

	if (pcie_configured && !(devdisr & MPC85xx_DEVDISR_PCIE)){
		SET_STD_PCIE_INFO(pci_info[num], 1);
		pcie_ep = fsl_setup_hose(&pcie1_hose, pci_info[num].regs);
		printf ("    PCIE1 connected to Slot as %s (base addr %lx)\n",
				pcie_ep ? "Endpoint" : "Root Complex",
				pci_info[num].regs);
		first_free_busno = fsl_pci_init_port(&pci_info[num++],
					&pcie1_hose, first_free_busno);
	} else {
		printf ("    PCIE1: disabled\n");
	}

	puts("\n");
#else
	setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_PCIE); /* disable */
#endif

}
#endif /* CONFIG_PCI */

#if defined(CONFIG_OF_BOARD_SETUP)
static unsigned int p1_pic_bay0_pio_map[] = {
	0x0, 0x6, 0x2, 0x0, 0x3, 0x0,	/* SCC RX, in: A20-d2 [UCC2 RXD] */
	0x0, 0x0, 0x1, 0x0, 0x3, 0x0,	/* SCC TX, out: A14-d2 (/PIC2_OE) [UCC2 TXD] */
	0x0, 0x4, 0x1, 0x0, 0x2, 0x0,	/* SCC RTS, out: A18-d2 (/PIC2_OE) [UCC2 RTS] */
	/* P1 hack for t1 (Just using output enable to drive signal)
	 * Also needs a code change to invert it. */
	0x4, 0xd, 0x1, 0x0, 0x0, 0x0,	/* SCC CTS, in: A26-d3 [UCC2 CTS] out: E6 (E13) */
	0x43000002, 0x00000d17, 0x0, 0x0, 0x30, 0x0,	/* SCC CD, in: A27-d3 [UCC2 CD] out: E7 (E10) */
	0x2, 0x8, 0x2, 0x0, 0x2, 0x0,	/* SCC RCK in: C2-d1 [CLK3] */
	0x47000322, 0x0008090f, 0x0, 0x0, 0x31, 0x0,	/* SCC TCK in: C3-d2 (/PIC2_OE) [CLK4] out: C19-d1 (D6) [BRGO9] */
	0x0, 0x5, 0x2, 0x0, 0x1, 0x0,	/* UCC2_TDMRXD in: F17-d1 (/PIC2_OE) [TDM2A RXD] */
	0x0, 0xa, 0x1, 0x0, 0x1, 0x0,	/* UCC2_TDMTXD out: F16-d1 (/PIC2_OE) [TDM2A TXD] */
	0x2, 0x0, 0x2, 0x0, 0x1, 0x0,	/* UCC2_TDMCLK in: C13-d2 (/PIC2_OE) [CLK14] */
	0x0, 0xb, 0x2, 0x0, 0x2, 0x0,	/* UCC2_TDMFSP in: F18-d3 (/PIC2_OE) [TDM2A RSYNC] */
	0x5, 0x16, 0x1, 0x0, 0x0, 0x0,	/* PIC RESET out: F21 */
	0x3, 0x16, 0x2, 0x0, 0x0, 0x0,	/* TE/NT_SELECT: D22 */
	0x4, 0x3, 0x2, 0x0, 0x0, 0x0	/* T1-SELECT: E3 */
};

static unsigned int p1_pic_bay1_pio_map[] = {
	0x0, 0x14, 0x2, 0x0, 0x2, 0x0,	/* SCC RX, in: A20-d2 [UCC2 RXD] */
	0x0, 0xe, 0x1, 0x0, 0x2, 0x0,	/* SCC TX, out: A14-d2 (/PIC2_OE) [UCC2 TXD] */
	0x0, 0x12, 0x1, 0x0, 0x2, 0x0,	/* SCC RTS, out: A18-d2 (/PIC2_OE) [UCC2 RTS] */
	0x47000404, 0x000a1a06, 0x0, 0x0, 0x30, 0x0,	/* SCC CTS, in: A26-d3 [UCC2 CTS] out: E6 (E10) */
	0x43000004, 0x00001b07, 0x0, 0x0, 0x30, 0x0,	/* SCC CD, in: A27-d3 [UCC2 CD] out: E7 (E10) */
	0x2, 0x2, 0x2, 0x0, 0x1, 0x0,	/* SCC RCK in: C2-d1 [CLK3] */
	0x47000322, 0x00060313, 0x0, 0x0, 0x21, 0x0,	/* SCC TCK in: C3-d2 (/PIC2_OE) [CLK4] out: C19-d1 (D6) [BRGO9] */
	0x5, 0x11, 0x2, 0x0, 0x1, 0x0,	/* UCC2_TDMRXD in: F17-d1 (/PIC2_OE) [TDM2A RXD] */
	0x5, 0x10, 0x1, 0x0, 0x1, 0x0,	/* UCC2_TDMTXD out: F16-d1 (/PIC2_OE) [TDM2A TXD] */
	0x2, 0x0d, 0x2, 0x0, 0x2, 0x0,	/* UCC2_TDMCLK in: C13-d2 (/PIC2_OE) [CLK14] */
	0x5, 0x12, 0x2, 0x0, 0x3, 0x0,	/* UCC2_TDMFSP in: F18-d3 (/PIC2_OE) [TDM2A RSYNC] */
	0x5, 0x15, 0x1, 0x0, 0x0, 0x0,	/* PIC RESET out: F21 */
	0x3, 0x17, 0x2, 0x0, 0x0, 0x0,	/* TE/NT_SELECT: D23 */
	0x4, 0x14, 0x2, 0x0, 0x0, 0x0	/* T1-SELECT: E20 */
};

static unsigned int p1_pic_bay2_pio_map[] = {
	0x1, 0x3, 0x2, 0x0, 0x3, 0x0,	/* SCC RX, in: B3-d3 [UCC3 RXD] */
	0x0, 0x1d, 0x1, 0x0, 0x2, 0x0,	/* SCC TX, out: A29-d2 (/PIC3_OE) [UCC3 TXD] */
	0x1, 0x1, 0x1, 0x0, 0x1, 0x0,	/* SCC RTS, out: B1-d1 (/PIC3_OE) [UCC3 RTS] */
	0x47000414, 0x00050903, 0x0, 0x0, 0x30, 0x0,	/* SCC CTS, in: B9-d3 [UCC3 CTS] out: E3 (E5) */
	0x43000014, 0x00000a04, 0x0, 0x0, 0x30, 0x0,	/* SCC CD, in: B10-d3 [UCC3 CD] out: E4 (E5) */
	0x2, 0xa, 0x2, 0x0, 0x1, 0x0,	/* SCC RCK, in: C10-d1 [CLK11] */
	0x47000322, 0x00070b12, 0x0, 0x0, 0x12, 0x0,	/* SCC TCK, in: C11-d1 (/PIC3_OE) [CLK12] out: C18-d2 (D7) [BRGO8] */
	0x1, 0x11, 0x2, 0x0, 0x1, 0x0,	/* UCC3_TDMRXD, in: B17-d1 (/PIC3_OE) [TDM1D RXD] */
	0x1, 0x16, 0x1, 0x0, 0x1, 0x0,	/* UCC3_TDMTXD, out: B22-d1 (/PIC3_OE) [TDM1D TXD] */
	0x2, 0x01, 0x2, 0x0, 0x1, 0x0,	/* UCC3_TDMCLK, in: C1-d1 (/PIC3_OE) [CLK2] */
	0x1, 0x17, 0x2, 0x0, 0x2, 0x0,	/* UCC3_TDMFSP, in: B23-d2 (/PIC3_OE) [TDM1D RSYNC] */
	0x5, 0x14, 0x1, 0x0, 0x0, 0x0,	/* PIC RESET, out: F20 */
	0x4, 0x1e, 0x2, 0x0, 0x0, 0x0,	/* TE/NT_SELECT: E30 */
	0x4, 0x15, 0x2, 0x0, 0x0, 0x0	/* T1-SELECT: E21 */
};

static unsigned int p1_pic_bay3_pio_map[] = {
	0x1, 0x12, 0x2, 0x0, 0x2, 0x0,	/* SCC RX, in: B18-d2 [UCC4 RXD] */
	0x1, 0xc, 0x1, 0x0, 0x2, 0x0,	/* SCC TX, out: B12-d2 (/PIC4_OE) [UCC4 TXD] */
	0x1, 0x10, 0x1, 0x0, 0x2, 0x0,	/* SCC RTS, out: B16-d2 (/PIC4_OE) [UCC4 RTS] */
	0x47000414, 0x00021800, 0x0, 0x0, 0x30, 0x0,	/* SCC CTS, in: B24-d3 [UCC4 CTS] out: E0 (E2) */
	0x43000014, 0x00001901, 0x0, 0x0, 0x30, 0x0,	/* SCC CD, in: B25-d3 [UCC4 CD] out: E1 (E2) */
	0x2, 0x6, 0x2, 0x0, 0x2, 0x0,	/* SCC RCK, in: C6-d2 [CLK7] */
	0x47000322, 0x00050715, 0x0, 0x0, 0x12, 0x0,	/* SCC TCK, in: C7-d1 (/PIC4_OE) [CLK8] out: C21-d2 (D5) [BRGO10] */
	0x3, 0x12, 0x2, 0x0, 0x1, 0x0,	/* UCC4_TDMRXD, in: D18-d1 (/PIC4_OE) [TDM2D RXD] */
	0x3, 0x16, 0x1, 0x0, 0x1, 0x0,	/* UCC4_TDMTXD, out: D22-d1 (/PIC4_OE) [TDM2D TXD] */
	0x2, 0x19, 0x2, 0x0, 0x1, 0x0,	/* UCC4_TDMCLK, in: C25-d1 (/PIC4_OE) [CLK26] */
	0x3, 0x17, 0x2, 0x0, 0x1, 0x0,	/* UCC4_TDMFSP, in: D23-d1 (/PIC4_OE) [TDM2D RSYNC] */
	0x5, 0x13, 0x1, 0x0, 0x0, 0x0,	/* PIC RESET, out: F19 */
	0x4, 0x1f, 0x2, 0x0, 0x0, 0x0,	/* TE/NT_SELECT: E31 */
	0x3, 0x10, 0x2, 0x0, 0x0, 0x0	/* T1-SELECT: D16 */
};

static int do_p1_fixup(void *blob)
{
	int offset;
	struct fdt_property *prop;
	unsigned long interrupts[2];
	unsigned long val;

	printf("Rapier48x X1 DTS fixups\r\n");

	/* Fixup Pic Bay 0 */
	val = fdt_get_phandle(blob, fdt_node_offset_by_compatible(blob, -1, "chrp,open-pic"));
	do_fixup_by_path_u32(blob, "/soc/pic_bay0", "interrupt-parent", val, 0);
	do_fixup_by_path(blob, "/soc/pic_bay0", "pio-map", p1_pic_bay0_pio_map, sizeof(p1_pic_bay0_pio_map), 0);
	interrupts[0] = 3;
	interrupts[1] = 1;
	do_fixup_by_path(blob, "/soc/pic_bay0", "interrupts", &interrupts, 8, 0);

	/* Fixup Pic Bay 1 */
	val = fdt_get_phandle(blob, fdt_node_offset_by_compatible(blob, -1, "chrp,open-pic"));
	do_fixup_by_path_u32(blob, "/soc/pic_bay1", "interrupt-parent", val, 0);
	do_fixup_by_path(blob, "/soc/pic_bay1", "pio-map", p1_pic_bay1_pio_map, sizeof(p1_pic_bay1_pio_map), 0);
	interrupts[0] = 4;
	interrupts[1] = 1;
	do_fixup_by_path(blob, "/soc/pic_bay1", "interrupts", &interrupts, 8, 0);
	do_fixup_by_path_u32(blob, "/soc/pic_bay1", "tdm-clk", 14, 0);
	do_fixup_by_path_u32(blob, "/soc/pic_bay1", "brg", 8, 0);

	/* Fixup Pic Bay 2 */
	val = fdt_get_phandle(blob, fdt_node_offset_by_compatible(blob, -1, "chrp,open-pic"));
	do_fixup_by_path_u32(blob, "/soc/pic_bay2", "interrupt-parent", val, 0);
	do_fixup_by_path(blob, "/soc/pic_bay2", "pio-map", p1_pic_bay2_pio_map, sizeof(p1_pic_bay2_pio_map), 0);
	interrupts[0] = 5;
	interrupts[1] = 1;
	do_fixup_by_path(blob, "/soc/pic_bay2", "interrupts", &interrupts, 8, 0);
	do_fixup_by_path_u32(blob, "/soc/pic_bay2", "scc-clk-rx", 11, 0);
	do_fixup_by_path_u32(blob, "/soc/pic_bay2", "tdm-clk", 2, 0);
	do_fixup_by_path_u32(blob, "/soc/pic_bay2", "tdm-bus", 4, 0);
	do_fixup_by_path_u32(blob, "/soc/pic_bay2", "brg", 9, 0);

	/* Fixup Pic Bay 3 */
	val = fdt_get_phandle(blob, fdt_node_offset_by_compatible(blob, -1, "chrp,open-pic"));
	do_fixup_by_path_u32(blob, "/soc/pic_bay3", "interrupt-parent", val, 0);
	do_fixup_by_path(blob, "/soc/pic_bay3", "pio-map", p1_pic_bay3_pio_map, sizeof(p1_pic_bay3_pio_map), 0);
	interrupts[0] = 6;
	interrupts[1] = 1;
	do_fixup_by_path(blob, "/soc/pic_bay3", "interrupts", &interrupts, 8, 0);
	do_fixup_by_path_u32(blob, "/soc/pic_bay3", "tdm-clk", 26, 0);
	do_fixup_by_path_u32(blob, "/soc/pic_bay3", "tdm-bus", 4, 0);

	/* Fixup Switch Chip 1 */
	interrupts[0] = 0;
	interrupts[1] = 1;
	do_fixup_by_path(blob, "/pcie/switch1", "interrupts", &interrupts, 8, 0);
	do_fixup_by_path_u32(blob, "/pcie/switch1", "bus", 4, 0);

	/* Fixup Switch Chip 2 */
	interrupts[0] = 1;
	interrupts[1] = 1;
	do_fixup_by_path(blob, "/pcie/switch2", "interrupts", &interrupts, 8, 0);
	do_fixup_by_path_u32(blob, "/pcie/switch2", "bus", 5, 0);

	/* Fixup FAN IRQ and fan present gpios */
	interrupts[0] = 2;
	interrupts[1] = 3;
	do_fixup_by_compat(blob, "atl-lm81", "interrupts", &interrupts, 8, 0);
	offset = fdt_node_offset_by_compatible(blob, -1, "atl-lm81");
	if (offset) {
		prop = fdt_getprop_w(blob, offset, "gpios", 0);
		if (prop != NULL) {
			((u8*)prop->data)[4] = 14;
			fdt_setprop(blob, offset, "gpios", (u8*)prop->data, prop->len);
		}
	}

	/* Fixup SFP IRQ - not supported on P1 */
	interrupts[0] = -1;
	interrupts[1] = 3;
	do_fixup_by_compat(blob, "atl-pca9555d", "interrupts", &interrupts, 8, 0);

	return 0;
}

void ft_board_setup(void *blob, bd_t *bd)
{
#ifdef CONFIG_DIAG_EPI3
	epi3Personality *personality = epi3_getcurrent();
#endif
	ft_cpu_setup(blob, bd);

#ifdef CONFIG_PCIE1
	ft_fsl_pci_setup(blob, "pci1", &pcie1_hose);
#endif

	/* Fixups for P1 */
#ifdef CONFIG_DIAG_EPI3
	if (personality && personality->epiPcbRev == 0x8000) {
		do_p1_fixup(blob);
	}
#endif
}
#endif

/*
 *  Not used by this product
 */
u32 atl_get_offset_from_base(void)
{
	return 0x0; /* 64MB system, no change, use _BASE Macros in config header */
}

/*
 * Get location of U-Boot environement.
 */
u32 atl_get_env_addr(void)
{
	return CONFIG_ENV_ADDR;
}

/*
 * Used by bootmenu to determine weather or not to print
 * option '5' (EPROM) in upgrade bootloader menu
 */
int atl_bootrom_board_attached(void)
{
	// TODO1558 - can we detect this?
	return 0; /* no such thing on this product */
}

/*
 * Get the size of the main JFFS2 partition.
 */
u32 atl_get_jffs2_part_size(void)
{
	u32 partition_size = 0;
	int i;

	for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
		if (flash_info[i].flash_id != FLASH_UNKNOWN) {
			partition_size += flash_info[i].size;
		}
	}
	if (partition_size != 0) {
		partition_size -= (CONFIG_UBOOT_SIZE +
				CONFIG_ENV_SECT_SIZE +
#ifdef CONFIG_DIAGNOSTICS
				CONFIG_EPI3_SIZE);
#else
				0);
#endif
	}
	return partition_size;
}

/*
 * Get the location of the epi3 block
 */
u32 atl_get_epi3_location(void)
{
        return (CONFIG_EPI3_LOCATION_BASE + atl_get_offset_from_base());
}
