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 |
| 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 | */ |
| 31 | struct sysinfo_rcar_priv { |
| 32 | char boardmodel[64]; |
| 33 | u8 val; |
| 34 | }; |
| 35 | |
| 36 | static 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 | |
| 43 | static 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 | |
| 57 | static const struct sysinfo_ops sysinfo_rcar_ops = { |
| 58 | .detect = sysinfo_rcar_detect, |
| 59 | .get_str = sysinfo_rcar_get_str, |
| 60 | }; |
| 61 | |
| 62 | static 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 | |
| 149 | static 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 | |
| 185 | static const struct udevice_id sysinfo_rcar_ids[] = { |
| 186 | { .compatible = "renesas,rcar-sysinfo" }, |
| 187 | { /* sentinel */ } |
| 188 | }; |
| 189 | |
| 190 | U_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 | }; |