From: Christoph Niedermaier <cniedermaier@dh-electronics.com>
To: Marek Vasut <marex@denx.de>,
"u-boot@lists.denx.de" <u-boot@lists.denx.de>
Cc: NXP i.MX U-Boot Team <uboot-imx@nxp.com>,
Fabio Estevam <festevam@gmail.com>,
Stefano Babic <sbabic@denx.de>, Tom Rini <trini@konsulko.com>,
u-boot <u-boot@dh-electronics.com>
Subject: RE: [PATCH V3 2/3] arm64: imx8mp: Read values from M24C32-D write-lockable page on DHCOM i.MX8MP
Date: Tue, 26 Nov 2024 16:18:42 +0000 [thread overview]
Message-ID: <cab2fb2f31294fef8014dc75938f57c7@dh-electronics.com> (raw)
In-Reply-To: <38fa4180-707b-4870-9f47-a1aaf7056795@denx.de>
From: Marek Vasut <marex@denx.de>
Sent: Sunday, November 24, 2024 10:02 PM
> On 11/21/24 6:21 PM, Christoph Niedermaier wrote:
>
> [...]
>
>> +struct eeprom_id_page {
>> + u8 id[3]; /* Identifier 'D', 'H', 'E' - 'D' is at index 0 */
>> + u8 version; /* 0x10 -- Version 1.0 */
>> + u8 data_crc16[2]; /* [1] is MSbyte */
>> + u8 header_crc8;
>> + u8 mac0[6];
>> + u8 mac1[6];
>> + u8 item_prefix; /* H/F is coded in MSbits, Vendor coding starts at LSbits */
>> + u8 item_num[3]; /* [2] is MSbyte */
>> + u8 serial[9]; /* [8] is MSbyte */
>> +};
>> +
>> +#define DH_EEPROM_ID_PAGE_HEADER_LEN offsetof(struct eeprom_id_page, mac0)
>
> If this is really meant to be header length and it should work reliably,
> then it should not depend on payload layout. You likely need something like:
>
> offsetof(struct eeprom_id_page, header_crc8) + sizeof(u8)
>
> Or better yet, rework the structure this way:
>
> struct eeprom_id_page {
> struct {
> u8 id[3]; /* Identifier 'D', 'H', 'E' - 'D' is at index 0 */
> u8 version; /* 0x10 -- Version 1.0 */
> u8 data_crc16[2]; /* [1] is MSbyte */
> u8 header_crc8;
> } header;
>
> struct {
> u8 mac0[6];
> u8 mac1[6];
> u8 item_prefix; /* H/F is coded in MSbits, Vendor coding starts at
> LSbits */
> u8 item_num[3]; /* [2] is MSbyte */
> u8 serial[9]; /* [8] is MSbyte */
> } payload;
> };
>
> ... and in the one callsite (*) which does use this macro, do:
>
> struct eeprom_id_page *eip;
> ...
> -crc16_calc = crc16(0xffff, eeprom_buffer + DH_EEPROM_ID_PAGE_HEADER_LEN, data_len);
> +crc16_calc = crc16(0xffff, eip->payload, sizeof(*eip->payload));
>
I will change it in V4.
>> +#define DH_EEPROM_ID_PAGE_V1_0 0x10
>> +#define DH_EEPROM_ID_PAGE_V1_0_DATA_LEN (sizeof(struct eeprom_id_page) - \
>> + offsetof(struct eeprom_id_page, mac0))
>
> This is not needed either, this would become
>
> sizeof(*eip->payload)
>
> in the only callsite which does use the macro.
>
I will change it in V4.
>> bool dh_mac_is_in_env(const char *env)
>> {
>> unsigned char enetaddr[6];
>> @@ -30,6 +65,141 @@ int dh_get_mac_is_enabled(const char *alias)
>> return 0;
>> }
>>
>> +int dh_read_eeprom_id_page(u8 *eeprom_buffer, const char *alias)
>> +{
>> + struct eeprom_id_page *eip;
>
> You can assign the eip pointer here already:
>
> struct eeprom_id_page *eip = eeprom_buffer;
>
I will change the function parameter to the struct eeprom_id_page in V4.
>> + struct udevice *dev;
>> + size_t data_len;
>> + int eeprom_size;
>> + u16 crc16_calc;
>> + u16 crc16_eip;
>> + u8 crc8_calc;
>> + ofnode node;
>> + int ret;
>> +
>> + node = ofnode_path(alias);
>> +
>> + ret = uclass_get_device_by_ofnode(UCLASS_I2C_EEPROM, node, &dev);
>> + if (ret)
>> + return ret;
>> +
>> + eeprom_size = i2c_eeprom_size(dev);
>> + if (eeprom_size < 0 || eeprom_size > DH_EEPROM_ID_PAGE_MAX_SIZE) {
>
> Wouldn't it be better to exit if eeprom_size < 0 (error) ?
I will add it in V4.
> What happens if eeprom_size == 0 ? Maybe that should be considered
> problematic too ?
I will add it also in V4.
>> + eeprom_size = DH_EEPROM_ID_PAGE_MAX_SIZE;
>> + printf("Warning: Cannot get valid EEPROM.ID page size! Try to read %d bytes.\n",
>
> s@EEPROM.ID@EEPROM ID@ , replace dot with space .
I will fix it in V4.
>
> Also please drop the Warning: prefix , it is unnecessary.
>
I will drop it in V4.
>> + DH_EEPROM_ID_PAGE_MAX_SIZE);
>
> Print both the original eeprom_size reported by i2c_eeprom_size() and
> DH_EEPROM_ID_PAGE_MAX_SIZE , the former is an important hint for debug
> purposes.
I will add it in V4.
>> + }
>> +
>> + ret = i2c_eeprom_read(dev, 0x0, eeprom_buffer, eeprom_size);
>> + if (ret) {
>> + printf("%s: Error reading EEPROM ID page! ret = %d\n", __func__, ret);
>> + return ret;
>> + }
>> +
>> + eip = (struct eeprom_id_page *)eeprom_buffer;
>
> See above.
>
I will remove this line in V4.
>> + /* Validate header ID */
>> + if (eip->id[0] != 'D' || eip->id[1] != 'H' || eip->id[2] != 'E') {
>> + printf("%s: Error validating header ID! (expected DHE)\n", __func__);
>
> To expedite and ease debugging, it is also important to print what the
> code received , not just what the code expected to receive.
>
I will add it in V4.
>> + return -EINVAL;
>> + }
>> +
>> + /* Validate header checksum */
>> + crc8_calc = crc8(0xff, eeprom_buffer, offsetof(struct eeprom_id_page, header_crc8));
>> + if (eip->header_crc8 != crc8_calc) {
>> + printf("%s: Error validating header checksum! (expected 0x%02X)\n",
>
> Better use %02x , I believe lib/tiny-printf.c cannot handle X modifier ,
> please fix globally.
I will fix it in V4.
> To expedite and ease debugging, it is also important to print what the
> code received , not just what the code expected to receive, please fix
> globally.
>
I will add it in V4.
>> + __func__, crc8_calc);
>> + return -EINVAL;
>> + }
>> +
>> + /* Validate header version */
>> + if (eip->version == DH_EEPROM_ID_PAGE_V1_0) {
>
> if if (eip->version != DH_EEPROM_ID_PAGE_V1_0) {
> printf(...);
> return -EINVAL;
> }
>
> data_len = sizeof(*eip->payload);
I will rework it in V4.
>> + data_len = DH_EEPROM_ID_PAGE_V1_0_DATA_LEN;
>> + } else {
>> + printf("%s: Error validating version! (0x%02X is not supported)\n",
>
> The CRC that got calculated is also very interesting, not only the
> expected one.
I will add it in V4.
>> + __func__, eip->version);
>> + return -EINVAL;
>> + }
>> +
>> + /* Validate data checksum */
>> + crc16_eip = (eip->data_crc16[1] << 8) | eip->data_crc16[0];
>> + crc16_calc = crc16(0xffff, eeprom_buffer + DH_EEPROM_ID_PAGE_HEADER_LEN, data_len);
>
> See (*) above
>
I will change it in V4.
>> + if (crc16_eip != crc16_calc) {
>> + printf("%s: Error validating data checksum! (expected 0x%02X)\n",
>> + __func__, crc16_calc);
>
> The CRC that got calculated is also very interesting, not only the
> expected one.
>
I will add it in V4.
>> + return -EINVAL;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +int dh_get_value_from_eeprom_buffer(enum eip_request_values request, u8 *data, int data_len,
>> + u8 *eeprom_buffer)
>> +{
>> + struct eeprom_id_page *eip = (struct eeprom_id_page *)eeprom_buffer;
>
> Is the type cast really needed at all here ? (it might be, please check)
Otherwise I get the following warning from the compiler:
warning: initialization of ‘struct eeprom_id_page *’ from incompatible pointer type ‘u8 *’ {aka ‘unsigned char *’} [-Wincompatible-pointer-types]
struct eeprom_id_page *eip = eeprom_buffer;
^~~~~~~~~~~~~
>> + char soc_chr;
>> +
>> + if (!eeprom_buffer)
>
> Why not pass in "struct eeprom_id_page *eip" directly as function
> parameter of this function ?
>
> This would become if (!eip) return -EINVAL; and the whole type cast
> business above would go away altogether.
>
I will change the function parameter to the struct eeprom_id_page in V4.
>> + return -EINVAL;
>> +
>> + /* Copy requested data */
>> + switch (request) {
>> + case DH_MAC0:
>> + if (!is_valid_ethaddr(eip->mac0))
>> + return -EINVAL;
>> +
>> + if (data_len >= sizeof(eip->mac0))
>> + memcpy(data, eip->mac0, sizeof(eip->mac0));
>> + else
>> + return -EINVAL;
>> + break;
>> + case DH_MAC1:
>> + if (!is_valid_ethaddr(eip->mac1))
>> + return -EINVAL;
>> +
>> + if (data_len >= sizeof(eip->mac1))
>> + memcpy(data, eip->mac1, sizeof(eip->mac1));
>> + else
>> + return -EINVAL;
>> + break;
>> + case DH_ITEM_NUMBER:
>> + if (data_len < 8) /* String length must be 7 characters + string termination */
>> + return -EINVAL;
>> +
>> + const u8 soc_coded = eip->item_prefix & 0xf;
>
> Doesn't the compiler warn about mixing code and variable declarations ?
> If yes, you can easily move this line to the very beginning of this
> function, which is probably just fine to do.
The compiler doesn't warn about that, but I will move it to the beginning in V4.
> [...]
>
>> @@ -28,9 +37,40 @@ int dh_get_mac_is_enabled(const char *alias);
>> */
>> int dh_get_mac_from_eeprom(unsigned char *enetaddr, const char *alias);
>>
>> +/*
>> + * dh_read_eeprom_id_page() - Read EEPROM ID page content into given buffer
>> + * @eeprom_buffer: Buffer for EEPROM ID page content
>> + * @alias: Alias for EEPROM device tree node
>
> Is this really alias to the EEPROM node or to the EEPROM WLP node ?
>
I will fix it in V4.
>> + * Read the content of the EEPROM ID page into the given buffer (parameter
>> + * eeprom_buffer). The EEPROM device is selected via alias device tree name
>> + * (parameter alias). The data of the EEPROM ID page is verified. An error
>> + * is returned for reading failures and invalid data.
>> + *
>> + * Return: 0 if OK, other value on error
>> + */
>> +int dh_read_eeprom_id_page(u8 *eeprom_buffer, const char *alias);
>> +
>> +/*
>> + * dh_get_value_from_eeprom_buffer() - Get value from EEPROM buffer
>> + * @eip_request_values: Requested value as enum
>> + * @data: Buffer where value is to be stored
>> + * @data_len: Length of the value buffer
>> + * @eeprom_buffer: EEPROM buffer from which the data is parsed
>> + *
>> + * Gets the value specified by the parameter eip_request_values from the EEPROM
>> + * buffer (parameter eeprom_buffer). The data is written to the specified data
>> + * buffer (parameter data). If the length of the data (parameter data_len) is
>> + * not sufficient to copy the data into the buffer, an error is returned.
>> + *
>> + * Return: 0 if OK, other value on error
>> + */
>> +int dh_get_value_from_eeprom_buffer(enum eip_request_values request, u8 *data, int data_len,
>> + u8 *eeprom_buffer);
>
> [...]
>
>> +void dh_add_item_number_and_serial_to_env(u8 *eeprom_buffer)
>> +{
>> + char *item_number_env;
>> + char item_number[8]; /* String with 7 characters + string termination */
>> + char *serial_env;
>> + char serial[10]; /* String with 9 characters + string termination */
>> + int ret;
>> +
>> + ret = dh_get_value_from_eeprom_buffer(DH_ITEM_NUMBER, item_number, sizeof(item_number),
>> + eeprom_buffer);
>> + if (ret) {
>> + printf("%s: Unable to get DHSOM item number from EEPROM ID page! ret = %d\n",
>> + __func__, ret);
>> + } else {
>> + item_number_env = env_get("dh_som_item_number");
>> + if (!item_number_env)
>> + env_set("dh_som_item_number", item_number);
>> + else if (strcmp(item_number_env, item_number) != 0)
>
> The != 0 is not necessary, please drop it.
I will drop it in V4.
>> + printf("Warning: Environment dh_som_item_number differs from EEPROM ID page value (%s != %s)\n",
>> + item_number_env, item_number);
>> + }
>> +
>> + ret = dh_get_value_from_eeprom_buffer(DH_SERIAL_NUMBER, serial, sizeof(serial),
>> + eeprom_buffer);
>> + if (ret) {
>> + printf("%s: Unable to get DHSOM serial number from EEPROM ID page! ret = %d\n",
>> + __func__, ret);
>> + } else {
>> + serial_env = env_get("dh_som_serial_number");
>> + if (!serial_env)
>> + env_set("dh_som_serial_number", serial);
>> + else if (strcmp(serial_env, serial) != 0)
>
> The != 0 is not necessary, please drop it.
I will drop it in V4.
>> + printf("Warning: Environment dh_som_serial_number differs from EEPROM ID page value (%s != %s)\n",
>> + serial_env, serial);
>> + }
>> +}
>> +
>> int board_init(void)
>> {
>> return 0;
>> @@ -117,7 +160,26 @@ int board_init(void)
>>
>> int board_late_init(void)
>> {
>> - dh_setup_mac_address();
>> + u8 eeprom_buffer[DH_EEPROM_ID_PAGE_MAX_SIZE] = { 0 };
>
> Do the following cast here:
>
> struct eeprom_id_page *eip = eeprom_buffer;
>
> and then you can pass *eip to dh_setup_mac_address() and
> dh_add_item_number_and_serial_to_env() and save yourself a lot of
> typecasts all around.
I will change it in V4.
>> + int ret;
>> +
>> + ret = dh_read_eeprom_id_page(eeprom_buffer, "eeprom0wl");
>> + if (ret) {
>> + /*
>> + * The EEPROM ID page is available on SoM rev. 200 and greater.
>> + * For SoM rev. 100 the return value will be -ENODEV. Suppress
>> + * the error message for that, because the absence cannot be
>> + * treated as an error.
>> + */
>> + if (ret != -ENODEV)
>> + printf("%s: Cannot read valid data from EEPROM ID page! ret = %d\n",
>> + __func__, ret);
>> + dh_setup_mac_address(NULL);
>> + } else {
>> + dh_setup_mac_address(eeprom_buffer);
>> + dh_add_item_number_and_serial_to_env(eeprom_buffer);
> [...]
Thanks and regards
Christoph
next prev parent reply other threads:[~2024-11-26 16:22 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-11-21 17:21 [PATCH V3 1/3] arm64: dts: imx8mp: Add aliases for the access to the EEMPROM ID page node Christoph Niedermaier
2024-11-21 17:21 ` [PATCH V3 2/3] arm64: imx8mp: Read values from M24C32-D write-lockable page on DHCOM i.MX8MP Christoph Niedermaier
2024-11-24 21:01 ` Marek Vasut
2024-11-26 16:18 ` Christoph Niedermaier [this message]
2024-11-21 17:21 ` [PATCH V3 3/3] board: dhelectronics: Sync env variable dh_som_serial_number with SN Christoph Niedermaier
2024-11-24 21:10 ` Marek Vasut
2024-11-24 22:11 ` Marek Vasut
2024-11-27 16:11 ` Christoph Niedermaier
2024-11-21 17:37 ` [PATCH V3 1/3] arm64: dts: imx8mp: Add aliases for the access to the EEMPROM ID page node Marek Vasut
2024-11-22 21:57 ` Christoph Niedermaier
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=cab2fb2f31294fef8014dc75938f57c7@dh-electronics.com \
--to=cniedermaier@dh-electronics.com \
--cc=festevam@gmail.com \
--cc=marex@denx.de \
--cc=sbabic@denx.de \
--cc=trini@konsulko.com \
--cc=u-boot@dh-electronics.com \
--cc=u-boot@lists.denx.de \
--cc=uboot-imx@nxp.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.