diff --git a/arch/arm/dts/devsoc-emulation.dts b/arch/arm/dts/devsoc-emulation.dts index 6edb15716c..837426ede8 100644 --- a/arch/arm/dts/devsoc-emulation.dts +++ b/arch/arm/dts/devsoc-emulation.dts @@ -169,4 +169,9 @@ xhci@8a00000 { qcom,emulation = <1>; }; + + ess-switch { + switch_mac_mode0 = ; + switch_mac_mode1 = ; + }; }; diff --git a/arch/arm/dts/devsoc-soc.dtsi b/arch/arm/dts/devsoc-soc.dtsi index 37763c80ec..d390c89aaf 100644 --- a/arch/arm/dts/devsoc-soc.dtsi +++ b/arch/arm/dts/devsoc-soc.dtsi @@ -15,6 +15,7 @@ #include "skeleton.dtsi" #include +#include / { serial@78AF000 { diff --git a/arch/arm/include/asm/arch-devsoc/edma_regs.h b/arch/arm/include/asm/arch-devsoc/edma_regs.h new file mode 100644 index 0000000000..97c56b781f --- /dev/null +++ b/arch/arm/include/asm/arch-devsoc/edma_regs.h @@ -0,0 +1,256 @@ +/* + ************************************************************************** + * Copyright (c) 2016-2019, 2021, The Linux Foundation. All rights reserved. + * + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** +*/ + +#ifndef __EDMA_REGS__ +#define __EDMA_REGS__ + +#define DEVSOC_EDMA_CFG_BASE 0x3ab00000 + +/* + * DEVSOC EDMA register offsets + */ +#define DEVSOC_EDMA_REG_MAS_CTRL 0x0 +#define DEVSOC_EDMA_REG_PORT_CTRL 0x4 +#define DEVSOC_EDMA_REG_RXDESC2FILL_MAP_0 0x14 +#define DEVSOC_EDMA_REG_RXDESC2FILL_MAP_1 0x18 +#define DEVSOC_EDMA_REG_DMAR_CTRL 0x48 +#define DEVSOC_EDMA_REG_MISC_INT_STAT 0x5c +#define DEVSOC_EDMA_REG_MISC_INT_MASK 0x60 +#define DEVSOC_EDMA_REG_TXDESC2CMPL_MAP_0 0x8c +#define DEVSOC_EDMA_REG_TXDESC2CMPL_MAP_1 0x90 +#define DEVSOC_EDMA_REG_TXDESC2CMPL_MAP_2 0x94 +#define DEVSOC_EDMA_REG_TXDESC2CMPL_MAP_3 0x98 +#define DEVSOC_EDMA_REG_MDIO_SLV_PASUE_MAP_0 0xA4 +#define DEVSOC_EDMA_REG_MDIO_SLV_PASUE_MAP_1 0xA8 + +#define DEVSOC_EDMA_REG_TXDESC_BA(n) (0x1000 + (0x1000 * n)) +#define DEVSOC_EDMA_REG_TXDESC_PROD_IDX(n) (0x1004 + (0x1000 * n)) +#define DEVSOC_EDMA_REG_TXDESC_CONS_IDX(n) (0x1008 + (0x1000 * n)) +#define DEVSOC_EDMA_REG_TXDESC_RING_SIZE(n) (0x100c + (0x1000 * n)) +#define DEVSOC_EDMA_REG_TXDESC_CTRL(n) (0x1010 + (0x1000 * n)) +#define DEVSOC_EDMA_REG_TXDESC_BA2(n) (0x1014 + (0x1000 * n)) + +#define DEVSOC_EDMA_REG_RXFILL_BA(n) (0x29000 + (0x1000 * n)) +#define DEVSOC_EDMA_REG_RXFILL_PROD_IDX(n) (0x29004 + (0x1000 * n)) +#define DEVSOC_EDMA_REG_RXFILL_CONS_IDX(n) (0x29008 + (0x1000 * n)) +#define DEVSOC_EDMA_REG_RXFILL_RING_SIZE(n) (0x2900c + (0x1000 * n)) +#define DEVSOC_EDMA_REG_RXFILL_RING_EN(n) (0x2901c + (0x1000 * n)) +#define DEVSOC_EDMA_REG_RXFILL_INT_STAT(n) (0x31000 + (0x1000 * n)) +#define DEVSOC_EDMA_REG_RXFILL_INT_MASK(n) (0x31004 + (0x1000 * n)) + +#define DEVSOC_EDMA_REG_RXDESC_BA(n) (0x39000 + (0x1000 * n)) +#define DEVSOC_EDMA_REG_RXDESC_PROD_IDX(n) (0x39004 + (0x1000 * n)) +#define DEVSOC_EDMA_REG_RXDESC_CONS_IDX(n) (0x39008 + (0x1000 * n)) +#define DEVSOC_EDMA_REG_RXDESC_RING_SIZE(n) (0x3900c + (0x1000 * n)) +#define DEVSOC_EDMA_REG_RXDESC_FC_THRE(n) (0x39010 + (0x1000 * n)) +#define DEVSOC_EDMA_REG_RXDESC_CTRL(n) (0x39018 + (0x1000 * n)) +#define DEVSOC_EDMA_REG_RXDESC_BA2(n) (0x39028 + (0x1000 * n)) +#define DEVSOC_EDMA_REG_RXDESC_INT_STAT(n) (0x59000 + (0x1000 * n)) +#define DEVSOC_EDMA_REG_RXDESC_INT_MASK(n) (0x59004 + (0x1000 * n)) +#define DEVSOC_EDMA_REG_RX_INT_CTRL(n) (0x5900c + (0x1000 * n)) + +#define DEVSOC_EDMA_REG_TXCMPL_BA(n) (0x79000 + (0x1000 * n)) +#define DEVSOC_EDMA_REG_TXCMPL_PROD_IDX(n) (0x79004 + (0x1000 * n)) +#define DEVSOC_EDMA_REG_TXCMPL_CONS_IDX(n) (0x79008 + (0x1000 * n)) +#define DEVSOC_EDMA_REG_TXCMPL_RING_SIZE(n) (0x7900c + (0x1000 * n)) +#define DEVSOC_EDMA_REG_TXCMPL_CTRL(n) (0x79014 + (0x1000 * n)) + +#define DEVSOC_EDMA_REG_TX_INT_STAT(n) (0x99000 + (0x1000 * n)) +#define DEVSOC_EDMA_REG_TX_INT_MASK(n) (0x99004 + (0x1000 * n)) +#define DEVSOC_EDMA_REG_TX_INT_CTRL(n) (0x9900c + (0x1000 * n)) + +/* + * EDMA QID2RID configuration + */ +#define DEVSOC_EDMA_QID2RID_TABLE_MEM(q) (0xb9000 + (0x4 * q)) + +#define DEVSOC_EDMA_CPU_PORT_MC_QID_MIN 256 +#define DEVSOC_EDMA_CPU_PORT_MC_QID_MAX 271 +#define DEVSOC_EDMA_QID2RID_NUM_PER_REG 4 + +/* + * EDMA_REG_DMAR_CTRL register + */ +#define DEVSOC_EDMA_DMAR_REQ_PRI_MASK 0x7 +#define DEVSOC_EDMA_DMAR_REQ_PRI_SHIFT 0x0 +#define DEVSOC_EDMA_DMAR_BURST_LEN_MASK 0x1 +#define DEVSOC_EDMA_DMAR_BURST_LEN_SHIFT 3 +#define DEVSOC_EDMA_DMAR_TXDATA_OUTSTANDING_NUM_MASK 0x1f +#define DEVSOC_EDMA_DMAR_TXDATA_OUTSTANDING_NUM_SHIFT 4 +#define DEVSOC_EDMA_DMAR_TXDESC_OUTSTANDING_NUM_MASK 0x7 +#define DEVSOC_EDMA_DMAR_TXDESC_OUTSTANDING_NUM_SHIFT 9 +#define DEVSOC_EDMA_DMAR_RXFILL_OUTSTANDING_NUM_MASK 0x7 +#define DEVSOC_EDMA_DMAR_RXFILL_OUTSTANDING_NUM_SHIFT 12 + +#define DEVSOC_EDMA_DMAR_REQ_PRI_SET(x) (((x) & DEVSOC_EDMA_DMAR_REQ_PRI_MASK) \ + << DEVSOC_EDMA_DMAR_REQ_PRI_SHIFT) +#define DEVSOC_EDMA_DMAR_TXDATA_OUTSTANDING_NUM_SET(x) (((x) & DEVSOC_EDMA_DMAR_TXDATA_OUTSTANDING_NUM_MASK) \ + << DEVSOC_EDMA_DMAR_TXDATA_OUTSTANDING_NUM_SHIFT) +#define DEVSOC_EDMA_DMAR_TXDESC_OUTSTANDING_NUM_SET(x) (((x) & DEVSOC_EDMA_DMAR_TXDESC_OUTSTANDING_NUM_MASK) \ + << DEVSOC_EDMA_DMAR_TXDESC_OUTSTANDING_NUM_SHIFT) +#define DEVSOC_EDMA_DMAR_RXFILL_OUTSTANDING_NUM_SET(x) (((x) & DEVSOC_EDMA_DMAR_RXFILL_OUTSTANDING_NUM_MASK) \ + << DEVSOC_EDMA_DMAR_RXFILL_OUTSTANDING_NUM_SHIFT) +#define DEVSOC_EDMA_DMAR_BURST_LEN_SET(x) (((x) & DEVSOC_EDMA_DMAR_BURST_LEN_MASK) \ + << DEVSOC_EDMA_DMAR_BURST_LEN_SHIFT) + +#define DEVSOC_EDMA_BURST_LEN_ENABLE 0x0 + +/* + * EDMA_REG_PORT_CTRL register + */ +#define DEVSOC_EDMA_PORT_CTRL_EN 0x3 + +/* + * EDMA_REG_TXDESC_PROD_IDX register + */ +#define DEVSOC_EDMA_TXDESC_PROD_IDX_MASK 0xffff + +/* + * EDMA_REG_TXDESC_CONS_IDX register + */ +#define DEVSOC_EDMA_TXDESC_CONS_IDX_MASK 0xffff + +/* + * EDMA_REG_TXDESC_RING_SIZE register + */ +#define DEVSOC_EDMA_TXDESC_RING_SIZE_MASK 0xffff + +/* + * EDMA_REG_TXDESC_CTRL register + */ +#define DEVSOC_EDMA_TXDESC_TX_EN 0x1 + +/* + * EDMA_REG_TXCMPL_PROD_IDX register + */ +#define DEVSOC_EDMA_TXCMPL_PROD_IDX_MASK 0xffff + +/* + * EDMA_REG_TXCMPL_CONS_IDX register + */ +#define DEVSOC_EDMA_TXCMPL_CONS_IDX_MASK 0xffff + +/* + * EDMA_REG_TX_INT_CTRL register + */ +#define DEVSOC_EDMA_TX_INT_MASK 0x3 + +/* + * EDMA_REG_RXFILL_PROD_IDX register + */ +#define DEVSOC_EDMA_RXFILL_PROD_IDX_MASK 0xffff + +/* + * EDMA_REG_RXFILL_CONS_IDX register + */ +#define DEVSOC_EDMA_RXFILL_CONS_IDX_MASK 0xffff + +/* + * EDMA_REG_RXFILL_RING_SIZE register + */ +#define DEVSOC_EDMA_RXFILL_RING_SIZE_MASK 0xffff +#define DEVSOC_EDMA_RXFILL_BUF_SIZE_MASK 0xffff0000 +#define DEVSOC_EDMA_RXFILL_BUF_SIZE_SHIFT 16 + +/* + * EDMA_REG_RXFILL_RING_EN register + */ +#define DEVSOC_EDMA_RXFILL_RING_EN 0x1 + +/* + * EDMA_REG_RXFILL_INT_MASK register + */ +#define DEVSOC_EDMA_RXFILL_INT_MASK 0x1 + +/* + * EDMA_REG_RXDESC_PROD_IDX register + */ +#define DEVSOC_EDMA_RXDESC_PROD_IDX_MASK 0xffff + +/* + * EDMA_REG_RXDESC_CONS_IDX register + */ +#define DEVSOC_EDMA_RXDESC_CONS_IDX_MASK 0xffff + +/* + * EDMA_REG_RXDESC_RING_SIZE register + */ +#define DEVSOC_EDMA_RXDESC_RING_SIZE_MASK 0xffff +#define DEVSOC_EDMA_RXDESC_PL_OFFSET_MASK 0x1ff +#define DEVSOC_EDMA_RXDESC_PL_OFFSET_SHIFT 16 + +/* + * EDMA_REG_RXDESC_CTRL register + */ +#define DEVSOC_EDMA_RXDESC_RX_EN 0x1 + +/* + * EDMA_REG_TX_INT_MASK register + */ +#define DEVSOC_EDMA_TX_INT_MASK_PKT_INT 0x1 +#define DEVSOC_EDMA_TX_INT_MASK_UGT_INT 0x2 + +/* + * EDMA_REG_RXDESC_INT_MASK register + */ +#define DEVSOC_EDMA_RXDESC_INT_MASK_PKT_INT 0x1 +#define DEVSOC_EDMA_MASK_INT_DISABLE 0x0 + +/* + * TXDESC shift values + */ +#define DEVSOC_EDMA_TXDESC_DATA_OFFSET_SHIFT 0 +#define DEVSOC_EDMA_TXDESC_DATA_OFFSET_MASK 0xfff + +#define DEVSOC_EDMA_TXDESC_DATA_LENGTH_SHIFT 0 +#define DEVSOC_EDMA_TXDESC_DATA_LENGTH_MASK 0x1ffff + +#define DEVSOC_EDMA_DST_PORT_TYPE 2 +#define DEVSOC_EDMA_DST_PORT_TYPE_SHIFT 28 +#define DEVSOC_EDMA_DST_PORT_TYPE_MASK (0xf << DEVSOC_EDMA_DST_PORT_TYPE_SHIFT) +#define DEVSOC_EDMA_DST_PORT_ID_SHIFT 16 +#define DEVSOC_EDMA_DST_PORT_ID_MASK (0xfff << DEVSOC_EDMA_DST_PORT_ID_SHIFT) + +#define DEVSOC_EDMA_DST_PORT_TYPE_SET(x) (((x) << DEVSOC_EDMA_DST_PORT_TYPE_SHIFT) & DEVSOC_EDMA_DST_PORT_TYPE_MASK) +#define DEVSOC_EDMA_DST_PORT_ID_SET(x) (((x) << EDMA_DST_PORT_ID_SHIFT) & EDMA_DST_PORT_ID_MASK) + +#define DEVSOC_EDMA_RXDESC_SRCINFO_TYPE_PORTID 0x2000 +#define DEVSOC_EDMA_RXDESC_SRCINFO_TYPE_SHIFT 8 +#define DEVSOC_EDMA_RXDESC_SRCINFO_TYPE_MASK 0xf000 +#define DEVSOC_EDMA_RXDESC_PORTNUM_BITS 0x0FFF + +#define DEVSOC_EDMA_RING_DMA_MASK 0xffffffff + +/* + * RXDESC shift values + */ +#define DEVSOC_EDMA_RXDESC_PKT_SIZE_MASK 0x3ffff +#define DEVSOC_EDMA_RXDESC_PKT_SIZE_SHIFT 0 +#define DEVSOC_EDMA_RXDESC_SRC_INFO_GET(x) (x & 0xFFFF) +#define DEVSOC_EDMA_RXDESC_RING_INT_STATUS_MASK 0x3 +#define DEVSOC_EDMA_RXFILL_RING_INT_STATUS_MASK 0x1 + +#define DEVSOC_EDMA_TXCMPL_RING_INT_STATUS_MASK 0x3 +#define DEVSOC_EDMA_TXCMPL_RETMODE_OPAQUE 0x0 +#define DEVSOC_EDMA_TX_NE_INT_EN 0x2 +#define DEVSOC_EDMA_RX_NE_INT_EN 0x2 +#define DEVSOC_EDMA_TX_INITIAL_PROD_IDX 0x0 + +#endif /* __EDMA_REGS__ */ diff --git a/board/qca/arm/devsoc/devsoc.c b/board/qca/arm/devsoc/devsoc.c index 1b505c5974..ee2a700dab 100644 --- a/board/qca/arm/devsoc/devsoc.c +++ b/board/qca/arm/devsoc/devsoc.c @@ -38,6 +38,7 @@ DECLARE_GLOBAL_DATA_PTR; +extern int devsoc_edma_init(void *cfg); extern int ipq_spi_init(u16); const char *rsvd_node = "/reserved-memory"; @@ -499,3 +500,16 @@ void ipq_fdt_fixup_usb_device_mode(void *blob) { return; } + +#ifdef CONFIG_DEVSOC_EDMA +int board_eth_init(bd_t *bis) +{ + int ret = 0; + + ret = devsoc_edma_init(NULL); + if (ret != 0) + printf("%s: devsoc_edma_init failed : %d\n", __func__, ret); + + return ret; +} +#endif diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 8f0b4daa69..da4cd26730 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -93,6 +93,13 @@ obj-$(CONFIG_IPQ5018_GMAC) += ipq5018/ipq5018_gmac.o obj-$(CONFIG_IPQ5018_GMAC) += ipq5018/ipq5018_uniphy.o obj-$(CONFIG_IPQ5018_MDIO) += ipq5018/ipq5018_mdio.o obj-$(CONFIG_IPQ5018_GMAC) += ipq5018/athrs17_phy.o +obj-$(CONFIG_DEVSOC_EDMA) += devsoc/devsoc_edma.o +obj-$(CONFIG_DEVSOC_EDMA) += devsoc/devsoc_ppe.o + +ifndef CONFIG_DEVSOC_RUMI +obj-$(CONFIG_DEVSOC_EDMA) += devsoc/devsoc_uniphy.o +endif + obj-$(CONFIG_IPQ_MDIO) += ipq_common/ipq_mdio.o obj-$(CONFIG_GEPHY) += ipq_common/ipq_gephy.o obj-$(CONFIG_QCA8075_PHY) += ipq_common/ipq_qca8075.o diff --git a/drivers/net/devsoc/devsoc_edma.c b/drivers/net/devsoc/devsoc_edma.c new file mode 100644 index 0000000000..44044a5872 --- /dev/null +++ b/drivers/net/devsoc/devsoc_edma.c @@ -0,0 +1,2013 @@ +/* + ************************************************************************** + * Copyright (c) 2016-2019, 2021, The Linux Foundation. All rights reserved. + * + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "devsoc_edma.h" +#include "ipq_phy.h" + +DECLARE_GLOBAL_DATA_PTR; +#ifdef DEBUG +#define pr_debug(fmt, args...) printf(fmt, ##args); +#else +#define pr_debug(fmt, args...) +#endif + +#define pr_info(fmt, args...) printf(fmt, ##args); +#define pr_warn(fmt, args...) printf(fmt, ##args); + +#ifndef CONFIG_DEVSOC_BRIDGED_MODE +#define DEVSOC_EDMA_MAC_PORT_NO 3 +#endif + +static struct devsoc_eth_dev *devsoc_edma_dev[DEVSOC_EDMA_DEV]; + +uchar devsoc_def_enetaddr[6] = {0x00, 0x03, 0x7F, 0xBA, 0xDB, 0xAD}; +phy_info_t *phy_info[DEVSOC_PHY_MAX] = {0}; +int sgmii_mode[2] = {0}; + +#ifndef CONFIG_DEVSOC_RUMI +extern int ipq_sw_mdio_init(const char *); +extern int ipq_mdio_read(int mii_id, int regnum, ushort *data); +extern void devsoc_qca8075_phy_map_ops(struct phy_ops **ops); +extern int devsoc_qca8075_phy_init(struct phy_ops **ops, u32 phy_id); +extern void devsoc_qca8075_phy_interface_set_mode(uint32_t phy_id, uint32_t mode); +extern int ipq_qca8033_phy_init(struct phy_ops **ops, u32 phy_id); +extern int ipq_qca8081_phy_init(struct phy_ops **ops, u32 phy_id); +extern int ipq_qca_aquantia_phy_init(struct phy_ops **ops, u32 phy_id); +extern int ipq_board_fw_download(unsigned int phy_addr); +#endif + +static int tftp_acl_our_port; + +/* + * EDMA hardware instance + */ +static u32 devsoc_edma_hw_addr; + +/* + * devsoc_edma_reg_read() + * Read EDMA register + */ +uint32_t devsoc_edma_reg_read(uint32_t reg_off) +{ + return (uint32_t)readl(devsoc_edma_hw_addr + reg_off); +} + +/* + * devsoc_edma_reg_write() + * Write EDMA register + */ +void devsoc_edma_reg_write(uint32_t reg_off, uint32_t val) +{ + writel(val, (devsoc_edma_hw_addr + reg_off)); +} + +/* + * devsoc_edma_alloc_rx_buffer() + * Alloc Rx buffers for one RxFill ring + */ +int devsoc_edma_alloc_rx_buffer(struct devsoc_edma_hw *ehw, + struct devsoc_edma_rxfill_ring *rxfill_ring) +{ + uint16_t num_alloc = 0; + uint16_t cons, next, counter; + struct devsoc_edma_rxfill_desc *rxfill_desc; + uint32_t reg_data; + + /* + * Read RXFILL ring producer index + */ + reg_data = devsoc_edma_reg_read(DEVSOC_EDMA_REG_RXFILL_PROD_IDX( + rxfill_ring->id)); + + next = reg_data & DEVSOC_EDMA_RXFILL_PROD_IDX_MASK & (rxfill_ring->count - 1); + + /* + * Read RXFILL ring consumer index + */ + reg_data = devsoc_edma_reg_read(DEVSOC_EDMA_REG_RXFILL_CONS_IDX( + rxfill_ring->id)); + + cons = reg_data & DEVSOC_EDMA_RXFILL_CONS_IDX_MASK; + + while (1) { + counter = next; + + if (++counter == rxfill_ring->count) + counter = 0; + + if (counter == cons) + break; + + /* + * Get RXFILL descriptor + */ + rxfill_desc = DEVSOC_EDMA_RXFILL_DESC(rxfill_ring, next); + + /* + * Fill the opaque value + */ + rxfill_desc->rdes2 = next; + + /* + * Save buffer size in RXFILL descriptor + */ + rxfill_desc->rdes1 |= cpu_to_le32((DEVSOC_EDMA_RX_BUFF_SIZE << + DEVSOC_EDMA_RXFILL_BUF_SIZE_SHIFT) & + DEVSOC_EDMA_RXFILL_BUF_SIZE_MASK); + num_alloc++; + next = counter; + } + + if (num_alloc) { + /* + * Update RXFILL ring producer index + */ + reg_data = next & DEVSOC_EDMA_RXFILL_PROD_IDX_MASK; + + /* + * make sure the producer index updated before + * updating the hardware + */ + devsoc_edma_reg_write(DEVSOC_EDMA_REG_RXFILL_PROD_IDX( + rxfill_ring->id), reg_data); + + pr_debug("%s: num_alloc = %d\n", __func__, num_alloc); + } + + return num_alloc; +} + +/* + * devsoc_edma_clean_tx() + * Reap Tx descriptors + */ +uint32_t devsoc_edma_clean_tx(struct devsoc_edma_hw *ehw, + struct devsoc_edma_txcmpl_ring *txcmpl_ring) +{ + struct devsoc_edma_txcmpl_desc *txcmpl_desc; + uint16_t prod_idx, cons_idx; + uint32_t data; + uint32_t txcmpl_consumed = 0; + uchar *skb; + + /* + * Get TXCMPL ring producer index + */ + data = devsoc_edma_reg_read(DEVSOC_EDMA_REG_TXCMPL_PROD_IDX( + txcmpl_ring->id)); + prod_idx = data & DEVSOC_EDMA_TXCMPL_PROD_IDX_MASK; + + /* + * Get TXCMPL ring consumer index + */ + data = devsoc_edma_reg_read(DEVSOC_EDMA_REG_TXCMPL_CONS_IDX( + txcmpl_ring->id)); + cons_idx = data & DEVSOC_EDMA_TXCMPL_CONS_IDX_MASK; + + while (cons_idx != prod_idx) { + + txcmpl_desc = DEVSOC_EDMA_TXCMPL_DESC(txcmpl_ring, cons_idx); + + skb = (uchar *)txcmpl_desc->tdes0; + + if (unlikely(!skb)) { + printf("Invalid skb: cons_idx:%u prod_idx:%u\n", + cons_idx, prod_idx); + } + + if (++cons_idx == txcmpl_ring->count) + cons_idx = 0; + + txcmpl_consumed++; + } + + pr_debug("%s :%u txcmpl_consumed:%u prod_idx:%u cons_idx:%u\n", + __func__, txcmpl_ring->id, txcmpl_consumed, prod_idx, + cons_idx); + + if (txcmpl_consumed == 0) + return 0; + + /* + * Update TXCMPL ring consumer index + */ + devsoc_edma_reg_write(DEVSOC_EDMA_REG_TXCMPL_CONS_IDX( + txcmpl_ring->id), cons_idx); + + return txcmpl_consumed; +} + +/* + * devsoc_edma_clean_rx() + * Reap Rx descriptors + */ +uint32_t devsoc_edma_clean_rx(struct devsoc_edma_common_info *c_info, + struct devsoc_edma_rxdesc_ring *rxdesc_ring) +{ + void *skb; + struct devsoc_edma_rxdesc_desc *rxdesc_desc; + uint16_t prod_idx, cons_idx; + int src_port_num; + int pkt_length; + int rx = CONFIG_SYS_RX_ETH_BUFFER; + u16 cleaned_count = 0; + struct devsoc_edma_hw *ehw = &c_info->hw; + + pr_debug("%s: rxdesc_ring->id = %d\n", __func__, rxdesc_ring->id); + /* + * Read Rx ring consumer index + */ + cons_idx = devsoc_edma_reg_read(DEVSOC_EDMA_REG_RXDESC_CONS_IDX( + rxdesc_ring->id)) & + DEVSOC_EDMA_RXDESC_CONS_IDX_MASK; + + while (rx) { + /* + * Read Rx ring producer index + */ + prod_idx = devsoc_edma_reg_read( + DEVSOC_EDMA_REG_RXDESC_PROD_IDX(rxdesc_ring->id)) + & DEVSOC_EDMA_RXDESC_PROD_IDX_MASK; + + if (cons_idx == prod_idx) { + pr_debug("%s: cons idx = %u, prod idx = %u\n", + __func__, cons_idx, prod_idx); + break; + } + + rxdesc_desc = DEVSOC_EDMA_RXDESC_DESC(rxdesc_ring, cons_idx); + + skb = (void *)rxdesc_desc->rdes0; + + rx--; + + /* + * Check src_info from Rx Descriptor + */ + src_port_num = DEVSOC_EDMA_RXDESC_SRC_INFO_GET(rxdesc_desc->rdes4); + if ((src_port_num & DEVSOC_EDMA_RXDESC_SRCINFO_TYPE_MASK) == + DEVSOC_EDMA_RXDESC_SRCINFO_TYPE_PORTID) { + src_port_num &= DEVSOC_EDMA_RXDESC_PORTNUM_BITS; + } else { + pr_warn("WARN: src_info_type:0x%x. Drop skb:%p\n", + (src_port_num & DEVSOC_EDMA_RXDESC_SRCINFO_TYPE_MASK), + skb); + goto next_rx_desc; + } + + /* + * Get packet length + */ + pkt_length = (rxdesc_desc->rdes5 & + DEVSOC_EDMA_RXDESC_PKT_SIZE_MASK) >> + DEVSOC_EDMA_RXDESC_PKT_SIZE_SHIFT; + + if (unlikely((src_port_num < DEVSOC_NSS_DP_START_PHY_PORT) || + (src_port_num > DEVSOC_NSS_DP_MAX_PHY_PORTS))) { + pr_warn("WARN: Port number error :%d. Drop skb:%p\n", + src_port_num, skb); + goto next_rx_desc; + } + + cleaned_count++; + + pr_debug("%s: received pkt %p with length %d\n", + __func__, skb, pkt_length); + + net_process_received_packet(skb, pkt_length); +next_rx_desc: + /* + * Update consumer index + */ + if (++cons_idx == rxdesc_ring->count) + cons_idx = 0; + } + + if (cleaned_count) { + devsoc_edma_alloc_rx_buffer(ehw, rxdesc_ring->rxfill); + devsoc_edma_reg_write(DEVSOC_EDMA_REG_RXDESC_CONS_IDX( + rxdesc_ring->id), cons_idx); + } + + return 0; +} + +/* + * devsoc_edma_rx_complete() + */ +static int devsoc_edma_rx_complete(struct devsoc_edma_common_info *c_info) +{ + struct devsoc_edma_hw *ehw = &c_info->hw; + struct devsoc_edma_txcmpl_ring *txcmpl_ring; + struct devsoc_edma_rxdesc_ring *rxdesc_ring; + struct devsoc_edma_rxfill_ring *rxfill_ring; + uint32_t misc_intr_status, reg_data; + int i; + + for (i = 0; i < ehw->rxdesc_rings; i++) { + rxdesc_ring = &ehw->rxdesc_ring[i]; + devsoc_edma_clean_rx(c_info, rxdesc_ring); + } + + for (i = 0; i < ehw->txcmpl_rings; i++) { + txcmpl_ring = &ehw->txcmpl_ring[i]; + devsoc_edma_clean_tx(ehw, txcmpl_ring); + } + + for (i = 0; i < ehw->rxfill_rings; i++) { + rxfill_ring = &ehw->rxfill_ring[i]; + devsoc_edma_alloc_rx_buffer(ehw, rxfill_ring); + } + + /* + * Enable RXDESC EDMA ring interrupt masks + */ + for (i = 0; i < ehw->rxdesc_rings; i++) { + rxdesc_ring = &ehw->rxdesc_ring[i]; + devsoc_edma_reg_write( + DEVSOC_EDMA_REG_RXDESC_INT_MASK(rxdesc_ring->id), + ehw->rxdesc_intr_mask); + } + + /* + * Enable TX EDMA ring interrupt masks + */ + for (i = 0; i < ehw->txcmpl_rings; i++) { + txcmpl_ring = &ehw->txcmpl_ring[i]; + devsoc_edma_reg_write(DEVSOC_EDMA_REG_TX_INT_MASK( + txcmpl_ring->id), + ehw->txcmpl_intr_mask); + } + + /* + * Enable RXFILL EDMA ring interrupt masks + */ + for (i = 0; i < ehw->rxfill_rings; i++) { + rxfill_ring = &ehw->rxfill_ring[i]; + devsoc_edma_reg_write(DEVSOC_EDMA_REG_RXFILL_INT_MASK( + rxfill_ring->id), + ehw->rxfill_intr_mask); + } + + /* + * Read Misc intr status + */ + reg_data = devsoc_edma_reg_read(DEVSOC_EDMA_REG_MISC_INT_STAT); + misc_intr_status = reg_data & ehw->misc_intr_mask; + + if (misc_intr_status != 0) { + pr_info("%s: misc_intr_status = 0x%x\n", __func__, + misc_intr_status); + devsoc_edma_reg_write(DEVSOC_EDMA_REG_MISC_INT_MASK, + DEVSOC_EDMA_MASK_INT_DISABLE); + } + + return 0; +} + +/* + * devsoc_eth_snd() + * Transmit a packet using an EDMA ring + */ +static int devsoc_eth_snd(struct eth_device *dev, void *packet, int length) +{ + struct devsoc_eth_dev *priv = dev->priv; + struct devsoc_edma_common_info *c_info = priv->c_info; + struct devsoc_edma_hw *ehw = &c_info->hw; + struct devsoc_edma_txdesc_desc *txdesc; + struct devsoc_edma_txdesc_ring *txdesc_ring; + uint16_t hw_next_to_use, hw_next_to_clean, chk_idx; + uint32_t data; + uchar *skb; + + txdesc_ring = ehw->txdesc_ring; + + if (tftp_acl_our_port != tftp_our_port) { + /* Allowing tftp packets */ + devsoc_ppe_acl_set(3, 0x4, 0x1, tftp_our_port, 0xffff, 0, 0); + tftp_acl_our_port = tftp_our_port; + } + /* + * Read TXDESC ring producer index + */ + data = devsoc_edma_reg_read(DEVSOC_EDMA_REG_TXDESC_PROD_IDX( + txdesc_ring->id)); + + hw_next_to_use = data & DEVSOC_EDMA_TXDESC_PROD_IDX_MASK; + + pr_debug("%s: txdesc_ring->id = %d\n", __func__, txdesc_ring->id); + + /* + * Read TXDESC ring consumer index + */ + /* + * TODO - read to local variable to optimize uncached access + */ + data = devsoc_edma_reg_read( + DEVSOC_EDMA_REG_TXDESC_CONS_IDX(txdesc_ring->id)); + + hw_next_to_clean = data & DEVSOC_EDMA_TXDESC_CONS_IDX_MASK; + + /* + * Check for available Tx descriptor + */ + chk_idx = (hw_next_to_use + 1) & (txdesc_ring->count - 1); + + if (chk_idx == hw_next_to_clean) { + pr_info("netdev tx busy"); + return NETDEV_TX_BUSY; + } + + /* + * Get Tx descriptor + */ + txdesc = DEVSOC_EDMA_TXDESC_DESC(txdesc_ring, hw_next_to_use); + + txdesc->tdes1 = 0; + txdesc->tdes2 = 0; + txdesc->tdes3 = 0; + txdesc->tdes4 = 0; + txdesc->tdes5 = 0; + txdesc->tdes6 = 0; + txdesc->tdes7 = 0; + skb = (uchar *)txdesc->tdes0; + + pr_debug("%s: txdesc->tdes0 (buffer addr) = 0x%x length = %d \ + prod_idx = %d cons_idx = %d\n", + __func__, txdesc->tdes0, length, + hw_next_to_use, hw_next_to_clean); + +#ifdef CONFIG_DEVSOC_BRIDGED_MODE + /* VP 0x0 share vsi 2 with port 1-4 */ + /* src is 0x2000, dest is 0x0 */ + txdesc->tdes4 = 0x00002000; +#else + /* + * Populate Tx dst info, port id is macid in dp_dev + * We have separate netdev for each port in Kernel but that is not the + * case in U-Boot. + * This part needs to be fixed to support multiple ports in non bridged + * mode during when all the ports are currently under same netdev. + * + * Currently mac port no. is fixed as 3 for the purpose of testing + */ + txdesc->tdes4 |= (DEVSOC_EDMA_DST_PORT_TYPE_SET(DEVSOC_EDMA_DST_PORT_TYPE) | + DEVSOC_EDMA_DST_PORT_ID_SET(DEVSOC_EDMA_MAC_PORT_NO)); +#endif + + /* + * Set opaque field + */ + txdesc->tdes2 = cpu_to_le32(skb); + + /* + * copy the packet + */ + memcpy(skb, packet, length); + + /* + * Populate Tx descriptor + */ + txdesc->tdes5 |= ((length << DEVSOC_EDMA_TXDESC_DATA_LENGTH_SHIFT) & + DEVSOC_EDMA_TXDESC_DATA_LENGTH_MASK); + + /* + * Update producer index + */ + hw_next_to_use = (hw_next_to_use + 1) & (txdesc_ring->count - 1); + + /* + * make sure the hw_next_to_use is updated before the + * write to hardware + */ + + devsoc_edma_reg_write(DEVSOC_EDMA_REG_TXDESC_PROD_IDX( + txdesc_ring->id), hw_next_to_use & + DEVSOC_EDMA_TXDESC_PROD_IDX_MASK); + + pr_debug("%s: successfull\n", __func__); + + return EDMA_TX_OK; +} + +static int devsoc_eth_recv(struct eth_device *dev) +{ + struct devsoc_eth_dev *priv = dev->priv; + struct devsoc_edma_common_info *c_info = priv->c_info; + struct devsoc_edma_rxdesc_ring *rxdesc_ring; + struct devsoc_edma_txcmpl_ring *txcmpl_ring; + struct devsoc_edma_rxfill_ring *rxfill_ring; + struct devsoc_edma_hw *ehw = &c_info->hw; + volatile u32 reg_data; + u32 rxdesc_intr_status = 0, txcmpl_intr_status = 0, rxfill_intr_status = 0; + int i; + + /* + * Read RxDesc intr status + */ + for (i = 0; i < ehw->rxdesc_rings; i++) { + rxdesc_ring = &ehw->rxdesc_ring[i]; + + reg_data = devsoc_edma_reg_read( + DEVSOC_EDMA_REG_RXDESC_INT_STAT( + rxdesc_ring->id)); + rxdesc_intr_status |= reg_data & + DEVSOC_EDMA_RXDESC_RING_INT_STATUS_MASK; + + /* + * Disable RxDesc intr + */ + devsoc_edma_reg_write(DEVSOC_EDMA_REG_RXDESC_INT_MASK( + rxdesc_ring->id), + DEVSOC_EDMA_MASK_INT_DISABLE); + } + + /* + * Read TxCmpl intr status + */ + for (i = 0; i < ehw->txcmpl_rings; i++) { + txcmpl_ring = &ehw->txcmpl_ring[i]; + + reg_data = devsoc_edma_reg_read( + DEVSOC_EDMA_REG_TX_INT_STAT( + txcmpl_ring->id)); + txcmpl_intr_status |= reg_data & + DEVSOC_EDMA_TXCMPL_RING_INT_STATUS_MASK; + + /* + * Disable TxCmpl intr + */ + devsoc_edma_reg_write(DEVSOC_EDMA_REG_TX_INT_MASK( + txcmpl_ring->id), + DEVSOC_EDMA_MASK_INT_DISABLE); + } + + /* + * Read RxFill intr status + */ + for (i = 0; i < ehw->rxfill_rings; i++) { + rxfill_ring = &ehw->rxfill_ring[i]; + + reg_data = devsoc_edma_reg_read( + DEVSOC_EDMA_REG_RXFILL_INT_STAT( + rxfill_ring->id)); + rxfill_intr_status |= reg_data & + DEVSOC_EDMA_RXFILL_RING_INT_STATUS_MASK; + + /* + * Disable RxFill intr + */ + devsoc_edma_reg_write(DEVSOC_EDMA_REG_RXFILL_INT_MASK( + rxfill_ring->id), + DEVSOC_EDMA_MASK_INT_DISABLE); + } + + if ((rxdesc_intr_status != 0) || (txcmpl_intr_status != 0) || + (rxfill_intr_status != 0)) { + for (i = 0; i < ehw->rxdesc_rings; i++) { + rxdesc_ring = &ehw->rxdesc_ring[i]; + devsoc_edma_reg_write(DEVSOC_EDMA_REG_RXDESC_INT_MASK( + rxdesc_ring->id), + DEVSOC_EDMA_MASK_INT_DISABLE); + } + devsoc_edma_rx_complete(c_info); + } + + return 0; +} + +/* + * devsoc_edma_setup_ring_resources() + * Allocate/setup resources for EDMA rings + */ +static int devsoc_edma_setup_ring_resources(struct devsoc_edma_hw *ehw) +{ + struct devsoc_edma_txcmpl_ring *txcmpl_ring; + struct devsoc_edma_txdesc_ring *txdesc_ring; + struct devsoc_edma_rxfill_ring *rxfill_ring; + struct devsoc_edma_rxdesc_ring *rxdesc_ring; + struct devsoc_edma_txdesc_desc *txdesc_desc; + struct devsoc_edma_rxfill_desc *rxfill_desc; + int i, j, index; + void *tx_buf; + void *rx_buf; + + /* + * Allocate Rx fill ring descriptors + */ + for (i = 0; i < ehw->rxfill_rings; i++) { + rxfill_ring = &ehw->rxfill_ring[i]; + rxfill_ring->count = DEVSOC_EDMA_RX_RING_SIZE; + rxfill_ring->id = ehw->rxfill_ring_start + i; + rxfill_ring->desc = (void *)noncached_alloc( + DEVSOC_EDMA_RXFILL_DESC_SIZE * rxfill_ring->count, + CONFIG_SYS_CACHELINE_SIZE); + + if (rxfill_ring->desc == NULL) { + pr_info("%s: rxfill_ring->desc alloc error\n", __func__); + return -ENOMEM; + } + rxfill_ring->dma = virt_to_phys(rxfill_ring->desc); + pr_debug("rxfill ring id = %d, rxfill ring ptr = %p, rxfill ring dma = %u\n", + rxfill_ring->id, rxfill_ring->desc, (unsigned int) + rxfill_ring->dma); + + rx_buf = (void *)noncached_alloc(DEVSOC_EDMA_RX_BUFF_SIZE * + rxfill_ring->count, + CONFIG_SYS_CACHELINE_SIZE); + + if (rx_buf == NULL) { + pr_info("%s: rxfill_ring->desc buffer alloc error\n", + __func__); + return -ENOMEM; + } + + /* + * Allocate buffers for each of the desc + */ + for (j = 0; j < rxfill_ring->count; j++) { + rxfill_desc = DEVSOC_EDMA_RXFILL_DESC(rxfill_ring, j); + rxfill_desc->rdes0 = virt_to_phys(rx_buf); + rxfill_desc->rdes1 = 0; + rxfill_desc->rdes2 = 0; + rxfill_desc->rdes3 = 0; + rx_buf += DEVSOC_EDMA_RX_BUFF_SIZE; + } + } + + /* + * Allocate RxDesc ring descriptors + */ + for (i = 0; i < ehw->rxdesc_rings; i++) { + rxdesc_ring = &ehw->rxdesc_ring[i]; + rxdesc_ring->count = DEVSOC_EDMA_RX_RING_SIZE; + rxdesc_ring->id = ehw->rxdesc_ring_start + i; + + /* + * Create a mapping between RX Desc ring and Rx fill ring. + * Number of fill rings are lesser than the descriptor rings + * Share the fill rings across descriptor rings. + */ + index = ehw->rxfill_ring_start + (i % ehw->rxfill_rings); + rxdesc_ring->rxfill = + &ehw->rxfill_ring[index - ehw->rxfill_ring_start]; + rxdesc_ring->rxfill = ehw->rxfill_ring; + + rxdesc_ring->desc = (void *)noncached_alloc( + DEVSOC_EDMA_RXDESC_DESC_SIZE * rxdesc_ring->count, + CONFIG_SYS_CACHELINE_SIZE); + if (rxdesc_ring->desc == NULL) { + pr_info("%s: rxdesc_ring->desc alloc error\n", __func__); + return -ENOMEM; + } + rxdesc_ring->dma = virt_to_phys(rxdesc_ring->desc); + + /* + * Allocate secondary Rx ring descriptors + */ + rxdesc_ring->sdesc = (void *)noncached_alloc( + DEVSOC_EDMA_RX_SEC_DESC_SIZE * rxdesc_ring->count, + CONFIG_SYS_CACHELINE_SIZE); + if (rxdesc_ring->sdesc == NULL) { + pr_info("%s: rxdesc_ring->sdesc alloc error\n", __func__); + return -ENOMEM; + } + rxdesc_ring->sdma = virt_to_phys(rxdesc_ring->sdesc); + } + + /* + * Allocate TxDesc ring descriptors + */ + for (i = 0; i < ehw->txdesc_rings; i++) { + txdesc_ring = &ehw->txdesc_ring[i]; + txdesc_ring->count = DEVSOC_EDMA_TX_RING_SIZE; + txdesc_ring->id = ehw->txdesc_ring_start + i; + txdesc_ring->desc = (void *)noncached_alloc( + DEVSOC_EDMA_TXDESC_DESC_SIZE * txdesc_ring->count, + CONFIG_SYS_CACHELINE_SIZE); + if (txdesc_ring->desc == NULL) { + pr_info("%s: txdesc_ring->desc alloc error\n", __func__); + return -ENOMEM; + } + txdesc_ring->dma = virt_to_phys(txdesc_ring->desc); + + tx_buf = (void *)noncached_alloc(DEVSOC_EDMA_TX_BUFF_SIZE * + txdesc_ring->count, + CONFIG_SYS_CACHELINE_SIZE); + if (tx_buf == NULL) { + pr_info("%s: txdesc_ring->desc buffer alloc error\n", + __func__); + return -ENOMEM; + } + + /* + * Allocate buffers for each of the desc + */ + for (j = 0; j < txdesc_ring->count; j++) { + txdesc_desc = DEVSOC_EDMA_TXDESC_DESC(txdesc_ring, j); + txdesc_desc->tdes0 = virt_to_phys(tx_buf); + txdesc_desc->tdes1 = 0; + txdesc_desc->tdes2 = 0; + txdesc_desc->tdes3 = 0; + txdesc_desc->tdes4 = 0; + txdesc_desc->tdes5 = 0; + txdesc_desc->tdes6 = 0; + txdesc_desc->tdes7 = 0; + tx_buf += DEVSOC_EDMA_TX_BUFF_SIZE; + } + + /* + * Allocate secondary Tx ring descriptors + */ + txdesc_ring->sdesc = (void *)noncached_alloc( + DEVSOC_EDMA_TX_SEC_DESC_SIZE * txdesc_ring->count, + CONFIG_SYS_CACHELINE_SIZE); + if (txdesc_ring->sdesc == NULL) { + pr_info("%s: txdesc_ring->sdesc alloc error\n", __func__); + return -ENOMEM; + } + txdesc_ring->sdma = virt_to_phys(txdesc_ring->sdesc); + } + + /* + * Allocate TxCmpl ring descriptors + */ + for (i = 0; i < ehw->txcmpl_rings; i++) { + txcmpl_ring = &ehw->txcmpl_ring[i]; + txcmpl_ring->count = DEVSOC_EDMA_TX_RING_SIZE; + txcmpl_ring->id = ehw->txcmpl_ring_start + i; + txcmpl_ring->desc = (void *)noncached_alloc( + DEVSOC_EDMA_TXCMPL_DESC_SIZE * txcmpl_ring->count, + CONFIG_SYS_CACHELINE_SIZE); + + if (txcmpl_ring->desc == NULL) { + pr_info("%s: txcmpl_ring->desc alloc error\n", __func__); + return -ENOMEM; + } + txcmpl_ring->dma = virt_to_phys(txcmpl_ring->desc); + } + + pr_info("%s: successfull\n", __func__); + + return 0; +} + +static void devsoc_edma_disable_rings(struct devsoc_edma_hw *edma_hw) +{ + int i, desc_index; + u32 data; + + /* + * Disable Rx rings + */ + for (i = 0; i < DEVSOC_EDMA_MAX_RXDESC_RINGS; i++) { + data = devsoc_edma_reg_read(DEVSOC_EDMA_REG_RXDESC_CTRL(i)); + data &= ~DEVSOC_EDMA_RXDESC_RX_EN; + devsoc_edma_reg_write(DEVSOC_EDMA_REG_RXDESC_CTRL(i), data); + } + + /* + * Disable RxFill Rings + */ + for (i = 0; i < DEVSOC_EDMA_MAX_RXFILL_RINGS; i++) { + data = devsoc_edma_reg_read( + DEVSOC_EDMA_REG_RXFILL_RING_EN(i)); + data &= ~DEVSOC_EDMA_RXFILL_RING_EN; + devsoc_edma_reg_write( + DEVSOC_EDMA_REG_RXFILL_RING_EN(i), data); + } + + /* + * Disable Tx rings + */ + for (desc_index = 0; desc_index < + DEVSOC_EDMA_MAX_TXDESC_RINGS; desc_index++) { + data = devsoc_edma_reg_read( + DEVSOC_EDMA_REG_TXDESC_CTRL(desc_index)); + data &= ~DEVSOC_EDMA_TXDESC_TX_EN; + devsoc_edma_reg_write( + DEVSOC_EDMA_REG_TXDESC_CTRL(desc_index), data); + } +} + +static void devsoc_edma_disable_intr(struct devsoc_edma_hw *ehw) +{ + int i; + + /* + * Disable interrupts + */ + for (i = 0; i < DEVSOC_EDMA_MAX_RXDESC_RINGS; i++) + devsoc_edma_reg_write(DEVSOC_EDMA_REG_RX_INT_CTRL(i), 0); + + for (i = 0; i < DEVSOC_EDMA_MAX_RXFILL_RINGS; i++) + devsoc_edma_reg_write(DEVSOC_EDMA_REG_RXFILL_INT_MASK(i), 0); + + for (i = 0; i < DEVSOC_EDMA_MAX_TXCMPL_RINGS; i++) + devsoc_edma_reg_write(DEVSOC_EDMA_REG_TX_INT_MASK(i), 0); + + /* + * Clear MISC interrupt mask + */ + devsoc_edma_reg_write(DEVSOC_EDMA_REG_MISC_INT_MASK, + DEVSOC_EDMA_MASK_INT_DISABLE); +} + +#ifndef CONFIG_DEVSOC_RUMI +static void set_sgmii_mode(int port_id, int sg_mode) +{ + if (port_id == 4) + sgmii_mode[0] = sg_mode; + else if (port_id == 5) + sgmii_mode[1] = sg_mode; +} + +static int get_sgmii_mode(int port_id) +{ + if (port_id == 4) + return sgmii_mode[0]; + else if (port_id == 5) + return sgmii_mode[1]; + else + return -1; +} +#endif + +static int devsoc_eth_init(struct eth_device *eth_dev, bd_t *this) +{ + int i; + u8 status = 0; + int mac_speed = 0x1; +#ifndef CONFIG_DEVSOC_RUMI + struct devsoc_eth_dev *priv = eth_dev->priv; + struct phy_ops *phy_get_ops; + static fal_port_speed_t old_speed[DEVSOC_PHY_MAX] = {[0 ... DEVSOC_PHY_MAX-1] = FAL_SPEED_BUTT}; + static fal_port_speed_t curr_speed[DEVSOC_PHY_MAX]; + fal_port_duplex_t duplex; + char *lstatus[] = {"up", "Down"}; + char *dp[] = {"Half", "Full"}; + int linkup = 0; + int clk[4] = {0}; + int phy_addr = -1, node = -1; + int aquantia_port[2] = {-1, -1}, aquantia_port_cnt = -1; + int sfp_port[2] = {-1, -1}, sfp_port_cnt = -1; + int sgmii_mode = -1, sfp_mode = -1, sgmii_fiber = -1; + int phy_node = -1, res = -1; + + node = fdt_path_offset(gd->fdt_blob, "/ess-switch"); + + if (node >= 0) { + aquantia_port_cnt = fdtdec_get_uint(gd->fdt_blob, node, "aquantia_port_cnt", -1); + + if (aquantia_port_cnt >= 1) { + res = fdtdec_get_int_array(gd->fdt_blob, node, "aquantia_port", + (u32 *)aquantia_port, aquantia_port_cnt); + if (res < 0) + printf("Error: Aquantia port details not provided in DT\n"); + } + + sfp_port_cnt = fdtdec_get_uint(gd->fdt_blob, node, "sfp_port_cnt", -1); + + if (sfp_port_cnt >= 1) { + res = fdtdec_get_int_array(gd->fdt_blob, node, "sfp_port", + (u32 *)sfp_port, sfp_port_cnt); + if (res < 0) + printf("Error: SFP port details not provided in DT\n"); + } + } + + phy_node = fdt_path_offset(gd->fdt_blob, "/ess-switch/port_phyinfo"); +#endif + /* + * Check PHY link, speed, Duplex on all phys. + * we will proceed even if single link is up + * else we will return with -1; + */ + for (i = 0; i < DEVSOC_PHY_MAX; i++) { +#ifndef CONFIG_DEVSOC_RUMI + if (i == sfp_port[0] || i == sfp_port[1]) { + status = phy_status_get_from_ppe(i); + duplex = FAL_FULL_DUPLEX; + /* SFP Port can be enabled in USXGMII0 or USXGMII1 i.e + * SFP Port can be port5 or port6 (with port id - 4 or 5). + * Port5 (port id - 4) -> Serdes1 + * Port6 (port id - 5) -> Serdes2 + */ + if (i == 4) { + sfp_mode = fdtdec_get_uint(gd->fdt_blob, node, "switch_mac_mode1", -1); + if (sfp_mode < 0) { + printf("Error: switch_mac_mode1 not specified in dts\n"); + return sfp_mode; + } + } else if (i == 5) { + sfp_mode = fdtdec_get_uint(gd->fdt_blob, node, "switch_mac_mode2", -1); + if (sfp_mode < 0) { + printf("Error: switch_mac_mode2 not specified in dts\n"); + return sfp_mode; + } + } else { + printf("Error: SFP Port can be enabled in USXGMII0 or USXGMII1 (Port5 or Port6) only in devsoc platform\n"); + } + if (sfp_mode == EPORT_WRAPPER_SGMII_FIBER) { + sgmii_fiber = 1; + curr_speed[i] = FAL_SPEED_1000; + } else if (sfp_mode == EPORT_WRAPPER_10GBASE_R) { + sgmii_fiber = 0; + curr_speed[i] = FAL_SPEED_10000; + } else if (sfp_mode == EPORT_WRAPPER_SGMII_PLUS) { + sgmii_fiber = 0; + curr_speed[i] = FAL_SPEED_2500; + } else { + printf("Error: Wrong mode specified for SFP Port in DT\n"); + return sfp_mode; + } + } else { + if (!priv->ops[i]) { + printf("Phy ops not mapped\n"); + continue; + } + phy_get_ops = priv->ops[i]; + + if (!phy_get_ops->phy_get_link_status || + !phy_get_ops->phy_get_speed || + !phy_get_ops->phy_get_duplex) { + printf("Error:Link status/Get speed/Get duplex not mapped\n"); + return -1; + } + + if (phy_node >= 0) { + /* + * For each ethernet port, one node should be added + * inside port_phyinfo with appropriate phy address + */ + phy_addr = phy_info[i]->phy_address; + } else { + printf("Error:Phy addresses not configured in DT\n"); + return -1; + } + + status = phy_get_ops->phy_get_link_status(priv->mac_unit, phy_addr); + phy_get_ops->phy_get_speed(priv->mac_unit, phy_addr, &curr_speed[i]); + phy_get_ops->phy_get_duplex(priv->mac_unit, phy_addr, &duplex); + } + + if (status == 0) { + linkup++; + if (old_speed[i] == curr_speed[i]) { + printf("eth%d PHY%d %s Speed :%d %s duplex\n", + priv->mac_unit, i, lstatus[status], curr_speed[i], + dp[duplex]); + continue; + } else { + old_speed[i] = curr_speed[i]; + } + } else { + printf("eth%d PHY%d %s Speed :%d %s duplex\n", + priv->mac_unit, i, lstatus[status], curr_speed[i], + dp[duplex]); + continue; + } +#endif + +#ifndef CONFIG_DEVSOC_RUMI + /* + * Note: If the current port link is up and its speed is + * different from its initially configured speed, only then + * below re-configuration is done. + * + * These conditions are checked above and if any of it + * fails, then no config is done for that eth port. + */ + switch (curr_speed[i]) { + case FAL_SPEED_10: + mac_speed = 0x0; + clk[0] = 0x209; + clk[1] = 0x9; + clk[2] = 0x309; + clk[3] = 0x9; + if (i == aquantia_port[0] || i == aquantia_port[1]) { + clk[1] = 0x18; + clk[3] = 0x18; + if (i == 4) { + clk[0] = 0x413; + clk[2] = 0x513; + } else { + clk[0] = 0x213; + clk[2] = 0x313; + } + } + if (phy_node >= 0) { + if (phy_info[i]->phy_type == QCA8081_PHY_TYPE) { + set_sgmii_mode(i, 1); + if (i == 4) { + clk[0] = 0x409; + clk[2] = 0x509; + } + } + } + printf("eth%d PHY%d %s Speed :%d %s duplex\n", + priv->mac_unit, i, lstatus[status], curr_speed[i], + dp[duplex]); + break; + case FAL_SPEED_100: + mac_speed = 0x1; + clk[0] = 0x209; + clk[1] = 0x0; + clk[2] = 0x309; + clk[3] = 0x0; + if (i == aquantia_port[0] || i == aquantia_port[1]) { + clk[1] = 0x4; + clk[3] = 0x4; + if (i == 4) { + clk[0] = 0x409; + clk[2] = 0x509; + } + } + if (phy_node >= 0) { + if (phy_info[i]->phy_type == QCA8081_PHY_TYPE) { + set_sgmii_mode(i, 1); + if (i == 4) { + clk[0] = 0x409; + clk[2] = 0x509; + } + } + } + printf("eth%d PHY%d %s Speed :%d %s duplex\n", + priv->mac_unit, i, lstatus[status], curr_speed[i], + dp[duplex]); + break; + case FAL_SPEED_1000: + mac_speed = 0x2; + clk[0] = 0x201; + clk[1] = 0x0; + clk[2] = 0x301; + clk[3] = 0x0; + if (i == aquantia_port[0] || i == aquantia_port[1]) { + if (i == 4) { + clk[0] = 0x404; + clk[2] = 0x504; + } else { + clk[0] = 0x204; + clk[2] = 0x304; + } + } else if (i == sfp_port[0] || i == sfp_port[1]) { + if (i == 4) { + clk[0] = 0x401; + clk[2] = 0x501; + } + } + if (phy_node >= 0) { + if (phy_info[i]->phy_type == QCA8081_PHY_TYPE) { + set_sgmii_mode(i, 1); + if (i == 4) { + clk[0] = 0x401; + clk[2] = 0x501; + } + } + } + printf("eth%d PHY%d %s Speed :%d %s duplex\n", + priv->mac_unit, i, lstatus[status], curr_speed[i], + dp[duplex]); + break; + case FAL_SPEED_2500: + clk[1] = 0x0; + clk[3] = 0x0; + if (i == aquantia_port[0] || i == aquantia_port[1]) { + mac_speed = 0x4; + if (i == 4) { + clk[0] = 0x407; + clk[2] = 0x507; + } else { + clk[0] = 0x207; + clk[2] = 0x307; + } + } else if (i == sfp_port[0] || i == sfp_port[1]) { + mac_speed = 0x2; + if (i == 4) { + clk[0] = 0x401; + clk[2] = 0x501; + } else { + clk[0] = 0x201; + clk[2] = 0x301; + } + } + if (phy_node >= 0) { + if (phy_info[i]->phy_type == QCA8081_PHY_TYPE) { + mac_speed = 0x2; + set_sgmii_mode(i, 0); + if (i == 4) { + clk[0] = 0x401; + clk[2] = 0x501; + } else { + clk[0] = 0x201; + clk[2] = 0x301; + } + } + } + printf("eth%d PHY%d %s Speed :%d %s duplex\n", + priv->mac_unit, i, lstatus[status], curr_speed[i], + dp[duplex]); + break; + case FAL_SPEED_5000: + mac_speed = 0x5; + clk[1] = 0x0; + clk[3] = 0x0; + if (i == 4) { + clk[0] = 0x403; + clk[2] = 0x503; + } else { + clk[0] = 0x203; + clk[2] = 0x303; + } + printf("eth%d PHY%d %s Speed :%d %s duplex\n", + priv->mac_unit, i, lstatus[status], curr_speed[i], + dp[duplex]); + break; + case FAL_SPEED_10000: + mac_speed = 0x3; + clk[1] = 0x0; + clk[3] = 0x0; + if (i == 4) { + clk[0] = 0x401; + clk[2] = 0x501; + } else { + clk[0] = 0x201; + clk[2] = 0x301; + } + printf("eth%d PHY%d %s Speed :%d %s duplex\n", + priv->mac_unit, i, lstatus[status], curr_speed[i], + dp[duplex]); + break; + default: + printf("Unknown speed\n"); + break; + } + + if (phy_node >= 0) { + if (phy_info[i]->phy_type == QCA8081_PHY_TYPE) { + sgmii_mode = get_sgmii_mode(i); + ppe_port_bridge_txmac_set(i + 1, 1); + if (sgmii_mode == 1) { /* SGMII Mode */ + if (i == 4) + ppe_uniphy_mode_set(0x1, EPORT_WRAPPER_SGMII0_RGMII4); + else if (i == 5) + ppe_uniphy_mode_set(0x2, EPORT_WRAPPER_SGMII0_RGMII4); + + } else if (sgmii_mode == 0) { /* SGMII Plus Mode */ + if (i == 4) + ppe_uniphy_mode_set(0x1, EPORT_WRAPPER_SGMII_PLUS); + else if (i == 5) + ppe_uniphy_mode_set(0x2, EPORT_WRAPPER_SGMII_PLUS); + } + } + } + + if (i == sfp_port[0] || i == sfp_port[1]) { + if (sgmii_fiber) { /* SGMII Fiber mode */ + ppe_port_bridge_txmac_set(i + 1, 1); + if (i == 4) + ppe_uniphy_mode_set(0x1, EPORT_WRAPPER_SGMII_FIBER); + else + ppe_uniphy_mode_set(0x2, EPORT_WRAPPER_SGMII_FIBER); + ppe_port_mux_mac_type_set(i + 1, EPORT_WRAPPER_SGMII_FIBER); + } else if (sfp_mode == EPORT_WRAPPER_10GBASE_R) { /* 10GBASE_R mode */ + if (i == 4) + ppe_uniphy_mode_set(0x1, EPORT_WRAPPER_10GBASE_R); + else + ppe_uniphy_mode_set(0x2, EPORT_WRAPPER_10GBASE_R); + ppe_port_mux_mac_type_set(i + 1, EPORT_WRAPPER_10GBASE_R); + } else { /* SGMII Plus Mode */ + ppe_port_bridge_txmac_set(i + 1, 1); + if (i == 4) + ppe_uniphy_mode_set(0x1, EPORT_WRAPPER_SGMII_PLUS); + else if (i == 5) + ppe_uniphy_mode_set(0x2, EPORT_WRAPPER_SGMII_PLUS); + } + } + + devsoc_speed_clock_set(i, clk); + + devsoc_port_mac_clock_reset(i); + + if (i == aquantia_port[0] || i == aquantia_port[1]) + devsoc_uxsgmii_speed_set(i, mac_speed, duplex, status); + else if ((i == sfp_port[0] || i == sfp_port[1]) && sgmii_fiber == 0) + devsoc_10g_r_speed_set(i, status); + else + devsoc_pqsgmii_speed_set(i, mac_speed, status); +#else + ppe_port_bridge_txmac_set(i + 1, 1); + //FAL_SPEED_5000 + mac_speed = 0x5; + devsoc_uxsgmii_speed_set(i, mac_speed, FAL_DUPLEX_BUTT, status); +#endif + } + +#ifndef CONFIG_DEVSOC_RUMI + if (linkup <= 0) { + /* No PHY link is alive */ + return -1; + } +#endif + + pr_info("%s: done\n", __func__); + + return 0; +} + +static int devsoc_edma_wr_macaddr(struct eth_device *dev) +{ + return 0; +} + +static void devsoc_eth_halt(struct eth_device *dev) +{ + pr_debug("\n\n*****GMAC0 info*****\n"); + pr_debug("GMAC0 RXPAUSE(0x3a001044):%x\n", readl(0x3a001044)); + pr_debug("GMAC0 TXPAUSE(0x3a0010A4):%x\n", readl(0x3a0010A4)); + pr_debug("GMAC0 RXGOODBYTE_L(0x3a001084):%x\n", readl(0x3a001084)); + pr_debug("GMAC0 RXGOODBYTE_H(0x3a001088):%x\n", readl(0x3a001088)); + pr_debug("GMAC0 RXBADBYTE_L(0x3a00108c):%x\n", readl(0x3a00108c)); + pr_debug("GMAC0 RXBADBYTE_H(0x3a001090):%x\n", readl(0x3a001090)); + + pr_debug("\n\n*****GMAC1 info*****\n"); + pr_debug("GMAC1 RXPAUSE(0x3a001244):%x\n", readl(0x3a001244)); + pr_debug("GMAC1 TXPAUSE(0x3a0012A4):%x\n", readl(0x3a0012A4)); + pr_debug("GMAC1 RXGOODBYTE_L(0x3a001284):%x\n", readl(0x3a001284)); + pr_debug("GMAC1 RXGOODBYTE_H(0x3a001288):%x\n", readl(0x3a001288)); + pr_debug("GMAC1 RXBADBYTE_L(0x3a00128c):%x\n", readl(0x3a00128c)); + pr_debug("GMAC1 RXBADBYTE_H(0x3a001290):%x\n", readl(0x3a001290)); + + pr_info("%s: done\n", __func__); +} + +static void devsoc_edma_set_ring_values(struct devsoc_edma_hw *edma_hw) +{ + edma_hw->txdesc_ring_start = DEVSOC_EDMA_TX_DESC_RING_START; + edma_hw->txdesc_rings = DEVSOC_EDMA_TX_DESC_RING_NOS; + edma_hw->txdesc_ring_end = DEVSOC_EDMA_TX_DESC_RING_SIZE; + + edma_hw->txcmpl_ring_start = DEVSOC_EDMA_TX_CMPL_RING_START; + edma_hw->txcmpl_rings = DEVSOC_EDMA_TX_CMPL_RING_NOS; + edma_hw->txcmpl_ring_end = DEVSOC_EDMA_TX_CMPL_RING_SIZE; + + edma_hw->rxfill_ring_start = DEVSOC_EDMA_RX_FILL_RING_START; + edma_hw->rxfill_rings = DEVSOC_EDMA_RX_FILL_RING_NOS; + edma_hw->rxfill_ring_end = DEVSOC_EDMA_RX_FILL_RING_SIZE; + + edma_hw->rxdesc_ring_start = DEVSOC_EDMA_RX_DESC_RING_START; + edma_hw->rxdesc_rings = DEVSOC_EDMA_RX_DESC_RING_NOS; + edma_hw->rxdesc_ring_end = DEVSOC_EDMA_RX_DESC_RING_SIZE; + + pr_info("Num rings - TxDesc:%u (%u-%u) TxCmpl:%u (%u-%u)\n", + edma_hw->txdesc_rings, edma_hw->txdesc_ring_start, + (edma_hw->txdesc_ring_start + edma_hw->txdesc_rings - 1), + edma_hw->txcmpl_rings, edma_hw->txcmpl_ring_start, + (edma_hw->txcmpl_ring_start + edma_hw->txcmpl_rings - 1)); + + pr_info("RxDesc:%u (%u-%u) RxFill:%u (%u-%u)\n", + edma_hw->rxdesc_rings, edma_hw->rxdesc_ring_start, + (edma_hw->rxdesc_ring_start + edma_hw->rxdesc_rings - 1), + edma_hw->rxfill_rings, edma_hw->rxfill_ring_start, + (edma_hw->rxfill_ring_start + edma_hw->rxfill_rings - 1)); +} + +/* + * devsoc_edma_alloc_rings() + * Allocate EDMA software rings + */ +static int devsoc_edma_alloc_rings(struct devsoc_edma_hw *ehw) +{ + ehw->rxfill_ring = (void *)noncached_alloc((sizeof( + struct devsoc_edma_rxfill_ring) * + ehw->rxfill_rings), + CONFIG_SYS_CACHELINE_SIZE); + if (!ehw->rxfill_ring) { + pr_info("%s: rxfill_ring alloc error\n", __func__); + return -ENOMEM; + } + + ehw->rxdesc_ring = (void *)noncached_alloc((sizeof( + struct devsoc_edma_rxdesc_ring) * + ehw->rxdesc_rings), + CONFIG_SYS_CACHELINE_SIZE); + if (!ehw->rxdesc_ring) { + pr_info("%s: rxdesc_ring alloc error\n", __func__); + return -ENOMEM; + } + + ehw->txdesc_ring = (void *)noncached_alloc((sizeof( + struct devsoc_edma_txdesc_ring) * + ehw->txdesc_rings), + CONFIG_SYS_CACHELINE_SIZE); + if (!ehw->txdesc_ring) { + pr_info("%s: txdesc_ring alloc error\n", __func__); + return -ENOMEM; + } + + ehw->txcmpl_ring = (void *)noncached_alloc((sizeof( + struct devsoc_edma_txcmpl_ring) * + ehw->txcmpl_rings), + CONFIG_SYS_CACHELINE_SIZE); + if (!ehw->txcmpl_ring) { + pr_info("%s: txcmpl_ring alloc error\n", __func__); + return -ENOMEM; + } + + pr_info("%s: successfull\n", __func__); + + return 0; + +} + + +/* + * devsoc_edma_init_rings() + * Initialize EDMA rings + */ +static int devsoc_edma_init_rings(struct devsoc_edma_hw *ehw) +{ + int ret; + + /* + * Setup ring values + */ + devsoc_edma_set_ring_values(ehw); + + /* + * Allocate desc rings + */ + ret = devsoc_edma_alloc_rings(ehw); + if (ret) + return ret; + + /* + * Setup ring resources + */ + ret = devsoc_edma_setup_ring_resources(ehw); + if (ret) + return ret; + + return 0; +} + +/* + * devsoc_edma_configure_txdesc_ring() + * Configure one TxDesc ring + */ +static void devsoc_edma_configure_txdesc_ring(struct devsoc_edma_hw *ehw, + struct devsoc_edma_txdesc_ring *txdesc_ring) +{ + /* + * Configure TXDESC ring + */ + devsoc_edma_reg_write(DEVSOC_EDMA_REG_TXDESC_BA(txdesc_ring->id), + (uint32_t)(txdesc_ring->dma & + DEVSOC_EDMA_RING_DMA_MASK)); + + devsoc_edma_reg_write(DEVSOC_EDMA_REG_TXDESC_BA2(txdesc_ring->id), + (uint32_t)(txdesc_ring->sdma & + DEVSOC_EDMA_RING_DMA_MASK)); + + devsoc_edma_reg_write(DEVSOC_EDMA_REG_TXDESC_RING_SIZE( + txdesc_ring->id), (uint32_t)(txdesc_ring->count & + DEVSOC_EDMA_TXDESC_RING_SIZE_MASK)); + + devsoc_edma_reg_write(DEVSOC_EDMA_REG_TXDESC_PROD_IDX( + txdesc_ring->id), + DEVSOC_EDMA_TX_INITIAL_PROD_IDX); +} + +/* + * devsoc_edma_configure_txcmpl_ring() + * Configure one TxCmpl ring + */ +static void devsoc_edma_configure_txcmpl_ring(struct devsoc_edma_hw *ehw, + struct devsoc_edma_txcmpl_ring *txcmpl_ring) +{ + /* + * Configure TxCmpl ring base address + */ + devsoc_edma_reg_write(DEVSOC_EDMA_REG_TXCMPL_BA(txcmpl_ring->id), + (uint32_t)(txcmpl_ring->dma & + DEVSOC_EDMA_RING_DMA_MASK)); + + devsoc_edma_reg_write(DEVSOC_EDMA_REG_TXCMPL_RING_SIZE( + txcmpl_ring->id), (uint32_t)(txcmpl_ring->count & + DEVSOC_EDMA_TXDESC_RING_SIZE_MASK)); + + /* + * Set TxCmpl ret mode to opaque + */ + devsoc_edma_reg_write(DEVSOC_EDMA_REG_TXCMPL_CTRL(txcmpl_ring->id), + DEVSOC_EDMA_TXCMPL_RETMODE_OPAQUE); + + /* + * Enable ring. Set ret mode to 'opaque'. + */ + devsoc_edma_reg_write(DEVSOC_EDMA_REG_TX_INT_CTRL(txcmpl_ring->id), + DEVSOC_EDMA_TX_NE_INT_EN); +} + +/* + * devsoc_edma_configure_rxdesc_ring() + * Configure one RxDesc ring + */ +static void devsoc_edma_configure_rxdesc_ring(struct devsoc_edma_hw *ehw, + struct devsoc_edma_rxdesc_ring *rxdesc_ring) +{ + uint32_t data; + + devsoc_edma_reg_write(DEVSOC_EDMA_REG_RXDESC_BA(rxdesc_ring->id), + (uint32_t)(rxdesc_ring->dma & DEVSOC_EDMA_RING_DMA_MASK)); + + devsoc_edma_reg_write(DEVSOC_EDMA_REG_RXDESC_BA2(rxdesc_ring->id), + (uint32_t)(rxdesc_ring->sdma & DEVSOC_EDMA_RING_DMA_MASK)); + + data = rxdesc_ring->count & DEVSOC_EDMA_RXDESC_RING_SIZE_MASK; + data |= (ehw->rx_payload_offset & DEVSOC_EDMA_RXDESC_PL_OFFSET_MASK) << + DEVSOC_EDMA_RXDESC_PL_OFFSET_SHIFT; + + devsoc_edma_reg_write(DEVSOC_EDMA_REG_RXDESC_RING_SIZE( + rxdesc_ring->id), data); + + /* + * Enable ring. Set ret mode to 'opaque'. + */ + devsoc_edma_reg_write(DEVSOC_EDMA_REG_RX_INT_CTRL(rxdesc_ring->id), + DEVSOC_EDMA_RX_NE_INT_EN); +} + +/* + * devsoc_edma_configure_rxfill_ring() + * Configure one RxFill ring + */ +static void devsoc_edma_configure_rxfill_ring(struct devsoc_edma_hw *ehw, + struct devsoc_edma_rxfill_ring *rxfill_ring) +{ + uint32_t data; + + devsoc_edma_reg_write(DEVSOC_EDMA_REG_RXFILL_BA(rxfill_ring->id), + (uint32_t)(rxfill_ring->dma & DEVSOC_EDMA_RING_DMA_MASK)); + + data = rxfill_ring->count & DEVSOC_EDMA_RXFILL_RING_SIZE_MASK; + + devsoc_edma_reg_write(DEVSOC_EDMA_REG_RXFILL_RING_SIZE(rxfill_ring->id), data); +} + + +/* + * devsoc_edma_configure_rings() + * Configure EDMA rings + */ +static void devsoc_edma_configure_rings(struct devsoc_edma_hw *ehw) +{ + int i; + + /* + * Configure TXDESC ring + */ + for (i = 0; i < ehw->txdesc_rings; i++) + devsoc_edma_configure_txdesc_ring(ehw, &ehw->txdesc_ring[i]); + + /* + * Configure TXCMPL ring + */ + for (i = 0; i < ehw->txcmpl_rings; i++) + devsoc_edma_configure_txcmpl_ring(ehw, &ehw->txcmpl_ring[i]); + + /* + * Configure RXFILL rings + */ + for (i = 0; i < ehw->rxfill_rings; i++) + devsoc_edma_configure_rxfill_ring(ehw, &ehw->rxfill_ring[i]); + + /* + * Configure RXDESC ring + */ + for (i = 0; i < ehw->rxdesc_rings; i++) + devsoc_edma_configure_rxdesc_ring(ehw, &ehw->rxdesc_ring[i]); + + pr_info("%s: successfull\n", __func__); +} + +/* + * devsoc_edma_hw_reset() + * EDMA hw reset + */ +void devsoc_edma_hw_reset(void) +{ +#if 0 + writel(NSS_CC_EDMA_HW_RESET_ASSERT, NSS_CC_PPE_RESET_ADDR); + mdelay(500); + writel(NSS_CC_EDMA_HW_RESET_DEASSERT, NSS_CC_PPE_RESET_ADDR); + mdelay(100); +#endif +} + +/* + * devsoc_edma_hw_init() + * EDMA hw init + */ +int devsoc_edma_hw_init(struct devsoc_edma_hw *ehw) +{ + int ret, desc_index; + uint32_t i, reg, reg_idx, ring_id; + volatile uint32_t data; + + struct devsoc_edma_rxdesc_ring *rxdesc_ring = NULL; + + devsoc_ppe_provision_init(); + + data = devsoc_edma_reg_read(DEVSOC_EDMA_REG_MAS_CTRL); + printf("EDMA ver %d hw init\n", data); + + /* + * Setup private data structure + */ + ehw->rxfill_intr_mask = DEVSOC_EDMA_RXFILL_INT_MASK; + ehw->rxdesc_intr_mask = DEVSOC_EDMA_RXDESC_INT_MASK_PKT_INT; + ehw->txcmpl_intr_mask = DEVSOC_EDMA_TX_INT_MASK_PKT_INT; + ehw->misc_intr_mask = 0xff; + ehw->rx_payload_offset = 0x0; + +#ifndef CONFIG_DEVSOC_RUMI + /* + * Reset EDMA + */ + devsoc_edma_hw_reset(); +#endif + + /* + * Disable interrupts + */ + devsoc_edma_disable_intr(ehw); + + /* + * Disable rings + */ + devsoc_edma_disable_rings(ehw); + + ret = devsoc_edma_init_rings(ehw); + if (ret) + return ret; + + devsoc_edma_configure_rings(ehw); + + /* + * Clear the TXDESC2CMPL_MAP_xx reg before setting up + * the mapping. This register holds TXDESC to TXFILL ring + * mapping. + */ + devsoc_edma_reg_write(DEVSOC_EDMA_REG_TXDESC2CMPL_MAP_0, 0); + devsoc_edma_reg_write(DEVSOC_EDMA_REG_TXDESC2CMPL_MAP_1, 0); + devsoc_edma_reg_write(DEVSOC_EDMA_REG_TXDESC2CMPL_MAP_2, 0); + devsoc_edma_reg_write(DEVSOC_EDMA_REG_TXDESC2CMPL_MAP_3, 0); + desc_index = ehw->txcmpl_ring_start; + + /* + * 6 registers to hold the completion mapping for total 32 + * TX desc rings (0-5, 6-11, 12-17, 18-23, 24-29 & rest). + * In each entry 5 bits hold the mapping for a particular TX desc ring. + */ + for (i = ehw->txdesc_ring_start; + i < ehw->txdesc_ring_end; i++) { + if ((i >= 0) && (i <= 5)) + reg = DEVSOC_EDMA_REG_TXDESC2CMPL_MAP_0; + else if ((i >= 6) && (i <= 11)) + reg = DEVSOC_EDMA_REG_TXDESC2CMPL_MAP_1; + else if ((i >= 12) && (i <= 17)) + reg = DEVSOC_EDMA_REG_TXDESC2CMPL_MAP_2; + else + reg = DEVSOC_EDMA_REG_TXDESC2CMPL_MAP_3; + + pr_debug("Configure TXDESC:%u to use TXCMPL:%u\n", + i, desc_index); + + /* + * Set the Tx complete descriptor ring number in the mapping + * register. + * E.g. If (txcmpl ring)desc_index = 31, (txdesc ring)i = 28. + * reg = DEVSOC_EDMA_REG_TXDESC2CMPL_MAP_4 + * data |= (desc_index & 0x1F) << ((i % 6) * 5); + * data |= (0x1F << 20); - This sets 11111 at 20th bit of + * register DEVSOC_EDMA_REG_TXDESC2CMPL_MAP_4 + */ + + data = devsoc_edma_reg_read(reg); + data |= (desc_index & 0x1F) << ((i % 6) * 5); + devsoc_edma_reg_write(reg, data); + + desc_index++; + if (desc_index == ehw->txcmpl_ring_end) + desc_index = ehw->txcmpl_ring_start; + } + + pr_debug("EDMA_REG_TXDESC2CMPL_MAP_0: 0x%x\n", + devsoc_edma_reg_read(DEVSOC_EDMA_REG_TXDESC2CMPL_MAP_0)); + pr_debug("EDMA_REG_TXDESC2CMPL_MAP_1: 0x%x\n", + devsoc_edma_reg_read(DEVSOC_EDMA_REG_TXDESC2CMPL_MAP_1)); + pr_debug("EDMA_REG_TXDESC2CMPL_MAP_2: 0x%x\n", + devsoc_edma_reg_read(DEVSOC_EDMA_REG_TXDESC2CMPL_MAP_2)); + pr_debug("EDMA_REG_TXDESC2CMPL_MAP_3: 0x%x\n", + devsoc_edma_reg_read(DEVSOC_EDMA_REG_TXDESC2CMPL_MAP_3)); + + /* + * Set PPE QID to EDMA Rx ring mapping. + * Each entry can hold mapping for 4 PPE queues and entry size is + * 4 bytes + */ + desc_index = (ehw->rxdesc_ring_start & 0x1f); + + reg = DEVSOC_EDMA_QID2RID_TABLE_MEM(0); + data = ((desc_index << 0) & 0xff) | + (((desc_index + 1) << 8) & 0xff00) | + (((desc_index + 2) << 16) & 0xff0000) | + (((desc_index + 3) << 24) & 0xff000000); + + devsoc_edma_reg_write(reg, data); + pr_debug("Configure QID2RID(0) reg:0x%x to 0x%x\n", reg, data); + + /* + * Map PPE multicast queues to the first Rx ring. + */ + desc_index = (ehw->rxdesc_ring_start & 0x1f); + + for (i = DEVSOC_EDMA_CPU_PORT_MC_QID_MIN; + i <= DEVSOC_EDMA_CPU_PORT_MC_QID_MAX; + i += DEVSOC_EDMA_QID2RID_NUM_PER_REG) { + reg_idx = i/DEVSOC_EDMA_QID2RID_NUM_PER_REG; + + reg = DEVSOC_EDMA_QID2RID_TABLE_MEM(reg_idx); + data = ((desc_index << 0) & 0xff) | + ((desc_index << 8) & 0xff00) | + ((desc_index << 16) & 0xff0000) | + ((desc_index << 24) & 0xff000000); + + devsoc_edma_reg_write(reg, data); + pr_debug("Configure QID2RID(%d) reg:0x%x to 0x%x\n", + reg_idx, reg, data); + } + + /* + * Set RXDESC2FILL_MAP_xx reg. + * There are 3 registers RXDESC2FILL_0, RXDESC2FILL_1 and RXDESC2FILL_2 + * 3 bits holds the rx fill ring mapping for each of the + * rx descriptor ring. + */ + devsoc_edma_reg_write(DEVSOC_EDMA_REG_RXDESC2FILL_MAP_0, 0); + devsoc_edma_reg_write(DEVSOC_EDMA_REG_RXDESC2FILL_MAP_1, 0); + + for (i = 0; i < ehw->rxdesc_rings; i++) { + rxdesc_ring = &ehw->rxdesc_ring[i]; + + ring_id = rxdesc_ring->id; + if ((ring_id >= 0) && (ring_id <= 9)) + reg = DEVSOC_EDMA_REG_RXDESC2FILL_MAP_0; + else + reg = DEVSOC_EDMA_REG_RXDESC2FILL_MAP_1; + + + pr_debug("Configure RXDESC:%u to use RXFILL:%u\n", + ring_id, rxdesc_ring->rxfill->id); + + /* + * Set the Rx fill descriptor ring number in the mapping + * register. + */ + data = devsoc_edma_reg_read(reg); + data |= (rxdesc_ring->rxfill->id & 0x7) << ((ring_id % 10) * 3); + devsoc_edma_reg_write(reg, data); + } + + pr_debug("EDMA_REG_RXDESC2FILL_MAP_0: 0x%x\n", + devsoc_edma_reg_read(DEVSOC_EDMA_REG_RXDESC2FILL_MAP_0)); + pr_debug("EDMA_REG_RXDESC2FILL_MAP_1: 0x%x\n", + devsoc_edma_reg_read(DEVSOC_EDMA_REG_RXDESC2FILL_MAP_1)); + + /* + * Configure DMA request priority, DMA read burst length, + * and AXI write size. + */ + data = DEVSOC_EDMA_DMAR_BURST_LEN_SET(DEVSOC_EDMA_BURST_LEN_ENABLE) + | DEVSOC_EDMA_DMAR_REQ_PRI_SET(0) + | DEVSOC_EDMA_DMAR_TXDATA_OUTSTANDING_NUM_SET(31) + | DEVSOC_EDMA_DMAR_TXDESC_OUTSTANDING_NUM_SET(7) + | DEVSOC_EDMA_DMAR_RXFILL_OUTSTANDING_NUM_SET(7); + devsoc_edma_reg_write(DEVSOC_EDMA_REG_DMAR_CTRL, data); + + /* + * Global EDMA and padding enable + */ + devsoc_edma_reg_write(DEVSOC_EDMA_REG_PORT_CTRL, + DEVSOC_EDMA_PORT_CTRL_EN); + + /* + * Enable Rx rings + */ + for (i = ehw->rxdesc_ring_start; i < ehw->rxdesc_ring_end; i++) { + data = devsoc_edma_reg_read(DEVSOC_EDMA_REG_RXDESC_CTRL(i)); + data |= DEVSOC_EDMA_RXDESC_RX_EN; + devsoc_edma_reg_write(DEVSOC_EDMA_REG_RXDESC_CTRL(i), data); + } + + for (i = ehw->rxfill_ring_start; i < ehw->rxfill_ring_end; i++) { + data = devsoc_edma_reg_read(DEVSOC_EDMA_REG_RXFILL_RING_EN(i)); + data |= DEVSOC_EDMA_RXFILL_RING_EN; + devsoc_edma_reg_write(DEVSOC_EDMA_REG_RXFILL_RING_EN(i), data); + } + + /* + * Enable Tx rings + */ + for (i = ehw->txdesc_ring_start; i < ehw->txdesc_ring_end; i++) { + data = devsoc_edma_reg_read(DEVSOC_EDMA_REG_TXDESC_CTRL(i)); + data |= DEVSOC_EDMA_TXDESC_TX_EN; + devsoc_edma_reg_write(DEVSOC_EDMA_REG_TXDESC_CTRL(i), data); + } + + /* + * Enable MISC interrupt mask + */ + devsoc_edma_reg_write(DEVSOC_EDMA_REG_MISC_INT_MASK, + ehw->misc_intr_mask); + + pr_info("%s: successfull\n", __func__); + return 0; +} + +void get_phy_address(int offset) +{ + int phy_type; + int phy_address; + int i; + + for (i = 0; i < DEVSOC_PHY_MAX; i++) + phy_info[i] = devsoc_alloc_mem(sizeof(phy_info_t)); + i = 0; + for (offset = fdt_first_subnode(gd->fdt_blob, offset); offset > 0; + offset = fdt_next_subnode(gd->fdt_blob, offset)) { + phy_address = fdtdec_get_uint(gd->fdt_blob, + offset, "phy_address", 0); + phy_type = fdtdec_get_uint(gd->fdt_blob, + offset, "phy_type", 0); + phy_info[i]->phy_address = phy_address; + phy_info[i++]->phy_type = phy_type; + } +} + +int devsoc_edma_init(void *edma_board_cfg) +{ + struct eth_device *dev[DEVSOC_EDMA_DEV]; + struct devsoc_edma_common_info *c_info[DEVSOC_EDMA_DEV]; + struct devsoc_edma_hw *hw[DEVSOC_EDMA_DEV]; + uchar enet_addr[DEVSOC_EDMA_DEV * 6]; + int i; + int ret = -1; + devsoc_edma_board_cfg_t ledma_cfg, *edma_cfg; +#ifndef CONFIG_DEVSOC_RUMI + int phy_id; + uint32_t phy_chip_id, phy_chip_id1, phy_chip_id2; +#ifdef CONFIG_DEVSOC_QCA8075_PHY + static int sw_init_done = 0; +#endif + int node, phy_addr, aquantia_port[2] = {-1, -1}, aquantia_port_cnt = -1; + int mode, phy_node = -1, res = -1; + + /* + * Init non cache buffer + */ + noncached_init(); + + node = fdt_path_offset(gd->fdt_blob, "/ess-switch"); + + if (node >= 0) { + aquantia_port_cnt = fdtdec_get_uint(gd->fdt_blob, node, "aquantia_port_cnt", -1); + + if (aquantia_port_cnt >= 1) { + res = fdtdec_get_int_array(gd->fdt_blob, node, "aquantia_port", + (u32 *)aquantia_port, aquantia_port_cnt); + if (res < 0) + printf("Error: Aquantia port details not provided in DT"); + } + } + + phy_node = fdt_path_offset(gd->fdt_blob, "/ess-switch/port_phyinfo"); + if (phy_node >= 0) + get_phy_address(phy_node); + + mode = fdtdec_get_uint(gd->fdt_blob, node, "switch_mac_mode0", -1); + if (mode < 0) { + printf("Error:switch_mac_mode0 not specified in dts"); + return mode; + } +#endif + + memset(c_info, 0, (sizeof(c_info) * DEVSOC_EDMA_DEV)); + memset(enet_addr, 0, sizeof(enet_addr)); + memset(&ledma_cfg, 0, sizeof(ledma_cfg)); + edma_cfg = &ledma_cfg; + strlcpy(edma_cfg->phy_name, "IPQ MDIO0", sizeof(edma_cfg->phy_name)); + + /* Getting the MAC address from ART partition */ + ret = get_eth_mac_address(enet_addr, DEVSOC_EDMA_DEV); + + /* + * Register EDMA as single ethernet + * interface. + */ + for (i = 0; i < DEVSOC_EDMA_DEV; edma_cfg++, i++) { + dev[i] = devsoc_alloc_mem(sizeof(struct eth_device)); + + if (!dev[i]) + goto init_failed; + + memset(dev[i], 0, sizeof(struct eth_device)); + + c_info[i] = devsoc_alloc_mem( + sizeof(struct devsoc_edma_common_info)); + + if (!c_info[i]) + goto init_failed; + + memset(c_info[i], 0, + sizeof(struct devsoc_edma_common_info)); + + hw[i] = &c_info[i]->hw; + + c_info[i]->hw.hw_addr = (unsigned long __iomem *) + DEVSOC_EDMA_CFG_BASE; + + devsoc_edma_dev[i] = devsoc_alloc_mem( + sizeof(struct devsoc_eth_dev)); + + if (!devsoc_edma_dev[i]) + goto init_failed; + + memset (devsoc_edma_dev[i], 0, + sizeof(struct devsoc_eth_dev)); + + dev[i]->iobase = DEVSOC_EDMA_CFG_BASE; + dev[i]->init = devsoc_eth_init; + dev[i]->halt = devsoc_eth_halt; + dev[i]->recv = devsoc_eth_recv; + dev[i]->send = devsoc_eth_snd; + dev[i]->write_hwaddr = devsoc_edma_wr_macaddr; + dev[i]->priv = (void *)devsoc_edma_dev[i]; + + if ((ret < 0) || + (!is_valid_ethaddr(&enet_addr[edma_cfg->unit * 6]))) { + memcpy(&dev[i]->enetaddr[0], devsoc_def_enetaddr, 6); + } else { + memcpy(&dev[i]->enetaddr[0], + &enet_addr[edma_cfg->unit * 6], 6); + } + + printf("MAC%x addr:%x:%x:%x:%x:%x:%x\n", + edma_cfg->unit, dev[i]->enetaddr[0], + dev[i]->enetaddr[1], + dev[i]->enetaddr[2], + dev[i]->enetaddr[3], + dev[i]->enetaddr[4], + dev[i]->enetaddr[5]); + + snprintf(dev[i]->name, sizeof(dev[i]->name), "eth%d", i); + + devsoc_edma_dev[i]->dev = dev[i]; + devsoc_edma_dev[i]->mac_unit = edma_cfg->unit; + devsoc_edma_dev[i]->c_info = c_info[i]; + devsoc_edma_hw_addr = DEVSOC_EDMA_CFG_BASE; + +#ifndef CONFIG_DEVSOC_RUMI + ret = ipq_sw_mdio_init(edma_cfg->phy_name); + if (ret) + goto init_failed; + + for (phy_id = 0; phy_id < DEVSOC_PHY_MAX; phy_id++) { + if (phy_node >= 0) { + phy_addr = phy_info[phy_id]->phy_address; + } else { + printf("Error:Phy addresses not configured in DT\n"); + goto init_failed; + } + + phy_chip_id1 = ipq_mdio_read(phy_addr, QCA_PHY_ID1, NULL); + phy_chip_id2 = ipq_mdio_read(phy_addr, QCA_PHY_ID2, NULL); + phy_chip_id = (phy_chip_id1 << 16) | phy_chip_id2; + if (phy_id == aquantia_port[0] || phy_id == aquantia_port[1]) { + phy_chip_id1 = ipq_mdio_read(phy_addr, (1<<30) |(1<<16) | QCA_PHY_ID1, NULL); + phy_chip_id2 = ipq_mdio_read(phy_addr, (1<<30) |(1<<16) | QCA_PHY_ID2, NULL); + phy_chip_id = (phy_chip_id1 << 16) | phy_chip_id2; + } + pr_debug("phy_id is: 0x%x, phy_addr = 0x%x, phy_chip_id1 = 0x%x, phy_chip_id2 = 0x%x, phy_chip_id = 0x%x\n", + phy_id, phy_addr, phy_chip_id1, phy_chip_id2, phy_chip_id); + switch(phy_chip_id) { +#ifdef CONFIG_DEVSOC_QCA8075_PHY + case QCA8075_PHY_V1_0_5P: + case QCA8075_PHY_V1_1_5P: + case QCA8075_PHY_V1_1_2P: + if (!sw_init_done) { + if (devsoc_qca8075_phy_init(&devsoc_edma_dev[i]->ops[phy_id], phy_addr) == 0) { + sw_init_done = 1; + } + } else { + devsoc_qca8075_phy_map_ops(&devsoc_edma_dev[i]->ops[phy_id]); + } + + if (mode == EPORT_WRAPPER_PSGMII) + devsoc_qca8075_phy_interface_set_mode(phy_addr, 0x0); + else if (mode == EPORT_WRAPPER_QSGMII) + devsoc_qca8075_phy_interface_set_mode(phy_addr, 0x4); + break; +#endif +#ifdef CONFIG_QCA8033_PHY + case QCA8033_PHY: + ipq_qca8033_phy_init(&devsoc_edma_dev[i]->ops[phy_id], phy_addr); + break; +#endif +#ifdef CONFIG_QCA8081_PHY + case QCA8081_PHY: + case QCA8081_1_1_PHY: + ipq_qca8081_phy_init(&devsoc_edma_dev[i]->ops[phy_id], phy_addr); + break; +#endif +#ifdef CONFIG_DEVSOC_QCA_AQUANTIA_PHY + case AQUANTIA_PHY_107: + case AQUANTIA_PHY_109: + case AQUANTIA_PHY_111: + case AQUANTIA_PHY_111B0: + case AQUANTIA_PHY_112: + case AQUANTIA_PHY_112C: + case AQUANTIA_PHY_113C_A0: + case AQUANTIA_PHY_113C_A1: + case AQUANTIA_PHY_113C_B0: + case AQUANTIA_PHY_113C_B1: + ipq_board_fw_download(phy_addr); + mdelay(100); + ipq_qca_aquantia_phy_init(&devsoc_edma_dev[i]->ops[phy_id], phy_addr); + break; +#endif + default: + if (phy_info[phy_id]->phy_type != SFP_PHY_TYPE) + printf("\nphy chip id: 0x%x id not matching for phy id: 0x%x with phy_type: 0x%x and phy address: 0x%x", + phy_chip_id, phy_id, phy_info[phy_id]->phy_type, phy_info[phy_id]->phy_address); + break; + } + } +#endif + + ret = devsoc_edma_hw_init(hw[i]); + + if (ret) + goto init_failed; + + eth_register(dev[i]); + } + + return 0; + +init_failed: + printf("Error in allocating Mem\n"); + + for (i = 0; i < DEVSOC_EDMA_DEV; i++) { + if (dev[i]) { + eth_unregister(dev[i]); + devsoc_free_mem(dev[i]); + } + if (c_info[i]) { + devsoc_free_mem(c_info[i]); + } + if (devsoc_edma_dev[i]) { + devsoc_free_mem(devsoc_edma_dev[i]); + } + } + + return -1; +} diff --git a/drivers/net/devsoc/devsoc_edma.h b/drivers/net/devsoc/devsoc_edma.h new file mode 100644 index 0000000000..c9ad14049d --- /dev/null +++ b/drivers/net/devsoc/devsoc_edma.h @@ -0,0 +1,341 @@ +/* + ************************************************************************** + * Copyright (c) 2016-2019, 2021, The Linux Foundation. All rights reserved. + * + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** +*/ +#ifndef __DEVSOC_EDMA__ +#define __DEVSOC_EDMA__ + +#define DEVSOC_NSS_DP_START_PHY_PORT 1 +#define DEVSOC_NSS_DP_MAX_PHY_PORTS 2 + +#define DEVSOC_EDMA_DEVICE_NODE_NAME "edma" + +/* Number of descriptors in each ring is defined with below macro */ +#define DEVSOC_EDMA_TX_RING_SIZE 128 +#define DEVSOC_EDMA_RX_RING_SIZE 128 + +/* Number of byte in a descriptor is defined with below macros for each of + * the rings respectively */ +#define DEVSOC_EDMA_TXDESC_DESC_SIZE (sizeof(struct devsoc_edma_txdesc_desc)) +#define DEVSOC_EDMA_TXCMPL_DESC_SIZE (sizeof(struct devsoc_edma_txcmpl_desc)) +#define DEVSOC_EDMA_RXDESC_DESC_SIZE (sizeof(struct devsoc_edma_rxdesc_desc)) +#define DEVSOC_EDMA_RXFILL_DESC_SIZE (sizeof(struct devsoc_edma_rxfill_desc)) +#define DEVSOC_EDMA_RX_SEC_DESC_SIZE (sizeof(struct devsoc_edma_rx_sec_desc)) +#define DEVSOC_EDMA_TX_SEC_DESC_SIZE (sizeof(struct devsoc_edma_tx_sec_desc)) + +#define DEVSOC_EDMA_START_GMACS DEVSOC_NSS_DP_START_PHY_PORT +#define DEVSOC_EDMA_MAX_GMACS DEVSOC_NSS_DP_MAX_PHY_PORTS + +#define DEVSOC_EDMA_TX_BUFF_SIZE 2048 +#define DEVSOC_EDMA_RX_BUFF_SIZE 2048 + +/* Max number of rings of each type is defined with below macro */ +#define DEVSOC_EDMA_MAX_TXCMPL_RINGS 24 /* Max TxCmpl rings */ +#define DEVSOC_EDMA_MAX_TXDESC_RINGS 24 /* Max TxDesc rings */ +#define DEVSOC_EDMA_MAX_RXDESC_RINGS 16 /* Max RxDesc rings */ +#define DEVSOC_EDMA_MAX_RXFILL_RINGS 8 /* Max RxFill rings */ + +#define DEVSOC_EDMA_GET_DESC(R, i, type) (&(((type *)((R)->desc))[i])) +#define DEVSOC_EDMA_RXFILL_DESC(R, i) DEVSOC_EDMA_GET_DESC(R, i, struct devsoc_edma_rxfill_desc) +#define DEVSOC_EDMA_RXDESC_DESC(R, i) DEVSOC_EDMA_GET_DESC(R, i, struct devsoc_edma_rxdesc_desc) +#define DEVSOC_EDMA_TXDESC_DESC(R, i) DEVSOC_EDMA_GET_DESC(R, i, struct devsoc_edma_txdesc_desc) +#define DEVSOC_EDMA_TXCMPL_DESC(R, i) DEVSOC_EDMA_GET_DESC(R, i, struct devsoc_edma_txcmpl_desc) + +#define DEVSOC_EDMA_DEV 1 + +/* Only 1 ring of each type will be used in U-Boot which is defined with + * below macros */ +#define DEVSOC_EDMA_TX_DESC_RING_START 23 +#define DEVSOC_EDMA_TX_DESC_RING_NOS 1 +#define DEVSOC_EDMA_TX_DESC_RING_SIZE \ +(DEVSOC_EDMA_TX_DESC_RING_START + DEVSOC_EDMA_TX_DESC_RING_NOS) + +#define DEVSOC_EDMA_TX_CMPL_RING_START 23 +#define DEVSOC_EDMA_TX_CMPL_RING_NOS 1 +#define DEVSOC_EDMA_TX_CMPL_RING_SIZE \ +(DEVSOC_EDMA_TX_CMPL_RING_START + DEVSOC_EDMA_TX_CMPL_RING_NOS) + +#define DEVSOC_EDMA_RX_DESC_RING_START 15 +#define DEVSOC_EDMA_RX_DESC_RING_NOS 1 +#define DEVSOC_EDMA_RX_DESC_RING_SIZE \ +(DEVSOC_EDMA_RX_DESC_RING_START + DEVSOC_EDMA_RX_DESC_RING_NOS) + +#define DEVSOC_EDMA_RX_FILL_RING_START 7 +#define DEVSOC_EDMA_RX_FILL_RING_NOS 1 +#define DEVSOC_EDMA_RX_FILL_RING_SIZE \ +(DEVSOC_EDMA_RX_FILL_RING_START + DEVSOC_EDMA_RX_FILL_RING_NOS) + +#define NETDEV_TX_BUSY 1 + +/* + * RxDesc descriptor + */ +struct devsoc_edma_rxdesc_desc { + uint32_t rdes0; /* Contains buffer address */ + uint32_t rdes1; /* Contains more bit, priority bit, service code */ + uint32_t rdes2; /* Contains opaque */ + uint32_t rdes3; /* Contains opaque high bits */ + uint32_t rdes4; /* Contains destination and source information */ + uint32_t rdes5; /* Contains WiFi QoS, data length */ + uint32_t rdes6; /* Contains hash value, check sum status */ + uint32_t rdes7; /* Contains DSCP, packet offsets */ +}; + +/* + * EDMA Rx Secondary Descriptor + */ +struct devsoc_edma_rx_sec_desc { + uint32_t rx_sec0; /* Contains timestamp */ + uint32_t rx_sec1; /* Contains secondary checksum status */ + uint32_t rx_sec2; /* Contains QoS tag */ + uint32_t rx_sec3; /* Contains flow index details */ + uint32_t rx_sec4; /* Contains secondary packet offsets */ + uint32_t rx_sec5; /* Contains multicast bit, checksum */ + uint32_t rx_sec6; /* Contains SVLAN, CVLAN */ + uint32_t rx_sec7; /* Contains secondary SVLAN, CVLAN */ +}; + +/* + * RxFill descriptor + */ +struct devsoc_edma_rxfill_desc { + uint32_t rdes0; /* Contains buffer address */ + uint32_t rdes1; /* Contains buffer size */ + uint32_t rdes2; /* Contains opaque */ + uint32_t rdes3; /* Contains opaque high bits */ +}; + +/* + * TxDesc descriptor + */ +struct devsoc_edma_txdesc_desc { + uint32_t tdes0; /* Low 32-bit of buffer address */ + uint32_t tdes1; /* Buffer recycling, PTP tag flag, PRI valid flag */ + uint32_t tdes2; /* Low 32-bit of opaque value */ + uint32_t tdes3; /* High 32-bit of opaque value */ + uint32_t tdes4; /* Source/Destination port info */ + uint32_t tdes5; /* VLAN offload, csum_mode, ip_csum_en, tso_en, data length */ + uint32_t tdes6; /* MSS/hash_value/PTP tag, data offset */ + uint32_t tdes7; /* L4/L3 offset, PROT type, L2 type, CVLAN/SVLAN tag, service code */ +}; + +/* + * EDMA Tx Secondary Descriptor + */ +struct devsoc_edma_tx_sec_desc { + uint32_t tx_sec0; /* Reserved */ + uint32_t tx_sec1; /* Custom csum offset, payload offset, TTL/NAT action */ + uint32_t rx_sec2; /* NAPT translated port, DSCP value, TTL value */ + uint32_t rx_sec3; /* Flow index value and valid flag */ + uint32_t rx_sec4; /* Reserved */ + uint32_t rx_sec5; /* Reserved */ + uint32_t rx_sec6; /* CVLAN/SVLAN command */ + uint32_t rx_sec7; /* CVLAN/SVLAN tag value */ +}; + +/* + * TxCmpl descriptor + */ +struct devsoc_edma_txcmpl_desc { + uint32_t tdes0; /* Low 32-bit opaque value */ + uint32_t tdes1; /* High 32-bit opaque value */ + uint32_t tdes2; /* More fragment, transmit ring id, pool id */ + uint32_t tdes3; /* Error indications */ +}; + +/* + * Tx descriptor ring + */ +struct devsoc_edma_txdesc_ring { + uint32_t prod_idx; /* Producer index */ + uint32_t avail_desc; /* Number of available descriptor to process */ + uint32_t id; /* TXDESC ring number */ + struct devsoc_edma_txdesc_desc *desc; /* descriptor ring virtual address */ + dma_addr_t dma; /* descriptor ring physical address */ + struct devsoc_edma_tx_sec_desc *sdesc; /* Secondary descriptor ring virtual addr */ + dma_addr_t sdma; /* Secondary descriptor ring physical address */ + uint16_t count; /* number of descriptors */ +}; + +/* + * TxCmpl ring + */ +struct devsoc_edma_txcmpl_ring { + uint32_t cons_idx; /* Consumer index */ + uint32_t avail_pkt; /* Number of available packets to process */ + struct devsoc_edma_txcmpl_desc *desc; /* descriptor ring virtual address */ + uint32_t id; /* TXCMPL ring number */ + dma_addr_t dma; /* descriptor ring physical address */ + uint32_t count; /* Number of descriptors in the ring */ +}; + +/* + * RxFill ring + */ +struct devsoc_edma_rxfill_ring { + uint32_t id; /* RXFILL ring number */ + uint32_t count; /* number of descriptors in the ring */ + uint32_t prod_idx; /* Ring producer index */ + struct devsoc_edma_rxfill_desc *desc; /* descriptor ring virtual address */ + dma_addr_t dma; /* descriptor ring physical address */ +}; + +/* + * RxDesc ring + */ +struct devsoc_edma_rxdesc_ring { + uint32_t id; /* RXDESC ring number */ + uint32_t count; /* number of descriptors in the ring */ + uint32_t cons_idx; /* Ring consumer index */ + struct devsoc_edma_rxdesc_desc *desc; /* Primary descriptor ring virtual addr */ + struct devsoc_edma_sec_rxdesc_ring *sdesc; /* Secondary desc ring VA */ + struct devsoc_edma_rxfill_ring *rxfill; /* RXFILL ring used */ + dma_addr_t dma; /* Primary descriptor ring physical address */ + dma_addr_t sdma; /* Secondary descriptor ring physical address */ +}; + +enum devsoc_edma_tx { + EDMA_TX_OK = 0, /* Tx success */ + EDMA_TX_DESC = 1, /* Not enough descriptors */ + EDMA_TX_FAIL = 2, /* Tx failure */ +}; + + +/* per core queue related information */ +struct queue_per_cpu_info { + u32 tx_mask; /* tx interrupt mask */ + u32 rx_mask; /* rx interrupt mask */ + u32 tx_status; /* tx interrupt status */ + u32 rx_status; /* rx interrupt status */ + u32 tx_start; /* tx queue start */ + u32 rx_start; /* rx queue start */ + struct devsoc_edma_common_info *c_info; /* edma common info */ +}; + +/* edma hw specific data */ +struct devsoc_edma_hw { + unsigned long __iomem *hw_addr; /* inner register address */ + u8 intr_clear_type; /* interrupt clear */ + u8 intr_sw_idx_w; /* To do chk type interrupt software index */ + u16 rx_buff_size; /* To do chk type Rx buffer size */ + u8 rss_type; /* rss protocol type */ + uint16_t rx_payload_offset; /* start of the payload offset */ + uint32_t flags; /* internal flags */ + int active; /* status */ + struct devsoc_edma_txdesc_ring *txdesc_ring; /* Tx Descriptor Ring, SW is producer */ + struct devsoc_edma_txcmpl_ring *txcmpl_ring; /* Tx Completion Ring, SW is consumer */ + struct devsoc_edma_rxdesc_ring *rxdesc_ring; /* Rx Descriptor Ring, SW is consumer */ + struct devsoc_edma_rxfill_ring *rxfill_ring; /* Rx Fill Ring, SW is producer */ + uint32_t txdesc_rings; /* Number of TxDesc rings */ + uint32_t txdesc_ring_start; /* Id of first TXDESC ring */ + uint32_t txdesc_ring_end; /* Id of the last TXDESC ring */ + uint32_t txcmpl_rings; /* Number of TxCmpl rings */ + uint32_t txcmpl_ring_start; /* Id of first TXCMPL ring */ + uint32_t txcmpl_ring_end; /* Id of last TXCMPL ring */ + uint32_t rxfill_rings; /* Number of RxFill rings */ + uint32_t rxfill_ring_start; /* Id of first RxFill ring */ + uint32_t rxfill_ring_end; /* Id of last RxFill ring */ + uint32_t rxdesc_rings; /* Number of RxDesc rings */ + uint32_t rxdesc_ring_start; /* Id of first RxDesc ring */ + uint32_t rxdesc_ring_end; /* Id of last RxDesc ring */ + uint32_t tx_intr_mask; /* tx interrupt mask */ + uint32_t rx_intr_mask; /* rx interrupt mask */ + uint32_t rxfill_intr_mask; /* Rx fill ring interrupt mask */ + uint32_t rxdesc_intr_mask; /* Rx Desc ring interrupt mask */ + uint32_t txcmpl_intr_mask; /* Tx Cmpl ring interrupt mask */ + uint32_t misc_intr_mask; /* misc interrupt interrupt mask */ +}; + +struct devsoc_edma_common_info { + struct devsoc_edma_hw hw; +}; + +#define MAX_PHY 6 +struct devsoc_eth_dev { + u8 *phy_address; + uint no_of_phys; + uint interface; + uint speed; + uint duplex; + uint sw_configured; + uint mac_unit; + uint mac_ps; + int link_printed; + u32 padding; + struct eth_device *dev; + struct devsoc_edma_common_info *c_info; + struct phy_ops *ops[MAX_PHY]; + const char phy_name[MDIO_NAME_LEN]; +} __attribute__ ((aligned(8))); + +static inline void* devsoc_alloc_mem(u32 size) +{ + void *p = malloc(size); + if (p != NULL) + memset(p, 0, size); + return p; +} + +static inline void* devsoc_alloc_memalign(u32 size) +{ + void *p = memalign(CONFIG_SYS_CACHELINE_SIZE, size); + if (p != NULL) + memset(p, 0, size); + return p; +} + +static inline void devsoc_free_mem(void *ptr) +{ + if (ptr) + free(ptr); +} + +uint32_t devsoc_edma_reg_read(uint32_t reg_off); +void devsoc_edma_reg_write(uint32_t reg_off, uint32_t val); + + +extern int get_eth_mac_address(uchar *enetaddr, uint no_of_macs); + +typedef struct { + uint count; + u8 addr[7]; +} devsoc_edma_phy_addr_t; + +/* devsoc edma Paramaters */ +typedef struct { + uint base; + int unit; + uint mac_conn_to_phy; + phy_interface_t phy; + devsoc_edma_phy_addr_t phy_addr; + char phy_name[MDIO_NAME_LEN]; +} devsoc_edma_board_cfg_t; + +extern void devsoc_ppe_provision_init(void); +extern void devsoc_port_mac_clock_reset(int port); +extern void devsoc_speed_clock_set(int port, int clk[4]); +extern void devsoc_pqsgmii_speed_set(int port, int speed, int status); +extern void devsoc_uxsgmii_speed_set(int port, int speed, int duplex, int status); +extern void ppe_port_mux_mac_type_set(int port_id, int mode); +extern void ppe_port_bridge_txmac_set(int port, int status); +extern void devsoc_10g_r_speed_set(int port, int status); +extern int phy_status_get_from_ppe(int port_id); + +extern void devsoc_ppe_acl_set(int rule_id, int rule_type, int pkt_type, int l4_port_no, int l4_port_mask, int permit, int deny); +extern void ppe_uniphy_mode_set(uint32_t uniphy_index, uint32_t mode); +#endif /* ___DEVSOC_EDMA__ */ diff --git a/drivers/net/devsoc/devsoc_ppe.c b/drivers/net/devsoc/devsoc_ppe.c new file mode 100644 index 0000000000..38ac21e078 --- /dev/null +++ b/drivers/net/devsoc/devsoc_ppe.c @@ -0,0 +1,885 @@ +/* + ************************************************************************** + * Copyright (c) 2016-2019, 2021, The Linux Foundation. All rights reserved. + * + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** +*/ + +#include +#include +#include "devsoc_ppe.h" +#ifndef CONFIG_DEVSOC_RUMI +#include "devsoc_uniphy.h" +#endif +#include +#include "ipq_phy.h" + +DECLARE_GLOBAL_DATA_PTR; +#ifdef DEBUG +#define pr_debug(fmt, args...) printf(fmt, ##args); +#else +#define pr_debug(fmt, args...) +#endif + +#define pr_info(fmt, args...) printf(fmt, ##args); + +extern int is_uniphy_enabled(int uniphy_index); +extern void uniphy_port5_clock_source_set(void); + +/* + * devsoc_ppe_reg_read() + */ +static inline void devsoc_ppe_reg_read(u32 reg, u32 *val) +{ + *val = readl((void *)(DEVSOC_PPE_BASE_ADDR + reg)); +} + +/* + * devsoc_ppe_reg_write() + */ +static inline void devsoc_ppe_reg_write(u32 reg, u32 val) +{ + writel(val, (void *)(DEVSOC_PPE_BASE_ADDR + reg)); +} + +void ppe_ipo_rule_reg_set(union ipo_rule_reg_u *hw_reg, int rule_id) +{ + int i; + + for (i = 0; i < 3; i++) { + devsoc_ppe_reg_write(IPO_CSR_BASE_ADDR + IPO_RULE_REG_ADDRESS + + (rule_id * IPO_RULE_REG_INC) + (i * 4), hw_reg->val[i]); + } +} + +void ppe_ipo_mask_reg_set(union ipo_mask_reg_u *hw_mask, int rule_id) +{ + int i; + + for (i = 0; i < 2; i++) { + devsoc_ppe_reg_write((IPO_CSR_BASE_ADDR + IPO_MASK_REG_ADDRESS + + (rule_id * IPO_MASK_REG_INC) + (i * 4)), hw_mask->val[i]); + } +} + +void ppe_ipo_action_set(union ipo_action_u *hw_act, int rule_id) +{ + int i; + + for (i = 0; i < 5; i++) { + devsoc_ppe_reg_write((IPE_L2_BASE_ADDR + IPO_ACTION_ADDRESS + + (rule_id * IPO_ACTION_INC) + (i * 4)), hw_act->val[i]); + } +} + +void devsoc_ppe_acl_set(int rule_id, int rule_type, int field0, int field1, int mask, int permit, int deny) +{ + union ipo_rule_reg_u hw_reg = {0}; + union ipo_mask_reg_u hw_mask = {0}; + union ipo_action_u hw_act = {0}; + + memset(&hw_reg, 0, sizeof(hw_reg)); + memset(&hw_mask, 0, sizeof(hw_mask)); + memset(&hw_act, 0, sizeof(hw_act)); + + if (rule_id < MAX_RULE) { + hw_act.bf.dest_info_change_en = 1; + hw_mask.bf.maskfield_0 = mask; + hw_reg.bf.rule_type = rule_type; + if (rule_type == ADPT_ACL_HPPE_IPV4_DIP_RULE) { + hw_reg.bf.rule_field_0 = field1; + hw_reg.bf.rule_field_1 = field0<<17; + hw_mask.bf.maskfield_1 = 7<<17; + if (permit == 0x0) { + hw_act.bf.fwd_cmd = 0;/* forward */ + hw_reg.bf.pri = 0x1; + } + if (deny == 0x1) { + hw_act.bf.fwd_cmd = 1;/* drop */ + hw_reg.bf.pri = 0x0; + } + } else if (rule_type == ADPT_ACL_HPPE_MAC_SA_RULE) { + /* src mac AC rule */ + hw_reg.bf.rule_field_0 = field1; + hw_reg.bf.rule_field_1 = field0; + hw_mask.bf.maskfield_1 = 0xffff; + hw_act.bf.fwd_cmd = 1;/* drop */ + hw_reg.bf.pri = 0x2; + /* bypass fdb lean and fdb freash */ + hw_act.bf.bypass_bitmap_0 = 0x1800; + } else if (rule_type == ADPT_ACL_HPPE_MAC_DA_RULE) { + /* dest mac AC rule */ + hw_reg.bf.rule_field_0 = field1; + hw_reg.bf.rule_field_1 = field0; + hw_mask.bf.maskfield_1 = 0xffff; + hw_act.bf.fwd_cmd = 1;/* drop */ + hw_reg.bf.pri = 0x2; + } + /* bind port1-port6 */ + hw_reg.bf.src_0 = 0x0; + hw_reg.bf.src_1 = 0x3F; + ppe_ipo_rule_reg_set(&hw_reg, rule_id); + ppe_ipo_mask_reg_set(&hw_mask, rule_id); + ppe_ipo_action_set(&hw_act, rule_id); + } +} + +/* + * devsoc_ppe_vp_port_tbl_set() + */ +static void devsoc_ppe_vp_port_tbl_set(int port, int vsi) +{ + u32 addr = DEVSOC_PPE_L3_VP_PORT_TBL_ADDR + + (port * DEVSOC_PPE_L3_VP_PORT_TBL_INC); + devsoc_ppe_reg_write(addr, 0x0); + devsoc_ppe_reg_write(addr + 0x4 , 1 << 9 | vsi << 10); + devsoc_ppe_reg_write(addr + 0x8, 0x0); + devsoc_ppe_reg_write(addr + 0xc, 0x0); +} + +/* + * devsoc_ppe_ucast_queue_map_tbl_queue_id_set() + */ +static void devsoc_ppe_ucast_queue_map_tbl_queue_id_set(int queue, int port) +{ + uint32_t val; + + devsoc_ppe_reg_read(DEVSOC_PPE_QM_UQM_TBL + + (port * DEVSOC_PPE_UCAST_QUEUE_MAP_TBL_INC), &val); + + val |= queue << 4; + + devsoc_ppe_reg_write(DEVSOC_PPE_QM_UQM_TBL + + (port * DEVSOC_PPE_UCAST_QUEUE_MAP_TBL_INC), val); +} + +/* + * devsoc_vsi_setup() + */ +static void devsoc_vsi_setup(int vsi, uint8_t group_mask) +{ + uint32_t val = (group_mask << 24 | group_mask << 16 | group_mask << 8 + | group_mask); + + /* Set mask */ + devsoc_ppe_reg_write(0x063800 + (vsi * 0x10), val); + + /* new addr lrn en | station move lrn en */ + devsoc_ppe_reg_write(0x063804 + (vsi * 0x10), 0x9); +} + +/* + * devsoc_gmac_port_disable() + */ +static void devsoc_gmac_port_disable(int port) +{ + devsoc_ppe_reg_write(DEVSOC_PPE_MAC_ENABLE + (0x200 * port), 0x70); + devsoc_ppe_reg_write(DEVSOC_PPE_MAC_SPEED + (0x200 * port), 0x2); + devsoc_ppe_reg_write(DEVSOC_PPE_MAC_MIB_CTL + (0x200 * port), 0x1); +} + +/* + * ppe_port_bridge_txmac_set() + * TXMAC should be disabled for all ports by default + * TXMAC should be enabled for all ports that are link up alone + */ +void ppe_port_bridge_txmac_set(int port_id, int status) +{ + uint32_t reg_value = 0; + + devsoc_ppe_reg_read(IPE_L2_BASE_ADDR + PORT_BRIDGE_CTRL_ADDRESS + + (port_id * PORT_BRIDGE_CTRL_INC), ®_value); + if (status == 0) + reg_value |= TX_MAC_EN; + else + reg_value &= ~TX_MAC_EN; + + devsoc_ppe_reg_write(IPE_L2_BASE_ADDR + PORT_BRIDGE_CTRL_ADDRESS + + (port_id * PORT_BRIDGE_CTRL_INC), reg_value); + +} + +#ifndef CONFIG_DEVSOC_RUMI +/* + * devsoc_port_mac_clock_reset() + */ +void devsoc_port_mac_clock_reset(int port) +{ + int reg_val, reg_val1; + + reg_val = readl(NSS_CC_PPE_RESET_ADDR); + reg_val1 = readl(NSS_CC_UNIPHY_MISC_RESET); + switch(port) { + case 0: + /* Assert */ + reg_val |= GCC_PPE_PORT1_MAC_ARES; + reg_val1 |= GCC_PORT1_ARES; + writel(reg_val, NSS_CC_PPE_RESET_ADDR); + writel(reg_val1, NSS_CC_UNIPHY_MISC_RESET); + mdelay(150); + /* De-Assert */ + reg_val = readl(NSS_CC_PPE_RESET_ADDR); + reg_val1 = readl(NSS_CC_UNIPHY_MISC_RESET); + reg_val &= ~GCC_PPE_PORT1_MAC_ARES; + reg_val1 &= ~GCC_PORT1_ARES; + break; + case 1: + /* Assert */ + reg_val |= GCC_PPE_PORT2_MAC_ARES; + reg_val1 |= GCC_PORT2_ARES; + writel(reg_val, NSS_CC_PPE_RESET_ADDR); + writel(reg_val1, NSS_CC_UNIPHY_MISC_RESET); + mdelay(150); + /* De-Assert */ + reg_val = readl(NSS_CC_PPE_RESET_ADDR); + reg_val1 = readl(NSS_CC_UNIPHY_MISC_RESET); + reg_val &= ~GCC_PPE_PORT2_MAC_ARES; + reg_val1 &= ~GCC_PORT2_ARES; + break; + case 2: + /* Assert */ + reg_val |= GCC_PPE_PORT3_MAC_ARES; + reg_val1 |= GCC_PORT3_ARES; + writel(reg_val, NSS_CC_PPE_RESET_ADDR); + writel(reg_val1, NSS_CC_UNIPHY_MISC_RESET); + mdelay(150); + /* De-Assert */ + reg_val = readl(NSS_CC_PPE_RESET_ADDR); + reg_val1 = readl(NSS_CC_UNIPHY_MISC_RESET); + reg_val &= ~GCC_PPE_PORT3_MAC_ARES; + reg_val1 &= ~GCC_PORT3_ARES; + break; + case 3: + /* Assert */ + reg_val |= GCC_PPE_PORT4_MAC_ARES; + reg_val1 |= GCC_PORT4_ARES; + writel(reg_val, NSS_CC_PPE_RESET_ADDR); + writel(reg_val1, NSS_CC_UNIPHY_MISC_RESET); + mdelay(150); + /* De-Assert */ + reg_val = readl(NSS_CC_PPE_RESET_ADDR); + reg_val1 = readl(NSS_CC_UNIPHY_MISC_RESET); + reg_val &= ~GCC_PPE_PORT4_MAC_ARES; + reg_val1 &= ~GCC_PORT4_ARES; + break; + case 4: + /* Assert */ + reg_val |= GCC_PPE_PORT5_MAC_ARES; + reg_val1 |= GCC_PORT5_ARES; + writel(reg_val, NSS_CC_PPE_RESET_ADDR); + writel(reg_val1, NSS_CC_UNIPHY_MISC_RESET); + mdelay(150); + /* De-Assert */ + reg_val = readl(NSS_CC_PPE_RESET_ADDR); + reg_val1 = readl(NSS_CC_UNIPHY_MISC_RESET); + reg_val &= ~GCC_PPE_PORT5_MAC_ARES; + reg_val1 &= ~GCC_PORT5_ARES; + break; + case 5: + /* Assert */ + reg_val |= GCC_PPE_PORT6_MAC_ARES; + reg_val1 |= GCC_PORT6_ARES; + writel(reg_val, NSS_CC_PPE_RESET_ADDR); + writel(reg_val1, NSS_CC_UNIPHY_MISC_RESET); + mdelay(150); + /* De-Assert */ + reg_val = readl(NSS_CC_PPE_RESET_ADDR); + reg_val1 = readl(NSS_CC_UNIPHY_MISC_RESET); + reg_val &= ~GCC_PPE_PORT6_MAC_ARES; + reg_val1 &= ~GCC_PORT6_ARES; + break; + default: + break; + } + writel(reg_val, NSS_CC_PPE_RESET_ADDR); + writel(reg_val1, NSS_CC_UNIPHY_MISC_RESET); + mdelay(150); +} + +void devsoc_speed_clock_set(int port_id, int clk[4]) +{ + int i; + int reg_val[6]; + + for (i = 0; i < 6; i++) + { + reg_val[i] = readl(NSS_CC_PORT1_RX_CMD_RCGR + (i * 0x4) + (port_id * 0x18)); + } + reg_val[0] &= ~0x1; + reg_val[1] &= ~0x71f; + reg_val[2] &= ~0x1ff; + reg_val[3] &= ~0x1; + reg_val[4] &= ~0x71f; + reg_val[5] &= ~0x1ff; + + reg_val[1] |= clk[0]; + reg_val[2] |= clk[1]; + reg_val[4] |= clk[2]; + reg_val[5] |= clk[3]; + + /* Port Rx direction speed clock cfg */ + writel(reg_val[1], NSS_CC_PORT1_RX_CMD_RCGR + 0x4 + (port_id * 0x18)); + writel(reg_val[2], NSS_CC_PORT1_RX_CMD_RCGR + 0x8 + (port_id * 0x18)); + writel(reg_val[0] | 0x1 , NSS_CC_PORT1_RX_CMD_RCGR + (port_id * 0x18)); + /* Port Tx direction speed clock cfg */ + writel(reg_val[4], NSS_CC_PORT1_RX_CMD_RCGR + 0x10 + (port_id * 0x18)); + writel(reg_val[5], NSS_CC_PORT1_RX_CMD_RCGR + 0x14 + (port_id * 0x18)); + writel(reg_val[3] | 0x1, NSS_CC_PORT1_RX_CMD_RCGR + 0xc + (port_id * 0x18)); +} + +int phy_status_get_from_ppe(int port_id) +{ + uint32_t reg_field = 0; + + devsoc_ppe_reg_read(PORT_PHY_STATUS_ADDRESS, ®_field); + if (port_id == (PORT5 - PPE_UNIPHY_INSTANCE1)) + reg_field >>= PORT_PHY_STATUS_PORT5_1_OFFSET; + else + reg_field >>= PORT_PHY_STATUS_PORT6_OFFSET; + + return ((reg_field >> 7) & 0x1) ? 0 : 1; +} + +void ppe_xgmac_10g_r_speed_set(uint32_t port) +{ + uint32_t reg_value = 0; + + pr_debug("DEBUGGING 10g_r_speed_set......... PORTID = %d\n", port); + devsoc_ppe_reg_read(PPE_SWITCH_NSS_SWITCH_XGMAC0 + + (port * NSS_SWITCH_XGMAC_MAC_TX_CONFIGURATION), ®_value); + + reg_value |=JD; + devsoc_ppe_reg_write(PPE_SWITCH_NSS_SWITCH_XGMAC0 + + (port * NSS_SWITCH_XGMAC_MAC_TX_CONFIGURATION), reg_value); + + pr_debug("NSS_SWITCH_XGMAC_MAC_TX_CONFIGURATION Address = 0x%x -> Value = %u\n", + PPE_SWITCH_NSS_SWITCH_XGMAC0 + (port * NSS_SWITCH_XGMAC_MAC_TX_CONFIGURATION), + reg_value); +} + +void devsoc_10g_r_speed_set(int port, int status) +{ + ppe_xgmac_10g_r_speed_set(port); + ppe_port_bridge_txmac_set(port + 1, status); + ppe_port_txmac_status_set(port); + ppe_port_rxmac_status_set(port); + ppe_mac_packet_filter_set(port); +} +#endif + +void ppe_xgmac_speed_set(uint32_t port, int speed) +{ + uint32_t reg_value = 0; + + pr_debug("\nDEBUGGING xgmac_speed_set......... PORTID = %d\n", port); + devsoc_ppe_reg_read(PPE_SWITCH_NSS_SWITCH_XGMAC0 + + (port * NSS_SWITCH_XGMAC_MAC_TX_CONFIGURATION), ®_value); + + switch(speed) { + case 0: + case 1: + case 2: + reg_value &=~USS; + reg_value |=SS(XGMAC_SPEED_SELECT_1000M); + break; + case 3: + reg_value |=USS; + reg_value |=SS(XGMAC_SPEED_SELECT_10000M); + break; + case 4: + reg_value |=USS; + reg_value |=SS(XGMAC_SPEED_SELECT_2500M); + break; + case 5: + reg_value |=USS; + reg_value |=SS(XGMAC_SPEED_SELECT_5000M); + break; + } + reg_value |=JD; + devsoc_ppe_reg_write(PPE_SWITCH_NSS_SWITCH_XGMAC0 + + (port * NSS_SWITCH_XGMAC_MAC_TX_CONFIGURATION), reg_value); + pr_debug("NSS_SWITCH_XGMAC_MAC_TX_CONFIGURATION Address = 0x%x -> Value = %u\n", + PPE_SWITCH_NSS_SWITCH_XGMAC0 + (port * NSS_SWITCH_XGMAC_MAC_TX_CONFIGURATION), + reg_value); + +} + +void ppe_port_txmac_status_set(uint32_t port) +{ + uint32_t reg_value = 0; + + pr_debug("DEBUGGING txmac_status_set......... PORTID = %d\n", port); + devsoc_ppe_reg_read(PPE_SWITCH_NSS_SWITCH_XGMAC0 + + (port * NSS_SWITCH_XGMAC_MAC_TX_CONFIGURATION), ®_value); + + reg_value |=TE; + devsoc_ppe_reg_write(PPE_SWITCH_NSS_SWITCH_XGMAC0 + + (port * NSS_SWITCH_XGMAC_MAC_TX_CONFIGURATION), reg_value); + + pr_debug("NSS_SWITCH_XGMAC_MAC_TX_CONFIGURATION Address = 0x%x -> Value = %u\n", + PPE_SWITCH_NSS_SWITCH_XGMAC0 + (port * NSS_SWITCH_XGMAC_MAC_TX_CONFIGURATION), + reg_value); +} + +void ppe_port_rxmac_status_set(uint32_t port) +{ + uint32_t reg_value = 0; + + pr_debug("DEBUGGING rxmac_status_set......... PORTID = %d\n", port); + devsoc_ppe_reg_read(PPE_SWITCH_NSS_SWITCH_XGMAC0 + + MAC_RX_CONFIGURATION_ADDRESS + + (port * NSS_SWITCH_XGMAC_MAC_RX_CONFIGURATION), ®_value); + + reg_value |= 0x5ee00c0; + reg_value |=RE; + reg_value |=ACS; + reg_value |=CST; + devsoc_ppe_reg_write(PPE_SWITCH_NSS_SWITCH_XGMAC0 + + MAC_RX_CONFIGURATION_ADDRESS + + (port * NSS_SWITCH_XGMAC_MAC_RX_CONFIGURATION), reg_value); + + pr_debug("NSS_SWITCH_XGMAC_MAC_RX_CONFIGURATION Address = 0x%x -> Value = %u\n", + PPE_SWITCH_NSS_SWITCH_XGMAC0 + MAC_RX_CONFIGURATION_ADDRESS + + (port * NSS_SWITCH_XGMAC_MAC_RX_CONFIGURATION), + reg_value); +} + +void ppe_mac_packet_filter_set(uint32_t port) +{ + pr_debug("DEBUGGING mac_packet_filter_set......... PORTID = %d\n", port); + devsoc_ppe_reg_write(PPE_SWITCH_NSS_SWITCH_XGMAC0 + + MAC_PACKET_FILTER_ADDRESS + + (port * MAC_PACKET_FILTER_INC), 0x81); + pr_debug("NSS_SWITCH_XGMAC_MAC_PACKET_FILTER Address = 0x%x -> Value = %u\n", + PPE_SWITCH_NSS_SWITCH_XGMAC0 + MAC_PACKET_FILTER_ADDRESS + + (port * MAC_PACKET_FILTER_ADDRESS), + 0x81); +} + +void devsoc_uxsgmii_speed_set(int port, int speed, int duplex, + int status) +{ +#ifndef CONFIG_DEVSOC_RUMI + uint32_t uniphy_index; + + /* Setting the speed only for PORT5 and PORT6 */ + if (port == (PORT5 - PPE_UNIPHY_INSTANCE1)) + uniphy_index = PPE_UNIPHY_INSTANCE1; + else if (port == (PORT6 - PPE_UNIPHY_INSTANCE1)) + uniphy_index = PPE_UNIPHY_INSTANCE2; + else + uniphy_index = PPE_UNIPHY_INSTANCE0; + + ppe_uniphy_usxgmii_autoneg_completed(uniphy_index); + ppe_uniphy_usxgmii_speed_set(uniphy_index, speed); +#endif + ppe_xgmac_speed_set(port, speed); +#ifndef CONFIG_DEVSOC_RUMI + ppe_uniphy_usxgmii_duplex_set(uniphy_index, duplex); + ppe_uniphy_usxgmii_port_reset(uniphy_index); +#endif + ppe_port_bridge_txmac_set(port + 1, status); + ppe_port_txmac_status_set(port); + ppe_port_rxmac_status_set(port); + ppe_mac_packet_filter_set(port); +} + +void devsoc_pqsgmii_speed_set(int port, int speed, int status) +{ + ppe_port_bridge_txmac_set(port + 1, status); + devsoc_ppe_reg_write(DEVSOC_PPE_MAC_SPEED + (0x200 * port), speed); + devsoc_ppe_reg_write(DEVSOC_PPE_MAC_ENABLE + (0x200 * port), 0x73); + devsoc_ppe_reg_write(DEVSOC_PPE_MAC_MIB_CTL + (0x200 * port), 0x1); +} + +/* + * devsoc_ppe_flow_port_map_tbl_port_num_set() + */ +static void devsoc_ppe_flow_port_map_tbl_port_num_set(int queue, int port) +{ + devsoc_ppe_reg_write(DEVSOC_PPE_L0_FLOW_PORT_MAP_TBL + + queue * DEVSOC_PPE_L0_FLOW_PORT_MAP_TBL_INC, port); + devsoc_ppe_reg_write(DEVSOC_PPE_L1_FLOW_PORT_MAP_TBL + + port * DEVSOC_PPE_L1_FLOW_PORT_MAP_TBL_INC, port); +} + +/* + * devsoc_ppe_flow_map_tbl_set() + */ +static void devsoc_ppe_flow_map_tbl_set(int queue, int port) +{ + uint32_t val = port | 0x401000; /* c_drr_wt = 1, e_drr_wt = 1 */ + devsoc_ppe_reg_write(DEVSOC_PPE_L0_FLOW_MAP_TBL + queue * DEVSOC_PPE_L0_FLOW_MAP_TBL_INC, + val); + + val = port | 0x100400; /* c_drr_wt = 1, e_drr_wt = 1 */ + devsoc_ppe_reg_write(DEVSOC_PPE_L1_FLOW_MAP_TBL + port * DEVSOC_PPE_L1_FLOW_MAP_TBL_INC, + val); +} + +/* + * devsoc_ppe_tdm_configuration + */ +static void devsoc_ppe_tdm_configuration(void) +{ + devsoc_ppe_reg_write(0xc000, 0x20); + devsoc_ppe_reg_write(0xc010, 0x32); + devsoc_ppe_reg_write(0xc020, 0x21); + devsoc_ppe_reg_write(0xc030, 0x30); + devsoc_ppe_reg_write(0xc040, 0x22); + devsoc_ppe_reg_write(0xc050, 0x31); + devsoc_ppe_reg_write(0xb000, 0x80000006); + + devsoc_ppe_reg_write(0x47a000, 0xfa10); + devsoc_ppe_reg_write(0x47a010, 0xfc21); + devsoc_ppe_reg_write(0x47a020, 0xf902); + devsoc_ppe_reg_write(0x400000, 0x3); +} + +/* + * devsoc_ppe_queue_ac_enable + */ +static void devsoc_ppe_queue_ac_enable(void) +{ + int i; + + /* ucast queue */ + for (i = 0; i < 256; i++) { + devsoc_ppe_reg_write(DEVSOC_PPE_UCAST_QUEUE_AC_EN_BASE_ADDR + + (i * 0x10), 0x32120001); + devsoc_ppe_reg_write(DEVSOC_PPE_UCAST_QUEUE_AC_EN_BASE_ADDR + + (i * 0x10) + 0x4, 0x0); + devsoc_ppe_reg_write(DEVSOC_PPE_UCAST_QUEUE_AC_EN_BASE_ADDR + + (i * 0x10) + 0x8, 0x0); + devsoc_ppe_reg_write(DEVSOC_PPE_UCAST_QUEUE_AC_EN_BASE_ADDR + + (i * 0x10) + 0xc, 0x48000); + } + + /* mcast queue */ + for (i = 0; i < 44; i++) { + devsoc_ppe_reg_write(DEVSOC_PPE_MCAST_QUEUE_AC_EN_BASE_ADDR + + (i * 0x10), 0x00fa0001); + devsoc_ppe_reg_write(DEVSOC_PPE_MCAST_QUEUE_AC_EN_BASE_ADDR + + (i * 0x10) + 0x4, 0x0); + devsoc_ppe_reg_write(DEVSOC_PPE_MCAST_QUEUE_AC_EN_BASE_ADDR + + (i * 0x10) + 0x8, 0x1200); + } +} + +/* + * devsoc_ppe_enable_port_counter + */ +static void devsoc_ppe_enable_port_counter(void) +{ + int i; + uint32_t reg = 0; + + for (i = 0; i < 7; i++) { + /* MRU_MTU_CTRL_TBL.rx_cnt_en, MRU_MTU_CTRL_TBL.tx_cnt_en */ + devsoc_ppe_reg_read(DEVSOC_PPE_MRU_MTU_CTRL_TBL_ADDR + + (i * 0x10), ®); + devsoc_ppe_reg_write(DEVSOC_PPE_MRU_MTU_CTRL_TBL_ADDR + + (i * 0x10), reg); + devsoc_ppe_reg_read(DEVSOC_PPE_MRU_MTU_CTRL_TBL_ADDR + + (i * 0x10) + 0x4, ®); + devsoc_ppe_reg_write(DEVSOC_PPE_MRU_MTU_CTRL_TBL_ADDR + + (i * 0x10) + 0x4, reg | 0x284303); + devsoc_ppe_reg_read(DEVSOC_PPE_MRU_MTU_CTRL_TBL_ADDR + + (i * 0x10) + 0x8, ®); + devsoc_ppe_reg_write(DEVSOC_PPE_MRU_MTU_CTRL_TBL_ADDR + + (i * 0x10) + 0x8, reg); + devsoc_ppe_reg_read(DEVSOC_PPE_MRU_MTU_CTRL_TBL_ADDR + + (i * 0x10) + 0xc, ®); + devsoc_ppe_reg_write(DEVSOC_PPE_MRU_MTU_CTRL_TBL_ADDR + + (i * 0x10) + 0xc, reg); + + /* MC_MTU_CTRL_TBL.tx_cnt_en */ + devsoc_ppe_reg_read(DEVSOC_PPE_MC_MTU_CTRL_TBL_ADDR + + (i * 0x4), ®); + devsoc_ppe_reg_write(DEVSOC_PPE_MC_MTU_CTRL_TBL_ADDR + + (i * 0x4), reg | 0x10000); + + /* PORT_EG_VLAN.tx_counting_en */ + devsoc_ppe_reg_read(DEVSOC_PPE_PORT_EG_VLAN_TBL_ADDR + + (i * 0x4), ®); + devsoc_ppe_reg_write(DEVSOC_PPE_PORT_EG_VLAN_TBL_ADDR + + (i * 0x4), reg | 0x100); + + /* TL_PORT_VP_TBL.rx_cnt_en */ + devsoc_ppe_reg_read(DEVSOC_PPE_TL_PORT_VP_TBL_ADDR + + (i * 0x10), ®); + devsoc_ppe_reg_write(DEVSOC_PPE_TL_PORT_VP_TBL_ADDR + + (i * 0x10), reg); + devsoc_ppe_reg_read(DEVSOC_PPE_TL_PORT_VP_TBL_ADDR + + (i * 0x10) + 0x4, ®); + devsoc_ppe_reg_write(DEVSOC_PPE_TL_PORT_VP_TBL_ADDR + + (i * 0x10) + 0x4, reg); + devsoc_ppe_reg_read(DEVSOC_PPE_TL_PORT_VP_TBL_ADDR + + (i * 0x10) + 0x8, ®); + devsoc_ppe_reg_write(DEVSOC_PPE_TL_PORT_VP_TBL_ADDR + + (i * 0x10) + 0x8, reg | 0x20000); + devsoc_ppe_reg_read(DEVSOC_PPE_TL_PORT_VP_TBL_ADDR + + (i * 0x10) + 0xc, ®); + devsoc_ppe_reg_write(DEVSOC_PPE_TL_PORT_VP_TBL_ADDR + + (i * 0x10) + 0xc, reg); + } +} + +/* + * devsoc_ppe_c_sp_cfg_tbl_drr_id_set + */ +static void devsoc_ppe_c_sp_cfg_tbl_drr_id_set(int id) +{ + devsoc_ppe_reg_write(DEVSOC_PPE_L0_C_SP_CFG_TBL + (id * 0x80), id * 2); + devsoc_ppe_reg_write(DEVSOC_PPE_L1_C_SP_CFG_TBL + (id * 0x80), id * 2); +} + +/* + * devsoc_ppe_e_sp_cfg_tbl_drr_id_set + */ +static void devsoc_ppe_e_sp_cfg_tbl_drr_id_set(int id) +{ + devsoc_ppe_reg_write(DEVSOC_PPE_L0_E_SP_CFG_TBL + (id * 0x80), id * 2 + 1); + devsoc_ppe_reg_write(DEVSOC_PPE_L1_E_SP_CFG_TBL + (id * 0x80), id * 2 + 1); +} + +static void ppe_port_mux_set(int port_id, int port_type, int mode) +{ + uint32_t mux_mac_type = 0; + union port_mux_ctrl_u port_mux_ctrl; + + pr_debug("\nport id is: %d, port type is %d, mode is %d", + port_id, port_type, mode); + + if (port_type == PORT_GMAC_TYPE) + mux_mac_type = DEVSOC_PORT_MUX_MAC_TYPE; + else if (port_type == PORT_XGMAC_TYPE) + mux_mac_type = DEVSOC_PORT_MUX_XMAC_TYPE; + else + printf("\nAttention!!!..Port type configured wrongly..port_id = %d, mode = %d, port_type = %d", + port_id, mode, port_type); + + port_mux_ctrl.val = 0; + devsoc_ppe_reg_read(DEVSOC_PORT_MUX_CTRL, &(port_mux_ctrl.val)); + pr_debug("\nBEFORE UPDATE: Port MUX CTRL value is %u", port_mux_ctrl.val); + + + switch (port_id) { + case PORT1: + port_mux_ctrl.bf.port1_mac_sel = mux_mac_type; + port_mux_ctrl.bf.port1_pcs_sel = 0; + break; + case PORT2: + port_mux_ctrl.bf.port2_mac_sel = mux_mac_type; + port_mux_ctrl.bf.port2_pcs_sel = 0; + break; + default: + break; + } + + devsoc_ppe_reg_write(DEVSOC_PORT_MUX_CTRL, port_mux_ctrl.val); + pr_debug("\nAFTER UPDATE: Port MUX CTRL value is %u", port_mux_ctrl.val); +} + +void ppe_port_mux_mac_type_set(int port_id, int mode) +{ + uint32_t port_type; + + switch(mode) + { + case EPORT_WRAPPER_PSGMII: + case EPORT_WRAPPER_SGMII0_RGMII4: + case EPORT_WRAPPER_SGMII_PLUS: + case EPORT_WRAPPER_SGMII_FIBER: + port_type = PORT_GMAC_TYPE; + break; + case EPORT_WRAPPER_USXGMII: + case EPORT_WRAPPER_10GBASE_R: + port_type = PORT_XGMAC_TYPE; + break; + default: + printf("\nError during port_type set: mode is %d, port_id is: %d", + mode, port_id); + return; + } + ppe_port_mux_set(port_id, port_type, mode); +} + +void devsoc_ppe_interface_mode_init(void) +{ + uint32_t mode0, mode1; + int node; + node = fdt_path_offset(gd->fdt_blob, "/ess-switch"); + if (node < 0) { + printf("\nError: ess-switch not specified in dts"); + return; + } + + mode0 = fdtdec_get_uint(gd->fdt_blob, node, "switch_mac_mode0", -1); + if (mode0 < 0) { + printf("\nError: switch_mac_mode0 not specified in dts"); + return; + } + + mode1 = fdtdec_get_uint(gd->fdt_blob, node, "switch_mac_mode1", -1); + if (mode1 < 0) { + printf("\nError: switch_mac_mode1 not specified in dts"); + return; + } + +#ifndef CONFIG_DEVSOC_RUMI + ppe_uniphy_mode_set(PPE_UNIPHY_INSTANCE0, mode0); + ppe_uniphy_mode_set(PPE_UNIPHY_INSTANCE1, mode1); +#endif + + /* + * Port1 and Port2 can be used as GMAC or XGMAC. + */ + ppe_port_mux_mac_type_set(PORT1, mode0); + ppe_port_mux_mac_type_set(PORT2, mode0); +} + +/* + * devsoc_ppe_provision_init() + */ +void devsoc_ppe_provision_init(void) +{ + int i; + uint32_t queue; + + /* tdm/sched configuration */ + devsoc_ppe_tdm_configuration(); + +#ifdef CONFIG_DEVSOC_BRIDGED_MODE + /* Add CPU port 0 to VSI 2 */ + devsoc_ppe_vp_port_tbl_set(0, 2); + + /* Add port 1 - 4 to VSI 2 */ + devsoc_ppe_vp_port_tbl_set(1, 2); + devsoc_ppe_vp_port_tbl_set(2, 2); + devsoc_ppe_vp_port_tbl_set(3, 2); + devsoc_ppe_vp_port_tbl_set(4, 2); + devsoc_ppe_vp_port_tbl_set(5, 2); + devsoc_ppe_vp_port_tbl_set(6, 2); + +#else + devsoc_ppe_vp_port_tbl_set(1, 2); + devsoc_ppe_vp_port_tbl_set(2, 3); + devsoc_ppe_vp_port_tbl_set(3, 4); + devsoc_ppe_vp_port_tbl_set(4, 5); + devsoc_ppe_vp_port_tbl_set(5, 6); + devsoc_ppe_vp_port_tbl_set(6, 7); +#endif + + /* Unicast priority map */ + devsoc_ppe_reg_write(DEVSOC_PPE_QM_UPM_TBL, 0); + + /* Port0 - 7 unicast queue settings */ + for (i = 0; i < 8; i++) { + if (i == 0) + queue = 0; + else + queue = ((i * 0x10) + 0x70); + + devsoc_ppe_ucast_queue_map_tbl_queue_id_set(queue, i); + devsoc_ppe_flow_port_map_tbl_port_num_set(queue, i); + devsoc_ppe_flow_map_tbl_set(queue, i); + devsoc_ppe_c_sp_cfg_tbl_drr_id_set(i); + devsoc_ppe_e_sp_cfg_tbl_drr_id_set(i); + } + + /* Port0 multicast queue */ + devsoc_ppe_reg_write(0x409000, 0x00000000); + devsoc_ppe_reg_write(0x403000, 0x00401000); + + /* Port1 - 7 multicast queue */ + for (i = 1; i < 8; i++) { + devsoc_ppe_reg_write(0x409100 + ((i - 1) * 0x40), i); + devsoc_ppe_reg_write(0x403100 + ((i - 1) * 0x40), 0x401000 | i); + } + + /* ac enable for queues - disable queue tail drop */ + devsoc_ppe_queue_ac_enable(); + + /* enable queue counter */ + devsoc_ppe_reg_write(0x020044,0x4); + + /* assign the ac group 0 with buffer number */ + devsoc_ppe_reg_write(0x84c000, 0x0); + devsoc_ppe_reg_write(0x84c004, 0x7D00); + devsoc_ppe_reg_write(0x84c008, 0x0); + devsoc_ppe_reg_write(0x84c00c, 0x0); + + /* enable physical/virtual port TX/RX counters for all ports (0-6) */ + devsoc_ppe_enable_port_counter(); + + /* + * Port0 - TX_EN is set by default, Port1 - LRN_EN is set + * Port0 -> CPU Port + * Port1-6 -> Ethernet Ports + * Port7 -> EIP197 + */ + for (i = 0; i < 8; i++) { + if (i == 0) + devsoc_ppe_reg_write(DEVSOC_PPE_PORT_BRIDGE_CTRL_OFFSET + (i * 4), + DEVSOC_PPE_PORT_BRIDGE_CTRL_PROMISC_EN | + DEVSOC_PPE_PORT_BRIDGE_CTRL_TXMAC_EN | + DEVSOC_PPE_PORT_BRIDGE_CTRL_PORT_ISOLATION_BMP | + DEVSOC_PPE_PORT_BRIDGE_CTRL_STATION_LRN_EN | + DEVSOC_PPE_PORT_BRIDGE_CTRL_NEW_ADDR_LRN_EN); + else if (i == 7) + devsoc_ppe_reg_write(DEVSOC_PPE_PORT_BRIDGE_CTRL_OFFSET + (i * 4), + DEVSOC_PPE_PORT_BRIDGE_CTRL_PROMISC_EN | + DEVSOC_PPE_PORT_BRIDGE_CTRL_PORT_ISOLATION_BMP | + DEVSOC_PPE_PORT_BRIDGE_CTRL_STATION_LRN_EN | + DEVSOC_PPE_PORT_BRIDGE_CTRL_NEW_ADDR_LRN_EN); + else + devsoc_ppe_reg_write(DEVSOC_PPE_PORT_BRIDGE_CTRL_OFFSET + (i * 4), + DEVSOC_PPE_PORT_BRIDGE_CTRL_PROMISC_EN | + DEVSOC_PPE_PORT_BRIDGE_CTRL_PORT_ISOLATION_BMP); + } + + /* Global learning */ + devsoc_ppe_reg_write(0x060038, 0xc0); + +#ifdef CONFIG_DEVSOC_BRIDGED_MODE + devsoc_vsi_setup(2, 0x7f); +#else + devsoc_vsi_setup(2, 0x03); + devsoc_vsi_setup(3, 0x05); + devsoc_vsi_setup(4, 0x09); + devsoc_vsi_setup(5, 0x11); + devsoc_vsi_setup(6, 0x21); + devsoc_vsi_setup(7, 0x41); +#endif + + /* Port 0-7 STP */ + for (i = 0; i < 8; i++) + devsoc_ppe_reg_write(DEVSOC_PPE_STP_BASE + (0x4 * i), 0x3); + + devsoc_ppe_interface_mode_init(); + /* Port 1-2 disable */ + for (i = 0; i < 2; i++) { + devsoc_gmac_port_disable(i); + ppe_port_bridge_txmac_set(i + 1, 1); + } + + /* Allowing DHCP packets */ + devsoc_ppe_acl_set(0, ADPT_ACL_HPPE_IPV4_DIP_RULE, UDP_PKT, 67, 0xffff, 0, 0); + devsoc_ppe_acl_set(1, ADPT_ACL_HPPE_IPV4_DIP_RULE, UDP_PKT, 68, 0xffff, 0, 0); + /* Dropping all the UDP packets */ + devsoc_ppe_acl_set(2, ADPT_ACL_HPPE_IPV4_DIP_RULE, UDP_PKT, 0, 0, 0, 1); +} diff --git a/drivers/net/devsoc/devsoc_ppe.h b/drivers/net/devsoc/devsoc_ppe.h new file mode 100644 index 0000000000..cfc554887b --- /dev/null +++ b/drivers/net/devsoc/devsoc_ppe.h @@ -0,0 +1,266 @@ +/* + ************************************************************************** + * Copyright (c) 2016-2019, 2021, The Linux Foundation. All rights reserved. + * + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + + +#define DEVSOC_PPE_BASE_ADDR 0x3a000000 +#define PORT1 1 +#define PORT2 2 + +#define DEVSOC_PORT5_MUX_PCS_UNIPHY0 0x0 +#define DEVSOC_PORT5_MUX_PCS_UNIPHY1 0x1 + +#define PORT_GMAC_TYPE 1 +#define PORT_XGMAC_TYPE 2 + +#define DEVSOC_PORT_MUX_MAC_TYPE 0 +#define DEVSOC_PORT_MUX_XMAC_TYPE 1 + +struct port_mux_ctrl { + uint32_t port1_pcs_sel:1; + uint32_t port2_pcs_sel:1; + uint32_t _reserved0:6; + uint32_t port1_mac_sel:1; + uint32_t port2_mac_sel:1; + uint32_t _reserved1:22; +}; + +union port_mux_ctrl_u { + uint32_t val; + struct port_mux_ctrl bf; +}; + +enum { + TCP_PKT, + UDP_PKT, +}; + +#define ADPT_ACL_HPPE_IPV4_DIP_RULE 4 +#define ADPT_ACL_HPPE_MAC_SA_RULE 1 +#define ADPT_ACL_HPPE_MAC_DA_RULE 0 +#define MAX_RULE 512 + +struct ipo_rule_reg { + uint32_t rule_field_0:32; + uint32_t rule_field_1:20; + uint32_t fake_mac_header:1; + uint32_t range_en:1; + uint32_t inverse_en:1; + uint32_t rule_type:5; + uint32_t src_type:3; + uint32_t src_0:1; + uint32_t src_1:7; + uint32_t pri:9; + uint32_t res_chain:1; + uint32_t post_routing_en:1; + uint32_t _reserved0:14; +}; + +union ipo_rule_reg_u { + uint32_t val[3]; + struct ipo_rule_reg bf; +}; + +struct ipo_mask_reg { + uint32_t maskfield_0:32; + uint32_t maskfield_1:21; + uint32_t _reserved0:11; +}; + +union ipo_mask_reg_u { + uint32_t val[2]; + struct ipo_mask_reg bf; +}; + +struct ipo_action { + uint32_t dest_info_change_en:1; + uint32_t fwd_cmd:2; + uint32_t _reserved0:15; + uint32_t bypass_bitmap_0:14; + uint32_t bypass_bitmap_1:18; + uint32_t _reserved1:14; + uint32_t _reserved2:32; + uint32_t _reserved3:32; + uint32_t _reserved4:32; +}; + +union ipo_action_u { + uint32_t val[5]; + struct ipo_action bf; +}; + +#define DEVSOC_PORT_MUX_CTRL 0x10 +#define DEVSOC_PORT_MUX_CTRL_NUM 1 +#define DEVSOC_PORT_MUX_CTRL_INC 0x4 +#define DEVSOC_PORT_MUX_CTRL_DEFAULT 0x0 + +#define PORT_PHY_STATUS_ADDRESS 0x44 +#define PORT_PHY_STATUS_PORT5_1_OFFSET 8 +#define PORT_PHY_STATUS_PORT6_OFFSET 16 + +#define DEVSOC_PPE_IPE_L3_BASE_ADDR 0x200000 +#define DEVSOC_PPE_L3_VP_PORT_TBL_ADDR (DEVSOC_PPE_IPE_L3_BASE_ADDR + 0x4000) +#define DEVSOC_PPE_L3_VP_PORT_TBL_INC 0x10 + +#define DEVSOC_PPE_TL_PORT_VP_TBL_ADDR 0x302000 +#define DEVSOC_PPE_MRU_MTU_CTRL_TBL_ADDR 0x65000 +#define DEVSOC_PPE_MC_MTU_CTRL_TBL_ADDR 0x60a00 +#define DEVSOC_PPE_PORT_EG_VLAN_TBL_ADDR 0x20020 + +#define DEVSOC_PPE_UCAST_QUEUE_AC_EN_BASE_ADDR 0x848000 +#define DEVSOC_PPE_MCAST_QUEUE_AC_EN_BASE_ADDR 0x84a000 +#define DEVSOC_PPE_QUEUE_MANAGER_BASE_ADDR 0x800000 +#define DEVSOC_PPE_UCAST_QUEUE_MAP_TBL_ADDR 0x10000 +#define DEVSOC_PPE_UCAST_QUEUE_MAP_TBL_INC 0x10 +#define DEVSOC_PPE_QM_UQM_TBL (DEVSOC_PPE_QUEUE_MANAGER_BASE_ADDR +\ + DEVSOC_PPE_UCAST_QUEUE_MAP_TBL_ADDR) +#define DEVSOC_PPE_UCAST_PRIORITY_MAP_TBL_ADDR 0x42000 +#define DEVSOC_PPE_QM_UPM_TBL (DEVSOC_PPE_QUEUE_MANAGER_BASE_ADDR +\ + DEVSOC_PPE_UCAST_PRIORITY_MAP_TBL_ADDR) + +#define DEVSOC_PPE_STP_BASE 0x060100 +#define DEVSOC_PPE_MAC_ENABLE 0x001000 +#define DEVSOC_PPE_MAC_SPEED 0x001004 +#define DEVSOC_PPE_MAC_MIB_CTL 0x001034 + +#define DEVSOC_PPE_TRAFFIC_MANAGER_BASE_ADDR 0x400000 +#define DEVSOC_PPE_TM_SHP_CFG_L0_OFFSET 0x00000030 +#define DEVSOC_PPE_TM_SHP_CFG_L1_OFFSET 0x00000034 +#define DEVSOC_PPE_TM_SHP_CFG_L0 DEVSOC_PPE_TRAFFIC_MANAGER_BASE_ADDR +\ + DEVSOC_PPE_TM_SHP_CFG_L0_OFFSET +#define DEVSOC_PPE_TM_SHP_CFG_L1 DEVSOC_PPE_TRAFFIC_MANAGER_BASE_ADDR +\ + DEVSOC_PPE_TM_SHP_CFG_L1_OFFSET + +#define DEVSOC_PPE_L0_FLOW_PORT_MAP_TBL_ADDR 0x10000 +#define DEVSOC_PPE_L0_FLOW_PORT_MAP_TBL_INC 0x10 +#define DEVSOC_PPE_L0_FLOW_PORT_MAP_TBL (DEVSOC_PPE_TRAFFIC_MANAGER_BASE_ADDR +\ + DEVSOC_PPE_L0_FLOW_PORT_MAP_TBL_ADDR) + +#define DEVSOC_PPE_L0_FLOW_MAP_TBL_ADDR 0x2000 +#define DEVSOC_PPE_L0_FLOW_MAP_TBL_INC 0x10 +#define DEVSOC_PPE_L0_FLOW_MAP_TBL (DEVSOC_PPE_TRAFFIC_MANAGER_BASE_ADDR +\ + DEVSOC_PPE_L0_FLOW_MAP_TBL_ADDR) + +#define DEVSOC_PPE_L1_FLOW_PORT_MAP_TBL_ADDR 0x46000 +#define DEVSOC_PPE_L1_FLOW_PORT_MAP_TBL_INC 0x10 +#define DEVSOC_PPE_L1_FLOW_PORT_MAP_TBL (DEVSOC_PPE_TRAFFIC_MANAGER_BASE_ADDR +\ + DEVSOC_PPE_L1_FLOW_PORT_MAP_TBL_ADDR) + +#define DEVSOC_PPE_L1_FLOW_MAP_TBL_ADDR 0x40000 +#define DEVSOC_PPE_L1_FLOW_MAP_TBL_INC 0x10 +#define DEVSOC_PPE_L1_FLOW_MAP_TBL (DEVSOC_PPE_TRAFFIC_MANAGER_BASE_ADDR +\ + DEVSOC_PPE_L1_FLOW_MAP_TBL_ADDR) + +#define DEVSOC_PPE_L0_C_SP_CFG_TBL_ADDR 0x4000 +#define DEVSOC_PPE_L0_C_SP_CFG_TBL (DEVSOC_PPE_TRAFFIC_MANAGER_BASE_ADDR +\ + DEVSOC_PPE_L0_C_SP_CFG_TBL_ADDR) + +#define DEVSOC_PPE_L1_C_SP_CFG_TBL_ADDR 0x42000 +#define DEVSOC_PPE_L1_C_SP_CFG_TBL (DEVSOC_PPE_TRAFFIC_MANAGER_BASE_ADDR +\ + DEVSOC_PPE_L1_C_SP_CFG_TBL_ADDR) + +#define DEVSOC_PPE_L0_E_SP_CFG_TBL_ADDR 0x6000 +#define DEVSOC_PPE_L0_E_SP_CFG_TBL (DEVSOC_PPE_TRAFFIC_MANAGER_BASE_ADDR +\ + DEVSOC_PPE_L0_E_SP_CFG_TBL_ADDR) + +#define DEVSOC_PPE_L1_E_SP_CFG_TBL_ADDR 0x44000 +#define DEVSOC_PPE_L1_E_SP_CFG_TBL (DEVSOC_PPE_TRAFFIC_MANAGER_BASE_ADDR +\ + DEVSOC_PPE_L1_E_SP_CFG_TBL_ADDR) + +#define DEVSOC_PPE_FPGA_GPIO_BASE_ADDR 0x01008000 + +#define DEVSOC_PPE_MAC_PORT_MUX_OFFSET 0x10 +#define DEVSOC_PPE_FPGA_GPIO_OFFSET 0xc000 +#define DEVSOC_PPE_FPGA_SCHED_OFFSET 0x47a000 +#define DEVSOC_PPE_TDM_CFG_DEPTH_OFFSET 0xb000 +#define DEVSOC_PPE_TDM_SCHED_DEPTH_OFFSET 0x400000 +#define DEVSOC_PPE_PORT_BRIDGE_CTRL_OFFSET 0x060300 + +#define DEVSOC_PPE_TDM_CFG_DEPTH_VAL 0x80000064 +#define DEVSOC_PPE_MAC_PORT_MUX_OFFSET_VAL 0x15 +#define DEVSOC_PPE_TDM_SCHED_DEPTH_VAL 0x32 +#define DEVSOC_PPE_TDM_CFG_VALID 0x20 +#define DEVSOC_PPE_TDM_CFG_DIR_INGRESS 0x0 +#define DEVSOC_PPE_TDM_CFG_DIR_EGRESS 0x10 +#define DEVSOC_PPE_PORT_EDMA 0x0 +#define DEVSOC_PPE_PORT_QTI1 0x1 +#define DEVSOC_PPE_PORT_QTI2 0x2 +#define DEVSOC_PPE_PORT_QTI3 0x3 +#define DEVSOC_PPE_PORT_QTI4 0x4 +#define DEVSOC_PPE_PORT_XGMAC1 0x5 +#define DEVSOC_PPE_PORT_XGMAC2 0x6 +#define DEVSOC_PPE_PORT_CRYPTO1 0x7 +#define DEVSOC_PPE_PORT_BRIDGE_CTRL_PROMISC_EN 0x20000 +#define DEVSOC_PPE_PORT_BRIDGE_CTRL_TXMAC_EN 0x10000 +#define DEVSOC_PPE_PORT_BRIDGE_CTRL_PORT_ISOLATION_BMP 0x7f00 +#define DEVSOC_PPE_PORT_BRIDGE_CTRL_STATION_LRN_EN 0x8 +#define DEVSOC_PPE_PORT_BRIDGE_CTRL_NEW_ADDR_LRN_EN 0x1 + +#define DEVSOC_PPE_PORT_EDMA_BITPOS 0x1 +#define DEVSOC_PPE_PORT_QTI1_BITPOS (1 << DEVSOC_PPE_PORT_QTI1) +#define DEVSOC_PPE_PORT_QTI2_BITPOS (1 << DEVSOC_PPE_PORT_QTI2) +#define DEVSOC_PPE_PORT_QTI3_BITPOS (1 << DEVSOC_PPE_PORT_QTI3) +#define DEVSOC_PPE_PORT_QTI4_BITPOS (1 << DEVSOC_PPE_PORT_QTI4) +#define DEVSOC_PPE_PORT_XGMAC1_BITPOS (1 << DEVSOC_PPE_PORT_XGMAC1) +#define DEVSOC_PPE_PORT_XGMAC2_BITPOS (1 << DEVSOC_PPE_PORT_XGMAC2) +#define DEVSOC_PPE_PORT_CRYPTO1_BITPOS (1 << DEVSOC_PPE_PORT_CRYPTO1) + +#define PPE_SWITCH_NSS_SWITCH_XGMAC0 0x500000 +#define NSS_SWITCH_XGMAC_MAC_TX_CONFIGURATION 0x4000 +#define USS (1 << 31) +#define SS(i) (i << 29) +#define JD (1 << 16) +#define TE (1 << 0) +#define NSS_SWITCH_XGMAC_MAC_RX_CONFIGURATION 0x4000 +#define MAC_RX_CONFIGURATION_ADDRESS 0x4 +#define RE (1 << 0) +#define ACS (1 << 1) +#define CST (1 << 2) +#define MAC_PACKET_FILTER_INC 0x4000 +#define MAC_PACKET_FILTER_ADDRESS 0x8 + +#define XGMAC_SPEED_SELECT_10000M 0 +#define XGMAC_SPEED_SELECT_5000M 1 +#define XGMAC_SPEED_SELECT_2500M 2 +#define XGMAC_SPEED_SELECT_1000M 3 + +#define IPE_L2_BASE_ADDR 0x060000 +#define PORT_BRIDGE_CTRL_ADDRESS 0x300 +#define PORT_BRIDGE_CTRL_INC 0x4 +#define TX_MAC_EN (1 << 16) + +#define IPO_CSR_BASE_ADDR 0x0b0000 + +#define IPO_RULE_REG_ADDRESS 0x0 +#define IPO_RULE_REG_INC 0x10 + +#define IPO_MASK_REG_ADDRESS 0x2000 +#define IPO_MASK_REG_INC 0x10 + +#define IPO_ACTION_ADDRESS 0x8000 +#define IPO_ACTION_INC 0x20 diff --git a/drivers/net/devsoc/devsoc_uniphy.c b/drivers/net/devsoc/devsoc_uniphy.c new file mode 100644 index 0000000000..364b4f23f3 --- /dev/null +++ b/drivers/net/devsoc/devsoc_uniphy.c @@ -0,0 +1,557 @@ +/* + * Copyright (c) 2017-2019, 2021, The Linux Foundation. All rights reserved. + * + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "devsoc_edma.h" +#include "devsoc_uniphy.h" +#include "devsoc_ppe.h" +#include +#include "ipq_phy.h" + +extern int is_uniphy_enabled(int uniphy_index); + +DECLARE_GLOBAL_DATA_PTR; +extern int ipq_mdio_write(int mii_id, + int regnum, u16 value); +extern int ipq_mdio_read(int mii_id, + int regnum, ushort *data); +extern void devsoc_qca8075_phy_serdes_reset(u32 phy_id); + +void csr1_write(int phy_id, int addr, int value) +{ + int addr_h, addr_l, ahb_h, ahb_l, phy; + phy=phy_id<<(0x10); + addr_h=(addr&0xffffff)>>8; + addr_l=((addr&0xff)<<2)|(0x20<<(0xa)); + ahb_l=(addr_l&0xffff)|(0x7A00000|phy); + ahb_h=(0x7A083FC|phy); + writel(addr_h,ahb_h); + writel(value,ahb_l); +} + +int csr1_read(int phy_id, int addr ) +{ + int addr_h ,addr_l,ahb_h, ahb_l, phy; + phy=phy_id<<(0x10); + addr_h=(addr&0xffffff)>>8; + addr_l=((addr&0xff)<<2)|(0x20<<(0xa)); + ahb_l=(addr_l&0xffff)|(0x7A00000|phy); + ahb_h=(0x7A083FC|phy); + writel(addr_h, ahb_h); + return readl(ahb_l); +} + +static int ppe_uniphy_calibration(uint32_t uniphy_index) +{ + int retries = 100, calibration_done = 0; + uint32_t reg_value = 0; + + while(calibration_done != UNIPHY_CALIBRATION_DONE) { + mdelay(1); + if (retries-- == 0) { + printf("uniphy callibration time out!\n"); + return -1; + } + reg_value = readl(PPE_UNIPHY_BASE + (uniphy_index * PPE_UNIPHY_REG_INC) + + PPE_UNIPHY_OFFSET_CALIB_4); + calibration_done = (reg_value >> 0x7) & 0x1; + } + + return 0; +} + +static void ppe_uniphy_reset(enum uniphy_reset_type rst_type, bool enable) +{ + uint32_t mode, node; + uint32_t reg_val, reg_val1; + + switch(rst_type) { + case UNIPHY0_SOFT_RESET: + node = fdt_path_offset(gd->fdt_blob, "/ess-switch"); + if (node < 0) { + printf("\nError: ess-switch not specified in dts"); + return; + } + mode = fdtdec_get_uint(gd->fdt_blob, node, "switch_mac_mode1", -1); + if (mode < 0) { + printf("\nError: switch_mac_mode1 not specified in dts"); + return; + } + reg_val = readl(GCC_UNIPHY0_MISC); + reg_val1 = readl(NSS_CC_UNIPHY_MISC_RESET); + if (mode == EPORT_WRAPPER_MAX) { + if (enable) { + reg_val |= 0x1; + reg_val1 |= 0xffc000; + } else { + reg_val &= ~0x1; + reg_val1 &= ~0xffc000; + } + } else { + if (enable) { + reg_val |= 0x1; + reg_val1 |= 0xff0000; + } else { + reg_val &= ~0x1; + reg_val1 &= ~0xff0000; + } + } + writel(reg_val, GCC_UNIPHY0_MISC); + writel(reg_val1, NSS_CC_UNIPHY_MISC_RESET); + break; + case UNIPHY0_XPCS_RESET: + reg_val = readl(GCC_UNIPHY0_MISC); + if (enable) + reg_val |= 0x4; + else + reg_val &= ~0x4; + writel(reg_val, GCC_UNIPHY0_MISC); + break; + case UNIPHY1_SOFT_RESET: + reg_val = readl(GCC_UNIPHY0_MISC + GCC_UNIPHY_REG_INC); + reg_val1 = readl(NSS_CC_UNIPHY_MISC_RESET); + if (enable) { + reg_val |= 0x1; + reg_val1 |= 0xC000; + } else { + reg_val &= ~0x1; + reg_val1 &= ~0xC000; + } + writel(reg_val, GCC_UNIPHY0_MISC + GCC_UNIPHY_REG_INC); + writel(reg_val1, NSS_CC_UNIPHY_MISC_RESET); + break; + case UNIPHY1_XPCS_RESET: + reg_val = readl(GCC_UNIPHY0_MISC + GCC_UNIPHY_REG_INC); + if (enable) + reg_val |= 0x4; + else + reg_val &= ~0x4; + writel(reg_val, GCC_UNIPHY0_MISC + GCC_UNIPHY_REG_INC); + break; + case UNIPHY2_SOFT_RESET: + reg_val = readl(GCC_UNIPHY0_MISC + (2 * GCC_UNIPHY_REG_INC)); + reg_val1 = readl(NSS_CC_UNIPHY_MISC_RESET); + if (enable) { + reg_val |= 0x1; + reg_val1 |= 0x3000; + } else { + reg_val &= ~0x1; + reg_val1 &= ~0x3000; + } + writel(reg_val, GCC_UNIPHY0_MISC + (2 * GCC_UNIPHY_REG_INC)); + writel(reg_val1, NSS_CC_UNIPHY_MISC_RESET); + break; + case UNIPHY2_XPCS_RESET: + reg_val = readl(GCC_UNIPHY0_MISC + (2 * GCC_UNIPHY_REG_INC)); + if (enable) + reg_val |= 0x4; + else + reg_val &= ~0x4; + writel(reg_val, GCC_UNIPHY0_MISC + (2 * GCC_UNIPHY_REG_INC)); + break; + default: + break; + } +} + +static void ppe_uniphy_psgmii_mode_set(uint32_t uniphy_index) +{ + if (uniphy_index == 0) + ppe_uniphy_reset(UNIPHY0_XPCS_RESET, true); + else if (uniphy_index == 1) + ppe_uniphy_reset(UNIPHY1_XPCS_RESET, true); + else + ppe_uniphy_reset(UNIPHY2_XPCS_RESET, true); + mdelay(100); + + writel(0x220, PPE_UNIPHY_BASE + (uniphy_index * PPE_UNIPHY_REG_INC) + + PPE_UNIPHY_MODE_CONTROL); + + if (uniphy_index == 0) { + ppe_uniphy_reset(UNIPHY0_SOFT_RESET, true); + mdelay(100); + ppe_uniphy_reset(UNIPHY0_SOFT_RESET, false); + } else if (uniphy_index == 1) { + ppe_uniphy_reset(UNIPHY1_SOFT_RESET, true); + mdelay(100); + ppe_uniphy_reset(UNIPHY1_SOFT_RESET, false); + } else { + ppe_uniphy_reset(UNIPHY2_SOFT_RESET, true); + mdelay(100); + ppe_uniphy_reset(UNIPHY2_SOFT_RESET, false); + } + mdelay(100); + ppe_uniphy_calibration(uniphy_index); +#ifdef CONFIG_DEVSOC_QCA8075_PHY + devsoc_qca8075_phy_serdes_reset(0x10); +#endif +} + +static void ppe_uniphy_qsgmii_mode_set(uint32_t uniphy_index) +{ + if (uniphy_index == 0) + ppe_uniphy_reset(UNIPHY0_XPCS_RESET, true); + else if (uniphy_index == 1) + ppe_uniphy_reset(UNIPHY1_XPCS_RESET, true); + else + ppe_uniphy_reset(UNIPHY2_XPCS_RESET, true); + mdelay(100); + + writel(0x120, PPE_UNIPHY_BASE + (uniphy_index * PPE_UNIPHY_REG_INC) + + PPE_UNIPHY_MODE_CONTROL); + if (uniphy_index == 0) { + ppe_uniphy_reset(UNIPHY0_SOFT_RESET, true); + mdelay(100); + ppe_uniphy_reset(UNIPHY0_SOFT_RESET, false); + } else if (uniphy_index == 1) { + ppe_uniphy_reset(UNIPHY1_SOFT_RESET, true); + mdelay(100); + ppe_uniphy_reset(UNIPHY1_SOFT_RESET, false); + } else { + ppe_uniphy_reset(UNIPHY2_SOFT_RESET, true); + mdelay(100); + ppe_uniphy_reset(UNIPHY2_SOFT_RESET, false); + } + mdelay(100); +} + +static void ppe_uniphy_sgmii_mode_set(uint32_t uniphy_index, uint32_t mode) +{ + writel(UNIPHY_MISC2_REG_SGMII_MODE, PPE_UNIPHY_BASE + + (uniphy_index * PPE_UNIPHY_REG_INC) + UNIPHY_MISC2_REG_OFFSET); + + writel(UNIPHY_PLL_RESET_REG_VALUE, PPE_UNIPHY_BASE + + (uniphy_index * PPE_UNIPHY_REG_INC) + UNIPHY_PLL_RESET_REG_OFFSET); + mdelay(500); + writel(UNIPHY_PLL_RESET_REG_DEFAULT_VALUE, PPE_UNIPHY_BASE + + (uniphy_index * PPE_UNIPHY_REG_INC) + UNIPHY_PLL_RESET_REG_OFFSET); + mdelay(500); + if (uniphy_index == 0) + ppe_uniphy_reset(UNIPHY0_XPCS_RESET, true); + else if (uniphy_index == 1) + ppe_uniphy_reset(UNIPHY1_XPCS_RESET, true); + else + ppe_uniphy_reset(UNIPHY2_XPCS_RESET, true); + mdelay(100); + + if (uniphy_index == 1) { + writel(0x0, NSS_CC_UNIPHY_PORT1_RX_CBCR + (PORT5 - 1) * 0x8); + writel(0x0, NSS_CC_UNIPHY_PORT1_RX_CBCR + 0x4 + (PORT5 - 1) * 0x8); + writel(0x0, NSS_CC_PORT1_RX_CBCR + (PORT5 - 1) * 0x8); + writel(0x0, NSS_CC_PORT1_RX_CBCR + 0x4 + (PORT5 - 1) * 0x8); + } else if (uniphy_index == 2) { + writel(0x0, NSS_CC_UNIPHY_PORT1_RX_CBCR + (PORT6 - 1) * 0x8); + writel(0x0, NSS_CC_UNIPHY_PORT1_RX_CBCR + 0x4 + (PORT6 - 1) * 8); + writel(0x0, NSS_CC_PORT1_RX_CBCR + (PORT6 - 1) * 0x8); + writel(0x0, NSS_CC_PORT1_RX_CBCR + 0x4 + (PORT6 - 1) * 0x8); + } + + switch (mode) { + case EPORT_WRAPPER_SGMII_FIBER: + writel(0x400, PPE_UNIPHY_BASE + (uniphy_index * PPE_UNIPHY_REG_INC) + + PPE_UNIPHY_MODE_CONTROL); + break; + + case EPORT_WRAPPER_SGMII0_RGMII4: + case EPORT_WRAPPER_SGMII1_RGMII4: + case EPORT_WRAPPER_SGMII4_RGMII4: + writel(0x420, PPE_UNIPHY_BASE + (uniphy_index * PPE_UNIPHY_REG_INC) + + PPE_UNIPHY_MODE_CONTROL); + break; + + case EPORT_WRAPPER_SGMII_PLUS: + writel(0x820, PPE_UNIPHY_BASE + (uniphy_index * PPE_UNIPHY_REG_INC) + + PPE_UNIPHY_MODE_CONTROL); + break; + + default: + printf("SGMII Config. wrongly"); + break; + } + + if (uniphy_index == 0) { + ppe_uniphy_reset(UNIPHY0_SOFT_RESET, true); + mdelay(100); + ppe_uniphy_reset(UNIPHY0_SOFT_RESET, false); + } else if (uniphy_index == 1) { + ppe_uniphy_reset(UNIPHY1_SOFT_RESET, true); + mdelay(100); + ppe_uniphy_reset(UNIPHY1_SOFT_RESET, false); + } else { + ppe_uniphy_reset(UNIPHY2_SOFT_RESET, true); + mdelay(100); + ppe_uniphy_reset(UNIPHY2_SOFT_RESET, false); + } + mdelay(100); + + if (uniphy_index == 1) { + writel(0x1, NSS_CC_UNIPHY_PORT1_RX_CBCR + (PORT5 - 1) * 0x8); + writel(0x1, NSS_CC_UNIPHY_PORT1_RX_CBCR + 0x4 + (PORT5 - 1) * 0x8); + writel(0x1, NSS_CC_PORT1_RX_CBCR + (PORT5 - 1) * 0x8); + writel(0x1, NSS_CC_PORT1_RX_CBCR + 0x4 + (PORT5 - 1) * 0x8); + } else if (uniphy_index == 2) { + writel(0x1, NSS_CC_UNIPHY_PORT1_RX_CBCR + (PORT6 - 1) * 0x8); + writel(0x1, NSS_CC_UNIPHY_PORT1_RX_CBCR + 0x4 + (PORT6 - 1) * 8); + writel(0x1, NSS_CC_PORT1_RX_CBCR + (PORT6 - 1) * 0x8); + writel(0x1, NSS_CC_PORT1_RX_CBCR + 0x4 + (PORT6 - 1) * 0x8); + } + + ppe_uniphy_calibration(uniphy_index); +} + +static int ppe_uniphy_10g_r_linkup(uint32_t uniphy_index) +{ + uint32_t reg_value = 0; + uint32_t retries = 100, linkup = 0; + + while (linkup != UNIPHY_10GR_LINKUP) { + mdelay(1); + if (retries-- == 0) + return -1; + reg_value = csr1_read(uniphy_index, SR_XS_PCS_KR_STS1_ADDRESS); + linkup = (reg_value >> 12) & UNIPHY_10GR_LINKUP; + } + mdelay(10); + return 0; +} + +static void ppe_uniphy_10g_r_mode_set(uint32_t uniphy_index) +{ + if (uniphy_index == 0) + ppe_uniphy_reset(UNIPHY0_XPCS_RESET, true); + else if (uniphy_index == 1) + ppe_uniphy_reset(UNIPHY1_XPCS_RESET, true); + else + ppe_uniphy_reset(UNIPHY2_XPCS_RESET, true); + + writel(0x1021, PPE_UNIPHY_BASE + (uniphy_index * PPE_UNIPHY_REG_INC) + + PPE_UNIPHY_MODE_CONTROL); + writel(0x1C0, PPE_UNIPHY_BASE + (uniphy_index * PPE_UNIPHY_REG_INC) + + UNIPHY_INSTANCE_LINK_DETECT); + + if (uniphy_index == 0) { + ppe_uniphy_reset(UNIPHY0_SOFT_RESET, true); + mdelay(100); + ppe_uniphy_reset(UNIPHY0_SOFT_RESET, false); + } else if (uniphy_index == 1) { + ppe_uniphy_reset(UNIPHY1_SOFT_RESET, true); + mdelay(100); + ppe_uniphy_reset(UNIPHY1_SOFT_RESET, false); + } else { + ppe_uniphy_reset(UNIPHY2_SOFT_RESET, true); + mdelay(100); + ppe_uniphy_reset(UNIPHY2_SOFT_RESET, false); + } + mdelay(100); + + ppe_uniphy_calibration(uniphy_index); + + if (uniphy_index == 0) + ppe_uniphy_reset(UNIPHY0_XPCS_RESET, false); + else if (uniphy_index == 1) + ppe_uniphy_reset(UNIPHY1_XPCS_RESET, false); + else + ppe_uniphy_reset(UNIPHY2_XPCS_RESET, false); +} + + +static void ppe_uniphy_usxgmii_mode_set(uint32_t uniphy_index) +{ + uint32_t reg_value = 0; + + writel(UNIPHY_MISC2_REG_VALUE, PPE_UNIPHY_BASE + + (uniphy_index * PPE_UNIPHY_REG_INC) + UNIPHY_MISC2_REG_OFFSET); + writel(UNIPHY_PLL_RESET_REG_VALUE, PPE_UNIPHY_BASE + + (uniphy_index * PPE_UNIPHY_REG_INC) + UNIPHY_PLL_RESET_REG_OFFSET); + mdelay(500); + writel(UNIPHY_PLL_RESET_REG_DEFAULT_VALUE, PPE_UNIPHY_BASE + + (uniphy_index * PPE_UNIPHY_REG_INC) + UNIPHY_PLL_RESET_REG_OFFSET); + mdelay(500); + + if (uniphy_index == 0) + ppe_uniphy_reset(UNIPHY0_XPCS_RESET, true); + else if (uniphy_index == 1) + ppe_uniphy_reset(UNIPHY1_XPCS_RESET, true); + else + ppe_uniphy_reset(UNIPHY2_XPCS_RESET, true); + mdelay(100); + + writel(0x1021, PPE_UNIPHY_BASE + (uniphy_index * PPE_UNIPHY_REG_INC) + + PPE_UNIPHY_MODE_CONTROL); + + if (uniphy_index == 0) { + ppe_uniphy_reset(UNIPHY0_SOFT_RESET, true); + mdelay(100); + ppe_uniphy_reset(UNIPHY0_SOFT_RESET, false); + } else if (uniphy_index == 1) { + ppe_uniphy_reset(UNIPHY1_SOFT_RESET, true); + mdelay(100); + ppe_uniphy_reset(UNIPHY1_SOFT_RESET, false); + } else { + ppe_uniphy_reset(UNIPHY2_SOFT_RESET, true); + mdelay(100); + ppe_uniphy_reset(UNIPHY2_SOFT_RESET, false); + } + mdelay(100); + + ppe_uniphy_calibration(uniphy_index); + + if (uniphy_index == 0) + ppe_uniphy_reset(UNIPHY0_XPCS_RESET, false); + else if (uniphy_index == 1) + ppe_uniphy_reset(UNIPHY1_XPCS_RESET, false); + else + ppe_uniphy_reset(UNIPHY2_XPCS_RESET, false); + mdelay(100); + + ppe_uniphy_10g_r_linkup(uniphy_index); + reg_value = csr1_read(uniphy_index, VR_XS_PCS_DIG_CTRL1_ADDRESS); + reg_value |= USXG_EN; + csr1_write(uniphy_index, VR_XS_PCS_DIG_CTRL1_ADDRESS, reg_value); + reg_value = csr1_read(uniphy_index, VR_MII_AN_CTRL_ADDRESS); + reg_value |= MII_AN_INTR_EN; + reg_value |= MII_CTRL; + csr1_write(uniphy_index, VR_MII_AN_CTRL_ADDRESS, reg_value); + reg_value = csr1_read(uniphy_index, SR_MII_CTRL_ADDRESS); + reg_value |= AN_ENABLE; + reg_value &= ~SS5; + reg_value |= SS6 | SS13 | DUPLEX_MODE; + csr1_write(uniphy_index, SR_MII_CTRL_ADDRESS, reg_value); +} + +void ppe_uniphy_mode_set(uint32_t uniphy_index, uint32_t mode) +{ + if (!is_uniphy_enabled(uniphy_index)) { + printf("Uniphy %u is disabled\n", uniphy_index); + return; + } + + switch(mode) { + case EPORT_WRAPPER_PSGMII: + ppe_uniphy_psgmii_mode_set(uniphy_index); + break; + case EPORT_WRAPPER_QSGMII: + ppe_uniphy_qsgmii_mode_set(uniphy_index); + break; + case EPORT_WRAPPER_SGMII0_RGMII4: + case EPORT_WRAPPER_SGMII1_RGMII4: + case EPORT_WRAPPER_SGMII4_RGMII4: + case EPORT_WRAPPER_SGMII_PLUS: + case EPORT_WRAPPER_SGMII_FIBER: + ppe_uniphy_sgmii_mode_set(uniphy_index, mode); + break; + case EPORT_WRAPPER_USXGMII: + ppe_uniphy_usxgmii_mode_set(uniphy_index); + break; + case EPORT_WRAPPER_10GBASE_R: + ppe_uniphy_10g_r_mode_set(uniphy_index); + break; + default: + break; + } +} + +void ppe_uniphy_usxgmii_autoneg_completed(uint32_t uniphy_index) +{ + uint32_t autoneg_complete = 0, retries = 100; + uint32_t reg_value = 0; + + while (autoneg_complete != 0x1) { + mdelay(1); + if (retries-- == 0) + { + return; + } + reg_value = csr1_read(uniphy_index, VR_MII_AN_INTR_STS); + autoneg_complete = reg_value & 0x1; + } + reg_value &= ~CL37_ANCMPLT_INTR; + csr1_write(uniphy_index, VR_MII_AN_INTR_STS, reg_value); +} + +void ppe_uniphy_usxgmii_speed_set(uint32_t uniphy_index, int speed) +{ + uint32_t reg_value = 0; + + reg_value = csr1_read(uniphy_index, SR_MII_CTRL_ADDRESS); + reg_value |= DUPLEX_MODE; + + switch(speed) { + case 0: + reg_value &=~SS5; + reg_value &=~SS6; + reg_value &=~SS13; + break; + case 1: + reg_value &=~SS5; + reg_value &=~SS6; + reg_value |=SS13; + break; + case 2: + reg_value &=~SS5; + reg_value |=SS6; + reg_value &=~SS13; + break; + case 3: + reg_value &=~SS5; + reg_value |=SS6; + reg_value |=SS13; + break; + case 4: + reg_value |=SS5; + reg_value &=~SS6; + reg_value &=~SS13; + break; + case 5: + reg_value |=SS5; + reg_value &=~SS6; + reg_value |=SS13; + break; + } + csr1_write(uniphy_index, SR_MII_CTRL_ADDRESS, reg_value); + +} + +void ppe_uniphy_usxgmii_duplex_set(uint32_t uniphy_index, int duplex) +{ + uint32_t reg_value = 0; + + reg_value = csr1_read(uniphy_index, SR_MII_CTRL_ADDRESS); + + if (duplex & 0x1) + reg_value |= DUPLEX_MODE; + else + reg_value &= ~DUPLEX_MODE; + + csr1_write(uniphy_index, SR_MII_CTRL_ADDRESS, reg_value); +} + +void ppe_uniphy_usxgmii_port_reset(uint32_t uniphy_index) +{ + uint32_t reg_value = 0; + + reg_value = csr1_read(uniphy_index, VR_XS_PCS_DIG_CTRL1_ADDRESS); + reg_value |= USRA_RST; + csr1_write(uniphy_index, VR_XS_PCS_DIG_CTRL1_ADDRESS, reg_value); +} diff --git a/drivers/net/devsoc/devsoc_uniphy.h b/drivers/net/devsoc/devsoc_uniphy.h new file mode 100644 index 0000000000..0857f03a51 --- /dev/null +++ b/drivers/net/devsoc/devsoc_uniphy.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2017-2019, 2021, The Linux Foundation. All rights reserved. + * + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#define PPE_UNIPHY_INSTANCE0 0 +#define PPE_UNIPHY_INSTANCE1 1 + +#define GCC_UNIPHY_REG_INC 0x10 + +#define PPE_UNIPHY_OFFSET_CALIB_4 0x1E0 +#define UNIPHY_CALIBRATION_DONE 0x1 + +#define PPE_UNIPHY_BASE 0X07A00000 +#define PPE_UNIPHY_REG_INC 0x10000 +#define PPE_UNIPHY_MODE_CONTROL 0x46C +#define UNIPHY_XPCS_MODE (1 << 12) +#define UNIPHY_SG_PLUS_MODE (1 << 11) +#define UNIPHY_SG_MODE (1 << 10) +#define UNIPHY_CH0_PSGMII_QSGMII (1 << 9) +#define UNIPHY_CH0_QSGMII_SGMII (1 << 8) +#define UNIPHY_CH4_CH1_0_SGMII (1 << 2) +#define UNIPHY_CH1_CH0_SGMII (1 << 1) +#define UNIPHY_CH0_ATHR_CSCO_MODE_25M (1 << 0) + +#define UNIPHY_INSTANCE_LINK_DETECT 0x570 + +#define UNIPHY_MISC2_REG_OFFSET 0x218 +#define UNIPHY_MISC2_REG_SGMII_MODE 0x30 +#define UNIPHY_MISC2_REG_SGMII_PLUS_MODE 0x50 + +#define UNIPHY_MISC2_REG_VALUE 0x70 + +#define UNIPHY_PLL_RESET_REG_OFFSET 0x780 +#define UNIPHY_PLL_RESET_REG_VALUE 0x02bf +#define UNIPHY_PLL_RESET_REG_DEFAULT_VALUE 0x02ff + +#define SR_XS_PCS_KR_STS1_ADDRESS 0x30020 +#define UNIPHY_10GR_LINKUP 0x1 + +#define VR_XS_PCS_DIG_CTRL1_ADDRESS 0x38000 +#define USXG_EN (1 << 9) +#define USRA_RST (1 << 10) + +#define VR_MII_AN_CTRL_ADDRESS 0x1f8001 +#define MII_AN_INTR_EN (1 << 0) +#define MII_CTRL (1 << 8) + +#define SR_MII_CTRL_ADDRESS 0x1f0000 +#define AN_ENABLE (1 << 12) +#define SS5 (1 << 5) +#define SS6 (1 << 6) +#define SS13 (1 << 13) +#define DUPLEX_MODE (1 << 8) + +#define VR_MII_AN_INTR_STS 0x1f8002 +#define CL37_ANCMPLT_INTR (1 << 0) + +enum uniphy_reset_type { + UNIPHY0_SOFT_RESET = 0, + UNIPHY0_XPCS_RESET, + UNIPHY1_SOFT_RESET, + UNIPHY1_XPCS_RESET, + UNIPHY2_SOFT_RESET, + UNIPHY2_XPCS_RESET, + UNIPHY_RST_MAX +}; + +void ppe_uniphy_mode_set(uint32_t uniphy_index, uint32_t mode); +void ppe_uniphy_usxgmii_port_reset(uint32_t uniphy_index); +void ppe_uniphy_usxgmii_duplex_set(uint32_t uniphy_index, int duplex); +void ppe_uniphy_usxgmii_speed_set(uint32_t uniphy_index, int speed); +void ppe_uniphy_usxgmii_autoneg_completed(uint32_t uniphy_index); diff --git a/drivers/net/ipq_common/ipq_phy.h b/drivers/net/ipq_common/ipq_phy.h index b393fcebdf..b4160e84f0 100755 --- a/drivers/net/ipq_common/ipq_phy.h +++ b/drivers/net/ipq_common/ipq_phy.h @@ -20,6 +20,7 @@ #define PHY_MAX 6 #define IPQ9574_PHY_MAX 6 #define IPQ6018_PHY_MAX 5 +#define DEVSOC_PHY_MAX 2 #define MDIO_CTRL_0_REG 0x00090040 #define MDIO_CTRL_0_DIV(x) (x << 0) #define MDIO_CTRL_0_MODE (1 << 8) diff --git a/include/configs/devsoc.h b/include/configs/devsoc.h index 2eb3fbabce..5443aea3da 100644 --- a/include/configs/devsoc.h +++ b/include/configs/devsoc.h @@ -21,11 +21,14 @@ #endif #define CONFIG_DEVSOC +#define CONFIG_DEVSOC_RUMI #undef CONFIG_QCA_DISABLE_SCM #define CONFIG_SPI_FLASH_CYPRESS #define CONFIG_SYS_NO_FLASH #define CONFIG_IPQ_NO_RELOC +#define CONFIG_SYS_NONCACHED_MEMORY (1 << 20) + #define CONFIG_SYS_VSNPRINTF /* @@ -191,6 +194,27 @@ extern loff_t board_env_size; /* Mii command support */ #define CONFIG_CMD_MII +/* +* Ethernet Configs +*/ +#define CONFIG_DEVSOC_EDMA +#ifdef CONFIG_DEVSOC_EDMA +#define CONFIG_DEVSOC_BRIDGED_MODE 1 +#define CONFIG_NET_RETRY_COUNT 5 +#define CONFIG_SYS_RX_ETH_BUFFER 128 +#define CONFIG_TFTP_BLOCKSIZE 1280 +#define CONFIG_CMD_PING +#define CONFIG_CMD_DHCP +#define CONFIG_MII +#define CONFIG_CMD_MII +#define CONFIG_IPADDR 192.168.10.10 +#define CONFIG_NETMASK 255.255.255.0 +#define CONFIG_SERVERIP 192.168.10.1 +#define CONFIG_CMD_TFTPPUT +#define CONFIG_IPQ_MDIO 1 +#define CONFIG_IPQ_ETH_INIT_DEFER +#endif + /* L1 cache line size is 64 bytes, L2 cache line size is 128 bytes * Cache flush and invalidation based on L1 cache, so the cache line * size is configured to 64 */ diff --git a/include/dt-bindings/qcom/eth-devsoc.h b/include/dt-bindings/qcom/eth-devsoc.h new file mode 100644 index 0000000000..50f59afcef --- /dev/null +++ b/include/dt-bindings/qcom/eth-devsoc.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved. + * + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __DT_BINDINGS_DEVSOC_ETH_H__ +#define __DT_BINDINGS_DEVSOC_ETH_H__ + +/* ESS Switch Mac Modes */ +#define PORT_WRAPPER_PSGMII 0 +#define PORT_WRAPPER_PSGMII_RGMII5 1 +#define PORT_WRAPPER_SGMII0_RGMII5 2 +#define PORT_WRAPPER_SGMII1_RGMII5 3 +#define PORT_WRAPPER_PSGMII_RMII0 4 +#define PORT_WRAPPER_PSGMII_RMII1 5 +#define PORT_WRAPPER_PSGMII_RMII0_RMII1 6 +#define PORT_WRAPPER_PSGMII_RGMII4 7 +#define PORT_WRAPPER_SGMII0_RGMII4 8 +#define PORT_WRAPPER_SGMII1_RGMII4 9 +#define PORT_WRAPPER_SGMII4_RGMII4 10 +#define PORT_WRAPPER_QSGMII 11 +#define PORT_WRAPPER_SGMII_PLUS 12 +#define PORT_WRAPPER_USXGMII 13 +#define PORT_WRAPPER_10GBASE_R 14 +#define PORT_WRAPPER_SGMII_CHANNEL0 15 +#define PORT_WRAPPER_SGMII_CHANNEL1 16 +#define PORT_WRAPPER_SGMII_CHANNEL4 17 +#define PORT_WRAPPER_RGMII 18 +#define PORT_WRAPPER_PSGMII_FIBER 19 +#define PORT_WRAPPER_SGMII_FIBER 20 +#define PORT_WRAPPER_MAX 0xFF + +/* ETH PHY Types */ +#define MALIBU_PHY_TYPE 0x1 +#define QCA8081_PHY_TYPE 0x2 +#define AQ_PHY_TYPE 0x3 +#define QCA8033_PHY_TYPE 0x4 +#define SFP_PHY_TYPE 0x5 +#endif +