U-Boot
Threads by month
- ----- 2025 -----
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2000 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
November 2014
- 182 participants
- 736 discussions

15 Jan '15
Add USB EHCI/XHCI support for ls1021atwr platform and
making xHCI as default mode
Signed-off-by: Ramneek Mehresh <ramneek.mehresh(a)freescale.com>
---
include/configs/ls1021atwr.h | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/include/configs/ls1021atwr.h b/include/configs/ls1021atwr.h
index 45b2272..109e58c 100644
--- a/include/configs/ls1021atwr.h
+++ b/include/configs/ls1021atwr.h
@@ -28,6 +28,34 @@
#define CONFIG_SYS_INIT_RAM_SIZE OCRAM_SIZE
/*
+ * USB
+ */
+/*EHCI Support*/
+/*#define CONFIG_HAS_FSL_DR_USB*/
+
+#ifdef CONFIG_HAS_FSL_DR_USB
+#define CONFIG_USB_EHCI
+#define CONFIG_USB_EHCI_FSL
+#define CONFIG_EHCI_HCD_INIT_AFTER_RESET
+#endif
+
+/*XHCI Support*/
+#define CONFIG_HAS_FSL_XHCI_USB
+
+#ifdef CONFIG_HAS_FSL_XHCI_USB
+#define CONFIG_USB_XHCI
+#define CONFIG_USB_XHCI_FSL
+#define CONFIG_USB_MAX_CONTROLLER_COUNT 1
+#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 1
+#endif
+
+#if defined(CONFIG_HAS_FSL_DR_USB) || defined(CONFIG_HAS_FSL_XHCI_USB)
+#define CONFIG_CMD_USB
+#define CONFIG_USB_STORAGE
+#define CONFIG_CMD_EXT2
+#endif
+
+/*
* Generic Timer Definitions
*/
#define GENERIC_TIMER_CLK 12500000
--
1.8.3.1
2
5

15 Jan '15
The common/board_r.c has show_model_r() to display the model name
if the DTB has a "model" property. It sounds useful to have a similar
function in common/board_f.c too because most of the boards show
their board name before relocation.
Instead of implementing the same function in both common/board_f.c
and common/board_r.c, let's split it up into common/show_board_info.c.
Signed-off-by: Masahiro Yamada <yamada.m(a)jp.panasonic.com>
---
common/Makefile | 2 ++
common/board_f.c | 2 +-
common/board_info.c | 34 ++++++++++++++++++++++++++++++++++
common/board_r.c | 18 +-----------------
include/common.h | 13 +++++++------
5 files changed, 45 insertions(+), 24 deletions(-)
create mode 100644 common/board_info.c
diff --git a/common/Makefile b/common/Makefile
index 9c47e20..8de1ac7 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -37,6 +37,8 @@ endif
# boards
obj-$(CONFIG_SYS_GENERIC_BOARD) += board_f.o
obj-$(CONFIG_SYS_GENERIC_BOARD) += board_r.o
+obj-$(CONFIG_DISPLAY_BOARDINFO) += board_info.o
+obj-$(CONFIG_DISPLAY_BOARDINFO_LATE) += board_info.o
# core command
obj-y += cmd_boot.o
diff --git a/common/board_f.c b/common/board_f.c
index 98c9c72..48acc7d 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -886,7 +886,7 @@ static init_fnc_t init_sequence_f[] = {
prt_mpc5xxx_clks,
#endif /* CONFIG_MPC5xxx */
#if defined(CONFIG_DISPLAY_BOARDINFO)
- checkboard, /* display board info */
+ show_board_info,
#endif
INIT_FUNC_WATCHDOG_INIT
#if defined(CONFIG_MISC_INIT_F)
diff --git a/common/board_info.c b/common/board_info.c
new file mode 100644
index 0000000..e0d5cef
--- /dev/null
+++ b/common/board_info.c
@@ -0,0 +1,34 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/compiler.h>
+
+int __weak checkboard(void)
+{
+ printf("Board: Unknown\n");
+ return 0;
+}
+
+/*
+ * If the root node of the DTB has a "model" property, show it.
+ * If CONFIG_OF_CONTROL is disabled or the "model" property is missing,
+ * fall back to checkboard().
+ */
+int show_board_info(void)
+{
+#ifdef CONFIG_OF_CONTROL
+ DECLARE_GLOBAL_DATA_PTR;
+ const char *model;
+
+ model = fdt_getprop(gd->fdt_blob, 0, "model", NULL);
+
+ if (model) {
+ printf("Model: %s\n", model);
+ return 0;
+ }
+#endif
+
+ return checkboard();
+}
diff --git a/common/board_r.c b/common/board_r.c
index 19c6427..61fbbc8 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -498,22 +498,6 @@ static int initr_api(void)
}
#endif
-#ifdef CONFIG_DISPLAY_BOARDINFO_LATE
-static int show_model_r(void)
-{
- /* Put this here so it appears on the LCD, now it is ready */
-# ifdef CONFIG_OF_CONTROL
- const char *model;
-
- model = (char *)fdt_getprop(gd->fdt_blob, 0, "model", NULL);
- printf("Model: %s\n", model ? model : "<unknown>");
-# else
- checkboard();
-# endif
- return 0;
-}
-#endif
-
/* enable exceptions */
#ifdef CONFIG_ARM
static int initr_enable_interrupts(void)
@@ -823,7 +807,7 @@ init_fnc_t init_sequence_r[] = {
#endif
console_init_r, /* fully init console as a device */
#ifdef CONFIG_DISPLAY_BOARDINFO_LATE
- show_model_r,
+ show_board_info,
#endif
#ifdef CONFIG_ARCH_MISC_INIT
arch_misc_init, /* miscellaneous arch-dependent init */
diff --git a/include/common.h b/include/common.h
index f1ab2cf..c82336f 100644
--- a/include/common.h
+++ b/include/common.h
@@ -231,12 +231,13 @@ int run_command_list(const char *cmd, int len, int flag);
extern char console_buffer[];
/* arch/$(ARCH)/lib/board.c */
-void board_init_f(ulong);
-void board_init_r (gd_t *, ulong) __attribute__ ((noreturn));
-int checkboard (void);
-int checkflash (void);
-int checkdram (void);
-int last_stage_init(void);
+void board_init_f(ulong);
+void board_init_r(gd_t *, ulong) __attribute__ ((noreturn));
+int checkboard(void);
+int show_board_info(void);
+int checkflash(void);
+int checkdram(void);
+int last_stage_init(void);
extern ulong monitor_flash_len;
int mac_read_from_eeprom(void);
extern u8 __dtb_dt_begin[]; /* embedded device tree blob */
--
1.9.1
2
3
Resending this since I got no replies on the first version.
I also fixed up the commit log of #1.
------------
I spent some time looking into boot times of AM335x platforms. One big
improvement I made came with adding support for GPMC prefetch mode,
which gave a speed-up of NAND reads of roughly factor 2.
This is what patch #1 does.
Note that this is currently limited to read operations in 8-bit mode, but
I believe it could be easily extended to 16-bit operations if anyone has
hardware to test it on. Using the engine for write mode speed
improvements should also be doable, but I didn't spend time on it yet.
That can be added as a separate patch later.
Patch #2 decreases the GPMC memory map window size from 256MiB to 16MiB.
Admittedly, I'm not quite sure about the reason, but a read from
offset 0 in this memory area will freeze U-Boot instantly if the size
is configured to 256MiB. As contents of the FIFO are accessed in a
pseudo-mode from offset 0 anyway, it doesn't really matter.
What I also did to further speed up my boot was to tweak the GPMC
parameters for the NAND chip on our boards, but that's not part of this
patch set, and probably deserves a little more cleanup.
Test results and feedback very welcome.
Thanks,
Daniel
Daniel Mack (2):
mtd: OMAP: Enable GPMC prefetch mode
ARM: omap-common: gpmp: decrease memory region size to 16MiB
arch/arm/cpu/armv7/omap-common/mem-common.c | 2 +-
doc/README.nand | 5 ++
drivers/mtd/nand/omap_gpmc.c | 115 +++++++++++++++++++++++++++-
include/linux/mtd/omap_gpmc.h | 6 +-
4 files changed, 124 insertions(+), 4 deletions(-)
--
1.9.3
5
10

[U-Boot] [PATCH] tools/kwbimage.c: fix parser error handling
by andreas.develï¼ googlemail.com 11 Jan '15
by andreas.develï¼ googlemail.com 11 Jan '15
11 Jan '15
From: Andreas Bießmann <andreas.devel(a)googlemail.com>
The two error checks for image_boot_mode_id and image_nand_ecc_mode_id where
wrong and would never fail, fix that!
This was detected by Apple's clang compiler:
---8<---
HOSTCC tools/kwbimage.o
tools/kwbimage.c:553:20: warning: comparison of unsigned expression < 0 is always false [-Wtautological-compare]
if (el->bootfrom < 0) {
~~~~~~~~~~~~ ^ ~
tools/kwbimage.c:571:23: warning: comparison of unsigned expression < 0 is always false [-Wtautological-compare]
if (el->nandeccmode < 0) {
~~~~~~~~~~~~~~~ ^ ~
2 warnings generated.
--->8---
Signed-off-by: Andreas Bießmann <andreas.devel(a)googlemail.com>
---
tools/kwbimage.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/tools/kwbimage.c b/tools/kwbimage.c
index 42870ed..8fd70ef 100644
--- a/tools/kwbimage.c
+++ b/tools/kwbimage.c
@@ -548,13 +548,14 @@ static int image_create_config_parse_oneline(char *line,
el->version = atoi(value);
} else if (!strcmp(keyword, "BOOT_FROM")) {
char *value = strtok_r(NULL, deliminiters, &saveptr);
- el->type = IMAGE_CFG_BOOT_FROM;
- el->bootfrom = image_boot_mode_id(value);
- if (el->bootfrom < 0) {
+ int ret = image_boot_mode_id(value);
+ if (ret < 0) {
fprintf(stderr,
"Invalid boot media '%s'\n", value);
return -1;
}
+ el->type = IMAGE_CFG_BOOT_FROM;
+ el->bootfrom = ret;
} else if (!strcmp(keyword, "NAND_BLKSZ")) {
char *value = strtok_r(NULL, deliminiters, &saveptr);
el->type = IMAGE_CFG_NAND_BLKSZ;
@@ -566,13 +567,14 @@ static int image_create_config_parse_oneline(char *line,
strtoul(value, NULL, 16);
} else if (!strcmp(keyword, "NAND_ECC_MODE")) {
char *value = strtok_r(NULL, deliminiters, &saveptr);
- el->type = IMAGE_CFG_NAND_ECC_MODE;
- el->nandeccmode = image_nand_ecc_mode_id(value);
- if (el->nandeccmode < 0) {
+ int ret = image_nand_ecc_mode_id(value);
+ if (ret < 0) {
fprintf(stderr,
"Invalid NAND ECC mode '%s'\n", value);
return -1;
}
+ el->type = IMAGE_CFG_NAND_ECC_MODE;
+ el->nandeccmode = ret;
} else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
char *value = strtok_r(NULL, deliminiters, &saveptr);
el->type = IMAGE_CFG_NAND_PAGESZ;
--
1.9.3 (Apple Git-50)
4
4

[U-Boot] [PATCH] fix: tools: kwbimage.c: Initialize headersz to suppress warning
by Lukasz Majewski 10 Jan '15
by Lukasz Majewski 10 Jan '15
10 Jan '15
When building with my toolchain (4.8.2):
CROSS_COMPILE=/home/lukma/work/ptxdist/toolchains/arm/OSELAS.Toolchain-2013.12.0/arm-v7a-linux-gnueabi/gcc-4.8.2-glibc-2.18-binutils-2.24-kernel-3.12-sanitized/bin/arm-v7a-linux-gnueabi-
I see following WARNING:
tools/kwbimage.c: In function "kwbimage_set_header":
tools/kwbimage.c:803:8: warning: "headersz" may be used uninitialized in this function [-Wmaybe-uninitialized]
memcpy(ptr, image, headersz);
^
This fix aims to suppress it.
Signed-off-by: Lukasz Majewski <l.majewski(a)samsung.com>
---
tools/kwbimage.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/kwbimage.c b/tools/kwbimage.c
index c50f2e2..2c302e5 100644
--- a/tools/kwbimage.c
+++ b/tools/kwbimage.c
@@ -728,7 +728,7 @@ static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
FILE *fcfg;
void *image = NULL;
int version;
- size_t headersz;
+ size_t headersz = 0;
uint32_t checksum;
int ret;
int size;
--
2.0.0.rc2
9
16

[U-Boot] [PATCH] Kconfig: move EXPERT option under "General setup" menu
by Masahiro Yamada 07 Jan '15
by Masahiro Yamada 07 Jan '15
07 Jan '15
Make it a sub-menu of "General setup" like Linux Kernel.
Signed-off-by: Masahiro Yamada <yamada.m(a)jp.panasonic.com>
Cc: Tom Rini <trini(a)ti.com>
---
Kconfig | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Kconfig b/Kconfig
index 153ee2b..60cf1dd 100644
--- a/Kconfig
+++ b/Kconfig
@@ -56,8 +56,6 @@ config CC_OPTIMIZE_FOR_SIZE
This option is enabled by default for U-Boot.
-endmenu # General setup
-
menuconfig EXPERT
bool "Configure standard U-Boot features (expert users)"
help
@@ -66,6 +64,8 @@ menuconfig EXPERT
environments which can tolerate a "non-standard" U-Boot.
Only use this if you really know what you are doing.
+endmenu # General setup
+
menu "Boot images"
config SPL_BUILD
--
1.9.1
3
5

07 Jan '15
This is v9 of the patchset adding support Odroud XU3 board.
link to the previous version:
v2: https://www.mail-archive.com/u-boot@lists.denx.de/msg152275.html
v3: https://www.mail-archive.com/u-boot%40lists.denx.de/msg152677.html
v4: https://patchwork.ozlabs.org/patch/407411/
v5: https://patchwork.ozlabs.org/patch/407941/
v6: https://patchwork.ozlabs.org/patch/408647/
v7: https://patchwork.ozlabs.org/patch/410204/
v8: https://patchwork.ozlabs.org/patch/410709/
The patchset by Akshay Saraswat is already merged into u-boot-samsung.
Please ignore the instruction about the additional patchset in v8.
How to test this patch:
1. git clone http://git.denx.de/u-boot-samsung.git
2. Apply this patchset
3. make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- odroid-xu3_config
4. make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j8
5. Now you can use u-boot-dtb.bin for your downloading
WANRNING: The u-boot-dtb.bin must not be bigger than 335872 bytes.
Depending on your compiler, it can be. Try another one if you get a
problem. I use 'gcc version 4.8.2 (Ubuntu/Linaro 4.8.2-16ubuntu4)' on
Ubuntu 64-bit machine.
Note: If you use micro SD card for your test you have to apply the below
patch additionally. This patch is needed, because micro sd card is
recognized as MMC1 instead of MMC0. Additional work is needed to make it
work regardless of device id.
diff --git a/include/configs/exynos5-common.h b/include/configs/exynos5-common.h
index ba591e7..437eaae 100644
--- a/include/configs/exynos5-common.h
+++ b/include/configs/exynos5-common.h
@@ -109,7 +109,7 @@
#define CONFIG_SYS_MONITOR_BASE 0x00000000
-#define CONFIG_SYS_MMC_ENV_DEV 0
+#define CONFIG_SYS_MMC_ENV_DEV 1
#define CONFIG_SECURE_BL1_ONLY
diff --git a/include/configs/odroid_xu3.h b/include/configs/odroid_xu3.h
index cda4f26..b46ccad 100644
--- a/include/configs/odroid_xu3.h
+++ b/include/configs/odroid_xu3.h
@@ -110,15 +110,15 @@
"run kernel_args;" \
"bootz ${kerneladdr} ${initrd_addr} ${fdt_addr};\0" \
"autoboot=" \
- "if test -e mmc 0 Image.itb; then; " \
+ "if test -e mmc 1 Image.itb; then; " \
"run boot_fit;" \
- "elif test -e mmc 0 zImage; then; " \
+ "elif test -e mmc 1 zImage; then; " \
"run boot_zimg;" \
- "elif test -e mmc 0 uImage; then; " \
+ "elif test -e mmc 1 uImage; then; " \
"run boot_uimg;" \
"fi;\0" \
"console=" CONFIG_DEFAULT_CONSOLE \
- "mmcbootdev=0\0" \
+ "mmcbootdev=1\0" \
"mmcbootpart=1\0" \
"mmcrootdev=0\0" \
"mmcrootpart=2\0" \
Changes for v2:
- Add a patch to add new common setup header file for Odroid X2/U3
and Odroid XU3
Changes for v3:
- Remove the patch which adds new common setup header file from v2
- Remove the wrong patch to fix GPIO information of Exynos 5800
- Remove unnecessary node from DT file
- Remove unnecessary features from config file
- Fix some trivial typos in comments
Changes for v4:
- Add MMC FIFO buffer's configuration to DT file
- Make CONFIG_OF_CONTROL be set by the target information
- Add basic document to doc/README.odroid-xu3
- Add CONFIG_CMD_EXT4 to config file
- Add environment size and offset to config file
- Add extra default environment to make bootable without modification
- Remove unnecessary features from config file
Changes for v5:
- Add the specific build instruction
- Update the information of patchset by Akshay Saraswat
- Convert /include/ to #include in DT file
Changes for v6:
- Separate out the documentation to new commit
- Remove unnecessary header file inclusuib from the board-specific setup file
- Make the function board_clock_init be declared, only when
CONFIG_BOARD_EARLY_INIT_F is defined
Changes for v7:
- Fix several errata in the documentation
- Remove OF_CONTROL dependency from !SPL_BUILD
Changes for v8:
- Remove unnecessary properties in DT mmc node
Changes for v9:
- Remove the first patch which change GPIO entries order. It became useless,
after DT support is added
- Remove useless variables in the default environment
- Add the new contents to the documentation of Odroid X2/U2, instead of
making new document for Odorid XU3
- Remove the detailed information in the header file, and leave the
reference to the documentation
Hyungwon Hwang (2):
Odroid-XU3: Add support for Odroid-XU3
Odroid-XU3: Add documentation for Odroid-XU3
arch/arm/cpu/armv7/exynos/Kconfig | 5 ++
arch/arm/dts/Makefile | 3 +-
arch/arm/dts/exynos5422-odroidxu3.dts | 57 +++++++++++++++
board/samsung/odroid-xu3/Kconfig | 12 +++
board/samsung/odroid-xu3/MAINTAINERS | 6 ++
board/samsung/odroid-xu3/Makefile | 7 ++
board/samsung/odroid-xu3/odroid-xu3.c | 122 +++++++++++++++++++++++++++++++
board/samsung/odroid-xu3/setup.h | 95 ++++++++++++++++++++++++
configs/odroid-xu3_defconfig | 4 +
doc/README.odroid | 46 ++++++++----
include/configs/odroid.h | 5 --
include/configs/odroid_xu3.h | 133 ++++++++++++++++++++++++++++++++++
12 files changed, 473 insertions(+), 22 deletions(-)
create mode 100644 arch/arm/dts/exynos5422-odroidxu3.dts
create mode 100644 board/samsung/odroid-xu3/Kconfig
create mode 100644 board/samsung/odroid-xu3/MAINTAINERS
create mode 100644 board/samsung/odroid-xu3/Makefile
create mode 100644 board/samsung/odroid-xu3/odroid-xu3.c
create mode 100644 board/samsung/odroid-xu3/setup.h
create mode 100644 configs/odroid-xu3_defconfig
create mode 100644 include/configs/odroid_xu3.h
--
1.9.1
10
47
From: Christoph Dietrich <christoph.dietrich(a)keymile.com>
This board is similar to TUXX1, but it has a different FPGA connected to
chipselect 2. Therefore we need a different configuration for this
chipselect.
Signed-off-by: Christoph Dietrich <christoph.dietrich(a)keymile.com>
Signed-off-by: Holger Brunck <holger.brunck(a)keymile.com>
cc: Kim Phillips <kim.phillips(a)freescale.com>
---
boards.cfg | 1 +
include/configs/tuxx1.h | 42 ++++++++++++++++++++++++++++++++++--------
2 files changed, 35 insertions(+), 8 deletions(-)
diff --git a/boards.cfg b/boards.cfg
index 1ba2081..7ddf34d 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -717,6 +717,7 @@ Active powerpc mpc83xx - keymile km83xx
Active powerpc mpc83xx - keymile km83xx kmeter1 km8360:KMETER1 Holger Brunck <holger.brunck(a)keymile.com>
Active powerpc mpc83xx - keymile km83xx kmopti2 tuxx1:KMOPTI2 Holger Brunck <holger.brunck(a)keymile.com>
Active powerpc mpc83xx - keymile km83xx kmsupx5 tuxx1:KMSUPX5 Heiko Schocher <hs(a)denx.de>
+Active powerpc mpc83xx - keymile km83xx kmtepr2 tuxx1:KMTEPR2 Holger Brunck <holger.brunck(a)keymile.com>
Active powerpc mpc83xx - keymile km83xx kmvect1 suvd3:KMVECT1 Holger Brunck <holger.brunck(a)keymile.com>
Active powerpc mpc83xx - keymile km83xx suvd3 suvd3:SUVD3 Holger Brunck <holger.brunck(a)keymile.com>
Active powerpc mpc83xx - keymile km83xx tuge1 tuxx1:TUGE1 Holger Brunck <holger.brunck(a)keymile.com>
diff --git a/include/configs/tuxx1.h b/include/configs/tuxx1.h
index 08ead7f..a2eb82c 100644
--- a/include/configs/tuxx1.h
+++ b/include/configs/tuxx1.h
@@ -36,6 +36,9 @@
#elif defined(CONFIG_KMOPTI2)
#define CONFIG_KM_BOARD_NAME "kmopti2"
#define CONFIG_HOSTNAME kmopti2
+#elif defined(CONFIG_KMTEPR2)
+#define CONFIG_KM_BOARD_NAME "kmtepr2"
+#define CONFIG_HOSTNAME kmtepr2
#else
#error ("Board not supported")
#endif
@@ -47,21 +50,42 @@
#define CONFIG_SYS_APP1_BASE 0xA0000000 /* PAXG */
#define CONFIG_SYS_APP1_SIZE 256 /* Megabytes */
-#if defined(CONFIG_TUXX1) || defined(CONFIG_KMOPTI2)
+#if defined(CONFIG_TUXX1) || defined(CONFIG_KMOPTI2) || defined(CONFIG_KMTEPR2)
#define CONFIG_SYS_APP2_BASE 0xB0000000 /* PINC3 */
#define CONFIG_SYS_APP2_SIZE 256 /* Megabytes */
#endif
/*
- * Init Local Bus Memory Controller:
+ * Init Local Bus Memory Controller
+ * All devices use Local bus configuration with 8Bit size and the
+ * general-purpose chip-select machine (GPCM) otherwise it's
+ * documented in the table.
* Device on
- * Bank Bus Machine PortSz Size TUDA1 TUXA1 TUGE1 KMSUPX4 KMOPTI2
- * ---- --- ------- ------ ----- ---------------------------------------
- * 2 Local GPCM 8 bit 256MB PAXG LPXF PAXI LPXF PAXE
- * 3 Local GPCM 8 bit 256MB PINC3 PINC2 unused unused OPI2(16 bit)
- *
+ * Bank Size TUDA1 TUXA1 TUGE1 KMSUPX4 KMOPTI2 KMTEPR2
+ * ---- ----- -------------------------------------------------------
+ * 2 256MB PAXG LPXF PAXI LPXF PAXE NVRAM
+ * 3 256MB PINC3 PINC2 unused unused OPI2(16 bit) TEP2 (16 bit)
*/
+#if defined(CONFIG_KMTEPRO2)
+/*
+ * Configuration for C2 (NVRAM) on the local bus
+ */
+#define CONFIG_SYS_LBLAWBAR2_PRELIM CONFIG_SYS_APP1_BASE
+#define CONFIG_SYS_LBLAWAR2_PRELIM (LBLAWAR_EN | LBLAWAR_256MB)
+#define CONFIG_SYS_BR2_PRELIM (CONFIG_SYS_APP1_BASE | \
+ BR_PS_8 | \
+ BR_MS_GPCM | \
+ BR_V)
+#define CONFIG_SYS_OR2_PRELIM (MEG_TO_AM(CONFIG_SYS_APP1_SIZE) | \
+ OR_GPCM_CSNT | \
+ OR_GPCM_ACS_DIV2 | \
+ OR_GPCM_XACS | \
+ OR_GPCM_SCY_2 | \
+ OR_GPCM_TRLX_SET | \
+ OR_GPCM_EHTR_SET | \
+ OR_GPCM_EAD)
+#else
/*
* Configuration for C2 on the local bus
*/
@@ -82,6 +106,8 @@
OR_GPCM_TRLX_SET | \
OR_GPCM_EHTR_CLEAR | \
OR_GPCM_EAD)
+#endif
+
#if defined(CONFIG_TUXX1)
/*
* Configuration for C3 on the local bus
@@ -108,7 +134,7 @@
MxMR_WLFx_2X)
#endif
-#if defined(CONFIG_KMOPTI2)
+#if defined(CONFIG_KMOPTI2) || defined(CONFIG_KMTEPR2)
/*
* Configuration for C3 on the local bus
*/
--
1.8.0.1
1
2
From: Oliver Schinagl <oliver(a)schinagl.nl>
The A31 uses the AXP221 pmic for various voltages.
Signed-off-by: Oliver Schinagl <oliver(a)schinagl.nl>
Signed-off-by: Hans de Goede <hdegoede(a)redhat.com>
--
Changes in v2:
-Rebase
Changes in v3:
-Add support for all dldo and aldo-s
-Add Kconfig option to select building AXP221 and to select voltage of
dldo and aldo-s
Changes in v4:
-Add axp221_setbits helper function
-Use symbolic names for enabled bits in CTRL1 - CTRL3 registers
---
board/sunxi/board.c | 26 +++++++
drivers/power/Kconfig | 47 +++++++++++++
drivers/power/Makefile | 1 +
drivers/power/axp221.c | 186 +++++++++++++++++++++++++++++++++++++++++++++++++
include/axp221.h | 50 +++++++++++++
5 files changed, 310 insertions(+)
create mode 100644 drivers/power/axp221.c
create mode 100644 include/axp221.h
diff --git a/board/sunxi/board.c b/board/sunxi/board.c
index 03890c8..e6ec5b8 100644
--- a/board/sunxi/board.c
+++ b/board/sunxi/board.c
@@ -19,6 +19,9 @@
#ifdef CONFIG_AXP209_POWER
#include <axp209.h>
#endif
+#ifdef CONFIG_AXP221_POWER
+#include <axp221.h>
+#endif
#include <asm/arch/clock.h>
#include <asm/arch/cpu.h>
#include <asm/arch/dram.h>
@@ -169,6 +172,29 @@ void sunxi_board_init(void)
power_failed |= axp209_set_ldo3(2800);
power_failed |= axp209_set_ldo4(2800);
#endif
+#ifdef CONFIG_AXP221_POWER
+ power_failed = axp221_init();
+ power_failed |= axp221_set_dcdc1(3000);
+ power_failed |= axp221_set_dcdc2(1200);
+ power_failed |= axp221_set_dcdc3(1200);
+ power_failed |= axp221_set_dcdc4(1200);
+ power_failed |= axp221_set_dcdc5(1500);
+#if CONFIG_AXP221_DLDO1_VOLT != -1
+ power_failed |= axp221_set_dldo1(CONFIG_AXP221_DLDO1_VOLT);
+#endif
+#if CONFIG_AXP221_DLDO4_VOLT != -1
+ power_failed |= axp221_set_dldo4(CONFIG_AXP221_DLDO4_VOLT);
+#endif
+#if CONFIG_AXP221_ALDO1_VOLT != -1
+ power_failed |= axp221_set_aldo1(CONFIG_AXP221_ALDO1_VOLT);
+#endif
+#if CONFIG_AXP221_ALDO2_VOLT != -1
+ power_failed |= axp221_set_aldo2(CONFIG_AXP221_ALDO2_VOLT);
+#endif
+#if CONFIG_AXP221_ALDO3_VOLT != -1
+ power_failed |= axp221_set_aldo3(CONFIG_AXP221_ALDO3_VOLT);
+#endif
+#endif
printf("DRAM:");
ramsize = sunxi_dram_init();
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index e69de29..1ec7c0e 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -0,0 +1,47 @@
+config AXP221_POWER
+ boolean "axp221 pmic support"
+ depends on MACH_SUN6I
+ default y
+ ---help---
+ Say y here to enable support for the axp221 pmic found on most sun6i
+ (A31) boards.
+
+config AXP221_DLDO1_VOLT
+ int "axp221 dldo1 voltage"
+ depends on AXP221_POWER
+ default -1
+ ---help---
+ Set the voltage (mV) to program the axp221 dldo1 at, set to -1 to
+ disable dldo1.
+
+config AXP221_DLDO4_VOLT
+ int "axp221 dldo4 voltage"
+ depends on AXP221_POWER
+ default -1
+ ---help---
+ Set the voltage (mV) to program the axp221 dldo4 at, set to -1 to
+ disable dldo4.
+
+config AXP221_ALDO1_VOLT
+ int "axp221 aldo1 voltage"
+ depends on AXP221_POWER
+ default -1
+ ---help---
+ Set the voltage (mV) to program the axp221 aldo1 at, set to -1 to
+ disable aldo1.
+
+config AXP221_ALDO2_VOLT
+ int "axp221 aldo2 voltage"
+ depends on AXP221_POWER
+ default -1
+ ---help---
+ Set the voltage (mV) to program the axp221 aldo2 at, set to -1 to
+ disable aldo2.
+
+config AXP221_ALDO3_VOLT
+ int "axp221 aldo3 voltage"
+ depends on AXP221_POWER
+ default -1
+ ---help---
+ Set the voltage (mV) to program the axp221 aldo3 at, set to -1 to
+ disable aldo3.
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index dc64e4d..04bd996 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -7,6 +7,7 @@
obj-$(CONFIG_AXP152_POWER) += axp152.o
obj-$(CONFIG_AXP209_POWER) += axp209.o
+obj-$(CONFIG_AXP221_POWER) += axp221.o
obj-$(CONFIG_EXYNOS_TMU) += exynos-tmu.o
obj-$(CONFIG_FTPMU010_POWER) += ftpmu010.o
obj-$(CONFIG_TPS6586X_POWER) += tps6586x.o
diff --git a/drivers/power/axp221.c b/drivers/power/axp221.c
new file mode 100644
index 0000000..941193a
--- /dev/null
+++ b/drivers/power/axp221.c
@@ -0,0 +1,186 @@
+/*
+ * (C) Copyright 2013 Oliver Schinagl <oliver(a)schinagl.nl>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <asm/arch/p2wi.h>
+#include <axp221.h>
+
+static u8 axp221_mvolt_to_cfg(int mvolt, int min, int max, int div)
+{
+ if (mvolt < min)
+ mvolt = min;
+ else if (mvolt > max)
+ mvolt = max;
+
+ return (mvolt - min) / div;
+}
+
+static int axp221_setbits(u8 reg, u8 bits)
+{
+ int ret;
+ u8 val;
+
+ ret = p2wi_read(reg, &val);
+ if (ret)
+ return ret;
+
+ val |= bits;
+ return p2wi_write(reg, val);
+}
+
+int axp221_set_dcdc1(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 1600, 3400, 100);
+
+ ret = p2wi_write(AXP221_DCDC1_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return axp221_setbits(AXP221_OUTPUT_CTRL2,
+ AXP221_OUTPUT_CTRL2_DCDC1_EN);
+}
+
+int axp221_set_dcdc2(unsigned int mvolt)
+{
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
+
+ return p2wi_write(AXP221_DCDC2_CTRL, cfg);
+}
+
+int axp221_set_dcdc3(unsigned int mvolt)
+{
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1860, 20);
+
+ return p2wi_write(AXP221_DCDC3_CTRL, cfg);
+}
+
+int axp221_set_dcdc4(unsigned int mvolt)
+{
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
+
+ return p2wi_write(AXP221_DCDC4_CTRL, cfg);
+}
+
+int axp221_set_dcdc5(unsigned int mvolt)
+{
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 1000, 2550, 50);
+
+ return p2wi_write(AXP221_DCDC5_CTRL, cfg);
+}
+
+int axp221_set_dldo1(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
+
+ ret = p2wi_write(AXP221_DLDO1_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return axp221_setbits(AXP221_OUTPUT_CTRL2,
+ AXP221_OUTPUT_CTRL2_DLDO1_EN);
+}
+
+int axp221_set_dldo2(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
+
+ ret = p2wi_write(AXP221_DLDO2_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return axp221_setbits(AXP221_OUTPUT_CTRL2,
+ AXP221_OUTPUT_CTRL2_DLDO2_EN);
+}
+
+int axp221_set_dldo3(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
+
+ ret = p2wi_write(AXP221_DLDO3_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return axp221_setbits(AXP221_OUTPUT_CTRL2,
+ AXP221_OUTPUT_CTRL2_DLDO3_EN);
+}
+
+int axp221_set_dldo4(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
+
+ ret = p2wi_write(AXP221_DLDO4_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return axp221_setbits(AXP221_OUTPUT_CTRL2,
+ AXP221_OUTPUT_CTRL2_DLDO4_EN);
+}
+
+int axp221_set_aldo1(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
+
+ ret = p2wi_write(AXP221_ALDO1_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return axp221_setbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_ALDO1_EN);
+}
+
+int axp221_set_aldo2(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
+
+ ret = p2wi_write(AXP221_ALDO2_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return axp221_setbits(AXP221_OUTPUT_CTRL1,
+ AXP221_OUTPUT_CTRL1_ALDO2_EN);
+}
+
+int axp221_set_aldo3(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
+
+ ret = p2wi_write(AXP221_ALDO3_CTRL, cfg);
+ if (ret)
+ return ret;
+
+ return axp221_setbits(AXP221_OUTPUT_CTRL3,
+ AXP221_OUTPUT_CTRL3_ALDO3_EN);
+}
+
+int axp221_init(void)
+{
+ u8 axp_chip_id;
+ int ret;
+
+ p2wi_init();
+ ret = p2wi_change_to_p2wi_mode(AXP221_CHIP_ADDR, AXP221_CTRL_ADDR,
+ AXP221_INIT_DATA);
+ if (ret)
+ return ret;
+
+ ret = p2wi_read(AXP221_CHIP_ID, &axp_chip_id);
+ if (ret)
+ return ret;
+
+ if (!(axp_chip_id == 0x6 || axp_chip_id == 0x7 || axp_chip_id == 0x17))
+ return -ENODEV;
+
+ return 0;
+}
diff --git a/include/axp221.h b/include/axp221.h
new file mode 100644
index 0000000..e3b4409
--- /dev/null
+++ b/include/axp221.h
@@ -0,0 +1,50 @@
+/*
+ * (C) Copyright 2013 Oliver Schinagl <oliver(a)schinagl.nl>
+ *
+ * X-Powers AXP221 Power Management IC driver
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#define AXP221_CHIP_ADDR 0x68
+#define AXP221_CTRL_ADDR 0x3e
+#define AXP221_INIT_DATA 0x3e
+
+#define AXP221_CHIP_ID 0x03
+#define AXP221_OUTPUT_CTRL1 0x10
+#define AXP221_OUTPUT_CTRL1_ALDO1_EN (1 << 6)
+#define AXP221_OUTPUT_CTRL1_ALDO2_EN (1 << 7)
+#define AXP221_OUTPUT_CTRL2 0x12
+#define AXP221_OUTPUT_CTRL2_DLDO1_EN (1 << 3)
+#define AXP221_OUTPUT_CTRL2_DLDO2_EN (1 << 4)
+#define AXP221_OUTPUT_CTRL2_DLDO3_EN (1 << 5)
+#define AXP221_OUTPUT_CTRL2_DLDO4_EN (1 << 6)
+#define AXP221_OUTPUT_CTRL2_DCDC1_EN (1 << 7)
+#define AXP221_OUTPUT_CTRL3 0x13
+#define AXP221_OUTPUT_CTRL3_ALDO3_EN (1 << 7)
+#define AXP221_DLDO1_CTRL 0x15
+#define AXP221_DLDO2_CTRL 0x16
+#define AXP221_DLDO3_CTRL 0x17
+#define AXP221_DLDO4_CTRL 0x18
+#define AXP221_DCDC1_CTRL 0x21
+#define AXP221_DCDC2_CTRL 0x22
+#define AXP221_DCDC3_CTRL 0x23
+#define AXP221_DCDC4_CTRL 0x24
+#define AXP221_DCDC5_CTRL 0x25
+#define AXP221_ALDO1_CTRL 0x28
+#define AXP221_ALDO2_CTRL 0x28
+#define AXP221_ALDO3_CTRL 0x2a
+
+int axp221_set_dcdc1(unsigned int mvolt);
+int axp221_set_dcdc2(unsigned int mvolt);
+int axp221_set_dcdc3(unsigned int mvolt);
+int axp221_set_dcdc4(unsigned int mvolt);
+int axp221_set_dcdc5(unsigned int mvolt);
+int axp221_set_dldo1(unsigned int mvolt);
+int axp221_set_dldo2(unsigned int mvolt);
+int axp221_set_dldo3(unsigned int mvolt);
+int axp221_set_dldo4(unsigned int mvolt);
+int axp221_set_aldo1(unsigned int mvolt);
+int axp221_set_aldo2(unsigned int mvolt);
+int axp221_set_aldo3(unsigned int mvolt);
+int axp221_init(void);
--
2.1.0
3
6
This is an early preview of some recent work to support PCI in driver model.
It was prompted by fiddling with bare x86 support and finding that PCI has
its own device model, but no actual storage as to what devices exist in
the system. It is not possible to specify configuration information for
devices other than in board code.
This patch is a collection of changes in core DM, sandbox and PCI code to
implement a PCI uclass and associated operations. Some basic tests are
provided but they are incomplete.
As is becoming common with DM conversions, the existing structure (here
struct pci_controller) becomes per-bus uclass data. This allows the concept
of a 'hose' (generally a PCI host controller and a bus) to continue to exist
in the interim, even if it should not be needed in the end. This makes it
much easier to convert over existing code.
There is one major core DM change tacked into this patch. The core DM
code is updated to move allocation of platform data into the bind()
stage instead of probe(). This is because with PCI we need to know the
bus address of a device (in PCI speak: device and function or devfn) before
we can probe it. Actually a similar problem arose with SPI and I2C and I
worked around it, but with evidence from PCI also it seems we should make
this change.
PCI buses are not scanned in the bind() method but only later when probe()
is called. This will be automatic if you access a bus, but it does mean that
if PCI is not used it will not be touched, in keeping with U-Boot's lazy-
init philosophy.
The existing 'pciauto' bus configuration code is still used, although it now
uses DM underneath. It works exclusively by reading and writing PCI config
and does not refer to DM data structures. In fact that file is not touched
in this patch which is an indication that a good level of compatibility is
achieved between DM and legacy PCI.
In order to support testing of PCI I/O and memory space, support has been
added to sandbox to allow mapping of these. This allows commands like 'md'
and 'iod' to display data from mapped PCI devices. Similarly, it is possible
to make changes to this space. This support relies on the existing
map_sysmem() and unmap_sysmem() calls which are now fairly widespread in
U-Boot.
Apart from the driver model tests (run with ./test/dm/test-dm.sh) you can
try out these commands which use the new 'swap_case' test device:
../u-boot -d b/sandbox/u-boot.dtb
....
=> iow.b 20000000 2
=> iod.b 20000000
0000: 02
=> mw.l 10000000 64436241
=> md.l 10000000 1
10000000: 44634261 aBcD
=>
This shows an I/O access to 20000000, setting the value 2 which means to
swap the case. Then 'AbCd' is written to the memory space at 10000000 and
'aBcD' is read back.
The 'pci' command works to some extent.
Most existing PCI functions still work, but route through driver model.
The file drivers/pci/pci.c is replaced when driver model is enabled so not
everything is present. Also multiple bus support is untested and probably
broken. A new pci_common.c file holds functions common to driver model and
the old system, and pci_compat.c contains functions I would like to
eventually deprecate.
This series is not tested on any real hardware at this stage. Once the bare
x86 support is merged I will tidy this patch up and move it over, fix up
Kconfig, etc.
This patch is available at u-boot-dm.git branch pci-working.
Signed-off-by: Simon Glass <sjg(a)chromium.org>
---
arch/sandbox/Kconfig | 6 +
arch/sandbox/cpu/cpu.c | 37 ++-
arch/sandbox/dts/sandbox.dts | 26 ++-
arch/sandbox/include/asm/io.h | 16 +-
arch/sandbox/include/asm/processor.h | 12 +
arch/sandbox/include/asm/test.h | 7 +-
arch/sandbox/include/asm/u-boot-sandbox.h | 7 +
arch/sandbox/lib/Makefile | 2 +-
arch/sandbox/lib/pci_io.c | 137 +++++++++++
common/board_r.c | 2 +
common/cmd_mem.c | 7 +-
common/cmd_pci.c | 14 +-
configs/sandbox_defconfig | 4 +
doc/driver-model/pci-info.txt | 52 +++++
drivers/core/device.c | 92 ++++++--
drivers/core/root.c | 3 +
drivers/misc/Makefile | 1 +
drivers/misc/swap_case.c | 284 +++++++++++++++++++++++
drivers/pci/Kconfig | 22 ++
drivers/pci/Makefile | 10 +-
drivers/pci/pci-emul-uclass.c | 66 ++++++
drivers/pci/pci-uclass.c | 374 ++++++++++++++++++++++++++++++
drivers/pci/pci.c | 72 +-----
drivers/pci/pci_common.c | 72 ++++++
drivers/pci/pci_compat.c | 67 ++++++
drivers/pci/pci_sandbox.c | 171 ++++++++++++++
include/configs/sandbox.h | 5 +-
include/dm/device.h | 32 +++
include/dm/uclass-id.h | 3 +
include/dm/uclass.h | 4 +
include/fdtdec.h | 11 +
include/pci.h | 156 ++++++++++++-
lib/fdtdec.c | 2 +-
test/dm/Makefile | 1 +
test/dm/test-fdt.c | 4 +-
test/dm/test.dts | 17 ++
36 files changed, 1687 insertions(+), 111 deletions(-)
create mode 100644 arch/sandbox/include/asm/processor.h
create mode 100644 arch/sandbox/lib/pci_io.c
create mode 100644 doc/driver-model/pci-info.txt
create mode 100644 drivers/misc/swap_case.c
create mode 100644 drivers/pci/pci-emul-uclass.c
create mode 100644 drivers/pci/pci-uclass.c
create mode 100644 drivers/pci/pci_common.c
create mode 100644 drivers/pci/pci_compat.c
create mode 100644 drivers/pci/pci_sandbox.c
diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig
index 3057325..8d1ec1d 100644
--- a/arch/sandbox/Kconfig
+++ b/arch/sandbox/Kconfig
@@ -10,4 +10,10 @@ config SYS_BOARD
config SYS_CONFIG_NAME
default "sandbox"
+config PCI
+ bool "PCI support"
+ help
+ Enable support for PCI (Peripheral Interconnect Bus), a type of bus
+ used on some devices to allow the CPU to communicate with
+
endmenu
diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c
index 1aa397c..1e67a31 100644
--- a/arch/sandbox/cpu/cpu.c
+++ b/arch/sandbox/cpu/cpu.c
@@ -2,7 +2,7 @@
* Copyright (c) 2011 The Chromium OS Authors.
* SPDX-License-Identifier: GPL-2.0+
*/
-
+#define DEBUG
#include <common.h>
#include <dm/root.h>
#include <os.h>
@@ -10,6 +10,13 @@
DECLARE_GLOBAL_DATA_PTR;
+/* Enable access to PCI memory with map_sysmem() */
+static bool enable_pci_map;
+
+/* Last device that was mapped into memory, and length of mapping */
+static struct udevice *map_dev;
+unsigned long map_len;
+
void reset_cpu(ulong ignored)
{
if (state_uninit())
@@ -59,9 +66,37 @@ int cleanup_before_linux(void)
void *map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
{
+#ifdef CONFIG_PCI
+ unsigned long plen = len;
+ void *ptr;
+
+ map_dev = NULL;
+ if (enable_pci_map && !pci_map_physmem(paddr, &len, &map_dev, &ptr)) {
+ if (plen != len) {
+ printf("%s: Warning: partial map at %x, wanted %lx, got %lx\n",
+ __func__, paddr, len, plen);
+ }
+ map_len = len;
+ return ptr;
+ }
+#endif
+
return (void *)(gd->arch.ram_buf + paddr);
}
+void unmap_physmem(const void *vaddr, unsigned long flags)
+{
+ if (map_dev) {
+ pci_unmap_physmem(vaddr, map_len, map_dev);
+ map_dev = NULL;
+ }
+}
+
+void sandbox_set_enable_pci_map(int enable)
+{
+ enable_pci_map = enable;
+}
+
phys_addr_t map_to_sysmem(const void *ptr)
{
return (u8 *)ptr - gd->arch.ram_buf;
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts
index 7614715..c8df40b 100644
--- a/arch/sandbox/dts/sandbox.dts
+++ b/arch/sandbox/dts/sandbox.dts
@@ -1,8 +1,14 @@
/dts-v1/;
+#define MBUS_ID(target, attributes) (((target) << 24) | ((attributes) << 16))
+
/ {
#address-cells = <1>;
- #size-cells = <0>;
+ #size-cells = <1>;
+
+ aliases {
+ pci0 = &pci;
+ };
chosen {
stdout-path = "/serial";
@@ -137,7 +143,7 @@
spi@0 {
#address-cells = <1>;
#size-cells = <0>;
- reg = <0>;
+ reg = <0 0>;
compatible = "sandbox,spi";
cs-gpios = <0>, <&gpio_a 0>;
flash@0 {
@@ -157,4 +163,20 @@
};
};
+ pci: pci-controller {
+ compatible = "sandbox,pci";
+ device_type = "pci";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges = <0x02000000 0 0x10000000 0x10000000 0 0x2000
+ 0x01000000 0 0x20000000 0x20000000 0 0x2000>;
+ pci@1f,0 {
+ compatible = "pci-generic";
+ reg = <0xf800 0 0 0 0>;
+ emul@1f,0 {
+ compatible = "sandbox,swap-case";
+ };
+ };
+ };
+
};
diff --git a/arch/sandbox/include/asm/io.h b/arch/sandbox/include/asm/io.h
index 895fcb8..5b87fde 100644
--- a/arch/sandbox/include/asm/io.h
+++ b/arch/sandbox/include/asm/io.h
@@ -22,10 +22,7 @@ void *map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags);
/*
* Take down a mapping set up by map_physmem().
*/
-static inline void unmap_physmem(void *vaddr, unsigned long flags)
-{
-
-}
+void unmap_physmem(const void *vaddr, unsigned long flags);
/* For sandbox, we want addresses to point into our RAM buffer */
static inline void *map_sysmem(phys_addr_t paddr, unsigned long len)
@@ -33,8 +30,10 @@ static inline void *map_sysmem(phys_addr_t paddr, unsigned long len)
return map_physmem(paddr, len, MAP_WRBACK);
}
+/* Remove a previous mapping */
static inline void unmap_sysmem(const void *vaddr)
{
+ unmap_physmem(vaddr, MAP_WRBACK);
}
/* Map from a pointer to our RAM buffer */
@@ -48,6 +47,15 @@ phys_addr_t map_to_sysmem(const void *ptr);
#define writew(v, addr)
#define writel(v, addr)
+/* I/O access functions */
+int inl(unsigned int addr);
+int inw(unsigned int addr);
+int inb(unsigned int addr);
+
+void outl(unsigned int value, unsigned int addr);
+void outw(unsigned int value, unsigned int addr);
+void outb(unsigned int value, unsigned int addr);
+
#include <iotrace.h>
#endif
diff --git a/arch/sandbox/include/asm/processor.h b/arch/sandbox/include/asm/processor.h
new file mode 100644
index 0000000..3c1794e
--- /dev/null
+++ b/arch/sandbox/include/asm/processor.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _ASM_PROCESSOR_H
+#define _ASM_PROCESSOR_H
+
+/* This file is required for PCI */
+
+#endif
diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h
index d7f7bb5..fa61b5e 100644
--- a/arch/sandbox/include/asm/test.h
+++ b/arch/sandbox/include/asm/test.h
@@ -10,6 +10,11 @@
#define __ASM_TEST_H
/* The sandbox driver always permits an I2C device with this address */
-#define SANDBOX_I2C_TEST_ADDR 0x59
+#define SANDBOX_I2C_TEST_ADDR 0x59
+
+#define SANDBOX_PCI_VENDOR_ID 0x1234
+#define SANDBOX_PCI_DEVICE_ID 0x5678
+#define SANDBOX_PCI_CLASS_CODE PCI_CLASS_CODE_COMM
+#define SANDBOX_PCI_CLASS_SUB_CODE PCI_CLASS_SUB_CODE_COMM_SERIAL
#endif
diff --git a/arch/sandbox/include/asm/u-boot-sandbox.h b/arch/sandbox/include/asm/u-boot-sandbox.h
index d2f1b65..1a29cf1 100644
--- a/arch/sandbox/include/asm/u-boot-sandbox.h
+++ b/arch/sandbox/include/asm/u-boot-sandbox.h
@@ -28,4 +28,11 @@ int cleanup_before_linux(void);
/* drivers/video/sandbox_sdl.c */
int sandbox_lcd_sdl_early_init(void);
+int pci_map_physmem(phys_addr_t paddr, unsigned long *lenp,
+ struct udevice **devp, void **ptrp);
+int pci_unmap_physmem(const void *addr, unsigned long len,
+ struct udevice *dev);
+
+void sandbox_set_enable_pci_map(int enable);
+
#endif /* _U_BOOT_SANDBOX_H_ */
diff --git a/arch/sandbox/lib/Makefile b/arch/sandbox/lib/Makefile
index 4c1a38d..dedc752 100644
--- a/arch/sandbox/lib/Makefile
+++ b/arch/sandbox/lib/Makefile
@@ -7,5 +7,5 @@
# SPDX-License-Identifier: GPL-2.0+
#
-
obj-y += interrupts.o
+obj-y += pci_io.o
diff --git a/arch/sandbox/lib/pci_io.c b/arch/sandbox/lib/pci_io.c
new file mode 100644
index 0000000..601d969
--- /dev/null
+++ b/arch/sandbox/lib/pci_io.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2012 The Chromium OS Authors.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*
+ * IO space access commands.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <asm/io.h>
+
+int pci_map_physmem(phys_addr_t paddr, unsigned long *lenp,
+ struct udevice **devp, void **ptrp)
+{
+ struct udevice *dev;
+ int ret;
+
+ *ptrp = 0;
+ for (uclass_first_device(UCLASS_PCI_EMUL, &dev);
+ dev;
+ uclass_next_device(&dev)) {
+ struct dm_pci_emul_ops *ops = pci_get_emul_ops(dev);
+
+ if (!ops || !ops->map_physmem)
+ continue;
+ ret = (ops->map_physmem)(dev, paddr, lenp, ptrp);
+ if (ret)
+ continue;
+ *devp = dev;
+ return 0;
+ }
+
+ debug("%s: failed: addr=%x\n", __func__, paddr);
+ return -ENOSYS;
+}
+
+int pci_unmap_physmem(const void *vaddr, unsigned long len,
+ struct udevice *dev)
+{
+ struct dm_pci_emul_ops *ops = pci_get_emul_ops(dev);
+
+ if (!ops || !ops->unmap_physmem)
+ return -ENOSYS;
+ return (ops->unmap_physmem)(vaddr, len, dev);
+}
+
+static int pci_io_read(unsigned int addr, ulong *valuep, pci_size_t size)
+{
+ struct udevice *dev;
+ int ret;
+
+ *valuep = pci_get_ff(size);
+ for (uclass_first_device(UCLASS_PCI_EMUL, &dev);
+ dev;
+ uclass_next_device(&dev)) {
+ struct dm_pci_emul_ops *ops = pci_get_emul_ops(dev);
+
+ if (ops && ops->read_io) {
+ ret = (ops->read_io)(dev, addr, valuep, size);
+ if (!ret)
+ return 0;
+ }
+ }
+
+ debug("%s: failed: addr=%x\n", __func__, addr);
+ return -ENOSYS;
+}
+
+static int pci_io_write(unsigned int addr, ulong value, pci_size_t size)
+{
+ struct udevice *dev;
+ int ret;
+
+ for (uclass_first_device(UCLASS_PCI_EMUL, &dev);
+ dev;
+ uclass_next_device(&dev)) {
+ struct dm_pci_emul_ops *ops = pci_get_emul_ops(dev);
+
+ if (ops && ops->write_io) {
+ ret = (ops->write_io)(dev, addr, value, size);
+ if (!ret)
+ return 0;
+ }
+ }
+
+ debug("%s: failed: addr=%x, value=%lx\n", __func__, addr, value);
+ return -ENOSYS;
+}
+
+int inl(unsigned int addr)
+{
+ unsigned long value;
+ int ret;
+
+ ret = pci_io_read(addr, &value, PCI_SIZE_32);
+
+ return ret ? 0 : value;
+}
+
+int inw(unsigned int addr)
+{
+ unsigned long value;
+ int ret;
+
+ ret = pci_io_read(addr, &value, PCI_SIZE_16);
+
+ return ret ? 0 : value;
+}
+
+int inb(unsigned int addr)
+{
+ unsigned long value;
+ int ret;
+
+ ret = pci_io_read(addr, &value, PCI_SIZE_8);
+
+ return ret ? 0 : value;
+}
+
+void outl(unsigned int value, unsigned int addr)
+{
+ pci_io_write(addr, value, PCI_SIZE_32);
+}
+
+void outw(unsigned int value, unsigned int addr)
+{
+ pci_io_write(addr, value, PCI_SIZE_16);
+}
+
+void outb(unsigned int value, unsigned int addr)
+{
+ pci_io_write(addr, value, PCI_SIZE_8);
+}
diff --git a/common/board_r.c b/common/board_r.c
index 8625a90..1448f42 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -223,7 +223,9 @@ static int initr_unlock_ram_in_cache(void)
#ifdef CONFIG_PCI
static int initr_pci(void)
{
+#ifndef CONFIG_DM_PCI
pci_init();
+#endif
return 0;
}
diff --git a/common/cmd_mem.c b/common/cmd_mem.c
index bcb3ee3..855aa57 100644
--- a/common/cmd_mem.c
+++ b/common/cmd_mem.c
@@ -165,7 +165,7 @@ static int do_mem_mw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
#endif
ulong addr, count;
int size;
- void *buf;
+ void *buf, *start;
ulong bytes;
if ((argc < 3) || (argc > 4))
@@ -197,7 +197,8 @@ static int do_mem_mw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
}
bytes = size * count;
- buf = map_sysmem(addr, bytes);
+ start = map_sysmem(addr, bytes);
+ buf = start;
while (count-- > 0) {
if (size == 4)
*((u32 *)buf) = (u32)writeval;
@@ -211,7 +212,7 @@ static int do_mem_mw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
*((u8 *)buf) = (u8)writeval;
buf += size;
}
- unmap_sysmem(buf);
+ unmap_sysmem(start);
return 0;
}
diff --git a/common/cmd_pci.c b/common/cmd_pci.c
index a1ba42e..e847ada 100644
--- a/common/cmd_pci.c
+++ b/common/cmd_pci.c
@@ -47,6 +47,7 @@ void pciinfo(int BusNum, int ShortPCIListing)
unsigned char HeaderType;
unsigned short VendorID;
pci_dev_t dev;
+ int ret;
printf("Scanning PCI devices on bus %d\n", BusNum);
@@ -67,7 +68,10 @@ void pciinfo(int BusNum, int ShortPCIListing)
dev = PCI_BDF(BusNum, Device, Function);
- pci_read_config_word(dev, PCI_VENDOR_ID, &VendorID);
+ ret = pci_read_config_word(dev, PCI_VENDOR_ID,
+ &VendorID);
+ if (ret)
+ goto error;
if ((VendorID == 0xFFFF) || (VendorID == 0x0000))
continue;
@@ -84,8 +88,12 @@ void pciinfo(int BusNum, int ShortPCIListing)
BusNum, Device, Function);
pci_header_show(dev);
}
- }
- }
+ }
+ }
+
+ return;
+error:
+ printf("Cannot read bus configuration: %d\n", ret);
}
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 47d8400..ca47480 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -1,3 +1,7 @@
CONFIG_OF_CONTROL=y
CONFIG_OF_HOSTFILE=y
CONFIG_DEFAULT_DEVICE_TREE="sandbox"
+CONFIG_DM=y
+CONFIG_PCI=y
+CONFIG_DM_PCI=y
+CONFIG_PCI_SANDBOX=y
diff --git a/doc/driver-model/pci-info.txt b/doc/driver-model/pci-info.txt
new file mode 100644
index 0000000..ac82e7e
--- /dev/null
+++ b/doc/driver-model/pci-info.txt
@@ -0,0 +1,52 @@
+PCI with Driver Model
+=====================
+
+How busses are scanned
+----------------------
+
+Any config read will end up at pci_read_config(). This uses uclass_get_device by seq() to get the PCI bus for a particular bus number. Bus number 0 will need to be requested first, and the alias in the device tree file will point to the correct device:
+
+
+ aliases {
+ pci0 = &pci;
+ };
+
+ pci: pci-controller {
+ compatible = "sandbox,pci";
+ ...
+ };
+
+The call to uclass_get_device by seq() will caus the PCI bus to be probed. This does a scan of the bus to locate available devices. These devices are bound to their appropriate driver if availbale. If there is no driver, then they are bound to a generic PCI driver which does nothing.
+
+After probing a bus the available devices will appear in the device tree under that bus.
+
+Note that this is all done on a lazy basis, as needed, so until something is touched on PCI it will not be probed.
+
+PCI devices can appear in the device tree. If they do this servers to specify the driver to use for the device. In this case they will be bound at start-up.
+
+
+Sandbox
+-------
+
+With sandbox we need a device emulator for each device on the bus since there is no real PCI bus. This works by looking in the device tree node for a driver. For example:
+
+
+ pci@1f,0 {
+ compatible = "pci-generic";
+ reg = <0xf800 0 0 0 0>;
+ emul@1f,0 {
+ compatible = "sandbox,swap-case";
+ };
+ };
+
+This means that there is a 'sandbox,swap-case' driver at that bus position.
+Note that the first cell in the 'reg' value is the bus/device/function. See
+PCI_BDF() for the encoding.
+
+When this bus is scanned we will end up with something like this:
+
+`- * pci-controller @ 05c660c8, 0
+ `- pci@1f,0 @ 05c661c8, 63488
+ `- emul@1f,0 @ 05c662c8
+
+When accesses go to the pci@1f,0 device they are forwarded to its child, the emulator.
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 49faa29..5faf2d7 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -118,8 +118,27 @@ int device_bind(struct udevice *parent, struct driver *drv, const char *name,
#else
dev->req_seq = -1;
#endif
- if (!dev->platdata && drv->platdata_auto_alloc_size)
+ if (!dev->platdata && drv->platdata_auto_alloc_size) {
dev->flags |= DM_FLAG_ALLOC_PDATA;
+ dev->platdata = calloc(1, drv->platdata_auto_alloc_size);
+ if (!dev->platdata) {
+ ret = -ENOMEM;
+ goto fail_alloc1;
+ }
+ }
+ if (dev->parent && !dev->parent_platdata) {
+ int size = dev->parent->driver->
+ per_child_platdata_auto_alloc_size;
+
+ if (size) {
+ dev->flags |= DM_FLAG_ALLOC_PARENT_PDATA;
+ dev->parent_platdata = calloc(1, size);
+ if (!dev->parent_platdata) {
+ ret = -ENOMEM;
+ goto fail_alloc2;
+ }
+ }
+ }
/* put dev into parent's successor list */
if (parent)
@@ -127,27 +146,50 @@ int device_bind(struct udevice *parent, struct driver *drv, const char *name,
ret = uclass_bind_device(dev);
if (ret)
- goto fail_bind;
+ goto fail_uclass_bind;
/* if we fail to bind we remove device from successors and free it */
if (drv->bind) {
ret = drv->bind(dev);
- if (ret) {
- if (uclass_unbind_device(dev)) {
- dm_warn("Failed to unbind dev '%s' on error path\n",
- dev->name);
- }
+ if (ret)
goto fail_bind;
- }
}
+ if (dev->parent && dev->parent->driver->child_post_bind) {
+ ret = dev->parent->driver->child_post_bind(dev);
+ if (ret)
+ goto fail_child_post_bind;
+ }
+
if (parent)
dm_dbg("Bound device %s to %s\n", dev->name, parent->name);
*devp = dev;
return 0;
+fail_child_post_bind:
+ if (drv->unbind && drv->unbind(dev)) {
+ dm_warn("unbind() method failed on dev '%s' on error path\n",
+ dev->name);
+ }
+
fail_bind:
+ if (uclass_unbind_device(dev)) {
+ dm_warn("Failed to unbind dev '%s' on error path\n",
+ dev->name);
+ }
+
+fail_uclass_bind:
list_del(&dev->sibling_node);
+ if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) {
+ free(dev->parent_platdata);
+ dev->parent_platdata = NULL;
+ }
+fail_alloc2:
+ if (dev->flags & DM_FLAG_ALLOC_PDATA) {
+ free(dev->platdata);
+ dev->platdata = NULL;
+ }
+fail_alloc1:
free(dev);
return ret;
}
@@ -191,6 +233,14 @@ int device_unbind(struct udevice *dev)
if (ret)
return ret;
+ if (dev->flags & DM_FLAG_ALLOC_PDATA) {
+ free(dev->platdata);
+ dev->platdata = NULL;
+ }
+ if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) {
+ free(dev->parent_platdata);
+ dev->parent_platdata = NULL;
+ }
ret = uclass_unbind_device(dev);
if (ret)
return ret;
@@ -214,10 +264,6 @@ static void device_free(struct udevice *dev)
free(dev->priv);
dev->priv = NULL;
}
- if (dev->flags & DM_FLAG_ALLOC_PDATA) {
- free(dev->platdata);
- dev->platdata = NULL;
- }
size = dev->uclass->uc_drv->per_device_auto_alloc_size;
if (size) {
free(dev->uclass_priv);
@@ -257,13 +303,6 @@ int device_probe_child(struct udevice *dev, void *parent_priv)
}
}
/* Allocate private data if requested */
- if (dev->flags & DM_FLAG_ALLOC_PDATA) {
- dev->platdata = calloc(1, drv->platdata_auto_alloc_size);
- if (!dev->platdata) {
- ret = -ENOMEM;
- goto fail;
- }
- }
size = dev->uclass->uc_drv->per_device_auto_alloc_size;
if (size) {
dev->uclass_priv = calloc(1, size);
@@ -409,6 +448,16 @@ void *dev_get_platdata(struct udevice *dev)
return dev->platdata;
}
+void *dev_get_parent_platdata(struct udevice *dev)
+{
+ if (!dev) {
+ dm_warn("%s: null device", __func__);
+ return NULL;
+ }
+
+ return dev->parent_platdata;
+}
+
void *dev_get_priv(struct udevice *dev)
{
if (!dev) {
@@ -548,3 +597,8 @@ int device_find_next_child(struct udevice **devp)
return 0;
}
+
+enum uclass_id device_get_uclass_id(struct udevice *dev)
+{
+ return dev->uclass->uc_drv->id;
+}
diff --git a/drivers/core/root.c b/drivers/core/root.c
index a328a48..8dc615a 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -49,6 +49,9 @@ int dm_init(void)
ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST);
if (ret)
return ret;
+#ifdef CONFIG_OF_CONTROL
+ DM_ROOT_NON_CONST->of_offset = 0;
+#endif
ret = device_probe(DM_ROOT_NON_CONST);
if (ret)
return ret;
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 2f2e48f..01ecf30 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -21,5 +21,6 @@ obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o
obj-$(CONFIG_NS87308) += ns87308.o
obj-$(CONFIG_PDSP188x) += pdsp188x.o
obj-$(CONFIG_STATUS_LED) += status_led.o
+obj-$(CONFIG_SANDBOX) += swap_case.o
obj-$(CONFIG_TWL4030_LED) += twl4030_led.o
obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
diff --git a/drivers/misc/swap_case.c b/drivers/misc/swap_case.c
new file mode 100644
index 0000000..50f3b1d
--- /dev/null
+++ b/drivers/misc/swap_case.c
@@ -0,0 +1,284 @@
+/*
+ * PCI emulation device which swaps the case of text
+ *
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <pci.h>
+#include <asm/test.h>
+#include <linux/ctype.h>
+
+/**
+ * struct swap_case_platdata - platform data for this device
+ *
+ * @command: Current PCI command value
+ * @bar: Current base address values
+ */
+struct swap_case_platdata {
+ u16 command;
+ u32 bar[2];
+};
+
+#define offset_to_barnum(offset) \
+ (((offset) - PCI_BASE_ADDRESS_0) / sizeof(u32))
+
+enum {
+ MEM_TEXT_SIZE = 0x100,
+};
+
+enum swap_case_op {
+ OP_TO_LOWER,
+ OP_TO_UPPER,
+ OP_SWAP,
+};
+
+static struct pci_bar {
+ int type;
+ u32 size;
+} barinfo[] = {
+ { PCI_BASE_ADDRESS_SPACE_IO, 1 },
+ { PCI_BASE_ADDRESS_MEM_TYPE_32, MEM_TEXT_SIZE },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+};
+
+struct swap_case_priv {
+ enum swap_case_op op;
+ char mem_text[MEM_TEXT_SIZE];
+};
+
+static int sandbox_swap_case_get_devfn(struct udevice *dev)
+{
+ struct pci_child_platdata *plat = dev_get_parent_platdata(dev);
+
+ return plat->devfn;
+}
+
+static int sandbox_swap_case_read_config(struct udevice *emul, uint offset,
+ ulong *valuep, enum pci_size_t size)
+{
+ struct swap_case_platdata *plat = dev_get_platdata(emul);
+
+ switch (offset) {
+ case PCI_COMMAND:
+ *valuep = plat->command;
+ break;
+ case PCI_HEADER_TYPE:
+ *valuep = 0;
+ break;
+ case PCI_VENDOR_ID:
+ *valuep = SANDBOX_PCI_VENDOR_ID;
+ break;
+ case PCI_DEVICE_ID:
+ *valuep = SANDBOX_PCI_DEVICE_ID;
+ break;
+ case PCI_CLASS_DEVICE:
+ if (size == PCI_SIZE_8) {
+ *valuep = SANDBOX_PCI_CLASS_SUB_CODE;
+ } else {
+ *valuep = (SANDBOX_PCI_CLASS_CODE << 8) |
+ SANDBOX_PCI_CLASS_SUB_CODE;
+ }
+ break;
+ case PCI_CLASS_CODE:
+ *valuep = SANDBOX_PCI_CLASS_CODE;
+ break;
+ case PCI_BASE_ADDRESS_0:
+ case PCI_BASE_ADDRESS_1:
+ case PCI_BASE_ADDRESS_2:
+ case PCI_BASE_ADDRESS_3:
+ case PCI_BASE_ADDRESS_4:
+ case PCI_BASE_ADDRESS_5: {
+ int barnum;
+ u32 *bar, result;
+
+ barnum = offset_to_barnum(offset);
+ bar = &plat->bar[barnum];
+
+ result = *bar;
+ if (*bar == 0xffffffff) {
+ if (barinfo[barnum].type) {
+ result = (~(barinfo[barnum].size - 1) &
+ PCI_BASE_ADDRESS_IO_MASK) |
+ PCI_BASE_ADDRESS_SPACE_IO;
+ } else {
+ result = (~(barinfo[barnum].size - 1) &
+ PCI_BASE_ADDRESS_MEM_MASK) |
+ PCI_BASE_ADDRESS_MEM_TYPE_32;
+ }
+ }
+ debug("r bar %d=%x\n", barnum, result);
+ *valuep = result;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int sandbox_swap_case_write_config(struct udevice *emul, uint offset,
+ ulong value, enum pci_size_t size)
+{
+ struct swap_case_platdata *plat = dev_get_platdata(emul);
+
+ switch (offset) {
+ case PCI_COMMAND:
+ plat->command = value;
+ break;
+ case PCI_BASE_ADDRESS_0:
+ case PCI_BASE_ADDRESS_1: {
+ int barnum;
+ u32 *bar;
+
+ barnum = offset_to_barnum(offset);
+ bar = &plat->bar[barnum];
+
+ debug("w bar %d=%lx\n", barnum, value);
+ *bar = value;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int sandbox_swap_case_find_bar(struct udevice *emul, unsigned int addr,
+ int *barnump, unsigned int *offsetp)
+{
+ struct swap_case_platdata *plat = dev_get_platdata(emul);
+ int barnum;
+
+ for (barnum = 0; barnum < ARRAY_SIZE(barinfo); barnum++) {
+ unsigned int size = barinfo[barnum].size;
+
+ if (addr >= plat->bar[barnum] &&
+ addr < plat->bar[barnum] + size) {
+ *barnump = barnum;
+ *offsetp = addr - plat->bar[barnum];
+ return 0;
+ }
+ }
+ *barnump = -1;
+
+ return -ENOENT;
+}
+
+static void sandbox_swap_case_do_op(enum swap_case_op op, char *str, int len)
+{
+ for (; len > 0; len--, str++) {
+ switch (op) {
+ case OP_TO_UPPER:
+ *str = toupper(*str);
+ break;
+ case OP_TO_LOWER:
+ *str = tolower(*str);
+ break;
+ case OP_SWAP:
+ if (isupper(*str))
+ *str = tolower(*str);
+ else
+ *str = toupper(*str);
+ break;
+ }
+ }
+}
+
+int sandbox_swap_case_read_io(struct udevice *dev, unsigned int addr,
+ ulong *valuep, enum pci_size_t size)
+{
+ struct swap_case_priv *priv = dev_get_priv(dev);
+ unsigned int offset;
+ int barnum;
+ int ret;
+
+ ret = sandbox_swap_case_find_bar(dev, addr, &barnum, &offset);
+ if (ret)
+ return ret;
+
+ if (barnum == 0 && offset == 0)
+ *valuep = (*valuep & ~0xff) | priv->op;
+
+ return 0;
+}
+
+int sandbox_swap_case_write_io(struct udevice *dev, unsigned int addr,
+ ulong value, enum pci_size_t size)
+{
+ struct swap_case_priv *priv = dev_get_priv(dev);
+ unsigned int offset;
+ int barnum;
+ int ret;
+
+ ret = sandbox_swap_case_find_bar(dev, addr, &barnum, &offset);
+ if (ret)
+ return ret;
+ if (barnum == 0 && offset == 0)
+ priv->op = value;
+
+ return 0;
+}
+
+static int sandbox_swap_case_map_physmem(struct udevice *dev,
+ phys_addr_t addr, unsigned long *lenp, void **ptrp)
+{
+ struct swap_case_priv *priv = dev_get_priv(dev);
+ unsigned int offset, avail;
+ int barnum;
+ int ret;
+
+ ret = sandbox_swap_case_find_bar(dev, addr, &barnum, &offset);
+ if (ret)
+ return ret;
+ if (barnum == 1) {
+ *ptrp = priv->mem_text + offset;
+ avail = barinfo[1].size - offset;
+ if (avail > barinfo[1].size)
+ *lenp = 0;
+ else
+ *lenp = min(*lenp, avail);
+
+ return 0;
+ }
+
+ return -ENOENT;
+}
+
+static int sandbox_swap_case_unmap_physmem(const void *vaddr,
+ unsigned long len, struct udevice *dev)
+{
+ struct swap_case_priv *priv = dev_get_priv(dev);
+
+ sandbox_swap_case_do_op(priv->op, (void *)vaddr, len);
+
+ return 0;
+}
+
+struct dm_pci_emul_ops sandbox_swap_case_emul_ops = {
+ .get_devfn = sandbox_swap_case_get_devfn,
+ .read_config = sandbox_swap_case_read_config,
+ .write_config = sandbox_swap_case_write_config,
+ .read_io = sandbox_swap_case_read_io,
+ .write_io = sandbox_swap_case_write_io,
+ .map_physmem = sandbox_swap_case_map_physmem,
+ .unmap_physmem = sandbox_swap_case_unmap_physmem,
+};
+
+static const struct udevice_id sandbox_swap_case_ids[] = {
+ { .compatible = "sandbox,swap-case" },
+ { }
+};
+
+U_BOOT_DRIVER(sandbox_swap_case_emul) = {
+ .name = "sandbox_swap_case_emul",
+ .id = UCLASS_PCI_EMUL,
+ .of_match = sandbox_swap_case_ids,
+ .ops = &sandbox_swap_case_emul_ops,
+ .priv_auto_alloc_size = sizeof(struct swap_case_priv),
+ .platdata_auto_alloc_size = sizeof(struct swap_case_platdata),
+};
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index e69de29..167d405 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -0,0 +1,22 @@
+menu "PCI"
+
+config DM_PCI
+ bool "Enable driver mode for PCI"
+ depends on DM
+ help
+ Use driver model for PCI. Driver model is the new method for
+ orgnising devices in U-Boot. For PCI, driver model keeps track of
+ available PCI devices, allows scanning of PCI buses and provides
+ device configuration support.
+
+config PCI_SANDBOX
+ bool "Sandbox PCI support"
+ depends on SANDBOX && DM_PCI
+ help
+ Support PCI on sandbox, as an emulated bus. This permits testing of
+ PCI feature such as bus scanning, device configuration and device
+ access. The available (emulated) devices are defined statically in
+ the device tree but the normal PCI scan technique is used to find
+ then.
+
+endmenu
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 55d6a9b..11bae12 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -5,13 +5,21 @@
# SPDX-License-Identifier: GPL-2.0+
#
+ifneq ($(CONFIG_DM_PCI),)
+obj-$(CONFIG_PCI) += pci-uclass.o pci_compat.o
+obj-$(CONFIG_SANDBOX) += pci-emul-uclass.o
+else
+obj-$(CONFIG_PCI) += pci.o pci_rom.o
+endif
+obj-$(CONFIG_PCI) += pci_common.o pci_auto.o
+
obj-$(CONFIG_FSL_PCI_INIT) += fsl_pci_init.o
-obj-$(CONFIG_PCI) += pci.o pci_auto.o pci_rom.o
obj-$(CONFIG_PCI_INDIRECT_BRIDGE) += pci_indirect.o
obj-$(CONFIG_PCI_GT64120) += pci_gt64120.o
obj-$(CONFIG_PCI_MSC01) += pci_msc01.o
obj-$(CONFIG_PCIE_IMX) += pcie_imx.o
obj-$(CONFIG_FTPCI100) += pci_ftpci100.o
+obj-$(CONFIG_PCI_SANDBOX) += pci_sandbox.o
obj-$(CONFIG_SH4_PCI) += pci_sh4.o
obj-$(CONFIG_SH7751_PCI) +=pci_sh7751.o
obj-$(CONFIG_SH7780_PCI) +=pci_sh7780.o
diff --git a/drivers/pci/pci-emul-uclass.c b/drivers/pci/pci-emul-uclass.c
new file mode 100644
index 0000000..2baeab6
--- /dev/null
+++ b/drivers/pci/pci-emul-uclass.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <libfdt.h>
+#include <pci.h>
+#include <dm/lists.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct sandbox_pci_priv {
+ int dev_count;
+};
+
+int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn,
+ struct udevice **emulp)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = pci_bus_find_devfn(bus, find_devfn, &dev);
+ if (ret) {
+ debug("%s: Could not find emulator for dev %x\n", __func__,
+ find_devfn);
+ return ret;
+ }
+
+ ret = device_find_first_child(dev, emulp);
+ if (ret)
+ return ret;
+
+ return *emulp ? 0 : -ENODEV;
+}
+
+static int sandbox_pci_emul_post_probe(struct udevice *dev)
+{
+ struct sandbox_pci_priv *priv = dev->uclass->priv;
+
+ priv->dev_count++;
+ sandbox_set_enable_pci_map(true);
+
+ return 0;
+}
+
+static int sandbox_pci_emul_pre_remove(struct udevice *dev)
+{
+ struct sandbox_pci_priv *priv = dev->uclass->priv;
+
+ priv->dev_count--;
+ sandbox_set_enable_pci_map(priv->dev_count > 0);
+
+ return 0;
+}
+
+UCLASS_DRIVER(pci_emul) = {
+ .id = UCLASS_PCI_EMUL,
+ .name = "pci_emul",
+ .post_probe = sandbox_pci_emul_post_probe,
+ .pre_remove = sandbox_pci_emul_pre_remove,
+ .priv_auto_alloc_size = sizeof(struct sandbox_pci_priv),
+};
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
new file mode 100644
index 0000000..a5bd8df
--- /dev/null
+++ b/drivers/pci/pci-uclass.c
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <pci.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int pci_get_ff(enum pci_size_t size)
+{
+ switch (size) {
+ case PCI_SIZE_8:
+ return 0xff;
+ case PCI_SIZE_16:
+ return 0xffff;
+ default:
+ return 0xffffffff;
+ }
+}
+
+int pci_bus_find_devfn(struct udevice *bus, pci_dev_t find_devfn,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+
+ for (device_find_first_child(bus, &dev);
+ dev;
+ device_find_next_child(&dev)) {
+ struct pci_child_platdata *pplat;
+
+ pplat = dev_get_parent_platdata(dev);
+ if (pplat && pplat->devfn == find_devfn) {
+ *devp = dev;
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
+int pci_bus_find_bdf(pci_dev_t bdf, struct udevice **devp)
+{
+ struct udevice *bus;
+ int ret;
+
+ ret = uclass_get_device_by_seq(UCLASS_PCI, PCI_BUS(bdf), &bus);
+ if (ret)
+ return ret;
+ return pci_bus_find_devfn(bus, PCI_MASK_BUS(bdf), devp);
+}
+
+static int pci_device_matches_ids(struct udevice *dev,
+ struct pci_device_id *ids)
+{
+ struct pci_child_platdata *pplat;
+ int i;
+
+ pplat = dev_get_parent_platdata(dev);
+ if (!pplat)
+ return -EINVAL;
+ for (i = 0; ids[i].vendor != 0; i++) {
+ if (pplat->vendor == ids[i].vendor &&
+ pplat->device == ids[i].device)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+int pci_bus_find_devices(struct udevice *bus, struct pci_device_id *ids,
+ int *indexp, struct udevice **devp)
+{
+ struct udevice *dev;
+
+ /* Scan all devices on this bus */
+ for (device_find_first_child(bus, &dev);
+ dev;
+ device_find_next_child(&dev)) {
+ if (pci_device_matches_ids(dev, ids) >= 0) {
+ if ((*indexp)-- <= 0) {
+ *devp = dev;
+ return 0;
+ }
+ }
+ }
+
+ return -ENODEV;
+}
+
+int pci_find_device_id(struct pci_device_id *ids, int index,
+ struct udevice **devp)
+{
+ struct udevice *bus;
+
+ /* Scan all known buses */
+ for (uclass_first_device(UCLASS_PCI, &bus);
+ bus;
+ uclass_next_device(&bus)) {
+ if (!pci_bus_find_devices(bus, ids, &index, devp))
+ return 0;
+ }
+ *devp = NULL;
+
+ return -ENODEV;
+}
+
+int pci_bus_write_config(struct udevice *bus, pci_dev_t devfn, int offset,
+ unsigned long value, enum pci_size_t size)
+{
+ struct dm_pci_ops *ops;
+
+ ops = pci_get_ops(bus);
+ if (!ops->write_config)
+ return -ENOSYS;
+ return ops->write_config(bus, devfn, offset, value, size);
+}
+
+int pci_write_config(pci_dev_t bdf, int offset, unsigned long value,
+ enum pci_size_t size)
+{
+ struct udevice *bus;
+ int ret;
+
+ ret = uclass_get_device_by_seq(UCLASS_PCI, PCI_BUS(bdf), &bus);
+ if (ret)
+ return ret;
+
+ return pci_bus_write_config(bus, PCI_MASK_BUS(bdf), offset, value,
+ size);
+}
+
+int pci_write_config32(pci_dev_t devfn, int offset, u32 value)
+{
+ return pci_write_config(devfn, offset, value, PCI_SIZE_8);
+}
+
+int pci_write_config16(pci_dev_t devfn, int offset, u16 value)
+{
+ return pci_write_config(devfn, offset, value, PCI_SIZE_16);
+}
+
+int pci_write_config8(pci_dev_t devfn, int offset, u8 value)
+{
+ return pci_write_config(devfn, offset, value, PCI_SIZE_8);
+}
+
+int pci_bus_read_config(struct udevice *bus, pci_dev_t devfn, int offset,
+ unsigned long *valuep, enum pci_size_t size)
+{
+ struct dm_pci_ops *ops;
+
+ ops = pci_get_ops(bus);
+ if (!ops->read_config)
+ return -ENOSYS;
+ return ops->read_config(bus, devfn, offset, valuep, size);
+}
+
+int pci_read_config(pci_dev_t bdf, int offset, unsigned long *valuep,
+ enum pci_size_t size)
+{
+ struct udevice *bus;
+ int ret;
+
+ ret = uclass_get_device_by_seq(UCLASS_PCI, PCI_BUS(bdf), &bus);
+ if (ret)
+ return ret;
+
+ return pci_bus_read_config(bus, PCI_MASK_BUS(bdf), offset, valuep,
+ size);
+}
+
+int pci_read_config32(pci_dev_t bdf, int offset, u32 *valuep)
+{
+ unsigned long value;
+ int ret;
+
+ ret = pci_read_config(bdf, offset, &value, PCI_SIZE_32);
+ if (ret)
+ return ret;
+ *valuep = value;
+
+ return 0;
+}
+
+int pci_read_config16(pci_dev_t bdf, int offset, u16 *valuep)
+{
+ unsigned long value;
+ int ret;
+
+ ret = pci_read_config(bdf, offset, &value, PCI_SIZE_16);
+ if (ret)
+ return ret;
+ *valuep = value;
+
+ return 0;
+}
+
+int pci_read_config8(pci_dev_t bdf, int offset, u8 *valuep)
+{
+ unsigned long value;
+ int ret;
+
+ ret = pci_read_config(bdf, offset, &value, PCI_SIZE_8);
+ if (ret)
+ return ret;
+ *valuep = value;
+
+ return 0;
+}
+
+int pci_auto_config_devices(struct udevice *bus)
+{
+ struct pci_controller *hose = bus->uclass_priv;
+ struct pci_platdata *bus_plat;
+ unsigned int sub_bus;
+ struct udevice *dev;
+ int ret;
+
+ bus_plat = dev_get_platdata(bus);
+ sub_bus = bus_plat->busnum;
+ debug("%s: start\n", __func__);
+ pciauto_config_init(hose);
+ for (ret = device_find_first_child(bus, &dev);
+ !ret && dev;
+ ret = device_find_next_child(&dev)) {
+ struct pci_child_platdata *pplat;
+
+ pplat = dev_get_parent_platdata(dev);
+ int max_bus;
+ pci_dev_t bdf;
+
+ bdf = PCI_ADD_BUS(bus_plat->busnum, pplat->devfn);
+ debug("%s: device %s\n", __func__, dev->name);
+ max_bus = pciauto_config_device(hose, bdf);
+ sub_bus = max(sub_bus, max_bus);
+ }
+ debug("%s: done\n", __func__);
+
+ return sub_bus;
+}
+
+int pci_bind_bus_devices(struct udevice *bus)
+{
+ struct pci_platdata *bus_plat;
+ ulong vendor, device;
+ ulong header_type;
+ pci_dev_t devfn, end;
+ bool found_multi;
+ int ret;
+
+ bus_plat = dev_get_platdata(bus);
+ found_multi = false;
+ end = PCI_DEVFN(PCI_MAX_PCI_DEVICES - 1, PCI_MAX_PCI_FUNCTIONS - 1);
+ for (devfn = PCI_DEVFN(0, 0); devfn < end; devfn += PCI_DEVFN(0, 1)) {
+ struct pci_child_platdata *pplat;
+ struct udevice *dev;
+ ulong val;
+
+ if (PCI_FUNC(devfn) && !found_multi)
+ continue;
+ /* Check only the first access, we don't expect problems */
+ ret = pci_bus_read_config(bus, devfn, PCI_HEADER_TYPE,
+ &header_type, PCI_SIZE_8);
+ if (ret)
+ goto error;
+ pci_bus_read_config(bus, devfn, PCI_VENDOR_ID, &vendor,
+ PCI_SIZE_16);
+ if (vendor == 0xffff || vendor == 0x0000)
+ continue;
+
+ if (!PCI_FUNC(devfn))
+ found_multi = header_type & 0x80;
+
+ debug("%s: bus %s: found device %d, function %d\n", __func__,
+ bus->name, PCI_DEV(devfn), PCI_FUNC(devfn));
+ pci_bus_read_config(bus, devfn, PCI_DEVICE_ID, &device,
+ PCI_SIZE_16);
+
+ /* Find this device in the device tree */
+ ret = pci_bus_find_devfn(bus, devfn, &dev);
+ /*
+ if (ret == -ENODEV) {
+ u32 vendev = PCI_VENDEV(vendor, device);
+
+ ret = pci_bus_find_vendev(bus, vendev, &dev);
+ }
+*/
+ /* If nothing in the device tree, bind a generic device */
+ if (ret == -ENODEV) {
+ char name[30], *str;
+
+ sprintf(name, "pci_%x:%x.%x", bus_plat->busnum,
+ PCI_DEV(devfn), PCI_FUNC(devfn));
+ str = strdup(name);
+ if (!str)
+ return -ENOMEM;
+ ret = device_bind_driver(bus, "pci_generic_drv", str,
+ &dev);
+ }
+ if (ret)
+ return ret;
+
+ /* Update the platform data */
+ pplat = dev_get_parent_platdata(dev);
+ pplat->devfn = devfn;
+ pplat->vendor = vendor;
+ pplat->device = device;
+ pci_bus_read_config(bus, devfn, PCI_CLASS_DEVICE, &val,
+ PCI_SIZE_16);
+ pplat->class = val;
+ }
+
+ return 0;
+error:
+ printf("Cannot read bus configuration: %d\n", ret);
+
+ return ret;
+}
+
+static int pci_uclass_post_bind(struct udevice *bus)
+{
+ /*
+ * Scan the device tree for devices. This does not probe the PCI bus,
+ * as this is not permitted while binding. It just finds devices
+ * mentioned in the device tree.
+ */
+ return dm_scan_fdt_node(bus, gd->fdt_blob, bus->of_offset, false);
+}
+
+static int pci_uclass_post_probe(struct udevice *bus)
+{
+ int ret;
+
+ debug("%s: probing\n", __func__);
+ ret = pci_bind_bus_devices(bus);
+ if (ret)
+ return ret;
+
+#ifdef CONFIG_PCI_PNP
+ ret = pci_auto_config_devices(bus);
+#endif
+
+ return ret;
+}
+
+UCLASS_DRIVER(pci) = {
+ .id = UCLASS_PCI,
+ .name = "pci",
+ .post_bind = pci_uclass_post_bind,
+ .post_probe = pci_uclass_post_probe,
+ .per_device_auto_alloc_size = sizeof(struct pci_controller),
+};
+
+UCLASS_DRIVER(pci_generic) = {
+ .id = UCLASS_PCI_GENERIC,
+ .name = "pci_generic",
+};
+
+static const struct udevice_id pci_generic_ids[] = {
+ { .compatible = "pci-generic" },
+ { }
+};
+
+U_BOOT_DRIVER(pci_generic_drv) = {
+ .name = "pci_generic_drv",
+ .id = UCLASS_PCI_GENERIC,
+ .of_match = pci_generic_ids,
+};
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 332df61..9ccee7b 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -15,6 +15,7 @@
#include <common.h>
#include <command.h>
+#include <inttypes.h>
#include <asm/processor.h>
#include <asm/io.h>
#include <pci.h>
@@ -398,8 +399,8 @@ int pci_hose_config_device(struct pci_controller *hose,
unsigned char pin;
int bar, found_mem64;
- debug("PCI Config: I/O=0x%lx, Memory=0x%llx, Command=0x%lx\n", io,
- (u64)mem, command);
+ debug("PCI Config: I/O=0x%lx, Memory=0x%" PRIx64 ", Command=0x%lx\n",
+ io, (u64)mem, command);
pci_hose_write_config_dword(hose, dev, PCI_COMMAND, 0);
@@ -525,71 +526,6 @@ void pci_cfgfunc_do_nothing(struct pci_controller *hose,
*/
extern int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev);
-#if defined(CONFIG_CMD_PCI) || defined(CONFIG_PCI_SCAN_SHOW)
-const char * pci_class_str(u8 class)
-{
- switch (class) {
- case PCI_CLASS_NOT_DEFINED:
- return "Build before PCI Rev2.0";
- break;
- case PCI_BASE_CLASS_STORAGE:
- return "Mass storage controller";
- break;
- case PCI_BASE_CLASS_NETWORK:
- return "Network controller";
- break;
- case PCI_BASE_CLASS_DISPLAY:
- return "Display controller";
- break;
- case PCI_BASE_CLASS_MULTIMEDIA:
- return "Multimedia device";
- break;
- case PCI_BASE_CLASS_MEMORY:
- return "Memory controller";
- break;
- case PCI_BASE_CLASS_BRIDGE:
- return "Bridge device";
- break;
- case PCI_BASE_CLASS_COMMUNICATION:
- return "Simple comm. controller";
- break;
- case PCI_BASE_CLASS_SYSTEM:
- return "Base system peripheral";
- break;
- case PCI_BASE_CLASS_INPUT:
- return "Input device";
- break;
- case PCI_BASE_CLASS_DOCKING:
- return "Docking station";
- break;
- case PCI_BASE_CLASS_PROCESSOR:
- return "Processor";
- break;
- case PCI_BASE_CLASS_SERIAL:
- return "Serial bus controller";
- break;
- case PCI_BASE_CLASS_INTELLIGENT:
- return "Intelligent controller";
- break;
- case PCI_BASE_CLASS_SATELLITE:
- return "Satellite controller";
- break;
- case PCI_BASE_CLASS_CRYPT:
- return "Cryptographic device";
- break;
- case PCI_BASE_CLASS_SIGNAL_PROCESSING:
- return "DSP";
- break;
- case PCI_CLASS_OTHERS:
- return "Does not fit any class";
- break;
- default:
- return "???";
- break;
- };
-}
-#endif /* CONFIG_CMD_PCI || CONFIG_PCI_SCAN_SHOW */
-
__weak int pci_skip_dev(struct pci_controller *hose, pci_dev_t dev)
{
/*
@@ -733,6 +669,7 @@ int pci_hose_scan(struct pci_controller *hose)
return pci_hose_scan_bus(hose, hose->current_busno);
}
+#ifndef CONFIG_DM_PCI
void pci_init(void)
{
hose_head = NULL;
@@ -740,6 +677,7 @@ void pci_init(void)
/* now call board specific pci_init()... */
pci_init_board();
}
+#endif
/* Returns the address of the requested capability structure within the
* device's PCI configuration space or 0 in case the device does not
diff --git a/drivers/pci/pci_common.c b/drivers/pci/pci_common.c
new file mode 100644
index 0000000..4d01373
--- /dev/null
+++ b/drivers/pci/pci_common.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+
+#if defined(CONFIG_CMD_PCI) || defined(CONFIG_PCI_SCAN_SHOW)
+const char *pci_class_str(u8 class)
+{
+ switch (class) {
+ case PCI_CLASS_NOT_DEFINED:
+ return "Build before PCI Rev2.0";
+ break;
+ case PCI_BASE_CLASS_STORAGE:
+ return "Mass storage controller";
+ break;
+ case PCI_BASE_CLASS_NETWORK:
+ return "Network controller";
+ break;
+ case PCI_BASE_CLASS_DISPLAY:
+ return "Display controller";
+ break;
+ case PCI_BASE_CLASS_MULTIMEDIA:
+ return "Multimedia device";
+ break;
+ case PCI_BASE_CLASS_MEMORY:
+ return "Memory controller";
+ break;
+ case PCI_BASE_CLASS_BRIDGE:
+ return "Bridge device";
+ break;
+ case PCI_BASE_CLASS_COMMUNICATION:
+ return "Simple comm. controller";
+ break;
+ case PCI_BASE_CLASS_SYSTEM:
+ return "Base system peripheral";
+ break;
+ case PCI_BASE_CLASS_INPUT:
+ return "Input device";
+ break;
+ case PCI_BASE_CLASS_DOCKING:
+ return "Docking station";
+ break;
+ case PCI_BASE_CLASS_PROCESSOR:
+ return "Processor";
+ break;
+ case PCI_BASE_CLASS_SERIAL:
+ return "Serial bus controller";
+ break;
+ case PCI_BASE_CLASS_INTELLIGENT:
+ return "Intelligent controller";
+ break;
+ case PCI_BASE_CLASS_SATELLITE:
+ return "Satellite controller";
+ break;
+ case PCI_BASE_CLASS_CRYPT:
+ return "Cryptographic device";
+ break;
+ case PCI_BASE_CLASS_SIGNAL_PROCESSING:
+ return "DSP";
+ break;
+ case PCI_CLASS_OTHERS:
+ return "Does not fit any class";
+ break;
+ default:
+ return "???";
+ break;
+ };
+}
+#endif /* CONFIG_CMD_PCI || CONFIG_PCI_SCAN_SHOW */
diff --git a/drivers/pci/pci_compat.c b/drivers/pci/pci_compat.c
new file mode 100644
index 0000000..ed8a67d
--- /dev/null
+++ b/drivers/pci/pci_compat.c
@@ -0,0 +1,67 @@
+/*
+ * Compatibility functions for pre-driver-model code
+ *
+ * Copyright (C) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <pci.h>
+
+#define PCI_HOSE_OP(rw, name, size, type) \
+int pci_hose_##rw##_config_##name(struct pci_controller *hose, \
+ pci_dev_t dev, \
+ int offset, type value) \
+{ \
+ return pci_##rw##_config##size(dev, offset, value); \
+}
+
+PCI_HOSE_OP(read, byte, 8, u8 *)
+PCI_HOSE_OP(read, word, 16, u16 *)
+PCI_HOSE_OP(read, dword, 32, u32 *)
+PCI_HOSE_OP(write, byte, 8, u8)
+PCI_HOSE_OP(write, word, 16, u16)
+PCI_HOSE_OP(write, dword, 32, u32)
+
+int pci_hose_scan_bus(struct pci_controller *hose, int busnum)
+{
+ struct pci_platdata *bus_plat;
+ struct udevice *bus;
+ int sub_bus;
+ int ret;
+
+ ret = uclass_get_device_by_seq(UCLASS_PCI, busnum, &bus);
+ if (ret)
+ return ret;
+
+ ret = pci_bind_bus_devices(bus);
+ if (ret)
+ return ret;
+ bus_plat = dev_get_platdata(bus);
+ sub_bus = bus_plat->busnum;
+
+#ifdef CONFIG_PCI_PNP
+ sub_bus = pci_auto_config_devices(bus);
+#else
+ /* TODO(sjg(a)chromium.org): Configure from device tree */
+#endif
+
+ return sub_bus;
+}
+
+pci_dev_t pci_find_devices(struct pci_device_id *ids, int index)
+{
+ struct pci_child_platdata *pplat;
+ struct pci_platdata *bus_plat;
+ struct udevice *bus, *dev;
+
+ if (pci_find_device_id(ids, index, &dev))
+ return -1;
+ bus = dev->parent;
+ bus_plat = dev_get_platdata(bus);
+ pplat = dev_get_parent_platdata(dev);
+
+ return PCI_ADD_BUS(bus_plat->busnum, pplat->devfn);
+}
diff --git a/drivers/pci/pci_sandbox.c b/drivers/pci/pci_sandbox.c
new file mode 100644
index 0000000..435f2a4
--- /dev/null
+++ b/drivers/pci/pci_sandbox.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <inttypes.h>
+#include <pci.h>
+#include <dm/root.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int sandbox_pci_write_config(struct udevice *bus, pci_dev_t devfn,
+ uint offset, ulong value,
+ enum pci_size_t size)
+{
+ struct dm_pci_emul_ops *ops;
+ struct udevice *emul;
+ int ret;
+
+ ret = sandbox_pci_get_emul(bus, devfn, &emul);
+ if (ret)
+ return ret == -ENODEV ? 0 : ret;
+ ops = pci_get_emul_ops(emul);
+ if (!ops || !ops->write_config)
+ return -ENOSYS;
+
+ return ops->write_config(emul, offset, value, size);
+}
+
+static int sandbox_pci_read_config(struct udevice *bus, pci_dev_t devfn,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
+{
+ struct dm_pci_emul_ops *ops;
+ struct udevice *emul;
+ int ret;
+
+ /* Prepare the default response */
+ *valuep = pci_get_ff(size);
+ ret = sandbox_pci_get_emul(bus, devfn, &emul);
+ if (ret)
+ return ret == -ENODEV ? 0 : ret;
+ ops = pci_get_emul_ops(emul);
+ if (!ops || !ops->read_config)
+ return -ENOSYS;
+
+ return ops->read_config(emul, offset, valuep, size);
+}
+
+static int sandbox_pci_child_pre_probe(struct udevice *dev)
+{
+ return 0;
+}
+
+static int sandbox_pci_child_post_bind(struct udevice *dev)
+{
+ struct pci_child_platdata *pplat;
+
+ /*
+ * We could read vendor, device, class if available. But we must have
+ * the device/function
+ */
+ pplat = dev_get_parent_platdata(dev);
+ if (fdtdec_pci_get_bdf(gd->fdt_blob, dev->of_offset, &pplat->devfn)) {
+ debug("Cannot decode reg property from '%s'\n", dev->name);
+ return -EINVAL;
+ }
+
+ /* Attach an emulator if we can */
+ return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
+}
+
+static int decode_regions(struct pci_controller *hose, const void *blob,
+ int parent_node, int node)
+{
+ int pci_addr_cells, addr_cells, size_cells;
+ int cells_per_record;
+ const u32 *prop;
+ int len;
+ int i;
+
+ prop = fdt_getprop(blob, node, "ranges", &len);
+ if (!prop)
+ return -EINVAL;
+ pci_addr_cells = fdt_address_cells(blob, node);
+ addr_cells = fdt_address_cells(blob, parent_node);
+ size_cells = fdt_size_cells(blob, node);
+
+ /* PCI addresses are always 3 cells */
+ len /= sizeof(u32);
+ cells_per_record = pci_addr_cells + addr_cells + size_cells;
+ hose->region_count = 0;
+ debug("%s: len=%d, cells_per_record=%d\n", __func__, len,
+ cells_per_record);
+ for (i = 0; i < MAX_PCI_REGIONS; i++, len -= cells_per_record) {
+ u64 pci_addr, addr, size;
+ int space_code;
+ int type;
+
+ if (len < cells_per_record)
+ break;
+ space_code = (fdt32_to_cpu(prop[0]) >> 24) & 3;
+ pci_addr = fdtdec_get_number(prop + 1, 2);
+ prop += pci_addr_cells;
+ addr = fdtdec_get_number(prop, addr_cells);
+ prop += addr_cells;
+ size = fdtdec_get_number(prop, size_cells);
+ prop += size_cells;
+ if (space_code & 2)
+ type = PCI_REGION_MEM;
+ else if (space_code & 1)
+ type = PCI_REGION_IO;
+ else
+ continue;
+ debug("%s: region %d, pci_addr=%" PRIx64 ", addr=%" PRIx64
+ ", size=%" PRIx64 ", type=%d\n", __func__,
+ hose->region_count, pci_addr, addr, size, type);
+ pci_set_region(hose->regions + hose->region_count++, pci_addr,
+ addr, size, type);
+ }
+
+ return 0;
+}
+
+static int sandbox_pci_probe(struct udevice *bus)
+{
+ struct pci_controller *hose;
+ int ret;
+
+ debug("%s, bus=%s, parent=%s\n", __func__, bus->name,
+ bus->parent->name);
+ hose = bus->uclass_priv;
+ ret = decode_regions(hose, gd->fdt_blob, bus->parent->of_offset,
+ bus->of_offset);
+ if (ret) {
+ debug("%s: Cannot decode regions\n", __func__);
+ return ret;
+ }
+ hose->bus = bus;
+ hose->first_busno = 0;
+ hose->last_busno = 0;
+
+ return 0;
+}
+
+static const struct dm_pci_ops sandbox_pci_ops = {
+ .read_config = sandbox_pci_read_config,
+ .write_config = sandbox_pci_write_config,
+};
+
+static const struct udevice_id sandbox_pci_ids[] = {
+ { .compatible = "sandbox,pci" },
+ { }
+};
+
+U_BOOT_DRIVER(pci_sandbox) = {
+ .name = "pci_sandbox",
+ .id = UCLASS_PCI,
+ .of_match = sandbox_pci_ids,
+ .ops = &sandbox_pci_ops,
+ .probe = sandbox_pci_probe,
+ .child_post_bind = sandbox_pci_child_post_bind,
+ .child_pre_probe = sandbox_pci_child_pre_probe,
+ .platdata_auto_alloc_size = sizeof(struct pci_platdata),
+ .per_child_platdata_auto_alloc_size =
+ sizeof(struct pci_child_platdata),
+};
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h
index ee4b244..d8e6535 100644
--- a/include/configs/sandbox.h
+++ b/include/configs/sandbox.h
@@ -23,7 +23,6 @@
#define CONFIG_BOOTSTAGE
#define CONFIG_BOOTSTAGE_REPORT
-#define CONFIG_DM
#define CONFIG_CMD_DEMO
#define CONFIG_CMD_DM
#define CONFIG_DM_DEMO
@@ -47,6 +46,10 @@
#define CONFIG_CMD_FDT
#define CONFIG_ANDROID_BOOT_IMAGE
+#define CONFIG_CMD_PCI
+#define CONFIG_PCI_PNP
+#define CONFIG_CMD_IO
+
#define CONFIG_FS_FAT
#define CONFIG_FS_EXT4
#define CONFIG_EXT4_WRITE
diff --git a/include/dm/device.h b/include/dm/device.h
index 9ce95a8..90779e6 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -26,6 +26,9 @@ struct driver_info;
/* DM should init this device prior to relocation */
#define DM_FLAG_PRE_RELOC (1 << 2)
+/* DM is responsible for allocating and freeing parent_platdata */
+#define DM_FLAG_ALLOC_PARENT_PDATA (1 << 3)
+
/**
* struct udevice - An instance of a driver
*
@@ -46,6 +49,7 @@ struct driver_info;
* @driver: The driver used by this device
* @name: Name of device, typically the FDT node name
* @platdata: Configuration data for this device
+ * @parent_platdata: The parent bus's configuration data for this device
* @of_offset: Device tree node offset for this device (- for none)
* @parent: Parent of this device, or NULL for the top level device
* @priv: Private data for this device
@@ -61,9 +65,13 @@ struct driver_info;
* when the device is probed and will be unique within the device's uclass.
*/
struct udevice {
+#ifdef CONFIG_DM_PCI
+ struct udevice *bus;
+#endif
struct driver *driver;
const char *name;
void *platdata;
+ void *parent_platdata;
int of_offset;
struct udevice *parent;
void *priv;
@@ -125,6 +133,7 @@ struct udevice_id {
* @remove: Called to remove a device, i.e. de-activate it
* @unbind: Called to unbind a device from its driver
* @ofdata_to_platdata: Called before probe to decode device tree data
+ * @child_post_bind: Called after a new child has been bound
* @child_pre_probe: Called before a child device is probed. The device has
* memory allocated but it has not yet been probed.
* @child_post_remove: Called after a child device is removed. The device
@@ -144,6 +153,9 @@ struct udevice_id {
* device_probe_child() pass it in. So far the use case for allocating it
* is SPI, but I found that unsatisfactory. Since it is here I will leave it
* until things are clearer.
+ * @per_child_platdata_auto_alloc_size: A bus likes to store information about
+ * its children. If non-zero this is the size of this data, to be allocated
+ * in the child's parent_platdata pointer.
* @ops: Driver-specific operations. This is typically a list of function
* pointers defined by the driver, to implement driver functions required by
* the uclass.
@@ -158,11 +170,13 @@ struct driver {
int (*remove)(struct udevice *dev);
int (*unbind)(struct udevice *dev);
int (*ofdata_to_platdata)(struct udevice *dev);
+ int (*child_post_bind)(struct udevice *dev);
int (*child_pre_probe)(struct udevice *dev);
int (*child_post_remove)(struct udevice *dev);
int priv_auto_alloc_size;
int platdata_auto_alloc_size;
int per_child_auto_alloc_size;
+ int per_child_platdata_auto_alloc_size;
const void *ops; /* driver-specific operations */
uint32_t flags;
};
@@ -182,6 +196,16 @@ struct driver {
void *dev_get_platdata(struct udevice *dev);
/**
+ * dev_get_parent_latdata() - Get the parent platform data for a device
+ *
+ * This checks that dev is not NULL, but no other checks for now
+ *
+ * @dev Device to check
+ * @return parent's platform data, or NULL if none
+ */
+void *dev_get_parent_platdata(struct udevice *dev);
+
+/**
* dev_get_parentdata() - Get the parent data for a device
*
* The parent data is data stored in the device but owned by the parent.
@@ -206,6 +230,14 @@ void *dev_get_parentdata(struct udevice *dev);
void *dev_get_priv(struct udevice *dev);
/**
+ * device_get_uclass_id() - return the uclass ID of a device
+ *
+ * @dev: Device to check
+ * @return uclass ID for the device
+ */
+enum uclass_id device_get_uclass_id(struct udevice *dev);
+
+/**
* device_get_child() - Get the child of a device by index
*
* Returns the numbered child, 0 being the first. This does not use
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index a8944c9..364921e 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -19,6 +19,7 @@ enum uclass_id {
UCLASS_TEST_FDT,
UCLASS_TEST_BUS,
UCLASS_SPI_EMUL, /* sandbox SPI device emulator */
+ UCLASS_PCI_EMUL, /* sandbox PCI device emulator */
UCLASS_SIMPLE_BUS,
/* U-Boot uclasses start here */
@@ -28,6 +29,8 @@ enum uclass_id {
UCLASS_SPI_GENERIC, /* Generic SPI flash target */
UCLASS_SPI_FLASH, /* SPI flash */
UCLASS_CROS_EC, /* Chrome OS EC */
+ UCLASS_PCI, /* PCI bus */
+ UCLASS_PCI_GENERIC, /* Generic PCI bus device */
UCLASS_COUNT,
UCLASS_INVALID = -1,
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index f6ec6d7..2577ae6 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -141,6 +141,8 @@ int uclass_get_device_by_of_offset(enum uclass_id id, int node,
/**
* uclass_first_device() - Get the first device in a uclass
*
+ * The device returned is probed if necessary, and ready for use
+ *
* @id: Uclass ID to look up
* @devp: Returns pointer to the first device in that uclass, or NULL if none
* @return 0 if OK (found or not found), -1 on error
@@ -150,6 +152,8 @@ int uclass_first_device(enum uclass_id id, struct udevice **devp);
/**
* uclass_next_device() - Get the next device in a uclass
*
+ * The device returned is probed if necessary, and ready for use
+ *
* @devp: On entry, pointer to device to lookup. On exit, returns pointer
* to the next device in the same uclass, or NULL if none
* @return 0 if OK (found or not found), -1 on error
diff --git a/include/fdtdec.h b/include/fdtdec.h
index ea92894..01bf82c 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -266,6 +266,17 @@ s32 fdtdec_get_int(const void *blob, int node, const char *prop_name,
s32 default_val);
/**
+ * Get a variable-sized number from a property
+ *
+ * This reads a number from one or more cells.
+ *
+ * @param ptr Pointer to property
+ * @param cells Number of cells containing the number
+ * @return the value in the cells
+ */
+u64 fdtdec_get_number(const fdt32_t *ptr, unsigned int cells);
+
+/**
* Look up a 64-bit integer property in a node and return it. The property
* must have at least 8 bytes of data (2 cells). The first two cells are
* concatenated to form a 8 bytes value, where the first cell is top half and
diff --git a/include/pci.h b/include/pci.h
index ccda2c5..4412dd3 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -460,8 +460,11 @@ typedef int pci_dev_t;
#define PCI_BUS(d) (((d) >> 16) & 0xff)
#define PCI_DEV(d) (((d) >> 11) & 0x1f)
#define PCI_FUNC(d) (((d) >> 8) & 0x7)
-#define PCI_BDF(b,d,f) ((b) << 16 | (d) << 11 | (f) << 8)
-
+#define PCI_DEVFN(d, f) ((d) << 11 | (f) << 8)
+#define PCI_MASK_BUS(bdf) ((bdf) & 0xffff)
+#define PCI_ADD_BUS(bus, devfn) (((bus) << 16) | (devfn))
+#define PCI_BDF(b, d, f) ((b) << 16 | PCI_DEVFN(d, f))
+#define PCI_VENDEV(v, d) (((v) << 16) | (d))
#define PCI_ANY_ID (~0)
struct pci_device_id {
@@ -495,6 +498,9 @@ extern void pci_cfgfunc_config_device(struct pci_controller* hose, pci_dev_t dev
* Structure of a PCI controller (host bridge)
*/
struct pci_controller {
+#ifdef CONFIG_DM_PCI
+ struct udevice *bus;
+#endif
struct pci_controller *next;
int first_busno;
@@ -511,7 +517,7 @@ struct pci_controller {
struct pci_config_table *config_table;
void (*fixup_irq)(struct pci_controller *, pci_dev_t);
-
+#ifndef CONFIG_DM_PCI
/* Low-level architecture-dependent routines */
int (*read_byte)(struct pci_controller*, pci_dev_t, int where, u8 *);
int (*read_word)(struct pci_controller*, pci_dev_t, int where, u16 *);
@@ -519,6 +525,7 @@ struct pci_controller {
int (*write_byte)(struct pci_controller*, pci_dev_t, int where, u8);
int (*write_word)(struct pci_controller*, pci_dev_t, int where, u16);
int (*write_dword)(struct pci_controller*, pci_dev_t, int where, u32);
+#endif
/* Used by auto config */
struct pci_region *pci_mem, *pci_io, *pci_prefetch;
@@ -530,6 +537,7 @@ struct pci_controller {
void *priv_data;
};
+#ifndef CONFIG_DM_PCI
static inline void pci_set_ops(struct pci_controller *hose,
int (*read_byte)(struct pci_controller*,
pci_dev_t, int where, u8 *),
@@ -550,6 +558,7 @@ static inline void pci_set_ops(struct pci_controller *hose,
hose->write_word = write_word;
hose->write_dword = write_dword;
}
+#endif
#ifdef CONFIG_PCI_INDIRECT_BRIDGE
extern void pci_setup_indirect(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data);
@@ -602,12 +611,14 @@ extern int pci_hose_write_config_word(struct pci_controller *hose,
extern int pci_hose_write_config_dword(struct pci_controller *hose,
pci_dev_t dev, int where, u32 val);
+#ifndef CONFIG_DM_PCI
extern int pci_read_config_byte(pci_dev_t dev, int where, u8 *val);
extern int pci_read_config_word(pci_dev_t dev, int where, u16 *val);
extern int pci_read_config_dword(pci_dev_t dev, int where, u32 *val);
extern int pci_write_config_byte(pci_dev_t dev, int where, u8 val);
extern int pci_write_config_word(pci_dev_t dev, int where, u16 val);
extern int pci_write_config_dword(pci_dev_t dev, int where, u32 val);
+#endif
extern int pci_hose_read_config_byte_via_dword(struct pci_controller *hose,
pci_dev_t dev, int where, u8 *val);
@@ -643,8 +654,6 @@ extern int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev);
extern pci_dev_t pci_find_device (unsigned int vendor, unsigned int device, int index);
extern pci_dev_t pci_find_devices (struct pci_device_id *ids, int index);
-extern pci_dev_t pci_find_class(int wanted_class, int wanted_sub_code,
- int wanted_prog_if, int index);
extern int pci_hose_config_device(struct pci_controller *hose,
pci_dev_t dev,
@@ -700,5 +709,142 @@ void pci_write_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum,
* */
u32 pci_read_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum);
+#ifdef CONFIG_DM_PCI
+struct pci_child_platdata {
+ int devfn; /* encoded device & function index */
+ unsigned short vendor;
+ unsigned short device;
+ unsigned int class; /* 3 bytes: (base,sub,prog-if) */
+};
+
+struct pci_platdata {
+ unsigned int busnum;
+ unsigned int devfn; /* encoded device & function index */
+};
+
+enum pci_size_t {
+ PCI_SIZE_8,
+ PCI_SIZE_16,
+ PCI_SIZE_32,
+};
+
+struct udevice;
+
+struct dm_pci_ops {
+ int (*write_config)(struct udevice *bus, pci_dev_t devfn, uint offset,
+ ulong value, enum pci_size_t size);
+ int (*read_config)(struct udevice *bus, pci_dev_t devfn, uint offset,
+ ulong *valuep, enum pci_size_t size);
+};
+
+#define pci_get_ops(dev) ((struct dm_pci_ops *)(dev)->driver->ops)
+
+int pci_bind_bus_devices(struct udevice *bus);
+
+int pci_auto_config_devices(struct udevice *bus);
+
+int pci_bus_read_config(struct udevice *bus, pci_dev_t devfn, int offset,
+ unsigned long *valuep, enum pci_size_t size);
+
+int pci_bus_write_config(struct udevice *bus, pci_dev_t devfn, int offset,
+ unsigned long value, enum pci_size_t size);
+
+int pci_write_config32(pci_dev_t pcidev, int offset, u32 value);
+
+/* Compatibility with old naming */
+static inline int pci_write_config_dword(pci_dev_t pcidev, int offset,
+ u32 value)
+{
+ return pci_write_config32(pcidev, offset, value);
+}
+
+int pci_write_config16(pci_dev_t pcidev, int offset, u16 value);
+
+/* Compatibility with old naming */
+static inline int pci_write_config_word(pci_dev_t pcidev, int offset,
+ u16 value)
+{
+ return pci_write_config16(pcidev, offset, value);
+}
+
+int pci_write_config8(pci_dev_t pcidev, int offset, u8 value);
+
+/* Compatibility with old naming */
+static inline int pci_write_config_byte(pci_dev_t pcidev, int offset,
+ u8 value)
+{
+ return pci_write_config8(pcidev, offset, value);
+}
+
+int pci_read_config32(pci_dev_t pcidev, int offset, u32 *valuep);
+
+/* Compatibility with old naming */
+static inline int pci_read_config_dword(pci_dev_t pcidev, int offset,
+ u32 *valuep)
+{
+ return pci_read_config32(pcidev, offset, valuep);
+}
+
+int pci_read_config16(pci_dev_t pcidev, int offset, u16 *valuep);
+
+/* Compatibility with old naming */
+static inline int pci_read_config_word(pci_dev_t pcidev, int offset,
+ u16 *valuep)
+{
+ return pci_read_config16(pcidev, offset, valuep);
+}
+
+int pci_read_config8(pci_dev_t pcidev, int offset, u8 *valuep);
+
+/* Compatibility with old naming */
+static inline int pci_read_config_byte(pci_dev_t pcidev, int offset,
+ u8 *valuep)
+{
+ return pci_read_config8(pcidev, offset, valuep);
+}
+
+struct dm_pci_emul_ops {
+ /**
+ * get_devfn(): Check which device and function this emulators
+ *
+ * @return the device and function this emulatoes, or -ve on error
+ */
+ int (*get_devfn)(struct udevice *dev);
+
+ int (*read_config)(struct udevice *emul, uint offset, ulong *valuep,
+ enum pci_size_t size);
+
+ int (*write_config)(struct udevice *emul, uint offset, ulong value,
+ enum pci_size_t size);
+ int (*write_io)(struct udevice *dev, unsigned int addr,
+ ulong value, enum pci_size_t size);
+ int (*read_io)(struct udevice *dev, unsigned int addr, ulong *valuep,
+ enum pci_size_t size);
+ int (*map_physmem)(struct udevice *dev, phys_addr_t addr,
+ unsigned long *lenp, void **ptrp);
+ int (*unmap_physmem)(const void *vaddr, unsigned long len,
+ struct udevice *dev);
+};
+
+int pci_bus_find_bdf(pci_dev_t bdf, struct udevice **devp);
+
+int pci_bus_find_devfn(struct udevice *bus, pci_dev_t find_devfn,
+ struct udevice **devp);
+
+#define pci_get_emul_ops(dev) ((struct dm_pci_emul_ops *)(dev)->driver->ops)
+
+int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn,
+ struct udevice **emulp);
+
+int pci_get_ff(enum pci_size_t size);
+
+int pci_bus_find_devices(struct udevice *bus, struct pci_device_id *ids,
+ int *indexp, struct udevice **devp);
+
+int pci_find_device_id(struct pci_device_id *ids, int index,
+ struct udevice **devp);
+
+#endif
+
#endif /* __ASSEMBLY__ */
#endif /* _PCI_H */
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 2345df4..b622ba2 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -735,7 +735,7 @@ int fdtdec_read_fmap_entry(const void *blob, int node, const char *name,
return 0;
}
-static u64 fdtdec_get_number(const fdt32_t *ptr, unsigned int cells)
+u64 fdtdec_get_number(const fdt32_t *ptr, unsigned int cells)
{
u64 number = 0;
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 612aa95..8281779 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -21,4 +21,5 @@ obj-$(CONFIG_DM_GPIO) += gpio.o
obj-$(CONFIG_DM_SPI) += spi.o
obj-$(CONFIG_DM_SPI_FLASH) += sf.o
obj-$(CONFIG_DM_I2C) += i2c.o
+obj-$(CONFIG_DM_PCI) += pci.o
endif
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index cd2c389..3341a08 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -143,12 +143,12 @@ static int dm_test_fdt(struct dm_test_state *dms)
/* These are num_devices compatible root-level device tree nodes */
ut_asserteq(num_devices, list_count_items(&uc->dev_head));
- /* Each should have no platdata / priv */
+ /* Each should have platdata but no priv */
for (i = 0; i < num_devices; i++) {
ret = uclass_find_device(UCLASS_TEST_FDT, i, &dev);
ut_assert(!ret);
ut_assert(!dev_get_priv(dev));
- ut_assert(!dev->platdata);
+ ut_assert(dev->platdata);
}
ut_assertok(dm_check_devices(dms, num_devices));
diff --git a/test/dm/test.dts b/test/dm/test.dts
index 69991a3..af2fb2c 100644
--- a/test/dm/test.dts
+++ b/test/dm/test.dts
@@ -8,6 +8,7 @@
aliases {
console = &uart0;
+ pci0 = &pci;
testfdt6 = "/e-test";
};
@@ -110,6 +111,22 @@
};
};
+ pci: pci-controller {
+ compatible = "sandbox,pci";
+ device_type = "pci";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges = <0x02000000 0 0x10000000 0x10000000 0 0x2000
+ 0x01000000 0 0x20000000 0x20000000 0 0x2000>;
+ pci@1f,0 {
+ compatible = "pci-generic";
+ reg = <0xf800 0 0 0 0>;
+ emul@1f,0 {
+ compatible = "sandbox,swap-case";
+ };
+ };
+ };
+
spi@0 {
#address-cells = <1>;
#size-cells = <0>;
--
2.1.0.rc2.206.gedb03e5
2
2