1122715Sbde/*-
2122715Sbde * Copyright (c) 2007-2008 Semihalf, Rafal Jaworowski <raj@semihalf.com>
3122715Sbde * All rights reserved.
4122715Sbde *
5122715Sbde * Redistribution and use in source and binary forms, with or without
685909Simp * modification, are permitted provided that the following conditions
788893Simp * are met:
888893Simp * 1. Redistributions of source code must retain the above copyright
988969Simp *    notice, this list of conditions and the following disclaimer.
1085909Simp * 2. Redistributions in binary form must reproduce the above copyright
11115572Sphk *    notice, this list of conditions and the following disclaimer in the
12115572Sphk *    documentation and/or other materials provided with the distribution.
13115572Sphk *
14115572Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15191794Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16191794Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17115572Sphk * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18205640Snetchild * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19205640Snetchild * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20205640Snetchild * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21205640Snetchild * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22206082Snetchild * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23206082Snetchild * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24206082Snetchild * SUCH DAMAGE.
25206082Snetchild */
26111211Sru
2785909Simp#include <sys/cdefs.h>
28111802Sru__FBSDID("$FreeBSD$");
29111802Sru
30111211Sru#include <sys/types.h>
31111211Sru
32111211Sru#include <crc32.h>
33111211Sru#include <stand.h>
34111802Sru#include "api_public.h"
35111802Sru#include "glue.h"
36111211Sru
37111211Sru#ifdef DEBUG
3885909Simp#define	debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt,##args); } while (0)
39137596Simp#else
40147155Simp#define	debugf(fmt, args...)
41137596Simp#endif
42147011Smux
43142424Simp/* Some random address used by U-Boot. */
44142413Simpextern long uboot_address;
45137596Simp
46147011Smuxstatic int
47137596Simpvalid_sig(struct api_signature *sig)
48137596Simp{
49137596Simp	uint32_t checksum;
50137596Simp	struct api_signature s;
51111211Sru
52111211Sru	if (sig == NULL)
53167845Simp		return (0);
54111211Sru	/*
55155427Sru	 * Clear the checksum field (in the local copy) so as to calculate the
56111802Sru	 * CRC with the same initial contents as at the time when the sig was
57111802Sru	 * produced
58111766Sru	 */
59111211Sru	s = *sig;
60111766Sru	s.checksum = 0;
61111766Sru
62111211Sru	checksum = crc32((void *)&s, sizeof(struct api_signature));
63111211Sru
64111211Sru	if (checksum != sig->checksum)
65111211Sru		return (0);
66111211Sru
67111211Sru	return (1);
68111211Sru}
69111211Sru
70151636Simp/*
71151636Simp * Searches for the U-Boot API signature
72151636Simp *
73151636Simp * returns 1/0 depending on found/not found result
74151750Sru */
75151750Sruint
76151731Sruapi_search_sig(struct api_signature **sig)
77151750Sru{
78151731Sru	unsigned char *sp, *spend;
79151646Sru
80151646Sru	if (sig == NULL)
81116252Sgrog		return (0);
82123965Sbde
83116252Sgrog	if (uboot_address == 0)
84123965Sbde		uboot_address = 255 * 1024 * 1024;
85123965Sbde
86135611Sphk	sp = (void *)(uboot_address & ~0x000fffff);
87124776Sru	spend = sp + 0x00300000 - API_SIG_MAGLEN;
88116252Sgrog	while (sp < spend) {
89123965Sbde		if (!bcmp(sp, API_SIG_MAGIC, API_SIG_MAGLEN)) {
9085909Simp			*sig = (struct api_signature *)sp;
91124776Sru			if (valid_sig(*sig))
9285909Simp				return (1);
93151636Simp		}
9485909Simp		sp += API_SIG_MAGLEN;
9585909Simp	}
9685909Simp
97206082Snetchild	*sig = NULL;
98125775Sru	return (0);
99125775Sru}
100125775Sru
10185909Simp/****************************************
102159560Scognet *
103175984Sraj * console
104159560Scognet *
10585909Simp ****************************************/
106116691Sru
107131129Simpint
10885909Simpub_getc(void)
10985909Simp{
110116341Smarkm	int c;
111116341Smarkm
11285909Simp	if (!syscall(API_GETC, NULL, (uint32_t)&c))
113102082Sbde		return (-1);
114102082Sbde
115102082Sbde	return (c);
116102082Sbde}
11785909Simp
11895844Sobrienint
11985909Simpub_tstc(void)
12085909Simp{
12185909Simp	int t;
12285909Simp
123151750Sru	if (!syscall(API_TSTC, NULL, (uint32_t)&t))
124151731Sru		return (-1);
125145416Sru
126123965Sbde	return (t);
127163332Sru}
12885909Simp
129116341Smarkmvoid
130123965Sbdeub_putc(char c)
131123965Sbde{
13292491Smarkm
13385909Simp	syscall(API_PUTC, NULL, (uint32_t)&c);
13485909Simp}
13585909Simp
13685909Simpvoid
13785909Simpub_puts(const char *s)
138161283Sdes{
139123966Sbde
14085909Simp	syscall(API_PUTS, NULL, (uint32_t)s);
14185909Simp}
142123965Sbde
14385909Simp/****************************************
14485909Simp *
14585909Simp * system
146127306Sobrien *
14785909Simp ****************************************/
14885909Simp
149123985Sbdevoid
15085909Simpub_reset(void)
15185909Simp{
15285909Simp
153145403Sru	syscall(API_RESET, NULL);
154102073Sbde}
15591104Sjake
156152964Srustatic struct mem_region mr[UB_MAX_MR];
157152964Srustatic struct sys_info si;
158152964Sru
159163332Srustruct sys_info *
16085909Simpub_get_sys_info(void)
161131210Simp{
162102073Sbde	int err = 0;
163111684Sru
164102073Sbde	memset(&si, 0, sizeof(struct sys_info));
16585909Simp	si.mr = mr;
16685909Simp	si.mr_no = UB_MAX_MR;
16785909Simp	memset(&mr, 0, sizeof(mr));
168152964Sru
169152964Sru	if (!syscall(API_GET_SYS_INFO, &err, (u_int32_t)&si))
170152964Sru		return (NULL);
171152964Sru
172152964Sru	return ((err) ? NULL : &si);
173152964Sru}
174152964Sru
175152964Sru/****************************************
176152964Sru *
177152964Sru * timing
178152964Sru *
179152964Sru ****************************************/
180152964Sru
181152964Sruvoid
182152964Sruub_udelay(unsigned long usec)
183152964Sru{
184152964Sru
185152964Sru	syscall(API_UDELAY, NULL, &usec);
186152964Sru}
187152964Sru
188152964Sruunsigned long
189152964Sruub_get_timer(unsigned long base)
190163332Sru{
19185909Simp	unsigned long cur;
192163332Sru
19385909Simp	if (!syscall(API_GET_TIMER, NULL, &cur, &base))
19485909Simp		return (0);
19585909Simp
196123965Sbde	return (cur);
19791046Sluigi}
198123965Sbde
199123965Sbde/****************************************************************************
20085909Simp *
20185909Simp * devices
20285909Simp *
20385909Simp * Devices are identified by handles: numbers 0, 1, 2, ..., UB_MAX_DEV-1
20485909Simp *
20585909Simp ***************************************************************************/
206127246Smarcel
207151731Srustatic struct device_info devices[UB_MAX_DEV];
20885909Simp
20985909Simpstruct device_info *
21085909Simpub_dev_get(int i)
21185909Simp{
21285909Simp
213145623Sru	return ((i < 0 || i >= UB_MAX_DEV) ? NULL : &devices[i]);
21485909Simp}
21585909Simp
21685909Simp/*
21785909Simp * Enumerates the devices: fills out device_info elements in the devices[]
21885909Simp * array.
21985909Simp *
22085909Simp * returns:		number of devices found
22185909Simp */
222118633Sruint
22385909Simpub_dev_enum(void)
22485909Simp{
22585909Simp	struct device_info *di;
226186854Sbz	int n = 0;
227151636Simp
228186854Sbz	memset(&devices, 0, sizeof(struct device_info) * UB_MAX_DEV);
229151636Simp	di = &devices[0];
230167845Simp
231186854Sbz	if (!syscall(API_DEV_ENUM, NULL, di))
232167845Simp		return (0);
23385909Simp
234167845Simp	while (di->cookie != NULL) {
235167845Simp
23695356Sru		if (++n >= UB_MAX_DEV)
23785909Simp			break;
238186854Sbz
239151636Simp		/* take another device_info */
240186854Sbz		di++;
241151636Simp
24285909Simp		/* pass on the previous cookie */
243144293Sphk		di->cookie = devices[n - 1].cookie;
24485909Simp
245206082Snetchild		if (!syscall(API_DEV_ENUM, NULL, di))
24685909Simp			return (0);
247144293Sphk	}
248116341Smarkm
249116341Smarkm	return (n);
25085909Simp}
251135371Sru
25285909Simp/*
25391512Sobrien * handle:	0-based id of the device
25491512Sobrien *
25585909Simp * returns:	0 when OK, err otherwise
256163705Sru */
257163705Sruint
258163705Sruub_dev_open(int handle)
25991512Sobrien{
260163705Sru	struct device_info *di;
261138290Sphk	int err = 0;
262163705Sru
263138290Sphk	if (handle < 0 || handle >= UB_MAX_DEV)
26485909Simp		return (API_EINVAL);
265116691Sru
266116691Sru	di = &devices[handle];
26785909Simp	if (!syscall(API_DEV_OPEN, &err, di))
268111686Sru		return (-1);
269
270	return (err);
271}
272
273int
274ub_dev_close(int handle)
275{
276	struct device_info *di;
277
278	if (handle < 0 || handle >= UB_MAX_DEV)
279		return (API_EINVAL);
280
281	di = &devices[handle];
282	if (!syscall(API_DEV_CLOSE, NULL, di))
283		return (-1);
284
285	return (0);
286}
287
288/*
289 * Validates device for read/write, it has to:
290 *
291 * - have sane handle
292 * - be opened
293 *
294 * returns:	0/1 accordingly
295 */
296static int
297dev_valid(int handle)
298{
299
300	if (handle < 0 || handle >= UB_MAX_DEV)
301		return (0);
302
303	if (devices[handle].state != DEV_STA_OPEN)
304		return (0);
305
306	return (1);
307}
308
309static int
310dev_stor_valid(int handle)
311{
312
313	if (!dev_valid(handle))
314		return (0);
315
316	if (!(devices[handle].type & DEV_TYP_STOR))
317		return (0);
318
319	return (1);
320}
321
322int
323ub_dev_read(int handle, void *buf, lbasize_t len, lbastart_t start,
324    lbasize_t *rlen)
325{
326	struct device_info *di;
327	lbasize_t act_len;
328	int err = 0;
329
330	if (!dev_stor_valid(handle))
331		return (API_ENODEV);
332
333	di = &devices[handle];
334	if (!syscall(API_DEV_READ, &err, di, buf, &len, &start, &act_len))
335		return (API_ESYSC);
336
337	if (!err && rlen)
338		*rlen = act_len;
339
340	return (err);
341}
342
343static int
344dev_net_valid(int handle)
345{
346
347	if (!dev_valid(handle))
348		return (0);
349
350	if (devices[handle].type != DEV_TYP_NET)
351		return (0);
352
353	return (1);
354}
355
356int
357ub_dev_recv(int handle, void *buf, int len, int *rlen)
358{
359	struct device_info *di;
360	int err = 0, act_len;
361
362	if (!dev_net_valid(handle))
363		return (API_ENODEV);
364
365	di = &devices[handle];
366	if (!syscall(API_DEV_READ, &err, di, buf, &len, &act_len))
367		return (API_ESYSC);
368
369	if (!err)
370		*rlen = act_len;
371
372	return (err);
373}
374
375int
376ub_dev_send(int handle, void *buf, int len)
377{
378	struct device_info *di;
379	int err = 0;
380
381	if (!dev_net_valid(handle))
382		return (API_ENODEV);
383
384	di = &devices[handle];
385	if (!syscall(API_DEV_WRITE, &err, di, buf, &len))
386		return (API_ESYSC);
387
388	return (err);
389}
390
391char *
392ub_stor_type(int type)
393{
394
395	if (type & DT_STOR_IDE)
396		return ("IDE");
397
398	if (type & DT_STOR_SCSI)
399		return ("SCSI");
400
401	if (type & DT_STOR_USB)
402		return ("USB");
403
404	if (type & DT_STOR_MMC)
405		return ("MMC");
406
407	if (type & DT_STOR_SATA)
408		return ("SATA");
409
410	return ("Unknown");
411}
412
413char *
414ub_mem_type(int flags)
415{
416
417	switch (flags & 0x000F) {
418	case MR_ATTR_FLASH:
419		return ("FLASH");
420	case MR_ATTR_DRAM:
421		return ("DRAM");
422	case MR_ATTR_SRAM:
423		return ("SRAM");
424	default:
425		return ("Unknown");
426	}
427}
428
429void
430ub_dump_di(int handle)
431{
432	struct device_info *di = ub_dev_get(handle);
433	int i;
434
435	printf("device info (%d):\n", handle);
436	printf("  cookie\t= 0x%08x\n", (uint32_t)di->cookie);
437	printf("  type\t\t= 0x%08x\n", di->type);
438
439	if (di->type == DEV_TYP_NET) {
440		printf("  hwaddr\t= ");
441		for (i = 0; i < 6; i++)
442			printf("%02x ", di->di_net.hwaddr[i]);
443
444		printf("\n");
445
446	} else if (di->type & DEV_TYP_STOR) {
447		printf("  type\t\t= %s\n", ub_stor_type(di->type));
448		printf("  blk size\t\t= %ld\n", di->di_stor.block_size);
449		printf("  blk count\t\t= %ld\n", di->di_stor.block_count);
450	}
451}
452
453void
454ub_dump_si(struct sys_info *si)
455{
456	int i;
457
458	printf("sys info:\n");
459	printf("  clkbus\t= %ld MHz\n", si->clk_bus / 1000 / 1000);
460	printf("  clkcpu\t= %ld MHz\n", si->clk_cpu / 1000 / 1000);
461	printf("  bar\t\t= 0x%08lx\n", si->bar);
462
463	printf("---\n");
464	for (i = 0; i < si->mr_no; i++) {
465		if (si->mr[i].flags == 0)
466			break;
467
468		printf("  start\t= 0x%08lx\n", si->mr[i].start);
469		printf("  size\t= 0x%08lx\n", si->mr[i].size);
470		printf("  type\t= %s\n", ub_mem_type(si->mr[i].flags));
471		printf("---\n");
472	}
473}
474
475/****************************************
476 *
477 * env vars
478 *
479 ****************************************/
480
481char *
482ub_env_get(const char *name)
483{
484	char *value;
485
486	if (!syscall(API_ENV_GET, NULL, (uint32_t)name, (uint32_t)&value))
487		return (NULL);
488
489	return (value);
490}
491
492void
493ub_env_set(const char *name, char *value)
494{
495
496	syscall(API_ENV_SET, NULL, (uint32_t)name, (uint32_t)value);
497}
498
499static char env_name[256];
500
501const char *
502ub_env_enum(const char *last)
503{
504	const char *env, *str;
505	int i;
506
507	/*
508	 * It's OK to pass only the name piece as last (and not the whole
509	 * 'name=val' string), since the API_ENUM_ENV call uses envmatch()
510	 * internally, which handles such case
511	 */
512	env = NULL;
513	if (!syscall(API_ENV_ENUM, NULL, (uint32_t)last, (uint32_t)&env))
514		return (NULL);
515
516	if (env == NULL)
517		/* no more env. variables to enumerate */
518		return (NULL);
519
520	/* next enumerated env var */
521	memset(env_name, 0, 256);
522	for (i = 0, str = env; *str != '=' && *str != '\0';)
523		env_name[i++] = *str++;
524
525	env_name[i] = '\0';
526
527	return (env_name);
528}
529