diff options
Diffstat (limited to 'bus.c')
-rw-r--r-- | bus.c | 336 |
1 files changed, 336 insertions, 0 deletions
@@ -0,0 +1,336 @@ +/* + * bus.c + * + * Created on: 9 Aug 2012 + * Author: daniel + */ + +#include <stdint.h> +#include <stddef.h> +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <unistd.h> +#include <stdbool.h> +#include <inttypes.h> +#include "bus.h" + +#define GPIO_SYSFSPATH "/sys/class/gpio" +#define GPIO_EXPORTNODE "export" +#define GPIO_UNEXPORTNODE "unexport" +#define GPIO_DIRECTIONNODE "direction" +#define GPIO_VALUENODE "value" +#define GPIO_LABELNODE "label" +#define GPIO_BASENODE "base" + +#define GPIO_DIRECTION_IN "in" +#define GPIO_DIRECTION_OUT "out" +#define SIZEOFARRAY(a) (sizeof(a)/sizeof(a[0])) +#define PATHLEN 256 + +#define GPMC_BASE 0x50000000 +#define GPMC_REVISION 0x0 +#define GPMC_SYSCONFIG (0x10 / 4) +#define GPMC_SYSSTATUS (0x14 / 4) +#define GPMC_IRQSTATUS (0x18 / 4) +#define GPMC_IRQENABLE (0x1c / 4) +#define GPMC_TIMEOUT_CONTROL (0x40 / 4) +#define GPMC_ERR_ADDRESS (0x44 / 4) +#define GPMC_ERR_TYPE (0x48 / 4) + +#define GPMC_CHIPSELECTCONFIGDISPLACEMENT (0x30 / 4) + +#define GPMC_CONFIG1 (0x60 / 4) +#define GPMC_CONFIG2 (0x64 / 4) +#define GPMC_CONFIG3 (0x68 / 4) +#define GPMC_CONFIG4 (0x6c / 4) +#define GPMC_CONFIG5 (0x70 / 4) +#define GPMC_CONFIG6 (0x74 / 4) +#define GPMC_CONFIG7 (0x78 / 4) + +#define GPMC_SIZE_256MB 0 +#define GPMC_SIZE_128MB 0x8 +#define GPMC_SIZE_64MB 0xc +#define GPMC_SIZE_32MB 0xe +#define GPMC_SIZE_16MB 0xf + +static int devmemfd = -1; + +static void* util_mapmemoryblock(off_t offset, size_t len) +{ + devmemfd = open("/dev/mem", O_RDWR | O_SYNC); + void* registers = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, devmemfd, offset); + if (registers == MAP_FAILED) { + printf("Map failed\n"); + } + return registers; +} + +static void util_unmapmemoryblock(void* block, size_t len) +{ + munmap((void*) block, len); + if (devmemfd != -1) { + close(devmemfd); + } +} + +static void pinmux_configurepin(char* pin, int option, int mode) +{ + char path[256]; + snprintf(path, sizeof(path), "/sys/kernel/debug/omap_mux/%s", pin); + FILE* node = fopen(path, "w"); + if (node != NULL) { + fprintf(node, "0x%02x\n", (((option << 4) | mode) & 0xff)); + fclose(node); + } else { + printf("Failed to configure pin %s (%s)\n", pin, path); + } +} + +#define REGLEN 0x10000000 + +static volatile uint32_t* registers = NULL; + +static void gpmc_mapregisters() +{ + registers = (uint32_t*) util_mapmemoryblock(GPMC_BASE, REGLEN); +} + +static void gpmc_unmapregisters() +{ + util_unmapmemoryblock((void*) registers, REGLEN); +} + +static void gpmc_printconfig(int chipselect) +{ + + int displacement = GPMC_CHIPSELECTCONFIGDISPLACEMENT * chipselect; + printf("Config for CS%d\n", chipselect); + printf("CONFIG_1 [0x%08"PRIx32"]\n", *(registers + displacement + GPMC_CONFIG1)); + printf("CONFIG_2 [0x%08"PRIx32"]\n", *(registers + displacement + GPMC_CONFIG2)); + printf("CONFIG_3 [0x%08"PRIx32"]\n", *(registers + displacement + GPMC_CONFIG3)); + printf("CONFIG_4 [0x%08"PRIx32"]\n", *(registers + displacement + GPMC_CONFIG4)); + printf("CONFIG_5 [0x%08"PRIx32"]\n", *(registers + displacement + GPMC_CONFIG5)); + printf("CONFIG_6 [0x%08"PRIx32"]\n", *(registers + displacement + GPMC_CONFIG6)); + printf("CONFIG_7 [0x%08"PRIx32"]\n", *(registers + displacement + GPMC_CONFIG7)); +} + +static void gpmc_printinfo() +{ + + gpmc_mapregisters(); + + uint32_t rev = *(registers + GPMC_REVISION); + uint8_t major = (rev >> 4) & 0xF; + uint8_t minor = rev & 0xF; + + printf("GPMC Rev is apparently %"PRId8".%"PRId8"\n", major, minor); + printf("SYSCONFIG\t[0x%08"PRIx32"]\n", *(registers + GPMC_SYSCONFIG)); + printf("SYSSTATUS\t[0x%08"PRIx32"]\n", *(registers + GPMC_SYSSTATUS)); + printf("IRQSTATUS\t[0x%08"PRIx32"]\n", *(registers + GPMC_IRQSTATUS)); + printf("IRQENABLE\t[0x%08"PRIx32"]\n", *(registers + GPMC_IRQENABLE)); + printf("TIMEOUT_CONTROL\t[0x%08"PRIx32"]\n", *(registers + GPMC_TIMEOUT_CONTROL)); + printf("ERR_ADDRESS\t[0x%08"PRIx32"]\n", *(registers + GPMC_ERR_ADDRESS)); + printf("ERR_TYPE\t[0x%08"PRIx32"]\n", *(registers + GPMC_ERR_TYPE)); + + int i; + for (i = 0; i < 8; i++) { + gpmc_printconfig(i); + } + + gpmc_unmapregisters(); + +} + +// The shift amounts + +#define CSWROFFTIME 16 +#define CSRDOFFTIME 8 +#define OEOFFTIME 8 +#define RDACCESSTIME 16 +#define WRCYCLETIME 8 +#define RDCYCLETIME 0 +#define WRACCESSTIME 24 + +static void gpmc_setup(int chipselect, int accesscycles, int size, bool enablecs, int baseaddress) +{ + + pinmux_configurepin("gpmc_csn0", 0x0, 0x0); + pinmux_configurepin("gpmc_oen_ren", 0x0, 0x0); + pinmux_configurepin("gpmc_wen", 0x0, 0x0); + + pinmux_configurepin("gpmc_ad7", 0x3, 0x0); + pinmux_configurepin("gpmc_ad6", 0x3, 0x0); + pinmux_configurepin("gpmc_ad5", 0x3, 0x0); + pinmux_configurepin("gpmc_ad4", 0x3, 0x0); + pinmux_configurepin("gpmc_ad3", 0x3, 0x0); + pinmux_configurepin("gpmc_ad2", 0x3, 0x0); + pinmux_configurepin("gpmc_ad1", 0x3, 0x0); + pinmux_configurepin("gpmc_ad0", 0x3, 0x0); + + pinmux_configurepin("lcd_data0", 0x0, 0x1); + pinmux_configurepin("lcd_data1", 0x0, 0x1); + pinmux_configurepin("lcd_data2", 0x0, 0x1); + pinmux_configurepin("lcd_data3", 0x0, 0x1); + pinmux_configurepin("lcd_data4", 0x0, 0x1); + pinmux_configurepin("lcd_data5", 0x0, 0x1); + pinmux_configurepin("lcd_data6", 0x0, 0x1); + pinmux_configurepin("lcd_data7", 0x0, 0x1); + + int displacement = GPMC_CHIPSELECTCONFIGDISPLACEMENT * chipselect; + + gpmc_mapregisters(); + + // disable before playing with the registers.. + *(registers + displacement + GPMC_CONFIG7) = 0x0; + + *(registers + displacement + GPMC_CONFIG1) = 0x0; + *(registers + displacement + GPMC_CONFIG2) = (accesscycles << CSWROFFTIME) | (accesscycles << CSRDOFFTIME); + *(registers + displacement + GPMC_CONFIG3) = 0x0; // not using ADV so we can ignore this guy + *(registers + displacement + GPMC_CONFIG4) = (accesscycles << OEOFFTIME); + *(registers + displacement + GPMC_CONFIG5) = (accesscycles << RDACCESSTIME) | (accesscycles << WRCYCLETIME) + | (accesscycles << RDCYCLETIME); + *(registers + displacement + GPMC_CONFIG6) = (accesscycles << WRACCESSTIME); + *(registers + displacement + GPMC_CONFIG7) = size << 8 | (enablecs ? 1 << 6 : 0) | baseaddress; + + gpmc_unmapregisters(); +} + +/* + * Export a gpio from the kernel to userland + */ + +static int gpio_export(unsigned base, unsigned io) +{ + FILE* exportfile = fopen(GPIO_SYSFSPATH"/"GPIO_EXPORTNODE, "w"); + if (exportfile != NULL) { + fprintf(exportfile, "%d\n", base + io); + fclose(exportfile); + return 0; + } + return -1; +} + +/* + * Un-export a gpio from userland + */ + +static int gpio_unexport(unsigned base, unsigned io) +{ + FILE* unexportfile = fopen(GPIO_SYSFSPATH"/"GPIO_UNEXPORTNODE, "w"); + if (unexportfile != NULL) { + fprintf(unexportfile, "%d\n", base + io); + fclose(unexportfile); + return 0; + } + return -1; +} + +/* + * Change a pins direction + */ + +static int gpio_changedirection(unsigned base, unsigned io, bool out) +{ + char path[PATHLEN]; + snprintf(path, PATHLEN, GPIO_SYSFSPATH"/gpio%d/"GPIO_DIRECTIONNODE, base + io); + FILE* directionfile = fopen(path, "w"); + if (directionfile != NULL) { + if (out) { + fputs(GPIO_DIRECTION_OUT, directionfile); + } else { + fputs(GPIO_DIRECTION_IN, directionfile); + } + + fclose(directionfile); + return 0; + } + return -1; +} + +static void gpio_getvaluenodepath(unsigned base, unsigned io, char* buffer) +{ + snprintf(buffer, PATHLEN, GPIO_SYSFSPATH"/gpio%d/"GPIO_VALUENODE, base + io); +} + +/* + * Read a pin's value + */ + +static int gpio_readvalue(unsigned base, unsigned io) +{ + char path[PATHLEN]; + char value[2]; // value will be a single char and \n + gpio_getvaluenodepath(base, io, path); + FILE* valuefile = fopen(path, "r"); + if (valuefile != NULL) { + fread(value, 1, 2, valuefile); + fclose(valuefile); + return atoi(value); + } + return -1; +} + +/* + * Write a pin's value + */ + +static int gpio_writevalue(unsigned base, unsigned io, int value) +{ + char path[PATHLEN]; + gpio_getvaluenodepath(base, io, path); + FILE* valuefile = fopen(path, "w"); + if (valuefile != NULL) { + fprintf(valuefile, "%d\n", value); + fclose(valuefile); + return 0; + } + return -1; +} + +static unsigned bases[] = { GPIOPIN0BASE, GPIOPIN1BASE, GPIOPIN2BASE, GPIOPIN3BASE, GPIOPIN4BASE, GPIOPIN5BASE }; +static unsigned pins[] = { GPIOPIN0PIN, GPIOPIN1PIN, GPIOPIN2PIN, GPIOPIN3PIN, GPIOPIN4PIN, GPIOPIN5PIN }; + +static volatile uint8_t* extbus; + +void bus_init() +{ + gpmc_setup(0, GPMCACCESSTIME, GPMC_SIZE_16MB, true, 1); + + extbus = (uint8_t*) util_mapmemoryblock(0x01000000, 0x100); + + //gpmc_printinfo(); + + int i; + for (i = 0; i < SIZEOFARRAY(bases); i++) { + gpio_export(bases[i], pins[i]); + gpio_changedirection(bases[i], pins[i], true); + } +} + +void bus_setpin(int pin, int value) +{ + gpio_writevalue(bases[pin], pins[pin], value & 0x1); +} + +void bus_writebyte(uint8_t address, uint8_t data) +{ + *(extbus + address) = data; +} + +uint8_t bus_readbyte(uint8_t address) +{ + return *(extbus + address); +} + +void bus_shutdown() +{ + util_unmapmemoryblock((void*) extbus, 0x100); + int i; + for (i = 0; i < SIZEOFARRAY(bases); i++) { + gpio_unexport(bases[i], pins[i]); + + } +} |