mbed-os
Fork of mbed-os by
targets/TARGET_NXP/TARGET_LPC23XX/ethernet_api.c@0:f269e3021894, 2016-10-23 (annotated)
- Committer:
- elessair
- Date:
- Sun Oct 23 15:10:02 2016 +0000
- Revision:
- 0:f269e3021894
Initial commit
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
elessair | 0:f269e3021894 | 1 | /* mbed Microcontroller Library |
elessair | 0:f269e3021894 | 2 | * Copyright (c) 2006-2013 ARM Limited |
elessair | 0:f269e3021894 | 3 | * |
elessair | 0:f269e3021894 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
elessair | 0:f269e3021894 | 5 | * you may not use this file except in compliance with the License. |
elessair | 0:f269e3021894 | 6 | * You may obtain a copy of the License at |
elessair | 0:f269e3021894 | 7 | * |
elessair | 0:f269e3021894 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
elessair | 0:f269e3021894 | 9 | * |
elessair | 0:f269e3021894 | 10 | * Unless required by applicable law or agreed to in writing, software |
elessair | 0:f269e3021894 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
elessair | 0:f269e3021894 | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
elessair | 0:f269e3021894 | 13 | * See the License for the specific language governing permissions and |
elessair | 0:f269e3021894 | 14 | * limitations under the License. |
elessair | 0:f269e3021894 | 15 | */ |
elessair | 0:f269e3021894 | 16 | #include <string.h> |
elessair | 0:f269e3021894 | 17 | |
elessair | 0:f269e3021894 | 18 | #include "ethernet_api.h" |
elessair | 0:f269e3021894 | 19 | #include "cmsis.h" |
elessair | 0:f269e3021894 | 20 | #include "mbed_interface.h" |
elessair | 0:f269e3021894 | 21 | #include "toolchain.h" |
elessair | 0:f269e3021894 | 22 | #include "mbed_error.h" |
elessair | 0:f269e3021894 | 23 | |
elessair | 0:f269e3021894 | 24 | #define NEW_LOGIC 0 |
elessair | 0:f269e3021894 | 25 | #define NEW_ETH_BUFFER 0 |
elessair | 0:f269e3021894 | 26 | |
elessair | 0:f269e3021894 | 27 | #if NEW_ETH_BUFFER |
elessair | 0:f269e3021894 | 28 | |
elessair | 0:f269e3021894 | 29 | #define NUM_RX_FRAG 4 // Number of Rx Fragments (== packets) |
elessair | 0:f269e3021894 | 30 | #define NUM_TX_FRAG 3 // Number of Tx Fragments (== packets) |
elessair | 0:f269e3021894 | 31 | |
elessair | 0:f269e3021894 | 32 | #define ETH_MAX_FLEN 1536 // Maximum Ethernet Frame Size |
elessair | 0:f269e3021894 | 33 | #define ETH_FRAG_SIZE ETH_MAX_FLEN // Packet Fragment size (same as packet length) |
elessair | 0:f269e3021894 | 34 | |
elessair | 0:f269e3021894 | 35 | #else |
elessair | 0:f269e3021894 | 36 | |
elessair | 0:f269e3021894 | 37 | // Memfree calculation: |
elessair | 0:f269e3021894 | 38 | // (16 * 1024) - ((2 * 4 * NUM_RX) + (2 * 4 * NUM_RX) + (0x300 * NUM_RX) + |
elessair | 0:f269e3021894 | 39 | // (2 * 4 * NUM_TX) + (1 * 4 * NUM_TX) + (0x300 * NUM_TX)) = 8556 |
elessair | 0:f269e3021894 | 40 | /* EMAC Memory Buffer configuration for 16K Ethernet RAM. */ |
elessair | 0:f269e3021894 | 41 | #define NUM_RX_FRAG 4 /* Num.of RX Fragments 4*1536= 6.0kB */ |
elessair | 0:f269e3021894 | 42 | #define NUM_TX_FRAG 3 /* Num.of TX Fragments 3*1536= 4.6kB */ |
elessair | 0:f269e3021894 | 43 | //#define ETH_FRAG_SIZE 1536 /* Packet Fragment size 1536 Bytes */ |
elessair | 0:f269e3021894 | 44 | |
elessair | 0:f269e3021894 | 45 | //#define ETH_MAX_FLEN 1536 /* Max. Ethernet Frame Size */ |
elessair | 0:f269e3021894 | 46 | #define ETH_FRAG_SIZE 0x300 /* Packet Fragment size 1536/2 Bytes */ |
elessair | 0:f269e3021894 | 47 | #define ETH_MAX_FLEN 0x300 /* Max. Ethernet Frame Size */ |
elessair | 0:f269e3021894 | 48 | |
elessair | 0:f269e3021894 | 49 | const int ethernet_MTU_SIZE = 0x300; |
elessair | 0:f269e3021894 | 50 | |
elessair | 0:f269e3021894 | 51 | #endif |
elessair | 0:f269e3021894 | 52 | |
elessair | 0:f269e3021894 | 53 | #define ETHERNET_ADDR_SIZE 6 |
elessair | 0:f269e3021894 | 54 | |
elessair | 0:f269e3021894 | 55 | PACKED struct RX_DESC_TypeDef { /* RX Descriptor struct */ |
elessair | 0:f269e3021894 | 56 | unsigned int Packet; |
elessair | 0:f269e3021894 | 57 | unsigned int Ctrl; |
elessair | 0:f269e3021894 | 58 | }; |
elessair | 0:f269e3021894 | 59 | typedef struct RX_DESC_TypeDef RX_DESC_TypeDef; |
elessair | 0:f269e3021894 | 60 | |
elessair | 0:f269e3021894 | 61 | PACKED struct RX_STAT_TypeDef { /* RX Status struct */ |
elessair | 0:f269e3021894 | 62 | unsigned int Info; |
elessair | 0:f269e3021894 | 63 | unsigned int HashCRC; |
elessair | 0:f269e3021894 | 64 | }; |
elessair | 0:f269e3021894 | 65 | typedef struct RX_STAT_TypeDef RX_STAT_TypeDef; |
elessair | 0:f269e3021894 | 66 | |
elessair | 0:f269e3021894 | 67 | PACKED struct TX_DESC_TypeDef { /* TX Descriptor struct */ |
elessair | 0:f269e3021894 | 68 | unsigned int Packet; |
elessair | 0:f269e3021894 | 69 | unsigned int Ctrl; |
elessair | 0:f269e3021894 | 70 | }; |
elessair | 0:f269e3021894 | 71 | typedef struct TX_DESC_TypeDef TX_DESC_TypeDef; |
elessair | 0:f269e3021894 | 72 | |
elessair | 0:f269e3021894 | 73 | PACKED struct TX_STAT_TypeDef { /* TX Status struct */ |
elessair | 0:f269e3021894 | 74 | unsigned int Info; |
elessair | 0:f269e3021894 | 75 | }; |
elessair | 0:f269e3021894 | 76 | typedef struct TX_STAT_TypeDef TX_STAT_TypeDef; |
elessair | 0:f269e3021894 | 77 | |
elessair | 0:f269e3021894 | 78 | /* MAC Configuration Register 1 */ |
elessair | 0:f269e3021894 | 79 | #define MAC1_REC_EN 0x00000001 /* Receive Enable */ |
elessair | 0:f269e3021894 | 80 | #define MAC1_PASS_ALL 0x00000002 /* Pass All Receive Frames */ |
elessair | 0:f269e3021894 | 81 | #define MAC1_RX_FLOWC 0x00000004 /* RX Flow Control */ |
elessair | 0:f269e3021894 | 82 | #define MAC1_TX_FLOWC 0x00000008 /* TX Flow Control */ |
elessair | 0:f269e3021894 | 83 | #define MAC1_LOOPB 0x00000010 /* Loop Back Mode */ |
elessair | 0:f269e3021894 | 84 | #define MAC1_RES_TX 0x00000100 /* Reset TX Logic */ |
elessair | 0:f269e3021894 | 85 | #define MAC1_RES_MCS_TX 0x00000200 /* Reset MAC TX Control Sublayer */ |
elessair | 0:f269e3021894 | 86 | #define MAC1_RES_RX 0x00000400 /* Reset RX Logic */ |
elessair | 0:f269e3021894 | 87 | #define MAC1_RES_MCS_RX 0x00000800 /* Reset MAC RX Control Sublayer */ |
elessair | 0:f269e3021894 | 88 | #define MAC1_SIM_RES 0x00004000 /* Simulation Reset */ |
elessair | 0:f269e3021894 | 89 | #define MAC1_SOFT_RES 0x00008000 /* Soft Reset MAC */ |
elessair | 0:f269e3021894 | 90 | |
elessair | 0:f269e3021894 | 91 | /* MAC Configuration Register 2 */ |
elessair | 0:f269e3021894 | 92 | #define MAC2_FULL_DUP 0x00000001 /* Full Duplex Mode */ |
elessair | 0:f269e3021894 | 93 | #define MAC2_FRM_LEN_CHK 0x00000002 /* Frame Length Checking */ |
elessair | 0:f269e3021894 | 94 | #define MAC2_HUGE_FRM_EN 0x00000004 /* Huge Frame Enable */ |
elessair | 0:f269e3021894 | 95 | #define MAC2_DLY_CRC 0x00000008 /* Delayed CRC Mode */ |
elessair | 0:f269e3021894 | 96 | #define MAC2_CRC_EN 0x00000010 /* Append CRC to every Frame */ |
elessair | 0:f269e3021894 | 97 | #define MAC2_PAD_EN 0x00000020 /* Pad all Short Frames */ |
elessair | 0:f269e3021894 | 98 | #define MAC2_VLAN_PAD_EN 0x00000040 /* VLAN Pad Enable */ |
elessair | 0:f269e3021894 | 99 | #define MAC2_ADET_PAD_EN 0x00000080 /* Auto Detect Pad Enable */ |
elessair | 0:f269e3021894 | 100 | #define MAC2_PPREAM_ENF 0x00000100 /* Pure Preamble Enforcement */ |
elessair | 0:f269e3021894 | 101 | #define MAC2_LPREAM_ENF 0x00000200 /* Long Preamble Enforcement */ |
elessair | 0:f269e3021894 | 102 | #define MAC2_NO_BACKOFF 0x00001000 /* No Backoff Algorithm */ |
elessair | 0:f269e3021894 | 103 | #define MAC2_BACK_PRESSURE 0x00002000 /* Backoff Presurre / No Backoff */ |
elessair | 0:f269e3021894 | 104 | #define MAC2_EXCESS_DEF 0x00004000 /* Excess Defer */ |
elessair | 0:f269e3021894 | 105 | |
elessair | 0:f269e3021894 | 106 | /* Back-to-Back Inter-Packet-Gap Register */ |
elessair | 0:f269e3021894 | 107 | #define IPGT_FULL_DUP 0x00000015 /* Recommended value for Full Duplex */ |
elessair | 0:f269e3021894 | 108 | #define IPGT_HALF_DUP 0x00000012 /* Recommended value for Half Duplex */ |
elessair | 0:f269e3021894 | 109 | |
elessair | 0:f269e3021894 | 110 | /* Non Back-to-Back Inter-Packet-Gap Register */ |
elessair | 0:f269e3021894 | 111 | #define IPGR_DEF 0x00000012 /* Recommended value */ |
elessair | 0:f269e3021894 | 112 | |
elessair | 0:f269e3021894 | 113 | /* Collision Window/Retry Register */ |
elessair | 0:f269e3021894 | 114 | #define CLRT_DEF 0x0000370F /* Default value */ |
elessair | 0:f269e3021894 | 115 | |
elessair | 0:f269e3021894 | 116 | /* PHY Support Register */ |
elessair | 0:f269e3021894 | 117 | #define SUPP_SPEED 0x00000100 /* Reduced MII Logic Current Speed */ |
elessair | 0:f269e3021894 | 118 | //#define SUPP_RES_RMII 0x00000800 /* Reset Reduced MII Logic */ |
elessair | 0:f269e3021894 | 119 | #define SUPP_RES_RMII 0x00000000 /* Reset Reduced MII Logic */ |
elessair | 0:f269e3021894 | 120 | |
elessair | 0:f269e3021894 | 121 | /* Test Register */ |
elessair | 0:f269e3021894 | 122 | #define TEST_SHCUT_PQUANTA 0x00000001 /* Shortcut Pause Quanta */ |
elessair | 0:f269e3021894 | 123 | #define TEST_TST_PAUSE 0x00000002 /* Test Pause */ |
elessair | 0:f269e3021894 | 124 | #define TEST_TST_BACKP 0x00000004 /* Test Back Pressure */ |
elessair | 0:f269e3021894 | 125 | |
elessair | 0:f269e3021894 | 126 | /* MII Management Configuration Register */ |
elessair | 0:f269e3021894 | 127 | #define MCFG_SCAN_INC 0x00000001 /* Scan Increment PHY Address */ |
elessair | 0:f269e3021894 | 128 | #define MCFG_SUPP_PREAM 0x00000002 /* Suppress Preamble */ |
elessair | 0:f269e3021894 | 129 | #define MCFG_CLK_SEL 0x0000003C /* Clock Select Mask */ |
elessair | 0:f269e3021894 | 130 | #define MCFG_RES_MII 0x00008000 /* Reset MII Management Hardware */ |
elessair | 0:f269e3021894 | 131 | |
elessair | 0:f269e3021894 | 132 | /* MII Management Command Register */ |
elessair | 0:f269e3021894 | 133 | #define MCMD_READ 0x00000001 /* MII Read */ |
elessair | 0:f269e3021894 | 134 | #define MCMD_SCAN 0x00000002 /* MII Scan continuously */ |
elessair | 0:f269e3021894 | 135 | |
elessair | 0:f269e3021894 | 136 | #define MII_WR_TOUT 0x00050000 /* MII Write timeout count */ |
elessair | 0:f269e3021894 | 137 | #define MII_RD_TOUT 0x00050000 /* MII Read timeout count */ |
elessair | 0:f269e3021894 | 138 | |
elessair | 0:f269e3021894 | 139 | /* MII Management Address Register */ |
elessair | 0:f269e3021894 | 140 | #define MADR_REG_ADR 0x0000001F /* MII Register Address Mask */ |
elessair | 0:f269e3021894 | 141 | #define MADR_PHY_ADR 0x00001F00 /* PHY Address Mask */ |
elessair | 0:f269e3021894 | 142 | |
elessair | 0:f269e3021894 | 143 | /* MII Management Indicators Register */ |
elessair | 0:f269e3021894 | 144 | #define MIND_BUSY 0x00000001 /* MII is Busy */ |
elessair | 0:f269e3021894 | 145 | #define MIND_SCAN 0x00000002 /* MII Scanning in Progress */ |
elessair | 0:f269e3021894 | 146 | #define MIND_NOT_VAL 0x00000004 /* MII Read Data not valid */ |
elessair | 0:f269e3021894 | 147 | #define MIND_MII_LINK_FAIL 0x00000008 /* MII Link Failed */ |
elessair | 0:f269e3021894 | 148 | |
elessair | 0:f269e3021894 | 149 | /* Command Register */ |
elessair | 0:f269e3021894 | 150 | #define CR_RX_EN 0x00000001 /* Enable Receive */ |
elessair | 0:f269e3021894 | 151 | #define CR_TX_EN 0x00000002 /* Enable Transmit */ |
elessair | 0:f269e3021894 | 152 | #define CR_REG_RES 0x00000008 /* Reset Host Registers */ |
elessair | 0:f269e3021894 | 153 | #define CR_TX_RES 0x00000010 /* Reset Transmit Datapath */ |
elessair | 0:f269e3021894 | 154 | #define CR_RX_RES 0x00000020 /* Reset Receive Datapath */ |
elessair | 0:f269e3021894 | 155 | #define CR_PASS_RUNT_FRM 0x00000040 /* Pass Runt Frames */ |
elessair | 0:f269e3021894 | 156 | #define CR_PASS_RX_FILT 0x00000080 /* Pass RX Filter */ |
elessair | 0:f269e3021894 | 157 | #define CR_TX_FLOW_CTRL 0x00000100 /* TX Flow Control */ |
elessair | 0:f269e3021894 | 158 | #define CR_RMII 0x00000200 /* Reduced MII Interface */ |
elessair | 0:f269e3021894 | 159 | #define CR_FULL_DUP 0x00000400 /* Full Duplex */ |
elessair | 0:f269e3021894 | 160 | |
elessair | 0:f269e3021894 | 161 | /* Status Register */ |
elessair | 0:f269e3021894 | 162 | #define SR_RX_EN 0x00000001 /* Enable Receive */ |
elessair | 0:f269e3021894 | 163 | #define SR_TX_EN 0x00000002 /* Enable Transmit */ |
elessair | 0:f269e3021894 | 164 | |
elessair | 0:f269e3021894 | 165 | /* Transmit Status Vector 0 Register */ |
elessair | 0:f269e3021894 | 166 | #define TSV0_CRC_ERR 0x00000001 /* CRC error */ |
elessair | 0:f269e3021894 | 167 | #define TSV0_LEN_CHKERR 0x00000002 /* Length Check Error */ |
elessair | 0:f269e3021894 | 168 | #define TSV0_LEN_OUTRNG 0x00000004 /* Length Out of Range */ |
elessair | 0:f269e3021894 | 169 | #define TSV0_DONE 0x00000008 /* Tramsmission Completed */ |
elessair | 0:f269e3021894 | 170 | #define TSV0_MCAST 0x00000010 /* Multicast Destination */ |
elessair | 0:f269e3021894 | 171 | #define TSV0_BCAST 0x00000020 /* Broadcast Destination */ |
elessair | 0:f269e3021894 | 172 | #define TSV0_PKT_DEFER 0x00000040 /* Packet Deferred */ |
elessair | 0:f269e3021894 | 173 | #define TSV0_EXC_DEFER 0x00000080 /* Excessive Packet Deferral */ |
elessair | 0:f269e3021894 | 174 | #define TSV0_EXC_COLL 0x00000100 /* Excessive Collision */ |
elessair | 0:f269e3021894 | 175 | #define TSV0_LATE_COLL 0x00000200 /* Late Collision Occured */ |
elessair | 0:f269e3021894 | 176 | #define TSV0_GIANT 0x00000400 /* Giant Frame */ |
elessair | 0:f269e3021894 | 177 | #define TSV0_UNDERRUN 0x00000800 /* Buffer Underrun */ |
elessair | 0:f269e3021894 | 178 | #define TSV0_BYTES 0x0FFFF000 /* Total Bytes Transferred */ |
elessair | 0:f269e3021894 | 179 | #define TSV0_CTRL_FRAME 0x10000000 /* Control Frame */ |
elessair | 0:f269e3021894 | 180 | #define TSV0_PAUSE 0x20000000 /* Pause Frame */ |
elessair | 0:f269e3021894 | 181 | #define TSV0_BACK_PRESS 0x40000000 /* Backpressure Method Applied */ |
elessair | 0:f269e3021894 | 182 | #define TSV0_VLAN 0x80000000 /* VLAN Frame */ |
elessair | 0:f269e3021894 | 183 | |
elessair | 0:f269e3021894 | 184 | /* Transmit Status Vector 1 Register */ |
elessair | 0:f269e3021894 | 185 | #define TSV1_BYTE_CNT 0x0000FFFF /* Transmit Byte Count */ |
elessair | 0:f269e3021894 | 186 | #define TSV1_COLL_CNT 0x000F0000 /* Transmit Collision Count */ |
elessair | 0:f269e3021894 | 187 | |
elessair | 0:f269e3021894 | 188 | /* Receive Status Vector Register */ |
elessair | 0:f269e3021894 | 189 | #define RSV_BYTE_CNT 0x0000FFFF /* Receive Byte Count */ |
elessair | 0:f269e3021894 | 190 | #define RSV_PKT_IGNORED 0x00010000 /* Packet Previously Ignored */ |
elessair | 0:f269e3021894 | 191 | #define RSV_RXDV_SEEN 0x00020000 /* RXDV Event Previously Seen */ |
elessair | 0:f269e3021894 | 192 | #define RSV_CARR_SEEN 0x00040000 /* Carrier Event Previously Seen */ |
elessair | 0:f269e3021894 | 193 | #define RSV_REC_CODEV 0x00080000 /* Receive Code Violation */ |
elessair | 0:f269e3021894 | 194 | #define RSV_CRC_ERR 0x00100000 /* CRC Error */ |
elessair | 0:f269e3021894 | 195 | #define RSV_LEN_CHKERR 0x00200000 /* Length Check Error */ |
elessair | 0:f269e3021894 | 196 | #define RSV_LEN_OUTRNG 0x00400000 /* Length Out of Range */ |
elessair | 0:f269e3021894 | 197 | #define RSV_REC_OK 0x00800000 /* Frame Received OK */ |
elessair | 0:f269e3021894 | 198 | #define RSV_MCAST 0x01000000 /* Multicast Frame */ |
elessair | 0:f269e3021894 | 199 | #define RSV_BCAST 0x02000000 /* Broadcast Frame */ |
elessair | 0:f269e3021894 | 200 | #define RSV_DRIB_NIBB 0x04000000 /* Dribble Nibble */ |
elessair | 0:f269e3021894 | 201 | #define RSV_CTRL_FRAME 0x08000000 /* Control Frame */ |
elessair | 0:f269e3021894 | 202 | #define RSV_PAUSE 0x10000000 /* Pause Frame */ |
elessair | 0:f269e3021894 | 203 | #define RSV_UNSUPP_OPC 0x20000000 /* Unsupported Opcode */ |
elessair | 0:f269e3021894 | 204 | #define RSV_VLAN 0x40000000 /* VLAN Frame */ |
elessair | 0:f269e3021894 | 205 | |
elessair | 0:f269e3021894 | 206 | /* Flow Control Counter Register */ |
elessair | 0:f269e3021894 | 207 | #define FCC_MIRR_CNT 0x0000FFFF /* Mirror Counter */ |
elessair | 0:f269e3021894 | 208 | #define FCC_PAUSE_TIM 0xFFFF0000 /* Pause Timer */ |
elessair | 0:f269e3021894 | 209 | |
elessair | 0:f269e3021894 | 210 | /* Flow Control Status Register */ |
elessair | 0:f269e3021894 | 211 | #define FCS_MIRR_CNT 0x0000FFFF /* Mirror Counter Current */ |
elessair | 0:f269e3021894 | 212 | |
elessair | 0:f269e3021894 | 213 | /* Receive Filter Control Register */ |
elessair | 0:f269e3021894 | 214 | #define RFC_UCAST_EN 0x00000001 /* Accept Unicast Frames Enable */ |
elessair | 0:f269e3021894 | 215 | #define RFC_BCAST_EN 0x00000002 /* Accept Broadcast Frames Enable */ |
elessair | 0:f269e3021894 | 216 | #define RFC_MCAST_EN 0x00000004 /* Accept Multicast Frames Enable */ |
elessair | 0:f269e3021894 | 217 | #define RFC_UCAST_HASH_EN 0x00000008 /* Accept Unicast Hash Filter Frames */ |
elessair | 0:f269e3021894 | 218 | #define RFC_MCAST_HASH_EN 0x00000010 /* Accept Multicast Hash Filter Fram.*/ |
elessair | 0:f269e3021894 | 219 | #define RFC_PERFECT_EN 0x00000020 /* Accept Perfect Match Enable */ |
elessair | 0:f269e3021894 | 220 | #define RFC_MAGP_WOL_EN 0x00001000 /* Magic Packet Filter WoL Enable */ |
elessair | 0:f269e3021894 | 221 | #define RFC_PFILT_WOL_EN 0x00002000 /* Perfect Filter WoL Enable */ |
elessair | 0:f269e3021894 | 222 | |
elessair | 0:f269e3021894 | 223 | /* Receive Filter WoL Status/Clear Registers */ |
elessair | 0:f269e3021894 | 224 | #define WOL_UCAST 0x00000001 /* Unicast Frame caused WoL */ |
elessair | 0:f269e3021894 | 225 | #define WOL_BCAST 0x00000002 /* Broadcast Frame caused WoL */ |
elessair | 0:f269e3021894 | 226 | #define WOL_MCAST 0x00000004 /* Multicast Frame caused WoL */ |
elessair | 0:f269e3021894 | 227 | #define WOL_UCAST_HASH 0x00000008 /* Unicast Hash Filter Frame WoL */ |
elessair | 0:f269e3021894 | 228 | #define WOL_MCAST_HASH 0x00000010 /* Multicast Hash Filter Frame WoL */ |
elessair | 0:f269e3021894 | 229 | #define WOL_PERFECT 0x00000020 /* Perfect Filter WoL */ |
elessair | 0:f269e3021894 | 230 | #define WOL_RX_FILTER 0x00000080 /* RX Filter caused WoL */ |
elessair | 0:f269e3021894 | 231 | #define WOL_MAG_PACKET 0x00000100 /* Magic Packet Filter caused WoL */ |
elessair | 0:f269e3021894 | 232 | |
elessair | 0:f269e3021894 | 233 | /* Interrupt Status/Enable/Clear/Set Registers */ |
elessair | 0:f269e3021894 | 234 | #define INT_RX_OVERRUN 0x00000001 /* Overrun Error in RX Queue */ |
elessair | 0:f269e3021894 | 235 | #define INT_RX_ERR 0x00000002 /* Receive Error */ |
elessair | 0:f269e3021894 | 236 | #define INT_RX_FIN 0x00000004 /* RX Finished Process Descriptors */ |
elessair | 0:f269e3021894 | 237 | #define INT_RX_DONE 0x00000008 /* Receive Done */ |
elessair | 0:f269e3021894 | 238 | #define INT_TX_UNDERRUN 0x00000010 /* Transmit Underrun */ |
elessair | 0:f269e3021894 | 239 | #define INT_TX_ERR 0x00000020 /* Transmit Error */ |
elessair | 0:f269e3021894 | 240 | #define INT_TX_FIN 0x00000040 /* TX Finished Process Descriptors */ |
elessair | 0:f269e3021894 | 241 | #define INT_TX_DONE 0x00000080 /* Transmit Done */ |
elessair | 0:f269e3021894 | 242 | #define INT_SOFT_INT 0x00001000 /* Software Triggered Interrupt */ |
elessair | 0:f269e3021894 | 243 | #define INT_WAKEUP 0x00002000 /* Wakeup Event Interrupt */ |
elessair | 0:f269e3021894 | 244 | |
elessair | 0:f269e3021894 | 245 | /* Power Down Register */ |
elessair | 0:f269e3021894 | 246 | #define PD_POWER_DOWN 0x80000000 /* Power Down MAC */ |
elessair | 0:f269e3021894 | 247 | |
elessair | 0:f269e3021894 | 248 | /* RX Descriptor Control Word */ |
elessair | 0:f269e3021894 | 249 | #define RCTRL_SIZE 0x000007FF /* Buffer size mask */ |
elessair | 0:f269e3021894 | 250 | #define RCTRL_INT 0x80000000 /* Generate RxDone Interrupt */ |
elessair | 0:f269e3021894 | 251 | |
elessair | 0:f269e3021894 | 252 | /* RX Status Hash CRC Word */ |
elessair | 0:f269e3021894 | 253 | #define RHASH_SA 0x000001FF /* Hash CRC for Source Address */ |
elessair | 0:f269e3021894 | 254 | #define RHASH_DA 0x001FF000 /* Hash CRC for Destination Address */ |
elessair | 0:f269e3021894 | 255 | |
elessair | 0:f269e3021894 | 256 | /* RX Status Information Word */ |
elessair | 0:f269e3021894 | 257 | #define RINFO_SIZE 0x000007FF /* Data size in bytes */ |
elessair | 0:f269e3021894 | 258 | #define RINFO_CTRL_FRAME 0x00040000 /* Control Frame */ |
elessair | 0:f269e3021894 | 259 | #define RINFO_VLAN 0x00080000 /* VLAN Frame */ |
elessair | 0:f269e3021894 | 260 | #define RINFO_FAIL_FILT 0x00100000 /* RX Filter Failed */ |
elessair | 0:f269e3021894 | 261 | #define RINFO_MCAST 0x00200000 /* Multicast Frame */ |
elessair | 0:f269e3021894 | 262 | #define RINFO_BCAST 0x00400000 /* Broadcast Frame */ |
elessair | 0:f269e3021894 | 263 | #define RINFO_CRC_ERR 0x00800000 /* CRC Error in Frame */ |
elessair | 0:f269e3021894 | 264 | #define RINFO_SYM_ERR 0x01000000 /* Symbol Error from PHY */ |
elessair | 0:f269e3021894 | 265 | #define RINFO_LEN_ERR 0x02000000 /* Length Error */ |
elessair | 0:f269e3021894 | 266 | #define RINFO_RANGE_ERR 0x04000000 /* Range Error (exceeded max. size) */ |
elessair | 0:f269e3021894 | 267 | #define RINFO_ALIGN_ERR 0x08000000 /* Alignment Error */ |
elessair | 0:f269e3021894 | 268 | #define RINFO_OVERRUN 0x10000000 /* Receive overrun */ |
elessair | 0:f269e3021894 | 269 | #define RINFO_NO_DESCR 0x20000000 /* No new Descriptor available */ |
elessair | 0:f269e3021894 | 270 | #define RINFO_LAST_FLAG 0x40000000 /* Last Fragment in Frame */ |
elessair | 0:f269e3021894 | 271 | #define RINFO_ERR 0x80000000 /* Error Occured (OR of all errors) */ |
elessair | 0:f269e3021894 | 272 | |
elessair | 0:f269e3021894 | 273 | //#define RINFO_ERR_MASK (RINFO_FAIL_FILT | RINFO_CRC_ERR | RINFO_SYM_ERR | RINFO_LEN_ERR | RINFO_ALIGN_ERR | RINFO_OVERRUN) |
elessair | 0:f269e3021894 | 274 | #define RINFO_ERR_MASK (RINFO_FAIL_FILT | RINFO_SYM_ERR | \ |
elessair | 0:f269e3021894 | 275 | RINFO_LEN_ERR | RINFO_ALIGN_ERR | RINFO_OVERRUN) |
elessair | 0:f269e3021894 | 276 | |
elessair | 0:f269e3021894 | 277 | |
elessair | 0:f269e3021894 | 278 | /* TX Descriptor Control Word */ |
elessair | 0:f269e3021894 | 279 | #define TCTRL_SIZE 0x000007FF /* Size of data buffer in bytes */ |
elessair | 0:f269e3021894 | 280 | #define TCTRL_OVERRIDE 0x04000000 /* Override Default MAC Registers */ |
elessair | 0:f269e3021894 | 281 | #define TCTRL_HUGE 0x08000000 /* Enable Huge Frame */ |
elessair | 0:f269e3021894 | 282 | #define TCTRL_PAD 0x10000000 /* Pad short Frames to 64 bytes */ |
elessair | 0:f269e3021894 | 283 | #define TCTRL_CRC 0x20000000 /* Append a hardware CRC to Frame */ |
elessair | 0:f269e3021894 | 284 | #define TCTRL_LAST 0x40000000 /* Last Descriptor for TX Frame */ |
elessair | 0:f269e3021894 | 285 | #define TCTRL_INT 0x80000000 /* Generate TxDone Interrupt */ |
elessair | 0:f269e3021894 | 286 | |
elessair | 0:f269e3021894 | 287 | /* TX Status Information Word */ |
elessair | 0:f269e3021894 | 288 | #define TINFO_COL_CNT 0x01E00000 /* Collision Count */ |
elessair | 0:f269e3021894 | 289 | #define TINFO_DEFER 0x02000000 /* Packet Deferred (not an error) */ |
elessair | 0:f269e3021894 | 290 | #define TINFO_EXCESS_DEF 0x04000000 /* Excessive Deferral */ |
elessair | 0:f269e3021894 | 291 | #define TINFO_EXCESS_COL 0x08000000 /* Excessive Collision */ |
elessair | 0:f269e3021894 | 292 | #define TINFO_LATE_COL 0x10000000 /* Late Collision Occured */ |
elessair | 0:f269e3021894 | 293 | #define TINFO_UNDERRUN 0x20000000 /* Transmit Underrun */ |
elessair | 0:f269e3021894 | 294 | #define TINFO_NO_DESCR 0x40000000 /* No new Descriptor available */ |
elessair | 0:f269e3021894 | 295 | #define TINFO_ERR 0x80000000 /* Error Occured (OR of all errors) */ |
elessair | 0:f269e3021894 | 296 | |
elessair | 0:f269e3021894 | 297 | /* ENET Device Revision ID */ |
elessair | 0:f269e3021894 | 298 | #define OLD_EMAC_MODULE_ID 0x39022000 /* Rev. ID for first rev '-' */ |
elessair | 0:f269e3021894 | 299 | |
elessair | 0:f269e3021894 | 300 | /* DP83848C PHY Registers */ |
elessair | 0:f269e3021894 | 301 | #define PHY_REG_BMCR 0x00 /* Basic Mode Control Register */ |
elessair | 0:f269e3021894 | 302 | #define PHY_REG_BMSR 0x01 /* Basic Mode Status Register */ |
elessair | 0:f269e3021894 | 303 | #define PHY_REG_IDR1 0x02 /* PHY Identifier 1 */ |
elessair | 0:f269e3021894 | 304 | #define PHY_REG_IDR2 0x03 /* PHY Identifier 2 */ |
elessair | 0:f269e3021894 | 305 | #define PHY_REG_ANAR 0x04 /* Auto-Negotiation Advertisement */ |
elessair | 0:f269e3021894 | 306 | #define PHY_REG_ANLPAR 0x05 /* Auto-Neg. Link Partner Abitily */ |
elessair | 0:f269e3021894 | 307 | #define PHY_REG_ANER 0x06 /* Auto-Neg. Expansion Register */ |
elessair | 0:f269e3021894 | 308 | #define PHY_REG_ANNPTR 0x07 /* Auto-Neg. Next Page TX */ |
elessair | 0:f269e3021894 | 309 | |
elessair | 0:f269e3021894 | 310 | /* PHY Extended Registers */ |
elessair | 0:f269e3021894 | 311 | #define PHY_REG_STS 0x10 /* Status Register */ |
elessair | 0:f269e3021894 | 312 | #define PHY_REG_MICR 0x11 /* MII Interrupt Control Register */ |
elessair | 0:f269e3021894 | 313 | #define PHY_REG_MISR 0x12 /* MII Interrupt Status Register */ |
elessair | 0:f269e3021894 | 314 | #define PHY_REG_FCSCR 0x14 /* False Carrier Sense Counter */ |
elessair | 0:f269e3021894 | 315 | #define PHY_REG_RECR 0x15 /* Receive Error Counter */ |
elessair | 0:f269e3021894 | 316 | #define PHY_REG_PCSR 0x16 /* PCS Sublayer Config. and Status */ |
elessair | 0:f269e3021894 | 317 | #define PHY_REG_RBR 0x17 /* RMII and Bypass Register */ |
elessair | 0:f269e3021894 | 318 | #define PHY_REG_LEDCR 0x18 /* LED Direct Control Register */ |
elessair | 0:f269e3021894 | 319 | #define PHY_REG_PHYCR 0x19 /* PHY Control Register */ |
elessair | 0:f269e3021894 | 320 | #define PHY_REG_10BTSCR 0x1A /* 10Base-T Status/Control Register */ |
elessair | 0:f269e3021894 | 321 | #define PHY_REG_CDCTRL1 0x1B /* CD Test Control and BIST Extens. */ |
elessair | 0:f269e3021894 | 322 | #define PHY_REG_EDCR 0x1D /* Energy Detect Control Register */ |
elessair | 0:f269e3021894 | 323 | |
elessair | 0:f269e3021894 | 324 | #define PHY_REG_SCSR 0x1F /* PHY Special Control/Status Register */ |
elessair | 0:f269e3021894 | 325 | |
elessair | 0:f269e3021894 | 326 | #define PHY_FULLD_100M 0x2100 /* Full Duplex 100Mbit */ |
elessair | 0:f269e3021894 | 327 | #define PHY_HALFD_100M 0x2000 /* Half Duplex 100Mbit */ |
elessair | 0:f269e3021894 | 328 | #define PHY_FULLD_10M 0x0100 /* Full Duplex 10Mbit */ |
elessair | 0:f269e3021894 | 329 | #define PHY_HALFD_10M 0x0000 /* Half Duplex 10MBit */ |
elessair | 0:f269e3021894 | 330 | #define PHY_AUTO_NEG 0x3000 /* Select Auto Negotiation */ |
elessair | 0:f269e3021894 | 331 | |
elessair | 0:f269e3021894 | 332 | #define DP83848C_DEF_ADR 0x0100 /* Default PHY device address */ |
elessair | 0:f269e3021894 | 333 | #define DP83848C_ID 0x20005C90 /* PHY Identifier - DP83848C */ |
elessair | 0:f269e3021894 | 334 | |
elessair | 0:f269e3021894 | 335 | #define LAN8720_ID 0x0007C0F0 /* PHY Identifier - LAN8720 */ |
elessair | 0:f269e3021894 | 336 | |
elessair | 0:f269e3021894 | 337 | #define PHY_STS_LINK 0x0001 /* PHY Status Link Mask */ |
elessair | 0:f269e3021894 | 338 | #define PHY_STS_SPEED 0x0002 /* PHY Status Speed Mask */ |
elessair | 0:f269e3021894 | 339 | #define PHY_STS_DUPLEX 0x0004 /* PHY Status Duplex Mask */ |
elessair | 0:f269e3021894 | 340 | |
elessair | 0:f269e3021894 | 341 | #define PHY_BMCR_RESET 0x8000 /* PHY Reset */ |
elessair | 0:f269e3021894 | 342 | |
elessair | 0:f269e3021894 | 343 | #define PHY_BMSR_LINK 0x0004 /* PHY BMSR Link valid */ |
elessair | 0:f269e3021894 | 344 | |
elessair | 0:f269e3021894 | 345 | #define PHY_SCSR_100MBIT 0x0008 /* Speed: 1=100 MBit, 0=10Mbit */ |
elessair | 0:f269e3021894 | 346 | #define PHY_SCSR_DUPLEX 0x0010 /* PHY Duplex Mask */ |
elessair | 0:f269e3021894 | 347 | |
elessair | 0:f269e3021894 | 348 | |
elessair | 0:f269e3021894 | 349 | static int phy_read(unsigned int PhyReg); |
elessair | 0:f269e3021894 | 350 | static int phy_write(unsigned int PhyReg, unsigned short Data); |
elessair | 0:f269e3021894 | 351 | |
elessair | 0:f269e3021894 | 352 | static void txdscr_init(void); |
elessair | 0:f269e3021894 | 353 | static void rxdscr_init(void); |
elessair | 0:f269e3021894 | 354 | |
elessair | 0:f269e3021894 | 355 | #if defined (__ICCARM__) |
elessair | 0:f269e3021894 | 356 | # define AHBSRAM1 |
elessair | 0:f269e3021894 | 357 | #elif defined(TOOLCHAIN_GCC_CR) |
elessair | 0:f269e3021894 | 358 | # define AHBSRAM1 __attribute__((section(".data.$RamPeriph32"))) |
elessair | 0:f269e3021894 | 359 | #else |
elessair | 0:f269e3021894 | 360 | # define AHBSRAM1 __attribute__((section("AHBSRAM1"),aligned)) |
elessair | 0:f269e3021894 | 361 | #endif |
elessair | 0:f269e3021894 | 362 | |
elessair | 0:f269e3021894 | 363 | AHBSRAM1 volatile uint8_t rxbuf[NUM_RX_FRAG][ETH_FRAG_SIZE]; |
elessair | 0:f269e3021894 | 364 | AHBSRAM1 volatile uint8_t txbuf[NUM_TX_FRAG][ETH_FRAG_SIZE]; |
elessair | 0:f269e3021894 | 365 | AHBSRAM1 volatile RX_DESC_TypeDef rxdesc[NUM_RX_FRAG]; |
elessair | 0:f269e3021894 | 366 | AHBSRAM1 volatile RX_STAT_TypeDef rxstat[NUM_RX_FRAG]; |
elessair | 0:f269e3021894 | 367 | AHBSRAM1 volatile TX_DESC_TypeDef txdesc[NUM_TX_FRAG]; |
elessair | 0:f269e3021894 | 368 | AHBSRAM1 volatile TX_STAT_TypeDef txstat[NUM_TX_FRAG]; |
elessair | 0:f269e3021894 | 369 | |
elessair | 0:f269e3021894 | 370 | |
elessair | 0:f269e3021894 | 371 | #if NEW_LOGIC |
elessair | 0:f269e3021894 | 372 | static int rx_consume_offset = -1; |
elessair | 0:f269e3021894 | 373 | static int tx_produce_offset = -1; |
elessair | 0:f269e3021894 | 374 | #else |
elessair | 0:f269e3021894 | 375 | static int send_doff = 0; |
elessair | 0:f269e3021894 | 376 | static int send_idx = -1; |
elessair | 0:f269e3021894 | 377 | static int send_size = 0; |
elessair | 0:f269e3021894 | 378 | |
elessair | 0:f269e3021894 | 379 | static int receive_soff = 0; |
elessair | 0:f269e3021894 | 380 | static int receive_idx = -1; |
elessair | 0:f269e3021894 | 381 | #endif |
elessair | 0:f269e3021894 | 382 | |
elessair | 0:f269e3021894 | 383 | static uint32_t phy_id = 0; |
elessair | 0:f269e3021894 | 384 | |
elessair | 0:f269e3021894 | 385 | static inline int rinc(int idx, int mod) { |
elessair | 0:f269e3021894 | 386 | ++idx; |
elessair | 0:f269e3021894 | 387 | idx %= mod; |
elessair | 0:f269e3021894 | 388 | return idx; |
elessair | 0:f269e3021894 | 389 | } |
elessair | 0:f269e3021894 | 390 | |
elessair | 0:f269e3021894 | 391 | //extern unsigned int SystemFrequency; |
elessair | 0:f269e3021894 | 392 | static inline unsigned int clockselect() { |
elessair | 0:f269e3021894 | 393 | if(SystemCoreClock < 10000000) { |
elessair | 0:f269e3021894 | 394 | return 1; |
elessair | 0:f269e3021894 | 395 | } else if(SystemCoreClock < 15000000) { |
elessair | 0:f269e3021894 | 396 | return 2; |
elessair | 0:f269e3021894 | 397 | } else if(SystemCoreClock < 20000000) { |
elessair | 0:f269e3021894 | 398 | return 3; |
elessair | 0:f269e3021894 | 399 | } else if(SystemCoreClock < 25000000) { |
elessair | 0:f269e3021894 | 400 | return 4; |
elessair | 0:f269e3021894 | 401 | } else if(SystemCoreClock < 35000000) { |
elessair | 0:f269e3021894 | 402 | return 5; |
elessair | 0:f269e3021894 | 403 | } else if(SystemCoreClock < 50000000) { |
elessair | 0:f269e3021894 | 404 | return 6; |
elessair | 0:f269e3021894 | 405 | } else if(SystemCoreClock < 70000000) { |
elessair | 0:f269e3021894 | 406 | return 7; |
elessair | 0:f269e3021894 | 407 | } else if(SystemCoreClock < 80000000) { |
elessair | 0:f269e3021894 | 408 | return 8; |
elessair | 0:f269e3021894 | 409 | } else if(SystemCoreClock < 90000000) { |
elessair | 0:f269e3021894 | 410 | return 9; |
elessair | 0:f269e3021894 | 411 | } else if(SystemCoreClock < 100000000) { |
elessair | 0:f269e3021894 | 412 | return 10; |
elessair | 0:f269e3021894 | 413 | } else if(SystemCoreClock < 120000000) { |
elessair | 0:f269e3021894 | 414 | return 11; |
elessair | 0:f269e3021894 | 415 | } else if(SystemCoreClock < 130000000) { |
elessair | 0:f269e3021894 | 416 | return 12; |
elessair | 0:f269e3021894 | 417 | } else if(SystemCoreClock < 140000000) { |
elessair | 0:f269e3021894 | 418 | return 13; |
elessair | 0:f269e3021894 | 419 | } else if(SystemCoreClock < 150000000) { |
elessair | 0:f269e3021894 | 420 | return 15; |
elessair | 0:f269e3021894 | 421 | } else if(SystemCoreClock < 160000000) { |
elessair | 0:f269e3021894 | 422 | return 16; |
elessair | 0:f269e3021894 | 423 | } else { |
elessair | 0:f269e3021894 | 424 | return 0; |
elessair | 0:f269e3021894 | 425 | } |
elessair | 0:f269e3021894 | 426 | } |
elessair | 0:f269e3021894 | 427 | |
elessair | 0:f269e3021894 | 428 | #ifndef min |
elessair | 0:f269e3021894 | 429 | #define min(x, y) (((x)<(y))?(x):(y)) |
elessair | 0:f269e3021894 | 430 | #endif |
elessair | 0:f269e3021894 | 431 | |
elessair | 0:f269e3021894 | 432 | /*---------------------------------------------------------------------------- |
elessair | 0:f269e3021894 | 433 | Ethernet Device initialize |
elessair | 0:f269e3021894 | 434 | *----------------------------------------------------------------------------*/ |
elessair | 0:f269e3021894 | 435 | int ethernet_init() { |
elessair | 0:f269e3021894 | 436 | int regv, tout; |
elessair | 0:f269e3021894 | 437 | char mac[ETHERNET_ADDR_SIZE]; |
elessair | 0:f269e3021894 | 438 | unsigned int clock = clockselect(); |
elessair | 0:f269e3021894 | 439 | |
elessair | 0:f269e3021894 | 440 | LPC_SC->PCONP |= 0x40000000; /* Power Up the EMAC controller. */ |
elessair | 0:f269e3021894 | 441 | |
elessair | 0:f269e3021894 | 442 | LPC_PINCON->PINSEL2 = 0x50150105; /* Enable P1 Ethernet Pins. */ |
elessair | 0:f269e3021894 | 443 | LPC_PINCON->PINSEL3 = (LPC_PINCON->PINSEL3 & ~0x0000000F) | 0x00000005; |
elessair | 0:f269e3021894 | 444 | |
elessair | 0:f269e3021894 | 445 | /* Reset all EMAC internal modules. */ |
elessair | 0:f269e3021894 | 446 | LPC_EMAC->MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | |
elessair | 0:f269e3021894 | 447 | MAC1_RES_MCS_RX | MAC1_SIM_RES | MAC1_SOFT_RES; |
elessair | 0:f269e3021894 | 448 | LPC_EMAC->Command = CR_REG_RES | CR_TX_RES | CR_RX_RES | CR_PASS_RUNT_FRM; |
elessair | 0:f269e3021894 | 449 | |
elessair | 0:f269e3021894 | 450 | for(tout = 100; tout; tout--) __NOP(); /* A short delay after reset. */ |
elessair | 0:f269e3021894 | 451 | |
elessair | 0:f269e3021894 | 452 | LPC_EMAC->MAC1 = MAC1_PASS_ALL; /* Initialize MAC control registers. */ |
elessair | 0:f269e3021894 | 453 | LPC_EMAC->MAC2 = MAC2_CRC_EN | MAC2_PAD_EN; |
elessair | 0:f269e3021894 | 454 | LPC_EMAC->MAXF = ETH_MAX_FLEN; |
elessair | 0:f269e3021894 | 455 | LPC_EMAC->CLRT = CLRT_DEF; |
elessair | 0:f269e3021894 | 456 | LPC_EMAC->IPGR = IPGR_DEF; |
elessair | 0:f269e3021894 | 457 | |
elessair | 0:f269e3021894 | 458 | LPC_EMAC->Command = CR_RMII | CR_PASS_RUNT_FRM; /* Enable Reduced MII interface. */ |
elessair | 0:f269e3021894 | 459 | |
elessair | 0:f269e3021894 | 460 | LPC_EMAC->MCFG = (clock << 0x2) & MCFG_CLK_SEL; /* Set clock */ |
elessair | 0:f269e3021894 | 461 | LPC_EMAC->MCFG |= MCFG_RES_MII; /* and reset */ |
elessair | 0:f269e3021894 | 462 | |
elessair | 0:f269e3021894 | 463 | for(tout = 100; tout; tout--) __NOP(); /* A short delay */ |
elessair | 0:f269e3021894 | 464 | |
elessair | 0:f269e3021894 | 465 | LPC_EMAC->MCFG = (clock << 0x2) & MCFG_CLK_SEL; |
elessair | 0:f269e3021894 | 466 | LPC_EMAC->MCMD = 0; |
elessair | 0:f269e3021894 | 467 | |
elessair | 0:f269e3021894 | 468 | LPC_EMAC->SUPP = SUPP_RES_RMII; /* Reset Reduced MII Logic. */ |
elessair | 0:f269e3021894 | 469 | |
elessair | 0:f269e3021894 | 470 | for (tout = 100; tout; tout--) __NOP(); /* A short delay */ |
elessair | 0:f269e3021894 | 471 | |
elessair | 0:f269e3021894 | 472 | LPC_EMAC->SUPP = 0; |
elessair | 0:f269e3021894 | 473 | |
elessair | 0:f269e3021894 | 474 | phy_write(PHY_REG_BMCR, PHY_BMCR_RESET); /* perform PHY reset */ |
elessair | 0:f269e3021894 | 475 | for(tout = 0x20000; ; tout--) { /* Wait for hardware reset to end. */ |
elessair | 0:f269e3021894 | 476 | regv = phy_read(PHY_REG_BMCR); |
elessair | 0:f269e3021894 | 477 | if(regv < 0 || tout == 0) { |
elessair | 0:f269e3021894 | 478 | return -1; /* Error */ |
elessair | 0:f269e3021894 | 479 | } |
elessair | 0:f269e3021894 | 480 | if(!(regv & PHY_BMCR_RESET)) { |
elessair | 0:f269e3021894 | 481 | break; /* Reset complete. */ |
elessair | 0:f269e3021894 | 482 | } |
elessair | 0:f269e3021894 | 483 | } |
elessair | 0:f269e3021894 | 484 | |
elessair | 0:f269e3021894 | 485 | phy_id = (phy_read(PHY_REG_IDR1) << 16); |
elessair | 0:f269e3021894 | 486 | phy_id |= (phy_read(PHY_REG_IDR2) & 0XFFF0); |
elessair | 0:f269e3021894 | 487 | |
elessair | 0:f269e3021894 | 488 | if (phy_id != DP83848C_ID && phy_id != LAN8720_ID) { |
elessair | 0:f269e3021894 | 489 | error("Unknown Ethernet PHY (%x)", (unsigned int)phy_id); |
elessair | 0:f269e3021894 | 490 | } |
elessair | 0:f269e3021894 | 491 | |
elessair | 0:f269e3021894 | 492 | ethernet_set_link(-1, 0); |
elessair | 0:f269e3021894 | 493 | |
elessair | 0:f269e3021894 | 494 | /* Set the Ethernet MAC Address registers */ |
elessair | 0:f269e3021894 | 495 | ethernet_address(mac); |
elessair | 0:f269e3021894 | 496 | LPC_EMAC->SA0 = ((uint32_t)mac[5] << 8) | (uint32_t)mac[4]; |
elessair | 0:f269e3021894 | 497 | LPC_EMAC->SA1 = ((uint32_t)mac[3] << 8) | (uint32_t)mac[2]; |
elessair | 0:f269e3021894 | 498 | LPC_EMAC->SA2 = ((uint32_t)mac[1] << 8) | (uint32_t)mac[0]; |
elessair | 0:f269e3021894 | 499 | |
elessair | 0:f269e3021894 | 500 | txdscr_init(); /* initialize DMA TX Descriptor */ |
elessair | 0:f269e3021894 | 501 | rxdscr_init(); /* initialize DMA RX Descriptor */ |
elessair | 0:f269e3021894 | 502 | |
elessair | 0:f269e3021894 | 503 | LPC_EMAC->RxFilterCtrl = RFC_UCAST_EN | RFC_MCAST_EN | RFC_BCAST_EN | RFC_PERFECT_EN; |
elessair | 0:f269e3021894 | 504 | /* Receive Broadcast, Perfect Match Packets */ |
elessair | 0:f269e3021894 | 505 | |
elessair | 0:f269e3021894 | 506 | LPC_EMAC->IntEnable = INT_RX_DONE | INT_TX_DONE; /* Enable EMAC interrupts. */ |
elessair | 0:f269e3021894 | 507 | LPC_EMAC->IntClear = 0xFFFF; /* Reset all interrupts */ |
elessair | 0:f269e3021894 | 508 | |
elessair | 0:f269e3021894 | 509 | |
elessair | 0:f269e3021894 | 510 | LPC_EMAC->Command |= (CR_RX_EN | CR_TX_EN); /* Enable receive and transmit mode of MAC Ethernet core */ |
elessair | 0:f269e3021894 | 511 | LPC_EMAC->MAC1 |= MAC1_REC_EN; |
elessair | 0:f269e3021894 | 512 | |
elessair | 0:f269e3021894 | 513 | #if NEW_LOGIC |
elessair | 0:f269e3021894 | 514 | rx_consume_offset = -1; |
elessair | 0:f269e3021894 | 515 | tx_produce_offset = -1; |
elessair | 0:f269e3021894 | 516 | #else |
elessair | 0:f269e3021894 | 517 | send_doff = 0; |
elessair | 0:f269e3021894 | 518 | send_idx = -1; |
elessair | 0:f269e3021894 | 519 | send_size = 0; |
elessair | 0:f269e3021894 | 520 | |
elessair | 0:f269e3021894 | 521 | receive_soff = 0; |
elessair | 0:f269e3021894 | 522 | receive_idx = -1; |
elessair | 0:f269e3021894 | 523 | #endif |
elessair | 0:f269e3021894 | 524 | |
elessair | 0:f269e3021894 | 525 | return 0; |
elessair | 0:f269e3021894 | 526 | } |
elessair | 0:f269e3021894 | 527 | |
elessair | 0:f269e3021894 | 528 | /*---------------------------------------------------------------------------- |
elessair | 0:f269e3021894 | 529 | Ethernet Device Uninitialize |
elessair | 0:f269e3021894 | 530 | *----------------------------------------------------------------------------*/ |
elessair | 0:f269e3021894 | 531 | void ethernet_free() { |
elessair | 0:f269e3021894 | 532 | LPC_EMAC->IntEnable &= ~(INT_RX_DONE | INT_TX_DONE); |
elessair | 0:f269e3021894 | 533 | LPC_EMAC->IntClear = 0xFFFF; |
elessair | 0:f269e3021894 | 534 | |
elessair | 0:f269e3021894 | 535 | LPC_SC->PCONP &= ~0x40000000; /* Power down the EMAC controller. */ |
elessair | 0:f269e3021894 | 536 | |
elessair | 0:f269e3021894 | 537 | LPC_PINCON->PINSEL2 &= ~0x50150105; /* Disable P1 ethernet pins. */ |
elessair | 0:f269e3021894 | 538 | LPC_PINCON->PINSEL3 = (LPC_PINCON->PINSEL3 & ~0x0000000F) | 0x00000000; |
elessair | 0:f269e3021894 | 539 | } |
elessair | 0:f269e3021894 | 540 | |
elessair | 0:f269e3021894 | 541 | // if(TxProduceIndex == TxConsumeIndex) buffer array is empty |
elessair | 0:f269e3021894 | 542 | // if(TxProduceIndex == TxConsumeIndex - 1) buffer is full, should not fill |
elessair | 0:f269e3021894 | 543 | // TxProduceIndex - The buffer that will/is being fileld by driver, s/w increment |
elessair | 0:f269e3021894 | 544 | // TxConsumeIndex - The buffer that will/is beign sent by hardware |
elessair | 0:f269e3021894 | 545 | |
elessair | 0:f269e3021894 | 546 | int ethernet_write(const char *data, int slen) { |
elessair | 0:f269e3021894 | 547 | |
elessair | 0:f269e3021894 | 548 | #if NEW_LOGIC |
elessair | 0:f269e3021894 | 549 | |
elessair | 0:f269e3021894 | 550 | if(tx_produce_offset < 0) { // mark as active if not already |
elessair | 0:f269e3021894 | 551 | tx_produce_offset = 0; |
elessair | 0:f269e3021894 | 552 | } |
elessair | 0:f269e3021894 | 553 | |
elessair | 0:f269e3021894 | 554 | int index = LPC_EMAC->TxProduceIndex; |
elessair | 0:f269e3021894 | 555 | |
elessair | 0:f269e3021894 | 556 | int remaining = ETH_MAX_FLEN - tx_produce_offset - 4; // bytes written plus checksum |
elessair | 0:f269e3021894 | 557 | int requested = slen; |
elessair | 0:f269e3021894 | 558 | int ncopy = min(remaining, requested); |
elessair | 0:f269e3021894 | 559 | |
elessair | 0:f269e3021894 | 560 | void *pdst = (void *)(txdesc[index].Packet + tx_produce_offset); |
elessair | 0:f269e3021894 | 561 | void *psrc = (void *)(data); |
elessair | 0:f269e3021894 | 562 | |
elessair | 0:f269e3021894 | 563 | if(ncopy > 0 ){ |
elessair | 0:f269e3021894 | 564 | if(data != NULL) { |
elessair | 0:f269e3021894 | 565 | memcpy(pdst, psrc, ncopy); |
elessair | 0:f269e3021894 | 566 | } else { |
elessair | 0:f269e3021894 | 567 | memset(pdst, 0, ncopy); |
elessair | 0:f269e3021894 | 568 | } |
elessair | 0:f269e3021894 | 569 | } |
elessair | 0:f269e3021894 | 570 | |
elessair | 0:f269e3021894 | 571 | tx_produce_offset += ncopy; |
elessair | 0:f269e3021894 | 572 | |
elessair | 0:f269e3021894 | 573 | return ncopy; |
elessair | 0:f269e3021894 | 574 | |
elessair | 0:f269e3021894 | 575 | #else |
elessair | 0:f269e3021894 | 576 | void *pdst, *psrc; |
elessair | 0:f269e3021894 | 577 | const int dlen = ETH_FRAG_SIZE; |
elessair | 0:f269e3021894 | 578 | int copy = 0; |
elessair | 0:f269e3021894 | 579 | int soff = 0; |
elessair | 0:f269e3021894 | 580 | |
elessair | 0:f269e3021894 | 581 | if(send_idx == -1) { |
elessair | 0:f269e3021894 | 582 | send_idx = LPC_EMAC->TxProduceIndex; |
elessair | 0:f269e3021894 | 583 | } |
elessair | 0:f269e3021894 | 584 | |
elessair | 0:f269e3021894 | 585 | if(slen + send_doff > ethernet_MTU_SIZE) { |
elessair | 0:f269e3021894 | 586 | return -1; |
elessair | 0:f269e3021894 | 587 | } |
elessair | 0:f269e3021894 | 588 | |
elessair | 0:f269e3021894 | 589 | do { |
elessair | 0:f269e3021894 | 590 | copy = min(slen - soff, dlen - send_doff); |
elessair | 0:f269e3021894 | 591 | pdst = (void *)(txdesc[send_idx].Packet + send_doff); |
elessair | 0:f269e3021894 | 592 | psrc = (void *)(data + soff); |
elessair | 0:f269e3021894 | 593 | if(send_doff + copy > ETH_FRAG_SIZE) { |
elessair | 0:f269e3021894 | 594 | txdesc[send_idx].Ctrl = (send_doff-1) | (TCTRL_INT); |
elessair | 0:f269e3021894 | 595 | send_idx = rinc(send_idx, NUM_TX_FRAG); |
elessair | 0:f269e3021894 | 596 | send_doff = 0; |
elessair | 0:f269e3021894 | 597 | } |
elessair | 0:f269e3021894 | 598 | |
elessair | 0:f269e3021894 | 599 | if(data != NULL) { |
elessair | 0:f269e3021894 | 600 | memcpy(pdst, psrc, copy); |
elessair | 0:f269e3021894 | 601 | } else { |
elessair | 0:f269e3021894 | 602 | memset(pdst, 0, copy); |
elessair | 0:f269e3021894 | 603 | } |
elessair | 0:f269e3021894 | 604 | |
elessair | 0:f269e3021894 | 605 | soff += copy; |
elessair | 0:f269e3021894 | 606 | send_doff += copy; |
elessair | 0:f269e3021894 | 607 | send_size += copy; |
elessair | 0:f269e3021894 | 608 | } while(soff != slen); |
elessair | 0:f269e3021894 | 609 | |
elessair | 0:f269e3021894 | 610 | return soff; |
elessair | 0:f269e3021894 | 611 | #endif |
elessair | 0:f269e3021894 | 612 | } |
elessair | 0:f269e3021894 | 613 | |
elessair | 0:f269e3021894 | 614 | int ethernet_send() { |
elessair | 0:f269e3021894 | 615 | |
elessair | 0:f269e3021894 | 616 | #if NEW_LOGIC |
elessair | 0:f269e3021894 | 617 | if(tx_produce_offset < 0) { // no buffer active |
elessair | 0:f269e3021894 | 618 | return -1; |
elessair | 0:f269e3021894 | 619 | } |
elessair | 0:f269e3021894 | 620 | |
elessair | 0:f269e3021894 | 621 | // ensure there is a link |
elessair | 0:f269e3021894 | 622 | if(!ethernet_link()) { |
elessair | 0:f269e3021894 | 623 | return -2; |
elessair | 0:f269e3021894 | 624 | } |
elessair | 0:f269e3021894 | 625 | |
elessair | 0:f269e3021894 | 626 | // we have been writing in to a buffer, so finalise it |
elessair | 0:f269e3021894 | 627 | int size = tx_produce_offset; |
elessair | 0:f269e3021894 | 628 | int index = LPC_EMAC->TxProduceIndex; |
elessair | 0:f269e3021894 | 629 | txdesc[index].Ctrl = (tx_produce_offset-1) | (TCTRL_INT | TCTRL_LAST); |
elessair | 0:f269e3021894 | 630 | |
elessair | 0:f269e3021894 | 631 | // Increment ProduceIndex to allow it to be sent |
elessair | 0:f269e3021894 | 632 | // We can only do this if the next slot is free |
elessair | 0:f269e3021894 | 633 | int next = rinc(index, NUM_TX_FRAG); |
elessair | 0:f269e3021894 | 634 | while(next == LPC_EMAC->TxConsumeIndex) { |
elessair | 0:f269e3021894 | 635 | for(int i=0; i<1000; i++) { __NOP(); } |
elessair | 0:f269e3021894 | 636 | } |
elessair | 0:f269e3021894 | 637 | |
elessair | 0:f269e3021894 | 638 | LPC_EMAC->TxProduceIndex = next; |
elessair | 0:f269e3021894 | 639 | tx_produce_offset = -1; |
elessair | 0:f269e3021894 | 640 | return size; |
elessair | 0:f269e3021894 | 641 | |
elessair | 0:f269e3021894 | 642 | #else |
elessair | 0:f269e3021894 | 643 | int s = send_size; |
elessair | 0:f269e3021894 | 644 | txdesc[send_idx].Ctrl = (send_doff-1) | (TCTRL_INT | TCTRL_LAST); |
elessair | 0:f269e3021894 | 645 | send_idx = rinc(send_idx, NUM_TX_FRAG); |
elessair | 0:f269e3021894 | 646 | LPC_EMAC->TxProduceIndex = send_idx; |
elessair | 0:f269e3021894 | 647 | send_doff = 0; |
elessair | 0:f269e3021894 | 648 | send_idx = -1; |
elessair | 0:f269e3021894 | 649 | send_size = 0; |
elessair | 0:f269e3021894 | 650 | return s; |
elessair | 0:f269e3021894 | 651 | #endif |
elessair | 0:f269e3021894 | 652 | } |
elessair | 0:f269e3021894 | 653 | |
elessair | 0:f269e3021894 | 654 | // RxConsmeIndex - The index of buffer the driver will/is reading from. Driver should inc once read |
elessair | 0:f269e3021894 | 655 | // RxProduceIndex - The index of buffer that will/is being filled by MAC. H/w will inc once rxd |
elessair | 0:f269e3021894 | 656 | // |
elessair | 0:f269e3021894 | 657 | // if(RxConsumeIndex == RxProduceIndex) buffer array is empty |
elessair | 0:f269e3021894 | 658 | // if(RxConsumeIndex == RxProduceIndex + 1) buffer array is full |
elessair | 0:f269e3021894 | 659 | |
elessair | 0:f269e3021894 | 660 | // Recevies an arrived ethernet packet. |
elessair | 0:f269e3021894 | 661 | // Receiving an ethernet packet will drop the last received ethernet packet |
elessair | 0:f269e3021894 | 662 | // and make a new ethernet packet ready to read. |
elessair | 0:f269e3021894 | 663 | // Returns size of packet, else 0 if nothing to receive |
elessair | 0:f269e3021894 | 664 | |
elessair | 0:f269e3021894 | 665 | // We read from RxConsumeIndex from position rx_consume_offset |
elessair | 0:f269e3021894 | 666 | // if rx_consume_offset < 0, then we have not recieved the RxConsumeIndex packet for reading |
elessair | 0:f269e3021894 | 667 | // rx_consume_offset = -1 // no frame |
elessair | 0:f269e3021894 | 668 | // rx_consume_offset = 0 // start of frame |
elessair | 0:f269e3021894 | 669 | // Assumption: A fragment should alway be a whole frame |
elessair | 0:f269e3021894 | 670 | |
elessair | 0:f269e3021894 | 671 | int ethernet_receive() { |
elessair | 0:f269e3021894 | 672 | #if NEW_LOGIC |
elessair | 0:f269e3021894 | 673 | |
elessair | 0:f269e3021894 | 674 | // if we are currently reading a valid RxConsume buffer, increment to the next one |
elessair | 0:f269e3021894 | 675 | if(rx_consume_offset >= 0) { |
elessair | 0:f269e3021894 | 676 | LPC_EMAC->RxConsumeIndex = rinc(LPC_EMAC->RxConsumeIndex, NUM_RX_FRAG); |
elessair | 0:f269e3021894 | 677 | } |
elessair | 0:f269e3021894 | 678 | |
elessair | 0:f269e3021894 | 679 | // if the buffer is empty, mark it as no valid buffer |
elessair | 0:f269e3021894 | 680 | if(LPC_EMAC->RxConsumeIndex == LPC_EMAC->RxProduceIndex) { |
elessair | 0:f269e3021894 | 681 | rx_consume_offset = -1; |
elessair | 0:f269e3021894 | 682 | return 0; |
elessair | 0:f269e3021894 | 683 | } |
elessair | 0:f269e3021894 | 684 | |
elessair | 0:f269e3021894 | 685 | uint32_t info = rxstat[LPC_EMAC->RxConsumeIndex].Info; |
elessair | 0:f269e3021894 | 686 | rx_consume_offset = 0; |
elessair | 0:f269e3021894 | 687 | |
elessair | 0:f269e3021894 | 688 | // check if it is not marked as last or for errors |
elessair | 0:f269e3021894 | 689 | if(!(info & RINFO_LAST_FLAG) || (info & RINFO_ERR_MASK)) { |
elessair | 0:f269e3021894 | 690 | return -1; |
elessair | 0:f269e3021894 | 691 | } |
elessair | 0:f269e3021894 | 692 | |
elessair | 0:f269e3021894 | 693 | int size = (info & RINFO_SIZE) + 1; |
elessair | 0:f269e3021894 | 694 | return size - 4; // don't include checksum bytes |
elessair | 0:f269e3021894 | 695 | |
elessair | 0:f269e3021894 | 696 | #else |
elessair | 0:f269e3021894 | 697 | if(receive_idx == -1) { |
elessair | 0:f269e3021894 | 698 | receive_idx = LPC_EMAC->RxConsumeIndex; |
elessair | 0:f269e3021894 | 699 | } else { |
elessair | 0:f269e3021894 | 700 | while(!(rxstat[receive_idx].Info & RINFO_LAST_FLAG) && ((uint32_t)receive_idx != LPC_EMAC->RxProduceIndex)) { |
elessair | 0:f269e3021894 | 701 | receive_idx = rinc(receive_idx, NUM_RX_FRAG); |
elessair | 0:f269e3021894 | 702 | } |
elessair | 0:f269e3021894 | 703 | unsigned int info = rxstat[receive_idx].Info; |
elessair | 0:f269e3021894 | 704 | int slen = (info & RINFO_SIZE) + 1; |
elessair | 0:f269e3021894 | 705 | |
elessair | 0:f269e3021894 | 706 | if(slen > ethernet_MTU_SIZE || (info & RINFO_ERR_MASK)) { |
elessair | 0:f269e3021894 | 707 | /* Invalid frame, ignore it and free buffer. */ |
elessair | 0:f269e3021894 | 708 | receive_idx = rinc(receive_idx, NUM_RX_FRAG); |
elessair | 0:f269e3021894 | 709 | } |
elessair | 0:f269e3021894 | 710 | receive_idx = rinc(receive_idx, NUM_RX_FRAG); |
elessair | 0:f269e3021894 | 711 | receive_soff = 0; |
elessair | 0:f269e3021894 | 712 | |
elessair | 0:f269e3021894 | 713 | LPC_EMAC->RxConsumeIndex = receive_idx; |
elessair | 0:f269e3021894 | 714 | } |
elessair | 0:f269e3021894 | 715 | |
elessair | 0:f269e3021894 | 716 | if((uint32_t)receive_idx == LPC_EMAC->RxProduceIndex) { |
elessair | 0:f269e3021894 | 717 | receive_idx = -1; |
elessair | 0:f269e3021894 | 718 | return 0; |
elessair | 0:f269e3021894 | 719 | } |
elessair | 0:f269e3021894 | 720 | |
elessair | 0:f269e3021894 | 721 | return (rxstat[receive_idx].Info & RINFO_SIZE) - 3; |
elessair | 0:f269e3021894 | 722 | #endif |
elessair | 0:f269e3021894 | 723 | } |
elessair | 0:f269e3021894 | 724 | |
elessair | 0:f269e3021894 | 725 | // Read from an recevied ethernet packet. |
elessair | 0:f269e3021894 | 726 | // After receive returnd a number bigger than 0 it is |
elessair | 0:f269e3021894 | 727 | // possible to read bytes from this packet. |
elessair | 0:f269e3021894 | 728 | // Read will write up to size bytes into data. |
elessair | 0:f269e3021894 | 729 | // It is possible to use read multible times. |
elessair | 0:f269e3021894 | 730 | // Each time read will start reading after the last read byte before. |
elessair | 0:f269e3021894 | 731 | |
elessair | 0:f269e3021894 | 732 | int ethernet_read(char *data, int dlen) { |
elessair | 0:f269e3021894 | 733 | #if NEW_LOGIC |
elessair | 0:f269e3021894 | 734 | // Check we have a valid buffer to read |
elessair | 0:f269e3021894 | 735 | if(rx_consume_offset < 0) { |
elessair | 0:f269e3021894 | 736 | return 0; |
elessair | 0:f269e3021894 | 737 | } |
elessair | 0:f269e3021894 | 738 | |
elessair | 0:f269e3021894 | 739 | // Assume 1 fragment block |
elessair | 0:f269e3021894 | 740 | uint32_t info = rxstat[LPC_EMAC->RxConsumeIndex].Info; |
elessair | 0:f269e3021894 | 741 | int size = (info & RINFO_SIZE) + 1 - 4; // exclude checksum |
elessair | 0:f269e3021894 | 742 | |
elessair | 0:f269e3021894 | 743 | int remaining = size - rx_consume_offset; |
elessair | 0:f269e3021894 | 744 | int requested = dlen; |
elessair | 0:f269e3021894 | 745 | int ncopy = min(remaining, requested); |
elessair | 0:f269e3021894 | 746 | |
elessair | 0:f269e3021894 | 747 | void *psrc = (void *)(rxdesc[LPC_EMAC->RxConsumeIndex].Packet + rx_consume_offset); |
elessair | 0:f269e3021894 | 748 | void *pdst = (void *)(data); |
elessair | 0:f269e3021894 | 749 | |
elessair | 0:f269e3021894 | 750 | if(data != NULL && ncopy > 0) { |
elessair | 0:f269e3021894 | 751 | memcpy(pdst, psrc, ncopy); |
elessair | 0:f269e3021894 | 752 | } |
elessair | 0:f269e3021894 | 753 | |
elessair | 0:f269e3021894 | 754 | rx_consume_offset += ncopy; |
elessair | 0:f269e3021894 | 755 | |
elessair | 0:f269e3021894 | 756 | return ncopy; |
elessair | 0:f269e3021894 | 757 | #else |
elessair | 0:f269e3021894 | 758 | int slen; |
elessair | 0:f269e3021894 | 759 | int copy = 0; |
elessair | 0:f269e3021894 | 760 | unsigned int more; |
elessair | 0:f269e3021894 | 761 | unsigned int info; |
elessair | 0:f269e3021894 | 762 | void *pdst, *psrc; |
elessair | 0:f269e3021894 | 763 | int doff = 0; |
elessair | 0:f269e3021894 | 764 | |
elessair | 0:f269e3021894 | 765 | if((uint32_t)receive_idx == LPC_EMAC->RxProduceIndex || receive_idx == -1) { |
elessair | 0:f269e3021894 | 766 | return 0; |
elessair | 0:f269e3021894 | 767 | } |
elessair | 0:f269e3021894 | 768 | |
elessair | 0:f269e3021894 | 769 | do { |
elessair | 0:f269e3021894 | 770 | info = rxstat[receive_idx].Info; |
elessair | 0:f269e3021894 | 771 | more = !(info & RINFO_LAST_FLAG); |
elessair | 0:f269e3021894 | 772 | slen = (info & RINFO_SIZE) + 1; |
elessair | 0:f269e3021894 | 773 | |
elessair | 0:f269e3021894 | 774 | if(slen > ethernet_MTU_SIZE || (info & RINFO_ERR_MASK)) { |
elessair | 0:f269e3021894 | 775 | /* Invalid frame, ignore it and free buffer. */ |
elessair | 0:f269e3021894 | 776 | receive_idx = rinc(receive_idx, NUM_RX_FRAG); |
elessair | 0:f269e3021894 | 777 | } else { |
elessair | 0:f269e3021894 | 778 | |
elessair | 0:f269e3021894 | 779 | copy = min(slen - receive_soff, dlen - doff); |
elessair | 0:f269e3021894 | 780 | psrc = (void *)(rxdesc[receive_idx].Packet + receive_soff); |
elessair | 0:f269e3021894 | 781 | pdst = (void *)(data + doff); |
elessair | 0:f269e3021894 | 782 | |
elessair | 0:f269e3021894 | 783 | if(data != NULL) { |
elessair | 0:f269e3021894 | 784 | /* check if Buffer available */ |
elessair | 0:f269e3021894 | 785 | memcpy(pdst, psrc, copy); |
elessair | 0:f269e3021894 | 786 | } |
elessair | 0:f269e3021894 | 787 | |
elessair | 0:f269e3021894 | 788 | receive_soff += copy; |
elessair | 0:f269e3021894 | 789 | doff += copy; |
elessair | 0:f269e3021894 | 790 | |
elessair | 0:f269e3021894 | 791 | if((more && (receive_soff == slen))) { |
elessair | 0:f269e3021894 | 792 | receive_idx = rinc(receive_idx, NUM_RX_FRAG); |
elessair | 0:f269e3021894 | 793 | receive_soff = 0; |
elessair | 0:f269e3021894 | 794 | } |
elessair | 0:f269e3021894 | 795 | } |
elessair | 0:f269e3021894 | 796 | } while(more && !(doff == dlen) && !receive_soff); |
elessair | 0:f269e3021894 | 797 | |
elessair | 0:f269e3021894 | 798 | return doff; |
elessair | 0:f269e3021894 | 799 | #endif |
elessair | 0:f269e3021894 | 800 | } |
elessair | 0:f269e3021894 | 801 | |
elessair | 0:f269e3021894 | 802 | int ethernet_link(void) { |
elessair | 0:f269e3021894 | 803 | if (phy_id == DP83848C_ID) { |
elessair | 0:f269e3021894 | 804 | return (phy_read(PHY_REG_STS) & PHY_STS_LINK); |
elessair | 0:f269e3021894 | 805 | } |
elessair | 0:f269e3021894 | 806 | else { // LAN8720_ID |
elessair | 0:f269e3021894 | 807 | return (phy_read(PHY_REG_BMSR) & PHY_BMSR_LINK); |
elessair | 0:f269e3021894 | 808 | } |
elessair | 0:f269e3021894 | 809 | } |
elessair | 0:f269e3021894 | 810 | |
elessair | 0:f269e3021894 | 811 | static int phy_write(unsigned int PhyReg, unsigned short Data) { |
elessair | 0:f269e3021894 | 812 | unsigned int timeOut; |
elessair | 0:f269e3021894 | 813 | |
elessair | 0:f269e3021894 | 814 | LPC_EMAC->MADR = DP83848C_DEF_ADR | PhyReg; |
elessair | 0:f269e3021894 | 815 | LPC_EMAC->MWTD = Data; |
elessair | 0:f269e3021894 | 816 | |
elessair | 0:f269e3021894 | 817 | for(timeOut = 0; timeOut < MII_WR_TOUT; timeOut++) { /* Wait until operation completed */ |
elessair | 0:f269e3021894 | 818 | if((LPC_EMAC->MIND & MIND_BUSY) == 0) { |
elessair | 0:f269e3021894 | 819 | return 0; |
elessair | 0:f269e3021894 | 820 | } |
elessair | 0:f269e3021894 | 821 | } |
elessair | 0:f269e3021894 | 822 | |
elessair | 0:f269e3021894 | 823 | return -1; |
elessair | 0:f269e3021894 | 824 | } |
elessair | 0:f269e3021894 | 825 | |
elessair | 0:f269e3021894 | 826 | static int phy_read(unsigned int PhyReg) { |
elessair | 0:f269e3021894 | 827 | unsigned int timeOut; |
elessair | 0:f269e3021894 | 828 | |
elessair | 0:f269e3021894 | 829 | LPC_EMAC->MADR = DP83848C_DEF_ADR | PhyReg; |
elessair | 0:f269e3021894 | 830 | LPC_EMAC->MCMD = MCMD_READ; |
elessair | 0:f269e3021894 | 831 | |
elessair | 0:f269e3021894 | 832 | for(timeOut = 0; timeOut < MII_RD_TOUT; timeOut++) { /* Wait until operation completed */ |
elessair | 0:f269e3021894 | 833 | if((LPC_EMAC->MIND & MIND_BUSY) == 0) { |
elessair | 0:f269e3021894 | 834 | LPC_EMAC->MCMD = 0; |
elessair | 0:f269e3021894 | 835 | return LPC_EMAC->MRDD; /* Return a 16-bit value. */ |
elessair | 0:f269e3021894 | 836 | } |
elessair | 0:f269e3021894 | 837 | } |
elessair | 0:f269e3021894 | 838 | |
elessair | 0:f269e3021894 | 839 | return -1; |
elessair | 0:f269e3021894 | 840 | } |
elessair | 0:f269e3021894 | 841 | |
elessair | 0:f269e3021894 | 842 | |
elessair | 0:f269e3021894 | 843 | static void txdscr_init() { |
elessair | 0:f269e3021894 | 844 | int i; |
elessair | 0:f269e3021894 | 845 | |
elessair | 0:f269e3021894 | 846 | for(i = 0; i < NUM_TX_FRAG; i++) { |
elessair | 0:f269e3021894 | 847 | txdesc[i].Packet = (uint32_t)&txbuf[i]; |
elessair | 0:f269e3021894 | 848 | txdesc[i].Ctrl = 0; |
elessair | 0:f269e3021894 | 849 | txstat[i].Info = 0; |
elessair | 0:f269e3021894 | 850 | } |
elessair | 0:f269e3021894 | 851 | |
elessair | 0:f269e3021894 | 852 | LPC_EMAC->TxDescriptor = (uint32_t)txdesc; /* Set EMAC Transmit Descriptor Registers. */ |
elessair | 0:f269e3021894 | 853 | LPC_EMAC->TxStatus = (uint32_t)txstat; |
elessair | 0:f269e3021894 | 854 | LPC_EMAC->TxDescriptorNumber = NUM_TX_FRAG-1; |
elessair | 0:f269e3021894 | 855 | |
elessair | 0:f269e3021894 | 856 | LPC_EMAC->TxProduceIndex = 0; /* Tx Descriptors Point to 0 */ |
elessair | 0:f269e3021894 | 857 | } |
elessair | 0:f269e3021894 | 858 | |
elessair | 0:f269e3021894 | 859 | static void rxdscr_init() { |
elessair | 0:f269e3021894 | 860 | int i; |
elessair | 0:f269e3021894 | 861 | |
elessair | 0:f269e3021894 | 862 | for(i = 0; i < NUM_RX_FRAG; i++) { |
elessair | 0:f269e3021894 | 863 | rxdesc[i].Packet = (uint32_t)&rxbuf[i]; |
elessair | 0:f269e3021894 | 864 | rxdesc[i].Ctrl = RCTRL_INT | (ETH_FRAG_SIZE-1); |
elessair | 0:f269e3021894 | 865 | rxstat[i].Info = 0; |
elessair | 0:f269e3021894 | 866 | rxstat[i].HashCRC = 0; |
elessair | 0:f269e3021894 | 867 | } |
elessair | 0:f269e3021894 | 868 | |
elessair | 0:f269e3021894 | 869 | LPC_EMAC->RxDescriptor = (uint32_t)rxdesc; /* Set EMAC Receive Descriptor Registers. */ |
elessair | 0:f269e3021894 | 870 | LPC_EMAC->RxStatus = (uint32_t)rxstat; |
elessair | 0:f269e3021894 | 871 | LPC_EMAC->RxDescriptorNumber = NUM_RX_FRAG-1; |
elessair | 0:f269e3021894 | 872 | |
elessair | 0:f269e3021894 | 873 | LPC_EMAC->RxConsumeIndex = 0; /* Rx Descriptors Point to 0 */ |
elessair | 0:f269e3021894 | 874 | } |
elessair | 0:f269e3021894 | 875 | |
elessair | 0:f269e3021894 | 876 | void ethernet_address(char *mac) { |
elessair | 0:f269e3021894 | 877 | mbed_mac_address(mac); |
elessair | 0:f269e3021894 | 878 | } |
elessair | 0:f269e3021894 | 879 | |
elessair | 0:f269e3021894 | 880 | void ethernet_set_link(int speed, int duplex) { |
elessair | 0:f269e3021894 | 881 | unsigned short phy_data; |
elessair | 0:f269e3021894 | 882 | int tout; |
elessair | 0:f269e3021894 | 883 | |
elessair | 0:f269e3021894 | 884 | if((speed < 0) || (speed > 1)) { |
elessair | 0:f269e3021894 | 885 | phy_data = PHY_AUTO_NEG; |
elessair | 0:f269e3021894 | 886 | } else { |
elessair | 0:f269e3021894 | 887 | phy_data = (((unsigned short) speed << 13) | |
elessair | 0:f269e3021894 | 888 | ((unsigned short) duplex << 8)); |
elessair | 0:f269e3021894 | 889 | } |
elessair | 0:f269e3021894 | 890 | |
elessair | 0:f269e3021894 | 891 | phy_write(PHY_REG_BMCR, phy_data); |
elessair | 0:f269e3021894 | 892 | |
elessair | 0:f269e3021894 | 893 | for(tout = 100; tout; tout--) { __NOP(); } /* A short delay */ |
elessair | 0:f269e3021894 | 894 | |
elessair | 0:f269e3021894 | 895 | switch(phy_id) { |
elessair | 0:f269e3021894 | 896 | case DP83848C_ID: |
elessair | 0:f269e3021894 | 897 | phy_data = phy_read(PHY_REG_STS); |
elessair | 0:f269e3021894 | 898 | |
elessair | 0:f269e3021894 | 899 | if(phy_data & PHY_STS_DUPLEX) { |
elessair | 0:f269e3021894 | 900 | LPC_EMAC->MAC2 |= MAC2_FULL_DUP; |
elessair | 0:f269e3021894 | 901 | LPC_EMAC->Command |= CR_FULL_DUP; |
elessair | 0:f269e3021894 | 902 | LPC_EMAC->IPGT = IPGT_FULL_DUP; |
elessair | 0:f269e3021894 | 903 | } else { |
elessair | 0:f269e3021894 | 904 | LPC_EMAC->MAC2 &= ~MAC2_FULL_DUP; |
elessair | 0:f269e3021894 | 905 | LPC_EMAC->Command &= ~CR_FULL_DUP; |
elessair | 0:f269e3021894 | 906 | LPC_EMAC->IPGT = IPGT_HALF_DUP; |
elessair | 0:f269e3021894 | 907 | } |
elessair | 0:f269e3021894 | 908 | |
elessair | 0:f269e3021894 | 909 | if(phy_data & PHY_STS_SPEED) { |
elessair | 0:f269e3021894 | 910 | LPC_EMAC->SUPP &= ~SUPP_SPEED; |
elessair | 0:f269e3021894 | 911 | } else { |
elessair | 0:f269e3021894 | 912 | LPC_EMAC->SUPP |= SUPP_SPEED; |
elessair | 0:f269e3021894 | 913 | } |
elessair | 0:f269e3021894 | 914 | break; |
elessair | 0:f269e3021894 | 915 | |
elessair | 0:f269e3021894 | 916 | case LAN8720_ID: |
elessair | 0:f269e3021894 | 917 | phy_data = phy_read(PHY_REG_SCSR); |
elessair | 0:f269e3021894 | 918 | |
elessair | 0:f269e3021894 | 919 | if (phy_data & PHY_SCSR_DUPLEX) { |
elessair | 0:f269e3021894 | 920 | LPC_EMAC->MAC2 |= MAC2_FULL_DUP; |
elessair | 0:f269e3021894 | 921 | LPC_EMAC->Command |= CR_FULL_DUP; |
elessair | 0:f269e3021894 | 922 | LPC_EMAC->IPGT = IPGT_FULL_DUP; |
elessair | 0:f269e3021894 | 923 | } else { |
elessair | 0:f269e3021894 | 924 | LPC_EMAC->Command &= ~CR_FULL_DUP; |
elessair | 0:f269e3021894 | 925 | LPC_EMAC->IPGT = IPGT_HALF_DUP; |
elessair | 0:f269e3021894 | 926 | } |
elessair | 0:f269e3021894 | 927 | |
elessair | 0:f269e3021894 | 928 | if(phy_data & PHY_SCSR_100MBIT) { |
elessair | 0:f269e3021894 | 929 | LPC_EMAC->SUPP |= SUPP_SPEED; |
elessair | 0:f269e3021894 | 930 | } else { |
elessair | 0:f269e3021894 | 931 | LPC_EMAC->SUPP &= ~SUPP_SPEED; |
elessair | 0:f269e3021894 | 932 | } |
elessair | 0:f269e3021894 | 933 | break; |
elessair | 0:f269e3021894 | 934 | } |
elessair | 0:f269e3021894 | 935 | } |