162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci.text
362306a36Sopenharmony_ci#include <linux/linkage.h>
462306a36Sopenharmony_ci#include <asm/segment.h>
562306a36Sopenharmony_ci#include <asm/page.h>
662306a36Sopenharmony_ci#include <asm/pgtable_32.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci	.macro writepost,value
962306a36Sopenharmony_ci		movb $0x34, %al
1062306a36Sopenharmony_ci		outb %al, $0x70
1162306a36Sopenharmony_ci		movb $\value, %al
1262306a36Sopenharmony_ci		outb %al, $0x71
1362306a36Sopenharmony_ci	.endm
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ciwakeup_start:
1662306a36Sopenharmony_ci	# OFW lands us here, running in protected mode, with a
1762306a36Sopenharmony_ci	# kernel-compatible GDT already setup.
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	# Clear any dangerous flags
2062306a36Sopenharmony_ci	pushl $0
2162306a36Sopenharmony_ci	popfl
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	writepost 0x31
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	# Set up %cr3
2662306a36Sopenharmony_ci	movl $initial_page_table - __PAGE_OFFSET, %eax
2762306a36Sopenharmony_ci	movl %eax, %cr3
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	movl saved_cr4, %eax
3062306a36Sopenharmony_ci	movl %eax, %cr4
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	movl saved_cr0, %eax
3362306a36Sopenharmony_ci	movl %eax, %cr0
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	# Control registers were modified, pipeline resync is needed
3662306a36Sopenharmony_ci	jmp 1f
3762306a36Sopenharmony_ci1:
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	movw    $__KERNEL_DS, %ax
4062306a36Sopenharmony_ci	movw    %ax, %ss
4162306a36Sopenharmony_ci	movw    %ax, %ds
4262306a36Sopenharmony_ci	movw    %ax, %es
4362306a36Sopenharmony_ci	movw    %ax, %fs
4462306a36Sopenharmony_ci	movw    %ax, %gs
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	lgdt    saved_gdt
4762306a36Sopenharmony_ci	lidt    saved_idt
4862306a36Sopenharmony_ci	lldt    saved_ldt
4962306a36Sopenharmony_ci	ljmp    $(__KERNEL_CS),$1f
5062306a36Sopenharmony_ci1:
5162306a36Sopenharmony_ci	movl    %cr3, %eax
5262306a36Sopenharmony_ci	movl    %eax, %cr3
5362306a36Sopenharmony_ci	wbinvd
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	# Go back to the return point
5662306a36Sopenharmony_ci	jmp ret_point
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cisave_registers:
5962306a36Sopenharmony_ci	sgdt  saved_gdt
6062306a36Sopenharmony_ci	sidt  saved_idt
6162306a36Sopenharmony_ci	sldt  saved_ldt
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	pushl %edx
6462306a36Sopenharmony_ci	movl %cr4, %edx
6562306a36Sopenharmony_ci	movl %edx, saved_cr4
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	movl %cr0, %edx
6862306a36Sopenharmony_ci	movl %edx, saved_cr0
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	popl %edx
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	movl %ebx, saved_context_ebx
7362306a36Sopenharmony_ci	movl %ebp, saved_context_ebp
7462306a36Sopenharmony_ci	movl %esi, saved_context_esi
7562306a36Sopenharmony_ci	movl %edi, saved_context_edi
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	pushfl
7862306a36Sopenharmony_ci	popl saved_context_eflags
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	RET
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cirestore_registers:
8362306a36Sopenharmony_ci	movl saved_context_ebp, %ebp
8462306a36Sopenharmony_ci	movl saved_context_ebx, %ebx
8562306a36Sopenharmony_ci	movl saved_context_esi, %esi
8662306a36Sopenharmony_ci	movl saved_context_edi, %edi
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	pushl saved_context_eflags
8962306a36Sopenharmony_ci	popfl
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	RET
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ciSYM_CODE_START(do_olpc_suspend_lowlevel)
9462306a36Sopenharmony_ci	call	save_processor_state
9562306a36Sopenharmony_ci	call	save_registers
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	# This is the stack context we want to remember
9862306a36Sopenharmony_ci	movl %esp, saved_context_esp
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	pushl	$3
10162306a36Sopenharmony_ci	call	xo1_do_sleep
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	jmp	wakeup_start
10462306a36Sopenharmony_ci	.p2align 4,,7
10562306a36Sopenharmony_ciret_point:
10662306a36Sopenharmony_ci	movl    saved_context_esp, %esp
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	writepost 0x32
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	call	restore_registers
11162306a36Sopenharmony_ci	call	restore_processor_state
11262306a36Sopenharmony_ci	RET
11362306a36Sopenharmony_ciSYM_CODE_END(do_olpc_suspend_lowlevel)
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci.data
11662306a36Sopenharmony_cisaved_gdt:             .long   0,0
11762306a36Sopenharmony_cisaved_idt:             .long   0,0
11862306a36Sopenharmony_cisaved_ldt:             .long   0
11962306a36Sopenharmony_cisaved_cr4:             .long   0
12062306a36Sopenharmony_cisaved_cr0:             .long   0
12162306a36Sopenharmony_cisaved_context_esp:     .long   0
12262306a36Sopenharmony_cisaved_context_edi:     .long   0
12362306a36Sopenharmony_cisaved_context_esi:     .long   0
12462306a36Sopenharmony_cisaved_context_ebx:     .long   0
12562306a36Sopenharmony_cisaved_context_ebp:     .long   0
12662306a36Sopenharmony_cisaved_context_eflags:  .long   0
127