mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2025-12-24 10:52:13 +01:00
Merge branch 'qcom-next' of https://gitlab.denx.de/u-boot/custodians/u-boot-snapdragon into next
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:
commit
48038bfb4d
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
28
arch/arm/dts/qcs6490-rb3gen2-u-boot.dtsi
Normal file
28
arch/arm/dts/qcs6490-rb3gen2-u-boot.dtsi
Normal 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
|
||||
@ -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);
|
||||
|
||||
/*
|
||||
|
||||
@ -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)
|
||||
|
||||
5
board/qualcomm/debug-sdm845.config
Normal file
5
board/qualcomm/debug-sdm845.config
Normal 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
|
||||
5
board/qualcomm/debug-sm6115.config
Normal file
5
board/qualcomm/debug-sm6115.config
Normal 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
|
||||
5
board/qualcomm/debug-sm8250.config
Normal file
5
board/qualcomm/debug-sm8250.config
Normal 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
21
configs/qcm6490_defconfig
Normal 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"
|
||||
@ -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
|
||||
|
||||
@ -7,5 +7,6 @@ Qualcomm
|
||||
:maxdepth: 2
|
||||
|
||||
dragonboard410c
|
||||
rb3gen2
|
||||
board
|
||||
debugging
|
||||
|
||||
53
doc/board/qualcomm/rb3gen2.rst
Normal file
53
doc/board/qualcomm/rb3gen2.rst
Normal 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.
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
132
drivers/clk/qcom/clock-sc7280.c
Normal file
132
drivers/clk/qcom/clock-sc7280.c
Normal 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,
|
||||
};
|
||||
@ -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 */ }
|
||||
};
|
||||
|
||||
@ -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 */ },
|
||||
};
|
||||
|
||||
|
||||
@ -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__);
|
||||
|
||||
@ -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++) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user