mirror of
https://github.com/AsahiLinux/u-boot
synced 2025-03-16 06:46:59 +00:00
Merge branch '2022-06-09-add-support-for-nvmem-api' into next
To quote the author: This adds support for the nvmem-cells properties cropping up in manyb device trees. This is an easy way to load configuration, version information, or calibration data from a non-volatile memory source. For more information, refer to patch 6 ("misc: Add support for nvmem cells"). For the moment I have only added some integration tests using the ethernet addresses. This hits the main code paths (looking up nvmem cells) but doesn't test writing. I can add a few stand-alone tests if desired.
This commit is contained in:
commit
e5028bb227
26 changed files with 436 additions and 29 deletions
|
@ -1091,6 +1091,13 @@ F: cmd/nvme.c
|
|||
F: include/nvme.h
|
||||
F: doc/develop/driver-model/nvme.rst
|
||||
|
||||
NVMEM
|
||||
M: Sean Anderson <seanga2@gmail.com>
|
||||
S: Maintained
|
||||
F: doc/api/nvmem.rst
|
||||
F: drivers/misc/nvmem.c
|
||||
F: include/nvmem.h
|
||||
|
||||
NXP C45 TJA11XX PHY DRIVER
|
||||
M: Radu Pirea <radu-nicolae.pirea@oss.nxp.com>
|
||||
S: Maintained
|
||||
|
|
|
@ -63,7 +63,6 @@
|
|||
eth@10002000 {
|
||||
compatible = "sandbox,eth";
|
||||
reg = <0x10002000 0x1000>;
|
||||
fake-host-hwaddr = [00 00 66 44 22 00];
|
||||
};
|
||||
|
||||
host-fs {
|
||||
|
|
|
@ -58,7 +58,6 @@
|
|||
eth@10002000 {
|
||||
compatible = "sandbox,eth";
|
||||
reg = <0x0 0x10002000 0x0 0x1000>;
|
||||
fake-host-hwaddr = [00 00 66 44 22 00];
|
||||
};
|
||||
|
||||
i2c_0: i2c@0 {
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
ethernet3 = ð_3;
|
||||
ethernet4 = &dsa_eth0;
|
||||
ethernet5 = ð_5;
|
||||
ethernet6 = "/eth@10004000";
|
||||
ethernet7 = &swp_1;
|
||||
ethernet8 = &phy_eth0;
|
||||
gpio1 = &gpio_a;
|
||||
gpio2 = &gpio_b;
|
||||
gpio3 = &gpio_c;
|
||||
|
@ -524,31 +527,31 @@
|
|||
eth@10002000 {
|
||||
compatible = "sandbox,eth";
|
||||
reg = <0x10002000 0x1000>;
|
||||
fake-host-hwaddr = [00 00 66 44 22 00];
|
||||
};
|
||||
|
||||
eth_5: eth@10003000 {
|
||||
compatible = "sandbox,eth";
|
||||
reg = <0x10003000 0x1000>;
|
||||
fake-host-hwaddr = [00 00 66 44 22 11];
|
||||
nvmem-cells = <ð5_addr>;
|
||||
nvmem-cell-names = "mac-address";
|
||||
};
|
||||
|
||||
eth_3: sbe5 {
|
||||
compatible = "sandbox,eth";
|
||||
reg = <0x10005000 0x1000>;
|
||||
fake-host-hwaddr = [00 00 66 44 22 33];
|
||||
nvmem-cells = <ð3_addr>;
|
||||
nvmem-cell-names = "mac-address";
|
||||
};
|
||||
|
||||
eth@10004000 {
|
||||
compatible = "sandbox,eth";
|
||||
reg = <0x10004000 0x1000>;
|
||||
fake-host-hwaddr = [00 00 66 44 22 22];
|
||||
};
|
||||
|
||||
phy_eth0: phy-test-eth {
|
||||
compatible = "sandbox,eth";
|
||||
reg = <0x10007000 0x1000>;
|
||||
fake-host-hwaddr = [00 00 66 44 22 77];
|
||||
mac-address = [ 02 00 11 22 33 49 ];
|
||||
phy-handle = <ðphy1>;
|
||||
phy-mode = "2500base-x";
|
||||
};
|
||||
|
@ -556,7 +559,8 @@
|
|||
dsa_eth0: dsa-test-eth {
|
||||
compatible = "sandbox,eth";
|
||||
reg = <0x10006000 0x1000>;
|
||||
fake-host-hwaddr = [00 00 66 44 22 66];
|
||||
nvmem-cells = <ð4_addr>;
|
||||
nvmem-cell-names = "mac-address";
|
||||
};
|
||||
|
||||
dsa-test {
|
||||
|
@ -700,6 +704,8 @@
|
|||
pinctrl-0 = <&pinmux_i2c0_pins>;
|
||||
|
||||
eeprom@2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
reg = <0x2c>;
|
||||
compatible = "i2c-eeprom";
|
||||
sandbox,emul = <&emul_eeprom>;
|
||||
|
@ -711,12 +717,22 @@
|
|||
reg = <10 2>;
|
||||
};
|
||||
};
|
||||
|
||||
eth3_addr: mac-address@24 {
|
||||
reg = <24 6>;
|
||||
};
|
||||
};
|
||||
|
||||
rtc_0: rtc@43 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
reg = <0x43>;
|
||||
compatible = "sandbox-rtc";
|
||||
sandbox,emul = <&emul0>;
|
||||
|
||||
eth4_addr: mac-address@40 {
|
||||
reg = <0x40 6>;
|
||||
};
|
||||
};
|
||||
|
||||
rtc_1: rtc@61 {
|
||||
|
@ -898,7 +914,13 @@
|
|||
};
|
||||
|
||||
misc-test {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "sandbox,misc_sandbox";
|
||||
|
||||
eth5_addr: mac-address@10 {
|
||||
reg = <0x10 6>;
|
||||
};
|
||||
};
|
||||
|
||||
mmc2 {
|
||||
|
|
|
@ -6,10 +6,6 @@ stdout=serial,vidconsole
|
|||
stderr=serial,vidconsole
|
||||
|
||||
ethaddr=02:00:11:22:33:44
|
||||
eth2addr=02:00:11:22:33:48
|
||||
eth3addr=02:00:11:22:33:45
|
||||
eth4addr=02:00:11:22:33:48
|
||||
eth5addr=02:00:11:22:33:46
|
||||
eth6addr=02:00:11:22:33:47
|
||||
ipaddr=192.0.2.1
|
||||
|
||||
|
|
|
@ -144,6 +144,7 @@ CONFIG_LED_GPIO=y
|
|||
CONFIG_DM_MAILBOX=y
|
||||
CONFIG_SANDBOX_MBOX=y
|
||||
CONFIG_MISC=y
|
||||
CONFIG_NVMEM=y
|
||||
CONFIG_CROS_EC=y
|
||||
CONFIG_CROS_EC_I2C=y
|
||||
CONFIG_CROS_EC_LPC=y
|
||||
|
|
|
@ -188,6 +188,7 @@ CONFIG_LED_GPIO=y
|
|||
CONFIG_DM_MAILBOX=y
|
||||
CONFIG_SANDBOX_MBOX=y
|
||||
CONFIG_MISC=y
|
||||
CONFIG_NVMEM=y
|
||||
CONFIG_CROS_EC=y
|
||||
CONFIG_CROS_EC_I2C=y
|
||||
CONFIG_CROS_EC_LPC=y
|
||||
|
|
|
@ -117,6 +117,7 @@ CONFIG_LED_GPIO=y
|
|||
CONFIG_DM_MAILBOX=y
|
||||
CONFIG_SANDBOX_MBOX=y
|
||||
CONFIG_MISC=y
|
||||
CONFIG_NVMEM=y
|
||||
CONFIG_CROS_EC=y
|
||||
CONFIG_CROS_EC_I2C=y
|
||||
CONFIG_CROS_EC_LPC=y
|
||||
|
|
|
@ -144,6 +144,7 @@ CONFIG_LED_GPIO=y
|
|||
CONFIG_DM_MAILBOX=y
|
||||
CONFIG_SANDBOX_MBOX=y
|
||||
CONFIG_MISC=y
|
||||
CONFIG_NVMEM=y
|
||||
CONFIG_CROS_EC=y
|
||||
CONFIG_CROS_EC_I2C=y
|
||||
CONFIG_CROS_EC_LPC=y
|
||||
|
|
|
@ -145,6 +145,8 @@ CONFIG_LED_GPIO=y
|
|||
CONFIG_DM_MAILBOX=y
|
||||
CONFIG_SANDBOX_MBOX=y
|
||||
CONFIG_MISC=y
|
||||
CONFIG_NVMEM=y
|
||||
CONFIG_SPL_NVMEM=y
|
||||
CONFIG_CROS_EC=y
|
||||
CONFIG_CROS_EC_I2C=y
|
||||
CONFIG_CROS_EC_LPC=y
|
||||
|
@ -153,6 +155,7 @@ CONFIG_CROS_EC_SPI=y
|
|||
CONFIG_P2SB=y
|
||||
CONFIG_PWRSEQ=y
|
||||
CONFIG_SPL_PWRSEQ=y
|
||||
CONFIG_I2C_EEPROM=y
|
||||
CONFIG_MMC_SANDBOX=y
|
||||
CONFIG_SPI_FLASH_SANDBOX=y
|
||||
CONFIG_SPI_FLASH_ATMEL=y
|
||||
|
|
|
@ -14,6 +14,7 @@ U-Boot API documentation
|
|||
linker_lists
|
||||
lmb
|
||||
logging
|
||||
nvmem
|
||||
pinctrl
|
||||
rng
|
||||
sandbox
|
||||
|
|
10
doc/api/nvmem.rst
Normal file
10
doc/api/nvmem.rst
Normal file
|
@ -0,0 +1,10 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
NVMEM API
|
||||
=========
|
||||
|
||||
.. kernel-doc:: include/nvmem.h
|
||||
:doc: Design
|
||||
|
||||
.. kernel-doc:: include/nvmem.h
|
||||
:internal:
|
|
@ -43,6 +43,22 @@ config VPL_MISC
|
|||
set of generic read, write and ioctl methods may be used to
|
||||
access the device.
|
||||
|
||||
config NVMEM
|
||||
bool "NVMEM support"
|
||||
help
|
||||
This adds support for a common interface to different types of
|
||||
non-volatile memory. Consumers can use nvmem-cells properties to look
|
||||
up hardware configuration data such as MAC addresses and calibration
|
||||
settings.
|
||||
|
||||
config SPL_NVMEM
|
||||
bool "NVMEM support in SPL"
|
||||
help
|
||||
This adds support for a common interface to different types of
|
||||
non-volatile memory. Consumers can use nvmem-cells properties to look
|
||||
up hardware configuration data such as MAC addresses and calibration
|
||||
settings.
|
||||
|
||||
config ALTERA_SYSID
|
||||
bool "Altera Sysid support"
|
||||
depends on MISC
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
|
||||
obj-$(CONFIG_$(SPL_TPL_)MISC) += misc-uclass.o
|
||||
obj-$(CONFIG_$(SPL_TPL_)NVMEM) += nvmem.o
|
||||
|
||||
obj-$(CONFIG_$(SPL_TPL_)CROS_EC) += cros_ec.o
|
||||
obj-$(CONFIG_$(SPL_TPL_)CROS_EC_SANDBOX) += cros_ec_sandbox.o
|
||||
|
|
|
@ -33,7 +33,8 @@ int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf, int size)
|
|||
return ops->read(dev, offset, buf, size);
|
||||
}
|
||||
|
||||
int i2c_eeprom_write(struct udevice *dev, int offset, uint8_t *buf, int size)
|
||||
int i2c_eeprom_write(struct udevice *dev, int offset, const uint8_t *buf,
|
||||
int size)
|
||||
{
|
||||
const struct i2c_eeprom_ops *ops = device_get_ops(dev);
|
||||
|
||||
|
|
|
@ -171,11 +171,15 @@ static int sandbox_i2c_eeprom_probe(struct udevice *dev)
|
|||
{
|
||||
struct sandbox_i2c_flash_plat_data *plat = dev_get_plat(dev);
|
||||
struct sandbox_i2c_flash *priv = dev_get_priv(dev);
|
||||
/* For eth3 */
|
||||
const u8 mac[] = { 0x02, 0x00, 0x11, 0x22, 0x33, 0x45 };
|
||||
|
||||
priv->data = calloc(1, plat->size);
|
||||
if (!priv->data)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(&priv->data[24], mac, sizeof(mac));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -112,8 +112,11 @@ static const struct misc_ops misc_sandbox_ops = {
|
|||
int misc_sandbox_probe(struct udevice *dev)
|
||||
{
|
||||
struct misc_sandbox_priv *priv = dev_get_priv(dev);
|
||||
/* For eth5 */
|
||||
const u8 mac[] = { 0x02, 0x00, 0x11, 0x22, 0x33, 0x46 };
|
||||
|
||||
priv->enabled = true;
|
||||
memcpy(&priv->mem[16], mac, sizeof(mac));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
142
drivers/misc/nvmem.c
Normal file
142
drivers/misc/nvmem.c
Normal file
|
@ -0,0 +1,142 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2022 Sean Anderson <sean.anderson@seco.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <i2c_eeprom.h>
|
||||
#include <linker_lists.h>
|
||||
#include <misc.h>
|
||||
#include <nvmem.h>
|
||||
#include <rtc.h>
|
||||
#include <dm/device_compat.h>
|
||||
#include <dm/ofnode.h>
|
||||
#include <dm/read.h>
|
||||
#include <dm/uclass.h>
|
||||
|
||||
int nvmem_cell_read(struct nvmem_cell *cell, void *buf, size_t size)
|
||||
{
|
||||
dev_dbg(cell->nvmem, "%s: off=%u size=%zu\n", __func__, cell->offset, size);
|
||||
if (size != cell->size)
|
||||
return -EINVAL;
|
||||
|
||||
switch (cell->nvmem->driver->id) {
|
||||
case UCLASS_I2C_EEPROM:
|
||||
return i2c_eeprom_read(cell->nvmem, cell->offset, buf, size);
|
||||
case UCLASS_MISC: {
|
||||
int ret = misc_read(cell->nvmem, cell->offset, buf, size);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret != size)
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
case UCLASS_RTC:
|
||||
return dm_rtc_read(cell->nvmem, cell->offset, buf, size);
|
||||
default:
|
||||
return -ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
int nvmem_cell_write(struct nvmem_cell *cell, const void *buf, size_t size)
|
||||
{
|
||||
dev_dbg(cell->nvmem, "%s: off=%u size=%zu\n", __func__, cell->offset, size);
|
||||
if (size != cell->size)
|
||||
return -EINVAL;
|
||||
|
||||
switch (cell->nvmem->driver->id) {
|
||||
case UCLASS_I2C_EEPROM:
|
||||
return i2c_eeprom_write(cell->nvmem, cell->offset, buf, size);
|
||||
case UCLASS_MISC: {
|
||||
int ret = misc_write(cell->nvmem, cell->offset, buf, size);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret != size)
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
case UCLASS_RTC:
|
||||
return dm_rtc_write(cell->nvmem, cell->offset, buf, size);
|
||||
default:
|
||||
return -ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* nvmem_get_device() - Get an nvmem device for a cell
|
||||
* @node: ofnode of the nvmem device
|
||||
* @cell: Cell to look up
|
||||
*
|
||||
* Try to find a nvmem-compatible device by going through the nvmem interfaces.
|
||||
*
|
||||
* Return:
|
||||
* * 0 on success
|
||||
* * -ENODEV if we didn't find anything
|
||||
* * A negative error if there was a problem looking up the device
|
||||
*/
|
||||
static int nvmem_get_device(ofnode node, struct nvmem_cell *cell)
|
||||
{
|
||||
int i, ret;
|
||||
enum uclass_id ids[] = {
|
||||
UCLASS_I2C_EEPROM,
|
||||
UCLASS_MISC,
|
||||
UCLASS_RTC,
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ids); i++) {
|
||||
ret = uclass_get_device_by_ofnode(ids[i], node, &cell->nvmem);
|
||||
if (!ret)
|
||||
return 0;
|
||||
if (ret != -ENODEV && ret != -EPFNOSUPPORT)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int nvmem_cell_get_by_index(struct udevice *dev, int index,
|
||||
struct nvmem_cell *cell)
|
||||
{
|
||||
fdt_addr_t offset;
|
||||
fdt_size_t size = FDT_SIZE_T_NONE;
|
||||
int ret;
|
||||
struct ofnode_phandle_args args;
|
||||
|
||||
dev_dbg(dev, "%s: index=%d\n", __func__, index);
|
||||
|
||||
ret = dev_read_phandle_with_args(dev, "nvmem-cells", NULL, 0, index,
|
||||
&args);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nvmem_get_device(ofnode_get_parent(args.node), cell);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
offset = ofnode_get_addr_size_index_notrans(args.node, 0, &size);
|
||||
if (offset == FDT_ADDR_T_NONE || size == FDT_SIZE_T_NONE) {
|
||||
dev_dbg(cell->nvmem, "missing address or size for %s\n",
|
||||
ofnode_get_name(args.node));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cell->offset = offset;
|
||||
cell->size = size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nvmem_cell_get_by_name(struct udevice *dev, const char *name,
|
||||
struct nvmem_cell *cell)
|
||||
{
|
||||
int index;
|
||||
|
||||
dev_dbg(dev, "%s, name=%s\n", __func__, name);
|
||||
|
||||
index = dev_read_stringlist_search(dev, "nvmem-cell-names", name);
|
||||
if (index < 0)
|
||||
return index;
|
||||
|
||||
return nvmem_cell_get_by_index(dev, index, cell);
|
||||
}
|
|
@ -395,9 +395,11 @@ static void sb_eth_stop(struct udevice *dev)
|
|||
static int sb_eth_write_hwaddr(struct udevice *dev)
|
||||
{
|
||||
struct eth_pdata *pdata = dev_get_plat(dev);
|
||||
struct eth_sandbox_priv *priv = dev_get_priv(dev);
|
||||
|
||||
debug("eth_sandbox %s: Write HW ADDR - %pM\n", dev->name,
|
||||
pdata->enetaddr);
|
||||
memcpy(priv->fake_host_hwaddr, pdata->enetaddr, ARP_HLEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -419,16 +421,8 @@ static int sb_eth_of_to_plat(struct udevice *dev)
|
|||
{
|
||||
struct eth_pdata *pdata = dev_get_plat(dev);
|
||||
struct eth_sandbox_priv *priv = dev_get_priv(dev);
|
||||
const u8 *mac;
|
||||
|
||||
pdata->iobase = dev_read_addr(dev);
|
||||
|
||||
mac = dev_read_u8_array_ptr(dev, "fake-host-hwaddr", ARP_HLEN);
|
||||
if (!mac) {
|
||||
printf("'fake-host-hwaddr' is missing from the DT\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
memcpy(priv->fake_host_hwaddr, mac, ARP_HLEN);
|
||||
priv->disabled = false;
|
||||
priv->tx_handler = sb_default_handler;
|
||||
|
||||
|
|
|
@ -203,6 +203,15 @@ static int sandbox_i2c_rtc_bind(struct udevice *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sandbox_i2c_rtc_probe(struct udevice *dev)
|
||||
{
|
||||
const u8 mac[] = { 0x02, 0x00, 0x11, 0x22, 0x33, 0x48 };
|
||||
struct sandbox_i2c_rtc_plat_data *plat = dev_get_plat(dev);
|
||||
|
||||
memcpy(&plat->reg[0x40], mac, sizeof(mac));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id sandbox_i2c_rtc_ids[] = {
|
||||
{ .compatible = "sandbox,i2c-rtc-emul" },
|
||||
{ }
|
||||
|
@ -213,6 +222,7 @@ U_BOOT_DRIVER(sandbox_i2c_rtc_emul) = {
|
|||
.id = UCLASS_I2C_EMUL,
|
||||
.of_match = sandbox_i2c_rtc_ids,
|
||||
.bind = sandbox_i2c_rtc_bind,
|
||||
.probe = sandbox_i2c_rtc_probe,
|
||||
.priv_auto = sizeof(struct sandbox_i2c_rtc),
|
||||
.plat_auto = sizeof(struct sandbox_i2c_rtc_plat_data),
|
||||
.ops = &sandbox_i2c_rtc_emul_ops,
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#ifndef __I2C_EEPROM
|
||||
#define __I2C_EEPROM
|
||||
|
||||
struct udevice;
|
||||
|
||||
struct i2c_eeprom_ops {
|
||||
int (*read)(struct udevice *dev, int offset, uint8_t *buf, int size);
|
||||
int (*write)(struct udevice *dev, int offset, const uint8_t *buf,
|
||||
|
@ -20,6 +22,7 @@ struct i2c_eeprom {
|
|||
unsigned long size;
|
||||
};
|
||||
|
||||
#if CONFIG_IS_ENABLED(I2C_EEPROM)
|
||||
/*
|
||||
* i2c_eeprom_read() - read bytes from an I2C EEPROM chip
|
||||
*
|
||||
|
@ -42,7 +45,8 @@ int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf, int size);
|
|||
*
|
||||
* Return: 0 on success, -ve on failure
|
||||
*/
|
||||
int i2c_eeprom_write(struct udevice *dev, int offset, uint8_t *buf, int size);
|
||||
int i2c_eeprom_write(struct udevice *dev, int offset, const uint8_t *buf,
|
||||
int size);
|
||||
|
||||
/*
|
||||
* i2c_eeprom_size() - get size of I2C EEPROM chip
|
||||
|
@ -53,4 +57,25 @@ int i2c_eeprom_write(struct udevice *dev, int offset, uint8_t *buf, int size);
|
|||
*/
|
||||
int i2c_eeprom_size(struct udevice *dev);
|
||||
|
||||
#else /* !I2C_EEPROM */
|
||||
|
||||
static inline int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf,
|
||||
int size)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline int i2c_eeprom_write(struct udevice *dev, int offset,
|
||||
const uint8_t *buf, int size)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline int i2c_eeprom_size(struct udevice *dev)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
#endif /* I2C_EEPROM */
|
||||
|
||||
#endif
|
||||
|
|
134
include/nvmem.h
Normal file
134
include/nvmem.h
Normal file
|
@ -0,0 +1,134 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright (c) 2022 Sean Anderson <sean.anderson@seco.com>
|
||||
*/
|
||||
|
||||
#ifndef NVMEM_H
|
||||
#define NVMEM_H
|
||||
|
||||
/**
|
||||
* DOC: Design
|
||||
*
|
||||
* The NVMEM subsystem is a "meta-uclass" in that it abstracts over several
|
||||
* different uclasses all with read/write APIs. One approach to implementing
|
||||
* this could be to add a new sub-device for each nvmem-style device of
|
||||
* UCLASS_NVMEM. This subsystem has taken the approach of using the existing
|
||||
* access methods (i2c_eeprom_write, misc_write, etc.) directly. This has the
|
||||
* advantage of not requiring an extra device/driver, saving on binary size and
|
||||
* runtime memory usage. On the other hand, it is not idiomatic. Similar
|
||||
* efforts should generally use a new uclass.
|
||||
*/
|
||||
|
||||
/**
|
||||
* struct nvmem_cell - One datum within non-volatile memory
|
||||
* @nvmem: The backing storage device
|
||||
* @offset: The offset of the cell from the start of @nvmem
|
||||
* @size: The size of the cell, in bytes
|
||||
*/
|
||||
struct nvmem_cell {
|
||||
struct udevice *nvmem;
|
||||
unsigned int offset;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct udevice;
|
||||
|
||||
#if CONFIG_IS_ENABLED(NVMEM)
|
||||
|
||||
/**
|
||||
* nvmem_cell_read() - Read the value of an nvmem cell
|
||||
* @cell: The nvmem cell to read
|
||||
* @buf: The buffer to read into
|
||||
* @size: The size of @buf
|
||||
*
|
||||
* Return:
|
||||
* * 0 on success
|
||||
* * -EINVAL if @buf is not the same size as @cell.
|
||||
* * -ENOSYS if CONFIG_NVMEM is disabled
|
||||
* * A negative error if there was a problem reading the underlying storage
|
||||
*/
|
||||
int nvmem_cell_read(struct nvmem_cell *cell, void *buf, size_t size);
|
||||
|
||||
/**
|
||||
* nvmem_cell_write() - Write a value to an nvmem cell
|
||||
* @cell: The nvmem cell to write
|
||||
* @buf: The buffer to write from
|
||||
* @size: The size of @buf
|
||||
*
|
||||
* Return:
|
||||
* * 0 on success
|
||||
* * -EINVAL if @buf is not the same size as @cell
|
||||
* * -ENOSYS if @cell is read-only, or if CONFIG_NVMEM is disabled
|
||||
* * A negative error if there was a problem writing the underlying storage
|
||||
*/
|
||||
int nvmem_cell_write(struct nvmem_cell *cell, const void *buf, size_t size);
|
||||
|
||||
/**
|
||||
* nvmem_cell_get_by_index() - Get an nvmem cell from a given device and index
|
||||
* @dev: The device that uses the nvmem cell
|
||||
* @index: The index of the cell in nvmem-cells
|
||||
* @cell: The cell to initialize
|
||||
*
|
||||
* Look up the nvmem cell referenced by the phandle at @index in nvmem-cells in
|
||||
* @dev.
|
||||
*
|
||||
* Return:
|
||||
* * 0 on success
|
||||
* * -EINVAL if the regs property is missing, empty, or undersized
|
||||
* * -ENODEV if the nvmem device is missing or unimplemented
|
||||
* * -ENOSYS if CONFIG_NVMEM is disabled
|
||||
* * A negative error if there was a problem reading nvmem-cells or getting the
|
||||
* device
|
||||
*/
|
||||
int nvmem_cell_get_by_index(struct udevice *dev, int index,
|
||||
struct nvmem_cell *cell);
|
||||
|
||||
/**
|
||||
* nvmem_cell_get_by_name() - Get an nvmem cell from a given device and name
|
||||
* @dev: The device that uses the nvmem cell
|
||||
* @name: The name of the nvmem cell
|
||||
* @cell: The cell to initialize
|
||||
*
|
||||
* Look up the nvmem cell referenced by @name in the nvmem-cell-names property
|
||||
* of @dev.
|
||||
*
|
||||
* Return:
|
||||
* * 0 on success
|
||||
* * -EINVAL if the regs property is missing, empty, or undersized
|
||||
* * -ENODEV if the nvmem device is missing or unimplemented
|
||||
* * -ENODATA if @name is not in nvmem-cell-names
|
||||
* * -ENOSYS if CONFIG_NVMEM is disabled
|
||||
* * A negative error if there was a problem reading nvmem-cell-names,
|
||||
* nvmem-cells, or getting the device
|
||||
*/
|
||||
int nvmem_cell_get_by_name(struct udevice *dev, const char *name,
|
||||
struct nvmem_cell *cell);
|
||||
|
||||
#else /* CONFIG_NVMEM */
|
||||
|
||||
static inline int nvmem_cell_read(struct nvmem_cell *cell, void *buf, int size)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline int nvmem_cell_write(struct nvmem_cell *cell, const void *buf,
|
||||
int size)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline int nvmem_cell_get_by_index(struct udevice *dev, int index,
|
||||
struct nvmem_cell *cell)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline int nvmem_cell_get_by_name(struct udevice *dev, const char *name,
|
||||
struct nvmem_cell *cell)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NVMEM */
|
||||
|
||||
#endif /* NVMEM_H */
|
|
@ -477,8 +477,10 @@ static int dsa_pre_probe(struct udevice *dev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
uclass_find_device_by_ofnode(UCLASS_ETH, pdata->master_node,
|
||||
&priv->master_dev);
|
||||
err = uclass_get_device_by_ofnode(UCLASS_ETH, pdata->master_node,
|
||||
&priv->master_dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Simulate a probing event for the CPU port */
|
||||
if (ops->port_probe) {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <env.h>
|
||||
#include <log.h>
|
||||
#include <net.h>
|
||||
#include <nvmem.h>
|
||||
#include <asm/global_data.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <dm/uclass-internal.h>
|
||||
|
@ -507,17 +508,21 @@ static bool eth_dev_get_mac_address(struct udevice *dev, u8 mac[ARP_HLEN])
|
|||
{
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
const uint8_t *p;
|
||||
struct nvmem_cell mac_cell;
|
||||
|
||||
p = dev_read_u8_array_ptr(dev, "mac-address", ARP_HLEN);
|
||||
if (!p)
|
||||
p = dev_read_u8_array_ptr(dev, "local-mac-address", ARP_HLEN);
|
||||
|
||||
if (!p)
|
||||
if (p) {
|
||||
memcpy(mac, p, ARP_HLEN);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (nvmem_cell_get_by_name(dev, "mac-address", &mac_cell))
|
||||
return false;
|
||||
|
||||
memcpy(mac, p, ARP_HLEN);
|
||||
|
||||
return true;
|
||||
return !nvmem_cell_read(&mac_cell, mac, ARP_HLEN);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
|
|
|
@ -147,6 +147,35 @@ static int dm_test_eth_act(struct unit_test_state *uts)
|
|||
}
|
||||
DM_TEST(dm_test_eth_act, UT_TESTF_SCAN_FDT);
|
||||
|
||||
/* Ensure that all addresses are loaded properly */
|
||||
static int dm_test_ethaddr(struct unit_test_state *uts)
|
||||
{
|
||||
static const char *const addr[] = {
|
||||
"02:00:11:22:33:44",
|
||||
"02:00:11:22:33:48", /* dsa slave */
|
||||
"02:00:11:22:33:45",
|
||||
"02:00:11:22:33:48", /* dsa master */
|
||||
"02:00:11:22:33:46",
|
||||
"02:00:11:22:33:47",
|
||||
"02:00:11:22:33:48", /* dsa slave */
|
||||
"02:00:11:22:33:49",
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(addr); i++) {
|
||||
char addrname[10];
|
||||
|
||||
if (i)
|
||||
snprintf(addrname, sizeof(addrname), "eth%daddr", i + 1);
|
||||
else
|
||||
strcpy(addrname, "ethaddr");
|
||||
ut_asserteq_str(addr[i], env_get(addrname));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_ethaddr, UT_TESTF_SCAN_FDT);
|
||||
|
||||
/* The asserts include a return on fail; cleanup in the caller */
|
||||
static int _dm_test_eth_rotate1(struct unit_test_state *uts)
|
||||
{
|
||||
|
|
|
@ -184,7 +184,7 @@ static int dm_test_alias_highest_id(struct unit_test_state *uts)
|
|||
int ret;
|
||||
|
||||
ret = dev_read_alias_highest_id("ethernet");
|
||||
ut_asserteq(5, ret);
|
||||
ut_asserteq(8, ret);
|
||||
|
||||
ret = dev_read_alias_highest_id("gpio");
|
||||
ut_asserteq(3, ret);
|
||||
|
|
Loading…
Add table
Reference in a new issue