From 3a42e3475ff8d43313749879542e432f39c6c5d6 Mon Sep 17 00:00:00 2001 From: Ram Kumar D Date: Wed, 22 Jun 2022 16:12:49 +0530 Subject: [PATCH 1/4] drivers: net: devsoc: add aquantia PHY support Change-Id: I4671838eae0d0d7d47bb15a31235b686dc34dccb Signed-off-by: Ram Kumar D --- configs/devsoc_defconfig | 1 + drivers/net/Kconfig | 6 + drivers/net/Makefile | 1 + drivers/net/devsoc/devsoc_edma.c | 2 +- drivers/net/ipq_common/ipq_aquantia_phy.c | 597 ++++++++++++++++++++++ drivers/net/ipq_common/ipq_aquantia_phy.h | 50 ++ 6 files changed, 656 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ipq_common/ipq_aquantia_phy.c create mode 100644 drivers/net/ipq_common/ipq_aquantia_phy.h diff --git a/configs/devsoc_defconfig b/configs/devsoc_defconfig index 033dcc4e85..0fbc223f24 100644 --- a/configs/devsoc_defconfig +++ b/configs/devsoc_defconfig @@ -100,6 +100,7 @@ CONFIG_CMD_SETEXPR=y # # Network PHY # +CONFIG_IPQ_QCA_AQUANTIA_PHY=y CONFIG_QCA8081_PHY=y CONFIG_CMD_NET=y diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index de54ca8014..6ab67a845e 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -110,3 +110,9 @@ config ZYNQ_GEM This MAC is present in Xilinx Zynq and ZynqMP SoCs. endif # NETDEVICES + +config IPQ_QCA_AQUANTIA_PHY + bool "Aquantia PHY support" + help + Enable Aquantia PHY support. + diff --git a/drivers/net/Makefile b/drivers/net/Makefile index da4cd26730..844462a591 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -109,6 +109,7 @@ obj-$(CONFIG_QCA8084_PHY) += ipq_common/ipq_qca8084_interface_ctrl.o obj-$(CONFIG_IPQ9574_QCA8075_PHY) += ipq9574/ipq9574_qca8075.o obj-$(CONFIG_QCA8033_PHY) += ipq_common/ipq_qca8033.o obj-$(CONFIG_QCA8081_PHY) += ipq_common/ipq_qca8081.o +obj-$(CONFIG_IPQ_QCA_AQUANTIA_PHY) += ipq_common/ipq_aquantia_phy.o obj-$(CONFIG_QCA_AQUANTIA_PHY) += ipq807x/ipq807x_aquantia_phy.o obj-$(CONFIG_IPQ6018_QCA_AQUANTIA_PHY) += ipq6018/ipq6018_aquantia_phy.o obj-$(CONFIG_IPQ9574_QCA_AQUANTIA_PHY) += ipq9574/ipq9574_aquantia_phy.o diff --git a/drivers/net/devsoc/devsoc_edma.c b/drivers/net/devsoc/devsoc_edma.c index 0a5ff166d6..e6f47def69 100644 --- a/drivers/net/devsoc/devsoc_edma.c +++ b/drivers/net/devsoc/devsoc_edma.c @@ -1826,7 +1826,7 @@ int devsoc_edma_init(void *edma_board_cfg) ipq_qca8081_phy_init(&devsoc_edma_dev[i]->ops[phy_id], phy_addr); break; #endif -#ifdef CONFIG_DEVSOC_QCA_AQUANTIA_PHY +#ifdef CONFIG_IPQ_QCA_AQUANTIA_PHY case AQUANTIA_PHY_107: case AQUANTIA_PHY_109: case AQUANTIA_PHY_111: diff --git a/drivers/net/ipq_common/ipq_aquantia_phy.c b/drivers/net/ipq_common/ipq_aquantia_phy.c new file mode 100644 index 0000000000..4645a1bf67 --- /dev/null +++ b/drivers/net/ipq_common/ipq_aquantia_phy.c @@ -0,0 +1,597 @@ +/* + * 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 "ipq_phy.h" +#include "ipq_aquantia_phy.h" +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; +typedef struct { + unsigned int image_type; + unsigned int header_vsn_num; + unsigned int image_src; + unsigned char *image_dest_ptr; + unsigned int image_size; + unsigned int code_size; + unsigned char *signature_ptr; + unsigned int signature_size; + unsigned char *cert_chain_ptr; + unsigned int cert_chain_size; +} mbn_header_t; + +mbn_header_t *fwimg_header; +static int debug = 0; + +#ifdef CONFIG_QCA_MMC +extern qca_mmc mmc_host; +static qca_mmc *host = &mmc_host; +#endif + +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 int ipq_sw_mdio_init(const char *); +extern void devsoc_eth_initialize(void); +static int program_ethphy_fw(unsigned int phy_addr, + uint32_t load_addr,uint32_t file_size ); +static qca_smem_flash_info_t *sfi = &qca_smem_flash_info; + +u16 aq_phy_reg_write(u32 dev_id, u32 phy_id, + u32 reg_id, u16 reg_val) +{ + ipq_mdio_write(phy_id, reg_id, reg_val); + return 0; +} + +u16 aq_phy_reg_read(u32 dev_id, u32 phy_id, u32 reg_id) +{ + return ipq_mdio_read(phy_id, reg_id, NULL); +} + +u8 aq_phy_get_link_status(u32 dev_id, u32 phy_id) +{ + u16 phy_data; + uint32_t reg; + + reg = AQ_PHY_AUTO_STATUS_REG | AQUANTIA_MII_ADDR_C45; + phy_data = aq_phy_reg_read(dev_id, phy_id, reg); + phy_data = aq_phy_reg_read(dev_id, phy_id, reg); + + if (((phy_data >> 2) & 0x1) & PORT_LINK_UP) + return 0; + + return 1; +} + +u32 aq_phy_get_duplex(u32 dev_id, u32 phy_id, fal_port_duplex_t *duplex) +{ + u16 phy_data; + uint32_t reg; + + reg = AQ_PHY_LINK_STATUS_REG | AQUANTIA_MII_ADDR_C45; + phy_data = aq_phy_reg_read(dev_id, phy_id, reg); + + /* + * Read duplex + */ + phy_data = phy_data & 0x1; + if (phy_data & 0x1) + *duplex = FAL_FULL_DUPLEX; + else + *duplex = FAL_HALF_DUPLEX; + + return 0; +} + +u32 aq_phy_get_speed(u32 dev_id, u32 phy_id, fal_port_speed_t *speed) +{ + u16 phy_data; + uint32_t reg; + + reg = AQ_PHY_LINK_STATUS_REG | AQUANTIA_MII_ADDR_C45; + phy_data = aq_phy_reg_read(dev_id, phy_id, reg); + + switch ((phy_data >> 1) & 0x7) { + case SPEED_10G: + *speed = FAL_SPEED_10000; + break; + case SPEED_5G: + *speed = FAL_SPEED_5000; + break; + case SPEED_2_5G: + *speed = FAL_SPEED_2500; + break; + case SPEED_1000MBS: + *speed = FAL_SPEED_1000; + break; + case SPEED_100MBS: + *speed = FAL_SPEED_100; + break; + case SPEED_10MBS: + *speed = FAL_SPEED_10; + break; + default: + return -EINVAL; + } + return 0; +} + +void aquantia_phy_restart_autoneg(u32 phy_id) +{ + u16 phy_data; + + phy_data = aq_phy_reg_read(0x0, phy_id, AQUANTIA_REG_ADDRESS(AQUANTIA_MMD_PHY_XS_REGISTERS, + AQUANTIA_PHY_XS_USX_TRANSMIT)); + if (!(phy_data & AQUANTIA_PHY_USX_AUTONEG_ENABLE)) + aq_phy_reg_write(0x0, phy_id,AQUANTIA_REG_ADDRESS( + AQUANTIA_MMD_PHY_XS_REGISTERS, + AQUANTIA_PHY_XS_USX_TRANSMIT), + phy_data | AQUANTIA_PHY_USX_AUTONEG_ENABLE); + + phy_data = aq_phy_reg_read(0x0, phy_id, AQUANTIA_REG_ADDRESS(AQUANTIA_MMD_AUTONEG, + AQUANTIA_AUTONEG_STANDARD_CONTROL1)); + + phy_data |= AQUANTIA_CTRL_AUTONEGOTIATION_ENABLE; + aq_phy_reg_write(0x0, phy_id, AQUANTIA_REG_ADDRESS(AQUANTIA_MMD_AUTONEG, + AQUANTIA_AUTONEG_STANDARD_CONTROL1), + phy_data | AQUANTIA_CTRL_RESTART_AUTONEGOTIATION); +} + +int ipq_qca_aquantia_phy_init(struct phy_ops **ops, u32 phy_id) +{ + u16 phy_data; + struct phy_ops *aq_phy_ops; + aq_phy_ops = (struct phy_ops *)malloc(sizeof(struct phy_ops)); + if (!aq_phy_ops) + return -ENOMEM; + aq_phy_ops->phy_get_link_status = aq_phy_get_link_status; + aq_phy_ops->phy_get_speed = aq_phy_get_speed; + aq_phy_ops->phy_get_duplex = aq_phy_get_duplex; + *ops = aq_phy_ops; + + phy_data = aq_phy_reg_read(0x0, phy_id, AQUANTIA_REG_ADDRESS(AQUANTIA_MMD_PHY_XS_REGISTERS, + AQUANTIA_PHY_XS_USX_TRANSMIT)); + + phy_data = aq_phy_reg_read(0x0, phy_id, AQUANTIA_REG_ADDRESS(1, QCA_PHY_ID1)); + printf ("PHY ID1: 0x%x\n", phy_data); + phy_data = aq_phy_reg_read(0x0, phy_id, AQUANTIA_REG_ADDRESS(1, QCA_PHY_ID2)); + printf ("PHY ID2: 0x%x\n", phy_data); + phy_data = aq_phy_reg_read(0x0, phy_id, AQUANTIA_REG_ADDRESS(AQUANTIA_MMD_PHY_XS_REGISTERS, + AQUANTIA_PHY_XS_USX_TRANSMIT)); + phy_data |= AQUANTIA_PHY_USX_AUTONEG_ENABLE; + aq_phy_reg_write(0x0, phy_id, AQUANTIA_REG_ADDRESS(AQUANTIA_MMD_PHY_XS_REGISTERS, + AQUANTIA_PHY_XS_USX_TRANSMIT), phy_data); + phy_data = aq_phy_reg_read(0x0, phy_id, AQUANTIA_REG_ADDRESS(AQUANTIA_MMD_AUTONEG, + AQUANTIA_AUTONEG_TRANSMIT_VENDOR_INTR_MASK)); + phy_data |= AQUANTIA_INTR_LINK_STATUS_CHANGE; + aq_phy_reg_write(0x0, phy_id, AQUANTIA_REG_ADDRESS(AQUANTIA_MMD_AUTONEG, + AQUANTIA_AUTONEG_TRANSMIT_VENDOR_INTR_MASK), phy_data); + phy_data = aq_phy_reg_read(0x0, phy_id, AQUANTIA_REG_ADDRESS(AQUANTIA_MMD_GLOABLE_REGISTERS, + AQUANTIA_GLOBAL_INTR_STANDARD_MASK)); + phy_data |= AQUANTIA_ALL_VENDOR_ALARMS_INTERRUPT_MASK; + aq_phy_reg_write(0x0, phy_id, AQUANTIA_REG_ADDRESS(AQUANTIA_MMD_GLOABLE_REGISTERS, + AQUANTIA_GLOBAL_INTR_STANDARD_MASK), phy_data); + phy_data = aq_phy_reg_read(0x0, phy_id, AQUANTIA_REG_ADDRESS(AQUANTIA_MMD_GLOABLE_REGISTERS, + AQUANTIA_GLOBAL_INTR_VENDOR_MASK)); + phy_data |= AQUANTIA_AUTO_AND_ALARMS_INTR_MASK; + aq_phy_reg_write(0x0, phy_id, AQUANTIA_REG_ADDRESS(AQUANTIA_MMD_GLOABLE_REGISTERS, + AQUANTIA_GLOBAL_INTR_VENDOR_MASK), phy_data); + + phy_data = aq_phy_reg_read(0x0, phy_id, AQUANTIA_REG_ADDRESS(AQUANTIA_MMD_PHY_XS_REGISTERS, + AQUANTIA_PHY_XS_USX_TRANSMIT)); + return 0; +} + +static int do_aq_phy_restart(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + unsigned int phy_addr = AQU_PHY_ADDR; + if (argc > 2) + return CMD_RET_USAGE; + + if (argc == 2) + phy_addr = simple_strtoul(argv[1], NULL, 16); + + aquantia_phy_restart_autoneg(phy_addr); + return 0; +} + +int ipq_board_fw_download(unsigned int phy_addr) +{ + char runcmd[256]; + int ret,i=0; + uint32_t start; /* block number */ + uint32_t size; /* no. of blocks */ + qca_part_entry_t ethphyfw; + unsigned int *ethphyfw_load_addr = NULL; + struct { char *name; qca_part_entry_t *part; } entries[] = { + { "0:ETHPHYFW", ðphyfw }, + }; +#ifdef CONFIG_QCA_MMC + block_dev_desc_t *blk_dev; + disk_partition_t disk_info; +#endif + /* check the smem info to see which flash used for booting */ + if (sfi->flash_type == SMEM_BOOT_SPI_FLASH) { + if (debug) { + printf("Using nor device \n"); + } + } else if (sfi->flash_type == SMEM_BOOT_NAND_FLASH) { + if (debug) { + printf("Using nand device 0\n"); + } + } else if (sfi->flash_type == SMEM_BOOT_MMC_FLASH) { + if (debug) { + printf("Using MMC device\n"); + } + } else if (sfi->flash_type == SMEM_BOOT_QSPI_NAND_FLASH) { + if (debug) { + printf("Using qspi nand device 0\n"); + } + } else { + printf("Unsupported BOOT flash type\n"); + return -1; + } + + ret = smem_getpart(entries[i].name, &start, &size); + if (ret < 0) { + debug("cdp: get part failed for %s\n", entries[i].name); + } else { + qca_set_part_entry(entries[i].name, sfi, entries[i].part, start, size); + } + + if ((sfi->flash_type == SMEM_BOOT_NAND_FLASH) || + (sfi->flash_type == SMEM_BOOT_QSPI_NAND_FLASH) || + (sfi->flash_type == SMEM_BOOT_SPI_FLASH)) { + ethphyfw_load_addr = (uint *)malloc(AQ_ETHPHYFW_IMAGE_SIZE); + /* We only need memory equivalent to max size ETHPHYFW + * which is currently assumed as 512 KB. + */ + if (ethphyfw_load_addr == NULL) { + printf("ETHPHYFW Loading failed, size = %llu\n", + ethphyfw.size); + return -1; + } else { + memset(ethphyfw_load_addr, 0, AQ_ETHPHYFW_IMAGE_SIZE); + } + } + + if ((sfi->flash_type == SMEM_BOOT_NAND_FLASH) || + (sfi->flash_type == SMEM_BOOT_QSPI_NAND_FLASH)) { + /* + * Kernel is in a separate partition + */ + snprintf(runcmd, sizeof(runcmd), + /* NOR is treated as psuedo NAND */ + "nand read 0x%p 0x%llx 0x%llx && ", + ethphyfw_load_addr, ethphyfw.offset, (long long unsigned int) AQ_ETHPHYFW_IMAGE_SIZE); + + if (debug) + printf("%s", runcmd); + + if (run_command(runcmd, 0) != CMD_RET_SUCCESS) { + free(ethphyfw_load_addr); + return CMD_RET_FAILURE; + } + } else if (sfi->flash_type == SMEM_BOOT_SPI_FLASH) { + snprintf(runcmd, sizeof(runcmd), + "sf probe && " "sf read 0x%p 0x%llx 0x%llx && ", + ethphyfw_load_addr, ethphyfw.offset, (long long unsigned int) AQ_ETHPHYFW_IMAGE_SIZE); + + if (debug) + printf("%s", runcmd); + + if (run_command(runcmd, 0) != CMD_RET_SUCCESS) { + free(ethphyfw_load_addr); + return CMD_RET_FAILURE; + } +#ifdef CONFIG_QCA_MMC + } else if (sfi->flash_type == SMEM_BOOT_MMC_FLASH ) { + blk_dev = mmc_get_dev(host->dev_num); + ret = get_partition_info_efi_by_name(blk_dev, + "0:ETHPHYFW", &disk_info); + + ethphyfw_load_addr = (uint *)malloc(((uint)disk_info.size) * + ((uint)disk_info.blksz)); + if (ethphyfw_load_addr == NULL) { + printf("ETHPHYFW Loading failed, size = %lu\n", + ((long unsigned int)(uint)disk_info.size) * ((uint)disk_info.blksz)); + return -1; + } else { + memset(ethphyfw_load_addr, 0, + (((uint)disk_info.size) * + ((uint)disk_info.blksz))); + } + + if (ret == 0) { + snprintf(runcmd, sizeof(runcmd), + "mmc read 0x%p 0x%X 0x%X", + ethphyfw_load_addr, + (uint)disk_info.start, (uint)disk_info.size); + + if (run_command(runcmd, 0) != CMD_RET_SUCCESS) { + free(ethphyfw_load_addr); + return CMD_RET_FAILURE; + } + } +#endif + } + + fwimg_header = (mbn_header_t *)(ethphyfw_load_addr); + + if (fwimg_header->image_type == 0x13 && + fwimg_header->header_vsn_num == 0x3) { + program_ethphy_fw(phy_addr, + (uint32_t)(((uint32_t)ethphyfw_load_addr) + + sizeof(mbn_header_t)), + (uint32_t)(fwimg_header->image_size)); + } else { + printf("bad magic on ETHPHYFW partition\n"); + free(ethphyfw_load_addr); + return -1; + } + free(ethphyfw_load_addr); + return 0; +} + + +#define AQ_PHY_IMAGE_HEADER_CONTENT_OFFSET_HHD 0x300 +static int program_ethphy_fw(unsigned int phy_addr, uint32_t load_addr, uint32_t file_size) +{ + int i; + uint8_t *buf; + uint16_t file_crc; + uint16_t computed_crc; + uint32_t reg1, reg2; + uint16_t recorded_ggp8_val; + uint16_t daisy_chain_dis; + uint32_t primary_header_ptr = 0x00000000; + uint32_t primary_iram_ptr = 0x00000000; + uint32_t primary_dram_ptr = 0x00000000; + uint32_t primary_iram_sz = 0x00000000; + uint32_t primary_dram_sz = 0x00000000; + uint32_t phy_img_hdr_off; + uint32_t byte_sz; + uint32_t dword_sz; + uint32_t byte_ptr; + uint16_t msw = 0; + uint16_t lsw = 0; + uint8_t msb1; + uint8_t msb2; + uint8_t lsb1; + uint8_t lsb2; + uint16_t mailbox_crc; + + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0x300), 0xdead); + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0x301), 0xbeaf); + reg1 = aq_phy_reg_read(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0x300)); + reg2 = aq_phy_reg_read(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0x301)); + + if(reg1 != 0xdead && reg2 != 0xbeaf) { + printf("PHY::Scratchpad Read/Write test fail\n"); + return 0; + } + buf = (uint8_t *)load_addr; + file_crc = buf[file_size - 2] << 8 | buf[file_size - 1]; + computed_crc = cyg_crc16(buf, file_size - 2); + + if (file_crc != computed_crc) { + printf("CRC check failed on phy fw file\n"); + return 0; + } else { + printf("CRC check good on phy fw file (0x%04X)\n",computed_crc); + } + + daisy_chain_dis = aq_phy_reg_read(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0xc452)); + if (!(daisy_chain_dis & 0x1)) + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0xc452), 0x1); + + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0xc471), 0x40); + recorded_ggp8_val = aq_phy_reg_read(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0xc447)); + if ((recorded_ggp8_val & 0x1f) != phy_addr) + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0xc447), phy_addr); + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0xc441), 0x4000); + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0xc001), 0x41); + primary_header_ptr = (((buf[0x9] & 0x0F) << 8) | buf[0x8]) << 12; + phy_img_hdr_off = AQ_PHY_IMAGE_HEADER_CONTENT_OFFSET_HHD; + primary_iram_ptr = (buf[primary_header_ptr + phy_img_hdr_off + 0x4 + 2] << 16) | + (buf[primary_header_ptr + phy_img_hdr_off + 0x4 + 1] << 8) | + buf[primary_header_ptr + phy_img_hdr_off + 0x4]; + primary_iram_sz = (buf[primary_header_ptr + phy_img_hdr_off + 0x7 + 2] << 16) | + (buf[primary_header_ptr + phy_img_hdr_off + 0x7 + 1] << 8) | + buf[primary_header_ptr + phy_img_hdr_off + 0x7]; + primary_dram_ptr = (buf[primary_header_ptr + phy_img_hdr_off + 0xA + 2] << 16) | + (buf[primary_header_ptr + phy_img_hdr_off + 0xA + 1] << 8) | + buf[primary_header_ptr + phy_img_hdr_off + 0xA]; + primary_dram_sz = (buf[primary_header_ptr + phy_img_hdr_off + 0xD + 2] << 16) | + (buf[primary_header_ptr + phy_img_hdr_off + 0xD + 1] << 8) | + buf[primary_header_ptr + phy_img_hdr_off + 0xD]; + primary_iram_ptr += primary_header_ptr; + primary_dram_ptr += primary_header_ptr; + + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0x200), 0x1000); + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0x200), 0x0); + computed_crc = 0; + printf("PHYFW:Loading IRAM..........."); + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0x202), 0x4000); + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0x203), 0x0); + byte_sz = primary_iram_sz; + dword_sz = byte_sz >> 2; + byte_ptr = primary_iram_ptr; + for (i = 0; i < dword_sz; i++) { + lsw = (buf[byte_ptr + 1] << 8) | buf[byte_ptr]; + byte_ptr += 2; + msw = (buf[byte_ptr + 1] << 8) | buf[byte_ptr]; + byte_ptr += 2; + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0x204), msw); + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0x205), lsw); + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0x200), 0xc000); + msb1 = msw >> 8; + msb2 = msw & 0xFF; + lsb1 = lsw >> 8; + lsb2 = lsw & 0xFF; + computed_crc = cyg_crc16_computed(&msb1, 0x1, computed_crc); + computed_crc = cyg_crc16_computed(&msb2, 0x1, computed_crc); + computed_crc = cyg_crc16_computed(&lsb1, 0x1, computed_crc); + computed_crc = cyg_crc16_computed(&lsb2, 0x1, computed_crc); + } + + switch (byte_sz & 0x3) { + case 0x1: + lsw = buf[byte_ptr++]; + msw = 0x0000; + break; + case 0x2: + lsw = (buf[byte_ptr + 1] << 8) | buf[byte_ptr]; + byte_ptr += 2; + msw = 0x0000; + break; + case 0x3: + lsw = (buf[byte_ptr + 1] << 8) | buf[byte_ptr]; + byte_ptr += 2; + msw = buf[byte_ptr++]; + break; + } + + if (byte_sz & 0x3) { + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0x204), msw); + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0x205), lsw); + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0x200), 0xc000); + msb1 = msw >> 8; + msb2 = msw & 0xFF; + lsb1 = lsw >> 8; + lsb2 = lsw & 0xFF; + computed_crc = cyg_crc16_computed(&msb1, 0x1, computed_crc); + computed_crc = cyg_crc16_computed(&msb2, 0x1, computed_crc); + computed_crc = cyg_crc16_computed(&lsb1, 0x1, computed_crc); + computed_crc = cyg_crc16_computed(&lsb2, 0x1, computed_crc); + } + printf("done.\n"); + printf("PHYFW:Loading DRAM.............."); + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0x202), 0x3ffe); + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0x203), 0x0); + byte_sz = primary_dram_sz; + dword_sz = byte_sz >> 2; + byte_ptr = primary_dram_ptr; + for (i = 0; i < dword_sz; i++) { + lsw = (buf[byte_ptr + 1] << 8) | buf[byte_ptr]; + byte_ptr += 2; + msw = (buf[byte_ptr + 1] << 8) | buf[byte_ptr]; + byte_ptr += 2; + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0x204), msw); + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0x205), lsw); + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0x200), 0xc000); + msb1 = msw >> 8; + msb2 = msw & 0xFF; + lsb1 = lsw >> 8; + lsb2 = lsw & 0xFF; + computed_crc = cyg_crc16_computed(&msb1, 0x1, computed_crc); + computed_crc = cyg_crc16_computed(&msb2, 0x1, computed_crc); + computed_crc = cyg_crc16_computed(&lsb1, 0x1, computed_crc); + computed_crc = cyg_crc16_computed(&lsb2, 0x1, computed_crc); + } + + switch (byte_sz & 0x3) { + case 0x1: + lsw = buf[byte_ptr++]; + msw = 0x0000; + break; + case 0x2: + lsw = (buf[byte_ptr + 1] << 8) | buf[byte_ptr]; + byte_ptr += 2; + msw = 0x0000; + break; + case 0x3: + lsw = (buf[byte_ptr + 1] << 8) | buf[byte_ptr]; + byte_ptr += 2; + msw = buf[byte_ptr++]; + break; + } + + if (byte_sz & 0x3) { + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0x204), msw); + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0x205), lsw); + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0x200), 0xc000); + msb1 = msw >> 8; + msb2 = msw & 0xFF; + lsb1 = lsw >> 8; + lsb2 = lsw & 0xFF; + computed_crc = cyg_crc16_computed(&msb1, 0x1, computed_crc); + computed_crc = cyg_crc16_computed(&msb2, 0x1, computed_crc); + computed_crc = cyg_crc16_computed(&lsb1, 0x1, computed_crc); + computed_crc = cyg_crc16_computed(&lsb2, 0x1, computed_crc); + } + printf("done.\n"); + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0xc441), 0x2010); + mailbox_crc = aq_phy_reg_read(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0x201)); + if (mailbox_crc != computed_crc) { + printf("phy fw image load CRC-16 (0x%X) does not match calculated CRC-16 (0x%X)\n", mailbox_crc, computed_crc); + return 0; + } else + printf("phy fw image load good CRC-16 matches (0x%X)\n", mailbox_crc); + + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0x0), 0x0); + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0xc001), 0x41); + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0xc001), 0x8041); + mdelay(100); + aq_phy_reg_write(0x0, phy_addr, AQUANTIA_REG_ADDRESS(0x1e, 0xc001), 0x40); + mdelay(100); + aquantia_phy_restart_autoneg(phy_addr); + return 0; +} + +static int do_load_fw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + unsigned int phy_addr = AQU_PHY_ADDR; + + if (argc > 2) + return CMD_RET_USAGE; + + if (argc == 2) + phy_addr = simple_strtoul(argv[1], NULL, 16); + + miiphy_init(); + devsoc_eth_initialize(); + ipq_sw_mdio_init("IPQ MDIO0"); + ipq_board_fw_download(phy_addr); + return 0; +} + +U_BOOT_CMD( + aq_load_fw, 5, 1, do_load_fw, + "LOAD aq-fw-binary", + "" +); + +U_BOOT_CMD( + aq_phy_restart, 5, 1, do_aq_phy_restart, + "Restart Aquantia phy", + "" +); diff --git a/drivers/net/ipq_common/ipq_aquantia_phy.h b/drivers/net/ipq_common/ipq_aquantia_phy.h new file mode 100644 index 0000000000..d7eec1e5c1 --- /dev/null +++ b/drivers/net/ipq_common/ipq_aquantia_phy.h @@ -0,0 +1,50 @@ +/* + * 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 AQ_ETHPHYFW_IMAGE_SIZE 0x80000 + +#define AQUANTIA_MII_ADDR_C45 (1<<30) +#define AQUANTIA_REG_ADDRESS(dev_ad, reg_num) (AQUANTIA_MII_ADDR_C45 |\ + ((dev_ad & 0x1f) << 16) | (reg_num & 0xFFFF)) + +#define AQUANTIA_MMD_PHY_XS_REGISTERS 4 +#define AQUANTIA_PHY_XS_USX_TRANSMIT 0xc441 +#define AQUANTIA_PHY_USX_AUTONEG_ENABLE 0x8 + +#define AQUANTIA_MMD_AUTONEG 0x7 +#define AQUANTIA_AUTONEG_TRANSMIT_VENDOR_INTR_MASK 0xD401 +#define AQUANTIA_INTR_LINK_STATUS_CHANGE 0x0001 + +#define AQUANTIA_MMD_GLOABLE_REGISTERS 0x1E +#define AQUANTIA_GLOBAL_INTR_STANDARD_MASK 0xff00 +#define AQUANTIA_ALL_VENDOR_ALARMS_INTERRUPT_MASK 0x0001 + +#define AQUANTIA_GLOBAL_INTR_VENDOR_MASK 0xff01 +#define AQUANTIA_AUTO_AND_ALARMS_INTR_MASK 0x1001 + +#define AQUANTIA_AUTONEG_STANDARD_CONTROL1 0 +#define AQUANTIA_CTRL_AUTONEGOTIATION_ENABLE 0x1000 +#define AQUANTIA_CTRL_RESTART_AUTONEGOTIATION 0x0200 + +#define AQ_PHY_AUTO_STATUS_REG 0x70001 + +#define AQ_PHY_LINK_STATUS_REG 0x7c800 +#define SPEED_5G 5 +#define SPEED_2_5G 4 +#define SPEED_10G 3 +#define SPEED_1000MBS 2 +#define SPEED_100MBS 1 +#define SPEED_10MBS 0 From 498754d0ebc6ae7a392311af529512f8a06a58eb Mon Sep 17 00:00:00 2001 From: Ram Kumar D Date: Thu, 23 Jun 2022 15:23:38 +0530 Subject: [PATCH 2/4] drivers: net: devsoc: Add support for QCA8084 switch mode Change-Id: Ibc6517c39f0f9a24e18e62a6810b529b2d60afcf Signed-off-by: Ram Kumar D --- board/devsoc/Kconfig | 7 ++ configs/devsoc_defconfig | 1 + drivers/net/devsoc/devsoc_edma.c | 174 +++++++++++++++++++------- drivers/net/devsoc/devsoc_ppe.h | 4 - drivers/net/devsoc/devsoc_uniphy.c | 32 ++++- drivers/net/devsoc/devsoc_uniphy.h | 6 + include/dt-bindings/qcom/eth-devsoc.h | 2 + 7 files changed, 174 insertions(+), 52 deletions(-) diff --git a/board/devsoc/Kconfig b/board/devsoc/Kconfig index 18a3c14417..331dbb2c51 100644 --- a/board/devsoc/Kconfig +++ b/board/devsoc/Kconfig @@ -41,4 +41,11 @@ config IPQ_TINY_SPI_NOR config ART_COMPRESSED bool "Enable uncompress support" + +config QCA8081_PHY + bool "Enable QCA8081 PHY support" + +config QCA8084_PHY + depends on QCA8081_PHY + bool "Enable QCA8084 PHY support" endif diff --git a/configs/devsoc_defconfig b/configs/devsoc_defconfig index 0fbc223f24..5a4f9c41e9 100644 --- a/configs/devsoc_defconfig +++ b/configs/devsoc_defconfig @@ -102,6 +102,7 @@ CONFIG_CMD_SETEXPR=y # CONFIG_IPQ_QCA_AQUANTIA_PHY=y CONFIG_QCA8081_PHY=y +CONFIG_QCA8084_PHY=y CONFIG_CMD_NET=y # CONFIG_CMD_TFTPPUT is not set diff --git a/drivers/net/devsoc/devsoc_edma.c b/drivers/net/devsoc/devsoc_edma.c index e6f47def69..afec4676ca 100644 --- a/drivers/net/devsoc/devsoc_edma.c +++ b/drivers/net/devsoc/devsoc_edma.c @@ -18,7 +18,6 @@ ************************************************************************** */ #include -#include #include #include #include @@ -49,9 +48,12 @@ 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}; +phy_info_t *swt_info[QCA8084_MAX_PORTS] = {0}; int sgmii_mode[2] = {0}; #ifndef CONFIG_DEVSOC_RUMI +extern void ipq_phy_addr_fixup(void); +extern void ipq_clock_init(void); 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); @@ -61,9 +63,18 @@ 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); +extern int ipq_qca8084_hw_init(phy_info_t * phy_info[]); +extern int ipq_qca8084_link_update(phy_info_t * phy_info[]); +extern void ipq_qca8084_switch_hw_reset(int gpio); #endif static int tftp_acl_our_port; +#ifndef CONFIG_DEVSOC_RUMI +#ifdef CONFIG_QCA8084_PHY +static int qca8084_swt_enb = 0; +static int qca8084_chip_detect = 0; +#endif +#endif /* * EDMA hardware instance @@ -902,49 +913,61 @@ static int devsoc_eth_init(struct eth_device *eth_dev, bd_t *this) */ for (i = 0; i < DEVSOC_PHY_MAX; i++) { #ifndef CONFIG_DEVSOC_RUMI - if (!priv->ops[i]) { - printf("Phy ops not mapped\n"); + if (phy_info[i]->phy_type == UNUSED_PHY_TYPE) + continue; +#ifdef CONFIG_QCA8084_PHY + else if ((qca8084_swt_enb && qca8084_chip_detect) && + (phy_info[i]->phy_type == QCA8084_PHY_TYPE)) { + if (!ipq_qca8084_link_update(swt_info)) + linkup++; 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]); +#endif + 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; - } 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 @@ -1631,13 +1654,14 @@ int devsoc_edma_hw_init(struct devsoc_edma_hw *ehw) return 0; } -void get_phy_address(int offset) +void get_phy_address(int offset, phy_info_t * phy_info[], int max_phy_ports) { int phy_type; int phy_address; + int forced_speed, forced_duplex; int i; - for (i = 0; i < DEVSOC_PHY_MAX; i++) + for (i = 0; i < max_phy_ports; i++) phy_info[i] = devsoc_alloc_mem(sizeof(phy_info_t)); i = 0; for (offset = fdt_first_subnode(gd->fdt_blob, offset); offset > 0; @@ -1646,7 +1670,13 @@ void get_phy_address(int offset) offset, "phy_address", 0); phy_type = fdtdec_get_uint(gd->fdt_blob, offset, "phy_type", 0); + forced_speed = fdtdec_get_uint(gd->fdt_blob, + offset, "forced-speed", 0); + forced_duplex = fdtdec_get_uint(gd->fdt_blob, + offset, "forced-duplex", 0); phy_info[i]->phy_address = phy_address; + phy_info[i]->forced_speed = forced_speed; + phy_info[i]->forced_duplex = forced_duplex; phy_info[i++]->phy_type = phy_type; } } @@ -1666,8 +1696,12 @@ int devsoc_edma_init(void *edma_board_cfg) #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; +#ifdef CONFIG_QCA8084_PHY + static int qca8084_init_done = 0; + int qca8084_gpio, clk[4] = {0}; +#endif + int node, phy_addr, mode, phy_node = -1, res = -1; + int aquantia_port[2] = {-1, -1}, aquantia_port_cnt = -1; /* * Init non cache buffer @@ -1687,9 +1721,22 @@ int devsoc_edma_init(void *edma_board_cfg) } } +#ifdef CONFIG_QCA8084_PHY + qca8084_swt_enb = fdtdec_get_uint(gd->fdt_blob, node, "qca8084_switch_enable", 0); + if (qca8084_swt_enb) { + qca8084_gpio = fdtdec_get_uint(gd->fdt_blob, node, "qca808x_gpio", 0); + if (qca8084_gpio) + ipq_qca8084_switch_hw_reset(qca8084_gpio); + } + + phy_node = fdt_path_offset(gd->fdt_blob, "/ess-switch/qca8084_swt_info"); + if (phy_node >= 0) + get_phy_address(phy_node, swt_info, QCA8084_MAX_PORTS); +#endif + phy_node = fdt_path_offset(gd->fdt_blob, "/ess-switch/port_phyinfo"); if (phy_node >= 0) - get_phy_address(phy_node); + get_phy_address(phy_node, phy_info, DEVSOC_PHY_MAX); mode = fdtdec_get_uint(gd->fdt_blob, node, "switch_mac_mode0", -1); if (mode < 0) { @@ -1785,6 +1832,13 @@ int devsoc_edma_init(void *edma_board_cfg) printf("Error:Phy addresses not configured in DT\n"); goto init_failed; } +#ifdef CONFIG_QCA8084_PHY + if (phy_info[phy_id]->phy_type == QCA8084_PHY_TYPE && !qca8084_init_done) { + ipq_phy_addr_fixup(); + ipq_clock_init(); + qca8084_init_done = 1; + } +#endif phy_chip_id1 = ipq_mdio_read(phy_addr, QCA_PHY_ID1, NULL); phy_chip_id2 = ipq_mdio_read(phy_addr, QCA_PHY_ID2, NULL); @@ -1826,6 +1880,11 @@ int devsoc_edma_init(void *edma_board_cfg) ipq_qca8081_phy_init(&devsoc_edma_dev[i]->ops[phy_id], phy_addr); break; #endif +#ifdef CONFIG_QCA8084_PHY + case QCA8084_PHY: + qca8084_chip_detect = 1; + break; +#endif #ifdef CONFIG_IPQ_QCA_AQUANTIA_PHY case AQUANTIA_PHY_107: case AQUANTIA_PHY_109: @@ -1856,6 +1915,31 @@ int devsoc_edma_init(void *edma_board_cfg) if (ret) goto init_failed; +#ifndef CONFIG_DEVSOC_RUMI +#ifdef CONFIG_QCA8084_PHY + /** QCA8084 switch specific configurations */ + if (qca8084_swt_enb && qca8084_chip_detect) { + /** Force speed devsoc 2nd port for QCA8084 switch mode */ + clk[0] = 0x301; + clk[1] = 0x0; + clk[2] = 0x401; + clk[3] = 0x0; + + pr_debug("Force speed devsoc 2nd PORT for QCA8084 switch mode \n"); + devsoc_speed_clock_set(PORT1, clk); + + /** Force Link-speed: 1000M + * Force Link-status: enable */ + devsoc_pqsgmii_speed_set(PORT1, 0x2, 0x0); + + ret = ipq_qca8084_hw_init(swt_info); + if (ret < 0) { + printf("Error: ipq_qca8084_hw_init failed \n"); + goto init_failed; + } + } +#endif +#endif eth_register(dev[i]); } diff --git a/drivers/net/devsoc/devsoc_ppe.h b/drivers/net/devsoc/devsoc_ppe.h index cfc554887b..c7fd0e6749 100644 --- a/drivers/net/devsoc/devsoc_ppe.h +++ b/drivers/net/devsoc/devsoc_ppe.h @@ -24,13 +24,9 @@ #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 diff --git a/drivers/net/devsoc/devsoc_uniphy.c b/drivers/net/devsoc/devsoc_uniphy.c index 5bc796b4c0..d767623a52 100644 --- a/drivers/net/devsoc/devsoc_uniphy.c +++ b/drivers/net/devsoc/devsoc_uniphy.c @@ -202,10 +202,32 @@ static void ppe_uniphy_qsgmii_mode_set(uint32_t uniphy_index) mdelay(100); } +void ppe_uniphy_set_forceMode(uint32_t uniphy_index) +{ + uint32_t reg_value; + + reg_value = readl(PPE_UNIPHY_BASE + (uniphy_index * PPE_UNIPHY_REG_INC) + + UNIPHY_DEC_CHANNEL_0_INPUT_OUTPUT_4); + reg_value |= UNIPHY_FORCE_SPEED_25M; + + writel(reg_value, PPE_UNIPHY_BASE + (uniphy_index * PPE_UNIPHY_REG_INC) + + UNIPHY_DEC_CHANNEL_0_INPUT_OUTPUT_4); +} + 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); + if ((uniphy_index == 1) && (mode == EPORT_WRAPPER_SGMII_PLUS)) { + writel(UNIPHY_MISC_SRC_PHY_MODE, PPE_UNIPHY_BASE + + (uniphy_index * PPE_UNIPHY_REG_INC) + UNIPHY_MISC_SOURCE_SELECTION_REG_OFFSET); + + ppe_uniphy_set_forceMode(uniphy_index); + + writel(UNIPHY_MISC2_REG_SGMII_PLUS_MODE, PPE_UNIPHY_BASE + + (uniphy_index * PPE_UNIPHY_REG_INC) + UNIPHY_MISC2_REG_OFFSET); + } else { + 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); @@ -238,7 +260,11 @@ static void ppe_uniphy_sgmii_mode_set(uint32_t uniphy_index, uint32_t mode) break; case EPORT_WRAPPER_SGMII_PLUS: - writel(0x820, PPE_UNIPHY_BASE + (uniphy_index * PPE_UNIPHY_REG_INC) + if (uniphy_index == 1) + writel(0x20, PPE_UNIPHY_BASE + (uniphy_index * PPE_UNIPHY_REG_INC) + + PPE_UNIPHY_MODE_CONTROL); + else + writel(0x820, PPE_UNIPHY_BASE + (uniphy_index * PPE_UNIPHY_REG_INC) + PPE_UNIPHY_MODE_CONTROL); break; diff --git a/drivers/net/devsoc/devsoc_uniphy.h b/drivers/net/devsoc/devsoc_uniphy.h index 0857f03a51..8ab195c008 100644 --- a/drivers/net/devsoc/devsoc_uniphy.h +++ b/drivers/net/devsoc/devsoc_uniphy.h @@ -41,6 +41,12 @@ #define UNIPHY_MISC2_REG_VALUE 0x70 +#define UNIPHY_MISC_SOURCE_SELECTION_REG_OFFSET 0x21c +#define UNIPHY_MISC_SRC_PHY_MODE 0xa882 + +#define UNIPHY_DEC_CHANNEL_0_INPUT_OUTPUT_4 0x480 +#define UNIPHY_FORCE_SPEED_25M (1 << 3) + #define UNIPHY_PLL_RESET_REG_OFFSET 0x780 #define UNIPHY_PLL_RESET_REG_VALUE 0x02bf #define UNIPHY_PLL_RESET_REG_DEFAULT_VALUE 0x02ff diff --git a/include/dt-bindings/qcom/eth-devsoc.h b/include/dt-bindings/qcom/eth-devsoc.h index 50f59afcef..9f676c1fa6 100644 --- a/include/dt-bindings/qcom/eth-devsoc.h +++ b/include/dt-bindings/qcom/eth-devsoc.h @@ -46,5 +46,7 @@ #define AQ_PHY_TYPE 0x3 #define QCA8033_PHY_TYPE 0x4 #define SFP_PHY_TYPE 0x5 +#define QCA8084_PHY_TYPE 0x6 +#define UNUSED_PHY_TYPE 0xFF #endif From 9a6c369849bd69b8c365341b6ca5139461f0e78b Mon Sep 17 00:00:00 2001 From: Ram Kumar D Date: Mon, 27 Jun 2022 09:38:04 +0530 Subject: [PATCH 3/4] driver: net: devsoc: add support for S17C switch Change-Id: If7ccaf9b63b68b0635f955228b161040ab5618cb Signed-off-by: Ram Kumar D --- configs/devsoc_defconfig | 1 + drivers/net/Kconfig | 4 + drivers/net/Makefile | 1 + drivers/net/devsoc/devsoc_edma.c | 59 +++ drivers/net/ipq_common/athrs17_phy.c | 419 +++++++++++++++++ drivers/net/ipq_common/athrs17_phy.h | 621 ++++++++++++++++++++++++++ drivers/net/ipq_common/ipq_phy.h | 5 + include/dt-bindings/qcom/eth-devsoc.h | 1 + 8 files changed, 1111 insertions(+) create mode 100644 drivers/net/ipq_common/athrs17_phy.c create mode 100644 drivers/net/ipq_common/athrs17_phy.h diff --git a/configs/devsoc_defconfig b/configs/devsoc_defconfig index 5a4f9c41e9..74ad98c326 100644 --- a/configs/devsoc_defconfig +++ b/configs/devsoc_defconfig @@ -103,6 +103,7 @@ CONFIG_CMD_SETEXPR=y CONFIG_IPQ_QCA_AQUANTIA_PHY=y CONFIG_QCA8081_PHY=y CONFIG_QCA8084_PHY=y +CONFIG_ATHRS17C_SWITCH=y CONFIG_CMD_NET=y # CONFIG_CMD_TFTPPUT is not set diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 6ab67a845e..332d999ecc 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -116,3 +116,7 @@ config IPQ_QCA_AQUANTIA_PHY help Enable Aquantia PHY support. +config ATHRS17C_SWITCH + bool "QTI S17C switch support" + help + Enable QTI S17C switch support. diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 844462a591..8241f84c74 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -106,6 +106,7 @@ obj-$(CONFIG_QCA8075_PHY) += ipq_common/ipq_qca8075.o obj-$(CONFIG_QCA8084_PHY) += ipq_common/ipq_qca8084.o obj-$(CONFIG_QCA8084_PHY) += ipq_common/ipq_qca8084_clk.o obj-$(CONFIG_QCA8084_PHY) += ipq_common/ipq_qca8084_interface_ctrl.o +obj-$(CONFIG_ATHRS17C_SWITCH) += ipq_common/athrs17_phy.o obj-$(CONFIG_IPQ9574_QCA8075_PHY) += ipq9574/ipq9574_qca8075.o obj-$(CONFIG_QCA8033_PHY) += ipq_common/ipq_qca8033.o obj-$(CONFIG_QCA8081_PHY) += ipq_common/ipq_qca8081.o diff --git a/drivers/net/devsoc/devsoc_edma.c b/drivers/net/devsoc/devsoc_edma.c index afec4676ca..06aec4160a 100644 --- a/drivers/net/devsoc/devsoc_edma.c +++ b/drivers/net/devsoc/devsoc_edma.c @@ -66,6 +66,15 @@ extern int ipq_board_fw_download(unsigned int phy_addr); extern int ipq_qca8084_hw_init(phy_info_t * phy_info[]); extern int ipq_qca8084_link_update(phy_info_t * phy_info[]); extern void ipq_qca8084_switch_hw_reset(int gpio); + +#ifdef CONFIG_ATHRS17C_SWITCH +extern void ppe_uniphy_set_forceMode(uint32_t uniphy_index); + +extern int ipq_qca8337_switch_init(ipq_s17c_swt_cfg_t *s17c_swt_cfg); +extern int ipq_qca8337_link_update(ipq_s17c_swt_cfg_t *s17c_swt_cfg); +extern void ipq_s17c_switch_reset(int gpio); +ipq_s17c_swt_cfg_t s17c_swt_cfg; +#endif #endif static int tftp_acl_our_port; @@ -922,6 +931,15 @@ static int devsoc_eth_init(struct eth_device *eth_dev, bd_t *this) linkup++; continue; } +#endif +#ifdef CONFIG_ATHRS17C_SWITCH + else if (phy_info[i]->phy_type == ATHRS17C_SWITCH_TYPE) { + if (s17c_swt_cfg.chip_detect) { + if (!ipq_qca8337_link_update(&s17c_swt_cfg)) + linkup++; + continue; + } + } #endif else { if (!priv->ops[i]) { @@ -1699,6 +1717,9 @@ int devsoc_edma_init(void *edma_board_cfg) #ifdef CONFIG_QCA8084_PHY static int qca8084_init_done = 0; int qca8084_gpio, clk[4] = {0}; +#endif +#ifdef CONFIG_ATHRS17C_SWITCH + int s17c_swt_enb = 0, s17c_rst_gpio = 0; #endif int node, phy_addr, mode, phy_node = -1, res = -1; int aquantia_port[2] = {-1, -1}, aquantia_port_cnt = -1; @@ -1734,6 +1755,34 @@ int devsoc_edma_init(void *edma_board_cfg) get_phy_address(phy_node, swt_info, QCA8084_MAX_PORTS); #endif +#ifdef CONFIG_ATHRS17C_SWITCH + s17c_swt_enb = fdtdec_get_uint(gd->fdt_blob, node, + "s17c_switch_enable", 0); + if (s17c_swt_enb) { + s17c_swt_cfg.chip_detect = 0; + s17c_rst_gpio = fdtdec_get_uint(gd->fdt_blob, node, + "s17c_rst_gpio", 0); + + ipq_s17c_switch_reset(s17c_rst_gpio); + + /* + * Set ref clock 25MHZ and enable Force mode + */ + ppe_uniphy_set_forceMode(PORT0); + + phy_node = fdt_path_offset(gd->fdt_blob, + "/ess-switch/s17c_swt_info"); + s17c_swt_cfg.port_count = fdtdec_get_uint(gd->fdt_blob, + phy_node, "s17c_mac_pwr", 0); + s17c_swt_cfg.port_count = fdtdec_get_uint(gd->fdt_blob, + phy_node, "s17c_port_count", 0); + fdtdec_get_int_array(gd->fdt_blob, phy_node, + "s17c_port_address", + s17c_swt_cfg.port_phy_address, + s17c_swt_cfg.port_count); + } +#endif + phy_node = fdt_path_offset(gd->fdt_blob, "/ess-switch/port_phyinfo"); if (phy_node >= 0) get_phy_address(phy_node, phy_info, DEVSOC_PHY_MAX); @@ -1885,6 +1934,12 @@ int devsoc_edma_init(void *edma_board_cfg) qca8084_chip_detect = 1; break; #endif +#ifdef CONFIG_ATHRS17C_SWITCH + case QCA8337_PHY: + if (s17c_swt_enb) + s17c_swt_cfg.chip_detect = 1; + break; +#endif #ifdef CONFIG_IPQ_QCA_AQUANTIA_PHY case AQUANTIA_PHY_107: case AQUANTIA_PHY_109: @@ -1939,6 +1994,10 @@ int devsoc_edma_init(void *edma_board_cfg) } } #endif +#ifdef CONFIG_ATHRS17C_SWITCH + if (s17c_swt_cfg.chip_detect) + ipq_qca8337_switch_init(&s17c_swt_cfg); +#endif #endif eth_register(dev[i]); } diff --git a/drivers/net/ipq_common/athrs17_phy.c b/drivers/net/ipq_common/athrs17_phy.c new file mode 100644 index 0000000000..78e1c5f64e --- /dev/null +++ b/drivers/net/ipq_common/athrs17_phy.c @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2015-2016, 2020 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. + */ + +/* + * Manage the QTI S17C ethernet PHY. + * + * All definitions in this file are operating system independent! + */ + +#include +#include "athrs17_phy.h" + +/* + * Externel Common mdio read, PHY Name : IPQ MDIO1 + */ + +extern int ipq_mdio_write(int mii_id, int regnum, u16 value); +extern int ipq_mdio_read(int mii_id, int regnum, ushort *data); + +/****************************************************************************** + * FUNCTION DESCRIPTION: Read switch internal register. + * Switch internal register is accessed through the + * MDIO interface. MDIO access is only 16 bits wide so + * it needs the two time access to complete the internal + * register access. + * INPUT : register address + * OUTPUT : Register value + * + *****************************************************************************/ +static uint32_t athrs17_reg_read(uint32_t reg_addr) +{ + uint32_t reg_word_addr; + uint32_t phy_addr, reg_val; + uint16_t phy_val; + uint16_t tmp_val; + uint8_t phy_reg; + + /* change reg_addr to 16-bit word address, 32-bit aligned */ + reg_word_addr = (reg_addr & 0xfffffffc) >> 1; + + /* configure register high address */ + phy_addr = 0x18; + phy_reg = 0x0; + phy_val = (uint16_t) ((reg_word_addr >> 8) & 0x1ff); /* bit16-8 of reg address */ + ipq_mdio_write(phy_addr, phy_reg, phy_val); + /* + * For some registers such as MIBs, since it is read/clear, we should + * read the lower 16-bit register then the higher one + */ + + /* read register in lower address */ + phy_addr = 0x10 | ((reg_word_addr >> 5) & 0x7); /* bit7-5 of reg address */ + phy_reg = (uint8_t) (reg_word_addr & 0x1f); /* bit4-0 of reg address */ + ipq_mdio_read(phy_addr, phy_reg, &phy_val); + + /* read register in higher address */ + reg_word_addr++; + phy_addr = 0x10 | ((reg_word_addr >> 5) & 0x7); /* bit7-5 of reg address */ + phy_reg = (uint8_t) (reg_word_addr & 0x1f); /* bit4-0 of reg address */ + ipq_mdio_read(phy_addr, phy_reg, &tmp_val); + reg_val = (tmp_val << 16 | phy_val); + + return reg_val; +} + +/****************************************************************************** + * FUNCTION DESCRIPTION: Write switch internal register. + * Switch internal register is accessed through the + * MDIO interface. MDIO access is only 16 bits wide so + * it needs the two time access to complete the internal + * register access. + * INPUT : register address, value to be written + * OUTPUT : NONE + * + *****************************************************************************/ +static void athrs17_reg_write(uint32_t reg_addr, uint32_t reg_val) +{ + uint32_t reg_word_addr; + uint32_t phy_addr; + uint16_t phy_val; + uint8_t phy_reg; + + /* change reg_addr to 16-bit word address, 32-bit aligned */ + reg_word_addr = (reg_addr & 0xfffffffc) >> 1; + + /* configure register high address */ + phy_addr = 0x18; + phy_reg = 0x0; + phy_val = (uint16_t) ((reg_word_addr >> 8) & 0x1ff); /* bit16-8 of reg address */ + ipq_mdio_write(phy_addr, phy_reg, phy_val); + + /* + * For some registers such as ARL and VLAN, since they include BUSY bit + * in lower address, we should write the higher 16-bit register then the + * lower one + */ + + /* read register in higher address */ + reg_word_addr++; + phy_addr = 0x10 | ((reg_word_addr >> 5) & 0x7); /* bit7-5 of reg address */ + phy_reg = (uint8_t) (reg_word_addr & 0x1f); /* bit4-0 of reg address */ + phy_val = (uint16_t) ((reg_val >> 16) & 0xffff); + ipq_mdio_write(phy_addr, phy_reg, phy_val); + + /* write register in lower address */ + reg_word_addr--; + phy_addr = 0x10 | ((reg_word_addr >> 5) & 0x7); /* bit7-5 of reg address */ + phy_reg = (uint8_t) (reg_word_addr & 0x1f); /* bit4-0 of reg address */ + phy_val = (uint16_t) (reg_val & 0xffff); + ipq_mdio_write(phy_addr, phy_reg, phy_val); +} + +/********************************************************************* + * FUNCTION DESCRIPTION: V-lan configuration given by Switch team + Vlan 1:PHY0,1,2,3 and Mac 6 of s17c + Vlan 2:PHY4 and Mac 0 of s17c + * INPUT : NONE + * OUTPUT: NONE + *********************************************************************/ +void athrs17_vlan_config(void) +{ + athrs17_reg_write(S17_P0LOOKUP_CTRL_REG, 0x00140020); + athrs17_reg_write(S17_P0VLAN_CTRL0_REG, 0x20001); + + athrs17_reg_write(S17_P1LOOKUP_CTRL_REG, 0x0014005c); + athrs17_reg_write(S17_P1VLAN_CTRL0_REG, 0x10001); + + athrs17_reg_write(S17_P2LOOKUP_CTRL_REG, 0x0014005a); + athrs17_reg_write(S17_P2VLAN_CTRL0_REG, 0x10001); + + athrs17_reg_write(S17_P3LOOKUP_CTRL_REG, 0x00140056); + athrs17_reg_write(S17_P3VLAN_CTRL0_REG, 0x10001); + + athrs17_reg_write(S17_P4LOOKUP_CTRL_REG, 0x0014004e); + athrs17_reg_write(S17_P4VLAN_CTRL0_REG, 0x10001); + + athrs17_reg_write(S17_P5LOOKUP_CTRL_REG, 0x00140001); + athrs17_reg_write(S17_P5VLAN_CTRL0_REG, 0x20001); + + athrs17_reg_write(S17_P6LOOKUP_CTRL_REG, 0x0014001e); + athrs17_reg_write(S17_P6VLAN_CTRL0_REG, 0x10001); + printf("%s ...done\n", __func__); +} + +/******************************************************************* +* FUNCTION DESCRIPTION: Reset S17 register +* INPUT: NONE +* OUTPUT: NONE +*******************************************************************/ +int athrs17_init_switch(void) +{ + uint32_t data; + uint32_t i = 0; + + /* Reset the switch before initialization */ + athrs17_reg_write(S17_MASK_CTRL_REG, S17_MASK_CTRL_SOFT_RET); + do { + udelay(10); + data = athrs17_reg_read(S17_MASK_CTRL_REG); + i++; + if (i == 10){ + printf("QCA_8337: Failed to reset\n"); + return -1; + } + } while (data & S17_MASK_CTRL_SOFT_RET); + + i = 0; + + do { + udelay(10); + data = athrs17_reg_read(S17_GLOBAL_INT0_REG); + i++; + if (i == 10) + return -1; + } while ((data & S17_GLOBAL_INITIALIZED_STATUS) != S17_GLOBAL_INITIALIZED_STATUS); + + return 0; +} + +/********************************************************************* + * FUNCTION DESCRIPTION: Configure S17 register + * INPUT : NONE + * OUTPUT: NONE + *********************************************************************/ +void athrs17_reg_init(ipq_s17c_swt_cfg_t *swt_cfg) +{ + athrs17_reg_write(S17_MAC_PWR_REG, swt_cfg->mac_pwr); + + athrs17_reg_write(S17_P0STATUS_REG, (S17_SPEED_1000M | + S17_TXMAC_EN | + S17_RXMAC_EN | + S17_DUPLEX_FULL)); + + athrs17_reg_write(S17_GLOFW_CTRL1_REG, (S17_IGMP_JOIN_LEAVE_DPALL | + S17_BROAD_DPALL | + S17_MULTI_FLOOD_DPALL | + S17_UNI_FLOOD_DPALL)); + + athrs17_reg_write(S17_P5PAD_MODE_REG, S17_MAC0_RGMII_RXCLK_DELAY); + + athrs17_reg_write(S17_P0PAD_MODE_REG, (S17_MAC0_RGMII_EN | + S17_MAC0_RGMII_TXCLK_DELAY | + S17_MAC0_RGMII_RXCLK_DELAY | + (0x1 << S17_MAC0_RGMII_TXCLK_SHIFT) | + (0x2 << S17_MAC0_RGMII_RXCLK_SHIFT))); + + printf("%s: complete\n", __func__); +} + +/********************************************************************* + * FUNCTION DESCRIPTION: Configure S17 register + * INPUT : NONE + * OUTPUT: NONE + *********************************************************************/ +void athrs17_reg_init_lan(ipq_s17c_swt_cfg_t *swt_cfg) +{ + uint32_t reg_val; + + athrs17_reg_write(S17_P6STATUS_REG, (S17_SPEED_1000M | + S17_TXMAC_EN | + S17_RXMAC_EN | + S17_DUPLEX_FULL)); + + athrs17_reg_write(S17_MAC_PWR_REG, swt_cfg->mac_pwr); + reg_val = athrs17_reg_read(S17_P6PAD_MODE_REG); + athrs17_reg_write(S17_P6PAD_MODE_REG, (reg_val | S17_MAC6_SGMII_EN)); + + athrs17_reg_write(S17_PWS_REG, 0x2613a0); + + athrs17_reg_write(S17_SGMII_CTRL_REG,(S17c_SGMII_EN_PLL | + S17c_SGMII_EN_RX | + S17c_SGMII_EN_TX | + S17c_SGMII_EN_SD | + S17c_SGMII_BW_HIGH | + S17c_SGMII_SEL_CLK125M | + S17c_SGMII_TXDR_CTRL_600mV | + S17c_SGMII_CDR_BW_8 | + S17c_SGMII_DIS_AUTO_LPI_25M | + S17c_SGMII_MODE_CTRL_SGMII_PHY | + S17c_SGMII_PAUSE_SG_TX_EN_25M | + S17c_SGMII_ASYM_PAUSE_25M | + S17c_SGMII_PAUSE_25M | + S17c_SGMII_HALF_DUPLEX_25M | + S17c_SGMII_FULL_DUPLEX_25M)); + + athrs17_reg_write(S17_MODULE_EN_REG, S17_MIB_COUNTER_ENABLE); +} + +struct athrs17_regmap { + uint32_t start; + uint32_t end; +}; + +struct athrs17_regmap regmap[] = { + { 0x000, 0x0e4 }, + { 0x100, 0x168 }, + { 0x200, 0x270 }, + { 0x400, 0x454 }, + { 0x600, 0x718 }, + { 0x800, 0xb70 }, + { 0xC00, 0xC80 }, + { 0x1100, 0x11a7 }, + { 0x1200, 0x12a7 }, + { 0x1300, 0x13a7 }, + { 0x1400, 0x14a7 }, + { 0x1600, 0x16a7 }, +}; + +int do_ar8xxx_dump(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { + int i; + + for (i = 0; i < ARRAY_SIZE(regmap); i++) { + uint32_t reg; + struct athrs17_regmap *section = ®map[i]; + + for (reg = section->start; reg <= section->end; reg += sizeof(uint32_t)) { + uint32_t val = athrs17_reg_read(reg); + printf("%03zx: %08zx\n", reg, val); + } + } + + return 0; +}; +U_BOOT_CMD( + ar8xxx_dump, 1, 1, do_ar8xxx_dump, + "Dump ar8xxx registers", + "\n - print all ar8xxx registers\n" +); + +/********************************************************************* + * + * FUNCTION DESCRIPTION: This function invokes RGMII, + * SGMII switch init routines. + * INPUT : ipq_s17c_swt_cfg_t * + * OUTPUT: NONE + * +**********************************************************************/ +int ipq_athrs17_init(ipq_s17c_swt_cfg_t *swt_cfg) +{ + int ret; + + if (swt_cfg == NULL) + return -1; + + ret = athrs17_init_switch(); + if (ret != -1) { + athrs17_reg_init(swt_cfg); + athrs17_reg_init_lan(swt_cfg); + athrs17_vlan_config(); + printf ("S17c init done\n"); + } + + return ret; +} + +int ipq_qca8337_switch_init(ipq_s17c_swt_cfg_t *s17c_swt_cfg) +{ + int port; + for (port = 0; port < s17c_swt_cfg->port_count; ++port) { + u32 phy_val; + + /* phy powerdown */ + ipq_mdio_write(s17c_swt_cfg->port_phy_address[port], 0x0, + 0x0800); + phy_val = ipq_mdio_read(s17c_swt_cfg->port_phy_address[port], + 0x3d, NULL); + phy_val &= ~0x0040; + ipq_mdio_write(s17c_swt_cfg->port_phy_address[port], 0x3d, + phy_val); + + /* + * PHY will stop the tx clock for a while when link is down + * en_anychange debug port 0xb bit13 = 0 //speed up link down tx_clk + * sel_rst_80us debug port 0xb bit10 = 0 //speed up speed mode change to 2'b10 tx_clk + */ + phy_val = ipq_mdio_read(s17c_swt_cfg->port_phy_address[port], + 0xb, NULL); + phy_val &= ~0x2400; + ipq_mdio_write(s17c_swt_cfg->port_phy_address[port], 0xb, + phy_val); + mdelay(100); + } + + if (ipq_athrs17_init(s17c_swt_cfg) != 0) { + printf("QCA_8337 switch init failed \n"); + return 0; + } + + for (port = 0; port < s17c_swt_cfg->port_count; ++port) { + ipq_mdio_write(s17c_swt_cfg->port_phy_address[port], + MII_ADVERTISE, ADVERTISE_ALL | + ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); + /* phy reg 0x9, b10,1 = Prefer multi-port device (master) */ + ipq_mdio_write(s17c_swt_cfg->port_phy_address[port], + MII_CTRL1000, (0x0400|ADVERTISE_1000FULL)); + ipq_mdio_write(s17c_swt_cfg->port_phy_address[port], + MII_BMCR, BMCR_RESET | BMCR_ANENABLE); + mdelay(100); + } + + return 1; +} + +int ipq_qca8337_link_update(ipq_s17c_swt_cfg_t *s17c_swt_cfg) +{ + uint16_t phy_data; + int status = 1; + + for(int i = 0; i < s17c_swt_cfg->port_count; ++i){ + phy_data = ipq_mdio_read(s17c_swt_cfg->port_phy_address[i], + 0x11, NULL); + + if (phy_data == 0x50) + continue; + + /* Atleast one port should be link up*/ + if (phy_data & LINK_UP) + status = 0; + + printf("Port%d %s ", i + 1, LINK(phy_data)); + + switch(SPEED(phy_data)){ + case SPEED_1000M: + printf("Speed :1000M "); + break; + case SPEED_100M: + printf("Speed :100M "); + break; + default: + printf("Speed :10M "); + } + + printf ("%s \n", DUPLEX(phy_data)); + } + return status; +} + +void ipq_s17c_switch_reset(int gpio) +{ + unsigned int *switch_gpio_base = + (unsigned int *)GPIO_CONFIG_ADDR(gpio); + + writel(0x203, switch_gpio_base); + writel(0x0, GPIO_IN_OUT_ADDR(gpio)); + mdelay(500); + writel(0x2, GPIO_IN_OUT_ADDR(gpio)); +} diff --git a/drivers/net/ipq_common/athrs17_phy.h b/drivers/net/ipq_common/athrs17_phy.h new file mode 100644 index 0000000000..2975c83bf7 --- /dev/null +++ b/drivers/net/ipq_common/athrs17_phy.h @@ -0,0 +1,621 @@ +/* + * Copyright (c) 2015-2016, 2020 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 _ATHRS17_PHY_H +#define _ATHRS17_PHY_H + +/*****************/ +/* PHY Registers */ +/*****************/ +#define ATHR_PHY_CONTROL 0 +#define ATHR_PHY_STATUS 1 +#define ATHR_PHY_ID1 2 +#define ATHR_PHY_ID2 3 +#define ATHR_AUTONEG_ADVERT 4 +#define ATHR_LINK_PARTNER_ABILITY 5 +#define ATHR_AUTONEG_EXPANSION 6 +#define ATHR_NEXT_PAGE_TRANSMIT 7 +#define ATHR_LINK_PARTNER_NEXT_PAGE 8 +#define ATHR_1000BASET_CONTROL 9 +#define ATHR_1000BASET_STATUS 10 +#define ATHR_PHY_SPEC_CONTROL 16 +#define ATHR_PHY_SPEC_STATUS 17 +#define ATHR_DEBUG_PORT_ADDRESS 29 +#define ATHR_DEBUG_PORT_DATA 30 + +/* ATHR_PHY_CONTROL fields */ +#define ATHR_CTRL_SOFTWARE_RESET 0x8000 +#define ATHR_CTRL_SPEED_LSB 0x2000 +#define ATHR_CTRL_AUTONEGOTIATION_ENABLE 0x1000 +#define ATHR_CTRL_RESTART_AUTONEGOTIATION 0x0200 +#define ATHR_CTRL_SPEED_FULL_DUPLEX 0x0100 +#define ATHR_CTRL_SPEED_MSB 0x0040 + +#define ATHR_RESET_DONE(phy_control) \ + (((phy_control) & (ATHR_CTRL_SOFTWARE_RESET)) == 0) + +/* Phy status fields */ +#define ATHR_STATUS_AUTO_NEG_DONE 0x0020 + +#define ATHR_AUTONEG_DONE(ip_phy_status) \ + (((ip_phy_status) & \ + (ATHR_STATUS_AUTO_NEG_DONE)) == \ + (ATHR_STATUS_AUTO_NEG_DONE)) + +/* Link Partner ability */ +#define ATHR_LINK_100BASETX_FULL_DUPLEX 0x0100 +#define ATHR_LINK_100BASETX 0x0080 +#define ATHR_LINK_10BASETX_FULL_DUPLEX 0x0040 +#define ATHR_LINK_10BASETX 0x0020 + +/* Advertisement register. */ +#define ATHR_ADVERTISE_NEXT_PAGE 0x8000 +#define ATHR_ADVERTISE_ASYM_PAUSE 0x0800 +#define ATHR_ADVERTISE_PAUSE 0x0400 +#define ATHR_ADVERTISE_100FULL 0x0100 +#define ATHR_ADVERTISE_100HALF 0x0080 +#define ATHR_ADVERTISE_10FULL 0x0040 +#define ATHR_ADVERTISE_10HALF 0x0020 + +#define ATHR_ADVERTISE_ALL (ATHR_ADVERTISE_ASYM_PAUSE | ATHR_ADVERTISE_PAUSE | \ + ATHR_ADVERTISE_10HALF | ATHR_ADVERTISE_10FULL | \ + ATHR_ADVERTISE_100HALF | ATHR_ADVERTISE_100FULL) + +/* 1000BASET_CONTROL */ +#define ATHR_ADVERTISE_1000FULL 0x0200 + +/* Phy Specific status fields */ +#define ATHER_STATUS_LINK_MASK 0xC000 +#define ATHER_STATUS_LINK_SHIFT 14 +#define ATHER_STATUS_FULL_DEPLEX 0x2000 +#define ATHR_STATUS_LINK_PASS 0x0400 +#define ATHR_STATUS_RESOVLED 0x0800 + +/*phy debug port register */ +#define ATHER_DEBUG_SERDES_REG 5 + +/* Serdes debug fields */ +#define ATHER_SERDES_BEACON 0x0100 + +/* S17 CSR Registers */ + +#define S17_ENABLE_CPU_BROADCAST (1 << 26) + +#define S17_PHY_LINK_CHANGE_REG 0x4 +#define S17_PHY_LINK_UP 0x400 +#define S17_PHY_LINK_DOWN 0x800 +#define S17_PHY_LINK_DUPLEX_CHANGE 0x2000 +#define S17_PHY_LINK_SPEED_CHANGE 0x4000 +#define S17_PHY_LINK_INTRS (PHY_LINK_UP | PHY_LINK_DOWN | PHY_LINK_DUPLEX_CHANGE | PHY_LINK_SPEED_CHANGE) + +#define S17_MASK_CTRL_REG 0x0000 +#define S17_P0PAD_MODE_REG 0x0004 +#define S17_P5PAD_MODE_REG 0x0008 +#define S17_P6PAD_MODE_REG 0x000c +#define S17_PWS_REG 0x0010 +#define S17_GLOBAL_INT0_REG 0x0020 +#define S17_GLOBAL_INT1_REG 0x0024 +#define S17_GLOBAL_INTMASK0 0x0028 +#define S17_GLOBAL_INTMASK1 0x002c +#define S17_MODULE_EN_REG 0x0030 +#define S17_MIB_REG 0x0034 +#define S17_INTF_HIADDR_REG 0x0038 +#define S17_MDIO_CTRL_REG 0x003c +#define S17_BIST_CTRL_REG 0x0040 +#define S17_BIST_REC_REG 0x0044 +#define S17_SERVICE_REG 0x0048 +#define S17_LED_CTRL0_REG 0x0050 +#define S17_LED_CTRL1_REG 0x0054 +#define S17_LED_CTRL2_REG 0x0058 +#define S17_LED_CTRL3_REG 0x005c +#define S17_MACADDR0_REG 0x0060 +#define S17_MACADDR1_REG 0x0064 +#define S17_MAX_FRAME_SIZE_REG 0x0078 +#define S17_P0STATUS_REG 0x007c +#define S17_P1STATUS_REG 0x0080 +#define S17_P2STATUS_REG 0x0084 +#define S17_P3STATUS_REG 0x0088 +#define S17_P4STATUS_REG 0x008c +#define S17_P5STATUS_REG 0x0090 +#define S17_P6STATUS_REG 0x0094 +#define S17_HDRCTRL_REG 0x0098 +#define S17_P0HDRCTRL_REG 0x009c +#define S17_P1HDRCTRL_REG 0x00A0 +#define S17_P2HDRCTRL_REG 0x00a4 +#define S17_P3HDRCTRL_REG 0x00a8 +#define S17_P4HDRCTRL_REG 0x00ac +#define S17_P5HDRCTRL_REG 0x00b0 +#define S17_P6HDRCTRL_REG 0x00b4 +#define S17_SGMII_CTRL_REG 0x00e0 +#define S17_MAC_PWR_REG 0x00e4 +#define S17_EEE_CTRL_REG 0x0100 + +/* ACL Registers */ +#define S17_ACL_FUNC0_REG 0x0400 +#define S17_ACL_FUNC1_REG 0x0404 +#define S17_ACL_FUNC2_REG 0x0408 +#define S17_ACL_FUNC3_REG 0x040c +#define S17_ACL_FUNC4_REG 0x0410 +#define S17_ACL_FUNC5_REG 0x0414 +#define S17_PRIVATE_IP_REG 0x0418 +#define S17_P0VLAN_CTRL0_REG 0x0420 +#define S17_P0VLAN_CTRL1_REG 0x0424 +#define S17_P1VLAN_CTRL0_REG 0x0428 +#define S17_P1VLAN_CTRL1_REG 0x042c +#define S17_P2VLAN_CTRL0_REG 0x0430 +#define S17_P2VLAN_CTRL1_REG 0x0434 +#define S17_P3VLAN_CTRL0_REG 0x0438 +#define S17_P3VLAN_CTRL1_REG 0x043c +#define S17_P4VLAN_CTRL0_REG 0x0440 +#define S17_P4VLAN_CTRL1_REG 0x0444 +#define S17_P5VLAN_CTRL0_REG 0x0448 +#define S17_P5VLAN_CTRL1_REG 0x044c +#define S17_P6VLAN_CTRL0_REG 0x0450 +#define S17_P6VLAN_CTRL1_REG 0x0454 + +/* Table Lookup Registers */ +#define S17_ATU_DATA0_REG 0x0600 +#define S17_ATU_DATA1_REG 0x0604 +#define S17_ATU_DATA2_REG 0x0608 +#define S17_ATU_FUNC_REG 0x060C +#define S17_VTU_FUNC0_REG 0x0610 +#define S17_VTU_FUNC1_REG 0x0614 +#define S17_ARL_CTRL_REG 0x0618 +#define S17_GLOFW_CTRL0_REG 0x0620 +#define S17_GLOFW_CTRL1_REG 0x0624 +#define S17_GLOLEARN_LIMIT_REG 0x0628 +#define S17_TOS_PRIMAP_REG0 0x0630 +#define S17_TOS_PRIMAP_REG1 0x0634 +#define S17_TOS_PRIMAP_REG2 0x0638 +#define S17_TOS_PRIMAP_REG3 0x063c +#define S17_TOS_PRIMAP_REG4 0x0640 +#define S17_TOS_PRIMAP_REG5 0x0644 +#define S17_TOS_PRIMAP_REG6 0x0648 +#define S17_TOS_PRIMAP_REG7 0x064c +#define S17_VLAN_PRIMAP_REG0 0x0650 +#define S17_LOOP_CHECK_REG 0x0654 +#define S17_P0LOOKUP_CTRL_REG 0x0660 +#define S17_P0PRI_CTRL_REG 0x0664 +#define S17_P0LEARN_LMT_REG 0x0668 +#define S17_P1LOOKUP_CTRL_REG 0x066c +#define S17_P1PRI_CTRL_REG 0x0670 +#define S17_P1LEARN_LMT_REG 0x0674 +#define S17_P2LOOKUP_CTRL_REG 0x0678 +#define S17_P2PRI_CTRL_REG 0x067c +#define S17_P2LEARN_LMT_REG 0x0680 +#define S17_P3LOOKUP_CTRL_REG 0x0684 +#define S17_P3PRI_CTRL_REG 0x0688 +#define S17_P3LEARN_LMT_REG 0x068c +#define S17_P4LOOKUP_CTRL_REG 0x0690 +#define S17_P4PRI_CTRL_REG 0x0694 +#define S17_P4LEARN_LMT_REG 0x0698 +#define S17_P5LOOKUP_CTRL_REG 0x069c +#define S17_P5PRI_CTRL_REG 0x06a0 +#define S17_P5LEARN_LMT_REG 0x06a4 +#define S17_P6LOOKUP_CTRL_REG 0x06a8 +#define S17_P6PRI_CTRL_REG 0x06ac +#define S17_P6LEARN_LMT_REG 0x06b0 +#define S17_GLO_TRUNK_CTRL0_REG 0x0700 +#define S17_GLO_TRUNK_CTRL1_REG 0x0704 +#define S17_GLO_TRUNK_CTRL2_REG 0x0708 + +/* Queue Management Registers */ +#define S17_PORT0_HOL_CTRL0 0x0970 +#define S17_PORT0_HOL_CTRL1 0x0974 +#define S17_PORT1_HOL_CTRL0 0x0978 +#define S17_PORT1_HOL_CTRL1 0x097c +#define S17_PORT2_HOL_CTRL0 0x0980 +#define S17_PORT2_HOL_CTRL1 0x0984 +#define S17_PORT3_HOL_CTRL0 0x0988 +#define S17_PORT3_HOL_CTRL1 0x098c +#define S17_PORT4_HOL_CTRL0 0x0990 +#define S17_PORT4_HOL_CTRL1 0x0994 +#define S17_PORT5_HOL_CTRL0 0x0998 +#define S17_PORT5_HOL_CTRL1 0x099c +#define S17_PORT6_HOL_CTRL0 0x09a0 +#define S17_PORT6_HOL_CTRL1 0x09a4 + +/* Port flow control registers */ +#define S17_P0_FLCTL_REG 0x09b0 +#define S17_P1_FLCTL_REG 0x09b4 +#define S17_P2_FLCTL_REG 0x09b8 +#define S17_P3_FLCTL_REG 0x09bc +#define S17_P4_FLCTL_REG 0x09c0 +#define S17_P5_FLCTL_REG 0x09c4 + +/* Packet Edit registers */ +#define S17_PKT_EDIT_CTRL 0x0c00 +#define S17_P0Q_REMAP_REG0 0x0c40 +#define S17_P0Q_REMAP_REG1 0x0c44 +#define S17_P1Q_REMAP_REG0 0x0c48 +#define S17_P2Q_REMAP_REG0 0x0c4c +#define S17_P3Q_REMAP_REG0 0x0c50 +#define S17_P4Q_REMAP_REG0 0x0c54 +#define S17_P5Q_REMAP_REG0 0x0c58 +#define S17_P5Q_REMAP_REG1 0x0c5c +#define S17_P6Q_REMAP_REG0 0x0c60 +#define S17_P6Q_REMAP_REG1 0x0c64 +#define S17_ROUTER_VID0 0x0c70 +#define S17_ROUTER_VID1 0x0c74 +#define S17_ROUTER_VID2 0x0c78 +#define S17_ROUTER_VID3 0x0c7c +#define S17_ROUTER_EG_VLAN_MODE 0x0c80 + +/* L3 Registers */ +#define S17_HROUTER_CTRL_REG 0x0e00 +#define S17_HROUTER_PBCTRL0_REG 0x0e04 +#define S17_HROUTER_PBCTRL1_REG 0x0e08 +#define S17_HROUTER_PBCTRL2_REG 0x0e0c +#define S17_WCMP_HASH_TABLE0_REG 0x0e10 +#define S17_WCMP_HASH_TABLE1_REG 0x0e14 +#define S17_WCMP_HASH_TABLE2_REG 0x0e18 +#define S17_WCMP_HASH_TABLE3_REG 0x0e1c +#define S17_WCMP_NHOP_TABLE0_REG 0x0e20 +#define S17_WCMP_NHOP_TABLE1_REG 0x0e24 +#define S17_WCMP_NHOP_TABLE2_REG 0x0e28 +#define S17_WCMP_NHOP_TABLE3_REG 0x0e2c +#define S17_ARP_ENTRY_CTRL_REG 0x0e30 +#define S17_ARP_USECNT_REG 0x0e34 +#define S17_HNAT_CTRL_REG 0x0e38 +#define S17_NAPT_ENTRY_CTRL0_REG 0x0e3c +#define S17_NAPT_ENTRY_CTRL1_REG 0x0e40 +#define S17_NAPT_USECNT_REG 0x0e44 +#define S17_ENTRY_EDIT_DATA0_REG 0x0e48 +#define S17_ENTRY_EDIT_DATA1_REG 0x0e4c +#define S17_ENTRY_EDIT_DATA2_REG 0x0e50 +#define S17_ENTRY_EDIT_DATA3_REG 0x0e54 +#define S17_ENTRY_EDIT_CTRL_REG 0x0e58 +#define S17_HNAT_PRIVATE_IP_REG 0x0e5c + +/* MIB counters */ +#define S17_MIB_PORT0 0x1000 +#define S17_MIB_PORT1 0x1100 +#define S17_MIB_PORT2 0x1200 +#define S17_MIB_PORT3 0x1300 +#define S17_MIB_PORT4 0x1400 +#define S17_MIB_PORT5 0x1500 +#define S17_MIB_PORT6 0x1600 + +#define S17_MIB_COUNTER_ENABLE (1 << 0) +#define S17_MIB_NON_CLEAR (1 << 20) + +#define S17_MIB_RXBROAD 0x0 +#define S17_MIB_RXPAUSE 0x4 +#define S17_MIB_RXMULTI 0x8 +#define S17_MIB_RXFCSERR 0xC +#define S17_MIB_RXALIGNERR 0x10 +#define S17_MIB_RXUNDERSIZE 0x14 +#define S17_MIB_RXFRAG 0x18 +#define S17_MIB_RX64B 0x1C +#define S17_MIB_RX128B 0x20 +#define S17_MIB_RX256B 0x24 +#define S17_MIB_RX512B 0x28 +#define S17_MIB_RX1024B 0x2C +#define S17_MIB_RX1518B 0x30 +#define S17_MIB_RXMAXB 0x34 +#define S17_MIB_RXTOOLONG 0x38 +#define S17_MIB_RXBYTE1 0x3C +#define S17_MIB_RXBYTE2 0x40 +#define S17_MIB_RXOVERFLOW 0x4C +#define S17_MIB_FILTERED 0x50 +#define S17_MIB_TXBROAD 0x54 +#define S17_MIB_TXPAUSE 0x58 +#define S17_MIB_TXMULTI 0x5C +#define S17_MIB_TXUNDERRUN 0x60 +#define S17_MIB_TX64B 0x64 +#define S17_MIB_TX128B 0x68 +#define S17_MIB_TX256B 0x6c +#define S17_MIB_TX512B 0x70 +#define S17_MIB_TX1024B 0x74 +#define S17_MIB_TX1518B 0x78 +#define S17_MIB_TXMAXB 0x7C +#define S17_MIB_TXOVERSIZE 0x80 +#define S17_MIB_TXBYTE1 0x84 +#define S17_MIB_TXBYTE2 0x88 +#define S17_MIB_TXCOL 0x8C +#define S17_MIB_TXABORTCOL 0x90 +#define S17_MIB_TXMULTICOL 0x94 +#define S17_MIB_TXSINGLECOL 0x98 +#define S17_MIB_TXEXCDEFER 0x9C +#define S17_MIB_TXDEFER 0xA0 +#define S17_MIB_TXLATECOL 0xA4 + +/* Register fields */ +#define S17_CHIPID_V1_0 0x1201 +#define S17_CHIPID_V1_1 0x1202 + +#define S17_MASK_CTRL_SOFT_RET (1 << 31) + +#define S17_GLOBAL_INT0_ACL_INI_INT (1<<29) +#define S17_GLOBAL_INT0_LOOKUP_INI_INT (1<<28) +#define S17_GLOBAL_INT0_QM_INI_INT (1<<27) +#define S17_GLOBAL_INT0_MIB_INI_INT (1<<26) +#define S17_GLOBAL_INT0_OFFLOAD_INI_INT (1<<25) +#define S17_GLOBAL_INT0_HARDWARE_INI_DONE (1<<24) + +#define S17_GLOBAL_INITIALIZED_STATUS \ + ( \ + S17_GLOBAL_INT0_ACL_INI_INT | \ + S17_GLOBAL_INT0_LOOKUP_INI_INT | \ + S17_GLOBAL_INT0_QM_INI_INT | \ + S17_GLOBAL_INT0_MIB_INI_INT | \ + S17_GLOBAL_INT0_OFFLOAD_INI_INT | \ + S17_GLOBAL_INT0_HARDWARE_INI_DONE \ + ) + +#define S17_MAC0_MAC_MII_RXCLK_SEL (1 << 0) +#define S17_MAC0_MAC_MII_TXCLK_SEL (1 << 1) +#define S17_MAC0_MAC_MII_EN (1 << 2) +#define S17_MAC0_MAC_GMII_RXCLK_SEL (1 << 4) +#define S17_MAC0_MAC_GMII_TXCLK_SEL (1 << 5) +#define S17_MAC0_MAC_GMII_EN (1 << 6) +#define S17_MAC0_SGMII_EN (1 << 7) +#define S17_MAC0_PHY_MII_RXCLK_SEL (1 << 8) +#define S17_MAC0_PHY_MII_TXCLK_SEL (1 << 9) +#define S17_MAC0_PHY_MII_EN (1 << 10) +#define S17_MAC0_PHY_MII_PIPE_SEL (1 << 11) +#define S17_MAC0_PHY_GMII_RXCLK_SEL (1 << 12) +#define S17_MAC0_PHY_GMII_TXCLK_SEL (1 << 13) +#define S17_MAC0_PHY_GMII_EN (1 << 14) +#define S17_MAC0_RGMII_RXCLK_SHIFT 20 +#define S17_MAC0_RGMII_TXCLK_SHIFT 22 +#define S17_MAC0_RGMII_RXCLK_DELAY (1 << 24) +#define S17_MAC0_RGMII_TXCLK_DELAY (1 << 25) +#define S17_MAC0_RGMII_EN (1 << 26) + +#define S17_MAC5_MAC_MII_RXCLK_SEL (1 << 0) +#define S17_MAC5_MAC_MII_TXCLK_SEL (1 << 1) +#define S17_MAC5_MAC_MII_EN (1 << 2) +#define S17_MAC5_PHY_MII_RXCLK_SEL (1 << 8) +#define S17_MAC5_PHY_MII_TXCLK_SEL (1 << 9) +#define S17_MAC5_PHY_MII_EN (1 << 10) +#define S17_MAC5_PHY_MII_PIPE_SEL (1 << 11) +#define S17_MAC5_RGMII_RXCLK_SHIFT 20 +#define S17_MAC5_RGMII_TXCLK_SHIFT 22 +#define S17_MAC5_RGMII_RXCLK_DELAY (1 << 24) +#define S17_MAC5_RGMII_TXCLK_DELAY (1 << 25) +#define S17_MAC5_RGMII_EN (1 << 26) + +#define S17_MAC6_MAC_MII_RXCLK_SEL (1 << 0) +#define S17_MAC6_MAC_MII_TXCLK_SEL (1 << 1) +#define S17_MAC6_MAC_MII_EN (1 << 2) +#define S17_MAC6_MAC_GMII_RXCLK_SEL (1 << 4) +#define S17_MAC6_MAC_GMII_TXCLK_SEL (1 << 5) +#define S17_MAC6_MAC_GMII_EN (1 << 6) +#define S17_MAC6_SGMII_EN (1 << 7) +#define S17_MAC6_PHY_MII_RXCLK_SEL (1 << 8) +#define S17_MAC6_PHY_MII_TXCLK_SEL (1 << 9) +#define S17_MAC6_PHY_MII_EN (1 << 10) +#define S17_MAC6_PHY_MII_PIPE_SEL (1 << 11) +#define S17_MAC6_PHY_GMII_RXCLK_SEL (1 << 12) +#define S17_MAC6_PHY_GMII_TXCLK_SEL (1 << 13) +#define S17_MAC6_PHY_GMII_EN (1 << 14) +#define S17_PHY4_GMII_EN (1 << 16) +#define S17_PHY4_RGMII_EN (1 << 17) +#define S17_PHY4_MII_EN (1 << 18) +#define S17_MAC6_RGMII_RXCLK_SHIFT 20 +#define S17_MAC6_RGMII_TXCLK_SHIFT 22 +#define S17_MAC6_RGMII_RXCLK_DELAY (1 << 24) +#define S17_MAC6_RGMII_TXCLK_DELAY (1 << 25) +#define S17_MAC6_RGMII_EN (1 << 26) + +#define S17_SPEED_10M (0 << 0) +#define S17_SPEED_100M (1 << 0) +#define S17_SPEED_1000M (2 << 0) +#define S17_TXMAC_EN (1 << 2) +#define S17_RXMAC_EN (1 << 3) +#define S17_TX_FLOW_EN (1 << 4) +#define S17_RX_FLOW_EN (1 << 5) +#define S17_DUPLEX_FULL (1 << 6) +#define S17_DUPLEX_HALF (0 << 6) +#define S17_TX_HALF_FLOW_EN (1 << 7) +#define S17_LINK_EN (1 << 9) +#define S17_FLOW_LINK_EN (1 << 12) +#define S17_PORT_STATUS_DEFAULT (S17_SPEED_1000M | S17_TXMAC_EN | \ + S17_RXMAC_EN | S17_TX_FLOW_EN | \ + S17_RX_FLOW_EN | S17_DUPLEX_FULL | \ + S17_TX_HALF_FLOW_EN) + +#define S17_PORT_STATUS_AZ_DEFAULT (S17_SPEED_1000M | S17_TXMAC_EN | \ + S17_RXMAC_EN | S17_TX_FLOW_EN | \ + S17_RX_FLOW_EN | S17_DUPLEX_FULL) + + +#define S17_HDRLENGTH_SEL (1 << 16) +#define S17_HDR_VALUE 0xAAAA + +#define S17_TXHDR_MODE_NO 0 +#define S17_TXHDR_MODE_MGM 1 +#define S17_TXHDR_MODE_ALL 2 +#define S17_RXHDR_MODE_NO (0 << 2) +#define S17_RXHDR_MODE_MGM (1 << 2) +#define S17_RXHDR_MODE_ALL (2 << 2) + +#define S17_CPU_PORT_EN (1 << 10) +#define S17_PPPOE_REDIR_EN (1 << 8) +#define S17_MIRROR_PORT_SHIFT 4 +#define S17_IGMP_COPY_EN (1 << 3) +#define S17_RIP_COPY_EN (1 << 2) +#define S17_EAPOL_REDIR_EN (1 << 0) + +#define S17_IGMP_JOIN_LEAVE_DP_SHIFT 24 +#define S17_BROAD_DP_SHIFT 16 +#define S17_MULTI_FLOOD_DP_SHIFT 8 +#define S17_UNI_FLOOD_DP_SHIFT 0 +#define S17_IGMP_JOIN_LEAVE_DPALL (0x7f << S17_IGMP_JOIN_LEAVE_DP_SHIFT) +#define S17_BROAD_DPALL (0x7f << S17_BROAD_DP_SHIFT) +#define S17_MULTI_FLOOD_DPALL (0x7f << S17_MULTI_FLOOD_DP_SHIFT) +#define S17_UNI_FLOOD_DPALL (0x7f << S17_UNI_FLOOD_DP_SHIFT) + +#define S17_PWS_CHIP_AR8327 (1 << 30) +#define S17c_PWS_SERDES_ANEG_DISABLE (1 << 7) + +/* S17_PHY_CONTROL fields */ +#define S17_CTRL_SOFTWARE_RESET 0x8000 +#define S17_CTRL_SPEED_LSB 0x2000 +#define S17_CTRL_AUTONEGOTIATION_ENABLE 0x1000 +#define S17_CTRL_RESTART_AUTONEGOTIATION 0x0200 +#define S17_CTRL_SPEED_FULL_DUPLEX 0x0100 +#define S17_CTRL_SPEED_MSB 0x0040 + +/* For EEE_CTRL_REG */ +#define S17_LPI_DISABLE_P1 (1 << 4) +#define S17_LPI_DISABLE_P2 (1 << 6) +#define S17_LPI_DISABLE_P3 (1 << 8) +#define S17_LPI_DISABLE_P4 (1 << 10) +#define S17_LPI_DISABLE_P5 (1 << 12) +#define S17_LPI_DISABLE_ALL 0x1550 + +/* For MMD register control */ +#define S17_MMD_FUNC_ADDR (0 << 14) +#define S17_MMD_FUNC_DATA (1 << 14) +#define S17_MMD_FUNC_DATA_2 (2 << 14) +#define S17_MMD_FUNC_DATA_3 (3 << 14) + +/* For phyInfo_t azFeature */ +#define S17_8023AZ_PHY_ENABLED (1 << 0) +#define S17_8023AZ_PHY_LINKED (1 << 1) + +/* Queue Management registe fields */ +#define S17_HOL_CTRL0_LAN 0x2a008888 /* egress priority 8, eg_portq = 0x2a */ +#define S17_HOL_CTRL0_WAN 0x2a666666 /* egress priority 6, eg_portq = 0x2a */ +#define S17_HOL_CTRL1_DEFAULT 0xc6 /* enable HOL control */ + +/* Packet Edit register fields */ +#define S17_ROUTER_EG_UNMOD 0x0 /* unmodified */ +#define S17_ROUTER_EG_WOVLAN 0x1 /* without VLAN */ +#define S17_ROUTER_EG_WVLAN 0x2 /* with VLAN */ +#define S17_ROUTER_EG_UNTOUCH 0x3 /* untouched */ +#define S17_ROUTER_EG_MODE_DEFAULT 0x01111111 /* all ports without VLAN */ + +#define S17_RESET_DONE(phy_control) \ + (((phy_control) & (S17_CTRL_SOFTWARE_RESET)) == 0) + +/* Phy status fields */ +#define S17_STATUS_AUTO_NEG_DONE 0x0020 + +#define S17_AUTONEG_DONE(ip_phy_status) \ + (((ip_phy_status) & \ + (S17_STATUS_AUTO_NEG_DONE)) == \ + (S17_STATUS_AUTO_NEG_DONE)) + +/* Link Partner ability */ +#define S17_LINK_100BASETX_FULL_DUPLEX 0x0100 +#define S17_LINK_100BASETX 0x0080 +#define S17_LINK_10BASETX_FULL_DUPLEX 0x0040 +#define S17_LINK_10BASETX 0x0020 + +/* Advertisement register. */ +#define S17_ADVERTISE_NEXT_PAGE 0x8000 +#define S17_ADVERTISE_ASYM_PAUSE 0x0800 +#define S17_ADVERTISE_PAUSE 0x0400 +#define S17_ADVERTISE_100FULL 0x0100 +#define S17_ADVERTISE_100HALF 0x0080 +#define S17_ADVERTISE_10FULL 0x0040 +#define S17_ADVERTISE_10HALF 0x0020 + +#define S17_ADVERTISE_ALL (S17_ADVERTISE_ASYM_PAUSE | S17_ADVERTISE_PAUSE | \ + S17_ADVERTISE_10HALF | S17_ADVERTISE_10FULL | \ + S17_ADVERTISE_100HALF | S17_ADVERTISE_100FULL) + +/* 1000BASET_CONTROL */ +#define S17_ADVERTISE_1000FULL 0x0200 + +/* Phy Specific status fields */ +#define S17_STATUS_LINK_MASK 0xC000 +#define S17_STATUS_LINK_SHIFT 14 +#define S17_STATUS_FULL_DEPLEX 0x2000 +#define S17_STATUS_LINK_PASS 0x0400 +#define S17_STATUS_RESOLVED 0x0800 +#define S17_STATUS_LINK_10M 0 +#define S17_STATUS_LINK_100M 1 +#define S17_STATUS_LINK_1000M 2 + +#define S17_GLOBAL_INT_PHYMASK (1 << 15) + +#define S17_PHY_LINK_UP 0x400 +#define S17_PHY_LINK_DOWN 0x800 +#define S17_PHY_LINK_DUPLEX_CHANGE 0x2000 +#define S17_PHY_LINK_SPEED_CHANGE 0x4000 + +/* For Port flow control registers */ +#define S17_PORT_FLCTL_XON_DEFAULT (0x3a << 16) +#define S17_PORT_FLCTL_XOFF_DEFAULT (0x4a) + +/* Module enable Register */ +#define S17_MODULE_L3_EN (1 << 2) +#define S17_MODULE_ACL_EN (1 << 1) +#define S17_MODULE_MIB_EN (1 << 0) + +/* MIB Function Register 1 */ +#define S17_MIB_FUNC_ALL (3 << 24) +#define S17_MIB_CPU_KEEP (1 << 20) +#define S17_MIB_BUSY (1 << 17) +#define S17_MIB_AT_HALF_EN (1 << 16) +#define S17_MIB_TIMER_DEFAULT 0x100 + +#define S17_MAC_MAX 7 + +/* MAC power selector bit definitions */ +#define S17_RGMII0_1_8V (1 << 19) +#define S17_RGMII1_1_8V (1 << 18) + +/* SGMII_CTRL bit definitions */ +#define S17c_SGMII_EN_LCKDT (1 << 0) +#define S17c_SGMII_EN_PLL (1 << 1) +#define S17c_SGMII_EN_RX (1 << 2) +#define S17c_SGMII_EN_TX (1 << 3) +#define S17c_SGMII_EN_SD (1 << 4) +#define S17c_SGMII_BW_HIGH (1 << 6) +#define S17c_SGMII_SEL_CLK125M (1 << 7) +#define S17c_SGMII_TXDR_CTRL_600mV (1 << 10) +#define S17c_SGMII_CDR_BW_8 (3 << 13) +#define S17c_SGMII_DIS_AUTO_LPI_25M (1 << 16) +#define S17c_SGMII_MODE_CTRL_SGMII_PHY (1 << 22) +#define S17c_SGMII_PAUSE_SG_TX_EN_25M (1 << 24) +#define S17c_SGMII_ASYM_PAUSE_25M (1 << 25) +#define S17c_SGMII_PAUSE_25M (1 << 26) +#define S17c_SGMII_HALF_DUPLEX_25M (1 << 30) +#define S17c_SGMII_FULL_DUPLEX_25M (1 << 31) + +#ifndef BOOL +#define BOOL int +#endif + +/*add feature define here*/ + +#ifdef CONFIG_AR7242_S17_PHY +#undef HEADER_REG_CONF +#undef HEADER_EN +#endif + +#define LINK_UP 0x400 +#define LINK(_data) (_data & LINK_UP)? "Up" : "Down" +#define DUPLEX(_data) (_data & 0x2000)?\ + "Full duplex" : "Half duplex" +#define SPEED(_data) ((_data & 0xC000) >> 12) +#define SPEED_1000M (1 << 3) +#define SPEED_100M (1 << 2) + +#define S17C_MAX_PORT 4 +typedef struct { + u32 mac_pwr; + int port_count; + int chip_detect; + u32 port_phy_address[S17C_MAX_PORT]; +} ipq_s17c_swt_cfg_t; + +#endif + diff --git a/drivers/net/ipq_common/ipq_phy.h b/drivers/net/ipq_common/ipq_phy.h index 593ecf9f92..e1bf906e84 100755 --- a/drivers/net/ipq_common/ipq_phy.h +++ b/drivers/net/ipq_common/ipq_phy.h @@ -16,6 +16,9 @@ #include #include +#ifdef CONFIG_ATHRS17C_SWITCH +#include "athrs17_phy.h" +#endif #define PHY_MAX 6 #define IPQ9574_PHY_MAX 6 @@ -40,6 +43,7 @@ #define GP_PU_RES(x) (x << 13) #define QCA8075_RST_VAL (GP_PULL_DOWN | GP_OE_EN | \ GP_VM_EN | GP_PU_RES(2)) +#define QCA8337_PHY 0x004DD036 #define QCA8075_PHY_V1_0_5P 0x004DD0B0 #define QCA8075_PHY_V1_1_5P 0x004DD0B1 #define QCA8075_PHY_V1_1_2P 0x004DD0B2 @@ -144,6 +148,7 @@ enum phy_mode { QCA8033_PHY_TYPE = 4, SFP_PHY_TYPE = 5, QCA8084_PHY_TYPE = 6, + ATHRS17C_SWITCH_TYPE = 7, UNUSED_PHY_TYPE = 0xFF, }; diff --git a/include/dt-bindings/qcom/eth-devsoc.h b/include/dt-bindings/qcom/eth-devsoc.h index 9f676c1fa6..d87238c869 100644 --- a/include/dt-bindings/qcom/eth-devsoc.h +++ b/include/dt-bindings/qcom/eth-devsoc.h @@ -47,6 +47,7 @@ #define QCA8033_PHY_TYPE 0x4 #define SFP_PHY_TYPE 0x5 #define QCA8084_PHY_TYPE 0x6 +#define ATHRS17C_SWITCH_TYPE 0x7 #define UNUSED_PHY_TYPE 0xFF #endif From 5eaf4d7afab5292b335401aa5269abe820894e13 Mon Sep 17 00:00:00 2001 From: Ram Kumar D Date: Tue, 28 Jun 2022 14:21:35 +0530 Subject: [PATCH 4/4] board: arm: devsoc: add QCA8033 ethernet PHY support Change-Id: Ifdb6a372c54f3cf1865e7463ecf6dea65495f29e Signed-off-by: Ram Kumar D --- board/devsoc/Kconfig | 3 +++ configs/devsoc_defconfig | 1 + 2 files changed, 4 insertions(+) diff --git a/board/devsoc/Kconfig b/board/devsoc/Kconfig index 331dbb2c51..25f1de7852 100644 --- a/board/devsoc/Kconfig +++ b/board/devsoc/Kconfig @@ -42,6 +42,9 @@ config IPQ_TINY_SPI_NOR config ART_COMPRESSED bool "Enable uncompress support" +config QCA8033_PHY + bool "Enable QCA8033 PHY support" + config QCA8081_PHY bool "Enable QCA8081 PHY support" diff --git a/configs/devsoc_defconfig b/configs/devsoc_defconfig index 74ad98c326..08f4094a04 100644 --- a/configs/devsoc_defconfig +++ b/configs/devsoc_defconfig @@ -101,6 +101,7 @@ CONFIG_CMD_SETEXPR=y # Network PHY # CONFIG_IPQ_QCA_AQUANTIA_PHY=y +CONFIG_QCA8033_PHY=y CONFIG_QCA8081_PHY=y CONFIG_QCA8084_PHY=y CONFIG_ATHRS17C_SWITCH=y