commit 23616a1c4b87679eb7809c2b63752b1160ced165 Author: Your Name Date: Wed Nov 28 10:52:27 2018 -0500 initial commit Signed-off-by: Your Name diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a097b40 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.obj +*.swp +*.swo +bbflash diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8bc5f85 --- /dev/null +++ b/Makefile @@ -0,0 +1,87 @@ +PACKAGE = $(notdir $(realpath .)) +ADD_CFLAGS = +ADD_LFLAGS = + +GIT_VERSION= $(shell git describe --tags) +#TRGT ?= arm-none-eabi- +CC = $(TRGT)gcc +CXX = $(TRGT)g++ +OBJCOPY = $(TRGT)objcopy + +RM = rm -rf +COPY = cp -a +PATH_SEP = / + +ifeq ($(OS),Windows_NT) +COPY = copy +RM = del +PATH_SEP = \\ +endif + +DBG_CFLAGS = -ggdb -g -DDEBUG -Wall +DBG_LFLAGS = -ggdb -g -Wall +CFLAGS = $(ADD_CFLAGS) \ + -Wall -Wextra \ + -ffunction-sections -fdata-sections -fno-common \ + -fomit-frame-pointer -Os \ + -DGIT_VERSION=u\"$(GIT_VERSION)\" -std=gnu11 +CXXFLAGS = $(CFLAGS) -std=c++11 +LFLAGS = $(ADD_LFLAGS) $(CFLAGS) \ + +OBJ_DIR = .obj + +CSOURCES = $(wildcard *.c) +CPPSOURCES = $(wildcard *.cpp) +ASOURCES = $(wildcard *.S) +COBJS = $(addprefix $(OBJ_DIR)/, $(notdir $(CSOURCES:.c=.o))) +CXXOBJS = $(addprefix $(OBJ_DIR)/, $(notdir $(CPPSOURCES:.cpp=.o))) +AOBJS = $(addprefix $(OBJ_DIR)/, $(notdir $(ASOURCES:.S=.o))) +OBJECTS = $(COBJS) $(CXXOBJS) $(AOBJS) +VPATH = . + +QUIET = @ + +ALL = all +TARGET = $(PACKAGE) +CLEAN = clean + +$(ALL): $(TARGET) + +$(OBJECTS): | $(OBJ_DIR) + +$(TARGET): $(OBJECTS) + $(QUIET) echo " LD $@" + $(QUIET) $(CXX) $(OBJECTS) $(LFLAGS) -o $@ + +$(DEBUG): CFLAGS += $(DBG_CFLAGS) +$(DEBUG): LFLAGS += $(DBG_LFLAGS) +CFLAGS += $(DBG_CFLAGS) +LFLAGS += $(DBG_LFLAGS) +$(DEBUG): $(TARGET) + +$(OBJ_DIR): + $(QUIET) mkdir $(OBJ_DIR) + +$(COBJS) : $(OBJ_DIR)/%.o : %.c Makefile + $(QUIET) echo " CC $< $(notdir $@)" + $(QUIET) $(CC) -c $< $(CFLAGS) -o $@ -MMD + +$(OBJ_DIR)/%.o: %.cpp + $(QUIET) echo " CXX $< $(notdir $@)" + $(QUIET) $(CXX) -c $< $(CXXFLAGS) -o $@ -MMD + +$(OBJ_DIR)/%.o: %.S + $(QUIET) echo " AS $< $(notdir $@)" + $(QUIET) $(CC) -x assembler-with-cpp -c $< $(CFLAGS) -o $@ -MMD + +.PHONY: clean + +clean: + $(QUIET) echo " RM $(subst /,$(PATH_SEP),$(wildcard $(OBJ_DIR)/*.d))" + -$(QUIET) $(RM) $(subst /,$(PATH_SEP),$(wildcard $(OBJ_DIR)/*.d)) + $(QUIET) echo " RM $(subst /,$(PATH_SEP),$(wildcard $(OBJ_DIR)/*.d))" + -$(QUIET) $(RM) $(subst /,$(PATH_SEP),$(wildcard $(OBJ_DIR)/*.o)) + $(QUIET) echo " RM $(TARGET)" + -$(QUIET) $(RM) $(TARGET) + +include $(wildcard $(OBJ_DIR)/*.d) diff --git a/bbflash.c b/bbflash.c new file mode 100644 index 0000000..5ed6dfb --- /dev/null +++ b/bbflash.c @@ -0,0 +1,729 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "rpi.h" + +#define S_MOSI 10 +#define S_MISO 9 +#define S_CLK 11 +#define S_CE0 8 +#define S_HOLD 25 +#define S_WP 24 +#define S_D0 S_MOSI +#define S_D1 S_MISO +#define S_D2 S_WP +#define S_D3 S_HOLD +#define F_RESET 27 +#define F_DONE 17 + +enum spi_state { + SS_UNCONFIGURED = 0, + SS_SINGLE, + SS_DUAL_RX, + SS_DUAL_TX, + SS_QUAD_RX, + SS_QUAD_TX, + SS_HARDWARE, +}; + +enum spi_type { + ST_UNCONFIGURED, + ST_SINGLE, + ST_DUAL, + ST_QUAD, + ST_QPI, +}; + +struct bb_spi { + enum spi_state state; + enum spi_type type; + int qpi; +}; + +static void spi_set_state(struct bb_spi *spi, enum spi_state state) { + if (spi->state == state) + return; + + switch (state) { + case SS_SINGLE: + gpioSetMode(S_CLK, PI_OUTPUT); // CLK + gpioSetMode(S_CE0, PI_OUTPUT); // CE0# + gpioSetMode(S_MOSI, PI_OUTPUT); // MOSI + gpioSetMode(S_MISO, PI_INPUT); // MISO + gpioSetMode(S_HOLD, PI_OUTPUT); + gpioSetMode(S_WP, PI_OUTPUT); + break; + + case SS_DUAL_RX: + gpioSetMode(S_CLK, PI_OUTPUT); // CLK + gpioSetMode(S_CE0, PI_OUTPUT); // CE0# + gpioSetMode(S_MOSI, PI_INPUT); // MOSI + gpioSetMode(S_MISO, PI_INPUT); // MISO + gpioSetMode(S_HOLD, PI_OUTPUT); + gpioSetMode(S_WP, PI_OUTPUT); + break; + + case SS_DUAL_TX: + gpioSetMode(S_CLK, PI_OUTPUT); // CLK + gpioSetMode(S_CE0, PI_OUTPUT); // CE0# + gpioSetMode(S_MOSI, PI_OUTPUT); // MOSI + gpioSetMode(S_MISO, PI_OUTPUT); // MISO + gpioSetMode(S_HOLD, PI_OUTPUT); + gpioSetMode(S_WP, PI_OUTPUT); + break; + + case SS_QUAD_RX: + gpioSetMode(S_CLK, PI_OUTPUT); // CLK + gpioSetMode(S_CE0, PI_OUTPUT); // CE0# + gpioSetMode(S_MOSI, PI_INPUT); // MOSI + gpioSetMode(S_MISO, PI_INPUT); // MISO + gpioSetMode(S_HOLD, PI_INPUT); + gpioSetMode(S_WP, PI_INPUT); + break; + + case SS_QUAD_TX: + gpioSetMode(S_CLK, PI_OUTPUT); // CLK + gpioSetMode(S_CE0, PI_OUTPUT); // CE0# + gpioSetMode(S_MOSI, PI_OUTPUT); // MOSI + gpioSetMode(S_MISO, PI_OUTPUT); // MISO + gpioSetMode(S_HOLD, PI_OUTPUT); + gpioSetMode(S_WP, PI_OUTPUT); + break; + + case SS_HARDWARE: + gpioSetMode(S_CLK, PI_ALT0); // CLK + gpioSetMode(S_CE0, PI_ALT0); // CE0# + gpioSetMode(S_MOSI, PI_ALT0); // MOSI + gpioSetMode(S_MISO, PI_ALT0); // MISO + gpioSetMode(S_HOLD, PI_OUTPUT); + gpioSetMode(S_WP, PI_OUTPUT); + break; + + default: + fprintf(stderr, "Unrecognized spi state\n"); + return; + } + + spi->state = state; +} + +static void spi_pause(void) { +// usleep(1); + return; +} + +static void spiBegin(struct bb_spi *spi) { + spi_set_state(spi, SS_SINGLE); + gpioWrite(S_CE0, 0); +} + +static void spiEnd(struct bb_spi *spi) { + (void)spi; + gpioWrite(S_CE0, 1); +} + +static uint8_t spiXfer(struct bb_spi *spi, uint8_t out) { + int bit; + uint8_t in = 0; + for (bit = 7; bit >= 0; bit--) { + if (out & (1 << bit)) { + gpioWrite(S_MOSI, 1); + } + else { + gpioWrite(S_MOSI, 0); + } + gpioWrite(S_CLK, 1); + spi_pause(); + in |= ((!!gpioRead(S_MISO)) << bit); + gpioWrite(S_CLK, 0); + spi_pause(); + } + return in; +} + +static void spiSingleTx(struct bb_spi *spi, uint8_t out) { + spi_set_state(spi, SS_SINGLE); + spiXfer(spi, out); +} + +static uint8_t spiSingleRx(struct bb_spi *spi) { + spi_set_state(spi, SS_SINGLE); + return spiXfer(spi, 0xff); +} + +static void spiDualTx(struct bb_spi *spi, uint8_t out) { + int bit; + spi_set_state(spi, SS_DUAL_TX); + for (bit = 7; bit >= 0; bit -= 2) { + if (out & (1 << (bit - 1))) { + gpioWrite(S_D0, 1); + } + else { + gpioWrite(S_D0, 0); + } + + if (out & (1 << (bit - 0))) { + gpioWrite(S_D1, 1); + } + else { + gpioWrite(S_D1, 0); + } + gpioWrite(S_CLK, 1); + spi_pause(); + gpioWrite(S_CLK, 0); + spi_pause(); + } +} + +static void spiQuadTx(struct bb_spi *spi, uint8_t out) { + int bit; + spi_set_state(spi, SS_QUAD_TX); + for (bit = 7; bit >= 0; bit -= 4) { + if (out & (1 << (bit - 3))) { + gpioWrite(S_D0, 1); + } + else { + gpioWrite(S_D0, 0); + } + + if (out & (1 << (bit - 2))) { + gpioWrite(S_D1, 1); + } + else { + gpioWrite(S_D1, 0); + } + + if (out & (1 << (bit - 1))) { + gpioWrite(S_D2, 1); + } + else { + gpioWrite(S_D2, 0); + } + + if (out & (1 << (bit - 0))) { + gpioWrite(S_D3, 1); + } + else { + gpioWrite(S_D3, 0); + } + gpioWrite(S_CLK, 1); + spi_pause(); + gpioWrite(S_CLK, 0); + spi_pause(); + } +} + +void spiCommand(struct bb_spi *spi, uint8_t cmd) { + if (spi->qpi) + spiQuadTx(spi, cmd); + else + spiSingleTx(spi, cmd); +} + +static uint8_t spiDualRx(struct bb_spi *spi) { + int bit; + uint8_t in = 0; + + spi_set_state(spi, SS_QUAD_RX); + for (bit = 7; bit >= 0; bit -= 2) { + gpioWrite(S_CLK, 1); + spi_pause(); + in |= ((!!gpioRead(S_D0)) << (bit - 1)); + in |= ((!!gpioRead(S_D1)) << (bit - 0)); + gpioWrite(S_CLK, 0); + spi_pause(); + } + return in; +} + +static uint8_t spiQuadRx(struct bb_spi *spi) { + int bit; + uint8_t in = 0; + + spi_set_state(spi, SS_QUAD_RX); + for (bit = 7; bit >= 0; bit -= 4) { + gpioWrite(S_CLK, 1); + spi_pause(); + in |= ((!!gpioRead(S_D0)) << (bit - 3)); + in |= ((!!gpioRead(S_D1)) << (bit - 2)); + in |= ((!!gpioRead(S_D2)) << (bit - 1)); + in |= ((!!gpioRead(S_D3)) << (bit - 0)); + gpioWrite(S_CLK, 0); + spi_pause(); + } + return in; +} + +int spiTx(struct bb_spi *spi, uint8_t word) { + switch (spi->type) { + case ST_SINGLE: + spiSingleTx(spi, word); + break; + case ST_DUAL: + spiDualTx(spi, word); + break; + case ST_QUAD: + case ST_QPI: + spiQuadTx(spi, word); + break; + default: + return -1; + } + return 0; +} + +uint8_t spiRx(struct bb_spi *spi) { + switch (spi->type) { + case ST_SINGLE: + return spiSingleRx(spi); + case ST_DUAL: + return spiDualRx(spi); + case ST_QUAD: + case ST_QPI: + return spiQuadRx(spi); + default: + return 0xff; + } +} + +uint8_t spiReadSr(struct bb_spi *spi, int sr) { + uint8_t val = 0xff; + + switch (sr) { + case 1: + spiBegin(spi); + spiCommand(spi, 0x05); + val = spiRx(spi); + spiEnd(spi); + break; + + case 2: + spiBegin(spi); + spiCommand(spi, 0x35); + val = spiRx(spi); + spiEnd(spi); + break; + + case 3: + spiBegin(spi); + spiCommand(spi, 0x15); + val = spiRx(spi); + spiEnd(spi); + break; + + default: + fprintf(stderr, "unrecognized status register: %d\n", sr); + break; + } + + return val; +} + +void spiWriteSr(struct bb_spi *spi, int sr, uint8_t val) { + switch (sr) { + case 1: + spiBegin(spi); + spiCommand(spi, 0x50); + spiEnd(spi); + + spiBegin(spi); + spiCommand(spi, 0x01); + spiCommand(spi, val); + spiEnd(spi); + break; + + case 2: + spiBegin(spi); + spiCommand(spi, 0x50); + spiEnd(spi); + + spiBegin(spi); + spiCommand(spi, 0x31); + spiCommand(spi, val); + spiEnd(spi); + break; + + case 3: + spiBegin(spi); + spiCommand(spi, 0x50); + spiEnd(spi); + + spiBegin(spi); + spiCommand(spi, 0x11); + spiCommand(spi, val); + spiEnd(spi); + break; + + default: + fprintf(stderr, "unrecognized status register: %d\n", sr); + break; + } +} + +int spiSetType(struct bb_spi *spi, enum spi_type type) { + + if (spi->type == type) + return 0; + + switch (type) { + + case ST_SINGLE: + if (spi->type == ST_QPI) { + spiBegin(spi); + spiCommand(spi, 0xff); // Exit QPI Mode + spiEnd(spi); + spi->qpi = 0; + } + spi->type = type; + spi_set_state(spi, SS_SINGLE); + break; + + case ST_DUAL: + if (spi->type == ST_QPI) { + spiBegin(spi); + spiCommand(spi, 0xff); // Exit QPI Mode + spiEnd(spi); + spi->qpi = 0; + } + spi->type = type; + spi_set_state(spi, SS_DUAL_TX); + break; + + case ST_QUAD: + if (spi->type == ST_QPI) { + spiBegin(spi); + spiCommand(spi, 0xff); // Exit QPI Mode + spiEnd(spi); + spi->qpi = 0; + } + + // Enable QE bit + spiWriteSr(spi, 2, spiReadSr(spi, 2) | (1 << 1)); + + spi->type = type; + spi_set_state(spi, SS_QUAD_TX); + break; + + case ST_QPI: + // Enable QE bit + spiWriteSr(spi, 2, spiReadSr(spi, 2) | (1 << 1)); + + spiBegin(spi); + spiCommand(spi, 0x38); // Enter QPI Mode + spiEnd(spi); + spi->qpi = 1; + spi->type = type; + spi_set_state(spi, SS_QUAD_TX); + break; + + default: + fprintf(stderr, "Unrecognized SPI type: %d\n", type); + return 1; + } + return 0; +} + +int spiRead(struct bb_spi *spi, uint32_t addr, uint8_t *data, unsigned int count) { + + unsigned int i; + + spiBegin(spi); + switch (spi->type) { + case ST_SINGLE: + case ST_QPI: + spiCommand(spi, 0x0b); + break; + case ST_DUAL: + spiCommand(spi, 0x3b); + break; + case ST_QUAD: + spiCommand(spi, 0x6b); + break; + default: + fprintf(stderr, "unrecognized spi mode\n"); + spiEnd(spi); + return 1; + } + spiCommand(spi, addr >> 16); + spiCommand(spi, addr >> 8); + spiCommand(spi, addr >> 0); + spiCommand(spi, 0x00); + for (i = 0; i < count; i++) + data[i] = spiRx(spi); + + spiEnd(spi); + return 0; +} + +int spi_wait_for_not_busy(struct bb_spi *spi) { + uint8_t sr1; + sr1 = spiReadSr(spi, 1); + + do { + sr1 = spiReadSr(spi, 1); + } while (sr1 & (1 << 0)); + return 0; +} + +int spiWrite(struct bb_spi *spi, uint32_t addr, const uint8_t *data, unsigned int count) { + + unsigned int i; + + if (addr & 0xff) { + fprintf(stderr, "Error: Target address is not page-aligned to 256 bytes\n"); + return 1; + } + + // Erase all applicable blocks + uint32_t erase_addr; + for (erase_addr = 0; erase_addr < count; erase_addr += 32768) { + spiBegin(spi); + spiCommand(spi, 0x06); + spiEnd(spi); + + spiBegin(spi); + spiCommand(spi, 0x52); + spiCommand(spi, erase_addr >> 16); + spiCommand(spi, erase_addr >> 8); + spiCommand(spi, erase_addr >> 0); + spiEnd(spi); + + spi_wait_for_not_busy(spi); + } + + uint8_t write_cmd; + switch (spi->type) { + case ST_DUAL: + fprintf(stderr, "dual writes are broken -- need to temporarily set SINGLE mode\n"); + return 1; + case ST_SINGLE: + case ST_QPI: + write_cmd = 0x02; + break; + case ST_QUAD: + write_cmd = 0x32; + break; + default: + fprintf(stderr, "unrecognized spi mode\n"); + return 1; + } + + while (count) { + spiBegin(spi); + spiCommand(spi, 0x06); + spiEnd(spi); + + spiBegin(spi); + spiCommand(spi, write_cmd); + spiCommand(spi, addr >> 16); + spiCommand(spi, addr >> 8); + spiCommand(spi, addr >> 0); + for (i = 0; (i < count) && (i < 256); i++) + spiTx(spi, *data++); + spiEnd(spi); + count -= i; + addr += i; + spi_wait_for_not_busy(spi); + } + return 0; +} + +uint8_t spiReset(struct bb_spi *spi) { + // XXX You should check the "Ready" bit before doing this! + + spiSetType(spi, ST_SINGLE); + + spiBegin(spi); + spiSingleTx(spi, 0x66); // "Enable Reset" command + spiEnd(spi); + + spiBegin(spi); + spiSingleTx(spi, 0x99); // "Reset Device" command + spiEnd(spi); + + usleep(30); + return 0; +} + +void fpgaSlaveMode(void) { + + // Set the CS pin to a GPIO, which will let us control it + gpioSetMode(S_CE0, PI_OUTPUT); + + // Set CS to 0, which will put the FPGA into slave mode + gpioWrite(S_CE0, 0); + + usleep(10000); // XXX figure out correct sleep length here + + // Bring the FPGA out of reset + gpioWrite(F_RESET, 1); + + usleep(1200); // 13.2.SPI Slave Configuration Process +} + +int spiInit(struct bb_spi *spi) { + spi->state = SS_UNCONFIGURED; + spi->type = ST_UNCONFIGURED; + spi->qpi = 0; + + // Reset the SPI flash, which will return it to SPI mode even + // if it's in QPI mode. + spiReset(spi); + + spiSetType(spi, ST_SINGLE); + + return 0; +} + + +static inline int isprint(int c) +{ + return c > 32 && c < 127; +} + +int print_hex_offset(FILE *stream, + const void *block, int count, int offset, uint32_t start) +{ + + int byte; + const uint8_t *b = block; + + count += offset; + b -= offset; + for ( ; offset < count; offset += 16) { + fprintf(stream, "%08x", start + offset); + + for (byte = 0; byte < 16; byte++) { + if (byte == 8) + fprintf(stream, " "); + fprintf(stream, " "); + if (offset + byte < count) + fprintf(stream, "%02x", b[offset + byte] & 0xff); + else + fprintf(stream, " "); + } + + fprintf(stream, " |"); + for (byte = 0; byte < 16 && byte + offset < count; byte++) + fprintf(stream, "%c", isprint(b[offset + byte]) ? b[offset + byte] : '.'); + fprintf(stream, "|\r\n"); + } + return 0; +} + +int print_hex(const void *block, int count, uint32_t start) +{ + FILE *stream = stdout; + return print_hex_offset(stream, block, count, 0, start); +} + +int main(int argc, char *argv[]) +{ + int result; + struct bb_spi spi; + + if (gpioInitialise() < 0) { + fprintf(stderr, "Unable to initialize GPIO\n"); + return 1; + } + + /* The dance to put the FPGA into programming mode: + * 1) Put it into reset (set C_RESET to 0) + * 2) Drive CS to 0 + * 3) Bring it out of reset + * 4) Let CS go back to 1 + * 5) Set HOLD/ on the SPI flash by setting pin 25 to 0 + * To program the FPGA + */ + + + // Have the SPI flash pay attention to us + gpioWrite(S_HOLD, 1); + + // Disable WP + gpioWrite(S_WP, 1); + + // Put the FPGA into reset + gpioSetMode(F_RESET, PI_OUTPUT); + gpioWrite(F_RESET, 0); + + // Also monitor the C_DONE pin + gpioSetMode(F_DONE, PI_INPUT); + + // Restart the FPGA in slave mode + //fpgaSlaveMode(); + + result = gpioRead(F_DONE); + fprintf(stderr, "Reset before running: %d\n", result); + + spiInit(&spi); + + spiSetType(&spi, ST_QPI); + + // Assert CS + spiBegin(&spi); + + int i; + fprintf(stderr, "Write:"); + spiCommand(&spi, 0x90); + spiTx(&spi, 0x00); // A23-16 + spiTx(&spi, 0x00); // A15-8 + spiRx(&spi); // Dummy0 + spiRx(&spi); // Dummy1 + fprintf(stderr, "\nRead:"); + for (i=0; i<16; i++) { + fprintf(stderr, " 0x%02x", spiRx(&spi)); + } + fprintf(stderr, "\n"); + spiEnd(&spi); + + + uint8_t data[383316]; + { + memset(data, 0xaa, sizeof(data)); + int fd = open("/tmp/image-gateware+bios+micropython.bin", O_RDONLY); + if (read(fd, data, sizeof(data)) != sizeof(data)) { + perror("uanble to read"); + return 1; + } + spiWrite(&spi, 0, data, sizeof(data)); + } + + { + uint8_t page0[256]; + spiRead(&spi, 0, page0, sizeof(page0)); + print_hex(page0, sizeof(page0), 0); + } + { + uint8_t check_data[sizeof(data)]; + spiRead(&spi, 0, check_data, sizeof(check_data)); + int j; + for (j=0; j +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static volatile uint32_t piModel = 1; + +static volatile uint32_t piPeriphBase = 0x20000000; +static volatile uint32_t piBusAddr = 0x40000000; + +#define SYST_BASE (piPeriphBase + 0x003000) +#define DMA_BASE (piPeriphBase + 0x007000) +#define CLK_BASE (piPeriphBase + 0x101000) +#define GPIO_BASE (piPeriphBase + 0x200000) +#define UART0_BASE (piPeriphBase + 0x201000) +#define PCM_BASE (piPeriphBase + 0x203000) +#define SPI0_BASE (piPeriphBase + 0x204000) +#define I2C0_BASE (piPeriphBase + 0x205000) +#define PWM_BASE (piPeriphBase + 0x20C000) +#define BSCS_BASE (piPeriphBase + 0x214000) +#define UART1_BASE (piPeriphBase + 0x215000) +#define I2C1_BASE (piPeriphBase + 0x804000) +#define I2C2_BASE (piPeriphBase + 0x805000) +#define DMA15_BASE (piPeriphBase + 0xE05000) + +#define DMA_LEN 0x1000 /* allow access to all channels */ +#define CLK_LEN 0xA8 +#define GPIO_LEN 0xB4 +#define SYST_LEN 0x1C +#define PCM_LEN 0x24 +#define PWM_LEN 0x28 +#define I2C_LEN 0x1C + +#define GPSET0 7 +#define GPSET1 8 + +#define GPCLR0 10 +#define GPCLR1 11 + +#define GPLEV0 13 +#define GPLEV1 14 + +#define GPPUD 37 +#define GPPUDCLK0 38 +#define GPPUDCLK1 39 + +#define SYST_CS 0 +#define SYST_CLO 1 +#define SYST_CHI 2 + +#define CLK_PASSWD (0x5A<<24) + +#define CLK_CTL_MASH(x)((x)<<9) +#define CLK_CTL_BUSY (1 <<7) +#define CLK_CTL_KILL (1 <<5) +#define CLK_CTL_ENAB (1 <<4) +#define CLK_CTL_SRC(x) ((x)<<0) + +#define CLK_SRCS 4 + +#define CLK_CTL_SRC_OSC 1 /* 19.2 MHz */ +#define CLK_CTL_SRC_PLLC 5 /* 1000 MHz */ +#define CLK_CTL_SRC_PLLD 6 /* 500 MHz */ +#define CLK_CTL_SRC_HDMI 7 /* 216 MHz */ + +#define CLK_DIV_DIVI(x) ((x)<<12) +#define CLK_DIV_DIVF(x) ((x)<< 0) + +#define CLK_GP0_CTL 28 +#define CLK_GP0_DIV 29 +#define CLK_GP1_CTL 30 +#define CLK_GP1_DIV 31 +#define CLK_GP2_CTL 32 +#define CLK_GP2_DIV 33 + +#define CLK_PCM_CTL 38 +#define CLK_PCM_DIV 39 + +#define CLK_PWM_CTL 40 +#define CLK_PWM_DIV 41 + + +static volatile uint32_t *gpioReg = MAP_FAILED; +static volatile uint32_t *systReg = MAP_FAILED; +static volatile uint32_t *clkReg = MAP_FAILED; + +#define PI_BANK (gpio>>5) +#define PI_BIT (1<<(gpio&0x1F)) + +/* gpio modes. */ + +#define PI_INPUT 0 +#define PI_OUTPUT 1 +#define PI_ALT0 4 +#define PI_ALT1 5 +#define PI_ALT2 6 +#define PI_ALT3 7 +#define PI_ALT4 3 +#define PI_ALT5 2 + +void gpioSetMode(unsigned gpio, unsigned mode) { + int reg, shift; + + reg = gpio/10; + shift = (gpio%10) * 3; + + gpioReg[reg] = (gpioReg[reg] & ~(7<> shift) & 7; +} + +/* Values for pull-ups/downs off, pull-down and pull-up. */ + +#define PI_PUD_OFF 0 +#define PI_PUD_DOWN 1 +#define PI_PUD_UP 2 + +void gpioSetPullUpDown(unsigned gpio, unsigned pud) { + *(gpioReg + GPPUD) = pud; + + usleep(20); + + *(gpioReg + GPPUDCLK0 + PI_BANK) = PI_BIT; + + usleep(20); + + *(gpioReg + GPPUD) = 0; + + *(gpioReg + GPPUDCLK0 + PI_BANK) = 0; +} + +int gpioRead(unsigned gpio) { + if ((*(gpioReg + GPLEV0 + PI_BANK) & PI_BIT) != 0) return 1; + else return 0; +} + +void gpioWrite(unsigned gpio, unsigned level) { + if (level == 0) *(gpioReg + GPCLR0 + PI_BANK) = PI_BIT; + else *(gpioReg + GPSET0 + PI_BANK) = PI_BIT; +} + +void gpioTrigger(unsigned gpio, unsigned pulseLen, unsigned level) { + if (level == 0) *(gpioReg + GPCLR0 + PI_BANK) = PI_BIT; + else *(gpioReg + GPSET0 + PI_BANK) = PI_BIT; + + usleep(pulseLen); + + if (level != 0) *(gpioReg + GPCLR0 + PI_BANK) = PI_BIT; + else *(gpioReg + GPSET0 + PI_BANK) = PI_BIT; +} + +/* Bit (1<