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