blob: c2f4ddfbbe380fa0c51a818396aa450141d6b38b [file] [log] [blame]
Marek Vasut85cd3452021-07-03 20:38:26 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2021 Marek Vasut <marek.vasut+renesas@gmail.com>
4 */
5
6#include <common.h>
7#include <dm.h>
8#include <i2c_eeprom.h>
9#include <log.h>
10#include <sysinfo.h>
11
12#define BOARD_CODE_MASK 0xF8
13#define BOARD_REV_MASK 0x07
14#define BOARD_CODE_SHIFT 0x03
15
16#define BOARD_SALVATOR_X 0x0
17#define BOARD_KRIEK 0x1
18#define BOARD_STARTER_KIT 0x2
19#define BOARD_SALVATOR_XS 0x4
20#define BOARD_EBISU 0x8
21#define BOARD_STARTER_KIT_PRE 0xB
22#define BOARD_EBISU_4D 0xD
23#define BOARD_DRAAK 0xE
24#define BOARD_EAGLE 0xF
25
26/**
27 * struct sysinfo_rcar_priv - sysinfo private data
28 * @boardname: board model and revision
29 * @val: board ID value from eeprom
30 */
31struct sysinfo_rcar_priv {
32 char boardmodel[64];
33 u8 val;
34};
35
36static int sysinfo_rcar_detect(struct udevice *dev)
37{
38 struct sysinfo_rcar_priv *priv = dev_get_priv(dev);
39
40 return priv->val == 0xff;
41}
42
43static int sysinfo_rcar_get_str(struct udevice *dev, int id, size_t size, char *val)
44{
45 struct sysinfo_rcar_priv *priv = dev_get_priv(dev);
46
47 switch (id) {
48 case SYSINFO_ID_BOARD_MODEL:
49 strncpy(val, priv->boardmodel, size);
50 val[size - 1] = '\0';
51 return 0;
52 default:
53 return -EINVAL;
54 };
55}
56
57static const struct sysinfo_ops sysinfo_rcar_ops = {
58 .detect = sysinfo_rcar_detect,
59 .get_str = sysinfo_rcar_get_str,
60};
61
62static void sysinfo_rcar_parse(struct sysinfo_rcar_priv *priv)
63{
64 const u8 board_id = (priv->val & BOARD_CODE_MASK) >> BOARD_CODE_SHIFT;
65 const u8 board_rev = priv->val & BOARD_REV_MASK;
66 bool salvator_xs = false;
67 bool ebisu_4d = false;
68 char rev_major = '?';
69 char rev_minor = '?';
70
71 switch (board_id) {
72 case BOARD_SALVATOR_XS:
73 salvator_xs = true;
74 fallthrough;
75 case BOARD_SALVATOR_X:
76 if (!(board_rev & ~1)) { /* Only rev 0 and 1 is valid */
77 rev_major = '1';
78 rev_minor = '0' + (board_rev & BIT(0));
79 }
80 snprintf(priv->boardmodel, sizeof(priv->boardmodel),
81 "Renesas Salvator-X%s board rev %c.%c",
82 salvator_xs ? "S" : "", rev_major, rev_minor);
83 return;
84 case BOARD_STARTER_KIT:
85 if (!(board_rev & ~1)) { /* Only rev 0 and 1 is valid */
86 rev_major = (board_rev & BIT(0)) ? '3' : '1';
87 rev_minor = '0';
88 }
89 snprintf(priv->boardmodel, sizeof(priv->boardmodel),
90 "Renesas Starter Kit board rev %c.%c",
91 rev_major, rev_minor);
92 return;
93 case BOARD_STARTER_KIT_PRE:
94 if (!(board_rev & ~3)) { /* Only rev 0..3 is valid */
95 rev_major = (board_rev & BIT(1)) ? '2' : '1';
96 rev_minor = (board_rev == 3) ? '1' : '0';
97 }
98 snprintf(priv->boardmodel, sizeof(priv->boardmodel),
99 "Renesas Starter Kit Premier board rev %c.%c",
100 rev_major, rev_minor);
101 return;
102 case BOARD_EAGLE:
103 if (!board_rev) { /* Only rev 0 is valid */
104 rev_major = '1';
105 rev_minor = '0';
106 }
107 snprintf(priv->boardmodel, sizeof(priv->boardmodel),
108 "Renesas Eagle board rev %c.%c",
109 rev_major, rev_minor);
110 return;
111 case BOARD_EBISU_4D:
112 ebisu_4d = true;
113 fallthrough;
114 case BOARD_EBISU:
115 if (!board_rev) { /* Only rev 0 is valid */
116 rev_major = '1';
117 rev_minor = '0';
118 }
119 snprintf(priv->boardmodel, sizeof(priv->boardmodel),
120 "Renesas Ebisu%s board rev %c.%c",
121 ebisu_4d ? "-4D" : "", rev_major, rev_minor);
122 return;
123 case BOARD_DRAAK:
124 if (!board_rev) { /* Only rev 0 is valid */
125 rev_major = '1';
126 rev_minor = '0';
127 }
128 snprintf(priv->boardmodel, sizeof(priv->boardmodel),
129 "Renesas Draak board rev %c.%c",
130 rev_major, rev_minor);
131 return;
132 case BOARD_KRIEK:
133 if (!board_rev) { /* Only rev 0 is valid */
134 rev_major = '1';
135 rev_minor = '0';
136 }
137 snprintf(priv->boardmodel, sizeof(priv->boardmodel),
138 "Renesas Kriek board rev %c.%c",
139 rev_major, rev_minor);
140 return;
141 default:
142 snprintf(priv->boardmodel, sizeof(priv->boardmodel),
143 "Renesas -Unknown- board rev ?.?");
144 priv->val = 0xff;
145 return;
146 }
147}
148
149static int sysinfo_rcar_probe(struct udevice *dev)
150{
151 struct sysinfo_rcar_priv *priv = dev_get_priv(dev);
152 struct ofnode_phandle_args phandle_args;
153 struct udevice *i2c_eeprom;
154 u32 offset;
155 int ret;
156
157 offset = dev_read_u32_default(dev, "offset", 0x70);
158
159 ret = dev_read_phandle_with_args(dev, "i2c-eeprom", NULL,
160 0, 0, &phandle_args);
161 if (ret) {
162 debug("%s: i2c-eeprom backing device not specified\n",
163 dev->name);
164 return ret;
165 }
166
167 ret = uclass_get_device_by_ofnode(UCLASS_I2C_EEPROM, phandle_args.node,
168 &i2c_eeprom);
169 if (ret) {
170 debug("%s: could not get backing device\n", dev->name);
171 return ret;
172 }
173
174 ret = i2c_eeprom_read(i2c_eeprom, offset, &priv->val, 1);
175 if (ret < 0) {
176 debug("%s: read failed\n", __func__);
177 return -EIO;
178 }
179
180 sysinfo_rcar_parse(priv);
181
182 return 0;
183}
184
185static const struct udevice_id sysinfo_rcar_ids[] = {
186 { .compatible = "renesas,rcar-sysinfo" },
187 { /* sentinel */ }
188};
189
190U_BOOT_DRIVER(sysinfo_rcar) = {
191 .name = "sysinfo_rcar",
192 .id = UCLASS_SYSINFO,
193 .of_match = sysinfo_rcar_ids,
194 .ops = &sysinfo_rcar_ops,
195 .priv_auto = sizeof(struct sysinfo_rcar_priv),
196 .probe = sysinfo_rcar_probe,
197};