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: releng/10.2/sys/boot/uboot/lib/glue.c 265071 2014-04-29 00:45:42Z ian $");
29176348Smarcel
30233287Smarius#include <sys/types.h>
31233287Smarius
32233287Smarius#include <crc32.h>
33176348Smarcel#include <stand.h>
34176348Smarcel#include "api_public.h"
35176481Smarcel#include "glue.h"
36176348Smarcel
37176348Smarcel#ifdef DEBUG
38177152Sobrien#define	debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt,##args); } while (0)
39176348Smarcel#else
40177152Sobrien#define	debugf(fmt, args...)
41176348Smarcel#endif
42176348Smarcel
43176481Smarcel/* Some random address used by U-Boot. */
44182732Srajextern long uboot_address;
45176348Smarcel
46177152Sobrienstatic int
47177152Sobrienvalid_sig(struct api_signature *sig)
48176348Smarcel{
49176348Smarcel	uint32_t checksum;
50176348Smarcel	struct api_signature s;
51176348Smarcel
52176348Smarcel	if (sig == NULL)
53177108Sraj		return (0);
54176348Smarcel	/*
55176348Smarcel	 * Clear the checksum field (in the local copy) so as to calculate the
56176348Smarcel	 * CRC with the same initial contents as at the time when the sig was
57176348Smarcel	 * produced
58176348Smarcel	 */
59176348Smarcel	s = *sig;
60176348Smarcel	s.checksum = 0;
61176348Smarcel
62176348Smarcel	checksum = crc32((void *)&s, sizeof(struct api_signature));
63176348Smarcel
64176348Smarcel	if (checksum != sig->checksum)
65177108Sraj		return (0);
66176348Smarcel
67177108Sraj	return (1);
68176348Smarcel}
69176348Smarcel
70176348Smarcel/*
71176348Smarcel * Searches for the U-Boot API signature
72176348Smarcel *
73176348Smarcel * returns 1/0 depending on found/not found result
74176348Smarcel */
75177152Sobrienint
76177152Sobrienapi_search_sig(struct api_signature **sig)
77177152Sobrien{
78176481Smarcel	unsigned char *sp, *spend;
79176348Smarcel
80176348Smarcel	if (sig == NULL)
81177108Sraj		return (0);
82176348Smarcel
83176481Smarcel	if (uboot_address == 0)
84176481Smarcel		uboot_address = 255 * 1024 * 1024;
85176348Smarcel
86176481Smarcel	sp = (void *)(uboot_address & ~0x000fffff);
87183878Sraj	spend = sp + 0x00300000 - API_SIG_MAGLEN;
88176481Smarcel	while (sp < spend) {
89176348Smarcel		if (!bcmp(sp, API_SIG_MAGIC, API_SIG_MAGLEN)) {
90176348Smarcel			*sig = (struct api_signature *)sp;
91176348Smarcel			if (valid_sig(*sig))
92177108Sraj				return (1);
93176348Smarcel		}
94176348Smarcel		sp += API_SIG_MAGLEN;
95176348Smarcel	}
96176348Smarcel
97176348Smarcel	*sig = NULL;
98177108Sraj	return (0);
99176348Smarcel}
100176348Smarcel
101176348Smarcel/****************************************
102176348Smarcel *
103176348Smarcel * console
104176348Smarcel *
105176348Smarcel ****************************************/
106176348Smarcel
107177152Sobrienint
108177152Sobrienub_getc(void)
109176348Smarcel{
110176348Smarcel	int c;
111176348Smarcel
112176348Smarcel	if (!syscall(API_GETC, NULL, (uint32_t)&c))
113177108Sraj		return (-1);
114177108Sraj
115182732Sraj	return (c);
116176348Smarcel}
117176348Smarcel
118177152Sobrienint
119177152Sobrienub_tstc(void)
120176348Smarcel{
121176348Smarcel	int t;
122176348Smarcel
123176348Smarcel	if (!syscall(API_TSTC, NULL, (uint32_t)&t))
124177108Sraj		return (-1);
125176348Smarcel
126182732Sraj	return (t);
127176348Smarcel}
128176348Smarcel
129177152Sobrienvoid
130177152Sobrienub_putc(char c)
131176348Smarcel{
132177152Sobrien
133176348Smarcel	syscall(API_PUTC, NULL, (uint32_t)&c);
134176348Smarcel}
135176348Smarcel
136177152Sobrienvoid
137177152Sobrienub_puts(const char *s)
138176348Smarcel{
139177152Sobrien
140176348Smarcel	syscall(API_PUTS, NULL, (uint32_t)s);
141176348Smarcel}
142176348Smarcel
143176348Smarcel/****************************************
144176348Smarcel *
145176348Smarcel * system
146176348Smarcel *
147176348Smarcel ****************************************/
148176348Smarcel
149177152Sobrienvoid
150177152Sobrienub_reset(void)
151176348Smarcel{
152177152Sobrien
153176348Smarcel	syscall(API_RESET, NULL);
154176348Smarcel}
155176348Smarcel
156183598Srajstatic struct mem_region mr[UB_MAX_MR];
157176348Smarcelstatic struct sys_info si;
158176348Smarcel
159177152Sobrienstruct sys_info *
160177152Sobrienub_get_sys_info(void)
161176348Smarcel{
162176348Smarcel	int err = 0;
163177152Sobrien
164176348Smarcel	memset(&si, 0, sizeof(struct sys_info));
165176348Smarcel	si.mr = mr;
166183598Sraj	si.mr_no = UB_MAX_MR;
167176348Smarcel	memset(&mr, 0, sizeof(mr));
168177152Sobrien
169176348Smarcel	if (!syscall(API_GET_SYS_INFO, &err, (u_int32_t)&si))
170177108Sraj		return (NULL);
171176348Smarcel
172176348Smarcel	return ((err) ? NULL : &si);
173176348Smarcel}
174176348Smarcel
175176348Smarcel/****************************************
176176348Smarcel *
177176348Smarcel * timing
178176348Smarcel *
179176348Smarcel ****************************************/
180177108Sraj
181177152Sobrienvoid
182177152Sobrienub_udelay(unsigned long usec)
183176348Smarcel{
184177108Sraj
185176348Smarcel	syscall(API_UDELAY, NULL, &usec);
186176348Smarcel}
187176348Smarcel
188177152Sobrienunsigned long
189177152Sobrienub_get_timer(unsigned long base)
190176348Smarcel{
191176348Smarcel	unsigned long cur;
192177152Sobrien
193176348Smarcel	if (!syscall(API_GET_TIMER, NULL, &cur, &base))
194177108Sraj		return (0);
195176348Smarcel
196177108Sraj	return (cur);
197176348Smarcel}
198176348Smarcel
199176348Smarcel/****************************************************************************
200176348Smarcel *
201176348Smarcel * devices
202176348Smarcel *
203183598Sraj * Devices are identified by handles: numbers 0, 1, 2, ..., UB_MAX_DEV-1
204176348Smarcel *
205176348Smarcel ***************************************************************************/
206176348Smarcel
207183598Srajstatic struct device_info devices[UB_MAX_DEV];
208176348Smarcel
209177152Sobrienstruct device_info *
210177152Sobrienub_dev_get(int i)
211176348Smarcel{
212177152Sobrien
213183598Sraj	return ((i < 0 || i >= UB_MAX_DEV) ? NULL : &devices[i]);
214176348Smarcel}
215176348Smarcel
216176348Smarcel/*
217176348Smarcel * Enumerates the devices: fills out device_info elements in the devices[]
218176348Smarcel * array.
219176348Smarcel *
220176348Smarcel * returns:		number of devices found
221176348Smarcel */
222177152Sobrienint
223177152Sobrienub_dev_enum(void)
224176348Smarcel{
225176348Smarcel	struct device_info *di;
226176348Smarcel	int n = 0;
227176348Smarcel
228183598Sraj	memset(&devices, 0, sizeof(struct device_info) * UB_MAX_DEV);
229176348Smarcel	di = &devices[0];
230176348Smarcel
231176348Smarcel	if (!syscall(API_DEV_ENUM, NULL, di))
232177108Sraj		return (0);
233176348Smarcel
234176348Smarcel	while (di->cookie != NULL) {
235176348Smarcel
236183598Sraj		if (++n >= UB_MAX_DEV)
237176348Smarcel			break;
238176348Smarcel
239176348Smarcel		/* take another device_info */
240176348Smarcel		di++;
241176348Smarcel
242176348Smarcel		/* pass on the previous cookie */
243176348Smarcel		di->cookie = devices[n - 1].cookie;
244176348Smarcel
245176348Smarcel		if (!syscall(API_DEV_ENUM, NULL, di))
246182732Sraj			return (0);
247177108Sraj	}
248176348Smarcel
249177108Sraj	return (n);
250176348Smarcel}
251176348Smarcel
252176348Smarcel/*
253176348Smarcel * handle:	0-based id of the device
254176348Smarcel *
255176348Smarcel * returns:	0 when OK, err otherwise
256176348Smarcel */
257177152Sobrienint
258177152Sobrienub_dev_open(int handle)
259176348Smarcel{
260176348Smarcel	struct device_info *di;
261176348Smarcel	int err = 0;
262176348Smarcel
263183598Sraj	if (handle < 0 || handle >= UB_MAX_DEV)
264177108Sraj		return (API_EINVAL);
265176348Smarcel
266176348Smarcel	di = &devices[handle];
267176348Smarcel	if (!syscall(API_DEV_OPEN, &err, di))
268177108Sraj		return (-1);
269176348Smarcel
270177108Sraj	return (err);
271176348Smarcel}
272176348Smarcel
273177152Sobrienint
274177152Sobrienub_dev_close(int handle)
275176348Smarcel{
276176348Smarcel	struct device_info *di;
277176348Smarcel
278183598Sraj	if (handle < 0 || handle >= UB_MAX_DEV)
279177108Sraj		return (API_EINVAL);
280176348Smarcel
281176348Smarcel	di = &devices[handle];
282176348Smarcel	if (!syscall(API_DEV_CLOSE, NULL, di))
283177108Sraj		return (-1);
284176348Smarcel
285177108Sraj	return (0);
286176348Smarcel}
287176348Smarcel
288176348Smarcel/*
289176348Smarcel * Validates device for read/write, it has to:
290176348Smarcel *
291176348Smarcel * - have sane handle
292176348Smarcel * - be opened
293176348Smarcel *
294176348Smarcel * returns:	0/1 accordingly
295176348Smarcel */
296177152Sobrienstatic int
297177152Sobriendev_valid(int handle)
298176348Smarcel{
299177108Sraj
300183598Sraj	if (handle < 0 || handle >= UB_MAX_DEV)
301177108Sraj		return (0);
302176348Smarcel
303176348Smarcel	if (devices[handle].state != DEV_STA_OPEN)
304177108Sraj		return (0);
305176348Smarcel
306177108Sraj	return (1);
307176348Smarcel}
308176348Smarcel
309177152Sobrienstatic int
310177152Sobriendev_stor_valid(int handle)
311176348Smarcel{
312177108Sraj
313176348Smarcel	if (!dev_valid(handle))
314177108Sraj		return (0);
315176348Smarcel
316176348Smarcel	if (!(devices[handle].type & DEV_TYP_STOR))
317177108Sraj		return (0);
318176348Smarcel
319177108Sraj	return (1);
320176348Smarcel}
321176348Smarcel
322177152Sobrienint
323183598Srajub_dev_read(int handle, void *buf, lbasize_t len, lbastart_t start,
324183598Sraj    lbasize_t *rlen)
325176348Smarcel{
326176348Smarcel	struct device_info *di;
327176348Smarcel	lbasize_t act_len;
328176348Smarcel	int err = 0;
329176348Smarcel
330176348Smarcel	if (!dev_stor_valid(handle))
331177108Sraj		return (API_ENODEV);
332176348Smarcel
333176348Smarcel	di = &devices[handle];
334176348Smarcel	if (!syscall(API_DEV_READ, &err, di, buf, &len, &start, &act_len))
335183598Sraj		return (API_ESYSC);
336176348Smarcel
337183598Sraj	if (!err && rlen)
338183598Sraj		*rlen = act_len;
339176348Smarcel
340183598Sraj	return (err);
341176348Smarcel}
342176348Smarcel
343177152Sobrienstatic int
344177152Sobriendev_net_valid(int handle)
345176348Smarcel{
346177108Sraj
347176348Smarcel	if (!dev_valid(handle))
348177108Sraj		return (0);
349176348Smarcel
350176348Smarcel	if (devices[handle].type != DEV_TYP_NET)
351177108Sraj		return (0);
352176348Smarcel
353177108Sraj	return (1);
354176348Smarcel}
355176348Smarcel
356177152Sobrienint
357183598Srajub_dev_recv(int handle, void *buf, int len, int *rlen)
358176348Smarcel{
359176348Smarcel	struct device_info *di;
360176348Smarcel	int err = 0, act_len;
361176348Smarcel
362176348Smarcel	if (!dev_net_valid(handle))
363177108Sraj		return (API_ENODEV);
364176348Smarcel
365176348Smarcel	di = &devices[handle];
366176348Smarcel	if (!syscall(API_DEV_READ, &err, di, buf, &len, &act_len))
367183598Sraj		return (API_ESYSC);
368176348Smarcel
369183598Sraj	if (!err)
370183598Sraj		*rlen = act_len;
371176348Smarcel
372183598Sraj	return (err);
373176348Smarcel}
374176348Smarcel
375177152Sobrienint
376177152Sobrienub_dev_send(int handle, void *buf, int len)
377176348Smarcel{
378176348Smarcel	struct device_info *di;
379176348Smarcel	int err = 0;
380176348Smarcel
381176348Smarcel	if (!dev_net_valid(handle))
382177108Sraj		return (API_ENODEV);
383176348Smarcel
384176348Smarcel	di = &devices[handle];
385176348Smarcel	if (!syscall(API_DEV_WRITE, &err, di, buf, &len))
386183598Sraj		return (API_ESYSC);
387176348Smarcel
388177108Sraj	return (err);
389176348Smarcel}
390176348Smarcel
391185099Srajchar *
392182732Srajub_stor_type(int type)
393182732Sraj{
394182732Sraj
395182732Sraj	if (type & DT_STOR_IDE)
396182732Sraj		return ("IDE");
397182732Sraj
398182732Sraj	if (type & DT_STOR_SCSI)
399182732Sraj		return ("SCSI");
400182732Sraj
401182732Sraj	if (type & DT_STOR_USB)
402182732Sraj		return ("USB");
403182732Sraj
404199193Santoine	if (type & DT_STOR_MMC)
405182732Sraj		return ("MMC");
406182732Sraj
407265071Sian	if (type & DT_STOR_SATA)
408265071Sian		return ("SATA");
409235609Sgber
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