From patchwork Wed Mar 25 16:46:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Vasut X-Patchwork-Id: 244263 List-Id: U-Boot discussion From: marek.vasut at gmail.com (Marek Vasut) Date: Wed, 25 Mar 2020 17:46:41 +0100 Subject: [PATCH V4 01/13] net: smc911x: Remove pkt_data_{push,pull} In-Reply-To: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> References: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> Message-ID: <20200325164653.112079-2-marek.vasut+renesas@gmail.com> These functions are never used and are likely a pre-DM remnant from times long past, just remove them. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada --- V2: No change V3: No change V4: No change --- drivers/net/smc911x.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 257b0385c2..24b4eaeb3f 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -13,11 +13,6 @@ #include "smc911x.h" -u32 pkt_data_pull(struct eth_device *dev, u32 addr) \ - __attribute__ ((weak, alias ("smc911x_reg_read"))); -void pkt_data_push(struct eth_device *dev, u32 addr, u32 val) \ - __attribute__ ((weak, alias ("smc911x_reg_write"))); - static void smc911x_handle_mac_address(struct eth_device *dev) { unsigned long addrh, addrl; @@ -157,7 +152,7 @@ static int smc911x_send(struct eth_device *dev, void *packet, int length) tmplen = (length + 3) / 4; while (tmplen--) - pkt_data_push(dev, TX_DATA_FIFO, *data++); + smc911x_reg_write(dev, TX_DATA_FIFO, *data++); /* wait for transmission */ while (!((smc911x_reg_read(dev, TX_FIFO_INF) & @@ -203,7 +198,7 @@ static int smc911x_rx(struct eth_device *dev) tmplen = (pktlen + 3) / 4; while (tmplen--) - *data++ = pkt_data_pull(dev, RX_DATA_FIFO); + *data++ = smc911x_reg_read(dev, RX_DATA_FIFO); if (status & RX_STS_ES) printf(DRIVERNAME From patchwork Wed Mar 25 16:46:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Vasut X-Patchwork-Id: 244264 List-Id: U-Boot discussion From: marek.vasut at gmail.com (Marek Vasut) Date: Wed, 25 Mar 2020 17:46:42 +0100 Subject: [PATCH V4 02/13] net: smc911x: Replace malloc()+memset() with calloc() In-Reply-To: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> References: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> Message-ID: <20200325164653.112079-3-marek.vasut+renesas@gmail.com> Replace combination of malloc()+memset() with calloc() as the behavior is exactly the same and the amount of code is reduced. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada --- V2: - Use kzalloc() - Return -ENOMEM on alloc fail V3: - Switch back to calloc(), it's not worth pulling in all the linux-compatibility complexity V4: No change --- drivers/net/smc911x.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 24b4eaeb3f..2c72e3469d 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -242,11 +242,9 @@ int smc911x_initialize(u8 dev_num, int base_addr) unsigned long addrl, addrh; struct eth_device *dev; - dev = malloc(sizeof(*dev)); - if (!dev) { - return -1; - } - memset(dev, 0, sizeof(*dev)); + dev = calloc(1, sizeof(*dev)); + if (!dev) + return -ENOMEM; dev->iobase = base_addr; From patchwork Wed Mar 25 16:46:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Vasut X-Patchwork-Id: 244265 List-Id: U-Boot discussion From: marek.vasut at gmail.com (Marek Vasut) Date: Wed, 25 Mar 2020 17:46:43 +0100 Subject: [PATCH V4 03/13] net: smc911x: Rename smc911x_rx() to smc911x_recv() In-Reply-To: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> References: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> Message-ID: <20200325164653.112079-4-marek.vasut+renesas@gmail.com> Rename the function to keep the naming scheme consistent, no functional change. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada --- V2: No change V3: No change V4: No change --- drivers/net/smc911x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 2c72e3469d..6da6c89546 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -184,7 +184,7 @@ static void smc911x_halt(struct eth_device *dev) smc911x_handle_mac_address(dev); } -static int smc911x_rx(struct eth_device *dev) +static int smc911x_recv(struct eth_device *dev) { u32 *data = (u32 *)net_rx_packets[0]; u32 pktlen, tmplen; @@ -269,7 +269,7 @@ int smc911x_initialize(u8 dev_num, int base_addr) dev->init = smc911x_init; dev->halt = smc911x_halt; dev->send = smc911x_send; - dev->recv = smc911x_rx; + dev->recv = smc911x_recv; sprintf(dev->name, "%s-%hu", DRIVERNAME, dev_num); eth_register(dev); From patchwork Wed Mar 25 16:46:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Vasut X-Patchwork-Id: 244266 List-Id: U-Boot discussion From: marek.vasut at gmail.com (Marek Vasut) Date: Wed, 25 Mar 2020 17:46:44 +0100 Subject: [PATCH V4 04/13] net: smc911x: Invert the logic in smc911x_miiphy_{read, write}() In-Reply-To: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> References: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> Message-ID: <20200325164653.112079-5-marek.vasut+renesas@gmail.com> Invert the logic in the aforementioned functions to reduce indent, no functional change. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada --- V2: No change V3: No change V4: No change --- drivers/net/smc911x.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 6da6c89546..ceb4f81215 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -216,24 +216,29 @@ static int smc911x_recv(struct eth_device *dev) static int smc911x_miiphy_read(struct mii_dev *bus, int phy, int devad, int reg) { - u16 val = 0; struct eth_device *dev = eth_get_dev_by_name(bus->name); - if (dev) { - int retval = smc911x_eth_phy_read(dev, phy, reg, &val); - if (retval < 0) - return retval; - return val; - } - return -ENODEV; + u16 val = 0; + int ret; + + if (!dev) + return -ENODEV; + + ret = smc911x_eth_phy_read(dev, phy, reg, &val); + if (ret < 0) + return ret; + + return val; } /* wrapper for smc911x_eth_phy_write */ static int smc911x_miiphy_write(struct mii_dev *bus, int phy, int devad, int reg, u16 val) { struct eth_device *dev = eth_get_dev_by_name(bus->name); - if (dev) - return smc911x_eth_phy_write(dev, phy, reg, val); - return -ENODEV; + + if (!dev) + return -ENODEV; + + return smc911x_eth_phy_write(dev, phy, reg, val); } #endif From patchwork Wed Mar 25 16:46:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Vasut X-Patchwork-Id: 244267 List-Id: U-Boot discussion From: marek.vasut at gmail.com (Marek Vasut) Date: Wed, 25 Mar 2020 17:46:45 +0100 Subject: [PATCH V4 05/13] net: smc911x: Fix potential memleak() in init fail path In-Reply-To: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> References: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> Message-ID: <20200325164653.112079-6-marek.vasut+renesas@gmail.com> Fix memleak in the init fail path, where if allocation or registration of MDIO bus fails, then ethernet interface is not unregistered and the private data are not freed, yet the probe function reports a failure. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada --- V2: No change V3: No change V4: No change --- drivers/net/smc911x.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index ceb4f81215..4459da5945 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -282,15 +282,23 @@ int smc911x_initialize(u8 dev_num, int base_addr) #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) int retval; struct mii_dev *mdiodev = mdio_alloc(); - if (!mdiodev) + if (!mdiodev) { + eth_unregister(dev); + free(dev); return -ENOMEM; + } + strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN); mdiodev->read = smc911x_miiphy_read; mdiodev->write = smc911x_miiphy_write; retval = mdio_register(mdiodev); - if (retval < 0) + if (retval < 0) { + mdio_free(mdiodev); + eth_unregister(dev); + free(dev); return retval; + } #endif return 1; From patchwork Wed Mar 25 16:46:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Vasut X-Patchwork-Id: 244268 List-Id: U-Boot discussion From: marek.vasut at gmail.com (Marek Vasut) Date: Wed, 25 Mar 2020 17:46:46 +0100 Subject: [PATCH V4 06/13] net: smc911x: Pull MII registration into separate function In-Reply-To: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> References: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> Message-ID: <20200325164653.112079-7-marek.vasut+renesas@gmail.com> Pull the MII interface registration into separate function to avoid the ifdeffery in smc911x_initialize(). Moreover, adjust the fail path such that we use goto labels. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada --- V2: New patch V3: No change V4: No change --- drivers/net/smc911x.c | 64 +++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 4459da5945..65c25f3bfd 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -240,12 +240,39 @@ static int smc911x_miiphy_write(struct mii_dev *bus, int phy, int devad, return smc911x_eth_phy_write(dev, phy, reg, val); } + +static int smc911x_initialize_mii(struct eth_device *dev) +{ + struct mii_dev *mdiodev = mdio_alloc(); + int ret; + + if (!mdiodev) + return -ENOMEM; + + strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN); + mdiodev->read = smc911x_miiphy_read; + mdiodev->write = smc911x_miiphy_write; + + ret = mdio_register(mdiodev); + if (ret < 0) { + mdio_free(mdiodev); + return ret; + } + + return 0; +} +#else +static int smc911x_initialize_mii(struct eth_device *dev) +{ + return 0; +} #endif int smc911x_initialize(u8 dev_num, int base_addr) { unsigned long addrl, addrh; struct eth_device *dev; + int ret; dev = calloc(1, sizeof(*dev)); if (!dev) @@ -254,9 +281,10 @@ int smc911x_initialize(u8 dev_num, int base_addr) dev->iobase = base_addr; /* Try to detect chip. Will fail if not present. */ - if (smc911x_detect_chip(dev)) { - free(dev); - return 0; + ret = smc911x_detect_chip(dev); + if (ret) { + ret = 0; /* Card not detected is not an error */ + goto err_detect; } addrh = smc911x_get_mac_csr(dev, ADDRH); @@ -279,27 +307,15 @@ int smc911x_initialize(u8 dev_num, int base_addr) eth_register(dev); -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) - int retval; - struct mii_dev *mdiodev = mdio_alloc(); - if (!mdiodev) { - eth_unregister(dev); - free(dev); - return -ENOMEM; - } - - strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN); - mdiodev->read = smc911x_miiphy_read; - mdiodev->write = smc911x_miiphy_write; - - retval = mdio_register(mdiodev); - if (retval < 0) { - mdio_free(mdiodev); - eth_unregister(dev); - free(dev); - return retval; - } -#endif + ret = smc911x_initialize_mii(dev); + if (ret) + goto err_mii; return 1; + +err_mii: + eth_unregister(dev); +err_detect: + free(dev); + return ret; } From patchwork Wed Mar 25 16:46:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Vasut X-Patchwork-Id: 244269 List-Id: U-Boot discussion From: marek.vasut at gmail.com (Marek Vasut) Date: Wed, 25 Mar 2020 17:46:47 +0100 Subject: [PATCH V4 07/13] net: smc911x: Inline all functions from header file In-Reply-To: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> References: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> Message-ID: <20200325164653.112079-8-marek.vasut+renesas@gmail.com> 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 --- V2: No change V3: No change V4: No change --- drivers/net/smc911x.c | 157 ++++++++++++++++++++++++++- drivers/net/smc911x.h | 157 --------------------------- examples/standalone/smc911x_eeprom.c | 156 ++++++++++++++++++++++++++ 3 files changed, 312 insertions(+), 158 deletions(-) diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 65c25f3bfd..ff285f14b4 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -10,9 +10,165 @@ #include #include #include +#include #include "smc911x.h" +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 }, +}; + +#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 + +#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); +} + static void smc911x_handle_mac_address(struct eth_device *dev) { unsigned long addrh, addrl; @@ -117,7 +273,6 @@ static void smc911x_enable(struct eth_device *dev) smc911x_set_mac_csr(dev, MAC_CR, MAC_CR_TXEN | MAC_CR_RXEN | MAC_CR_HBDIS); - } static int smc911x_init(struct eth_device *dev, bd_t * bd) diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h index 3145fbde2b..ce66900f4c 100644 --- a/drivers/net/smc911x.h +++ b/drivers/net/smc911x.h @@ -8,47 +8,6 @@ #ifndef _SMC911X_H_ #define _SMC911X_H_ -#include - -#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 - -#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 */ - /* Below are the register offsets and bit definitions * of the Lan911x memory space */ @@ -380,120 +339,4 @@ static inline void smc911x_reg_write(struct eth_device *dev, #define CHIP_9220 0x9220 #define CHIP_9221 0x9221 -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 }, -}; - -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); -} - #endif diff --git a/examples/standalone/smc911x_eeprom.c b/examples/standalone/smc911x_eeprom.c index 2c05ed902d..19ad9e6297 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!?) */ From patchwork Wed Mar 25 16:46:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Vasut X-Patchwork-Id: 244270 List-Id: U-Boot discussion From: marek.vasut at gmail.com (Marek Vasut) Date: Wed, 25 Mar 2020 17:46:48 +0100 Subject: [PATCH V4 08/13] net: smc911x: Drop weak alias from 32bit accessors In-Reply-To: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> References: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> Message-ID: <20200325164653.112079-9-marek.vasut+renesas@gmail.com> 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 --- V2: s at overriden@overridden@ V3: No change V4: No change --- drivers/net/smc911x.c | 14 ++++---------- examples/standalone/smc911x_eeprom.c | 16 +++++----------- 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index ff285f14b4..effee5367c 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 19ad9e6297..270588bcf5 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); From patchwork Wed Mar 25 16:46:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Vasut X-Patchwork-Id: 244272 List-Id: U-Boot discussion From: marek.vasut at gmail.com (Marek Vasut) Date: Wed, 25 Mar 2020 17:46:49 +0100 Subject: [PATCH V4 09/13] net: smc911x: Convert IO accessors to {read, write}{w, l}() In-Reply-To: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> References: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> Message-ID: <20200325164653.112079-10-marek.vasut+renesas@gmail.com> Convert the IO accessors to standard ones instead of using volatile void pointers, as those do not cover all the bus access details. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada --- V2: No change V3: No change V4: No change --- drivers/net/smc911x.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index effee5367c..364f8c5da8 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "smc911x.h" @@ -46,23 +47,23 @@ static const struct chip_id chip_ids[] = { #if defined (CONFIG_SMC911X_32_BIT) static u32 smc911x_reg_read(struct eth_device *dev, u32 offset) { - return *(volatile u32*)(dev->iobase + offset); + return readl(dev->iobase + offset); } static void smc911x_reg_write(struct eth_device *dev, u32 offset, u32 val) { - *(volatile u32*)(dev->iobase + offset) = val; + writel(val, dev->iobase + offset); } #elif defined (CONFIG_SMC911X_16_BIT) 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 (readw(dev->iobase + offset) & 0xffff) | + (readw(dev->iobase + offset + 2) << 16); } 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); + writew(val & 0xffff, dev->iobase + offset); + writew(val >> 16, dev->iobase + offset + 2); } #else #error "SMC911X: undefined bus width" From patchwork Wed Mar 25 16:46:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Vasut X-Patchwork-Id: 244275 List-Id: U-Boot discussion From: marek.vasut at gmail.com (Marek Vasut) Date: Wed, 25 Mar 2020 17:46:50 +0100 Subject: [PATCH V4 10/13] net: smc911x: Pass around driver private data In-Reply-To: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> References: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> Message-ID: <20200325164653.112079-11-marek.vasut+renesas@gmail.com> Introduce a private data structure for this driver with embedded struct eth_device and pass it around. This prepares the driver to work with both DM and non-DM systems. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada --- V2: No change V3: No change V4: Repair the calloc conversion again --- drivers/net/smc911x.c | 232 ++++++++++++++++++++++-------------------- 1 file changed, 124 insertions(+), 108 deletions(-) diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 364f8c5da8..07066ce108 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -20,6 +20,13 @@ struct chip_id { char *name; }; +struct smc911x_priv { + struct eth_device dev; + phys_addr_t iobase; + const struct chip_id *chipid; + unsigned char enetaddr[6]; +}; + static const struct chip_id chip_ids[] = { { CHIP_89218, "LAN89218" }, { CHIP_9115, "LAN9115" }, @@ -45,57 +52,57 @@ static const struct chip_id chip_ids[] = { #endif #if defined (CONFIG_SMC911X_32_BIT) -static u32 smc911x_reg_read(struct eth_device *dev, u32 offset) +static u32 smc911x_reg_read(struct smc911x_priv *priv, u32 offset) { - return readl(dev->iobase + offset); + return readl(priv->iobase + offset); } -static void smc911x_reg_write(struct eth_device *dev, u32 offset, u32 val) +static void smc911x_reg_write(struct smc911x_priv *priv, u32 offset, u32 val) { - writel(val, dev->iobase + offset); + writel(val, priv->iobase + offset); } #elif defined (CONFIG_SMC911X_16_BIT) -static u32 smc911x_reg_read(struct eth_device *dev, u32 offset) +static u32 smc911x_reg_read(struct smc911x_priv *priv, u32 offset) { - return (readw(dev->iobase + offset) & 0xffff) | - (readw(dev->iobase + offset + 2) << 16); + return (readw(priv->iobase + offset) & 0xffff) | + (readw(priv->iobase + offset + 2) << 16); } -static void smc911x_reg_write(struct eth_device *dev, u32 offset, u32 val) +static void smc911x_reg_write(struct smc911x_priv *priv, u32 offset, u32 val) { - writew(val & 0xffff, dev->iobase + offset); - writew(val >> 16, dev->iobase + offset + 2); + writew(val & 0xffff, priv->iobase + offset); + writew(val >> 16, priv->iobase + offset + 2); } #else #error "SMC911X: undefined bus width" #endif /* CONFIG_SMC911X_16_BIT */ -static u32 smc911x_get_mac_csr(struct eth_device *dev, u8 reg) +static u32 smc911x_get_mac_csr(struct smc911x_priv *priv, u8 reg) { - while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) + while (smc911x_reg_read(priv, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) ; - smc911x_reg_write(dev, MAC_CSR_CMD, + smc911x_reg_write(priv, 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) + while (smc911x_reg_read(priv, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) ; - return smc911x_reg_read(dev, MAC_CSR_DATA); + return smc911x_reg_read(priv, MAC_CSR_DATA); } -static void smc911x_set_mac_csr(struct eth_device *dev, u8 reg, u32 data) +static void smc911x_set_mac_csr(struct smc911x_priv *priv, u8 reg, u32 data) { - while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) + while (smc911x_reg_read(priv, 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) + smc911x_reg_write(priv, MAC_CSR_DATA, data); + smc911x_reg_write(priv, MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | reg); + while (smc911x_reg_read(priv, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) ; } -static int smc911x_detect_chip(struct eth_device *dev) +static int smc911x_detect_chip(struct smc911x_priv *priv) { unsigned long val, i; - val = smc911x_reg_read(dev, BYTE_TEST); + val = smc911x_reg_read(priv, BYTE_TEST); if (val == 0xffffffff) { /* Special case -- no chip present */ return -1; @@ -104,7 +111,7 @@ static int smc911x_detect_chip(struct eth_device *dev) return -1; } - val = smc911x_reg_read(dev, ID_REV) >> 16; + val = smc911x_reg_read(priv, ID_REV) >> 16; for (i = 0; chip_ids[i].id != 0; i++) { if (chip_ids[i].id == val) break; } @@ -113,12 +120,12 @@ static int smc911x_detect_chip(struct eth_device *dev) return -1; } - dev->priv = (void *)&chip_ids[i]; + priv->chipid = &chip_ids[i]; return 0; } -static void smc911x_reset(struct eth_device *dev) +static void smc911x_reset(struct smc911x_priv *priv) { int timeout; @@ -126,14 +133,14 @@ static void smc911x_reset(struct eth_device *dev) * 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) { + if ((smc911x_reg_read(priv, PMT_CTRL) & PMT_CTRL_READY) == 0) { /* Write to the bytetest will take out of powerdown */ - smc911x_reg_write(dev, BYTE_TEST, 0x0); + smc911x_reg_write(priv, BYTE_TEST, 0x0); timeout = 10; while (timeout-- && - !(smc911x_reg_read(dev, PMT_CTRL) & PMT_CTRL_READY)) + !(smc911x_reg_read(priv, PMT_CTRL) & PMT_CTRL_READY)) udelay(10); if (timeout < 0) { printf(DRIVERNAME @@ -143,12 +150,12 @@ static void smc911x_reset(struct eth_device *dev) } /* Disable interrupts */ - smc911x_reg_write(dev, INT_EN, 0); + smc911x_reg_write(priv, INT_EN, 0); - smc911x_reg_write(dev, HW_CFG, HW_CFG_SRST); + smc911x_reg_write(priv, HW_CFG, HW_CFG_SRST); timeout = 1000; - while (timeout-- && smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY) + while (timeout-- && smc911x_reg_read(priv, E2P_CMD) & E2P_CMD_EPC_BUSY) udelay(10); if (timeout < 0) { @@ -157,83 +164,83 @@ static void smc911x_reset(struct eth_device *dev) } /* 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); + smc911x_set_mac_csr(priv, FLOW, FLOW_FCPT | FLOW_FCEN); + smc911x_reg_write(priv, AFC_CFG, 0x0050287F); /* Set to LED outputs */ - smc911x_reg_write(dev, GPIO_CFG, 0x70070000); + smc911x_reg_write(priv, GPIO_CFG, 0x70070000); } -static void smc911x_handle_mac_address(struct eth_device *dev) +static void smc911x_handle_mac_address(struct smc911x_priv *priv) { unsigned long addrh, addrl; - uchar *m = dev->enetaddr; + unsigned char *m = priv->enetaddr; addrl = m[0] | (m[1] << 8) | (m[2] << 16) | (m[3] << 24); addrh = m[4] | (m[5] << 8); - smc911x_set_mac_csr(dev, ADDRL, addrl); - smc911x_set_mac_csr(dev, ADDRH, addrh); + smc911x_set_mac_csr(priv, ADDRL, addrl); + smc911x_set_mac_csr(priv, ADDRH, addrh); printf(DRIVERNAME ": MAC %pM\n", m); } -static int smc911x_eth_phy_read(struct eth_device *dev, +static int smc911x_eth_phy_read(struct smc911x_priv *priv, u8 phy, u8 reg, u16 *val) { - while (smc911x_get_mac_csr(dev, MII_ACC) & MII_ACC_MII_BUSY) + while (smc911x_get_mac_csr(priv, MII_ACC) & MII_ACC_MII_BUSY) ; - smc911x_set_mac_csr(dev, MII_ACC, phy << 11 | reg << 6 | + smc911x_set_mac_csr(priv, MII_ACC, phy << 11 | reg << 6 | MII_ACC_MII_BUSY); - while (smc911x_get_mac_csr(dev, MII_ACC) & MII_ACC_MII_BUSY) + while (smc911x_get_mac_csr(priv, MII_ACC) & MII_ACC_MII_BUSY) ; - *val = smc911x_get_mac_csr(dev, MII_DATA); + *val = smc911x_get_mac_csr(priv, MII_DATA); return 0; } -static int smc911x_eth_phy_write(struct eth_device *dev, +static int smc911x_eth_phy_write(struct smc911x_priv *priv, u8 phy, u8 reg, u16 val) { - while (smc911x_get_mac_csr(dev, MII_ACC) & MII_ACC_MII_BUSY) + while (smc911x_get_mac_csr(priv, MII_ACC) & MII_ACC_MII_BUSY) ; - smc911x_set_mac_csr(dev, MII_DATA, val); - smc911x_set_mac_csr(dev, MII_ACC, + smc911x_set_mac_csr(priv, MII_DATA, val); + smc911x_set_mac_csr(priv, MII_ACC, phy << 11 | reg << 6 | MII_ACC_MII_BUSY | MII_ACC_MII_WRITE); - while (smc911x_get_mac_csr(dev, MII_ACC) & MII_ACC_MII_BUSY) + while (smc911x_get_mac_csr(priv, MII_ACC) & MII_ACC_MII_BUSY) ; return 0; } -static int smc911x_phy_reset(struct eth_device *dev) +static int smc911x_phy_reset(struct smc911x_priv *priv) { u32 reg; - reg = smc911x_reg_read(dev, PMT_CTRL); + reg = smc911x_reg_read(priv, PMT_CTRL); reg &= ~0xfffff030; reg |= PMT_CTRL_PHY_RST; - smc911x_reg_write(dev, PMT_CTRL, reg); + smc911x_reg_write(priv, PMT_CTRL, reg); mdelay(100); return 0; } -static void smc911x_phy_configure(struct eth_device *dev) +static void smc911x_phy_configure(struct smc911x_priv *priv) { int timeout; u16 status; - smc911x_phy_reset(dev); + smc911x_phy_reset(priv); - smc911x_eth_phy_write(dev, 1, MII_BMCR, BMCR_RESET); + smc911x_eth_phy_write(priv, 1, MII_BMCR, BMCR_RESET); mdelay(1); - smc911x_eth_phy_write(dev, 1, MII_ADVERTISE, 0x01e1); - smc911x_eth_phy_write(dev, 1, MII_BMCR, BMCR_ANENABLE | + smc911x_eth_phy_write(priv, 1, MII_ADVERTISE, 0x01e1); + smc911x_eth_phy_write(priv, 1, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART); timeout = 5000; @@ -242,7 +249,7 @@ static void smc911x_phy_configure(struct eth_device *dev) if ((timeout--) == 0) goto err_out; - if (smc911x_eth_phy_read(dev, 1, MII_BMSR, &status) != 0) + if (smc911x_eth_phy_read(priv, 1, MII_BMSR, &status) != 0) goto err_out; } while (!(status & BMSR_LSTATUS)); @@ -254,64 +261,66 @@ err_out: printf(DRIVERNAME ": autonegotiation timed out\n"); } -static void smc911x_enable(struct eth_device *dev) +static void smc911x_enable(struct smc911x_priv *priv) { /* Enable TX */ - smc911x_reg_write(dev, HW_CFG, 8 << 16 | HW_CFG_SF); + smc911x_reg_write(priv, HW_CFG, 8 << 16 | HW_CFG_SF); - smc911x_reg_write(dev, GPT_CFG, GPT_CFG_TIMER_EN | 10000); + smc911x_reg_write(priv, GPT_CFG, GPT_CFG_TIMER_EN | 10000); - smc911x_reg_write(dev, TX_CFG, TX_CFG_TX_ON); + smc911x_reg_write(priv, TX_CFG, TX_CFG_TX_ON); /* no padding to start of packets */ - smc911x_reg_write(dev, RX_CFG, 0); + smc911x_reg_write(priv, RX_CFG, 0); - smc911x_set_mac_csr(dev, MAC_CR, MAC_CR_TXEN | MAC_CR_RXEN | + smc911x_set_mac_csr(priv, MAC_CR, MAC_CR_TXEN | MAC_CR_RXEN | MAC_CR_HBDIS); } static int smc911x_init(struct eth_device *dev, bd_t * bd) { - struct chip_id *id = dev->priv; + struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev); + const struct chip_id *id = priv->chipid; printf(DRIVERNAME ": detected %s controller\n", id->name); - smc911x_reset(dev); + smc911x_reset(priv); /* Configure the PHY, initialize the link state */ - smc911x_phy_configure(dev); + smc911x_phy_configure(priv); - smc911x_handle_mac_address(dev); + smc911x_handle_mac_address(priv); /* Turn on Tx + Rx */ - smc911x_enable(dev); + smc911x_enable(priv); return 0; } static int smc911x_send(struct eth_device *dev, void *packet, int length) { + struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev); u32 *data = (u32*)packet; u32 tmplen; u32 status; - smc911x_reg_write(dev, TX_DATA_FIFO, TX_CMD_A_INT_FIRST_SEG | + smc911x_reg_write(priv, TX_DATA_FIFO, TX_CMD_A_INT_FIRST_SEG | TX_CMD_A_INT_LAST_SEG | length); - smc911x_reg_write(dev, TX_DATA_FIFO, length); + smc911x_reg_write(priv, TX_DATA_FIFO, length); tmplen = (length + 3) / 4; while (tmplen--) - smc911x_reg_write(dev, TX_DATA_FIFO, *data++); + smc911x_reg_write(priv, TX_DATA_FIFO, *data++); /* wait for transmission */ - while (!((smc911x_reg_read(dev, TX_FIFO_INF) & + while (!((smc911x_reg_read(priv, TX_FIFO_INF) & TX_FIFO_INF_TSUSED) >> 16)); /* get status. Ignore 'no carrier' error, it has no meaning for * full duplex operation */ - status = smc911x_reg_read(dev, TX_STATUS_FIFO) & + status = smc911x_reg_read(priv, TX_STATUS_FIFO) & (TX_STS_LOC | TX_STS_LATE_COLL | TX_STS_MANY_COLL | TX_STS_MANY_DEFER | TX_STS_UNDERRUN); @@ -330,25 +339,28 @@ static int smc911x_send(struct eth_device *dev, void *packet, int length) static void smc911x_halt(struct eth_device *dev) { - smc911x_reset(dev); - smc911x_handle_mac_address(dev); + struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev); + + smc911x_reset(priv); + smc911x_handle_mac_address(priv); } static int smc911x_recv(struct eth_device *dev) { + struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev); u32 *data = (u32 *)net_rx_packets[0]; u32 pktlen, tmplen; u32 status; - if ((smc911x_reg_read(dev, RX_FIFO_INF) & RX_FIFO_INF_RXSUSED) >> 16) { - status = smc911x_reg_read(dev, RX_STATUS_FIFO); + if ((smc911x_reg_read(priv, RX_FIFO_INF) & RX_FIFO_INF_RXSUSED) >> 16) { + status = smc911x_reg_read(priv, RX_STATUS_FIFO); pktlen = (status & RX_STS_PKT_LEN) >> 16; - smc911x_reg_write(dev, RX_CFG, 0); + smc911x_reg_write(priv, RX_CFG, 0); tmplen = (pktlen + 3) / 4; while (tmplen--) - *data++ = smc911x_reg_read(dev, RX_DATA_FIFO); + *data++ = smc911x_reg_read(priv, RX_DATA_FIFO); if (status & RX_STS_ES) printf(DRIVERNAME @@ -367,31 +379,34 @@ static int smc911x_miiphy_read(struct mii_dev *bus, int phy, int devad, int reg) { struct eth_device *dev = eth_get_dev_by_name(bus->name); + struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev); u16 val = 0; int ret; - if (!dev) + if (!dev || !priv) return -ENODEV; - ret = smc911x_eth_phy_read(dev, phy, reg, &val); + ret = smc911x_eth_phy_read(priv, phy, reg, &val); if (ret < 0) return ret; return val; } + /* wrapper for smc911x_eth_phy_write */ static int smc911x_miiphy_write(struct mii_dev *bus, int phy, int devad, int reg, u16 val) { struct eth_device *dev = eth_get_dev_by_name(bus->name); + struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev); - if (!dev) + if (!dev || !priv) return -ENODEV; - return smc911x_eth_phy_write(dev, phy, reg, val); + return smc911x_eth_phy_write(priv, phy, reg, val); } -static int smc911x_initialize_mii(struct eth_device *dev) +static int smc911x_initialize_mii(struct smc911x_priv *priv) { struct mii_dev *mdiodev = mdio_alloc(); int ret; @@ -399,7 +414,7 @@ static int smc911x_initialize_mii(struct eth_device *dev) if (!mdiodev) return -ENOMEM; - strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN); + strncpy(mdiodev->name, priv->dev.name, MDIO_NAME_LEN); mdiodev->read = smc911x_miiphy_read; mdiodev->write = smc911x_miiphy_write; @@ -412,7 +427,7 @@ static int smc911x_initialize_mii(struct eth_device *dev) return 0; } #else -static int smc911x_initialize_mii(struct eth_device *dev) +static int smc911x_initialize_mii(struct smc911x_priv *priv) { return 0; } @@ -421,51 +436,52 @@ static int smc911x_initialize_mii(struct eth_device *dev) int smc911x_initialize(u8 dev_num, int base_addr) { unsigned long addrl, addrh; - struct eth_device *dev; + struct smc911x_priv *priv; int ret; - dev = calloc(1, sizeof(*dev)); - if (!dev) + priv = calloc(1, sizeof(*priv)); + if (!priv) return -ENOMEM; - dev->iobase = base_addr; + priv->iobase = base_addr; + priv->dev.iobase = base_addr; /* Try to detect chip. Will fail if not present. */ - ret = smc911x_detect_chip(dev); + ret = smc911x_detect_chip(priv); if (ret) { ret = 0; /* Card not detected is not an error */ goto err_detect; } - addrh = smc911x_get_mac_csr(dev, ADDRH); - addrl = smc911x_get_mac_csr(dev, ADDRL); + 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 */ - dev->enetaddr[0] = addrl; - dev->enetaddr[1] = addrl >> 8; - dev->enetaddr[2] = addrl >> 16; - dev->enetaddr[3] = addrl >> 24; - dev->enetaddr[4] = addrh; - dev->enetaddr[5] = addrh >> 8; + 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; } - dev->init = smc911x_init; - dev->halt = smc911x_halt; - dev->send = smc911x_send; - dev->recv = smc911x_recv; - sprintf(dev->name, "%s-%hu", DRIVERNAME, dev_num); + priv->dev.init = smc911x_init; + priv->dev.halt = smc911x_halt; + priv->dev.send = smc911x_send; + priv->dev.recv = smc911x_recv; + sprintf(priv->dev.name, "%s-%hu", DRIVERNAME, dev_num); - eth_register(dev); + eth_register(&priv->dev); - ret = smc911x_initialize_mii(dev); + ret = smc911x_initialize_mii(priv); if (ret) goto err_mii; return 1; err_mii: - eth_unregister(dev); + eth_unregister(&priv->dev); err_detect: - free(dev); + free(priv); return ret; } From patchwork Wed Mar 25 16:46:51 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Vasut X-Patchwork-Id: 244271 List-Id: U-Boot discussion From: marek.vasut at gmail.com (Marek Vasut) Date: Wed, 25 Mar 2020 17:46:51 +0100 Subject: [PATCH V4 11/13] net: smc911x: Clean up the status handling in smc911x_recv() In-Reply-To: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> References: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> Message-ID: <20200325164653.112079-12-marek.vasut+renesas@gmail.com> Invert the status handling logic in smc911x_recv(), to make the function easier to read, no functional change. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada --- V2: Simplify RX_FIFO_INF_RXSUSED mask handling s at Invest@Invert@ V3: No change V4: No change --- drivers/net/smc911x.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 07066ce108..2d1a9e0f5a 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -352,23 +352,25 @@ static int smc911x_recv(struct eth_device *dev) u32 pktlen, tmplen; u32 status; - if ((smc911x_reg_read(priv, RX_FIFO_INF) & RX_FIFO_INF_RXSUSED) >> 16) { - status = smc911x_reg_read(priv, RX_STATUS_FIFO); - pktlen = (status & RX_STS_PKT_LEN) >> 16; + status = smc911x_reg_read(priv, RX_FIFO_INF); + if (!(status & RX_FIFO_INF_RXSUSED)) + return 0; - smc911x_reg_write(priv, RX_CFG, 0); + status = smc911x_reg_read(priv, RX_STATUS_FIFO); + pktlen = (status & RX_STS_PKT_LEN) >> 16; - tmplen = (pktlen + 3) / 4; - while (tmplen--) - *data++ = smc911x_reg_read(priv, RX_DATA_FIFO); + smc911x_reg_write(priv, RX_CFG, 0); - if (status & RX_STS_ES) - printf(DRIVERNAME - ": dropped bad packet. Status: 0x%08x\n", - status); - else - net_process_received_packet(net_rx_packets[0], pktlen); - } + tmplen = (pktlen + 3) / 4; + while (tmplen--) + *data++ = smc911x_reg_read(priv, RX_DATA_FIFO); + + if (status & RX_STS_ES) + printf(DRIVERNAME + ": dropped bad packet. Status: 0x%08x\n", + status); + else + net_process_received_packet(net_rx_packets[0], pktlen); return 0; } From patchwork Wed Mar 25 16:46:52 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Vasut X-Patchwork-Id: 244273 List-Id: U-Boot discussion From: marek.vasut at gmail.com (Marek Vasut) Date: Wed, 25 Mar 2020 17:46:52 +0100 Subject: [PATCH V4 12/13] net: smc911x: Split non-DM specific bits from common code In-Reply-To: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> References: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> Message-ID: <20200325164653.112079-13-marek.vasut+renesas@gmail.com> Split network handling functions into non-DM specific parts and common code in preparation for conversion to DM. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Masahiro Yamada Acked-by: Joe Hershberger --- V2: Add AB from Joe V3: No change V4: No change --- drivers/net/smc911x.c | 57 ++++++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 2d1a9e0f5a..95f955f6d8 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -277,9 +277,8 @@ static void smc911x_enable(struct smc911x_priv *priv) MAC_CR_HBDIS); } -static int smc911x_init(struct eth_device *dev, bd_t * bd) +static int smc911x_init_common(struct smc911x_priv *priv) { - struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev); const struct chip_id *id = priv->chipid; printf(DRIVERNAME ": detected %s controller\n", id->name); @@ -297,9 +296,9 @@ static int smc911x_init(struct eth_device *dev, bd_t * bd) return 0; } -static int smc911x_send(struct eth_device *dev, void *packet, int length) +static int smc911x_send_common(struct smc911x_priv *priv, + void *packet, int length) { - struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev); u32 *data = (u32*)packet; u32 tmplen; u32 status; @@ -337,18 +336,14 @@ static int smc911x_send(struct eth_device *dev, void *packet, int length) return -1; } -static void smc911x_halt(struct eth_device *dev) +static void smc911x_halt_common(struct smc911x_priv *priv) { - struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev); - smc911x_reset(priv); smc911x_handle_mac_address(priv); } -static int smc911x_recv(struct eth_device *dev) +static int smc911x_recv_common(struct smc911x_priv *priv, u32 *data) { - struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev); - u32 *data = (u32 *)net_rx_packets[0]; u32 pktlen, tmplen; u32 status; @@ -365,14 +360,14 @@ static int smc911x_recv(struct eth_device *dev) while (tmplen--) *data++ = smc911x_reg_read(priv, RX_DATA_FIFO); - if (status & RX_STS_ES) + if (status & RX_STS_ES) { printf(DRIVERNAME ": dropped bad packet. Status: 0x%08x\n", status); - else - net_process_received_packet(net_rx_packets[0], pktlen); + return 0; + } - return 0; + return pktlen; } #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) @@ -435,6 +430,40 @@ static int smc911x_initialize_mii(struct smc911x_priv *priv) } #endif +static int smc911x_init(struct eth_device *dev, bd_t *bd) +{ + struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev); + + return smc911x_init_common(priv); +} + +static void smc911x_halt(struct eth_device *dev) +{ + struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev); + + smc911x_halt_common(priv); +} + +static int smc911x_send(struct eth_device *dev, void *packet, int length) +{ + struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev); + + return smc911x_send_common(priv, packet, length); +} + +static int smc911x_recv(struct eth_device *dev) +{ + struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev); + u32 *data = (u32 *)net_rx_packets[0]; + int ret; + + ret = smc911x_recv_common(priv, data); + if (ret) + net_process_received_packet(net_rx_packets[0], ret); + + return ret; +} + int smc911x_initialize(u8 dev_num, int base_addr) { unsigned long addrl, addrh; From patchwork Wed Mar 25 16:46:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Vasut X-Patchwork-Id: 244274 List-Id: U-Boot discussion From: marek.vasut at gmail.com (Marek Vasut) Date: Wed, 25 Mar 2020 17:46:53 +0100 Subject: [PATCH V4 13/13] net: smc911x: Add DM support In-Reply-To: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> References: <20200325164653.112079-1-marek.vasut+renesas@gmail.com> Message-ID: <20200325164653.112079-14-marek.vasut+renesas@gmail.com> 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 --- V2: Drop the board-specific bits Hide SMC911X_BASE from Kconfig if DM_ETH V3: No change V4: No change --- drivers/net/Kconfig | 2 + drivers/net/smc911x.c | 114 +++++++++++++++++++++++++++++++++++ examples/standalone/Makefile | 5 +- 3 files changed, 120 insertions(+), 1 deletion(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 4d1013c984..095395813a 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 95f955f6d8..89be192d5f 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, @@ -516,3 +520,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 0b17a91804..6b061bac69 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.