1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2017 Marek Behún <kabel@kernel.org>
4  * Copyright (C) 2016 Tomas Hlavacek <tomas.hlavacek@nic.cz>
5  */
6 
7 #include <env.h>
8 #include <net.h>
9 #include <dm/device.h>
10 #include <dm/uclass.h>
11 #include <atsha204a-i2c.h>
12 
13 #include "turris_atsha_otp.h"
14 #include "turris_common.h"
15 
16 #define TURRIS_ATSHA_OTP_VERSION	0
17 #define TURRIS_ATSHA_OTP_SERIAL		1
18 #define TURRIS_ATSHA_OTP_MAC0		3
19 #define TURRIS_ATSHA_OTP_MAC1		4
20 
21 extern U_BOOT_DRIVER(atsha204);
22 
get_atsha204a_dev(void)23 static struct udevice *get_atsha204a_dev(void)
24 {
25 	/* Cannot be static because BSS does not have to be ready at this early stage */
26 	struct udevice *dev;
27 
28 	if (uclass_get_device_by_driver(UCLASS_MISC, DM_DRIVER_GET(atsha204), &dev)) {
29 		puts("Cannot find ATSHA204A on I2C bus!\n");
30 		dev = NULL;
31 	}
32 
33 	return dev;
34 }
35 
turris_atsha_otp_init_mac_addresses(int first_idx)36 int turris_atsha_otp_init_mac_addresses(int first_idx)
37 {
38 	struct udevice *dev = get_atsha204a_dev();
39 	u8 mac0[4], mac1[4], mac[6];
40 	int ret;
41 
42 	if (!dev)
43 		return -1;
44 
45 	ret = atsha204a_wakeup(dev);
46 	if (ret)
47 		return ret;
48 
49 	ret = atsha204a_read(dev, ATSHA204A_ZONE_OTP, false,
50 			     TURRIS_ATSHA_OTP_MAC0, mac0);
51 	if (ret)
52 		return ret;
53 
54 	ret = atsha204a_read(dev, ATSHA204A_ZONE_OTP, false,
55 			     TURRIS_ATSHA_OTP_MAC1, mac1);
56 	if (ret)
57 		return ret;
58 
59 	atsha204a_sleep(dev);
60 
61 	mac[0] = mac0[1];
62 	mac[1] = mac0[2];
63 	mac[2] = mac0[3];
64 	mac[3] = mac1[1];
65 	mac[4] = mac1[2];
66 	mac[5] = mac1[3];
67 
68 	turris_init_mac_addresses(first_idx, mac);
69 
70 	return 0;
71 }
72 
turris_atsha_otp_init_serial_number(void)73 int turris_atsha_otp_init_serial_number(void)
74 {
75 	char serial[17];
76 	int ret;
77 
78 	ret = turris_atsha_otp_get_serial_number(serial);
79 	if (ret)
80 		return ret;
81 
82 	if (!env_get("serial#"))
83 		return -1;
84 
85 	return 0;
86 }
87 
turris_atsha_otp_get_serial_number(char serial[17])88 int turris_atsha_otp_get_serial_number(char serial[17])
89 {
90 	struct udevice *dev = get_atsha204a_dev();
91 	u32 version_num, serial_num;
92 	const char *serial_env;
93 	int ret;
94 
95 	if (!dev)
96 		return -1;
97 
98 	serial_env = env_get("serial#");
99 	if (serial_env && strlen(serial_env) == 16) {
100 		memcpy(serial, serial_env, 17);
101 		return 0;
102 	}
103 
104 	ret = atsha204a_wakeup(dev);
105 	if (ret)
106 		return ret;
107 
108 	ret = atsha204a_read(dev, ATSHA204A_ZONE_OTP, false,
109 			     TURRIS_ATSHA_OTP_VERSION,
110 			     (u8 *)&version_num);
111 	if (ret)
112 		return ret;
113 
114 	ret = atsha204a_read(dev, ATSHA204A_ZONE_OTP, false,
115 			     TURRIS_ATSHA_OTP_SERIAL,
116 			     (u8 *)&serial_num);
117 	if (ret)
118 		return ret;
119 
120 	atsha204a_sleep(dev);
121 
122 	sprintf(serial, "%08X%08X", be32_to_cpu(version_num), be32_to_cpu(serial_num));
123 	env_set("serial#", serial);
124 
125 	return 0;
126 }
127