diff options
Diffstat (limited to 'roms/u-boot/arch/x86/cpu/tangier')
-rw-r--r-- | roms/u-boot/arch/x86/cpu/tangier/Kconfig | 32 | ||||
-rw-r--r-- | roms/u-boot/arch/x86/cpu/tangier/Makefile | 6 | ||||
-rw-r--r-- | roms/u-boot/arch/x86/cpu/tangier/acpi.c | 127 | ||||
-rw-r--r-- | roms/u-boot/arch/x86/cpu/tangier/car.S | 12 | ||||
-rw-r--r-- | roms/u-boot/arch/x86/cpu/tangier/pinmux.c | 195 | ||||
-rw-r--r-- | roms/u-boot/arch/x86/cpu/tangier/sdram.c | 252 | ||||
-rw-r--r-- | roms/u-boot/arch/x86/cpu/tangier/sysreset.c | 47 | ||||
-rw-r--r-- | roms/u-boot/arch/x86/cpu/tangier/tangier.c | 27 |
8 files changed, 698 insertions, 0 deletions
diff --git a/roms/u-boot/arch/x86/cpu/tangier/Kconfig b/roms/u-boot/arch/x86/cpu/tangier/Kconfig new file mode 100644 index 000000000..19aaf165d --- /dev/null +++ b/roms/u-boot/arch/x86/cpu/tangier/Kconfig @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c) 2017 Intel Corporation + +config INTEL_TANGIER + bool + depends on INTEL_MID + imply INTEL_MID_SERIAL + imply MMC + imply MMC_SDHCI + imply MMC_SDHCI_SDMA + imply MMC_SDHCI_TANGIER + imply MISC + imply USB + imply USB_XHCI_HCD + imply USB_DWC3 + imply USB_DWC3_GENERIC + +if INTEL_TANGIER + +config SYS_CAR_ADDR + hex + default 0x19200000 + +config SYS_CAR_SIZE + hex + default 0x4000 + help + Space in bytes in eSRAM used as Cache-As-RAM (CAR). + Note this size must not exceed eSRAM's total size. + +endif diff --git a/roms/u-boot/arch/x86/cpu/tangier/Makefile b/roms/u-boot/arch/x86/cpu/tangier/Makefile new file mode 100644 index 000000000..68f4a326e --- /dev/null +++ b/roms/u-boot/arch/x86/cpu/tangier/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c) 2017 Intel Corporation + +obj-y += car.o tangier.o sdram.o sysreset.o pinmux.o +obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi.o diff --git a/roms/u-boot/arch/x86/cpu/tangier/acpi.c b/roms/u-boot/arch/x86/cpu/tangier/acpi.c new file mode 100644 index 000000000..41bd177e0 --- /dev/null +++ b/roms/u-boot/arch/x86/cpu/tangier/acpi.c @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2017 Intel Corporation + * + * Partially based on acpi.c for other x86 platforms + */ + +#include <common.h> +#include <cpu.h> +#include <dm.h> +#include <acpi/acpi_table.h> +#include <asm/ioapic.h> +#include <asm/mpspec.h> +#include <asm/tables.h> +#include <asm/arch/global_nvs.h> +#include <asm/arch/iomap.h> +#include <dm/uclass-internal.h> + +void acpi_create_fadt(struct acpi_fadt *fadt, struct acpi_facs *facs, + void *dsdt) +{ + struct acpi_table_header *header = &(fadt->header); + + memset((void *)fadt, 0, sizeof(struct acpi_fadt)); + + acpi_fill_header(header, "FACP"); + header->length = sizeof(struct acpi_fadt); + header->revision = 6; + + fadt->firmware_ctrl = (u32)facs; + fadt->dsdt = (u32)dsdt; + fadt->preferred_pm_profile = ACPI_PM_UNSPECIFIED; + + fadt->iapc_boot_arch = ACPI_FADT_VGA_NOT_PRESENT | + ACPI_FADT_NO_PCIE_ASPM_CONTROL; + fadt->flags = + ACPI_FADT_WBINVD | + ACPI_FADT_POWER_BUTTON | ACPI_FADT_SLEEP_BUTTON | + ACPI_FADT_SEALED_CASE | ACPI_FADT_HEADLESS | + ACPI_FADT_HW_REDUCED_ACPI; + + fadt->minor_revision = 2; + + fadt->x_firmware_ctl_l = (u32)facs; + fadt->x_firmware_ctl_h = 0; + fadt->x_dsdt_l = (u32)dsdt; + fadt->x_dsdt_h = 0; + + header->checksum = table_compute_checksum(fadt, header->length); +} + +u32 acpi_fill_madt(u32 current) +{ + current += acpi_create_madt_lapics(current); + + current += acpi_create_madt_ioapic((struct acpi_madt_ioapic *)current, + io_apic_read(IO_APIC_ID) >> 24, IO_APIC_ADDR, 0); + + return current; +} + +u32 acpi_fill_mcfg(u32 current) +{ + /* TODO: Derive parameters from SFI MCFG table */ + current += acpi_create_mcfg_mmconfig + ((struct acpi_mcfg_mmconfig *)current, + MCFG_BASE_ADDRESS, 0x0, 0x0, 0x0); + + return current; +} + +static u32 acpi_fill_csrt_dma(struct acpi_csrt_group *grp) +{ + struct acpi_csrt_shared_info *si = (struct acpi_csrt_shared_info *)&grp[1]; + + /* Fill the Resource Group with Shared Information attached */ + memset(grp, 0, sizeof(*grp)); + grp->shared_info_length = sizeof(struct acpi_csrt_shared_info); + grp->length = sizeof(struct acpi_csrt_group) + grp->shared_info_length; + /* TODO: All values below should come from U-Boot DT somehow */ + sprintf((char *)&grp->vendor_id, "%04X", 0x8086); + grp->device_id = 0x11a2; + + /* Fill the Resource Group Shared Information */ + memset(si, 0, sizeof(*si)); + si->major_version = 1; + si->minor_version = 0; + /* TODO: All values below should come from U-Boot DT somehow */ + si->mmio_base_low = 0xff192000; + si->mmio_base_high = 0; + si->gsi_interrupt = 32; + si->interrupt_polarity = 1; + si->interrupt_mode = 0; + si->num_channels = 8; + si->dma_address_width = 32; + si->base_request_line = 0; + si->num_handshake_signals = 16; + si->max_block_size = 0x1ffff; + + return grp->length; +} + +u32 acpi_fill_csrt(u32 current) +{ + current += acpi_fill_csrt_dma((struct acpi_csrt_group *)current); + + return current; +} + +int acpi_create_gnvs(struct acpi_global_nvs *gnvs) +{ + struct udevice *dev; + int ret; + + /* at least we have one processor */ + gnvs->pcnt = 1; + + /* override the processor count with actual number */ + ret = uclass_find_first_device(UCLASS_CPU, &dev); + if (ret == 0 && dev != NULL) { + ret = cpu_get_count(dev); + if (ret > 0) + gnvs->pcnt = ret; + } + + return 0; +} diff --git a/roms/u-boot/arch/x86/cpu/tangier/car.S b/roms/u-boot/arch/x86/cpu/tangier/car.S new file mode 100644 index 000000000..7163b69a4 --- /dev/null +++ b/roms/u-boot/arch/x86/cpu/tangier/car.S @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * (C) Copyright 2010-2011 + * Graeme Russ, <graeme.russ@gmail.com> + */ + +.section .text + +.globl car_init +car_init: + jmp car_init_ret diff --git a/roms/u-boot/arch/x86/cpu/tangier/pinmux.c b/roms/u-boot/arch/x86/cpu/tangier/pinmux.c new file mode 100644 index 000000000..acf97e3af --- /dev/null +++ b/roms/u-boot/arch/x86/cpu/tangier/pinmux.c @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2018 Emlid Limited + */ + +#include <common.h> +#include <dm.h> +#include <log.h> +#include <dm/pinctrl.h> +#include <dm/read.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/cpu.h> +#include <asm/scu.h> +#include <linux/io.h> + +#define BUFCFG_OFFSET 0x100 + +#define MRFLD_FAMILY_LEN 0x400 + +/* These are taken from Linux kernel */ +#define MRFLD_PINMODE_MASK 0x07 + +#define pin_to_bufno(f, p) ((p) - (f)->pin_base) + +struct mrfld_family { + unsigned int family_number; + unsigned int pin_base; + size_t npins; + void __iomem *regs; +}; + +#define MRFLD_FAMILY(b, s, e) \ + { \ + .family_number = (b), \ + .pin_base = (s), \ + .npins = (e) - (s) + 1, \ + } + +/* Now we only support I2C family of pins */ +static struct mrfld_family mrfld_families[] = { + MRFLD_FAMILY(7, 101, 114), +}; + +struct mrfld_pinctrl { + const struct mrfld_family *families; + size_t nfamilies; +}; + +static const struct mrfld_family * +mrfld_get_family(struct mrfld_pinctrl *mp, unsigned int pin) +{ + const struct mrfld_family *family; + unsigned int i; + + for (i = 0; i < mp->nfamilies; i++) { + family = &mp->families[i]; + if (pin >= family->pin_base && + pin < family->pin_base + family->npins) + return family; + } + + pr_err("failed to find family for pin %u\n", pin); + return NULL; +} + +static void __iomem * +mrfld_get_bufcfg(struct mrfld_pinctrl *pinctrl, unsigned int pin) +{ + const struct mrfld_family *family; + unsigned int bufno; + + family = mrfld_get_family(pinctrl, pin); + if (!family) + return NULL; + + bufno = pin_to_bufno(family, pin); + + return family->regs + BUFCFG_OFFSET + bufno * 4; +} + +static void +mrfld_setup_families(void *base_addr, + struct mrfld_family *families, unsigned int nfam) +{ + for (int i = 0; i < nfam; i++) { + struct mrfld_family *family = &families[i]; + + family->regs = base_addr + + family->family_number * MRFLD_FAMILY_LEN; + } +} + +static int mrfld_pinconfig_protected(unsigned int pin, u32 mask, u32 bits) +{ + struct mrfld_pinctrl *pinctrl; + struct udevice *dev; + void __iomem *bufcfg; + u32 v, value; + int ret; + + ret = syscon_get_by_driver_data(X86_SYSCON_PINCONF, &dev); + if (ret) + return ret; + + pinctrl = dev_get_priv(dev); + + bufcfg = mrfld_get_bufcfg(pinctrl, pin); + if (!bufcfg) + return -EINVAL; + + value = readl(bufcfg); + + v = (value & ~mask) | (bits & mask); + + debug("scu: v: 0x%x p: 0x%x bits: %d, mask: %d bufcfg: 0x%p\n", + v, (u32)bufcfg, bits, mask, bufcfg); + + ret = scu_ipc_raw_command(IPCMSG_INDIRECT_WRITE, 0, &v, 4, + NULL, 0, (u32)bufcfg, 0); + if (ret) + pr_err("Failed to set mode via SCU for pin %u (%d)\n", + pin, ret); + + return ret; +} + +static int mrfld_pinctrl_cfg_pin(ofnode pin_node) +{ + bool is_protected; + int pad_offset; + int mode; + u32 mask; + int ret; + + /* For now we only support just protected Family of pins */ + is_protected = ofnode_read_bool(pin_node, "protected"); + if (!is_protected) + return -ENOTSUPP; + + pad_offset = ofnode_read_s32_default(pin_node, "pad-offset", -1); + if (pad_offset == -1) + return -EINVAL; + + mode = ofnode_read_s32_default(pin_node, "mode-func", -1); + if (mode == -1) + return -EINVAL; + + mask = MRFLD_PINMODE_MASK; + + /* We don't support modes not in range 0..7 */ + if (mode & ~mask) + return -ENOTSUPP; + + ret = mrfld_pinconfig_protected(pad_offset, mask, mode); + + return ret; +} + +static int tangier_pinctrl_probe(struct udevice *dev) +{ + void *base_addr = syscon_get_first_range(X86_SYSCON_PINCONF); + struct mrfld_pinctrl *pinctrl = dev_get_priv(dev); + ofnode pin_node; + int ret; + + mrfld_setup_families(base_addr, mrfld_families, + ARRAY_SIZE(mrfld_families)); + + pinctrl->families = mrfld_families; + pinctrl->nfamilies = ARRAY_SIZE(mrfld_families); + + ofnode_for_each_subnode(pin_node, dev_ofnode(dev)) { + ret = mrfld_pinctrl_cfg_pin(pin_node); + if (ret) { + pr_err("%s: invalid configuration for the pin %ld\n", + __func__, pin_node.of_offset); + } + } + + return 0; +} + +static const struct udevice_id tangier_pinctrl_match[] = { + { .compatible = "intel,pinctrl-tangier", .data = X86_SYSCON_PINCONF }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(tangier_pinctrl) = { + .name = "tangier_pinctrl", + .id = UCLASS_SYSCON, + .of_match = tangier_pinctrl_match, + .probe = tangier_pinctrl_probe, + .priv_auto = sizeof(struct mrfld_pinctrl), +}; diff --git a/roms/u-boot/arch/x86/cpu/tangier/sdram.c b/roms/u-boot/arch/x86/cpu/tangier/sdram.c new file mode 100644 index 000000000..afb08476e --- /dev/null +++ b/roms/u-boot/arch/x86/cpu/tangier/sdram.c @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2017 Intel Corporation + */ + +#include <common.h> +#include <init.h> +#include <log.h> +#include <asm/e820.h> +#include <asm/global_data.h> +#include <asm/sfi.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * SFI tables are part of the first stage bootloader. + * + * U-Boot finds the System Table by searching 16-byte boundaries between + * physical address 0x000E0000 and 0x000FFFFF. U-Boot shall search this region + * starting at the low address and shall stop searching when the 1st valid SFI + * System Table is found. + */ +#define SFI_BASE_ADDR 0x000E0000 +#define SFI_LENGTH 0x00020000 +#define SFI_TABLE_LENGTH 16 + +static int sfi_table_check(struct sfi_table_header *sbh) +{ + char chksum = 0; + char *pos = (char *)sbh; + u32 i; + + if (sbh->len < SFI_TABLE_LENGTH) + return -ENXIO; + + if (sbh->len > SFI_LENGTH) + return -ENXIO; + + for (i = 0; i < sbh->len; i++) + chksum += *pos++; + + if (chksum) + pr_err("sfi: Invalid checksum\n"); + + /* Checksum is OK if zero */ + return chksum ? -EILSEQ : 0; +} + +static int sfi_table_is_type(struct sfi_table_header *sbh, const char *signature) +{ + return !strncmp(sbh->sig, signature, SFI_SIGNATURE_SIZE) && + !sfi_table_check(sbh); +} + +static struct sfi_table_simple *sfi_get_table_by_sig(unsigned long addr, + const char *signature) +{ + struct sfi_table_simple *sb; + u32 i; + + for (i = 0; i < SFI_LENGTH; i += SFI_TABLE_LENGTH) { + sb = (struct sfi_table_simple *)(addr + i); + if (sfi_table_is_type(&sb->header, signature)) + return sb; + } + + return NULL; +} + +static struct sfi_table_simple *sfi_search_mmap(void) +{ + struct sfi_table_header *sbh; + struct sfi_table_simple *sb; + u32 sys_entry_cnt; + u32 i; + + /* Find SYST table */ + sb = sfi_get_table_by_sig(SFI_BASE_ADDR, SFI_SIG_SYST); + if (!sb) { + pr_err("sfi: failed to locate SYST table\n"); + return NULL; + } + + sys_entry_cnt = (sb->header.len - sizeof(*sbh)) / 8; + + /* Search through each SYST entry for MMAP table */ + for (i = 0; i < sys_entry_cnt; i++) { + sbh = (struct sfi_table_header *)(unsigned long)sb->pentry[i]; + + if (sfi_table_is_type(sbh, SFI_SIG_MMAP)) + return (struct sfi_table_simple *)sbh; + } + + pr_err("sfi: failed to locate SFI MMAP table\n"); + return NULL; +} + +#define sfi_for_each_mentry(i, sb, mentry) \ + for (i = 0, mentry = (struct sfi_mem_entry *)sb->pentry; \ + i < SFI_GET_NUM_ENTRIES(sb, struct sfi_mem_entry); \ + i++, mentry++) \ + +static unsigned int sfi_setup_e820(unsigned int max_entries, + struct e820_entry *entries) +{ + struct sfi_table_simple *sb; + struct sfi_mem_entry *mentry; + unsigned long long start, end, size; + int type, total = 0; + u32 i; + + sb = sfi_search_mmap(); + if (!sb) + return 0; + + sfi_for_each_mentry(i, sb, mentry) { + start = mentry->phys_start; + size = mentry->pages << 12; + end = start + size; + + if (start > end) + continue; + + /* translate SFI mmap type to E820 map type */ + switch (mentry->type) { + case SFI_MEM_CONV: + type = E820_RAM; + break; + case SFI_MEM_UNUSABLE: + case SFI_RUNTIME_SERVICE_DATA: + continue; + default: + type = E820_RESERVED; + } + + if (total == E820MAX) + break; + entries[total].addr = start; + entries[total].size = size; + entries[total].type = type; + + total++; + } + + return total; +} + +static int sfi_get_bank_size(void) +{ + struct sfi_table_simple *sb; + struct sfi_mem_entry *mentry; + int bank = 0; + u32 i; + + sb = sfi_search_mmap(); + if (!sb) + return 0; + + sfi_for_each_mentry(i, sb, mentry) { + if (mentry->type != SFI_MEM_CONV) + continue; + + gd->bd->bi_dram[bank].start = mentry->phys_start; + gd->bd->bi_dram[bank].size = mentry->pages << 12; + bank++; + } + + return bank; +} + +static phys_size_t sfi_get_ram_size(void) +{ + struct sfi_table_simple *sb; + struct sfi_mem_entry *mentry; + phys_size_t ram = 0; + u32 i; + + sb = sfi_search_mmap(); + if (!sb) + return 0; + + sfi_for_each_mentry(i, sb, mentry) { + if (mentry->type != SFI_MEM_CONV) + continue; + + ram += mentry->pages << 12; + } + + debug("sfi: RAM size %llu\n", ram); + return ram; +} + +unsigned int install_e820_map(unsigned int max_entries, + struct e820_entry *entries) +{ + return sfi_setup_e820(max_entries, entries); +} + +/* + * This function looks for the highest region of memory lower than 2GB which + * has enough space for U-Boot where U-Boot is aligned on a page boundary. It + * overrides the default implementation found elsewhere which simply picks the + * end of RAM, wherever that may be. The location of the stack, the relocation + * address, and how far U-Boot is moved by relocation are set in the global + * data structure. + */ +ulong board_get_usable_ram_top(ulong total_size) +{ + struct sfi_table_simple *sb; + struct sfi_mem_entry *mentry; + ulong dest_addr = 0; + u32 i; + + sb = sfi_search_mmap(); + if (!sb) + panic("No available memory found for relocation"); + + sfi_for_each_mentry(i, sb, mentry) { + unsigned long long start, end; + + if (mentry->type != SFI_MEM_CONV) + continue; + + start = mentry->phys_start; + end = start + (mentry->pages << 12); + + /* Filter memory over 2GB. */ + if (end > 0x7fffffffULL) + end = 0x80000000ULL; + /* Skip this region if it's too small. */ + if (end - start < total_size) + continue; + + /* Use this address if it's the largest so far. */ + if (end > dest_addr) + dest_addr = end; + } + + return dest_addr; +} + +int dram_init_banksize(void) +{ + sfi_get_bank_size(); + return 0; +} + +int dram_init(void) +{ + gd->ram_size = sfi_get_ram_size(); + return 0; +} diff --git a/roms/u-boot/arch/x86/cpu/tangier/sysreset.c b/roms/u-boot/arch/x86/cpu/tangier/sysreset.c new file mode 100644 index 000000000..b03bc28f9 --- /dev/null +++ b/roms/u-boot/arch/x86/cpu/tangier/sysreset.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com> + * + * Reset driver for tangier processor + */ + +#include <common.h> +#include <dm.h> +#include <sysreset.h> +#include <asm/scu.h> + +static int tangier_sysreset_request(struct udevice *dev, enum sysreset_t type) +{ + int value; + + switch (type) { + case SYSRESET_WARM: + value = IPCMSG_WARM_RESET; + break; + case SYSRESET_COLD: + value = IPCMSG_COLD_RESET; + break; + default: + return -ENOSYS; + } + + scu_ipc_simple_command(value, 0); + + return -EINPROGRESS; +} + +static const struct udevice_id tangier_sysreset_ids[] = { + { .compatible = "intel,reset-tangier" }, + { } +}; + +static struct sysreset_ops tangier_sysreset_ops = { + .request = tangier_sysreset_request, +}; + +U_BOOT_DRIVER(tangier_sysreset) = { + .name = "tangier-sysreset", + .id = UCLASS_SYSRESET, + .of_match = tangier_sysreset_ids, + .ops = &tangier_sysreset_ops, +}; diff --git a/roms/u-boot/arch/x86/cpu/tangier/tangier.c b/roms/u-boot/arch/x86/cpu/tangier/tangier.c new file mode 100644 index 000000000..1e2f6cc8b --- /dev/null +++ b/roms/u-boot/arch/x86/cpu/tangier/tangier.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2017 Intel Corporation + */ + +#include <common.h> +#include <cpu_func.h> +#include <init.h> +#include <asm/u-boot-x86.h> + +/* + * Miscellaneous platform dependent initializations + */ +int arch_cpu_init(void) +{ + return x86_cpu_init_f(); +} + +int checkcpu(void) +{ + return 0; +} + +int print_cpuinfo(void) +{ + return default_print_cpuinfo(); +} |