1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * memory mapped NVRAM
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * (C) Copyright IBM Corp. 2005
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Authors : Utz Bacher <utz.bacher@de.ibm.com>
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/fs.h>
11*4882a593Smuzhiyun #include <linux/init.h>
12*4882a593Smuzhiyun #include <linux/kernel.h>
13*4882a593Smuzhiyun #include <linux/spinlock.h>
14*4882a593Smuzhiyun #include <linux/types.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #include <asm/machdep.h>
17*4882a593Smuzhiyun #include <asm/nvram.h>
18*4882a593Smuzhiyun #include <asm/prom.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun static void __iomem *mmio_nvram_start;
21*4882a593Smuzhiyun static long mmio_nvram_len;
22*4882a593Smuzhiyun static DEFINE_SPINLOCK(mmio_nvram_lock);
23*4882a593Smuzhiyun
mmio_nvram_read(char * buf,size_t count,loff_t * index)24*4882a593Smuzhiyun static ssize_t mmio_nvram_read(char *buf, size_t count, loff_t *index)
25*4882a593Smuzhiyun {
26*4882a593Smuzhiyun unsigned long flags;
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun if (*index >= mmio_nvram_len)
29*4882a593Smuzhiyun return 0;
30*4882a593Smuzhiyun if (*index + count > mmio_nvram_len)
31*4882a593Smuzhiyun count = mmio_nvram_len - *index;
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun spin_lock_irqsave(&mmio_nvram_lock, flags);
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun memcpy_fromio(buf, mmio_nvram_start + *index, count);
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun spin_unlock_irqrestore(&mmio_nvram_lock, flags);
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun *index += count;
40*4882a593Smuzhiyun return count;
41*4882a593Smuzhiyun }
42*4882a593Smuzhiyun
mmio_nvram_read_val(int addr)43*4882a593Smuzhiyun static unsigned char mmio_nvram_read_val(int addr)
44*4882a593Smuzhiyun {
45*4882a593Smuzhiyun unsigned long flags;
46*4882a593Smuzhiyun unsigned char val;
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun if (addr >= mmio_nvram_len)
49*4882a593Smuzhiyun return 0xff;
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun spin_lock_irqsave(&mmio_nvram_lock, flags);
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun val = ioread8(mmio_nvram_start + addr);
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun spin_unlock_irqrestore(&mmio_nvram_lock, flags);
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun return val;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun
mmio_nvram_write(char * buf,size_t count,loff_t * index)60*4882a593Smuzhiyun static ssize_t mmio_nvram_write(char *buf, size_t count, loff_t *index)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun unsigned long flags;
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun if (*index >= mmio_nvram_len)
65*4882a593Smuzhiyun return 0;
66*4882a593Smuzhiyun if (*index + count > mmio_nvram_len)
67*4882a593Smuzhiyun count = mmio_nvram_len - *index;
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun spin_lock_irqsave(&mmio_nvram_lock, flags);
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun memcpy_toio(mmio_nvram_start + *index, buf, count);
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun spin_unlock_irqrestore(&mmio_nvram_lock, flags);
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun *index += count;
76*4882a593Smuzhiyun return count;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun
mmio_nvram_write_val(int addr,unsigned char val)79*4882a593Smuzhiyun static void mmio_nvram_write_val(int addr, unsigned char val)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun unsigned long flags;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun if (addr < mmio_nvram_len) {
84*4882a593Smuzhiyun spin_lock_irqsave(&mmio_nvram_lock, flags);
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun iowrite8(val, mmio_nvram_start + addr);
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun spin_unlock_irqrestore(&mmio_nvram_lock, flags);
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
mmio_nvram_get_size(void)92*4882a593Smuzhiyun static ssize_t mmio_nvram_get_size(void)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun return mmio_nvram_len;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
mmio_nvram_init(void)97*4882a593Smuzhiyun int __init mmio_nvram_init(void)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun struct device_node *nvram_node;
100*4882a593Smuzhiyun unsigned long nvram_addr;
101*4882a593Smuzhiyun struct resource r;
102*4882a593Smuzhiyun int ret;
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun nvram_node = of_find_node_by_type(NULL, "nvram");
105*4882a593Smuzhiyun if (!nvram_node)
106*4882a593Smuzhiyun nvram_node = of_find_compatible_node(NULL, NULL, "nvram");
107*4882a593Smuzhiyun if (!nvram_node) {
108*4882a593Smuzhiyun printk(KERN_WARNING "nvram: no node found in device-tree\n");
109*4882a593Smuzhiyun return -ENODEV;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun ret = of_address_to_resource(nvram_node, 0, &r);
113*4882a593Smuzhiyun if (ret) {
114*4882a593Smuzhiyun printk(KERN_WARNING "nvram: failed to get address (err %d)\n",
115*4882a593Smuzhiyun ret);
116*4882a593Smuzhiyun goto out;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun nvram_addr = r.start;
119*4882a593Smuzhiyun mmio_nvram_len = resource_size(&r);
120*4882a593Smuzhiyun if ( (!mmio_nvram_len) || (!nvram_addr) ) {
121*4882a593Smuzhiyun printk(KERN_WARNING "nvram: address or length is 0\n");
122*4882a593Smuzhiyun ret = -EIO;
123*4882a593Smuzhiyun goto out;
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun mmio_nvram_start = ioremap(nvram_addr, mmio_nvram_len);
127*4882a593Smuzhiyun if (!mmio_nvram_start) {
128*4882a593Smuzhiyun printk(KERN_WARNING "nvram: failed to ioremap\n");
129*4882a593Smuzhiyun ret = -ENOMEM;
130*4882a593Smuzhiyun goto out;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun printk(KERN_INFO "mmio NVRAM, %luk at 0x%lx mapped to %p\n",
134*4882a593Smuzhiyun mmio_nvram_len >> 10, nvram_addr, mmio_nvram_start);
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun ppc_md.nvram_read_val = mmio_nvram_read_val;
137*4882a593Smuzhiyun ppc_md.nvram_write_val = mmio_nvram_write_val;
138*4882a593Smuzhiyun ppc_md.nvram_read = mmio_nvram_read;
139*4882a593Smuzhiyun ppc_md.nvram_write = mmio_nvram_write;
140*4882a593Smuzhiyun ppc_md.nvram_size = mmio_nvram_get_size;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun out:
143*4882a593Smuzhiyun of_node_put(nvram_node);
144*4882a593Smuzhiyun return ret;
145*4882a593Smuzhiyun }
146