1*9a163ed8SThomas Gleixner /* 2*9a163ed8SThomas Gleixner * Implement 'Simple Boot Flag Specification 2.0' 3*9a163ed8SThomas Gleixner */ 4*9a163ed8SThomas Gleixner 5*9a163ed8SThomas Gleixner 6*9a163ed8SThomas Gleixner #include <linux/types.h> 7*9a163ed8SThomas Gleixner #include <linux/kernel.h> 8*9a163ed8SThomas Gleixner #include <linux/init.h> 9*9a163ed8SThomas Gleixner #include <linux/string.h> 10*9a163ed8SThomas Gleixner #include <linux/slab.h> 11*9a163ed8SThomas Gleixner #include <linux/spinlock.h> 12*9a163ed8SThomas Gleixner #include <linux/acpi.h> 13*9a163ed8SThomas Gleixner #include <asm/io.h> 14*9a163ed8SThomas Gleixner 15*9a163ed8SThomas Gleixner #include <linux/mc146818rtc.h> 16*9a163ed8SThomas Gleixner 17*9a163ed8SThomas Gleixner 18*9a163ed8SThomas Gleixner #define SBF_RESERVED (0x78) 19*9a163ed8SThomas Gleixner #define SBF_PNPOS (1<<0) 20*9a163ed8SThomas Gleixner #define SBF_BOOTING (1<<1) 21*9a163ed8SThomas Gleixner #define SBF_DIAG (1<<2) 22*9a163ed8SThomas Gleixner #define SBF_PARITY (1<<7) 23*9a163ed8SThomas Gleixner 24*9a163ed8SThomas Gleixner 25*9a163ed8SThomas Gleixner int sbf_port __initdata = -1; /* set via acpi_boot_init() */ 26*9a163ed8SThomas Gleixner 27*9a163ed8SThomas Gleixner 28*9a163ed8SThomas Gleixner static int __init parity(u8 v) 29*9a163ed8SThomas Gleixner { 30*9a163ed8SThomas Gleixner int x = 0; 31*9a163ed8SThomas Gleixner int i; 32*9a163ed8SThomas Gleixner 33*9a163ed8SThomas Gleixner for(i=0;i<8;i++) 34*9a163ed8SThomas Gleixner { 35*9a163ed8SThomas Gleixner x^=(v&1); 36*9a163ed8SThomas Gleixner v>>=1; 37*9a163ed8SThomas Gleixner } 38*9a163ed8SThomas Gleixner return x; 39*9a163ed8SThomas Gleixner } 40*9a163ed8SThomas Gleixner 41*9a163ed8SThomas Gleixner static void __init sbf_write(u8 v) 42*9a163ed8SThomas Gleixner { 43*9a163ed8SThomas Gleixner unsigned long flags; 44*9a163ed8SThomas Gleixner if(sbf_port != -1) 45*9a163ed8SThomas Gleixner { 46*9a163ed8SThomas Gleixner v &= ~SBF_PARITY; 47*9a163ed8SThomas Gleixner if(!parity(v)) 48*9a163ed8SThomas Gleixner v|=SBF_PARITY; 49*9a163ed8SThomas Gleixner 50*9a163ed8SThomas Gleixner printk(KERN_INFO "Simple Boot Flag at 0x%x set to 0x%x\n", sbf_port, v); 51*9a163ed8SThomas Gleixner 52*9a163ed8SThomas Gleixner spin_lock_irqsave(&rtc_lock, flags); 53*9a163ed8SThomas Gleixner CMOS_WRITE(v, sbf_port); 54*9a163ed8SThomas Gleixner spin_unlock_irqrestore(&rtc_lock, flags); 55*9a163ed8SThomas Gleixner } 56*9a163ed8SThomas Gleixner } 57*9a163ed8SThomas Gleixner 58*9a163ed8SThomas Gleixner static u8 __init sbf_read(void) 59*9a163ed8SThomas Gleixner { 60*9a163ed8SThomas Gleixner u8 v; 61*9a163ed8SThomas Gleixner unsigned long flags; 62*9a163ed8SThomas Gleixner if(sbf_port == -1) 63*9a163ed8SThomas Gleixner return 0; 64*9a163ed8SThomas Gleixner spin_lock_irqsave(&rtc_lock, flags); 65*9a163ed8SThomas Gleixner v = CMOS_READ(sbf_port); 66*9a163ed8SThomas Gleixner spin_unlock_irqrestore(&rtc_lock, flags); 67*9a163ed8SThomas Gleixner return v; 68*9a163ed8SThomas Gleixner } 69*9a163ed8SThomas Gleixner 70*9a163ed8SThomas Gleixner static int __init sbf_value_valid(u8 v) 71*9a163ed8SThomas Gleixner { 72*9a163ed8SThomas Gleixner if(v&SBF_RESERVED) /* Reserved bits */ 73*9a163ed8SThomas Gleixner return 0; 74*9a163ed8SThomas Gleixner if(!parity(v)) 75*9a163ed8SThomas Gleixner return 0; 76*9a163ed8SThomas Gleixner return 1; 77*9a163ed8SThomas Gleixner } 78*9a163ed8SThomas Gleixner 79*9a163ed8SThomas Gleixner static int __init sbf_init(void) 80*9a163ed8SThomas Gleixner { 81*9a163ed8SThomas Gleixner u8 v; 82*9a163ed8SThomas Gleixner if(sbf_port == -1) 83*9a163ed8SThomas Gleixner return 0; 84*9a163ed8SThomas Gleixner v = sbf_read(); 85*9a163ed8SThomas Gleixner if(!sbf_value_valid(v)) 86*9a163ed8SThomas Gleixner printk(KERN_WARNING "Simple Boot Flag value 0x%x read from CMOS RAM was invalid\n",v); 87*9a163ed8SThomas Gleixner 88*9a163ed8SThomas Gleixner v &= ~SBF_RESERVED; 89*9a163ed8SThomas Gleixner v &= ~SBF_BOOTING; 90*9a163ed8SThomas Gleixner v &= ~SBF_DIAG; 91*9a163ed8SThomas Gleixner #if defined(CONFIG_ISAPNP) 92*9a163ed8SThomas Gleixner v |= SBF_PNPOS; 93*9a163ed8SThomas Gleixner #endif 94*9a163ed8SThomas Gleixner sbf_write(v); 95*9a163ed8SThomas Gleixner return 0; 96*9a163ed8SThomas Gleixner } 97*9a163ed8SThomas Gleixner 98*9a163ed8SThomas Gleixner module_init(sbf_init); 99