/*
 * Startup Code for CQ-FRK-FM3 w/ LFCQ1
 *
 * Copyright (c) 2014 Yoshinori Sato <ysato@users.sourceforge.jp>
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

#include <common.h>
#include <netdev.h>
#include <asm/io.h>

#define GPIO_PFR0   0x40033000
#define GPIO_PFR1   0x40033004
#define GPIO_PFR2   0x40033008
#define GPIO_PFR3   0x4003300C
#define GPIO_DDR3   0x4003320C
#define GPIO_PFR4   0x40033010
#define GPIO_PFR5   0x40033014
#define GPIO_PFR6   0x40033018
#define GPIO_DDR6   0x40033218
#define GPIO_PDIR6  0x40033318
#define GPIO_PFR7   0x4003301C
#define GPIO_PFR8   0x40033020
#define GPIO_PFR9   0x40033024
#define GPIO_PFRC   0x40033030
#define GPIO_PFRD   0x40033034
#define GPIO_PFRF   0x4003303C
#define GPIO_DDRF   0x4003323C
#define GPIO_PZRF   0x4003373C
#define GPIO_PDORF  0x4003343C
#define GPIO_ADE    0x40033500
#define GPIO_SPSR   0x40033580

#define GPIO_PCR3   0x4003310C
#define GPIO_EPFR00 0x40033600
#define GPIO_EPFR07 0x4003361C
#define GPIO_EPFR08 0x40033620
#define GPIO_EPFR10 0x40033628
#define GPIO_EPFR11 0x4003362C
#define GPIO_EPFR14 0x40033638

#define BUS_MODE0   0x4003F000
#define BUS_MODE1   0x4003F004
#define BUS_MODE2   0x4003F008
#define BUS_MODE3   0x4003F00C
#define BUS_TIM0    0x4003F020
#define BUS_TIM1    0x4003F024
#define BUS_TIM2    0x4003F028
#define BUS_TIM3    0x4003F02C
#define BUS_AREA0   0x4003F040
#define BUS_AREA1   0x4003F044
#define BUS_AREA2   0x4003F048
#define BUS_AREA3   0x4003F04C
#define BUS_DCLKR   0x4003F300

#define ETH_MODE    0x40066000
#define ETH_CLKG    0x40066008

#define UECLK_UCCR	0x40036000
#define UECLK_UPCR1	0x40036004
#define UECLK_UPCR2	0x40036008
#define UECLK_UPCR3	0x4003600C
#define UECLK_UPCR4	0x40036010
#define UECLK_UP_STR	0x40036014
#define UECLK_UPINT_ENR	0x40036018
#define UECLK_UPINT_CLR	0x4003601C
#define UECLK_UPINT_STR	0x40036020
#define UECLK_UPCR5	0x40036024
#define UECLK_UPCR6	0x40036028
#define UECLK_UPCR7	0x4003602C
#define UECLK_USBEN0	0x40036030
#define UECLK_USBEN1	0x40036034

void mb9bfxxx_udc_probe(void);

DECLARE_GLOBAL_DATA_PTR;
int board_early_init_f(void)
{
        writel(readl(GPIO_EPFR00) | 0x00000200, GPIO_EPFR00);
        writel(readl(GPIO_EPFR07) | 0x03c05040, GPIO_EPFR07);
        writel(readl(GPIO_EPFR08) | 0x002a00f0, GPIO_EPFR08);

        writel(0x7FFFC3B7, GPIO_EPFR10);
        writel(0x01FFFFFE, GPIO_EPFR11);
	writel(0x37FC0000, GPIO_EPFR14);
        writel(readl(GPIO_ADE) & 0xC0FF000F, GPIO_ADE);
	writel(readl(GPIO_SPSR) | 0x00000030, GPIO_SPSR);

        writel(readl(GPIO_PFR0) | 0x0000007F, GPIO_PFR0);
        writel(readl(GPIO_PFR1) | 0x0000FFF0, GPIO_PFR1);
        writel(readl(GPIO_PFR2) | 0x000003F1, GPIO_PFR2);
        writel(readl(GPIO_PFR3) | 0x000001CE, GPIO_PFR3);
        writel(readl(GPIO_PFR4) | 0x00007C00, GPIO_PFR4);
        writel(readl(GPIO_PFR5) | 0x00000C2D, GPIO_PFR5);
	writel(readl(GPIO_PFR6) & ~0x00000004, GPIO_PFR6);
	writel(readl(GPIO_PFR6) | 0x00000002, GPIO_PFR6);
	writel(readl(GPIO_DDR6) & ~0x00000004, GPIO_DDR6);
        writel(readl(GPIO_PFR7) | 0x000007FF, GPIO_PFR7);
        writel(readl(GPIO_PFR8) | 0x0000000F, GPIO_PFR8);
        writel(readl(GPIO_PFR9) | 0x0000001F, GPIO_PFR9);
        writel(0x0000F1FF, GPIO_PFRC);
        writel(0x0000000F, GPIO_PFRD);
        writel(readl(GPIO_PFRF) | 0x00000060, GPIO_PFRF);
	writel(readl(GPIO_PFRF) & ~0x00000008, GPIO_PFRF);
	writel(readl(GPIO_PZRF) | 0x00000008, GPIO_PZRF);
	writel(readl(GPIO_DDRF) | 0x00000008, GPIO_DDRF);
	writel(readl(GPIO_PDORF)| 0x00000008, GPIO_PDORF);
 
        writel(0x00000013, BUS_DCLKR);

        writel(0x00000809, BUS_MODE0);
        writel(0x00020012, BUS_TIM0);
        writel(0x000F0000, BUS_AREA0);

        writel(0x00000849, BUS_MODE1);
        writel(0x01030013, BUS_TIM1);
        writel(0x000F0010, BUS_AREA1);

        writel(0x00000809, BUS_MODE2);
        writel(0x01030013, BUS_TIM2);
        writel(0x000F0020, BUS_AREA2);

	writel(0x00000848, BUS_MODE3);
	writel(0x05170027, BUS_TIM3);
	writel(0x000F0030, BUS_AREA3);

	return 0;
}

int board_init(void)
{
#if defined (CONFIG_USB_MB9BFXXX) || defined(CONFIG_FM3_UDC)
	writeb(readb(UECLK_UCCR) & ~0x09, UECLK_UCCR);
	while(readb(UECLK_UCCR) & 0x09);
	writeb(0x06, UECLK_UCCR);
	writeb(0x00, UECLK_UPCR1);
	writeb(0x07, UECLK_UPCR2);
	writeb(0x00, UECLK_UPCR3);
	writeb(23 , UECLK_UPCR4);
	writeb(1, UECLK_UPCR5);
	writeb(0x00, UECLK_UPINT_ENR);
	writeb(0x01, UECLK_UPCR1);
	while(!(readb(UECLK_UP_STR) & 0x01));
	writeb(0x0f, UECLK_UCCR);
	readb(UECLK_UCCR);
	readb(UECLK_UCCR);
	readb(UECLK_UCCR);
	readb(UECLK_UCCR);
	readb(UECLK_UCCR);
	writeb(0x01, UECLK_USBEN0);
	writeb(0x01, UECLK_USBEN1);
#endif
	return 0;
}

int board_late_init()
{
#if defined (CONFIG_FM3_UDC)
	mb9bfxxx_udc_probe();
#endif
	return 0;
}

#ifdef CONFIG_CMD_NET
int board_eth_init(bd_t *bis)
{
	writel(1 << CONFIG_FM3_MAC_CH, ETH_CLKG);
	writel((CONFIG_FM3_MAC_CH << 28) |
	       1 << (8 + CONFIG_FM3_MAC_CH) |
	       1, ETH_MODE);
	udelay(1);
	writel((CONFIG_FM3_MAC_CH << 28) |
	       1, ETH_MODE);

	return fm3_eth_initialize(bis, CONFIG_FM3_MAC_CH);
}
#endif

int dram_init(void)
{
	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
	return 0;
}

void reset_cpu(ulong addr)
{
	writel(0x05fa0001, 0xe000ed0c);
	for(;;);
}

