Merge pull request #3883 from bigmagic123/ls2k_add_gmac

Ls2k add gmac
This commit is contained in:
Bernard Xiong 2020-09-11 13:33:16 +08:00 committed by GitHub
commit de0bb6f96c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 9225 additions and 204 deletions

View File

@ -19,6 +19,7 @@ env = Environment(tools = ['mingw'],
AR = rtconfig.AR, ARFLAGS = '-rc',
LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS)
env.PrependENVPath('PATH', rtconfig.EXEC_PATH)
env['ASCOM'] = env['ASPPCOM']
Export('RTT_ROOT')
Export('rtconfig')

View File

@ -12,7 +12,6 @@ from building import *
TARGET = 'rtthread.' + rtconfig.TARGET_EXT
rtconfig.AFLAGS += ' -I' + str(Dir('#'))
DefaultEnvironment(tools=[])
env = Environment(tools = ['mingw'],
@ -21,6 +20,7 @@ env = Environment(tools = ['mingw'],
AR = rtconfig.AR, ARFLAGS = '-rc',
LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS)
env.PrependENVPath('PATH', rtconfig.EXEC_PATH)
env['ASCOM'] = env['ASPPCOM']
Export('RTT_ROOT')
Export('rtconfig')

View File

@ -6,7 +6,7 @@
#
# RT-Thread Kernel
#
CONFIG_RT_NAME_MAX=8
CONFIG_RT_NAME_MAX=30
# CONFIG_RT_USING_ARCH_DATA_TYPE is not set
# CONFIG_RT_USING_SMP is not set
CONFIG_RT_ALIGN_SIZE=8
@ -14,12 +14,12 @@ CONFIG_RT_ALIGN_SIZE=8
CONFIG_RT_THREAD_PRIORITY_32=y
# CONFIG_RT_THREAD_PRIORITY_256 is not set
CONFIG_RT_THREAD_PRIORITY_MAX=32
CONFIG_RT_TICK_PER_SECOND=100
CONFIG_RT_TICK_PER_SECOND=1000
CONFIG_RT_USING_OVERFLOW_CHECK=y
CONFIG_RT_USING_HOOK=y
CONFIG_RT_USING_IDLE_HOOK=y
CONFIG_RT_IDLE_HOOK_LIST_SIZE=4
CONFIG_IDLE_THREAD_STACK_SIZE=2048
CONFIG_IDLE_THREAD_STACK_SIZE=16384
# CONFIG_RT_USING_TIMER_SOFT is not set
CONFIG_RT_DEBUG=y
# CONFIG_RT_DEBUG_COLOR is not set
@ -65,6 +65,7 @@ CONFIG_RT_USING_CONSOLE=y
CONFIG_RT_CONSOLEBUF_SIZE=256
CONFIG_RT_CONSOLE_DEVICE_NAME="uart"
CONFIG_RT_VER_NUM=0x40003
CONFIG_ARCH_CPU_64BIT=y
# CONFIG_RT_USING_CPU_FFS is not set
CONFIG_ARCH_MIPS64=y
# CONFIG_ARCH_CPU_STACK_GROWS_UPWARD is not set
@ -74,7 +75,7 @@ CONFIG_ARCH_MIPS64=y
#
CONFIG_RT_USING_COMPONENTS_INIT=y
CONFIG_RT_USING_USER_MAIN=y
CONFIG_RT_MAIN_THREAD_STACK_SIZE=2048
CONFIG_RT_MAIN_THREAD_STACK_SIZE=16384
CONFIG_RT_MAIN_THREAD_PRIORITY=10
#
@ -93,7 +94,7 @@ CONFIG_FINSH_USING_SYMTAB=y
CONFIG_FINSH_USING_DESCRIPTION=y
# CONFIG_FINSH_ECHO_DISABLE_DEFAULT is not set
CONFIG_FINSH_THREAD_PRIORITY=20
CONFIG_FINSH_THREAD_STACK_SIZE=4096
CONFIG_FINSH_THREAD_STACK_SIZE=16384
CONFIG_FINSH_CMD_SIZE=80
# CONFIG_FINSH_USING_AUTH is not set
CONFIG_FINSH_USING_MSH=y
@ -106,23 +107,42 @@ CONFIG_FINSH_ARG_MAX=10
#
CONFIG_RT_USING_DFS=y
CONFIG_DFS_USING_WORKDIR=y
CONFIG_DFS_FILESYSTEMS_MAX=2
CONFIG_DFS_FILESYSTEM_TYPES_MAX=2
CONFIG_DFS_FILESYSTEMS_MAX=10
CONFIG_DFS_FILESYSTEM_TYPES_MAX=10
CONFIG_DFS_FD_MAX=16
# CONFIG_RT_USING_DFS_MNTTABLE is not set
# CONFIG_RT_USING_DFS_ELMFAT is not set
CONFIG_RT_USING_DFS_ELMFAT=y
#
# elm-chan's FatFs, Generic FAT Filesystem Module
#
CONFIG_RT_DFS_ELM_CODE_PAGE=936
CONFIG_RT_DFS_ELM_WORD_ACCESS=y
# CONFIG_RT_DFS_ELM_USE_LFN_0 is not set
# CONFIG_RT_DFS_ELM_USE_LFN_1 is not set
# CONFIG_RT_DFS_ELM_USE_LFN_2 is not set
CONFIG_RT_DFS_ELM_USE_LFN_3=y
CONFIG_RT_DFS_ELM_USE_LFN=3
CONFIG_RT_DFS_ELM_MAX_LFN=255
CONFIG_RT_DFS_ELM_DRIVES=9
CONFIG_RT_DFS_ELM_MAX_SECTOR_SIZE=512
# CONFIG_RT_DFS_ELM_USE_ERASE is not set
CONFIG_RT_DFS_ELM_REENTRANT=y
CONFIG_RT_USING_DFS_DEVFS=y
# CONFIG_RT_USING_DFS_ROMFS is not set
# CONFIG_RT_USING_DFS_RAMFS is not set
# CONFIG_RT_USING_DFS_UFFS is not set
# CONFIG_RT_USING_DFS_JFFS2 is not set
# CONFIG_RT_USING_DFS_NFS is not set
#
# Device Drivers
#
CONFIG_RT_USING_DEVICE_IPC=y
CONFIG_RT_PIPE_BUFSZ=512
# CONFIG_RT_USING_SYSTEM_WORKQUEUE is not set
CONFIG_RT_USING_SYSTEM_WORKQUEUE=y
CONFIG_RT_SYSTEM_WORKQUEUE_STACKSIZE=16384
CONFIG_RT_SYSTEM_WORKQUEUE_PRIORITY=5
CONFIG_RT_USING_SERIAL=y
CONFIG_RT_SERIAL_USING_DMA=y
CONFIG_RT_SERIAL_RB_BUFSZ=64
@ -132,6 +152,7 @@ CONFIG_RT_SERIAL_RB_BUFSZ=64
# CONFIG_RT_USING_I2C is not set
CONFIG_RT_USING_PIN=y
# CONFIG_RT_USING_ADC is not set
# CONFIG_RT_USING_DAC is not set
# CONFIG_RT_USING_PWM is not set
# CONFIG_RT_USING_MTD_NOR is not set
# CONFIG_RT_USING_MTD_NAND is not set
@ -172,22 +193,91 @@ CONFIG_RT_USING_POSIX=y
#
# Socket abstraction layer
#
# CONFIG_RT_USING_SAL is not set
CONFIG_RT_USING_SAL=y
#
# protocol stack implement
#
CONFIG_SAL_USING_LWIP=y
# CONFIG_SAL_USING_POSIX is not set
CONFIG_SAL_SOCKETS_NUM=16
#
# Network interface device
#
# CONFIG_RT_USING_NETDEV is not set
CONFIG_RT_USING_NETDEV=y
CONFIG_NETDEV_USING_IFCONFIG=y
CONFIG_NETDEV_USING_PING=y
CONFIG_NETDEV_USING_NETSTAT=y
CONFIG_NETDEV_USING_AUTO_DEFAULT=y
# CONFIG_NETDEV_USING_IPV6 is not set
CONFIG_NETDEV_IPV4=1
CONFIG_NETDEV_IPV6=0
# CONFIG_NETDEV_IPV6_SCOPES is not set
#
# light weight TCP/IP stack
#
# CONFIG_RT_USING_LWIP is not set
CONFIG_RT_USING_LWIP=y
# CONFIG_RT_USING_LWIP141 is not set
CONFIG_RT_USING_LWIP202=y
# CONFIG_RT_USING_LWIP212 is not set
# CONFIG_RT_USING_LWIP_IPV6 is not set
CONFIG_RT_LWIP_MEM_ALIGNMENT=8
CONFIG_RT_LWIP_IGMP=y
CONFIG_RT_LWIP_ICMP=y
CONFIG_RT_LWIP_SNMP=y
CONFIG_RT_LWIP_DNS=y
CONFIG_RT_LWIP_DHCP=y
CONFIG_IP_SOF_BROADCAST=1
CONFIG_IP_SOF_BROADCAST_RECV=1
#
# Static IPv4 Address
#
CONFIG_RT_LWIP_IPADDR="192.168.1.30"
CONFIG_RT_LWIP_GWADDR="192.168.1.1"
CONFIG_RT_LWIP_MSKADDR="255.255.255.0"
CONFIG_RT_LWIP_UDP=y
CONFIG_RT_LWIP_TCP=y
CONFIG_RT_LWIP_RAW=y
# CONFIG_RT_LWIP_PPP is not set
CONFIG_RT_MEMP_NUM_NETCONN=8
CONFIG_RT_LWIP_PBUF_NUM=16
CONFIG_RT_LWIP_RAW_PCB_NUM=4
CONFIG_RT_LWIP_UDP_PCB_NUM=4
CONFIG_RT_LWIP_TCP_PCB_NUM=4
CONFIG_RT_LWIP_TCP_SEG_NUM=40
CONFIG_RT_LWIP_TCP_SND_BUF=8196
CONFIG_RT_LWIP_TCP_WND=8196
CONFIG_RT_LWIP_TCPTHREAD_PRIORITY=5
CONFIG_RT_LWIP_TCPTHREAD_MBOX_SIZE=32
CONFIG_RT_LWIP_TCPTHREAD_STACKSIZE=16384
# CONFIG_LWIP_NO_RX_THREAD is not set
# CONFIG_LWIP_NO_TX_THREAD is not set
CONFIG_RT_LWIP_ETHTHREAD_PRIORITY=5
CONFIG_RT_LWIP_ETHTHREAD_STACKSIZE=16384
CONFIG_RT_LWIP_ETHTHREAD_MBOX_SIZE=32
CONFIG_RT_LWIP_REASSEMBLY_FRAG=y
CONFIG_LWIP_NETIF_STATUS_CALLBACK=1
CONFIG_LWIP_NETIF_LINK_CALLBACK=1
CONFIG_SO_REUSE=1
CONFIG_LWIP_SO_RCVTIMEO=1
CONFIG_LWIP_SO_SNDTIMEO=1
CONFIG_LWIP_SO_RCVBUF=1
CONFIG_LWIP_SO_LINGER=0
# CONFIG_RT_LWIP_NETIF_LOOPBACK is not set
CONFIG_LWIP_NETIF_LOOPBACK=0
CONFIG_RT_LWIP_STATS=y
# CONFIG_RT_LWIP_USING_HW_CHECKSUM is not set
CONFIG_RT_LWIP_USING_PING=y
# CONFIG_RT_LWIP_DEBUG is not set
#
# AT commands
#
# CONFIG_RT_USING_AT is not set
# CONFIG_LWIP_USING_DHCPD is not set
#
# VBUS(Virtual Software BUS)
@ -213,7 +303,9 @@ CONFIG_RT_USING_POSIX=y
#
# IoT - internet of things
#
# CONFIG_PKG_USING_LORAWAN_DRIVER is not set
# CONFIG_PKG_USING_PAHOMQTT is not set
# CONFIG_PKG_USING_UMQTT is not set
# CONFIG_PKG_USING_WEBCLIENT is not set
# CONFIG_PKG_USING_WEBNET is not set
# CONFIG_PKG_USING_MONGOOSE is not set
@ -259,7 +351,7 @@ CONFIG_RT_USING_POSIX=y
# CONFIG_PKG_USING_GAGENT_CLOUD is not set
# CONFIG_PKG_USING_ALI_IOTKIT is not set
# CONFIG_PKG_USING_AZURE is not set
# CONFIG_PKG_USING_TENCENT_IOTHUB is not set
# CONFIG_PKG_USING_TENCENT_IOT_EXPLORER is not set
# CONFIG_PKG_USING_JIOT-C-SDK is not set
# CONFIG_PKG_USING_UCLOUD_IOT_SDK is not set
# CONFIG_PKG_USING_JOYLINK is not set
@ -281,6 +373,8 @@ CONFIG_RT_USING_POSIX=y
# CONFIG_PKG_USING_CAPNP is not set
# CONFIG_PKG_USING_RT_CJSON_TOOLS is not set
# CONFIG_PKG_USING_AGILE_TELNET is not set
# CONFIG_PKG_USING_NMEALIB is not set
# CONFIG_PKG_USING_AGILE_JSMN is not set
#
# security packages
@ -289,6 +383,7 @@ CONFIG_RT_USING_POSIX=y
# CONFIG_PKG_USING_libsodium is not set
# CONFIG_PKG_USING_TINYCRYPT is not set
# CONFIG_PKG_USING_TFM is not set
# CONFIG_PKG_USING_YD_CRYPTO is not set
#
# language packages
@ -323,7 +418,9 @@ CONFIG_RT_USING_POSIX=y
# CONFIG_PKG_USING_CHINESE_FONT_LIBRARY is not set
# CONFIG_PKG_USING_LUNAR_CALENDAR is not set
# CONFIG_PKG_USING_BS8116A is not set
# CONFIG_PKG_USING_GPS_RMC is not set
# CONFIG_PKG_USING_URLENCODE is not set
# CONFIG_PKG_USING_UMCN is not set
#
# system packages
@ -331,9 +428,15 @@ CONFIG_RT_USING_POSIX=y
# CONFIG_PKG_USING_GUIENGINE is not set
# CONFIG_PKG_USING_CAIRO is not set
# CONFIG_PKG_USING_PIXMAN is not set
# CONFIG_PKG_USING_LWEXT4 is not set
CONFIG_PKG_USING_LWEXT4=y
CONFIG_PKG_LWEXT4_PATH="/packages/system/lwext4"
CONFIG_RT_USING_DFS_LWEXT4=y
CONFIG_PKG_USING_LWEXT4_LATEST_VERSION=y
# CONFIG_PKG_USING_LWEXT4_V100 is not set
CONFIG_PKG_LWEXT4_VER="latest"
# CONFIG_PKG_USING_PARTITION is not set
# CONFIG_PKG_USING_FAL is not set
# CONFIG_PKG_USING_FLASHDB is not set
# CONFIG_PKG_USING_SQLITE is not set
# CONFIG_PKG_USING_RTI is not set
# CONFIG_PKG_USING_LITTLEVGL2RTT is not set
@ -346,6 +449,10 @@ CONFIG_RT_USING_POSIX=y
# CONFIG_PKG_USING_SYSWATCH is not set
# CONFIG_PKG_USING_SYS_LOAD_MONITOR is not set
# CONFIG_PKG_USING_PLCCORE is not set
# CONFIG_PKG_USING_RAMDISK is not set
# CONFIG_PKG_USING_MININI is not set
# CONFIG_PKG_USING_QBOOT is not set
# CONFIG_PKG_USING_UCOSIII_WRAPPER is not set
#
# peripheral libraries and drivers
@ -383,6 +490,7 @@ CONFIG_RT_USING_POSIX=y
# CONFIG_PKG_USING_RPLIDAR is not set
# CONFIG_PKG_USING_AS608 is not set
# CONFIG_PKG_USING_RC522 is not set
# CONFIG_PKG_USING_WS2812B is not set
# CONFIG_PKG_USING_EMBARC_BSP is not set
# CONFIG_PKG_USING_EXTERN_RTC_DRIVERS is not set
# CONFIG_PKG_USING_MULTI_RTIMER is not set
@ -390,6 +498,13 @@ CONFIG_RT_USING_POSIX=y
# CONFIG_PKG_USING_BEEP is not set
# CONFIG_PKG_USING_EASYBLINK is not set
# CONFIG_PKG_USING_PMS_SERIES is not set
# CONFIG_PKG_USING_CAN_YMODEM is not set
# CONFIG_PKG_USING_LORA_RADIO_DRIVER is not set
# CONFIG_PKG_USING_QLED is not set
# CONFIG_PKG_USING_PAJ7620 is not set
# CONFIG_PKG_USING_AGILE_CONSOLE is not set
# CONFIG_PKG_USING_LD3320 is not set
# CONFIG_PKG_USING_WK2124 is not set
#
# miscellaneous packages
@ -426,36 +541,5 @@ CONFIG_RT_USING_POSIX=y
# CONFIG_PKG_USING_VT100 is not set
# CONFIG_PKG_USING_ULAPACK is not set
# CONFIG_PKG_USING_UKAL is not set
#
# Privated Packages of RealThread
#
# CONFIG_PKG_USING_CODEC is not set
# CONFIG_PKG_USING_PLAYER is not set
# CONFIG_PKG_USING_MPLAYER is not set
# CONFIG_PKG_USING_PERSIMMON_SRC is not set
# CONFIG_PKG_USING_JS_PERSIMMON is not set
# CONFIG_PKG_USING_JERRYSCRIPT_WIN32 is not set
#
# Network Utilities
#
# CONFIG_PKG_USING_WICED is not set
# CONFIG_PKG_USING_CLOUDSDK is not set
# CONFIG_PKG_USING_POWER_MANAGER is not set
# CONFIG_PKG_USING_RT_OTA is not set
# CONFIG_PKG_USING_RDBD_SRC is not set
# CONFIG_PKG_USING_RTINSIGHT is not set
# CONFIG_PKG_USING_SMARTCONFIG is not set
# CONFIG_PKG_USING_RTX is not set
# CONFIG_RT_USING_TESTCASE is not set
# CONFIG_PKG_USING_NGHTTP2 is not set
# CONFIG_PKG_USING_AVS is not set
# CONFIG_PKG_USING_ALI_LINKKIT is not set
# CONFIG_PKG_USING_STS is not set
# CONFIG_PKG_USING_DLMS is not set
# CONFIG_PKG_USING_AUDIO_FRAMEWORK is not set
# CONFIG_PKG_USING_ZBAR is not set
# CONFIG_PKG_USING_MCF is not set
# CONFIG_PKG_USING_URPC is not set
# CONFIG_PKG_USING_CRCLIB is not set
CONFIG_SOC_LS2K1000=y

View File

@ -84,13 +84,43 @@ Hi, this is RT-Thread!!
msh >
```
## 4. 支持情况
## 4.开机自动启动
在调试阶段可以利用脚本在pmon阶段从TFTP服务器上获取固件然后引导启动。这样可以节省开发配置的时间。具体的步骤如下
**第一步:**
设置开发板的IP地址在进入pmon的控制台后输入`set ifconfig syn0:10.1.1.100`。其中`syn0`后面的ip地址为开发板的ip地址与存放rt-thread固件的TFTP的服务器IP地址在**同一网段**。
**第二步:**
进入龙芯的Debian系统用管理员权限进入输入用户名`root`,密码`loongson`。并且修改boot分区下的boot.cfg文件。增加如下
```
title TFTPBOOT
kernel tftfp://10.1.1.118/rtthread.elf
args console=tty root=/dev/sda2
initrd (wd0,0)/initrd.img
```
其中`tftfp://10.1.1.118/rtthread.elf`中的`10.1.1.118`为tftp服务器的ip地址。
**第三步:**
电脑开启TFTP服务器将路径指向存放有ls2k的rt-thread固件的目录下。
以上三步完成之后重启系统就可以省略每次都需要进入pmon的输入命令的麻烦板子上电后可以自动从系统TFTP服务器中获取固件然后启动大大提高调试代码效率。
## 5. 支持情况
| 驱动 | 支持情况 | 备注 |
| ------ | ---- | :------: |
| UART | 支持 | UART0|
| GPIO | 支持 | - |
| PWM | 支持 | - |
| GMAC | 支持 | 网卡驱动 |
| RTC | 支持 | - |
## 5. 联系人信息
## 6. 联系人信息
维护人:[bernard][4]

View File

@ -9,8 +9,6 @@ from building import *
TARGET = 'rtthread.' + rtconfig.TARGET_EXT
rtconfig.AFLAGS += ' -I' + str(Dir('#')) + ' -I ' + RTT_ROOT + '/libcpu/mips/common/'
DefaultEnvironment(tools=[])
env = Environment(tools = ['mingw'],
AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS,
@ -19,6 +17,7 @@ env = Environment(tools = ['mingw'],
AR = rtconfig.AR, ARFLAGS = '-rc',
LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS)
env.PrependENVPath('PATH', rtconfig.EXEC_PATH)
env['ASCOM'] = env['ASPPCOM']
Export('RTT_ROOT')
Export('rtconfig')

View File

@ -7,4 +7,14 @@ CPPPATH = [cwd]
group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH)
objs = []
list = os.listdir(cwd)
for d in list:
path = os.path.join(cwd, d)
if os.path.isfile(os.path.join(path, 'SConscript')):
objs = objs + SConscript(os.path.join(d, 'SConscript'))
group = group + objs
Return('group')

View File

@ -16,7 +16,7 @@
extern unsigned char __bss_end;
#define CPU_HZ (1000 * 1000 * 1000) //QEMU 200*1000*1000
#define RT_HW_HEAP_BEGIN KSEG1BASE//(void*)&__bss_end
#define RT_HW_HEAP_BEGIN (void*)&__bss_end
#define RT_HW_HEAP_END (void*)(RT_HW_HEAP_BEGIN + 64 * 1024 * 1024)
void rt_hw_board_init(void);

View File

@ -14,7 +14,6 @@
#include <rtthread.h>
#include "ls2k1000.h"
struct loongson_pll {
rt_uint64_t PLL_SYS_0;
rt_uint64_t PLL_SYS_1;

View File

@ -36,6 +36,5 @@ struct loongson_gpio {
int loongson_pin_init(void);
#endif

View File

@ -53,7 +53,6 @@
#define FIFO_TRIGGER_8 0x80 /* trigger at 8 chars */
#define FIFO_TRIGGER_14 0xc0 /* trigger at 14 chars */
// 线路控制寄存器
/* character format control register */
#define CFCR_DLAB 0x80 /* divisor latch */
#define CFCR_SBREAK 0x40 /* send break */

View File

@ -64,11 +64,11 @@
#define LS2K_GPIO2_INT_IRQ (62)
#define LS2K_GPIO3_INT_IRQ (63)
#define MAX_INTR 64
#define LIOINTC0_IRQBASE 0
#define LIOINTC1_IRQBASE 32
#define MAX_INTR (64)
#define LIOINTC0_IRQBASE (0)
#define LIOINTC1_IRQBASE (32)
#define LIOINTC_SHIFT_INTx 4
#define LIOINTC_SHIFT_INTx (4)
#define LIOINTC_COREx_INTy(x, y) ((1 << x) | (1 << (y + LIOINTC_SHIFT_INTx)))
#define LIOINTC_INTC_CHIP_START 0x20

View File

@ -6,8 +6,8 @@
#define APB_BASE CKSEG1ADDR(0xbfe00000)
#define UART0_BASE_ADDR 0xbfe00000
#define UART0_OFF 0x0
#define UART0_BASE_ADDR (0xbfe00000)
#define UART0_OFF (0x0)
#define UART0_BASE CKSEG1ADDR(UART0_BASE_ADDR + UART0_OFF)
#define UARTx_BASE(x) ((APB_BASE | (0x0 << 12) | (x << 8)))
@ -18,11 +18,11 @@
#define LIOINTC1_BASE CKSEG1ADDR(0x1fe11440)
#define CORE0_INTISR1 CKSEG1ADDR(0x1fe11048)
#define GPIO_BASE 0xFFFFFFFFBFE10500
#define PLL_SYS_BASE 0xFFFFFFFFBFE10480
#define RTC_BASE 0xFFFFFFFFBFE07820
#define GPIO_BASE (0xFFFFFFFFBFE10500)
#define PLL_SYS_BASE (0xFFFFFFFFBFE10480)
#define RTC_BASE (0xFFFFFFFFBFE07820)
#define GEN_CONFIG0_REG 0xFFFFFFFFBfe10420
#define GEN_CONFIG0_REG (0xFFFFFFFFBfe10420)
void rt_hw_timer_handler(void);
void rt_hw_uart_init(void);

View File

@ -0,0 +1,16 @@
from building import *
cwd = GetCurrentDir()
src = Glob('*.c')
CPPPATH = [cwd]
if GetDepend('RT_USING_LWIP') == False:
SrcRemove(src, 'mii.c')
SrcRemove(src, 'synopGMAC.c')
SrcRemove(src, 'synopGMAC_Dev.c')
SrcRemove(src, 'synopGMAC_plat.c')
group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH)
Return('group')

View File

@ -0,0 +1,132 @@
/*
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-08-24 chinesebear first version
*/
#include "mii.h"
static inline unsigned int mii_nway_result (unsigned int negotiated)
{
unsigned int ret;
if (negotiated & LPA_100FULL)
ret = LPA_100FULL;
else if (negotiated & LPA_100BASE4)
ret = LPA_100BASE4;
else if (negotiated & LPA_100HALF)
ret = LPA_100HALF;
else if (negotiated & LPA_10FULL)
ret = LPA_10FULL;
else
ret = LPA_10HALF;
return ret;
}
static int mii_check_gmii_support(struct mii_if_info *mii)
{
int reg;
reg = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
if (reg & BMSR_ESTATEN) {
reg = mii->mdio_read(mii->dev, mii->phy_id, MII_ESTATUS);
if (reg & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF))
return 1;
}
return 0;
}
static int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
{
struct synopGMACNetworkAdapter * dev = mii->dev;
u32 advert, bmcr, lpa, nego;
u32 advert2 = 0, bmcr2 = 0, lpa2 = 0;
ecmd->supported =
(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
if (mii->supports_gmii)
ecmd->supported |= SUPPORTED_1000baseT_Half |
SUPPORTED_1000baseT_Full;
/* only supports twisted-pair */
ecmd->port = PORT_MII;
/* only supports internal transceiver */
ecmd->transceiver = XCVR_INTERNAL;
/* this isn't fully supported at higher layers */
ecmd->phy_address = mii->phy_id;
ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
if (mii->supports_gmii)
advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
if (advert & ADVERTISE_10HALF)
ecmd->advertising |= ADVERTISED_10baseT_Half;
if (advert & ADVERTISE_10FULL)
ecmd->advertising |= ADVERTISED_10baseT_Full;
if (advert & ADVERTISE_100HALF)
ecmd->advertising |= ADVERTISED_100baseT_Half;
if (advert & ADVERTISE_100FULL)
ecmd->advertising |= ADVERTISED_100baseT_Full;
if (advert2 & ADVERTISE_1000HALF)
ecmd->advertising |= ADVERTISED_1000baseT_Half;
if (advert2 & ADVERTISE_1000FULL)
ecmd->advertising |= ADVERTISED_1000baseT_Full;
bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
lpa = mii->mdio_read(dev, mii->phy_id, MII_LPA);
if (mii->supports_gmii) {
bmcr2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
lpa2 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000);
}
if (bmcr & BMCR_ANENABLE) {
ecmd->advertising |= ADVERTISED_Autoneg;
ecmd->autoneg = AUTONEG_ENABLE;
nego = mii_nway_result(advert & lpa);
if ((bmcr2 & (ADVERTISE_1000HALF | ADVERTISE_1000FULL)) &
(lpa2 >> 2))
ecmd->speed = SPEED_1000;
else if (nego == LPA_100FULL || nego == LPA_100HALF)
ecmd->speed = SPEED_100;
else
ecmd->speed = SPEED_10;
if ((lpa2 & LPA_1000FULL) || nego == LPA_100FULL ||
nego == LPA_10FULL) {
ecmd->duplex = DUPLEX_FULL;
mii->full_duplex = 1;
} else {
ecmd->duplex = DUPLEX_HALF;
mii->full_duplex = 0;
}
} else {
ecmd->autoneg = AUTONEG_DISABLE;
ecmd->speed = ((bmcr & BMCR_SPEED1000 &&
(bmcr & BMCR_SPEED100) == 0) ? SPEED_1000 :
(bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10);
ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
}
/* ignore maxtxpkt, maxrxpkt for now */
return 0;
}
static int mii_link_ok (struct mii_if_info *mii)
{
/* first, a dummy read, needed to latch some MII phys */
mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
return 1;
return 0;
}

View File

@ -0,0 +1,229 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-08-24 chinesebear first version
*/
#ifndef __MII_H__
#define __MII_H__
/* Generic MII registers. */
#include "synopGMAC_types.h"
#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_CTRL1000 0x09 /* 1000BASE-T control */
#define MII_STAT1000 0x0a /* 1000BASE-T status */
#define MII_ESTATUS 0x0f /* Extended Status */
#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 0x003f /* Unused... */
#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */
#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 0x00c0 /* Unused... */
#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */
#define BMSR_100FULL2 0x0200 /* Can do 100BASE-T2 HDX */
#define BMSR_100HALF2 0x0400 /* Can do 100BASE-T2 FDX */
#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_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */
#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
#define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */
#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
#define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */
#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */
#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */
#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */
#define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */
#define ADVERTISE_RESV 0x1000 /* 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 ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \
ADVERTISE_CSMA)
#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \
ADVERTISE_100HALF | ADVERTISE_100FULL)
/* Indicates what features are advertised by the interface. */
#define ADVERTISED_10baseT_Half (1 << 0)
#define ADVERTISED_10baseT_Full (1 << 1)
#define ADVERTISED_100baseT_Half (1 << 2)
#define ADVERTISED_100baseT_Full (1 << 3)
#define ADVERTISED_1000baseT_Half (1 << 4)
#define ADVERTISED_1000baseT_Full (1 << 5)
#define ADVERTISED_Autoneg (1 << 6)
#define ADVERTISED_TP (1 << 7)
#define ADVERTISED_AUI (1 << 8)
#define ADVERTISED_MII (1 << 9)
#define ADVERTISED_FIBRE (1 << 10)
#define ADVERTISED_BNC (1 << 11)
#define ADVERTISED_10000baseT_Full (1 << 12)
#define ADVERTISED_Pause (1 << 13)
#define ADVERTISED_Asym_Pause (1 << 14)
/* Link partner ability register. */
#define LPA_SLCT 0x001f /* Same as advertise selector */
#define LPA_10HALF 0x0020 /* Can do 10mbps half-duplex */
#define LPA_1000XFULL 0x0020 /* Can do 1000BASE-X full-duplex */
#define LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */
#define LPA_1000XHALF 0x0040 /* Can do 1000BASE-X half-duplex */
#define LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */
#define LPA_1000XPAUSE 0x0080 /* Can do 1000BASE-X pause */
#define LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */
#define LPA_1000XPAUSE_ASYM 0x0100 /* Can do 1000BASE-X pause asym*/
#define LPA_100BASE4 0x0200 /* Can do 100mbps 4k packets */
#define LPA_PAUSE_CAP 0x0400 /* Can pause */
#define LPA_PAUSE_ASYM 0x0800 /* Can pause asymetrically */
#define LPA_RESV 0x1000 /* Unused... */
#define LPA_RFAULT 0x2000 /* Link partner faulted */
#define LPA_LPACK 0x4000 /* Link partner acked us */
#define LPA_NPAGE 0x8000 /* Next page bit */
#define LPA_DUPLEX (LPA_10FULL | LPA_100FULL)
#define LPA_100 (LPA_100FULL | LPA_100HALF | LPA_100BASE4)
/* Expansion register for auto-negotiation. */
#define EXPANSION_NWAY 0x0001 /* Can do N-way auto-nego */
#define EXPANSION_LCWP 0x0002 /* Got new RX page code word */
#define EXPANSION_ENABLENPAGE 0x0004 /* This enables npage words */
#define EXPANSION_NPCAPABLE 0x0008 /* Link partner supports npage */
#define EXPANSION_MFAULTS 0x0010 /* Multiple faults detected */
#define EXPANSION_RESV 0xffe0 /* Unused... */
#define ESTATUS_1000_TFULL 0x2000 /* Can do 1000BT Full */
#define ESTATUS_1000_THALF 0x1000 /* Can do 1000BT Half */
/* N-way test register. */
#define NWAYTEST_RESV1 0x00ff /* Unused... */
#define NWAYTEST_LOOPBACK 0x0100 /* Enable loopback for N-way */
#define NWAYTEST_RESV2 0xfe00 /* Unused... */
/* 1000BASE-T Control register */
#define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */
#define ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */
/* 1000BASE-T Status register */
#define LPA_1000LOCALRXOK 0x2000 /* Link partner local receiver status */
#define LPA_1000REMRXOK 0x1000 /* Link partner remote receiver status */
#define LPA_1000FULL 0x0800 /* Link partner 1000BASE-T full duplex */
#define SUPPORTED_10baseT_Half (1 << 0)
#define SUPPORTED_10baseT_Full (1 << 1)
#define SUPPORTED_100baseT_Half (1 << 2)
#define SUPPORTED_100baseT_Full (1 << 3)
#define SUPPORTED_1000baseT_Half (1 << 4)
#define SUPPORTED_1000baseT_Full (1 << 5)
#define SUPPORTED_Autoneg (1 << 6)
#define SUPPORTED_TP (1 << 7)
#define SUPPORTED_AUI (1 << 8)
#define SUPPORTED_MII (1 << 9)
#define SUPPORTED_FIBRE (1 << 10)
#define SUPPORTED_BNC (1 << 11)
#define SUPPORTED_10000baseT_Full (1 << 12)
#define SUPPORTED_Pause (1 << 13)
#define SUPPORTED_Asym_Pause (1 << 14)
/* Which connector port. */
#define PORT_TP 0x00
#define PORT_AUI 0x01
#define PORT_MII 0x02
#define PORT_FIBRE 0x03
#define PORT_BNC 0x04
/* Which transceiver to use. */
#define XCVR_INTERNAL 0x00
#define XCVR_EXTERNAL 0x01
#define XCVR_DUMMY1 0x02
#define XCVR_DUMMY2 0x03
#define XCVR_DUMMY3 0x04
#define AUTONEG_DISABLE 0x00
#define AUTONEG_ENABLE 0x01
#define SPEED_10 10
#define SPEED_100 100
#define SPEED_1000 1000
#define SPEED_2500 2500
#define SPEED_10000 10000
#define DUPLEX_HALF 0x00
#define DUPLEX_FULL 0x01
struct ethtool_cmd {
u32 cmd;
u32 supported; /* Features this interface supports */
u32 advertising; /* Features this interface advertises */
u16 speed; /* The forced speed, 10Mb, 100Mb, gigabit */
u8 duplex; /* Duplex, half or full */
u8 port; /* Which connector port */
u8 phy_address;
u8 transceiver; /* Which transceiver to use */
u8 autoneg; /* Enable or disable autonegotiation */
u32 maxtxpkt; /* Tx pkts before generating tx int */
u32 maxrxpkt; /* Rx pkts before generating rx int */
u32 reserved[4];
};
struct mii_if_info {
int phy_id;
int advertising;
int phy_id_mask;
int reg_num_mask;
unsigned int full_duplex : 1; /* is full duplex? */
unsigned int force_media : 1; /* is autoneg. disabled? */
unsigned int supports_gmii : 1; /* are GMII registers supported? */
struct synopGMACNetworkAdapter *dev;
int (*mdio_read) (struct synopGMACNetworkAdapter *dev, int phy_id, int location);
void (*mdio_write) (struct synopGMACNetworkAdapter *dev, int phy_id, int location, int val);
};
#endif

View File

@ -0,0 +1,961 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-08-24 chinesebear first version
* 2020-08-10 lizhirui porting to ls2k
*/
#include <rtthread.h>
#include <rtdef.h>
//#include <lwip/pbuf.h>
#include "synopGMAC.h"
#include "mii.c"
#include "synopGMAC_debug.h"
#define RMII
#define Gmac_base (0x9000000000000000 | 0x40040000)
#define Buffer_Size 2048
#define MAX_ADDR_LEN 6
#define NAMESIZE 16
#define LS1B_GMAC0_IRQ 34
#define BUS_SIZE_ALIGN(x) ((x+15)&~15)
#define DEFAULT_MAC_ADDRESS {0x00, 0x55, 0x7B, 0xB5, 0x7D, 0xF7}
u64 regbase = 0x9000000000000000 | 0x40040000;
static u32 GMAC_Power_down;
extern void *plat_alloc_consistent_dmaable_memory(synopGMACdevice *pcidev, u32 size, u32 *addr) ;
extern s32 synopGMAC_check_phy_init(synopGMACPciNetworkAdapter *adapter) ;
extern int init_phy(synopGMACdevice *gmacdev);
dma_addr_t plat_dma_map_single(void *hwdev, void *ptr, u32 size);
void eth_rx_irq(int irqno, void *param);
static char Rx_Buffer[Buffer_Size];
static char Tx_Buffer[Buffer_Size];
struct rt_eth_dev
{
struct eth_device parent;
rt_uint8_t dev_addr[MAX_ADDR_LEN];
char *name;
int iobase;
int state;
int index;
struct rt_timer link_timer;
struct rt_timer rx_poll_timer;
void *priv;
};
static struct rt_eth_dev eth_dev;
static struct rt_semaphore sem_ack, sem_lock;
/**
* This sets up the transmit Descriptor queue in ring or chain mode.
* This function is tightly coupled to the platform and operating system
* Device is interested only after the descriptors are setup. Therefore this function
* is not included in the device driver API. This function should be treated as an
* example code to design the descriptor structures for ring mode or chain mode.
* This function depends on the pcidev structure for allocation consistent dma-able memory in case
* of linux.
* This limitation is due to the fact that linux uses pci structure to allocate a dmable memory
* - Allocates the memory for the descriptors.
* - Initialize the Busy and Next descriptors indices to 0(Indicating first descriptor).
* - Initialize the Busy and Next descriptors to first descriptor address.
* - Initialize the last descriptor with the endof ring in case of ring mode.
* - Initialize the descriptors in chain mode.
* @param[in] pointer to synopGMACdevice.
* @param[in] pointer to pci_device structure.
* @param[in] number of descriptor expected in tx descriptor queue.
* @param[in] whether descriptors to be created in RING mode or CHAIN mode.
* \return 0 upon success. Error code upon failure.
* \note This function fails if allocation fails for required number of descriptors in Ring mode,
* but in chain mode
* function returns -ESYNOPGMACNOMEM in the process of descriptor chain creation. once returned from
* this function
* user should for gmacdev->TxDescCount to see how many descriptors are there in the chain. Should
* continue further
* only if the number of descriptors in the chain meets the requirements
*/
s32 synopGMAC_setup_tx_desc_queue(synopGMACdevice *gmacdev, u32 no_of_desc, u32 desc_mode)
{
s32 i;
DmaDesc *bf1;
DmaDesc *first_desc = NULL;
dma_addr_t dma_addr;
gmacdev->TxDescCount = 0;
first_desc = (DmaDesc *)plat_alloc_consistent_dmaable_memory(gmacdev, sizeof(DmaDesc) * (no_of_desc), &dma_addr);
if (first_desc == NULL)
{
rt_kprintf("Error in Tx Descriptors memory allocation\n");
return -ESYNOPGMACNOMEM;
}
DEBUG_MES("tx_first_desc_addr = %p\n", first_desc);
DEBUG_MES("dmaadr = %p\n", dma_addr);
gmacdev->TxDescCount = no_of_desc;
gmacdev->TxDesc = first_desc;
gmacdev->TxDescDma = dma_addr;
for (i = 0; i < gmacdev->TxDescCount; i++)
{
synopGMAC_tx_desc_init_ring(gmacdev->TxDesc + i, i == gmacdev->TxDescCount - 1);
#if SYNOP_TOP_DEBUG
rt_kprintf("\n%02d %08x \n", i, (unsigned int)(gmacdev->TxDesc + i));
rt_kprintf("%08x ", (unsigned int)((gmacdev->TxDesc + i))->status);
rt_kprintf("%08x ", (unsigned int)((gmacdev->TxDesc + i)->length));
rt_kprintf("%08x ", (unsigned int)((gmacdev->TxDesc + i)->buffer1));
rt_kprintf("%08x ", (unsigned int)((gmacdev->TxDesc + i)->buffer2));
rt_kprintf("%08x ", (unsigned int)((gmacdev->TxDesc + i)->data1));
rt_kprintf("%08x ", (unsigned int)((gmacdev->TxDesc + i)->data2));
rt_kprintf("%08x ", (unsigned int)((gmacdev->TxDesc + i)->dummy1));
rt_kprintf("%08x ", (unsigned int)((gmacdev->TxDesc + i)->dummy2));
#endif
}
gmacdev->TxNext = 0;
gmacdev->TxBusy = 0;
gmacdev->TxNextDesc = gmacdev->TxDesc;
gmacdev->TxBusyDesc = gmacdev->TxDesc;
gmacdev->BusyTxDesc = 0;
return -ESYNOPGMACNOERR;
}
/**
* This sets up the receive Descriptor queue in ring or chain mode.
* This function is tightly coupled to the platform and operating system
* Device is interested only after the descriptors are setup. Therefore this function
* is not included in the device driver API. This function should be treated as an
* example code to design the descriptor structures in ring mode or chain mode.
* This function depends on the pcidev structure for allocation of consistent dma-able memory in
* case of linux.
* This limitation is due to the fact that linux uses pci structure to allocate a dmable memory
* - Allocates the memory for the descriptors.
* - Initialize the Busy and Next descriptors indices to 0(Indicating first descriptor).
* - Initialize the Busy and Next descriptors to first descriptor address.
* - Initialize the last descriptor with the endof ring in case of ring mode.
* - Initialize the descriptors in chain mode.
* @param[in] pointer to synopGMACdevice.
* @param[in] pointer to pci_device structure.
* @param[in] number of descriptor expected in rx descriptor queue.
* @param[in] whether descriptors to be created in RING mode or CHAIN mode.
* \return 0 upon success. Error code upon failure.
* \note This function fails if allocation fails for required number of descriptors in Ring mode,
* but in chain mode
* function returns -ESYNOPGMACNOMEM in the process of descriptor chain creation. once returned from
* this function
* user should for gmacdev->RxDescCount to see how many descriptors are there in the chain. Should
* continue further
* only if the number of descriptors in the chain meets the requirements
*/
s32 synopGMAC_setup_rx_desc_queue(synopGMACdevice *gmacdev, u32 no_of_desc, u32 desc_mode)
{
s32 i;
DmaDesc *bf1;
DmaDesc *first_desc = NULL;
dma_addr_t dma_addr;
gmacdev->RxDescCount = 0;
first_desc = (DmaDesc *)plat_alloc_consistent_dmaable_memory(gmacdev, sizeof(DmaDesc) * no_of_desc, &dma_addr);
if (first_desc == NULL)
{
rt_kprintf("Error in Rx Descriptor Memory allocation in Ring mode\n");
return -ESYNOPGMACNOMEM;
}
DEBUG_MES("rx_first_desc_addr = %p\n", first_desc);
DEBUG_MES("dmaadr = %p\n", dma_addr);
gmacdev->RxDescCount = no_of_desc;
gmacdev->RxDesc = (DmaDesc *)first_desc;
gmacdev->RxDescDma = dma_addr;
for (i = 0; i < gmacdev->RxDescCount; i++)
{
synopGMAC_rx_desc_init_ring(gmacdev->RxDesc + i, i == gmacdev->RxDescCount - 1);
}
gmacdev->RxNext = 0;
gmacdev->RxBusy = 0;
gmacdev->RxNextDesc = gmacdev->RxDesc;
gmacdev->RxBusyDesc = gmacdev->RxDesc;
gmacdev->BusyRxDesc = 0;
return -ESYNOPGMACNOERR;
}
void synopGMAC_linux_cable_unplug_function(void *adaptr)
{
s32 data;
synopGMACPciNetworkAdapter *adapter = (synopGMACPciNetworkAdapter *)adaptr;
synopGMACdevice *gmacdev = adapter->synopGMACdev;
struct ethtool_cmd cmd;
//rt_kprintf("%s\n",__FUNCTION__);
if (!mii_link_ok(&adapter->mii))
{
if (gmacdev->LinkState)
rt_kprintf("\r\nNo Link\r\n");
gmacdev->DuplexMode = 0;
gmacdev->Speed = 0;
gmacdev->LoopBackMode = 0;
gmacdev->LinkState = 0;
}
else
{
data = synopGMAC_check_phy_init(adapter);
if (gmacdev->LinkState != data)
{
gmacdev->LinkState = data;
synopGMAC_mac_init(gmacdev);
rt_kprintf("Link is up in %s mode\n", (gmacdev->DuplexMode == FULLDUPLEX) ? "FULL DUPLEX" : "HALF DUPLEX");
if (gmacdev->Speed == SPEED1000)
rt_kprintf("Link is with 1000M Speed \r\n");
if (gmacdev->Speed == SPEED100)
rt_kprintf("Link is with 100M Speed \n");
if (gmacdev->Speed == SPEED10)
rt_kprintf("Link is with 10M Speed \n");
}
}
}
s32 synopGMAC_check_phy_init(synopGMACPciNetworkAdapter *adapter)
{
struct ethtool_cmd cmd;
synopGMACdevice *gmacdev = adapter->synopGMACdev;
if (!mii_link_ok(&adapter->mii))
{
gmacdev->DuplexMode = FULLDUPLEX;
gmacdev->Speed = SPEED100;
return 0;
}
else
{
mii_ethtool_gset(&adapter->mii, &cmd);
gmacdev->DuplexMode = (cmd.duplex == DUPLEX_FULL) ? FULLDUPLEX : HALFDUPLEX ;
if (cmd.speed == SPEED_1000)
gmacdev->Speed = SPEED1000;
else if (cmd.speed == SPEED_100)
gmacdev->Speed = SPEED100;
else
gmacdev->Speed = SPEED10;
}
return gmacdev->Speed | (gmacdev->DuplexMode << 4);
}
static int Mac_change_check(u8 *macaddr0, u8 *macaddr1)
{
int i;
for (i = 0; i < 6; i++)
{
if (macaddr0[i] != macaddr1[i])
return 1;
}
return 0;
}
static rt_err_t eth_init(rt_device_t device)
{
struct eth_device *eth_device = (struct eth_device *)device;
RT_ASSERT(eth_device != RT_NULL);
s32 ijk;
s32 status = 0;
u64 dma_addr;
u32 Mac_changed = 0;
struct pbuf *pbuf;
u8 macaddr[6] = DEFAULT_MAC_ADDRESS;
struct rt_eth_dev *dev = &eth_dev;
struct synopGMACNetworkAdapter *adapter = dev->priv;
synopGMACdevice *gmacdev = (synopGMACdevice *)adapter->synopGMACdev;
synopGMAC_reset(gmacdev);
synopGMAC_attach(gmacdev, (regbase + MACBASE), (regbase + DMABASE), DEFAULT_PHY_BASE, macaddr);
synopGMAC_read_version(gmacdev);
synopGMAC_set_mdc_clk_div(gmacdev, GmiiCsrClk3);
gmacdev->ClockDivMdc = synopGMAC_get_mdc_clk_div(gmacdev);
init_phy(adapter->synopGMACdev);
DEBUG_MES("tx desc_queue\n");
synopGMAC_setup_tx_desc_queue(gmacdev, TRANSMIT_DESC_SIZE, RINGMODE);
synopGMAC_init_tx_desc_base(gmacdev);
DEBUG_MES("rx desc_queue\n");
synopGMAC_setup_rx_desc_queue(gmacdev, RECEIVE_DESC_SIZE, RINGMODE);
synopGMAC_init_rx_desc_base(gmacdev);
DEBUG_MES("DmaRxBaseAddr = %08x\n", synopGMACReadReg(gmacdev->DmaBase, DmaRxBaseAddr));
// u32 dmaRx_Base_addr = synopGMACReadReg(gmacdev->DmaBase,DmaRxBaseAddr);
// rt_kprintf("first_desc_addr = 0x%x\n", dmaRx_Base_addr);
#ifdef ENH_DESC_8W
synopGMAC_dma_bus_mode_init(gmacdev, DmaBurstLength32 | DmaDescriptorSkip2 | DmaDescriptor8Words);
#else
synopGMAC_dma_bus_mode_init(gmacdev, DmaBurstLength4 | DmaDescriptorSkip1);
//synopGMAC_dma_bus_mode_init(gmacdev, DmaBurstLength4 | DmaDescriptorSkip2);
#endif
synopGMAC_dma_control_init(gmacdev, DmaStoreAndForward | DmaTxSecondFrame | DmaRxThreshCtrl128);
status = synopGMAC_check_phy_init(adapter);
synopGMAC_mac_init(gmacdev);
synopGMAC_pause_control(gmacdev);
#ifdef IPC_OFFLOAD
synopGMAC_enable_rx_chksum_offload(gmacdev);
synopGMAC_rx_tcpip_chksum_drop_enable(gmacdev);
#endif
u64 skb;
do
{
skb = (u64)plat_alloc_memory(RX_BUF_SIZE); //should skb aligned here?
if (skb == RT_NULL)
{
rt_kprintf("ERROR in skb buffer allocation\n");
break;
}
dma_addr = plat_dma_map_single(gmacdev, (void *)skb, RX_BUF_SIZE); //获取 skb 的 dma 地址
status = synopGMAC_set_rx_qptr(gmacdev, dma_addr, RX_BUF_SIZE, (u64)skb, 0, 0, 0);
if (status < 0)
{
rt_kprintf("status < 0!!\n");
plat_free_memory((void *)skb);
}
}
while (status >= 0 && (status < (RECEIVE_DESC_SIZE - 1)));
synopGMAC_clear_interrupt(gmacdev);
synopGMAC_disable_mmc_tx_interrupt(gmacdev, 0xFFFFFFFF);
synopGMAC_disable_mmc_rx_interrupt(gmacdev, 0xFFFFFFFF);
synopGMAC_disable_mmc_ipc_rx_interrupt(gmacdev, 0xFFFFFFFF);
// synopGMAC_disable_interrupt_all(gmacdev);
synopGMAC_enable_interrupt(gmacdev, DmaIntEnable);
synopGMAC_enable_dma_rx(gmacdev);
synopGMAC_enable_dma_tx(gmacdev);
plat_delay(DEFAULT_LOOP_VARIABLE);
synopGMAC_check_phy_init(adapter);
synopGMAC_mac_init(gmacdev);
rt_timer_init(&dev->link_timer, "link_timer",
synopGMAC_linux_cable_unplug_function,
(void *)adapter,
RT_TICK_PER_SECOND,
RT_TIMER_FLAG_PERIODIC);
rt_timer_start(&dev->link_timer);
#ifdef RT_USING_GMAC_INT_MODE
/* installl isr */
DEBUG_MES("%s\n", __FUNCTION__);
rt_hw_interrupt_install(LS1C_MAC_IRQ, eth_rx_irq, RT_NULL, "e0_isr");
rt_hw_interrupt_umask(LS1C_MAC_IRQ);
#else
rt_timer_init(&dev->rx_poll_timer, "rx_poll_timer",
eth_rx_irq,
(void *)adapter,
1,
RT_TIMER_FLAG_PERIODIC);
rt_timer_start(&dev->rx_poll_timer);
#endif /*RT_USING_GMAC_INT_MODE*/
return RT_EOK;
}
static rt_err_t eth_open(rt_device_t dev, rt_uint16_t oflag)
{
rt_kprintf("eth_open!!\n");
return RT_EOK;
}
static rt_err_t eth_close(rt_device_t dev)
{
return RT_EOK;
}
static rt_size_t eth_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
rt_set_errno(-RT_ENOSYS);
return 0;
}
static rt_size_t eth_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
rt_set_errno(-RT_ENOSYS);
return 0;
}
static rt_err_t eth_control(rt_device_t dev, int cmd, void *args)
{
switch (cmd)
{
case NIOCTL_GADDR:
if (args) rt_memcpy(args, eth_dev.dev_addr, 6);
else return -RT_ERROR;
break;
default :
break;
}
return RT_EOK;
}
rt_err_t rt_eth_tx(rt_device_t device, struct pbuf *p)
{
/* lock eth device */
rt_sem_take(&sem_lock, RT_WAITING_FOREVER);
DEBUG_MES("in %s\n", __FUNCTION__);
s32 status;
u64 pbuf;
u64 dma_addr;
u32 offload_needed = 0;
u32 index;
DmaDesc *dpr;
struct rt_eth_dev *dev = (struct rt_eth_dev *) device;
struct synopGMACNetworkAdapter *adapter;
synopGMACdevice *gmacdev;
adapter = (struct synopGMACNetworkAdapter *) dev->priv;
if (adapter == NULL)
return -1;
gmacdev = (synopGMACdevice *) adapter->synopGMACdev;
if (gmacdev == NULL)
return -1;
if (!synopGMAC_is_desc_owned_by_dma(gmacdev->TxNextDesc))
{
pbuf = (u64)plat_alloc_memory(p->tot_len);
//pbuf = (u32)pbuf_alloc(PBUF_LINK, p->len, PBUF_RAM);
if (pbuf == 0)
{
rt_kprintf("===error in alloc bf1\n");
return -1;
}
DEBUG_MES("p->len = %d\n", p->len);
pbuf_copy_partial(p, (void *)pbuf, p->tot_len, 0);
dma_addr = plat_dma_map_single(gmacdev, (void *)pbuf, p->tot_len);
status = synopGMAC_set_tx_qptr(gmacdev, dma_addr, p->tot_len, pbuf, 0, 0, 0, offload_needed, &index, dpr);
if (status < 0)
{
rt_kprintf("%s No More Free Tx Descriptors\n", __FUNCTION__);
plat_free_memory((void *)pbuf);
return -16;
}
}
synopGMAC_resume_dma_tx(gmacdev);
s32 desc_index;
u64 data1, data2;
u32 dma_addr1, dma_addr2;
u32 length1, length2;
#ifdef ENH_DESC_8W
u32 ext_status;
u16 time_stamp_higher;
u32 time_stamp_high;
u32 time_stamp_low;
#endif
do
{
#ifdef ENH_DESC_8W
desc_index = synopGMAC_get_tx_qptr(gmacdev, &status, &dma_addr1, &length1, &data1, &dma_addr2, &length2, &data2, &ext_status, &time_stamp_high, &time_stamp_low);
synopGMAC_TS_read_timestamp_higher_val(gmacdev, &time_stamp_higher);
#else
desc_index = synopGMAC_get_tx_qptr(gmacdev, &status, &dma_addr1, &length1, &data1, &dma_addr2, &length2, &data2);
#endif
if (desc_index >= 0 && data1 != 0)
{
#ifdef IPC_OFFLOAD
if (synopGMAC_is_tx_ipv4header_checksum_error(gmacdev, status))
{
rt_kprintf("Harware Failed to Insert IPV4 Header Checksum\n");
}
if (synopGMAC_is_tx_payload_checksum_error(gmacdev, status))
{
rt_kprintf("Harware Failed to Insert Payload Checksum\n");
}
#endif
plat_free_memory((void *)(data1)); //sw: data1 = buffer1
if (synopGMAC_is_desc_valid(status))
{
adapter->synopGMACNetStats.tx_bytes += length1;
adapter->synopGMACNetStats.tx_packets++;
}
else
{
adapter->synopGMACNetStats.tx_errors++;
adapter->synopGMACNetStats.tx_aborted_errors += synopGMAC_is_tx_aborted(status);
adapter->synopGMACNetStats.tx_carrier_errors += synopGMAC_is_tx_carrier_error(status);
}
}
adapter->synopGMACNetStats.collisions += synopGMAC_get_tx_collision_count(status);
}
while (desc_index >= 0);
/* unlock eth device */
rt_sem_release(&sem_lock);
// rt_kprintf("output %d bytes\n", p->len);
u32 test_data;
test_data = synopGMACReadReg(gmacdev->DmaBase, DmaStatus);
//rt_kprintf("dma_status = 0x%08x\n",test_data);
return RT_EOK;
}
struct pbuf *rt_eth_rx(rt_device_t device)
{
DEBUG_MES("%s : \n", __FUNCTION__);
struct rt_eth_dev *dev = &eth_dev;
struct synopGMACNetworkAdapter *adapter;
synopGMACdevice *gmacdev;
// struct PmonInet * pinetdev;
s32 desc_index;
int i;
char *ptr;
u32 bf1;
u64 data1;
u64 data2;
u32 len;
u32 status;
u32 dma_addr1;
u32 dma_addr2;
struct pbuf *pbuf = RT_NULL;
rt_sem_take(&sem_lock, RT_WAITING_FOREVER);
adapter = (struct synopGMACNetworkAdapter *) dev->priv;
if (adapter == NULL)
{
rt_kprintf("%S : Unknown Device !!\n", __FUNCTION__);
return NULL;
}
gmacdev = (synopGMACdevice *) adapter->synopGMACdev;
if (gmacdev == NULL)
{
rt_kprintf("%s : GMAC device structure is missing\n", __FUNCTION__);
return NULL;
}
/*Handle the Receive Descriptors*/
desc_index = synopGMAC_get_rx_qptr(gmacdev, &status, &dma_addr1, NULL, &data1, &dma_addr2, NULL, &data2);
if(((u32)desc_index >= RECEIVE_DESC_SIZE) && (desc_index != -1))
{
rt_kprintf("host receive descriptor address pointer = 0x%08x\n",synopGMACReadReg(gmacdev->DmaBase,DmaRxCurrDesc));
rt_kprintf("host receive buffer = 0x%08x\n",synopGMACReadReg(gmacdev->DmaBase,DmaRxCurrAddr));
rt_kprintf("desc_index error!!!!,tick = %d\n",rt_tick_get());
while(1);
}
if (desc_index >= 0 && data1 != 0)
{
DEBUG_MES("Received Data at Rx Descriptor %d for skb 0x%08x whose status is %08x\n", desc_index, dma_addr1, status);
if (synopGMAC_is_rx_desc_valid(status) || SYNOP_PHY_LOOPBACK)
{
dma_addr1 = plat_dma_map_single(gmacdev, (void *)data1, RX_BUF_SIZE);
len = synopGMAC_get_rx_desc_frame_length(status)-4; //Not interested in Ethernet CRC bytes
pbuf = pbuf_alloc(PBUF_LINK, len, PBUF_RAM);
if (pbuf == 0) rt_kprintf("===error in pbuf_alloc\n");
rt_memcpy(pbuf->payload, (char *)data1, len);
DEBUG_MES("==get pkg len: %d\n", len);
}
else
{
rt_kprintf("s: %08x\n", status);
adapter->synopGMACNetStats.rx_errors++;
adapter->synopGMACNetStats.collisions += synopGMAC_is_rx_frame_collision(status);
adapter->synopGMACNetStats.rx_crc_errors += synopGMAC_is_rx_crc(status);
adapter->synopGMACNetStats.rx_frame_errors += synopGMAC_is_frame_dribbling_errors(status);
adapter->synopGMACNetStats.rx_length_errors += synopGMAC_is_rx_frame_length_errors(status);
}
desc_index = synopGMAC_set_rx_qptr(gmacdev, dma_addr1, RX_BUF_SIZE, (u64)data1, 0, 0, 0);
if (desc_index < 0)
{
#if SYNOP_RX_DEBUG
rt_kprintf("Cannot set Rx Descriptor for data1 %08x\n", (u32)data1);
#endif
plat_free_memory((void *)data1);
}
}
rt_sem_release(&sem_lock);
DEBUG_MES("%s : before return \n", __FUNCTION__);
return pbuf;
}
static int rtl88e1111_config_init(synopGMACdevice *gmacdev)
{
int retval, err;
u16 data;
DEBUG_MES("in %s\n", __FUNCTION__);
synopGMAC_read_phy_reg(gmacdev->MacBase, gmacdev->PhyBase, 0x14, &data);
data = data | 0x82;
err = synopGMAC_write_phy_reg(gmacdev->MacBase, gmacdev->PhyBase, 0x14, data);
synopGMAC_read_phy_reg(gmacdev->MacBase, gmacdev->PhyBase, 0x00, &data);
data = data | 0x8000;
err = synopGMAC_write_phy_reg(gmacdev->MacBase, gmacdev->PhyBase, 0x00, data);
#if SYNOP_PHY_LOOPBACK
synopGMAC_read_phy_reg(gmacdev->MacBase, gmacdev->PhyBase, 0x14, &data);
data = data | 0x70;
data = data & 0xffdf;
err = synopGMAC_write_phy_reg(gmacdev->MacBase, gmacdev->PhyBase, 0x14, data);
data = 0x8000;
err = synopGMAC_write_phy_reg(gmacdev->MacBase, gmacdev->PhyBase, 0x00, data);
data = 0x5140;
err = synopGMAC_write_phy_reg(gmacdev->MacBase, gmacdev->PhyBase, 0x00, data);
#endif
if (err < 0)
return err;
return 0;
}
int init_phy(synopGMACdevice *gmacdev)
{
u16 data;
synopGMAC_read_phy_reg(gmacdev->MacBase, gmacdev->PhyBase, 2, &data);
/*set 88e1111 clock phase delay*/
if (data == 0x141)
rtl88e1111_config_init(gmacdev);
#if defined (RMII)
else if (data == 0x8201)
{
//RTL8201
data = 0x400; // set RMII mode
synopGMAC_write_phy_reg(gmacdev->MacBase, gmacdev->PhyBase, 0x19, data);
synopGMAC_read_phy_reg(gmacdev->MacBase, gmacdev->PhyBase, 0x19, &data);
TR("phy reg25 is %0x \n", data);
data = 0x3100; //set 100M speed
synopGMAC_write_phy_reg(gmacdev->MacBase, gmacdev->PhyBase, 0x0, data);
}
else if (data == 0x0180 || data == 0x0181)
{
//DM9161
synopGMAC_read_phy_reg(gmacdev->MacBase, gmacdev->PhyBase, 0x10, &data);
data |= (1 << 8); //set RMII mode
synopGMAC_write_phy_reg(gmacdev->MacBase, gmacdev->PhyBase, 0x10, data); //set RMII mode
synopGMAC_read_phy_reg(gmacdev->MacBase, gmacdev->PhyBase, 0x10, &data);
TR("phy reg16 is 0x%0x \n", data);
// synopGMAC_read_phy_reg(gmacdev->MacBase,gmacdev->PhyBase,0x0,&data);
// data &= ~(1<<10);
data = 0x3100; //set auto-
//data = 0x0100; //set 10M speed
synopGMAC_write_phy_reg(gmacdev->MacBase, gmacdev->PhyBase, 0x0, data);
}
#endif
return 0;
}
u32 synopGMAC_wakeup_filter_config3[] =
{
0x00000000,
0x000000FF,
0x00000000,
0x00000000,
0x00000100,
0x00003200,
0x7eED0000,
0x00000000
};
static void synopGMAC_linux_powerdown_mac(synopGMACdevice *gmacdev)
{
rt_kprintf("Put the GMAC to power down mode..\n");
GMAC_Power_down = 1;
synopGMAC_disable_dma_tx(gmacdev);
plat_delay(10000);
synopGMAC_tx_disable(gmacdev);
synopGMAC_rx_disable(gmacdev);
plat_delay(10000);
synopGMAC_disable_dma_rx(gmacdev);
synopGMAC_magic_packet_enable(gmacdev);
synopGMAC_write_wakeup_frame_register(gmacdev, synopGMAC_wakeup_filter_config3);
synopGMAC_wakeup_frame_enable(gmacdev);
synopGMAC_rx_enable(gmacdev);
synopGMAC_pmt_int_enable(gmacdev);
synopGMAC_power_down_enable(gmacdev);
return;
}
static void synopGMAC_linux_powerup_mac(synopGMACdevice *gmacdev)
{
GMAC_Power_down = 0;
if (synopGMAC_is_magic_packet_received(gmacdev))
rt_kprintf("GMAC wokeup due to Magic Pkt Received\n");
if (synopGMAC_is_wakeup_frame_received(gmacdev))
rt_kprintf("GMAC wokeup due to Wakeup Frame Received\n");
synopGMAC_pmt_int_disable(gmacdev);
synopGMAC_rx_enable(gmacdev);
synopGMAC_enable_dma_rx(gmacdev);
synopGMAC_tx_enable(gmacdev);
synopGMAC_enable_dma_tx(gmacdev);
return;
}
static int mdio_read(synopGMACPciNetworkAdapter *adapter, int addr, int reg)
{
synopGMACdevice *gmacdev;
u16 data;
gmacdev = adapter->synopGMACdev;
synopGMAC_read_phy_reg(gmacdev->MacBase, addr, reg, &data);
return data;
}
static void mdio_write(synopGMACPciNetworkAdapter *adapter, int addr, int reg, int data)
{
synopGMACdevice *gmacdev;
gmacdev = adapter->synopGMACdev;
synopGMAC_write_phy_reg(gmacdev->MacBase, addr, reg, data);
}
void eth_rx_irq(int irqno, void *param)
{
struct rt_eth_dev *dev = &eth_dev;
struct synopGMACNetworkAdapter *adapter = dev->priv;
//DEBUG_MES("in irq!!\n");
#ifdef RT_USING_GMAC_INT_MODE
int i ;
for (i = 0; i < 7200; i++)
;
#endif /*RT_USING_GMAC_INT_MODE*/
synopGMACdevice *gmacdev = (synopGMACdevice *)adapter->synopGMACdev;
u32 interrupt, dma_status_reg;
s32 status;
u32 dma_addr;
//rt_kprintf("irq i = %d\n", i++);
dma_status_reg = synopGMACReadReg(gmacdev->DmaBase, DmaStatus);
if (dma_status_reg == 0)
{
rt_kprintf("dma_status ==0 \n");
return;
}
//rt_kprintf("dma_status_reg is 0x%x\n", dma_status_reg);
u32 gmacstatus;
synopGMAC_disable_interrupt_all(gmacdev);
gmacstatus = synopGMACReadReg(gmacdev->MacBase, GmacStatus);
if (dma_status_reg & GmacPmtIntr)
{
rt_kprintf("%s:: Interrupt due to PMT module\n", __FUNCTION__);
//synopGMAC_linux_powerup_mac(gmacdev);
}
if (dma_status_reg & GmacMmcIntr)
{
rt_kprintf("%s:: Interrupt due to MMC module\n", __FUNCTION__);
DEBUG_MES("%s:: synopGMAC_rx_int_status = %08x\n", __FUNCTION__, synopGMAC_read_mmc_rx_int_status(gmacdev));
DEBUG_MES("%s:: synopGMAC_tx_int_status = %08x\n", __FUNCTION__, synopGMAC_read_mmc_tx_int_status(gmacdev));
}
if (dma_status_reg & GmacLineIntfIntr)
{
//rt_kprintf("%s:: Interrupt due to GMAC LINE module\n", __FUNCTION__);
}
interrupt = synopGMAC_get_interrupt_type(gmacdev);
//rt_kprintf("%s:Interrupts to be handled: 0x%08x\n",__FUNCTION__,interrupt);
if (interrupt & synopGMACDmaError)
{
u8 mac_addr0[6];
rt_kprintf("%s::Fatal Bus Error Inetrrupt Seen\n", __FUNCTION__);
memcpy(mac_addr0, dev->dev_addr, 6);
synopGMAC_disable_dma_tx(gmacdev);
synopGMAC_disable_dma_rx(gmacdev);
synopGMAC_take_desc_ownership_tx(gmacdev);
synopGMAC_take_desc_ownership_rx(gmacdev);
synopGMAC_init_tx_rx_desc_queue(gmacdev);
synopGMAC_reset(gmacdev);
synopGMAC_set_mac_addr(gmacdev, GmacAddr0High, GmacAddr0Low, mac_addr0);
synopGMAC_dma_bus_mode_init(gmacdev, DmaFixedBurstEnable | DmaBurstLength8 | DmaDescriptorSkip1);
synopGMAC_dma_control_init(gmacdev, DmaStoreAndForward);
synopGMAC_init_rx_desc_base(gmacdev);
synopGMAC_init_tx_desc_base(gmacdev);
synopGMAC_mac_init(gmacdev);
synopGMAC_enable_dma_rx(gmacdev);
synopGMAC_enable_dma_tx(gmacdev);
}
if (interrupt & synopGMACDmaRxNormal)
{
//DEBUG_MES("%s:: Rx Normal \n", __FUNCTION__);
//synop_handle_received_data(netdev);
eth_device_ready(&eth_dev.parent);
}
if (interrupt & synopGMACDmaRxAbnormal)
{
//rt_kprintf("%s::Abnormal Rx Interrupt Seen\n",__FUNCTION__);
if (GMAC_Power_down == 0)
{
adapter->synopGMACNetStats.rx_over_errors++;
synopGMACWriteReg(gmacdev->DmaBase, DmaStatus, 0x80);
synopGMAC_resume_dma_rx(gmacdev);
}
}
if (interrupt & synopGMACDmaRxStopped)
{
rt_kprintf("%s::Receiver stopped seeing Rx interrupts\n", __FUNCTION__); //Receiver gone in to stopped state
}
if (interrupt & synopGMACDmaTxNormal)
{
DEBUG_MES("%s::Finished Normal Transmission \n", __FUNCTION__);
// synop_handle_transmit_over(netdev);
}
if (interrupt & synopGMACDmaTxAbnormal)
{
rt_kprintf("%s::Abnormal Tx Interrupt Seen\n", __FUNCTION__);
}
if (interrupt & synopGMACDmaTxStopped)
{
TR("%s::Transmitter stopped sending the packets\n", __FUNCTION__);
if (GMAC_Power_down == 0) // If Mac is not in powerdown
{
synopGMAC_disable_dma_tx(gmacdev);
synopGMAC_take_desc_ownership_tx(gmacdev);
synopGMAC_enable_dma_tx(gmacdev);
// netif_wake_queue(netdev);
TR("%s::Transmission Resumed\n", __FUNCTION__);
}
}
/* Enable the interrrupt before returning from ISR*/
synopGMAC_enable_interrupt(gmacdev, DmaIntEnable);
return;
}
int rt_hw_eth_init(void)
{
u64 base_addr = Gmac_base;
struct synopGMACNetworkAdapter *synopGMACadapter;
static u8 mac_addr0[6] = DEFAULT_MAC_ADDRESS;
int index;
rt_sem_init(&sem_ack, "tx_ack", 1, RT_IPC_FLAG_FIFO);
rt_sem_init(&sem_lock, "eth_lock", 1, RT_IPC_FLAG_FIFO);
memset(&eth_dev, 0, sizeof(eth_dev));
synopGMACadapter = (struct synopGMACNetworkAdapter *)plat_alloc_memory(sizeof(struct synopGMACNetworkAdapter));
if (!synopGMACadapter)
{
rt_kprintf("Error in Memory Allocataion, Founction : %s \n", __FUNCTION__);
}
memset((char *)synopGMACadapter, 0, sizeof(struct synopGMACNetworkAdapter));
synopGMACadapter->synopGMACdev = NULL;
synopGMACadapter->synopGMACdev = (synopGMACdevice *) plat_alloc_memory(sizeof(synopGMACdevice));
if (!synopGMACadapter->synopGMACdev)
{
rt_kprintf("Error in Memory Allocataion, Founction : %s \n", __FUNCTION__);
}
memset((char *)synopGMACadapter->synopGMACdev, 0, sizeof(synopGMACdevice));
/*
* Attach the device to MAC struct This will configure all the required base addresses
* such as Mac base, configuration base, phy base address(out of 32 possible phys)
* */
synopGMAC_attach(synopGMACadapter->synopGMACdev, (regbase + MACBASE), regbase + DMABASE, DEFAULT_PHY_BASE, mac_addr0);
init_phy(synopGMACadapter->synopGMACdev);
synopGMAC_reset(synopGMACadapter->synopGMACdev);
/* MII setup */
synopGMACadapter->mii.phy_id_mask = 0x1F;
synopGMACadapter->mii.reg_num_mask = 0x1F;
synopGMACadapter->mii.dev = synopGMACadapter;
synopGMACadapter->mii.mdio_read = mdio_read;
synopGMACadapter->mii.mdio_write = mdio_write;
synopGMACadapter->mii.phy_id = synopGMACadapter->synopGMACdev->PhyBase;
synopGMACadapter->mii.supports_gmii = mii_check_gmii_support(&synopGMACadapter->mii);
eth_dev.iobase = base_addr;
eth_dev.name = "e0";
eth_dev.priv = synopGMACadapter;
eth_dev.dev_addr[0] = mac_addr0[0];
eth_dev.dev_addr[1] = mac_addr0[1];
eth_dev.dev_addr[2] = mac_addr0[2];
eth_dev.dev_addr[3] = mac_addr0[3];
eth_dev.dev_addr[4] = mac_addr0[4];
eth_dev.dev_addr[5] = mac_addr0[5];
eth_dev.parent.parent.type = RT_Device_Class_NetIf;
eth_dev.parent.parent.init = eth_init;
eth_dev.parent.parent.open = eth_open;
eth_dev.parent.parent.close = eth_close;
eth_dev.parent.parent.read = eth_read;
eth_dev.parent.parent.write = eth_write;
eth_dev.parent.parent.control = eth_control;
eth_dev.parent.parent.user_data = RT_NULL;
eth_dev.parent.eth_tx = rt_eth_tx;
eth_dev.parent.eth_rx = rt_eth_rx;
eth_device_init(&(eth_dev.parent), "e0");
eth_device_linkchange(&eth_dev.parent, RT_TRUE); //linkup the e0 for lwip to check
return 0;
}
INIT_COMPONENT_EXPORT(rt_hw_eth_init);

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-08-24 chinesebear first version
*/
#ifndef __SYNOPGMAC__H
#define __SYNOPGMAC__H
#include "synopGMAC_network_interface.h"
#include "synopGMAC_Host.h"
#include "synopGMAC_Dev.h"
#include "synopGMAC_plat.h"
#include "mii.h"
#include "synopGMAC_types.h"
int rt_hw_eth_init(void);
#endif /*__SYNOPGMAC__H*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-08-24 chinesebear first version
*/
#ifndef SYNOP_GMAC_HOST_H
#define SYNOP_GMAC_HOST_H 1
#include "synopGMAC_plat.h"
#include "synopGMAC_Dev.h"
#include "mii.h"
struct net_device_stats
{
unsigned long rx_packets; /* total packets received */
unsigned long tx_packets; /* total packets transmitted */
unsigned long rx_bytes; /* total bytes received */
unsigned long tx_bytes; /* total bytes transmitted */
unsigned long rx_errors; /* bad packets received */
unsigned long tx_errors; /* packet transmit problems */
unsigned long rx_dropped; /* no space in linux buffers */
unsigned long tx_dropped; /* no space available in linux */
unsigned long multicast; /* multicast packets received */
unsigned long collisions;
/* detailed rx_errors: */
unsigned long rx_length_errors;
unsigned long rx_over_errors; /* receiver ring buff overflow */
unsigned long rx_crc_errors; /* recved pkt with crc error */
unsigned long rx_frame_errors; /* recv'd frame alignment error */
unsigned long rx_fifo_errors; /* recv'r fifo overrun */
unsigned long rx_missed_errors; /* receiver missed packet */
/* detailed tx_errors */
unsigned long tx_aborted_errors;
unsigned long tx_carrier_errors;
unsigned long tx_fifo_errors;
unsigned long tx_heartbeat_errors;
unsigned long tx_window_errors;
/* for cslip etc */
unsigned long rx_compressed;
unsigned long tx_compressed;
};
typedef struct synopGMACNetworkAdapter{
/*Device Dependent Data structur*/
synopGMACdevice * synopGMACdev;
struct net_device_stats synopGMACNetStats;
struct mii_if_info mii;
} synopGMACPciNetworkAdapter;
#endif

View File

@ -0,0 +1,22 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-08-24 chinesebear first version
*/
#ifndef __DEBUG_H__
#define __DEBUG_H__
//#define GMAC_DEBUG
#include <rtthread.h>
#ifdef GMAC_DEBUG
#define DEBUG_MES rt_kprintf
#else
#define DEBUG_MES(...)
#endif
#endif /*__DEBUG_H__*/

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-08-24 chinesebear first version
*/
#ifndef SYNOP_GMAC_NETWORK_INTERFACE_H
#define SYNOP_GMAC_NETWORK_INTERFACE_H 1
#include <lwip/sys.h>
#include <netif/ethernetif.h>
#include "synopGMAC_plat.h"
#include "synopGMAC_Host.h"
#include "synopGMAC_Dev.h"
#define NET_IF_TIMEOUT (10*HZ)
#define CHECK_TIME (HZ)
s32 synopGMAC_init_network_interface(char* xname,u64 synopGMACMappedAddr);
void synopGMAC_exit_network_interface(void);
s32 synopGMAC_linux_open(struct eth_device *);
s32 synopGMAC_linux_close(struct eth_device *);
struct net_device_stats * synopGMAC_linux_get_stats(struct synopGMACNetworkAdapter *);
s32 synopGMAC_test(synopGMACdevice * gmacdev_0,synopGMACdevice * gmacdev_1);
void dumpreg(u64 );
void dumpphyreg();
/*
* gethex(vp,p,n)
* convert n hex digits from p to binary, result in vp,
* rtn 1 on success
*/
static int gethex(u8 *vp, char *p, int n)
{
u8 v;
int digit;
for (v = 0; n > 0; n--) {
if (*p == 0)
return (0);
if (*p >= '0' && *p <= '9')
digit = *p - '0';
else if (*p >= 'a' && *p <= 'f')
digit = *p - 'a' + 10;
else if (*p >= 'A' && *p <= 'F')
digit = *p - 'A' + 10;
else
return (0);
v <<= 4;
v |= digit;
p++;
}
*vp = v;
return (1);
}
#endif /* End of file */

View File

@ -0,0 +1,130 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-08-24 chinesebear first version
* 2020-08-10 lizhirui porting to ls2k
*/
#include "synopGMAC_plat.h"
#include "synopGMAC_Dev.h"
#include <rthw.h>
#include <rtthread.h>
void flush_cache(unsigned long start_addr, unsigned long size)
{
/*r4k_dcache_wback_inv(start_addr,size);
//rt_kprintf("flush_cache:start_addr = 0x%p,size = 0x%p",start_addr,size);
unsigned long new_addr = start_addr - CACHED_MEMORY_ADDR + UNCACHED_MEMORY_ADDR;
rt_memcpy(new_addr,start_addr,size);
if(rt_memcmp(start_addr,new_addr,size) != 0)
{
rt_kprintf("flush_cache:data isn't matched!\n");
while(1);
}
else
{
//rt_kprintf("flush_cache:data is matched!\n");
}*/
}
//convert virtual address to physical address
dma_addr_t __attribute__((weak)) gmac_dmamap(unsigned long va,u32 size)
{
return VA_TO_PA (va);
//return UNCACHED_TO_PHYS(va);
}
/**
* This is a wrapper function for Memory allocation routine. In linux Kernel
* it it kmalloc function
* @param[in] bytes in bytes to allocate
*/
void *plat_alloc_memory(u32 bytes)
{
//return (void*)malloc((size_t)bytes, M_DEVBUF, M_DONTWAIT);
void *buf = (void*)rt_malloc((u32)bytes);
flush_cache((unsigned long)buf, bytes);
return buf;
}
/**
* This is a wrapper function for consistent dma-able Memory allocation routine.
* In linux Kernel, it depends on pci dev structure
* @param[in] bytes in bytes to allocate
*/
//allocate a space aligned to 16-byte boundary without cache
void *plat_alloc_consistent_dmaable_memory(synopGMACdevice *pcidev, u32 size, u32 *addr)
{
void *buf;
buf = (void*)rt_malloc((u32)(size + 16));
//CPU_IOFlushDCache( buf,size, SYNC_W);
unsigned long i = (unsigned long)buf;
// rt_kprintf("size = %d\n", size);
// rt_kprintf("bufaddr = %p\n", buf);
// rt_kprintf("i%%16 == %d\n", i%16);
if(i % 16 == 8){
i += 8;
}
else if(i % 16 == 4){
i += 12;
}
else if(i % 16 == 12){
i += 4;
}
flush_cache(i, size);
*addr = gmac_dmamap(i, size);
buf = (unsigned char *)CACHED_TO_UNCACHED(i);
//rt_kprintf("bufaddr = %p\n", buf);
return buf;
}
/**
* This is a wrapper function for freeing consistent dma-able Memory.
* In linux Kernel, it depends on pci dev structure
* @param[in] bytes in bytes to allocate
*/
//void plat_free_consistent_dmaable_memory(void * addr)
void plat_free_consistent_dmaable_memory(synopGMACdevice *pcidev, u32 size, void * addr,u64 dma_addr)
{
rt_free((void*)PHYS_TO_CACHED(UNCACHED_TO_PHYS(addr)));
return;
}
/**
* This is a wrapper function for Memory free routine. In linux Kernel
* it it kfree function
* @param[in] buffer pointer to be freed
*/
void plat_free_memory(void *buffer)
{
rt_free(buffer);
return ;
}
//convert virtual address to physical address and flush cache
dma_addr_t plat_dma_map_single(void *hwdev,void *ptr,u32 size)
{
unsigned long addr = (unsigned long) ptr;
//CPU_IOFlushDCache(addr,size, direction);
flush_cache(addr, size);
return gmac_dmamap(addr, size);
}
/**
* This is a wrapper function for platform dependent delay
* Take care while passing the argument to this function
* @param[in] buffer pointer to be freed
*/
void plat_delay(u32 delay)
{
while (delay--);
return;
}

View File

@ -0,0 +1,242 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-08-24 chinesebear first version
* 2020-08-10 lizhirui porting to ls2k
*/
#ifndef SYNOP_GMAC_PLAT_H
#define SYNOP_GMAC_PLAT_H 1
/* sw
#include <linux/kernel.h>
#include <asm/io.h>
#include <linux/gfp.h>
#include <linux/slab.h>
#include <linux/pci.h>
*/
#include "synopGMAC_types.h"
#include "synopGMAC_debug.h"
//#include "mii.h"
//#include "GMAC_Pmon.h"
//#include "synopGMAC_Host.h"
#include <rtthread.h>
#include <stdint.h>
#include "mips_addrspace.h"
//sw: copy the type define into here
#define IOCTL_READ_REGISTER SIOCDEVPRIVATE+1
#define IOCTL_WRITE_REGISTER SIOCDEVPRIVATE+2
#define IOCTL_READ_IPSTRUCT SIOCDEVPRIVATE+3
#define IOCTL_READ_RXDESC SIOCDEVPRIVATE+4
#define IOCTL_READ_TXDESC SIOCDEVPRIVATE+5
#define IOCTL_POWER_DOWN SIOCDEVPRIVATE+6
#define SYNOP_GMAC0 1
typedef int bool;
//typedef unsigned long dma_addr_t;
#define KUSEG_ADDR 0x0
#define CACHED_MEMORY_ADDR KSEG0BASE
#define UNCACHED_MEMORY_ADDR KSEG0BASE
#define KSEG2_ADDR KSEG2BASE
#define MAX_MEM_ADDR KSEG3BASE
#define RESERVED_ADDR KSEG3BASE
#define CACHED_TO_PHYS(x) ((uint64_t)(x) - CACHED_MEMORY_ADDR)
#define PHYS_TO_CACHED(x) ((uint64_t)(x) + CACHED_MEMORY_ADDR)
#define UNCACHED_TO_PHYS(x) ((uint64_t)(x) - UNCACHED_MEMORY_ADDR)
#define PHYS_TO_UNCACHED(x) ((uint64_t)(x) + UNCACHED_MEMORY_ADDR)
#define VA_TO_CINDEX(x) (PHYS_TO_CACHED(UNCACHED_TO_PHYS(x)))
#define CACHED_TO_UNCACHED(x) (PHYS_TO_UNCACHED(CACHED_TO_PHYS(x)))
#define VA_TO_PA(x) CACHED_TO_PHYS(x)
/* sw
#define TR0(fmt, args...) printk(KERN_CRIT "SynopGMAC: " fmt, ##args)
#ifdef DEBUG
#undef TR
# define TR(fmt, args...) printk(KERN_CRIT "SynopGMAC: " fmt, ##args)
#else
# define TR(fmt, args...) // not debugging: nothing
#endif
*/
/*
#define TR0(fmt, args...) printf("SynopGMAC: " fmt, ##args)
*/
/*
#ifdef DEBUG
#undef TR
# define TR(fmt, args...) printf("SynopGMAC: " fmt, ##args)
#else
//# define TR(fmt, args...) // not debugging: nothing
#define TR(fmt, args...) printf("SynopGMAC: " fmt, ##args)
#endif
*/
//sw: nothing to display
#define TR0(fmt, args...) //rt_kprintf(fmt, ##args)
#define TR(fmt, args...) //rt_kprintf(fmt, ##args)
//typedef int bool;
enum synopGMAC_boolean
{
false = 0,
true = 1
};
#define DEFAULT_DELAY_VARIABLE 10
#define DEFAULT_LOOP_VARIABLE 10000
/* There are platform related endian conversions
*
*/
#define LE32_TO_CPU __le32_to_cpu
#define BE32_TO_CPU __be32_to_cpu
#define CPU_TO_LE32 __cpu_to_le32
/* Error Codes */
#define ESYNOPGMACNOERR 0
#define ESYNOPGMACNOMEM 1
#define ESYNOPGMACPHYERR 2
#define ESYNOPGMACBUSY 3
struct Network_interface_data
{
u32 unit;
u64 addr;
u32 data;
};
/**
* These are the wrapper function prototypes for OS/platform related routines
*/
void * plat_alloc_memory(u32 );
void plat_free_memory(void *);
//void * plat_alloc_consistent_dmaable_memory(struct pci_dev *, u32, u32 *);
//void plat_free_consistent_dmaable_memory (struct pci_dev *, u32, void *, u32);
void plat_delay(u32);
/**
* The Low level function to read register contents from Hardware.
*
* @param[in] pointer to the base of register map
* @param[in] Offset from the base
* \return Returns the register contents
*/
static u32 synopGMACReadReg(u64 RegBase, u32 RegOffset)
{
u64 addr;
u32 data;
addr = RegBase + (u32)RegOffset;
data = *(volatile u32 *)addr;
#if SYNOP_REG_DEBUG
TR("%s RegBase = 0x%08x RegOffset = 0x%08x RegData = 0x%08x\n", __FUNCTION__, (u32)RegBase, RegOffset, data );
#endif
// rt_kprintf("%s RegBase = 0x%08x RegOffset = 0x%08x RegData = 0x%08x\n", __FUNCTION__, (u32)RegBase, RegOffset, data );
return data;
}
/**
* The Low level function to write to a register in Hardware.
*
* @param[in] pointer to the base of register map
* @param[in] Offset from the base
* @param[in] Data to be written
* \return void
*/
static void synopGMACWriteReg(u64 RegBase, u32 RegOffset, u32 RegData )
{
u64 addr;
addr = RegBase + (u32)RegOffset;
// rt_kprintf("%s RegBase = 0x%08x RegOffset = 0x%08x RegData = 0x%08x\n", __FUNCTION__,(u32) RegBase, RegOffset, RegData );
#if SYNOP_REG_DEBUG
TR("%s RegBase = 0x%p RegOffset = 0x%08x RegData = 0x%08x\n", __FUNCTION__,(u32) RegBase, RegOffset, RegData );
#endif
*(volatile u32 *)addr = RegData;
/*if(addr == 0xbfe1100c)
DEBUG_MES("regdata = %08x\n", RegData);*/
return;
}
/**
* The Low level function to set bits of a register in Hardware.
*
* @param[in] pointer to the base of register map
* @param[in] Offset from the base
* @param[in] Bit mask to set bits to logical 1
* \return void
*/
static void synopGMACSetBits(u64 RegBase, u32 RegOffset, u32 BitPos)
{
//u64 addr = (u64)RegBase + (u64)RegOffset;
u32 data;
data = synopGMACReadReg(RegBase, RegOffset);
data |= BitPos;
synopGMACWriteReg(RegBase, RegOffset, data);
// writel(data,(void *)addr);
#if SYNOP_REG_DEBUG
TR("%s !!!!!!!!!!!!! RegOffset = 0x%08x RegData = 0x%08x\n", __FUNCTION__, RegOffset, data );
#endif
return;
}
/**
* The Low level function to clear bits of a register in Hardware.
*
* @param[in] pointer to the base of register map
* @param[in] Offset from the base
* @param[in] Bit mask to clear bits to logical 0
* \return void
*/
static void synopGMACClearBits(u64 RegBase, u32 RegOffset, u32 BitPos)
{
u32 data;
data = synopGMACReadReg(RegBase, RegOffset);
data &= (~BitPos);
synopGMACWriteReg(RegBase, RegOffset, data);
#if SYNOP_REG_DEBUG
TR("%s !!!!!!!!!!!!! RegOffset = 0x%08x RegData = 0x%08x\n", __FUNCTION__, RegOffset, data );
#endif
return;
}
/**
* The Low level function to Check the setting of the bits.
*
* @param[in] pointer to the base of register map
* @param[in] Offset from the base
* @param[in] Bit mask to set bits to logical 1
* \return returns TRUE if set to '1' returns FALSE if set to '0'. Result undefined there are no bit set in the BitPos argument.
*
*/
static bool synopGMACCheckBits(u64 RegBase, u32 RegOffset, u32 BitPos)
{
u32 data;
data = synopGMACReadReg(RegBase, RegOffset);
data &= BitPos;
if(data)
{
return true;
}
else
{
return false;
}
}
#endif

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-08-24 chinesebear first version
*/
#ifndef __TYPES__H
#define __TYPES__H
typedef unsigned char uint8_t;
typedef unsigned long long u64;
typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;
typedef signed int s32;
typedef u32 dma_addr_t;
#endif /*__TYPES__H*/

View File

@ -6,16 +6,16 @@
/* RT-Thread Kernel */
#define RT_NAME_MAX 8
#define RT_NAME_MAX 30
#define RT_ALIGN_SIZE 8
#define RT_THREAD_PRIORITY_32
#define RT_THREAD_PRIORITY_MAX 32
#define RT_TICK_PER_SECOND 100
#define RT_TICK_PER_SECOND 1000
#define RT_USING_OVERFLOW_CHECK
#define RT_USING_HOOK
#define RT_USING_IDLE_HOOK
#define RT_IDLE_HOOK_LIST_SIZE 4
#define IDLE_THREAD_STACK_SIZE 2048
#define IDLE_THREAD_STACK_SIZE 16384
#define RT_DEBUG
/* Inter-Thread communication */
@ -39,13 +39,14 @@
#define RT_CONSOLEBUF_SIZE 256
#define RT_CONSOLE_DEVICE_NAME "uart"
#define RT_VER_NUM 0x40003
#define ARCH_CPU_64BIT
#define ARCH_MIPS64
/* RT-Thread Components */
#define RT_USING_COMPONENTS_INIT
#define RT_USING_USER_MAIN
#define RT_MAIN_THREAD_STACK_SIZE 2048
#define RT_MAIN_THREAD_STACK_SIZE 16384
#define RT_MAIN_THREAD_PRIORITY 10
/* C++ features */
@ -60,7 +61,7 @@
#define FINSH_USING_SYMTAB
#define FINSH_USING_DESCRIPTION
#define FINSH_THREAD_PRIORITY 20
#define FINSH_THREAD_STACK_SIZE 4096
#define FINSH_THREAD_STACK_SIZE 16384
#define FINSH_CMD_SIZE 80
#define FINSH_USING_MSH
#define FINSH_USING_MSH_DEFAULT
@ -70,15 +71,30 @@
#define RT_USING_DFS
#define DFS_USING_WORKDIR
#define DFS_FILESYSTEMS_MAX 2
#define DFS_FILESYSTEM_TYPES_MAX 2
#define DFS_FILESYSTEMS_MAX 10
#define DFS_FILESYSTEM_TYPES_MAX 10
#define DFS_FD_MAX 16
#define RT_USING_DFS_ELMFAT
/* elm-chan's FatFs, Generic FAT Filesystem Module */
#define RT_DFS_ELM_CODE_PAGE 936
#define RT_DFS_ELM_WORD_ACCESS
#define RT_DFS_ELM_USE_LFN_3
#define RT_DFS_ELM_USE_LFN 3
#define RT_DFS_ELM_MAX_LFN 255
#define RT_DFS_ELM_DRIVES 9
#define RT_DFS_ELM_MAX_SECTOR_SIZE 512
#define RT_DFS_ELM_REENTRANT
#define RT_USING_DFS_DEVFS
/* Device Drivers */
#define RT_USING_DEVICE_IPC
#define RT_PIPE_BUFSZ 512
#define RT_USING_SYSTEM_WORKQUEUE
#define RT_SYSTEM_WORKQUEUE_STACKSIZE 16384
#define RT_SYSTEM_WORKQUEUE_PRIORITY 5
#define RT_USING_SERIAL
#define RT_SERIAL_USING_DMA
#define RT_SERIAL_RB_BUFSZ 64
@ -96,12 +112,69 @@
/* Socket abstraction layer */
#define RT_USING_SAL
/* protocol stack implement */
#define SAL_USING_LWIP
#define SAL_SOCKETS_NUM 16
/* Network interface device */
#define RT_USING_NETDEV
#define NETDEV_USING_IFCONFIG
#define NETDEV_USING_PING
#define NETDEV_USING_NETSTAT
#define NETDEV_USING_AUTO_DEFAULT
#define NETDEV_IPV4 1
#define NETDEV_IPV6 0
/* light weight TCP/IP stack */
#define RT_USING_LWIP
#define RT_USING_LWIP202
#define RT_LWIP_MEM_ALIGNMENT 8
#define RT_LWIP_IGMP
#define RT_LWIP_ICMP
#define RT_LWIP_SNMP
#define RT_LWIP_DNS
#define RT_LWIP_DHCP
#define IP_SOF_BROADCAST 1
#define IP_SOF_BROADCAST_RECV 1
/* Static IPv4 Address */
#define RT_LWIP_IPADDR "192.168.1.30"
#define RT_LWIP_GWADDR "192.168.1.1"
#define RT_LWIP_MSKADDR "255.255.255.0"
#define RT_LWIP_UDP
#define RT_LWIP_TCP
#define RT_LWIP_RAW
#define RT_MEMP_NUM_NETCONN 8
#define RT_LWIP_PBUF_NUM 16
#define RT_LWIP_RAW_PCB_NUM 4
#define RT_LWIP_UDP_PCB_NUM 4
#define RT_LWIP_TCP_PCB_NUM 4
#define RT_LWIP_TCP_SEG_NUM 40
#define RT_LWIP_TCP_SND_BUF 8196
#define RT_LWIP_TCP_WND 8196
#define RT_LWIP_TCPTHREAD_PRIORITY 5
#define RT_LWIP_TCPTHREAD_MBOX_SIZE 32
#define RT_LWIP_TCPTHREAD_STACKSIZE 16384
#define RT_LWIP_ETHTHREAD_PRIORITY 5
#define RT_LWIP_ETHTHREAD_STACKSIZE 16384
#define RT_LWIP_ETHTHREAD_MBOX_SIZE 32
#define RT_LWIP_REASSEMBLY_FRAG
#define LWIP_NETIF_STATUS_CALLBACK 1
#define LWIP_NETIF_LINK_CALLBACK 1
#define SO_REUSE 1
#define LWIP_SO_RCVTIMEO 1
#define LWIP_SO_SNDTIMEO 1
#define LWIP_SO_RCVBUF 1
#define LWIP_SO_LINGER 0
#define LWIP_NETIF_LOOPBACK 0
#define RT_LWIP_STATS
#define RT_LWIP_USING_PING
/* AT commands */
@ -145,6 +218,9 @@
/* system packages */
#define PKG_USING_LWEXT4
#define RT_USING_DFS_LWEXT4
#define PKG_USING_LWEXT4_LATEST_VERSION
/* peripheral libraries and drivers */
@ -154,12 +230,6 @@
/* samples: kernel and components samples */
/* Privated Packages of RealThread */
/* Network Utilities */
#define SOC_LS2K1000
#endif

View File

@ -131,6 +131,10 @@ config RT_USING_LWIP
select NETDEV_IPV6_SCOPES if RT_USING_LWIP212
endif
config RT_LWIP_MEM_ALIGNMENT
int "Memory alignment"
default 4
config RT_LWIP_IGMP
bool "IGMP protocol"
default y

View File

@ -460,7 +460,7 @@ void sys_mbox_post(sys_mbox_t *mbox, void *msg)
{
RT_DEBUG_NOT_IN_INTERRUPT;
rt_mb_send_wait(*mbox, (rt_uint32_t)msg, RT_WAITING_FOREVER);
rt_mb_send_wait(*mbox, (rt_ubase_t)msg, RT_WAITING_FOREVER);
return;
}
@ -472,7 +472,7 @@ void sys_mbox_post(sys_mbox_t *mbox, void *msg)
*/
err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
{
if (rt_mb_send(*mbox, (rt_uint32_t)msg) == RT_EOK)
if (rt_mb_send(*mbox, (rt_ubase_t)msg) == RT_EOK)
return ERR_OK;
return ERR_MEM;

View File

@ -230,7 +230,12 @@
#define LWIP_DBG_TYPES_ON (LWIP_DBG_ON|LWIP_DBG_TRACE|LWIP_DBG_STATE|LWIP_DBG_FRESH|LWIP_DBG_HALT)
/* ---------- Memory options ---------- */
#ifdef RT_LWIP_MEM_ALIGNMENT
#define MEM_ALIGNMENT RT_LWIP_MEM_ALIGNMENT
#else
#define MEM_ALIGNMENT 4
#endif
#define MEMP_OVERFLOW_CHECK 1 ////
#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 1 ////
//#define MEM_LIBC_MALLOC 1

View File

@ -38,6 +38,7 @@
* after lwIP initialization.
* 2013-02-28 aozima fixed list_tcps bug: ipaddr_ntoa isn't reentrant.
* 2016-08-18 Bernard port to lwIP 2.0.0
* 2020-08-10 lizhirui fixed some problems when this is running on 64-bit cpu
*/
#include "lwip/opt.h"
@ -85,10 +86,10 @@ struct eth_tx_msg
static struct rt_mailbox eth_tx_thread_mb;
static struct rt_thread eth_tx_thread;
#ifndef RT_LWIP_ETHTHREAD_MBOX_SIZE
static char eth_tx_thread_mb_pool[32 * 4];
static char eth_tx_thread_mb_pool[32 * sizeof(rt_ubase_t)];
static char eth_tx_thread_stack[512];
#else
static char eth_tx_thread_mb_pool[RT_LWIP_ETHTHREAD_MBOX_SIZE * 4];
static char eth_tx_thread_mb_pool[RT_LWIP_ETHTHREAD_MBOX_SIZE * sizeof(rt_ubase_t)];
static char eth_tx_thread_stack[RT_LWIP_ETHTHREAD_STACKSIZE];
#endif
#endif
@ -97,10 +98,10 @@ static char eth_tx_thread_stack[RT_LWIP_ETHTHREAD_STACKSIZE];
static struct rt_mailbox eth_rx_thread_mb;
static struct rt_thread eth_rx_thread;
#ifndef RT_LWIP_ETHTHREAD_MBOX_SIZE
static char eth_rx_thread_mb_pool[48 * 4];
static char eth_rx_thread_mb_pool[48 * sizeof(rt_ubase_t)];
static char eth_rx_thread_stack[1024];
#else
static char eth_rx_thread_mb_pool[RT_LWIP_ETHTHREAD_MBOX_SIZE * 4];
static char eth_rx_thread_mb_pool[RT_LWIP_ETHTHREAD_MBOX_SIZE * sizeof(rt_ubase_t)];
static char eth_rx_thread_stack[RT_LWIP_ETHTHREAD_STACKSIZE];
#endif
#endif
@ -395,7 +396,7 @@ static err_t ethernetif_linkoutput(struct netif *netif, struct pbuf *p)
/* send a message to eth tx thread */
msg.netif = netif;
msg.buf = p;
if (rt_mb_send(&eth_tx_thread_mb, (rt_uint32_t) &msg) == RT_EOK)
if (rt_mb_send(&eth_tx_thread_mb, (rt_ubase_t) &msg) == RT_EOK)
{
/* waiting for ack */
rt_sem_take(&(enetif->tx_ack), RT_WAITING_FOREVER);
@ -599,7 +600,7 @@ rt_err_t eth_device_ready(struct eth_device* dev)
{
if (dev->netif)
/* post message to Ethernet thread */
return rt_mb_send(&eth_rx_thread_mb, (rt_uint32_t)dev);
return rt_mb_send(&eth_rx_thread_mb, (rt_ubase_t)dev);
else
return ERR_OK; /* netif is not initialized yet, just return. */
}
@ -619,7 +620,7 @@ rt_err_t eth_device_linkchange(struct eth_device* dev, rt_bool_t up)
rt_hw_interrupt_enable(level);
/* post message to ethernet thread */
return rt_mb_send(&eth_rx_thread_mb, (rt_uint32_t)dev);
return rt_mb_send(&eth_rx_thread_mb, (rt_ubase_t)dev);
}
#else
/* NOTE: please not use it in interrupt when no RxThread exist */
@ -739,7 +740,7 @@ int eth_system_device_init_private(void)
#ifndef LWIP_NO_RX_THREAD
/* initialize mailbox and create Ethernet Rx thread */
result = rt_mb_init(&eth_rx_thread_mb, "erxmb",
&eth_rx_thread_mb_pool[0], sizeof(eth_rx_thread_mb_pool)/4,
&eth_rx_thread_mb_pool[0], sizeof(eth_rx_thread_mb_pool)/sizeof(rt_ubase_t),
RT_IPC_FLAG_FIFO);
RT_ASSERT(result == RT_EOK);
@ -755,7 +756,7 @@ int eth_system_device_init_private(void)
#ifndef LWIP_NO_TX_THREAD
/* initialize mailbox and create Ethernet Tx thread */
result = rt_mb_init(&eth_tx_thread_mb, "etxmb",
&eth_tx_thread_mb_pool[0], sizeof(eth_tx_thread_mb_pool)/4,
&eth_tx_thread_mb_pool[0], sizeof(eth_tx_thread_mb_pool)/sizeof(rt_ubase_t),
RT_IPC_FLAG_FIFO);
RT_ASSERT(result == RT_EOK);

View File

@ -63,11 +63,11 @@ static struct rt_mailbox eth_rx_thread_mb;
static struct rt_thread eth_rx_thread;
#ifndef RT_LWIP_ETHTHREAD_PRIORITY
#define RT_ETHERNETIF_THREAD_PREORITY 0x90
static char eth_rx_thread_mb_pool[48 * 4];
static char eth_rx_thread_mb_pool[48 * sizeof(rt_ubase_t)];
static char eth_rx_thread_stack[1024];
#else
#define RT_ETHERNETIF_THREAD_PREORITY RT_LWIP_ETHTHREAD_PRIORITY
static char eth_rx_thread_mb_pool[RT_LWIP_ETHTHREAD_MBOX_SIZE * 4];
static char eth_rx_thread_mb_pool[RT_LWIP_ETHTHREAD_MBOX_SIZE * sizeof(rt_ubase_t)];
static char eth_rx_thread_stack[RT_LWIP_ETHTHREAD_STACKSIZE];
#endif
@ -79,10 +79,10 @@ struct eth_tx_msg
static struct rt_mailbox eth_tx_thread_mb;
static struct rt_thread eth_tx_thread;
#ifndef RT_LWIP_ETHTHREAD_PRIORITY
static char eth_tx_thread_mb_pool[32 * 4];
static char eth_tx_thread_mb_pool[32 * sizeof(rt_ubase_t)];
static char eth_tx_thread_stack[512];
#else
static char eth_tx_thread_mb_pool[RT_LWIP_ETHTHREAD_MBOX_SIZE * 4];
static char eth_tx_thread_mb_pool[RT_LWIP_ETHTHREAD_MBOX_SIZE * sizeof(rt_ubase_t)];
static char eth_tx_thread_stack[RT_LWIP_ETHTHREAD_STACKSIZE];
#endif
@ -281,7 +281,7 @@ rt_err_t eth_system_device_init()
/* init rx thread */
/* init mailbox and create ethernet thread */
result = rt_mb_init(&eth_rx_thread_mb, "erxmb",
&eth_rx_thread_mb_pool[0], sizeof(eth_rx_thread_mb_pool)/4,
&eth_rx_thread_mb_pool[0], sizeof(eth_rx_thread_mb_pool)/sizeof(rt_ubase_t),
RT_IPC_FLAG_FIFO);
RT_ASSERT(result == RT_EOK);
@ -297,7 +297,7 @@ rt_err_t eth_system_device_init()
/* init mailbox and create ethernet thread */
result = rt_mb_init(&eth_tx_thread_mb, "etxmb",
&eth_tx_thread_mb_pool[0], sizeof(eth_tx_thread_mb_pool)/4,
&eth_tx_thread_mb_pool[0], sizeof(eth_tx_thread_mb_pool)/sizeof(rt_ubase_t),
RT_IPC_FLAG_FIFO);
RT_ASSERT(result == RT_EOK);

View File

@ -82,6 +82,10 @@ config ARCH_MIPS
config ARCH_MIPS64
bool
select ARCH_CPU_64BIT
config ARCH_CPU_64BIT
bool
config ARCH_MIPS_XBURST
bool

View File

@ -1,11 +1,12 @@
/*
* Copyright (c) 2006-2019, RT-Thread Development Team
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-12-04 Jiaxun Yang Initial version
* 2020-07-26 lizhirui Fixed some problems
*/
#ifndef __ASSEMBLY__
@ -56,12 +57,12 @@ rt_hw_context_switch_interrupt:
bnez t1, _reswitch
nop
li t1, 0x01 /* set rt_thread_switch_interrupt_flag to 1 */
sw t1, 0(t0)
LONG_S t1, 0(t0)
PTR_LA t0, rt_interrupt_from_thread /* set rt_interrupt_from_thread */
sw a0, 0(t0)
LONG_S a0, 0(t0)
_reswitch:
PTR_LA t0, rt_interrupt_to_thread /* set rt_interrupt_to_thread */
sw a1, 0(t0)
LONG_S a1, 0(t0)
jr ra
nop
@ -97,24 +98,24 @@ mips_irq_handle:
* rt_hw_context_switch_interrupt_do and do not return
*/
PTR_LA k0, rt_thread_switch_interrupt_flag
lw k1, 0(k0)
LONG_L k1, 0(k0)
beqz k1, spurious_interrupt
nop
sw zero, 0(k0) /* clear flag */
LONG_S zero, 0(k0) /* clear flag */
nop
/*
* switch to the new thread
*/
PTR_LA k0, rt_interrupt_from_thread
lw k1, 0(k0)
LONG_L k1, 0(k0)
nop
sw sp, 0(k1) /* store sp in preempted task TCB */
LONG_S sp, 0(k1) /* store sp in preempted task TCB */
PTR_LA k0, rt_interrupt_to_thread
lw k1, 0(k0)
LONG_L k1, 0(k0)
nop
lw sp, 0(k1) /* get new task stack pointer */
LONG_L sp, 0(k1) /* get new task stack pointer */
j spurious_interrupt
nop

View File

@ -24,6 +24,41 @@ rt_ubase_t rt_interrupt_from_thread;
rt_ubase_t rt_interrupt_to_thread;
rt_ubase_t rt_thread_switch_interrupt_flag;
const char *exception_name[] = {
"Interrupt",
"(X)TLB Modify Exception",
"(X)TLB Read/Fetch Exception",
"(X)TLB Write Exception",
"Address Read/Fetch Exception",
"Address Write Exception",
"",
"",
"Syscall",
"Breakpoint",
"Reversed Instruction Exception",
"Coprocessor Unit Invalid",
"Overflow",
"Trap",
"FPU Exception in Vector Instruction",
"FPU Exception",
"Loongson Custom Exception",
"",
"",
"(X)TLB Read Denied Exception",
"(X)TLB Execute Denied Exception",
"Vector Module Disabled Exception",
"",
"",
"",
"",
"",
"",
"",
"",
"Cache Error Exception",
""
};
rt_base_t rt_hw_interrupt_disable(void)
{
rt_base_t status = read_c0_status();
@ -87,10 +122,15 @@ void cache_error_handler(void)
static void unhandled_exception_handle(struct pt_regs *regs)
{
rt_kprintf("Unknown Exception, EPC: 0x%08x, CAUSE: 0x%08x\n", read_c0_epc(),
read_c0_cause());
rt_kprintf("ST0: 0x%08x ", regs->cp0_status);
rt_kprintf("ErrorPC: 0x%08x\n", read_c0_errorepc());
rt_kprintf("Unknown Exception, EPC: 0x%p, CAUSE: 0x%08x\n", read_c0_epc(), read_c0_cause());
rt_kprintf("Exception Name:%s\n",exception_name[(read_c0_cause() >> 2) & 0x1f]);
#ifdef SOC_LS2K1000
rt_kprintf("ExeCode = 0x%08x,BadAddr = 0x%p\n",(read_c0_cause() >> 2) & 0x1f,mmu_tlb_get_bad_vaddr());
#else
rt_kprintf("ExeCode = 0x%08x\n",(read_c0_cause() >> 2) & 0x1f);
#endif
rt_kprintf("ST0: 0x%08x ",regs->cp0_status);
rt_kprintf("ErrorPC: 0x%p\n",read_c0_errorepc());
mips_dump_regs(regs);
rt_hw_cpu_shutdown();
}

View File

@ -1,11 +1,12 @@
/*
* Copyright (c) 2006-2019, RT-Thread Development Team
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-12-04 Jiaxun Yang Initial version
* 2020-07-26 lizhirui Add xtlb exception entry
*/
#ifndef __ASSEMBLY__
#define __ASSEMBLY__
@ -26,6 +27,11 @@ tlb_refill_exception:
b _general_exception_handler
nop
/* 0x080 - XTLB refill handler */
.org ebase_start + 0x080
b _general_exception_handler
nop
/* 0x100 - Cache error handler */
.org ebase_start + 0x100
j cache_error_handler

View File

@ -206,6 +206,8 @@
li v1, ~(ST0_CU1 | ST0_FR | ST0_IM)
and v0, v1
or v0, a0
li v1, (ST0_KX | ST0_SX | ST0_UX)
or v0, v1
mtc0 v0, CP0_STATUS
LONG_L v1, PT_EPC(sp)
MTC0 v1, CP0_EPC

70
libcpu/mips/gs264/cache.c Normal file
View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-03-29 quanzhao the first version
* 2020-07-26 lizhirui porting to ls2k
*/
#include <rthw.h>
#include <rtdef.h>
rt_inline rt_uint64_t rt_cpu_icache_line_size(void)
{
rt_uint64_t ctr;
return 4 << (ctr & 0xF);
}
rt_inline rt_uint64_t rt_cpu_dcache_line_size(void)
{
rt_uint64_t ctr;
return 4 << ((ctr >> 16) & 0xF);
}
void rt_hw_cpu_icache_invalidate(void *addr, int size)
{
rt_uint64_t line_size = rt_cpu_icache_line_size();
rt_uint64_t start_addr = (rt_uint64_t)addr;
rt_uint64_t end_addr = (rt_uint64_t) addr + size + line_size - 1;
}
void rt_hw_cpu_dcache_invalidate(void *addr, int size)
{
rt_uint64_t line_size = rt_cpu_dcache_line_size();
rt_uint64_t start_addr = (rt_uint64_t)addr;
rt_uint64_t end_addr = (rt_uint64_t) addr + size + line_size - 1;
}
void rt_hw_cpu_dcache_clean(void *addr, int size)
{
rt_uint64_t line_size = rt_cpu_dcache_line_size();
rt_uint64_t start_addr = (rt_uint64_t)addr;
rt_uint64_t end_addr = (rt_uint64_t) addr + size + line_size - 1;
}
void rt_hw_cpu_icache_ops(int ops, void *addr, int size)
{
if (ops == RT_HW_CACHE_INVALIDATE)
rt_hw_cpu_icache_invalidate(addr, size);
}
void rt_hw_cpu_dcache_ops(int ops, void *addr, int size)
{
if (ops == RT_HW_CACHE_FLUSH)
rt_hw_cpu_dcache_clean(addr, size);
else if (ops == RT_HW_CACHE_INVALIDATE)
rt_hw_cpu_dcache_invalidate(addr, size);
}
rt_base_t rt_hw_cpu_icache_status(void)
{
return 0;
}
rt_base_t rt_hw_cpu_dcache_status(void)
{
return 0;
}

24
libcpu/mips/gs264/cache.h Normal file
View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-03-25 quanzhao the first version
*/
#ifndef __CACHE_H__
#define __CACHE_H__
unsigned long rt_cpu_get_smp_id(void);
void rt_cpu_mmu_disable(void);
void rt_cpu_mmu_enable(void);
void rt_cpu_tlb_set(volatile unsigned long*);
void rt_cpu_dcache_clean_flush(void);
void rt_cpu_icache_flush(void);
void rt_cpu_vector_set_base(unsigned int addr);
#endif

View File

@ -0,0 +1,222 @@
/*
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-07-26 lizhirui the first version
*/
#include <string.h>
#include <stdlib.h>
#include "mips.h"
#include "mips_mmu.h"
void mmu_init()
{
uint32_t status = read_c0_status();
status |= 0x07 << 5;//ux = 1,sx = 1,kx = 1
write_c0_status(status);
mmu_clear_tlb();
mmu_clear_itlb();
}
void mmu_set_cpu_mode(cpu_mode_t cpu_mode)
{
uint32_t status = read_c0_status();
status &= ~(0x03 << 3);
status |= ((uint32_t)cpu_mode & 0x03) << 3;
write_c0_status(status);
}
cpu_mode_t mmu_get_cpu_mode()
{
uint32_t status = read_c0_status();
return (cpu_mode_t)((status >> 3) & 0x03);
}
void mmu_clear_tlb()
{
uint32_t max_tlb_index = mmu_get_max_tlb_index();
uint64_t va = KSEG0BASE;
uint32_t entry;
tlb_item_t tlb_item;
for(entry = 0;entry <= max_tlb_index;entry++)
{
mmu_tlb_item_init(&tlb_item);
mmu_tlb_write_indexed(entry,&tlb_item);
}
}
void mmu_clear_itlb()
{
uint32_t diag = read_c0_diag();
write_c0_diag(diag | (0x01 << 2));//write ITLB bit
read_c0_entrylo0();
}
uint32_t mmu_get_max_tlb_index()
{
uint32_t config1 = read_c0_config1();
return ((config1 >> 25) & 0x3F);
}
void mmu_tlb_write_indexed(uint32_t index,tlb_item_t *tlb_item)
{
tlb_item -> entry_lo[0].g |= tlb_item -> entry_lo[1].g;
tlb_item -> entry_lo[1].g |= tlb_item -> entry_lo[0].g;
mmu_tlb_set_index(index);
write_c0_entrylo0(reg_type_convert(tlb_item -> entry_lo[0],uint64_t));
write_c0_entrylo1(reg_type_convert(tlb_item -> entry_lo[1],uint64_t));
write_c0_entryhi(reg_type_convert(tlb_item -> entry_hi,uint64_t));
write_c0_pagemask(reg_type_convert(tlb_item -> page_mask,uint64_t));
tlb_write_indexed();
read_c0_entrylo0();
}
void mmu_tlb_write_random(tlb_item_t *tlb_item)
{
tlb_item -> entry_lo[0].g |= tlb_item -> entry_lo[1].g;
tlb_item -> entry_lo[1].g |= tlb_item -> entry_lo[0].g;
write_c0_entrylo0(reg_type_convert(tlb_item -> entry_lo[0],uint64_t));
write_c0_entrylo1(reg_type_convert(tlb_item -> entry_lo[1],uint64_t));
write_c0_entryhi(reg_type_convert(tlb_item -> entry_hi,uint64_t));
write_c0_pagemask(reg_type_convert(tlb_item -> page_mask,uint64_t));
tlb_write_random();
read_c0_entrylo0();
}
void mmu_tlb_read(uint32_t index,tlb_item_t *tlb_item)
{
mmu_tlb_set_index(index);
tlb_read();
uint64_t entrylo[2];
uint64_t entryhi;
uint64_t page_mask;
entrylo[0] = read_c0_entrylo0();
entrylo[1] = read_c0_entrylo1();
entryhi = read_c0_entryhi();
page_mask = read_c0_pagemask();
tlb_item -> entry_lo[0] = reg_type_convert(entrylo[0],entry_lo_t);
tlb_item -> entry_lo[1] = reg_type_convert(entrylo[1],entry_lo_t);
tlb_item -> entry_hi = reg_type_convert(entryhi,entry_hi_t);
tlb_item -> page_mask = reg_type_convert(page_mask,page_mask_t);
}
uint32_t mmu_tlb_find(uint64_t vpn,uint32_t asid,uint32_t *index)
{
entry_hi_t entry_hi;
entry_hi.r = (vpn >> 62) & 0x03;
entry_hi.vpn2 = (vpn >> 13) & 0x7FFFFFFU;
entry_hi.asid = asid & 0xFFU;
tlb_item_t tlb_item;
//mmu_tlb_read(6,&tlb_item);
//tlb_dump();
mmu_tlb_item_init(&tlb_item);
tlb_item.entry_lo[0].g = tlb_item.entry_lo[1].g = 1;
read_c0_entrylo0();//i don't know why,but if i don't read any register of mmu,tplb will be failed in qemu.
write_c0_entrylo0(reg_type_convert(tlb_item.entry_lo[0],uint64_t));
write_c0_entrylo1(reg_type_convert(tlb_item.entry_lo[1],uint64_t));
write_c0_entryhi(reg_type_convert(entry_hi,uint64_t));
//__asm__ __volatile__("ehb");
//read_c0_entryhi();
//rt_kprintf("entry_hi = %p\n",read_c0_entryhi());
tlb_probe();
*index = mmu_tlb_get_index();
return mmu_tlb_is_matched();
}
void mmu_tlb_item_init(tlb_item_t *tlb_item)
{
memset(tlb_item,0,sizeof(tlb_item_t));
tlb_item -> entry_lo[0].c = 0x03;
tlb_item -> entry_lo[1].c = 0x03;
}
void mmu_set_map(uint64_t vpn,uint64_t ppn,page_mask_enum_t page_mask,uint32_t asid,uint32_t global)
{
uint64_t page_mask_v = (uint64_t)page_mask;
/*if(page_mask_v & (1 << 13))
{
page_mask_v |= (1 << 12);
}*/
uint64_t lb = lowbit((~(page_mask_v)) << 12);
uint64_t pn_remained = ((~(page_mask_v)) << 12) | lb;
vpn &= pn_remained;
ppn &= pn_remained;
uint64_t odd_vpn = vpn | lb;
uint64_t even_vpn = vpn & (~lb);
uint32_t index;
tlb_item_t tlb_item,tlb2_item;
mmu_tlb_item_init(&tlb_item);
mmu_tlb_item_init(&tlb2_item);
tlb_item.page_mask.mask = page_mask;
if(mmu_tlb_find(vpn & (~lb),asid,&index))
{
mmu_tlb_read(index,&tlb_item);
mmu_tlb_write_indexed(index,&tlb2_item);
}
entry_lo_t *entry_lo = &tlb_item.entry_lo[vpn == even_vpn ? 0 : 1];
tlb_item.entry_lo[0].g = tlb_item.entry_lo[1].g = global;
entry_lo -> d = 1;
entry_lo -> ri = 0;
entry_lo -> xi = 0;
entry_lo -> v = 1;
entry_lo -> pfn = ppn >> 12;
tlb_item.entry_hi.r = (vpn >> 62) & 0x03;
tlb_item.entry_hi.vpn2 = (vpn >> 13) & 0x7FFFFFFU;
tlb_item.entry_hi.asid = asid & 0xFFU;
mmu_tlb_write_random(&tlb_item);
}
uint32_t mmu_tlb_get_random()
{
return read_c0_random();
}
uint32_t mmu_tlb_get_index()
{
return read_c0_index() & 0x3F;
}
void mmu_tlb_set_index(uint32_t index)
{
write_c0_index(index & 0x3F);
}
uint32_t mmu_tlb_is_matched()
{
return (read_c0_index() & 0x80000000) == 0;
}
uint64_t mmu_tlb_get_bad_vaddr()
{
return read_c0_badvaddr();
}
void tlb_dump()
{
uint32_t max_index = mmu_get_max_tlb_index();
//uint32_t max_index = 10;
uint32_t entry;
tlb_item_t tlb_item;
for(entry = 0;entry <= max_index;entry++)
{
mmu_tlb_read(entry,&tlb_item);
//mmu_tlb_write_indexed(entry,&tlb_item);
//mmu_tlb_read(entry,&tlb_item);
rt_kprintf("vpn = 0x%p,ppn0 = 0x%p,ppn1 = 0x%p\n",(uint64_t)tlb_item.entry_hi.vpn2 << 13 | (uint64_t)tlb_item.entry_hi.asid << 62,(uint64_t)tlb_item.entry_lo[0].pfn << 12,(uint64_t)tlb_item.entry_lo[1].pfn << 12);
rt_kprintf("v = %d,d = %d,g = %d,ri = %d,xi = %d,c = %d\n",tlb_item.entry_lo[0].v,tlb_item.entry_lo[0].d,tlb_item.entry_lo[0].g,tlb_item.entry_lo[0].ri,tlb_item.entry_lo[0].xi,tlb_item.entry_lo[0].c);
rt_kprintf("v = %d,d = %d,g = %d,ri = %d,xi = %d,c = %d\n",tlb_item.entry_lo[1].v,tlb_item.entry_lo[1].d,tlb_item.entry_lo[1].g,tlb_item.entry_lo[1].ri,tlb_item.entry_lo[1].xi,tlb_item.entry_lo[1].c);
}
}

View File

@ -0,0 +1,99 @@
/*
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-07-26 lizhirui the first version
*/
#ifndef __MIPS_MMU_H__
#define __MIPS_MMU_H__
typedef enum cpu_mode_t
{
CPU_MODE_KERNEL = 0x00,
CPU_MODE_SUPERVISOR = 0x01,
CPU_MODE_USER = 0x02
}cpu_mode_t;
typedef enum page_mask_enum_t
{
PAGE_MASK_4KB = 0x00,
PAGE_MASK_16KB = 0x03,
PAGE_MASK_64KB = 0x0F,
PAGE_MASK_256KB = 0x3F,
PAGE_MASK_1MB = 0xFF,
PAGE_MASK_4MB = 0x3FF,
PAGE_MASK_16MB = 0xFFF,
PAGE_MASK_64MB = 0x3FFF,
PAGE_MASK_256MB = 0xFFFF,
PAGE_MASK_1GB = 0x3FFFF
}page_mask_enum_t;
typedef struct page_mask_t
{
uint64_t : 11;
uint64_t : 2;
uint64_t mask : 18;
uint64_t : 33;
}page_mask_t;
typedef struct entry_lo_t
{
uint64_t g : 1;
uint64_t v : 1;
uint64_t d : 1;
uint64_t c : 3;
uint64_t pfn : 24;
uint64_t pfnx : 3;
uint64_t : 29;
uint64_t xi : 1;
uint64_t ri : 1;
}entry_lo_t;
typedef struct entry_hi_t
{
uint64_t asid : 8;
uint64_t : 5;
uint64_t vpn2 : 27;
uint64_t : 22;
uint64_t r : 2;
}entry_hi_t;
typedef struct tlb_item_t
{
entry_lo_t entry_lo[2];
entry_hi_t entry_hi;
page_mask_t page_mask;
}tlb_item_t;
#define read_c0_diag() __read_32bit_c0_register($22, 0)
#define write_c0_diag(val) __write_32bit_c0_register($22, 0, val)
#define read_c0_badvaddr() __read_64bit_c0_register($8, 0)
#define read_c0_random() __read_32bit_c0_register($1, 0)
#define reg_type_convert(variable,new_type) *((new_type *)(&variable))
#define lowbit(x) ((x) & (-(x)))
void mmu_init();
void mmu_set_cpu_mode(cpu_mode_t cpu_mode);
cpu_mode_t mmu_get_cpu_mode();
void mmu_clear_tlb();
void mmu_clear_itlb();
uint32_t mmu_get_max_tlb_index();
void mmu_tlb_write_indexed(uint32_t index,tlb_item_t *tlb_item);
void mmu_tlb_write_random(tlb_item_t *tlb_item);
void mmu_tlb_read(uint32_t index,tlb_item_t *tlb_item);
uint32_t mmu_tlb_find(uint64_t vpn,uint32_t asid,uint32_t *index);
void mmu_tlb_item_init(tlb_item_t *tlb_item);
void mmu_set_map(uint64_t vpn,uint64_t ppn,page_mask_enum_t page_mask,uint32_t asid,uint32_t global);
uint32_t mmu_tlb_get_random();
uint32_t mmu_tlb_get_index();
void mmu_tlb_set_index(uint32_t index);
uint32_t mmu_tlb_is_matched();
uint64_t mmu_tlb_get_bad_vaddr();
void tlb_dump();
#endif

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-07-28 lizhirui first version
*/
#include <rtthread.h>
#include <mips.h>
mips32_core_cfg_t g_mips_core =
{
64, /* icache_line_size */
128, /* icache_lines_per_way */
4, /* icache_ways */
32768,
64, /* dcache_line_size */
128, /* dcache_lines_per_way */
4, /* dcache_ways */
32768,
64, /* max_tlb_entries */
};
static rt_uint16_t m_pow(rt_uint16_t b, rt_uint16_t n)
{
rt_uint16_t rets = 1;
while (n--)
rets *= b;
return rets;
}
static rt_uint16_t m_log2(rt_uint16_t b)
{
rt_uint16_t rets = 0;
while (b != 1)
{
b /= 2;
rets++;
}
return rets;
}
/**
* read core attribute
*/
void mips32_cfg_init(void)
{
rt_uint16_t val;
rt_uint32_t cp0_config1;
cp0_config1 = read_c0_config();
if (cp0_config1 & 0x80000000)
{
cp0_config1 = read_c0_config1();
val = (cp0_config1 & (7<<22))>>22;
g_mips_core.icache_lines_per_way = 64 * m_pow(2, val);
val = (cp0_config1 & (7<<19))>>19;
g_mips_core.icache_line_size = 2 * m_pow(2, val);
val = (cp0_config1 & (7<<16))>>16;
g_mips_core.icache_ways = val + 1;
val = (cp0_config1 & (7<<13))>>13;
g_mips_core.dcache_lines_per_way = 64 * m_pow(2, val);
val = (cp0_config1 & (7<<10))>>10;
g_mips_core.dcache_line_size = 2 * m_pow(2, val);
val = (cp0_config1 & (7<<7))>>7;
g_mips_core.dcache_ways = val + 1;
val = (cp0_config1 & (0x3F<<25))>>25;
g_mips_core.max_tlb_entries = val + 1;
}
}

819
libcpu/mips/gs264/mmu.c Normal file
View File

@ -0,0 +1,819 @@
/*
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-01-10 bernard porting to AM1808
* 2020-07-26 lizhirui porting to ls2k
*/
#include <rtthread.h>
#include <rthw.h>
#include <board.h>
#include "cache.h"
#include "mips_mmu.h"
#include "mmu.h"
void *current_mmu_table = RT_NULL;
void *mmu_table_get()
{
return current_mmu_table;
}
void switch_mmu(void *mmu_table)
{
current_mmu_table = mmu_table;
mmu_clear_tlb();
mmu_clear_itlb();
}
/* dump 2nd level page table */
void rt_hw_cpu_dump_page_table_2nd(rt_uint32_t *ptb)
{
int i;
int fcnt = 0;
for (i = 0; i < 256; i++)
{
rt_uint32_t pte2 = ptb[i];
if ((pte2 & 0x3) == 0)
{
if (fcnt == 0)
rt_kprintf(" ");
rt_kprintf("%04x: ", i);
fcnt++;
if (fcnt == 16)
{
rt_kprintf("fault\n");
fcnt = 0;
}
continue;
}
if (fcnt != 0)
{
rt_kprintf("fault\n");
fcnt = 0;
}
rt_kprintf(" %04x: %x: ", i, pte2);
if ((pte2 & 0x3) == 0x1)
{
rt_kprintf("L,ap:%x,xn:%d,texcb:%02x\n",
((pte2 >> 7) | (pte2 >> 4))& 0xf,
(pte2 >> 15) & 0x1,
((pte2 >> 10) | (pte2 >> 2)) & 0x1f);
}
else
{
rt_kprintf("S,ap:%x,xn:%d,texcb:%02x\n",
((pte2 >> 7) | (pte2 >> 4))& 0xf, pte2 & 0x1,
((pte2 >> 4) | (pte2 >> 2)) & 0x1f);
}
}
}
void rt_hw_cpu_dump_page_table(rt_uint32_t *ptb)
{
int i;
int fcnt = 0;
rt_kprintf("page table@%p\n", ptb);
for (i = 0; i < 1024*4; i++)
{
rt_uint32_t pte1 = ptb[i];
if ((pte1 & 0x3) == 0)
{
rt_kprintf("%03x: ", i);
fcnt++;
if (fcnt == 16)
{
rt_kprintf("fault\n");
fcnt = 0;
}
continue;
}
if (fcnt != 0)
{
rt_kprintf("fault\n");
fcnt = 0;
}
rt_kprintf("%03x: %08x: ", i, pte1);
if ((pte1 & 0x3) == 0x3)
{
rt_kprintf("LPAE\n");
}
else if ((pte1 & 0x3) == 0x1)
{
rt_kprintf("pte,ns:%d,domain:%d\n",
(pte1 >> 3) & 0x1, (pte1 >> 5) & 0xf);
/*
*rt_hw_cpu_dump_page_table_2nd((void*)((pte1 & 0xfffffc000)
* - 0x80000000 + 0xC0000000));
*/
}
else if (pte1 & (1 << 18))
{
rt_kprintf("super section,ns:%d,ap:%x,xn:%d,texcb:%02x\n",
(pte1 >> 19) & 0x1,
((pte1 >> 13) | (pte1 >> 10))& 0xf,
(pte1 >> 4) & 0x1,
((pte1 >> 10) | (pte1 >> 2)) & 0x1f);
}
else
{
rt_kprintf("section,ns:%d,ap:%x,"
"xn:%d,texcb:%02x,domain:%d\n",
(pte1 >> 19) & 0x1,
((pte1 >> 13) | (pte1 >> 10))& 0xf,
(pte1 >> 4) & 0x1,
(((pte1 & (0x7 << 12)) >> 10) |
((pte1 & 0x0c) >> 2)) & 0x1f,
(pte1 >> 5) & 0xf);
}
}
}
/* level1 page table, each entry for 1MB memory. */
volatile unsigned long MMUTable[4*1024] __attribute__((aligned(16*1024)));
void rt_hw_mmu_setmtt(rt_uint32_t vaddrStart,
rt_uint32_t vaddrEnd,
rt_uint32_t paddrStart,
rt_uint32_t attr)
{
volatile rt_uint32_t *pTT;
volatile int i, nSec;
pTT = (rt_uint32_t *)MMUTable + (vaddrStart >> 20);
nSec = (vaddrEnd >> 20) - (vaddrStart >> 20);
for(i = 0; i <= nSec; i++)
{
*pTT = attr | (((paddrStart >> 20) + i) << 20);
pTT++;
}
}
unsigned long rt_hw_set_domain_register(unsigned long domain_val)
{
unsigned long old_domain;
//asm volatile ("mrc p15, 0, %0, c3, c0\n" : "=r" (old_domain));
//asm volatile ("mcr p15, 0, %0, c3, c0\n" : :"r" (domain_val) : "memory");
return old_domain;
}
void rt_hw_cpu_dcache_clean(void *addr, int size);
void rt_hw_init_mmu_table(struct mem_desc *mdesc, rt_uint32_t size)
{
/* set page table */
for(; size > 0; size--)
{
rt_hw_mmu_setmtt(mdesc->vaddr_start, mdesc->vaddr_end,
mdesc->paddr_start, mdesc->attr);
mdesc++;
}
rt_hw_cpu_dcache_clean((void*)MMUTable, sizeof MMUTable);
}
void rt_hw_mmu_init(void)
{
rt_cpu_dcache_clean_flush();
rt_cpu_icache_flush();
rt_hw_cpu_dcache_disable();
rt_hw_cpu_icache_disable();
rt_cpu_mmu_disable();
/*rt_hw_cpu_dump_page_table(MMUTable);*/
rt_hw_set_domain_register(0x55555555);
rt_cpu_tlb_set(MMUTable);
rt_cpu_mmu_enable();
rt_hw_cpu_icache_enable();
rt_hw_cpu_dcache_enable();
}
/*
mem map
*/
void rt_hw_cpu_dcache_clean(void *addr, int size);
int rt_hw_mmu_map_init(rt_mmu_info *mmu_info, void* v_address, size_t size, size_t *vtable, size_t pv_off)
{
size_t l1_off, va_s, va_e;
rt_base_t level;
if (!mmu_info || !vtable)
{
return -1;
}
va_s = (size_t)v_address;
va_e = (size_t)v_address + size - 1;
if ( va_e < va_s)
{
return -1;
}
va_s >>= ARCH_SECTION_SHIFT;
va_e >>= ARCH_SECTION_SHIFT;
if (va_s == 0)
{
return -1;
}
level = rt_hw_interrupt_disable();
for (l1_off = va_s; l1_off <= va_e; l1_off++)
{
size_t v = vtable[l1_off];
if (v & ARCH_MMU_USED_MASK)
{
rt_kprintf("Error:vtable[%d] = 0x%p(is not zero),va_s = 0x%p,va_e = 0x%p!\n",l1_off,v,va_s,va_e);
rt_hw_interrupt_enable(level);
return -1;
}
}
mmu_info->vtable = vtable;
mmu_info->vstart = va_s;
mmu_info->vend = va_e;
mmu_info->pv_off = pv_off;
rt_hw_interrupt_enable(level);
return 0;
}
static size_t find_vaddr(rt_mmu_info *mmu_info, int pages)
{
size_t l1_off, l2_off;
size_t *mmu_l1, *mmu_l2;
size_t find_off = 0;
size_t find_va = 0;
int n = 0;
if (!pages)
{
return 0;
}
if (!mmu_info)
{
return 0;
}
for (l1_off = mmu_info->vstart; l1_off <= mmu_info->vend; l1_off++)
{
mmu_l1 = (size_t*)mmu_info->vtable + l1_off;
if (*mmu_l1 & ARCH_MMU_USED_MASK)
{
mmu_l2 = (size_t *)((*mmu_l1 & ~ARCH_PAGE_TBL_MASK) - mmu_info->pv_off);
for (l2_off = 0; l2_off < (ARCH_SECTION_SIZE/ARCH_PAGE_SIZE); l2_off++)
{
if (*(mmu_l2 + l2_off) & ARCH_MMU_USED_MASK)
{
/* in use */
n = 0;
}
else
{
if (!n)
{
find_va = l1_off;
find_off = l2_off;
}
n++;
if (n >= pages)
{
return (find_va << ARCH_SECTION_SHIFT) + (find_off << ARCH_PAGE_SHIFT);
}
}
}
}
else
{
if (!n)
{
find_va = l1_off;
find_off = 0;
}
n += (ARCH_SECTION_SIZE/ARCH_PAGE_SIZE);
if (n >= pages)
{
return (find_va << ARCH_SECTION_SHIFT) + (find_off << ARCH_PAGE_SHIFT);
}
}
}
return 0;
}
#ifdef RT_USING_USERSPACE
static int check_vaddr(rt_mmu_info *mmu_info, void *va, int pages)
{
size_t loop_va = (size_t)va & ~ARCH_PAGE_MASK;
size_t l1_off, l2_off;
size_t *mmu_l1, *mmu_l2;
if (!pages)
{
return -1;
}
if (!mmu_info)
{
return -1;
}
while (pages--)
{
l1_off = (loop_va >> ARCH_SECTION_SHIFT);
l2_off = ((loop_va & ARCH_SECTION_MASK) >> ARCH_PAGE_SHIFT);
mmu_l1 = (size_t*)mmu_info->vtable + l1_off;
if (*mmu_l1 & ARCH_MMU_USED_MASK)
{
mmu_l2 = (size_t *)((*mmu_l1 & ~ARCH_PAGE_TBL_MASK) - mmu_info->pv_off);
if (*(mmu_l2 + l2_off) & ARCH_MMU_USED_MASK)
{
return -1;
}
}
loop_va += ARCH_PAGE_SIZE;
}
return 0;
}
#endif
static void __rt_hw_mmu_unmap(rt_mmu_info *mmu_info, void* v_addr, size_t npages)
{
size_t loop_va = (size_t)v_addr & ~ARCH_PAGE_MASK;
size_t l1_off, l2_off;
size_t *mmu_l1, *mmu_l2;
size_t *ref_cnt;
if (!mmu_info)
{
return;
}
while (npages--)
{
l1_off = (loop_va >> ARCH_SECTION_SHIFT);
if (l1_off < mmu_info->vstart || l1_off > mmu_info->vend)
{
return;
}
l2_off = ((loop_va & ARCH_SECTION_MASK) >> ARCH_PAGE_SHIFT);
mmu_l1 = (size_t*)mmu_info->vtable + l1_off;
if (*mmu_l1 & ARCH_MMU_USED_MASK)
{
mmu_l2 = (size_t *)((*mmu_l1 & ~ARCH_PAGE_TBL_MASK) - mmu_info->pv_off);
}
else
{
return;
}
if (*(mmu_l2 + l2_off) & ARCH_MMU_USED_MASK)
{
*(mmu_l2 + l2_off) = 0;
/* cache maintain */
rt_hw_cpu_dcache_clean(mmu_l2 + l2_off, 4);
ref_cnt = mmu_l2 + (ARCH_SECTION_SIZE/ARCH_PAGE_SIZE);
(*ref_cnt)--;
if (!*ref_cnt)
{
#ifdef RT_USING_USERSPACE
rt_pages_free(mmu_l2, 0);
#else
rt_free_align(mmu_l2);
#endif
*mmu_l1 = 0;
/* cache maintain */
rt_hw_cpu_dcache_clean(mmu_l1, 4);
}
}
loop_va += ARCH_PAGE_SIZE;
}
}
static int __rt_hw_mmu_map(rt_mmu_info *mmu_info, void* v_addr, void* p_addr, size_t npages, size_t attr)
{
size_t loop_va = (size_t)v_addr & ~ARCH_PAGE_MASK;
size_t loop_pa = (size_t)p_addr & ~ARCH_PAGE_MASK;
size_t l1_off, l2_off;
size_t *mmu_l1, *mmu_l2;
size_t *ref_cnt;
if (!mmu_info)
{
return -1;
}
while (npages--)
{
l1_off = (loop_va >> ARCH_SECTION_SHIFT);
l2_off = ((loop_va & ARCH_SECTION_MASK) >> ARCH_PAGE_SHIFT);
mmu_l1 = (size_t*)mmu_info->vtable + l1_off;
if (*mmu_l1 & ARCH_MMU_USED_MASK)
{
mmu_l2 = (size_t *)((*mmu_l1 & ~ARCH_PAGE_TBL_MASK) - mmu_info->pv_off);
}
else
{
#ifdef RT_USING_USERSPACE
mmu_l2 = (size_t*)rt_pages_alloc(0);
#else
mmu_l2 = (size_t*)rt_malloc_align(ARCH_PAGE_TBL_SIZE * 2, ARCH_PAGE_TBL_SIZE);
#endif
if (mmu_l2)
{
rt_memset(mmu_l2, 0, ARCH_PAGE_TBL_SIZE * 2);
/* cache maintain */
rt_hw_cpu_dcache_clean(mmu_l2, ARCH_PAGE_TBL_SIZE);
*mmu_l1 = (((size_t)mmu_l2 + mmu_info->pv_off) | 0x1);
/* cache maintain */
rt_hw_cpu_dcache_clean(mmu_l1, 4);
}
else
{
/* error, unmap and quit */
__rt_hw_mmu_unmap(mmu_info, v_addr, npages);
return -1;
}
}
ref_cnt = mmu_l2 + (ARCH_SECTION_SIZE/ARCH_PAGE_SIZE);
(*ref_cnt)++;
*(mmu_l2 + l2_off) = (loop_pa | attr);
/* cache maintain */
rt_hw_cpu_dcache_clean(mmu_l2 + l2_off, 4);
loop_va += ARCH_PAGE_SIZE;
loop_pa += ARCH_PAGE_SIZE;
}
return 0;
}
static void rt_hw_cpu_tlb_invalidate(void)
{
mmu_clear_tlb();
mmu_clear_itlb();
}
#ifdef RT_USING_USERSPACE
void *_rt_hw_mmu_map(rt_mmu_info *mmu_info, void *v_addr, void* p_addr, size_t size, size_t attr)
{
size_t pa_s, pa_e;
size_t vaddr;
int pages;
int ret;
if (!size)
{
return 0;
}
pa_s = (size_t)p_addr;
pa_e = (size_t)p_addr + size - 1;
pa_s >>= ARCH_PAGE_SHIFT;
pa_e >>= ARCH_PAGE_SHIFT;
pages = pa_e - pa_s + 1;
if (v_addr)
{
vaddr = (size_t)v_addr;
pa_s = (size_t)p_addr;
if ((vaddr & ARCH_PAGE_MASK) != (pa_s & ARCH_PAGE_MASK))
{
return 0;
}
vaddr &= ~ARCH_PAGE_MASK;
if (check_vaddr(mmu_info, (void*)vaddr, pages) != 0)
{
return 0;
}
}
else
{
vaddr = find_vaddr(mmu_info, pages);
}
if (vaddr) {
ret = __rt_hw_mmu_map(mmu_info, (void*)vaddr, p_addr, pages, attr);
if (ret == 0)
{
rt_hw_cpu_tlb_invalidate();
return (void*)(vaddr + ((size_t)p_addr & ARCH_PAGE_MASK));
}
}
return 0;
}
#else
void *_rt_hw_mmu_map(rt_mmu_info *mmu_info, void* p_addr, size_t size, size_t attr)
{
size_t pa_s, pa_e;
size_t vaddr;
int pages;
int ret;
pa_s = (size_t)p_addr;
pa_e = (size_t)p_addr + size - 1;
pa_s >>= ARCH_PAGE_SHIFT;
pa_e >>= ARCH_PAGE_SHIFT;
pages = pa_e - pa_s + 1;
vaddr = find_vaddr(mmu_info, pages);
if (vaddr) {
ret = __rt_hw_mmu_map(mmu_info, (void*)vaddr, p_addr, pages, attr);
if (ret == 0)
{
rt_hw_cpu_tlb_invalidate();
return (void*)(vaddr + ((size_t)p_addr & ARCH_PAGE_MASK));
}
}
return 0;
}
#endif
#ifdef RT_USING_USERSPACE
static int __rt_hw_mmu_map_auto(rt_mmu_info *mmu_info, void* v_addr, size_t npages, size_t attr)
{
size_t loop_va = (size_t)v_addr & ~ARCH_PAGE_MASK;
size_t loop_pa;
size_t l1_off, l2_off;
size_t *mmu_l1, *mmu_l2;
size_t *ref_cnt;
if (!mmu_info)
{
return -1;
}
while (npages--)
{
loop_pa = (size_t)rt_pages_alloc(0) + mmu_info->pv_off;
if (!loop_pa)
goto err;
//rt_kprintf("vaddr = %08x is mapped to paddr = %08x\n",v_addr,loop_pa);
l1_off = (loop_va >> ARCH_SECTION_SHIFT);
l2_off = ((loop_va & ARCH_SECTION_MASK) >> ARCH_PAGE_SHIFT);
mmu_l1 = (size_t*)mmu_info->vtable + l1_off;
if (*mmu_l1 & ARCH_MMU_USED_MASK)
{
mmu_l2 = (size_t *)((*mmu_l1 & ~ARCH_PAGE_TBL_MASK) - mmu_info->pv_off);
}
else
{
//mmu_l2 = (size_t*)rt_malloc_align(ARCH_PAGE_TBL_SIZE * 2, ARCH_PAGE_TBL_SIZE);
mmu_l2 = (size_t*)rt_pages_alloc(0);
if (mmu_l2)
{
rt_memset(mmu_l2, 0, ARCH_PAGE_TBL_SIZE * 2);
/* cache maintain */
rt_hw_cpu_dcache_clean(mmu_l2, ARCH_PAGE_TBL_SIZE);
*mmu_l1 = (((size_t)mmu_l2 + mmu_info->pv_off) | 0x1);
/* cache maintain */
rt_hw_cpu_dcache_clean(mmu_l1, 4);
}
else
goto err;
}
ref_cnt = mmu_l2 + (ARCH_SECTION_SIZE/ARCH_PAGE_SIZE);
(*ref_cnt)++;
//loop_pa += mmu_info->pv_off;
*(mmu_l2 + l2_off) = (loop_pa | attr);
/* cache maintain */
rt_hw_cpu_dcache_clean(mmu_l2 + l2_off, 4);
loop_va += ARCH_PAGE_SIZE;
}
return 0;
err:
{
/* error, unmap and quit */
int i;
void *va, *pa;
va = (void*)((size_t)v_addr & ~ARCH_PAGE_MASK);
for (i = 0; i < npages; i++)
{
pa = rt_hw_mmu_v2p(mmu_info, va);
pa -= mmu_info->pv_off;
rt_pages_free(pa, 0);
va += ARCH_PAGE_SIZE;
}
__rt_hw_mmu_unmap(mmu_info, v_addr, npages);
return -1;
}
}
void *_rt_hw_mmu_map_auto(rt_mmu_info *mmu_info, void *v_addr, size_t size, size_t attr)
{
size_t vaddr;
size_t offset;
int pages;
int ret;
if (!size)
{
return 0;
}
offset = (size_t)v_addr & ARCH_PAGE_MASK;
size += (offset + ARCH_PAGE_SIZE - 1);
pages = (size >> ARCH_PAGE_SHIFT);
if (v_addr)
{
vaddr = (size_t)v_addr;
vaddr &= ~ARCH_PAGE_MASK;
if (check_vaddr(mmu_info, (void*)vaddr, pages) != 0)
{
return 0;
}
}
else
{
vaddr = find_vaddr(mmu_info, pages);
}
if (vaddr) {
ret = __rt_hw_mmu_map_auto(mmu_info, (void*)vaddr, pages, attr);
if (ret == 0)
{
rt_hw_cpu_tlb_invalidate();
return (void*)vaddr + offset;
}
}
return 0;
}
#endif
void _rt_hw_mmu_unmap(rt_mmu_info *mmu_info, void* v_addr, size_t size)
{
size_t va_s, va_e;
int pages;
va_s = (size_t)v_addr;
va_e = (size_t)v_addr + size - 1;
va_s >>= ARCH_PAGE_SHIFT;
va_e >>= ARCH_PAGE_SHIFT;
pages = va_e - va_s + 1;
__rt_hw_mmu_unmap(mmu_info, v_addr, pages);
rt_hw_cpu_tlb_invalidate();
}
//va --> pa
void *rt_hw_kernel_virt_to_phys(void *v_addr, size_t size)
{
void *p_addr = 0;
return p_addr;
}
//pa --> va
void *rt_hw_kernel_phys_to_virt(void *p_addr, size_t size)
{
void *v_addr = 0;
#ifdef RT_USING_USERSPACE
extern rt_mmu_info mmu_info;
v_addr = rt_hw_mmu_map(&mmu_info, 0, p_addr, size, MMU_MAP_K_RW);
#else
v_addr = p_addr;
#endif
return v_addr;
}
#ifdef RT_USING_USERSPACE
void *rt_hw_mmu_map(rt_mmu_info *mmu_info, void *v_addr, void* p_addr, size_t size, size_t attr)
{
void *ret;
rt_base_t level;
level = rt_hw_interrupt_disable();
ret = _rt_hw_mmu_map(mmu_info, v_addr, p_addr, size, attr);
rt_hw_interrupt_enable(level);
return ret;
}
void *rt_hw_mmu_map_auto(rt_mmu_info *mmu_info, void *v_addr, size_t size, size_t attr)
{
void *ret;
rt_base_t level;
level = rt_hw_interrupt_disable();
ret = _rt_hw_mmu_map_auto(mmu_info, v_addr, size, attr);
rt_hw_interrupt_enable(level);
return ret;
}
#endif
void rt_hw_mmu_unmap(rt_mmu_info *mmu_info, void* v_addr, size_t size)
{
rt_base_t level;
level = rt_hw_interrupt_disable();
_rt_hw_mmu_unmap(mmu_info, v_addr, size);
rt_hw_interrupt_enable(level);
}
void *_rt_hw_mmu_v2p(rt_mmu_info *mmu_info, void* v_addr)
{
size_t l1_off, l2_off;
size_t *mmu_l1, *mmu_l2;
size_t tmp;
size_t pa;
l1_off = (size_t)v_addr >> ARCH_SECTION_SHIFT;
if (!mmu_info)
{
return (void*)0;
}
mmu_l1 = (size_t*)mmu_info->vtable + l1_off;
tmp = *mmu_l1;
switch (tmp & ARCH_MMU_USED_MASK)
{
case 0: /* not used */
break;
case 1: /* page table */
mmu_l2 = (size_t *)((tmp & ~ARCH_PAGE_TBL_MASK) - mmu_info->pv_off);
l2_off = (((size_t)v_addr & ARCH_SECTION_MASK) >> ARCH_PAGE_SHIFT);
pa = *(mmu_l2 + l2_off);
if (pa & ARCH_MMU_USED_MASK)
{
if ((pa & ARCH_MMU_USED_MASK) == 1)
{
/* lage page, not support */
break;
}
pa &= ~(ARCH_PAGE_MASK);
pa += ((size_t)v_addr & ARCH_PAGE_MASK);
return (void*)pa;
}
break;
case 2:
case 3:
/* section */
if (tmp & ARCH_TYPE_SUPERSECTION)
{
/* super section, not support */
break;
}
pa = (tmp & ~ARCH_SECTION_MASK);
pa += ((size_t)v_addr & ARCH_SECTION_MASK);
return (void*)pa;
}
return (void*)0;
}
void *rt_hw_mmu_v2p(rt_mmu_info *mmu_info, void* v_addr)
{
void *ret;
rt_base_t level;
level = rt_hw_interrupt_disable();
ret = _rt_hw_mmu_v2p(mmu_info, v_addr);
rt_hw_interrupt_enable(level);
return ret;
}
#ifdef RT_USING_USERSPACE
void init_mm_setup(unsigned int *mtbl, unsigned int size, unsigned int pv_off) {
unsigned int va;
for (va = 0; va < 0x1000; va++) {
unsigned int vaddr = (va << 20);
if (vaddr >= KERNEL_VADDR_START && vaddr - KERNEL_VADDR_START < size) {
mtbl[va] = ((va << 20) + pv_off) | NORMAL_MEM;
} else if (vaddr >= (KERNEL_VADDR_START + pv_off) && vaddr - (KERNEL_VADDR_START + pv_off) < size) {
mtbl[va] = (va << 20) | NORMAL_MEM;
} else {
mtbl[va] = 0;
}
}
}
#endif

113
libcpu/mips/gs264/mmu.h Normal file
View File

@ -0,0 +1,113 @@
/*
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-03-25 quanzhao the first version
* 2020-07-26 lizhirui porting to ls2k
*/
#ifndef __MMU_H_
#define __MMU_H_
#include <rtthread.h>
#define DESC_SEC (0x2)
#define MEMWBWA ((1<<12)|(3<<2)) /* write back, write allocate */
#define MEMWB (3<<2) /* write back, no write allocate */
#define MEMWT (2<<2) /* write through, no write allocate */
#define SHAREDEVICE (1<<2) /* shared device */
#define STRONGORDER (0<<2) /* strong ordered */
#define XN (1<<4) /* execute Never */
#ifdef RT_USING_USERSPACE
#define AP_RW (1<<10) /* supervisor=RW, user=No */
#define AP_RO ((1<<10) |(1 << 15)) /* supervisor=RW, user=No */
#else
#define AP_RW (3<<10) /* supervisor=RW, user=RW */
#define AP_RO ((2<<10) /* supervisor=RW, user=RO */
#endif
#define SHARED (1<<16) /* shareable */
#define DOMAIN_FAULT (0x0)
#define DOMAIN_CHK (0x1)
#define DOMAIN_NOTCHK (0x3)
#define DOMAIN0 (0x0<<5)
#define DOMAIN1 (0x1<<5)
#define DOMAIN0_ATTR (DOMAIN_CHK<<0)
#define DOMAIN1_ATTR (DOMAIN_FAULT<<2)
/* device mapping type */
#define DEVICE_MEM (SHARED|AP_RW|DOMAIN0|SHAREDEVICE|DESC_SEC|XN)
/* normal memory mapping type */
#define NORMAL_MEM (SHARED|AP_RW|DOMAIN0|MEMWBWA|DESC_SEC)
#define STRONG_ORDER_MEM (SHARED|AP_RO|XN|DESC_SEC)
struct mem_desc
{
rt_uint32_t vaddr_start;
rt_uint32_t vaddr_end;
rt_uint32_t paddr_start;
rt_uint32_t attr;
};
#define MMU_MAP_MTBL_XN (1<<0)
#define MMU_MAP_MTBL_A (1<<1)
#define MMU_MAP_MTBL_B (1<<2)
#define MMU_MAP_MTBL_C (1<<3)
#define MMU_MAP_MTBL_AP01(x) (x<<4)
#define MMU_MAP_MTBL_TEX(x) (x<<6)
#define MMU_MAP_MTBL_AP2(x) (x<<9)
#define MMU_MAP_MTBL_SHARE (1<<10)
#define MMU_MAP_K_RO (MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(1)|MMU_MAP_MTBL_AP01(1)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_C|MMU_MAP_MTBL_SHARE)
#define MMU_MAP_K_RWCB (MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(1)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_B|MMU_MAP_MTBL_C|MMU_MAP_MTBL_SHARE)
#define MMU_MAP_K_RW (MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(1)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_SHARE)
#define MMU_MAP_K_DEVICE (MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(1)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_B|MMU_MAP_MTBL_SHARE)
#define MMU_MAP_U_RO (MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(1)|MMU_MAP_MTBL_AP01(2)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_C|MMU_MAP_MTBL_SHARE)
#define MMU_MAP_U_RWCB (MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(3)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_B|MMU_MAP_MTBL_C|MMU_MAP_MTBL_SHARE)
#define MMU_MAP_U_RW (MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(3)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_SHARE)
#define MMU_MAP_U_DEVICE (MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(3)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_B|MMU_MAP_MTBL_SHARE)
#define ARCH_SECTION_SHIFT 20
#define ARCH_SECTION_SIZE (1 << ARCH_SECTION_SHIFT)
#define ARCH_SECTION_MASK (ARCH_SECTION_SIZE - 1)
#define ARCH_PAGE_SHIFT 14
#define ARCH_PAGE_SIZE (1 << ARCH_PAGE_SHIFT)
#define ARCH_PAGE_MASK (ARCH_PAGE_SIZE - 1)
#define ARCH_PAGE_TBL_SHIFT 10
#define ARCH_PAGE_TBL_SIZE (1 << ARCH_PAGE_TBL_SHIFT)
#define ARCH_PAGE_TBL_MASK (ARCH_PAGE_TBL_SIZE - 1)
#define ARCH_MMU_USED_MASK 3
#define ARCH_TYPE_SUPERSECTION (1 << 18)
typedef struct
{
size_t *vtable;
size_t vstart;
size_t vend;
size_t pv_off;
} rt_mmu_info;
void *mmu_table_get();
void switch_mmu(void *mmu_table);
int rt_hw_mmu_map_init(rt_mmu_info *mmu_info, void* v_address, size_t size, size_t *vtable, size_t pv_off);
#ifdef RT_USING_USERSPACE
void *rt_hw_mmu_map(rt_mmu_info *mmu_info, void *v_addr, void* p_addr, size_t size, size_t attr);
void *rt_hw_mmu_map_auto(rt_mmu_info *mmu_info, void *v_addr, size_t size, size_t attr);
#else
void *rt_hw_mmu_map(rt_mmu_info *mmu_info, void* p_addr, size_t size, size_t attr);
#endif
void rt_hw_mmu_unmap(rt_mmu_info *mmu_info, void* v_addr, size_t size);
void *rt_hw_mmu_v2p(rt_mmu_info *mmu_info, void* v_addr);
void *rt_hw_kernel_phys_to_virt(void *p_addr, size_t size);
void *rt_hw_kernel_virt_to_phys(void *v_addr, size_t size);
#endif