]> git.sesse.net Git - pistorm/blob - gpio/ps_protocol.c
Fix config reload?
[pistorm] / gpio / ps_protocol.c
1 // SPDX-License-Identifier: MIT
2
3 /*
4   Original Copyright 2020 Claude Schwarz
5   Code reorganized and rewritten by
6   Niklas Ekström 2021 (https://github.com/niklasekstrom)
7 */
8
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <stddef.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <sys/mman.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include <unistd.h>
18
19 #include "ps_protocol.h"
20 #include "m68k.h"
21
22 volatile unsigned int *gpio;
23 volatile unsigned int *gpclk;
24
25 unsigned int gpfsel0;
26 unsigned int gpfsel1;
27 unsigned int gpfsel2;
28
29 unsigned int gpfsel0_o;
30 unsigned int gpfsel1_o;
31 unsigned int gpfsel2_o;
32
33 static void setup_io() {
34   int fd = open("/dev/mem", O_RDWR | O_SYNC);
35   if (fd < 0) {
36     printf("Unable to open /dev/mem. Run as root using sudo?\n");
37     exit(-1);
38   }
39
40   void *gpio_map = mmap(
41       NULL,                    // Any adddress in our space will do
42       BCM2708_PERI_SIZE,       // Map length
43       PROT_READ | PROT_WRITE,  // Enable reading & writting to mapped memory
44       MAP_SHARED,              // Shared with other processes
45       fd,                      // File to map
46       BCM2708_PERI_BASE        // Offset to GPIO peripheral
47   );
48
49   close(fd);
50
51   if (gpio_map == MAP_FAILED) {
52     printf("mmap failed, errno = %d\n", errno);
53     exit(-1);
54   }
55
56   gpio = ((volatile unsigned *)gpio_map) + GPIO_ADDR / 4;
57   gpclk = ((volatile unsigned *)gpio_map) + GPCLK_ADDR / 4;
58 }
59
60 static void setup_gpclk() {
61   // Enable 200MHz CLK output on GPIO4, adjust divider and pll source depending
62   // on pi model
63   *(gpclk + (CLK_GP0_CTL / 4)) = CLK_PASSWD | (1 << 5);
64   usleep(10);
65   while ((*(gpclk + (CLK_GP0_CTL / 4))) & (1 << 7))
66     ;
67   usleep(100);
68   *(gpclk + (CLK_GP0_DIV / 4)) =
69       CLK_PASSWD | (6 << 12);  // divider , 6=200MHz on pi3
70   usleep(10);
71   *(gpclk + (CLK_GP0_CTL / 4)) =
72       CLK_PASSWD | 5 | (1 << 4);  // pll? 6=plld, 5=pllc
73   usleep(10);
74   while (((*(gpclk + (CLK_GP0_CTL / 4))) & (1 << 7)) == 0)
75     ;
76   usleep(100);
77
78   SET_GPIO_ALT(PIN_CLK, 0);  // gpclk0
79 }
80
81 void ps_setup_protocol() {
82   setup_io();
83   setup_gpclk();
84
85   *(gpio + 10) = 0xffffec;
86
87   *(gpio + 0) = GPFSEL0_INPUT;
88   *(gpio + 1) = GPFSEL1_INPUT;
89   *(gpio + 2) = GPFSEL2_INPUT;
90 }
91
92 void ps_write_16(unsigned int address, unsigned int data) {
93   *(gpio + 0) = GPFSEL0_OUTPUT;
94   *(gpio + 1) = GPFSEL1_OUTPUT;
95   *(gpio + 2) = GPFSEL2_OUTPUT;
96
97   *(gpio + 7) = ((data & 0xffff) << 8) | (REG_DATA << PIN_A0);
98   *(gpio + 7) = 1 << PIN_WR;
99   *(gpio + 10) = 1 << PIN_WR;
100   *(gpio + 10) = 0xffffec;
101
102   *(gpio + 7) = ((address & 0xffff) << 8) | (REG_ADDR_LO << PIN_A0);
103   *(gpio + 7) = 1 << PIN_WR;
104   *(gpio + 10) = 1 << PIN_WR;
105   *(gpio + 10) = 0xffffec;
106
107   *(gpio + 7) = ((0x0000 | (address >> 16)) << 8) | (REG_ADDR_HI << PIN_A0);
108   *(gpio + 7) = 1 << PIN_WR;
109   *(gpio + 10) = 1 << PIN_WR;
110   *(gpio + 10) = 0xffffec;
111
112   *(gpio + 0) = GPFSEL0_INPUT;
113   *(gpio + 1) = GPFSEL1_INPUT;
114   *(gpio + 2) = GPFSEL2_INPUT;
115
116   while (*(gpio + 13) & (1 << PIN_TXN_IN_PROGRESS))
117     ;
118 }
119
120 void ps_write_8(unsigned int address, unsigned int data) {
121   if ((address & 1) == 0)
122     data = data + (data << 8);  // EVEN, A0=0,UDS
123   else
124     data = data & 0xff;  // ODD , A0=1,LDS
125
126   *(gpio + 0) = GPFSEL0_OUTPUT;
127   *(gpio + 1) = GPFSEL1_OUTPUT;
128   *(gpio + 2) = GPFSEL2_OUTPUT;
129
130   *(gpio + 7) = ((data & 0xffff) << 8) | (REG_DATA << PIN_A0);
131   *(gpio + 7) = 1 << PIN_WR;
132   *(gpio + 10) = 1 << PIN_WR;
133   *(gpio + 10) = 0xffffec;
134
135   *(gpio + 7) = ((address & 0xffff) << 8) | (REG_ADDR_LO << PIN_A0);
136   *(gpio + 7) = 1 << PIN_WR;
137   *(gpio + 10) = 1 << PIN_WR;
138   *(gpio + 10) = 0xffffec;
139
140   *(gpio + 7) = ((0x0100 | (address >> 16)) << 8) | (REG_ADDR_HI << PIN_A0);
141   *(gpio + 7) = 1 << PIN_WR;
142   *(gpio + 10) = 1 << PIN_WR;
143   *(gpio + 10) = 0xffffec;
144
145   *(gpio + 0) = GPFSEL0_INPUT;
146   *(gpio + 1) = GPFSEL1_INPUT;
147   *(gpio + 2) = GPFSEL2_INPUT;
148
149   while (*(gpio + 13) & (1 << PIN_TXN_IN_PROGRESS))
150     ;
151 }
152
153 void ps_write_32(unsigned int address, unsigned int value) {
154   ps_write_16(address, value >> 16);
155   ps_write_16(address + 2, value);
156 }
157
158 unsigned int ps_read_16(unsigned int address) {
159   *(gpio + 0) = GPFSEL0_OUTPUT;
160   *(gpio + 1) = GPFSEL1_OUTPUT;
161   *(gpio + 2) = GPFSEL2_OUTPUT;
162
163   *(gpio + 7) = ((address & 0xffff) << 8) | (REG_ADDR_LO << PIN_A0);
164   *(gpio + 7) = 1 << PIN_WR;
165   *(gpio + 10) = 1 << PIN_WR;
166   *(gpio + 10) = 0xffffec;
167
168   *(gpio + 7) = ((0x0200 | (address >> 16)) << 8) | (REG_ADDR_HI << PIN_A0);
169   *(gpio + 7) = 1 << PIN_WR;
170   *(gpio + 10) = 1 << PIN_WR;
171   *(gpio + 10) = 0xffffec;
172
173   *(gpio + 0) = GPFSEL0_INPUT;
174   *(gpio + 1) = GPFSEL1_INPUT;
175   *(gpio + 2) = GPFSEL2_INPUT;
176
177   *(gpio + 7) = (REG_DATA << PIN_A0);
178   *(gpio + 7) = 1 << PIN_RD;
179
180   unsigned int value = *(gpio + 13);
181   while ((value=*(gpio + 13)) & (1 << PIN_TXN_IN_PROGRESS))
182     ;
183
184   *(gpio + 10) = 0xffffec;
185
186   return (value >> 8) & 0xffff;
187 }
188
189 unsigned int ps_read_8(unsigned int address) {
190   *(gpio + 0) = GPFSEL0_OUTPUT;
191   *(gpio + 1) = GPFSEL1_OUTPUT;
192   *(gpio + 2) = GPFSEL2_OUTPUT;
193
194   *(gpio + 7) = ((address & 0xffff) << 8) | (REG_ADDR_LO << PIN_A0);
195   *(gpio + 7) = 1 << PIN_WR;
196   *(gpio + 10) = 1 << PIN_WR;
197   *(gpio + 10) = 0xffffec;
198
199   *(gpio + 7) = ((0x0300 | (address >> 16)) << 8) | (REG_ADDR_HI << PIN_A0);
200   *(gpio + 7) = 1 << PIN_WR;
201   *(gpio + 10) = 1 << PIN_WR;
202   *(gpio + 10) = 0xffffec;
203
204   *(gpio + 0) = GPFSEL0_INPUT;
205   *(gpio + 1) = GPFSEL1_INPUT;
206   *(gpio + 2) = GPFSEL2_INPUT;
207
208   *(gpio + 7) = (REG_DATA << PIN_A0);
209   *(gpio + 7) = 1 << PIN_RD;
210
211   unsigned int value = *(gpio + 13);
212   while ((value=*(gpio + 13)) & (1 << PIN_TXN_IN_PROGRESS))
213     ;
214
215   *(gpio + 10) = 0xffffec;
216
217   value = (value >> 8) & 0xffff;
218
219   if ((address & 1) == 0)
220     return (value >> 8) & 0xff;  // EVEN, A0=0,UDS
221   else
222     return value & 0xff;  // ODD , A0=1,LDS
223 }
224
225 unsigned int ps_read_32(unsigned int address) {
226   unsigned int a = ps_read_16(address);
227   unsigned int b = ps_read_16(address + 2);
228   return (a << 16) | b;
229 }
230
231 void ps_write_status_reg(unsigned int value) {
232   *(gpio + 0) = GPFSEL0_OUTPUT;
233   *(gpio + 1) = GPFSEL1_OUTPUT;
234   *(gpio + 2) = GPFSEL2_OUTPUT;
235
236   *(gpio + 7) = ((value & 0xffff) << 8) | (REG_STATUS << PIN_A0);
237
238   *(gpio + 7) = 1 << PIN_WR;
239   *(gpio + 7) = 1 << PIN_WR;  // delay
240   *(gpio + 10) = 1 << PIN_WR;
241   *(gpio + 10) = 0xffffec;
242
243   *(gpio + 0) = GPFSEL0_INPUT;
244   *(gpio + 1) = GPFSEL1_INPUT;
245   *(gpio + 2) = GPFSEL2_INPUT;
246 }
247
248 unsigned int ps_read_status_reg() {
249   *(gpio + 7) = (REG_STATUS << PIN_A0);
250   *(gpio + 7) = 1 << PIN_RD;
251   *(gpio + 7) = 1 << PIN_RD;
252   *(gpio + 7) = 1 << PIN_RD;
253   *(gpio + 7) = 1 << PIN_RD;
254
255   unsigned int value = *(gpio + 13);
256
257   *(gpio + 10) = 0xffffec;
258
259   return (value >> 8) & 0xffff;
260 }
261
262 void ps_reset_state_machine() {
263   ps_write_status_reg(STATUS_BIT_INIT);
264   usleep(1500);
265   ps_write_status_reg(0);
266   usleep(100);
267 }
268
269 void ps_pulse_reset() {
270   ps_write_status_reg(0);
271   usleep(100000);
272   ps_write_status_reg(STATUS_BIT_RESET);
273 }
274
275 unsigned int ps_get_ipl_zero() {
276   unsigned int value = *(gpio + 13);
277   return value & (1 << PIN_IPL_ZERO);
278 }
279
280 #define INT2_ENABLED 1
281
282 void ps_update_irq() {
283   unsigned int ipl = 0;
284
285   if (!ps_get_ipl_zero()) {
286     unsigned int status = ps_read_status_reg();
287     ipl = (status & 0xe000) >> 13;
288   }
289
290   /*if (ipl < 2 && INT2_ENABLED && emu_int2_req()) {
291     ipl = 2;
292   }*/
293
294   m68k_set_irq(ipl);
295 }