From eb46efa381d6dedb03af77d74b896ff40f1591b8 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 15 Mar 2020 15:03:07 +0100 Subject: net: smc911x: Inline all functions from header file Inline all the functions from the header file, as they are not used outside of the driver or the standalone EEPROM example. Note that this does introduce considerable amount of duplication in the standalone EEPROM example, however that one has to be rewritten anyway, roughly such that the SMC911x driver would expose DM EEPROM interface and the standalone example would use that. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada --- examples/standalone/smc911x_eeprom.c | 156 +++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) (limited to 'examples') diff --git a/examples/standalone/smc911x_eeprom.c b/examples/standalone/smc911x_eeprom.c index 2c05ed902d0..19ad9e6297c 100644 --- a/examples/standalone/smc911x_eeprom.c +++ b/examples/standalone/smc911x_eeprom.c @@ -18,8 +18,164 @@ #include #include #include +#include #include "../drivers/net/smc911x.h" +#define DRIVERNAME "smc911x" + +#if defined (CONFIG_SMC911X_32_BIT) && \ + defined (CONFIG_SMC911X_16_BIT) +#error "SMC911X: Only one of CONFIG_SMC911X_32_BIT and \ + CONFIG_SMC911X_16_BIT shall be set" +#endif + +struct chip_id { + u16 id; + char *name; +}; + +static const struct chip_id chip_ids[] = { + { CHIP_89218, "LAN89218" }, + { CHIP_9115, "LAN9115" }, + { CHIP_9116, "LAN9116" }, + { CHIP_9117, "LAN9117" }, + { CHIP_9118, "LAN9118" }, + { CHIP_9211, "LAN9211" }, + { CHIP_9215, "LAN9215" }, + { CHIP_9216, "LAN9216" }, + { CHIP_9217, "LAN9217" }, + { CHIP_9218, "LAN9218" }, + { CHIP_9220, "LAN9220" }, + { CHIP_9221, "LAN9221" }, + { 0, NULL }, +}; + +#if defined (CONFIG_SMC911X_32_BIT) +static inline u32 __smc911x_reg_read(struct eth_device *dev, u32 offset) +{ + return *(volatile u32*)(dev->iobase + offset); +} +u32 smc911x_reg_read(struct eth_device *dev, u32 offset) + __attribute__((weak, alias("__smc911x_reg_read"))); + +static inline void __smc911x_reg_write(struct eth_device *dev, + u32 offset, u32 val) +{ + *(volatile u32*)(dev->iobase + offset) = val; +} +void smc911x_reg_write(struct eth_device *dev, u32 offset, u32 val) + __attribute__((weak, alias("__smc911x_reg_write"))); +#elif defined (CONFIG_SMC911X_16_BIT) +static inline u32 smc911x_reg_read(struct eth_device *dev, u32 offset) +{ + volatile u16 *addr_16 = (u16 *)(dev->iobase + offset); + return ((*addr_16 & 0x0000ffff) | (*(addr_16 + 1) << 16)); +} +static inline void smc911x_reg_write(struct eth_device *dev, + u32 offset, u32 val) +{ + *(volatile u16 *)(dev->iobase + offset) = (u16)val; + *(volatile u16 *)(dev->iobase + offset + 2) = (u16)(val >> 16); +} +#else +#error "SMC911X: undefined bus width" +#endif /* CONFIG_SMC911X_16_BIT */ + +static u32 smc911x_get_mac_csr(struct eth_device *dev, u8 reg) +{ + while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) + ; + smc911x_reg_write(dev, MAC_CSR_CMD, + MAC_CSR_CMD_CSR_BUSY | MAC_CSR_CMD_R_NOT_W | reg); + while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) + ; + + return smc911x_reg_read(dev, MAC_CSR_DATA); +} + +static void smc911x_set_mac_csr(struct eth_device *dev, u8 reg, u32 data) +{ + while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) + ; + smc911x_reg_write(dev, MAC_CSR_DATA, data); + smc911x_reg_write(dev, MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | reg); + while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) + ; +} + +static int smc911x_detect_chip(struct eth_device *dev) +{ + unsigned long val, i; + + val = smc911x_reg_read(dev, BYTE_TEST); + if (val == 0xffffffff) { + /* Special case -- no chip present */ + return -1; + } else if (val != 0x87654321) { + printf(DRIVERNAME ": Invalid chip endian 0x%08lx\n", val); + return -1; + } + + val = smc911x_reg_read(dev, ID_REV) >> 16; + for (i = 0; chip_ids[i].id != 0; i++) { + if (chip_ids[i].id == val) break; + } + if (!chip_ids[i].id) { + printf(DRIVERNAME ": Unknown chip ID %04lx\n", val); + return -1; + } + + dev->priv = (void *)&chip_ids[i]; + + return 0; +} + +static void smc911x_reset(struct eth_device *dev) +{ + int timeout; + + /* + * Take out of PM setting first + * Device is already wake up if PMT_CTRL_READY bit is set + */ + if ((smc911x_reg_read(dev, PMT_CTRL) & PMT_CTRL_READY) == 0) { + /* Write to the bytetest will take out of powerdown */ + smc911x_reg_write(dev, BYTE_TEST, 0x0); + + timeout = 10; + + while (timeout-- && + !(smc911x_reg_read(dev, PMT_CTRL) & PMT_CTRL_READY)) + udelay(10); + if (timeout < 0) { + printf(DRIVERNAME + ": timeout waiting for PM restore\n"); + return; + } + } + + /* Disable interrupts */ + smc911x_reg_write(dev, INT_EN, 0); + + smc911x_reg_write(dev, HW_CFG, HW_CFG_SRST); + + timeout = 1000; + while (timeout-- && smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY) + udelay(10); + + if (timeout < 0) { + printf(DRIVERNAME ": reset timeout\n"); + return; + } + + /* Reset the FIFO level and flow control settings */ + smc911x_set_mac_csr(dev, FLOW, FLOW_FCPT | FLOW_FCEN); + smc911x_reg_write(dev, AFC_CFG, 0x0050287F); + + /* Set to LED outputs */ + smc911x_reg_write(dev, GPIO_CFG, 0x70070000); +} + /** * smsc_ctrlc - detect press of CTRL+C (common ctrlc() isnt exported!?) */ -- cgit v1.3.1 From f0d73f5cd0ec0967fffcdf130a8c016262a216c4 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 15 Mar 2020 14:38:59 +0100 Subject: net: smc911x: Drop weak alias from 32bit accessors These accessors are not overridden by any board, and even if they were, this is something which should be handled via DM now, so remove the weak alias option. Moreover, drop the inline keyword, as the compiler can decide better. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada --- drivers/net/smc911x.c | 14 ++++---------- examples/standalone/smc911x_eeprom.c | 16 +++++----------- 2 files changed, 9 insertions(+), 21 deletions(-) (limited to 'examples') diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index ff285f14b4b..effee5367ca 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -44,28 +44,22 @@ static const struct chip_id chip_ids[] = { #endif #if defined (CONFIG_SMC911X_32_BIT) -static inline u32 __smc911x_reg_read(struct eth_device *dev, u32 offset) +static u32 smc911x_reg_read(struct eth_device *dev, u32 offset) { return *(volatile u32*)(dev->iobase + offset); } -u32 smc911x_reg_read(struct eth_device *dev, u32 offset) - __attribute__((weak, alias("__smc911x_reg_read"))); -static inline void __smc911x_reg_write(struct eth_device *dev, - u32 offset, u32 val) +static void smc911x_reg_write(struct eth_device *dev, u32 offset, u32 val) { *(volatile u32*)(dev->iobase + offset) = val; } -void smc911x_reg_write(struct eth_device *dev, u32 offset, u32 val) - __attribute__((weak, alias("__smc911x_reg_write"))); #elif defined (CONFIG_SMC911X_16_BIT) -static inline u32 smc911x_reg_read(struct eth_device *dev, u32 offset) +static u32 smc911x_reg_read(struct eth_device *dev, u32 offset) { volatile u16 *addr_16 = (u16 *)(dev->iobase + offset); return ((*addr_16 & 0x0000ffff) | (*(addr_16 + 1) << 16)); } -static inline void smc911x_reg_write(struct eth_device *dev, - u32 offset, u32 val) +static void smc911x_reg_write(struct eth_device *dev, u32 offset, u32 val) { *(volatile u16 *)(dev->iobase + offset) = (u16)val; *(volatile u16 *)(dev->iobase + offset + 2) = (u16)(val >> 16); diff --git a/examples/standalone/smc911x_eeprom.c b/examples/standalone/smc911x_eeprom.c index 19ad9e6297c..270588bcf5e 100644 --- a/examples/standalone/smc911x_eeprom.c +++ b/examples/standalone/smc911x_eeprom.c @@ -51,28 +51,22 @@ static const struct chip_id chip_ids[] = { }; #if defined (CONFIG_SMC911X_32_BIT) -static inline u32 __smc911x_reg_read(struct eth_device *dev, u32 offset) +static u32 smc911x_reg_read(struct eth_device *dev, u32 offset) { return *(volatile u32*)(dev->iobase + offset); } -u32 smc911x_reg_read(struct eth_device *dev, u32 offset) - __attribute__((weak, alias("__smc911x_reg_read"))); -static inline void __smc911x_reg_write(struct eth_device *dev, - u32 offset, u32 val) +static void smc911x_reg_write(struct eth_device *dev, u32 offset, u32 val) { *(volatile u32*)(dev->iobase + offset) = val; } -void smc911x_reg_write(struct eth_device *dev, u32 offset, u32 val) - __attribute__((weak, alias("__smc911x_reg_write"))); #elif defined (CONFIG_SMC911X_16_BIT) -static inline u32 smc911x_reg_read(struct eth_device *dev, u32 offset) +static u32 smc911x_reg_read(struct eth_device *dev, u32 offset) { volatile u16 *addr_16 = (u16 *)(dev->iobase + offset); - return ((*addr_16 & 0x0000ffff) | (*(addr_16 + 1) << 16)); + return (*addr_16 & 0x0000ffff) | (*(addr_16 + 1) << 16); } -static inline void smc911x_reg_write(struct eth_device *dev, - u32 offset, u32 val) +static void smc911x_reg_write(struct eth_device *dev, u32 offset, u32 val) { *(volatile u16 *)(dev->iobase + offset) = (u16)val; *(volatile u16 *)(dev->iobase + offset + 2) = (u16)(val >> 16); -- cgit v1.3.1 From 8148693b988fb36463dbc12cef4b7947acae9846 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 15 Mar 2020 17:39:01 +0100 Subject: net: smc911x: Add DM support Add support for U-Boot DM and DT probing. Furthermore, build the SMC911x standalone EEPROM example only for the non-DM case, as it is not converted yet. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada --- drivers/net/Kconfig | 2 + drivers/net/smc911x.c | 115 +++++++++++++++++++++++++++++++++++++++++++ examples/standalone/Makefile | 5 +- 3 files changed, 121 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index bc518f218da..a2587a29e16 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -388,11 +388,13 @@ config SMC911X if SMC911X +if !DM_ETH config SMC911X_BASE hex "SMC911X Base Address" help Define this to hold the physical address of the device (I/O space) +endif #DM_ETH choice prompt "SMC911X bus width" diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 95f955f6d8a..45ecd6a2633 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -21,7 +21,9 @@ struct chip_id { }; struct smc911x_priv { +#ifndef CONFIG_DM_ETH struct eth_device dev; +#endif phys_addr_t iobase; const struct chip_id *chipid; unsigned char enetaddr[6]; @@ -370,6 +372,8 @@ static int smc911x_recv_common(struct smc911x_priv *priv, u32 *data) return pktlen; } +#ifndef CONFIG_DM_ETH + #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) /* wrapper for smc911x_eth_phy_read */ static int smc911x_miiphy_read(struct mii_dev *bus, int phy, int devad, @@ -494,6 +498,7 @@ int smc911x_initialize(u8 dev_num, int base_addr) priv->enetaddr[3] = addrl >> 24; priv->enetaddr[4] = addrh; priv->enetaddr[5] = addrh >> 8; + memcpy(priv->dev.enetaddr, priv->enetaddr, 6); } priv->dev.init = smc911x_init; @@ -516,3 +521,113 @@ err_detect: free(priv); return ret; } + +#else /* ifdef CONFIG_DM_ETH */ + +static int smc911x_start(struct udevice *dev) +{ + struct eth_pdata *plat = dev_get_platdata(dev); + struct smc911x_priv *priv = dev_get_priv(dev); + + memcpy(priv->enetaddr, plat->enetaddr, sizeof(plat->enetaddr)); + + return smc911x_init_common(priv); +} + +static void smc911x_stop(struct udevice *dev) +{ + struct smc911x_priv *priv = dev_get_priv(dev); + + smc911x_halt_common(priv); +} + +static int smc911x_send(struct udevice *dev, void *packet, int length) +{ + struct smc911x_priv *priv = dev_get_priv(dev); + int ret; + + ret = smc911x_send_common(priv, packet, length); + + return ret ? 0 : -ETIMEDOUT; +} + +static int smc911x_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct smc911x_priv *priv = dev_get_priv(dev); + u32 *data = (u32 *)net_rx_packets[0]; + int ret; + + ret = smc911x_recv_common(priv, data); + if (ret) + *packetp = (void *)data; + + return ret ? ret : -EAGAIN; +} + +static int smc911x_bind(struct udevice *dev) +{ + return device_set_name(dev, dev->name); +} + +static int smc911x_probe(struct udevice *dev) +{ + struct smc911x_priv *priv = dev_get_priv(dev); + unsigned long addrh, addrl; + int ret; + + /* Try to detect chip. Will fail if not present. */ + ret = smc911x_detect_chip(priv); + if (ret) + return ret; + + addrh = smc911x_get_mac_csr(priv, ADDRH); + addrl = smc911x_get_mac_csr(priv, ADDRL); + if (!(addrl == 0xffffffff && addrh == 0x0000ffff)) { + /* address is obtained from optional eeprom */ + priv->enetaddr[0] = addrl; + priv->enetaddr[1] = addrl >> 8; + priv->enetaddr[2] = addrl >> 16; + priv->enetaddr[3] = addrl >> 24; + priv->enetaddr[4] = addrh; + priv->enetaddr[5] = addrh >> 8; + } + + return 0; +} + +static int smc911x_ofdata_to_platdata(struct udevice *dev) +{ + struct smc911x_priv *priv = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + + pdata->iobase = devfdt_get_addr(dev); + priv->iobase = pdata->iobase; + + return 0; +} + +static const struct eth_ops smc911x_ops = { + .start = smc911x_start, + .send = smc911x_send, + .recv = smc911x_recv, + .stop = smc911x_stop, +}; + +static const struct udevice_id smc911x_ids[] = { + { .compatible = "smsc,lan9115" }, + { } +}; + +U_BOOT_DRIVER(smc911x) = { + .name = "eth_smc911x", + .id = UCLASS_ETH, + .of_match = smc911x_ids, + .bind = smc911x_bind, + .ofdata_to_platdata = smc911x_ofdata_to_platdata, + .probe = smc911x_probe, + .ops = &smc911x_ops, + .priv_auto_alloc_size = sizeof(struct smc911x_priv), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; +#endif diff --git a/examples/standalone/Makefile b/examples/standalone/Makefile index 779e2528b77..4a34813804f 100644 --- a/examples/standalone/Makefile +++ b/examples/standalone/Makefile @@ -5,10 +5,13 @@ extra-y := hello_world extra-$(CONFIG_SMC91111) += smc91111_eeprom -extra-$(CONFIG_SMC911X) += smc911x_eeprom extra-$(CONFIG_SPI_FLASH_ATMEL) += atmel_df_pow2 extra-$(CONFIG_PPC) += sched +ifndef CONFIG_DM_ETH +extra-$(CONFIG_SMC911X) += smc911x_eeprom +endif + # # Some versions of make do not handle trailing white spaces properly; # leading to build failures. The problem was found with GNU Make 3.80. -- cgit v1.3.1