1fc1992baSJijie Shao // SPDX-License-Identifier: GPL-2.0+ 2fc1992baSJijie Shao // Copyright (c) 2024 Hisilicon Limited. 3fc1992baSJijie Shao 4fc1992baSJijie Shao #include <linux/etherdevice.h> 5fc1992baSJijie Shao #include <linux/ethtool.h> 6fc1992baSJijie Shao #include <linux/iopoll.h> 7fc1992baSJijie Shao #include <linux/minmax.h> 8fc1992baSJijie Shao #include "hbg_common.h" 9fc1992baSJijie Shao #include "hbg_hw.h" 10fc1992baSJijie Shao #include "hbg_reg.h" 11fc1992baSJijie Shao 12fc1992baSJijie Shao #define HBG_HW_EVENT_WAIT_TIMEOUT_US (2 * 1000 * 1000) 13fc1992baSJijie Shao #define HBG_HW_EVENT_WAIT_INTERVAL_US (10 * 1000) 14a239b2b1SJijie Shao /* little endian or big endian. 15a239b2b1SJijie Shao * ctrl means packet description, data means skb packet data 16a239b2b1SJijie Shao */ 17a239b2b1SJijie Shao #define HBG_ENDIAN_CTRL_LE_DATA_BE 0x0 18ff4edac6SJijie Shao #define HBG_PCU_FRAME_LEN_PLUS 4 19fc1992baSJijie Shao 20fc1992baSJijie Shao static bool hbg_hw_spec_is_valid(struct hbg_priv *priv) 21fc1992baSJijie Shao { 22fc1992baSJijie Shao return hbg_reg_read(priv, HBG_REG_SPEC_VALID_ADDR) && 23fc1992baSJijie Shao !hbg_reg_read(priv, HBG_REG_EVENT_REQ_ADDR); 24fc1992baSJijie Shao } 25fc1992baSJijie Shao 26fc1992baSJijie Shao int hbg_hw_event_notify(struct hbg_priv *priv, 27fc1992baSJijie Shao enum hbg_hw_event_type event_type) 28fc1992baSJijie Shao { 29fc1992baSJijie Shao bool is_valid; 30fc1992baSJijie Shao int ret; 31fc1992baSJijie Shao 32fc1992baSJijie Shao if (test_and_set_bit(HBG_NIC_STATE_EVENT_HANDLING, &priv->state)) 33fc1992baSJijie Shao return -EBUSY; 34fc1992baSJijie Shao 35fc1992baSJijie Shao /* notify */ 36fc1992baSJijie Shao hbg_reg_write(priv, HBG_REG_EVENT_REQ_ADDR, event_type); 37fc1992baSJijie Shao 38fc1992baSJijie Shao ret = read_poll_timeout(hbg_hw_spec_is_valid, is_valid, is_valid, 39fc1992baSJijie Shao HBG_HW_EVENT_WAIT_INTERVAL_US, 40fc1992baSJijie Shao HBG_HW_EVENT_WAIT_TIMEOUT_US, 41fc1992baSJijie Shao HBG_HW_EVENT_WAIT_INTERVAL_US, priv); 42fc1992baSJijie Shao 43fc1992baSJijie Shao clear_bit(HBG_NIC_STATE_EVENT_HANDLING, &priv->state); 44fc1992baSJijie Shao 45fc1992baSJijie Shao if (ret) 46fc1992baSJijie Shao dev_err(&priv->pdev->dev, 47fc1992baSJijie Shao "event %d wait timeout\n", event_type); 48fc1992baSJijie Shao 49fc1992baSJijie Shao return ret; 50fc1992baSJijie Shao } 51fc1992baSJijie Shao 52fc1992baSJijie Shao static int hbg_hw_dev_specs_init(struct hbg_priv *priv) 53fc1992baSJijie Shao { 54fc1992baSJijie Shao struct hbg_dev_specs *specs = &priv->dev_specs; 55fc1992baSJijie Shao u64 mac_addr; 56fc1992baSJijie Shao 57fc1992baSJijie Shao if (!hbg_hw_spec_is_valid(priv)) { 58fc1992baSJijie Shao dev_err(&priv->pdev->dev, "dev_specs not init\n"); 59fc1992baSJijie Shao return -EINVAL; 60fc1992baSJijie Shao } 61fc1992baSJijie Shao 62fc1992baSJijie Shao specs->mac_id = hbg_reg_read(priv, HBG_REG_MAC_ID_ADDR); 63fc1992baSJijie Shao specs->phy_addr = hbg_reg_read(priv, HBG_REG_PHY_ID_ADDR); 64fc1992baSJijie Shao specs->mdio_frequency = hbg_reg_read(priv, HBG_REG_MDIO_FREQ_ADDR); 65fc1992baSJijie Shao specs->max_mtu = hbg_reg_read(priv, HBG_REG_MAX_MTU_ADDR); 66fc1992baSJijie Shao specs->min_mtu = hbg_reg_read(priv, HBG_REG_MIN_MTU_ADDR); 67fc1992baSJijie Shao specs->vlan_layers = hbg_reg_read(priv, HBG_REG_VLAN_LAYERS_ADDR); 68fc1992baSJijie Shao specs->rx_fifo_num = hbg_reg_read(priv, HBG_REG_RX_FIFO_NUM_ADDR); 69fc1992baSJijie Shao specs->tx_fifo_num = hbg_reg_read(priv, HBG_REG_TX_FIFO_NUM_ADDR); 70fc1992baSJijie Shao mac_addr = hbg_reg_read64(priv, HBG_REG_MAC_ADDR_ADDR); 71fc1992baSJijie Shao u64_to_ether_addr(mac_addr, (u8 *)specs->mac_addr.sa_data); 72fc1992baSJijie Shao 73fc1992baSJijie Shao if (!is_valid_ether_addr((u8 *)specs->mac_addr.sa_data)) 74fc1992baSJijie Shao return -EADDRNOTAVAIL; 75fc1992baSJijie Shao 7640735e75SJijie Shao specs->max_frame_len = HBG_PCU_CACHE_LINE_SIZE + specs->max_mtu; 77*f72e2559SJijie Shao specs->rx_buf_size = HBG_PACKET_HEAD_SIZE + specs->max_frame_len; 78fc1992baSJijie Shao return 0; 79fc1992baSJijie Shao } 80fc1992baSJijie Shao 814d089035SJijie Shao u32 hbg_hw_get_irq_status(struct hbg_priv *priv) 824d089035SJijie Shao { 834d089035SJijie Shao u32 status; 844d089035SJijie Shao 854d089035SJijie Shao status = hbg_reg_read(priv, HBG_REG_CF_INTRPT_STAT_ADDR); 864d089035SJijie Shao 874d089035SJijie Shao hbg_field_modify(status, HBG_INT_MSK_TX_B, 884d089035SJijie Shao hbg_reg_read(priv, HBG_REG_CF_IND_TXINT_STAT_ADDR)); 894d089035SJijie Shao hbg_field_modify(status, HBG_INT_MSK_RX_B, 904d089035SJijie Shao hbg_reg_read(priv, HBG_REG_CF_IND_RXINT_STAT_ADDR)); 914d089035SJijie Shao 924d089035SJijie Shao return status; 934d089035SJijie Shao } 944d089035SJijie Shao 954d089035SJijie Shao void hbg_hw_irq_clear(struct hbg_priv *priv, u32 mask) 964d089035SJijie Shao { 974d089035SJijie Shao if (FIELD_GET(HBG_INT_MSK_TX_B, mask)) 984d089035SJijie Shao return hbg_reg_write(priv, HBG_REG_CF_IND_TXINT_CLR_ADDR, 0x1); 994d089035SJijie Shao 1004d089035SJijie Shao if (FIELD_GET(HBG_INT_MSK_RX_B, mask)) 1014d089035SJijie Shao return hbg_reg_write(priv, HBG_REG_CF_IND_RXINT_CLR_ADDR, 0x1); 1024d089035SJijie Shao 1034d089035SJijie Shao return hbg_reg_write(priv, HBG_REG_CF_INTRPT_CLR_ADDR, mask); 1044d089035SJijie Shao } 1054d089035SJijie Shao 1064d089035SJijie Shao bool hbg_hw_irq_is_enabled(struct hbg_priv *priv, u32 mask) 1074d089035SJijie Shao { 1084d089035SJijie Shao if (FIELD_GET(HBG_INT_MSK_TX_B, mask)) 1094d089035SJijie Shao return hbg_reg_read(priv, HBG_REG_CF_IND_TXINT_MSK_ADDR); 1104d089035SJijie Shao 1114d089035SJijie Shao if (FIELD_GET(HBG_INT_MSK_RX_B, mask)) 1124d089035SJijie Shao return hbg_reg_read(priv, HBG_REG_CF_IND_RXINT_MSK_ADDR); 1134d089035SJijie Shao 1144d089035SJijie Shao return hbg_reg_read(priv, HBG_REG_CF_INTRPT_MSK_ADDR) & mask; 1154d089035SJijie Shao } 1164d089035SJijie Shao 1174d089035SJijie Shao void hbg_hw_irq_enable(struct hbg_priv *priv, u32 mask, bool enable) 1184d089035SJijie Shao { 1194d089035SJijie Shao u32 value; 1204d089035SJijie Shao 1214d089035SJijie Shao if (FIELD_GET(HBG_INT_MSK_TX_B, mask)) 1224d089035SJijie Shao return hbg_reg_write(priv, 1234d089035SJijie Shao HBG_REG_CF_IND_TXINT_MSK_ADDR, enable); 1244d089035SJijie Shao 1254d089035SJijie Shao if (FIELD_GET(HBG_INT_MSK_RX_B, mask)) 1264d089035SJijie Shao return hbg_reg_write(priv, 1274d089035SJijie Shao HBG_REG_CF_IND_RXINT_MSK_ADDR, enable); 1284d089035SJijie Shao 1294d089035SJijie Shao value = hbg_reg_read(priv, HBG_REG_CF_INTRPT_MSK_ADDR); 1304d089035SJijie Shao if (enable) 1314d089035SJijie Shao value |= mask; 1324d089035SJijie Shao else 1334d089035SJijie Shao value &= ~mask; 1344d089035SJijie Shao 1354d089035SJijie Shao hbg_reg_write(priv, HBG_REG_CF_INTRPT_MSK_ADDR, value); 1364d089035SJijie Shao } 1374d089035SJijie Shao 138ff4edac6SJijie Shao void hbg_hw_set_uc_addr(struct hbg_priv *priv, u64 mac_addr) 139ff4edac6SJijie Shao { 140ff4edac6SJijie Shao hbg_reg_write64(priv, HBG_REG_STATION_ADDR_LOW_2_ADDR, mac_addr); 141ff4edac6SJijie Shao } 142ff4edac6SJijie Shao 143ff4edac6SJijie Shao static void hbg_hw_set_pcu_max_frame_len(struct hbg_priv *priv, 144ff4edac6SJijie Shao u16 max_frame_len) 145ff4edac6SJijie Shao { 146ff4edac6SJijie Shao max_frame_len = max_t(u32, max_frame_len, ETH_DATA_LEN); 147ff4edac6SJijie Shao 148ff4edac6SJijie Shao /* lower two bits of value must be set to 0 */ 149ff4edac6SJijie Shao max_frame_len = round_up(max_frame_len, HBG_PCU_FRAME_LEN_PLUS); 150ff4edac6SJijie Shao 151ff4edac6SJijie Shao hbg_reg_write_field(priv, HBG_REG_MAX_FRAME_LEN_ADDR, 152ff4edac6SJijie Shao HBG_REG_MAX_FRAME_LEN_M, max_frame_len); 153ff4edac6SJijie Shao } 154ff4edac6SJijie Shao 155ff4edac6SJijie Shao static void hbg_hw_set_mac_max_frame_len(struct hbg_priv *priv, 156ff4edac6SJijie Shao u16 max_frame_size) 157ff4edac6SJijie Shao { 158ff4edac6SJijie Shao hbg_reg_write_field(priv, HBG_REG_MAX_FRAME_SIZE_ADDR, 159ff4edac6SJijie Shao HBG_REG_MAX_FRAME_LEN_M, max_frame_size); 160ff4edac6SJijie Shao } 161ff4edac6SJijie Shao 162ff4edac6SJijie Shao void hbg_hw_set_mtu(struct hbg_priv *priv, u16 mtu) 163ff4edac6SJijie Shao { 164ff4edac6SJijie Shao hbg_hw_set_pcu_max_frame_len(priv, mtu); 165ff4edac6SJijie Shao hbg_hw_set_mac_max_frame_len(priv, mtu); 166ff4edac6SJijie Shao } 167ff4edac6SJijie Shao 168ff4edac6SJijie Shao void hbg_hw_mac_enable(struct hbg_priv *priv, u32 enable) 169ff4edac6SJijie Shao { 170ff4edac6SJijie Shao hbg_reg_write_field(priv, HBG_REG_PORT_ENABLE_ADDR, 171ff4edac6SJijie Shao HBG_REG_PORT_ENABLE_TX_B, enable); 172ff4edac6SJijie Shao hbg_reg_write_field(priv, HBG_REG_PORT_ENABLE_ADDR, 173ff4edac6SJijie Shao HBG_REG_PORT_ENABLE_RX_B, enable); 174ff4edac6SJijie Shao } 175ff4edac6SJijie Shao 17640735e75SJijie Shao u32 hbg_hw_get_fifo_used_num(struct hbg_priv *priv, enum hbg_dir dir) 17740735e75SJijie Shao { 17840735e75SJijie Shao if (dir & HBG_DIR_TX) 17940735e75SJijie Shao return hbg_reg_read_field(priv, HBG_REG_CF_CFF_DATA_NUM_ADDR, 18040735e75SJijie Shao HBG_REG_CF_CFF_DATA_NUM_ADDR_TX_M); 18140735e75SJijie Shao 182*f72e2559SJijie Shao if (dir & HBG_DIR_RX) 183*f72e2559SJijie Shao return hbg_reg_read_field(priv, HBG_REG_CF_CFF_DATA_NUM_ADDR, 184*f72e2559SJijie Shao HBG_REG_CF_CFF_DATA_NUM_ADDR_RX_M); 185*f72e2559SJijie Shao 18640735e75SJijie Shao return 0; 18740735e75SJijie Shao } 18840735e75SJijie Shao 18940735e75SJijie Shao void hbg_hw_set_tx_desc(struct hbg_priv *priv, struct hbg_tx_desc *tx_desc) 19040735e75SJijie Shao { 19140735e75SJijie Shao hbg_reg_write(priv, HBG_REG_TX_CFF_ADDR_0_ADDR, tx_desc->word0); 19240735e75SJijie Shao hbg_reg_write(priv, HBG_REG_TX_CFF_ADDR_1_ADDR, tx_desc->word1); 19340735e75SJijie Shao hbg_reg_write(priv, HBG_REG_TX_CFF_ADDR_2_ADDR, tx_desc->word2); 19440735e75SJijie Shao hbg_reg_write(priv, HBG_REG_TX_CFF_ADDR_3_ADDR, tx_desc->word3); 19540735e75SJijie Shao } 19640735e75SJijie Shao 197*f72e2559SJijie Shao void hbg_hw_fill_buffer(struct hbg_priv *priv, u32 buffer_dma_addr) 198*f72e2559SJijie Shao { 199*f72e2559SJijie Shao hbg_reg_write(priv, HBG_REG_RX_CFF_ADDR_ADDR, buffer_dma_addr); 200*f72e2559SJijie Shao } 201*f72e2559SJijie Shao 202a239b2b1SJijie Shao void hbg_hw_adjust_link(struct hbg_priv *priv, u32 speed, u32 duplex) 203a239b2b1SJijie Shao { 204a239b2b1SJijie Shao hbg_reg_write_field(priv, HBG_REG_PORT_MODE_ADDR, 205a239b2b1SJijie Shao HBG_REG_PORT_MODE_M, speed); 206a239b2b1SJijie Shao hbg_reg_write_field(priv, HBG_REG_DUPLEX_TYPE_ADDR, 207a239b2b1SJijie Shao HBG_REG_DUPLEX_B, duplex); 208a239b2b1SJijie Shao } 209a239b2b1SJijie Shao 210a239b2b1SJijie Shao static void hbg_hw_init_transmit_ctrl(struct hbg_priv *priv) 211a239b2b1SJijie Shao { 212a239b2b1SJijie Shao u32 ctrl = 0; 213a239b2b1SJijie Shao 214a239b2b1SJijie Shao ctrl |= FIELD_PREP(HBG_REG_TRANSMIT_CTRL_AN_EN_B, HBG_STATUS_ENABLE); 215a239b2b1SJijie Shao ctrl |= FIELD_PREP(HBG_REG_TRANSMIT_CTRL_CRC_ADD_B, HBG_STATUS_ENABLE); 216a239b2b1SJijie Shao ctrl |= FIELD_PREP(HBG_REG_TRANSMIT_CTRL_PAD_EN_B, HBG_STATUS_ENABLE); 217a239b2b1SJijie Shao 218a239b2b1SJijie Shao hbg_reg_write(priv, HBG_REG_TRANSMIT_CTRL_ADDR, ctrl); 219a239b2b1SJijie Shao } 220a239b2b1SJijie Shao 221a239b2b1SJijie Shao static void hbg_hw_init_rx_ctrl(struct hbg_priv *priv) 222a239b2b1SJijie Shao { 223a239b2b1SJijie Shao u32 ctrl = 0; 224a239b2b1SJijie Shao 225a239b2b1SJijie Shao ctrl |= FIELD_PREP(HBG_REG_RX_CTRL_RX_GET_ADDR_MODE_B, 226a239b2b1SJijie Shao HBG_STATUS_ENABLE); 227a239b2b1SJijie Shao ctrl |= FIELD_PREP(HBG_REG_RX_CTRL_TIME_INF_EN_B, HBG_STATUS_DISABLE); 228a239b2b1SJijie Shao ctrl |= FIELD_PREP(HBG_REG_RX_CTRL_RXBUF_1ST_SKIP_SIZE_M, HBG_RX_SKIP1); 229a239b2b1SJijie Shao ctrl |= FIELD_PREP(HBG_REG_RX_CTRL_RXBUF_1ST_SKIP_SIZE2_M, 230a239b2b1SJijie Shao HBG_RX_SKIP2); 231a239b2b1SJijie Shao ctrl |= FIELD_PREP(HBG_REG_RX_CTRL_RX_ALIGN_NUM_M, NET_IP_ALIGN); 232a239b2b1SJijie Shao ctrl |= FIELD_PREP(HBG_REG_RX_CTRL_PORT_NUM, priv->dev_specs.mac_id); 233a239b2b1SJijie Shao 234a239b2b1SJijie Shao hbg_reg_write(priv, HBG_REG_RX_CTRL_ADDR, ctrl); 235a239b2b1SJijie Shao } 236a239b2b1SJijie Shao 237a239b2b1SJijie Shao static void hbg_hw_init_rx_control(struct hbg_priv *priv) 238a239b2b1SJijie Shao { 239a239b2b1SJijie Shao hbg_hw_init_rx_ctrl(priv); 240a239b2b1SJijie Shao 241a239b2b1SJijie Shao /* parse from L2 layer */ 242a239b2b1SJijie Shao hbg_reg_write_field(priv, HBG_REG_RX_PKT_MODE_ADDR, 243a239b2b1SJijie Shao HBG_REG_RX_PKT_MODE_PARSE_MODE_M, 0x1); 244a239b2b1SJijie Shao 245a239b2b1SJijie Shao hbg_reg_write_field(priv, HBG_REG_RECV_CTRL_ADDR, 246a239b2b1SJijie Shao HBG_REG_RECV_CTRL_STRIP_PAD_EN_B, 247a239b2b1SJijie Shao HBG_STATUS_ENABLE); 248a239b2b1SJijie Shao hbg_reg_write_field(priv, HBG_REG_RX_BUF_SIZE_ADDR, 249a239b2b1SJijie Shao HBG_REG_RX_BUF_SIZE_M, priv->dev_specs.rx_buf_size); 250a239b2b1SJijie Shao hbg_reg_write_field(priv, HBG_REG_CF_CRC_STRIP_ADDR, 251a239b2b1SJijie Shao HBG_REG_CF_CRC_STRIP_B, HBG_STATUS_DISABLE); 252a239b2b1SJijie Shao } 253a239b2b1SJijie Shao 254fc1992baSJijie Shao int hbg_hw_init(struct hbg_priv *priv) 255fc1992baSJijie Shao { 256a239b2b1SJijie Shao int ret; 257a239b2b1SJijie Shao 258a239b2b1SJijie Shao ret = hbg_hw_dev_specs_init(priv); 259a239b2b1SJijie Shao if (ret) 260a239b2b1SJijie Shao return ret; 261a239b2b1SJijie Shao 262a239b2b1SJijie Shao hbg_reg_write_field(priv, HBG_REG_BUS_CTRL_ADDR, 263a239b2b1SJijie Shao HBG_REG_BUS_CTRL_ENDIAN_M, 264a239b2b1SJijie Shao HBG_ENDIAN_CTRL_LE_DATA_BE); 265a239b2b1SJijie Shao hbg_reg_write_field(priv, HBG_REG_MODE_CHANGE_EN_ADDR, 266a239b2b1SJijie Shao HBG_REG_MODE_CHANGE_EN_B, HBG_STATUS_ENABLE); 267a239b2b1SJijie Shao 268a239b2b1SJijie Shao hbg_hw_init_rx_control(priv); 269a239b2b1SJijie Shao hbg_hw_init_transmit_ctrl(priv); 270a239b2b1SJijie Shao return 0; 271fc1992baSJijie Shao } 272