162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * c 2001 PPC 64 Team, IBM Corp 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * /dev/nvram driver for PPC 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#include <linux/spinlock.h> 1262306a36Sopenharmony_ci#include <linux/uaccess.h> 1362306a36Sopenharmony_ci#include <linux/of.h> 1462306a36Sopenharmony_ci#include <asm/machdep.h> 1562306a36Sopenharmony_ci#include <asm/rtas.h> 1662306a36Sopenharmony_ci#include "chrp.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic unsigned int nvram_size; 1962306a36Sopenharmony_cistatic unsigned char nvram_buf[4]; 2062306a36Sopenharmony_cistatic DEFINE_SPINLOCK(nvram_lock); 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic unsigned char chrp_nvram_read_val(int addr) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci unsigned int done; 2562306a36Sopenharmony_ci unsigned long flags; 2662306a36Sopenharmony_ci unsigned char ret; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci if (addr >= nvram_size) { 2962306a36Sopenharmony_ci printk(KERN_DEBUG "%s: read addr %d > nvram_size %u\n", 3062306a36Sopenharmony_ci current->comm, addr, nvram_size); 3162306a36Sopenharmony_ci return 0xff; 3262306a36Sopenharmony_ci } 3362306a36Sopenharmony_ci spin_lock_irqsave(&nvram_lock, flags); 3462306a36Sopenharmony_ci if ((rtas_call(rtas_function_token(RTAS_FN_NVRAM_FETCH), 3, 2, &done, addr, 3562306a36Sopenharmony_ci __pa(nvram_buf), 1) != 0) || 1 != done) 3662306a36Sopenharmony_ci ret = 0xff; 3762306a36Sopenharmony_ci else 3862306a36Sopenharmony_ci ret = nvram_buf[0]; 3962306a36Sopenharmony_ci spin_unlock_irqrestore(&nvram_lock, flags); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci return ret; 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic void chrp_nvram_write_val(int addr, unsigned char val) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci unsigned int done; 4762306a36Sopenharmony_ci unsigned long flags; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if (addr >= nvram_size) { 5062306a36Sopenharmony_ci printk(KERN_DEBUG "%s: write addr %d > nvram_size %u\n", 5162306a36Sopenharmony_ci current->comm, addr, nvram_size); 5262306a36Sopenharmony_ci return; 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci spin_lock_irqsave(&nvram_lock, flags); 5562306a36Sopenharmony_ci nvram_buf[0] = val; 5662306a36Sopenharmony_ci if ((rtas_call(rtas_function_token(RTAS_FN_NVRAM_STORE), 3, 2, &done, addr, 5762306a36Sopenharmony_ci __pa(nvram_buf), 1) != 0) || 1 != done) 5862306a36Sopenharmony_ci printk(KERN_DEBUG "rtas IO error storing 0x%02x at %d", val, addr); 5962306a36Sopenharmony_ci spin_unlock_irqrestore(&nvram_lock, flags); 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic ssize_t chrp_nvram_size(void) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci return nvram_size; 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_civoid __init chrp_nvram_init(void) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci struct device_node *nvram; 7062306a36Sopenharmony_ci const __be32 *nbytes_p; 7162306a36Sopenharmony_ci unsigned int proplen; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci nvram = of_find_node_by_type(NULL, "nvram"); 7462306a36Sopenharmony_ci if (nvram == NULL) 7562306a36Sopenharmony_ci return; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci nbytes_p = of_get_property(nvram, "#bytes", &proplen); 7862306a36Sopenharmony_ci if (nbytes_p == NULL || proplen != sizeof(unsigned int)) { 7962306a36Sopenharmony_ci of_node_put(nvram); 8062306a36Sopenharmony_ci return; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci nvram_size = be32_to_cpup(nbytes_p); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci printk(KERN_INFO "CHRP nvram contains %u bytes\n", nvram_size); 8662306a36Sopenharmony_ci of_node_put(nvram); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci ppc_md.nvram_read_val = chrp_nvram_read_val; 8962306a36Sopenharmony_ci ppc_md.nvram_write_val = chrp_nvram_write_val; 9062306a36Sopenharmony_ci ppc_md.nvram_size = chrp_nvram_size; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci return; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 96