cpu/allwinner: Remove support
The Allwinner code was never completed and lacks a driver to load romstage from the bootblock. Change-Id: If2bae9e28a6e1ed6bfe0e9cb022ca410918cc4db Signed-off-by: Arthur Heymans <arthur@aheymans.xyz> Reviewed-on: https://review.coreboot.org/c/coreboot/+/33133 Reviewed-by: Angel Pons <th3fanbus@gmail.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
		
				
					committed by
					
						 Patrick Georgi
						Patrick Georgi
					
				
			
			
				
	
			
			
			
						parent
						
							041200fae3
						
					
				
				
					commit
					c27f1c390a
				
			| @@ -1 +0,0 @@ | ||||
| source src/cpu/allwinner/a10/Kconfig | ||||
| @@ -1 +0,0 @@ | ||||
| subdirs-$(CONFIG_CPU_ALLWINNER_A10) += a10 | ||||
| @@ -1,18 +0,0 @@ | ||||
| config CPU_ALLWINNER_A10 | ||||
| 	bool | ||||
| 	default n | ||||
|  | ||||
| if CPU_ALLWINNER_A10 | ||||
|  | ||||
| config CPU_SPECIFIC_OPTIONS | ||||
| 	def_bool y | ||||
| 	select ARCH_BOOTBLOCK_ARMV7 | ||||
| 	select ARCH_VERSTAGE_ARMV7 | ||||
| 	select ARCH_ROMSTAGE_ARMV7 | ||||
| 	select ARCH_RAMSTAGE_ARMV7 | ||||
| 	select NO_MONOTONIC_TIMER | ||||
| 	select HAVE_UART_SPECIAL | ||||
| 	select UART_OVERRIDE_REFCLK | ||||
| 	select BOOT_DEVICE_NOT_SPI_FLASH | ||||
|  | ||||
| endif # if CPU_ALLWINNER_A10 | ||||
| @@ -1,55 +0,0 @@ | ||||
| bootblock-y	+= bootblock.c | ||||
| bootblock-y	+= bootblock_media.c | ||||
| bootblock-y	+= clock.c | ||||
| bootblock-y	+= gpio.c | ||||
| bootblock-y	+= pinmux.c | ||||
| bootblock-y	+= raminit.c | ||||
| bootblock-y	+= timer.c | ||||
|  | ||||
| romstage-y	+= bootblock_media.c | ||||
| romstage-y	+= cbmem.c | ||||
| romstage-y	+= clock.c | ||||
| romstage-y	+= pinmux.c | ||||
| romstage-y	+= timer.c | ||||
| romstage-y	+= twi.c | ||||
|  | ||||
| ramstage-y	+= bootblock_media.c | ||||
| ramstage-y	+= cbmem.c | ||||
| ramstage-y	+= clock.c | ||||
| ramstage-y	+= cpu.c | ||||
| ramstage-y	+= timer.c | ||||
| ramstage-y	+= twi.c | ||||
|  | ||||
| bootblock-y	+= uart.c uart_console.c | ||||
| romstage-y	+= uart.c uart_console.c | ||||
| ramstage-y	+= uart.c uart_console.c | ||||
|  | ||||
| real-target: $(obj)/BOOT0 | ||||
|  | ||||
| get_bootblock_size= \ | ||||
| 	$(eval bb_s=$(shell $(CBFSTOOL) $(1) print | grep bootblocksize | \ | ||||
| 					sed 's/[^0-9 ]//g')) \ | ||||
| 	$(shell echo $$(($(word 2, $(strip $(bb_s)))))) | ||||
|  | ||||
| # This tool is used to prepend a header to coreboot.rom to trick the SoC into | ||||
| # loading out bootblock | ||||
| # | ||||
| MKSUNXIBOOT:=$(objutil)/mksunxiboot | ||||
| $(MKSUNXIBOOT): $(top)/util/arm_boot_tools/mksunxiboot/mksunxiboot.c | ||||
| 	@printf "    HOSTCC     $(subst $(obj)/,,$(@))\n" | ||||
| 	$(HOSTCC) $(HOSTCFLAGS) -o $@ $< | ||||
|  | ||||
| # The boot ROM in the SoC will start loading code if a special BOOT0 header is | ||||
| # found (at an offset of 8KiB in either NAND or SD), and the checksum is | ||||
| # correct. This header is added by the 'mxsunxiboot' tool, which is provided | ||||
| # under util/arm_boot_tools/mksunxiboot. The boot ROM will load at most 24KiB of | ||||
| # data to SRAM. The BOOT0 header takes 32 bytes, so bootblock is limited to | ||||
| # 24KiB - 32 bytes. | ||||
| # TODO: make mksunxiboot take the bootblock size as a parameter | ||||
| # TODO: print an error if bootblock is too large (maybe place ROMSTAGE at the | ||||
| #	exact offset needed to collide with the bootblock) | ||||
| # FIXME: A10 loads 24KiB. According to Oliver other chips load a little more | ||||
| # | ||||
| $(obj)/BOOT0: $(obj)/coreboot.rom $(MKSUNXIBOOT) | ||||
| 	@printf "    BOOT0      $(subst $(obj)/,,$(^))\n" | ||||
| 	$(MKSUNXIBOOT) $(word 1, $^) $@ | ||||
| @@ -1,33 +0,0 @@ | ||||
| /* | ||||
|  * This file is part of the coreboot project. | ||||
|  * | ||||
|  * Copyright (C) 2013 Google Inc. | ||||
|  * Copyright (C) 2013  Alexandru Gagniuc <mr.nuke.me@gmail.com> | ||||
|  * | ||||
|  * 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  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. | ||||
|  * | ||||
|  * Allwinner A10 bootblock initialization | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include <types.h> | ||||
| #include <arch/cache.h> | ||||
| #include <bootblock_common.h> | ||||
|  | ||||
| void bootblock_soc_init(void) | ||||
| { | ||||
| 	uint32_t sctlr; | ||||
|  | ||||
| 	/* enable dcache */ | ||||
| 	sctlr = read_sctlr(); | ||||
| 	sctlr |= SCTLR_C; | ||||
| 	write_sctlr(sctlr); | ||||
| } | ||||
| @@ -1,26 +0,0 @@ | ||||
| /* | ||||
|  * This file is part of the coreboot project. | ||||
|  * | ||||
|  * Copyright (C) 2013  Alexandru Gagniuc <mr.nuke.me@gmail.com> | ||||
|  * | ||||
|  * 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 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. | ||||
|  * | ||||
|  * CBFS accessors for bootblock stage. | ||||
|  * | ||||
|  */ | ||||
| #include <boot_device.h> | ||||
| #include <console/console.h> | ||||
|  | ||||
| const struct region_device *boot_device_ro(void) | ||||
| { | ||||
| 	printk(BIOS_ERR, "Oh my! I don't know how to access CBFS yet."); | ||||
| 	return NULL; | ||||
| } | ||||
| @@ -1,26 +0,0 @@ | ||||
| /* | ||||
|  * This file is part of the coreboot project. | ||||
|  * | ||||
|  * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com> | ||||
|  * | ||||
|  * 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  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. | ||||
|  * | ||||
|  * Provides cbmem utilities for romstage and ramstage | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include "ram_segs.h" | ||||
| #include <cbmem.h> | ||||
|  | ||||
| void *cbmem_top(void) | ||||
| { | ||||
| 	return a1x_get_cbmem_top(); | ||||
| } | ||||
| @@ -1,23 +0,0 @@ | ||||
| /* | ||||
|  * This file is part of the coreboot project. | ||||
|  * | ||||
|  * Copyright (C) 2013  Alexandru Gagniuc <mr.nuke.me@gmail.com> | ||||
|  * | ||||
|  * 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  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. | ||||
|  * | ||||
|  * Allwinnwer A10 devicetree config struct | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include <types.h> | ||||
|  | ||||
| struct cpu_allwinner_a10_config { | ||||
| }; | ||||
| @@ -1,283 +0,0 @@ | ||||
| /* | ||||
|  * This file is part of the coreboot project. | ||||
|  * | ||||
|  * Copyright (C) 2013  Alexandru Gagniuc <mr.nuke.me@gmail.com> | ||||
|  * | ||||
|  * 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  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. | ||||
|  * | ||||
|  * Helpers for clock control and gating on Allwinner CPUs | ||||
|  */ | ||||
|  | ||||
| #include "clock.h" | ||||
|  | ||||
| #include <device/mmio.h> | ||||
| #include <console/console.h> | ||||
| #include <delay.h> | ||||
| #include <lib.h> | ||||
|  | ||||
| static struct a10_ccm *const ccm = (void *)A1X_CCM_BASE; | ||||
|  | ||||
| /** | ||||
|  * \brief Enable the clock source for the peripheral | ||||
|  * | ||||
|  * @param[in] periph peripheral and clock type to enable @see a1x_clken | ||||
|  */ | ||||
| void a1x_periph_clock_enable(enum a1x_clken periph) | ||||
| { | ||||
| 	void *addr; | ||||
| 	u32 reg32; | ||||
|  | ||||
| 	addr = (void *)A1X_CCM_BASE + (periph >> 5); | ||||
| 	reg32 = read32(addr); | ||||
| 	reg32 |= 1 << (periph & 0x1f); | ||||
| 	write32(addr, reg32); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * \brief Disable the clock source for the peripheral | ||||
|  * | ||||
|  * @param[in] periph peripheral and clock type to disable @see a1x_clken | ||||
|  */ | ||||
| void a1x_periph_clock_disable(enum a1x_clken periph) | ||||
| { | ||||
| 	void *addr; | ||||
| 	u32 reg32; | ||||
|  | ||||
| 	addr = (void *)A1X_CCM_BASE + (periph >> 5); | ||||
| 	reg32 = read32(addr); | ||||
| 	reg32 &= ~(1 << (periph & 0x1f)); | ||||
| 	write32(addr, reg32); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * \brief Configure PLL5 factors | ||||
|  * | ||||
|  * This is a low-level accessor to configure the divisors and multipliers of | ||||
|  * PLL5. PLL5 uses two factors to multiply the 24MHz oscillator clock to | ||||
|  * generate a pre-clock. The pre-divided clock is then divided by one of two | ||||
|  * independent divisors, one for DRAM, and another for peripherals clocked from | ||||
|  * this PLL. If the PLL was previously disabled, this function will enable it. | ||||
|  * Other than that, this function only modifies these factors, and leaves the | ||||
|  * other settings unchanged. | ||||
|  * | ||||
|  * The output clocks are given by the following formulas: | ||||
|  * | ||||
|  * Pre-clock    = (24 MHz * N * K) <- Must be between 240MHz and 2GHz | ||||
|  * DRAM clock   = pre / M | ||||
|  * Other module = pre / P | ||||
|  * | ||||
|  * It is the caller's responsibility to make sure the pre-divided clock falls | ||||
|  * within the operational range of the PLL, and that the divisors and | ||||
|  * multipliers are within their ranges. | ||||
|  * | ||||
|  * @param[in] mul_n Multiplier N, between 0 and 32 | ||||
|  * @param[in] mul_k Multiplier K, between 1 and 4 | ||||
|  * @param[in] div_m DRAM clock divisor, between 1 and 4 | ||||
|  * @param[in] exp_div_p Peripheral clock divisor exponent, between 0 and 3 | ||||
|  *			(P = 1/2/4/8, respectively) | ||||
|  */ | ||||
| void a1x_pll5_configure(u8 mul_n, u8 mul_k, u8 div_m, u8 exp_div_p) | ||||
| { | ||||
| 	u32 reg32; | ||||
|  | ||||
| 	reg32 = read32(&ccm->pll5_cfg); | ||||
| 	reg32 &= ~(PLL5_FACTOR_M_MASK | PLL5_FACTOR_N_MASK | | ||||
| 		   PLL5_FACTOR_K_MASK | PLL5_DIV_EXP_P_MASK); | ||||
| 	/* The M1 factor is not documented in the datasheet, and the reference | ||||
| 	 * raminit code does not use it. Whether this is a fractional divisor, | ||||
| 	 * or an additional divisor is unknown, so don't use it for now */ | ||||
| 	reg32 &= ~PLL5_FACTOR_M1_MASK; | ||||
| 	reg32 |= (PLL5_FACTOR_M(div_m) | PLL5_FACTOR_N(mul_n) | | ||||
| 		  PLL5_FACTOR_K(mul_k) | PLL5_DIV_EXP_P(exp_div_p)); | ||||
| 	reg32 |= PLL5_PLL_ENABLE; | ||||
| 	write32(&ccm->pll5_cfg, reg32); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * \brief Enable the clock output to DRAM chips | ||||
|  * | ||||
|  * This enables the DRAM clock to be sent to DRAM chips. This should normally be | ||||
|  * done after PLL5 is configured and locked. Note that the clock may be gated, | ||||
|  * and also needs to be ungated in order to reach the DDR chips. | ||||
|  * Also see @ref clock_ungate_dram_clk_output | ||||
|  */ | ||||
| void a1x_pll5_enable_dram_clock_output(void) | ||||
| { | ||||
| 	setbits_le32(&ccm->pll5_cfg, PLL5_DDR_CLK_OUT_EN); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * \brief Ungate the clock to DRAM chips | ||||
|  * | ||||
|  * Although the DRAM clock output may be enabled, it is by default gated. It | ||||
|  * needs to be ungated before reaching DRAM. | ||||
|  */ | ||||
| void a1x_ungate_dram_clock_output(void) | ||||
| { | ||||
| 	setbits_le32(&ccm->dram_clk_cfg, DRAM_CTRL_DCLK_OUT); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * \brief Gate the clock to DRAM chips | ||||
|  * | ||||
|  * Disable the clock to DRAM without altering PLL configuration, by closing the | ||||
|  * DRAM clock gate. | ||||
|  */ | ||||
| void a1x_gate_dram_clock_output(void) | ||||
| { | ||||
| 	clrbits_le32(&ccm->dram_clk_cfg, DRAM_CTRL_DCLK_OUT); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Linker doesn't garbage collect and the function below adds about half | ||||
|  * kilobyte to the bootblock, and log2_ceil is not available in the bootblock. | ||||
|  */ | ||||
| #ifndef __BOOTBLOCK__ | ||||
|  | ||||
| #define PLL1_CFG(N, K, M, P_EXP)	\ | ||||
| 	((1 << 31 | 0 << 30 | 8 << 26 | 0 << 25 | 16 << 20 | 2 << 13) | \ | ||||
| 	(P_EXP) << 16 |  (N) << 8 | \ | ||||
| 	(K - 1) << 4 | 0 << 3 | 0 << 2 | (M -1) << 0) | ||||
|  | ||||
| static const struct { | ||||
| 	u32 pll1_cfg; | ||||
| 	u16 freq_mhz; | ||||
| } pll1_table[] = { | ||||
| 	/* PLL1 output = (24MHz * N * K) / (M * P) */ | ||||
| 	{ PLL1_CFG(16, 1, 1, 0),  384 }, | ||||
| 	{ PLL1_CFG(16, 2, 1, 0),  768 }, | ||||
| 	{ PLL1_CFG(20, 2, 1, 0),  960 }, | ||||
| 	{ PLL1_CFG(21, 2, 1, 0), 1008 }, | ||||
| 	{ PLL1_CFG(22, 2, 1, 0), 1056 }, | ||||
| 	{ PLL1_CFG(23, 2, 1, 0), 1104 }, | ||||
| 	{ PLL1_CFG(24, 2, 1, 0), 1152 }, | ||||
| 	{ PLL1_CFG(25, 2, 1, 0), 1200 }, | ||||
| 	{ PLL1_CFG(26, 2, 1, 0), 1248 }, | ||||
| 	{ PLL1_CFG(27, 2, 1, 0), 1296 }, | ||||
| 	{ PLL1_CFG(28, 2, 1, 0), 1344 }, | ||||
| 	{ PLL1_CFG(29, 2, 1, 0), 1392 }, | ||||
| 	{ PLL1_CFG(30, 2, 1, 0), 1440 }, | ||||
| 	{ PLL1_CFG(31, 2, 1, 0), 1488 }, | ||||
| 	{ PLL1_CFG(20, 4, 1, 0), 1944 }, | ||||
| }; | ||||
|  | ||||
| static void cpu_clk_src_switch(u32 clksel_bits) | ||||
| { | ||||
| 	u32 reg32; | ||||
|  | ||||
| 	reg32 = read32(&ccm->cpu_ahb_apb0_cfg); | ||||
| 	reg32 &= ~CPU_CLK_SRC_MASK; | ||||
| 	reg32 |= clksel_bits & CPU_CLK_SRC_MASK; | ||||
| 	write32(&ccm->cpu_ahb_apb0_cfg, reg32); | ||||
| } | ||||
|  | ||||
| static void change_sys_divisors(u8 axi, u8 ahb_exp, u8 apb0_exp) | ||||
| { | ||||
| 	u32 reg32; | ||||
|  | ||||
| 	reg32 = read32(&ccm->cpu_ahb_apb0_cfg); | ||||
| 	/* Not a typo: We want to keep only the CLK_SRC bits */ | ||||
| 	reg32 &= CPU_CLK_SRC_MASK; | ||||
| 	reg32 |= ((axi - 1) << 0) & AXI_DIV_MASK; | ||||
| 	reg32 |= (ahb_exp << 4) & AHB_DIV_MASK; | ||||
| 	reg32 |= (apb0_exp << 8) & APB0_DIV_MASK; | ||||
| 	write32(&ccm->cpu_ahb_apb0_cfg, reg32); | ||||
| } | ||||
|  | ||||
| static void spin_delay(u32 loops) | ||||
| { | ||||
| 	volatile u32 x = loops; | ||||
| 	while (x--); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * \brief Configure the CPU clock and PLL1 | ||||
|  * | ||||
|  * To run at full speed, the CPU uses PLL1 as the clock source. AXI, AHB, and | ||||
|  * APB0 are derived from the CPU clock, and need to be kept within certain | ||||
|  * limits. This function configures PLL1 as close as possible to the desired | ||||
|  * frequency, based on a set of known working configurations for PLL1. It then | ||||
|  * calculates and applies the appropriate divisors for the AXI/AHB/APB0 clocks, | ||||
|  * before finally switching the CPU to run from the new clock. | ||||
|  * No further configuration of the CPU clock or divisors is needed. after | ||||
|  * calling this function. | ||||
|  * | ||||
|  * @param[in] cpu_clk_mhz Desired CPU clock, in MHz | ||||
|  */ | ||||
| void a1x_set_cpu_clock(u16 cpu_clk_mhz) | ||||
| { | ||||
| 	int i = 0; | ||||
| 	u8 axi, ahb, ahb_exp, apb0, apb0_exp; | ||||
| 	u32 actual_mhz; | ||||
|  | ||||
| 	/* | ||||
| 	 * Rated clock for PLL1 is 2000 MHz, but there is no combination of | ||||
| 	 * parameters that yields that exact frequency. 1944 MHz is the highest. | ||||
| 	 */ | ||||
| 	if (cpu_clk_mhz > 1944) { | ||||
| 		printk(BIOS_CRIT, "BUG! maximum PLL1 clock is 1944 MHz," | ||||
| 				  "but asked to clock CPU at %d MHz\n", | ||||
| 				  cpu_clk_mhz); | ||||
| 		cpu_clk_mhz = 1944; | ||||
| 	} | ||||
| 	/* Find target frequency */ | ||||
| 	while (pll1_table[i].freq_mhz < cpu_clk_mhz) | ||||
| 		i++; | ||||
|  | ||||
| 	actual_mhz = pll1_table[i].freq_mhz; | ||||
|  | ||||
| 	if (cpu_clk_mhz != actual_mhz) { | ||||
| 		printk(BIOS_WARNING, "Parameters for %d MHz not available, " | ||||
| 				     "setting CPU clock at %d MHz\n", | ||||
| 				     cpu_clk_mhz, actual_mhz); | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Calculate system clock divisors: | ||||
| 	 * The minimum clock divisor for APB0 is 2, which guarantees that AHB0 | ||||
| 	 * will always be in spec, as long as AHB is in spec, although the max | ||||
| 	 * AHB0 clock we can get is 125 MHz | ||||
| 	 */ | ||||
| 	axi = DIV_ROUND_UP(actual_mhz, 450);		/* Max 450 MHz */ | ||||
| 	ahb = DIV_ROUND_UP(actual_mhz/axi, 250);	/* Max 250 MHz */ | ||||
| 	apb0 = 2;					/* Max 150 MHz */ | ||||
|  | ||||
| 	ahb_exp = log2_ceil(ahb); | ||||
| 	ahb = 1 << ahb_exp; | ||||
| 	apb0_exp = 1; | ||||
|  | ||||
| 	printk(BIOS_INFO, "CPU: %d MHz, AXI %d Mhz, AHB: %d MHz APB0: %d MHz\n", | ||||
| 			  actual_mhz, | ||||
| 			  actual_mhz / axi, | ||||
| 			  actual_mhz / (axi * ahb), | ||||
| 			  actual_mhz / (axi * ahb * apb0)); | ||||
|  | ||||
| 	/* Keep the CPU off PLL1 while we change PLL parameters */ | ||||
| 	cpu_clk_src_switch(CPU_CLK_SRC_OSC24M); | ||||
| 	/* | ||||
| 	 * We can't use udelay() here. udelay() relies on timer 0, but timers | ||||
| 	 * have the habit of not ticking when the CPU is clocked from the main | ||||
| 	 * oscillator. | ||||
| 	 */ | ||||
| 	spin_delay(8); | ||||
|  | ||||
| 	change_sys_divisors(axi, ahb_exp, apb0_exp); | ||||
|  | ||||
| 	/* Configure PLL1 at the desired frequency */ | ||||
| 	write32(&ccm->pll1_cfg, pll1_table[i].pll1_cfg); | ||||
| 	spin_delay(8); | ||||
|  | ||||
| 	cpu_clk_src_switch(CPU_CLK_SRC_PLL1); | ||||
| 	/* Here, we're running from PLL, so timers will tick */ | ||||
| 	udelay(1); | ||||
| } | ||||
|  | ||||
| #endif  /* __BOOTBLOCK__ */ | ||||
| @@ -1,283 +0,0 @@ | ||||
| /* | ||||
|  * This file is part of the coreboot project. | ||||
|  * | ||||
|  * Copyright (C) 2007-2011 Allwinner Technology Co., Ltd. | ||||
|  *	Tom Cubie <tangliang@allwinnertech.com> | ||||
|  * Copyright (C) 2013  Alexandru Gagniuc <mr.nuke.me@gmail.com> | ||||
|  * | ||||
|  * 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. 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. | ||||
|  * | ||||
|  * Definitions for clock control and gating on Allwinner CPUs | ||||
|  */ | ||||
|  | ||||
| #ifndef CPU_ALLWINNER_A10_CLOCK_H | ||||
| #define CPU_ALLWINNER_A10_CLOCK_H | ||||
|  | ||||
| #include "memmap.h" | ||||
| #include <types.h> | ||||
|  | ||||
| /* CPU_AHB_APB0 config values */ | ||||
| #define CPU_CLK_SRC_MASK		(3 << 16) | ||||
| #define  CPU_CLK_SRC_OSC24M		(1 << 16) | ||||
| #define  CPU_CLK_SRC_PLL1		(2 << 16) | ||||
| #define APB0_DIV_MASK			(3 << 8) | ||||
| #define  APB0_DIV_1			(0 << 8) | ||||
| #define  APB0_DIV_2			(1 << 8) | ||||
| #define  APB0_DIV_4			(2 << 8) | ||||
| #define  APB0_DIV_8			(3 << 8) | ||||
| #define AHB_DIV_MASK			(3 << 4) | ||||
| #define  AHB_DIV_1			(0 << 4) | ||||
| #define  AHB_DIV_2			(1 << 4) | ||||
| #define  AHB_DIV_4			(2 << 4) | ||||
| #define  AHB_DIV_8			(3 << 4) | ||||
| #define AXI_DIV_MASK			(3 << 0) | ||||
| #define  AXI_DIV_1			(0 << 0) | ||||
| #define  AXI_DIV_2			(1 << 0) | ||||
| #define  AXI_DIV_3			(2 << 0) | ||||
| #define  AXI_DIV_4			(3 << 0) | ||||
|  | ||||
| /* APB1_CLK_DIV values */ | ||||
| #define APB1_CLK_SRC_MASK		(3 << 24) | ||||
| #define  APB1_CLK_SRC_OSC24M		(0 << 24) | ||||
| #define  APB1_CLK_SRC_PLL6		(1 << 24) | ||||
| #define  APB1_CLK_SRC_32K		(2 << 24) | ||||
| #define APB1_RAT_N_MASK			(3 << 16) | ||||
| #define  APB1_RAT_N(m)			(((m) & 0x3) << 16) | ||||
| #define APB1_RAT_M_MASK			(0x1f << 0) | ||||
| #define  APB1_RAT_M(n)			(((n) & 0x1f) << 0) | ||||
|  | ||||
| /* PLL5_CFG values */ | ||||
| #define PLL5_PLL_ENABLE			(1 << 31) | ||||
| #define PLL5_OUT_BYPASS_EN		(1 << 30) | ||||
| #define PLL5_DDR_CLK_OUT_EN		(1 << 29) | ||||
| #define PLL5_DIV_EXP_P_MASK		(0x3 << 16) | ||||
| #define PLL5_DIV_EXP_P(ep)		((ep << 16) & PLL5_DIV_EXP_P_MASK) | ||||
| #define  PLL5_DIV_P_1			(0x0 << 16) | ||||
| #define  PLL5_DIV_P_2			(0x1 << 16) | ||||
| #define  PLL5_DIV_P_4			(0x2 << 16) | ||||
| #define  PLL5_DIV_P_8			(0x3 << 16) | ||||
| #define PLL5_FACTOR_N_MASK		(0x1f << 8) | ||||
| #define PLL5_FACTOR_N(n)		((n << 8) & PLL5_FACTOR_N_MASK) | ||||
| #define PLL5_LDO_EN			(1 << 7) | ||||
| #define PLL5_FACTOR_K_MASK		(0x3 << 4) | ||||
| #define PLL5_FACTOR_K(k)		((((k) - 1) << 4) & PLL5_FACTOR_K_MASK) | ||||
| #define PLL5_FACTOR_M1_MASK		(0x3 << 2) | ||||
| #define PLL5_FACTOR_M1(m1)		(((m1) << 2) & PLL5_FACTOR_M1_MASK) | ||||
| #define PLL5_FACTOR_M_MASK		(0x3 << 0) | ||||
| #define PLL5_FACTOR_M(m)		((((m) - 1) << 0) & PLL5_FACTOR_M_MASK) | ||||
|  | ||||
| /* DRAM_CLK values*/ | ||||
| #define DRAM_CTRL_DCLK_OUT		(1 << 15) | ||||
|  | ||||
| /* SDx_CLK values */ | ||||
| #define SDx_CLK_GATE			(1 << 31) | ||||
| #define SDx_CLK_SRC_MASK		(3 << 24) | ||||
| #define  SDx_CLK_SRC_OSC24M		(0 << 24) | ||||
| #define  SDx_CLK_SRC_PLL6		(1 << 24) | ||||
| #define  SDx_CLK_SRC_PLL5		(2 << 24) | ||||
| #define SDx_RAT_EXP_N_MASK		(3 << 16) | ||||
| #define  SDx_RAT_EXP_N(n)		(((n) << 16) & SDx_RAT_EXP_N_MASK) | ||||
| #define SDx_RAT_M_MASK			(0xf << 0) | ||||
| #define  SDx_RAT_M(m)			((((m) - 1) << 0) & SDx_RAT_M_MASK) | ||||
| /** | ||||
|  * \brief Clock gating definitions | ||||
|  * | ||||
|  * The definitions are specified in the form: | ||||
|  * 31:5 register offset from A1X_CCM_BASE for the clock register | ||||
|  * 4:0  bit offset for the given peripheral | ||||
|  * | ||||
|  * The names have the form [periph_type][periph_number] | ||||
|  * | ||||
|  * These definitions are meant to be used with @ref a1x_periph_clock_enable and | ||||
|  * @ref a1x_periph_clock_disable | ||||
|  */ | ||||
|  | ||||
| enum a1x_clken { | ||||
| 	/* AXI module clock gating */ | ||||
| 	A1X_CLKEN_DRAM_AXI = (0x5C << 5), | ||||
| 	/* AHB0 module clock gating */ | ||||
| 	A1X_CLKEN_USB0 = (0x60 << 5), | ||||
| 	A1X_CLKEN_EHCI0, | ||||
| 	RSVD_0x60_2, | ||||
| 	A1X_CLKEN_EHCI1, | ||||
| 	RSVD_0x60_4, | ||||
| 	A1X_CLKEN_SS, | ||||
| 	A1X_CLKEN_DMA, | ||||
| 	A1X_CLKEN_BIST, | ||||
| 	A1X_CLKEN_MMC0, | ||||
| 	A1X_CLKEN_MMC1, | ||||
| 	A1X_CLKEN_MMC2, | ||||
| 	A1X_CLKEN_MMC3, | ||||
| 	A1X_CLKEN_NC, | ||||
| 	A1X_CLKEN_NAND, | ||||
| 	A1X_CLKEN_SDRAM, | ||||
| 	RSVD_0x60_15, | ||||
| 	A1X_CLKEN_ACE, | ||||
| 	A1X_CLKEN_EMAC, | ||||
| 	A1X_CLKEN_TS, | ||||
| 	RSVD_0x60_19, | ||||
| 	A1X_CLKEN_SPI0, | ||||
| 	A1X_CLKEN_SPI1, | ||||
| 	A1X_CLKEN_SPI2, | ||||
| 	A1X_CLKEN_SPI3, | ||||
| 	A1X_CLKEN_PATA, | ||||
| 	RSVD_0x60_25, | ||||
| 	A1X_CLKEN_GPS, | ||||
| 	/* AHB1 module clock gating */ | ||||
| 	A1X_CLKEN_DRAM_VE = (0x64 << 5), | ||||
| 	A1X_CLKEN_TVD, | ||||
| 	A1X_CLKEN_TVE0, | ||||
| 	A1X_CLKEN_TVE1, | ||||
| 	A1X_CLKEN_LCD0, | ||||
| 	A1X_CLKEN_LCD1, | ||||
| 	RSVD_0x64_6, | ||||
| 	RSVD_0x64_7, | ||||
| 	A1X_CLKEN_CSI0, | ||||
| 	A1X_CLKEN_CSI1, | ||||
| 	RSVD_0x64_10, | ||||
| 	A1X_CLKEN_HDMI, | ||||
| 	A1X_CLKEN_DE_BE0, | ||||
| 	A1X_CLKEN_DE_BE1, | ||||
| 	A1X_CLKEN_DE_FE0, | ||||
| 	A1X_CLKEN_DE_FE1, | ||||
| 	RSVD_0x64_16, | ||||
| 	RSVD_0x64_17, | ||||
| 	A1X_CLKEN_MP, | ||||
| 	RSVD_0x64_19, | ||||
| 	A1X_CLKEN_MALI400, | ||||
| 	/* APB0 module clock gating */ | ||||
| 	A1X_CLKEN_CODEC = (0x68 << 5), | ||||
| 	A1X_CLKEN_NC_APB, | ||||
| 	A1X_CLKEN_AC97, | ||||
| 	A1X_CLKEN_IIS, | ||||
| 	RSVD_0x68_4, | ||||
| 	A1X_CLKEN_PIO, | ||||
| 	A1X_CLKEN_IR0, | ||||
| 	A1X_CLKEN_IR1, | ||||
| 	RSVD_0x68_8, | ||||
| 	RSVD_0x68_9, | ||||
| 	A1X_CLKEN_KEYPAD, | ||||
| 	/* APB1 module clock gating */ | ||||
| 	A1X_CLKEN_TWI0 = (0x6C << 5), | ||||
| 	A1X_CLKEN_TWI1, | ||||
| 	A1X_CLKEN_TWI2, | ||||
| 	RSVD_0x6C_3, | ||||
| 	A1X_CLKEN_CAN, | ||||
| 	A1X_CLKEN_SCR, | ||||
| 	A1X_CLKEN_PS20, | ||||
| 	A1X_CLKEN_PS21, | ||||
| 	RSVD_0x6C_8, | ||||
| 	RSVD_0x6C_9, | ||||
| 	RSVD_0x6C_10, | ||||
| 	RSVD_0x6C_11, | ||||
| 	RSVD_0x6C_12, | ||||
| 	RSVD_0x6C_13, | ||||
| 	RSVD_0x6C_14, | ||||
| 	RSVD_0x6C_15, | ||||
| 	A1X_CLKEN_UART0, | ||||
| 	A1X_CLKEN_UART1, | ||||
| 	A1X_CLKEN_UART2, | ||||
| 	A1X_CLKEN_UART3, | ||||
| 	A1X_CLKEN_UART4, | ||||
| 	A1X_CLKEN_UART5, | ||||
| 	A1X_CLKEN_UART6, | ||||
| 	A1X_CLKEN_UART7, | ||||
| }; | ||||
|  | ||||
| struct a10_ccm { | ||||
| 	u32 pll1_cfg;		/* 0x00 pll1 control */ | ||||
| 	u32 pll1_tun;		/* 0x04 pll1 tuning */ | ||||
| 	u32 pll2_cfg;		/* 0x08 pll2 control */ | ||||
| 	u32 pll2_tun;		/* 0x0c pll2 tuning */ | ||||
| 	u32 pll3_cfg;		/* 0x10 pll3 control */ | ||||
| 	u8 res0[0x4]; | ||||
| 	u32 pll4_cfg;		/* 0x18 pll4 control */ | ||||
| 	u8 res1[0x4]; | ||||
| 	u32 pll5_cfg;		/* 0x20 pll5 control */ | ||||
| 	u32 pll5_tun;		/* 0x24 pll5 tuning */ | ||||
| 	u32 pll6_cfg;		/* 0x28 pll6 control */ | ||||
| 	u32 pll6_tun;		/* 0x2c pll6 tuning */ | ||||
| 	u32 pll7_cfg;		/* 0x30 pll7 control */ | ||||
| 	u32 pll1_tun2;		/* 0x34 pll5 tuning2 */ | ||||
| 	u8 res2[0x4]; | ||||
| 	u32 pll5_tun2;		/* 0x3c pll5 tuning2 */ | ||||
| 	u8 res3[0xc]; | ||||
| 	u32 pll_lock_dbg;	/* 0x4c pll lock time debug */ | ||||
| 	u32 osc24m_cfg;		/* 0x50 osc24m control */ | ||||
| 	u32 cpu_ahb_apb0_cfg;	/* 0x54 CPU, ahb and apb0 divide ratio */ | ||||
| 	u32 apb1_clk_div_cfg;	/* 0x58 apb1 clock dividor */ | ||||
| 	u32 axi_gate;		/* 0x5c axi module clock gating */ | ||||
| 	u32 ahb_gate0;		/* 0x60 ahb module clock gating 0 */ | ||||
| 	u32 ahb_gate1;		/* 0x64 ahb module clock gating 1 */ | ||||
| 	u32 apb0_gate;		/* 0x68 apb0 module clock gating */ | ||||
| 	u32 apb1_gate;		/* 0x6c apb1 module clock gating */ | ||||
| 	u8 res4[0x10]; | ||||
| 	u32 nand_sclk_cfg;	/* 0x80 nand sub clock control */ | ||||
| 	u32 ms_sclk_cfg;	/* 0x84 memory stick sub clock control */ | ||||
| 	u32 sd0_clk_cfg;	/* 0x88 sd0 clock control */ | ||||
| 	u32 sd1_clk_cfg;	/* 0x8c sd1 clock control */ | ||||
| 	u32 sd2_clk_cfg;	/* 0x90 sd2 clock control */ | ||||
| 	u32 sd3_clk_cfg;	/* 0x94 sd3 clock control */ | ||||
| 	u32 ts_clk_cfg;		/* 0x98 transport stream clock control */ | ||||
| 	u32 ss_clk_cfg;		/* 0x9c */ | ||||
| 	u32 spi0_clk_cfg;	/* 0xa0 */ | ||||
| 	u32 spi1_clk_cfg;	/* 0xa4 */ | ||||
| 	u32 spi2_clk_cfg;	/* 0xa8 */ | ||||
| 	u32 pata_clk_cfg;	/* 0xac */ | ||||
| 	u32 ir0_clk_cfg;	/* 0xb0 */ | ||||
| 	u32 ir1_clk_cfg;	/* 0xb4 */ | ||||
| 	u32 iis_clk_cfg;	/* 0xb8 */ | ||||
| 	u32 ac97_clk_cfg;	/* 0xbc */ | ||||
| 	u32 spdif_clk_cfg;	/* 0xc0 */ | ||||
| 	u32 keypad_clk_cfg;	/* 0xc4 */ | ||||
| 	u32 sata_clk_cfg;	/* 0xc8 */ | ||||
| 	u32 usb_clk_cfg;	/* 0xcc */ | ||||
| 	u32 gps_clk_cfg;	/* 0xd0 */ | ||||
| 	u32 spi3_clk_cfg;	/* 0xd4 */ | ||||
| 	u8 res5[0x28]; | ||||
| 	u32 dram_clk_cfg;	/* 0x100 */ | ||||
| 	u32 be0_clk_cfg;	/* 0x104 */ | ||||
| 	u32 be1_clk_cfg;	/* 0x108 */ | ||||
| 	u32 fe0_clk_cfg;	/* 0x10c */ | ||||
| 	u32 fe1_clk_cfg;	/* 0x110 */ | ||||
| 	u32 mp_clk_cfg;		/* 0x114 */ | ||||
| 	u32 lcd0_ch0_clk_cfg;	/* 0x118 */ | ||||
| 	u32 lcd1_ch0_clk_cfg;	/* 0x11c */ | ||||
| 	u32 csi_isp_clk_cfg;	/* 0x120 */ | ||||
| 	u8 res6[0x4]; | ||||
| 	u32 tvd_clk_reg;	/* 0x128 */ | ||||
| 	u32 lcd0_ch1_clk_cfg;	/* 0x12c */ | ||||
| 	u32 lcd1_ch1_clk_cfg;	/* 0x130 */ | ||||
| 	u32 csi0_clk_cfg;	/* 0x134 */ | ||||
| 	u32 csi1_clk_cfg;	/* 0x138 */ | ||||
| 	u32 ve_clk_cfg;		/* 0x13c */ | ||||
| 	u32 audio_codec_clk_cfg;	/* 0x140 */ | ||||
| 	u32 avs_clk_cfg;	/* 0x144 */ | ||||
| 	u32 ace_clk_cfg;	/* 0x148 */ | ||||
| 	u32 lvds_clk_cfg;	/* 0x14c */ | ||||
| 	u32 hdmi_clk_cfg;	/* 0x150 */ | ||||
| 	u32 mali_clk_cfg;	/* 0x154 */ | ||||
| 	u8 res7[0x4]; | ||||
| 	u32 mbus_clk_cfg;	/* 0x15c */ | ||||
| } __packed; | ||||
|  | ||||
| void a1x_periph_clock_enable(enum a1x_clken periph); | ||||
| void a1x_periph_clock_disable(enum a1x_clken periph); | ||||
|  | ||||
| void a1x_pll5_configure(u8 mul_n, u8 mul_k, u8 div_m, u8 exp_div_p); | ||||
| void a1x_pll5_enable_dram_clock_output(void); | ||||
| void a1x_ungate_dram_clock_output(void); | ||||
| void a1x_gate_dram_clock_output(void); | ||||
|  | ||||
| /* Not available in bootblock */ | ||||
| void a1x_set_cpu_clock(u16 cpu_clk_mhz); | ||||
|  | ||||
| #endif				/* CPU_ALLWINNER_A10_CLOCK_H */ | ||||
| @@ -1,53 +0,0 @@ | ||||
| /* | ||||
|  * This file is part of the coreboot project. | ||||
|  * | ||||
|  * Copyright (C) 2014 Alexandru Gagniuc <mr.nuke.me@gmail.com> | ||||
|  * | ||||
|  * 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 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. | ||||
|  * | ||||
|  * Ramstage initialization for Allwinner CPUs | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include <device/device.h> | ||||
| #include <symbols.h> | ||||
|  | ||||
| static void cpu_enable_resources(struct device *dev) | ||||
| { | ||||
| 	ram_resource(dev, 0, (uintptr_t)_dram/KiB, | ||||
| 		     CONFIG_DRAM_SIZE_MB << 10); | ||||
| 	/* TODO: Declare CBFS cache as reserved? There's no guarantee we won't | ||||
| 	 * overwrite it. It seems to stay intact, being so high in RAM | ||||
| 	 */ | ||||
| } | ||||
|  | ||||
| static void cpu_init(struct device *dev) | ||||
| { | ||||
| 	/* TODO: Check if anything else needs to be explicitly initialized */ | ||||
| } | ||||
|  | ||||
| static struct device_operations cpu_ops = { | ||||
| 	.read_resources   = DEVICE_NOOP, | ||||
| 	.set_resources    = DEVICE_NOOP, | ||||
| 	.enable_resources = cpu_enable_resources, | ||||
| 	.init             = cpu_init, | ||||
| 	.scan_bus         = NULL, | ||||
| }; | ||||
|  | ||||
| static void a1x_cpu_enable_dev(struct device *dev) | ||||
| { | ||||
| 	dev->ops = &cpu_ops; | ||||
| } | ||||
|  | ||||
| struct chip_operations cpu_allwinner_a10_ops = { | ||||
| 	CHIP_NAME("CPU Allwinner A10") | ||||
| 	.enable_dev = a1x_cpu_enable_dev, | ||||
| }; | ||||
| @@ -1,187 +0,0 @@ | ||||
| /* | ||||
|  * This file is part of the coreboot project. | ||||
|  * | ||||
|  * Copyright (C) 2007-2012 Allwinner Technology Co., Ltd. | ||||
|  *	Berg Xing <bergxing@allwinnertech.com> | ||||
|  *	Tom Cubie <tangliang@allwinnertech.com> | ||||
|  * Copyright (C) 2013  Alexandru Gagniuc <mr.nuke.me@gmail.com> | ||||
|  * | ||||
|  * 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.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. | ||||
|  * | ||||
|  * Allwinner A10 platform dram register definition. | ||||
|  * | ||||
|  * Based on sun4i Linux kernel sources mach-sunxi/pm/standby/dram*.c | ||||
|  * and earlier U-Boot Allwiner A10 SPL work | ||||
|  */ | ||||
|  | ||||
| #ifndef CPU_ALLWINNER_A10_DRAMC_H | ||||
| #define CPU_ALLWINNER_A10_DRAMC_H | ||||
|  | ||||
| #include <types.h> | ||||
|  | ||||
| #define DRAM_CCR_COMMAND_RATE_1T (0x1 << 5) | ||||
| #define DRAM_CCR_DQS_GATE (0x1 << 14) | ||||
| #define DRAM_CCR_DQS_DRIFT_COMP (0x1 << 17) | ||||
| #define DRAM_CCR_ITM_OFF (0x1 << 28) | ||||
| #define DRAM_CCR_DATA_TRAINING (0x1 << 30) | ||||
| #define DRAM_CCR_INIT (0x1 << 31) | ||||
|  | ||||
| #define DRAM_MEMORY_TYPE_DDR1 1 | ||||
| #define DRAM_MEMORY_TYPE_DDR2 2 | ||||
| #define DRAM_MEMORY_TYPE_DDR3 3 | ||||
| #define DRAM_MEMORY_TYPE_LPDDR2 4 | ||||
| #define DRAM_MEMORY_TYPE_LPDDR 5 | ||||
| #define DRAM_DCR_TYPE (0x1 << 0) | ||||
| #define DRAM_DCR_TYPE_DDR2 0x0 | ||||
| #define DRAM_DCR_TYPE_DDR3 0x1 | ||||
| #define DRAM_DCR_IO_WIDTH(n) (((n) & 0x3) << 1) | ||||
| #define DRAM_DCR_IO_WIDTH_MASK DRAM_DCR_IO_WIDTH(0x3) | ||||
| #define DRAM_DCR_IO_WIDTH_8BIT 0x0 | ||||
| #define DRAM_DCR_IO_WIDTH_16BIT 0x1 | ||||
| #define DRAM_DCR_CHIP_DENSITY(n) (((n) & 0x7) << 3) | ||||
| #define DRAM_DCR_CHIP_DENSITY_MASK DRAM_DCR_CHIP_DENSITY(0x7) | ||||
| #define DRAM_DCR_CHIP_DENSITY_256M 0x0 | ||||
| #define DRAM_DCR_CHIP_DENSITY_512M 0x1 | ||||
| #define DRAM_DCR_CHIP_DENSITY_1024M 0x2 | ||||
| #define DRAM_DCR_CHIP_DENSITY_2048M 0x3 | ||||
| #define DRAM_DCR_CHIP_DENSITY_4096M 0x4 | ||||
| #define DRAM_DCR_CHIP_DENSITY_8192M 0x5 | ||||
| #define DRAM_DCR_BUS_WIDTH(n) (((n) & 0x7) << 6) | ||||
| #define DRAM_DCR_BUS_WIDTH_MASK DRAM_DCR_BUS_WIDTH(0x7) | ||||
| #define DRAM_DCR_BUS_WIDTH_32BIT 0x3 | ||||
| #define DRAM_DCR_BUS_WIDTH_16BIT 0x1 | ||||
| #define DRAM_DCR_BUS_WIDTH_8BIT 0x0 | ||||
| #define DRAM_DCR_NR_DLLCR_32BIT 5 | ||||
| #define DRAM_DCR_NR_DLLCR_16BIT 3 | ||||
| #define DRAM_DCR_NR_DLLCR_8BIT 2 | ||||
| #define DRAM_DCR_RANK_SEL(n) (((n) & 0x3) << 10) | ||||
| #define DRAM_DCR_RANK_SEL_MASK DRAM_DCR_CMD_RANK(0x3) | ||||
| #define DRAM_DCR_CMD_RANK_ALL (0x1 << 12) | ||||
| #define DRAM_DCR_MODE(n) (((n) & 0x3) << 13) | ||||
| #define DRAM_DCR_MODE_MASK DRAM_DCR_MODE(0x3) | ||||
| #define DRAM_DCR_MODE_SEQ 0x0 | ||||
| #define DRAM_DCR_MODE_INTERLEAVE 0x1 | ||||
|  | ||||
| #define DRAM_CSR_FAILED (0x1 << 20) | ||||
|  | ||||
| #define DRAM_MCR_MODE_NORM(n) (((n) & 0x3) << 0) | ||||
| #define DRAM_MCR_MODE_NORM_MASK DRAM_MCR_MOD_NORM(0x3) | ||||
| #define DRAM_MCR_MODE_DQ_OUT(n) (((n) & 0x3) << 2) | ||||
| #define DRAM_MCR_MODE_DQ_OUT_MASK DRAM_MCR_MODE_DQ_OUT(0x3) | ||||
| #define DRAM_MCR_MODE_ADDR_OUT(n) (((n) & 0x3) << 4) | ||||
| #define DRAM_MCR_MODE_ADDR_OUT_MASK DRAM_MCR_MODE_ADDR_OUT(0x3) | ||||
| #define DRAM_MCR_MODE_DQ_IN_OUT(n) (((n) & 0x3) << 6) | ||||
| #define DRAM_MCR_MODE_DQ_IN_OUT_MASK DRAM_MCR_MODE_DQ_IN_OUT(0x3) | ||||
| #define DRAM_MCR_MODE_DQ_TURNON_DELAY(n) (((n) & 0x7) << 8) | ||||
| #define DRAM_MCR_MODE_DQ_TURNON_DELAY_MASK DRAM_MCR_MODE_DQ_TURNON_DELAY(0x7) | ||||
| #define DRAM_MCR_MODE_ADDR_IN (0x1 << 11) | ||||
| #define DRAM_MCR_RESET (0x1 << 12) | ||||
| #define DRAM_MCR_MODE_EN(n) (((n) & 0x3) << 13) | ||||
| #define DRAM_MCR_MODE_EN_MASK DRAM_MCR_MOD_EN(0x3) | ||||
| #define DRAM_MCR_DCLK_OUT (0x1 << 16) | ||||
|  | ||||
| #define DRAM_DLLCR_NRESET (0x1 << 30) | ||||
| #define DRAM_DLLCR_DISABLE (0x1 << 31) | ||||
|  | ||||
| #define DRAM_ZQCR0_IMP_DIV(n) (((n) & 0xff) << 20) | ||||
| #define DRAM_ZQCR0_IMP_DIV_MASK DRAM_ZQCR0_IMP_DIV(0xff) | ||||
|  | ||||
| #define DRAM_IOCR_ODT_EN(n) ((((n) & 0x3) << 30) | ((n) & 0x3) << 0) | ||||
| #define DRAM_IOCR_ODT_EN_MASK DRAM_IOCR_ODT_EN(0x3) | ||||
|  | ||||
| #define DRAM_MR_BURST_LENGTH(n) (((n) & 0x7) << 0) | ||||
| #define DRAM_MR_BURST_LENGTH_MASK DRAM_MR_BURST_LENGTH(0x7) | ||||
| #define DRAM_MR_CAS_LAT(n) (((n) & 0x7) << 4) | ||||
| #define DRAM_MR_CAS_LAT_MASK DRAM_MR_CAS_LAT(0x7) | ||||
| #define DRAM_MR_WRITE_RECOVERY(n) (((n) & 0x7) << 9) | ||||
| #define DRAM_MR_WRITE_RECOVERY_MASK DRAM_MR_WRITE_RECOVERY(0x7) | ||||
| #define DRAM_MR_POWER_DOWN (0x1 << 12) | ||||
|  | ||||
| #define DRAM_CSEL_MAGIC 0x16237495 | ||||
|  | ||||
| struct a1x_dramc { | ||||
| 	u32 ccr;		/* 0x00 controller configuration register */ | ||||
| 	u32 dcr;		/* 0x04 dram configuration register */ | ||||
| 	u32 iocr;		/* 0x08 i/o configuration register */ | ||||
| 	u32 csr;		/* 0x0c controller status register */ | ||||
| 	u32 drr;		/* 0x10 dram refresh register */ | ||||
| 	u32 tpr0;		/* 0x14 dram timing parameters register 0 */ | ||||
| 	u32 tpr1;		/* 0x18 dram timing parameters register 1 */ | ||||
| 	u32 tpr2;		/* 0x1c dram timing parameters register 2 */ | ||||
| 	u32 gdllcr;		/* 0x20 global dll control register */ | ||||
| 	u8 res0[0x28]; | ||||
| 	u32 rslr0;		/* 0x4c rank system latency register */ | ||||
| 	u32 rslr1;		/* 0x50 rank system latency register */ | ||||
| 	u8 res1[0x8]; | ||||
| 	u32 rdgr0;		/* 0x5c rank dqs gating register */ | ||||
| 	u32 rdgr1;		/* 0x60 rank dqs gating register */ | ||||
| 	u8 res2[0x34]; | ||||
| 	u32 odtcr;		/* 0x98 odt configuration register */ | ||||
| 	u32 dtr0;		/* 0x9c data training register 0 */ | ||||
| 	u32 dtr1;		/* 0xa0 data training register 1 */ | ||||
| 	u32 dtar;		/* 0xa4 data training address register */ | ||||
| 	u32 zqcr0;		/* 0xa8 zq control register 0 */ | ||||
| 	u32 zqcr1;		/* 0xac zq control register 1 */ | ||||
| 	u32 zqsr;		/* 0xb0 zq status register */ | ||||
| 	u32 idcr;		/* 0xb4 initializaton delay configure reg */ | ||||
| 	u8 res3[0x138]; | ||||
| 	u32 mr;			/* 0x1f0 mode register */ | ||||
| 	u32 emr;		/* 0x1f4 extended mode register */ | ||||
| 	u32 emr2;		/* 0x1f8 extended mode register */ | ||||
| 	u32 emr3;		/* 0x1fc extended mode register */ | ||||
| 	u32 dllctr;		/* 0x200 dll control register */ | ||||
| 	u32 dllcr[5];		/* 0x204 dll control register 0(byte 0) */ | ||||
| 	/* 0x208 dll control register 1(byte 1) */ | ||||
| 	/* 0x20c dll control register 2(byte 2) */ | ||||
| 	/* 0x210 dll control register 3(byte 3) */ | ||||
| 	/* 0x214 dll control register 4(byte 4) */ | ||||
| 	u32 dqtr0;		/* 0x218 dq timing register */ | ||||
| 	u32 dqtr1;		/* 0x21c dq timing register */ | ||||
| 	u32 dqtr2;		/* 0x220 dq timing register */ | ||||
| 	u32 dqtr3;		/* 0x224 dq timing register */ | ||||
| 	u32 dqstr;		/* 0x228 dqs timing register */ | ||||
| 	u32 dqsbtr;		/* 0x22c dqsb timing register */ | ||||
| 	u32 mcr;		/* 0x230 mode configure register */ | ||||
| 	u8 res[0x8]; | ||||
| 	u32 ppwrsctl;		/* 0x23c pad power save control */ | ||||
| 	u32 apr;		/* 0x240 arbiter period register */ | ||||
| 	u32 pldtr;		/* 0x244 priority level data threshold reg */ | ||||
| 	u8 res5[0x8]; | ||||
| 	u32 hpcr[32];		/* 0x250 host port configure register */ | ||||
| 	u8 res6[0x10]; | ||||
| 	u32 csel;		/* 0x2e0 controller select register */ | ||||
| }; | ||||
|  | ||||
| struct dram_para { | ||||
| 	u32 clock; | ||||
| 	u32 type; | ||||
| 	u32 rank_num; | ||||
| 	u32 density; | ||||
| 	u32 io_width; | ||||
| 	u32 bus_width; | ||||
| 	u32 cas; | ||||
| 	u32 zq; | ||||
| 	u32 odt_en; | ||||
| 	u32 size; | ||||
| 	u32 tpr0; | ||||
| 	u32 tpr1; | ||||
| 	u32 tpr2; | ||||
| 	u32 tpr3; | ||||
| 	u32 tpr4; | ||||
| 	u32 tpr5; | ||||
| 	u32 emr1; | ||||
| 	u32 emr2; | ||||
| 	u32 emr3; | ||||
| }; | ||||
|  | ||||
| unsigned long dramc_init(struct dram_para *para); | ||||
|  | ||||
| #endif				/* CPU_ALLWINNER_A10_DRAMC_H */ | ||||
| @@ -1,109 +0,0 @@ | ||||
| /* | ||||
|  * This file is part of the coreboot project. | ||||
|  * | ||||
|  * Copyright (C) 2013  Alexandru Gagniuc <mr.nuke.me@gmail.com> | ||||
|  * | ||||
|  * 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 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. | ||||
|  * | ||||
|  * Basic GPIO helpers for Allwinner CPUs | ||||
|  */ | ||||
|  | ||||
| #include "gpio.h" | ||||
|  | ||||
| #include <device/mmio.h> | ||||
|  | ||||
| static struct a10_gpio *const gpio = (void *)GPIO_BASE; | ||||
|  | ||||
| /** | ||||
|  * \brief Set a single output pin | ||||
|  * | ||||
|  * @param[in] port GPIO port of the pin (GPA -> GPS) | ||||
|  * @param[in] pin the pin number in the given port (1 -> 31) | ||||
|  */ | ||||
| void gpio_set(u8 port, u8 pin) | ||||
| { | ||||
| 	u32 reg32; | ||||
|  | ||||
| 	if ((port > GPS)) | ||||
| 		return; | ||||
|  | ||||
| 	reg32 = gpio_read(port); | ||||
| 	reg32 |= (1 << pin); | ||||
| 	gpio_write(port, reg32); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * \brief Clear a single output pin | ||||
|  * | ||||
|  * @param[in] port GPIO port of the pin (GPA -> GPS) | ||||
|  * @param[in] pin the pin number in the given port (1 -> 31) | ||||
|  */ | ||||
| void gpio_clear(u8 port, u8 pin) | ||||
| { | ||||
| 	u32 reg32; | ||||
| 	if ((port > GPS)) | ||||
| 		return; | ||||
|  | ||||
| 	reg32 = gpio_read(port); | ||||
| 	reg32 &= ~(1 << pin); | ||||
| 	gpio_write(port, reg32); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * \brief Get the status of a single input pin | ||||
|  * | ||||
|  * @param[in] port GPIO port of the pin (GPA -> GPS) | ||||
|  * @param[in] pin the pin number in the given port (1 -> 31) | ||||
|  * @return 1 if the pin is high, or 0 if the pin is low | ||||
|  */ | ||||
| int gpio_get(u8 port, u8 pin) | ||||
| { | ||||
| 	if ((port > GPS)) | ||||
| 		return 0; | ||||
|  | ||||
| 	return (gpio_read(port) & (1 << pin)) ? 1 : 0; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * \brief Write to a GPIO port | ||||
|  * | ||||
|  * Write the state of all output pins in the GPIO port. This only affects pins | ||||
|  * configured as output pins. | ||||
|  * | ||||
|  * @param[in] port GPIO port of the pin (GPA -> GPS) | ||||
|  * @param[in] val 32-bit mask indicating which pins to set. For a set bit, the | ||||
|  *                  corresponding pin will be set. Otherwise, it will be cleared | ||||
|  */ | ||||
| void gpio_write(u8 port, u32 val) | ||||
| { | ||||
| 	if ((port > GPS)) | ||||
| 		return; | ||||
|  | ||||
| 	write32(&gpio->port[port].dat, val); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * \brief Write to a GPIO port | ||||
|  * | ||||
|  * Read the state of all input pins in the GPIO port. | ||||
|  * | ||||
|  * @param[in] port GPIO port of the pin (GPA -> GPS) | ||||
|  * @return 32-bit mask indicating which pins are high. For each set bit, the | ||||
|  *         corresponding pin is high. The value of bits corresponding to pins | ||||
|  *         which are not configured as inputs is undefined. | ||||
|  */ | ||||
| u32 gpio_read(u8 port) | ||||
| { | ||||
| 	if ((port > GPS)) | ||||
| 		return 0; | ||||
|  | ||||
| 	return read32(&gpio->port[port].dat); | ||||
| } | ||||
| @@ -1,74 +0,0 @@ | ||||
| /* | ||||
|  * This file is part of the coreboot project. | ||||
|  * | ||||
|  * Copyright (C) 2013  Alexandru Gagniuc <mr.nuke.me@gmail.com> | ||||
|  * | ||||
|  * 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 or (at your option) | ||||
|  * any later version. | ||||
|  * | ||||
|  * 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. | ||||
|  * | ||||
|  * Definitions for GPIO and pin multiplexing on Allwinner CPUs | ||||
|  */ | ||||
|  | ||||
| #ifndef __CPU_ALLWINNER_A10_PINMUX_H | ||||
| #define __CPU_ALLWINNER_A10_PINMUX_H | ||||
|  | ||||
| #include <types.h> | ||||
|  | ||||
| #define GPIO_BASE		 0x01C20800 | ||||
|  | ||||
| #define GPA			0 | ||||
| #define GPB			1 | ||||
| #define GPC			2 | ||||
| #define GPD			3 | ||||
| #define GPE			4 | ||||
| #define GPF			5 | ||||
| #define GPG			6 | ||||
| #define GPH			7 | ||||
| #define GPI			8 | ||||
| #define GPS			9 | ||||
|  | ||||
| /* GPIO pad functions valid for all pins */ | ||||
| #define GPIO_PIN_FUNC_INPUT	0 | ||||
| #define GPIO_PIN_FUNC_OUTPUT	1 | ||||
|  | ||||
| struct a10_gpio_port { | ||||
| 	u32 cfg[4]; | ||||
| 	u32 dat; | ||||
| 	u32 drv[2]; | ||||
| 	u32 pul[2]; | ||||
| } __packed; | ||||
|  | ||||
| struct a10_gpio { | ||||
| 	struct a10_gpio_port port[10]; | ||||
| 	u8 reserved_0x168[0x98]; | ||||
|  | ||||
| 	/* Offset 0x200 */ | ||||
| 	u32 int_cfg[4]; | ||||
|  | ||||
| 	u32 int_ctl; | ||||
| 	u32 int_sta; | ||||
| 	u8 reserved_0x21C[4]; | ||||
| 	u32 int_deb; | ||||
|  | ||||
| 	u32 sdr_pad_drv; | ||||
| 	u32 sdr_pad_pul; | ||||
| } __packed; | ||||
|  | ||||
| /* gpio.c */ | ||||
| void gpio_set(u8 port, u8 pin); | ||||
| void gpio_clear(u8 port, u8 pin); | ||||
| int gpio_get(u8 port, u8 pin); | ||||
| void gpio_write(u8 port, u32 val); | ||||
| u32 gpio_read(u8 port); | ||||
|  | ||||
| /* pinmux.c */ | ||||
| void gpio_set_pin_func(u8 port, u8 pin, u8 pad_func); | ||||
| void gpio_set_multipin_func(u8 port, u32 pin_mask, u8 pad_func); | ||||
|  | ||||
| #endif				/* __CPU_ALLWINNER_A10_PINMUX_H */ | ||||
| @@ -1,128 +0,0 @@ | ||||
| /* | ||||
|  * This file is part of the coreboot project. | ||||
|  * | ||||
|  * Copyright (C) 2007-2011 Allwinner Technology Co., Ltd. | ||||
|  *	Tom Cubie <tangliang@allwinnertech.com> | ||||
|  * Copyright (C) 2013  Alexandru Gagniuc <mr.nuke.me@gmail.com> | ||||
|  * | ||||
|  * 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 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. | ||||
|  * | ||||
|  * Memory map definitions for Allwinner A10 CPUs | ||||
|  */ | ||||
|  | ||||
| #ifndef CPU_ALLWINNER_A10_MEMMAP_H | ||||
| #define CPU_ALLWINNER_A10_MEMMAP_H | ||||
|  | ||||
| #define A1X_SRAM_A1_BASE		0x00000000 | ||||
| #define A1X_SRAM_A1_SIZE		(16 * 1024)	/* 16 kiB */ | ||||
|  | ||||
| #define A1X_SRAM_A2_BASE		0x00004000	/* 16 kiB */ | ||||
| #define A1X_SRAM_A3_BASE		0x00008000	/* 13 kiB */ | ||||
| #define A1X_SRAM_A4_BASE		0x0000b400	/* 3 kiB */ | ||||
| #define A1X_SRAM_D_BASE			0x01c00000 | ||||
| #define A1X_SRAM_B_BASE			0x01c00000	/* 64 kiB (secure) */ | ||||
|  | ||||
| #define A1X_SRAMC_BASE			0x01c00000 | ||||
| #define A1X_DRAMC_BASE			0x01c01000 | ||||
| #define A1X_DMA_BASE			0x01c02000 | ||||
| #define A1X_NFC_BASE			0x01c03000 | ||||
| #define A1X_TS_BASE			0x01c04000 | ||||
| #define A1X_SPI0_BASE			0x01c05000 | ||||
| #define A1X_SPI1_BASE			0x01c06000 | ||||
| #define A1X_MS_BASE			0x01c07000 | ||||
| #define A1X_TVD_BASE			0x01c08000 | ||||
| #define A1X_CSI0_BASE			0x01c09000 | ||||
| #define A1X_TVE0_BASE			0x01c0a000 | ||||
| #define A1X_EMAC_BASE			0x01c0b000 | ||||
| #define A1X_LCD0_BASE			0x01c0C000 | ||||
| #define A1X_LCD1_BASE			0x01c0d000 | ||||
| #define A1X_VE_BASE			0x01c0e000 | ||||
| #define A1X_MMC0_BASE			0x01c0f000 | ||||
| #define A1X_MMC1_BASE			0x01c10000 | ||||
| #define A1X_MMC2_BASE			0x01c11000 | ||||
| #define A1X_MMC3_BASE			0x01c12000 | ||||
| #define A1X_USB0_BASE			0x01c13000 | ||||
| #define A1X_USB1_BASE			0x01c14000 | ||||
| #define A1X_SS_BASE			0x01c15000 | ||||
| #define A1X_HDMI_BASE			0x01c16000 | ||||
| #define A1X_SPI2_BASE			0x01c17000 | ||||
| #define A1X_SATA_BASE			0x01c18000 | ||||
| #define A1X_PATA_BASE			0x01c19000 | ||||
| #define A1X_ACE_BASE			0x01c1a000 | ||||
| #define A1X_TVE1_BASE			0x01c1b000 | ||||
| #define A1X_USB2_BASE			0x01c1c000 | ||||
| #define A1X_CSI1_BASE			0x01c1d000 | ||||
| #define A1X_TZASC_BASE			0x01c1e000 | ||||
| #define A1X_SPI3_BASE			0x01c1f000 | ||||
|  | ||||
| #define A1X_CCM_BASE			0x01c20000 | ||||
| #define A1X_INTC_BASE			0x01c20400 | ||||
| #define A1X_PIO_BASE			0x01c20800 | ||||
| #define A1X_TIMER_BASE			0x01c20c00 | ||||
| #define A1X_SPDIF_BASE			0x01c21000 | ||||
| #define A1X_AC97_BASE			0x01c21400 | ||||
| #define A1X_IR0_BASE			0x01c21800 | ||||
| #define A1X_IR1_BASE			0x01c21c00 | ||||
|  | ||||
| #define A1X_IIS_BASE			0x01c22400 | ||||
| #define A1X_LRADC_BASE			0x01c22800 | ||||
| #define A1X_AD_DA_BASE			0x01c22c00 | ||||
| #define A1X_KEYPAD_BASE			0x01c23000 | ||||
| #define A1X_TZPC_BASE			0x01c23400 | ||||
| #define A1X_SID_BASE			0x01c23800 | ||||
| #define A1X_SJTAG_BASE			0x01c23c00 | ||||
|  | ||||
| #define A1X_TP_BASE			0x01c25000 | ||||
| #define A1X_PMU_BASE			0x01c25400 | ||||
| #define A1X_CPUCFG_BASE			0x01c25c00	/* sun7i only ? */ | ||||
|  | ||||
| #define A1X_UART0_BASE			0x01c28000 | ||||
| #define A1X_UART1_BASE			0x01c28400 | ||||
| #define A1X_UART2_BASE			0x01c28800 | ||||
| #define A1X_UART3_BASE			0x01c28c00 | ||||
| #define A1X_UART4_BASE			0x01c29000 | ||||
| #define A1X_UART5_BASE			0x01c29400 | ||||
| #define A1X_UART6_BASE			0x01c29800 | ||||
| #define A1X_UART7_BASE			0x01c29c00 | ||||
| #define A1X_PS2_0_BASE			0x01c2a000 | ||||
| #define A1X_PS2_1_BASE			0x01c2a400 | ||||
|  | ||||
| #define A1X_TWI0_BASE			0x01c2ac00 | ||||
| #define A1X_TWI1_BASE			0x01c2b000 | ||||
| #define A1X_TWI2_BASE			0x01c2b400 | ||||
|  | ||||
| #define A1X_CAN_BASE			0x01c2bc00 | ||||
|  | ||||
| #define A1X_SCR_BASE			0x01c2c400 | ||||
|  | ||||
| #define A1X_GPS_BASE			0x01c30000 | ||||
| #define A1X_MALI400_BASE		0x01c40000 | ||||
|  | ||||
| /* module sram */ | ||||
| #define A1X_SRAM_C_BASE			0x01d00000 | ||||
|  | ||||
| #define A1X_DE_FE0_BASE			0x01e00000 | ||||
| #define A1X_DE_FE1_BASE			0x01e20000 | ||||
| #define A1X_DE_BE0_BASE			0x01e60000 | ||||
| #define A1X_DE_BE1_BASE			0x01e40000 | ||||
| #define A1X_MP_BASE			0x01e80000 | ||||
| #define A1X_AVG_BASE			0x01ea0000 | ||||
|  | ||||
| /* CoreSight Debug Module */ | ||||
| #define A1X_CSDM_BASE			0x3f500000 | ||||
|  | ||||
| #define A1X_DRAM_BASE			0x40000000	/* 2 GiB */ | ||||
|  | ||||
| #define A1X_BROM_BASE			0xffff0000	/* 32 kiB */ | ||||
|  | ||||
| #define A1X_CPU_CFG			(A1X_TIMER_BASE + 0x13c) | ||||
|  | ||||
| #endif				/* CPU_ALLWINNER_A10_MEMMAP_H */ | ||||
| @@ -1,92 +0,0 @@ | ||||
| /* | ||||
|  * This file is part of the coreboot project. | ||||
|  * | ||||
|  * Copyright (C) 2013  Alexandru Gagniuc <mr.nuke.me@gmail.com> | ||||
|  * | ||||
|  * 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 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. | ||||
|  * | ||||
|  * | ||||
|  * Helpers to multiplex and configure pins on Allwinner SoCs | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include "gpio.h" | ||||
|  | ||||
| #include <device/mmio.h> | ||||
|  | ||||
| static struct a10_gpio *const gpio = (void *)GPIO_BASE; | ||||
|  | ||||
| /** | ||||
|  * \brief Set the pad function of a single pin | ||||
|  * | ||||
|  * @param[in] port GPIO port of the pin (GPA -> GPS) | ||||
|  * @param[in] pin the pin number in the given port (1 -> 31) | ||||
|  * @param[in] pad_func The peripheral function to which to connect this pin | ||||
|  */ | ||||
| void gpio_set_pin_func(u8 port, u8 pin, u8 pad_func) | ||||
| { | ||||
| 	u8 reg, bit; | ||||
| 	u32 reg32; | ||||
|  | ||||
| 	if ((port > GPS)) | ||||
| 		return; | ||||
|  | ||||
| 	pin &= 0x1f; | ||||
| 	reg = pin / 8; | ||||
| 	bit = (pin % 8) * 4; | ||||
|  | ||||
| 	reg32 = read32(&gpio->port[port].cfg[reg]); | ||||
| 	reg32 &= ~(0xf << bit); | ||||
| 	reg32 |= (pad_func & 0xf) << bit; | ||||
| 	write32(&gpio->port[port].cfg[reg], reg32); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * \brief Set the pad function of a group of pins | ||||
|  * | ||||
|  * Multiplex a group of pins to the same pad function. This is useful for | ||||
|  * peripherals that use the same function number for several pins. This function | ||||
|  * allows those pins to be set with a single call. | ||||
|  * | ||||
|  * Example: | ||||
|  *	gpio_set_multipin_func(GPB, (1 << 23) | (1 << 22), 2); | ||||
|  * | ||||
|  * @param[in] port GPIO port of the pin (GPA -> GPS) | ||||
|  * @param[in] pin_mask 32-bit mask indicating which pins to re-multiplex. For | ||||
|  *			each set bit, the corresponding pin will be multiplexed. | ||||
|  * @param[in] pad_func The peripheral function to which to connect the pins | ||||
|  */ | ||||
| void gpio_set_multipin_func(u8 port, u32 pin_mask, u8 pad_func) | ||||
| { | ||||
| 	int j; | ||||
| 	u8 reg, bit; | ||||
| 	u32 reg32, mask_offset; | ||||
|  | ||||
| 	if ((port > GPS)) | ||||
| 		return; | ||||
|  | ||||
| 	for (reg = 0; reg < 4; reg++) { | ||||
| 		mask_offset = 8 * reg; | ||||
| 		/* Don't run the inner loop if we're not touching any pins */ | ||||
| 		if (!(pin_mask & (0xff << mask_offset))) | ||||
| 			continue; | ||||
|  | ||||
| 		reg32 = read32(&gpio->port[port].cfg[reg]); | ||||
| 		for (j = 0; j < 8; j++) { | ||||
| 			if (!(pin_mask & (1 << (j + mask_offset)))) | ||||
| 				continue; | ||||
| 			bit = j * 4; | ||||
| 			reg32 &= ~(0xf << bit); | ||||
| 			reg32 |= (pad_func & 0xf) << bit; | ||||
| 		} | ||||
| 		write32(&gpio->port[port].cfg[reg], reg32); | ||||
| 	} | ||||
| } | ||||
| @@ -1,42 +0,0 @@ | ||||
| /* | ||||
|  * This file is part of the coreboot project. | ||||
|  * | ||||
|  * Copyright (C) 2014  Alexandru Gagniuc <mr.nuke.me@gmail.com> | ||||
|  * | ||||
|  * 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 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. | ||||
|  * | ||||
|  * | ||||
|  * How we use DRAM on Allwinner CPUs | ||||
|  */ | ||||
|  | ||||
| #include <symbols.h> | ||||
|  | ||||
| /* | ||||
|  * Put CBMEM at top of RAM | ||||
|  */ | ||||
| static inline void *a1x_get_cbmem_top(void) | ||||
| { | ||||
| 	return _dram + (CONFIG_DRAM_SIZE_MB << 20); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * By CBFS cache, we mean a cached copy, in RAM, of the entire CBFS region. | ||||
|  */ | ||||
| static inline void *a1x_get_cbfs_cache_top(void) | ||||
| { | ||||
| 	/* Arbitrary 16 MiB gap for cbmem tables and bouncebuffer */ | ||||
| 	return a1x_get_cbmem_top() - (16 << 20); | ||||
| } | ||||
|  | ||||
| static inline void *a1x_get_cbfs_cache_base(void) | ||||
| { | ||||
| 	return a1x_get_cbfs_cache_top() - CONFIG_ROM_SIZE; | ||||
| } | ||||
| @@ -1,478 +0,0 @@ | ||||
| /* | ||||
|  * This file is part of the coreboot project. | ||||
|  * | ||||
|  * Copyright (C) 2012 Henrik Nordstrom <henrik@henriknordstrom.net> | ||||
|  * Copyright (C) 2013 Luke Kenneth Casson Leighton <lkcl@lkcl.net> | ||||
|  * Copyright (C) 2007-2012 Allwinner Technology Co., Ltd. | ||||
|  *	Berg Xing <bergxing@allwinnertech.com> | ||||
|  *	Tom Cubie <tangliang@allwinnertech.com> | ||||
|  * Copyright (C) 2013  Alexandru Gagniuc <mr.nuke.me@gmail.com> | ||||
|  * | ||||
|  * 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  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. | ||||
|  * | ||||
|  * Allwinner A10 DRAM controller initialization | ||||
|  * | ||||
|  * Based on sun4i Linux kernel sources mach-sunxi/pm/standby/dram*.c | ||||
|  * and earlier U-Boot Allwiner A10 SPL work | ||||
|  */ | ||||
|  | ||||
| #include "clock.h" | ||||
| #include "dramc.h" | ||||
| #include "memmap.h" | ||||
| #include "timer.h" | ||||
|  | ||||
| #include <device/mmio.h> | ||||
| #include <delay.h> | ||||
|  | ||||
| static struct a1x_dramc *const dram = (void *)A1X_DRAMC_BASE; | ||||
|  | ||||
| static void mctl_ddr3_reset(void) | ||||
| { | ||||
| 	if (a1x_get_cpu_chip_revision() != A1X_CHIP_REV_A) { | ||||
| 		setbits_le32(&dram->mcr, DRAM_MCR_RESET); | ||||
| 		udelay(2); | ||||
| 		clrbits_le32(&dram->mcr, DRAM_MCR_RESET); | ||||
| 	} else { | ||||
| 		clrbits_le32(&dram->mcr, DRAM_MCR_RESET); | ||||
| 		udelay(2); | ||||
| 		setbits_le32(&dram->mcr, DRAM_MCR_RESET); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void mctl_set_drive(void) | ||||
| { | ||||
| 	clrsetbits_le32(&dram->mcr, DRAM_MCR_MODE_NORM(0x3), | ||||
| 			DRAM_MCR_MODE_EN(0x3) | 0xffc); | ||||
| } | ||||
|  | ||||
| static void mctl_itm_disable(void) | ||||
| { | ||||
| 	clrsetbits_le32(&dram->ccr, DRAM_CCR_INIT, DRAM_CCR_ITM_OFF); | ||||
| } | ||||
|  | ||||
| static void mctl_itm_enable(void) | ||||
| { | ||||
| 	clrbits_le32(&dram->ccr, DRAM_CCR_ITM_OFF); | ||||
| } | ||||
|  | ||||
| static void mctl_enable_dll0(u32 phase) | ||||
| { | ||||
| 	clrsetbits_le32(&dram->dllcr[0], 0x3f << 6, | ||||
| 			((phase >> 16) & 0x3f) << 6); | ||||
| 	clrsetbits_le32(&dram->dllcr[0], DRAM_DLLCR_NRESET, DRAM_DLLCR_DISABLE); | ||||
| 	udelay(2); | ||||
|  | ||||
| 	clrbits_le32(&dram->dllcr[0], DRAM_DLLCR_NRESET | DRAM_DLLCR_DISABLE); | ||||
| 	udelay(22); | ||||
|  | ||||
| 	clrsetbits_le32(&dram->dllcr[0], DRAM_DLLCR_DISABLE, DRAM_DLLCR_NRESET); | ||||
| 	udelay(22); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Note: This differs from pm/standby in that it checks the bus width | ||||
|  */ | ||||
| static void mctl_enable_dllx(u32 phase) | ||||
| { | ||||
| 	u32 i, n, bus_width; | ||||
|  | ||||
| 	bus_width = read32(&dram->dcr); | ||||
|  | ||||
| 	if ((bus_width & DRAM_DCR_BUS_WIDTH_MASK) == | ||||
| 	    DRAM_DCR_BUS_WIDTH(DRAM_DCR_BUS_WIDTH_32BIT)) | ||||
| 		n = DRAM_DCR_NR_DLLCR_32BIT; | ||||
| 	else | ||||
| 		n = DRAM_DCR_NR_DLLCR_16BIT; | ||||
|  | ||||
| 	for (i = 1; i < n; i++) { | ||||
| 		clrsetbits_le32(&dram->dllcr[i], 0x4 << 14, | ||||
| 				(phase & 0xf) << 14); | ||||
| 		clrsetbits_le32(&dram->dllcr[i], DRAM_DLLCR_NRESET, | ||||
| 				DRAM_DLLCR_DISABLE); | ||||
| 		phase >>= 4; | ||||
| 	} | ||||
| 	udelay(2); | ||||
|  | ||||
| 	for (i = 1; i < n; i++) | ||||
| 		clrbits_le32(&dram->dllcr[i], DRAM_DLLCR_NRESET | | ||||
| 			     DRAM_DLLCR_DISABLE); | ||||
| 	udelay(22); | ||||
|  | ||||
| 	for (i = 1; i < n; i++) | ||||
| 		clrsetbits_le32(&dram->dllcr[i], DRAM_DLLCR_DISABLE, | ||||
| 				DRAM_DLLCR_NRESET); | ||||
| 	udelay(22); | ||||
| } | ||||
|  | ||||
| static u32 hpcr_value[32] = { | ||||
| 	0x0301, 0x0301, 0x0301, 0x0301, | ||||
| 	0x0301, 0x0301, 0, 0, | ||||
| 	0, 0, 0, 0, | ||||
| 	0, 0, 0, 0, | ||||
| 	0x1031, 0x1031, 0x0735, 0x1035, | ||||
| 	0x1035, 0x0731, 0x1031, 0x0735, | ||||
| 	0x1035, 0x1031, 0x0731, 0x1035, | ||||
| 	0x1031, 0x0301, 0x0301, 0x0731 | ||||
| }; | ||||
|  | ||||
| static void mctl_configure_hostport(void) | ||||
| { | ||||
| 	u32 i; | ||||
|  | ||||
| 	for (i = 0; i < 32; i++) | ||||
| 		write32(&dram->hpcr[i], hpcr_value[i]); | ||||
| } | ||||
|  | ||||
| static void mctl_setup_dram_clock(u32 clk) | ||||
| { | ||||
| 	/* setup DRAM PLL */ | ||||
| 	a1x_pll5_configure(clk / 24, 2, 2, 1); | ||||
|  | ||||
| 	/* FIXME: This bit is not documented for A10, and altering it doesn't | ||||
| 	 * seem to change anything. | ||||
| 	 * | ||||
| 	 * #define CCM_PLL5_CTRL_VCO_GAIN (0x1 << 19) | ||||
| 	 * reg_val = read32(&ccm->pll5_cfg); | ||||
| 	 * reg_val &= ~CCM_PLL5_CTRL_VCO_GAIN;  // PLL VCO Gain off | ||||
| 	 * write32(reg_val, &ccm->pll5_cfg); | ||||
| 	 */ | ||||
| 	udelay(5500); | ||||
|  | ||||
| 	a1x_pll5_enable_dram_clock_output(); | ||||
|  | ||||
| 	/* reset GPS */ | ||||
| 	/* FIXME: These bits are also undocumented, and seem to have no effect | ||||
| 	 * on A10. | ||||
| 	 * | ||||
| 	 * #define CCM_GPS_CTRL_RESET (0x1 << 0) | ||||
| 	 * #define CCM_GPS_CTRL_GATE (0x1 << 1) | ||||
| 	 * clrbits_le32(&ccm->gps_clk_cfg, CCM_GPS_CTRL_RESET | CCM_GPS_CTRL_GATE); | ||||
| 	 */ | ||||
| 	a1x_periph_clock_enable(A1X_CLKEN_GPS); | ||||
| 	udelay(1); | ||||
| 	a1x_periph_clock_disable(A1X_CLKEN_GPS); | ||||
|  | ||||
| 	/* setup MBUS clock */ | ||||
| 	/* FIXME: The MBUS does not seem to be present or do anything on A10. It | ||||
| 	 * is documented in the A13 user manual, but changing settings on A10 | ||||
| 	 * has no effect. | ||||
| 	 * | ||||
| 	 * #define CCM_MBUS_CTRL_M(n) (((n) & 0xf) << 0) | ||||
| 	 * #define CCM_MBUS_CTRL_M_MASK CCM_MBUS_CTRL_M(0xf) | ||||
| 	 * #define CCM_MBUS_CTRL_M_X(n) ((n) - 1) | ||||
| 	 * #define CCM_MBUS_CTRL_N(n) (((n) & 0xf) << 16) | ||||
| 	 * #define CCM_MBUS_CTRL_N_MASK CCM_MBUS_CTRL_N(0xf) | ||||
| 	 * #define CCM_MBUS_CTRL_N_X(n) (((n) >> 3) ? 3 : (((n) >> 2) ? 2 : (((n) >> 1) ? 1 : 0))) | ||||
| 	 * #define CCM_MBUS_CTRL_CLK_SRC(n) (((n) & 0x3) << 24) | ||||
| 	 * #define CCM_MBUS_CTRL_CLK_SRC_MASK CCM_MBUS_CTRL_CLK_SRC(0x3) | ||||
| 	 * #define CCM_MBUS_CTRL_CLK_SRC_HOSC 0x0 | ||||
| 	 * #define CCM_MBUS_CTRL_CLK_SRC_PLL6 0x1 | ||||
| 	 * #define CCM_MBUS_CTRL_CLK_SRC_PLL5 0x2 | ||||
| 	 * #define CCM_MBUS_CTRL_GATE (0x1 << 31) | ||||
| 	 * reg_val = CCM_MBUS_CTRL_GATE | | ||||
| 	 *           CCM_MBUS_CTRL_CLK_SRC(CCM_MBUS_CTRL_CLK_SRC_PLL5) | | ||||
| 	 *           CCM_MBUS_CTRL_N(CCM_MBUS_CTRL_N_X(1)) | | ||||
| 	 *           CCM_MBUS_CTRL_M(CCM_MBUS_CTRL_M_X(2)); | ||||
| 	 * write32(reg_val, &ccm->mbus_clk_cfg); | ||||
| 	 */ | ||||
| 	/* | ||||
| 	 * open DRAMC AHB & DLL register clock | ||||
| 	 * close it first | ||||
| 	 */ | ||||
| 	a1x_periph_clock_disable(A1X_CLKEN_SDRAM); | ||||
|  | ||||
| 	udelay(22); | ||||
|  | ||||
| 	/* then open it */ | ||||
| 	a1x_periph_clock_enable(A1X_CLKEN_SDRAM); | ||||
| 	udelay(22); | ||||
| } | ||||
|  | ||||
| static int dramc_scan_readpipe(void) | ||||
| { | ||||
| 	u32 reg32; | ||||
|  | ||||
| 	/* data training trigger */ | ||||
| 	setbits_le32(&dram->ccr, DRAM_CCR_DATA_TRAINING); | ||||
|  | ||||
| 	/* check whether data training process has completed */ | ||||
| 	while (read32(&dram->ccr) & DRAM_CCR_DATA_TRAINING); | ||||
|  | ||||
| 	/* check data training result */ | ||||
| 	reg32 = read32(&dram->csr); | ||||
| 	if (reg32 & DRAM_CSR_FAILED) | ||||
| 		return -1; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int dramc_scan_dll_para(void) | ||||
| { | ||||
| 	const u32 dqs_dly[7] = { 0x3, 0x2, 0x1, 0x0, 0xe, 0xd, 0xc }; | ||||
| 	const u32 clk_dly[15] = { 0x07, 0x06, 0x05, 0x04, 0x03, | ||||
| 		0x02, 0x01, 0x00, 0x08, 0x10, | ||||
| 		0x18, 0x20, 0x28, 0x30, 0x38 | ||||
| 	}; | ||||
| 	u32 clk_dqs_count[15]; | ||||
| 	u32 dqs_i, clk_i, cr_i; | ||||
| 	u32 max_val, min_val; | ||||
| 	u32 dqs_index, clk_index; | ||||
|  | ||||
| 	/* Find DQS_DLY Pass Count for every CLK_DLY */ | ||||
| 	for (clk_i = 0; clk_i < 15; clk_i++) { | ||||
| 		clk_dqs_count[clk_i] = 0; | ||||
| 		clrsetbits_le32(&dram->dllcr[0], 0x3f << 6, | ||||
| 				(clk_dly[clk_i] & 0x3f) << 6); | ||||
| 		for (dqs_i = 0; dqs_i < 7; dqs_i++) { | ||||
| 			for (cr_i = 1; cr_i < 5; cr_i++) { | ||||
| 				clrsetbits_le32(&dram->dllcr[cr_i], | ||||
| 						0x4f << 14, | ||||
| 						(dqs_dly[dqs_i] & 0x4f) << 14); | ||||
| 			} | ||||
| 			udelay(2); | ||||
| 			if (dramc_scan_readpipe() == 0) | ||||
| 				clk_dqs_count[clk_i]++; | ||||
| 		} | ||||
| 	} | ||||
| 	/* Test DQS_DLY Pass Count for every CLK_DLY from up to down */ | ||||
| 	for (dqs_i = 15; dqs_i > 0; dqs_i--) { | ||||
| 		max_val = 15; | ||||
| 		min_val = 15; | ||||
| 		for (clk_i = 0; clk_i < 15; clk_i++) { | ||||
| 			if (clk_dqs_count[clk_i] == dqs_i) { | ||||
| 				max_val = clk_i; | ||||
| 				if (min_val == 15) | ||||
| 					min_val = clk_i; | ||||
| 			} | ||||
| 		} | ||||
| 		if (max_val < 15) | ||||
| 			break; | ||||
| 	} | ||||
|  | ||||
| 	/* Check if Find a CLK_DLY failed */ | ||||
| 	if (!dqs_i) | ||||
| 		goto fail; | ||||
|  | ||||
| 	/* Find the middle index of CLK_DLY */ | ||||
| 	clk_index = (max_val + min_val) >> 1; | ||||
| 	if ((max_val == (15 - 1)) && (min_val > 0)) | ||||
| 		/* if CLK_DLY[MCTL_CLK_DLY_COUNT] is very good, then the middle | ||||
| 		 * value can be more close to the max_val | ||||
| 		 */ | ||||
| 		clk_index = (15 + clk_index) >> 1; | ||||
| 	else if ((max_val < (15 - 1)) && (min_val == 0)) | ||||
| 		/* if CLK_DLY[0] is very good, then the middle value can be more | ||||
| 		 * close to the min_val | ||||
| 		 */ | ||||
| 		clk_index >>= 1; | ||||
| 	if (clk_dqs_count[clk_index] < dqs_i) | ||||
| 		clk_index = min_val; | ||||
|  | ||||
| 	/* Find the middle index of DQS_DLY for the CLK_DLY got above, and Scan | ||||
| 	 * read pipe again | ||||
| 	 */ | ||||
| 	clrsetbits_le32(&dram->dllcr[0], 0x3f << 6, | ||||
| 			(clk_dly[clk_index] & 0x3f) << 6); | ||||
| 	max_val = 7; | ||||
| 	min_val = 7; | ||||
| 	for (dqs_i = 0; dqs_i < 7; dqs_i++) { | ||||
| 		clk_dqs_count[dqs_i] = 0; | ||||
| 		for (cr_i = 1; cr_i < 5; cr_i++) { | ||||
| 			clrsetbits_le32(&dram->dllcr[cr_i], | ||||
| 					0x4f << 14, | ||||
| 					(dqs_dly[dqs_i] & 0x4f) << 14); | ||||
| 		} | ||||
| 		udelay(2); | ||||
| 		if (dramc_scan_readpipe() == 0) { | ||||
| 			clk_dqs_count[dqs_i] = 1; | ||||
| 			max_val = dqs_i; | ||||
| 			if (min_val == 7) | ||||
| 				min_val = dqs_i; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (max_val < 7) { | ||||
| 		dqs_index = (max_val + min_val) >> 1; | ||||
| 		if ((max_val == (7 - 1)) && (min_val > 0)) | ||||
| 			dqs_index = (7 + dqs_index) >> 1; | ||||
| 		else if ((max_val < (7 - 1)) && (min_val == 0)) | ||||
| 			dqs_index >>= 1; | ||||
| 		if (!clk_dqs_count[dqs_index]) | ||||
| 			dqs_index = min_val; | ||||
| 		for (cr_i = 1; cr_i < 5; cr_i++) { | ||||
| 			clrsetbits_le32(&dram->dllcr[cr_i], | ||||
| 					0x4f << 14, | ||||
| 					(dqs_dly[dqs_index] & 0x4f) << 14); | ||||
| 		} | ||||
| 		udelay(2); | ||||
| 		return dramc_scan_readpipe(); | ||||
| 	} | ||||
|  | ||||
| fail: | ||||
| 	clrbits_le32(&dram->dllcr[0], 0x3f << 6); | ||||
| 	for (cr_i = 1; cr_i < 5; cr_i++) | ||||
| 		clrbits_le32(&dram->dllcr[cr_i], 0x4f << 14); | ||||
| 	udelay(2); | ||||
|  | ||||
| 	return dramc_scan_readpipe(); | ||||
| } | ||||
|  | ||||
| static void dramc_set_autorefresh_cycle(u32 clk) | ||||
| { | ||||
| 	u32 reg32; | ||||
| 	u32 tmp_val; | ||||
| 	u32 reg_dcr; | ||||
|  | ||||
| 	if (clk < 600) { | ||||
| 		reg_dcr = read32(&dram->dcr); | ||||
| 		if ((reg_dcr & DRAM_DCR_CHIP_DENSITY_MASK) <= | ||||
| 		    DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_1024M)) | ||||
| 			reg32 = (131 * clk) >> 10; | ||||
| 		else | ||||
| 			reg32 = (336 * clk) >> 10; | ||||
|  | ||||
| 		tmp_val = (7987 * clk) >> 10; | ||||
| 		tmp_val = tmp_val * 9 - 200; | ||||
| 		reg32 |= tmp_val << 8; | ||||
| 		reg32 |= 0x8 << 24; | ||||
| 		write32(&dram->drr, reg32); | ||||
| 	} else { | ||||
| 		write32(&dram->drr, 0x0); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| unsigned long dramc_init(struct dram_para *para) | ||||
| { | ||||
| 	u32 reg32; | ||||
| 	int ret_val; | ||||
|  | ||||
| 	/* check input dram parameter structure */ | ||||
| 	if (!para) | ||||
| 		return 0; | ||||
|  | ||||
| 	/* setup DRAM relative clock */ | ||||
| 	mctl_setup_dram_clock(para->clock); | ||||
|  | ||||
| 	/* reset external DRAM */ | ||||
| 	mctl_ddr3_reset(); | ||||
|  | ||||
| 	mctl_set_drive(); | ||||
|  | ||||
| 	/* dram clock off */ | ||||
| 	a1x_gate_dram_clock_output(); | ||||
|  | ||||
| 	/* select dram controller 1 */ | ||||
| 	write32(&dram->csel, DRAM_CSEL_MAGIC); | ||||
|  | ||||
| 	mctl_itm_disable(); | ||||
| 	mctl_enable_dll0(para->tpr3); | ||||
|  | ||||
| 	/* configure external DRAM */ | ||||
| 	reg32 = 0x0; | ||||
| 	if (para->type == DRAM_MEMORY_TYPE_DDR3) | ||||
| 		reg32 |= DRAM_DCR_TYPE_DDR3; | ||||
| 	reg32 |= DRAM_DCR_IO_WIDTH(para->io_width >> 3); | ||||
|  | ||||
| 	if (para->density == 256) | ||||
| 		reg32 |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_256M); | ||||
| 	else if (para->density == 512) | ||||
| 		reg32 |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_512M); | ||||
| 	else if (para->density == 1024) | ||||
| 		reg32 |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_1024M); | ||||
| 	else if (para->density == 2048) | ||||
| 		reg32 |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_2048M); | ||||
| 	else if (para->density == 4096) | ||||
| 		reg32 |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_4096M); | ||||
| 	else if (para->density == 8192) | ||||
| 		reg32 |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_8192M); | ||||
| 	else | ||||
| 		reg32 |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_256M); | ||||
|  | ||||
| 	reg32 |= DRAM_DCR_BUS_WIDTH((para->bus_width >> 3) - 1); | ||||
| 	reg32 |= DRAM_DCR_RANK_SEL(para->rank_num - 1); | ||||
| 	reg32 |= DRAM_DCR_CMD_RANK_ALL; | ||||
| 	reg32 |= DRAM_DCR_MODE(DRAM_DCR_MODE_INTERLEAVE); | ||||
| 	write32(&dram->dcr, reg32); | ||||
|  | ||||
| 	/* dram clock on */ | ||||
| 	a1x_ungate_dram_clock_output(); | ||||
|  | ||||
| 	udelay(1); | ||||
|  | ||||
| 	while (read32(&dram->ccr) & DRAM_CCR_INIT); | ||||
|  | ||||
| 	mctl_enable_dllx(para->tpr3); | ||||
|  | ||||
| 	/* set odt impendance divide ratio */ | ||||
| 	reg32 = ((para->zq) >> 8) & 0xfffff; | ||||
| 	reg32 |= ((para->zq) & 0xff) << 20; | ||||
| 	reg32 |= (para->zq) & 0xf0000000; | ||||
| 	write32(&dram->zqcr0, reg32); | ||||
|  | ||||
| 	/* set I/O configure register */ | ||||
| 	reg32 = 0x00cc0000; | ||||
| 	reg32 |= (para->odt_en) & 0x3; | ||||
| 	reg32 |= ((para->odt_en) & 0x3) << 30; | ||||
| 	write32(&dram->iocr, reg32); | ||||
|  | ||||
| 	/* set refresh period */ | ||||
| 	dramc_set_autorefresh_cycle(para->clock); | ||||
|  | ||||
| 	/* set timing parameters */ | ||||
| 	write32(&dram->tpr0, para->tpr0); | ||||
| 	write32(&dram->tpr1, para->tpr1); | ||||
| 	write32(&dram->tpr2, para->tpr2); | ||||
|  | ||||
| 	if (para->type == DRAM_MEMORY_TYPE_DDR3) { | ||||
| 		reg32 = DRAM_MR_BURST_LENGTH(0x0); | ||||
| 		reg32 |= DRAM_MR_CAS_LAT(para->cas - 4); | ||||
| 		reg32 |= DRAM_MR_WRITE_RECOVERY(0x5); | ||||
| 	} else if (para->type == DRAM_MEMORY_TYPE_DDR2) { | ||||
| 		reg32 = DRAM_MR_BURST_LENGTH(0x2); | ||||
| 		reg32 |= DRAM_MR_CAS_LAT(para->cas); | ||||
| 		reg32 |= DRAM_MR_WRITE_RECOVERY(0x5); | ||||
| 	} | ||||
| 	write32(&dram->mr, reg32); | ||||
|  | ||||
| 	write32(&dram->emr, para->emr1); | ||||
| 	write32(&dram->emr2, para->emr2); | ||||
| 	write32(&dram->emr3, para->emr3); | ||||
|  | ||||
| 	/* set DQS window mode */ | ||||
| 	clrsetbits_le32(&dram->ccr, DRAM_CCR_DQS_DRIFT_COMP, DRAM_CCR_DQS_GATE); | ||||
|  | ||||
| 	/* reset external DRAM */ | ||||
| 	setbits_le32(&dram->ccr, DRAM_CCR_INIT); | ||||
| 	while (read32(&dram->ccr) & DRAM_CCR_INIT); | ||||
|  | ||||
| 	/* scan read pipe value */ | ||||
| 	mctl_itm_enable(); | ||||
| 	if (para->tpr3 & (0x1 << 31)) { | ||||
| 		ret_val = dramc_scan_dll_para(); | ||||
| 		if (ret_val == 0) | ||||
| 			para->tpr3 = | ||||
| 			    (((read32(&dram->dllcr[0]) >> 6) & 0x3f) << 16) | | ||||
| 			    (((read32(&dram->dllcr[1]) >> 14) & 0xf) << 0) | | ||||
| 			    (((read32(&dram->dllcr[2]) >> 14) & 0xf) << 4) | | ||||
| 			    (((read32(&dram->dllcr[3]) >> 14) & 0xf) << 8) | | ||||
| 			    (((read32(&dram->dllcr[4]) >> 14) & 0xf) << 12); | ||||
| 	} else { | ||||
| 		ret_val = dramc_scan_readpipe(); | ||||
| 	} | ||||
|  | ||||
| 	if (ret_val < 0) | ||||
| 		return 0; | ||||
|  | ||||
| 	/* configure all host port */ | ||||
| 	mctl_configure_hostport(); | ||||
|  | ||||
| 	return para->size; | ||||
| } | ||||
| @@ -1,77 +0,0 @@ | ||||
| /* | ||||
|  * This file is part of the coreboot project. | ||||
|  * | ||||
|  * Copyright (C) 2013  Alexandru Gagniuc <mr.nuke.me@gmail.com> | ||||
|  * | ||||
|  * 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 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. | ||||
|  * | ||||
|  * Timer control and delays for Allwinner CPUs | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include <device/mmio.h> | ||||
| #include <delay.h> | ||||
|  | ||||
| #include "timer.h" | ||||
|  | ||||
| struct a1x_timer_module *const timer_module = (void *)A1X_TIMER_BASE; | ||||
| struct a1x_timer *const tmr0 = | ||||
| 		&((struct a1x_timer_module *)A1X_TIMER_BASE)->timer[0]; | ||||
|  | ||||
| static inline u32 read_timer(void) | ||||
| { | ||||
| 	return read32(&tmr0->val); | ||||
| } | ||||
|  | ||||
| void init_timer(void) | ||||
| { | ||||
| 	u32 reg32; | ||||
| 	/* Load the timer rollover value */ | ||||
| 	write32(&tmr0->interval, 0xffffffff); | ||||
| 	/* Configure the timer to run from 24MHz oscillator, no prescaler */ | ||||
| 	reg32 = TIMER_CTRL_PRESC_DIV_EXP(0); | ||||
| 	reg32 |= TIMER_CTRL_CLK_SRC_OSC24M; | ||||
| 	reg32 |= TIMER_CTRL_RELOAD; | ||||
| 	reg32 |= TIMER_CTRL_TMR_EN; | ||||
| 	write32(&tmr0->ctrl, reg32); | ||||
| } | ||||
|  | ||||
| void udelay(unsigned usec) | ||||
| { | ||||
| 	u32 curr_tick, last_tick; | ||||
| 	s32 ticks_left; | ||||
|  | ||||
| 	last_tick = read_timer(); | ||||
| 	/* 24 timer ticks per microsecond (24 MHz, divided by 1) */ | ||||
| 	ticks_left = usec * 24; | ||||
|  | ||||
| 	/* FIXME: Should we consider timer rollover? | ||||
| 	 * From when we start the timer, we have almost three minutes before it | ||||
| 	 * rolls over, so we should be long into having booted our payload. | ||||
| 	 */ | ||||
| 	while (ticks_left > 0) { | ||||
| 		curr_tick = read_timer(); | ||||
| 		/* Timer value decreases with each tick */ | ||||
| 		ticks_left -= last_tick - curr_tick; | ||||
| 		last_tick = curr_tick; | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This function has nothing to do with timers; however, the chip revision | ||||
|  * register is in the timer module, so keep this function here. | ||||
|  */ | ||||
| u8 a1x_get_cpu_chip_revision(void) | ||||
| { | ||||
| 	write32(&timer_module->cpu_cfg, 0); | ||||
| 	return (read32(&timer_module->cpu_cfg) >> 6) & 0x3; | ||||
| } | ||||
| @@ -1,110 +0,0 @@ | ||||
| /* | ||||
|  * This file is part of the coreboot project. | ||||
|  * | ||||
|  * Copyright (C) 2007-2011 Allwinner Technology Co., Ltd. | ||||
|  *	Tom Cubie <tangliang@allwinnertech.com> | ||||
|  * Copyright (C) 2013  Alexandru Gagniuc <mr.nuke.me@gmail.com> | ||||
|  * | ||||
|  * 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 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. | ||||
|  * | ||||
|  * Definitions for timer control on Allwinner CPUs | ||||
|  */ | ||||
|  | ||||
| #ifndef CPU_ALLWINNER_A10_TIMER_H | ||||
| #define CPU_ALLWINNER_A10_TIMER_H | ||||
|  | ||||
| #include "memmap.h" | ||||
| #include <types.h> | ||||
|  | ||||
| /* TMRx_CTRL values */ | ||||
| #define TIMER_CTRL_MODE_SINGLE		(1 << 7) | ||||
| #define TIMER_CTRL_PRESC_MASK		(0x7 << 4) | ||||
| #define  TIMER_CTRL_PRESC_DIV_EXP(ep)	((ep << 4) & TIMER_CTRL_PRESC_MASK) | ||||
| #define TIMER_CTRL_CLK_SRC_MASK		(0x3 << 2) | ||||
| #define  TIMER_CTRL_CLK_SRC_LOSC	(0x0 << 2) | ||||
| #define  TIMER_CTRL_CLK_SRC_OSC24M	(0x1 << 2) | ||||
| #define  TIMER_CTRL_CLK_SRC_PLL6	(0x2 << 2) | ||||
| #define TIMER_CTRL_RELOAD		(1 << 1) | ||||
| #define TIMER_CTRL_TMR_EN		(1 << 0) | ||||
|  | ||||
| /* Chip revision definitions (found in CPU_CFG register) */ | ||||
| #define A1X_CHIP_REV_A			0x0 | ||||
| #define A1X_CHIP_REV_C1			0x1 | ||||
| #define A1X_CHIP_REV_C2			0x2 | ||||
| #define A1X_CHIP_REV_B			0x3 | ||||
|  | ||||
|  | ||||
| /* General purpose timer */ | ||||
| struct a1x_timer { | ||||
| 	u32 ctrl; | ||||
| 	u32 interval; | ||||
| 	u32 val; | ||||
| 	u8 res[4]; | ||||
| } __packed; | ||||
|  | ||||
| /* Audio video sync*/ | ||||
| struct a1x_avs { | ||||
| 	u32 ctrl;		/* 0x80 */ | ||||
| 	u32 cnt0;		/* 0x84 */ | ||||
| 	u32 cnt1;		/* 0x88 */ | ||||
| 	u32 div;		/* 0x8c */ | ||||
| } __packed; | ||||
|  | ||||
| /* Watchdog */ | ||||
| struct a1x_wdog { | ||||
| 	u32 ctrl;		/* 0x90 */ | ||||
| 	u32 mode;		/* 0x94 */ | ||||
| } __packed; | ||||
|  | ||||
| /* 64 bit counter */ | ||||
| struct a1x_64cnt { | ||||
| 	u32 ctrl;		/* 0xa0 */ | ||||
| 	u32 lo;			/* 0xa4 */ | ||||
| 	u32 hi;			/* 0xa8 */ | ||||
| } __packed; | ||||
|  | ||||
| /* Rtc */ | ||||
| struct a1x_rtc { | ||||
| 	u32 ctrl;		/* 0x100 */ | ||||
| 	u32 yymmdd;		/* 0x104 */ | ||||
| 	u32 hhmmss;		/* 0x108 */ | ||||
| } __packed; | ||||
|  | ||||
| /* Alarm */ | ||||
| struct a1x_alarm { | ||||
| 	u32 ddhhmmss;		/* 0x10c */ | ||||
| 	u32 hhmmss;		/* 0x110 */ | ||||
| 	u32 en;			/* 0x114 */ | ||||
| 	u32 irq_en;		/* 0x118 */ | ||||
| 	u32 irq_sta;		/* 0x11c */ | ||||
| } __packed; | ||||
|  | ||||
| struct a1x_timer_module { | ||||
| 	u32 irq_en;		/* 0x00 */ | ||||
| 	u32 irq_sta;		/* 0x04 */ | ||||
| 	u8 res1[8]; | ||||
| 	struct a1x_timer timer[6];	/* We have 6 timers */ | ||||
| 	u8 res2[16]; | ||||
| 	struct a1x_avs avs; | ||||
| 	struct a1x_wdog wdog; | ||||
| 	u8 res3[8]; | ||||
| 	struct a1x_64cnt cnt64; | ||||
| 	u8 res4[0x58]; | ||||
| 	struct a1x_rtc rtc; | ||||
| 	struct a1x_alarm alarm; | ||||
| 	u32 gp_data[4]; | ||||
| 	u8 res5[8]; | ||||
| 	u32 cpu_cfg; | ||||
| } __packed; | ||||
|  | ||||
| u8 a1x_get_cpu_chip_revision(void); | ||||
|  | ||||
| #endif				/* CPU_ALLWINNER_A10_TIMER_H */ | ||||
| @@ -1,217 +0,0 @@ | ||||
| /* | ||||
|  * This file is part of the coreboot project. | ||||
|  * | ||||
|  * Copyright (C) 2012 Henrik Nordstrom <henrik@henriknordstrom.net> | ||||
|  * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com> | ||||
|  * | ||||
|  * 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 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. | ||||
|  * | ||||
|  * Setup helpers for Two Wire Interface (TWI) (I2C) Allwinner CPUs | ||||
|  * | ||||
|  * Only functionality for I2C master is provided. | ||||
|  * Largely based on the uboot-sunxi code. | ||||
|  */ | ||||
|  | ||||
| #include <device/mmio.h> | ||||
| #include <delay.h> | ||||
| #include <device/i2c_simple.h> | ||||
| #include <types.h> | ||||
|  | ||||
| #include "memmap.h" | ||||
| #include "twi.h" | ||||
|  | ||||
| #define TWI_BASE(n)			(A1X_TWI0_BASE + 0x400 * (n)) | ||||
|  | ||||
| #define TWI_TIMEOUT			(50 * 1000) | ||||
|  | ||||
| static u8 is_busy(struct a1x_twi *twi) | ||||
| { | ||||
| 	return (read32(&twi->stat) != TWI_STAT_IDLE); | ||||
| } | ||||
|  | ||||
| static enum cb_err wait_until_idle(struct a1x_twi *twi) | ||||
| { | ||||
| 	u32 i = TWI_TIMEOUT; | ||||
| 	while (i-- && is_busy((twi))) | ||||
| 		udelay(1); | ||||
| 	return i ? CB_SUCCESS : CB_ERR; | ||||
| } | ||||
|  | ||||
| /* FIXME: This function is basic, and unintelligent */ | ||||
| static void configure_clock(struct a1x_twi *twi, u32 speed_hz) | ||||
| { | ||||
| 	/* FIXME: We assume clock is 24MHz, which may not be the case */ | ||||
| 	u32 apb_clk = 24000000, m, n; | ||||
|  | ||||
| 	/* Pre-divide the clock by 8 */ | ||||
| 	n = 3; | ||||
| 	m = (apb_clk >> n) / speed_hz; | ||||
| 	write32(&twi->clk, TWI_CLK_M(m) | TWI_CLK_N(n)); | ||||
| } | ||||
|  | ||||
| void a1x_twi_init(u8 bus, u32 speed_hz) | ||||
| { | ||||
| 	u32 i = TWI_TIMEOUT; | ||||
| 	struct a1x_twi *twi = (void *)TWI_BASE(bus); | ||||
|  | ||||
| 	configure_clock(twi, speed_hz); | ||||
|  | ||||
| 	/* Enable the I2C bus */ | ||||
| 	write32(&twi->ctl, TWI_CTL_BUS_EN); | ||||
| 	/* Issue soft reset */ | ||||
| 	write32(&twi->reset, 1); | ||||
|  | ||||
| 	while (i-- && read32(&twi->reset)) | ||||
| 		udelay(1); | ||||
| } | ||||
|  | ||||
| static void clear_interrupt_flag(struct a1x_twi *twi) | ||||
| { | ||||
| 	write32(&twi->ctl, read32(&twi->ctl) & ~TWI_CTL_INT_FLAG); | ||||
| } | ||||
|  | ||||
| static void i2c_send_data(struct a1x_twi *twi, u8 data) | ||||
| { | ||||
| 	write32(&twi->data, data); | ||||
| 	clear_interrupt_flag(twi); | ||||
| } | ||||
|  | ||||
| static enum twi_status wait_for_status(struct a1x_twi *twi) | ||||
| { | ||||
| 	u32 i = TWI_TIMEOUT; | ||||
| 	/* Wait until interrupt is asserted again */ | ||||
| 	while (i-- && !(read32(&twi->ctl) & TWI_CTL_INT_FLAG)) | ||||
| 		udelay(1); | ||||
| 	/* A timeout here most likely indicates a bus error */ | ||||
| 	return i ? read32(&twi->stat) : TWI_STAT_BUS_ERROR; | ||||
| } | ||||
|  | ||||
| static void i2c_send_start(struct a1x_twi *twi) | ||||
| { | ||||
| 	u32 reg32, i; | ||||
|  | ||||
| 	/* Send START condition */ | ||||
| 	reg32 = read32(&twi->ctl); | ||||
| 	reg32 &= ~TWI_CTL_INT_FLAG; | ||||
| 	reg32 |= TWI_CTL_M_START; | ||||
| 	write32(&twi->ctl, reg32); | ||||
|  | ||||
| 	/* M_START is automatically cleared after condition is transmitted */ | ||||
| 	i = TWI_TIMEOUT; | ||||
| 	while (i-- && (read32(&twi->ctl) & TWI_CTL_M_START)) | ||||
| 		udelay(1); | ||||
| } | ||||
|  | ||||
| static void i2c_send_stop(struct a1x_twi *twi) | ||||
| { | ||||
| 	u32 reg32; | ||||
|  | ||||
| 	/* Send STOP condition */ | ||||
| 	reg32 = read32(&twi->ctl); | ||||
| 	reg32 &= ~TWI_CTL_INT_FLAG; | ||||
| 	reg32 |= TWI_CTL_M_STOP; | ||||
| 	write32(&twi->ctl, reg32); | ||||
| } | ||||
|  | ||||
| static int i2c_read(struct a1x_twi *twi, uint8_t chip, | ||||
| 			uint8_t *buf, size_t len) | ||||
| { | ||||
| 	unsigned count = len; | ||||
| 	enum twi_status expected_status; | ||||
|  | ||||
| 	/* Send restart for read */ | ||||
| 	i2c_send_start(twi); | ||||
| 	if (wait_for_status(twi) != TWI_STAT_TX_RSTART) | ||||
| 		return CB_ERR; | ||||
|  | ||||
| 	/* Send chip address */ | ||||
| 	i2c_send_data(twi, chip << 1 | 1); | ||||
| 	if (wait_for_status(twi) != TWI_STAT_TX_AR_ACK) | ||||
| 		return CB_ERR; | ||||
|  | ||||
| 	/* Start ACK-ing received data */ | ||||
| 	setbits_le32(&twi->ctl, TWI_CTL_A_ACK); | ||||
| 	expected_status = TWI_STAT_RXD_ACK; | ||||
|  | ||||
| 	/* Read data */ | ||||
| 	while (count > 0) { | ||||
| 		if (count == 1) { | ||||
| 			/* Do not ACK the last byte */ | ||||
| 			clrbits_le32(&twi->ctl, TWI_CTL_A_ACK); | ||||
| 			expected_status = TWI_STAT_RXD_NAK; | ||||
| 		} | ||||
|  | ||||
| 		clear_interrupt_flag(twi); | ||||
|  | ||||
| 		if (wait_for_status(twi) != expected_status) | ||||
| 			return CB_ERR; | ||||
|  | ||||
| 		*buf++ = read32(&twi->data); | ||||
| 		count--; | ||||
| 	} | ||||
|  | ||||
| 	return len; | ||||
| } | ||||
|  | ||||
| static int i2c_write(struct a1x_twi *twi, uint8_t chip, | ||||
| 		     const uint8_t *buf, size_t len) | ||||
| { | ||||
| 	size_t count = len; | ||||
|  | ||||
| 	i2c_send_start(twi); | ||||
| 	if (wait_for_status(twi) != TWI_STAT_TX_START) | ||||
| 		return CB_ERR; | ||||
|  | ||||
| 	/* Send chip address */ | ||||
| 	i2c_send_data(twi, chip << 1); | ||||
| 	if (wait_for_status(twi) != TWI_STAT_TX_AW_ACK) | ||||
| 		return CB_ERR; | ||||
|  | ||||
| 	/* Send data */ | ||||
| 	while (count > 0) { | ||||
| 		i2c_send_data(twi, *buf++); | ||||
| 		if (wait_for_status(twi) != TWI_STAT_TXD_ACK) | ||||
| 			return CB_ERR; | ||||
| 		count--; | ||||
| 	} | ||||
|  | ||||
| 	return len; | ||||
| } | ||||
|  | ||||
| int platform_i2c_transfer(unsigned bus, struct i2c_msg *segments, int count) | ||||
| { | ||||
| 	int i, ret = CB_SUCCESS; | ||||
| 	struct i2c_msg *seg = segments; | ||||
| 	struct a1x_twi *twi = (void *)TWI_BASE(bus); | ||||
|  | ||||
|  | ||||
| 	if (wait_until_idle(twi) != CB_SUCCESS) | ||||
| 		return CB_ERR; | ||||
|  | ||||
| 	for (i = 0; i < count; i++) { | ||||
| 		seg = segments + i; | ||||
|  | ||||
| 		if (seg->flags & I2C_M_RD) { | ||||
| 			ret = i2c_read(twi, seg->slave, seg->buf, seg->len); | ||||
| 			if (ret < 0) | ||||
| 				break; | ||||
| 		} else { | ||||
| 			ret = i2c_write(twi, seg->slave, seg->buf, seg->len); | ||||
| 			if (ret < 0) | ||||
| 				break; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* Don't worry about the status. STOP is on a best-effort basis */ | ||||
| 	i2c_send_stop(twi); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
| @@ -1,69 +0,0 @@ | ||||
| /* | ||||
|  * This file is part of the coreboot project. | ||||
|  * | ||||
|  * Copyright (C) 2013  Alexandru Gagniuc <mr.nuke.me@gmail.com> | ||||
|  * | ||||
|  * 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 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. | ||||
|  * | ||||
|  * Definitions Two Wire Interface (TWI) (I2C) Allwinner CPUs | ||||
|  */ | ||||
|  | ||||
| #ifndef CPU_ALLWINNER_A10_TWI_H | ||||
| #define CPU_ALLWINNER_A10_TWI_H | ||||
|  | ||||
| #include <types.h> | ||||
|  | ||||
| /* TWI_CTL values */ | ||||
| #define TWI_CTL_INT_EN		(1 << 7) | ||||
| #define TWI_CTL_BUS_EN		(1 << 6) | ||||
| #define TWI_CTL_M_START		(1 << 5) | ||||
| #define TWI_CTL_M_STOP		(1 << 4) | ||||
| #define TWI_CTL_INT_FLAG	(1 << 3) | ||||
| #define TWI_CTL_A_ACK	(1 << 2) | ||||
|  | ||||
| /* TWI_STAT values */ | ||||
| enum twi_status { | ||||
| 	TWI_STAT_BUS_ERROR	= 0x00,		/**< Bus error */ | ||||
| 	TWI_STAT_TX_START	= 0x08,		/**< START sent */ | ||||
| 	TWI_STAT_TX_RSTART	= 0x10,		/**< Repeated START sent */ | ||||
| 	TWI_STAT_TX_AW_ACK	= 0x18,		/**< Sent address+read, ACK */ | ||||
| 	TWI_STAT_TX_AW_NAK	= 0x20,		/**< Sent address+read, NAK */ | ||||
| 	TWI_STAT_TXD_ACK	= 0x28,		/**< Sent data, got ACK */ | ||||
| 	TWI_STAT_TXD_NAK	= 0x30,		/**< Sent data, no ACK */ | ||||
| 	TWI_STAT_LOST_ARB	= 0x38,		/**< Lost arbitration */ | ||||
| 	TWI_STAT_TX_AR_ACK	= 0x40,		/**< Sent address+write, ACK */ | ||||
| 	TWI_STAT_TX_AR_NAK	= 0x48,		/**< Sent address+write, NAK */ | ||||
| 	TWI_STAT_RXD_ACK	= 0x50,		/**< Got data, sent ACK */ | ||||
| 	TWI_STAT_RXD_NAK	= 0x58,		/**< Got data, no ACK */ | ||||
| 	TWI_STAT_IDLE		= 0xf8,		/**< Bus idle*/ | ||||
| }; | ||||
|  | ||||
| /* TWI_CLK values */ | ||||
| #define TWI_CLK_M_MASK		(0xf << 3) | ||||
| #define TWI_CLK_M(m)		(((m - 1) << 3) & TWI_CLK_M_MASK) | ||||
| #define TWI_CLK_N_MASK		(0x7 << 0) | ||||
| #define TWI_CLK_N(n)		((n) & TWI_CLK_N_MASK) | ||||
|  | ||||
| struct a1x_twi { | ||||
| 	u32 addr;	/**< 0x00: Slave address */ | ||||
| 	u32 xaddr;	/**< 0x04: Extended slave address */ | ||||
| 	u32 data;	/**< 0x08: Data byte */ | ||||
| 	u32 ctl;	/**< 0x0C: Control register */ | ||||
| 	u32 stat;	/**< 0x10: Status register */ | ||||
| 	u32 clk;	/**< 0x14: Clock control register */ | ||||
| 	u32 reset;	/**< 0x18: Software reset */ | ||||
| 	u32 efr;	/**< 0x1C: Enhanced Feature register */ | ||||
| 	u32 lcr;	/**< 0x20: Line control register */ | ||||
| }; | ||||
|  | ||||
| void a1x_twi_init(u8 bus, u32 speed_hz); | ||||
|  | ||||
| #endif				/* CPU_ALLWINNER_A10_TWI_H */ | ||||
| @@ -1,125 +0,0 @@ | ||||
| /* | ||||
|  * This file is part of the coreboot project. | ||||
|  * | ||||
|  * Copyright (C) 2013  Alexandru Gagniuc <mr.nuke.me@gmail.com> | ||||
|  * | ||||
|  * 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 (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. | ||||
|  * | ||||
|  * Uart setup helpers for Allwinner SoCs | ||||
|  * | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include "uart.h" | ||||
| #include <device/mmio.h> | ||||
| #include <console/uart.h> | ||||
| #include <drivers/uart/uart8250reg.h> | ||||
|  | ||||
| /** | ||||
|  * \brief Configure line control settings for UART | ||||
|  */ | ||||
| static void a10_uart_configure(struct a10_uart *uart, u32 baud_rate, u8 data_bits, | ||||
| 			enum uart_parity parity, u8 stop_bits) | ||||
| { | ||||
| 	u32 reg32; | ||||
| 	u16 div; | ||||
|  | ||||
| 	div = (u16) uart_baudrate_divisor(baud_rate, | ||||
| 		uart_platform_refclk(), 16); | ||||
| 	/* Enable access to Divisor Latch register */ | ||||
| 	write32(&uart->lcr, UART8250_LCR_DLAB); | ||||
| 	/* Set baudrate */ | ||||
| 	write32(&uart->dlh, (div >> 8) & 0xff); | ||||
| 	write32(&uart->dll, div & 0xff); | ||||
| 	/* Set line control */ | ||||
| 	reg32 = (data_bits - 5) & UART8250_LCR_WLS_MSK; | ||||
| 	switch (parity) { | ||||
| 	case UART_PARITY_ODD: | ||||
| 		reg32 |= UART8250_LCR_PEN; | ||||
| 		break; | ||||
| 	case UART_PARITY_EVEN: | ||||
| 		reg32 |= UART8250_LCR_PEN; | ||||
| 		reg32 |= UART8250_LCR_EPS; | ||||
| 		break; | ||||
| 	case UART_PARITY_NONE:	/* Fall through */ | ||||
| 	default: | ||||
| 		break; | ||||
| 	} | ||||
| 	write32(&uart->lcr, reg32); | ||||
| } | ||||
|  | ||||
| static void a10_uart_enable_fifos(struct a10_uart *uart) | ||||
| { | ||||
| 	write32(&uart->fcr, UART8250_FCR_FIFO_EN); | ||||
| } | ||||
|  | ||||
| static int tx_fifo_full(struct a10_uart *uart) | ||||
| { | ||||
| 	/* This may be a misnomer, or a typo in the datasheet. THRE indicates | ||||
| 	 * that the TX register is empty, not that the FIFO is not full, but | ||||
| 	 * this may be due to a datasheet typo. Keep the current name to signal | ||||
| 	 * intent. */ | ||||
| 	return !(read32(&uart->lsr) & UART8250_LSR_THRE); | ||||
| } | ||||
|  | ||||
| static int rx_fifo_empty(struct a10_uart *uart) | ||||
| { | ||||
| 	return !(read32(&uart->lsr) & UART8250_LSR_DR); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * \brief Read a single byte from the UART. | ||||
|  * | ||||
|  * Blocks until at least a byte is available. | ||||
|  */ | ||||
| static u8 a10_uart_rx_blocking(struct a10_uart *uart) | ||||
| { | ||||
| 	while (rx_fifo_empty(uart)); | ||||
|  | ||||
| 	return read32(&uart->rbr); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * \brief Write a single byte to the UART. | ||||
|  * | ||||
|  * Blocks until there is space in the FIFO. | ||||
|  */ | ||||
| static void a10_uart_tx_blocking(struct a10_uart *uart, u8 data) | ||||
| { | ||||
| 	while (tx_fifo_full(uart)); | ||||
|  | ||||
| 	return write32(&uart->thr, data); | ||||
| } | ||||
|  | ||||
|  | ||||
| void uart_init(int idx) | ||||
| { | ||||
| 	struct a10_uart *uart_base = uart_platform_baseptr(idx); | ||||
|  | ||||
| 	/* Use default 8N1 encoding */ | ||||
| 	a10_uart_configure(uart_base, get_uart_baudrate(), | ||||
| 		8, UART_PARITY_NONE, 1); | ||||
| 	a10_uart_enable_fifos(uart_base); | ||||
| } | ||||
|  | ||||
| unsigned char uart_rx_byte(int idx) | ||||
| { | ||||
| 	return a10_uart_rx_blocking(uart_platform_baseptr(idx)); | ||||
| } | ||||
|  | ||||
| void uart_tx_byte(int idx, unsigned char data) | ||||
| { | ||||
| 	a10_uart_tx_blocking(uart_platform_baseptr(idx), data); | ||||
| } | ||||
|  | ||||
| void uart_tx_flush(int idx) | ||||
| { | ||||
| } | ||||
| @@ -1,82 +0,0 @@ | ||||
| /* | ||||
|  * This file is part of the coreboot project. | ||||
|  * | ||||
|  * Copyright (C) 2013  Alexandru Gagniuc <mr.nuke.me@gmail.com> | ||||
|  * | ||||
|  * 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 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. | ||||
|  * | ||||
|  * Definitions for UART on Allwinner CPUs | ||||
|  * | ||||
|  * The UART on the A10 seems to be 8250-compatible, however, this has not been | ||||
|  * verified. Our 8250mem code is specific to x86, and does not yet work, so we | ||||
|  * have to re-implement it ARM-style for the time being. The register | ||||
|  * definitions are present in <uart7250.h>, and are not redefined here. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #ifndef CPU_ALLWINNER_A10_UART_H | ||||
| #define CPU_ALLWINNER_A10_UART_H | ||||
|  | ||||
| #include <types.h> | ||||
|  | ||||
| struct a10_uart { | ||||
| 	union { | ||||
| 		/* operational mode */ | ||||
| 		u32 rbr;	/* receiver buffer (read) */ | ||||
| 		u32 thr;	/* transmit holding (write) */ | ||||
| 		/* config mode (DLAB set) */ | ||||
| 		u32 dll;	/* divisor latches low */ | ||||
| 	}; | ||||
|  | ||||
| 	union { | ||||
| 		/* operational mode */ | ||||
| 		u32 ier;	/* interrupt enable */ | ||||
| 		/* config mode (DLAB set) */ | ||||
| 		u32 dlh;	/* divisor latches high */ | ||||
| 	}; | ||||
|  | ||||
| 	union { | ||||
| 		u32 iir;	/* interrupt ID (read) */ | ||||
| 		u32 fcr;	/* FIFO control (write) */ | ||||
| 	}; | ||||
|  | ||||
| 	u32 lcr;		/* line control */ | ||||
|  | ||||
| 	/* 0x10 */ | ||||
| 	u32 mcr;		/* modem control */ | ||||
| 	u32 lsr;		/* line status, read-only */ | ||||
| 	u32 msr;		/* modem status */ | ||||
| 	u32 sch;		/* scratch register */ | ||||
|  | ||||
| 	u8 reserved_0x20[0x50]; | ||||
|  | ||||
| 	/* 0x70 */ | ||||
| 	u8 reserved_0x70[0xc]; | ||||
| 	u32 usr;		/* UART status register */ | ||||
|  | ||||
| 	/* 0x80 */ | ||||
| 	u32 tfl;		/* Transmit FIFO level */ | ||||
| 	u32 rfl;		/* Receive FIFO level */ | ||||
| 	u8 reserved_0x88[0x18]; | ||||
|  | ||||
| 	/* 0xa0 */ | ||||
| 	u8 reserved_0xa0[4]; | ||||
| 	u32 halt;		/* Halt register */ | ||||
|  | ||||
| } __packed; | ||||
|  | ||||
| enum uart_parity { | ||||
| 	UART_PARITY_NONE, | ||||
| 	UART_PARITY_EVEN, | ||||
| 	UART_PARITY_ODD, | ||||
| }; | ||||
|  | ||||
| #endif				/* CPU_ALLWINNER_A10_UART_H */ | ||||
| @@ -1,55 +0,0 @@ | ||||
| /* | ||||
|  * This file is part of the coreboot project. | ||||
|  * | ||||
|  * Copyright 2013 Google Inc. | ||||
|  * Copyright (C) 2013  Alexandru Gagniuc <mr.nuke.me@gmail.com> | ||||
|  * | ||||
|  * 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 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. | ||||
|  * | ||||
|  * Glue to UART code to enable serial console | ||||
|  */ | ||||
|  | ||||
| #include <types.h> | ||||
| #include <console/uart.h> | ||||
| #include <boot/coreboot_tables.h> | ||||
|  | ||||
| #include "memmap.h" | ||||
|  | ||||
| uintptr_t uart_platform_base(int idx) | ||||
| { | ||||
| 	/* UART blocks are mapped 0x400 bytes apart */ | ||||
| 	if (idx < 8) | ||||
| 		return A1X_UART0_BASE + 0x400 * idx; | ||||
| 	else | ||||
| 		return 0; | ||||
| } | ||||
|  | ||||
| /* FIXME: We assume clock is 24MHz, which may not be the case. */ | ||||
| unsigned int uart_platform_refclk(void) | ||||
| { | ||||
| 	return 24000000; | ||||
| } | ||||
|  | ||||
| #ifndef __PRE_RAM__ | ||||
| void uart_fill_lb(void *data) | ||||
| { | ||||
| 	struct lb_serial serial; | ||||
| 	serial.type = LB_SERIAL_TYPE_MEMORY_MAPPED; | ||||
| 	serial.baseaddr = uart_platform_base(CONFIG_UART_FOR_CONSOLE); | ||||
| 	serial.baud = get_uart_baudrate(); | ||||
| 	serial.regwidth = 1; | ||||
| 	serial.input_hertz = uart_platform_refclk(); | ||||
| 	serial.uart_pci_addr = 0; | ||||
| 	lb_add_serial(&serial, data); | ||||
|  | ||||
| 	lb_add_console(LB_TAG_CONSOLE_SERIAL8250MEM, data); | ||||
| } | ||||
| #endif | ||||
		Reference in New Issue
	
	Block a user