From 813598e3b46601d6dd8d373e689f60f7c60fbb48 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 19 May 2015 23:34:00 +0200 Subject: sunxi: Use axp221 sid on a33 Unlike the A31 and the A23 the A33 actually has a SID inside the SoC again, but sid[3] is 0 (at least on some SoCs), so it is better to use the axp221 sid. Signed-off-by: Hans de Goede Acked-by: Ian Campbell diff --git a/arch/arm/cpu/armv7/sunxi/cpu_info.c b/arch/arm/cpu/armv7/sunxi/cpu_info.c index 30ec4ac..8e8c84f 100644 --- a/arch/arm/cpu/armv7/sunxi/cpu_info.c +++ b/arch/arm/cpu/armv7/sunxi/cpu_info.c @@ -78,18 +78,16 @@ int print_cpuinfo(void) int sunxi_get_sid(unsigned int *sid) { -#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I_A23 #ifdef CONFIG_AXP221_POWER return axp221_get_sid(sid); -#else - return -ENODEV; -#endif -#else +#elif defined SUNXI_SID_BASE int i; for (i = 0; i< 4; i++) sid[i] = readl(SUNXI_SID_BASE + 4 * i); return 0; +#else + return -ENODEV; #endif } -- cgit v0.10.2 From 93fc39a7c3ec5d4ed9f1b75cdbac641c3fe12369 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 19 May 2015 21:44:44 +0200 Subject: sunxi: Remove support for building "old-fashioned" fel binaries The latest versions of the fel tool support loading normal u-boot builds directly, and this is now the preferred way to use the fel boot method. This commit removes support for the old deprecated standalone fel builds. Signed-off-by: Hans de Goede Acked-by: Ian Campbell diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c index e6730c0..75ce7b5 100644 --- a/arch/arm/cpu/armv7/sunxi/board.c +++ b/arch/arm/cpu/armv7/sunxi/board.c @@ -120,13 +120,6 @@ void s_init(void) */ u32 spl_boot_device(void) { -#ifdef CONFIG_SPL_FEL - /* - * This is the legacy compile time configuration for a special FEL - * enabled build. It has many restrictions and can only boot over USB. - */ - return BOOT_DEVICE_BOARD; -#else /* * When booting from the SD card, the "eGON.BT0" signature is expected * to be found in memory at the address 0x0004 (see the "mksunxiboot" @@ -147,7 +140,6 @@ u32 spl_boot_device(void) return BOOT_DEVICE_MMC1; else return BOOT_DEVICE_BOARD; -#endif } /* No confirmation data available in SPL yet. Hardcode bootmode */ diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig index a6bbf6e..ca805e4 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -194,24 +194,8 @@ config SYS_BOARD config SYS_SOC default "sunxi" -config SPL_FEL - bool "SPL/FEL mode support" - depends on SPL - default n - help - This enables support for Fast Early Loader (FEL) mode. This - allows U-Boot to be loaded to the board over USB by the on-chip - boot rom. U-Boot should be sent in two parts: SPL first, with - 'fel write 0x2000 u-boot-spl.bin; fel exe 0x2000' then U-Boot with - 'fel write 0x4a000000 u-boot.bin; fel exe 0x4a000000'. This option - shrinks the amount of SRAM available to SPL, so only enable it if - you need FEL. Note that enabling this option only allows FEL to be - used; it is still possible to boot U-Boot from boot media. U-Boot - SPL detects when it is being loaded using FEL. - config UART0_PORT_F bool "UART0 on MicroSD breakout board" - depends on SPL_FEL default n ---help--- Repurpose the SD card slot for getting access to the UART0 serial diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index d829899..5dd2480 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -162,13 +162,6 @@ #define CONFIG_SPL_BOARD_LOAD_IMAGE -#ifdef CONFIG_SPL_FEL - -#define CONFIG_SPL_TEXT_BASE 0x2000 -#define CONFIG_SPL_MAX_SIZE 0x4000 /* 16 KiB */ - -#else /* CONFIG_SPL */ - #define CONFIG_SPL_BSS_START_ADDR 0x4ff80000 #define CONFIG_SPL_BSS_MAX_SIZE 0x80000 /* 512 KiB */ @@ -186,8 +179,6 @@ #define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR 80 /* 40KiB */ #define CONFIG_SPL_PAD_TO 32768 /* decimal for 'dd' */ -#endif /* CONFIG_SPL */ - /* end of 32 KiB in sram */ #define LOW_LEVEL_SRAM_STACK 0x00008000 /* End of sram */ #define CONFIG_SPL_STACK LOW_LEVEL_SRAM_STACK -- cgit v0.10.2 From e049fe282622d78fcc8f2ab9fe00cd186a542fa2 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 19 May 2015 22:12:31 +0200 Subject: sunxi: Update sunxi-common.h to deal with different DRAM base addr on sun9i The DRAM Base differs between sun9i and the others, update sunxi-common.h to deal with this. Signed-off-by: Hans de Goede Acked-by: Ian Campbell diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index 5dd2480..2b90681 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -13,6 +13,8 @@ #ifndef _SUNXI_COMMON_CONFIG_H #define _SUNXI_COMMON_CONFIG_H +#include + #ifdef CONFIG_OLD_SUNXI_KERNEL_COMPAT /* * The U-Boot workarounds bugs in the outdated buggy sunxi-3.4 kernels at the @@ -39,8 +41,6 @@ #include /* get chip and board defs */ -#define CONFIG_SYS_TEXT_BASE 0x4a000000 - #if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_DM_SERIAL) # define CONFIG_DW_SERIAL #endif @@ -69,8 +69,34 @@ /* CPU */ #define CONFIG_SYS_CACHELINE_SIZE 64 -/* DRAM Base */ +/* + * The DRAM Base differs between some models. We cannot use macros for the + * CONFIG_FOO defines which contain the DRAM base address since they end + * up unexpanded in include/autoconf.mk . + * + * So we have to have this #ifdef #else #endif block for these. + */ +#ifdef CONFIG_MACH_SUN9I +#define SDRAM_OFFSET(x) 0x2##x +#define CONFIG_SYS_SDRAM_BASE 0x20000000 +#define CONFIG_SYS_LOAD_ADDR 0x22000000 /* default load address */ +#define CONFIG_SYS_TEXT_BASE 0x2a000000 +#define CONFIG_PRE_CON_BUF_ADDR 0x2f000000 +#define CONFIG_SYS_SPL_MALLOC_START 0x2ff00000 +#define CONFIG_SPL_BSS_START_ADDR 0x2ff80000 +#else +#define SDRAM_OFFSET(x) 0x4##x #define CONFIG_SYS_SDRAM_BASE 0x40000000 +#define CONFIG_SYS_LOAD_ADDR 0x42000000 /* default load address */ +#define CONFIG_SYS_TEXT_BASE 0x4a000000 +#define CONFIG_PRE_CON_BUF_ADDR 0x4f000000 +#define CONFIG_SYS_SPL_MALLOC_START 0x4ff00000 +#define CONFIG_SPL_BSS_START_ADDR 0x4ff80000 +#endif + +#define CONFIG_SPL_BSS_MAX_SIZE 0x00080000 /* 512 KiB */ +#define CONFIG_SYS_SPL_MALLOC_SIZE 0x00080000 /* 512 KiB */ + #define CONFIG_SYS_INIT_RAM_ADDR 0x0 #define CONFIG_SYS_INIT_RAM_SIZE 0x8000 /* 32 KiB */ @@ -129,10 +155,8 @@ /* Boot Argument Buffer Size */ #define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE -#define CONFIG_SYS_LOAD_ADDR 0x42000000 /* default load address */ - /* standalone support */ -#define CONFIG_STANDALONE_LOAD_ADDR 0x42000000 +#define CONFIG_STANDALONE_LOAD_ADDR CONFIG_SYS_LOAD_ADDR /* baudrate */ #define CONFIG_BAUDRATE 115200 @@ -162,9 +186,6 @@ #define CONFIG_SPL_BOARD_LOAD_IMAGE -#define CONFIG_SPL_BSS_START_ADDR 0x4ff80000 -#define CONFIG_SPL_BSS_MAX_SIZE 0x80000 /* 512 KiB */ - #define CONFIG_SPL_TEXT_BASE 0x20 /* sram start+header */ #define CONFIG_SPL_MAX_SIZE 0x5fe0 /* 24KB on sun4i/sun7i */ @@ -182,8 +203,6 @@ /* end of 32 KiB in sram */ #define LOW_LEVEL_SRAM_STACK 0x00008000 /* End of sram */ #define CONFIG_SPL_STACK LOW_LEVEL_SRAM_STACK -#define CONFIG_SYS_SPL_MALLOC_START 0x4ff00000 -#define CONFIG_SYS_SPL_MALLOC_SIZE 0x00080000 /* 512 KiB */ /* I2C */ #if defined CONFIG_AXP152_POWER || defined CONFIG_AXP209_POWER @@ -333,8 +352,6 @@ extern int soft_i2c_gpio_scl; /* Enable pre-console buffer to get complete log on the VGA console */ #define CONFIG_PRE_CONSOLE_BUFFER #define CONFIG_PRE_CON_BUF_SZ 4096 /* Aprox 2 80*25 screens */ -/* Use the room between the end of bootm_size and the framebuffer */ -#define CONFIG_PRE_CON_BUF_ADDR 0x4f000000 /* * 240M RAM (256M minimum minus space for the framebuffer), @@ -343,11 +360,11 @@ extern int soft_i2c_gpio_scl; */ #define MEM_LAYOUT_ENV_SETTINGS \ "bootm_size=0xf000000\0" \ - "kernel_addr_r=0x42000000\0" \ - "fdt_addr_r=0x43000000\0" \ - "scriptaddr=0x43100000\0" \ - "pxefile_addr_r=0x43200000\0" \ - "ramdisk_addr_r=0x43300000\0" + "kernel_addr_r=" __stringify(SDRAM_OFFSET(2000000)) "\0" \ + "fdt_addr_r=" __stringify(SDRAM_OFFSET(3000000)) "\0" \ + "scriptaddr=" __stringify(SDRAM_OFFSET(3100000)) "\0" \ + "pxefile_addr_r=" __stringify(SDRAM_OFFSET(3200000)) "\0" \ + "ramdisk_addr_r=" __stringify(SDRAM_OFFSET(3300000)) "\0" #ifdef CONFIG_MMC #define BOOT_TARGET_DEVICES_MMC(func) func(MMC, mmc, 0) -- cgit v0.10.2 From 77fe98870bfef558ae12193ffb9d7cfe1736292b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 20 May 2015 15:27:16 +0200 Subject: sunxi: Update sunxi-common.h to deal with different A1-SRAM base addr on sun9i The A1 SRAM Base differs between sun9i and the others, update sunxi-common.h to deal with this, so that we do not set the initial stack pointer to point to the BROM. This avoids the need for the weird undocumented register write I previously took from the allwiner u-boot sources and which needed #ifdef-ery in start.S as it needed to be done really early on. Signed-off-by: Hans de Goede Acked-by: Ian Campbell diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index 2b90681..76f42f5 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -97,8 +97,20 @@ #define CONFIG_SPL_BSS_MAX_SIZE 0x00080000 /* 512 KiB */ #define CONFIG_SYS_SPL_MALLOC_SIZE 0x00080000 /* 512 KiB */ +#ifdef CONFIG_MACH_SUN9I +/* + * The A80's A1 sram starts at 0x00010000 rather then at 0x00000000 and is + * slightly bigger. Note that it is possible to map the first 32 KiB of the + * A1 at 0x00000000 like with older SoCs by writing 0x16aa0001 to the + * undocumented 0x008000e0 SYS_CTRL register. Where the 16aa is a key and + * the 1 actually activates the mapping of the first 32 KiB to 0x00000000. + */ +#define CONFIG_SYS_INIT_RAM_ADDR 0x10000 +#define CONFIG_SYS_INIT_RAM_SIZE 0x0a000 /* 40 KiB */ +#else #define CONFIG_SYS_INIT_RAM_ADDR 0x0 #define CONFIG_SYS_INIT_RAM_SIZE 0x8000 /* 32 KiB */ +#endif #define CONFIG_SYS_INIT_SP_OFFSET \ (CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE) -- cgit v0.10.2 From 1871a8ca62a9f1a3c339b04850a486cf723a4134 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 13 Jan 2015 19:25:06 +0100 Subject: sun9i: Basic sun9i (A80) support Add initial sun9i (A80) support, only uart + mmc are supported for now. Signed-off-by: Hans de Goede Acked-by: Ian Campbell diff --git a/arch/arm/cpu/armv7/sunxi/Makefile b/arch/arm/cpu/armv7/sunxi/Makefile index 6a0299f..7ef6b4c 100644 --- a/arch/arm/cpu/armv7/sunxi/Makefile +++ b/arch/arm/cpu/armv7/sunxi/Makefile @@ -13,7 +13,9 @@ obj-y += clock.o obj-y += cpu_info.o obj-y += dram_helpers.o obj-y += pinmux.o +ifndef CONFIG_MACH_SUN9I obj-y += usb_phy.o +endif obj-$(CONFIG_MACH_SUN6I) += prcm.o obj-$(CONFIG_MACH_SUN8I) += prcm.o obj-$(CONFIG_MACH_SUN9I) += prcm.o diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c index 75ce7b5..23aa249 100644 --- a/arch/arm/cpu/armv7/sunxi/board.c +++ b/arch/arm/cpu/armv7/sunxi/board.c @@ -64,6 +64,10 @@ static int gpio_init(void) sunxi_gpio_set_cfgpin(SUNXI_GPH(20), SUN6I_GPH_UART0); sunxi_gpio_set_cfgpin(SUNXI_GPH(21), SUN6I_GPH_UART0); sunxi_gpio_set_pull(SUNXI_GPH(21), SUNXI_GPIO_PULL_UP); +#elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN9I) + sunxi_gpio_set_cfgpin(SUNXI_GPH(12), SUN9I_GPH_UART0); + sunxi_gpio_set_cfgpin(SUNXI_GPH(13), SUN9I_GPH_UART0); + sunxi_gpio_set_pull(SUNXI_GPH(13), SUNXI_GPIO_PULL_UP); #elif CONFIG_CONS_INDEX == 2 && defined(CONFIG_MACH_SUN5I) sunxi_gpio_set_cfgpin(SUNXI_GPG(3), SUN5I_GPG_UART1); sunxi_gpio_set_cfgpin(SUNXI_GPG(4), SUN5I_GPG_UART1); diff --git a/arch/arm/cpu/armv7/sunxi/cpu_info.c b/arch/arm/cpu/armv7/sunxi/cpu_info.c index 8e8c84f..a276fad 100644 --- a/arch/arm/cpu/armv7/sunxi/cpu_info.c +++ b/arch/arm/cpu/armv7/sunxi/cpu_info.c @@ -11,6 +11,7 @@ #include #include #include +#include #ifdef CONFIG_MACH_SUN6I int sunxi_get_ss_bonding_id(void) @@ -68,6 +69,8 @@ int print_cpuinfo(void) puts("CPU: Allwinner A23 (SUN8I)\n"); #elif defined CONFIG_MACH_SUN8I_A33 puts("CPU: Allwinner A33 (SUN8I)\n"); +#elif defined CONFIG_MACH_SUN9I + puts("CPU: Allwinner A80 (SUN9I)\n"); #else #warning Please update cpu_info.c with correct CPU information puts("CPU: SUNXI Family\n"); diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h index 148123a..496295d 100644 --- a/arch/arm/include/asm/arch-sunxi/gpio.h +++ b/arch/arm/include/asm/arch-sunxi/gpio.h @@ -185,6 +185,7 @@ enum sunxi_gpio_number { #define SUN8I_GPH_TWI1 2 #define SUN6I_GPH_TWI2 2 #define SUN6I_GPH_UART0 2 +#define SUN9I_GPH_UART0 2 #define SUNXI_GPI_SDC3 2 #define SUN7I_GPI_TWI3 3 diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig index ca805e4..6f5fde9 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -59,6 +59,11 @@ config MACH_SUN8I_A33 select SUNXI_GEN_SUN6I select SUPPORT_SPL +config MACH_SUN9I + bool "sun9i (Allwinner A80)" + select CPU_V7 + select SUNXI_GEN_SUN6I + endchoice # The sun8i SoCs share a lot, this helps to avoid a lot of "if A23 || A33" @@ -187,6 +192,7 @@ config SYS_CONFIG_NAME default "sun6i" if MACH_SUN6I default "sun7i" if MACH_SUN7I default "sun8i" if MACH_SUN8I + default "sun9i" if MACH_SUN9I config SYS_BOARD default "sunxi" diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 5f79cc1..ed60e74 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -530,10 +530,11 @@ int misc_init_r(void) } } +#ifndef CONFIG_MACH_SUN9I ret = sunxi_usb_phy_probe(); if (ret) return ret; - +#endif #if defined(CONFIG_MUSB_HOST) || defined(CONFIG_MUSB_GADGET) musb_register(&musb_plat, NULL, (void *)SUNXI_USB0_BASE); #endif diff --git a/include/configs/sun9i.h b/include/configs/sun9i.h new file mode 100644 index 0000000..cd9e08d --- /dev/null +++ b/include/configs/sun9i.h @@ -0,0 +1,21 @@ +/* + * (C) Copyright 2015 Hans de Goede + * + * Configuration settings for the Allwinner A80 (sun9i) CPU + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +/* + * A80 specific configuration + */ + +/* + * Include common sunxi configuration where most the settings are + */ +#include + +#endif /* __CONFIG_H */ -- cgit v0.10.2 From 9d1111b70e20fc9dd4e45ada9a921da5591ee74a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 13 Jan 2015 23:24:05 +0100 Subject: sun9i: Add Merrii_A80_Optimus board / defconfig file Signed-off-by: Hans de Goede Acked-by: Ian Campbell diff --git a/board/sunxi/MAINTAINERS b/board/sunxi/MAINTAINERS index a650554..22d560a 100644 --- a/board/sunxi/MAINTAINERS +++ b/board/sunxi/MAINTAINERS @@ -40,6 +40,8 @@ F: include/configs/sun8i.h F: configs/ga10h_v1_1_defconfig F: configs/Ippo_q8h_v1_2_defconfig F: configs/Ippo_q8h_v1_2_a33_1024x600_defconfig +F: include/configs/sun9i.h +F: configs/Merrii_A80_Optimus_defconfig A20-OLINUXINO-LIME BOARD M: FUKAUMI Naoki diff --git a/configs/Merrii_A80_Optimus_defconfig b/configs/Merrii_A80_Optimus_defconfig new file mode 100644 index 0000000..6bd5273 --- /dev/null +++ b/configs/Merrii_A80_Optimus_defconfig @@ -0,0 +1,11 @@ +CONFIG_DEFAULT_DEVICE_TREE="sun9i-a80-optimus" +CONFIG_VIDEO=n +CONFIG_USB_KEYBOARD=n +CONFIG_MMC0_CD_PIN="PH18" +CONFIG_ARM=y +CONFIG_ARCH_SUNXI=y +CONFIG_MACH_SUN9I=y +# these are unused atm but we must set them to something +CONFIG_DRAM_CLK=360 +CONFIG_DRAM_ZQ=123 +CONFIG_SYS_CLK_FREQ=1008000000 -- cgit v0.10.2 From 1f6f61fe4c7c9637e2c8b2960a08f106fbe01134 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Kochma=C5=84ski?= Date: Tue, 26 May 2015 17:00:39 +0200 Subject: sunxi/nand: change BLOCK_SIZE in mksunxiboot to match NAND block size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change is necessary to calculate correct checksum for NAND boot. Works both for MMC and NAND. Without it BROM rejects boot image as invalid (bad checksum). (Changes block size from 0x200 to 0x2000). Signed-off-by: Daniel KochmaƄski Signed-off-by: Roy Spliet Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede diff --git a/tools/mksunxiboot.c b/tools/mksunxiboot.c index 0035f6e..3361251 100644 --- a/tools/mksunxiboot.c +++ b/tools/mksunxiboot.c @@ -65,7 +65,13 @@ int gen_check_sum(struct boot_file_head *head_p) #define SUN4I_SRAM_SIZE 0x7600 /* 0x7748+ is used by BROM */ #define SRAM_LOAD_MAX_SIZE (SUN4I_SRAM_SIZE - sizeof(struct boot_file_head)) -#define BLOCK_SIZE 512 + +/* + * BROM (at least on A10 and A20) requires NAND-images to be explicitly aligned + * to a multiple of 8K, and rejects the image otherwise. MMC-images are fine + * with 512B blocks. To cater for both, align to the largest of the two. + */ +#define BLOCK_SIZE 0x2000 struct boot_img { struct boot_file_head header; -- cgit v0.10.2 From a19e735d3cbf8fb50a69e911d107635be858c84f Mon Sep 17 00:00:00 2001 From: Roy Spliet Date: Tue, 26 May 2015 17:00:40 +0200 Subject: sunxi: Add DMA definitions Signed-off-by: Roy Spliet Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede diff --git a/arch/arm/include/asm/arch-sunxi/dma.h b/arch/arm/include/asm/arch-sunxi/dma.h new file mode 100644 index 0000000..e54a2ba --- /dev/null +++ b/arch/arm/include/asm/arch-sunxi/dma.h @@ -0,0 +1,16 @@ +/* + * (C) Copyright 2015 Roy Spliet + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _SUNXI_DMA_H +#define _SUNXI_DMA_H + +#if defined(CONFIG_MACH_SUN4I) || defined(CONFIG_MACH_SUN5I) || defined(CONFIG_MACH_SUN7I) +#include +#else +#error "DMA definition not available for this architecture" +#endif + +#endif /* _SUNXI_DMA_H */ diff --git a/arch/arm/include/asm/arch-sunxi/dma_sun4i.h b/arch/arm/include/asm/arch-sunxi/dma_sun4i.h new file mode 100644 index 0000000..778a04b --- /dev/null +++ b/arch/arm/include/asm/arch-sunxi/dma_sun4i.h @@ -0,0 +1,68 @@ +/* + * (C) Copyright 2015 Roy Spliet + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _SUNXI_DMA_SUN4I_H +#define _SUNXI_DMA_SUN4I_H + +struct sunxi_dma_cfg +{ + u32 ctl; /* 0x00 Control */ + u32 src_addr; /* 0x04 Source address */ + u32 dst_addr; /* 0x08 Destination address */ + u32 bc; /* 0x0C Byte counter */ + u32 res0[2]; + u32 ddma_para; /* 0x18 extra parameter (dedicated DMA only) */ + u32 res1; +}; + +struct sunxi_dma +{ + u32 irq_en; /* 0x000 IRQ enable */ + u32 irq_pend; /* 0x004 IRQ pending */ + u32 auto_gate; /* 0x008 auto gating */ + u32 res0[61]; + struct sunxi_dma_cfg ndma[8]; /* 0x100 Normal DMA */ + u32 res1[64]; + struct sunxi_dma_cfg ddma[8]; /* 0x300 Dedicated DMA */ +}; + +enum ddma_drq_type { + DDMA_DST_DRQ_SRAM = 0, + DDMA_SRC_DRQ_SRAM = 0, + DDMA_DST_DRQ_SDRAM = 1, + DDMA_SRC_DRQ_SDRAM = 1, + DDMA_DST_DRQ_PATA = 2, + DDMA_SRC_DRQ_PATA = 2, + DDMA_DST_DRQ_NAND = 3, + DDMA_SRC_DRQ_NAND = 3, + DDMA_DST_DRQ_USB0 = 4, + DDMA_SRC_DRQ_USB0 = 4, + DDMA_DST_DRQ_ETHERNET_MAC_TX = 6, + DDMA_SRC_DRQ_ETHERNET_MAC_RX = 7, + DDMA_DST_DRQ_SPI1_TX = 8, + DDMA_SRC_DRQ_SPI1_RX = 9, + DDMA_DST_DRQ_SECURITY_SYS_TX = 10, + DDMA_SRC_DRQ_SECURITY_SYS_RX = 11, + DDMA_DST_DRQ_TCON0 = 14, + DDMA_DST_DRQ_TCON1 = 15, + DDMA_DST_DRQ_MSC = 23, + DDMA_SRC_DRQ_MSC = 23, + DDMA_DST_DRQ_SPI0_TX = 26, + DDMA_SRC_DRQ_SPI0_RX = 27, + DDMA_DST_DRQ_SPI2_TX = 28, + DDMA_SRC_DRQ_SPI2_RX = 29, + DDMA_DST_DRQ_SPI3_TX = 30, + DDMA_SRC_DRQ_SPI3_RX = 31, +}; + +#define SUNXI_DMA_CTL_SRC_DRQ(a) ((a) & 0x1f) +#define SUNXI_DMA_CTL_MODE_IO (1 << 5) +#define SUNXI_DMA_CTL_SRC_DATA_WIDTH_32 (2 << 9) +#define SUNXI_DMA_CTL_DST_DRQ(a) (((a) & 0x1f) << 16) +#define SUNXI_DMA_CTL_DST_DATA_WIDTH_32 (2 << 25) +#define SUNXI_DMA_CTL_TRIGGER (1 << 31) + +#endif /* _SUNXI_DMA_SUN4I_H */ -- cgit v0.10.2 From d0f4200392515194bf67213165be906e5b9e5748 Mon Sep 17 00:00:00 2001 From: Roy Spliet Date: Tue, 26 May 2015 17:00:41 +0200 Subject: sunxi: Match sun4i, sun6i, sun9i CCI definitions for NAND and DMA Make sure definitions for NAND clock and DMA gate bits are the same across boards. Signed-off-by: Roy Spliet Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun4i.h b/arch/arm/include/asm/arch-sunxi/clock_sun4i.h index 63c3319..58aff16 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun4i.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun4i.h @@ -39,7 +39,7 @@ struct sunxi_ccm_reg { 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 nand0_clk_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 */ @@ -177,7 +177,7 @@ struct sunxi_ccm_reg { #define AHB_GATE_OFFSET_ACE 16 #define AHB_GATE_OFFSET_DLL 15 #define AHB_GATE_OFFSET_SDRAM 14 -#define AHB_GATE_OFFSET_NAND 13 +#define AHB_GATE_OFFSET_NAND0 13 #define AHB_GATE_OFFSET_MS 12 #define AHB_GATE_OFFSET_MMC3 11 #define AHB_GATE_OFFSET_MMC2 10 diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h index 6465f21..8a26b9f 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h @@ -215,11 +215,14 @@ struct sunxi_ccm_reg { #define AHB_GATE_OFFSET_USB0 24 #define AHB_GATE_OFFSET_MCTL 14 #define AHB_GATE_OFFSET_GMAC 17 +#define AHB_GATE_OFFSET_NAND0 13 +#define AHB_GATE_OFFSET_NAND1 12 #define AHB_GATE_OFFSET_MMC3 11 #define AHB_GATE_OFFSET_MMC2 10 #define AHB_GATE_OFFSET_MMC1 9 #define AHB_GATE_OFFSET_MMC0 8 #define AHB_GATE_OFFSET_MMC(n) (AHB_GATE_OFFSET_MMC0 + (n)) +#define AHB_GATE_OFFSET_DMA 6 #define AHB_GATE_OFFSET_SS 5 /* ahb_gate1 offsets */ diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun9i.h b/arch/arm/include/asm/arch-sunxi/clock_sun9i.h index c506b0a..a61934f 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun9i.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun9i.h @@ -42,7 +42,7 @@ struct sunxi_ccm_reg { u32 clk_output_b; /* 0x184 clk_output_a */ u8 reserved5[0x278]; /* 0x188 */ - u32 nand0_clk_cfg0; /* 0x400 nand0 clock configuration0 */ + u32 nand0_clk_cfg; /* 0x400 nand0 clock configuration0 */ u32 nand0_clk_cfg1; /* 0x404 nand1 clock configuration */ u8 reserved6[0x08]; /* 0x408 */ u32 sd0_clk_cfg; /* 0x410 sd0 clock configuration */ @@ -113,8 +113,12 @@ struct sunxi_ccm_reg { /* ahb_gate0 fields */ /* On sun9i all sdc-s share their ahb gate, so ignore (x) */ +#define AHB_GATE_OFFSET_NAND0 13 #define AHB_GATE_OFFSET_MMC(x) 8 +/* ahb gate1 field */ +#define AHB_GATE_OFFSET_DMA 24 + /* apb1_gate fields */ #define APB1_GATE_UART_SHIFT 16 #define APB1_GATE_UART_MASK (0xff << APB1_GATE_UART_SHIFT) -- cgit v0.10.2 From f76eba38b3eda905ff3bdc18dd1240d3dcbc6e5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Kochma=C5=84ski?= Date: Tue, 26 May 2015 17:00:42 +0200 Subject: sunxi/nand: Add support to the SPL for loading u-boot from internal NAND memory This commit adds support to the sunxi SPL to load u-boot from the internal NAND. Note this only adds support to access the boot partitions to load u-boot, full NAND support to load the kernel, etc. from the nand data partition will come later. Signed-off-by: Roy Spliet Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c index 23aa249..a82c8b9 100644 --- a/arch/arm/cpu/armv7/sunxi/board.c +++ b/arch/arm/cpu/armv7/sunxi/board.c @@ -119,11 +119,20 @@ void s_init(void) #ifdef CONFIG_SPL_BUILD /* The sunxi internal brom will try to loader external bootloader * from mmc0, nand flash, mmc2. - * Unfortunately we can't check how SPL was loaded so assume - * it's always the first SD/MMC controller + * + * Unfortunately we can't check how SPL was loaded so assume it's + * always the first SD/MMC controller, unless it was explicitly + * stated that SPL is on nand flash. */ u32 spl_boot_device(void) { +#if defined(CONFIG_SPL_NAND_SUPPORT) + /* + * This is compile time configuration informing SPL, that it + * was loaded from nand flash. + */ + return BOOT_DEVICE_NAND; +#else /* * When booting from the SD card, the "eGON.BT0" signature is expected * to be found in memory at the address 0x0004 (see the "mksunxiboot" @@ -144,6 +153,7 @@ u32 spl_boot_device(void) return BOOT_DEVICE_MMC1; else return BOOT_DEVICE_BOARD; +#endif } /* No confirmation data available in SPL yet. Hardcode bootmode */ diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h index 496295d..b628fee 100644 --- a/arch/arm/include/asm/arch-sunxi/gpio.h +++ b/arch/arm/include/asm/arch-sunxi/gpio.h @@ -157,6 +157,8 @@ enum sunxi_gpio_number { #define SUN5I_GPB_UART0 2 #define SUN8I_GPB_UART2 2 +#define SUNXI_GPC_NAND 2 + #define SUNXI_GPC_SDC2 3 #define SUN6I_GPC_SDC3 4 diff --git a/arch/arm/include/asm/arch-sunxi/nand.h b/arch/arm/include/asm/arch-sunxi/nand.h new file mode 100644 index 0000000..22844d8 --- /dev/null +++ b/arch/arm/include/asm/arch-sunxi/nand.h @@ -0,0 +1,67 @@ +/* + * (C) Copyright 2015 Roy Spliet + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _SUNXI_NAND_H +#define _SUNXI_NAND_H + +#include + +struct sunxi_nand +{ + u32 ctl; /* 0x000 Configure and control */ + u32 st; /* 0x004 Status information */ + u32 intr; /* 0x008 Interrupt control */ + u32 timing_ctl; /* 0x00C Timing control */ + u32 timing_cfg; /* 0x010 Timing configure */ + u32 addr_low; /* 0x014 Low word address */ + u32 addr_high; /* 0x018 High word address */ + u32 block_num; /* 0x01C Data block number */ + u32 data_cnt; /* 0x020 Data counter for transfer */ + u32 cmd; /* 0x024 NDFC commands */ + u32 rcmd_set; /* 0x028 Read command set for vendor NAND mem */ + u32 wcmd_set; /* 0x02C Write command set */ + u32 io_data; /* 0x030 IO data */ + u32 ecc_ctl; /* 0x034 ECC configure and control */ + u32 ecc_st; /* 0x038 ECC status and operation info */ + u32 efr; /* 0x03C Enhanced feature */ + u32 err_cnt0; /* 0x040 Corrected error bit counter 0 */ + u32 err_cnt1; /* 0x044 Corrected error bit counter 1 */ + u32 user_data[16]; /* 0x050[16] User data field */ + u32 efnand_st; /* 0x090 EFNAND status */ + u32 res0[3]; + u32 spare_area; /* 0x0A0 Spare area configure */ + u32 pat_id; /* 0x0A4 Pattern ID register */ + u32 rdata_sta_ctl; /* 0x0A8 Read data status control */ + u32 rdata_sta_0; /* 0x0AC Read data status 0 */ + u32 rdata_sta_1; /* 0x0B0 Read data status 1 */ + u32 res1[3]; + u32 mdma_addr; /* 0x0C0 MBUS DMA Address */ + u32 mdma_cnt; /* 0x0C4 MBUS DMA data counter */ +}; + +#define SUNXI_NAND_CTL_EN (1 << 0) +#define SUNXI_NAND_CTL_RST (1 << 1) +#define SUNXI_NAND_CTL_PAGE_SIZE(a) ((fls(a) - 11) << 8) +#define SUNXI_NAND_CTL_RAM_METHOD_DMA (1 << 14) + +#define SUNXI_NAND_ST_CMD_INT (1 << 1) +#define SUNXI_NAND_ST_DMA_INT (1 << 2) +#define SUNXI_NAND_ST_FIFO_FULL (1 << 3) + +#define SUNXI_NAND_CMD_ADDR_CYCLES(a) ((a - 1) << 16); +#define SUNXI_NAND_CMD_SEND_CMD1 (1 << 22) +#define SUNXI_NAND_CMD_WAIT_FLAG (1 << 23) +#define SUNXI_NAND_CMD_ORDER_INTERLEAVE 0 +#define SUNXI_NAND_CMD_ORDER_SEQ (1 << 25) + +#define SUNXI_NAND_ECC_CTL_ECC_EN (1 << 0) +#define SUNXI_NAND_ECC_CTL_PIPELINE (1 << 3) +#define SUNXI_NAND_ECC_CTL_BS_512B (1 << 5) +#define SUNXI_NAND_ECC_CTL_RND_EN (1 << 9) +#define SUNXI_NAND_ECC_CTL_MODE(a) ((a) << 12) +#define SUNXI_NAND_ECC_CTL_RND_SEED(a) ((a) << 16) + +#endif /* _SUNXI_NAND_H */ diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig index 6f5fde9..c6c876d 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -271,6 +271,18 @@ config MMC_SUNXI_SLOT_EXTRA slot or emmc on mmc1 - mmc3. Setting this to 1, 2 or 3 will enable support for this. +config SPL_NAND_SUPPORT + bool "SPL/NAND mode support" + depends on SPL + default n + ---help--- + This enables support for booting from NAND internal + memory. U-Boot SPL doesn't detect where is it load from, + therefore this option is needed to properly load image from + flash. Option also disables MMC functionality on U-Boot due to + initialization errors encountered, when both controllers are + enabled. + config USB0_VBUS_PIN string "Vbus enable pin for usb0 (otg)" default "" diff --git a/board/sunxi/board.c b/board/sunxi/board.c index ed60e74..f27967b 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -22,6 +22,9 @@ #ifdef CONFIG_AXP221_POWER #include #endif +#ifdef CONFIG_NAND_SUNXI +#include +#endif #include #include #include @@ -315,6 +318,21 @@ int board_mmc_init(bd_t *bis) } #endif +#ifdef CONFIG_NAND +void board_nand_init(void) +{ + unsigned int pin; + static u8 ports[] = CONFIG_NAND_SUNXI_GPC_PORTS; + + /* Configure AHB muxes to connect output pins with NAND controller */ + for (pin = 0; pin < 16; pin++) + sunxi_gpio_set_cfgpin(SUNXI_GPC(pin), SUNXI_GPC_NAND); + + for (pin = 0; pin < ARRAY_SIZE(ports); pin++) + sunxi_gpio_set_cfgpin(SUNXI_GPC(ports[pin]), SUNXI_GPC_NAND); +} +#endif + void i2c_init_board(void) { #ifdef CONFIG_I2C0_ENABLE diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 347ea62..a0cf4d5 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -73,5 +73,6 @@ obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_spl.o obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_spl.o obj-$(CONFIG_NAND_MXC) += mxc_nand_spl.o obj-$(CONFIG_NAND_MXS) += mxs_nand_spl.o mxs_nand.o +obj-$(CONFIG_NAND_SUNXI) += sunxi_nand_spl.o endif # drivers diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c new file mode 100644 index 0000000..75982f5 --- /dev/null +++ b/drivers/mtd/nand/sunxi_nand_spl.c @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2014, Antmicro Ltd + * Copyright (c) 2015, Turtle Solutions + * Copyright (c) 2015, Roy Spliet + * + * SPDX-License-Identifier: GPL-2.0+ + * + * \todo Detect chip parameters (page size, ECC mode, randomisation...) + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +void +nand_init(void) +{ + struct sunxi_ccm_reg * const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + struct sunxi_nand * const nand = (struct sunxi_nand *)SUNXI_NFC_BASE; + u32 val; + + board_nand_init(); + + /* "un-gate" NAND clock and clock source + * This assumes that the clock was already correctly configured by + * BootROM */ + setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_NAND0)); +#ifdef CONFIG_MACH_SUN9I + setbits_le32(&ccm->ahb_gate1, (1 << AHB_GATE_OFFSET_DMA)); +#else + setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_DMA)); +#endif + setbits_le32(&ccm->nand0_clk_cfg, 0x80000000); + + val = readl(&nand->ctl); + val |= SUNXI_NAND_CTL_RST; + writel(val, &nand->ctl); + + /* Wait until reset pin is deasserted */ + do { + val = readl(&nand->ctl); + if (!(val & SUNXI_NAND_CTL_RST)) + break; + } while (1); + + /** \todo Chip select, currently kind of static */ + val = readl(&nand->ctl); + val &= 0xf0fff0f2; + val |= SUNXI_NAND_CTL_EN; + val |= SUNXI_NAND_CTL_PAGE_SIZE(CONFIG_NAND_SUNXI_PAGE_SIZE); + writel(val, &nand->ctl); + + writel(0x100, &nand->timing_ctl); + writel(0x7ff, &nand->timing_cfg); + + /* reset CMD */ + val = SUNXI_NAND_CMD_SEND_CMD1 | SUNXI_NAND_CMD_WAIT_FLAG | + NAND_CMD_RESET; + writel(val, &nand->cmd); + do { + val = readl(&nand->st); + if (val & (1<<1)) + break; + udelay(1000); + } while (1); + + printf("Nand initialised\n"); +} + +int +nand_wait_timeout(u32 *reg, u32 mask, u32 val) +{ + unsigned long tmo = timer_get_us() + 1000000; /* 1s */ + + while ((readl(reg) & mask) != val) { + if (timer_get_us() > tmo) + return -ETIMEDOUT; + } + + return 0; +} + +/* random seed */ +static const uint16_t random_seed[128] = { + 0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72, + 0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436, + 0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d, + 0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130, + 0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56, + 0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55, + 0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb, + 0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17, + 0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62, + 0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064, + 0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126, + 0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e, + 0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3, + 0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b, + 0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d, + 0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db, +}; + +uint32_t ecc_errors = 0; + +static void +nand_config_ecc(struct sunxi_nand *nand, uint32_t page, int syndrome) +{ + static u8 strength[] = {16, 24, 28, 32, 40, 48, 56, 60, 64}; + int i; + uint32_t ecc_mode; + u32 ecc; + u16 seed = 0; + + for (i = 0; i < ARRAY_SIZE(strength); i++) { + if (CONFIG_NAND_SUNXI_ECC_STRENGTH == strength[i]) { + ecc_mode = i; + break; + } + } + + if (i == ARRAY_SIZE(strength)) { + printf("ECC strength unsupported\n"); + return; + } + + ecc = SUNXI_NAND_ECC_CTL_ECC_EN | + SUNXI_NAND_ECC_CTL_PIPELINE | + SUNXI_NAND_ECC_CTL_RND_EN | + SUNXI_NAND_ECC_CTL_MODE(ecc_mode); + + if (CONFIG_NAND_SUNXI_ECC_STEP == 512) + ecc |= SUNXI_NAND_ECC_CTL_BS_512B; + + if (syndrome) + seed = 0x4A80; + else + seed = random_seed[page % ARRAY_SIZE(random_seed)]; + + ecc |= SUNXI_NAND_ECC_CTL_RND_SEED(seed); + + writel(ecc, &nand->ecc_ctl); +} + +/* read CONFIG_NAND_SUNXI_ECC_STEP bytes from real_addr to temp_buf */ +void +nand_read_block(struct sunxi_nand *nand, phys_addr_t src, dma_addr_t dst, + int syndrome) +{ + struct sunxi_dma * const dma = (struct sunxi_dma *)SUNXI_DMA_BASE; + struct sunxi_dma_cfg * const dma_cfg = &dma->ddma[0]; + + uint32_t shift; + uint32_t page; + uint32_t addr; + uint32_t oob_offset; + uint32_t ecc_bytes; + u32 val; + u32 cmd; + + page = src / CONFIG_NAND_SUNXI_PAGE_SIZE; + if (page > 0xFFFF) { + /* TODO: currently this is not supported */ + printf("Reading from address >= %08X is not allowed.\n", + 0xFFFF * CONFIG_NAND_SUNXI_PAGE_SIZE); + return; + } + + shift = src % CONFIG_NAND_SUNXI_PAGE_SIZE; + writel(0, &nand->ecc_st); + + /* ECC_CTL, randomization */ + ecc_bytes = CONFIG_NAND_SUNXI_ECC_STRENGTH * + fls(CONFIG_NAND_SUNXI_ECC_STEP * 8); + ecc_bytes = DIV_ROUND_UP(ecc_bytes, 8); + ecc_bytes += (ecc_bytes & 1); /* Align to 2-bytes */ + ecc_bytes += 4; + + nand_config_ecc(nand, page, syndrome); + if (syndrome) { + /* shift every 1kB in syndrome */ + shift += (shift / CONFIG_NAND_SUNXI_ECC_STEP) * ecc_bytes; + oob_offset = CONFIG_NAND_SUNXI_ECC_STEP + shift; + } else { + oob_offset = CONFIG_NAND_SUNXI_PAGE_SIZE + + (shift / CONFIG_NAND_SUNXI_ECC_STEP) * ecc_bytes; + } + + addr = (page << 16) | shift; + + /* DMA */ + val = readl(&nand->ctl); + writel(val | SUNXI_NAND_CTL_RAM_METHOD_DMA, &nand->ctl); + + writel(oob_offset, &nand->spare_area); + + /* DMAC + * \todo Separate this into a tidy driver */ + writel(0x0, &dma->irq_en); /* clear dma interrupts */ + writel((uint32_t) &nand->io_data , &dma_cfg->src_addr); + writel(dst , &dma_cfg->dst_addr); + writel(0x00007F0F , &dma_cfg->ddma_para); + writel(CONFIG_NAND_SUNXI_ECC_STEP, &dma_cfg->bc); + + val = SUNXI_DMA_CTL_SRC_DRQ(DDMA_SRC_DRQ_NAND) | + SUNXI_DMA_CTL_MODE_IO | + SUNXI_DMA_CTL_SRC_DATA_WIDTH_32 | + SUNXI_DMA_CTL_DST_DRQ(DDMA_DST_DRQ_SDRAM) | + SUNXI_DMA_CTL_DST_DATA_WIDTH_32 | + SUNXI_DMA_CTL_TRIGGER; + writel(val, &dma_cfg->ctl); + + writel(0x00E00530, &nand->rcmd_set); + nand_wait_timeout(&nand->st, SUNXI_NAND_ST_FIFO_FULL, 0); + + writel(1 , &nand->block_num); + writel(addr, &nand->addr_low); + writel(0 , &nand->addr_high); + + /* CMD (PAGE READ) */ + cmd = 0x85E80000; + cmd |= SUNXI_NAND_CMD_ADDR_CYCLES(CONFIG_NAND_SUNXI_ADDR_CYCLES); + cmd |= (syndrome ? SUNXI_NAND_CMD_ORDER_SEQ : + SUNXI_NAND_CMD_ORDER_INTERLEAVE); + writel(cmd, &nand->cmd); + + if(nand_wait_timeout(&nand->st, SUNXI_NAND_ST_DMA_INT, + SUNXI_NAND_ST_DMA_INT)) { + printf("NAND timeout reading data\n"); + return; + } + + if(nand_wait_timeout(&dma_cfg->ctl, SUNXI_DMA_CTL_TRIGGER, 0)) { + printf("NAND timeout reading data\n"); + return; + } + + if (readl(&nand->ecc_st)) + ecc_errors++; +} + +int +nand_spl_load_image(uint32_t offs, unsigned int size, void *dest) +{ + struct sunxi_nand * const nand = (struct sunxi_nand *)SUNXI_NFC_BASE; + dma_addr_t dst_block; + dma_addr_t dst_end; + phys_addr_t addr = offs; + + dst_end = ((dma_addr_t) dest) + size; + + memset((void *)dest, 0x0, size); + ecc_errors = 0; + for (dst_block = (dma_addr_t) dest; dst_block < dst_end; + dst_block += CONFIG_NAND_SUNXI_ECC_STEP, + addr += CONFIG_NAND_SUNXI_ECC_STEP) { + /* syndrome read first 4MiB to match Allwinner BootROM */ + nand_read_block(nand, addr, dst_block, addr < 0x400000); + } + + if (ecc_errors) + printf("Error: %d ECC failures detected\n", ecc_errors); + return ecc_errors == 0; +} + +void +nand_deselect(void) +{} diff --git a/include/configs/sun4i.h b/include/configs/sun4i.h index ea079eb..a3c9408 100644 --- a/include/configs/sun4i.h +++ b/include/configs/sun4i.h @@ -18,6 +18,7 @@ #endif #define CONFIG_SUNXI_USB_PHYS 3 +#define CONFIG_NAND_SUNXI_GPC_PORTS {16, 17, 18, 19, 20, 21, 22, 24} /* * Include common sunxi configuration where most the settings are diff --git a/include/configs/sun5i.h b/include/configs/sun5i.h index d257659..8e13df5 100644 --- a/include/configs/sun5i.h +++ b/include/configs/sun5i.h @@ -19,6 +19,9 @@ #define CONFIG_SUNXI_USB_PHYS 2 +/* \todo A13 only defines port 19, whereas A10s requires each of these */ +#define CONFIG_NAND_SUNXI_GPC_PORTS {16, 17, 18, 19} + /* * Include common sunxi configuration where most the settings are */ diff --git a/include/configs/sun6i.h b/include/configs/sun6i.h index 2c24bd2..e1263f6 100644 --- a/include/configs/sun6i.h +++ b/include/configs/sun6i.h @@ -22,6 +22,8 @@ #define CONFIG_SUNXI_USB_PHYS 3 +#define CONFIG_NAND_SUNXI_GPC_PORTS {24, 25, 26} + /* * Include common sunxi configuration where most the settings are */ diff --git a/include/configs/sun7i.h b/include/configs/sun7i.h index 56101a9..3d26ce8 100644 --- a/include/configs/sun7i.h +++ b/include/configs/sun7i.h @@ -24,6 +24,8 @@ #define CONFIG_ARMV7_SECURE_BASE SUNXI_SRAM_B_BASE #define CONFIG_TIMER_CLK_FREQ 24000000 +#define CONFIG_NAND_SUNXI_GPC_PORTS {16, 17, 18, 19, 20, 21, 22, 24} + /* * Include common sunxi configuration where most the settings are */ diff --git a/include/configs/sun8i.h b/include/configs/sun8i.h index 7111c63..cd33758 100644 --- a/include/configs/sun8i.h +++ b/include/configs/sun8i.h @@ -20,6 +20,12 @@ #define CONFIG_SUNXI_USB_PHYS 2 +#if defined(CONFIG_MACH_SUN8I_A23) +#define CONFIG_NAND_SUNXI_GPC_PORTS {16, 17, 18} +#elif defined(CONFIG_MACH_SUN8I_A33) +#define CONFIG_NAND_SUNXI_GPC_PORTS {16} +#endif + /* * Include common sunxi configuration where most the settings are */ diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index 76f42f5..aad22f7 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -148,8 +148,10 @@ #define CONFIG_CMD_MMC #define CONFIG_MMC_SUNXI #define CONFIG_MMC_SUNXI_SLOT 0 +#if !defined(CONFIG_SPL_NAND_SUPPORT) #define CONFIG_ENV_IS_IN_MMC #define CONFIG_SYS_MMC_ENV_DEV 0 /* first detected MMC controller */ +#endif /* CONFIG_SPL_NAND_SUPPORT */ #endif /* 4MB of malloc() pool */ @@ -355,6 +357,24 @@ extern int soft_i2c_gpio_scl; #define CONFIG_ENV_IS_NOWHERE #endif +#ifdef CONFIG_SPL_NAND_SUPPORT +#define CONFIG_NAND +#define CONFIG_SYS_NAND_SELF_INIT +#define CONFIG_NAND_SUNXI +#define CONFIG_CMD_SPL_WRITE_SIZE 0x000400 +#define CONFIG_SYS_NAND_U_BOOT_OFFS 0x008000 + +/* \todo Make these parameterisable in kernel config ? */ +#define CONFIG_NAND_SUNXI_PAGE_SIZE 8192 +#define CONFIG_NAND_SUNXI_ECC_STEP 1024 +#define CONFIG_NAND_SUNXI_ECC_STRENGTH 40 +#define CONFIG_NAND_SUNXI_ADDR_CYCLES 5 + +#ifndef CONFIG_NAND_SUNXI_GPC_PORTS +#error "No NAND GPC ports defined, NAND unsupported" +#endif +#endif /* CONFIG_SPL_NAND_SUPPORT */ + #define CONFIG_MISC_INIT_R #define CONFIG_SYS_CONSOLE_IS_IN_ENV -- cgit v0.10.2 From 4ffd62451243c226709924c1459935739478231c Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 28 May 2015 21:25:29 +0800 Subject: ARM: sunxi: Document registers in PSCI code The PSCI CPU_ON code accesses quite a few registers. Document their names to make it easier to cross reference. Also explain "lock cpu" and "unlock cpu" as enabling/disabling debug access. Signed-off-by: Chen-Yu Tsai Acked-by: Hans de Goede Signed-off-by: Hans de Goede diff --git a/arch/arm/cpu/armv7/sunxi/psci.S b/arch/arm/cpu/armv7/sunxi/psci.S index 7ec0500..bbfeec8 100644 --- a/arch/arm/cpu/armv7/sunxi/psci.S +++ b/arch/arm/cpu/armv7/sunxi/psci.S @@ -165,12 +165,12 @@ psci_cpu_on: str r6, [r5] @ Reset CPU @ l1 invalidate - ldr r6, [r0, #0x184] + ldr r6, [r0, #0x184] @ CPUCFG_GEN_CTRL_REG bic r6, r6, r4 str r6, [r0, #0x184] - @ Lock CPU - ldr r6, [r0, #0x1e4] + @ Lock CPU (Disable external debug access) + ldr r6, [r0, #0x1e4] @ CPUCFG_DBG_CTL1_REG bic r6, r6, r4 str r6, [r0, #0x1e4] @@ -178,13 +178,13 @@ psci_cpu_on: movw r6, #0x1ff movt r6, #0 1: lsrs r6, r6, #1 - str r6, [r0, #0x1b0] + str r6, [r0, #0x1b0] @ CPU1_PWR_CLAMP bne 1b timer_wait r1, TEN_MS @ Clear power gating - ldr r6, [r0, #0x1b4] + ldr r6, [r0, #0x1b4] @ CPU1_PWROFF_REG bic r6, r6, #1 str r6, [r0, #0x1b4] @@ -192,8 +192,8 @@ psci_cpu_on: mov r6, #3 str r6, [r5] - @ Unlock CPU - ldr r6, [r0, #0x1e4] + @ Unlock CPU (Enable external debug access) + ldr r6, [r0, #0x1e4] @ CPUCFG_DBG_CTL1_REG orr r6, r6, r4 str r6, [r0, #0x1e4] -- cgit v0.10.2 From d4611aff4d17010d0d753a92d9e887035dc4eae5 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 28 May 2015 21:25:30 +0800 Subject: ARM: sunxi: Make PSCI code sun7i specific The PSCI code only works for sun7i. Rename it with _sun7i suffix, and build only if building for sun7i. This paves the way for adding PSCI support for other platforms. Signed-off-by: Chen-Yu Tsai Acked-by: Hans de Goede Signed-off-by: Hans de Goede diff --git a/arch/arm/cpu/armv7/sunxi/Makefile b/arch/arm/cpu/armv7/sunxi/Makefile index 7ef6b4c..85fbc85 100644 --- a/arch/arm/cpu/armv7/sunxi/Makefile +++ b/arch/arm/cpu/armv7/sunxi/Makefile @@ -35,7 +35,7 @@ obj-$(CONFIG_AXP221_POWER) += pmic_bus.o ifndef CONFIG_SPL_BUILD ifdef CONFIG_ARMV7_PSCI -obj-y += psci.o +obj-$(CONFIG_MACH_SUN7I) += psci_sun7i.o endif endif diff --git a/arch/arm/cpu/armv7/sunxi/psci.S b/arch/arm/cpu/armv7/sunxi/psci.S deleted file mode 100644 index bbfeec8..0000000 --- a/arch/arm/cpu/armv7/sunxi/psci.S +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (C) 2013 - ARM Ltd - * Author: Marc Zyngier - * - * Based on code by Carl van Schaik . - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include - -/* - * Memory layout: - * - * SECURE_RAM to text_end : - * ._secure_text section - * text_end to ALIGN_PAGE(text_end): - * nothing - * ALIGN_PAGE(text_end) to ALIGN_PAGE(text_end) + 0x1000) - * 1kB of stack per CPU (4 CPUs max). - */ - - .pushsection ._secure.text, "ax" - - .arch_extension sec - -#define ONE_MS (CONFIG_TIMER_CLK_FREQ / 1000) -#define TEN_MS (10 * ONE_MS) -#define GICD_BASE 0x1c81000 -#define GICC_BASE 0x1c82000 - -.macro timer_wait reg, ticks - @ Program CNTP_TVAL - movw \reg, #(\ticks & 0xffff) - movt \reg, #(\ticks >> 16) - mcr p15, 0, \reg, c14, c2, 0 - isb - @ Enable physical timer, mask interrupt - mov \reg, #3 - mcr p15, 0, \reg, c14, c2, 1 - @ Poll physical timer until ISTATUS is on -1: isb - mrc p15, 0, \reg, c14, c2, 1 - ands \reg, \reg, #4 - bne 1b - @ Disable timer - mov \reg, #0 - mcr p15, 0, \reg, c14, c2, 1 - isb -.endm - -.globl psci_fiq_enter -psci_fiq_enter: - push {r0-r12} - - @ Switch to secure - mrc p15, 0, r7, c1, c1, 0 - bic r8, r7, #1 - mcr p15, 0, r8, c1, c1, 0 - isb - - @ Validate reason based on IAR and acknowledge - movw r8, #(GICC_BASE & 0xffff) - movt r8, #(GICC_BASE >> 16) - ldr r9, [r8, #GICC_IAR] - movw r10, #0x3ff - movt r10, #0 - cmp r9, r10 @ skip spurious interrupt 1023 - beq out - movw r10, #0x3fe @ ...and 1022 - cmp r9, r10 - beq out - str r9, [r8, #GICC_EOIR] @ acknowledge the interrupt - dsb - - @ Compute CPU number - lsr r9, r9, #10 - and r9, r9, #0xf - - movw r8, #(SUN7I_CPUCFG_BASE & 0xffff) - movt r8, #(SUN7I_CPUCFG_BASE >> 16) - - @ Wait for the core to enter WFI - lsl r11, r9, #6 @ x64 - add r11, r11, r8 - -1: ldr r10, [r11, #0x48] - tst r10, #(1 << 2) - bne 2f - timer_wait r10, ONE_MS - b 1b - - @ Reset CPU -2: mov r10, #0 - str r10, [r11, #0x40] - - @ Lock CPU - mov r10, #1 - lsl r9, r10, r9 @ r9 is now CPU mask - ldr r10, [r8, #0x1e4] - bic r10, r10, r9 - str r10, [r8, #0x1e4] - - @ Set power gating - ldr r10, [r8, #0x1b4] - orr r10, r10, #1 - str r10, [r8, #0x1b4] - timer_wait r10, ONE_MS - - @ Activate power clamp - mov r10, #1 -1: str r10, [r8, #0x1b0] - lsl r10, r10, #1 - orr r10, r10, #1 - tst r10, #0x100 - beq 1b - - @ Restore security level -out: mcr p15, 0, r7, c1, c1, 0 - - pop {r0-r12} - subs pc, lr, #4 - - @ r1 = target CPU - @ r2 = target PC -.globl psci_cpu_on -psci_cpu_on: - push {lr} - - mov r0, r1 - bl psci_get_cpu_stack_top @ get stack top of target CPU - str r2, [r0] @ store target PC at stack top - dsb - - movw r0, #(SUN7I_CPUCFG_BASE & 0xffff) - movt r0, #(SUN7I_CPUCFG_BASE >> 16) - - @ CPU mask - and r1, r1, #3 @ only care about first cluster - mov r4, #1 - lsl r4, r4, r1 - - ldr r6, =psci_cpu_entry - str r6, [r0, #0x1a4] @ PRIVATE_REG (boot vector) - - @ Assert reset on target CPU - mov r6, #0 - lsl r5, r1, #6 @ 64 bytes per CPU - add r5, r5, #0x40 @ Offset from base - add r5, r5, r0 @ CPU control block - str r6, [r5] @ Reset CPU - - @ l1 invalidate - ldr r6, [r0, #0x184] @ CPUCFG_GEN_CTRL_REG - bic r6, r6, r4 - str r6, [r0, #0x184] - - @ Lock CPU (Disable external debug access) - ldr r6, [r0, #0x1e4] @ CPUCFG_DBG_CTL1_REG - bic r6, r6, r4 - str r6, [r0, #0x1e4] - - @ Release power clamp - movw r6, #0x1ff - movt r6, #0 -1: lsrs r6, r6, #1 - str r6, [r0, #0x1b0] @ CPU1_PWR_CLAMP - bne 1b - - timer_wait r1, TEN_MS - - @ Clear power gating - ldr r6, [r0, #0x1b4] @ CPU1_PWROFF_REG - bic r6, r6, #1 - str r6, [r0, #0x1b4] - - @ Deassert reset on target CPU - mov r6, #3 - str r6, [r5] - - @ Unlock CPU (Enable external debug access) - ldr r6, [r0, #0x1e4] @ CPUCFG_DBG_CTL1_REG - orr r6, r6, r4 - str r6, [r0, #0x1e4] - - mov r0, #ARM_PSCI_RET_SUCCESS @ Return PSCI_RET_SUCCESS - pop {pc} - -.globl psci_cpu_off -psci_cpu_off: - bl psci_cpu_off_common - - @ Ask CPU0 to pull the rug... - movw r0, #(GICD_BASE & 0xffff) - movt r0, #(GICD_BASE >> 16) - movw r1, #15 @ SGI15 - movt r1, #1 @ Target is CPU0 - str r1, [r0, #GICD_SGIR] - dsb - -1: wfi - b 1b - -.globl psci_arch_init -psci_arch_init: - mov r6, lr - - movw r4, #(GICD_BASE & 0xffff) - movt r4, #(GICD_BASE >> 16) - - ldr r5, [r4, #GICD_IGROUPRn] - bic r5, r5, #(1 << 15) @ SGI15 as Group-0 - str r5, [r4, #GICD_IGROUPRn] - - mov r5, #0 @ Set SGI15 priority to 0 - strb r5, [r4, #(GICD_IPRIORITYRn + 15)] - - add r4, r4, #0x1000 @ GICC address - - mov r5, #0xff - str r5, [r4, #GICC_PMR] @ Be cool with non-secure - - ldr r5, [r4, #GICC_CTLR] - orr r5, r5, #(1 << 3) @ Switch FIQEn on - str r5, [r4, #GICC_CTLR] - - mrc p15, 0, r5, c1, c1, 0 @ Read SCR - orr r5, r5, #4 @ Enable FIQ in monitor mode - bic r5, r5, #1 @ Secure mode - mcr p15, 0, r5, c1, c1, 0 @ Write SCR - isb - - bl psci_get_cpu_id @ CPU ID => r0 - bl psci_get_cpu_stack_top @ stack top => r0 - mov sp, r0 - - bx r6 - - .globl psci_text_end -psci_text_end: - .popsection diff --git a/arch/arm/cpu/armv7/sunxi/psci_sun7i.S b/arch/arm/cpu/armv7/sunxi/psci_sun7i.S new file mode 100644 index 0000000..bbfeec8 --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/psci_sun7i.S @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2013 - ARM Ltd + * Author: Marc Zyngier + * + * Based on code by Carl van Schaik . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +/* + * Memory layout: + * + * SECURE_RAM to text_end : + * ._secure_text section + * text_end to ALIGN_PAGE(text_end): + * nothing + * ALIGN_PAGE(text_end) to ALIGN_PAGE(text_end) + 0x1000) + * 1kB of stack per CPU (4 CPUs max). + */ + + .pushsection ._secure.text, "ax" + + .arch_extension sec + +#define ONE_MS (CONFIG_TIMER_CLK_FREQ / 1000) +#define TEN_MS (10 * ONE_MS) +#define GICD_BASE 0x1c81000 +#define GICC_BASE 0x1c82000 + +.macro timer_wait reg, ticks + @ Program CNTP_TVAL + movw \reg, #(\ticks & 0xffff) + movt \reg, #(\ticks >> 16) + mcr p15, 0, \reg, c14, c2, 0 + isb + @ Enable physical timer, mask interrupt + mov \reg, #3 + mcr p15, 0, \reg, c14, c2, 1 + @ Poll physical timer until ISTATUS is on +1: isb + mrc p15, 0, \reg, c14, c2, 1 + ands \reg, \reg, #4 + bne 1b + @ Disable timer + mov \reg, #0 + mcr p15, 0, \reg, c14, c2, 1 + isb +.endm + +.globl psci_fiq_enter +psci_fiq_enter: + push {r0-r12} + + @ Switch to secure + mrc p15, 0, r7, c1, c1, 0 + bic r8, r7, #1 + mcr p15, 0, r8, c1, c1, 0 + isb + + @ Validate reason based on IAR and acknowledge + movw r8, #(GICC_BASE & 0xffff) + movt r8, #(GICC_BASE >> 16) + ldr r9, [r8, #GICC_IAR] + movw r10, #0x3ff + movt r10, #0 + cmp r9, r10 @ skip spurious interrupt 1023 + beq out + movw r10, #0x3fe @ ...and 1022 + cmp r9, r10 + beq out + str r9, [r8, #GICC_EOIR] @ acknowledge the interrupt + dsb + + @ Compute CPU number + lsr r9, r9, #10 + and r9, r9, #0xf + + movw r8, #(SUN7I_CPUCFG_BASE & 0xffff) + movt r8, #(SUN7I_CPUCFG_BASE >> 16) + + @ Wait for the core to enter WFI + lsl r11, r9, #6 @ x64 + add r11, r11, r8 + +1: ldr r10, [r11, #0x48] + tst r10, #(1 << 2) + bne 2f + timer_wait r10, ONE_MS + b 1b + + @ Reset CPU +2: mov r10, #0 + str r10, [r11, #0x40] + + @ Lock CPU + mov r10, #1 + lsl r9, r10, r9 @ r9 is now CPU mask + ldr r10, [r8, #0x1e4] + bic r10, r10, r9 + str r10, [r8, #0x1e4] + + @ Set power gating + ldr r10, [r8, #0x1b4] + orr r10, r10, #1 + str r10, [r8, #0x1b4] + timer_wait r10, ONE_MS + + @ Activate power clamp + mov r10, #1 +1: str r10, [r8, #0x1b0] + lsl r10, r10, #1 + orr r10, r10, #1 + tst r10, #0x100 + beq 1b + + @ Restore security level +out: mcr p15, 0, r7, c1, c1, 0 + + pop {r0-r12} + subs pc, lr, #4 + + @ r1 = target CPU + @ r2 = target PC +.globl psci_cpu_on +psci_cpu_on: + push {lr} + + mov r0, r1 + bl psci_get_cpu_stack_top @ get stack top of target CPU + str r2, [r0] @ store target PC at stack top + dsb + + movw r0, #(SUN7I_CPUCFG_BASE & 0xffff) + movt r0, #(SUN7I_CPUCFG_BASE >> 16) + + @ CPU mask + and r1, r1, #3 @ only care about first cluster + mov r4, #1 + lsl r4, r4, r1 + + ldr r6, =psci_cpu_entry + str r6, [r0, #0x1a4] @ PRIVATE_REG (boot vector) + + @ Assert reset on target CPU + mov r6, #0 + lsl r5, r1, #6 @ 64 bytes per CPU + add r5, r5, #0x40 @ Offset from base + add r5, r5, r0 @ CPU control block + str r6, [r5] @ Reset CPU + + @ l1 invalidate + ldr r6, [r0, #0x184] @ CPUCFG_GEN_CTRL_REG + bic r6, r6, r4 + str r6, [r0, #0x184] + + @ Lock CPU (Disable external debug access) + ldr r6, [r0, #0x1e4] @ CPUCFG_DBG_CTL1_REG + bic r6, r6, r4 + str r6, [r0, #0x1e4] + + @ Release power clamp + movw r6, #0x1ff + movt r6, #0 +1: lsrs r6, r6, #1 + str r6, [r0, #0x1b0] @ CPU1_PWR_CLAMP + bne 1b + + timer_wait r1, TEN_MS + + @ Clear power gating + ldr r6, [r0, #0x1b4] @ CPU1_PWROFF_REG + bic r6, r6, #1 + str r6, [r0, #0x1b4] + + @ Deassert reset on target CPU + mov r6, #3 + str r6, [r5] + + @ Unlock CPU (Enable external debug access) + ldr r6, [r0, #0x1e4] @ CPUCFG_DBG_CTL1_REG + orr r6, r6, r4 + str r6, [r0, #0x1e4] + + mov r0, #ARM_PSCI_RET_SUCCESS @ Return PSCI_RET_SUCCESS + pop {pc} + +.globl psci_cpu_off +psci_cpu_off: + bl psci_cpu_off_common + + @ Ask CPU0 to pull the rug... + movw r0, #(GICD_BASE & 0xffff) + movt r0, #(GICD_BASE >> 16) + movw r1, #15 @ SGI15 + movt r1, #1 @ Target is CPU0 + str r1, [r0, #GICD_SGIR] + dsb + +1: wfi + b 1b + +.globl psci_arch_init +psci_arch_init: + mov r6, lr + + movw r4, #(GICD_BASE & 0xffff) + movt r4, #(GICD_BASE >> 16) + + ldr r5, [r4, #GICD_IGROUPRn] + bic r5, r5, #(1 << 15) @ SGI15 as Group-0 + str r5, [r4, #GICD_IGROUPRn] + + mov r5, #0 @ Set SGI15 priority to 0 + strb r5, [r4, #(GICD_IPRIORITYRn + 15)] + + add r4, r4, #0x1000 @ GICC address + + mov r5, #0xff + str r5, [r4, #GICC_PMR] @ Be cool with non-secure + + ldr r5, [r4, #GICC_CTLR] + orr r5, r5, #(1 << 3) @ Switch FIQEn on + str r5, [r4, #GICC_CTLR] + + mrc p15, 0, r5, c1, c1, 0 @ Read SCR + orr r5, r5, #4 @ Enable FIQ in monitor mode + bic r5, r5, #1 @ Secure mode + mcr p15, 0, r5, c1, c1, 0 @ Write SCR + isb + + bl psci_get_cpu_id @ CPU ID => r0 + bl psci_get_cpu_stack_top @ stack top => r0 + mov sp, r0 + + bx r6 + + .globl psci_text_end +psci_text_end: + .popsection -- cgit v0.10.2 From 073f29843847163c407878511cbf2a6cb36ed97b Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 28 May 2015 21:25:31 +0800 Subject: ARM: sunxi: Add sun6i specific PSCI implementation This adds PSCI support for sun6i. So far it only supports the PWR_ON method. Signed-off-by: Chen-Yu Tsai Acked-by: Hans de Goede Signed-off-by: Hans de Goede diff --git a/arch/arm/cpu/armv7/sunxi/Makefile b/arch/arm/cpu/armv7/sunxi/Makefile index 85fbc85..4b783e0 100644 --- a/arch/arm/cpu/armv7/sunxi/Makefile +++ b/arch/arm/cpu/armv7/sunxi/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_AXP221_POWER) += pmic_bus.o ifndef CONFIG_SPL_BUILD ifdef CONFIG_ARMV7_PSCI +obj-$(CONFIG_MACH_SUN6I) += psci_sun6i.o obj-$(CONFIG_MACH_SUN7I) += psci_sun7i.o endif endif diff --git a/arch/arm/cpu/armv7/sunxi/psci_sun6i.S b/arch/arm/cpu/armv7/sunxi/psci_sun6i.S new file mode 100644 index 0000000..2516804 --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/psci_sun6i.S @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2015 - Chen-Yu Tsai + * Author: Chen-Yu Tsai + * + * Based on psci_sun7i.S by Marc Zyngier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +/* + * Memory layout: + * + * SECURE_RAM to text_end : + * ._secure_text section + * text_end to ALIGN_PAGE(text_end): + * nothing + * ALIGN_PAGE(text_end) to ALIGN_PAGE(text_end) + 0x1000) + * 1kB of stack per CPU (4 CPUs max). + */ + + .pushsection ._secure.text, "ax" + + .arch_extension sec + +#define ONE_MS (CONFIG_TIMER_CLK_FREQ / 1000) +#define TEN_MS (10 * ONE_MS) +#define GICD_BASE 0x1c81000 +#define GICC_BASE 0x1c82000 + +.macro timer_wait reg, ticks + @ Program CNTP_TVAL + movw \reg, #(\ticks & 0xffff) + movt \reg, #(\ticks >> 16) + mcr p15, 0, \reg, c14, c2, 0 + isb + @ Enable physical timer, mask interrupt + mov \reg, #3 + mcr p15, 0, \reg, c14, c2, 1 + @ Poll physical timer until ISTATUS is on +1: isb + mrc p15, 0, \reg, c14, c2, 1 + ands \reg, \reg, #4 + bne 1b + @ Disable timer + mov \reg, #0 + mcr p15, 0, \reg, c14, c2, 1 + isb +.endm + +.globl psci_fiq_enter +psci_fiq_enter: + push {r0-r12} + + @ Switch to secure + mrc p15, 0, r7, c1, c1, 0 + bic r8, r7, #1 + mcr p15, 0, r8, c1, c1, 0 + isb + + @ Validate reason based on IAR and acknowledge + movw r8, #(GICC_BASE & 0xffff) + movt r8, #(GICC_BASE >> 16) + ldr r9, [r8, #GICC_IAR] + movw r10, #0x3ff + movt r10, #0 + cmp r9, r10 @ skip spurious interrupt 1023 + beq out + movw r10, #0x3fe @ ...and 1022 + cmp r9, r10 + beq out + str r9, [r8, #GICC_EOIR] @ acknowledge the interrupt + dsb + + @ Compute CPU number + lsr r9, r9, #10 + and r9, r9, #0xf + + movw r8, #(SUN6I_CPUCFG_BASE & 0xffff) + movt r8, #(SUN6I_CPUCFG_BASE >> 16) + + @ Wait for the core to enter WFI + lsl r11, r9, #6 @ x64 + add r11, r11, r8 + +1: ldr r10, [r11, #0x48] + tst r10, #(1 << 2) + bne 2f + timer_wait r10, ONE_MS + b 1b + + @ Reset CPU +2: mov r10, #0 + str r10, [r11, #0x40] + + @ Lock CPU + mov r10, #1 + lsl r11, r10, r9 @ r11 is now CPU mask + ldr r10, [r8, #0x1e4] + bic r10, r10, r11 + str r10, [r8, #0x1e4] + + movw r8, #(SUNXI_PRCM_BASE & 0xffff) + movt r8, #(SUNXI_PRCM_BASE >> 16) + + @ Set power gating + ldr r10, [r8, #0x100] + orr r10, r10, r11 + str r10, [r8, #0x100] + timer_wait r10, ONE_MS + + @ Activate power clamp + lsl r12, r9, #2 @ x4 + add r12, r12, r8 + mov r10, #0xff + str r10, [r12, #0x140] + + movw r8, #(SUN6I_CPUCFG_BASE & 0xffff) + movt r8, #(SUN6I_CPUCFG_BASE >> 16) + + @ Unlock CPU + ldr r10, [r8, #0x1e4] + orr r10, r10, r11 + str r10, [r8, #0x1e4] + + @ Restore security level +out: mcr p15, 0, r7, c1, c1, 0 + + pop {r0-r12} + subs pc, lr, #4 + + @ r1 = target CPU + @ r2 = target PC +.globl psci_cpu_on +psci_cpu_on: + push {lr} + + mov r0, r1 + bl psci_get_cpu_stack_top @ get stack top of target CPU + str r2, [r0] @ store target PC at stack top + dsb + + movw r0, #(SUN6I_CPUCFG_BASE & 0xffff) + movt r0, #(SUN6I_CPUCFG_BASE >> 16) + + @ CPU mask + and r1, r1, #3 @ only care about first cluster + mov r4, #1 + lsl r4, r4, r1 + + ldr r6, =psci_cpu_entry + str r6, [r0, #0x1a4] @ PRIVATE_REG (boot vector) + + @ Assert reset on target CPU + mov r6, #0 + lsl r5, r1, #6 @ 64 bytes per CPU + add r5, r5, #0x40 @ Offset from base + add r5, r5, r0 @ CPU control block + str r6, [r5] @ Reset CPU + + @ l1 invalidate + ldr r6, [r0, #0x184] @ CPUCFG_GEN_CTRL_REG + bic r6, r6, r4 + str r6, [r0, #0x184] + + @ Lock CPU (Disable external debug access) + ldr r6, [r0, #0x1e4] @ CPUCFG_DBG_CTL1_REG + bic r6, r6, r4 + str r6, [r0, #0x1e4] + + movw r0, #(SUNXI_PRCM_BASE & 0xffff) + movt r0, #(SUNXI_PRCM_BASE >> 16) + + @ Release power clamp + lsl r5, r1, #2 @ 1 register per CPU + add r5, r5, r0 @ PRCM + movw r6, #0x1ff + movt r6, #0 +1: lsrs r6, r6, #1 + str r6, [r5, #0x140] @ CPUx_PWR_CLAMP + bne 1b + + timer_wait r6, TEN_MS + + @ Clear power gating + ldr r6, [r0, #0x100] @ CPU_PWROFF_GATING + bic r6, r6, r4 + str r6, [r0, #0x100] + + @ re-calculate CPU control register address + movw r0, #(SUN6I_CPUCFG_BASE & 0xffff) + movt r0, #(SUN6I_CPUCFG_BASE >> 16) + + @ Deassert reset on target CPU + mov r6, #3 + lsl r5, r1, #6 @ 64 bytes per CPU + add r5, r5, #0x40 @ Offset from base + add r5, r5, r0 @ CPU control block + str r6, [r5] + + @ Unlock CPU (Enable external debug access) + ldr r6, [r0, #0x1e4] @ CPUCFG_DBG_CTL1_REG + orr r6, r6, r4 + str r6, [r0, #0x1e4] + + mov r0, #ARM_PSCI_RET_SUCCESS @ Return PSCI_RET_SUCCESS + pop {pc} + +.globl psci_cpu_off +psci_cpu_off: + bl psci_cpu_off_common + + @ Ask CPU0 to pull the rug... + movw r0, #(GICD_BASE & 0xffff) + movt r0, #(GICD_BASE >> 16) + movw r1, #15 @ SGI15 + movt r1, #1 @ Target is CPU0 + str r1, [r0, #GICD_SGIR] + dsb + +1: wfi + b 1b + +.globl psci_arch_init +psci_arch_init: + mov r6, lr + + movw r4, #(GICD_BASE & 0xffff) + movt r4, #(GICD_BASE >> 16) + + ldr r5, [r4, #GICD_IGROUPRn] + bic r5, r5, #(1 << 15) @ SGI15 as Group-0 + str r5, [r4, #GICD_IGROUPRn] + + mov r5, #0 @ Set SGI15 priority to 0 + strb r5, [r4, #(GICD_IPRIORITYRn + 15)] + + add r4, r4, #0x1000 @ GICC address + + mov r5, #0xff + str r5, [r4, #GICC_PMR] @ Be cool with non-secure + + ldr r5, [r4, #GICC_CTLR] + orr r5, r5, #(1 << 3) @ Switch FIQEn on + str r5, [r4, #GICC_CTLR] + + mrc p15, 0, r5, c1, c1, 0 @ Read SCR + orr r5, r5, #4 @ Enable FIQ in monitor mode + bic r5, r5, #1 @ Secure mode + mcr p15, 0, r5, c1, c1, 0 @ Write SCR + isb + + bl psci_get_cpu_id @ CPU ID => r0 + bl psci_get_cpu_stack_top @ stack top => r0 + mov sp, r0 + + bx r6 + + .globl psci_text_end +psci_text_end: + .popsection -- cgit v0.10.2 From cc08ea4cff827f0929744d8d0134422e01c1f2b5 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 28 May 2015 21:25:32 +0800 Subject: ARM: sunxi: Enable PSCI for sun6i Now that we have a PSCI backend for sun6i, enable it. Signed-off-by: Chen-Yu Tsai Acked-by: Hans de Goede Signed-off-by: Hans de Goede diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig index c6c876d..64d2af8 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -35,8 +35,11 @@ config MACH_SUN5I config MACH_SUN6I bool "sun6i (Allwinner A31)" select CPU_V7 + select CPU_V7_HAS_NONSEC + select CPU_V7_HAS_VIRT select SUNXI_GEN_SUN6I select SUPPORT_SPL + select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT config MACH_SUN7I bool "sun7i (Allwinner A20)" diff --git a/include/configs/sun6i.h b/include/configs/sun6i.h index e1263f6..a0ebc7e 100644 --- a/include/configs/sun6i.h +++ b/include/configs/sun6i.h @@ -22,6 +22,11 @@ #define CONFIG_SUNXI_USB_PHYS 3 +#define CONFIG_ARMV7_PSCI 1 +#define CONFIG_ARMV7_PSCI_NR_CPUS 4 +#define CONFIG_ARMV7_SECURE_BASE SUNXI_SRAM_B_BASE +#define CONFIG_TIMER_CLK_FREQ 24000000 + #define CONFIG_NAND_SUNXI_GPC_PORTS {24, 25, 26} /* -- cgit v0.10.2 From 98167430317a6275e582def8cb4aee76799789af Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 28 May 2015 21:25:33 +0800 Subject: ARM: sunxi: Share sun6i PSCI backend with sun8i sun8i can share the PSCI backend with sun6i. Only difference is sun8i does not have CPU power clamp controls. Signed-off-by: Chen-Yu Tsai Acked-by: Hans de Goede Signed-off-by: Hans de Goede diff --git a/arch/arm/cpu/armv7/sunxi/Makefile b/arch/arm/cpu/armv7/sunxi/Makefile index 4b783e0..76c7e55 100644 --- a/arch/arm/cpu/armv7/sunxi/Makefile +++ b/arch/arm/cpu/armv7/sunxi/Makefile @@ -37,6 +37,7 @@ ifndef CONFIG_SPL_BUILD ifdef CONFIG_ARMV7_PSCI obj-$(CONFIG_MACH_SUN6I) += psci_sun6i.o obj-$(CONFIG_MACH_SUN7I) += psci_sun7i.o +obj-$(CONFIG_MACH_SUN8I) += psci_sun6i.o endif endif diff --git a/arch/arm/cpu/armv7/sunxi/psci_sun6i.S b/arch/arm/cpu/armv7/sunxi/psci_sun6i.S index 2516804..d4cb51e 100644 --- a/arch/arm/cpu/armv7/sunxi/psci_sun6i.S +++ b/arch/arm/cpu/armv7/sunxi/psci_sun6i.S @@ -124,11 +124,13 @@ psci_fiq_enter: str r10, [r8, #0x100] timer_wait r10, ONE_MS +#ifdef CONFIG_MACH_SUN6I @ Activate power clamp lsl r12, r9, #2 @ x4 add r12, r12, r8 mov r10, #0xff str r10, [r12, #0x140] +#endif movw r8, #(SUN6I_CPUCFG_BASE & 0xffff) movt r8, #(SUN6I_CPUCFG_BASE >> 16) @@ -186,6 +188,7 @@ psci_cpu_on: movw r0, #(SUNXI_PRCM_BASE & 0xffff) movt r0, #(SUNXI_PRCM_BASE >> 16) +#ifdef CONFIG_MACH_SUN6I @ Release power clamp lsl r5, r1, #2 @ 1 register per CPU add r5, r5, r0 @ PRCM @@ -194,6 +197,7 @@ psci_cpu_on: 1: lsrs r6, r6, #1 str r6, [r5, #0x140] @ CPUx_PWR_CLAMP bne 1b +#endif timer_wait r6, TEN_MS -- cgit v0.10.2 From 014414f53695ab3ba5a9d344ad1ba8952bce157c Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 28 May 2015 21:25:34 +0800 Subject: ARM: sunxi: Enable PSCI for sun8i sun8i uses the same PSCI backend as sun6i, without power clamps. Since there is no secure SRAM, the backend is placed at the end of DRAM. Signed-off-by: Chen-Yu Tsai Acked-by: Hans de Goede Signed-off-by: Hans de Goede diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig index 64d2af8..8e27396 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -53,14 +53,20 @@ config MACH_SUN7I config MACH_SUN8I_A23 bool "sun8i (Allwinner A23)" select CPU_V7 + select CPU_V7_HAS_NONSEC + select CPU_V7_HAS_VIRT select SUNXI_GEN_SUN6I select SUPPORT_SPL + select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT config MACH_SUN8I_A33 bool "sun8i (Allwinner A33)" select CPU_V7 + select CPU_V7_HAS_NONSEC + select CPU_V7_HAS_VIRT select SUNXI_GEN_SUN6I select SUPPORT_SPL + select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT config MACH_SUN9I bool "sun9i (Allwinner A80)" diff --git a/include/configs/sun8i.h b/include/configs/sun8i.h index cd33758..fe8c511 100644 --- a/include/configs/sun8i.h +++ b/include/configs/sun8i.h @@ -20,11 +20,17 @@ #define CONFIG_SUNXI_USB_PHYS 2 +#define CONFIG_ARMV7_PSCI 1 #if defined(CONFIG_MACH_SUN8I_A23) +#define CONFIG_ARMV7_PSCI_NR_CPUS 2 #define CONFIG_NAND_SUNXI_GPC_PORTS {16, 17, 18} #elif defined(CONFIG_MACH_SUN8I_A33) +#define CONFIG_ARMV7_PSCI_NR_CPUS 4 #define CONFIG_NAND_SUNXI_GPC_PORTS {16} +#else +#error Unsupported sun8i variant #endif +#define CONFIG_TIMER_CLK_FREQ 24000000 /* * Include common sunxi configuration where most the settings are -- cgit v0.10.2