summaryrefslogtreecommitdiffstats
path: root/include/hw/net/npcm7xx_emc.h
blob: eac7f2981678fdcc77ec47dc35d9c29df00cecc2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
/*
 * Nuvoton NPCM7xx EMC Module
 *
 * Copyright 2020 Google LLC
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 * for more details.
 */

#ifndef NPCM7XX_EMC_H
#define NPCM7XX_EMC_H

#include "hw/irq.h"
#include "hw/sysbus.h"
#include "net/net.h"

/* 32-bit register indices. */
enum NPCM7xxPWMRegister {
    /* Control registers. */
    REG_CAMCMR,
    REG_CAMEN,

    /* There are 16 CAMn[ML] registers. */
    REG_CAMM_BASE,
    REG_CAML_BASE,
    REG_CAMML_LAST = 0x21,

    REG_TXDLSA = 0x22,
    REG_RXDLSA,
    REG_MCMDR,
    REG_MIID,
    REG_MIIDA,
    REG_FFTCR,
    REG_TSDR,
    REG_RSDR,
    REG_DMARFC,
    REG_MIEN,

    /* Status registers. */
    REG_MISTA,
    REG_MGSTA,
    REG_MPCNT,
    REG_MRPC,
    REG_MRPCC,
    REG_MREPC,
    REG_DMARFS,
    REG_CTXDSA,
    REG_CTXBSA,
    REG_CRXDSA,
    REG_CRXBSA,

    NPCM7XX_NUM_EMC_REGS,
};

/* REG_CAMCMR fields */
/* Enable CAM Compare */
#define REG_CAMCMR_ECMP (1 << 4)
/* Complement CAM Compare */
#define REG_CAMCMR_CCAM (1 << 3)
/* Accept Broadcast Packet */
#define REG_CAMCMR_ABP (1 << 2)
/* Accept Multicast Packet */
#define REG_CAMCMR_AMP (1 << 1)
/* Accept Unicast Packet */
#define REG_CAMCMR_AUP (1 << 0)

/* REG_MCMDR fields */
/* Software Reset */
#define REG_MCMDR_SWR (1 << 24)
/* Internal Loopback Select */
#define REG_MCMDR_LBK (1 << 21)
/* Operation Mode Select */
#define REG_MCMDR_OPMOD (1 << 20)
/* Enable MDC Clock Generation */
#define REG_MCMDR_ENMDC (1 << 19)
/* Full-Duplex Mode Select */
#define REG_MCMDR_FDUP (1 << 18)
/* Enable SQE Checking */
#define REG_MCMDR_ENSEQ (1 << 17)
/* Send PAUSE Frame */
#define REG_MCMDR_SDPZ (1 << 16)
/* No Defer */
#define REG_MCMDR_NDEF (1 << 9)
/* Frame Transmission On */
#define REG_MCMDR_TXON (1 << 8)
/* Strip CRC Checksum */
#define REG_MCMDR_SPCRC (1 << 5)
/* Accept CRC Error Packet */
#define REG_MCMDR_AEP (1 << 4)
/* Accept Control Packet */
#define REG_MCMDR_ACP (1 << 3)
/* Accept Runt Packet */
#define REG_MCMDR_ARP (1 << 2)
/* Accept Long Packet */
#define REG_MCMDR_ALP (1 << 1)
/* Frame Reception On */
#define REG_MCMDR_RXON (1 << 0)

/* REG_MIEN fields */
/* Enable Transmit Descriptor Unavailable Interrupt */
#define REG_MIEN_ENTDU (1 << 23)
/* Enable Transmit Completion Interrupt */
#define REG_MIEN_ENTXCP (1 << 18)
/* Enable Transmit Interrupt */
#define REG_MIEN_ENTXINTR (1 << 16)
/* Enable Receive Descriptor Unavailable Interrupt */
#define REG_MIEN_ENRDU (1 << 10)
/* Enable Receive Good Interrupt */
#define REG_MIEN_ENRXGD (1 << 4)
/* Enable Receive Interrupt */
#define REG_MIEN_ENRXINTR (1 << 0)

/* REG_MISTA fields */
/* TODO: Add error fields and support simulated errors? */
/* Transmit Bus Error Interrupt */
#define REG_MISTA_TXBERR (1 << 24)
/* Transmit Descriptor Unavailable Interrupt */
#define REG_MISTA_TDU (1 << 23)
/* Transmit Completion Interrupt */
#define REG_MISTA_TXCP (1 << 18)
/* Transmit Interrupt */
#define REG_MISTA_TXINTR (1 << 16)
/* Receive Bus Error Interrupt */
#define REG_MISTA_RXBERR (1 << 11)
/* Receive Descriptor Unavailable Interrupt */
#define REG_MISTA_RDU (1 << 10)
/* DMA Early Notification Interrupt */
#define REG_MISTA_DENI (1 << 9)
/* Maximum Frame Length Interrupt */
#define REG_MISTA_DFOI (1 << 8)
/* Receive Good Interrupt */
#define REG_MISTA_RXGD (1 << 4)
/* Packet Too Long Interrupt */
#define REG_MISTA_PTLE (1 << 3)
/* Receive Interrupt */
#define REG_MISTA_RXINTR (1 << 0)

/* REG_MGSTA fields */
/* Transmission Halted */
#define REG_MGSTA_TXHA (1 << 11)
/* Receive Halted */
#define REG_MGSTA_RXHA (1 << 11)

/* REG_DMARFC fields */
/* Maximum Receive Frame Length */
#define REG_DMARFC_RXMS(word) extract32((word), 0, 16)

/* REG MIIDA fields */
/* Busy Bit */
#define REG_MIIDA_BUSY (1 << 17)

/* Transmit and receive descriptors */
typedef struct NPCM7xxEMCTxDesc NPCM7xxEMCTxDesc;
typedef struct NPCM7xxEMCRxDesc NPCM7xxEMCRxDesc;

struct NPCM7xxEMCTxDesc {
    uint32_t flags;
    uint32_t txbsa;
    uint32_t status_and_length;
    uint32_t ntxdsa;
};

struct NPCM7xxEMCRxDesc {
    uint32_t status_and_length;
    uint32_t rxbsa;
    uint32_t reserved;
    uint32_t nrxdsa;
};

/* NPCM7xxEMCTxDesc.flags values */
/* Owner: 0 = cpu, 1 = emc */
#define TX_DESC_FLAG_OWNER_MASK (1 << 31)
/* Transmit interrupt enable */
#define TX_DESC_FLAG_INTEN (1 << 2)
/* CRC append */
#define TX_DESC_FLAG_CRCAPP (1 << 1)
/* Padding enable */
#define TX_DESC_FLAG_PADEN (1 << 0)

/* NPCM7xxEMCTxDesc.status_and_length values */
/* Collision count */
#define TX_DESC_STATUS_CCNT_SHIFT 28
#define TX_DESC_STATUS_CCNT_BITSIZE 4
/* SQE error */
#define TX_DESC_STATUS_SQE (1 << 26)
/* Transmission paused */
#define TX_DESC_STATUS_PAU (1 << 25)
/* P transmission halted */
#define TX_DESC_STATUS_TXHA (1 << 24)
/* Late collision */
#define TX_DESC_STATUS_LC (1 << 23)
/* Transmission abort */
#define TX_DESC_STATUS_TXABT (1 << 22)
/* No carrier sense */
#define TX_DESC_STATUS_NCS (1 << 21)
/* Defer exceed */
#define TX_DESC_STATUS_EXDEF (1 << 20)
/* Transmission complete */
#define TX_DESC_STATUS_TXCP (1 << 19)
/* Transmission deferred */
#define TX_DESC_STATUS_DEF (1 << 17)
/* Transmit interrupt */
#define TX_DESC_STATUS_TXINTR (1 << 16)

#define TX_DESC_PKT_LEN(word) extract32((word), 0, 16)

/* Transmit buffer start address */
#define TX_DESC_TXBSA(word) ((uint32_t) (word) & ~3u)

/* Next transmit descriptor start address */
#define TX_DESC_NTXDSA(word) ((uint32_t) (word) & ~3u)

/* NPCM7xxEMCRxDesc.status_and_length values */
/* Owner: 0b00 = cpu, 0b01 = undefined, 0b10 = emc, 0b11 = undefined */
#define RX_DESC_STATUS_OWNER_SHIFT 30
#define RX_DESC_STATUS_OWNER_BITSIZE 2
#define RX_DESC_STATUS_OWNER_MASK (3 << RX_DESC_STATUS_OWNER_SHIFT)
/* Runt packet */
#define RX_DESC_STATUS_RP (1 << 22)
/* Alignment error */
#define RX_DESC_STATUS_ALIE (1 << 21)
/* Frame reception complete */
#define RX_DESC_STATUS_RXGD (1 << 20)
/* Packet too long */
#define RX_DESC_STATUS_PTLE (1 << 19)
/* CRC error */
#define RX_DESC_STATUS_CRCE (1 << 17)
/* Receive interrupt */
#define RX_DESC_STATUS_RXINTR (1 << 16)

#define RX_DESC_PKT_LEN(word) extract32((word), 0, 16)

/* Receive buffer start address */
#define RX_DESC_RXBSA(word) ((uint32_t) (word) & ~3u)

/* Next receive descriptor start address */
#define RX_DESC_NRXDSA(word) ((uint32_t) (word) & ~3u)

/* Minimum packet length, when TX_DESC_FLAG_PADEN is set. */
#define MIN_PACKET_LENGTH 64

struct NPCM7xxEMCState {
    /*< private >*/
    SysBusDevice parent;
    /*< public >*/

    MemoryRegion iomem;

    qemu_irq tx_irq;
    qemu_irq rx_irq;

    NICState *nic;
    NICConf conf;

    /* 0 or 1, for log messages */
    uint8_t emc_num;

    uint32_t regs[NPCM7XX_NUM_EMC_REGS];

    /*
     * tx is active. Set to true by TSDR and then switches off when out of
     * descriptors. If the TXON bit in REG_MCMDR is off then this is off.
     */
    bool tx_active;

    /*
     * rx is active. Set to true by RSDR and then switches off when out of
     * descriptors. If the RXON bit in REG_MCMDR is off then this is off.
     */
    bool rx_active;
};

typedef struct NPCM7xxEMCState NPCM7xxEMCState;

#define TYPE_NPCM7XX_EMC "npcm7xx-emc"
#define NPCM7XX_EMC(obj) \
    OBJECT_CHECK(NPCM7xxEMCState, (obj), TYPE_NPCM7XX_EMC)

#endif /* NPCM7XX_EMC_H */