Firmware for MNT ZZ9000 graphics and ARM coprocessor card for Amiga computers.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ethernet.c 26KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882
  1. /*
  2. * MNT ZZ9000 Amiga Graphics and Coprocessor Card Operating System (ZZ9000OS)
  3. *
  4. * Copyright (C) 2019, Lukas F. Hartmann <lukas@mntre.com>
  5. * MNT Research GmbH, Berlin
  6. * https://mntre.com
  7. *
  8. * More Info: https://mntre.com/zz9000
  9. *
  10. * SPDX-License-Identifier: GPL-3.0-or-later
  11. * GNU General Public License v3.0 or later
  12. *
  13. * https://spdx.org/licenses/GPL-3.0-or-later.html
  14. *
  15. * Some portions (from EMACPS example code, weird custom license) Copyright (C) 2010 - 2015 Xilinx, Inc.
  16. *
  17. */
  18. #include <stdio.h>
  19. #include "platform.h"
  20. #include <xil_printf.h>
  21. #include <xil_cache.h>
  22. #include <xil_mmu.h>
  23. #include "sleep.h"
  24. #include "xparameters.h"
  25. #include <xemacps.h>
  26. #include <xscugic.h>
  27. #include "ethernet.h"
  28. static XEmacPs EmacPsInstance;
  29. static XScuGic IntcInstance;
  30. // could also be 55, 77 (eth1), see interrupts.pdf last page
  31. // XPS_GEM0_INT_ID == 54
  32. #define EMACPS_IRPT_INTR XPS_GEM0_INT_ID
  33. #define SLCR_LOCK_ADDR (XPS_SYS_CTRL_BASEADDR + 0x4)
  34. #define SLCR_UNLOCK_ADDR (XPS_SYS_CTRL_BASEADDR + 0x8)
  35. #define SLCR_GEM0_CLK_CTRL_ADDR (XPS_SYS_CTRL_BASEADDR + 0x140)
  36. #define SLCR_GEM1_CLK_CTRL_ADDR (XPS_SYS_CTRL_BASEADDR + 0x144)
  37. #define SLCR_LOCK_KEY_VALUE 0x767B
  38. #define SLCR_UNLOCK_KEY_VALUE 0xDF0D
  39. #define SLCR_ADDR_GEM_RST_CTRL (XPS_SYS_CTRL_BASEADDR + 0x214)
  40. #define EMACPS_PHY_DELAY_SEC 4 //Amount of time to delay waiting on PHY to reset
  41. #define EMACPS_SLCR_DIV_MASK 0xFC0FC0FF
  42. static s32 GemVersion;
  43. uint8_t EmacPsMAC[6] = {0x68,0x82,0xf2,0x00,0x01,0x00};
  44. static volatile s32 DeviceErrors = 0;
  45. static volatile u32 FramesTx = 0;
  46. static volatile u32 FramesRx = 0;
  47. static volatile u16 frame_serial = 0;
  48. static volatile u32 frames_received = 0;
  49. static volatile u16 frames_backlog = 0;
  50. int frames_received_from_backlog = 0;
  51. typedef char EthernetFrame[XEMACPS_MAX_VLAN_FRAME_SIZE_JUMBO] __attribute__ ((aligned(64)));
  52. volatile char* TxFrame = (char*)TX_FRAME_ADDRESS; /* Transmit buffer */
  53. volatile char* RxFrame = (char*)RX_FRAME_ADDRESS; /* Receive buffer */
  54. /*
  55. * Buffer descriptors are allocated in uncached memory. The memory is made
  56. * uncached by setting the attributes appropriately in the MMU table.
  57. */
  58. #define RXBD_SPACE_BYTES XEmacPs_BdRingMemCalc(XEMACPS_BD_ALIGNMENT, RXBD_CNT)
  59. #define TXBD_SPACE_BYTES XEmacPs_BdRingMemCalc(XEMACPS_BD_ALIGNMENT, TXBD_CNT)
  60. #define PHY_DETECT_REG1 2
  61. #define PHY_DETECT_REG2 3
  62. #define PHY_ID_MARVELL 0x141
  63. #define PHY_ID_MICREL_KSZ9031 0x22
  64. static void XEmacPsSendHandler(void *Callback);
  65. static void XEmacPsRecvHandler(void *Callback);
  66. static void XEmacPsErrorHandler(void *Callback, u8 direction, u32 word);
  67. LONG setup_phy(XEmacPs * EmacPsInstancePtr);
  68. static LONG EmacPsSetupIntrSystem(XScuGic *IntcInstancePtr, XEmacPs *EmacPsInstancePtr, u16 EmacPsIntrId);
  69. static u32 micrel_auto_negotiate(XEmacPs *xemacpsp, u32 phy_addr);
  70. void XEmacPsClkSetup(XEmacPs *EmacPsInstancePtr, u16 EmacPsIntrId, int link_speed)
  71. {
  72. u32 SlcrTxClkCntrl;
  73. //u32 CrlApbClkCntrl;
  74. if (GemVersion == 2)
  75. {
  76. // SLCR unlock
  77. *(volatile unsigned int *)(SLCR_UNLOCK_ADDR) = SLCR_UNLOCK_KEY_VALUE;
  78. if (EmacPsIntrId == XPS_GEM0_INT_ID) {
  79. // GEM0 clock configuration
  80. SlcrTxClkCntrl = *(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR);
  81. SlcrTxClkCntrl &= EMACPS_SLCR_DIV_MASK;
  82. if (link_speed == 100) {
  83. SlcrTxClkCntrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV1 << 20);
  84. SlcrTxClkCntrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0 << 8);
  85. } else if (link_speed == 1000) {
  86. SlcrTxClkCntrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV1 << 20);
  87. SlcrTxClkCntrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0 << 8);
  88. } else if (link_speed == 10) {
  89. SlcrTxClkCntrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV1 << 20);
  90. SlcrTxClkCntrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0 << 8);
  91. } else {
  92. printf("XEmacPsClkSetup: invalid link speed %d\n", link_speed);
  93. }
  94. *(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR) = SlcrTxClkCntrl;
  95. } else if (EmacPsIntrId == XPS_GEM1_INT_ID) {
  96. }
  97. // SLCR lock
  98. *(unsigned int *)(SLCR_LOCK_ADDR) = SLCR_LOCK_KEY_VALUE;
  99. sleep(1);
  100. }
  101. }
  102. static XEmacPs_Bd *BdRxPtr;
  103. int init_ethernet_buffers() {
  104. XEmacPs* EmacPsInstancePtr = &EmacPsInstance;
  105. XEmacPs_Bd BdTemplate;
  106. XEmacPs_Stop(EmacPsInstancePtr);
  107. XEmacPs_BdClear(&BdTemplate);
  108. int Status = XEmacPs_BdRingCreate(&(XEmacPs_GetRxRing
  109. (EmacPsInstancePtr)),
  110. RX_BD_LIST_START_ADDRESS,
  111. RX_BD_LIST_START_ADDRESS,
  112. XEMACPS_BD_ALIGNMENT,
  113. RXBD_CNT);
  114. if (Status != XST_SUCCESS) {
  115. printf("EMAC: Error setting up RxBD space, BdRingCreate\n");
  116. return XST_FAILURE;
  117. }
  118. Status = XEmacPs_BdRingClone(&(XEmacPs_GetRxRing(EmacPsInstancePtr)),
  119. &BdTemplate, XEMACPS_RECV);
  120. if (Status != XST_SUCCESS) {
  121. printf("EMAC: Error setting up RxBD space, BdRingClone\n");
  122. return XST_FAILURE;
  123. }
  124. XEmacPs_BdClear(&BdTemplate);
  125. XEmacPs_BdSetStatus(&BdTemplate, XEMACPS_TXBUF_USED_MASK);
  126. // Create the TxBD ring
  127. Status = XEmacPs_BdRingCreate(&(XEmacPs_GetTxRing
  128. (EmacPsInstancePtr)),
  129. TX_BD_LIST_START_ADDRESS,
  130. TX_BD_LIST_START_ADDRESS,
  131. XEMACPS_BD_ALIGNMENT,
  132. TXBD_CNT);
  133. if (Status != XST_SUCCESS) {
  134. printf("Error setting up TxBD space, BdRingCreate\n");
  135. return XST_FAILURE;
  136. }
  137. Status = XEmacPs_BdRingClone(&(XEmacPs_GetTxRing(EmacPsInstancePtr)), &BdTemplate, XEMACPS_SEND);
  138. if (Status != XST_SUCCESS) {
  139. printf("Error setting up TxBD space, BdRingClone\n");
  140. return XST_FAILURE;
  141. }
  142. Status = XEmacPs_BdRingAlloc(&
  143. (XEmacPs_GetRxRing(EmacPsInstancePtr)),
  144. RXBD_CNT, &BdRxPtr);
  145. if (Status != XST_SUCCESS) {
  146. printf("EMAC: Error allocating RxBDs\n");
  147. return XST_FAILURE;
  148. }
  149. for (int i=0; i<RXBD_CNT; i++) {
  150. XEmacPs_BdSetAddressRx(BdRxPtr, RxFrame + FRAME_SIZE*i);
  151. BdRxPtr = XEmacPs_BdRingNext(&(XEmacPs_GetRxRing(EmacPsInstancePtr)), BdRxPtr);
  152. }
  153. Status = XEmacPs_BdRingToHw(&(XEmacPs_GetRxRing(EmacPsInstancePtr)), RXBD_CNT, BdRxPtr);
  154. if (Status != XST_SUCCESS) {
  155. printf("EMAC: Error committing RxBD to HW\n");
  156. return XST_FAILURE;
  157. }
  158. //XEmacPs_Reset(EmacPsInstancePtr);
  159. //sleep(1);
  160. //printf("EMAC: XEmacPs_Reset done.\n");
  161. XEmacPs_Start(EmacPsInstancePtr);
  162. printf("EMAC: XEmacPs_Start done.\n");
  163. return XST_SUCCESS;
  164. }
  165. int ethernet_init() {
  166. XEmacPs_Config *Config;
  167. long Status;
  168. XEmacPs* EmacPsInstancePtr = &EmacPsInstance;
  169. XScuGic* IntcInstancePtr = &IntcInstance;
  170. frames_backlog = 0;
  171. frames_received_from_backlog = 0;
  172. DeviceErrors = 0;
  173. FramesTx = 0;
  174. FramesRx = 0;
  175. frame_serial = 0;
  176. frames_received = 0;
  177. Config = XEmacPs_LookupConfig(XPAR_XEMACPS_0_DEVICE_ID);
  178. Status = XEmacPs_CfgInitialize(EmacPsInstancePtr, Config, Config->BaseAddress);
  179. if (Status != XST_SUCCESS) {
  180. printf("EMAC: Error in initialize\n");
  181. return XST_FAILURE;
  182. }
  183. GemVersion = ((Xil_In32(Config->BaseAddress + 0xFC)) >> 16) & 0xFFF;
  184. printf("EMAC: GemVersion: %ld\n", GemVersion);
  185. Status = XEmacPs_SetMacAddress(EmacPsInstancePtr, EmacPsMAC, 1);
  186. if (Status != XST_SUCCESS) {
  187. printf("EMAC: Error setting MAC address\n");
  188. return XST_FAILURE;
  189. }
  190. Status = XEmacPs_SetHandler(EmacPsInstancePtr,
  191. XEMACPS_HANDLER_DMASEND,
  192. (void *) XEmacPsSendHandler,
  193. EmacPsInstancePtr);
  194. Status |=
  195. XEmacPs_SetHandler(EmacPsInstancePtr,
  196. XEMACPS_HANDLER_DMARECV,
  197. (void *) XEmacPsRecvHandler,
  198. EmacPsInstancePtr);
  199. Status |=
  200. XEmacPs_SetHandler(EmacPsInstancePtr, XEMACPS_HANDLER_ERROR,
  201. (void *) XEmacPsErrorHandler,
  202. EmacPsInstancePtr);
  203. if (Status != XST_SUCCESS) {
  204. printf("EMAC: Error assigning handlers\n");
  205. return XST_FAILURE;
  206. }
  207. // FIXME address space?
  208. /*
  209. * The BDs need to be allocated in uncached memory. Hence the 1 MB
  210. * address range that starts at address 0x0FF00000 is made uncached.
  211. */
  212. Xil_SetTlbAttributes(RX_BD_LIST_START_ADDRESS, STRONG_ORDERED);
  213. //Xil_SetTlbAttributes(RX_FRAME_ADDRESS, 0xc02);
  214. //Xil_SetTlbAttributes(TX_FRAME_ADDRESS, 0xc02);
  215. XEmacPs_SetMdioDivisor(EmacPsInstancePtr, MDC_DIV_224);
  216. sleep(1);
  217. setup_phy(EmacPsInstancePtr);
  218. // FIXME
  219. EmacPsSetupIntrSystem(IntcInstancePtr, EmacPsInstancePtr, EMACPS_IRPT_INTR);
  220. // init_ethernet_buffers() also starts EmacPS
  221. Status = init_ethernet_buffers();
  222. if (Status != XST_SUCCESS) {
  223. printf("EMAC: init_ethernet_buffers() error\n");
  224. return XST_FAILURE;
  225. }
  226. return XST_SUCCESS;
  227. }
  228. static void XEmacPsSendHandler(void *Callback)
  229. {
  230. XEmacPs_Bd *BdTxPtr;
  231. XEmacPs *EmacPsInstancePtr = (XEmacPs *) Callback;
  232. u32 status = XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_TXSR_OFFSET);
  233. XEmacPs_WriteReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_TXSR_OFFSET, status);
  234. //printf("XEMACPS_TXSR status: %lu\n", status);
  235. int bds_sent = XEmacPs_BdRingFromHwTx(&(XEmacPs_GetTxRing(EmacPsInstancePtr)), 1, &BdTxPtr);
  236. if (bds_sent == 1) {
  237. status = XEmacPs_BdGetStatus(BdTxPtr);
  238. /*printf("BD status: ");
  239. if (status&XEMACPS_TXBUF_USED_MASK) printf("USED ");
  240. if (status&XEMACPS_TXBUF_WRAP_MASK) printf("WRAP ");
  241. if (status&XEMACPS_TXBUF_RETRY_MASK) printf("RETRY "); // retry limit exceeded
  242. if (status&XEMACPS_TXBUF_URUN_MASK) printf("URUN"); // tx underrun
  243. if (status&XEMACPS_TXBUF_EXH_MASK) printf("EXH "); // buffers exhausted
  244. if (status&XEMACPS_TXBUF_TCP_MASK) printf("TCP "); // late collision
  245. if (status&XEMACPS_TXBUF_NOCRC_MASK) printf("NOCRC "); // no crc
  246. if (status&XEMACPS_TXBUF_LAST_MASK) printf("LAST ");
  247. if (status&XEMACPS_TXBUF_LEN_MASK) printf("LEN ");
  248. printf("\n");*/
  249. status = XEmacPs_BdRingFree(&(XEmacPs_GetTxRing(EmacPsInstancePtr)), 1, BdTxPtr);
  250. if (status != XST_SUCCESS) {
  251. printf("XEmacPs_BdRingFree error: %lu\n",status);
  252. return;
  253. }
  254. XEmacPs_BdSetStatus(BdTxPtr, XEMACPS_TXBUF_USED_MASK); // XEMACPS_TXBUF_WRAP_MASK
  255. FramesTx++;
  256. }
  257. }
  258. #define XEMACPS_BD_TO_INDEX(ringptr, bdptr) \
  259. (((u32)bdptr - (u32)(ringptr)->BaseBdAddr) / (ringptr)->Separation)
  260. void ethernet_alloc_rx_frames() {
  261. XEmacPs* EmacPsInstancePtr = &EmacPsInstance;
  262. XEmacPs_BdRing* rxring = &(XEmacPs_GetRxRing(EmacPsInstancePtr));
  263. XEmacPs_Bd* rxbd;
  264. int free_bds = XEmacPs_BdRingGetFreeCnt(rxring);
  265. for (int i=0; i<free_bds; i++) {
  266. int Status = XEmacPs_BdRingAlloc(rxring, 1, &rxbd);
  267. if (Status != XST_SUCCESS) {
  268. printf("EMAC: Error allocating RxBD\n");
  269. } else {
  270. int bd_index=XEMACPS_BD_TO_INDEX(rxring, rxbd);
  271. XEmacPs_BdClearRxNew(rxbd);
  272. XEmacPs_BdSetAddressRx(rxbd, RxFrame+bd_index*FRAME_SIZE); // FIXME redundant?
  273. Status = XEmacPs_BdRingToHw(rxring, 1, rxbd);
  274. if (Status != XST_SUCCESS) {
  275. printf("EMAC: Error committing RxBD to HW\n");
  276. XEmacPs_BdRingUnAlloc(rxring, 1, rxbd); // FIXME double check
  277. }
  278. }
  279. }
  280. if (!free_bds) {
  281. printf("EMAC: no BDs free for allocation\n");
  282. }
  283. }
  284. int frame_receive_lock = 0;
  285. static void XEmacPsRecvHandler(void *Callback)
  286. {
  287. u32 status;
  288. XEmacPs* EmacPsInstancePtr = (XEmacPs *) Callback;
  289. XEmacPs_BdRing* rxring = &(XEmacPs_GetRxRing(EmacPsInstancePtr));
  290. XEmacPs_Bd* rxbdset, *cur_bd_ptr;
  291. int num_rx_bufs = XEmacPs_BdRingFromHwRx(rxring, RXBD_CNT, &rxbdset);
  292. // we immediately process the incoming frame.
  293. // main task will then signal the Amiga via interrupt
  294. // driver on Amiga side will call ethernet_receive_frame after copying the frame
  295. // and this will free up the EmacPS receive buffer again.
  296. if (num_rx_bufs > 0) {
  297. //printf("EMAC: num_rx_bufs %d\n", num_rx_bufs);
  298. cur_bd_ptr = rxbdset;
  299. for (int i=0; i<num_rx_bufs; i++) {
  300. frame_serial++;
  301. //printf("RX ser: %d\n",frame_serial);
  302. u32 bd_idx = XEMACPS_BD_TO_INDEX(rxring, cur_bd_ptr);
  303. int rx_bytes = XEmacPs_BdGetLength(cur_bd_ptr);
  304. uint8_t* frame_ptr = (uint8_t*)(RxFrame + bd_idx*FRAME_SIZE);
  305. //printf("EMAC: RX: %d [%d] bd_idx: %d\n", frame_serial, rx_bytes, bd_idx);
  306. Xil_DCacheInvalidateRange((UINTPTR)frame_ptr, FRAME_SIZE);
  307. if (frames_backlog<FRAME_MAX_BACKLOG) {
  308. // copy the frame to the backlog (frames that amiga hasn't fetched yet)
  309. uint8_t* frame_bl_ptr = (uint8_t*)(RX_BACKLOG_ADDRESS+frames_backlog*FRAME_SIZE);
  310. memcpy(frame_bl_ptr+RX_FRAME_PAD, frame_ptr, rx_bytes);
  311. *(frame_bl_ptr) = (rx_bytes&0xff00)>>8;
  312. *(frame_bl_ptr+1) = (rx_bytes&0xff);
  313. *(frame_bl_ptr+2) = (frame_serial&0xff00)>>8;
  314. *(frame_bl_ptr+3) = (frame_serial&0xff);
  315. frames_backlog++;
  316. //printf("bd %d [%d] copied from %p to %p\n", bd_idx, rx_bytes, frame_ptr, frame_bl_ptr);
  317. } else {
  318. //printf("EMAC: frames_backlog full\n");
  319. }
  320. XEmacPs_BdClearRxNew(cur_bd_ptr);
  321. cur_bd_ptr = XEmacPs_BdRingNext(rxring, cur_bd_ptr);
  322. frames_received++;
  323. }
  324. int Status = XEmacPs_BdRingFree(rxring, num_rx_bufs, rxbdset);
  325. if (Status != XST_SUCCESS) {
  326. //printf("EMAC: Error freeing RxBDs\n");
  327. } else {
  328. //printf("EMAC: freed %d RxBDs\n", num_rx_bufs);
  329. }
  330. ethernet_alloc_rx_frames();
  331. //printf("EMAC: backlog %d fetched %d\n", frames_backlog, frames_received_from_backlog);
  332. }
  333. status = XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXSR_OFFSET);
  334. XEmacPs_WriteReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXSR_OFFSET, status);
  335. }
  336. uint8_t* ethernet_current_receive_ptr() {
  337. return (uint8_t*)(RX_BACKLOG_ADDRESS+frames_received_from_backlog*FRAME_SIZE);
  338. }
  339. int ethernet_get_backlog() {
  340. return frames_backlog;
  341. }
  342. void ethernet_receive_frame() {
  343. // TODO disable interrupts while here
  344. uint8_t* frm = ethernet_current_receive_ptr();
  345. //printf("ethernet_receive_frame: %d bytes: %d serial: %d\n", frames_received_from_backlog, frm[0]<<8|frm[1], frm[2]<<8|frm[3]);
  346. if (frames_backlog>0) {
  347. frames_received_from_backlog++;
  348. if (frames_received_from_backlog >= frames_backlog) {
  349. // start over
  350. frames_backlog = 0;
  351. frames_received_from_backlog = 0;
  352. //printf("EMAC: caught up with backlog\n");
  353. }
  354. } else {
  355. printf("EMAC: ethernet_receive_frame() called but backlog is empty\n");
  356. }
  357. }
  358. u32 get_frames_received() {
  359. return frames_received;
  360. }
  361. static int frames_dropped = 0;
  362. uint8_t* ethernet_get_mac_address_ptr() {
  363. return (uint8_t*)&EmacPsMAC;
  364. }
  365. void ethernet_update_mac_address() {
  366. XEmacPs* EmacPsInstancePtr = &EmacPsInstance;
  367. printf("Ethernet: New MAC address %x %x %x %x %x %x\n",
  368. EmacPsMAC[0],EmacPsMAC[1],EmacPsMAC[2],EmacPsMAC[3],EmacPsMAC[4],EmacPsMAC[5]);
  369. XEmacPs_Stop(EmacPsInstancePtr);
  370. int Status = XEmacPs_SetMacAddress(EmacPsInstancePtr, EmacPsMAC, 1);
  371. if (Status != XST_SUCCESS) {
  372. printf("EMAC: Error setting MAC address\n");
  373. }
  374. XEmacPs_Start(EmacPsInstancePtr);
  375. }
  376. static void XEmacPsErrorHandler(void *Callback, u8 Direction, u32 ErrorWord)
  377. {
  378. //XEmacPs *EmacPsInstancePtr = (XEmacPs *) Callback;
  379. DeviceErrors++;
  380. switch (Direction) {
  381. case XEMACPS_RECV:
  382. if (ErrorWord & XEMACPS_RXSR_HRESPNOK_MASK) {
  383. printf("EMAC: Receive DMA error\n");
  384. }
  385. if (ErrorWord & XEMACPS_RXSR_RXOVR_MASK) {
  386. printf("EMAC: Receive over run\n");
  387. }
  388. if (ErrorWord & XEMACPS_RXSR_BUFFNA_MASK) {
  389. printf("EMAC: Receive buffer not available\n");
  390. // signal to host that frames are available
  391. frames_dropped++;
  392. frames_received++;
  393. if (frames_dropped%10 == 0) {
  394. printf("ETHDROP: %d\n",frames_dropped);
  395. ethernet_alloc_rx_frames();
  396. }
  397. }
  398. break;
  399. case XEMACPS_SEND:
  400. if (ErrorWord & XEMACPS_TXSR_HRESPNOK_MASK) {
  401. printf("EMAC: Transmit DMA error\n");
  402. }
  403. if (ErrorWord & XEMACPS_TXSR_URUN_MASK) {
  404. printf("EMAC: Transmit under run\n");
  405. }
  406. if (ErrorWord & XEMACPS_TXSR_BUFEXH_MASK) {
  407. printf("EMAC: Transmit buffer exhausted\n");
  408. }
  409. if (ErrorWord & XEMACPS_TXSR_RXOVR_MASK) {
  410. printf("EMAC: Transmit retry excessed limits\n");
  411. }
  412. if (ErrorWord & XEMACPS_TXSR_FRAMERX_MASK) {
  413. printf("EMAC: Transmit collision\n");
  414. }
  415. if (ErrorWord & XEMACPS_TXSR_USEDREAD_MASK) {
  416. printf("EMAC: Transmit buffer not available\n");
  417. }
  418. break;
  419. }
  420. /*
  421. * Bypassing the reset functionality as the default tx status for q0 is
  422. * USED BIT READ. so, the first interrupt will be tx used bit and it resets
  423. * the core always.
  424. */
  425. if (GemVersion == 2) {
  426. //EmacPsResetDevice(EmacPsInstancePtr);
  427. }
  428. }
  429. u32 XEmacPsDetectPHY(XEmacPs * EmacPsInstancePtr)
  430. {
  431. u32 PhyAddr;
  432. u32 Status;
  433. u16 PhyReg1;
  434. u16 PhyReg2;
  435. for (PhyAddr = 0; PhyAddr <= 31; PhyAddr++) {
  436. Status = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr,
  437. PHY_DETECT_REG1, &PhyReg1);
  438. Status |= XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr,
  439. PHY_DETECT_REG2, &PhyReg2);
  440. if ((Status == XST_SUCCESS) &&
  441. (PhyReg1 > 0x0000) && (PhyReg1 < 0xffff) &&
  442. (PhyReg2 > 0x0000) && (PhyReg2 < 0xffff)) {
  443. /* Found a valid PHY address */
  444. return PhyAddr;
  445. }
  446. }
  447. return PhyAddr; /* default to 32(max of iteration) */
  448. }
  449. LONG setup_phy(XEmacPs * EmacPsInstancePtr)
  450. {
  451. u16 PhyIdentity;
  452. u32 PhyAddr;
  453. PhyAddr = XEmacPsDetectPHY(EmacPsInstancePtr);
  454. if (PhyAddr >= 32) {
  455. printf("EMAC: Error detecting PHY\n");
  456. return XST_FAILURE;
  457. }
  458. XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, PHY_DETECT_REG1, &PhyIdentity);
  459. if (PhyIdentity == PHY_ID_MICREL_KSZ9031) {
  460. printf("EMAC: MICREL KSZ9031 PHY detected\n");
  461. micrel_auto_negotiate(EmacPsInstancePtr, PhyAddr);
  462. return XST_SUCCESS;
  463. }
  464. else {
  465. printf("EMAC: Unsupported PHY with id 0x%x\n",PhyIdentity);
  466. }
  467. return XST_FAILURE;
  468. }
  469. #define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
  470. #define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */
  471. #define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
  472. #define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */
  473. #define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
  474. #define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */
  475. #define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
  476. #define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */
  477. #define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */
  478. #define ADVERTISE_100_AND_10 (ADVERTISE_10FULL | ADVERTISE_100FULL | ADVERTISE_10HALF | ADVERTISE_100HALF)
  479. #define ADVERTISE_100 (ADVERTISE_100FULL | ADVERTISE_100HALF)
  480. #define ADVERTISE_10 (ADVERTISE_10FULL | ADVERTISE_10HALF)
  481. #define ADVERTISE_1000 0x0300
  482. #define IEEE_ASYMMETRIC_PAUSE_MASK 0x0800
  483. #define IEEE_PAUSE_MASK 0x0400
  484. #define IEEE_AUTONEG_ERROR_MASK 0x8000
  485. #define IEEE_CONTROL_REG_OFFSET 0
  486. #define IEEE_STATUS_REG_OFFSET 1
  487. #define IEEE_AUTONEGO_ADVERTISE_REG 4
  488. #define IEEE_PARTNER_ABILITIES_1_REG_OFFSET 5
  489. #define IEEE_PARTNER_ABILITIES_2_REG_OFFSET 8
  490. #define IEEE_1000BASET_CONTROL_REG 9
  491. #define IEEE_1000BASET_STATUS_REG 10
  492. #define IEEE_COPPER_SPECIFIC_CONTROL_REG 16
  493. #define IEEE_SPECIFIC_STATUS_REG 17
  494. #define IEEE_COPPER_SPECIFIC_STATUS_REG_2 19
  495. #define IEEE_EXT_PHY_SPECIFIC_CONTROL_REG 20
  496. #define IEEE_CONTROL_REG_MAC 21
  497. #define IEEE_PAGE_ADDRESS_REGISTER 22
  498. #define IEEE_CTRL_1GBPS_LINKSPEED_MASK 0x2040
  499. #define IEEE_CTRL_LINKSPEED_MASK 0x0040
  500. #define IEEE_CTRL_LINKSPEED_1000M 0x0040
  501. #define IEEE_CTRL_LINKSPEED_100M 0x2000
  502. #define IEEE_CTRL_LINKSPEED_10M 0x0000
  503. #define IEEE_CTRL_RESET_MASK 0x8000
  504. #define IEEE_CTRL_AUTONEGOTIATE_ENABLE 0x1000
  505. #define IEEE_STAT_AUTONEGOTIATE_CAPABLE 0x0008
  506. #define IEEE_STAT_AUTONEGOTIATE_COMPLETE 0x0020
  507. #define IEEE_STAT_AUTONEGOTIATE_RESTART 0x0200
  508. #define IEEE_STAT_1GBPS_EXTENSIONS 0x0100
  509. #define IEEE_AN1_ABILITY_MASK 0x1FE0
  510. #define IEEE_AN3_ABILITY_MASK_1GBPS 0x0C00
  511. #define IEEE_AN1_ABILITY_MASK_100MBPS 0x0380
  512. #define IEEE_AN1_ABILITY_MASK_10MBPS 0x0060
  513. #define IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK 0x0030
  514. #define IEEE_1000BASE_STATUS_REG 0x0a
  515. static u32 micrel_auto_negotiate(XEmacPs *xemacpsp, u32 phy_addr)
  516. {
  517. u16 temp;
  518. u16 control;
  519. u16 status;
  520. u16 status_speed;
  521. u32 timeout_counter = 0;
  522. int link_speed = 100;
  523. int auto_negotiate = 1;
  524. if (auto_negotiate) {
  525. printf("PHY: Start Micrel PHY auto negotiation\n");
  526. XEmacPs_PhyWrite(xemacpsp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2);
  527. XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, &control);
  528. control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK;
  529. XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, control);
  530. XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
  531. XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control); //reg 0x04
  532. control |= IEEE_ASYMMETRIC_PAUSE_MASK; //0x0800
  533. control |= IEEE_PAUSE_MASK;
  534. control |= ADVERTISE_100;
  535. control |= ADVERTISE_10;
  536. XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);
  537. if (link_speed == 100) {
  538. // register 0: 100 mbit
  539. XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
  540. control &= ~(1<<6);
  541. //control |= (1<<13);
  542. XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
  543. // register 9
  544. XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000BASET_CONTROL_REG, &control);
  545. control &= ~(1<<9 | 1<<8);
  546. XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000BASET_CONTROL_REG,control);
  547. } else if (link_speed == 1000) {
  548. // register 0: 1000 mbit
  549. /*XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
  550. control |= (1<<6);
  551. control &= ~(1<<13);
  552. XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);*/
  553. // register 9
  554. XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000BASET_CONTROL_REG, &control);
  555. control |= ADVERTISE_1000;
  556. XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000BASET_CONTROL_REG, control);
  557. // this is "reserved" according to manual?!
  558. // page 0, register 10h
  559. XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,&control);
  560. control |= (7 << 12); // max number of gigabit attempts
  561. control |= (1 << 11); // enable downshift
  562. XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,control);
  563. }
  564. // register 0
  565. XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
  566. if (link_speed == 1000) {
  567. control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;
  568. }
  569. control |= IEEE_STAT_AUTONEGOTIATE_RESTART;
  570. XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
  571. if (link_speed == 1000) {
  572. XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
  573. control |= IEEE_CTRL_RESET_MASK;
  574. XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
  575. while (1) {
  576. XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
  577. if (control & IEEE_CTRL_RESET_MASK) continue; // ??? weird
  578. else break;
  579. }
  580. }
  581. XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
  582. printf("PHY: Waiting for PHY to complete auto negotiation.\n");
  583. while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
  584. sleep(1);
  585. XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_STATUS_REG_2, &temp);
  586. timeout_counter++;
  587. if (timeout_counter > 2) {
  588. printf("PHY: Auto negotiation timeout\n");
  589. break;
  590. }
  591. XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
  592. }
  593. // http://www.fpgadeveloper.com/2018/05/board-bring-up-myir-myd-y7z010-dev-board.html
  594. XEmacPs_PhyRead(xemacpsp, phy_addr, 0x1F, &status_speed);
  595. if (status_speed & 0x040)
  596. link_speed = 1000;
  597. else if(status_speed & 0x020)
  598. link_speed = 100;
  599. else if(status_speed & 0x010)
  600. link_speed = 10;
  601. }
  602. printf("PHY: Link speed: %d mbit\n",link_speed);
  603. XEmacPs_SetOperatingSpeed(xemacpsp, link_speed);
  604. XEmacPsClkSetup(xemacpsp, EMACPS_IRPT_INTR, link_speed);
  605. return link_speed;
  606. }
  607. /****************************************************************************/
  608. /**
  609. *
  610. * This function setups the interrupt system so interrupts can occur for the
  611. * EMACPS.
  612. * @param IntcInstancePtr is a pointer to the instance of the Intc driver.
  613. * @param EmacPsInstancePtr is a pointer to the instance of the EmacPs
  614. * driver.
  615. * @param EmacPsIntrId is the Interrupt ID and is typically
  616. * XPAR_<EMACPS_instance>_INTR value from xparameters.h.
  617. *
  618. * @return XST_SUCCESS if successful, otherwise XST_FAILURE.
  619. *
  620. * @note None.
  621. *
  622. *****************************************************************************/
  623. static LONG EmacPsSetupIntrSystem(XScuGic *IntcInstancePtr, XEmacPs *EmacPsInstancePtr, u16 EmacPsIntrId)
  624. {
  625. LONG Status;
  626. XScuGic_Config *GicConfig;
  627. Xil_ExceptionInit();
  628. /*
  629. * Initialize the interrupt controller driver so that it is ready to
  630. * use.
  631. */
  632. GicConfig = XScuGic_LookupConfig(XPAR_SCUGIC_SINGLE_DEVICE_ID);
  633. if (NULL == GicConfig) {
  634. printf("GIC: XScuGic_LookupConfig failed\n");
  635. return XST_FAILURE;
  636. }
  637. Status = XScuGic_CfgInitialize(IntcInstancePtr, GicConfig, GicConfig->CpuBaseAddress);
  638. if (Status != XST_SUCCESS) {
  639. printf("GIC: XScuGic_CfgInitialize failed\n");
  640. return XST_FAILURE;
  641. }
  642. /*
  643. * Connect the interrupt controller interrupt handler to the hardware
  644. * interrupt handling logic in the processor.
  645. */
  646. Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
  647. (Xil_ExceptionHandler)XScuGic_InterruptHandler,
  648. IntcInstancePtr);
  649. /*
  650. * Connect a device driver handler that will be called when an
  651. * interrupt for the device occurs, the device driver handler performs
  652. * the specific interrupt processing for the device.
  653. */
  654. Status = XScuGic_Connect(IntcInstancePtr, EmacPsIntrId,
  655. (Xil_InterruptHandler) XEmacPs_IntrHandler,
  656. (void *) EmacPsInstancePtr);
  657. if (Status != XST_SUCCESS) {
  658. printf("GIC: Unable to connect ISR to interrupt controller\n");
  659. return XST_FAILURE;
  660. }
  661. /*
  662. * Enable interrupts from the hardware
  663. */
  664. XScuGic_Enable(IntcInstancePtr, EmacPsIntrId);
  665. printf("GIC: SCU GIC enabled\n");
  666. /*
  667. * Enable interrupts in the processor
  668. */
  669. Xil_ExceptionEnable();
  670. printf("GIC: Interrupts enabled\n");
  671. return XST_SUCCESS;
  672. }
  673. u16 ethernet_send_frame(u16 frame_size) {
  674. XEmacPs* EmacPsInstancePtr = &EmacPsInstance;
  675. XEmacPs_Bd *BdTxPtr;
  676. u32 old_frames_tx = FramesTx;
  677. Xil_DCacheInvalidateRange((UINTPTR)TxFrame, sizeof(EthernetFrame));
  678. /*printf("ethernet_send_frame: %lu %d\n",old_frames_tx,frame_size);
  679. for (int y=0; y<frame_size; y++) {
  680. printf("%02x",TxFrame[y]);
  681. if (y%4==3) printf(" ");
  682. if (y%32==31) printf("\n");
  683. }
  684. printf("\n==========================================\n");*/
  685. LONG Status = XEmacPs_BdRingAlloc(&(XEmacPs_GetTxRing(EmacPsInstancePtr)), 1, &BdTxPtr);
  686. if (Status != XST_SUCCESS) {
  687. printf("ERROR: BdRingAlloc error: %ld\n",Status);
  688. // lets unstick this
  689. //init_ethernet_buffers();
  690. return 2;
  691. }
  692. XEmacPs_BdSetAddressTx(BdTxPtr, TxFrame);
  693. XEmacPs_BdSetLength(BdTxPtr, frame_size);
  694. XEmacPs_BdClearTxUsed(BdTxPtr);
  695. XEmacPs_BdSetLast(BdTxPtr);
  696. Status = XEmacPs_BdRingToHw(&(XEmacPs_GetTxRing(EmacPsInstancePtr)), 1, BdTxPtr);
  697. if (Status != XST_SUCCESS) {
  698. printf("ERROR: BdRingToHw error: %ld\n",Status);
  699. return 3;
  700. }
  701. Xil_DCacheFlushRange((UINTPTR)BdTxPtr, 128);
  702. XEmacPs_Transmit(EmacPsInstancePtr);
  703. u32 counter = 0;
  704. while (old_frames_tx == FramesTx) {
  705. usleep(100);
  706. counter++;
  707. // 1ms
  708. if (counter>10) {
  709. printf("ERROR: timeout in ethernet_send_frame waiting for tx!\n");
  710. //init_ethernet_buffers();
  711. return 4;
  712. }
  713. }
  714. //printf("frame %ld transmitted!\n",FramesTx);
  715. // all good
  716. return 0;
  717. }