apf27.c 6.35 KB
Newer Older
정종선 committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
/*
 * Copyright (C) 2008-2013 Eric Jarrige <eric.jarrige@armadeus.org>
 *
 * based on the files by
 * Sascha Hauer, Pengutronix
 *
 * SPDX-License-Identifier:    GPL-2.0+
 */

#include <common.h>
#include <environment.h>
#include <jffs2/jffs2.h>
#include <nand.h>
#include <netdev.h>
#include <asm/io.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/gpio.h>
#include <asm/gpio.h>
#include <asm/errno.h>
#include "apf27.h"
#include "crc.h"
#include "fpga.h"

DECLARE_GLOBAL_DATA_PTR;

/*
 * Fuse bank 1 row 8 is "reserved for future use" and therefore available for
 * customer use. The APF27 board uses this fuse to store the board revision:
 * 0: initial board revision
 * 1: first revision - Presence of the second RAM chip on the board is blown in
 *     fuse bank 1 row 9  bit 0 - No hardware change
 * N: to be defined
 */
static u32 get_board_rev(void)
{
	struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE;

	return readl(&iim->bank[1].fuse_regs[8]);
}

/*
 * Fuse bank 1 row 9 is "reserved for future use" and therefore available for
 * customer use. The APF27 board revision 1 uses the bit 0 to permanently store
 * the presence of the second RAM chip
 * 0: AFP27 with 1 RAM of 64 MiB
 * 1: AFP27 with 2 RAM chips of 64 MiB each (128MB)
 */
static int get_num_ram_bank(void)
{
	struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE;
	int nr_dram_banks = 1;

	if ((get_board_rev() > 0) && (CONFIG_NR_DRAM_BANKS > 1))
		nr_dram_banks += readl(&iim->bank[1].fuse_regs[9]) & 0x01;
	else
		nr_dram_banks = CONFIG_NR_DRAM_POPULATED;

	return nr_dram_banks;
}

static void apf27_port_init(int port, u32 gpio_dr, u32 ocr1, u32 ocr2,
			    u32 iconfa1, u32 iconfa2, u32 iconfb1, u32 iconfb2,
			    u32 icr1, u32 icr2, u32 imr, u32 gpio_dir, u32 gpr,
			    u32 puen, u32 gius)
{
	struct gpio_port_regs *regs = (struct gpio_port_regs *)IMX_GPIO_BASE;

	writel(gpio_dr,   &regs->port[port].gpio_dr);
	writel(ocr1,      &regs->port[port].ocr1);
	writel(ocr2,      &regs->port[port].ocr2);
	writel(iconfa1,   &regs->port[port].iconfa1);
	writel(iconfa2,   &regs->port[port].iconfa2);
	writel(iconfb1,   &regs->port[port].iconfb1);
	writel(iconfb2,   &regs->port[port].iconfb2);
	writel(icr1,      &regs->port[port].icr1);
	writel(icr2,      &regs->port[port].icr2);
	writel(imr,       &regs->port[port].imr);
	writel(gpio_dir,  &regs->port[port].gpio_dir);
	writel(gpr,       &regs->port[port].gpr);
	writel(puen,      &regs->port[port].puen);
	writel(gius,      &regs->port[port].gius);
}

#define APF27_PORT_INIT(n) apf27_port_init(PORT##n, ACFG_DR_##n##_VAL,	  \
	ACFG_OCR1_##n##_VAL, ACFG_OCR2_##n##_VAL, ACFG_ICFA1_##n##_VAL,	  \
	ACFG_ICFA2_##n##_VAL, ACFG_ICFB1_##n##_VAL, ACFG_ICFB2_##n##_VAL, \
	ACFG_ICR1_##n##_VAL, ACFG_ICR2_##n##_VAL, ACFG_IMR_##n##_VAL,	  \
	ACFG_DDIR_##n##_VAL, ACFG_GPR_##n##_VAL, ACFG_PUEN_##n##_VAL,	  \
	ACFG_GIUS_##n##_VAL)

static void apf27_iomux_init(void)
{
	APF27_PORT_INIT(A);
	APF27_PORT_INIT(B);
	APF27_PORT_INIT(C);
	APF27_PORT_INIT(D);
	APF27_PORT_INIT(E);
	APF27_PORT_INIT(F);
}

static int apf27_devices_init(void)
{
	int i;
	unsigned int mode[] = {
		PC5_PF_I2C2_DATA,
		PC6_PF_I2C2_CLK,
		PD17_PF_I2C_DATA,
		PD18_PF_I2C_CLK,
	};

	for (i = 0; i < ARRAY_SIZE(mode); i++)
		imx_gpio_mode(mode[i]);

#ifdef CONFIG_MXC_UART
	mx27_uart1_init_pins();
#endif

#ifdef CONFIG_FEC_MXC
	mx27_fec_init_pins();
#endif

#ifdef CONFIG_MXC_MMC
	mx27_sd2_init_pins();
	imx_gpio_mode((GPIO_PORTF | GPIO_OUT | GPIO_PUEN | GPIO_GPIO | 16));
	gpio_request(PC_PWRON, "pc_pwron");
	gpio_set_value(PC_PWRON, 1);
#endif
	return 0;
}

static void apf27_setup_csx(void)
{
	struct weim_regs *weim = (struct weim_regs *)IMX_WEIM_BASE;

	writel(ACFG_CS0U_VAL, &weim->cs0u);
	writel(ACFG_CS0L_VAL, &weim->cs0l);
	writel(ACFG_CS0A_VAL, &weim->cs0a);

	writel(ACFG_CS1U_VAL, &weim->cs1u);
	writel(ACFG_CS1L_VAL, &weim->cs1l);
	writel(ACFG_CS1A_VAL, &weim->cs1a);

	writel(ACFG_CS2U_VAL, &weim->cs2u);
	writel(ACFG_CS2L_VAL, &weim->cs2l);
	writel(ACFG_CS2A_VAL, &weim->cs2a);

	writel(ACFG_CS3U_VAL, &weim->cs3u);
	writel(ACFG_CS3L_VAL, &weim->cs3l);
	writel(ACFG_CS3A_VAL, &weim->cs3a);

	writel(ACFG_CS4U_VAL, &weim->cs4u);
	writel(ACFG_CS4L_VAL, &weim->cs4l);
	writel(ACFG_CS4A_VAL, &weim->cs4a);

	writel(ACFG_CS5U_VAL, &weim->cs5u);
	writel(ACFG_CS5L_VAL, &weim->cs5l);
	writel(ACFG_CS5A_VAL, &weim->cs5a);

	writel(ACFG_EIM_VAL, &weim->eim);
}

static void apf27_setup_port(void)
{
	struct system_control_regs *system =
		(struct system_control_regs *)IMX_SYSTEM_CTL_BASE;

	writel(ACFG_FMCR_VAL, &system->fmcr);
}

int board_init(void)
{
	gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100;

	apf27_setup_csx();
	apf27_setup_port();
	apf27_iomux_init();
	apf27_devices_init();
#if defined(CONFIG_FPGA)
	APF27_init_fpga();
#endif


	return 0;
}

int dram_init(void)
{
	gd->ram_size = get_ram_size((void *)PHYS_SDRAM_1, PHYS_SDRAM_1_SIZE);
	if (get_num_ram_bank() > 1)
		gd->ram_size += get_ram_size((void *)PHYS_SDRAM_2,
					     PHYS_SDRAM_2_SIZE);

	return 0;
}

void dram_init_banksize(void)
{
	gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
	gd->bd->bi_dram[0].size  = get_ram_size((void *)PHYS_SDRAM_1,
						PHYS_SDRAM_1_SIZE);
	gd->bd->bi_dram[1].start = PHYS_SDRAM_2;
	if (get_num_ram_bank() > 1)
		gd->bd->bi_dram[1].size = get_ram_size((void *)PHYS_SDRAM_2,
					     PHYS_SDRAM_2_SIZE);
	else
		gd->bd->bi_dram[1].size = 0;
}

ulong board_get_usable_ram_top(ulong total_size)
{
	ulong ramtop;

	if (get_num_ram_bank() > 1)
		ramtop = PHYS_SDRAM_2 + get_ram_size((void *)PHYS_SDRAM_2,
						     PHYS_SDRAM_2_SIZE);
	else
		ramtop = PHYS_SDRAM_1 + get_ram_size((void *)PHYS_SDRAM_1,
						     PHYS_SDRAM_1_SIZE);

	return ramtop;
}

int checkboard(void)
{
	printf("Board: Armadeus APF27 revision %d\n", get_board_rev());
	return 0;
}

#ifdef CONFIG_SPL_BUILD
inline void hang(void)
{
	for (;;)
		;
}

void board_init_f(ulong bootflag)
{
	/*
	 * copy ourselves from where we are running to where we were
	 * linked at. Use ulong pointers as all addresses involved
	 * are 4-byte-aligned.
	 */
	ulong *start_ptr, *end_ptr, *link_ptr, *run_ptr, *dst;
	asm volatile ("ldr %0, =_start" : "=r"(start_ptr));
	asm volatile ("ldr %0, =_end" : "=r"(end_ptr));
	asm volatile ("ldr %0, =board_init_f" : "=r"(link_ptr));
	asm volatile ("adr %0, board_init_f" : "=r"(run_ptr));
	for (dst = start_ptr; dst < end_ptr; dst++)
		*dst = *(dst+(run_ptr-link_ptr));

	/*
	 * branch to nand_boot's link-time address.
	 */
	asm volatile("ldr pc, =nand_boot");
}
#endif /* CONFIG_SPL_BUILD */