Compare commits
33 Commits
lldb-2
...
rpi_fix_sd
| Author | SHA1 | Date | |
|---|---|---|---|
| 2ac629943d | |||
| 9ffc21964a | |||
| 5a7163ed5e | |||
|
|
c95010bf0e | ||
|
|
394a5878ef | ||
|
|
944242a42c | ||
|
|
d0f19da8ee | ||
|
|
364990d9da | ||
|
|
25de27fbcb | ||
|
|
8e0800e994 | ||
|
|
7442558681 | ||
|
|
dab346e282 | ||
|
|
fc93b4db26 | ||
|
|
88661079be | ||
|
|
ef69c49d79 | ||
|
|
65def63cad | ||
|
|
03eaf9dac8 | ||
|
|
6192a53b2d | ||
|
|
add751549f | ||
|
|
e70062feb3 | ||
|
|
7b468ec005 | ||
|
|
63723e1e7b | ||
|
|
cde275c049 | ||
|
|
cecc3c0d18 | ||
|
|
7cbfcd26a2 | ||
|
|
b76b176eaf | ||
|
|
1e7d6ee8a7 | ||
|
|
aed435f2cf | ||
|
|
61569864b0 | ||
|
|
c5e7db6fac | ||
|
|
1fb1a5c17c | ||
|
|
04a7b1091f | ||
|
|
ad60a889a0 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -9,6 +9,7 @@ cscope.*
|
||||
*.rej
|
||||
*.[1-9].gz
|
||||
*.o
|
||||
*.elf
|
||||
*.[psS]o
|
||||
*.pico
|
||||
lib*.so*
|
||||
|
||||
@@ -16,13 +16,18 @@
|
||||
./etc/system.conf.d/usbd minix-base
|
||||
./service/bmp085 minix-base
|
||||
./service/cat24c256 minix-base
|
||||
./service/emmc minix-base
|
||||
./service/fb minix-base
|
||||
./service/gpio minix-base
|
||||
./service/i2c minix-base
|
||||
./service/i2c_omap minix-base
|
||||
./service/i2c_rpi minix-base
|
||||
./service/lan8710a minix-base
|
||||
./service/mmc minix-base
|
||||
./service/mailbox minix-base
|
||||
./service/omap_emmc minix-base
|
||||
./service/omap_mmc minix-base
|
||||
./service/random minix-base
|
||||
./service/rpi_emmc minix-base
|
||||
./service/rpi_mmc minix-base
|
||||
./service/sht21 minix-base
|
||||
./service/tda19988 minix-base
|
||||
./service/tps65217 minix-base
|
||||
|
||||
@@ -707,6 +707,8 @@
|
||||
./usr/lib/libexpat.so minix-base
|
||||
./usr/lib/libexpat.so.2 minix-base
|
||||
./usr/lib/libexpat.so.2.1 minix-base
|
||||
./usr/lib/libfdt.a minix-base
|
||||
./usr/lib/libfdt_pic.a minix-base
|
||||
./usr/lib/libfetch.so minix-base
|
||||
./usr/lib/libfetch.so.3 minix-base
|
||||
./usr/lib/libfetch.so.3.0 minix-base
|
||||
|
||||
@@ -331,6 +331,7 @@
|
||||
./usr/include/expat.h minix-comp
|
||||
./usr/include/expat_external.h minix-comp
|
||||
./usr/include/fcntl.h minix-comp
|
||||
./usr/include/fdt.h minix-comp
|
||||
./usr/include/fenv.h minix-comp
|
||||
./usr/include/fetch.h minix-comp
|
||||
./usr/include/float.h minix-comp
|
||||
@@ -1125,6 +1126,9 @@
|
||||
./usr/include/libdde/usb_server.h minix-comp
|
||||
./usr/include/libelf.h minix-comp
|
||||
./usr/include/libexec.h minix-comp
|
||||
./usr/include/libfdt.h minix-comp
|
||||
./usr/include/libfdt_env.h minix-comp
|
||||
./usr/include/libfdt_internal.h minix-comp
|
||||
./usr/include/libgen.h minix-comp
|
||||
./usr/include/libutil.h minix-comp
|
||||
./usr/include/limits.h minix-comp
|
||||
|
||||
@@ -227,14 +227,14 @@ service mib
|
||||
service init
|
||||
{
|
||||
uid 0;
|
||||
ipc # ipc targets allowed:
|
||||
ipc # ipc targets allowed:
|
||||
pm vfs rs vm
|
||||
;
|
||||
system NONE; # No kernel calls allowed
|
||||
system NONE; # No kernel calls allowed
|
||||
vm BASIC; # Only basic VM calls allowed
|
||||
io NONE; # No I/O range allowed
|
||||
irq NONE; # No IRQs allowed
|
||||
sigmgr pm; # Signal manager is PM
|
||||
sigmgr pm; # Signal manager is PM
|
||||
};
|
||||
|
||||
#
|
||||
@@ -327,9 +327,9 @@ service virtio_blk
|
||||
service at_wini
|
||||
{
|
||||
io 1f0:8 # Controller 0
|
||||
3f6 # Also controller 0
|
||||
3f6 # Also controller 0
|
||||
170:8 # Controller 1
|
||||
376 # Also controller 1
|
||||
376 # Also controller 1
|
||||
;
|
||||
irq
|
||||
14 # Controller 0
|
||||
@@ -430,17 +430,30 @@ service devman
|
||||
;
|
||||
};
|
||||
|
||||
service mmc
|
||||
service omap_mmc
|
||||
{
|
||||
system
|
||||
PRIVCTL # 4
|
||||
IRQCTL # 19
|
||||
IRQCTL # 19
|
||||
;
|
||||
# Interrupts allowed
|
||||
irq
|
||||
64
|
||||
83
|
||||
; # IRQs allowed
|
||||
; # IRQs allowed
|
||||
priority 4; # priority queue 4
|
||||
};
|
||||
|
||||
service rpi_mmc
|
||||
{
|
||||
system
|
||||
PRIVCTL # 4
|
||||
IRQCTL # 19
|
||||
;
|
||||
# Interrupts allowed
|
||||
irq
|
||||
126
|
||||
; # IRQs allowed
|
||||
priority 4; # priority queue 4
|
||||
};
|
||||
|
||||
@@ -448,11 +461,11 @@ service fb
|
||||
{
|
||||
system
|
||||
UMAP # 14
|
||||
DEVIO # 21
|
||||
DEVIO # 21
|
||||
PRIVCTL # 4
|
||||
;
|
||||
ipc
|
||||
SYSTEM pm rs ds vm vfs cat24c256 tda19988
|
||||
SYSTEM pm rs ds vm vfs cat24c256 tda19988
|
||||
;
|
||||
};
|
||||
|
||||
@@ -507,7 +520,7 @@ service uds
|
||||
service pty
|
||||
{
|
||||
system
|
||||
KILL # 06
|
||||
KILL # 06
|
||||
;
|
||||
ipc
|
||||
SYSTEM vfs rs vm
|
||||
@@ -526,7 +539,7 @@ service edfictl
|
||||
ipc ALL;
|
||||
};
|
||||
|
||||
service emmc
|
||||
service omap_emmc
|
||||
{
|
||||
system
|
||||
PRIVCTL
|
||||
@@ -537,3 +550,39 @@ service emmc
|
||||
28 # MMCSD1INT
|
||||
;
|
||||
};
|
||||
|
||||
service mailbox
|
||||
{
|
||||
system
|
||||
UMAP # 14
|
||||
PRIVCTL # 4
|
||||
IRQCTL # 19
|
||||
;
|
||||
irq
|
||||
33
|
||||
;
|
||||
ipc ALL
|
||||
};
|
||||
|
||||
service i2c
|
||||
{
|
||||
system
|
||||
PRIVCTL # 4
|
||||
IRQCTL # 19
|
||||
PADCONF # 57
|
||||
;
|
||||
irq
|
||||
# DM37XX (BeagleBoard-xM)
|
||||
56 # I2C module 1
|
||||
57 # I2C module 2
|
||||
61 # I2C module 3
|
||||
# AM335X (BeagleBone)
|
||||
70 # I2C module 1
|
||||
71 # I2C module 2
|
||||
30 # I2C module 3
|
||||
# BCM283X (RaspberryPi 2,3)
|
||||
47
|
||||
;
|
||||
ipc SYSTEM rs ds vm
|
||||
;
|
||||
};
|
||||
|
||||
2
external/bsd/Makefile
vendored
2
external/bsd/Makefile
vendored
@@ -6,7 +6,7 @@
|
||||
SUBDIR= byacc \
|
||||
fetch file flex less \
|
||||
libarchive libevent mdocml \
|
||||
tmux top
|
||||
tmux top libfdt
|
||||
|
||||
.if (${MKATF} != "no")
|
||||
SUBDIR+= atf
|
||||
|
||||
3
external/bsd/libfdt/Makefile
vendored
Normal file
3
external/bsd/libfdt/Makefile
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
SUBDIR = include lib
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
3
external/bsd/libfdt/Makefile.inc
vendored
Normal file
3
external/bsd/libfdt/Makefile.inc
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.include <bsd.own.mk>
|
||||
|
||||
.PATH: ${SRCDIR} ${SRCDIR}/include
|
||||
251
external/bsd/libfdt/dist/fdt.c
vendored
Normal file
251
external/bsd/libfdt/dist/fdt.c
vendored
Normal file
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "libfdt_internal.h"
|
||||
|
||||
int fdt_check_header(const void *fdt)
|
||||
{
|
||||
if (fdt_magic(fdt) == FDT_MAGIC) {
|
||||
/* Complete tree */
|
||||
if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
|
||||
return -FDT_ERR_BADVERSION;
|
||||
if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
|
||||
return -FDT_ERR_BADVERSION;
|
||||
} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
|
||||
/* Unfinished sequential-write blob */
|
||||
if (fdt_size_dt_struct(fdt) == 0)
|
||||
return -FDT_ERR_BADSTATE;
|
||||
} else {
|
||||
return -FDT_ERR_BADMAGIC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
|
||||
{
|
||||
unsigned absoffset = offset + fdt_off_dt_struct(fdt);
|
||||
|
||||
if ((absoffset < offset)
|
||||
|| ((absoffset + len) < absoffset)
|
||||
|| (absoffset + len) > fdt_totalsize(fdt))
|
||||
return NULL;
|
||||
|
||||
if (fdt_version(fdt) >= 0x11)
|
||||
if (((offset + len) < offset)
|
||||
|| ((offset + len) > fdt_size_dt_struct(fdt)))
|
||||
return NULL;
|
||||
|
||||
return _fdt_offset_ptr(fdt, offset);
|
||||
}
|
||||
|
||||
uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
|
||||
{
|
||||
const fdt32_t *tagp, *lenp;
|
||||
uint32_t tag;
|
||||
int offset = startoffset;
|
||||
const char *p;
|
||||
|
||||
*nextoffset = -FDT_ERR_TRUNCATED;
|
||||
tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
|
||||
if (!tagp)
|
||||
return FDT_END; /* premature end */
|
||||
tag = fdt32_to_cpu(*tagp);
|
||||
offset += FDT_TAGSIZE;
|
||||
|
||||
*nextoffset = -FDT_ERR_BADSTRUCTURE;
|
||||
switch (tag) {
|
||||
case FDT_BEGIN_NODE:
|
||||
/* skip name */
|
||||
do {
|
||||
p = fdt_offset_ptr(fdt, offset++, 1);
|
||||
} while (p && (*p != '\0'));
|
||||
if (!p)
|
||||
return FDT_END; /* premature end */
|
||||
break;
|
||||
|
||||
case FDT_PROP:
|
||||
lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
|
||||
if (!lenp)
|
||||
return FDT_END; /* premature end */
|
||||
/* skip-name offset, length and value */
|
||||
offset += sizeof(struct fdt_property) - FDT_TAGSIZE
|
||||
+ fdt32_to_cpu(*lenp);
|
||||
break;
|
||||
|
||||
case FDT_END:
|
||||
case FDT_END_NODE:
|
||||
case FDT_NOP:
|
||||
break;
|
||||
|
||||
default:
|
||||
return FDT_END;
|
||||
}
|
||||
|
||||
if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset))
|
||||
return FDT_END; /* premature end */
|
||||
|
||||
*nextoffset = FDT_TAGALIGN(offset);
|
||||
return tag;
|
||||
}
|
||||
|
||||
int _fdt_check_node_offset(const void *fdt, int offset)
|
||||
{
|
||||
if ((offset < 0) || (offset % FDT_TAGSIZE)
|
||||
|| (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
|
||||
return -FDT_ERR_BADOFFSET;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int _fdt_check_prop_offset(const void *fdt, int offset)
|
||||
{
|
||||
if ((offset < 0) || (offset % FDT_TAGSIZE)
|
||||
|| (fdt_next_tag(fdt, offset, &offset) != FDT_PROP))
|
||||
return -FDT_ERR_BADOFFSET;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int fdt_next_node(const void *fdt, int offset, int *depth)
|
||||
{
|
||||
int nextoffset = 0;
|
||||
uint32_t tag;
|
||||
|
||||
if (offset >= 0)
|
||||
if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0)
|
||||
return nextoffset;
|
||||
|
||||
do {
|
||||
offset = nextoffset;
|
||||
tag = fdt_next_tag(fdt, offset, &nextoffset);
|
||||
|
||||
switch (tag) {
|
||||
case FDT_PROP:
|
||||
case FDT_NOP:
|
||||
break;
|
||||
|
||||
case FDT_BEGIN_NODE:
|
||||
if (depth)
|
||||
(*depth)++;
|
||||
break;
|
||||
|
||||
case FDT_END_NODE:
|
||||
if (depth && ((--(*depth)) < 0))
|
||||
return nextoffset;
|
||||
break;
|
||||
|
||||
case FDT_END:
|
||||
if ((nextoffset >= 0)
|
||||
|| ((nextoffset == -FDT_ERR_TRUNCATED) && !depth))
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
else
|
||||
return nextoffset;
|
||||
}
|
||||
} while (tag != FDT_BEGIN_NODE);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int fdt_first_subnode(const void *fdt, int offset)
|
||||
{
|
||||
int depth = 0;
|
||||
|
||||
offset = fdt_next_node(fdt, offset, &depth);
|
||||
if (offset < 0 || depth != 1)
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int fdt_next_subnode(const void *fdt, int offset)
|
||||
{
|
||||
int depth = 1;
|
||||
|
||||
/*
|
||||
* With respect to the parent, the depth of the next subnode will be
|
||||
* the same as the last.
|
||||
*/
|
||||
do {
|
||||
offset = fdt_next_node(fdt, offset, &depth);
|
||||
if (offset < 0 || depth < 1)
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
} while (depth > 1);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
|
||||
{
|
||||
int len = strlen(s) + 1;
|
||||
const char *last = strtab + tabsize - len;
|
||||
const char *p;
|
||||
|
||||
for (p = strtab; p <= last; p++)
|
||||
if (memcmp(p, s, len) == 0)
|
||||
return p;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int fdt_move(const void *fdt, void *buf, int bufsize)
|
||||
{
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
|
||||
if (fdt_totalsize(fdt) > bufsize)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
memmove(buf, fdt, fdt_totalsize(fdt));
|
||||
return 0;
|
||||
}
|
||||
96
external/bsd/libfdt/dist/fdt_addresses.c
vendored
Normal file
96
external/bsd/libfdt/dist/fdt_addresses.c
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au>
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "libfdt_internal.h"
|
||||
|
||||
int fdt_address_cells(const void *fdt, int nodeoffset)
|
||||
{
|
||||
const fdt32_t *ac;
|
||||
int val;
|
||||
int len;
|
||||
|
||||
ac = fdt_getprop(fdt, nodeoffset, "#address-cells", &len);
|
||||
if (!ac)
|
||||
return 2;
|
||||
|
||||
if (len != sizeof(*ac))
|
||||
return -FDT_ERR_BADNCELLS;
|
||||
|
||||
val = fdt32_to_cpu(*ac);
|
||||
if ((val <= 0) || (val > FDT_MAX_NCELLS))
|
||||
return -FDT_ERR_BADNCELLS;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
int fdt_size_cells(const void *fdt, int nodeoffset)
|
||||
{
|
||||
const fdt32_t *sc;
|
||||
int val;
|
||||
int len;
|
||||
|
||||
sc = fdt_getprop(fdt, nodeoffset, "#size-cells", &len);
|
||||
if (!sc)
|
||||
return 2;
|
||||
|
||||
if (len != sizeof(*sc))
|
||||
return -FDT_ERR_BADNCELLS;
|
||||
|
||||
val = fdt32_to_cpu(*sc);
|
||||
if ((val < 0) || (val > FDT_MAX_NCELLS))
|
||||
return -FDT_ERR_BADNCELLS;
|
||||
|
||||
return val;
|
||||
}
|
||||
83
external/bsd/libfdt/dist/fdt_empty_tree.c
vendored
Normal file
83
external/bsd/libfdt/dist/fdt_empty_tree.c
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2012 David Gibson, IBM Corporation.
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "libfdt_internal.h"
|
||||
|
||||
int fdt_create_empty_tree(void *buf, int bufsize)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = fdt_create(buf, bufsize);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fdt_finish_reservemap(buf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fdt_begin_node(buf, "");
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fdt_end_node(buf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fdt_finish(buf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return fdt_open_into(buf, buf, bufsize);
|
||||
}
|
||||
676
external/bsd/libfdt/dist/fdt_overlay.c
vendored
Normal file
676
external/bsd/libfdt/dist/fdt_overlay.c
vendored
Normal file
@@ -0,0 +1,676 @@
|
||||
#include "libfdt_env.h"
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "libfdt_internal.h"
|
||||
/**
|
||||
* overlay_get_target_phandle - retrieves the target phandle of a fragment
|
||||
* @fdto: pointer to the device tree overlay blob
|
||||
* @fragment: node offset of the fragment in the overlay
|
||||
*
|
||||
* overlay_get_target_phandle() retrieves the target phandle of an
|
||||
* overlay fragment when that fragment uses a phandle (target
|
||||
* property) instead of a path (target-path property).
|
||||
*
|
||||
* returns:
|
||||
* the phandle pointed by the target property
|
||||
* 0, if the phandle was not found
|
||||
* -1, if the phandle was malformed
|
||||
*/
|
||||
static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
|
||||
{
|
||||
const fdt32_t *val;
|
||||
int len;
|
||||
|
||||
val = fdt_getprop(fdto, fragment, "target", &len);
|
||||
if (!val)
|
||||
return 0;
|
||||
|
||||
if ((len != sizeof(*val)) || (fdt32_to_cpu(*val) == (uint32_t)-1))
|
||||
return (uint32_t)-1;
|
||||
|
||||
return fdt32_to_cpu(*val);
|
||||
}
|
||||
|
||||
/**
|
||||
* overlay_get_target - retrieves the offset of a fragment's target
|
||||
* @fdt: Base device tree blob
|
||||
* @fdto: Device tree overlay blob
|
||||
* @fragment: node offset of the fragment in the overlay
|
||||
*
|
||||
* overlay_get_target() retrieves the target offset in the base
|
||||
* device tree of a fragment, no matter how the actual targetting is
|
||||
* done (through a phandle or a path)
|
||||
*
|
||||
* returns:
|
||||
* the targetted node offset in the base device tree
|
||||
* Negative error code on error
|
||||
*/
|
||||
static int overlay_get_target(const void *fdt, const void *fdto,
|
||||
int fragment)
|
||||
{
|
||||
uint32_t phandle;
|
||||
const char *path;
|
||||
int path_len;
|
||||
|
||||
/* Try first to do a phandle based lookup */
|
||||
phandle = overlay_get_target_phandle(fdto, fragment);
|
||||
if (phandle == (uint32_t)-1)
|
||||
return -FDT_ERR_BADPHANDLE;
|
||||
|
||||
if (phandle)
|
||||
return fdt_node_offset_by_phandle(fdt, phandle);
|
||||
|
||||
/* And then a path based lookup */
|
||||
path = fdt_getprop(fdto, fragment, "target-path", &path_len);
|
||||
if (!path) {
|
||||
/*
|
||||
* If we haven't found either a target or a
|
||||
* target-path property in a node that contains a
|
||||
* __overlay__ subnode (we wouldn't be called
|
||||
* otherwise), consider it a improperly written
|
||||
* overlay
|
||||
*/
|
||||
if (path_len == -FDT_ERR_NOTFOUND)
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
|
||||
return path_len;
|
||||
}
|
||||
|
||||
return fdt_path_offset(fdt, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* overlay_phandle_add_offset - Increases a phandle by an offset
|
||||
* @fdt: Base device tree blob
|
||||
* @node: Device tree overlay blob
|
||||
* @name: Name of the property to modify (phandle or linux,phandle)
|
||||
* @delta: offset to apply
|
||||
*
|
||||
* overlay_phandle_add_offset() increments a node phandle by a given
|
||||
* offset.
|
||||
*
|
||||
* returns:
|
||||
* 0 on success.
|
||||
* Negative error code on error
|
||||
*/
|
||||
static int overlay_phandle_add_offset(void *fdt, int node,
|
||||
const char *name, uint32_t delta)
|
||||
{
|
||||
const fdt32_t *val;
|
||||
uint32_t adj_val;
|
||||
int len;
|
||||
|
||||
val = fdt_getprop(fdt, node, name, &len);
|
||||
if (!val)
|
||||
return len;
|
||||
|
||||
if (len != sizeof(*val))
|
||||
return -FDT_ERR_BADPHANDLE;
|
||||
|
||||
adj_val = fdt32_to_cpu(*val);
|
||||
if ((adj_val + delta) < adj_val)
|
||||
return -FDT_ERR_NOPHANDLES;
|
||||
|
||||
adj_val += delta;
|
||||
if (adj_val == (uint32_t)-1)
|
||||
return -FDT_ERR_NOPHANDLES;
|
||||
|
||||
return fdt_setprop_inplace_u32(fdt, node, name, adj_val);
|
||||
}
|
||||
|
||||
/**
|
||||
* overlay_adjust_node_phandles - Offsets the phandles of a node
|
||||
* @fdto: Device tree overlay blob
|
||||
* @node: Offset of the node we want to adjust
|
||||
* @delta: Offset to shift the phandles of
|
||||
*
|
||||
* overlay_adjust_node_phandles() adds a constant to all the phandles
|
||||
* of a given node. This is mainly use as part of the overlay
|
||||
* application process, when we want to update all the overlay
|
||||
* phandles to not conflict with the overlays of the base device tree.
|
||||
*
|
||||
* returns:
|
||||
* 0 on success
|
||||
* Negative error code on failure
|
||||
*/
|
||||
static int overlay_adjust_node_phandles(void *fdto, int node,
|
||||
uint32_t delta)
|
||||
{
|
||||
int child;
|
||||
int ret;
|
||||
|
||||
ret = overlay_phandle_add_offset(fdto, node, "phandle", delta);
|
||||
if (ret && ret != -FDT_ERR_NOTFOUND)
|
||||
return ret;
|
||||
|
||||
ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta);
|
||||
if (ret && ret != -FDT_ERR_NOTFOUND)
|
||||
return ret;
|
||||
|
||||
fdt_for_each_subnode(child, fdto, node) {
|
||||
ret = overlay_adjust_node_phandles(fdto, child, delta);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* overlay_adjust_local_phandles - Adjust the phandles of a whole overlay
|
||||
* @fdto: Device tree overlay blob
|
||||
* @delta: Offset to shift the phandles of
|
||||
*
|
||||
* overlay_adjust_local_phandles() adds a constant to all the
|
||||
* phandles of an overlay. This is mainly use as part of the overlay
|
||||
* application process, when we want to update all the overlay
|
||||
* phandles to not conflict with the overlays of the base device tree.
|
||||
*
|
||||
* returns:
|
||||
* 0 on success
|
||||
* Negative error code on failure
|
||||
*/
|
||||
static int overlay_adjust_local_phandles(void *fdto, uint32_t delta)
|
||||
{
|
||||
/*
|
||||
* Start adjusting the phandles from the overlay root
|
||||
*/
|
||||
return overlay_adjust_node_phandles(fdto, 0, delta);
|
||||
}
|
||||
|
||||
/**
|
||||
* overlay_update_local_node_references - Adjust the overlay references
|
||||
* @fdto: Device tree overlay blob
|
||||
* @tree_node: Node offset of the node to operate on
|
||||
* @fixup_node: Node offset of the matching local fixups node
|
||||
* @delta: Offset to shift the phandles of
|
||||
*
|
||||
* overlay_update_local_nodes_references() update the phandles
|
||||
* pointing to a node within the device tree overlay by adding a
|
||||
* constant delta.
|
||||
*
|
||||
* This is mainly used as part of a device tree application process,
|
||||
* where you want the device tree overlays phandles to not conflict
|
||||
* with the ones from the base device tree before merging them.
|
||||
*
|
||||
* returns:
|
||||
* 0 on success
|
||||
* Negative error code on failure
|
||||
*/
|
||||
static int overlay_update_local_node_references(void *fdto,
|
||||
int tree_node,
|
||||
int fixup_node,
|
||||
uint32_t delta)
|
||||
{
|
||||
int fixup_prop;
|
||||
int fixup_child;
|
||||
int ret;
|
||||
|
||||
fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) {
|
||||
const fdt32_t *fixup_val;
|
||||
const char *tree_val;
|
||||
const char *name;
|
||||
int fixup_len;
|
||||
int tree_len;
|
||||
int i;
|
||||
|
||||
fixup_val = fdt_getprop_by_offset(fdto, fixup_prop,
|
||||
&name, &fixup_len);
|
||||
if (!fixup_val)
|
||||
return fixup_len;
|
||||
|
||||
if (fixup_len % sizeof(uint32_t))
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
|
||||
tree_val = fdt_getprop(fdto, tree_node, name, &tree_len);
|
||||
if (!tree_val) {
|
||||
if (tree_len == -FDT_ERR_NOTFOUND)
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
|
||||
return tree_len;
|
||||
}
|
||||
|
||||
for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) {
|
||||
fdt32_t adj_val;
|
||||
uint32_t poffset;
|
||||
|
||||
poffset = fdt32_to_cpu(fixup_val[i]);
|
||||
|
||||
/*
|
||||
* phandles to fixup can be unaligned.
|
||||
*
|
||||
* Use a memcpy for the architectures that do
|
||||
* not support unaligned accesses.
|
||||
*/
|
||||
memcpy(&adj_val, tree_val + poffset, sizeof(adj_val));
|
||||
|
||||
adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta);
|
||||
|
||||
ret = fdt_setprop_inplace_namelen_partial(fdto,
|
||||
tree_node,
|
||||
name,
|
||||
strlen(name),
|
||||
poffset,
|
||||
&adj_val,
|
||||
sizeof(adj_val));
|
||||
if (ret == -FDT_ERR_NOSPACE)
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
fdt_for_each_subnode(fixup_child, fdto, fixup_node) {
|
||||
const char *fixup_child_name = fdt_get_name(fdto, fixup_child,
|
||||
NULL);
|
||||
int tree_child;
|
||||
|
||||
tree_child = fdt_subnode_offset(fdto, tree_node,
|
||||
fixup_child_name);
|
||||
if (tree_child == -FDT_ERR_NOTFOUND)
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
if (tree_child < 0)
|
||||
return tree_child;
|
||||
|
||||
ret = overlay_update_local_node_references(fdto,
|
||||
tree_child,
|
||||
fixup_child,
|
||||
delta);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* overlay_update_local_references - Adjust the overlay references
|
||||
* @fdto: Device tree overlay blob
|
||||
* @delta: Offset to shift the phandles of
|
||||
*
|
||||
* overlay_update_local_references() update all the phandles pointing
|
||||
* to a node within the device tree overlay by adding a constant
|
||||
* delta to not conflict with the base overlay.
|
||||
*
|
||||
* This is mainly used as part of a device tree application process,
|
||||
* where you want the device tree overlays phandles to not conflict
|
||||
* with the ones from the base device tree before merging them.
|
||||
*
|
||||
* returns:
|
||||
* 0 on success
|
||||
* Negative error code on failure
|
||||
*/
|
||||
static int overlay_update_local_references(void *fdto, uint32_t delta)
|
||||
{
|
||||
int fixups;
|
||||
|
||||
fixups = fdt_path_offset(fdto, "/__local_fixups__");
|
||||
if (fixups < 0) {
|
||||
/* There's no local phandles to adjust, bail out */
|
||||
if (fixups == -FDT_ERR_NOTFOUND)
|
||||
return 0;
|
||||
|
||||
return fixups;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update our local references from the root of the tree
|
||||
*/
|
||||
return overlay_update_local_node_references(fdto, 0, fixups,
|
||||
delta);
|
||||
}
|
||||
|
||||
/**
|
||||
* overlay_fixup_one_phandle - Set an overlay phandle to the base one
|
||||
* @fdt: Base Device Tree blob
|
||||
* @fdto: Device tree overlay blob
|
||||
* @symbols_off: Node offset of the symbols node in the base device tree
|
||||
* @path: Path to a node holding a phandle in the overlay
|
||||
* @path_len: number of path characters to consider
|
||||
* @name: Name of the property holding the phandle reference in the overlay
|
||||
* @name_len: number of name characters to consider
|
||||
* @poffset: Offset within the overlay property where the phandle is stored
|
||||
* @label: Label of the node referenced by the phandle
|
||||
*
|
||||
* overlay_fixup_one_phandle() resolves an overlay phandle pointing to
|
||||
* a node in the base device tree.
|
||||
*
|
||||
* This is part of the device tree overlay application process, when
|
||||
* you want all the phandles in the overlay to point to the actual
|
||||
* base dt nodes.
|
||||
*
|
||||
* returns:
|
||||
* 0 on success
|
||||
* Negative error code on failure
|
||||
*/
|
||||
static int overlay_fixup_one_phandle(void *fdt, void *fdto,
|
||||
int symbols_off,
|
||||
const char *path, uint32_t path_len,
|
||||
const char *name, uint32_t name_len,
|
||||
int poffset, const char *label)
|
||||
{
|
||||
const char *symbol_path;
|
||||
uint32_t phandle;
|
||||
fdt32_t phandle_prop;
|
||||
int symbol_off, fixup_off;
|
||||
int prop_len;
|
||||
|
||||
if (symbols_off < 0)
|
||||
return symbols_off;
|
||||
|
||||
symbol_path = fdt_getprop(fdt, symbols_off, label,
|
||||
&prop_len);
|
||||
if (!symbol_path)
|
||||
return prop_len;
|
||||
|
||||
symbol_off = fdt_path_offset(fdt, symbol_path);
|
||||
if (symbol_off < 0)
|
||||
return symbol_off;
|
||||
|
||||
phandle = fdt_get_phandle(fdt, symbol_off);
|
||||
if (!phandle)
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
|
||||
fixup_off = fdt_path_offset_namelen(fdto, path, path_len);
|
||||
if (fixup_off == -FDT_ERR_NOTFOUND)
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
if (fixup_off < 0)
|
||||
return fixup_off;
|
||||
|
||||
phandle_prop = cpu_to_fdt32(phandle);
|
||||
return fdt_setprop_inplace_namelen_partial(fdto, fixup_off,
|
||||
name, name_len, poffset,
|
||||
&phandle_prop,
|
||||
sizeof(phandle_prop));
|
||||
};
|
||||
|
||||
/**
|
||||
* overlay_fixup_phandle - Set an overlay phandle to the base one
|
||||
* @fdt: Base Device Tree blob
|
||||
* @fdto: Device tree overlay blob
|
||||
* @symbols_off: Node offset of the symbols node in the base device tree
|
||||
* @property: Property offset in the overlay holding the list of fixups
|
||||
*
|
||||
* overlay_fixup_phandle() resolves all the overlay phandles pointed
|
||||
* to in a __fixups__ property, and updates them to match the phandles
|
||||
* in use in the base device tree.
|
||||
*
|
||||
* This is part of the device tree overlay application process, when
|
||||
* you want all the phandles in the overlay to point to the actual
|
||||
* base dt nodes.
|
||||
*
|
||||
* returns:
|
||||
* 0 on success
|
||||
* Negative error code on failure
|
||||
*/
|
||||
static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
|
||||
int property)
|
||||
{
|
||||
const char *value;
|
||||
const char *label;
|
||||
int len;
|
||||
|
||||
value = fdt_getprop_by_offset(fdto, property,
|
||||
&label, &len);
|
||||
if (!value) {
|
||||
if (len == -FDT_ERR_NOTFOUND)
|
||||
return -FDT_ERR_INTERNAL;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
do {
|
||||
const char *path, *name, *fixup_end;
|
||||
const char *fixup_str = value;
|
||||
uint32_t path_len, name_len;
|
||||
uint32_t fixup_len;
|
||||
char *sep, *endptr;
|
||||
int poffset, ret;
|
||||
|
||||
fixup_end = memchr(value, '\0', len);
|
||||
if (!fixup_end)
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
fixup_len = fixup_end - fixup_str;
|
||||
|
||||
len -= fixup_len + 1;
|
||||
value += fixup_len + 1;
|
||||
|
||||
path = fixup_str;
|
||||
sep = memchr(fixup_str, ':', fixup_len);
|
||||
if (!sep || *sep != ':')
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
|
||||
path_len = sep - path;
|
||||
if (path_len == (fixup_len - 1))
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
|
||||
fixup_len -= path_len + 1;
|
||||
name = sep + 1;
|
||||
sep = memchr(name, ':', fixup_len);
|
||||
if (!sep || *sep != ':')
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
|
||||
name_len = sep - name;
|
||||
if (!name_len)
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
|
||||
poffset = strtoul(sep + 1, &endptr, 10);
|
||||
if ((*endptr != '\0') || (endptr <= (sep + 1)))
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
|
||||
ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off,
|
||||
path, path_len, name, name_len,
|
||||
poffset, label);
|
||||
if (ret)
|
||||
return ret;
|
||||
} while (len > 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* overlay_fixup_phandles - Resolve the overlay phandles to the base
|
||||
* device tree
|
||||
* @fdt: Base Device Tree blob
|
||||
* @fdto: Device tree overlay blob
|
||||
*
|
||||
* overlay_fixup_phandles() resolves all the overlay phandles pointing
|
||||
* to nodes in the base device tree.
|
||||
*
|
||||
* This is one of the steps of the device tree overlay application
|
||||
* process, when you want all the phandles in the overlay to point to
|
||||
* the actual base dt nodes.
|
||||
*
|
||||
* returns:
|
||||
* 0 on success
|
||||
* Negative error code on failure
|
||||
*/
|
||||
static int overlay_fixup_phandles(void *fdt, void *fdto)
|
||||
{
|
||||
int fixups_off, symbols_off;
|
||||
int property;
|
||||
|
||||
/* We can have overlays without any fixups */
|
||||
fixups_off = fdt_path_offset(fdto, "/__fixups__");
|
||||
if (fixups_off == -FDT_ERR_NOTFOUND)
|
||||
return 0; /* nothing to do */
|
||||
if (fixups_off < 0)
|
||||
return fixups_off;
|
||||
|
||||
/* And base DTs without symbols */
|
||||
symbols_off = fdt_path_offset(fdt, "/__symbols__");
|
||||
if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND)))
|
||||
return symbols_off;
|
||||
|
||||
fdt_for_each_property_offset(property, fdto, fixups_off) {
|
||||
int ret;
|
||||
|
||||
ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* overlay_apply_node - Merges a node into the base device tree
|
||||
* @fdt: Base Device Tree blob
|
||||
* @target: Node offset in the base device tree to apply the fragment to
|
||||
* @fdto: Device tree overlay blob
|
||||
* @node: Node offset in the overlay holding the changes to merge
|
||||
*
|
||||
* overlay_apply_node() merges a node into a target base device tree
|
||||
* node pointed.
|
||||
*
|
||||
* This is part of the final step in the device tree overlay
|
||||
* application process, when all the phandles have been adjusted and
|
||||
* resolved and you just have to merge overlay into the base device
|
||||
* tree.
|
||||
*
|
||||
* returns:
|
||||
* 0 on success
|
||||
* Negative error code on failure
|
||||
*/
|
||||
static int overlay_apply_node(void *fdt, int target,
|
||||
void *fdto, int node)
|
||||
{
|
||||
int property;
|
||||
int subnode;
|
||||
|
||||
fdt_for_each_property_offset(property, fdto, node) {
|
||||
const char *name;
|
||||
const void *prop;
|
||||
int prop_len;
|
||||
int ret;
|
||||
|
||||
prop = fdt_getprop_by_offset(fdto, property, &name,
|
||||
&prop_len);
|
||||
if (prop_len == -FDT_ERR_NOTFOUND)
|
||||
return -FDT_ERR_INTERNAL;
|
||||
if (prop_len < 0)
|
||||
return prop_len;
|
||||
|
||||
ret = fdt_setprop(fdt, target, name, prop, prop_len);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
fdt_for_each_subnode(subnode, fdto, node) {
|
||||
const char *name = fdt_get_name(fdto, subnode, NULL);
|
||||
int nnode;
|
||||
int ret;
|
||||
|
||||
nnode = fdt_add_subnode(fdt, target, name);
|
||||
if (nnode == -FDT_ERR_EXISTS) {
|
||||
nnode = fdt_subnode_offset(fdt, target, name);
|
||||
if (nnode == -FDT_ERR_NOTFOUND)
|
||||
return -FDT_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
if (nnode < 0)
|
||||
return nnode;
|
||||
|
||||
ret = overlay_apply_node(fdt, nnode, fdto, subnode);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* overlay_merge - Merge an overlay into its base device tree
|
||||
* @fdt: Base Device Tree blob
|
||||
* @fdto: Device tree overlay blob
|
||||
*
|
||||
* overlay_merge() merges an overlay into its base device tree.
|
||||
*
|
||||
* This is the final step in the device tree overlay application
|
||||
* process, when all the phandles have been adjusted and resolved and
|
||||
* you just have to merge overlay into the base device tree.
|
||||
*
|
||||
* returns:
|
||||
* 0 on success
|
||||
* Negative error code on failure
|
||||
*/
|
||||
static int overlay_merge(void *fdt, void *fdto)
|
||||
{
|
||||
int fragment;
|
||||
|
||||
fdt_for_each_subnode(fragment, fdto, 0) {
|
||||
int overlay;
|
||||
int target;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Each fragments will have an __overlay__ node. If
|
||||
* they don't, it's not supposed to be merged
|
||||
*/
|
||||
overlay = fdt_subnode_offset(fdto, fragment, "__overlay__");
|
||||
if (overlay == -FDT_ERR_NOTFOUND)
|
||||
continue;
|
||||
|
||||
if (overlay < 0)
|
||||
return overlay;
|
||||
|
||||
target = overlay_get_target(fdt, fdto, fragment);
|
||||
if (target < 0)
|
||||
return target;
|
||||
|
||||
ret = overlay_apply_node(fdt, target, fdto, overlay);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_overlay_apply(void *fdt, void *fdto)
|
||||
{
|
||||
uint32_t delta = fdt_get_max_phandle(fdt);
|
||||
int ret;
|
||||
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
FDT_CHECK_HEADER(fdto);
|
||||
|
||||
ret = overlay_adjust_local_phandles(fdto, delta);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = overlay_update_local_references(fdto, delta);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = overlay_fixup_phandles(fdt, fdto);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = overlay_merge(fdt, fdto);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* The overlay has been damaged, erase its magic.
|
||||
*/
|
||||
fdt_set_magic(fdto, ~0);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
/*
|
||||
* The overlay might have been damaged, erase its magic.
|
||||
*/
|
||||
fdt_set_magic(fdto, ~0);
|
||||
|
||||
/*
|
||||
* The base device tree might have been damaged, erase its
|
||||
* magic.
|
||||
*/
|
||||
fdt_set_magic(fdt, ~0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
703
external/bsd/libfdt/dist/fdt_ro.c
vendored
Normal file
703
external/bsd/libfdt/dist/fdt_ro.c
vendored
Normal file
@@ -0,0 +1,703 @@
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "libfdt_internal.h"
|
||||
|
||||
static int _fdt_nodename_eq(const void *fdt, int offset,
|
||||
const char *s, int len)
|
||||
{
|
||||
const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
|
||||
|
||||
if (!p)
|
||||
/* short match */
|
||||
return 0;
|
||||
|
||||
if (memcmp(p, s, len) != 0)
|
||||
return 0;
|
||||
|
||||
if (p[len] == '\0')
|
||||
return 1;
|
||||
else if (!memchr(s, '@', len) && (p[len] == '@'))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *fdt_string(const void *fdt, int stroffset)
|
||||
{
|
||||
return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
|
||||
}
|
||||
|
||||
static int _fdt_string_eq(const void *fdt, int stroffset,
|
||||
const char *s, int len)
|
||||
{
|
||||
const char *p = fdt_string(fdt, stroffset);
|
||||
|
||||
return (strlen(p) == len) && (memcmp(p, s, len) == 0);
|
||||
}
|
||||
|
||||
uint32_t fdt_get_max_phandle(const void *fdt)
|
||||
{
|
||||
uint32_t max_phandle = 0;
|
||||
int offset;
|
||||
|
||||
for (offset = fdt_next_node(fdt, -1, NULL);;
|
||||
offset = fdt_next_node(fdt, offset, NULL)) {
|
||||
uint32_t phandle;
|
||||
|
||||
if (offset == -FDT_ERR_NOTFOUND)
|
||||
return max_phandle;
|
||||
|
||||
if (offset < 0)
|
||||
return (uint32_t)-1;
|
||||
|
||||
phandle = fdt_get_phandle(fdt, offset);
|
||||
if (phandle == (uint32_t)-1)
|
||||
continue;
|
||||
|
||||
if (phandle > max_phandle)
|
||||
max_phandle = phandle;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
|
||||
{
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
*address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
|
||||
*size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_num_mem_rsv(const void *fdt)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
|
||||
i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
static int _nextprop(const void *fdt, int offset)
|
||||
{
|
||||
uint32_t tag;
|
||||
int nextoffset;
|
||||
|
||||
do {
|
||||
tag = fdt_next_tag(fdt, offset, &nextoffset);
|
||||
|
||||
switch (tag) {
|
||||
case FDT_END:
|
||||
if (nextoffset >= 0)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
else
|
||||
return nextoffset;
|
||||
|
||||
case FDT_PROP:
|
||||
return offset;
|
||||
}
|
||||
offset = nextoffset;
|
||||
} while (tag == FDT_NOP);
|
||||
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
}
|
||||
|
||||
int fdt_subnode_offset_namelen(const void *fdt, int offset,
|
||||
const char *name, int namelen)
|
||||
{
|
||||
int depth;
|
||||
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
|
||||
for (depth = 0;
|
||||
(offset >= 0) && (depth >= 0);
|
||||
offset = fdt_next_node(fdt, offset, &depth))
|
||||
if ((depth == 1)
|
||||
&& _fdt_nodename_eq(fdt, offset, name, namelen))
|
||||
return offset;
|
||||
|
||||
if (depth < 0)
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
return offset; /* error */
|
||||
}
|
||||
|
||||
int fdt_subnode_offset(const void *fdt, int parentoffset,
|
||||
const char *name)
|
||||
{
|
||||
return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
|
||||
}
|
||||
|
||||
int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
|
||||
{
|
||||
const char *end = path + namelen;
|
||||
const char *p = path;
|
||||
int offset = 0;
|
||||
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
|
||||
/* see if we have an alias */
|
||||
if (*path != '/') {
|
||||
const char *q = memchr(path, '/', end - p);
|
||||
|
||||
if (!q)
|
||||
q = end;
|
||||
|
||||
p = fdt_get_alias_namelen(fdt, p, q - p);
|
||||
if (!p)
|
||||
return -FDT_ERR_BADPATH;
|
||||
offset = fdt_path_offset(fdt, p);
|
||||
|
||||
p = q;
|
||||
}
|
||||
|
||||
while (p < end) {
|
||||
const char *q;
|
||||
|
||||
while (*p == '/') {
|
||||
p++;
|
||||
if (p == end)
|
||||
return offset;
|
||||
}
|
||||
q = memchr(p, '/', end - p);
|
||||
if (! q)
|
||||
q = end;
|
||||
|
||||
offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
|
||||
if (offset < 0)
|
||||
return offset;
|
||||
|
||||
p = q;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int fdt_path_offset(const void *fdt, const char *path)
|
||||
{
|
||||
return fdt_path_offset_namelen(fdt, path, strlen(path));
|
||||
}
|
||||
|
||||
const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
|
||||
{
|
||||
const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
|
||||
int err;
|
||||
|
||||
if (((err = fdt_check_header(fdt)) != 0)
|
||||
|| ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
|
||||
goto fail;
|
||||
|
||||
if (len)
|
||||
*len = strlen(nh->name);
|
||||
|
||||
return nh->name;
|
||||
|
||||
fail:
|
||||
if (len)
|
||||
*len = err;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int fdt_first_property_offset(const void *fdt, int nodeoffset)
|
||||
{
|
||||
int offset;
|
||||
|
||||
if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
|
||||
return offset;
|
||||
|
||||
return _nextprop(fdt, offset);
|
||||
}
|
||||
|
||||
int fdt_next_property_offset(const void *fdt, int offset)
|
||||
{
|
||||
if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0)
|
||||
return offset;
|
||||
|
||||
return _nextprop(fdt, offset);
|
||||
}
|
||||
|
||||
const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
|
||||
int offset,
|
||||
int *lenp)
|
||||
{
|
||||
int err;
|
||||
const struct fdt_property *prop;
|
||||
|
||||
if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) {
|
||||
if (lenp)
|
||||
*lenp = err;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
prop = _fdt_offset_ptr(fdt, offset);
|
||||
|
||||
if (lenp)
|
||||
*lenp = fdt32_to_cpu(prop->len);
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
const struct fdt_property *fdt_get_property_namelen(const void *fdt,
|
||||
int offset,
|
||||
const char *name,
|
||||
int namelen, int *lenp)
|
||||
{
|
||||
for (offset = fdt_first_property_offset(fdt, offset);
|
||||
(offset >= 0);
|
||||
(offset = fdt_next_property_offset(fdt, offset))) {
|
||||
const struct fdt_property *prop;
|
||||
|
||||
if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) {
|
||||
offset = -FDT_ERR_INTERNAL;
|
||||
break;
|
||||
}
|
||||
if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),
|
||||
name, namelen))
|
||||
return prop;
|
||||
}
|
||||
|
||||
if (lenp)
|
||||
*lenp = offset;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct fdt_property *fdt_get_property(const void *fdt,
|
||||
int nodeoffset,
|
||||
const char *name, int *lenp)
|
||||
{
|
||||
return fdt_get_property_namelen(fdt, nodeoffset, name,
|
||||
strlen(name), lenp);
|
||||
}
|
||||
|
||||
const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
|
||||
const char *name, int namelen, int *lenp)
|
||||
{
|
||||
const struct fdt_property *prop;
|
||||
|
||||
prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
|
||||
if (!prop)
|
||||
return NULL;
|
||||
|
||||
return prop->data;
|
||||
}
|
||||
|
||||
const void *fdt_getprop_by_offset(const void *fdt, int offset,
|
||||
const char **namep, int *lenp)
|
||||
{
|
||||
const struct fdt_property *prop;
|
||||
|
||||
prop = fdt_get_property_by_offset(fdt, offset, lenp);
|
||||
if (!prop)
|
||||
return NULL;
|
||||
if (namep)
|
||||
*namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
|
||||
return prop->data;
|
||||
}
|
||||
|
||||
const void *fdt_getprop(const void *fdt, int nodeoffset,
|
||||
const char *name, int *lenp)
|
||||
{
|
||||
return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
|
||||
}
|
||||
|
||||
uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
|
||||
{
|
||||
const fdt32_t *php;
|
||||
int len;
|
||||
|
||||
/* FIXME: This is a bit sub-optimal, since we potentially scan
|
||||
* over all the properties twice. */
|
||||
php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
|
||||
if (!php || (len != sizeof(*php))) {
|
||||
php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
|
||||
if (!php || (len != sizeof(*php)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return fdt32_to_cpu(*php);
|
||||
}
|
||||
|
||||
const char *fdt_get_alias_namelen(const void *fdt,
|
||||
const char *name, int namelen)
|
||||
{
|
||||
int aliasoffset;
|
||||
|
||||
aliasoffset = fdt_path_offset(fdt, "/aliases");
|
||||
if (aliasoffset < 0)
|
||||
return NULL;
|
||||
|
||||
return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
|
||||
}
|
||||
|
||||
const char *fdt_get_alias(const void *fdt, const char *name)
|
||||
{
|
||||
return fdt_get_alias_namelen(fdt, name, strlen(name));
|
||||
}
|
||||
|
||||
int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
|
||||
{
|
||||
int pdepth = 0, p = 0;
|
||||
int offset, depth, namelen;
|
||||
const char *name;
|
||||
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
|
||||
if (buflen < 2)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
for (offset = 0, depth = 0;
|
||||
(offset >= 0) && (offset <= nodeoffset);
|
||||
offset = fdt_next_node(fdt, offset, &depth)) {
|
||||
while (pdepth > depth) {
|
||||
do {
|
||||
p--;
|
||||
} while (buf[p-1] != '/');
|
||||
pdepth--;
|
||||
}
|
||||
|
||||
if (pdepth >= depth) {
|
||||
name = fdt_get_name(fdt, offset, &namelen);
|
||||
if (!name)
|
||||
return namelen;
|
||||
if ((p + namelen + 1) <= buflen) {
|
||||
memcpy(buf + p, name, namelen);
|
||||
p += namelen;
|
||||
buf[p++] = '/';
|
||||
pdepth++;
|
||||
}
|
||||
}
|
||||
|
||||
if (offset == nodeoffset) {
|
||||
if (pdepth < (depth + 1))
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
if (p > 1) /* special case so that root path is "/", not "" */
|
||||
p--;
|
||||
buf[p] = '\0';
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
|
||||
return -FDT_ERR_BADOFFSET;
|
||||
else if (offset == -FDT_ERR_BADOFFSET)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
|
||||
return offset; /* error from fdt_next_node() */
|
||||
}
|
||||
|
||||
int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
|
||||
int supernodedepth, int *nodedepth)
|
||||
{
|
||||
int offset, depth;
|
||||
int supernodeoffset = -FDT_ERR_INTERNAL;
|
||||
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
|
||||
if (supernodedepth < 0)
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
|
||||
for (offset = 0, depth = 0;
|
||||
(offset >= 0) && (offset <= nodeoffset);
|
||||
offset = fdt_next_node(fdt, offset, &depth)) {
|
||||
if (depth == supernodedepth)
|
||||
supernodeoffset = offset;
|
||||
|
||||
if (offset == nodeoffset) {
|
||||
if (nodedepth)
|
||||
*nodedepth = depth;
|
||||
|
||||
if (supernodedepth > depth)
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
else
|
||||
return supernodeoffset;
|
||||
}
|
||||
}
|
||||
|
||||
if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
|
||||
return -FDT_ERR_BADOFFSET;
|
||||
else if (offset == -FDT_ERR_BADOFFSET)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
|
||||
return offset; /* error from fdt_next_node() */
|
||||
}
|
||||
|
||||
int fdt_node_depth(const void *fdt, int nodeoffset)
|
||||
{
|
||||
int nodedepth;
|
||||
int err;
|
||||
|
||||
err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
|
||||
if (err)
|
||||
return (err < 0) ? err : -FDT_ERR_INTERNAL;
|
||||
return nodedepth;
|
||||
}
|
||||
|
||||
int fdt_parent_offset(const void *fdt, int nodeoffset)
|
||||
{
|
||||
int nodedepth = fdt_node_depth(fdt, nodeoffset);
|
||||
|
||||
if (nodedepth < 0)
|
||||
return nodedepth;
|
||||
return fdt_supernode_atdepth_offset(fdt, nodeoffset,
|
||||
nodedepth - 1, NULL);
|
||||
}
|
||||
|
||||
int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
|
||||
const char *propname,
|
||||
const void *propval, int proplen)
|
||||
{
|
||||
int offset;
|
||||
const void *val;
|
||||
int len;
|
||||
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
|
||||
/* FIXME: The algorithm here is pretty horrible: we scan each
|
||||
* property of a node in fdt_getprop(), then if that didn't
|
||||
* find what we want, we scan over them again making our way
|
||||
* to the next node. Still it's the easiest to implement
|
||||
* approach; performance can come later. */
|
||||
for (offset = fdt_next_node(fdt, startoffset, NULL);
|
||||
offset >= 0;
|
||||
offset = fdt_next_node(fdt, offset, NULL)) {
|
||||
val = fdt_getprop(fdt, offset, propname, &len);
|
||||
if (val && (len == proplen)
|
||||
&& (memcmp(val, propval, len) == 0))
|
||||
return offset;
|
||||
}
|
||||
|
||||
return offset; /* error from fdt_next_node() */
|
||||
}
|
||||
|
||||
int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
|
||||
{
|
||||
int offset;
|
||||
|
||||
if ((phandle == 0) || (phandle == -1))
|
||||
return -FDT_ERR_BADPHANDLE;
|
||||
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
|
||||
/* FIXME: The algorithm here is pretty horrible: we
|
||||
* potentially scan each property of a node in
|
||||
* fdt_get_phandle(), then if that didn't find what
|
||||
* we want, we scan over them again making our way to the next
|
||||
* node. Still it's the easiest to implement approach;
|
||||
* performance can come later. */
|
||||
for (offset = fdt_next_node(fdt, -1, NULL);
|
||||
offset >= 0;
|
||||
offset = fdt_next_node(fdt, offset, NULL)) {
|
||||
if (fdt_get_phandle(fdt, offset) == phandle)
|
||||
return offset;
|
||||
}
|
||||
|
||||
return offset; /* error from fdt_next_node() */
|
||||
}
|
||||
|
||||
int fdt_stringlist_contains(const char *strlist, int listlen, const char *str)
|
||||
{
|
||||
int len = strlen(str);
|
||||
const char *p;
|
||||
|
||||
while (listlen >= len) {
|
||||
if (memcmp(str, strlist, len+1) == 0)
|
||||
return 1;
|
||||
p = memchr(strlist, '\0', listlen);
|
||||
if (!p)
|
||||
return 0; /* malformed strlist.. */
|
||||
listlen -= (p-strlist) + 1;
|
||||
strlist = p + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
|
||||
{
|
||||
const char *list, *end;
|
||||
int length, count = 0;
|
||||
|
||||
list = fdt_getprop(fdt, nodeoffset, property, &length);
|
||||
if (!list)
|
||||
return length;
|
||||
|
||||
end = list + length;
|
||||
|
||||
while (list < end) {
|
||||
length = strnlen(list, end - list) + 1;
|
||||
|
||||
/* Abort if the last string isn't properly NUL-terminated. */
|
||||
if (list + length > end)
|
||||
return -FDT_ERR_BADVALUE;
|
||||
|
||||
list += length;
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
|
||||
const char *string)
|
||||
{
|
||||
int length, len, idx = 0;
|
||||
const char *list, *end;
|
||||
|
||||
list = fdt_getprop(fdt, nodeoffset, property, &length);
|
||||
if (!list)
|
||||
return length;
|
||||
|
||||
len = strlen(string) + 1;
|
||||
end = list + length;
|
||||
|
||||
while (list < end) {
|
||||
length = strnlen(list, end - list) + 1;
|
||||
|
||||
/* Abort if the last string isn't properly NUL-terminated. */
|
||||
if (list + length > end)
|
||||
return -FDT_ERR_BADVALUE;
|
||||
|
||||
if (length == len && memcmp(list, string, length) == 0)
|
||||
return idx;
|
||||
|
||||
list += length;
|
||||
idx++;
|
||||
}
|
||||
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
}
|
||||
|
||||
const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
|
||||
const char *property, int idx,
|
||||
int *lenp)
|
||||
{
|
||||
const char *list, *end;
|
||||
int length;
|
||||
|
||||
list = fdt_getprop(fdt, nodeoffset, property, &length);
|
||||
if (!list) {
|
||||
if (lenp)
|
||||
*lenp = length;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
end = list + length;
|
||||
|
||||
while (list < end) {
|
||||
length = strnlen(list, end - list) + 1;
|
||||
|
||||
/* Abort if the last string isn't properly NUL-terminated. */
|
||||
if (list + length > end) {
|
||||
if (lenp)
|
||||
*lenp = -FDT_ERR_BADVALUE;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (idx == 0) {
|
||||
if (lenp)
|
||||
*lenp = length - 1;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
list += length;
|
||||
idx--;
|
||||
}
|
||||
|
||||
if (lenp)
|
||||
*lenp = -FDT_ERR_NOTFOUND;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int fdt_node_check_compatible(const void *fdt, int nodeoffset,
|
||||
const char *compatible)
|
||||
{
|
||||
const void *prop;
|
||||
int len;
|
||||
|
||||
prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
|
||||
if (!prop)
|
||||
return len;
|
||||
|
||||
return !fdt_stringlist_contains(prop, len, compatible);
|
||||
}
|
||||
|
||||
int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
|
||||
const char *compatible)
|
||||
{
|
||||
int offset, err;
|
||||
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
|
||||
/* FIXME: The algorithm here is pretty horrible: we scan each
|
||||
* property of a node in fdt_node_check_compatible(), then if
|
||||
* that didn't find what we want, we scan over them again
|
||||
* making our way to the next node. Still it's the easiest to
|
||||
* implement approach; performance can come later. */
|
||||
for (offset = fdt_next_node(fdt, startoffset, NULL);
|
||||
offset >= 0;
|
||||
offset = fdt_next_node(fdt, offset, NULL)) {
|
||||
err = fdt_node_check_compatible(fdt, offset, compatible);
|
||||
if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
|
||||
return err;
|
||||
else if (err == 0)
|
||||
return offset;
|
||||
}
|
||||
|
||||
return offset; /* error from fdt_next_node() */
|
||||
}
|
||||
491
external/bsd/libfdt/dist/fdt_rw.c
vendored
Normal file
491
external/bsd/libfdt/dist/fdt_rw.c
vendored
Normal file
@@ -0,0 +1,491 @@
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "libfdt_internal.h"
|
||||
|
||||
static int _fdt_blocks_misordered(const void *fdt,
|
||||
int mem_rsv_size, int struct_size)
|
||||
{
|
||||
return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
|
||||
|| (fdt_off_dt_struct(fdt) <
|
||||
(fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
|
||||
|| (fdt_off_dt_strings(fdt) <
|
||||
(fdt_off_dt_struct(fdt) + struct_size))
|
||||
|| (fdt_totalsize(fdt) <
|
||||
(fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
|
||||
}
|
||||
|
||||
static int _fdt_rw_check_header(void *fdt)
|
||||
{
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
|
||||
if (fdt_version(fdt) < 17)
|
||||
return -FDT_ERR_BADVERSION;
|
||||
if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
|
||||
fdt_size_dt_struct(fdt)))
|
||||
return -FDT_ERR_BADLAYOUT;
|
||||
if (fdt_version(fdt) > 17)
|
||||
fdt_set_version(fdt, 17);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define FDT_RW_CHECK_HEADER(fdt) \
|
||||
{ \
|
||||
int __err; \
|
||||
if ((__err = _fdt_rw_check_header(fdt)) != 0) \
|
||||
return __err; \
|
||||
}
|
||||
|
||||
static inline int _fdt_data_size(void *fdt)
|
||||
{
|
||||
return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
|
||||
}
|
||||
|
||||
static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen)
|
||||
{
|
||||
char *p = splicepoint;
|
||||
char *end = (char *)fdt + _fdt_data_size(fdt);
|
||||
|
||||
if (((p + oldlen) < p) || ((p + oldlen) > end))
|
||||
return -FDT_ERR_BADOFFSET;
|
||||
if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt))
|
||||
return -FDT_ERR_BADOFFSET;
|
||||
if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
|
||||
return -FDT_ERR_NOSPACE;
|
||||
memmove(p + newlen, p + oldlen, end - p - oldlen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
|
||||
int oldn, int newn)
|
||||
{
|
||||
int delta = (newn - oldn) * sizeof(*p);
|
||||
int err;
|
||||
err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
|
||||
if (err)
|
||||
return err;
|
||||
fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
|
||||
fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _fdt_splice_struct(void *fdt, void *p,
|
||||
int oldlen, int newlen)
|
||||
{
|
||||
int delta = newlen - oldlen;
|
||||
int err;
|
||||
|
||||
if ((err = _fdt_splice(fdt, p, oldlen, newlen)))
|
||||
return err;
|
||||
|
||||
fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
|
||||
fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _fdt_splice_string(void *fdt, int newlen)
|
||||
{
|
||||
void *p = (char *)fdt
|
||||
+ fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
|
||||
int err;
|
||||
|
||||
if ((err = _fdt_splice(fdt, p, 0, newlen)))
|
||||
return err;
|
||||
|
||||
fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _fdt_find_add_string(void *fdt, const char *s)
|
||||
{
|
||||
char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
|
||||
const char *p;
|
||||
char *new;
|
||||
int len = strlen(s) + 1;
|
||||
int err;
|
||||
|
||||
p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s);
|
||||
if (p)
|
||||
/* found it */
|
||||
return (p - strtab);
|
||||
|
||||
new = strtab + fdt_size_dt_strings(fdt);
|
||||
err = _fdt_splice_string(fdt, len);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
memcpy(new, s, len);
|
||||
return (new - strtab);
|
||||
}
|
||||
|
||||
int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
|
||||
{
|
||||
struct fdt_reserve_entry *re;
|
||||
int err;
|
||||
|
||||
FDT_RW_CHECK_HEADER(fdt);
|
||||
|
||||
re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
|
||||
err = _fdt_splice_mem_rsv(fdt, re, 0, 1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
re->address = cpu_to_fdt64(address);
|
||||
re->size = cpu_to_fdt64(size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_del_mem_rsv(void *fdt, int n)
|
||||
{
|
||||
struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
|
||||
|
||||
FDT_RW_CHECK_HEADER(fdt);
|
||||
|
||||
if (n >= fdt_num_mem_rsv(fdt))
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
|
||||
return _fdt_splice_mem_rsv(fdt, re, 1, 0);
|
||||
}
|
||||
|
||||
static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
|
||||
int len, struct fdt_property **prop)
|
||||
{
|
||||
int oldlen;
|
||||
int err;
|
||||
|
||||
*prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
|
||||
if (!*prop)
|
||||
return oldlen;
|
||||
|
||||
if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
|
||||
FDT_TAGALIGN(len))))
|
||||
return err;
|
||||
|
||||
(*prop)->len = cpu_to_fdt32(len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _fdt_add_property(void *fdt, int nodeoffset, const char *name,
|
||||
int len, struct fdt_property **prop)
|
||||
{
|
||||
int proplen;
|
||||
int nextoffset;
|
||||
int namestroff;
|
||||
int err;
|
||||
|
||||
if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
|
||||
return nextoffset;
|
||||
|
||||
namestroff = _fdt_find_add_string(fdt, name);
|
||||
if (namestroff < 0)
|
||||
return namestroff;
|
||||
|
||||
*prop = _fdt_offset_ptr_w(fdt, nextoffset);
|
||||
proplen = sizeof(**prop) + FDT_TAGALIGN(len);
|
||||
|
||||
err = _fdt_splice_struct(fdt, *prop, 0, proplen);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
(*prop)->tag = cpu_to_fdt32(FDT_PROP);
|
||||
(*prop)->nameoff = cpu_to_fdt32(namestroff);
|
||||
(*prop)->len = cpu_to_fdt32(len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_set_name(void *fdt, int nodeoffset, const char *name)
|
||||
{
|
||||
char *namep;
|
||||
int oldlen, newlen;
|
||||
int err;
|
||||
|
||||
FDT_RW_CHECK_HEADER(fdt);
|
||||
|
||||
namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
|
||||
if (!namep)
|
||||
return oldlen;
|
||||
|
||||
newlen = strlen(name);
|
||||
|
||||
err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1),
|
||||
FDT_TAGALIGN(newlen+1));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
memcpy(namep, name, newlen+1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_setprop(void *fdt, int nodeoffset, const char *name,
|
||||
const void *val, int len)
|
||||
{
|
||||
struct fdt_property *prop;
|
||||
int err;
|
||||
|
||||
FDT_RW_CHECK_HEADER(fdt);
|
||||
|
||||
err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop);
|
||||
if (err == -FDT_ERR_NOTFOUND)
|
||||
err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (len)
|
||||
memcpy(prop->data, val, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
|
||||
const void *val, int len)
|
||||
{
|
||||
struct fdt_property *prop;
|
||||
int err, oldlen, newlen;
|
||||
|
||||
FDT_RW_CHECK_HEADER(fdt);
|
||||
|
||||
prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
|
||||
if (prop) {
|
||||
newlen = len + oldlen;
|
||||
err = _fdt_splice_struct(fdt, prop->data,
|
||||
FDT_TAGALIGN(oldlen),
|
||||
FDT_TAGALIGN(newlen));
|
||||
if (err)
|
||||
return err;
|
||||
prop->len = cpu_to_fdt32(newlen);
|
||||
memcpy(prop->data + oldlen, val, len);
|
||||
} else {
|
||||
err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
|
||||
if (err)
|
||||
return err;
|
||||
memcpy(prop->data, val, len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_delprop(void *fdt, int nodeoffset, const char *name)
|
||||
{
|
||||
struct fdt_property *prop;
|
||||
int len, proplen;
|
||||
|
||||
FDT_RW_CHECK_HEADER(fdt);
|
||||
|
||||
prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
|
||||
if (!prop)
|
||||
return len;
|
||||
|
||||
proplen = sizeof(*prop) + FDT_TAGALIGN(len);
|
||||
return _fdt_splice_struct(fdt, prop, proplen, 0);
|
||||
}
|
||||
|
||||
int fdt_add_subnode_namelen(void *fdt, int parentoffset,
|
||||
const char *name, int namelen)
|
||||
{
|
||||
struct fdt_node_header *nh;
|
||||
int offset, nextoffset;
|
||||
int nodelen;
|
||||
int err;
|
||||
uint32_t tag;
|
||||
fdt32_t *endtag;
|
||||
|
||||
FDT_RW_CHECK_HEADER(fdt);
|
||||
|
||||
offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
|
||||
if (offset >= 0)
|
||||
return -FDT_ERR_EXISTS;
|
||||
else if (offset != -FDT_ERR_NOTFOUND)
|
||||
return offset;
|
||||
|
||||
/* Try to place the new node after the parent's properties */
|
||||
fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
|
||||
do {
|
||||
offset = nextoffset;
|
||||
tag = fdt_next_tag(fdt, offset, &nextoffset);
|
||||
} while ((tag == FDT_PROP) || (tag == FDT_NOP));
|
||||
|
||||
nh = _fdt_offset_ptr_w(fdt, offset);
|
||||
nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;
|
||||
|
||||
err = _fdt_splice_struct(fdt, nh, 0, nodelen);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
|
||||
memset(nh->name, 0, FDT_TAGALIGN(namelen+1));
|
||||
memcpy(nh->name, name, namelen);
|
||||
endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE);
|
||||
*endtag = cpu_to_fdt32(FDT_END_NODE);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int fdt_add_subnode(void *fdt, int parentoffset, const char *name)
|
||||
{
|
||||
return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
|
||||
}
|
||||
|
||||
int fdt_del_node(void *fdt, int nodeoffset)
|
||||
{
|
||||
int endoffset;
|
||||
|
||||
FDT_RW_CHECK_HEADER(fdt);
|
||||
|
||||
endoffset = _fdt_node_end_offset(fdt, nodeoffset);
|
||||
if (endoffset < 0)
|
||||
return endoffset;
|
||||
|
||||
return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
|
||||
endoffset - nodeoffset, 0);
|
||||
}
|
||||
|
||||
static void _fdt_packblocks(const char *old, char *new,
|
||||
int mem_rsv_size, int struct_size)
|
||||
{
|
||||
int mem_rsv_off, struct_off, strings_off;
|
||||
|
||||
mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
|
||||
struct_off = mem_rsv_off + mem_rsv_size;
|
||||
strings_off = struct_off + struct_size;
|
||||
|
||||
memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size);
|
||||
fdt_set_off_mem_rsvmap(new, mem_rsv_off);
|
||||
|
||||
memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size);
|
||||
fdt_set_off_dt_struct(new, struct_off);
|
||||
fdt_set_size_dt_struct(new, struct_size);
|
||||
|
||||
memmove(new + strings_off, old + fdt_off_dt_strings(old),
|
||||
fdt_size_dt_strings(old));
|
||||
fdt_set_off_dt_strings(new, strings_off);
|
||||
fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
|
||||
}
|
||||
|
||||
int fdt_open_into(const void *fdt, void *buf, int bufsize)
|
||||
{
|
||||
int err;
|
||||
int mem_rsv_size, struct_size;
|
||||
int newsize;
|
||||
const char *fdtstart = fdt;
|
||||
const char *fdtend = fdtstart + fdt_totalsize(fdt);
|
||||
char *tmp;
|
||||
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
|
||||
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
|
||||
* sizeof(struct fdt_reserve_entry);
|
||||
|
||||
if (fdt_version(fdt) >= 17) {
|
||||
struct_size = fdt_size_dt_struct(fdt);
|
||||
} else {
|
||||
struct_size = 0;
|
||||
while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
|
||||
;
|
||||
if (struct_size < 0)
|
||||
return struct_size;
|
||||
}
|
||||
|
||||
if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
|
||||
/* no further work necessary */
|
||||
err = fdt_move(fdt, buf, bufsize);
|
||||
if (err)
|
||||
return err;
|
||||
fdt_set_version(buf, 17);
|
||||
fdt_set_size_dt_struct(buf, struct_size);
|
||||
fdt_set_totalsize(buf, bufsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Need to reorder */
|
||||
newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
|
||||
+ struct_size + fdt_size_dt_strings(fdt);
|
||||
|
||||
if (bufsize < newsize)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
/* First attempt to build converted tree at beginning of buffer */
|
||||
tmp = buf;
|
||||
/* But if that overlaps with the old tree... */
|
||||
if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) {
|
||||
/* Try right after the old tree instead */
|
||||
tmp = (char *)(uintptr_t)fdtend;
|
||||
if ((tmp + newsize) > ((char *)buf + bufsize))
|
||||
return -FDT_ERR_NOSPACE;
|
||||
}
|
||||
|
||||
_fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size);
|
||||
memmove(buf, tmp, newsize);
|
||||
|
||||
fdt_set_magic(buf, FDT_MAGIC);
|
||||
fdt_set_totalsize(buf, bufsize);
|
||||
fdt_set_version(buf, 17);
|
||||
fdt_set_last_comp_version(buf, 16);
|
||||
fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_pack(void *fdt)
|
||||
{
|
||||
int mem_rsv_size;
|
||||
|
||||
FDT_RW_CHECK_HEADER(fdt);
|
||||
|
||||
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
|
||||
* sizeof(struct fdt_reserve_entry);
|
||||
_fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
|
||||
fdt_set_totalsize(fdt, _fdt_data_size(fdt));
|
||||
|
||||
return 0;
|
||||
}
|
||||
102
external/bsd/libfdt/dist/fdt_strerror.c
vendored
Normal file
102
external/bsd/libfdt/dist/fdt_strerror.c
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "libfdt_internal.h"
|
||||
|
||||
struct fdt_errtabent {
|
||||
const char *str;
|
||||
};
|
||||
|
||||
#define FDT_ERRTABENT(val) \
|
||||
[(val)] = { .str = #val, }
|
||||
|
||||
static struct fdt_errtabent fdt_errtable[] = {
|
||||
FDT_ERRTABENT(FDT_ERR_NOTFOUND),
|
||||
FDT_ERRTABENT(FDT_ERR_EXISTS),
|
||||
FDT_ERRTABENT(FDT_ERR_NOSPACE),
|
||||
|
||||
FDT_ERRTABENT(FDT_ERR_BADOFFSET),
|
||||
FDT_ERRTABENT(FDT_ERR_BADPATH),
|
||||
FDT_ERRTABENT(FDT_ERR_BADPHANDLE),
|
||||
FDT_ERRTABENT(FDT_ERR_BADSTATE),
|
||||
|
||||
FDT_ERRTABENT(FDT_ERR_TRUNCATED),
|
||||
FDT_ERRTABENT(FDT_ERR_BADMAGIC),
|
||||
FDT_ERRTABENT(FDT_ERR_BADVERSION),
|
||||
FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE),
|
||||
FDT_ERRTABENT(FDT_ERR_BADLAYOUT),
|
||||
FDT_ERRTABENT(FDT_ERR_INTERNAL),
|
||||
FDT_ERRTABENT(FDT_ERR_BADNCELLS),
|
||||
FDT_ERRTABENT(FDT_ERR_BADVALUE),
|
||||
FDT_ERRTABENT(FDT_ERR_BADOVERLAY),
|
||||
FDT_ERRTABENT(FDT_ERR_NOPHANDLES),
|
||||
};
|
||||
#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
|
||||
|
||||
const char *fdt_strerror(int errval)
|
||||
{
|
||||
if (errval > 0)
|
||||
return "<valid offset/length>";
|
||||
else if (errval == 0)
|
||||
return "<no error>";
|
||||
else if (errval > -FDT_ERRTABSIZE) {
|
||||
const char *s = fdt_errtable[-errval].str;
|
||||
|
||||
if (s)
|
||||
return s;
|
||||
}
|
||||
|
||||
return "<unknown error>";
|
||||
}
|
||||
300
external/bsd/libfdt/dist/fdt_sw.c
vendored
Normal file
300
external/bsd/libfdt/dist/fdt_sw.c
vendored
Normal file
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "libfdt_internal.h"
|
||||
|
||||
static int _fdt_sw_check_header(void *fdt)
|
||||
{
|
||||
if (fdt_magic(fdt) != FDT_SW_MAGIC)
|
||||
return -FDT_ERR_BADMAGIC;
|
||||
/* FIXME: should check more details about the header state */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define FDT_SW_CHECK_HEADER(fdt) \
|
||||
{ \
|
||||
int err; \
|
||||
if ((err = _fdt_sw_check_header(fdt)) != 0) \
|
||||
return err; \
|
||||
}
|
||||
|
||||
static void *_fdt_grab_space(void *fdt, size_t len)
|
||||
{
|
||||
int offset = fdt_size_dt_struct(fdt);
|
||||
int spaceleft;
|
||||
|
||||
spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
|
||||
- fdt_size_dt_strings(fdt);
|
||||
|
||||
if ((offset + len < offset) || (offset + len > spaceleft))
|
||||
return NULL;
|
||||
|
||||
fdt_set_size_dt_struct(fdt, offset + len);
|
||||
return _fdt_offset_ptr_w(fdt, offset);
|
||||
}
|
||||
|
||||
int fdt_create(void *buf, int bufsize)
|
||||
{
|
||||
void *fdt = buf;
|
||||
|
||||
if (bufsize < sizeof(struct fdt_header))
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
memset(buf, 0, bufsize);
|
||||
|
||||
fdt_set_magic(fdt, FDT_SW_MAGIC);
|
||||
fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
|
||||
fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
|
||||
fdt_set_totalsize(fdt, bufsize);
|
||||
|
||||
fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header),
|
||||
sizeof(struct fdt_reserve_entry)));
|
||||
fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
|
||||
fdt_set_off_dt_strings(fdt, bufsize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_resize(void *fdt, void *buf, int bufsize)
|
||||
{
|
||||
size_t headsize, tailsize;
|
||||
char *oldtail, *newtail;
|
||||
|
||||
FDT_SW_CHECK_HEADER(fdt);
|
||||
|
||||
headsize = fdt_off_dt_struct(fdt);
|
||||
tailsize = fdt_size_dt_strings(fdt);
|
||||
|
||||
if ((headsize + tailsize) > bufsize)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize;
|
||||
newtail = (char *)buf + bufsize - tailsize;
|
||||
|
||||
/* Two cases to avoid clobbering data if the old and new
|
||||
* buffers partially overlap */
|
||||
if (buf <= fdt) {
|
||||
memmove(buf, fdt, headsize);
|
||||
memmove(newtail, oldtail, tailsize);
|
||||
} else {
|
||||
memmove(newtail, oldtail, tailsize);
|
||||
memmove(buf, fdt, headsize);
|
||||
}
|
||||
|
||||
fdt_set_off_dt_strings(buf, bufsize);
|
||||
fdt_set_totalsize(buf, bufsize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
|
||||
{
|
||||
struct fdt_reserve_entry *re;
|
||||
int offset;
|
||||
|
||||
FDT_SW_CHECK_HEADER(fdt);
|
||||
|
||||
if (fdt_size_dt_struct(fdt))
|
||||
return -FDT_ERR_BADSTATE;
|
||||
|
||||
offset = fdt_off_dt_struct(fdt);
|
||||
if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
re = (struct fdt_reserve_entry *)((char *)fdt + offset);
|
||||
re->address = cpu_to_fdt64(addr);
|
||||
re->size = cpu_to_fdt64(size);
|
||||
|
||||
fdt_set_off_dt_struct(fdt, offset + sizeof(*re));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_finish_reservemap(void *fdt)
|
||||
{
|
||||
return fdt_add_reservemap_entry(fdt, 0, 0);
|
||||
}
|
||||
|
||||
int fdt_begin_node(void *fdt, const char *name)
|
||||
{
|
||||
struct fdt_node_header *nh;
|
||||
int namelen = strlen(name) + 1;
|
||||
|
||||
FDT_SW_CHECK_HEADER(fdt);
|
||||
|
||||
nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
|
||||
if (! nh)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
|
||||
memcpy(nh->name, name, namelen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_end_node(void *fdt)
|
||||
{
|
||||
fdt32_t *en;
|
||||
|
||||
FDT_SW_CHECK_HEADER(fdt);
|
||||
|
||||
en = _fdt_grab_space(fdt, FDT_TAGSIZE);
|
||||
if (! en)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
*en = cpu_to_fdt32(FDT_END_NODE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _fdt_find_add_string(void *fdt, const char *s)
|
||||
{
|
||||
char *strtab = (char *)fdt + fdt_totalsize(fdt);
|
||||
const char *p;
|
||||
int strtabsize = fdt_size_dt_strings(fdt);
|
||||
int len = strlen(s) + 1;
|
||||
int struct_top, offset;
|
||||
|
||||
p = _fdt_find_string(strtab - strtabsize, strtabsize, s);
|
||||
if (p)
|
||||
return p - strtab;
|
||||
|
||||
/* Add it */
|
||||
offset = -strtabsize - len;
|
||||
struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
|
||||
if (fdt_totalsize(fdt) + offset < struct_top)
|
||||
return 0; /* no more room :( */
|
||||
|
||||
memcpy(strtab + offset, s, len);
|
||||
fdt_set_size_dt_strings(fdt, strtabsize + len);
|
||||
return offset;
|
||||
}
|
||||
|
||||
int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)
|
||||
{
|
||||
struct fdt_property *prop;
|
||||
int nameoff;
|
||||
|
||||
FDT_SW_CHECK_HEADER(fdt);
|
||||
|
||||
nameoff = _fdt_find_add_string(fdt, name);
|
||||
if (nameoff == 0)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
|
||||
if (! prop)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
prop->tag = cpu_to_fdt32(FDT_PROP);
|
||||
prop->nameoff = cpu_to_fdt32(nameoff);
|
||||
prop->len = cpu_to_fdt32(len);
|
||||
*valp = prop->data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_property(void *fdt, const char *name, const void *val, int len)
|
||||
{
|
||||
void *ptr;
|
||||
int ret;
|
||||
|
||||
ret = fdt_property_placeholder(fdt, name, len, &ptr);
|
||||
if (ret)
|
||||
return ret;
|
||||
memcpy(ptr, val, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_finish(void *fdt)
|
||||
{
|
||||
char *p = (char *)fdt;
|
||||
fdt32_t *end;
|
||||
int oldstroffset, newstroffset;
|
||||
uint32_t tag;
|
||||
int offset, nextoffset;
|
||||
|
||||
FDT_SW_CHECK_HEADER(fdt);
|
||||
|
||||
/* Add terminator */
|
||||
end = _fdt_grab_space(fdt, sizeof(*end));
|
||||
if (! end)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
*end = cpu_to_fdt32(FDT_END);
|
||||
|
||||
/* Relocate the string table */
|
||||
oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);
|
||||
newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
|
||||
memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));
|
||||
fdt_set_off_dt_strings(fdt, newstroffset);
|
||||
|
||||
/* Walk the structure, correcting string offsets */
|
||||
offset = 0;
|
||||
while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
|
||||
if (tag == FDT_PROP) {
|
||||
struct fdt_property *prop =
|
||||
_fdt_offset_ptr_w(fdt, offset);
|
||||
int nameoff;
|
||||
|
||||
nameoff = fdt32_to_cpu(prop->nameoff);
|
||||
nameoff += fdt_size_dt_strings(fdt);
|
||||
prop->nameoff = cpu_to_fdt32(nameoff);
|
||||
}
|
||||
offset = nextoffset;
|
||||
}
|
||||
if (nextoffset < 0)
|
||||
return nextoffset;
|
||||
|
||||
/* Finally, adjust the header */
|
||||
fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
|
||||
fdt_set_magic(fdt, FDT_MAGIC);
|
||||
return 0;
|
||||
}
|
||||
139
external/bsd/libfdt/dist/fdt_wip.c
vendored
Normal file
139
external/bsd/libfdt/dist/fdt_wip.c
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "libfdt_internal.h"
|
||||
|
||||
int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
|
||||
const char *name, int namelen,
|
||||
uint32_t idx, const void *val,
|
||||
int len)
|
||||
{
|
||||
void *propval;
|
||||
int proplen;
|
||||
|
||||
propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen,
|
||||
&proplen);
|
||||
if (!propval)
|
||||
return proplen;
|
||||
|
||||
if (proplen < (len + idx))
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
memcpy((char *)propval + idx, val, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
|
||||
const void *val, int len)
|
||||
{
|
||||
const void *propval;
|
||||
int proplen;
|
||||
|
||||
propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
|
||||
if (!propval)
|
||||
return proplen;
|
||||
|
||||
if (proplen != len)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name,
|
||||
strlen(name), 0,
|
||||
val, len);
|
||||
}
|
||||
|
||||
static void _fdt_nop_region(void *start, int len)
|
||||
{
|
||||
fdt32_t *p;
|
||||
|
||||
for (p = start; (char *)p < ((char *)start + len); p++)
|
||||
*p = cpu_to_fdt32(FDT_NOP);
|
||||
}
|
||||
|
||||
int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
|
||||
{
|
||||
struct fdt_property *prop;
|
||||
int len;
|
||||
|
||||
prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
|
||||
if (!prop)
|
||||
return len;
|
||||
|
||||
_fdt_nop_region(prop, len + sizeof(*prop));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _fdt_node_end_offset(void *fdt, int offset)
|
||||
{
|
||||
int depth = 0;
|
||||
|
||||
while ((offset >= 0) && (depth >= 0))
|
||||
offset = fdt_next_node(fdt, offset, &depth);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int fdt_nop_node(void *fdt, int nodeoffset)
|
||||
{
|
||||
int endoffset;
|
||||
|
||||
endoffset = _fdt_node_end_offset(fdt, nodeoffset);
|
||||
if (endoffset < 0)
|
||||
return endoffset;
|
||||
|
||||
_fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0),
|
||||
endoffset - nodeoffset);
|
||||
return 0;
|
||||
}
|
||||
111
external/bsd/libfdt/dist/include/fdt.h
vendored
Normal file
111
external/bsd/libfdt/dist/include/fdt.h
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
#ifndef _FDT_H
|
||||
#define _FDT_H
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
* Copyright 2012 Kim Phillips, Freescale Semiconductor.
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
struct fdt_header {
|
||||
fdt32_t magic; /* magic word FDT_MAGIC */
|
||||
fdt32_t totalsize; /* total size of DT block */
|
||||
fdt32_t off_dt_struct; /* offset to structure */
|
||||
fdt32_t off_dt_strings; /* offset to strings */
|
||||
fdt32_t off_mem_rsvmap; /* offset to memory reserve map */
|
||||
fdt32_t version; /* format version */
|
||||
fdt32_t last_comp_version; /* last compatible version */
|
||||
|
||||
/* version 2 fields below */
|
||||
fdt32_t boot_cpuid_phys; /* Which physical CPU id we're
|
||||
booting on */
|
||||
/* version 3 fields below */
|
||||
fdt32_t size_dt_strings; /* size of the strings block */
|
||||
|
||||
/* version 17 fields below */
|
||||
fdt32_t size_dt_struct; /* size of the structure block */
|
||||
};
|
||||
|
||||
struct fdt_reserve_entry {
|
||||
fdt64_t address;
|
||||
fdt64_t size;
|
||||
};
|
||||
|
||||
struct fdt_node_header {
|
||||
fdt32_t tag;
|
||||
char name[0];
|
||||
};
|
||||
|
||||
struct fdt_property {
|
||||
fdt32_t tag;
|
||||
fdt32_t len;
|
||||
fdt32_t nameoff;
|
||||
char data[0];
|
||||
};
|
||||
|
||||
#endif /* !__ASSEMBLY */
|
||||
|
||||
#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */
|
||||
#define FDT_TAGSIZE sizeof(fdt32_t)
|
||||
|
||||
#define FDT_BEGIN_NODE 0x1 /* Start node: full name */
|
||||
#define FDT_END_NODE 0x2 /* End node */
|
||||
#define FDT_PROP 0x3 /* Property: name off,
|
||||
size, content */
|
||||
#define FDT_NOP 0x4 /* nop */
|
||||
#define FDT_END 0x9
|
||||
|
||||
#define FDT_V1_SIZE (7*sizeof(fdt32_t))
|
||||
#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t))
|
||||
#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t))
|
||||
#define FDT_V16_SIZE FDT_V3_SIZE
|
||||
#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t))
|
||||
|
||||
#endif /* _FDT_H */
|
||||
1868
external/bsd/libfdt/dist/include/libfdt.h
vendored
Normal file
1868
external/bsd/libfdt/dist/include/libfdt.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
112
external/bsd/libfdt/dist/include/libfdt_env.h
vendored
Normal file
112
external/bsd/libfdt/dist/include/libfdt_env.h
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
#ifndef _LIBFDT_ENV_H
|
||||
#define _LIBFDT_ENV_H
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
* Copyright 2012 Kim Phillips, Freescale Semiconductor.
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __CHECKER__
|
||||
#define FDT_FORCE __attribute__((force))
|
||||
#define FDT_BITWISE __attribute__((bitwise))
|
||||
#else
|
||||
#define FDT_FORCE
|
||||
#define FDT_BITWISE
|
||||
#endif
|
||||
|
||||
typedef uint16_t FDT_BITWISE fdt16_t;
|
||||
typedef uint32_t FDT_BITWISE fdt32_t;
|
||||
typedef uint64_t FDT_BITWISE fdt64_t;
|
||||
|
||||
#define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n])
|
||||
#define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1))
|
||||
#define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \
|
||||
(EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3))
|
||||
#define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \
|
||||
(EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \
|
||||
(EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \
|
||||
(EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7))
|
||||
|
||||
static inline uint16_t fdt16_to_cpu(fdt16_t x)
|
||||
{
|
||||
return (FDT_FORCE uint16_t)CPU_TO_FDT16(x);
|
||||
}
|
||||
static inline fdt16_t cpu_to_fdt16(uint16_t x)
|
||||
{
|
||||
return (FDT_FORCE fdt16_t)CPU_TO_FDT16(x);
|
||||
}
|
||||
|
||||
static inline uint32_t fdt32_to_cpu(fdt32_t x)
|
||||
{
|
||||
return (FDT_FORCE uint32_t)CPU_TO_FDT32(x);
|
||||
}
|
||||
static inline fdt32_t cpu_to_fdt32(uint32_t x)
|
||||
{
|
||||
return (FDT_FORCE fdt32_t)CPU_TO_FDT32(x);
|
||||
}
|
||||
|
||||
static inline uint64_t fdt64_to_cpu(fdt64_t x)
|
||||
{
|
||||
return (FDT_FORCE uint64_t)CPU_TO_FDT64(x);
|
||||
}
|
||||
static inline fdt64_t cpu_to_fdt64(uint64_t x)
|
||||
{
|
||||
return (FDT_FORCE fdt64_t)CPU_TO_FDT64(x);
|
||||
}
|
||||
#undef CPU_TO_FDT64
|
||||
#undef CPU_TO_FDT32
|
||||
#undef CPU_TO_FDT16
|
||||
#undef EXTRACT_BYTE
|
||||
|
||||
#endif /* _LIBFDT_ENV_H */
|
||||
95
external/bsd/libfdt/dist/include/libfdt_internal.h
vendored
Normal file
95
external/bsd/libfdt/dist/include/libfdt_internal.h
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
#ifndef _LIBFDT_INTERNAL_H
|
||||
#define _LIBFDT_INTERNAL_H
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "fdt.h"
|
||||
|
||||
#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
|
||||
#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
|
||||
|
||||
#define FDT_CHECK_HEADER(fdt) \
|
||||
{ \
|
||||
int __err; \
|
||||
if ((__err = fdt_check_header(fdt)) != 0) \
|
||||
return __err; \
|
||||
}
|
||||
|
||||
int _fdt_check_node_offset(const void *fdt, int offset);
|
||||
int _fdt_check_prop_offset(const void *fdt, int offset);
|
||||
const char *_fdt_find_string(const char *strtab, int tabsize, const char *s);
|
||||
int _fdt_node_end_offset(void *fdt, int nodeoffset);
|
||||
|
||||
static inline const void *_fdt_offset_ptr(const void *fdt, int offset)
|
||||
{
|
||||
return (const char *)fdt + fdt_off_dt_struct(fdt) + offset;
|
||||
}
|
||||
|
||||
static inline void *_fdt_offset_ptr_w(void *fdt, int offset)
|
||||
{
|
||||
return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset);
|
||||
}
|
||||
|
||||
static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n)
|
||||
{
|
||||
const struct fdt_reserve_entry *rsv_table =
|
||||
(const struct fdt_reserve_entry *)
|
||||
((const char *)fdt + fdt_off_mem_rsvmap(fdt));
|
||||
|
||||
return rsv_table + n;
|
||||
}
|
||||
static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n)
|
||||
{
|
||||
return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n);
|
||||
}
|
||||
|
||||
#define FDT_SW_MAGIC (~FDT_MAGIC)
|
||||
|
||||
#endif /* _LIBFDT_INTERNAL_H */
|
||||
15
external/bsd/libfdt/include/Makefile
vendored
Normal file
15
external/bsd/libfdt/include/Makefile
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
.include <bsd.init.mk>
|
||||
|
||||
SRCDIST= ${NETBSDSRCDIR}/external/bsd/libfdt/dist
|
||||
|
||||
.PATH: ${SRCDIST} ${SRCDIST}/include
|
||||
|
||||
INCSDIR=/usr/include/
|
||||
|
||||
INCS= \
|
||||
fdt.h \
|
||||
libfdt.h \
|
||||
libfdt_env.h \
|
||||
libfdt_internal.h
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
17
external/bsd/libfdt/lib/Makefile
vendored
Normal file
17
external/bsd/libfdt/lib/Makefile
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
.include <bsd.init.mk>
|
||||
|
||||
SRCDIST= ${NETBSDSRCDIR}/external/bsd/libfdt/dist
|
||||
SRCDIR= ${NETBSDSRCDIR}/external/bsd/libfdt
|
||||
|
||||
LIB= fdt
|
||||
|
||||
SRCS= fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c \
|
||||
fdt_addresses.c fdt_overlay.c
|
||||
|
||||
.PATH: ${SRCDIST} ${SRCDIST}/include
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
CPPFLAGS+= -I${SRCDIST} -I${SRCDIR}/include -I${SRCDIST}/include
|
||||
|
||||
.include <bsd.lib.mk>
|
||||
71
external/bsd/libfdt/libfdt2netbsd
vendored
Normal file
71
external/bsd/libfdt/libfdt2netbsd
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
#! /bin/sh
|
||||
#
|
||||
# $NetBSD: libfdt2netbsd,v 1.2 2014/11/19 19:33:30 christos Exp $
|
||||
#
|
||||
# Copyright (c) 2011 The NetBSD Foundation, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# libfdt2netbsd: convert an libfdt source tree into a
|
||||
# netbsd libfdt source tree, under src/dist,
|
||||
#
|
||||
# Rough instructions for importing new libfdt release:
|
||||
#
|
||||
# $ cd /some/where/temporary
|
||||
# $ tar xpfz /new/libfdt/release/tar/file
|
||||
# $ sh /usr/src/external/bsd/libfdt/libfdt2netbsd libfdt-x.y.z
|
||||
# $ cd libfdt-x.y.z
|
||||
# $ cvs -d cvs.netbsd.org:/cvsroot import -m "Import libfdt-x.y.z" src/external/bsd/libfdt/dist TCPDUMP libfdt-x_y_z
|
||||
# - check makefiles to see if any extra sources have been added.
|
||||
# - update distrib/sets if necessary.
|
||||
|
||||
if [ $# -ne 1 ]; then echo "libfdt2netbsd src"; exit 1; fi
|
||||
|
||||
r=$1
|
||||
case "$r" in
|
||||
/*)
|
||||
;;
|
||||
*)
|
||||
r=`/bin/pwd`/$r
|
||||
;;
|
||||
esac
|
||||
|
||||
cd $r
|
||||
|
||||
### Remove the $'s around RCS tags
|
||||
cleantags $r
|
||||
|
||||
### Clean up any CVS directories that might be around.
|
||||
echo "cleaning up CVS residue."
|
||||
find $r -type d -name "CVS" -print | xargs rm -r
|
||||
echo done
|
||||
|
||||
### Fixing file and directory permissions.
|
||||
echo "Fixing file/directory permissions."
|
||||
(
|
||||
find $r -type f -print | xargs chmod u+rw,go+r
|
||||
find $r -type d -print | xargs chmod u+rwx,go+rx
|
||||
)
|
||||
echo done
|
||||
|
||||
exit 0
|
||||
@@ -82,7 +82,7 @@ SUBDIR+= \
|
||||
libpci libprop \
|
||||
libpuffs librmt \
|
||||
libterminfo \
|
||||
libutil libz
|
||||
libutil libz \
|
||||
|
||||
.if !defined(BSD_MK_COMPAT_FILE)
|
||||
#SUBDIR+= libkern
|
||||
@@ -110,6 +110,7 @@ SUBDIR+= ../external/apache2/mDNSResponder/lib
|
||||
|
||||
#SUBDIR+= ../external/bsd/am-utils/lib
|
||||
SUBDIR+= ../external/bsd/blacklist/lib
|
||||
SUBDIR+= ../external/bsd/libfdt/lib
|
||||
|
||||
SUBDIR+= ../external/bsd/flex/lib
|
||||
#SUBDIR+= ../external/bsd/tre/lib
|
||||
|
||||
@@ -220,6 +220,9 @@ do
|
||||
des="keyboard input $n"
|
||||
dev=kbd$n
|
||||
;;
|
||||
15,0)
|
||||
dev=mailbox
|
||||
;;
|
||||
64,64)
|
||||
des="mouse input multiplexer"
|
||||
dev=mousemux
|
||||
|
||||
@@ -26,6 +26,7 @@ RAMDISK_DEVICES="
|
||||
c1d4 c1d4p0 c1d4p0s0 c1d5 c1d5p0 c1d5p0s0
|
||||
c1d6 c1d6p0 c1d6p0s0 c1d7 c1d7p0 c1d7p0s0
|
||||
fd0 fd1 fd0p0 fd1p0
|
||||
mailbox
|
||||
pci
|
||||
ttyc1 ttyc2 ttyc3 tty00 tty01 tty02 tty03
|
||||
"
|
||||
@@ -138,6 +139,7 @@ Where key is one of the following:
|
||||
filter # Make /dev/filter
|
||||
fbd # Make /dev/fbd
|
||||
hello # Make /dev/hello
|
||||
mailbox # Make /dev/mailbox
|
||||
video # Make /dev/video
|
||||
pci # Make /dev/pci
|
||||
vnd0 vnd0p0 vnd0p0s0 .. # Make vnode disks /dev/vnd[0-7] and (sub)partitions
|
||||
@@ -354,6 +356,9 @@ do
|
||||
# Logging device.
|
||||
makedev ${dev} c 15 0 ${uname} ${gname} ${permissions}
|
||||
;;
|
||||
mailbox)
|
||||
makedev ${dev} c 22 0 ${uname} ${gname} 0666
|
||||
;;
|
||||
pc[0-3]|at[0-3]|qd[0-3]|ps[0-3]|pat[0-3]|qh[0-3]|PS[0-3])
|
||||
# Obsolete density locked floppy disk drive n.
|
||||
drive=`expr ${dev} : '.*\\(.\\)'`
|
||||
|
||||
@@ -71,14 +71,14 @@ int open_audio(unsigned int *fragment_size, unsigned int channels,
|
||||
{
|
||||
unsigned int sign;
|
||||
int audio;
|
||||
|
||||
printf ("before open\n");
|
||||
/* Open DSP */
|
||||
if ((audio = open("/dev/audio", O_RDWR)) < 0)
|
||||
{
|
||||
printf("Cannot open /dev/audio: %s\n", strerror(errno));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
printf ("before ioctl\n");
|
||||
ioctl(audio, DSPIOMAX, fragment_size); /* Get maximum fragment size. */
|
||||
|
||||
/* Set DSP parameters (should check return values..) */
|
||||
@@ -145,7 +145,7 @@ int main ( int argc, char *argv[] )
|
||||
printf("%s not in MicroSoft PCM format\n", file_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf ("before open audio\n");
|
||||
/* Open audio device and set DSP parameters */
|
||||
audio = open_audio(&fragment_size, c_fields.Channels - 1,
|
||||
c_fields.SamplesPerSec, s_fields.BitsPerSample);
|
||||
@@ -199,7 +199,7 @@ int main ( int argc, char *argv[] )
|
||||
buffer[i] = buffer[(int)data_len-1];
|
||||
data_len = 0;
|
||||
}
|
||||
|
||||
printf ("before write\n");
|
||||
/* Copy data to DSP */
|
||||
r= write(audio, buffer, fragment_size);
|
||||
if (r != fragment_size)
|
||||
|
||||
@@ -6,4 +6,7 @@ SUBDIR+= es1371
|
||||
SUBDIR+= sb16
|
||||
.endif # ${MACHINE_ARCH} == "i386"
|
||||
|
||||
.if ${MACHINE_ARCH} == "earm"
|
||||
SUBDIR+= pcm
|
||||
.endif # ${MACHINE_ARCH} == "earm"
|
||||
.include <bsd.subdir.mk>
|
||||
|
||||
8
minix/drivers/audio/pcm/Makefile
Normal file
8
minix/drivers/audio/pcm/Makefile
Normal file
@@ -0,0 +1,8 @@
|
||||
# Makefile for the PCM broadcom driver
|
||||
PROG= pcm
|
||||
SRCS= pcm.c
|
||||
|
||||
DPADD+= ${LIBAUDIODRIVER} ${LIBCHARDRIVER} ${LIBSYS}
|
||||
LDADD+= -laudiodriver -lchardriver -lsys
|
||||
|
||||
.include <minix.service.mk>
|
||||
499
minix/drivers/audio/pcm/pcm.c
Normal file
499
minix/drivers/audio/pcm/pcm.c
Normal file
@@ -0,0 +1,499 @@
|
||||
#include <minix/com.h>
|
||||
#include <minix/vm.h>
|
||||
#include <minix/mmio.h>
|
||||
#include <minix/type.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <minix/padconf.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "pcm.h"
|
||||
|
||||
#include <minix/log.h>
|
||||
|
||||
static void dsp_dma_setup(phys_bytes address, int count, int sub_dev);
|
||||
|
||||
static int dsp_ioctl(unsigned long request, void *val, int *len);
|
||||
static int dsp_set_size(unsigned int size);
|
||||
static int dsp_set_speed(unsigned int speed);
|
||||
static int dsp_set_stereo(unsigned int stereo);
|
||||
static int dsp_set_bits(unsigned int bits);
|
||||
static int dsp_set_sign(unsigned int sign);
|
||||
static int dsp_get_max_frag_size(u32_t *val, int *len);
|
||||
|
||||
static void clock_stop();
|
||||
static void clock_start();
|
||||
|
||||
static unsigned int DspStereo = DEFAULT_STEREO;
|
||||
static unsigned int DspSpeed = DEFAULT_SPEED;
|
||||
static unsigned int DspBits = DEFAULT_BITS;
|
||||
static unsigned int DspSign = DEFAULT_SIGN;
|
||||
static unsigned int DspFragmentSize;
|
||||
|
||||
static phys_bytes DmaPhys;
|
||||
static int running = FALSE;
|
||||
|
||||
/*
|
||||
* Define a structure to be used for logging
|
||||
*/
|
||||
static struct log log = {
|
||||
.name = "pcm",
|
||||
.log_level = LEVEL_DEBUG,
|
||||
.log_func = default_log
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t TI;
|
||||
uint32_t SRC_AD;
|
||||
uint32_t DST_AD;
|
||||
uint32_t TXR_LEN;
|
||||
uint32_t STRIDE;
|
||||
uint32_t NEXTCONBK;
|
||||
uint32_t unused1;
|
||||
uint32_t unused2;
|
||||
} ctrl_blk_t;
|
||||
|
||||
ctrl_blk_t ctrl_blk __attribute__((aligned(32)));
|
||||
|
||||
sub_dev_t sub_dev[2];
|
||||
special_file_t special_file[3];
|
||||
drv_t drv;
|
||||
uint32_t io_base;
|
||||
uint32_t clk_base;
|
||||
uint32_t dma_base;
|
||||
|
||||
int drv_init(void)
|
||||
{
|
||||
drv.DriverName = "pcm";
|
||||
drv.NrOfSubDevices = 1;
|
||||
drv.NrOfSpecialFiles = 2;
|
||||
|
||||
sub_dev[AUDIO].readable = 1;
|
||||
sub_dev[AUDIO].writable = 1;
|
||||
sub_dev[AUDIO].DmaSize = 16 * 1024;
|
||||
sub_dev[AUDIO].NrOfDmaFragments = 2;
|
||||
sub_dev[AUDIO].MinFragmentSize = 1024;
|
||||
sub_dev[AUDIO].NrOfExtraBuffers = 4;
|
||||
|
||||
special_file[0].minor_dev_nr = 0;
|
||||
special_file[0].write_chan = AUDIO;
|
||||
special_file[0].read_chan = NO_CHANNEL;
|
||||
special_file[0].io_ctl = AUDIO;
|
||||
|
||||
special_file[1].minor_dev_nr = 1;
|
||||
special_file[1].write_chan = NO_CHANNEL;
|
||||
special_file[1].read_chan = AUDIO;
|
||||
special_file[1].io_ctl = AUDIO;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static void config_clk()
|
||||
{
|
||||
log_debug(&log, "config clk starts\n");
|
||||
|
||||
struct minix_mem_range mr;
|
||||
|
||||
mr.mr_base = CLK_BASE;
|
||||
mr.mr_limit = CLK_BASE + CLK_REG_SIZE;
|
||||
|
||||
/* grant ourself rights to map the register memory */
|
||||
if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) {
|
||||
panic("Unable to request permission to map memory");
|
||||
}
|
||||
|
||||
/* Set the base address to use */
|
||||
clk_base =
|
||||
(uint32_t) vm_map_phys(SELF, (void *) CLK_BASE,
|
||||
CLK_REG_SIZE);
|
||||
|
||||
if (clk_base == (uint32_t) MAP_FAILED)
|
||||
panic("Unable to map clock memory");
|
||||
}
|
||||
|
||||
static void config_dma()
|
||||
{
|
||||
log_debug(&log, "config dma starts\n");
|
||||
|
||||
struct minix_mem_range mr;
|
||||
|
||||
mr.mr_base = DMA_BASE + DMA_REG_SIZE * DMA_CHAN;
|
||||
mr.mr_limit = mr.mr_base + DMA_REG_SIZE;
|
||||
|
||||
/* grant ourself rights to map the register memory */
|
||||
if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) {
|
||||
panic("Unable to request permission to map memory");
|
||||
}
|
||||
|
||||
/* Set the base address to use */
|
||||
dma_base =
|
||||
(uint32_t) vm_map_phys(SELF, (void *) DMA_BASE + DMA_REG_SIZE * DMA_CHAN,
|
||||
DMA_REG_SIZE);
|
||||
|
||||
if (dma_base == (uint32_t) MAP_FAILED)
|
||||
panic("Unable to map dma memory");
|
||||
}
|
||||
|
||||
static void
|
||||
pcm_padconf()
|
||||
{
|
||||
log_debug(&log, "padconf starts\n");
|
||||
|
||||
int r;
|
||||
uint32_t pinopts = CONTROL_BCM_CONF_PCM_CLK;
|
||||
|
||||
r = sys_padconf(GPFSEL1019, pinopts,
|
||||
pinopts);
|
||||
if (r != OK) {
|
||||
log_warn(&log, "padconf failed (r=%d)\n", r);
|
||||
}
|
||||
|
||||
log_debug(&log, "pinopts=0x%x\n", pinopts);
|
||||
}
|
||||
|
||||
int drv_init_hw(void)
|
||||
{
|
||||
int i;
|
||||
log_debug(&log, "drv_init_hw starts\n");
|
||||
struct minix_mem_range mr;
|
||||
|
||||
mr.mr_base = I2S_BASE;
|
||||
mr.mr_limit = I2S_BASE + I2S_REG_SIZE;
|
||||
|
||||
/* grant ourself rights to map the register memory */
|
||||
if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) {
|
||||
panic("Unable to request permission to map memory");
|
||||
}
|
||||
|
||||
/* Set the base address to use */
|
||||
io_base =
|
||||
(uint32_t) vm_map_phys(SELF, (void *) I2S_BASE,
|
||||
I2S_REG_SIZE);
|
||||
|
||||
if (io_base == (uint32_t) MAP_FAILED)
|
||||
panic("Unable to map I2S memory");
|
||||
|
||||
if(drv_reset () != OK) {
|
||||
log_debug(&log, "No audio card detected\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
config_clk();
|
||||
|
||||
config_dma();
|
||||
|
||||
pcm_padconf();
|
||||
|
||||
pcm_write(PCM_TXC_A, PCM_TXC_A_CH1WID16 | PCM_TXC_A_CH2WID16 |
|
||||
PCM_TXC_A_CH1EN | PCM_TXC_A_CH2EN);
|
||||
/* Set frame start position */
|
||||
pcm_set(PCM_TXC_A, (1 << 20) | (33 << 4), (1 << 20) | (33 << 4));
|
||||
pcm_set(PCM_MODE_A, PCM_MODE_A_FTXP | (63 << 10) | 32,
|
||||
PCM_MODE_A_FTXP | (63 << 10) | 32);
|
||||
|
||||
pcm_set(PCM_CS_A, PCM_CS_A_STBY, PCM_CS_A_STBY);
|
||||
for(i = 0; i < 1000; i++); /* wait a while */
|
||||
|
||||
pcm_set(PCM_CS_A, PCM_CS_A_TXCLR, PCM_CS_A_TXCLR);
|
||||
|
||||
pcm_set(PCM_CS_A, PCM_CS_A_TXCHR, 1);
|
||||
|
||||
for (i = 0; i < 32; i++)
|
||||
pcm_write(PCM_FIFO_A, 0);
|
||||
|
||||
pcm_set(PCM_CS_A, PCM_CS_A_SYNC, 0);
|
||||
|
||||
pcm_write(PCM_INTSTC_A, PCM_INTSTC_A_TXW |
|
||||
PCM_INTSTC_A_RXR | PCM_INTSTC_A_TXERR | PCM_INTSTC_A_RXERR);
|
||||
pcm_write(PCM_INTEN_A, PCM_INTEN_A_TXW | PCM_INTEN_A_TXERR);
|
||||
|
||||
pcm_set(PCM_CS_A, PCM_CS_A_EN, PCM_CS_A_EN);
|
||||
pcm_set(PCM_CS_A, PCM_CS_A_TXON, PCM_CS_A_TXON);
|
||||
|
||||
DspFragmentSize = sub_dev[AUDIO].DmaSize / sub_dev[AUDIO].NrOfDmaFragments;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int drv_reset(void)
|
||||
{
|
||||
int i;
|
||||
log_debug(&log, "drv_reset starts\n");
|
||||
|
||||
uint32_t ctrl = pcm_read(PCM_CS_A);
|
||||
ctrl &= (~PCM_CS_A_EN);
|
||||
pcm_write(PCM_CS_A, ctrl);
|
||||
for(i = 0; i < 1000; i++); /* wait a while */
|
||||
|
||||
ctrl = pcm_read(PCM_CS_A);
|
||||
ctrl |= PCM_CS_A_EN;
|
||||
pcm_write(PCM_CS_A, ctrl);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int drv_start(int channel, int DmaMode)
|
||||
{
|
||||
int i;
|
||||
|
||||
log_debug(&log, "drv_start starts\n");
|
||||
|
||||
drv_reset();
|
||||
|
||||
ctrl_blk.SRC_AD = DmaPhys;
|
||||
ctrl_blk.TXR_LEN = DspFragmentSize * sub_dev[channel].NrOfDmaFragments;
|
||||
ctrl_blk.TI = PERMAP_SET(DREQ_TX) | DMA_TI_SRC_DREQ | DMA_TI_INTEN;
|
||||
dsp_dma_setup(DmaMode);
|
||||
|
||||
dsp_set_speed(DspSpeed);
|
||||
|
||||
clock_stop();
|
||||
|
||||
if (!DspStereo)
|
||||
pcm_set(PCM_TXC_A, PCM_TXC_A_CH2EN, 0);
|
||||
|
||||
pcm_set(PCM_CS_A, PCM_CS_A_STBY, PCM_CS_A_STBY);
|
||||
|
||||
running = TRUE;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static void clock_start()
|
||||
{
|
||||
set32(clk_base + CLK_PCMCTL,
|
||||
BCM2708_CLK_PASSWD_MASK | BCM2708_CLK_ENAB,
|
||||
BCM2708_CLK_PASSWD | BCM2708_CLK_ENAB);
|
||||
}
|
||||
|
||||
static int clock_stop()
|
||||
{
|
||||
int timeout = 1000;
|
||||
uint32_t clkreg;
|
||||
|
||||
set32(clk_base + CLK_PCMCTL,
|
||||
PCM_CLK_PASSWD_MASK | PCM_CLK_ENAB,
|
||||
PCM_CLK_PASSWD);
|
||||
|
||||
while (--timeout) {
|
||||
read32(clk_base + CLK_PCMCTL, &clkreg);
|
||||
if (!(clkreg & PCM_CLK_BUSY))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!timeout) {
|
||||
/* KILL the clock */
|
||||
log_warn(&log, "PCM clock didn't stop. Kill the clock!\n");
|
||||
set32(clk_base + CLK_PCMCTL,
|
||||
PCM_CLK_KILL | PCM_CLK_PASSWD_MASK,
|
||||
PCM_CLK_KILL | PCM_CLK_PASSWD);
|
||||
}
|
||||
}
|
||||
|
||||
int drv_stop(int sub_dev)
|
||||
{
|
||||
if(running) {
|
||||
log_debug(&log, "drv_stop start\n");
|
||||
pcm_set(PCM_CS_A, PCM_CS_A_TXON, 0);
|
||||
running = FALSE;
|
||||
drv_reenable_int(sub_dev);
|
||||
|
||||
clock_stop();
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
int drv_set_dma(u32_t dma, u32_t UNUSED(length), int UNUSED(chan))
|
||||
{
|
||||
log_debug(&log, "drv_set_dma starts\n");
|
||||
DmaPhys = dma;
|
||||
return OK;
|
||||
}
|
||||
|
||||
int drv_reenable_int(int UNUSED(chan))
|
||||
{
|
||||
log_debug(&log, "drv_reenable_int starts\n");
|
||||
pcm_write(PCM_INTEN_A, PCM_INTEN_A_TXW | PCM_INTEN_A_TXERR);
|
||||
return OK;
|
||||
}
|
||||
|
||||
int drv_pause(int chan)
|
||||
{
|
||||
drv_stop(chan);
|
||||
return OK;
|
||||
}
|
||||
|
||||
int drv_resume(int UNUSED(chan))
|
||||
{
|
||||
start_clock();
|
||||
pcm_set(PCM_CS_A, PCM_CS_A_TXON, PCM_CS_A_TXON);
|
||||
return OK;
|
||||
}
|
||||
|
||||
int drv_io_ctl(unsigned long request, void *val, int *len, int sub_dev)
|
||||
{
|
||||
log_debug(&log, "got ioctl %lu, argument: %d sub_dev: %d\n",
|
||||
request, val, sub_dev);
|
||||
|
||||
if(sub_dev == AUDIO)
|
||||
return dsp_ioctl(request, val, len);
|
||||
|
||||
return EIO;
|
||||
}
|
||||
|
||||
int drv_get_irq(char *irq)
|
||||
{
|
||||
log_debug(&log, "drv_get_irq starts\n");
|
||||
*irq = PCM_IRQ;
|
||||
return OK;
|
||||
}
|
||||
|
||||
int drv_get_frag_size(u32_t *frag_size, int UNUSED(sub_dev))
|
||||
{
|
||||
log_debug(&log, "drv_get_frag_size starts\n");
|
||||
*frag_size = DspFragmentSize;
|
||||
return OK;
|
||||
}
|
||||
|
||||
int drv_int(int sub_dev) {
|
||||
return sub_dev == AUDIO;
|
||||
}
|
||||
|
||||
static int dsp_ioctl(unsigned long request, void *val, int *len)
|
||||
{
|
||||
int status;
|
||||
|
||||
switch(request) {
|
||||
case DSPIORATE: status = dsp_set_speed(*((u32_t*) val)); break;
|
||||
case DSPIOSTEREO: status = dsp_set_stereo(*((u32_t*) val)); break;
|
||||
case DSPIOSIZE: status = dsp_set_size(*((u32_t*) val)); break;
|
||||
case DSPIOBITS: status = dsp_set_bits(*((u32_t*) val)); break;
|
||||
case DSPIOSIGN: status = dsp_set_sign(*((u32_t*) val)); break;
|
||||
case DSPIOMAX: status = dsp_get_max_frag_size(val, len); break;
|
||||
case DSPIORESET: status = drv_reset(); break;
|
||||
default: status = ENOTTY; break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void dsp_dma_setup(int DmaMode)
|
||||
{
|
||||
pvb_pair_t pvb[9];
|
||||
|
||||
log_debug(&log, "Setting up %d bit DMA\n", DspBits);
|
||||
if(DspBits == 16 || DspBits == 8) { /* 16 bit sound */
|
||||
count -= 2;
|
||||
pcm_set(PCM_CS_A, PCM_CS_A_DMAEN, 0); /* put speaker on */
|
||||
|
||||
write32(dma_base + DMA_CS, DMA_CS_END);
|
||||
|
||||
write32(dma_base + DMA_CONBLK, &ctrl_blk);
|
||||
|
||||
pcm_write(PCM_DREQ_A, PCM_TX_PANIC(0x10) |
|
||||
PCM_RX_PANIC(0x30) | PCM_TX(0x30) | PCM_RX(0x20), 0xffffffff);
|
||||
|
||||
pcm_set(PCM_CS_A, PCM_CS_A_DMAEN, PCM_CS_A_DMAEN); /* put speaker on */
|
||||
|
||||
set32(dma_base + DMA_CS, DMA_CS_ACTIVE, DMA_CS_ACTIVE);
|
||||
}
|
||||
}
|
||||
|
||||
static int dsp_set_size(unsigned int size)
|
||||
{
|
||||
log_debug(&log, "set fragment size to %u\n", size);
|
||||
|
||||
/* Sanity checks */
|
||||
if(size < sub_dev[AUDIO].MinFragmentSize || size > sub_dev[AUDIO].DmaSize / sub_dev[AUDIO].NrOfDmaFragments || size % 2 != 0) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
DspFragmentSize = size;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int dsp_set_speed(unsigned int speed)
|
||||
{
|
||||
log_debug(&log, "setting speed to %u, stereo = %d\n", speed, DspStereo);
|
||||
|
||||
if(speed < DSP_MIN_SPEED || speed > DSP_MAX_SPEED) {
|
||||
return EPERM;
|
||||
}
|
||||
|
||||
DspSpeed = speed;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int dsp_set_stereo(unsigned int stereo)
|
||||
{
|
||||
if(stereo) {
|
||||
DspStereo = 1;
|
||||
} else {
|
||||
DspStereo = 0;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int dsp_set_bits(unsigned int bits)
|
||||
{
|
||||
/* Sanity checks */
|
||||
if(bits != 16 && bits != 8) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
DspBits = bits;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int dsp_set_sign(unsigned int sign)
|
||||
{
|
||||
log_debug(&log, "set sign to %u\n", sign);
|
||||
|
||||
DspSign = (sign > 0 ? 1 : 0);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int dsp_get_max_frag_size(u32_t *val, int *len)
|
||||
{
|
||||
*len = sizeof(*val);
|
||||
*val = sub_dev[AUDIO].DmaSize / sub_dev[AUDIO].NrOfDmaFragments;
|
||||
return OK;
|
||||
}
|
||||
|
||||
void
|
||||
pcm_set(vir_bytes reg, uint32_t mask, uint32_t value)
|
||||
{
|
||||
if(reg < 0 || reg > I2S_REG_SIZE) {
|
||||
log_warn(&log, "Non-existent register");
|
||||
return;
|
||||
}
|
||||
set32(io_base + reg, mask, value);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
pcm_read(vir_bytes reg)
|
||||
{
|
||||
if(reg < 0 || reg > I2S_REG_SIZE) {
|
||||
log_warn(&log, "Non-existent register");
|
||||
return 0;
|
||||
}
|
||||
return read32(io_base + reg);
|
||||
}
|
||||
|
||||
void
|
||||
pcm_write(vir_bytes reg, uint32_t value)
|
||||
{
|
||||
if(reg < 0 || reg > I2S_REG_SIZE) {
|
||||
log_warn(&log, "Non-existent register");
|
||||
return;
|
||||
}
|
||||
write32(io_base + reg, value);
|
||||
}
|
||||
144
minix/drivers/audio/pcm/pcm.h
Normal file
144
minix/drivers/audio/pcm/pcm.h
Normal file
@@ -0,0 +1,144 @@
|
||||
#ifndef _PCM_H_
|
||||
#define _PCM_H_
|
||||
|
||||
#include <minix/sound.h>
|
||||
#include <minix/audio_fw.h>
|
||||
|
||||
#define AUDIO 0
|
||||
|
||||
#define PCM_IRQ 49
|
||||
|
||||
#define DEFAULT_SPEED 44100 /* Sample rate */
|
||||
#define DEFAULT_BITS 16 /* Nr. of bits */
|
||||
#define DEFAULT_SIGN 0 /* 0 = unsigned, 1 = signed */
|
||||
#define DEFAULT_STEREO 0 /* 0 = mono, 1 = stereo */
|
||||
|
||||
#define PCM_CS_A 0x00
|
||||
#define PCM_FIFO_A 0x04
|
||||
#define PCM_MODE_A 0x08
|
||||
#define PCM_RXC_A 0x0C
|
||||
#define PCM_TXC_A 0x10
|
||||
#define PCM_DREQ_A 0x14
|
||||
#define PCM_INTEN_A 0x18
|
||||
#define PCM_INTSTC_A 0x1C
|
||||
#define PCM_GRAY 0x20
|
||||
|
||||
#define I2S_BASE 0x3f203000
|
||||
#define I2S_REG_SIZE 0x200
|
||||
#define CLK_BASE 0x3f101000
|
||||
#define CLK_REG_SIZE 0x50
|
||||
#define DMA_BASE 0x3f007000
|
||||
#define DMA_REG_SIZE 0x100
|
||||
|
||||
#define DMA_CHAN 5
|
||||
|
||||
#define DMA_CS 0x0
|
||||
#define DMA_CONBLK 0x4
|
||||
#define DMA_TI 0x8
|
||||
#define DMA_SOURCE_AD 0xc
|
||||
#define DMA_DEST_AD 0x10
|
||||
#define DMA_TXFR_LEN 0x14
|
||||
#define DMA_STRIDE 0x18
|
||||
#define DMA_NEXTCONBK 0x1c
|
||||
|
||||
#define DMA_CS_END 0x2
|
||||
#define DMA_TI_SRC_DREQ 0x400
|
||||
#define DMA_TI_INTEN 0x1
|
||||
|
||||
#define DREQ_RX 2
|
||||
#define DREQ_TX 3
|
||||
#define PERMAP_SET(v) ((v) << 16)
|
||||
|
||||
#define PCM_CS_A_EN 0x1
|
||||
#define PCM_CS_A_RXON 0x2
|
||||
#define PCM_CS_A_TXON 0x4
|
||||
#define PCM_CS_A_TXCLR 0x8
|
||||
#define PCM_CS_A_RXCLR 0x10
|
||||
#define PCM_CS_A_TXCHR 0x60
|
||||
#define PCM_CS_A_RXCHR 0x180
|
||||
#define PCM_CS_A_DMAEN 0x200
|
||||
#define PCM_CS_A_TXSYNC 0x2000
|
||||
#define PCM_CS_A_RXSYNC 0x4000
|
||||
#define PCM_CS_A_TXERR 0x8000
|
||||
#define PCM_CS_A_RXERR 0x10000
|
||||
#define PCM_CS_A_TXW 0x20000
|
||||
#define PCM_CS_A_RXR 0x40000
|
||||
#define PCM_CS_A_TXD 0x80000
|
||||
#define PCM_CS_A_RXD 0x100000
|
||||
#define PCM_CS_A_TXE 0x200000
|
||||
#define PCM_CS_A_RXF 0x400000
|
||||
#define PCM_CS_A_RXSEX 0x800000
|
||||
#define PCM_CS_A_SYNC 0x1000000
|
||||
#define PCM_CS_A_STBY 0x2000000
|
||||
|
||||
#define PCM_TXC_A_CH2WID8 0x0
|
||||
#define PCM_TXC_A_CH2WID16 0x8
|
||||
#define PCM_TXC_A_CH2WID24 0x8000
|
||||
#define PCM_TXC_A_CH2WID32 0x8008
|
||||
#define PCM_TXC_A_CH2EN 0x4000
|
||||
#define PCM_TXC_A_CH1WID8 0x0
|
||||
#define PCM_TXC_A_CH1WID16 0x80000
|
||||
#define PCM_TXC_A_CH1WID24 0x80000000
|
||||
#define PCM_TXC_A_CH1WID32 0x80080000
|
||||
#define PCM_TXC_A_CH1EN 0x40000000
|
||||
|
||||
#define PCM_RXC_A_CH2WID8 0x0
|
||||
#define PCM_RXC_A_CH2WID16 0x8
|
||||
#define PCM_RXC_A_CH2WID24 0x8000
|
||||
#define PCM_RXC_A_CH2WID32 0x8008
|
||||
#define PCM_RXC_A_CH2EN 0x4000
|
||||
#define PCM_RXC_A_CH1WID8 0x0
|
||||
#define PCM_RXC_A_CH1WID16 0x80000
|
||||
#define PCM_RXC_A_CH1WID24 0x80000000
|
||||
#define PCM_RXC_A_CH1WID32 0x80080000
|
||||
#define PCM_RXC_A_CH1EN 0x40000000
|
||||
|
||||
#define PCM_MODE_A_FSI 0x100000
|
||||
#define PCM_MODE_A_FSM 0x200000
|
||||
#define PCM_MODE_A_CLKI 0x400000
|
||||
#define PCM_MODE_A_CLKM 0x800000
|
||||
#define PCM_MODE_A_FTXP 0x1000000
|
||||
#define PCM_MODE_A_FRXP 0x2000000
|
||||
#define PCM_MODE_A_PDME 0x4000000
|
||||
#define PCM_MODE_A_PDMN 0x8000000
|
||||
#define PCM_MODE_A_CLK_DIS 0x10000000
|
||||
|
||||
#define PCM_INTEN_A_TXW 0x1
|
||||
#define PCM_INTEN_A_RXR 0x2
|
||||
#define PCM_INTEN_A_TXERR 0x4
|
||||
#define PCM_INTEN_A_RXERR 0x8
|
||||
|
||||
#define PCM_INTSTC_A_TXW 0x1
|
||||
#define PCM_INTSTC_A_RXR 0x2
|
||||
#define PCM_INTSTC_A_TXERR 0x4
|
||||
#define PCM_INTSTC_A_RXERR 0x8
|
||||
|
||||
#define CLK_PCMCTL 0x00
|
||||
#define CLK_PCMDIV 0x04
|
||||
|
||||
/* Clock register settings */
|
||||
#define PCM_CLK_PASSWD (0x5a000000)
|
||||
#define PCM_CLK_PASSWD_MASK (0xff000000)
|
||||
#define PCM_CLK_FLIP 0x100
|
||||
#define PCM_CLK_BUSY 0x80
|
||||
#define PCM_CLK_KILL 0x20
|
||||
#define PCM_CLK_ENAB 0x10
|
||||
|
||||
#define DSP_MAX_SPEED 44100 /* Max sample speed in KHz */
|
||||
#define DSP_MIN_SPEED 4000 /* Min sample speed in KHz */
|
||||
|
||||
#define PCM_TX_PANIC(v) ((v) << 24)
|
||||
#define PCM_RX_PANIC(v) ((v) << 16)
|
||||
#define PCM_TX(v) ((v) << 8)
|
||||
#define PCM_RX(v) (v)
|
||||
|
||||
/* Number of bytes you can DMA before hitting a 64K boundary: */
|
||||
#define dma_bytes_left(phys) \
|
||||
((unsigned) (sizeof(int) == 2 ? 0 : 0x10000) - (unsigned) ((phys) & 0xFFFF))
|
||||
|
||||
uint32_t pcm_read(vir_bytes port);
|
||||
void pcm_write(vir_bytes port, uint32_t value);
|
||||
void pcm_set(vir_bytes port, uint32_t mask, uint32_t value);
|
||||
|
||||
|
||||
#endif // _PCM_H_
|
||||
@@ -7,6 +7,7 @@ SUBDIR+= ti1225
|
||||
|
||||
. if ${MACHINE_ARCH} == "earm"
|
||||
SUBDIR+= i2c
|
||||
SUBDIR+= spi
|
||||
. endif # ${MACHINE_ARCH} == "earm"
|
||||
.endif # ${MKIMAGEONLY} == "no"
|
||||
|
||||
|
||||
@@ -1,13 +1,26 @@
|
||||
# Makefile for I2C support
|
||||
PROG= i2c
|
||||
|
||||
.include "arch/${MACHINE_ARCH}/Makefile.inc"
|
||||
PROG= i2c
|
||||
SRCS+= i2c.c
|
||||
|
||||
SRCS+= i2c.c
|
||||
FILES=${PROG}.conf
|
||||
FILESNAME=${PROG}
|
||||
FILESDIR= /etc/system.conf.d
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
.if ${MACHINE_ARCH} == "earm"
|
||||
.for pl in rpi omap
|
||||
.PATH: ${.CURDIR}/arch/earm/${pl}
|
||||
SRCS+= ${pl}_i2c.c
|
||||
.endfor
|
||||
.else
|
||||
.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}
|
||||
SRCS+= pci_i2c.c
|
||||
.endif
|
||||
|
||||
CPPFLAGS+= -I${.CURDIR} -I${.CURDIR}/arch/earm/rpi -I${.CURDIR}/arch/earm/omap
|
||||
DPADD+= ${LIBCHARDRIVER} ${LIBSYS} ${LIBTIMERS} ${LIBCLKCONF}
|
||||
LDADD+= -lchardriver -lsys -ltimers -lclkconf
|
||||
|
||||
CPPFLAGS+= -I${.CURDIR} -I${.CURDIR}/arch/${MACHINE_ARCH}
|
||||
|
||||
.include <minix.service.mk>
|
||||
.include <minix.service.mk>
|
||||
@@ -14,11 +14,17 @@ Organization and Layout
|
||||
-----------------------
|
||||
|
||||
i2c.c generic i2c bus driver
|
||||
i2c.conf configuration for the i2c driver
|
||||
arch/ arch specific code
|
||||
earm/ earm specific code
|
||||
omap_i2c.c AM335X/DM37XX i2c bus driver
|
||||
omap_i2c.h AM335X/DM37XX function prototypes
|
||||
omap_i2c_registers.h AM335X/DM37XX register offsets, etc.
|
||||
omap/
|
||||
omap_i2c.c AM335X/DM37XX i2c bus driver
|
||||
omap_i2c.h AM335X/DM37XX function prototypes
|
||||
omap_i2c_registers.h AM335X/DM37XX register offsets, etc.
|
||||
rpi/
|
||||
rpi_i2c.c BCM283X i2c bus driver
|
||||
rpi_i2c.h BCM283X function prototypes
|
||||
rpi_i2c_registers.h BCM283X register offsets, etc.
|
||||
|
||||
Testing the Code
|
||||
----------------
|
||||
@@ -62,3 +68,17 @@ Minix i2c device drivers. It shows how to use the i2cdriver library and
|
||||
how to use the bus for reads and writes. commands/eepromread is another
|
||||
place to look if you're interested in accessing devices through the /dev
|
||||
interface.
|
||||
|
||||
Developing I2C Drivers For The New Arm Platform
|
||||
-------------------------------------------
|
||||
|
||||
1) Create the directory "your_platform" in the arch/earm
|
||||
2) Your driver has to implement "int your_platform_interface_setup
|
||||
(int (**process)(minix_i2c_ioctl_exec_t *ioctl_exec), int i2c_bus_id);",
|
||||
which is called by the general i2c driver for control platform dependent
|
||||
functions. See previous realizations for more examples.
|
||||
3) Your files have to named your_platform_i2c.c your_platform_i2c.h
|
||||
your_platform_i2c_registers.h
|
||||
4) Add your platform name in the Makefile directories list.
|
||||
5) Include "your_platform_i2c.h" in the i2c.c.
|
||||
6) Add else/if section in the i2c.c in the sef_cb_init function.
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# Makefile for arch-dependent i2c code
|
||||
.include <bsd.own.mk>
|
||||
|
||||
HERE=${.CURDIR}/arch/${MACHINE_ARCH}
|
||||
.PATH: ${HERE}
|
||||
|
||||
SRCS += omap_i2c.c omap_i2c.h omap_i2c_registers.h
|
||||
|
||||
FILES=${PROG}.conf
|
||||
FILESNAME=${PROG}
|
||||
FILESDIR= /etc/system.conf.d
|
||||
@@ -1,20 +0,0 @@
|
||||
service i2c
|
||||
{
|
||||
system
|
||||
PRIVCTL # 4
|
||||
IRQCTL # 19
|
||||
PADCONF # 57
|
||||
;
|
||||
irq
|
||||
# DM37XX (BeagleBoard-xM)
|
||||
56 # I2C module 1
|
||||
57 # I2C module 2
|
||||
61 # I2C module 3
|
||||
# AM335X (BeagleBone)
|
||||
70 # I2C module 1
|
||||
71 # I2C module 2
|
||||
30 # I2C module 3
|
||||
;
|
||||
ipc SYSTEM RS DS;
|
||||
};
|
||||
|
||||
630
minix/drivers/bus/i2c/arch/earm/rpi/rpi_i2c.c
Normal file
630
minix/drivers/bus/i2c/arch/earm/rpi/rpi_i2c.c
Normal file
@@ -0,0 +1,630 @@
|
||||
/*
|
||||
* This file implements support for i2c on the BeagleBone and BeagleBoard-xM
|
||||
*/
|
||||
|
||||
/* kernel headers */
|
||||
#include <minix/chardriver.h>
|
||||
#include <minix/drivers.h>
|
||||
#include <minix/ds.h>
|
||||
#include <minix/log.h>
|
||||
#include <minix/mmio.h>
|
||||
#include <minix/padconf.h>
|
||||
#include <minix/sysutil.h>
|
||||
#include <minix/syslib.h>
|
||||
#include <minix/type.h>
|
||||
#include <minix/board.h>
|
||||
#include <minix/spin.h>
|
||||
|
||||
/* device headers */
|
||||
#include <minix/i2c.h>
|
||||
|
||||
/* system headers */
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/* usr headers */
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* local headers */
|
||||
#include "rpi_i2c.h"
|
||||
|
||||
/*
|
||||
* defines the set of register
|
||||
*
|
||||
* Warning: always use the 16-bit variants of read/write/set from mmio.h
|
||||
* to access these registers. The DM37XX TRM Section 17.6 warns that 32-bit
|
||||
* accesses can corrupt the register contents.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
vir_bytes CTRL;
|
||||
vir_bytes ST;
|
||||
vir_bytes DLEN;
|
||||
vir_bytes SL_ADDR;
|
||||
vir_bytes FIFO;
|
||||
vir_bytes DIV;
|
||||
vir_bytes DEL;
|
||||
vir_bytes CLKT;
|
||||
} rpi_i2c_regs_t;
|
||||
|
||||
/* generic definition an i2c bus */
|
||||
|
||||
typedef struct rpi_i2c_bus
|
||||
{
|
||||
phys_bytes mr_base;
|
||||
phys_bytes mr_size;
|
||||
vir_bytes mapped_addr;
|
||||
rpi_i2c_regs_t *regs;
|
||||
uint32_t functional_clock;
|
||||
uint32_t module_clock;
|
||||
uint32_t bus_speed;
|
||||
int irq;
|
||||
int irq_hook_id;
|
||||
int irq_hook_kernel_id;
|
||||
} rpi_i2c_bus_t;
|
||||
|
||||
/* Define the registers for each chip */
|
||||
|
||||
static rpi_i2c_regs_t bcm283x_i2c_regs = {
|
||||
.CTRL = BCM283X_CTRL,
|
||||
.ST = BCM283X_STATUS,
|
||||
.DLEN = BCM283X_DLEN,
|
||||
.SL_ADDR = BCM283X_SL_ADDR,
|
||||
.FIFO = BCM283X_FIFO,
|
||||
.DIV = BCM283X_DIV,
|
||||
.DEL = BCM283X_DEL,
|
||||
.CLKT = BCM283X_CLKT,
|
||||
};
|
||||
|
||||
/* Define the buses available on each chip */
|
||||
|
||||
static rpi_i2c_bus_t bcm283x_i2c_buses[] = {
|
||||
{BCM283X_I2C0_BASE, BCM283X_I2C0_SIZE, 0, &bcm283x_i2c_regs,
|
||||
BCM283X_FUNCTIONAL_CLOCK, BCM283X_MODULE_CLOCK,
|
||||
BUS_SPEED_100KHz, BCM283X_I2C0_IRQ, 1, 1},
|
||||
{BCM283X_I2C1_BASE, BCM283X_I2C1_SIZE, 0, &bcm283x_i2c_regs,
|
||||
BCM283X_FUNCTIONAL_CLOCK, BCM283X_MODULE_CLOCK,
|
||||
BUS_SPEED_100KHz, BCM283X_I2C0_IRQ, 2, 3}
|
||||
};
|
||||
|
||||
#define BCM283X_rpi_NBUSES (sizeof(bcm283x_i2c_buses) / sizeof(rpi_i2c_bus_t))
|
||||
|
||||
/* Globals */
|
||||
|
||||
static rpi_i2c_bus_t *rpi_i2c_buses; /* all available buses for this SoC */
|
||||
static rpi_i2c_bus_t *rpi_i2c_bus; /* the bus selected at start-up */
|
||||
static int rpi_i2c_nbuses; /* number of buses supported by SoC */
|
||||
|
||||
/* logging - use with log_warn(), log_info(), log_debug(), log_trace() */
|
||||
static struct log log = {
|
||||
.name = "i2c",
|
||||
.log_level = LEVEL_TRACE,
|
||||
.log_func = default_log
|
||||
};
|
||||
|
||||
/* Local Function Prototypes */
|
||||
|
||||
/* Implementation of Generic I2C Interface using Bus Specific Code */
|
||||
static int rpi_i2c_process(minix_i2c_ioctl_exec_t * m);
|
||||
|
||||
/* Bus Specific Code */
|
||||
static void rpi_i2c_flush(void);
|
||||
static uint32_t rpi_i2c_poll(uint32_t mask);
|
||||
static int rpi_i2c_bus_is_free(void);
|
||||
static int rpi_i2c_soft_reset(void);
|
||||
static void rpi_i2c_bus_init(void);
|
||||
static void rpi_i2c_padconf(int i2c_bus_id);
|
||||
static void rpi_i2c_intr_enable(void);
|
||||
static uint32_t rpi_i2c_read_status(void);
|
||||
static void rpi_i2c_write_status(uint32_t mask);
|
||||
static int rpi_i2c_read(i2c_addr_t addr, uint8_t * buf, size_t buflen,
|
||||
int dostop);
|
||||
static int rpi_i2c_write(i2c_addr_t addr, const uint8_t * buf, size_t buflen,
|
||||
int dostop);
|
||||
|
||||
/*
|
||||
* Performs the action in minix_i2c_ioctl_exec_t.
|
||||
*/
|
||||
static int
|
||||
rpi_i2c_process(minix_i2c_ioctl_exec_t * ioctl_exec)
|
||||
{
|
||||
int r;
|
||||
|
||||
/*
|
||||
* Zero data bytes transfers are not allowed. The controller treats
|
||||
* I2C_CNT register value of 0x0 as 65536. This is true for both the
|
||||
* am335x and dm37xx. Full details in the TRM on the I2C_CNT page.
|
||||
*/
|
||||
if (ioctl_exec->iie_buflen == 0) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
rpi_i2c_flush(); /* clear any garbage in the fifo */
|
||||
log_debug(&log, "buflen %d, cmdlen %d, addr 0x%x\n", ioctl_exec->iie_buflen, ioctl_exec->iie_cmdlen, ioctl_exec->iie_addr);
|
||||
|
||||
/* Check bus busy flag before using the bus */
|
||||
r = rpi_i2c_bus_is_free();
|
||||
if (r == 0) {
|
||||
log_warn(&log, "Bus is busy\n");
|
||||
return EBUSY;
|
||||
}
|
||||
if (ioctl_exec->iie_cmdlen > 0) {
|
||||
r = rpi_i2c_write(ioctl_exec->iie_addr, ioctl_exec->iie_cmd,
|
||||
ioctl_exec->iie_cmdlen,
|
||||
!(I2C_OP_READ_P(ioctl_exec->iie_op)));
|
||||
if (r != OK) {
|
||||
rpi_i2c_soft_reset();
|
||||
rpi_i2c_bus_init();
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (I2C_OP_READ_P(ioctl_exec->iie_op)) {
|
||||
r = rpi_i2c_read(ioctl_exec->iie_addr, ioctl_exec->iie_buf,
|
||||
ioctl_exec->iie_buflen, I2C_OP_STOP_P(ioctl_exec->iie_op));
|
||||
} else {
|
||||
r = rpi_i2c_write(ioctl_exec->iie_addr, ioctl_exec->iie_buf,
|
||||
ioctl_exec->iie_buflen, I2C_OP_STOP_P(ioctl_exec->iie_op));
|
||||
}
|
||||
|
||||
if (r != OK) {
|
||||
rpi_i2c_soft_reset();
|
||||
rpi_i2c_bus_init();
|
||||
return r;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Drain the incoming FIFO.
|
||||
*
|
||||
* Usually called to clear any garbage that may be in the buffer before
|
||||
* doing a read.
|
||||
*/
|
||||
static void
|
||||
rpi_i2c_flush(void)
|
||||
{
|
||||
int tries;
|
||||
int status;
|
||||
|
||||
for (tries = 0; tries < 1000; tries++) {
|
||||
status = rpi_i2c_poll(BCM283X_STATUS_RXD);
|
||||
if ((status & BCM283X_STATUS_RXD) != 0) { /* bytes available for reading */
|
||||
/* consume the byte and throw it away */
|
||||
read32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->FIFO);
|
||||
|
||||
set32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->CTRL,
|
||||
BCM283X_CTRL_CFIFO, BCM283X_CTRL_CFIFO);
|
||||
set32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->ST,
|
||||
BCM283X_STATUS_DONE, BCM283X_STATUS_DONE);
|
||||
|
||||
} else {
|
||||
break; /* buffer drained */
|
||||
}
|
||||
}
|
||||
log_debug(&log, "bytes available 0x%x\n", status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Poll the status register checking the bits set in 'mask'.
|
||||
* Returns the status if any bits set or 0x0000 when the timeout is reached.
|
||||
*/
|
||||
static uint32_t
|
||||
rpi_i2c_poll(uint32_t mask)
|
||||
{
|
||||
spin_t spin;
|
||||
uint32_t status;
|
||||
|
||||
/* poll for up to 1 s */
|
||||
spin_init(&spin, 1000000);
|
||||
do {
|
||||
status = rpi_i2c_read_status();
|
||||
if ((status & mask) != 0) { /* any bits in mask set */
|
||||
return status;
|
||||
}
|
||||
} while (spin_check(&spin));
|
||||
|
||||
return status; /* timeout reached, abort */
|
||||
}
|
||||
|
||||
/*
|
||||
* Poll Bus Busy Flag until the bus becomes free (return 1) or the timeout
|
||||
* expires (return 0).
|
||||
*/
|
||||
static int
|
||||
rpi_i2c_bus_is_free(void)
|
||||
{
|
||||
spin_t spin;
|
||||
uint16_t status;
|
||||
|
||||
/* wait for up to 1 second for the bus to become free */
|
||||
spin_init(&spin, 1000000);
|
||||
do {
|
||||
|
||||
status = rpi_i2c_read_status();
|
||||
if ((status & BCM283X_STATUS_TA) == 0) {
|
||||
return 1; /* bus is free */
|
||||
}
|
||||
} while (spin_check(&spin));
|
||||
|
||||
return 0; /* timeout expired */
|
||||
}
|
||||
|
||||
static void
|
||||
rpi_i2c_padconf(int i2c_bus_id)
|
||||
{
|
||||
int r;
|
||||
u32_t pinopts;
|
||||
|
||||
switch (i2c_bus_id) {
|
||||
case 0:
|
||||
pinopts |= CONTROL_BCM_CONF_I2C0_SDA | CONTROL_BCM_CONF_I2C0_SCL;
|
||||
|
||||
r = sys_padconf(GPFSEL09, 0xffffffff,
|
||||
pinopts);
|
||||
if (r != OK) {
|
||||
log_warn(&log, "padconf failed (r=%d)\n", r);
|
||||
}
|
||||
|
||||
log_debug(&log, "pinopts=0x%x\n", pinopts);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
pinopts |= CONTROL_BCM_CONF_I2C1_SDA | CONTROL_BCM_CONF_I2C1_SCL;
|
||||
|
||||
r = sys_padconf(GPFSEL09, 0xffffffff,
|
||||
pinopts);
|
||||
if (r != OK) {
|
||||
log_warn(&log, "padconf failed (r=%d)\n", r);
|
||||
}
|
||||
|
||||
log_debug(&log, "pinopts=0x%x\n", pinopts);
|
||||
break;
|
||||
|
||||
default:
|
||||
log_warn(&log, "Invalid i2c_bus_id\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
rpi_i2c_soft_reset(void)
|
||||
{
|
||||
/* Disable to do soft reset */
|
||||
write32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->CTRL, 0);
|
||||
micro_delay(50000);
|
||||
|
||||
/* Have to temporarily enable I2C to read RDONE */
|
||||
set32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->CTRL, BCM283X_CTRL_I2C_EN | BCM283X_CTRL_CFIFO,
|
||||
BCM283X_CTRL_I2C_EN | BCM283X_CTRL_CFIFO);
|
||||
micro_delay(50000);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static void
|
||||
rpi_i2c_intr_enable(void)
|
||||
{
|
||||
int r;
|
||||
uint16_t intmask;
|
||||
static int policy_set = 0;
|
||||
static int enabled = 0;
|
||||
|
||||
if (!policy_set) {
|
||||
r = sys_irqsetpolicy(rpi_i2c_bus->irq, 0,
|
||||
&rpi_i2c_bus->irq_hook_kernel_id);
|
||||
if (r == OK) {
|
||||
policy_set = 1;
|
||||
} else {
|
||||
log_warn(&log, "Couldn't set irq policy\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (policy_set && !enabled) {
|
||||
r = sys_irqenable(&rpi_i2c_bus->irq_hook_kernel_id);
|
||||
if (r == OK) {
|
||||
enabled = 1;
|
||||
} else {
|
||||
log_warn(&log, "Couldn't enable irq %d (hooked)\n",
|
||||
rpi_i2c_bus->irq);
|
||||
}
|
||||
}
|
||||
|
||||
/* According to NetBSD driver and u-boot, these are needed even
|
||||
* if just using polling (i.e. non-interrupt driver programming).
|
||||
*/
|
||||
intmask = 0;
|
||||
intmask |= BCM283X_CTRL_INTR;
|
||||
intmask |= BCM283X_CTRL_INTT;
|
||||
intmask |= BCM283X_CTRL_INTD;
|
||||
|
||||
write32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->CTRL, intmask);
|
||||
}
|
||||
|
||||
static void
|
||||
rpi_i2c_bus_init(void)
|
||||
{
|
||||
/* Ensure i2c module is disabled before setting prescalar & bus speed */
|
||||
write32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->CTRL, 0);
|
||||
micro_delay(50000);
|
||||
|
||||
/* Set prescalar to obtain 12 MHz i2c module clock */
|
||||
uint32_t divider = (sys_hz() * 10000 + rpi_i2c_bus->bus_speed - 1) / rpi_i2c_bus->bus_speed;
|
||||
log_debug(&log, "divider %lu sys_hz %lu\n", (uint32_t)divider, sys_hz());
|
||||
if (divider > BCM283X_I2C_CDIV_MAX ||
|
||||
divider < BCM283X_I2C_CDIV_MIN) {
|
||||
log_warn(&log, "Incorrect divider\n");
|
||||
}
|
||||
|
||||
if (divider & 0x01)
|
||||
divider++;
|
||||
|
||||
write32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->DIV, 1500);
|
||||
|
||||
/* Set own I2C address */
|
||||
write32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->SL_ADDR, I2C_OWN_ADDRESS);
|
||||
|
||||
/* Bring the i2c module out of reset */
|
||||
set32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->CTRL, BCM283X_CTRL_I2C_EN, BCM283X_CTRL_I2C_EN);
|
||||
micro_delay(50000);
|
||||
|
||||
/*
|
||||
* Enable interrupts
|
||||
*/
|
||||
rpi_i2c_intr_enable();
|
||||
|
||||
log_debug(&log, "interrupts enabled\n");
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
rpi_i2c_read_status(void)
|
||||
{
|
||||
uint16_t status = read32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->ST);
|
||||
return status;
|
||||
}
|
||||
|
||||
static void
|
||||
rpi_i2c_write_status(uint32_t mask)
|
||||
{
|
||||
write32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->ST, mask);
|
||||
}
|
||||
|
||||
static int
|
||||
rpi_i2c_read(i2c_addr_t addr, uint8_t * buf, size_t buflen, int dostop)
|
||||
{
|
||||
int r, i;
|
||||
uint32_t ctrl;
|
||||
uint32_t pollmask;
|
||||
uint32_t errmask;
|
||||
|
||||
/* Set address of slave device */
|
||||
addr &= MAX_I2C_SA_MASK; /* sanitize address (10-bit max) */
|
||||
if (addr > 0xff) {
|
||||
write32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->DLEN, 1);
|
||||
|
||||
write32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->SL_ADDR, (addr >> XSA) | SL_ADDR_MASK);
|
||||
|
||||
write32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->FIFO, addr & 0xff);
|
||||
|
||||
ctrl = read32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->CTRL);
|
||||
ctrl |= BCM283X_CTRL_ST;
|
||||
ctrl &= (~BCM283X_CTRL_READ);
|
||||
write32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->CTRL, ctrl);
|
||||
|
||||
pollmask |= BCM283X_STATUS_TA;
|
||||
pollmask |= BCM283X_STATUS_DONE;
|
||||
errmask |= BCM283X_STATUS_CLKT;
|
||||
errmask |= BCM283X_STATUS_ERR;
|
||||
|
||||
r = rpi_i2c_poll(pollmask | errmask);
|
||||
if ((r & errmask) != 0) {
|
||||
/* only debug log level because i2cscan trigers this */
|
||||
log_debug(&log, "Write addrress Error! On %d byte, Status=%x\n", i, r);
|
||||
return EIO;
|
||||
} else if ((r & pollmask) == 0) {
|
||||
log_warn(&log, "No TA Interrupt. Status=%x\n", r);
|
||||
log_warn(&log,
|
||||
"Likely cause: bad pinmux or no devices on bus\n");
|
||||
return EBUSY;
|
||||
}
|
||||
} else {
|
||||
write32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->SL_ADDR, addr);
|
||||
}
|
||||
|
||||
ctrl = read32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->CTRL);
|
||||
ctrl |= BCM283X_CTRL_ST;
|
||||
ctrl |= BCM283X_CTRL_READ;
|
||||
write32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->CTRL, ctrl);
|
||||
|
||||
errmask |= BCM283X_STATUS_CLKT;
|
||||
errmask |= BCM283X_STATUS_ERR;
|
||||
pollmask = BCM283X_STATUS_RXD;
|
||||
pollmask |= BCM283X_STATUS_RXR;
|
||||
pollmask |= BCM283X_STATUS_RXF;
|
||||
pollmask |= BCM283X_STATUS_DONE;
|
||||
|
||||
write32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->DLEN, buflen);
|
||||
|
||||
for (i = 0; i < buflen; i++) {
|
||||
/* Data to read? */
|
||||
r = rpi_i2c_poll(pollmask | errmask);
|
||||
if ((r & errmask) != 0) {
|
||||
/* only debug log level because i2cscan trigers this */
|
||||
log_debug(&log, "Read Error! On %d byte, Status=%x\n", i, r);
|
||||
return EIO;
|
||||
} else if ((r & pollmask) == 0) {
|
||||
log_warn(&log, "No RXD Interrupt. Status=%x\n", r);
|
||||
log_warn(&log,
|
||||
"Likely cause: bad pinmux or no devices on bus\n");
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
/* read a byte */
|
||||
buf[i] = read32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->FIFO) & 0xff;
|
||||
}
|
||||
|
||||
if (rpi_i2c_read_status() & BCM283X_STATUS_ERR) {
|
||||
log_warn(&log, "can't wait ack\n");
|
||||
return EIO;
|
||||
}
|
||||
|
||||
pollmask = BCM283X_STATUS_DONE; /* poll access ready bit */
|
||||
r = rpi_i2c_poll(pollmask);
|
||||
if ((r & pollmask) == 0) {
|
||||
log_warn(&log, "Read operation never finished.\n");
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
ctrl = read32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->CTRL);
|
||||
ctrl |= BCM283X_CTRL_CFIFO;
|
||||
write32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->CTRL, ctrl);
|
||||
|
||||
/* clear the read ready flag */
|
||||
rpi_i2c_write_status(BCM283X_STATUS_DONE | errmask);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int
|
||||
rpi_i2c_write(i2c_addr_t addr, const uint8_t * buf, size_t buflen, int dostop)
|
||||
{
|
||||
int r, i;
|
||||
uint32_t pollmask;
|
||||
uint32_t errmask;
|
||||
uint32_t ctrl;
|
||||
/* Set address of slave device */
|
||||
addr &= MAX_I2C_SA_MASK; /* sanitize address (10-bit max) */
|
||||
|
||||
if (addr > 0xff) {
|
||||
write32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->DLEN, buflen + 1);
|
||||
|
||||
write32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->SL_ADDR, (addr >> XSA) | SL_ADDR_MASK);
|
||||
|
||||
write32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->FIFO, addr & 0xff);
|
||||
} else {
|
||||
write32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->DLEN, buflen);
|
||||
|
||||
write32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->SL_ADDR, addr);
|
||||
}
|
||||
|
||||
pollmask |= BCM283X_STATUS_TXD;
|
||||
pollmask |= BCM283X_STATUS_DONE;
|
||||
errmask |= BCM283X_STATUS_CLKT;
|
||||
errmask |= BCM283X_STATUS_ERR;
|
||||
|
||||
ctrl = read32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->CTRL);
|
||||
ctrl |= BCM283X_CTRL_ST;
|
||||
ctrl &= (~BCM283X_CTRL_READ);
|
||||
write32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->CTRL, ctrl);
|
||||
|
||||
log_debug(&log, "buflen %d data 0x%x\n", buflen, buf[0]);
|
||||
|
||||
for (i = 0; i < buflen; i++) {
|
||||
log_debug(&log, "write\n");
|
||||
/* Ready to write? */
|
||||
r = rpi_i2c_poll(pollmask | errmask);
|
||||
if ((r & errmask) != 0) {
|
||||
log_warn(&log, "Write Error! On %d byte, Status=%x\n", i, r);
|
||||
return EIO;
|
||||
} else if ((r & pollmask) == 0) {
|
||||
log_warn(&log, "Not ready for write? Status=%x\n", r);
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
write32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->FIFO, buf[i]);
|
||||
}
|
||||
|
||||
if (rpi_i2c_read_status() & BCM283X_STATUS_ERR) {
|
||||
log_warn(&log, "can't wait ack\n");
|
||||
return EIO;
|
||||
}
|
||||
|
||||
r = rpi_i2c_poll(pollmask);
|
||||
if ((r & pollmask) == 0) {
|
||||
log_warn(&log, "Write operation never finished.\n");
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
ctrl = read32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->CTRL);
|
||||
ctrl |= BCM283X_CTRL_CFIFO;
|
||||
write32(rpi_i2c_bus->mapped_addr + rpi_i2c_bus->regs->CTRL, ctrl);
|
||||
/* clear the write ready flag */
|
||||
rpi_i2c_write_status(BCM283X_STATUS_DONE | errmask);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int
|
||||
rpi_interface_setup(int (**process) (minix_i2c_ioctl_exec_t * ioctl_exec),
|
||||
int i2c_bus_id)
|
||||
{
|
||||
int r;
|
||||
int i2c_rev, major, minor;
|
||||
struct minix_mem_range mr;
|
||||
struct machine machine;
|
||||
sys_getmachine(&machine);
|
||||
|
||||
log_info(&log, "setup start\n");
|
||||
/* Fill in the function pointer */
|
||||
|
||||
*process = rpi_i2c_process;
|
||||
|
||||
/* Select the correct i2c definition for this SoC */
|
||||
|
||||
if (BOARD_IS_RPI_2_B(machine.board_id) || BOARD_IS_RPI_3_B(machine.board_id)){
|
||||
rpi_i2c_buses = bcm283x_i2c_buses;
|
||||
rpi_i2c_nbuses = BCM283X_rpi_NBUSES;
|
||||
} else {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
log_debug(&log, "cont\n");
|
||||
|
||||
if (i2c_bus_id < 0 || i2c_bus_id >= rpi_i2c_nbuses) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* select the bus to operate on */
|
||||
rpi_i2c_bus = &rpi_i2c_buses[i2c_bus_id];
|
||||
|
||||
/* Configure Pins */
|
||||
rpi_i2c_padconf(i2c_bus_id);
|
||||
|
||||
/*
|
||||
* Map I2C Registers
|
||||
*/
|
||||
|
||||
/* Configure memory access */
|
||||
mr.mr_base = rpi_i2c_bus->mr_base; /* start addr */
|
||||
mr.mr_limit = mr.mr_base + rpi_i2c_bus->mr_size; /* end addr */
|
||||
|
||||
/* ask for privileges to access the I2C memory range */
|
||||
if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != OK) {
|
||||
panic("Unable to obtain i2c memory range privileges");
|
||||
}
|
||||
|
||||
/* map the memory into this process */
|
||||
rpi_i2c_bus->mapped_addr = (vir_bytes) vm_map_phys(SELF,
|
||||
(void *) rpi_i2c_bus->mr_base, rpi_i2c_bus->mr_size);
|
||||
|
||||
if (rpi_i2c_bus->mapped_addr == (vir_bytes) MAP_FAILED) {
|
||||
panic("Unable to map i2c registers");
|
||||
}
|
||||
|
||||
/* Perform a soft reset of the I2C module to ensure a fresh start */
|
||||
r = rpi_i2c_soft_reset();
|
||||
if (r != OK) {
|
||||
log_warn(&log, "can't do soft reset\n");
|
||||
/* module didn't come back up :( */
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Bring up I2C module */
|
||||
rpi_i2c_bus_init();
|
||||
|
||||
return OK;
|
||||
}
|
||||
10
minix/drivers/bus/i2c/arch/earm/rpi/rpi_i2c.h
Normal file
10
minix/drivers/bus/i2c/arch/earm/rpi/rpi_i2c.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef _RPI_I2C_H
|
||||
#define _RPI_I2C_H
|
||||
|
||||
#include <minix/chardriver.h>
|
||||
#include <minix/i2c.h>
|
||||
#include "rpi_i2c_registers.h"
|
||||
|
||||
int rpi_interface_setup(int (**process)(minix_i2c_ioctl_exec_t *ioctl_exec), int i2c_bus_id);
|
||||
|
||||
#endif /* _RPI_I2C_H */
|
||||
86
minix/drivers/bus/i2c/arch/earm/rpi/rpi_i2c_registers.h
Normal file
86
minix/drivers/bus/i2c/arch/earm/rpi/rpi_i2c_registers.h
Normal file
@@ -0,0 +1,86 @@
|
||||
#ifndef _RPI_I2C_REGISTERS_H
|
||||
#define _RPI_I2C_REGISTERS_H
|
||||
|
||||
/* I2C Addresses for bcm2835 */
|
||||
|
||||
/* IRQ Numbers */
|
||||
#define BCM283X_I2C0_IRQ 47
|
||||
|
||||
/* Base Addresses */
|
||||
#define BCM283X_I2C0_BASE 0x3f205000
|
||||
#define BCM283X_I2C1_BASE 0x3f804000
|
||||
|
||||
/* Size of I2C Register Address Range */
|
||||
#define BCM283X_I2C0_SIZE 0x1000
|
||||
#define BCM283X_I2C1_SIZE 0x1000
|
||||
|
||||
/* Register Offsets */
|
||||
#define BCM283X_CTRL 0x00
|
||||
#define BCM283X_STATUS 0x04
|
||||
#define BCM283X_DLEN 0x08
|
||||
#define BCM283X_SL_ADDR 0x0C
|
||||
#define BCM283X_FIFO 0x10
|
||||
#define BCM283X_DIV 0x14
|
||||
#define BCM283X_DEL 0x18
|
||||
#define BCM283X_CLKT 0x1c
|
||||
|
||||
/* Constants */
|
||||
#define BCM283X_FUNCTIONAL_CLOCK 96000000 /* 96 MHz */
|
||||
#define BCM283X_MODULE_CLOCK 12000000 /* 12 MHz */
|
||||
|
||||
#define BCM283X_I2C_CDIV_MIN 0x0002
|
||||
#define BCM283X_I2C_CDIV_MAX 0xFFFE
|
||||
|
||||
/* Shared Values */
|
||||
|
||||
#define BUS_SPEED_100KHz 100000 /* 100 KHz */
|
||||
#define BUS_SPEED_400KHz 400000 /* 400 KHz */
|
||||
#define I2C_OWN_ADDRESS 0x01
|
||||
|
||||
/* Masks */
|
||||
|
||||
#define MAX_I2C_SA_MASK (0x3ff) /* Highest 10 bit address -- 9..0 */
|
||||
#define SL_ADDR_MASK (0x78) /* Mask for slave address (the last two bits
|
||||
are the most significant of the addr)*/
|
||||
|
||||
/* Bit Offsets within Registers (only those used are listed) */
|
||||
|
||||
#define I2C_EN 15
|
||||
#define MST 10
|
||||
#define TRX 9
|
||||
#define XSA 8
|
||||
#define STP 1
|
||||
#define STT 0
|
||||
|
||||
#define CLKACTIVITY_S 9
|
||||
#define CLKACTIVITY_I 8
|
||||
#define SMART_WAKE_UP 4
|
||||
#define NO_IDLE_MODE 3
|
||||
#define SRST 1
|
||||
#define AUTOIDLE 0
|
||||
|
||||
#define RDONE 0
|
||||
|
||||
#define RXFIFO_CLR 14
|
||||
#define TXFIFO_CLR 6
|
||||
|
||||
#define BCM283X_STATUS_TA 0x01
|
||||
#define BCM283X_STATUS_DONE 0x02
|
||||
#define BCM283X_STATUS_TXW 0x04
|
||||
#define BCM283X_STATUS_RXR 0x08
|
||||
#define BCM283X_STATUS_TXD 0x10
|
||||
#define BCM283X_STATUS_RXD 0x20
|
||||
#define BCM283X_STATUS_TXE 0x40
|
||||
#define BCM283X_STATUS_RXF 0x80
|
||||
#define BCM283X_STATUS_ERR 0x100
|
||||
#define BCM283X_STATUS_CLKT 0x200
|
||||
|
||||
#define BCM283X_CTRL_READ 0x01
|
||||
#define BCM283X_CTRL_ST 0x80
|
||||
#define BCM283X_CTRL_CFIFO 0x30
|
||||
#define BCM283X_CTRL_INTD 0x100
|
||||
#define BCM283X_CTRL_INTT 0x200
|
||||
#define BCM283X_CTRL_INTR 0x400
|
||||
#define BCM283X_CTRL_I2C_EN 0x8000
|
||||
|
||||
#endif /* _RPI_I2C_REGISTERS_H */
|
||||
@@ -1,7 +0,0 @@
|
||||
# Makefile for arch-dependent i2c code
|
||||
.include <bsd.own.mk>
|
||||
|
||||
HERE=${.CURDIR}/arch/${MACHINE_ARCH}
|
||||
.PATH: ${HERE}
|
||||
|
||||
SRCS += pci_i2c.c pci_i2c.h pci_i2c_register.h
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
/* SoC specific headers - 1 for each SoC */
|
||||
#include "omap_i2c.h"
|
||||
#include "rpi_i2c.h"
|
||||
|
||||
/* local definitions */
|
||||
|
||||
@@ -437,6 +438,12 @@ sef_cb_init(int type, sef_init_info_t * UNUSED(info))
|
||||
if (r != OK) {
|
||||
return r;
|
||||
}
|
||||
} else if (BOARD_IS_RPI_2_B(machine.board_id) || BOARD_IS_RPI_3_B(machine.board_id)){
|
||||
/* Set callback and initialize the bus */
|
||||
r = rpi_interface_setup(&process, i2c_bus_id);
|
||||
if (r != OK) {
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
return ENODEV;
|
||||
}
|
||||
|
||||
21
minix/drivers/bus/i2c/i2c.conf
Normal file
21
minix/drivers/bus/i2c/i2c.conf
Normal file
@@ -0,0 +1,21 @@
|
||||
service i2c
|
||||
{
|
||||
system
|
||||
PRIVCTL # 4
|
||||
IRQCTL # 19
|
||||
PADCONF # 57
|
||||
;
|
||||
irq
|
||||
# DM37XX (BeagleBoard-xM)
|
||||
56 # I2C module 1
|
||||
57 # I2C module 2
|
||||
61 # I2C module 3
|
||||
# AM335X (BeagleBone)
|
||||
70 # I2C module 1
|
||||
71 # I2C module 2
|
||||
30 # I2C module 3
|
||||
# BCM283X (RaspberryPi 2,3)
|
||||
47
|
||||
;
|
||||
ipc SYSTEM rs ds;
|
||||
};
|
||||
14
minix/drivers/bus/spi/Makefile
Normal file
14
minix/drivers/bus/spi/Makefile
Normal file
@@ -0,0 +1,14 @@
|
||||
# Makefile for the SPI broadcom driver
|
||||
PROG= spi
|
||||
SRCS= spi.c
|
||||
|
||||
FILESNAME=${PROG}
|
||||
FILESDIR= /etc/system.conf.d
|
||||
|
||||
DPADD+= ${LIBCHARDRIVER} ${LIBSYS}
|
||||
LDADD+= -lchardriver -lsys
|
||||
|
||||
# This is a system driver.
|
||||
CPPFLAGS+= -D_SYSTEM=1
|
||||
|
||||
.include <minix.service.mk>
|
||||
380
minix/drivers/bus/spi/spi.c
Normal file
380
minix/drivers/bus/spi/spi.c
Normal file
@@ -0,0 +1,380 @@
|
||||
#include <minix/drivers.h>
|
||||
#include <minix/chardriver.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <minix/ds.h>
|
||||
#include <minix/log.h>
|
||||
#include <minix/com.h>
|
||||
#include <minix/vm.h>
|
||||
#include <minix/mmio.h>
|
||||
#include <minix/type.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <minix/padconf.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "spi.h"
|
||||
|
||||
/*
|
||||
* Function prototypes for the spi driver.
|
||||
*/
|
||||
static int spi_open(devminor_t minor, int access, endpoint_t user_endpt);
|
||||
static int spi_close(devminor_t minor);
|
||||
static ssize_t spi_read(devminor_t minor, u64_t position, endpoint_t endpt,
|
||||
cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
|
||||
static ssize_t spi_write(devminor_t minor, u64_t position, endpoint_t endpt,
|
||||
cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
|
||||
|
||||
#define COPYBUF_SIZE 0x1000 /* 4k buff */
|
||||
static unsigned char copybuf[COPYBUF_SIZE];
|
||||
|
||||
/* SEF functions and variables. */
|
||||
static void sef_local_startup(void);
|
||||
static int sef_cb_init(int type, sef_init_info_t *info);
|
||||
static int sef_cb_lu_state_save(int, int);
|
||||
static int lu_state_restore(void);
|
||||
|
||||
/* Entry points to the spi driver. */
|
||||
static struct chardriver spi_tab =
|
||||
{
|
||||
.cdr_open = spi_open,
|
||||
.cdr_close = spi_close,
|
||||
.cdr_read = spi_read,
|
||||
.cdr_write = spi_write,
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vir_bytes CS;
|
||||
vir_bytes FIFO;
|
||||
vir_bytes CLK;
|
||||
vir_bytes DLEN;
|
||||
vir_bytes LTOH;
|
||||
vir_bytes DC;
|
||||
} spi_regs_t;
|
||||
|
||||
static spi_regs_t spi_reg = {
|
||||
.CS = SPI_CS,
|
||||
.FIFO = SPI_FIFO,
|
||||
.CLK = SPI_CLK,
|
||||
.DLEN = SPI_DLEN,
|
||||
.LTOH = SPI_LTOH,
|
||||
.DC = SPI_DC,
|
||||
};
|
||||
|
||||
vir_bytes io_base;
|
||||
spi_regs_t *rpi_spi_bus;
|
||||
|
||||
/*
|
||||
* Define a structure to be used for logging
|
||||
*/
|
||||
static struct log log = {
|
||||
.name = "spi",
|
||||
.log_level = LEVEL_DEBUG,
|
||||
.log_func = default_log
|
||||
};
|
||||
|
||||
#define div_roundup(x, y) (((x)+((y)-1))/(y))
|
||||
|
||||
static int spi_reset()
|
||||
{
|
||||
/* Disable interrupts */
|
||||
spi_set32(rpi_spi_bus->CS, SPI_CS_INTR | SPI_CS_INTD | SPI_CS_DMAEN | SPI_CS_TA, 0);
|
||||
/* Clear fifo */
|
||||
spi_set32(rpi_spi_bus->CS, SPI_CS_RX_CLEAR | SPI_CS_TX_CLEAR,
|
||||
SPI_CS_RX_CLEAR | SPI_CS_TX_CLEAR);
|
||||
|
||||
spi_write32(rpi_spi_bus->DLEN, 0);
|
||||
return OK;
|
||||
}
|
||||
|
||||
static void spi_padconf()
|
||||
{
|
||||
int r;
|
||||
uint32_t pinopts;
|
||||
|
||||
pinopts = CONTROL_BCM_CONF_SPI0_MISO |
|
||||
CONTROL_BCM_CONF_SPI0_CE1 | CONTROL_BCM_CONF_SPI0_CE0;
|
||||
|
||||
r = sys_padconf(GPFSEL09, pinopts,
|
||||
pinopts);
|
||||
if (r != OK) {
|
||||
log_warn(&log, "padconf failed (r=%d)\n", r);
|
||||
}
|
||||
|
||||
log_debug(&log, "pinopts=0x%x\n", pinopts);
|
||||
|
||||
pinopts = CONTROL_BCM_CONF_SPI0_MOSI | CONTROL_BCM_CONF_SPI0_SCLK;
|
||||
r = sys_padconf(GPFSEL1019, pinopts,
|
||||
pinopts);
|
||||
if (r != OK) {
|
||||
log_warn(&log, "padconf failed (r=%d)\n", r);
|
||||
}
|
||||
|
||||
log_debug(&log, "pinopts=0x%x\n", pinopts);
|
||||
}
|
||||
|
||||
static int spi_open(devminor_t UNUSED(minor), int UNUSED(access),
|
||||
endpoint_t UNUSED(user_endpt))
|
||||
{
|
||||
log_debug(&log, "spi_open\n");
|
||||
/* Clear fifo */
|
||||
spi_set32(rpi_spi_bus->CS, SPI_CS_RX_CLEAR | SPI_CS_TX_CLEAR,
|
||||
SPI_CS_RX_CLEAR | SPI_CS_TX_CLEAR);
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int spi_close(devminor_t UNUSED(minor))
|
||||
{
|
||||
log_debug(&log, "spi_close\n");
|
||||
spi_reset();
|
||||
return OK;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
spi_poll(uint32_t mask)
|
||||
{
|
||||
spin_t spin;
|
||||
uint32_t status;
|
||||
|
||||
/* poll for up to 1 s */
|
||||
spin_init(&spin, 1000000);
|
||||
do {
|
||||
status = spi_read32(rpi_spi_bus->CS);
|
||||
if ((status & mask) != 0) { /* any bits in mask set */
|
||||
return status;
|
||||
}
|
||||
} while (spin_check(&spin));
|
||||
|
||||
return status; /* timeout reached, abort */
|
||||
}
|
||||
|
||||
static int spi_read_bytes(uint32_t size)
|
||||
{
|
||||
int i;
|
||||
uint32_t status;
|
||||
uint32_t pollmask;
|
||||
|
||||
for(i = 0; i < size; i++) {
|
||||
pollmask = SPI_CS_RXD;
|
||||
status = spi_poll(pollmask);
|
||||
if ((pollmask & status) == 0) {
|
||||
log_warn(&log, "Can't wait RXD interrupt. Status = 0x%08x\n", status);
|
||||
return (-EIO);
|
||||
}
|
||||
copybuf[i] = spi_read32(rpi_spi_bus->FIFO);
|
||||
|
||||
pollmask = SPI_CS_DONE;
|
||||
status = spi_poll(pollmask);
|
||||
if ((pollmask & status) == 0) {
|
||||
log_warn(&log, "Can't wait DONE interrupt. Status = 0x%08x\n", status);
|
||||
return (-EIO);
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static int spi_write_bytes(uint32_t size)
|
||||
{
|
||||
int i;
|
||||
uint32_t status;
|
||||
uint32_t pollmask;
|
||||
|
||||
for(i = 0; i < size; i++) {
|
||||
pollmask = SPI_CS_TXD;
|
||||
status = spi_poll(pollmask);
|
||||
if ((pollmask & status) == 0) {
|
||||
log_warn(&log, "Can't wait TXD interrupt. Status = 0x%08x\n", status);
|
||||
return (-EIO);
|
||||
}
|
||||
spi_write32(rpi_spi_bus->FIFO, copybuf[i]);
|
||||
|
||||
pollmask = SPI_CS_DONE;
|
||||
status = spi_poll(pollmask);
|
||||
if ((pollmask & status) == 0) {
|
||||
log_warn(&log, "Can't wait DONE interrupt. Status = 0x%08x\n", status);
|
||||
return (-EIO);
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static int spi_transfer(uint32_t size, int mode)
|
||||
{
|
||||
int retv;
|
||||
|
||||
spi_set32(rpi_spi_bus->CS, SPI_CS_CS, 0);
|
||||
spi_set32(rpi_spi_bus->CS, SPI_CS_MODE, SPI_CS_MODE0);
|
||||
|
||||
/* Start transfer */
|
||||
spi_set32(rpi_spi_bus->CS, SPI_CS_TA, SPI_CS_TA);
|
||||
|
||||
log_debug(&log, "size %d\n", size);
|
||||
|
||||
if (mode == WRITE_MODE) {
|
||||
retv = spi_write_bytes(size);
|
||||
} else {
|
||||
spi_set32(rpi_spi_bus->CS, SPI_CS_REN, SPI_CS_REN);
|
||||
retv = spi_read_bytes(size);
|
||||
}
|
||||
|
||||
if (retv < 0) {
|
||||
log_warn(&log, "Transfer failed\n");
|
||||
return (-EIO);
|
||||
}
|
||||
|
||||
/* Stop transfer */
|
||||
spi_set32(rpi_spi_bus->CS, SPI_CS_TA, 0);
|
||||
|
||||
return retv;
|
||||
}
|
||||
|
||||
static ssize_t spi_read(devminor_t UNUSED(minor), u64_t position,
|
||||
endpoint_t endpt, cp_grant_id_t grant, size_t size, int UNUSED(flags),
|
||||
cdev_id_t UNUSED(id))
|
||||
{
|
||||
int retv;
|
||||
log_debug(&log, "spi_read\n");
|
||||
|
||||
if(size < 0 || size > COPYBUF_SIZE) {
|
||||
log_warn(&log, "illegal size\n");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
retv = spi_transfer(size, READ_MODE);
|
||||
|
||||
ssize_t ret;
|
||||
if ((ret = sys_safecopyto(endpt, grant, 0, (vir_bytes) copybuf, size)) != OK)
|
||||
return ret;
|
||||
|
||||
return retv;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t spi_write(devminor_t UNUSED(minor), u64_t position,
|
||||
endpoint_t endpt, cp_grant_id_t grant, size_t size, int UNUSED(flags),
|
||||
cdev_id_t UNUSED(id))
|
||||
{
|
||||
int retv;
|
||||
log_debug(&log, "spi_write\n");
|
||||
|
||||
if(size < 0 || size > COPYBUF_SIZE) {
|
||||
log_warn(&log, "illegal size\n");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
ssize_t ret;
|
||||
if ((ret = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) copybuf, size)) != OK)
|
||||
return ret;
|
||||
|
||||
retv = spi_transfer(size, WRITE_MODE);
|
||||
|
||||
return retv;
|
||||
}
|
||||
|
||||
static void sef_local_startup()
|
||||
{
|
||||
/*
|
||||
* Register init callbacks. Use the same function for all event types
|
||||
*/
|
||||
sef_setcb_init_fresh(sef_cb_init);
|
||||
sef_setcb_init_lu(sef_cb_init);
|
||||
sef_setcb_init_restart(sef_cb_init);
|
||||
|
||||
/* Let SEF perform startup. */
|
||||
sef_startup();
|
||||
}
|
||||
|
||||
static int sef_cb_init(int type, sef_init_info_t *UNUSED(info))
|
||||
{
|
||||
spi_reset();
|
||||
|
||||
/* 3.9 MHz */
|
||||
spi_write32(rpi_spi_bus->CLK, SPI_SPEED_3DOT9);
|
||||
|
||||
/* Enable interrupts */
|
||||
spi_set32(rpi_spi_bus->CS, SPI_CS_INTR | SPI_CS_INTD | SPI_CS_DMAEN | SPI_CS_TA,
|
||||
SPI_CS_INTR | SPI_CS_INTD | SPI_CS_TA);
|
||||
|
||||
chardriver_announce();
|
||||
|
||||
/* Initialization completed successfully. */
|
||||
return OK;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct minix_mem_range mr;
|
||||
|
||||
/* Configure memory access */
|
||||
mr.mr_base = SPI_BASE; /* start addr */
|
||||
mr.mr_limit = mr.mr_base + SPI_REG_SIZE; /* end addr */
|
||||
|
||||
/* ask for privileges to access the SPI memory range */
|
||||
if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != OK) {
|
||||
panic("Unable to obtain spi memory range privileges");
|
||||
}
|
||||
|
||||
/* map the memory into this process */
|
||||
io_base = (vir_bytes) vm_map_phys(SELF,
|
||||
(void *) SPI_BASE, SPI_REG_SIZE);
|
||||
|
||||
if (io_base == (vir_bytes) MAP_FAILED) {
|
||||
panic("Unable to map spi registers");
|
||||
}
|
||||
|
||||
uint32_t hook_id = 1;
|
||||
if (sys_irqsetpolicy(SPI_IRQ, 0, &hook_id) != OK) {
|
||||
log_warn(&log, "couldn't set IRQ policy %d\n",
|
||||
SPI_IRQ);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rpi_spi_bus = &spi_reg;
|
||||
|
||||
spi_padconf();
|
||||
/*
|
||||
* Perform initialization.
|
||||
*/
|
||||
sef_local_startup();
|
||||
|
||||
/*
|
||||
* Run the main loop.
|
||||
*/
|
||||
chardriver_task(&spi_tab);
|
||||
log_debug(&log, "Started\n");
|
||||
return OK;
|
||||
}
|
||||
|
||||
void
|
||||
spi_set32(vir_bytes reg, uint32_t mask, uint32_t value)
|
||||
{
|
||||
if(reg < 0 || reg > SPI_REG_SIZE) {
|
||||
log_warn(&log, "Non-existent register");
|
||||
return;
|
||||
}
|
||||
set32(io_base + reg, mask, value);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
spi_read32(vir_bytes reg)
|
||||
{
|
||||
if(reg < 0 || reg > SPI_REG_SIZE) {
|
||||
log_warn(&log, "Non-existent register");
|
||||
return 0;
|
||||
}
|
||||
return read32(io_base + reg);
|
||||
}
|
||||
|
||||
void
|
||||
spi_write32(vir_bytes reg, uint32_t value)
|
||||
{
|
||||
if(reg < 0 || reg > SPI_REG_SIZE) {
|
||||
log_warn(&log, "Non-existent register");
|
||||
return;
|
||||
}
|
||||
write32(io_base + reg, value);
|
||||
}
|
||||
|
||||
42
minix/drivers/bus/spi/spi.h
Normal file
42
minix/drivers/bus/spi/spi.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifndef _SPI_H_
|
||||
#define _SPI_H_
|
||||
|
||||
#define SPI_BASE 0x3f204000
|
||||
#define SPI_REG_SIZE 0x100
|
||||
|
||||
#define SPI_IRQ 48
|
||||
|
||||
#define SPI_SPEED3DOT9 64
|
||||
|
||||
#define SPI_CS 0x0
|
||||
#define SPI_FIFO 0x4
|
||||
#define SPI_CLK 0x8
|
||||
#define SPI_DLEN 0xc
|
||||
#define SPI_LTOH 0x10
|
||||
#define SPI_DC 0x14
|
||||
|
||||
#define SPI_CS_CS 0x3
|
||||
#define SPI_CS_MODE 0xc
|
||||
#define SPI_CS_MODE0 0x0
|
||||
#define SPI_CS_MODE1 0x4
|
||||
#define SPI_CS_MODE2 0x8
|
||||
#define SPI_CS_MODE3 0xc
|
||||
#define SPI_CS_TX_CLEAR 0x10
|
||||
#define SPI_CS_RX_CLEAR 0x20
|
||||
#define SPI_CS_TA 0x80
|
||||
#define SPI_CS_DMAEN 0x100
|
||||
#define SPI_CS_INTD 0x200
|
||||
#define SPI_CS_INTR 0x400
|
||||
#define SPI_CS_REN 0x1000
|
||||
#define SPI_CS_DONE 0x10000
|
||||
#define SPI_CS_RXD 0x20000
|
||||
#define SPI_CS_TXD 0x40000
|
||||
#define SPI_CS_CSPOL0 0x200000
|
||||
|
||||
#define WRITE_MODE 1
|
||||
#define READ_MODE 0
|
||||
|
||||
uint32_t spi_read32(vir_bytes port);
|
||||
void spi_write32(vir_bytes port, uint32_t value);
|
||||
void spi_set32(vir_bytes port, uint32_t mask, uint32_t value);
|
||||
#endif /* _SPI_H_ */
|
||||
@@ -1,18 +1,17 @@
|
||||
# Makefile for the mmc driver.
|
||||
PROGS= mmc emmc
|
||||
MAN.mmc=
|
||||
MAN.emmc=
|
||||
.include <bsd.own.mk>
|
||||
|
||||
SRCS.mmc= mmcblk.c mmchost_dummy.c sdhcreg.h sdmmcreg.h
|
||||
SRCS.mmc += mmchost_mmchs.c
|
||||
SRCS.emmc= emmc.c mmcblk.c
|
||||
.for pl in omap rpi
|
||||
PROGS += ${pl}_mmc ${pl}_emmc
|
||||
MAN.${pl}_emmc =
|
||||
MAN.${pl}_mmc =
|
||||
|
||||
SRCS.${pl}_emmc += mmcblk.c emmc_${pl}.c
|
||||
SRCS.${pl}_mmc += mmcblk.c mmchost_dummy.c mmchost_${pl}.c
|
||||
.endfor
|
||||
|
||||
BINDIR= /service/
|
||||
|
||||
DPADD+= ${LIBBLOCKDRIVER} ${LIBSYS}
|
||||
LDADD+= -lblockdriver -lsys
|
||||
CLEANFILES+=.depend mmcblk.d
|
||||
|
||||
#
|
||||
# This is a system driver.
|
||||
CPPFLAGS+= -D_SYSTEM=1
|
||||
|
||||
.include <minix.service.mk>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "omap_mmc.h"
|
||||
#include "mmc_omap.h"
|
||||
#include "mmchost.h"
|
||||
#include "sdmmcreg.h"
|
||||
|
||||
@@ -77,14 +77,6 @@ static uint64_t card_size;
|
||||
/* IRQ_HOOK_ID for SYS_IRQCTL kernel call. */
|
||||
static int hook_id = 1;
|
||||
|
||||
/* Initialize the log system. */
|
||||
static struct log log = {
|
||||
.name = "emmc",
|
||||
.log_level = LEVEL_INFO,
|
||||
.log_func = default_log,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Spin until a register flag is set, or the time runs out.
|
||||
* Return the flag value.
|
||||
@@ -223,8 +215,10 @@ send_cmd(uint32_t arg, uint32_t cmd)
|
||||
write32(reg->ARG, arg);
|
||||
write32(reg->CMD, cmd);
|
||||
/* Wait for the command completion. */
|
||||
if (irq_wait() < 0)
|
||||
if (irq_wait() < 0) {
|
||||
log_warn (&log, "can't wait irq\n");
|
||||
return -1;
|
||||
}
|
||||
stat = read32(reg->SD_STAT);
|
||||
/*
|
||||
* Clear only the command status/error bits. The transfer status/error
|
||||
@@ -236,6 +230,7 @@ send_cmd(uint32_t arg, uint32_t cmd)
|
||||
| MMCHS_SD_STAT_CTO
|
||||
| MMCHS_SD_STAT_CC);
|
||||
if (stat & MMCHS_SD_STAT_CTO) {
|
||||
log_warn(&log, "timeout error\n");
|
||||
reset_mmchs_fsm(MMCHS_SD_SYSCTL_SRC);
|
||||
return -1;
|
||||
}
|
||||
@@ -623,8 +618,10 @@ minix_init(void)
|
||||
reg->ISE += v_base;
|
||||
|
||||
/* Register the MMC1 interrupt number. */
|
||||
if (sys_irqsetpolicy(AM335X_MMCSD1INT, 0, &hook_id) != OK)
|
||||
if (sys_irqsetpolicy(AM335X_MMCSD1INT, 0, &hook_id) != OK) {
|
||||
log_warn(&log, "can't set irq\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -743,17 +740,6 @@ emmc_host_init(struct mmc_host *host)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Interface to the MINIX block device driver.
|
||||
* Set the log level.
|
||||
*/
|
||||
static void
|
||||
emmc_set_log_level(int level)
|
||||
{
|
||||
log.log_level = level;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Interface to the MINIX block device driver.
|
||||
* Unused, but declared in mmchost.h.
|
||||
@@ -841,6 +827,7 @@ emmc_card_initialize(struct sd_slot *slot)
|
||||
/* CMD8 */
|
||||
if (send_ext_csd() < 0)
|
||||
return NULL;
|
||||
|
||||
/* Receive the Extended CSD register. */
|
||||
if (read_data((uint32_t *)card_ext_csd) < 0)
|
||||
return NULL;
|
||||
@@ -1005,7 +992,6 @@ host_initialize_host_structure_mmchs(struct mmc_host *host)
|
||||
/* Register the driver interface at the block device driver. */
|
||||
host->host_set_instance = &emmc_host_set_instance;
|
||||
host->host_init = &emmc_host_init;
|
||||
host->set_log_level = &emmc_set_log_level;
|
||||
host->host_reset = NULL;
|
||||
host->card_detect = &emmc_card_detect;
|
||||
host->card_initialize = &emmc_card_initialize;
|
||||
@@ -1018,6 +1004,9 @@ host_initialize_host_structure_mmchs(struct mmc_host *host)
|
||||
host->slot[i].card.state = SD_MODE_UNINITIALIZED;
|
||||
host->slot[i].card.slot = &host->slot[i];
|
||||
}
|
||||
|
||||
/* Customize name for logs */
|
||||
log.name = "emmc_omap";
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1027,4 +1016,4 @@ host_initialize_host_structure_mmchs(struct mmc_host *host)
|
||||
void
|
||||
host_initialize_host_structure_dummy(struct mmc_host *host)
|
||||
{
|
||||
}
|
||||
}
|
||||
958
minix/drivers/storage/mmc/emmc_rpi.c
Normal file
958
minix/drivers/storage/mmc/emmc_rpi.c
Normal file
@@ -0,0 +1,958 @@
|
||||
#include <minix/blockdriver.h>
|
||||
#include <minix/board.h>
|
||||
#include <minix/log.h>
|
||||
#include <minix/mmio.h>
|
||||
#include <minix/spin.h>
|
||||
#include <minix/syslib.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "mmc_rpi.h"
|
||||
#include "mmchost.h"
|
||||
#include "sdmmcreg.h"
|
||||
|
||||
/* MINIX IRQ timeout. Twice the host controller data/busy timeout @ 48MHz. */
|
||||
#define IRQ_TIMEOUT 5600000 /* 5,600,000 us */
|
||||
|
||||
#define MMCHS_TIMEOUT 500000 /* 500,000 us */
|
||||
|
||||
/* Reference clock frequency divisors: */
|
||||
#define MMCHS_SD_SYSCTL_CLKD_400KHZ 240 /* 96MHz/400kHz */
|
||||
#define MMCHS_SD_SYSCTL_CLKD_26MHZ 4 /* ceiling 96MHz/26MHz */
|
||||
#define MMCHS_SD_SYSCTL_CLKD_52MHZ 2 /* ceiling 96MHz/52MHz */
|
||||
|
||||
/* The host SD_DATA register is 128 words (512B). */
|
||||
#define SD_DATA_WLEN 128
|
||||
|
||||
/*
|
||||
* Card initialization timeout, twice the standard:
|
||||
* "The device must complete its initialization within 1 second of the first
|
||||
* CMD1 issued with a valid OCR range." (MMCA, 4.41)
|
||||
*/
|
||||
#define CARD_INI_TIMEOUT 2000000 /* 2,000,000 us */
|
||||
|
||||
/* Card EXT_CSD register fields. */
|
||||
#define MMC_EXT_CSD_SEC_COUNT (*(uint32_t *)&card_ext_csd[212])
|
||||
#define MMC_EXT_CSD_CARD_TYPE (card_ext_csd[196])
|
||||
#define MMC_EXT_CSD_CARD_TYPE_HS_MMC_52MHZ (0x1 << 1)
|
||||
|
||||
/* Card intended operating voltage range: 2.7V to 3.6V */
|
||||
#define MMC_OCR_VDD_RANGE 0x00FF8000
|
||||
|
||||
/* Error bits in the card status (R1) response. */
|
||||
#define R1_ERROR_MASK 0xFDFFA080
|
||||
|
||||
/* Relative Card Address. Must be greater than 1. */
|
||||
#define RCA 0x2
|
||||
|
||||
/* The card sector size is 512B. */
|
||||
#define SEC_SIZE 512
|
||||
|
||||
/*
|
||||
* AM335x Control Module registers CONF_GPMC_ADn.
|
||||
* Configuration do multiplex CONF_GPMC_ADn to signals MMC1_DATn (Mode 1).
|
||||
*/
|
||||
#define CONF_GPMC_AD(N) (0x800 + 4*(N))
|
||||
#define CONF_GPMC_AD_MASK 0x7F
|
||||
#define CONF_GPMC_AD_VAL 0x31
|
||||
|
||||
/* AM335x MMC1 memory map (physical start address and size). */
|
||||
#define BCM2835_MMC0_BASE_ADDR 0x3F300000
|
||||
#define BCM2835_MMC0_SIZE (4 << 6)
|
||||
/* BCM2835 MMC1 interrupt number. */
|
||||
#define BCM2835_MMCSD1INT 52
|
||||
|
||||
static uint32_t bus_width;
|
||||
|
||||
/* AM335x MMCHS registers virtual addresses: virtual base + offset. */
|
||||
static struct rpi_mmchs_registers *reg;
|
||||
|
||||
/* Card registers. */
|
||||
static uint32_t card_csd[4];
|
||||
static uint8_t card_ext_csd[512];
|
||||
|
||||
static uint32_t card_write_protect;
|
||||
static uint64_t card_size;
|
||||
|
||||
/* IRQ_HOOK_ID for SYS_IRQCTL kernel call. */
|
||||
static int hook_id = 1;
|
||||
|
||||
/*
|
||||
* Spin until a register flag is set, or the time runs out.
|
||||
* Return the flag value.
|
||||
*/
|
||||
static uint32_t
|
||||
spin_until_set(uint32_t address, uint32_t flag)
|
||||
{
|
||||
spin_t s;
|
||||
int spin;
|
||||
uint32_t v;
|
||||
|
||||
spin_init(&s, MMCHS_TIMEOUT);
|
||||
do {
|
||||
spin = spin_check(&s);
|
||||
v = (read32(address) & flag);
|
||||
} while ((v == 0) && (spin == TRUE));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/*
|
||||
* Spin until the time runs out.
|
||||
*/
|
||||
static void
|
||||
spin_time()
|
||||
{
|
||||
spin_t s;
|
||||
int spin;
|
||||
|
||||
spin_init(&s, MMCHS_TIMEOUT);
|
||||
do {
|
||||
spin = spin_check(&s);
|
||||
} while (spin == TRUE);
|
||||
}
|
||||
/*
|
||||
* Spin until a register flag is clear, or the time runs out.
|
||||
* Return the flag value.
|
||||
*/
|
||||
static uint32_t
|
||||
spin_until_clear(uint32_t address, uint32_t flag)
|
||||
{
|
||||
spin_t s;
|
||||
int spin;
|
||||
uint32_t v;
|
||||
|
||||
spin_init(&s, MMCHS_TIMEOUT);
|
||||
do {
|
||||
spin = spin_check(&s);
|
||||
v = (read32(address) & flag);
|
||||
} while ((v != 0) && (spin == TRUE));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the bus clock frequency (divisor).
|
||||
* Return 0 on success, a negative integer on error.
|
||||
*/
|
||||
static int
|
||||
set_bus_clkd(uint32_t clkd)
|
||||
{
|
||||
/*
|
||||
* Disable the bus clock, set the clock divider, wait until the
|
||||
* internal clock is stable, enable the bus clock.
|
||||
*/
|
||||
set32(reg->control1, MMCHS_SD_SYSCTL_CEN, MMCHS_SD_SYSCTL_CEN_DIS);
|
||||
set32(reg->control1, MMCHS_SD_SYSCTL_CLKD, clkd << 6);
|
||||
if (spin_until_set(reg->control1, MMCHS_SD_SYSCTL_ICS)
|
||||
== MMCHS_SD_SYSCTL_ICS_UNSTABLE)
|
||||
return -1;
|
||||
set32(reg->control1, MMCHS_SD_SYSCTL_CEN, MMCHS_SD_SYSCTL_CEN_EN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Receive an interrupt request.
|
||||
* Return 0 on success, a negative integer on error.
|
||||
*/
|
||||
static int
|
||||
irq_receive(void)
|
||||
{
|
||||
message m;
|
||||
int ipc_status;
|
||||
|
||||
while (1) {
|
||||
if (driver_receive(ANY, &m, &ipc_status) != OK)
|
||||
return -1;
|
||||
if (is_ipc_notify(ipc_status)
|
||||
&& (_ENDPOINT_P(m.m_source) == CLOCK))
|
||||
return -1;
|
||||
if (is_ipc_notify(ipc_status)
|
||||
&& (_ENDPOINT_P(m.m_source) == HARDWARE))
|
||||
return 0;
|
||||
/*
|
||||
* m will be discarded if the driver is out of memory.
|
||||
*/
|
||||
blockdriver_mq_queue(&m, ipc_status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for an interrupt request.
|
||||
* Return 0 on interrupt, a negative integer on error.
|
||||
*/
|
||||
static int
|
||||
irq_wait(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (sys_irqenable(&hook_id) != OK)
|
||||
return -1;
|
||||
sys_setalarm(micros_to_ticks(IRQ_TIMEOUT), 0);
|
||||
r = irq_receive();
|
||||
sys_setalarm(0, 0);
|
||||
if (r < 0)
|
||||
sys_irqdisable(&hook_id);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Software reset for mmc_cmd or mmc_dat line.
|
||||
*/
|
||||
static void
|
||||
reset_mmchs_fsm(uint32_t line)
|
||||
{
|
||||
/*
|
||||
* "The proper procedure is: (a) Set to 1 to start reset,
|
||||
* (b) Poll for 1 to identify start of reset, and
|
||||
* (c) Poll for 0 to identify reset is complete." (AM335x TRM)
|
||||
*/
|
||||
set32(reg->control1, line, line);
|
||||
spin_until_set(reg->control1, line);
|
||||
spin_until_clear(reg->control1, line);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a command to the card.
|
||||
* Return 0 on success, a negative integer on error.
|
||||
*/
|
||||
static int
|
||||
send_cmd(uint32_t arg, uint32_t cmd)
|
||||
{
|
||||
uint32_t stat;
|
||||
|
||||
if (read32(reg->status)
|
||||
& (MMCHS_SD_PSTATE_DATI | MMCHS_SD_PSTATE_CMDI))
|
||||
return -1; /* Issuing of commands is not allowed. */
|
||||
|
||||
write32(reg->arg1, arg);
|
||||
write32(reg->cmdtm, cmd);
|
||||
/* Wait for the command completion. */
|
||||
if (irq_wait() < 0) {
|
||||
log_warn (&log, "can't wait irq\n");
|
||||
return -1;
|
||||
}
|
||||
stat = read32(reg->irpt);
|
||||
/*
|
||||
* Clear only the command status/error bits. The transfer status/error
|
||||
* bits (including ERRI) must be preserved.
|
||||
*/
|
||||
write32(reg->irpt, MMCHS_SD_STAT_CIE
|
||||
| MMCHS_SD_STAT_CEB
|
||||
| MMCHS_SD_STAT_CCRC
|
||||
| MMCHS_SD_STAT_CTO
|
||||
| MMCHS_SD_STAT_CC);
|
||||
if (stat & MMCHS_SD_STAT_CTO) {
|
||||
log_warn(&log, "timeout error\n");
|
||||
reset_mmchs_fsm(MMCHS_SD_SYSCTL_SRC);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a command to the card, and check for errors in the response (R1).
|
||||
* Return 0 on success, a negative integer on error.
|
||||
*/
|
||||
static int
|
||||
send_cmd_check_r1(uint32_t arg, uint32_t cmd)
|
||||
{
|
||||
if (send_cmd(arg, cmd) < 0)
|
||||
return -1;
|
||||
/* Check for card errors in the card response (R1). */
|
||||
if (read32(reg->resp0) & R1_ERROR_MASK)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Send CMD0 (GO_IDLE_STATE) command to the card. */
|
||||
static int
|
||||
go_idle_state(void)
|
||||
{
|
||||
return send_cmd(0, MMCHS_SD_CMD_INDX_CMD(MMC_GO_IDLE_STATE));
|
||||
}
|
||||
|
||||
/* Send CMD1 (SEND_OP_COND) command to the card. */
|
||||
static int
|
||||
send_op_cond(void)
|
||||
{
|
||||
uint32_t cmd;
|
||||
|
||||
/* The driver is capable of handling sector type of addressing. */
|
||||
cmd = MMCHS_SD_CMD_INDX_CMD(SD_SEND_OP_COND)
|
||||
| MMCHS_SD_CMD_RSP_TYPE_48B;
|
||||
return send_cmd((MMC_OCR_HCS | MMC_OCR_VDD_RANGE), cmd);
|
||||
}
|
||||
|
||||
/* Send CMD2 (ALL_SEND_CID) command to the card. */
|
||||
static int
|
||||
all_send_cid(void)
|
||||
{
|
||||
uint32_t cmd;
|
||||
|
||||
cmd = MMCHS_SD_CMD_INDX_CMD(MMC_ALL_SEND_CID)
|
||||
| MMCHS_SD_CMD_CCCE_ENABLE
|
||||
| MMCHS_SD_CMD_RSP_TYPE_136B;
|
||||
return send_cmd(0, cmd);
|
||||
}
|
||||
|
||||
/* Send CMD3 (SET_RELATIVE_ADDR) command to the card. */
|
||||
static int
|
||||
set_relative_addr(void)
|
||||
{
|
||||
uint32_t cmd;
|
||||
|
||||
cmd = MMCHS_SD_CMD_INDX_CMD(MMC_SET_RELATIVE_ADDR)
|
||||
| MMCHS_SD_CMD_CICE_ENABLE
|
||||
| MMCHS_SD_CMD_CCCE_ENABLE
|
||||
| MMCHS_SD_CMD_RSP_TYPE_48B;
|
||||
return send_cmd_check_r1(MMC_ARG_RCA(RCA), cmd);
|
||||
}
|
||||
|
||||
/* Send CMD6 (SWITCH) command to the card. */
|
||||
static int
|
||||
mmc_switch(uint32_t access, uint32_t index, uint32_t value)
|
||||
{
|
||||
uint32_t arg, cmd;
|
||||
|
||||
/* SWITCH argument: [25:24] Access, [23:16] Index, [15:8] Value. */
|
||||
arg = (access << 24) | (index << 16) | (value << 8);
|
||||
cmd = MMCHS_SD_CMD_INDX_CMD(MMC_SWITCH)
|
||||
| MMCHS_SD_CMD_CICE_ENABLE
|
||||
| MMCHS_SD_CMD_CCCE_ENABLE
|
||||
| MMCHS_SD_CMD_RSP_TYPE_48B_BUSY;
|
||||
return send_cmd_check_r1(arg, cmd);
|
||||
}
|
||||
|
||||
/* Send CMD7 (SELECT_CARD) command to the card. */
|
||||
static int
|
||||
select_card(void)
|
||||
{
|
||||
uint32_t cmd;
|
||||
|
||||
cmd = MMCHS_SD_CMD_INDX_CMD(MMC_SELECT_CARD)
|
||||
| MMCHS_SD_CMD_CICE_ENABLE
|
||||
| MMCHS_SD_CMD_CCCE_ENABLE
|
||||
| MMCHS_SD_CMD_RSP_TYPE_48B;
|
||||
return send_cmd_check_r1(MMC_ARG_RCA(RCA), cmd);
|
||||
}
|
||||
|
||||
/* Send CMD9 (SEND_CSD) command to the card. */
|
||||
static int
|
||||
send_csd(void)
|
||||
{
|
||||
uint32_t cmd;
|
||||
|
||||
cmd = MMCHS_SD_CMD_INDX_CMD(MMC_SEND_CSD)
|
||||
| MMCHS_SD_CMD_CCCE_ENABLE
|
||||
| MMCHS_SD_CMD_RSP_TYPE_136B;
|
||||
return send_cmd(MMC_ARG_RCA(RCA), cmd);
|
||||
}
|
||||
|
||||
/* Send CMD13 (SEND_STATUS) command to the card. */
|
||||
static int
|
||||
send_status(void)
|
||||
{
|
||||
uint32_t cmd;
|
||||
|
||||
cmd = MMCHS_SD_CMD_INDX_CMD(MMC_SEND_STATUS)
|
||||
| MMCHS_SD_CMD_CICE_ENABLE
|
||||
| MMCHS_SD_CMD_CCCE_ENABLE
|
||||
| MMCHS_SD_CMD_RSP_TYPE_48B;
|
||||
return send_cmd_check_r1(MMC_ARG_RCA(RCA), cmd);
|
||||
}
|
||||
|
||||
/* Send CMD16 (SET_BLOCKLEN) command to the card. */
|
||||
static int
|
||||
set_blocklen(void)
|
||||
{
|
||||
uint32_t cmd;
|
||||
|
||||
/* Set block length to sector size (512B). */
|
||||
cmd = MMCHS_SD_CMD_INDX_CMD(MMC_SET_BLOCKLEN)
|
||||
| MMCHS_SD_CMD_CICE_ENABLE
|
||||
| MMCHS_SD_CMD_CCCE_ENABLE
|
||||
| MMCHS_SD_CMD_RSP_TYPE_48B;
|
||||
return send_cmd_check_r1(SEC_SIZE, cmd);
|
||||
}
|
||||
|
||||
/* Send CMD17 (READ_SINGLE_BLOCK) to the card. */
|
||||
static int
|
||||
read_single_block(uint32_t addr)
|
||||
{
|
||||
uint32_t cmd;
|
||||
|
||||
cmd = MMCHS_SD_CMD_INDX_CMD(MMC_READ_BLOCK_SINGLE)
|
||||
| MMCHS_SD_CMD_DP_DATA
|
||||
| MMCHS_SD_CMD_CICE_ENABLE
|
||||
| MMCHS_SD_CMD_CCCE_ENABLE
|
||||
| MMCHS_SD_CMD_RSP_TYPE_48B
|
||||
| MMCHS_SD_CMD_DDIR_READ;
|
||||
return send_cmd_check_r1(addr, cmd);
|
||||
}
|
||||
|
||||
/* Send CMD24 (WRITE_BLOCK) to the card. */
|
||||
static int
|
||||
write_block(uint32_t addr)
|
||||
{
|
||||
uint32_t cmd;
|
||||
|
||||
cmd = MMCHS_SD_CMD_INDX_CMD(MMC_WRITE_BLOCK_SINGLE)
|
||||
| MMCHS_SD_CMD_DP_DATA
|
||||
| MMCHS_SD_CMD_CICE_ENABLE
|
||||
| MMCHS_SD_CMD_CCCE_ENABLE
|
||||
| MMCHS_SD_CMD_RSP_TYPE_48B
|
||||
| MMCHS_SD_CMD_DDIR_WRITE;
|
||||
return send_cmd_check_r1(addr, cmd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Repeat CMD1 until the card is ready, or the time runs out.
|
||||
* Return 0 on ready, a negative integer on error.
|
||||
*/
|
||||
static int
|
||||
repeat_send_op_cond(void)
|
||||
{
|
||||
spin_t s;
|
||||
int spin;
|
||||
uint32_t card_ocr;
|
||||
|
||||
spin_init(&s, CARD_INI_TIMEOUT);
|
||||
do {
|
||||
spin = spin_check(&s);
|
||||
if (send_op_cond() < 0)
|
||||
return -1;
|
||||
card_ocr = read32(reg->resp0);
|
||||
} while (((card_ocr & MMC_OCR_MEM_READY) == 0) && (spin == TRUE));
|
||||
|
||||
if ((card_ocr & MMC_OCR_MEM_READY) == 0)
|
||||
return -1; /* Card is still busy. */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read (receive) the busy signal from the card.
|
||||
* Return 0 on success, a negative integer on error.
|
||||
*/
|
||||
static int
|
||||
read_busy(void)
|
||||
{
|
||||
uint32_t stat;
|
||||
/*
|
||||
* The busy signal is optional, but the host controller will assert
|
||||
* SD_STAT[1] TC even if the card does not send it.
|
||||
*/
|
||||
if (irq_wait() < 0)
|
||||
return -1;
|
||||
stat = read32(reg->irpt);
|
||||
write32(reg->irpt, MMCHS_SD_STAT_DCRC
|
||||
| MMCHS_SD_STAT_DTO
|
||||
| MMCHS_SD_STAT_TC);
|
||||
if (stat & MMCHS_SD_STAT_ERRI) {
|
||||
reset_mmchs_fsm(MMCHS_SD_SYSCTL_SRD);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read (receive) data from the card.
|
||||
* Return 0 on success, a negative integer on error.
|
||||
*/
|
||||
static int
|
||||
read_data(uint32_t *data)
|
||||
{
|
||||
uint32_t stat, i;
|
||||
|
||||
/* Wait for BRR interrupt. */
|
||||
if (irq_wait() < 0)
|
||||
return -1;
|
||||
if (read32(reg->irpt) & MMCHS_SD_STAT_BRR) {
|
||||
write32(reg->irpt, MMCHS_SD_STAT_BRR);
|
||||
for (i=SD_DATA_WLEN; i>0; i--)
|
||||
*data++ = read32(reg->data);
|
||||
}
|
||||
|
||||
/* Wait for TC or ERRI interrupt. */
|
||||
if (irq_wait() < 0)
|
||||
return -1;
|
||||
stat = read32(reg->irpt);
|
||||
write32(reg->irpt, MMCHS_SD_STAT_DEB
|
||||
| MMCHS_SD_STAT_DCRC
|
||||
| MMCHS_SD_STAT_DTO
|
||||
| MMCHS_SD_STAT_TC);
|
||||
if (stat & MMCHS_SD_STAT_ERRI) {
|
||||
reset_mmchs_fsm(MMCHS_SD_SYSCTL_SRD);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write (send) data to the card.
|
||||
* Return 0 on success, a negative integer on error.
|
||||
*/
|
||||
static int
|
||||
write_data(uint32_t *data)
|
||||
{
|
||||
uint32_t stat, i;
|
||||
|
||||
/* Wait for BWR interrupt. */
|
||||
if (irq_wait() < 0)
|
||||
return -1;
|
||||
if (read32(reg->status) & MMCHS_SD_STAT_BWR) {
|
||||
write32(reg->irpt, MMCHS_SD_STAT_BWR);
|
||||
for (i = SD_DATA_WLEN; i > 0; i--)
|
||||
write32(reg->data, *data++);
|
||||
}
|
||||
|
||||
/* Wait for TC or ERRI interrupt. */
|
||||
if (irq_wait() < 0)
|
||||
return -1;
|
||||
stat = read32(reg->irpt);
|
||||
write32(reg->irpt, MMCHS_SD_STAT_DEB
|
||||
| MMCHS_SD_STAT_DCRC
|
||||
| MMCHS_SD_STAT_DTO
|
||||
| MMCHS_SD_STAT_TC);
|
||||
if (stat & MMCHS_SD_STAT_ERRI) {
|
||||
reset_mmchs_fsm(MMCHS_SD_SYSCTL_SRD);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a block from the card.
|
||||
* Return 0 on success, a negative integer on error.
|
||||
*/
|
||||
static int
|
||||
cim_read_block(uint32_t addr, uint32_t *data)
|
||||
{
|
||||
/* Send CMD17. */
|
||||
if (read_single_block(addr) < 0)
|
||||
return -1;
|
||||
/* Read from the host buffer. */
|
||||
return read_data(data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a block to the card.
|
||||
* Return 0 on success, a negative integer on error.
|
||||
*/
|
||||
static int
|
||||
cim_write_block(uint32_t addr, uint32_t *data)
|
||||
{
|
||||
/* Send CMD24. */
|
||||
if (write_block(addr) < 0)
|
||||
return -1;
|
||||
/* Write into the host buffer. */
|
||||
if (write_data(data) < 0)
|
||||
return -1;
|
||||
/* CMD13. Check the result of the write operation. */
|
||||
return send_status();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Interface to the MINIX block device driver.
|
||||
*/
|
||||
static int
|
||||
emmc_host_set_instance(struct mmc_host *host, int instance)
|
||||
{
|
||||
if (instance != 0)
|
||||
return EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the driver and kernel structures.
|
||||
* Return 0 on success, a negative integer on error.
|
||||
*/
|
||||
static int
|
||||
minix_init(void)
|
||||
{
|
||||
struct minix_mem_range mr;
|
||||
uint32_t v_base;
|
||||
|
||||
mr.mr_base = BCM2835_MMC0_BASE_ADDR;
|
||||
mr.mr_limit = BCM2835_MMC0_BASE_ADDR + BCM2835_MMC0_SIZE - 1;
|
||||
if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != OK)
|
||||
return -1;
|
||||
|
||||
/* Map the MMC1 physical base address to a virtual address. */
|
||||
v_base = (uint32_t)vm_map_phys(SELF, (void *)mr.mr_base,
|
||||
BCM2835_MMC0_SIZE);
|
||||
if (v_base == (uint32_t)MAP_FAILED)
|
||||
return -1;
|
||||
|
||||
/* Set the registers virtual addresses. */
|
||||
reg = ®s_v0;
|
||||
reg->blkscnt += v_base;
|
||||
reg->arg1 += v_base;
|
||||
reg->cmdtm += v_base;
|
||||
reg->resp0 += v_base;
|
||||
reg->resp1 += v_base;
|
||||
reg->resp2 += v_base;
|
||||
reg->resp3 += v_base;
|
||||
reg->data += v_base;
|
||||
reg->status += v_base;
|
||||
reg->control0 += v_base;
|
||||
reg->control1 += v_base;
|
||||
reg->irpt += v_base;
|
||||
reg->irpt_mask += v_base;
|
||||
reg->irpt_en += v_base;
|
||||
reg->control2 += v_base;
|
||||
reg->slotisr_var += v_base;
|
||||
|
||||
/* Register the MMC1 interrupt number. */
|
||||
if (sys_irqsetpolicy(BCM2835_MMCSD1INT, 0, &hook_id) != OK) {
|
||||
log_warn(&log, "can't set irq\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure the Control Module registers CONF_GPMC_AD4-7.
|
||||
* Multiplex pins GPMC_AD4-7 to signals MMC1_DAT4-7 (Mode 1).
|
||||
* Return 0 on success, a negative integer on error.
|
||||
*/
|
||||
static int
|
||||
conf_gpmc_ad(void)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i=4; i<8; i++) {
|
||||
if (sys_padconf(CONF_GPMC_AD(i), CONF_GPMC_AD_MASK,
|
||||
CONF_GPMC_AD_VAL) != OK)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Interface to the MINIX block device driver.
|
||||
* Host controller initialization.
|
||||
* Return 0 on success, a negative integer on error.
|
||||
*/
|
||||
static int
|
||||
emmc_host_init(struct mmc_host *host)
|
||||
{
|
||||
/* Initialize the driver and kernel structures. */
|
||||
if (minix_init() < 0)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Multiplex pins GPMC_AD4-7 to signals MMC1_DAT4-7 (Mode 1), in order
|
||||
* to allow the use of 8-bit mode.
|
||||
* U-Boot multiplexes only pins GPMC_AD0-3 to signals MMC1_DAT0-3.
|
||||
*/
|
||||
if (conf_gpmc_ad() < 0)
|
||||
bus_width = EXT_CSD_BUS_WIDTH_4;
|
||||
else
|
||||
bus_width = EXT_CSD_BUS_WIDTH_8;
|
||||
|
||||
set32(reg->control1, MMCHS_SD_SYSCTL_SRA,
|
||||
MMCHS_SD_SYSCTL_SRA);
|
||||
|
||||
/* Set the bus clock frequency to FOD (400kHz). */
|
||||
set32(reg->control1, MMCHS_SD_SYSCTL_CLKD,
|
||||
MMCHS_SD_SYSCTL_CLKD_400KHZ << 6);
|
||||
|
||||
/* Set data and busy time-out: ~2,6s @ 400kHz.*/
|
||||
set32(reg->control1, MMCHS_SD_SYSCTL_DTO, MMCHS_SD_SYSCTL_DTO_2POW20);
|
||||
|
||||
/* Enable the internal clock. */
|
||||
set32(reg->control1, MMCHS_SD_SYSCTL_ICE, MMCHS_SD_SYSCTL_ICE_EN);
|
||||
if (spin_until_set(reg->control1, MMCHS_SD_SYSCTL_ICS)
|
||||
== MMCHS_SD_SYSCTL_ICS_UNSTABLE) {
|
||||
log_warn(&log, "clock is unstable\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Enable the bus clock. */
|
||||
set32(reg->control1, MMCHS_SD_SYSCTL_CEN, MMCHS_SD_SYSCTL_CEN_EN);
|
||||
|
||||
/* The driver reads and writes single 512B blocks. */
|
||||
set32(reg->blkscnt, MMCHS_SD_BLK_BLEN, SEC_SIZE);
|
||||
|
||||
/* Enable interrupt status and requests. */
|
||||
write32(reg->irpt_mask, MMCHS_SD_IE_ERROR_MASK
|
||||
| MMCHS_SD_IE_BRR_ENABLE_ENABLE
|
||||
| MMCHS_SD_IE_BWR_ENABLE_ENABLE
|
||||
| MMCHS_SD_IE_TC_ENABLE_ENABLE
|
||||
| MMCHS_SD_IE_CC_ENABLE_ENABLE);
|
||||
write32(reg->irpt_en, MMCHS_SD_IE_ERROR_MASK
|
||||
| MMCHS_SD_IE_BRR_ENABLE_ENABLE
|
||||
| MMCHS_SD_IE_BWR_ENABLE_ENABLE
|
||||
| MMCHS_SD_IE_TC_ENABLE_ENABLE
|
||||
| MMCHS_SD_IE_CC_ENABLE_ENABLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Interface to the MINIX block device driver.
|
||||
* Unused, but declared in mmchost.h.
|
||||
*/
|
||||
#if 0
|
||||
static int
|
||||
emmc_host_reset(struct mmc_host *host)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Interface to the MINIX block device driver.
|
||||
* Card detection.
|
||||
*/
|
||||
static int
|
||||
emmc_card_detect(struct sd_slot *slot)
|
||||
{
|
||||
/* The card is detected during card initialization. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Interface to the MINIX block device driver.
|
||||
* Card initialization. Also, finish the MMCHS initialization.
|
||||
* Return NULL on error.
|
||||
*/
|
||||
static struct sd_card *
|
||||
emmc_card_initialize(struct sd_slot *slot)
|
||||
{
|
||||
uint32_t clkd;
|
||||
|
||||
/* CMD0 */
|
||||
if (go_idle_state() < 0)
|
||||
return NULL;
|
||||
|
||||
/* CMD1 */
|
||||
if (repeat_send_op_cond() < 0)
|
||||
return NULL;
|
||||
|
||||
/* CMD2. The driver has no use for the CID. */
|
||||
if (all_send_cid() < 0)
|
||||
return NULL;
|
||||
|
||||
/* CMD3 */
|
||||
if (set_relative_addr() < 0)
|
||||
return NULL;
|
||||
|
||||
/* CMD9 */
|
||||
if (send_csd() < 0)
|
||||
return NULL;
|
||||
card_csd[0] = read32(reg->resp0);
|
||||
card_csd[1] = read32(reg->resp1);
|
||||
card_csd[2] = read32(reg->resp2);
|
||||
card_csd[3] = read32(reg->resp3);
|
||||
|
||||
/* Card capacity for cards up to 2GB of density. */
|
||||
card_size = (uint64_t)MMC_CSD_CAPACITY(card_csd)
|
||||
<< MMC_CSD_READ_BL_LEN(card_csd);
|
||||
|
||||
card_write_protect = (SD_CSD_PERM_WRITE_PROTECT(card_csd)
|
||||
| SD_CSD_TMP_WRITE_PROTECT(card_csd));
|
||||
if (card_write_protect)
|
||||
log_info(&log, "the eMMC is write protected\n");
|
||||
|
||||
/* CMD7 */
|
||||
if (select_card() < 0)
|
||||
return NULL;
|
||||
|
||||
/* Receive the Extended CSD register. */
|
||||
if (read_data((uint32_t *)card_ext_csd) < 0)
|
||||
return NULL;
|
||||
|
||||
/* Card capacity for densities greater than 2GB. */
|
||||
if (MMC_EXT_CSD_SEC_COUNT > 0)
|
||||
card_size = (uint64_t)MMC_EXT_CSD_SEC_COUNT * SEC_SIZE;
|
||||
|
||||
/* CMD6. Switch to high-speed mode: EXT_CSD[185] HS_TIMING = 1. */
|
||||
if (mmc_switch(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, 1) < 0)
|
||||
return NULL;
|
||||
/* Wait for the (optional) busy signal. */
|
||||
if (read_busy() < 0)
|
||||
return NULL;
|
||||
/* CMD13. Check the result of the SWITCH operation. */
|
||||
if (send_status() < 0)
|
||||
return NULL;
|
||||
|
||||
/* Change the bus clock frequency. */
|
||||
if (MMC_EXT_CSD_CARD_TYPE & MMC_EXT_CSD_CARD_TYPE_HS_MMC_52MHZ)
|
||||
clkd = MMCHS_SD_SYSCTL_CLKD_52MHZ; /* 48 MHz */
|
||||
else
|
||||
clkd = MMCHS_SD_SYSCTL_CLKD_26MHZ; /* 24 MHz */
|
||||
if (set_bus_clkd(clkd) < 0)
|
||||
return NULL;
|
||||
|
||||
/* Set data and busy time-out: ~ 2,8s @ 48MHz.*/
|
||||
set32(reg->control1, MMCHS_SD_SYSCTL_DTO, MMCHS_SD_SYSCTL_DTO_2POW27);
|
||||
|
||||
/* CMD6. Set data bus width. */
|
||||
if (mmc_switch(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_BUS_WIDTH,
|
||||
bus_width) < 0)
|
||||
return NULL;
|
||||
/* Wait for the (optional) busy signal. */
|
||||
if (read_busy() < 0)
|
||||
return NULL;
|
||||
/* CMD13. Check the result of the SWITCH operation. */
|
||||
if (send_status() < 0)
|
||||
return NULL;
|
||||
|
||||
set32(reg->control0, MMCHS_SD_HCTL_DTW,
|
||||
MMCHS_SD_HCTL_DTW_1BIT);
|
||||
|
||||
/* CMD16. Set block length to sector size (512B). */
|
||||
if (set_blocklen() < 0)
|
||||
return NULL;
|
||||
|
||||
/* Initialize the block device driver structures. */
|
||||
slot->card.blk_size = SEC_SIZE;
|
||||
slot->card.blk_count = card_size / SEC_SIZE;
|
||||
slot->card.state = SD_MODE_DATA_TRANSFER_MODE;
|
||||
slot->card.open_ct = 0;
|
||||
memset(slot->card.part, 0, sizeof(slot->card.part));
|
||||
memset(slot->card.subpart, 0, sizeof(slot->card.subpart));
|
||||
slot->card.part[0].dv_size = card_size;
|
||||
|
||||
return &(slot->card);
|
||||
}
|
||||
|
||||
/*
|
||||
* Interface to the MINIX block device driver.
|
||||
* Card release.
|
||||
*/
|
||||
static int
|
||||
emmc_card_release(struct sd_card *card)
|
||||
{
|
||||
/* Decrements the "in-use count." */
|
||||
card->open_ct--;
|
||||
|
||||
/*
|
||||
* The block special file is closed, but the driver does not need to
|
||||
* "release" the eMMC, even if the driver is unloaded.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Interface to the MINIX block device driver.
|
||||
* Handle unexpected interrupts.
|
||||
*/
|
||||
static void
|
||||
emmc_hw_intr(unsigned int irqs)
|
||||
{
|
||||
log_warn(&log, "register SD_STAT == 0x%08x\n", reg->irpt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Interface to the MINIX block device driver.
|
||||
* Read/write blocks.
|
||||
* Return the number of blocks read/written, or a negative integer on error.
|
||||
*/
|
||||
static int
|
||||
emmc_read_write(int (*cim_read_write)(uint32_t, uint32_t *),
|
||||
uint32_t blknr, uint32_t count, unsigned char *buf)
|
||||
{
|
||||
int blocks, r;
|
||||
uint32_t addr;
|
||||
|
||||
blocks = 0; /* count of blocks read/written. */
|
||||
r = 0;
|
||||
while ((count > 0) && (r == 0)) {
|
||||
/*
|
||||
* Data address for media =< 2GB is byte address, and data
|
||||
* address for media > 2GB is sector address.
|
||||
*/
|
||||
if (card_size <= (2U << 30))
|
||||
addr = blknr * SEC_SIZE;
|
||||
else
|
||||
addr = blknr;
|
||||
|
||||
r = (*cim_read_write)(addr, (uint32_t *)buf);
|
||||
if (r == 0) {
|
||||
blknr++;
|
||||
count--;
|
||||
buf += SEC_SIZE;
|
||||
blocks++;
|
||||
}
|
||||
else if (blocks == 0)
|
||||
blocks = r;
|
||||
}
|
||||
|
||||
return blocks;
|
||||
}
|
||||
|
||||
/*
|
||||
* Interface to the MINIX block device driver.
|
||||
* Read blocks.
|
||||
*/
|
||||
static int
|
||||
emmc_read(struct sd_card *card,
|
||||
uint32_t blknr, uint32_t count, unsigned char *buf)
|
||||
{
|
||||
return emmc_read_write(&cim_read_block, blknr, count, buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Interface to the MINIX block device driver.
|
||||
* Write blocks.
|
||||
*/
|
||||
static int
|
||||
emmc_write(struct sd_card *card,
|
||||
uint32_t blknr, uint32_t count, unsigned char *buf)
|
||||
{
|
||||
if (card_write_protect)
|
||||
return -1; /* The card is write protected. */
|
||||
return emmc_read_write(&cim_write_block, blknr, count, buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Interface to the MINIX block device driver.
|
||||
* Driver interface registration.
|
||||
*/
|
||||
void
|
||||
host_initialize_host_structure_mmchs(struct mmc_host *host)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
/* Register the driver interface at the block device driver. */
|
||||
host->host_set_instance = &emmc_host_set_instance;
|
||||
host->host_init = &emmc_host_init;
|
||||
host->host_reset = NULL;
|
||||
host->card_detect = &emmc_card_detect;
|
||||
host->card_initialize = &emmc_card_initialize;
|
||||
host->card_release = &emmc_card_release;
|
||||
host->hw_intr = &emmc_hw_intr;
|
||||
host->read = &emmc_read;
|
||||
host->write = &emmc_write;
|
||||
for (i=0; i<MAX_SD_SLOTS; i++) {
|
||||
host->slot[i].host = host;
|
||||
host->slot[i].card.state = SD_MODE_UNINITIALIZED;
|
||||
host->slot[i].card.slot = &host->slot[i];
|
||||
}
|
||||
|
||||
/* Customize name for logs */
|
||||
log.name = "emmc_rpi";
|
||||
}
|
||||
|
||||
/*
|
||||
* Interface to the MINIX block device driver.
|
||||
* Unused, but declared in mmchost.h.
|
||||
*/
|
||||
void
|
||||
host_initialize_host_structure_dummy(struct mmc_host *host)
|
||||
{
|
||||
}
|
||||
@@ -1,12 +1,5 @@
|
||||
struct omap_mmchs_registers;
|
||||
|
||||
struct omap_mmchs {
|
||||
vir_bytes io_base;
|
||||
vir_bytes io_size;
|
||||
phys_bytes hw_base;/* HW address */
|
||||
int irq_nr;
|
||||
struct omap_mmchs_registers * regs;
|
||||
};
|
||||
#ifndef _MMC_OMAP_H_
|
||||
#define _MMC_OMAP_H_
|
||||
|
||||
struct omap_mmchs_registers {
|
||||
/* SD system configuration */
|
||||
@@ -51,8 +44,16 @@ struct omap_mmchs_registers {
|
||||
vir_bytes CUR_CAPA;
|
||||
};
|
||||
|
||||
struct omap_mmchs {
|
||||
vir_bytes io_base;
|
||||
vir_bytes io_size;
|
||||
phys_bytes hw_base;/* HW address */
|
||||
int irq_nr;
|
||||
struct omap_mmchs_registers * regs;
|
||||
};
|
||||
|
||||
/* version used on the AM335x */
|
||||
static struct omap_mmchs_registers regs_v1 = {
|
||||
struct omap_mmchs_registers regs_v1 = {
|
||||
.SYSCONFIG = 0x110,
|
||||
.SYSSTATUS = 0x114,
|
||||
.CON = 0x12c,
|
||||
@@ -77,7 +78,7 @@ static struct omap_mmchs_registers regs_v1 = {
|
||||
|
||||
/* version used on the DM37xx */
|
||||
/* DM and AM have the same register but shifted by 0x100. */
|
||||
static struct omap_mmchs_registers regs_v0 = {
|
||||
struct omap_mmchs_registers regs_v0 = {
|
||||
.SYSCONFIG = 0x010,
|
||||
.SYSSTATUS = 0x014,
|
||||
.CON = 0x02c,
|
||||
@@ -100,7 +101,6 @@ static struct omap_mmchs_registers regs_v0 = {
|
||||
.CUR_CAPA = 0x148,
|
||||
};
|
||||
|
||||
|
||||
#define MMCHS_SD_SYSCONFIG_AUTOIDLE (0x1 << 0) /* Internal clock gating strategy */
|
||||
#define MMCHS_SD_SYSCONFIG_AUTOIDLE_DIS (0x0 << 0) /* Clocks are free running */
|
||||
#define MMCHS_SD_SYSCONFIG_AUTOIDLE_EN (0x1 << 0) /* Automatic clock gating strategy */
|
||||
@@ -273,3 +273,4 @@ static struct omap_mmchs_registers regs_v0 = {
|
||||
#define MMCHS_SD_CAPA_VS30 (0x01 << 25 ) /* 3.0 volt */
|
||||
#define MMCHS_SD_CAPA_VS33 (0x01 << 24 ) /* 3.3 volt */
|
||||
|
||||
#endif /* _MMC_OMAP_H_*/
|
||||
246
minix/drivers/storage/mmc/mmc_rpi.h
Normal file
246
minix/drivers/storage/mmc/mmc_rpi.h
Normal file
@@ -0,0 +1,246 @@
|
||||
#ifndef _MMC_RPI_H_
|
||||
#define _MMC_RPI_H_
|
||||
|
||||
#define RW
|
||||
#define R
|
||||
|
||||
struct rpi_mmchs_registers {
|
||||
RW vir_bytes blkscnt;
|
||||
RW vir_bytes arg1;
|
||||
RW vir_bytes cmdtm;
|
||||
R vir_bytes resp0;
|
||||
R vir_bytes resp1;
|
||||
R vir_bytes resp2;
|
||||
R vir_bytes resp3;
|
||||
RW vir_bytes data;
|
||||
R vir_bytes status;
|
||||
RW vir_bytes control0;
|
||||
RW vir_bytes control1;
|
||||
RW vir_bytes irpt;
|
||||
RW vir_bytes irpt_mask;
|
||||
RW vir_bytes irpt_en;
|
||||
RW vir_bytes control2;
|
||||
RW vir_bytes slotisr_var;
|
||||
};
|
||||
|
||||
struct rpi_mmchs {
|
||||
vir_bytes io_base;
|
||||
vir_bytes io_size;
|
||||
phys_bytes hw_base;/* HW address */
|
||||
int irq_nr;
|
||||
struct rpi_mmchs_registers * regs;
|
||||
};
|
||||
|
||||
struct rpi_mmchs_registers regs_v0 = {
|
||||
.blkscnt = 0x4,
|
||||
.arg1 = 0x8,
|
||||
.cmdtm = 0xc,
|
||||
.resp0 = 0x10,
|
||||
.resp1 = 0x14,
|
||||
.resp2 = 0x18,
|
||||
.resp3 = 0x1c,
|
||||
.data = 0x20,
|
||||
.status = 0x24,
|
||||
.control0 = 0x28,
|
||||
.control1 = 0x2c,
|
||||
.irpt = 0x30,
|
||||
.irpt_mask = 0x34,
|
||||
.irpt_en = 0x38,
|
||||
.control2 = 0x3c,
|
||||
.slotisr_var = 0xfc
|
||||
};
|
||||
#define MMCHS_SD_SYSCONFIG_AUTOIDLE (0x1 << 0) /* Internal clock gating strategy */
|
||||
#define MMCHS_SD_SYSCONFIG_AUTOIDLE_DIS (0x0 << 0) /* Clocks are free running */
|
||||
#define MMCHS_SD_SYSCONFIG_AUTOIDLE_EN (0x1 << 0) /* Automatic clock gating strategy */
|
||||
#define MMCHS_SD_SYSCONFIG_SOFTRESET (0x1 << 1) /* Software reset bit writing */
|
||||
#define MMCHS_SD_SYSCONFIG_ENAWAKEUP (0x1 << 2) /* Wake-up feature control */
|
||||
#define MMCHS_SD_SYSCONFIG_ENAWAKEUP_DIS (0x0 << 2) /* Disable wake-up capability */
|
||||
#define MMCHS_SD_SYSCONFIG_ENAWAKEUP_EN (0x1 << 2) /* Enable wake-up capability */
|
||||
#define MMCHS_SD_SYSCONFIG_SIDLEMODE (0x3 << 3) /* Power management */
|
||||
#define MMCHS_SD_SYSCONFIG_SIDLEMODE_UNCONDITIONAL (0x0 << 3) /* Go into idle mode unconditionally upon request */
|
||||
#define MMCHS_SD_SYSCONFIG_SIDLEMODE_IGNORE (0x1 << 3) /* Ignore ILDE requests */
|
||||
#define MMCHS_SD_SYSCONFIG_SIDLEMODE_IDLE (0x2 << 3) /* Acknowledge IDLE request switch to wake-up mode */
|
||||
#define MMCHS_SD_SYSCONFIG_SIDLEMODE_SMART_IDLE (0x3 << 3) /* Smart-idle */
|
||||
#define MMCHS_SD_SYSCONFIG_CLOCKACTIVITY (0x3 << 8) /* Clock activity during wake-up */
|
||||
#define MMCHS_SD_SYSCONFIG_CLOCKACTIVITY_OFF (0x0 << 8) /* Interface and functional clock can be switched off */
|
||||
#define MMCHS_SD_SYSCONFIG_CLOCKACTIVITY_IF (0x1 << 8) /* Only Interface clock (functional can be switched off*/
|
||||
#define MMCHS_SD_SYSCONFIG_CLOCKACTIVITY_FUNC (0x2 << 8) /* Only Functional clock (interface clock can be switched off) */
|
||||
#define MMCHS_SD_SYSCONFIG_CLOCKACTIVITY_BOOTH (0x3 << 8) /* Booth the interface and functional clock are maintained */
|
||||
#define MMCHS_SD_SYSCONFIG_STANDBYMODE (0x3 << 12) /* Configuration for standby */
|
||||
#define MMCHS_SD_SYSCONFIG_STANDBYMODE_FORCE_STANDBY (0x0 << 12) /* Force standby mode upon idle request*/
|
||||
#define MMCHS_SD_SYSCONFIG_STANDBYMODE_NO_STANDBY (0x1 << 12) /* Never go into standby mode */
|
||||
#define MMCHS_SD_SYSCONFIG_STANDBYMODE_WAKEUP_INTERNAL (0x2 << 12) /* Go into wake-up mode based on internal knowledge */
|
||||
#define MMCHS_SD_SYSCONFIG_STANDBYMODE_WAKEUP_SMART (0x3 << 12) /* Go info wake-up mode when possible */
|
||||
|
||||
#define MMCHS_SD_SYSSTATUS_RESETDONE 0x01
|
||||
|
||||
#define MMCHS_SD_CON_DW8 (0x1 << 5) /* 8-bit mode MMC select , For SD clear this bit */
|
||||
#define MMCHS_SD_CON_DW8_1BIT (0x0 << 5) /* 1 or 4 bits data width configuration(also set SD_HCTL) */
|
||||
#define MMCHS_SD_CON_DW8_8BITS (0x1 << 5) /* 8 bits data width configuration */
|
||||
#define MMCHS_SD_CON_INIT (0x1 << 1) /* Send initialization stream (all cards) */
|
||||
#define MMCHS_SD_CON_INIT_NOINIT (0x0 << 1) /* Do nothing */
|
||||
#define MMCHS_SD_CON_INIT_INIT (0x1 << 1) /* Send initialization stream */
|
||||
#define MMCHS_SD_CON_OD (0x1 << 0) /* Card open drain mode (MMC cards only) */
|
||||
#define MMCHS_SD_CON_OD_PP (0x0 << 0) /* No open drain (push-pull). */
|
||||
#define MMCHS_SD_CON_OD_OD (0x1 << 0) /* Open drain */
|
||||
|
||||
#define MMCHS_SD_BLK_NBLK (0xffffu << 16) /* Block count for the current transfer */
|
||||
#define MMCHS_SD_BLK_BLEN (0xfff << 0) /* Transfer block size */
|
||||
#define MMCHS_SD_BLK_BLEN_NOTRANSFER (0x0 << 0) /* No transfer */
|
||||
|
||||
#define MMCHS_SD_CMD_INDX (0x3f << 24) /* Command index */
|
||||
#define MMCHS_SD_CMD_INDX_CMD(x) (x << 24) /* MMC command index binary encoded values from 0 to 63 */
|
||||
|
||||
#define MMCHS_SD_ARG_MASK (0xffffffffu) /* Mask everything */
|
||||
#define MMCHS_SD_ARG_CMD8_VHS (0x1 << (16 - 8)) /* Voltage between 2.7 and 3.6 v*/
|
||||
#define MMCHS_SD_ARG_CMD8_CHECK_PATTERN (0xaa <<(8 - 8)) /* 10101010b pattern */
|
||||
|
||||
#define MMCHS_SD_CMD_TYPE (0x3 << 22) /* Command type. */
|
||||
#define MMCHS_SD_CMD_TYPE_OTHER (0x0 << 22) /* Other type of commands (like go idle) */
|
||||
#define MMCHS_SD_CMD_TYPE_BUS_SUSPEND (0x1 << 22) /* Upon CMD52 "Bus Suspend" operation */
|
||||
#define MMCHS_SD_CMD_TYPE_FUNCTION_SELECT (0x2 << 22) /* Upon CMD52 "Function Select" operation */
|
||||
#define MMCHS_SD_CMD_TYPE_IOABORT (0x3 << 22) /* Upon CMD12 and CMD21 "I/O Abort */
|
||||
#define MMCHS_SD_CMD_DP (0x1 << 21) /* Data present select */
|
||||
#define MMCHS_SD_CMD_DP_DATA (0x1 << 21) /* Additional data is present on the data lines */
|
||||
#define MMCHS_SD_CMD_DP_NODATA (0x0 << 21) /* No additional data is present on the data lines */
|
||||
#define MMCHS_SD_CMD_CICE (0x1 << 20) /* Command index response check enable */
|
||||
#define MMCHS_SD_CMD_CICE_ENABLE (0x1 << 20) /* Enable index check response */
|
||||
#define MMCHS_SD_CMD_CICE_DISABLE (0x0 << 20) /* Disable index check response */
|
||||
#define MMCHS_SD_CMD_CCCE (0x1 << 19) /* Command CRC7 Check enable on responses*/
|
||||
#define MMCHS_SD_CMD_CCCE_ENABLE (0x1 << 19) /* Enable CRC7 Check on response */
|
||||
#define MMCHS_SD_CMD_CCCE_DISABLE (0x0 << 19) /* Disable CRC7 Check on response */
|
||||
#define MMCHS_SD_CMD_RSP_TYPE (0x3 << 16) /* Response type */
|
||||
#define MMCHS_SD_CMD_RSP_TYPE_NO_RESP (0x0 << 16) /* No response */
|
||||
#define MMCHS_SD_CMD_RSP_TYPE_136B (0x1 << 16) /* Response length 136 bits */
|
||||
#define MMCHS_SD_CMD_RSP_TYPE_48B (0x2 << 16) /* Response length 48 bits */
|
||||
#define MMCHS_SD_CMD_RSP_TYPE_48B_BUSY (0x3 << 16) /* Response length 48 bits with busy after response */
|
||||
#define MMCHS_SD_CMD_MSBS (0x1 << 5) /* Multi/Single block select */
|
||||
#define MMCHS_SD_CMD_MSBS_SINGLE (0x0 << 5) /* Single block mode */
|
||||
#define MMCHS_SD_CMD_MSBS_MULTI (0x0 << 5) /* Multi block mode */
|
||||
#define MMCHS_SD_CMD_DDIR (0x1 << 4) /* Data transfer direction */
|
||||
#define MMCHS_SD_CMD_DDIR_READ (0x1 << 4) /* Data read (card to host) */
|
||||
#define MMCHS_SD_CMD_DDIR_WRITE (0x0 << 4) /* Data write (host to card) */
|
||||
#define MMCHS_SD_CMD_ACEN (0x1 << 2) /* Auto CMD12 Enable */
|
||||
#define MMCHS_SD_CMD_ACEN_DIS (0x0 << 2) /* Auto CMD12 Disable */
|
||||
#define MMCHS_SD_CMD_ACEN_EN (0x1 << 2) /* Auto CMD12 Enable */
|
||||
#define MMCHS_SD_CMD_BCE (0x1 << 1) /* Block Count Enable(for multi block transfer) */
|
||||
#define MMCHS_SD_CMD_BCE_DIS (0x0 << 1) /* Disabled block count for infinite transfer*/
|
||||
#define MMCHS_SD_CMD_BCE_EN (0x1 << 1) /* Enabled for multi block transfer with know amount of blocks */
|
||||
#define MMCHS_SD_CMD_DE (0x1 << 0) /* DMA enable */
|
||||
#define MMCHS_SD_CMD_DE_DIS (0x0 << 0) /* Disable DMA */
|
||||
#define MMCHS_SD_CMD_DE_EN (0x1 << 0) /* Enable DMA */
|
||||
#define MMCHS_SD_CMD_MASK ~(0x1 << 30 | 0x1 << 31 | 0x1 << 18 | 0x1 <<3) /* bits 30 , 31 and 18 are reserved */
|
||||
|
||||
#define MMCHS_SD_PSTATE_CI (0x1 << 16) /* Card Inserted */
|
||||
#define MMCHS_SD_PSTATE_CI_INSERTED (0x1 << 16) /* Card Inserted is inserted*/
|
||||
#define MMCHS_SD_PSTATE_BRE (0x1 << 11) /* Buffer read enable */
|
||||
#define MMCHS_SD_PSTATE_BRE_DIS (0x0 << 11) /* Read BLEN bytes disabled*/
|
||||
#define MMCHS_SD_PSTATE_BRE_EN (0x1 << 11) /* Read BLEN bytes enabled*/
|
||||
#define MMCHS_SD_PSTATE_BWE (0x1 << 10) /* Buffer Write enable */
|
||||
#define MMCHS_SD_PSTATE_BWE_DIS (0x0 << 10) /* There is no room left in the buffer to write BLEN bytes of data */
|
||||
#define MMCHS_SD_PSTATE_BWE_EN (0x1 << 10) /* There is enough space in the buffer to write BLEN bytes of data*/
|
||||
#define MMCHS_SD_PSTATE_DATI (0x1 << 1) /* Command inhibit (mmc_dat) */
|
||||
#define MMCHS_SD_PSTATE_CMDI (0x1 << 0) /* Command inhibit (mmc_cmd) */
|
||||
|
||||
#define MMCHS_SD_HCTL_DTW (0x1 << 1) /*Data transfer width.(must be set after a successful ACMD6) */
|
||||
#define MMCHS_SD_HCTL_DTW_1BIT (0x0 << 1) /*1 bit transfer with */
|
||||
#define MMCHS_SD_HCTL_DTW_4BIT (0x1 << 1) /*4 bit transfer with */
|
||||
#define MMCHS_SD_HCTL_SDBP (0x1 << 8) /*SD bus power */
|
||||
#define MMCHS_SD_HCTL_SDBP_OFF (0x0 << 8) /*SD Power off (start card detect?) */
|
||||
#define MMCHS_SD_HCTL_SDBP_ON (0x1 << 8) /*SD Power on (start card detect?) */
|
||||
#define MMCHS_SD_HCTL_SDVS (0x7 << 9) /*SD bus voltage select */
|
||||
#define MMCHS_SD_HCTL_SDVS_VS18 (0x5 << 9) /*1.8 V */
|
||||
#define MMCHS_SD_HCTL_SDVS_VS30 (0x6 << 9) /*3.0 V */
|
||||
#define MMCHS_SD_HCTL_SDVS_VS33 (0x7 << 9) /*3.3 V */
|
||||
#define MMCHS_SD_HCTL_IWE (0x1 << 24)/* wake-up event on SD interrupt */
|
||||
#define MMCHS_SD_HCTL_IWE_DIS (0x0 << 24)/* Disable wake-up on SD interrupt */
|
||||
#define MMCHS_SD_HCTL_IWE_EN (0x1 << 24)/* Enable wake-up on SD interrupt */
|
||||
|
||||
#define MMCHS_SD_SYSCTL_CLKD (0x3ff << 6) /* 10 bits clock frequency select */
|
||||
#define MMCHS_SD_SYSCTL_SRD (0x1 << 26) /* Soft reset for mmc_dat line */
|
||||
#define MMCHS_SD_SYSCTL_SRC (0x1 << 25) /* Soft reset for mmc_cmd line */
|
||||
#define MMCHS_SD_SYSCTL_SRA (0x1 << 24) /* Soft reset all (host controller) */
|
||||
|
||||
#define MMCHS_SD_SYSCTL_ICE (0x1 << 0) /* Internal clock enable register */
|
||||
#define MMCHS_SD_SYSCTL_ICE_DIS (0x0 << 0) /* Disable internal clock */
|
||||
#define MMCHS_SD_SYSCTL_ICE_EN (0x1 << 0) /* Enable internal clock */
|
||||
#define MMCHS_SD_SYSCTL_ICS (0x1 << 1) /* Internal clock stable register */
|
||||
#define MMCHS_SD_SYSCTL_ICS_UNSTABLE (0x0 << 1) /* Internal clock is unstable */
|
||||
#define MMCHS_SD_SYSCTL_ICS_STABLE (0x1 << 1) /* Internal clock is stable */
|
||||
#define MMCHS_SD_SYSCTL_CEN (0x1 << 2) /* Card lock enable provide clock to the card */
|
||||
#define MMCHS_SD_SYSCTL_CEN_DIS (0x0 << 2) /* Internal clock is unstable */
|
||||
#define MMCHS_SD_SYSCTL_CEN_EN (0x1 << 2) /* Internal clock is stable */
|
||||
|
||||
#define MMCHS_SD_SYSCTL_DTO (0xf << 16) /* Data timeout counter */
|
||||
#define MMCHS_SD_SYSCTL_DTO_2POW13 (0x0 << 16) /* TCF x 2^13 */
|
||||
#define MMCHS_SD_SYSCTL_DTO_2POW14 (0x1 << 16) /* TCF x 2^14 */
|
||||
#define MMCHS_SD_SYSCTL_DTO_2POW20 (0x7 << 16) /* TCF x 2^20 */
|
||||
#define MMCHS_SD_SYSCTL_DTO_2POW27 (0xe << 16) /* TCF x 2^27 */
|
||||
|
||||
#define MMCHS_SD_STAT_CERR (0x1 << 28) /* card error */
|
||||
#define MMCHS_SD_STAT_DEB (0x1 << 22) /* data end bit error */
|
||||
#define MMCHS_SD_STAT_DCRC (0x1 << 21) /* data CRC error */
|
||||
#define MMCHS_SD_STAT_DTO (0x1 << 20) /* data timeout error */
|
||||
#define MMCHS_SD_STAT_CIE (0x1 << 19) /* command index error */
|
||||
#define MMCHS_SD_STAT_CEB (0x1 << 18) /* command end bit error */
|
||||
#define MMCHS_SD_STAT_CCRC (0x1 << 17) /* command CRC error */
|
||||
#define MMCHS_SD_STAT_CTO (0x1 << 16) /* command timeout error */
|
||||
#define MMCHS_SD_STAT_DONE (0xffff0001u) /* send command done */
|
||||
#define MMCHS_SD_STAT_ERRI (0x01 << 15) /* Error interrupt */
|
||||
#define MMCHS_SD_STAT_ERROR_MASK (0xfe << 15 | 0x1 << 24)
|
||||
#define MMCHS_SD_STAT_BRR (0x1 << 5) /* Buffer Read ready */
|
||||
#define MMCHS_SD_STAT_BWR (0x1 << 4) /* Buffer Write ready */
|
||||
#define MMCHS_SD_STAT_CC (0x1 << 0) /* Command complete status */
|
||||
#define MMCHS_SD_STAT_CC_UNRAISED (0x0 << 0) /* Command not completed */
|
||||
#define MMCHS_SD_STAT_CC_RAISED (0x1 << 0) /* Command completed */
|
||||
#define MMCHS_SD_STAT_TC (0x1 << 1) /* Transfer complete status */
|
||||
#define MMCHS_SD_STAT_TC_UNRAISED (0x0 << 1) /* Transfer not completed */
|
||||
#define MMCHS_SD_STAT_TC_RAISED (0x1 << 1) /* Transfer completed */
|
||||
|
||||
#define MMCHS_SD_IE_ERROR_MASK (0xfe << 15 | 0x1 << 24)
|
||||
|
||||
#define MMCHS_SD_IE_CC_ENABLE (0x1 << 0) /* Command complete interrupt enable */
|
||||
#define MMCHS_SD_IE_CC_ENABLE_ENABLE (0x1 << 0) /* Command complete Interrupts are enabled */
|
||||
#define MMCHS_SD_IE_CC_ENABLE_CLEAR (0x1 << 0) /* Clearing is done by writing a 0x1 */
|
||||
|
||||
#define MMCHS_SD_IE_TC_ENABLE (0x1 << 1) /* Transfer complete interrupt enable */
|
||||
#define MMCHS_SD_IE_TC_ENABLE_ENABLE (0x1 << 1) /* Transfer complete Interrupts are enabled */
|
||||
#define MMCHS_SD_IE_TC_ENABLE_CLEAR (0x1 << 1) /* Clearing TC is done by writing a 0x1 */
|
||||
|
||||
#define MMCHS_SD_IE_BRR_ENABLE (0x1 << 5) /* Buffer read ready interrupt */
|
||||
#define MMCHS_SD_IE_BRR_ENABLE_DISABLE (0x0 << 5) /* Buffer read ready interrupt disable */
|
||||
#define MMCHS_SD_IE_BRR_ENABLE_ENABLE (0x1 << 5) /* Buffer read ready interrupt enable */
|
||||
#define MMCHS_SD_IE_BRR_ENABLE_CLEAR (0x1 << 5) /* Buffer read ready interrupt clear */
|
||||
|
||||
#define MMCHS_SD_IE_BWR_ENABLE (0x1 << 4) /* Buffer write ready interrupt */
|
||||
#define MMCHS_SD_IE_BWR_ENABLE_DISABLE (0x0 << 4) /* Buffer write ready interrupt disable */
|
||||
#define MMCHS_SD_IE_BWR_ENABLE_ENABLE (0x1 << 4) /* Buffer write ready interrupt enable */
|
||||
#define MMCHS_SD_IE_BWR_ENABLE_CLEAR (0x1 << 4) /* Buffer write ready interrupt clear */
|
||||
|
||||
#define MMCHS_SD_CAPA_VS_MASK (0x7 << 24 ) /* voltage mask */
|
||||
#define MMCHS_SD_CAPA_VS18 (0x01 << 26 ) /* 1.8 volt */
|
||||
#define MMCHS_SD_CAPA_VS30 (0x01 << 25 ) /* 3.0 volt */
|
||||
#define MMCHS_SD_CAPA_VS33 (0x01 << 24 ) /* 3.3 volt */
|
||||
|
||||
#define IS_APP_CMD 0x80000000
|
||||
#define ACMD(a) (a | IS_APP_CMD)
|
||||
#define SET_BUS_WIDTH (6 | IS_APP_CMD)
|
||||
#define SD_STATUS (13 | IS_APP_CMD)
|
||||
#define SEND_NUM_WR_BLOCKS (22 | IS_APP_CMD)
|
||||
#define SET_WR_BLK_ERASE_COUNT (23 | IS_APP_CMD)
|
||||
#define SD_SEND_OP_COND (41 | IS_APP_CMD)
|
||||
#define SET_CLR_CARD_DETECT (42 | IS_APP_CMD)
|
||||
#define SEND_SCR (51 | IS_APP_CMD)
|
||||
|
||||
#define SD_GET_CLOCK_DIVIDER_FAIL 0xffffffff
|
||||
|
||||
#define MIN_FREQ 400000
|
||||
#define BCM2835_EMMC_WRITE_DELAY (((2 * 1000000) / MIN_FREQ) + 1)
|
||||
|
||||
// Enable 4-bit support
|
||||
#define SD_4BIT_DATA
|
||||
|
||||
// Enable SDXC maximum performance mode
|
||||
#define SDXC_MAXIMUM_PERFORMANCE
|
||||
|
||||
#endif /* _MMC_RPI_H_*/
|
||||
@@ -22,11 +22,11 @@
|
||||
/* local headers */
|
||||
#include "mmchost.h"
|
||||
|
||||
/* used for logging */
|
||||
static struct log log = {
|
||||
.name = "mmc_block",
|
||||
/* Initialize the log system. */
|
||||
struct log log = {
|
||||
.name = "mmc",
|
||||
.log_level = LEVEL_INFO,
|
||||
.log_func = default_log
|
||||
.log_func = default_log,
|
||||
};
|
||||
|
||||
/* holding the current host controller */
|
||||
@@ -114,10 +114,10 @@ apply_env()
|
||||
} else {
|
||||
log_warn(&log, "Unknown driver %s\n", driver);
|
||||
}
|
||||
/* Initialize the verbosity level. */
|
||||
v = 0;
|
||||
/* Initialize the verbosity level. */
|
||||
if (env_parse("log_level", "d", 0, &v, LEVEL_NONE,
|
||||
LEVEL_TRACE) == EP_SET) {
|
||||
LEVEL_TRACE + 1) == EP_SET) {
|
||||
set_log_level(v);
|
||||
}
|
||||
|
||||
@@ -641,14 +641,11 @@ get_slot(devminor_t minor)
|
||||
static void
|
||||
set_log_level(int level)
|
||||
{
|
||||
if (level < 0 || level >= 4) {
|
||||
if ((level < LEVEL_NONE) || (level > (LEVEL_TRACE + 1))) {
|
||||
return;
|
||||
}
|
||||
log_info(&log, "Setting verbosity level to %d\n", level);
|
||||
log.log_level = level;
|
||||
if (host.set_log_level) {
|
||||
host.set_log_level(level);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
#define SUBPARTITION_PER_PARTITION 4 /* 4 sub partitions per partition */
|
||||
#define PARTITONS_PER_DISK 4 /* 4 partitions per disk */
|
||||
#define MINOR_PER_DISK 1 /* one additional minor to point to */
|
||||
@@ -30,6 +29,7 @@
|
||||
|
||||
#define MAX_SD_SLOTS 4
|
||||
|
||||
extern struct log log;
|
||||
struct mmc_host;
|
||||
|
||||
//TODO Add more modes like INACTIVE STATE and such
|
||||
@@ -110,8 +110,6 @@ struct mmc_host
|
||||
int (*host_set_instance) (struct mmc_host * host, int instance);
|
||||
/* MMC host configuration */
|
||||
int (*host_init) (struct mmc_host * host);
|
||||
/* Set log level */
|
||||
void (*set_log_level) (int level);
|
||||
/* Host controller reset */
|
||||
int (*host_reset) (struct mmc_host * host);
|
||||
/* Card detection (binary yes/no) */
|
||||
|
||||
@@ -14,15 +14,6 @@
|
||||
#include "mmchost.h"
|
||||
#include "sdmmcreg.h"
|
||||
|
||||
/*
|
||||
* Define a structure to be used for logging
|
||||
*/
|
||||
static struct log log = {
|
||||
.name = "mmc_host_memory",
|
||||
.log_level = LEVEL_INFO,
|
||||
.log_func = default_log
|
||||
};
|
||||
|
||||
/* This is currently a dummy driver using an in-memory structure */
|
||||
#define DUMMY_SIZE_IN_BLOCKS 0xFFFFFu
|
||||
#define DUMMY_BLOCK_SIZE 512
|
||||
@@ -70,14 +61,6 @@ dummy_host_init(struct mmc_host *host)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
dummy_set_log_level(int level)
|
||||
{
|
||||
if (level >= 0 && level <= 4) {
|
||||
log.log_level = level;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
dummy_host_set_instance(struct mmc_host *host, int instance)
|
||||
{
|
||||
@@ -152,7 +135,6 @@ host_initialize_host_structure_dummy(struct mmc_host *host)
|
||||
|
||||
host->host_set_instance = dummy_host_set_instance;
|
||||
host->host_init = dummy_host_init;
|
||||
host->set_log_level = dummy_set_log_level;
|
||||
host->host_reset = dummy_host_reset;
|
||||
host->card_detect = dummy_card_detect;
|
||||
host->card_initialize = dummy_card_initialize;
|
||||
@@ -167,4 +149,7 @@ host_initialize_host_structure_dummy(struct mmc_host *host)
|
||||
host->slot[i].card.slot = &host->slot[i];
|
||||
}
|
||||
init_dummy_sdcard(&host->slot[0]);
|
||||
|
||||
/* Customize name for logs */
|
||||
log.name = "mmc_memory";
|
||||
}
|
||||
|
||||
@@ -25,11 +25,10 @@
|
||||
|
||||
/* header imported from netbsd */
|
||||
#include "sdmmcreg.h"
|
||||
#include "sdmmcreg.h"
|
||||
#include "sdhcreg.h"
|
||||
|
||||
/* omap /hardware related */
|
||||
#include "omap_mmc.h"
|
||||
#include "mmc_omap.h"
|
||||
|
||||
#define USE_INTR
|
||||
|
||||
@@ -37,8 +36,6 @@
|
||||
static int hook_id = 1;
|
||||
#endif
|
||||
|
||||
#define USE_DMA
|
||||
|
||||
#define SANE_TIMEOUT 500000 /* 500 ms */
|
||||
|
||||
struct omap_mmchs *mmchs; /* pointer to the current mmchs */
|
||||
@@ -64,19 +61,10 @@ struct omap_mmchs bbxm_sdcard = {
|
||||
*/
|
||||
#define div_roundup(x, y) (((x)+((y)-1))/(y))
|
||||
|
||||
/*
|
||||
* Define a structure to be used for logging
|
||||
*/
|
||||
static struct log log = {
|
||||
.name = "mmc_host_mmchs",
|
||||
.log_level = LEVEL_INFO,
|
||||
.log_func = default_log
|
||||
};
|
||||
|
||||
#define HSMMCSD_0_IN_FREQ 96000000 /* 96MHz */
|
||||
#define HSMMCSD_0_INIT_FREQ 400000 /* 400kHz */
|
||||
#define HSMMCSD_0_FREQ_25MHZ 25000000 /* 25MHz */
|
||||
#define HSMMCSD_0_FREQ_50MHZ 50000000 /* 50MHz */
|
||||
#define HSMMCSD_0_IN_FREQ 96000000 /* 96MHz */
|
||||
#define HSMMCSD_0_INIT_FREQ 400000 /* 400kHz */
|
||||
#define HSMMCSD_0_FREQ_25MHZ 25000000 /* 25MHz */
|
||||
#define HSMMCSD_0_FREQ_50MHZ 50000000 /* 50MHz */
|
||||
|
||||
void
|
||||
mmc_set32(vir_bytes reg, u32_t mask, u32_t value)
|
||||
@@ -150,7 +138,7 @@ mmchs_init(uint32_t instance)
|
||||
|
||||
/* Write 1 to sysconfig[0] to trigger a reset */
|
||||
mmc_set32(mmchs->regs->SYSCONFIG, MMCHS_SD_SYSCONFIG_SOFTRESET,
|
||||
MMCHS_SD_SYSCONFIG_SOFTRESET);
|
||||
MMCHS_SD_SYSCONFIG_SOFTRESET);
|
||||
|
||||
/* Read sysstatus to know when it's done */
|
||||
|
||||
@@ -1077,14 +1065,6 @@ mmchs_host_init(struct mmc_host *host)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
mmchs_set_log_level(int level)
|
||||
{
|
||||
if (level >= 0 && level <= 4) {
|
||||
log.log_level = level;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
mmchs_host_set_instance(struct mmc_host *host, int instance)
|
||||
{
|
||||
@@ -1190,9 +1170,7 @@ static int
|
||||
mmchs_host_read(struct sd_card *card,
|
||||
uint32_t blknr, uint32_t count, unsigned char *buf)
|
||||
{
|
||||
uint32_t i;
|
||||
i = count;
|
||||
for (i = 0; i < count; i++) {
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
read_single_block(&card->regs, blknr + i,
|
||||
buf + (i * card->blk_size));
|
||||
}
|
||||
@@ -1249,7 +1227,6 @@ host_initialize_host_structure_mmchs(struct mmc_host *host)
|
||||
assert(mmchs);
|
||||
host->host_set_instance = mmchs_host_set_instance;
|
||||
host->host_init = mmchs_host_init;
|
||||
host->set_log_level = mmchs_set_log_level;
|
||||
host->host_reset = mmchs_host_reset;
|
||||
host->card_detect = mmchs_card_detect;
|
||||
host->card_initialize = mmchs_card_initialize;
|
||||
@@ -1264,4 +1241,7 @@ host_initialize_host_structure_mmchs(struct mmc_host *host)
|
||||
host->slot[i].host = host;
|
||||
host->slot[i].card.slot = &host->slot[i];
|
||||
}
|
||||
|
||||
/* Customize name for logs */
|
||||
log.name = "mmc_omap";
|
||||
}
|
||||
1148
minix/drivers/storage/mmc/mmchost_rpi.c
Normal file
1148
minix/drivers/storage/mmc/mmchost_rpi.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -21,156 +21,156 @@
|
||||
#define _SDHCREG_H_
|
||||
|
||||
/* Host standard register set */
|
||||
#define SDHC_DMA_ADDR 0x00
|
||||
#define SDHC_BLOCK_SIZE 0x04
|
||||
#define SDHC_BLOCK_COUNT 0x06
|
||||
#define SDHC_BLOCK_COUNT_MAX 512
|
||||
#define SDHC_ARGUMENT 0x08
|
||||
#define SDHC_TRANSFER_MODE 0x0c
|
||||
#define SDHC_MULTI_BLOCK_MODE (1<<5)
|
||||
#define SDHC_READ_MODE (1<<4)
|
||||
#define SDHC_AUTO_CMD12_ENABLE (1<<2)
|
||||
#define SDHC_BLOCK_COUNT_ENABLE (1<<1)
|
||||
#define SDHC_DMA_ENABLE (1<<0)
|
||||
#define SDHC_COMMAND 0x0e
|
||||
#define SDHC_DMA_ADDR 0x00
|
||||
#define SDHC_BLOCK_SIZE 0x04
|
||||
#define SDHC_BLOCK_COUNT 0x06
|
||||
#define SDHC_BLOCK_COUNT_MAX 512
|
||||
#define SDHC_ARGUMENT 0x08
|
||||
#define SDHC_TRANSFER_MODE 0x0c
|
||||
#define SDHC_MULTI_BLOCK_MODE (1<<5)
|
||||
#define SDHC_READ_MODE (1<<4)
|
||||
#define SDHC_AUTO_CMD12_ENABLE (1<<2)
|
||||
#define SDHC_BLOCK_COUNT_ENABLE (1<<1)
|
||||
#define SDHC_DMA_ENABLE (1<<0)
|
||||
#define SDHC_COMMAND 0x0e
|
||||
/* 14-15 reserved */
|
||||
#define SDHC_COMMAND_INDEX_SHIFT 8
|
||||
#define SDHC_COMMAND_INDEX_MASK 0x3f
|
||||
#define SDHC_COMMAND_TYPE_ABORT (3<<6)
|
||||
#define SDHC_COMMAND_TYPE_RESUME (2<<6)
|
||||
#define SDHC_COMMAND_TYPE_SUSPEND (1<<6)
|
||||
#define SDHC_COMMAND_TYPE_NORMAL (0<<6)
|
||||
#define SDHC_DATA_PRESENT_SELECT (1<<5)
|
||||
#define SDHC_INDEX_CHECK_ENABLE (1<<4)
|
||||
#define SDHC_CRC_CHECK_ENABLE (1<<3)
|
||||
#define SDHC_COMMAND_INDEX_SHIFT 8
|
||||
#define SDHC_COMMAND_INDEX_MASK 0x3f
|
||||
#define SDHC_COMMAND_TYPE_ABORT (3<<6)
|
||||
#define SDHC_COMMAND_TYPE_RESUME (2<<6)
|
||||
#define SDHC_COMMAND_TYPE_SUSPEND (1<<6)
|
||||
#define SDHC_COMMAND_TYPE_NORMAL (0<<6)
|
||||
#define SDHC_DATA_PRESENT_SELECT (1<<5)
|
||||
#define SDHC_INDEX_CHECK_ENABLE (1<<4)
|
||||
#define SDHC_CRC_CHECK_ENABLE (1<<3)
|
||||
/* 2 reserved */
|
||||
#define SDHC_RESP_LEN_48_CHK_BUSY (3<<0)
|
||||
#define SDHC_RESP_LEN_48 (2<<0)
|
||||
#define SDHC_RESP_LEN_136 (1<<0)
|
||||
#define SDHC_NO_RESPONSE (0<<0)
|
||||
#define SDHC_RESPONSE 0x10 /* - 0x1f */
|
||||
#define SDHC_DATA 0x20
|
||||
#define SDHC_PRESENT_STATE 0x24
|
||||
#define SDHC_RESP_LEN_48_CHK_BUSY (3<<0)
|
||||
#define SDHC_RESP_LEN_48 (2<<0)
|
||||
#define SDHC_RESP_LEN_136 (1<<0)
|
||||
#define SDHC_NO_RESPONSE (0<<0)
|
||||
#define SDHC_RESPONSE 0x10 /* - 0x1f */
|
||||
#define SDHC_DATA 0x20
|
||||
#define SDHC_PRESENT_STATE 0x24
|
||||
/* 25-31 reserved */
|
||||
#define SDHC_CMD_LINE_SIGNAL_LEVEL (1<<24)
|
||||
#define SDHC_DAT3_LINE_LEVEL (1<<23)
|
||||
#define SDHC_DAT2_LINE_LEVEL (1<<22)
|
||||
#define SDHC_DAT1_LINE_LEVEL (1<<21)
|
||||
#define SDHC_DAT0_LINE_LEVEL (1<<20)
|
||||
#define SDHC_WRITE_PROTECT_SWITCH (1<<19)
|
||||
#define SDHC_CARD_DETECT_PIN_LEVEL (1<<18)
|
||||
#define SDHC_CARD_STATE_STABLE (1<<17)
|
||||
#define SDHC_CARD_INSERTED (1<<16)
|
||||
#define SDHC_CMD_LINE_SIGNAL_LEVEL (1<<24)
|
||||
#define SDHC_DAT3_LINE_LEVEL (1<<23)
|
||||
#define SDHC_DAT2_LINE_LEVEL (1<<22)
|
||||
#define SDHC_DAT1_LINE_LEVEL (1<<21)
|
||||
#define SDHC_DAT0_LINE_LEVEL (1<<20)
|
||||
#define SDHC_WRITE_PROTECT_SWITCH (1<<19)
|
||||
#define SDHC_CARD_DETECT_PIN_LEVEL (1<<18)
|
||||
#define SDHC_CARD_STATE_STABLE (1<<17)
|
||||
#define SDHC_CARD_INSERTED (1<<16)
|
||||
/* 12-15 reserved */
|
||||
#define SDHC_BUFFER_READ_ENABLE (1<<11)
|
||||
#define SDHC_BUFFER_WRITE_ENABLE (1<<10)
|
||||
#define SDHC_READ_TRANSFER_ACTIVE (1<<9)
|
||||
#define SDHC_WRITE_TRANSFER_ACTIVE (1<<8)
|
||||
#define SDHC_BUFFER_READ_ENABLE (1<<11)
|
||||
#define SDHC_BUFFER_WRITE_ENABLE (1<<10)
|
||||
#define SDHC_READ_TRANSFER_ACTIVE (1<<9)
|
||||
#define SDHC_WRITE_TRANSFER_ACTIVE (1<<8)
|
||||
/* 3-7 reserved */
|
||||
#define SDHC_DAT_ACTIVE (1<<2)
|
||||
#define SDHC_CMD_INHIBIT_DAT (1<<1)
|
||||
#define SDHC_CMD_INHIBIT_CMD (1<<0)
|
||||
#define SDHC_CMD_INHIBIT_MASK 0x0003
|
||||
#define SDHC_HOST_CTL 0x28
|
||||
#define SDHC_HIGH_SPEED (1<<2)
|
||||
#define SDHC_ESDHC_8BIT_MODE (1<<2) /* eSDHC */
|
||||
#define SDHC_4BIT_MODE (1<<1)
|
||||
#define SDHC_LED_ON (1<<0)
|
||||
#define SDHC_POWER_CTL 0x29
|
||||
#define SDHC_VOLTAGE_SHIFT 1
|
||||
#define SDHC_VOLTAGE_MASK 0x07
|
||||
#define SDHC_VOLTAGE_3_3V 0x07
|
||||
#define SDHC_VOLTAGE_3_0V 0x06
|
||||
#define SDHC_VOLTAGE_1_8V 0x05
|
||||
#define SDHC_BUS_POWER (1<<0)
|
||||
#define SDHC_BLOCK_GAP_CTL 0x2a
|
||||
#define SDHC_WAKEUP_CTL 0x2b
|
||||
#define SDHC_CLOCK_CTL 0x2c
|
||||
#define SDHC_SDCLK_DIV_SHIFT 8
|
||||
#define SDHC_SDCLK_DIV_MASK 0xff
|
||||
#define SDHC_SDCLK_XDIV_SHIFT 6
|
||||
#define SDHC_SDCLK_XDIV_MASK 0x3
|
||||
#define SDHC_SDCLK_CGM (1<<5)
|
||||
#define SDHC_SDCLK_DVS_SHIFT 4
|
||||
#define SDHC_SDCLK_DVS_MASK 0xf
|
||||
#define SDHC_SDCLK_ENABLE (1<<2)
|
||||
#define SDHC_INTCLK_STABLE (1<<1)
|
||||
#define SDHC_INTCLK_ENABLE (1<<0)
|
||||
#define SDHC_TIMEOUT_CTL 0x2e
|
||||
#define SDHC_TIMEOUT_MAX 0x0e
|
||||
#define SDHC_SOFTWARE_RESET 0x2f
|
||||
#define SDHC_INIT_ACTIVE (1<<3)
|
||||
#define SDHC_RESET_MASK 0x5
|
||||
#define SDHC_RESET_DAT (1<<2)
|
||||
#define SDHC_RESET_CMD (1<<1)
|
||||
#define SDHC_RESET_ALL (1<<0)
|
||||
#define SDHC_NINTR_STATUS 0x30
|
||||
#define SDHC_ERROR_INTERRUPT (1<<15)
|
||||
#define SDHC_CARD_INTERRUPT (1<<8)
|
||||
#define SDHC_CARD_REMOVAL (1<<7)
|
||||
#define SDHC_CARD_INSERTION (1<<6)
|
||||
#define SDHC_BUFFER_READ_READY (1<<5)
|
||||
#define SDHC_BUFFER_WRITE_READY (1<<4)
|
||||
#define SDHC_DMA_INTERRUPT (1<<3)
|
||||
#define SDHC_BLOCK_GAP_EVENT (1<<2)
|
||||
#define SDHC_TRANSFER_COMPLETE (1<<1)
|
||||
#define SDHC_COMMAND_COMPLETE (1<<0)
|
||||
#define SDHC_NINTR_STATUS_MASK 0x81ff
|
||||
#define SDHC_EINTR_STATUS 0x32
|
||||
#define SDHC_DMA_ERROR (1<<12)
|
||||
#define SDHC_AUTO_CMD12_ERROR (1<<8)
|
||||
#define SDHC_CURRENT_LIMIT_ERROR (1<<7)
|
||||
#define SDHC_DATA_END_BIT_ERROR (1<<6)
|
||||
#define SDHC_DATA_CRC_ERROR (1<<5)
|
||||
#define SDHC_DATA_TIMEOUT_ERROR (1<<4)
|
||||
#define SDHC_CMD_INDEX_ERROR (1<<3)
|
||||
#define SDHC_CMD_END_BIT_ERROR (1<<2)
|
||||
#define SDHC_CMD_CRC_ERROR (1<<1)
|
||||
#define SDHC_CMD_TIMEOUT_ERROR (1<<0)
|
||||
#define SDHC_EINTR_STATUS_MASK 0x01ff /* excluding vendor signals */
|
||||
#define SDHC_DAT_ACTIVE (1<<2)
|
||||
#define SDHC_CMD_INHIBIT_DAT (1<<1)
|
||||
#define SDHC_CMD_INHIBIT_CMD (1<<0)
|
||||
#define SDHC_CMD_INHIBIT_MASK 0x0003
|
||||
#define SDHC_HOST_CTL 0x28
|
||||
#define SDHC_HIGH_SPEED (1<<2)
|
||||
#define SDHC_ESDHC_8BIT_MODE (1<<2) /* eSDHC */
|
||||
#define SDHC_4BIT_MODE (1<<1)
|
||||
#define SDHC_LED_ON (1<<0)
|
||||
#define SDHC_POWER_CTL 0x29
|
||||
#define SDHC_VOLTAGE_SHIFT 1
|
||||
#define SDHC_VOLTAGE_MASK 0x07
|
||||
#define SDHC_VOLTAGE_3_3V 0x07
|
||||
#define SDHC_VOLTAGE_3_0V 0x06
|
||||
#define SDHC_VOLTAGE_1_8V 0x05
|
||||
#define SDHC_BUS_POWER (1<<0)
|
||||
#define SDHC_BLOCK_GAP_CTL 0x2a
|
||||
#define SDHC_WAKEUP_CTL 0x2b
|
||||
#define SDHC_CLOCK_CTL 0x2c
|
||||
#define SDHC_SDCLK_DIV_SHIFT 8
|
||||
#define SDHC_SDCLK_DIV_MASK 0xff
|
||||
#define SDHC_SDCLK_XDIV_SHIFT 6
|
||||
#define SDHC_SDCLK_XDIV_MASK 0x3
|
||||
#define SDHC_SDCLK_CGM (1<<5)
|
||||
#define SDHC_SDCLK_DVS_SHIFT 4
|
||||
#define SDHC_SDCLK_DVS_MASK 0xf
|
||||
#define SDHC_SDCLK_ENABLE (1<<2)
|
||||
#define SDHC_INTCLK_STABLE (1<<1)
|
||||
#define SDHC_INTCLK_ENABLE (1<<0)
|
||||
#define SDHC_TIMEOUT_CTL 0x2e
|
||||
#define SDHC_TIMEOUT_MAX 0x0e
|
||||
#define SDHC_SOFTWARE_RESET 0x2f
|
||||
#define SDHC_INIT_ACTIVE (1<<3)
|
||||
#define SDHC_RESET_MASK 0x5
|
||||
#define SDHC_RESET_DAT (1<<2)
|
||||
#define SDHC_RESET_CMD (1<<1)
|
||||
#define SDHC_RESET_ALL (1<<0)
|
||||
#define SDHC_NINTR_STATUS 0x30
|
||||
#define SDHC_ERROR_INTERRUPT (1<<15)
|
||||
#define SDHC_CARD_INTERRUPT (1<<8)
|
||||
#define SDHC_CARD_REMOVAL (1<<7)
|
||||
#define SDHC_CARD_INSERTION (1<<6)
|
||||
#define SDHC_BUFFER_READ_READY (1<<5)
|
||||
#define SDHC_BUFFER_WRITE_READY (1<<4)
|
||||
#define SDHC_DMA_INTERRUPT (1<<3)
|
||||
#define SDHC_BLOCK_GAP_EVENT (1<<2)
|
||||
#define SDHC_TRANSFER_COMPLETE (1<<1)
|
||||
#define SDHC_COMMAND_COMPLETE (1<<0)
|
||||
#define SDHC_NINTR_STATUS_MASK 0x81ff
|
||||
#define SDHC_EINTR_STATUS 0x32
|
||||
#define SDHC_DMA_ERROR (1<<12)
|
||||
#define SDHC_AUTO_CMD12_ERROR (1<<8)
|
||||
#define SDHC_CURRENT_LIMIT_ERROR (1<<7)
|
||||
#define SDHC_DATA_END_BIT_ERROR (1<<6)
|
||||
#define SDHC_DATA_CRC_ERROR (1<<5)
|
||||
#define SDHC_DATA_TIMEOUT_ERROR (1<<4)
|
||||
#define SDHC_CMD_INDEX_ERROR (1<<3)
|
||||
#define SDHC_CMD_END_BIT_ERROR (1<<2)
|
||||
#define SDHC_CMD_CRC_ERROR (1<<1)
|
||||
#define SDHC_CMD_TIMEOUT_ERROR (1<<0)
|
||||
#define SDHC_EINTR_STATUS_MASK 0x01ff /* excluding vendor signals */
|
||||
#define SDHC_NINTR_STATUS_EN 0x34
|
||||
#define SDHC_EINTR_STATUS_EN 0x36
|
||||
#define SDHC_NINTR_SIGNAL_EN 0x38
|
||||
#define SDHC_NINTR_SIGNAL_MASK 0x01ff
|
||||
#define SDHC_NINTR_SIGNAL_MASK 0x01ff
|
||||
#define SDHC_EINTR_SIGNAL_EN 0x3a
|
||||
#define SDHC_EINTR_SIGNAL_MASK 0x01ff /* excluding vendor signals */
|
||||
#define SDHC_EINTR_SIGNAL_MASK 0x01ff /* excluding vendor signals */
|
||||
#define SDHC_CMD12_ERROR_STATUS 0x3c
|
||||
#define SDHC_CAPABILITIES 0x40
|
||||
#define SDHC_VOLTAGE_SUPP_1_8V (1<<26)
|
||||
#define SDHC_VOLTAGE_SUPP_3_0V (1<<25)
|
||||
#define SDHC_VOLTAGE_SUPP_3_3V (1<<24)
|
||||
#define SDHC_DMA_SUPPORT (1<<22)
|
||||
#define SDHC_HIGH_SPEED_SUPP (1<<21)
|
||||
#define SDHC_MAX_BLK_LEN_512 0
|
||||
#define SDHC_MAX_BLK_LEN_1024 1
|
||||
#define SDHC_MAX_BLK_LEN_2048 2
|
||||
#define SDHC_MAX_BLK_LEN_4096 3
|
||||
#define SDHC_MAX_BLK_LEN_SHIFT 16
|
||||
#define SDHC_MAX_BLK_LEN_MASK 0x3
|
||||
#define SDHC_BASE_FREQ_SHIFT 8
|
||||
#define SDHC_BASE_FREQ_MASK 0x3f
|
||||
#define SDHC_TIMEOUT_FREQ_UNIT (1<<7) /* 0=KHz, 1=MHz */
|
||||
#define SDHC_TIMEOUT_FREQ_SHIFT 0
|
||||
#define SDHC_TIMEOUT_FREQ_MASK 0x1f
|
||||
#define SDHC_CAPABILITIES 0x40
|
||||
#define SDHC_VOLTAGE_SUPP_1_8V (1<<26)
|
||||
#define SDHC_VOLTAGE_SUPP_3_0V (1<<25)
|
||||
#define SDHC_VOLTAGE_SUPP_3_3V (1<<24)
|
||||
#define SDHC_DMA_SUPPORT (1<<22)
|
||||
#define SDHC_HIGH_SPEED_SUPP (1<<21)
|
||||
#define SDHC_MAX_BLK_LEN_512 0
|
||||
#define SDHC_MAX_BLK_LEN_1024 1
|
||||
#define SDHC_MAX_BLK_LEN_2048 2
|
||||
#define SDHC_MAX_BLK_LEN_4096 3
|
||||
#define SDHC_MAX_BLK_LEN_SHIFT 16
|
||||
#define SDHC_MAX_BLK_LEN_MASK 0x3
|
||||
#define SDHC_BASE_FREQ_SHIFT 8
|
||||
#define SDHC_BASE_FREQ_MASK 0x3f
|
||||
#define SDHC_TIMEOUT_FREQ_UNIT (1<<7) /* 0=KHz, 1=MHz */
|
||||
#define SDHC_TIMEOUT_FREQ_SHIFT 0
|
||||
#define SDHC_TIMEOUT_FREQ_MASK 0x1f
|
||||
#define SDHC_MAX_CAPABILITIES 0x48
|
||||
#define SDHC_HOST_VER 0xFC
|
||||
#define SDHC_VVN_MASK 0x0f
|
||||
#define SDHC_VVN_SHIFT 0x04
|
||||
#define SDHC_SVN_MASK 0x0f
|
||||
#define SDHC_SVN_SHIFT 0x00
|
||||
#define SDHC_HOST_VER 0xFC
|
||||
#define SDHC_VVN_MASK 0x0f
|
||||
#define SDHC_VVN_SHIFT 0x04
|
||||
#define SDHC_SVN_MASK 0x0f
|
||||
#define SDHC_SVN_SHIFT 0x00
|
||||
#define SDHC_SLOT_INTR_STATUS 0xfc
|
||||
#define SDHC_HOST_CTL_VERSION 0xfe
|
||||
#define SDHC_SPEC_VERS_SHIFT 0
|
||||
#define SDHC_SPEC_VERS_MASK 0xff
|
||||
#define SDHC_VENDOR_VERS_SHIFT 8
|
||||
#define SDHC_VENDOR_VERS_MASK 0xff
|
||||
#define SDHC_DMA_CTL 0x40c /* eSDHC */
|
||||
#define SDHC_DMA_SNOOP 0x40
|
||||
#define SDHC_SPEC_VERS_SHIFT 0
|
||||
#define SDHC_SPEC_VERS_MASK 0xff
|
||||
#define SDHC_VENDOR_VERS_SHIFT 8
|
||||
#define SDHC_VENDOR_VERS_MASK 0xff
|
||||
#define SDHC_DMA_CTL 0x40c /* eSDHC */
|
||||
#define SDHC_DMA_SNOOP 0x40
|
||||
|
||||
/* SDHC_SPEC_VERS */
|
||||
#define SDHC_SPEC_VERS_100 0x00
|
||||
#define SDHC_SPEC_VERS_200 0x01
|
||||
#define SDHC_SPEC_VERS_300 0x02
|
||||
#define SDHC_SPEC_VERS_100 0x00
|
||||
#define SDHC_SPEC_VERS_200 0x01
|
||||
#define SDHC_SPEC_VERS_300 0x02
|
||||
|
||||
/* SDHC_CAPABILITIES decoding */
|
||||
#define SDHC_BASE_FREQ_KHZ(cap) \
|
||||
|
||||
@@ -21,52 +21,52 @@
|
||||
#define _SDMMCREG_H_
|
||||
|
||||
/* MMC commands */ /* response type */
|
||||
#define MMC_GO_IDLE_STATE 0 /* R0 */
|
||||
#define MMC_SEND_OP_COND 1 /* R3 */
|
||||
#define MMC_ALL_SEND_CID 2 /* R2 */
|
||||
#define MMC_SET_RELATIVE_ADDR 3 /* R1 */
|
||||
#define MMC_SWITCH 6 /* R1b */
|
||||
#define MMC_SELECT_CARD 7 /* R1 */
|
||||
#define MMC_SEND_EXT_CSD 8 /* R1 */
|
||||
#define MMC_SEND_CSD 9 /* R2 */
|
||||
#define MMC_SEND_CID 10 /* R2 */
|
||||
#define MMC_GO_IDLE_STATE 0 /* R0 */
|
||||
#define MMC_SEND_OP_COND 1 /* R3 */
|
||||
#define MMC_ALL_SEND_CID 2 /* R2 */
|
||||
#define MMC_SET_RELATIVE_ADDR 3 /* R1 */
|
||||
#define MMC_SWITCH 6 /* R1b */
|
||||
#define MMC_SELECT_CARD 7 /* R1 */
|
||||
#define MMC_SEND_EXT_CSD 8 /* R1 */
|
||||
#define MMC_SEND_CSD 9 /* R2 */
|
||||
#define MMC_SEND_CID 10 /* R2 */
|
||||
#define MMC_STOP_TRANSMISSION 12 /* R1b */
|
||||
#define MMC_SEND_STATUS 13 /* R1 */
|
||||
#define MMC_INACTIVE_STATE 15 /* R0 */
|
||||
#define MMC_SET_BLOCKLEN 16 /* R1 */
|
||||
#define MMC_SEND_STATUS 13 /* R1 */
|
||||
#define MMC_INACTIVE_STATE 15 /* R0 */
|
||||
#define MMC_SET_BLOCKLEN 16 /* R1 */
|
||||
#define MMC_READ_BLOCK_SINGLE 17 /* R1 */
|
||||
#define MMC_READ_BLOCK_MULTIPLE 18 /* R1 */
|
||||
#define MMC_SET_BLOCK_COUNT 23 /* R1 */
|
||||
#define MMC_SET_BLOCK_COUNT 23 /* R1 */
|
||||
#define MMC_WRITE_BLOCK_SINGLE 24 /* R1 */
|
||||
#define MMC_WRITE_BLOCK_MULTIPLE 25 /* R1 */
|
||||
#define MMC_PROGRAM_CSD 27 /* R1 */
|
||||
#define MMC_SET_WRITE_PROT 28 /* R1b */
|
||||
#define MMC_PROGRAM_CSD 27 /* R1 */
|
||||
#define MMC_SET_WRITE_PROT 28 /* R1b */
|
||||
#define MMC_SET_CLR_WRITE_PROT 29 /* R1b */
|
||||
#define MMC_SET_SEND_WRITE_PROT 30 /* R1 */
|
||||
#define MMC_TAG_SECTOR_START 32 /* R1 */
|
||||
#define MMC_TAG_SECTOR_END 33 /* R1 */
|
||||
#define MMC_UNTAG_SECTOR 34 /* R1 */
|
||||
#define MMC_TAG_SECTOR_END 33 /* R1 */
|
||||
#define MMC_UNTAG_SECTOR 34 /* R1 */
|
||||
#define MMC_TAG_ERASE_GROUP_START 35 /* R1 */
|
||||
#define MMC_TAG_ERASE_GROUP_END 36 /* R1 */
|
||||
#define MMC_UNTAG_ERASE_GROUP 37 /* R1 */
|
||||
#define MMC_ERASE 38 /* R1b */
|
||||
#define MMC_LOCK_UNLOCK 42 /* R1b */
|
||||
#define MMC_APP_CMD 55 /* R1 */
|
||||
#define MMC_READ_OCR 58 /* R3 */
|
||||
#define MMC_ERASE 38 /* R1b */
|
||||
#define MMC_LOCK_UNLOCK 42 /* R1b */
|
||||
#define MMC_APP_CMD 55 /* R1 */
|
||||
#define MMC_READ_OCR 58 /* R3 */
|
||||
|
||||
/* SD commands */ /* response type */
|
||||
#define SD_SEND_RELATIVE_ADDR 3 /* R6 */
|
||||
#define SD_SEND_SWITCH_FUNC 6 /* R1 */
|
||||
#define SD_SEND_IF_COND 8 /* R7 */
|
||||
#define SD_SEND_RELATIVE_ADDR 3 /* R6 */
|
||||
#define SD_SEND_SWITCH_FUNC 6 /* R1 */
|
||||
#define SD_SEND_IF_COND 8 /* R7 */
|
||||
|
||||
/* SD application commands */ /* response type */
|
||||
#define SD_APP_SET_BUS_WIDTH 6 /* R1 */
|
||||
#define SD_APP_OP_COND 41 /* R3 */
|
||||
#define SD_APP_SEND_SCR 51 /* R1 */
|
||||
#define SD_APP_OP_COND 41 /* R3 */
|
||||
#define SD_APP_SEND_SCR 51 /* R1 */
|
||||
|
||||
/* OCR bits */
|
||||
#define MMC_OCR_MEM_READY (1U<<31)/* memory power-up status bit */
|
||||
#define MMC_OCR_HCS (1<<30)
|
||||
#define MMC_OCR_HCS (1<<30)
|
||||
#define MMC_OCR_3_5V_3_6V (1<<23)
|
||||
#define MMC_OCR_3_4V_3_5V (1<<22)
|
||||
#define MMC_OCR_3_3V_3_4V (1<<21)
|
||||
@@ -89,13 +89,13 @@
|
||||
#define MMC_OCR_1_6V_1_7V (1<<4)
|
||||
|
||||
/* R1 response type bits */
|
||||
#define MMC_R1_READY_FOR_DATA (1<<8) /* ready for next transfer */
|
||||
#define MMC_R1_READY_FOR_DATA (1<<8) /* ready for next transfer */
|
||||
#define MMC_R1_APP_CMD (1<<5) /* app. commands supported */
|
||||
|
||||
/* 48-bit response decoding (32 bits w/o CRC) */
|
||||
#define MMC_R1(resp) ((resp)[0])
|
||||
#define MMC_R3(resp) ((resp)[0])
|
||||
#define SD_R6(resp) ((resp)[0])
|
||||
#define SD_R6(resp) ((resp)[0])
|
||||
#define MMC_R7(resp) ((resp)[0])
|
||||
#define MMC_SPI_R1(resp) ((resp)[0])
|
||||
#define MMC_SPI_R7(resp) ((resp)[1])
|
||||
@@ -111,7 +111,7 @@
|
||||
/* EXT_CSD fields */
|
||||
#define EXT_CSD_BUS_WIDTH 183 /* WO */
|
||||
#define EXT_CSD_HS_TIMING 185 /* R/W */
|
||||
#define EXT_CSD_REV 192 /* RO */
|
||||
#define EXT_CSD_REV 192 /* RO */
|
||||
#define EXT_CSD_STRUCTURE 194 /* RO */
|
||||
#define EXT_CSD_CARD_TYPE 196 /* RO */
|
||||
|
||||
@@ -141,54 +141,54 @@
|
||||
#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */
|
||||
|
||||
/* SPI mode reports R1/R2(SEND_STATUS) status. */
|
||||
#define R1_SPI_IDLE (1 << 0)
|
||||
#define R1_SPI_ERASE_RESET (1 << 1)
|
||||
#define R1_SPI_IDLE (1 << 0)
|
||||
#define R1_SPI_ERASE_RESET (1 << 1)
|
||||
#define R1_SPI_ILLEGAL_COMMAND (1 << 2)
|
||||
#define R1_SPI_COM_CRC (1 << 3)
|
||||
#define R1_SPI_ERASE_SEQ (1 << 4)
|
||||
#define R1_SPI_ADDRESS (1 << 5)
|
||||
#define R1_SPI_PARAMETER (1 << 6)
|
||||
#define R1_SPI_COM_CRC (1 << 3)
|
||||
#define R1_SPI_ERASE_SEQ (1 << 4)
|
||||
#define R1_SPI_ADDRESS (1 << 5)
|
||||
#define R1_SPI_PARAMETER (1 << 6)
|
||||
/* R1 bit 7 is always zero */
|
||||
#define R2_SPI_CARD_LOCKED (1 << 8)
|
||||
#define R2_SPI_CARD_LOCKED (1 << 8)
|
||||
#define R2_SPI_WP_ERASE_SKIP (1 << 9) /* or lock/unlock fail */
|
||||
#define R2_SPI_LOCK_UNLOCK_FAIL R2_SPI_WP_ERASE_SKIP
|
||||
#define R2_SPI_ERROR (1 << 10)
|
||||
#define R2_SPI_CC_ERROR (1 << 11)
|
||||
#define R2_SPI_ERROR (1 << 10)
|
||||
#define R2_SPI_CC_ERROR (1 << 11)
|
||||
#define R2_SPI_CARD_ECC_ERROR (1 << 12)
|
||||
#define R2_SPI_WP_VIOLATION (1 << 13)
|
||||
#define R2_SPI_ERASE_PARAM (1 << 14)
|
||||
#define R2_SPI_OUT_OF_RANGE (1 << 15) /* or CSD overwrite */
|
||||
#define R2_SPI_WP_VIOLATION (1 << 13)
|
||||
#define R2_SPI_ERASE_PARAM (1 << 14)
|
||||
#define R2_SPI_OUT_OF_RANGE (1 << 15) /* or CSD overwrite */
|
||||
#define R2_SPI_CSD_OVERWRITE R2_SPI_OUT_OF_RANGE
|
||||
|
||||
/* MMC R2 response (CSD) */
|
||||
#define MMC_CSD_CSDVER(resp) MMC_RSP_BITS((resp), 126, 2)
|
||||
#define MMC_CSD_CSDVER_1_0 0
|
||||
#define MMC_CSD_CSDVER_1_1 1
|
||||
#define MMC_CSD_CSDVER_1_2 2 /* MMC 4.1 - 4.2 - 4.3 */
|
||||
#define MMC_CSD_CSDVER_EXT_CSD 3 /* Version is coded in CSD_STRUCTURE in EXT_CSD */
|
||||
#define MMC_CSD_MMCVER(resp) MMC_RSP_BITS((resp), 122, 4)
|
||||
#define MMC_CSD_MMCVER_1_0 0 /* MMC 1.0 - 1.2 */
|
||||
#define MMC_CSD_MMCVER_1_4 1 /* MMC 1.4 */
|
||||
#define MMC_CSD_MMCVER_2_0 2 /* MMC 2.0 - 2.2 */
|
||||
#define MMC_CSD_MMCVER_3_1 3 /* MMC 3.1 - 3.3 */
|
||||
#define MMC_CSD_MMCVER_4_0 4 /* MMC 4.1 - 4.2 - 4.3 */
|
||||
#define MMC_CSD_TAAC(resp) MMC_RSP_BITS((resp), 112, 8)
|
||||
#define MMC_CSD_TAAC_MANT(resp) MMC_RSP_BITS((resp), 115, 4)
|
||||
#define MMC_CSD_TAAC_EXP(resp) MMC_RSP_BITS((resp), 112, 3)
|
||||
#define MMC_CSD_NSAC(resp) MMC_RSP_BITS((resp), 104, 8)
|
||||
#define MMC_CSD_TRAN_SPEED(resp) MMC_RSP_BITS((resp), 96, 8)
|
||||
#define MMC_CSD_CSDVER(resp) MMC_RSP_BITS((resp), 126, 2)
|
||||
#define MMC_CSD_CSDVER_1_0 0
|
||||
#define MMC_CSD_CSDVER_1_1 1
|
||||
#define MMC_CSD_CSDVER_1_2 2 /* MMC 4.1 - 4.2 - 4.3 */
|
||||
#define MMC_CSD_CSDVER_EXT_CSD 3 /* Version is coded in CSD_STRUCTURE in EXT_CSD */
|
||||
#define MMC_CSD_MMCVER(resp) MMC_RSP_BITS((resp), 122, 4)
|
||||
#define MMC_CSD_MMCVER_1_0 0 /* MMC 1.0 - 1.2 */
|
||||
#define MMC_CSD_MMCVER_1_4 1 /* MMC 1.4 */
|
||||
#define MMC_CSD_MMCVER_2_0 2 /* MMC 2.0 - 2.2 */
|
||||
#define MMC_CSD_MMCVER_3_1 3 /* MMC 3.1 - 3.3 */
|
||||
#define MMC_CSD_MMCVER_4_0 4 /* MMC 4.1 - 4.2 - 4.3 */
|
||||
#define MMC_CSD_TAAC(resp) MMC_RSP_BITS((resp), 112, 8)
|
||||
#define MMC_CSD_TAAC_MANT(resp) MMC_RSP_BITS((resp), 115, 4)
|
||||
#define MMC_CSD_TAAC_EXP(resp) MMC_RSP_BITS((resp), 112, 3)
|
||||
#define MMC_CSD_NSAC(resp) MMC_RSP_BITS((resp), 104, 8)
|
||||
#define MMC_CSD_TRAN_SPEED(resp) MMC_RSP_BITS((resp), 96, 8)
|
||||
#define MMC_CSD_TRAN_SPEED_MANT(resp) MMC_RSP_BITS((resp), 99, 4)
|
||||
#define MMC_CSD_TRAN_SPEED_EXP(resp) MMC_RSP_BITS((resp), 96, 3)
|
||||
#define MMC_CSD_READ_BL_LEN(resp) MMC_RSP_BITS((resp), 80, 4)
|
||||
#define MMC_CSD_C_SIZE(resp) MMC_RSP_BITS((resp), 62, 12)
|
||||
#define MMC_CSD_CAPACITY(resp) ((MMC_CSD_C_SIZE((resp))+1) << \
|
||||
#define MMC_CSD_READ_BL_LEN(resp) MMC_RSP_BITS((resp), 80, 4)
|
||||
#define MMC_CSD_C_SIZE(resp) MMC_RSP_BITS((resp), 62, 12)
|
||||
#define MMC_CSD_CAPACITY(resp) ((MMC_CSD_C_SIZE((resp))+1) << \
|
||||
(MMC_CSD_C_SIZE_MULT((resp))+2))
|
||||
#define MMC_CSD_C_SIZE_MULT(resp) MMC_RSP_BITS((resp), 47, 3)
|
||||
#define MMC_CSD_R2W_FACTOR(resp) MMC_RSP_BITS((resp), 26, 3)
|
||||
#define MMC_CSD_WRITE_BL_LEN(resp) MMC_RSP_BITS((resp), 22, 4)
|
||||
#define MMC_CSD_C_SIZE_MULT(resp) MMC_RSP_BITS((resp), 47, 3)
|
||||
#define MMC_CSD_R2W_FACTOR(resp) MMC_RSP_BITS((resp), 26, 3)
|
||||
#define MMC_CSD_WRITE_BL_LEN(resp) MMC_RSP_BITS((resp), 22, 4)
|
||||
|
||||
/* MMC v1 R2 response (CID) */
|
||||
#define MMC_CID_MID_V1(resp) MMC_RSP_BITS((resp), 104, 24)
|
||||
#define MMC_CID_MID_V1(resp) MMC_RSP_BITS((resp), 104, 24)
|
||||
#define MMC_CID_PNM_V1_CPY(resp, pnm) \
|
||||
do { \
|
||||
(pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \
|
||||
@@ -217,65 +217,65 @@
|
||||
(pnm)[5] = MMC_RSP_BITS((resp), 56, 8); \
|
||||
(pnm)[6] = '\0'; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
#define MMC_CID_PSN_V2(resp) MMC_RSP_BITS((resp), 16, 32)
|
||||
#define MMC_CID_PSN_V2(resp) MMC_RSP_BITS((resp), 16, 32)
|
||||
|
||||
/* SD R2 response (CSD) */
|
||||
#define SD_CSD_CSDVER(resp) MMC_RSP_BITS((resp), 126, 2)
|
||||
#define SD_CSD_CSDVER_1_0 0
|
||||
#define SD_CSD_CSDVER_2_0 1
|
||||
#define SD_CSD_MMCVER(resp) MMC_RSP_BITS((resp), 122, 4)
|
||||
#define SD_CSD_TAAC(resp) MMC_RSP_BITS((resp), 112, 8)
|
||||
#define SD_CSD_TAAC_EXP(resp) MMC_RSP_BITS((resp), 115, 4)
|
||||
#define SD_CSD_TAAC_MANT(resp) MMC_RSP_BITS((resp), 112, 3)
|
||||
#define SD_CSD_TAAC_1_5_MSEC 0x26
|
||||
#define SD_CSD_NSAC(resp) MMC_RSP_BITS((resp), 104, 8)
|
||||
#define SD_CSD_SPEED(resp) MMC_RSP_BITS((resp), 96, 8)
|
||||
#define SD_CSD_SPEED_MANT(resp) MMC_RSP_BITS((resp), 99, 4)
|
||||
#define SD_CSD_SPEED_EXP(resp) MMC_RSP_BITS((resp), 96, 3)
|
||||
#define SD_CSD_SPEED_25_MHZ 0x32
|
||||
#define SD_CSD_SPEED_50_MHZ 0x5a
|
||||
#define SD_CSD_CCC(resp) MMC_RSP_BITS((resp), 84, 12)
|
||||
#define SD_CSD_CCC_BASIC (1 << 0) /* basic */
|
||||
#define SD_CSD_CCC_BR (1 << 2) /* block read */
|
||||
#define SD_CSD_CCC_BW (1 << 4) /* block write */
|
||||
#define SD_CSD_CCC_ERACE (1 << 5) /* erase */
|
||||
#define SD_CSD_CCC_WP (1 << 6) /* write protection */
|
||||
#define SD_CSD_CCC_LC (1 << 7) /* lock card */
|
||||
#define SD_CSD_CCC_AS (1 << 8) /*application specific*/
|
||||
#define SD_CSD_CCC_IOM (1 << 9) /* I/O mode */
|
||||
#define SD_CSD_CCC_SWITCH (1 << 10) /* switch */
|
||||
#define SD_CSD_READ_BL_LEN(resp) MMC_RSP_BITS((resp), 80, 4)
|
||||
#define SD_CSD_CSDVER(resp) MMC_RSP_BITS((resp), 126, 2)
|
||||
#define SD_CSD_CSDVER_1_0 0
|
||||
#define SD_CSD_CSDVER_2_0 1
|
||||
#define SD_CSD_MMCVER(resp) MMC_RSP_BITS((resp), 122, 4)
|
||||
#define SD_CSD_TAAC(resp) MMC_RSP_BITS((resp), 112, 8)
|
||||
#define SD_CSD_TAAC_EXP(resp) MMC_RSP_BITS((resp), 115, 4)
|
||||
#define SD_CSD_TAAC_MANT(resp) MMC_RSP_BITS((resp), 112, 3)
|
||||
#define SD_CSD_TAAC_1_5_MSEC 0x26
|
||||
#define SD_CSD_NSAC(resp) MMC_RSP_BITS((resp), 104, 8)
|
||||
#define SD_CSD_SPEED(resp) MMC_RSP_BITS((resp), 96, 8)
|
||||
#define SD_CSD_SPEED_MANT(resp) MMC_RSP_BITS((resp), 99, 4)
|
||||
#define SD_CSD_SPEED_EXP(resp) MMC_RSP_BITS((resp), 96, 3)
|
||||
#define SD_CSD_SPEED_25_MHZ 0x32
|
||||
#define SD_CSD_SPEED_50_MHZ 0x5a
|
||||
#define SD_CSD_CCC(resp) MMC_RSP_BITS((resp), 84, 12)
|
||||
#define SD_CSD_CCC_BASIC (1 << 0) /* basic */
|
||||
#define SD_CSD_CCC_BR (1 << 2) /* block read */
|
||||
#define SD_CSD_CCC_BW (1 << 4) /* block write */
|
||||
#define SD_CSD_CCC_ERACE (1 << 5) /* erase */
|
||||
#define SD_CSD_CCC_WP (1 << 6) /* write protection */
|
||||
#define SD_CSD_CCC_LC (1 << 7) /* lock card */
|
||||
#define SD_CSD_CCC_AS (1 << 8) /*application specific*/
|
||||
#define SD_CSD_CCC_IOM (1 << 9) /* I/O mode */
|
||||
#define SD_CSD_CCC_SWITCH (1 << 10) /* switch */
|
||||
#define SD_CSD_READ_BL_LEN(resp) MMC_RSP_BITS((resp), 80, 4)
|
||||
#define SD_CSD_READ_BL_PARTIAL(resp) MMC_RSP_BITS((resp), 79, 1)
|
||||
#define SD_CSD_WRITE_BLK_MISALIGN(resp) MMC_RSP_BITS((resp), 78, 1)
|
||||
#define SD_CSD_READ_BLK_MISALIGN(resp) MMC_RSP_BITS((resp), 77, 1)
|
||||
#define SD_CSD_DSR_IMP(resp) MMC_RSP_BITS((resp), 76, 1)
|
||||
#define SD_CSD_C_SIZE(resp) MMC_RSP_BITS((resp), 62, 12)
|
||||
#define SD_CSD_CAPACITY(resp) ((SD_CSD_C_SIZE((resp))+1) << \
|
||||
#define SD_CSD_DSR_IMP(resp) MMC_RSP_BITS((resp), 76, 1)
|
||||
#define SD_CSD_C_SIZE(resp) MMC_RSP_BITS((resp), 62, 12)
|
||||
#define SD_CSD_CAPACITY(resp) ((SD_CSD_C_SIZE((resp))+1) << \
|
||||
(SD_CSD_C_SIZE_MULT((resp))+2))
|
||||
#define SD_CSD_VDD_R_CURR_MIN(resp) MMC_RSP_BITS((resp), 59, 3)
|
||||
#define SD_CSD_VDD_R_CURR_MAX(resp) MMC_RSP_BITS((resp), 56, 3)
|
||||
#define SD_CSD_VDD_W_CURR_MIN(resp) MMC_RSP_BITS((resp), 53, 3)
|
||||
#define SD_CSD_VDD_W_CURR_MAX(resp) MMC_RSP_BITS((resp), 50, 3)
|
||||
#define SD_CSD_VDD_RW_CURR_100mA 0x7
|
||||
#define SD_CSD_VDD_RW_CURR_80mA 0x6
|
||||
#define SD_CSD_V2_C_SIZE(resp) MMC_RSP_BITS((resp), 48, 22)
|
||||
#define SD_CSD_V2_CAPACITY(resp) ((SD_CSD_V2_C_SIZE((resp))+1) << 10)
|
||||
#define SD_CSD_V2_BL_LEN 0x9 /* 512 */
|
||||
#define SD_CSD_C_SIZE_MULT(resp) MMC_RSP_BITS((resp), 47, 3)
|
||||
#define SD_CSD_ERASE_BLK_EN(resp) MMC_RSP_BITS((resp), 46, 1)
|
||||
#define SD_CSD_SECTOR_SIZE(resp) MMC_RSP_BITS((resp), 39, 7) /* +1 */
|
||||
#define SD_CSD_WP_GRP_SIZE(resp) MMC_RSP_BITS((resp), 32, 7) /* +1 */
|
||||
#define SD_CSD_WP_GRP_ENABLE(resp) MMC_RSP_BITS((resp), 31, 1)
|
||||
#define SD_CSD_R2W_FACTOR(resp) MMC_RSP_BITS((resp), 26, 3)
|
||||
#define SD_CSD_WRITE_BL_LEN(resp) MMC_RSP_BITS((resp), 22, 4)
|
||||
#define SD_CSD_RW_BL_LEN_2G 0xa
|
||||
#define SD_CSD_RW_BL_LEN_1G 0x9
|
||||
#define SD_CSD_VDD_R_CURR_MIN(resp) MMC_RSP_BITS((resp), 59, 3)
|
||||
#define SD_CSD_VDD_R_CURR_MAX(resp) MMC_RSP_BITS((resp), 56, 3)
|
||||
#define SD_CSD_VDD_W_CURR_MIN(resp) MMC_RSP_BITS((resp), 53, 3)
|
||||
#define SD_CSD_VDD_W_CURR_MAX(resp) MMC_RSP_BITS((resp), 50, 3)
|
||||
#define SD_CSD_VDD_RW_CURR_100mA 0x7
|
||||
#define SD_CSD_VDD_RW_CURR_80mA 0x6
|
||||
#define SD_CSD_V2_C_SIZE(resp) MMC_RSP_BITS((resp), 48, 22)
|
||||
#define SD_CSD_V2_CAPACITY(resp) ((SD_CSD_V2_C_SIZE((resp))+1) << 10)
|
||||
#define SD_CSD_V2_BL_LEN 0x9 /* 512 */
|
||||
#define SD_CSD_C_SIZE_MULT(resp) MMC_RSP_BITS((resp), 47, 3)
|
||||
#define SD_CSD_ERASE_BLK_EN(resp) MMC_RSP_BITS((resp), 46, 1)
|
||||
#define SD_CSD_SECTOR_SIZE(resp) MMC_RSP_BITS((resp), 39, 7) /* +1 */
|
||||
#define SD_CSD_WP_GRP_SIZE(resp) MMC_RSP_BITS((resp), 32, 7) /* +1 */
|
||||
#define SD_CSD_WP_GRP_ENABLE(resp) MMC_RSP_BITS((resp), 31, 1)
|
||||
#define SD_CSD_R2W_FACTOR(resp) MMC_RSP_BITS((resp), 26, 3)
|
||||
#define SD_CSD_WRITE_BL_LEN(resp) MMC_RSP_BITS((resp), 22, 4)
|
||||
#define SD_CSD_RW_BL_LEN_2G 0xa
|
||||
#define SD_CSD_RW_BL_LEN_1G 0x9
|
||||
#define SD_CSD_WRITE_BL_PARTIAL(resp) MMC_RSP_BITS((resp), 21, 1)
|
||||
#define SD_CSD_FILE_FORMAT_GRP(resp) MMC_RSP_BITS((resp), 15, 1)
|
||||
#define SD_CSD_COPY(resp) MMC_RSP_BITS((resp), 14, 1)
|
||||
#define SD_CSD_COPY(resp) MMC_RSP_BITS((resp), 14, 1)
|
||||
#define SD_CSD_PERM_WRITE_PROTECT(resp) MMC_RSP_BITS((resp), 13, 1)
|
||||
#define SD_CSD_TMP_WRITE_PROTECT(resp) MMC_RSP_BITS((resp), 12, 1)
|
||||
#define SD_CSD_FILE_FORMAT(resp) MMC_RSP_BITS((resp), 10, 2)
|
||||
#define SD_CSD_FILE_FORMAT(resp) MMC_RSP_BITS((resp), 10, 2)
|
||||
|
||||
/* SD R2 response (CID) */
|
||||
#define SD_CID_MID(resp) MMC_RSP_BITS((resp), 120, 8)
|
||||
@@ -294,22 +294,22 @@
|
||||
#define SD_CID_MDT(resp) MMC_RSP_BITS((resp), 8, 12)
|
||||
|
||||
/* SCR (SD Configuration Register) */
|
||||
#define SCR_STRUCTURE(scr) MMC_RSP_BITS((scr), 60, 4)
|
||||
#define SCR_STRUCTURE_VER_1_0 0 /* Version 1.0 */
|
||||
#define SCR_SD_SPEC(scr) MMC_RSP_BITS((scr), 56, 4)
|
||||
#define SCR_SD_SPEC_VER_1_0 0 /* Version 1.0 and 1.01 */
|
||||
#define SCR_SD_SPEC_VER_1_10 1 /* Version 1.10 */
|
||||
#define SCR_SD_SPEC_VER_2 2 /* Version 2.00 or Version 3.0X */
|
||||
#define SCR_STRUCTURE(scr) MMC_RSP_BITS((scr), 60, 4)
|
||||
#define SCR_STRUCTURE_VER_1_0 0 /* Version 1.0 */
|
||||
#define SCR_SD_SPEC(scr) MMC_RSP_BITS((scr), 56, 4)
|
||||
#define SCR_SD_SPEC_VER_1_0 0 /* Version 1.0 and 1.01 */
|
||||
#define SCR_SD_SPEC_VER_1_10 1 /* Version 1.10 */
|
||||
#define SCR_SD_SPEC_VER_2 2 /* Version 2.00 or Version 3.0X */
|
||||
#define SCR_DATA_STAT_AFTER_ERASE(scr) MMC_RSP_BITS((scr), 55, 1)
|
||||
#define SCR_SD_SECURITY(scr) MMC_RSP_BITS((scr), 52, 3)
|
||||
#define SCR_SD_SECURITY_NONE 0 /* no security */
|
||||
#define SCR_SD_SECURITY_1_0 1 /* security protocol 1.0 */
|
||||
#define SCR_SD_SECURITY_1_0_2 2 /* security protocol 1.0 */
|
||||
#define SCR_SD_BUS_WIDTHS(scr) MMC_RSP_BITS((scr), 48, 4)
|
||||
#define SCR_SD_BUS_WIDTHS_1BIT (1 << 0) /* 1bit (DAT0) */
|
||||
#define SCR_SD_BUS_WIDTHS_4BIT (1 << 2) /* 4bit (DAT0-3) */
|
||||
#define SCR_RESERVED(scr) MMC_RSP_BITS((scr), 32, 16)
|
||||
#define SCR_RESERVED2(scr) MMC_RSP_BITS((scr), 0, 32)
|
||||
#define SCR_SD_SECURITY(scr) MMC_RSP_BITS((scr), 52, 3)
|
||||
#define SCR_SD_SECURITY_NONE 0 /* no security */
|
||||
#define SCR_SD_SECURITY_1_0 1 /* security protocol 1.0 */
|
||||
#define SCR_SD_SECURITY_1_0_2 2 /* security protocol 1.0 */
|
||||
#define SCR_SD_BUS_WIDTHS(scr) MMC_RSP_BITS((scr), 48, 4)
|
||||
#define SCR_SD_BUS_WIDTHS_1BIT (1 << 0) /* 1bit (DAT0) */
|
||||
#define SCR_SD_BUS_WIDTHS_4BIT (1 << 2) /* 4bit (DAT0-3) */
|
||||
#define SCR_RESERVED(scr) MMC_RSP_BITS((scr), 32, 16)
|
||||
#define SCR_RESERVED2(scr) MMC_RSP_BITS((scr), 0, 32)
|
||||
|
||||
/* Status of Switch Function */
|
||||
#define SFUNC_STATUS_GROUP(status, group) \
|
||||
|
||||
@@ -28,27 +28,29 @@ PROTO= proto
|
||||
# Common to all architectures
|
||||
ETC= system.conf group
|
||||
EXTRA= rc
|
||||
PROTO_FILES= proto.common.etc
|
||||
PROTO_FILES+= proto.common.dynamic
|
||||
PROTO_FILES= proto.common.etc
|
||||
PROTO_FILES+= proto.common.dynamic
|
||||
PROGRAMS= # defined
|
||||
PROGRAMS+= fsck_mfs
|
||||
dir.fsck_mfs:= minix/commands/fsck.mfs
|
||||
PROGRAMS+= grep
|
||||
dir.grep:= minix/usr.bin/grep
|
||||
dir.grep:= minix/usr.bin/grep
|
||||
PROGRAMS+= dd
|
||||
dir.dd:= bin/dd
|
||||
PROGRAMS+= input
|
||||
dir.input:= minix/servers/input
|
||||
dir.input:= minix/servers/input
|
||||
PROGRAMS+= loadramdisk
|
||||
dir.loadramdisk:= minix/commands/loadramdisk
|
||||
PROGRAMS+= mfs
|
||||
dir.mfs:= minix/fs/mfs
|
||||
dir.mfs:= minix/fs/mfs
|
||||
PROGRAMS+= mount
|
||||
dir.mount:= minix/commands/mount
|
||||
dir.mount:= minix/commands/mount
|
||||
PROGRAMS+= procfs
|
||||
dir.procfs:= minix/fs/procfs
|
||||
PROGRAMS+= service
|
||||
dir.service:= minix/commands/service
|
||||
PROGRAMS+= sh
|
||||
dir.sh:= bin/sh
|
||||
dir.sh:= bin/sh
|
||||
PROGRAMS+= sysenv
|
||||
dir.sysenv:= minix/commands/sysenv
|
||||
PROGRAMS+= umount
|
||||
@@ -65,9 +67,9 @@ dir.at_wini:= minix/drivers/storage/at_wini
|
||||
PROGRAMS+= floppy
|
||||
dir.floppy:= minix/drivers/storage/floppy
|
||||
PROGRAMS+= pci
|
||||
dir.pci:= minix/drivers/bus/pci
|
||||
dir.pci:= minix/drivers/bus/pci
|
||||
PROGRAMS+= pckbd
|
||||
dir.pckbd:= minix/drivers/hid/pckbd
|
||||
dir.pckbd:= minix/drivers/hid/pckbd
|
||||
PROGRAMS+= cdprobe
|
||||
dir.cdprobe:= minix/commands/cdprobe
|
||||
PROGRAMS+= pwd_mkdb
|
||||
@@ -77,23 +79,27 @@ dir.isofs:= minix/fs/isofs
|
||||
|
||||
.if ${MKSMALL} != "yes"
|
||||
PROGRAMS+= ahci
|
||||
dir.ahci:= minix/drivers/storage/ahci
|
||||
dir.ahci:= minix/drivers/storage/ahci
|
||||
PROGRAMS+= virtio_blk
|
||||
dir.virtio_blk:= minix/drivers/storage/virtio_blk
|
||||
PROGRAMS+= ext2
|
||||
dir.ext2:= minix/fs/ext2
|
||||
dir.ext2:= minix/fs/ext2
|
||||
.endif
|
||||
|
||||
.if ${MKACPI} != "no"
|
||||
RAMDISK_INC_ACPI= 1
|
||||
PROGRAMS+= acpi
|
||||
dir.acpi:= minix/drivers/power/acpi
|
||||
dir.acpi:= minix/drivers/power/acpi
|
||||
.endif
|
||||
.endif # ${MACHINE_ARCH} == "i386"
|
||||
|
||||
.if ${MACHINE_ARCH} == "earm"
|
||||
PROGRAMS+= mmc
|
||||
dir.mmc:= minix/drivers/storage/mmc
|
||||
PROGRAMS+= omap_mmc
|
||||
dir.omap_mmc:= minix/drivers/storage/mmc
|
||||
PROGRAMS+= rpi_mmc
|
||||
dir.rpi_mmc:= minix/drivers/storage/mmc
|
||||
PROGRAMS+= mailbox
|
||||
dir.mailbox:= minix/drivers/system/mailbox
|
||||
.endif # ${MACHINE_ARCH} == "earm"
|
||||
|
||||
.if ${LDSTATIC} == "-dynamic"
|
||||
|
||||
@@ -12,6 +12,7 @@ d--755 0 0
|
||||
mount ---755 0 0 mount
|
||||
umount ---755 0 0 umount
|
||||
grep ---755 0 0 grep
|
||||
dd ---755 0 0 dd
|
||||
sh ---755 0 0 sh
|
||||
service ---755 0 0 service
|
||||
$
|
||||
@@ -28,7 +29,9 @@ d--755 0 0
|
||||
isofs ---755 0 0 isofs
|
||||
#endif
|
||||
#ifdef __arm__
|
||||
mmc ---755 0 0 mmc
|
||||
rpi_mmc ---755 0 0 rpi_mmc
|
||||
omap_mmc ---755 0 0 omap_mmc
|
||||
mailbox ---755 0 0 mailbox
|
||||
#endif
|
||||
mfs ---755 0 0 mfs
|
||||
procfs ---755 0 0 procfs
|
||||
|
||||
@@ -3,7 +3,7 @@ set -e
|
||||
|
||||
exec >/dev/log
|
||||
exec 2>/dev/log
|
||||
exec </dev/null
|
||||
exec </dev/console
|
||||
|
||||
FSCK=/bin/fsck_mfs
|
||||
ACPI=/service/acpi
|
||||
@@ -47,7 +47,7 @@ fi
|
||||
|
||||
if [ X`/bin/sysenv arch` = Xearm ]
|
||||
then echo Starting the mmc driver
|
||||
/bin/service -c up /service/mmc -dev /dev/c0d0
|
||||
/bin/service -c up /service/rpi_mmc -args "log_level=5" -dev /dev/c0d0
|
||||
fi
|
||||
|
||||
/bin/service up /service/procfs || echo "WARNING: couldn't start procfs"
|
||||
@@ -88,7 +88,7 @@ fi
|
||||
|
||||
echo "Root device name is $rootdevname"
|
||||
|
||||
if ! sysenv cdproberoot >/dev/null
|
||||
if (! sysenv cdproberoot) && (! sysenv bootramdisk) >/dev/null
|
||||
then
|
||||
if [ -e $FSCK ]
|
||||
then $FSCK -p $rootdevname
|
||||
@@ -104,6 +104,12 @@ fi
|
||||
|
||||
/bin/mount -e -n -t procfs none /proc || echo "WARNING: couldn't mount procfs"
|
||||
|
||||
# XXX: We don't have anything better to do on Raspberry Pi yet
|
||||
if [ "$(/bin/sysenv board_name)" = "RPI_2_B" ] || [ "$(/bin/sysenv board_name)" = "RPI_3_B" ]
|
||||
then
|
||||
exec /bin/sh < /dev/console
|
||||
fi
|
||||
|
||||
if ! sysenv bootramdisk >/dev/null
|
||||
then
|
||||
exec /bin/sh /etc/rc `sysenv bootopts` "$@"
|
||||
|
||||
@@ -6,5 +6,6 @@ SUBDIR+= gpio
|
||||
|
||||
SUBDIR+= log
|
||||
SUBDIR+= random
|
||||
SUBDIR+= mailbox
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
|
||||
@@ -205,7 +205,16 @@ init_hook(void)
|
||||
CONTROL_CONF_PUDEN | CONTROL_CONF_MUXMODE(7)));
|
||||
|
||||
add_gpio_inode("RIGHT", (32 * 1) + 17, GPIO_MODE_INPUT);
|
||||
} else if (BOARD_IS_RPI_2_B(machine.board_id) || BOARD_IS_RPI_3_B(machine.board_id)) {
|
||||
/* Export GPIO 26 as SLIDE_PREV */
|
||||
add_gpio_inode("SLIDE_PREV", 26, GPIO_MODE_INPUT);
|
||||
/* Export GPIO 21 as SLIDE_NEXT */
|
||||
add_gpio_inode("SLIDE_NEXT", 21, GPIO_MODE_INPUT);
|
||||
|
||||
/* Put both of them in pull-up */
|
||||
sys_padconf(0x94, 0x3, 2);
|
||||
sys_padconf(0x98, 0xffffffff, (1<<26)|(1<<21));
|
||||
sys_padconf(0x98, 0xffffffff, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
14
minix/drivers/system/mailbox/Makefile
Normal file
14
minix/drivers/system/mailbox/Makefile
Normal file
@@ -0,0 +1,14 @@
|
||||
# Makefile for the mailbox driver.
|
||||
PROG= mailbox
|
||||
SRCS= mbox.c main.c
|
||||
|
||||
FILESNAME=${PROG}
|
||||
FILESDIR= /etc/system.conf.d
|
||||
|
||||
DPADD+= ${LIBCHARDRIVER} ${LIBSYS}
|
||||
LDADD+= -lchardriver -lsys
|
||||
|
||||
# This is a system driver.
|
||||
CPPFLAGS+= -D_SYSTEM=1
|
||||
|
||||
.include <minix.service.mk>
|
||||
208
minix/drivers/system/mailbox/main.c
Normal file
208
minix/drivers/system/mailbox/main.c
Normal file
@@ -0,0 +1,208 @@
|
||||
#include <minix/drivers.h>
|
||||
#include <minix/chardriver.h>
|
||||
#include <minix/type.h>
|
||||
#include <minix/vm.h>
|
||||
#include <sys/mman.h>
|
||||
#include <minix/log.h>
|
||||
|
||||
#include "mbox.h"
|
||||
|
||||
#define NR_DEVS 1 /* number of minor devices */
|
||||
#define MAILBOX_DEV 0 /* minor device for /dev/mailbox */
|
||||
|
||||
#define SANE_TIMEOUT 500000 /* 500 ms */
|
||||
|
||||
#define MBOX_IRQ 33
|
||||
|
||||
/* SEF functions and variables. */
|
||||
static void sef_local_startup(void);
|
||||
static int sef_cb_init_fresh(int type, sef_init_info_t *info);
|
||||
|
||||
static ssize_t m_read(devminor_t minor, u64_t position, endpoint_t endpt,
|
||||
cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
|
||||
static ssize_t m_write(devminor_t minor, u64_t position, endpoint_t endpt,
|
||||
cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
|
||||
static int m_open(devminor_t minor, int access, endpoint_t user_endpt);
|
||||
static int m_select(devminor_t, unsigned int, endpoint_t);
|
||||
|
||||
static u8_t* mboxbuffer_vir; /* Address of dss phys memory map */
|
||||
static phys_bytes mboxbuffer_phys;
|
||||
|
||||
/* Entry points to this driver. */
|
||||
static struct chardriver m_dtab = {
|
||||
.cdr_open = m_open, /* open device */
|
||||
.cdr_read = m_read, /* read from device */
|
||||
.cdr_write = m_write, /* write to device (seeding it) */
|
||||
.cdr_select = m_select, /* select hook */
|
||||
};
|
||||
|
||||
static struct log log = {
|
||||
.name = "mailbox",
|
||||
.log_level = LEVEL_INFO,
|
||||
.log_func = default_log
|
||||
};
|
||||
|
||||
/*===========================================================================*
|
||||
* main *
|
||||
*===========================================================================*/
|
||||
int main(void)
|
||||
{
|
||||
/* SEF local startup. */
|
||||
sef_local_startup();
|
||||
|
||||
/* Call the generic receive loop. */
|
||||
chardriver_task(&m_dtab);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* sef_local_startup *
|
||||
*===========================================================================*/
|
||||
static void sef_local_startup()
|
||||
{
|
||||
/* Register init callbacks. */
|
||||
sef_setcb_init_fresh(sef_cb_init_fresh);
|
||||
sef_setcb_init_restart(sef_cb_init_fresh);
|
||||
|
||||
/* Let SEF perform startup. */
|
||||
sef_startup();
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* sef_cb_init_fresh *
|
||||
*===========================================================================*/
|
||||
static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
|
||||
{
|
||||
/* Initialize the random driver. */
|
||||
static struct k_randomness krandom;
|
||||
int i, s;
|
||||
|
||||
mailbox_init();
|
||||
|
||||
int hook_id = 1;
|
||||
if (sys_irqsetpolicy(MBOX_IRQ, 0, &hook_id) != OK) {
|
||||
log_warn(&log, "mailbox: couldn't set IRQ policy %d\n",
|
||||
MBOX_IRQ);
|
||||
return(EPERM);
|
||||
}
|
||||
|
||||
mbox_flush();
|
||||
|
||||
/* Configure mailbox buffer */
|
||||
mboxbuffer_vir = (u8_t*) alloc_contig(0x1000, 0, &mboxbuffer_phys);
|
||||
if (mboxbuffer_vir == (u8_t*) MAP_FAILED) {
|
||||
panic("Unable to allocate contiguous memory for mailbox buffer\n");
|
||||
}
|
||||
|
||||
/* Announce we are up! */
|
||||
chardriver_announce();
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
static ssize_t m_read(devminor_t minor, u64_t position, endpoint_t endpt,
|
||||
cp_grant_id_t grant, size_t size, int flags, cdev_id_t id)
|
||||
{
|
||||
/* Read from one of the driver's minor devices. */
|
||||
size_t offset, chunk;
|
||||
int r;
|
||||
|
||||
if (minor != MAILBOX_DEV)
|
||||
return(EIO);
|
||||
|
||||
mbox_read(MBOX_PROP);
|
||||
r = sys_safecopyto(endpt, grant, 0, (vir_bytes)mboxbuffer_vir, size);
|
||||
if (r != OK) {
|
||||
log_warn(&log, "mailbox: sys_safecopyto failed for proc %d, grant %d\n",
|
||||
endpt, grant);
|
||||
return r;
|
||||
}
|
||||
|
||||
mbox_flush();
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
static int hook_id = 1;
|
||||
|
||||
static int wait_irq()
|
||||
{
|
||||
if (sys_irqenable(&hook_id) != OK)
|
||||
log_warn(&log, "Failed to enable irq\n");
|
||||
|
||||
/* Wait for a task completion interrupt. */
|
||||
message m;
|
||||
int ipc_status;
|
||||
int ticks = SANE_TIMEOUT * sys_hz() / 1000000;
|
||||
|
||||
if (ticks <= 0)
|
||||
ticks = 1;
|
||||
while (1) {
|
||||
int rr;
|
||||
sys_setalarm(ticks, 0);
|
||||
if ((rr = driver_receive(ANY, &m, &ipc_status)) != OK) {
|
||||
panic("driver_receive failed: %d", rr);
|
||||
};
|
||||
if (is_ipc_notify(ipc_status)) {
|
||||
switch (_ENDPOINT_P(m.m_source)) {
|
||||
case CLOCK:
|
||||
/* Timeout. */
|
||||
log_warn(&log, "TIMEOUT\n");
|
||||
return -1;
|
||||
break;
|
||||
case HARDWARE:
|
||||
log_debug(&log, "HARDWARE\n");
|
||||
sys_setalarm(0, 0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
sys_setalarm(0, 0); /* cancel the alarm */
|
||||
|
||||
}
|
||||
|
||||
static ssize_t m_write(devminor_t minor, u64_t position, endpoint_t endpt,
|
||||
cp_grant_id_t grant, size_t size, int flags, cdev_id_t id)
|
||||
{
|
||||
/* Write to one of the driver's minor devices. */
|
||||
int r;
|
||||
uint32_t msg;
|
||||
|
||||
|
||||
if (minor != MAILBOX_DEV)
|
||||
return(EIO);
|
||||
|
||||
r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes)mboxbuffer_vir, size);
|
||||
if (r != OK) {
|
||||
log_warn(&log, "mailbox: sys_safecopyfrom failed for proc %d,"
|
||||
" grant %d\n", endpt, grant);
|
||||
return r;
|
||||
}
|
||||
mbox_write(MBOX_PROP, (uint32_t)mboxbuffer_phys + 0x40000000);
|
||||
|
||||
if (wait_irq() < 0) {
|
||||
log_warn(&log, "can't wait interrupt from mbox\n");
|
||||
return(ETIME);
|
||||
}
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
static int m_open(devminor_t minor, int access, endpoint_t user_endpt)
|
||||
{
|
||||
if (minor < 0 || minor >= NR_DEVS)
|
||||
return(ENXIO);
|
||||
}
|
||||
|
||||
static int m_select(devminor_t minor, unsigned int ops, endpoint_t endpt)
|
||||
{
|
||||
/* mailbox device is always writable; it's infinitely readable
|
||||
* once seeded, and doesn't block when it's not, so all operations
|
||||
* are instantly possible. we ignore CDEV_OP_ERR.
|
||||
*/
|
||||
int ready_ops = 0;
|
||||
if (minor != MAILBOX_DEV)
|
||||
return(EIO);
|
||||
return ops & (CDEV_OP_RD | CDEV_OP_WR);
|
||||
}
|
||||
111
minix/drivers/system/mailbox/mbox.c
Normal file
111
minix/drivers/system/mailbox/mbox.c
Normal file
@@ -0,0 +1,111 @@
|
||||
#include <minix/drivers.h>
|
||||
#include <minix/chardriver.h>
|
||||
#include <minix/type.h>
|
||||
#include <minix/log.h>
|
||||
#include <minix/vm.h>
|
||||
#include <minix/spin.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "mbox.h"
|
||||
|
||||
struct mailbox_t mailbox = {
|
||||
.read = 0x00,
|
||||
.res1 = 0x04,
|
||||
.res2 = 0x08,
|
||||
.res3 = 0x0c,
|
||||
.peek = 0x10,
|
||||
.sender = 0x14,
|
||||
.status = 0x18,
|
||||
.config = 0x1c,
|
||||
.write = 0x20
|
||||
};
|
||||
|
||||
struct mailbox_t *gmailbox;
|
||||
|
||||
uint32_t mbox_base;
|
||||
/*
|
||||
* Define a structure to be used for logging
|
||||
*/
|
||||
static struct log log = {
|
||||
.name = "mailbox",
|
||||
.log_level = LEVEL_INFO,
|
||||
.log_func = default_log
|
||||
};
|
||||
|
||||
static void write32(vir_bytes reg, uint32_t data)
|
||||
{
|
||||
assert(reg >= 0 && reg <= sizeof (struct mailbox_t));
|
||||
*(volatile uint32_t *)(mbox_base + reg) = data;
|
||||
}
|
||||
|
||||
static uint32_t read32(vir_bytes reg)
|
||||
{
|
||||
assert(reg >= 0 && reg <= sizeof (struct mailbox_t));
|
||||
return *(volatile uint32_t *)(mbox_base + reg);
|
||||
}
|
||||
|
||||
void mailbox_init()
|
||||
{
|
||||
uint32_t value;
|
||||
value = 0;
|
||||
struct minix_mem_range mr;
|
||||
|
||||
mr.mr_base = MBOX_BASE;
|
||||
mr.mr_limit = MBOX_BASE + 0x1000;
|
||||
|
||||
/* grant ourself rights to map the register memory */
|
||||
if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) {
|
||||
panic("Unable to request permission to map memory");
|
||||
}
|
||||
|
||||
/* Set the base address to use */
|
||||
mbox_base =
|
||||
(uint32_t) vm_map_phys(SELF, (void *) MBOX_BASE,
|
||||
0x1000);
|
||||
|
||||
if (mbox_base == (uint32_t) MAP_FAILED)
|
||||
panic("Unable to map MMC memory");
|
||||
|
||||
gmailbox = &mailbox;
|
||||
|
||||
write32(gmailbox->config, IRQ_EN);
|
||||
}
|
||||
|
||||
uint32_t mbox_read(uint8_t chan)
|
||||
{
|
||||
uint32_t data = 0;
|
||||
while (1) {
|
||||
while (read32(gmailbox->status) & MAILBOX_EMPTY)
|
||||
log_debug(&log, "status: 0x%x\n", read32(gmailbox->status));
|
||||
|
||||
log_info(&log, "0x%08x\n", read32(gmailbox->status));
|
||||
data = read32(gmailbox->read);
|
||||
|
||||
log_debug(&log, "received data %d\n", data);
|
||||
|
||||
if (((uint8_t) data & 0xf) == chan) {
|
||||
return (data & ~0xf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mbox_write(uint8_t chan, uint32_t data)
|
||||
{
|
||||
while (read32(gmailbox->status) & MAILBOX_FULL);
|
||||
|
||||
write32(gmailbox->write, (data & ~0xf) | (uint32_t) (chan & 0xf));
|
||||
}
|
||||
|
||||
void mbox_flush(void)
|
||||
{
|
||||
spin_t spin;
|
||||
while (!(read32(gmailbox->status) & MAILBOX_EMPTY)) {
|
||||
spin_init(&spin, 20000);
|
||||
while (1) {
|
||||
if(spin_check(&spin) == FALSE)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
140
minix/drivers/system/mailbox/mbox.h
Normal file
140
minix/drivers/system/mailbox/mbox.h
Normal file
@@ -0,0 +1,140 @@
|
||||
#ifndef _MBOX_H_
|
||||
#define _MBOX_H_
|
||||
|
||||
#define MBOX_BASE (0x3f000000 + 0xb880)
|
||||
|
||||
struct mailbox_t {
|
||||
vir_bytes read;
|
||||
vir_bytes res1;
|
||||
vir_bytes res2;
|
||||
vir_bytes res3;
|
||||
vir_bytes peek;
|
||||
vir_bytes sender;
|
||||
vir_bytes status;
|
||||
vir_bytes config;
|
||||
vir_bytes write;
|
||||
};
|
||||
|
||||
enum mail_chan {
|
||||
MBOX_POWER,
|
||||
MBOX_FRAMEBUFFER,
|
||||
MBOX_UART,
|
||||
MBOX_VCHIQ,
|
||||
MBOX_LEDS,
|
||||
MBOX_BUTTONS,
|
||||
MBOX_TOUCH,
|
||||
MBOX_NUSED,
|
||||
MBOX_PROP,
|
||||
MBOX_REVPROP
|
||||
};
|
||||
|
||||
void mailbox_init();
|
||||
|
||||
uint32_t mbox_read(uint8_t chan);
|
||||
|
||||
void mbox_write(uint8_t chan, uint32_t data);
|
||||
|
||||
void mbox_flush();
|
||||
|
||||
#define IRQ_EN (0x1 << 0)
|
||||
|
||||
#define MAILBOX_FULL 0x80000000
|
||||
#define MAILBOX_EMPTY 0x40000000
|
||||
#define MBX_TAG_GET_BOARD_MODEL 0x00010001
|
||||
#define MBX_TAG_GET_BOARD_REVISION 0x00010002
|
||||
|
||||
// Timers interrupt control registers
|
||||
#define CORE0_TIMER_IRQCNTL 0x40000040
|
||||
#define CORE1_TIMER_IRQCNTL 0x40000044
|
||||
#define CORE2_TIMER_IRQCNTL 0x40000048
|
||||
#define CORE3_TIMER_IRQCNTL 0x4000004C
|
||||
|
||||
// Where to route timer interrupt to, IRQ/FIQ
|
||||
// Setting both the IRQ and FIQ bit gives an FIQ
|
||||
#define TIMER0_IRQ 0x01
|
||||
#define TIMER1_IRQ 0x02
|
||||
#define TIMER2_IRQ 0x04
|
||||
#define TIMER3_IRQ 0x08
|
||||
#define TIMER0_FIQ 0x10
|
||||
#define TIMER1_FIQ 0x20
|
||||
#define TIMER2_FIQ 0x40
|
||||
#define TIMER3_FIQ 0x80
|
||||
|
||||
// Mailbox interrupt control registers
|
||||
#define CORE0_MBOX_IRQCNTL 0x40000050
|
||||
#define CORE1_MBOX_IRQCNTL 0x40000054
|
||||
#define CORE2_MBOX_IRQCNTL 0x40000058
|
||||
#define CORE3_MBOX_IRQCNTL 0x4000005C
|
||||
|
||||
// Where to route mailbox interrupt to, IRQ/FIQ
|
||||
// Setting both the IRQ and FIQ bit gives an FIQ
|
||||
#define MBOX0_IRQ 0x01
|
||||
#define MBOX1_IRQ 0x02
|
||||
#define MBOX2_IRQ 0x04
|
||||
#define MBOX3_IRQ 0x08
|
||||
#define MBOX0_FIQ 0x10
|
||||
#define MBOX1_FIQ 0x20
|
||||
#define MBOX2_FIQ 0x40
|
||||
#define MBOX3_FIQ 0x80
|
||||
|
||||
// IRQ & FIQ
|
||||
#define CORE0_IRQ_SOURCE 0x40000060
|
||||
#define CORE1_IRQ_SOURCE 0x40000064
|
||||
#define CORE2_IRQ_SOURCE 0x40000068
|
||||
#define CORE3_IRQ_SOURCE 0x4000006C
|
||||
#define CORE0_FIQ_SOURCE 0x40000070
|
||||
#define CORE1_FIQ_SOURCE 0x40000074
|
||||
#define CORE2_FIQ_SOURCE 0x40000078
|
||||
#define CORE3_FIQ_SOURCE 0x4000007C
|
||||
|
||||
// Interrupt source bits
|
||||
// IRQ and FIQ are the same
|
||||
// GPU bits can be set
|
||||
#define INT_SRC_TIMER0 0x00000001
|
||||
#define INT_SRC_TIMER1 0x00000002
|
||||
#define INT_SRC_TIMER2 0x00000004
|
||||
#define INT_SRC_TIMER3 0x00000008
|
||||
#define INT_SRC_MBOX0 0x00000010
|
||||
#define INT_SRC_MBOX1 0x00000020
|
||||
#define INT_SRC_MBOX2 0x00000040
|
||||
#define INT_SRC_MBOX3 0x00000080
|
||||
#define INT_SRC_GPU 0x00000100
|
||||
#define INT_SRC_PMU 0x00000200
|
||||
|
||||
// Mailbox write
|
||||
#define CORE0_MBOX0_SET 0x40000080
|
||||
#define CORE0_MBOX1_SET 0x40000084
|
||||
#define CORE0_MBOX2_SET 0x40000088
|
||||
#define CORE0_MBOX3_SET 0x4000008C
|
||||
#define CORE1_MBOX0_SET 0x40000090
|
||||
#define CORE1_MBOX1_SET 0x40000094
|
||||
#define CORE1_MBOX2_SET 0x40000098
|
||||
#define CORE1_MBOX3_SET 0x4000009C
|
||||
#define CORE2_MBOX0_SET 0x400000A0
|
||||
#define CORE2_MBOX1_SET 0x400000A4
|
||||
#define CORE2_MBOX2_SET 0x400000A8
|
||||
#define CORE2_MBOX3_SET 0x400000AC
|
||||
#define CORE3_MBOX0_SET 0x400000B0
|
||||
#define CORE3_MBOX1_SET 0x400000B4
|
||||
#define CORE3_MBOX2_SET 0x400000B8
|
||||
#define CORE3_MBOX3_SET 0x400000BC
|
||||
|
||||
// Mailbox write (Read & Write)
|
||||
#define CORE0_MBOX0_RDCLR 0x400000C0
|
||||
#define CORE0_MBOX1_RDCLR 0x400000C4
|
||||
#define CORE0_MBOX2_RDCLR 0x400000C8
|
||||
#define CORE0_MBOX3_RDCLR 0x400000CC
|
||||
#define CORE1_MBOX0_RDCLR 0x400000D0
|
||||
#define CORE1_MBOX1_RDCLR 0x400000D4
|
||||
#define CORE1_MBOX2_RDCLR 0x400000D8
|
||||
#define CORE1_MBOX3_RDCLR 0x400000DC
|
||||
#define CORE2_MBOX0_RDCLR 0x400000E0
|
||||
#define CORE2_MBOX1_RDCLR 0x400000E4
|
||||
#define CORE2_MBOX2_RDCLR 0x400000E8
|
||||
#define CORE2_MBOX3_RDCLR 0x400000EC
|
||||
#define CORE3_MBOX0_RDCLR 0x400000F0
|
||||
#define CORE3_MBOX1_RDCLR 0x400000F4
|
||||
#define CORE3_MBOX2_RDCLR 0x400000F8
|
||||
#define CORE3_MBOX3_RDCLR 0x400000FC
|
||||
|
||||
#endif /* _MBOX_H_ */
|
||||
@@ -4,4 +4,12 @@
|
||||
HERE=${.CURDIR}/arch/${MACHINE_ARCH}
|
||||
.PATH: ${HERE}
|
||||
|
||||
SRCS += console.c keyboard.c rs232.c
|
||||
SRCS += console.c keyboard.c
|
||||
|
||||
.if ${BSP_NAME} == rpi
|
||||
SRCS += pl011.c
|
||||
.elif ${BSP_NAME} == omap
|
||||
SRCS += omap.c
|
||||
.else
|
||||
.error Unknown bsp ${BSP_NAME}
|
||||
.endif
|
||||
|
||||
604
minix/drivers/tty/tty/arch/earm/pl011.c
Normal file
604
minix/drivers/tty/tty/arch/earm/pl011.c
Normal file
@@ -0,0 +1,604 @@
|
||||
#include <minix/config.h>
|
||||
#include <minix/drivers.h>
|
||||
#include <minix/vm.h>
|
||||
#include <minix/type.h>
|
||||
#include <minix/board.h>
|
||||
#include <sys/mman.h>
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
#include <termios.h>
|
||||
#include "pl011_serial.h"
|
||||
#include "tty.h"
|
||||
|
||||
#if NR_RS_LINES > 0
|
||||
|
||||
#define UART_FREQ 48000000L /* timer frequency */
|
||||
#if 0
|
||||
#define DFLT_BAUD TSPEED_DEF /* default baud rate */
|
||||
#else
|
||||
#define DFLT_BAUD B115200 /* default baud rate */
|
||||
#endif
|
||||
|
||||
|
||||
#define RS_IBUFSIZE 40960 /* RS232 input buffer size */
|
||||
#define RS_OBUFSIZE 40960 /* RS232 output buffer size */
|
||||
|
||||
/* Input buffer watermarks.
|
||||
* The external device is asked to stop sending when the buffer
|
||||
* exactly reaches high water, or when TTY requests it. Sending restarts
|
||||
* when the input buffer empties below the low watermark.
|
||||
*/
|
||||
#define RS_ILOWWATER (1 * RS_IBUFSIZE / 4)
|
||||
#define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
|
||||
|
||||
/* Output buffer low watermark.
|
||||
* TTY is notified when the output buffer empties below the low watermark, so
|
||||
* it may continue filling the buffer if doing a large write.
|
||||
*/
|
||||
#define RS_OLOWWATER (1 * RS_OBUFSIZE / 4)
|
||||
|
||||
/* RS232 device structure, one per device. */
|
||||
typedef struct rs232 {
|
||||
tty_t *tty; /* associated TTY structure */
|
||||
|
||||
int icount; /* number of bytes in the input buffer */
|
||||
char *ihead; /* next free spot in input buffer */
|
||||
char *itail; /* first byte to give to TTY */
|
||||
char idevready; /* nonzero if we are ready to receive (RTS) */
|
||||
char cts; /* normally 0, but MS_CTS if CLOCAL is set */
|
||||
|
||||
unsigned char ostate; /* combination of flags: */
|
||||
#define ODONE 1 /* output completed (< output enable bits) */
|
||||
#define ORAW 2 /* raw mode for xoff disable (< enab. bits) */
|
||||
#define OWAKEUP 4 /* tty_wakeup() pending (asm code only) */
|
||||
#define ODEVREADY PL011_FR_CTS /* external device hardware ready (CTS) */
|
||||
#define OQUEUED 0x20 /* output buffer not empty */
|
||||
#define OSWREADY 0x40 /* external device software ready (no xoff) */
|
||||
#define ODEVHUP 0x80 /* external device has dropped carrier */
|
||||
#define OSOFTBITS (ODONE | ORAW | OWAKEUP | OQUEUED | OSWREADY)
|
||||
/* user-defined bits */
|
||||
#if (OSOFTBITS | ODEVREADY | ODEVHUP) == OSOFTBITS
|
||||
/* a weak sanity check */
|
||||
#error /* bits are not unique */
|
||||
#endif
|
||||
unsigned char oxoff; /* char to stop output */
|
||||
char inhibited; /* output inhibited? (follows tty_inhibited) */
|
||||
char drain; /* if set drain output and reconfigure line */
|
||||
int ocount; /* number of bytes in the output buffer */
|
||||
char *ohead; /* next free spot in output buffer */
|
||||
char *otail; /* next char to output */
|
||||
|
||||
phys_bytes phys_base; /* UART physical base address (I/O map) */
|
||||
unsigned int reg_offset; /* UART register offset */
|
||||
unsigned int uartclk; /* UART clock rate */
|
||||
int rx_overrun_events;
|
||||
|
||||
int irq; /* irq for this line */
|
||||
int irq_hook_id; /* interrupt hook */
|
||||
int irq_hook_kernel_id; /* id as returned from sys_irqsetpolicy */
|
||||
|
||||
char ibuf[RS_IBUFSIZE]; /* input buffer */
|
||||
char obuf[RS_OBUFSIZE]; /* output buffer */
|
||||
} rs232_t;
|
||||
|
||||
static rs232_t rs_lines[NR_RS_LINES];
|
||||
|
||||
typedef struct uart_port {
|
||||
phys_bytes base_addr;
|
||||
int irq;
|
||||
} uart_port_t;
|
||||
|
||||
static uart_port_t bcm2835_ports[] = {
|
||||
{ PL011_UART0_BASE, 121 }, /* UART0 */
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static int rs_write(tty_t *tp, int try);
|
||||
static void rs_echo(tty_t *tp, int c);
|
||||
static int rs_ioctl(tty_t *tp, int try);
|
||||
static void rs_config(rs232_t *rs);
|
||||
static int rs_read(tty_t *tp, int try);
|
||||
static int rs_icancel(tty_t *tp, int try);
|
||||
static int rs_ocancel(tty_t *tp, int try);
|
||||
static void rs_ostart(rs232_t *rs);
|
||||
static int rs_break_on(tty_t *tp, int try);
|
||||
static int rs_break_off(tty_t *tp, int try);
|
||||
static int rs_close(tty_t *tp, int try);
|
||||
static int rs_open(tty_t *tp, int try);
|
||||
static void rs232_handler(rs232_t *rs);
|
||||
static void rs_reset(rs232_t *rs);
|
||||
|
||||
static inline unsigned int readw(vir_bytes addr);
|
||||
static inline unsigned int serial_in(rs232_t *rs, int offset);
|
||||
static inline void serial_out(rs232_t *rs, int offset, int val);
|
||||
static inline void writew(vir_bytes addr, int val);
|
||||
static void write_chars(rs232_t *rs);
|
||||
static void read_chars(rs232_t *rs);
|
||||
|
||||
static inline unsigned int
|
||||
readw(vir_bytes addr)
|
||||
{
|
||||
return *((volatile unsigned int *) addr);
|
||||
}
|
||||
|
||||
static inline void
|
||||
writew(vir_bytes addr, int val)
|
||||
{
|
||||
*((volatile unsigned int *) addr) = val;
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
serial_in(rs232_t *rs, int offset)
|
||||
{
|
||||
offset <<= rs->reg_offset;
|
||||
return readw(rs->phys_base + offset);
|
||||
}
|
||||
|
||||
static inline void
|
||||
serial_out(rs232_t *rs, int offset, int val)
|
||||
{
|
||||
offset <<= rs->reg_offset;
|
||||
writew(rs->phys_base + offset, val);
|
||||
}
|
||||
|
||||
static void
|
||||
rs_reset(rs232_t *rs)
|
||||
{
|
||||
unsigned int fr;
|
||||
|
||||
fr = PL011_FR_RXFE | PL011_FR_TXFE | PL011_FR_CTS;
|
||||
|
||||
serial_out(rs, PL011_FR, fr);
|
||||
}
|
||||
|
||||
static int
|
||||
rs_write(register tty_t *tp, int try)
|
||||
{
|
||||
/* (*devwrite)() routine for RS232. */
|
||||
rs232_t *rs = tp->tty_priv;
|
||||
int r, count, ocount;
|
||||
|
||||
if (rs->inhibited != tp->tty_inhibited) {
|
||||
/* Inhibition state has changed. */
|
||||
rs->ostate |= OSWREADY;
|
||||
if (tp->tty_inhibited) rs->ostate &= ~OSWREADY;
|
||||
rs->inhibited = tp->tty_inhibited;
|
||||
}
|
||||
|
||||
if (rs->drain) {
|
||||
/* Wait for the line to drain then reconfigure and continue
|
||||
* output. */
|
||||
if (rs->ocount > 0) return 0;
|
||||
rs->drain = FALSE;
|
||||
rs_config(rs);
|
||||
}
|
||||
/* While there is something to do. */
|
||||
for (;;) {
|
||||
ocount = buflen(rs->obuf) - rs->ocount;
|
||||
count = bufend(rs->obuf) - rs->ohead;
|
||||
if (count > ocount) count = ocount;
|
||||
if (count > tp->tty_outleft) count = tp->tty_outleft;
|
||||
if (count == 0 || tp->tty_inhibited) {
|
||||
if (try) return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (try) return 1;
|
||||
|
||||
/* Copy from user space to the RS232 output buffer. */
|
||||
if (tp->tty_outcaller == KERNEL) {
|
||||
/* We're trying to print on kernel's behalf */
|
||||
memcpy(rs->ohead,
|
||||
(char *) tp->tty_outgrant + tp->tty_outcum,
|
||||
count);
|
||||
} else {
|
||||
if ((r = sys_safecopyfrom(tp->tty_outcaller,
|
||||
tp->tty_outgrant, tp->tty_outcum,
|
||||
(vir_bytes) rs->ohead, count)) != OK) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform output processing on the output buffer. */
|
||||
out_process(tp, rs->obuf, rs->ohead, bufend(rs->obuf), &count,
|
||||
&ocount);
|
||||
if (count == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Assume echoing messed up by output. */
|
||||
tp->tty_reprint = TRUE;
|
||||
|
||||
/* Bookkeeping. */
|
||||
rs->ocount += ocount;
|
||||
rs_ostart(rs);
|
||||
if ((rs->ohead += ocount) >= bufend(rs->obuf))
|
||||
rs->ohead -= buflen(rs->obuf);
|
||||
tp->tty_outcum += count;
|
||||
if ((tp->tty_outleft -= count) == 0) {
|
||||
/* Output is finished, reply to the writer. */
|
||||
if (tp->tty_outcaller != KERNEL)
|
||||
chardriver_reply_task(tp->tty_outcaller,
|
||||
tp->tty_outid, tp->tty_outcum);
|
||||
tp->tty_outcum = 0;
|
||||
tp->tty_outcaller = NONE;
|
||||
}
|
||||
|
||||
}
|
||||
if (tp->tty_outleft > 0 && tp->tty_termios.c_ospeed == B0) {
|
||||
/* Oops, the line has hung up. */
|
||||
if (tp->tty_outcaller != KERNEL)
|
||||
chardriver_reply_task(tp->tty_outcaller, tp->tty_outid,
|
||||
EIO);
|
||||
tp->tty_outleft = tp->tty_outcum = 0;
|
||||
tp->tty_outcaller = NONE;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
rs_echo(tty_t *tp, int character)
|
||||
{
|
||||
/* Echo one character. (Like rs_write, but only one character, optionally.) */
|
||||
rs232_t *rs = tp->tty_priv;
|
||||
int count, ocount;
|
||||
|
||||
ocount = buflen(rs->obuf) - rs->ocount;
|
||||
if (ocount == 0) return; /* output buffer full */
|
||||
count = 1;
|
||||
*rs->ohead = character; /* add one character */
|
||||
|
||||
out_process(tp, rs->obuf, rs->ohead, bufend(rs->obuf), &count, &ocount);
|
||||
if (count == 0) return;
|
||||
|
||||
rs->ocount += ocount;
|
||||
rs_ostart(rs);
|
||||
if ((rs->ohead += ocount) >= bufend(rs->obuf))
|
||||
rs->ohead -= buflen(rs->obuf);
|
||||
}
|
||||
|
||||
static int
|
||||
rs_ioctl(tty_t *tp, int UNUSED(dummy))
|
||||
{
|
||||
/* Reconfigure the line as soon as the output has drained. */
|
||||
rs232_t *rs = tp->tty_priv;
|
||||
|
||||
rs->drain = TRUE;
|
||||
return 0; /* dummy */
|
||||
}
|
||||
|
||||
static void rs_config(rs232_t *rs)
|
||||
{
|
||||
unsigned int lcr;
|
||||
tty_t *tp = rs->tty;
|
||||
|
||||
rs->ostate = ODEVREADY | ORAW | OSWREADY; /* reads MSR */
|
||||
/* Enable FIFO */
|
||||
serial_out(rs, PL011_LCR_H, serial_in(rs, PL011_LCR_H) | PL011_LCR_FEN);
|
||||
/* Set level of FIFO filling in */
|
||||
serial_out(rs, PL011_IFLS, PL011_IFLS_TXIFLSEL12 | PL011_IFLS_RXIFLSEL12);
|
||||
/* Set interrupt levels */
|
||||
serial_out(rs, PL011_IFLS, 0x0);
|
||||
|
||||
if (sys_irqenable(&rs->irq_hook_kernel_id) != OK)
|
||||
panic("unable to enable interrupts");
|
||||
}
|
||||
|
||||
void
|
||||
rs_init(tty_t *tp)
|
||||
{
|
||||
/* Initialize RS232 for one line. */
|
||||
rs232_t *rs;
|
||||
int line;
|
||||
uart_port_t this_pl011;
|
||||
char l[10];
|
||||
struct minix_mem_range mr;
|
||||
|
||||
/* Associate RS232 and TTY structures. */
|
||||
line = tp - &tty_table[NR_CONS];
|
||||
|
||||
/* See if kernel debugging is enabled; if so, don't initialize this
|
||||
* serial line, making tty not look at the irq and returning ENXIO
|
||||
* for all requests on it from userland. (The kernel will use it.)
|
||||
*/
|
||||
if(env_get_param(SERVARNAME, l, sizeof(l)-1) == OK && atoi(l) == line){
|
||||
printf("TTY: rs232 line %d not initialized (used by kernel)\n",
|
||||
line);
|
||||
return;
|
||||
}
|
||||
|
||||
rs = tp->tty_priv = &rs_lines[line];
|
||||
rs->tty = tp;
|
||||
|
||||
/* Set up input queue. */
|
||||
rs->ihead = rs->itail = rs->ibuf;
|
||||
|
||||
this_pl011 = bcm2835_ports[line];
|
||||
if (this_pl011.base_addr == 0) return;
|
||||
|
||||
/* Configure memory access */
|
||||
mr.mr_base = rs->phys_base;
|
||||
mr.mr_limit = rs->phys_base + 0x1000;
|
||||
if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != OK) {
|
||||
panic("Unable to request access to UART memory");
|
||||
}
|
||||
rs->phys_base = (vir_bytes) vm_map_phys(SELF,
|
||||
(void *) this_pl011.base_addr, 0x1000);
|
||||
|
||||
if (rs->phys_base == (vir_bytes) MAP_FAILED) {
|
||||
panic("Unable to request access to UART memory");
|
||||
}
|
||||
rs->reg_offset = 0;
|
||||
|
||||
rs->uartclk = UART_FREQ;
|
||||
rs->ohead = rs->otail = rs->obuf;
|
||||
|
||||
/* Override system default baud rate. We do this because u-boot
|
||||
* configures the UART for a baud rate of 115200 b/s and the kernel
|
||||
* directly sends data over serial out upon boot up. If we then
|
||||
* suddenly change the settings, the output will be garbled during
|
||||
* booting.
|
||||
*/
|
||||
tp->tty_termios.c_ospeed = DFLT_BAUD;
|
||||
|
||||
/* Configure IRQ */
|
||||
rs->irq = this_pl011.irq;
|
||||
|
||||
/* callback with irq line number */
|
||||
rs->irq_hook_kernel_id = rs->irq_hook_id = line;
|
||||
|
||||
/*
|
||||
* sys_irqsetpolicy modifies irq_hook_kernel_id. this modified id
|
||||
* needs to be used in sys_irqenable and similar calls.
|
||||
*/
|
||||
if (sys_irqsetpolicy(rs->irq, 0, &rs->irq_hook_kernel_id) != OK) {
|
||||
printf("RS232: Couldn't obtain hook for irq %d\n", rs->irq);
|
||||
} else {
|
||||
if (sys_irqenable(&rs->irq_hook_kernel_id) != OK) {
|
||||
printf("RS232: Couldn't enable irq %d (hooked)\n",
|
||||
rs->irq);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* When we get called back we get called back using the original
|
||||
* hook_id bit set. e.g. if we register with hook_id 5 the callback
|
||||
* calls us with the 5 th bit set
|
||||
*/
|
||||
rs_irq_set |= (1 << (rs->irq_hook_id ));
|
||||
|
||||
/* Enable interrupts */
|
||||
rs_reset(rs);
|
||||
rs_config(rs);
|
||||
|
||||
/* Fill in TTY function hooks. */
|
||||
tp->tty_devread = rs_read;
|
||||
tp->tty_devwrite = rs_write;
|
||||
tp->tty_echo = rs_echo;
|
||||
tp->tty_icancel = rs_icancel;
|
||||
tp->tty_ocancel = rs_ocancel;
|
||||
tp->tty_ioctl = rs_ioctl;
|
||||
tp->tty_break_on = rs_break_on;
|
||||
tp->tty_break_off = rs_break_off;
|
||||
tp->tty_open = rs_open;
|
||||
tp->tty_close = rs_close;
|
||||
|
||||
serial_out(rs, PL011_IMSC, PL011_RIS_RXRIS);
|
||||
}
|
||||
|
||||
void
|
||||
rs_interrupt(message *m)
|
||||
{
|
||||
unsigned long irq_set;
|
||||
int line;
|
||||
rs232_t *rs;
|
||||
|
||||
switch (_ENDPOINT_P(m->m_source)) {
|
||||
case CLOCK:
|
||||
for (line = 0, rs = rs_lines; line < NR_RS_LINES; line++, rs++) {
|
||||
if (rs->phys_base != 0) {
|
||||
if ((serial_in(rs, PL011_FR) & PL011_FR_RXFE) == 0) {
|
||||
read_chars(rs);
|
||||
}
|
||||
if (sys_irqenable(&rs->irq_hook_kernel_id) != OK)
|
||||
panic("unable to enable interrupts");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HARDWARE:
|
||||
irq_set = m->m_notify.interrupts;
|
||||
for (line = 0, rs = rs_lines; line < NR_RS_LINES; line++, rs++) {
|
||||
if ((irq_set & (1 << rs->irq_hook_id)) && (rs->phys_base != 0)) {
|
||||
rs232_handler(rs);
|
||||
if (sys_irqenable(&rs->irq_hook_kernel_id) != OK)
|
||||
panic("unable to enable interrupts");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
rs_icancel(tty_t *tp, int UNUSED(dummy))
|
||||
{
|
||||
return 0; /* dummy */
|
||||
}
|
||||
|
||||
static int
|
||||
rs_ocancel(tty_t *tp, int UNUSED(dummy))
|
||||
{
|
||||
/* Cancel pending output. */
|
||||
rs232_t *rs = tp->tty_priv;
|
||||
|
||||
rs->ostate &= ~(ODONE | OQUEUED);
|
||||
rs->ocount = 0;
|
||||
rs->otail = rs->ohead;
|
||||
|
||||
return 0; /* dummy */
|
||||
}
|
||||
|
||||
static int
|
||||
rs_read(tty_t *tp, int try)
|
||||
{
|
||||
/* Process characters from the circular input buffer. */
|
||||
rs232_t *rs = tp->tty_priv;
|
||||
int icount, count, ostate;
|
||||
|
||||
if (!(tp->tty_termios.c_cflag & CLOCAL)) {
|
||||
if (try) return 1;
|
||||
|
||||
/* Send a SIGHUP if hangup detected. */
|
||||
ostate = rs->ostate;
|
||||
rs->ostate &= ~ODEVHUP; /* save ostate, clear DEVHUP */
|
||||
if (ostate & ODEVHUP) {
|
||||
sigchar(tp, SIGHUP, 1);
|
||||
tp->tty_termios.c_ospeed = B0;/* Disable further I/O.*/
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (try) {
|
||||
return(rs->icount > 0);
|
||||
}
|
||||
|
||||
while ((count = rs->icount) > 0) {
|
||||
icount = bufend(rs->ibuf) - rs->itail;
|
||||
if (count > icount) count = icount;
|
||||
|
||||
/* Perform input processing on (part of) the input buffer. */
|
||||
if ((count = in_process(tp, rs->itail, count)) == 0) break;
|
||||
rs->icount -= count;
|
||||
|
||||
if ((rs->itail += count) == bufend(rs->ibuf))
|
||||
rs->itail = rs->ibuf;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
rs_ostart(rs232_t *rs)
|
||||
{
|
||||
/* Tell RS232 there is something waiting in the output buffer. */
|
||||
rs->ostate |= OQUEUED;
|
||||
write_chars(rs);
|
||||
|
||||
serial_out(rs, PL011_IMSC, PL011_RIS_TXRIS | PL011_RIS_RXRIS);
|
||||
}
|
||||
|
||||
static int
|
||||
rs_break_on(tty_t *tp, int UNUSED(dummy))
|
||||
{
|
||||
/* Raise break condition */
|
||||
return 0; /* dummy */
|
||||
}
|
||||
|
||||
static int
|
||||
rs_break_off(tty_t *tp, int UNUSED(dummy))
|
||||
{
|
||||
/* Clear break condition */
|
||||
return 0; /* dummy */
|
||||
}
|
||||
|
||||
static int
|
||||
rs_open(tty_t *tp, int UNUSED(dummy))
|
||||
{
|
||||
/* Set the speed to 115200 by default */
|
||||
tp->tty_termios.c_ospeed = DFLT_BAUD;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rs_close(tty_t *tp, int UNUSED(dummy))
|
||||
{
|
||||
/* The line is closed; optionally hang up. */
|
||||
return 0; /* dummy */
|
||||
}
|
||||
|
||||
/* Low level (interrupt) routines. */
|
||||
|
||||
static void
|
||||
rs232_handler(struct rs232 *rs)
|
||||
{
|
||||
/* Handle interrupt of a UART port */
|
||||
unsigned int ris;
|
||||
|
||||
ris = serial_in(rs, PL011_RIS);
|
||||
|
||||
if (ris & PL011_RIS_RXRIS) {
|
||||
/* Data ready interrupt */
|
||||
read_chars(rs);
|
||||
}
|
||||
rs->ostate |= ODEVREADY;
|
||||
if (ris & PL011_RIS_TXRIS) {
|
||||
/* Ready to send and space available */
|
||||
write_chars(rs);
|
||||
}
|
||||
|
||||
serial_out(rs, PL011_ICR, ris);
|
||||
}
|
||||
|
||||
static void
|
||||
read_chars(rs232_t *rs)
|
||||
{
|
||||
unsigned char c;
|
||||
|
||||
/* check the line status to know if there are more chars */
|
||||
while ((serial_in(rs, PL011_FR) & PL011_FR_RXFE) == 0) {
|
||||
c = serial_in(rs, PL011_DR);
|
||||
if (!(rs->ostate & ORAW)) {
|
||||
if (c == rs->oxoff) {
|
||||
rs->ostate &= ~OSWREADY;
|
||||
} else if (!(rs->ostate & OSWREADY)) {
|
||||
rs->ostate = OSWREADY;
|
||||
}
|
||||
}
|
||||
|
||||
if (rs->icount == buflen(rs->ibuf)) {
|
||||
/* no buffer space? keep reading */
|
||||
continue;
|
||||
}
|
||||
|
||||
++rs->icount;
|
||||
|
||||
*rs->ihead = c;
|
||||
if (++rs->ihead == bufend(rs->ibuf)) {
|
||||
rs->ihead = rs->ibuf;
|
||||
}
|
||||
|
||||
if (rs->icount == 1) {
|
||||
rs->tty->tty_events = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
write_chars(rs232_t *rs)
|
||||
{
|
||||
/*
|
||||
* If there is output to do and everything is ready, do it (local device is
|
||||
* known ready).
|
||||
* Notify TTY when the buffer goes empty.
|
||||
*/
|
||||
while ((rs->ostate >= (OQUEUED | OSWREADY)) && ((serial_in(rs, PL011_FR) & PL011_FR_TXFF) == 0)) {
|
||||
/* Bit test allows ORAW and requires the others. */
|
||||
serial_out(rs, PL011_DR, *rs->otail);
|
||||
if (++rs->otail == bufend(rs->obuf))
|
||||
rs->otail = rs->obuf;
|
||||
if (--rs->ocount == 0) {
|
||||
serial_out(rs, PL011_IMSC, PL011_RIS_RXRIS);
|
||||
/* Turn on ODONE flag, turn off OQUEUED */
|
||||
rs->ostate ^= (ODONE | OQUEUED);
|
||||
rs->tty->tty_events = 1;
|
||||
|
||||
} else {
|
||||
if (rs->icount == RS_OLOWWATER)
|
||||
rs->tty->tty_events = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* NR_RS_LINES > 0 */
|
||||
59
minix/drivers/tty/tty/arch/earm/pl011_serial.h
Normal file
59
minix/drivers/tty/tty/arch/earm/pl011_serial.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifndef _PL011_SERIAL_H
|
||||
#define _PL011_SERIAL_H
|
||||
|
||||
/* UART register map */
|
||||
#define PL011_UART0_BASE 0x3f201000 /* UART0 physical address */
|
||||
|
||||
/* UART registers */
|
||||
#define PL011_DR 0x000 /* Data register, */
|
||||
#define PL011_SR_CR 0x004 /* Receive status register/error clear register */
|
||||
#define PL011_FR 0x018 /* Flag register, */
|
||||
#define PL011_ILPR 0x020 /* IrDA low-power counter register */
|
||||
#define PL011_IBRD 0x024 /* Integer baud rate register */
|
||||
#define PL011_FBRD 0x028 /* Fractional baud rate register */
|
||||
#define PL011_LCR_H 0x02C /* Line control register, */
|
||||
#define PL011_CR 0x030 /* control register */
|
||||
#define PL011_IFLS 0x034 /* Interrupt FIFO level select register */
|
||||
#define PL011_IMSC 0x038 /* Interrupt mask set/clear register */
|
||||
#define PL011_RIS 0x03C /* Raw interrupt status register */
|
||||
#define PL011_MIS 0x040 /* Masked interrupt status register */
|
||||
#define PL011_ICR 0x044 /* Interrupt clear register */
|
||||
#define PL011_DMACR 0x048 /* DMA control register */
|
||||
|
||||
/* Raw interrupt status register */
|
||||
#define PL011_RIS_RXRIS 0x10 /* receiver interrupt */
|
||||
#define PL011_RIS_TXRIS 0x20 /* transmiter interrupt */
|
||||
#define PL011_RIS_RTRIS 0x40 /* timeout interrupt */
|
||||
|
||||
/* Flag Register bits */
|
||||
#define PL011_FR_RXFE 0x10 /* receive fifo is empty */
|
||||
#define PL011_FR_TXFF 0x20 /* transmit fifo is full */
|
||||
#define PL011_FR_RXFF 0x40 /* receive fifo is full */
|
||||
#define PL011_FR_TXFE 0x80 /* transmit fifo is empty */
|
||||
#define PL011_FR_CTS 0x00 /* clear to send */
|
||||
|
||||
/* Line Control Register bits */
|
||||
#define PL011_LCR_BRK 0x01 /* Send break */
|
||||
#define PL011_LCR_EPS 0x04 /* Even parity select */
|
||||
#define PL011_LCR_SPS 0x80 /* Stick parity select */
|
||||
#define PL011_LCR_FEN 0x10 /* Enable FIFO */
|
||||
#define PL011_LCR_PARITY 0x02 /* Enable parity */
|
||||
#define PL011_LCR_STP2 0x08 /* Stop bits; 0=1 bit, 1=2 bits */
|
||||
#define PL011_LCR_WLEN5 0x00 /* Wordlength 5 bits */
|
||||
#define PL011_LCR_WLEN6 0x20 /* Wordlength 6 bits */
|
||||
#define PL011_LCR_WLEN7 0x40 /* Wordlength 7 bits */
|
||||
#define PL011_LCR_WLEN8 0x60 /* Wordlength 8 bits */
|
||||
|
||||
/* Interrupt FIFO Level Select */
|
||||
#define PL011_IFLS_RXIFLSEL18 0x00 /* receive fifo become 1/8 full */
|
||||
#define PL011_IFLS_RXIFLSEL14 0x08 /* receive fifo become 1/4 full */
|
||||
#define PL011_IFLS_RXIFLSEL12 0x10 /* receive fifo become 1/2 full */
|
||||
#define PL011_IFLS_RXIFLSEL34 0x18 /* receive fifo become 3/4 full */
|
||||
#define PL011_IFLS_RXIFLSEL78 0x20 /* receive fifo become 7/8 full */
|
||||
#define PL011_IFLS_TXIFLSEL18 0x00 /* receive fifo become 1/8 full */
|
||||
#define PL011_IFLS_TXIFLSEL14 0x01 /* receive fifo become 1/4 full */
|
||||
#define PL011_IFLS_TXIFLSEL12 0x02 /* receive fifo become 1/2 full */
|
||||
#define PL011_IFLS_TXIFLSEL34 0x03 /* receive fifo become 3/4 full */
|
||||
#define PL011_IFLS_TXIFLSEL78 0x04 /* receive fifo become 7/8 full */
|
||||
|
||||
#endif /* _PL011_SERIAL_H */
|
||||
@@ -140,6 +140,7 @@ static void sef_local_startup(void);
|
||||
static int sef_cb_init_fresh(int type, sef_init_info_t *info);
|
||||
static void sef_cb_signal_handler(int signo);
|
||||
|
||||
#define SANE_TIMEOUT 100000 /* 100 ms */
|
||||
/*===========================================================================*
|
||||
* tty_task *
|
||||
*===========================================================================*/
|
||||
@@ -155,7 +156,13 @@ int main(void)
|
||||
|
||||
/* SEF local startup. */
|
||||
sef_local_startup();
|
||||
int ticks = SANE_TIMEOUT * sys_hz() / 1000000;
|
||||
|
||||
if (ticks <= 0)
|
||||
ticks = 1;
|
||||
|
||||
while (TRUE) {
|
||||
sys_setalarm(ticks, 0);
|
||||
/* Check for and handle any events on any of the ttys. */
|
||||
for (tp = FIRST_TTY; tp < END_TTY; tp++) {
|
||||
if (tp->tty_events) handle_events(tp);
|
||||
@@ -178,26 +185,27 @@ int main(void)
|
||||
|
||||
if (is_ipc_notify(ipc_status)) {
|
||||
switch (_ENDPOINT_P(tty_mess.m_source)) {
|
||||
case CLOCK:
|
||||
/* run watchdogs of expired timers */
|
||||
expire_timers(tty_mess.m_notify.timestamp);
|
||||
break;
|
||||
case HARDWARE:
|
||||
/* hardware interrupt notification */
|
||||
case CLOCK:
|
||||
/* run watchdogs of expired timers */
|
||||
rs_interrupt(&tty_mess);
|
||||
expire_timers(tty_mess.m_notify.timestamp);
|
||||
break;
|
||||
case HARDWARE:
|
||||
/* hardware interrupt notification */
|
||||
|
||||
#if NR_RS_LINES > 0
|
||||
/* serial I/O */
|
||||
if (tty_mess.m_notify.interrupts & rs_irq_set)
|
||||
rs_interrupt(&tty_mess);
|
||||
/* serial I/O */
|
||||
if (tty_mess.m_notify.interrupts & rs_irq_set)
|
||||
rs_interrupt(&tty_mess);
|
||||
#endif
|
||||
/* run watchdogs of expired timers */
|
||||
expire_timers(tty_mess.m_notify.timestamp);
|
||||
break;
|
||||
default:
|
||||
/* do nothing */
|
||||
break;
|
||||
/* run watchdogs of expired timers */
|
||||
expire_timers(tty_mess.m_notify.timestamp);
|
||||
break;
|
||||
default:
|
||||
/* do nothing */
|
||||
break;
|
||||
}
|
||||
|
||||
sys_setalarm(0, 0);
|
||||
/* done, get new message */
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -4,4 +4,10 @@
|
||||
HERE=${.CURDIR}/arch/${MACHINE_ARCH}
|
||||
.PATH: ${HERE}
|
||||
|
||||
SRCS += fb_arch.c
|
||||
.if ${BSP_NAME} == omap
|
||||
SRCS= fb_arch_omap.c
|
||||
.elif ${BSP_NAME} == rpi
|
||||
SRCS= fb_arch_rpi.c
|
||||
.else
|
||||
.error Unknown bsp ${BSP_NAME}
|
||||
.endif
|
||||
|
||||
297
minix/drivers/video/fb/arch/earm/fb_arch_rpi.c
Normal file
297
minix/drivers/video/fb/arch/earm/fb_arch_rpi.c
Normal file
@@ -0,0 +1,297 @@
|
||||
/* Architecture dependent part for the framebuffer on the OMAP3.
|
||||
* There's obvious room for improvement.
|
||||
*/
|
||||
|
||||
#include <minix/chardriver.h>
|
||||
#include <minix/drivers.h>
|
||||
#include <minix/fb.h>
|
||||
#include <minix/type.h>
|
||||
#include <minix/vm.h>
|
||||
#include <minix/log.h>
|
||||
#include <assert.h>
|
||||
#include <sys/mman.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <dev/videomode/videomode.h>
|
||||
#include <dev/videomode/edidvar.h>
|
||||
#include <dev/videomode/edidreg.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "dss.h"
|
||||
#include "fb.h"
|
||||
|
||||
/* default / fallback resolution if EDID reading fails */
|
||||
#define SCREEN_WIDTH 640
|
||||
#define SCREEN_HEIGHT 480
|
||||
#define PAGES_NR 2
|
||||
|
||||
#define NSUPPORTED_MODES (4)
|
||||
|
||||
/* List of valid modes from TRM 7.1
|
||||
* Other modes might work (like the default 1024x600), but no guarantees.
|
||||
*/
|
||||
struct supported_modes {
|
||||
int hdisplay;
|
||||
int vdisplay;
|
||||
} omap_supported_modes[NSUPPORTED_MODES] = {
|
||||
{ .hdisplay = 1024, .vdisplay = 768 }, /* XGA */
|
||||
{ .hdisplay = 1280, .vdisplay = 800 }, /* WXGA */
|
||||
{ .hdisplay = 1400, .vdisplay = 1050 }, /* SXGA+ */
|
||||
{ .hdisplay = 1280, .vdisplay = 720 } /* HD 720p */
|
||||
};
|
||||
|
||||
/* local function prototypes */
|
||||
static struct videomode *choose_mode(struct edid_info *info);
|
||||
static void configure_with_defaults(int minor);
|
||||
|
||||
static vir_bytes fb_vir;
|
||||
static phys_bytes fb_phys;
|
||||
static size_t fb_size;
|
||||
static int initialized = 0;
|
||||
|
||||
struct panel_config {
|
||||
u32_t timing_h;
|
||||
u32_t timing_v;
|
||||
u32_t pol_freq;
|
||||
u32_t divisor;
|
||||
u32_t lcd_size;
|
||||
u32_t panel_type;
|
||||
u32_t data_lines;
|
||||
u32_t load_mode;
|
||||
u32_t panel_color;
|
||||
};
|
||||
|
||||
static const struct fb_fix_screeninfo default_fbfs = {
|
||||
.xpanstep = 0,
|
||||
.ypanstep = 0,
|
||||
.ywrapstep = 0,
|
||||
.line_length = SCREEN_WIDTH * 4,
|
||||
.mmio_start = 0, /* Not implemented for char. special, so */
|
||||
.mmio_len = 0 /* these are set to 0 */
|
||||
};
|
||||
|
||||
static struct fb_fix_screeninfo omap_fbfs[FB_DEV_NR];
|
||||
|
||||
static const struct fb_var_screeninfo default_fbvs = {
|
||||
.xres = SCREEN_WIDTH,
|
||||
.yres = SCREEN_HEIGHT,
|
||||
.xres_virtual = SCREEN_WIDTH,
|
||||
.yres_virtual = SCREEN_HEIGHT,
|
||||
.xoffset = 0,
|
||||
.yoffset = 0,
|
||||
.bits_per_pixel = 32,
|
||||
.red = {
|
||||
.offset = 16,
|
||||
.length = 8,
|
||||
.msb_right = 0
|
||||
},
|
||||
.green = {
|
||||
.offset = 8,
|
||||
.length = 8,
|
||||
.msb_right = 0
|
||||
},
|
||||
.blue = {
|
||||
.offset = 0,
|
||||
.length = 8,
|
||||
.msb_right = 0
|
||||
},
|
||||
.transp = {
|
||||
.offset = 24,
|
||||
.length = 8,
|
||||
.msb_right = 0
|
||||
}
|
||||
};
|
||||
|
||||
static struct fb_var_screeninfo omap_fbvs[FB_DEV_NR];
|
||||
|
||||
/* logging - use with log_warn(), log_info(), log_debug(), log_trace() */
|
||||
static struct log log = {
|
||||
.name = "fb",
|
||||
.log_level = LEVEL_INFO,
|
||||
.log_func = default_log
|
||||
};
|
||||
|
||||
static inline u32_t
|
||||
readw(vir_bytes addr)
|
||||
{
|
||||
return *((volatile u32_t *) addr);
|
||||
}
|
||||
|
||||
static inline void
|
||||
writew(vir_bytes addr, u32_t val)
|
||||
{
|
||||
*((volatile u32_t *) addr) = val;
|
||||
}
|
||||
|
||||
static void
|
||||
configure_with_defaults(int minor)
|
||||
{
|
||||
if (minor < 0 || minor >= FB_DEV_NR) {
|
||||
log_warn(&log, "Invalid minor #%d\n", minor);
|
||||
return;
|
||||
}
|
||||
|
||||
/* copy the default values into this minor's configuration */
|
||||
memcpy(&omap_fbfs[minor], &default_fbfs, sizeof(struct fb_fix_screeninfo));
|
||||
memcpy(&omap_fbvs[minor], &default_fbvs, sizeof(struct fb_var_screeninfo));
|
||||
}
|
||||
|
||||
static void
|
||||
arch_configure_display(int minor)
|
||||
{
|
||||
/* Tell hardware where frame buffer is and turn display on */
|
||||
u32_t off, rdispc;
|
||||
|
||||
struct minix_mem_range mr;
|
||||
|
||||
if (!initialized) return;
|
||||
if (minor != 0) return;
|
||||
|
||||
uint32_t mboxbuffer_vir[1024];
|
||||
|
||||
int fd = open("/dev/mailbox", O_RDWR);
|
||||
if (fd < 0)
|
||||
panic("Unable to open mailbox device");
|
||||
|
||||
/* Fill mailbox property tags buffer */
|
||||
mboxbuffer_vir[0] = 4096;
|
||||
mboxbuffer_vir[1] = 0;
|
||||
mboxbuffer_vir[2] = 0x00048003; /* set physical size */
|
||||
mboxbuffer_vir[3] = 8;
|
||||
mboxbuffer_vir[4] = 0;
|
||||
mboxbuffer_vir[5] = omap_fbvs[0].xres_virtual;
|
||||
mboxbuffer_vir[6] = omap_fbvs[0].yres_virtual;
|
||||
mboxbuffer_vir[7] = 0x00048004; /* set virtual size */
|
||||
mboxbuffer_vir[8] = 8;
|
||||
mboxbuffer_vir[9] = 0;
|
||||
mboxbuffer_vir[10] = omap_fbvs[0].xres_virtual;
|
||||
mboxbuffer_vir[11] = omap_fbvs[0].yres_virtual;
|
||||
mboxbuffer_vir[12] = 0x00048005; /* set depth */
|
||||
mboxbuffer_vir[13] = 4;
|
||||
mboxbuffer_vir[14] = 0;
|
||||
mboxbuffer_vir[15] = omap_fbvs[0].bits_per_pixel;
|
||||
mboxbuffer_vir[16] = 0x00040001; /* allocate framebuffer */
|
||||
mboxbuffer_vir[17] = 8;
|
||||
mboxbuffer_vir[18] = 0;
|
||||
mboxbuffer_vir[19] = 4096;
|
||||
mboxbuffer_vir[20] = 0; /* end tag */
|
||||
|
||||
write(fd, mboxbuffer_vir, 4096);
|
||||
read(fd, mboxbuffer_vir, 4096);
|
||||
|
||||
if (mboxbuffer_vir[1] != 0x80000000)
|
||||
panic("Unable to configure framebuffer");
|
||||
|
||||
int c = 2;
|
||||
while (mboxbuffer_vir[c] != 0x40001)
|
||||
c += 3 + (mboxbuffer_vir[c+1] >> 2);
|
||||
|
||||
if (mboxbuffer_vir[c+2] != 0x80000008)
|
||||
panic("Unrecognized response from mailbox");
|
||||
|
||||
/* Configure framebuffer memory access */
|
||||
mboxbuffer_vir[c+3] &= ~0xC0000000;
|
||||
mr.mr_base = mboxbuffer_vir[c+3];
|
||||
mr.mr_limit = mboxbuffer_vir[c+3] + mboxbuffer_vir[c+4];
|
||||
if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != OK) {
|
||||
panic("Unable to request access to framebuffer memory");
|
||||
}
|
||||
|
||||
fb_size = mr.mr_limit-mr.mr_base;
|
||||
fb_vir = (vir_bytes) vm_map_phys(SELF, (void *) mr.mr_base, fb_size);
|
||||
if (fb_vir == (vir_bytes) MAP_FAILED) {
|
||||
panic("Unable to map framebuffer memory");
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
int
|
||||
arch_get_device(int minor, struct device *dev)
|
||||
{
|
||||
if (!initialized) return ENXIO;
|
||||
if (minor != 0) return ENXIO;
|
||||
dev->dv_base = fb_vir;
|
||||
dev->dv_size = fb_size;
|
||||
return OK;
|
||||
}
|
||||
|
||||
int
|
||||
arch_get_varscreeninfo(int minor, struct fb_var_screeninfo *fbvsp)
|
||||
{
|
||||
if (!initialized) return ENXIO;
|
||||
if (minor != 0) return ENXIO;
|
||||
|
||||
*fbvsp = omap_fbvs[minor];
|
||||
return OK;
|
||||
}
|
||||
|
||||
int
|
||||
arch_put_varscreeninfo(int minor, struct fb_var_screeninfo *fbvsp)
|
||||
{
|
||||
int r = OK;
|
||||
|
||||
assert(fbvsp != NULL);
|
||||
|
||||
if (!initialized) return ENXIO;
|
||||
if (minor != 0) return ENXIO;
|
||||
|
||||
/* For now we only allow to play with the yoffset setting */
|
||||
if (fbvsp->yoffset != omap_fbvs[minor].yoffset) {
|
||||
if (/* fbvsp->yoffset < 0 || */ fbvsp->yoffset > omap_fbvs[minor].yres) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
omap_fbvs[minor].yoffset = fbvsp->yoffset;
|
||||
}
|
||||
|
||||
/* Now update hardware with new settings */
|
||||
arch_configure_display(minor);
|
||||
return OK;
|
||||
}
|
||||
|
||||
int
|
||||
arch_get_fixscreeninfo(int minor, struct fb_fix_screeninfo *fbfsp)
|
||||
{
|
||||
if (!initialized) return ENXIO;
|
||||
if (minor != 0) return ENXIO;
|
||||
|
||||
*fbfsp = omap_fbfs[minor];
|
||||
return OK;
|
||||
}
|
||||
|
||||
int
|
||||
arch_pan_display(int minor, struct fb_var_screeninfo *fbvsp)
|
||||
{
|
||||
return arch_put_varscreeninfo(minor, fbvsp);
|
||||
}
|
||||
|
||||
int
|
||||
arch_fb_init(int minor, struct edid_info *info)
|
||||
{
|
||||
int r;
|
||||
u32_t rdispc;
|
||||
|
||||
if (minor != 0) return ENXIO; /* We support only one minor */
|
||||
|
||||
if (initialized) {
|
||||
return OK;
|
||||
} else {
|
||||
log_debug(&log, "Loading Default Settings...\n");
|
||||
configure_with_defaults(minor);
|
||||
}
|
||||
|
||||
initialized = 1;
|
||||
|
||||
/* Configure buffer settings and turn on LCD/Digital */
|
||||
arch_configure_display(minor);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
#ifndef _INTERRUPT_H
|
||||
#define _INTERRUPT_H
|
||||
|
||||
#define NR_IRQ_VECTORS 125
|
||||
#define NR_IRQ_VECTORS 128
|
||||
|
||||
#endif /* _INTERRUPT_H */
|
||||
|
||||
@@ -3,8 +3,4 @@
|
||||
#ifndef _ARM_MEMORY_H
|
||||
#define _ARM_MEMORY_H
|
||||
|
||||
/* omap */
|
||||
#define PHYS_MEM_BEGIN 0x80000000
|
||||
#define PHYS_MEM_END 0xbfffffff
|
||||
|
||||
#endif /* _ARM_MEMORY_H */
|
||||
|
||||
@@ -67,12 +67,15 @@
|
||||
|
||||
#define MINIX_BOARD_VENDOR_INTEL MINIX_MK_BOARD_VENDOR(1<<0)
|
||||
#define MINIX_BOARD_VENDOR_TI MINIX_MK_BOARD_VENDOR(1<<1)
|
||||
#define MINIX_BOARD_VENDOR_RPI MINIX_MK_BOARD_VENDOR(1<<2)
|
||||
|
||||
#define MINIX_BOARD_GENERIC MINIX_MK_BOARD(1<<0)
|
||||
/* BeagleBoard XM */
|
||||
#define MINIX_BOARD_BBXM MINIX_MK_BOARD(1<<1)
|
||||
/* BeagleBone (Black and* white) */
|
||||
#define MINIX_BOARD_BB MINIX_MK_BOARD(1<<2)
|
||||
/* Raspberry Pi */
|
||||
#define MINIX_BOARD_RPI MINIX_MK_BOARD(1<<3)
|
||||
|
||||
/* Only one of a kind */
|
||||
#define MINIX_BOARD_VARIANT_GENERIC MINIX_MK_BOARD_VARIANT(1<<0)
|
||||
@@ -81,6 +84,10 @@
|
||||
/* BeagleBone Black */
|
||||
#define MINIX_BOARD_VARIANT_BBB MINIX_MK_BOARD_VARIANT(1<<2)
|
||||
|
||||
/* Rasberry Pi */
|
||||
#define MINIX_BOARD_VARIANT_RPI_2_B MINIX_MK_BOARD_VARIANT(1<<1)
|
||||
#define MINIX_BOARD_VARIANT_RPI_3_B MINIX_MK_BOARD_VARIANT(1<<2)
|
||||
|
||||
#define BOARD_ID_INTEL \
|
||||
( MINIX_BOARD_ARCH_X86 \
|
||||
| MINIX_BOARD_ARCH_VARIANT_X86_GENERIC \
|
||||
@@ -113,6 +120,22 @@
|
||||
| MINIX_BOARD_VARIANT_BBB\
|
||||
)
|
||||
|
||||
#define BOARD_ID_RPI_2_B \
|
||||
( MINIX_BOARD_ARCH_ARM \
|
||||
| MINIX_BOARD_ARCH_VARIANT_ARM_ARMV7 \
|
||||
| MINIX_BOARD_VENDOR_RPI \
|
||||
| MINIX_BOARD_RPI \
|
||||
| MINIX_BOARD_VARIANT_RPI_2_B \
|
||||
)
|
||||
|
||||
#define BOARD_ID_RPI_3_B \
|
||||
( MINIX_BOARD_ARCH_ARM \
|
||||
| MINIX_BOARD_ARCH_VARIANT_ARM_ARMV7 \
|
||||
| MINIX_BOARD_VENDOR_RPI \
|
||||
| MINIX_BOARD_RPI \
|
||||
| MINIX_BOARD_VARIANT_RPI_3_B \
|
||||
)
|
||||
|
||||
#define BOARD_IS_BBXM(v) \
|
||||
( (BOARD_ID_BBXM & ~MINIX_BOARD_VARIANT_MASK) == (v & ~MINIX_BOARD_VARIANT_MASK))
|
||||
/* Either one of the known BeagleBones */
|
||||
@@ -121,6 +144,9 @@
|
||||
#define BOARD_IS_BBW(v) ( v == BOARD_ID_BBW)
|
||||
#define BOARD_IS_BBB(v) ( v == BOARD_ID_BBB)
|
||||
|
||||
#define BOARD_IS_RPI_2_B(v) ( v == BOARD_ID_RPI_2_B)
|
||||
#define BOARD_IS_RPI_3_B(v) ( v == BOARD_ID_RPI_3_B)
|
||||
|
||||
#define BOARD_FILTER_BBXM_VALUE (BOARD_ID_BBXM)
|
||||
#define BOARD_FILTER_BBXM_MASK \
|
||||
(MINIX_BOARD_ARCH_MASK \
|
||||
@@ -142,12 +168,28 @@ struct shortname2id
|
||||
unsigned int id;
|
||||
};
|
||||
|
||||
|
||||
/* mapping from fields given by the bootloader to board id's */
|
||||
static struct shortname2id shortname2id[] = {
|
||||
{.name = "BBXM",.id = BOARD_ID_BBXM},
|
||||
{.name = "A335BONE",.id = BOARD_ID_BBW},
|
||||
{.name = "A335BNLT",.id = BOARD_ID_BBB},
|
||||
{.name = "RPI_2_B",.id = BOARD_ID_RPI_2_B},
|
||||
{.name = "RPI_3_B",.id = BOARD_ID_RPI_3_B},
|
||||
};
|
||||
|
||||
struct longname2id
|
||||
{
|
||||
const char name[40];
|
||||
unsigned int id;
|
||||
};
|
||||
|
||||
/* mapping from fields given by the device tree to board id's */
|
||||
static struct longname2id longname2id[] = {
|
||||
{.name = "BBXM",.id = BOARD_ID_BBXM},
|
||||
{.name = "A335BONE",.id = BOARD_ID_BBW},
|
||||
{.name = "A335BNLT",.id = BOARD_ID_BBB},
|
||||
{.name = "Raspberry Pi 2 Model B Rev 1.1",.id = BOARD_ID_RPI_2_B},
|
||||
{.name = "Raspberry Pi 3 Model B Rev 1.2",.id = BOARD_ID_RPI_3_B},
|
||||
};
|
||||
|
||||
struct board_id2name
|
||||
@@ -162,6 +204,8 @@ static struct board_id2name board_id2name[] = {
|
||||
{.id = BOARD_ID_BBXM,.name = "ARM-ARMV7-TI-BBXM-GENERIC"},
|
||||
{.id = BOARD_ID_BBW,.name = "ARM-ARMV7-TI-BB-WHITE"},
|
||||
{.id = BOARD_ID_BBB,.name = "ARM-ARMV7-TI-BB-BLACK"},
|
||||
{.id = BOARD_ID_RPI_2_B,.name = "ARM-ARMV7-RPI-RPI_2_B"},
|
||||
{.id = BOARD_ID_RPI_3_B,.name = "ARM-ARMV7-RPI-RPI_3_B"},
|
||||
};
|
||||
|
||||
struct board_arch2arch
|
||||
@@ -188,6 +232,19 @@ get_board_id_by_short_name(const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* returns 0 if no board was found that match that id */
|
||||
static int
|
||||
get_board_id_by_long_name(const char *name)
|
||||
{
|
||||
int x;
|
||||
for (x = 0; x < sizeof(longname2id) / sizeof(longname2id[0]); x++) {
|
||||
if (strncmp(name, longname2id[x].name, 15) == 0) {
|
||||
return longname2id[x].id;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* returns 0 if no board was found that match that id */
|
||||
static int
|
||||
get_board_id_by_name(const char *name)
|
||||
|
||||
@@ -9,6 +9,12 @@ struct gpio
|
||||
|
||||
#define GPIO_MODE_INPUT 0
|
||||
#define GPIO_MODE_OUTPUT 1
|
||||
#define GPIO_MODE_ALT0 2
|
||||
#define GPIO_MODE_ALT1 3
|
||||
#define GPIO_MODE_ALT2 4
|
||||
#define GPIO_MODE_ALT3 5
|
||||
#define GPIO_MODE_ALT4 6
|
||||
#define GPIO_MODE_ALT5 7
|
||||
|
||||
int gpio_init(void);
|
||||
|
||||
|
||||
@@ -319,4 +319,21 @@
|
||||
#define CONTROL_CONF_PUDEN (1<<3)
|
||||
#define CONTROL_CONF_MUXMODE(X) (X&0x7)
|
||||
|
||||
/* Raspberry Pi specific registers */
|
||||
#define PADCONF_RPI2_REGISTERS_BASE 0x3F200000
|
||||
#define PADCONF_RPI2_REGISTERS_OFFSET 0x0000
|
||||
#define PADCONF_RPI2_REGISTERS_SIZE 0x1000
|
||||
|
||||
#define GPFSEL09 (0x00000000)
|
||||
#define GPFSEL1019 (0x00000004)
|
||||
#define GPFSEL2029 (0x00000008)
|
||||
#define GPFSEL3039 (0x0000000C)
|
||||
#define GPFSEL4049 (0x00000010)
|
||||
#define GPFSEL5053 (0x00000014)
|
||||
|
||||
#define CONTROL_BCM_CONF_I2C0_SDA (0x00E00000)
|
||||
#define CONTROL_BCM_CONF_I2C0_SCL (0x07000000)
|
||||
#define CONTROL_BCM_CONF_I2C1_SDA (0x00000100)
|
||||
#define CONTROL_BCM_CONF_I2C1_SCL (0x00000800)
|
||||
|
||||
#endif /* __MINIX_PADCONF_H */
|
||||
|
||||
@@ -17,7 +17,7 @@ SRCS+= clock.c cpulocals.c interrupt.c main.c proc.c system.c \
|
||||
|
||||
LDADD+= -ltimers -lsys -lexec
|
||||
|
||||
LINKERSCRIPT= ${.CURDIR}/arch/${MACHINE_ARCH}/kernel.lds
|
||||
LINKERSCRIPT= ${.CURDIR}/arch/${MACHINE_ARCH}/kernel-${BSP_NAME}.lds
|
||||
|
||||
.if ${HAVE_GOLD:U} != ""
|
||||
CFLAGS+= -fno-common
|
||||
|
||||
@@ -4,79 +4,36 @@
|
||||
HERE=${.CURDIR}/arch/${MACHINE_ARCH}
|
||||
.PATH: ${HERE}
|
||||
|
||||
# objects we want unpaged from -lc
|
||||
MINLIB_OBJS_UNPAGED= get_bp.o
|
||||
get_bp.o: ${NETBSDSRCDIR}/minix/lib/libc/arch/arm/get_bp.S
|
||||
|
||||
# objects we want unpaged from -lsys
|
||||
SYS_OBJS_UNPAGED=assert.o stacktrace.o
|
||||
assert.o: ${NETBSDSRCDIR}/minix/lib/libsys/assert.c
|
||||
stacktrace.o: ${NETBSDSRCDIR}/minix/lib/libsys/stacktrace.c
|
||||
|
||||
# objects we want unpaged from -lminc
|
||||
MINC_OBJS_UNPAGED= atoi.o \
|
||||
printf.o subr_prf.o \
|
||||
strcmp.o strcpy.o strlen.o strncmp.o \
|
||||
memcpy.o memmove.o memset.o
|
||||
MINC_OBJS_UNPAGED+= divmodsi4.o divsi3.o udivsi3.o umodsi3.o \
|
||||
umoddi3.o udivmoddi4.o __aeabi_idiv0.o aeabi_idivmod.o aeabi_uidivmod.o \
|
||||
udivmodsi4.o aeabi_uldivmod.o
|
||||
atoi.o: ${NETBSDSRCDIR}/minix/lib/libminc/atoi.c
|
||||
printf.o: ${NETBSDSRCDIR}/sys/lib/libsa/printf.c
|
||||
subr_prf.o: ${NETBSDSRCDIR}/sys/lib/libsa/subr_prf.c
|
||||
memcpy.o: ${NETBSDSRCDIR}/common/lib/libc/arch/arm/string/memcpy.S
|
||||
memmove.o: ${NETBSDSRCDIR}/common/lib/libc/arch/arm/string/memmove.S
|
||||
memset.o: ${NETBSDSRCDIR}/common/lib/libc/arch/arm/string/memset.S
|
||||
strlen.o: ${NETBSDSRCDIR}/common/lib/libc/arch/arm/string/strlen.S
|
||||
strcpy.o: ${NETBSDSRCDIR}/common/lib/libc/arch/arm/string/strcpy.S
|
||||
strcmp.o: ${NETBSDSRCDIR}/common/lib/libc/arch/arm/string/strcmp.S
|
||||
__aeabi_idiv0.o: ${NETBSDSRCDIR}/common/lib/libc/arch/arm/gen/__aeabi_idiv0.c
|
||||
CPPFLAGS.__aeabi_idiv0.c+= -D_STANDALONE -I${NETBSDSRCDIR}/sys
|
||||
|
||||
divsi3.o: ${NETBSDSRCDIR}/sys/external/bsd/compiler_rt/dist/lib/builtins/divsi3.c
|
||||
udivsi3.o: ${NETBSDSRCDIR}/sys/external/bsd/compiler_rt/dist/lib/builtins/udivsi3.c
|
||||
umodsi3.o: ${NETBSDSRCDIR}/sys/external/bsd/compiler_rt/dist/lib/builtins/umodsi3.c
|
||||
umoddi3.o: ${NETBSDSRCDIR}/sys/external/bsd/compiler_rt/dist/lib/builtins/umoddi3.c
|
||||
udivmoddi4.o: ${NETBSDSRCDIR}/sys/external/bsd/compiler_rt/dist/lib/builtins/udivmoddi4.c
|
||||
divmodsi4.o: ${NETBSDSRCDIR}/sys/external/bsd/compiler_rt/dist/lib/builtins/arm/divmodsi4.S
|
||||
udivmodsi4.o: ${NETBSDSRCDIR}/sys/external/bsd/compiler_rt/dist/lib/builtins/arm/udivmodsi4.S
|
||||
aeabi_idivmod.o: ${NETBSDSRCDIR}/sys/external/bsd/compiler_rt/dist/lib/builtins/arm/aeabi_idivmod.S
|
||||
aeabi_uidivmod.o: ${NETBSDSRCDIR}/sys/external/bsd/compiler_rt/dist/lib/builtins/arm/aeabi_uidivmod.S
|
||||
aeabi_uldivmod.o: ${NETBSDSRCDIR}/sys/external/bsd/compiler_rt/dist/lib/builtins/arm/aeabi_uldivmod.S
|
||||
|
||||
# the following is required by pre_init.c
|
||||
strncmp.o: ${NETBSDSRCDIR}/common/lib/libc/string/strncmp.c
|
||||
|
||||
# LSC: putchar and kputc have the same signature. A bit hackish.
|
||||
CPPFLAGS.subr_prf.c+= -Dputchar=kputc
|
||||
|
||||
# Activate optional support, may be deactivated.
|
||||
CPPFLAGS.subr_prf.c+= -DLIBSA_PRINTF_LONGLONG_SUPPORT -DLIBSA_PRINTF_WIDTH_SUPPORT
|
||||
|
||||
.include "bsp/ti/Makefile.inc"
|
||||
.include "bsp/omap/Makefile.inc"
|
||||
.include "bsp/rpi/Makefile.inc"
|
||||
|
||||
# some object files we give a symbol prefix (or namespace) of __k_unpaged_
|
||||
# that must live in their own unique namespace.
|
||||
#
|
||||
.for unpaged_obj in head.o pre_init.o direct_tty_utils.o \
|
||||
pg_utils.o klib.o utility.o arch_reset.o \
|
||||
${MINLIB_OBJS_UNPAGED} ${MINC_OBJS_UNPAGED} ${SYS_OBJS_UNPAGED} ${BSP_OBJS_UNPAGED}
|
||||
.for unpaged_obj in head.o
|
||||
unpaged_${unpaged_obj}: ${unpaged_obj}
|
||||
${OBJCOPY} --prefix-symbols=__k_unpaged_ ${.OBJDIR}/${unpaged_obj} $@
|
||||
UNPAGED_OBJS += unpaged_${unpaged_obj}
|
||||
ORIG_UNPAGED_OBJS += ${unpaged_obj}
|
||||
.endfor
|
||||
|
||||
|
||||
CLEANFILES+= ${ORIG_UNPAGED_OBJS}
|
||||
|
||||
SRCS+= mpx.S arch_clock.c arch_do_vmctl.c arch_system.c do_padconf.c \
|
||||
exception.c hw_intr.c klib.S memory.c \
|
||||
exception.c hw_intr.c klib.S memory.c pre_init.c \
|
||||
protect.c direct_tty_utils.c arch_reset.c \
|
||||
pg_utils.c phys_copy.S phys_memset.S exc.S
|
||||
pg_utils.c fdt.c phys_copy.S phys_memset.S exc.S
|
||||
|
||||
OBJS.kernel+= ${UNPAGED_OBJS}
|
||||
|
||||
LDADD+=-lfdt
|
||||
|
||||
klib.o mpx.o head.o: procoffsets.h
|
||||
|
||||
SRCS+= procoffsets.h
|
||||
|
||||
@@ -24,20 +24,28 @@
|
||||
|
||||
#include "bsp_timer.h"
|
||||
#include "bsp_intr.h"
|
||||
#include "cpufunc_timer.h"
|
||||
#include "bsp_table.h"
|
||||
|
||||
static unsigned tsc_per_ms[CONFIG_MAX_CPUS];
|
||||
static unsigned tsc_per_tick[CONFIG_MAX_CPUS];
|
||||
static uint64_t tsc_per_state[CONFIG_MAX_CPUS][CPUSTATES];
|
||||
|
||||
extern bsp_table *bsp_tb;
|
||||
|
||||
int init_local_timer(unsigned freq)
|
||||
{
|
||||
bsp_timer_init(freq);
|
||||
bsp_tb->bsp_timer_init(freq);
|
||||
|
||||
if (BOARD_IS_BBXM(machine.board_id)) {
|
||||
tsc_per_ms[0] = 16250;
|
||||
} else if (BOARD_IS_BB(machine.board_id)) {
|
||||
tsc_per_ms[0] = 15000;
|
||||
} else {
|
||||
} else if (BOARD_IS_RPI_2_B(machine.board_id) ||
|
||||
BOARD_IS_RPI_3_B(machine.board_id)) {
|
||||
tsc_per_ms[0] = 1000;
|
||||
}
|
||||
else {
|
||||
panic("Can not do the clock setup. machine (0x%08x) is unknown\n",machine.board_id);
|
||||
};
|
||||
|
||||
@@ -48,12 +56,12 @@ int init_local_timer(unsigned freq)
|
||||
|
||||
void stop_local_timer(void)
|
||||
{
|
||||
bsp_timer_stop();
|
||||
bsp_tb->bsp_timer_stop();
|
||||
}
|
||||
|
||||
void arch_timer_int_handler(void)
|
||||
{
|
||||
bsp_timer_int_handler();
|
||||
bsp_tb->bsp_timer_int_handler();
|
||||
}
|
||||
|
||||
void cycles_accounting_init(void)
|
||||
@@ -181,7 +189,7 @@ void restart_local_timer(void)
|
||||
|
||||
int register_local_timer_handler(const irq_handler_t handler)
|
||||
{
|
||||
return bsp_register_timer_handler(handler);
|
||||
return bsp_tb->bsp_register_timer_handler(handler);
|
||||
}
|
||||
|
||||
u64_t ms_2_cpu_time(unsigned ms)
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
#include "kernel/debug.h"
|
||||
#include "direct_utils.h"
|
||||
#include <machine/multiboot.h>
|
||||
#include "bsp_table.h"
|
||||
|
||||
extern bsp_table *bsp_tb;
|
||||
|
||||
void
|
||||
halt_cpu(void)
|
||||
@@ -35,7 +38,7 @@ halt_cpu(void)
|
||||
void
|
||||
reset(void)
|
||||
{
|
||||
bsp_reset(); /* should not exit */
|
||||
bsp_tb->bsp_reset(); /* should not exit */
|
||||
direct_print("Reset not supported.");
|
||||
while (1);
|
||||
}
|
||||
@@ -43,7 +46,7 @@ reset(void)
|
||||
void
|
||||
poweroff(void)
|
||||
{
|
||||
bsp_poweroff();
|
||||
bsp_tb->bsp_poweroff();
|
||||
/* fallback option: hang */
|
||||
direct_print("Unable to power-off this device.");
|
||||
while (1);
|
||||
@@ -76,7 +79,7 @@ arch_shutdown(int how)
|
||||
void
|
||||
ser_putc(char c)
|
||||
{
|
||||
bsp_ser_putc(c);
|
||||
bsp_tb->bsp_ser_putc(c);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
#include "bsp_serial.h"
|
||||
|
||||
#include "glo.h"
|
||||
#include "bsp_table.h"
|
||||
|
||||
extern bsp_table *bsp_tb;
|
||||
|
||||
void * k_stacks;
|
||||
|
||||
@@ -128,7 +131,7 @@ void arch_init(void)
|
||||
/* enable cycle counter in user mode: ARM ARM B4.1.124 */
|
||||
value = PMU_PMUSERENR_EN;
|
||||
asm volatile ("MCR p15, 0, %0, c9, c14, 0\t\n": : "r" (value));
|
||||
bsp_init();
|
||||
bsp_tb->bsp_init();
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
@@ -182,7 +185,7 @@ void get_randomness(struct k_randomness *rand, int source)
|
||||
|
||||
void arch_ser_init(void)
|
||||
{
|
||||
bsp_ser_init();
|
||||
bsp_tb->bsp_ser_init();
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
#define _BSP_INIT_H_
|
||||
|
||||
/* BSP init */
|
||||
void bsp_init(void);
|
||||
#define INIT_GENERATE(name) \
|
||||
void name##_init (void);
|
||||
|
||||
INIT_GENERATE(rpi);
|
||||
INIT_GENERATE(omap);
|
||||
|
||||
#endif /* __BSP_INIT_H__ */
|
||||
|
||||
@@ -3,9 +3,14 @@
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
void bsp_irq_unmask(int irq);
|
||||
void bsp_irq_mask(int irq);
|
||||
void bsp_irq_handle(void);
|
||||
#define INTR_GENERATE(name) \
|
||||
void name##_irq_unmask (int irq); \
|
||||
void name##_irq_mask (int irq); \
|
||||
void name##_irq_handle (void); \
|
||||
int name##_intr_init(const int auto_eoi);
|
||||
|
||||
INTR_GENERATE(rpi);
|
||||
INTR_GENERATE(omap);
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
|
||||
@@ -3,8 +3,12 @@
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
void bsp_padconf_init(void);
|
||||
int bsp_padconf_set(u32_t padconf, u32_t mask, u32_t value);
|
||||
#define PADCONF_GENERATE(name) \
|
||||
void name##_padconf_init (void); \
|
||||
int name##_padconf_set (u32_t padconf, u32_t mask, u32_t value);
|
||||
|
||||
PADCONF_GENERATE(rpi);
|
||||
PADCONF_GENERATE(omap);
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
#ifndef _BSP_RESET_H_
|
||||
#define _BSP_RESET_H_
|
||||
|
||||
void bsp_reset_init(void);
|
||||
void bsp_reset(void);
|
||||
void bsp_poweroff(void);
|
||||
void bsp_disable_watchdog(void);
|
||||
#define RESET_GENERATE(name) \
|
||||
void name##_reset_init (void); \
|
||||
void name##_reset (void); \
|
||||
void name##_poweroff (void); \
|
||||
void name##_disable_watchdog (void);
|
||||
|
||||
RESET_GENERATE(rpi);
|
||||
RESET_GENERATE(omap);
|
||||
|
||||
#endif /* _BSP_RESET_H_ */
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
#ifndef _BSP_SERIAL_H_
|
||||
#define _BSP_SERIAL_H_
|
||||
|
||||
void bsp_ser_init(void);
|
||||
void bsp_ser_putc(char c);
|
||||
#define SERIAL_GENERATE(name) \
|
||||
void name##_ser_init (void); \
|
||||
void name##_ser_putc (char c);
|
||||
|
||||
SERIAL_GENERATE(rpi);
|
||||
SERIAL_GENERATE(omap);
|
||||
|
||||
#endif /* _BSP_SERIAL_H_ */
|
||||
|
||||
@@ -3,10 +3,15 @@
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
void bsp_timer_init(unsigned freq);
|
||||
void bsp_timer_stop(void);
|
||||
int bsp_register_timer_handler(const irq_handler_t handler);
|
||||
void bsp_timer_int_handler(void);
|
||||
#define TIMER_GENERATE(name) \
|
||||
void name##_timer_init (unsigned freq); \
|
||||
void name##_timer_stop (void); \
|
||||
int name##_register_timer_handler (const irq_handler_t handler); \
|
||||
void name##_timer_int_handler (void); \
|
||||
void name##_read_tsc_64 (u64_t * t)
|
||||
|
||||
TIMER_GENERATE(rpi);
|
||||
TIMER_GENERATE(omap);
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
|
||||
9
minix/kernel/arch/earm/bsp/omap/Makefile.inc
Normal file
9
minix/kernel/arch/earm/bsp/omap/Makefile.inc
Normal file
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# BSP for TI hardware
|
||||
#
|
||||
|
||||
.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/bsp/omap
|
||||
|
||||
SRCS+= omap_init.c omap_serial.c omap_timer.c omap_padconf.c omap_intr.c omap_rtc.c \
|
||||
omap_reset.c
|
||||
|
||||
@@ -5,18 +5,18 @@
|
||||
#include "bsp_reset.h"
|
||||
|
||||
void
|
||||
bsp_init(void)
|
||||
omap_init(void)
|
||||
{
|
||||
|
||||
/* map memory for padconf */
|
||||
bsp_padconf_init();
|
||||
omap_padconf_init();
|
||||
|
||||
/* map memory for rtc */
|
||||
omap3_rtc_init();
|
||||
|
||||
/* map memory for reset control */
|
||||
bsp_reset_init();
|
||||
omap_reset_init();
|
||||
|
||||
/* disable watchdog */
|
||||
bsp_disable_watchdog();
|
||||
omap_disable_watchdog();
|
||||
}
|
||||
@@ -21,7 +21,7 @@ static struct omap_intr
|
||||
static kern_phys_map intr_phys_map;
|
||||
|
||||
int
|
||||
intr_init(const int auto_eoi)
|
||||
omap_intr_init(const int auto_eoi)
|
||||
{
|
||||
if (BOARD_IS_BBXM(machine.board_id)) {
|
||||
omap_intr.base = OMAP3_DM37XX_INTR_BASE;
|
||||
@@ -41,7 +41,7 @@ intr_init(const int auto_eoi)
|
||||
}
|
||||
|
||||
void
|
||||
bsp_irq_handle(void)
|
||||
omap_irq_handle(void)
|
||||
{
|
||||
/* Function called from assembly to handle interrupts */
|
||||
|
||||
@@ -58,14 +58,14 @@ bsp_irq_handle(void)
|
||||
}
|
||||
|
||||
void
|
||||
bsp_irq_unmask(int irq)
|
||||
omap_irq_unmask(int irq)
|
||||
{
|
||||
mmio_write(OMAP3_INTR_MIR_CLEAR(omap_intr.base, irq >> 5),
|
||||
1 << (irq & 0x1f));
|
||||
}
|
||||
|
||||
void
|
||||
bsp_irq_mask(const int irq)
|
||||
omap_irq_mask(const int irq)
|
||||
{
|
||||
mmio_write(OMAP3_INTR_MIR_SET(omap_intr.base, irq >> 5),
|
||||
1 << (irq & 0x1f));
|
||||
@@ -47,7 +47,7 @@ static struct omap_padconf *omap_padconf;
|
||||
static kern_phys_map padconf_phys_map;
|
||||
|
||||
int
|
||||
bsp_padconf_set(u32_t padconf, u32_t mask, u32_t value)
|
||||
omap_padconf_set(u32_t padconf, u32_t mask, u32_t value)
|
||||
{
|
||||
/* check that the value will be inside the padconf memory range */
|
||||
if (padconf >= (omap_padconf->size - omap_padconf->offset)) {
|
||||
@@ -61,7 +61,7 @@ bsp_padconf_set(u32_t padconf, u32_t mask, u32_t value)
|
||||
}
|
||||
|
||||
void
|
||||
bsp_padconf_init(void)
|
||||
omap_padconf_init(void)
|
||||
{
|
||||
int x;
|
||||
omap_padconf = NULL;
|
||||
@@ -33,41 +33,41 @@ struct omap_reset
|
||||
vir_bytes size;
|
||||
};
|
||||
|
||||
static struct omap_reset omap_reset;
|
||||
static struct omap_reset omap_res;
|
||||
|
||||
static kern_phys_map reset_phys_map;
|
||||
|
||||
void
|
||||
bsp_reset_init(void)
|
||||
omap_reset_init(void)
|
||||
{
|
||||
if (BOARD_IS_BBXM(machine.board_id)) {
|
||||
omap_reset.base = DM37XX_CM_BASE;
|
||||
omap_reset.size = DM37XX_CM_SIZE;
|
||||
omap_res.base = DM37XX_CM_BASE;
|
||||
omap_res.size = DM37XX_CM_SIZE;
|
||||
} else if (BOARD_IS_BB(machine.board_id)) {
|
||||
omap_reset.base = AM335X_CM_BASE;
|
||||
omap_reset.size = AM335X_CM_SIZE;
|
||||
omap_res.base = AM335X_CM_BASE;
|
||||
omap_res.size = AM335X_CM_SIZE;
|
||||
}
|
||||
|
||||
kern_phys_map_ptr(omap_reset.base, omap_reset.size,
|
||||
kern_phys_map_ptr(omap_res.base, omap_res.size,
|
||||
VMMF_UNCACHED | VMMF_WRITE,
|
||||
&reset_phys_map, (vir_bytes) & omap_reset.base);
|
||||
&reset_phys_map, (vir_bytes) & omap_res.base);
|
||||
}
|
||||
|
||||
void
|
||||
bsp_reset(void)
|
||||
omap_reset(void)
|
||||
{
|
||||
if (BOARD_IS_BBXM(machine.board_id)) {
|
||||
mmio_set((omap_reset.base + DM37XX_PRM_RSTCTRL_REG),
|
||||
mmio_set((omap_res.base + DM37XX_PRM_RSTCTRL_REG),
|
||||
(1 << DM37XX_RST_DPLL3_BIT));
|
||||
} else if (BOARD_IS_BB(machine.board_id)) {
|
||||
mmio_set((omap_reset.base + AM335X_PRM_DEVICE_OFFSET +
|
||||
mmio_set((omap_res.base + AM335X_PRM_DEVICE_OFFSET +
|
||||
AM335X_PRM_RSTCTRL_REG),
|
||||
(1 << AM335X_RST_GLOBAL_WARM_SW_BIT));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bsp_poweroff(void)
|
||||
omap_poweroff(void)
|
||||
{
|
||||
|
||||
/*
|
||||
@@ -88,7 +88,7 @@ bsp_poweroff(void)
|
||||
}
|
||||
}
|
||||
|
||||
void bsp_disable_watchdog(void)
|
||||
void omap_disable_watchdog(void)
|
||||
{
|
||||
if(BOARD_IS_BB(machine.board_id)) {
|
||||
mmio_write(AM335X_WDT_BASE+AM335X_WDT_WSPR, 0xAAAA);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user