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