summaryrefslogtreecommitdiff
path: root/board/theobroma-systems/puma_rk3399
diff options
context:
space:
mode:
Diffstat (limited to 'board/theobroma-systems/puma_rk3399')
-rw-r--r--board/theobroma-systems/puma_rk3399/Kconfig6
-rw-r--r--board/theobroma-systems/puma_rk3399/fit_spl_atf.its12
-rw-r--r--board/theobroma-systems/puma_rk3399/puma-rk3399.c135
3 files changed, 146 insertions, 7 deletions
diff --git a/board/theobroma-systems/puma_rk3399/Kconfig b/board/theobroma-systems/puma_rk3399/Kconfig
index a645590d78..80b3460d4c 100644
--- a/board/theobroma-systems/puma_rk3399/Kconfig
+++ b/board/theobroma-systems/puma_rk3399/Kconfig
@@ -12,4 +12,10 @@ config SYS_CONFIG_NAME
config BOARD_SPECIFIC_OPTIONS # dummy
def_bool y
+config ENV_SIZE
+ default 0x2000 if ENV_IS_IN_SPI_FLASH
+
+config ENV_OFFSET
+ default 0x3c000 if ENV_IS_IN_SPI_FLASH
+
endif
diff --git a/board/theobroma-systems/puma_rk3399/fit_spl_atf.its b/board/theobroma-systems/puma_rk3399/fit_spl_atf.its
index 520f846d66..cb7d92fead 100644
--- a/board/theobroma-systems/puma_rk3399/fit_spl_atf.its
+++ b/board/theobroma-systems/puma_rk3399/fit_spl_atf.its
@@ -17,6 +17,7 @@
description = "U-Boot (64-bit)";
data = /incbin/("../../../u-boot-nodtb.bin");
type = "standalone";
+ os = "U-Boot";
arch = "arm64";
compression = "none";
load = <0x00200000>;
@@ -26,16 +27,17 @@
data = /incbin/("../../../bl31-rk3399.bin");
type = "firmware";
arch = "arm64";
+ os = "arm-trusted-firmware";
compression = "none";
- load = <0x00001000>;
- entry = <0x00001000>;
+ load = <0x1000>;
+ entry = <0x1000>;
};
pmu {
description = "Cortex-M0 firmware";
data = /incbin/("../../../rk3399m0.bin");
type = "pmu-firmware";
compression = "none";
- load = <0xff8c0000>;
+ load = <0x180000>;
};
fdt {
description = "RK3399-Q7 (Puma) flat device-tree";
@@ -49,8 +51,8 @@
default = "conf";
conf {
description = "Theobroma Systems RK3399-Q7 (Puma) SoM";
- firmware = "uboot";
- loadables = "atf";
+ firmware = "atf";
+ loadables = "uboot", "pmu";
fdt = "fdt";
};
};
diff --git a/board/theobroma-systems/puma_rk3399/puma-rk3399.c b/board/theobroma-systems/puma_rk3399/puma-rk3399.c
index 2b4988e2d2..c6690fa069 100644
--- a/board/theobroma-systems/puma_rk3399/puma-rk3399.c
+++ b/board/theobroma-systems/puma_rk3399/puma-rk3399.c
@@ -7,12 +7,20 @@
#include <common.h>
#include <dm.h>
#include <misc.h>
+#include <spl.h>
+#include <syscon.h>
+#include <usb.h>
#include <dm/pinctrl.h>
#include <dm/uclass-internal.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
#include <asm/setup.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/cru_rk3399.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/grf_rk3399.h>
#include <asm/arch/periph.h>
#include <power/regulator.h>
-#include <spl.h>
#include <u-boot/sha256.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -32,9 +40,50 @@ int board_init(void)
return 0;
}
+static void rk3399_force_power_on_reset(void)
+{
+ ofnode node;
+ struct gpio_desc sysreset_gpio;
+
+ debug("%s: trying to force a power-on reset\n", __func__);
+
+ node = ofnode_path("/config");
+ if (!ofnode_valid(node)) {
+ debug("%s: no /config node?\n", __func__);
+ return;
+ }
+
+ if (gpio_request_by_name_nodev(node, "sysreset-gpio", 0,
+ &sysreset_gpio, GPIOD_IS_OUT)) {
+ debug("%s: could not find a /config/sysreset-gpio\n", __func__);
+ return;
+ }
+
+ dm_gpio_set_value(&sysreset_gpio, 1);
+}
+
void spl_board_init(void)
{
int ret;
+ struct rk3399_cru *cru = rockchip_get_cru();
+
+ /*
+ * The RK3399 resets only 'almost all logic' (see also in the TRM
+ * "3.9.4 Global software reset"), when issuing a software reset.
+ * This may cause issues during boot-up for some configurations of
+ * the application software stack.
+ *
+ * To work around this, we test whether the last reset reason was
+ * a power-on reset and (if not) issue an overtemp-reset to reset
+ * the entire module.
+ *
+ * While this was previously fixed by modifying the various places
+ * that could generate a software reset (e.g. U-Boot's sysreset
+ * driver, the ATF or Linux), we now have it here to ensure that
+ * we no longer have to track this through the various components.
+ */
+ if (cru->glb_rst_st != 0)
+ rk3399_force_power_on_reset();
/*
* Turning the eMMC and SPI back on (if disabled via the Qseven
@@ -128,17 +177,32 @@ static void setup_serial(void)
serialno = crc32_no_comp(0, low, 8);
serialno |= (u64)crc32_no_comp(serialno, high, 8) << 32;
- snprintf(serialno_str, sizeof(serialno_str), "%llx", serialno);
+ snprintf(serialno_str, sizeof(serialno_str), "%016llx", serialno);
env_set("cpuid#", cpuid_str);
env_set("serial#", serialno_str);
#endif
}
+static void setup_iodomain(void)
+{
+ const u32 GRF_IO_VSEL_GPIO4CD_SHIFT = 3;
+ struct rk3399_grf_regs *grf =
+ syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+
+ /*
+ * Set bit 3 in GRF_IO_VSEL so PCIE_RST# works (pin GPIO4_C6).
+ * Linux assumes that PCIE_RST# works out of the box as it probes
+ * PCIe before loading the iodomain driver.
+ */
+ rk_setreg(&grf->io_vsel, 1 << GRF_IO_VSEL_GPIO4CD_SHIFT);
+}
+
int misc_init_r(void)
{
setup_serial();
setup_macaddr();
+ setup_iodomain();
return 0;
}
@@ -158,3 +222,70 @@ void get_board_serial(struct tag_serialnr *serialnr)
serialnr->low = (u32)(serial & 0xffffffff);
}
#endif
+
+/**
+ * Switch power at an external regulator (for our root hub).
+ *
+ * @param ctrl pointer to the xHCI controller
+ * @param port port number as in the control message (one-based)
+ * @param enable boolean indicating whether to enable or disable power
+ * @return returns 0 on success, an error-code on failure
+ */
+static int board_usb_port_power_set(struct udevice *dev, int port,
+ bool enable)
+{
+#if CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(DM_REGULATOR)
+ /* We start counting ports at 0, while USB counts from 1. */
+ int index = port - 1;
+ const char *regname = NULL;
+ struct udevice *regulator;
+ const char *prop = "tsd,usb-port-power";
+ int ret;
+
+ debug("%s: ctrl '%s' port %d enable %s\n", __func__,
+ dev_read_name(dev), port, enable ? "true" : "false");
+
+ ret = dev_read_string_index(dev, prop, index, &regname);
+ if (ret < 0) {
+ debug("%s: ctrl '%s' port %d: no entry in '%s'\n",
+ __func__, dev_read_name(dev), port, prop);
+ return ret;
+ }
+
+ ret = regulator_get_by_platname(regname, &regulator);
+ if (ret) {
+ debug("%s: ctrl '%s' port %d: could not get regulator '%s'\n",
+ __func__, dev_read_name(dev), port, regname);
+ return ret;
+ }
+
+ regulator_set_enable(regulator, enable);
+ return 0;
+#else
+ return -ENOTSUPP;
+#endif
+}
+
+void usb_hub_reset_devices(struct usb_hub_device *hub, int port)
+{
+ struct udevice *dev = hub->pusb_dev->dev;
+ struct udevice *ctrl;
+
+ /* We are only interested in our root-hubs */
+ if (usb_hub_is_root_hub(dev) == false)
+ return;
+
+ ctrl = usb_get_bus(dev);
+ if (!ctrl) {
+ debug("%s: could not retrieve ctrl for hub\n", __func__);
+ return;
+ }
+
+ /*
+ * To work around an incompatibility between the single-threaded
+ * USB stack in U-Boot and (a strange low-power mode of) the USB
+ * hub we have on-module, we need to delay powering on the hub
+ * until the first time the port is probed.
+ */
+ board_usb_port_power_set(ctrl, port, true);
+}