summaryrefslogtreecommitdiff
path: root/bus.c
diff options
context:
space:
mode:
Diffstat (limited to 'bus.c')
-rw-r--r--bus.c336
1 files changed, 336 insertions, 0 deletions
diff --git a/bus.c b/bus.c
new file mode 100644
index 0000000..c45fda6
--- /dev/null
+++ b/bus.c
@@ -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]);
+
+ }
+}