#include <stdint.h>
#include <arch/io.h>
#include <arch/pciconf.h>
#include <delay.h>
#include "cpc710.h"
#include "cpc710_pci.h"

extern void setCPC710(uint32_t, uint32_t);

void
setCPC710_PCI32(uint32_t addr, uint32_t data)
{
	out_be32((unsigned *)(CPC710_PCI32_CONFIG + addr), data);
}

#if 0
void
setCPC710_PCI64(uint32_t addr, uint32_t data)
{
	out_be32((unsigned *)(CPC710_PCI64_CONFIG + addr), data);
}
#endif

void
cpc710_pci_init(void)
{
	/* Enable PCI32 */
	setCPC710(CPC710_CPC0_PCICNFR, 0x80000002); /* activate PCI32 config */
	setCPC710(CPC710_CPC0_PCIBAR,  CPC710_PCI32_CONFIG); /* PCI32 base address */
	setCPC710(CPC710_CPC0_PCIENB,  0x80000000); /* enable addr space */
	setCPC710(CPC710_CPC0_PCICNFR, 0x00000000); /* config done */

	/* Reset PCI Status register */
	pci_ppc_write_config16(0, 0, 0x06, 0xffff);

	/* Configure bus number */
	pci_ppc_write_config16(0, 0, 0x40, 0);

	/* Set PCI configuration registers */
	setCPC710_PCI32(CPC710_PCIL0_PCIDG,  0x40000000);
	setCPC710_PCI32(CPC710_PCIL0_PIBAR,  0x00000000);
	setCPC710_PCI32(CPC710_PCIL0_PMBAR,  0x00000000);
	setCPC710_PCI32(CPC710_PCIL0_PR,     0xa000c000);
	setCPC710_PCI32(CPC710_PCIL0_ACR,    0xfc000000);
	setCPC710_PCI32(CPC710_PCIL0_MSIZE,  CPC710_PCI32_MEM_SIZE);
	setCPC710_PCI32(CPC710_PCIL0_IOSIZE, CPC710_PCI32_IO_SIZE);
	setCPC710_PCI32(CPC710_PCIL0_SMBAR,  CPC710_PCI32_MEM_BASE);
	setCPC710_PCI32(CPC710_PCIL0_SIBAR,  CPC710_PCI32_IO_BASE);
	setCPC710_PCI32(CPC710_PCIL0_CTLRW,  0x00000000);
	setCPC710_PCI32(CPC710_PCIL0_PSSIZE, 0x00000080);
	setCPC710_PCI32(CPC710_PCIL0_BARPS,  0x00000000);
	setCPC710_PCI32(CPC710_PCIL0_PSBAR,  0x00000080);
	setCPC710_PCI32(CPC710_PCIL0_BPMDLK, 0x00000000);
	setCPC710_PCI32(CPC710_PCIL0_TPMDLK, 0x00000000);
	setCPC710_PCI32(CPC710_PCIL0_BIODLK, 0x00000000);
	setCPC710_PCI32(CPC710_PCIL0_TIODLK, 0x00000000);

	/* Enable address space */
	pci_ppc_write_config16(0, 0, 0x04, 0xfda7);

	setCPC710_PCI32(CPC710_PCIL0_CRR,    0xfc000000);

	/*
	 * wait for PCI to reset
	 */
	udelay(250);

#if 0
	/* Enable PCI64 */
	setCPC710(CPC710_CPC0_PCICNFR, 0x80000003); /* activate PCI64 config */
	setCPC710(CPC710_CPC0_PCIBAR,  CPC710_PCI64_CONFIG); /* PCI64 base address */
	setCPC710(CPC710_CPC0_PCIENB,  0x80000000); /* enable addr space */
	setCPC710(CPC710_CPC0_PCICNFR, 0x00000000); /* config done */

	/* Reset PCI Status register */
	setCPC710_PCI64(CPC710_PCIL0_CFGADDR, 0x06000080);
	setCPC710_PCI64_16(CPC710_PCIL0_CFGDATA, 0xffff);

	/* Reset G_INT[A-D] bits in INT_RESET */
	setCPC710_PCI64(CPC710_PCIL0_CFGADDR, 0x68000080);
	setCPC710_PCI64(CPC710_PCIL0_CFGDATA, 0x0f000000);

	/* Configure bus number BUSNO=1, SUBNO=1 */
	setCPC710_PCI64(CPC710_PCIL0_CFGADDR, 0x40000080);
	setCPC710_PCI64_16(CPC710_PCIL0_CFGDATA, 0x0101);

	/* Set PCI configuration registers */
	setCPC710_PCI64(CPC710_PCIL0_PSEA,   0x00000000);
	setCPC710_PCI64(CPC710_PCIL0_PCIDG,  0xc0000000);
	setCPC710_PCI64(CPC710_PCIL0_PIBAR,  0x00000000);
	setCPC710_PCI64(CPC710_PCIL0_PMBAR,  0x00000000);
	setCPC710_PCI64(CPC710_PCIL0_PR,     0x80008000);
	setCPC710_PCI64(CPC710_PCIL0_ACR,    0xff000000);
	setCPC710_PCI64(CPC710_PCIL0_MSIZE,  CPC710_PCI64_MEM_SIZE);
	setCPC710_PCI64(CPC710_PCIL0_IOSIZE, CPC710_PCI64_IO_SIZE);
	setCPC710_PCI64(CPC710_PCIL0_SMBAR,  CPC710_PCI64_MEM_BASE);
	setCPC710_PCI64(CPC710_PCIL0_SIBAR,  CPC710_PCI64_IO_BASE);
	setCPC710_PCI64(CPC710_PCIL0_CTLRW,  0x02000000);
	setCPC710_PCI64(CPC710_PCIL0_PSSIZE, 0x00000080);

	/* Config PSBAR for PCI64 */
	setCPC710_PCI64(CPC710_PCIL0_CFGADDR, 0x10000080);
	setCPC710_PCI64(CPC710_PCIL0_CFGDATA, 0x00000080);

	setCPC710_PCI64(CPC710_PCIL0_BARPS,   0x00000000);
	setCPC710_PCI64(CPC710_PCIL0_INTSET,  0x00000000);

	/* Enable address space */
	setCPC710_PCI64(CPC710_PCIL0_CFGADDR, 0x04000180);
	setCPC710_PCI64_16(CPC710_PCIL0_CFGDATA, 0xfda7);

	setCPC710_PCI64(CPC710_PCIL0_CRR,    0xfc000000);

	/*
	 * wait for PCI to reset
	 */
	udelay(250);
#endif
}