bcm53xx: use bcma callback in SPROM driver to fill the SPROM
[openwrt.git] / target / linux / bcm53xx / files / drivers / misc / bcm47xx-nvram.c
1 /*
2  * BCM947xx nvram variable access
3  *
4  * Copyright (C) 2005 Broadcom Corporation
5  * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
6  * Copyright (C) 2010-2014 Hauke Mehrtens <hauke@hauke-m.de>
7  *
8  * This program is free software; you can redistribute  it and/or modify it
9  * under  the terms of  the GNU General  Public License as published by the
10  * Free Software Foundation;  either version 2 of the  License, or (at your
11  * option) any later version.
12  */
13
14 #include <linux/types.h>
15 #include <linux/module.h>
16 #include <linux/kernel.h>
17 #include <linux/string.h>
18 #include <linux/of_address.h>
19 #include <linux/device.h>
20 #include <linux/platform_device.h>
21 #include <linux/io.h>
22 #include <linux/bcm47xx_nvram.h>
23
24 #define NVRAM_HEADER            0x48534C46      /* 'FLSH' */
25 #define NVRAM_SPACE             0x8000
26
27 #define FLASH_MIN               0x00020000      /* Minimum flash size */
28
29 struct nvram_header {
30         u32 magic;
31         u32 len;
32         u32 crc_ver_init;       /* 0:7 crc, 8:15 ver, 16:31 sdram_init */
33         u32 config_refresh;     /* 0:15 sdram_config, 16:31 sdram_refresh */
34         u32 config_ncdl;        /* ncdl values for memc */
35 };
36
37 struct bcm47xx_nvram {
38         size_t nvram_len;
39         char *nvram_buf;
40 };
41
42 static struct bcm47xx_nvram *nvram = NULL;
43
44 static const u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000};
45
46 static u32 find_nvram_size(void __iomem *end)
47 {
48         struct nvram_header __iomem *header;
49         int i;
50
51         for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) {
52                 header = (struct nvram_header __iomem *)(end - nvram_sizes[i]);
53                 if (__raw_readl(&header->magic) == NVRAM_HEADER)
54                         return nvram_sizes[i];
55         }
56
57         return 0;
58 }
59
60 /* Probe for NVRAM header */
61 static int nvram_find_and_copy(struct device *dev, void __iomem *base,
62                                size_t len, char **nvram_buf,
63                                size_t *nvram_len)
64 {
65         struct nvram_header __iomem *header;
66         int i;
67         u32 off;
68         u32 *dst;
69         __le32 __iomem *src;
70         u32 size;
71
72         /* TODO: when nvram is on nand flash check for bad blocks first. */
73         off = FLASH_MIN;
74         while (off <= len) {
75                 /* Windowed flash access */
76                 size = find_nvram_size(base + off);
77                 if (size) {
78                         header = (struct nvram_header __iomem *)
79                                         (base + off - size);
80                         goto found;
81                 }
82                 off += 0x10000;
83         }
84
85         /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
86         header = (struct nvram_header __iomem *)(base + 4096);
87         if (__raw_readl(&header->magic) == NVRAM_HEADER) {
88                 size = NVRAM_SPACE;
89                 goto found;
90         }
91
92         header = (struct nvram_header __iomem *)(base + 1024);
93         if (__raw_readl(&header->magic) == NVRAM_HEADER) {
94                 size = NVRAM_SPACE;
95                 goto found;
96         }
97
98         *nvram_buf = NULL;
99         *nvram_len = 0;
100         pr_err("no nvram found\n");
101         return -ENXIO;
102
103 found:
104         if (readl(&header->len) > size)
105                 pr_err("The nvram size accoridng to the header seems to be bigger than the partition on flash\n");
106         *nvram_len = min_t(u32, readl(&header->len), size);
107
108         *nvram_buf = devm_kzalloc(dev, *nvram_len, GFP_KERNEL);
109         if (!*nvram_buf)
110                 return -ENOMEM;
111
112         src = (__le32 __iomem *) header;
113         dst = (u32 *) *nvram_buf;
114         for (i = 0; i < sizeof(struct nvram_header); i += 4)
115                 *dst++ = __raw_readl(src++);
116         for (; i < *nvram_len; i += 4)
117                 *dst++ = readl(src++);
118
119         return 0;
120 }
121
122 int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len)
123 {
124         char *var, *value, *end, *eq;
125
126         if (!name || !nvram || !nvram->nvram_len)
127                 return -EINVAL;
128
129         /* Look for name=value and return value */
130         var = nvram->nvram_buf + sizeof(struct nvram_header);
131         end = nvram->nvram_buf + nvram->nvram_len - 2;
132         end[0] = end[1] = '\0';
133         for (; *var; var = value + strlen(value) + 1) {
134                 eq = strchr(var, '=');
135                 if (!eq)
136                         break;
137                 value = eq + 1;
138                 if ((eq - var) == strlen(name) &&
139                         strncmp(var, name, (eq - var)) == 0) {
140                         return snprintf(val, val_len, "%s", value);
141                 }
142         }
143         return -ENOENT;
144 }
145 EXPORT_SYMBOL(bcm47xx_nvram_getenv);
146
147 int bcm47xx_nvram_gpio_pin(const char *name)
148 {
149         int i, err;
150         char nvram_var[10];
151         char buf[30];
152
153         for (i = 0; i < 32; i++) {
154                 err = snprintf(nvram_var, sizeof(nvram_var), "gpio%i", i);
155                 if (err <= 0)
156                         continue;
157                 err = bcm47xx_nvram_getenv(nvram_var, buf, sizeof(buf));
158                 if (err <= 0)
159                         continue;
160                 if (!strcmp(name, buf))
161                         return i;
162         }
163         return -ENOENT;
164 }
165 EXPORT_SYMBOL(bcm47xx_nvram_gpio_pin);
166
167 static int bcm47xx_nvram_probe(struct platform_device *pdev)
168 {
169         struct device *dev = &pdev->dev;
170         struct device_node *np = dev->of_node;
171         int err;
172         struct resource flash_mem;
173         void __iomem *mmio;
174
175         /* Alloc */
176         nvram = devm_kzalloc(dev, sizeof(*nvram), GFP_KERNEL);
177         if (!nvram)
178                 return -ENOMEM;
179
180         err = of_address_to_resource(np, 0, &flash_mem);
181         if (err)
182                 return err;
183
184         mmio = ioremap_nocache(flash_mem.start, resource_size(&flash_mem));
185         if (!mmio)
186                 return -ENOMEM;
187
188         err = nvram_find_and_copy(dev, mmio, resource_size(&flash_mem),
189                                   &nvram->nvram_buf, &nvram->nvram_len);
190         if (err)
191                 goto err_unmap_mmio;
192
193 err_unmap_mmio:
194         iounmap(mmio);
195         return err;
196 }
197
198 static const struct of_device_id bcm47xx_nvram_of_match_table[] = {
199         { .compatible = "brcm,bcm47xx-nvram", },
200         {},
201 };
202 MODULE_DEVICE_TABLE(of, mvebu_pcie_of_match_table);
203
204 static struct platform_driver bcm47xx_nvram_driver = {
205         .driver = {
206                 .owner = THIS_MODULE,
207                 .name = "bcm47xx-nvram",
208                 .of_match_table = bcm47xx_nvram_of_match_table,
209                 /* driver unloading/unbinding currently not supported */
210                 .suppress_bind_attrs = true,
211         },
212         .probe = bcm47xx_nvram_probe,
213 };
214 module_platform_driver(bcm47xx_nvram_driver);
215
216 MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
217 MODULE_LICENSE("GPLv2");