1176348Smarcel/*-
2182732Sraj * Copyright (c) 2007-2008 Semihalf, Rafal Jaworowski <raj@semihalf.com>
3176348Smarcel * All rights reserved.
4176348Smarcel *
5176348Smarcel * Redistribution and use in source and binary forms, with or without
6176348Smarcel * modification, are permitted provided that the following conditions
7176348Smarcel * are met:
8176348Smarcel * 1. Redistributions of source code must retain the above copyright
9176348Smarcel *    notice, this list of conditions and the following disclaimer.
10176348Smarcel * 2. Redistributions in binary form must reproduce the above copyright
11176348Smarcel *    notice, this list of conditions and the following disclaimer in the
12176348Smarcel *    documentation and/or other materials provided with the distribution.
13176348Smarcel *
14176348Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15176348Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16176348Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17176348Smarcel * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18176348Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19176348Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20176348Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21176348Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22176348Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23176348Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24176348Smarcel * SUCH DAMAGE.
25176348Smarcel */
26176348Smarcel
27176348Smarcel#include <sys/cdefs.h>
28176348Smarcel__FBSDID("$FreeBSD$");
29176348Smarcel
30233719Smarius#include <sys/types.h>
31233719Smarius
32233719Smarius#include <crc32.h>
33176348Smarcel#include <stand.h>
34176348Smarcel#include "api_public.h"
35176481Smarcel#include "glue.h"
36176348Smarcel
37176481Smarcel#define DEBUG
38176348Smarcel#undef DEBUG
39176348Smarcel
40176348Smarcel#ifdef DEBUG
41177152Sobrien#define	debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt,##args); } while (0)
42176348Smarcel#else
43177152Sobrien#define	debugf(fmt, args...)
44176348Smarcel#endif
45176348Smarcel
46176481Smarcel/* Some random address used by U-Boot. */
47182732Srajextern long uboot_address;
48176348Smarcel
49177152Sobrienstatic int
50177152Sobrienvalid_sig(struct api_signature *sig)
51176348Smarcel{
52176348Smarcel	uint32_t checksum;
53176348Smarcel	struct api_signature s;
54176348Smarcel
55176348Smarcel	if (sig == NULL)
56177108Sraj		return (0);
57176348Smarcel	/*
58176348Smarcel	 * Clear the checksum field (in the local copy) so as to calculate the
59176348Smarcel	 * CRC with the same initial contents as at the time when the sig was
60176348Smarcel	 * produced
61176348Smarcel	 */
62176348Smarcel	s = *sig;
63176348Smarcel	s.checksum = 0;
64176348Smarcel
65176348Smarcel	checksum = crc32((void *)&s, sizeof(struct api_signature));
66176348Smarcel
67176348Smarcel	if (checksum != sig->checksum)
68177108Sraj		return (0);
69176348Smarcel
70177108Sraj	return (1);
71176348Smarcel}
72176348Smarcel
73176348Smarcel/*
74176348Smarcel * Searches for the U-Boot API signature
75176348Smarcel *
76176348Smarcel * returns 1/0 depending on found/not found result
77176348Smarcel */
78177152Sobrienint
79177152Sobrienapi_search_sig(struct api_signature **sig)
80177152Sobrien{
81176481Smarcel	unsigned char *sp, *spend;
82176348Smarcel
83176348Smarcel	if (sig == NULL)
84177108Sraj		return (0);
85176348Smarcel
86176481Smarcel	if (uboot_address == 0)
87176481Smarcel		uboot_address = 255 * 1024 * 1024;
88176348Smarcel
89176481Smarcel	sp = (void *)(uboot_address & ~0x000fffff);
90183878Sraj	spend = sp + 0x00300000 - API_SIG_MAGLEN;
91176481Smarcel	while (sp < spend) {
92176348Smarcel		if (!bcmp(sp, API_SIG_MAGIC, API_SIG_MAGLEN)) {
93176348Smarcel			*sig = (struct api_signature *)sp;
94176348Smarcel			if (valid_sig(*sig))
95177108Sraj				return (1);
96176348Smarcel		}
97176348Smarcel		sp += API_SIG_MAGLEN;
98176348Smarcel	}
99176348Smarcel
100176348Smarcel	*sig = NULL;
101177108Sraj	return (0);
102176348Smarcel}
103176348Smarcel
104176348Smarcel/****************************************
105176348Smarcel *
106176348Smarcel * console
107176348Smarcel *
108176348Smarcel ****************************************/
109176348Smarcel
110177152Sobrienint
111177152Sobrienub_getc(void)
112176348Smarcel{
113176348Smarcel	int c;
114176348Smarcel
115176348Smarcel	if (!syscall(API_GETC, NULL, (uint32_t)&c))
116177108Sraj		return (-1);
117177108Sraj
118182732Sraj	return (c);
119176348Smarcel}
120176348Smarcel
121177152Sobrienint
122177152Sobrienub_tstc(void)
123176348Smarcel{
124176348Smarcel	int t;
125176348Smarcel
126176348Smarcel	if (!syscall(API_TSTC, NULL, (uint32_t)&t))
127177108Sraj		return (-1);
128176348Smarcel
129182732Sraj	return (t);
130176348Smarcel}
131176348Smarcel
132177152Sobrienvoid
133177152Sobrienub_putc(char c)
134176348Smarcel{
135177152Sobrien
136176348Smarcel	syscall(API_PUTC, NULL, (uint32_t)&c);
137176348Smarcel}
138176348Smarcel
139177152Sobrienvoid
140177152Sobrienub_puts(const char *s)
141176348Smarcel{
142177152Sobrien
143176348Smarcel	syscall(API_PUTS, NULL, (uint32_t)s);
144176348Smarcel}
145176348Smarcel
146176348Smarcel/****************************************
147176348Smarcel *
148176348Smarcel * system
149176348Smarcel *
150176348Smarcel ****************************************/
151176348Smarcel
152177152Sobrienvoid
153177152Sobrienub_reset(void)
154176348Smarcel{
155177152Sobrien
156176348Smarcel	syscall(API_RESET, NULL);
157176348Smarcel}
158176348Smarcel
159183598Srajstatic struct mem_region mr[UB_MAX_MR];
160176348Smarcelstatic struct sys_info si;
161176348Smarcel
162177152Sobrienstruct sys_info *
163177152Sobrienub_get_sys_info(void)
164176348Smarcel{
165176348Smarcel	int err = 0;
166177152Sobrien
167176348Smarcel	memset(&si, 0, sizeof(struct sys_info));
168176348Smarcel	si.mr = mr;
169183598Sraj	si.mr_no = UB_MAX_MR;
170176348Smarcel	memset(&mr, 0, sizeof(mr));
171177152Sobrien
172176348Smarcel	if (!syscall(API_GET_SYS_INFO, &err, (u_int32_t)&si))
173177108Sraj		return (NULL);
174176348Smarcel
175176348Smarcel	return ((err) ? NULL : &si);
176176348Smarcel}
177176348Smarcel
178176348Smarcel/****************************************
179176348Smarcel *
180176348Smarcel * timing
181176348Smarcel *
182176348Smarcel ****************************************/
183177108Sraj
184177152Sobrienvoid
185177152Sobrienub_udelay(unsigned long usec)
186176348Smarcel{
187177108Sraj
188176348Smarcel	syscall(API_UDELAY, NULL, &usec);
189176348Smarcel}
190176348Smarcel
191177152Sobrienunsigned long
192177152Sobrienub_get_timer(unsigned long base)
193176348Smarcel{
194176348Smarcel	unsigned long cur;
195177152Sobrien
196176348Smarcel	if (!syscall(API_GET_TIMER, NULL, &cur, &base))
197177108Sraj		return (0);
198176348Smarcel
199177108Sraj	return (cur);
200176348Smarcel}
201176348Smarcel
202176348Smarcel/****************************************************************************
203176348Smarcel *
204176348Smarcel * devices
205176348Smarcel *
206183598Sraj * Devices are identified by handles: numbers 0, 1, 2, ..., UB_MAX_DEV-1
207176348Smarcel *
208176348Smarcel ***************************************************************************/
209176348Smarcel
210183598Srajstatic struct device_info devices[UB_MAX_DEV];
211176348Smarcel
212177152Sobrienstruct device_info *
213177152Sobrienub_dev_get(int i)
214176348Smarcel{
215177152Sobrien
216183598Sraj	return ((i < 0 || i >= UB_MAX_DEV) ? NULL : &devices[i]);
217176348Smarcel}
218176348Smarcel
219176348Smarcel/*
220176348Smarcel * Enumerates the devices: fills out device_info elements in the devices[]
221176348Smarcel * array.
222176348Smarcel *
223176348Smarcel * returns:		number of devices found
224176348Smarcel */
225177152Sobrienint
226177152Sobrienub_dev_enum(void)
227176348Smarcel{
228176348Smarcel	struct device_info *di;
229176348Smarcel	int n = 0;
230176348Smarcel
231183598Sraj	memset(&devices, 0, sizeof(struct device_info) * UB_MAX_DEV);
232176348Smarcel	di = &devices[0];
233176348Smarcel
234176348Smarcel	if (!syscall(API_DEV_ENUM, NULL, di))
235177108Sraj		return (0);
236176348Smarcel
237176348Smarcel	while (di->cookie != NULL) {
238176348Smarcel
239183598Sraj		if (++n >= UB_MAX_DEV)
240176348Smarcel			break;
241176348Smarcel
242176348Smarcel		/* take another device_info */
243176348Smarcel		di++;
244176348Smarcel
245176348Smarcel		/* pass on the previous cookie */
246176348Smarcel		di->cookie = devices[n - 1].cookie;
247176348Smarcel
248176348Smarcel		if (!syscall(API_DEV_ENUM, NULL, di))
249182732Sraj			return (0);
250177108Sraj	}
251176348Smarcel
252177108Sraj	return (n);
253176348Smarcel}
254176348Smarcel
255176348Smarcel/*
256176348Smarcel * handle:	0-based id of the device
257176348Smarcel *
258176348Smarcel * returns:	0 when OK, err otherwise
259176348Smarcel */
260177152Sobrienint
261177152Sobrienub_dev_open(int handle)
262176348Smarcel{
263176348Smarcel	struct device_info *di;
264176348Smarcel	int err = 0;
265176348Smarcel
266183598Sraj	if (handle < 0 || handle >= UB_MAX_DEV)
267177108Sraj		return (API_EINVAL);
268176348Smarcel
269176348Smarcel	di = &devices[handle];
270176348Smarcel	if (!syscall(API_DEV_OPEN, &err, di))
271177108Sraj		return (-1);
272176348Smarcel
273177108Sraj	return (err);
274176348Smarcel}
275176348Smarcel
276177152Sobrienint
277177152Sobrienub_dev_close(int handle)
278176348Smarcel{
279176348Smarcel	struct device_info *di;
280176348Smarcel
281183598Sraj	if (handle < 0 || handle >= UB_MAX_DEV)
282177108Sraj		return (API_EINVAL);
283176348Smarcel
284176348Smarcel	di = &devices[handle];
285176348Smarcel	if (!syscall(API_DEV_CLOSE, NULL, di))
286177108Sraj		return (-1);
287176348Smarcel
288177108Sraj	return (0);
289176348Smarcel}
290176348Smarcel
291176348Smarcel/*
292176348Smarcel * Validates device for read/write, it has to:
293176348Smarcel *
294176348Smarcel * - have sane handle
295176348Smarcel * - be opened
296176348Smarcel *
297176348Smarcel * returns:	0/1 accordingly
298176348Smarcel */
299177152Sobrienstatic int
300177152Sobriendev_valid(int handle)
301176348Smarcel{
302177108Sraj
303183598Sraj	if (handle < 0 || handle >= UB_MAX_DEV)
304177108Sraj		return (0);
305176348Smarcel
306176348Smarcel	if (devices[handle].state != DEV_STA_OPEN)
307177108Sraj		return (0);
308176348Smarcel
309177108Sraj	return (1);
310176348Smarcel}
311176348Smarcel
312177152Sobrienstatic int
313177152Sobriendev_stor_valid(int handle)
314176348Smarcel{
315177108Sraj
316176348Smarcel	if (!dev_valid(handle))
317177108Sraj		return (0);
318176348Smarcel
319176348Smarcel	if (!(devices[handle].type & DEV_TYP_STOR))
320177108Sraj		return (0);
321176348Smarcel
322177108Sraj	return (1);
323176348Smarcel}
324176348Smarcel
325177152Sobrienint
326183598Srajub_dev_read(int handle, void *buf, lbasize_t len, lbastart_t start,
327183598Sraj    lbasize_t *rlen)
328176348Smarcel{
329176348Smarcel	struct device_info *di;
330176348Smarcel	lbasize_t act_len;
331176348Smarcel	int err = 0;
332176348Smarcel
333176348Smarcel	if (!dev_stor_valid(handle))
334177108Sraj		return (API_ENODEV);
335176348Smarcel
336176348Smarcel	di = &devices[handle];
337176348Smarcel	if (!syscall(API_DEV_READ, &err, di, buf, &len, &start, &act_len))
338183598Sraj		return (API_ESYSC);
339176348Smarcel
340183598Sraj	if (!err && rlen)
341183598Sraj		*rlen = act_len;
342176348Smarcel
343183598Sraj	return (err);
344176348Smarcel}
345176348Smarcel
346177152Sobrienstatic int
347177152Sobriendev_net_valid(int handle)
348176348Smarcel{
349177108Sraj
350176348Smarcel	if (!dev_valid(handle))
351177108Sraj		return (0);
352176348Smarcel
353176348Smarcel	if (devices[handle].type != DEV_TYP_NET)
354177108Sraj		return (0);
355176348Smarcel
356177108Sraj	return (1);
357176348Smarcel}
358176348Smarcel
359177152Sobrienint
360183598Srajub_dev_recv(int handle, void *buf, int len, int *rlen)
361176348Smarcel{
362176348Smarcel	struct device_info *di;
363176348Smarcel	int err = 0, act_len;
364176348Smarcel
365176348Smarcel	if (!dev_net_valid(handle))
366177108Sraj		return (API_ENODEV);
367176348Smarcel
368176348Smarcel	di = &devices[handle];
369176348Smarcel	if (!syscall(API_DEV_READ, &err, di, buf, &len, &act_len))
370183598Sraj		return (API_ESYSC);
371176348Smarcel
372183598Sraj	if (!err)
373183598Sraj		*rlen = act_len;
374176348Smarcel
375183598Sraj	return (err);
376176348Smarcel}
377176348Smarcel
378177152Sobrienint
379177152Sobrienub_dev_send(int handle, void *buf, int len)
380176348Smarcel{
381176348Smarcel	struct device_info *di;
382176348Smarcel	int err = 0;
383176348Smarcel
384176348Smarcel	if (!dev_net_valid(handle))
385177108Sraj		return (API_ENODEV);
386176348Smarcel
387176348Smarcel	di = &devices[handle];
388176348Smarcel	if (!syscall(API_DEV_WRITE, &err, di, buf, &len))
389183598Sraj		return (API_ESYSC);
390176348Smarcel
391177108Sraj	return (err);
392176348Smarcel}
393176348Smarcel
394185099Srajchar *
395182732Srajub_stor_type(int type)
396182732Sraj{
397182732Sraj
398182732Sraj	if (type & DT_STOR_IDE)
399182732Sraj		return ("IDE");
400182732Sraj
401182732Sraj	if (type & DT_STOR_SCSI)
402182732Sraj		return ("SCSI");
403182732Sraj
404182732Sraj	if (type & DT_STOR_USB)
405182732Sraj		return ("USB");
406182732Sraj
407199193Santoine	if (type & DT_STOR_MMC)
408182732Sraj		return ("MMC");
409182732Sraj
410182732Sraj	return ("Unknown");
411182732Sraj}
412182732Sraj
413182732Srajchar *
414182732Srajub_mem_type(int flags)
415182732Sraj{
416182732Sraj
417183599Sraj	switch (flags & 0x000F) {
418182732Sraj	case MR_ATTR_FLASH:
419182732Sraj		return ("FLASH");
420182732Sraj	case MR_ATTR_DRAM:
421182732Sraj		return ("DRAM");
422182732Sraj	case MR_ATTR_SRAM:
423182732Sraj		return ("SRAM");
424182732Sraj	default:
425182732Sraj		return ("Unknown");
426182732Sraj	}
427182732Sraj}
428182732Sraj
429182732Srajvoid
430182732Srajub_dump_di(int handle)
431182732Sraj{
432182732Sraj	struct device_info *di = ub_dev_get(handle);
433182732Sraj	int i;
434182732Sraj
435182732Sraj	printf("device info (%d):\n", handle);
436182732Sraj	printf("  cookie\t= 0x%08x\n", (uint32_t)di->cookie);
437182732Sraj	printf("  type\t\t= 0x%08x\n", di->type);
438182732Sraj
439182732Sraj	if (di->type == DEV_TYP_NET) {
440182732Sraj		printf("  hwaddr\t= ");
441182732Sraj		for (i = 0; i < 6; i++)
442182732Sraj			printf("%02x ", di->di_net.hwaddr[i]);
443182732Sraj
444182732Sraj		printf("\n");
445182732Sraj
446182732Sraj	} else if (di->type & DEV_TYP_STOR) {
447182732Sraj		printf("  type\t\t= %s\n", ub_stor_type(di->type));
448182732Sraj		printf("  blk size\t\t= %ld\n", di->di_stor.block_size);
449182732Sraj		printf("  blk count\t\t= %ld\n", di->di_stor.block_count);
450182732Sraj	}
451182732Sraj}
452182732Sraj
453182732Srajvoid
454182732Srajub_dump_si(struct sys_info *si)
455182732Sraj{
456182732Sraj	int i;
457182732Sraj
458182732Sraj	printf("sys info:\n");
459182732Sraj	printf("  clkbus\t= %ld MHz\n", si->clk_bus / 1000 / 1000);
460182732Sraj	printf("  clkcpu\t= %ld MHz\n", si->clk_cpu / 1000 / 1000);
461182732Sraj	printf("  bar\t\t= 0x%08lx\n", si->bar);
462182732Sraj
463182732Sraj	printf("---\n");
464182732Sraj	for (i = 0; i < si->mr_no; i++) {
465182732Sraj		if (si->mr[i].flags == 0)
466182732Sraj			break;
467182732Sraj
468182732Sraj		printf("  start\t= 0x%08lx\n", si->mr[i].start);
469182732Sraj		printf("  size\t= 0x%08lx\n", si->mr[i].size);
470182732Sraj		printf("  type\t= %s\n", ub_mem_type(si->mr[i].flags));
471182732Sraj		printf("---\n");
472182732Sraj	}
473182732Sraj}
474182732Sraj
475176348Smarcel/****************************************
476176348Smarcel *
477176348Smarcel * env vars
478176348Smarcel *
479176348Smarcel ****************************************/
480176348Smarcel
481177152Sobrienchar *
482177152Sobrienub_env_get(const char *name)
483176348Smarcel{
484176348Smarcel	char *value;
485176348Smarcel
486176348Smarcel	if (!syscall(API_ENV_GET, NULL, (uint32_t)name, (uint32_t)&value))
487177108Sraj		return (NULL);
488176348Smarcel
489177108Sraj	return (value);
490176348Smarcel}
491176348Smarcel
492177152Sobrienvoid
493177152Sobrienub_env_set(const char *name, char *value)
494176348Smarcel{
495177108Sraj
496176348Smarcel	syscall(API_ENV_SET, NULL, (uint32_t)name, (uint32_t)value);
497176348Smarcel}
498176348Smarcel
499176348Smarcelstatic char env_name[256];
500176348Smarcel
501177152Sobrienconst char *
502177152Sobrienub_env_enum(const char *last)
503176348Smarcel{
504176348Smarcel	const char *env, *str;
505176348Smarcel	int i;
506176348Smarcel
507176348Smarcel	/*
508176348Smarcel	 * It's OK to pass only the name piece as last (and not the whole
509176348Smarcel	 * 'name=val' string), since the API_ENUM_ENV call uses envmatch()
510176348Smarcel	 * internally, which handles such case
511176348Smarcel	 */
512200691Smarcel	env = NULL;
513208535Sraj	if (!syscall(API_ENV_ENUM, NULL, (uint32_t)last, (uint32_t)&env))
514177108Sraj		return (NULL);
515176348Smarcel
516200691Smarcel	if (env == NULL)
517176348Smarcel		/* no more env. variables to enumerate */
518177108Sraj		return (NULL);
519176348Smarcel
520176348Smarcel	/* next enumerated env var */
521176348Smarcel	memset(env_name, 0, 256);
522176348Smarcel	for (i = 0, str = env; *str != '=' && *str != '\0';)
523176348Smarcel		env_name[i++] = *str++;
524176348Smarcel
525176348Smarcel	env_name[i] = '\0';
526176348Smarcel
527177108Sraj	return (env_name);
528176348Smarcel}
529