From 51e21b48b6fb8c9599de6c567737772a1c770294 Mon Sep 17 00:00:00 2001 From: Jesus Sanchez-Palencia Date: Tue, 3 Feb 2015 16:58:04 -0200 Subject: [PATCH 01/92] gitignore: add cscope related files --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 74f62f59b..0bccbc7b5 100644 --- a/.gitignore +++ b/.gitignore @@ -103,3 +103,6 @@ regression-tests/[0-9][0-9]-*/org/ # rl78 build artifacts *.eval-adf7xxxmb4z *.eval-adf7xxxmb4z.srec + +# cscope files +cscope.* From 5a0e2a76549cba5a3da9f55eeb8406fc9d2082aa Mon Sep 17 00:00:00 2001 From: Jesus Sanchez-Palencia Date: Mon, 23 Feb 2015 22:14:13 -0300 Subject: [PATCH 02/92] x86: Fix missing include warning due to memset usage --- cpu/x86/mtarch.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cpu/x86/mtarch.c b/cpu/x86/mtarch.c index 6dd72c61f..ccc9567b8 100644 --- a/cpu/x86/mtarch.c +++ b/cpu/x86/mtarch.c @@ -1,5 +1,6 @@ #include +#include #include "sys/mt.h" #ifndef __WORDSIZE From 3a26d9dbc713222a50615792e6fddd6cc82f8507 Mon Sep 17 00:00:00 2001 From: Jesus Sanchez-Palencia Date: Fri, 20 Mar 2015 09:18:13 -0300 Subject: [PATCH 03/92] x86: Only add elfloader-x86.c to the platforms using it Currently there are only one platform using CPU x86: Cooja. The elfloader-x86.c is rather a POSIX implementation, so the Galileo port won't use it for now. This patch fixes this by moving this source file to be included by the platforms using it instead of the cpu's Makefile. --- cpu/x86/Makefile.x86 | 2 +- platform/cooja/Makefile.cooja | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cpu/x86/Makefile.x86 b/cpu/x86/Makefile.x86 index 0aececd4d..46ab27817 100644 --- a/cpu/x86/Makefile.x86 +++ b/cpu/x86/Makefile.x86 @@ -1,6 +1,6 @@ CONTIKI_CPU_DIRS = . -CONTIKI_SOURCEFILES += mtarch.c elfloader-x86.c +CONTIKI_SOURCEFILES += mtarch.c ### Compiler definitions CC = gcc diff --git a/platform/cooja/Makefile.cooja b/platform/cooja/Makefile.cooja index c28dac608..d10979cd9 100644 --- a/platform/cooja/Makefile.cooja +++ b/platform/cooja/Makefile.cooja @@ -47,7 +47,7 @@ CONTIKI_TARGET_DIRS = . dev lib sys cfs net # (COOJA_SOURCEDIRS contains additional sources dirs set from simulator) vpath %.c $(COOJA_SOURCEDIRS) -COOJA_BASE = simEnvChange.c cooja_mt.c cooja_mtarch.c rtimer-arch.c slip.c watchdog.c rimestats.c +COOJA_BASE = simEnvChange.c cooja_mt.c cooja_mtarch.c rtimer-arch.c slip.c watchdog.c rimestats.c elfloader-x86.c COOJA_INTFS = beep.c button-sensor.c ip.c leds-arch.c moteid.c \ pir-sensor.c rs232.c vib-sensor.c \ From c9897fe9b0f515b570237d790c0c2562f8eae5e2 Mon Sep 17 00:00:00 2001 From: Jesus Sanchez-Palencia Date: Mon, 23 Feb 2015 22:28:29 -0300 Subject: [PATCH 04/92] galileo: Add BSP files This patch creates the platform/galileo/bsp directory. This directory contain all files related to Galileo's Board Support Package (BSP). For now, the BSP consists of libc and bootloader. Within the BSP directory, we have the scripts build_newlib.sh and build_ grub.sh. These scripts provide an easy and quick way to build the newlib and the grub for the Galileo platform. --- .gitignore | 6 + platform/galileo/bsp/grub/build_grub.sh | 60 ++++++++++ platform/galileo/bsp/libc/build_newlib.sh | 105 ++++++++++++++++++ .../bsp/libc/patches/large64_files.patch | 11 ++ .../libc/patches/newlib_add_i586_elf.patch | 13 +++ 5 files changed, 195 insertions(+) create mode 100755 platform/galileo/bsp/grub/build_grub.sh create mode 100755 platform/galileo/bsp/libc/build_newlib.sh create mode 100644 platform/galileo/bsp/libc/patches/large64_files.patch create mode 100644 platform/galileo/bsp/libc/patches/newlib_add_i586_elf.patch diff --git a/.gitignore b/.gitignore index 0bccbc7b5..299193bae 100644 --- a/.gitignore +++ b/.gitignore @@ -106,3 +106,9 @@ regression-tests/[0-9][0-9]-*/org/ # cscope files cscope.* + +# galileo bsp files +platform/galileo/bsp/libc/i586-elf/ +platform/galileo/bsp/libc/newlib-2.2.0-1* +platform/galileo/bsp/grub/src/ +platform/galileo/bsp/grub/bin/ diff --git a/platform/galileo/bsp/grub/build_grub.sh b/platform/galileo/bsp/grub/build_grub.sh new file mode 100755 index 000000000..6d33799e3 --- /dev/null +++ b/platform/galileo/bsp/grub/build_grub.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +set -e + +JOBS=5 +HEAD="bac5d1a64ab4191058a8fd4c05f6b3b339e249e7" +SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) + +prepare() { + if [[ ! -d ./src ]]; then + git clone git://git.savannah.gnu.org/grub.git src + fi + + pushd src + git checkout $HEAD + git clean -fdx + popd +} + +build() { + pushd src + + ./autogen.sh + ./configure --with-platform=efi --target=i386 + + make -j${JOBS} + + ./grub-mkimage -p /EFI/BOOT -d ./grub-core/ -O i386-efi -o grub.efi \ + boot efifwsetup efi_gop efinet efi_uga lsefimmap lsefi lsefisystab \ + exfat fat multiboot2 multiboot terminal part_msdos part_gpt normal \ + all_video aout configfile echo file fixvideo fshelp gfxterm gfxmenu \ + gfxterm_background gfxterm_menu legacycfg video_bochs video_cirrus \ + video_colors video_fb videoinfo video + + popd +} + +setup() { + mkdir -p bin + cp src/grub.efi bin/ +} + +cleanup() { + rm -rf ./src + rm -rf ./bin +} + +# This script will always run on its own basepath, no matter where you call it from. +pushd ${SCRIPT_DIR} + +case $1 in + -c | --cleanup) + cleanup + ;; + *) + prepare && build && setup + ;; +esac + +popd diff --git a/platform/galileo/bsp/libc/build_newlib.sh b/platform/galileo/bsp/libc/build_newlib.sh new file mode 100755 index 000000000..a187a7838 --- /dev/null +++ b/platform/galileo/bsp/libc/build_newlib.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +JOBS=5 +TARGET=i586-elf +VERSION=2.2.0-1 +MD5=94114fdc1d8391cdbc2653d89249cccf +TARBALL=newlib-${VERSION}.tar.gz + +SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) + +# This script will always run on its own basepath, no matter where you call it from. +pushd ${SCRIPT_DIR} + +prepare() { + # If the source tarball doesn't exist of its md5 checksum doesn't match, download it. + if [ ! -e ./${TARBALL} ] || [ "$(md5sum ./${TARBALL} | cut -d' ' -f1)" != $MD5 ]; then + wget -c ftp://sources.redhat.com/pub/newlib/${TARBALL} + fi + + # Clean up the previous source dir, if any. + if [[ -d ./newlib-${VERSION} ]]; then + rm -rf ./newlib-${VERSION} + fi + + # Clean up the previous install dir, if any. + if [[ -d ./${VERSION} ]]; then + rm -rf ./${VERSION} + fi + + tar xf ${TARBALL} + cd newlib-${VERSION} + + for i in `ls ../patches/`; do patch -p0 < ../patches/${i}; done +} + + +build() { + export AR_FOR_TARGET=ar + export AS_FOR_TARGET=as + export CC_FOR_TARGET=cc + export GCC_FOR_TARGET=gcc + export CXX_FOR_TARGET=c++ + export RAW_CXX_FOR_TARGET=c++ + export GCJ_FOR_TARGET=gcj + export GFORTRAN_FOR_TARGET=gfortran + export GOC_FOR_TARGET=gccgo + export DLLTOOL_FOR_TARGET=dlltool + export LD_FOR_TARGET=ld + export LIPO_FOR_TARGET=lipo + export NM_FOR_TARGET=nm + export OBJDUMP_FOR_TARGET=objdump + export RANLIB_FOR_TARGET=ranlib + export READELF_FOR_TARGET=readelf + export STRIP_FOR_TARGET=strip + export WINDRES_FOR_TARGET=windres + export WINDMC_FOR_TARGET=windmc + export COMPILER_AS_FOR_TARGET=as + export COMPILER_LD_FOR_TARGET=ld + export COMPILER_NM_FOR_TARGET=nm + export CFLAGS_FOR_TARGET="-Os -m32 -march=i586 -mtune=i586 -DPREFER_SIZE_OVER_SPEED" + export CXXFLAGS_FOR_TARGET="-Os -m32 -march=i586 -mtune=i586 -DPREFER_SIZE_OVER_SPEED" + + mkdir -p install + ./configure --target=${TARGET} \ + --prefix=`pwd`/install \ + --enable-newlib-nano-formatted-io \ + --enable-newlib-nano-malloc \ + --enable-multithread \ + --disable-newlib-fvwrite-in-streamio \ + --disable-newlib-fseek-optimization \ + --disable-newlib-wide-orient \ + --disable-newlib-unbuf-stream-opt \ + --disable-libstdcxx \ + --disable-multilib \ + --disable-newlib-mb \ + --disable-newlib-supplied-syscalls + + make -j${JOBS} all && make install + cd .. +} + +setup() { + cp -r ./newlib-${VERSION}/install/${TARGET} . +} + +cleanup() { + rm -rf ./newlib-${VERSION}* +} + + +# By default we always call prepare, build and setup. +prepare && build && setup + +# But we only cleanup if -c is used. +case $1 in + -c | --cleanup) + cleanup + shift + ;; + *) + # unknown option + ;; +esac + +popd diff --git a/platform/galileo/bsp/libc/patches/large64_files.patch b/platform/galileo/bsp/libc/patches/large64_files.patch new file mode 100644 index 000000000..07d5aeeea --- /dev/null +++ b/platform/galileo/bsp/libc/patches/large64_files.patch @@ -0,0 +1,11 @@ +--- newlib/libc/include/sys/config.h 2015-01-14 07:25:15.000000000 -0200 ++++ newlib/libc/include/sys/config.h 2015-03-13 14:21:33.247980336 -0300 +@@ -94,9 +94,6 @@ + #define HAVE_GETDATE + #define _HAVE_SYSTYPES + #define _READ_WRITE_RETURN_TYPE _ssize_t +-#define __LARGE64_FILES 1 +-/* we use some glibc header files so turn on glibc large file feature */ +-#define _LARGEFILE64_SOURCE 1 + #endif + #endif diff --git a/platform/galileo/bsp/libc/patches/newlib_add_i586_elf.patch b/platform/galileo/bsp/libc/patches/newlib_add_i586_elf.patch new file mode 100644 index 000000000..20c444ba3 --- /dev/null +++ b/platform/galileo/bsp/libc/patches/newlib_add_i586_elf.patch @@ -0,0 +1,13 @@ +--- newlib/configure.host 2015-03-12 17:59:39.380318464 -0300 ++++ newlib/configure.host 2015-03-12 17:55:05.933645678 -0300 +@@ -810,6 +810,10 @@ + z8k-*-*) + syscall_dir=syscalls + ;; ++ i586-*-elf) ++ newlib_cflags="${newlib_cflags} -DREENTRANT_SYSCALLS_PROVIDED" ++ syscall_dir=syscalls ++ ;; + *) + newlib_cflags="${newlib_cflags} -DMISSING_SYSCALL_NAMES" + syscall_dir= From f14f9aba4109c6693ce1db0b87c73e5d2cb03f08 Mon Sep 17 00:00:00 2001 From: Jesus Sanchez-Palencia Date: Wed, 1 Jul 2015 16:43:42 -0300 Subject: [PATCH 05/92] galileo: Initial support for Intel Galileo Platform This patch adds the initial support for Intel Galileo Platform. It contains the minimum set of code required to boot a dummy Contiki image. For Galileo initial support, we implemented a linker script, a minimal bootstrap code, a set of stubbed functions required by newlib, and a very simple main() function. Moreover, we also define some header files and macros required by Contiki. To build applications for this platform you should first build newlib (in case it wasn't already built). To build newlib you can run the following command: $ platform/galileo/bsp/libc/build_newlib.sh Once newlib is built, you can build applications. To build applications for Galileo platform you should set TARGET variable to 'galileo'. For instance, building the hello-world application should look like this: $ cd examples/hello-world/ && make TARGET=galileo This will generate the 'hello-world.galileo' file which is a multiboot- compliant [1] ELF image. This image can be booted by any multiboot- complaint bootloader such as Grub. Finally, this patch should be used as a guideline to add the initial support for others platforms based on x86 SoCs. [1] https://www.gnu.org/software/grub/manual/multiboot/multiboot.html --- .gitignore | 3 + platform/galileo/Makefile.galileo | 20 ++++++ platform/galileo/contiki-conf.h | 45 +++++++++++++ platform/galileo/contiki-main.c | 35 ++++++++++ platform/galileo/galileo.ld | 69 +++++++++++++++++++ platform/galileo/loader.S | 45 +++++++++++++ platform/galileo/newlib-syscalls.c | 102 +++++++++++++++++++++++++++++ platform/galileo/rtimer-arch.h | 34 ++++++++++ 8 files changed, 353 insertions(+) create mode 100644 platform/galileo/Makefile.galileo create mode 100644 platform/galileo/contiki-conf.h create mode 100644 platform/galileo/contiki-main.c create mode 100644 platform/galileo/galileo.ld create mode 100644 platform/galileo/loader.S create mode 100644 platform/galileo/newlib-syscalls.c create mode 100644 platform/galileo/rtimer-arch.h diff --git a/.gitignore b/.gitignore index 299193bae..02b314dfc 100644 --- a/.gitignore +++ b/.gitignore @@ -112,3 +112,6 @@ platform/galileo/bsp/libc/i586-elf/ platform/galileo/bsp/libc/newlib-2.2.0-1* platform/galileo/bsp/grub/src/ platform/galileo/bsp/grub/bin/ + +# galileo build artefacts +*.galileo diff --git a/platform/galileo/Makefile.galileo b/platform/galileo/Makefile.galileo new file mode 100644 index 000000000..ead4e7441 --- /dev/null +++ b/platform/galileo/Makefile.galileo @@ -0,0 +1,20 @@ +LIBC=$(CONTIKI)/platform/galileo/bsp/libc/i586-elf +LIBGCC_PATH = /usr/lib/gcc/$(shell gcc -dumpmachine)/$(shell gcc -dumpversion) + +CONTIKI_TARGET_DIRS = . +CONTIKI_TARGET_MAIN = ${addprefix $(OBJECTDIR)/,contiki-main.o} +CONTIKI_SOURCEFILES += contiki-main.c newlib-syscalls.c loader.S + +LINKERSCRIPT = $(CONTIKI)/platform/galileo/galileo.ld + +CONTIKI_CPU=$(CONTIKI)/cpu/x86 +include $(CONTIKI)/cpu/x86/Makefile.x86 + +CFLAGS += -m32 -march=i586 -nostdinc -isystem $(LIBC)/include -isystem $(LIBGCC_PATH)/include -isystem $(LIBGCC_PATH)/include-fixed +LDFLAGS += -m32 -nostdlib -T $(LINKERSCRIPT) +ASFLAGS += --32 -march=i586 -mtune=i586 + +# Ideally, this should be part of LDFLAGS (-lc -lm etc). However, we found out that archive +# static files (.a) must be linked after our own object files, otherwise the linker gets lost +# and we get undefined references only. +TARGET_LIBFILES = $(OBJECTDIR)/newlib-syscalls.o $(LIBC)/lib/libm.a $(LIBC)/lib/libc.a $(LIBGCC_PATH)/32/libgcc.a diff --git a/platform/galileo/contiki-conf.h b/platform/galileo/contiki-conf.h new file mode 100644 index 000000000..4df707d8a --- /dev/null +++ b/platform/galileo/contiki-conf.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CONTIKI_CONF_H +#define CONTIKI_CONF_H + +#include + +/* We define the following macros and types otherwise Contiki does not + * compile. + */ +#define CCIF +#define CLIF + +typedef unsigned long clock_time_t; +typedef unsigned short uip_stats_t; + +#endif /* CONTIKI_CONF_H */ diff --git a/platform/galileo/contiki-main.c b/platform/galileo/contiki-main.c new file mode 100644 index 000000000..76ad75e57 --- /dev/null +++ b/platform/galileo/contiki-main.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +int +main(void) +{ + return 0; +} diff --git a/platform/galileo/galileo.ld b/platform/galileo/galileo.ld new file mode 100644 index 000000000..e703b9f1d --- /dev/null +++ b/platform/galileo/galileo.ld @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +OUTPUT_FORMAT("elf32-i386") + +ENTRY(start) + +SECTIONS { + /* + OS-Dev Wiki says it is common for kernels to start at 1M. Addresses before that + are used by BIOS/EFI, the bootloader and memory-mapped I/O. + */ + . = 1M; + + .text ALIGN (4K) : + { + *(.multiboot) + *(.text) + } + + .rodata ALIGN (4K) : + { + *(.rodata*) + } + + .data ALIGN (4K) : + { + *(.data) + } + + .bss ALIGN (4K) : + { + *(COMMON) + *(.bss) + } + + /* Put this here so it doesn't sit above the multiboot section. */ + .note.gnu.build-id : + { + *(.note.gnu.build-id) + } +} diff --git a/platform/galileo/loader.S b/platform/galileo/loader.S new file mode 100644 index 000000000..66edacd08 --- /dev/null +++ b/platform/galileo/loader.S @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +.set MAGIC_NUMBER, 0x1BADB002 +.set FLAGS, 0x0 +.set CHECKSUM, -MAGIC_NUMBER + +.section .multiboot +.align 4 +.long MAGIC_NUMBER +.long FLAGS +.long CHECKSUM + +.section .text +.global start +start: + cli + call main diff --git a/platform/galileo/newlib-syscalls.c b/platform/galileo/newlib-syscalls.c new file mode 100644 index 000000000..5a7831857 --- /dev/null +++ b/platform/galileo/newlib-syscalls.c @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +int +_close_r(struct _reent *ptr, int file) +{ + /* Stubbed function */ + ptr->_errno = ENOTSUP; + return -1; +} +/*---------------------------------------------------------------------------*/ +int +_isatty_r(struct _reent *ptr, int file) +{ + /* Stubbed function */ + return 0; +} +/*---------------------------------------------------------------------------*/ +int +_read_r(struct _reent *ptr, int file, char *buf, int len) +{ + /* Stubbed function */ + ptr->_errno = ENOTSUP; + return 0; +} +/*---------------------------------------------------------------------------*/ +int +_write_r(struct _reent *ptr, int file, const char *buf, int len) +{ + /* Stubbed function */ + ptr->_errno = ENOTSUP; + return -1; +} +/*---------------------------------------------------------------------------*/ +int +_lseek_r(struct _reent *ptr, int file, int p, int dir) +{ + /* Stubbed function */ + ptr->_errno = ENOTSUP; + return 0; +} +/*---------------------------------------------------------------------------*/ +int +_fstat_r(struct _reent *ptr, int file, struct stat *st) +{ + /* Stubbed function */ + ptr->_errno = ENOTSUP; + return -1; +} +/*---------------------------------------------------------------------------*/ +caddr_t +_sbrk_r(struct _reent *ptr, int incr) +{ + /* Stubbed function */ + ptr->_errno = ENOTSUP; + return NULL; +} +/*---------------------------------------------------------------------------*/ +void +_kill_r(struct _reent *ptr) +{ + /* Stubbed function */ + ptr->_errno = ENOTSUP; +} +/*---------------------------------------------------------------------------*/ +int +_getpid_r(struct _reent *ptr) +{ + /* Stubbed function */ + ptr->_errno = ENOTSUP; + return 1; +} diff --git a/platform/galileo/rtimer-arch.h b/platform/galileo/rtimer-arch.h new file mode 100644 index 000000000..086602aa2 --- /dev/null +++ b/platform/galileo/rtimer-arch.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RTIMER_ARCH_H +#define RTIMER_ARCH_H + +#endif /* RTIMER_ARCH_H */ From 1fb780011036db1fd48c1f97bc524ca3e0f354f7 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 1 Jul 2015 19:12:38 -0300 Subject: [PATCH 06/92] galileo: Add 'debug' rule This patch the 'debug' rule to simplify the debugging process. This new rule runs OpenOCD and gdb with the right parameters. OpenOCD runs in background and its output will be redirected to a log file in the application's path called LOG_OPENOCD. Once gdb client is detached, OpenOCD is terminated. The 'debug' rule is defined in Makefile.customrules-galileo file (create by this patch) which is included by the Contiki's buildsystem. So to debug a Contiki application for Galileo board, run the following command: $ make TARGET=galileo debug If you use a gdb front-end, you can define the "GDB" environment variable and your gdb front-end will be used instead of default gdb. For instance, if you want to use cgdb front-end, just run the command: $ make BOARD=galileo debug GDB=cgdb --- .gitignore | 3 ++- platform/galileo/Makefile.customrules-galileo | 8 ++++++++ platform/galileo/bsp/openocd-scripts/debug.cfg | 11 +++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 platform/galileo/Makefile.customrules-galileo create mode 100644 platform/galileo/bsp/openocd-scripts/debug.cfg diff --git a/.gitignore b/.gitignore index 02b314dfc..02e32989b 100644 --- a/.gitignore +++ b/.gitignore @@ -113,5 +113,6 @@ platform/galileo/bsp/libc/newlib-2.2.0-1* platform/galileo/bsp/grub/src/ platform/galileo/bsp/grub/bin/ -# galileo build artefacts +# galileo build and debug artefacts *.galileo +LOG_OPENOCD diff --git a/platform/galileo/Makefile.customrules-galileo b/platform/galileo/Makefile.customrules-galileo new file mode 100644 index 000000000..0ab0e662c --- /dev/null +++ b/platform/galileo/Makefile.customrules-galileo @@ -0,0 +1,8 @@ +GDB ?= gdb +OPENOCD_SCRIPTS = $(CONTIKI)/platform/galileo/bsp/openocd-scripts + +.PHONY: debug + +debug: $(CONTIKI_PROJECT).$(TARGET) + @openocd -s $(OPENOCD_SCRIPTS) -f debug.cfg &> $(shell pwd)/LOG_OPENOCD & + @$(GDB) $< -ex "target remote :3333" diff --git a/platform/galileo/bsp/openocd-scripts/debug.cfg b/platform/galileo/bsp/openocd-scripts/debug.cfg new file mode 100644 index 000000000..bbe8a5919 --- /dev/null +++ b/platform/galileo/bsp/openocd-scripts/debug.cfg @@ -0,0 +1,11 @@ +source [find interface/ftdi/flyswatter2.cfg]; +source [find board/quark_x10xx_board.cfg]; + +quark_x10xx.cpu configure -event gdb-attach { + halt +} + +quark_x10xx.cpu configure -event gdb-detach { + resume + shutdown +} From e820a8b03b13a4d18379ea42b167ec608180cfc9 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 26 Jun 2015 19:02:56 -0300 Subject: [PATCH 07/92] galileo: Add README file This patch adds a README file which contains general information about the Intel Galileo board support. The file provides information about supported features as well as instructions on how to build, run and debug applications for this platform. --- platform/galileo/README.md | 147 +++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 platform/galileo/README.md diff --git a/platform/galileo/README.md b/platform/galileo/README.md new file mode 100644 index 000000000..1ccd9b0a6 --- /dev/null +++ b/platform/galileo/README.md @@ -0,0 +1,147 @@ +Intel Galileo Board +=================== + +This README file contains general information about the Intel Galileo board +support. In the following lines you will find information about supported +features as well as instructions on how to build, run and debug applications +for this platform. The instructions were only test in Linux environment. + +Requirements +------------ + +In order to build and debug the following packages must be installed in your +system: + * gcc + * gdb + * openocd + +Moreover, in order to debug via JTAG or serial console, you will some extra +devices as described in [1] and [2]. + +Features +-------- + +This section presents the features currently supported (e.g. device drivers +and Contiki APIs) by the Galileo port. + +For now, no features are supported. + +Building +-------- + +To build applications for this platform you should first build newlib (in +case it wasn't already built). To build newlib you can run the following +command: +``` +$ ./platform/galileo/bsp/libc/build_newlib.sh +``` + +Once newlib is built, you are ready to build applications. To build +applications for Galileo platform you should set TARGET variable to 'galileo'. +For instance, building the hello-world application should look like this: +``` +$ cd examples/hello-world/ && make TARGET=galileo +``` + +This will generate the 'hello-world.galileo' file which is a multiboot- +compliant [3] ELF image. In order to boot the Contiki image, you will need +a multiboot-compliant bootloader. In the bsp directory, we provide a helper +script which builds the Grub bootloader with multiboot support. To build the +bootloader, just run the following command: +``` +$ platform/galileo/bsp/grub/build_grub.sh +``` + +Running +------- + +So to run Contiki applications in Galileo, we have three main steps: +prepare SDcard, connect to console, and boot image. Below follows +detailed instructions. + +### Prepare SDcard + +Mount the sdcard in directory /mnt/sdcard. + +Copy Contiki binary image to sdcard +``` +$ cp examples/hello-world/hello-world.galileo /mnt/sdcard +``` + +Copy grub binary to sdcard +``` +$ cp platform/galileo/bsp/grub/bin/grub.efi /mnt/sdcard +``` + +### Connect to the console output + +Connect the serial cable to your computer as showed in [2]. + +Choose one terminal emulator such as screen, putty or minicom. Make sure you +use keyboard SCO mode (on putty that option is at Terminal -> Keyboard, on +the left menu). Connect to /dev/ttyUSB0, use 115200 speed. + +### Boot Contiki Image + +Turn on your board. After a few seconds you should see the following text +in the screen: +``` +Press [Enter] to directly boot. +Press [F7] to show boot menu options. +``` + +Press and select the option "UEFI Internal Shell" within the menu. Once +you have a shell, run the following commands to run grub application: +``` +$ fs0: +$ grub.efi +``` + +You'll reach de grub shell. Now run the following commands to boot Contiki +image: +``` +$ multiboot /hello-world.galileo +$ boot +``` + +For now, we lack of UART support so you won't see any output. However, you can +use JTAG (see next section) to verify that the Contiki is running. + +Debugging +--------- + +This section describes how to debug Contiki via JTAG. The following +instructions consider you have the devices: Flyswatter2 and ARM-JTAG-20-10 +adapter (see [1]). + +Attach the Flyswatter2 to your host computer with an USB cable. Connect the +Flyswatter2 and ARM-JTAG-20-10 adapter using the 20-pins head. Connect the +ARM-JTAG-20-10 adapter to Galileo Gen2 JTAG port using the 10-pins head. + +Once everything is connected, run Contiki as described in "Running" section, +but right after loading Contiki image (multiboot command), run the following +command: +``` +$ make TARGET=galileo debug +``` + +The 'debug' rule will run OpenOCD and gdb with the right parameters. OpenOCD +will run in background and its output will be redirected to a log file in the +application's path called LOG_OPENOCD. Once gdb client is detached, OpenOCD +is terminated. + +If you use a gdb front-end, you can define the "GDB" environment +variable and your gdb front-end will be used instead of default gdb. +For instance, if you want to use cgdb front-end, just run the command: +``` +$ make BOARD=galileo debug GDB=cgdb +``` + +References +---------- + +[1] https://communities.intel.com/message/211778 + +[2] http://www.intel.com/support/galileo/sb/CS-035124.htm + +[3] https://www.gnu.org/software/grub/manual/multiboot/multiboot.html From 7e13081776db8341b5f9793f6bd529410c75ec91 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 1 Jul 2015 18:20:20 -0300 Subject: [PATCH 08/92] galileo: Print elf sections sizes after build This patch changes Galileo's buildsystem to print the elf sections sizes after a new image is built. This way we can easily track how these sections increase or decrease after any change. To achieve that, we define a custom linking rule which is pretty much the same as the default linking rule define in Makefile.include, but we run 'size' command after the image is built. --- cpu/x86/Makefile.x86 | 1 + platform/galileo/Makefile.customrules-galileo | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/cpu/x86/Makefile.x86 b/cpu/x86/Makefile.x86 index 46ab27817..899b78bd3 100644 --- a/cpu/x86/Makefile.x86 +++ b/cpu/x86/Makefile.x86 @@ -7,6 +7,7 @@ CC = gcc LD = gcc AS = as OBJCOPY = objcopy +SIZE = size STRIP = strip CFLAGSNO = -Wall -g -I/usr/local/include CFLAGS += $(CFLAGSNO) diff --git a/platform/galileo/Makefile.customrules-galileo b/platform/galileo/Makefile.customrules-galileo index 0ab0e662c..eceebb9c4 100644 --- a/platform/galileo/Makefile.customrules-galileo +++ b/platform/galileo/Makefile.customrules-galileo @@ -6,3 +6,10 @@ OPENOCD_SCRIPTS = $(CONTIKI)/platform/galileo/bsp/openocd-scripts debug: $(CONTIKI_PROJECT).$(TARGET) @openocd -s $(OPENOCD_SCRIPTS) -f debug.cfg &> $(shell pwd)/LOG_OPENOCD & @$(GDB) $< -ex "target remote :3333" + +CUSTOM_RULE_LINK=1 +%.$(TARGET): %.co $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) contiki-$(TARGET).a + $(TRACE_LD) + $(Q)$(LD) $(LDFLAGS) $(TARGET_STARTFILES) ${filter-out %.a,$^} \ + ${filter %.a,$^} $(TARGET_LIBFILES) -o $@ + @$(SIZE) $@ From 766d3aa8209310ad9790b5e8652f1bf35f9e1f4b Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Thu, 12 Mar 2015 09:04:00 +0000 Subject: [PATCH 09/92] gitignore: Add Vim swap files --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 02e32989b..28db7d3b7 100644 --- a/.gitignore +++ b/.gitignore @@ -107,6 +107,10 @@ regression-tests/[0-9][0-9]-*/org/ # cscope files cscope.* +# vim swap files +*.swp +*.swo + # galileo bsp files platform/galileo/bsp/libc/i586-elf/ platform/galileo/bsp/libc/newlib-2.2.0-1* From 7a1898f73e20db5c72dc847a45103593a68f84ad Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 11 Mar 2015 19:44:00 +0000 Subject: [PATCH 10/92] galileo: Halt if main() returns This patch adds extra intrunctions to loader.S so we halt if main() returns. --- platform/galileo/loader.S | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/platform/galileo/loader.S b/platform/galileo/loader.S index 66edacd08..9e0458dda 100644 --- a/platform/galileo/loader.S +++ b/platform/galileo/loader.S @@ -43,3 +43,8 @@ start: cli call main + + /* We're not expected to return from main(). But if we do we halt */ + cli +halt: hlt + jmp halt From 595088be0928a7b4b9e3603497c1b5fdc8ca52af Mon Sep 17 00:00:00 2001 From: Jesus Sanchez-Palencia Date: Mon, 16 Mar 2015 10:39:13 -0300 Subject: [PATCH 11/92] galileo: Add a bootstrap stack for C runtime All we need to provide to C at this point is a region in memory dedicated to its stack. This is done by allocating a region in .bss and pushing its start address to esp. Since the multiboot spec says it is not safe to rely on the initial stack provided by the bootloader, this patch provides our own stack. Galileo boards have 512Kb of SRAM and 256Mb of DDR3 RAM, so providing 8kb as a start seems safe. Moreover, stack sizes are very application-oriented so it may be too early to provide a bigger (or smaller) stack. --- platform/galileo/loader.S | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/platform/galileo/loader.S b/platform/galileo/loader.S index 9e0458dda..146665d4a 100644 --- a/platform/galileo/loader.S +++ b/platform/galileo/loader.S @@ -28,6 +28,10 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ +# Kernel +.set STACK_SIZE, 8192 + +# Multiboot .set MAGIC_NUMBER, 0x1BADB002 .set FLAGS, 0x0 .set CHECKSUM, -MAGIC_NUMBER @@ -38,10 +42,14 @@ .long FLAGS .long CHECKSUM +# Reserve space for the C stack. +.lcomm c_stack, STACK_SIZE + .section .text .global start start: cli + movl $(c_stack + STACK_SIZE), %esp call main /* We're not expected to return from main(). But if we do we halt */ From 6ecc4a7371351d5cc84be0ade5141186d7638a13 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 1 Jul 2015 19:56:48 -0300 Subject: [PATCH 12/92] galileo: Implement main() function This patch implements the main() function for Galileo platform. At this moment, only Processes subsystem is enabled. After this patch we are able to some rudimentary debugging to ensure that process thread from applications are being indeed executed. Once we properly support more Contiki subsystems, such as clock, ctimer, etimer, and rtimer, we will add them to Galileo platform's main() as well. --- platform/galileo/contiki-main.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/platform/galileo/contiki-main.c b/platform/galileo/contiki-main.c index 76ad75e57..28550ac9e 100644 --- a/platform/galileo/contiki-main.c +++ b/platform/galileo/contiki-main.c @@ -28,8 +28,17 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "contiki.h" + int main(void) { + process_init(); + autostart_start(autostart_processes); + + while(1) { + process_run(); + } + return 0; } From 41bca35c1e5bc493b96ee50810eaadba40326fb6 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 1 Apr 2015 11:46:29 -0300 Subject: [PATCH 13/92] x86: Initialize Global Descriptor Table This patch adds code to initialize the Global Descriptor Table. For simplicity, the memory is organized following the flat model. Thus, memory appears to Contiki as a single, continuous address space. Code, data, and stack are all contained in this address space (so called linear address space). The macros to manipulate bits from segment descriptor and the set_descriptor() helper are based on the ones described in [1]. [1] http://wiki.osdev.org/GDT_Tutorial --- cpu/x86/Makefile.x86 | 2 +- cpu/x86/gdt.c | 136 +++++++++++++++++++++++++++++++++++++++++++ cpu/x86/gdt.h | 36 ++++++++++++ 3 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 cpu/x86/gdt.c create mode 100644 cpu/x86/gdt.h diff --git a/cpu/x86/Makefile.x86 b/cpu/x86/Makefile.x86 index 899b78bd3..b861117a7 100644 --- a/cpu/x86/Makefile.x86 +++ b/cpu/x86/Makefile.x86 @@ -1,6 +1,6 @@ CONTIKI_CPU_DIRS = . -CONTIKI_SOURCEFILES += mtarch.c +CONTIKI_SOURCEFILES += mtarch.c gdt.c ### Compiler definitions CC = gcc diff --git a/cpu/x86/gdt.c b/cpu/x86/gdt.c new file mode 100644 index 000000000..1ba38a724 --- /dev/null +++ b/cpu/x86/gdt.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#define NUM_DESC 3 + +/* Each define here is for a specific flag in the descriptor. Refer to Intel + * Combined Manual (Intel 64 and IA-32 Architectures Software Developer's + * Manual), Vol. 3, Section 3.4.5 for a description of each flag. + */ +#define SEG_DESCTYPE(x) ((x) << 0x04) /* Descriptor type (0 for system, 1 for code/data) */ +#define SEG_PRES(x) ((x) << 0x07) /* Present */ +#define SEG_SAVL(x) ((x) << 0x0C) /* Available for system use */ +#define SEG_LONG(x) ((x) << 0x0D) /* Long mode */ +#define SEG_SIZE(x) ((x) << 0x0E) /* Size (0 for 16-bit, 1 for 32) */ +#define SEG_GRAN(x) ((x) << 0x0F) /* Granularity (0 for 1B - 1MB, 1 for 4KB - 4GB) */ +#define SEG_PRIV(x) (((x) & 0x03) << 0x05) /* Set privilege level (0 - 3) */ + +#define SEG_DATA_RDWR 0x02 /* Read/Write */ +#define SEG_CODE_EXRD 0x0A /* Execute/Read */ + +#define GDT_CODE_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \ + SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ + SEG_PRIV(0) | SEG_CODE_EXRD + +#define GDT_DATA_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \ + SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ + SEG_PRIV(0) | SEG_DATA_RDWR + +typedef struct gdtr +{ + uint16_t limit; + uint32_t base; +} __attribute__((packed)) gdtr_t; + +typedef uint64_t segment_desc_t; + +/* From Intel Combined Manual, Vol. 3 , Section 3.5.1: The base addresses of + * the GDT should be aligned on an eight-byte boundary to yield the best + * processor performance. + */ +static segment_desc_t gdt[NUM_DESC] __attribute__ ((aligned (8))); + +static void +set_descriptor(unsigned int index, uint32_t base, uint32_t limit, uint16_t flag) +{ + segment_desc_t descriptor; + + if (index >= NUM_DESC) + return; + + /* Create the high 32 bit segment */ + descriptor = limit & 0x000F0000; /* set limit bits 19:16 */ + descriptor |= (flag << 8) & 0x00F0FF00; /* set type, p, dpl, s, g, d/b, l and avl fields */ + descriptor |= (base >> 16) & 0x000000FF; /* set base bits 23:16 */ + descriptor |= base & 0xFF000000; /* set base bits 31:24 */ + + /* Shift by 32 to allow for low part of segment */ + descriptor <<= 32; + + /* Create the low 32 bit segment */ + descriptor |= base << 16; /* set base bits 15:0 */ + descriptor |= limit & 0x0000FFFF; /* set limit bits 15:0 */ + + /* Save descriptor into gdt */ + gdt[index] = descriptor; +} + + +/* This function initializes the Global Offset Table. For simplicity, the + * memory is organized following the flat model. Thus, memory appears to + * Contiki as a single continuous address space. Code, data, and stack + * are all contained in this address space (so called linear address space). + */ +void +gdt_init(void) +{ + gdtr_t gdtr; + + /* Initialize gdtr structure */ + gdtr.limit = sizeof(segment_desc_t) * NUM_DESC - 1; + gdtr.base = (uint32_t) &gdt; + + /* Initialize descriptors */ + set_descriptor(0, 0, 0, 0); + set_descriptor(1, 0, 0x0FFFFF, GDT_CODE_PL0); + set_descriptor(2, 0, 0x0FFFFF, GDT_DATA_PL0); + + /* Load GDTR register and update segment registers. + * + * In protected mode, segment registers should be loaded according to + * the offset in GDT. So DS, SS, ES, FS and GS registers should be + * loadded with 0x10 while CS with 0x08. CS register cannot be changed + * directly. For that reason, we do a far jump. + */ + __asm__ ("lgdt %0\n\t" + "jmp $0x08, $1f\n\t" + "1:\n\t" + "mov $0x10, %%ax\n\t" + "mov %%ax, %%ds\n\t" + "mov %%ax, %%ss\n\t" + "mov %%ax, %%es\n\t" + "mov %%ax, %%fs\n\t" + "mov %%ax, %%gs\n\t" + : + : "m" (gdtr) + ); +} diff --git a/cpu/x86/gdt.h b/cpu/x86/gdt.h new file mode 100644 index 000000000..3db17f08c --- /dev/null +++ b/cpu/x86/gdt.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GDT_H +#define GDT_H + +void gdt_init(void); + +#endif /* GDT_H */ From b8feaea30d1da2afe5c752eeafa2c3690bac3853 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Mon, 13 Apr 2015 14:07:59 -0300 Subject: [PATCH 14/92] x86: Add helpers.h This patch adds the helpers.h. This file should contain only x86-related helper functions and macros. For now, we define the BIT macro and halt() helpers which will be used in upcoming patches. Additionally, this patch also changes loader.S to call the halt(). --- cpu/x86/Makefile.x86 | 2 +- cpu/x86/helpers.S | 37 +++++++++++++++++++++++++++++++++++++ cpu/x86/helpers.h | 38 ++++++++++++++++++++++++++++++++++++++ platform/galileo/loader.S | 4 +--- 4 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 cpu/x86/helpers.S create mode 100644 cpu/x86/helpers.h diff --git a/cpu/x86/Makefile.x86 b/cpu/x86/Makefile.x86 index b861117a7..dd79ec7d3 100644 --- a/cpu/x86/Makefile.x86 +++ b/cpu/x86/Makefile.x86 @@ -1,6 +1,6 @@ CONTIKI_CPU_DIRS = . -CONTIKI_SOURCEFILES += mtarch.c gdt.c +CONTIKI_SOURCEFILES += mtarch.c gdt.c helpers.S ### Compiler definitions CC = gcc diff --git a/cpu/x86/helpers.S b/cpu/x86/helpers.S new file mode 100644 index 000000000..07e3c7655 --- /dev/null +++ b/cpu/x86/helpers.S @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +.text + +.global halt +halt: + cli +die: hlt + jmp die diff --git a/cpu/x86/helpers.h b/cpu/x86/helpers.h new file mode 100644 index 000000000..29476e690 --- /dev/null +++ b/cpu/x86/helpers.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HELPERS_H +#define HELPERS_H + +#define BIT(n) (1UL << (n)) + +void halt(void) __attribute__((__noreturn__)); + +#endif /* HELPERS_H */ diff --git a/platform/galileo/loader.S b/platform/galileo/loader.S index 146665d4a..8def35843 100644 --- a/platform/galileo/loader.S +++ b/platform/galileo/loader.S @@ -53,6 +53,4 @@ start: call main /* We're not expected to return from main(). But if we do we halt */ - cli -halt: hlt - jmp halt + call halt From 13d92cf67aa55fc5d4f4991e69a6c9ebb2cc8819 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 15 Apr 2015 15:03:51 -0300 Subject: [PATCH 15/92] x86: Initialize Interrupt Descriptor Table This patch adds code to handle Interrupt Descriptor Table (IDT) initialization. The IDT is initialized with null descriptors therefore any interrupt at this point will cause a triple fault. The IDT initialization is part of x86 CPU initialization. Strictly speaking, there is no need to use attribute packed in struct intr_gate_desc however we use it for readability reasons. --- cpu/x86/Makefile.x86 | 2 +- cpu/x86/idt.c | 89 ++++++++++++++++++++++++++++++++++++++++++++ cpu/x86/idt.h | 39 +++++++++++++++++++ 3 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 cpu/x86/idt.c create mode 100644 cpu/x86/idt.h diff --git a/cpu/x86/Makefile.x86 b/cpu/x86/Makefile.x86 index dd79ec7d3..6b3757da5 100644 --- a/cpu/x86/Makefile.x86 +++ b/cpu/x86/Makefile.x86 @@ -1,6 +1,6 @@ CONTIKI_CPU_DIRS = . -CONTIKI_SOURCEFILES += mtarch.c gdt.c helpers.S +CONTIKI_SOURCEFILES += mtarch.c gdt.c helpers.S idt.c ### Compiler definitions CC = gcc diff --git a/cpu/x86/idt.c b/cpu/x86/idt.c new file mode 100644 index 000000000..a75b704e8 --- /dev/null +++ b/cpu/x86/idt.c @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "helpers.h" + +#define NUM_DESC 256 + +typedef struct idtr { + uint16_t limit; + uint32_t base; +} __attribute__((packed)) idtr_t; + +typedef struct intr_gate_desc { + uint16_t offset_low; + uint16_t selector; /* Segment Selector for destination code segment */ + uint16_t fixed:11; + uint16_t d:1; /* Size of gate: 1 = 32 bits; 0 = 16 bits */ + uint16_t pad:1; + uint16_t dpl:2; /* Descriptor Privilege Level */ + uint16_t p:1; /* Segment Present flag */ + uint16_t offset_high; + +} __attribute__((packed)) intr_gate_desc_t; + +/* According to Intel Combined Manual, Vol. 3, Section 6.10, the base addresses + * of the IDT should be aligned on an 8-byte boundary to maximize performance + * of cache line fills. + */ +static intr_gate_desc_t idt[NUM_DESC] __attribute__ ((aligned(8))); + +void +idt_set_intr_gate_desc(int intr_num, uint32_t offset) +{ + intr_gate_desc_t *desc = &idt[intr_num]; + + desc->offset_low = offset & 0xFFFF; + desc->selector = 0x08; /* Offset in GDT for code segment */ + desc->fixed = BIT(9) | BIT(10); + desc->d = 1; + desc->dpl = 0; + desc->p = 1; + desc->offset_high = (offset >> 16) & 0xFFFF; +} +/*---------------------------------------------------------------------------*/ +/* Initialize Interrupt Descriptor Table. The IDT is initialized with + * null descriptors. Therefore, any interrupt at this point will cause + * a triple fault. + */ +void +idt_init(void) +{ + idtr_t idtr; + + /* Initialize idtr structure */ + idtr.limit = (sizeof(intr_gate_desc_t) * NUM_DESC) - 1; + idtr.base = (uint32_t)&idt; + + /* Load IDTR register */ + __asm__("lidt %0\n\t" :: "m" (idtr)); +} diff --git a/cpu/x86/idt.h b/cpu/x86/idt.h new file mode 100644 index 000000000..d29b97153 --- /dev/null +++ b/cpu/x86/idt.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IDT_H +#define IDT_H + +#include + +void idt_init(void); +void idt_set_intr_gate_desc(int intr_num, uint32_t offset); + +#endif /* IDT_H */ From f6644d9208ee953c1781f61dc56443d3a7d8992d Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 1 Jul 2015 18:30:46 -0300 Subject: [PATCH 16/92] x86: CPU Initialization This patch defines the cpu_init() function which should encapsulate all code related to x86 CPU initialization. For now, this function initializes GDT and IDT. --- cpu/x86/Makefile.x86 | 2 +- cpu/x86/cpu.c | 39 +++++++++++++++++++++++++++++++++ cpu/x86/cpu.h | 36 ++++++++++++++++++++++++++++++ platform/galileo/contiki-main.c | 3 +++ 4 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 cpu/x86/cpu.c create mode 100644 cpu/x86/cpu.h diff --git a/cpu/x86/Makefile.x86 b/cpu/x86/Makefile.x86 index 6b3757da5..94f1d0a03 100644 --- a/cpu/x86/Makefile.x86 +++ b/cpu/x86/Makefile.x86 @@ -1,6 +1,6 @@ CONTIKI_CPU_DIRS = . -CONTIKI_SOURCEFILES += mtarch.c gdt.c helpers.S idt.c +CONTIKI_SOURCEFILES += mtarch.c gdt.c helpers.S idt.c cpu.c ### Compiler definitions CC = gcc diff --git a/cpu/x86/cpu.c b/cpu/x86/cpu.c new file mode 100644 index 000000000..9e4707856 --- /dev/null +++ b/cpu/x86/cpu.c @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gdt.h" +#include "idt.h" + +void +cpu_init(void) +{ + gdt_init(); + idt_init(); +} diff --git a/cpu/x86/cpu.h b/cpu/x86/cpu.h new file mode 100644 index 000000000..a56d0db5a --- /dev/null +++ b/cpu/x86/cpu.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CPU_H +#define CPU_H + +void cpu_init(void); + +#endif /* CPU_H */ diff --git a/platform/galileo/contiki-main.c b/platform/galileo/contiki-main.c index 28550ac9e..30dd57b5a 100644 --- a/platform/galileo/contiki-main.c +++ b/platform/galileo/contiki-main.c @@ -29,10 +29,13 @@ */ #include "contiki.h" +#include "cpu.h" int main(void) { + cpu_init(); + process_init(); autostart_start(autostart_processes); From e28f400e0c0e15a2e9e7263152f95b9f3d6e6117 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 15 Apr 2015 15:05:12 -0300 Subject: [PATCH 17/92] x86: Introduce interrupt.h This patch introduces the interrupt.h header file which provides some helper macros to set a interrupt handler and disable/enable maskable hardware interrupts. Since there is no easy way to write an Interrupt Service Routines (ISR) in C (for further information on this, see [1]), we introduce the SET_INTERRUPT_HANDLER helper macro. The macro does two things: 1) Defines an assembly trampolin to a C function that will, indeed, handle the interrupt. 2) Sets the corresponding interrupt gate descriptor in IDT. The macro usage is pretty straightforward. The macro is defined as SET_INTERRUPT_HANDLER(num, has_error_code, handler) where: @num: Interrupt number (0-255) @has_error_code: 0 if processor doesn't push error code onto the stack. Otherwise, set this argument to 1. @handler: Pointer to function that should be called once the interrupt is raised. In case has_error_code == 0 the function prototype should be the following: void handler(void) Otherwise, it should be: void handler(struct interrupt_context context) For instance, let's say we want to set a handler for a device interrupt (for example, interrupt number 101). Remember, hardware interrupts don't have error code. So we should have something like this: void interrupt_handler(void) { /* Handling code here */ } void my_device_init(void) { ... SET_INTERRUPT_HANDLER(101, 0, interrupt_handler); ... } Now, let's say we want to set an interrupt handler for Page Fault (interrupt number 14). Some exceptions, such as Page Fault, pushes an error code onto the stack and may require registers values in order to be properly be handled. Thus, the code should look like this: void pagefault_handler(struct interrupt_context context) { /* Handling code here */ } void init_memory(void) { ... SET_INTERRUPT_HANDLER(14, 1, pagefault_handler); ... } For further information about exceptions and error code, refer to Intel Combined Manual, Vol. 3, Sections 6.3 and 6.13. Finally, we don't define any API to unregister interrupt handlers since we believe that it wouldn't be useful at all, at least at this moment. Considering Contiki's context, interrupt handler registration is pretty "static" and defined at compile-time by platform code (or the device drivers used by the platform). [1] http://wiki.osdev.org/Interrupt_Service_Routines --- cpu/x86/idt.c | 4 ++ cpu/x86/interrupt.h | 110 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 cpu/x86/interrupt.h diff --git a/cpu/x86/idt.c b/cpu/x86/idt.c index a75b704e8..d561f49f7 100644 --- a/cpu/x86/idt.c +++ b/cpu/x86/idt.c @@ -57,6 +57,10 @@ typedef struct intr_gate_desc { */ static intr_gate_desc_t idt[NUM_DESC] __attribute__ ((aligned(8))); +/* XXX: If you change this function prototype, make sure you fix the assembly + * code in SET_INTERRUPT_HANDLER macro in interrupt.h. Otherwise, you might + * face a very-hard-to-find bug in the interrupt handling system. + */ void idt_set_intr_gate_desc(int intr_num, uint32_t offset) { diff --git a/cpu/x86/interrupt.h b/cpu/x86/interrupt.h new file mode 100644 index 000000000..3310dad02 --- /dev/null +++ b/cpu/x86/interrupt.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef INTERRUPT_H +#define INTERRUPT_H + +#include + +#include "idt.h" + +struct interrupt_context { + uint32_t edi; + uint32_t esi; + uint32_t ebp; + uint32_t esp; + uint32_t ebx; + uint32_t edx; + uint32_t ecx; + uint32_t eax; + uint32_t error_code; + uint32_t eip; +}; + +/* Helper macro to register interrupt handler function. + * + * num: Interrupt number (0-255) + * has_error_code: 0 if interrupt doesn't push error code onto the + * stack. Otherwise, set this argument to 1. + * handler: Pointer to function that should be called once the + * interrupt is raised. In case has_error_code == 0 + * the function prototype should be the following: + * void handler(void) + * Otherwise, it should be: + * void handler(struct interrupt_context context) + * + * Since there is no easy way to write an Interrupt Service Routines + * (ISR) in C (for further information on this, see [1]), we provide + * this helper macro. It basically provides an assembly trampoline + * to a C function (handler parameter) which, indeed, handles the + * interrupt. + * + * [1] http://wiki.osdev.org/Interrupt_Service_Routines + * + * XXX: If you are debugging at assembly level, make sure you don't be misled + * by the "trampolineXX" symbol name. The suffix number is NOT related to the + * interrupt number at all. The suffix number is a unique random number to + * guarantee there is no symbol name clashing. + */ +#define SET_INTERRUPT_HANDLER(num, has_error_code, handler) \ + do { \ + __asm__ __volatile__ ( \ + "push $trampoline%=\n\t" \ + "push %0\n\t" \ + "call %P1\n\t" \ + "add $8, %%esp\n\t" \ + "jmp skip_trampoline%=\n\t" \ + ".align 4\n\t" \ + "trampoline%=:\n\t" \ + " pushal\n\t" \ + " call %P2\n\t" \ + " popal\n\t" \ + " .if " #has_error_code "\n\t" \ + " add $4, %%esp\n\t" \ + " .endif\n\t" \ + " iret\n\t" \ + "skip_trampoline%=:\n\t" \ + :: "g" (num), "i" (idt_set_intr_gate_desc), "i" (handler) \ + ); \ + } while (0) + +/* Disable maskable hardware interrupts */ +#define DISABLE_IRQ() \ + do { \ + __asm__ ("cli"); \ + } while (0) + +/* Enable maskable hardware interrupts */ +#define ENABLE_IRQ() \ + do { \ + __asm__ ("sti"); \ + } while (0) + +#endif /* INTERRUPT_H */ From 604538ed62cb688d88c4b3f6a9fad72b1e0eb32e Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 15 Apr 2015 17:44:38 -0300 Subject: [PATCH 18/92] x86: Set interrupt handler for Double Fault exception This patch sets an interrupt handler for Double Fault exception during CPU initialization. In case such exception is raised, we halt the system. This way, we avoid the system to triple fault (due to an unhandled interrupt for instance), leaving no trace about what cause the triple fault. --- cpu/x86/cpu.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/cpu/x86/cpu.c b/cpu/x86/cpu.c index 9e4707856..d3e5fef84 100644 --- a/cpu/x86/cpu.c +++ b/cpu/x86/cpu.c @@ -30,10 +30,23 @@ #include "gdt.h" #include "idt.h" +#include "interrupt.h" +#include "helpers.h" +static void +double_fault_handler(struct interrupt_context context) +{ + halt(); +} +/*---------------------------------------------------------------------------*/ void cpu_init(void) { gdt_init(); idt_init(); + + /* Set an interrupt handler for Double Fault exception. This way, we avoid + * the system to triple fault, leaving no trace about what happened. + */ + SET_INTERRUPT_HANDLER(8, 1, double_fault_handler); } From 11098501d83d75613df7678e4650011eccd54ae8 Mon Sep 17 00:00:00 2001 From: Jesus Sanchez-Palencia Date: Wed, 8 Apr 2015 17:18:27 -0300 Subject: [PATCH 19/92] x86: Initialize the 8259 PIC The Programmable Interrupt Controller is a chip responsible for translating hardware interrupts to system interrupts. When it receives an Interrupt Request (IRQ), it triggers the appropriate interrupt line reaching the appropriate IDT gate, following a previously setup offset. There are 2 daisy-chained PICs. PIC1 handles IRQs 0-7 and PIC2 handles IRQs 8-15. If no vector offset is set, an IRQ0, for instance, would trigger the interrupt 0, clashing with the "Division by zero exception" handler. Thus the IRQs must be remapped. This patch implements the PICs initialization through their 4 Initialization Command Words (ICWs) in a very "canonical" way: - ICW1: the initializing command; - ICW2: the vector offset for the PIC1 and PIC2 (we add an offset of 32 positions); - ICW3: the inter-PICs wiring setup (we connect PIC2 to PIC1's IRQ2); - ICW4: extra systems information (we set PIC1 as Master and PIC2 as slave). It then masks the Interrupt Mask Register, blocking all IRQs but #2 initially. These must be unmasked on demand. The IMR is 8-bits long, so setting the n^th bit to 1 would DISABLE the IRQ n while setting it to 0 would ENABLE IRQ n. As stated, this is an implementation of the legacy 8259 PIC. More investigation is needed so we decide if it is enough or if we need the (newer) APIC implementation instead. This patch also adds the outb() helper function to helpers.h. The helpers is a wrapper for assembly 'out' instruction. Finally, since we now properly support hardware interrupts, this patch also enables IRQs in platform main(). More information: - Quark X1000 Datasheet, section 21.12, page 898. - http://wiki.osdev.org/8259_PIC - http://stanislavs.org/helppc/8259.html --- cpu/x86/Makefile.x86 | 2 +- cpu/x86/cpu.c | 5 ++- cpu/x86/drivers/pic.h | 70 +++++++++++++++++++++++++++++++++ cpu/x86/helpers.S | 7 ++++ cpu/x86/helpers.h | 8 ++++ platform/galileo/contiki-main.c | 3 ++ 6 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 cpu/x86/drivers/pic.h diff --git a/cpu/x86/Makefile.x86 b/cpu/x86/Makefile.x86 index 94f1d0a03..af69e98f5 100644 --- a/cpu/x86/Makefile.x86 +++ b/cpu/x86/Makefile.x86 @@ -1,4 +1,4 @@ -CONTIKI_CPU_DIRS = . +CONTIKI_CPU_DIRS = . drivers CONTIKI_SOURCEFILES += mtarch.c gdt.c helpers.S idt.c cpu.c diff --git a/cpu/x86/cpu.c b/cpu/x86/cpu.c index d3e5fef84..b7b7a9e5b 100644 --- a/cpu/x86/cpu.c +++ b/cpu/x86/cpu.c @@ -29,9 +29,10 @@ */ #include "gdt.h" +#include "helpers.h" #include "idt.h" #include "interrupt.h" -#include "helpers.h" +#include "pic.h" static void double_fault_handler(struct interrupt_context context) @@ -49,4 +50,6 @@ cpu_init(void) * the system to triple fault, leaving no trace about what happened. */ SET_INTERRUPT_HANDLER(8, 1, double_fault_handler); + + pic_init(); } diff --git a/cpu/x86/drivers/pic.h b/cpu/x86/drivers/pic.h new file mode 100644 index 000000000..3f82a00ab --- /dev/null +++ b/cpu/x86/drivers/pic.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PIC_H +#define PIC_H + +#include "helpers.h" + +#define PIC1_CMD_PORT 0x20 +#define PIC1_DATA_PORT 0x21 +#define PIC2_CMD_PORT 0xA0 +#define PIC2_DATA_PORT 0xA1 + +/* This function initializes the daisy-chained Master and Slave 8259 PICs. + * It is only called once, so let's give the compiler the option to inline it. + * For more information about the ICWs, please refer to http://stanislavs.org/helppc/8259.html. + */ +static inline void +pic_init(void) +{ + /* ICW1: Initialization. */ + outb(PIC1_CMD_PORT, 0x11); + outb(PIC2_CMD_PORT, 0x11); + + /* ICW2: Remap IRQs by setting an IDT Offset for each PIC. */ + outb(PIC1_DATA_PORT, 0x20); + outb(PIC2_DATA_PORT, 0x28); + + /* ICW3: Setup Slave to Master's IRQ2. */ + outb(PIC1_DATA_PORT, 0x04); + outb(PIC2_DATA_PORT, 0x02); + + /* ICW4: Environment setup. Set PIC1 as master and PIC2 as slave. */ + outb(PIC1_DATA_PORT, 0x01); + outb(PIC2_DATA_PORT, 0x01); + + /* Set the IMR register, masking all hardware interrupts but IRQ 2. + * We will have to unmask each IRQ when registering them. */ + outb(PIC1_DATA_PORT, 0xfb); + outb(PIC2_DATA_PORT, 0xff); +} + +#endif /* PIC_H */ diff --git a/cpu/x86/helpers.S b/cpu/x86/helpers.S index 07e3c7655..694f4ef21 100644 --- a/cpu/x86/helpers.S +++ b/cpu/x86/helpers.S @@ -35,3 +35,10 @@ halt: cli die: hlt jmp die + +.global outb +outb: + mov 4(%esp), %dx + mov 8(%esp), %al + out %al, %dx + ret diff --git a/cpu/x86/helpers.h b/cpu/x86/helpers.h index 29476e690..4b76bae98 100644 --- a/cpu/x86/helpers.h +++ b/cpu/x86/helpers.h @@ -31,8 +31,16 @@ #ifndef HELPERS_H #define HELPERS_H +#include + #define BIT(n) (1UL << (n)) void halt(void) __attribute__((__noreturn__)); +/** + * Wrapper for the assembly 'out' instruction. + * + */ +void outb(uint16_t port, uint8_t byte); + #endif /* HELPERS_H */ diff --git a/platform/galileo/contiki-main.c b/platform/galileo/contiki-main.c index 30dd57b5a..8e0f4d6eb 100644 --- a/platform/galileo/contiki-main.c +++ b/platform/galileo/contiki-main.c @@ -30,12 +30,15 @@ #include "contiki.h" #include "cpu.h" +#include "interrupt.h" int main(void) { cpu_init(); + ENABLE_IRQ(); + process_init(); autostart_start(autostart_processes); From 5f47bafc6a2925d58b71ebc234398e9eb6b91eb9 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Thu, 2 Jul 2015 17:29:02 -0300 Subject: [PATCH 20/92] x86: Add Real-Time Clock Driver This patch adds a driver for Real-Time Clock (RTC). The RTC timer is suitable to implement some operating system features such as the system clock. Actually, the RTC will be used to implement the system clock in galileo platform. The driver introduced by this patch programs the RTC to generate interrupt periodically. The interrupt frequency can be configured by the user. On each RTC interrupt, a callback configured by the user is called. As expected, that callback is executed in interrupt context so the user should be aware of what it is not supposed to do (e.g. to call blocking functions). This patch also adds the inb() helper function to helpers.h. The helpers is a wrapper for assembly 'in' instruction. --- cpu/x86/Makefile.x86 | 2 +- cpu/x86/drivers/rtc.c | 92 +++++++++++++++++++++++++++++++++++++++++++ cpu/x86/drivers/rtc.h | 52 ++++++++++++++++++++++++ cpu/x86/helpers.S | 6 +++ cpu/x86/helpers.h | 3 ++ 5 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 cpu/x86/drivers/rtc.c create mode 100644 cpu/x86/drivers/rtc.h diff --git a/cpu/x86/Makefile.x86 b/cpu/x86/Makefile.x86 index af69e98f5..68e7410d5 100644 --- a/cpu/x86/Makefile.x86 +++ b/cpu/x86/Makefile.x86 @@ -1,6 +1,6 @@ CONTIKI_CPU_DIRS = . drivers -CONTIKI_SOURCEFILES += mtarch.c gdt.c helpers.S idt.c cpu.c +CONTIKI_SOURCEFILES += mtarch.c gdt.c helpers.S idt.c cpu.c rtc.c ### Compiler definitions CC = gcc diff --git a/cpu/x86/drivers/rtc.c b/cpu/x86/drivers/rtc.c new file mode 100644 index 000000000..84d534003 --- /dev/null +++ b/cpu/x86/drivers/rtc.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "drivers/rtc.h" +#include "helpers.h" +#include "interrupt.h" + +#define RTC_INDEX_REGISTER 0x70 +#define RTC_TARGET_REGISTER 0x71 + +static void (*user_callback)(void); + +static void +rtc_handler() +{ + user_callback(); + + /* Clear Register C otherwise interrupts will not happen again. + * Register C is automatically cleared when it is read so we do + * a dummy read to clear it. + */ + outb(RTC_INDEX_REGISTER, 0x0C); + inb(RTC_TARGET_REGISTER); + + /* Issue the End of Interrupt to PIC */ + outb(0xA0, 0x20); + outb(0x20, 0x20); +} +/*---------------------------------------------------------------------------*/ +/* Initialize the Real Time Clock. + * @frequency: RTC has very specific values for frequency. They are: 2, 4, 8, + * 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, and 8192 Hz. + * value otherwise it will not work properly. + * @callback: This callback is called every time the RTC IRQ is raised. + * It is executed in interrupt context. + */ +void +rtc_init(rtc_frequency_t frequency, void (*callback)(void)) +{ + uint8_t reg_a, reg_b; + + user_callback = callback; + + /* FIXME: Once we have a proper API to ask PIC what is the IRQ offset, we + * should consider using it here. + */ + SET_INTERRUPT_HANDLER(40, 0, rtc_handler); + + /* Select interrupt period to 7.8125 ms */ + outb(RTC_INDEX_REGISTER, 0x0A); + reg_a = inb(RTC_TARGET_REGISTER); + reg_a &= 0xF0; + reg_a |= frequency; + outb(RTC_INDEX_REGISTER, 0x0A); + outb(RTC_TARGET_REGISTER, reg_a); + + /* Enable periodic interrupt */ + outb(RTC_INDEX_REGISTER, 0x0B); + reg_b = inb(RTC_TARGET_REGISTER); + outb(RTC_INDEX_REGISTER, 0x0B); + outb(RTC_TARGET_REGISTER, reg_b | BIT(6)); + + /* Unmask IRQ8 */ + outb(0xA1, 0xFE); +} diff --git a/cpu/x86/drivers/rtc.h b/cpu/x86/drivers/rtc.h new file mode 100644 index 000000000..257accb43 --- /dev/null +++ b/cpu/x86/drivers/rtc.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RTC_H +#define RTC_H + +typedef enum { + RTC_8192_HZ = 2, + RTC_4096_HZ = 3, + RTC_2048_HZ = 4, + RTC_1024_HZ = 5, + RTC_512_HZ = 6, + RTC_256_HZ = 7, + RTC_128_HZ = 8, + RTC_64_HZ = 9, + RTC_32_HZ = 10, + RTC_16_HZ = 11, + RTC_8_HZ = 12, + RTC_4_HZ = 13, + RTC_2_HZ = 14, +} rtc_frequency_t; + +void rtc_init(rtc_frequency_t frequency, void (*callback)(void)); + +#endif /* RTC_H */ diff --git a/cpu/x86/helpers.S b/cpu/x86/helpers.S index 694f4ef21..0f9f517b8 100644 --- a/cpu/x86/helpers.S +++ b/cpu/x86/helpers.S @@ -42,3 +42,9 @@ outb: mov 8(%esp), %al out %al, %dx ret + +.global inb +inb: + mov 4(%esp), %dx + in %dx, %al + ret diff --git a/cpu/x86/helpers.h b/cpu/x86/helpers.h index 4b76bae98..705f37d45 100644 --- a/cpu/x86/helpers.h +++ b/cpu/x86/helpers.h @@ -43,4 +43,7 @@ void halt(void) __attribute__((__noreturn__)); */ void outb(uint16_t port, uint8_t byte); +/* Wrapper for the assembly 'in' instruction */ +uint8_t inb(uint16_t port); + #endif /* HELPERS_H */ From eafcba5e7a027629ec941b9ec97e2a117b8ad09f Mon Sep 17 00:00:00 2001 From: Jesus Sanchez-Palencia Date: Fri, 3 Jul 2015 18:17:46 -0300 Subject: [PATCH 21/92] galileo: Add support for Clock module This patch adds support for Contiki's clock module. All functions from core/sys/clock.h are implemented, except clock_set_seconds() and clock_ delay_usec(). The CLOCK_CONF_SECOND macro is set to 128. This value seems to be good enough since several platforms used it. Finally, we use the RTC driver to track the number of ticks from the system clock. --- platform/galileo/Makefile.galileo | 2 +- platform/galileo/clock.c | 111 ++++++++++++++++++++++++++++++ platform/galileo/contiki-conf.h | 4 +- platform/galileo/contiki-main.c | 1 + 4 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 platform/galileo/clock.c diff --git a/platform/galileo/Makefile.galileo b/platform/galileo/Makefile.galileo index ead4e7441..350f0c899 100644 --- a/platform/galileo/Makefile.galileo +++ b/platform/galileo/Makefile.galileo @@ -3,7 +3,7 @@ LIBGCC_PATH = /usr/lib/gcc/$(shell gcc -dumpmachine)/$(shell gcc -dumpversion) CONTIKI_TARGET_DIRS = . CONTIKI_TARGET_MAIN = ${addprefix $(OBJECTDIR)/,contiki-main.o} -CONTIKI_SOURCEFILES += contiki-main.c newlib-syscalls.c loader.S +CONTIKI_SOURCEFILES += contiki-main.c newlib-syscalls.c loader.S clock.c LINKERSCRIPT = $(CONTIKI)/platform/galileo/galileo.ld diff --git a/platform/galileo/clock.c b/platform/galileo/clock.c new file mode 100644 index 000000000..e000f1db5 --- /dev/null +++ b/platform/galileo/clock.c @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "sys/clock.h" + +#include "contiki-conf.h" +#include "drivers/rtc.h" + +#if CLOCK_CONF_SECOND == 2 +#define FREQ RTC_2_HZ +#elif CLOCK_CONF_SECOND == 4 +#define FREQ RTC_4_HZ +#elif CLOCK_CONF_SECOND == 8 +#define FREQ RTC_8_HZ +#elif CLOCK_CONF_SECOND == 16 +#define FREQ RTC_16_HZ +#elif CLOCK_CONF_SECOND == 32 +#define FREQ RTC_32_HZ +#elif CLOCK_CONF_SECOND == 64 +#define FREQ RTC_64_HZ +#elif CLOCK_CONF_SECOND == 128 +#define FREQ RTC_128_HZ +#elif CLOCK_CONF_SECOND == 256 +#define FREQ RTC_256_HZ +#elif CLOCK_CONF_SECOND == 512 +#define FREQ RTC_512_HZ +#elif CLOCK_CONF_SECOND == 1024 +#define FREQ RTC_1024_HZ +#elif CLOCK_CONF_SECOND == 2048 +#define FREQ RTC_2048_HZ +#elif CLOCK_CONF_SECOND == 4096 +#define FREQ RTC_4096_HZ +#elif CLOCK_CONF_SECOND == 8192 +#define FREQ RTC_8192_HZ +#else +#define FREQ -1 +#error "RTC is being used thus CLOCK_CONF_SECOND has to be a value defined by rtc_frequency_t." +#endif + +static volatile clock_time_t tick_count = 0; + +static void +update_ticks(void) +{ + tick_count++; +} +/*---------------------------------------------------------------------------*/ +void +clock_init(void) +{ + rtc_init(FREQ, update_ticks); +} +/*---------------------------------------------------------------------------*/ +clock_time_t +clock_time(void) +{ + return tick_count; +} +/*---------------------------------------------------------------------------*/ +unsigned long +clock_seconds(void) +{ + return tick_count / CLOCK_CONF_SECOND; +} +/*---------------------------------------------------------------------------*/ +void +clock_wait(clock_time_t t) +{ + clock_time_t initial = tick_count; + + while(tick_count < t + initial); +} +/*---------------------------------------------------------------------------*/ +void +clock_set_seconds(unsigned long sec) +{ + /* Stubbed function */ +} +/*---------------------------------------------------------------------------*/ +void +clock_delay_usec(uint16_t t) +{ + /* Stubbed function */ +} diff --git a/platform/galileo/contiki-conf.h b/platform/galileo/contiki-conf.h index 4df707d8a..8cc6aa9d6 100644 --- a/platform/galileo/contiki-conf.h +++ b/platform/galileo/contiki-conf.h @@ -33,13 +33,15 @@ #include +#define CLOCK_CONF_SECOND 128 +typedef unsigned long clock_time_t; + /* We define the following macros and types otherwise Contiki does not * compile. */ #define CCIF #define CLIF -typedef unsigned long clock_time_t; typedef unsigned short uip_stats_t; #endif /* CONTIKI_CONF_H */ diff --git a/platform/galileo/contiki-main.c b/platform/galileo/contiki-main.c index 8e0f4d6eb..69387ead5 100644 --- a/platform/galileo/contiki-main.c +++ b/platform/galileo/contiki-main.c @@ -36,6 +36,7 @@ int main(void) { cpu_init(); + clock_init(); ENABLE_IRQ(); From 7c871871deedc555d41cbaff5adbbc39a18aee2f Mon Sep 17 00:00:00 2001 From: Jesus Sanchez-Palencia Date: Fri, 3 Jul 2015 19:21:21 -0300 Subject: [PATCH 22/92] galileo: Add support for Etimer and Ctimer libraries This patch adds support for the Etimer and Ctimer libraries. To support the Etimer library, we should poll the etimer process every time the system clock is updated. To do this more efficiently, by taking advantage of etimer_next_expiration_time() API, we poll the etimer process only when an 'Event Timer' has expired. We don't need any platform specific support in order to enable the Ctimer library since it relies completely on Etimer. The others timer libraries (Timer and Stime) don't required any specific platform support as well since they rely on the system Clock module only. --- platform/galileo/clock.c | 8 ++++++++ platform/galileo/contiki-main.c | 2 ++ 2 files changed, 10 insertions(+) diff --git a/platform/galileo/clock.c b/platform/galileo/clock.c index e000f1db5..d81ba835f 100644 --- a/platform/galileo/clock.c +++ b/platform/galileo/clock.c @@ -29,6 +29,7 @@ */ #include "sys/clock.h" +#include "sys/etimer.h" #include "contiki-conf.h" #include "drivers/rtc.h" @@ -69,7 +70,14 @@ static volatile clock_time_t tick_count = 0; static void update_ticks(void) { + clock_time_t expire = etimer_next_expiration_time(); + tick_count++; + + /* Notify etimer library if the next event timer has expired */ + if(expire != 0 && tick_count >= expire) { + etimer_request_poll(); + } } /*---------------------------------------------------------------------------*/ void diff --git a/platform/galileo/contiki-main.c b/platform/galileo/contiki-main.c index 69387ead5..53b7f9cb1 100644 --- a/platform/galileo/contiki-main.c +++ b/platform/galileo/contiki-main.c @@ -41,6 +41,8 @@ main(void) ENABLE_IRQ(); process_init(); + process_start(&etimer_process, NULL); + ctimer_init(); autostart_start(autostart_processes); while(1) { From d70f67cd604decc704b6e85a71b26a340f69ddd5 Mon Sep 17 00:00:00 2001 From: Jesus Sanchez-Palencia Date: Fri, 3 Jul 2015 19:51:07 -0300 Subject: [PATCH 23/92] galileo: Add PIT driver This patch adds a driver for the 8254 Programmable Interrupt Timer (PIT). The driver introduced by this patch programs the PIT to generate interrupt periodically. The interrupt frequency can be configured by the user. On each PIT interrupt, a callback configured by the user is called. As expected, that callback is executed in interrupt context so the user should be aware of what it is not supposed to do (e.g. to call blocking functions). Issues marked as FIXME are all related to missing APIs on the PIC driver so they will be addressed by a future commit. --- cpu/x86/Makefile.x86 | 2 +- cpu/x86/drivers/pit.c | 80 +++++++++++++++++++++++++++++++++++++++++++ cpu/x86/drivers/pit.h | 45 ++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 cpu/x86/drivers/pit.c create mode 100644 cpu/x86/drivers/pit.h diff --git a/cpu/x86/Makefile.x86 b/cpu/x86/Makefile.x86 index 68e7410d5..eabe99242 100644 --- a/cpu/x86/Makefile.x86 +++ b/cpu/x86/Makefile.x86 @@ -1,6 +1,6 @@ CONTIKI_CPU_DIRS = . drivers -CONTIKI_SOURCEFILES += mtarch.c gdt.c helpers.S idt.c cpu.c rtc.c +CONTIKI_SOURCEFILES += mtarch.c gdt.c helpers.S idt.c cpu.c rtc.c pit.c ### Compiler definitions CC = gcc diff --git a/cpu/x86/drivers/pit.c b/cpu/x86/drivers/pit.c new file mode 100644 index 000000000..c9ce8ff4c --- /dev/null +++ b/cpu/x86/drivers/pit.c @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "pit.h" +#include "helpers.h" +#include "interrupt.h" + +/* PCs usually provide an 8254 PIT chip with maximum clock of 1.193182 MHz. */ +#define PIT_CONTROL_PORT 0x43 +#define PIT_COUNTER0_PORT 0x40 +#define PIT_CLOCK_FREQUENCY 1193182 + +static pit_int_callback interrupt_cb; + +static void +pit_int_handler(void) +{ + interrupt_cb(); + + /* FIXME: Add a pic_send_eoi() API or similar and call it here. */ + outb(0x20, 0x20); /* master PIC */ +} +/*---------------------------------------------------------------------------*/ +void +pit_init(uint32_t ticks_rate, pit_int_callback cb) +{ + /* FIXME: Call some PIC API to get the current offset and then add to its default IRQ number (0). */ + SET_INTERRUPT_HANDLER(32, 0, pit_int_handler); + + interrupt_cb = cb; + + /* Calculate the 16bit divisor that can provide the chosen clock tick rate + * (CLOCK_CONF_SECOND in contiki-conf.h). For reference --> tick rate = clock frequency / divisor. + * If we provide an odd divisor to the Square Wave generator (Mode 3) of + * the Counter0, the duty cycle won't be exactly 50%, so we always round + * it to nearest even integer. + */ + uint16_t divisor = rint(PIT_CLOCK_FREQUENCY / ticks_rate); + + /* Setup Control register flags in a didactic way. */ + uint8_t flags = 0x30; /* Set bits 7:6 to select Counter0 and 5:4 to select "write 7:0 bits first". */ + flags |= 0x6; /* Set bits 3:1 to Mode 3 and bit 0 to BCD off. */ + + outb(PIT_CONTROL_PORT, flags); + + outb(PIT_COUNTER0_PORT, divisor & 0xFF); /* Write least significant bytes first. */ + outb(PIT_COUNTER0_PORT, (divisor >> 8) & 0xFF); + + /* FIXME: Unmask IRQ0 from Master PIC. Add a pic_set_mask() or similar and call it here. */ + outb(0x21, 0xfa); +} diff --git a/cpu/x86/drivers/pit.h b/cpu/x86/drivers/pit.h new file mode 100644 index 000000000..0a16b8929 --- /dev/null +++ b/cpu/x86/drivers/pit.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PIT_H +#define PIT_H + +#include + +typedef void (*pit_int_callback)(void); + +/** + * Initializes the 8254 Programmable Interrupt Timer chip (Counter 0 only). + * The PIT Interrupt callback is implemented by the driver's users. It is + * called from interrupt context, so it has to return as soon as possible. + */ +void pit_init(uint32_t ticks_rate, pit_int_callback c); + +#endif /* PIT_H */ From e4ff61ff6c5fa97beceec0cdb68c758c5f8b0fec Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Thu, 2 Jul 2015 17:57:03 -0300 Subject: [PATCH 24/92] galileo: Support for rtimer library This patch adds support for rtimer library on Galileo's platform. We use the PIT to implement the rtimer platform dependent functionalities. We chose the PIT for mainly two reason: I) its configuration is very simple II) it has a high frequency which provides us a good clock resolution (requirement from rtimer library). Since we keep track of the number of ticks in software, we define rtimer_clock_t type as uint64_t. This gives us a good amount of time til the variable overflows. For instance, a 32-bit type would overflow in about one hour for high clock resolution (~ 1us). The rtimer clock frequency (RTIMER_ARCH_SECOND) is setup to 1 kHz. There is no technical matter regarding this value. It is just an initial guess. Just for the record, we might want to use HPET in future to implement the rtimer library since it seems to be more appropriate. The reason why we don't use it at this moment is that, in order to configure it, we need support for ACPI 2.0 which we don't. Once we have use-cases for the rtimer library we'll probably replace PIT by HPET or any other timer more suitable for the job. --- platform/galileo/Makefile.galileo | 2 +- platform/galileo/contiki-conf.h | 4 ++ platform/galileo/contiki-main.c | 1 + platform/galileo/rtimer-arch.c | 65 +++++++++++++++++++++++++++++++ platform/galileo/rtimer-arch.h | 2 + 5 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 platform/galileo/rtimer-arch.c diff --git a/platform/galileo/Makefile.galileo b/platform/galileo/Makefile.galileo index 350f0c899..9fd8b60ba 100644 --- a/platform/galileo/Makefile.galileo +++ b/platform/galileo/Makefile.galileo @@ -3,7 +3,7 @@ LIBGCC_PATH = /usr/lib/gcc/$(shell gcc -dumpmachine)/$(shell gcc -dumpversion) CONTIKI_TARGET_DIRS = . CONTIKI_TARGET_MAIN = ${addprefix $(OBJECTDIR)/,contiki-main.o} -CONTIKI_SOURCEFILES += contiki-main.c newlib-syscalls.c loader.S clock.c +CONTIKI_SOURCEFILES += contiki-main.c newlib-syscalls.c loader.S clock.c rtimer-arch.c LINKERSCRIPT = $(CONTIKI)/platform/galileo/galileo.ld diff --git a/platform/galileo/contiki-conf.h b/platform/galileo/contiki-conf.h index 8cc6aa9d6..4f1b0fe4b 100644 --- a/platform/galileo/contiki-conf.h +++ b/platform/galileo/contiki-conf.h @@ -36,6 +36,10 @@ #define CLOCK_CONF_SECOND 128 typedef unsigned long clock_time_t; +typedef uint64_t rtimer_clock_t; +#define RTIMER_ARCH_SECOND 1024 +#define RTIMER_CLOCK_LT(a, b) ((int64_t)((a) - (b)) < 0) + /* We define the following macros and types otherwise Contiki does not * compile. */ diff --git a/platform/galileo/contiki-main.c b/platform/galileo/contiki-main.c index 53b7f9cb1..199ae45cc 100644 --- a/platform/galileo/contiki-main.c +++ b/platform/galileo/contiki-main.c @@ -37,6 +37,7 @@ main(void) { cpu_init(); clock_init(); + rtimer_init(); ENABLE_IRQ(); diff --git a/platform/galileo/rtimer-arch.c b/platform/galileo/rtimer-arch.c new file mode 100644 index 000000000..862c26692 --- /dev/null +++ b/platform/galileo/rtimer-arch.c @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "sys/rtimer.h" + +#include "contiki-conf.h" +#include "drivers/pit.h" + +static volatile rtimer_clock_t tick_count = 0; +static rtimer_clock_t trigger = UINT64_MAX; + +static void +update_ticks(void) +{ + if(++tick_count >= trigger) { + /* Disable trigger by assigning it to the maximum value */ + trigger = UINT64_MAX; + rtimer_run_next(); + } +} +/*---------------------------------------------------------------------------*/ +void +rtimer_arch_init(void) +{ + pit_init(RTIMER_ARCH_SECOND, update_ticks); +} +/*---------------------------------------------------------------------------*/ +rtimer_clock_t +rtimer_arch_now() +{ + return tick_count; +} +/*---------------------------------------------------------------------------*/ +void +rtimer_arch_schedule(rtimer_clock_t t) +{ + trigger = t; +} diff --git a/platform/galileo/rtimer-arch.h b/platform/galileo/rtimer-arch.h index 086602aa2..3f12056e1 100644 --- a/platform/galileo/rtimer-arch.h +++ b/platform/galileo/rtimer-arch.h @@ -31,4 +31,6 @@ #ifndef RTIMER_ARCH_H #define RTIMER_ARCH_H +rtimer_clock_t rtimer_arch_now(); + #endif /* RTIMER_ARCH_H */ From b8056b9c9750c3330c5546dda4b28ded5d032dd6 Mon Sep 17 00:00:00 2001 From: Jesus Sanchez-Palencia Date: Thu, 2 Jul 2015 14:42:03 -0300 Subject: [PATCH 25/92] examples: Add all-timers example This commit adds a very simple example which is useful to verify that all timers APIs are working. There are 3 protothreads running, the first process tests etimer, timer and stimer APIs, the second process tests the ctimer APIs, and the third one tests the rtimer APIs. --- examples/timers/Makefile | 5 ++ examples/timers/all-timers.c | 131 +++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 examples/timers/Makefile create mode 100644 examples/timers/all-timers.c diff --git a/examples/timers/Makefile b/examples/timers/Makefile new file mode 100644 index 000000000..d5b2a2846 --- /dev/null +++ b/examples/timers/Makefile @@ -0,0 +1,5 @@ +CONTIKI_PROJECT = all-timers +all: $(CONTIKI_PROJECT) + +CONTIKI = ../.. +include $(CONTIKI)/Makefile.include diff --git a/examples/timers/all-timers.c b/examples/timers/all-timers.c new file mode 100644 index 000000000..60eb56651 --- /dev/null +++ b/examples/timers/all-timers.c @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "contiki.h" +#include "sys/etimer.h" +#include "sys/stimer.h" +#include "sys/timer.h" +#include "sys/rtimer.h" + +PROCESS(process1, "ETimer x Timer x STimer Process"); +PROCESS(process2, "CTimer Process 2"); +PROCESS(process3, "RTimer Process 3"); +AUTOSTART_PROCESSES(&process1, &process2, &process3); + +static int counter_etimer; +static int counter_timer; +static int counter_stimer; +static int counter_ctimer; +static int counter_rtimer; +static struct timer timer_timer; +static struct stimer timer_stimer; +static struct ctimer timer_ctimer; +static struct rtimer timer_rtimer; +static rtimer_clock_t timeout_rtimer = RTIMER_SECOND / 2; + +void +do_timeout1() +{ + counter_etimer++; + if(timer_expired(&timer_timer)) { + counter_timer++; + } + + if(stimer_expired(&timer_stimer)) { + counter_stimer++; + } + + printf("\nProcess 1: %s", counter_timer == counter_etimer + && counter_timer == counter_stimer ? "SUCCESS" : "FAIL"); +} +/*---------------------------------------------------------------------------*/ +void +do_timeout2() +{ + ctimer_reset(&timer_ctimer); + printf("\nProcess 2: CTimer callback called"); + counter_ctimer++; +} +/*---------------------------------------------------------------------------*/ +void +do_timeout3(struct rtimer *timer, void *ptr) +{ + counter_rtimer++; + + printf("\nProcess 3: RTimer callback called"); + + /* Re-arm rtimer */ + rtimer_set(&timer_rtimer, RTIMER_NOW() + timeout_rtimer, 0, do_timeout3, + NULL); +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(process1, ev, data) +{ + static struct etimer timer_etimer; + + PROCESS_BEGIN(); + + while(1) { + timer_set(&timer_timer, 3 * CLOCK_SECOND); + stimer_set(&timer_stimer, 3); + etimer_set(&timer_etimer, 3 * CLOCK_SECOND); + PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_TIMER); + do_timeout1(); + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(process2, ev, data) +{ + PROCESS_BEGIN(); + + while(1) { + ctimer_set(&timer_ctimer, 5 * CLOCK_SECOND, do_timeout2, NULL); + PROCESS_YIELD(); + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(process3, ev, data) +{ + PROCESS_BEGIN(); + + while(1) { + rtimer_set(&timer_rtimer, RTIMER_NOW() + timeout_rtimer, 0, + do_timeout3, NULL); + PROCESS_YIELD(); + } + + PROCESS_END(); +} From 826ff7cb29cb2b9f966c8950a89e88121f3820f8 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Thu, 2 Jul 2015 17:46:47 -0300 Subject: [PATCH 26/92] x86: Add pic_unmask_irq() helper This patch implements the pic_unmask_irq() helper and uses it where applicable. This function zeros the corresponding bit from the IRQ number in IMR register. This patch doesn't implement the pic_mask_irq() helper since it is not useful at this moment. --- cpu/x86/Makefile.x86 | 2 +- cpu/x86/drivers/pic.c | 48 +++++++++++++++++++++++++++++++++++++++++++ cpu/x86/drivers/pic.h | 2 ++ cpu/x86/drivers/pit.c | 4 ++-- cpu/x86/drivers/rtc.c | 4 ++-- 5 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 cpu/x86/drivers/pic.c diff --git a/cpu/x86/Makefile.x86 b/cpu/x86/Makefile.x86 index eabe99242..57e2006c9 100644 --- a/cpu/x86/Makefile.x86 +++ b/cpu/x86/Makefile.x86 @@ -1,6 +1,6 @@ CONTIKI_CPU_DIRS = . drivers -CONTIKI_SOURCEFILES += mtarch.c gdt.c helpers.S idt.c cpu.c rtc.c pit.c +CONTIKI_SOURCEFILES += mtarch.c gdt.c helpers.S idt.c cpu.c rtc.c pit.c pic.c ### Compiler definitions CC = gcc diff --git a/cpu/x86/drivers/pic.c b/cpu/x86/drivers/pic.c new file mode 100644 index 000000000..2e6428756 --- /dev/null +++ b/cpu/x86/drivers/pic.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "drivers/pic.h" + +void +pic_unmask_irq(unsigned int num) +{ + uint16_t port; + uint8_t bitmap; + + if(num <= 7) { + port = PIC1_DATA_PORT; + } else { + port = PIC2_DATA_PORT; + num -= 8; + } + + bitmap = inb(port); + outb(port, bitmap & ~BIT(num)); +} diff --git a/cpu/x86/drivers/pic.h b/cpu/x86/drivers/pic.h index 3f82a00ab..81de51e7b 100644 --- a/cpu/x86/drivers/pic.h +++ b/cpu/x86/drivers/pic.h @@ -38,6 +38,8 @@ #define PIC2_CMD_PORT 0xA0 #define PIC2_DATA_PORT 0xA1 +void pic_unmask_irq(unsigned int num); + /* This function initializes the daisy-chained Master and Slave 8259 PICs. * It is only called once, so let's give the compiler the option to inline it. * For more information about the ICWs, please refer to http://stanislavs.org/helppc/8259.html. diff --git a/cpu/x86/drivers/pit.c b/cpu/x86/drivers/pit.c index c9ce8ff4c..9eeb38523 100644 --- a/cpu/x86/drivers/pit.c +++ b/cpu/x86/drivers/pit.c @@ -30,6 +30,7 @@ #include +#include "drivers/pic.h" #include "pit.h" #include "helpers.h" #include "interrupt.h" @@ -75,6 +76,5 @@ pit_init(uint32_t ticks_rate, pit_int_callback cb) outb(PIT_COUNTER0_PORT, divisor & 0xFF); /* Write least significant bytes first. */ outb(PIT_COUNTER0_PORT, (divisor >> 8) & 0xFF); - /* FIXME: Unmask IRQ0 from Master PIC. Add a pic_set_mask() or similar and call it here. */ - outb(0x21, 0xfa); + pic_unmask_irq(0); } diff --git a/cpu/x86/drivers/rtc.c b/cpu/x86/drivers/rtc.c index 84d534003..243c6623f 100644 --- a/cpu/x86/drivers/rtc.c +++ b/cpu/x86/drivers/rtc.c @@ -29,6 +29,7 @@ */ #include "drivers/rtc.h" +#include "drivers/pic.h" #include "helpers.h" #include "interrupt.h" @@ -87,6 +88,5 @@ rtc_init(rtc_frequency_t frequency, void (*callback)(void)) outb(RTC_INDEX_REGISTER, 0x0B); outb(RTC_TARGET_REGISTER, reg_b | BIT(6)); - /* Unmask IRQ8 */ - outb(0xA1, 0xFE); + pic_unmask_irq(8); } From afd9b5b0b7b2dcbf964ff7955890777a60919949 Mon Sep 17 00:00:00 2001 From: Jesus Sanchez-Palencia Date: Thu, 2 Jul 2015 18:24:20 -0300 Subject: [PATCH 27/92] x86: Add APIs to 8259 PIC driver This commit implements pic_eoi(int irq) and a helper macro PIC_INT(irq). This first checks which PICs should be 'acked' given an IRQ number, while the macro returns the actual system interrupt number for the IRQ according to the offset used on the PIC initialization. --- cpu/x86/drivers/pic.c | 12 ++++++++++++ cpu/x86/drivers/pic.h | 18 ++++++++++++++++-- cpu/x86/drivers/pit.c | 10 +++++----- cpu/x86/drivers/rtc.c | 12 +++++------- 4 files changed, 38 insertions(+), 14 deletions(-) diff --git a/cpu/x86/drivers/pic.c b/cpu/x86/drivers/pic.c index 2e6428756..12b79e39b 100644 --- a/cpu/x86/drivers/pic.c +++ b/cpu/x86/drivers/pic.c @@ -30,6 +30,8 @@ #include "drivers/pic.h" +#define PIC_ACK 0x20 + void pic_unmask_irq(unsigned int num) { @@ -46,3 +48,13 @@ pic_unmask_irq(unsigned int num) bitmap = inb(port); outb(port, bitmap & ~BIT(num)); } +/*---------------------------------------------------------------------------*/ +void +pic_eoi(unsigned int irq) +{ + if(irq >= 8) { + outb(PIC2_CMD_PORT, PIC_ACK); + } + + outb(PIC1_CMD_PORT, PIC_ACK); +} diff --git a/cpu/x86/drivers/pic.h b/cpu/x86/drivers/pic.h index 81de51e7b..d39942438 100644 --- a/cpu/x86/drivers/pic.h +++ b/cpu/x86/drivers/pic.h @@ -37,6 +37,14 @@ #define PIC1_DATA_PORT 0x21 #define PIC2_CMD_PORT 0xA0 #define PIC2_DATA_PORT 0xA1 +#define PIC1_OFFSET 0x20 +#define PIC2_OFFSET PIC1_OFFSET + 8 + +/* + * Returns the actual interrupt number of a given IRQ, + * no matter which PIC it is part of. + */ +#define PIC_INT(a) (a + PIC1_OFFSET) void pic_unmask_irq(unsigned int num); @@ -52,8 +60,8 @@ pic_init(void) outb(PIC2_CMD_PORT, 0x11); /* ICW2: Remap IRQs by setting an IDT Offset for each PIC. */ - outb(PIC1_DATA_PORT, 0x20); - outb(PIC2_DATA_PORT, 0x28); + outb(PIC1_DATA_PORT, PIC1_OFFSET); + outb(PIC2_DATA_PORT, PIC2_OFFSET); /* ICW3: Setup Slave to Master's IRQ2. */ outb(PIC1_DATA_PORT, 0x04); @@ -69,4 +77,10 @@ pic_init(void) outb(PIC2_DATA_PORT, 0xff); } +/* + * This function sends an end-of-interrupt (EOI) to the correct PIC according + * to the IRQ line number. + */ +void pic_eoi(unsigned int irq); + #endif /* PIC_H */ diff --git a/cpu/x86/drivers/pit.c b/cpu/x86/drivers/pit.c index 9eeb38523..557b27985 100644 --- a/cpu/x86/drivers/pit.c +++ b/cpu/x86/drivers/pit.c @@ -39,6 +39,8 @@ #define PIT_CONTROL_PORT 0x43 #define PIT_COUNTER0_PORT 0x40 #define PIT_CLOCK_FREQUENCY 1193182 +#define PIT_IRQ 0 +#define PIT_INT PIC_INT(PIT_IRQ) static pit_int_callback interrupt_cb; @@ -47,15 +49,13 @@ pit_int_handler(void) { interrupt_cb(); - /* FIXME: Add a pic_send_eoi() API or similar and call it here. */ - outb(0x20, 0x20); /* master PIC */ + pic_eoi(PIT_IRQ); } /*---------------------------------------------------------------------------*/ void pit_init(uint32_t ticks_rate, pit_int_callback cb) { - /* FIXME: Call some PIC API to get the current offset and then add to its default IRQ number (0). */ - SET_INTERRUPT_HANDLER(32, 0, pit_int_handler); + SET_INTERRUPT_HANDLER(PIT_INT, 0, pit_int_handler); interrupt_cb = cb; @@ -76,5 +76,5 @@ pit_init(uint32_t ticks_rate, pit_int_callback cb) outb(PIT_COUNTER0_PORT, divisor & 0xFF); /* Write least significant bytes first. */ outb(PIT_COUNTER0_PORT, (divisor >> 8) & 0xFF); - pic_unmask_irq(0); + pic_unmask_irq(PIT_IRQ); } diff --git a/cpu/x86/drivers/rtc.c b/cpu/x86/drivers/rtc.c index 243c6623f..ad9eec221 100644 --- a/cpu/x86/drivers/rtc.c +++ b/cpu/x86/drivers/rtc.c @@ -35,6 +35,8 @@ #define RTC_INDEX_REGISTER 0x70 #define RTC_TARGET_REGISTER 0x71 +#define RTC_IRQ 8 +#define RTC_INT PIC_INT(RTC_IRQ) static void (*user_callback)(void); @@ -51,8 +53,7 @@ rtc_handler() inb(RTC_TARGET_REGISTER); /* Issue the End of Interrupt to PIC */ - outb(0xA0, 0x20); - outb(0x20, 0x20); + pic_eoi(RTC_IRQ); } /*---------------------------------------------------------------------------*/ /* Initialize the Real Time Clock. @@ -69,10 +70,7 @@ rtc_init(rtc_frequency_t frequency, void (*callback)(void)) user_callback = callback; - /* FIXME: Once we have a proper API to ask PIC what is the IRQ offset, we - * should consider using it here. - */ - SET_INTERRUPT_HANDLER(40, 0, rtc_handler); + SET_INTERRUPT_HANDLER(RTC_INT, 0, rtc_handler); /* Select interrupt period to 7.8125 ms */ outb(RTC_INDEX_REGISTER, 0x0A); @@ -88,5 +86,5 @@ rtc_init(rtc_frequency_t frequency, void (*callback)(void)) outb(RTC_INDEX_REGISTER, 0x0B); outb(RTC_TARGET_REGISTER, reg_b | BIT(6)); - pic_unmask_irq(8); + pic_unmask_irq(RTC_IRQ); } From 3b01e04379bdb59e42c413f01d4b34d30ecafc0f Mon Sep 17 00:00:00 2001 From: Jesus Sanchez-Palencia Date: Thu, 2 Jul 2015 18:28:44 -0300 Subject: [PATCH 28/92] x86: Add a fake IRQ7 handler to avoid spurious interrupts The 8259a PIC has a well known problem of generating flaky IRQ7 interrupts. The correct solution is to always check if an IRQ7 interrupt is real or not by probing the PIC's ISR register. This check is only mandatory if the IRQ7 is actually being used by the system. More importantly, the handler should NEVER send and EOI if the interrupt was spurious. This patch addresses this issue by implementing a fake empty handler for this IRQ and, as stated, NOT sending the EOI. --- cpu/x86/cpu.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/cpu/x86/cpu.c b/cpu/x86/cpu.c index b7b7a9e5b..77e8f8026 100644 --- a/cpu/x86/cpu.c +++ b/cpu/x86/cpu.c @@ -34,12 +34,28 @@ #include "interrupt.h" #include "pic.h" +#define IRQ7_INT PIC_INT(7) + static void double_fault_handler(struct interrupt_context context) { halt(); } /*---------------------------------------------------------------------------*/ +static void +spurious_irq7_handler(void) +{ + /* + * NOTE: Originally IRQ7 was used for the parallel port interrupts. Nowadays, + * though, it is only used if some other IRQ (i.e.: a PCIx interrupt) is + * mapped to it. In this case we will have to check the PIC ISR register in + * order to confirm this was a real interrupt. + * + * In case of a spurious interrupt, we should NEVER send an EOI here so the PIC + * doesn't trigger the next queued interrupt. + */ +} +/*---------------------------------------------------------------------------*/ void cpu_init(void) { @@ -52,4 +68,9 @@ cpu_init(void) SET_INTERRUPT_HANDLER(8, 1, double_fault_handler); pic_init(); + + /* Set a 'fake' handler for the Spurious IRQ7 interrupts. + * Refer to http://wiki.osdev.org/PIC . + */ + SET_INTERRUPT_HANDLER(IRQ7_INT, 0, spurious_irq7_handler); } From 568f565b3d726775cfda28184e1780845aa6a6ff Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Thu, 2 Jul 2015 20:49:55 -0300 Subject: [PATCH 29/92] galileo: Update README.md file This patch updates the README.md file, including information about the current device drivers implementations as well as the Contiki APIs supported. --- platform/galileo/README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/platform/galileo/README.md b/platform/galileo/README.md index 1ccd9b0a6..121bf2471 100644 --- a/platform/galileo/README.md +++ b/platform/galileo/README.md @@ -24,7 +24,14 @@ Features This section presents the features currently supported (e.g. device drivers and Contiki APIs) by the Galileo port. -For now, no features are supported. +Device drivers: + * Programmable Interrupt Controller (PIC) + * Programmable Intergal Timer (PIT) + * Real-Time Clock (RTC) + +Contiki APIs: + * Clock module + * Timer, Stimer, Etimer, Ctimer, and Rtimer libraries Building -------- From 9d3b9cadc40d3b78432fbc4dc840ab3fa6ee9c28 Mon Sep 17 00:00:00 2001 From: Jesus Sanchez-Palencia Date: Wed, 29 Apr 2015 12:51:29 -0300 Subject: [PATCH 30/92] galileo: Concentrate core implementations in platform/galileo/core/ Currently, it is common to see Contiki's core/ interfaces implementations spread in both cpu/ and platform/. We here take one step further starting an effort to centralize all of these in platform's code instead. This commit starts this by adding platform/galileo/core/ and its sys/ subfolder, adding a stubbed mtarch.h and moving clock and rtimer implementations to this new folder. From now on we should concentrate implementation from Contiki's core/ interfaces into the appropriate subfolder in platform/galileo/core/. Note that this is not the current fashion followed on other platforms and cpus folders, as most of them add the core interface implementation into its subfolder directly. For instance, on CC2538DK, core/dev/button-sensor.h is implemented in platform/cc2538dk/dev/ directly, while on Galileo it would sit at platform/galileo/core/dev/. We believe ours is a better approach to organize and escalate a platform's code base. We also remove previous x86 mtarch.h and mtarch.c since they weren't used at all - both native and cooja platforms have their own mtarch implementations. --- cpu/x86/Makefile.x86 | 2 +- cpu/x86/mtarch.c | 188 ------------------ cpu/x86/mtarch.h | 49 ----- platform/galileo/Makefile.galileo | 2 +- platform/galileo/{ => core/sys}/clock.c | 0 platform/galileo/core/sys/mtarch.h | 37 ++++ platform/galileo/{ => core/sys}/rtimer-arch.c | 0 platform/galileo/{ => core/sys}/rtimer-arch.h | 0 8 files changed, 39 insertions(+), 239 deletions(-) delete mode 100644 cpu/x86/mtarch.c delete mode 100644 cpu/x86/mtarch.h rename platform/galileo/{ => core/sys}/clock.c (100%) create mode 100644 platform/galileo/core/sys/mtarch.h rename platform/galileo/{ => core/sys}/rtimer-arch.c (100%) rename platform/galileo/{ => core/sys}/rtimer-arch.h (100%) diff --git a/cpu/x86/Makefile.x86 b/cpu/x86/Makefile.x86 index 57e2006c9..d5772d973 100644 --- a/cpu/x86/Makefile.x86 +++ b/cpu/x86/Makefile.x86 @@ -1,6 +1,6 @@ CONTIKI_CPU_DIRS = . drivers -CONTIKI_SOURCEFILES += mtarch.c gdt.c helpers.S idt.c cpu.c rtc.c pit.c pic.c +CONTIKI_SOURCEFILES += gdt.c helpers.S idt.c cpu.c rtc.c pit.c pic.c ### Compiler definitions CC = gcc diff --git a/cpu/x86/mtarch.c b/cpu/x86/mtarch.c deleted file mode 100644 index ccc9567b8..000000000 --- a/cpu/x86/mtarch.c +++ /dev/null @@ -1,188 +0,0 @@ - -#include -#include -#include "sys/mt.h" - -#ifndef __WORDSIZE -#define __WORDSIZE 32 -#endif /* __WORDSIZE */ - -#ifndef ON_64BIT_ARCH -#if __WORDSIZE == 64 -#define ON_64BIT_ARCH 1 -#else /* ON_64BIT_ARCH */ -#define ON_64BIT_ARCH 0 -#endif /* __WORDSIZE == 64 */ -#endif /* ON_64BIT_ARCH */ - -struct frame { - unsigned long flags; -#if ON_64BIT_ARCH - unsigned long rbp; - unsigned long rdi; - unsigned long rsi; - unsigned long rdx; - unsigned long rcx; - unsigned long rbx; - unsigned long rax; -#else /* ON_64BIT_ARCH */ - unsigned long ebp; - unsigned long edi; - unsigned long esi; - unsigned long edx; - unsigned long ecx; - unsigned long ebx; - unsigned long eax; -#endif /* ON_64BIT_ARCH */ - unsigned long retaddr; - unsigned long retaddr2; - unsigned long data; -}; -/*--------------------------------------------------------------------------*/ -void -mtarch_init(void) -{ -} -/*--------------------------------------------------------------------------*/ -void -mtarch_start(struct mtarch_thread *t, - void (*function)(void *), void *data) -{ - struct frame *f = (struct frame *)&t->stack[MTARCH_STACKSIZE - sizeof(struct frame)/sizeof(unsigned long)]; - int i; - - for(i = 0; i < MTARCH_STACKSIZE; ++i) { - t->stack[i] = i; - } - - memset(f, 0, sizeof(struct frame)); - f->retaddr = (unsigned long)function; - f->data = (unsigned long)data; - t->sp = (unsigned long)&f->flags; -#if ON_64BIT_ARCH - f->rbp = (unsigned long)&f->rax; -#else /* ON_64BIT_ARCH */ - f->ebp = (unsigned long)&f->eax; -#endif /* ON_64BIT_ARCH */ -} -/*--------------------------------------------------------------------------*/ -static struct mtarch_thread *running_thread; -/*--------------------------------------------------------------------------*/ -static void -sw(void) -{ - /* Store registers */ -#if ON_64BIT_ARCH - __asm__ ( - "pushq %rax\n\t" - "pushq %rbx\n\t" - "pushq %rcx\n\t" - "pushq %rdx\n\t" - "pushq %rsi\n\t" - "pushq %rdi\n\t" - "pushq %rbp\n\t" - "pushq %rbp\n\t"); -#else /* ON_64BIT_ARCH */ - __asm__ ( - "pushl %eax\n\t" - "pushl %ebx\n\t" - "pushl %ecx\n\t" - "pushl %edx\n\t" - "pushl %esi\n\t" - "pushl %edi\n\t" - "pushl %ebp\n\t" - "pushl %ebp\n\t"); -#endif /* ON_64BIT_ARCH */ - - /* Switch stack pointer */ -#if ON_64BIT_ARCH - __asm__ ("movq %0, %%rax\n\t" : : "m" (running_thread)); - __asm__ ( - "movq (%rax), %rbx\n\t" - "movq %rsp, (%rax)\n\t" - "movq %rbx, %rsp\n\t" - ); -#else /* ON_64BIT_ARCH */ - __asm__ ("movl %0, %%eax\n\t" : : "m" (running_thread)); - __asm__ ( - "movl (%eax), %ebx\n\t" - "movl %esp, (%eax)\n\t" - "movl %ebx, %esp\n\t" - ); -#endif /* ON_64BIT_ARCH */ - - /* Restore previous registers */ -#if ON_64BIT_ARCH - __asm__ ( - "popq %rbp\n\t" - "popq %rbp\n\t" - "popq %rdi\n\t" - "popq %rsi\n\t" - "popq %rdx\n\t" - "popq %rcx\n\t" - "popq %rbx\n\t" - "popq %rax\n\t" - - "leave\n\t" - "ret\n\t" - ); -#else /* ON_64BIT_ARCH */ - __asm__ ( - "popl %ebp\n\t" - "popl %ebp\n\t" - "popl %edi\n\t" - "popl %esi\n\t" - "popl %edx\n\t" - "popl %ecx\n\t" - "popl %ebx\n\t" - "popl %eax\n\t" - - "leave\n\t" - "ret\n\t" - ); -#endif /* ON_64BIT_ARCH */ - -} - -/*--------------------------------------------------------------------------*/ -void -mtarch_exec(struct mtarch_thread *t) -{ - running_thread = t; - sw(); - running_thread = NULL; -} -/*--------------------------------------------------------------------------*/ -void -mtarch_remove(void) -{ -} -/*--------------------------------------------------------------------------*/ -void -mtarch_yield(void) -{ - sw(); -} -/*--------------------------------------------------------------------------*/ -void -mtarch_pstop(void) -{ -} -/*--------------------------------------------------------------------------*/ -void -mtarch_pstart(void) -{ -} -/*--------------------------------------------------------------------------*/ -int -mtarch_stack_usage(struct mt_thread *t) -{ - int i; - for(i = 0; i < MTARCH_STACKSIZE; ++i) { - if(t->thread.stack[i] != i) { - return MTARCH_STACKSIZE - i; - } - } - return -1; -} -/*--------------------------------------------------------------------------*/ diff --git a/cpu/x86/mtarch.h b/cpu/x86/mtarch.h deleted file mode 100644 index 9f982828a..000000000 --- a/cpu/x86/mtarch.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2003, Adam Dunkels. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ -#ifndef MTARCH_H_ -#define MTARCH_H_ - -#ifndef MTARCH_STACKSIZE -#define MTARCH_STACKSIZE 1024 -#endif /* MTARCH_STACKSIZE */ - -struct mtarch_thread { - /* Note: stack must be aligned on 4-byte boundary. */ - unsigned long stack[MTARCH_STACKSIZE]; - unsigned long sp; -}; - -struct mt_thread; - -int mtarch_stack_usage(struct mt_thread *t); - -#endif /* MTARCH_H_ */ - diff --git a/platform/galileo/Makefile.galileo b/platform/galileo/Makefile.galileo index 9fd8b60ba..15f693401 100644 --- a/platform/galileo/Makefile.galileo +++ b/platform/galileo/Makefile.galileo @@ -1,7 +1,7 @@ LIBC=$(CONTIKI)/platform/galileo/bsp/libc/i586-elf LIBGCC_PATH = /usr/lib/gcc/$(shell gcc -dumpmachine)/$(shell gcc -dumpversion) -CONTIKI_TARGET_DIRS = . +CONTIKI_TARGET_DIRS = . core/sys/ CONTIKI_TARGET_MAIN = ${addprefix $(OBJECTDIR)/,contiki-main.o} CONTIKI_SOURCEFILES += contiki-main.c newlib-syscalls.c loader.S clock.c rtimer-arch.c diff --git a/platform/galileo/clock.c b/platform/galileo/core/sys/clock.c similarity index 100% rename from platform/galileo/clock.c rename to platform/galileo/core/sys/clock.c diff --git a/platform/galileo/core/sys/mtarch.h b/platform/galileo/core/sys/mtarch.h new file mode 100644 index 000000000..c8c3440df --- /dev/null +++ b/platform/galileo/core/sys/mtarch.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MTARCH_H_ +#define MTARCH_H_ + +struct mtarch_thread { +}; + +#endif /* MTARCH_H_ */ diff --git a/platform/galileo/rtimer-arch.c b/platform/galileo/core/sys/rtimer-arch.c similarity index 100% rename from platform/galileo/rtimer-arch.c rename to platform/galileo/core/sys/rtimer-arch.c diff --git a/platform/galileo/rtimer-arch.h b/platform/galileo/core/sys/rtimer-arch.h similarity index 100% rename from platform/galileo/rtimer-arch.h rename to platform/galileo/core/sys/rtimer-arch.h From 23e80902578ec682ae40f4b3e1bb349f8ab4d9e1 Mon Sep 17 00:00:00 2001 From: Jesus Sanchez-Palencia Date: Thu, 2 Jul 2015 19:50:18 -0300 Subject: [PATCH 31/92] x86: Move available drivers into drivers/legacy_pc/ All drivers implemented so far are for chips which are only available on legacy x86 PCs. This commit moves them into a more appropriate folder, also making the cpu/x86/drivers/ folder ready for other x86 based SoCs. --- cpu/x86/Makefile.x86 | 2 +- cpu/x86/drivers/{ => legacy_pc}/pic.c | 2 +- cpu/x86/drivers/{ => legacy_pc}/pic.h | 0 cpu/x86/drivers/{ => legacy_pc}/pit.c | 4 ++-- cpu/x86/drivers/{ => legacy_pc}/pit.h | 0 cpu/x86/drivers/{ => legacy_pc}/rtc.c | 4 ++-- cpu/x86/drivers/{ => legacy_pc}/rtc.h | 0 platform/galileo/core/sys/clock.c | 2 +- platform/galileo/core/sys/rtimer-arch.c | 2 +- 9 files changed, 8 insertions(+), 8 deletions(-) rename cpu/x86/drivers/{ => legacy_pc}/pic.c (98%) rename cpu/x86/drivers/{ => legacy_pc}/pic.h (100%) rename cpu/x86/drivers/{ => legacy_pc}/pit.c (97%) rename cpu/x86/drivers/{ => legacy_pc}/pit.h (100%) rename cpu/x86/drivers/{ => legacy_pc}/rtc.c (97%) rename cpu/x86/drivers/{ => legacy_pc}/rtc.h (100%) diff --git a/cpu/x86/Makefile.x86 b/cpu/x86/Makefile.x86 index d5772d973..4cb49df37 100644 --- a/cpu/x86/Makefile.x86 +++ b/cpu/x86/Makefile.x86 @@ -1,4 +1,4 @@ -CONTIKI_CPU_DIRS = . drivers +CONTIKI_CPU_DIRS = . drivers/legacy_pc CONTIKI_SOURCEFILES += gdt.c helpers.S idt.c cpu.c rtc.c pit.c pic.c diff --git a/cpu/x86/drivers/pic.c b/cpu/x86/drivers/legacy_pc/pic.c similarity index 98% rename from cpu/x86/drivers/pic.c rename to cpu/x86/drivers/legacy_pc/pic.c index 12b79e39b..1acb351d1 100644 --- a/cpu/x86/drivers/pic.c +++ b/cpu/x86/drivers/legacy_pc/pic.c @@ -28,7 +28,7 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "drivers/pic.h" +#include "drivers/legacy_pc/pic.h" #define PIC_ACK 0x20 diff --git a/cpu/x86/drivers/pic.h b/cpu/x86/drivers/legacy_pc/pic.h similarity index 100% rename from cpu/x86/drivers/pic.h rename to cpu/x86/drivers/legacy_pc/pic.h diff --git a/cpu/x86/drivers/pit.c b/cpu/x86/drivers/legacy_pc/pit.c similarity index 97% rename from cpu/x86/drivers/pit.c rename to cpu/x86/drivers/legacy_pc/pit.c index 557b27985..3d7b2816d 100644 --- a/cpu/x86/drivers/pit.c +++ b/cpu/x86/drivers/legacy_pc/pit.c @@ -30,8 +30,8 @@ #include -#include "drivers/pic.h" -#include "pit.h" +#include "drivers/legacy_pc/pic.h" +#include "drivers/legacy_pc/pit.h" #include "helpers.h" #include "interrupt.h" diff --git a/cpu/x86/drivers/pit.h b/cpu/x86/drivers/legacy_pc/pit.h similarity index 100% rename from cpu/x86/drivers/pit.h rename to cpu/x86/drivers/legacy_pc/pit.h diff --git a/cpu/x86/drivers/rtc.c b/cpu/x86/drivers/legacy_pc/rtc.c similarity index 97% rename from cpu/x86/drivers/rtc.c rename to cpu/x86/drivers/legacy_pc/rtc.c index ad9eec221..7ba6dccc3 100644 --- a/cpu/x86/drivers/rtc.c +++ b/cpu/x86/drivers/legacy_pc/rtc.c @@ -28,8 +28,8 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "drivers/rtc.h" -#include "drivers/pic.h" +#include "drivers/legacy_pc/rtc.h" +#include "drivers/legacy_pc/pic.h" #include "helpers.h" #include "interrupt.h" diff --git a/cpu/x86/drivers/rtc.h b/cpu/x86/drivers/legacy_pc/rtc.h similarity index 100% rename from cpu/x86/drivers/rtc.h rename to cpu/x86/drivers/legacy_pc/rtc.h diff --git a/platform/galileo/core/sys/clock.c b/platform/galileo/core/sys/clock.c index d81ba835f..e84ef20eb 100644 --- a/platform/galileo/core/sys/clock.c +++ b/platform/galileo/core/sys/clock.c @@ -32,7 +32,7 @@ #include "sys/etimer.h" #include "contiki-conf.h" -#include "drivers/rtc.h" +#include "drivers/legacy_pc/rtc.h" #if CLOCK_CONF_SECOND == 2 #define FREQ RTC_2_HZ diff --git a/platform/galileo/core/sys/rtimer-arch.c b/platform/galileo/core/sys/rtimer-arch.c index 862c26692..71c4f13f5 100644 --- a/platform/galileo/core/sys/rtimer-arch.c +++ b/platform/galileo/core/sys/rtimer-arch.c @@ -31,7 +31,7 @@ #include "sys/rtimer.h" #include "contiki-conf.h" -#include "drivers/pit.h" +#include "drivers/legacy_pc/pit.h" static volatile rtimer_clock_t tick_count = 0; static rtimer_clock_t trigger = UINT64_MAX; From b2fa72bb98ccb1a6dd71bc5c60e1b6e7248dd4d8 Mon Sep 17 00:00:00 2001 From: Jesus Sanchez-Palencia Date: Wed, 29 Apr 2015 14:58:29 -0300 Subject: [PATCH 32/92] x86: Break Makefile.x86 into common and pc specific ones Now the cpu/x86/ provides a Makefile.x86_common and a Makefile.x86_pc. The former includes the common Makefile and adds legacy pc specific implementations (currently, drivers only) into the building context, while the latter has everything that defines the bootstrap of a x86 CPU. This commit also fixes platform/galileo/ so it includes the correct makefile - Makefile.x86_quarkX1000. Galileo uses a Quark X1000 SoC which is not an IBM Generic PC-like CPU, but it does provide most of a PCs peripherals through its "Legacy Bridge". Thus, it makes sense that QuarkX1000's Makefile includes code from the legacy_pc x86 cpu. --- cpu/x86/{Makefile.x86 => Makefile.x86_common} | 6 +++--- cpu/x86/Makefile.x86_quarkX1000 | 5 +++++ platform/galileo/Makefile.galileo | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) rename cpu/x86/{Makefile.x86 => Makefile.x86_common} (81%) create mode 100644 cpu/x86/Makefile.x86_quarkX1000 diff --git a/cpu/x86/Makefile.x86 b/cpu/x86/Makefile.x86_common similarity index 81% rename from cpu/x86/Makefile.x86 rename to cpu/x86/Makefile.x86_common index 4cb49df37..ca14d0c96 100644 --- a/cpu/x86/Makefile.x86 +++ b/cpu/x86/Makefile.x86_common @@ -1,14 +1,14 @@ -CONTIKI_CPU_DIRS = . drivers/legacy_pc +CONTIKI_CPU_DIRS += . -CONTIKI_SOURCEFILES += gdt.c helpers.S idt.c cpu.c rtc.c pit.c pic.c +CONTIKI_SOURCEFILES += gdt.c helpers.S idt.c cpu.c -### Compiler definitions CC = gcc LD = gcc AS = as OBJCOPY = objcopy SIZE = size STRIP = strip + CFLAGSNO = -Wall -g -I/usr/local/include CFLAGS += $(CFLAGSNO) ifeq ($(HOST_OS),Linux) diff --git a/cpu/x86/Makefile.x86_quarkX1000 b/cpu/x86/Makefile.x86_quarkX1000 new file mode 100644 index 000000000..01f206d66 --- /dev/null +++ b/cpu/x86/Makefile.x86_quarkX1000 @@ -0,0 +1,5 @@ +include $(CONTIKI)/cpu/x86/Makefile.x86_common + +CONTIKI_CPU_DIRS += drivers/legacy_pc + +CONTIKI_SOURCEFILES += rtc.c pit.c pic.c diff --git a/platform/galileo/Makefile.galileo b/platform/galileo/Makefile.galileo index 15f693401..9d186f8c5 100644 --- a/platform/galileo/Makefile.galileo +++ b/platform/galileo/Makefile.galileo @@ -8,7 +8,7 @@ CONTIKI_SOURCEFILES += contiki-main.c newlib-syscalls.c loader.S clock.c rtimer- LINKERSCRIPT = $(CONTIKI)/platform/galileo/galileo.ld CONTIKI_CPU=$(CONTIKI)/cpu/x86 -include $(CONTIKI)/cpu/x86/Makefile.x86 +include $(CONTIKI)/cpu/x86/Makefile.x86_quarkX1000 CFLAGS += -m32 -march=i586 -nostdinc -isystem $(LIBC)/include -isystem $(LIBGCC_PATH)/include -isystem $(LIBGCC_PATH)/include-fixed LDFLAGS += -m32 -nostdlib -T $(LINKERSCRIPT) From e4bc1a1e8ccaaa60017788cb1f42898fde3ac5c6 Mon Sep 17 00:00:00 2001 From: Jesus Sanchez-Palencia Date: Thu, 2 Jul 2015 20:13:53 -0300 Subject: [PATCH 33/92] x86: Add init folder and move code accordingly The x86/init/common/ folder holds all cpu initialization code - idt and gdt setup, interrupts and cpu initialization. On this folder will also sit any SoC specific implementation of the functions called from cpu_init(). --- cpu/x86/Makefile.x86_common | 2 +- cpu/x86/{ => init/common}/cpu.c | 0 cpu/x86/{ => init/common}/cpu.h | 0 cpu/x86/{ => init/common}/gdt.c | 0 cpu/x86/{ => init/common}/gdt.h | 0 cpu/x86/{ => init/common}/idt.c | 0 cpu/x86/{ => init/common}/idt.h | 0 cpu/x86/{ => init/common}/interrupt.h | 0 8 files changed, 1 insertion(+), 1 deletion(-) rename cpu/x86/{ => init/common}/cpu.c (100%) rename cpu/x86/{ => init/common}/cpu.h (100%) rename cpu/x86/{ => init/common}/gdt.c (100%) rename cpu/x86/{ => init/common}/gdt.h (100%) rename cpu/x86/{ => init/common}/idt.c (100%) rename cpu/x86/{ => init/common}/idt.h (100%) rename cpu/x86/{ => init/common}/interrupt.h (100%) diff --git a/cpu/x86/Makefile.x86_common b/cpu/x86/Makefile.x86_common index ca14d0c96..b5ea26271 100644 --- a/cpu/x86/Makefile.x86_common +++ b/cpu/x86/Makefile.x86_common @@ -1,4 +1,4 @@ -CONTIKI_CPU_DIRS += . +CONTIKI_CPU_DIRS += . init/common CONTIKI_SOURCEFILES += gdt.c helpers.S idt.c cpu.c diff --git a/cpu/x86/cpu.c b/cpu/x86/init/common/cpu.c similarity index 100% rename from cpu/x86/cpu.c rename to cpu/x86/init/common/cpu.c diff --git a/cpu/x86/cpu.h b/cpu/x86/init/common/cpu.h similarity index 100% rename from cpu/x86/cpu.h rename to cpu/x86/init/common/cpu.h diff --git a/cpu/x86/gdt.c b/cpu/x86/init/common/gdt.c similarity index 100% rename from cpu/x86/gdt.c rename to cpu/x86/init/common/gdt.c diff --git a/cpu/x86/gdt.h b/cpu/x86/init/common/gdt.h similarity index 100% rename from cpu/x86/gdt.h rename to cpu/x86/init/common/gdt.h diff --git a/cpu/x86/idt.c b/cpu/x86/init/common/idt.c similarity index 100% rename from cpu/x86/idt.c rename to cpu/x86/init/common/idt.c diff --git a/cpu/x86/idt.h b/cpu/x86/init/common/idt.h similarity index 100% rename from cpu/x86/idt.h rename to cpu/x86/init/common/idt.h diff --git a/cpu/x86/interrupt.h b/cpu/x86/init/common/interrupt.h similarity index 100% rename from cpu/x86/interrupt.h rename to cpu/x86/init/common/interrupt.h From 80fe1de0b1ab6ccd47c3787bef52fa9c24b1c3ee Mon Sep 17 00:00:00 2001 From: Jesus Sanchez-Palencia Date: Fri, 8 May 2015 09:34:32 -0300 Subject: [PATCH 34/92] x86: Isolate SoC specific cpu_init code This commit turns cpu_init() into a SoC-agnostic function by removing any SoC specific calls and isolating them into their own SoC implementation. We start this by isolating all IRQs initialization code from the legacy-pc target, pic_init() and spurious IRQ7 registration, into a new interface: irq_init() from irq.h. Future SoCs will have to provide their own implementation of this interface. This model is to be followed by future initialization code that we may need to add and which is not common to all x86 SoCs. --- cpu/x86/Makefile.x86_quarkX1000 | 4 +-- cpu/x86/init/common/cpu.c | 25 ++------------ cpu/x86/init/common/irq.h | 36 ++++++++++++++++++++ cpu/x86/init/legacy_pc/irq.c | 60 +++++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+), 25 deletions(-) create mode 100644 cpu/x86/init/common/irq.h create mode 100644 cpu/x86/init/legacy_pc/irq.c diff --git a/cpu/x86/Makefile.x86_quarkX1000 b/cpu/x86/Makefile.x86_quarkX1000 index 01f206d66..b48b4a90f 100644 --- a/cpu/x86/Makefile.x86_quarkX1000 +++ b/cpu/x86/Makefile.x86_quarkX1000 @@ -1,5 +1,5 @@ include $(CONTIKI)/cpu/x86/Makefile.x86_common -CONTIKI_CPU_DIRS += drivers/legacy_pc +CONTIKI_CPU_DIRS += drivers/legacy_pc init/legacy_pc -CONTIKI_SOURCEFILES += rtc.c pit.c pic.c +CONTIKI_SOURCEFILES += rtc.c pit.c pic.c irq.c diff --git a/cpu/x86/init/common/cpu.c b/cpu/x86/init/common/cpu.c index 77e8f8026..a174853cc 100644 --- a/cpu/x86/init/common/cpu.c +++ b/cpu/x86/init/common/cpu.c @@ -32,9 +32,7 @@ #include "helpers.h" #include "idt.h" #include "interrupt.h" -#include "pic.h" - -#define IRQ7_INT PIC_INT(7) +#include "irq.h" static void double_fault_handler(struct interrupt_context context) @@ -42,20 +40,6 @@ double_fault_handler(struct interrupt_context context) halt(); } /*---------------------------------------------------------------------------*/ -static void -spurious_irq7_handler(void) -{ - /* - * NOTE: Originally IRQ7 was used for the parallel port interrupts. Nowadays, - * though, it is only used if some other IRQ (i.e.: a PCIx interrupt) is - * mapped to it. In this case we will have to check the PIC ISR register in - * order to confirm this was a real interrupt. - * - * In case of a spurious interrupt, we should NEVER send an EOI here so the PIC - * doesn't trigger the next queued interrupt. - */ -} -/*---------------------------------------------------------------------------*/ void cpu_init(void) { @@ -67,10 +51,5 @@ cpu_init(void) */ SET_INTERRUPT_HANDLER(8, 1, double_fault_handler); - pic_init(); - - /* Set a 'fake' handler for the Spurious IRQ7 interrupts. - * Refer to http://wiki.osdev.org/PIC . - */ - SET_INTERRUPT_HANDLER(IRQ7_INT, 0, spurious_irq7_handler); + irq_init(); } diff --git a/cpu/x86/init/common/irq.h b/cpu/x86/init/common/irq.h new file mode 100644 index 000000000..94af19b74 --- /dev/null +++ b/cpu/x86/init/common/irq.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IRQ_H +#define IRQ_H + +void irq_init(void); + +#endif /* IRQ_H */ diff --git a/cpu/x86/init/legacy_pc/irq.c b/cpu/x86/init/legacy_pc/irq.c new file mode 100644 index 000000000..04cfa1c13 --- /dev/null +++ b/cpu/x86/init/legacy_pc/irq.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "drivers/legacy_pc/pic.h" +#include "interrupt.h" +#include "irq.h" + +#define IRQ7_INT PIC_INT(7) + +static void +spurious_irq7_handler(void) +{ + /* + * NOTE: Originally IRQ7 was used for the parallel port interrupts. Nowadays, + * though, it is only used if some other IRQ (i.e.: a PCIx interrupt) is + * mapped to it. In this case we will have to check the PIC ISR register in + * order to confirm this was a real interrupt. + * + * In case of a spurious interrupt, we should NEVER send an EOI here so the PIC + * doesn't trigger the next queued interrupt. + */ +} +/*---------------------------------------------------------------------------*/ +void +irq_init(void) +{ + pic_init(); + + /* Set a 'fake' handler for the Spurious IRQ7 interrupts. + * Refer to http://wiki.osdev.org/PIC . + */ + SET_INTERRUPT_HANDLER(IRQ7_INT, 0, spurious_irq7_handler); +} From a8849b290972fe895e6dd368b770c5475db87d6d Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Thu, 7 May 2015 19:20:14 -0300 Subject: [PATCH 35/92] x86: Move bootstrap code and linker script to cpu/x86 This is a refactoring patch, no functionality is changed. It moves loader.S and galileo.ld from platform/galileo/ to cpu/x86/ directory since they seem to be more SoC-specific than platform-specific. It also renames galileo.ld to quarkX1000.ld since it can be used by any platform based on Quark X1000 SoC, not only Galileo. Furthermore, this patch also renames loader.S to bootstrap_quarkX1000.S since it is pretty much a bootstrap code to any platform based on Quark X1000 SoC. --- cpu/x86/Makefile.x86_quarkX1000 | 4 +++- platform/galileo/loader.S => cpu/x86/bootstrap_quarkX1000.S | 0 platform/galileo/galileo.ld => cpu/x86/quarkX1000.ld | 0 platform/galileo/Makefile.galileo | 4 +--- 4 files changed, 4 insertions(+), 4 deletions(-) rename platform/galileo/loader.S => cpu/x86/bootstrap_quarkX1000.S (100%) rename platform/galileo/galileo.ld => cpu/x86/quarkX1000.ld (100%) diff --git a/cpu/x86/Makefile.x86_quarkX1000 b/cpu/x86/Makefile.x86_quarkX1000 index b48b4a90f..b7b6966b3 100644 --- a/cpu/x86/Makefile.x86_quarkX1000 +++ b/cpu/x86/Makefile.x86_quarkX1000 @@ -2,4 +2,6 @@ include $(CONTIKI)/cpu/x86/Makefile.x86_common CONTIKI_CPU_DIRS += drivers/legacy_pc init/legacy_pc -CONTIKI_SOURCEFILES += rtc.c pit.c pic.c irq.c +CONTIKI_SOURCEFILES += bootstrap_quarkX1000.S rtc.c pit.c pic.c irq.c + +LINKERSCRIPT = $(CONTIKI)/cpu/x86/quarkX1000.ld diff --git a/platform/galileo/loader.S b/cpu/x86/bootstrap_quarkX1000.S similarity index 100% rename from platform/galileo/loader.S rename to cpu/x86/bootstrap_quarkX1000.S diff --git a/platform/galileo/galileo.ld b/cpu/x86/quarkX1000.ld similarity index 100% rename from platform/galileo/galileo.ld rename to cpu/x86/quarkX1000.ld diff --git a/platform/galileo/Makefile.galileo b/platform/galileo/Makefile.galileo index 9d186f8c5..7dce1a5c8 100644 --- a/platform/galileo/Makefile.galileo +++ b/platform/galileo/Makefile.galileo @@ -3,9 +3,7 @@ LIBGCC_PATH = /usr/lib/gcc/$(shell gcc -dumpmachine)/$(shell gcc -dumpversion) CONTIKI_TARGET_DIRS = . core/sys/ CONTIKI_TARGET_MAIN = ${addprefix $(OBJECTDIR)/,contiki-main.o} -CONTIKI_SOURCEFILES += contiki-main.c newlib-syscalls.c loader.S clock.c rtimer-arch.c - -LINKERSCRIPT = $(CONTIKI)/platform/galileo/galileo.ld +CONTIKI_SOURCEFILES += contiki-main.c newlib-syscalls.c clock.c rtimer-arch.c CONTIKI_CPU=$(CONTIKI)/cpu/x86 include $(CONTIKI)/cpu/x86/Makefile.x86_quarkX1000 From cb0510ebcfb6fae05628ef94027f2f2c744498aa Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 6 May 2015 15:24:43 -0300 Subject: [PATCH 36/92] x86: Disable NMI while initializing RTC According to [1], we should disable non-maskable and maskable interrupts while initializing RTC. Otherwise, the RTC may be left in an undefined state (non-functional) if an interrupt occurs. Currently, maskable interrupts are already disabled, but NMI is not. This patch adds helpers APIs to enable/disable non-maskable interrupts (NMI) and changes rtc_init() to disable NMI while initializing the RTC. NMI enable/disable code is legacy-PC specific therefore it was put in driver/legacy_pc/ directory. Regarding the RTC initialization changes, just calling nmi_disable() and nmi_enable is not enough since NMI and RTC share the same IO port. So We should also set the NMI_ENABLE bit while selecting the RTC_INDEX. Additionally, the nmi_disable() call is not strictly required since we set the NMI_ENABLE bit while selecting the RTC_INDEX. However, to make clear hat we are disabling NMI and to improve readability (by matching NMI disable/enable), the nmi_disable() call was purposely used. [1] http://wiki.osdev.org/RTC --- cpu/x86/Makefile.x86_quarkX1000 | 2 +- cpu/x86/drivers/legacy_pc/nmi.c | 47 +++++++++++++++++++++++++++++++++ cpu/x86/drivers/legacy_pc/nmi.h | 38 ++++++++++++++++++++++++++ cpu/x86/drivers/legacy_pc/rtc.c | 13 ++++++--- 4 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 cpu/x86/drivers/legacy_pc/nmi.c create mode 100644 cpu/x86/drivers/legacy_pc/nmi.h diff --git a/cpu/x86/Makefile.x86_quarkX1000 b/cpu/x86/Makefile.x86_quarkX1000 index b7b6966b3..630d33804 100644 --- a/cpu/x86/Makefile.x86_quarkX1000 +++ b/cpu/x86/Makefile.x86_quarkX1000 @@ -2,6 +2,6 @@ include $(CONTIKI)/cpu/x86/Makefile.x86_common CONTIKI_CPU_DIRS += drivers/legacy_pc init/legacy_pc -CONTIKI_SOURCEFILES += bootstrap_quarkX1000.S rtc.c pit.c pic.c irq.c +CONTIKI_SOURCEFILES += bootstrap_quarkX1000.S rtc.c pit.c pic.c irq.c nmi.c LINKERSCRIPT = $(CONTIKI)/cpu/x86/quarkX1000.ld diff --git a/cpu/x86/drivers/legacy_pc/nmi.c b/cpu/x86/drivers/legacy_pc/nmi.c new file mode 100644 index 000000000..e57d93325 --- /dev/null +++ b/cpu/x86/drivers/legacy_pc/nmi.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "helpers.h" + +#define NMI_ENABLE_PORT 0x70 + +void +nmi_enable(void) +{ + uint8_t value = inb(NMI_ENABLE_PORT); + outb(NMI_ENABLE_PORT, value & ~BIT(8)); +} +/*---------------------------------------------------------------------------*/ +void +nmi_disable(void) +{ + uint8_t value = inb(NMI_ENABLE_PORT); + outb(NMI_ENABLE_PORT, value | BIT(8)); +} diff --git a/cpu/x86/drivers/legacy_pc/nmi.h b/cpu/x86/drivers/legacy_pc/nmi.h new file mode 100644 index 000000000..3b5544cf0 --- /dev/null +++ b/cpu/x86/drivers/legacy_pc/nmi.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef NMI_H +#define NMI_H + +void nmi_enable(void); + +void nmi_disable(void); + +#endif /* NMI_H */ diff --git a/cpu/x86/drivers/legacy_pc/rtc.c b/cpu/x86/drivers/legacy_pc/rtc.c index 7ba6dccc3..cf059315b 100644 --- a/cpu/x86/drivers/legacy_pc/rtc.c +++ b/cpu/x86/drivers/legacy_pc/rtc.c @@ -30,6 +30,7 @@ #include "drivers/legacy_pc/rtc.h" #include "drivers/legacy_pc/pic.h" +#include "drivers/legacy_pc/nmi.h" #include "helpers.h" #include "interrupt.h" @@ -72,19 +73,23 @@ rtc_init(rtc_frequency_t frequency, void (*callback)(void)) SET_INTERRUPT_HANDLER(RTC_INT, 0, rtc_handler); + nmi_disable(); + /* Select interrupt period to 7.8125 ms */ - outb(RTC_INDEX_REGISTER, 0x0A); + outb(RTC_INDEX_REGISTER, 0x8A); reg_a = inb(RTC_TARGET_REGISTER); reg_a &= 0xF0; reg_a |= frequency; - outb(RTC_INDEX_REGISTER, 0x0A); + outb(RTC_INDEX_REGISTER, 0x8A); outb(RTC_TARGET_REGISTER, reg_a); /* Enable periodic interrupt */ - outb(RTC_INDEX_REGISTER, 0x0B); + outb(RTC_INDEX_REGISTER, 0x8B); reg_b = inb(RTC_TARGET_REGISTER); - outb(RTC_INDEX_REGISTER, 0x0B); + outb(RTC_INDEX_REGISTER, 0x8B); outb(RTC_TARGET_REGISTER, reg_b | BIT(6)); + nmi_enable(); + pic_unmask_irq(RTC_IRQ); } From 13bbe8a5b5ab6041ed5dca83b42631b8416b74c5 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 8 May 2015 16:15:42 -0300 Subject: [PATCH 37/92] x86: Don't generate .note.gnu.build-id section This patch adds "--build-id=none" to default LDFLAGS so .note.gnu.build-id section is not generated. This section contains unique identification for the built files what is not important to us (at least at this moment). This change simplifies all linker scripts for SoCs based on x86 (at this moment we only have Quark X1000) since we don't have to care about it anymore. --- cpu/x86/Makefile.x86_common | 2 +- cpu/x86/quarkX1000.ld | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/cpu/x86/Makefile.x86_common b/cpu/x86/Makefile.x86_common index b5ea26271..b7590ff40 100644 --- a/cpu/x86/Makefile.x86_common +++ b/cpu/x86/Makefile.x86_common @@ -12,7 +12,7 @@ STRIP = strip CFLAGSNO = -Wall -g -I/usr/local/include CFLAGS += $(CFLAGSNO) ifeq ($(HOST_OS),Linux) - LDFLAGS = -Wl,-Map=contiki-$(TARGET).map,-export-dynamic + LDFLAGS = -Wl,-Map=contiki-$(TARGET).map,-export-dynamic,--build-id=none else LDFLAGS = -Wl endif diff --git a/cpu/x86/quarkX1000.ld b/cpu/x86/quarkX1000.ld index e703b9f1d..b4a3afa44 100644 --- a/cpu/x86/quarkX1000.ld +++ b/cpu/x86/quarkX1000.ld @@ -60,10 +60,4 @@ SECTIONS { *(COMMON) *(.bss) } - - /* Put this here so it doesn't sit above the multiboot section. */ - .note.gnu.build-id : - { - *(.note.gnu.build-id) - } } From b79fcaa7d8875f33861b640c6f3424236e4b0f69 Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Thu, 2 Jul 2015 19:14:04 -0700 Subject: [PATCH 38/92] galileo: Override Ubuntu's default GCC flags to avoid link errors Ubuntu enables GCC's stack protector by default (see https://wiki.ubuntu.com/Security/Features). This causes link errors like the following: ...undefined reference to `__stack_chk_fail' To avoid these errors, this patch adds the "-fno-stack-protector" flag to both the CFLAGS used by the Contiki build process and the CFLAGS used by the newlib build process. --- platform/galileo/Makefile.galileo | 2 +- platform/galileo/bsp/libc/build_newlib.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/galileo/Makefile.galileo b/platform/galileo/Makefile.galileo index 7dce1a5c8..05a2b7280 100644 --- a/platform/galileo/Makefile.galileo +++ b/platform/galileo/Makefile.galileo @@ -8,7 +8,7 @@ CONTIKI_SOURCEFILES += contiki-main.c newlib-syscalls.c clock.c rtimer-arch.c CONTIKI_CPU=$(CONTIKI)/cpu/x86 include $(CONTIKI)/cpu/x86/Makefile.x86_quarkX1000 -CFLAGS += -m32 -march=i586 -nostdinc -isystem $(LIBC)/include -isystem $(LIBGCC_PATH)/include -isystem $(LIBGCC_PATH)/include-fixed +CFLAGS += -m32 -march=i586 -fno-stack-protector -nostdinc -isystem $(LIBC)/include -isystem $(LIBGCC_PATH)/include -isystem $(LIBGCC_PATH)/include-fixed LDFLAGS += -m32 -nostdlib -T $(LINKERSCRIPT) ASFLAGS += --32 -march=i586 -mtune=i586 diff --git a/platform/galileo/bsp/libc/build_newlib.sh b/platform/galileo/bsp/libc/build_newlib.sh index a187a7838..baf2cab93 100755 --- a/platform/galileo/bsp/libc/build_newlib.sh +++ b/platform/galileo/bsp/libc/build_newlib.sh @@ -57,8 +57,8 @@ build() { export COMPILER_AS_FOR_TARGET=as export COMPILER_LD_FOR_TARGET=ld export COMPILER_NM_FOR_TARGET=nm - export CFLAGS_FOR_TARGET="-Os -m32 -march=i586 -mtune=i586 -DPREFER_SIZE_OVER_SPEED" - export CXXFLAGS_FOR_TARGET="-Os -m32 -march=i586 -mtune=i586 -DPREFER_SIZE_OVER_SPEED" + export CFLAGS_FOR_TARGET="-Os -m32 -march=i586 -mtune=i586 -fno-stack-protector -DPREFER_SIZE_OVER_SPEED" + export CXXFLAGS_FOR_TARGET="-Os -m32 -march=i586 -mtune=i586 -fno-stack-protector -DPREFER_SIZE_OVER_SPEED" mkdir -p install ./configure --target=${TARGET} \ From 2b5efdfbe75debc5e5a3d32bfeb3ddc9cf4d6893 Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Thu, 2 Jul 2015 19:21:26 -0700 Subject: [PATCH 39/92] galileo: Revise C compiler flags for consistency. The CFLAGS setting used for the newlib build process includes "-mtune=i586" as does the ASFLAGS setting used for the Contiki build process. However, the CFLAGS setting used for the Contiki build process did not include that flag. This patch adds it for consistency. --- platform/galileo/Makefile.galileo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/galileo/Makefile.galileo b/platform/galileo/Makefile.galileo index 05a2b7280..3fbe88e8f 100644 --- a/platform/galileo/Makefile.galileo +++ b/platform/galileo/Makefile.galileo @@ -8,7 +8,7 @@ CONTIKI_SOURCEFILES += contiki-main.c newlib-syscalls.c clock.c rtimer-arch.c CONTIKI_CPU=$(CONTIKI)/cpu/x86 include $(CONTIKI)/cpu/x86/Makefile.x86_quarkX1000 -CFLAGS += -m32 -march=i586 -fno-stack-protector -nostdinc -isystem $(LIBC)/include -isystem $(LIBGCC_PATH)/include -isystem $(LIBGCC_PATH)/include-fixed +CFLAGS += -m32 -march=i586 -mtune=i586 -fno-stack-protector -nostdinc -isystem $(LIBC)/include -isystem $(LIBGCC_PATH)/include -isystem $(LIBGCC_PATH)/include-fixed LDFLAGS += -m32 -nostdlib -T $(LINKERSCRIPT) ASFLAGS += --32 -march=i586 -mtune=i586 From b697646b1170f2545bbc95627b9514dce09c8324 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Mon, 6 Jul 2015 18:39:18 -0300 Subject: [PATCH 40/92] x86: Cleanup Makefile.x86_common This patch does several cleanups in Makefile.x86_common file. The changes are described above. 1) The CFLAGNO variable was removed since it is used only to assign the CFLAGS variable. Also, CFLAGNO is not used outside Makefile.x86_ common. 2) The "-I/usr/local/include" option was removed since we provide manually the include path from newlib in the bsp/ directory. 3) We only support building x86-based platforms on Linux so there is no point in setting LDFLAGS conditionally. 4) The '-export-dynamic' option was removed from LDFLAGS since we are not creating a dynamically linked executable. 5) Makefile.x86_quarkX1000 is the only one that includes Makefile.x86_ common. Since it doesn't use the custom rules from Makefile.x86_ common we remove them. --- cpu/x86/Makefile.x86_common | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/cpu/x86/Makefile.x86_common b/cpu/x86/Makefile.x86_common index b7590ff40..206a02d4e 100644 --- a/cpu/x86/Makefile.x86_common +++ b/cpu/x86/Makefile.x86_common @@ -9,25 +9,5 @@ OBJCOPY = objcopy SIZE = size STRIP = strip -CFLAGSNO = -Wall -g -I/usr/local/include -CFLAGS += $(CFLAGSNO) -ifeq ($(HOST_OS),Linux) - LDFLAGS = -Wl,-Map=contiki-$(TARGET).map,-export-dynamic,--build-id=none -else - LDFLAGS = -Wl -endif - -### Compilation rules - -%.so: $(OBJECTDIR)/%.o - $(LD) -shared -o $@ $^ - -ifdef CORE -.PHONY: symbols.c symbols.h -symbols.c symbols.h: - $(NM) $(CORE) | awk -f $(CONTIKI)/tools/mknmlist > symbols.c -else -symbols.c symbols.h: - cp ${CONTIKI}/tools/empty-symbols.c symbols.c - cp ${CONTIKI}/tools/empty-symbols.h symbols.h -endif +CFLAGS += -Wall -g +LDFLAGS += -Wl,-Map=contiki-$(TARGET).map,--build-id=none From 96e50ec2c42cc9a07f2764cb8056a4ff93157800 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Mon, 6 Jul 2015 19:34:00 -0300 Subject: [PATCH 41/92] galileo: Fix Makefile.galileo This patch moves the compiler and linking options related to QuarkX1000 SoC to Makefile.x86_quarkX1000 since it is more suitable. For instance, '-m32' should be used in any platform based on QuarkX1000, not only Galileo. The same rationale applies for the others options (e.g. -march, mtune). --- cpu/x86/Makefile.x86_quarkX1000 | 4 +++- platform/galileo/Makefile.galileo | 5 ++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cpu/x86/Makefile.x86_quarkX1000 b/cpu/x86/Makefile.x86_quarkX1000 index 630d33804..d6a258453 100644 --- a/cpu/x86/Makefile.x86_quarkX1000 +++ b/cpu/x86/Makefile.x86_quarkX1000 @@ -4,4 +4,6 @@ CONTIKI_CPU_DIRS += drivers/legacy_pc init/legacy_pc CONTIKI_SOURCEFILES += bootstrap_quarkX1000.S rtc.c pit.c pic.c irq.c nmi.c -LINKERSCRIPT = $(CONTIKI)/cpu/x86/quarkX1000.ld +CFLAGS += -m32 -march=i586 -mtune=i586 +LDFLAGS += -m32 -T $(CONTIKI)/cpu/x86/quarkX1000.ld +ASFLAGS += --32 -march=i586 -mtune=i586 diff --git a/platform/galileo/Makefile.galileo b/platform/galileo/Makefile.galileo index 3fbe88e8f..fcff32cdd 100644 --- a/platform/galileo/Makefile.galileo +++ b/platform/galileo/Makefile.galileo @@ -8,9 +8,8 @@ CONTIKI_SOURCEFILES += contiki-main.c newlib-syscalls.c clock.c rtimer-arch.c CONTIKI_CPU=$(CONTIKI)/cpu/x86 include $(CONTIKI)/cpu/x86/Makefile.x86_quarkX1000 -CFLAGS += -m32 -march=i586 -mtune=i586 -fno-stack-protector -nostdinc -isystem $(LIBC)/include -isystem $(LIBGCC_PATH)/include -isystem $(LIBGCC_PATH)/include-fixed -LDFLAGS += -m32 -nostdlib -T $(LINKERSCRIPT) -ASFLAGS += --32 -march=i586 -mtune=i586 +CFLAGS += -fno-stack-protector -nostdinc -isystem $(LIBC)/include -isystem $(LIBGCC_PATH)/include -isystem $(LIBGCC_PATH)/include-fixed +LDFLAGS += -nostdlib # Ideally, this should be part of LDFLAGS (-lc -lm etc). However, we found out that archive # static files (.a) must be linked after our own object files, otherwise the linker gets lost From c8cdc0c157c860ee15d5b9911b2649e5fad132d9 Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Fri, 10 Jul 2015 13:41:24 -0700 Subject: [PATCH 42/92] galileo: Check for errors after downloading newlib tarball Repeat the file existence and MD5 checks in build_newlib.sh after the newlib tarball is downloaded and exit if either of the checks fail. --- platform/galileo/bsp/libc/build_newlib.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/platform/galileo/bsp/libc/build_newlib.sh b/platform/galileo/bsp/libc/build_newlib.sh index baf2cab93..a752c4ffb 100755 --- a/platform/galileo/bsp/libc/build_newlib.sh +++ b/platform/galileo/bsp/libc/build_newlib.sh @@ -16,6 +16,10 @@ prepare() { if [ ! -e ./${TARBALL} ] || [ "$(md5sum ./${TARBALL} | cut -d' ' -f1)" != $MD5 ]; then wget -c ftp://sources.redhat.com/pub/newlib/${TARBALL} fi + if [ ! -e ./${TARBALL} ] || [ "$(md5sum ./${TARBALL} | cut -d' ' -f1)" != $MD5 ]; then + echo "Error obtaining tarball." + exit 1 + fi # Clean up the previous source dir, if any. if [[ -d ./newlib-${VERSION} ]]; then From b2e47861876cad366dbe596888645d6409d0e638 Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Fri, 10 Jul 2015 13:51:53 -0700 Subject: [PATCH 43/92] galileo: Stylistic changes to make build_newlib.sh less repetitive This script defines new variables to represent common paths and filenames. It does not introduce any functional changes. --- platform/galileo/bsp/libc/build_newlib.sh | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/platform/galileo/bsp/libc/build_newlib.sh b/platform/galileo/bsp/libc/build_newlib.sh index a752c4ffb..8456c76c2 100755 --- a/platform/galileo/bsp/libc/build_newlib.sh +++ b/platform/galileo/bsp/libc/build_newlib.sh @@ -4,7 +4,11 @@ JOBS=5 TARGET=i586-elf VERSION=2.2.0-1 MD5=94114fdc1d8391cdbc2653d89249cccf -TARBALL=newlib-${VERSION}.tar.gz +PKG_NAME=newlib +SRC_DIR=${PKG_NAME}-${VERSION} +PATCH_DIR=../patches +TARBALL=${SRC_DIR}.tar.gz +DIST_SITE=ftp://sources.redhat.com/pub/newlib SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) @@ -14,7 +18,7 @@ pushd ${SCRIPT_DIR} prepare() { # If the source tarball doesn't exist of its md5 checksum doesn't match, download it. if [ ! -e ./${TARBALL} ] || [ "$(md5sum ./${TARBALL} | cut -d' ' -f1)" != $MD5 ]; then - wget -c ftp://sources.redhat.com/pub/newlib/${TARBALL} + wget -c ${DIST_SITE}/${TARBALL} fi if [ ! -e ./${TARBALL} ] || [ "$(md5sum ./${TARBALL} | cut -d' ' -f1)" != $MD5 ]; then echo "Error obtaining tarball." @@ -22,8 +26,8 @@ prepare() { fi # Clean up the previous source dir, if any. - if [[ -d ./newlib-${VERSION} ]]; then - rm -rf ./newlib-${VERSION} + if [[ -d ./${SRC_DIR} ]]; then + rm -rf ./${SRC_DIR} fi # Clean up the previous install dir, if any. @@ -32,9 +36,9 @@ prepare() { fi tar xf ${TARBALL} - cd newlib-${VERSION} + cd ${SRC_DIR} - for i in `ls ../patches/`; do patch -p0 < ../patches/${i}; done + for i in `ls ${PATCH_DIR}`; do patch -p0 < ${PATCH_DIR}/${i}; done } @@ -84,11 +88,11 @@ build() { } setup() { - cp -r ./newlib-${VERSION}/install/${TARGET} . + cp -r ./${SRC_DIR}/install/${TARGET} . } cleanup() { - rm -rf ./newlib-${VERSION}* + rm -rf ./${SRC_DIR}* } From 9b6b5ce5b01528c0e4e7e3ae138db693a2948840 Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Fri, 10 Jul 2015 14:07:07 -0700 Subject: [PATCH 44/92] galileo: Instruct developer to build C library prior to building Contiki This patch enhances build_newlib.sh to create Makefile.libc so that the main Galileo makefile can attempt to include Makefile.libc and instruct the developer to run build_newlib.sh first if the definition within Makefile.libc is not detected. --- platform/galileo/Makefile.galileo | 10 +++++++++- platform/galileo/bsp/libc/build_newlib.sh | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/platform/galileo/Makefile.galileo b/platform/galileo/Makefile.galileo index fcff32cdd..662042e56 100644 --- a/platform/galileo/Makefile.galileo +++ b/platform/galileo/Makefile.galileo @@ -1,4 +1,6 @@ -LIBC=$(CONTIKI)/platform/galileo/bsp/libc/i586-elf +BSP_PATH=$(CONTIKI)/platform/galileo/bsp +LIBC_PATH=$(BSP_PATH)/libc +LIBC=$(LIBC_PATH)/i586-elf LIBGCC_PATH = /usr/lib/gcc/$(shell gcc -dumpmachine)/$(shell gcc -dumpversion) CONTIKI_TARGET_DIRS = . core/sys/ @@ -11,6 +13,12 @@ include $(CONTIKI)/cpu/x86/Makefile.x86_quarkX1000 CFLAGS += -fno-stack-protector -nostdinc -isystem $(LIBC)/include -isystem $(LIBGCC_PATH)/include -isystem $(LIBGCC_PATH)/include-fixed LDFLAGS += -nostdlib +-include $(LIBC_PATH)/Makefile.libc + +ifndef BUILT_LIBC + $(error Build the C library by executing $(LIBC_PATH)/build_newlib.sh) +endif + # Ideally, this should be part of LDFLAGS (-lc -lm etc). However, we found out that archive # static files (.a) must be linked after our own object files, otherwise the linker gets lost # and we get undefined references only. diff --git a/platform/galileo/bsp/libc/build_newlib.sh b/platform/galileo/bsp/libc/build_newlib.sh index 8456c76c2..a48cb2e4c 100755 --- a/platform/galileo/bsp/libc/build_newlib.sh +++ b/platform/galileo/bsp/libc/build_newlib.sh @@ -85,6 +85,8 @@ build() { make -j${JOBS} all && make install cd .. + + echo "BUILT_LIBC = newlib" > Makefile.libc } setup() { From 62fc195d0f21b103a700e0b5bcd9a1b12bca9423 Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Sat, 11 Jul 2015 15:53:10 -0700 Subject: [PATCH 45/92] x86: Refactor GDT initialization code This patch refactors the GDT initialization code in more of a self-documenting style. --- cpu/x86/init/common/gdt.c | 44 +++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/cpu/x86/init/common/gdt.c b/cpu/x86/init/common/gdt.c index 1ba38a724..39a8a7ce4 100644 --- a/cpu/x86/init/common/gdt.c +++ b/cpu/x86/init/common/gdt.c @@ -32,6 +32,20 @@ #define NUM_DESC 3 +#define GDT_IDX_NULL 0 +#define GDT_IDX_CODE 1 +#define GDT_IDX_DATA 2 + +/* All code in the x86 port of Contiki runs at ring (privilege) level 0 */ +#define PRIV_LVL 0 + +/* Compute GDT selector from descriptor index and requested privilege level */ +#define GDT_SEL(IDX, RPL) (((IDX) << 3) | (RPL)) + +#define GDT_SEL_NULL GDT_SEL(GDT_IDX_NULL, 0) +#define GDT_SEL_CODE GDT_SEL(GDT_IDX_CODE, PRIV_LVL) +#define GDT_SEL_DATA GDT_SEL(GDT_IDX_DATA, PRIV_LVL) + /* Each define here is for a specific flag in the descriptor. Refer to Intel * Combined Manual (Intel 64 and IA-32 Architectures Software Developer's * Manual), Vol. 3, Section 3.4.5 for a description of each flag. @@ -110,27 +124,25 @@ gdt_init(void) gdtr.base = (uint32_t) &gdt; /* Initialize descriptors */ - set_descriptor(0, 0, 0, 0); - set_descriptor(1, 0, 0x0FFFFF, GDT_CODE_PL0); - set_descriptor(2, 0, 0x0FFFFF, GDT_DATA_PL0); + set_descriptor(GDT_IDX_NULL, 0, 0, 0); + set_descriptor(GDT_IDX_CODE, 0, 0x0FFFFF, GDT_CODE_PL0); + set_descriptor(GDT_IDX_DATA, 0, 0x0FFFFF, GDT_DATA_PL0); /* Load GDTR register and update segment registers. * - * In protected mode, segment registers should be loaded according to - * the offset in GDT. So DS, SS, ES, FS and GS registers should be - * loadded with 0x10 while CS with 0x08. CS register cannot be changed - * directly. For that reason, we do a far jump. + * CS register cannot be changed directly. For that reason, we do a far jump. */ - __asm__ ("lgdt %0\n\t" - "jmp $0x08, $1f\n\t" + __asm__ ("lgdt %[_gdtr_]\n\t" + "jmp %[_cs_], $1f\n\t" "1:\n\t" - "mov $0x10, %%ax\n\t" - "mov %%ax, %%ds\n\t" - "mov %%ax, %%ss\n\t" - "mov %%ax, %%es\n\t" - "mov %%ax, %%fs\n\t" - "mov %%ax, %%gs\n\t" + "mov %[_ds_], %%ds\n\t" + "mov %[_ds_], %%ss\n\t" + "mov %[_ds_], %%es\n\t" + "mov %[_ds_], %%fs\n\t" + "mov %[_ds_], %%gs\n\t" : - : "m" (gdtr) + : [_gdtr_] "m" (gdtr), + [_cs_] "i" (GDT_SEL_CODE), + [_ds_] "r" (GDT_SEL_DATA) ); } From 2dccb55e15e6223075779ca1d7c6efd1c40c480c Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Fri, 3 Jul 2015 00:27:11 -0700 Subject: [PATCH 46/92] x86: Add PCI support This patch adds the pci.c and pci.h files, which support access to PCI configuration registers through a function interface. It defines the PCI configuration register access I/O port addresses and the pci_config_addr union and structure to assist in specifying addresses of PCI configuration registers. It also defines the PCI configuration register identifier for PCI BAR0. This patch also adds wrappers for 32-bit 'in' and 'out' port I/O instructions. They were placed in helpers.S, since they may be useful to other modules besides just the PCI support module. --- cpu/x86/Makefile.x86_quarkX1000 | 2 +- cpu/x86/drivers/legacy_pc/pci.c | 63 +++++++++++++++++++++++++++++++++ cpu/x86/drivers/legacy_pc/pci.h | 61 +++++++++++++++++++++++++++++++ cpu/x86/helpers.S | 13 +++++++ cpu/x86/helpers.h | 11 +++--- 5 files changed, 143 insertions(+), 7 deletions(-) create mode 100644 cpu/x86/drivers/legacy_pc/pci.c create mode 100644 cpu/x86/drivers/legacy_pc/pci.h diff --git a/cpu/x86/Makefile.x86_quarkX1000 b/cpu/x86/Makefile.x86_quarkX1000 index d6a258453..76665fd86 100644 --- a/cpu/x86/Makefile.x86_quarkX1000 +++ b/cpu/x86/Makefile.x86_quarkX1000 @@ -2,7 +2,7 @@ include $(CONTIKI)/cpu/x86/Makefile.x86_common CONTIKI_CPU_DIRS += drivers/legacy_pc init/legacy_pc -CONTIKI_SOURCEFILES += bootstrap_quarkX1000.S rtc.c pit.c pic.c irq.c nmi.c +CONTIKI_SOURCEFILES += bootstrap_quarkX1000.S rtc.c pit.c pic.c irq.c nmi.c pci.c CFLAGS += -m32 -march=i586 -mtune=i586 LDFLAGS += -m32 -T $(CONTIKI)/cpu/x86/quarkX1000.ld diff --git a/cpu/x86/drivers/legacy_pc/pci.c b/cpu/x86/drivers/legacy_pc/pci.c new file mode 100644 index 000000000..6ce60f102 --- /dev/null +++ b/cpu/x86/drivers/legacy_pc/pci.c @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "pci.h" +#include "helpers.h" + +/* I/O port for PCI configuration address */ +#define PCI_CONFIG_ADDR_PORT 0xCF8 +/* I/O port for PCI configuration data */ +#define PCI_CONFIG_DATA_PORT 0xCFC + +/*---------------------------------------------------------------------------*/ +/* Initialize PCI configuration register address in preparation for accessing + * the specified register. + */ +static void +set_addr(pci_config_addr_t addr) +{ + addr.en_mapping = 1; + + outl(PCI_CONFIG_ADDR_PORT, addr.raw); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Read from the specified PCI configuration register. + * \param addr Address of PCI configuration register. + * \return Value read from PCI configuration register. + */ +uint32_t +pci_config_read(pci_config_addr_t addr) +{ + set_addr(addr); + + return inl(PCI_CONFIG_DATA_PORT); +} +/*---------------------------------------------------------------------------*/ diff --git a/cpu/x86/drivers/legacy_pc/pci.h b/cpu/x86/drivers/legacy_pc/pci.h new file mode 100644 index 000000000..439cd3fc3 --- /dev/null +++ b/cpu/x86/drivers/legacy_pc/pci.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CPU_X86_DRIVERS_LEGACY_PC_PCI_H_ +#define CPU_X86_DRIVERS_LEGACY_PC_PCI_H_ + +#include + +/** PCI configuration register identifier for Base Address Register 0 (BAR0) */ +#define PCI_CONFIG_REG_BAR0 0x10 + +/** + * PCI configuration address + * + * Refer to Intel Quark SoC X1000 Datasheet, Section 5.5 for more details on + * PCI configuration register access. + */ +typedef union pci_config_addr { + struct { + /** Register/offset number. Least-significant two bits should be zero. */ + uint32_t reg_off : 8; + uint32_t func : 3; /**< Function number */ + uint32_t dev : 5; /**< Device number */ + uint32_t bus : 8; /**< Bus number */ + uint32_t : 7; + /** Must be set to perform PCI configuration access. */ + uint32_t en_mapping : 1; + }; + uint32_t raw; +} pci_config_addr_t; + +uint32_t pci_config_read(pci_config_addr_t addr); + +#endif /* CPU_X86_DRIVERS_LEGACY_PC_PCI_H_ */ diff --git a/cpu/x86/helpers.S b/cpu/x86/helpers.S index 0f9f517b8..c1c73130f 100644 --- a/cpu/x86/helpers.S +++ b/cpu/x86/helpers.S @@ -43,8 +43,21 @@ outb: out %al, %dx ret +.global outl +outl: + mov 4(%esp), %dx + mov 8(%esp), %eax + out %eax, %dx + ret + .global inb inb: mov 4(%esp), %dx in %dx, %al ret + +.global inl +inl: + mov 4(%esp), %dx + in %dx, %eax + ret diff --git a/cpu/x86/helpers.h b/cpu/x86/helpers.h index 705f37d45..91b120a9e 100644 --- a/cpu/x86/helpers.h +++ b/cpu/x86/helpers.h @@ -37,13 +37,12 @@ void halt(void) __attribute__((__noreturn__)); -/** - * Wrapper for the assembly 'out' instruction. - * - */ -void outb(uint16_t port, uint8_t byte); +/** Wrappers for the assembly 'out' instruction. */ +void outb(uint16_t port, uint8_t val); +void outl(uint16_t port, uint32_t val); -/* Wrapper for the assembly 'in' instruction */ +/** Wrappers for the assembly 'in' instruction */ uint8_t inb(uint16_t port); +uint32_t inl(uint16_t port); #endif /* HELPERS_H */ From c5f9cefac7123c127b84a33c6abee2c29ae888aa Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Fri, 3 Jul 2015 05:03:12 -0700 Subject: [PATCH 47/92] x86: Add generic driver structure and associated initialization code This patch adds a generic device driver structure with a field for referencing an MMIO range. It also provides a structure initialization procedure that initializes the MMIO range field with the value read from the PCI BAR0 register for a device. --- cpu/x86/drivers/legacy_pc/pci.c | 16 ++++++++++++++++ cpu/x86/drivers/legacy_pc/pci.h | 9 +++++++++ 2 files changed, 25 insertions(+) diff --git a/cpu/x86/drivers/legacy_pc/pci.c b/cpu/x86/drivers/legacy_pc/pci.c index 6ce60f102..fe18e79d6 100644 --- a/cpu/x86/drivers/legacy_pc/pci.c +++ b/cpu/x86/drivers/legacy_pc/pci.c @@ -61,3 +61,19 @@ pci_config_read(pci_config_addr_t addr) return inl(PCI_CONFIG_DATA_PORT); } /*---------------------------------------------------------------------------*/ +/** + * \brief Initialize a structure for a PCI device driver that performs + * MMIO to address range 0. Assumes that device has already + * been configured with an MMIO address range 0, e.g. by + * firmware. + * \param c_this Structure that will be initialized to represent the driver. + * \param pci_addr PCI base address of device. + */ +void +pci_init_bar0(pci_driver_t *c_this, pci_config_addr_t pci_addr) +{ + pci_addr.reg_off = PCI_CONFIG_REG_BAR0; + /* The BAR0 value is masked to clear non-address bits. */ + c_this->mmio = pci_config_read(pci_addr) & ~0xFFF; +} +/*---------------------------------------------------------------------------*/ diff --git a/cpu/x86/drivers/legacy_pc/pci.h b/cpu/x86/drivers/legacy_pc/pci.h index 439cd3fc3..fca51ab69 100644 --- a/cpu/x86/drivers/legacy_pc/pci.h +++ b/cpu/x86/drivers/legacy_pc/pci.h @@ -58,4 +58,13 @@ typedef union pci_config_addr { uint32_t pci_config_read(pci_config_addr_t addr); +/** + * PCI device driver instance with a single MMIO range. + */ +typedef struct pci_driver { + uintptr_t mmio; /**< MMIO range base address */ +} pci_driver_t; + +void pci_init_bar0(pci_driver_t *c_this, pci_config_addr_t pci_addr); + #endif /* CPU_X86_DRIVERS_LEGACY_PC_PCI_H_ */ From 6acdf50262c474b88d28b44253c420163fb69ec2 Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Fri, 3 Jul 2015 05:09:34 -0700 Subject: [PATCH 48/92] x86: Add driver for MMIO-accessible 16X50 UART This patch adds a driver for an MMIO-accessible 16X50 UART. It assumes that the boot firmware assigned an MMIO range to the UART. It operates in polled mode with FIFOs enabled. --- cpu/x86/Makefile.x86_quarkX1000 | 2 +- cpu/x86/drivers/legacy_pc/uart-16x50.c | 123 +++++++++++++++++++++++++ cpu/x86/drivers/legacy_pc/uart-16x50.h | 44 +++++++++ 3 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 cpu/x86/drivers/legacy_pc/uart-16x50.c create mode 100644 cpu/x86/drivers/legacy_pc/uart-16x50.h diff --git a/cpu/x86/Makefile.x86_quarkX1000 b/cpu/x86/Makefile.x86_quarkX1000 index 76665fd86..87c9981dc 100644 --- a/cpu/x86/Makefile.x86_quarkX1000 +++ b/cpu/x86/Makefile.x86_quarkX1000 @@ -2,7 +2,7 @@ include $(CONTIKI)/cpu/x86/Makefile.x86_common CONTIKI_CPU_DIRS += drivers/legacy_pc init/legacy_pc -CONTIKI_SOURCEFILES += bootstrap_quarkX1000.S rtc.c pit.c pic.c irq.c nmi.c pci.c +CONTIKI_SOURCEFILES += bootstrap_quarkX1000.S rtc.c pit.c pic.c irq.c nmi.c pci.c uart-16x50.c CFLAGS += -m32 -march=i586 -mtune=i586 LDFLAGS += -m32 -T $(CONTIKI)/cpu/x86/quarkX1000.ld diff --git a/cpu/x86/drivers/legacy_pc/uart-16x50.c b/cpu/x86/drivers/legacy_pc/uart-16x50.c new file mode 100644 index 000000000..090544ddc --- /dev/null +++ b/cpu/x86/drivers/legacy_pc/uart-16x50.c @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "uart-16x50.h" +#include +#include "helpers.h" + +/* Refer to Intel Quark SoC X1000 Datasheet, Chapter 18 for more details on + * UART operation. + */ + +/* Divisor Latch Access Bit (DLAB) mask for Line Control Register (LCR). + * + * When bit is set, enables access to divisor registers to set baud rate. When + * clear, enables access to other registers mapped to the same addresses as the + * divisor registers. + */ +#define UART_LCR_7_DLAB BIT(7) +/* Setting for LCR that configures the UART to operate with no parity, 1 stop + * bit, and eight bits per character. + */ +#define UART_LCR_8BITS 0x03 + +/* FIFO Control Register (FCR) bitmasks */ +#define UART_FCR_0_FIFOE BIT(0) /*< enable FIFOs */ +#define UART_FCR_1_RFIFOR BIT(1) /*< reset RX FIFO */ +#define UART_FCR_2_XFIFOR BIT(2) /*< reset TX FIFO */ + +/* Line Status Register (LSR) Transmit Holding Register Empty bitmask to check + * whether the Transmit Holding Register (THR) or TX FIFO is empty. + */ +#define UART_LSR_5_THRE BIT(5) + +/* MMIO registers for UART */ +typedef struct uart_16x50_regs { + volatile uint32_t rbr_thr_dll, ier_dlh, iir_fcr, lcr; + volatile uint32_t mcr, lsr, msr, scr, usr, htx, dmasa; +} uart_16x50_regs_t; + +/*---------------------------------------------------------------------------*/ +/** + * \brief Initialize an MMIO-programmable 16X50 UART. + * \param c_this Structure that will be initialized to represent the device. + * \param pci_addr PCI address of device. + * \param dl Divisor setting to configure the baud rate. + */ +void +uart_16x50_init(uart_16x50_driver_t *c_this, + pci_config_addr_t pci_addr, + uint16_t dl) +{ + /* This assumes that the UART had an MMIO range assigned to it by the + * firmware during boot. + */ + pci_init_bar0(c_this, pci_addr); + + uart_16x50_regs_t *regs = (uart_16x50_regs_t *)c_this->mmio; + + /* Set the DLAB bit to enable access to divisor settings. */ + regs->lcr = UART_LCR_7_DLAB; + + /* The divisor settings configure the baud rate, and may need to be defined + * on a per-device basis. + */ + regs->rbr_thr_dll = dl & UINT8_MAX; + regs->ier_dlh = dl >> 8; + + /* Clear the DLAB bit to enable access to other settings and configure other + * UART parameters. + */ + regs->lcr = UART_LCR_8BITS; + + /* Enable the FIFOs. */ + regs->iir_fcr = UART_FCR_0_FIFOE | UART_FCR_1_RFIFOR | UART_FCR_2_XFIFOR; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Transmit a character through a UART. + * \param c_this Initialized structure representing the device. + * \param c Character to be transmitted. + * + * This procedure will block indefinitely until the UART is ready + * to accept the character to be transmitted. + */ +void +uart_16x50_tx(uart_16x50_driver_t c_this, uint8_t c) +{ + struct uart_16x50_regs *regs = (uart_16x50_regs_t *)c_this.mmio; + + /* Wait for space in TX FIFO. */ + while((regs->lsr & UART_LSR_5_THRE) == 0); + + /* Add character to TX FIFO. */ + regs->rbr_thr_dll = c; +} +/*---------------------------------------------------------------------------*/ diff --git a/cpu/x86/drivers/legacy_pc/uart-16x50.h b/cpu/x86/drivers/legacy_pc/uart-16x50.h new file mode 100644 index 000000000..615806518 --- /dev/null +++ b/cpu/x86/drivers/legacy_pc/uart-16x50.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CPU_X86_DRIVERS_LEGACY_PC_UART_16X50_H_ +#define CPU_X86_DRIVERS_LEGACY_PC_UART_16X50_H_ + +#include "pci.h" + +typedef pci_driver_t uart_16x50_driver_t; + +void uart_16x50_init(uart_16x50_driver_t *c_this, + pci_config_addr_t pci_addr, + uint16_t dl); + +void uart_16x50_tx(uart_16x50_driver_t c_this, uint8_t c); + +#endif /* CPU_X86_DRIVERS_LEGACY_PC_UART_16X50_H_ */ From 15f947fe403f6cd6ed759abd48cbe28afbbc672e Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Fri, 3 Jul 2015 05:38:17 -0700 Subject: [PATCH 49/92] x86: Add Intel Quark X1000 UART support. This patch adds a driver that wraps the generic 16X50 UART driver with specific support for the two Intel Quark X1000 built-in UARTs. --- cpu/x86/Makefile.x86_quarkX1000 | 4 +- cpu/x86/drivers/quarkX1000/uart.c | 75 +++++++++++++++++++++++++++++++ cpu/x86/drivers/quarkX1000/uart.h | 44 ++++++++++++++++++ 3 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 cpu/x86/drivers/quarkX1000/uart.c create mode 100644 cpu/x86/drivers/quarkX1000/uart.h diff --git a/cpu/x86/Makefile.x86_quarkX1000 b/cpu/x86/Makefile.x86_quarkX1000 index 87c9981dc..cdc9dec52 100644 --- a/cpu/x86/Makefile.x86_quarkX1000 +++ b/cpu/x86/Makefile.x86_quarkX1000 @@ -1,8 +1,8 @@ include $(CONTIKI)/cpu/x86/Makefile.x86_common -CONTIKI_CPU_DIRS += drivers/legacy_pc init/legacy_pc +CONTIKI_CPU_DIRS += drivers/legacy_pc drivers/quarkX1000 init/legacy_pc -CONTIKI_SOURCEFILES += bootstrap_quarkX1000.S rtc.c pit.c pic.c irq.c nmi.c pci.c uart-16x50.c +CONTIKI_SOURCEFILES += bootstrap_quarkX1000.S rtc.c pit.c pic.c irq.c nmi.c pci.c uart-16x50.c uart.c CFLAGS += -m32 -march=i586 -mtune=i586 LDFLAGS += -m32 -T $(CONTIKI)/cpu/x86/quarkX1000.ld diff --git a/cpu/x86/drivers/quarkX1000/uart.c b/cpu/x86/drivers/quarkX1000/uart.c new file mode 100644 index 000000000..ba56992c9 --- /dev/null +++ b/cpu/x86/drivers/quarkX1000/uart.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "uart.h" +#include "uart-16x50.h" +#include + +static uart_16x50_driver_t quarkX1000_uart0; +static uart_16x50_driver_t quarkX1000_uart1; + +/* Divisor setting for 115200 baud from section 18.2.2 of Intel Quark SoC + * X1000 Datasheet. + */ +#define QUARK_X1000_UART_DL_115200 24 + +/*---------------------------------------------------------------------------*/ +/** + * \brief Initialize a UART. + * \param dev Device to initialize. + */ +void +quarkX1000_uart_init(quarkX1000_uart_dev_t dev) +{ + pci_config_addr_t pci_addr; + + assert((dev == QUARK_X1000_UART_0) || (dev == QUARK_X1000_UART_1)); + + pci_addr.raw = 0; + + /* PCI addresses from section 18.4 of Intel Quark SoC X1000 Datasheet. */ + pci_addr.dev = 20; + pci_addr.func = (dev == QUARK_X1000_UART_0) ? 1 : 5; + + uart_16x50_init((dev == QUARK_X1000_UART_0) ? &quarkX1000_uart0 : &quarkX1000_uart1, pci_addr, QUARK_X1000_UART_DL_115200); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Transmit a character via a UART. + * \param dev Device to use. + * \param c Character to transmit. + */ +void +quarkX1000_uart_tx(quarkX1000_uart_dev_t dev, uint8_t c) +{ + assert((dev == QUARK_X1000_UART_0) || (dev == QUARK_X1000_UART_1)); + uart_16x50_tx((dev == QUARK_X1000_UART_0) ? quarkX1000_uart0 : quarkX1000_uart1, c); +} +/*---------------------------------------------------------------------------*/ diff --git a/cpu/x86/drivers/quarkX1000/uart.h b/cpu/x86/drivers/quarkX1000/uart.h new file mode 100644 index 000000000..8b545d8cd --- /dev/null +++ b/cpu/x86/drivers/quarkX1000/uart.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CPU_X86_DRIVERS_QUARKX1000_UART_H_ +#define CPU_X86_DRIVERS_QUARKX1000_UART_H_ + +#include + +typedef enum { + QUARK_X1000_UART_0, + QUARK_X1000_UART_1 +} quarkX1000_uart_dev_t; + +void quarkX1000_uart_init(quarkX1000_uart_dev_t dev); +void quarkX1000_uart_tx(quarkX1000_uart_dev_t dev, uint8_t c); + +#endif /* CPU_X86_DRIVERS_QUARKX1000_UART_H_ */ From ee82304211b885ab1a5370e5dd426e89e64bfde3 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 17 Jul 2015 10:21:31 -0300 Subject: [PATCH 50/92] galileo: Implement _sbrk_r syscall This patch implements the _sbrk_r() system call for Galileo platform. This system call is required by newlib's malloc() implementation. Next patch will introduce the initial support for stdio library which requires a working malloc() function for proper operation. We are not sure about the heap size we should use. Preliminary tests have shown that stdio library requests 1032 bytes heap. So, as an initial guess, a 2Kb heap size should be enough for now. --- platform/galileo/newlib-syscalls.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/platform/galileo/newlib-syscalls.c b/platform/galileo/newlib-syscalls.c index 5a7831857..6adcccd19 100644 --- a/platform/galileo/newlib-syscalls.c +++ b/platform/galileo/newlib-syscalls.c @@ -31,6 +31,11 @@ #include #include +#define HEAP_MAX_SIZE 2048 + +static char _heap[HEAP_MAX_SIZE]; +static char *prog_break = _heap; + int _close_r(struct _reent *ptr, int file) { @@ -81,9 +86,21 @@ _fstat_r(struct _reent *ptr, int file, struct stat *st) caddr_t _sbrk_r(struct _reent *ptr, int incr) { - /* Stubbed function */ - ptr->_errno = ENOTSUP; - return NULL; + char *prev_prog_break; + + /* If the new program break overruns the maximum heap address, we return + * "Out of Memory" error to the user. + */ + if(prog_break + incr > _heap + HEAP_MAX_SIZE) { + ptr->_errno = ENOMEM; + return NULL; + } + + prev_prog_break = prog_break; + + prog_break += incr; + + return prev_prog_break; } /*---------------------------------------------------------------------------*/ void From d3d2b51fa21187c8b1bedbf52e9fa19553a50c1c Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 17 Jul 2015 10:43:55 -0300 Subject: [PATCH 51/92] galileo: Initial stdio support This patch introduces the initial support for stdio library in Galileo platform. For now, only standard output and error are supported. Both streams use the UART1 device. Newlib doesn't call open() for stdin, stdout, and stderr which means that the _write_r call is the first activity the stub will see on those streams. For that reason, we initialize the UART1 device in Galileo's platform main() function instead of in open() system call. --- platform/galileo/README.md | 5 +++ platform/galileo/contiki-main.c | 7 ++++ platform/galileo/newlib-syscalls.c | 58 ++++++++++++++++++++++++++---- 3 files changed, 64 insertions(+), 6 deletions(-) diff --git a/platform/galileo/README.md b/platform/galileo/README.md index 121bf2471..5b3ff9715 100644 --- a/platform/galileo/README.md +++ b/platform/galileo/README.md @@ -28,11 +28,16 @@ Device drivers: * Programmable Interrupt Controller (PIC) * Programmable Intergal Timer (PIT) * Real-Time Clock (RTC) + * UART Contiki APIs: * Clock module * Timer, Stimer, Etimer, Ctimer, and Rtimer libraries +Standard APIs: + * Stdio library (stdout and stderr only). Console output through UART 1 + device (connected to Galileo Gen2 FTDI header) + Building -------- diff --git a/platform/galileo/contiki-main.c b/platform/galileo/contiki-main.c index 199ae45cc..7e8658d60 100644 --- a/platform/galileo/contiki-main.c +++ b/platform/galileo/contiki-main.c @@ -28,17 +28,24 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include + #include "contiki.h" #include "cpu.h" #include "interrupt.h" +#include "uart.h" int main(void) { cpu_init(); + /* Initialize UART connected to Galileo Gen2 FTDI header */ + quarkX1000_uart_init(QUARK_X1000_UART_1); clock_init(); rtimer_init(); + printf("Starting Contiki\n"); + ENABLE_IRQ(); process_init(); diff --git a/platform/galileo/newlib-syscalls.c b/platform/galileo/newlib-syscalls.c index 6adcccd19..6c3be2d4c 100644 --- a/platform/galileo/newlib-syscalls.c +++ b/platform/galileo/newlib-syscalls.c @@ -31,6 +31,10 @@ #include #include +#include "uart.h" + +#define CONSOLE_OUTPUT_DEV QUARK_X1000_UART_1 + #define HEAP_MAX_SIZE 2048 static char _heap[HEAP_MAX_SIZE]; @@ -62,9 +66,40 @@ _read_r(struct _reent *ptr, int file, char *buf, int len) int _write_r(struct _reent *ptr, int file, const char *buf, int len) { - /* Stubbed function */ - ptr->_errno = ENOTSUP; - return -1; + int ret; + int i; + + switch(file) { + case 0: + ptr->_errno = EBADF; + ret = -1; + break; + + case 1: + case 2: + for(i = 0; i < len; i++) { + /* Since file descriptors 1 and 2 (stdout and stderr) are mapped to a + * serial console, we should translate the 'newline' escape sequence + * to 'carriage return' (CR) followed by 'line feed' (LF) ASCII + * characters. + */ + if(buf[i] == '\n') { + quarkX1000_uart_tx(CONSOLE_OUTPUT_DEV, '\r'); + } + quarkX1000_uart_tx(CONSOLE_OUTPUT_DEV, buf[i]); + } + + ret = len; + break; + + default: + /* We don't support any filesystem yet. */ + ptr->_errno = ENOTSUP; + ret = -1; + break; + } + + return ret; } /*---------------------------------------------------------------------------*/ int @@ -78,9 +113,20 @@ _lseek_r(struct _reent *ptr, int file, int p, int dir) int _fstat_r(struct _reent *ptr, int file, struct stat *st) { - /* Stubbed function */ - ptr->_errno = ENOTSUP; - return -1; + /* We don't support the standard input yet so file descriptor 0 is not + * supported by this function. Additionally, we don't have support for + * any filesystem thus file descriptors greater than 2 are not supported + * as well. + * + * We support standard ouput and error (file descriptors 1 and 2) only. + */ + if(file == 0 || file > 2) { + ptr->_errno = ENOTSUP; + return -1; + } + + st->st_mode = S_IFCHR; + return 0; } /*---------------------------------------------------------------------------*/ caddr_t From dd540e9a216a309b616f02974e942d5dd840f6da Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 17 Jul 2015 21:03:21 -0300 Subject: [PATCH 52/92] gitignore: Add platform/galileo/bsp/libc/Makefile.libc --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 28db7d3b7..1e566f4de 100644 --- a/.gitignore +++ b/.gitignore @@ -112,6 +112,7 @@ cscope.* *.swo # galileo bsp files +platform/galileo/bsp/libc/Makefile.libc platform/galileo/bsp/libc/i586-elf/ platform/galileo/bsp/libc/newlib-2.2.0-1* platform/galileo/bsp/grub/src/ From 6c9ab4eb6c036f6d345e7c065edc52571d343246 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Mon, 13 Jul 2015 19:24:31 -0300 Subject: [PATCH 53/92] galileo: Remove unneeded syscall stubs This patch removes _kill_r and _getpid_r stubs since they are not required by newlib at this moment. These stubs should not be in the commit that introduced the initial newlib-syscalls.c file. --- platform/galileo/newlib-syscalls.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/platform/galileo/newlib-syscalls.c b/platform/galileo/newlib-syscalls.c index 6c3be2d4c..8032e6da8 100644 --- a/platform/galileo/newlib-syscalls.c +++ b/platform/galileo/newlib-syscalls.c @@ -148,18 +148,3 @@ _sbrk_r(struct _reent *ptr, int incr) return prev_prog_break; } -/*---------------------------------------------------------------------------*/ -void -_kill_r(struct _reent *ptr) -{ - /* Stubbed function */ - ptr->_errno = ENOTSUP; -} -/*---------------------------------------------------------------------------*/ -int -_getpid_r(struct _reent *ptr) -{ - /* Stubbed function */ - ptr->_errno = ENOTSUP; - return 1; -} From c9020d95e7ee60a6641af3a31932f0578e38ace8 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 10 Jul 2015 11:01:57 -0300 Subject: [PATCH 54/92] x86: Build release image This patch adds support for building release images. The main difference between release images and default images is that the former is optimized for size while the latter is "optimized" for debugging. To build a release image, the BUILD_RELEASE variable should be set to 1. For instance, the following command build a release image from the hello-world application: $ cd examples/hello-world && make TARGET=galileo BUILD_RELEASE=1 To optimize for size we use the '-Os' option from gcc. This option also enables the strict aliasing optimization. This generates lots of warning messages since we use the '-Wall' option and lots of code in core/net/ break the strict-aliasing rules. Some test have shown that the strict aliasing optimization it not taking effect in the final binary. For that reasons, this patch manually disables the optimization. Also, the release image is stripped. For the sake of comparison, below follows the output from 'wc' and 'size' for both debugging (default) and release images. Default image: $ wc -c hello-world.galileo 71112 hello-world.galileo $ size hello-world.galileo text data bss dec hex filename 20379 1188 12808 34375 8647 hello-world.galileo Release image: $ wc -c hello-world.galileo 26320 hello-world.galileo $ size hello-world.galileo text data bss dec hex filename 18146 1156 12808 32110 7d6e hello-world.galileo --- cpu/x86/Makefile.x86_common | 6 ++++++ platform/galileo/README.md | 21 +++++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/cpu/x86/Makefile.x86_common b/cpu/x86/Makefile.x86_common index 206a02d4e..44e96363b 100644 --- a/cpu/x86/Makefile.x86_common +++ b/cpu/x86/Makefile.x86_common @@ -11,3 +11,9 @@ STRIP = strip CFLAGS += -Wall -g LDFLAGS += -Wl,-Map=contiki-$(TARGET).map,--build-id=none + +ifeq ($(BUILD_RELEASE),1) + CFLAGS += -Os -fno-strict-aliasing + LDFLAGS += -Wl,--strip-all +endif + diff --git a/platform/galileo/README.md b/platform/galileo/README.md index 5b3ff9715..131bbb6d0 100644 --- a/platform/galileo/README.md +++ b/platform/galileo/README.md @@ -56,18 +56,27 @@ $ cd examples/hello-world/ && make TARGET=galileo ``` This will generate the 'hello-world.galileo' file which is a multiboot- -compliant [3] ELF image. In order to boot the Contiki image, you will need -a multiboot-compliant bootloader. In the bsp directory, we provide a helper -script which builds the Grub bootloader with multiboot support. To build the -bootloader, just run the following command: +compliant [3] ELF image. This image contains debugging information and it +should be used in your daily development. + +You can also build a "Release" image by setting the BUILD_RELEASE variable to +1. This will generate a Contiki stripped-image optimized for size. ``` -$ platform/galileo/bsp/grub/build_grub.sh +$ cd examples/hello-world/ && make TARGET=galileo BUILD_RELEASE=1 ``` Running ------- -So to run Contiki applications in Galileo, we have three main steps: +In order to boot the Contiki image, you will need a multiboot-compliant +bootloader. In the bsp directory, we provide a helper script which builds the +Grub bootloader with multiboot support. To build the bootloader, just run the +following command: +``` +$ platform/galileo/bsp/grub/build_grub.sh +``` + +Once Grub is built, we have three main steps to run Contiki applications: prepare SDcard, connect to console, and boot image. Below follows detailed instructions. From 8a0bc49433d2e90b612be7beffca928a73ec7d11 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 10 Jul 2015 11:44:28 -0300 Subject: [PATCH 55/92] x86: Improve debugging experience This patch appends some gcc options to CFLAGS when building the default image in order to improve the debugging experience on GDB. We use the '-ggdb' option which produces debugging information used by GDB (including GDB extensions) with level 3 which includes preprocessor macros information. We also use '-Og' which enables optimizations that do not interfere with debugging. According to gcc manpage, it should be the optimization level of choice for the standard edit-compile-debug cycle, offering a reasonable level of optimization while maintaining fast compilation and a good debugging experience. Also, this patch removes the '-g' option from the default CFLAGS because there is no point in using it when BUILD_RELEASE=1. As expected, the overall ELF image increases (due to -ggdb3 option) while the .text section is reduced (due to -Og). For the sake of comparison, below follows the output of 'size'. Before patch: $ size -A hello-world.galileo hello-world.galileo : section size addr .text 13766 1048576 .rodata 241 1064960 .eh_frame 5160 1065204 .eh_frame_hdr 1212 1070364 .data 1188 1073152 .bss 12808 1077248 .debug_info 14351 0 .debug_abbrev 6281 0 .debug_aranges 768 0 .debug_line 6443 0 .debug_str 4805 0 .comment 17 0 .note 40 0 .debug_ranges 24 0 Total 67104 After patch: $ size -A hello-world.galileo hello-world.galileo : section size addr .text 11718 1048576 .rodata 249 1060864 .eh_frame 5496 1061116 .eh_frame_hdr 1204 1066612 .data 1156 1069056 .bss 12808 1073152 .debug_info 16727 0 .debug_abbrev 7254 0 .debug_loc 2083 0 .debug_aranges 768 0 .debug_macro 17273 0 .debug_line 13433 0 .debug_str 42192 0 .comment 17 0 .note 40 0 Total 132418 --- cpu/x86/Makefile.x86_common | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cpu/x86/Makefile.x86_common b/cpu/x86/Makefile.x86_common index 44e96363b..23095a493 100644 --- a/cpu/x86/Makefile.x86_common +++ b/cpu/x86/Makefile.x86_common @@ -9,11 +9,12 @@ OBJCOPY = objcopy SIZE = size STRIP = strip -CFLAGS += -Wall -g +CFLAGS += -Wall LDFLAGS += -Wl,-Map=contiki-$(TARGET).map,--build-id=none ifeq ($(BUILD_RELEASE),1) CFLAGS += -Os -fno-strict-aliasing LDFLAGS += -Wl,--strip-all +else + CFLAGS += -Og -ggdb3 endif - From 7043aa41b36dde8aaf1674c37df6aeaab285e848 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Mon, 13 Jul 2015 18:54:24 -0300 Subject: [PATCH 56/92] galileo: Fix newlib-syscalls issue in Makefile This patch removes 'newlib-syscalls.c' from CONTIKI_SOURCEFILES variable and appends it to PROJECT_SOURCEFILES. This way the buildsystem will automatically consider the newlib-syscalls object code during linking time. --- platform/galileo/Makefile.galileo | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/platform/galileo/Makefile.galileo b/platform/galileo/Makefile.galileo index 662042e56..1a2238370 100644 --- a/platform/galileo/Makefile.galileo +++ b/platform/galileo/Makefile.galileo @@ -5,7 +5,9 @@ LIBGCC_PATH = /usr/lib/gcc/$(shell gcc -dumpmachine)/$(shell gcc -dumpversion) CONTIKI_TARGET_DIRS = . core/sys/ CONTIKI_TARGET_MAIN = ${addprefix $(OBJECTDIR)/,contiki-main.o} -CONTIKI_SOURCEFILES += contiki-main.c newlib-syscalls.c clock.c rtimer-arch.c +CONTIKI_SOURCEFILES += contiki-main.c clock.c rtimer-arch.c + +PROJECT_SOURCEFILES += newlib-syscalls.c CONTIKI_CPU=$(CONTIKI)/cpu/x86 include $(CONTIKI)/cpu/x86/Makefile.x86_quarkX1000 @@ -22,4 +24,4 @@ endif # Ideally, this should be part of LDFLAGS (-lc -lm etc). However, we found out that archive # static files (.a) must be linked after our own object files, otherwise the linker gets lost # and we get undefined references only. -TARGET_LIBFILES = $(OBJECTDIR)/newlib-syscalls.o $(LIBC)/lib/libm.a $(LIBC)/lib/libc.a $(LIBGCC_PATH)/32/libgcc.a +TARGET_LIBFILES = $(LIBC)/lib/libm.a $(LIBC)/lib/libc.a $(LIBGCC_PATH)/32/libgcc.a From e41bed319f3377c56e7d210ccfbab87c8892bf35 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 14 Jul 2015 11:22:31 -0300 Subject: [PATCH 57/92] galileo: Revise stdlib static linking This patch does some refactoring so we are able to statically link against standard libraries in a more usual way. --- platform/galileo/Makefile.galileo | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/platform/galileo/Makefile.galileo b/platform/galileo/Makefile.galileo index 1a2238370..9aca3d0a8 100644 --- a/platform/galileo/Makefile.galileo +++ b/platform/galileo/Makefile.galileo @@ -13,15 +13,12 @@ CONTIKI_CPU=$(CONTIKI)/cpu/x86 include $(CONTIKI)/cpu/x86/Makefile.x86_quarkX1000 CFLAGS += -fno-stack-protector -nostdinc -isystem $(LIBC)/include -isystem $(LIBGCC_PATH)/include -isystem $(LIBGCC_PATH)/include-fixed -LDFLAGS += -nostdlib +LDFLAGS += -nostdlib -L$(LIBC)/lib -L$(LIBGCC_PATH)/32 + +TARGET_LIBFILES += -lm -lc -lgcc -include $(LIBC_PATH)/Makefile.libc ifndef BUILT_LIBC $(error Build the C library by executing $(LIBC_PATH)/build_newlib.sh) endif - -# Ideally, this should be part of LDFLAGS (-lc -lm etc). However, we found out that archive -# static files (.a) must be linked after our own object files, otherwise the linker gets lost -# and we get undefined references only. -TARGET_LIBFILES = $(LIBC)/lib/libm.a $(LIBC)/lib/libc.a $(LIBGCC_PATH)/32/libgcc.a From bdcf58033a65581c190a8a826ff9aabd365b0733 Mon Sep 17 00:00:00 2001 From: Jesus Sanchez-Palencia Date: Wed, 22 Jul 2015 09:27:40 -0300 Subject: [PATCH 58/92] x86: Group sections for QuarkX1000 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Child sections can be created depending on the CFLAGS used when building Contiki. For instance, if built with -ffunction-sections or -fdata-sections would create one section per function/variable and -Os sometimes split part of .text into one child section. This can also be an issue if we start linking with external libraries that are built in such a way. Since we can't foresee how the port is going to be used, we should make sure it is ready for the cases above. This patch fixes this by correctly grouping child sections into their parent sections. Patch developed while investigating a bug with José Souza (jose.souza@intel.com). --- cpu/x86/quarkX1000.ld | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cpu/x86/quarkX1000.ld b/cpu/x86/quarkX1000.ld index b4a3afa44..f9ff105c2 100644 --- a/cpu/x86/quarkX1000.ld +++ b/cpu/x86/quarkX1000.ld @@ -42,7 +42,7 @@ SECTIONS { .text ALIGN (4K) : { *(.multiboot) - *(.text) + *(.text*) } .rodata ALIGN (4K) : @@ -52,12 +52,12 @@ SECTIONS { .data ALIGN (4K) : { - *(.data) + *(.data*) } .bss ALIGN (4K) : { *(COMMON) - *(.bss) + *(.bss*) } } From 06e25c487a67161bf82053e985b3abc1528f6cfe Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Fri, 24 Jul 2015 07:50:59 -0700 Subject: [PATCH 59/92] galileo: Correct README.md to explain how to verify boot with UART This patch revises README.md to mention the UART support introduced by earlier patches in the section about verifying that Contiki is running. It also revises the serial console setup instructions to focus on the more thoroughly tested option. --- platform/galileo/README.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/platform/galileo/README.md b/platform/galileo/README.md index 131bbb6d0..c108bd185 100644 --- a/platform/galileo/README.md +++ b/platform/galileo/README.md @@ -96,11 +96,11 @@ $ cp platform/galileo/bsp/grub/bin/grub.efi /mnt/sdcard ### Connect to the console output -Connect the serial cable to your computer as showed in [2]. +Connect the serial cable to your computer as shown in [2]. -Choose one terminal emulator such as screen, putty or minicom. Make sure you -use keyboard SCO mode (on putty that option is at Terminal -> Keyboard, on -the left menu). Connect to /dev/ttyUSB0, use 115200 speed. +Choose a terminal emulator such as PuTTY. Make sure you use the SCO keyboard +mode (on PuTTY that option is at Terminal -> Keyboard, on the left menu). +Connect to the appropriate serial port using a baud rate of 115200. ### Boot Contiki Image @@ -118,15 +118,19 @@ $ fs0: $ grub.efi ``` -You'll reach de grub shell. Now run the following commands to boot Contiki +You'll reach the grub shell. Now run the following commands to boot Contiki image: ``` $ multiboot /hello-world.galileo $ boot ``` -For now, we lack of UART support so you won't see any output. However, you can -use JTAG (see next section) to verify that the Contiki is running. +This should boot the Contiki image, resulted in the following messages being +sent to the serial console: +``` +Starting Contiki +Hello World +``` Debugging --------- From 17b855aac959b3e8cea64d7b4e887ef3b8aa584e Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Thu, 23 Jul 2015 14:17:55 -0700 Subject: [PATCH 60/92] galileo: Replace non-halting core implementation of assert with the halting one from newlib This patch modifies the include order to include headers from newlib ahead of those from the core of Contiki. The only header file names that are common between Contiki and newlib are assert.h and config.h, but the config.h files in Contiki are only located in ports for other CPUs so they are irrelevant to this patch. The motivation for this patch is to cause files that include assert.h to include the one from newlib that halts when an assertion fails. The assert implementation in the core of Contiki does not halt when an assertion fails. This patch also adds newlib syscall stubs that are required by the newlib assert implementation and the _exit syscall function that halts the system. Finally, this patch updates some other newlib syscall stubs to properly indicate their status as unsupported syscalls. --- platform/galileo/Makefile.galileo | 2 +- platform/galileo/newlib-syscalls.c | 28 ++++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/platform/galileo/Makefile.galileo b/platform/galileo/Makefile.galileo index 9aca3d0a8..a1429b398 100644 --- a/platform/galileo/Makefile.galileo +++ b/platform/galileo/Makefile.galileo @@ -12,7 +12,7 @@ PROJECT_SOURCEFILES += newlib-syscalls.c CONTIKI_CPU=$(CONTIKI)/cpu/x86 include $(CONTIKI)/cpu/x86/Makefile.x86_quarkX1000 -CFLAGS += -fno-stack-protector -nostdinc -isystem $(LIBC)/include -isystem $(LIBGCC_PATH)/include -isystem $(LIBGCC_PATH)/include-fixed +CFLAGS += -fno-stack-protector -nostdinc -I$(LIBC)/include -isystem $(LIBGCC_PATH)/include -isystem $(LIBGCC_PATH)/include-fixed LDFLAGS += -nostdlib -L$(LIBC)/lib -L$(LIBGCC_PATH)/32 TARGET_LIBFILES += -lm -lc -lgcc diff --git a/platform/galileo/newlib-syscalls.c b/platform/galileo/newlib-syscalls.c index 8032e6da8..fa098c6eb 100644 --- a/platform/galileo/newlib-syscalls.c +++ b/platform/galileo/newlib-syscalls.c @@ -32,6 +32,7 @@ #include #include "uart.h" +#include "helpers.h" #define CONSOLE_OUTPUT_DEV QUARK_X1000_UART_1 @@ -48,19 +49,42 @@ _close_r(struct _reent *ptr, int file) return -1; } /*---------------------------------------------------------------------------*/ +void +_exit(int status) +{ + halt(); +} +/*---------------------------------------------------------------------------*/ +int +_getpid_r(struct _reent *ptr) +{ + /* Stubbed function */ + ptr->_errno = ENOTSUP; + return -1; +} +/*---------------------------------------------------------------------------*/ int _isatty_r(struct _reent *ptr, int file) { /* Stubbed function */ + ptr->_errno = ENOTSUP; return 0; } /*---------------------------------------------------------------------------*/ int +_kill_r(struct _reent *ptr, int pid, int signal) +{ + /* Stubbed function */ + ptr->_errno = ENOTSUP; + return -1; +} +/*---------------------------------------------------------------------------*/ +int _read_r(struct _reent *ptr, int file, char *buf, int len) { /* Stubbed function */ ptr->_errno = ENOTSUP; - return 0; + return -1; } /*---------------------------------------------------------------------------*/ int @@ -107,7 +131,7 @@ _lseek_r(struct _reent *ptr, int file, int p, int dir) { /* Stubbed function */ ptr->_errno = ENOTSUP; - return 0; + return -1; } /*---------------------------------------------------------------------------*/ int From f9072c166bd102c44e9a9b653473f346dd9c5a1b Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Wed, 29 Jul 2015 07:00:54 -0700 Subject: [PATCH 61/92] x86: Add missing clobber list in interrupt.h The SET_INTERRUPT_HANDLER macro defines and registers an interrupt handler. It outputs a trampoline for the interrupt handler using a block of inline assembly, and the address of that trampoline is what is actually placed in the IDT. That trampoline invokes the main body of the interrupt handler. This patch adds a missing clobber list to the inline assembly block. It simply lists the caller-saved registers defined by the cdecl calling convention: EAX, ECX, and EDX. This is necessary, because the inline assembly block invokes idt_set_intr_gate_desc using a call instruction at the time the function containing the SET_INTERRUPT_HANDLER instance is executed. The idt_set_intr_gate_desc function is free to clobber EAX, ECX, and EDX according to cdecl. A Clang-generated implementation of idt_set_intr_gate_desc did in fact clobber those registers, resulting in incorrect operation of the code following an instance of SET_INTERRUPT_HANDLER. The change in this patch informs the compiler that those registers may be clobbered so that it can adjust the code that it outputs around the inline assembly block accordingly. --- cpu/x86/init/common/interrupt.h | 1 + 1 file changed, 1 insertion(+) diff --git a/cpu/x86/init/common/interrupt.h b/cpu/x86/init/common/interrupt.h index 3310dad02..498a766fc 100644 --- a/cpu/x86/init/common/interrupt.h +++ b/cpu/x86/init/common/interrupt.h @@ -92,6 +92,7 @@ struct interrupt_context { " iret\n\t" \ "skip_trampoline%=:\n\t" \ :: "g" (num), "i" (idt_set_intr_gate_desc), "i" (handler) \ + : "eax", "ecx", "edx" \ ); \ } while (0) From 128d9f3566d2d8ca0dd33f1aca53aed123fd39e7 Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Wed, 29 Jul 2015 07:21:55 -0700 Subject: [PATCH 62/92] x86: Revise SET_INTERRUPT_HANDLER to avoid using inline assembly feature that does not work with LLVM Clang The SET_INTERRUPT_HANDLER macro in interrupt.h used an inline assembly feature to cause GCC to generate a unique number for a trampoline label. Clang compiled the code using that feature without generating any compile-time errors, but it always generated the number 0, resulting in all interrupt trampolines having the same label names. This patch replaces the usage of that feature with local labels, which are supported by both GCC and Clang. See https://sourceware.org/binutils/docs/as/Symbol-Names.html for an explanation of local labels. --- cpu/x86/init/common/interrupt.h | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/cpu/x86/init/common/interrupt.h b/cpu/x86/init/common/interrupt.h index 498a766fc..2ab228c72 100644 --- a/cpu/x86/init/common/interrupt.h +++ b/cpu/x86/init/common/interrupt.h @@ -67,22 +67,17 @@ struct interrupt_context { * interrupt. * * [1] http://wiki.osdev.org/Interrupt_Service_Routines - * - * XXX: If you are debugging at assembly level, make sure you don't be misled - * by the "trampolineXX" symbol name. The suffix number is NOT related to the - * interrupt number at all. The suffix number is a unique random number to - * guarantee there is no symbol name clashing. */ #define SET_INTERRUPT_HANDLER(num, has_error_code, handler) \ do { \ __asm__ __volatile__ ( \ - "push $trampoline%=\n\t" \ + "push $1f\n\t" \ "push %0\n\t" \ "call %P1\n\t" \ "add $8, %%esp\n\t" \ - "jmp skip_trampoline%=\n\t" \ + "jmp 2f\n\t" \ ".align 4\n\t" \ - "trampoline%=:\n\t" \ + "1:\n\t" \ " pushal\n\t" \ " call %P2\n\t" \ " popal\n\t" \ @@ -90,7 +85,7 @@ struct interrupt_context { " add $4, %%esp\n\t" \ " .endif\n\t" \ " iret\n\t" \ - "skip_trampoline%=:\n\t" \ + "2:\n\t" \ :: "g" (num), "i" (idt_set_intr_gate_desc), "i" (handler) \ : "eax", "ecx", "edx" \ ); \ From 0dcd5e9b5a098671dc86060fa4dcb59d56c8f830 Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Wed, 29 Jul 2015 07:28:13 -0700 Subject: [PATCH 63/92] x86: Revise CFLAGS and LDFLAGS for LLVM Clang compatibility This patch slightly revises CFLAGS and LDFLAGS to specify the optimization and debugging options and linker script in a way that is compatible with using Clang as the C compiler and to invoke the linker (i.e. CC = clang and LD = clang). --- cpu/x86/Makefile.x86_common | 6 +++++- cpu/x86/Makefile.x86_quarkX1000 | 2 +- platform/galileo/README.md | 13 +++++++++---- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/cpu/x86/Makefile.x86_common b/cpu/x86/Makefile.x86_common index 23095a493..12192db39 100644 --- a/cpu/x86/Makefile.x86_common +++ b/cpu/x86/Makefile.x86_common @@ -16,5 +16,9 @@ ifeq ($(BUILD_RELEASE),1) CFLAGS += -Os -fno-strict-aliasing LDFLAGS += -Wl,--strip-all else - CFLAGS += -Og -ggdb3 + ifeq ($(findstring clang,$(CC)),clang) + CFLAGS += -O0 -g + else + CFLAGS += -Og -ggdb3 + endif endif diff --git a/cpu/x86/Makefile.x86_quarkX1000 b/cpu/x86/Makefile.x86_quarkX1000 index cdc9dec52..4cbdc94b6 100644 --- a/cpu/x86/Makefile.x86_quarkX1000 +++ b/cpu/x86/Makefile.x86_quarkX1000 @@ -5,5 +5,5 @@ CONTIKI_CPU_DIRS += drivers/legacy_pc drivers/quarkX1000 init/legacy_pc CONTIKI_SOURCEFILES += bootstrap_quarkX1000.S rtc.c pit.c pic.c irq.c nmi.c pci.c uart-16x50.c uart.c CFLAGS += -m32 -march=i586 -mtune=i586 -LDFLAGS += -m32 -T $(CONTIKI)/cpu/x86/quarkX1000.ld +LDFLAGS += -m32 -Xlinker -T -Xlinker $(CONTIKI)/cpu/x86/quarkX1000.ld ASFLAGS += --32 -march=i586 -mtune=i586 diff --git a/platform/galileo/README.md b/platform/galileo/README.md index c108bd185..ba0c79670 100644 --- a/platform/galileo/README.md +++ b/platform/galileo/README.md @@ -48,9 +48,14 @@ command: $ ./platform/galileo/bsp/libc/build_newlib.sh ``` -Once newlib is built, you are ready to build applications. To build -applications for Galileo platform you should set TARGET variable to 'galileo'. -For instance, building the hello-world application should look like this: +Once newlib is built, you are ready to build applications. By default, the +following steps will use gcc as the C compiler and to invoke the linker. To +use LLVM clang instead, change the values for both the CC and LD variables in +cpu/x86/Makefile.x86_common to 'clang'. + +To build applications for the Galileo platform you should set the TARGET +variable to 'galileo'. For instance, building the hello-world application +should look like this: ``` $ cd examples/hello-world/ && make TARGET=galileo ``` @@ -125,7 +130,7 @@ $ multiboot /hello-world.galileo $ boot ``` -This should boot the Contiki image, resulted in the following messages being +This should boot the Contiki image, resulting in the following messages being sent to the serial console: ``` Starting Contiki From 8ae392e66f91e92433e56c7238ab2fb401688cff Mon Sep 17 00:00:00 2001 From: Jesus Sanchez-Palencia Date: Tue, 6 Oct 2015 09:44:03 -0300 Subject: [PATCH 64/92] x86: Reduce .eh_frame section size When generating binaries, gcc will always add information of what it calls "the exception handler framework" into its own section: .eh_frame. This section is based on the DWARF format's call frame information (CFI) [1] and holds information that can be useful for debuggers but also for language constructs that relies on always having stack unwinding information (i.e. exceptions). Such constructs, however, are pretty much useless for the C language and are mainly just used on C++. Furthermore, this section is one of the loadable sections of a binary, meaning it will take extra space on flash. When .eh_frame is not present, debuggers can still get the exact same information they need for unwinding a stack frame and for restoring registers thanks to yet another section: .debug_frame. This section is generated by '-g' gcc option and friends. It is actually defined by DWARF and, as opposed to .eh_frame, is not a loadable section. In other words, it is 'strippable' while .eh_frame is not. Since all we need is the debug information we can get from .debug_frame, we can disable the generation of these large and unused information tables by using gcc's '-fno-asynchronous-unwind-tables'. The .eh_frame section stays around but the code size issue is heavily tackled. This is the same approach taken on other projects that target small code size generation [2] [3]. Pratically speaking, on a DEBUG build of the all-timers appplication, before this patch we had: text data bss dec hex filename 21319 1188 12952 35459 8a83 all-timers.galileo And now, after this patch: text data bss dec hex filename 16347 1188 12952 30487 7717 all-timers.galileo This means a ~5Kb reduction on the loadable text segment (.text + .rodata + .eh_frame). The flag is applied regardless of build type, DEBUG or RELEASE, since it benefits both. Note that when release builds apply --gc-sections, they will remove .eh_frame section entirely. [1] http://comments.gmane.org/gmane.comp.standards.dwarf/222 [2] https://github.com/gfto/toybox/commit/0d74ad383b8bb8aa82e9cb6449b509ec6d4794a5 [3] http://git.musl-libc.org/cgit/musl/commit/?id=b439c051c7eee4eb4b93fc382f993aa6305ce530 [4] https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html Signed-off-by: Jesus Sanchez-Palencia --- cpu/x86/Makefile.x86_common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpu/x86/Makefile.x86_common b/cpu/x86/Makefile.x86_common index 12192db39..0656dd0d6 100644 --- a/cpu/x86/Makefile.x86_common +++ b/cpu/x86/Makefile.x86_common @@ -9,7 +9,7 @@ OBJCOPY = objcopy SIZE = size STRIP = strip -CFLAGS += -Wall +CFLAGS += -Wall -fno-asynchronous-unwind-tables LDFLAGS += -Wl,-Map=contiki-$(TARGET).map,--build-id=none ifeq ($(BUILD_RELEASE),1) From c796e270bf1eb9bf1a611a0cbff18f88d2fcee12 Mon Sep 17 00:00:00 2001 From: Ricardo de Almeida Gonzaga Date: Mon, 5 Oct 2015 15:38:50 -0300 Subject: [PATCH 65/92] x86: Add Intel Quark X1000 PCI Interrupt Routing support PCI Interrupt Routing is mapped using Interrupt Queue Agents IRQAGENT[0:3] and aggregating the INT[A:D] interrupts for each PCI-mapped device in the SoC. PCI based interrupts PIRQ[A:H] are then available for consumption by either the 8259 PICs or the IO-APIC, depending on the configuration of the 8 PIRQx Routing Control Registers PIRQ[A:H]. More information about can be find in Intel Quark X1000 datasheet[1] section 21.11. [1] - http://www.intel.com/content/www/us/en/embedded/products/quark/quark-x1000-datasheet.html --- cpu/x86/drivers/legacy_pc/pci.c | 133 ++++++++++++++++++++++++++++++++ cpu/x86/drivers/legacy_pc/pci.h | 33 ++++++++ 2 files changed, 166 insertions(+) diff --git a/cpu/x86/drivers/legacy_pc/pci.c b/cpu/x86/drivers/legacy_pc/pci.c index fe18e79d6..a56be38fa 100644 --- a/cpu/x86/drivers/legacy_pc/pci.c +++ b/cpu/x86/drivers/legacy_pc/pci.c @@ -28,6 +28,8 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include + #include "pci.h" #include "helpers.h" @@ -61,6 +63,137 @@ pci_config_read(pci_config_addr_t addr) return inl(PCI_CONFIG_DATA_PORT); } /*---------------------------------------------------------------------------*/ +/** + * \brief Set current PIRQ to interrupt queue agent. PCI based interrupts + * PIRQ[A:H] are then available for consumption by either the 8259 + * PICs or the IO-APIC depending on configuration of the 8 PIRQx + * Routing Control Registers PIRQ[A:H]. See also pci_pirq_set_irq(). + * \param agent Interrupt Queue Agent to be used, IRQAGENT[0:3]. + * \param pin Interrupt Pin Route to be used, INT[A:D]. + * \param pirq PIRQ to be used, PIRQ[A:H]. + * \return Returns 0 on success and a negative number otherwise. + */ +int +pci_irq_agent_set_pirq(IRQAGENT agent, INTR_PIN pin, PIRQ pirq) +{ + pci_config_addr_t pci; + uint16_t value; + uint32_t rcba_addr, offset = 0; + + assert(agent >= IRQAGENT0 && agent <= IRQAGENT3); + assert(pin >= INTA && pin <= INTD); + assert(pirq >= PIRQA && pirq <= PIRQH); + + pci.raw = 0; + pci.bus = 0; + pci.dev = 31; + pci.func = 0; + pci.reg_off = 0xF0; /* Root Complex Base Address Register */ + + /* masked to clear non-address bits. */ + rcba_addr = pci_config_read(pci) & ~0x3FFF; + + switch(agent) { + case IRQAGENT0: + if (pin != INTA) + return -1; + offset = 0x3140; + break; + case IRQAGENT1: + offset = 0x3142; + break; + case IRQAGENT2: + if (pin != INTA) + return -1; + offset = 0x3144; + break; + case IRQAGENT3: + offset = 0x3146; + } + + value = *(uint16_t*)(rcba_addr + offset); + + /* clear interrupt pin route and set corresponding pirq. */ + switch(pin) { + case INTA: + value &= ~0xF; + value |= pirq; + break; + case INTB: + value &= ~0xF0; + value |= (pirq << 4); + break; + case INTC: + value &= ~0xF00; + value |= (pirq << 8); + break; + case INTD: + value &= ~0xF000; + value |= (pirq << 12); + } + + *(uint16_t*)(rcba_addr + offset) = value; + + return 0; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Set current IRQ to PIRQ. The interrupt router can be + * programmed to allow PIRQ[A:H] to be routed internally + * to the 8259 as ISA compatible interrupts. See also + * pci_irq_agent_set_pirq(). + * \param pirq PIRQ to be used, PIRQ[A:H]. + * \param pin IRQ to be used, IRQ[0:15]. + * \param route_to_legacy Whether or not the interrupt should be routed to PIC 8259. + */ +void +pci_pirq_set_irq(PIRQ pirq, uint8_t irq, uint8_t route_to_legacy) +{ + pci_config_addr_t pci; + uint32_t value; + + assert(pirq >= PIRQA && pirq <= PIRQH); + assert(irq >= 0 && irq <= 0xF); + assert(route_to_legacy == 0 || route_to_legacy == 1); + + pci.raw = 0; + pci.bus = 0; + pci.dev = 31; + pci.func = 0; + pci.reg_off = (pirq <= PIRQD) ? 0x60 : 0x64; /* PABCDRC and PEFGHRC Registers */ + + value = pci_config_read(pci); + + switch(pirq) { + case PIRQA: + case PIRQE: + value &= ~0x8F; + value |= irq; + value |= (!route_to_legacy << 7); + break; + case PIRQB: + case PIRQF: + value &= ~0x8F00; + value |= (irq << 8); + value |= (!route_to_legacy << 15); + break; + case PIRQC: + case PIRQG: + value &= ~0x8F0000; + value |= (irq << 16); + value |= (!route_to_legacy << 23); + break; + case PIRQD: + case PIRQH: + value &= ~0x8F000000; + value |= (irq << 24); + value |= (!route_to_legacy << 31); + } + + set_addr(pci); + outl(PCI_CONFIG_DATA_PORT, value); +} +/*---------------------------------------------------------------------------*/ /** * \brief Initialize a structure for a PCI device driver that performs * MMIO to address range 0. Assumes that device has already diff --git a/cpu/x86/drivers/legacy_pc/pci.h b/cpu/x86/drivers/legacy_pc/pci.h index fca51ab69..0b7f21ce6 100644 --- a/cpu/x86/drivers/legacy_pc/pci.h +++ b/cpu/x86/drivers/legacy_pc/pci.h @@ -36,6 +36,37 @@ /** PCI configuration register identifier for Base Address Register 0 (BAR0) */ #define PCI_CONFIG_REG_BAR0 0x10 +/** PCI Interrupt Routing is mapped using Interrupt Queue Agents */ +typedef enum { + IRQAGENT0, + IRQAGENT1, + IRQAGENT2, + IRQAGENT3 +} IRQAGENT; + +/** PCI Interupt Pins */ +typedef enum { + INTA, + INTB, + INTC, + INTD +} INTR_PIN; + +/** + * PCI based interrupts PIRQ[A:H] are then available for consumption by either + * the 8259 PICs or the IO-APIC. + */ +typedef enum { + PIRQA, + PIRQB, + PIRQC, + PIRQD, + PIRQE, + PIRQF, + PIRQG, + PIRQH, +} PIRQ; + /** * PCI configuration address * @@ -66,5 +97,7 @@ typedef struct pci_driver { } pci_driver_t; void pci_init_bar0(pci_driver_t *c_this, pci_config_addr_t pci_addr); +int pci_irq_agent_set_pirq(IRQAGENT agent, INTR_PIN pin, PIRQ pirq); +void pci_pirq_set_irq(PIRQ pirq, uint8_t irq, uint8_t route_to_legacy); #endif /* CPU_X86_DRIVERS_LEGACY_PC_PCI_H_ */ From 6b433aede18a9275241653b721ea16ffae117fe2 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 29 Sep 2015 17:06:21 -0300 Subject: [PATCH 66/92] x86: Improve release binary size This patch adds -ffunction-sections and -fdata-sections to the 'release' CFLAGS so each function and data is place into its own section in the output file. It also adds --gc-section to the 'release' LDFLAGS so the linker removes the sections which are not referenced. This patch also adds -ffunction-sections and -fdata-sections options to CFLAGS from build_newlib.sh. This increases newlib static libraries size, however, the Contiki image shrinks even more since --gc-section removes "dead code" from newlib. As a practical effect, all unused function and data (as well as sections such as .eh_frame) are striped out from the final elf binary. This shrinks our release binary drastically. Finally, to prevent --gc-section from removing .multiboot section, this patch adds KEEP(*(.multiboot)) to quarkX1000.ld. --- cpu/x86/Makefile.x86_common | 6 ++++-- cpu/x86/quarkX1000.ld | 2 +- platform/galileo/bsp/libc/build_newlib.sh | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/cpu/x86/Makefile.x86_common b/cpu/x86/Makefile.x86_common index 0656dd0d6..d920327cf 100644 --- a/cpu/x86/Makefile.x86_common +++ b/cpu/x86/Makefile.x86_common @@ -13,8 +13,10 @@ CFLAGS += -Wall -fno-asynchronous-unwind-tables LDFLAGS += -Wl,-Map=contiki-$(TARGET).map,--build-id=none ifeq ($(BUILD_RELEASE),1) - CFLAGS += -Os -fno-strict-aliasing - LDFLAGS += -Wl,--strip-all + CFLAGS += -Os -fno-strict-aliasing -ffunction-sections -fdata-sections +# XXX: --gc-sections can be very tricky sometimes. If somehow the release +# binary seems to be broken, check if removing this option fixes the issue. + LDFLAGS += -Wl,--strip-all,--gc-sections else ifeq ($(findstring clang,$(CC)),clang) CFLAGS += -O0 -g diff --git a/cpu/x86/quarkX1000.ld b/cpu/x86/quarkX1000.ld index f9ff105c2..8beb425cf 100644 --- a/cpu/x86/quarkX1000.ld +++ b/cpu/x86/quarkX1000.ld @@ -41,7 +41,7 @@ SECTIONS { .text ALIGN (4K) : { - *(.multiboot) + KEEP(*(.multiboot)) *(.text*) } diff --git a/platform/galileo/bsp/libc/build_newlib.sh b/platform/galileo/bsp/libc/build_newlib.sh index a48cb2e4c..cee34f3ff 100755 --- a/platform/galileo/bsp/libc/build_newlib.sh +++ b/platform/galileo/bsp/libc/build_newlib.sh @@ -65,8 +65,8 @@ build() { export COMPILER_AS_FOR_TARGET=as export COMPILER_LD_FOR_TARGET=ld export COMPILER_NM_FOR_TARGET=nm - export CFLAGS_FOR_TARGET="-Os -m32 -march=i586 -mtune=i586 -fno-stack-protector -DPREFER_SIZE_OVER_SPEED" - export CXXFLAGS_FOR_TARGET="-Os -m32 -march=i586 -mtune=i586 -fno-stack-protector -DPREFER_SIZE_OVER_SPEED" + export CFLAGS_FOR_TARGET="-Os -m32 -march=i586 -mtune=i586 -fno-stack-protector -DPREFER_SIZE_OVER_SPEED -ffunction-sections -fdata-sections" + export CXXFLAGS_FOR_TARGET="-Os -m32 -march=i586 -mtune=i586 -fno-stack-protector -DPREFER_SIZE_OVER_SPEED -ffunction-sections -fdata-sections" mkdir -p install ./configure --target=${TARGET} \ From c6ef8454a1c39a618276405581b4bd4bb176b729 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 2 Oct 2015 09:19:15 -0300 Subject: [PATCH 67/92] x86: Use -O0 instead of -Og for debug build This patch replaces the gcc option '-Og' by '-O0' which is used when building debugging binaries. The motivation for this change comes from the fact that we have found at least one optimization done by '-Og' that interfered with one of our debugging sessions. --- cpu/x86/Makefile.x86_common | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cpu/x86/Makefile.x86_common b/cpu/x86/Makefile.x86_common index d920327cf..054cfcd68 100644 --- a/cpu/x86/Makefile.x86_common +++ b/cpu/x86/Makefile.x86_common @@ -18,9 +18,10 @@ ifeq ($(BUILD_RELEASE),1) # binary seems to be broken, check if removing this option fixes the issue. LDFLAGS += -Wl,--strip-all,--gc-sections else + CFLAGS += -O0 ifeq ($(findstring clang,$(CC)),clang) - CFLAGS += -O0 -g + CFLAGS += -g else - CFLAGS += -Og -ggdb3 + CFLAGS += -ggdb3 endif endif From 6dc27579bc9f0dc1361b72043c7eea4d991ece39 Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Wed, 8 Jul 2015 13:36:29 -0700 Subject: [PATCH 68/92] x86: Extend PCI driver module with support for metadata and configuration writes This patch adds the 'meta' field to the generic driver structure to point to optional driver-defined metadata. It also modifies the associated initialization routine to populate it and updates the 16X50 UART driver to use the new initialization routine signature. This patch also adds a function to perform PCI configuration register writes, definitions for the PCI Command configuration register address and some of the bits in that register, and a function to set additional bits in that register. Finally, it adds macros to help with performing MMIO to and from PCI devices. --- cpu/x86/drivers/legacy_pc/pci.c | 36 +++++++++++++++++++++++++- cpu/x86/drivers/legacy_pc/pci.h | 21 +++++++++++++-- cpu/x86/drivers/legacy_pc/uart-16x50.c | 2 +- 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/cpu/x86/drivers/legacy_pc/pci.c b/cpu/x86/drivers/legacy_pc/pci.c index a56be38fa..922a3db4b 100644 --- a/cpu/x86/drivers/legacy_pc/pci.c +++ b/cpu/x86/drivers/legacy_pc/pci.c @@ -63,6 +63,36 @@ pci_config_read(pci_config_addr_t addr) return inl(PCI_CONFIG_DATA_PORT); } /*---------------------------------------------------------------------------*/ +/** + * \brief Write to the PCI configuration data port. + * \param addr Address of PCI configuration register. + * \param data Value to write. + */ +void +pci_config_write(pci_config_addr_t addr, uint32_t data) +{ + set_addr(addr); + + outl(PCI_CONFIG_DATA_PORT, data); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Enable PCI command bits of the specified PCI configuration + * register. + * \param addr Address of PCI configuration register. + * \param flags Flags used to enable PCI command bits. + */ +void +pci_command_enable(pci_config_addr_t addr, uint32_t flags) +{ + uint32_t data; + + addr.reg_off = 0x04; /* PCI COMMAND_REGISTER */ + + data = pci_config_read(addr); + pci_config_write(addr, data | flags); +} +/*---------------------------------------------------------------------------*/ /** * \brief Set current PIRQ to interrupt queue agent. PCI based interrupts * PIRQ[A:H] are then available for consumption by either the 8259 @@ -201,12 +231,16 @@ pci_pirq_set_irq(PIRQ pirq, uint8_t irq, uint8_t route_to_legacy) * firmware. * \param c_this Structure that will be initialized to represent the driver. * \param pci_addr PCI base address of device. + * \param meta Base address of optional driver-defined metadata. */ void -pci_init_bar0(pci_driver_t *c_this, pci_config_addr_t pci_addr) +pci_init_bar0(pci_driver_t *c_this, + pci_config_addr_t pci_addr, + uintptr_t meta) { pci_addr.reg_off = PCI_CONFIG_REG_BAR0; /* The BAR0 value is masked to clear non-address bits. */ c_this->mmio = pci_config_read(pci_addr) & ~0xFFF; + c_this->meta = meta; } /*---------------------------------------------------------------------------*/ diff --git a/cpu/x86/drivers/legacy_pc/pci.h b/cpu/x86/drivers/legacy_pc/pci.h index 0b7f21ce6..180d0a074 100644 --- a/cpu/x86/drivers/legacy_pc/pci.h +++ b/cpu/x86/drivers/legacy_pc/pci.h @@ -32,6 +32,7 @@ #define CPU_X86_DRIVERS_LEGACY_PC_PCI_H_ #include +#include "helpers.h" /** PCI configuration register identifier for Base Address Register 0 (BAR0) */ #define PCI_CONFIG_REG_BAR0 0x10 @@ -67,6 +68,11 @@ typedef enum { PIRQH, } PIRQ; +/** PCI command register bit to enable bus mastering */ +#define PCI_CMD_2_BUS_MST_EN BIT(2) +/** PCI command register bit to enable memory space */ +#define PCI_CMD_1_MEM_SPACE_EN BIT(1) + /** * PCI configuration address * @@ -88,16 +94,27 @@ typedef union pci_config_addr { } pci_config_addr_t; uint32_t pci_config_read(pci_config_addr_t addr); +void pci_config_write(pci_config_addr_t addr, uint32_t data); +void pci_command_enable(pci_config_addr_t addr, uint32_t flags); /** - * PCI device driver instance with a single MMIO range. + * PCI device driver instance with an optional single MMIO range and optional + * metadata. */ typedef struct pci_driver { uintptr_t mmio; /**< MMIO range base address */ + uintptr_t meta; /**< Driver-defined metadata base address */ } pci_driver_t; -void pci_init_bar0(pci_driver_t *c_this, pci_config_addr_t pci_addr); +void pci_init_bar0(pci_driver_t *c_this, + pci_config_addr_t pci_addr, + uintptr_t meta); int pci_irq_agent_set_pirq(IRQAGENT agent, INTR_PIN pin, PIRQ pirq); void pci_pirq_set_irq(PIRQ pirq, uint8_t irq, uint8_t route_to_legacy); +#define PCI_MMIO_READL(c_this, dest, reg_addr) \ + dest = *((volatile uint32_t *)((c_this).mmio + (reg_addr))) +#define PCI_MMIO_WRITEL(c_this, reg_addr, src) \ + *((volatile uint32_t *)((c_this).mmio + (reg_addr))) = (src) + #endif /* CPU_X86_DRIVERS_LEGACY_PC_PCI_H_ */ diff --git a/cpu/x86/drivers/legacy_pc/uart-16x50.c b/cpu/x86/drivers/legacy_pc/uart-16x50.c index 090544ddc..1b9bab10b 100644 --- a/cpu/x86/drivers/legacy_pc/uart-16x50.c +++ b/cpu/x86/drivers/legacy_pc/uart-16x50.c @@ -79,7 +79,7 @@ uart_16x50_init(uart_16x50_driver_t *c_this, /* This assumes that the UART had an MMIO range assigned to it by the * firmware during boot. */ - pci_init_bar0(c_this, pci_addr); + pci_init_bar0(c_this, pci_addr, 0); uart_16x50_regs_t *regs = (uart_16x50_regs_t *)c_this->mmio; From 60f6edef804f22fa79724dcc2bcc2f3431a56395 Mon Sep 17 00:00:00 2001 From: Ricardo de Almeida Gonzaga Date: Thu, 10 Sep 2015 11:26:00 -0300 Subject: [PATCH 69/92] x86: Add support for PCI BAR1 This patch adds support for PCI BAR1 and also changes the pci_init(), instead of having one function for each `bar` we now set the `bar` to pci_config_addr_t parameter before calling the pci_init() function.. --- cpu/x86/drivers/legacy_pc/pci.c | 7 ++----- cpu/x86/drivers/legacy_pc/pci.h | 7 +++---- cpu/x86/drivers/legacy_pc/uart-16x50.c | 2 +- cpu/x86/drivers/quarkX1000/uart.c | 1 + 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/cpu/x86/drivers/legacy_pc/pci.c b/cpu/x86/drivers/legacy_pc/pci.c index 922a3db4b..2af9f4883 100644 --- a/cpu/x86/drivers/legacy_pc/pci.c +++ b/cpu/x86/drivers/legacy_pc/pci.c @@ -234,12 +234,9 @@ pci_pirq_set_irq(PIRQ pirq, uint8_t irq, uint8_t route_to_legacy) * \param meta Base address of optional driver-defined metadata. */ void -pci_init_bar0(pci_driver_t *c_this, - pci_config_addr_t pci_addr, - uintptr_t meta) +pci_init(pci_driver_t *c_this, pci_config_addr_t pci_addr, uintptr_t meta) { - pci_addr.reg_off = PCI_CONFIG_REG_BAR0; - /* The BAR0 value is masked to clear non-address bits. */ + /* The reg_off (BAR) value is masked to clear non-address bits. */ c_this->mmio = pci_config_read(pci_addr) & ~0xFFF; c_this->meta = meta; } diff --git a/cpu/x86/drivers/legacy_pc/pci.h b/cpu/x86/drivers/legacy_pc/pci.h index 180d0a074..c938f9c6c 100644 --- a/cpu/x86/drivers/legacy_pc/pci.h +++ b/cpu/x86/drivers/legacy_pc/pci.h @@ -34,8 +34,9 @@ #include #include "helpers.h" -/** PCI configuration register identifier for Base Address Register 0 (BAR0) */ +/** PCI configuration register identifier for Base Address Registers */ #define PCI_CONFIG_REG_BAR0 0x10 +#define PCI_CONFIG_REG_BAR1 0x14 /** PCI Interrupt Routing is mapped using Interrupt Queue Agents */ typedef enum { @@ -106,9 +107,7 @@ typedef struct pci_driver { uintptr_t meta; /**< Driver-defined metadata base address */ } pci_driver_t; -void pci_init_bar0(pci_driver_t *c_this, - pci_config_addr_t pci_addr, - uintptr_t meta); +void pci_init(pci_driver_t *c_this, pci_config_addr_t pci_addr, uintptr_t meta); int pci_irq_agent_set_pirq(IRQAGENT agent, INTR_PIN pin, PIRQ pirq); void pci_pirq_set_irq(PIRQ pirq, uint8_t irq, uint8_t route_to_legacy); diff --git a/cpu/x86/drivers/legacy_pc/uart-16x50.c b/cpu/x86/drivers/legacy_pc/uart-16x50.c index 1b9bab10b..296719faa 100644 --- a/cpu/x86/drivers/legacy_pc/uart-16x50.c +++ b/cpu/x86/drivers/legacy_pc/uart-16x50.c @@ -79,7 +79,7 @@ uart_16x50_init(uart_16x50_driver_t *c_this, /* This assumes that the UART had an MMIO range assigned to it by the * firmware during boot. */ - pci_init_bar0(c_this, pci_addr, 0); + pci_init(c_this, pci_addr, 0); uart_16x50_regs_t *regs = (uart_16x50_regs_t *)c_this->mmio; diff --git a/cpu/x86/drivers/quarkX1000/uart.c b/cpu/x86/drivers/quarkX1000/uart.c index ba56992c9..23731ba93 100644 --- a/cpu/x86/drivers/quarkX1000/uart.c +++ b/cpu/x86/drivers/quarkX1000/uart.c @@ -57,6 +57,7 @@ quarkX1000_uart_init(quarkX1000_uart_dev_t dev) /* PCI addresses from section 18.4 of Intel Quark SoC X1000 Datasheet. */ pci_addr.dev = 20; pci_addr.func = (dev == QUARK_X1000_UART_0) ? 1 : 5; + pci_addr.reg_off = PCI_CONFIG_REG_BAR0; uart_16x50_init((dev == QUARK_X1000_UART_0) ? &quarkX1000_uart0 : &quarkX1000_uart1, pci_addr, QUARK_X1000_UART_DL_115200); } From 2d552285cdb2beb4eb02e169ab49a87d522682ee Mon Sep 17 00:00:00 2001 From: Ricardo de Almeida Gonzaga Date: Thu, 10 Sep 2015 11:41:44 -0300 Subject: [PATCH 70/92] x86: Add Intel Quark X1000 GPIO Controller (non-legacy) support This patch adds the gpio.c and gpio.h files, which support access to GPIO Controller (non-legacy) configuration register through a function interface. It doesn't add interrupt support due to pinmux reasons. On Galileo Gen 2 we need to configure a pin as input/interrupt using pinmux and this can only be achieved through I2C. There's one pin exported by default as GPIO output and we used this one to test this driver. In the future, we plan to add an I2C driver and a pinmux configuration driver in order to solve this kind of problems. --- cpu/x86/Makefile.x86_quarkX1000 | 2 +- cpu/x86/drivers/quarkX1000/gpio.c | 184 ++++++++++++++++++++++++++++++ cpu/x86/drivers/quarkX1000/gpio.h | 61 ++++++++++ 3 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 cpu/x86/drivers/quarkX1000/gpio.c create mode 100644 cpu/x86/drivers/quarkX1000/gpio.h diff --git a/cpu/x86/Makefile.x86_quarkX1000 b/cpu/x86/Makefile.x86_quarkX1000 index 4cbdc94b6..2ef0b00e9 100644 --- a/cpu/x86/Makefile.x86_quarkX1000 +++ b/cpu/x86/Makefile.x86_quarkX1000 @@ -2,7 +2,7 @@ include $(CONTIKI)/cpu/x86/Makefile.x86_common CONTIKI_CPU_DIRS += drivers/legacy_pc drivers/quarkX1000 init/legacy_pc -CONTIKI_SOURCEFILES += bootstrap_quarkX1000.S rtc.c pit.c pic.c irq.c nmi.c pci.c uart-16x50.c uart.c +CONTIKI_SOURCEFILES += bootstrap_quarkX1000.S rtc.c pit.c pic.c irq.c nmi.c pci.c uart-16x50.c uart.c gpio.c CFLAGS += -m32 -march=i586 -mtune=i586 LDFLAGS += -m32 -Xlinker -T -Xlinker $(CONTIKI)/cpu/x86/quarkX1000.ld diff --git a/cpu/x86/drivers/quarkX1000/gpio.c b/cpu/x86/drivers/quarkX1000/gpio.c new file mode 100644 index 000000000..aa9932681 --- /dev/null +++ b/cpu/x86/drivers/quarkX1000/gpio.c @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gpio.h" +#include "helpers.h" + +/* GPIO Controler Registers */ +#define SWPORTA_DR 0x00 +#define SWPORTA_DDR 0x04 +#define INTEN 0x30 +#define INTMASK 0x34 +#define INTTYPE_LEVEL 0x38 +#define INT_POLARITY 0x3c +#define INTSTATUS 0x40 +#define RAW_INTSTATUS 0x44 +#define DEBOUNCE 0x48 +#define PORTA_EOI 0x4c +#define EXT_PORTA 0x50 +#define LS_SYNC 0x60 + +#define PINS 8 + +struct gpio_internal_data { + pci_driver_t pci; +}; + +static struct gpio_internal_data data; + +static inline uint32_t +read(uint32_t base_addr, uint32_t offset) +{ + return *(uint32_t*)(base_addr + offset); +} + +static inline void +write(uint32_t base_addr, uint32_t offset, uint32_t val) +{ + *(uint32_t*)(base_addr + offset) = val; +} + +/* value must be 0x0 or 0x1 */ +static void +set_bit(uint32_t base_addr, uint32_t offset, uint32_t bit, uint32_t value) +{ + uint32_t reg; + + reg = read(base_addr, offset); + + reg &= ~BIT(bit); + reg |= value << bit; + + write(base_addr, offset, reg); +} + +int +quarkX1000_gpio_config(uint8_t pin, int flags) +{ + if (((flags & QUARKX1000_GPIO_IN) && (flags & QUARKX1000_GPIO_OUT)) || + ((flags & QUARKX1000_GPIO_INT) && (flags & QUARKX1000_GPIO_OUT))) { + return -1; + } + + /* interrupts are not supported yet */ + if (flags & QUARKX1000_GPIO_INT) + return -1; + + /* set direction */ + set_bit(data.pci.mmio, SWPORTA_DDR, pin, !!(flags & QUARKX1000_GPIO_OUT)); + + /* set interrupt disabled */ + set_bit(data.pci.mmio, INTEN, pin, 0); + + return 0; +} + +int +quarkX1000_gpio_config_port(int flags) +{ + uint8_t i; + + for (i = 0; i < PINS; i++) { + if (quarkX1000_gpio_config(i, flags) < 0) { + return -1; + } + } + + return 0; +} + +int +quarkX1000_gpio_read(uint8_t pin, uint8_t *value) +{ + uint32_t value32 = read(data.pci.mmio, EXT_PORTA); + *value = !!(value32 & BIT(pin)); + + return 0; +} + +int +quarkX1000_gpio_write(uint8_t pin, uint8_t value) +{ + set_bit(data.pci.mmio, SWPORTA_DR, pin, !!value); + return 0; +} + +int +quarkX1000_gpio_read_port(uint8_t *value) +{ + uint32_t value32 = read(data.pci.mmio, EXT_PORTA); + *value = value32 & ~0xFFFFFF00; + + return 0; +} + +int +quarkX1000_gpio_write_port(uint8_t value) +{ + write(data.pci.mmio, SWPORTA_DR, value); + return 0; +} + +void +quarkX1000_gpio_clock_enable(void) +{ + set_bit(data.pci.mmio, LS_SYNC, 0, 1); +} + +void +quarkX1000_gpio_clock_disable(void) +{ + set_bit(data.pci.mmio, LS_SYNC, 0, 0); +} + +int +quarkX1000_gpio_init(void) +{ + pci_config_addr_t pci_addr; + + pci_addr.raw = 0; + pci_addr.bus = 0; + pci_addr.dev = 21; + pci_addr.func = 2; + pci_addr.reg_off = PCI_CONFIG_REG_BAR1; + + pci_command_enable(pci_addr, PCI_CMD_1_MEM_SPACE_EN); + + pci_init(&data.pci, pci_addr, 0); + + quarkX1000_gpio_clock_enable(); + + /* clear registers */ + write(data.pci.mmio, INTEN, 0); + write(data.pci.mmio, INTMASK, 0); + write(data.pci.mmio, PORTA_EOI, 0); + + return 0; +} diff --git a/cpu/x86/drivers/quarkX1000/gpio.h b/cpu/x86/drivers/quarkX1000/gpio.h new file mode 100644 index 000000000..6e434900f --- /dev/null +++ b/cpu/x86/drivers/quarkX1000/gpio.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CPU_X86_DRIVERS_QUARKX1000_GPIO_H_ +#define CPU_X86_DRIVERS_QUARKX1000_GPIO_H_ + +#include + +#include "pci.h" + +#define QUARKX1000_GPIO_IN (0 << 0) +#define QUARKX1000_GPIO_OUT (1 << 0) +#define QUARKX1000_GPIO_INT (1 << 1) +#define QUARKX1000_GPIO_ACTIVE_LOW (0 << 2) +#define QUARKX1000_GPIO_ACTIVE_HIGH (1 << 2) +#define QUARKX1000_GPIO_LEVEL (0 << 3) +#define QUARKX1000_GPIO_EDGE (1 << 3) +#define QUARKX1000_GPIO_DEBOUNCE (1 << 4) +#define QUARKX1000_GPIO_CLOCK_SYNC (1 << 5) + +int quarkX1000_gpio_init(void); + +int quarkX1000_gpio_config(uint8_t pin, int flags); +int quarkX1000_gpio_read(uint8_t pin, uint8_t *value); +int quarkX1000_gpio_write(uint8_t pin, uint8_t value); + +int quarkX1000_gpio_config_port(int flags); +int quarkX1000_gpio_read_port(uint8_t *value); +int quarkX1000_gpio_write_port(uint8_t value); + +void quarkX1000_gpio_clock_enable(void); +void quarkX1000_gpio_clock_disable(void); + +#endif /* CPU_X86_DRIVERS_QUARKX1000_GPIO_H_ */ From cc51f89b3154c5328e5cad5b1d8cfd0c12e1c053 Mon Sep 17 00:00:00 2001 From: Ricardo de Almeida Gonzaga Date: Thu, 24 Sep 2015 14:24:46 -0300 Subject: [PATCH 71/92] galileo: Add GPIO output example This patch introduces an example application to demonstrate how to use GPIO driver APIs to manipulate output pins. The application sets the GPIO 4 pin as output pin and toggles its state at every half second. --- examples/galileo/Makefile | 16 ++++++++ examples/galileo/README | 25 ++++++++++++ examples/galileo/gpio-output.c | 73 ++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+) create mode 100644 examples/galileo/Makefile create mode 100644 examples/galileo/README create mode 100644 examples/galileo/gpio-output.c diff --git a/examples/galileo/Makefile b/examples/galileo/Makefile new file mode 100644 index 000000000..95539c7e6 --- /dev/null +++ b/examples/galileo/Makefile @@ -0,0 +1,16 @@ +KNOWN_EXAMPLES = gpio-output + +ifneq ($(filter $(EXAMPLE),$(KNOWN_EXAMPLES)),) + CONTIKI_PROJECT = $(EXAMPLE) +else + CONTIKI_PROJECT = help +endif + +all: $(CONTIKI_PROJECT) + +CONTIKI = ../.. +include $(CONTIKI)/Makefile.include + +help: + @echo -e "\nSet the variable EXAMPLE to one of the following Galileo-specific examples:" + @for EXAMPLE in $(KNOWN_EXAMPLES); do echo $$EXAMPLE; done diff --git a/examples/galileo/README b/examples/galileo/README new file mode 100644 index 000000000..cdd2133a9 --- /dev/null +++ b/examples/galileo/README @@ -0,0 +1,25 @@ +Galileo Specific Examples +======================= + +This directory contains galileo-specific example applications to illustrate +how to use galileo APIs. + +In order to build a application, you should set the EXAMPLE environment +variable to the name of the application you want to build. For instance, if +you want to build gpio-output application, run the following command: +$ make TARGET=galileo EXAMPLE=gpio-output + +============ += GPIO = +============ + +GPIO Output +=========== + +This application shows how to use the GPIO driver APIs to manipulate output +pins. This application sets the GPIO 4 pin as output pin and toggles its +state at every half second. + +For a visual effect, you should wire shield pin IO1 to a led in a protoboard. +Once the application is running, you should see a blinking LED. + diff --git a/examples/galileo/gpio-output.c b/examples/galileo/gpio-output.c new file mode 100644 index 000000000..39a92516f --- /dev/null +++ b/examples/galileo/gpio-output.c @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "contiki.h" +#include "sys/ctimer.h" + +#include "gpio.h" + +#define PIN 4 /* IO1 */ + +static uint32_t value; +static struct ctimer timer; + +PROCESS(gpio_output_process, "GPIO Output Process"); +AUTOSTART_PROCESSES(&gpio_output_process); +/*---------------------------------------------------------------------------*/ +static void +timeout(void *data) +{ + /* toggle pin state */ + value = !value; + quarkX1000_gpio_write(PIN, value); + + ctimer_reset(&timer); +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(gpio_output_process, ev, data) +{ + PROCESS_BEGIN(); + + quarkX1000_gpio_init(); + quarkX1000_gpio_config(PIN, QUARKX1000_GPIO_OUT); + + quarkX1000_gpio_clock_enable(); + + ctimer_set(&timer, CLOCK_SECOND / 2, timeout, NULL); + + printf("GPIO output example is running\n"); + PROCESS_YIELD(); + + quarkX1000_gpio_clock_disable(); + + PROCESS_END(); +} From a27af5b395bdea390032e6ed65ed4e01893932db Mon Sep 17 00:00:00 2001 From: Ricardo de Almeida Gonzaga Date: Wed, 30 Sep 2015 09:32:16 -0300 Subject: [PATCH 72/92] x86: Add Intel Quark X1000 I2C support This patch adds the i2c.c, i2c.h and i2c-registers.h files, which support access to I2C controller configuration register through a function interface. --- cpu/x86/Makefile.x86_quarkX1000 | 2 +- cpu/x86/drivers/quarkX1000/i2c-registers.h | 156 +++++++ cpu/x86/drivers/quarkX1000/i2c.c | 512 +++++++++++++++++++++ cpu/x86/drivers/quarkX1000/i2c.h | 67 +++ 4 files changed, 736 insertions(+), 1 deletion(-) create mode 100644 cpu/x86/drivers/quarkX1000/i2c-registers.h create mode 100644 cpu/x86/drivers/quarkX1000/i2c.c create mode 100644 cpu/x86/drivers/quarkX1000/i2c.h diff --git a/cpu/x86/Makefile.x86_quarkX1000 b/cpu/x86/Makefile.x86_quarkX1000 index 2ef0b00e9..8e78fd95e 100644 --- a/cpu/x86/Makefile.x86_quarkX1000 +++ b/cpu/x86/Makefile.x86_quarkX1000 @@ -2,7 +2,7 @@ include $(CONTIKI)/cpu/x86/Makefile.x86_common CONTIKI_CPU_DIRS += drivers/legacy_pc drivers/quarkX1000 init/legacy_pc -CONTIKI_SOURCEFILES += bootstrap_quarkX1000.S rtc.c pit.c pic.c irq.c nmi.c pci.c uart-16x50.c uart.c gpio.c +CONTIKI_SOURCEFILES += bootstrap_quarkX1000.S rtc.c pit.c pic.c irq.c nmi.c pci.c uart-16x50.c uart.c gpio.c i2c.c CFLAGS += -m32 -march=i586 -mtune=i586 LDFLAGS += -m32 -Xlinker -T -Xlinker $(CONTIKI)/cpu/x86/quarkX1000.ld diff --git a/cpu/x86/drivers/quarkX1000/i2c-registers.h b/cpu/x86/drivers/quarkX1000/i2c-registers.h new file mode 100644 index 000000000..7b9e4cec0 --- /dev/null +++ b/cpu/x86/drivers/quarkX1000/i2c-registers.h @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CPU_X86_DRIVERS_QUARKX1000_I2C_REGISTERS_H_ +#define CPU_X86_DRIVERS_QUARKX1000_I2C_REGISTERS_H_ + +#define QUARKX1000_IC_CON 0x00 +#define QUARKX1000_IC_TAR 0x04 +#define QUARKX1000_IC_DATA_CMD 0x10 +#define QUARKX1000_IC_SS_SCL_HCNT 0x14 +#define QUARKX1000_IC_SS_SCL_LCNT 0x18 +#define QUARKX1000_IC_FS_SCL_HCNT 0x1C +#define QUARKX1000_IC_FS_SCL_LCNT 0x20 +#define QUARKX1000_IC_INTR_STAT 0x2C +#define QUARKX1000_IC_INTR_MASK 0x30 +#define QUARKX1000_IC_RAW_INTR_STAT 0x34 +#define QUARKX1000_IC_RX_TL 0x38 +#define QUARKX1000_IC_TX_TL 0x3C +#define QUARKX1000_IC_CLR_INTR 0x40 +#define QUARKX1000_IC_CLR_RX_UNDER 0x44 +#define QUARKX1000_IC_CLR_RX_OVER 0x48 +#define QUARKX1000_IC_CLR_TX_OVER 0x4C +#define QUARKX1000_IC_CLR_RD_REQ 0x50 +#define QUARKX1000_IC_CLR_TX_ABRT 0x54 +#define QUARKX1000_IC_CLR_ACTIVITY 0x5C +#define QUARKX1000_IC_CLR_STOP_DET 0x60 +#define QUARKX1000_IC_CLR_START_DET 0x64 +#define QUARKX1000_IC_ENABLE 0x6C +#define QUARKX1000_IC_STATUS 0x70 +#define QUARKX1000_IC_TXFLR 0x74 +#define QUARKX1000_IC_RXFLR 0x78 +#define QUARKX1000_IC_SDA_HOLD 0x7C +#define QUARKX1000_IC_TX_ABRT_SOURCE 0x80 +#define QUARKX1000_IC_ENABLE_STATUS 0x9C +#define QUARKX1000_IC_FS_SPKLEN 0xA0 + +/* IC_CON */ +#define QUARKX1000_IC_CON_MASTER_MODE_SHIFT 0 +#define QUARKX1000_IC_CON_MASTER_MODE_MASK 0x01 +#define QUARKX1000_IC_CON_SPEED_SHIFT 1 +#define QUARKX1000_IC_CON_SPEED_MASK 0x06 +#define QUARKX1000_IC_CON_10BITADDR_MASTER_SHIFT 4 +#define QUARKX1000_IC_CON_10BITADDR_MASTER_MASK 0x10 +#define QUARKX1000_IC_CON_RESTART_EN_SHIFT 5 +#define QUARKX1000_IC_CON_RESTART_EN_MASK 0x20 + +/* IC_TAR */ +#define QUARKX1000_IC_TAR_SHIFT 0 +#define QUARKX1000_IC_TAR_MASK 0x3FF + +/* IC_DATA_CMD */ +#define QUARKX1000_IC_DATA_CMD_DAT_SHIFT 0 +#define QUARKX1000_IC_DATA_CMD_DAT_MASK 0x0FF +#define QUARKX1000_IC_DATA_CMD_CMD_SHIFT 8 +#define QUARKX1000_IC_DATA_CMD_CMD_MASK 0x100 +#define QUARKX1000_IC_DATA_CMD_STOP_SHIFT 9 +#define QUARKX1000_IC_DATA_CMD_STOP_MASK 0x200 +#define QUARKX1000_IC_DATA_CMD_RESTART_SHIFT 10 +#define QUARKX1000_IC_DATA_CMD_RESTART_MASK 0x400 + +/* IC_SS_SCL_HCNT */ +#define QUARKX1000_IC_SS_SCL_HCNT_SHIFT 0 +#define QUARKX1000_IC_SS_SCL_HCNT_MASK 0xFFFF + +/* IC_SS_SCL_LCNT */ +#define QUARKX1000_IC_SS_SCL_LCNT_SHIFT 0 +#define QUARKX1000_IC_SS_SCL_LCNT_MASK 0xFFFF + +/* IC_FS_SCL_HCNT */ +#define QUARKX1000_IC_FS_SCL_HCNT_SHIFT 0 +#define QUARKX1000_IC_FS_SCL_HCNT_MASK 0xFFFF + +/* IC_FS_SCL_LCNT */ +#define QUARKX1000_IC_FS_SCL_LCNT_SHIFT 0 +#define QUARKX1000_IC_FS_SCL_LCNT_MASK 0xFFFF + +/* IC_INTR_STAT */ +#define QUARKX1000_IC_INTR_STAT_RX_UNDER_SHIFT 0 +#define QUARKX1000_IC_INTR_STAT_RX_UNDER_MASK 0x001 +#define QUARKX1000_IC_INTR_STAT_RX_OVER_SHIFT 1 +#define QUARKX1000_IC_INTR_STAT_RX_OVER_MASK 0x002 +#define QUARKX1000_IC_INTR_STAT_RX_FULL_SHIFT 2 +#define QUARKX1000_IC_INTR_STAT_RX_FULL_MASK 0x004 +#define QUARKX1000_IC_INTR_STAT_TX_OVER_SHIFT 3 +#define QUARKX1000_IC_INTR_STAT_TX_OVER_MASK 0x008 +#define QUARKX1000_IC_INTR_STAT_TX_EMPTY_SHIFT 4 +#define QUARKX1000_IC_INTR_STAT_TX_EMPTY_MASK 0x010 +#define QUARKX1000_IC_INTR_STAT_RD_REQ_SHIFT 5 +#define QUARKX1000_IC_INTR_STAT_RD_REQ_MASK 0x020 +#define QUARKX1000_IC_INTR_STAT_TX_ABRT_SHIFT 6 +#define QUARKX1000_IC_INTR_STAT_TX_ABRT_MASK 0x040 +#define QUARKX1000_IC_INTR_STAT_ACTIVITY_SHIFT 8 +#define QUARKX1000_IC_INTR_STAT_ACTIVITY_MASK 0x100 +#define QUARKX1000_IC_INTR_STAT_STOP_DET_SHIFT 9 +#define QUARKX1000_IC_INTR_STAT_STOP_DET_MASK 0x200 +#define QUARKX1000_IC_INTR_STAT_START_DET_SHIFT 10 +#define QUARKX1000_IC_INTR_STAT_START_DET_MASK 0x400 + +/* IC_ENABLE */ +#define QUARKX1000_IC_ENABLE_SHIFT 0 +#define QUARKX1000_IC_ENABLE_MASK 0x01 + +/* IC_STATUS */ +#define QUARKX1000_IC_STATUS_ACTIVITY_SHIFT 0 +#define QUARKX1000_IC_STATUS_ACTIVITY_MASK 0x01 +#define QUARKX1000_IC_STATUS_TFNF_SHIFT 1 +#define QUARKX1000_IC_STATUS_TFNF_MASK 0x02 +#define QUARKX1000_IC_STATUS_TFE_SHIFT 2 +#define QUARKX1000_IC_STATUS_TFE_MASK 0x04 +#define QUARKX1000_IC_STATUS_RFNE_SHIFT 3 +#define QUARKX1000_IC_STATUS_RFNE_MASK 0x08 +#define QUARKX1000_IC_STATUS_RFF_SHIFT 4 +#define QUARKX1000_IC_STATUS_RFF_MASK 0x10 +#define QUARKX1000_IC_STATUS_MST_ACTIVITY_SHIFT 5 +#define QUARKX1000_IC_STATUS_MST_ACTIVITY_MASK 0x20 + +/* IC_TXFLR */ +#define QUARKX1000_IC_TXFLR_SHIFT 0 +#define QUARKX1000_IC_TXFLR_MASK 0x1F + +/* IC_RXFLR */ +#define QUARKX1000_IC_RXFLR_SHIFT 0 +#define QUARKX1000_IC_RXFLR_MASK 0x1F + +/* IC_FS_SPKLEN */ +#define QUARKX1000_IC_FS_SPKLEN_SHIFT 0 +#define QUARKX1000_IC_FS_SPKLEN_MASK 0xFF + +#endif /* CPU_X86_DRIVERS_QUARKX1000_I2C_REGISTERS_H_ */ diff --git a/cpu/x86/drivers/quarkX1000/i2c.c b/cpu/x86/drivers/quarkX1000/i2c.c new file mode 100644 index 000000000..bf7b6110a --- /dev/null +++ b/cpu/x86/drivers/quarkX1000/i2c.c @@ -0,0 +1,512 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "contiki.h" +#include "i2c.h" +#include "i2c-registers.h" +#include "interrupt.h" +#include "pic.h" + +#define I2C_CLOCK_SPEED 25 /* kHz */ +#define I2C_FIFO_DEPTH 16 + +#define I2C_STD_HCNT (I2C_CLOCK_SPEED * 4) +#define I2C_STD_LCNT (I2C_CLOCK_SPEED * 5) +#define I2C_FS_HCNT (I2C_CLOCK_SPEED) +#define I2C_FS_LCNT (I2C_CLOCK_SPEED) + +#define I2C_FS_SPKLEN_LCNT_OFFSET 8 +#define I2C_FS_SPKLEN_HCNT_OFFSET 6 + +#define I2C_POLLING_TIMEOUT (CLOCK_SECOND / 10) + +#define I2C_IRQ 9 +#define I2C_INT PIC_INT(I2C_IRQ) + +typedef enum { + I2C_DIRECTION_READ, + I2C_DIRECTION_WRITE +} I2C_DIRECTION; + +struct i2c_internal_data { + struct quarkX1000_i2c_config config; + + pci_driver_t pci; + + I2C_DIRECTION direction; + + uint8_t rx_len; + uint8_t *rx_buffer; + uint8_t tx_len; + uint8_t *tx_buffer; + uint8_t rx_tx_len; + + uint32_t hcnt; + uint32_t lcnt; +}; + +static struct i2c_internal_data device; + +static uint32_t +read(uint32_t base_addr, uint32_t offset) +{ + return *(uint32_t*)(base_addr + offset); +} + +static void +write(uint32_t base_addr, uint32_t offset, uint32_t val) +{ + *(uint32_t*)(base_addr + offset) = val; +} + +static uint32_t +get_value(uint32_t base_addr, uint32_t offset, uint32_t mask, uint32_t shift) +{ + uint32_t register_value = *(uint32_t*)(base_addr + offset); + + register_value &= ~(0xFFFFFFFF - mask); + + return register_value >> shift; +} + +static void +set_value(uint32_t base_addr, uint32_t offset, uint32_t mask, uint32_t shift, uint32_t value) +{ + volatile uint32_t *register_value = (volatile uint32_t*)(base_addr + offset); + + *register_value &= ~mask; + *register_value |= value << shift; +} + +static void +i2c_data_read(void) +{ + uint8_t i, rx_cnt; + + if (device.rx_len == 0) + return; + + rx_cnt = get_value(device.pci.mmio, QUARKX1000_IC_RXFLR, + QUARKX1000_IC_RXFLR_MASK, QUARKX1000_IC_RXFLR_SHIFT); + + if (rx_cnt > device.rx_len) + rx_cnt = device.rx_len; + + for (i = 0; i < rx_cnt; i++) { + device.rx_buffer[i] = get_value(device.pci.mmio, QUARKX1000_IC_DATA_CMD, + QUARKX1000_IC_DATA_CMD_DAT_MASK, QUARKX1000_IC_DATA_CMD_DAT_SHIFT); + } + + device.rx_buffer += i; + device.rx_len -= i; +} + +static void +i2c_data_send(void) +{ + uint32_t data = 0; + uint8_t i, tx_cnt; + + if (device.rx_tx_len == 0) + return; + + tx_cnt = I2C_FIFO_DEPTH - get_value(device.pci.mmio, QUARKX1000_IC_TXFLR, + QUARKX1000_IC_TXFLR_MASK, QUARKX1000_IC_TXFLR_SHIFT); + + if (tx_cnt > device.rx_tx_len) + tx_cnt = device.rx_tx_len; + + for (i = 0; i < tx_cnt; i++) { + if (device.tx_len > 0) { + data = device.tx_buffer[i]; + + if (device.tx_len == 1) + data |= (device.rx_len > 0) ? QUARKX1000_IC_DATA_CMD_RESTART_MASK : QUARKX1000_IC_DATA_CMD_STOP_MASK; + + device.tx_len -= 1; + } else { + data = QUARKX1000_IC_DATA_CMD_CMD_MASK; + + if (device.rx_tx_len == 1) + data |= QUARKX1000_IC_DATA_CMD_STOP_MASK; + } + + write(device.pci.mmio, QUARKX1000_IC_DATA_CMD, data); + device.rx_tx_len -= 1; + } + + device.tx_buffer += i; +} + +static void +i2c_isr(void) +{ + if (read(device.pci.mmio, QUARKX1000_IC_INTR_STAT) & QUARKX1000_IC_INTR_STAT_STOP_DET_MASK) { + i2c_data_read(); + + write(device.pci.mmio, QUARKX1000_IC_INTR_MASK, 0); + read(device.pci.mmio, QUARKX1000_IC_CLR_INTR); + + if (device.direction == I2C_DIRECTION_WRITE) { + if (device.config.cb_tx) + device.config.cb_tx(); + } else { + if (device.config.cb_rx) + device.config.cb_rx(); + } + } + + if (read(device.pci.mmio, QUARKX1000_IC_INTR_STAT) & QUARKX1000_IC_INTR_STAT_TX_EMPTY_MASK) { + i2c_data_send(); + if (device.rx_tx_len <= 0) { + set_value(device.pci.mmio, QUARKX1000_IC_INTR_MASK, + QUARKX1000_IC_INTR_STAT_TX_EMPTY_MASK, QUARKX1000_IC_INTR_STAT_TX_EMPTY_SHIFT, 0); + set_value(device.pci.mmio, QUARKX1000_IC_INTR_MASK, + QUARKX1000_IC_INTR_STAT_STOP_DET_MASK, QUARKX1000_IC_INTR_STAT_STOP_DET_SHIFT, 1); + } + } + + if (read(device.pci.mmio, QUARKX1000_IC_INTR_STAT) & QUARKX1000_IC_INTR_STAT_RX_FULL_MASK) + i2c_data_read(); + + if (read(device.pci.mmio, QUARKX1000_IC_INTR_STAT) & (QUARKX1000_IC_INTR_STAT_TX_ABRT_MASK + | QUARKX1000_IC_INTR_STAT_TX_OVER_MASK | QUARKX1000_IC_INTR_STAT_RX_OVER_MASK + | QUARKX1000_IC_INTR_STAT_RX_UNDER_MASK)) { + write(device.pci.mmio, QUARKX1000_IC_INTR_MASK, 0); + read(device.pci.mmio, QUARKX1000_IC_CLR_INTR); + + if (device.config.cb_err) + device.config.cb_err(); + } +} + +int +quarkX1000_i2c_configure(struct quarkX1000_i2c_config *config) +{ + uint32_t hcnt, lcnt; + uint8_t ic_fs_spklen; + + device.config.speed = config->speed; + device.config.addressing_mode = config->addressing_mode; + device.config.cb_rx = config->cb_rx; + device.config.cb_tx = config->cb_tx; + device.config.cb_err = config->cb_err; + + if (device.config.speed == QUARKX1000_I2C_SPEED_STANDARD) { + lcnt = I2C_STD_LCNT; + hcnt = I2C_STD_HCNT; + } else { + lcnt = I2C_FS_LCNT; + hcnt = I2C_FS_HCNT; + } + + ic_fs_spklen = get_value(device.pci.mmio, QUARKX1000_IC_FS_SPKLEN, + QUARKX1000_IC_FS_SPKLEN_MASK, QUARKX1000_IC_FS_SPKLEN_SHIFT); + + /* We adjust the Low Count and High Count based on the Spike Suppression Limit */ + device.lcnt = (lcnt < (ic_fs_spklen + I2C_FS_SPKLEN_LCNT_OFFSET)) ? ic_fs_spklen + I2C_FS_SPKLEN_LCNT_OFFSET : lcnt; + device.hcnt = (hcnt < (ic_fs_spklen + I2C_FS_SPKLEN_HCNT_OFFSET)) ? ic_fs_spklen + I2C_FS_SPKLEN_HCNT_OFFSET : hcnt; + + /* Clear interrupts. */ + read(device.pci.mmio, QUARKX1000_IC_CLR_INTR); + + return 0; +} + +static int +i2c_setup(void) +{ + /* Clear all values */ + write(device.pci.mmio, QUARKX1000_IC_CON, 0); + + /* Clear interrupts */ + read(device.pci.mmio, QUARKX1000_IC_CLR_INTR); + + /* Quark X1000 SoC I2C only supports master mode. */ + set_value(device.pci.mmio, QUARKX1000_IC_CON, + QUARKX1000_IC_CON_MASTER_MODE_MASK, QUARKX1000_IC_CON_MASTER_MODE_SHIFT, 1); + + /* Set restart enable */ + set_value(device.pci.mmio, QUARKX1000_IC_CON, + QUARKX1000_IC_CON_RESTART_EN_MASK, QUARKX1000_IC_CON_RESTART_EN_SHIFT, 1); + + /* Set addressing mode */ + if (device.config.addressing_mode == QUARKX1000_I2C_ADDR_MODE_10BIT) { + set_value(device.pci.mmio, QUARKX1000_IC_CON, + QUARKX1000_IC_CON_10BITADDR_MASTER_MASK, QUARKX1000_IC_CON_10BITADDR_MASTER_SHIFT, 1); + } + + if (device.config.speed == QUARKX1000_I2C_SPEED_STANDARD) { + set_value(device.pci.mmio, QUARKX1000_IC_SS_SCL_LCNT, + QUARKX1000_IC_SS_SCL_LCNT_MASK, QUARKX1000_IC_SS_SCL_LCNT_SHIFT, device.lcnt); + set_value(device.pci.mmio, QUARKX1000_IC_SS_SCL_HCNT, + QUARKX1000_IC_SS_SCL_HCNT_MASK, QUARKX1000_IC_SS_SCL_HCNT_SHIFT, device.hcnt); + set_value(device.pci.mmio, QUARKX1000_IC_CON, + QUARKX1000_IC_CON_SPEED_MASK, QUARKX1000_IC_CON_SPEED_SHIFT, 0x1); + } else { + set_value(device.pci.mmio, QUARKX1000_IC_FS_SCL_LCNT, + QUARKX1000_IC_FS_SCL_LCNT_MASK, QUARKX1000_IC_FS_SCL_LCNT_SHIFT, device.lcnt); + set_value(device.pci.mmio, QUARKX1000_IC_FS_SCL_HCNT, + QUARKX1000_IC_FS_SCL_HCNT_MASK, QUARKX1000_IC_FS_SCL_HCNT_SHIFT, device.hcnt); + set_value(device.pci.mmio, QUARKX1000_IC_CON, + QUARKX1000_IC_CON_SPEED_MASK, QUARKX1000_IC_CON_SPEED_SHIFT, 0x2); + } + + return 0; +} + +static void +i2c_operation_setup(uint8_t *write_buf, uint8_t write_len, + uint8_t *read_buf, uint8_t read_len, uint16_t addr) +{ + device.rx_len = read_len; + device.rx_buffer = read_buf; + device.tx_len = write_len; + device.tx_buffer = write_buf; + device.rx_tx_len = device.rx_len + device.tx_len; + + /* Disable controller */ + set_value(device.pci.mmio, QUARKX1000_IC_ENABLE, + QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 0); + + i2c_setup(); + + /* Disable interrupts */ + write(device.pci.mmio, QUARKX1000_IC_INTR_MASK, 0); + + /* Clear interrupts */ + read(device.pci.mmio, QUARKX1000_IC_CLR_INTR); + + /* Set address of target slave */ + set_value(device.pci.mmio, QUARKX1000_IC_TAR, + QUARKX1000_IC_TAR_MASK, QUARKX1000_IC_TAR_SHIFT, addr); +} + +/* This is an interrupt based operation */ +static int +i2c_operation(uint8_t *write_buf, uint8_t write_len, + uint8_t *read_buf, uint8_t read_len, uint16_t addr) +{ + if (read(device.pci.mmio, QUARKX1000_IC_STATUS) & QUARKX1000_IC_STATUS_ACTIVITY_MASK) + return -1; + + i2c_operation_setup(write_buf, write_len, read_buf, read_len, addr); + + /* Enable master TX and RX interrupts */ + set_value(device.pci.mmio, QUARKX1000_IC_INTR_MASK, + QUARKX1000_IC_INTR_STAT_TX_OVER_MASK, QUARKX1000_IC_INTR_STAT_TX_OVER_SHIFT, 1); + set_value(device.pci.mmio, QUARKX1000_IC_INTR_MASK, + QUARKX1000_IC_INTR_STAT_TX_EMPTY_MASK, QUARKX1000_IC_INTR_STAT_TX_EMPTY_SHIFT, 1); + set_value(device.pci.mmio, QUARKX1000_IC_INTR_MASK, + QUARKX1000_IC_INTR_STAT_TX_ABRT_MASK, QUARKX1000_IC_INTR_STAT_TX_ABRT_SHIFT, 1); + set_value(device.pci.mmio, QUARKX1000_IC_INTR_MASK, + QUARKX1000_IC_INTR_STAT_RX_UNDER_MASK, QUARKX1000_IC_INTR_STAT_RX_UNDER_SHIFT, 1); + set_value(device.pci.mmio, QUARKX1000_IC_INTR_MASK, + QUARKX1000_IC_INTR_STAT_RX_OVER_MASK, QUARKX1000_IC_INTR_STAT_RX_OVER_SHIFT, 1); + set_value(device.pci.mmio, QUARKX1000_IC_INTR_MASK, + QUARKX1000_IC_INTR_STAT_RX_FULL_MASK, QUARKX1000_IC_INTR_STAT_RX_FULL_SHIFT, 1); + set_value(device.pci.mmio, QUARKX1000_IC_INTR_MASK, + QUARKX1000_IC_INTR_STAT_STOP_DET_MASK, QUARKX1000_IC_INTR_STAT_STOP_DET_SHIFT, 1); + + /* Enable controller */ + set_value(device.pci.mmio, QUARKX1000_IC_ENABLE, + QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 1); + + return 0; +} + +/* This is an interrupt based write */ +int +quarkX1000_i2c_write(uint8_t *buf, uint8_t len, uint16_t addr) +{ + device.direction = I2C_DIRECTION_WRITE; + return i2c_operation(buf, len, 0, 0, addr); +} + +/* This is an interrupt based read */ +int +quarkX1000_i2c_read(uint8_t *buf, uint8_t len, uint16_t addr) +{ + device.direction = I2C_DIRECTION_READ; + return i2c_operation(0, 0, buf, len, addr); +} + +static int +i2c_polling_operation(uint8_t *write_buf, uint8_t write_len, + uint8_t *read_buf, uint8_t read_len, uint16_t addr) +{ + uint32_t start_time, intr_mask_stat; + + if (!(read(device.pci.mmio, QUARKX1000_IC_CON) & QUARKX1000_IC_CON_MASTER_MODE_MASK)) + return -1; + + /* Wait i2c idle */ + start_time = clock_seconds(); + while (read(device.pci.mmio, QUARKX1000_IC_STATUS) & QUARKX1000_IC_STATUS_ACTIVITY_MASK) { + if ((clock_seconds() - start_time) > I2C_POLLING_TIMEOUT) { + return -1; + } + } + + /* Get interrupt mask to restore in the end of polling operation */ + intr_mask_stat = read(device.pci.mmio, QUARKX1000_IC_INTR_MASK); + + i2c_operation_setup(write_buf, write_len, read_buf, read_len, addr); + + /* Enable controller */ + set_value(device.pci.mmio, QUARKX1000_IC_ENABLE, + QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 1); + + /* Transmit */ + if (device.tx_len != 0) { + while (device.tx_len > 0) { + start_time = clock_seconds(); + while (!(read(device.pci.mmio, QUARKX1000_IC_STATUS) & QUARKX1000_IC_STATUS_TFNF_MASK)) { + if ((clock_seconds() - start_time) > I2C_POLLING_TIMEOUT) { + set_value(device.pci.mmio, QUARKX1000_IC_ENABLE, + QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 0); + return -1; + } + } + i2c_data_send(); + } + + start_time = clock_seconds(); + while (!(read(device.pci.mmio, QUARKX1000_IC_STATUS) & QUARKX1000_IC_STATUS_TFE_MASK)) { + if ((clock_seconds() - start_time) > I2C_POLLING_TIMEOUT) { + set_value(device.pci.mmio, QUARKX1000_IC_ENABLE, + QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 0); + return -1; + } + } + } + + i2c_data_send(); + + /* Receive */ + if (device.rx_len != 0) { + while (device.rx_len > 0) { + start_time = clock_seconds(); + while (!(read(device.pci.mmio, QUARKX1000_IC_STATUS) & QUARKX1000_IC_STATUS_RFNE_MASK)) { + if ((clock_seconds() - start_time) > I2C_POLLING_TIMEOUT) { + set_value(device.pci.mmio, QUARKX1000_IC_ENABLE, + QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 0); + return -1; + } + } + i2c_data_read(); + } + } + + /* Stop Det */ + start_time = clock_seconds(); + while (!(read(device.pci.mmio, QUARKX1000_IC_RAW_INTR_STAT) & QUARKX1000_IC_INTR_STAT_STOP_DET_MASK)) { + if ((clock_seconds() - start_time) > I2C_POLLING_TIMEOUT) { + set_value(device.pci.mmio, QUARKX1000_IC_ENABLE, + QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 0); + return -1; + } + } + read(device.pci.mmio, QUARKX1000_IC_CLR_STOP_DET); + + /* Wait i2c idle */ + start_time = clock_seconds(); + while (read(device.pci.mmio, QUARKX1000_IC_STATUS) & QUARKX1000_IC_STATUS_ACTIVITY_MASK) { + if ((clock_seconds() - start_time) > I2C_POLLING_TIMEOUT) { + set_value(device.pci.mmio, QUARKX1000_IC_ENABLE, + QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 0); + return -1; + } + } + + /* Disable controller */ + set_value(device.pci.mmio, QUARKX1000_IC_ENABLE, + QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 0); + + /* Restore interrupt mask */ + write(device.pci.mmio, QUARKX1000_IC_INTR_MASK, intr_mask_stat); + + return 0; +} + +int +quarkX1000_i2c_polling_write(uint8_t *buf, uint8_t len, uint16_t addr) +{ + device.direction = I2C_DIRECTION_WRITE; + return i2c_polling_operation(buf, len, 0, 0, addr); +} + +int +quarkX1000_i2c_polling_read(uint8_t *buf, uint8_t len, uint16_t addr) +{ + device.direction = I2C_DIRECTION_READ; + return i2c_polling_operation(0, 0, buf, len ,addr); +} + +int +quarkX1000_i2c_is_available(void) +{ + return device.pci.mmio ? 1 : 0; +} + +static void +i2c_handler() +{ + i2c_isr(); + + pic_eoi(I2C_IRQ); +} + +int +quarkX1000_i2c_init(void) +{ + pci_config_addr_t pci_addr; + + pci_addr.raw = 0; + pci_addr.bus = 0; + pci_addr.dev = 21; + pci_addr.func = 2; + pci_addr.reg_off = PCI_CONFIG_REG_BAR0; + + pci_command_enable(pci_addr, PCI_CMD_1_MEM_SPACE_EN); + + SET_INTERRUPT_HANDLER(I2C_INT, 0, i2c_handler); + + if (pci_irq_agent_set_pirq(IRQAGENT3, INTC, PIRQC) < 0) + return -1; + + pci_pirq_set_irq(PIRQC, I2C_IRQ, 1); + + pci_init(&device.pci, pci_addr, 0); + + pic_unmask_irq(I2C_IRQ); + + return 0; +} diff --git a/cpu/x86/drivers/quarkX1000/i2c.h b/cpu/x86/drivers/quarkX1000/i2c.h new file mode 100644 index 000000000..b5292524f --- /dev/null +++ b/cpu/x86/drivers/quarkX1000/i2c.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CPU_X86_DRIVERS_QUARKX1000_I2C_H_ +#define CPU_X86_DRIVERS_QUARKX1000_I2C_H_ + +#include "pci.h" + +typedef enum { + QUARKX1000_I2C_SPEED_STANDARD, + QUARKX1000_I2C_SPEED_FAST +} QUARKX1000_I2C_SPEED; + +typedef enum { + QUARKX1000_I2C_ADDR_MODE_7BIT, + QUARKX1000_I2C_ADDR_MODE_10BIT +} QUARKX1000_I2C_ADDR_MODE; + +typedef void (*quarkX1000_i2c_callback)(void); + +struct quarkX1000_i2c_config { + QUARKX1000_I2C_SPEED speed; + QUARKX1000_I2C_ADDR_MODE addressing_mode; + + quarkX1000_i2c_callback cb_rx; + quarkX1000_i2c_callback cb_tx; + quarkX1000_i2c_callback cb_err; +}; + +int quarkX1000_i2c_init(void); +int quarkX1000_i2c_configure(struct quarkX1000_i2c_config *config); +int quarkX1000_i2c_is_available(void); + +int quarkX1000_i2c_read(uint8_t *buf, uint8_t len, uint16_t addr); +int quarkX1000_i2c_write(uint8_t *buf, uint8_t len, uint16_t addr); + +int quarkX1000_i2c_polling_read(uint8_t *buf, uint8_t len, uint16_t addr); +int quarkX1000_i2c_polling_write(uint8_t *buf, uint8_t len, uint16_t addr); + +#endif /* CPU_X86_DRIVERS_QUARKX1000_I2C_H_ */ From 7dfd753b21b9e921fe7c7629091a8292445ed832 Mon Sep 17 00:00:00 2001 From: Ricardo de Almeida Gonzaga Date: Wed, 7 Oct 2015 10:16:39 -0300 Subject: [PATCH 73/92] galileo: Add I2C master example This patch adds an example application that shows how to use I2C driver APIs to communicate with LSM9DS0 sensor. At every 5 seconds, the application reads the "Who Am I" register from gyroscope sensor and prints if the register value matches the expected value. --- examples/galileo/Makefile | 4 +- examples/galileo/README | 30 ++++++++++ examples/galileo/i2c-LSM9DS0.c | 102 +++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 examples/galileo/i2c-LSM9DS0.c diff --git a/examples/galileo/Makefile b/examples/galileo/Makefile index 95539c7e6..6af6b61e3 100644 --- a/examples/galileo/Makefile +++ b/examples/galileo/Makefile @@ -1,4 +1,6 @@ -KNOWN_EXAMPLES = gpio-output +TARGET=galileo + +KNOWN_EXAMPLES = gpio-output i2c-LSM9DS0 ifneq ($(filter $(EXAMPLE),$(KNOWN_EXAMPLES)),) CONTIKI_PROJECT = $(EXAMPLE) diff --git a/examples/galileo/README b/examples/galileo/README index cdd2133a9..87f3f0ec7 100644 --- a/examples/galileo/README +++ b/examples/galileo/README @@ -23,3 +23,33 @@ state at every half second. For a visual effect, you should wire shield pin IO1 to a led in a protoboard. Once the application is running, you should see a blinking LED. +======= += I2C = +======= + +I2C LSM9DS0 +=========== +This application shows how to use I2C driver APIs to configure I2C Master +controller and communicate with LSM9DS0 sensor. At every 5 seconds, the +application reads the "who am I" register from gyroscope sensor and prints if +the register value matches the expected value described in the spec [1]. + +According to the sensor spec, to read the value in "who am I" register, we +should first perform an i2c write operation to select the register we want +to read from and then we perform the i2c read operation to actually read +the register contents. + +The wiring setup is as follows (left column from Galileo and right column from LSM9DS0): +- 3.3v and Vin +- GND and GND +- GND and SDOG +- 3.3v and CSG +- SDA and SDA +- SCL and SCL + +============== += References = +============== + +[1] http://www.st.com/st-web-ui/static/active/en/resource/technical/document/datasheet/DM00087365.pdf + diff --git a/examples/galileo/i2c-LSM9DS0.c b/examples/galileo/i2c-LSM9DS0.c new file mode 100644 index 000000000..9abfffcc8 --- /dev/null +++ b/examples/galileo/i2c-LSM9DS0.c @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "contiki.h" +#include "sys/ctimer.h" + +#include "i2c.h" + +#define LSM9DS0_I2C_ADDR 0x6A +#define WHO_AM_I_ADDR 0x0F +#define WHO_AM_I_ANSWER 0xD4 + +static uint8_t tx_data = WHO_AM_I_ADDR; +static uint8_t rx_data = 0; +static struct ctimer timer; +static struct quarkX1000_i2c_config cfg; + +PROCESS(i2c_lsm9ds0_process, "I2C LSM9DS0 Who Am I Process"); +AUTOSTART_PROCESSES(&i2c_lsm9ds0_process); +/*---------------------------------------------------------------------------*/ +static void +rx(void) +{ + if (rx_data == WHO_AM_I_ANSWER) + printf("Who am I register value match!\n"); + else + printf("Who am I register value DOESN'T match! %u\n", rx_data); +} +/*---------------------------------------------------------------------------*/ +static void +tx(void) +{ + rx_data = 0; + + quarkX1000_i2c_read(&rx_data, sizeof(rx_data), LSM9DS0_I2C_ADDR); +} +/*---------------------------------------------------------------------------*/ +static void +err(void) +{ + printf("Something went wrong. err() callback has been called.\n"); +} +/*---------------------------------------------------------------------------*/ +static void +timeout(void *data) +{ + quarkX1000_i2c_write(&tx_data, sizeof(tx_data), LSM9DS0_I2C_ADDR); + + ctimer_reset(&timer); +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(i2c_lsm9ds0_process, ev, data) +{ + PROCESS_BEGIN(); + + cfg.speed = QUARKX1000_I2C_SPEED_STANDARD; + cfg.addressing_mode = QUARKX1000_I2C_ADDR_MODE_7BIT; + cfg.cb_rx = rx; + cfg.cb_tx = tx; + cfg.cb_err = err; + + quarkX1000_i2c_init(); + quarkX1000_i2c_configure(&cfg); + + ctimer_set(&timer, CLOCK_SECOND * 5, timeout, NULL); + + printf("I2C LSM9DS0 example is running\n"); + + PROCESS_YIELD(); + + PROCESS_END(); +} From 495dcd659a37b1f0a844c9551d18ea9ab147d68c Mon Sep 17 00:00:00 2001 From: Ricardo de Almeida Gonzaga Date: Thu, 8 Oct 2015 10:16:53 -0300 Subject: [PATCH 74/92] x86: Add PCAL9535A support This patch adds gpio-pcal9535a.c and gpio-pcal9535a.h files, which support access to I2C-based PCAL9535A GPIO controller configuration register through a function interface. The PCAL9535A is a low-voltage 16-bit GPIO expander with interrupt and reset for I2C-bus/SMBus applications. It contains the PCA9535 register set of four pairs of 8-bit Configuration, Input, Output, and Polarity Inversion registers, and additionally, the PCAL9535A has Agile I/O, which are additional features specifically designed to enhance the I/O. More about PCAL9535A can be found in its datasheet[1]. This driver is needed in order to configure Galileo pinmux. [1] - http://www.nxp.com/documents/data_sheet/PCAL9535A.pdf --- cpu/x86/drivers/quarkX1000/gpio.h | 27 +- platform/galileo/Makefile.galileo | 4 +- platform/galileo/drivers/gpio-pcal9535a.c | 344 ++++++++++++++++++++++ platform/galileo/drivers/gpio-pcal9535a.h | 65 ++++ 4 files changed, 429 insertions(+), 11 deletions(-) create mode 100644 platform/galileo/drivers/gpio-pcal9535a.c create mode 100644 platform/galileo/drivers/gpio-pcal9535a.h diff --git a/cpu/x86/drivers/quarkX1000/gpio.h b/cpu/x86/drivers/quarkX1000/gpio.h index 6e434900f..c63e6dc91 100644 --- a/cpu/x86/drivers/quarkX1000/gpio.h +++ b/cpu/x86/drivers/quarkX1000/gpio.h @@ -35,15 +35,24 @@ #include "pci.h" -#define QUARKX1000_GPIO_IN (0 << 0) -#define QUARKX1000_GPIO_OUT (1 << 0) -#define QUARKX1000_GPIO_INT (1 << 1) -#define QUARKX1000_GPIO_ACTIVE_LOW (0 << 2) -#define QUARKX1000_GPIO_ACTIVE_HIGH (1 << 2) -#define QUARKX1000_GPIO_LEVEL (0 << 3) -#define QUARKX1000_GPIO_EDGE (1 << 3) -#define QUARKX1000_GPIO_DEBOUNCE (1 << 4) -#define QUARKX1000_GPIO_CLOCK_SYNC (1 << 5) +#define QUARKX1000_GPIO_IN (0 << 0) +#define QUARKX1000_GPIO_OUT (1 << 0) +#define QUARKX1000_GPIO_INT (1 << 1) +#define QUARKX1000_GPIO_ACTIVE_LOW (0 << 2) +#define QUARKX1000_GPIO_ACTIVE_HIGH (1 << 2) +#define QUARKX1000_GPIO_LEVEL (0 << 3) +#define QUARKX1000_GPIO_EDGE (1 << 3) +#define QUARKX1000_GPIO_DEBOUNCE (1 << 4) +#define QUARKX1000_GPIO_CLOCK_SYNC (1 << 5) +#define QUARKX1000_GPIO_POL_NORMAL (0 << 6) +#define QUARKX1000_GPIO_POL_INV (1 << 6) +#define QUARKX1000_GPIO_PUD_NORMAL (0 << 7) +#define QUARKX1000_GPIO_PUD_PULL_UP (1 << 7) +#define QUARKX1000_GPIO_PUD_PULL_DOWN (2 << 7) + +#define QUARKX1000_GPIO_DIR_MASK (1 << 0) +#define QUARKX1000_GPIO_POL_MASK (1 << 6) +#define QUARKX1000_GPIO_PUD_MASK (3 << 7) int quarkX1000_gpio_init(void); diff --git a/platform/galileo/Makefile.galileo b/platform/galileo/Makefile.galileo index a1429b398..ec26cf908 100644 --- a/platform/galileo/Makefile.galileo +++ b/platform/galileo/Makefile.galileo @@ -3,9 +3,9 @@ LIBC_PATH=$(BSP_PATH)/libc LIBC=$(LIBC_PATH)/i586-elf LIBGCC_PATH = /usr/lib/gcc/$(shell gcc -dumpmachine)/$(shell gcc -dumpversion) -CONTIKI_TARGET_DIRS = . core/sys/ +CONTIKI_TARGET_DIRS = . core/sys/ drivers/ CONTIKI_TARGET_MAIN = ${addprefix $(OBJECTDIR)/,contiki-main.o} -CONTIKI_SOURCEFILES += contiki-main.c clock.c rtimer-arch.c +CONTIKI_SOURCEFILES += contiki-main.c clock.c rtimer-arch.c gpio-pcal9535a.c PROJECT_SOURCEFILES += newlib-syscalls.c diff --git a/platform/galileo/drivers/gpio-pcal9535a.c b/platform/galileo/drivers/gpio-pcal9535a.c new file mode 100644 index 000000000..ce7dd82b1 --- /dev/null +++ b/platform/galileo/drivers/gpio-pcal9535a.c @@ -0,0 +1,344 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "contiki.h" +#include "gpio.h" +#include "gpio-pcal9535a.h" +#include "i2c.h" +#include "stdio.h" + +#define REG_INPUT_PORT0 0x00 +#define REG_INPUT_PORT1 0x01 +#define REG_OUTPUT_PORT0 0x02 +#define REG_OUTPUT_PORT1 0x03 +#define REG_POL_INV_PORT0 0x04 +#define REG_POL_INV_PORT1 0x05 +#define REG_CONF_PORT0 0x06 +#define REG_CONG_PORT1 0x07 +#define REG_OUT_DRV_STRENGTH_PORT0_L 0x40 +#define REG_OUT_DRV_STRENGTH_PORT0_H 0x41 +#define REG_OUT_DRV_STRENGTH_PORT1_L 0x42 +#define REG_OUT_DRV_STRENGTH_PORT1_H 0x43 +#define REG_INPUT_LATCH_PORT0 0x44 +#define REG_INPUT_LATCH_PORT1 0x45 +#define REG_PUD_EN_PORT0 0x46 +#define REG_PUD_EN_PORT1 0x47 +#define REG_PUD_SEL_PORT0 0x48 +#define REG_PUD_SEL_PORT1 0x49 +#define REG_INT_MASK_PORT0 0x4A +#define REG_INT_MASK_PORT1 0x4B +#define REG_INT_STATUS_PORT0 0x4C +#define REG_INT_STATUS_PORT1 0x4D +#define REG_OUTPUT_PORT_CONF 0x4F + +#define READ_PORT_TIMEOUT (CLOCK_SECOND / 100) +#define READ_PORT_TRIES 5 + +static int +read_port_regs(struct gpio_pcal9535a_data *data, uint8_t reg, union gpio_pcal9535a_port_data *buf) +{ + int r; + uint8_t tries = READ_PORT_TRIES; + + buf->byte[0] = reg; + buf->byte[1] = 0; + + if (quarkX1000_i2c_write(buf->byte, 1, data->i2c_slave_addr) < 0) + return -1; + + do { + clock_wait(READ_PORT_TIMEOUT); + + r = quarkX1000_i2c_read(buf->byte, 2, data->i2c_slave_addr); + if (r == 0) + break; + } while (tries--); + + if (r < 0) + return -1; + + return 0; +} + +static int +write_port_regs(struct gpio_pcal9535a_data *data, uint8_t reg, union gpio_pcal9535a_port_data *buf) +{ + uint8_t cmd[] = {reg, buf->byte[0], buf->byte[1]}; + + if (quarkX1000_i2c_polling_write(cmd, sizeof(cmd), data->i2c_slave_addr) < 0) + return -1; + + return 0; +} + +static int +setup_pin_dir(struct gpio_pcal9535a_data *data, uint32_t pin, int flags) +{ + union gpio_pcal9535a_port_data *port = &data->reg_cache.dir; + uint16_t bit_mask, new_value = 0; + + bit_mask = 1 << pin; + + if ((flags & QUARKX1000_GPIO_DIR_MASK) == QUARKX1000_GPIO_IN) + new_value = 1 << pin; + + port->all &= ~bit_mask; + port->all |= new_value; + + return write_port_regs(data, REG_CONF_PORT0, port); +} + +static int +setup_pin_pullupdown(struct gpio_pcal9535a_data *data, uint32_t pin, int flags) +{ + union gpio_pcal9535a_port_data *port; + uint16_t bit_mask, new_value = 0; + + if ((flags & QUARKX1000_GPIO_PUD_MASK) != QUARKX1000_GPIO_PUD_NORMAL) { + port = &data->reg_cache.pud_sel; + bit_mask = 1 << pin; + + if ((flags & QUARKX1000_GPIO_PUD_MASK) == QUARKX1000_GPIO_PUD_PULL_UP) + new_value = 1 << pin; + + port->all &= ~bit_mask; + port->all |= new_value; + + if (write_port_regs(data, REG_PUD_SEL_PORT0, port) < 0) + return -1; + } + + port = &data->reg_cache.pud_en; + bit_mask = 1 << pin; + + if ((flags & QUARKX1000_GPIO_PUD_MASK) != QUARKX1000_GPIO_PUD_NORMAL) + new_value = 1 << pin; + + port->all &= ~bit_mask; + port->all |= new_value; + + return write_port_regs(data, REG_PUD_EN_PORT0, port); +} + +static int +setup_pin_polarity(struct gpio_pcal9535a_data *data, uint32_t pin, int flags) +{ + union gpio_pcal9535a_port_data *port = &data->reg_cache.pol_inv; + uint16_t bit_mask, new_value = 0; + + bit_mask = 1 << pin; + + if ((flags & QUARKX1000_GPIO_POL_MASK) == QUARKX1000_GPIO_POL_INV) + new_value = 1 << pin; + + port->all &= ~bit_mask; + port->all |= new_value; + + if (write_port_regs(data, REG_POL_INV_PORT0, port) < 0) + return -1; + + data->out_pol_inv = port->all; + + return 0; +} + +int +gpio_pcal9535a_write(struct gpio_pcal9535a_data *data, uint32_t pin, uint32_t value) +{ + union gpio_pcal9535a_port_data *port = &data->reg_cache.output; + uint16_t bit_mask, new_value; + + if (!quarkX1000_i2c_is_available()) + return -1; + + bit_mask = 1 << pin; + + new_value = (value << pin) & bit_mask; + new_value ^= (data->out_pol_inv & bit_mask); + new_value &= bit_mask; + + port->all &= ~bit_mask; + port->all |= new_value; + + return write_port_regs(data, REG_OUTPUT_PORT0, port); +} + +int +gpio_pcal9535a_read(struct gpio_pcal9535a_data *data, uint32_t pin, uint32_t *value) +{ + union gpio_pcal9535a_port_data buf; + + if (!quarkX1000_i2c_is_available()) + return -1; + + if (read_port_regs(data, REG_INPUT_PORT0, &buf) < 0) + return -1; + + *value = (buf.all >> pin) & 0x01; + + return 0; +} + +int +gpio_pcal9535a_config(struct gpio_pcal9535a_data *data, uint32_t pin, int flags) +{ + if (!quarkX1000_i2c_is_available()) + return -1; + + if (setup_pin_dir(data, pin, flags) < 0) + return -1; + + if (setup_pin_polarity(data, pin, flags) < 0) + return -1; + + if (setup_pin_pullupdown(data, pin, flags) < 0) + return -1; + + return 0; +} + +static int +setup_port_dir(struct gpio_pcal9535a_data *data, uint32_t pin, int flags) +{ + union gpio_pcal9535a_port_data *port = &data->reg_cache.dir; + + port->all = ((flags & QUARKX1000_GPIO_DIR_MASK) == QUARKX1000_GPIO_IN) ? 0xFFFF : 0x0; + + return write_port_regs(data, REG_CONF_PORT0, port); +} + +static int +setup_port_pullupdown(struct gpio_pcal9535a_data *data, uint32_t pin, int flags) +{ + union gpio_pcal9535a_port_data *port; + + if ((flags & QUARKX1000_GPIO_PUD_MASK) != QUARKX1000_GPIO_PUD_NORMAL) { + port = &data->reg_cache.pud_sel; + port->all = ((flags & QUARKX1000_GPIO_PUD_MASK) == QUARKX1000_GPIO_PUD_PULL_UP) ? 0xFFFF : 0x0; + + if (write_port_regs(data, REG_PUD_SEL_PORT0, port) < 0) + return -1; + } + + port = &data->reg_cache.pud_en; + port->all = ((flags & QUARKX1000_GPIO_PUD_MASK) != QUARKX1000_GPIO_PUD_NORMAL) ? 0xFFFF : 0x0; + + return write_port_regs(data, REG_PUD_EN_PORT0, port); +} + +static int +setup_port_polarity(struct gpio_pcal9535a_data *data, uint32_t pin, int flags) +{ + union gpio_pcal9535a_port_data *port = &data->reg_cache.pol_inv; + + port->all = ((flags & QUARKX1000_GPIO_POL_MASK) == QUARKX1000_GPIO_POL_INV) ? 0xFFFF : 0x0; + + if (write_port_regs(data, REG_POL_INV_PORT0, port) < 0) + return -1; + + data->out_pol_inv = port->all; + + return 0; +} + +int +gpio_pcal9535a_write_port(struct gpio_pcal9535a_data *data, uint32_t pin, uint32_t value) +{ + union gpio_pcal9535a_port_data *port = &data->reg_cache.output; + uint16_t bit_mask, new_value; + + if (!quarkX1000_i2c_is_available()) + return -1; + + port->all = value; + bit_mask = data->out_pol_inv; + + new_value = value & bit_mask; + new_value ^= data->out_pol_inv; + new_value &= bit_mask; + + port->all &= ~bit_mask; + port->all |= new_value; + + return write_port_regs(data, REG_OUTPUT_PORT0, port); +} + +int +gpio_pcal9535a_read_port(struct gpio_pcal9535a_data *data, uint32_t pin, uint32_t *value) +{ + union gpio_pcal9535a_port_data buf; + + if (!quarkX1000_i2c_is_available()) + return -1; + + if (read_port_regs(data, REG_INPUT_PORT0, &buf) < 0) + return -1; + + *value = buf.all; + + return 0; +} + +int +gpio_pcal9535a_config_port(struct gpio_pcal9535a_data *data, uint32_t pin, int flags) +{ + if (!quarkX1000_i2c_is_available()) + return -1; + + if (setup_port_dir(data, pin, flags) < 0) + return -1; + + if (setup_port_polarity(data, pin, flags) < 0) + return -1; + + if (setup_port_pullupdown(data, pin, flags) < 0) + return -1; + + return 0; +} + +int +gpio_pcal9535a_init(struct gpio_pcal9535a_data *data, uint16_t i2c_slave_addr) +{ + /* has to init after I2C master */ + if (!quarkX1000_i2c_is_available()) + return -1; + + data->i2c_slave_addr = i2c_slave_addr; + + /* default for registers according to datasheet */ + data->reg_cache.output.all = 0xFFFF; + data->reg_cache.pol_inv.all = 0x0; + data->reg_cache.dir.all = 0xFFFF; + data->reg_cache.pud_en.all = 0x0; + data->reg_cache.pud_sel.all = 0xFFFF; + + return 0; +} diff --git a/platform/galileo/drivers/gpio-pcal9535a.h b/platform/galileo/drivers/gpio-pcal9535a.h new file mode 100644 index 000000000..f7f8ce699 --- /dev/null +++ b/platform/galileo/drivers/gpio-pcal9535a.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CPU_X86_DRIVERS_GPIO_PCAL9535A_H_ +#define CPU_X86_DRIVERS_GPIO_PCAL9535A_H_ + +#include + +union gpio_pcal9535a_port_data { + uint16_t all; + uint8_t port[2]; + uint8_t byte[2]; +}; + +struct gpio_pcal9535a_data { + uint16_t i2c_slave_addr; + uint32_t out_pol_inv; + + struct { + union gpio_pcal9535a_port_data output; + union gpio_pcal9535a_port_data pol_inv; + union gpio_pcal9535a_port_data dir; + union gpio_pcal9535a_port_data pud_en; + union gpio_pcal9535a_port_data pud_sel; + } reg_cache; +}; + +int gpio_pcal9535a_init(struct gpio_pcal9535a_data *data, uint16_t i2c_slave_addr); + +int gpio_pcal9535a_config(struct gpio_pcal9535a_data *data, uint32_t pin, int flags); +int gpio_pcal9535a_read(struct gpio_pcal9535a_data *data, uint32_t pin, uint32_t *value); +int gpio_pcal9535a_write(struct gpio_pcal9535a_data *data, uint32_t pin, uint32_t value); + +int gpio_pcal9535a_config_port(struct gpio_pcal9535a_data *data, uint32_t pin, int flags); +int gpio_pcal9535a_read_port(struct gpio_pcal9535a_data *data, uint32_t pin, uint32_t *value); +int gpio_pcal9535a_write_port(struct gpio_pcal9535a_data *data, uint32_t pin, uint32_t value); + +#endif /* CPU_X86_DRIVERS_GPIO_PCAL9535A_H_ */ From 781375f1d112876e8c867cb45ba30c936d3d760e Mon Sep 17 00:00:00 2001 From: Ricardo de Almeida Gonzaga Date: Thu, 8 Oct 2015 14:16:11 -0300 Subject: [PATCH 75/92] x86: Add PCA9685 support This patch adds pwm-pca9685.c and pwm-pca9685.h files, which support access to I2C-based PCA9685 PWM controller configuration register through a function interface. The PCA9685 is an I2C-bus controlled 16-channel LED controller optimized for Red/Green/Blue/Amber (RGBA) color backlighting applications. Each LED output has its own 12-bit resolution (4096 steps) fixed frequency individual PWM controller that operates at a programmable frequency from a typical of 24 Hz to 1526 Hz with a duty cycle that is adjustable from 0 % to 100 % to allow the LED to be set to a specific brightness value. More about PCA9685 can be found in its datasheet[1]. This driver is needed in order to configure Galileo pinmux. [1] - http://www.nxp.com/documents/data_sheet/PCA9685.pdf --- platform/galileo/Makefile.galileo | 2 +- platform/galileo/drivers/pwm-pca9685.c | 118 +++++++++++++++++++++++++ platform/galileo/drivers/pwm-pca9685.h | 44 +++++++++ 3 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 platform/galileo/drivers/pwm-pca9685.c create mode 100644 platform/galileo/drivers/pwm-pca9685.h diff --git a/platform/galileo/Makefile.galileo b/platform/galileo/Makefile.galileo index ec26cf908..cd801addf 100644 --- a/platform/galileo/Makefile.galileo +++ b/platform/galileo/Makefile.galileo @@ -5,7 +5,7 @@ LIBGCC_PATH = /usr/lib/gcc/$(shell gcc -dumpmachine)/$(shell gcc -dumpversion) CONTIKI_TARGET_DIRS = . core/sys/ drivers/ CONTIKI_TARGET_MAIN = ${addprefix $(OBJECTDIR)/,contiki-main.o} -CONTIKI_SOURCEFILES += contiki-main.c clock.c rtimer-arch.c gpio-pcal9535a.c +CONTIKI_SOURCEFILES += contiki-main.c clock.c rtimer-arch.c gpio-pcal9535a.c pwm-pca9685.c PROJECT_SOURCEFILES += newlib-syscalls.c diff --git a/platform/galileo/drivers/pwm-pca9685.c b/platform/galileo/drivers/pwm-pca9685.c new file mode 100644 index 000000000..a3d93fd5c --- /dev/null +++ b/platform/galileo/drivers/pwm-pca9685.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "i2c.h" +#include "pwm-pca9685.h" + +#define REG_MODE1 0x00 +#define REG_MODE2 0x01 + +#define REG_LED_ON_L(n) ((4 * n) + 0x06) +#define REG_LED_ON_H(n) ((4 * n) + 0x07) +#define REG_LED_OFF_L(n) ((4 * n) + 0x08) +#define REG_LED_OFF_H(n) ((4 * n) + 0x09) + +#define MAX_PWM_OUT 16 +#define PWM_ONE_PERIOD_TICKS 4096 + +int +pwm_pca9685_set_values(struct pwm_pca9685_data *data, uint32_t pwm, uint32_t on, uint32_t off) +{ + uint8_t buf[5] = { 0 }; + + if (!quarkX1000_i2c_is_available()) + return -1; + + if (pwm > MAX_PWM_OUT) + return -1; + + buf[0] = REG_LED_ON_L(pwm); + + if ((on >= PWM_ONE_PERIOD_TICKS) || (off >= PWM_ONE_PERIOD_TICKS)) { + /* Treat as 100% */ + buf[1] = 0x0; + buf[2] = (1 << 4); + buf[3] = 0x0; + buf[4] = 0x0; + } else if (off == 0) { + /* Treat it as 0% */ + buf[1] = 0x0; + buf[2] = 0x0; + buf[3] = 0x0; + buf[4] = (1 << 4); + } else { + /* Populate registers accordingly */ + buf[0] = (on & 0xFF); + buf[1] = ((on >> 8) & 0x0F); + buf[2] = (off & 0xFF); + buf[3] = ((off >> 8) & 0x0F); + } + + return quarkX1000_i2c_polling_write(buf, sizeof(buf), data->i2c_slave_addr); +} + +int +pwm_pca9685_set_duty_cycle(struct pwm_pca9685_data *data, uint32_t pwm, uint8_t duty) +{ + uint32_t on, off; + + if (duty == 0) { + on = 0; + off = 0; + } else if (duty >= 100) { + on = PWM_ONE_PERIOD_TICKS + 1; + off = PWM_ONE_PERIOD_TICKS + 1; + } else { + on = PWM_ONE_PERIOD_TICKS * duty / 100; + off = PWM_ONE_PERIOD_TICKS - 1; + } + + return pwm_pca9685_set_values(data, pwm, on, off); +} + +int +pwm_pca9685_init(struct pwm_pca9685_data *data, uint16_t i2c_slave_addr) +{ + uint8_t buf[2] = { 0 }; + + /* has to init after I2C master */ + if (!quarkX1000_i2c_is_available()) + return -1; + + data->i2c_slave_addr = i2c_slave_addr; + + buf[0] = REG_MODE1; + buf[1] = (1 << 5); + + if (quarkX1000_i2c_polling_write(buf, 2, i2c_slave_addr) < 0) + return -1; + + return 0; +} diff --git a/platform/galileo/drivers/pwm-pca9685.h b/platform/galileo/drivers/pwm-pca9685.h new file mode 100644 index 000000000..394e9357d --- /dev/null +++ b/platform/galileo/drivers/pwm-pca9685.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CPU_X86_DRIVERS_PWM_PCA9685_H_ +#define CPU_X86_DRIVERS_PWM_PCA9685_H_ + +#include + +struct pwm_pca9685_data { + uint16_t i2c_slave_addr; +}; + +int pwm_pca9685_init(struct pwm_pca9685_data *data, uint16_t i2c_slave_addr); +int pwm_pca9685_set_duty_cycle(struct pwm_pca9685_data *data, uint32_t pwm, uint8_t duty); +int pwm_pca9685_set_values(struct pwm_pca9685_data *data, uint32_t pwm, uint32_t on, uint32_t off); + +#endif /* CPU_X86_DRIVERS_PWM_PCA9685_H_ */ From 93c7988069ed4f228f9bc65e74f3c1b54f9b5ef4 Mon Sep 17 00:00:00 2001 From: Ricardo de Almeida Gonzaga Date: Fri, 16 Oct 2015 11:13:56 -0300 Subject: [PATCH 76/92] x86: Add Galileo pinmux support This patch adds the galileo-pinmux.c and galileo-pinmux.h files, which support access to pinmux configuration through a function interface. This is not 100% supported yet due to some pinmux paths need Quark X1000 GPIO (legacy and non-legacy) configurations. After we finish to implement Quark X1000 GPIO driver we'll add support for this. --- platform/galileo/Makefile.galileo | 2 +- platform/galileo/drivers/galileo-pinmux.c | 605 ++++++++++++++++++++++ platform/galileo/drivers/galileo-pinmux.h | 46 ++ 3 files changed, 652 insertions(+), 1 deletion(-) create mode 100644 platform/galileo/drivers/galileo-pinmux.c create mode 100644 platform/galileo/drivers/galileo-pinmux.h diff --git a/platform/galileo/Makefile.galileo b/platform/galileo/Makefile.galileo index cd801addf..bbf937ac0 100644 --- a/platform/galileo/Makefile.galileo +++ b/platform/galileo/Makefile.galileo @@ -5,7 +5,7 @@ LIBGCC_PATH = /usr/lib/gcc/$(shell gcc -dumpmachine)/$(shell gcc -dumpversion) CONTIKI_TARGET_DIRS = . core/sys/ drivers/ CONTIKI_TARGET_MAIN = ${addprefix $(OBJECTDIR)/,contiki-main.o} -CONTIKI_SOURCEFILES += contiki-main.c clock.c rtimer-arch.c gpio-pcal9535a.c pwm-pca9685.c +CONTIKI_SOURCEFILES += contiki-main.c clock.c rtimer-arch.c gpio-pcal9535a.c pwm-pca9685.c galileo-pinmux.c PROJECT_SOURCEFILES += newlib-syscalls.c diff --git a/platform/galileo/drivers/galileo-pinmux.c b/platform/galileo/drivers/galileo-pinmux.c new file mode 100644 index 000000000..9b91c367a --- /dev/null +++ b/platform/galileo/drivers/galileo-pinmux.c @@ -0,0 +1,605 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "galileo-pinmux.h" +#include "gpio.h" +#include "gpio-pcal9535a.h" +#include "i2c.h" +#include "pwm-pca9685.h" + +#define GPIO_PCAL9535A_0_I2C_ADDR 0x25 +#define GPIO_PCAL9535A_1_I2C_ADDR 0x26 +#define GPIO_PCAL9535A_2_I2C_ADDR 0x27 +#define PWM_PCA9685_0_I2C_ADDR 0x47 + +#define PINMUX_NUM_FUNCS 4 +#define PINMUX_NUM_PATHS 4 +#define PINMUX_NUM_PINS 20 + +typedef enum { + NONE, + EXP0, + EXP1, + EXP2, + PWM0 +} MUX_CHIP; + +typedef enum { + PIN_LOW = 0x00, + PIN_HIGH = 0x01, + DISABLED = 0xFF +} PIN_LEVEL; + +struct pin_config { + uint8_t pin_num; + GALILEO_PINMUX_FUNC func; +}; + +static struct pin_config default_pinmux_config[PINMUX_NUM_PINS] = { + { 0, GALILEO_PINMUX_FUNC_C }, /* UART0_RXD */ + { 1, GALILEO_PINMUX_FUNC_C }, /* UART0_TXD */ + { 2, GALILEO_PINMUX_FUNC_A }, /* GPIO5(out) */ + { 3, GALILEO_PINMUX_FUNC_B }, /* GPIO6(in) */ + { 4, GALILEO_PINMUX_FUNC_B }, /* GPIO_SUS4 (in) */ + { 5, GALILEO_PINMUX_FUNC_B }, /* GPIO8 (in) */ + { 6, GALILEO_PINMUX_FUNC_B }, /* GPIO9 (in) */ + { 7, GALILEO_PINMUX_FUNC_B }, /* EXP1.P0_6 (in) */ + { 8, GALILEO_PINMUX_FUNC_B }, /* EXP1.P1_0 (in) */ + { 9, GALILEO_PINMUX_FUNC_B }, /* GPIO_SUS2 (in) */ + { 10, GALILEO_PINMUX_FUNC_A }, /* GPIO2 (out) */ + { 11, GALILEO_PINMUX_FUNC_B }, /* GPIO_SUS3 (in) */ + { 12, GALILEO_PINMUX_FUNC_B }, /* GPIO7 (in) */ + { 13, GALILEO_PINMUX_FUNC_B }, /* GPIO_SUS5(in) */ + { 14, GALILEO_PINMUX_FUNC_B }, /* EXP2.P0_0 (in)/ADC.IN0 */ + { 15, GALILEO_PINMUX_FUNC_B }, /* EXP2.P0_2 (in)/ADC.IN1 */ + { 16, GALILEO_PINMUX_FUNC_B }, /* EXP2.P0_4 (in)/ADC.IN2 */ + { 17, GALILEO_PINMUX_FUNC_B }, /* EXP2.P0_6 (in)/ADC.IN3 */ + { 18, GALILEO_PINMUX_FUNC_C }, /* I2C_SDA */ + { 19, GALILEO_PINMUX_FUNC_C }, /* I2C_SCL */ +}; + +struct mux_pin { + MUX_CHIP chip; + uint8_t pin; + PIN_LEVEL level; + uint32_t cfg; +}; + +struct mux_path { + uint8_t io_pin; + GALILEO_PINMUX_FUNC func; + struct mux_pin path[PINMUX_NUM_PATHS]; +}; + +struct pinmux_internal_data { + struct gpio_pcal9535a_data exp0; + struct gpio_pcal9535a_data exp1; + struct gpio_pcal9535a_data exp2; + struct pwm_pca9685_data pwm0; +}; + +static struct pinmux_internal_data data; + +static struct mux_path galileo_pinmux_paths[PINMUX_NUM_PINS * PINMUX_NUM_FUNCS] = { + {0, GALILEO_PINMUX_FUNC_A, { + { EXP1, 0, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* GPIO3 out */ + { EXP1, 1, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {0, GALILEO_PINMUX_FUNC_B, { + { EXP1, 0, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO3 in */ + { EXP1, 1, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {0, GALILEO_PINMUX_FUNC_C, { + { EXP1, 0, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* UART0_RXD */ + { EXP1, 1, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {0, GALILEO_PINMUX_FUNC_D, { + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */ + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + + {1, GALILEO_PINMUX_FUNC_A, { + { EXP1, 13, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO4 out */ + { EXP0, 12, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP0, 13, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {1, GALILEO_PINMUX_FUNC_B, { + { EXP1, 13, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO4 in */ + { EXP0, 12, PIN_HIGH, (QUARKX1000_GPIO_OUT)}, + { EXP0, 13, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {1, GALILEO_PINMUX_FUNC_C, { + { EXP1, 13, PIN_HIGH, (QUARKX1000_GPIO_OUT)}, /* UART0_TXD */ + { EXP0, 12, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP0, 13, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {1, GALILEO_PINMUX_FUNC_D, { + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */ + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + + {2, GALILEO_PINMUX_FUNC_A, { + { PWM0, 13, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* GPIO5 out */ + { EXP1, 2, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP1, 3, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {2, GALILEO_PINMUX_FUNC_B, { + { PWM0, 13, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* GPIO5 in */ + { EXP1, 2, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, + { EXP1, 3, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {2, GALILEO_PINMUX_FUNC_C, { + { PWM0, 13, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* UART1_RXD */ + { EXP1, 2, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, + { EXP1, 3, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {2, GALILEO_PINMUX_FUNC_D, { + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */ + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + + {3, GALILEO_PINMUX_FUNC_A, { + { PWM0, 0, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO6 out */ + { PWM0, 12, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP0, 0, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP0, 1, PIN_LOW, (QUARKX1000_GPIO_OUT) }}}, + {3, GALILEO_PINMUX_FUNC_B, { + { PWM0, 0, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO6 in */ + { PWM0, 12, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP0, 0, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, + { EXP0, 1, PIN_LOW, (QUARKX1000_GPIO_OUT) }}}, + {3, GALILEO_PINMUX_FUNC_C, { + { PWM0, 0, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* UART1_TXD */ + { PWM0, 12, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, + { EXP0, 0, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP0, 1, PIN_LOW, (QUARKX1000_GPIO_OUT) }}}, + {3, GALILEO_PINMUX_FUNC_D, { + { PWM0, 0, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* PWM.LED1 */ + { PWM0, 12, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP0, 0, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP0, 1, PIN_LOW, (QUARKX1000_GPIO_OUT) }}}, + + {4, GALILEO_PINMUX_FUNC_A, { + { EXP1, 4, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO_SUS4 out */ + { EXP1, 5, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {4, GALILEO_PINMUX_FUNC_B, { + { EXP1, 4, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* GPIO_SUS4 in */ + { EXP1, 5, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {4, GALILEO_PINMUX_FUNC_C, { + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */ + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {4, GALILEO_PINMUX_FUNC_D, { + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */ + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + + {5, GALILEO_PINMUX_FUNC_A, { + { PWM0, 2, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO8 (out) */ + { EXP0, 2, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP0, 3, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {5, GALILEO_PINMUX_FUNC_B, { + { PWM0, 2, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO8 (in) */ + { EXP0, 2, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, + { EXP0, 3, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {5, GALILEO_PINMUX_FUNC_C, { + { PWM0, 2, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* PWM.LED3 */ + { EXP0, 2, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP0, 3, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {5, GALILEO_PINMUX_FUNC_D, { + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */ + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + + {6, GALILEO_PINMUX_FUNC_A, { + { PWM0, 4, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO9 (out) */ + { EXP0, 4, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP0, 5, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {6, GALILEO_PINMUX_FUNC_B, { + { PWM0, 4, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO9 (in) */ + { EXP0, 4, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, + { EXP0, 5, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {6, GALILEO_PINMUX_FUNC_C, { + { PWM0, 4, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* PWM.LED5 */ + { EXP0, 4, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP0, 5, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {6, GALILEO_PINMUX_FUNC_D, { + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */ + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + + {7, GALILEO_PINMUX_FUNC_A, { + { EXP1, 6, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO_SUS0 (out) */ + { EXP1, 7, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {7, GALILEO_PINMUX_FUNC_B, { + { EXP1, 6, PIN_LOW, (QUARKX1000_GPIO_IN ) }, /* GPIO_SUS0 (in) */ + { EXP1, 7, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {7, GALILEO_PINMUX_FUNC_C, { + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */ + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {7, GALILEO_PINMUX_FUNC_D, { + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */ + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + + {8, GALILEO_PINMUX_FUNC_A, { + { EXP1, 8, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO_SUS1 (out) */ + { EXP1, 9, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {8, GALILEO_PINMUX_FUNC_B, { + { EXP1, 8, PIN_LOW, (QUARKX1000_GPIO_IN ) }, /* GPIO_SUS1 (in) */ + { EXP1, 9, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {8, GALILEO_PINMUX_FUNC_C, { + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */ + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {8, GALILEO_PINMUX_FUNC_D, { + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */ + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + + {9, GALILEO_PINMUX_FUNC_A, { + { PWM0, 6, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO_SUS2 (out) */ + { EXP0, 6, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP0, 7, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {9, GALILEO_PINMUX_FUNC_B, { + { PWM0, 6, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO_SUS2 (in) */ + { EXP0, 6, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, + { EXP0, 7, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {9, GALILEO_PINMUX_FUNC_C, { + { PWM0, 6, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* PWM.LED7 */ + { EXP0, 6, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP0, 7, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {9, GALILEO_PINMUX_FUNC_C, { + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */ + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + + {10, GALILEO_PINMUX_FUNC_A, { + { PWM0, 10, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO2 (out) */ + { EXP0, 10, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP0, 11, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {10, GALILEO_PINMUX_FUNC_B, { + { PWM0, 10, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO2 (in) */ + { EXP0, 10, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, + { EXP0, 11, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {10, GALILEO_PINMUX_FUNC_C, { + { PWM0, 10, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* PWM.LED11 */ + { EXP0, 10, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP0, 11, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {10, GALILEO_PINMUX_FUNC_D, { + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */ + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + + {11, GALILEO_PINMUX_FUNC_A, { + { EXP1, 12, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO_SUS3 (out) */ + { PWM0, 8, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP0, 8, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP0, 9, PIN_LOW, (QUARKX1000_GPIO_OUT) }}}, + {11, GALILEO_PINMUX_FUNC_B, { + { EXP1, 12, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO_SUS3 (in) */ + { PWM0, 8, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP0, 8, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, + { EXP0, 9, PIN_LOW, (QUARKX1000_GPIO_OUT) }}}, + {11, GALILEO_PINMUX_FUNC_C, { + { EXP1, 12, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* PWM.LED9 */ + { PWM0, 8, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, + { EXP0, 8, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP0, 9, PIN_LOW, (QUARKX1000_GPIO_OUT) }}}, + {11, GALILEO_PINMUX_FUNC_D, { + { EXP1, 12, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* SPI1_MOSI */ + { PWM0, 8, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP0, 8, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP0, 9, PIN_LOW, (QUARKX1000_GPIO_OUT) }}}, + + {12, GALILEO_PINMUX_FUNC_A, { + { EXP1, 10, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO7 (out) */ + { EXP1, 11, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {12, GALILEO_PINMUX_FUNC_B, { + { EXP1, 10, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* GPIO7 (in) */ + { EXP1, 11, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {12, GALILEO_PINMUX_FUNC_C, { + { EXP1, 10, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* SPI1_MISO */ + { EXP1, 11, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {12, GALILEO_PINMUX_FUNC_D, { + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */ + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + + {13, GALILEO_PINMUX_FUNC_A, { + { EXP1, 14, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO_SUS5 (out) */ + { EXP0, 14, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP0, 15, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {13, GALILEO_PINMUX_FUNC_B, { + { EXP1, 14, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO_SUS5 (in) */ + { EXP0, 14, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, + { EXP0, 15, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {13, GALILEO_PINMUX_FUNC_C, { + { EXP1, 14, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* SPI1_CLK */ + { EXP0, 14, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP0, 15, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {13, GALILEO_PINMUX_FUNC_D, { + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */ + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + + {14, GALILEO_PINMUX_FUNC_A, { + { EXP2, 0, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* EXP2.P0_0 (out)/ADC.IN0 */ + { EXP2, 1, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {14, GALILEO_PINMUX_FUNC_B, { + { EXP2, 0, PIN_LOW, (QUARKX1000_GPIO_IN ) }, /* EXP2.P0_0 (in)/ADC.IN0 */ + { EXP2, 1, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {14, GALILEO_PINMUX_FUNC_C, { + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */ + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {14, GALILEO_PINMUX_FUNC_D, { + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */ + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + + {15, GALILEO_PINMUX_FUNC_A, { + { EXP2, 2, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* EXP2.P0_2 (out)/ADC.IN1 */ + { EXP2, 3, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {15, GALILEO_PINMUX_FUNC_B, { + { EXP2, 2, PIN_LOW, (QUARKX1000_GPIO_IN ) }, /* EXP2.P0_2 (in)/ADC.IN1 */ + { EXP2, 3, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {15, GALILEO_PINMUX_FUNC_C, { + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */ + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {15, GALILEO_PINMUX_FUNC_D, { + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */ + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + + {16, GALILEO_PINMUX_FUNC_A, { + { EXP2, 4, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* EXP2.P0_4 (out)/ADC.IN2 */ + { EXP2, 5, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {16, GALILEO_PINMUX_FUNC_B, { + { EXP2, 4, PIN_LOW, (QUARKX1000_GPIO_IN ) }, /* EXP2.P0_4 (in)/ADC.IN2 */ + { EXP2, 5, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {16, GALILEO_PINMUX_FUNC_C, { + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */ + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {16, GALILEO_PINMUX_FUNC_D, { + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */ + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + + {17, GALILEO_PINMUX_FUNC_A, { + { EXP2, 6, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* EXP2.P0_6 (out)/ADC.IN3 */ + { EXP2, 7, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {17, GALILEO_PINMUX_FUNC_B, { + { EXP2, 6, PIN_LOW, (QUARKX1000_GPIO_IN ) }, /* EXP2.P0_6 (in)/ADC.IN3 */ + { EXP2, 7, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {17, GALILEO_PINMUX_FUNC_C, { + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */ + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {17, GALILEO_PINMUX_FUNC_D, { + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */ + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + + {18, GALILEO_PINMUX_FUNC_A, { + { PWM0, 14, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* EXP2.P1_0 (out)/ADC.IN4 */ + { EXP2, 12, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, + { EXP2, 8, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP2, 9, PIN_LOW, (QUARKX1000_GPIO_OUT) }}}, + {18, GALILEO_PINMUX_FUNC_B, { + { PWM0, 14, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* EXP2.P1_0 (in)/ADC.IN4 */ + { EXP2, 12, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, + { EXP2, 8, PIN_LOW, (QUARKX1000_GPIO_IN ) }, + { EXP2, 9, PIN_LOW, (QUARKX1000_GPIO_OUT) }}}, + {18, GALILEO_PINMUX_FUNC_C, { + { PWM0, 14, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* I2C SDA */ + { EXP2, 9, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP2, 12, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {18, GALILEO_PINMUX_FUNC_D, { + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */ + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + + {19, GALILEO_PINMUX_FUNC_A, { + { PWM0, 15, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* EXP2.P1_2 (out)/ADC.IN5 */ + { EXP2, 12, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, + { EXP2, 10, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP2, 11, PIN_LOW, (QUARKX1000_GPIO_OUT) }}}, + {19, GALILEO_PINMUX_FUNC_B, { + { PWM0, 15, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* EXP2.P1_2 (in)/ADC.IN5 */ + { EXP2, 12, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, + { EXP2, 10, PIN_LOW, (QUARKX1000_GPIO_IN ) }, + { EXP2, 11, PIN_LOW, (QUARKX1000_GPIO_OUT) }}}, + {19, GALILEO_PINMUX_FUNC_C, { + { PWM0, 15, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* I2C SCL */ + { EXP2, 11, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { EXP2, 12, PIN_LOW, (QUARKX1000_GPIO_OUT) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, + {19, GALILEO_PINMUX_FUNC_D, { + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */ + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, + { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, +}; + +int +galileo_pinmux_set_pin(uint8_t pin, GALILEO_PINMUX_FUNC func) +{ + struct mux_path *mux_path; + uint8_t index, i; + + if (pin > PINMUX_NUM_PINS) + return -1; + + index = PINMUX_NUM_FUNCS * pin; + index += func; + + mux_path = &galileo_pinmux_paths[index]; + + for (i = 0; i < PINMUX_NUM_PATHS; i++) { + switch(mux_path->path[i].chip) { + case EXP0: + if (gpio_pcal9535a_write(&data.exp0, mux_path->path[i].pin, mux_path->path[i].level) < 0) + return -1; + if (gpio_pcal9535a_config(&data.exp0, mux_path->path[i].pin, mux_path->path[i].cfg) < 0) + return -1; + break; + case EXP1: + if (gpio_pcal9535a_write(&data.exp1, mux_path->path[i].pin, mux_path->path[i].level) < 0) + return -1; + if (gpio_pcal9535a_config(&data.exp1, mux_path->path[i].pin, mux_path->path[i].cfg) < 0) + return -1; + break; + case EXP2: + if (gpio_pcal9535a_write(&data.exp2, mux_path->path[i].pin, mux_path->path[i].level) < 0) + return -1; + if (gpio_pcal9535a_config(&data.exp2, mux_path->path[i].pin, mux_path->path[i].cfg) < 0) + return -1; + break; + case PWM0: + if (pwm_pca9685_set_duty_cycle(&data.pwm0, mux_path->path[i].pin, mux_path->path[i].level ? 100 : 0) < 0) + return -1; + break; + case NONE: + break; + } + } + + return 0; +} + +int +galileo_pinmux_initialize(void) +{ + uint8_t i; + + /* has to init after I2C master */ + if (!quarkX1000_i2c_is_available()) + return -1; + + if (gpio_pcal9535a_init(&data.exp0, GPIO_PCAL9535A_0_I2C_ADDR) < 0) + return -1; + + if (gpio_pcal9535a_init(&data.exp1, GPIO_PCAL9535A_1_I2C_ADDR) < 0) + return -1; + + if (gpio_pcal9535a_init(&data.exp2, GPIO_PCAL9535A_2_I2C_ADDR) < 0) + return -1; + + if (pwm_pca9685_init(&data.pwm0, PWM_PCA9685_0_I2C_ADDR) < 0) + return -1; + + for (i = 0; i < PINMUX_NUM_PINS; i++) { + if (galileo_pinmux_set_pin(default_pinmux_config[i].pin_num, default_pinmux_config[i].func) < 0) + return -1; + } + + return 0; +} diff --git a/platform/galileo/drivers/galileo-pinmux.h b/platform/galileo/drivers/galileo-pinmux.h new file mode 100644 index 000000000..f7d4fa39e --- /dev/null +++ b/platform/galileo/drivers/galileo-pinmux.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CPU_X86_DRIVERS_GALILEO_PINMUX_H_ +#define CPU_X86_DRIVERS_GALILEO_PINMUX_H_ + +#include + +typedef enum { + GALILEO_PINMUX_FUNC_A, + GALILEO_PINMUX_FUNC_B, + GALILEO_PINMUX_FUNC_C, + GALILEO_PINMUX_FUNC_D +} GALILEO_PINMUX_FUNC; + +int galileo_pinmux_initialize(void); +int galileo_pinmux_set_pin(uint8_t pin, GALILEO_PINMUX_FUNC func); + +#endif /* CPU_X86_DRIVERS_GALILEO_PINMUX_H_ */ From 61e06c632a561aa1f3783d8f40a490dd2bfe3129 Mon Sep 17 00:00:00 2001 From: Ricardo de Almeida Gonzaga Date: Fri, 16 Oct 2015 11:04:17 -0300 Subject: [PATCH 77/92] galileo: Add GPIO input example This patch introduces an example application to demonstrate how to use GPIO driver APIs to manipulate input pins. The application uses default galileo pinmux initialization and sets the GPIO 5 (IO2) as output pin and GPIO 6 (IO3) as input. It toggles the output pin state at every half second and checks the value on input pin. --- examples/galileo/Makefile | 2 +- examples/galileo/README | 8 +++ examples/galileo/gpio-input.c | 96 +++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 examples/galileo/gpio-input.c diff --git a/examples/galileo/Makefile b/examples/galileo/Makefile index 6af6b61e3..f9f678481 100644 --- a/examples/galileo/Makefile +++ b/examples/galileo/Makefile @@ -1,6 +1,6 @@ TARGET=galileo -KNOWN_EXAMPLES = gpio-output i2c-LSM9DS0 +KNOWN_EXAMPLES = gpio-input gpio-output i2c-LSM9DS0 ifneq ($(filter $(EXAMPLE),$(KNOWN_EXAMPLES)),) CONTIKI_PROJECT = $(EXAMPLE) diff --git a/examples/galileo/README b/examples/galileo/README index 87f3f0ec7..b7698cb5d 100644 --- a/examples/galileo/README +++ b/examples/galileo/README @@ -23,6 +23,14 @@ state at every half second. For a visual effect, you should wire shield pin IO1 to a led in a protoboard. Once the application is running, you should see a blinking LED. +GPIO Input +========== + +This application shows how to use the GPIO driver APIs to manipulate input +pins. This application uses default galileo pinmux initialization and sets +the GPIO 5 (IO2) as output pin and GPIO 6 (IO3) as input. It toggles the +output pin state at every half second and checks the value on input pin. + ======= = I2C = ======= diff --git a/examples/galileo/gpio-input.c b/examples/galileo/gpio-input.c new file mode 100644 index 000000000..8728d5088 --- /dev/null +++ b/examples/galileo/gpio-input.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "contiki.h" +#include "sys/ctimer.h" + +#include "galileo-pinmux.h" +#include "gpio.h" +#include "i2c.h" + +#define PIN_OUTPUT 5 +#define PIN_INPUT 6 + +static uint32_t value; +static struct ctimer timer; +static struct quarkX1000_i2c_config i2c_config; + +PROCESS(gpio_input_process, "GPIO Input Process"); +AUTOSTART_PROCESSES(&gpio_input_process); +/*---------------------------------------------------------------------------*/ +static void +timeout(void *data) +{ + uint8_t value_in; + + /* toggle pin state */ + value = !value; + quarkX1000_gpio_write(PIN_OUTPUT, value); + + quarkX1000_gpio_read(PIN_INPUT, &value_in); + + if (value == value_in) + printf("GPIO pin value match!\n"); + else + printf("GPIO pin value DOESN'T match!\n"); + + ctimer_reset(&timer); +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(gpio_input_process, ev, data) +{ + PROCESS_BEGIN(); + + i2c_config.speed = QUARKX1000_I2C_SPEED_STANDARD; + i2c_config.addressing_mode = QUARKX1000_I2C_ADDR_MODE_7BIT; + + quarkX1000_i2c_init(); + quarkX1000_i2c_configure(&i2c_config); + + /* use default pinmux configuration */ + galileo_pinmux_initialize(); + + quarkX1000_gpio_init(); + quarkX1000_gpio_config(PIN_OUTPUT, QUARKX1000_GPIO_OUT); + quarkX1000_gpio_config(PIN_INPUT, QUARKX1000_GPIO_IN); + + quarkX1000_gpio_clock_enable(); + + ctimer_set(&timer, CLOCK_SECOND / 2, timeout, NULL); + + printf("GPIO input example is running\n"); + PROCESS_YIELD(); + + quarkX1000_gpio_clock_disable(); + + PROCESS_END(); +} From 4726bc33139016df50411ab850e2044f0f134bf5 Mon Sep 17 00:00:00 2001 From: Ricardo de Almeida Gonzaga Date: Tue, 20 Oct 2015 11:28:31 -0200 Subject: [PATCH 78/92] x86: Add Intel Quark X1000 GPIO Controller (non-legacy) interrupt support Since Galileo pinmux is available, this patch adds interrupt support for GPIO Controller (non-legacy). --- cpu/x86/drivers/quarkX1000/gpio.c | 86 ++++++++++++++++++++++++++++--- cpu/x86/drivers/quarkX1000/gpio.h | 4 ++ 2 files changed, 82 insertions(+), 8 deletions(-) diff --git a/cpu/x86/drivers/quarkX1000/gpio.c b/cpu/x86/drivers/quarkX1000/gpio.c index aa9932681..45bcae711 100644 --- a/cpu/x86/drivers/quarkX1000/gpio.c +++ b/cpu/x86/drivers/quarkX1000/gpio.c @@ -30,6 +30,8 @@ #include "gpio.h" #include "helpers.h" +#include "interrupt.h" +#include "pic.h" /* GPIO Controler Registers */ #define SWPORTA_DR 0x00 @@ -47,8 +49,12 @@ #define PINS 8 +#define GPIO_IRQ 10 +#define GPIO_INT PIC_INT(GPIO_IRQ) + struct gpio_internal_data { pci_driver_t pci; + quarkX1000_gpio_callback callback; }; static struct gpio_internal_data data; @@ -79,6 +85,44 @@ set_bit(uint32_t base_addr, uint32_t offset, uint32_t bit, uint32_t value) write(base_addr, offset, reg); } +static void +gpio_isr(void) +{ + uint32_t int_status; + + int_status = read(data.pci.mmio, INTSTATUS); + + if (data.callback) + data.callback(int_status); + + write(data.pci.mmio, PORTA_EOI, -1); +} + +static void +gpio_interrupt_config(uint8_t pin, int flags) +{ + /* set as input */ + set_bit(data.pci.mmio, SWPORTA_DDR, pin, 0); + + /* set interrupt enabled */ + set_bit(data.pci.mmio, INTEN, pin, 1); + + /* unmask interrupt */ + set_bit(data.pci.mmio, INTMASK, pin, 0); + + /* set active high/low */ + set_bit(data.pci.mmio, INT_POLARITY, pin, !!(flags & QUARKX1000_GPIO_ACTIVE_HIGH)); + + /* set level/edge */ + set_bit(data.pci.mmio, INTTYPE_LEVEL, pin, !!(flags & QUARKX1000_GPIO_EDGE)); + + /* set debounce */ + set_bit(data.pci.mmio, DEBOUNCE, pin, !!(flags & QUARKX1000_GPIO_DEBOUNCE)); + + /* set clock synchronous */ + set_bit(data.pci.mmio, LS_SYNC, 0, !!(flags & QUARKX1000_GPIO_CLOCK_SYNC)); +} + int quarkX1000_gpio_config(uint8_t pin, int flags) { @@ -87,15 +131,15 @@ quarkX1000_gpio_config(uint8_t pin, int flags) return -1; } - /* interrupts are not supported yet */ - if (flags & QUARKX1000_GPIO_INT) - return -1; + if (flags & QUARKX1000_GPIO_INT) { + gpio_interrupt_config(pin, flags); + } else { + /* set direction */ + set_bit(data.pci.mmio, SWPORTA_DDR, pin, !!(flags & QUARKX1000_GPIO_OUT)); - /* set direction */ - set_bit(data.pci.mmio, SWPORTA_DDR, pin, !!(flags & QUARKX1000_GPIO_OUT)); - - /* set interrupt disabled */ - set_bit(data.pci.mmio, INTEN, pin, 0); + /* set interrupt disabled */ + set_bit(data.pci.mmio, INTEN, pin, 0); + } return 0; } @@ -146,6 +190,13 @@ quarkX1000_gpio_write_port(uint8_t value) return 0; } +int +quarkX1000_gpio_set_callback(quarkX1000_gpio_callback callback) +{ + data.callback = callback; + return 0; +} + void quarkX1000_gpio_clock_enable(void) { @@ -158,6 +209,14 @@ quarkX1000_gpio_clock_disable(void) set_bit(data.pci.mmio, LS_SYNC, 0, 0); } +static void +gpio_handler(void) +{ + gpio_isr(); + + pic_eoi(GPIO_IRQ); +} + int quarkX1000_gpio_init(void) { @@ -171,8 +230,17 @@ quarkX1000_gpio_init(void) pci_command_enable(pci_addr, PCI_CMD_1_MEM_SPACE_EN); + SET_INTERRUPT_HANDLER(GPIO_INT, 0, gpio_handler); + + if (pci_irq_agent_set_pirq(IRQAGENT3, INTA, PIRQC) < 0) + return -1; + + pci_pirq_set_irq(PIRQC, GPIO_IRQ, 1); + pci_init(&data.pci, pci_addr, 0); + data.callback = 0; + quarkX1000_gpio_clock_enable(); /* clear registers */ @@ -180,5 +248,7 @@ quarkX1000_gpio_init(void) write(data.pci.mmio, INTMASK, 0); write(data.pci.mmio, PORTA_EOI, 0); + pic_unmask_irq(GPIO_IRQ); + return 0; } diff --git a/cpu/x86/drivers/quarkX1000/gpio.h b/cpu/x86/drivers/quarkX1000/gpio.h index c63e6dc91..61ef11aab 100644 --- a/cpu/x86/drivers/quarkX1000/gpio.h +++ b/cpu/x86/drivers/quarkX1000/gpio.h @@ -54,6 +54,8 @@ #define QUARKX1000_GPIO_POL_MASK (1 << 6) #define QUARKX1000_GPIO_PUD_MASK (3 << 7) +typedef void (*quarkX1000_gpio_callback)(uint32_t); + int quarkX1000_gpio_init(void); int quarkX1000_gpio_config(uint8_t pin, int flags); @@ -64,6 +66,8 @@ int quarkX1000_gpio_config_port(int flags); int quarkX1000_gpio_read_port(uint8_t *value); int quarkX1000_gpio_write_port(uint8_t value); +int quarkX1000_gpio_set_callback(quarkX1000_gpio_callback callback); + void quarkX1000_gpio_clock_enable(void); void quarkX1000_gpio_clock_disable(void); From 77327181e0f49ba01d9248330244ec78ae7af6e0 Mon Sep 17 00:00:00 2001 From: Ricardo de Almeida Gonzaga Date: Wed, 21 Oct 2015 14:02:50 -0200 Subject: [PATCH 79/92] galileo: Add GPIO interrupt example This patch introduces an example application to demonstrate how to use GPIO driver APIs to manipulate interrupt pins. The application uses default galileo pinmux initialization and sets the GPIO 5 (IO2) as output pin and GPIO 6 (IO3) as interrupt. It toggles the output pin stat at every half second in order to emulate an interrupt. This triggers an interrupt and the application callback is called. --- examples/galileo/Makefile | 2 +- examples/galileo/README | 10 ++++ examples/galileo/gpio-interrupt.c | 94 +++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 examples/galileo/gpio-interrupt.c diff --git a/examples/galileo/Makefile b/examples/galileo/Makefile index f9f678481..19a29f78a 100644 --- a/examples/galileo/Makefile +++ b/examples/galileo/Makefile @@ -1,6 +1,6 @@ TARGET=galileo -KNOWN_EXAMPLES = gpio-input gpio-output i2c-LSM9DS0 +KNOWN_EXAMPLES = gpio-input gpio-output gpio-interrupt i2c-LSM9DS0 ifneq ($(filter $(EXAMPLE),$(KNOWN_EXAMPLES)),) CONTIKI_PROJECT = $(EXAMPLE) diff --git a/examples/galileo/README b/examples/galileo/README index b7698cb5d..643a2e418 100644 --- a/examples/galileo/README +++ b/examples/galileo/README @@ -31,6 +31,16 @@ pins. This application uses default galileo pinmux initialization and sets the GPIO 5 (IO2) as output pin and GPIO 6 (IO3) as input. It toggles the output pin state at every half second and checks the value on input pin. +GPIO Interrupt +============== + +This application shows how to use the GPIO driver APIs to manipulate interrupt +pins. This application uses default galileo pinmux initialization and sets +the GPIO 5 (IO2) as output pin and GPIO 6 (IO3) as interrupt. It toggles the +output pin stat at every half second in order to emulate an interrupt. This +triggers an interrupt and the application callback is called. You can confirm +that though the UART output. + ======= = I2C = ======= diff --git a/examples/galileo/gpio-interrupt.c b/examples/galileo/gpio-interrupt.c new file mode 100644 index 000000000..149279f6f --- /dev/null +++ b/examples/galileo/gpio-interrupt.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "contiki.h" +#include "sys/ctimer.h" + +#include "gpio.h" +#include "i2c.h" +#include "galileo-pinmux.h" + +#define PIN_OUTPUT 5 +#define PIN_INTR 6 + +static struct ctimer timer; +static struct quarkX1000_i2c_config i2c_config; + +PROCESS(gpio_interrupt_process, "GPIO Interrupt Process"); +AUTOSTART_PROCESSES(&gpio_interrupt_process); +/*---------------------------------------------------------------------------*/ +static void +timeout(void *data) +{ + /* emulate an interrupt */ + quarkX1000_gpio_write(PIN_OUTPUT, 0); + quarkX1000_gpio_write(PIN_OUTPUT, 1); + + ctimer_reset(&timer); +} +/*---------------------------------------------------------------------------*/ +static void +callback(uint32_t status) +{ + printf("GPIO interrupt callback called, status: %d\n", status); +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(gpio_interrupt_process, ev, data) +{ + PROCESS_BEGIN(); + + i2c_config.speed = QUARKX1000_I2C_SPEED_STANDARD; + i2c_config.addressing_mode = QUARKX1000_I2C_ADDR_MODE_7BIT; + + quarkX1000_i2c_init(); + quarkX1000_i2c_configure(&i2c_config); + + /* use default pinmux configuration */ + galileo_pinmux_initialize(); + + quarkX1000_gpio_init(); + quarkX1000_gpio_config(PIN_OUTPUT, QUARKX1000_GPIO_OUT); + quarkX1000_gpio_config(PIN_INTR, QUARKX1000_GPIO_INT | QUARKX1000_GPIO_ACTIVE_HIGH | QUARKX1000_GPIO_EDGE); + + quarkX1000_gpio_set_callback(callback); + + quarkX1000_gpio_clock_enable(); + + ctimer_set(&timer, CLOCK_SECOND / 2, timeout, NULL); + + printf("GPIO interrupt example is running\n"); + PROCESS_YIELD(); + + quarkX1000_gpio_clock_disable(); + + PROCESS_END(); +} From ba09b47d65f543f06e7c59f62d6bcbc6f450b79a Mon Sep 17 00:00:00 2001 From: Ricardo de Almeida Gonzaga Date: Fri, 23 Oct 2015 10:41:11 -0200 Subject: [PATCH 80/92] galileo: Initialize pinmux in i2c-LSM9DS0 example In order to ensure SCL and SDA are exported in the correct pins. --- examples/galileo/i2c-LSM9DS0.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/examples/galileo/i2c-LSM9DS0.c b/examples/galileo/i2c-LSM9DS0.c index 9abfffcc8..e5a47c458 100644 --- a/examples/galileo/i2c-LSM9DS0.c +++ b/examples/galileo/i2c-LSM9DS0.c @@ -34,6 +34,7 @@ #include "contiki.h" #include "sys/ctimer.h" +#include "galileo-pinmux.h" #include "i2c.h" #define LSM9DS0_I2C_ADDR 0x6A @@ -85,11 +86,16 @@ PROCESS_THREAD(i2c_lsm9ds0_process, ev, data) cfg.speed = QUARKX1000_I2C_SPEED_STANDARD; cfg.addressing_mode = QUARKX1000_I2C_ADDR_MODE_7BIT; + + quarkX1000_i2c_init(); + quarkX1000_i2c_configure(&cfg); + + galileo_pinmux_initialize(); + cfg.cb_rx = rx; cfg.cb_tx = tx; cfg.cb_err = err; - quarkX1000_i2c_init(); quarkX1000_i2c_configure(&cfg); ctimer_set(&timer, CLOCK_SECOND * 5, timeout, NULL); From abeed93da59cc6d182d1852eb03a174331963f4a Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Tue, 7 Jul 2015 16:07:00 -0700 Subject: [PATCH 81/92] x86: Add driver for Intel Quark X1000 built-in Ethernet This patch adds a simple, space-efficient driver for the Ethernet interface built into the Intel Quark X1000. It only allocates a single packet descriptor for each of the transmit and receive directions, computes checksums on the CPU, and enables store-and-forward mode for both transmit and receive directions. --- cpu/x86/Makefile.x86_quarkX1000 | 2 +- cpu/x86/drivers/legacy_pc/pci.c | 2 +- cpu/x86/drivers/quarkX1000/eth.c | 372 +++++++++++++++++++++++++++++++ cpu/x86/drivers/quarkX1000/eth.h | 40 ++++ 4 files changed, 414 insertions(+), 2 deletions(-) create mode 100644 cpu/x86/drivers/quarkX1000/eth.c create mode 100644 cpu/x86/drivers/quarkX1000/eth.h diff --git a/cpu/x86/Makefile.x86_quarkX1000 b/cpu/x86/Makefile.x86_quarkX1000 index 8e78fd95e..192fd302b 100644 --- a/cpu/x86/Makefile.x86_quarkX1000 +++ b/cpu/x86/Makefile.x86_quarkX1000 @@ -2,7 +2,7 @@ include $(CONTIKI)/cpu/x86/Makefile.x86_common CONTIKI_CPU_DIRS += drivers/legacy_pc drivers/quarkX1000 init/legacy_pc -CONTIKI_SOURCEFILES += bootstrap_quarkX1000.S rtc.c pit.c pic.c irq.c nmi.c pci.c uart-16x50.c uart.c gpio.c i2c.c +CONTIKI_SOURCEFILES += bootstrap_quarkX1000.S rtc.c pit.c pic.c irq.c nmi.c pci.c uart-16x50.c uart.c gpio.c i2c.c eth.c CFLAGS += -m32 -march=i586 -mtune=i586 LDFLAGS += -m32 -Xlinker -T -Xlinker $(CONTIKI)/cpu/x86/quarkX1000.ld diff --git a/cpu/x86/drivers/legacy_pc/pci.c b/cpu/x86/drivers/legacy_pc/pci.c index 2af9f4883..0507ad231 100644 --- a/cpu/x86/drivers/legacy_pc/pci.c +++ b/cpu/x86/drivers/legacy_pc/pci.c @@ -236,7 +236,7 @@ pci_pirq_set_irq(PIRQ pirq, uint8_t irq, uint8_t route_to_legacy) void pci_init(pci_driver_t *c_this, pci_config_addr_t pci_addr, uintptr_t meta) { - /* The reg_off (BAR) value is masked to clear non-address bits. */ + /* The BAR value is masked to clear non-address bits. */ c_this->mmio = pci_config_read(pci_addr) & ~0xFFF; c_this->meta = meta; } diff --git a/cpu/x86/drivers/quarkX1000/eth.c b/cpu/x86/drivers/quarkX1000/eth.c new file mode 100644 index 000000000..2f02213ea --- /dev/null +++ b/cpu/x86/drivers/quarkX1000/eth.c @@ -0,0 +1,372 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include "contiki-net.h" +#include "eth.h" +#include "helpers.h" +#include "net/ip/uip.h" +#include "pci.h" + +typedef pci_driver_t quarkX1000_eth_driver_t; + +/* Refer to Intel Quark SoC X1000 Datasheet, Chapter 15 for more details on + * Ethernet device operation. + * + * This driver puts the Ethernet device into a very simple and space-efficient + * mode of operation. It only allocates a single packet descriptor for each of + * the transmit and receive directions, computes checksums on the CPU, and + * enables store-and-forward mode for both transmit and receive directions. + */ + +/* Transmit descriptor */ +typedef struct quarkX1000_eth_tx_desc { + /* First word of transmit descriptor */ + union { + struct { + /* Only valid in half-duplex mode. */ + uint32_t deferred_bit : 1; + uint32_t err_underflow : 1; + uint32_t err_excess_defer : 1; + uint32_t coll_cnt_slot_num : 4; + uint32_t vlan_frm : 1; + uint32_t err_excess_coll : 1; + uint32_t err_late_coll : 1; + uint32_t err_no_carrier : 1; + uint32_t err_carrier_loss : 1; + uint32_t err_ip_payload : 1; + uint32_t err_frm_flushed : 1; + uint32_t err_jabber_tout : 1; + /* OR of all other error bits. */ + uint32_t err_summary : 1; + uint32_t err_ip_hdr : 1; + uint32_t tx_timestamp_stat : 1; + uint32_t vlan_ins_ctrl : 2; + uint32_t addr2_chained : 1; + uint32_t tx_end_of_ring : 1; + uint32_t chksum_ins_ctrl : 2; + uint32_t replace_crc : 1; + uint32_t tx_timestamp_en : 1; + uint32_t dis_pad : 1; + uint32_t dis_crc : 1; + uint32_t first_seg_in_frm : 1; + uint32_t last_seg_in_frm : 1; + uint32_t intr_on_complete : 1; + /* When set, descriptor is owned by DMA. */ + uint32_t own : 1; + }; + uint32_t tdes0; + }; + /* Second word of transmit descriptor */ + union { + struct { + uint32_t tx_buf1_sz : 13; + uint32_t : 3; + uint32_t tx_buf2_sz : 13; + uint32_t src_addr_ins_ctrl : 3; + }; + uint32_t tdes1; + }; + /* Pointer to frame data buffer */ + uint8_t *buf1_ptr; + /* Unused, since this driver initializes only a single descriptor for each + * direction. + */ + uint8_t *buf2_ptr; +} quarkX1000_eth_tx_desc_t; + +/* Transmit descriptor */ +typedef struct quarkX1000_eth_rx_desc { + /* First word of receive descriptor */ + union { + struct { + uint32_t ext_stat : 1; + uint32_t err_crc : 1; + uint32_t err_dribble_bit : 1; + uint32_t err_rx_mii : 1; + uint32_t err_rx_wdt : 1; + uint32_t frm_type : 1; + uint32_t err_late_coll : 1; + uint32_t giant_frm : 1; + uint32_t last_desc : 1; + uint32_t first_desc : 1; + uint32_t vlan_tag : 1; + uint32_t err_overflow : 1; + uint32_t length_err : 1; + uint32_t s_addr_filt_fail : 1; + uint32_t err_desc : 1; + uint32_t err_summary : 1; + uint32_t frm_len : 14; + uint32_t d_addr_filt_fail : 1; + uint32_t own : 1; + }; + uint32_t rdes0; + }; + /* Second word of receive descriptor */ + union { + struct { + uint32_t rx_buf1_sz : 13; + uint32_t : 1; + uint32_t addr2_chained : 1; + uint32_t rx_end_of_ring : 1; + uint32_t rx_buf2_sz : 13; + uint32_t : 2; + uint32_t dis_int_compl : 1; + }; + uint32_t rdes1; + }; + /* Pointer to frame data buffer */ + uint8_t *buf1_ptr; + /* Unused, since this driver initializes only a single descriptor for each + * direction. + */ + uint8_t *buf2_ptr; +} quarkX1000_eth_rx_desc_t; + +/* Driver metadata associated with each Ethernet device */ +typedef struct quarkX1000_eth_meta { + /* Transmit descriptor */ + volatile quarkX1000_eth_tx_desc_t tx_desc; + /* Transmit DMA packet buffer */ + volatile uint8_t tx_buf[UIP_BUFSIZE]; + /* Receive descriptor */ + volatile quarkX1000_eth_rx_desc_t rx_desc; + /* Receive DMA packet buffer */ + volatile uint8_t rx_buf[UIP_BUFSIZE]; +} quarkX1000_eth_meta_t; + +#define LOG_PFX "quarkX1000_eth: " + +#define MMIO_SZ 0x2000 + +#define MAC_CONF_14_RMII_100M BIT(14) +#define MAC_CONF_11_DUPLEX BIT(11) +#define MAC_CONF_3_TX_EN BIT(3) +#define MAC_CONF_2_RX_EN BIT(2) + +#define OP_MODE_25_RX_STORE_N_FORWARD BIT(25) +#define OP_MODE_21_TX_STORE_N_FORWARD BIT(21) +#define OP_MODE_13_START_TX BIT(13) +#define OP_MODE_1_START_RX BIT(1) + +#define REG_ADDR_MAC_CONF 0x0000 +#define REG_ADDR_MACADDR_HI 0x0040 +#define REG_ADDR_MACADDR_LO 0x0044 +#define REG_ADDR_TX_POLL_DEMAND 0x1004 +#define REG_ADDR_RX_POLL_DEMAND 0x1008 +#define REG_ADDR_RX_DESC_LIST 0x100C +#define REG_ADDR_TX_DESC_LIST 0x1010 +#define REG_ADDR_DMA_OPERATION 0x1018 + +static quarkX1000_eth_driver_t drv; +static quarkX1000_eth_meta_t meta; + +/*---------------------------------------------------------------------------*/ +/** + * \brief Initialize the first Quark X1000 Ethernet MAC. + * + * This procedure assumes that an MMIO range for the device was + * previously assigned, e.g. by firmware. + */ +void +quarkX1000_eth_init(void) +{ + pci_config_addr_t pci_addr = { .raw = 0 }; + uip_eth_addr mac_addr; + uint32_t mac_tmp1, mac_tmp2; + + /* PCI address from section 15.4 of Intel Quark SoC X1000 Datasheet. */ + + pci_addr.dev = 20; + pci_addr.func = 6; + + /* Activate MMIO and DMA access. */ + pci_command_enable(pci_addr, PCI_CMD_2_BUS_MST_EN | PCI_CMD_1_MEM_SPACE_EN); + + printf(LOG_PFX "Activated MMIO and DMA access.\n"); + + pci_addr.reg_off = PCI_CONFIG_REG_BAR0; + + /* Configure the device MMIO range and initialize the driver structure. */ + pci_init(&drv, pci_addr, (uintptr_t)&meta); + + /* Read the MAC address from the device. */ + PCI_MMIO_READL(drv, mac_tmp1, REG_ADDR_MACADDR_HI); + PCI_MMIO_READL(drv, mac_tmp2, REG_ADDR_MACADDR_LO); + + /* Convert the data read from the device into the format expected by + * Contiki. + */ + mac_addr.addr[5] = (uint8_t)(mac_tmp1 >> 8); + mac_addr.addr[4] = (uint8_t)mac_tmp1; + mac_addr.addr[3] = (uint8_t)(mac_tmp2 >> 24); + mac_addr.addr[2] = (uint8_t)(mac_tmp2 >> 16); + mac_addr.addr[1] = (uint8_t)(mac_tmp2 >> 8); + mac_addr.addr[0] = (uint8_t)mac_tmp2; + + printf(LOG_PFX "MAC address = %02x:%02x:%02x:%02x:%02x:%02x.\n", + mac_addr.addr[0], + mac_addr.addr[1], + mac_addr.addr[2], + mac_addr.addr[3], + mac_addr.addr[4], + mac_addr.addr[5] + ); + + uip_setethaddr(mac_addr); + + /* Initialize transmit descriptor. */ + meta.tx_desc.tdes0 = 0; + meta.tx_desc.tdes1 = 0; + + meta.tx_desc.buf1_ptr = (uint8_t *)meta.tx_buf; + meta.tx_desc.tx_end_of_ring = 1; + meta.tx_desc.first_seg_in_frm = 1; + meta.tx_desc.last_seg_in_frm = 1; + meta.tx_desc.tx_end_of_ring = 1; + + /* Initialize receive descriptor. */ + meta.rx_desc.rdes0 = 0; + meta.rx_desc.rdes1 = 0; + + meta.rx_desc.buf1_ptr = (uint8_t *)meta.rx_buf; + meta.rx_desc.own = 1; + meta.rx_desc.first_desc = 1; + meta.rx_desc.last_desc = 1; + meta.rx_desc.rx_buf1_sz = UIP_BUFSIZE; + meta.rx_desc.rx_end_of_ring = 1; + + /* Install transmit and receive descriptors. */ + PCI_MMIO_WRITEL(drv, REG_ADDR_RX_DESC_LIST, (uint32_t)&meta.rx_desc); + PCI_MMIO_WRITEL(drv, REG_ADDR_TX_DESC_LIST, (uint32_t)&meta.tx_desc); + + PCI_MMIO_WRITEL(drv, REG_ADDR_MAC_CONF, + /* Set the RMII speed to 100Mbps */ + MAC_CONF_14_RMII_100M | + /* Enable full-duplex mode */ + MAC_CONF_11_DUPLEX | + /* Enable transmitter */ + MAC_CONF_3_TX_EN | + /* Enable receiver */ + MAC_CONF_2_RX_EN); + + PCI_MMIO_WRITEL(drv, REG_ADDR_DMA_OPERATION, + /* Enable receive store-and-forward mode for simplicity. */ + OP_MODE_25_RX_STORE_N_FORWARD | + /* Enable transmit store-and-forward mode for simplicity. */ + OP_MODE_21_TX_STORE_N_FORWARD | + /* Place the transmitter state machine in the Running + state. */ + OP_MODE_13_START_TX | + /* Place the receiver state machine in the Running state. */ + OP_MODE_1_START_RX); + + printf(LOG_PFX "Enabled 100M full-duplex mode.\n"); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Poll for a received Ethernet frame. + * \param frame_len Will be set to the size of the received Ethernet frame or + * zero if no frame is available. + * + * If a frame is received, this procedure copies it into the + * global uip_buf buffer. + */ +void +quarkX1000_eth_poll(uint16_t *frame_len) +{ + uint16_t frm_len = 0; + + /* Check whether the RX descriptor is still owned by the device. If not, + * process the received frame or an error that may have occurred. + */ + if(meta.rx_desc.own == 0) { + if(meta.rx_desc.err_summary) { + fprintf(stderr, + LOG_PFX "Error receiving frame: RDES0 = %08x, RDES1 = %08x.\n", + meta.rx_desc.rdes0, meta.rx_desc.rdes1); + assert(0); + } + + frm_len = meta.rx_desc.frm_len; + assert(frm_len <= UIP_BUFSIZE); + memcpy(uip_buf, (void *)meta.rx_buf, frm_len); + + /* Return ownership of the RX descriptor to the device. */ + meta.rx_desc.own = 1; + + /* Request that the device check for an available RX descriptor, since + * ownership of the descriptor was just transferred to the device. + */ + PCI_MMIO_WRITEL(drv, REG_ADDR_RX_POLL_DEMAND, 1); + } + + *frame_len = frm_len; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Transmit the current Ethernet frame. + * + * This procedure will block indefinitely until the Ethernet device is + * ready to accept a new outgoing frame. It then copies the current + * Ethernet frame from the global uip_buf buffer to the device DMA + * buffer and signals to the device that a new frame is available to be + * transmitted. + */ +void +quarkX1000_eth_send(void) +{ + /* Wait until the TX descriptor is no longer owned by the device. */ + while(meta.tx_desc.own == 1); + + /* Check whether an error occurred transmitting the previous frame. */ + if(meta.tx_desc.err_summary) { + fprintf(stderr, + LOG_PFX "Error transmitting frame: TDES0 = %08x, TDES1 = %08x.\n", + meta.tx_desc.tdes0, meta.tx_desc.tdes1); + assert(0); + } + + /* Transmit the next frame. */ + assert(uip_len <= UIP_BUFSIZE); + memcpy((void *)meta.tx_buf, uip_buf, uip_len); + + meta.tx_desc.tx_buf1_sz = uip_len; + + meta.tx_desc.own = 1; + + /* Request that the device check for an available TX descriptor, since + * ownership of the descriptor was just transferred to the device. + */ + PCI_MMIO_WRITEL(drv, REG_ADDR_TX_POLL_DEMAND, 1); +} +/*---------------------------------------------------------------------------*/ diff --git a/cpu/x86/drivers/quarkX1000/eth.h b/cpu/x86/drivers/quarkX1000/eth.h new file mode 100644 index 000000000..e94267466 --- /dev/null +++ b/cpu/x86/drivers/quarkX1000/eth.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CPU_X86_DRIVERS_QUARKX1000_ETH_H_ +#define CPU_X86_DRIVERS_QUARKX1000_ETH_H_ + +#include + +void quarkX1000_eth_init(void); +void quarkX1000_eth_poll(uint16_t *frame_len); +void quarkX1000_eth_send(void); + +#endif /* CPU_X86_DRIVERS_QUARKX1000_ETH_H_ */ From 38206e398040e834886068fef2b27293ac9577d0 Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Tue, 7 Jul 2015 16:40:21 -0700 Subject: [PATCH 82/92] galileo: Add Ethernet support This patch adds support for Ethernet to the Intel Galileo port. It uses the Intel Quark X1000 Ethernet driver. It initializes the first Ethernet interface and starts some common network services. By default, it uses the following addresses: - Host: 192.0.2.2 - Netmask: 255.255.255.0 - Default gateway: 192.0.2.1 - DNS server: (same as default gateway) These settings can be changed by editing eth-conf.c. --- platform/galileo/Makefile.galileo | 8 ++- platform/galileo/README.md | 1 + platform/galileo/contiki-conf.h | 12 ++++ platform/galileo/contiki-main.c | 13 +++- platform/galileo/net/eth-conf.c | 75 ++++++++++++++++++++ platform/galileo/net/eth-conf.h | 36 ++++++++++ platform/galileo/net/eth-proc.c | 112 ++++++++++++++++++++++++++++++ platform/galileo/net/eth-proc.h | 38 ++++++++++ 8 files changed, 292 insertions(+), 3 deletions(-) create mode 100644 platform/galileo/net/eth-conf.c create mode 100644 platform/galileo/net/eth-conf.h create mode 100644 platform/galileo/net/eth-proc.c create mode 100644 platform/galileo/net/eth-proc.h diff --git a/platform/galileo/Makefile.galileo b/platform/galileo/Makefile.galileo index bbf937ac0..189471fc2 100644 --- a/platform/galileo/Makefile.galileo +++ b/platform/galileo/Makefile.galileo @@ -3,9 +3,13 @@ LIBC_PATH=$(BSP_PATH)/libc LIBC=$(LIBC_PATH)/i586-elf LIBGCC_PATH = /usr/lib/gcc/$(shell gcc -dumpmachine)/$(shell gcc -dumpversion) -CONTIKI_TARGET_DIRS = . core/sys/ drivers/ +CONTIKI_TARGET_DIRS = . core/sys/ drivers/ net/ CONTIKI_TARGET_MAIN = ${addprefix $(OBJECTDIR)/,contiki-main.o} -CONTIKI_SOURCEFILES += contiki-main.c clock.c rtimer-arch.c gpio-pcal9535a.c pwm-pca9685.c galileo-pinmux.c +CONTIKI_SOURCEFILES += contiki-main.c clock.c rtimer-arch.c gpio-pcal9535a.c pwm-pca9685.c galileo-pinmux.c eth-proc.c eth-conf.c + +ifeq ($(CONTIKI_WITH_IPV6),1) + CONTIKI_SOURCEFILES += nbr-table.c packetbuf.c linkaddr.c +endif PROJECT_SOURCEFILES += newlib-syscalls.c diff --git a/platform/galileo/README.md b/platform/galileo/README.md index ba0c79670..e58722634 100644 --- a/platform/galileo/README.md +++ b/platform/galileo/README.md @@ -29,6 +29,7 @@ Device drivers: * Programmable Intergal Timer (PIT) * Real-Time Clock (RTC) * UART + * Ethernet Contiki APIs: * Clock module diff --git a/platform/galileo/contiki-conf.h b/platform/galileo/contiki-conf.h index 4f1b0fe4b..dca42b8de 100644 --- a/platform/galileo/contiki-conf.h +++ b/platform/galileo/contiki-conf.h @@ -31,6 +31,14 @@ #ifndef CONTIKI_CONF_H #define CONTIKI_CONF_H +/* Include the default configuration file early here so that this file can + * unconfigure the IP buffer size. That will allow uipopt.h to define a + * default IP buffer size that is larger and more useful. + */ +#include "contiki-default-conf.h" + +#undef UIP_CONF_BUFFER_SIZE + #include #define CLOCK_CONF_SECOND 128 @@ -46,6 +54,10 @@ typedef uint64_t rtimer_clock_t; #define CCIF #define CLIF +#define UIP_CONF_LLH_LEN 14 + +#define LINKADDR_CONF_SIZE 6 + typedef unsigned short uip_stats_t; #endif /* CONTIKI_CONF_H */ diff --git a/platform/galileo/contiki-main.c b/platform/galileo/contiki-main.c index 7e8658d60..943ac3174 100644 --- a/platform/galileo/contiki-main.c +++ b/platform/galileo/contiki-main.c @@ -31,9 +31,18 @@ #include #include "contiki.h" +#include "contiki-net.h" #include "cpu.h" #include "interrupt.h" #include "uart.h" +#include "eth-conf.h" + +PROCINIT( &etimer_process + , &tcpip_process +#if WITH_DNS + , &resolv_process +#endif + ); int main(void) @@ -49,10 +58,12 @@ main(void) ENABLE_IRQ(); process_init(); - process_start(&etimer_process, NULL); + procinit_init(); ctimer_init(); autostart_start(autostart_processes); + eth_init(); + while(1) { process_run(); } diff --git a/platform/galileo/net/eth-conf.c b/platform/galileo/net/eth-conf.c new file mode 100644 index 000000000..ff3a771bf --- /dev/null +++ b/platform/galileo/net/eth-conf.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "eth-conf.h" +#include "eth.h" +#include "net/eth-proc.h" +#include "contiki-net.h" +#include "net/linkaddr.h" + +#if NETSTACK_CONF_WITH_IPV6 +const linkaddr_t linkaddr_null = { { 0, 0, 0, 0, 0, 0 } }; +#else +/* 192.0.2.0/24 is a block reserved for documentation by RFC 5737. */ +#define SUBNET_IP 192, 0, 2 +#define NETMASK_IP 255, 255, 255, 0 +#define HOST_IP SUBNET_IP, 2 +#define GATEWAY_IP SUBNET_IP, 1 +#define NAMESERVER_IP GATEWAY_IP +#endif + +void +eth_init(void) +{ +#if !NETSTACK_CONF_WITH_IPV6 + uip_ipaddr_t ip_addr; + +#define SET_IP_ADDR(x) \ + uip_ipaddr(&ip_addr, x) + + SET_IP_ADDR(HOST_IP); + uip_sethostaddr(&ip_addr); + + SET_IP_ADDR(NETMASK_IP); + uip_setnetmask(&ip_addr); + + SET_IP_ADDR(GATEWAY_IP); + uip_setdraddr(&ip_addr); + +#if WITH_DNS + SET_IP_ADDR(NAMESERVER_IP); + uip_nameserver_update(&ip_addr, UIP_NAMESERVER_INFINITE_LIFETIME); +#endif +#endif + + quarkX1000_eth_init(); + + process_start(ð_process, NULL); +} diff --git a/platform/galileo/net/eth-conf.h b/platform/galileo/net/eth-conf.h new file mode 100644 index 000000000..e84091809 --- /dev/null +++ b/platform/galileo/net/eth-conf.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PLATFORM_GALILEO_ETH_CONF_H_ +#define PLATFORM_GALILEO_ETH_CONF_H_ + +void eth_init(void); + +#endif /* PLATFORM_GALILEO_ETH_CONF_H_ */ diff --git a/platform/galileo/net/eth-proc.c b/platform/galileo/net/eth-proc.c new file mode 100644 index 000000000..412d0c8cf --- /dev/null +++ b/platform/galileo/net/eth-proc.c @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "contiki-net.h" +#include "net/ipv4/uip-neighbor.h" +#include "net/eth-proc.h" +#include "eth.h" + +#define BUF ((struct uip_eth_hdr *)&uip_buf[0]) +#define IPBUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) + +PROCESS(eth_process, "Ethernet"); + +/*---------------------------------------------------------------------------*/ +#if NETSTACK_CONF_WITH_IPV6 +static uint8_t +output(const uip_lladdr_t *dest_mac) +{ + if (dest_mac == NULL) { + /* broadcast packet */ + memset(&BUF->dest, 0xFF, UIP_LLH_LEN); + } else { + memcpy(&BUF->dest, dest_mac, UIP_LLH_LEN); + } + memcpy(&BUF->src, uip_lladdr.addr, UIP_LLH_LEN); + quarkX1000_eth_send(); + + return 0; +} +#else +static uint8_t +output(void) +{ + uip_arp_out(); + quarkX1000_eth_send(); + + return 0; +} +#endif /* NETSTACK_CONF_WITH_IPV6 */ +/*---------------------------------------------------------------------------*/ +static void +pollhandler(void) +{ + process_poll(ð_process); + quarkX1000_eth_poll(&uip_len); + + if(uip_len > 0) { +#if NETSTACK_CONF_WITH_IPV6 + if(BUF->type == uip_htons(UIP_ETHTYPE_IPV6)) { + tcpip_input(); + } +#else + if(BUF->type == uip_htons(UIP_ETHTYPE_IP)) { + uip_len -= sizeof(struct uip_eth_hdr); + tcpip_input(); + } else if(BUF->type == uip_htons(UIP_ETHTYPE_ARP)) { + uip_arp_arpin(); + /* If the above function invocation resulted in data that + should be sent out on the network, the global variable + uip_len is set to a value > 0. */ + if(uip_len > 0) { + quarkX1000_eth_send(); + } + } +#endif /* NETSTACK_CONF_WITH_IPV6 */ + } +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(eth_process, ev, data) +{ + PROCESS_POLLHANDLER(pollhandler()); + + PROCESS_BEGIN(); + + tcpip_set_outputfunc(output); + + process_poll(ð_process); + + PROCESS_WAIT_UNTIL(ev == PROCESS_EVENT_EXIT); + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/platform/galileo/net/eth-proc.h b/platform/galileo/net/eth-proc.h new file mode 100644 index 000000000..88dbf4c7b --- /dev/null +++ b/platform/galileo/net/eth-proc.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PLATFORM_GALILEO_NET_ETH_PROC_H_ +#define PLATFORM_GALILEO_NET_ETH_PROC_H_ + +#include "contiki.h" + +PROCESS_NAME(eth_process); + +#endif /* PLATFORM_GALILEO_NET_ETH_PROC_H_ */ From b915e7d5e3e226fa43ec68417b7cc2a49bf736e8 Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Sun, 26 Jul 2015 19:28:31 -0700 Subject: [PATCH 83/92] galileo: Omit exception handling unwind tables This patch modifies the newlib and Contiki C and C++ compiler flags to omit exception handling unwind tables (see http://wiki.dwarfstd.org/index.php?title=Exception_Handling). Removing these tables saves space in debug builds and has not caused any readily-apparent functional changes. Here is the size listing for an example program built without this patch: text data bss dec hex filename 76002 1508 21224 98734 181ae all-timers.galileo Here is the size listing for the same program with this patch: text data bss dec hex filename 72918 1508 21224 95650 175a2 all-timers.galileo The primary motivation for this patch is to help enable UEFI support. The .eh_frame and .eh_frame_hdr sections that are otherwise generated are treated as code sections by the EDK2 GenFw program, since they are read-only alloc sections. They get grouped with the actual code sections, ahead of the data sections. This perturbs symbols and complicates debugging. --- cpu/x86/Makefile.x86_common | 9 ++++++++- platform/galileo/bsp/libc/build_newlib.sh | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/cpu/x86/Makefile.x86_common b/cpu/x86/Makefile.x86_common index 054cfcd68..c243dddcd 100644 --- a/cpu/x86/Makefile.x86_common +++ b/cpu/x86/Makefile.x86_common @@ -9,7 +9,14 @@ OBJCOPY = objcopy SIZE = size STRIP = strip -CFLAGS += -Wall -fno-asynchronous-unwind-tables +# Omit exception handling unwind tables (see +# http://wiki.dwarfstd.org/index.php?title=Exception_Handling). Removing these +# tables saves space and has not caused any readily-apparent functional +# changes. +# +# Synchronize the unwind table options here with the CFLAGS and CXXFLAGS in +# ./bsp/libc/build_newlib.sh. +CFLAGS += -Wall -fno-asynchronous-unwind-tables -fno-unwind-tables LDFLAGS += -Wl,-Map=contiki-$(TARGET).map,--build-id=none ifeq ($(BUILD_RELEASE),1) diff --git a/platform/galileo/bsp/libc/build_newlib.sh b/platform/galileo/bsp/libc/build_newlib.sh index cee34f3ff..89d3b870c 100755 --- a/platform/galileo/bsp/libc/build_newlib.sh +++ b/platform/galileo/bsp/libc/build_newlib.sh @@ -65,8 +65,8 @@ build() { export COMPILER_AS_FOR_TARGET=as export COMPILER_LD_FOR_TARGET=ld export COMPILER_NM_FOR_TARGET=nm - export CFLAGS_FOR_TARGET="-Os -m32 -march=i586 -mtune=i586 -fno-stack-protector -DPREFER_SIZE_OVER_SPEED -ffunction-sections -fdata-sections" - export CXXFLAGS_FOR_TARGET="-Os -m32 -march=i586 -mtune=i586 -fno-stack-protector -DPREFER_SIZE_OVER_SPEED -ffunction-sections -fdata-sections" + export CFLAGS_FOR_TARGET="-Os -m32 -march=i586 -mtune=i586 -fno-stack-protector -DPREFER_SIZE_OVER_SPEED -ffunction-sections -fdata-sections -fno-asynchronous-unwind-tables -fno-unwind-tables" + export CXXFLAGS_FOR_TARGET="-Os -m32 -march=i586 -mtune=i586 -fno-stack-protector -DPREFER_SIZE_OVER_SPEED -ffunction-sections -fdata-sections -fno-asynchronous-unwind-tables -fno-unwind-tables" mkdir -p install ./configure --target=${TARGET} \ From f85654a82f2b48e3db5b72b2ad02da30bdab6a52 Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Fri, 10 Jul 2015 11:21:00 -0700 Subject: [PATCH 84/92] x86, galileo: Add UEFI support This patch adds support for optionally building EFI binaries in addition to Multiboot ELF binaries. It includes a script, build_uefi.sh, that downloads tool and library sources from the EDK II project, builds the GenFw tool that is used to create UEFI binaries, and creates a makefile that is included from the main x86 common makefile and enables UEFI support in the Contiki build system. If the script is not run prior to building Contiki, then an informational message will be displayed with instructions for running build_uefi.sh if UEFI support is desired. This patch also adds the path to the auto-generated makefile to .gitignore. This patch modifies the linker script for the Intel Quark X1000 to account for the output file section offsets and alignment expectations of the EDK II GenFw project. This patch also adds a newlib patch to remove the weak symbol attribute from floating point stdio support routines. See /newlib/README for an explanation of how the newlib developers intended for _printf_float and _scanf_float to be linked. Newlib declares them as weak symbols with the intention that developers would force them to be linked only when needed using a linker command line option. However, some but not all Contiki programs require them, so we cannot simply always include or exclude them. Instead, we remove the weak symbol attributes and rely on the linker to automatically determine whether or not they should be linked. This avoids an issue in which weak symbols were undefined in the intermediate DLL generated as part of the UEFI build process. That resulted in the GenFw program emitting "ERROR 3000" messages when it encountered relocations referencing such an undefined symbol. Finally, this patch updates README.md to both make some revisions to account for the UART support introduced in previous patches as well as to provide instructions for using the UEFI support. --- .gitignore | 6 ++ cpu/x86/Makefile.x86_common | 10 ++- cpu/x86/Makefile.x86_quarkX1000 | 28 ++++++++ cpu/x86/quarkX1000.ld | 25 +++++-- cpu/x86/uefi/bootstrap_uefi.c | 67 +++++++++++++++++++ cpu/x86/uefi/build_uefi.sh | 20 ++++++ platform/galileo/Makefile.customrules-galileo | 47 +++++++++++-- platform/galileo/README.md | 34 +++++++++- .../libc/patches/stdio_strengthen_syms.patch | 19 ++++++ 9 files changed, 240 insertions(+), 16 deletions(-) create mode 100644 cpu/x86/uefi/bootstrap_uefi.c create mode 100755 cpu/x86/uefi/build_uefi.sh create mode 100644 platform/galileo/bsp/libc/patches/stdio_strengthen_syms.patch diff --git a/.gitignore b/.gitignore index 1e566f4de..6ff425546 100644 --- a/.gitignore +++ b/.gitignore @@ -111,6 +111,10 @@ cscope.* *.swp *.swo +# x86 UEFI files +cpu/x86/uefi/Makefile.uefi +cpu/x86/uefi/edk2 + # galileo bsp files platform/galileo/bsp/libc/Makefile.libc platform/galileo/bsp/libc/i586-elf/ @@ -120,4 +124,6 @@ platform/galileo/bsp/grub/bin/ # galileo build and debug artefacts *.galileo +*.galileo.dll +*.galileo.efi LOG_OPENOCD diff --git a/cpu/x86/Makefile.x86_common b/cpu/x86/Makefile.x86_common index c243dddcd..d6e692e9a 100644 --- a/cpu/x86/Makefile.x86_common +++ b/cpu/x86/Makefile.x86_common @@ -14,6 +14,12 @@ STRIP = strip # tables saves space and has not caused any readily-apparent functional # changes. # +# Furthermore, the .eh_frame and .eh_frame_hdr sections that are otherwise +# generated are treated as code sections by the UEFI GenFw program, since they +# are read-only alloc sections. They get grouped with the actual code +# sections, ahead of the data sections. This perturbs symbols and complicates +# debugging. +# # Synchronize the unwind table options here with the CFLAGS and CXXFLAGS in # ./bsp/libc/build_newlib.sh. CFLAGS += -Wall -fno-asynchronous-unwind-tables -fno-unwind-tables @@ -23,7 +29,9 @@ ifeq ($(BUILD_RELEASE),1) CFLAGS += -Os -fno-strict-aliasing -ffunction-sections -fdata-sections # XXX: --gc-sections can be very tricky sometimes. If somehow the release # binary seems to be broken, check if removing this option fixes the issue. - LDFLAGS += -Wl,--strip-all,--gc-sections +# Applying the --strip-all option to the UEFI build may induce an "Invalid operation" error. +# The UEFI GenFw program strips symbols. + MULTIBOOT_LDFLAGS += -Wl,--strip-all,--gc-sections else CFLAGS += -O0 ifeq ($(findstring clang,$(CC)),clang) diff --git a/cpu/x86/Makefile.x86_quarkX1000 b/cpu/x86/Makefile.x86_quarkX1000 index 192fd302b..59601d8d5 100644 --- a/cpu/x86/Makefile.x86_quarkX1000 +++ b/cpu/x86/Makefile.x86_quarkX1000 @@ -7,3 +7,31 @@ CONTIKI_SOURCEFILES += bootstrap_quarkX1000.S rtc.c pit.c pic.c irq.c nmi.c pci. CFLAGS += -m32 -march=i586 -mtune=i586 LDFLAGS += -m32 -Xlinker -T -Xlinker $(CONTIKI)/cpu/x86/quarkX1000.ld ASFLAGS += --32 -march=i586 -mtune=i586 + +### UEFI support + +UEFI_DIR = $(CONTIKI_CPU)/uefi + +ifndef EN_UEFI +# Include a Makefile generated by the build_uefi.sh script, if available. +# If that script was not run, then UEFI support will not be built. +-include $(UEFI_DIR)/Makefile.uefi +endif + +ifeq ($(EN_UEFI),1) + EDK2_DIR = $(UEFI_DIR)/edk2 + + GEN_FW = $(EDK2_DIR)/BaseTools/Source/C/bin/GenFw + + CONTIKI_CPU_DIRS += uefi + CONTIKI_SOURCEFILES += bootstrap_uefi.c + CFLAGS += -I$(EDK2_DIR)/MdePkg/Include -I$(EDK2_DIR)/MdePkg/Include/Ia32 +else + $(info Note: UEFI support is disabled.) + ifndef EN_UEFI + $(info To enable UEFI support, run $(CONTIKI_CPU)/uefi/build_uefi.sh prior) + $(info to building Contiki.) + else + $(info LTO and UEFI support are mututally-exclusive.) + endif +endif diff --git a/cpu/x86/quarkX1000.ld b/cpu/x86/quarkX1000.ld index 8beb425cf..b50c47bb8 100644 --- a/cpu/x86/quarkX1000.ld +++ b/cpu/x86/quarkX1000.ld @@ -36,26 +36,39 @@ SECTIONS { /* OS-Dev Wiki says it is common for kernels to start at 1M. Addresses before that are used by BIOS/EFI, the bootloader and memory-mapped I/O. - */ - . = 1M; - .text ALIGN (4K) : + The UEFI GenFw program inserts a 0x240-byte offset between the image base and + the .text section. We add that same offset here to align the symbols in the + UEFI DLL with those in the final UEFI binary to make debugging easier. We also + apply 32-byte alignments to sections rather than more conventional 4K-byte + alignments to avoid symbols being shifted from the intermediate DLL to the + final UEFI image as would occur if the GenFw program shifted the .text section + from a higher, 4K-aligned offset to the 0x240-byte offset from the image base. + Such shifting may make debugging more difficult by preventing the DLL from + being a directly-useful source of symbol information. The debugging symbols + are not included in the final UEFI image. The GenFw program uses a minimum + section alignment of 32 bytes, so smaller alignment granularities may also + result in symbol perturbation. + */ + . = 1M + 0x240; + + .text ALIGN (32) : { KEEP(*(.multiboot)) *(.text*) } - .rodata ALIGN (4K) : + .rodata ALIGN (32) : { *(.rodata*) } - .data ALIGN (4K) : + .data ALIGN (32) : { *(.data*) } - .bss ALIGN (4K) : + .bss ALIGN (32) : { *(COMMON) *(.bss*) diff --git a/cpu/x86/uefi/bootstrap_uefi.c b/cpu/x86/uefi/bootstrap_uefi.c new file mode 100644 index 000000000..f6981eb96 --- /dev/null +++ b/cpu/x86/uefi/bootstrap_uefi.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#define MAX_MEM_DESC 128 + +void start(void); + +EFI_STATUS EFIAPI +uefi_start(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) +{ + EFI_MEMORY_DESCRIPTOR mem_map[MAX_MEM_DESC]; + UINTN mem_map_len = sizeof(mem_map); + UINTN mem_map_key; + UINTN mem_map_desc_sz; + UINT32 mem_map_rev; + + EFI_STATUS res; + + res = SystemTable->BootServices->GetMemoryMap(&mem_map_len, + mem_map, + &mem_map_key, + &mem_map_desc_sz, + &mem_map_rev); + if(res != EFI_SUCCESS) { + return EFI_ABORTED; + } + + res = SystemTable->BootServices->ExitBootServices(ImageHandle, mem_map_key); + if(res != EFI_SUCCESS) { + return EFI_ABORTED; + } + + start(); + + /* Should not be reachable: */ + return EFI_SUCCESS; +} diff --git a/cpu/x86/uefi/build_uefi.sh b/cpu/x86/uefi/build_uefi.sh new file mode 100755 index 000000000..5b7cba644 --- /dev/null +++ b/cpu/x86/uefi/build_uefi.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) + +# This script will always run on its own basepath, no matter where you call it from. +pushd ${SCRIPT_DIR} + +# Download the UEFI tool and library sources: +git clone --depth=1 https://github.com/tianocore/edk2 || exit +# This script only supports building the tools on 64-bit hosts: +export ARCH=X64 +# Build common sources required by the GenFw tool: +make -C edk2/BaseTools/Source/C/Common || exit +# Build the GenFw tool that is used to generate UEFI binaries: +make -C edk2/BaseTools/Source/C/GenFw || exit +# Create a makefile that indicates to the Contiki build system that UEFI support +# should be built: +echo "EN_UEFI = 1" > Makefile.uefi + +popd diff --git a/platform/galileo/Makefile.customrules-galileo b/platform/galileo/Makefile.customrules-galileo index eceebb9c4..d0527cf8f 100644 --- a/platform/galileo/Makefile.customrules-galileo +++ b/platform/galileo/Makefile.customrules-galileo @@ -1,15 +1,48 @@ GDB ?= gdb OPENOCD_SCRIPTS = $(CONTIKI)/platform/galileo/bsp/openocd-scripts -.PHONY: debug +.PHONY: debug $(CONTIKI_PROJECT) -debug: $(CONTIKI_PROJECT).$(TARGET) +# Multiboot ELF binary +MULTIBOOT_SFX = $(TARGET) +MULTIBOOT = $(CONTIKI_PROJECT).$(MULTIBOOT_SFX) +# UEFI binary +UEFI_DLL_SFX = $(TARGET).dll +UEFI_DLL = $(CONTIKI_PROJECT).$(UEFI_SFX) +UEFI_LDFLAGS += -Xlinker --emit-relocs -Xlinker --entry=uefi_start +UEFI_SFX = $(TARGET).efi +UEFI = $(CONTIKI_PROJECT).$(UEFI_SFX) + +# Suffixes for final (non-intermediate) files to be built +FINAL_SFXS = $(MULTIBOOT_SFX) +ifeq ($(EN_UEFI),1) +FINAL_SFXS += $(UEFI_SFX) +endif + +debug: $(MULTIBOOT) @openocd -s $(OPENOCD_SCRIPTS) -f debug.cfg &> $(shell pwd)/LOG_OPENOCD & @$(GDB) $< -ex "target remote :3333" CUSTOM_RULE_LINK=1 -%.$(TARGET): %.co $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) contiki-$(TARGET).a - $(TRACE_LD) - $(Q)$(LD) $(LDFLAGS) $(TARGET_STARTFILES) ${filter-out %.a,$^} \ - ${filter %.a,$^} $(TARGET_LIBFILES) -o $@ - @$(SIZE) $@ +define LINK_template = +%.$(1): %.co $$(PROJECT_OBJECTFILES) $$(PROJECT_LIBRARIES) contiki-$$(TARGET).a + $$(TRACE_LD) + $$(Q)$$(LD) $$(LDFLAGS) $(2) $$(TARGET_STARTFILES) $${filter-out %.a,$$^} \ + $${filter %.a,$$^} $$(TARGET_LIBFILES) -o $$@ +endef + +$(eval $(call LINK_template,$(MULTIBOOT_SFX),$(MULTIBOOT_LDFLAGS))) +$(eval $(call LINK_template,$(UEFI_DLL_SFX),$(UEFI_LDFLAGS))) + +%.$(UEFI_SFX): %.$(UEFI_DLL_SFX) + $(Q)$(GEN_FW) -o $@ -e UEFI_APPLICATION $^ + # The Intel Galileo firmware has been observed to not relocate the image + # if its base is set to the 1M boundary. This makes debugging easier, + # since the symbols in the intermediate DLL then correspond to the load + # addresses. + $(Q)$(GEN_FW) -o $@ --rebase 0x100000 $@ + +$(CONTIKI_PROJECT): $(addprefix $(CONTIKI_PROJECT).,$(FINAL_SFXS)) + @$(SIZE) $^ + +CLEAN += $(addprefix $(CONTIKI_PROJECT).,$(FINAL_SFXS)) diff --git a/platform/galileo/README.md b/platform/galileo/README.md index e58722634..e769cf068 100644 --- a/platform/galileo/README.md +++ b/platform/galileo/README.md @@ -71,6 +71,12 @@ You can also build a "Release" image by setting the BUILD_RELEASE variable to $ cd examples/hello-world/ && make TARGET=galileo BUILD_RELEASE=1 ``` +To also generate an '.galileo.efi' file which is a UEFI [4] image, +you can run the following command prior to building applications: +``` +$ cpu/x86/uefi/build_uefi.sh +``` + Running ------- @@ -90,6 +96,8 @@ detailed instructions. Mount the sdcard in directory /mnt/sdcard. +#### Approach for Multiboot-compliant ELF Image + Copy Contiki binary image to sdcard ``` $ cp examples/hello-world/hello-world.galileo /mnt/sdcard @@ -100,6 +108,13 @@ Copy grub binary to sdcard $ cp platform/galileo/bsp/grub/bin/grub.efi /mnt/sdcard ``` +#### Approach for UEFI Image + +Copy Contiki binary image to sdcard +``` +$ cp examples/hello-world/hello-world.galileo.efi /mnt/sdcard +``` + ### Connect to the console output Connect the serial cable to your computer as shown in [2]. @@ -117,8 +132,11 @@ Press [Enter] to directly boot. Press [F7] to show boot menu options. ``` -Press and select the option "UEFI Internal Shell" within the menu. Once -you have a shell, run the following commands to run grub application: +Press and select the option "UEFI Internal Shell" within the menu. + +#### Boot Multiboot-compliant ELF Image + +Once you have a shell, run the following commands to run grub application: ``` $ fs0: $ grub.efi @@ -131,6 +149,16 @@ $ multiboot /hello-world.galileo $ boot ``` +#### Boot UEFI Image + +Once you have a shell, run the following commands to boot Contiki image: +``` +$ fs0: +$ hello-world.galileo.efi +``` + +### Verify that Contiki is Running + This should boot the Contiki image, resulting in the following messages being sent to the serial console: ``` @@ -176,3 +204,5 @@ References [2] http://www.intel.com/support/galileo/sb/CS-035124.htm [3] https://www.gnu.org/software/grub/manual/multiboot/multiboot.html + +[4] http://www.uefi.org/ diff --git a/platform/galileo/bsp/libc/patches/stdio_strengthen_syms.patch b/platform/galileo/bsp/libc/patches/stdio_strengthen_syms.patch new file mode 100644 index 000000000..97c7f4f3a --- /dev/null +++ b/platform/galileo/bsp/libc/patches/stdio_strengthen_syms.patch @@ -0,0 +1,19 @@ +--- newlib/libc/stdio/nano-vfprintf_local.h 2014-07-04 10:21:43.000000000 -0700 ++++ newlib/libc/stdio/nano-vfprintf_local.h 2015-07-17 12:51:12.974269921 -0700 +@@ -230,5 +230,5 @@ _printf_float (struct _reent *data, + FILE *fp, + int (*pfunc)(struct _reent *, FILE *, + _CONST char *, size_t len), +- va_list *ap) _ATTRIBUTE((__weak__)); ++ va_list *ap); + #endif +--- newlib/libc/stdio/nano-vfscanf_local.h 2014-07-04 10:21:44.000000000 -0700 ++++ newlib/libc/stdio/nano-vfscanf_local.h 2015-07-17 12:51:33.967362409 -0700 +@@ -173,6 +173,6 @@ _scanf_i (struct _reent *rptr, + extern int + _scanf_float (struct _reent *rptr, + struct _scan_data_t *pdata, +- FILE *fp, va_list *ap) _ATTRIBUTE((__weak__)); ++ FILE *fp, va_list *ap); + + #endif From e297177a69e24b3b28fcd208c3524a4fc9bcb468 Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Fri, 23 Oct 2015 09:34:17 -0700 Subject: [PATCH 85/92] x86: Streamline MMIO accesses in GPIO and I2C drivers This patch refactors the MMIO routines in the GPIO and I2C drivers to eliminate the base_addr parameter that specifies the MMIO base address. Instead, just the MMIO routines themselves retrieve the base address from the driver structure. --- cpu/x86/drivers/quarkX1000/gpio.c | 56 ++++++------ cpu/x86/drivers/quarkX1000/i2c.c | 138 +++++++++++++++--------------- 2 files changed, 100 insertions(+), 94 deletions(-) diff --git a/cpu/x86/drivers/quarkX1000/gpio.c b/cpu/x86/drivers/quarkX1000/gpio.c index 45bcae711..92438b456 100644 --- a/cpu/x86/drivers/quarkX1000/gpio.c +++ b/cpu/x86/drivers/quarkX1000/gpio.c @@ -60,29 +60,31 @@ struct gpio_internal_data { static struct gpio_internal_data data; static inline uint32_t -read(uint32_t base_addr, uint32_t offset) +read(uint32_t offset) { - return *(uint32_t*)(base_addr + offset); + uint32_t res; + PCI_MMIO_READL(data.pci, res, offset); + return res; } static inline void -write(uint32_t base_addr, uint32_t offset, uint32_t val) +write(uint32_t offset, uint32_t val) { - *(uint32_t*)(base_addr + offset) = val; + PCI_MMIO_WRITEL(data.pci, offset, val); } /* value must be 0x0 or 0x1 */ static void -set_bit(uint32_t base_addr, uint32_t offset, uint32_t bit, uint32_t value) +set_bit(uint32_t offset, uint32_t bit, uint32_t value) { uint32_t reg; - reg = read(base_addr, offset); + reg = read(offset); reg &= ~BIT(bit); reg |= value << bit; - write(base_addr, offset, reg); + write(offset, reg); } static void @@ -90,37 +92,37 @@ gpio_isr(void) { uint32_t int_status; - int_status = read(data.pci.mmio, INTSTATUS); + int_status = read(INTSTATUS); if (data.callback) data.callback(int_status); - write(data.pci.mmio, PORTA_EOI, -1); + write(PORTA_EOI, -1); } static void gpio_interrupt_config(uint8_t pin, int flags) { /* set as input */ - set_bit(data.pci.mmio, SWPORTA_DDR, pin, 0); + set_bit(SWPORTA_DDR, pin, 0); /* set interrupt enabled */ - set_bit(data.pci.mmio, INTEN, pin, 1); + set_bit(INTEN, pin, 1); /* unmask interrupt */ - set_bit(data.pci.mmio, INTMASK, pin, 0); + set_bit(INTMASK, pin, 0); /* set active high/low */ - set_bit(data.pci.mmio, INT_POLARITY, pin, !!(flags & QUARKX1000_GPIO_ACTIVE_HIGH)); + set_bit(INT_POLARITY, pin, !!(flags & QUARKX1000_GPIO_ACTIVE_HIGH)); /* set level/edge */ - set_bit(data.pci.mmio, INTTYPE_LEVEL, pin, !!(flags & QUARKX1000_GPIO_EDGE)); + set_bit(INTTYPE_LEVEL, pin, !!(flags & QUARKX1000_GPIO_EDGE)); /* set debounce */ - set_bit(data.pci.mmio, DEBOUNCE, pin, !!(flags & QUARKX1000_GPIO_DEBOUNCE)); + set_bit(DEBOUNCE, pin, !!(flags & QUARKX1000_GPIO_DEBOUNCE)); /* set clock synchronous */ - set_bit(data.pci.mmio, LS_SYNC, 0, !!(flags & QUARKX1000_GPIO_CLOCK_SYNC)); + set_bit(LS_SYNC, 0, !!(flags & QUARKX1000_GPIO_CLOCK_SYNC)); } int @@ -135,10 +137,10 @@ quarkX1000_gpio_config(uint8_t pin, int flags) gpio_interrupt_config(pin, flags); } else { /* set direction */ - set_bit(data.pci.mmio, SWPORTA_DDR, pin, !!(flags & QUARKX1000_GPIO_OUT)); + set_bit(SWPORTA_DDR, pin, !!(flags & QUARKX1000_GPIO_OUT)); /* set interrupt disabled */ - set_bit(data.pci.mmio, INTEN, pin, 0); + set_bit(INTEN, pin, 0); } return 0; @@ -161,7 +163,7 @@ quarkX1000_gpio_config_port(int flags) int quarkX1000_gpio_read(uint8_t pin, uint8_t *value) { - uint32_t value32 = read(data.pci.mmio, EXT_PORTA); + uint32_t value32 = read(EXT_PORTA); *value = !!(value32 & BIT(pin)); return 0; @@ -170,14 +172,14 @@ quarkX1000_gpio_read(uint8_t pin, uint8_t *value) int quarkX1000_gpio_write(uint8_t pin, uint8_t value) { - set_bit(data.pci.mmio, SWPORTA_DR, pin, !!value); + set_bit(SWPORTA_DR, pin, !!value); return 0; } int quarkX1000_gpio_read_port(uint8_t *value) { - uint32_t value32 = read(data.pci.mmio, EXT_PORTA); + uint32_t value32 = read(EXT_PORTA); *value = value32 & ~0xFFFFFF00; return 0; @@ -186,7 +188,7 @@ quarkX1000_gpio_read_port(uint8_t *value) int quarkX1000_gpio_write_port(uint8_t value) { - write(data.pci.mmio, SWPORTA_DR, value); + write(SWPORTA_DR, value); return 0; } @@ -200,13 +202,13 @@ quarkX1000_gpio_set_callback(quarkX1000_gpio_callback callback) void quarkX1000_gpio_clock_enable(void) { - set_bit(data.pci.mmio, LS_SYNC, 0, 1); + set_bit(LS_SYNC, 0, 1); } void quarkX1000_gpio_clock_disable(void) { - set_bit(data.pci.mmio, LS_SYNC, 0, 0); + set_bit(LS_SYNC, 0, 0); } static void @@ -244,9 +246,9 @@ quarkX1000_gpio_init(void) quarkX1000_gpio_clock_enable(); /* clear registers */ - write(data.pci.mmio, INTEN, 0); - write(data.pci.mmio, INTMASK, 0); - write(data.pci.mmio, PORTA_EOI, 0); + write(INTEN, 0); + write(INTMASK, 0); + write(PORTA_EOI, 0); pic_unmask_irq(GPIO_IRQ); diff --git a/cpu/x86/drivers/quarkX1000/i2c.c b/cpu/x86/drivers/quarkX1000/i2c.c index bf7b6110a..b781bcc35 100644 --- a/cpu/x86/drivers/quarkX1000/i2c.c +++ b/cpu/x86/drivers/quarkX1000/i2c.c @@ -75,21 +75,23 @@ struct i2c_internal_data { static struct i2c_internal_data device; static uint32_t -read(uint32_t base_addr, uint32_t offset) +read(uint32_t offset) { - return *(uint32_t*)(base_addr + offset); + uint32_t res; + PCI_MMIO_READL(device.pci, res, offset); + return res; } static void -write(uint32_t base_addr, uint32_t offset, uint32_t val) +write(uint32_t offset, uint32_t val) { - *(uint32_t*)(base_addr + offset) = val; + PCI_MMIO_WRITEL(device.pci, offset, val); } static uint32_t -get_value(uint32_t base_addr, uint32_t offset, uint32_t mask, uint32_t shift) +get_value(uint32_t offset, uint32_t mask, uint32_t shift) { - uint32_t register_value = *(uint32_t*)(base_addr + offset); + uint32_t register_value = read(offset); register_value &= ~(0xFFFFFFFF - mask); @@ -97,12 +99,14 @@ get_value(uint32_t base_addr, uint32_t offset, uint32_t mask, uint32_t shift) } static void -set_value(uint32_t base_addr, uint32_t offset, uint32_t mask, uint32_t shift, uint32_t value) +set_value(uint32_t offset, uint32_t mask, uint32_t shift, uint32_t value) { - volatile uint32_t *register_value = (volatile uint32_t*)(base_addr + offset); + uint32_t register_value = read(offset); - *register_value &= ~mask; - *register_value |= value << shift; + register_value &= ~mask; + register_value |= value << shift; + + write(offset, register_value); } static void @@ -113,14 +117,14 @@ i2c_data_read(void) if (device.rx_len == 0) return; - rx_cnt = get_value(device.pci.mmio, QUARKX1000_IC_RXFLR, + rx_cnt = get_value(QUARKX1000_IC_RXFLR, QUARKX1000_IC_RXFLR_MASK, QUARKX1000_IC_RXFLR_SHIFT); if (rx_cnt > device.rx_len) rx_cnt = device.rx_len; for (i = 0; i < rx_cnt; i++) { - device.rx_buffer[i] = get_value(device.pci.mmio, QUARKX1000_IC_DATA_CMD, + device.rx_buffer[i] = get_value(QUARKX1000_IC_DATA_CMD, QUARKX1000_IC_DATA_CMD_DAT_MASK, QUARKX1000_IC_DATA_CMD_DAT_SHIFT); } @@ -137,7 +141,7 @@ i2c_data_send(void) if (device.rx_tx_len == 0) return; - tx_cnt = I2C_FIFO_DEPTH - get_value(device.pci.mmio, QUARKX1000_IC_TXFLR, + tx_cnt = I2C_FIFO_DEPTH - get_value(QUARKX1000_IC_TXFLR, QUARKX1000_IC_TXFLR_MASK, QUARKX1000_IC_TXFLR_SHIFT); if (tx_cnt > device.rx_tx_len) @@ -158,7 +162,7 @@ i2c_data_send(void) data |= QUARKX1000_IC_DATA_CMD_STOP_MASK; } - write(device.pci.mmio, QUARKX1000_IC_DATA_CMD, data); + write(QUARKX1000_IC_DATA_CMD, data); device.rx_tx_len -= 1; } @@ -168,11 +172,11 @@ i2c_data_send(void) static void i2c_isr(void) { - if (read(device.pci.mmio, QUARKX1000_IC_INTR_STAT) & QUARKX1000_IC_INTR_STAT_STOP_DET_MASK) { + if (read(QUARKX1000_IC_INTR_STAT) & QUARKX1000_IC_INTR_STAT_STOP_DET_MASK) { i2c_data_read(); - write(device.pci.mmio, QUARKX1000_IC_INTR_MASK, 0); - read(device.pci.mmio, QUARKX1000_IC_CLR_INTR); + write(QUARKX1000_IC_INTR_MASK, 0); + read(QUARKX1000_IC_CLR_INTR); if (device.direction == I2C_DIRECTION_WRITE) { if (device.config.cb_tx) @@ -183,24 +187,24 @@ i2c_isr(void) } } - if (read(device.pci.mmio, QUARKX1000_IC_INTR_STAT) & QUARKX1000_IC_INTR_STAT_TX_EMPTY_MASK) { + if (read(QUARKX1000_IC_INTR_STAT) & QUARKX1000_IC_INTR_STAT_TX_EMPTY_MASK) { i2c_data_send(); if (device.rx_tx_len <= 0) { - set_value(device.pci.mmio, QUARKX1000_IC_INTR_MASK, + set_value(QUARKX1000_IC_INTR_MASK, QUARKX1000_IC_INTR_STAT_TX_EMPTY_MASK, QUARKX1000_IC_INTR_STAT_TX_EMPTY_SHIFT, 0); - set_value(device.pci.mmio, QUARKX1000_IC_INTR_MASK, + set_value(QUARKX1000_IC_INTR_MASK, QUARKX1000_IC_INTR_STAT_STOP_DET_MASK, QUARKX1000_IC_INTR_STAT_STOP_DET_SHIFT, 1); } } - if (read(device.pci.mmio, QUARKX1000_IC_INTR_STAT) & QUARKX1000_IC_INTR_STAT_RX_FULL_MASK) + if (read(QUARKX1000_IC_INTR_STAT) & QUARKX1000_IC_INTR_STAT_RX_FULL_MASK) i2c_data_read(); - if (read(device.pci.mmio, QUARKX1000_IC_INTR_STAT) & (QUARKX1000_IC_INTR_STAT_TX_ABRT_MASK + if (read(QUARKX1000_IC_INTR_STAT) & (QUARKX1000_IC_INTR_STAT_TX_ABRT_MASK | QUARKX1000_IC_INTR_STAT_TX_OVER_MASK | QUARKX1000_IC_INTR_STAT_RX_OVER_MASK | QUARKX1000_IC_INTR_STAT_RX_UNDER_MASK)) { - write(device.pci.mmio, QUARKX1000_IC_INTR_MASK, 0); - read(device.pci.mmio, QUARKX1000_IC_CLR_INTR); + write(QUARKX1000_IC_INTR_MASK, 0); + read(QUARKX1000_IC_CLR_INTR); if (device.config.cb_err) device.config.cb_err(); @@ -227,7 +231,7 @@ quarkX1000_i2c_configure(struct quarkX1000_i2c_config *config) hcnt = I2C_FS_HCNT; } - ic_fs_spklen = get_value(device.pci.mmio, QUARKX1000_IC_FS_SPKLEN, + ic_fs_spklen = get_value(QUARKX1000_IC_FS_SPKLEN, QUARKX1000_IC_FS_SPKLEN_MASK, QUARKX1000_IC_FS_SPKLEN_SHIFT); /* We adjust the Low Count and High Count based on the Spike Suppression Limit */ @@ -235,7 +239,7 @@ quarkX1000_i2c_configure(struct quarkX1000_i2c_config *config) device.hcnt = (hcnt < (ic_fs_spklen + I2C_FS_SPKLEN_HCNT_OFFSET)) ? ic_fs_spklen + I2C_FS_SPKLEN_HCNT_OFFSET : hcnt; /* Clear interrupts. */ - read(device.pci.mmio, QUARKX1000_IC_CLR_INTR); + read(QUARKX1000_IC_CLR_INTR); return 0; } @@ -244,38 +248,38 @@ static int i2c_setup(void) { /* Clear all values */ - write(device.pci.mmio, QUARKX1000_IC_CON, 0); + write(QUARKX1000_IC_CON, 0); /* Clear interrupts */ - read(device.pci.mmio, QUARKX1000_IC_CLR_INTR); + read(QUARKX1000_IC_CLR_INTR); /* Quark X1000 SoC I2C only supports master mode. */ - set_value(device.pci.mmio, QUARKX1000_IC_CON, + set_value(QUARKX1000_IC_CON, QUARKX1000_IC_CON_MASTER_MODE_MASK, QUARKX1000_IC_CON_MASTER_MODE_SHIFT, 1); /* Set restart enable */ - set_value(device.pci.mmio, QUARKX1000_IC_CON, + set_value(QUARKX1000_IC_CON, QUARKX1000_IC_CON_RESTART_EN_MASK, QUARKX1000_IC_CON_RESTART_EN_SHIFT, 1); /* Set addressing mode */ if (device.config.addressing_mode == QUARKX1000_I2C_ADDR_MODE_10BIT) { - set_value(device.pci.mmio, QUARKX1000_IC_CON, + set_value(QUARKX1000_IC_CON, QUARKX1000_IC_CON_10BITADDR_MASTER_MASK, QUARKX1000_IC_CON_10BITADDR_MASTER_SHIFT, 1); } if (device.config.speed == QUARKX1000_I2C_SPEED_STANDARD) { - set_value(device.pci.mmio, QUARKX1000_IC_SS_SCL_LCNT, + set_value(QUARKX1000_IC_SS_SCL_LCNT, QUARKX1000_IC_SS_SCL_LCNT_MASK, QUARKX1000_IC_SS_SCL_LCNT_SHIFT, device.lcnt); - set_value(device.pci.mmio, QUARKX1000_IC_SS_SCL_HCNT, + set_value(QUARKX1000_IC_SS_SCL_HCNT, QUARKX1000_IC_SS_SCL_HCNT_MASK, QUARKX1000_IC_SS_SCL_HCNT_SHIFT, device.hcnt); - set_value(device.pci.mmio, QUARKX1000_IC_CON, + set_value(QUARKX1000_IC_CON, QUARKX1000_IC_CON_SPEED_MASK, QUARKX1000_IC_CON_SPEED_SHIFT, 0x1); } else { - set_value(device.pci.mmio, QUARKX1000_IC_FS_SCL_LCNT, + set_value(QUARKX1000_IC_FS_SCL_LCNT, QUARKX1000_IC_FS_SCL_LCNT_MASK, QUARKX1000_IC_FS_SCL_LCNT_SHIFT, device.lcnt); - set_value(device.pci.mmio, QUARKX1000_IC_FS_SCL_HCNT, + set_value(QUARKX1000_IC_FS_SCL_HCNT, QUARKX1000_IC_FS_SCL_HCNT_MASK, QUARKX1000_IC_FS_SCL_HCNT_SHIFT, device.hcnt); - set_value(device.pci.mmio, QUARKX1000_IC_CON, + set_value(QUARKX1000_IC_CON, QUARKX1000_IC_CON_SPEED_MASK, QUARKX1000_IC_CON_SPEED_SHIFT, 0x2); } @@ -293,19 +297,19 @@ i2c_operation_setup(uint8_t *write_buf, uint8_t write_len, device.rx_tx_len = device.rx_len + device.tx_len; /* Disable controller */ - set_value(device.pci.mmio, QUARKX1000_IC_ENABLE, + set_value(QUARKX1000_IC_ENABLE, QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 0); i2c_setup(); /* Disable interrupts */ - write(device.pci.mmio, QUARKX1000_IC_INTR_MASK, 0); + write(QUARKX1000_IC_INTR_MASK, 0); /* Clear interrupts */ - read(device.pci.mmio, QUARKX1000_IC_CLR_INTR); + read(QUARKX1000_IC_CLR_INTR); /* Set address of target slave */ - set_value(device.pci.mmio, QUARKX1000_IC_TAR, + set_value(QUARKX1000_IC_TAR, QUARKX1000_IC_TAR_MASK, QUARKX1000_IC_TAR_SHIFT, addr); } @@ -314,29 +318,29 @@ static int i2c_operation(uint8_t *write_buf, uint8_t write_len, uint8_t *read_buf, uint8_t read_len, uint16_t addr) { - if (read(device.pci.mmio, QUARKX1000_IC_STATUS) & QUARKX1000_IC_STATUS_ACTIVITY_MASK) + if (read(QUARKX1000_IC_STATUS) & QUARKX1000_IC_STATUS_ACTIVITY_MASK) return -1; i2c_operation_setup(write_buf, write_len, read_buf, read_len, addr); /* Enable master TX and RX interrupts */ - set_value(device.pci.mmio, QUARKX1000_IC_INTR_MASK, + set_value(QUARKX1000_IC_INTR_MASK, QUARKX1000_IC_INTR_STAT_TX_OVER_MASK, QUARKX1000_IC_INTR_STAT_TX_OVER_SHIFT, 1); - set_value(device.pci.mmio, QUARKX1000_IC_INTR_MASK, + set_value(QUARKX1000_IC_INTR_MASK, QUARKX1000_IC_INTR_STAT_TX_EMPTY_MASK, QUARKX1000_IC_INTR_STAT_TX_EMPTY_SHIFT, 1); - set_value(device.pci.mmio, QUARKX1000_IC_INTR_MASK, + set_value(QUARKX1000_IC_INTR_MASK, QUARKX1000_IC_INTR_STAT_TX_ABRT_MASK, QUARKX1000_IC_INTR_STAT_TX_ABRT_SHIFT, 1); - set_value(device.pci.mmio, QUARKX1000_IC_INTR_MASK, + set_value(QUARKX1000_IC_INTR_MASK, QUARKX1000_IC_INTR_STAT_RX_UNDER_MASK, QUARKX1000_IC_INTR_STAT_RX_UNDER_SHIFT, 1); - set_value(device.pci.mmio, QUARKX1000_IC_INTR_MASK, + set_value(QUARKX1000_IC_INTR_MASK, QUARKX1000_IC_INTR_STAT_RX_OVER_MASK, QUARKX1000_IC_INTR_STAT_RX_OVER_SHIFT, 1); - set_value(device.pci.mmio, QUARKX1000_IC_INTR_MASK, + set_value(QUARKX1000_IC_INTR_MASK, QUARKX1000_IC_INTR_STAT_RX_FULL_MASK, QUARKX1000_IC_INTR_STAT_RX_FULL_SHIFT, 1); - set_value(device.pci.mmio, QUARKX1000_IC_INTR_MASK, + set_value(QUARKX1000_IC_INTR_MASK, QUARKX1000_IC_INTR_STAT_STOP_DET_MASK, QUARKX1000_IC_INTR_STAT_STOP_DET_SHIFT, 1); /* Enable controller */ - set_value(device.pci.mmio, QUARKX1000_IC_ENABLE, + set_value(QUARKX1000_IC_ENABLE, QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 1); return 0; @@ -364,33 +368,33 @@ i2c_polling_operation(uint8_t *write_buf, uint8_t write_len, { uint32_t start_time, intr_mask_stat; - if (!(read(device.pci.mmio, QUARKX1000_IC_CON) & QUARKX1000_IC_CON_MASTER_MODE_MASK)) + if (!(read(QUARKX1000_IC_CON) & QUARKX1000_IC_CON_MASTER_MODE_MASK)) return -1; /* Wait i2c idle */ start_time = clock_seconds(); - while (read(device.pci.mmio, QUARKX1000_IC_STATUS) & QUARKX1000_IC_STATUS_ACTIVITY_MASK) { + while (read(QUARKX1000_IC_STATUS) & QUARKX1000_IC_STATUS_ACTIVITY_MASK) { if ((clock_seconds() - start_time) > I2C_POLLING_TIMEOUT) { return -1; } } /* Get interrupt mask to restore in the end of polling operation */ - intr_mask_stat = read(device.pci.mmio, QUARKX1000_IC_INTR_MASK); + intr_mask_stat = read(QUARKX1000_IC_INTR_MASK); i2c_operation_setup(write_buf, write_len, read_buf, read_len, addr); /* Enable controller */ - set_value(device.pci.mmio, QUARKX1000_IC_ENABLE, + set_value(QUARKX1000_IC_ENABLE, QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 1); /* Transmit */ if (device.tx_len != 0) { while (device.tx_len > 0) { start_time = clock_seconds(); - while (!(read(device.pci.mmio, QUARKX1000_IC_STATUS) & QUARKX1000_IC_STATUS_TFNF_MASK)) { + while (!(read(QUARKX1000_IC_STATUS) & QUARKX1000_IC_STATUS_TFNF_MASK)) { if ((clock_seconds() - start_time) > I2C_POLLING_TIMEOUT) { - set_value(device.pci.mmio, QUARKX1000_IC_ENABLE, + set_value(QUARKX1000_IC_ENABLE, QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 0); return -1; } @@ -399,9 +403,9 @@ i2c_polling_operation(uint8_t *write_buf, uint8_t write_len, } start_time = clock_seconds(); - while (!(read(device.pci.mmio, QUARKX1000_IC_STATUS) & QUARKX1000_IC_STATUS_TFE_MASK)) { + while (!(read(QUARKX1000_IC_STATUS) & QUARKX1000_IC_STATUS_TFE_MASK)) { if ((clock_seconds() - start_time) > I2C_POLLING_TIMEOUT) { - set_value(device.pci.mmio, QUARKX1000_IC_ENABLE, + set_value(QUARKX1000_IC_ENABLE, QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 0); return -1; } @@ -414,9 +418,9 @@ i2c_polling_operation(uint8_t *write_buf, uint8_t write_len, if (device.rx_len != 0) { while (device.rx_len > 0) { start_time = clock_seconds(); - while (!(read(device.pci.mmio, QUARKX1000_IC_STATUS) & QUARKX1000_IC_STATUS_RFNE_MASK)) { + while (!(read(QUARKX1000_IC_STATUS) & QUARKX1000_IC_STATUS_RFNE_MASK)) { if ((clock_seconds() - start_time) > I2C_POLLING_TIMEOUT) { - set_value(device.pci.mmio, QUARKX1000_IC_ENABLE, + set_value(QUARKX1000_IC_ENABLE, QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 0); return -1; } @@ -427,31 +431,31 @@ i2c_polling_operation(uint8_t *write_buf, uint8_t write_len, /* Stop Det */ start_time = clock_seconds(); - while (!(read(device.pci.mmio, QUARKX1000_IC_RAW_INTR_STAT) & QUARKX1000_IC_INTR_STAT_STOP_DET_MASK)) { + while (!(read(QUARKX1000_IC_RAW_INTR_STAT) & QUARKX1000_IC_INTR_STAT_STOP_DET_MASK)) { if ((clock_seconds() - start_time) > I2C_POLLING_TIMEOUT) { - set_value(device.pci.mmio, QUARKX1000_IC_ENABLE, + set_value(QUARKX1000_IC_ENABLE, QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 0); return -1; } } - read(device.pci.mmio, QUARKX1000_IC_CLR_STOP_DET); + read(QUARKX1000_IC_CLR_STOP_DET); /* Wait i2c idle */ start_time = clock_seconds(); - while (read(device.pci.mmio, QUARKX1000_IC_STATUS) & QUARKX1000_IC_STATUS_ACTIVITY_MASK) { + while (read(QUARKX1000_IC_STATUS) & QUARKX1000_IC_STATUS_ACTIVITY_MASK) { if ((clock_seconds() - start_time) > I2C_POLLING_TIMEOUT) { - set_value(device.pci.mmio, QUARKX1000_IC_ENABLE, + set_value(QUARKX1000_IC_ENABLE, QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 0); return -1; } } /* Disable controller */ - set_value(device.pci.mmio, QUARKX1000_IC_ENABLE, + set_value(QUARKX1000_IC_ENABLE, QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 0); /* Restore interrupt mask */ - write(device.pci.mmio, QUARKX1000_IC_INTR_MASK, intr_mask_stat); + write(QUARKX1000_IC_INTR_MASK, intr_mask_stat); return 0; } From c75e9466f6f1eacf45b570b3f9c4974f71af2740 Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Wed, 11 Nov 2015 09:19:17 -0800 Subject: [PATCH 86/92] galileo: Fix bug in newlib build script This patch fixes a bug in the newlib build script that causes it to not delete an old source directory as intended prior to rebuilding the library. --- platform/galileo/bsp/libc/build_newlib.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/galileo/bsp/libc/build_newlib.sh b/platform/galileo/bsp/libc/build_newlib.sh index 89d3b870c..cef167e14 100755 --- a/platform/galileo/bsp/libc/build_newlib.sh +++ b/platform/galileo/bsp/libc/build_newlib.sh @@ -31,8 +31,8 @@ prepare() { fi # Clean up the previous install dir, if any. - if [[ -d ./${VERSION} ]]; then - rm -rf ./${VERSION} + if [[ -d ./${TARGET} ]]; then + rm -rf ./${TARGET} fi tar xf ${TARBALL} From 0e99ebbded742ba725383b20dda7b7d9b38d4509 Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Wed, 18 Nov 2015 09:19:04 -0800 Subject: [PATCH 87/92] x86: Add support for 32-bit build hosts in build_uefi.sh This patch adds support for building the UEFI EDK2 tools on 32-bit hosts. It also revises the script to support rebuilding the tools when the script is re-invoked after the EDK2 repository has previously been downloaded. --- cpu/x86/uefi/build_uefi.sh | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/cpu/x86/uefi/build_uefi.sh b/cpu/x86/uefi/build_uefi.sh index 5b7cba644..c49718f93 100755 --- a/cpu/x86/uefi/build_uefi.sh +++ b/cpu/x86/uefi/build_uefi.sh @@ -5,10 +5,17 @@ SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) # This script will always run on its own basepath, no matter where you call it from. pushd ${SCRIPT_DIR} +if [ "$(uname -m)" = "x86_64" ]; then + export ARCH=X64 +fi + # Download the UEFI tool and library sources: -git clone --depth=1 https://github.com/tianocore/edk2 || exit -# This script only supports building the tools on 64-bit hosts: -export ARCH=X64 +if [ -e edk2 ]; then + make -C edk2/BaseTools/Source/C/Common clean + make -C edk2/BaseTools/Source/C/GenFw clean +else + git clone --depth=1 https://github.com/tianocore/edk2 || exit +fi # Build common sources required by the GenFw tool: make -C edk2/BaseTools/Source/C/Common || exit # Build the GenFw tool that is used to generate UEFI binaries: From 09d168da0427977504dd18e7ddd3bb7bda2670f3 Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Fri, 20 Nov 2015 15:07:51 -0800 Subject: [PATCH 88/92] galileo: Add support for old versions of GNU Make This patch revises a Makefile to avoid using a feature that is incompatible with GNU Make v.3.81. --- platform/galileo/Makefile.customrules-galileo | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/platform/galileo/Makefile.customrules-galileo b/platform/galileo/Makefile.customrules-galileo index d0527cf8f..cb5bc26a9 100644 --- a/platform/galileo/Makefile.customrules-galileo +++ b/platform/galileo/Makefile.customrules-galileo @@ -24,15 +24,16 @@ debug: $(MULTIBOOT) @$(GDB) $< -ex "target remote :3333" CUSTOM_RULE_LINK=1 -define LINK_template = -%.$(1): %.co $$(PROJECT_OBJECTFILES) $$(PROJECT_LIBRARIES) contiki-$$(TARGET).a - $$(TRACE_LD) - $$(Q)$$(LD) $$(LDFLAGS) $(2) $$(TARGET_STARTFILES) $${filter-out %.a,$$^} \ - $${filter %.a,$$^} $$(TARGET_LIBFILES) -o $$@ -endef -$(eval $(call LINK_template,$(MULTIBOOT_SFX),$(MULTIBOOT_LDFLAGS))) -$(eval $(call LINK_template,$(UEFI_DLL_SFX),$(UEFI_LDFLAGS))) +%.$(MULTIBOOT_SFX): %.co $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) contiki-$(TARGET).a + $(TRACE_LD) + $(Q)$(LD) $(LDFLAGS) $(MULTIBOOT_LDFLAGS) $(TARGET_STARTFILES) ${filter-out %.a,$^} \ + ${filter %.a,$^} $(TARGET_LIBFILES) -o $@ + +%.$(UEFI_DLL_SFX): %.co $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) contiki-$(TARGET).a + $(TRACE_LD) + $(Q)$(LD) $(LDFLAGS) $(UEFI_LDFLAGS) $(TARGET_STARTFILES) ${filter-out %.a,$^} \ + ${filter %.a,$^} $(TARGET_LIBFILES) -o $@ %.$(UEFI_SFX): %.$(UEFI_DLL_SFX) $(Q)$(GEN_FW) -o $@ -e UEFI_APPLICATION $^ From 52d75dce0d9dfe2b78af76c2f358e6f467722b15 Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Fri, 11 Dec 2015 11:14:36 -0800 Subject: [PATCH 89/92] x86: Remove spurious UEFI-related info message This patch removes a spurious info message in a UEFI-related portion of a Makefile. --- cpu/x86/Makefile.x86_quarkX1000 | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/cpu/x86/Makefile.x86_quarkX1000 b/cpu/x86/Makefile.x86_quarkX1000 index 59601d8d5..00f352102 100644 --- a/cpu/x86/Makefile.x86_quarkX1000 +++ b/cpu/x86/Makefile.x86_quarkX1000 @@ -28,10 +28,6 @@ ifeq ($(EN_UEFI),1) CFLAGS += -I$(EDK2_DIR)/MdePkg/Include -I$(EDK2_DIR)/MdePkg/Include/Ia32 else $(info Note: UEFI support is disabled.) - ifndef EN_UEFI - $(info To enable UEFI support, run $(CONTIKI_CPU)/uefi/build_uefi.sh prior) - $(info to building Contiki.) - else - $(info LTO and UEFI support are mututally-exclusive.) - endif + $(info To enable UEFI support, run $(CONTIKI_CPU)/uefi/build_uefi.sh prior) + $(info to building Contiki.) endif From e14761c26b79a11ee8bf563654e8ae2459da677b Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Fri, 11 Dec 2015 11:15:37 -0800 Subject: [PATCH 90/92] galileo: Document prerequisites for building on Ubuntu Linux This patch documents the prerequisites for building on Ubuntu Linux in the Galileo platform README. --- platform/galileo/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/platform/galileo/README.md b/platform/galileo/README.md index e769cf068..c38589de7 100644 --- a/platform/galileo/README.md +++ b/platform/galileo/README.md @@ -42,6 +42,10 @@ Standard APIs: Building -------- +Prerequisites on all Ubuntu Linux systems include texinfo and uuid-dev. +Additional prerequisites on 64-bit Ubuntu Linux systems include +gcc-multilib and g++-multilib. + To build applications for this platform you should first build newlib (in case it wasn't already built). To build newlib you can run the following command: From 13be942d408975d0c5665230677019e3e77a472b Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Sat, 19 Dec 2015 17:28:27 -0800 Subject: [PATCH 91/92] galileo: Fix code style violations --- platform/galileo/drivers/galileo-pinmux.c | 81 ++++++++++------- platform/galileo/drivers/gpio-pcal9535a.c | 103 ++++++++++++---------- platform/galileo/drivers/pwm-pca9685.c | 22 ++--- 3 files changed, 117 insertions(+), 89 deletions(-) diff --git a/platform/galileo/drivers/galileo-pinmux.c b/platform/galileo/drivers/galileo-pinmux.c index 9b91c367a..c66036ea2 100644 --- a/platform/galileo/drivers/galileo-pinmux.c +++ b/platform/galileo/drivers/galileo-pinmux.c @@ -535,70 +535,83 @@ galileo_pinmux_set_pin(uint8_t pin, GALILEO_PINMUX_FUNC func) struct mux_path *mux_path; uint8_t index, i; - if (pin > PINMUX_NUM_PINS) + if(pin > PINMUX_NUM_PINS) { return -1; + } index = PINMUX_NUM_FUNCS * pin; index += func; mux_path = &galileo_pinmux_paths[index]; - for (i = 0; i < PINMUX_NUM_PATHS; i++) { + for(i = 0; i < PINMUX_NUM_PATHS; i++) { switch(mux_path->path[i].chip) { - case EXP0: - if (gpio_pcal9535a_write(&data.exp0, mux_path->path[i].pin, mux_path->path[i].level) < 0) - return -1; - if (gpio_pcal9535a_config(&data.exp0, mux_path->path[i].pin, mux_path->path[i].cfg) < 0) - return -1; - break; - case EXP1: - if (gpio_pcal9535a_write(&data.exp1, mux_path->path[i].pin, mux_path->path[i].level) < 0) - return -1; - if (gpio_pcal9535a_config(&data.exp1, mux_path->path[i].pin, mux_path->path[i].cfg) < 0) - return -1; - break; - case EXP2: - if (gpio_pcal9535a_write(&data.exp2, mux_path->path[i].pin, mux_path->path[i].level) < 0) - return -1; - if (gpio_pcal9535a_config(&data.exp2, mux_path->path[i].pin, mux_path->path[i].cfg) < 0) - return -1; - break; - case PWM0: - if (pwm_pca9685_set_duty_cycle(&data.pwm0, mux_path->path[i].pin, mux_path->path[i].level ? 100 : 0) < 0) - return -1; - break; - case NONE: - break; + case EXP0: + if(gpio_pcal9535a_write(&data.exp0, mux_path->path[i].pin, mux_path->path[i].level) < 0) { + return -1; + } + if(gpio_pcal9535a_config(&data.exp0, mux_path->path[i].pin, mux_path->path[i].cfg) < 0) { + return -1; + } + break; + case EXP1: + if(gpio_pcal9535a_write(&data.exp1, mux_path->path[i].pin, mux_path->path[i].level) < 0) { + return -1; + } + if(gpio_pcal9535a_config(&data.exp1, mux_path->path[i].pin, mux_path->path[i].cfg) < 0) { + return -1; + } + break; + case EXP2: + if(gpio_pcal9535a_write(&data.exp2, mux_path->path[i].pin, mux_path->path[i].level) < 0) { + return -1; + } + if(gpio_pcal9535a_config(&data.exp2, mux_path->path[i].pin, mux_path->path[i].cfg) < 0) { + return -1; + } + break; + case PWM0: + if(pwm_pca9685_set_duty_cycle(&data.pwm0, mux_path->path[i].pin, mux_path->path[i].level ? 100 : 0) < 0) { + return -1; + } + break; + case NONE: + break; } } return 0; } - int galileo_pinmux_initialize(void) { uint8_t i; /* has to init after I2C master */ - if (!quarkX1000_i2c_is_available()) + if(!quarkX1000_i2c_is_available()) { return -1; + } - if (gpio_pcal9535a_init(&data.exp0, GPIO_PCAL9535A_0_I2C_ADDR) < 0) + if(gpio_pcal9535a_init(&data.exp0, GPIO_PCAL9535A_0_I2C_ADDR) < 0) { return -1; + } - if (gpio_pcal9535a_init(&data.exp1, GPIO_PCAL9535A_1_I2C_ADDR) < 0) + if(gpio_pcal9535a_init(&data.exp1, GPIO_PCAL9535A_1_I2C_ADDR) < 0) { return -1; + } - if (gpio_pcal9535a_init(&data.exp2, GPIO_PCAL9535A_2_I2C_ADDR) < 0) + if(gpio_pcal9535a_init(&data.exp2, GPIO_PCAL9535A_2_I2C_ADDR) < 0) { return -1; + } - if (pwm_pca9685_init(&data.pwm0, PWM_PCA9685_0_I2C_ADDR) < 0) + if(pwm_pca9685_init(&data.pwm0, PWM_PCA9685_0_I2C_ADDR) < 0) { return -1; + } - for (i = 0; i < PINMUX_NUM_PINS; i++) { - if (galileo_pinmux_set_pin(default_pinmux_config[i].pin_num, default_pinmux_config[i].func) < 0) + for(i = 0; i < PINMUX_NUM_PINS; i++) { + if(galileo_pinmux_set_pin(default_pinmux_config[i].pin_num, default_pinmux_config[i].func) < 0) { return -1; + } } return 0; diff --git a/platform/galileo/drivers/gpio-pcal9535a.c b/platform/galileo/drivers/gpio-pcal9535a.c index ce7dd82b1..1fac7f74b 100644 --- a/platform/galileo/drivers/gpio-pcal9535a.c +++ b/platform/galileo/drivers/gpio-pcal9535a.c @@ -70,34 +70,36 @@ read_port_regs(struct gpio_pcal9535a_data *data, uint8_t reg, union gpio_pcal953 buf->byte[0] = reg; buf->byte[1] = 0; - if (quarkX1000_i2c_write(buf->byte, 1, data->i2c_slave_addr) < 0) + if(quarkX1000_i2c_write(buf->byte, 1, data->i2c_slave_addr) < 0) { return -1; + } do { clock_wait(READ_PORT_TIMEOUT); r = quarkX1000_i2c_read(buf->byte, 2, data->i2c_slave_addr); - if (r == 0) + if(r == 0) { break; - } while (tries--); + } + } while(tries--); - if (r < 0) + if(r < 0) { return -1; + } return 0; } - static int write_port_regs(struct gpio_pcal9535a_data *data, uint8_t reg, union gpio_pcal9535a_port_data *buf) { - uint8_t cmd[] = {reg, buf->byte[0], buf->byte[1]}; + uint8_t cmd[] = { reg, buf->byte[0], buf->byte[1] }; - if (quarkX1000_i2c_polling_write(cmd, sizeof(cmd), data->i2c_slave_addr) < 0) + if(quarkX1000_i2c_polling_write(cmd, sizeof(cmd), data->i2c_slave_addr) < 0) { return -1; + } return 0; } - static int setup_pin_dir(struct gpio_pcal9535a_data *data, uint32_t pin, int flags) { @@ -106,47 +108,49 @@ setup_pin_dir(struct gpio_pcal9535a_data *data, uint32_t pin, int flags) bit_mask = 1 << pin; - if ((flags & QUARKX1000_GPIO_DIR_MASK) == QUARKX1000_GPIO_IN) + if((flags & QUARKX1000_GPIO_DIR_MASK) == QUARKX1000_GPIO_IN) { new_value = 1 << pin; + } port->all &= ~bit_mask; port->all |= new_value; return write_port_regs(data, REG_CONF_PORT0, port); } - static int setup_pin_pullupdown(struct gpio_pcal9535a_data *data, uint32_t pin, int flags) { union gpio_pcal9535a_port_data *port; uint16_t bit_mask, new_value = 0; - if ((flags & QUARKX1000_GPIO_PUD_MASK) != QUARKX1000_GPIO_PUD_NORMAL) { + if((flags & QUARKX1000_GPIO_PUD_MASK) != QUARKX1000_GPIO_PUD_NORMAL) { port = &data->reg_cache.pud_sel; bit_mask = 1 << pin; - if ((flags & QUARKX1000_GPIO_PUD_MASK) == QUARKX1000_GPIO_PUD_PULL_UP) + if((flags & QUARKX1000_GPIO_PUD_MASK) == QUARKX1000_GPIO_PUD_PULL_UP) { new_value = 1 << pin; + } port->all &= ~bit_mask; port->all |= new_value; - if (write_port_regs(data, REG_PUD_SEL_PORT0, port) < 0) + if(write_port_regs(data, REG_PUD_SEL_PORT0, port) < 0) { return -1; + } } port = &data->reg_cache.pud_en; bit_mask = 1 << pin; - if ((flags & QUARKX1000_GPIO_PUD_MASK) != QUARKX1000_GPIO_PUD_NORMAL) + if((flags & QUARKX1000_GPIO_PUD_MASK) != QUARKX1000_GPIO_PUD_NORMAL) { new_value = 1 << pin; + } port->all &= ~bit_mask; port->all |= new_value; return write_port_regs(data, REG_PUD_EN_PORT0, port); } - static int setup_pin_polarity(struct gpio_pcal9535a_data *data, uint32_t pin, int flags) { @@ -155,28 +159,30 @@ setup_pin_polarity(struct gpio_pcal9535a_data *data, uint32_t pin, int flags) bit_mask = 1 << pin; - if ((flags & QUARKX1000_GPIO_POL_MASK) == QUARKX1000_GPIO_POL_INV) + if((flags & QUARKX1000_GPIO_POL_MASK) == QUARKX1000_GPIO_POL_INV) { new_value = 1 << pin; + } port->all &= ~bit_mask; port->all |= new_value; - if (write_port_regs(data, REG_POL_INV_PORT0, port) < 0) + if(write_port_regs(data, REG_POL_INV_PORT0, port) < 0) { return -1; + } data->out_pol_inv = port->all; return 0; } - int gpio_pcal9535a_write(struct gpio_pcal9535a_data *data, uint32_t pin, uint32_t value) { union gpio_pcal9535a_port_data *port = &data->reg_cache.output; uint16_t bit_mask, new_value; - if (!quarkX1000_i2c_is_available()) + if(!quarkX1000_i2c_is_available()) { return -1; + } bit_mask = 1 << pin; @@ -189,41 +195,44 @@ gpio_pcal9535a_write(struct gpio_pcal9535a_data *data, uint32_t pin, uint32_t va return write_port_regs(data, REG_OUTPUT_PORT0, port); } - int gpio_pcal9535a_read(struct gpio_pcal9535a_data *data, uint32_t pin, uint32_t *value) { union gpio_pcal9535a_port_data buf; - if (!quarkX1000_i2c_is_available()) + if(!quarkX1000_i2c_is_available()) { return -1; + } - if (read_port_regs(data, REG_INPUT_PORT0, &buf) < 0) + if(read_port_regs(data, REG_INPUT_PORT0, &buf) < 0) { return -1; + } *value = (buf.all >> pin) & 0x01; return 0; } - int gpio_pcal9535a_config(struct gpio_pcal9535a_data *data, uint32_t pin, int flags) { - if (!quarkX1000_i2c_is_available()) + if(!quarkX1000_i2c_is_available()) { return -1; + } - if (setup_pin_dir(data, pin, flags) < 0) + if(setup_pin_dir(data, pin, flags) < 0) { return -1; + } - if (setup_pin_polarity(data, pin, flags) < 0) + if(setup_pin_polarity(data, pin, flags) < 0) { return -1; + } - if (setup_pin_pullupdown(data, pin, flags) < 0) + if(setup_pin_pullupdown(data, pin, flags) < 0) { return -1; + } return 0; } - static int setup_port_dir(struct gpio_pcal9535a_data *data, uint32_t pin, int flags) { @@ -233,18 +242,18 @@ setup_port_dir(struct gpio_pcal9535a_data *data, uint32_t pin, int flags) return write_port_regs(data, REG_CONF_PORT0, port); } - static int setup_port_pullupdown(struct gpio_pcal9535a_data *data, uint32_t pin, int flags) { union gpio_pcal9535a_port_data *port; - if ((flags & QUARKX1000_GPIO_PUD_MASK) != QUARKX1000_GPIO_PUD_NORMAL) { + if((flags & QUARKX1000_GPIO_PUD_MASK) != QUARKX1000_GPIO_PUD_NORMAL) { port = &data->reg_cache.pud_sel; port->all = ((flags & QUARKX1000_GPIO_PUD_MASK) == QUARKX1000_GPIO_PUD_PULL_UP) ? 0xFFFF : 0x0; - if (write_port_regs(data, REG_PUD_SEL_PORT0, port) < 0) + if(write_port_regs(data, REG_PUD_SEL_PORT0, port) < 0) { return -1; + } } port = &data->reg_cache.pud_en; @@ -252,7 +261,6 @@ setup_port_pullupdown(struct gpio_pcal9535a_data *data, uint32_t pin, int flags) return write_port_regs(data, REG_PUD_EN_PORT0, port); } - static int setup_port_polarity(struct gpio_pcal9535a_data *data, uint32_t pin, int flags) { @@ -260,22 +268,23 @@ setup_port_polarity(struct gpio_pcal9535a_data *data, uint32_t pin, int flags) port->all = ((flags & QUARKX1000_GPIO_POL_MASK) == QUARKX1000_GPIO_POL_INV) ? 0xFFFF : 0x0; - if (write_port_regs(data, REG_POL_INV_PORT0, port) < 0) + if(write_port_regs(data, REG_POL_INV_PORT0, port) < 0) { return -1; + } data->out_pol_inv = port->all; return 0; } - int gpio_pcal9535a_write_port(struct gpio_pcal9535a_data *data, uint32_t pin, uint32_t value) { union gpio_pcal9535a_port_data *port = &data->reg_cache.output; uint16_t bit_mask, new_value; - if (!quarkX1000_i2c_is_available()) + if(!quarkX1000_i2c_is_available()) { return -1; + } port->all = value; bit_mask = data->out_pol_inv; @@ -289,47 +298,51 @@ gpio_pcal9535a_write_port(struct gpio_pcal9535a_data *data, uint32_t pin, uint32 return write_port_regs(data, REG_OUTPUT_PORT0, port); } - int gpio_pcal9535a_read_port(struct gpio_pcal9535a_data *data, uint32_t pin, uint32_t *value) { union gpio_pcal9535a_port_data buf; - if (!quarkX1000_i2c_is_available()) + if(!quarkX1000_i2c_is_available()) { return -1; + } - if (read_port_regs(data, REG_INPUT_PORT0, &buf) < 0) + if(read_port_regs(data, REG_INPUT_PORT0, &buf) < 0) { return -1; + } *value = buf.all; return 0; } - int gpio_pcal9535a_config_port(struct gpio_pcal9535a_data *data, uint32_t pin, int flags) { - if (!quarkX1000_i2c_is_available()) + if(!quarkX1000_i2c_is_available()) { return -1; + } - if (setup_port_dir(data, pin, flags) < 0) + if(setup_port_dir(data, pin, flags) < 0) { return -1; + } - if (setup_port_polarity(data, pin, flags) < 0) + if(setup_port_polarity(data, pin, flags) < 0) { return -1; + } - if (setup_port_pullupdown(data, pin, flags) < 0) + if(setup_port_pullupdown(data, pin, flags) < 0) { return -1; + } return 0; } - int gpio_pcal9535a_init(struct gpio_pcal9535a_data *data, uint16_t i2c_slave_addr) { /* has to init after I2C master */ - if (!quarkX1000_i2c_is_available()) + if(!quarkX1000_i2c_is_available()) { return -1; + } data->i2c_slave_addr = i2c_slave_addr; diff --git a/platform/galileo/drivers/pwm-pca9685.c b/platform/galileo/drivers/pwm-pca9685.c index a3d93fd5c..6a3d7ce2d 100644 --- a/platform/galileo/drivers/pwm-pca9685.c +++ b/platform/galileo/drivers/pwm-pca9685.c @@ -47,21 +47,23 @@ pwm_pca9685_set_values(struct pwm_pca9685_data *data, uint32_t pwm, uint32_t on, { uint8_t buf[5] = { 0 }; - if (!quarkX1000_i2c_is_available()) + if(!quarkX1000_i2c_is_available()) { return -1; + } - if (pwm > MAX_PWM_OUT) + if(pwm > MAX_PWM_OUT) { return -1; + } buf[0] = REG_LED_ON_L(pwm); - if ((on >= PWM_ONE_PERIOD_TICKS) || (off >= PWM_ONE_PERIOD_TICKS)) { + if((on >= PWM_ONE_PERIOD_TICKS) || (off >= PWM_ONE_PERIOD_TICKS)) { /* Treat as 100% */ buf[1] = 0x0; buf[2] = (1 << 4); buf[3] = 0x0; buf[4] = 0x0; - } else if (off == 0) { + } else if(off == 0) { /* Treat it as 0% */ buf[1] = 0x0; buf[2] = 0x0; @@ -77,16 +79,15 @@ pwm_pca9685_set_values(struct pwm_pca9685_data *data, uint32_t pwm, uint32_t on, return quarkX1000_i2c_polling_write(buf, sizeof(buf), data->i2c_slave_addr); } - int pwm_pca9685_set_duty_cycle(struct pwm_pca9685_data *data, uint32_t pwm, uint8_t duty) { uint32_t on, off; - if (duty == 0) { + if(duty == 0) { on = 0; off = 0; - } else if (duty >= 100) { + } else if(duty >= 100) { on = PWM_ONE_PERIOD_TICKS + 1; off = PWM_ONE_PERIOD_TICKS + 1; } else { @@ -96,23 +97,24 @@ pwm_pca9685_set_duty_cycle(struct pwm_pca9685_data *data, uint32_t pwm, uint8_t return pwm_pca9685_set_values(data, pwm, on, off); } - int pwm_pca9685_init(struct pwm_pca9685_data *data, uint16_t i2c_slave_addr) { uint8_t buf[2] = { 0 }; /* has to init after I2C master */ - if (!quarkX1000_i2c_is_available()) + if(!quarkX1000_i2c_is_available()) { return -1; + } data->i2c_slave_addr = i2c_slave_addr; buf[0] = REG_MODE1; buf[1] = (1 << 5); - if (quarkX1000_i2c_polling_write(buf, 2, i2c_slave_addr) < 0) + if(quarkX1000_i2c_polling_write(buf, 2, i2c_slave_addr) < 0) { return -1; + } return 0; } From b4523b9130636d5cf25662a0c4e875bdc3fcb3f1 Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Sat, 19 Dec 2015 17:35:58 -0800 Subject: [PATCH 92/92] galileo: Fix broken link in README.md This patch fixes a broken link in README.md to serial cable connection instructions. --- platform/galileo/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/galileo/README.md b/platform/galileo/README.md index c38589de7..b99ad7d65 100644 --- a/platform/galileo/README.md +++ b/platform/galileo/README.md @@ -205,7 +205,7 @@ References [1] https://communities.intel.com/message/211778 -[2] http://www.intel.com/support/galileo/sb/CS-035124.htm +[2] https://software.intel.com/en-us/articles/intel-galileo-gen-2-board-assembly-using-eclipse-and-intel-xdk-iot-edition [3] https://www.gnu.org/software/grub/manual/multiboot/multiboot.html