From mboxrd@z Thu Jan 1 00:00:00 1970 Delivery-date: Wed, 17 Sep 2025 19:07:53 +0200 Received: from metis.whiteo.stw.pengutronix.de ([2a0a:edc0:2:b01:1d::104]) by lore.white.stw.pengutronix.de with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1uyvdJ-0049IY-2A for lore@lore.pengutronix.de; Wed, 17 Sep 2025 19:07:53 +0200 Received: from bombadil.infradead.org ([2607:7c80:54:3::133]) by metis.whiteo.stw.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1uyvdI-0001co-4s for lore@pengutronix.de; Wed, 17 Sep 2025 19:07:53 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id: Content-Transfer-Encoding:Content-Type:To:Subject:Message-ID:Date:From: In-Reply-To:References:MIME-Version:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=rCBdOjcQxSmlYlqrxt4C0nN9t1ha3apXuJ+JUILeq2s=; b=baH/XFP1RgQMq9 66FZm6MWOTL5m1f6wkl+M9MQ9s6iNkVyQBYaI0KOhydKDmnuQuUFGeyp5yerb+tg0jmcZogurcWuo XRhhRk/UqSY25SNVu47SAJxu6ZYm2apWcIHpm6YftR2cThiGn4i/Ng24PkJxrgmLqs/cg6AcdEwIs Pfi/IM9WfeZWPPL3X/aeG6LTUR9xzE4slQvSuigW4CVwpJTU0gwv7Vt/QIYGz00358FLxWg3t3cCD zL8odEcesvcF1d/x3r+yvsQzqX/uH3OGEIjECWswjS2nuMUvSJtPGwo6ky8f+456y1jJVdGBfHSls YpwXdJhgdthh+RdGdjLQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98.2 #2 (Red Hat Linux)) id 1uyvcb-0000000DQMb-13rS; Wed, 17 Sep 2025 17:07:09 +0000 Received: from mail-pf1-x434.google.com ([2607:f8b0:4864:20::434]) by bombadil.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux)) id 1uyvcZ-0000000DQKF-1KJ5 for barebox@lists.infradead.org; Wed, 17 Sep 2025 17:07:08 +0000 Received: by mail-pf1-x434.google.com with SMTP id d2e1a72fcca58-77b2e3169dcso110760b3a.2 for ; Wed, 17 Sep 2025 10:07:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1758128826; x=1758733626; darn=lists.infradead.org; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=rCBdOjcQxSmlYlqrxt4C0nN9t1ha3apXuJ+JUILeq2s=; b=KNyKdVJFrDCt3+EmQ3wf+g5UhiX9ncQZBpgJy/pdQkS5S3nZBuGm9Iy0X8NUvP0/nk mb6Wcr54gbaFTJ2NHCWvKcnXa4+3nvr3PDiPyUeqVNNERauxZk3LsxYbBFeCt9PkyytH byXWe66rxhY3usD4yS6mWA5WJtfXFsTfdYOnJfUflBDz/+EzXBHD6qSla2v2Bh3R9aOg vRNae/GPVR/GPEcN3X1XfxlJ9A3xEgGLXDZ7TLdeMzm/HLfsrC3TZ6Big4lqt/QDQlH3 8bXrQjzwas4Uv1u2uz660h7vBGa8fHjhqpUSWRwsTbBr3qSFW2Nb70fgfAIXCnXmXDAz I7aQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1758128826; x=1758733626; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=rCBdOjcQxSmlYlqrxt4C0nN9t1ha3apXuJ+JUILeq2s=; b=tKwwqLUAyqCoXWS+C4N0YVedOek453omenTjP2sU6k5+qsksZylnxt66gXBBddy97q sFecAbNB807K49h64etrsmqfdgutnQAxgALBKImUY40fz5pxdhXIr/RHdvWLaQMzMrog o3VaYxPaVT497NNoAuU3RWXftp9tSTb6uoTGkaHhEIcN+UA/rL4aQAVFtOLbPv+JPiFw gOk1wbfFbs7LPkn/zpMlZzw5LvG2bhUdlsdmpIqkmb1/XVy13r3oiXX9yrMWbrZngRkU AAxHLHOpNyIzQir3ZDDg/2uShztJa/gtNuX8hDWpKUd3GZd/2RB114QEgr/8IFyfJgo3 r9IQ== X-Forwarded-Encrypted: i=1; AJvYcCURw0A4/rDgV7v1dsZe1M2RdipQ2y5OQcQBO1HI3s1JHA570Lb9K05WvBalzqtOcsUk1mt9TNu6@lists.infradead.org X-Gm-Message-State: AOJu0Yzaxzy6wjz7jDqXR2E91uUD0slRnuAeP5+OtlFe+jY+DYYoesz3 7AaFL4OnCa7s1c4SJ2m0os9EOYURzC4mkZhF/p1JbD9Du46IWrU71lgFlkkApizx7Ex1sRYctpW FQ3PGtWezk/W0nazMDZjBfxhwZnIe68w= X-Gm-Gg: ASbGncstZhhIZ5QljuXhov5tr26OAZqWoACayYqL9pYSEosrN+30Jyvl4LDBwgpSY25 onzD/5UcyfX5C29rI09LUTDKOsuUxGb/Ta4vAxtfd5P9sNZeCNYb+GUN+tZZoeHeMVmD78AZkGe obgEG4/lMv4odAQ0IdsoOATZgEiK5uPi/hsMWyoe744tir2ZZKeXFrsoAztISxMY+yzLPDiMJsU P6J9IVN X-Google-Smtp-Source: AGHT+IGevJMadO/+DUcH/juDX98zmH4diDyXXAfcc0KcEh6xOzcuvMLFxizfaZJ0h9+kqsFlcsjgiywwuFrrmW5kPpA= X-Received: by 2002:a17:903:22c9:b0:265:bb0:cbc with SMTP id d9443c01a7336-26813be8919mr40842785ad.47.1758128825563; Wed, 17 Sep 2025 10:07:05 -0700 (PDT) MIME-Version: 1.0 References: <20250917-boards-enclustra-sa2-add-support-v1-0-2de8f69107a1@clermont.in2p3.fr> <20250917-boards-enclustra-sa2-add-support-v1-6-2de8f69107a1@clermont.in2p3.fr> In-Reply-To: <20250917-boards-enclustra-sa2-add-support-v1-6-2de8f69107a1@clermont.in2p3.fr> From: Alexander Shiyan Date: Wed, 17 Sep 2025 20:06:53 +0300 X-Gm-Features: AS18NWCQFhMMLHyO0rRHuQyhEYts90wHvSHF_GgBFogFqVDgnLjMse5-PIlYZz0 Message-ID: To: David Picard Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250917_100707_428375_160A2EE9 X-CRM114-Status: GOOD ( 33.54 ) X-BeenThere: barebox@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: BAREBOX Sender: "barebox" X-SA-Exim-Connect-IP: 2607:7c80:54:3::133 X-SA-Exim-Mail-From: barebox-bounces+lore=pengutronix.de@lists.infradead.org X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on metis.whiteo.stw.pengutronix.de X-Spam-Level: X-Spam-Status: No, score=-4.1 required=4.0 tests=AWL,BAYES_00, DKIM_ADSP_CUSTOM_MED,DKIM_SIGNED,DKIM_VALID,FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM,HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI, RCVD_IN_DNSWL_LOW,SPF_HELO_NONE,SPF_NONE autolearn=unavailable autolearn_force=no version=3.4.2 Subject: Re: [PATCH 06/11] boards: enclustra-sa2: read MAC address from EEPROM X-SA-Exim-Version: 4.2.1 (built Wed, 08 May 2019 21:11:16 +0000) X-SA-Exim-Scanned: Yes (on metis.whiteo.stw.pengutronix.de) Hello. I think we can bring the crc16() procedure into the public location (/crypto?, /lib?). =D1=81=D1=80, 17 =D1=81=D0=B5=D0=BD=D1=82. 2025=E2=80=AF=D0=B3. =D0=B2 18:5= 1, David Picard : > > Signed-off-by: David Picard > --- > arch/arm/boards/enclustra-sa2/Makefile | 2 +- > arch/arm/boards/enclustra-sa2/atsha204a.c | 436 ++++++++++++++++++++++++= ++++++ > arch/arm/boards/enclustra-sa2/atsha204a.h | 19 ++ > arch/arm/boards/enclustra-sa2/board.c | 51 +++- > arch/arm/boards/enclustra-sa2/crc16.c | 65 +++++ > arch/arm/boards/enclustra-sa2/crc16.h | 28 ++ > arch/arm/mach-socfpga/Kconfig | 1 + > 7 files changed, 598 insertions(+), 4 deletions(-) > > diff --git a/arch/arm/boards/enclustra-sa2/Makefile b/arch/arm/boards/enc= lustra-sa2/Makefile > index 8c927fe291a6b3eb20a32a2db96c73f231ab4697..1448ea1266aa24a5b0404cb63= 79f8c2d76573079 100644 > --- a/arch/arm/boards/enclustra-sa2/Makefile > +++ b/arch/arm/boards/enclustra-sa2/Makefile > @@ -1,2 +1,2 @@ > -obj-y +=3D lowlevel.o board.o > +obj-y +=3D lowlevel.o board.o atsha204a.o crc16.o > pbl-y +=3D lowlevel.o > diff --git a/arch/arm/boards/enclustra-sa2/atsha204a.c b/arch/arm/boards/= enclustra-sa2/atsha204a.c > new file mode 100644 > index 0000000000000000000000000000000000000000..3f445de06e73c5bdf27d2d0fc= 81dc6d939d5cd17 > --- /dev/null > +++ b/arch/arm/boards/enclustra-sa2/atsha204a.c > @@ -0,0 +1,436 @@ > +// SPDX-License-Identifier: GPL-2.0-only > + > +#include "atsha204a.h" > +#include > +#include > +#include > +#include /* ARRAY_SIZE */ > +#include /* bitrev16 */ > +#include > +#include "crc16.h" > + > +#define ATSHA204A_TWLO_US (60) > +#define ATSHA204A_TWHI_US (2500) > +#define ATSHA204A_EXECTIME_US (5000) > +#define ATSHA204A_TRANSACTION_TIMEOUT (100000) > +#define ATSHA204A_TRANSACTION_RETRY (5) > + > +enum atsha204a_status { > + ATSHA204A_STATUS_SUCCES =3D 0x00, > + ATSHA204A_STATUS_MISCOMPARE =3D 0x01, > + ATSHA204A_STATUS_PARSE_ERROR =3D 0x03, > + ATSHA204A_STATUS_EXEC_ERROR =3D 0x0F, > + ATSHA204A_STATUS_AFTER_WAKE =3D 0x11, > + ATSHA204A_STATUS_CRC_ERROR =3D 0xFF, > +}; > + > +enum atsha204a_func { > + ATSHA204A_FUNC_RESET =3D 0x00, > + ATSHA204A_FUNC_SLEEP =3D 0x01, > + ATSHA204A_FUNC_IDLE =3D 0x02, > + ATSHA204A_FUNC_COMMAND =3D 0x03, > +}; > + > +enum atsha204a_zone { > + ATSHA204A_ZONE_CONFIG =3D 0, > + ATSHA204A_ZONE_OTP =3D 1, > + ATSHA204A_ZONE_DATA =3D 2, > +}; > + > +enum atsha204a_cmd { > + ATSHA204A_CMD_READ =3D 0x02, > + ATSHA204A_CMD_RANDOM =3D 0x1B, > +}; > + > +/** > + * @brief A response from the device to the host > + */ > +struct atsha204a_resp { > + uint8_t length; /**< Number of bytes in the struct, inclu= ding \a > + length an= d \a code */ > + uint8_t code; /**< Op code that must match the last com= mand */ > + uint8_t data[82]; /**< Data buffer */ > +} __packed; > + > +struct atsha204a_req { > + u8 function; > + u8 length; > + u8 command; > + u8 param1; > + u16 param2; > + u8 data[78]; > +} __packed; > + > +/** > + * @brief Calculate a CRC > + * @param[in] buffer Data on which the CRC must be calculated > + * @param[in] len Number of bytes in \a buffer > + * > + * For example, afer wake-up, the data read from the device is `0x04 0x1= 1 0x33 > + *0x43`. > + * The 1st byte is the packet length, the 2nd byte is the op code and th= e last > + * 2 bytes are the CRC, with the bytes swapped. > + * The function must be called with the 1st 2 bytes and if it returns 0x= 4333, > + * then the CRC is valid. > + * > + * @return The CRC. > + */ > +static inline u16 atsha204a_crc16(const u8 *buffer, size_t len) > +{ > + debug("%s() >> len =3D %u, buffer =3D", __func__, len); > + for (size_t i =3D 0 ; i < len ; i++) > + debug(" 0x%02x", buffer[i]); > + debug("\n"); > + return bitrev16(crc16(0, buffer, len)); > +} > + > +/** > + * @brief Get the device from the devicetree > + * @return A pointer to the device if found, or \t NULL otherwise. > + */ > +static struct device *atsha204a_get_dev(void) > +{ > + struct device *dev; > + struct i2c_client *client; > + > + dev =3D get_device_by_name("atsha204a0"); > + if (dev =3D=3D NULL) { > + printf("%s() >> ERROR: can't find device\n", __func__); > + return NULL; > + } > + client =3D to_i2c_client(dev); > + debug("%s() >> ATASHA204a found at I2C address 0x%02x\n", __func_= _, > + client->addr); > + > + return dev; > +} > + > +/** > + * @brief Send one message to the device > + * @param[in] dev A pointer to the device, returned by #atsha204a_get_de= v() > + * @param[in] buf The data to send > + * @param[in] len The number of bytes in \a buf > + * @return 0 on success, a negative value from `asm-generic/errno.h` on = error. > + */ > +static int atsha204a_send(struct device *dev, const uint8_t *buf, uint8_= t len) > +{ > + int ret; > + struct i2c_client *client; > + > + client =3D to_i2c_client(dev); > + struct i2c_msg msg[] =3D { > + { > + .addr =3D client->addr, > + .buf =3D (uint8_t *)buf, > + .len =3D len, > + } > + }; > + debug("%s() >> dev addr =3D 0x%02x\n", __func__, client->addr); > + > + ret =3D i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); > + if (ret < 0) > + return ret; > + > + return 0; > +} > + > +/** > + * @brief Read from the device > + * @param[in] dev A pointer to the device, returned by #atsha204a_get_de= v() > + * @param[in] buf The data to send > + * @param[in] len The number of bytes in \a buf > + * @return 0 on success, a negative value from `asm-generic/errno.h` on = error. > + */ > +static int atsha204a_recv(struct device *dev, uint8_t *buf, uint8_t len) > +{ > + int ret; > + struct i2c_client *client; > + > + client =3D to_i2c_client(dev); > + /* flags: this is a read operation and generate a stop condition = */ > + struct i2c_msg msg[] =3D { > + { > + .addr =3D client->addr, > + .buf =3D (uint8_t *)buf, > + .len =3D len, > + .flags =3D I2C_M_RD | I2C_M_STOP, > + } > + }; > + > + ret =3D i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); > + if (ret < 0) { > + printf("%s() >> ERROR: ret =3D %d\n", __func__, ret); > + return ret; > + } > + > + return 0; > +} > + > +/** > + * @brief Read from the device and check the CRC > + * @param[in] dev A pointer to the device, returned by #atsha204a_get_de= v() > + * @param[in] resp The response from the device > + * @return 0 on success, a negative value from `asm-generic/errno.h` on = error. > + */ > +static int atsha204a_recv_resp(struct device *dev, struct atsha204a_resp= *resp) > +{ > + int ret; > + uint16_t resp_crc, computed_crc; > + uint8_t *p =3D (uint8_t *)resp; > + > + ret =3D atsha204a_recv(dev, p, 4); > + if (ret) > + return ret; > + debug("%s() >> resp:", __func__); > + for (size_t i =3D 0 ; i < 4 ; i++) > + debug(" 0x%02x", p[i]); > + debug( > + "\n%s() >> length=3D0x%02x, code=3D0x%02x, data[0]=3D0x%0= 2x, data[1]=3D0x%02x\n", > + __func__, > + resp->length, resp->code, resp->data[0], resp->data[1]); > + > + if (resp->length > 4) { > + if (resp->length > sizeof(*resp)) { > + printf("%s() >> ERROR: resp->length %d > 4\n", __= func__, > + resp->length); > + return -EMSGSIZE; > + } > + ret =3D atsha204a_recv(dev, p + 4, resp->length - 4); > + if (ret) > + return ret; > + } > + > + debug("%s() >> checking CRC... resp->length =3D %d\n", __func__, > + resp->length); > + resp_crc =3D (uint16_t)p[resp->length - 2] > + | (((uint16_t)p[resp->length - 1]) << 8); > + computed_crc =3D atsha204a_crc16(p, resp->length - 2); > + > + if (resp_crc !=3D computed_crc) { > + printf( > + "%s() >> ERROR: Invalid CRC. Received: 0x%04x; co= mputed: 0x%04x\n", > + __func__, > + resp_crc, computed_crc); > + return -EBADMSG; > + } > + debug("%s() >> CRC OK: 0x%04x\n", __func__, resp_crc); > + return 0; > +} > + > +/** > + * @brief Put the device to sleep > + * @param[in] dev A pointer to the device, returned by #atsha204a_get_de= v() > + * @return 0 on success, a negative value from `asm-generic/errno.h` on = error. > + */ > +static int atsha204a_sleep(struct device *dev) > +{ > + int ret; > + uint8_t req =3D ATSHA204A_FUNC_SLEEP; > + > + for (int i =3D 1 ; i < 10 ; i++) { > + ret =3D atsha204a_send(dev, &req, 1); > + if (!ret) { > + debug("%s() >> sleeping! Trial #%d\n", __func__, = i); > + break; > + } > + udelay(ATSHA204A_EXECTIME_US); > + } > + > + return ret; > +} > + > +/** > + * @brief Wake up the device > + * @param[in] dev A pointer to the device, returned by #atsha204a_get_de= v() > + * > + * See datasheet =C2=A75.3.2 Synchronization Procedures. > + * > + * @return 0 on success, a negative value from `asm-generic/errno.h` on = error. > + */ > +static int atsha204a_wakeup(struct device *dev) > +{ > + uint8_t buf =3D 0x00; > + struct atsha204a_resp resp; > + int ret; > + struct i2c_client *client; > + > + client =3D to_i2c_client(dev); > + > + for (int i =3D 1; i <=3D 10; i++) { > + /* > + * The device ignores any levels or transitions on the SC= L pin > + * when the device is idle, asleep or during waking up. > + * Generate the wake condition: set SDA low for at least = t_WLO. > + */ > + struct i2c_msg msg; > + > + msg.addr =3D 0; > + msg.flags =3D I2C_M_IGNORE_NAK; > + msg.len =3D 1; > + msg.buf =3D &buf; > + /* don't check errors: there is always one */ > + i2c_transfer(client->adapter, &msg, 1); > + > + udelay(ATSHA204A_TWLO_US + ATSHA204A_TWHI_US); > + > + ret =3D atsha204a_recv_resp(dev, &resp); > + if (ret =3D=3D -EBADMSG) { > + debug("%s() >> WARN: CRC error. Retrying...\n", _= _func__); > + continue; /* retry on CRC error */ > + } else if (ret) { > + printf("%s() >> ERROR: no response\n", __func__); > + return ret; > + } > + > + if (resp.code !=3D ATSHA204A_STATUS_AFTER_WAKE) { > + printf( > + "%s() >> ERROR: bad response, code =3D %0= 2x, expected =3D 0x11\n", > + __func__, resp.code); > + return -EBADMSG; > + } > + > + return 0; > + } > + > + return -ETIMEDOUT; > +} > + > +static void atsha204a_req_crc32(struct atsha204a_req *req) > +{ > + u8 *p =3D (u8 *)req; > + u16 computed_crc; > + u16 *crc_ptr =3D (u16 *)&p[req->length - 1]; > + > + /* The buffer to crc16 starts at byte 1, not 0 */ > + computed_crc =3D atsha204a_crc16(p + 1, req->length - 2); > + > + *crc_ptr =3D cpu_to_le16(computed_crc); > +} > + > +static int atsha204a_transaction(struct device *dev, struct atsha204a_re= q *req, > + struct a= tsha204a_resp *resp) > +{ > + int ret, timeout =3D ATSHA204A_TRANSACTION_TIMEOUT; > + > + ret =3D atsha204a_send(dev, (u8 *)req, req->length + 1); > + if (ret) { > + printf("%s() >> ERROR: transaction send failed\n", __func= __); > + return -EBUSY; > + } > + > + do { > + udelay(ATSHA204A_EXECTIME_US); > + ret =3D atsha204a_recv_resp(dev, resp); > + if (!ret || ret =3D=3D -EMSGSIZE || ret =3D=3D -EBADMSG) > + break; > + > + debug("%s() >> polling for response " > + "(timeout =3D %d)\n", __func__, timeout); > + > + timeout -=3D ATSHA204A_EXECTIME_US; > + } while (timeout > 0); > + > + if (timeout <=3D 0) { > + printf("%s() >> ERROR: transaction timed out\n", __func__= ); > + return -ETIMEDOUT; > + } > + > + return ret; > +} > + > +static int atsha204a_read(struct device *dev, enum atsha204a_zone zone, > + bool read32, > + u16 addr, u8 *buffer) > +{ > + int res, retry =3D ATSHA204A_TRANSACTION_RETRY; > + struct atsha204a_req req; > + struct atsha204a_resp resp; > + > + req.function =3D ATSHA204A_FUNC_COMMAND; > + req.length =3D 7; > + req.command =3D ATSHA204A_CMD_READ; > + > + req.param1 =3D (u8)zone; > + if (read32) > + req.param1 |=3D 0x80; > + > + req.param2 =3D cpu_to_le16(addr); > + > + atsha204a_req_crc32(&req); > + > + do { > + res =3D atsha204a_transaction(dev, &req, &resp); > + if (!res) > + break; > + > + debug("ATSHA204A read retry (%d)\n", retry); > + retry--; > + atsha204a_wakeup(dev); > + } while (retry >=3D 0); > + > + if (res) { > + debug("ATSHA204A read failed\n"); > + return res; > + } > + > + if (resp.length !=3D (read32 ? 32 : 4) + 3) { > + debug("ATSHA204A read bad response length (%d)\n", > + resp.length); > + return -EBADMSG; > + } > + > + memcpy(buffer, ((u8 *)&resp) + 1, read32 ? 32 : 4); > + > + return 0; > +} > + > +int atsha204_get_mac(uint8_t *buffer) > +{ > + int ret; > + uint8_t data[4]; > + struct device *dev; > + > + dev =3D atsha204a_get_dev(); > + if (dev =3D=3D NULL) > + return -ENODEV; > + > + /* put the device to sleep to make sure it is in a defined state = */ > + ret =3D atsha204a_sleep(dev); > + if (ret) { > + printf("%s() >> ERROR: can't put the device to sleep; ret= =3D %d\n", > + __func__, ret); > + return ret; > + } > + > + ret =3D atsha204a_wakeup(dev); > + if (ret) { > + printf("%s() >> ERROR: can't wake up the device; ret =3D = %d\n", __func__, > + ret); > + return ret; > + } > + > + ret =3D atsha204a_read(dev, ATSHA204A_ZONE_OTP, false, > + 4, data); > + if (ret) > + return ret; > + for (int i =3D 0; i < 4; i++) > + buffer[i] =3D data[i]; > + > + ret =3D atsha204a_read(dev, ATSHA204A_ZONE_OTP, false, > + 5, data); > + if (ret) > + return ret; > + buffer[4] =3D data[0]; > + buffer[5] =3D data[1]; > + > + atsha204a_sleep(dev); > + debug("%s() >> MAC address: ", __func__); > + for (int i =3D 0; i <=3D 5; i++) { > + debug("%02x", buffer[i]); > + if (i !=3D 5) > + debug(":"); > + } > + debug("\n"); > + > + return 0; > +} > diff --git a/arch/arm/boards/enclustra-sa2/atsha204a.h b/arch/arm/boards/= enclustra-sa2/atsha204a.h > new file mode 100644 > index 0000000000000000000000000000000000000000..5062c7c07c587994c90a1ba8c= 3de5baeae94badb > --- /dev/null > +++ b/arch/arm/boards/enclustra-sa2/atsha204a.h > @@ -0,0 +1,19 @@ > +// SPDX-License-Identifier: GPL-2.0-only > + > +#pragma once > + > +#include > + > +/** > + * @brief Read the board MAC address from EEPROM > + * @param[out] buffer A 6-byte buffer set to the MAC address on success > + * > + * If the MAC address is 20:B0:F7:0A:6C:08, `buffer[0]` equals 0x20. > + * > + * Read from the one-time programmable zone (OTP) of the chip: > + * - 4 bytes at address 0x10 (32-bit word address 0x04) > + * - 2 bytes at address 0x14 (32-bit word address 0x04) > + * > + * @return 0 on success, a negative value from `asm-generic/errno.h` on = error. > + */ > +int atsha204_get_mac(uint8_t *buffer); > diff --git a/arch/arm/boards/enclustra-sa2/board.c b/arch/arm/boards/encl= ustra-sa2/board.c > index 834d0ab91871d0329af20f89a13af65e194b21c3..4629ca8c08b3046bd0bdc2f09= a24d6cc006794b0 100644 > --- a/arch/arm/boards/enclustra-sa2/board.c > +++ b/arch/arm/boards/enclustra-sa2/board.c > @@ -10,6 +10,11 @@ > #include > #include > #include > +#include > +#include "atsha204a.h" > + > +/** Enclustra's MAC address vendor prefix is 20:B0:F7 */ > +#define ENCLUSTRA_PREFIX (0x20b0f7) > > /* > * Ethernet PHY: Microchip/Micrel KSZ9031RNX > @@ -19,14 +24,54 @@ static int phy_fixup(struct phy_device *dev) > return 0; > } > > +static void set_mac_addr(void) > +{ > + uint8_t hwaddr[6] =3D { 0, 0, 0, 0, 0, 0 }; > + uint32_t hwaddr_prefix; > + /* backup MAC addresses, used if the actual one can't be read fro= m EEPROM: > + */ > + const uint8_t enclustra_ethaddr_def1[] =3D { 0x20, 0xB0, 0xF7, 0x= 01, 0x02, > + = 0x03 }; > + > + /* 2nd backup MAC address if required later > + const uint8_t enclustra_ethaddr_def2[] =3D { 0x20, 0xB0, 0xF7,= 0x01, 0x02, > + 0x04 }; > + */ > + > + if (atsha204_get_mac(hwaddr)) { > + printf( > + "%s() >> ERROR: can't read MAC address from EEPRO= M, using default address\n", > + __func__); > + eth_register_ethaddr(0, enclustra_ethaddr_def1); > + return; > + } > + > + debug("MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n", > + hwaddr[0], hwaddr[1], hwaddr[2], > + hwaddr[3], hwaddr[4], hwaddr[5]); > + > + /* check vendor prefix and set the environment variable */ > + hwaddr_prefix =3D (hwaddr[0] << 16) | (hwaddr[1] << 8) | (hwaddr[= 2]); > + if (hwaddr_prefix =3D=3D ENCLUSTRA_PREFIX) > + eth_register_ethaddr(0, hwaddr); > + else { > + printf( > + "ERROR: invalid MAC address vendor prefix, using = default address\n"); > + eth_register_ethaddr(0, enclustra_ethaddr_def1); > + } > +} > + > static int socfpga_init(void) > { > - if (!of_machine_is_compatible("altr,socfpga-cyclone5")) > + if (!of_machine_is_compatible("enclustra,mercury-sa2")) > return 0; > > if (IS_ENABLED(CONFIG_PHYLIB)) > - phy_register_fixup_for_uid(PHY_ID_KSZ9031, MICREL_PHY_ID_= MASK, phy_fixup); > + phy_register_fixup_for_uid(PHY_ID_KSZ9031, MICREL_PHY_ID_= MASK, > + phy_fi= xup); > + > + set_mac_addr(); > > return 0; > } > -console_initcall(socfpga_init); > +late_initcall(socfpga_init); > diff --git a/arch/arm/boards/enclustra-sa2/crc16.c b/arch/arm/boards/encl= ustra-sa2/crc16.c > new file mode 100644 > index 0000000000000000000000000000000000000000..a94659df00fec8a61b6a0ab64= 97ebd925e720b4c > --- /dev/null > +++ b/arch/arm/boards/enclustra-sa2/crc16.c > @@ -0,0 +1,65 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * crc16.c > + */ > + > +#include > +#include > +#include "crc16.h" > + > +/** CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1)= */ > +u16 const crc16_table[256] =3D { > + 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, > + 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, > + 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, > + 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, > + 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, > + 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, > + 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, > + 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, > + 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, > + 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, > + 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, > + 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, > + 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, > + 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, > + 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, > + 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, > + 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, > + 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, > + 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, > + 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, > + 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, > + 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, > + 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, > + 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, > + 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, > + 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, > + 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, > + 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, > + 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, > + 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, > + 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, > + 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 > +}; > +EXPORT_SYMBOL(crc16_table); > + > +/** > + * crc16 - compute the CRC-16 for the data buffer > + * @crc: previous CRC value > + * @buffer: data pointer > + * @len: number of bytes in the buffer > + * > + * Returns the updated CRC value. > + */ > +u16 crc16(u16 crc, u8 const *buffer, size_t len) > +{ > + while (len--) > + crc =3D crc16_byte(crc, *buffer++); > + return crc; > +} > +EXPORT_SYMBOL(crc16); > + > +MODULE_DESCRIPTION("CRC16 calculations"); > +MODULE_LICENSE("GPL"); > + > diff --git a/arch/arm/boards/enclustra-sa2/crc16.h b/arch/arm/boards/encl= ustra-sa2/crc16.h > new file mode 100644 > index 0000000000000000000000000000000000000000..9fa74529b31787ba2434326d9= ff02913c8cdf740 > --- /dev/null > +++ b/arch/arm/boards/enclustra-sa2/crc16.h > @@ -0,0 +1,28 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +/* > + * crc16.h - CRC-16 routine > + * > + * Implements the standard CRC-16: > + * Width 16 > + * Poly 0x8005 (x^16 + x^15 + x^2 + 1) > + * Init 0 > + * > + * Copyright (c) 2005 Ben Gardner > + */ > + > +#ifndef __CRC16_H > +#define __CRC16_H > + > +#include > + > +extern u16 const crc16_table[256]; > + > +extern u16 crc16(u16 crc, const u8 *buffer, size_t len); > + > +static inline u16 crc16_byte(u16 crc, const u8 data) > +{ > + return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff]; > +} > + > +#endif /* __CRC16_H */ > + > diff --git a/arch/arm/mach-socfpga/Kconfig b/arch/arm/mach-socfpga/Kconfi= g > index a4f859ebf3d7956697d180e15f50b3495cd4c472..fbd7d5c4abb1c6d598adf9209= 535f6f8fbd060e2 100644 > --- a/arch/arm/mach-socfpga/Kconfig > +++ b/arch/arm/mach-socfpga/Kconfig > @@ -36,6 +36,7 @@ config MACH_SOCFPGA_ENCLUSTRA_AA1 > > config MACH_SOCFPGA_ENCLUSTRA_SA2 > select ARCH_SOCFPGA_CYCLONE5 > + select BITREV > bool "Enclustra SA2" > > config MACH_SOCFPGA_REFLEX_ACHILLES > > -- > 2.43.0 > >