/* * bus.c * * Created on: 9 Aug 2012 * Author: daniel */ #include #include #include #include #include #include #include #include #include #include #include "globals.h" #include "bus.h" #include "version.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 bool util_model_is (char *check_model) { FILE *fp; char content[100]; bool retval; retval = FALSE; if ((fp=fopen("/sys/firmware/devicetree/base/model", "r"))==NULL) { return retval; } while(fgets(content, sizeof(content), fp)) { if(strstr(content,check_model)) { retval = TRUE; } } fclose (fp); return retval; } static bool util_is_beaglebone() { return util_model_is ("TI AM335x BeagleBone"); } static bool util_is_olimex() { return util_model_is ("Olimex AM335x SOM"); } 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); } } #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(); } #define BIDIR 0x20 #define PULL_UP 0x10 #define PULL_DOWN 0x00 #define NO_PULL 0x80 #define MODE_0 0x00 #define MODE_1 0x01 #define MODE_2 0x02 #define MODE_3 0x03 #define MODE_4 0x04 #define MODE_5 0x05 #define MODE_6 0x06 #define MODE_7 0x07 // multiply by 20 ns #define TOTAL_IO_CYCLE 14 // 280 ns cycle #define CS_DELAY 1 // CS low 20ns after address valid #define DELAY_TO_WR_RD 2 // RD/WR lines low 40ns after address valid #define WR_RD_WIDTH 8 // stay low for until 200 ns after address valid #define DATA_READY 8 // data ready 160ns after address valid static void gpmc_setup(void) { int CSWROFFTIME = TOTAL_IO_CYCLE; int CSRDOFFTIME = TOTAL_IO_CYCLE; int CSONTIME = CS_DELAY; int config2 = (CSWROFFTIME << 16) | (CSRDOFFTIME << 8) | CSONTIME; int WEOFFTIME = DELAY_TO_WR_RD + WR_RD_WIDTH; int WEONTIME = DELAY_TO_WR_RD; int OEOFFTIME = DELAY_TO_WR_RD + WR_RD_WIDTH; int OEONTIME = DELAY_TO_WR_RD; int config4 = (WEOFFTIME << 24) | (WEONTIME << 16) | (OEOFFTIME << 8) | OEONTIME; int RDACCESSTIME = DATA_READY; int WRCYCLETIME = TOTAL_IO_CYCLE; int RDCYCLETIME = TOTAL_IO_CYCLE; int config5 = (RDACCESSTIME << 16) | (WRCYCLETIME << 8) | RDCYCLETIME; int WRACCESSTIME = DATA_READY; int config6 = WRACCESSTIME << 24; gpmc_mapregisters(); if (registers != MAP_FAILED) { int chipselect = 0; int size = GPMC_SIZE_16MB; bool enablecs = true; int baseaddress = 1; int displacement = GPMC_CHIPSELECTCONFIGDISPLACEMENT * chipselect; // disable before playing with the registers.. *(registers + displacement + GPMC_CONFIG7) = 0x0; *(registers + displacement + GPMC_CONFIG1) = 0x10; // double all of the timing values *(registers + displacement + GPMC_CONFIG2) = config2; *(registers + displacement + GPMC_CONFIG3) = 0x0; // not using ADV so we can ignore this guy *(registers + displacement + GPMC_CONFIG4) = config4; *(registers + displacement + GPMC_CONFIG5) = config5; *(registers + displacement + GPMC_CONFIG6) = config6; *(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 gpio_pin) { FILE* exportfile = fopen(GPIO_SYSFSPATH"/"GPIO_EXPORTNODE, "w"); if (exportfile != NULL) { fprintf(exportfile, "%u\n", gpio_pin); fclose(exportfile); return 0; } return -1; } /* * Un-export a gpio from userland */ static int gpio_unexport(unsigned gpio_pin) { FILE* unexportfile = fopen(GPIO_SYSFSPATH"/"GPIO_UNEXPORTNODE, "w"); if (unexportfile != NULL) { fprintf(unexportfile, "%u\n", gpio_pin); fclose(unexportfile); return 0; } return -1; } /* * Change a pins direction */ static int gpio_changedirection(unsigned gpio_pin, bool out) { char path[PATHLEN]; snprintf(path, PATHLEN, GPIO_SYSFSPATH"/gpio%u/"GPIO_DIRECTIONNODE, gpio_pin); 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 gpio_pin, char* buffer) { snprintf(buffer, PATHLEN, GPIO_SYSFSPATH"/gpio%u/"GPIO_VALUENODE, gpio_pin); } /* * Read a pin's value */ static int gpio_readvalue(unsigned gpio_pin) { char path[PATHLEN]; gpio_getvaluenodepath(gpio_pin, path); FILE* valuefile = fopen(path, "r"); if (valuefile != NULL) { char value[2]; // value will be a single char and \n fread(value, 1, 2, valuefile); fclose(valuefile); return atoi(value); } return -1; } /* * Write a pin's value */ static int gpio_writevalue(unsigned gpio_pin, int value) { char path[PATHLEN]; gpio_getvaluenodepath(gpio_pin, path); FILE* valuefile = fopen(path, "w"); if (valuefile != NULL) { fprintf(valuefile, "%d\n", value); fclose(valuefile); return 0; } return -1; } // gpio pins are grouped into 4 bunches of 32 pins #define GPIO0_X (0 * 32) #define GPIO1_X (1 * 32) #define GPIO2_X (2 * 32) #define GPIO3_X (3 * 32) static unsigned gpio_pins[] = { GPIO0_X + 22, // i.e., GPIO0_22 GPIO0_X + 23, GPIO0_X + 26, GPIO1_X + 15, // i.e., GPIO1_15 GPIO1_X + 14, GPIO0_X + 27, GPIO1_X + 12, GPIO2_X + 1 }; static volatile uint8_t* extbus; void bus_init() { globals.HWDetect.beaglebone = util_is_beaglebone(); globals.HWDetect.olimex = util_is_olimex(); strcpy(globals.HWDetect.firmware,FW_VERSION); if (globals.HWDetect.beaglebone) { strcat(globals.HWDetect.firmware,"BB"); } else if (globals.HWDetect.olimex) { strcat(globals.HWDetect.firmware,"OL"); } globals.HWDetect.has_i2c = globals.HWDetect.beaglebone || globals.HWDetect.olimex; globals.HWDetect.has_gpmc = globals.HWDetect.beaglebone || globals.HWDetect.olimex; globals.HWDetect.has_gpio = globals.HWDetect.beaglebone || globals.HWDetect.olimex; printf("Beaglebone: %d. Olimex: %d.\n", globals.HWDetect.beaglebone, globals.HWDetect.olimex); if (globals.HWDetect.has_gpmc) { gpmc_setup(); extbus = (uint8_t*) util_mapmemoryblock(0x01000000, 0x100); gpmc_printinfo(); } else { printf("No recognized hardware. gpmc bus stuff disabled!\n"); } if (globals.HWDetect.has_gpio) { int i; for (i = 0; i < SIZEOFARRAY(gpio_pins); i++) { // these pins all happen to default to the correct mode (7) // so no call to pinmux_configurepin is necessary gpio_export(gpio_pins[i]); gpio_changedirection(gpio_pins[i], true); } // this could be more elegant - // the POWER_FAIL pin is an input gpio_changedirection(gpio_pins[POWER_FAIL], false); // reset the TNT4882 chip bus_setpin(RST_GPIB, 0); g_usleep(10); bus_setpin(RST_GPIB, 1); g_usleep(10); } else { printf("No recognized hardware. gpio stuff disabled!\n"); } } int bus_getpin(int pin) { if (globals.HWDetect.has_gpio) { return gpio_readvalue(gpio_pins[pin]); } else { return 0; } } void bus_setpin(int pin, int value) { if (globals.HWDetect.has_gpio) { gpio_writevalue(gpio_pins[pin], value & 0x1); } } void bus_writebyte(uint8_t address, uint8_t data) { if (globals.HWDetect.has_gpmc) { *(extbus + address) = data; } } uint8_t bus_readbyte(uint8_t address) { if (globals.HWDetect.has_gpmc) { return *(extbus + address); } else { return 0; } } void bus_shutdown() { if (globals.HWDetect.has_gpmc) { util_unmapmemoryblock((void*) extbus, 0x100); } if (globals.HWDetect.has_gpio) { int i; for (i = 0; i < SIZEOFARRAY(gpio_pins); i++) { gpio_unexport(gpio_pins[i]); } } }