Merge git://git.denx.de/u-boot-x86
This commit is contained in:
		
						commit
						ae1b939930
					
				|  | @ -85,6 +85,7 @@ config X86 | |||
| 	select DM_SPI | ||||
| 	select DM_SPI_FLASH | ||||
| 	select USB_EHCI_HCD | ||||
| 	select DM_MMC if MMC | ||||
| 
 | ||||
| config XTENSA | ||||
| 	bool "Xtensa architecture" | ||||
|  |  | |||
|  | @ -589,6 +589,38 @@ config GENERATE_ACPI_TABLE | |||
| 
 | ||||
| endmenu | ||||
| 
 | ||||
| config HAVE_ACPI_RESUME | ||||
| 	bool "Enable ACPI S3 resume" | ||||
| 	help | ||||
| 	  Select this to enable ACPI S3 resume. S3 is an ACPI-defined sleeping | ||||
| 	  state where all system context is lost except system memory. U-Boot | ||||
| 	  is responsible for restoring the machine state as it was before sleep. | ||||
| 	  It needs restore the memory controller, without overwriting memory | ||||
| 	  which is not marked as reserved. For the peripherals which lose their | ||||
| 	  registers, U-Boot needs to write the original value. When everything | ||||
| 	  is done, U-Boot needs to find out the wakeup vector provided by OSes | ||||
| 	  and jump there. | ||||
| 
 | ||||
| config S3_VGA_ROM_RUN | ||||
| 	bool "Re-run VGA option ROMs on S3 resume" | ||||
| 	depends on HAVE_ACPI_RESUME | ||||
| 	default y if HAVE_ACPI_RESUME | ||||
| 	help | ||||
| 	  Execute VGA option ROMs in U-Boot when resuming from S3. Normally | ||||
| 	  this is needed when graphics console is being used in the kernel. | ||||
| 
 | ||||
| 	  Turning it off can reduce some resume time, but be aware that your | ||||
| 	  graphics console won't work without VGA options ROMs. Set it to N | ||||
| 	  if your kernel is only on a serial console. | ||||
| 
 | ||||
| config STACK_SIZE | ||||
| 	hex | ||||
| 	depends on HAVE_ACPI_RESUME | ||||
| 	default 0x1000 | ||||
| 	help | ||||
| 	  Estimated U-Boot's runtime stack size that needs to be reserved | ||||
| 	  during an ACPI S3 resume. | ||||
| 
 | ||||
| config MAX_PIRQ_LINKS | ||||
| 	int | ||||
| 	default 8 | ||||
|  |  | |||
|  | @ -45,6 +45,7 @@ ifndef CONFIG_$(SPL_)X86_64 | |||
| obj-$(CONFIG_SMP) += sipi_vector.o | ||||
| endif | ||||
| obj-y += turbo.o | ||||
| obj-$(CONFIG_HAVE_ACPI_RESUME) += wakeup.o | ||||
| 
 | ||||
| ifeq ($(CONFIG_$(SPL_)X86_64),y) | ||||
| obj-y += x86_64/ | ||||
|  |  | |||
|  | @ -8,7 +8,9 @@ | |||
| #include <cpu.h> | ||||
| #include <dm.h> | ||||
| #include <dm/uclass-internal.h> | ||||
| #include <asm/acpi_s3.h> | ||||
| #include <asm/acpi_table.h> | ||||
| #include <asm/io.h> | ||||
| #include <asm/ioapic.h> | ||||
| #include <asm/mpspec.h> | ||||
| #include <asm/tables.h> | ||||
|  | @ -187,3 +189,48 @@ void acpi_create_gnvs(struct acpi_global_nvs *gnvs) | |||
| 	else | ||||
| 		gnvs->iuart_en = 0; | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_HAVE_ACPI_RESUME | ||||
| /*
 | ||||
|  * The following two routines are called at a very early stage, even before | ||||
|  * FSP 2nd phase API fsp_init() is called. Registers off ACPI_BASE_ADDRESS | ||||
|  * and PMC_BASE_ADDRESS are accessed, so we need make sure the base addresses | ||||
|  * of these two blocks are programmed by either U-Boot or FSP. | ||||
|  * | ||||
|  * It has been verified that 1st phase API (see arch/x86/lib/fsp/fsp_car.S) | ||||
|  * on Intel BayTrail SoC already initializes these two base addresses so | ||||
|  * we are safe to access these registers here. | ||||
|  */ | ||||
| 
 | ||||
| enum acpi_sleep_state chipset_prev_sleep_state(void) | ||||
| { | ||||
| 	u32 pm1_sts; | ||||
| 	u32 pm1_cnt; | ||||
| 	u32 gen_pmcon1; | ||||
| 	enum acpi_sleep_state prev_sleep_state = ACPI_S0; | ||||
| 
 | ||||
| 	/* Read Power State */ | ||||
| 	pm1_sts = inw(ACPI_BASE_ADDRESS + PM1_STS); | ||||
| 	pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT); | ||||
| 	gen_pmcon1 = readl(PMC_BASE_ADDRESS + GEN_PMCON1); | ||||
| 
 | ||||
| 	debug("PM1_STS = 0x%x PM1_CNT = 0x%x GEN_PMCON1 = 0x%x\n", | ||||
| 	      pm1_sts, pm1_cnt, gen_pmcon1); | ||||
| 
 | ||||
| 	if (pm1_sts & WAK_STS) | ||||
| 		prev_sleep_state = acpi_sleep_from_pm1(pm1_cnt); | ||||
| 
 | ||||
| 	if (gen_pmcon1 & (PWR_FLR | SUS_PWR_FLR)) | ||||
| 		prev_sleep_state = ACPI_S5; | ||||
| 
 | ||||
| 	return prev_sleep_state; | ||||
| } | ||||
| 
 | ||||
| void chipset_clear_sleep_state(void) | ||||
| { | ||||
| 	u32 pm1_cnt; | ||||
| 
 | ||||
| 	pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT); | ||||
| 	outl(pm1_cnt & ~(SLP_TYP), ACPI_BASE_ADDRESS + PM1_CNT); | ||||
| } | ||||
| #endif | ||||
|  |  | |||
|  | @ -11,18 +11,6 @@ | |||
| #include <asm/mrccache.h> | ||||
| #include <asm/post.h> | ||||
| 
 | ||||
| static struct pci_device_id mmc_supported[] = { | ||||
| 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_SDIO }, | ||||
| 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_SD }, | ||||
| 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_EMMC2 }, | ||||
| 	{}, | ||||
| }; | ||||
| 
 | ||||
| int cpu_mmc_init(bd_t *bis) | ||||
| { | ||||
| 	return pci_mmc_init("ValleyView SDHCI", mmc_supported); | ||||
| } | ||||
| 
 | ||||
| #ifndef CONFIG_EFI_APP | ||||
| int arch_cpu_init(void) | ||||
| { | ||||
|  |  | |||
|  | @ -25,6 +25,8 @@ | |||
| #include <errno.h> | ||||
| #include <malloc.h> | ||||
| #include <syscon.h> | ||||
| #include <asm/acpi_s3.h> | ||||
| #include <asm/acpi_table.h> | ||||
| #include <asm/control_regs.h> | ||||
| #include <asm/coreboot_tables.h> | ||||
| #include <asm/cpu.h> | ||||
|  | @ -179,6 +181,11 @@ int default_print_cpuinfo(void) | |||
| 	       cpu_has_64bit() ? "x86_64" : "x86", | ||||
| 	       cpu_vendor_name(gd->arch.x86_vendor), gd->arch.x86_device); | ||||
| 
 | ||||
| #ifdef CONFIG_HAVE_ACPI_RESUME | ||||
| 	debug("ACPI previous sleep state: %s\n", | ||||
| 	      acpi_ss_string(gd->arch.prev_sleep_state)); | ||||
| #endif | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  | @ -198,10 +205,17 @@ __weak void board_final_cleanup(void) | |||
| 
 | ||||
| int last_stage_init(void) | ||||
| { | ||||
| 	write_tables(); | ||||
| 
 | ||||
| 	board_final_cleanup(); | ||||
| 
 | ||||
| #if CONFIG_HAVE_ACPI_RESUME | ||||
| 	struct acpi_fadt *fadt = acpi_find_fadt(); | ||||
| 
 | ||||
| 	if (fadt != NULL && gd->arch.prev_sleep_state == ACPI_S3) | ||||
| 		acpi_resume(fadt); | ||||
| #endif | ||||
| 
 | ||||
| 	write_tables(); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
|  | @ -264,6 +278,18 @@ int reserve_arch(void) | |||
| 	high_table_reserve(); | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_HAVE_ACPI_RESUME | ||||
| 	acpi_s3_reserve(); | ||||
| 
 | ||||
| #ifdef CONFIG_HAVE_FSP | ||||
| 	/*
 | ||||
| 	 * Save stack address to CMOS so that at next S3 boot, | ||||
| 	 * we can use it as the stack address for fsp_contiue() | ||||
| 	 */ | ||||
| 	fsp_save_s3_stack(); | ||||
| #endif /* CONFIG_HAVE_FSP */ | ||||
| #endif /* CONFIG_HAVE_ACPI_RESUME */ | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
|  |  | |||
|  | @ -16,11 +16,6 @@ | |||
| #include <asm/arch/msg_port.h> | ||||
| #include <asm/arch/quark.h> | ||||
| 
 | ||||
| static struct pci_device_id mmc_supported[] = { | ||||
| 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QRK_SDIO }, | ||||
| 	{}, | ||||
| }; | ||||
| 
 | ||||
| static void quark_setup_mtrr(void) | ||||
| { | ||||
| 	u32 base, mask; | ||||
|  | @ -328,11 +323,6 @@ int arch_early_init_r(void) | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int cpu_mmc_init(bd_t *bis) | ||||
| { | ||||
| 	return pci_mmc_init("Quark SDHCI", mmc_supported); | ||||
| } | ||||
| 
 | ||||
| int arch_misc_init(void) | ||||
| { | ||||
| #ifdef CONFIG_ENABLE_MRC_CACHE | ||||
|  |  | |||
|  | @ -5,4 +5,4 @@ | |||
| #
 | ||||
| 
 | ||||
| obj-y += fsp_configs.o irq.o | ||||
| obj-y += tnc.o topcliff.o | ||||
| obj-y += tnc.o | ||||
|  |  | |||
|  | @ -1,20 +0,0 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com> | ||||
|  * | ||||
|  * SPDX-License-Identifier:	GPL-2.0+ | ||||
|  */ | ||||
| 
 | ||||
| #include <common.h> | ||||
| #include <mmc.h> | ||||
| #include <pci_ids.h> | ||||
| 
 | ||||
| static struct pci_device_id mmc_supported[] = { | ||||
| 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TCF_SDIO_0 }, | ||||
| 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TCF_SDIO_1 }, | ||||
| 	{}, | ||||
| }; | ||||
| 
 | ||||
| int cpu_mmc_init(bd_t *bis) | ||||
| { | ||||
| 	return pci_mmc_init("Topcliff SDHCI", mmc_supported); | ||||
| } | ||||
|  | @ -0,0 +1,78 @@ | |||
| /* | ||||
|  * Copyright (C) 2017, Bin Meng <bmeng.cn@gmail.com>
 | ||||
|  * | ||||
|  * From coreboot src/arch/x86/wakeup.S | ||||
|  * | ||||
|  * SPDX-License-Identifier:	GPL-2.0+ | ||||
|  */ | ||||
| 
 | ||||
| #include <asm/acpi_s3.h> | ||||
| #include <asm/processor.h> | ||||
| #include <asm/processor-flags.h> | ||||
| 
 | ||||
| #define RELOCATED(x)	((x) - __wakeup + WAKEUP_BASE) | ||||
| 
 | ||||
| #define CODE_SEG	(X86_GDT_ENTRY_16BIT_CS * X86_GDT_ENTRY_SIZE) | ||||
| #define DATA_SEG	(X86_GDT_ENTRY_16BIT_DS * X86_GDT_ENTRY_SIZE) | ||||
| 
 | ||||
| 	.code32 | ||||
| 	.globl __wakeup
 | ||||
| __wakeup: | ||||
| 	/* First prepare the jmp to the resume vector */ | ||||
| 	mov	0x4(%esp), %eax	/* vector */ | ||||
| 	/* last 4 bits of linear addr are taken as offset */ | ||||
| 	andw	$0x0f, %ax | ||||
| 	movw	%ax, (__wakeup_offset) | ||||
| 	mov	0x4(%esp), %eax | ||||
| 	/* the rest is taken as segment */ | ||||
| 	shr	$4, %eax | ||||
| 	movw	%ax, (__wakeup_segment) | ||||
| 
 | ||||
| 	/* Activate the right segment descriptor real mode */ | ||||
| 	ljmp	$CODE_SEG, $RELOCATED(1f) | ||||
| 1: | ||||
| 	/* 16 bit code from here on... */ | ||||
| 	.code16 | ||||
| 
 | ||||
| 	/* | ||||
| 	 * Load the segment registers w/ properly configured segment | ||||
| 	 * descriptors. They will retain these configurations (limits, | ||||
| 	 * writability, etc.) once protected mode is turned off. | ||||
| 	 */ | ||||
| 	mov	$DATA_SEG, %ax | ||||
| 	mov	%ax, %ds | ||||
| 	mov	%ax, %es | ||||
| 	mov	%ax, %fs | ||||
| 	mov	%ax, %gs | ||||
| 	mov	%ax, %ss | ||||
| 
 | ||||
| 	/* Turn off protection */ | ||||
| 	movl	%cr0, %eax | ||||
| 	andl	$~X86_CR0_PE, %eax | ||||
| 	movl	%eax, %cr0 | ||||
| 
 | ||||
| 	/* Now really going into real mode */ | ||||
| 	ljmp	$0, $RELOCATED(1f) | ||||
| 1: | ||||
| 	movw	$0x0, %ax | ||||
| 	movw	%ax, %ds | ||||
| 	movw	%ax, %es | ||||
| 	movw	%ax, %ss | ||||
| 	movw	%ax, %fs | ||||
| 	movw	%ax, %gs | ||||
| 
 | ||||
| 	/* | ||||
| 	 * This is a FAR JMP to the OS waking vector. | ||||
| 	 * The C code changes the address to be correct. | ||||
| 	 */ | ||||
| 	.byte 0xea
 | ||||
| 
 | ||||
| __wakeup_offset = RELOCATED(.) | ||||
| 	.word 0x0000
 | ||||
| 
 | ||||
| __wakeup_segment = RELOCATED(.) | ||||
| 	.word 0x0000
 | ||||
| 
 | ||||
| 	.globl __wakeup_size
 | ||||
| __wakeup_size: | ||||
| 	.long . - __wakeup | ||||
|  | @ -189,6 +189,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0 0x20>; | ||||
| 				bank-name = "A"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 
 | ||||
| 			gpiob { | ||||
|  | @ -196,6 +197,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0x20 0x20>; | ||||
| 				bank-name = "B"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 
 | ||||
| 			gpioc { | ||||
|  | @ -203,6 +205,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0x40 0x20>; | ||||
| 				bank-name = "C"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 
 | ||||
| 			gpiod { | ||||
|  | @ -210,6 +213,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0x60 0x20>; | ||||
| 				bank-name = "D"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 
 | ||||
| 			gpioe { | ||||
|  | @ -217,6 +221,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0x80 0x20>; | ||||
| 				bank-name = "E"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 
 | ||||
| 			gpiof { | ||||
|  | @ -224,6 +229,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0xA0 0x20>; | ||||
| 				bank-name = "F"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 		}; | ||||
| 	}; | ||||
|  |  | |||
|  | @ -212,6 +212,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0 0x20>; | ||||
| 				bank-name = "A"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 
 | ||||
| 			gpiob { | ||||
|  | @ -219,6 +220,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0x20 0x20>; | ||||
| 				bank-name = "B"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 
 | ||||
| 			gpioc { | ||||
|  | @ -226,6 +228,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0x40 0x20>; | ||||
| 				bank-name = "C"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 
 | ||||
| 			gpiod { | ||||
|  | @ -233,6 +236,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0x60 0x20>; | ||||
| 				bank-name = "D"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 
 | ||||
| 			gpioe { | ||||
|  | @ -240,6 +244,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0x80 0x20>; | ||||
| 				bank-name = "E"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 
 | ||||
| 			gpiof { | ||||
|  | @ -247,6 +252,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0xA0 0x20>; | ||||
| 				bank-name = "F"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 		}; | ||||
| 	}; | ||||
|  |  | |||
|  | @ -199,6 +199,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0 0x20>; | ||||
| 				bank-name = "A"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 
 | ||||
| 			gpiob { | ||||
|  | @ -206,6 +207,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0x20 0x20>; | ||||
| 				bank-name = "B"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 
 | ||||
| 			gpioc { | ||||
|  | @ -213,6 +215,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0x40 0x20>; | ||||
| 				bank-name = "C"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 
 | ||||
| 			gpiod { | ||||
|  | @ -220,6 +223,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0x60 0x20>; | ||||
| 				bank-name = "D"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 
 | ||||
| 			gpioe { | ||||
|  | @ -227,6 +231,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0x80 0x20>; | ||||
| 				bank-name = "E"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 
 | ||||
| 			gpiof { | ||||
|  | @ -234,6 +239,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0xA0 0x20>; | ||||
| 				bank-name = "F"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 		}; | ||||
| 	}; | ||||
|  |  | |||
|  | @ -201,6 +201,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0 0x20>; | ||||
| 				bank-name = "A"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 
 | ||||
| 			gpiob { | ||||
|  | @ -208,6 +209,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0x20 0x20>; | ||||
| 				bank-name = "B"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 
 | ||||
| 			gpioc { | ||||
|  | @ -215,6 +217,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0x40 0x20>; | ||||
| 				bank-name = "C"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 
 | ||||
| 			gpiod { | ||||
|  | @ -222,6 +225,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0x60 0x20>; | ||||
| 				bank-name = "D"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 
 | ||||
| 			gpioe { | ||||
|  | @ -229,6 +233,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0x80 0x20>; | ||||
| 				bank-name = "E"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 
 | ||||
| 			gpiof { | ||||
|  | @ -236,6 +241,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0xA0 0x20>; | ||||
| 				bank-name = "F"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 		}; | ||||
| 	}; | ||||
|  |  | |||
|  | @ -35,7 +35,6 @@ | |||
| 		/* GPIO E0 */ | ||||
| 		soc_gpio_s5_0@0 { | ||||
| 			gpio-offset = <0x80 0>; | ||||
| 			pad-offset = <0x1d0>; | ||||
| 			mode-gpio; | ||||
| 			output-value = <0>; | ||||
| 			direction = <PIN_OUTPUT>; | ||||
|  | @ -44,7 +43,6 @@ | |||
| 		/* GPIO E1 */ | ||||
| 		soc_gpio_s5_1@0 { | ||||
| 			gpio-offset = <0x80 1>; | ||||
| 			pad-offset = <0x210>; | ||||
| 			mode-gpio; | ||||
| 			output-value = <0>; | ||||
| 			direction = <PIN_OUTPUT>; | ||||
|  | @ -53,7 +51,6 @@ | |||
| 		/* GPIO E2 */ | ||||
| 		soc_gpio_s5_2@0 { | ||||
| 			gpio-offset = <0x80 2>; | ||||
| 			pad-offset = <0x1e0>; | ||||
| 			mode-gpio; | ||||
| 			output-value = <0>; | ||||
| 			direction = <PIN_OUTPUT>; | ||||
|  | @ -61,7 +58,6 @@ | |||
| 
 | ||||
| 		pin_usb_host_en0@0 { | ||||
| 			gpio-offset = <0x80 8>; | ||||
| 			pad-offset = <0x260>; | ||||
| 			mode-gpio; | ||||
| 			output-value = <1>; | ||||
| 			direction = <PIN_OUTPUT>; | ||||
|  | @ -69,7 +65,6 @@ | |||
| 
 | ||||
| 		pin_usb_host_en1@0 { | ||||
| 			gpio-offset = <0x80 9>; | ||||
| 			pad-offset = <0x250>; | ||||
| 			mode-gpio; | ||||
| 			output-value = <1>; | ||||
| 			direction = <PIN_OUTPUT>; | ||||
|  | @ -218,6 +213,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0 0x20>; | ||||
| 				bank-name = "A"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 
 | ||||
| 			gpiob { | ||||
|  | @ -225,6 +221,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0x20 0x20>; | ||||
| 				bank-name = "B"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 
 | ||||
| 			gpioc { | ||||
|  | @ -232,6 +229,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0x40 0x20>; | ||||
| 				bank-name = "C"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 
 | ||||
| 			gpiod { | ||||
|  | @ -239,6 +237,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0x60 0x20>; | ||||
| 				bank-name = "D"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 
 | ||||
| 			gpioe { | ||||
|  | @ -246,6 +245,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0x80 0x20>; | ||||
| 				bank-name = "E"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 
 | ||||
| 			gpiof { | ||||
|  | @ -253,6 +253,7 @@ | |||
| 				u-boot,dm-pre-reloc; | ||||
| 				reg = <0xA0 0x20>; | ||||
| 				bank-name = "F"; | ||||
| 				use-lvl-write-cache; | ||||
| 			}; | ||||
| 		}; | ||||
| 	}; | ||||
|  |  | |||
|  | @ -0,0 +1,131 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2017, Bin Meng <bmeng.cn@gmail.com> | ||||
|  * | ||||
|  * SPDX-License-Identifier:	GPL-2.0+ | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __ASM_ACPI_S3_H__ | ||||
| #define __ASM_ACPI_S3_H__ | ||||
| 
 | ||||
| #define WAKEUP_BASE	0x600 | ||||
| 
 | ||||
| /* PM1_STATUS register */ | ||||
| #define WAK_STS		(1 << 15) | ||||
| #define PCIEXPWAK_STS	(1 << 14) | ||||
| #define RTC_STS		(1 << 10) | ||||
| #define SLPBTN_STS	(1 << 9) | ||||
| #define PWRBTN_STS	(1 << 8) | ||||
| #define GBL_STS		(1 << 5) | ||||
| #define BM_STS		(1 << 4) | ||||
| #define TMR_STS		(1 << 0) | ||||
| 
 | ||||
| /* PM1_CNT register */ | ||||
| #define SLP_EN		(1 << 13) | ||||
| #define SLP_TYP_SHIFT	10 | ||||
| #define SLP_TYP		(7 << SLP_TYP_SHIFT) | ||||
| #define SLP_TYP_S0	0 | ||||
| #define SLP_TYP_S1	1 | ||||
| #define SLP_TYP_S3	5 | ||||
| #define SLP_TYP_S4	6 | ||||
| #define SLP_TYP_S5	7 | ||||
| 
 | ||||
| /* Memory size reserved for S3 resume */ | ||||
| #define S3_RESERVE_SIZE	0x1000 | ||||
| 
 | ||||
| #ifndef __ASSEMBLY__ | ||||
| 
 | ||||
| extern char __wakeup[]; | ||||
| extern int __wakeup_size; | ||||
| 
 | ||||
| enum acpi_sleep_state { | ||||
| 	ACPI_S0, | ||||
| 	ACPI_S1, | ||||
| 	ACPI_S2, | ||||
| 	ACPI_S3, | ||||
| 	ACPI_S4, | ||||
| 	ACPI_S5, | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * acpi_ss_string() - get ACPI-defined sleep state string | ||||
|  * | ||||
|  * @pm1_cnt:	ACPI-defined sleep state | ||||
|  * @return:	a pointer to the sleep state string. | ||||
|  */ | ||||
| static inline char *acpi_ss_string(enum acpi_sleep_state state) | ||||
| { | ||||
| 	char *ss_string[] = { "S0", "S1", "S2", "S3", "S4", "S5"}; | ||||
| 
 | ||||
| 	return ss_string[state]; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * acpi_sleep_from_pm1() - get ACPI-defined sleep state from PM1_CNT register | ||||
|  * | ||||
|  * @pm1_cnt:	PM1_CNT register value | ||||
|  * @return:	ACPI-defined sleep state if given valid PM1_CNT register value, | ||||
|  *		-EINVAL otherwise. | ||||
|  */ | ||||
| static inline enum acpi_sleep_state acpi_sleep_from_pm1(u32 pm1_cnt) | ||||
| { | ||||
| 	switch ((pm1_cnt & SLP_TYP) >> SLP_TYP_SHIFT) { | ||||
| 	case SLP_TYP_S0: | ||||
| 		return ACPI_S0; | ||||
| 	case SLP_TYP_S1: | ||||
| 		return ACPI_S1; | ||||
| 	case SLP_TYP_S3: | ||||
| 		return ACPI_S3; | ||||
| 	case SLP_TYP_S4: | ||||
| 		return ACPI_S4; | ||||
| 	case SLP_TYP_S5: | ||||
| 		return ACPI_S5; | ||||
| 	} | ||||
| 
 | ||||
| 	return -EINVAL; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * chipset_prev_sleep_state() - Get chipset previous sleep state | ||||
|  * | ||||
|  * This returns chipset previous sleep state from ACPI registers. | ||||
|  * Platform codes must supply this routine in order to support ACPI S3. | ||||
|  * | ||||
|  * @return ACPI_S0/S1/S2/S3/S4/S5. | ||||
|  */ | ||||
| enum acpi_sleep_state chipset_prev_sleep_state(void); | ||||
| 
 | ||||
| /**
 | ||||
|  * chipset_clear_sleep_state() - Clear chipset sleep state | ||||
|  * | ||||
|  * This clears chipset sleep state in ACPI registers. | ||||
|  * Platform codes must supply this routine in order to support ACPI S3. | ||||
|  */ | ||||
| void chipset_clear_sleep_state(void); | ||||
| 
 | ||||
| struct acpi_fadt; | ||||
| /**
 | ||||
|  * acpi_resume() - Do ACPI S3 resume | ||||
|  * | ||||
|  * This calls U-Boot wake up assembly stub and jumps to OS's wake up vector. | ||||
|  * | ||||
|  * @fadt:	FADT table pointer in the ACPI table | ||||
|  * @return:	Never returns | ||||
|  */ | ||||
| void acpi_resume(struct acpi_fadt *fadt); | ||||
| 
 | ||||
| /**
 | ||||
|  * acpi_s3_reserve() - Reserve memory for ACPI S3 resume | ||||
|  * | ||||
|  * This copies memory where real mode interrupt handler stubs reside to the | ||||
|  * reserved place on the stack. | ||||
|  * | ||||
|  * This routine should be called by reserve_arch() before U-Boot is relocated | ||||
|  * when ACPI S3 resume is enabled. | ||||
|  * | ||||
|  * @return:	0 always | ||||
|  */ | ||||
| int acpi_s3_reserve(void); | ||||
| 
 | ||||
| #endif /* __ASSEMBLY__ */ | ||||
| 
 | ||||
| #endif /* __ASM_ACPI_S3_H__ */ | ||||
|  | @ -316,4 +316,32 @@ int acpi_create_madt_lapic_nmi(struct acpi_madt_lapic_nmi *lapic_nmi, | |||
| 			       u8 cpu, u16 flags, u8 lint); | ||||
| u32 acpi_fill_madt(u32 current); | ||||
| void acpi_create_gnvs(struct acpi_global_nvs *gnvs); | ||||
| /**
 | ||||
|  * enter_acpi_mode() - enter into ACPI mode | ||||
|  * | ||||
|  * This programs the ACPI-defined PM1_CNT register to enable SCI interrupt | ||||
|  * so that the whole system swiches to ACPI mode. | ||||
|  * | ||||
|  * @pm1_cnt:	PM1_CNT register I/O address | ||||
|  */ | ||||
| void enter_acpi_mode(int pm1_cnt); | ||||
| ulong write_acpi_tables(ulong start); | ||||
| 
 | ||||
| /**
 | ||||
|  * acpi_find_fadt() - find ACPI FADT table in the sytem memory | ||||
|  * | ||||
|  * This routine parses the ACPI table to locate the ACPI FADT table. | ||||
|  * | ||||
|  * @return:	a pointer to the ACPI FADT table in the system memory | ||||
|  */ | ||||
| struct acpi_fadt *acpi_find_fadt(void); | ||||
| 
 | ||||
| /**
 | ||||
|  * acpi_find_wakeup_vector() - find OS installed wake up vector address | ||||
|  * | ||||
|  * This routine parses the ACPI table to locate the wake up vector installed | ||||
|  * by the OS previously. | ||||
|  * | ||||
|  * @return:	wake up vector address installed by the OS | ||||
|  */ | ||||
| void *acpi_find_wakeup_vector(struct acpi_fadt *); | ||||
|  |  | |||
|  | @ -8,6 +8,8 @@ | |||
|  */ | ||||
| 
 | ||||
| Name(\_S0, Package() {0x0, 0x0, 0x0, 0x0}) | ||||
| #ifdef CONFIG_HAVE_ACPI_RESUME | ||||
| Name(\_S3, Package() {0x5, 0x0, 0x0, 0x0}) | ||||
| #endif | ||||
| Name(\_S4, Package() {0x6, 0x0, 0x0, 0x0}) | ||||
| Name(\_S5, Package() {0x7, 0x0, 0x0, 0x0}) | ||||
|  |  | |||
|  | @ -35,6 +35,27 @@ | |||
| #define PMC_BASE_ADDRESS		0xfed03000 | ||||
| #define PMC_BASE_SIZE			0x400 | ||||
| 
 | ||||
| #define GEN_PMCON1			0x20 | ||||
| #define  UART_EN			(1 << 24) | ||||
| #define  DISB				(1 << 23) | ||||
| #define  MEM_SR				(1 << 21) | ||||
| #define  SRS				(1 << 20) | ||||
| #define  CTS				(1 << 19) | ||||
| #define  MS4V				(1 << 18) | ||||
| #define  PWR_FLR			(1 << 16) | ||||
| #define  PME_B0_S5_DIS			(1 << 15) | ||||
| #define  SUS_PWR_FLR			(1 << 14) | ||||
| #define  WOL_EN_OVRD			(1 << 13) | ||||
| #define  DIS_SLP_X_STRCH_SUS_UP		(1 << 12) | ||||
| #define  GEN_RST_STS			(1 <<  9) | ||||
| #define  RPS				(1 <<  2) | ||||
| #define  AFTERG3_EN			(1 <<  0) | ||||
| #define GEN_PMCON2			0x24 | ||||
| #define  SLPSX_STR_POL_LOCK		(1 << 18) | ||||
| #define  BIOS_PCI_EXP_EN		(1 << 10) | ||||
| #define  PWRBTN_LVL			(1 <<  9) | ||||
| #define  SMI_LOCK			(1 <<  4) | ||||
| 
 | ||||
| /* Power Management Unit */ | ||||
| #define PUNIT_BASE_ADDRESS		0xfed05000 | ||||
| #define PUNIT_BASE_SIZE			0x800 | ||||
|  | @ -62,6 +83,9 @@ | |||
| #define ACPI_BASE_ADDRESS		0x0400 | ||||
| #define ACPI_BASE_SIZE			0x80 | ||||
| 
 | ||||
| #define PM1_STS				0x00 | ||||
| #define PM1_CNT				0x04 | ||||
| 
 | ||||
| #define GPIO_BASE_ADDRESS		0x0500 | ||||
| #define GPIO_BASE_SIZE			0x100 | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,31 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2017, Bin Meng <bmeng.cn@gmail.com> | ||||
|  * | ||||
|  * SPDX-License-Identifier:	GPL-2.0+ | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __CMOS_LAYOUT_H | ||||
| #define __CMOS_LAYOUT_H | ||||
| 
 | ||||
| /*
 | ||||
|  * The RTC internal registers and RAM is organized as two banks of 128 bytes | ||||
|  * each, called the standard and extended banks. The first 14 bytes of the | ||||
|  * standard bank contain the RTC time and date information along with four | ||||
|  * registers, A - D, that are used for configuration of the RTC. The extended | ||||
|  * bank contains a full 128 bytes of battery backed SRAM. | ||||
|  * | ||||
|  * For simplicity in U-Boot we only support CMOS in the standard bank, and | ||||
|  * its base address starts from offset 0x10, which leaves us 112 bytes space. | ||||
|  */ | ||||
| #define CMOS_BASE		0x10 | ||||
| 
 | ||||
| /*
 | ||||
|  * The file records all offsets off CMOS_BASE that is currently used by | ||||
|  * U-Boot for various reasons. It is put in such a unified place in order | ||||
|  * to be consistent across platforms. | ||||
|  */ | ||||
| 
 | ||||
| /* stack address for S3 boot in a FSP configuration, 4 bytes */ | ||||
| #define CMOS_FSP_STACK_ADDR	CMOS_BASE | ||||
| 
 | ||||
| #endif /* __CMOS_LAYOUT_H */ | ||||
|  | @ -0,0 +1,43 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2017, Bin Meng <bmeng.cn@gmail.com> | ||||
|  * | ||||
|  * SPDX-License-Identifier:	GPL-2.0+ | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __EARLY_CMOS_H | ||||
| #define __EARLY_CMOS_H | ||||
| 
 | ||||
| /* CMOS actually resides in the RTC SRAM */ | ||||
| #define CMOS_IO_PORT	0x70 | ||||
| 
 | ||||
| /**
 | ||||
|  * cmos_read8() - Get 8-bit data stored at the given address | ||||
|  * | ||||
|  * This reads from CMOS for the 8-bit data stored at the given address. | ||||
|  * | ||||
|  * @addr:	RTC SRAM address | ||||
|  * @return:	8-bit data stored at the given address | ||||
|  */ | ||||
| u8 cmos_read8(u8 addr); | ||||
| 
 | ||||
| /**
 | ||||
|  * cmos_read16() - Get 16-bit data stored at the given address | ||||
|  * | ||||
|  * This reads from CMOS for the 16-bit data stored at the given address. | ||||
|  * | ||||
|  * @addr:	RTC SRAM address | ||||
|  * @return:	16-bit data stored at the given address | ||||
|  */ | ||||
| u16 cmos_read16(u8 addr); | ||||
| 
 | ||||
| /**
 | ||||
|  * cmos_read32() - Get 32-bit data stored at the given address | ||||
|  * | ||||
|  * This reads from CMOS for the 32-bit data stored at the given address. | ||||
|  * | ||||
|  * @addr:	RTC SRAM address | ||||
|  * @return:	32-bit data stored at the given address | ||||
|  */ | ||||
| u32 cmos_read32(u8 addr); | ||||
| 
 | ||||
| #endif /* __EARLY_CMOS_H */ | ||||
|  | @ -99,6 +99,10 @@ struct arch_global_data { | |||
| 	u32 high_table_ptr; | ||||
| 	u32 high_table_limit; | ||||
| #endif | ||||
| #ifdef CONFIG_HAVE_ACPI_RESUME | ||||
| 	int prev_sleep_state;		/* Previous sleep state ACPI_S0/1../5 */ | ||||
| 	ulong backup_mem;		/* Backup memory address for S3 */ | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -31,10 +31,12 @@ | |||
| #define POST_MRC		0x2f | ||||
| #define POST_DRAM		0x30 | ||||
| #define POST_LAPIC		0x31 | ||||
| #define POST_OS_RESUME		0x40 | ||||
| 
 | ||||
| #define POST_RAM_FAILURE	0xea | ||||
| #define POST_BIST_FAILURE	0xeb | ||||
| #define POST_CAR_FAILURE	0xec | ||||
| #define POST_RESUME_FAILURE	0xed | ||||
| 
 | ||||
| /* Output a post code using al - value must be 0 to 0xff */ | ||||
| #ifdef __ASSEMBLY__ | ||||
|  |  | |||
|  | @ -15,6 +15,7 @@ | |||
|  * PIRQ routing table, Multi-Processor table and ACPI table. | ||||
|  */ | ||||
| #define ROM_TABLE_ADDR	0xf0000 | ||||
| #define ROM_TABLE_END	0xfffff | ||||
| 
 | ||||
| #define ROM_TABLE_ALIGN	1024 | ||||
| 
 | ||||
|  |  | |||
|  | @ -54,6 +54,19 @@ u32 isa_map_rom(u32 bus_addr, int size); | |||
| /* arch/x86/lib/... */ | ||||
| int video_bios_init(void); | ||||
| 
 | ||||
| /* arch/x86/lib/fsp/... */ | ||||
| 
 | ||||
| /**
 | ||||
|  * fsp_save_s3_stack() - save stack address to CMOS for next S3 boot | ||||
|  * | ||||
|  * At the end of pre-relocation phase, save the new stack address | ||||
|  * to CMOS and use it as the stack on next S3 boot for fsp_init() | ||||
|  * continuation function. | ||||
|  * | ||||
|  * @return:	0 if OK, -ve on error | ||||
|  */ | ||||
| int fsp_save_s3_stack(void); | ||||
| 
 | ||||
| void	board_init_f_r_trampoline(ulong) __attribute__ ((noreturn)); | ||||
| void	board_init_f_r(void) __attribute__ ((noreturn)); | ||||
| 
 | ||||
|  |  | |||
|  | @ -15,6 +15,7 @@ obj-$(CONFIG_CMD_BOOTM) += bootm.o | |||
| endif | ||||
| obj-y	+= cmd_boot.o | ||||
| obj-$(CONFIG_SEABIOS) += coreboot_table.o | ||||
| obj-y	+= early_cmos.o | ||||
| obj-$(CONFIG_EFI) += efi/ | ||||
| obj-y	+= e820.o | ||||
| obj-y	+= gcc.o | ||||
|  | @ -37,6 +38,7 @@ obj-$(CONFIG_INTEL_MID) += scu.o | |||
| obj-y	+= sections.o | ||||
| obj-y += sfi.o | ||||
| obj-y	+= string.o | ||||
| obj-$(CONFIG_HAVE_ACPI_RESUME) += acpi_s3.o | ||||
| ifndef CONFIG_QEMU | ||||
| obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o | ||||
| endif | ||||
|  |  | |||
|  | @ -0,0 +1,82 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2017, Bin Meng <bmeng.cn@gmail.com> | ||||
|  * | ||||
|  * SPDX-License-Identifier:	GPL-2.0+ | ||||
|  */ | ||||
| 
 | ||||
| #include <common.h> | ||||
| #include <asm/acpi_s3.h> | ||||
| #include <asm/acpi_table.h> | ||||
| #include <asm/post.h> | ||||
| 
 | ||||
| DECLARE_GLOBAL_DATA_PTR; | ||||
| 
 | ||||
| static void asmlinkage (*acpi_do_wakeup)(void *vector) = (void *)WAKEUP_BASE; | ||||
| 
 | ||||
| static void acpi_jump_to_wakeup(void *vector) | ||||
| { | ||||
| 	/* Copy wakeup trampoline in place */ | ||||
| 	memcpy((void *)WAKEUP_BASE, __wakeup, __wakeup_size); | ||||
| 
 | ||||
| 	printf("Jumping to OS waking vector %p\n", vector); | ||||
| 	acpi_do_wakeup(vector); | ||||
| } | ||||
| 
 | ||||
| void acpi_resume(struct acpi_fadt *fadt) | ||||
| { | ||||
| 	void *wake_vec; | ||||
| 
 | ||||
| 	/* Turn on ACPI mode for S3 */ | ||||
| 	enter_acpi_mode(fadt->pm1a_cnt_blk); | ||||
| 
 | ||||
| 	wake_vec = acpi_find_wakeup_vector(fadt); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Restore the memory content starting from address 0x1000 which is | ||||
| 	 * used for the real mode interrupt handler stubs. | ||||
| 	 */ | ||||
| 	memcpy((void *)0x1000, (const void *)gd->arch.backup_mem, | ||||
| 	       S3_RESERVE_SIZE); | ||||
| 
 | ||||
| 	post_code(POST_OS_RESUME); | ||||
| 	acpi_jump_to_wakeup(wake_vec); | ||||
| } | ||||
| 
 | ||||
| int acpi_s3_reserve(void) | ||||
| { | ||||
| 	/* adjust stack pointer for ACPI S3 resume backup memory */ | ||||
| 	gd->start_addr_sp -= S3_RESERVE_SIZE; | ||||
| 	gd->arch.backup_mem = gd->start_addr_sp; | ||||
| 
 | ||||
| 	gd->start_addr_sp &= ~0xf; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * U-Boot sets up the real mode interrupt handler stubs starting from | ||||
| 	 * address 0x1000. In most cases, the first 640K (0x00000 - 0x9ffff) | ||||
| 	 * system memory is reported as system RAM in E820 table to the OS. | ||||
| 	 * (see install_e820_map() implementation for each platform). So OS | ||||
| 	 * can use these memories whatever it wants. | ||||
| 	 * | ||||
| 	 * If U-Boot is in an S3 resume path, care must be taken not to corrupt | ||||
| 	 * these memorie otherwise OS data gets lost. Testing shows that, on | ||||
| 	 * Microsoft Windows 10 on Intel Baytrail its wake up vector happens to | ||||
| 	 * be installed at the same address 0x1000. While on Linux its wake up | ||||
| 	 * vector does not overlap this memory range, but after resume kernel | ||||
| 	 * checks low memory range per config option CONFIG_X86_RESERVE_LOW | ||||
| 	 * which is 64K by default to see whether a memory corruption occurs | ||||
| 	 * during the suspend/resume (it's harmless, but warnings are shown | ||||
| 	 * in the kernel dmesg logs). | ||||
| 	 * | ||||
| 	 * We cannot simply mark the these memory as reserved in E820 table | ||||
| 	 * because such configuration makes GRUB complain: unable to allocate | ||||
| 	 * real mode page. Hence we choose to back up these memories to the | ||||
| 	 * place where we reserved on our stack for our S3 resume work. | ||||
| 	 * Before jumping to OS wake up vector, we need restore the original | ||||
| 	 * content there (see acpi_resume() above). | ||||
| 	 */ | ||||
| 	if (gd->arch.prev_sleep_state == ACPI_S3) | ||||
| 		memcpy((void *)gd->arch.backup_mem, (const void *)0x1000, | ||||
| 		       S3_RESERVE_SIZE); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  | @ -304,8 +304,10 @@ static void acpi_create_mcfg(struct acpi_mcfg *mcfg) | |||
| 	header->checksum = table_compute_checksum((void *)mcfg, header->length); | ||||
| } | ||||
| 
 | ||||
| static void enter_acpi_mode(int pm1_cnt) | ||||
| void enter_acpi_mode(int pm1_cnt) | ||||
| { | ||||
| 	u16 val = inw(pm1_cnt); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * PM1_CNT register bit0 selects the power management event to be | ||||
| 	 * either an SCI or SMI interrupt. When this bit is set, then power | ||||
|  | @ -320,7 +322,7 @@ static void enter_acpi_mode(int pm1_cnt) | |||
| 	 * system, and expose ourselves to OSPM as working under ACPI mode | ||||
| 	 * already, turn this bit on. | ||||
| 	 */ | ||||
| 	outw(PM1_CNT_SCI_EN, pm1_cnt); | ||||
| 	outw(val | PM1_CNT_SCI_EN, pm1_cnt); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  | @ -438,3 +440,81 @@ ulong write_acpi_tables(ulong start) | |||
| 
 | ||||
| 	return current; | ||||
| } | ||||
| 
 | ||||
| static struct acpi_rsdp *acpi_valid_rsdp(struct acpi_rsdp *rsdp) | ||||
| { | ||||
| 	if (strncmp((char *)rsdp, RSDP_SIG, sizeof(RSDP_SIG) - 1) != 0) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	debug("Looking on %p for valid checksum\n", rsdp); | ||||
| 
 | ||||
| 	if (table_compute_checksum((void *)rsdp, 20) != 0) | ||||
| 		return NULL; | ||||
| 	debug("acpi rsdp checksum 1 passed\n"); | ||||
| 
 | ||||
| 	if ((rsdp->revision > 1) && | ||||
| 	    (table_compute_checksum((void *)rsdp, rsdp->length) != 0)) | ||||
| 		return NULL; | ||||
| 	debug("acpi rsdp checksum 2 passed\n"); | ||||
| 
 | ||||
| 	return rsdp; | ||||
| } | ||||
| 
 | ||||
| struct acpi_fadt *acpi_find_fadt(void) | ||||
| { | ||||
| 	char *p, *end; | ||||
| 	struct acpi_rsdp *rsdp = NULL; | ||||
| 	struct acpi_rsdt *rsdt; | ||||
| 	struct acpi_fadt *fadt = NULL; | ||||
| 	int i; | ||||
| 
 | ||||
| 	/* Find RSDP */ | ||||
| 	for (p = (char *)ROM_TABLE_ADDR; p < (char *)ROM_TABLE_END; p += 16) { | ||||
| 		rsdp = acpi_valid_rsdp((struct acpi_rsdp *)p); | ||||
| 		if (rsdp) | ||||
| 			break; | ||||
| 	} | ||||
| 
 | ||||
| 	if (rsdp == NULL) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	debug("RSDP found at %p\n", rsdp); | ||||
| 	rsdt = (struct acpi_rsdt *)rsdp->rsdt_address; | ||||
| 
 | ||||
| 	end = (char *)rsdt + rsdt->header.length; | ||||
| 	debug("RSDT found at %p ends at %p\n", rsdt, end); | ||||
| 
 | ||||
| 	for (i = 0; ((char *)&rsdt->entry[i]) < end; i++) { | ||||
| 		fadt = (struct acpi_fadt *)rsdt->entry[i]; | ||||
| 		if (strncmp((char *)fadt, "FACP", 4) == 0) | ||||
| 			break; | ||||
| 		fadt = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (fadt == NULL) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	debug("FADT found at %p\n", fadt); | ||||
| 	return fadt; | ||||
| } | ||||
| 
 | ||||
| void *acpi_find_wakeup_vector(struct acpi_fadt *fadt) | ||||
| { | ||||
| 	struct acpi_facs *facs; | ||||
| 	void *wake_vec; | ||||
| 
 | ||||
| 	debug("Trying to find the wakeup vector...\n"); | ||||
| 
 | ||||
| 	facs = (struct acpi_facs *)fadt->firmware_ctrl; | ||||
| 
 | ||||
| 	if (facs == NULL) { | ||||
| 		debug("No FACS found, wake up from S3 not possible.\n"); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	debug("FACS found at %p\n", facs); | ||||
| 	wake_vec = (void *)facs->firmware_waking_vector; | ||||
| 	debug("OS waking vector is %p\n", wake_vec); | ||||
| 
 | ||||
| 	return wake_vec; | ||||
| } | ||||
|  |  | |||
|  | @ -10,6 +10,8 @@ | |||
| 
 | ||||
| #include <common.h> | ||||
| #include <command.h> | ||||
| #include <dm/device.h> | ||||
| #include <dm/root.h> | ||||
| #include <errno.h> | ||||
| #include <fdt_support.h> | ||||
| #include <image.h> | ||||
|  | @ -46,6 +48,13 @@ void bootm_announce_and_cleanup(void) | |||
| #ifdef CONFIG_BOOTSTAGE_REPORT | ||||
| 	bootstage_report(); | ||||
| #endif | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Call remove function of all devices with a removal flag set. | ||||
| 	 * This may be useful for last-stage operations, like cancelling | ||||
| 	 * of DMA operation or releasing device internal buffers. | ||||
| 	 */ | ||||
| 	dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL); | ||||
| } | ||||
| 
 | ||||
| #if defined(CONFIG_OF_LIBFDT) && !defined(CONFIG_OF_NO_KERNEL) | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ | |||
| 
 | ||||
| #include <common.h> | ||||
| #include <vbe.h> | ||||
| #include <asm/acpi_s3.h> | ||||
| #include <asm/coreboot_tables.h> | ||||
| #include <asm/e820.h> | ||||
| 
 | ||||
|  | @ -19,7 +20,11 @@ int high_table_reserve(void) | |||
| 	gd->arch.high_table_ptr = gd->start_addr_sp; | ||||
| 
 | ||||
| 	/* clear the memory */ | ||||
| 	memset((void *)gd->arch.high_table_ptr, 0, CONFIG_HIGH_TABLE_SIZE); | ||||
| #ifdef CONFIG_HAVE_ACPI_RESUME | ||||
| 	if (gd->arch.prev_sleep_state != ACPI_S3) | ||||
| #endif | ||||
| 		memset((void *)gd->arch.high_table_ptr, 0, | ||||
| 		       CONFIG_HIGH_TABLE_SIZE); | ||||
| 
 | ||||
| 	gd->start_addr_sp &= ~0xf; | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,51 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2017, Bin Meng <bmeng.cn@gmail.com> | ||||
|  * | ||||
|  * SPDX-License-Identifier:	GPL-2.0+ | ||||
|  */ | ||||
| 
 | ||||
| /*
 | ||||
|  * This library provides CMOS (inside RTC SRAM) access routines at a very | ||||
|  * early stage when driver model is not available yet. Only read access is | ||||
|  * provided. The 16-bit/32-bit read are compatible with driver model RTC | ||||
|  * uclass write ops, that data is stored in little-endian mode. | ||||
|  */ | ||||
| 
 | ||||
| #include <common.h> | ||||
| #include <asm/early_cmos.h> | ||||
| #include <asm/io.h> | ||||
| 
 | ||||
| u8 cmos_read8(u8 addr) | ||||
| { | ||||
| 	outb(addr, CMOS_IO_PORT); | ||||
| 
 | ||||
| 	return inb(CMOS_IO_PORT + 1); | ||||
| } | ||||
| 
 | ||||
| u16 cmos_read16(u8 addr) | ||||
| { | ||||
| 	u16 value = 0; | ||||
| 	u16 data; | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < sizeof(value); i++) { | ||||
| 		data = cmos_read8(addr + i); | ||||
| 		value |= data << (i << 3); | ||||
| 	} | ||||
| 
 | ||||
| 	return value; | ||||
| } | ||||
| 
 | ||||
| u32 cmos_read32(u8 addr) | ||||
| { | ||||
| 	u32 value = 0; | ||||
| 	u32 data; | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < sizeof(value); i++) { | ||||
| 		data = cmos_read8(addr + i); | ||||
| 		value |= data << (i << 3); | ||||
| 	} | ||||
| 
 | ||||
| 	return value; | ||||
| } | ||||
|  | @ -5,7 +5,12 @@ | |||
|  */ | ||||
| 
 | ||||
| #include <common.h> | ||||
| #include <dm.h> | ||||
| #include <errno.h> | ||||
| #include <rtc.h> | ||||
| #include <asm/acpi_s3.h> | ||||
| #include <asm/cmos_layout.h> | ||||
| #include <asm/early_cmos.h> | ||||
| #include <asm/io.h> | ||||
| #include <asm/mrccache.h> | ||||
| #include <asm/post.h> | ||||
|  | @ -75,9 +80,41 @@ static __maybe_unused void *fsp_prepare_mrc_cache(void) | |||
| 	return cache->data; | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_HAVE_ACPI_RESUME | ||||
| int fsp_save_s3_stack(void) | ||||
| { | ||||
| 	struct udevice *dev; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (gd->arch.prev_sleep_state == ACPI_S3) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	ret = uclass_get_device(UCLASS_RTC, 0, &dev); | ||||
| 	if (ret) { | ||||
| 		debug("Cannot find RTC: err=%d\n", ret); | ||||
| 		return -ENODEV; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Save the stack address to CMOS */ | ||||
| 	ret = rtc_write32(dev, CMOS_FSP_STACK_ADDR, gd->start_addr_sp); | ||||
| 	if (ret) { | ||||
| 		debug("Save stack address to CMOS: err=%d\n", ret); | ||||
| 		return -EIO; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| int arch_fsp_init(void) | ||||
| { | ||||
| 	void *nvs; | ||||
| 	int stack = CONFIG_FSP_TEMP_RAM_ADDR; | ||||
| 	int boot_mode = BOOT_FULL_CONFIG; | ||||
| #ifdef CONFIG_HAVE_ACPI_RESUME | ||||
| 	int prev_sleep_state = chipset_prev_sleep_state(); | ||||
| 	gd->arch.prev_sleep_state = prev_sleep_state; | ||||
| #endif | ||||
| 
 | ||||
| 	if (!gd->arch.hob_list) { | ||||
| #ifdef CONFIG_ENABLE_MRC_CACHE | ||||
|  | @ -85,12 +122,36 @@ int arch_fsp_init(void) | |||
| #else | ||||
| 		nvs = NULL; | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_HAVE_ACPI_RESUME | ||||
| 		if (prev_sleep_state == ACPI_S3) { | ||||
| 			if (nvs == NULL) { | ||||
| 				/* If waking from S3 and no cache then */ | ||||
| 				debug("No MRC cache found in S3 resume path\n"); | ||||
| 				post_code(POST_RESUME_FAILURE); | ||||
| 				/* Clear Sleep Type */ | ||||
| 				chipset_clear_sleep_state(); | ||||
| 				/* Reboot */ | ||||
| 				debug("Rebooting..\n"); | ||||
| 				reset_cpu(0); | ||||
| 				/* Should not reach here.. */ | ||||
| 				panic("Reboot System"); | ||||
| 			} | ||||
| 
 | ||||
| 			/*
 | ||||
| 			 * DM is not avaiable yet at this point, hence call | ||||
| 			 * CMOS access library which does not depend on DM. | ||||
| 			 */ | ||||
| 			stack = cmos_read32(CMOS_FSP_STACK_ADDR); | ||||
| 			boot_mode = BOOT_ON_S3_RESUME; | ||||
| 		} | ||||
| #endif | ||||
| 		/*
 | ||||
| 		 * The first time we enter here, call fsp_init(). | ||||
| 		 * Note the execution does not return to this function, | ||||
| 		 * instead it jumps to fsp_continue(). | ||||
| 		 */ | ||||
| 		fsp_init(CONFIG_FSP_TEMP_RAM_ADDR, BOOT_FULL_CONFIG, nvs); | ||||
| 		fsp_init(stack, boot_mode, nvs); | ||||
| 	} else { | ||||
| 		/*
 | ||||
| 		 * The second time we enter here, adjust the size of malloc() | ||||
|  |  | |||
|  | @ -92,5 +92,17 @@ unsigned install_e820_map(unsigned max_entries, struct e820entry *entries) | |||
| 	entries[num_entries].type = E820_RESERVED; | ||||
| 	num_entries++; | ||||
| 
 | ||||
| #ifdef CONFIG_HAVE_ACPI_RESUME | ||||
| 	/*
 | ||||
| 	 * Everything between U-Boot's stack and ram top needs to be | ||||
| 	 * reserved in order for ACPI S3 resume to work. | ||||
| 	 */ | ||||
| 	entries[num_entries].addr = gd->start_addr_sp - CONFIG_STACK_SIZE; | ||||
| 	entries[num_entries].size = gd->ram_top - gd->start_addr_sp + \ | ||||
| 		CONFIG_STACK_SIZE; | ||||
| 	entries[num_entries].type = E820_RESERVED; | ||||
| 	num_entries++; | ||||
| #endif | ||||
| 
 | ||||
| 	return num_entries; | ||||
| } | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ CONFIG_HAVE_VGA_BIOS=y | |||
| CONFIG_GENERATE_PIRQ_TABLE=y | ||||
| CONFIG_GENERATE_MP_TABLE=y | ||||
| CONFIG_GENERATE_ACPI_TABLE=y | ||||
| CONFIG_HAVE_ACPI_RESUME=y | ||||
| CONFIG_SEABIOS=y | ||||
| CONFIG_FIT=y | ||||
| CONFIG_FIT_SIGNATURE=y | ||||
|  |  | |||
|  | @ -1014,12 +1014,12 @@ compile ACPI DSDT table written in ASL format to AML format. You can get | |||
| the compiler via "apt-get install iasl" if you are on Ubuntu or download | ||||
| the source from [17] to compile one by yourself. | ||||
| 
 | ||||
| Current ACPI support in U-Boot is not complete. More features will be added | ||||
| in the future. The status as of today is: | ||||
| Current ACPI support in U-Boot is basically complete. More optional features | ||||
| can be added in the future. The status as of today is: | ||||
| 
 | ||||
|  * Support generating RSDT, XSDT, FACS, FADT, MADT, MCFG tables. | ||||
|  * Support one static DSDT table only, compiled by Intel ACPI compiler. | ||||
|  * Support S0/S5, reboot and shutdown from OS. | ||||
|  * Support S0/S3/S4/S5, reboot and shutdown from OS. | ||||
|  * Support booting a pre-installed Ubuntu distribution via 'zboot' command. | ||||
|  * Support installing and booting Ubuntu 14.04 (or above) from U-Boot with | ||||
|    the help of SeaBIOS using legacy interface (non-UEFI mode). | ||||
|  | @ -1027,9 +1027,6 @@ in the future. The status as of today is: | |||
|    of SeaBIOS using legacy interface (non-UEFI mode). | ||||
|  * Support ACPI interrupts with SCI only. | ||||
| 
 | ||||
| Features not supported so far (to make it a complete ACPI solution): | ||||
|  * S3 (Suspend to RAM), S4 (Suspend to Disk). | ||||
| 
 | ||||
| Features that are optional: | ||||
|  * Dynamic AML bytecodes insertion at run-time. We may need this to support | ||||
|    SSDT table generation and DSDT fix up. | ||||
|  | @ -1046,6 +1043,21 @@ command from the OS. | |||
| For other platform boards, ACPI support status can be checked by examining their | ||||
| board defconfig files to see if CONFIG_GENERATE_ACPI_TABLE is set to y. | ||||
| 
 | ||||
| The S3 sleeping state is a low wake latency sleeping state defined by ACPI | ||||
| spec where all system context is lost except system memory. To test S3 resume | ||||
| with a Linux kernel, simply run "echo mem > /sys/power/state" and kernel will | ||||
| put the board to S3 state where the power is off. So when the power button is | ||||
| pressed again, U-Boot runs as it does in cold boot and detects the sleeping | ||||
| state via ACPI register to see if it is S3, if yes it means we are waking up. | ||||
| U-Boot is responsible for restoring the machine state as it is before sleep. | ||||
| When everything is done, U-Boot finds out the wakeup vector provided by OSes | ||||
| and jump there. To determine whether ACPI S3 resume is supported, check to | ||||
| see if CONFIG_HAVE_ACPI_RESUME is set for that specific board. | ||||
| 
 | ||||
| Note for testing S3 resume with Windows, correct graphics driver must be | ||||
| installed for your platform, otherwise you won't find "Sleep" option in | ||||
| the "Power" submenu from the Windows start menu. | ||||
| 
 | ||||
| EFI Support | ||||
| ----------- | ||||
| U-Boot supports booting as a 32-bit or 64-bit EFI payload, e.g. with UEFI. | ||||
|  |  | |||
|  | @ -152,6 +152,15 @@ void device_free(struct udevice *dev) | |||
| 	devres_release_probe(dev); | ||||
| } | ||||
| 
 | ||||
| static bool flags_remove(uint flags, uint drv_flags) | ||||
| { | ||||
| 	if ((flags & DM_REMOVE_NORMAL) || | ||||
| 	    (flags & (drv_flags & (DM_FLAG_ACTIVE_DMA | DM_FLAG_OS_PREPARE)))) | ||||
| 		return true; | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| int device_remove(struct udevice *dev, uint flags) | ||||
| { | ||||
| 	const struct driver *drv; | ||||
|  | @ -178,9 +187,7 @@ int device_remove(struct udevice *dev, uint flags) | |||
| 	 * Remove the device if called with the "normal" remove flag set, | ||||
| 	 * or if the remove flag matches any of the drivers remove flags | ||||
| 	 */ | ||||
| 	if (drv->remove && | ||||
| 	    ((flags & DM_REMOVE_NORMAL) || | ||||
| 	     (flags & (drv->flags & DM_FLAG_ACTIVE_DMA)))) { | ||||
| 	if (drv->remove && flags_remove(flags, drv->flags)) { | ||||
| 		ret = drv->remove(dev); | ||||
| 		if (ret) | ||||
| 			goto err_remove; | ||||
|  | @ -194,8 +201,7 @@ int device_remove(struct udevice *dev, uint flags) | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if ((flags & DM_REMOVE_NORMAL) || | ||||
| 	    (flags & (drv->flags & DM_FLAG_ACTIVE_DMA))) { | ||||
| 	if (flags_remove(flags, drv->flags)) { | ||||
| 		device_free(dev); | ||||
| 
 | ||||
| 		dev->seq = -1; | ||||
|  |  | |||
|  | @ -46,22 +46,31 @@ struct ich6_bank_priv { | |||
| 	uint16_t use_sel; | ||||
| 	uint16_t io_sel; | ||||
| 	uint16_t lvl; | ||||
| 	u32 lvl_write_cache; | ||||
| 	bool use_lvl_write_cache; | ||||
| }; | ||||
| 
 | ||||
| #define GPIO_USESEL_OFFSET(x)	(x) | ||||
| #define GPIO_IOSEL_OFFSET(x)	(x + 4) | ||||
| #define GPIO_LVL_OFFSET(x)	(x + 8) | ||||
| 
 | ||||
| static int _ich6_gpio_set_value(uint16_t base, unsigned offset, int value) | ||||
| static int _ich6_gpio_set_value(struct ich6_bank_priv *bank, unsigned offset, | ||||
| 				int value) | ||||
| { | ||||
| 	u32 val; | ||||
| 
 | ||||
| 	val = inl(base); | ||||
| 	if (bank->use_lvl_write_cache) | ||||
| 		val = bank->lvl_write_cache; | ||||
| 	else | ||||
| 		val = inl(bank->lvl); | ||||
| 
 | ||||
| 	if (value) | ||||
| 		val |= (1UL << offset); | ||||
| 	else | ||||
| 		val &= ~(1UL << offset); | ||||
| 	outl(val, base); | ||||
| 	outl(val, bank->lvl); | ||||
| 	if (bank->use_lvl_write_cache) | ||||
| 		bank->lvl_write_cache = val; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  | @ -112,6 +121,7 @@ static int ich6_gpio_probe(struct udevice *dev) | |||
| 	struct ich6_bank_platdata *plat = dev_get_platdata(dev); | ||||
| 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); | ||||
| 	struct ich6_bank_priv *bank = dev_get_priv(dev); | ||||
| 	const void *prop; | ||||
| 
 | ||||
| 	uc_priv->gpio_count = GPIO_PER_BANK; | ||||
| 	uc_priv->bank_name = plat->bank_name; | ||||
|  | @ -119,6 +129,14 @@ static int ich6_gpio_probe(struct udevice *dev) | |||
| 	bank->io_sel = plat->base_addr + 4; | ||||
| 	bank->lvl = plat->base_addr + 8; | ||||
| 
 | ||||
| 	prop = fdt_getprop(gd->fdt_blob, dev->of_offset, | ||||
| 			   "use-lvl-write-cache", NULL); | ||||
| 	if (prop) | ||||
| 		bank->use_lvl_write_cache = true; | ||||
| 	else | ||||
| 		bank->use_lvl_write_cache = false; | ||||
| 	bank->lvl_write_cache = 0; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  | @ -160,7 +178,7 @@ static int ich6_gpio_direction_output(struct udevice *dev, unsigned offset, | |||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	return _ich6_gpio_set_value(bank->lvl, offset, value); | ||||
| 	return _ich6_gpio_set_value(bank, offset, value); | ||||
| } | ||||
| 
 | ||||
| static int ich6_gpio_get_value(struct udevice *dev, unsigned offset) | ||||
|  | @ -170,6 +188,8 @@ static int ich6_gpio_get_value(struct udevice *dev, unsigned offset) | |||
| 	int r; | ||||
| 
 | ||||
| 	tmplong = inl(bank->lvl); | ||||
| 	if (bank->use_lvl_write_cache) | ||||
| 		tmplong |= bank->lvl_write_cache; | ||||
| 	r = (tmplong & (1UL << offset)) ? 1 : 0; | ||||
| 	return r; | ||||
| } | ||||
|  | @ -178,7 +198,7 @@ static int ich6_gpio_set_value(struct udevice *dev, unsigned offset, | |||
| 			       int value) | ||||
| { | ||||
| 	struct ich6_bank_priv *bank = dev_get_priv(dev); | ||||
| 	return _ich6_gpio_set_value(bank->lvl, offset, value); | ||||
| 	return _ich6_gpio_set_value(bank, offset, value); | ||||
| } | ||||
| 
 | ||||
| static int ich6_gpio_get_function(struct udevice *dev, unsigned offset) | ||||
|  |  | |||
|  | @ -6,37 +6,71 @@ | |||
|  */ | ||||
| 
 | ||||
| #include <common.h> | ||||
| #include <dm.h> | ||||
| #include <errno.h> | ||||
| #include <malloc.h> | ||||
| #include <mapmem.h> | ||||
| #include <sdhci.h> | ||||
| #include <asm/pci.h> | ||||
| 
 | ||||
| int pci_mmc_init(const char *name, struct pci_device_id *mmc_supported) | ||||
| struct pci_mmc_plat { | ||||
| 	struct mmc_config cfg; | ||||
| 	struct mmc mmc; | ||||
| }; | ||||
| 
 | ||||
| struct pci_mmc_priv { | ||||
| 	struct sdhci_host host; | ||||
| 	void *base; | ||||
| }; | ||||
| 
 | ||||
| static int pci_mmc_probe(struct udevice *dev) | ||||
| { | ||||
| 	struct sdhci_host *mmc_host; | ||||
| 	u32 iobase; | ||||
| 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); | ||||
| 	struct pci_mmc_plat *plat = dev_get_platdata(dev); | ||||
| 	struct pci_mmc_priv *priv = dev_get_priv(dev); | ||||
| 	struct sdhci_host *host = &priv->host; | ||||
| 	u32 ioaddr; | ||||
| 	int ret; | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; ; i++) { | ||||
| 		struct udevice *dev; | ||||
| 	dm_pci_read_config32(dev, PCI_BASE_ADDRESS_0, &ioaddr); | ||||
| 	host->ioaddr = map_sysmem(ioaddr, 0); | ||||
| 	host->name = dev->name; | ||||
| 	ret = sdhci_setup_cfg(&plat->cfg, host, 0, 0); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 	host->mmc = &plat->mmc; | ||||
| 	host->mmc->priv = &priv->host; | ||||
| 	host->mmc->dev = dev; | ||||
| 	upriv->mmc = host->mmc; | ||||
| 
 | ||||
| 		ret = pci_find_device_id(mmc_supported, i, &dev); | ||||
| 		if (ret) | ||||
| 			return ret; | ||||
| 		mmc_host = malloc(sizeof(struct sdhci_host)); | ||||
| 		if (!mmc_host) | ||||
| 			return -ENOMEM; | ||||
| 
 | ||||
| 		mmc_host->name = name; | ||||
| 		dm_pci_read_config32(dev, PCI_BASE_ADDRESS_0, &iobase); | ||||
| 		mmc_host->ioaddr = (void *)(ulong)iobase; | ||||
| 		mmc_host->quirks = 0; | ||||
| 		mmc_host->max_clk = 0; | ||||
| 		ret = add_sdhci(mmc_host, 0, 0); | ||||
| 		if (ret) | ||||
| 			return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| 	return sdhci_probe(dev); | ||||
| } | ||||
| 
 | ||||
| static int pci_mmc_bind(struct udevice *dev) | ||||
| { | ||||
| 	struct pci_mmc_plat *plat = dev_get_platdata(dev); | ||||
| 
 | ||||
| 	return sdhci_bind(dev, &plat->mmc, &plat->cfg); | ||||
| } | ||||
| 
 | ||||
| U_BOOT_DRIVER(pci_mmc) = { | ||||
| 	.name	= "pci_mmc", | ||||
| 	.id	= UCLASS_MMC, | ||||
| 	.bind	= pci_mmc_bind, | ||||
| 	.probe	= pci_mmc_probe, | ||||
| 	.ops	= &sdhci_ops, | ||||
| 	.priv_auto_alloc_size = sizeof(struct pci_mmc_priv), | ||||
| 	.platdata_auto_alloc_size = sizeof(struct pci_mmc_plat), | ||||
| }; | ||||
| 
 | ||||
| static struct pci_device_id mmc_supported[] = { | ||||
| 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_SDIO) }, | ||||
| 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_SD) }, | ||||
| 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_EMMC2) }, | ||||
| 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QRK_SDIO) }, | ||||
| 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TCF_SDIO_0) }, | ||||
| 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TCF_SDIO_1) }, | ||||
| 	{}, | ||||
| }; | ||||
| 
 | ||||
| U_BOOT_PCI_DEVICE(pci_mmc, mmc_supported); | ||||
|  |  | |||
|  | @ -35,8 +35,22 @@ | |||
| #include <video_fb.h> | ||||
| #include <linux/screen_info.h> | ||||
| 
 | ||||
| #ifdef CONFIG_X86 | ||||
| #include <asm/acpi_s3.h> | ||||
| DECLARE_GLOBAL_DATA_PTR; | ||||
| #endif | ||||
| 
 | ||||
| __weak bool board_should_run_oprom(struct udevice *dev) | ||||
| { | ||||
| #if defined(CONFIG_X86) && defined(CONFIG_HAVE_ACPI_RESUME) | ||||
| 	if (gd->arch.prev_sleep_state == ACPI_S3) { | ||||
| 		if (IS_ENABLED(CONFIG_S3_VGA_ROM_RUN)) | ||||
| 			return true; | ||||
| 		else | ||||
| 			return false; | ||||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -349,7 +349,7 @@ static int serial_pre_remove(struct udevice *dev) | |||
| #if CONFIG_IS_ENABLED(SYS_STDIO_DEREGISTER) | ||||
| 	struct serial_dev_priv *upriv = dev_get_uclass_priv(dev); | ||||
| 
 | ||||
| 	if (stdio_deregister_dev(upriv->sdev, 0)) | ||||
| 	if (stdio_deregister_dev(upriv->sdev, true)) | ||||
| 		return -EPERM; | ||||
| #endif | ||||
| 
 | ||||
|  |  | |||
|  | @ -617,6 +617,22 @@ static int ich_spi_probe(struct udevice *dev) | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int ich_spi_remove(struct udevice *bus) | ||||
| { | ||||
| 	struct ich_spi_priv *ctlr = dev_get_priv(bus); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Configure SPI controller so that the Linux MTD driver can fully | ||||
| 	 * access the SPI NOR chip | ||||
| 	 */ | ||||
| 	ich_writew(ctlr, SPI_OPPREFIX, ctlr->preop); | ||||
| 	ich_writew(ctlr, SPI_OPTYPE, ctlr->optype); | ||||
| 	ich_writel(ctlr, SPI_OPMENU_LOWER, ctlr->opmenu); | ||||
| 	ich_writel(ctlr, SPI_OPMENU_UPPER, ctlr->opmenu + sizeof(u32)); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int ich_spi_set_speed(struct udevice *bus, uint speed) | ||||
| { | ||||
| 	struct ich_spi_priv *priv = dev_get_priv(bus); | ||||
|  | @ -700,4 +716,6 @@ U_BOOT_DRIVER(ich_spi) = { | |||
| 	.priv_auto_alloc_size = sizeof(struct ich_spi_priv), | ||||
| 	.child_pre_probe = ich_spi_child_pre_probe, | ||||
| 	.probe	= ich_spi_probe, | ||||
| 	.remove	= ich_spi_remove, | ||||
| 	.flags	= DM_FLAG_OS_PREPARE, | ||||
| }; | ||||
|  |  | |||
|  | @ -101,13 +101,6 @@ enum { | |||
| 	HSFC_FSMIE =		0x8000 | ||||
| }; | ||||
| 
 | ||||
| enum { | ||||
| 	SPI_OPCODE_TYPE_READ_NO_ADDRESS =	0, | ||||
| 	SPI_OPCODE_TYPE_WRITE_NO_ADDRESS =	1, | ||||
| 	SPI_OPCODE_TYPE_READ_WITH_ADDRESS =	2, | ||||
| 	SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS =	3 | ||||
| }; | ||||
| 
 | ||||
| enum { | ||||
| 	ICH_MAX_CMD_LEN		= 5, | ||||
| }; | ||||
|  | @ -124,8 +117,55 @@ struct spi_trans { | |||
| 	uint32_t offset; | ||||
| }; | ||||
| 
 | ||||
| #define SPI_OPCODE_WRSR		0x01 | ||||
| #define SPI_OPCODE_PAGE_PROGRAM	0x02 | ||||
| #define SPI_OPCODE_READ		0x03 | ||||
| #define SPI_OPCODE_WRDIS	0x04 | ||||
| #define SPI_OPCODE_RDSR		0x05 | ||||
| #define SPI_OPCODE_WREN		0x06 | ||||
| #define SPI_OPCODE_FAST_READ	0x0b | ||||
| #define SPI_OPCODE_ERASE_SECT	0x20 | ||||
| #define SPI_OPCODE_READ_ID	0x9f | ||||
| #define SPI_OPCODE_ERASE_BLOCK	0xd8 | ||||
| 
 | ||||
| #define SPI_OPCODE_TYPE_READ_NO_ADDRESS		0 | ||||
| #define SPI_OPCODE_TYPE_WRITE_NO_ADDRESS	1 | ||||
| #define SPI_OPCODE_TYPE_READ_WITH_ADDRESS	2 | ||||
| #define SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS	3 | ||||
| 
 | ||||
| #define SPI_OPMENU_0	SPI_OPCODE_WRSR | ||||
| #define SPI_OPTYPE_0	SPI_OPCODE_TYPE_WRITE_NO_ADDRESS | ||||
| 
 | ||||
| #define SPI_OPMENU_1	SPI_OPCODE_PAGE_PROGRAM | ||||
| #define SPI_OPTYPE_1	SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS | ||||
| 
 | ||||
| #define SPI_OPMENU_2	SPI_OPCODE_READ | ||||
| #define SPI_OPTYPE_2	SPI_OPCODE_TYPE_READ_WITH_ADDRESS | ||||
| 
 | ||||
| #define SPI_OPMENU_3	SPI_OPCODE_RDSR | ||||
| #define SPI_OPTYPE_3	SPI_OPCODE_TYPE_READ_NO_ADDRESS | ||||
| 
 | ||||
| #define SPI_OPMENU_4	SPI_OPCODE_ERASE_SECT | ||||
| #define SPI_OPTYPE_4	SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS | ||||
| 
 | ||||
| #define SPI_OPMENU_5	SPI_OPCODE_READ_ID | ||||
| #define SPI_OPTYPE_5	SPI_OPCODE_TYPE_READ_NO_ADDRESS | ||||
| 
 | ||||
| #define SPI_OPMENU_6	SPI_OPCODE_ERASE_BLOCK | ||||
| #define SPI_OPTYPE_6	SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS | ||||
| 
 | ||||
| #define SPI_OPMENU_7	SPI_OPCODE_FAST_READ | ||||
| #define SPI_OPTYPE_7	SPI_OPCODE_TYPE_READ_WITH_ADDRESS | ||||
| 
 | ||||
| #define SPI_OPPREFIX	((SPI_OPCODE_WREN << 8) | SPI_OPCODE_WREN) | ||||
| #define SPI_OPTYPE	((SPI_OPTYPE_7 << 14) | (SPI_OPTYPE_6 << 12) | \ | ||||
| 			 (SPI_OPTYPE_5 << 10) | (SPI_OPTYPE_4 <<  8) | \ | ||||
| 			 (SPI_OPTYPE_3 <<  6) | (SPI_OPTYPE_2 <<  4) | \ | ||||
| 			 (SPI_OPTYPE_1 <<  2) | (SPI_OPTYPE_0 <<  0)) | ||||
| #define SPI_OPMENU_UPPER ((SPI_OPMENU_7 << 24) | (SPI_OPMENU_6 << 16) | \ | ||||
| 			  (SPI_OPMENU_5 <<  8) | (SPI_OPMENU_4 <<  0)) | ||||
| #define SPI_OPMENU_LOWER ((SPI_OPMENU_3 << 24) | (SPI_OPMENU_2 << 16) | \ | ||||
| 			  (SPI_OPMENU_1 <<  8) | (SPI_OPMENU_0 <<  0)) | ||||
| 
 | ||||
| enum ich_version { | ||||
| 	ICHV_7, | ||||
|  |  | |||
|  | @ -54,6 +54,12 @@ struct driver_info; | |||
|  */ | ||||
| #define DM_FLAG_ACTIVE_DMA		(1 << 9) | ||||
| 
 | ||||
| /*
 | ||||
|  * Call driver remove function to do some final configuration, before | ||||
|  * U-Boot exits and the OS is started | ||||
|  */ | ||||
| #define DM_FLAG_OS_PREPARE		(1 << 10) | ||||
| 
 | ||||
| /*
 | ||||
|  * One or multiple of these flags are passed to device_remove() so that | ||||
|  * a selective device removal as specified by the remove-stage and the | ||||
|  | @ -66,10 +72,13 @@ enum { | |||
| 	/* Remove devices with active DMA */ | ||||
| 	DM_REMOVE_ACTIVE_DMA = DM_FLAG_ACTIVE_DMA, | ||||
| 
 | ||||
| 	/* Remove devices which need some final OS preparation steps */ | ||||
| 	DM_REMOVE_OS_PREPARE = DM_FLAG_OS_PREPARE, | ||||
| 
 | ||||
| 	/* Add more use cases here */ | ||||
| 
 | ||||
| 	/* Remove devices with any active flag */ | ||||
| 	DM_REMOVE_ACTIVE_ALL = DM_REMOVE_ACTIVE_DMA, | ||||
| 	DM_REMOVE_ACTIVE_ALL = DM_REMOVE_ACTIVE_DMA | DM_REMOVE_OS_PREPARE, | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  |  | |||
|  | @ -585,18 +585,6 @@ int cpu_mmc_init(bd_t *bis); | |||
| int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr); | ||||
| int mmc_get_env_dev(void); | ||||
| 
 | ||||
| struct pci_device_id; | ||||
| 
 | ||||
| /**
 | ||||
|  * pci_mmc_init() - set up PCI MMC devices | ||||
|  * | ||||
|  * This finds all the matching PCI IDs and sets them up as MMC devices. | ||||
|  * | ||||
|  * @name:		Name to use for devices | ||||
|  * @mmc_supported:	PCI IDs to search for, terminated by {0, 0} | ||||
|  */ | ||||
| int pci_mmc_init(const char *name, struct pci_device_id *mmc_supported); | ||||
| 
 | ||||
| /* Set block count limit because of 16 bit register limit on some hardware*/ | ||||
| #ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT | ||||
| #define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue