/* * Remote Laboratory FPGA Server GPMC Interface (Beaglebone Black) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * (c) 2012-2014 Timothy Pearson * Raptor Engineering * http://www.raptorengineeringinc.com */ /** BEGIN: Low-Level I/O Implementation **/ // Beaglebone Black GPMC driver #include #include #include #include #include #include #include #include #include #include #include #define MEMORY_SPACE_ADDRESS_BITS 16 #define GPMC_BASE 0x50000000 #define GPMC_REGLEN 0x10000000 #define GPMC_CHIPSELECTCONFIGDISPLACEMENT (0x30 / 4) #define GPMC_CONFIG (0x50 / 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 MEMORY_SIZE (1 << MEMORY_SPACE_ADDRESS_BITS) int mem_fd = 0; int gpmc_mem_fd = 0; char *gpio_mem, *gpio_map, *gpmc_map; // I/O access volatile unsigned int *gpio = NULL; volatile unsigned char *gpio_char = NULL; volatile unsigned int *gpmc = NULL; void gpmc_mapregisters() { /* open /dev/mem */ if ((gpmc_mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) { printf("[FATAL] can't open /dev/mem\n"); return; } /* mmap GPMC */ gpmc_map = (char *)mmap( 0, GPMC_REGLEN, PROT_READ|PROT_WRITE, MAP_SHARED, gpmc_mem_fd, GPMC_BASE ); if (gpmc_map == MAP_FAILED) { printf("[FATAL] mmap error %p\n", gpmc_map); return; } // Always use volatile pointer! gpmc = (volatile unsigned *)gpmc_map; } void gpmc_unmapregisters() { munmap((void*) gpmc, GPMC_REGLEN); if (gpmc_mem_fd != -1) { close(gpmc_mem_fd); } } void gpmc_setup(void) { gpmc_mapregisters(); if (gpmc != NULL) { int chipselect = 0; int displacement = GPMC_CHIPSELECTCONFIGDISPLACEMENT * chipselect; // disable before playing with the registers *(gpmc + displacement + GPMC_CONFIG7) = 0x00000000; // *(gpmc + displacement + GPMC_CONFIG) = 0x00000000; // Unlimited address space // *(gpmc + displacement + GPMC_CONFIG1) = 0x00000000; // No burst, async, 8-bit, non multiplexed // *(gpmc + displacement + GPMC_CONFIG2) = 0x00001000; // Assert CS on fclk0, deassert CS on fclk16 // *(gpmc + displacement + GPMC_CONFIG3) = 0x00000400; // Assert ADV on fclk 0, deassert ADV on fclk 4 // *(gpmc + displacement + GPMC_CONFIG4) = 0x0c041004; // Assert WE on fclk4, deassert WE on fclk12, assert OE on fclk4, deassert OE on fclk16 // *(gpmc + displacement + GPMC_CONFIG5) = 0x000c1010; // Data valid on fclk 12, cycle time 16 fclks // *(gpmc + displacement + GPMC_CONFIG6) = 0x00000000; // No back to back cycle restrictions // *(gpmc + displacement + GPMC_CONFIG7) = 0x00000e50; // CS0: Set base address 0x10000000, 32MB region, and enable CS // Use slower clocking to reduce errors in wire nest prototype *(gpmc + displacement + GPMC_CONFIG) = 0x00000000; // Unlimited address space *(gpmc + displacement + GPMC_CONFIG1) = 0x00000000; // No burst, async, 8-bit, non multiplexed *(gpmc + displacement + GPMC_CONFIG2) = 0x00001f00; // Assert CS on fclk0, deassert CS on fclk31 *(gpmc + displacement + GPMC_CONFIG3) = 0x00000400; // Assert ADV on fclk 0, deassert ADV on fclk 4 *(gpmc + displacement + GPMC_CONFIG4) = 0x1f041f04; // Assert WE on fclk4, deassert WE on fclk31, assert OE on fclk4, deassert OE on fclk31 *(gpmc + displacement + GPMC_CONFIG5) = 0x00101f1f; // Data valid on fclk 16, cycle time 31 fclks *(gpmc + displacement + GPMC_CONFIG6) = 0x00000000; // No back to back cycle restrictions *(gpmc + displacement + GPMC_CONFIG7) = 0x00000e50; // CS0: Set base address 0x10000000, 32MB region, and enable CS gpmc_unmapregisters(); } } int setup_gpmc_bbb(void) { /* open /dev/mem */ if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) { printf("[FATAL] can't open /dev/mem\n"); return -1; } /* mmap GPIO */ gpio_map = (char *)mmap( 0, MEMORY_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, 0x10000000 ); if (gpio_map == MAP_FAILED) { printf("[FATAL] mmap error %p\n", gpio_map); return -1; } // Always use volatile pointers! gpio = (volatile unsigned *)gpio_map; gpio_char = (volatile unsigned char *)gpio_map; return 0; } int shutdown_gpmc_bbb(void) { return 0; } void write_gpmc(unsigned int register_offset, unsigned char data) { *(gpio_char + register_offset) = data; } unsigned char read_gpmc(unsigned int register_offset) { return *(gpio_char + register_offset); } void write_gpmc_uint16_t(unsigned int register_offset, uint16_t data) { register_offset = register_offset * 2; *(gpio_char + register_offset + 0) = ((data & 0xff00) >> 8); *(gpio_char + register_offset + 1) = ((data & 0x00ff) >> 0); } uint16_t read_gpmc_uint16_t(unsigned int register_offset) { uint16_t result = 0; register_offset = register_offset * 2; result = result | ((uint16_t)(*(gpio_char + register_offset + 0)) << 8); result = result | ((uint16_t)(*(gpio_char + register_offset + 1)) << 0); return result; } void write_gpmc_uint64_t(unsigned int register_offset, uint64_t data) { register_offset = register_offset * 8; *(gpio_char + register_offset + 0) = ((data & 0xff00000000000000) >> 56); *(gpio_char + register_offset + 1) = ((data & 0x00ff000000000000) >> 48); *(gpio_char + register_offset + 2) = ((data & 0x0000ff0000000000) >> 40); *(gpio_char + register_offset + 3) = ((data & 0x000000ff00000000) >> 32); *(gpio_char + register_offset + 4) = ((data & 0x00000000ff000000) >> 24); *(gpio_char + register_offset + 5) = ((data & 0x0000000000ff0000) >> 16); *(gpio_char + register_offset + 6) = ((data & 0x000000000000ff00) >> 8); *(gpio_char + register_offset + 7) = ((data & 0x00000000000000ff) >> 0); } uint64_t read_gpmc_uint64_t(unsigned int register_offset) { uint64_t result = 0; register_offset = register_offset * 8; result = result | ((uint64_t)(*(gpio_char + register_offset + 0)) << 56); result = result | ((uint64_t)(*(gpio_char + register_offset + 1)) << 48); result = result | ((uint64_t)(*(gpio_char + register_offset + 2)) << 40); result = result | ((uint64_t)(*(gpio_char + register_offset + 3)) << 32); result = result | ((uint64_t)(*(gpio_char + register_offset + 4)) << 24); result = result | ((uint64_t)(*(gpio_char + register_offset + 5)) << 16); result = result | ((uint64_t)(*(gpio_char + register_offset + 6)) << 8); result = result | ((uint64_t)(*(gpio_char + register_offset + 7)) << 0); return result; } void memcpy_from_gpmc(char* destination, unsigned int register_offset, unsigned int length) { unsigned int i; for (i=0; i