xref: /linux/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c (revision 60675d4ca1ef0857e44eba5849b74a3a998d0c0f)
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