From b91f064be749ac1e22bb86d0878425b457c7b8cb Mon Sep 17 00:00:00 2001 From: cyliangtw Date: Fri, 16 Dec 2016 19:47:05 +0800 Subject: [PATCH] [M487] Add CAN, AES and Eth --- .../TARGET_M480/lwipopts_conf.h | 26 + .../TARGET_NUVOTON/TARGET_M480/m480_eth.c | 557 +++++++++++++++++ .../TARGET_NUVOTON/TARGET_M480/m480_eth.h | 150 +++++ .../TARGET_NUVOTON/TARGET_M480/m480_netif.c | 523 ++++++++++++++++ .../TARGET_NUVOTON/TARGET_M480/m480_netif.h | 69 ++ targets/TARGET_NUVOTON/TARGET_M480/can_api.c | 355 +++++++++++ .../TARGET_M480/crypto/aes/aes_alt.c | 590 ++++++++++++++++++ .../TARGET_M480/crypto/aes/aes_alt.h | 274 ++++++++ targets/TARGET_NUVOTON/TARGET_M480/trng_api.c | 4 + targets/targets.json | 3 +- 10 files changed, 2550 insertions(+), 1 deletion(-) create mode 100644 features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NUVOTON/TARGET_M480/lwipopts_conf.h create mode 100644 features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NUVOTON/TARGET_M480/m480_eth.c create mode 100644 features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NUVOTON/TARGET_M480/m480_eth.h create mode 100644 features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NUVOTON/TARGET_M480/m480_netif.c create mode 100644 features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NUVOTON/TARGET_M480/m480_netif.h create mode 100644 targets/TARGET_NUVOTON/TARGET_M480/can_api.c create mode 100644 targets/TARGET_NUVOTON/TARGET_M480/crypto/aes/aes_alt.c create mode 100644 targets/TARGET_NUVOTON/TARGET_M480/crypto/aes/aes_alt.h diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NUVOTON/TARGET_M480/lwipopts_conf.h b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NUVOTON/TARGET_M480/lwipopts_conf.h new file mode 100644 index 0000000000..f10219a748 --- /dev/null +++ b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NUVOTON/TARGET_M480/lwipopts_conf.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2012-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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 LWIPOPTS_CONF_H +#define LWIPOPTS_CONF_H + +#define LWIP_TRANSPORT_ETHERNET 1 +#define ETH_PAD_SIZE 2 + +#define MEM_SIZE (16*1024)//(8*1024)//(16*1024) + +#endif diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NUVOTON/TARGET_M480/m480_eth.c b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NUVOTON/TARGET_M480/m480_eth.c new file mode 100644 index 0000000000..9b50b6b437 --- /dev/null +++ b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NUVOTON/TARGET_M480/m480_eth.c @@ -0,0 +1,557 @@ +/* + * Copyright (c) 2016 Nuvoton Technology Corp. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Description: M480 MAC driver source file + */ +#include "m480_eth.h" +#include "lwip/opt.h" +#include "lwip/def.h" +#include "toolchain.h" + +#define ETH_TRIGGER_RX() do{EMAC->RXST = 0;}while(0) +#define ETH_TRIGGER_TX() do{EMAC->TXST = 0;}while(0) +#define ETH_ENABLE_TX() do{EMAC->CTL |= EMAC_CTL_TXON;}while(0) +#define ETH_ENABLE_RX() do{EMAC->CTL |= EMAC_CTL_RXON;}while(0) +#define ETH_DISABLE_TX() do{EMAC->CTL &= ~EMAC_CTL_TXON;}while(0) +#define ETH_DISABLE_RX() do{EMAC->CTL &= ~EMAC_CTL_RXON;}while(0) + +#define GPIO_MIIM // Use GPIO to simulation MIIM pins +#ifdef GPIO_MIIM +#define delay do{int volatile ii; for(ii = 0; ii < 10; ii++);}while(0) +#define tMDC PC9 +#define tMDIO PC10 +#endif + +/* +#ifdef __ICCARM__ +#pragma data_alignment=4 +struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM]; +struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM]; +#else +struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM] __attribute__ ((aligned(4))); +struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM] __attribute__ ((aligned(4))); +#endif +*/ +struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM] MBED_ALIGN(4); +struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM] MBED_ALIGN(4); + +struct eth_descriptor volatile *cur_tx_desc_ptr, *cur_rx_desc_ptr, *fin_tx_desc_ptr; + +u8_t rx_buf[RX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE] MBED_ALIGN(4); +u8_t tx_buf[TX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE] MBED_ALIGN(4); + +extern void ethernetif_input(u16_t len, u8_t *buf, u32_t s, u32_t ns); +extern void ethernetif_loopback_input(struct pbuf *p); +extern void ack_emac_rx_isr(void); + +// PTP source clock is 84MHz (Real chip using PLL). Each tick is 11.90ns +// Assume we want to set each tick to 100ns. +// Increase register = (100 * 2^31) / (10^9) = 214.71 =~ 215 = 0xD7 +// Addend register = 2^32 * tick_freq / (84MHz), where tick_freq = (2^31 / 215) MHz +// From above equation, addend register = 2^63 / (84M * 215) ~= 510707200 = 0x1E70C600 + + +#ifdef GPIO_MIIM +static void mdio_write(uint32_t u32Addr, uint32_t u32Reg, uint32_t u32Data) +{ + int i; + + tMDIO = 1; + tMDC = 1; + for(i = 0; i < 64; i++) { + delay; + tMDC = 0; + delay; + tMDC = 1; + } + + // ST + delay; + tMDC = 0; + tMDIO = 0; + delay; + tMDC = 1; + delay; + tMDC = 0; + tMDIO = 1; + delay; + tMDC = 1; + + // OP - write + delay; + tMDC = 0; + tMDIO = 0; + delay; + tMDC = 1; + delay; + tMDC = 0; + tMDIO = 1; + delay; + tMDC = 1; + + // PHYAD + for(i = 0; i < 5; i++) { + delay; + tMDC = 0; + tMDIO = (u32Addr >> (4 - i)) & 1; + delay; + tMDC = 1; + } + + // REGAD + for(i = 0; i < 5; i++) { + delay; + tMDC = 0; + tMDIO = (u32Reg >> (4 - i)) & 1; + delay; + tMDC = 1; + } + + //TA + delay; + tMDC = 0; + tMDIO = 1; + delay; + tMDC = 1; + delay; + tMDC = 0; + tMDIO = 0; + delay; + tMDC = 1; + + // data + for(i = 0; i < 16; i++) { + delay; + tMDC = 0; + tMDIO = (u32Data >> (15 - i)) & 1; + delay; + tMDC = 1; + } + for(i = 0; i < 32; i++) { + tMDC = 0; + tMDC = 1; + } + +} +#else +static void mdio_write(u8_t addr, u8_t reg, u16_t val) +{ + + EMAC->MIIMDAT = val; + EMAC->MIIMCTL = (addr << EMAC_MIIMCTL_PHYADDR_Pos) | reg | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_WRITE_Msk | EMAC_MIIMCTL_MDCON_Msk; + + while (EMAC->MIIMCTL & EMAC_MIIMCTL_BUSY_Msk); + +} +#endif + +#ifdef GPIO_MIIM +static uint32_t mdio_read(uint32_t u32Addr, uint32_t u32Reg) +{ + int i; + uint32_t u32Data = 0; + + tMDIO = 1; + tMDC = 1; + + for(i = 0; i < 64; i++) { + delay; + tMDC = 0; + delay; + tMDC = 1; + } + + // ST + delay; + tMDC = 0; + tMDIO = 0; + delay; + tMDC = 1; + delay; + tMDC = 0; + tMDIO = 1; + delay; + tMDC = 1; + + // OP - read + delay; + tMDC = 0; + tMDIO = 1; + delay; + tMDC = 1; + delay; + tMDC = 0; + tMDIO = 0; + delay; + tMDC = 1; + + // PHYAD + for(i = 0; i < 5; i++) { + delay; + tMDC = 0; + tMDIO = (u32Addr >> (4 - i)) & 1; + delay; + tMDC = 1; + } + + // REGAD + for(i = 0; i < 5; i++) { + delay; + tMDC = 0; + tMDIO = (u32Reg >> (4 - i)) & 1; + delay; + tMDC = 1; + } + //TA + PC->MODE &= ~(1 << 20); + delay; + tMDC = 0; + //tMDIO = 1; + delay; + tMDC = 1; + delay; + tMDC = 0; + //tMDIO = 0; + delay; + tMDC = 1; + + // data + for(i = 0; i < 16; i++) { + delay; + tMDC = 0; + delay; + u32Data |= tMDIO << (15 - i); + tMDC = 1; + } + PC->MODE |= (1 << 20); + for(i = 0; i < 64; i++) { + delay; + tMDC = 0; + delay; + tMDC = 1; + } + return u32Data; + +} +#else +static u16_t mdio_read(u8_t addr, u8_t reg) +{ + EMAC->MIIMCTL = (addr << EMAC_MIIMCTL_PHYADDR_Pos) | reg | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_MDCON_Msk; + while (EMAC->MIIMCTL & EMAC_MIIMCTL_BUSY_Msk); + + return(EMAC->MIIMDAT); +} +#endif + + +static int reset_phy(void) +{ + + u16_t reg; + u32_t delayCnt; + +#ifdef GPIO_MIIM + SYS->GPC_MFPH &= ~0x00000FF0; + PC->MODE |= (1 << 20) | (1 << 18); +#endif + + mdio_write(CONFIG_PHY_ADDR, MII_BMCR, BMCR_RESET); + + delayCnt = 2000; + while(delayCnt-- > 0) { + if((mdio_read(CONFIG_PHY_ADDR, MII_BMCR) & BMCR_RESET) == 0) + break; + + } + + if(delayCnt == 0) { + printf("Reset phy failed\n"); + return(-1); + } + +#if 1 + /* Enlarge IP101GA driving current as IP101A */ + mdio_write(CONFIG_PHY_ADDR, 20, 0x0004); //change to page 4 + mdio_write(CONFIG_PHY_ADDR, 22, 0x8000); // RXC driving = 8.10mA + mdio_write(CONFIG_PHY_ADDR, 20, 0x0010); // change to page 16(default) + mdio_write(CONFIG_PHY_ADDR, 26, 0x4924); // RXD driving = 8.10mA +#endif + + mdio_write(CONFIG_PHY_ADDR, MII_ADVERTISE, ADVERTISE_CSMA | + ADVERTISE_10HALF | + ADVERTISE_10FULL | + ADVERTISE_100HALF | + ADVERTISE_100FULL); + + reg = mdio_read(CONFIG_PHY_ADDR, MII_BMCR); + mdio_write(CONFIG_PHY_ADDR, MII_BMCR, reg | BMCR_ANRESTART); + + delayCnt = 200000; + while(delayCnt-- > 0) { + if((mdio_read(CONFIG_PHY_ADDR, MII_BMSR) & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS)) + == (BMSR_ANEGCOMPLETE | BMSR_LSTATUS)) + break; + } + + if(delayCnt == 0) { + printf("AN failed. Set to 100 FULL\n"); + EMAC->CTL |= (EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk); + return(-1); + } else { + reg = mdio_read(CONFIG_PHY_ADDR, MII_LPA); + + if(reg & ADVERTISE_100FULL) { + printf("100 full\n"); + EMAC->CTL |= (EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk); + } else if(reg & ADVERTISE_100HALF) { + printf("100 half\n"); + EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_FUDUP_Msk) | EMAC_CTL_OPMODE_Msk; + } else if(reg & ADVERTISE_10FULL) { + printf("10 full\n"); + EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_OPMODE_Msk) | EMAC_CTL_FUDUP_Msk; + } else { + printf("10 half\n"); + EMAC->CTL &= ~(EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk); + } + } + + printf("PHY ID 1:0x%x\r\n", mdio_read(CONFIG_PHY_ADDR, MII_PHYSID1)); + printf("PHY ID 2:0x%x\r\n", mdio_read(CONFIG_PHY_ADDR, MII_PHYSID2)); + + return(0); +} + + +static void init_tx_desc(void) +{ + u32_t i; + + + cur_tx_desc_ptr = fin_tx_desc_ptr = &tx_desc[0]; + + for(i = 0; i < TX_DESCRIPTOR_NUM; i++) { + tx_desc[i].status1 = TXFD_PADEN | TXFD_CRCAPP | TXFD_INTEN; + tx_desc[i].buf = &tx_buf[i][0]; + tx_desc[i].status2 = 0; + tx_desc[i].next = &tx_desc[(i + 1) % TX_DESCRIPTOR_NUM]; + + } + EMAC->TXDSA = (unsigned int)&tx_desc[0]; + return; +} + +static void init_rx_desc(void) +{ + u32_t i; + + + cur_rx_desc_ptr = &rx_desc[0]; + + for(i = 0; i < RX_DESCRIPTOR_NUM; i++) { + rx_desc[i].status1 = OWNERSHIP_EMAC; + rx_desc[i].buf = &rx_buf[i][0]; + rx_desc[i].status2 = 0; + rx_desc[i].next = &rx_desc[(i + 1) % TX_DESCRIPTOR_NUM]; + } + EMAC->RXDSA = (unsigned int)&rx_desc[0]; + return; +} + +static void set_mac_addr(u8_t *addr) +{ + + EMAC->CAM0M = (addr[0] << 24) | + (addr[1] << 16) | + (addr[2] << 8) | + addr[3]; + + EMAC->CAM0L = (addr[4] << 24) | + (addr[5] << 16); + + EMAC->CAMCTL = EMAC_CAMCTL_CMPEN_Msk | EMAC_CAMCTL_AMP_Msk | EMAC_CAMCTL_ABP_Msk; + EMAC->CAMEN = 1; // Enable CAM entry 0 + +} + +static void __eth_clk_pin_init() +{ + /* Unlock protected registers */ + SYS_UnlockReg(); + + /* Enable IP clock */ + CLK_EnableModuleClock(EMAC_MODULE); + + // Configure MDC clock rate to HCLK / (127 + 1) = 1.25 MHz if system is running at 160 MH + CLK_SetModuleClock(EMAC_MODULE, 0, CLK_CLKDIV3_EMAC(127)); + + /* Update System Core Clock */ + SystemCoreClockUpdate(); + + /*---------------------------------------------------------------------------------------------------------*/ + /* Init I/O Multi-function */ + /*---------------------------------------------------------------------------------------------------------*/ + // Configure RMII pins + SYS->GPC_MFPL = SYS_GPC_MFPL_PC0MFP_EMAC_REFCLK | + SYS_GPC_MFPL_PC1MFP_EMAC_MII_RXD0 | + SYS_GPC_MFPL_PC2MFP_EMAC_MII_RXD1 | + SYS_GPC_MFPL_PC3MFP_EMAC_MII_RXDV | + SYS_GPC_MFPL_PC4MFP_EMAC_MII_RXERR; + + SYS->GPC_MFPH = SYS_GPC_MFPH_PC9MFP_EMAC_MII_MDC | + SYS_GPC_MFPH_PC10MFP_EMAC_MII_MDIO | + SYS_GPC_MFPH_PC11MFP_EMAC_MII_TXD0 | + SYS_GPC_MFPH_PC12MFP_EMAC_MII_TXD1 | + SYS_GPC_MFPH_PC13MFP_EMAC_MII_TXEN; + + // Enable high slew rate on all RMII pins + PC->SLEWCTL |= 0x3E1F; + + /* Lock protected registers */ + SYS_LockReg(); +} + +void ETH_init(u8_t *mac_addr) +{ + + // init CLK & pins + __eth_clk_pin_init(); + + // Reset MAC + EMAC->CTL = EMAC_CTL_RST_Msk; + + init_tx_desc(); + init_rx_desc(); + + set_mac_addr(mac_addr); // need to reconfigure hardware address 'cos we just RESET emc... + reset_phy(); + + EMAC->CTL |= EMAC_CTL_STRIPCRC_Msk | EMAC_CTL_RXON_Msk | EMAC_CTL_TXON_Msk | EMAC_CTL_RMIIEN_Msk | EMAC_CTL_RMIIRXCTL_Msk; + EMAC->INTEN |= EMAC_INTEN_RXIEN_Msk | + EMAC_INTEN_RXGDIEN_Msk | + EMAC_INTEN_RDUIEN_Msk | + EMAC_INTEN_RXBEIEN_Msk | + EMAC_INTEN_TXIEN_Msk | + EMAC_INTEN_TXABTIEN_Msk | + EMAC_INTEN_TXCPIEN_Msk | + EMAC_INTEN_TXBEIEN_Msk; + EMAC->RXST = 0; // trigger Rx +} + + + +void ETH_halt(void) +{ + + EMAC->CTL &= ~(EMAC_CTL_RXON_Msk | EMAC_CTL_TXON_Msk); +} + +unsigned int m_status; + +void EMAC_RX_IRQHandler(void) +{ + + m_status = EMAC->INTSTS & 0xFFFF; + EMAC->INTSTS = m_status; + if (m_status & EMAC_INTSTS_RXBEIF_Msk) { + // Shouldn't goes here, unless descriptor corrupted + printf("RX descriptor corrupted \r\n"); + //return; + } + ack_emac_rx_isr(); +} + +void EMAC_RX_Action(void) +{ + unsigned int cur_entry, status; + do { + + cur_entry = EMAC->CRXDSA; + + if ((cur_entry == (u32_t)cur_rx_desc_ptr) && (!(m_status & EMAC_INTSTS_RDUIF_Msk))) // cur_entry may equal to cur_rx_desc_ptr if RDU occures + break; + status = cur_rx_desc_ptr->status1; + + if(status & OWNERSHIP_EMAC) + break; + + if (status & RXFD_RXGD) { + // Lwip will invoke osMutexWait for resource protection, so ethernetif_input can't be called in EMAC_RX_IRQHandler. + ethernetif_input(status & 0xFFFF, cur_rx_desc_ptr->buf, cur_rx_desc_ptr->status2, (u32_t)cur_rx_desc_ptr->next); + + } + + cur_rx_desc_ptr->status1 = OWNERSHIP_EMAC; + cur_rx_desc_ptr = cur_rx_desc_ptr->next; + + } while (1); + + ETH_TRIGGER_RX(); +// eth_arch_tcpip_thread(); +} + +void EMAC_TX_IRQHandler(void) +{ + unsigned int cur_entry, status; + + status = EMAC->INTSTS & 0xFFFF0000; + EMAC->INTSTS = status; + if(status & EMAC_INTSTS_TXBEIF_Msk) { + // Shouldn't goes here, unless descriptor corrupted + return; + } + + cur_entry = EMAC->CTXDSA; + + while (cur_entry != (u32_t)fin_tx_desc_ptr) { + + fin_tx_desc_ptr = fin_tx_desc_ptr->next; + } + +} + +u8_t *ETH_get_tx_buf(void) +{ + if(cur_tx_desc_ptr->status1 & OWNERSHIP_EMAC) + return(NULL); + else + return(cur_tx_desc_ptr->buf); +} + +void ETH_trigger_tx(u16_t length, struct pbuf *p) +{ + struct eth_descriptor volatile *desc; + cur_tx_desc_ptr->status2 = (unsigned int)length; + desc = cur_tx_desc_ptr->next; // in case TX is transmitting and overwrite next pointer before we can update cur_tx_desc_ptr + cur_tx_desc_ptr->status1 |= OWNERSHIP_EMAC; + cur_tx_desc_ptr = desc; + + ETH_TRIGGER_TX(); + +} + +int ETH_link_ok() +{ + /* first, a dummy read to latch */ + mdio_read(CONFIG_PHY_ADDR, MII_BMSR); + if(mdio_read(CONFIG_PHY_ADDR, MII_BMSR) & BMSR_LSTATUS) + return 1; + return 0; +} diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NUVOTON/TARGET_M480/m480_eth.h b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NUVOTON/TARGET_M480/m480_eth.h new file mode 100644 index 0000000000..836460dab7 --- /dev/null +++ b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NUVOTON/TARGET_M480/m480_eth.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2016 Nuvoton Technology Corp. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Description: M480 EMAC driver header file + */ +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "M480.h" +#ifndef _M480_ETH_ +#define _M480_ETH_ + +/* Generic MII registers. */ + +#define MII_BMCR 0x00 /* Basic mode control register */ +#define MII_BMSR 0x01 /* Basic mode status register */ +#define MII_PHYSID1 0x02 /* PHYS ID 1 */ +#define MII_PHYSID2 0x03 /* PHYS ID 2 */ +#define MII_ADVERTISE 0x04 /* Advertisement control reg */ +#define MII_LPA 0x05 /* Link partner ability reg */ +#define MII_EXPANSION 0x06 /* Expansion register */ +#define MII_DCOUNTER 0x12 /* Disconnect counter */ +#define MII_FCSCOUNTER 0x13 /* False carrier counter */ +#define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */ +#define MII_RERRCOUNTER 0x15 /* Receive error counter */ +#define MII_SREVISION 0x16 /* Silicon revision */ +#define MII_RESV1 0x17 /* Reserved... */ +#define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */ +#define MII_PHYADDR 0x19 /* PHY address */ +#define MII_RESV2 0x1a /* Reserved... */ +#define MII_TPISTATUS 0x1b /* TPI status for 10mbps */ +#define MII_NCONFIG 0x1c /* Network interface config */ + +/* Basic mode control register. */ +#define BMCR_RESV 0x007f /* Unused... */ +#define BMCR_CTST 0x0080 /* Collision test */ +#define BMCR_FULLDPLX 0x0100 /* Full duplex */ +#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */ +#define BMCR_ISOLATE 0x0400 /* Disconnect DP83840 from MII */ +#define BMCR_PDOWN 0x0800 /* Powerdown the DP83840 */ +#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */ +#define BMCR_SPEED100 0x2000 /* Select 100Mbps */ +#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */ +#define BMCR_RESET 0x8000 /* Reset the DP83840 */ + +/* Basic mode status register. */ +#define BMSR_ERCAP 0x0001 /* Ext-reg capability */ +#define BMSR_JCD 0x0002 /* Jabber detected */ +#define BMSR_LSTATUS 0x0004 /* Link status */ +#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */ +#define BMSR_RFAULT 0x0010 /* Remote fault detected */ +#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */ +#define BMSR_RESV 0x07c0 /* Unused... */ +#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */ +#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */ +#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */ +#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */ +#define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */ + +/* Advertisement control register. */ +#define ADVERTISE_SLCT 0x001f /* Selector bits */ +#define ADVERTISE_CSMA 0x0001 /* Only selector supported */ +#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ +#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ +#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ +#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ +#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */ +#define ADVERTISE_RESV 0x1c00 /* Unused... */ +#define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */ +#define ADVERTISE_LPACK 0x4000 /* Ack link partners response */ +#define ADVERTISE_NPAGE 0x8000 /* Next page bit */ + +#define RX_DESCRIPTOR_NUM 4 //2 // 4: Max Number of Rx Frame Descriptors +#define TX_DESCRIPTOR_NUM 4 //2 // 4: Max number of Tx Frame Descriptors + +#define PACKET_BUFFER_SIZE 1520 + +#define CONFIG_PHY_ADDR 1 + + +// Frame Descriptor's Owner bit +#define OWNERSHIP_EMAC 0x80000000 // 1 = EMAC +//#define OWNERSHIP_CPU 0x7fffffff // 0 = CPU + + + +// Rx Frame Descriptor Status +#define RXFD_RXGD 0x00100000 // Receiving Good Packet Received +#define RXFD_RTSAS 0x00800000 // RX Time Stamp Available + + +// Tx Frame Descriptor's Control bits +#define TXFD_TTSEN 0x08 // Tx Time Stamp Enable +#define TXFD_INTEN 0x04 // Interrupt Enable +#define TXFD_CRCAPP 0x02 // Append CRC +#define TXFD_PADEN 0x01 // Padding Enable + +// Tx Frame Descriptor Status +#define TXFD_TXCP 0x00080000 // Transmission Completion +#define TXFD_TTSAS 0x08000000 // TX Time Stamp Available + +// Tx/Rx buffer descriptor structure +struct eth_descriptor; +struct eth_descriptor { + u32_t status1; + u8_t *buf; + u32_t status2; + struct eth_descriptor *next; +#ifdef TIME_STAMPING + u32_t backup1; + u32_t backup2; + u32_t reserved1; + u32_t reserved2; +#endif +}; + +#ifdef TIME_STAMPING + +#define ETH_TS_ENABLE() do{EMAC->TSCTL = EMAC_TSCTL_TSEN_Msk;}while(0) +#define ETH_TS_START() do{EMAC->TSCTL |= (EMAC_TSCTL_TSMODE_Msk | EMAC_TSCTL_TSIEN_Msk);}while(0) +s32_t ETH_settime(u32_t sec, u32_t nsec); +s32_t ETH_gettime(u32_t *sec, u32_t *nsec); +s32_t ETH_updatetime(u32_t neg, u32_t sec, u32_t nsec); +s32_t ETH_adjtimex(int ppm); +void ETH_setinc(void); + +#endif + +extern void ETH_init(u8_t *mac_addr); +extern u8_t *ETH_get_tx_buf(void); +extern void ETH_trigger_tx(u16_t length, struct pbuf *p); + +#endif /* _M480_ETH_ */ diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NUVOTON/TARGET_M480/m480_netif.c b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NUVOTON/TARGET_M480/m480_netif.c new file mode 100644 index 0000000000..b7cf73cd02 --- /dev/null +++ b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NUVOTON/TARGET_M480/m480_netif.c @@ -0,0 +1,523 @@ +/** + * @file + * Ethernet Interface Skeleton + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/* + * This file is a skeleton for developing Ethernet network interface + * drivers for lwIP. Add code to the low_level functions and do a + * search-and-replace for the word "ethernetif" to replace it with + * something that better describes your network interface. + */ + +#include "lwip/opt.h" + +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" +#include +#include +#include "netif/etharp.h" +#include "lwip/ethip6.h" +#include "netif/ppp/pppoe.h" +#include "m480_eth.h" +#include "string.h" + +#include "eth_arch.h" +#include "sys_arch.h" +#include +#include + +#include "mbed_interface.h" +#include "cmsis.h" + + +/* Define those to better describe your network interface. */ +#define IFNAME0 'e' +#define IFNAME1 'n' + +// Fow now, all interrupt handling happens inside one single handler, so we need to figure +// out what actually triggered the interrupt. +static volatile uint8_t emac_timer_fired; +volatile uint8_t allow_net_callbacks; + +struct netif *_netif; + +unsigned char my_mac_addr[6] = {0x02, 0x00, 0xac, 0x55, 0x66, 0x88}; +extern u8_t my_mac_addr[6]; +extern int ETH_link_ok(void); +extern void EMAC_RX_Action(void); + +sys_sem_t RxReadySem; /**< RX packet ready semaphore */ + +static void __phy_task(void *data); +static void __packet_rx_task(void *data); +/** + * Helper struct to hold private data used to operate your ethernet interface. + * Keeping the ethernet address of the MAC in this struct is not necessary + * as it is already kept in the struct netif. + * But this is only an example, anyway... + */ +struct ethernetif { + struct eth_addr *ethaddr; + /* Add whatever per-interface state that is needed here. */ +}; + +// Override mbed_mac_address of mbed_interface.c to provide ethernet devices with a semi-unique MAC address +void mbed_mac_address(char *mac) +{ + unsigned char my_mac_addr[6] = {0x02, 0x00, 0xac, 0x55, 0x66, 0x88}; // default mac adderss + // Fetch word 0 + uint32_t word0 = *(uint32_t *)0x7FFFC; + // Fetch word 1 + // we only want bottom 16 bits of word1 (MAC bits 32-47) + // and bit 9 forced to 1, bit 8 forced to 0 + // Locally administered MAC, reduced conflicts + // http://en.wikipedia.org/wiki/MAC_address + uint32_t word1 = *(uint32_t *)0x7FFF8; + if( word0 == 0xFFFFFFFF ) // Not burn any mac address at the last 2 words of flash + { + mac[0] = my_mac_addr[0]; + mac[1] = my_mac_addr[1]; + mac[2] = my_mac_addr[2]; + mac[3] = my_mac_addr[3]; + mac[4] = my_mac_addr[4]; + mac[5] = my_mac_addr[5]; + return; + } + + word1 |= 0x00000200; + word1 &= 0x0000FEFF; + + mac[0] = (word1 & 0x000000ff); + mac[1] = (word1 & 0x0000ff00) >> 8; + mac[2] = (word0 & 0xff000000) >> 24; + mac[3] = (word0 & 0x00ff0000) >> 16; + mac[4] = (word0 & 0x0000ff00) >> 8; + mac[5] = (word0 & 0x000000ff); + +} + +/** + * In this function, the hardware should be initialized. + * Called from ethernetif_init(). + * + * @param netif the already initialized lwip network interface structure + * for this ethernetif + */ +static void +low_level_init(struct netif *netif) +{ + + /* set MAC hardware address length */ + netif->hwaddr_len = ETH_HWADDR_LEN; + + /* set MAC hardware address */ +#if 1 // set MAC HW address +#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE) + netif->hwaddr[0] = MBED_MAC_ADDR_0; + netif->hwaddr[1] = MBED_MAC_ADDR_1; + netif->hwaddr[2] = MBED_MAC_ADDR_2; + netif->hwaddr[3] = MBED_MAC_ADDR_3; + netif->hwaddr[4] = MBED_MAC_ADDR_4; + netif->hwaddr[5] = MBED_MAC_ADDR_5; +#else + mbed_mac_address((char *)netif->hwaddr); +#endif /* set MAC HW address */ + +#else + netif->hwaddr[0] = my_mac_addr[0]; + netif->hwaddr[1] = my_mac_addr[1]; + netif->hwaddr[2] = my_mac_addr[2]; + netif->hwaddr[3] = my_mac_addr[3]; + netif->hwaddr[4] = my_mac_addr[4]; + netif->hwaddr[5] = my_mac_addr[5]; +#endif // endif + + /* maximum transfer unit */ + netif->mtu = 1500; + + /* device capabilities */ + /* NETIF_FLAG_LINK_UP should be enabled by netif_set_link_up() */ + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET; +#ifdef LWIP_IGMP + netif->flags |= NETIF_FLAG_IGMP; +#endif +#if LWIP_IPV6_MLD + netif->flags |= NETIF_FLAG_MLD6; +#endif + // TODO: enable clock & configure GPIO function + ETH_init(netif->hwaddr); + +#if LWIP_IGMP + EMAC_ENABLE_RECV_BCASTPKT(); +#endif + +#if LWIP_IPV6_MLD + EMAC_ENABLE_RECV_MCASTPKT(); +#endif +} + +/** + * This function should do the actual transmission of the packet. The packet is + * contained in the pbuf that is passed to the function. This pbuf + * might be chained. + * + * @param netif the lwip network interface structure for this ethernetif + * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) + * @return ERR_OK if the packet could be sent + * an err_t value if the packet couldn't be sent + * + * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to + * strange results. You might consider waiting for space in the DMA queue + * to become availale since the stack doesn't retry to send a packet + * dropped because of memory failure (except for the TCP timers). + */ + +static err_t +low_level_output(struct netif *netif, struct pbuf *p) +{ + struct pbuf *q; + u8_t *buf = NULL; + u16_t len = 0; + + + buf = ETH_get_tx_buf(); + if(buf == NULL) + return ERR_MEM; +#if ETH_PAD_SIZE + pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ +#endif + + for(q = p; q != NULL; q = q->next) { + memcpy((u8_t*)&buf[len], q->payload, q->len); + len = len + q->len; + } +#ifdef TIME_STAMPING + ETH_trigger_tx(len, p->flags & PBUF_FLAG_GET_TXTS ? p : NULL); +#else + ETH_trigger_tx(len, NULL); +#endif + +#if ETH_PAD_SIZE + pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ +#endif + + LINK_STATS_INC(link.xmit); + + return ERR_OK; +} + +/** + * Should allocate a pbuf and transfer the bytes of the incoming + * packet from the interface into the pbuf. + * + * @param netif the lwip network interface structure for this ethernetif + * @return a pbuf filled with the received packet (including MAC header) + * NULL on memory error + */ +static struct pbuf * +low_level_input(struct netif *netif, u16_t len, u8_t *buf) +{ + struct pbuf *p, *q; + +#if ETH_PAD_SIZE + len += ETH_PAD_SIZE; /* allow room for Ethernet padding */ +#endif + + /* We allocate a pbuf chain of pbufs from the pool. */ + p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); + + if (p != NULL) { + +#if ETH_PAD_SIZE + pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ +#endif + + + len = 0; + /* We iterate over the pbuf chain until we have read the entire + * packet into the pbuf. */ + for(q = p; q != NULL; q = q->next) { + memcpy((u8_t*)q->payload, (u8_t*)&buf[len], q->len); + len = len + q->len; + } + + +#if ETH_PAD_SIZE + pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ +#endif + + LINK_STATS_INC(link.recv); + } else { + // do nothing. drop the packet + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + } + + return p; +} + +/** + * This function should be called when a packet is ready to be read + * from the interface. It uses the function low_level_input() that + * should handle the actual reception of bytes from the network + * interface. Then the type of the received packet is determined and + * the appropriate input function is called. + * + * @param netif the lwip network interface structure for this ethernetif + */ +void +ethernetif_input(u16_t len, u8_t *buf, u32_t s, u32_t ns) +{ + struct eth_hdr *ethhdr; + struct pbuf *p; + + + /* move received packet into a new pbuf */ + p = low_level_input(_netif, len, buf); + /* no packet could be read, silently ignore this */ + if (p == NULL) return; +#ifdef TIME_STAMPING + p->ts_sec = s; + p->ts_nsec = ns; +#endif + + /* points to packet payload, which starts with an Ethernet header */ + ethhdr = p->payload; + + switch (htons(ethhdr->type)) { + /* IP or ARP packet? */ + case ETHTYPE_IP: + case ETHTYPE_ARP: +#if PPPOE_SUPPORT + /* PPPoE packet? */ + case ETHTYPE_PPPOEDISC: + case ETHTYPE_PPPOE: +#endif /* PPPOE_SUPPORT */ + /* full packet send to tcpip_thread to process */ + if (_netif->input(p, _netif)!=ERR_OK) { + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); + pbuf_free(p); + p = NULL; + } + break; + + default: + pbuf_free(p); + p = NULL; + break; + } +} + +#ifdef TIME_STAMPING +void +ethernetif_loopback_input(struct pbuf *p) // TODO: make sure packet not drop in input() +{ + /* pass all packets to ethernet_input, which decides what packets it supports */ + if (netif->input(p, netif) != ERR_OK) { + LWIP_DEBUGF(NETIF_DEBUG, ("k64f_enetif_input: input error\n")); + /* Free buffer */ + pbuf_free(p); + } +} + +#endif + +/** + * Should be called at the beginning of the program to set up the + * network interface. It calls the function low_level_init() to do the + * actual setup of the hardware. + * + * This function should be passed as a parameter to netif_add(). + * + * @param netif the lwip network interface structure for this ethernetif + * @return ERR_OK if the loopif is initialized + * ERR_MEM if private data couldn't be allocated + * any other err_t on error + */ +err_t + eth_arch_enetif_init(struct netif *netif) +{ + err_t err; + struct ethernetif *ethernetif; + + LWIP_ASSERT("netif != NULL", (netif != NULL)); + + _netif = netif; + ethernetif = mem_malloc(sizeof(struct ethernetif)); + if (ethernetif == NULL) { + LWIP_DEBUGF(NETIF_DEBUG, (" eth_arch_enetif_init: out of memory\n")); + return ERR_MEM; + } + + // Chris: The initialization code uses osDelay, so timers neet to run + // SysTick_Init(); + +#if LWIP_NETIF_HOSTNAME + /* Initialize interface hostname */ + netif->hostname = "m480"; +#endif /* LWIP_NETIF_HOSTNAME */ + + /* + * Initialize the snmp variables and counters inside the struct netif. + * The last argument should be replaced with your link speed, in units + * of bits per second. + */ + NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS); + + netif->state = ethernetif; + netif->name[0] = IFNAME0; + netif->name[1] = IFNAME1; + /* We directly use etharp_output() here to save a function call. + * You can instead declare your own function an call etharp_output() + * from it if you have to do some checks before sending (e.g. if link + * is available...) */ +#if LWIP_IPV4 + netif->output = etharp_output; +#endif +#if LWIP_IPV6 + netif->output_ip6 = ethip6_output; +#endif + netif->linkoutput = low_level_output; + + ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]); + + /* initialize the hardware */ + low_level_init(netif); + + /* Packet receive task */ + + err = sys_sem_new(&RxReadySem, 0); + if(err != ERR_OK) LWIP_ASSERT("RxReadySem creation error", (err == ERR_OK)); + // In GCC code, DEFAULT_THREAD_STACKSIZE 512 bytes is not enough for rx_task +#if defined (__GNUC__) + // mbed OS 2.0, DEFAULT_THREAD_STACKSIZE*3 + // mbed OS 5.0, DEFAULT_THREAD_STACKSIZE*5 + sys_thread_new("receive_thread", __packet_rx_task, &RxReadySem, DEFAULT_THREAD_STACKSIZE*5, osPriorityNormal); +#else + sys_thread_new("receive_thread", __packet_rx_task, &RxReadySem, DEFAULT_THREAD_STACKSIZE, osPriorityNormal); +#endif + /* PHY monitoring task */ +#if defined (__GNUC__) + // mbed OS 2.0, DEFAULT_THREAD_STACKSIZE + // mbed OS 5.0, DEFAULT_THREAD_STACKSIZE*2 + sys_thread_new("phy_thread", __phy_task, netif, DEFAULT_THREAD_STACKSIZE*2, osPriorityNormal); +#else + sys_thread_new("phy_thread", __phy_task, netif, DEFAULT_THREAD_STACKSIZE, osPriorityNormal); +#endif + /* Allow the PHY task to detect the initial link state and set up the proper flags */ + osDelay(10); + + return ERR_OK; +} + +void eth_arch_enable_interrupts(void) { +// enet_hal_config_interrupt(BOARD_DEBUG_ENET_INSTANCE_ADDR, (kEnetTxFrameInterrupt | kEnetRxFrameInterrupt), true); + EMAC->INTEN |= EMAC_INTEN_RXIEN_Msk | + EMAC_INTEN_TXIEN_Msk ; + NVIC_EnableIRQ(EMAC_RX_IRQn); + NVIC_EnableIRQ(EMAC_TX_IRQn); +} + +void eth_arch_disable_interrupts(void) { + NVIC_DisableIRQ(EMAC_RX_IRQn); + NVIC_DisableIRQ(EMAC_TX_IRQn); +} + + +/* Defines the PHY link speed */ +typedef enum _phy_speed +{ + kPHY_Speed10M = 0U, /* ENET PHY 10M speed. */ + kPHY_Speed100M /* ENET PHY 100M speed. */ +} phy_speed_t; + +/* Defines the PHY link duplex. */ +typedef enum _phy_duplex +{ + kPHY_HalfDuplex = 0U, /* ENET PHY half duplex. */ + kPHY_FullDuplex /* ENET PHY full duplex. */ +} phy_duplex_t; + +typedef struct { + int connected; + phy_speed_t speed; + phy_duplex_t duplex; +} PHY_STATE; + +#define STATE_UNKNOWN (-1) + +static void __phy_task(void *data) { + struct netif *netif = (struct netif*)data; +// PHY_STATE crt_state = {STATE_UNKNOWN, (phy_speed_t)STATE_UNKNOWN, (phy_duplex_t)STATE_UNKNOWN}; +// PHY_STATE prev_state; + +// prev_state = crt_state; + while (1) { + // Get current status + // Get the actual PHY link speed + // Compare with previous state + + if( !(ETH_link_ok()) && (netif->flags & NETIF_FLAG_LINK_UP) ) { + //tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_down, (void*) netif, 1); + netif_set_link_down(netif); + printf("Link Down\r\n"); + }else if ( ETH_link_ok() && !(netif->flags & NETIF_FLAG_LINK_UP) ) { + //tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_up, (void*) netif, 1); + netif_set_link_up(netif); + printf("Link Up\r\n"); + } + +// printf("-"); + osDelay(200); + } +} + +void ack_emac_rx_isr() +{ + sys_sem_signal(&RxReadySem); +} + +static void __packet_rx_task(void *data) { + + while (1) { + /* Wait for receive task to wakeup */ + sys_arch_sem_wait(&RxReadySem, 0); + EMAC_RX_Action(); + } +} diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NUVOTON/TARGET_M480/m480_netif.h b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NUVOTON/TARGET_M480/m480_netif.h new file mode 100644 index 0000000000..0adcc7ad78 --- /dev/null +++ b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_NUVOTON/TARGET_M480/m480_netif.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2016 Nuvoton Technology Corp. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Description: EMAC driver header file + */ +#ifndef __ETHERNETIF_H__ +#define __ETHERNETIF_H__ + + +#include "lwip/err.h" +#include "lwip/netif.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +//extern sys_sem_t tx_sem; +extern sys_sem_t rx_sem; + +//err_t ethernetif_init(struct netif *netif); +//err_t ethernetif_input(struct netif *netif); +//struct netif *ethernetif_register(void); +//int ethernetif_poll(void); + +#if defined(__cplusplus) +} +#endif + +#ifdef SERVER + +#define MAC_ADDR0 0x00 +#define MAC_ADDR1 0x00 +#define MAC_ADDR2 0x00 +#define MAC_ADDR3 0x00 +#define MAC_ADDR4 0x00 +#define MAC_ADDR5 0x01 + +#else + +#define MAC_ADDR0 0x00 +#define MAC_ADDR1 0x00 +#define MAC_ADDR2 0x00 +#define MAC_ADDR3 0x00 +#define MAC_ADDR4 0x00 +//#define MAC_ADDR5 0x02 +#define MAC_ADDR5 0x03 +//#define MAC_ADDR5 0x04 + +#endif + +#endif diff --git a/targets/TARGET_NUVOTON/TARGET_M480/can_api.c b/targets/TARGET_NUVOTON/TARGET_M480/can_api.c new file mode 100644 index 0000000000..ad97cc2425 --- /dev/null +++ b/targets/TARGET_NUVOTON/TARGET_M480/can_api.c @@ -0,0 +1,355 @@ +/* mbed Microcontroller Library + * Copyright (c) 2015-2016 Nuvoton + * + * 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 "can_api.h" + #include "m480_gpio.h" + #include "m480_can.h" + + #if DEVICE_CAN + #include + #include "cmsis.h" + #include "pinmap.h" + #include "PeripheralPins.h" + #include "nu_modutil.h" + #include "nu_miscutil.h" + #include "nu_bitutil.h" + #include "critical.h" + + #define NU_CAN_DEBUG 0 + #define CAN_NUM 2 + + static uint32_t can_irq_ids[CAN_NUM] = {0}; + static can_irq_handler can0_irq_handler; + static can_irq_handler can1_irq_handler; + +extern uint32_t CAN_GetCANBitRate(CAN_T *tCAN); +extern void CAN_EnterInitMode(CAN_T *tCAN, uint8_t u8Mask); +extern void CAN_LeaveInitMode(CAN_T *tCAN); +extern void CAN_LeaveTestMode(CAN_T *tCAN); +extern void CAN_EnterTestMode(CAN_T *tCAN, uint8_t u8TestMask); + + static const struct nu_modinit_s can_modinit_tab[] = { + {CAN_0, CAN0_MODULE, 0, 0, CAN0_RST, CAN0_IRQn, NULL}, + {CAN_1, CAN1_MODULE, 0, 0, CAN1_RST, CAN1_IRQn, NULL}, + + {NC, 0, 0, 0, 0, (IRQn_Type) 0, NULL} +}; + + + void can_init(can_t *obj, PinName rd, PinName td) + { + uint32_t can_td = (CANName)pinmap_peripheral(td, PinMap_CAN_TD); + uint32_t can_rd = (CANName)pinmap_peripheral(rd, PinMap_CAN_RD); + obj->can = (CANName)pinmap_merge(can_td, can_rd); + MBED_ASSERT((int)obj->can != NC); + + const struct nu_modinit_s *modinit = get_modinit(obj->can, can_modinit_tab); + MBED_ASSERT(modinit != NULL); + MBED_ASSERT(modinit->modname == obj->can); + + // Reset this module + SYS_ResetModule(modinit->rsetidx); + + // Enable IP clock + CLK_EnableModuleClock(modinit->clkidx); + + if(obj->can == CAN_1) { + obj->index = 1; + } + else + obj->index = 0; + + pinmap_pinout(td, PinMap_CAN_TD); + pinmap_pinout(rd, PinMap_CAN_RD); +#if 0 + /* TBD: For M487 mbed Board Transmitter Setting (RS Pin) */ + GPIO_SetMode(PA, BIT2| BIT3, GPIO_MODE_OUTPUT); + PA2 = 0x00; + PA3 = 0x00; +#endif + CAN_Open((CAN_T *)obj->can, 500000, CAN_NORMAL_MODE); + + can_filter(obj, 0, 0, CANStandard, 0); + } + + +void can_free(can_t *obj) +{ + + const struct nu_modinit_s *modinit = get_modinit(obj->can, can_modinit_tab); + + MBED_ASSERT(modinit != NULL); + MBED_ASSERT(modinit->modname == obj->can); + + // Reset this module + SYS_ResetModule(modinit->rsetidx); + + CLK_DisableModuleClock(modinit->clkidx); +} + +int can_frequency(can_t *obj, int hz) +{ + CAN_SetBaudRate((CAN_T *)obj->can, hz); + + return CAN_GetCANBitRate((CAN_T *)obj->can); +} + +static void can_irq(CANName name, int id) +{ + + CAN_T *can = (CAN_T *)NU_MODBASE(name); + uint32_t u8IIDRstatus; + + u8IIDRstatus = can->IIDR; + + if(u8IIDRstatus == 0x00008000) { /* Check Status Interrupt Flag (Error status Int and Status change Int) */ + /**************************/ + /* Status Change interrupt*/ + /**************************/ + if(can->STATUS & CAN_STATUS_RXOK_Msk) { + can->STATUS &= ~CAN_STATUS_RXOK_Msk; /* Clear Rx Ok status*/ + if(id) + can1_irq_handler(can_irq_ids[id] , IRQ_RX); + else + can0_irq_handler(can_irq_ids[id], IRQ_RX); + } + + if(can->STATUS & CAN_STATUS_TXOK_Msk) { + can->STATUS &= ~CAN_STATUS_TXOK_Msk; /* Clear Tx Ok status*/ + if(id) + can1_irq_handler(can_irq_ids[id] , IRQ_TX); + else + can0_irq_handler(can_irq_ids[id], IRQ_TX); + + } + + /**************************/ + /* Error Status interrupt */ + /**************************/ + if(can->STATUS & CAN_STATUS_EWARN_Msk) { + if(id) + can1_irq_handler(can_irq_ids[id] , IRQ_ERROR); + else + can0_irq_handler(can_irq_ids[id], IRQ_ERROR); + } + + if(can->STATUS & CAN_STATUS_BOFF_Msk) { + if(id) + can1_irq_handler(can_irq_ids[id] , IRQ_BUS); + else + can0_irq_handler(can_irq_ids[id], IRQ_BUS); + } + } else if (u8IIDRstatus!=0) { + + if(id) + can1_irq_handler(can_irq_ids[id] , IRQ_OVERRUN); + else + can0_irq_handler(can_irq_ids[id], IRQ_OVERRUN); + + CAN_CLR_INT_PENDING_BIT(can, ((can->IIDR) -1)); /* Clear Interrupt Pending */ + + } else if(can->WU_STATUS == 1) { + + can->WU_STATUS = 0; /* Write '0' to clear */ + if(id) + can1_irq_handler(can_irq_ids[id] , IRQ_WAKEUP); + else + can0_irq_handler(can_irq_ids[id], IRQ_WAKEUP); + } +} + +void CAN0_IRQHandler(void) +{ + can_irq(CAN_0, 0); +} + +void CAN1_IRQHandler(void) +{ + can_irq(CAN_1, 1); +} + +void can_irq_init(can_t *obj, can_irq_handler handler, uint32_t id) +{ + if(obj->index) + can1_irq_handler = handler; + else + can0_irq_handler = handler; + can_irq_ids[obj->index] = id; + +} + +void can_irq_free(can_t *obj) +{ + CAN_DisableInt((CAN_T *)obj->can, (CAN_CON_IE_Msk|CAN_CON_SIE_Msk|CAN_CON_EIE_Msk)); + + can_irq_ids[obj->index] = 0; + + if(!obj->index) + NVIC_DisableIRQ(CAN0_IRQn); + else + NVIC_DisableIRQ(CAN1_IRQn); + + +} + +void can_irq_set(can_t *obj, CanIrqType irq, uint32_t enable) +{ + uint8_t u8Mask; + + u8Mask = ((enable != 0 )? CAN_CON_IE_Msk :0); + + switch (irq) + { + case IRQ_ERROR: + case IRQ_BUS: + case IRQ_PASSIVE: + u8Mask = u8Mask | CAN_CON_EIE_Msk | CAN_CON_SIE_Msk; + break; + + case IRQ_RX: + case IRQ_TX: + case IRQ_OVERRUN: + case IRQ_WAKEUP: + u8Mask = u8Mask | CAN_CON_SIE_Msk; + break; + + default: + break; + + } + CAN_EnterInitMode((CAN_T*)obj->can, u8Mask); + + CAN_LeaveInitMode((CAN_T*)obj->can); + + if(!obj->index) + { + NVIC_SetVector(CAN0_IRQn, (uint32_t)&CAN0_IRQHandler); + NVIC_EnableIRQ(CAN0_IRQn); + } + else + { + NVIC_SetVector(CAN1_IRQn, (uint32_t)&CAN1_IRQHandler); + NVIC_EnableIRQ(CAN1_IRQn); + } + +} + +int can_write(can_t *obj, CAN_Message msg, int cc) +{ + STR_CANMSG_T CMsg; + + CMsg.IdType = (uint32_t)msg.format; + CMsg.FrameType = (uint32_t)!msg.type; + CMsg.Id = msg.id; + CMsg.DLC = msg.len; + memcpy((void *)&CMsg.Data[0],(const void *)&msg.data[0], (unsigned int)8); + + return CAN_Transmit((CAN_T *)(obj->can), cc, &CMsg); +} + +int can_read(can_t *obj, CAN_Message *msg, int handle) +{ + STR_CANMSG_T CMsg; + + if(!CAN_Receive((CAN_T *)(obj->can), handle, &CMsg)) + return 0; + + msg->format = (CANFormat)CMsg.IdType; + msg->type = (CANType)!CMsg.FrameType; + msg->id = CMsg.Id; + msg->len = CMsg.DLC; + memcpy(&msg->data[0], &CMsg.Data[0], 8); + + return 1; +} + +int can_mode(can_t *obj, CanMode mode) +{ + int success = 0; + switch (mode) + { + case MODE_RESET: + CAN_LeaveTestMode((CAN_T*)obj->can); + success = 1; + break; + + case MODE_NORMAL: + CAN_EnterTestMode((CAN_T*)(obj->can), CAN_TEST_BASIC_Msk); + success = 1; + break; + + case MODE_SILENT: + CAN_EnterTestMode((CAN_T*)(obj->can), CAN_TEST_SILENT_Msk); + success = 1; + break; + + case MODE_TEST_LOCAL: + case MODE_TEST_GLOBAL: + CAN_EnterTestMode((CAN_T*)(obj->can), CAN_TEST_LBACK_Msk); + success = 1; + break; + + case MODE_TEST_SILENT: + CAN_EnterTestMode((CAN_T*)(obj->can), CAN_TEST_SILENT_Msk | CAN_TEST_LBACK_Msk); + success = 1; + break; + + default: + success = 0; + break; + + } + + + return success; +} + +int can_filter(can_t *obj, uint32_t id, uint32_t mask, CANFormat format, int32_t handle) +{ + return CAN_SetRxMsg((CAN_T *)(obj->can), handle , (uint32_t)format, id); +} + + +void can_reset(can_t *obj) +{ + const struct nu_modinit_s *modinit = get_modinit(obj->can, can_modinit_tab); + + MBED_ASSERT(modinit != NULL); + MBED_ASSERT(modinit->modname == obj->can); + + // Reset this module + SYS_ResetModule(modinit->rsetidx); + +} + +unsigned char can_rderror(can_t *obj) +{ + CAN_T *can = (CAN_T *)(obj->can); + return ((can->ERR>>8)&0xFF); +} + +unsigned char can_tderror(can_t *obj) +{ + CAN_T *can = (CAN_T *)(obj->can); + return ((can->ERR)&0xFF); +} + +void can_monitor(can_t *obj, int silent) +{ + CAN_EnterTestMode((CAN_T *)(obj->can), CAN_TEST_SILENT_Msk); +} + +#endif // DEVICE_CAN diff --git a/targets/TARGET_NUVOTON/TARGET_M480/crypto/aes/aes_alt.c b/targets/TARGET_NUVOTON/TARGET_M480/crypto/aes/aes_alt.c new file mode 100644 index 0000000000..6dda342893 --- /dev/null +++ b/targets/TARGET_NUVOTON/TARGET_M480/crypto/aes/aes_alt.c @@ -0,0 +1,590 @@ +/* mbed Microcontroller Library + * Copyright (c) 2015-2016 Nuvoton + * + * 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. + */ + +/* + * The AES block cipher was designed by Vincent Rijmen and Joan Daemen. + * + * http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf + * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_AES_ALT) + +#include + +#include "mbedtls/aes.h" + +#include "M480.h" +#include "toolchain.h" +#include "mbed_assert.h" + +//static int aes_init_done = 0; + + +#define mbedtls_trace(...) //printf(__VA_ARGS__) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; +} + + +static uint32_t au32MyAESIV[4] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000 +}; + +extern volatile int g_AES_done; + +// Must be a multiple of 16 bytes block size +#define MAX_DMA_CHAIN_SIZE (16*6) +static uint8_t au8OutputData[MAX_DMA_CHAIN_SIZE] MBED_ALIGN(4); +static uint8_t au8InputData[MAX_DMA_CHAIN_SIZE] MBED_ALIGN(4); + +static void dumpHex(const unsigned char au8Data[], int len) +{ + int j; + for (j = 0; j < len; j++) mbedtls_trace("%02x ", au8Data[j]); + mbedtls_trace("\r\n"); +} + +static void swapInitVector(unsigned char iv[16]) +{ + unsigned int* piv; + int i; + // iv SWAP + piv = (unsigned int*)iv; + for( i=0; i< 4; i++) + { + *piv = (((*piv) & 0x000000FF) << 24) | + (((*piv) & 0x0000FF00) << 8) | + (((*piv) & 0x00FF0000) >> 8) | + (((*piv) & 0xFF000000) >> 24); + piv++; + } +} + +//volatile void CRYPTO_IRQHandler() +//{ +// if (AES_GET_INT_FLAG()) { +// g_AES_done = 1; +// AES_CLR_INT_FLAG(); +// } +//} + +// AES available channel 0~3 +static unsigned char channel_flag[4]={0x00,0x00,0x00,0x00}; // 0: idle, 1: busy +static int channel_alloc() +{ + int i; + for(i=0; i< (int)sizeof(channel_flag); i++) + { + if( channel_flag[i] == 0x00 ) + { + channel_flag[i] = 0x01; + return i; + } + } + return(-1); +} + +static void channel_free(int i) +{ + if( i >=0 && i < (int)sizeof(channel_flag) ) + channel_flag[i] = 0x00; +} + + +void mbedtls_aes_init( mbedtls_aes_context *ctx ) +{ + int i =-1; + +// sw_mbedtls_aes_init(ctx); +// return; + + mbedtls_trace("=== %s \r\n", __FUNCTION__); + memset( ctx, 0, sizeof( mbedtls_aes_context ) ); + + ctx->swapType = AES_IN_OUT_SWAP; + while( (i = channel_alloc()) < 0 ) + { + mbed_assert_internal("No available AES channel", __FILE__, __LINE__); + //osDelay(300); + } + ctx->channel = i; + ctx->iv = au32MyAESIV; + + /* Unlock protected registers */ + SYS_UnlockReg(); + CLK_EnableModuleClock(CRYPTO_MODULE); + /* Lock protected registers */ + SYS_LockReg(); + + NVIC_EnableIRQ(CRPT_IRQn); + AES_ENABLE_INT(); + mbedtls_trace("=== %s channel[%d]\r\n", __FUNCTION__, (int)ctx->channel); +} + +void mbedtls_aes_free( mbedtls_aes_context *ctx ) +{ + + mbedtls_trace("=== %s channel[%d]\r\n", __FUNCTION__,(int)ctx->channel); + + if( ctx == NULL ) + return; + + /* Unlock protected registers */ +// SYS_UnlockReg(); +// CLK_DisableModuleClock(CRPT_MODULE); + /* Lock protected registers */ +// SYS_LockReg(); + +// NVIC_DisableIRQ(CRPT_IRQn); +// AES_DISABLE_INT(); + channel_free(ctx->channel); + mbedtls_zeroize( ctx, sizeof( mbedtls_aes_context ) ); +} + +/* + * AES key schedule (encryption) + */ +#if defined(MBEDTLS_AES_SETKEY_ENC_ALT) +int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + unsigned int i; + + mbedtls_trace("=== %s keybits[%d]\r\n", __FUNCTION__, keybits); + dumpHex(key,keybits/8); + + switch( keybits ) + { + case 128: + ctx->keySize = AES_KEY_SIZE_128; + break; + case 192: + ctx->keySize = AES_KEY_SIZE_192; + break; + case 256: + ctx->keySize = AES_KEY_SIZE_256; + break; + default : return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH ); + } + + + + // key swap + for( i = 0; i < ( keybits >> 5 ); i++ ) + { + ctx->buf[i] = (*(key+i*4) << 24) | + (*(key+1+i*4) << 16) | + (*(key+2+i*4) << 8) | + (*(key+3+i*4) ); + } + AES_SetKey(ctx->channel, ctx->buf, ctx->keySize); + + + return( 0 ); +} +#endif /* MBEDTLS_AES_SETKEY_ENC_ALT */ + +/* + * AES key schedule (decryption) + */ +#if defined(MBEDTLS_AES_SETKEY_DEC_ALT) +int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + int ret; + + mbedtls_trace("=== %s keybits[%d]\r\n", __FUNCTION__, keybits); + dumpHex((uint8_t *)key,keybits/8); + + /* Also checks keybits */ + if( ( ret = mbedtls_aes_setkey_enc( ctx, key, keybits ) ) != 0 ) + goto exit; + +exit: + + return( ret ); +} +#endif /* MBEDTLS_AES_SETKEY_DEC_ALT */ + + +static void __nvt_aes_crypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16], int dataSize) +{ + unsigned char* pIn; + unsigned char* pOut; + +// mbedtls_trace("=== %s \r\n", __FUNCTION__); + dumpHex(input,16); + + AES_Open(ctx->channel, ctx->encDec, ctx->opMode, ctx->keySize, ctx->swapType); + AES_SetInitVect(ctx->channel, ctx->iv); + if( ((uint32_t)input) & 0x03 ) + { + memcpy(au8InputData, input, dataSize); + pIn = au8InputData; + }else{ + pIn = (unsigned char*)input; + } + if( (((uint32_t)output) & 0x03) || (dataSize%4)) // HW CFB output byte count must be multiple of word + { + pOut = au8OutputData; + } else { + pOut = output; + } + + AES_SetDMATransfer(ctx->channel, (uint32_t)pIn, (uint32_t)pOut, dataSize); + + g_AES_done = 0; + AES_Start(ctx->channel, CRYPTO_DMA_ONE_SHOT); + while (!g_AES_done); + + if( pOut != output ) memcpy(output, au8OutputData, dataSize); + dumpHex(output,16); + +} + +/* + * AES-ECB block encryption + */ +#if defined(MBEDTLS_AES_ENCRYPT_ALT) +void mbedtls_aes_encrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + + mbedtls_trace("=== %s \r\n", __FUNCTION__); + + ctx->encDec = 1; + __nvt_aes_crypt(ctx, input, output, 16); + +} +#endif /* MBEDTLS_AES_ENCRYPT_ALT */ + +/* + * AES-ECB block decryption + */ +#if defined(MBEDTLS_AES_DECRYPT_ALT) +void mbedtls_aes_decrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + + mbedtls_trace("=== %s \r\n", __FUNCTION__); + + ctx->encDec = 0; + __nvt_aes_crypt(ctx, input, output, 16); + + +} +#endif /* MBEDTLS_AES_DECRYPT_ALT */ + +/* + * AES-ECB block encryption/decryption + */ +int mbedtls_aes_crypt_ecb( mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ + + mbedtls_trace("=== %s \r\n", __FUNCTION__); + + ctx->opMode = AES_MODE_ECB; + if( mode == MBEDTLS_AES_ENCRYPT ) + mbedtls_aes_encrypt( ctx, input, output ); + else + mbedtls_aes_decrypt( ctx, input, output ); + + + return( 0 ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * AES-CBC buffer encryption/decryption + */ +int mbedtls_aes_crypt_cbc( mbedtls_aes_context *ctx, + int mode, + size_t len, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + unsigned char temp[16]; + int length = len; + int blockChainLen; + mbedtls_trace("=== %s [0x%x]\r\n", __FUNCTION__,length); + if( length % 16 ) + return( MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH ); + + if( (((uint32_t)input) & 0x03) || (((uint32_t)output) & 0x03) ) + { + blockChainLen = (( length > MAX_DMA_CHAIN_SIZE ) ? MAX_DMA_CHAIN_SIZE : length ); + } else { + blockChainLen = length; + } + + while( length > 0 ) + { + ctx->opMode = AES_MODE_CBC; + swapInitVector(iv); // iv SWAP + ctx->iv = (uint32_t *)iv; + + if( mode == MBEDTLS_AES_ENCRYPT ) + { + ctx->encDec = 1; + __nvt_aes_crypt(ctx, input, output, blockChainLen); +// if( blockChainLen == length ) break; // finish last block chain but still need to prepare next iv for mbedtls_aes_self_test() + memcpy( iv, output+blockChainLen-16, 16 ); + }else{ + memcpy( temp, input+blockChainLen-16, 16 ); + ctx->encDec = 0; + __nvt_aes_crypt(ctx, input, output, blockChainLen); +// if( blockChainLen == length ) break; // finish last block chain but still need to prepare next iv for mbedtls_aes_self_test() + memcpy( iv, temp, 16 ); + } + length -= blockChainLen; + input += blockChainLen; + output += blockChainLen; + if(length < MAX_DMA_CHAIN_SIZE ) blockChainLen = length; // For last remainder block chain + + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * AES-CFB128 buffer encryption/decryption + */ +/* Support partial block encryption/decryption */ +static int __nvt_aes_crypt_partial_block_cfb128( mbedtls_aes_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int c; + size_t n = *iv_off; + unsigned char iv_tmp[16]; + mbedtls_trace("=== %s \r\n", __FUNCTION__); + if( mode == MBEDTLS_AES_DECRYPT ) + { + while( length-- ) + { + if( n == 0) + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + else if( ctx->opMode == AES_MODE_CFB) // For previous cryption is CFB mode + { + memcpy(iv_tmp, iv, n); + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, ctx->prv_iv, iv ); + memcpy(iv, iv_tmp, n); + } + + c = *input++; + *output++ = (unsigned char)( c ^ iv[n] ); + iv[n] = (unsigned char) c; + + n = ( n + 1 ) & 0x0F; + } + } + else + { + while( length-- ) + { + if( n == 0 ) + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + else if( ctx->opMode == AES_MODE_CFB) // For previous cryption is CFB mode + { + memcpy(iv_tmp, iv, n); + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, ctx->prv_iv, iv ); + memcpy(iv, iv_tmp, n); + } + + iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); + + n = ( n + 1 ) & 0x0F; + } + } + + *iv_off = n; + + return( 0 ); +} + +int mbedtls_aes_crypt_cfb128( mbedtls_aes_context *ctx, + int mode, + size_t len, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + size_t n = *iv_off; + unsigned char temp[16]; + int length=len; + int blockChainLen; + int remLen=0; + int ivLen; + + mbedtls_trace("=== %s \r\n", __FUNCTION__); + + // proceed: start with partial block by ECB mode first + if( n !=0 ) { + __nvt_aes_crypt_partial_block_cfb128(ctx, mode, 16 - n , iv_off, iv, input, output); + input += (16 - n); + output += (16 - n); + length -= (16 - n); + } + + // For address or byte count non-word alignment, go through reserved DMA buffer. + if( (((uint32_t)input) & 0x03) || (((uint32_t)output) & 0x03) ) // Must reserved DMA buffer for each block + { + blockChainLen = (( length > MAX_DMA_CHAIN_SIZE ) ? MAX_DMA_CHAIN_SIZE : length ); + } else if(length%4) { // Need reserved DMA buffer once for last chain + blockChainLen = (( length > MAX_DMA_CHAIN_SIZE ) ? (length - length%16) : length ); + } else { // Not need reserved DMA buffer + blockChainLen = length; + } + + // proceed: start with block alignment + while( length > 0 ) + { + + ctx->opMode = AES_MODE_CFB; + + swapInitVector(iv); // iv SWAP + + ctx->iv = (uint32_t *)iv; + remLen = blockChainLen%16; + ivLen = (( remLen > 0) ? remLen: 16 ); + + if( mode == MBEDTLS_AES_DECRYPT ) + { + memcpy(temp, input+blockChainLen - ivLen, ivLen); + if(blockChainLen >= 16) memcpy(ctx->prv_iv, input+blockChainLen-remLen-16 , 16); + ctx->encDec = 0; + __nvt_aes_crypt(ctx, input, output, blockChainLen); + memcpy(iv,temp, ivLen); + } + else + { + ctx->encDec = 1; + __nvt_aes_crypt(ctx, input, output, blockChainLen); + if(blockChainLen >= 16) memcpy(ctx->prv_iv, output+blockChainLen-remLen-16 , 16); + memcpy(iv,output+blockChainLen-ivLen,ivLen); + } + length -= blockChainLen; + input += blockChainLen; + output += blockChainLen; + if(length < MAX_DMA_CHAIN_SIZE ) blockChainLen = length; // For last remainder block chain + } + + *iv_off = remLen; + + return( 0 ); +} + + +/* + * AES-CFB8 buffer encryption/decryption + */ +int mbedtls_aes_crypt_cfb8( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + unsigned char c; + unsigned char ov[17]; + + mbedtls_trace("=== %s \r\n", __FUNCTION__); + while( length-- ) + { + memcpy( ov, iv, 16 ); + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + + if( mode == MBEDTLS_AES_DECRYPT ) + ov[16] = *input; + + c = *output++ = (unsigned char)( iv[0] ^ *input++ ); + + if( mode == MBEDTLS_AES_ENCRYPT ) + ov[16] = c; + + memcpy( iv, ov + 1, 16 ); + } + + return( 0 ); +} +#endif /*MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * AES-CTR buffer encryption/decryption + */ +int mbedtls_aes_crypt_ctr( mbedtls_aes_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ) +{ + int c, i; + size_t n = *nc_off; + + mbedtls_trace("=== %s \r\n", __FUNCTION__); + while( length-- ) + { + if( n == 0 ) { + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, nonce_counter, stream_block ); + + for( i = 16; i > 0; i-- ) + if( ++nonce_counter[i - 1] != 0 ) + break; + } + c = *input++; + *output++ = (unsigned char)( c ^ stream_block[n] ); + + n = ( n + 1 ) & 0x0F; + } + + *nc_off = n; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#endif /* MBEDTLS_AES_ALT */ + + +#endif /* MBEDTLS_AES_C */ diff --git a/targets/TARGET_NUVOTON/TARGET_M480/crypto/aes/aes_alt.h b/targets/TARGET_NUVOTON/TARGET_M480/crypto/aes/aes_alt.h new file mode 100644 index 0000000000..25a8ca5311 --- /dev/null +++ b/targets/TARGET_NUVOTON/TARGET_M480/crypto/aes/aes_alt.h @@ -0,0 +1,274 @@ +/** + * \file aes_alt.h + * + * \brief AES block cipher + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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 part of mbed TLS (https://tls.mbed.org) + */ + +#if defined(MBEDTLS_AES_ALT) +// Regular implementation +// +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief AES context structure + * + * \note buf is able to hold 32 extra bytes, which can be used: + * - for alignment purposes if VIA padlock is used, and/or + * - to simplify key expansion in the 256-bit case by + * generating an extra round key + */ +typedef struct +{ + uint32_t keySize; + uint32_t encDec; + uint32_t opMode; + uint32_t channel; + uint32_t swapType; + uint32_t *iv; + unsigned char prv_iv[16]; +#if 1 + uint32_t buf[8]; +/* For comparsion with software AES for correctness */ +#else + uint32_t buf[68]; /*!< unaligned data */ + int nr; /*!< number of rounds */ + uint32_t *rk; /*!< AES round keys */ +#endif +} +mbedtls_aes_context; + +/** + * \brief Initialize AES context + * + * \param ctx AES context to be initialized + */ +void mbedtls_aes_init( mbedtls_aes_context *ctx ); + +/** + * \brief Clear AES context + * + * \param ctx AES context to be cleared + */ +void mbedtls_aes_free( mbedtls_aes_context *ctx ); + +/** + * \brief AES key schedule (encryption) + * + * \param ctx AES context to be initialized + * \param key encryption key + * \param keybits must be 128, 192 or 256 + * + * \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_KEY_LENGTH + */ +int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ); + +/** + * \brief AES key schedule (decryption) + * + * \param ctx AES context to be initialized + * \param key decryption key + * \param keybits must be 128, 192 or 256 + * + * \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_KEY_LENGTH + */ +int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ); + +/** + * \brief AES-ECB block encryption/decryption + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 if successful + */ +int mbedtls_aes_crypt_ecb( mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief AES-CBC buffer encryption/decryption + * Length should be a multiple of the block + * size (16 bytes) + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH + */ +int mbedtls_aes_crypt_cbc( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/** + * \brief AES-CFB128 buffer encryption/decryption. + * + * Note: Due to the nature of CFB you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * mbedtls_aes_setkey_enc() for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param length length of the input data + * \param iv_off offset in IV (updated after use) + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful + */ +int mbedtls_aes_crypt_cfb128( mbedtls_aes_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +/** + * \brief AES-CFB8 buffer encryption/decryption. + * + * Note: Due to the nature of CFB you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * mbedtls_aes_setkey_enc() for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful + */ +int mbedtls_aes_crypt_cfb8( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); +#endif /*MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/** + * \brief AES-CTR buffer encryption/decryption + * + * Warning: You have to keep the maximum use of your counter in mind! + * + * Note: Due to the nature of CTR you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * mbedtls_aes_setkey_enc() for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT. + * + * \param ctx AES context + * \param length The length of the data + * \param nc_off The offset in the current stream_block (for resuming + * within current cipher stream). The offset pointer to + * should be 0 at the start of a stream. + * \param nonce_counter The 128-bit nonce and counter. + * \param stream_block The saved stream-block for resuming. Is overwritten + * by the function. + * \param input The input data stream + * \param output The output data stream + * + * \return 0 if successful + */ +int mbedtls_aes_crypt_ctr( mbedtls_aes_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +/** + * \brief Internal AES block encryption function + * (Only exposed to allow overriding it, + * see MBEDTLS_AES_ENCRYPT_ALT) + * + * \param ctx AES context + * \param input Plaintext block + * \param output Output (ciphertext) block + */ +void mbedtls_aes_encrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ); + +/** + * \brief Internal AES block decryption function + * (Only exposed to allow overriding it, + * see MBEDTLS_AES_DECRYPT_ALT) + * + * \param ctx AES context + * \param input Ciphertext block + * \param output Output (plaintext) block + */ +void mbedtls_aes_decrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ); + +#ifdef __cplusplus +} +#endif + + +#endif /* MBEDTLS_AES_ALT */ + + diff --git a/targets/TARGET_NUVOTON/TARGET_M480/trng_api.c b/targets/TARGET_NUVOTON/TARGET_M480/trng_api.c index 92d7b9f248..39e6bec86c 100644 --- a/targets/TARGET_NUVOTON/TARGET_M480/trng_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M480/trng_api.c @@ -26,12 +26,16 @@ * Get Random number generator. */ static volatile int g_PRNG_done; +volatile int g_AES_done; void CRYPTO_IRQHandler() { if (PRNG_GET_INT_FLAG()) { g_PRNG_done = 1; PRNG_CLR_INT_FLAG(); + } else if (AES_GET_INT_FLAG()) { + g_AES_done = 1; + AES_CLR_INT_FLAG(); } } diff --git a/targets/targets.json b/targets/targets.json index 55de4995ca..669bd5c4d1 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -3264,7 +3264,8 @@ "is_disk_virtual": true, "supported_toolchains": ["ARM", "uARM", "GCC_ARM", "IAR"], "inherits": ["Target"], - "device_has": ["I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "STDIO_MESSAGES", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "TRNG"], + "device_has": ["I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "STDIO_MESSAGES", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "TRNG", "CAN"], + "features": ["LWIP"], "release_versions": ["5"], "device_name": "M487JIDAE" }