1 /*
2 * Copyright (c) 2023-2024 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include "hpm_tsw_drv.h"
9 #include "hpm_swap.h"
10
tsw_ep_set_mdio_config(TSW_Type * ptr,uint8_t port,uint8_t clk_div)11 hpm_stat_t tsw_ep_set_mdio_config(TSW_Type *ptr, uint8_t port, uint8_t clk_div)
12 {
13 ptr->TSNPORT[port].MAC[TSW_RXFIFO_E1].MAC_MDIO_CFG = TSW_TSNPORT_MAC_MAC_MDIO_CFG_ENABLE_MASK | TSW_TSNPORT_MAC_MAC_MDIO_CFG_MDC_CLKDIV_SET(clk_div);
14
15 return status_success;
16 }
17
tsw_ep_mdio_read(TSW_Type * ptr,uint8_t port,uint32_t phy_addr,uint32_t reg_addr,uint16_t * data)18 hpm_stat_t tsw_ep_mdio_read(TSW_Type *ptr, uint8_t port, uint32_t phy_addr, uint32_t reg_addr, uint16_t *data)
19 {
20 if (data == NULL) {
21 return status_invalid_argument;
22 }
23
24 ptr->TSNPORT[port].MAC[TSW_RXFIFO_E1].MAC_MDIO_CTRL = TSW_TSNPORT_MAC_MAC_MDIO_CTRL_OP_SET(MAC_MDIO_CTRL_OP_RD)
25 | TSW_TSNPORT_MAC_MAC_MDIO_CTRL_PHYAD_SET(phy_addr)
26 | TSW_TSNPORT_MAC_MAC_MDIO_CTRL_REGAD_SET(reg_addr)
27 | TSW_TSNPORT_MAC_MAC_MDIO_CTRL_INIT_SET(1);
28
29 do {
30
31 } while (TSW_TSNPORT_MAC_MAC_MDIO_CTRL_READY_GET(ptr->TSNPORT[port].MAC[TSW_RXFIFO_E1].MAC_MDIO_CTRL) == 0);
32
33
34 *data = TSW_TSNPORT_MAC_MAC_MDIO_RD_DATA_RD_DATA_GET(ptr->TSNPORT[port].MAC[TSW_RXFIFO_E1].MAC_MDIO_RD_DATA);
35
36 return status_success;
37 }
38
tsw_ep_mdio_write(TSW_Type * ptr,uint8_t port,uint32_t phy_addr,uint32_t reg_addr,uint16_t data)39 hpm_stat_t tsw_ep_mdio_write(TSW_Type *ptr, uint8_t port, uint32_t phy_addr, uint32_t reg_addr, uint16_t data)
40 {
41 ptr->TSNPORT[port].MAC[TSW_RXFIFO_E1].MAC_MDIO_WR_DATA = data;
42 ptr->TSNPORT[port].MAC[TSW_RXFIFO_E1].MAC_MDIO_CTRL = TSW_TSNPORT_MAC_MAC_MDIO_CTRL_OP_SET(MAC_MDIO_CTRL_OP_WR)
43 | TSW_TSNPORT_MAC_MAC_MDIO_CTRL_PHYAD_SET(phy_addr)
44 | TSW_TSNPORT_MAC_MAC_MDIO_CTRL_REGAD_SET(reg_addr)
45 | TSW_TSNPORT_MAC_MAC_MDIO_CTRL_INIT_SET(1);
46
47 do {
48
49 } while (TSW_TSNPORT_MAC_MAC_MDIO_CTRL_READY_GET(ptr->TSNPORT[port].MAC[TSW_RXFIFO_E1].MAC_MDIO_CTRL) == 0);
50
51 return status_success;
52 }
53
tsw_ep_enable_mac_ctrl(TSW_Type * ptr,uint8_t port,uint8_t mac_type,bool enable)54 hpm_stat_t tsw_ep_enable_mac_ctrl(TSW_Type *ptr, uint8_t port, uint8_t mac_type, bool enable)
55 {
56 uint32_t temp;
57
58 temp = ptr->TSNPORT[port].MAC[mac_type].MAC_MAC_CTRL;
59 temp &= ~(TSW_TSNPORT_MAC_MAC_MAC_CTRL_TX_EN_MASK | TSW_TSNPORT_MAC_MAC_MAC_CTRL_RX_EN_MASK);
60 temp |= TSW_TSNPORT_MAC_MAC_MAC_CTRL_TX_EN_SET(enable) | TSW_TSNPORT_MAC_MAC_MAC_CTRL_RX_EN_SET(enable);
61
62 ptr->TSNPORT[port].MAC[mac_type].MAC_MAC_CTRL = temp;
63
64 if (!enable) {
65 do {
66 temp = ptr->TSNPORT[port].MAC[mac_type].MAC_MAC_CTRL;
67 } while (TSW_TSNPORT_MAC_MAC_MAC_CTRL_RX_EN_GET(temp) || TSW_TSNPORT_MAC_MAC_MAC_CTRL_TX_EN_GET(temp));
68 }
69
70 return status_success;
71 }
72
tsw_ep_set_mac_addr(TSW_Type * ptr,uint8_t port,uint8_t * mac_addr,bool promisc)73 hpm_stat_t tsw_ep_set_mac_addr(TSW_Type *ptr, uint8_t port, uint8_t *mac_addr, bool promisc)
74 {
75 uint32_t temp;
76
77 if (mac_addr == NULL) {
78 return status_invalid_argument;
79 }
80
81 /* MAC must be disabled when changing mode */
82 temp = ptr->TSNPORT[port].MAC[TSW_RXFIFO_E1].MAC_MAC_CTRL;
83 if (TSW_TSNPORT_MAC_MAC_MAC_CTRL_RX_EN_GET(temp) || TSW_TSNPORT_MAC_MAC_MAC_CTRL_TX_EN_GET(temp)) {
84 return status_fail;
85 }
86
87 ptr->TSNPORT[port].MAC[TSW_RXFIFO_E1].MAC_MACADDR_L = MAC_LO(mac_addr);
88 ptr->TSNPORT[port].MAC[TSW_RXFIFO_E1].MAC_MACADDR_H = MAC_HI(mac_addr) | TSW_TSNPORT_MAC_MAC_MACADDR_H_PROMISC_SET(promisc);
89
90 return status_success;
91 }
92
tsw_ep_set_mac_mode(TSW_Type * ptr,uint8_t port,uint8_t gmii)93 hpm_stat_t tsw_ep_set_mac_mode(TSW_Type *ptr, uint8_t port, uint8_t gmii)
94 {
95 uint32_t temp;
96
97 /* MAC must be disabled when changing mode */
98 temp = ptr->TSNPORT[port].MAC[TSW_RXFIFO_E1].MAC_MAC_CTRL;
99 if (TSW_TSNPORT_MAC_MAC_MAC_CTRL_RX_EN_GET(temp) || TSW_TSNPORT_MAC_MAC_MAC_CTRL_TX_EN_GET(temp)) {
100 return status_fail;
101 }
102
103 temp &= ~(TSW_TSNPORT_MAC_MAC_MAC_CTRL_CLKSEL_MASK | TSW_TSNPORT_MAC_MAC_MAC_CTRL_PHYSEL_MASK | TSW_TSNPORT_MAC_MAC_MAC_CTRL_GMIIMODE_MASK);
104 temp &= ~TSW_TSNPORT_MAC_MAC_MAC_CTRL_RESSTAT_MASK;
105
106 temp |= TSW_TSNPORT_MAC_MAC_MAC_CTRL_CLKSEL_SET(1)
107 | TSW_TSNPORT_MAC_MAC_MAC_CTRL_PHYSEL_SET(1)
108 | TSW_TSNPORT_MAC_MAC_MAC_CTRL_GMIIMODE_SET(gmii);
109
110 ptr->TSNPORT[port].MAC[TSW_RXFIFO_E1].MAC_MAC_CTRL = temp;
111
112 return status_success;
113 }
114
115 /* data: the start address of data buffer must be aligned with 4 bytes */
116 /* length in bytes */
tsw_send(TSW_Type * ptr,uint32_t * buffer,uint32_t length,uint8_t id)117 hpm_stat_t tsw_send(TSW_Type *ptr, uint32_t *buffer, uint32_t length, uint8_t id)
118 {
119 uint32_t resp;
120
121 /* Enable DMA: Write MM2S DMA CR (Run=1, SOE=0, IRQEN=0) */
122 ptr->MM2S_DMA_CR |= TSW_MM2S_DMA_CR_RUN_MASK | TSW_MM2S_DMA_CR_MXLEN_SET(0xff);
123
124 /* Set ADDRL */
125 ptr->MM2S_ADDRLO = (uint32_t)buffer;
126
127 /* Set Length */
128 ptr->MM2S_LENGTH = length;
129
130 /* Set Ctrl */
131 ptr->MM2S_CTRL &= ~TSW_MM2S_CTRL_ID_MASK;
132 ptr->MM2S_CTRL |= TSW_MM2S_CTRL_GO_MASK | TSW_MM2S_CTRL_ID_SET(id);
133
134 /* Wait for DMA to finish transmission */
135 do {
136
137 } while (TSW_MM2S_DMA_SR_RBUFE_GET(ptr->MM2S_DMA_SR));
138
139 /* Read response */
140 resp = ptr->MM2S_RESP;
141
142 if (TSW_MM2S_RESP_ID_GET(resp) == id) {
143
144
145 /* Check decode error */
146 if (TSW_MM2S_RESP_DECERR_GET(resp)) {
147
148 }
149
150 /* check slave error */
151 if (TSW_MM2S_RESP_SLVERR_GET(resp)) {
152
153 }
154 }
155
156 return status_success;
157 }
158
tsw_recv_setup(TSW_Type * ptr,uint32_t * buffer,uint32_t length,uint8_t id)159 hpm_stat_t tsw_recv_setup(TSW_Type *ptr, uint32_t *buffer, uint32_t length, uint8_t id)
160 {
161 /* Enable DMA-CTRL: Write S2MM_DMA_CR (Run=1, SOE=0, IRQEN=1) */
162 ptr->S2MM_DMA_CR &= ~TSW_S2MM_DMA_CR_SOE_MASK; /* SOE=0 */
163
164 ptr->S2MM_DMA_CR |= TSW_S2MM_DMA_CR_RUN_MASK;
165
166 /* Set ADDRL */
167 ptr->S2MM_ADDRLO = (uint32_t)buffer;
168
169 /* Set Length */
170 ptr->S2MM_LENGTH = length;
171
172 /* Set Ctrl */
173 ptr->S2MM_CTRL &= ~TSW_S2MM_CTRL_ID_MASK;
174 ptr->S2MM_CTRL |= TSW_S2MM_CTRL_GO_MASK | TSW_S2MM_CTRL_ID_SET(id);
175
176 return status_success;
177 }
178
tsw_recv(TSW_Type * ptr,uint32_t * buffer,uint32_t length,uint8_t id)179 uint32_t tsw_recv(TSW_Type *ptr, uint32_t *buffer, uint32_t length, uint8_t id)
180 {
181 uint32_t resp;
182
183 /* Wait for DMA to finish transmission */
184 do {
185
186 } while (TSW_S2MM_DMA_SR_RBUFE_GET(ptr->S2MM_DMA_SR));
187
188 HPM_TSW->S2MM_DMA_SR = TSW_S2MM_DMA_SR_IRQ_MASK;
189
190 /* Read response */
191 resp = ptr->S2MM_RESP;
192
193 if (TSW_S2MM_RESP_ID_GET(resp) == id) {
194
195 /* Check decode error */
196 if (TSW_S2MM_RESP_DECERR_GET(resp)) {
197 /* printf("decode error\n"); */
198 }
199
200 /* check slave error */
201 if (TSW_S2MM_RESP_SLVERR_GET(resp)) {
202 /* printf("slave error\n"); */
203 }
204 }
205
206 HPM_TSW->S2MM_CTRL |= TSW_S2MM_CTRL_GO_MASK;
207
208 return ptr->S2MM_LENGTH;
209 }
210
tsw_mac_lookup_bypass(TSW_Type * ptr,uint8_t dst_port)211 void tsw_mac_lookup_bypass(TSW_Type *ptr, uint8_t dst_port)
212 {
213 ptr->LU_MAIN_BYPASS &= ~TSW_LU_MAIN_BYPASS_DEST_MASK;
214 ptr->LU_MAIN_BYPASS |= TSW_LU_MAIN_BYPASS_HIT_MASK | TSW_LU_MAIN_BYPASS_DEST_SET(dst_port);
215 ptr->LU_MAIN_CTRL |= TSW_LU_MAIN_CTRL_BYP_EN_MASK;
216 }
217
tsw_set_cam_vlan_port(TSW_Type * ptr)218 void tsw_set_cam_vlan_port(TSW_Type *ptr)
219 {
220 ptr->APB2AXI_CAM_REQDATA_1 = 0x0f;
221 ptr->APB2AXI_CAM_REQDATA_0 = (1 << 16) /* VID = 1 */
222 | (1 << 8) /* 1: Set one VLAN_PORT entry */
223 | (1 << 0); /* CAM APB2AXIS channel selection. Always 1 for writing to VLAN_PORT table. */
224
225 }
226
227 /**
228 * speed: 00 1000mbps, 11 100mbps, 10 10mpbs
229 * itf: 000 MII; 001 RGMII; 100 RMII
230 */
tsw_port_gpr(TSW_Type * ptr,uint8_t port,uint8_t speed,uint8_t itf,uint8_t tx_dly,uint8_t rx_dly)231 void tsw_port_gpr(TSW_Type *ptr, uint8_t port, uint8_t speed, uint8_t itf, uint8_t tx_dly, uint8_t rx_dly)
232 {
233 ptr->TSNPORT[port].GPR_CTRL0 = TSW_TSNPORT_GPR_CTRL0_RXCLK_DLY_SEL_SET(rx_dly) | TSW_TSNPORT_GPR_CTRL0_TXCLK_DLY_SEL_SET(tx_dly);
234 ptr->TSNPORT[port].GPR_CTRL2 = TSW_TSNPORT_GPR_CTRL2_MAC_SPEED_SET(speed) | TSW_TSNPORT_GPR_CTRL2_PHY_INTF_SEL_SET(itf);
235 }
236
tsw_set_lookup_table(TSW_Type * ptr,uint16_t entry_num,uint8_t dest_port,uint64_t dest_mac)237 void tsw_set_lookup_table(TSW_Type *ptr, uint16_t entry_num, uint8_t dest_port, uint64_t dest_mac)
238 {
239 uint64_t dest_mac_temp;
240
241 /* Create a new ALMEM entry. This will specify what will be done with those detected frames */
242 if (TSW_APB2AXIS_ALMEM_STS_RDY_GET(ptr->APB2AXIS_ALMEM_STS)) {
243
244 ptr->APB2AXIS_ALMEM_REQDATA_1 = TSW_APB2AXIS_ALMEM_REQDATA_1_WR_NRD_SET(1) | TSW_APB2AXIS_ALMEM_REQDATA_1_ENTRY_NUM_SET(entry_num);
245
246 /* set forward to destination port, use PCP field, UTAG 1 and trigger the interface for sending the data */
247 ptr->APB2AXIS_ALMEM_REQDATA_0 = TSW_APB2AXIS_ALMEM_REQDATA_0_UTAG_SET(1) |
248 TSW_APB2AXIS_ALMEM_REQDATA_0_QSEL_SET(0) |
249 TSW_APB2AXIS_ALMEM_REQDATA_0_DROP_SET(0) |
250 TSW_APB2AXIS_ALMEM_REQDATA_0_QUEUE_SET(0) |
251 TSW_APB2AXIS_ALMEM_REQDATA_0_DEST_SET(dest_port);
252 }
253
254 /* Create a new CAM entry */
255 dest_mac_temp = __bswapdi2(dest_mac) >> 16;
256
257 ptr->APB2AXI_CAM_REQDATA_2 = TSW_APB2AXI_CAM_REQDATA_2_VID_SET(1) | TSW_APB2AXI_CAM_REQDATA_2_DESTMAC_HI_SET((dest_mac_temp >> 32));
258 ptr->APB2AXI_CAM_REQDATA_1 = TSW_APB2AXI_CAM_REQDATA_1_DESTMAC_LO_PORT_VEC_SET(dest_mac_temp);
259 ptr->APB2AXI_CAM_REQDATA_0 = TSW_APB2AXI_CAM_REQDATA_0_ENTRY_NUM_SET(entry_num) |
260 TSW_APB2AXI_CAM_REQDATA_0_TYPE_SET(1) | /* Set one DEST_MAC/VLAN_ID entry */
261 TSW_APB2AXI_CAM_REQDATA_0_CH_SET(0); /* CAM APB2AXIS channel selection. Always 0 for writing to DEST_MAC/VLAN_ID */
262
263
264 /* Add a new VLAN_PORT entry (VID 1) */
265 ptr->APB2AXI_CAM_REQDATA_1 = 0x0f;
266 ptr->APB2AXI_CAM_REQDATA_0 = (1 << 16) /* VID = 1 */
267 | (1 << 8) /* 1: Set one VLAN_PORT entry */
268 | (1 << 0); /* CAM APB2AXIS channel selection. Always 1 for writing to VLAN_PORT table. */
269
270 }
271
tsw_set_internal_frame_action(TSW_Type * ptr,uint8_t dest_port)272 void tsw_set_internal_frame_action(TSW_Type *ptr, uint8_t dest_port)
273 {
274 ptr->LU_MAIN_INTF_ACTION &= ~TSW_LU_MAIN_INTF_ACTION_DEST_MASK;
275 ptr->LU_MAIN_INTF_ACTION |= TSW_LU_MAIN_INTF_ACTION_DEST_SET(dest_port);
276 }
277
tsw_set_broadcast_frame_action(TSW_Type * ptr,uint8_t dest_port)278 void tsw_set_broadcast_frame_action(TSW_Type *ptr, uint8_t dest_port)
279 {
280 ptr->LU_MAIN_BC_ACTION &= ~TSW_LU_MAIN_BC_ACTION_DEST_MASK;
281 ptr->LU_MAIN_BC_ACTION |= TSW_LU_MAIN_BC_ACTION_DEST_SET(dest_port);
282 }
283
tsw_set_unknown_frame_action(TSW_Type * ptr,uint8_t dest_port)284 void tsw_set_unknown_frame_action(TSW_Type *ptr, uint8_t dest_port)
285 {
286 ptr->LU_MAIN_NN_ACTION &= ~TSW_LU_MAIN_NN_ACTION_DEST_MASK;
287 ptr->LU_MAIN_NN_ACTION |= TSW_LU_MAIN_NN_ACTION_DEST_SET(dest_port);
288 }
289
tsw_clear_cam(TSW_Type * ptr)290 void tsw_clear_cam(TSW_Type *ptr)
291 {
292 ptr->LU_MAIN_HITMEM &= ~TSW_LU_MAIN_HITMEM_CAMMEMCLR_MASK;
293 ptr->LU_MAIN_HITMEM |= TSW_LU_MAIN_HITMEM_CAMMEMCLR_MASK;
294 }
295
tsw_enable_store_forward_mode(TSW_Type * ptr,uint8_t port)296 void tsw_enable_store_forward_mode(TSW_Type *ptr, uint8_t port)
297 {
298 ptr->TSNPORT[port].RXFIFO[TSW_RXFIFO_E1].SW_CTRL_IGRESS_RX_FDFIFO_E_OUT_CONFIG |= TSW_TSNPORT_RXFIFO_SW_CTRL_IGRESS_RX_FDFIFO_E_OUT_CONFIG_MODE_STORE_FW_MASK;
299 }
300
tsw_disable_store_forward_mode(TSW_Type * ptr,uint8_t port)301 void tsw_disable_store_forward_mode(TSW_Type *ptr, uint8_t port)
302 {
303 ptr->TSNPORT[port].RXFIFO[TSW_RXFIFO_E1].SW_CTRL_IGRESS_RX_FDFIFO_E_OUT_CONFIG &= ~TSW_TSNPORT_RXFIFO_SW_CTRL_IGRESS_RX_FDFIFO_E_OUT_CONFIG_MODE_STORE_FW_MASK;
304 }