rt-thread/bsp/ck802/libraries/common/eth/ethernet_enc28j60.c

1260 lines
32 KiB
C

/*
* Copyright (C) 2016 YunOS Project. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <syslog.h>
#ifndef CONFIG_KERNEL_NONE
#include <csi_kernel.h>
#endif
#include "ethernet_enc28j60.h"
#include "pin.h"
#include "soc.h"
#include "drv_spi.h"
#include "drv_gpio.h"
#include "drv_eth.h"
#include "drv_eth_phy.h"
#include "drv_eth_mac.h"
#include <errno.h>
#define NET_HWADDR_LEN 6
#define THIS_MODULE MODULE_DEV_ETH
#define MAX_SPI_TRANSFER_LEN 512
#define MAX_RECV_ERROR_CNT 50
static uint8_t Enc28j60Bank;
static uint16_t NextPacketPtr;
gpio_pin_handle_t pin_int = NULL;
typedef int (*gpio_interrupt_t)(int irqno);
static spi_handle_t g_net_spi_hd = NULL;
static gpio_pin_handle_t pgpio_pin_handle1;
//static k_sem_handle_t g_sem_spi_tx_hd = NULL;
//static k_sem_handle_t g_sem_spi_rx_hd = NULL;
static eth_mac_priv_t s_eth_instance[CONFIG_ETH_NUM];
static eth_phy_priv_t s_phy_instance[CONFIG_ETH_NUM];
static uint8_t g_hw_addr[NET_HWADDR_LEN] = {0};
static uint8_t enc28j60ReadOp(uint8_t op, uint8_t address);
static void enc28j60WriteOp(uint8_t op, uint8_t address, uint8_t data);
static void enc28j60ReadBuffer(const uint16_t len, uint8_t *data);
static void enc28j60WriteBuffer(uint16_t len, uint8_t *data);
static void enc28j60SetBank(uint8_t address);
static uint8_t enc28j60Read(uint8_t address);
static void enc28j60Write(uint8_t address, uint8_t data);
static uint32_t enc28j60PhyWrite(uint8_t phy_addr, uint8_t reg_addr, uint16_t data);
static uint32_t enc28j60Phyregread(uint8_t phy_addr, uint8_t reg_addr, uint16_t *data);
static void enc28j60Init(const uint8_t *macaddr);
static int enc28j60Reset(int obj);
static uint16_t enc28j60GetRxFreeSpace(void);
static void enc28j60_int_handle(uint32_t event);
static int enc28j60_set_interrupt(pin_t gpio_pin);
extern void mdelay(uint32_t ms);
/**
* interrupt handle function to post sem for handle
*
* @param irqno the irq number of network
*
*/
static void enc28j60_int_handle(uint32_t event)
{
eth_mac_priv_t *eth_priv = &s_eth_instance[0];
uint8_t int_stat, ptkcnt, estat;
uint16_t freespace;
uint16_t status_vec_ptr;
uint8_t status_vec[7];
bool reset = 0;
csi_gpio_pin_irq_set(pin_int, GPIO_IRQ_MODE_LOW_LEVEL, 0);
//enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, EIE, EIE_INTIE);
int_stat = enc28j60Read(EIR); /* read EIR register data */;
// error flags to be handled first
if (int_stat & EIR_RXERIF) {
ptkcnt = enc28j60Read(EPKTCNT);
freespace = enc28j60GetRxFreeSpace();
#ifndef CONFIG_TEST_TTCP
if ((ptkcnt == 0xFF) || (freespace < MAX_FRAMELEN)) {
/* do nothing, data in buffer will be read out */
printf("Rx buffer has %d packets and %d bytes free space\n", ptkcnt, freespace);
} else {
printf("something is wrong other than no buffer.\n");
}
#endif
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, EIR, EIR_RXERIF);
if (ptkcnt > MAX_RECV_ERROR_CNT) {
reset = 1;
}
}
if (int_stat & EIR_TXERIF) {
estat = enc28j60Read(ESTAT);
if ((estat & ESTAT_TXABRT) || (estat & ESTAT_LATECOL)) {
printf("ESTAT=0x%x\n", estat);
status_vec_ptr = enc28j60Read(ETXNDL);
status_vec_ptr |= enc28j60Read(ETXNDH) << 8;
status_vec_ptr++;
enc28j60Write(ERDPTL, status_vec_ptr);
enc28j60Write(ERDPTH, status_vec_ptr >> 8);
enc28j60ReadBuffer(7, status_vec);
printf("status vector:0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x\n",
status_vec[0], status_vec[1], status_vec[2], status_vec[3], status_vec[4], status_vec[5], status_vec[6]);
reset = 1;
}
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, EIR, EIR_TXERIF);
}
if (reset) {
if (enc28j60Reset(RST_ENC28J60_ALL) == 0) {
printf("reset OK \n");
/* init enc28j60 module */
uint8_t macaddr[6];
csi_eth_mac_get_macaddr(NULL, (eth_mac_addr_t *)macaddr);
enc28j60Init(macaddr);
printf("enc28j60 init OK \n");
enc28j60_set_interrupt(PA5_A8);
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE);
return;
}
}
if (int_stat & EIR_PKTIF) {
ptkcnt = enc28j60Read(EPKTCNT); //just for debugging
//EIR_PKTIF will be cleared if all data is read out
eth_priv->cb_event((eth_mac_handle_t)eth_priv, CSI_ETH_MAC_EVENT_RX_FRAME);
}
if (int_stat & EIR_TXIF) {
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, EIR, EIR_TXIF);
//eth_priv->cb_event((eth_mac_handle_t)eth_priv, CSI_ETH_MAC_EVENT_TX_FRAME);
}
if (int_stat & EIR_LINKIF) {
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, EIR, EIR_LINKIF);
eth_priv->cb_event((eth_mac_handle_t)eth_priv, CSI_ETH_MAC_EVENT_LINK_CHANGE);
}
//clear all interrupt falgs. In fact, EIR_PKTIF can not be cleared
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, EIR, 0xFF & (~(EIR_PKTIF | EIR_LINKIF)));
// don't enable interrupt if events not handled
if (!(int_stat & (EIR_PKTIF | EIR_LINKIF))) {
//enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE);
csi_gpio_pin_irq_set(pin_int, GPIO_IRQ_MODE_LOW_LEVEL, 1);
}
}
void enc28j60_spi_transfer_callback(spi_event_e event)
{
if (event == SPI_EVENT_TRANSFER_COMPLETE) {
} else if (event == SPI_EVENT_TX_COMPLETE) {
//csi_kernel_sem_post(g_sem_spi_tx_hd);
} else if (event == SPI_EVENT_RX_COMPLETE) {
//csi_kernel_sem_post(g_sem_spi_rx_hd);
} else if (event == SPI_EVENT_DATA_LOST) {
printf("TRANSFER_DATA_LOST\n");
} else {
printf("TRANSFER_MODE_FAULT\n");
}
}
void enc28j60_spi_cs_status_change(int status)
{
csi_gpio_pin_write(pgpio_pin_handle1, status);
}
static int32_t enc28j60_spi_send(spi_handle_t handle, const void *data, uint32_t num)
{
csi_spi_send(handle, data, num, 1);
// csi_kernel_sem_wait(g_sem_spi_tx_hd, -1);
return 0;
}
static int32_t enc28j60_spi_receive(spi_handle_t handle, void *data, uint32_t num)
{
csi_spi_receive(handle, data, num, 1);
//csi_kernel_sem_wait(g_sem_spi_rx_hd, -1);
return 0;
}
/**
* read ctrl register
* @param op operation cmd
* @param register address
*
* @return
* -register data
*/
static uint8_t enc28j60ReadOp(uint8_t op, uint8_t address)
{
uint8_t dat = 0;
ENC28J60_CSL();
dat = (op | (address & ADDR_MASK));
uint8_t rdata[1] = {0};
enc28j60_spi_send(g_net_spi_hd, &dat, 1);
enc28j60_spi_receive(g_net_spi_hd, &rdata[0], 1);
/* do dummy read if needed (for mac and mii, see datasheet page 29) */
if (address & 0x80) {
enc28j60_spi_receive(g_net_spi_hd, &rdata[0], 1);
}
/* release CS */
ENC28J60_CSH();
return rdata[0];
}
/**
* write ctrl cmd to register
* @param op operation cmd
* @param register address
* @param data the data to be set
*
* @return
* -NULL
*/
static void enc28j60WriteOp(uint8_t op, uint8_t address, uint8_t data)
{
char dat = 0;
ENC28J60_CSL();
/* issue write command */
dat = op | (address & ADDR_MASK);
enc28j60_spi_send(g_net_spi_hd, &dat, 1);
dat = data;
enc28j60_spi_send(g_net_spi_hd, &dat, 1);
ENC28J60_CSH();
}
/**
* read buffer data
* @param len the data length waint to read
* @param data the data buffer
*
* @return
* -NULL
*/
static void enc28j60ReadBuffer(uint16_t len, uint8_t *data)
{
char ops_ctr = ENC28J60_READ_BUF_MEM;
ENC28J60_CSL();
/* issue read command */
enc28j60_spi_send(g_net_spi_hd, &ops_ctr, 1);
enc28j60_spi_receive(g_net_spi_hd, (char *)&data[0], len);
ENC28J60_CSH();
}
/**
* write data to buffer
* @param len the data length waint to write
* @param data the data buffer pointer
*
* @return
* -NULL
*/
static void enc28j60WriteBuffer(uint16_t len, uint8_t *data)
{
char ops_ctr = ENC28J60_WRITE_BUF_MEM;
ENC28J60_CSL();
/* issue write command */
//drv_porting_spi_write(NULL, &ops_ctr, 1);
enc28j60_spi_send(g_net_spi_hd, &ops_ctr, 1);
enc28j60_spi_send(g_net_spi_hd, &data[0], len);
ENC28J60_CSH();
}
/**
* select the bank to operation
* @param address the bank address
*
* @return
* -NULL
*/
static void enc28j60SetBank(uint8_t address)
{
/* set the bank (if needed) */
if ((address & BANK_MASK) != Enc28j60Bank) {
/* set the bank */
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1 | ECON1_BSEL0));
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK) >> 5);
Enc28j60Bank = (address & BANK_MASK);
}
}
/**
* read ctrl register data
* @param address the ctrl register address
*
* @return
* -ctrl register data
*/
static uint8_t enc28j60Read(uint8_t address)
{
/* set the bank */
enc28j60SetBank(address);
/* do the read */
return enc28j60ReadOp(ENC28J60_READ_CTRL_REG, address);
}
/**
* write data to ctrl register
* @param address the ctrl register address
* @param data ctrl register cmd
*
* @return
* - NULL
*/
static void enc28j60Write(uint8_t address, uint8_t data)
{
/* set the bank */
enc28j60SetBank(address);
/* do the write */
enc28j60WriteOp(ENC28J60_WRITE_CTRL_REG, address, data);
}
/**
* write data to phy register
* @param address the phy register address
* @param data phy register cmd
*
* @return
* - NULL
*/
static uint32_t enc28j60PhyWrite(uint8_t phy_addr, uint8_t reg_addr, uint16_t data)
{
int retry = 0;
/* set the PHY register address */
enc28j60Write(MIREGADR, phy_addr);
/* write the PHY data */
enc28j60Write(MIWRL, data);
enc28j60Write(MIWRH, data >> 8);
/* wait until the PHY write completes */
while (enc28j60Read(MISTAT) & MISTAT_BUSY) {
retry++;
if (retry > 0xFFF) {
printf("write Phyreg_status error \n");
return -1;
}
}
return 0;
}
/**
* read data from phy register
* @param address the phy register address
*
* @return
* -the data of phy register
*/
static uint32_t enc28j60Phyregread(uint8_t phy_addr, uint8_t reg_addr, uint16_t *data)
{
uint8_t temp;
int retry = 0;
temp = enc28j60Read(MICMD);
/* set the PHY register address */
enc28j60Write(MIREGADR, phy_addr);
enc28j60Write(MICMD, temp | MICMD_MIIRD);
/* Loop to wait until the PHY register has been read through the MII */
while ((enc28j60Read(MISTAT) & MISTAT_BUSY)) {
if (retry++ > 0xFFF) {
printf("read Phyreg_status error \n");
return -1;
}
}
enc28j60Write(MICMD, temp & (~MICMD_MIIRD)); /* clear bit MICMD.MIIRD */
/* Obtain results and return */
*data = enc28j60Read(MIRDL);
*data |= (enc28j60Read(MIRDH) << 8);
return *data;
}
/**
* init ethernet ctrl register
* @param address the MAC address
*
* @return
* - NULL
*/
static void enc28j60Init(const uint8_t *macaddr)
{
/* check CLKRDY bit to see if reset is complete */
/* The CLKRDY does not work. See Rev. B4 Silicon Errata point. Just wait. */
NextPacketPtr = RXSTART_INIT;
/* Rx start */
enc28j60Write(ERXSTL, RXSTART_INIT & 0xFF);
enc28j60Write(ERXSTH, RXSTART_INIT >> 8);
/* set receive pointer address */
enc28j60Write(ERXRDPTL, RXSTART_INIT & 0xFF);
enc28j60Write(ERXRDPTH, RXSTART_INIT >> 8);
/* RX end */
enc28j60Write(ERXNDL, RXSTOP_INIT & 0xFF);
enc28j60Write(ERXNDH, RXSTOP_INIT >> 8);
/* TX start */
enc28j60Write(ETXSTL, TXSTART_INIT & 0xFF);
enc28j60Write(ETXSTH, TXSTART_INIT >> 8);
/* TX end */
enc28j60Write(ETXNDL, TXSTOP_INIT & 0xFF);
enc28j60Write(ETXNDH, TXSTOP_INIT >> 8);
/* do bank 1 stuff, packet filter:
For broadcast packets we allow only ARP packtets
All other packets should be unicast only for our mac (MAADR) */
#if LWIP_IPV4 && LWIP_IPV6
enc28j60Write(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_PMEN | ERXFCON_MCEN);
enc28j60Write(EPMM0, 0x3f); /* ARP Pattern Match Filter */
enc28j60Write(EPMM1, 0x30);
enc28j60Write(EPMCSL, 0xf9);
enc28j60Write(EPMCSH, 0xf7);
#elif LWIP_IPV6
enc28j60Write(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_MCEN);
#else /* for IPv6 without ARP and BC */
enc28j60Write(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_PMEN);
enc28j60Write(EPMM0, 0x3f); /* ARP Pattern Match Filter */
enc28j60Write(EPMM1, 0x30);
enc28j60Write(EPMCSL, 0xf9);
enc28j60Write(EPMCSH, 0xf7);
#endif
/* do bank 2 stuff */
/* enable MAC receive */
enc28j60Write(MACON1, MACON1_MARXEN | MACON1_TXPAUS | MACON1_RXPAUS);
/* bring MAC out of reset */
enc28j60Write(MACON2, 0x00);
/* enable automatic padding to 60bytes and CRC operations */
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN | MACON3_FULDPX); /* MACON3_HFRMLEN */
/* set inter-frame gap (non-back-to-back) */
enc28j60Write(MAIPGL, 0x12);
enc28j60Write(MAIPGH, 0x0C);
/* set inter-frame gap (back-to-back) */
enc28j60Write(MABBIPG, 0x15);
/* Set the maximum packet size which the controller will accept */
/* Do not send packets longer than MAX_FRAMELEN: */
enc28j60Write(MAMXFLL, MAX_FRAMELEN & 0xFF);
enc28j60Write(MAMXFLH, MAX_FRAMELEN >> 8);
/* do bank 3 stuff */
/* write MAC address */
/* NOTE: MAC address in ENC28J60 is byte-backward */
enc28j60Write(MAADR5, macaddr[0]);
enc28j60Write(MAADR4, macaddr[1]);
enc28j60Write(MAADR3, macaddr[2]);
enc28j60Write(MAADR2, macaddr[3]);
enc28j60Write(MAADR1, macaddr[4]);
enc28j60Write(MAADR0, macaddr[5]);
enc28j60PhyWrite(PHCON1, 0, PHCON1_PDPXMD);
/* no loopback of transmitted frames */
enc28j60PhyWrite(PHCON2, 0, PHCON2_HDLDIS);
enc28j60PhyWrite(PHIE, 0, PHIE_PLNKIE | PHIE_PGEIE);
/* switch to bank 0 */
enc28j60SetBank(ECON1);
/* enable interrutps */
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_PKTIE | EIE_LINKIE | EIE_TXIE | EIE_TXERIE | EIE_RXERIE);
/* enable packet reception */
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE);
}
/**
* set mac addr
* @param macaddr the macaddr for net
*
* @return
* - NULL
*/
static void enc28j60Setmacaddr(const uint8_t *macaddr)
{
ENC28J60_CSH();
/* enable MAC receive */
enc28j60Write(MACON1, MACON1_MARXEN | MACON1_TXPAUS | MACON1_RXPAUS);
/* bring MAC out of reset */
enc28j60Write(MACON2, 0x00);
/* enable automatic padding to 60bytes and CRC operations */
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FULDPX);
/* write MAC address */
/* NOTE: MAC address in ENC28J60 is byte-backward */
enc28j60Write(MAADR5, macaddr[0]);
enc28j60Write(MAADR4, macaddr[1]);
enc28j60Write(MAADR3, macaddr[2]);
enc28j60Write(MAADR2, macaddr[3]);
enc28j60Write(MAADR1, macaddr[4]);
enc28j60Write(MAADR0, macaddr[5]);
}
/**
* Hard reset enc28j60
* @param void
*
*/
static void enc28j60hardreset(void)
{
gpio_pin_handle_t pin = NULL;
pin = csi_gpio_pin_initialize(PA1);
csi_gpio_pin_config(pin, GPIO_MODE_PULLNONE, GPIO_DIRECTION_OUTPUT);
csi_gpio_pin_write(pin, 0); /* LOW */
mdelay(3);
csi_gpio_pin_write(pin, 1);
mdelay(3);
printf("NET HARD RESET\n");
}
/**
* reset enc28j60
* @param obj the net work object
*
* @return
* - status
*/
static int enc28j60Reset(int obj)
{
int retry = 0;
ENC28J60_CSH();
if (obj == RST_ENC28J60_ALL) {
/* first net hard reset */
enc28j60hardreset();
enc28j60WriteOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
while (!(enc28j60Read(ESTAT) & ESTAT_CLKRDY)) {
if (retry++ > 0xFFF) {
return -1;
}
}
} else if (obj == RST_ENC28J60_TX) {
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
} else if (obj == RST_ENC28J60_RX) {
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXRST);
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXRST);
}
return 0;
}
/**
* get rx free space
* @param void
*
* @return
* - status 0
*/
static uint16_t enc28j60GetRxFreeSpace(void)
{
uint16_t free_space;
uint16_t erxrdpt;
uint16_t erxwrpt;
erxrdpt = enc28j60Read(ERXRDPTL);
erxrdpt |= enc28j60Read(ERXRDPTH) << 8;
erxwrpt = enc28j60Read(ERXWRPTL);
erxwrpt |= enc28j60Read(ERXWRPTH) << 8;
if (erxwrpt > erxrdpt) {
free_space = (RXSTOP_INIT - RXSTART_INIT) - (erxwrpt - erxrdpt);
} else if (erxwrpt == erxrdpt) {
free_space = (RXSTOP_INIT - RXSTART_INIT);
} else {
free_space = erxrdpt - erxwrpt - 1;
}
return free_space;
}
/**
* enc28j60 interrupt set
* @param interrupt_cb the interrupt callback function
*
* @return
* - status 0
*/
static int enc28j60_set_interrupt(pin_t gpio_pin)
{
uint32_t ret = 0;
pin_int = csi_gpio_pin_initialize(gpio_pin);
ret = csi_gpio_pin_config(pin_int, GPIO_MODE_PULLUP, GPIO_DIRECTION_INPUT);
ret = csi_gpio_pin_irq_set(pin_int, GPIO_IRQ_MODE_LOW_LEVEL, 1);
return 0;
}
csi_drv_version_t csi_eth_phy_get_version(eth_phy_handle_t handle)
{
csi_drv_version_t version = {0xff, 0xff};
uint16_t dev_version, dev_version1;
if (handle == NULL) {
return version;
}
enc28j60Phyregread(PHHID1, 0, &dev_version);
enc28j60Phyregread(PHHID2, 0, &dev_version1);
version.api = CSI_ETH_PHY_API_VERSION;
version.drv = (dev_version << 16) + dev_version1;
return version;
}
eth_phy_handle_t csi_eth_phy_initialize(csi_eth_phy_read_t fn_read, csi_eth_phy_write_t fn_write)
{
eth_phy_priv_t *phy_priv;
if ((fn_read == NULL) || (fn_write == NULL)) {
return NULL;
}
csi_gpio_port_initialize(0, (gpio_event_cb_t)enc28j60_int_handle);
phy_priv = &s_phy_instance[0];
phy_priv->phy_read = fn_read ;
phy_priv->phy_write = fn_write;
return (eth_mac_handle_t)phy_priv;
}
int32_t csi_eth_phy_uninitialize(eth_phy_handle_t handle)
{
if (handle == NULL) {
return -1;
}
return 0;
}
int32_t csi_eth_phy_deinit(void)
{
/* no loopback of transmitted frames */
enc28j60PhyWrite(PHCON2, 0, PHCON2_HDLDIS);
/* LINK AND ALL PHY Interrupt Enable */
enc28j60PhyWrite(PHIE, 0, PHIE_PLNKIE | PHIE_PGEIE);
return 0;
}
int32_t csi_eth_phy_power_control(eth_phy_handle_t handle, eth_power_state_t state)
{
uint16_t power_control;
if (handle == NULL) {
return -1;
}
enc28j60Phyregread(PHCON1, 0, &power_control);
if (state == CSI_ETH_POWER_FULL) {
power_control &= ~(1 << 11);
} else if (state == CSI_ETH_POWER_OFF) {
power_control |= (1 << 11);
} else if (state == CSI_ETH_POWER_LOW) {
} else {
return -1;
}
enc28j60PhyWrite(PHCON1, 0, power_control);
return 0;
}
int32_t csi_eth_phy_set_interface(eth_phy_handle_t handle, uint32_t interface)
{
if (handle == NULL) {
return -1;
}
return 0;
}
eth_link_info_t csi_eth_phy_get_linkinfo(eth_phy_handle_t handle)
{
eth_link_info_t net_link_info = {0};
if (handle == NULL) {
return net_link_info;
}
net_link_info.duplex = 1;
net_link_info.speed = 1;
return net_link_info;
}
int32_t csi_eth_phy_set_mode(eth_phy_handle_t handle, uint32_t mode)
{
uint32_t phy_mode = 0;
if (handle == NULL) {
return -1;
}
eth_phy_priv_t *phy_priv = (eth_phy_priv_t *)handle;
phy_priv->link_info.speed = (mode & 0x03);
phy_priv->link_info.duplex = (mode & 0x04);
phy_priv->link_info.Loopback = (mode & 0x05);
if (phy_priv->link_info.duplex) {
phy_mode |= PHCON1_PDPXMD;
} else {
phy_mode &= ~(PHCON1_PDPXMD);
}
if (phy_priv->link_info.Loopback) {
phy_mode |= PHCON1_PLOOPBK;
} else {
phy_mode &= ~(PHCON1_PLOOPBK);
}
enc28j60PhyWrite(PHCON1, 0, phy_mode);
return 0;
}
eth_link_state_t csi_eth_phy_get_linkstate(eth_phy_handle_t handle)
{
uint16_t phstat1;
uint16_t phstat2;
eth_link_state_t state;
if (handle == NULL) {
return -1;
}
uint8_t status = enc28j60Read(EIR);
if (status & EIR_LINKIF) {
/* as tested, need to read twice */
enc28j60Phyregread(PHSTAT1, 0, &phstat1);
enc28j60Phyregread(PHSTAT1, 0, &phstat2);
phstat1 |= phstat2;
if (phstat1 & 0x0004) {
state = ETH_LINK_UP;
} else {
state = ETH_LINK_DOWN;
}
/* resets to "0" when read */
enc28j60Phyregread(PHIR, 0, NULL);
return state;
}
return -1;
}
eth_mac_handle_t csi_eth_mac_initialize(eth_event_cb_t cb)
{
eth_mac_priv_t *eth_priv;
static int eth_mac_init = 0;
int ret = -1;
if (cb == NULL) {
printf("cb == null\n");
return NULL;
}
eth_priv = &s_eth_instance[0];
eth_priv->cb_event = cb;
if (eth_mac_init == 0) {
//init spi get spi_handle
g_net_spi_hd = csi_spi_initialize(SPI1_TX, SPI1_RX, SPI1_CLK, SPI1_CS, (spi_event_cb_t)enc28j60_spi_transfer_callback, NULL);
//spi_handle success goto config spi
if (g_net_spi_hd != NULL) {
ret = csi_spi_config(g_net_spi_hd, SYSTEM_CLOCK, 2000000, SPI_MODE_MASTER, SPI_FORMAT_CPOL0_CPHA0,
SPI_ORDER_MSB2LSB, SPI_SS_MASTER_SW, 7);
pgpio_pin_handle1 = csi_gpio_pin_initialize(SPI1_CS);
csi_gpio_pin_config(pgpio_pin_handle1, GPIO_MODE_PULLNONE, GPIO_DIRECTION_OUTPUT);
}
eth_mac_init = 1;
}
if ((ret == 0) || (eth_mac_init == 1)) {
if (enc28j60Reset(RST_ENC28J60_ALL) == 0) {
printf("reset OK \n");
/* init enc28j60 module */
uint8_t macaddr[6];
csi_eth_mac_get_macaddr(NULL, (eth_mac_addr_t *)macaddr);
enc28j60Init(macaddr);
printf("enc28j60 init OK \n");
enc28j60_set_interrupt(PA5_A8);
//g_sem_spi_tx_hd = csi_kernel_sem_new(1, 0);
//g_sem_spi_rx_hd = csi_kernel_sem_new(1, 0);
return (eth_mac_handle_t)eth_priv;
}
}
return NULL;
}
int32_t csi_eth_mac_uninitialize(eth_mac_handle_t handle)
{
if (handle == NULL) {
return -1;
}
return 0;
}
csi_drv_version_t csi_eth_mac_get_version(eth_mac_handle_t handle)
{
csi_drv_version_t mac_version = {0xff, 0xff};
if (handle == NULL) {
return mac_version;
}
mac_version.api = CSI_ETH_PHY_API_VERSION;
mac_version.drv = enc28j60Read(EREVID);
return mac_version;
}
int32_t csi_eth_mac_power_control(eth_mac_handle_t handle, eth_power_state_t state)
{
uint8_t pw_control;
if (handle == NULL) {
return -1;
}
pw_control = enc28j60Read(ECON2);
if (state == CSI_ETH_POWER_FULL) {
pw_control &= ~(1 << 11);
} else if (state == CSI_ETH_POWER_LOW) {
pw_control |= (1 << 11);
} else if (state == CSI_ETH_POWER_OFF) {
} else {
return -1;
}
enc28j60Write(ECON2, pw_control);
return 0;
}
int32_t csi_eth_mac_get_macaddr(eth_mac_handle_t handle, eth_mac_addr_t *mac)
{
if ((handle == NULL) || (mac == NULL)) {
return -1;
}
memcpy(mac, g_hw_addr, NET_HWADDR_LEN);
return 0;
}
int32_t csi_eth_mac_set_macaddr(eth_mac_handle_t handle, const eth_mac_addr_t *mac)
{
if ((handle == NULL) || (mac == NULL)) {
return -1;
}
memcpy(g_hw_addr, mac, NET_HWADDR_LEN);
printf("csiMAC: %02x:%02x:%02x:%02x:%02x:%02x\n", g_hw_addr[0], g_hw_addr[1], g_hw_addr[2],
g_hw_addr[3], g_hw_addr[4], g_hw_addr[5]);
enc28j60Setmacaddr(g_hw_addr);
return 0;
}
int32_t csi_eth_mac_set_addrfilter(eth_mac_handle_t handle, const eth_mac_addr_t *addr, uint32_t num_addr)
{
if ((handle == NULL) || (addr == NULL)) {
return -1;
}
return 0;
}
int32_t csi_eth_mac_get_rx_framesize(eth_mac_handle_t handle)
{
uint16_t len;
uint16_t rxstat;
if (handle == NULL) {
return -1;
}
/* check if a packet has been received and buffered
if( !(enc28j60Read(EIR) & EIR_PKTIF) ){
The above does not work. See Rev. B4 Silicon Errata point 6. */
if (enc28j60Read(EPKTCNT) == 0) {
return (0);
}
/* Set the read pointer to the start of the received packet */
enc28j60Write(ERDPTL, (NextPacketPtr));
enc28j60Write(ERDPTH, (NextPacketPtr) >> 8);
/* read the next packet pointer */
NextPacketPtr = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
NextPacketPtr |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0) << 8;
/* read the packet length (see datasheet page 43) */
len = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
len |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0) << 8;
len -= 4; /* remove the CRC count */
/* limit retrieve length */
if (len > MAX_FRAMELEN - 1) {
printf("rx packet length is %d\n", len);
len = MAX_FRAMELEN - 1;
return -1;
}
/* read the receive status (see datasheet page 43) */
rxstat = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
rxstat |= (uint16_t)enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0) << 8;
/* check CRC and symbol errors (see datasheet page 44, table 7-3): */
/* The ERXFCON.CRCEN is set by default. Normally we should not */
/* need to check this. */
if ((rxstat & 0x80) == 0) {
printf("rx status vector is 0x%x\n", rxstat);
len = 0; // invalid
return -1;
}
return len;
}
int32_t csi_eth_mac_get_rx_frametime(eth_mac_handle_t handle, eth_mac_time_t *time)
{
if ((handle == NULL)) {
return -1;
}
return 0;
}
int32_t csi_eth_mac_get_tx_frametime(eth_mac_handle_t handle, eth_mac_time_t *time)
{
if (handle == NULL) {
return -1;
}
return 0;
}
int32_t csi_eth_mac_control(eth_mac_handle_t handle, uint32_t control, uint32_t arg)
{
if (handle == NULL) {
return -1;
}
if (control == CSI_ETH_MAC_CONTROL_RX) {
if (arg) {
//enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE);
csi_gpio_pin_irq_set(pin_int, GPIO_IRQ_MODE_LOW_LEVEL, 1);
} else {
//enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, EIE, EIE_INTIE);
csi_gpio_pin_irq_set(pin_int, GPIO_IRQ_MODE_LOW_LEVEL, 0);
}
return 0;
}
return 0;
}
/**
* send a packet data
* @param address the packet data length
*
* @return
* - sent data length
*/
int32_t csi_eth_mac_send_frame(eth_mac_handle_t handle, const uint8_t *frame, uint32_t len, uint32_t flags)
{
int retry = 0;
if ((handle == NULL) || (frame == NULL)) {
return -1;
}
if (len > MAX_FRAMELEN) {
printf("TX len %d is too large to send\n", len);
return 0;
}
while (enc28j60Read(ECON1) & ECON1_TXRTS) {
if (retry++ > 0xFFF) {
printf("data not be sent out\n");
return -1;
}
}
/* Set the write pointer to start of transmit buffer area */
enc28j60Write(EWRPTL, TXSTART_INIT & 0xFF);
enc28j60Write(EWRPTH, TXSTART_INIT >> 8);
/* Set the TXND pointer to correspond to the packet size given */
/* Status vector will be written at ETXND+1. */
enc28j60Write(ETXNDL, (TXSTART_INIT + len) & 0xFF);
enc28j60Write(ETXNDH, (TXSTART_INIT + len) >> 8);
/* write per-packet control byte (0x00 means use macon3 settings) */
enc28j60WriteOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00);
/* copy the packet into the transmit buffer */
enc28j60WriteBuffer(len, (uint8_t *)frame);
/* send the contents of the transmit buffer onto the network */
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
/* Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12. */
if ((enc28j60Read(EIR) & EIR_TXERIF)) {
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS);
}
return len;
}
int32_t csi_eth_mac_read_frame(eth_mac_handle_t handle, uint8_t *frame, uint32_t len)
{
uint32_t rlen;
uint16_t rxstat;
if ((handle == NULL) || (frame == NULL)) {
return -1;
}
/* check if a packet has been received and buffered
if( !(enc28j60Read(EIR) & EIR_PKTIF) ){
The above does not work. See Rev. B4 Silicon Errata point 6. */
if (enc28j60Read(EPKTCNT) == 0) {
return (0);
}
/* Set the read pointer to the start of the received packet */
enc28j60Write(ERDPTL, (NextPacketPtr));
enc28j60Write(ERDPTH, (NextPacketPtr) >> 8);
/* read the next packet pointer */
NextPacketPtr = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
NextPacketPtr |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0) << 8;
/* read the packet length (see datasheet page 43) */
rlen = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
rlen |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0) << 8;
rlen -= 4; /* remove the CRC count */
/* limit retrieve length */
if (rlen > MAX_FRAMELEN - 1) {
printf("rx packet length is %d\n", rlen);
rlen = MAX_FRAMELEN - 1;
return -1;
}
/* read the receive status (see datasheet page 43) */
rxstat = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
rxstat |= (uint16_t)enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0) << 8;
/* check CRC and symbol errors (see datasheet page 44, table 7-3): */
/* The ERXFCON.CRCEN is set by default. Normally we should not */
/* need to check this. */
if ((rxstat & 0x80) == 0) {
printf("rx status vector is 0x%x\n", rxstat);
rlen = 0; // invalid
return -1;
}
/* copy the packet from the receive buffer */
enc28j60ReadBuffer(rlen, frame);
/* Move the RX read pointer to the start of the next received packet */
/* This frees the memory we just read out */
enc28j60Write(ERXRDPTL, (NextPacketPtr));
enc28j60Write(ERXRDPTH, (NextPacketPtr) >> 8);
/* decrement the packet counter indicate we are done with this packet */
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_AUTOINC | ECON2_PKTDEC);
return rlen;
}
eth_capabilities_t csi_eth_mac_get_capabilities(eth_mac_handle_t handle)
{
eth_capabilities_t capab = {0};
if (handle == NULL) {
return capab;
}
eth_mac_priv_t *mac_priv = (eth_mac_priv_t *)handle;
mac_priv->capabilities.mac_address = 1;
capab = mac_priv->capabilities;
return capab;
}
void csi_eth_mac_signal_event(eth_mac_handle_t handle, uint32_t event)
{
if (handle == NULL) {
return;
}
}
int32_t csi_eth_mac_control_time(eth_mac_handle_t handle, uint32_t control, eth_mac_time_t *time)
{
if (handle == NULL) {
return -1;
}
return 0;
}
int32_t csi_eth_mac_phy_read(eth_mac_handle_t handle, uint8_t phy_addr, uint8_t reg_addr, uint16_t *data)
{
if ((handle == NULL) || (data == NULL)) {
return -1;
}
return 0;
}
int32_t csi_eth_mac_phy_write(eth_mac_handle_t handle, uint8_t phy_addr, uint8_t reg_addr, uint16_t data)
{
if ((handle == NULL)) {
return -1;
}
return 0;
}
int32_t csi_eth_mac_add_framefilter(eth_mac_handle_t handle, const eth_frame_filter_t *filter)
{
if ((handle == NULL) || (filter == NULL)) {
return -1;
}
return 0;
}
int32_t csi_eth_mac_remove_framefilter(eth_mac_handle_t handle, uint32_t filter_id)
{
if (handle == NULL) {
return -1;
}
return 0;
}
int32_t csi_eth_mac_en_framefilter(eth_mac_handle_t handle, uint32_t filter_id, bool en)
{
if (handle == NULL) {
return -1;
}
return 0;
}
int32_t csi_eth_mac_get_framefilter(eth_mac_handle_t handle, eth_frame_filter_list_t *list, uint32_t *count_out, uint32_t max_count)
{
if ((handle == NULL) || (list == NULL)) {
return -1;
}
return 0;
}