drv_eth.c 19.5 KB
Newer Older
1 2

/*
W
Weilin Wang 已提交
3
 * Copyright (c) 2006-2020, RT-Thread Development Team
4 5 6 7 8 9 10 11
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author         Notes
 * 2020-10-30     bigmagic       first version
 */

B
bigmagic 已提交
12
#include <stdint.h>
13 14

#include <rthw.h>
B
bigmagic 已提交
15
#include <rtthread.h>
16 17
#include "board.h"

B
bigmagic 已提交
18 19 20 21 22 23 24
#include <lwip/sys.h>
#include <netif/ethernetif.h>

#include "mbox.h"
#include "raspi4.h"
#include "drv_eth.h"

W
Weilin Wang 已提交
25

B
bigmagic 已提交
26 27 28 29 30 31 32
#define DBG_LEVEL   DBG_LOG
#include <rtdbg.h>
#define LOG_TAG                "drv.eth"

static int link_speed = 0;
static int link_flag = 0;

W
Weilin Wang 已提交
33 34 35 36 37
#define RECV_CACHE_BUF          (1024)
#define SEND_CACHE_BUF          (1024)
#define SEND_DATA_NO_CACHE      (0x08200000)
#define RECV_DATA_NO_CACHE      (0x08400000)
#define DMA_DISC_ADDR_SIZE      (4 * 1024 *1024)
B
bigmagic 已提交
38

W
Weilin Wang 已提交
39 40
#define RX_DESC_BASE            (MAC_REG + GENET_RX_OFF)
#define TX_DESC_BASE            (MAC_REG + GENET_TX_OFF)
B
bigmagic 已提交
41

B
bigmagic 已提交
42 43 44 45 46 47
#define MAX_ADDR_LEN            (6)

#define upper_32_bits(n)        ((rt_uint32_t)(((n) >> 16) >> 16))
#define lower_32_bits(n)        ((rt_uint32_t)(n))

#define BIT(nr)                 (1UL << (nr))
B
bigmagic 已提交
48

B
bigmagic 已提交
49 50 51 52 53
static rt_thread_t link_thread_tid = RT_NULL;
#define LINK_THREAD_STACK_SIZE   (1024)
#define LINK_THREAD_PRIORITY     (20)
#define LINK_THREAD_TIMESLICE    (10)

B
bigmagic 已提交
54 55 56 57
static rt_uint32_t tx_index = 0;
static rt_uint32_t rx_index = 0;
static rt_uint32_t index_flag = 0;

W
Weilin Wang 已提交
58
static rt_uint32_t send_cache_pbuf[RECV_CACHE_BUF];
B
bigmagic 已提交
59 60 61 62 63 64 65 66 67 68

struct rt_eth_dev
{
    struct eth_device parent;
    rt_uint8_t dev_addr[MAX_ADDR_LEN];
    char *name;
    void *iobase;
    int state;
    int index;
    struct rt_timer link_timer;
W
Weilin Wang 已提交
69
    struct rt_timer rx_poll_timer;
B
bigmagic 已提交
70 71 72
    void *priv;
};
static struct rt_eth_dev eth_dev;
W
Weilin Wang 已提交
73
static struct rt_semaphore sem_lock;
B
bigmagic 已提交
74
static struct rt_semaphore link_ack;
B
bigmagic 已提交
75 76 77

static inline rt_uint32_t read32(void *addr)
{
78
    return (*((volatile unsigned int *)(addr)));
B
bigmagic 已提交
79 80 81 82
}

static inline void write32(void *addr, rt_uint32_t value)
{
83
    (*((volatile unsigned int *)(addr))) = value;
B
bigmagic 已提交
84 85
}

B
bigmagic 已提交
86
static void eth_rx_irq(int irq, void *param)
B
bigmagic 已提交
87
{
B
bigmagic 已提交
88
    rt_uint32_t val = 0;
W
Weilin Wang 已提交
89 90 91
    val = read32(MAC_REG + GENET_INTRL2_CPU_STAT);
    val &= ~read32(MAC_REG + GENET_INTRL2_CPU_STAT_MASK);
    write32(MAC_REG + GENET_INTRL2_CPU_CLEAR, val);
B
bigmagic 已提交
92 93 94 95 96 97 98
    if (val & GENET_IRQ_RXDMA_DONE)
    {
        eth_device_ready(&eth_dev.parent);
    }

    if (val & GENET_IRQ_TXDMA_DONE)
    {
W
Weilin Wang 已提交
99
        rt_sem_release(&sem_lock);
B
bigmagic 已提交
100
    }
B
bigmagic 已提交
101 102 103 104 105 106
}

/* We only support RGMII (as used on the RPi4). */
static int bcmgenet_interface_set(void)
{
    int phy_mode = PHY_INTERFACE_MODE_RGMII;
B
bigmagic 已提交
107 108
    switch (phy_mode)
    {
B
bigmagic 已提交
109 110
    case PHY_INTERFACE_MODE_RGMII:
    case PHY_INTERFACE_MODE_RGMII_RXID:
W
Weilin Wang 已提交
111
        write32(MAC_REG + SYS_PORT_CTRL, PORT_MODE_EXT_GPHY);
B
bigmagic 已提交
112 113
        break;
    default:
W
Weilin Wang 已提交
114
        rt_kprintf("unknown phy mode: %d\n", MAC_REG);
B
bigmagic 已提交
115 116 117 118 119 120 121 122
        return -1;
    }
    return 0;
}

static void bcmgenet_umac_reset(void)
{
    rt_uint32_t reg;
W
Weilin Wang 已提交
123
    reg = read32(MAC_REG + SYS_RBUF_FLUSH_CTRL);
B
bigmagic 已提交
124
    reg |= BIT(1);
W
Weilin Wang 已提交
125
    write32((MAC_REG + SYS_RBUF_FLUSH_CTRL), reg);
B
bigmagic 已提交
126 127

    reg &= ~BIT(1);
W
Weilin Wang 已提交
128
    write32((MAC_REG + SYS_RBUF_FLUSH_CTRL), reg);
B
bigmagic 已提交
129 130

    DELAY_MICROS(10);
W
Weilin Wang 已提交
131
    write32((MAC_REG + SYS_RBUF_FLUSH_CTRL), 0);
B
bigmagic 已提交
132
    DELAY_MICROS(10);
W
Weilin Wang 已提交
133 134
    write32(MAC_REG + UMAC_CMD, 0);
    write32(MAC_REG + UMAC_CMD, (CMD_SW_RESET | CMD_LCL_LOOP_EN));
B
bigmagic 已提交
135
    DELAY_MICROS(2);
W
Weilin Wang 已提交
136
    write32(MAC_REG + UMAC_CMD, 0);
B
bigmagic 已提交
137
    /* clear tx/rx counter */
W
Weilin Wang 已提交
138 139 140
    write32(MAC_REG + UMAC_MIB_CTRL, MIB_RESET_RX | MIB_RESET_TX | MIB_RESET_RUNT);
    write32(MAC_REG + UMAC_MIB_CTRL, 0);
    write32(MAC_REG + UMAC_MAX_FRAME_LEN, ENET_MAX_MTU_SIZE);
B
bigmagic 已提交
141
    /* init rx registers, enable ip header optimization */
W
Weilin Wang 已提交
142
    reg = read32(MAC_REG + RBUF_CTRL);
B
bigmagic 已提交
143
    reg |= RBUF_ALIGN_2B;
W
Weilin Wang 已提交
144 145
    write32(MAC_REG + RBUF_CTRL, reg);
    write32(MAC_REG + RBUF_TBUF_SIZE_CTRL, 1);
B
bigmagic 已提交
146 147 148 149 150 151
}

static void bcmgenet_disable_dma(void)
{
    rt_uint32_t tdma_reg = 0, rdma_reg = 0;

W
Weilin Wang 已提交
152
    tdma_reg = read32(MAC_REG + TDMA_REG_BASE + DMA_CTRL);
B
bigmagic 已提交
153
    tdma_reg &= ~(1UL << DMA_EN);
W
Weilin Wang 已提交
154 155
    write32(MAC_REG + TDMA_REG_BASE + DMA_CTRL, tdma_reg);
    rdma_reg = read32(MAC_REG + RDMA_REG_BASE + DMA_CTRL);
B
bigmagic 已提交
156
    rdma_reg &= ~(1UL << DMA_EN);
W
Weilin Wang 已提交
157 158
    write32(MAC_REG + RDMA_REG_BASE + DMA_CTRL, rdma_reg);
    write32(MAC_REG + UMAC_TX_FLUSH, 1);
B
bigmagic 已提交
159
    DELAY_MICROS(100);
W
Weilin Wang 已提交
160
    write32(MAC_REG + UMAC_TX_FLUSH, 0);
B
bigmagic 已提交
161 162 163 164 165 166 167 168
}

static void bcmgenet_enable_dma(void)
{
    rt_uint32_t reg = 0;
    rt_uint32_t dma_ctrl = 0;

    dma_ctrl = (1 << (DEFAULT_Q + DMA_RING_BUF_EN_SHIFT)) | DMA_EN;
W
Weilin Wang 已提交
169
    write32(MAC_REG + TDMA_REG_BASE + DMA_CTRL, dma_ctrl);
B
bigmagic 已提交
170

W
Weilin Wang 已提交
171 172
    reg = read32(MAC_REG + RDMA_REG_BASE + DMA_CTRL);
    write32(MAC_REG + RDMA_REG_BASE + DMA_CTRL, dma_ctrl | reg);
B
bigmagic 已提交
173 174 175 176 177 178
}

static int bcmgenet_mdio_write(rt_uint32_t addr, rt_uint32_t reg, rt_uint32_t value)
{
    int count = 10000;
    rt_uint32_t val;
B
bigmagic 已提交
179
    val = MDIO_WR | (addr << MDIO_PMD_SHIFT) | (reg << MDIO_REG_SHIFT) | (0xffff & value);
W
Weilin Wang 已提交
180
    write32(MAC_REG + MDIO_CMD, val);
B
bigmagic 已提交
181

W
Weilin Wang 已提交
182
    rt_uint32_t reg_val = read32(MAC_REG + MDIO_CMD);
B
bigmagic 已提交
183
    reg_val = reg_val | MDIO_START_BUSY;
W
Weilin Wang 已提交
184
    write32(MAC_REG + MDIO_CMD, reg_val);
B
bigmagic 已提交
185

W
Weilin Wang 已提交
186
    while ((read32(MAC_REG + MDIO_CMD) & MDIO_START_BUSY) && (--count))
B
bigmagic 已提交
187 188
        DELAY_MICROS(1);

W
Weilin Wang 已提交
189
    reg_val = read32(MAC_REG + MDIO_CMD);
B
bigmagic 已提交
190 191 192 193 194 195 196 197 198 199 200

    return reg_val & 0xffff;
}

static int bcmgenet_mdio_read(rt_uint32_t addr, rt_uint32_t reg)
{
    int count = 10000;
    rt_uint32_t val = 0;
    rt_uint32_t reg_val = 0;

    val = MDIO_RD | (addr << MDIO_PMD_SHIFT) | (reg << MDIO_REG_SHIFT);
W
Weilin Wang 已提交
201
    write32(MAC_REG + MDIO_CMD, val);
B
bigmagic 已提交
202

W
Weilin Wang 已提交
203
    reg_val = read32(MAC_REG + MDIO_CMD);
B
bigmagic 已提交
204
    reg_val = reg_val | MDIO_START_BUSY;
W
Weilin Wang 已提交
205
    write32(MAC_REG + MDIO_CMD, reg_val);
B
bigmagic 已提交
206

W
Weilin Wang 已提交
207
    while ((read32(MAC_REG + MDIO_CMD) & MDIO_START_BUSY) && (--count))
B
bigmagic 已提交
208 209
        DELAY_MICROS(1);

W
Weilin Wang 已提交
210
    reg_val = read32(MAC_REG + MDIO_CMD);
B
bigmagic 已提交
211

B
bigmagic 已提交
212
    return reg_val & 0xffff;
B
bigmagic 已提交
213 214 215 216
}

static int bcmgenet_gmac_write_hwaddr(void)
{
W
Weilin Wang 已提交
217
    //{0xdc,0xa6,0x32,0x28,0x22,0x50};
B
bigmagic 已提交
218 219 220 221 222
    rt_uint8_t addr[6];
    rt_uint32_t reg;
    bcm271x_mbox_hardware_get_mac_address(&addr[0]);

    reg = addr[0] << 24 | addr[1] << 16 | addr[2] << 8 | addr[3];
W
Weilin Wang 已提交
223
    write32(MAC_REG + UMAC_MAC0, reg);
B
bigmagic 已提交
224 225

    reg = addr[4] << 8 | addr[5];
W
Weilin Wang 已提交
226
    write32(MAC_REG + UMAC_MAC1, reg);
B
bigmagic 已提交
227 228 229
    return 0;
}

B
bigmagic 已提交
230
static int get_ethernet_uid(void)
B
bigmagic 已提交
231 232 233 234 235 236 237 238 239
{
    rt_uint32_t uid_high = 0;
    rt_uint32_t uid_low = 0;
    rt_uint32_t uid = 0;

    uid_high = bcmgenet_mdio_read(1, BCM54213PE_PHY_IDENTIFIER_HIGH);
    uid_low = bcmgenet_mdio_read(1, BCM54213PE_PHY_IDENTIFIER_LOW);
    uid = (uid_high << 16 | uid_low);

B
bigmagic 已提交
240
    if (BCM54213PE_VERSION_B1 == uid)
B
bigmagic 已提交
241
    {
B
bigmagic 已提交
242
        LOG_I("version is B1\n");
B
bigmagic 已提交
243 244 245 246 247 248 249 250 251
    }
    return uid;
}

static void bcmgenet_mdio_init(void)
{
    rt_uint32_t ret = 0;
    /*get ethernet uid*/
    ret = get_ethernet_uid();
W
Weilin Wang 已提交
252 253 254 255
    if (ret == 0)
    {
        return;
    }
B
bigmagic 已提交
256 257 258 259 260 261 262 263 264 265 266 267 268
    /* reset phy */
    bcmgenet_mdio_write(1, BCM54213PE_MII_CONTROL, MII_CONTROL_PHY_RESET);
    /* read control reg */
    bcmgenet_mdio_read(1, BCM54213PE_MII_CONTROL);
    /* reset phy again */
    bcmgenet_mdio_write(1, BCM54213PE_MII_CONTROL, MII_CONTROL_PHY_RESET);
    /* read control reg */
    bcmgenet_mdio_read(1, BCM54213PE_MII_CONTROL);
    /* read status reg */
    bcmgenet_mdio_read(1, BCM54213PE_MII_STATUS);
    /* read status reg */
    bcmgenet_mdio_read(1, BCM54213PE_IEEE_EXTENDED_STATUS);
    bcmgenet_mdio_read(1, BCM54213PE_AUTO_NEGOTIATION_ADV);
B
bigmagic 已提交
269

B
bigmagic 已提交
270 271 272 273 274
    bcmgenet_mdio_read(1, BCM54213PE_MII_STATUS);
    bcmgenet_mdio_read(1, BCM54213PE_CONTROL);
    /* half full duplex capability */
    bcmgenet_mdio_write(1, BCM54213PE_CONTROL, (CONTROL_HALF_DUPLEX_CAPABILITY | CONTROL_FULL_DUPLEX_CAPABILITY));
    bcmgenet_mdio_read(1, BCM54213PE_MII_CONTROL);
B
bigmagic 已提交
275

B
bigmagic 已提交
276
    /* set mii control */
B
bigmagic 已提交
277
    bcmgenet_mdio_write(1, BCM54213PE_MII_CONTROL, (MII_CONTROL_AUTO_NEGOTIATION_ENABLED | MII_CONTROL_AUTO_NEGOTIATION_RESTART | MII_CONTROL_PHY_FULL_DUPLEX | MII_CONTROL_SPEED_SELECTION));
B
bigmagic 已提交
278 279 280 281
}

static void rx_ring_init(void)
{
W
Weilin Wang 已提交
282 283 284 285 286 287 288 289 290 291 292
    write32(MAC_REG + RDMA_REG_BASE + DMA_SCB_BURST_SIZE, DMA_MAX_BURST_LENGTH);
    write32(MAC_REG + RDMA_RING_REG_BASE + DMA_START_ADDR, 0x0);
    write32(MAC_REG + RDMA_READ_PTR, 0x0);
    write32(MAC_REG + RDMA_WRITE_PTR, 0x0);
    write32(MAC_REG + RDMA_RING_REG_BASE + DMA_END_ADDR, RX_DESCS * DMA_DESC_SIZE / 4 - 1);

    write32(MAC_REG + RDMA_PROD_INDEX, 0x0);
    write32(MAC_REG + RDMA_CONS_INDEX, 0x0);
    write32(MAC_REG + RDMA_RING_REG_BASE + DMA_RING_BUF_SIZE, (RX_DESCS << DMA_RING_SIZE_SHIFT) | RX_BUF_LENGTH);
    write32(MAC_REG + RDMA_XON_XOFF_THRESH, DMA_FC_THRESH_VALUE);
    write32(MAC_REG + RDMA_REG_BASE + DMA_RING_CFG, 1 << DEFAULT_Q);
B
bigmagic 已提交
293 294 295 296
}

static void tx_ring_init(void)
{
W
Weilin Wang 已提交
297 298 299 300 301 302 303 304 305 306 307 308 309
    write32(MAC_REG + TDMA_REG_BASE + DMA_SCB_BURST_SIZE, DMA_MAX_BURST_LENGTH);
    write32(MAC_REG + TDMA_RING_REG_BASE + DMA_START_ADDR, 0x0);
    write32(MAC_REG + TDMA_READ_PTR, 0x0);
    write32(MAC_REG + TDMA_READ_PTR, 0x0);
    write32(MAC_REG + TDMA_READ_PTR, 0x0);
    write32(MAC_REG + TDMA_WRITE_PTR, 0x0);
    write32(MAC_REG + TDMA_RING_REG_BASE + DMA_END_ADDR, TX_DESCS * DMA_DESC_SIZE / 4 - 1);
    write32(MAC_REG + TDMA_PROD_INDEX, 0x0);
    write32(MAC_REG + TDMA_CONS_INDEX, 0x0);
    write32(MAC_REG + TDMA_RING_REG_BASE + DMA_MBUF_DONE_THRESH, 0x1);
    write32(MAC_REG + TDMA_FLOW_PERIOD, 0x0);
    write32(MAC_REG + TDMA_RING_REG_BASE + DMA_RING_BUF_SIZE, (TX_DESCS << DMA_RING_SIZE_SHIFT) | RX_BUF_LENGTH);
    write32(MAC_REG + TDMA_REG_BASE + DMA_RING_CFG, 1 << DEFAULT_Q);
B
bigmagic 已提交
310 311 312 313 314 315 316 317 318
}

static void rx_descs_init(void)
{
    char *rxbuffs = (char *)RECV_DATA_NO_CACHE;
    rt_uint32_t len_stat, i;
    void *desc_base = (void *)RX_DESC_BASE;

    len_stat = (RX_BUF_LENGTH << DMA_BUFLENGTH_SHIFT) | DMA_OWN;
B
bigmagic 已提交
319
    for (i = 0; i < RX_DESCS; i++)
B
bigmagic 已提交
320
    {
B
bigmagic 已提交
321 322 323
        write32((desc_base + i * DMA_DESC_SIZE + DMA_DESC_ADDRESS_LO), lower_32_bits((uintptr_t)&rxbuffs[i * RX_BUF_LENGTH]));
        write32((desc_base + i * DMA_DESC_SIZE + DMA_DESC_ADDRESS_HI), upper_32_bits((uintptr_t)&rxbuffs[i * RX_BUF_LENGTH]));
        write32((desc_base + i * DMA_DESC_SIZE + DMA_DESC_LENGTH_STATUS), len_stat);
B
bigmagic 已提交
324 325 326
    }
}

B
bigmagic 已提交
327
static int bcmgenet_adjust_link(void)
B
bigmagic 已提交
328 329
{
    rt_uint32_t speed;
B
bigmagic 已提交
330 331 332 333
    rt_uint32_t phy_dev_speed = link_speed;

    switch (phy_dev_speed)
    {
B
bigmagic 已提交
334 335 336 337 338 339 340 341 342 343 344 345 346 347
    case SPEED_1000:
        speed = UMAC_SPEED_1000;
        break;
    case SPEED_100:
        speed = UMAC_SPEED_100;
        break;
    case SPEED_10:
        speed = UMAC_SPEED_10;
        break;
    default:
        rt_kprintf("bcmgenet: Unsupported PHY speed: %d\n", phy_dev_speed);
        return -1;
    }

W
Weilin Wang 已提交
348
    rt_uint32_t reg1 = read32(MAC_REG + EXT_RGMII_OOB_CTRL);
B
bigmagic 已提交
349 350 351 352
    //reg1 &= ~(1UL << OOB_DISABLE);

    //rt_kprintf("OOB_DISABLE is %d\n", OOB_DISABLE);
    reg1 |= (RGMII_LINK | RGMII_MODE_EN | ID_MODE_DIS);
W
Weilin Wang 已提交
353
    write32(MAC_REG + EXT_RGMII_OOB_CTRL, reg1);
B
bigmagic 已提交
354
    DELAY_MICROS(1000);
W
Weilin Wang 已提交
355
    write32(MAC_REG + UMAC_CMD, speed << CMD_SPEED_SHIFT);
B
bigmagic 已提交
356 357 358
    return 0;
}

B
bigmagic 已提交
359 360 361 362 363 364 365 366
void link_irq(void *param)
{
    if ((bcmgenet_mdio_read(1, BCM54213PE_MII_STATUS) & MII_STATUS_LINK_UP) != 0)
    {
        rt_sem_release(&link_ack);
    }
}

B
bigmagic 已提交
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
static int bcmgenet_gmac_eth_start(void)
{
    rt_uint32_t ret;
    rt_uint32_t count = 10000;

    bcmgenet_umac_reset();

    bcmgenet_gmac_write_hwaddr();
    /* Disable RX/TX DMA and flush TX queues */
    bcmgenet_disable_dma();
    rx_ring_init();
    rx_descs_init();
    tx_ring_init();

    /* Enable RX/TX DMA */
    bcmgenet_enable_dma();

    /* Update MAC registers based on PHY property */
    ret = bcmgenet_adjust_link();
386
    if (ret)
B
bigmagic 已提交
387
    {
B
bigmagic 已提交
388 389 390 391 392
        rt_kprintf("bcmgenet: adjust PHY link failed: %d\n", ret);
        return ret;
    }

    /* wait tx index clear */
W
Weilin Wang 已提交
393
    while ((read32(MAC_REG + TDMA_CONS_INDEX) != 0) && (--count))
B
bigmagic 已提交
394
        DELAY_MICROS(1);
B
bigmagic 已提交
395

W
Weilin Wang 已提交
396 397
    tx_index = read32(MAC_REG + TDMA_CONS_INDEX);
    write32(MAC_REG + TDMA_PROD_INDEX, tx_index);
B
bigmagic 已提交
398

W
Weilin Wang 已提交
399
    index_flag = read32(MAC_REG + RDMA_PROD_INDEX);
B
bigmagic 已提交
400

W
Weilin Wang 已提交
401
    rx_index = index_flag % RX_DESCS;
B
bigmagic 已提交
402

W
Weilin Wang 已提交
403 404
    write32(MAC_REG + RDMA_CONS_INDEX, index_flag);
    write32(MAC_REG + RDMA_PROD_INDEX, index_flag);
B
bigmagic 已提交
405 406 407

    /* Enable Rx/Tx */
    rt_uint32_t rx_tx_en;
W
Weilin Wang 已提交
408
    rx_tx_en = read32(MAC_REG + UMAC_CMD);
B
bigmagic 已提交
409

W
Weilin Wang 已提交
410
    rx_tx_en |= (CMD_TX_EN | CMD_RX_EN);
W
Weilin Wang 已提交
411

W
Weilin Wang 已提交
412 413 414
    write32(MAC_REG + UMAC_CMD, rx_tx_en);
    //IRQ
    write32(MAC_REG + GENET_INTRL2_CPU_CLEAR_MASK, GENET_IRQ_TXDMA_DONE | GENET_IRQ_RXDMA_DONE);
B
bigmagic 已提交
415 416 417 418 419 420 421
    return 0;
}

static rt_uint32_t prev_recv_cnt = 0;
static rt_uint32_t cur_recv_cnt = 0;
static rt_uint32_t bcmgenet_gmac_eth_recv(rt_uint8_t **packetp)
{
422
    void *desc_base;
B
bigmagic 已提交
423
    rt_uint32_t length = 0, addr = 0;
W
Weilin Wang 已提交
424
    rt_uint32_t prod_index = read32(MAC_REG + RDMA_PROD_INDEX);
425
    if (prod_index == index_flag)
B
bigmagic 已提交
426 427
    {
        cur_recv_cnt = index_flag;
B
bigmagic 已提交
428
        index_flag = 0x7fffffff;
W
Weilin Wang 已提交
429
        /* no buff */
B
bigmagic 已提交
430 431 432 433
        return 0;
    }
    else
    {
434
        if (prev_recv_cnt == (prod_index & 0xffff))
B
bigmagic 已提交
435 436 437
        {
            return 0;
        }
B
bigmagic 已提交
438

B
bigmagic 已提交
439 440 441 442
        desc_base = RX_DESC_BASE + rx_index * DMA_DESC_SIZE;
        length = read32(desc_base + DMA_DESC_LENGTH_STATUS);
        length = (length >> DMA_BUFLENGTH_SHIFT) & DMA_BUFLENGTH_MASK;
        addr = read32(desc_base + DMA_DESC_ADDRESS_LO);
443

B
bigmagic 已提交
444
        /* To cater for the IP headepr alignment the hardware does.
445 446 447 448
            * This would actually not be needed if we don't program
            * RBUF_ALIGN_2B
            */
        rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, (void *) addr, length);
B
bigmagic 已提交
449 450 451
        *packetp = (rt_uint8_t *)(addr + RX_BUF_OFFSET);

        rx_index = rx_index + 1;
452
        if (rx_index >= RX_DESCS)
B
bigmagic 已提交
453 454 455
        {
            rx_index = 0;
        }
W
Weilin Wang 已提交
456
        write32(MAC_REG + RDMA_CONS_INDEX, cur_recv_cnt);
B
bigmagic 已提交
457 458

        cur_recv_cnt = cur_recv_cnt + 1;
B
bigmagic 已提交
459

460
        if (cur_recv_cnt > 0xffff)
B
bigmagic 已提交
461 462 463
        {
            cur_recv_cnt = 0;
        }
B
bigmagic 已提交
464 465
        prev_recv_cnt = cur_recv_cnt;

W
Weilin Wang 已提交
466
        return length;
B
bigmagic 已提交
467 468 469
    }
}

W
Weilin Wang 已提交
470
static int bcmgenet_gmac_eth_send(void *packet, int length)
B
bigmagic 已提交
471
{
B
bigmagic 已提交
472
    void *desc_base = (TX_DESC_BASE + tx_index * DMA_DESC_SIZE);
B
bigmagic 已提交
473
    rt_uint32_t len_stat = length << DMA_BUFLENGTH_SHIFT;
W
Weilin Wang 已提交
474

475
    rt_uint32_t prod_index;
B
bigmagic 已提交
476

W
Weilin Wang 已提交
477
    prod_index = read32(MAC_REG + TDMA_PROD_INDEX);
W
Weilin Wang 已提交
478

W
Weilin Wang 已提交
479 480 481
    len_stat |= 0x3F << DMA_TX_QTAG_SHIFT;
    len_stat |= DMA_TX_APPEND_CRC | DMA_SOP | DMA_EOP;

482 483 484
    rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, (void *)packet, length);

    write32((desc_base + DMA_DESC_ADDRESS_LO), (rt_uint32_t)packet);
B
bigmagic 已提交
485 486 487
    write32((desc_base + DMA_DESC_ADDRESS_HI), 0);
    write32((desc_base + DMA_DESC_LENGTH_STATUS), len_stat);

W
Weilin Wang 已提交
488
    tx_index = tx_index + 1;
W
Weilin Wang 已提交
489
    prod_index = prod_index + 1;
B
bigmagic 已提交
490

W
Weilin Wang 已提交
491
    if (prod_index == 0xe000)
B
bigmagic 已提交
492
    {
W
Weilin Wang 已提交
493
        write32(MAC_REG + TDMA_PROD_INDEX, 0);
W
Weilin Wang 已提交
494
        prod_index = 0;
B
bigmagic 已提交
495
    }
B
bigmagic 已提交
496

W
Weilin Wang 已提交
497 498 499 500 501
    if (tx_index >= TX_DESCS)
    {
        tx_index = 0;
    }

B
bigmagic 已提交
502
    /* Start Transmisson */
W
Weilin Wang 已提交
503 504
    write32(MAC_REG + TDMA_PROD_INDEX, prod_index);
    rt_sem_take(&sem_lock, RT_WAITING_FOREVER);
B
bigmagic 已提交
505 506 507
    return 0;
}

B
bigmagic 已提交
508
static void link_task_entry(void *param)
B
bigmagic 已提交
509
{
B
bigmagic 已提交
510
    struct eth_device *eth_device = (struct eth_device *)param;
B
bigmagic 已提交
511
    RT_ASSERT(eth_device != RT_NULL);
B
bigmagic 已提交
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
    struct rt_eth_dev *dev = &eth_dev;
    //start mdio
    bcmgenet_mdio_init();
    //start timer link
    rt_timer_init(&dev->link_timer, "link_timer",
                  link_irq,
                  NULL,
                  100,
                  RT_TIMER_FLAG_PERIODIC);
    rt_timer_start(&dev->link_timer);

    //link wait forever
    rt_sem_take(&link_ack, RT_WAITING_FOREVER);
    eth_device_linkchange(&eth_dev.parent, RT_TRUE); //link up
    rt_timer_stop(&dev->link_timer);

    //set mac
W
Weilin Wang 已提交
529
    bcmgenet_gmac_write_hwaddr();
B
bigmagic 已提交
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
    bcmgenet_gmac_write_hwaddr();

    //check link speed
    if ((bcmgenet_mdio_read(1, BCM54213PE_STATUS) & (1 << 10)) || (bcmgenet_mdio_read(1, BCM54213PE_STATUS) & (1 << 11)))
    {
        link_speed = 1000;
        rt_kprintf("Support link mode Speed 1000M\n");
    }
    else if ((bcmgenet_mdio_read(1, 0x05) & (1 << 7)) || (bcmgenet_mdio_read(1, 0x05) & (1 << 8)) || (bcmgenet_mdio_read(1, 0x05) & (1 << 9)))
    {
        link_speed = 100;
        rt_kprintf("Support link mode Speed 100M\n");
    }
    else
    {
        link_speed = 10;
        rt_kprintf("Support link mode Speed 10M\n");
    }

    bcmgenet_gmac_eth_start();
    rt_hw_interrupt_install(ETH_IRQ, eth_rx_irq, NULL, "eth_irq");
    rt_hw_interrupt_umask(ETH_IRQ);
    link_flag = 1;
}

static rt_err_t bcmgenet_eth_init(rt_device_t device)
{
B
bigmagic 已提交
557 558
    rt_uint32_t ret = 0;
    rt_uint32_t hw_reg = 0;
B
bigmagic 已提交
559

B
bigmagic 已提交
560 561
    /* Read GENET HW version */
    rt_uint8_t major = 0;
W
Weilin Wang 已提交
562
    hw_reg = read32(MAC_REG + SYS_REV_CTRL);
B
bigmagic 已提交
563
    major = (hw_reg >> 24) & 0x0f;
B
bigmagic 已提交
564 565
    if (major != 6)
    {
B
bigmagic 已提交
566 567 568 569 570 571 572 573 574 575 576 577 578
        if (major == 5)
            major = 4;
        else if (major == 0)
            major = 1;

        rt_kprintf("Uns upported GENETv%d.%d\n", major, (hw_reg >> 16) & 0x0f);
        return RT_ERROR;
    }
    /* set interface */
    ret = bcmgenet_interface_set();
    if (ret)
    {
        return ret;
B
bigmagic 已提交
579
    }
B
bigmagic 已提交
580 581

    /* rbuf clear */
W
Weilin Wang 已提交
582
    write32(MAC_REG + SYS_RBUF_FLUSH_CTRL, 0);
B
bigmagic 已提交
583 584

    /* disable MAC while updating its registers */
W
Weilin Wang 已提交
585
    write32(MAC_REG + UMAC_CMD, 0);
B
bigmagic 已提交
586
    /* issue soft reset with (rg)mii loopback to ensure a stable rxclk */
W
Weilin Wang 已提交
587
    write32(MAC_REG + UMAC_CMD, CMD_SW_RESET | CMD_LCL_LOOP_EN);
B
bigmagic 已提交
588

B
bigmagic 已提交
589 590 591 592 593
    link_thread_tid = rt_thread_create("link", link_task_entry, (void *)device,
                                       LINK_THREAD_STACK_SIZE,
                                       LINK_THREAD_PRIORITY, LINK_THREAD_TIMESLICE);
    if (link_thread_tid != RT_NULL)
        rt_thread_startup(link_thread_tid);
B
bigmagic 已提交
594 595 596 597 598 599 600 601 602

    return RT_EOK;
}

static rt_err_t bcmgenet_eth_control(rt_device_t dev, int cmd, void *args)
{
    switch (cmd)
    {
    case NIOCTL_GADDR:
B
bigmagic 已提交
603 604 605 606
        if (args)
            rt_memcpy(args, eth_dev.dev_addr, 6);
        else
            return -RT_ERROR;
B
bigmagic 已提交
607
        break;
B
bigmagic 已提交
608
    default:
B
bigmagic 已提交
609 610 611 612 613 614 615
        break;
    }
    return RT_EOK;
}

rt_err_t rt_eth_tx(rt_device_t device, struct pbuf *p)
{
W
Weilin Wang 已提交
616 617
    rt_uint32_t sendbuf = (rt_uint32_t)SEND_DATA_NO_CACHE + (rt_uint32_t)(tx_index * SEND_CACHE_BUF);
    /* lock eth device */
B
bigmagic 已提交
618 619
    if (link_flag == 1)
    {
W
Weilin Wang 已提交
620 621 622
        pbuf_copy_partial(p, (void *)&send_cache_pbuf[0], p->tot_len, 0);
        rt_memcpy((void *)sendbuf, send_cache_pbuf, p->tot_len);
        bcmgenet_gmac_eth_send((void *)sendbuf, p->tot_len);
B
bigmagic 已提交
623
    }
B
bigmagic 已提交
624 625 626 627 628 629
    return RT_EOK;
}

struct pbuf *rt_eth_rx(rt_device_t device)
{
    int recv_len = 0;
W
Weilin Wang 已提交
630
    rt_uint8_t *addr_point = RT_NULL;
B
bigmagic 已提交
631
    struct pbuf *pbuf = RT_NULL;
B
bigmagic 已提交
632
    if (link_flag == 1)
B
bigmagic 已提交
633
    {
W
Weilin Wang 已提交
634
        recv_len = bcmgenet_gmac_eth_recv((rt_uint8_t **)&addr_point);
B
bigmagic 已提交
635 636 637
        if (recv_len > 0)
        {
            pbuf = pbuf_alloc(PBUF_LINK, recv_len, PBUF_RAM);
638
            if (pbuf)
W
Weilin Wang 已提交
639 640 641
            {
                rt_memcpy(pbuf->payload, addr_point, recv_len);
            }
B
bigmagic 已提交
642
        }
B
bigmagic 已提交
643 644 645 646 647 648 649
    }
    return pbuf;
}

int rt_hw_eth_init(void)
{
    rt_uint8_t mac_addr[6];
W
Weilin Wang 已提交
650
    rt_sem_init(&sem_lock, "eth_send_lock", TX_DESCS, RT_IPC_FLAG_FIFO);
B
bigmagic 已提交
651
    rt_sem_init(&link_ack, "link_ack", 0, RT_IPC_FLAG_FIFO);
W
Weilin Wang 已提交
652

B
bigmagic 已提交
653
    memset(&eth_dev, 0, sizeof(eth_dev));
W
Weilin Wang 已提交
654 655
    memset((void *)SEND_DATA_NO_CACHE, 0, DMA_DISC_ADDR_SIZE);
    memset((void *)RECV_DATA_NO_CACHE, 0, DMA_DISC_ADDR_SIZE);
B
bigmagic 已提交
656 657
    bcm271x_mbox_hardware_get_mac_address(&mac_addr[0]);

W
Weilin Wang 已提交
658
    eth_dev.iobase = MAC_REG;
B
bigmagic 已提交
659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
    eth_dev.name = "e0";
    eth_dev.dev_addr[0] = mac_addr[0];
    eth_dev.dev_addr[1] = mac_addr[1];
    eth_dev.dev_addr[2] = mac_addr[2];
    eth_dev.dev_addr[3] = mac_addr[3];
    eth_dev.dev_addr[4] = mac_addr[4];
    eth_dev.dev_addr[5] = mac_addr[5];

    eth_dev.parent.parent.type          = RT_Device_Class_NetIf;
    eth_dev.parent.parent.init          = bcmgenet_eth_init;
    eth_dev.parent.parent.open          = RT_NULL;
    eth_dev.parent.parent.close         = RT_NULL;
    eth_dev.parent.parent.read          = RT_NULL;
    eth_dev.parent.parent.write         = RT_NULL;
    eth_dev.parent.parent.control       = bcmgenet_eth_control;
    eth_dev.parent.parent.user_data     = RT_NULL;

    eth_dev.parent.eth_tx            = rt_eth_tx;
    eth_dev.parent.eth_rx            = rt_eth_rx;

    eth_device_init(&(eth_dev.parent), "e0");
B
bigmagic 已提交
680
    eth_device_linkchange(&eth_dev.parent, RT_FALSE);   //link down
B
bigmagic 已提交
681 682 683
    return 0;
}
INIT_COMPONENT_EXPORT(rt_hw_eth_init);