URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
Compare Revisions
- This comparison shows the changes necessary to convert path
/openrisc/trunk/rtos/ecos-3.0
- from Rev 791 to Rev 798
- ↔ Reverse comparison
Rev 791 → Rev 798
/packages/devs/eth/opencores/ethmac/current/cdl/opencores_ethmac_eth_drivers.cdl
0,0 → 1,151
# ==================================================================== |
# |
# opencores_ethmac_eth_drivers.cdl |
# |
# OpenCores ETHMAC ethernet driver |
# |
# ==================================================================== |
## ####ECOSGPLCOPYRIGHTBEGIN#### |
## ------------------------------------------- |
## This file is part of eCos, the Embedded Configurable Operating System. |
## Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. |
## |
## eCos 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 or (at your option) any later |
## version. |
## |
## eCos 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. |
## |
## You should have received a copy of the GNU General Public License |
## along with eCos; if not, write to the Free Software Foundation, Inc., |
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
## |
## As a special exception, if other files instantiate templates or use |
## macros or inline functions from this file, or you compile this file |
## and link it with other works to produce a work based on this file, |
## this file does not by itself cause the resulting work to be covered by |
## the GNU General Public License. However the source code for this file |
## must still be made available in accordance with section (3) of the GNU |
## General Public License v2. |
## |
## This exception does not invalidate any other reasons why a work based |
## on this file might be covered by the GNU General Public License. |
## ------------------------------------------- |
## ####ECOSGPLCOPYRIGHTEND#### |
# ==================================================================== |
######DESCRIPTIONBEGIN#### |
# |
# Author(s): Piotr Skrzypek |
# Original data: |
# Contributors: |
# Date: 2012-04-10 |
# |
#####DESCRIPTIONEND#### |
# |
# ==================================================================== |
|
cdl_package CYGPKG_DEVS_ETH_OPENCORES_ETHMAC { |
|
display "OpenCores ETHMAC ethernet driver" |
description "Ethernet driver for OpenCores ETHMAC controller." |
|
parent CYGPKG_IO_ETH_DRIVERS |
active_if CYGPKG_IO_ETH_DRIVERS |
|
implements CYGHWR_NET_DRIVERS |
implements CYGHWR_NET_DRIVER_ETH0 |
|
compile -library=libextras.a if_ethmac.c |
|
cdl_option CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_MACADDR { |
display "Ethernet station (MAC) address for eth0" |
flavor data |
default_value {"0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC"} |
description "The default ethernet station address. This is the |
MAC address used when no value is found in the |
RedBoot FLASH configuration field." |
} |
|
cdl_option CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_INT { |
display "Interrupt vector number" |
flavor data |
default_value { 4 } |
description " |
This is the number of PIC channel that ETHMAC is connected |
to." |
} |
|
cdl_option CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_INT_PRIO { |
display "Interrupt priority" |
flavor data |
default_value { 4 } |
description " |
Priority of delayed interrupt routine that takes care |
of ETHMAC." |
} |
|
cdl_option CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_TXBUF_COUNT { |
display "Number of transmit buffers" |
flavor data |
default_value { 1 } |
legal_values 1 to 64 |
description " |
The number of transmit buffers. More buffers help |
increse the throughput, but require maintenance time |
and memory." |
} |
|
cdl_option CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_RXBUF_COUNT { |
display "Number of receive buffers" |
flavor data |
default_value { 1 } |
legal_values 1 to 64 |
description " |
The number of receive buffers. More buffers prevent |
missing packets, but require more maintenance time |
and memory." |
} |
|
cdl_option CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_PACKETLEN { |
display "Maximum frame length" |
flavor data |
default_value { 1536 } |
description " |
Specify maximum packet length. This value will be |
programmed into the MAC. It is also a size of receive |
buffers." |
} |
|
cdl_option CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_FULLDUPLEX { |
display "Enable full duplex transmission" |
flavor bool |
default_value { 1 } |
description " |
Enable full duplex when configuring ETHMAC." |
} |
|
cdl_component CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_OPTIONS { |
display "ETHMAC controller driver build options" |
flavor none |
no_define |
|
cdl_option CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_CFLAGS_ADD { |
display "Additional compiler flags" |
flavor data |
no_define |
default_value { "-D_KERNEL -D__ECOS" } |
description " |
This option modifies the set of compiler flags for |
building the ETHMAC controller driver package. |
These flags are used in addition to the set of global |
flags." |
} |
} |
|
|
} |
# EOF opencores_ethmac_eth_drivers.cdl |
/packages/devs/eth/opencores/ethmac/current/src/if_ethmac.c
0,0 → 1,627
//========================================================================== |
// |
// if_ethmac.c |
// |
// OpenCores ETHMAC controller driver |
// |
//========================================================================== |
// ####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 2003, 2004 Free Software Foundation, Inc. |
// |
// eCos 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 or (at your option) any later |
// version. |
// |
// eCos 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. |
// |
// You should have received a copy of the GNU General Public License |
// along with eCos; if not, write to the Free Software Foundation, Inc., |
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
// |
// As a special exception, if other files instantiate templates or use |
// macros or inline functions from this file, or you compile this file |
// and link it with other works to produce a work based on this file, |
// this file does not by itself cause the resulting work to be covered by |
// the GNU General Public License. However the source code for this file |
// must still be made available in accordance with section (3) of the GNU |
// General Public License v2. |
// |
// This exception does not invalidate any other reasons why a work based |
// on this file might be covered by the GNU General Public License. |
// ------------------------------------------- |
// ####ECOSGPLCOPYRIGHTEND#### |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): Piotr Skrzypek (pskrzypek@antmicro.com) |
// Date: 2012-04-10 |
// Purpose: |
// Description: |
// |
//####DESCRIPTIONEND#### |
// |
//========================================================================== |
|
#include <cyg/infra/cyg_type.h> |
#include <cyg/hal/hal_io.h> |
#include <cyg/hal/hal_arch.h> |
#include <cyg/infra/diag.h> |
#include <cyg/hal/drv_api.h> |
#include <cyg/io/eth/netdev.h> |
#include <cyg/io/eth/eth_drv.h> |
|
// Settings exported from CDL |
#include <pkgconf/devs_eth_opencores_ethmac.h> |
|
// ETHMAC address space |
#define ETHMAC_BASE 0x92000000 |
#define ETHMAC_REG_BASE (ETHMAC_BASE) |
#define ETHMAC_BD_BASE (ETHMAC_BASE + 0x400) |
#define ETHMAC_TX_BD_BASE (ETHMAC_BD_BASE) |
#define ETHMAC_RX_BD_BASE (ETHMAC_BD_BASE + 0x200) |
|
// Register space |
#define ETHMAC_MODER 0x000 |
#define ETHMAC_INT_SOURCE 0x004 |
#define ETHMAC_INT_MASK 0x008 |
#define ETHMAC_IPGT 0x00C |
#define ETHMAC_IPGR1 0x010 |
#define ETHMAC_IPGR2 0x014 |
#define ETHMAC_PACKETLEN 0x018 |
#define ETHMAC_COLLCONF 0x01C |
#define ETHMAC_TX_BD_NUM 0x020 |
#define ETHMAC_CTRLMODER 0x024 |
#define ETHMAC_MIIMODER 0x028 |
#define ETHMAC_MIICOMMAND 0x02C |
#define ETHMAC_MIIADDRESS 0x030 |
#define ETHMAC_MIITX_DATA 0x034 |
#define ETHMAC_MIIRX_DATA 0x038 |
#define ETHMAC_MIISTATUS 0x03C |
#define ETHMAC_MAC_ADDR0 0x040 |
#define ETHMAC_MAC_ADDR1 0x044 |
#define ETHMAC_ETH_HASH0_ADR 0x048 |
#define ETHMAC_ETH_HASH1_ADR 0x04C |
#define ETHMAC_ETH_TXCTRL 0x050 |
|
// MODER bits |
#define ETHMAC_MODER_RECSMALL 0x00010000 |
#define ETHMAC_MODER_PAD 0x00008000 |
#define ETHMAC_MODER_HUGEN 0x00004000 |
#define ETHMAC_MODER_CRCEN 0x00002000 |
#define ETHMAC_MODER_DLYCRCEN 0x00001000 |
#define ETHMAC_MODER_FULLD 0x00000400 |
#define ETHMAC_MODER_EXDFREN 0x00000200 |
#define ETHMAC_MODER_NOBCKOF 0x00000100 |
#define ETHMAC_MODER_LOOPBCK 0x00000080 |
#define ETHMAC_MODER_IFG 0x00000040 |
#define ETHMAC_MODER_PRO 0x00000020 |
#define ETHMAC_MODER_IAM 0x00000010 |
#define ETHMAC_MODER_BRO 0x00000008 |
#define ETHMAC_MODER_NOPRE 0x00000004 |
#define ETHMAC_MODER_TXEN 0x00000002 |
#define ETHMAC_MODER_RXEN 0x00000001 |
|
// INT_SOURCE bits |
#define ETHMAC_INT_SOURCE_RXC 0x00000040 |
#define ETHMAC_INT_SOURCE_TXC 0x00000020 |
#define ETHMAC_INT_SOURCE_BUSY 0x00000010 |
#define ETHMAC_INT_SOURCE_RXE 0x00000008 |
#define ETHMAC_INT_SOURCE_RXB 0x00000004 |
#define ETHMAC_INT_SOURCE_TXE 0x00000002 |
#define ETHMAC_INT_SOURCE_TXB 0x00000001 |
|
// INT_MASK bits |
#define ETHMAC_INT_MASK_RXC_M 0x00000040 |
#define ETHMAC_INT_MASK_TXC_M 0x00000020 |
#define ETHMAC_INT_MASK_BUSY_M 0x00000010 |
#define ETHMAC_INT_MASK_RXE_M 0x00000008 |
#define ETHMAC_INT_MASK_RXF_M 0x00000004 |
#define ETHMAC_INT_MASK_TXE_M 0x00000002 |
#define ETHMAC_INT_MASK_TXB_M 0x00000001 |
|
// CTRLMODER bits |
#define ETHMAC_CTRLMODER_TXFLOW 0x00000004 |
#define ETHMAC_CTRLMODER_RXFLOW 0x00000002 |
#define ETHMAC_CTRLMODER_PASSALL 0x00000001 |
|
// MIIMODER bits |
#define ETHMAC_MIIMODER_MIINOPRE 0x00000100 |
|
// MIICOMMAND bits |
#define ETHMAC_MIICOMMAND_WCTRLDATA 0x00000004 |
#define ETHMAC_MIICOMMAND_RSTAT 0x00000002 |
#define ETHMAC_MIICOMMAND_SCANSTAT 0x00000001 |
|
// MIISTATUS bits |
#define ETHMAC_MIISTATUS_NVALID 0x00000004 |
#define ETHMAC_MIISTATUS_BUSY 0x00000002 |
#define ETHMAC_MIISTATUS_LINKFAIL 0x00000001 |
|
// TXCTRL bits |
#define ETHMAC_TXCTRL_TXPAUSERQ 0x00010000 |
|
// TX BD bits |
#define ETHMAC_TX_BD_RD 0x8000 |
#define ETHMAC_TX_BD_IRQ 0x4000 |
#define ETHMAC_TX_BD_WR 0x2000 |
#define ETHMAC_TX_BD_PAD 0x1000 |
#define ETHMAC_TX_BD_CRC 0x0800 |
#define ETHMAC_TX_BD_UR 0x0100 |
#define ETHMAC_TX_BD_RTRY 0x00F0 |
#define ETHMAC_TX_BD_RL 0x0008 |
#define ETHMAC_TX_BD_LC 0x0004 |
#define ETHMAC_TX_BD_DF 0x0002 |
#define ETHMAC_TX_BD_CS 0x0001 |
|
// RX BD bits |
#define ETHMAC_RX_BD_E 0x8000 |
#define ETHMAC_RX_BD_IRQ 0x4000 |
#define ETHMAC_RX_BD_WR 0x2000 |
#define ETHMAC_RX_BD_CF 0x0100 |
#define ETHMAC_RX_BD_M 0x0080 |
#define ETHMAC_RX_BD_OR 0x0040 |
#define ETHMAC_RX_BD_IS 0x0020 |
#define ETHMAC_RX_BD_DN 0x0010 |
#define ETHMAC_RX_BD_TL 0x0008 |
#define ETHMAC_RX_BD_SF 0x0004 |
#define ETHMAC_RX_BD_CRC 0x0002 |
#define ETHMAC_RX_BD_LC 0x0001 |
|
typedef struct { |
|
// Buffer to store received frames |
char rx_buffer[CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_RXBUF_COUNT] |
[CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_PACKETLEN]; |
|
// Number of rx buffer descriptor that ETHMAC is pointing to |
int rx_head; |
|
// Array of keys (handlers given by the stack) |
unsigned long tx_key[CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_TXBUF_COUNT]; |
|
// Buffer to store frames for transmission |
char tx_buffer[CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_TXBUF_COUNT] |
[CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_PACKETLEN]; |
|
// Number of tx buffer descriptor that ETHMAC is pointing to |
int tx_head; |
|
// Number of descriptors waiting to be transmitted by ETHMAC |
int tx_count; |
|
// Interrupt resources |
cyg_handle_t int_handle; |
cyg_interrupt int_object; |
|
} ethmac_eth_t; |
|
ethmac_eth_t eth0_data; |
|
ETH_DRV_SC(ethmac_eth0_sc, |
(void*) ð0_data, |
"eth0", |
ethmac_eth_start, |
ethmac_eth_stop, |
ethmac_eth_control, |
ethmac_eth_can_send, |
ethmac_eth_send, |
ethmac_eth_recv, |
ethmac_eth_deliver, |
ethmac_eth_poll, |
ethmac_eth_int_vector); |
|
NETDEVTAB_ENTRY(ethmac_netdev, |
"ethmac_eth0", |
ethmac_eth_init, |
ðmac_eth0_sc); |
|
static void ethmac_eth_debug(char *msg) { |
//diag_printf("\033[31;1m%s\033[0m\n", msg); |
} |
|
static int ethmac_eth_isr(cyg_vector_t vector, cyg_addrword_t data) { |
|
// Mask the interrupt in PIC, and call generic network DSR. |
// This DSR will call ethmac_eth_deliver. The interrupt will be |
// unmasked there. |
cyg_drv_interrupt_mask(CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_INT); |
cyg_drv_interrupt_acknowledge(CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_INT); |
|
return(CYG_ISR_HANDLED | CYG_ISR_CALL_DSR); |
} |
|
static bool ethmac_eth_init(struct cyg_netdevtab_entry *tab) { |
|
struct eth_drv_sc *sc = tab->device_instance; |
ethmac_eth_t *data = sc->driver_private; |
|
// ETHMAC uses buffer descriptors that store a pointer to |
// RAM memory. The transmit / receive queue is made from |
// multiple buffer descriptors, serviced in a round robin |
// manner. Following is the initialization of those descriptors. |
int i; |
cyg_uint32 reg; |
|
// TX buffer descriptors |
reg = ETHMAC_TX_BD_IRQ | ETHMAC_TX_BD_PAD | ETHMAC_TX_BD_CRC; |
for(i = 0; i < CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_TXBUF_COUNT; i++) { |
HAL_WRITE_UINT32(ETHMAC_TX_BD_BASE + (i * 8), reg); |
HAL_WRITE_UINT32(ETHMAC_TX_BD_BASE + (i * 8) + 4, |
(cyg_uint32)&data->tx_buffer[i][0]); |
} |
reg |= ETHMAC_TX_BD_WR; |
i--; |
HAL_WRITE_UINT32(ETHMAC_TX_BD_BASE + (i * 8), reg); |
|
data->tx_head = 0; |
data->tx_count = 0; |
|
// RX buffer descriptors |
reg = CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_PACKETLEN << 16 | |
ETHMAC_RX_BD_E | ETHMAC_RX_BD_IRQ; |
for(i = 0; i < CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_RXBUF_COUNT; i++) { |
HAL_WRITE_UINT32(ETHMAC_RX_BD_BASE + (i * 8), reg); |
HAL_WRITE_UINT32(ETHMAC_RX_BD_BASE + (i * 8) + 4, |
(cyg_uint32)&data->rx_buffer[i][0]); |
} |
reg |= ETHMAC_RX_BD_WR; |
i--; |
HAL_WRITE_UINT32(ETHMAC_RX_BD_BASE + (i * 8), reg); |
|
data->rx_head = 0; |
|
// Below is a configuration of ETHMAC peripheral. The stack |
// sends here frames without the preamble and CRC, so we need |
// to enable them in the peripheral. |
|
// Disable MAC (just in case) |
HAL_READ_UINT32(ETHMAC_REG_BASE + ETHMAC_MODER, reg); |
reg &= ~(ETHMAC_MODER_TXEN | ETHMAC_MODER_RXEN); |
HAL_WRITE_UINT32(ETHMAC_REG_BASE + ETHMAC_MODER, reg); |
|
// Enable Full Duplex mode, CRC and PADDING |
HAL_READ_UINT32(ETHMAC_REG_BASE + ETHMAC_MODER, reg); |
#ifdef CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_FULLDUPLEX |
reg |= ETHMAC_MODER_FULLD; |
#endif |
reg |= ETHMAC_MODER_CRCEN | ETHMAC_MODER_PAD; |
HAL_WRITE_UINT32(ETHMAC_REG_BASE + ETHMAC_MODER, reg); |
|
#ifdef CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_FULLDUPLEX |
// Reconfigure timing if full duplex mode was selected |
HAL_WRITE_UINT32(ETHMAC_REG_BASE + ETHMAC_IPGT, 0x15); |
|
// Enable PAUSE frames |
reg = ETHMAC_CTRLMODER_RXFLOW | ETHMAC_CTRLMODER_TXFLOW; |
HAL_WRITE_UINT32(ETHMAC_REG_BASE + ETHMAC_CTRLMODER, reg); |
#endif |
|
// Configure packet size |
reg = (0x40 << 16) | CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_PACKETLEN; |
HAL_WRITE_UINT32(ETHMAC_REG_BASE + ETHMAC_PACKETLEN, reg); |
|
// Clear possible interrupts |
HAL_WRITE_UINT32(ETHMAC_REG_BASE + ETHMAC_INT_SOURCE, 0x7F); |
|
// Set MAC address |
unsigned char mac_addr[6] = { CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_MACADDR }; |
reg = mac_addr[0] << 8 | mac_addr[1]; |
HAL_WRITE_UINT32(ETHMAC_REG_BASE + ETHMAC_MAC_ADDR1, reg); |
reg = mac_addr[2] << 24 | mac_addr[3] << 16 | mac_addr[4] << 8 | mac_addr[5]; |
HAL_WRITE_UINT32(ETHMAC_REG_BASE + ETHMAC_MAC_ADDR0, reg); |
|
// Attach an interrupt |
cyg_drv_interrupt_create((cyg_vector_t)CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_INT, |
(cyg_priority_t)CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_INT_PRIO, |
(cyg_addrword_t) sc, |
(cyg_ISR_t*)ethmac_eth_isr, |
(cyg_DSR_t*)eth_drv_dsr, |
(cyg_handle_t*)&data->int_handle, |
(cyg_interrupt*)&data->int_object); |
cyg_drv_interrupt_attach(data->int_handle); |
cyg_drv_interrupt_acknowledge(CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_INT); |
cyg_drv_interrupt_unmask(CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_INT); |
|
// Initialize upper level driver by sending MAC address |
(sc->funs->eth_drv->init)(sc, mac_addr); |
|
return 1; |
} |
|
static void ethmac_eth_start(struct eth_drv_sc *sc, |
unsigned char *enaddr, |
int flags) { |
cyg_uint32 reg; |
|
// Enable transceiver |
HAL_READ_UINT32(ETHMAC_REG_BASE + ETHMAC_MODER, reg); |
reg |= ETHMAC_MODER_TXEN | ETHMAC_MODER_RXEN; |
HAL_WRITE_UINT32(ETHMAC_REG_BASE + ETHMAC_MODER, reg); |
|
// Enable interrutps. We want to track transmission and |
// reception of data frames only. Control frames are ignored. |
// They are not passed to the host. |
reg = ETHMAC_INT_MASK_RXE_M | ETHMAC_INT_MASK_RXF_M | |
ETHMAC_INT_MASK_TXE_M | ETHMAC_INT_MASK_TXB_M; |
HAL_WRITE_UINT32(ETHMAC_REG_BASE + ETHMAC_INT_MASK, reg); |
|
} |
|
static void ethmac_eth_stop(struct eth_drv_sc *sc) { |
cyg_uint32 reg; |
|
// Disable transceiver |
HAL_READ_UINT32(ETHMAC_REG_BASE + ETHMAC_MODER, reg); |
reg &= ~(ETHMAC_MODER_TXEN | ETHMAC_MODER_RXEN); |
HAL_WRITE_UINT32(ETHMAC_REG_BASE + ETHMAC_MODER, reg); |
|
// Disable interrupts |
reg = 0; |
HAL_WRITE_UINT32(ETHMAC_REG_BASE + ETHMAC_INT_MASK, reg); |
|
} |
|
static int ethmac_eth_control(struct eth_drv_sc *sc, |
unsigned long key, |
void *data, |
int len) { |
//TODO implement following keys: |
//ETH_DRV_GET_MAC_ADDRESS |
//ETH_DRV_SET_MAC_ADDRESS |
//ETH_DRV_GET_IF_STATS_UD |
//ETH_DRV_GET_IF_STATS |
//ETH_DRV_SET_MC_LIST |
//ETH_DRV_SET_MC_ALL |
return -1; |
} |
|
static int ethmac_eth_can_send(struct eth_drv_sc *sc) { |
|
ethmac_eth_t *data = sc->driver_private; |
|
// This function should return the number of free transmission |
// slots. |
|
int slots; |
|
cyg_drv_dsr_lock(); |
slots = CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_TXBUF_COUNT - data->tx_count; |
cyg_drv_dsr_unlock(); |
|
return slots; |
} |
|
static void ethmac_eth_send(struct eth_drv_sc *sc, |
struct eth_drv_sg *sg_list, |
int sg_len, |
int total_len, |
unsigned long key) { |
|
// Reject too big frames |
if(total_len > CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_PACKETLEN) { |
|
// Immediately notify the stack, that transmission failed |
sc->funs->eth_drv->tx_done(sc, key, -1); |
return; |
} |
|
ethmac_eth_t *data = sc->driver_private; |
|
// Determine the next free buffer descriptor |
int free_bd; |
cyg_drv_dsr_lock(); |
free_bd = (data->tx_head + data->tx_count) % CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_TXBUF_COUNT; |
cyg_drv_dsr_unlock(); |
|
// Upper stack gives us a scatter-gather list. We need to assemble that into one |
// single packet. We store the packet directly in the transmission buffer. |
int i, j; |
j = 0; |
for(i = 0; i < sg_len; i++) { |
memcpy(&data->tx_buffer[free_bd][j], (char*)sg_list[i].buf, sg_list[i].len); |
j += sg_list[i].len; |
} |
|
// Store key (handler) so it will be possible to notify the stack later |
data->tx_key[free_bd] = key; |
|
// Reconfigure the buffer descriptor so notify ETHMAC it is ready for transmission |
cyg_uint32 reg; |
reg = (total_len << 16) | ETHMAC_TX_BD_RD | ETHMAC_TX_BD_IRQ | ETHMAC_TX_BD_PAD | ETHMAC_TX_BD_CRC; |
if(free_bd == CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_TXBUF_COUNT - 1) { |
reg |= ETHMAC_TX_BD_WR; |
} |
HAL_WRITE_UINT32(ETHMAC_TX_BD_BASE + (8 * free_bd), reg); |
|
// Update queue control variables |
cyg_drv_dsr_lock(); |
data->tx_count++; |
cyg_drv_dsr_unlock(); |
|
} |
|
static void ethmac_eth_recv(struct eth_drv_sc *sc, |
struct eth_drv_sg *sg_list, |
int sg_len) { |
|
ethmac_eth_t *data = sc->driver_private; |
|
// This function is called by the upper layer as a result of calling |
// _recv callback. We need to move data from reception buffer |
// to given scatter-gather list. |
|
if(sg_list == NULL) { |
return; |
} |
|
// Copy.. |
int i, j; |
j = 0; |
for(i = 0; i < sg_len; i++) { |
if(sg_list[i].buf) { |
memcpy((char*)sg_list[i].buf, data->rx_buffer[data->rx_head] + j, sg_list[i].len); |
j += sg_list[i].len; |
} |
} |
|
} |
|
static void ethmac_eth_deliver(struct eth_drv_sc *sc) { |
|
// This function is called from default network DSR provided |
// by common eCos package. Is is called when network |
// interrupt occurs. It simply calls _poll to analyze status |
// registers. Interrupt flags in MAC registers are cleared in |
// _poll function. |
ethmac_eth_poll(sc); |
|
// Unmask the interrupt |
cyg_drv_interrupt_unmask(CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_INT); |
|
} |
|
static void ethmac_eth_poll(struct eth_drv_sc *sc) { |
|
cyg_uint32 reg; |
ethmac_eth_t *data = sc->driver_private; |
|
// This function is designed to be idempotent. It can be called multiple |
// times. We don't need to count how many interrupts occured. |
// This function analyzes ETHMAC status registers to find out if any |
// packets were received or transmitted. |
|
// Check if any packets were received |
|
// Clear flags associated with reception |
reg = ETHMAC_INT_SOURCE_RXC | ETHMAC_INT_SOURCE_BUSY | |
ETHMAC_INT_SOURCE_RXE | ETHMAC_INT_SOURCE_RXB; |
HAL_WRITE_UINT32(ETHMAC_REG_BASE + ETHMAC_INT_SOURCE, reg); |
|
// Traverse receive buffer descriptors to see if any frames were received |
|
cyg_uint32 errors = ETHMAC_RX_BD_CF | ETHMAC_RX_BD_M | |
ETHMAC_RX_BD_OR | ETHMAC_RX_BD_IS | |
ETHMAC_RX_BD_DN | ETHMAC_RX_BD_TL | |
ETHMAC_RX_BD_SF | ETHMAC_RX_BD_CRC | |
ETHMAC_RX_BD_LC; |
|
cyg_drv_dsr_lock(); |
|
while(1) { |
|
HAL_READ_UINT32(ETHMAC_RX_BD_BASE + (8*data->rx_head), reg); |
|
if(reg & ETHMAC_RX_BD_E) { |
// This buffer descriptor is not filled yet |
break; |
} |
|
if(reg & errors) { |
if(reg & ETHMAC_RX_BD_CF) |
ethmac_eth_debug("RX Control frame"); |
if(reg & ETHMAC_RX_BD_M) |
ethmac_eth_debug("RX Miss"); |
if(reg & ETHMAC_RX_BD_OR) |
ethmac_eth_debug("RX Overrun"); |
if(reg & ETHMAC_RX_BD_IS) |
ethmac_eth_debug("RX Invalid symbol"); |
if(reg & ETHMAC_RX_BD_DN) |
ethmac_eth_debug("RX Dribble nibble"); |
if(reg & ETHMAC_RX_BD_TL) |
ethmac_eth_debug("RX Too long"); |
if(reg & ETHMAC_RX_BD_SF) |
ethmac_eth_debug("RX Short frame"); |
if(reg & ETHMAC_RX_BD_CRC) |
ethmac_eth_debug("RX CRC error"); |
if(reg & ETHMAC_RX_BD_LC) |
ethmac_eth_debug("RX Late collision"); |
} |
else { |
// We need to notify the stack to prepare buffers for this frame. |
// Last 4 bytes need to be cut as ETHMAC attaches CRC behind |
// frames. |
int size = reg >> 16; |
size -= 4; |
sc->funs->eth_drv->recv(sc, size); |
} |
|
// Reconfigure buffer descriptor so it can accept new frame |
reg = CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_PACKETLEN << 16 | |
ETHMAC_RX_BD_E | ETHMAC_RX_BD_IRQ; |
if(data->rx_head == CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_RXBUF_COUNT-1) { |
reg |= ETHMAC_RX_BD_WR; |
} |
HAL_WRITE_UINT32(ETHMAC_RX_BD_BASE + (8*data->rx_head), reg); |
|
// Update queue control variables |
data->rx_head = (data->rx_head + 1) % CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_RXBUF_COUNT; |
|
} |
|
cyg_drv_dsr_unlock(); |
|
// Check if any packets were sent |
|
// Clear flags associated with transmission |
reg = ETHMAC_INT_SOURCE_TXC | ETHMAC_INT_SOURCE_TXE | |
ETHMAC_INT_SOURCE_TXB; |
HAL_WRITE_UINT32(ETHMAC_REG_BASE + ETHMAC_INT_SOURCE, reg); |
|
// Traverse transmit buffer descriptors to see if any frames were transmitted |
|
errors = ETHMAC_TX_BD_UR | ETHMAC_TX_BD_RL | |
ETHMAC_TX_BD_LC | ETHMAC_TX_BD_CS; |
|
cyg_drv_dsr_lock(); |
|
while(1) { |
|
HAL_READ_UINT32(ETHMAC_TX_BD_BASE + (8*data->tx_head), reg); |
|
if((reg & ETHMAC_TX_BD_RD) || (data->tx_count == 0)) { |
// This buffer descriptor is not yet transmitted or |
// there are no buffer descriptors to transmit. |
break; |
} |
|
if(reg & errors) { |
if(reg & ETHMAC_TX_BD_UR) |
ethmac_eth_debug("TX Underrun"); |
if(reg & ETHMAC_TX_BD_RL) |
ethmac_eth_debug("TX Retransmission limit"); |
if(reg & ETHMAC_TX_BD_LC) |
ethmac_eth_debug("TX Late collision"); |
if(reg & ETHMAC_TX_BD_CS) |
ethmac_eth_debug("TX Carrier lost"); |
|
// Notify the stack that transmission failed. |
sc->funs->eth_drv->tx_done(sc, data->tx_key[data->tx_head], -1); |
} |
else { |
// Notify the stack that transmission succeeded. |
sc->funs->eth_drv->tx_done(sc, data->tx_key[data->tx_head], 0); |
} |
|
// Update queue control variables. |
data->tx_count--; |
data->tx_head = (data->tx_head + 1) % CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_TXBUF_COUNT; |
} |
|
cyg_drv_dsr_unlock(); |
|
} |
|
static int ethmac_eth_int_vector(struct eth_drv_sc *sc) { |
|
return CYGPKG_DEVS_ETH_OPENCORES_ETHMAC_INT; |
|
} |
|
|
// ------------------------------------------------------------------------ |
// EOF if_ethmac.c |
/packages/devs/eth/opencores/ethmac/current/ChangeLog
0,0 → 1,27
2012-04-10 Piotr Skrzypek <pskrzypek@antmicro.com> |
|
Initial release of the driver |
|
//=========================================================================== |
// ####GPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc. |
// |
// 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 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. |
// |
// You should have received a copy of the GNU General Public License |
// along with this program; if not, write to the |
// Free Software Foundation, Inc., 51 Franklin Street, |
// Fifth Floor, Boston, MA 02110-1301, USA. |
// ------------------------------------------- |
// ####GPLCOPYRIGHTEND#### |
//=========================================================================== |
/packages/devs/disk/opencores/sdcmsc/current/cdl/devs_disk_opencores_sdcmsc.cdl
0,0 → 1,75
# ==================================================================== |
# |
# devs_disk_opencores_sdcmsc.cdl |
# |
# Support for SDCard Mass Storage Controller |
# |
# ==================================================================== |
## ####ECOSGPLCOPYRIGHTBEGIN#### |
## ------------------------------------------- |
## This file is part of eCos, the Embedded Configurable Operating System. |
## Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. |
## |
## eCos 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 or (at your option) any later |
## version. |
## |
## eCos 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. |
## |
## You should have received a copy of the GNU General Public License |
## along with eCos; if not, write to the Free Software Foundation, Inc., |
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
## |
## As a special exception, if other files instantiate templates or use |
## macros or inline functions from this file, or you compile this file |
## and link it with other works to produce a work based on this file, |
## this file does not by itself cause the resulting work to be covered by |
## the GNU General Public License. However the source code for this file |
## must still be made available in accordance with section (3) of the GNU |
## General Public License v2. |
## |
## This exception does not invalidate any other reasons why a work based |
## on this file might be covered by the GNU General Public License. |
## ------------------------------------------- |
## ####ECOSGPLCOPYRIGHTEND#### |
# ==================================================================== |
######DESCRIPTIONBEGIN#### |
# |
# Author(s): Piotr Skrzypek |
# Date: 2012-05-01 |
# |
#####DESCRIPTIONEND#### |
# ==================================================================== |
|
cdl_package CYGPKG_DEVS_DISK_OPENCORES_SDCMSC { |
display "Disk driver for SDCard Mass Storage Controller" |
|
include_dir cyg/io |
|
parent CYGPKG_IO_DISK_DEVICES |
active_if CYGPKG_IO_DISK |
|
compile -library=libextras.a if_sdcmsc.c |
requires CYGPKG_ERROR CYGPKG_LIBC_STRING |
|
description " |
This is a disk driver for SD Card Mass Storage Controller |
peripheral available at openCores." |
|
cdl_option CYGDAT_DEVS_DISK_OPENCORES_SDCMSC_DISK0_NAME { |
display "Device name for the MMC/SPI disk 0 device" |
flavor data |
default_value { "\"/dev/mmcdisk0/\"" } |
description " |
This is the device name used to access the raw disk device |
in eCos, for example for mount operations. Note that the |
trailing slash must be present." |
} |
|
} |
|
# EOF devs_disk_opencores_sdcmsc.cdl |
/packages/devs/disk/opencores/sdcmsc/current/src/if_sdcmsc.c
0,0 → 1,548
//========================================================================== |
// |
// if_sdcmsc.c |
// |
// Provide a disk device driver for SDCard Mass Storage Controller |
// |
//========================================================================== |
// ####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 2004, 2006 Free Software Foundation, Inc. |
// |
// eCos 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 or (at your option) any later |
// version. |
// |
// eCos 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. |
// |
// You should have received a copy of the GNU General Public License |
// along with eCos; if not, write to the Free Software Foundation, Inc., |
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
// |
// As a special exception, if other files instantiate templates or use |
// macros or inline functions from this file, or you compile this file |
// and link it with other works to produce a work based on this file, |
// this file does not by itself cause the resulting work to be covered by |
// the GNU General Public License. However the source code for this file |
// must still be made available in accordance with section (3) of the GNU |
// General Public License v2. |
// |
// This exception does not invalidate any other reasons why a work based |
// on this file might be covered by the GNU General Public License. |
// ------------------------------------------- |
// ####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author: Piotr Skrzypek |
// Date: 2012-05-01 |
// |
//####DESCRIPTIONEND#### |
//========================================================================== |
|
#include <pkgconf/system.h> |
#include <cyg/infra/cyg_type.h> |
#include <cyg/infra/cyg_ass.h> |
#include <cyg/infra/diag.h> |
#include <cyg/hal/hal_arch.h> |
#include <cyg/hal/hal_if.h> |
#include <cyg/hal/hal_intr.h> |
#include <string.h> |
#include <errno.h> |
#include <cyg/io/io.h> |
#include <cyg/io/devtab.h> |
#include <cyg/io/disk.h> |
|
// Settings exported from CDL |
#include <pkgconf/devs_disk_opencores_sdcmsc.h> |
|
// SDCMSC address space |
#define SDCMSC_BASE 0x9e000000 |
|
// Register space |
#define SDCMSC_ARGUMENT 0x00 |
#define SDCMSC_COMMAND 0x04 |
#define SDCMSC_CARD_STATUS 0x08 |
#define SDCMSC_RESPONSE 0x0C |
#define SDCMSC_CONTROLLER_SETTING 0x1C |
#define SDCMSC_BLOCK_SIZE 0x20 |
#define SDCMSC_POWER_CONTROL 0x24 |
#define SDCMSC_SOFTWARE_RESET 0x28 |
#define SDCMSC_TIMEOUT 0x2C |
#define SDCMSC_NORMAL_INT_STATUS 0x30 |
#define SDCMSC_ERROR_INT_STATUS 0x34 |
#define SDCMSC_NORMAL_INT_ENABLE 0x38 |
#define SDCMSC_ERROR_INT_ENABLE 0x3C |
#define SDCMSC_CAPABILITY 0x48 |
#define SDCMSC_CLOCK_DIVIDER 0x4C |
#define SDCMSC_BD_BUFFER_STATUS 0x50 |
#define SDCMSC_DAT_INT_STATUS 0x54 |
#define SDCMSC_DAT_INT_ENABLE 0x58 |
#define SDCMSC_BD_RX 0x60 |
#define SDCMSC_BD_TX 0x80 |
|
// SDCMSC_COMMAND bits |
#define SDCMSC_COMMAND_CMDI(x) (x << 8) |
#define SDCMSC_COMMAND_CMDW(x) (x << 6) |
#define SDCMSC_COMMAND_CICE 0x10 |
#define SDCMSC_COMMAND_CIRC 0x08 |
#define SDCMSC_COMMAND_RTS_48 0x02 |
#define SDCMSC_COMMAND_RTS_136 0x01 |
|
//SDCMSC_CARD_STATUS bits |
#define SDCMSC_CARD_STATUS_CICMD 0x01 |
|
// SDCMSC_NORMAL_INT_STATUS bits |
#define SDCMSC_NORMAL_INT_STATUS_EI 0x8000 |
#define SDCMSC_NORMAL_INT_STATUS_CC 0x0001 |
|
// SDCMSC_DAT_INT_STATUS |
#define SDCMSC_DAT_INT_STATUS_TRS 0x01 |
|
typedef struct cyg_sdcmsc_disk_info_t { |
int is_v20; |
int is_sdhc; |
cyg_uint32 rca; |
int connected; |
} cyg_sdcmsc_disk_info_t; |
|
static int sdcmsc_card_cmd(cyg_uint32 cmd, |
cyg_uint32 arg, |
cyg_uint32 *response) { |
|
// Send command to card |
HAL_WRITE_UINT32(SDCMSC_BASE + SDCMSC_COMMAND, cmd); |
HAL_WRITE_UINT32(SDCMSC_BASE + SDCMSC_ARGUMENT, arg); |
|
// Wait for response |
cyg_uint32 reg; |
cyg_uint32 mask = SDCMSC_NORMAL_INT_STATUS_EI | |
SDCMSC_NORMAL_INT_STATUS_CC; |
|
do { |
HAL_READ_UINT32(SDCMSC_BASE + SDCMSC_NORMAL_INT_STATUS, reg); |
} while(!(reg & mask)); |
HAL_WRITE_UINT32(SDCMSC_BASE + SDCMSC_NORMAL_INT_STATUS, 0); |
|
// Optionally read response register |
if(response) { |
HAL_READ_UINT32(SDCMSC_BASE + SDCMSC_RESPONSE, *response); |
} |
|
// Check for errors |
if(reg & SDCMSC_NORMAL_INT_STATUS_EI) { |
HAL_READ_UINT32(SDCMSC_BASE + SDCMSC_ERROR_INT_STATUS, reg); |
if(reg & (1 << 3)) diag_printf("Command index error\n"); |
if(reg & (1 << 1)) diag_printf("Command CRC error\n"); |
if(reg & (1 << 0)) diag_printf("Command timeout\n"); |
HAL_WRITE_UINT32(SDCMSC_BASE + SDCMSC_ERROR_INT_STATUS, 0); |
return 0; |
} |
else { |
return 1; |
} |
} |
|
// Card initialization and identification implemented according to |
// Physical Layer Simplified Specification Version 3.01 |
static int sdcmsc_card_init(cyg_sdcmsc_disk_info_t *data, |
char *serial, |
char *firmware_rev, |
char *model_num, |
cyg_uint32 *capacity) { |
|
cyg_uint32 reg; |
cyg_uint32 cmd; |
cyg_uint32 arg; |
|
// Send CMD0 to switch the card to idle state |
cmd = SDCMSC_COMMAND_CMDI(0); |
if(!sdcmsc_card_cmd(cmd, 0, NULL)) return 0; |
|
// Send CMD8 offering 2.7V to 3.6V range |
// If the card doesn't responde it means either: |
// 1. Card supports v2.0 but can't communicate using |
// current voltage levels |
// 2. Card does not support v2.0 |
cmd = SDCMSC_COMMAND_CMDI(8) | |
SDCMSC_COMMAND_CICE | |
SDCMSC_COMMAND_CIRC | |
SDCMSC_COMMAND_RTS_48; |
data->is_v20 = sdcmsc_card_cmd(cmd, 0x1AA, NULL); |
|
do { |
HAL_READ_UINT32(SDCMSC_BASE + SDCMSC_CARD_STATUS, reg); |
} while(reg & SDCMSC_CARD_STATUS_CICMD); |
|
// Repeat ACMD41 until card set the busy bit to 1 |
// Since ACMD is an extended command, it must be preceded |
// by CMD55 |
do { |
cmd = SDCMSC_COMMAND_CMDI(55) | |
SDCMSC_COMMAND_CICE | |
SDCMSC_COMMAND_CIRC | |
SDCMSC_COMMAND_RTS_48; |
if(!sdcmsc_card_cmd(cmd, 0, NULL)) return 0; |
|
cmd = SDCMSC_COMMAND_CMDI(41) | |
SDCMSC_COMMAND_RTS_48; |
arg = data->is_v20 ? |
0x40FF8000 : |
0x00FF8000; |
if(!sdcmsc_card_cmd(cmd, arg, ®)) return 0; |
|
} while(!(reg & 0x80000000)); |
|
data->is_sdhc = !!(reg & 0x40000000); |
|
// Issue CMD2 to switch from ready state to ident. Unfortunately, it is |
// not possible to read whole CID because the command can be issued only |
// once, and the peripheral can store only 32bit of the command at once. |
cmd = SDCMSC_COMMAND_CMDI(2) | |
SDCMSC_COMMAND_RTS_136; |
if(!sdcmsc_card_cmd(cmd, 0, NULL)) return 0; |
|
// Issue CMD3 to get RCA and switch from ident state to stby. |
cmd = SDCMSC_COMMAND_CMDI(3) | |
SDCMSC_COMMAND_CICE | |
SDCMSC_COMMAND_CIRC | |
SDCMSC_COMMAND_RTS_48; |
if(!sdcmsc_card_cmd(cmd, 0, ®)) return 0; |
data->rca = reg & 0xFFFF0000; |
|
// Calculate card capacity. Use information stored in CSD register. |
cyg_uint32 card_capacity; |
if(data->is_sdhc) { |
cmd = SDCMSC_COMMAND_CMDI(9) | |
SDCMSC_COMMAND_CMDW(1) | |
SDCMSC_COMMAND_RTS_136; |
if(!sdcmsc_card_cmd(cmd, data->rca, ®)) return 0; |
card_capacity = reg & 0x3F; |
card_capacity <<= 16; |
|
cmd = SDCMSC_COMMAND_CMDI(9) | |
SDCMSC_COMMAND_CMDW(2) | |
SDCMSC_COMMAND_RTS_136; |
if(!sdcmsc_card_cmd(cmd, data->rca, ®)) return 0; |
reg >>= 16; |
card_capacity |= reg; |
card_capacity += 1; |
card_capacity *= 1000; |
} |
else { |
cmd = SDCMSC_COMMAND_CMDI(9) | |
SDCMSC_COMMAND_CMDW(1) | |
SDCMSC_COMMAND_RTS_136; |
if(!sdcmsc_card_cmd(cmd, data->rca, ®)) return 0; |
cyg_uint32 read_bl_len = (reg >> 16) & 0x0F; |
cyg_uint32 c_size = reg & 0x3FF; |
c_size <<= 2; |
|
cmd = SDCMSC_COMMAND_CMDI(9) | |
SDCMSC_COMMAND_CMDW(2) | |
SDCMSC_COMMAND_RTS_136; |
if(!sdcmsc_card_cmd(cmd, data->rca, ®)) return 0; |
c_size |= (reg >> 30) & 0x03; |
cyg_uint32 c_size_mult = (reg >> 15) & 0x07; |
card_capacity = c_size + 1; |
card_capacity *= 1 << (c_size_mult + 2); |
card_capacity *= 1 << (read_bl_len); |
card_capacity >>= 9; |
} |
|
// Fill disk identification struct using information in CID register |
// use OEM/APPlication ID field to fill model_num, |
// Product revision field to fill firmware_rev, |
// and Product serial number to field to fill serial |
cmd = SDCMSC_COMMAND_CMDI(10) | |
SDCMSC_COMMAND_CMDW(0) | |
SDCMSC_COMMAND_RTS_136; |
if(!sdcmsc_card_cmd(cmd, data->rca, ®)) return 0; |
model_num[0] = (reg >> 16) & 0xFF; |
model_num[1] = (reg >> 8) & 0xFF; |
model_num[2] = 0; |
|
cmd = SDCMSC_COMMAND_CMDI(10) | |
SDCMSC_COMMAND_CMDW(2) | |
SDCMSC_COMMAND_RTS_136; |
if(!sdcmsc_card_cmd(cmd, data->rca, ®)) return 0; |
firmware_rev[0] = (reg >> 24) & 0xFF; |
firmware_rev[1] = 0; |
serial[0] = (reg >> 16) & 0xFF; |
serial[1] = (reg >> 8) & 0xFF; |
serial[2] = reg & 0xFF; |
|
cmd = SDCMSC_COMMAND_CMDI(10) | |
SDCMSC_COMMAND_CMDW(3) | |
SDCMSC_COMMAND_RTS_136; |
if(!sdcmsc_card_cmd(cmd, data->rca, ®)) return 0; |
serial[3] = (reg >> 24) & 0xFF; |
|
// Put card in transfer state |
cmd = SDCMSC_COMMAND_CMDI(7) | |
SDCMSC_COMMAND_CICE | |
SDCMSC_COMMAND_CIRC | |
SDCMSC_COMMAND_RTS_48; |
if(!sdcmsc_card_cmd(cmd, data->rca, ®)) return 0; |
if(reg != 0x700) return 0; |
|
// Set block size to 512 |
cmd = SDCMSC_COMMAND_CMDI(16) | |
SDCMSC_COMMAND_CICE | |
SDCMSC_COMMAND_CIRC | |
SDCMSC_COMMAND_RTS_48; |
if(!sdcmsc_card_cmd(cmd, 512, NULL)) return 0; |
|
// Set 4-bits bus mode |
cmd = SDCMSC_COMMAND_CMDI(55) | |
SDCMSC_COMMAND_CICE | |
SDCMSC_COMMAND_CIRC | |
SDCMSC_COMMAND_RTS_48; |
if(!sdcmsc_card_cmd(cmd, data->rca, NULL)) return 0; |
|
cmd = SDCMSC_COMMAND_CMDI(6) | |
SDCMSC_COMMAND_CICE | |
SDCMSC_COMMAND_CIRC | |
SDCMSC_COMMAND_RTS_48; |
if(!sdcmsc_card_cmd(cmd, 0x02, NULL)) return 0; |
|
return 1; |
} |
|
static int sdcmsc_card_queue(cyg_sdcmsc_disk_info_t *data, |
int direction_transmit, |
int block_addr, |
cyg_uint32 buffer_addr) { |
|
// SDSC cards use byte addressing, while SDHC use block addressing. |
// It is therefore required to multiply the address by 512 if |
// we are dealing with SDSC card, to remain compatible with the API. |
if(!data->is_sdhc) { |
block_addr <<= 9; |
} |
|
if(direction_transmit) { |
HAL_WRITE_UINT32(SDCMSC_BASE + SDCMSC_BD_TX, buffer_addr); |
HAL_WRITE_UINT32(SDCMSC_BASE + SDCMSC_BD_TX, block_addr); |
} |
else { |
HAL_WRITE_UINT32(SDCMSC_BASE + SDCMSC_BD_RX, buffer_addr); |
HAL_WRITE_UINT32(SDCMSC_BASE + SDCMSC_BD_RX, block_addr); |
} |
|
// Now wait for the response |
cyg_uint32 reg; |
do { |
HAL_READ_UINT32(SDCMSC_BASE + SDCMSC_DAT_INT_STATUS, reg); |
} while(!reg); |
HAL_WRITE_UINT32(SDCMSC_BASE + SDCMSC_DAT_INT_STATUS, 0); |
|
// Check for errors |
if(reg == SDCMSC_DAT_INT_STATUS_TRS) { |
return 1; |
} |
else { |
if(reg & (1 << 5)) diag_printf("Transmission error\n"); |
if(reg & (1 << 4)) diag_printf("Command error\n"); |
if(reg & (1 << 2)) diag_printf("FIFO error\n"); |
if(reg & (1 << 1)) diag_printf("Retry error\n"); |
return 0; |
} |
} |
|
// This is an API function. Is is called once, in the beginning |
static cyg_bool sdcmsc_disk_init(struct cyg_devtab_entry* tab) { |
|
// Set highest possible timeout |
HAL_WRITE_UINT32(SDCMSC_BASE + SDCMSC_TIMEOUT, 0xFFFE); |
|
// Reset the peripheral |
HAL_WRITE_UINT32(SDCMSC_BASE + SDCMSC_SOFTWARE_RESET, 1); |
HAL_WRITE_UINT32(SDCMSC_BASE + SDCMSC_CLOCK_DIVIDER, 2); |
HAL_WRITE_UINT32(SDCMSC_BASE + SDCMSC_SOFTWARE_RESET, 0); |
|
// Call upper level |
disk_channel* ch = (disk_channel*) tab->priv; |
return (*ch->callbacks->disk_init)(tab); |
} |
|
// This function is called when user mounts the disk |
static Cyg_ErrNo sdcmsc_disk_lookup(struct cyg_devtab_entry** tab, |
struct cyg_devtab_entry *sub_tab, |
const char* name) { |
|
disk_channel *ch = (disk_channel*) (*tab)->priv; |
cyg_sdcmsc_disk_info_t *data = (cyg_sdcmsc_disk_info_t*) ch->dev_priv; |
|
// If the card was not initialized yet, it's time to do it |
// and call disk_connected callback |
if(!data->connected) { |
|
cyg_disk_identify_t id; |
|
// Pass dummy CHS geometry and hope the upper level |
// will use LBA mode. To guess CHS we would need to |
// analyze partition table and confront LBA and CHS |
// addresses. And it would work only if proper LBA |
// field is stored in MBR. Is is definitely something |
// that should be done by upper level. |
id.cylinders_num = 1; |
id.heads_num = 1; |
id.sectors_num = 1; |
|
id.phys_block_size = 1; |
id.max_transfer = 512; |
|
// Initialize the card |
data->connected = sdcmsc_card_init(data, |
id.serial, |
id.firmware_rev, |
id.model_num, |
&id.lba_sectors_num); |
|
if(data->connected) { |
// Let upper level know there is a new disk |
(*ch->callbacks->disk_connected)(*tab, &id); |
} |
} |
|
// Call upper level |
return (*ch->callbacks->disk_lookup)(tab, sub_tab, name); |
} |
|
// API function to read block from the disk |
static Cyg_ErrNo sdcmsc_disk_read(disk_channel* ch, |
void* buf, |
cyg_uint32 blocks, |
cyg_uint32 first_block) { |
|
cyg_sdcmsc_disk_info_t *data = (cyg_sdcmsc_disk_info_t*) ch->dev_priv; |
|
int i; |
int result; |
cyg_uint32 reg; |
for(i = 0; i < blocks; i++) { |
|
// Check for free receive buffers |
HAL_READ_UINT32(SDCMSC_BASE + SDCMSC_BD_BUFFER_STATUS, reg); |
reg >>= 8; |
reg &= 0xFF; |
if(reg == 0) { |
return -EIO; |
} |
|
result = sdcmsc_card_queue(data, 0, first_block, (cyg_uint32) buf); |
if(!result) { |
return -EIO; |
} |
} |
|
return ENOERR; |
|
} |
|
// API function to write block to disk |
static Cyg_ErrNo sdcmsc_disk_write(disk_channel* ch, |
const void* buf, |
cyg_uint32 blocks, |
cyg_uint32 first_block) { |
|
cyg_sdcmsc_disk_info_t *data = (cyg_sdcmsc_disk_info_t*) ch->dev_priv; |
|
int i; |
int result; |
cyg_uint32 reg; |
for(i = 0; i < blocks; i++) { |
|
// Check for free transmit buffers |
HAL_READ_UINT32(SDCMSC_BASE + SDCMSC_BD_BUFFER_STATUS, reg); |
reg &= 0xFF; |
if(reg == 0) { |
return -EIO; |
} |
|
result = sdcmsc_card_queue(data, 1, first_block, (cyg_uint32) buf); |
if(!result) { |
return -EIO; |
} |
} |
|
return ENOERR; |
|
} |
|
// API function to fetch driver configuration and disk info. |
static Cyg_ErrNo sdcmsc_disk_get_config(disk_channel* ch, |
cyg_uint32 key, |
const void* buf, |
cyg_uint32* len) { |
|
CYG_UNUSED_PARAM(disk_channel*, ch); |
CYG_UNUSED_PARAM(cyg_uint32, key); |
CYG_UNUSED_PARAM(const void*, buf); |
CYG_UNUSED_PARAM(cyg_uint32*, len); |
|
return -EINVAL; |
} |
|
// API function to update driver status information. |
static Cyg_ErrNo sdcmsc_disk_set_config(disk_channel* ch, |
cyg_uint32 key, |
const void* buf, |
cyg_uint32* len) { |
|
cyg_sdcmsc_disk_info_t *data = (cyg_sdcmsc_disk_info_t*) ch->dev_priv; |
|
if(key == CYG_IO_SET_CONFIG_DISK_UMOUNT) { |
if(ch->info->mounts == 0) { |
data->connected = false; |
return (ch->callbacks->disk_disconnected)(ch); |
} |
else { |
return ENOERR; |
} |
} |
else { |
return -EINVAL; |
} |
|
} |
|
// Register the driver in the system |
|
static cyg_sdcmsc_disk_info_t cyg_sdcmsc_disk0_hwinfo = { |
.connected = 0 |
}; |
|
DISK_FUNS(cyg_sdcmsc_disk_funs, |
sdcmsc_disk_read, |
sdcmsc_disk_write, |
sdcmsc_disk_get_config, |
sdcmsc_disk_set_config |
); |
|
|
DISK_CONTROLLER(cyg_sdcmsc_disk_controller_0, cyg_sdcmsc_disk0_hwinfo); |
|
DISK_CHANNEL(cyg_sdcmsc_disk0_channel, |
cyg_sdcmsc_disk_funs, |
cyg_sdcmsc_disk0_hwinfo, |
cyg_sdcmsc_disk_controller_0, |
true, //mbr supported |
4 //partitions |
); |
|
BLOCK_DEVTAB_ENTRY(cyg_sdcmsc_disk0_devtab_entry, |
CYGDAT_DEVS_DISK_OPENCORES_SDCMSC_DISK0_NAME, |
0, |
&cyg_io_disk_devio, |
&sdcmsc_disk_init, |
&sdcmsc_disk_lookup, |
&cyg_sdcmsc_disk0_channel); |
|
// EOF if_sdcmsc.c |
/packages/devs/disk/opencores/sdcmsc/current/ChangeLog
0,0 → 1,28
|
2012-05-01 Piotr Skrzypek <pskrzypek@antmicro.com> |
|
* Initial release of the driver |
|
//=========================================================================== |
// ####GPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. |
// |
// 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 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. |
// |
// You should have received a copy of the GNU General Public License |
// along with this program; if not, write to the |
// Free Software Foundation, Inc., 51 Franklin Street, |
// Fifth Floor, Boston, MA 02110-1301, USA. |
// ------------------------------------------- |
// ####GPLCOPYRIGHTEND#### |
//=========================================================================== |
/packages/ecos.db
1801,6 → 1801,14
description "Ethernet driver for Davicom DM9000 controller." |
} |
|
package CYGPKG_DEVS_ETH_OPENCORES_ETHMAC { |
alias { "OpenCores ETHMAC ethernet driver" ethmac_eth_driver } |
hardware |
directory devs/eth/opencores/ethmac |
script opencores_ethmac_eth_drivers.cdl |
description "Ethernet driver for OpenCores ETHMAC controller." |
} |
|
package CYGPKG_DEVS_ETH_MIPS_MIPS32_MALTA { |
alias { "MIPS Malta board ethernet driver" malta_eth_driver } |
hardware |
6524,6 → 6532,8
alias { "OpenRISC Reference Platform System-on-Chip" orpsoc } |
packages { CYGPKG_HAL_OPENRISC |
CYGPKG_HAL_OPENRISC_ORPSOC |
CYGPKG_DEVS_ETH_OPENCORES_ETHMAC |
CYGPKG_DEVS_DISK_OPENCORES_SDCMSC |
} |
description " |
The ORPSoC (OpenRISC Reference Platform System-on-Chip) target |
6944,6 → 6954,13
description "Disk driver for MMC cards" |
} |
|
package CYGPKG_DEVS_DISK_OPENCORES_SDCMSC { |
alias { "SDCard Mass Storage Controller" sdcmsc } |
directory devs/disk/opencores/sdcmsc |
script devs_disk_opencores_sdcmsc.cdl |
description "Disk driver for SDCard Mass Storage Controller." |
} |
|
package CYGPKG_DEVS_DISK_MMC_FREESCALE_DSPI { |
alias { "MMC/SD disk over Freescale DSPI" } |
hardware |