1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 29a163ed8SThomas Gleixner /* 39a163ed8SThomas Gleixner * Implement 'Simple Boot Flag Specification 2.0' 49a163ed8SThomas Gleixner */ 59a163ed8SThomas Gleixner #include <linux/types.h> 69a163ed8SThomas Gleixner #include <linux/kernel.h> 79a163ed8SThomas Gleixner #include <linux/init.h> 89a163ed8SThomas Gleixner #include <linux/string.h> 99a163ed8SThomas Gleixner #include <linux/spinlock.h> 109a163ed8SThomas Gleixner #include <linux/acpi.h> 119a163ed8SThomas Gleixner #include <asm/io.h> 129a163ed8SThomas Gleixner 139a163ed8SThomas Gleixner #include <linux/mc146818rtc.h> 149a163ed8SThomas Gleixner 159a163ed8SThomas Gleixner #define SBF_RESERVED (0x78) 169a163ed8SThomas Gleixner #define SBF_PNPOS (1<<0) 179a163ed8SThomas Gleixner #define SBF_BOOTING (1<<1) 189a163ed8SThomas Gleixner #define SBF_DIAG (1<<2) 199a163ed8SThomas Gleixner #define SBF_PARITY (1<<7) 209a163ed8SThomas Gleixner 219a163ed8SThomas Gleixner int sbf_port __initdata = -1; /* set via acpi_boot_init() */ 229a163ed8SThomas Gleixner parity(u8 v)239a163ed8SThomas Gleixnerstatic int __init parity(u8 v) 249a163ed8SThomas Gleixner { 259a163ed8SThomas Gleixner int x = 0; 269a163ed8SThomas Gleixner int i; 279a163ed8SThomas Gleixner 288eed9260SCyrill Gorcunov for (i = 0; i < 8; i++) { 299a163ed8SThomas Gleixner x ^= (v & 1); 309a163ed8SThomas Gleixner v >>= 1; 319a163ed8SThomas Gleixner } 328eed9260SCyrill Gorcunov 339a163ed8SThomas Gleixner return x; 349a163ed8SThomas Gleixner } 359a163ed8SThomas Gleixner sbf_write(u8 v)369a163ed8SThomas Gleixnerstatic void __init sbf_write(u8 v) 379a163ed8SThomas Gleixner { 389a163ed8SThomas Gleixner unsigned long flags; 398eed9260SCyrill Gorcunov 408eed9260SCyrill Gorcunov if (sbf_port != -1) { 419a163ed8SThomas Gleixner v &= ~SBF_PARITY; 429a163ed8SThomas Gleixner if (!parity(v)) 439a163ed8SThomas Gleixner v |= SBF_PARITY; 449a163ed8SThomas Gleixner 458eed9260SCyrill Gorcunov printk(KERN_INFO "Simple Boot Flag at 0x%x set to 0x%x\n", 468eed9260SCyrill Gorcunov sbf_port, v); 479a163ed8SThomas Gleixner 489a163ed8SThomas Gleixner spin_lock_irqsave(&rtc_lock, flags); 499a163ed8SThomas Gleixner CMOS_WRITE(v, sbf_port); 509a163ed8SThomas Gleixner spin_unlock_irqrestore(&rtc_lock, flags); 519a163ed8SThomas Gleixner } 529a163ed8SThomas Gleixner } 539a163ed8SThomas Gleixner sbf_read(void)549a163ed8SThomas Gleixnerstatic u8 __init sbf_read(void) 559a163ed8SThomas Gleixner { 569a163ed8SThomas Gleixner unsigned long flags; 578eed9260SCyrill Gorcunov u8 v; 588eed9260SCyrill Gorcunov 599a163ed8SThomas Gleixner if (sbf_port == -1) 609a163ed8SThomas Gleixner return 0; 618eed9260SCyrill Gorcunov 629a163ed8SThomas Gleixner spin_lock_irqsave(&rtc_lock, flags); 639a163ed8SThomas Gleixner v = CMOS_READ(sbf_port); 649a163ed8SThomas Gleixner spin_unlock_irqrestore(&rtc_lock, flags); 658eed9260SCyrill Gorcunov 669a163ed8SThomas Gleixner return v; 679a163ed8SThomas Gleixner } 689a163ed8SThomas Gleixner sbf_value_valid(u8 v)699a163ed8SThomas Gleixnerstatic int __init sbf_value_valid(u8 v) 709a163ed8SThomas Gleixner { 719a163ed8SThomas Gleixner if (v & SBF_RESERVED) /* Reserved bits */ 729a163ed8SThomas Gleixner return 0; 739a163ed8SThomas Gleixner if (!parity(v)) 749a163ed8SThomas Gleixner return 0; 758eed9260SCyrill Gorcunov 769a163ed8SThomas Gleixner return 1; 779a163ed8SThomas Gleixner } 789a163ed8SThomas Gleixner sbf_init(void)799a163ed8SThomas Gleixnerstatic int __init sbf_init(void) 809a163ed8SThomas Gleixner { 819a163ed8SThomas Gleixner u8 v; 828eed9260SCyrill Gorcunov 839a163ed8SThomas Gleixner if (sbf_port == -1) 849a163ed8SThomas Gleixner return 0; 858eed9260SCyrill Gorcunov 869a163ed8SThomas Gleixner v = sbf_read(); 878eed9260SCyrill Gorcunov if (!sbf_value_valid(v)) { 888eed9260SCyrill Gorcunov printk(KERN_WARNING "Simple Boot Flag value 0x%x read from " 898eed9260SCyrill Gorcunov "CMOS RAM was invalid\n", v); 908eed9260SCyrill Gorcunov } 919a163ed8SThomas Gleixner 929a163ed8SThomas Gleixner v &= ~SBF_RESERVED; 939a163ed8SThomas Gleixner v &= ~SBF_BOOTING; 949a163ed8SThomas Gleixner v &= ~SBF_DIAG; 959a163ed8SThomas Gleixner #if defined(CONFIG_ISAPNP) 969a163ed8SThomas Gleixner v |= SBF_PNPOS; 979a163ed8SThomas Gleixner #endif 989a163ed8SThomas Gleixner sbf_write(v); 998eed9260SCyrill Gorcunov 1009a163ed8SThomas Gleixner return 0; 1019a163ed8SThomas Gleixner } 1021206f535SPaul Gortmaker arch_initcall(sbf_init); 103