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 3e093e32fb..5aa820438a 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -2929,13 +2929,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"],