/* * bus.c * * Created on: 9 Aug 2012 * Author: daniel */ #include #include #include #include #include #include #include #include #include #include #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(); if (registers != MAP_FAILED) { // 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]); } }