blob: a4f1dab469f3e10e822a1323e4e6337bcab488db [file] [log] [blame]
Marek BehĂșn7ca07fc2024-06-18 17:34:31 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2024 Marek BehĂșn <kabel@kernel.org>
4 */
5
6#include <asm/unaligned.h>
7#include <ctype.h>
8#include <linux/compiler.h>
9#include <linux/kernel.h>
10#include <eeprom_field.h>
11#include <eeprom_layout.h>
12#include <u-boot/crc.h>
13
14#define _DEF_FIELD(_n, _s, _t) \
15 { _n, _s, NULL, eeprom_field_print_ ## _t, eeprom_field_update_ ## _t }
16
17static void eeprom_field_print_ramsz(const struct eeprom_field *field)
18{
19 printf(PRINT_FIELD_SEGMENT, field->name);
20 printf("%u\n", get_unaligned_le32(field->buf));
21}
22
23static int eeprom_field_update_ramsz(struct eeprom_field *field, char *value)
24{
25 u32 sz;
26
27 if (value[0] == '1' || value[0] == '2' || value[0] == '4')
28 sz = value[0] - '0';
29 else
30 return -1;
31
32 if (value[1] != '\0')
33 return -1;
34
35 put_unaligned_le32(sz, field->buf);
36
37 return 0;
38}
39
40static void eeprom_field_print_region(const struct eeprom_field *field)
41{
42 eeprom_field_print_ascii(field);
43}
44
45static int eeprom_field_update_region(struct eeprom_field *field, char *value)
46{
47 if (strlen(value) != 2) {
48 printf("%s: has to be 2 characters\n", field->name);
49 return -1;
50 }
51
52 memcpy(field->buf, value, 2);
53 memset(&field->buf[2], '\0', 2);
54
55 return 0;
56}
57
58static struct eeprom_field omnia_layout[] = {
59 _DEF_FIELD("Magic constant", 4, bin),
60 _DEF_FIELD("RAM size in GB", 4, ramsz),
61 _DEF_FIELD("Wi-Fi Region", 4, region),
62 _DEF_FIELD("CRC32 checksum", 4, bin),
63};
64
65static struct eeprom_field *crc_field = &omnia_layout[3];
66
67static int omnia_update_field(struct eeprom_layout *layout, char *field_name,
68 char *new_data)
69{
70 struct eeprom_field *field;
71 int err;
72
73 if (!new_data)
74 return 0;
75
76 if (!field_name)
77 return -1;
78
79 field = eeprom_layout_find_field(layout, field_name, true);
80 if (!field)
81 return -1;
82
83 err = field->update(field, new_data);
84 if (err) {
85 printf("Invalid data for field %s\n", field_name);
86 return err;
87 }
88
89 if (field < crc_field) {
90 u32 crc = crc32(0, layout->data, 12);
91 put_unaligned_le32(crc, crc_field->buf);
92 }
93
94 return 0;
95}
96
97void eeprom_layout_assign(struct eeprom_layout *layout, int)
98{
99 layout->fields = omnia_layout;
100 layout->num_of_fields = ARRAY_SIZE(omnia_layout);
101 layout->update = omnia_update_field;
102 layout->data_size = 16;
103}
104
105int eeprom_layout_detect(unsigned char *)
106{
107 /* Turris Omnia has only one version of EEPROM layout */
108 return 0;
109}