From 9e6b1246a4919ed29e1193bf96f5c6bc2d578fea Mon Sep 17 00:00:00 2001 From: Bence Kaposzta Date: Fri, 12 Oct 2018 09:13:04 +0200 Subject: [PATCH] This commit adds EMAC driver for CM3DS that uses an SMSC LAN 9220 Ethernet controller. To ensure proper operation, some methods needed to be updated in the SMSC9220's native driver as well. It passes all related Greentea tests, however when supervised by the Python environment it tends to fail because of Timeout. The current timeout is set to 1200s that seems to be a little bit short to finish all test cases, the timeout happens towards the end of the last test case. Change-Id: I914608c34828b493a80e133cd132537a297bfc84 Signed-off-by: Bence Kaposzta --- .../COMPONENT_SMSC9220/mbed_lib.json | 7 + .../COMPONENT_SMSC9220/smsc9220_emac.cpp | 338 ++++++ .../COMPONENT_SMSC9220/smsc9220_emac.h | 180 +++ .../COMPONENT_SMSC9220/smsc9220_emac_config.h | 42 + .../TARGET_CM3DS_MPS2/device/device_cfg.h | 6 + .../device/drivers/smsc9220_eth.c | 746 ------------ .../device/drivers/smsc9220_eth.h | 170 --- .../device/drivers/smsc9220_eth_drv.c | 1074 +++++++++++++++++ .../device/drivers/smsc9220_eth_drv.h | 548 +++++++++ .../device/platform_devices.c | 10 + .../device/platform_devices.h | 5 + .../TARGET_CM3DS_MPS2/ethernet_api.c | 85 -- .../TARGET_CM3DS_MPS2/mbed_overrides.c | 8 +- targets/targets.json | 8 +- 14 files changed, 2221 insertions(+), 1006 deletions(-) create mode 100644 features/netsocket/emac-drivers/TARGET_ARM_SSG/COMPONENT_SMSC9220/mbed_lib.json create mode 100644 features/netsocket/emac-drivers/TARGET_ARM_SSG/COMPONENT_SMSC9220/smsc9220_emac.cpp create mode 100644 features/netsocket/emac-drivers/TARGET_ARM_SSG/COMPONENT_SMSC9220/smsc9220_emac.h create mode 100644 features/netsocket/emac-drivers/TARGET_ARM_SSG/COMPONENT_SMSC9220/smsc9220_emac_config.h delete mode 100644 targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/smsc9220_eth.c delete mode 100644 targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/smsc9220_eth.h create mode 100644 targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/smsc9220_eth_drv.c create mode 100644 targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/smsc9220_eth_drv.h delete mode 100644 targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/ethernet_api.c diff --git a/features/netsocket/emac-drivers/TARGET_ARM_SSG/COMPONENT_SMSC9220/mbed_lib.json b/features/netsocket/emac-drivers/TARGET_ARM_SSG/COMPONENT_SMSC9220/mbed_lib.json new file mode 100644 index 0000000000..d54a2784ea --- /dev/null +++ b/features/netsocket/emac-drivers/TARGET_ARM_SSG/COMPONENT_SMSC9220/mbed_lib.json @@ -0,0 +1,7 @@ +{ + "name": "smsc9220-emac", + "config": { + "rx-ring-len": 1, + "tx-ring-len": 1 + } +} diff --git a/features/netsocket/emac-drivers/TARGET_ARM_SSG/COMPONENT_SMSC9220/smsc9220_emac.cpp b/features/netsocket/emac-drivers/TARGET_ARM_SSG/COMPONENT_SMSC9220/smsc9220_emac.cpp new file mode 100644 index 0000000000..167024e11a --- /dev/null +++ b/features/netsocket/emac-drivers/TARGET_ARM_SSG/COMPONENT_SMSC9220/smsc9220_emac.cpp @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2018 Arm Limited + * + * 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 +#include +#include +#include + +#include "mbed_interface.h" +#include "mbed_wait_api.h" +#include "mbed_assert.h" +#include "netsocket/nsapi_types.h" +#include "mbed_shared_queues.h" + +#include "smsc9220_emac.h" +#include "smsc9220_eth_drv.h" + +#ifndef SMSC9220_ETH +#error "SMSC9220_ETH should be defined, check device_cfg.h!" +#endif + +#ifndef SMSC9220_Ethernet_Interrupt_Handler +#error "SMSC9220_Ethernet_Interrupt_Handler should be defined to platform's \ +Ethernet IRQ handler!" +#endif + +static SMSC9220_EMAC *board_emac_pointer = NULL; +const struct smsc9220_eth_dev_t* SMSC9220_EMAC::dev = &SMSC9220_ETH_DEV; + +extern "C" void SMSC9220_Ethernet_Interrupt_Handler(void) +{ + if (smsc9220_get_interrupt(SMSC9220_EMAC::dev, + SMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL)) { + board_emac_pointer->rx_isr(); + smsc9220_clear_interrupt(SMSC9220_EMAC::dev, + SMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL); + smsc9220_disable_interrupt(SMSC9220_EMAC::dev, + SMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL); + } +} + +SMSC9220_EMAC::SMSC9220_EMAC() : receiver_thread(LINK_STATUS_THREAD_PRIORITY, + (uint32_t)LINK_STATUS_THREAD_STACKSIZE) +{ +} + +/** \brief Ethernet receive interrupt handler + * + * This function handles the receive interrupt. + */ +void SMSC9220_EMAC::rx_isr() +{ + receiver_thread.flags_set(FLAG_RX); +} + +/** \brief Allocates a emac_mem_buf_t and returns the data from the incoming + * packet. + * + * \return a emac_mem_buf_t filled with the received packet + * (including MAC header) + */ +emac_mem_buf_t *SMSC9220_EMAC::low_level_input() +{ + emac_mem_buf_t *p = NULL; + uint32_t message_length = 0; + + message_length = smsc9220_peek_next_packet_size(dev); + if (message_length == 0) { + return p; + } else { + /* The Ethernet controller cannot remove CRC from the end of the + * incoming packet, thus it should be taken into account when + * calculating the actual message length.*/ + message_length -= CRC_LENGTH_BYTES; + } + + p = _memory_manager->alloc_heap(message_length, SMSC9220_BUFF_ALIGNMENT); + + if (p != NULL) { + _RXLockMutex.lock(); + smsc9220_receive_by_chunks(dev, (char*)_memory_manager->get_ptr(p), + _memory_manager->get_len(p)); + _RXLockMutex.unlock(); + } + + return p; +} + +/** \brief Receiver thread. + * + * Woken by thread flags to receive packets or clean up transmit + * + * \param[in] params pointer to the interface data + */ +void SMSC9220_EMAC::receiver_thread_function(void* params) +{ + struct SMSC9220_EMAC *smsc9220_enet = static_cast(params); + + while(1) { + uint32_t flags = ThisThread::flags_wait_any(FLAG_RX); + + if (flags & FLAG_RX) { + smsc9220_enet->packet_rx(); + } + } +} + +/** \brief Packet reception task + * + * This task is called when a packet is received. It will + * pass the packet to the Network Stack. + */ +void SMSC9220_EMAC::packet_rx() +{ + emac_mem_buf_t *p; + p = low_level_input(); + if(p != NULL) { + _emac_link_input_cb(p); + } + smsc9220_enable_interrupt(dev, SMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL); +} + +bool SMSC9220_EMAC::link_out(emac_mem_buf_t *buf) +{ + if(buf == NULL) { + return false; + } else { + uint32_t buffer_chain_length = 0; + enum smsc9220_error_t error = SMSC9220_ERROR_NONE; + /* If buffer is chained or not aligned then + * make a contiguous aligned copy of it */ + if (_memory_manager->get_next(buf) || + reinterpret_cast(_memory_manager->get_ptr(buf)) % + SMSC9220_BUFF_ALIGNMENT) { + emac_mem_buf_t *copy_buf; + copy_buf = _memory_manager->alloc_heap( + _memory_manager->get_total_len(buf), + SMSC9220_BUFF_ALIGNMENT); + if (NULL == copy_buf) { + _memory_manager->free(buf); + return false; + } + + /* Copy to new buffer and free original */ + _memory_manager->copy(copy_buf, buf); + _memory_manager->free(buf); + buf = copy_buf; + } + + buffer_chain_length = _memory_manager->get_total_len(buf); + + _TXLockMutex.lock(); + error = smsc9220_send_by_chunks(dev, + buffer_chain_length, + true, + (const char*)_memory_manager->get_ptr(buf), + _memory_manager->get_len(buf)); + if (error != SMSC9220_ERROR_NONE) { + _TXLockMutex.unlock(); + return false; + } + _TXLockMutex.unlock(); + return true; + } +} + +void SMSC9220_EMAC::link_status_task() +{ + uint32_t phy_basic_status_reg_value = 0; + bool current_link_status_up = false; + + /* Get current status */ + smsc9220_phy_regread(dev, SMSC9220_PHY_REG_OFFSET_BSTATUS, + &phy_basic_status_reg_value); + + current_link_status_up = (bool)(phy_basic_status_reg_value & + (1ul << (PHY_REG_BSTATUS_LINK_STATUS_INDEX))); + + /* Compare with previous state */ + if (current_link_status_up != _prev_link_status_up) { + _emac_link_state_cb(current_link_status_up); + _prev_link_status_up = current_link_status_up; + } + +} + +bool SMSC9220_EMAC::power_up() +{ + board_emac_pointer = this; + receiver_thread.start(callback(&SMSC9220_EMAC::receiver_thread_function, + this)); + + /* Initialize the hardware */ + enum smsc9220_error_t init_successful = smsc9220_init(dev, &wait_ms); + if (init_successful != SMSC9220_ERROR_NONE) { + return false; + } + + /* Init FIFO level interrupts: use Rx status level irq to trigger + * interrupts for any non-processed packets, while Tx is not irq driven */ + smsc9220_set_fifo_level_irq(dev, SMSC9220_FIFO_LEVEL_IRQ_RX_STATUS_POS, + SMSC9220_FIFO_LEVEL_IRQ_LEVEL_MIN); + smsc9220_set_fifo_level_irq(dev, SMSC9220_FIFO_LEVEL_IRQ_TX_STATUS_POS, + SMSC9220_FIFO_LEVEL_IRQ_LEVEL_MIN); + smsc9220_set_fifo_level_irq(dev, SMSC9220_FIFO_LEVEL_IRQ_TX_DATA_POS, + SMSC9220_FIFO_LEVEL_IRQ_LEVEL_MAX); + + /* Enable Ethernet interrupts in NVIC */ + NVIC_EnableIRQ(ETHERNET_IRQn); + smsc9220_enable_interrupt(dev, SMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL); + + /* Trigger thread to deal with any RX packets that arrived + * before receiver_thread was started */ + rx_isr(); + _prev_link_status_up = PHY_STATE_LINK_DOWN; + mbed::mbed_event_queue()->call(mbed::callback(this, + &SMSC9220_EMAC::link_status_task)); + + /* Allow the Link Status task to detect the initial link state */ + wait_ms(10); + _link_status_task_handle = mbed::mbed_event_queue()->call_every( + LINK_STATUS_TASK_PERIOD_MS, + mbed::callback(this, + &SMSC9220_EMAC::link_status_task)); + + return true; +} + +uint32_t SMSC9220_EMAC::get_mtu_size() const +{ + return SMSC9220_ETH_MTU_SIZE; +} + +uint32_t SMSC9220_EMAC::get_align_preference() const +{ + return SMSC9220_BUFF_ALIGNMENT; +} + +void SMSC9220_EMAC::get_ifname(char *name, uint8_t size) const +{ + memcpy(name, SMSC9220_ETH_IF_NAME, (size < sizeof(SMSC9220_ETH_IF_NAME)) ? + size : sizeof(SMSC9220_ETH_IF_NAME)); +} + +uint8_t SMSC9220_EMAC::get_hwaddr_size() const +{ + return SMSC9220_HWADDR_SIZE; +} + +bool SMSC9220_EMAC::get_hwaddr(uint8_t *addr) const +{ + if(smsc9220_read_mac_address(dev, (char*)addr) == SMSC9220_ERROR_NONE) { + return true; + } else { + return false; + } +} + +void SMSC9220_EMAC::set_hwaddr(const uint8_t *addr) +{ + if (!addr) { + return; + } + + memcpy(_hwaddr, addr, sizeof _hwaddr); + uint32_t mac_low = 0; + uint32_t mac_high = 0; + + /* Using local variables to make sure the right alignment is used */ + memcpy((void*)&mac_low, (void*)addr, 4); + memcpy((void*)&mac_high, (void*)(addr+4), 2); + + if (smsc9220_mac_regwrite(dev, SMSC9220_MAC_REG_OFFSET_ADDRL, mac_low)) { + return; + } + if (smsc9220_mac_regwrite(dev, SMSC9220_MAC_REG_OFFSET_ADDRH, mac_high)) { + return; + } +} + +void SMSC9220_EMAC::set_link_input_cb(emac_link_input_cb_t input_cb) +{ + _emac_link_input_cb = input_cb; +} + +void SMSC9220_EMAC::set_link_state_cb(emac_link_state_change_cb_t state_cb) +{ + _emac_link_state_cb = state_cb; +} + +void SMSC9220_EMAC::add_multicast_group(const uint8_t *addr) +{ + // No action for now +} + +void SMSC9220_EMAC::remove_multicast_group(const uint8_t *addr) +{ + // No action for now +} + +void SMSC9220_EMAC::set_all_multicast(bool all) +{ + // No action for now +} + +void SMSC9220_EMAC::power_down() +{ + // No action for now +} + +void SMSC9220_EMAC::set_memory_manager(EMACMemoryManager &mem_mngr) +{ + _memory_manager = &mem_mngr; +} + + +SMSC9220_EMAC &SMSC9220_EMAC::get_instance() { + static SMSC9220_EMAC emac; + return emac; +} + +/* Weak so a module can override */ +MBED_WEAK EMAC &EMAC::get_default_instance() { + return SMSC9220_EMAC::get_instance(); +} diff --git a/features/netsocket/emac-drivers/TARGET_ARM_SSG/COMPONENT_SMSC9220/smsc9220_emac.h b/features/netsocket/emac-drivers/TARGET_ARM_SSG/COMPONENT_SMSC9220/smsc9220_emac.h new file mode 100644 index 0000000000..58762d4f59 --- /dev/null +++ b/features/netsocket/emac-drivers/TARGET_ARM_SSG/COMPONENT_SMSC9220/smsc9220_emac.h @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2018 Arm Limited + * + * 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. + */ + +#ifndef SMSC9220_EMAC_H_ +#define SMSC9220_EMAC_H_ + +#include "EMAC.h" +#include "mbed.h" +#include "rtos/Mutex.h" + +#include "smsc9220_emac_config.h" + +class SMSC9220_EMAC : public EMAC { +public: + SMSC9220_EMAC(); + + static SMSC9220_EMAC &get_instance(); + + /** + * Return maximum transmission unit + * + * @return MTU in bytes + */ + virtual uint32_t get_mtu_size() const; + + /** + * Gets memory buffer alignment preference + * + * Gets preferred memory buffer alignment of the Emac device. IP stack may + * or may not align link out memory buffer chains using the alignment. + * + * @return Memory alignment requirement in bytes + */ + virtual uint32_t get_align_preference() const; + + /** + * Return interface name + * + * @param name Pointer to where the name should be written + * @param size Maximum number of character to copy + */ + virtual void get_ifname(char *name, uint8_t size) const; + + /** + * Returns size of the underlying interface HW address size. + * + * @return HW address size in bytes + */ + virtual uint8_t get_hwaddr_size() const; + + /** + * Return interface-supplied HW address + * + * Copies HW address to provided memory, @param addr has to be of correct + * size see @a get_hwaddr_size + * + * HW address need not be provided if this interface does not have its own + * HW address configuration; stack will choose address from central system + * configuration if the function returns false and does not write to addr. + * + * @param addr HW address for underlying interface + * @return true if HW address is available + */ + virtual bool get_hwaddr(uint8_t *addr) const; + + /** + * Set HW address for interface + * + * Provided address has to be of correct size, see @a get_hwaddr_size + * + * Called to set the MAC address to actually use - if @a get_hwaddr is + * provided the stack would normally use that, but it could be overridden, + * eg for test purposes. + * + * @param addr Address to be set + */ + virtual void set_hwaddr(const uint8_t *addr); + + /** + * Sends the packet over the link + * + * That can not be called from an interrupt context. + * + * @param buf Packet to be send + * @return True if the packet was send successfully, False otherwise + */ + virtual bool link_out(emac_mem_buf_t *buf); + + /** + * Initializes the HW + * + * @return True on success, False in case of an error. + */ + virtual bool power_up(); + + /** + * Deinitializes the HW + * + */ + virtual void power_down(); + + /** + * Sets a callback that needs to be called for packets received for that + * interface + * + * @param input_cb Function to be register as a callback + */ + virtual void set_link_input_cb(emac_link_input_cb_t input_cb); + + /** + * Sets a callback that needs to be called on link status changes for given + * interface + * + * @param state_cb Function to be register as a callback + */ + virtual void set_link_state_cb(emac_link_state_change_cb_t state_cb); + + /** Add device to a multicast group + * + * @param address A multicast group hardware address + */ + virtual void add_multicast_group(const uint8_t *address); + + /** Remove device from a multicast group + * + * @param address A multicast group hardware address + */ + virtual void remove_multicast_group(const uint8_t *address); + + /** Request reception of all multicast packets + * + * @param all True to receive all multicasts + * False to receive only multicasts addressed to specified groups + */ + virtual void set_all_multicast(bool all); + + /** Sets memory manager that is used to handle memory buffers + * + * @param mem_mngr Pointer to memory manager + */ + virtual void set_memory_manager(EMACMemoryManager &mem_mngr); + + void rx_isr(); + + static const struct smsc9220_eth_dev_t *dev; + +private: + void packet_rx(); + void link_status_task(); + bool low_level_init_successful(); + emac_mem_buf_t *low_level_input(); + static void receiver_thread_function(void* params); + + rtos::Mutex _TXLockMutex; + rtos::Mutex _RXLockMutex; + bool _prev_link_status_up; + int _link_status_task_handle; + uint8_t _hwaddr[SMSC9220_HWADDR_SIZE]; + + Thread receiver_thread; + EMACMemoryManager *_memory_manager; + emac_link_input_cb_t _emac_link_input_cb; + emac_link_state_change_cb_t _emac_link_state_cb; + +}; + +#endif /* SMSC9220_EMAC_H_ */ diff --git a/features/netsocket/emac-drivers/TARGET_ARM_SSG/COMPONENT_SMSC9220/smsc9220_emac_config.h b/features/netsocket/emac-drivers/TARGET_ARM_SSG/COMPONENT_SMSC9220/smsc9220_emac_config.h new file mode 100644 index 0000000000..f8299a84b6 --- /dev/null +++ b/features/netsocket/emac-drivers/TARGET_ARM_SSG/COMPONENT_SMSC9220/smsc9220_emac_config.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018 Arm Limited + * + * 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. + */ + +#ifndef SMSC9220_EMAC_CONFIG_H +#define SMSC9220_EMAC_CONFIG_H + +#include "cmsis_os.h" + +#define SMSC9220_HWADDR_SIZE 6U +#define SMSC9220_BUFF_ALIGNMENT 4U + +/* + * Maximum Transfer Unit + * The IEEE 802.3 specification limits the data portion of the 802.3 frame + * to a minimum of 46 and a maximum of 1522 bytes, this is on L2 level. + */ +#define SMSC9220_ETH_MTU_SIZE 1500U +#define SMSC9220_ETH_IF_NAME "smsc9220" + +/** \brief Defines for receiver thread */ +#define FLAG_RX 1U +#define LINK_STATUS_THREAD_PRIORITY (osPriorityNormal) +#define LINK_STATUS_THREAD_STACKSIZE 2048U +#define LINK_STATUS_TASK_PERIOD_MS 200U +#define PHY_STATE_LINK_DOWN false +#define PHY_STATE_LINK_UP true +#define CRC_LENGTH_BYTES 4U + +#endif /* SMSC9220_EMAC_CONFIG_H */ diff --git a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/device_cfg.h b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/device_cfg.h index dd39c21a0a..b18568b0d3 100644 --- a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/device_cfg.h +++ b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/device_cfg.h @@ -58,4 +58,10 @@ #define ARM_UART3 #define ARM_UART4 +/* SMSC9220 Ethernet */ +#ifdef COMPONENT_SMSC9220 +#define SMSC9220_ETH +#define SMSC9220_Ethernet_Interrupt_Handler ETHERNET_IRQHandler +#endif + #endif /* __ARM_LTD_DEVICE_CFG_H__ */ diff --git a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/smsc9220_eth.c b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/smsc9220_eth.c deleted file mode 100644 index 0fee077abf..0000000000 --- a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/smsc9220_eth.c +++ /dev/null @@ -1,746 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017-2018 ARM Limited - * - * 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. - */ - -/* - * Code implementation file for the LAN Ethernet interface. - * - * This file is the based on mps2_ethernet_api and Selftest's ETH_MPS2. - * MPS2 Selftest:https://silver.arm.com/browse/VEI10 -> - * \ISCM-1-0\AN491\software\Selftest\v2m_mps2\ - */ - -#include - -#include "mbed_retarget.h" -#include "mbed_wait_api.h" -#include "CM3DS.h" -#include "smsc9220_eth.h" - -#define REG_WRITE_TIME_OUT 50 -#define RESET_TIME_OUT 10 -#define PHY_RESET_TIME_OUT_MS 100 - -/* Forward declarations */ - -static unsigned int smsc9220_mac_regread(unsigned char regoffset, unsigned int *data); -static unsigned int smsc9220_mac_regwrite(unsigned char regoffset, unsigned int data); -static unsigned int smsc9220_phy_regread(unsigned char regoffset, unsigned int *data); -static unsigned int smsc9220_phy_regwrite(unsigned char regoffset, unsigned int data); - -static unsigned int smsc9220_read_id(void); -static unsigned int smsc9220_soft_reset(void); -static void smsc9220_set_txfifo(unsigned int val); -static unsigned int smsc9220_wait_eeprom(void); -static void smsc9220_init_irqs(void); -static unsigned int smsc9220_check_phy(void); -static unsigned int smsc9220_reset_phy(void); - -static void smsc9220_advertise_cap(void); -static void smsc9220_enable_xmit(void); -static void smsc9220_enable_mac_xmit(void); -static void smsc9220_enable_mac_recv(void); - -/* SMSC9220 low-level operations */ - -/** - * \brief Read MAC register. - * - * \param[in] regoffset Register offset - * \param[out] data Register value is read - * - * \return 0 in case of success, 1 otherwise - */ -static unsigned int smsc9220_mac_regread(unsigned char regoffset, unsigned int *data) -{ - unsigned int val = 0; - unsigned int maccmd = 0; - int time_out = REG_WRITE_TIME_OUT; - - val = SMSC9220->MAC_CSR_CMD; - if(!(val & ((unsigned int)1 << 31))) { /* Make sure there's no pending operation */ - maccmd |= regoffset; - maccmd |= ((unsigned int)1 << 30); /* Indicates read */ - maccmd |= ((unsigned int)1 << 31); /* Start bit */ - SMSC9220->MAC_CSR_CMD = maccmd; /* Start operation */ - - do { - val = SMSC9220->BYTE_TEST; /* A no-op read. */ - wait_ms(1); - time_out--; - } while(time_out && (SMSC9220->MAC_CSR_CMD & ((unsigned int)1 << 31))); - - if(!time_out) { - return 1; - } - else { - *data = SMSC9220->MAC_CSR_DATA; - } - } else { - *data = 0; - } - return 0; -} - -/** - * \brief Write MAC register. - * - * \param[in] regoffset Register offset - * \param[in] data Register value to write - * - * \return 0 in case of success, 1 otherwise - */ -static unsigned int smsc9220_mac_regwrite(unsigned char regoffset, unsigned int data) -{ - unsigned int read = 0; - unsigned int maccmd = 0; - int time_out = REG_WRITE_TIME_OUT; - - read = SMSC9220->MAC_CSR_CMD; - if(!(read & ((unsigned int)1 << 31))) { /* Make sure there's no pending operation */ - SMSC9220->MAC_CSR_DATA = data; /* Store data. */ - maccmd |= regoffset; - maccmd &= ~((unsigned int)1 << 30); /* Clear indicates write */ - maccmd |= ((unsigned int)1 << 31); /* Indicate start of operation */ - SMSC9220->MAC_CSR_CMD = maccmd; - - do { - read = SMSC9220->BYTE_TEST; /* A no-op read. */ - wait_ms(1); - time_out--; - } while(time_out && (SMSC9220->MAC_CSR_CMD & ((unsigned int)1 << 31))); - - if(!time_out) { - return 1; - } - } else { - printf("Error: SMSC9220 MAC CSR is busy. No data written.\n"); - } - return 0; -} - -/** - * \brief Read PHY register. - * - * \param[in] regoffset Register offset - * \param[out] data Register value is read - * - * \return 0 in case of success, 1 otherwise - */ -static unsigned int smsc9220_phy_regread(unsigned char regoffset, unsigned int *data) -{ - unsigned int val = 0; - unsigned int phycmd = 0; - int time_out = REG_WRITE_TIME_OUT; - - if (smsc9220_mac_regread(SMSC9220_MAC_MII_ACC, &val)) { - return 1; - } - - if(!(val & 1)) { /* Not busy */ - phycmd = 0; - phycmd |= (1 << 11); /* 1 to [15:11] */ - phycmd |= ((regoffset & 0x1F) << 6); /* Put regoffset to [10:6] */ - phycmd &= ~(1 << 1); /* Clear [1] indicates read. */ - phycmd |= (1 << 0); /* Set [0] indicates operation start */ - - if (smsc9220_mac_regwrite(SMSC9220_MAC_MII_ACC, phycmd)) { - return 1; - } - - val = 0; - do { - wait_ms(1); - time_out--; - if (smsc9220_mac_regread(SMSC9220_MAC_MII_ACC,&val)) { - return 1; - } - } while(time_out && (val & ((unsigned int)1 << 0))); - - if (!time_out) { - return 1; - } else if (smsc9220_mac_regread(SMSC9220_MAC_MII_DATA, data)) { - return 1; - } - } else { - *data = 0; - return 1; - } - return 0; -} - -/** - * \brief Write PHY register. - * - * \param[in] regoffset Register offset - * \param[in] data Register value to write - * - * \return 0 in case of success, 1 otherwise - */ -static unsigned int smsc9220_phy_regwrite(unsigned char regoffset, unsigned int data) -{ - unsigned int val = 0; - unsigned int phycmd = 0; - int time_out = REG_WRITE_TIME_OUT; - - if (smsc9220_mac_regread(SMSC9220_MAC_MII_ACC, &val)) { - return 1; - } - - if(!(val & 1)) { /* Not busy */ - /* Load the data */ - if (smsc9220_mac_regwrite(SMSC9220_MAC_MII_DATA, (data & 0xFFFF))) { - return 1; - } - phycmd = 0; - phycmd |= (1 << 11); /* 1 to [15:11] */ - phycmd |= ((regoffset & 0x1F) << 6); /* Put regoffset to [10:6] */ - phycmd |= (1 << 1); /* Set [1] indicates write. */ - phycmd |= (1 << 0); /* Set [0] indicates operation start */ - /* Start operation */ - if (smsc9220_mac_regwrite(SMSC9220_MAC_MII_ACC, phycmd)) { - return 1; - } - - phycmd = 0; - - do { - wait_ms(1); - time_out--; - if (smsc9220_mac_regread(SMSC9220_MAC_MII_ACC, &phycmd)){ - return 1; - } - } while(time_out && (phycmd & (1 << 0))); - - if (!time_out) { - return 1; - } - - } else { - printf("Error: SMSC9220 MAC MII is busy. No data written.\n"); - } - return 0; -} - -/** - * \brief Read SMSC9220 ID. - * - * \return ID number - */ -inline static unsigned int smsc9220_read_id(void) -{ - return SMSC9220->ID_REV; -} - -/** - * \brief Initiates a soft reset, returns failure or success. - * - * \return 0 in case of success, 1 otherwise - */ -static unsigned int smsc9220_soft_reset(void) -{ - int time_out = RESET_TIME_OUT; - - /* Soft reset */ - SMSC9220->HW_CFG |= 1; - - do { - wait_ms(1); - time_out--; - } while(time_out && (SMSC9220->HW_CFG & 1)); - - if (!time_out) { - return 1; - } - - return 0; -} - -/** - * \brief Set maximum transition unit by Tx fifo size. - * Note: The MTU will be smaller by 512 bytes, - * because the status uses this fixed space. - * - * \param[in] val Size of the fifo in kbytes, 2-14 - */ -static void smsc9220_set_txfifo(unsigned int val) -{ - /* 2kb minimum, 14kb maximum */ - if(val >= 2 && val <= 14) { - SMSC9220->HW_CFG = val << 16; - } -} - -/** - * \brief Wait for EEPROM to be ready to use. - * - * \return 0 if ready, 1 in case of timeout - */ -static unsigned int smsc9220_wait_eeprom(void) -{ - int time_out = REG_WRITE_TIME_OUT; - - do { - wait_ms(1); - time_out--; - } while(time_out && (SMSC9220->E2P_CMD & ((unsigned int) 1 << 31))); - - if (!time_out) { - return 1; - } - - return 0; -} - -/** - * \brief Initialise irqs - */ -static void smsc9220_init_irqs(void) -{ - SMSC9220->INT_EN = 0x0; - SMSC9220->INT_STS = 0xFFFFFFFF; /* clear all interrupts */ - SMSC9220->IRQ_CFG = 0x22000100; /* irq deassertion at 220 usecs and master IRQ enable. */ -} - -/** - * \brief Check PHY ID registers. - * - * \return 0 in case of success, 1 otherwise - */ -static unsigned int smsc9220_check_phy(void) -{ - unsigned int phyid1, phyid2; - - if (smsc9220_phy_regread(SMSC9220_PHY_ID1,&phyid1)) { - return 1; - } - if (smsc9220_phy_regread(SMSC9220_PHY_ID2,&phyid2)) { - return 1; - } - return ((phyid1 == 0xFFFF && phyid2 == 0xFFFF) || - (phyid1 == 0x0 && phyid2 == 0x0)); -} - -/** - * \brief Reset PHY - * - * \return 0 in case of success, 1 otherwise - */ -static unsigned int smsc9220_reset_phy(void) -{ - unsigned int read; - - if(smsc9220_phy_regread(SMSC9220_PHY_BCONTROL, &read)) { - return 1; - } - - read |= (1 << 15); - if(smsc9220_phy_regwrite(SMSC9220_PHY_BCONTROL, read)) { - return 1; - } - return 0; -} - - -/** - * \brief Advertise all speeds and pause capabilities - * - * \return 0 in case of success, 1 otherwise - */ -static void smsc9220_advertise_cap(void) -{ - unsigned int aneg_adv = 0; - - smsc9220_phy_regread(SMSC9220_PHY_ANEG_ADV, &aneg_adv); - aneg_adv |= 0xDE0; - - smsc9220_phy_regwrite(SMSC9220_PHY_ANEG_ADV, aneg_adv); - smsc9220_phy_regread(SMSC9220_PHY_ANEG_ADV, &aneg_adv); -} - -/** - * \brief Enable trasmission - */ -inline static void smsc9220_enable_xmit(void) -{ - SMSC9220->TX_CFG = 0x2; -} - -static void smsc9220_enable_mac_xmit(void) -{ - unsigned int mac_cr = 0; - - smsc9220_mac_regread(SMSC9220_MAC_CR, &mac_cr); - - mac_cr |= (1 << 3); /* xmit enable */ - mac_cr |= (1 << 28); /* Heartbeat disable */ - - smsc9220_mac_regwrite(SMSC9220_MAC_CR, mac_cr); -} - -/** - * \brief Enable receive - */ -static void smsc9220_enable_mac_recv(void) -{ - unsigned int mac_cr = 0; - - smsc9220_mac_regread(SMSC9220_MAC_CR, &mac_cr); - mac_cr |= (1 << 2); /* Recv enable */ - smsc9220_mac_regwrite(SMSC9220_MAC_CR, mac_cr); -} - -/** - * \brief Check device ID. - * - * \return 0 in case of success, 1 otherwise - */ -static int smsc9220_check_id(void) -{ - unsigned int id = smsc9220_read_id(); - - /* If bottom and top halves of the word are the same */ - if(((id >> 16) & 0xFFFF) == (id & 0xFFFF)) { - return 1; - } - switch(((id >> 16) & 0xFFFF)) { - case 0x9220: - break; - - default: - return 1; - } - - return 0; -} - -/** - * \brief Fill the SMSC9220 TX FIFO with a number of words at an aligned - * address. - * - * \param[in] data Pointer to the aligned data that should be sent. - * \param[in] dwords_to_write Number of data words to write. - */ -static void fill_tx_fifo_aligned(unsigned int *data, - unsigned int dwords_to_write) -{ - while (dwords_to_write > 0) { - SMSC9220->TX_DATA_PORT = *data; - data++; - dwords_to_write--; - } -} - -/** - * \brief Fill the SMSC9220 TX FIFO with a number of words at an unaligned - * address. This function ensures that loading words at that address will - * not generate unaligned access which can trigger an exception to the - * processor. - * - * \param[in] data Pointer to the unaligned data that should be sent. - * \param[in] dwords_to_write Number of data words to write. - */ -static void fill_tx_fifo_unaligned(uint8_t *data, unsigned int dwords_to_write) -{ - /* - * Prevent unaligned word access from data pointer, 4 bytes are copied to - * this variable for each word that need to be sent. - */ - unsigned int tx_data_port_tmp = 0; - uint8_t *tx_data_port_tmp_ptr = (uint8_t *)&tx_data_port_tmp; - - while (dwords_to_write > 0) { - /* Keep the same endianness in data than in the temp variable */ - tx_data_port_tmp_ptr[0] = data[0]; - tx_data_port_tmp_ptr[1] = data[1]; - tx_data_port_tmp_ptr[2] = data[2]; - tx_data_port_tmp_ptr[3] = data[3]; - SMSC9220->TX_DATA_PORT = tx_data_port_tmp; - data += 4; - dwords_to_write--; - } -} - -/*---------------------------------------------------------------------------- - Public API - *----------------------------------------------------------------------------*/ -int smsc9220_init(void) -{ - unsigned int phyreset = 0; - - if(smsc9220_check_id()) { - return 1; - } - - if(smsc9220_soft_reset()) { - return 1; - } - - smsc9220_set_txfifo(5); - - /* Sets automatic flow control thresholds, and backpressure */ - /* threshold to defaults specified. */ - SMSC9220->AFC_CFG = 0x006E3740; - - if(smsc9220_wait_eeprom()) { - return 1; - } - - /* Configure GPIOs as LED outputs. */ - SMSC9220->GPIO_CFG = 0x70070000; - - smsc9220_init_irqs(); - - /* Configure MAC addresses here if needed. */ - - if(smsc9220_check_phy()) { - return 1; - } - - if(smsc9220_reset_phy()) { - return 1; - } - - wait_ms(PHY_RESET_TIME_OUT_MS); - /* Checking whether phy reset completed successfully.*/ - if (smsc9220_phy_regread(SMSC9220_PHY_BCONTROL, &phyreset)) { - return 1; - } - if(phyreset & (1 << 15)) { - return 1; - } - - smsc9220_advertise_cap(); - smsc9220_establish_link(); /* bit [12] of BCONTROL seems self-clearing. */ - /* Although it's not so in the manual. */ - - /* Interrupt threshold */ - SMSC9220->FIFO_INT = 0xFF000000; - - smsc9220_enable_mac_xmit(); - smsc9220_enable_xmit(); - SMSC9220->RX_CFG = 0; - smsc9220_enable_mac_recv(); - - /* Rx status FIFO level irq threshold */ - SMSC9220->FIFO_INT &= ~(0xFF); /* Clear 2 bottom nibbles */ - - /* This sleep is compulsory otherwise txmit/receive will fail. */ - wait_ms(2000); - return 0; -} - -void smsc9220_enable_interrupt(enum smsc9220_interrupt_source source) -{ - SMSC9220->INT_EN |= (1 << source); -} - -void smsc9220_disable_interrupt(enum smsc9220_interrupt_source source) -{ - SMSC9220->INT_EN &= ~(1 << source); -} - -void smsc9220_clear_interrupt(enum smsc9220_interrupt_source source) -{ - SMSC9220->INT_STS |= (1 << source); -} - -int smsc9220_get_interrupt(enum smsc9220_interrupt_source source) -{ - return (SMSC9220->INT_STS & (1 << source)); -} - -void smsc9220_establish_link(void) -{ - unsigned int bcr = 0; - unsigned int hw_cfg = 0; - - smsc9220_phy_regread(SMSC9220_PHY_BCONTROL, &bcr); - bcr |= (1 << 12) | (1 << 9); - smsc9220_phy_regwrite(SMSC9220_PHY_BCONTROL, bcr); - smsc9220_phy_regread(SMSC9220_PHY_BCONTROL, &bcr); - - hw_cfg = SMSC9220->HW_CFG; - hw_cfg &= 0xF0000; - hw_cfg |= (1 << 20); - SMSC9220->HW_CFG = hw_cfg; -} - -int smsc9220_read_mac_address(char *mac) -{ - unsigned int mac_low = 0; - unsigned int mac_high = 0; - - if( !mac ) { - return 1; - } - - /* Read current mac address. */ - if (smsc9220_mac_regread(SMSC9220_MAC_ADDRH, &mac_high)) { - return 1; - } - if (smsc9220_mac_regread(SMSC9220_MAC_ADDRL, &mac_low)) { - return 1; - } - mac[0] = mac_low & 0xFF; - mac[1] = (mac_low >> 8) & 0xFF; - mac[2] = (mac_low >> 16) & 0xFF; - mac[3] = (mac_low >> 24) & 0xFF; - mac[4] = mac_high & 0xFF; - mac[5] = (mac_high >> 8) & 0xFF; - - return 0; -} - -unsigned int smsc9220_get_tx_data_fifo_size(void) -{ - const unsigned int tx_status_fifo_size = 512; /* fixed allocation in bytes */ - unsigned int tx_fifo_size = SMSC9220->HW_CFG; - tx_fifo_size = (( tx_fifo_size >> 16 ) & 0x0F) * 1024; /* size is set in kbytes */ - return (tx_fifo_size - tx_status_fifo_size); -} - -int smsc9220_send_by_chunks(unsigned int total_packet_length, int is_new_packet, - const char *data, unsigned int current_size) -{ - static unsigned int ongoing_packet_length = 0; /* size in bytes of the packet is sending */ - static unsigned int ongoing_packet_length_sent = 0; /* size in bytes of the packet has been sent */ - int is_first_segment = 0; /* signing this is the first segment of the packet to be sent */ - int is_last_segment = 0; /* signing this is the last segment of the packet to be sent */ - unsigned int txcmd_a, txcmd_b = 0; - unsigned int dwords_to_write = 0; - unsigned int xmit_inf = 0; - unsigned int tx_buffer_free_space = 0; - unsigned int xmit_stat = 0; - - if (!data) { - return -1; /* Invalid input parameter */ - } - - if (is_new_packet) { - is_first_segment = 1; - ongoing_packet_length = total_packet_length; - ongoing_packet_length_sent = 0; - } else if (ongoing_packet_length != total_packet_length || - ongoing_packet_length_sent >= total_packet_length) { - return -1; /* Invalid input parameter */ - } - - /* Would next chunk fit into buffer? */ - xmit_inf = SMSC9220->TX_FIFO_INF; - tx_buffer_free_space = xmit_inf & 0xFFFF; - if (current_size > tx_buffer_free_space) { - return -1; /* Not enough space in FIFO */ - } - if ((ongoing_packet_length_sent + current_size) == total_packet_length) { - is_last_segment = 1; - } - - txcmd_a = 0; - txcmd_b = 0; - - txcmd_a |= (is_last_segment << 12) | (is_first_segment << 13); /* Last and first segments */ - txcmd_a |= current_size & 0x7FF; /* [10:0] contains length */ - - txcmd_b |= ((current_size & 0xFFFF) << 16); /* [31:16] contains length */ - txcmd_b |= current_size & 0x7FF; /* [10:0] also contains length */ - - SMSC9220->TX_DATA_PORT = txcmd_a; - SMSC9220->TX_DATA_PORT = txcmd_b; - dwords_to_write = (current_size + 3) >> 2; - - /* - * Copy to TX FIFO - * The function to use depends on the alignment of the data pointer on a 32 - * bits boundary. - */ - if (((unsigned int)data % sizeof(uint32_t)) == 0) { - /* Cast is safe because we know data is aligned */ - fill_tx_fifo_aligned((unsigned int *)data, dwords_to_write); - } else { - fill_tx_fifo_unaligned((uint8_t *)data, dwords_to_write); - } - - if (is_last_segment) { - /* pop status port */ - /* for error check it should be checked "at a later time" according to data sheet */ - xmit_stat = SMSC9220->TX_STAT_PORT; - (void)xmit_stat; - } - - ongoing_packet_length_sent += current_size; - return 0; -} - -unsigned int smsc9220_get_rxfifo_data_used_space(void) -{ - unsigned int rxfifo_inf = SMSC9220->RX_FIFO_INF; - return rxfifo_inf & 0xFFFF; -} - -unsigned int smsc9220_receive_by_chunks(char *data, unsigned int dlen) -{ - static unsigned int current_packet_size_words = 0; - unsigned int rxfifo_inf = 0; - unsigned int rxfifo_stat = 0; - unsigned int dlen_word = 0; - unsigned int read_length_word = 0; - unsigned int i = 0; - - if (!data) { - return 0; /* Invalid input parameter */ - } - - if (current_packet_size_words == 0) { - /* First the packet status word should be read, */ - /* which tells the size of the data, */ - /* after the data can be read in synchron. */ - rxfifo_inf = SMSC9220->RX_FIFO_INF; - - if(rxfifo_inf & 0xFFFF) { /* If there's data */ - rxfifo_stat = SMSC9220->RX_STAT_PORT; - if(rxfifo_stat != 0) { /* Fetch status of this packet */ - if(rxfifo_stat & (1 << 15)) { - current_packet_size_words = 0; /* error */ - } - else { - /* Ethernet controller is padding to 32bit aligned data */ - current_packet_size_words = (((rxfifo_stat >> 16) & 0x3FFF) + 3) >> 2; - } - } - } - } - dlen_word = dlen / 4; - read_length_word = (dlen_word < current_packet_size_words) ? dlen_word : current_packet_size_words; - - for (i = 0; i < read_length_word; i++) { - ((unsigned int*)data)[i] = SMSC9220->RX_DATA_PORT; - current_packet_size_words--; - } - return (current_packet_size_words * 4); -} - -unsigned int smsc9220_peek_next_packet_size(void) -{ - unsigned int packet_size = 0; - unsigned int rx_stat_peek = 0; - - if(smsc9220_get_rxfifo_data_used_space()) { - rx_stat_peek = SMSC9220->RX_STAT_PEEK; - packet_size = ((rx_stat_peek >> 16) & 0x3FFF); - } - return (((packet_size + 3) >> 2) << 2); -} - diff --git a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/smsc9220_eth.h b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/smsc9220_eth.h deleted file mode 100644 index 7db5437937..0000000000 --- a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/smsc9220_eth.h +++ /dev/null @@ -1,170 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * - * 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. - */ - -/* This file is the re-implementation of mps2_ethernet_api and Selftest's ETH_MPS2. - * MPS2 Selftest:https://silver.arm.com/browse/VEI10 -> - * \ISCM-1-0\AN491\software\Selftest\v2m_mps2\ - */ -#ifndef _SMSC9220_ETH_H_ -#define _SMSC9220_ETH_H_ - -enum smsc9220_interrupt_source { - enum_smsc9220_interrupt_gpio0 = 0, - enum_smsc9220_interrupt_gpio1 = 1, - enum_smsc9220_interrupt_gpio2 = 2, - enum_smsc9220_interrupt_rxstatus_fifo_level = 3, - enum_smsc9220_interrupt_rxstatus_fifo_full = 4, - /* 5 Reserved according to Datasheet */ - enum_smsc9220_interrupt_rx_dropped_frame = 6, - enum_smsc9220_interrupt_txstatus_fifo_level = 7, - enum_smsc9220_interrupt_txstatus_fifo_full = 8, - enum_smsc9220_interrupt_txdata_fifo_available = 9, - enum_smsc9220_interrupt_txdata_fifo_overrun = 10, - /* 11, 12 Reserved according to Datasheet */ - enum_smsc9220_interrupt_transmit_error = 13, - enum_smsc9220_interrupt_receive_error = 14, - enum_smsc9220_interrupt_receive_watchdog_timeout = 15, - enum_smsc9220_interrupt_txstatus_overflow = 16, - enum_smsc9220_interrupt_power_management = 17, - enum_smsc9220_interrupt_phy = 18, - enum_smsc9220_interrupt_gp_timer = 19, - enum_smsc9220_interrupt_rx_dma = 20, - enum_smsc9220_interrupt_tx_ioc = 21, - /* 22 Reserved according to Datasheet*/ - enum_smsc9220_interrupt_rx_dropped_frame_half = 23, - enum_smsc9220_interrupt_rx_stopped = 24, - enum_smsc9220_interrupt_tx_stopped = 25, - /* 26 - 30 Reserved according to Datasheet*/ - enum_smsc9220_interrupt_sw = 31 -}; - -/* Function declarations */ - -/** - * \brief Initialize SMS9220 Ethernet controller - * - * \return 0 if init is successful, 1 otherwise - */ -int smsc9220_init(void); - -/** - * \brief Enable the given interrupt source. - * - * \param[in] source Enum of the interrupt source. - */ -void smsc9220_enable_interrupt(enum smsc9220_interrupt_source source); - -/** - * \brief Disable the given interrupt source. - * - * \param[in] source Enum of the interrupt source. - */ -void smsc9220_disable_interrupt(enum smsc9220_interrupt_source source); - -/** - * \brief Clear the given interrupt source. - * - * \param[in] source Enum of the interrupt source. - */ -void smsc9220_clear_interrupt(enum smsc9220_interrupt_source source); - -/** - * \brief Get the status of the given interrupt source. - * - * \param[in] source Enum of the interrupt source. - * - * \return non-zero if the given interrupt source is triggered, zero otherwise - */ -int smsc9220_get_interrupt(enum smsc9220_interrupt_source source); - -/** - * \brief Establish link - */ -void smsc9220_establish_link(void); - -/** - * \brief Read MAC address from EEPROM. - * - * \param[in,out] mac array will include the read MAC address in - * 6 bytes hexadecimal format. - * It should be allocated by the caller to 6 bytes. - * - * \return 0 if read is successful, 1 otherwise - */ -int smsc9220_read_mac_address(char *mac); - -/** - * \brief Get the data size of the Tx buffer, aka Maximum Transition Unit - * - * \return Fifo data size in bytes - */ -unsigned int smsc9220_get_tx_data_fifo_size(void); - -/** - * \brief Send Ethernet packet from buffer chain. - * The full packet length should be known in the beginning - * of a new packet. - * - * \param[in] total_packet_length Length of the packet. Should be equal to - * the sum of passed buffers within a packet. - * \param[in] is_new_packet Should be set to non-zero if the passed buffer - * should be sent as the start of a new packet. - * If the current buffer should be sent as a full packet, - * it should be set to non-zero respectively. - * \param[in] data Pointer to the data should be sent. - * \param[in] current_size Size of the data in bytes. - * - * \return 0 if the send process is successful, standard C error code otherwise - */ -int smsc9220_send_by_chunks(unsigned int total_packet_length, int is_new_packet, - const char *data, unsigned int current_size); - -/** - * \brief Receive Ethernet packet from Rx FIFO to the passed buffer. - * Stops reading at packet border. - * If the passed buffer is larger than the current packet, - * the whole packet will be read into the buffer. - * If the current packet is larger than the passed buffer, - * the buffer will be filled with data and the next call - * will continue the read from that point. - * - * \param[in,out] data Pointer where the data will be read to. - * The caller is responsible to allocate it. - * \param[in] dlen Length of the allocated data in bytes. - * - * \return Remaining bytes left in the fifo of the current packet. - */ -unsigned int smsc9220_receive_by_chunks(char *data, unsigned int dlen); - -/** - * \brief Get the used space of Rx fifo in bytes. - * - * \return Data received and waiting for read in bytes - */ -unsigned int smsc9220_get_rxfifo_data_used_space(void); - -/** - * \brief Get the size of next unread packet in Rx buffer, using the peak - * register, which is not destructive so can be read asynchronously. - * Warning: In case of heavy receiving load, it's possible this register - * is not perfectly in sync. - * - * \return Size in bytes of the next packet can be read from Rx fifo, according - * to the peek register. - */ -unsigned int smsc9220_peek_next_packet_size(void); - -#endif diff --git a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/smsc9220_eth_drv.c b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/smsc9220_eth_drv.c new file mode 100644 index 0000000000..b9b6b57fcc --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/smsc9220_eth_drv.c @@ -0,0 +1,1074 @@ +/* + * Copyright (c) 2016-2018 ARM Limited + * + * 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 "cmsis.h" +#include "smsc9220_eth_drv.h" + +/** Setter bit manipulation macro */ +#define SET_BIT(WORD, BIT_INDEX) ((WORD) |= (1U << (BIT_INDEX))) +/** Clearing bit manipulation macro */ +#define CLR_BIT(WORD, BIT_INDEX) ((WORD) &= ~(1U << (BIT_INDEX))) +/** Getter bit manipulation macro */ +#define GET_BIT(WORD, BIT_INDEX) (bool)(((WORD) & (1U << (BIT_INDEX)))) + +/** Setter bit-field manipulation macro */ +#define SET_BIT_FIELD(WORD, BIT_MASK, BIT_OFFSET, VALUE) \ + (WORD |= ((VALUE & BIT_MASK) << BIT_OFFSET)) + +/** Clearing bit-field manipulation macro */ +#define CLR_BIT_FIELD(WORD, BIT_MASK, BIT_OFFSET, VALUE) \ + (WORD &= ~((VALUE & BIT_MASK) << BIT_OFFSET)) + +/** Getter bit-field manipulation macro */ +#define GET_BIT_FIELD(WORD, BIT_MASK, BIT_OFFSET) \ + ((WORD >> BIT_OFFSET) & BIT_MASK) + +/** Millisec timeout macros */ +#define RESET_TIME_OUT_MS 10U +#define REG_WRITE_TIME_OUT_MS 50U +#define PHY_RESET_TIME_OUT_MS 100U +#define INIT_FINISH_DELAY 2000U + +struct smsc9220_eth_reg_map_t { +__I uint32_t rx_data_port; /**< Receive FIFO Ports (offset 0x0) */ + uint32_t reserved1[0x7]; +__O uint32_t tx_data_port; /**< Transmit FIFO Ports (offset 0x20) */ + uint32_t reserved2[0x7]; + +__I uint32_t rx_status_port; /**< Receive FIFO status port (offset 0x40) */ +__I uint32_t rx_status_peek; /**< Receive FIFO status peek (offset 0x44) */ +__I uint32_t tx_status_port; /**< Transmit FIFO status port (offset 0x48) */ +__I uint32_t tx_status_peek; /**< Transmit FIFO status peek (offset 0x4C) */ + +__I uint32_t id_revision; /**< Chip ID and Revision (offset 0x50) */ +__IO uint32_t irq_cfg; /**< Main Interrupt Config (offset 0x54) */ +__IO uint32_t irq_status; /**< Interrupt Status (offset 0x58) */ +__IO uint32_t irq_enable; /**< Interrupt Enable Register (offset 0x5C) */ + uint32_t reserved3; /**< Reserved for future use (offset 0x60) */ +__I uint32_t byte_test; /**< Byte order test 87654321h (offset 0x64) */ +__IO uint32_t fifo_level_irq; /**< FIFO Level Interrupts (offset 0x68) */ +__IO uint32_t rx_cfg; /**< Receive Configuration (offset 0x6C) */ +__IO uint32_t tx_cfg; /**< Transmit Configuration (offset 0x70) */ +__IO uint32_t hw_cfg; /**< Hardware Configuration (offset 0x74) */ +__IO uint32_t rx_datapath_ctrl; /**< RX Datapath Control (offset 0x78) */ +__I uint32_t rx_fifo_inf; /**< Receive FIFO Information (offset 0x7C) */ +__I uint32_t tx_fifo_inf; /**< Transmit FIFO Information (offset 0x80) */ +__IO uint32_t pmt_ctrl; /**< Power Management Control (offset 0x84) */ +__IO uint32_t gpio_cfg; /**< GPIO Configuration (offset 0x88) */ +__IO uint32_t gptimer_cfg; /**< GP Timer Configuration (offset 0x8C) */ +__I uint32_t gptimer_count; /**< GP Timer Count (offset 0x90) */ + uint32_t reserved4; /**< Reserved for future use (offset 0x94) */ +__IO uint32_t word_swap; /**< WORD SWAP Register (offset 0x98) */ +__I uint32_t free_run_counter; /**< Free Run Counter (offset 0x9C) */ +__I uint32_t rx_dropped_frames;/**< RX Dropped Frames Counter (offset 0xA0) */ +__IO uint32_t mac_csr_cmd; /**< MAC CSR Synchronizer Cmd (offset 0xA4) */ +__IO uint32_t mac_csr_data; /**< MAC CSR Synchronizer Data (offset 0xA8) */ +__IO uint32_t afc_cfg; /**< AutomaticFlow Ctrl Config (offset 0xAC) */ +__IO uint32_t eeprom_cmd; /**< EEPROM Command (offset 0xB0) */ +__IO uint32_t eeprom_data; /**< EEPROM Data (offset 0xB4) */ +}; + +/** + * \brief TX FIFO Size definitions + * + */ +#define TX_STATUS_FIFO_SIZE_BYTES 512U /*< fixed allocation in bytes */ +#define TX_DATA_FIFO_SIZE_KBYTES_POS 16U +#define TX_DATA_FIFO_SIZE_KBYTES_MASK 0x0FU +#define KBYTES_TO_BYTES_MULTIPLIER 1024U + +/** + * \brief FIFO Info definitions + * + */ +#define FIFO_USED_SPACE_MASK 0xFFFFU +#define DATA_FIFO_USED_SPACE_POS 0U +#define STATUS_FIFO_USED_SPACE_POS 16U + +/** + * \brief MAC CSR Synchronizer Command bit definitions + * + */ +enum mac_csr_cmd_bits_t{ + MAC_CSR_CMD_RW_INDEX = 30U, + MAC_CSR_CMD_BUSY_INDEX = 31U, +}; + +#define MAC_CSR_CMD_ADDRESS_MASK 0x0FU + +/** + * \brief MAC Control register bit definitions + * + */ +enum mac_reg_cr_bits_t{ + MAC_REG_CR_RXEN_INDEX = 2U, + MAC_REG_CR_TXEN_INDEX = 3U +}; + +/** + * \brief MII Access register bit definitions + * + */ +enum mac_reg_mii_acc_bits_t{ + MAC_REG_MII_ACC_BUSY_INDEX = 0U, + MAC_REG_MII_ACC_WRITE_INDEX = 1U, + MAC_REG_MII_ACC_PHYADDR_INDEX = 11U +}; +#define MAC_REG_MII_ACC_MII_REG_MASK 0x1FU +#define MAC_REG_MII_ACC_MII_REG_OFFSET 6U + +/** + * \brief Hardware config register bit definitions + * + */ +enum hw_cfg_reg_bits_t{ + HW_CFG_REG_SRST_INDEX = 0U, + HW_CFG_REG_SRST_TIMEOUT_INDEX = 1U, + HW_CFG_REG_MUST_BE_ONE_INDEX = 20U, +}; +#define HW_CFG_REG_TX_FIFO_SIZE_POS 16U +#define HW_CFG_REG_TX_FIFO_SIZE_MIN 2U /*< Min Tx fifo size in KB */ +#define HW_CFG_REG_TX_FIFO_SIZE_MAX 14U /*< Max Tx fifo size in KB */ +#define HW_CFG_REG_TX_FIFO_SIZE 5U /*< Tx fifo size in KB */ + +/** + * \brief EEPROM command register bit definitions + * + */ +enum eeprom_cmd_reg_bits_t{ + EEPROM_CMD_REG_BUSY_INDEX = 31U, +}; + +/** + * \brief PHY Basic Control register bit definitions + * + */ +enum phy_reg_bctrl_reg_bits_t{ + PHY_REG_BCTRL_RST_AUTO_NEG_INDEX = 9U, + PHY_REG_BCTRL_AUTO_NEG_EN_INDEX = 12U, + PHY_REG_BCTRL_RESET_INDEX = 15U +}; + +/** + * \brief TX Command A bit definitions + * + */ + +#define TX_CMD_DATA_START_OFFSET_BYTES_POS 16U +#define TX_CMD_DATA_START_OFFSET_BYTES_MASK 0x1FU + + +enum tx_command_a_bits_t{ + TX_COMMAND_A_LAST_SEGMENT_INDEX = 12U, + TX_COMMAND_A_FIRST_SEGMENT_INDEX = 13U +}; + +#define TX_CMD_PKT_LEN_BYTES_MASK 0x7FFU +#define TX_CMD_PKT_TAG_MASK 0xFFFFU +#define TX_CMD_PKT_TAG_POS 16U + + +/** + * \brief RX Fifo Status bit definitions + * + */ +enum rx_fifo_status_bits_t{ + RX_FIFO_STATUS_ERROR_INDEX = 15U +}; +#define RX_FIFO_STATUS_PKT_LENGTH_POS 16U +#define RX_FIFO_STATUS_PKT_LENGTH_MASK 0x3FFFU + +/** + * \brief Interrupt Configuration register bit definitions + * + */ +enum irq_cfg_bits_t{ + IRQ_CFG_IRQ_EN_INDEX = 8U +}; + +#define IRQ_CFG_INT_DEAS_MASK 0xFFU +#define IRQ_CFG_INT_DEAS_POS 24U +#define IRQ_CFG_INT_DEAS_10US 0x22U + +/** + * \brief Automatic Flow Control register bit definitions + * + */ +enum afc_bits_t{ + AFC_ANY_INDEX = 0U, + AFC_ADDR_INDEX = 1U, + AFC_BROADCAST_INDEX = 2U, + AFC_MULTICAST_INDEX = 3U +}; + +#define AFC_BACK_DUR_MASK 0x0FU +#define AFC_BACK_DUR_POS 4U +#define AFC_BACK_DUR 4U /**< equal to 50us */ + +#define AFC_LOW_LEVEL_MASK 0xFFU +#define AFC_LOW_LEVEL_POS 8U +#define AFC_LOW_LEVEL 55U /**< specifies in multiple of 64 bytes */ + +#define AFC_HIGH_LEVEL_MASK 0xFFU +#define AFC_HIGH_LEVEL_POS 16U +#define AFC_HIGH_LEVEL 110U /**< specifies in multiple of 64 bytes */ + +/** + * \brief Auto-Negotiation Advertisement register bit definitions + * + */ +enum aneg_bits_t{ + ANEG_10_BASE_T_INDEX = 5U, /**< 10Mbps able */ + ANEG_10_BASE_T_FULL_DUPL_INDEX = 6U, /**< 10Mbps with full duplex */ + ANEG_100_BASE_TX_INDEX = 7U, /**< 100Mbps Tx able */ + ANEG_100_BASE_TX_FULL_DUPL_INDEX = 8U, /**< 100Mbps with full duplex */ + ANEG_SYMM_PAUSE_INDEX = 10U, /**< Symmetric Pause */ + ANEG_ASYMM_PAUSE_INDEX = 11U /**< Asymmetric Pause */ +}; + +/** + * \brief Transmit Configuration register bit definitions + * + */ +enum tx_cfg_bits_t{ + TX_CFG_STOP_INDEX = 0U, /*< stop */ + TX_CFG_ON_INDEX = 1U, /*< on */ + TX_CFG_AO_INDEX = 2U, /*< allow overrun */ + TX_CFG_TXD_DUMP_INDEX = 14U, /*< Data FIFO dump */ + TX_CFG_TXS_DUMP_INDEX = 15U /*< Status FIFO dump */ +}; + +/** + * \brief Chip ID definitions + * + */ +#define CHIP_ID 0x9220U +#define CHIP_ID_MASK 0xFFFFU +#define CHIP_ID_POS 16U + +/** + * \brief GPIO Configuration register bit definitions + * + */ +enum gpio_cfg_bits_t{ + GPIO_CFG_GPIO0_PUSHPULL_INDEX = 16U, /*< GPIO0 push/pull or open-drain */ + GPIO_CFG_GPIO1_PUSHPULL_INDEX = 17U, /*< GPIO1 push/pull or open-drain */ + GPIO_CFG_GPIO2_PUSHPULL_INDEX = 18U, /*< GPIO2 push/pull or open-drain */ + GPIO_CFG_GPIO0_LED_INDEX = 28U, /*< GPIO0 set to LED1 */ + GPIO_CFG_GPIO1_LED_INDEX = 29U, /*< GPIO1 set to LED2 */ + GPIO_CFG_GPIO2_LED_INDEX = 30U /*< GPIO2 set to LED3 */ +}; + + +static void fill_tx_fifo(const struct smsc9220_eth_dev_t* dev, + uint8_t *data, uint32_t size_bytes) +{ + struct smsc9220_eth_reg_map_t* register_map = + (struct smsc9220_eth_reg_map_t*)dev->cfg->base; + + uint32_t tx_data_port_tmp = 0; + uint8_t *tx_data_port_tmp_ptr = (uint8_t *)&tx_data_port_tmp; + + /*If the data length is not a multiple of 4, then the beginning of the first + * DWORD of the TX DATA FIFO gets filled up with zeros and a byte offset is + * set accordingly to guarantee proper transmission.*/ + uint32_t remainder_bytes = (size_bytes % 4); + uint32_t filler_bytes = (4 - remainder_bytes); + for(uint32_t i = 0; i < 4; i++){ + if(i < filler_bytes){ + tx_data_port_tmp_ptr[i] = 0; + } else { + tx_data_port_tmp_ptr[i] = data[i-filler_bytes]; + } + } + register_map->tx_data_port = tx_data_port_tmp; + size_bytes -= remainder_bytes; + data += remainder_bytes; + + while (size_bytes > 0) { + /* Keep the same endianness in data than in the temp variable */ + tx_data_port_tmp_ptr[0] = data[0]; + tx_data_port_tmp_ptr[1] = data[1]; + tx_data_port_tmp_ptr[2] = data[2]; + tx_data_port_tmp_ptr[3] = data[3]; + register_map->tx_data_port = tx_data_port_tmp; + data += 4; + size_bytes -= 4; + } +} + +static void empty_rx_fifo(const struct smsc9220_eth_dev_t* dev, + uint8_t *data, uint32_t size_bytes) +{ + struct smsc9220_eth_reg_map_t* register_map = + (struct smsc9220_eth_reg_map_t*)dev->cfg->base; + + uint32_t rx_data_port_tmp = 0; + uint8_t *rx_data_port_tmp_ptr = (uint8_t *)&rx_data_port_tmp; + + uint32_t remainder_bytes = (size_bytes % 4); + size_bytes -= remainder_bytes; + + while (size_bytes > 0) { + /* Keep the same endianness in data than in the temp variable */ + rx_data_port_tmp = register_map->rx_data_port; + data[0] = rx_data_port_tmp_ptr[0]; + data[1] = rx_data_port_tmp_ptr[1]; + data[2] = rx_data_port_tmp_ptr[2]; + data[3] = rx_data_port_tmp_ptr[3]; + data += 4; + size_bytes -= 4; + } + + rx_data_port_tmp = register_map->rx_data_port; + for(uint32_t i = 0; i < remainder_bytes; i++) { + data[i] = rx_data_port_tmp_ptr[i]; + } +} + +enum smsc9220_error_t smsc9220_mac_regread( + const struct smsc9220_eth_dev_t* dev, + enum smsc9220_mac_reg_offsets_t regoffset, + uint32_t *data) +{ + volatile uint32_t val; + uint32_t maccmd = GET_BIT_FIELD(regoffset, + MAC_CSR_CMD_ADDRESS_MASK, 0); + uint32_t time_out = REG_WRITE_TIME_OUT_MS; + + struct smsc9220_eth_reg_map_t* register_map = + (struct smsc9220_eth_reg_map_t*)dev->cfg->base; + + /* Make sure there's no pending operation */ + if(!(GET_BIT(register_map->mac_csr_cmd, MAC_CSR_CMD_BUSY_INDEX))) { + SET_BIT(maccmd, MAC_CSR_CMD_RW_INDEX); + SET_BIT(maccmd, MAC_CSR_CMD_BUSY_INDEX); + register_map->mac_csr_cmd = maccmd; /* Start operation */ + + do { + val = register_map->byte_test; /* A no-op read. */ + (void)val; + if (dev->data->wait_ms) { + dev->data->wait_ms(1); + } + time_out--; + } while(time_out && + GET_BIT(register_map->mac_csr_cmd,MAC_CSR_CMD_BUSY_INDEX)); + + if(!time_out) { + return SMSC9220_ERROR_TIMEOUT; + } + else { + *data = register_map->mac_csr_data; + } + } else { + return SMSC9220_ERROR_BUSY; + } + return SMSC9220_ERROR_NONE; +} + +enum smsc9220_error_t smsc9220_mac_regwrite( + const struct smsc9220_eth_dev_t* dev, + enum smsc9220_mac_reg_offsets_t regoffset, + uint32_t data) +{ + volatile uint32_t read = 0; + uint32_t maccmd = GET_BIT_FIELD(regoffset, + MAC_CSR_CMD_ADDRESS_MASK, 0); + uint32_t time_out = REG_WRITE_TIME_OUT_MS; + + struct smsc9220_eth_reg_map_t* register_map = + (struct smsc9220_eth_reg_map_t*)dev->cfg->base; + + /* Make sure there's no pending operation */ + if(!GET_BIT(register_map->mac_csr_cmd, MAC_CSR_CMD_BUSY_INDEX)) { + register_map->mac_csr_data = data; /* Store data. */ + CLR_BIT(maccmd, MAC_CSR_CMD_RW_INDEX); + SET_BIT(maccmd, MAC_CSR_CMD_BUSY_INDEX); + register_map->mac_csr_cmd = maccmd; + + do { + read = register_map->byte_test; /* A no-op read. */ + (void)read; + if (dev->data->wait_ms) { + dev->data->wait_ms(1); + } + time_out--; + } while(time_out && + (register_map->mac_csr_cmd & + GET_BIT(register_map->mac_csr_cmd, MAC_CSR_CMD_BUSY_INDEX))); + + if(!time_out) { + return SMSC9220_ERROR_TIMEOUT; + } + } else { + return SMSC9220_ERROR_BUSY; + } + return SMSC9220_ERROR_NONE; +} + +enum smsc9220_error_t smsc9220_phy_regread( + const struct smsc9220_eth_dev_t* dev, + enum phy_reg_offsets_t regoffset, + uint32_t *data) +{ + uint32_t val = 0; + uint32_t phycmd = 0; + uint32_t time_out = REG_WRITE_TIME_OUT_MS; + + if (smsc9220_mac_regread(dev, SMSC9220_MAC_REG_OFFSET_MII_ACC, &val)) { + return SMSC9220_ERROR_INTERNAL; + } + + if(!GET_BIT(val, MAC_REG_MII_ACC_BUSY_INDEX)) { + phycmd = 0; + SET_BIT(phycmd, MAC_REG_MII_ACC_PHYADDR_INDEX); + SET_BIT_FIELD(phycmd, MAC_REG_MII_ACC_MII_REG_MASK, + MAC_REG_MII_ACC_MII_REG_OFFSET, regoffset); + CLR_BIT(phycmd, MAC_REG_MII_ACC_WRITE_INDEX); + SET_BIT(phycmd, MAC_REG_MII_ACC_BUSY_INDEX); + + if (smsc9220_mac_regwrite(dev, SMSC9220_MAC_REG_OFFSET_MII_ACC, + phycmd)) { + return SMSC9220_ERROR_INTERNAL; + } + + val = 0; + do { + if (dev->data->wait_ms) { + dev->data->wait_ms(1); + } + time_out--; + if (smsc9220_mac_regread(dev, SMSC9220_MAC_REG_OFFSET_MII_ACC, + &val)) { + return SMSC9220_ERROR_INTERNAL; + } + } while(time_out && (GET_BIT(val, MAC_REG_MII_ACC_BUSY_INDEX))); + + if (!time_out) { + return SMSC9220_ERROR_TIMEOUT; + } else if (smsc9220_mac_regread(dev, SMSC9220_MAC_REG_OFFSET_MII_DATA, + data)) { + return SMSC9220_ERROR_INTERNAL; + } + } else { + return SMSC9220_ERROR_BUSY; + } + return SMSC9220_ERROR_NONE; +} + +enum smsc9220_error_t smsc9220_phy_regwrite( + const struct smsc9220_eth_dev_t* dev, + enum phy_reg_offsets_t regoffset, + uint32_t data) +{ + uint32_t val = 0; + uint32_t phycmd = 0; + uint32_t time_out = REG_WRITE_TIME_OUT_MS; + + if (smsc9220_mac_regread(dev, SMSC9220_MAC_REG_OFFSET_MII_ACC, &val)) { + return SMSC9220_ERROR_INTERNAL; + } + + if(!GET_BIT(val, MAC_REG_MII_ACC_BUSY_INDEX)) { + /* Load the data */ + if (smsc9220_mac_regwrite(dev, SMSC9220_MAC_REG_OFFSET_MII_DATA, + (data & 0xFFFF))) { + return SMSC9220_ERROR_INTERNAL; + } + phycmd = 0; + SET_BIT(phycmd, MAC_REG_MII_ACC_PHYADDR_INDEX); + SET_BIT_FIELD(phycmd, MAC_REG_MII_ACC_MII_REG_MASK, + MAC_REG_MII_ACC_MII_REG_OFFSET, regoffset); + SET_BIT(phycmd, MAC_REG_MII_ACC_WRITE_INDEX); + SET_BIT(phycmd, MAC_REG_MII_ACC_BUSY_INDEX); + /* Start operation */ + if (smsc9220_mac_regwrite(dev, SMSC9220_MAC_REG_OFFSET_MII_ACC, + phycmd)) { + return SMSC9220_ERROR_INTERNAL; + } + + phycmd = 0; + + do { + if (dev->data->wait_ms) { + dev->data->wait_ms(1); + } + time_out--; + if (smsc9220_mac_regread(dev, SMSC9220_MAC_REG_OFFSET_MII_ACC, + &phycmd)){ + return SMSC9220_ERROR_INTERNAL; + } + } while(time_out && GET_BIT(phycmd, 0)); + + if (!time_out) { + return SMSC9220_ERROR_TIMEOUT; + } + + } else { + return SMSC9220_ERROR_BUSY; + } + return SMSC9220_ERROR_NONE; +} + +uint32_t smsc9220_read_id(const struct smsc9220_eth_dev_t* dev) +{ + struct smsc9220_eth_reg_map_t* register_map = + (struct smsc9220_eth_reg_map_t*)dev->cfg->base; + + return register_map->id_revision; +} + +enum smsc9220_error_t smsc9220_soft_reset( + const struct smsc9220_eth_dev_t* dev) +{ + uint32_t time_out = RESET_TIME_OUT_MS; + + struct smsc9220_eth_reg_map_t* register_map = + (struct smsc9220_eth_reg_map_t*)dev->cfg->base; + + /* Soft reset */ + SET_BIT(register_map->hw_cfg, HW_CFG_REG_SRST_INDEX); + + do { + if (dev->data->wait_ms) { + dev->data->wait_ms(1); + } + time_out--; + } while(time_out && + GET_BIT(register_map->hw_cfg, HW_CFG_REG_SRST_TIMEOUT_INDEX)); + + if (!time_out) { + return SMSC9220_ERROR_TIMEOUT; + } + + return SMSC9220_ERROR_NONE; +} + +void smsc9220_set_txfifo(const struct smsc9220_eth_dev_t* dev, + uint32_t val) +{ + struct smsc9220_eth_reg_map_t* register_map = + (struct smsc9220_eth_reg_map_t*)dev->cfg->base; + + if(val >= HW_CFG_REG_TX_FIFO_SIZE_MIN && + val <= HW_CFG_REG_TX_FIFO_SIZE_MAX) { + register_map->hw_cfg = val << HW_CFG_REG_TX_FIFO_SIZE_POS; + } +} + +enum smsc9220_error_t smsc9220_set_fifo_level_irq( + const struct smsc9220_eth_dev_t* dev, + enum smsc9220_fifo_level_irq_pos_t irq_level_pos, + uint32_t level) +{ + struct smsc9220_eth_reg_map_t* register_map = + (struct smsc9220_eth_reg_map_t*)dev->cfg->base; + + if (level < SMSC9220_FIFO_LEVEL_IRQ_LEVEL_MIN || + level > SMSC9220_FIFO_LEVEL_IRQ_LEVEL_MAX) { + return SMSC9220_ERROR_PARAM; + } + + CLR_BIT_FIELD(register_map->fifo_level_irq, SMSC9220_FIFO_LEVEL_IRQ_MASK, + irq_level_pos, SMSC9220_FIFO_LEVEL_IRQ_MASK); + SET_BIT_FIELD(register_map->fifo_level_irq, SMSC9220_FIFO_LEVEL_IRQ_MASK, + irq_level_pos, level); + return SMSC9220_ERROR_NONE; +} + +enum smsc9220_error_t smsc9220_wait_eeprom( + const struct smsc9220_eth_dev_t* dev) +{ + uint32_t time_out = REG_WRITE_TIME_OUT_MS; + + struct smsc9220_eth_reg_map_t* register_map = + (struct smsc9220_eth_reg_map_t*)dev->cfg->base; + + do { + if (dev->data->wait_ms) { + dev->data->wait_ms(1); + } + time_out--; + } while(time_out && + GET_BIT(register_map->eeprom_cmd, EEPROM_CMD_REG_BUSY_INDEX)); + + if (!time_out) { + return SMSC9220_ERROR_TIMEOUT; + } + + return SMSC9220_ERROR_NONE; +} + +void smsc9220_init_irqs(const struct smsc9220_eth_dev_t* dev) +{ + struct smsc9220_eth_reg_map_t* register_map = + (struct smsc9220_eth_reg_map_t*)dev->cfg->base; + + smsc9220_disable_all_interrupts(dev); + smsc9220_clear_all_interrupts(dev); + + /* Set IRQ deassertion interval */ + SET_BIT_FIELD(register_map->irq_cfg, IRQ_CFG_INT_DEAS_MASK, + IRQ_CFG_INT_DEAS_POS, IRQ_CFG_INT_DEAS_10US); + + /* enable interrupts */ + SET_BIT(register_map->irq_cfg, IRQ_CFG_IRQ_EN_INDEX); +} + +enum smsc9220_error_t smsc9220_check_phy(const struct smsc9220_eth_dev_t* dev) +{ + uint32_t phyid1 = 0; + uint32_t phyid2 = 0; + + if (smsc9220_phy_regread(dev, SMSC9220_PHY_REG_OFFSET_ID1,&phyid1)) { + return SMSC9220_ERROR_INTERNAL; + } + if (smsc9220_phy_regread(dev, SMSC9220_PHY_REG_OFFSET_ID2,&phyid2)) { + return SMSC9220_ERROR_INTERNAL; + } + if ((phyid1 == 0xFFFF && phyid2 == 0xFFFF) || + (phyid1 == 0x0 && phyid2 == 0x0)) { + return SMSC9220_ERROR_INTERNAL; + } + return SMSC9220_ERROR_NONE; +} + +enum smsc9220_error_t smsc9220_reset_phy(const struct smsc9220_eth_dev_t* dev) +{ + uint32_t read = 0; + + if(smsc9220_phy_regread(dev, SMSC9220_PHY_REG_OFFSET_BCTRL, &read)) { + return SMSC9220_ERROR_INTERNAL; + } + + SET_BIT(read, PHY_REG_BCTRL_RESET_INDEX); + if(smsc9220_phy_regwrite(dev, SMSC9220_PHY_REG_OFFSET_BCTRL, read)) { + return SMSC9220_ERROR_INTERNAL; + } + return SMSC9220_ERROR_NONE; +} + +void smsc9220_advertise_cap(const struct smsc9220_eth_dev_t* dev) +{ + uint32_t aneg_adv = 0; + smsc9220_phy_regread(dev, SMSC9220_PHY_REG_OFFSET_ANEG_ADV, &aneg_adv); + + SET_BIT(aneg_adv, ANEG_10_BASE_T_INDEX); + SET_BIT(aneg_adv, ANEG_10_BASE_T_FULL_DUPL_INDEX); + SET_BIT(aneg_adv, ANEG_100_BASE_TX_INDEX); + SET_BIT(aneg_adv, ANEG_100_BASE_TX_FULL_DUPL_INDEX); + SET_BIT(aneg_adv, ANEG_SYMM_PAUSE_INDEX); + SET_BIT(aneg_adv, ANEG_ASYMM_PAUSE_INDEX); + + smsc9220_phy_regwrite(dev, SMSC9220_PHY_REG_OFFSET_ANEG_ADV, aneg_adv); +} + +void smsc9220_enable_xmit(const struct smsc9220_eth_dev_t* dev) +{ + struct smsc9220_eth_reg_map_t* register_map = + (struct smsc9220_eth_reg_map_t*)dev->cfg->base; + + SET_BIT(register_map->tx_cfg, TX_CFG_ON_INDEX); +} + +void smsc9220_disable_xmit(const struct smsc9220_eth_dev_t* dev) +{ + struct smsc9220_eth_reg_map_t* register_map = + (struct smsc9220_eth_reg_map_t*)dev->cfg->base; + + CLR_BIT(register_map->tx_cfg, TX_CFG_ON_INDEX); +} + +void smsc9220_enable_mac_xmit(const struct smsc9220_eth_dev_t* dev) +{ + uint32_t mac_cr = 0; + smsc9220_mac_regread(dev, SMSC9220_MAC_REG_OFFSET_CR, &mac_cr); + + SET_BIT(mac_cr, MAC_REG_CR_TXEN_INDEX); + + smsc9220_mac_regwrite(dev, SMSC9220_MAC_REG_OFFSET_CR, mac_cr); +} + +void smsc9220_disable_mac_xmit(const struct smsc9220_eth_dev_t* dev) +{ + uint32_t mac_cr = 0; + smsc9220_mac_regread(dev, SMSC9220_MAC_REG_OFFSET_CR, &mac_cr); + + CLR_BIT(mac_cr, MAC_REG_CR_TXEN_INDEX); + + smsc9220_mac_regwrite(dev, SMSC9220_MAC_REG_OFFSET_CR, mac_cr); +} + +void smsc9220_enable_mac_recv(const struct smsc9220_eth_dev_t* dev) +{ + uint32_t mac_cr = 0; + smsc9220_mac_regread(dev, SMSC9220_MAC_REG_OFFSET_CR, &mac_cr); + + SET_BIT(mac_cr, MAC_REG_CR_RXEN_INDEX); + + smsc9220_mac_regwrite(dev, SMSC9220_MAC_REG_OFFSET_CR, mac_cr); +} + +void smsc9220_disable_mac_recv(const struct smsc9220_eth_dev_t* dev) +{ + uint32_t mac_cr = 0; + smsc9220_mac_regread(dev, SMSC9220_MAC_REG_OFFSET_CR, &mac_cr); + + CLR_BIT(mac_cr, MAC_REG_CR_RXEN_INDEX); + + smsc9220_mac_regwrite(dev, SMSC9220_MAC_REG_OFFSET_CR, mac_cr); +} + +int smsc9220_check_id(const struct smsc9220_eth_dev_t* dev) +{ + uint32_t id = smsc9220_read_id(dev); + + return ((GET_BIT_FIELD(id, CHIP_ID_MASK, CHIP_ID_POS) == CHIP_ID) ? 0 : 1); +} + + +void smsc9220_enable_interrupt(const struct smsc9220_eth_dev_t* dev, + enum smsc9220_interrupt_source source) +{ + struct smsc9220_eth_reg_map_t* register_map = + (struct smsc9220_eth_reg_map_t*)dev->cfg->base; + + SET_BIT(register_map->irq_enable, source); +} + +void smsc9220_disable_interrupt(const struct smsc9220_eth_dev_t* dev, + enum smsc9220_interrupt_source source) +{ + struct smsc9220_eth_reg_map_t* register_map = + (struct smsc9220_eth_reg_map_t*)dev->cfg->base; + + CLR_BIT(register_map->irq_enable, source); +} + +void smsc9220_disable_all_interrupts(const struct smsc9220_eth_dev_t* dev) +{ + struct smsc9220_eth_reg_map_t* register_map = + (struct smsc9220_eth_reg_map_t*)dev->cfg->base; + + register_map->irq_enable = 0; +} + +void smsc9220_clear_interrupt(const struct smsc9220_eth_dev_t* dev, + enum smsc9220_interrupt_source source) +{ + struct smsc9220_eth_reg_map_t* register_map = + (struct smsc9220_eth_reg_map_t*)dev->cfg->base; + + SET_BIT(register_map->irq_status, source); +} + +void smsc9220_clear_all_interrupts(const struct smsc9220_eth_dev_t* dev) +{ + struct smsc9220_eth_reg_map_t* register_map = + (struct smsc9220_eth_reg_map_t*)dev->cfg->base; + + register_map->irq_status = UINT32_MAX; +} + +int smsc9220_get_interrupt(const struct smsc9220_eth_dev_t* dev, + enum smsc9220_interrupt_source source) +{ + struct smsc9220_eth_reg_map_t* register_map = + (struct smsc9220_eth_reg_map_t*)dev->cfg->base; + + return GET_BIT(register_map->irq_status, source); +} + +void smsc9220_establish_link(const struct smsc9220_eth_dev_t* dev) +{ + uint32_t bcr = 0; + struct smsc9220_eth_reg_map_t* register_map = + (struct smsc9220_eth_reg_map_t*)dev->cfg->base; + + smsc9220_phy_regread(dev, SMSC9220_PHY_REG_OFFSET_BCTRL, &bcr); + SET_BIT(bcr, PHY_REG_BCTRL_AUTO_NEG_EN_INDEX); + SET_BIT(bcr, PHY_REG_BCTRL_RST_AUTO_NEG_INDEX); + smsc9220_phy_regwrite(dev, SMSC9220_PHY_REG_OFFSET_BCTRL, bcr); + + SET_BIT(register_map->hw_cfg, HW_CFG_REG_MUST_BE_ONE_INDEX); +} + +enum smsc9220_error_t smsc9220_read_mac_address( + const struct smsc9220_eth_dev_t* dev, char *mac) +{ + uint32_t mac_low = 0; + uint32_t mac_high = 0; + + if(!mac) { + return SMSC9220_ERROR_PARAM; + } + + /* Read current mac address. */ + if (smsc9220_mac_regread(dev, SMSC9220_MAC_REG_OFFSET_ADDRH, &mac_high)) { + return SMSC9220_ERROR_INTERNAL; + } + if (smsc9220_mac_regread(dev, SMSC9220_MAC_REG_OFFSET_ADDRL, &mac_low)) { + return SMSC9220_ERROR_INTERNAL; + } + mac[0] = mac_low & 0xFF; + mac[1] = (mac_low >> 8) & 0xFF; + mac[2] = (mac_low >> 16) & 0xFF; + mac[3] = (mac_low >> 24) & 0xFF; + mac[4] = mac_high & 0xFF; + mac[5] = (mac_high >> 8) & 0xFF; + + return SMSC9220_ERROR_NONE; +} + +uint32_t smsc9220_get_tx_data_fifo_size( + const struct smsc9220_eth_dev_t* dev) +{ + struct smsc9220_eth_reg_map_t* register_map = + (struct smsc9220_eth_reg_map_t*)dev->cfg->base; + + uint32_t tx_fifo_size = + GET_BIT_FIELD(register_map->hw_cfg, + TX_DATA_FIFO_SIZE_KBYTES_MASK, + TX_DATA_FIFO_SIZE_KBYTES_POS) * KBYTES_TO_BYTES_MULTIPLIER; + + return (tx_fifo_size - TX_STATUS_FIFO_SIZE_BYTES); +} + +enum smsc9220_error_t smsc9220_init( + const struct smsc9220_eth_dev_t* dev, + void(* wait_ms_function)(int)) +{ + uint32_t phyreset = 0; + enum smsc9220_error_t error = SMSC9220_ERROR_NONE; + struct smsc9220_eth_reg_map_t* register_map = + (struct smsc9220_eth_reg_map_t*)dev->cfg->base; + + if (!wait_ms_function) { + return SMSC9220_ERROR_PARAM; + } + dev->data->wait_ms = wait_ms_function; + + error = smsc9220_check_id(dev); + if(error != SMSC9220_ERROR_NONE) { + return error; + } + + error = smsc9220_soft_reset(dev); + if(error != SMSC9220_ERROR_NONE) { + return error; + } + + smsc9220_set_txfifo(dev, HW_CFG_REG_TX_FIFO_SIZE); + + SET_BIT_FIELD(register_map->afc_cfg, AFC_BACK_DUR_MASK, + AFC_BACK_DUR_POS, AFC_BACK_DUR); + SET_BIT_FIELD(register_map->afc_cfg, AFC_LOW_LEVEL_MASK, + AFC_LOW_LEVEL_POS, AFC_LOW_LEVEL); + SET_BIT_FIELD(register_map->afc_cfg, AFC_HIGH_LEVEL_MASK, + AFC_HIGH_LEVEL_POS, AFC_HIGH_LEVEL); + + error = smsc9220_wait_eeprom(dev); + if(error != SMSC9220_ERROR_NONE) { + return error; + } + + /* Configure GPIOs as LED outputs. */ + register_map->gpio_cfg = 0; + SET_BIT(register_map->gpio_cfg, GPIO_CFG_GPIO0_PUSHPULL_INDEX); + SET_BIT(register_map->gpio_cfg, GPIO_CFG_GPIO1_PUSHPULL_INDEX); + SET_BIT(register_map->gpio_cfg, GPIO_CFG_GPIO2_PUSHPULL_INDEX); + SET_BIT(register_map->gpio_cfg, GPIO_CFG_GPIO0_LED_INDEX); + SET_BIT(register_map->gpio_cfg, GPIO_CFG_GPIO1_LED_INDEX); + SET_BIT(register_map->gpio_cfg, GPIO_CFG_GPIO2_LED_INDEX); + + smsc9220_init_irqs(dev); + + /* Configure MAC addresses here if needed. */ + + error = smsc9220_check_phy(dev); + if(error != SMSC9220_ERROR_NONE) { + return error; + } + + error = smsc9220_reset_phy(dev); + if(error != SMSC9220_ERROR_NONE) { + return error; + } + + if (dev->data->wait_ms) { + dev->data->wait_ms(PHY_RESET_TIME_OUT_MS); + } + /* Checking whether phy reset completed successfully.*/ + error = smsc9220_phy_regread(dev, SMSC9220_PHY_REG_OFFSET_BCTRL, + &phyreset); + if(error != SMSC9220_ERROR_NONE) { + return error; + } + + if(GET_BIT(phyreset, PHY_REG_BCTRL_RESET_INDEX)) { + return SMSC9220_ERROR_INTERNAL; + } + + smsc9220_advertise_cap(dev); + smsc9220_establish_link(dev); + + smsc9220_enable_mac_xmit(dev); + smsc9220_enable_xmit(dev); + smsc9220_enable_mac_recv(dev); + + /* This sleep is compulsory otherwise txmit/receive will fail. */ + if (dev->data->wait_ms) { + dev->data->wait_ms(INIT_FINISH_DELAY); + } + dev->data->state = 1; + + return SMSC9220_ERROR_NONE; +} + +enum smsc9220_error_t smsc9220_send_by_chunks( + const struct smsc9220_eth_dev_t* dev, + uint32_t total_payload_length, + bool is_new_packet, + const char *data, uint32_t current_size) +{ + struct smsc9220_eth_reg_map_t* register_map = + (struct smsc9220_eth_reg_map_t*)dev->cfg->base; + + /* signing this is the first segment of the packet to be sent */ + bool is_first_segment = false; + /* signing this is the last segment of the packet to be sent */ + bool is_last_segment = false; + uint32_t txcmd_a, txcmd_b = 0; + uint32_t tx_buffer_free_space = 0; + volatile uint32_t xmit_stat = 0; + + if (!data) { + return SMSC9220_ERROR_PARAM; + } + + if (is_new_packet) { + is_first_segment = true; + dev->data->ongoing_packet_length = total_payload_length; + dev->data->ongoing_packet_length_sent = 0; + } else if (dev->data->ongoing_packet_length != total_payload_length || + dev->data->ongoing_packet_length_sent >= total_payload_length) { + return SMSC9220_ERROR_PARAM; + } + + /* Would next chunk fit into buffer? */ + tx_buffer_free_space = GET_BIT_FIELD(register_map->tx_fifo_inf, + FIFO_USED_SPACE_MASK, + DATA_FIFO_USED_SPACE_POS); + if (current_size > tx_buffer_free_space) { + return SMSC9220_ERROR_INTERNAL; /* Not enough space in FIFO */ + } + if ((dev->data->ongoing_packet_length_sent + current_size) == + total_payload_length) { + is_last_segment = true; + } + + txcmd_a = 0; + txcmd_b = 0; + + if (is_last_segment) { + SET_BIT(txcmd_a, TX_COMMAND_A_LAST_SEGMENT_INDEX); + } + if (is_first_segment) { + SET_BIT(txcmd_a, TX_COMMAND_A_FIRST_SEGMENT_INDEX); + } + + uint32_t data_start_offset_bytes = (4 - (current_size % 4)); + + SET_BIT_FIELD(txcmd_a, TX_CMD_PKT_LEN_BYTES_MASK, 0, current_size); + SET_BIT_FIELD(txcmd_a, TX_CMD_DATA_START_OFFSET_BYTES_MASK, + TX_CMD_DATA_START_OFFSET_BYTES_POS, + data_start_offset_bytes); + + SET_BIT_FIELD(txcmd_b, TX_CMD_PKT_LEN_BYTES_MASK, 0, current_size); + SET_BIT_FIELD(txcmd_b, TX_CMD_PKT_TAG_MASK, TX_CMD_PKT_TAG_POS, + current_size); + + register_map->tx_data_port = txcmd_a; + register_map->tx_data_port = txcmd_b; + + fill_tx_fifo(dev, (uint8_t *)data, current_size); + + if (is_last_segment) { + /* Pop status port for error check */ + xmit_stat = register_map->tx_status_port; + (void)xmit_stat; + } + dev->data->ongoing_packet_length_sent += current_size; + return SMSC9220_ERROR_NONE; +} + +uint32_t smsc9220_get_rxfifo_data_used_space(const struct + smsc9220_eth_dev_t* dev) +{ + struct smsc9220_eth_reg_map_t* register_map = + (struct smsc9220_eth_reg_map_t*)dev->cfg->base; + + return GET_BIT_FIELD(register_map->rx_fifo_inf, FIFO_USED_SPACE_MASK, + DATA_FIFO_USED_SPACE_POS); +} + +uint32_t smsc9220_receive_by_chunks(const struct smsc9220_eth_dev_t* dev, + char *data, uint32_t dlen) +{ + + uint32_t rxfifo_inf = 0; + uint32_t rxfifo_stat = 0; + uint32_t packet_length_byte = 0; + struct smsc9220_eth_reg_map_t* register_map = + (struct smsc9220_eth_reg_map_t*)dev->cfg->base; + + if (!data) { + return 0; /* Invalid input parameter, cannot read */ + } + rxfifo_inf = register_map->rx_fifo_inf; + + if(rxfifo_inf & 0xFFFF) { /* If there's data */ + rxfifo_stat = register_map->rx_status_port; + if(rxfifo_stat != 0) { /* Fetch status of this packet */ + /* Ethernet controller is padding to 32bit aligned data */ + packet_length_byte = GET_BIT_FIELD(rxfifo_stat, + RX_FIFO_STATUS_PKT_LENGTH_MASK, + RX_FIFO_STATUS_PKT_LENGTH_POS); + packet_length_byte -= 4; + dev->data->current_rx_size_words = packet_length_byte; + } + } + + empty_rx_fifo(dev, (uint8_t *)data, packet_length_byte); + dev->data->current_rx_size_words = 0; + return packet_length_byte; +} + +uint32_t smsc9220_peek_next_packet_size(const struct + smsc9220_eth_dev_t* dev) +{ + uint32_t packet_size = 0; + struct smsc9220_eth_reg_map_t* register_map = + (struct smsc9220_eth_reg_map_t*)dev->cfg->base; + + if(smsc9220_get_rxfifo_data_used_space(dev)) { + packet_size = GET_BIT_FIELD(register_map->rx_status_peek, + RX_FIFO_STATUS_PKT_LENGTH_MASK, + RX_FIFO_STATUS_PKT_LENGTH_POS); + } + return packet_size; +} diff --git a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/smsc9220_eth_drv.h b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/smsc9220_eth_drv.h new file mode 100644 index 0000000000..aa60b4f95f --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/drivers/smsc9220_eth_drv.h @@ -0,0 +1,548 @@ +/* + * Copyright (c) 2016-2018 ARM Limited + * + * 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. + */ + +/** + * \file smsc9220_drv.h + * \brief Generic driver for SMSC9220 Ethernet controller + */ + +#ifndef __SMSC9220_ETH_H__ +#define __SMSC9220_ETH_H__ + +#include "stdbool.h" +#include "stdint.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** SMSC9220 device configuration structure */ +struct smsc9220_eth_dev_cfg_t { + const uint32_t base; /*!< SMSC9220 base address */ +}; + +/** SMSC9220 device data structure */ +struct smsc9220_eth_dev_data_t { + uint32_t state; /*!< Indicates if the SMSC9220 driver + is initialized and enabled */ + void (*wait_ms) (int);/*!< function pointer to system's millisec delay + function, will be used for delays */ + uint32_t ongoing_packet_length;/*!< size in bytes of the packet + is being sent */ + uint32_t ongoing_packet_length_sent; /*!< size in bytes of the packet + has been sent */ + uint32_t current_rx_size_words; /*!< Data length in words, + currently is being read */ +}; + +/** SMSC9220 device structure */ +struct smsc9220_eth_dev_t { + const struct smsc9220_eth_dev_cfg_t* const cfg; /*!< configuration */ + struct smsc9220_eth_dev_data_t* const data; /*!< data */ +}; + +/** + * \brief Error code definitions + * + */ +enum smsc9220_error_t{ + SMSC9220_ERROR_NONE = 0U, /*!< no error */ + SMSC9220_ERROR_TIMEOUT = 1U, /*!< timeout */ + SMSC9220_ERROR_BUSY = 2U, /*!< no error */ + SMSC9220_ERROR_PARAM = 3U, /*!< invalid parameter */ + SMSC9220_ERROR_INTERNAL = 4U /*!< internal error */ +}; + +/** + * \brief Interrupt source definitions + * + */ +enum smsc9220_interrupt_source { + SMSC9220_INTERRUPT_GPIO0 = 0U, + SMSC9220_INTERRUPT_GPIO1 = 1U, + SMSC9220_INTERRUPT_GPIO2 = 2U, + SMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL = 3U, + SMSC9220_INTERRUPT_RX_STATUS_FIFO_FULL = 4U, + /* 5 Reserved according to Datasheet */ + SMSC9220_INTERRUPT_RX_DROPPED_FRAME = 6U, + SMSC9220_INTERRUPT_TX_STATUS_FIFO_LEVEL = 7U, + SMSC9220_INTERRUPT_TX_STATUS_FIFO_FULL = 8U, + SMSC9220_INTERRUPT_TX_DATA_FIFO_AVAILABLE = 9U, + SMSC9220_INTERRUPT_TX_DATA_FIFO_OVERRUN = 10U, + /* 11, 12 Reserved according to Datasheet */ + SMSC9220_INTERRUPT_TX_ERROR = 13U, + SMSC9220_INTERRUPT_RX_ERROR = 14U, + SMSC9220_INTERRUPT_RX_WATCHDOG_TIMEOUT = 15U, + SMSC9220_INTERRUPT_TX_STATUS_OVERFLOW = 16U, + SMSC9220_INTERRUPT_TX_POWER_MANAGEMENT = 17U, + SMSC9220_INTERRUPT_PHY = 18U, + SMSC9220_INTERRUPT_GP_TIMER = 19U, + SMSC9220_INTERRUPT_RX_DMA = 20U, + SMSC9220_INTERRUPT_TX_IOC = 21U, + /* 22 Reserved according to Datasheet*/ + SMSC9220_INTERRUPT_RX_DROPPED_FRAME_HALF = 23U, + SMSC9220_INTERRUPT_RX_STOPPED = 24U, + SMSC9220_INTERRUPT_TX_STOPPED = 25U, + /* 26 - 30 Reserved according to Datasheet*/ + SMSC9220_INTERRUPT_SW = 31U +}; + +/** + * \brief MAC register offset definitions + * + */ +enum smsc9220_mac_reg_offsets_t{ + SMSC9220_MAC_REG_OFFSET_CR = 0x1U, + SMSC9220_MAC_REG_OFFSET_ADDRH = 0x2U, + SMSC9220_MAC_REG_OFFSET_ADDRL = 0x3U, + SMSC9220_MAC_REG_OFFSET_HASHH = 0x4U, + SMSC9220_MAC_REG_OFFSET_HASHL = 0x5U, + SMSC9220_MAC_REG_OFFSET_MII_ACC = 0x6U, + SMSC9220_MAC_REG_OFFSET_MII_DATA = 0x7U, + SMSC9220_MAC_REG_OFFSET_FLOW = 0x8U, + SMSC9220_MAC_REG_OFFSET_VLAN1 = 0x9U, + SMSC9220_MAC_REG_OFFSET_VLAN2 = 0xAU, + SMSC9220_MAC_REG_OFFSET_WUFF = 0xBU, + SMSC9220_MAC_REG_OFFSET_WUCSR = 0xCU, + SMSC9220_MAC_REG_OFFSET_COE_CR = 0xDU +}; + +/** + * \brief PHY register offset definitions + * + */ +enum phy_reg_offsets_t{ + SMSC9220_PHY_REG_OFFSET_BCTRL = 0x0U, + SMSC9220_PHY_REG_OFFSET_BSTATUS = 0x1U, + SMSC9220_PHY_REG_OFFSET_ID1 = 0x2U, + SMSC9220_PHY_REG_OFFSET_ID2 = 0x3U, + SMSC9220_PHY_REG_OFFSET_ANEG_ADV = 0x4U, + SMSC9220_PHY_REG_OFFSET_ANEG_LPA = 0x5U, + SMSC9220_PHY_REG_OFFSET_ANEG_EXP = 0x6U, + SMSC9220_PHY_REG_OFFSET_MCONTROL = 0x17U, + SMSC9220_PHY_REG_OFFSET_MSTATUS = 0x18U, + SMSC9220_PHY_REG_OFFSET_CSINDICATE = 0x27U, + SMSC9220_PHY_REG_OFFSET_INTSRC = 0x29U, + SMSC9220_PHY_REG_OFFSET_INTMASK = 0x30U, + SMSC9220_PHY_REG_OFFSET_CS = 0x31U +}; + +/* Bit definitions for PHY Basic Status Register */ +#define PHY_REG_BSTATUS_EXTENDED_CAPABILITIES_INDEX 0U +#define PHY_REG_BSTATUS_JABBER_DETECT_INDEX 1U +#define PHY_REG_BSTATUS_LINK_STATUS_INDEX 2U +#define PHY_REG_BSTATUS_AUTO_NEG_ABILITY_INDEX 3U +#define PHY_REG_BSTATUS_REMOTE_FAULT_INDEX 4U +#define PHY_REG_BSTATUS_AUTO_NEG_COMPLETE_INDEX 5U +#define PHY_REG_BSTATUS_10BASE_T_HALF_DUPLEX_INDEX 11U +#define PHY_REG_BSTATUS_10BASE_T_FULL_DUPLEX_INDEX 12U +#define PHY_REG_BSTATUS_100BASE_TX_HALF_DUPLEX_INDEX 13U +#define PHY_REG_BSTATUS_100BASE_TX_FULL_DUPLEX_INDEX 14U +#define PHY_REG_BSTATUS_100BASE_T4_INDEX 15U + +/** + * \brief FIFO Level Interrupt bit definitions + * + */ +enum smsc9220_fifo_level_irq_pos_t{ + SMSC9220_FIFO_LEVEL_IRQ_RX_STATUS_POS = 0U, + SMSC9220_FIFO_LEVEL_IRQ_TX_STATUS_POS = 16U, + SMSC9220_FIFO_LEVEL_IRQ_TX_DATA_POS = 24U +}; + +/** + * \brief FIFO Level Interrupt limits + * + */ +#define SMSC9220_FIFO_LEVEL_IRQ_MASK 0xFFU +#define SMSC9220_FIFO_LEVEL_IRQ_LEVEL_MIN 0U +#define SMSC9220_FIFO_LEVEL_IRQ_LEVEL_MAX SMSC9220_FIFO_LEVEL_IRQ_MASK + +/** + * \brief Initializes SMSC9220 Ethernet controller to a known default state: + * - device ID is checked + * - global interrupt is enabled, but all irq sources are disabled + * - all capabilities are advertised + * - 10Mbps able + * - 10Mbps with full duplex + * - 100Mbps Tx able + * - 100Mbps with full duplex + * - Symmetric Pause + * - Asymmetric Pause + * - Establish link enabled + * - Rx enabled + * - Tx enabled + * Init should be called prior to any other process and + * it's the caller's responsibility to follow proper call order. + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + * \param[in] wait_ms_function function pointer to a millisec delay function + * for proper timing of some processes + * + * \return error code /ref smsc9220_error_t + */ +enum smsc9220_error_t smsc9220_init(const struct smsc9220_eth_dev_t* dev, + void(* wait_ms_function)(int)); + +/** + * \brief Read MAC register. + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + * \param[in] regoffset Register offset + * \param[in, out] data Pointer to register will be read + * + * \return error code /ref smsc9220_error_t + */ +enum smsc9220_error_t smsc9220_mac_regread( + const struct smsc9220_eth_dev_t* dev, + enum smsc9220_mac_reg_offsets_t regoffset, + uint32_t *data); + +/** + * \brief Write MAC register. + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + * \param[in] regoffset Register offset + * \param[in] data Register value to write + * + * \return error code /ref smsc9220_error_t + */ +enum smsc9220_error_t smsc9220_mac_regwrite( + const struct smsc9220_eth_dev_t* dev, + enum smsc9220_mac_reg_offsets_t regoffset, + uint32_t data); + +/** + * \brief Read PHY register. + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + * \param[in] regoffset Register offset + * \param[out] data Register value is read + * + * \return error code /ref smsc9220_error_t + */ +enum smsc9220_error_t smsc9220_phy_regread( + const struct smsc9220_eth_dev_t* dev, + enum phy_reg_offsets_t, + uint32_t *data); + +/** + * \brief Write PHY register. + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + * \param[in] regoffset Register offset + * \param[in] data Register value to write + * + * \return error code /ref smsc9220_error_t + */ +enum smsc9220_error_t smsc9220_phy_regwrite( + const struct smsc9220_eth_dev_t* dev, + enum phy_reg_offsets_t, + uint32_t data); + +/** + * \brief Read SMSC9220 ID. + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + * + * \return ID number + */ +uint32_t smsc9220_read_id(const struct smsc9220_eth_dev_t* dev); + +/** + * \brief Initiates a soft reset, returns failure or success. + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + * + * \return error code /ref smsc9220_error_t + */ +enum smsc9220_error_t smsc9220_soft_reset( + const struct smsc9220_eth_dev_t* dev); + +/** + * \brief Set maximum transition unit by Tx fifo size. + * Note: The MTU will be smaller by 512 bytes, + * because the status uses this fixed space. + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + * \param[in] val Size of the fifo in kbytes + * \ref HW_CFG_REG_TX_FIFO_SIZE_MIN + * \ref HW_CFG_REG_TX_FIFO_SIZE_MAX + */ +void smsc9220_set_txfifo(const struct smsc9220_eth_dev_t* dev, + uint32_t val); + +/** + * \brief Set FIFO level interrupt for a given source + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + * \param[in] irq_level_pos Bit position of the FIFO to set + * \ref smsc9220_fifo_level_irq_pos_t + * \param[in] level Level of the FIFO, when the FIFO used space is greater + * than this value, corresponding interrupt will be generated. + * + * \return error code /ref smsc9220_error_t + */ +enum smsc9220_error_t smsc9220_set_fifo_level_irq( + const struct smsc9220_eth_dev_t* dev, + enum smsc9220_fifo_level_irq_pos_t irq_level_pos, + uint32_t level); + +/** + * \brief Wait for EEPROM to be ready to use. + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + * + * \return error code /ref smsc9220_error_t + */ +enum smsc9220_error_t smsc9220_wait_eeprom( + const struct smsc9220_eth_dev_t* dev); + +/** + * \brief Initialise irqs by clearing and disabling all interrupt sources + * and enable interrupts. Since all interrupt sources are disabled, + * interrupt won't be triggered, until interrupt sources won't be + * enabled by \ref smsc9220_enable_interrupt + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + */ +void smsc9220_init_irqs(const struct smsc9220_eth_dev_t* dev); + +/** + * \brief Check PHY ID registers. + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + * + * \return error code /ref smsc9220_error_t + */ +enum smsc9220_error_t smsc9220_check_phy(const struct smsc9220_eth_dev_t* dev); + +/** + * \brief Reset PHY + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + * + * \return error code /ref smsc9220_error_t + */ +enum smsc9220_error_t smsc9220_reset_phy(const struct smsc9220_eth_dev_t* dev); + +/** + * \brief Advertise all speeds and pause capabilities + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + */ +void smsc9220_advertise_cap(const struct smsc9220_eth_dev_t* dev); + +/** + * \brief Enable transmission + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + */ +void smsc9220_enable_xmit(const struct smsc9220_eth_dev_t* dev); + +/** + * \brief Disable transmission + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + */ +void smsc9220_disable_xmit(const struct smsc9220_eth_dev_t* dev); + +/** + * \brief Enable MAC transmitter + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + */ +void smsc9220_enable_mac_xmit(const struct smsc9220_eth_dev_t* dev); + +/** + * \brief Disable MAC transmitter + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + */ +void smsc9220_disable_mac_xmit(const struct smsc9220_eth_dev_t* dev); + +/** + * \brief Enable receive + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + */ +void smsc9220_enable_mac_recv(const struct smsc9220_eth_dev_t* dev); + +/** + * \brief Disable receive + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + */ +void smsc9220_disable_mac_recv(const struct smsc9220_eth_dev_t* dev); + +/** + * \brief Enable the given interrupt source. + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + * \param[in] source Enum of the interrupt source. + */ +void smsc9220_enable_interrupt(const struct smsc9220_eth_dev_t* dev, + enum smsc9220_interrupt_source source); + +/** + * \brief Disable the given interrupt source. + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + * \param[in] source Enum of the interrupt source. + */ +void smsc9220_disable_interrupt(const struct smsc9220_eth_dev_t* dev, + enum smsc9220_interrupt_source source); + +/** + * \brief Disable all of the interrupt sources. + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + */ +void smsc9220_disable_all_interrupts(const struct smsc9220_eth_dev_t* dev); + +/** + * \brief Clear the given interrupt source. + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + * \param[in] source Enum of the interrupt source. + */ +void smsc9220_clear_interrupt(const struct smsc9220_eth_dev_t* dev, + enum smsc9220_interrupt_source source); + +/** + * \brief Clear all of the interrupt sources. + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + */ +void smsc9220_clear_all_interrupts(const struct smsc9220_eth_dev_t* dev); + +/** + * \brief Get the status of the given interrupt source. + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + * \param[in] source Enum of the interrupt source. + * + * \return non-zero if the given interrupt source is triggered, zero otherwise + */ +int smsc9220_get_interrupt(const struct smsc9220_eth_dev_t* dev, + enum smsc9220_interrupt_source source); + +/** + * \brief Establish link + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + */ +void smsc9220_establish_link(const struct smsc9220_eth_dev_t* dev); + +/** + * \brief Read MAC address from EEPROM. + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + * \param[in,out] mac array will include the read MAC address in + * 6 bytes hexadecimal format. + * It should be allocated by the caller to 6 bytes. + * + * \return error code /ref smsc9220_error_t + */ +enum smsc9220_error_t smsc9220_read_mac_address( + const struct smsc9220_eth_dev_t* dev, char *mac); + +/** + * \brief Check device ID. + * + * \return error code /ref smsc9220_error_t + */ +int smsc9220_check_id(const struct smsc9220_eth_dev_t* dev); + +/** + * \brief Get the data size of the Tx buffer, aka Maximum Transition Unit + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + * + * \return Fifo data size in bytes + */ +uint32_t smsc9220_get_tx_data_fifo_size(const struct + smsc9220_eth_dev_t* dev); + +/** + * \brief Send Ethernet packet from buffer chain. + * The full packet length should be known in the beginning + * of a new packet. + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + * \param[in] total_payload_length Length of the ethernet payload. + * Should be equal to the sum of passed buffers within a packet. + * \param[in] is_new_packet Should be set to true if the input buffer has to + * be sent as the start of a new packet or as a full packet. + * \param[in] data Pointer to the data should be sent. + * \param[in] current_size Size of the data in bytes. + * + * \return error code /ref smsc9220_error_t + */ +enum smsc9220_error_t smsc9220_send_by_chunks( + const struct smsc9220_eth_dev_t* dev, + uint32_t total_payload_length, + bool is_new_packet, + const char *data, uint32_t current_size); + +/** + * \brief Receive Ethernet packet from Rx FIFO to the passed buffer. + * Stops reading at packet border. + * If the passed buffer is larger than the current packet, + * the whole packet will be read into the buffer. + * If the current packet is larger than the passed buffer, + * the buffer will be filled with data and the next call + * will continue the read from that point. + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + * \param[in,out] data Pointer where the data will be read to. + * The caller is responsible to allocate it. + * \param[in] dlen Length of the allocated data in bytes. + * + * \return Remaining bytes left in the fifo of the current packet. + */ +uint32_t smsc9220_receive_by_chunks(const struct smsc9220_eth_dev_t* dev, + char *data, uint32_t dlen); + +/** + * \brief Get the used space of Rx fifo in bytes. + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + * + * \return Data received and waiting for read in bytes + */ +uint32_t smsc9220_get_rxfifo_data_used_space(const struct + smsc9220_eth_dev_t* dev); + +/** + * \brief Get the size of next unread packet in Rx buffer, using the peak + * register, which is not destructive so can be read asynchronously. + * Warning: In case of heavy receiving load, it's possible this register + * is not perfectly in sync. + * + * \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t + * + * \return Size in bytes of the next packet can be read from Rx fifo, according + * to the peek register. + */ +uint32_t smsc9220_peek_next_packet_size(const struct + smsc9220_eth_dev_t* dev); + +#ifdef __cplusplus +} +#endif + +#endif /* __SMSC9220_ETH_H__ */ diff --git a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/platform_devices.c b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/platform_devices.c index 53524a3594..ccfab4b4ac 100644 --- a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/platform_devices.c +++ b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/platform_devices.c @@ -270,3 +270,13 @@ static struct arm_uart_dev_data_t ARM_UART4_DEV_DATA = { struct arm_uart_dev_t ARM_UART4_DEV = {&(ARM_UART4_DEV_CFG), &(ARM_UART4_DEV_DATA)}; #endif /* ARM_UART4 */ + +/* SMSC9220 Ethernet driver structures */ +#ifdef SMSC9220_ETH +static const struct smsc9220_eth_dev_cfg_t SMSC9220_ETH_DEV_CFG = { + .base = SMSC9220_BASE}; +static struct smsc9220_eth_dev_data_t SMSC9220_ETH_DEV_DATA = { + .state = 0}; +struct smsc9220_eth_dev_t SMSC9220_ETH_DEV = {&(SMSC9220_ETH_DEV_CFG), + &(SMSC9220_ETH_DEV_DATA)}; +#endif \ No newline at end of file diff --git a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/platform_devices.h b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/platform_devices.h index c33f07e25b..14fdc45bc2 100644 --- a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/platform_devices.h +++ b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/device/platform_devices.h @@ -26,6 +26,7 @@ #include "arm_mps2_io_drv.h" #include "spi_pl022_drv.h" #include "arm_uart_drv.h" +#include "smsc9220_eth_drv.h" /* ======= Defines peripheral configuration structures ======= */ @@ -96,4 +97,8 @@ extern struct arm_uart_dev_t ARM_UART3_DEV; extern struct arm_uart_dev_t ARM_UART4_DEV; #endif +#ifdef SMSC9220_ETH +extern struct smsc9220_eth_dev_t SMSC9220_ETH_DEV; +#endif + #endif /* __ARM_LTD_PLATFORM_DEVICES_H__ */ diff --git a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/ethernet_api.c b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/ethernet_api.c deleted file mode 100644 index d9755dfb33..0000000000 --- a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/ethernet_api.c +++ /dev/null @@ -1,85 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2017 ARM Limited - * - * 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 - -#include "ethernet_api.h" -#include "cmsis.h" -#include "mbed_interface.h" -#include "mbed_toolchain.h" -#include "mbed_error.h" -#include "mbed_wait_api.h" -#include "smsc9220_eth.h" - -/*---------------------------------------------------------------------------- - Ethernet Device initialize - *----------------------------------------------------------------------------*/ -int ethernet_init() -{ - return smsc9220_init(); -} - -/*---------------------------------------------------------------------------- - Ethernet Device Uninitialize - *----------------------------------------------------------------------------*/ -void ethernet_free() -{ - /* Uninitialize function is not implemented in Ethernet driver. */ -} - -int ethernet_write(const char *data, int size) -{ - /* smsc9220 cannot provide the functionality of writing into the tx buffer */ - /* by chunks, without knowing the full size of the packet in the beginning */ - return 0; -} - -int ethernet_send() -{ - /* smsc9220 cannot provide the functionality of writing into the tx buffer */ - /* by chunks, without knowing the full size of the packet in the beginning */ - return 0; -} - -int ethernet_receive() -{ - return smsc9220_peek_next_packet_size(); -} - -/* Read from an recevied ethernet packet.*/ -/* After receive returnd a number bigger than 0 it is*/ -/* possible to read bytes from this packet.*/ -/* Read will write up to size bytes into data.*/ -/* It is possible to use read multible times.*/ -/* Each time read will start reading after the last read byte before. */ -int ethernet_read(char *data, int dlen) -{ - return smsc9220_receive_by_chunks(data, dlen); -} - -void ethernet_address(char *mac) -{ - smsc9220_read_mac_address(mac); -} - -int ethernet_link(void) -{ - return 0; -} - -void ethernet_set_link(int speed, int duplex) -{ - smsc9220_establish_link(); -} diff --git a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/mbed_overrides.c b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/mbed_overrides.c index 1531692bce..2fdfa0d75e 100644 --- a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/mbed_overrides.c +++ b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/mbed_overrides.c @@ -1,6 +1,6 @@ /* mbed Microcontroller Library - * Copyright (c) 2006-2017 ARM Limited + * Copyright (c) 2006-2018 Arm Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,10 +15,12 @@ * limitations under the License. */ -#include "smsc9220_eth.h" +#include "platform_devices.h" +#include "smsc9220_eth_drv.h" /* Provide ethernet devices with a semi-unique MAC address from the UUID */ void mbed_mac_address(char *mac) { - smsc9220_read_mac_address(mac); + smsc9220_read_mac_address(&SMSC9220_ETH_DEV, mac); } + diff --git a/targets/targets.json b/targets/targets.json index ce6dbed00b..15e90c6cd6 100755 --- a/targets/targets.json +++ b/targets/targets.json @@ -2880,13 +2880,17 @@ "inherits": ["ARM_IOTSS_Target"], "core": "Cortex-M3", "supported_toolchains": ["ARM", "GCC_ARM", "IAR"], + "components": ["SMSC9220"], "extra_labels": ["ARM_SSG", "CM3DS_MPS2"], "OUTPUT_EXT": "elf", "macros": ["CMSDK_CM3DS"], - "device_has": ["ANALOGIN", "ETHERNET", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "SERIAL", "SPI", "TRNG", "FLASH"], + "device_has": ["ANALOGIN", "EMAC", "FLASH", "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "SERIAL", "SPI", "TRNG"], "release_versions": ["2", "5"], "copy_method": "mps2", - "reset_method": "reboot.txt" + "reset_method": "reboot.txt", + "overrides": { + "target.network-default-interface-type": "ETHERNET" + } }, "ARM_BEETLE_SOC": { "inherits": ["ARM_IOTSS_Target"],