xref: /openbmc/linux/arch/mips/bcm63xx/nvram.c (revision bc0868c62bb13834b20a864f684cced1f84a2412)
1e7e333cbSJonas Gorski /*
2e7e333cbSJonas Gorski  * This file is subject to the terms and conditions of the GNU General Public
3e7e333cbSJonas Gorski  * License.  See the file "COPYING" in the main directory of this archive
4e7e333cbSJonas Gorski  * for more details.
5e7e333cbSJonas Gorski  *
6e7e333cbSJonas Gorski  * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
7e7e333cbSJonas Gorski  * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org>
8e7e333cbSJonas Gorski  * Copyright (C) 2012 Jonas Gorski <jonas.gorski@gmail.com>
9e7e333cbSJonas Gorski  */
10e7e333cbSJonas Gorski 
11e7e333cbSJonas Gorski #define pr_fmt(fmt) "bcm63xx_nvram: " fmt
12e7e333cbSJonas Gorski 
135a8b0b13SSimon Arlott #include <linux/bcm963xx_nvram.h>
14e7e333cbSJonas Gorski #include <linux/init.h>
15ce8f0d06SJonas Gorski #include <linux/crc32.h>
16e7e333cbSJonas Gorski #include <linux/export.h>
17e7e333cbSJonas Gorski #include <linux/kernel.h>
18e7e333cbSJonas Gorski #include <linux/if_ether.h>
19e7e333cbSJonas Gorski 
20e7e333cbSJonas Gorski #include <bcm63xx_nvram.h>
21e7e333cbSJonas Gorski 
22*b0a119fdSRalf Baechle #define BCM63XX_DEFAULT_PSI_SIZE	64
23*b0a119fdSRalf Baechle 
24e7e333cbSJonas Gorski static struct bcm963xx_nvram nvram;
25e7e333cbSJonas Gorski static int mac_addr_used;
26e7e333cbSJonas Gorski 
bcm63xx_nvram_init(void * addr)2797367519SJonas Gorski void __init bcm63xx_nvram_init(void *addr)
28e7e333cbSJonas Gorski {
29ce8f0d06SJonas Gorski 	u32 crc, expected_crc;
300680dc86SFlorian Fainelli 	u8 hcs_mac_addr[ETH_ALEN] = { 0x00, 0x10, 0x18, 0xff, 0xff, 0xff };
31e7e333cbSJonas Gorski 
32e7e333cbSJonas Gorski 	/* extract nvram data */
335a8b0b13SSimon Arlott 	memcpy(&nvram, addr, BCM963XX_NVRAM_V5_SIZE);
34e7e333cbSJonas Gorski 
35e7e333cbSJonas Gorski 	/* check checksum before using data */
365a8b0b13SSimon Arlott 	if (bcm963xx_nvram_checksum(&nvram, &expected_crc, &crc))
3797367519SJonas Gorski 		pr_warn("nvram checksum failed, contents may be invalid (expected %08x, got %08x)\n",
3897367519SJonas Gorski 			expected_crc, crc);
390680dc86SFlorian Fainelli 
400680dc86SFlorian Fainelli 	/* Cable modems have a different NVRAM which is embedded in the eCos
410680dc86SFlorian Fainelli 	 * firmware and not easily extractible, give at least a MAC address
420680dc86SFlorian Fainelli 	 * pool.
430680dc86SFlorian Fainelli 	 */
440680dc86SFlorian Fainelli 	if (BCMCPU_IS_3368()) {
450680dc86SFlorian Fainelli 		memcpy(nvram.mac_addr_base, hcs_mac_addr, ETH_ALEN);
460680dc86SFlorian Fainelli 		nvram.mac_addr_count = 2;
470680dc86SFlorian Fainelli 	}
48e7e333cbSJonas Gorski }
49e7e333cbSJonas Gorski 
bcm63xx_nvram_get_name(void)50e7e333cbSJonas Gorski u8 *bcm63xx_nvram_get_name(void)
51e7e333cbSJonas Gorski {
52e7e333cbSJonas Gorski 	return nvram.name;
53e7e333cbSJonas Gorski }
54e7e333cbSJonas Gorski EXPORT_SYMBOL(bcm63xx_nvram_get_name);
55e7e333cbSJonas Gorski 
bcm63xx_nvram_get_mac_address(u8 * mac)56e7e333cbSJonas Gorski int bcm63xx_nvram_get_mac_address(u8 *mac)
57e7e333cbSJonas Gorski {
58e7e333cbSJonas Gorski 	u8 *oui;
59e7e333cbSJonas Gorski 	int count;
60e7e333cbSJonas Gorski 
61e7e333cbSJonas Gorski 	if (mac_addr_used >= nvram.mac_addr_count) {
62e7e333cbSJonas Gorski 		pr_err("not enough mac addresses\n");
63e7e333cbSJonas Gorski 		return -ENODEV;
64e7e333cbSJonas Gorski 	}
65e7e333cbSJonas Gorski 
66e7e333cbSJonas Gorski 	memcpy(mac, nvram.mac_addr_base, ETH_ALEN);
67e7e333cbSJonas Gorski 	oui = mac + ETH_ALEN/2 - 1;
68e7e333cbSJonas Gorski 	count = mac_addr_used;
69e7e333cbSJonas Gorski 
70e7e333cbSJonas Gorski 	while (count--) {
71e7e333cbSJonas Gorski 		u8 *p = mac + ETH_ALEN - 1;
72e7e333cbSJonas Gorski 
73e7e333cbSJonas Gorski 		do {
74e7e333cbSJonas Gorski 			(*p)++;
75e7e333cbSJonas Gorski 			if (*p != 0)
76e7e333cbSJonas Gorski 				break;
77e7e333cbSJonas Gorski 			p--;
78e7e333cbSJonas Gorski 		} while (p != oui);
79e7e333cbSJonas Gorski 
80e7e333cbSJonas Gorski 		if (p == oui) {
81e7e333cbSJonas Gorski 			pr_err("unable to fetch mac address\n");
82e7e333cbSJonas Gorski 			return -ENODEV;
83e7e333cbSJonas Gorski 		}
84e7e333cbSJonas Gorski 	}
85e7e333cbSJonas Gorski 
86e7e333cbSJonas Gorski 	mac_addr_used++;
87e7e333cbSJonas Gorski 	return 0;
88e7e333cbSJonas Gorski }
89e7e333cbSJonas Gorski EXPORT_SYMBOL(bcm63xx_nvram_get_mac_address);
90*b0a119fdSRalf Baechle 
bcm63xx_nvram_get_psi_size(void)91*b0a119fdSRalf Baechle int bcm63xx_nvram_get_psi_size(void)
92*b0a119fdSRalf Baechle {
93*b0a119fdSRalf Baechle 	if (nvram.psi_size > 0)
94*b0a119fdSRalf Baechle 		return nvram.psi_size;
95*b0a119fdSRalf Baechle 
96*b0a119fdSRalf Baechle 	return BCM63XX_DEFAULT_PSI_SIZE;
97*b0a119fdSRalf Baechle }
98*b0a119fdSRalf Baechle EXPORT_SYMBOL(bcm63xx_nvram_get_psi_size);
99