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 }