33 Commits

Author SHA1 Message Date
2ac629943d ARM: MMC driver fix build lists 2017-07-31 07:55:37 +02:00
9ffc21964a ARM: MMC driver
- Simplify build structure & Makefiles

 - Fix log system, by making sure there is only one log object per
   driver and fixed level management, to be able to set LEVEL_TRACE

 - Fixed block size support on RPI, as the MMC driver uses different
   block sizes
2017-07-31 07:54:53 +02:00
5a7163ed5e ARM: Release scrips improvements 2017-07-30 10:08:26 +02:00
Korobov Nikita
c95010bf0e [MAJOR] Initial commit for the SPI driver
There are no opportunity to choose the SPI mode and bus speed.
It will be added in the future commits (maybe as the ioctl call)
It hasn't been debuged yet. Don't use it.
2017-07-27 15:47:02 +03:00
Korobov Nikita
394a5878ef [MAJOR] Initial commit for the PCM driver
It doesn't work yet. Don't use it.
2017-07-27 15:45:34 +03:00
Korobov Nikita
944242a42c [MINOR] This commit adds functionality of the i2c driver
I'm not sure that it's stable version.
2017-07-25 20:02:15 +03:00
Korobov Nikita
d0f19da8ee [CLEANUP] Changes, which are necessary after debug the mailbox driver 2017-07-14 03:50:32 +03:00
Korobov Nikita
364990d9da [MAJOR] The mailbox driver works
The final commit about the mailbox driver.
It was debuged and tested. You can use it from this moment.
2017-07-14 03:27:12 +03:00
Korobov Nikita
25de27fbcb [MAJOR] The I2C driver become driver for RPI
The driver is compatible with the Raspberry Pi.
There are only the one I2C driver for each platforms.
NOTE! It have not debuged yet. Don't use it!
2017-07-13 17:44:17 +03:00
Korobov Nikita
8e0800e994 [MAJOR] First commit for the RPI i2c driver
This commit present Makefile for the several platforms.
It doesn't work yet.
2017-07-12 23:59:13 +03:00
Korobov Nikita
7442558681 [CLEANUP] The tty constants updated 2017-07-12 16:09:05 +03:00
Korobov Nikita
dab346e282 [MAJOR] FIFO UART is enabled
Added support of FIFO, timeout and fifo-size may be not optimal, but
basic functional is free.
Copy-paste issue fixed by this hack.
2017-07-11 18:34:29 +03:00
Korobov Nikita
fc93b4db26 [MINOR] The framebuffer driver changed for mailbox 2017-07-09 20:49:53 +03:00
Korobov Nikita
88661079be [MAJOR] Full functionality of mailbox driver 2017-07-08 19:31:09 +03:00
Korobov Nikita
ef69c49d79 [MAJOR] The first version of mailbox driver
DON'T USE THIS VESRION.
Basic functional of mailbox realized.
2017-07-05 12:00:33 +03:00
Korobov Nikita
65def63cad [MINOR] SD card init success
It's almost stable version. DO NOT USE IT!
2017-07-05 05:53:50 +03:00
Korobov Nikita
03eaf9dac8 [MAJOR] The SDCard RPI driver first commit
The new driver for RPI added. There are two variants mmc and emmc
for each platform. It's not good solution, because each two implementations
differ by the registers set, the base address and some functionality.
This driver doesn't work. It'll be fixed in the future.
2017-06-30 17:19:06 +03:00
Korobov Nikita
6192a53b2d [MINOR] Fixed the RPI3 tty
Some small things in the tty driver are improved.
Added the RPI3 compatibility.
2017-05-30 05:08:58 +03:00
Korobov Nikita
add751549f [MAJOR] Added a simple device tree parser 2017-05-27 04:54:01 +03:00
Korobov Nikita
e70062feb3 [MAJOR] Add device tree compatibility
Unstable version of device tree compability.
Device tree passes through bootloader, but doesn't parse on this stage.
2017-05-25 08:23:38 +03:00
Korobov Nikita
7b468ec005 [MAJOR] Add libfdt under BSD license
The libfdt is a good toolchain to parse a device tree.
2017-05-25 08:22:08 +03:00
Korobov Nikita
63723e1e7b [MAJOR] Added platform-dependent functions table
Added table, which contains platform-dependent code.
All platform-dependent functions must be called by using this table.
There are no difference between kernels for any ARM platform.
There are the only one kernel for any ARM platform.
2017-05-25 08:21:08 +03:00
Korobov Nikita
cde275c049 [MAJOR] Updated early ARM bootstrap
There are no unmapped code in kernel now.

_kern_phys_base is determed in run-time.
NOTE! It doesn't work on the RPI3 now. Fix it later.
2017-05-25 08:19:17 +03:00
Korobov Nikita
cecc3c0d18 [MAJOR] Prepare to cleaning up boot process 2017-05-25 08:13:59 +03:00
Jean-Baptiste Boric
7cbfcd26a2 kernel: add support for system timer
This timer is the one we're supposed to use all along, but QEMU doesn't
support it for now, so we keep the ARM internal timers around if needed.
These timers shouldn't be used since they aren't memory-mapped and thus
unsuitable for MINIX 3 (for the user-mapped page).
2016-06-03 20:05:23 +02:00
Jean-Baptiste Boric
b76b176eaf gpio: add support for Raspberry Pi 2 and 3
Co-Authored-By: Benjamin Dauphin <benjamin.dauphin@live.fr>
Co-Authored-By: Gilles Henaux <gill.henaux@gmail.com>
2016-06-01 11:11:32 +02:00
Jean-Baptiste Boric
1e7d6ee8a7 fb: add support for Raspberry Pi 2 and 3
Co-Authored-By: Benjamin Dauphin <benjamin.dauphin@live.fr>
Co-Authored-By: Gilles Henaux <gill.henaux@gmail.com>
2016-06-01 11:11:31 +02:00
Jean-Baptiste Boric
aed435f2cf tty: add support for Raspberry Pi 2 and 3
Co-Authored-By: Benjamin Dauphin <benjamin.dauphin@live.fr>
Co-Authored-By: Gilles Henaux <gill.henaux@gmail.com>
2016-06-01 11:11:30 +02:00
Jean-Baptiste Boric
61569864b0 kernel: add support for Raspberry Pi 2 and 3
Co-Authored-By: Benjamin Dauphin <benjamin.dauphin@live.fr>
Co-Authored-By: Gilles Henaux <gill.henaux@gmail.com>
2016-06-01 11:11:29 +02:00
Jean-Baptiste Boric
c5e7db6fac kernel: remove hard-coded defines in earm
earm-wide defines don't play nice with multiple BSPs.

Co-Authored-By: Benjamin Dauphin <benjamin.dauphin@live.fr>
Co-Authored-By: Gilles Henaux <gill.henaux@gmail.com>
2016-06-01 11:11:28 +02:00
Jean-Baptiste Boric
1fb1a5c17c Use BSP_NAME when building kernel
Co-Authored-By: Benjamin Dauphin <benjamin.dauphin@live.fr>
Co-Authored-By: Gilles Henaux <gill.henaux@gmail.com>
2016-06-01 11:11:27 +02:00
Jean-Baptiste Boric
04a7b1091f Introduce BSP_NAME
The current build system can't handle properly having more than one
board family and more than one BSP, so we make up a way to select what
to build and what to do based on the BSP_NAME variable which will
become useful later on.

This commit purposely breaks the Jenkins infrastructure as it exists
now, so that the pain is felt only once.

Co-Authored-By: Benjamin Dauphin <benjamin.dauphin@live.fr>
Co-Authored-By: Gilles Henaux <gill.henaux@gmail.com>
2016-06-01 11:11:26 +02:00
Jean-Baptiste Boric
ad60a889a0 Replace fetch_u-boot.sh with checkout_repo.sh
This allows checking out Git repositories besides U-Boot.

Co-Authored-By: Benjamin Dauphin <benjamin.dauphin@live.fr>
Co-Authored-By: Gilles Henaux <gill.henaux@gmail.com>
2016-06-01 11:11:25 +02:00
148 changed files with 13595 additions and 850 deletions

1
.gitignore vendored
View File

@@ -9,6 +9,7 @@ cscope.*
*.rej
*.[1-9].gz
*.o
*.elf
*.[psS]o
*.pico
lib*.so*

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
;
};

View File

@@ -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
View File

@@ -0,0 +1,3 @@
SUBDIR = include lib
.include <bsd.subdir.mk>

3
external/bsd/libfdt/Makefile.inc vendored Normal file
View File

@@ -0,0 +1,3 @@
.include <bsd.own.mk>
.PATH: ${SRCDIR} ${SRCDIR}/include

251
external/bsd/libfdt/dist/fdt.c vendored Normal file
View 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;
}

View 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;
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

View 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 */

View 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
View 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
View 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
View 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

View File

@@ -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

View File

@@ -220,6 +220,9 @@ do
des="keyboard input $n"
dev=kbd$n
;;
15,0)
dev=mailbox
;;
64,64)
des="mouse input multiplexer"
dev=mousemux

View File

@@ -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} : '.*\\(.\\)'`

View File

@@ -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)

View File

@@ -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>

View 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>

View 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);
}

View 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_

View File

@@ -7,6 +7,7 @@ SUBDIR+= ti1225
. if ${MACHINE_ARCH} == "earm"
SUBDIR+= i2c
SUBDIR+= spi
. endif # ${MACHINE_ARCH} == "earm"
.endif # ${MKIMAGEONLY} == "no"

View File

@@ -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>

View File

@@ -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.

View File

@@ -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

View File

@@ -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;
};

View 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;
}

View 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 */

View 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 */

View File

@@ -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

View File

@@ -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;
}

View 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;
};

View 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
View 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);
}

View 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_ */

View File

@@ -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>

View File

@@ -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)
{
}
}

View 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 = &regs_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)
{
}

View File

@@ -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_*/

View 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_*/

View File

@@ -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

View File

@@ -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) */

View File

@@ -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";
}

View File

@@ -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";
}

File diff suppressed because it is too large Load Diff

View File

@@ -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) \

View File

@@ -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) \

View File

@@ -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"

View File

@@ -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

View File

@@ -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` "$@"

View File

@@ -6,5 +6,6 @@ SUBDIR+= gpio
SUBDIR+= log
SUBDIR+= random
SUBDIR+= mailbox
.include <bsd.subdir.mk>

View File

@@ -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);
}
}

View 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>

View 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);
}

View 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;
}
}
}

View 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_ */

View File

@@ -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

View 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 */

View 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 */

View File

@@ -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;
}

View File

@@ -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

View 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;
}

View File

@@ -3,6 +3,6 @@
#ifndef _INTERRUPT_H
#define _INTERRUPT_H
#define NR_IRQ_VECTORS 125
#define NR_IRQ_VECTORS 128
#endif /* _INTERRUPT_H */

View File

@@ -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 */

View File

@@ -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)

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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();
}
/*===========================================================================*/

View File

@@ -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__ */

View File

@@ -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__ */

View File

@@ -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__ */

View File

@@ -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_ */

View File

@@ -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_ */

View File

@@ -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__ */

View 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

View File

@@ -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();
}

View File

@@ -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));

View File

@@ -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;

View File

@@ -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