Various improvements to Snapdragon support:

* Bumped up the pagetable size to handle newer SoCs with much more RAM
* Made memory map parsing more robust, fixing chainloading on
  SM8550/SM8650
* Populate fdt_addr_r with U-Boot's FDT by default, and set $loadaddr to
  prevent
  crashes with some commands which expect it
* Added initial support for SC7280/QCM6490 and the new RB3 Gen 2 board
* Add debug config fragments to enable debug UART on some SoCs.
* Enable RPMh regulators on SM8550/SM8650
* Map the cmd-db memory explicitly since it may not be in the memory map

CI: https://source.denx.de/u-boot/custodians/u-boot-snapdragon/-/pipelines/22255
This commit is contained in:
Tom Rini 2024-09-09 10:52:55 -06:00
commit 48038bfb4d
20 changed files with 664 additions and 29 deletions

View File

@ -617,6 +617,7 @@ R: Sumit Garg <sumit.garg@linaro.org>
L: u-boot-qcom@groups.io
S: Maintained
T: git https://source.denx.de/u-boot/custodians/u-boot-snapdragon.git
F: configs/qcm6490_defconfig
F: drivers/*/*/pm8???-*
F: drivers/gpio/msm_gpio.c
F: drivers/mmc/msm_sdhci.c

View File

@ -339,6 +339,31 @@ static void map_range(u64 virt, u64 phys, u64 size, int level,
}
}
void mmu_map_region(phys_addr_t addr, u64 size, bool emergency)
{
u64 va_bits;
int level = 0;
u64 attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_INNER_SHARE;
attrs |= PTE_TYPE_BLOCK | PTE_BLOCK_AF;
get_tcr(NULL, &va_bits);
if (va_bits < 39)
level = 1;
if (emergency)
map_range(addr, addr, size, level,
(u64 *)gd->arch.tlb_emerg, attrs);
/* Switch pagetables while we update the primary one */
__asm_switch_ttbr(gd->arch.tlb_emerg);
map_range(addr, addr, size, level,
(u64 *)gd->arch.tlb_addr, attrs);
__asm_switch_ttbr(gd->arch.tlb_addr);
}
static void add_map(struct mm_region *map)
{
u64 attrs = map->attrs | PTE_TYPE_BLOCK | PTE_BLOCK_AF;

View File

@ -0,0 +1,28 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
* Copyright (c) 2024 Linaro Ltd.
*/
/ {
/* When running as the primary bootloader there is no prior
* stage to populate the memory layout for us. We *should*
* have two nodes here, but ABL does NOT like that.
* sooo we're stuck with this.
*/
memory@80000000 {
device_type = "memory";
reg = <0 0x80000000 0 0x3A800000>,
<0 0xC0000000 0 0x01800000>,
<0 0xC3400000 0 0x3CC00000>,
<1 0x00000000 1 0x00000000>;
};
};
&usb_1_dwc3 {
dr_mode = "host";
/delete-property/ usb-role-switch;
};
// RAM Entry 0 : Base 0x0080000000 Size 0x003A800000
// RAM Entry 1 : Base 0x00C0000000 Size 0x0001800000
// RAM Entry 2 : Base 0x00C3400000 Size 0x003CC00000
// RAM Entry 3 : Base 0x0100000000 Size 0x0100000000

View File

@ -277,6 +277,16 @@ void protect_secure_region(void);
void smp_kick_all_cpus(void);
void flush_l3_cache(void);
/**
* mmu_map_region() - map a region of previously unmapped memory.
* Will be mapped MT_NORMAL & PTE_BLOCK_INNER_SHARE.
*
* @start: Start address of the region
* @size: Size of the region
* @emerg: Also map the region in the emergency table
*/
void mmu_map_region(phys_addr_t start, u64 size, bool emerg);
void mmu_change_region_attr(phys_addr_t start, size_t size, u64 attrs);
/*

View File

@ -18,6 +18,7 @@
#include <dm/read.h>
#include <power/regulator.h>
#include <env.h>
#include <fdt_support.h>
#include <init.h>
#include <linux/arm-smccc.h>
#include <linux/bug.h>
@ -37,9 +38,18 @@ static struct mm_region rbx_mem_map[CONFIG_NR_DRAM_BANKS + 2] = { { 0 } };
struct mm_region *mem_map = rbx_mem_map;
static struct {
phys_addr_t start;
phys_size_t size;
} prevbl_ddr_banks[CONFIG_NR_DRAM_BANKS] __section(".data") = { 0 };
int dram_init(void)
{
return fdtdec_setup_mem_size_base();
/*
* gd->ram_base / ram_size have been setup already
* in qcom_parse_memory().
*/
return 0;
}
static int ddr_bank_cmp(const void *v1, const void *v2)
@ -57,23 +67,71 @@ static int ddr_bank_cmp(const void *v1, const void *v2)
return (res1->start >> 24) - (res2->start >> 24);
}
/* This has to be done post-relocation since gd->bd isn't preserved */
static void qcom_configure_bi_dram(void)
{
int i;
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
gd->bd->bi_dram[i].start = prevbl_ddr_banks[i].start;
gd->bd->bi_dram[i].size = prevbl_ddr_banks[i].size;
}
}
int dram_init_banksize(void)
{
int ret;
ret = fdtdec_setup_memory_banksize();
if (ret < 0)
return ret;
if (CONFIG_NR_DRAM_BANKS < 2)
return 0;
/* Sort our RAM banks -_- */
qsort(gd->bd->bi_dram, CONFIG_NR_DRAM_BANKS, sizeof(gd->bd->bi_dram[0]), ddr_bank_cmp);
qcom_configure_bi_dram();
return 0;
}
static void qcom_parse_memory(void)
{
ofnode node;
const fdt64_t *memory;
int memsize;
phys_addr_t ram_end = 0;
int i, j, banks;
node = ofnode_path("/memory");
if (!ofnode_valid(node)) {
log_err("No memory node found in device tree!\n");
return;
}
memory = ofnode_read_prop(node, "reg", &memsize);
if (!memory) {
log_err("No memory configuration was provided by the previous bootloader!\n");
return;
}
banks = min(memsize / (2 * sizeof(u64)), (ulong)CONFIG_NR_DRAM_BANKS);
if (memsize / sizeof(u64) > CONFIG_NR_DRAM_BANKS * 2)
log_err("Provided more than the max of %d memory banks\n", CONFIG_NR_DRAM_BANKS);
if (banks > CONFIG_NR_DRAM_BANKS)
log_err("Provided more memory banks than we can handle\n");
for (i = 0, j = 0; i < banks * 2; i += 2, j++) {
prevbl_ddr_banks[j].start = get_unaligned_be64(&memory[i]);
prevbl_ddr_banks[j].size = get_unaligned_be64(&memory[i + 1]);
/* SM8650 boards sometimes have empty regions! */
if (!prevbl_ddr_banks[j].size) {
j--;
continue;
}
ram_end = max(ram_end, prevbl_ddr_banks[j].start + prevbl_ddr_banks[j].size);
}
/* Sort our RAM banks -_- */
qsort(prevbl_ddr_banks, banks, sizeof(prevbl_ddr_banks[0]), ddr_bank_cmp);
gd->ram_base = prevbl_ddr_banks[0].start;
gd->ram_size = ram_end - gd->ram_base;
debug("ram_base = %#011lx, ram_size = %#011llx, ram_end = %#011llx\n",
gd->ram_base, gd->ram_size, ram_end);
}
static void show_psci_version(void)
{
struct arm_smccc_res res;
@ -85,26 +143,43 @@ static void show_psci_version(void)
PSCI_VERSION_MINOR(res.a0));
}
/* We support booting U-Boot with an internal DT when running as a first-stage bootloader
* or for supporting quirky devices where it's easier to leave the downstream DT in place
* to improve ABL compatibility. Otherwise, we use the DT provided by ABL.
*/
void *board_fdt_blob_setup(int *err)
{
phys_addr_t fdt;
/* Return DTB pointer passed by ABL */
struct fdt_header *fdt;
bool internal_valid, external_valid;
*err = 0;
fdt = get_prev_bl_fdt_addr();
fdt = (struct fdt_header *)get_prev_bl_fdt_addr();
external_valid = fdt && !fdt_check_header(fdt);
internal_valid = !fdt_check_header(gd->fdt_blob);
/*
* If we bail then the board will simply not boot, instead let's
* try and use the FDT built into U-Boot if there is one...
* This avoids having a hard dependency on the previous stage bootloader
* There is no point returning an error here, U-Boot can't do anything useful in this situation.
* Bail out while we can still print a useful error message.
*/
if (!internal_valid && !external_valid)
panic("Internal FDT is invalid and no external FDT was provided! (fdt=%#llx)\n",
(phys_addr_t)fdt);
if (IS_ENABLED(CONFIG_OF_SEPARATE) && (!fdt || fdt != ALIGN(fdt, SZ_4K) ||
fdt_check_header((void *)fdt))) {
debug("%s: Using built in FDT, bootloader gave us %#llx\n", __func__, fdt);
return (void *)gd->fdt_blob;
if (internal_valid) {
debug("Using built in FDT\n");
} else {
debug("Using external FDT\n");
/* So we can use it before returning */
gd->fdt_blob = fdt;
}
return (void *)fdt;
/*
* Parse the /memory node while we're here,
* this makes it easy to do other things early.
*/
qcom_parse_memory();
return (void *)gd->fdt_blob;
}
void reset_cpu(void)
@ -169,6 +244,66 @@ int board_init(void)
return 0;
}
/**
* out_len includes the trailing null space
*/
static int get_cmdline_option(const char *cmdline, const char *key, char *out, int out_len)
{
const char *p, *p_end;
int len;
p = strstr(cmdline, key);
if (!p)
return -ENOENT;
p += strlen(key);
p_end = strstr(p, " ");
if (!p_end)
return -ENOENT;
len = p_end - p;
if (len > out_len)
len = out_len;
strncpy(out, p, len);
out[len] = '\0';
return 0;
}
/* The bootargs are populated by the previous stage bootloader */
static const char *get_cmdline(void)
{
ofnode node;
static const char *cmdline = NULL;
if (cmdline)
return cmdline;
node = ofnode_path("/chosen");
if (!ofnode_valid(node))
return NULL;
cmdline = ofnode_read_string(node, "bootargs");
return cmdline;
}
void qcom_set_serialno(void)
{
const char *cmdline = get_cmdline();
char serial[32];
if (!cmdline) {
log_debug("Failed to get bootargs\n");
return;
}
get_cmdline_option(cmdline, "androidboot.serialno=", serial, sizeof(serial));
if (serial[0] != '\0')
env_set("serial#", serial);
}
/* Sets up the "board", and "soc" environment variables as well as constructing the devicetree
* path, with a few quirks to handle non-standard dtb filenames. This is not meant to be a
* comprehensive solution to automatically picking the DTB, but aims to be correct for the
@ -267,6 +402,8 @@ static void configure_env(void)
snprintf(dt_path, sizeof(dt_path), "qcom/%s-%s.dtb",
env_get("soc"), env_get("board"));
env_set("fdtfile", dt_path);
qcom_set_serialno();
}
void __weak qcom_late_init(void)
@ -274,6 +411,11 @@ void __weak qcom_late_init(void)
}
#define KERNEL_COMP_SIZE SZ_64M
#ifdef CONFIG_FASTBOOT_BUF_SIZE
#define FASTBOOT_BUF_SIZE CONFIG_FASTBOOT_BUF_SIZE
#else
#define FASTBOOT_BUF_SIZE 0
#endif
#define addr_alloc(size) lmb_alloc(size, SZ_2M)
@ -281,19 +423,29 @@ void __weak qcom_late_init(void)
int board_late_init(void)
{
u32 status = 0;
phys_addr_t addr;
struct fdt_header *fdt_blob = (struct fdt_header *)gd->fdt_blob;
/* We need to be fairly conservative here as we support boards with just 1G of TOTAL RAM */
status |= env_set_hex("kernel_addr_r", addr_alloc(SZ_128M));
addr = addr_alloc(SZ_128M);
status |= env_set_hex("kernel_addr_r", addr);
status |= env_set_hex("loadaddr", addr);
status |= env_set_hex("ramdisk_addr_r", addr_alloc(SZ_128M));
status |= env_set_hex("kernel_comp_addr_r", addr_alloc(KERNEL_COMP_SIZE));
status |= env_set_hex("kernel_comp_size", KERNEL_COMP_SIZE);
if (IS_ENABLED(CONFIG_FASTBOOT))
status |= env_set_hex("fastboot_addr_r", addr_alloc(FASTBOOT_BUF_SIZE));
status |= env_set_hex("scriptaddr", addr_alloc(SZ_4M));
status |= env_set_hex("pxefile_addr_r", addr_alloc(SZ_4M));
status |= env_set_hex("fdt_addr_r", addr_alloc(SZ_2M));
addr = addr_alloc(SZ_2M);
status |= env_set_hex("fdt_addr_r", addr);
if (status)
log_warning("%s: Failed to set run time variables\n", __func__);
/* By default copy U-Boots FDT, it will be used as a fallback */
memcpy((void *)addr, (void *)gd->fdt_blob, fdt32_to_cpu(fdt_blob->totalsize));
configure_env();
qcom_late_init();
@ -339,7 +491,7 @@ static void build_mem_map(void)
u64 get_page_table_size(void)
{
return SZ_64K;
return SZ_1M;
}
static int fdt_cmp_res(const void *v1, const void *v2)

View File

@ -0,0 +1,5 @@
CONFIG_DEBUG_UART=y
CONFIG_DEBUG_UART_ANNOUNCE=y
CONFIG_DEBUG_UART_BASE=0xa84000
CONFIG_DEBUG_UART_MSM_GENI=y
CONFIG_DEBUG_UART_CLOCK=7372800

View File

@ -0,0 +1,5 @@
CONFIG_DEBUG_UART=y
CONFIG_DEBUG_UART_ANNOUNCE=y
CONFIG_DEBUG_UART_BASE=0x4a90000
CONFIG_DEBUG_UART_MSM_GENI=y
CONFIG_DEBUG_UART_CLOCK=14745600

View File

@ -0,0 +1,5 @@
CONFIG_DEBUG_UART=y
CONFIG_DEBUG_UART_ANNOUNCE=y
CONFIG_DEBUG_UART_BASE=0xa90000
CONFIG_DEBUG_UART_MSM_GENI=y
CONFIG_DEBUG_UART_CLOCK=14745600

21
configs/qcm6490_defconfig Normal file
View File

@ -0,0 +1,21 @@
# Configuration for building U-Boot to be flashed
# to the uefi partition of QCM6490 dev boards with
# the "Linux Embedded" partition layout (which have
# a dedicated "uefi" partition for edk2/U-Boot)
#include "qcom_defconfig"
# Otherwise buildman thinks this isn't an ARM platform
CONFIG_ARM=y
CONFIG_DEBUG_UART=y
CONFIG_DEBUG_UART_ANNOUNCE=y
CONFIG_DEBUG_UART_BASE=0x994000
CONFIG_DEBUG_UART_MSM_GENI=y
CONFIG_DEBUG_UART_CLOCK=14745600
# Address where U-Boot will be loaded
CONFIG_TEXT_BASE=0x9fc00000
CONFIG_REMAKE_ELF=y
CONFIG_DEFAULT_DEVICE_TREE="qcom/qcs6490-rb3gen2"

View File

@ -3,6 +3,7 @@ CONFIG_SKIP_LOWLEVEL_INIT=y
CONFIG_POSITION_INDEPENDENT=y
CONFIG_SYS_INIT_SP_BSS_OFFSET=1572864
CONFIG_ARCH_SNAPDRAGON=y
CONFIG_NR_DRAM_BANKS=24
CONFIG_DEFAULT_DEVICE_TREE="qcom/sdm845-db845c"
CONFIG_SYS_LOAD_ADDR=0xA0000000
CONFIG_BUTTON_CMD=y
@ -44,6 +45,7 @@ CONFIG_CLK_QCOM_APQ8016=y
CONFIG_CLK_QCOM_APQ8096=y
CONFIG_CLK_QCOM_QCM2290=y
CONFIG_CLK_QCOM_QCS404=y
CONFIG_CLK_QCOM_SC7280=y
CONFIG_CLK_QCOM_SDM845=y
CONFIG_CLK_QCOM_SM6115=y
CONFIG_CLK_QCOM_SM8250=y

View File

@ -7,5 +7,6 @@ Qualcomm
:maxdepth: 2
dragonboard410c
rb3gen2
board
debugging

View File

@ -0,0 +1,53 @@
.. SPDX-License-Identifier: GPL-2.0+
.. sectionauthor:: Caleb Connolly <caleb.connolly@linaro.org>
Qualcomm Robotics RB3 Gen 2
===========================
The RB3 Gen 2 is a development board based on the Qualcomm QCM6490 SoC (a derivative
of SC7280). More information can be found on `Qualcomm's product page`_.
U-Boot can be used as a replacement for Qualcomm's original EDK2 bootloader by
flashing it directly to the uefi_a (or _b) partition.
.. _Qualcomm's product page: https://www.qualcomm.com/developer/hardware/rb3-gen-2-development-kit
Installation
------------
First, setup ``CROSS_COMPILE`` for aarch64. Then, build U-Boot for ``qcm6490``::
$ export CROSS_COMPILE=<aarch64 toolchain prefix>
$ make qcm6490_defconfig
$ make -j8
This will build ``u-boot.elf`` in the configured output directory.
Although the RB3 Gen 2 does not have secure boot set up by default,
the firmware still expects firmware ELF images to be "signed". The signature
does not provide any security in this case, but it provides the firmware with
some required metadata.
To "sign" ``u-boot.elf`` you can use e.g. `qtestsign`_::
$ qtestsign -v6 aboot -o u-boot.mbn u-boot.elf
Then install the resulting ``u-boot.mbn`` to the ``uefi_a`` partition
on your device with ``fastboot flash uefi_a u-boot.mbn``.
U-Boot should be running after a reboot (``fastboot reboot``).
Note that fastboot is not yet supported in U-Boot on this board, as a result,
to flash back the original firmware, or new versoins of the U-Boot, EDL mode
must be used. This can be accessed by pressing the EDL mode button as described
in the Qualcomm Linux documentation. A tool like bkerler's `edl`_ can be used
for flashing with the firehose loader binary appropriate for the board.
.. _qtestsign: https://github.com/msm8916-mainline/qtestsign
.. _edl: https://github.com/bkerler/edl
Usage
-----
The USB Type-A ports are connected via a PCIe USB hub, which is not supported yet.
However, the Type-C port can be used with a powered USB dock to connect peripherals
like a USB stick.

View File

@ -86,6 +86,14 @@ config CLK_QCOM_SM8650
on the Snapdragon SM8650 SoC. This driver supports the clocks
and resets exposed by the GCC hardware block.
config CLK_QCOM_SC7280
bool "Qualcomm SC7280 GCC"
select CLK_QCOM
help
Say Y here to enable support for the Global Clock Controller
on the Snapdragon SC7280 SoC. This driver supports the clocks
and resets exposed by the GCC hardware block.
endmenu
endif

View File

@ -9,6 +9,7 @@ obj-$(CONFIG_CLK_QCOM_APQ8096) += clock-apq8096.o
obj-$(CONFIG_CLK_QCOM_IPQ4019) += clock-ipq4019.o
obj-$(CONFIG_CLK_QCOM_QCM2290) += clock-qcm2290.o
obj-$(CONFIG_CLK_QCOM_QCS404) += clock-qcs404.o
obj-$(CONFIG_CLK_QCOM_SC7280) += clock-sc7280.o
obj-$(CONFIG_CLK_QCOM_SM6115) += clock-sm6115.o
obj-$(CONFIG_CLK_QCOM_SM8250) += clock-sm8250.o
obj-$(CONFIG_CLK_QCOM_SM8550) += clock-sm8550.o

View File

@ -11,6 +11,7 @@
#define CFG_CLK_SRC_GPLL0 (1 << 8)
#define CFG_CLK_SRC_GPLL0_AUX2 (2 << 8)
#define CFG_CLK_SRC_GPLL9 (2 << 8)
#define CFG_CLK_SRC_GPLL0_ODD (3 << 8)
#define CFG_CLK_SRC_GPLL6 (4 << 8)
#define CFG_CLK_SRC_GPLL7 (3 << 8)
#define CFG_CLK_SRC_GPLL4 (5 << 8)

View File

@ -0,0 +1,132 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Clock drivers for Qualcomm sc7280
*
* (C) Copyright 2024 Linaro Ltd.
*/
#include <linux/types.h>
#include <clk-uclass.h>
#include <dm.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <linux/bug.h>
#include <linux/bitops.h>
#include <dt-bindings/clock/qcom,gcc-sc7280.h>
#include "clock-qcom.h"
#define USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR 0xf038
#define USB30_PRIM_MASTER_CLK_CMD_RCGR 0xf020
static ulong sc7280_set_rate(struct clk *clk, ulong rate)
{
struct msm_clk_priv *priv = dev_get_priv(clk->dev);
if (clk->id < priv->data->num_clks)
debug("%s: %s, requested rate=%ld\n", __func__, priv->data->clks[clk->id].name, rate);
switch (clk->id) {
case GCC_USB30_PRIM_MOCK_UTMI_CLK:
WARN(rate != 19200000, "Unexpected rate for USB30_PRIM_MOCK_UTMI_CLK: %lu\n", rate);
clk_rcg_set_rate(priv->base, USB30_PRIM_MASTER_CLK_CMD_RCGR, 0, CFG_CLK_SRC_CXO);
return rate;
case GCC_USB30_PRIM_MASTER_CLK:
WARN(rate != 200000000, "Unexpected rate for USB30_PRIM_MASTER_CLK: %lu\n", rate);
clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MASTER_CLK_CMD_RCGR,
1, 0, 0, CFG_CLK_SRC_GPLL0_ODD, 8);
clk_rcg_set_rate(priv->base, 0xf064, 0, 0);
return rate;
default:
return 0;
}
}
static const struct gate_clk sc7280_clks[] = {
GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0xf07c, 1),
GATE_CLK(GCC_USB30_PRIM_MASTER_CLK, 0xf010, 1),
GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0xf080, 1),
GATE_CLK(GCC_USB30_PRIM_SLEEP_CLK, 0xf018, 1),
GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0xf01c, 1),
GATE_CLK(GCC_USB3_PRIM_PHY_AUX_CLK, 0xf054, 1),
GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0xf058, 1),
};
static int sc7280_enable(struct clk *clk)
{
struct msm_clk_priv *priv = dev_get_priv(clk->dev);
if (priv->data->num_clks < clk->id) {
debug("%s: unknown clk id %lu\n", __func__, clk->id);
return 0;
}
debug("%s: clk %ld: %s\n", __func__, clk->id, sc7280_clks[clk->id].name);
switch (clk->id) {
case GCC_AGGRE_USB3_PRIM_AXI_CLK:
qcom_gate_clk_en(priv, GCC_USB30_PRIM_MASTER_CLK);
fallthrough;
case GCC_USB30_PRIM_MASTER_CLK:
qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_AUX_CLK);
qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_COM_AUX_CLK);
break;
}
qcom_gate_clk_en(priv, clk->id);
return 0;
}
static const struct qcom_reset_map sc7280_gcc_resets[] = {
[GCC_PCIE_0_BCR] = { 0x6b000 },
[GCC_PCIE_0_PHY_BCR] = { 0x6c01c },
[GCC_PCIE_1_BCR] = { 0x8d000 },
[GCC_PCIE_1_PHY_BCR] = { 0x8e01c },
[GCC_QUSB2PHY_PRIM_BCR] = { 0x12000 },
[GCC_QUSB2PHY_SEC_BCR] = { 0x12004 },
[GCC_SDCC1_BCR] = { 0x75000 },
[GCC_SDCC2_BCR] = { 0x14000 },
[GCC_SDCC4_BCR] = { 0x16000 },
[GCC_UFS_PHY_BCR] = { 0x77000 },
[GCC_USB30_PRIM_BCR] = { 0xf000 },
[GCC_USB30_SEC_BCR] = { 0x9e000 },
[GCC_USB3_DP_PHY_PRIM_BCR] = { 0x50008 },
[GCC_USB3_PHY_PRIM_BCR] = { 0x50000 },
[GCC_USB3PHY_PHY_PRIM_BCR] = { 0x50004 },
[GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 },
};
static const struct qcom_power_map sc7280_gdscs[] = {
[GCC_UFS_PHY_GDSC] = { 0x77004 },
[GCC_USB30_PRIM_GDSC] = { 0xf004 },
};
static struct msm_clk_data qcs404_gcc_data = {
.resets = sc7280_gcc_resets,
.num_resets = ARRAY_SIZE(sc7280_gcc_resets),
.clks = sc7280_clks,
.num_clks = ARRAY_SIZE(sc7280_clks),
.power_domains = sc7280_gdscs,
.num_power_domains = ARRAY_SIZE(sc7280_gdscs),
.enable = sc7280_enable,
.set_rate = sc7280_set_rate,
};
static const struct udevice_id gcc_sc7280_of_match[] = {
{
.compatible = "qcom,gcc-sc7280",
.data = (ulong)&qcs404_gcc_data,
},
{ }
};
U_BOOT_DRIVER(gcc_sc7280) = {
.name = "gcc_sc7280",
.id = UCLASS_NOP,
.of_match = gcc_sc7280_of_match,
.bind = qcom_cc_bind,
.flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF,
};

View File

@ -381,6 +381,7 @@ static struct iommu_ops qcom_smmu_ops = {
static const struct udevice_id qcom_smmu500_ids[] = {
{ .compatible = "qcom,sdm845-smmu-500" },
{ .compatible = "qcom,sc7280-smmu-500" },
{ .compatible = "qcom,smmu-500", },
{ /* sentinel */ }
};

View File

@ -357,6 +357,69 @@ static const struct dm_regulator_ops rpmh_regulator_vrm_drms_ops = {
.get_mode = rpmh_regulator_vrm_get_mode,
};
static struct dm_regulator_mode pmic_mode_map_pmic5_bob[] = {
{
.id = REGULATOR_MODE_LPM,
.register_value = PMIC5_BOB_MODE_PFM,
.name = "PMIC5_BOB_MODE_PFM"
}, {
.id = REGULATOR_MODE_AUTO,
.register_value = PMIC5_BOB_MODE_AUTO,
.name = "PMIC5_BOB_MODE_AUTO"
}, {
.id = REGULATOR_MODE_HPM,
.register_value = PMIC5_BOB_MODE_PWM,
.name = "PMIC5_BOB_MODE_PWM"
},
};
static struct dm_regulator_mode pmic_mode_map_pmic5_smps[] = {
{
.id = REGULATOR_MODE_RETENTION,
.register_value = PMIC5_SMPS_MODE_RETENTION,
.name = "PMIC5_SMPS_MODE_RETENTION"
}, {
.id = REGULATOR_MODE_LPM,
.register_value = PMIC5_SMPS_MODE_PFM,
.name = "PMIC5_SMPS_MODE_PFM"
}, {
.id = REGULATOR_MODE_AUTO,
.register_value = PMIC5_SMPS_MODE_AUTO,
.name = "PMIC5_SMPS_MODE_AUTO"
}, {
.id = REGULATOR_MODE_HPM,
.register_value = PMIC5_SMPS_MODE_PWM,
.name = "PMIC5_SMPS_MODE_PWM"
},
};
static const struct rpmh_vreg_hw_data pmic5_bob = {
.regulator_type = VRM,
.ops = &rpmh_regulator_vrm_drms_ops,
.voltage_range = REGULATOR_LINEAR_RANGE(3000000, 0, 31, 32000),
.n_voltages = 32,
.pmic_mode_map = pmic_mode_map_pmic5_bob,
.n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_bob),
};
static const struct rpmh_vreg_hw_data pmic5_ftsmps525_lv = {
.regulator_type = VRM,
.ops = &rpmh_regulator_vrm_drms_ops,
.voltage_range = REGULATOR_LINEAR_RANGE(300000, 0, 267, 4000),
.n_voltages = 268,
.pmic_mode_map = pmic_mode_map_pmic5_smps,
.n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_smps),
};
static const struct rpmh_vreg_hw_data pmic5_ftsmps525_mv = {
.regulator_type = VRM,
.ops = &rpmh_regulator_vrm_drms_ops,
.voltage_range = REGULATOR_LINEAR_RANGE(600000, 0, 267, 8000),
.n_voltages = 268,
.pmic_mode_map = pmic_mode_map_pmic5_smps,
.n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_smps),
};
static struct dm_regulator_mode pmic_mode_map_pmic5_ldo[] = {
{
.id = REGULATOR_MODE_RETENTION,
@ -393,6 +456,16 @@ static const struct rpmh_vreg_hw_data pmic5_pldo_lv = {
.n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_ldo),
};
static const struct rpmh_vreg_hw_data pmic5_nldo515 = {
.regulator_type = VRM,
.ops = &rpmh_regulator_vrm_drms_ops,
.voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 210, 8000),
.n_voltages = 211,
.hpm_min_load_uA = 30000,
.pmic_mode_map = pmic_mode_map_pmic5_ldo,
.n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_ldo),
};
#define RPMH_VREG(_name, _resource_name, _hw_data, _supply_name) \
{ \
.name = _name, \
@ -412,6 +485,57 @@ static const struct rpmh_vreg_init_data pm8150l_vreg_data[] = {
{}
};
static const struct rpmh_vreg_init_data pm8550_vreg_data[] = {
RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1-l4-l10"),
RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l13-l14"),
RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"),
RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo515, "vdd-l1-l4-l10"),
RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l16"),
RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l6-l7"),
RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l6-l7"),
RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo, "vdd-l8-l9"),
RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l8-l9"),
RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo515, "vdd-l1-l4-l10"),
RPMH_VREG("ldo11", "ldo%s11", &pmic5_nldo515, "vdd-l11"),
RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo515, "vdd-l12"),
RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l2-l13-l14"),
RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo, "vdd-l2-l13-l14"),
RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo515, "vdd-l15"),
RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l5-l16"),
RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l17"),
RPMH_VREG("bob1", "bob%s1", &pmic5_bob, "vdd-bob1"),
RPMH_VREG("bob2", "bob%s2", &pmic5_bob, "vdd-bob2"),
{}
};
static const struct rpmh_vreg_init_data pm8550vs_vreg_data[] = {
RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"),
RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"),
RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"),
RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_lv, "vdd-s4"),
RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"),
RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_mv, "vdd-s6"),
RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"),
RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2"),
RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"),
{}
};
static const struct rpmh_vreg_init_data pm8550ve_vreg_data[] = {
RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"),
RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"),
RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"),
RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_mv, "vdd-s4"),
RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"),
RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_lv, "vdd-s6"),
RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525_lv, "vdd-s7"),
RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525_lv, "vdd-s8"),
RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"),
RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2"),
RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"),
{}
};
/* probe an individual regulator */
static int rpmh_regulator_probe(struct udevice *dev)
{
@ -526,6 +650,18 @@ static const struct udevice_id rpmh_regulator_ids[] = {
.compatible = "qcom,pm8150l-rpmh-regulators",
.data = (ulong)pm8150l_vreg_data,
},
{
.compatible = "qcom,pm8550-rpmh-regulators",
.data = (ulong)pm8550_vreg_data,
},
{
.compatible = "qcom,pm8550ve-rpmh-regulators",
.data = (ulong)pm8550ve_vreg_data,
},
{
.compatible = "qcom,pm8550vs-rpmh-regulators",
.data = (ulong)pm8550vs_vreg_data,
},
{ /* sentinal */ },
};

View File

@ -6,6 +6,7 @@
#define pr_fmt(fmt) "cmd-db: " fmt
#include <asm/system.h>
#include <dm.h>
#include <dm/ofnode.h>
#include <dm/device_compat.h>
@ -141,7 +142,7 @@ static int cmd_db_get_header(const char *id, const struct entry_header **eh,
ent = rsc_to_entry_header(rsc_hdr);
for (j = 0; j < le16_to_cpu(rsc_hdr->cnt); j++, ent++) {
if (memcmp(ent->id, query, sizeof(ent->id)) == 0) {
if (strncmp(ent->id, query, sizeof(ent->id)) == 0) {
if (eh)
*eh = ent;
if (rh)
@ -182,9 +183,10 @@ u32 cmd_db_read_addr(const char *id)
}
EXPORT_SYMBOL_GPL(cmd_db_read_addr);
int cmd_db_bind(struct udevice *dev)
static int cmd_db_bind(struct udevice *dev)
{
void __iomem *base;
fdt_size_t size;
ofnode node;
if (cmd_db_header)
@ -194,12 +196,15 @@ int cmd_db_bind(struct udevice *dev)
debug("%s(%s)\n", __func__, ofnode_get_name(node));
base = (void __iomem *)ofnode_get_addr(node);
base = (void __iomem *)ofnode_get_addr_size(node, "reg", &size);
if ((fdt_addr_t)base == FDT_ADDR_T_NONE) {
log_err("%s: Failed to read base address\n", __func__);
return -ENOENT;
}
/* On SM8550/SM8650 and newer SoCs cmd-db might not be mapped */
mmu_map_region((phys_addr_t)base, (phys_size_t)size, false);
cmd_db_header = base;
if (!cmd_db_magic_matches(cmd_db_header)) {
log_err("%s: Invalid Command DB Magic\n", __func__);

View File

@ -293,6 +293,48 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id,
write_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id, cmd_enable);
}
/**
* __tcs_set_trigger() - Start xfer on a TCS or unset trigger on a borrowed TCS
* @drv: The controller.
* @tcs_id: The global ID of this TCS.
* @trigger: If true then untrigger/retrigger. If false then just untrigger.
*
* In the normal case we only ever call with "trigger=true" to start a
* transfer. That will un-trigger/disable the TCS from the last transfer
* then trigger/enable for this transfer.
*
* If we borrowed a wake TCS for an active-only transfer we'll also call
* this function with "trigger=false" to just do the un-trigger/disable
* before using the TCS for wake purposes again.
*
* Note that the AP is only in charge of triggering active-only transfers.
* The AP never triggers sleep/wake values using this function.
*/
static void __tcs_set_trigger(struct rsc_drv *drv, int tcs_id, bool trigger)
{
u32 enable;
u32 reg = drv->regs[RSC_DRV_CONTROL];
/*
* HW req: Clear the DRV_CONTROL and enable TCS again
* While clearing ensure that the AMC mode trigger is cleared
* and then the mode enable is cleared.
*/
enable = read_tcs_reg(drv, reg, tcs_id);
enable &= ~TCS_AMC_MODE_TRIGGER;
write_tcs_reg_sync(drv, reg, tcs_id, enable);
enable &= ~TCS_AMC_MODE_ENABLE;
write_tcs_reg_sync(drv, reg, tcs_id, enable);
if (trigger) {
/* Enable the AMC mode on the TCS and then trigger the TCS */
enable = TCS_AMC_MODE_ENABLE;
write_tcs_reg_sync(drv, reg, tcs_id, enable);
enable |= TCS_AMC_MODE_TRIGGER;
write_tcs_reg(drv, reg, tcs_id, enable);
}
}
/**
* rpmh_rsc_send_data() - Write / trigger active-only message.
* @drv: The controller.
@ -348,6 +390,7 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg)
* of __tcs_set_trigger() below.
*/
__tcs_buffer_write(drv, tcs_id, 0, msg);
__tcs_set_trigger(drv, tcs_id, true);
/* U-Boot: Now wait for the TCS to be cleared, indicating that we're done */
for (i = 0; i < USEC_PER_SEC; i++) {