diff --git a/blinky/Makefile b/blinky/Makefile new file mode 100644 index 0000000..b1ef11b --- /dev/null +++ b/blinky/Makefile @@ -0,0 +1,28 @@ +ARCH = $(shell uname -m) +ifneq ("$(ARCH)", "ppc64") +ifneq ("$(ARCH)", "ppc64le") + CROSS_COMPILE ?= powerpc64le-linux- + endif + endif + +CC = $(CROSS_COMPILE)gcc +LD = $(CROSS_COMPILE)ld +OBJCOPY = $(CROSS_COMPILE)objcopy + +CFLAGS = -Os -g -Wall -std=c99 -msoft-float -mno-string -mno-multiple -mno-vsx -mno-altivec -mlittle-endian -fno-stack-protector -mstrict-align -ffreestanding -fdata-sections -ffunction-sections +ASFLAGS = $(CFLAGS) +LDFLAGS = -T powerpc.lds + +all: blinky.hex + +blinky.elf: blinky.o head.o + $(LD) $(LDFLAGS) -o blinky.elf blinky.o head.o + +blinky.bin: blinky.elf + $(OBJCOPY) -O binary blinky.elf blinky.bin + +blinky.hex: blinky.bin + ./bin2hex.py blinky.bin > blinky.hex + +clean: + @rm -f *.o blinky.elf blinky.bin blinky.hex diff --git a/blinky/bin2hex.py b/blinky/bin2hex.py new file mode 100755 index 0000000..af278bc --- /dev/null +++ b/blinky/bin2hex.py @@ -0,0 +1,17 @@ +#!/usr/bin/python3 + +import sys +import subprocess +import struct + +with open(sys.argv[1], "rb") as f: + while True: + word = f.read(8) + if len(word) == 8: + print("%016x" % struct.unpack('Q', word)); + elif len(word) == 4: + print("00000000%08x" % struct.unpack('I', word)); + elif len(word) == 0: + exit(0); + else: + raise Exception("Bad length") diff --git a/blinky/blinky.c b/blinky/blinky.c new file mode 100644 index 0000000..2a33c78 --- /dev/null +++ b/blinky/blinky.c @@ -0,0 +1,93 @@ +#include +#include + +#define GPIO0_BASE 0xc1000000ull + +#define GPIO_PORT_INCREMENT 0x100 +#define GPIO_IN 0x08 +#define GPIO_OUT 0x10 +#define GPIO_SET 0x18 +#define GPIO_CLEAR 0x20 +#define GPIO_TYPE_0 0x28 +#define GPIO_TYPE_1 0x30 +#define GPIO_TYPE_2 0x38 +#define GPIO_TYPE_3 0x40 + +enum gpio_type { + GPIO_TYPE_INPUT = 0x00, + GPIO_TYPE_INT_LEVEL_LOW = 0x02, + GPIO_TYPE_INT_LEVEL_HIGH = 0x03, + GPIO_TYPE_INT_EDGE_FALL = 0x04, + GPIO_TYPE_INT_EDGE_RISE = 0x05, + GPIO_TYPE_OUTPUT = 0x07, +}; + +/** + * Set the type of GPIO + * @param port the GPIO port + * @param pin the pin within the port + * @param type the type + */ +static void gpio_set_type(uint8_t port, uint8_t pin, enum gpio_type type) +{ + uint64_t val; + uint64_t addr = GPIO0_BASE + port * GPIO_PORT_INCREMENT; + + /* Advance to the type register for the pin, pin is left as the pin + * pin offset within the register + */ + if (pin < 16) { + addr += GPIO_TYPE_0; + } else if (pin < 32) { + addr += GPIO_TYPE_1; + pin -= 16; + } else if (pin < 48) { + addr += GPIO_TYPE_2; + pin -= 32; + } else { + addr += GPIO_TYPE_3; + pin -= 48; + } + + val = *(volatile uint64_t *)addr; // Fetch the current set of types + val &= ~(0x7 << (pin * 4)); // Mask out the old value + val |= type << (pin * 4); // add in the new type + *(volatile uint64_t *)addr = val; // write it back +} + +/** + * Toggle a GPIO + * @param port the GPIO port + * @param pin the pin within the port + * @param val the value to output + */ +static void gpio_toggle(uint8_t port, uint8_t pin) +{ + /* Writing to GPIO_IN toggles the pin. This allows us to save a + * read/modify/write operation to output GPIO. + */ + uint64_t addr = GPIO0_BASE + port * GPIO_PORT_INCREMENT + GPIO_IN; + + *(volatile uint64_t *)addr = 1ul << pin; +} + +/** + * Burn some CPU cycles + */ +static void busyloop(void) +{ + // volatile to force a memory access on each iteration + uint64_t volatile count = 50000000; + while (count--) {} +} + + +int main(void) +{ + gpio_set_type(0, 0, GPIO_TYPE_OUTPUT); + + while (1) { + gpio_toggle(0, 0); + busyloop(); + } +} diff --git a/blinky/head.S b/blinky/head.S new file mode 100644 index 0000000..af861f4 --- /dev/null +++ b/blinky/head.S @@ -0,0 +1,95 @@ +/* Copyright 2013-2014 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define STACK_TOP 0x3000 + +#define FIXUP_ENDIAN \ + tdi 0,0,0x48; /* Reverse endian of b . + 8 */ \ + b 191f; /* Skip trampoline if endian is good */ \ + .long 0xa600607d; /* mfmsr r11 */ \ + .long 0x01006b69; /* xori r11,r11,1 */ \ + .long 0x05009f42; /* bcl 20,31,$+4 */ \ + .long 0xa602487d; /* mflr r10 */ \ + .long 0x14004a39; /* addi r10,r10,20 */ \ + .long 0xa64b5a7d; /* mthsrr0 r10 */ \ + .long 0xa64b7b7d; /* mthsrr1 r11 */ \ + .long 0x2402004c; /* hrfid */ \ +191: + + +/* Load an immediate 64-bit value into a register */ +#define LOAD_IMM64(r, e) \ + lis r,(e)@highest; \ + ori r,r,(e)@higher; \ + rldicr r,r, 32, 31; \ + oris r,r, (e)@h; \ + ori r,r, (e)@l; + + .section ".head","ax" + + . = 0 +.global _start +_start: + FIXUP_ENDIAN + b boot_entry + +.global boot_entry +boot_entry: + /* setup stack */ + LOAD_IMM64(%r1, STACK_TOP - 0x100) + LOAD_IMM64(%r12, main) + mtctr %r12, + bctrl + b . + +#define EXCEPTION(nr) \ + .= nr ;\ + b . + + /* More exception stubs */ + EXCEPTION(0x300) + EXCEPTION(0x380) + EXCEPTION(0x400) + EXCEPTION(0x480) + EXCEPTION(0x500) + EXCEPTION(0x600) + EXCEPTION(0x700) + EXCEPTION(0x800) + EXCEPTION(0x900) + EXCEPTION(0x980) + EXCEPTION(0xa00) + EXCEPTION(0xb00) + EXCEPTION(0xc00) + EXCEPTION(0xd00) + EXCEPTION(0xe00) + EXCEPTION(0xe20) + EXCEPTION(0xe40) + EXCEPTION(0xe60) + EXCEPTION(0xe80) + EXCEPTION(0xf00) + EXCEPTION(0xf20) + EXCEPTION(0xf40) + EXCEPTION(0xf60) + EXCEPTION(0xf80) +#if 0 + EXCEPTION(0x1000) + EXCEPTION(0x1100) + EXCEPTION(0x1200) + EXCEPTION(0x1300) + EXCEPTION(0x1400) + EXCEPTION(0x1500) + EXCEPTION(0x1600) +#endif diff --git a/blinky/powerpc.lds b/blinky/powerpc.lds new file mode 100644 index 0000000..0b65470 --- /dev/null +++ b/blinky/powerpc.lds @@ -0,0 +1,13 @@ +SECTIONS +{ + _start = .; + . = 0; + .head : { + KEEP(*(.head)) + } + . = 0x1000; + .text : { *(.text) } + . = 0x2000; + .data : { *(.data) } + .bss : { *(.bss) } +}