uboot/board/theobroma-systems/puma_rk3399/puma-rk3399.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2017 Theobroma Systems Design und Consulting GmbH
   3 *
   4 * SPDX-License-Identifier:     GPL-2.0+
   5 */
   6
   7#include <common.h>
   8#include <dm.h>
   9#include <misc.h>
  10#include <spl.h>
  11#include <syscon.h>
  12#include <usb.h>
  13#include <dm/pinctrl.h>
  14#include <dm/uclass-internal.h>
  15#include <asm/io.h>
  16#include <asm/gpio.h>
  17#include <asm/setup.h>
  18#include <asm/arch/clock.h>
  19#include <asm/arch/cru_rk3399.h>
  20#include <asm/arch/hardware.h>
  21#include <asm/arch/grf_rk3399.h>
  22#include <asm/arch/periph.h>
  23#include <power/regulator.h>
  24#include <u-boot/sha256.h>
  25
  26DECLARE_GLOBAL_DATA_PTR;
  27
  28int board_init(void)
  29{
  30        int ret;
  31
  32        /*
  33         * We need to call into regulators_enable_boot_on() again, as the call
  34         * during SPL may have not included all regulators.
  35         */
  36        ret = regulators_enable_boot_on(false);
  37        if (ret)
  38                debug("%s: Cannot enable boot on regulator\n", __func__);
  39
  40        return 0;
  41}
  42
  43static void rk3399_force_power_on_reset(void)
  44{
  45        ofnode node;
  46        struct gpio_desc sysreset_gpio;
  47
  48        debug("%s: trying to force a power-on reset\n", __func__);
  49
  50        node = ofnode_path("/config");
  51        if (!ofnode_valid(node)) {
  52                debug("%s: no /config node?\n", __func__);
  53                return;
  54        }
  55
  56        if (gpio_request_by_name_nodev(node, "sysreset-gpio", 0,
  57                                       &sysreset_gpio, GPIOD_IS_OUT)) {
  58                debug("%s: could not find a /config/sysreset-gpio\n", __func__);
  59                return;
  60        }
  61
  62        dm_gpio_set_value(&sysreset_gpio, 1);
  63}
  64
  65void spl_board_init(void)
  66{
  67        int  ret;
  68        struct rk3399_cru *cru = rockchip_get_cru();
  69
  70        /*
  71         * The RK3399 resets only 'almost all logic' (see also in the TRM
  72         * "3.9.4 Global software reset"), when issuing a software reset.
  73         * This may cause issues during boot-up for some configurations of
  74         * the application software stack.
  75         *
  76         * To work around this, we test whether the last reset reason was
  77         * a power-on reset and (if not) issue an overtemp-reset to reset
  78         * the entire module.
  79         *
  80         * While this was previously fixed by modifying the various places
  81         * that could generate a software reset (e.g. U-Boot's sysreset
  82         * driver, the ATF or Linux), we now have it here to ensure that
  83         * we no longer have to track this through the various components.
  84         */
  85        if (cru->glb_rst_st != 0)
  86                rk3399_force_power_on_reset();
  87
  88        /*
  89         * Turning the eMMC and SPI back on (if disabled via the Qseven
  90         * BIOS_ENABLE) signal is done through a always-on regulator).
  91         */
  92        ret = regulators_enable_boot_on(false);
  93        if (ret)
  94                debug("%s: Cannot enable boot on regulator\n", __func__);
  95
  96        preloader_console_init();
  97}
  98
  99static void setup_macaddr(void)
 100{
 101#if CONFIG_IS_ENABLED(CMD_NET)
 102        int ret;
 103        const char *cpuid = env_get("cpuid#");
 104        u8 hash[SHA256_SUM_LEN];
 105        int size = sizeof(hash);
 106        u8 mac_addr[6];
 107
 108        /* Only generate a MAC address, if none is set in the environment */
 109        if (env_get("ethaddr"))
 110                return;
 111
 112        if (!cpuid) {
 113                debug("%s: could not retrieve 'cpuid#'\n", __func__);
 114                return;
 115        }
 116
 117        ret = hash_block("sha256", (void *)cpuid, strlen(cpuid), hash, &size);
 118        if (ret) {
 119                debug("%s: failed to calculate SHA256\n", __func__);
 120                return;
 121        }
 122
 123        /* Copy 6 bytes of the hash to base the MAC address on */
 124        memcpy(mac_addr, hash, 6);
 125
 126        /* Make this a valid MAC address and set it */
 127        mac_addr[0] &= 0xfe;  /* clear multicast bit */
 128        mac_addr[0] |= 0x02;  /* set local assignment bit (IEEE802) */
 129        eth_env_set_enetaddr("ethaddr", mac_addr);
 130#endif
 131}
 132
 133static void setup_serial(void)
 134{
 135#if CONFIG_IS_ENABLED(ROCKCHIP_EFUSE)
 136        const u32 cpuid_offset = 0x7;
 137        const u32 cpuid_length = 0x10;
 138
 139        struct udevice *dev;
 140        int ret, i;
 141        u8 cpuid[cpuid_length];
 142        u8 low[cpuid_length/2], high[cpuid_length/2];
 143        char cpuid_str[cpuid_length * 2 + 1];
 144        u64 serialno;
 145        char serialno_str[17];
 146
 147        /* retrieve the device */
 148        ret = uclass_get_device_by_driver(UCLASS_MISC,
 149                                          DM_GET_DRIVER(rockchip_efuse), &dev);
 150        if (ret) {
 151                debug("%s: could not find efuse device\n", __func__);
 152                return;
 153        }
 154
 155        /* read the cpu_id range from the efuses */
 156        ret = misc_read(dev, cpuid_offset, &cpuid, sizeof(cpuid));
 157        if (ret) {
 158                debug("%s: reading cpuid from the efuses failed\n",
 159                      __func__);
 160                return;
 161        }
 162
 163        memset(cpuid_str, 0, sizeof(cpuid_str));
 164        for (i = 0; i < 16; i++)
 165                sprintf(&cpuid_str[i * 2], "%02x", cpuid[i]);
 166
 167        debug("cpuid: %s\n", cpuid_str);
 168
 169        /*
 170         * Mix the cpuid bytes using the same rules as in
 171         *   ${linux}/drivers/soc/rockchip/rockchip-cpuinfo.c
 172         */
 173        for (i = 0; i < 8; i++) {
 174                low[i] = cpuid[1 + (i << 1)];
 175                high[i] = cpuid[i << 1];
 176        }
 177
 178        serialno = crc32_no_comp(0, low, 8);
 179        serialno |= (u64)crc32_no_comp(serialno, high, 8) << 32;
 180        snprintf(serialno_str, sizeof(serialno_str), "%016llx", serialno);
 181
 182        env_set("cpuid#", cpuid_str);
 183        env_set("serial#", serialno_str);
 184#endif
 185}
 186
 187static void setup_iodomain(void)
 188{
 189        const u32 GRF_IO_VSEL_GPIO4CD_SHIFT = 3;
 190        struct rk3399_grf_regs *grf =
 191            syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
 192
 193        /*
 194         * Set bit 3 in GRF_IO_VSEL so PCIE_RST# works (pin GPIO4_C6).
 195         * Linux assumes that PCIE_RST# works out of the box as it probes
 196         * PCIe before loading the iodomain driver.
 197         */
 198        rk_setreg(&grf->io_vsel, 1 << GRF_IO_VSEL_GPIO4CD_SHIFT);
 199}
 200
 201int misc_init_r(void)
 202{
 203        setup_serial();
 204        setup_macaddr();
 205        setup_iodomain();
 206
 207        return 0;
 208}
 209
 210#ifdef CONFIG_SERIAL_TAG
 211void get_board_serial(struct tag_serialnr *serialnr)
 212{
 213        char *serial_string;
 214        u64 serial = 0;
 215
 216        serial_string = env_get("serial#");
 217
 218        if (serial_string)
 219                serial = simple_strtoull(serial_string, NULL, 16);
 220
 221        serialnr->high = (u32)(serial >> 32);
 222        serialnr->low = (u32)(serial & 0xffffffff);
 223}
 224#endif
 225
 226/**
 227 * Switch power at an external regulator (for our root hub).
 228 *
 229 * @param ctrl pointer to the xHCI controller
 230 * @param port port number as in the control message (one-based)
 231 * @param enable boolean indicating whether to enable or disable power
 232 * @return returns 0 on success, an error-code on failure
 233 */
 234static int board_usb_port_power_set(struct udevice *dev, int port,
 235                                    bool enable)
 236{
 237#if CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(DM_REGULATOR)
 238        /* We start counting ports at 0, while USB counts from 1. */
 239        int index = port - 1;
 240        const char *regname = NULL;
 241        struct udevice *regulator;
 242        const char *prop = "tsd,usb-port-power";
 243        int ret;
 244
 245        debug("%s: ctrl '%s' port %d enable %s\n", __func__,
 246              dev_read_name(dev), port, enable ? "true" : "false");
 247
 248        ret = dev_read_string_index(dev, prop, index, &regname);
 249        if (ret < 0) {
 250                debug("%s: ctrl '%s' port %d: no entry in '%s'\n",
 251                      __func__, dev_read_name(dev), port, prop);
 252                return ret;
 253        }
 254
 255        ret = regulator_get_by_platname(regname, &regulator);
 256        if (ret) {
 257                debug("%s: ctrl '%s' port %d: could not get regulator '%s'\n",
 258                      __func__, dev_read_name(dev), port, regname);
 259                return ret;
 260        }
 261
 262        regulator_set_enable(regulator, enable);
 263        return 0;
 264#else
 265        return -ENOTSUPP;
 266#endif
 267}
 268
 269void usb_hub_reset_devices(struct usb_hub_device *hub, int port)
 270{
 271        struct udevice *dev = hub->pusb_dev->dev;
 272        struct udevice *ctrl;
 273
 274        /* We are only interested in our root-hubs */
 275        if (usb_hub_is_root_hub(dev) == false)
 276                return;
 277
 278        ctrl = usb_get_bus(dev);
 279        if (!ctrl) {
 280                debug("%s: could not retrieve ctrl for hub\n", __func__);
 281                return;
 282        }
 283
 284        /*
 285         * To work around an incompatibility between the single-threaded
 286         * USB stack in U-Boot and (a strange low-power mode of) the USB
 287         * hub we have on-module, we need to delay powering on the hub
 288         * until the first time the port is probed.
 289         */
 290        board_usb_port_power_set(ctrl, port, true);
 291}
 292