diff options
Diffstat (limited to 'arch/arm/mach-snapdragon/board.c')
-rw-r--r-- | arch/arm/mach-snapdragon/board.c | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/arch/arm/mach-snapdragon/board.c b/arch/arm/mach-snapdragon/board.c new file mode 100644 index 00000000000..a1867852bcc --- /dev/null +++ b/arch/arm/mach-snapdragon/board.c @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Common initialisation for Qualcomm Snapdragon boards. + * + * Copyright (c) 2024 Linaro Ltd. + * Author: Caleb Connolly <caleb.connolly@linaro.org> + */ + +#include "time.h" +#include <asm/armv8/mmu.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <asm/psci.h> +#include <asm/system.h> +#include <dm/device.h> +#include <dm/pinctrl.h> +#include <dm/uclass-internal.h> +#include <dm/read.h> +#include <env.h> +#include <init.h> +#include <linux/arm-smccc.h> +#include <linux/bug.h> +#include <linux/psci.h> +#include <linux/sizes.h> +#include <malloc.h> +#include <usb.h> + +DECLARE_GLOBAL_DATA_PTR; + +static struct mm_region rbx_mem_map[CONFIG_NR_DRAM_BANKS + 2] = { { 0 } }; + +struct mm_region *mem_map = rbx_mem_map; + +int dram_init(void) +{ + return fdtdec_setup_mem_size_base(); +} + +static int ddr_bank_cmp(const void *v1, const void *v2) +{ + const struct { + phys_addr_t start; + phys_size_t size; + } *res1 = v1, *res2 = v2; + + if (!res1->size) + return 1; + if (!res2->size) + return -1; + + return (res1->start >> 24) - (res2->start >> 24); +} + +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); + + return 0; +} + +static void show_psci_version(void) +{ + struct arm_smccc_res res; + + arm_smccc_smc(ARM_PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0, 0, 0, 0, 0, &res); + + debug("PSCI: v%ld.%ld\n", + PSCI_VERSION_MAJOR(res.a0), + PSCI_VERSION_MINOR(res.a0)); +} + +void *board_fdt_blob_setup(int *err) +{ + phys_addr_t fdt; + /* Return DTB pointer passed by ABL */ + *err = 0; + fdt = get_prev_bl_fdt_addr(); + + /* + * 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 + */ + if (IS_ENABLED(CONFIG_OF_SEPARATE) && (!fdt || fdt != ALIGN(fdt, SZ_4K))) { + debug("%s: Using built in FDT, bootloader gave us %#llx\n", __func__, fdt); + return (void *)gd->fdt_blob; + } + + return (void *)fdt; +} + +void reset_cpu(void) +{ + psci_system_reset(); +} + +/* + * Some Qualcomm boards require GPIO configuration when switching USB modes. + * Support setting this configuration via pinctrl state. + */ +int board_usb_init(int index, enum usb_init_type init) +{ + struct udevice *usb; + int ret = 0; + + /* USB device */ + ret = uclass_find_device_by_seq(UCLASS_USB, index, &usb); + if (ret) { + printf("Cannot find USB device\n"); + return ret; + } + + ret = dev_read_stringlist_search(usb, "pinctrl-names", + "device"); + /* No "device" pinctrl state, so just bail */ + if (ret < 0) + return 0; + + /* Select "default" or "device" pinctrl */ + switch (init) { + case USB_INIT_HOST: + pinctrl_select_state(usb, "default"); + break; + case USB_INIT_DEVICE: + pinctrl_select_state(usb, "device"); + break; + default: + debug("Unknown usb_init_type %d\n", init); + break; + } + + return 0; +} + +/* + * Some boards still need board specific init code, they can implement that by + * overriding this function. + * + * FIXME: get rid of board specific init code + */ +void __weak qcom_board_init(void) +{ +} + +int board_init(void) +{ + show_psci_version(); + qcom_board_init(); + return 0; +} + +static void build_mem_map(void) +{ + int i; + + /* + * Ensure the peripheral block is sized to correctly cover the address range + * up to the first memory bank. + * Don't map the first page to ensure that we actually trigger an abort on a + * null pointer access rather than just hanging. + * FIXME: we should probably split this into more precise regions + */ + mem_map[0].phys = 0x1000; + mem_map[0].virt = mem_map[0].phys; + mem_map[0].size = gd->bd->bi_dram[0].start - mem_map[0].phys; + mem_map[0].attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN; + + debug("Configured memory map:\n"); + debug(" 0x%016llx - 0x%016llx: Peripheral block\n", + mem_map[0].phys, mem_map[0].phys + mem_map[0].size); + + /* + * Now add memory map entries for each DRAM bank, ensuring we don't + * overwrite the list terminator + */ + for (i = 0; i < ARRAY_SIZE(rbx_mem_map) - 2 && gd->bd->bi_dram[i].size; i++) { + if (i == ARRAY_SIZE(rbx_mem_map) - 1) { + log_warning("Too many DRAM banks!\n"); + break; + } + mem_map[i + 1].phys = gd->bd->bi_dram[i].start; + mem_map[i + 1].virt = mem_map[i + 1].phys; + mem_map[i + 1].size = gd->bd->bi_dram[i].size; + mem_map[i + 1].attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | + PTE_BLOCK_INNER_SHARE; + + debug(" 0x%016llx - 0x%016llx: DDR bank %d\n", + mem_map[i + 1].phys, mem_map[i + 1].phys + mem_map[i + 1].size, i); + } +} + +u64 get_page_table_size(void) +{ + return SZ_64K; +} + +void enable_caches(void) +{ + build_mem_map(); + + icache_enable(); + dcache_enable(); +} |