1 /*
2 * (C) Copyright 2011 Henrik Nordstrom <henrik@henriknordstrom.net>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
17 * MA 02111-1307 USA
18 */
19
20 #include <errno.h>
21 #include <stdio.h>
22 #include <stdint.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #ifndef NO_MMAP
28 #include <sys/mman.h>
29 #endif
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33
34 #include "common.h"
35 #include "portable_endian.h"
36
37 #define PIO_REG_SIZE 0x228 /*0x300*/
38 #define PIO_PORT_SIZE 0x24
39
40 struct pio_status {
41 int mul_sel;
42 int pull;
43 int drv_level;
44 int data;
45 };
46
47 #define PIO_REG_CFG(B, N, I) ((B) + (N)*0x24 + ((I)<<2) + 0x00)
48 #define PIO_REG_DLEVEL(B, N, I) ((B) + (N)*0x24 + ((I)<<2) + 0x14)
49 #define PIO_REG_PULL(B, N, I) ((B) + (N)*0x24 + ((I)<<2) + 0x1C)
50 #define PIO_REG_DATA(B, N) ((B) + (N)*0x24 + 0x10)
51 #define PIO_NR_PORTS 9 /* A-I */
52
53 #define LE32TOH(X) le32toh(*((uint32_t*)(X)))
54
pio_get(const char * buf,uint32_t port,uint32_t port_num,struct pio_status * pio)55 static int pio_get(const char *buf, uint32_t port, uint32_t port_num, struct pio_status *pio)
56 {
57 uint32_t val;
58 uint32_t port_num_func, port_num_pull;
59 uint32_t offset_func, offset_pull;
60
61 port_num_func = port_num >> 3;
62 offset_func = ((port_num & 0x07) << 2);
63
64 port_num_pull = port_num >> 4;
65 offset_pull = ((port_num & 0x0f) << 1);
66
67 /* func */
68 val = LE32TOH(PIO_REG_CFG(buf, port, port_num_func));
69 pio->mul_sel = (val>>offset_func) & 0x07;
70
71 /* pull */
72 val = LE32TOH(PIO_REG_PULL(buf, port, port_num_pull));
73 pio->pull = (val>>offset_pull) & 0x03;
74
75 /* dlevel */
76 val = LE32TOH(PIO_REG_DLEVEL(buf, port, port_num_pull));
77 pio->drv_level = (val>>offset_pull) & 0x03;
78
79 /* i/o data */
80 if (pio->mul_sel > 1)
81 pio->data = -1;
82 else {
83 val = LE32TOH(PIO_REG_DATA(buf, port));
84 pio->data = (val >> port_num) & 0x01;
85 }
86 return 1;
87 }
88
pio_set(char * buf,uint32_t port,uint32_t port_num,struct pio_status * pio)89 static int pio_set(char *buf, uint32_t port, uint32_t port_num, struct pio_status *pio)
90 {
91 uint32_t *addr, val;
92 uint32_t port_num_func, port_num_pull;
93 uint32_t offset_func, offset_pull;
94
95 port_num_func = port_num >> 3;
96 offset_func = ((port_num & 0x07) << 2);
97
98 port_num_pull = port_num >> 4;
99 offset_pull = ((port_num & 0x0f) << 1);
100
101 /* func */
102 if (pio->mul_sel >= 0) {
103 addr = (uint32_t*)PIO_REG_CFG(buf, port, port_num_func);
104 val = le32toh(*addr);
105 val &= ~(0x07 << offset_func);
106 val |= (pio->mul_sel & 0x07) << offset_func;
107 *addr = htole32(val);
108 }
109
110 /* pull */
111 if (pio->pull >= 0) {
112 addr = (uint32_t*)PIO_REG_PULL(buf, port, port_num_pull);
113 val = le32toh(*addr);
114 val &= ~(0x03 << offset_pull);
115 val |= (pio->pull & 0x03) << offset_pull;
116 *addr = htole32(val);
117 }
118
119 /* dlevel */
120 if (pio->drv_level >= 0) {
121 addr = (uint32_t*)PIO_REG_DLEVEL(buf, port, port_num_pull);
122 val = le32toh(*addr);
123 val &= ~(0x03 << offset_pull);
124 val |= (pio->drv_level & 0x03) << offset_pull;
125 *addr = htole32(val);
126 }
127
128 /* data */
129 if (pio->data >= 0) {
130 addr = (uint32_t*)PIO_REG_DATA(buf, port);
131 val = le32toh(*addr);
132 if (pio->data)
133 val |= (0x01 << port_num);
134 else
135 val &= ~(0x01 << port_num);
136 *addr = htole32(val);
137 }
138
139 return 1;
140 }
141
pio_print(int port,int port_nr,struct pio_status * pio)142 static void pio_print(int port, int port_nr, struct pio_status *pio)
143 {
144 printf("P%c%d", 'A'+port, port_nr);
145 printf("<%x>", pio->mul_sel);
146 printf("<%x>", pio->pull);
147 printf("<%x>", pio->drv_level);
148 if (pio->data >= 0)
149 printf("<%x>", pio->data);
150 fputc('\n', stdout);
151 }
152
print(const char * buf)153 static void print(const char *buf)
154 {
155 int port, i;
156 struct pio_status pio;
157 for (port=0; port < PIO_NR_PORTS; port++) {
158 for (i=0; i<32; i++) {
159 if (pio_get(buf, port, i, &pio)) {
160 pio_print(port, i, &pio);
161 }
162 }
163 }
164 }
165
166 static const char *argv0;
167
usage(int rc)168 static void usage(int rc )
169 {
170 fputs("sunxi-pio " VERSION "\n\n", stderr);
171 fprintf(stderr, "usage: %s -m|-i input [-o output] pin..\n", argv0);
172 fprintf(stderr," -m mmap - read pin state from system\n");
173 fprintf(stderr," -i read pin state from file\n");
174 fprintf(stderr," -o save pin state data to file\n");
175 fprintf(stderr," print Show all pins\n");
176 fprintf(stderr," Pxx Show pin\n");
177 fprintf(stderr," Pxx<mode><pull><drive><data> Configure pin\n");
178 fprintf(stderr," Pxx=data,drive Configure GPIO output\n");
179 fprintf(stderr," Pxx*count Oscillate GPIO output (mmap mode only)\n");
180 fprintf(stderr," Pxx?pull Configure GPIO input\n");
181 fprintf(stderr," clean Clean input pins\n");
182 fprintf(stderr, "\n mode 0-7, 0=input, 1=ouput, 2-7 I/O function\n");
183 fprintf(stderr, " pull 0=none, 1=up, 2=down\n");
184 fprintf(stderr, " drive 0-3, I/O drive level\n");
185
186 exit(rc);
187 }
188
parse_pin(int * port,int * pin,const char * name)189 static void parse_pin(int *port, int *pin, const char *name)
190 {
191 if (*name == 'P') name++;
192 *port = *name++ - 'A';
193 *pin = atoi(name);
194 }
195
cmd_show_pin(char * buf,const char * pin)196 static void cmd_show_pin(char *buf, const char *pin)
197 {
198 int port, port_nr;
199 struct pio_status pio;
200 parse_pin(&port, &port_nr, pin);
201 if (!pio_get(buf, port, port_nr, &pio))
202 usage(1);
203 pio_print(port, port_nr, &pio);
204 }
205
parse_int(int * dst,const char * in)206 static int parse_int(int *dst, const char *in)
207 {
208 int value;
209 char *next;
210 errno = 0;
211 value = strtol(in, &next, 0);
212 if (!errno && next != in) {
213 *dst = value;
214 return 0;
215 }
216 return -1;
217 }
218
cmd_set_pin(char * buf,const char * pin)219 static void cmd_set_pin(char *buf, const char *pin)
220 {
221 int port, port_nr;
222 const char *t = pin;
223 struct pio_status pio;
224 parse_pin(&port, &port_nr, pin);
225 if (!pio_get(buf, port, port_nr, &pio))
226 usage(1);
227 if ((t = strchr(pin, '='))) {
228 pio.mul_sel = 1;
229 if (t) {
230 t++;
231 parse_int(&pio.data, t);
232 }
233 if (t)
234 t = strchr(t, ',');
235 if (t) {
236 t++;
237 parse_int(&pio.drv_level, t);
238 }
239 } else if ((t = strchr(pin, '?'))) {
240 pio.mul_sel = 0;
241 pio.data = 0;
242 pio.drv_level = 0;
243 if (t) {
244 t++;
245 parse_int(&pio.pull, t);
246 }
247 } else if ((t = strchr(pin, '<'))) {
248 if (t) {
249 t++;
250 parse_int(&pio.mul_sel, t);
251 }
252 if (t)
253 t = strchr(t, '<');
254 if (t) {
255 t++;
256 parse_int(&pio.pull, t);
257 }
258 if (t)
259 t = strchr(t, '<');
260 if (t) {
261 t++;
262 parse_int(&pio.drv_level, t);
263 }
264 if (t)
265 t = strchr(t, '<');
266 if (t) {
267 t++;
268 parse_int(&pio.data, t);
269 }
270 }
271 pio_set(buf, port, port_nr, &pio);
272 }
273
cmd_oscillate(char * buf,const char * pin)274 static void cmd_oscillate(char *buf, const char *pin)
275 {
276 int port, port_nr;
277 const char *t = pin;
278 int i, n = 0;
279 uint32_t *addr, val;
280
281 parse_pin(&port, &port_nr, pin);
282 {
283 struct pio_status pio;
284 if (!pio_get(buf, port, port_nr, &pio))
285 usage(1);
286 pio.mul_sel = 1;
287 pio_set(buf, port, port_nr, &pio);
288 }
289
290 addr = (uint32_t*)PIO_REG_DATA(buf, port);
291 t = strchr(pin, '*');
292 parse_int(&n, t+1);
293 val = le32toh(*addr);
294 for (i = 0; i < n; i++) {
295 val ^= 1 << port_nr;
296 *addr = htole32(val);
297 }
298 }
299
cmd_clean(char * buf)300 static void cmd_clean(char *buf)
301 {
302 int port, i;
303 struct pio_status pio;
304 for (port=0; port < PIO_NR_PORTS; port++) {
305 for (i=0; i<32; i++) {
306 if (pio_get(buf, port, i, &pio)) {
307 if (pio.mul_sel == 0) {
308 pio.data = 0;
309 pio_set(buf, port, i, &pio);
310 }
311 }
312 }
313 }
314 }
315
do_command(char * buf,const char ** args,int UNUSED (argc))316 static int do_command(char *buf, const char **args, int UNUSED(argc))
317 {
318 const char *command = args[0];
319 if (*command == 'P') {
320 if (strchr(command, '<'))
321 cmd_set_pin(buf, command);
322 else if (strchr(command, '='))
323 cmd_set_pin(buf, command);
324 else if (strchr(command, '?'))
325 cmd_set_pin(buf, command);
326 else if (strchr(command, '*'))
327 cmd_oscillate(buf, command);
328 else
329 cmd_show_pin(buf, command);
330 }
331 else if (strcmp(command, "print") == 0)
332 print(buf);
333 else if (strcmp(command, "clean") == 0)
334 cmd_clean(buf);
335 else usage(1);
336 return 1;
337 }
338
main(int argc,char ** argv)339 int main(int argc, char **argv)
340 {
341 int opt;
342 FILE *in = NULL;
343 FILE *out = NULL;
344 const char *in_name = NULL;
345 const char *out_name = NULL;
346 char buf_[PIO_REG_SIZE];
347 char *buf = buf_;
348 int do_mmap = 0;
349
350 argv0 = argv[0];
351
352 while ((opt = getopt(argc, argv, "i:o:m")) != -1) {
353 switch(opt) {
354 case '?':
355 usage(0);
356 case 'm':
357 do_mmap = 1;
358 break;
359 case 'i':
360 in_name = optarg;
361 break;
362 case 'o':
363 out_name = optarg;
364 break;
365 }
366 }
367 if (!in_name && !do_mmap)
368 usage(1);
369 if (do_mmap) {
370 #ifdef NO_MMAP
371 errno = ENOSYS; /* Function not implemented */
372 perror("mmap PIO");
373 #else
374 int pagesize = sysconf(_SC_PAGESIZE);
375 int fd = open("/dev/mem",O_RDWR);
376 int addr = 0x01c20800 & ~(pagesize-1);
377 int offset = 0x01c20800 & (pagesize-1);
378 if (fd == -1) {
379 perror("open /dev/mem");
380 exit(1);
381 }
382 buf = mmap(NULL, (0x800 + pagesize - 1) & ~(pagesize-1), PROT_WRITE|PROT_READ, MAP_SHARED, fd, addr);
383 if (!buf) {
384 perror("mmap PIO");
385 exit(1);
386 }
387 close(fd);
388 buf += offset;
389 #endif
390 }
391 if (in_name) {
392 if (strcmp(in_name, "-") == 0) {
393 in = stdin;
394 } else {
395 in = fopen(in_name, "rb");
396 if (!in) {
397 perror("open input");
398 exit(1);
399 }
400 }
401 }
402 if (in) {
403 if (fread(buf, PIO_REG_SIZE, 1, in) != 1) {
404 perror("read input");
405 exit(1);
406 }
407 if (in != stdin)
408 fclose(in);
409 }
410
411 while(optind < argc) {
412 optind += do_command(buf, (const char **)(argv + optind), argc - optind);
413 }
414
415 if (out_name) {
416 if (strcmp(out_name, "-") == 0) {
417 out = stdout;
418 } else {
419 out = fopen(out_name, "wb");
420 if (!out) {
421 perror("open output");
422 exit(1);
423 }
424 }
425 if (fwrite(buf, PIO_REG_SIZE, 1, out) != 1) {
426 perror("write output");
427 exit(1);
428 }
429 }
430 }
431