diff --git a/conf/bblayers.conf.sample b/conf/bblayers.conf.sample new file mode 100644 index 0000000..5b623be --- /dev/null +++ b/conf/bblayers.conf.sample @@ -0,0 +1,10 @@ +POKY_BBLAYERS_CONF_VERSION = "2" +BBPATH = "${TOPDIR}" +BBFILES ?= "" +BBLAYERS ?= " \ + ##COREBASE##/meta \ + ##COREBASE##/meta-poky \ + ##COREBASE##/meta-yocto-bsp \ + ##COREBASE##/meta-openembedded/meta-oe \ + ##COREBASE##/meta-img \ + " \ No newline at end of file diff --git a/conf/layer.conf b/conf/layer.conf index 267ab23..1dbc381 100644 --- a/conf/layer.conf +++ b/conf/layer.conf @@ -8,3 +8,9 @@ BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \ BBFILE_COLLECTIONS += "img" BBFILE_PATTERN_img = "^${LAYERDIR}/" BBFILE_PRIORITY_img = "6" + +LAYERDEPENDS_img = "\ + core \ + yocto \ + openembedded-layer \ +" diff --git a/conf/local.conf.sample b/conf/local.conf.sample new file mode 100644 index 0000000..0312fd5 --- /dev/null +++ b/conf/local.conf.sample @@ -0,0 +1,246 @@ +# +# This file is your local configuration file and is where all local user settings +# are placed. The comments in this file give some guide to the options a new user +# to the system might want to change but pretty much any configuration option can +# be set in this file. More adventurous users can look at local.conf.extended +# which contains other examples of configuration which can be placed in this file +# but new users likely won't need any of them initially. +# +# Lines starting with the '#' character are commented out and in some cases the +# default values are provided as comments to show people example syntax. Enabling +# the option is a question of removing the # character and making any change to the +# variable as required. + +# +# Machine Selection +# +# You need to select a specific machine to target the build with. There are a selection +# of emulated machines available which can boot and run in the QEMU emulator: +# +#MACHINE ?= "qemuarm" +#MACHINE ?= "qemuarm64" +#MACHINE ?= "qemumips" +#MACHINE ?= "qemumips64" +#MACHINE ?= "qemuppc" +#MACHINE ?= "qemux86" +#MACHINE ?= "qemux86-64" +# +# There are also the following hardware board target machines included for +# demonstration purposes: +# +#MACHINE ?= "beaglebone" +#MACHINE ?= "genericx86" +#MACHINE ?= "genericx86-64" +#MACHINE ?= "mpc8315e-rdb" +#MACHINE ?= "edgerouter" +# +# This sets the default machine to be qemuxmips if no other machine is selected: +MACHINE ??= "qemumips" + +# +# Where to place downloads +# +# During a first build the system will download many different source code tarballs +# from various upstream projects. This can take a while, particularly if your network +# connection is slow. These are all stored in DL_DIR. When wiping and rebuilding you +# can preserve this directory to speed up this part of subsequent builds. This directory +# is safe to share between multiple builds on the same machine too. +# +# The default is a downloads directory under TOPDIR which is the build directory. +# +#DL_DIR ?= "${TOPDIR}/downloads" + +# +# Where to place shared-state files +# +# BitBake has the capability to accelerate builds based on previously built output. +# This is done using "shared state" files which can be thought of as cache objects +# and this option determines where those files are placed. +# +# You can wipe out TMPDIR leaving this directory intact and the build would regenerate +# from these files if no changes were made to the configuration. If changes were made +# to the configuration, only shared state files where the state was still valid would +# be used (done using checksums). +# +# The default is a sstate-cache directory under TOPDIR. +# +#SSTATE_DIR ?= "${TOPDIR}/sstate-cache" + +# +# Where to place the build output +# +# This option specifies where the bulk of the building work should be done and +# where BitBake should place its temporary files and output. Keep in mind that +# this includes the extraction and compilation of many applications and the toolchain +# which can use Gigabytes of hard disk space. +# +# The default is a tmp directory under TOPDIR. +# +#TMPDIR = "${TOPDIR}/tmp" + +# +# Default policy config +# +# The distribution setting controls which policy settings are used as defaults. +# The default value is fine for general Yocto project use, at least initially. +# Ultimately when creating custom policy, people will likely end up subclassing +# these defaults. +# +DISTRO ?= "poky" +# As an example of a subclass there is a "bleeding" edge policy configuration +# where many versions are set to the absolute latest code from the upstream +# source control systems. This is just mentioned here as an example, its not +# useful to most new users. +# DISTRO ?= "poky-bleeding" + +# +# Package Management configuration +# +# This variable lists which packaging formats to enable. Multiple package backends +# can be enabled at once and the first item listed in the variable will be used +# to generate the root filesystems. +# Options are: +# - 'package_deb' for debian style deb files +# - 'package_ipk' for ipk files are used by opkg (a debian style embedded package manager) +# - 'package_rpm' for rpm style packages +# E.g.: PACKAGE_CLASSES ?= "package_rpm package_deb package_ipk" +# We default to rpm: +PACKAGE_CLASSES ?= "package_rpm" + +# Using rm_work to save space +INHERIT += "rm_work" + +# If using rm_work, this prevents the rootfs of these images from being deleted +# before wic has a chance to package it up into an image file. +RM_WORK_EXCLUDE = "\ + ${BUILD_IMAGE} \ + " + +# +# SDK target architecture +# +# This variable specifies the architecture to build SDK items for and means +# you can build the SDK packages for architectures other than the machine you are +# running the build on (i.e. building i686 packages on an x86_64 host). +# Supported values are i686 and x86_64 +#SDKMACHINE ?= "i686" + +# +# Extra image configuration defaults +# +# The EXTRA_IMAGE_FEATURES variable allows extra packages to be added to the generated +# images. Some of these options are added to certain image types automatically. The +# variable can contain the following options: +# "dbg-pkgs" - add -dbg packages for all installed packages +# (adds symbol information for debugging/profiling) +# "dev-pkgs" - add -dev packages for all installed packages +# (useful if you want to develop against libs in the image) +# "ptest-pkgs" - add -ptest packages for all ptest-enabled packages +# (useful if you want to run the package test suites) +# "tools-sdk" - add development tools (gcc, make, pkgconfig etc.) +# "tools-debug" - add debugging tools (gdb, strace) +# "eclipse-debug" - add Eclipse remote debugging support +# "tools-profile" - add profiling tools (oprofile, lttng, valgrind) +# "tools-testapps" - add useful testing tools (ts_print, aplay, arecord etc.) +# "debug-tweaks" - make an image suitable for development +# e.g. ssh root access has a blank password +# There are other application targets that can be used here too, see +# meta/classes/image.bbclass and meta/classes/core-image.bbclass for more details. +# We default to enabling the debugging tweaks. +EXTRA_IMAGE_FEATURES ?= "debug-tweaks" + +# +# Additional image features +# +# The following is a list of additional classes to use when building images which +# enable extra features. Some available options which can be included in this variable +# are: +# - 'buildstats' collect build statistics +# - 'image-mklibs' to reduce shared library files size for an image +# - 'image-prelink' in order to prelink the filesystem image +# - 'image-swab' to perform host system intrusion detection +# NOTE: if listing mklibs & prelink both, then make sure mklibs is before prelink +# NOTE: mklibs also needs to be explicitly enabled for a given image, see local.conf.extended +USER_CLASSES ?= "buildstats image-mklibs image-prelink" + +# +# Runtime testing of images +# +# The build system can test booting virtual machine images under qemu (an emulator) +# after any root filesystems are created and run tests against those images. To +# enable this uncomment this line. See classes/testimage(-auto).bbclass for +# further details. +#TEST_IMAGE = "1" +# +# Interactive shell configuration +# +# Under certain circumstances the system may need input from you and to do this it +# can launch an interactive shell. It needs to do this since the build is +# multithreaded and needs to be able to handle the case where more than one parallel +# process may require the user's attention. The default is iterate over the available +# terminal types to find one that works. +# +# Examples of the occasions this may happen are when resolving patches which cannot +# be applied, to use the devshell or the kernel menuconfig +# +# Supported values are auto, gnome, xfce, rxvt, screen, konsole (KDE 3.x only), none +# Note: currently, Konsole support only works for KDE 3.x due to the way +# newer Konsole versions behave +#OE_TERMINAL = "auto" +# By default disable interactive patch resolution (tasks will just fail instead): +PATCHRESOLVE = "noop" + +# +# Disk Space Monitoring during the build +# +# Monitor the disk space during the build. If there is less that 1GB of space or less +# than 100K inodes in any key build location (TMPDIR, DL_DIR, SSTATE_DIR), gracefully +# shutdown the build. If there is less that 100MB or 1K inodes, perform a hard abort +# of the build. The reason for this is that running completely out of space can corrupt +# files and damages the build in ways which may not be easily recoverable. +# It's necesary to monitor /tmp, if there is no space left the build will fail +# with very exotic errors. +BB_DISKMON_DIRS = "\ + STOPTASKS,${TMPDIR},1G,100K \ + STOPTASKS,${DL_DIR},1G,100K \ + STOPTASKS,${SSTATE_DIR},1G,100K \ + STOPTASKS,/tmp,100M,100K \ + ABORT,${TMPDIR},100M,1K \ + ABORT,${DL_DIR},100M,1K \ + ABORT,${SSTATE_DIR},100M,1K \ + ABORT,/tmp,10M,1K" + +# +# Shared-state files from other locations +# +# As mentioned above, shared state files are prebuilt cache data objects which can +# used to accelerate build time. This variable can be used to configure the system +# to search other mirror locations for these objects before it builds the data itself. +# +# This can be a filesystem directory, or a remote url such as http or ftp. These +# would contain the sstate-cache results from previous builds (possibly from other +# machines). This variable works like fetcher MIRRORS/PREMIRRORS and points to the +# cache locations to check for the shared objects. +# NOTE: if the mirror uses the same structure as SSTATE_DIR, you need to add PATH +# at the end as shown in the examples below. This will be substituted with the +# correct path within the directory structure. +#SSTATE_MIRRORS ?= "\ +#file://.* http://someserver.tld/share/sstate/PATH;downloadfilename=PATH \n \ +#file://.* file:///some/local/dir/sstate/PATH" + + +# +# Qemu configuration +# +# By default qemu will build with a builtin VNC server where graphical output can be +# seen. The two lines below enable the SDL backend too. By default libsdl-native will +# be built, if you want to use your host's libSDL instead of the minimal libsdl built +# by libsdl-native then uncomment the ASSUME_PROVIDED line below. +PACKAGECONFIG_append_pn-qemu-native = " sdl" +PACKAGECONFIG_append_pn-nativesdk-qemu = " sdl" +#ASSUME_PROVIDED += "libsdl-native" + +# CONF_VERSION is increased each time build/conf/ changes incompatibly and is used to +# track the version of this file when it was generated. This can safely be ignored if +# this doesn't mean anything to you. +CONF_VERSION = "1" \ No newline at end of file diff --git a/conf/machine/xilfpga.conf b/conf/machine/xilfpga.conf index 43c7aec..84413d1 100644 --- a/conf/machine/xilfpga.conf +++ b/conf/machine/xilfpga.conf @@ -10,5 +10,12 @@ SERIAL_CONSOLES = "115200;ttyS0" IMAGE_FSTYPES ?= "cpio.gz" PREFERRED_PROVIDER_virtual/kernel = "linux-yocto" -#KERNEL_DEFCONFIG_xilfpga = "xilfpga_defconfig" +PREFERRED_VERSION_linux-yocto = "4.8.12%" +MACHINE_DEVICETREE ?= "xilfpga/nexys4ddr.dts" KERNEL_IMAGETYPE = "vmlinux" + +INITRAMFS_IMAGE = "mipsfpga-soc-initramfs" +INITRAMFS_IMAGE_BUNDLE = "1" + +# This device doesn't have an RTC +MACHINE_FEATURES_BACKFILL_CONSIDERED = "rtc" diff --git a/recipes-core/images/mipsfpga-soc-initramfs.bb b/recipes-core/images/mipsfpga-soc-initramfs.bb new file mode 100644 index 0000000..d2657ed --- /dev/null +++ b/recipes-core/images/mipsfpga-soc-initramfs.bb @@ -0,0 +1,19 @@ + +include recipes-core/images/core-image-minimal.bb + +IMAGE_FSTYPES = "${INITRAMFS_FSTYPES}" +PACKAGE_INSTALL = "${IMAGE_INSTALL}" + +# initramfs/initrd support for dynamic /dev +PACKAGE_INSTALL += "\ + initramfs-module-udev \ + initramfs-module-debug \ + initramfs-module-use-rootfs \ + " +BAD_RECOMMENDATIONS += "initramfs-module-rootfs" + +CORE_IMAGE_EXTRA_INSTALL += "\ + devmem2 \ + i2c-tools \ + simple-gpio \ +" diff --git a/recipes-core/initrdscripts/files/userootfs b/recipes-core/initrdscripts/files/userootfs new file mode 100644 index 0000000..92c016a --- /dev/null +++ b/recipes-core/initrdscripts/files/userootfs @@ -0,0 +1,13 @@ +#!/bin/sh + +userootfs_enabled() { + return 0 +} + +userootfs_run() { + if [ -n "$ROOTFS_DIR" ]; then + info "Unsetting ROOTFS_DIR" + unset ROOTFS_DIR + fi + exec /sbin/init +} diff --git a/recipes-core/initrdscripts/initramfs-framework_1.0.bbappend b/recipes-core/initrdscripts/initramfs-framework_1.0.bbappend new file mode 100644 index 0000000..c40ac86 --- /dev/null +++ b/recipes-core/initrdscripts/initramfs-framework_1.0.bbappend @@ -0,0 +1,23 @@ +# Presently, we do not need to find an alternate rootfs since our +# kernel and file system are combined. In the future if we add +# SD card support to the MIPSfpga core, we can revisit using udev +# to bootstrap into an external filesystem if necessary. For now, +# this append adds a 'norootfs' script + +FILESEXTRAPATHS_prepend := "${THISDIR}/files:" + +SRC_URI += "\ + file://userootfs \ +" + +do_install_append() { + install -d ${D}/init.d + install -m 0755 ${WORKDIR}/userootfs ${D}/init.d/89-userootfs +} + +PACKAGES += "\ + initramfs-module-use-rootfs \ +" +SUMMARY_initramfs-module-use-rootfs = "initramfs for skipping the search for rootfs" +RDEPENDS_initramfs-module-use-rootfs = "${PN}-base" +FILES_initramfs-module-use-rootfs = "/init.d/89-userootfs" \ No newline at end of file diff --git a/recipes-examples/gpio/simple-gpio.bb b/recipes-examples/gpio/simple-gpio.bb new file mode 100644 index 0000000..0977ed9 --- /dev/null +++ b/recipes-examples/gpio/simple-gpio.bb @@ -0,0 +1,21 @@ +SUMMARY = "Simple GPIO control example" +LICENSE = "CLOSED" + +COMPATIBLE_MACHINE = "xilfpga" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI = "file://simple_gpio_on.c" + +S = "${WORKDIR}" + +do_configure[noexec] = "1" + +do_compile() { + ${CC} ${CFLAGS} ${LDFLAGS} simple_gpio_on.c -o simple_gpio_on +} + +do_install() { + install -d ${D}${bindir} + install -m 0755 simple_gpio_on ${D}${bindir} +} \ No newline at end of file diff --git a/recipes-examples/gpio/simple-gpio/simple_gpio_on.c b/recipes-examples/gpio/simple-gpio/simple_gpio_on.c new file mode 100644 index 0000000..d416463 --- /dev/null +++ b/recipes-examples/gpio/simple-gpio/simple_gpio_on.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include +#include +#include +#include + +int main(void) +{ + printf("Welcome to UIO test prog\n"); + + int fd = open("/dev/uio0", O_RDWR); + void *memory; + int *memory_int; + int N = 1; //get one page. + int offset = N * getpagesize(); + + printf("Opening file /dev/uio0 \n"); + + if (fd < 1) { + printf("could not open /dev/uio0\n"); + exit(EXIT_FAILURE); + } + + printf("Trying to mmap memory\n"); + + memory = mmap(NULL, offset, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + + if(memory == MAP_FAILED) { + printf("couldn't mmap memory space\n"); + exit(EXIT_FAILURE); + } + + memory_int = (unsigned int *) memory; + + printf("Writing 0xf at location 0x10C0_0004. 4 LEDs will light up. \n"); + + (memory_int[1]) = 0xf; //write 0xf to memory at location 0x10C0_0004. + + printf("Writing 0xf0 at location 0x10C0_0008. Bit 7:5 will be set as input. These switches will be read. \n"); + + (memory_int[2]) = 0xf0; //write 0xf0 to memory at location 0x10C0_0000. + + printf("Reading 0x10C0_0000 for switches %08x \n", memory_int[0]); + + close(fd); + exit(EXIT_SUCCESS); +} diff --git a/recipes-kernel/linux/files/0001-xilfpga-intc.patch b/recipes-kernel/linux/files/0001-xilfpga-intc.patch new file mode 100644 index 0000000..fa6a375 --- /dev/null +++ b/recipes-kernel/linux/files/0001-xilfpga-intc.patch @@ -0,0 +1,272 @@ +--- git/arch/mips/xilfpga/intc.c 2017-04-17 13:57:58.984583556 -0400 ++++ git.patched/arch/mips/xilfpga/intc.c 2017-04-17 14:11:02.276931707 -0400 +@@ -1,21 +1,254 @@ + /* +- * Xilfpga interrupt controller setup ++ * Copyright (C) 2007-2013 Michal Simek ++ * Copyright (C) 2012-2013 Xilinx, Inc. ++ * Copyright (C) 2007-2009 PetaLogix ++ * Copyright (C) 2006 Atmark Techno, Inc. + * +- * Copyright (C) 2015 Imagination Technologies +- * Author: Zubair Lutfullah Kakakhel +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms and conditions of the GNU General Public License, +- * version 2, as published by the Free Software Foundation. ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. + */ + +-#include ++#include ++#include ++#include ++#include ++#include ++#include + #include +- ++#include + #include + ++static void __iomem *intc_baseaddr; ++ ++/* No one else should require these constants, so define them locally here. */ ++#define ISR 0x00 /* Interrupt Status Register */ ++#define IPR 0x04 /* Interrupt Pending Register */ ++#define IER 0x08 /* Interrupt Enable Register */ ++#define IAR 0x0c /* Interrupt Acknowledge Register */ ++#define SIE 0x10 /* Set Interrupt Enable bits */ ++#define CIE 0x14 /* Clear Interrupt Enable bits */ ++#define IVR 0x18 /* Interrupt Vector Register */ ++#define MER 0x1c /* Master Enable Register */ ++ ++#define MER_ME (1<<0) ++#define MER_HIE (1<<1) ++ ++asmlinkage void plat_irq_dispatch(void) ++{ ++ unsigned long pending = read_c0_cause() & read_c0_status() & ST0_IM; ++ int irq = 0; ++ ++ if (!pending) { ++ spurious_interrupt(); ++ return; ++ } ++ pending >>= CAUSEB_IP; ++ while (pending) { ++ irq = fls(pending) - 1; ++ do_IRQ(MIPS_CPU_IRQ_BASE + irq); ++ pending &= ~BIT(irq); ++ } ++ ++} ++ ++static unsigned int (*read_fn)(void __iomem *); ++static void (*write_fn)(u32, void __iomem *); ++ ++static void intc_write32(u32 val, void __iomem *addr) ++{ ++ iowrite32(val, addr); ++} ++ ++static unsigned int intc_read32(void __iomem *addr) ++{ ++ return ioread32(addr); ++} ++ ++static void intc_write32_be(u32 val, void __iomem *addr) ++{ ++ iowrite32be(val, addr); ++} ++ ++static unsigned int intc_read32_be(void __iomem *addr) ++{ ++ return ioread32be(addr); ++} ++ ++static void intc_enable_or_unmask(struct irq_data *d) ++{ ++ unsigned long mask = 1 << d->hwirq; ++ ++ pr_debug("enable_or_unmask: %ld\n", d->hwirq); ++ ++ /* ack level irqs because they can't be acked during ++ * ack function since the handle_level_irq function ++ * acks the irq before calling the interrupt handler ++ */ ++ if (irqd_is_level_type(d)) ++ write_fn(mask, intc_baseaddr + IAR); ++ ++ write_fn(mask, intc_baseaddr + SIE); ++} ++ ++static void intc_disable_or_mask(struct irq_data *d) ++{ ++ pr_debug("disable: %ld\n", d->hwirq); ++ write_fn(1 << d->hwirq, intc_baseaddr + CIE); ++} ++ ++static void intc_ack(struct irq_data *d) ++{ ++ pr_debug("ack: %ld\n", d->hwirq); ++ write_fn(1 << d->hwirq, intc_baseaddr + IAR); ++} ++ ++static void intc_mask_ack(struct irq_data *d) ++{ ++ unsigned long mask = 1 << d->hwirq; ++ ++ pr_debug("disable_and_ack: %ld\n", d->hwirq); ++ write_fn(mask, intc_baseaddr + CIE); ++ write_fn(mask, intc_baseaddr + IAR); ++} ++ ++static struct irq_chip intc_dev = { ++ .name = "Xilinx INTC", ++ .irq_unmask = intc_enable_or_unmask, ++ .irq_mask = intc_disable_or_mask, ++ .irq_ack = intc_ack, ++ .irq_mask_ack = intc_mask_ack, ++}; ++ ++static struct irq_domain *root_domain; ++ ++unsigned int get_irq(void) ++{ ++ unsigned int hwirq, irq = -1; ++ ++ hwirq = read_fn(intc_baseaddr + IVR); ++ if (hwirq != -1U) ++ irq = irq_find_mapping(root_domain, hwirq); ++ ++ pr_debug("get_irq: hwirq=%d, irq=%d\n", hwirq, irq); ++ ++ return irq; ++} ++ ++static int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) ++{ ++ u32 intr_mask = (u32)d->host_data; ++ ++ if (intr_mask & (1 << hw)) { ++ irq_set_chip_and_handler_name(irq, &intc_dev, ++ handle_edge_irq, "edge"); ++ irq_clear_status_flags(irq, IRQ_LEVEL); ++ } else { ++ irq_set_chip_and_handler_name(irq, &intc_dev, ++ handle_level_irq, "level"); ++ irq_set_status_flags(irq, IRQ_LEVEL); ++ } ++ return 0; ++} ++ ++static const struct irq_domain_ops xintc_irq_domain_ops = { ++ .xlate = irq_domain_xlate_onetwocell, ++ .map = xintc_map, ++}; ++ ++static void xil_intc_irq_handler(struct irq_desc *desc) ++{ ++ u32 pending = get_irq(); ++ ++ if (pending) { ++ while(true) { ++ pending = get_irq(); ++ //printk("irq = %x \n", pending); ++ generic_handle_irq(pending); ++ if (pending == 0xffffffff) ++ break; ++ } ++ } else { ++ printk("%s spurious interrupt \n",__func__); ++ WARN_ON(1); ++ spurious_interrupt(); ++ } ++// pending = get_irq(); ++// if(pending != 0xffffffff) ++// { ++// generic_handle_irq(pending); ++// } ++// pending = get_irq(); ++// if(pending != 0xffffffff) ++// {printk("%s pending = %x \n",__func__ , pending); WARN_ON(1);} ++} ++ ++static int __init xilinx_intc_of_init(struct device_node *intc, ++ struct device_node *parent) ++{ ++ u32 nr_irq, intr_mask; ++ int ret, irq; ++ ++ intc_baseaddr = of_iomap(intc, 0); ++ BUG_ON(!intc_baseaddr); ++ ++ ret = of_property_read_u32(intc, "xlnx,num-intr-inputs", &nr_irq); ++ if (ret < 0) { ++ pr_err("%s: unable to read xlnx,num-intr-inputs\n", __func__); ++ return ret; ++ } ++ ++ ret = of_property_read_u32(intc, "xlnx,kind-of-intr", &intr_mask); ++ if (ret < 0) { ++ pr_err("%s: unable to read xlnx,kind-of-intr\n", __func__); ++ return ret; ++ } ++ ++ if (intr_mask >> nr_irq) ++ pr_warn("%s: mismatch in kind-of-intr param\n", __func__); ++ ++ pr_info("%s: num_irq=%d, edge=0x%x\n", ++ intc->full_name, nr_irq, intr_mask); ++ ++ irq = irq_of_parse_and_map(intc, 0); ++ if (!irq) ++ panic("Failed to get INTC IRQ"); ++ ++ write_fn = intc_write32; ++ read_fn = intc_read32; ++ ++ /* ++ * Disable all external interrupts until they are ++ * explicity requested. ++ */ ++ write_fn(0, intc_baseaddr + IER); ++ ++ /* Acknowledge any pending interrupts just in case. */ ++ write_fn(0xffffffff, intc_baseaddr + IAR); ++ ++ /* Turn on the Master Enable. */ ++ write_fn(MER_HIE | MER_ME, intc_baseaddr + MER); ++ if (!(read_fn(intc_baseaddr + MER) & (MER_HIE | MER_ME))) { ++ write_fn = intc_write32_be; ++ read_fn = intc_read32_be; ++ write_fn(MER_HIE | MER_ME, intc_baseaddr + MER); ++ } ++ ++ /* Yeah, okay, casting the intr_mask to a void* is butt-ugly, but I'm ++ * lazy and Michal can clean it up to something nicer when he tests ++ * and commits this patch. ~~gcl */ ++ root_domain = irq_domain_add_linear(intc, nr_irq, &xintc_irq_domain_ops, ++ (void *)intr_mask); ++ ++ irq_set_chained_handler(irq, xil_intc_irq_handler); ++ irq_set_handler_data(irq, root_domain); ++ ++ return 0; ++} ++ + static struct of_device_id of_irq_ids[] __initdata = { + { .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_irq_of_init }, ++ { .compatible = "xlnx,xps-intc-1.00.a", .data = xilinx_intc_of_init }, + {}, + }; + +@@ -23,3 +256,5 @@ + { + of_irq_init(of_irq_ids); + } ++ ++IRQCHIP_DECLARE(xilinx_intc, "xlnx,xps-intc-1.00.a", xilinx_intc_of_init); diff --git a/recipes-kernel/linux/files/0002-xilfpga-ethernet-kconfig.patch b/recipes-kernel/linux/files/0002-xilfpga-ethernet-kconfig.patch new file mode 100644 index 0000000..a6156cd --- /dev/null +++ b/recipes-kernel/linux/files/0002-xilfpga-ethernet-kconfig.patch @@ -0,0 +1,20 @@ +--- git/drivers/net/ethernet/xilinx/Kconfig 2017-04-17 11:24:27.380870221 -0400 ++++ git.patched/drivers/net/ethernet/xilinx/Kconfig 2017-04-17 11:37:07.849811936 -0400 +@@ -5,7 +5,7 @@ + config NET_VENDOR_XILINX + bool "Xilinx devices" + default y +- depends on PPC || PPC32 || MICROBLAZE || ARCH_ZYNQ ++ depends on PPC || PPC32 || MICROBLAZE || ARCH_ZYNQ || MIPS + ---help--- + If you have a network (Ethernet) card belonging to this class, say Y. + +@@ -18,7 +18,7 @@ + + config XILINX_EMACLITE + tristate "Xilinx 10/100 Ethernet Lite support" +- depends on (PPC32 || MICROBLAZE || ARCH_ZYNQ) ++ depends on (PPC32 || MICROBLAZE || ARCH_ZYNQ || MIPS) + select PHYLIB + ---help--- + This driver supports the 10/100 Ethernet Lite from Xilinx. diff --git a/recipes-kernel/linux/files/0003-xilfpga-dts.patch b/recipes-kernel/linux/files/0003-xilfpga-dts.patch new file mode 100644 index 0000000..a30db8d --- /dev/null +++ b/recipes-kernel/linux/files/0003-xilfpga-dts.patch @@ -0,0 +1,98 @@ +--- git/arch/mips/boot/dts/xilfpga/nexys4ddr.dts 2017-04-17 11:24:20.389042376 -0400 ++++ git.patched/arch/mips/boot/dts/xilfpga/nexys4ddr.dts 2017-04-17 11:45:35.831517603 -0400 +@@ -17,6 +17,48 @@ + compatible = "mti,cpu-interrupt-controller"; + }; + ++ axi_intc: interrupt-controller@10200000 { ++ #interrupt-cells = <1>; ++ compatible = "xlnx,xps-intc-1.00.a"; ++ interrupt-controller; ++ reg = <0x10200000 0x10000>; ++ xlnx,kind-of-intr = <0x0>; ++ xlnx,num-intr-inputs = <0x6>; ++ ++ interrupt-parent = <&cpuintc>; ++ interrupts = <6>; ++ }; ++ ++ axi_ethernetlite: ethernet@10e00000 { ++ compatible = "xlnx,axi-ethernetlite-3.0", "xlnx,xps-ethernetlite-1.00.a"; ++ device_type = "network"; ++ interrupt-parent = <&axi_intc>; ++ interrupts = <1>; ++ local-mac-address = [08 86 4C 0D F7 09]; ++ phy-handle = <&phy0>; ++ reg = <0x10e00000 0x10000>; ++ xlnx,duplex = <0x1>; ++ xlnx,include-global-buffers = <0x1>; ++ xlnx,include-internal-loopback = <0x0>; ++ xlnx,include-mdio = <0x1>; ++ xlnx,instance = "axi_ethernetlite_inst"; ++ xlnx,rx-ping-pong = <0x1>; ++ xlnx,s-axi-id-width = <0x1>; ++ xlnx,tx-ping-pong = <0x1>; ++ xlnx,use-internal = <0x0>; ++ mdio { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ phy0: phy@1 { ++ compatible = <0x0007c0f0 0xfffffff0>; ++ device_type = "ethernet-phy"; ++ interrupt-parent = <&axi_intc>; ++ interrupts = <2>; ++ reg = <1>; ++ }; ++ }; ++ }; ++ + axi_gpio: gpio@10600000 { + #gpio-cells = <1>; + compatible = "xlnx,xps-gpio-1.00.a"; +@@ -28,7 +70,36 @@ + xlnx,interrupt-present = <0x0>; + xlnx,is-dual = <0x0>; + xlnx,tri-default = <0xffffffff>; +- } ; ++ ++ interrupt-parent = <&axi_intc>; ++ interrupts = <0>; ++ }; ++ ++ axi_i2c: i2c@10A00000 { ++ compatible = "xlnx,xps-iic-2.00.a"; ++ interrupt-parent = <&axi_intc>; ++ interrupts = <4>; ++ reg = < 0x10A00000 0x10000 >; ++ xlnx,clk-freq = <0x5f5e100>; ++ xlnx,family = "Artix7"; ++ xlnx,gpo-width = <0x1>; ++ xlnx,iic-freq = <0x186a0>; ++ xlnx,scl-inertial-delay = <0x0>; ++ xlnx,sda-inertial-delay = <0x0>; ++ xlnx,ten-bit-adr = <0x0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&ext>; ++ ad7420@4B { ++ compatible = "adt7420"; ++ reg = <0x4B>; ++ }; ++ }; ++ ++ custom_axi_gpio: user_gpio@10C00000 { ++ compatible = "generic-uio" , "uio"; ++ reg = < 0x10C00000 0x1000>; ++ }; + + axi_uart16550: serial@10400000 { + compatible = "ns16550a"; +@@ -37,7 +108,7 @@ + reg-shift = <2>; + reg-offset = <0x1000>; + +- clocks = <&ext>; ++ clocks = <&ext>; + }; + }; + diff --git a/recipes-kernel/linux/files/xilfpga-cmdline.cfg b/recipes-kernel/linux/files/xilfpga-cmdline.cfg new file mode 100644 index 0000000..e47dcf0 --- /dev/null +++ b/recipes-kernel/linux/files/xilfpga-cmdline.cfg @@ -0,0 +1,3 @@ + +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="console=ttyS0,115200 clk_ignore_unused uio_pdrv_genirq.of_id=\"generic-uio\"" diff --git a/recipes-kernel/linux/files/xilfpga-periph.cfg b/recipes-kernel/linux/files/xilfpga-periph.cfg new file mode 100644 index 0000000..dc88658 --- /dev/null +++ b/recipes-kernel/linux/files/xilfpga-periph.cfg @@ -0,0 +1,52 @@ + +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_XILINX=y + +CONFIG_SPI=y +CONFIG_SPI_XILINX=y +CONFIG_SPI_SPIDEV=y + +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_XILINX=y + +CONFIG_HWMON=y +CONFIG_SENSORS_ADT7410=y +CONFIG_NETDEVICES=y +CONFIG_NET=y +# CONFIG_NET_CORE is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_CADENCE is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_XILINX_EMACLITE=y +CONFIG_SMSC_PHY=y +# CONFIG_WLAN is not set +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_DIAG is not set +# CONFIG_IPV6 is not set +# CONFIG_WIRELESS is not set + +CONFIG_UIO=y +CONFIG_UIO_PDRV_GENIRQ=y +CONFIG_UIO_DMEM_GENIRQ=y + +# CONFIG_LEGACY_PTYS is not set diff --git a/recipes-kernel/linux/files/xilfpga-rtc.cfg b/recipes-kernel/linux/files/xilfpga-rtc.cfg new file mode 100644 index 0000000..94d6a34 --- /dev/null +++ b/recipes-kernel/linux/files/xilfpga-rtc.cfg @@ -0,0 +1,3 @@ + +CONFIG_RTC_LIB=y +# CONFIG_RTC_CLASS is not set diff --git a/recipes-kernel/linux/linux-yocto_4.8.bbappend b/recipes-kernel/linux/linux-yocto_4.8.bbappend index 8bf3a9c..b179b49 100644 --- a/recipes-kernel/linux/linux-yocto_4.8.bbappend +++ b/recipes-kernel/linux/linux-yocto_4.8.bbappend @@ -6,6 +6,15 @@ SRC_URI += "file://modules.cfg \ file://tracepoints.cfg \ " +SRC_URI_append_xilfpga += "\ + file://0001-xilfpga-intc.patch \ + file://0002-xilfpga-ethernet-kconfig.patch \ + file://0003-xilfpga-dts.patch \ + file://xilfpga-cmdline.cfg \ + file://xilfpga-periph.cfg \ + file://xilfpga-rtc.cfg \ + " + # replace these SRCREVs with the real commit ids once you've had # the appropriate changes committed to the upstream linux-yocto repo #SRCREV_machine_pn-linux-yocto ?= "${AUTOREV}" diff --git a/recipes-support/libfdc/files/src/COPYING.txt b/recipes-support/libfdc/files/src/COPYING.txt new file mode 100644 index 0000000..d3875af --- /dev/null +++ b/recipes-support/libfdc/files/src/COPYING.txt @@ -0,0 +1,16 @@ +Copyright 2001, 2002 Georges Menie (www.menie.org) +stdarg version contributed by Christian Ettinger + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \ No newline at end of file diff --git a/recipes-support/libfdc/files/src/Makefile b/recipes-support/libfdc/files/src/Makefile new file mode 100644 index 0000000..9bd8234 --- /dev/null +++ b/recipes-support/libfdc/files/src/Makefile @@ -0,0 +1,33 @@ + +# CC=mips-mti-elf-gcc +# LD=mips-mti-elf-gcc +# OD=mips-mti-elf-objdump +# OC=mips-mti-elf-objcopy +# SZ=mips-mti-elf-size +# AR=mips-mti-elf-ar -cru + +CFLAGS = -Wall -O3 -g -nostdlib -EL -msoft-float -c -march=m14kc + +CSOURCES= \ + fdc_putchar.c \ + fdc_printf.c +COBJECTS=$(CSOURCES:.c=.o) + +.PHONY: all + +all: FDC_LIB # MAIN + +MAIN : + $(CC) -O3 -g -nostdlib -msoft-float -EL -Wl,-Ttext=0xa0000000 main.c start.S fdc_lib.a -o main.elf + +FDC_LIB : $(COBJECTS) + $(AR) -cru libfdc.a fdc_putchar.o fdc_printf.o + +.c.o: + $(CC) $(CFLAGS) $< -o $@ + +clean: + rm -f libfdc.a + rm -f main.elf + rm -f *.o + diff --git a/recipes-support/libfdc/files/src/fdc.h b/recipes-support/libfdc/files/src/fdc.h new file mode 100644 index 0000000..5747c72 --- /dev/null +++ b/recipes-support/libfdc/files/src/fdc.h @@ -0,0 +1,36 @@ +#ifndef FDC_H +#define FDC_H + +typedef int FDC_S32; +typedef unsigned int FDC_U32; +typedef unsigned char FDC_U8; +typedef unsigned short FDC_U16; +typedef signed short FDC_S16; + +enum { + FDC_SUCCESS=0, + FDC_ERR_UNSPECIFIED=-1, + FDC_ERR_INVALID_ARG=-2, + FDC_ERR_CHANNEL_ALREADY_CLAIMED=-3, + FDC_ERR_NO_MIPS_PROBE_ATTACHED=-4, + FDC_ERR_FDC_EMULATION_SYSCALL_NOT_INTERCEPTED=-5, + FDC_ERR_PROCESSOR_HAS_NO_CDMM=-6, + FDC_ERR_CDMM_BASE_ADDR_BAD_ALIGNMENT=-7, + FDC_ERR_CDMM_BASE_ADDR_NOT_ACCESSIBLE_VIA_KSEG1=-8, + FDC_ERR_NO_FDC_HW_FOUND=-9, + FDC_ERR_INVALID_PROCESSOR_NUMBER=-10, + FDC_ERR_INVALID_VPE_NUMBER=-11, +}; + +enum { + false=-1, + true=0 +}; + +int fdc_init(void); +int fdc_printf(const char *format, ...); +int fdc_sprintf(char *out, const char *format, ...); +void fdc_flush (void) __attribute__ ((noinline));; +void fdc_putchar(int c) __attribute__ ((noinline)); + +#endif /*FDC_H*/ diff --git a/recipes-support/libfdc/files/src/fdc_printf.c b/recipes-support/libfdc/files/src/fdc_printf.c new file mode 100644 index 0000000..6db804f --- /dev/null +++ b/recipes-support/libfdc/files/src/fdc_printf.c @@ -0,0 +1,330 @@ +/* + Copyright 2001, 2002 Georges Menie (www.menie.org) + stdarg version contributed by Christian Ettinger + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + putchar (fdc_putchar for now) is the only external dependency for this file, + if you have a working putchar, leave it commented out. If not, uncomment the define below and + replace outbyte(c) by your own function call. + +*/ + +#include +#include "fdc.h" + +void fdc_printchar(char **str, int c) __attribute__ ((noinline)); +void fdc_printchar(char **str, int c) +{ + + if (str) + { + **str = c; + ++(*str); + } + else + fdc_putchar(c); +} + +#define PAD_RIGHT 1 +#define PAD_ZERO 2 +int fdc_prints(char **out, const char *string, int width, int pad) +{ + register int pc = 0, padchar = ' '; + + if (width > 0) + { + register int len = 0; + register const char *ptr; + + for (ptr = string; *ptr; ++ptr) + ++len; + + if (len >= width) + width = 0; + + else + width -= len; + + if (pad & PAD_ZERO) + padchar = '0'; + } + + if (!(pad & PAD_RIGHT)) + { + for ( ; width > 0; --width) + { + fdc_printchar (out, padchar); + ++pc; + } + } + + for ( ; *string ; ++string) + { + fdc_printchar (out, *string); + ++pc; + } + + for ( ; width > 0; --width) + { + fdc_printchar (out, padchar); + ++pc; + } + + return pc; +} + +/* the following should be enough for 32 bit int */ +#define PRINT_BUF_LEN 24 + +int fdc_printi(char **out, int i, int b, int sg, int width, int pad, int letbase) +{ + char print_buf[PRINT_BUF_LEN]; + register char *s; + register int t, neg = 0, pc = 0; + register unsigned int u = i; + + if (i == 0) + { + print_buf[0] = '0'; + print_buf[1] = '\0'; + return fdc_prints (out, print_buf, width, pad); + } + + if (sg && b == 10 && i < 0) + { + neg = 1; + u = -i; + } + + s = print_buf + PRINT_BUF_LEN-1; + *s = '\0'; + + while (u) + { + t = u % b; + if( t >= 10 ) + t += letbase - '0' - 10; + *--s = t + '0'; + u /= b; + } + + if (neg) + { + if( width && (pad & PAD_ZERO) ) + { + fdc_printchar (out, '-'); + ++pc; + --width; + } + else + { + *--s = '-'; + } + } + + return pc + fdc_prints (out, s, width, pad); +} + +int fdc_print(char **out, const char *format, va_list args ) +{ + register int width, pad; + register int pc = 0; + char scr[2]; + + int i = 0; + + for (; *format != 0; ++format) + { + i++; + + if (*format == '%') + { + ++format; + width = pad = 0; + + if (*format == '\0') + break; + + if (*format == '%') + goto out; + + + if (*format == '-') + { + ++format; + pad = PAD_RIGHT; + } + + while (*format == '0') + { + ++format; + pad |= PAD_ZERO; + } + + for ( ; *format >= '0' && *format <= '9'; ++format) + { + width *= 10; + width += *format - '0'; + } + + if( *format == 's' ) + { + register char *s = (char *)va_arg( args, int ); + pc += fdc_prints (out, s?s:"(null)", width, pad); + continue; + } + + if( *format == 'd' ) + { + pc += fdc_printi (out, va_arg( args, int ), 10, 1, width, pad, 'a'); + continue; + } + + if( *format == 'x' ) + { + pc += fdc_printi (out, va_arg( args, int ), 16, 0, width, pad, 'a'); + continue; + } + + if( *format == 'X' ) + { + pc += fdc_printi (out, va_arg( args, int ), 16, 0, width, pad, 'A'); + continue; + } + + if( *format == 'u' ) + { + pc += fdc_printi (out, va_arg( args, int ), 10, 0, width, pad, 'a'); + continue; + } + + if( *format == 'c' ) + { + /* char are converted to int then pushed on the stack */ + scr[0] = (char)va_arg( args, int ); + scr[1] = '\0'; + pc += fdc_prints (out, scr, width, pad); + continue; + } + } + else + { + out: + fdc_printchar (out, *format); + ++pc; + } + } + + if (out) + **out = '\0'; + + va_end( args ); + return pc; +} + +int fdc_printf(const char *format, ...) +{ + va_list args; + int status; + va_start( args, format ); + + status = fdc_print( 0, format, args ); + + /* Flush the buffer */ + fdc_printchar (0, '\0'); + return status; +} +void fdc_flush (void) +{ + fdc_printchar (0, '\0'); +} + +int fdc_sprintf(char *out, const char *format, ...) +{ + va_list args; + + va_start( args, format ); + return fdc_print( &out, format, args ); +} + +#ifdef TEST_PRINTF +int main(void) +{ + char *ptr = "Hello world!"; + char *np = 0; + int i = 5; + unsigned int bs = sizeof(int)*8; + int mi; + char buf[80]; + + mi = (1 << (bs-1)) + 1; + printf("%s\n", ptr); + printf("printf test\n"); + printf("%s is null pointer\n", np); + printf("%d = 5\n", i); + printf("%d = - max int\n", mi); + printf("char %c = 'a'\n", 'a'); + printf("hex %x = ff\n", 0xff); + printf("hex %02x = 00\n", 0); + printf("signed %d = unsigned %u = hex %x\n", -3, -3, -3); + printf("%d %s(s)%", 0, "message"); + printf("\n"); + printf("%d %s(s) with %%\n", 0, "message"); + sprintf(buf, "justif: \"%-10s\"\n", "left"); printf("%s", buf); + sprintf(buf, "justif: \"%10s\"\n", "right"); printf("%s", buf); + sprintf(buf, " 3: %04d zero padded\n", 3); printf("%s", buf); + sprintf(buf, " 3: %-4d left justif.\n", 3); printf("%s", buf); + sprintf(buf, " 3: %4d right justif.\n", 3); printf("%s", buf); + sprintf(buf, "-3: %04d zero padded\n", -3); printf("%s", buf); + sprintf(buf, "-3: %-4d left justif.\n", -3); printf("%s", buf); + sprintf(buf, "-3: %4d right justif.\n", -3); printf("%s", buf); + + return 0; +} + +/* + * if you compile this file with + * gcc -Wall $(YOUR_C_OPTIONS) -DTEST_PRINTF -c printf.c + * you will get a normal warning: + * printf.c:214: warning: spurious trailing `%' in format + * this line is testing an invalid % at the end of the format string. + * + * this should display (on 32bit int machine) : + * + * Hello world! + * printf test + * (null) is null pointer + * 5 = 5 + * -2147483647 = - max int + * char a = 'a' + * hex ff = ff + * hex 00 = 00 + * signed -3 = unsigned 4294967293 = hex fffffffd + * 0 message(s) + * 0 message(s) with % + * justif: "left " + * justif: " right" + * 3: 0003 zero padded + * 3: 3 left justif. + * 3: 3 right justif. + * -3: -003 zero padded + * -3: -3 left justif. + * -3: -3 right justif. + */ + +#endif diff --git a/recipes-support/libfdc/files/src/fdc_putchar.c b/recipes-support/libfdc/files/src/fdc_putchar.c new file mode 100644 index 0000000..96bab9c --- /dev/null +++ b/recipes-support/libfdc/files/src/fdc_putchar.c @@ -0,0 +1,171 @@ +#include "fdc.h" +#include "fdc_putchar.h" + +static unsigned long fdcBaseAddr; +static int cdmm_was_mapped = 0; +static FDC_U32 gCDMMBase; +static int fdc_char_count = 0; + +void fdc_putchar(int c) __attribute__ ((noinline)); + + +/******************************************************************************************** + * * + * fdc_hw_find_base_addr - is used to locate the base address of the FDC memory mapped * + * registers. The FDC memory-mapped registers are located in the common device memory * + * map (CDMM) region. FDC has a device ID of 0xFD. If FDC not found return * + * FDC_ERR_NO_FDC_HW_FOUND otherwise return FDC_SUCCESS. * + * * + ********************************************************************************************/ +int fdc_hw_find_base_addr(unsigned long *fdcBaseAddr) { + int result; + int found = 0; + FDC_U32 CDMMBase; + FDC_U32 CDMMBaseAddr; + FDC_U32 numdrbs; + CDMM_DEVICE_RESOURCE_BLOCK *drb_begin; + CDMM_DEVICE_RESOURCE_BLOCK *drb_end; + CDMM_DEVICE_RESOURCE_BLOCK *drb_cur; + + CDMMBase = gCDMMBase; + CDMMBaseAddr = (CDMMBase >> 11) << 15; + numdrbs = (CDMMBase & 0x1FF); + drb_begin = (CDMM_DEVICE_RESOURCE_BLOCK*)CDMMBaseAddr; + drb_end = drb_begin + numdrbs; + + drb_cur = ((CDMMBase & (1 << 9)) == 0) ? drb_begin : drb_begin+1; + while (drb_cur < drb_end) { + FDC_U32 acsr = drb_cur->primary.acsr; + FDC_U32 extradrbs; + + if (CDMM_DEV_TYPE(acsr) == 0xFD) { + found = 1; + break; + } + extradrbs = CDMM_DEV_SIZE(acsr); + drb_cur += extradrbs; + } + if (found) { + *fdcBaseAddr = (unsigned long) drb_cur; + result = FDC_SUCCESS; + } else { + result = FDC_ERR_NO_FDC_HW_FOUND; + } + + return result; +} // end of fdc_hw_find_base_addr + +/******************************************************************************************** + * * + * fdc_init is called to emable the Common Device Memory Map and save global pointer to * + * CDMM. * + * * + * * + ********************************************************************************************/ +int fdc_init(void) { + int result = FDC_SUCCESS; + FDC_U32 CDMMOverlayPhysicalAddr = 0x1fc10000; + + if (!IS_PHYSICAL_ADDRESS_ADDRESSABLE_VIA_KSEG1(CDMMOverlayPhysicalAddr)) + result = FDC_ERR_CDMM_BASE_ADDR_NOT_ACCESSIBLE_VIA_KSEG1; + + if (result == FDC_SUCCESS) { + if ((CDMMOverlayPhysicalAddr & ((1 << 15)-1)) != 0) { + result = FDC_ERR_CDMM_BASE_ADDR_BAD_ALIGNMENT; + } + } + + if (result == FDC_SUCCESS) { + + FDC_U32 kseg1Addr = MAKE_KSEG1_ADDR(CDMMOverlayPhysicalAddr); + FDC_U32 config3 = ReadConfig3(); + + if ((config3 & 0x8) != 0) { + + FDC_U32 CDMMBase = ReadCDMMBase(); + + /* Is Memory-Mapped I/O enabled */ + if (((CDMMBase & 0x400) >> 10) != 1) + { + // set address + cdmm_was_mapped = (CDMMBase & (1 << 10)) != 0; + + // enable + CDMMBase |= (1 << 10); + WriteCDMMBase(CDMMBase); + CDMMBase |= ((kseg1Addr >> 15) << 11); + } + + gCDMMBase = CDMMBase; + + } else { + result = FDC_ERR_PROCESSOR_HAS_NO_CDMM; + } + + } + + fdc_hw_find_base_addr(&fdcBaseAddr); + fdc_char_count = 0; + return result; +} // end of fdc_init + +//******************************************************************************************** +// fdc_putchar +// +// Function writes a character to the next most significant byte of a 4 byte char buffer. +// Once buffer has 4 characters, checks for FIFO not full. If it is not, it writes the word +// to channel 0 of FDC transmit port. +// If the FDC FIFO is full then it polls waiting for it to be not full. While polling, it +// counts up and if the count exceeds a constant, it sets static variable "timeout" which +// means the openOCD host is not polling for characters. From then on if the function is called +// it is immediately bypassed so as not to waste time with each call. The program has +// to be restarted to reset the timeout variable. +// +// Future enhancement could add a control channel to pass info like semi-hosting enable/disable. * +// +// FDC Channel Zero only with Polling. Interrupts not support at this time. +// +//********************************************************************************************/ +#define FDC_PUTCHAR_TIMEOUT 1000000 //max spin count waiting to write to FIFO + +static volatile int timeout = 0; //initialize to no timeout +static volatile unsigned int fdc_buff; +static volatile unsigned int waitcount = 0; //accumulated count waiting for FIFO to be not full, for analysis of performance purposes + +void fdc_putchar(int c) +{ + volatile FDC_REGS *fdc = (FDC_REGS *)fdcBaseAddr; + volatile unsigned long i; + + if (timeout == 1) + return; // once a timeout occurs, bypass the function to reduce the overhead of calling this + // function when the host-side semihosting is not enabled + // Insert Char. in buffer + fdc_buff = (fdc_buff >> 8) | (c << 24); + + // if char is null, this means flush out any remaining characters by shifting them right + if (c == '\0') { + if (fdc_char_count == 0) + return; // no char's accumulated, return + while (fdc_char_count < 3) { + fdc_buff >>= 8; + fdc_char_count++; + } + } else { + fdc_char_count++; // non-null character, increment count + } + if ((fdc_char_count > 3) || (c == '\0')) { // write buffer to FDC outgoing FIFO + i = 0; + while (((fdc->fdstat) & 0x1) == 1) { // If Tx FIFO full, wait for not full or set timeout + i++; + waitcount++; + if (i >= FDC_PUTCHAR_TIMEOUT) { + timeout = 1; // set timeout so this function is bypassed from now on, or until user program is restarted + return; + } + } + fdc->fdtx = fdc_buff; // output word to FDC FIFO + fdc_buff = 0; + fdc_char_count = 0; + } +} // end of fdc_putchar() diff --git a/recipes-support/libfdc/files/src/fdc_putchar.h b/recipes-support/libfdc/files/src/fdc_putchar.h new file mode 100644 index 0000000..25062e7 --- /dev/null +++ b/recipes-support/libfdc/files/src/fdc_putchar.h @@ -0,0 +1,106 @@ +#ifndef FDC_PUTCHAR_H +#define FDC_PUTCHAR_H + +#define MHZ 50 /* Digilent 4 DDR CPU clock. */ + + +enum { + SEMI_HOSTING_DISABLED = 0, + SEMI_HOSTING_ENABLED = 1 +}; + +typedef struct { + unsigned long fdacsr; + unsigned long reserved_0; + unsigned long fdcfg; + unsigned long reserved_1; + unsigned long fdstat; + unsigned long reserved_2; + unsigned long fdrx; + unsigned long reserved_3; + unsigned long fdtx; +} FDC_REGS; + + +#define BYTES_PER_CDMM_DEVICE_RESOURCE_BLOCK 64 +#define IS_PHYSICAL_ADDRESS_ADDRESSABLE_VIA_KSEG1(addr) (((addr) & 0xE0000000) == 0) +#define MAKE_KSEG1_ADDR(addr) (((addr) & 0x1FFFFFFF)|0xA0000000) + +/******************************************************************************************** + * * + * Software on the core accesses FDC through memory mapped registers. These memory mapped * + * registers are located within the Common Device Memory Map (CDMM). The CDMM is a region * + * of physical address space that is reserved for mapping IO device configuration registers * + * within a MIPS processor. The base address and enabling of this region is controlled by * + * the CDMMBase CP0 register. * + * * + ********************************************************************************************/ +typedef union { + struct { + FDC_U32 acsr; + unsigned char data[BYTES_PER_CDMM_DEVICE_RESOURCE_BLOCK-sizeof(FDC_U32)]; + } primary; + struct { + unsigned char data[BYTES_PER_CDMM_DEVICE_RESOURCE_BLOCK]; + } secondary; +} CDMM_DEVICE_RESOURCE_BLOCK; + +#define CDMM_DEV_TYPE(acsr) ((FDC_U32)(((acsr) >> 24) & 0xFF)) +#define CDMM_DEV_SIZE(acsr) ((FDC_U32)(((acsr) >> 16) & 0x3F)) + +/******************************************************************************************** + * * + * Read Config3 register * + * * + ********************************************************************************************/ +FDC_U32 ReadConfig3(void) { + FDC_U32 val; + __asm("mfc0 %0, $16, 3" : "=r"(val)); + return val; +} + +/******************************************************************************************** + * * + * Read Common Device Memory Map Base register * + * * + ********************************************************************************************/ +static FDC_U32 ReadCDMMBase(void) { + FDC_U32 val; + __asm("mfc0 %0, $15, 2" : "=r"(val)); + return val; +} + +/******************************************************************************************** + * * + * Write Common Device Memory Map Base register * + * * + ********************************************************************************************/ +void WriteCDMMBase(FDC_U32 val) { + __asm("mtc0 %0, $15, 2" : : "r"(val)); + +} + +/******************************************************************************************** + * * + * Read Cause register * + * * + ********************************************************************************************/ +FDC_U32 ReadCause(void) { + FDC_U32 val; + __asm("mfc0 %0, $13, 0" : "=r"(val)); + return val; +} + +/******************************************************************************************** + * * + * Read Count register * + * * + ********************************************************************************************/ +volatile FDC_U32 ReadCount(void) { + FDC_U32 val; + __asm("mfc0 %0, $9, 1" : "=r"(val)); + return val; +} + +#endif /*FDC_PUTCHAR_H*/ + diff --git a/recipes-support/libfdc/libfdc.bb b/recipes-support/libfdc/libfdc.bb new file mode 100644 index 0000000..c0c718c --- /dev/null +++ b/recipes-support/libfdc/libfdc.bb @@ -0,0 +1,33 @@ +# License has been inferred from the fdc_printf.c (where it is stated) +# and copied to a new file +DESCRIPTION = "LibFDC" +LICENSE = "LGPLv2" +LIC_FILES_CHKSUM = "file://COPYING.txt;md5=f0e843e4a839940d9cf8a32529fe357f" + +# Use './files/src' directory for now. No SCM'd version of this library could be found +# online, so it is included with the recipe here with its file that had the license. +SRC_URI = "file://src" + +# Set source directory for the make as 'src' +S = "${WORKDIR}/src" + +# Based on the source, it directly refers to only the Nexys4 DDR configuration +COMPATIBLE_MACHINE = "xilfpga" + +# No reason to run configure +do_configure[noexec] = "1" + +# Run the standard make +do_compile() { + oe_runmake +} + +# Place the files in the typical locations, the packager will +# automatically pick them up rather than our explicitly defining FILES... +do_install() { + install -d ${D}${includedir} + install -m 0644 fdc.h ${D}${includedir} + + install -d ${D}${libdir} + install -m 0644 libfdc.a ${D}${libdir} +}