mirror of
https://github.com/captain-amygdala/pistorm.git
synced 2026-01-28 12:39:10 +00:00
298 lines
7.1 KiB
C
298 lines
7.1 KiB
C
// SPDX-License-Identifier: MIT
|
|
|
|
/*
|
|
Original Copyright 2020 Claude Schwarz
|
|
Code reorganized and rewritten by
|
|
Niklas Ekström 2021 (https://github.com/niklasekstrom)
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#include "ps_protocol.h"
|
|
#include "m68k.h"
|
|
|
|
volatile unsigned int *gpio;
|
|
volatile unsigned int *gpclk;
|
|
|
|
unsigned int gpfsel0;
|
|
unsigned int gpfsel1;
|
|
unsigned int gpfsel2;
|
|
|
|
unsigned int gpfsel0_o;
|
|
unsigned int gpfsel1_o;
|
|
unsigned int gpfsel2_o;
|
|
|
|
static void setup_io() {
|
|
int fd = open("/dev/mem", O_RDWR | O_SYNC);
|
|
if (fd < 0) {
|
|
printf("Unable to open /dev/mem. Run as root using sudo?\n");
|
|
exit(-1);
|
|
}
|
|
|
|
void *gpio_map = mmap(
|
|
NULL, // Any adddress in our space will do
|
|
BCM2708_PERI_SIZE, // Map length
|
|
PROT_READ | PROT_WRITE, // Enable reading & writting to mapped memory
|
|
MAP_SHARED, // Shared with other processes
|
|
fd, // File to map
|
|
BCM2708_PERI_BASE // Offset to GPIO peripheral
|
|
);
|
|
|
|
close(fd);
|
|
|
|
if (gpio_map == MAP_FAILED) {
|
|
printf("mmap failed, errno = %d\n", errno);
|
|
exit(-1);
|
|
}
|
|
|
|
gpio = ((volatile unsigned *)gpio_map) + GPIO_ADDR / 4;
|
|
gpclk = ((volatile unsigned *)gpio_map) + GPCLK_ADDR / 4;
|
|
}
|
|
|
|
static void setup_gpclk() {
|
|
// Enable 200MHz CLK output on GPIO4, adjust divider and pll source depending
|
|
// on pi model
|
|
*(gpclk + (CLK_GP0_CTL / 4)) = CLK_PASSWD | (1 << 5);
|
|
usleep(10);
|
|
while ((*(gpclk + (CLK_GP0_CTL / 4))) & (1 << 7))
|
|
;
|
|
usleep(100);
|
|
*(gpclk + (CLK_GP0_DIV / 4)) =
|
|
CLK_PASSWD | (6 << 12); // divider , 6=200MHz on pi3
|
|
usleep(10);
|
|
*(gpclk + (CLK_GP0_CTL / 4)) =
|
|
CLK_PASSWD | 5 | (1 << 4); // pll? 6=plld, 5=pllc
|
|
usleep(10);
|
|
while (((*(gpclk + (CLK_GP0_CTL / 4))) & (1 << 7)) == 0)
|
|
;
|
|
usleep(100);
|
|
|
|
SET_GPIO_ALT(PIN_CLK, 0); // gpclk0
|
|
}
|
|
|
|
void ps_setup_protocol() {
|
|
setup_io();
|
|
setup_gpclk();
|
|
|
|
*(gpio + 10) = 0xffffec;
|
|
|
|
*(gpio + 0) = GPFSEL0_INPUT;
|
|
*(gpio + 1) = GPFSEL1_INPUT;
|
|
*(gpio + 2) = GPFSEL2_INPUT;
|
|
}
|
|
|
|
void ps_write_16(unsigned int address, unsigned int data) {
|
|
*(gpio + 0) = GPFSEL0_OUTPUT;
|
|
*(gpio + 1) = GPFSEL1_OUTPUT;
|
|
*(gpio + 2) = GPFSEL2_OUTPUT;
|
|
|
|
*(gpio + 7) = ((data & 0xffff) << 8) | (REG_DATA << PIN_A0);
|
|
*(gpio + 7) = 1 << PIN_WR;
|
|
*(gpio + 10) = 1 << PIN_WR;
|
|
*(gpio + 10) = 0xffffec;
|
|
|
|
*(gpio + 7) = ((address & 0xffff) << 8) | (REG_ADDR_LO << PIN_A0);
|
|
*(gpio + 7) = 1 << PIN_WR;
|
|
*(gpio + 10) = 1 << PIN_WR;
|
|
*(gpio + 10) = 0xffffec;
|
|
|
|
*(gpio + 7) = ((0x0000 | (address >> 16)) << 8) | (REG_ADDR_HI << PIN_A0);
|
|
*(gpio + 7) = 1 << PIN_WR;
|
|
*(gpio + 10) = 1 << PIN_WR;
|
|
*(gpio + 10) = 0xffffec;
|
|
|
|
*(gpio + 0) = GPFSEL0_INPUT;
|
|
*(gpio + 1) = GPFSEL1_INPUT;
|
|
*(gpio + 2) = GPFSEL2_INPUT;
|
|
|
|
while (*(gpio + 13) & (1 << PIN_TXN_IN_PROGRESS))
|
|
;
|
|
}
|
|
|
|
void ps_write_8(unsigned int address, unsigned int data) {
|
|
if ((address & 1) == 0)
|
|
data = data + (data << 8); // EVEN, A0=0,UDS
|
|
else
|
|
data = data & 0xff; // ODD , A0=1,LDS
|
|
|
|
*(gpio + 0) = GPFSEL0_OUTPUT;
|
|
*(gpio + 1) = GPFSEL1_OUTPUT;
|
|
*(gpio + 2) = GPFSEL2_OUTPUT;
|
|
|
|
*(gpio + 7) = ((data & 0xffff) << 8) | (REG_DATA << PIN_A0);
|
|
*(gpio + 7) = 1 << PIN_WR;
|
|
*(gpio + 10) = 1 << PIN_WR;
|
|
*(gpio + 10) = 0xffffec;
|
|
|
|
*(gpio + 7) = ((address & 0xffff) << 8) | (REG_ADDR_LO << PIN_A0);
|
|
*(gpio + 7) = 1 << PIN_WR;
|
|
*(gpio + 10) = 1 << PIN_WR;
|
|
*(gpio + 10) = 0xffffec;
|
|
|
|
*(gpio + 7) = ((0x0100 | (address >> 16)) << 8) | (REG_ADDR_HI << PIN_A0);
|
|
*(gpio + 7) = 1 << PIN_WR;
|
|
*(gpio + 10) = 1 << PIN_WR;
|
|
*(gpio + 10) = 0xffffec;
|
|
|
|
*(gpio + 0) = GPFSEL0_INPUT;
|
|
*(gpio + 1) = GPFSEL1_INPUT;
|
|
*(gpio + 2) = GPFSEL2_INPUT;
|
|
|
|
while (*(gpio + 13) & (1 << PIN_TXN_IN_PROGRESS))
|
|
;
|
|
}
|
|
|
|
void ps_write_32(unsigned int address, unsigned int value) {
|
|
ps_write_16(address, value >> 16);
|
|
ps_write_16(address + 2, value);
|
|
}
|
|
|
|
unsigned int ps_read_16(unsigned int address) {
|
|
*(gpio + 0) = GPFSEL0_OUTPUT;
|
|
*(gpio + 1) = GPFSEL1_OUTPUT;
|
|
*(gpio + 2) = GPFSEL2_OUTPUT;
|
|
|
|
*(gpio + 7) = ((address & 0xffff) << 8) | (REG_ADDR_LO << PIN_A0);
|
|
*(gpio + 7) = 1 << PIN_WR;
|
|
*(gpio + 10) = 1 << PIN_WR;
|
|
*(gpio + 10) = 0xffffec;
|
|
|
|
*(gpio + 7) = ((0x0200 | (address >> 16)) << 8) | (REG_ADDR_HI << PIN_A0);
|
|
*(gpio + 7) = 1 << PIN_WR;
|
|
*(gpio + 10) = 1 << PIN_WR;
|
|
*(gpio + 10) = 0xffffec;
|
|
|
|
*(gpio + 0) = GPFSEL0_INPUT;
|
|
*(gpio + 1) = GPFSEL1_INPUT;
|
|
*(gpio + 2) = GPFSEL2_INPUT;
|
|
|
|
*(gpio + 7) = (REG_DATA << PIN_A0);
|
|
*(gpio + 7) = 1 << PIN_RD;
|
|
|
|
while (*(gpio + 13) & (1 << PIN_TXN_IN_PROGRESS))
|
|
;
|
|
|
|
unsigned int value = *(gpio + 13);
|
|
|
|
*(gpio + 10) = 0xffffec;
|
|
|
|
return (value >> 8) & 0xffff;
|
|
}
|
|
|
|
unsigned int ps_read_8(unsigned int address) {
|
|
*(gpio + 0) = GPFSEL0_OUTPUT;
|
|
*(gpio + 1) = GPFSEL1_OUTPUT;
|
|
*(gpio + 2) = GPFSEL2_OUTPUT;
|
|
|
|
*(gpio + 7) = ((address & 0xffff) << 8) | (REG_ADDR_LO << PIN_A0);
|
|
*(gpio + 7) = 1 << PIN_WR;
|
|
*(gpio + 10) = 1 << PIN_WR;
|
|
*(gpio + 10) = 0xffffec;
|
|
|
|
*(gpio + 7) = ((0x0300 | (address >> 16)) << 8) | (REG_ADDR_HI << PIN_A0);
|
|
*(gpio + 7) = 1 << PIN_WR;
|
|
*(gpio + 10) = 1 << PIN_WR;
|
|
*(gpio + 10) = 0xffffec;
|
|
|
|
*(gpio + 0) = GPFSEL0_INPUT;
|
|
*(gpio + 1) = GPFSEL1_INPUT;
|
|
*(gpio + 2) = GPFSEL2_INPUT;
|
|
|
|
*(gpio + 7) = (REG_DATA << PIN_A0);
|
|
*(gpio + 7) = 1 << PIN_RD;
|
|
|
|
while (*(gpio + 13) & (1 << PIN_TXN_IN_PROGRESS))
|
|
;
|
|
|
|
unsigned int value = *(gpio + 13);
|
|
|
|
*(gpio + 10) = 0xffffec;
|
|
|
|
value = (value >> 8) & 0xffff;
|
|
|
|
if ((address & 1) == 0)
|
|
return (value >> 8) & 0xff; // EVEN, A0=0,UDS
|
|
else
|
|
return value & 0xff; // ODD , A0=1,LDS
|
|
}
|
|
|
|
unsigned int ps_read_32(unsigned int address) {
|
|
unsigned int a = ps_read_16(address);
|
|
unsigned int b = ps_read_16(address + 2);
|
|
return (a << 16) | b;
|
|
}
|
|
|
|
void ps_write_status_reg(unsigned int value) {
|
|
*(gpio + 0) = GPFSEL0_OUTPUT;
|
|
*(gpio + 1) = GPFSEL1_OUTPUT;
|
|
*(gpio + 2) = GPFSEL2_OUTPUT;
|
|
|
|
*(gpio + 7) = ((value & 0xffff) << 8) | (REG_STATUS << PIN_A0);
|
|
|
|
*(gpio + 7) = 1 << PIN_WR;
|
|
*(gpio + 7) = 1 << PIN_WR; // delay
|
|
*(gpio + 10) = 1 << PIN_WR;
|
|
*(gpio + 10) = 0xffffec;
|
|
|
|
*(gpio + 0) = GPFSEL0_INPUT;
|
|
*(gpio + 1) = GPFSEL1_INPUT;
|
|
*(gpio + 2) = GPFSEL2_INPUT;
|
|
}
|
|
|
|
unsigned int ps_read_status_reg() {
|
|
*(gpio + 7) = (REG_STATUS << PIN_A0);
|
|
*(gpio + 7) = 1 << PIN_RD;
|
|
*(gpio + 7) = 1 << PIN_RD;
|
|
*(gpio + 7) = 1 << PIN_RD;
|
|
*(gpio + 7) = 1 << PIN_RD;
|
|
|
|
unsigned int value = *(gpio + 13);
|
|
|
|
*(gpio + 10) = 0xffffec;
|
|
|
|
return (value >> 8) & 0xffff;
|
|
}
|
|
|
|
void ps_reset_state_machine() {
|
|
ps_write_status_reg(STATUS_BIT_INIT);
|
|
usleep(1500);
|
|
ps_write_status_reg(0);
|
|
usleep(100);
|
|
}
|
|
|
|
void ps_pulse_reset() {
|
|
ps_write_status_reg(0);
|
|
usleep(100000);
|
|
ps_write_status_reg(STATUS_BIT_RESET);
|
|
}
|
|
|
|
unsigned int ps_get_ipl_zero() {
|
|
unsigned int value = *(gpio + 13);
|
|
return value & (1 << PIN_IPL_ZERO);
|
|
}
|
|
|
|
#define INT2_ENABLED 1
|
|
|
|
void ps_update_irq() {
|
|
unsigned int ipl = 0;
|
|
|
|
if (!ps_get_ipl_zero()) {
|
|
unsigned int status = ps_read_status_reg();
|
|
ipl = (status & 0xe000) >> 13;
|
|
}
|
|
|
|
/*if (ipl < 2 && INT2_ENABLED && emu_int2_req()) {
|
|
ipl = 2;
|
|
}*/
|
|
|
|
m68k_set_irq(ipl);
|
|
}
|