diff --git a/arch/risc-v/src/mpfs/Kconfig b/arch/risc-v/src/mpfs/Kconfig index a13d98ad3a86d..75b2e5dc3a4d9 100644 --- a/arch/risc-v/src/mpfs/Kconfig +++ b/arch/risc-v/src/mpfs/Kconfig @@ -747,6 +747,8 @@ config MPFS_MAC_NO_BROADCAST config MPFS_MAC_AUTONEG bool "Use autonegotiation" + depends on !MPFS_ETH0_PHY_KSZ9477 + depends on !MPFS_ETH1_PHY_KSZ9477 default y ---help--- Use PHY autonegotiation to determine speed and mode @@ -765,6 +767,34 @@ config MPFS_PHYINIT ---help--- call mpfs_phy_boardinitialize() on init +config MPFS_ETH0_PHY_KSZ9477 + bool "Use ksz9477 switch as an SGMII PHY for ETH0" + default n + select NET_KSZ9477 + ---help--- + Select to use ksz9477 connected to SGMII + +config MPFS_ETH1_PHY_KSZ9477 + bool "Use ksz9477 switch as an SGMII PHY for ETH1" + default n + select NET_KSZ9477 + ---help--- + Select to use ksz9477 connected to SGMII + +config MPFS_ETH0_PHY_KSZ9477_I2C_BUS + int "Management I2C bus number for ksz9477 switch" + depends on MPFS_ETH0_PHY_KSZ9477 + default 5 + ---help--- + The i2c port number for switch management + +config MPFS_ETH1_PHY_KSZ9477_I2C_BUS + int "Management I2C bus number for ksz9477 switch" + depends on MPFS_ETH1_PHY_KSZ9477 + default 5 + ---help--- + The i2c port number for switch management + if !MPFS_MAC_AUTONEG config MPFS_MAC_ETHFD @@ -776,6 +806,7 @@ config MPFS_MAC_ETHFD choice prompt "MAC Speed" + default MPFS_MAC_ETH1000MBPS if MPFS_ETH0_PHY_KSZ9477 || MPFS_ETH1_PHY_KSZ9477 default MPFS_MAC_ETH100MBPS ---help--- If autonegotiation is not used, then you must select the fixed speed diff --git a/arch/risc-v/src/mpfs/mpfs_ethernet.c b/arch/risc-v/src/mpfs/mpfs_ethernet.c index c72764ebb8c59..8fcc8f6129a3d 100644 --- a/arch/risc-v/src/mpfs/mpfs_ethernet.c +++ b/arch/risc-v/src/mpfs/mpfs_ethernet.c @@ -50,10 +50,31 @@ # include #endif +#include + #include "riscv_internal.h" #include "mpfs_memorymap.h" #include "mpfs_ethernet.h" #include "mpfs_dsn.h" +#include "mpfs_i2c.h" + +#if defined(CONFIG_MPFS_ETH0_PHY_KSZ9477) ||\ + defined(CONFIG_MPFS_ETH1_PHY_KSZ9477) +# if !defined(CONFIG_MPFS_MAC_SGMII) +# error Using KSZ9477 as a PHY requires CONFIG_MPFS_MAC_SGMII to be set +# endif + +# define ETH_HAS_KSZ_SWITCH + +# ifdef CONFIG_MPFS_ETH0_PHY_KSZ9477 +# define ETH_PHY_KSZ9477_I2C_BUS CONFIG_MPFS_ETH0_PHY_KSZ9477_I2C_BUS +# else +# define ETH_PHY_KSZ9477_I2C_BUS CONFIG_MPFS_ETH1_PHY_KSZ9477_I2C_BUS +# endif + +#else +# define ETH_HAS_MDIO_PHY +#endif #if defined(CONFIG_NET) && defined(CONFIG_MPFS_ETHMAC) @@ -90,7 +111,7 @@ # endif #endif -#ifndef CONFIG_MPFS_PHYADDR +#if defined(ETH_HAS_MDIO_PHY) && !defined(CONFIG_MPFS_PHYADDR) # error "CONFIG_MPFS_PHYADDR must be defined in the NuttX configuration" #endif @@ -253,7 +274,9 @@ struct mpfs_ethmac_s irq_t mac_q_int[MPFS_MAC_QUEUE_COUNT]; /* irq numbers */ uint8_t ifup : 1; /* true:ifup false:ifdown */ uint8_t intf; /* Ethernet interface number */ +#ifdef ETH_HAS_MDIO_PHY uint8_t phyaddr; /* PHY address */ +#endif struct wdog_s txtimeout; /* TX timeout timer */ struct wdog_s rxtimeout; /* RX timeout timer */ struct work_s irqwork; /* For deferring interrupt work to the work queue */ @@ -338,10 +361,13 @@ static int mpfs_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg); /* PHY Initialization */ +static int mpfs_phyinit(struct mpfs_ethmac_s *priv); + +#ifdef ETH_HAS_MDIO_PHY + static void mpfs_enablemdio(struct mpfs_ethmac_s *priv); static void mpfs_disablemdio(struct mpfs_ethmac_s *priv); static int mpfs_phyreset(struct mpfs_ethmac_s *priv); -static int mpfs_phyinit(struct mpfs_ethmac_s *priv); static int mpfs_phyread(struct mpfs_ethmac_s *priv, uint8_t phyaddr, uint8_t regaddr, uint16_t *phyval); static int mpfs_phywrite(struct mpfs_ethmac_s *priv, uint8_t phyaddr, @@ -350,16 +376,21 @@ static int mpfs_phywait(struct mpfs_ethmac_s *priv); static int mpfs_phyfind(struct mpfs_ethmac_s *priv, uint8_t *phyaddr); #ifdef CONFIG_MPFS_MAC_AUTONEG static int mpfs_autonegotiate(struct mpfs_ethmac_s *priv); -#else -static void mpfs_linkspeed(struct mpfs_ethmac_s *priv); #endif -#if defined(CONFIG_DEBUG_NET) && defined(CONFIG_DEBUG_INFO) +#endif /* ETH_HAS_MDIO_PHY */ + +#if defined(CONFIG_DEBUG_NET) && defined(CONFIG_DEBUG_INFO) && \ + defined(ETH_HAS_MDIO_PHY) static void mpfs_phydump(struct mpfs_ethmac_s *priv); #else # define mpfs_phydump(priv) #endif +#ifndef CONFIG_MPFS_MAC_AUTONEG +static void mpfs_linkspeed(struct mpfs_ethmac_s *priv); +#endif + /* MAC/DMA Initialization */ static void mpfs_txreset(struct mpfs_ethmac_s *priv); @@ -1873,6 +1904,8 @@ static int mpfs_rmmac(struct net_driver_s *dev, const uint8_t *mac) } #endif +#ifdef ETH_HAS_MDIO_PHY + /**************************************************************************** * Function: mpfs_enablemdio * @@ -2503,6 +2536,8 @@ static int mpfs_autonegotiate(struct mpfs_ethmac_s *priv) } #endif +#endif /* ETH_HAS_MDIO_PHY */ + /**************************************************************************** * Function: mpfs_linkspeed * @@ -2518,7 +2553,7 @@ static int mpfs_autonegotiate(struct mpfs_ethmac_s *priv) * ****************************************************************************/ -#ifndef CONFIG_MPFS_MAC_AUTONEG +#if !defined(CONFIG_MPFS_MAC_AUTONEG) || !defined(ETH_HAS_MDIO_PHY) static void mpfs_linkspeed(struct mpfs_ethmac_s *priv) { uint32_t regval; @@ -2594,7 +2629,7 @@ static void mpfs_linkspeed(struct mpfs_ethmac_s *priv) #ifdef CONFIG_NETDEV_IOCTL static int mpfs_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) { -#ifdef CONFIG_NETDEV_PHY_IOCTL +#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(ETH_HAS_MDIO_PHY) struct mpfs_ethmac_s *priv = (struct mpfs_ethmac_s *)dev->d_private; #endif int ret; @@ -2602,6 +2637,7 @@ static int mpfs_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) switch (cmd) { #ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef ETH_HAS_MDIO_PHY #ifdef CONFIG_ARCH_PHY_INTERRUPT case SIOCMIINOTIFY: /* Set up for PHY event notifications */ { @@ -2665,6 +2701,7 @@ static int mpfs_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) mpfs_disablemdio(priv); } break; +#endif /* ETH_HAS_MDIO_PHY */ #endif /* CONFIG_NETDEV_PHY_IOCTL */ default: @@ -3239,6 +3276,8 @@ static int mpfs_macenable(struct mpfs_ethmac_s *priv) * ****************************************************************************/ +#ifdef ETH_HAS_MDIO_PHY + static void mpfs_mdcclock(struct mpfs_ethmac_s *priv) { uint32_t ncfgr; @@ -3293,6 +3332,8 @@ static void mpfs_mdcclock(struct mpfs_ethmac_s *priv) mac_putreg(priv, NETWORK_CONTROL, ncr); } +#endif + /**************************************************************************** * Function: mpfs_phyinit * @@ -3309,7 +3350,9 @@ static void mpfs_mdcclock(struct mpfs_ethmac_s *priv) static int mpfs_phyinit(struct mpfs_ethmac_s *priv) { - int ret; + int ret = -EINVAL; + +#ifdef ETH_HAS_MDIO_PHY /* Configure PHY clocking */ @@ -3328,7 +3371,20 @@ static int mpfs_phyinit(struct mpfs_ethmac_s *priv) /* We have a PHY address. Reset the PHY */ mpfs_phyreset(priv); - return OK; + +#elif defined(ETH_HAS_KSZ_SWITCH) + struct i2c_master_s *bus; + + bus = mpfs_i2cbus_initialize(ETH_PHY_KSZ9477_I2C_BUS); + + if (bus) + { + ret = ksz9477_i2c_init(bus, KSZ9477_PORT_SGMII); + } + +#endif + + return ret; } /**************************************************************************** @@ -3347,6 +3403,8 @@ static int mpfs_phyinit(struct mpfs_ethmac_s *priv) * ****************************************************************************/ +#ifdef ETH_HAS_MDIO_PHY + static int mpfs_phyreset(struct mpfs_ethmac_s *priv) { uint16_t mcr; @@ -3416,6 +3474,8 @@ static int mpfs_phyreset(struct mpfs_ethmac_s *priv) return ret; } +#endif + /**************************************************************************** * Function: mpfs_ethconfig * diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index ff289b2fb021c..5028e0db17521 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -392,6 +392,30 @@ menuconfig NET_W5500 References: W5500 Datasheet, Version 1.0.9, 2013 WIZnet Co., Ltd. +config NET_KSZ9477 + bool "Management interface for ksz9477 ethernet switch" + default n + ---help--- + Support for Microchip/Micrel KSZ9477 managed switch. To use this, + one must also select the management interface (I2C / SPI) and + call the driver's init from board initialization code or from the + ethernet driver. + +choice + prompt "Management bus for the kzs9477 switch" + default NET_KSZ9477_I2C + depends on NET_KSZ9477 + ---help--- + Select the used management interface + +config NET_KSZ9477_I2C + bool "Use I2C management interface" + +config NET_KSZ9477_SPI + bool "Use SPI management interface" + +endchoice + if NET_W5500 config NET_W5500_NINTERFACES diff --git a/drivers/net/Make.defs b/drivers/net/Make.defs index 76aa70e6b73d4..070df18e55e66 100644 --- a/drivers/net/Make.defs +++ b/drivers/net/Make.defs @@ -80,6 +80,15 @@ ifeq ($(CONFIG_ARCH_PHY_INTERRUPT),y) CSRCS += phy_notify.c endif +ifeq ($(CONFIG_NET_KSZ9477),y) + CSRCS += ksz9477.c + +ifeq ($(CONFIG_NET_KSZ9477_I2C),y) + CSRCS += ksz9477_i2c.c +endif + +endif + # Include network build support DEPPATH += --dep-path net diff --git a/drivers/net/ksz9477.c b/drivers/net/ksz9477.c new file mode 100644 index 0000000000000..4cb5cb5d2ef3c --- /dev/null +++ b/drivers/net/ksz9477.c @@ -0,0 +1,260 @@ +/**************************************************************************** + * drivers/net/ksz9477.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include "ksz9477_reg.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint16_t bswap16(uint16_t data) +{ + return (data << 8) | (data >> 8); +} + +static uint32_t bswap32(uint32_t data) +{ + return (data << 24) | (data >> 24) | ((data << 8) & 0xff0000) | + ((data >> 8) & 0xff00); +} + +#if 0 /* Enable when needed */ +static int ksz9477_reg_read8(uint16_t reg, uint8_t *data) +{ + int ret; + struct ksz9477_transfer_s read_msg; + read_msg.len = 3; + read_msg.reg = bswap16(reg); + ret = ksz9477_read(&read_msg); + *data = read_msg.data; + return ret; +} +#endif + +static int ksz9477_reg_read16(uint16_t reg, uint16_t *data) +{ + int ret; + struct ksz9477_transfer_s read_msg; + read_msg.len = 4; + read_msg.reg = bswap16(reg); + ret = ksz9477_read(&read_msg); + *data = bswap16(read_msg.data); + return ret; +} + +static int ksz9477_reg_read32(uint16_t reg, uint32_t *data) +{ + int ret; + struct ksz9477_transfer_s read_msg; + read_msg.len = 6; + read_msg.reg = bswap16(reg); + ret = ksz9477_read(&read_msg); + *data = bswap32(read_msg.data); + return ret; +} + +#if 0 /* Enable when needed */ +static int ksz9477_reg_write8(uint16_t reg, uint8_t data) +{ + struct ksz9477_transfer_s write_msg; + write_msg.len = 3; + write_msg.reg = bswap16(reg); + write_msg.data = data; + return ksz9477_write(&write_msg); +} +#endif + +static int ksz9477_reg_write32(uint16_t reg, uint32_t data) +{ + struct ksz9477_transfer_s write_msg; + write_msg.len = 6; + write_msg.reg = bswap16(reg); + write_msg.data = bswap32(data); + return ksz9477_write(&write_msg); +} + +#if 0 /* Enable when needed */ +static int ksz9477_reg_write16(uint16_t reg, uint16_t data) +{ + int ret; + struct ksz9477_transfer_s write_msg; + uint16_t addr = reg; + uint32_t data32; + + /* Errata: 16-bit writes to registers 0xN120-0xN13f will corrupt the + * adjacent regsters. Workaround: perform only 32-bit writes to this + * area + */ + + if ((reg & 0xfff) >= 0x120 && (reg & 0xfff) <= 0x13f) + { + /* Align write on lower 16-byte boundary */ + + addr = reg & (~1); + + /* Read the full 32-bit register */ + + ret = ksz9477_reg_read32(addr, &data32); + if (ret != OK) + { + return ret; + } + + /* Inject the data to the 32-bit write data */ + + if (reg & 1) + { + data32 = (data32 & 0xff0000ff) | ((uint32_t)data << 8); + } + else + { + data32 = (data32 & 0xffff0000) | data; + } + + write_msg.len = 6; + write_msg.data = bswap32(data32); + } + else + { + write_msg.len = 4; + write_msg.data = bswap16(data); + } + + write_msg.reg = bswap16(reg); + + return ksz9477_write(&write_msg); +} +#endif + +static int ksz9477_sgmii_read_indirect(uint32_t address, uint16_t *value, + unsigned len) +{ + int ret; + uint32_t data; + + address |= SGMII_PORT_ADDRESS_AUTO_INC_ENB; + ret = ksz9477_reg_write32(KSZ9477_SGMII_PORT_ADDRESS, address); + while (len-- && ret == OK) + { + ret = ksz9477_reg_read32(KSZ9477_SGMII_PORT_DATA, &data); + *value++ = (uint16_t)data; + } + + return ret; +} + +static int ksz9477_sgmii_write_indirect(uint32_t address, uint16_t *value, + unsigned len) +{ + int ret; + uint32_t data; + + address |= SGMII_PORT_ADDRESS_AUTO_INC_ENB; + ret = ksz9477_reg_write32(KSZ9477_SGMII_PORT_ADDRESS, address); + while (len-- && ret == OK) + { + data = *value++; + ret = ksz9477_reg_write32(KSZ9477_SGMII_PORT_DATA, data); + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ksz9477_init + * + * Description: + * Switches the ksz9477's SGMII port into PHY mode and sets the + * default settings to work directly with an external MAC + * + * Input Parameters: + * master_port: Port connected to the host MAC + * + * Returned Value: + * OK or negative error number + * + ****************************************************************************/ + +int ksz9477_init(ksz9477_port_t master_port) +{ + int ret; + uint16_t regval16; + uint32_t regval32; + + /* Read the ID registers */ + + ret = ksz9477_reg_read16(KSZ9477_ID1, ®val16); + if (ret != OK || regval16 != KSZ9477_ID) + { + nerr("Device not found, id %x, ret %d\n", regval16, ret); + return ret ? ret : -EINVAL; + } + + /* Check that the SGMII block is alive and indirect accesses work */ + + ret = ksz9477_sgmii_read_indirect(KSZ9477_SGMII_ID1, + (uint16_t *)®val32, 2); + if (ret != OK || regval32 != SGMII_PHY_ID) + { + nerr("SGMII port access failure, id %x, ret %d\n", regval32, ret); + return ret ? ret : -EINVAL; + } + + if (master_port == KSZ9477_PORT_SGMII) + { + /* Set the switch's SGMII port into "PHY" mode and enable link */ + + regval16 = (SGMII_AUTONEG_CONTROL_PCS_SGMII | + SGMII_AUTONEG_CONTROL_TC_MASTER | + SGMII_AUTONEG_CONTROL_LINK_STATUS); + ret = ksz9477_sgmii_write_indirect(KSZ9477_SGMII_AUTONEG_CONTROL, + ®val16, 1); + + /* Write to autonegotiation advertisement register activates the new + * setting. Advertise only full duplex. + */ + + regval16 = SGMII_AUTONEG_ADVERTISE_FD; + ret = ksz9477_sgmii_write_indirect(KSZ9477_SGMII_AUTONEG_ADVERTISE, + ®val16, 1); + } + + return ret; +} diff --git a/drivers/net/ksz9477_i2c.c b/drivers/net/ksz9477_i2c.c new file mode 100644 index 0000000000000..35618d826cfbc --- /dev/null +++ b/drivers/net/ksz9477_i2c.c @@ -0,0 +1,111 @@ +/**************************************************************************** + * drivers/net/ksz9477_i2c.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include "ksz9477_reg.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct i2c_master_s *g_ksz9477_i2c_bus; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void setup_i2c_transfer(struct i2c_msg_s *msg, uint8_t *data, + size_t len, bool read) +{ + msg[0].frequency = KSZ9477_I2C_SPEED; + msg[0].addr = KSZ9477_I2C_ADDRESS; + msg[0].flags = read ? I2C_M_READ : 0; + msg[0].buffer = data; + msg[0].length = len; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int ksz9477_read(struct ksz9477_transfer_s *read_msg) +{ + struct i2c_msg_s msg[2]; + + /* Set up to write the address */ + + setup_i2c_transfer(&msg[0], (uint8_t *)&read_msg->reg, + sizeof(read_msg->reg), false); + + /* Followed by the read data */ + + setup_i2c_transfer(&msg[1], (uint8_t *)&read_msg->data, + read_msg->len - sizeof(read_msg->reg), true); + + return I2C_TRANSFER(g_ksz9477_i2c_bus, msg, 2); +} + +int ksz9477_write(struct ksz9477_transfer_s *write_msg) +{ + struct i2c_msg_s msg; + + /* Set up to write the address and data */ + + setup_i2c_transfer(&msg, (uint8_t *)&write_msg->reg, + write_msg->len, false); + + return I2C_TRANSFER(g_ksz9477_i2c_bus, &msg, 1); +} + +/**************************************************************************** + * Name: ksz9477_i2c_init + * + * Description: + * Stores the configured i2c_master and calls the main init function + * + * Input Parameters: + * i2c_bus: The i2c master used as a control interface + * master_port: The switch port connected to the host MAC + * Returned Value: + * OK or negative error number + * + ****************************************************************************/ + +int ksz9477_i2c_init(struct i2c_master_s *i2c_bus, + ksz9477_port_t master_port) +{ + if (!i2c_bus) + { + return -EINVAL; + } + + g_ksz9477_i2c_bus = i2c_bus; + + /* Call the main init function */ + + return ksz9477_init(master_port); +} diff --git a/drivers/net/ksz9477_reg.h b/drivers/net/ksz9477_reg.h new file mode 100644 index 0000000000000..3423edb8ef603 --- /dev/null +++ b/drivers/net/ksz9477_reg.h @@ -0,0 +1,155 @@ +/**************************************************************************** + * drivers/net/ksz9477_reg.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __DRIVERS_NET_KSZ9477_REG_H +#define __DRIVERS_NET_KSZ9477_REG_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* These define only a subset of full register map. New registers can added + * as needed + */ + +#define KSZ9477_I2C_ADDRESS 0x5f +#define KSZ9477_I2C_SPEED I2C_SPEED_FAST + +/* Global registers */ + +#define KSZ9477_ID0 0x0 +#define KSZ9477_ID1 0x1 +#define KSZ9477_ID2 0x2 +#define KSZ9477_ID3 0x3 + +/* Port registers */ + +#define KSZ9477_PORT_REG(p,r) ((((uint16_t)(p)) << 12) | (r)) + +#define KSZ9477_PORT_DEFAULT_TAG0(p) KSZ9477_PORT_REG(p, 0x0) +#define KSZ9477_PORT_DEFAULT_TAG1(p) KSZ9477_PORT_REG(p, 0x1) + +#define KSZ9477_PHY_CONTROL(p) KSZ9477_PORT_REG(p, 0x100) +#define KSZ9477_PHY_STATUS(p) KSZ9477_PORT_REG(p, 0x102) + +/* Note! Unlike in data sheet, the indirect data register reads and + * writes must be done with 32-bit accesses and the address is + * 0x204 + */ + +#define KSZ9477_PORT_ADDRESS(p) KSZ9477_PORT_REG(p, 0x200) +#define KSZ9477_PORT_DATA(p) KSZ9477_PORT_REG(p, 0x204) + +#define KSZ9477_SGMII_PORT_ADDRESS KSZ9477_PORT_ADDRESS(7) +#define KSZ9477_SGMII_PORT_DATA KSZ9477_PORT_DATA(7) + +/* SGMII indirect registers */ + +#define KSZ9477_SGMII_CONTROL 0x1F0000 +#define KSZ9477_SGMII_STATUS 0x1F0001 +#define KSZ9477_SGMII_ID1 0x1F0002 +#define KSZ9477_SGMII_ID2 0x1F0003 +#define KSZ9477_SGMII_AUTONEG_ADVERTISE 0x1F0004 +#define KSZ9477_SGMII_LINK_PARTNER_ABILITY 0x1F0005 +#define KSZ9477_SGMII_AUTONEG_EXPANSION 0x1F0006 +#define KSZ9477_SGMII_DIGITAL_CONTROL 0x1F8000 +#define KSZ9477_SGMII_AUTONEG_CONTROL 0x1F8001 +#define KSZ9477_SGMII_AUTONEG_STATUS 0x1F8002 + +/* Register bit definitions */ + +/* KSZ9477_ID2, KSZ9477_ID1 */ + +#define KSZ9477_ID 0x9477 + +/* KSZ9477_SGMII_ID2, KSZ9477_SGMII_ID1 */ + +#define SGMII_PHY_ID 0xced07996 + +/* KSZ9477_SGMII_PORT_ADDRESS */ + +#define SGMII_PORT_ADDRESS_AUTO_INC_ENB (1 << 23) + +/* KSZ9477_SGMII_AUTONEG_ADVERTISE */ + +#define SGMII_AUTONEG_ADVERTISE_FD (1 << 5) +#define SGMII_AUTONEG_ADVERTISE_HD (1 << 5) + +/* KSZ9477_SGMII_AUTONEG_CONTROL */ + +#define SGMII_AUTONEG_CONTROL_IE (1 << 0) +#define SGMII_AUTONEG_CONTROL_PCS_SERDES (0 << 1) +#define SGMII_AUTONEG_CONTROL_PCS_SGMII (2 << 1) +#define SGMII_AUTONEG_CONTROL_TC_MASTER (1 << 3) +#define SGMII_AUTONEG_CONTROL_LINK_STATUS (1 << 4) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct ksz9477_transfer_s +{ + uint16_t len; + uint16_t reg; + uint32_t data; +} +__attribute__((packed)); + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +int ksz9477_init(ksz9477_port_t master_port); + +int ksz9477_read(struct ksz9477_transfer_s *read_msg); + +int ksz9477_write(struct ksz9477_transfer_s *write_msg); + +#if defined(__cplusplus) +} +#endif +#undef EXTERN + +#endif /* __ASSEMBLY__ */ +#endif /* __DRIVERS_NET_KSZ9477_REG_H */ diff --git a/include/nuttx/net/ksz9477.h b/include/nuttx/net/ksz9477.h new file mode 100644 index 0000000000000..cc37adb48a40a --- /dev/null +++ b/include/nuttx/net/ksz9477.h @@ -0,0 +1,101 @@ +/**************************************************************************** + * include/nuttx/net/ksz9477.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_NET_KSZ9477_H +#define __INCLUDE_NUTTX_NET_KSZ9477_H + +#ifdef CONFIG_NET_KSZ9477 + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +typedef enum +{ + KSZ9477_PORT_NONE = -1, + KSZ9477_PORT_GLOBAL = 0, + KSZ9477_PORT_PHY1 = 1, + KSZ9477_PORT_PHY2 = 2, + KSZ9477_PORT_PHY3 = 3, + KSZ9477_PORT_PHY4 = 4, + KSZ9477_PORT_PHY5 = 5, + KSZ9477_PORT_RMII = 6, + KSZ9477_PORT_SGMII = 7, +} ksz9477_port_t; + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: ksz9477_i2c_init + * + * Description: + * Switches the ksz9477's SGMII port into PHY mode and sets the + * default settings to work directly with an external MAC + * + * Input Parameters: + * i2c_bus: Management i2c bus + * master_port: The port of the switch connected to host MAC + * + * Returned Value: + * OK or ERROR + * + ****************************************************************************/ + +#ifdef CONFIG_NET_KSZ9477_I2C +int ksz9477_i2c_init(struct i2c_master_s *i2c_bus, + ksz9477_port_t master_port); +#else +# error Only I2c interface currently supported +#endif + +#if defined(__cplusplus) +} +#endif +#undef EXTERN + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_NET_KSZ9477 */ +#endif /* __INCLUDE_NUTTX_NET_KSZ9477_H */