2 * BCM947xx nvram variable access
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>
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.
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>
22 #include <linux/bcm47xx_nvram.h>
24 #define NVRAM_HEADER 0x48534C46 /* 'FLSH' */
25 #define NVRAM_SPACE 0x8000
27 #define FLASH_MIN 0x00020000 /* Minimum flash size */
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 */
37 struct bcm47xx_nvram
{
42 static const u32 nvram_sizes
[] = {0x8000, 0xF000, 0x10000};
44 static u32
find_nvram_size(void __iomem
*end
)
46 struct nvram_header __iomem
*header
;
49 for (i
= 0; i
< ARRAY_SIZE(nvram_sizes
); i
++) {
50 header
= (struct nvram_header __iomem
*)(end
- nvram_sizes
[i
]);
51 if (__raw_readl(&header
->magic
) == NVRAM_HEADER
)
52 return nvram_sizes
[i
];
58 /* Probe for NVRAM header */
59 static int nvram_find_and_copy(struct device
*dev
, void __iomem
*base
,
60 size_t len
, char **nvram_buf
,
63 struct nvram_header __iomem
*header
;
70 /* TODO: when nvram is on nand flash check for bad blocks first. */
73 /* Windowed flash access */
74 size
= find_nvram_size(base
+ off
);
76 header
= (struct nvram_header __iomem
*)
83 /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
84 header
= (struct nvram_header __iomem
*)(base
+ 4096);
85 if (__raw_readl(&header
->magic
) == NVRAM_HEADER
) {
90 header
= (struct nvram_header __iomem
*)(base
+ 1024);
91 if (__raw_readl(&header
->magic
) == NVRAM_HEADER
) {
98 pr_err("no nvram found\n");
102 if (readl(&header
->len
) > size
)
103 pr_err("The nvram size accoridng to the header seems to be bigger than the partition on flash\n");
104 *nvram_len
= min_t(u32
, readl(&header
->len
), size
);
106 *nvram_buf
= devm_kzalloc(dev
, *nvram_len
, GFP_KERNEL
);
110 src
= (__le32 __iomem
*) header
;
111 dst
= (u32
*) *nvram_buf
;
112 for (i
= 0; i
< sizeof(struct nvram_header
); i
+= 4)
113 *dst
++ = __raw_readl(src
++);
114 for (; i
< *nvram_len
; i
+= 4)
115 *dst
++ = readl(src
++);
120 int bcm47xx_nvram_getenv(const struct device
*dev
, const char *name
, char *val
,
123 char *var
, *value
, *end
, *eq
;
124 struct bcm47xx_nvram
*nvram
;
129 nvram
= dev_get_drvdata(dev
);
131 if (!name
|| !nvram
|| !nvram
->nvram_len
)
134 /* Look for name=value and return value */
135 var
= nvram
->nvram_buf
+ sizeof(struct nvram_header
);
136 end
= nvram
->nvram_buf
+ nvram
->nvram_len
- 2;
137 end
[0] = end
[1] = '\0';
138 for (; *var
; var
= value
+ strlen(value
) + 1) {
139 eq
= strchr(var
, '=');
143 if ((eq
- var
) == strlen(name
) &&
144 strncmp(var
, name
, (eq
- var
)) == 0) {
145 return snprintf(val
, val_len
, "%s", value
);
150 EXPORT_SYMBOL(bcm47xx_nvram_getenv
);
152 int bcm47xx_nvram_gpio_pin(const struct device
*dev
, const char *name
)
161 for (i
= 0; i
< 32; i
++) {
162 err
= snprintf(nvram_var
, sizeof(nvram_var
), "gpio%i", i
);
165 err
= bcm47xx_nvram_getenv(dev
, nvram_var
, buf
, sizeof(buf
));
168 if (!strcmp(name
, buf
))
173 EXPORT_SYMBOL(bcm47xx_nvram_gpio_pin
);
175 static int bcm47xx_nvram_probe(struct platform_device
*pdev
)
177 struct device
*dev
= &pdev
->dev
;
178 struct device_node
*np
= dev
->of_node
;
179 struct bcm47xx_nvram
*nvram
;
181 struct resource flash_mem
;
185 nvram
= devm_kzalloc(dev
, sizeof(*nvram
), GFP_KERNEL
);
189 err
= of_address_to_resource(np
, 0, &flash_mem
);
193 mmio
= ioremap_nocache(flash_mem
.start
, resource_size(&flash_mem
));
197 err
= nvram_find_and_copy(dev
, mmio
, resource_size(&flash_mem
),
198 &nvram
->nvram_buf
, &nvram
->nvram_len
);
202 platform_set_drvdata(pdev
, nvram
);
209 static const struct of_device_id bcm47xx_nvram_of_match_table
[] = {
210 { .compatible
= "brcm,bcm47xx-nvram", },
213 MODULE_DEVICE_TABLE(of
, mvebu_pcie_of_match_table
);
215 static struct platform_driver bcm47xx_nvram_driver
= {
217 .owner
= THIS_MODULE
,
218 .name
= "bcm47xx-nvram",
219 .of_match_table
= bcm47xx_nvram_of_match_table
,
220 /* driver unloading/unbinding currently not supported */
221 .suppress_bind_attrs
= true,
223 .probe
= bcm47xx_nvram_probe
,
225 module_platform_driver(bcm47xx_nvram_driver
);
227 MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
228 MODULE_LICENSE("GPLv2");