diff options
Diffstat (limited to 'roms/u-boot/board/gdsys')
33 files changed, 4430 insertions, 0 deletions
diff --git a/roms/u-boot/board/gdsys/a38x/MAINTAINERS b/roms/u-boot/board/gdsys/a38x/MAINTAINERS new file mode 100644 index 000000000..d31e675dd --- /dev/null +++ b/roms/u-boot/board/gdsys/a38x/MAINTAINERS @@ -0,0 +1,7 @@ +A38X BOARD +M: Dirk Eibach <dirk.eibach@gdsys.cc> +M: Mario Six <mario.six@gdsys.cc> +S: Maintained +F: board/gdsys/a38x/ +F: include/configs/controlcenterdc.h +F: configs/controlcenterdc_defconfig diff --git a/roms/u-boot/board/gdsys/a38x/Makefile b/roms/u-boot/board/gdsys/a38x/Makefile new file mode 100644 index 000000000..32fffab46 --- /dev/null +++ b/roms/u-boot/board/gdsys/a38x/Makefile @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (C) 2015 Stefan Roese <sr@denx.de> +# Copyright (C) 2015 Reinhard Pfau <reinhard.pfau@gdsys.cc> +# Copyright (C) 2016 Mario Six <mario.six@gdsys.cc> + +obj-$(CONFIG_TARGET_CONTROLCENTERDC) += controlcenterdc.o hre.o spl.o keyprogram.o dt_helpers.o + +ifeq ($(CONFIG_SPL_BUILD),) +obj-$(CONFIG_TARGET_CONTROLCENTERDC) += hydra.o ihs_phys.o +endif diff --git a/roms/u-boot/board/gdsys/a38x/controlcenterdc.c b/roms/u-boot/board/gdsys/a38x/controlcenterdc.c new file mode 100644 index 000000000..dc424f271 --- /dev/null +++ b/roms/u-boot/board/gdsys/a38x/controlcenterdc.c @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2015 Stefan Roese <sr@denx.de> + * Copyright (C) 2016 Mario Six <mario.six@gdsys.cc> + */ + +#include <common.h> +#include <command.h> +#include <dm.h> +#include <init.h> +#include <miiphy.h> +#include <net.h> +#include <tpm-v1.h> +#include <asm/global_data.h> +#include <asm/io.h> +#include <asm/arch/cpu.h> +#include <asm-generic/gpio.h> +#include <linux/delay.h> + +#include "../drivers/ddr/marvell/a38x/ddr3_init.h" +#include "../arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.h" + +#include "keyprogram.h" +#include "dt_helpers.h" +#include "hydra.h" +#include "ihs_phys.h" + +DECLARE_GLOBAL_DATA_PTR; + +#define DB_GP_88F68XX_GPP_OUT_ENA_LOW 0x7fffffff +#define DB_GP_88F68XX_GPP_OUT_ENA_MID 0xffffefff + +#define DB_GP_88F68XX_GPP_OUT_VAL_LOW 0x0 +#define DB_GP_88F68XX_GPP_OUT_VAL_MID 0x00001000 +#define DB_GP_88F68XX_GPP_POL_LOW 0x0 +#define DB_GP_88F68XX_GPP_POL_MID 0x0 + +static int get_tpm(struct udevice **devp) +{ + int rc; + + rc = uclass_first_device_err(UCLASS_TPM, devp); + if (rc) { + printf("Could not find TPM (ret=%d)\n", rc); + return CMD_RET_FAILURE; + } + + return 0; +} + +/* + * Define the DDR layout / topology here in the board file. This will + * be used by the DDR3 init code in the SPL U-Boot version to configure + * the DDR3 controller. + */ +static struct mv_ddr_topology_map ddr_topology_map = { + DEBUG_LEVEL_ERROR, + 0x1, /* active interfaces */ + /* cs_mask, mirror, dqs_swap, ck_swap X PUPs */ + { { { {0x1, 0, 0, 0}, + {0x1, 0, 0, 0}, + {0x1, 0, 0, 0}, + {0x1, 0, 0, 0}, + {0x1, 0, 0, 0} }, + SPEED_BIN_DDR_1600K, /* speed_bin */ + MV_DDR_DEV_WIDTH_16BIT, /* memory_width */ + MV_DDR_DIE_CAP_4GBIT, /* mem_size */ + MV_DDR_FREQ_533, /* frequency */ + 0, 0, /* cas_wl cas_l */ + MV_DDR_TEMP_LOW, /* temperature */ + MV_DDR_TIM_DEFAULT} }, /* timing */ + BUS_MASK_32BIT, /* Busses mask */ + MV_DDR_CFG_DEFAULT, /* ddr configuration data source */ + NOT_COMBINED, /* ddr twin-die combined */ + { {0} }, /* raw spd data */ + {0} /* timing parameters */ + +}; + +static struct serdes_map serdes_topology_map[] = { + {SGMII0, SERDES_SPEED_1_25_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + /* SATA tx polarity is inverted */ + {SATA1, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 1}, + {SGMII2, SERDES_SPEED_1_25_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {DEFAULT_SERDES, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {PEX2, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0} +}; + +int hws_board_topology_load(struct serdes_map **serdes_map_array, u8 *count) +{ + *serdes_map_array = serdes_topology_map; + *count = ARRAY_SIZE(serdes_topology_map); + return 0; +} + +void board_pex_config(void) +{ +#ifdef CONFIG_SPL_BUILD + uint k; + struct gpio_desc gpio = {}; + + if (!request_gpio_by_name(&gpio, "pca9698@22", 31, "fpga-program-gpio")) { + /* prepare FPGA reconfiguration */ + dm_gpio_set_dir_flags(&gpio, GPIOD_IS_OUT); + dm_gpio_set_value(&gpio, 0); + + /* give lunatic PCIe clock some time to stabilize */ + mdelay(500); + + /* start FPGA reconfiguration */ + dm_gpio_set_dir_flags(&gpio, GPIOD_IS_IN); + } + + /* wait for FPGA done */ + if (!request_gpio_by_name(&gpio, "pca9698@22", 19, "fpga-done-gpio")) { + for (k = 0; k < 20; ++k) { + if (dm_gpio_get_value(&gpio)) { + printf("FPGA done after %u rounds\n", k); + break; + } + mdelay(100); + } + } + + /* disable FPGA reset */ + if (!request_gpio_by_name(&gpio, "gpio@18100", 6, "cpu-to-fpga-reset")) { + dm_gpio_set_dir_flags(&gpio, GPIOD_IS_OUT); + dm_gpio_set_value(&gpio, 1); + } + + /* wait for FPGA ready */ + if (!request_gpio_by_name(&gpio, "pca9698@22", 27, "fpga-ready-gpio")) { + for (k = 0; k < 2; ++k) { + if (!dm_gpio_get_value(&gpio)) + break; + mdelay(100); + } + } +#endif +} + +struct mv_ddr_topology_map *mv_ddr_topology_map_get(void) +{ + return &ddr_topology_map; +} + +int board_early_init_f(void) +{ +#ifdef CONFIG_SPL_BUILD + /* Configure MPP */ + writel(0x00111111, MVEBU_MPP_BASE + 0x00); + writel(0x40040000, MVEBU_MPP_BASE + 0x04); + writel(0x00466444, MVEBU_MPP_BASE + 0x08); + writel(0x00043300, MVEBU_MPP_BASE + 0x0c); + writel(0x44400000, MVEBU_MPP_BASE + 0x10); + writel(0x20000334, MVEBU_MPP_BASE + 0x14); + writel(0x40000000, MVEBU_MPP_BASE + 0x18); + writel(0x00004444, MVEBU_MPP_BASE + 0x1c); + + /* Set GPP Out value */ + writel(DB_GP_88F68XX_GPP_OUT_VAL_LOW, MVEBU_GPIO0_BASE + 0x00); + writel(DB_GP_88F68XX_GPP_OUT_VAL_MID, MVEBU_GPIO1_BASE + 0x00); + + /* Set GPP Polarity */ + writel(DB_GP_88F68XX_GPP_POL_LOW, MVEBU_GPIO0_BASE + 0x0c); + writel(DB_GP_88F68XX_GPP_POL_MID, MVEBU_GPIO1_BASE + 0x0c); + + /* Set GPP Out Enable */ + writel(DB_GP_88F68XX_GPP_OUT_ENA_LOW, MVEBU_GPIO0_BASE + 0x04); + writel(DB_GP_88F68XX_GPP_OUT_ENA_MID, MVEBU_GPIO1_BASE + 0x04); +#endif + + return 0; +} + +int board_init(void) +{ + /* Address of boot parameters */ + gd->bd->bi_boot_params = mvebu_sdram_bar(0) + 0x100; + + return 0; +} + +#ifndef CONFIG_SPL_BUILD +void init_host_phys(struct mii_dev *bus) +{ + uint k; + + for (k = 0; k < 2; ++k) { + struct phy_device *phydev; + + phydev = phy_find_by_mask(bus, 1 << k, + PHY_INTERFACE_MODE_SGMII); + + if (phydev) + phy_config(phydev); + } +} + +int ccdc_eth_init(void) +{ + uint k; + uint octo_phy_mask = 0; + int ret; + struct mii_dev *bus; + + /* Init SoC's phys */ + bus = miiphy_get_dev_by_name("ethernet@34000"); + + if (bus) + init_host_phys(bus); + + bus = miiphy_get_dev_by_name("ethernet@70000"); + + if (bus) + init_host_phys(bus); + + /* Init octo phys */ + octo_phy_mask = calculate_octo_phy_mask(); + + printf("IHS PHYS: %08x", octo_phy_mask); + + ret = init_octo_phys(octo_phy_mask); + + if (ret) + return ret; + + printf("\n"); + + if (!get_fpga()) { + puts("fpga was NULL\n"); + return 1; + } + + /* reset all FPGA-QSGMII instances */ + for (k = 0; k < 80; ++k) + writel(1 << 31, get_fpga()->qsgmii_port_state[k]); + + udelay(100); + + for (k = 0; k < 80; ++k) + writel(0, get_fpga()->qsgmii_port_state[k]); + return 0; +} + +#endif + +int board_late_init(void) +{ +#ifndef CONFIG_SPL_BUILD + hydra_initialize(); +#endif + return 0; +} + +int board_fix_fdt(void *rw_fdt_blob) +{ + struct udevice *bus = NULL; + uint k; + char name[64]; + int err; + + err = uclass_get_device_by_name(UCLASS_I2C, "i2c@11000", &bus); + + if (err) { + printf("Could not get I2C bus.\n"); + return err; + } + + for (k = 0x21; k <= 0x26; k++) { + snprintf(name, 64, + "/soc/internal-regs/i2c@11000/pca9698@%02x", k); + + if (!dm_i2c_simple_probe(bus, k)) + fdt_disable_by_ofname(rw_fdt_blob, name); + } + + return 0; +} + +int last_stage_init(void) +{ + struct udevice *tpm; + int ret; + +#ifndef CONFIG_SPL_BUILD + ccdc_eth_init(); +#endif + ret = get_tpm(&tpm); + if (ret || tpm_init(tpm) || tpm1_startup(tpm, TPM_ST_CLEAR) || + tpm1_continue_self_test(tpm)) { + return 1; + } + + mdelay(37); + + flush_keys(tpm); + load_and_run_keyprog(tpm); + + return 0; +} diff --git a/roms/u-boot/board/gdsys/a38x/dt_helpers.c b/roms/u-boot/board/gdsys/a38x/dt_helpers.c new file mode 100644 index 000000000..c859024a2 --- /dev/null +++ b/roms/u-boot/board/gdsys/a38x/dt_helpers.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2016 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + */ + +#include <common.h> +#include <i2c.h> +#include <fdt_support.h> +#include <asm-generic/gpio.h> +#include <dm.h> + +int fdt_disable_by_ofname(void *rw_fdt_blob, char *ofname) +{ + int offset = fdt_path_offset(rw_fdt_blob, ofname); + + return fdt_status_disabled(rw_fdt_blob, offset); +} + +bool dm_i2c_simple_probe(struct udevice *bus, uint chip_addr) +{ + struct udevice *dev; + + return !dm_i2c_probe(bus, chip_addr, DM_I2C_CHIP_RD_ADDRESS | + DM_I2C_CHIP_WR_ADDRESS, &dev); +} + +int request_gpio_by_name(struct gpio_desc *gpio, const char *gpio_dev_name, + uint offset, char *gpio_name) +{ + struct udevice *gpio_dev = NULL; + + if (uclass_get_device_by_name(UCLASS_GPIO, gpio_dev_name, &gpio_dev)) + return 1; + + gpio->dev = gpio_dev; + gpio->offset = offset; + gpio->flags = 0; + + return dm_gpio_request(gpio, gpio_name); +} + diff --git a/roms/u-boot/board/gdsys/a38x/dt_helpers.h b/roms/u-boot/board/gdsys/a38x/dt_helpers.h new file mode 100644 index 000000000..245fadd0d --- /dev/null +++ b/roms/u-boot/board/gdsys/a38x/dt_helpers.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2016 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + */ + +#ifndef __DT_HELPERS_H +#define __DT_HELPERS_H + +int fdt_disable_by_ofname(void *rw_fdt_blob, char *ofname); +bool dm_i2c_simple_probe(struct udevice *bus, uint chip_addr); +int request_gpio_by_name(struct gpio_desc *gpio, const char *gpio_dev_name, + uint offset, char *gpio_name); + +#endif /* __DT_HELPERS_H */ diff --git a/roms/u-boot/board/gdsys/a38x/hre.c b/roms/u-boot/board/gdsys/a38x/hre.c new file mode 100644 index 000000000..de5411a6b --- /dev/null +++ b/roms/u-boot/board/gdsys/a38x/hre.c @@ -0,0 +1,529 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2013 + * Reinhard Pfau, Guntermann & Drunck GmbH, reinhard.pfau@gdsys.cc + */ + +#include <common.h> +#include <log.h> +#include <malloc.h> +#include <fs.h> +#include <i2c.h> +#include <mmc.h> +#include <tpm-v1.h> +#include <u-boot/crc.h> +#include <u-boot/sha1.h> +#include <asm/byteorder.h> +#include <asm/unaligned.h> +#include <pca9698.h> + +#include "hre.h" + +/* other constants */ +enum { + ESDHC_BOOT_IMAGE_SIG_OFS = 0x40, + ESDHC_BOOT_IMAGE_SIZE_OFS = 0x48, + ESDHC_BOOT_IMAGE_ADDR_OFS = 0x50, + ESDHC_BOOT_IMAGE_TARGET_OFS = 0x58, + ESDHC_BOOT_IMAGE_ENTRY_OFS = 0x60, +}; + +enum { + I2C_SOC_0 = 0, + I2C_SOC_1 = 1, +}; + +enum access_mode { + HREG_NONE = 0, + HREG_RD = 1, + HREG_WR = 2, + HREG_RDWR = 3, +}; + +/* register constants */ +enum { + FIX_HREG_DEVICE_ID_HASH = 0, + FIX_HREG_UNUSED1 = 1, + FIX_HREG_UNUSED2 = 2, + FIX_HREG_VENDOR = 3, + COUNT_FIX_HREGS +}; + +static struct h_reg pcr_hregs[24]; +static struct h_reg fix_hregs[COUNT_FIX_HREGS]; +static struct h_reg var_hregs[8]; + +/* hre opcodes */ +enum { + /* opcodes w/o data */ + HRE_NOP = 0x00, + HRE_SYNC = HRE_NOP, + HRE_CHECK0 = 0x01, + /* opcodes w/o data, w/ sync dst */ + /* opcodes w/ data */ + HRE_LOAD = 0x81, + /* opcodes w/data, w/sync dst */ + HRE_XOR = 0xC1, + HRE_AND = 0xC2, + HRE_OR = 0xC3, + HRE_EXTEND = 0xC4, + HRE_LOADKEY = 0xC5, +}; + +/* hre errors */ +enum { + HRE_E_OK = 0, + HRE_E_TPM_FAILURE, + HRE_E_INVALID_HREG, +}; + +static uint64_t device_id; +static uint64_t device_cl; +static uint64_t device_type; + +static uint32_t platform_key_handle; + +static uint32_t hre_tpm_err; +static int hre_err = HRE_E_OK; + +#define IS_PCR_HREG(spec) ((spec) & 0x20) +#define IS_FIX_HREG(spec) (((spec) & 0x38) == 0x08) +#define IS_VAR_HREG(spec) (((spec) & 0x38) == 0x10) +#define HREG_IDX(spec) ((spec) & (IS_PCR_HREG(spec) ? 0x1f : 0x7)) + +static const uint8_t vendor[] = "Guntermann & Drunck"; + +/** + * @brief get the size of a given (TPM) NV area + * @param tpm TPM device + * @param index NV index of the area to get size for + * @param size pointer to the size + * @return 0 on success, != 0 on error + */ +static int get_tpm_nv_size(struct udevice *tpm, uint32_t index, uint32_t *size) +{ + uint32_t err; + uint8_t info[72]; + uint8_t *ptr; + uint16_t v16; + + err = tpm1_get_capability(tpm, TPM_CAP_NV_INDEX, index, info, + sizeof(info)); + if (err) { + printf("tpm_get_capability(CAP_NV_INDEX, %08x) failed: %u\n", + index, err); + return 1; + } + + /* skip tag and nvIndex */ + ptr = info + 6; + /* skip 2 pcr info fields */ + v16 = get_unaligned_be16(ptr); + ptr += 2 + v16 + 1 + 20; + v16 = get_unaligned_be16(ptr); + ptr += 2 + v16 + 1 + 20; + /* skip permission and flags */ + ptr += 6 + 3; + + *size = get_unaligned_be32(ptr); + return 0; +} + +/** + * @brief search for a key by usage auth and pub key hash. + * @param tpm TPM device + * @param auth usage auth of the key to search for + * @param pubkey_digest (SHA1) hash of the pub key structure of the key + * @param[out] handle the handle of the key iff found + * @return 0 if key was found in TPM; != 0 if not. + */ +static int find_key(struct udevice *tpm, const uint8_t auth[20], + const uint8_t pubkey_digest[20], uint32_t *handle) +{ + uint16_t key_count; + uint32_t key_handles[10]; + uint8_t buf[288]; + uint8_t *ptr; + uint32_t err; + uint8_t digest[20]; + size_t buf_len; + unsigned int i; + + /* fetch list of already loaded keys in the TPM */ + err = tpm1_get_capability(tpm, TPM_CAP_HANDLE, TPM_RT_KEY, buf, + sizeof(buf)); + if (err) + return -1; + key_count = get_unaligned_be16(buf); + ptr = buf + 2; + for (i = 0; i < key_count; ++i, ptr += 4) + key_handles[i] = get_unaligned_be32(ptr); + + /* now search a(/ the) key which we can access with the given auth */ + for (i = 0; i < key_count; ++i) { + buf_len = sizeof(buf); + err = tpm1_get_pub_key_oiap(tpm, key_handles[i], auth, buf, + &buf_len); + if (err && err != TPM_AUTHFAIL) + return -1; + if (err) + continue; + sha1_csum(buf, buf_len, digest); + if (!memcmp(digest, pubkey_digest, 20)) { + *handle = key_handles[i]; + return 0; + } + } + return 1; +} + +/** + * @brief read CCDM common data from TPM NV + * @param tpm TPM device + * @return 0 if CCDM common data was found and read, !=0 if something failed. + */ +static int read_common_data(struct udevice *tpm) +{ + uint32_t size = 0; + uint32_t err; + uint8_t buf[256]; + sha1_context ctx; + + if (get_tpm_nv_size(tpm, NV_COMMON_DATA_INDEX, &size) || + size < NV_COMMON_DATA_MIN_SIZE) + return 1; + err = tpm1_nv_read_value(tpm, NV_COMMON_DATA_INDEX, buf, + min(sizeof(buf), size)); + if (err) { + printf("tpm_nv_read_value() failed: %u\n", err); + return 1; + } + + device_id = get_unaligned_be64(buf); + device_cl = get_unaligned_be64(buf + 8); + device_type = get_unaligned_be64(buf + 16); + + sha1_starts(&ctx); + sha1_update(&ctx, buf, 24); + sha1_finish(&ctx, fix_hregs[FIX_HREG_DEVICE_ID_HASH].digest); + fix_hregs[FIX_HREG_DEVICE_ID_HASH].valid = true; + + platform_key_handle = get_unaligned_be32(buf + 24); + + return 0; +} + +/** + * @brief get pointer to hash register by specification + * @param spec specification of a hash register + * @return pointer to hash register or NULL if @a spec does not qualify a + * valid hash register; NULL else. + */ +static struct h_reg *get_hreg(uint8_t spec) +{ + uint8_t idx; + + idx = HREG_IDX(spec); + if (IS_FIX_HREG(spec)) { + if (idx < ARRAY_SIZE(fix_hregs)) + return fix_hregs + idx; + hre_err = HRE_E_INVALID_HREG; + } else if (IS_PCR_HREG(spec)) { + if (idx < ARRAY_SIZE(pcr_hregs)) + return pcr_hregs + idx; + hre_err = HRE_E_INVALID_HREG; + } else if (IS_VAR_HREG(spec)) { + if (idx < ARRAY_SIZE(var_hregs)) + return var_hregs + idx; + hre_err = HRE_E_INVALID_HREG; + } + return NULL; +} + +/** + * @brief get pointer of a hash register by specification and usage. + * @param tpm TPM device + * @param spec specification of a hash register + * @param mode access mode (read or write or read/write) + * @return pointer to hash register if found and valid; NULL else. + * + * This func uses @a get_reg() to determine the hash register for a given spec. + * If a register is found it is validated according to the desired access mode. + * The value of automatic registers (PCR register and fixed registers) is + * loaded or computed on read access. + */ +static struct h_reg *access_hreg(struct udevice *tpm, uint8_t spec, + enum access_mode mode) +{ + struct h_reg *result; + + result = get_hreg(spec); + if (!result) + return NULL; + + if (mode & HREG_WR) { + if (IS_FIX_HREG(spec)) { + hre_err = HRE_E_INVALID_HREG; + return NULL; + } + } + if (mode & HREG_RD) { + if (!result->valid) { + if (IS_PCR_HREG(spec)) { + hre_tpm_err = tpm1_pcr_read(tpm, HREG_IDX(spec), + result->digest, 20); + result->valid = (hre_tpm_err == TPM_SUCCESS); + } else if (IS_FIX_HREG(spec)) { + switch (HREG_IDX(spec)) { + case FIX_HREG_DEVICE_ID_HASH: + read_common_data(tpm); + break; + case FIX_HREG_VENDOR: + memcpy(result->digest, vendor, 20); + result->valid = true; + break; + } + } else { + result->valid = true; + } + } + if (!result->valid) { + hre_err = HRE_E_INVALID_HREG; + return NULL; + } + } + + return result; +} + +static void *compute_and(void *_dst, const void *_src, size_t n) +{ + uint8_t *dst = _dst; + const uint8_t *src = _src; + size_t i; + + for (i = n; i-- > 0; ) + *dst++ &= *src++; + + return _dst; +} + +static void *compute_or(void *_dst, const void *_src, size_t n) +{ + uint8_t *dst = _dst; + const uint8_t *src = _src; + size_t i; + + for (i = n; i-- > 0; ) + *dst++ |= *src++; + + return _dst; +} + +static void *compute_xor(void *_dst, const void *_src, size_t n) +{ + uint8_t *dst = _dst; + const uint8_t *src = _src; + size_t i; + + for (i = n; i-- > 0; ) + *dst++ ^= *src++; + + return _dst; +} + +static void *compute_extend(void *_dst, const void *_src, size_t n) +{ + uint8_t digest[20]; + sha1_context ctx; + + sha1_starts(&ctx); + sha1_update(&ctx, _dst, n); + sha1_update(&ctx, _src, n); + sha1_finish(&ctx, digest); + memcpy(_dst, digest, min(n, sizeof(digest))); + + return _dst; +} + +static int hre_op_loadkey(struct udevice *tpm, struct h_reg *src_reg, + struct h_reg *dst_reg, const void *key, + size_t key_size) +{ + uint32_t parent_handle; + uint32_t key_handle; + + if (!src_reg || !dst_reg || !src_reg->valid || !dst_reg->valid) + return -1; + if (find_key(tpm, src_reg->digest, dst_reg->digest, &parent_handle)) + return -1; + hre_tpm_err = tpm1_load_key2_oiap(tpm, parent_handle, key, key_size, + src_reg->digest, &key_handle); + if (hre_tpm_err) { + hre_err = HRE_E_TPM_FAILURE; + return -1; + } + + return 0; +} + +/** + * @brief executes the next opcode on the hash register engine. + * @param tpm TPM device + * @param[in,out] ip pointer to the opcode (instruction pointer) + * @param[in,out] code_size (remaining) size of the code + * @return new instruction pointer on success, NULL on error. + */ +static const uint8_t *hre_execute_op(struct udevice *tpm, const uint8_t **ip, + size_t *code_size) +{ + bool dst_modified = false; + uint32_t ins; + uint8_t opcode; + uint8_t src_spec; + uint8_t dst_spec; + uint16_t data_size; + struct h_reg *src_reg, *dst_reg; + uint8_t buf[20]; + const uint8_t *src_buf, *data; + uint8_t *ptr; + int i; + void * (*bin_func)(void *, const void *, size_t); + + if (*code_size < 4) + return NULL; + + ins = get_unaligned_be32(*ip); + opcode = **ip; + data = *ip + 4; + src_spec = (ins >> 18) & 0x3f; + dst_spec = (ins >> 12) & 0x3f; + data_size = (ins & 0x7ff); + + debug("HRE: ins=%08x (op=%02x, s=%02x, d=%02x, L=%d)\n", ins, + opcode, src_spec, dst_spec, data_size); + + if ((opcode & 0x80) && (data_size + 4) > *code_size) + return NULL; + + src_reg = access_hreg(tpm, src_spec, HREG_RD); + if (hre_err || hre_tpm_err) + return NULL; + dst_reg = access_hreg(tpm, dst_spec, + (opcode & 0x40) ? HREG_RDWR : HREG_WR); + if (hre_err || hre_tpm_err) + return NULL; + + switch (opcode) { + case HRE_NOP: + goto end; + case HRE_CHECK0: + if (src_reg) { + for (i = 0; i < 20; ++i) { + if (src_reg->digest[i]) + return NULL; + } + } + break; + case HRE_LOAD: + bin_func = memcpy; + goto do_bin_func; + case HRE_XOR: + bin_func = compute_xor; + goto do_bin_func; + case HRE_AND: + bin_func = compute_and; + goto do_bin_func; + case HRE_OR: + bin_func = compute_or; + goto do_bin_func; + case HRE_EXTEND: + bin_func = compute_extend; +do_bin_func: + if (!dst_reg) + return NULL; + if (src_reg) { + src_buf = src_reg->digest; + } else { + if (!data_size) { + memset(buf, 0, 20); + src_buf = buf; + } else if (data_size == 1) { + memset(buf, *data, 20); + src_buf = buf; + } else if (data_size >= 20) { + src_buf = data; + } else { + src_buf = buf; + for (ptr = (uint8_t *)src_buf, i = 20; i > 0; + i -= data_size, ptr += data_size) + memcpy(ptr, data, + min_t(size_t, i, data_size)); + } + } + bin_func(dst_reg->digest, src_buf, 20); + dst_reg->valid = true; + dst_modified = true; + break; + case HRE_LOADKEY: + if (hre_op_loadkey(tpm, src_reg, dst_reg, data, data_size)) + return NULL; + break; + default: + return NULL; + } + + if (dst_reg && dst_modified && IS_PCR_HREG(dst_spec)) { + hre_tpm_err = tpm1_extend(tpm, HREG_IDX(dst_spec), + dst_reg->digest, dst_reg->digest); + if (hre_tpm_err) { + hre_err = HRE_E_TPM_FAILURE; + return NULL; + } + } +end: + *ip += 4; + *code_size -= 4; + if (opcode & 0x80) { + *ip += data_size; + *code_size -= data_size; + } + + return *ip; +} + +/** + * @brief runs a program on the hash register engine. + * @param tpm TPM device + * @param code pointer to the (HRE) code. + * @param code_size size of the code (in bytes). + * @return 0 on success, != 0 on failure. + */ +int hre_run_program(struct udevice *tpm, const uint8_t *code, size_t code_size) +{ + size_t code_left; + const uint8_t *ip = code; + + code_left = code_size; + hre_tpm_err = 0; + hre_err = HRE_E_OK; + while (code_left > 0) + if (!hre_execute_op(tpm, &ip, &code_left)) + return -1; + + return hre_err; +} + +int hre_verify_program(struct key_program *prg) +{ + uint32_t crc; + + crc = crc32(0, prg->code, prg->code_size); + + if (crc != prg->code_crc) { + printf("HRC crc mismatch: %08x != %08x\n", + crc, prg->code_crc); + return 1; + } + return 0; +} diff --git a/roms/u-boot/board/gdsys/a38x/hre.h b/roms/u-boot/board/gdsys/a38x/hre.h new file mode 100644 index 000000000..da983aa45 --- /dev/null +++ b/roms/u-boot/board/gdsys/a38x/hre.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2013 + * Reinhard Pfau, Guntermann & Drunck GmbH, reinhard.pfau@gdsys.cc + */ + +#ifndef __HRE_H +#define __HRE_H + +struct key_program { + uint32_t magic; + uint32_t code_crc; + uint32_t code_size; + uint8_t code[]; +}; + +struct h_reg { + bool valid; + uint8_t digest[20]; +}; + +/* CCDM specific contants */ +enum { + /* NV indices */ + NV_COMMON_DATA_INDEX = 0x40000001, + /* magics for key blob chains */ + MAGIC_KEY_PROGRAM = 0x68726500, + MAGIC_HMAC = 0x68616300, + MAGIC_END_OF_CHAIN = 0x00000000, + /* sizes */ + NV_COMMON_DATA_MIN_SIZE = 3 * sizeof(uint64_t) + 2 * sizeof(uint16_t), +}; + +int hre_verify_program(struct key_program *prg); +int hre_run_program(struct udevice *tpm, const uint8_t *code, size_t code_size); + +#endif /* __HRE_H */ diff --git a/roms/u-boot/board/gdsys/a38x/hydra.c b/roms/u-boot/board/gdsys/a38x/hydra.c new file mode 100644 index 000000000..495a97691 --- /dev/null +++ b/roms/u-boot/board/gdsys/a38x/hydra.c @@ -0,0 +1,140 @@ +#include <common.h> +#include <command.h> +#include <console.h> /* ctrlc */ +#include <pci.h> +#include <asm/io.h> + +#include "hydra.h" + +enum { + HWVER_100 = 0, + HWVER_110 = 1, + HWVER_120 = 2, +}; + +static struct pci_device_id hydra_supported[] = { + { 0x6d5e, 0xcdc1 }, + {} +}; + +static struct ihs_fpga *fpga; + +struct ihs_fpga *get_fpga(void) +{ + return fpga; +} + +void print_hydra_version(uint index) +{ + u32 versions = readl(&fpga->versions); + u32 fpga_version = readl(&fpga->fpga_version); + + uint hardware_version = versions & 0xf; + + printf("FPGA%u: mapped to %p\n ", index, fpga); + + switch (hardware_version) { + case HWVER_100: + printf("HW-Ver 1.00\n"); + break; + + case HWVER_110: + printf("HW-Ver 1.10\n"); + break; + + case HWVER_120: + printf("HW-Ver 1.20\n"); + break; + + default: + printf("HW-Ver %d(not supported)\n", + hardware_version); + break; + } + + printf(" FPGA V %d.%02d\n", + fpga_version / 100, fpga_version % 100); +} + +void hydra_initialize(void) +{ + uint i; + pci_dev_t devno; + + /* Find and probe all the matching PCI devices */ + for (i = 0; (devno = pci_find_devices(hydra_supported, i)) >= 0; i++) { + u32 val; + + /* Try to enable I/O accesses and bus-mastering */ + val = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; + pci_write_config_dword(devno, PCI_COMMAND, val); + + /* Make sure it worked */ + pci_read_config_dword(devno, PCI_COMMAND, &val); + if (!(val & PCI_COMMAND_MEMORY)) { + puts("Can't enable I/O memory\n"); + continue; + } + if (!(val & PCI_COMMAND_MASTER)) { + puts("Can't enable bus-mastering\n"); + continue; + } + + /* read FPGA details */ + fpga = pci_map_bar(devno, PCI_BASE_ADDRESS_0, + PCI_REGION_MEM); + + print_hydra_version(i); + } +} + +#define REFL_PATTERN (0xdededede) +#define REFL_PATTERN_INV (~REFL_PATTERN) + +int do_hydrate(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + uint k = 0; + void __iomem *pcie2_base = (void __iomem *)(MVEBU_REG_PCIE_BASE + + 0x4000); + + if (!fpga) + return -1; + + while (1) { + u32 res; + + writel(REFL_PATTERN, &fpga->reflection_low); + res = readl(&fpga->reflection_low); + if (res != REFL_PATTERN_INV) + printf("round %u: read %08x, expected %08x\n", + k, res, REFL_PATTERN_INV); + writel(REFL_PATTERN_INV, &fpga->reflection_low); + res = readl(&fpga->reflection_low); + if (res != REFL_PATTERN) + printf("round %u: read %08x, expected %08x\n", + k, res, REFL_PATTERN); + + res = readl(pcie2_base + 0x118) & 0x1f; + if (res) + printf("FrstErrPtr %u\n", res); + res = readl(pcie2_base + 0x104); + if (res) { + printf("Uncorrectable Error Status 0x%08x\n", res); + writel(res, pcie2_base + 0x104); + } + + if (!(++k % 10000)) + printf("round %u\n", k); + + if (ctrlc()) + break; + } + + return 0; +} + +U_BOOT_CMD( + hydrate, 1, 0, do_hydrate, + "hydra reflection test", + "hydra reflection test" +); diff --git a/roms/u-boot/board/gdsys/a38x/hydra.h b/roms/u-boot/board/gdsys/a38x/hydra.h new file mode 100644 index 000000000..26562a560 --- /dev/null +++ b/roms/u-boot/board/gdsys/a38x/hydra.h @@ -0,0 +1,14 @@ +struct ihs_fpga { + u32 reflection_low; /* 0x0000 */ + u32 versions; /* 0x0004 */ + u32 fpga_version; /* 0x0008 */ + u32 fpga_features; /* 0x000c */ + u32 reserved0[4]; /* 0x0010 */ + u32 control; /* 0x0020 */ + u32 reserved1[375]; /* 0x0024 */ + u32 qsgmii_port_state[80]; /* 0x0600 */ +}; + +void print_hydra_version(uint index); +void hydra_initialize(void); +struct ihs_fpga *get_fpga(void); diff --git a/roms/u-boot/board/gdsys/a38x/ihs_phys.c b/roms/u-boot/board/gdsys/a38x/ihs_phys.c new file mode 100644 index 000000000..c23d15092 --- /dev/null +++ b/roms/u-boot/board/gdsys/a38x/ihs_phys.c @@ -0,0 +1,357 @@ +#include <common.h> +#include <dm.h> +#include <miiphy.h> +#include <asm-generic/gpio.h> +#include <linux/bitops.h> +#include <linux/delay.h> + +#include "ihs_phys.h" +#include "dt_helpers.h" + +enum { + PORTTYPE_MAIN_CAT, + PORTTYPE_TOP_CAT, + PORTTYPE_16C_16F, + PORTTYPE_UNKNOWN +}; + +static struct porttype { + bool phy_invert_in_pol; + bool phy_invert_out_pol; +} porttypes[] = { + { true, false }, + { false, true }, + { false, false }, +}; + +static void ihs_phy_config(struct phy_device *phydev, bool qinpn, bool qoutpn) +{ + u16 reg; + + phy_config(phydev); + + /* enable QSGMII autonegotiation with flow control */ + phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x0004); + reg = phy_read(phydev, MDIO_DEVAD_NONE, 16); + reg |= (3 << 6); + phy_write(phydev, MDIO_DEVAD_NONE, 16, reg); + + /* + * invert QSGMII Q_INP/N and Q_OUTP/N if required + * and perform global reset + */ + reg = phy_read(phydev, MDIO_DEVAD_NONE, 26); + if (qinpn) + reg |= (1 << 13); + if (qoutpn) + reg |= (1 << 12); + reg |= (1 << 15); + phy_write(phydev, MDIO_DEVAD_NONE, 26, reg); + + /* advertise 1000BASE-T full-duplex only */ + phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x0000); + reg = phy_read(phydev, MDIO_DEVAD_NONE, 4); + reg &= ~0x1e0; + phy_write(phydev, MDIO_DEVAD_NONE, 4, reg); + reg = phy_read(phydev, MDIO_DEVAD_NONE, 9); + reg = (reg & ~0x300) | 0x200; + phy_write(phydev, MDIO_DEVAD_NONE, 9, reg); + + /* copper power up */ + reg = phy_read(phydev, MDIO_DEVAD_NONE, 16); + reg &= ~0x0004; + phy_write(phydev, MDIO_DEVAD_NONE, 16, reg); +} + +uint calculate_octo_phy_mask(void) +{ + uint k; + uint octo_phy_mask = 0; + struct gpio_desc gpio = {}; + char gpio_name[64]; + static const char * const dev_name[] = {"pca9698@23", "pca9698@21", + "pca9698@24", "pca9698@25", + "pca9698@26"}; + + /* mark all octo phys that should be present */ + for (k = 0; k < 5; ++k) { + snprintf(gpio_name, 64, "cat-gpio-%u", k); + + if (request_gpio_by_name(&gpio, dev_name[k], 0x20, gpio_name)) + continue; + + /* check CAT flag */ + if (dm_gpio_get_value(&gpio)) + octo_phy_mask |= (1 << (k * 2)); + else + /* If CAT == 0, there's no second octo phy -> skip */ + continue; + + snprintf(gpio_name, 64, "second-octo-gpio-%u", k); + + if (request_gpio_by_name(&gpio, dev_name[k], 0x27, gpio_name)) { + /* default: second octo phy is present */ + octo_phy_mask |= (1 << (k * 2 + 1)); + continue; + } + + if (dm_gpio_get_value(&gpio) == 0) + octo_phy_mask |= (1 << (k * 2 + 1)); + } + + return octo_phy_mask; +} + +int register_miiphy_bus(uint k, struct mii_dev **bus) +{ + int retval; + struct mii_dev *mdiodev = mdio_alloc(); + char *name = bb_miiphy_buses[k].name; + + if (!mdiodev) + return -ENOMEM; + strncpy(mdiodev->name, + name, + MDIO_NAME_LEN); + mdiodev->read = bb_miiphy_read; + mdiodev->write = bb_miiphy_write; + + retval = mdio_register(mdiodev); + if (retval < 0) + return retval; + *bus = miiphy_get_dev_by_name(name); + + return 0; +} + +struct porttype *get_porttype(uint octo_phy_mask, uint k) +{ + uint octo_index = k * 4; + + if (!k) { + if (octo_phy_mask & 0x01) + return &porttypes[PORTTYPE_MAIN_CAT]; + else if (!(octo_phy_mask & 0x03)) + return &porttypes[PORTTYPE_16C_16F]; + } else { + if (octo_phy_mask & (1 << octo_index)) + return &porttypes[PORTTYPE_TOP_CAT]; + } + + return NULL; +} + +int init_single_phy(struct porttype *porttype, struct mii_dev *bus, + uint bus_idx, uint m, uint phy_idx) +{ + struct phy_device *phydev = phy_find_by_mask( + bus, 1 << (m * 8 + phy_idx), + PHY_INTERFACE_MODE_MII); + + printf(" %u", bus_idx * 32 + m * 8 + phy_idx); + + if (!phydev) + puts("!"); + else + ihs_phy_config(phydev, porttype->phy_invert_in_pol, + porttype->phy_invert_out_pol); + + return 0; +} + +int init_octo_phys(uint octo_phy_mask) +{ + uint bus_idx; + + /* there are up to four octo-phys on each mdio bus */ + for (bus_idx = 0; bus_idx < bb_miiphy_buses_num; ++bus_idx) { + uint m; + uint octo_index = bus_idx * 4; + struct mii_dev *bus = NULL; + struct porttype *porttype = NULL; + int ret; + + porttype = get_porttype(octo_phy_mask, bus_idx); + + if (!porttype) + continue; + + for (m = 0; m < 4; ++m) { + uint phy_idx; + + /** + * Register a bus device if there is at least one phy + * on the current bus + */ + if (!m && octo_phy_mask & (0xf << octo_index)) { + ret = register_miiphy_bus(bus_idx, &bus); + if (ret) + return ret; + } + + if (!(octo_phy_mask & BIT(octo_index + m))) + continue; + + for (phy_idx = 0; phy_idx < 8; ++phy_idx) + init_single_phy(porttype, bus, bus_idx, m, + phy_idx); + } + } + + return 0; +} + +/* + * MII GPIO bitbang implementation + * MDC MDIO bus + * 13 14 PHY1-4 + * 25 45 PHY5-8 + * 46 24 PHY9-10 + */ + +struct gpio_mii { + int index; + struct gpio_desc mdc_gpio; + struct gpio_desc mdio_gpio; + int mdc_num; + int mdio_num; + int mdio_value; +} gpio_mii_set[] = { + { 0, {}, {}, 13, 14, 1 }, + { 1, {}, {}, 25, 45, 1 }, + { 2, {}, {}, 46, 24, 1 }, +}; + +static int mii_mdio_init(struct bb_miiphy_bus *bus) +{ + struct gpio_mii *gpio_mii = bus->priv; + char name[32] = {}; + struct udevice *gpio_dev1 = NULL; + struct udevice *gpio_dev2 = NULL; + + if (uclass_get_device_by_name(UCLASS_GPIO, "gpio@18100", &gpio_dev1) || + uclass_get_device_by_name(UCLASS_GPIO, "gpio@18140", &gpio_dev2)) { + printf("Could not get GPIO device.\n"); + return 1; + } + + if (gpio_mii->mdc_num > 31) { + gpio_mii->mdc_gpio.dev = gpio_dev2; + gpio_mii->mdc_gpio.offset = gpio_mii->mdc_num - 32; + } else { + gpio_mii->mdc_gpio.dev = gpio_dev1; + gpio_mii->mdc_gpio.offset = gpio_mii->mdc_num; + } + gpio_mii->mdc_gpio.flags = 0; + snprintf(name, 32, "bb_miiphy_bus-%d-mdc", gpio_mii->index); + dm_gpio_request(&gpio_mii->mdc_gpio, name); + + if (gpio_mii->mdio_num > 31) { + gpio_mii->mdio_gpio.dev = gpio_dev2; + gpio_mii->mdio_gpio.offset = gpio_mii->mdio_num - 32; + } else { + gpio_mii->mdio_gpio.dev = gpio_dev1; + gpio_mii->mdio_gpio.offset = gpio_mii->mdio_num; + } + gpio_mii->mdio_gpio.flags = 0; + snprintf(name, 32, "bb_miiphy_bus-%d-mdio", gpio_mii->index); + dm_gpio_request(&gpio_mii->mdio_gpio, name); + + dm_gpio_set_dir_flags(&gpio_mii->mdc_gpio, GPIOD_IS_OUT); + dm_gpio_set_value(&gpio_mii->mdc_gpio, 1); + + return 0; +} + +static int mii_mdio_active(struct bb_miiphy_bus *bus) +{ + struct gpio_mii *gpio_mii = bus->priv; + + dm_gpio_set_value(&gpio_mii->mdc_gpio, gpio_mii->mdio_value); + + return 0; +} + +static int mii_mdio_tristate(struct bb_miiphy_bus *bus) +{ + struct gpio_mii *gpio_mii = bus->priv; + + dm_gpio_set_dir_flags(&gpio_mii->mdio_gpio, GPIOD_IS_IN); + + return 0; +} + +static int mii_set_mdio(struct bb_miiphy_bus *bus, int v) +{ + struct gpio_mii *gpio_mii = bus->priv; + + dm_gpio_set_dir_flags(&gpio_mii->mdio_gpio, GPIOD_IS_OUT); + dm_gpio_set_value(&gpio_mii->mdio_gpio, v); + gpio_mii->mdio_value = v; + + return 0; +} + +static int mii_get_mdio(struct bb_miiphy_bus *bus, int *v) +{ + struct gpio_mii *gpio_mii = bus->priv; + + dm_gpio_set_dir_flags(&gpio_mii->mdio_gpio, GPIOD_IS_IN); + *v = (dm_gpio_get_value(&gpio_mii->mdio_gpio)); + + return 0; +} + +static int mii_set_mdc(struct bb_miiphy_bus *bus, int v) +{ + struct gpio_mii *gpio_mii = bus->priv; + + dm_gpio_set_value(&gpio_mii->mdc_gpio, v); + + return 0; +} + +static int mii_delay(struct bb_miiphy_bus *bus) +{ + udelay(1); + + return 0; +} + +struct bb_miiphy_bus bb_miiphy_buses[] = { + { + .name = "ihs0", + .init = mii_mdio_init, + .mdio_active = mii_mdio_active, + .mdio_tristate = mii_mdio_tristate, + .set_mdio = mii_set_mdio, + .get_mdio = mii_get_mdio, + .set_mdc = mii_set_mdc, + .delay = mii_delay, + .priv = &gpio_mii_set[0], + }, + { + .name = "ihs1", + .init = mii_mdio_init, + .mdio_active = mii_mdio_active, + .mdio_tristate = mii_mdio_tristate, + .set_mdio = mii_set_mdio, + .get_mdio = mii_get_mdio, + .set_mdc = mii_set_mdc, + .delay = mii_delay, + .priv = &gpio_mii_set[1], + }, + { + .name = "ihs2", + .init = mii_mdio_init, + .mdio_active = mii_mdio_active, + .mdio_tristate = mii_mdio_tristate, + .set_mdio = mii_set_mdio, + .get_mdio = mii_get_mdio, + .set_mdc = mii_set_mdc, + .delay = mii_delay, + .priv = &gpio_mii_set[2], + }, +}; + +int bb_miiphy_buses_num = ARRAY_SIZE(bb_miiphy_buses); diff --git a/roms/u-boot/board/gdsys/a38x/ihs_phys.h b/roms/u-boot/board/gdsys/a38x/ihs_phys.h new file mode 100644 index 000000000..c4bec4d46 --- /dev/null +++ b/roms/u-boot/board/gdsys/a38x/ihs_phys.h @@ -0,0 +1,2 @@ +uint calculate_octo_phy_mask(void); +int init_octo_phys(uint octo_phy_mask); diff --git a/roms/u-boot/board/gdsys/a38x/keyprogram.c b/roms/u-boot/board/gdsys/a38x/keyprogram.c new file mode 100644 index 000000000..7020fae18 --- /dev/null +++ b/roms/u-boot/board/gdsys/a38x/keyprogram.c @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2016 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + */ + +#include <common.h> +#include <command.h> +#include <env.h> +#include <tpm-v1.h> +#include <malloc.h> +#include <linux/ctype.h> +#include <asm/unaligned.h> + +#include "hre.h" + +int flush_keys(struct udevice *tpm) +{ + u16 key_count; + u8 buf[288]; + u8 *ptr; + u32 err; + uint i; + + /* fetch list of already loaded keys in the TPM */ + err = tpm1_get_capability(tpm, TPM_CAP_HANDLE, TPM_RT_KEY, buf, + sizeof(buf)); + if (err) + return -1; + key_count = get_unaligned_be16(buf); + ptr = buf + 2; + for (i = 0; i < key_count; ++i, ptr += 4) { + err = tpm1_flush_specific(tpm, get_unaligned_be32(ptr), + TPM_RT_KEY); + if (err && err != TPM_KEY_OWNER_CONTROL) + return err; + } + + return 0; +} + +int decode_hexstr(char *hexstr, u8 **result) +{ + int len = strlen(hexstr); + int bytes = len / 2; + int i; + u8 acc = 0; + + if (len % 2 == 1) + return 1; + + *result = (u8 *)malloc(bytes); + + for (i = 0; i < len; i++) { + char cur = tolower(hexstr[i]); + u8 val; + + if ((cur >= 'a' && cur <= 'f') || (cur >= '0' && cur <= '9')) { + val = cur - (cur > '9' ? 87 : 48); + + if (i % 2 == 0) + acc = 16 * val; + else + (*result)[i / 2] = acc + val; + } else { + free(*result); + return 1; + } + } + + return 0; +} + +int extract_subprogram(u8 **progdata, u32 expected_magic, + struct key_program **result) +{ + struct key_program *prog = *result; + u32 magic, code_crc, code_size; + + magic = get_unaligned_be32(*progdata); + code_crc = get_unaligned_be32(*progdata + 4); + code_size = get_unaligned_be32(*progdata + 8); + + *progdata += 12; + + if (magic != expected_magic) + return -1; + + *result = malloc(sizeof(struct key_program) + code_size); + + if (!*result) + return -1; + + prog->magic = magic; + prog->code_crc = code_crc; + prog->code_size = code_size; + memcpy(prog->code, *progdata, code_size); + + *progdata += code_size; + + if (hre_verify_program(prog)) { + free(prog); + return -1; + } + + return 0; +} + +struct key_program *parse_and_check_keyprog(u8 *progdata) +{ + struct key_program *result = NULL, *hmac = NULL; + + /* Part 1: Load key program */ + + if (extract_subprogram(&progdata, MAGIC_KEY_PROGRAM, &result)) + return NULL; + + /* Part 2: Load hmac program */ + + if (extract_subprogram(&progdata, MAGIC_HMAC, &hmac)) + return NULL; + + free(hmac); + + return result; +} + +int load_and_run_keyprog(struct udevice *tpm) +{ + char *cmd = NULL; + u8 *binprog = NULL; + char *hexprog; + struct key_program *prog; + + cmd = env_get("loadkeyprogram"); + + if (!cmd || run_command(cmd, 0)) + return 1; + + hexprog = env_get("keyprogram"); + + if (decode_hexstr(hexprog, &binprog)) + return 1; + + prog = parse_and_check_keyprog(binprog); + free(binprog); + + if (!prog) + return 1; + + if (hre_run_program(tpm, prog->code, prog->code_size)) { + free(prog); + return 1; + } + + printf("\nSD code ran successfully\n"); + + free(prog); + + return 0; +} diff --git a/roms/u-boot/board/gdsys/a38x/keyprogram.h b/roms/u-boot/board/gdsys/a38x/keyprogram.h new file mode 100644 index 000000000..06889c67e --- /dev/null +++ b/roms/u-boot/board/gdsys/a38x/keyprogram.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2016 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + */ + +#ifndef __KEYPROGRAM_H +#define __KEYPROGRAM_H + +int load_and_run_keyprog(struct udevice *tpm); +int flush_keys(struct udevice *tpm); + +#endif /* __KEYPROGRAM_H */ diff --git a/roms/u-boot/board/gdsys/a38x/spl.c b/roms/u-boot/board/gdsys/a38x/spl.c new file mode 100644 index 000000000..84864d197 --- /dev/null +++ b/roms/u-boot/board/gdsys/a38x/spl.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2016 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + */ + +#include <common.h> +#include <config.h> +#include <asm/arch/cpu.h> + +void spl_board_init(void) +{ +#if CONFIG_SPL_BOOT_DEVICE == SPL_BOOT_SPI_NOR_FLASH + u32 *bootrom_save = (u32 *)CONFIG_SPL_BOOTROM_SAVE; + u32 *regs = (u32 *)(*bootrom_save); + + printf("Returning to BootROM (return address %08x)...\n", regs[13]); + return_to_bootrom(); +#endif +} diff --git a/roms/u-boot/board/gdsys/common/Makefile b/roms/u-boot/board/gdsys/common/Makefile new file mode 100644 index 000000000..dd6d5e69d --- /dev/null +++ b/roms/u-boot/board/gdsys/common/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2007 +# Stefan Roese, DENX Software Engineering, sr@denx.de. + +obj-$(CONFIG_SYS_FPGA_COMMON) += fpga.o +obj-$(CONFIG_CMD_IOLOOP) += cmd_ioloop.o +obj-$(CONFIG_CONTROLCENTERD) += dp501.o +obj-$(CONFIG_TARGET_GAZERBEAM) += osd.o ihs_mdio.o ioep-fpga.o + +ifdef CONFIG_OSD +obj-$(CONFIG_GDSYS_LEGACY_OSD_CMDS) += osd_cmd.o +endif diff --git a/roms/u-boot/board/gdsys/common/cmd_ioloop.c b/roms/u-boot/board/gdsys/common/cmd_ioloop.c new file mode 100644 index 000000000..658756d98 --- /dev/null +++ b/roms/u-boot/board/gdsys/common/cmd_ioloop.c @@ -0,0 +1,585 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2014 + * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc + */ + +#include <common.h> +#include <command.h> +#include <console.h> +#include <linux/bitops.h> +#include <linux/delay.h> + +#include <gdsys_fpga.h> + +#ifndef CONFIG_GDSYS_LEGACY_DRIVERS +#include <dm.h> +#include <misc.h> +#include <regmap.h> +#include <sysinfo.h> + +#include "../../../drivers/misc/gdsys_soc.h" +#include "../../../drivers/misc/gdsys_ioep.h" +#include "../../../drivers/misc/ihs_fpga.h" + +const int HEADER_WORDS = sizeof(struct io_generic_packet) / 2; +#endif /* !CONFIG_GDSYS_LEGACY_DRIVERS */ + +enum status_print_type { + STATUS_LOUD = 0, + STATUS_SILENT = 1, +}; + +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS +enum { + STATE_TX_PACKET_BUILDING = BIT(0), + STATE_TX_TRANSMITTING = BIT(1), + STATE_TX_BUFFER_FULL = BIT(2), + STATE_TX_ERR = BIT(3), + STATE_RECEIVE_TIMEOUT = BIT(4), + STATE_PROC_RX_STORE_TIMEOUT = BIT(5), + STATE_PROC_RX_RECEIVE_TIMEOUT = BIT(6), + STATE_RX_DIST_ERR = BIT(7), + STATE_RX_LENGTH_ERR = BIT(8), + STATE_RX_FRAME_CTR_ERR = BIT(9), + STATE_RX_FCS_ERR = BIT(10), + STATE_RX_PACKET_DROPPED = BIT(11), + STATE_RX_DATA_LAST = BIT(12), + STATE_RX_DATA_FIRST = BIT(13), + STATE_RX_DATA_AVAILABLE = BIT(15), +}; + +enum { + IRQ_CPU_TRANSMITBUFFER_FREE_STATUS = BIT(5), + IRQ_CPU_PACKET_TRANSMITTED_EVENT = BIT(6), + IRQ_NEW_CPU_PACKET_RECEIVED_EVENT = BIT(7), + IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS = BIT(8), +}; + +enum { + CTRL_PROC_RECEIVE_ENABLE = BIT(12), + CTRL_FLUSH_TRANSMIT_BUFFER = BIT(15), +}; + +struct io_generic_packet { + u16 target_address; + u16 source_address; + u8 packet_type; + u8 bc; + u16 packet_length; +} __attribute__((__packed__)); +#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */ + +unsigned long long rx_ctr; +unsigned long long tx_ctr; +unsigned long long err_ctr; +#ifndef CONFIG_GDSYS_LEGACY_DRIVERS +struct udevice *dev; +#endif /* !CONFIG_GDSYS_LEGACY_DRIVERS */ + +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS +static void io_check_status(uint fpga, u16 status, enum status_print_type type) +{ + u16 mask = STATE_RX_DIST_ERR | STATE_RX_LENGTH_ERR | + STATE_RX_FRAME_CTR_ERR | STATE_RX_FCS_ERR | + STATE_RX_PACKET_DROPPED | STATE_TX_ERR; + + if (!(status & mask)) { + FPGA_SET_REG(fpga, ep.rx_tx_status, status); + return; + } + + err_ctr++; + FPGA_SET_REG(fpga, ep.rx_tx_status, status); + + if (type == STATUS_SILENT) + return; + + if (status & STATE_RX_PACKET_DROPPED) + printf("RX_PACKET_DROPPED, status %04x\n", status); + + if (status & STATE_RX_DIST_ERR) + printf("RX_DIST_ERR\n"); + if (status & STATE_RX_LENGTH_ERR) + printf("RX_LENGTH_ERR\n"); + if (status & STATE_RX_FRAME_CTR_ERR) + printf("RX_FRAME_CTR_ERR\n"); + if (status & STATE_RX_FCS_ERR) + printf("RX_FCS_ERR\n"); + + if (status & STATE_TX_ERR) + printf("TX_ERR\n"); +} +#else +static void io_check_status(struct udevice *dev, enum status_print_type type) +{ + u16 status = 0; + int ret; + + ret = misc_call(dev, 0, NULL, 0, &status, 0); + if (!ret) + return; + + err_ctr++; + + if (type != STATUS_LOUD) + return; + + if (status & STATE_RX_PACKET_DROPPED) + printf("RX_PACKET_DROPPED, status %04x\n", status); + + if (status & STATE_RX_DIST_ERR) + printf("RX_DIST_ERR\n"); + if (status & STATE_RX_LENGTH_ERR) + printf("RX_LENGTH_ERR\n"); + if (status & STATE_RX_FRAME_CTR_ERR) + printf("RX_FRAME_CTR_ERR\n"); + if (status & STATE_RX_FCS_ERR) + printf("RX_FCS_ERR\n"); + + if (status & STATE_TX_ERR) + printf("TX_ERR\n"); +} +#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */ + +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS +static void io_send(uint fpga, uint size) +{ + uint k; + struct io_generic_packet packet = { + .source_address = 1, + .packet_type = 1, + .packet_length = size, + }; + u16 *p = (u16 *)&packet; + + for (k = 0; k < sizeof(packet) / 2; ++k) + FPGA_SET_REG(fpga, ep.transmit_data, *p++); + + for (k = 0; k < (size + 1) / 2; ++k) + FPGA_SET_REG(fpga, ep.transmit_data, k); + + FPGA_SET_REG(fpga, ep.rx_tx_control, + CTRL_PROC_RECEIVE_ENABLE | CTRL_FLUSH_TRANSMIT_BUFFER); + + tx_ctr++; +} +#else +static void io_send(struct udevice *dev, uint size) +{ + uint k; + u16 buffer[HEADER_WORDS + 128]; + struct io_generic_packet header = { + .source_address = 1, + .packet_type = 1, + .packet_length = size, + }; + const uint words = (size + 1) / 2; + + memcpy(buffer, &header, 2 * HEADER_WORDS); + for (k = 0; k < words; ++k) + buffer[k + HEADER_WORDS] = (2 * k + 1) + ((2 * k) << 8); + + misc_write(dev, 0, buffer, HEADER_WORDS + words); + + tx_ctr++; +} +#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */ + +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS +static void io_receive(uint fpga) +{ + u16 rx_tx_status; + + FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status); + + while (rx_tx_status & STATE_RX_DATA_AVAILABLE) { + u16 rx; + + if (rx_tx_status & STATE_RX_DATA_LAST) + rx_ctr++; + + FPGA_GET_REG(fpga, ep.receive_data, &rx); + + FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status); + } +} +#else +static void io_receive(struct udevice *dev) +{ + u16 buffer[HEADER_WORDS + 128]; + + if (!misc_read(dev, 0, buffer, 0)) + rx_ctr++; +} +#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */ + +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS +static void io_reflect(uint fpga) +{ + u16 buffer[128]; + + uint k = 0; + uint n; + u16 rx_tx_status; + + FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status); + + while (rx_tx_status & STATE_RX_DATA_AVAILABLE) { + FPGA_GET_REG(fpga, ep.receive_data, &buffer[k++]); + if (rx_tx_status & STATE_RX_DATA_LAST) + break; + + FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status); + } + + if (!k) + return; + + for (n = 0; n < k; ++n) + FPGA_SET_REG(fpga, ep.transmit_data, buffer[n]); + + FPGA_SET_REG(fpga, ep.rx_tx_control, + CTRL_PROC_RECEIVE_ENABLE | CTRL_FLUSH_TRANSMIT_BUFFER); + + tx_ctr++; +} +#else +static void io_reflect(struct udevice *dev) +{ + u16 buffer[HEADER_WORDS + 128]; + struct io_generic_packet *header; + + if (misc_read(dev, 0, buffer, 0)) + return; + + header = (struct io_generic_packet *)&buffer; + + misc_write(dev, 0, buffer, HEADER_WORDS + header->packet_length); +} +#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */ + +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS +/* + * FPGA io-endpoint reflector + * + * Syntax: + * ioreflect {fpga} {reportrate} + */ +int do_ioreflect(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + uint fpga; + uint rate = 0; + unsigned long long last_seen = 0; + + if (argc < 2) + return CMD_RET_USAGE; + + fpga = simple_strtoul(argv[1], NULL, 10); + + /* + * If another parameter, it is the report rate in packets. + */ + if (argc > 2) + rate = simple_strtoul(argv[2], NULL, 10); + + /* Enable receive path */ + FPGA_SET_REG(fpga, ep.rx_tx_control, CTRL_PROC_RECEIVE_ENABLE); + + /* Set device address to dummy 1*/ + FPGA_SET_REG(fpga, ep.device_address, 1); + + rx_ctr = 0; tx_ctr = 0; err_ctr = 0; + + while (1) { + u16 top_int; + u16 rx_tx_status; + + FPGA_GET_REG(fpga, top_interrupt, &top_int); + FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status); + + io_check_status(fpga, rx_tx_status, STATUS_SILENT); + if ((top_int & IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS) && + (top_int & IRQ_CPU_TRANSMITBUFFER_FREE_STATUS)) + io_reflect(fpga); + + if (rate) { + if (!(tx_ctr % rate) && (tx_ctr != last_seen)) + printf("refl %llu, err %llu\n", tx_ctr, + err_ctr); + last_seen = tx_ctr; + } + + if (ctrlc()) + break; + } + + return 0; +} +#else +/* + * FPGA io-endpoint reflector + * + * Syntax: + * ioreflect {reportrate} + */ +int do_ioreflect(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + struct udevice *fpga; + struct regmap *map; + uint rate = 0; + unsigned long long last_seen = 0; + + if (!dev) { + printf("No device selected\n"); + return 1; + } + + gdsys_soc_get_fpga(dev, &fpga); + regmap_init_mem(dev_ofnode(dev), &map); + + /* Enable receive path */ + misc_set_enabled(dev, true); + + rx_ctr = 0; tx_ctr = 0; err_ctr = 0; + + while (1) { + uint top_int; + + ihs_fpga_get(map, top_interrupt, &top_int); + io_check_status(dev, STATUS_SILENT); + if ((top_int & IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS) && + (top_int & IRQ_CPU_TRANSMITBUFFER_FREE_STATUS)) + io_reflect(dev); + + if (rate) { + if (!(tx_ctr % rate) && (tx_ctr != last_seen)) + printf("refl %llu, err %llu\n", tx_ctr, + err_ctr); + last_seen = tx_ctr; + } + + if (ctrlc()) + break; + } + + return 0; +} +#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */ + +#define DISP_LINE_LEN 16 + +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS +/* + * FPGA io-endpoint looptest + * + * Syntax: + * ioloop {fpga} {size} {rate} + */ +int do_ioloop(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + uint fpga; + uint size; + uint rate = 0; + + if (argc < 3) + return CMD_RET_USAGE; + + /* + * FPGA is specified since argc > 2 + */ + fpga = simple_strtoul(argv[1], NULL, 10); + + /* + * packet size is specified since argc > 2 + */ + size = simple_strtoul(argv[2], NULL, 10); + + /* + * If another parameter, it is the test rate in packets per second. + */ + if (argc > 3) + rate = simple_strtoul(argv[3], NULL, 10); + + /* enable receive path */ + FPGA_SET_REG(fpga, ep.rx_tx_control, CTRL_PROC_RECEIVE_ENABLE); + + /* set device address to dummy 1*/ + FPGA_SET_REG(fpga, ep.device_address, 1); + + rx_ctr = 0; tx_ctr = 0; err_ctr = 0; + + while (1) { + u16 top_int; + u16 rx_tx_status; + + FPGA_GET_REG(fpga, top_interrupt, &top_int); + FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status); + + io_check_status(fpga, rx_tx_status, STATUS_LOUD); + if (top_int & IRQ_CPU_TRANSMITBUFFER_FREE_STATUS) + io_send(fpga, size); + if (top_int & IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS) + io_receive(fpga); + + if (rate) { + if (ctrlc()) + break; + udelay(1000000 / rate); + if (!(tx_ctr % rate)) + printf("d %llu, tx %llu, rx %llu, err %llu\n", + tx_ctr - rx_ctr, tx_ctr, rx_ctr, + err_ctr); + } + } + + return 0; +} +#else +/* + * FPGA io-endpoint looptest + * + * Syntax: + * ioloop {size} {rate} + */ +int do_ioloop(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + uint size; + uint rate = 0; + struct udevice *fpga; + struct regmap *map; + + if (!dev) { + printf("No device selected\n"); + return 1; + } + + gdsys_soc_get_fpga(dev, &fpga); + regmap_init_mem(dev_ofnode(dev), &map); + + if (argc < 2) + return CMD_RET_USAGE; + + /* + * packet size is specified since argc > 1 + */ + size = simple_strtoul(argv[2], NULL, 10); + + /* + * If another parameter, it is the test rate in packets per second. + */ + if (argc > 2) + rate = simple_strtoul(argv[3], NULL, 10); + + /* Enable receive path */ + misc_set_enabled(dev, true); + + rx_ctr = 0; tx_ctr = 0; err_ctr = 0; + + while (1) { + uint top_int; + + if (ctrlc()) + break; + + ihs_fpga_get(map, top_interrupt, &top_int); + + io_check_status(dev, STATUS_LOUD); + if (top_int & IRQ_CPU_TRANSMITBUFFER_FREE_STATUS) + io_send(dev, size); + if (top_int & IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS) + io_receive(dev); + + if (rate) { + udelay(1000000 / rate); + if (!(tx_ctr % rate)) + printf("d %llu, tx %llu, rx %llu, err %llu\n", + tx_ctr - rx_ctr, tx_ctr, rx_ctr, + err_ctr); + } + } + return 0; +} +#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */ + +#ifndef CONFIG_GDSYS_LEGACY_DRIVERS +int do_iodev(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + struct udevice *ioep = NULL; + struct udevice *sysinfo; + char name[8]; + int ret; + + if (sysinfo_get(&sysinfo)) + return CMD_RET_FAILURE; + + if (argc > 1) { + int i = simple_strtoul(argv[1], NULL, 10); + + snprintf(name, sizeof(name), "ioep%d", i); + + ret = uclass_get_device_by_phandle(UCLASS_MISC, sysinfo, name, + &ioep); + + if (ret || !ioep) { + printf("Invalid IOEP %d\n", i); + return CMD_RET_FAILURE; + } + + dev = ioep; + } else { + int i = 0; + + while (1) { + snprintf(name, sizeof(name), "ioep%d", i); + + ret = uclass_get_device_by_phandle(UCLASS_MISC, sysinfo, + name, &ioep); + + if (ret || !ioep) + break; + + printf("IOEP %d:\t%s\n", i++, ioep->name); + } + + if (dev) + printf("\nSelected IOEP: %s\n", dev->name); + else + puts("\nNo IOEP selected.\n"); + } + + return 0; +} +#endif /* !CONFIG_GDSYS_LEGACY_DRIVERS */ + +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS +U_BOOT_CMD( + ioloop, 4, 0, do_ioloop, + "fpga io-endpoint looptest", + "fpga packetsize [packets/sec]" +); + +U_BOOT_CMD( + ioreflect, 3, 0, do_ioreflect, + "fpga io-endpoint reflector", + "fpga reportrate" +); +#else +U_BOOT_CMD( + ioloop, 3, 0, do_ioloop, + "fpga io-endpoint looptest", + "packetsize [packets/sec]" +); + +U_BOOT_CMD( + ioreflect, 2, 0, do_ioreflect, + "fpga io-endpoint reflector", + "reportrate" +); + +U_BOOT_CMD( + iodev, 2, 0, do_iodev, + "fpga io-endpoint listing/selection", + "[ioep device to select]" +); +#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */ diff --git a/roms/u-boot/board/gdsys/common/dp501.c b/roms/u-boot/board/gdsys/common/dp501.c new file mode 100644 index 000000000..9ca69ebcb --- /dev/null +++ b/roms/u-boot/board/gdsys/common/dp501.c @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2012 + * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc + */ + +/* Parade Technologies Inc. DP501 DisplayPort DVI/HDMI Transmitter */ + +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS + +#include <common.h> +#include <asm/io.h> +#include <errno.h> +#include <i2c.h> + +#define DP501_I2C_ADDR 0x08 + +#ifdef CONFIG_SYS_DP501_I2C +int dp501_i2c[] = CONFIG_SYS_DP501_I2C; +#endif + +#ifdef CONFIG_SYS_DP501_BASE +int dp501_base[] = CONFIG_SYS_DP501_BASE; +#endif + +static void dp501_setbits(u8 addr, u8 reg, u8 mask) +{ + u8 val; + + val = i2c_reg_read(addr, reg); + setbits_8(&val, mask); + i2c_reg_write(addr, reg, val); +} + +static void dp501_clrbits(u8 addr, u8 reg, u8 mask) +{ + u8 val; + + val = i2c_reg_read(addr, reg); + clrbits_8(&val, mask); + i2c_reg_write(addr, reg, val); +} + +static int dp501_detect_cable_adapter(u8 addr) +{ + u8 val = i2c_reg_read(addr, 0x00); + + return !(val & 0x04); +} + +static void dp501_link_training(u8 addr) +{ + u8 val; + u8 link_bw; + u8 max_lane_cnt; + u8 lane_cnt; + + val = i2c_reg_read(addr, 0x51); + if (val >= 0x0a) + link_bw = 0x0a; + else + link_bw = 0x06; + if (link_bw != val) + printf("DP sink supports %d Mbps link rate, set to %d Mbps\n", + val * 270, link_bw * 270); + i2c_reg_write(addr, 0x5d, link_bw); /* set link_bw */ + val = i2c_reg_read(addr, 0x52); + max_lane_cnt = val & 0x1f; + if (max_lane_cnt >= 4) + lane_cnt = 4; + else + lane_cnt = max_lane_cnt; + if (lane_cnt != max_lane_cnt) + printf("DP sink supports %d lanes, set to %d lanes\n", + max_lane_cnt, lane_cnt); + i2c_reg_write(addr, 0x5e, lane_cnt | (val & 0x80)); /* set lane_cnt */ + val = i2c_reg_read(addr, 0x53); + i2c_reg_write(addr, 0x5c, val); /* set downspread_ctl */ + + i2c_reg_write(addr, 0x5f, 0x0d); /* start training */ +} + +void dp501_powerup(u8 addr) +{ + dp501_clrbits(addr, 0x0a, 0x30); /* power on encoder */ + dp501_setbits(addr, 0x0a, 0x0e); /* block HDCP and MCCS on I2C bride*/ + i2c_reg_write(addr, 0x27, 0x30); /* Hardware auto detect DVO timing */ + dp501_setbits(addr, 0x72, 0x80); /* DPCD read enable */ + dp501_setbits(addr, 0x30, 0x20); /* RS polynomial select */ + i2c_reg_write(addr, 0x71, 0x20); /* Enable Aux burst write */ + dp501_setbits(addr, 0x78, 0x30); /* Disable HPD2 IRQ */ + dp501_clrbits(addr, 0x2f, 0x40); /* Link FIFO reset selection */ + dp501_clrbits(addr, 0x60, 0x20); /* Enable scrambling */ + +#ifdef CONFIG_SYS_DP501_VCAPCTRL0 + i2c_reg_write(addr, 0x24, CONFIG_SYS_DP501_VCAPCTRL0); +#else + i2c_reg_write(addr, 0x24, 0xc0); /* SDR mode 0, ext. H/VSYNC */ +#endif + +#ifdef CONFIG_SYS_DP501_DIFFERENTIAL + i2c_reg_write(addr + 2, 0x24, 0x10); /* clock input differential */ + i2c_reg_write(addr + 2, 0x25, 0x04); + i2c_reg_write(addr + 2, 0x26, 0x10); +#else + i2c_reg_write(addr + 2, 0x24, 0x02); /* clock input single ended */ +#endif + + i2c_reg_write(addr + 2, 0x1a, 0x04); /* SPDIF input method TTL */ + + i2c_reg_write(addr + 2, 0x00, 0x18); /* driving strength */ + i2c_reg_write(addr + 2, 0x03, 0x06); /* driving strength */ + i2c_reg_write(addr, 0x2c, 0x00); /* configure N value */ + i2c_reg_write(addr, 0x2d, 0x00); /* configure N value */ + i2c_reg_write(addr, 0x2e, 0x0c); /* configure N value */ + i2c_reg_write(addr, 0x76, 0xff); /* clear all interrupt */ + dp501_setbits(addr, 0x78, 0x03); /* clear all interrupt */ + i2c_reg_write(addr, 0x75, 0xf8); /* aux channel reset */ + i2c_reg_write(addr, 0x75, 0x00); /* clear aux channel reset */ + i2c_reg_write(addr, 0x87, 0x7f); /* set retry counter as 7 + retry interval 400us */ + + if (dp501_detect_cable_adapter(addr)) { + printf("DVI/HDMI cable adapter detected\n"); + i2c_reg_write(addr, 0x5e, 0x04); /* enable 4 channel */ + dp501_clrbits(addr, 0x00, 0x08); /* DVI/HDMI HDCP operation */ + } else { + printf("no DVI/HDMI cable adapter detected\n"); + dp501_setbits(addr, 0x00, 0x08); /* for DP HDCP operation */ + + dp501_link_training(addr); + } +} + +void dp501_powerdown(u8 addr) +{ + dp501_setbits(addr, 0x0a, 0x30); /* power down encoder, standby mode */ +} + + +int dp501_probe(unsigned screen, bool power) +{ +#ifdef CONFIG_SYS_DP501_BASE + uint8_t dp501_addr = dp501_base[screen]; +#else + uint8_t dp501_addr = DP501_I2C_ADDR; +#endif + +#ifdef CONFIG_SYS_DP501_I2C + i2c_set_bus_num(dp501_i2c[screen]); +#endif + + if (i2c_probe(dp501_addr)) + return -1; + + dp501_powerup(dp501_addr); + + return 0; +} + +#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */ diff --git a/roms/u-boot/board/gdsys/common/dp501.h b/roms/u-boot/board/gdsys/common/dp501.h new file mode 100644 index 000000000..b98b54edc --- /dev/null +++ b/roms/u-boot/board/gdsys/common/dp501.h @@ -0,0 +1,31 @@ +/* + * (C) Copyright 2012 + * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _DP501_H_ +#define _DP501_H_ + +void dp501_powerup(u8 addr); +void dp501_powerdown(u8 addr); +int dp501_probe(unsigned screen, bool power); + +#endif diff --git a/roms/u-boot/board/gdsys/common/fpga.c b/roms/u-boot/board/gdsys/common/fpga.c new file mode 100644 index 000000000..5ba6613ed --- /dev/null +++ b/roms/u-boot/board/gdsys/common/fpga.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2013 + * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc + */ + +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS + +#include <common.h> +#include <gdsys_fpga.h> + +#include <asm/io.h> + +int fpga_set_reg(u32 fpga, u16 *reg, off_t regoff, u16 data) +{ + out_le16(reg, data); + + return 0; +} + +int fpga_get_reg(u32 fpga, u16 *reg, off_t regoff, u16 *data) +{ + *data = in_le16(reg); + + return 0; +} + +#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */ diff --git a/roms/u-boot/board/gdsys/common/ihs_mdio.c b/roms/u-boot/board/gdsys/common/ihs_mdio.c new file mode 100644 index 000000000..5f1215e9e --- /dev/null +++ b/roms/u-boot/board/gdsys/common/ihs_mdio.c @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2014 + * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc + */ + +#include <common.h> +#include <linux/delay.h> + +#include <miiphy.h> +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS +#include <gdsys_fpga.h> +#else +#include <fdtdec.h> +#include <dm.h> +#include <regmap.h> +#endif + +#include "ihs_mdio.h" + +#ifndef CONFIG_GDSYS_LEGACY_DRIVERS +enum { + REG_MDIO_CONTROL = 0x0, + REG_MDIO_ADDR_DATA = 0x2, + REG_MDIO_RX_DATA = 0x4, +}; + +static inline u16 read_reg(struct udevice *fpga, uint base, uint addr) +{ + struct regmap *map; + u8 *ptr; + + regmap_init_mem(dev_ofnode(fpga), &map); + ptr = regmap_get_range(map, 0); + + return in_le16((u16 *)(ptr + base + addr)); +} + +static inline void write_reg(struct udevice *fpga, uint base, uint addr, + u16 val) +{ + struct regmap *map; + u8 *ptr; + + regmap_init_mem(dev_ofnode(fpga), &map); + ptr = regmap_get_range(map, 0); + + out_le16((u16 *)(ptr + base + addr), val); +} +#endif + +static inline u16 read_control(struct ihs_mdio_info *info) +{ + u16 val; +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS + FPGA_GET_REG(info->fpga, mdio.control, &val); +#else + val = read_reg(info->fpga, info->base, REG_MDIO_CONTROL); +#endif + return val; +} + +static inline void write_control(struct ihs_mdio_info *info, u16 val) +{ +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS + FPGA_SET_REG(info->fpga, mdio.control, val); +#else + write_reg(info->fpga, info->base, REG_MDIO_CONTROL, val); +#endif +} + +static inline void write_addr_data(struct ihs_mdio_info *info, u16 val) +{ +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS + FPGA_SET_REG(info->fpga, mdio.address_data, val); +#else + write_reg(info->fpga, info->base, REG_MDIO_ADDR_DATA, val); +#endif +} + +static inline u16 read_rx_data(struct ihs_mdio_info *info) +{ + u16 val; +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS + FPGA_GET_REG(info->fpga, mdio.rx_data, &val); +#else + val = read_reg(info->fpga, info->base, REG_MDIO_RX_DATA); +#endif + return val; +} + +static int ihs_mdio_idle(struct mii_dev *bus) +{ + struct ihs_mdio_info *info = bus->priv; + u16 val; + unsigned int ctr = 0; + + do { + val = read_control(info); + udelay(100); + if (ctr++ > 10) + return -1; + } while (!(val & (1 << 12))); + + return 0; +} + +static int ihs_mdio_reset(struct mii_dev *bus) +{ + ihs_mdio_idle(bus); + + return 0; +} + +static int ihs_mdio_read(struct mii_dev *bus, int addr, int dev_addr, + int regnum) +{ + struct ihs_mdio_info *info = bus->priv; + u16 val; + + ihs_mdio_idle(bus); + + write_control(info, + ((addr & 0x1f) << 5) | (regnum & 0x1f) | (2 << 10)); + + /* wait for rx data available */ + udelay(100); + + val = read_rx_data(info); + + return val; +} + +static int ihs_mdio_write(struct mii_dev *bus, int addr, int dev_addr, + int regnum, u16 value) +{ + struct ihs_mdio_info *info = bus->priv; + + ihs_mdio_idle(bus); + + write_addr_data(info, value); + write_control(info, ((addr & 0x1f) << 5) | (regnum & 0x1f) | (1 << 10)); + + return 0; +} + +int ihs_mdio_init(struct ihs_mdio_info *info) +{ + struct mii_dev *bus = mdio_alloc(); + + if (!bus) { + printf("Failed to allocate FSL MDIO bus\n"); + return -1; + } + + bus->read = ihs_mdio_read; + bus->write = ihs_mdio_write; + bus->reset = ihs_mdio_reset; + strcpy(bus->name, info->name); + + bus->priv = info; + + return mdio_register(bus); +} diff --git a/roms/u-boot/board/gdsys/common/ihs_mdio.h b/roms/u-boot/board/gdsys/common/ihs_mdio.h new file mode 100644 index 000000000..d0a4b0d7a --- /dev/null +++ b/roms/u-boot/board/gdsys/common/ihs_mdio.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2014 + * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc + */ + +#ifndef _IHS_MDIO_H_ +#define _IHS_MDIO_H_ + +struct ihs_mdio_info { +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS + u32 fpga; +#else + struct udevice *fpga; + int base; +#endif + char *name; +}; + +int ihs_mdio_init(struct ihs_mdio_info *info); + +#endif diff --git a/roms/u-boot/board/gdsys/common/ioep-fpga.c b/roms/u-boot/board/gdsys/common/ioep-fpga.c new file mode 100644 index 000000000..7292d7ab5 --- /dev/null +++ b/roms/u-boot/board/gdsys/common/ioep-fpga.c @@ -0,0 +1,591 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2014 + * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc + */ + +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS + +#include <common.h> + +#include <gdsys_fpga.h> +#include <linux/bitops.h> + +enum pcb_video_type { + PCB_DVI_SL, + PCB_DP_165MPIX, + PCB_DP_300MPIX, + PCB_HDMI, + PCB_DP_1_2, + PCB_HDMI_2_0, +}; + +enum pcb_transmission_type { + PCB_CAT_1G, + PCB_FIBER_3G, + PCB_CAT_10G, + PCB_FIBER_10G, +}; + +enum carrier_speed { + CARRIER_SPEED_1G, + CARRIER_SPEED_3G, + CARRIER_SPEED_2_5G = CARRIER_SPEED_3G, + CARRIER_SPEED_10G, +}; + +enum ram_config { + RAM_DDR2_32BIT_295MBPS, + RAM_DDR3_32BIT_590MBPS, + RAM_DDR3_48BIT_590MBPS, + RAM_DDR3_64BIT_1800MBPS, + RAM_DDR3_48BIT_1800MBPS, +}; + +enum sysclock { + SYSCLK_147456, +}; + +struct fpga_versions { + bool video_channel; + bool con_side; + enum pcb_video_type pcb_video_type; + enum pcb_transmission_type pcb_transmission_type; + unsigned int hw_version; +}; + +struct fpga_features { + u8 video_channels; + u8 carriers; + enum carrier_speed carrier_speed; + enum ram_config ram_config; + enum sysclock sysclock; + + bool pcm_tx; + bool pcm_rx; + bool spdif_tx; + bool spdif_rx; + bool usb2; + bool rs232; + bool compression_type1; + bool compression_type2; + bool compression_type3; + bool interlace; + bool osd; + bool compression_pipes; +}; + +#ifdef CONFIG_SYS_FPGA_FLAVOR_GAZERBEAM + +static int get_versions(unsigned int fpga, struct fpga_versions *versions) +{ + enum { + VERSIONS_FPGA_VIDEO_CHANNEL = BIT(12), + VERSIONS_FPGA_CON_SIDE = BIT(13), + VERSIONS_FPGA_SC = BIT(14), + VERSIONS_PCB_CON = BIT(9), + VERSIONS_PCB_SC = BIT(8), + VERSIONS_PCB_VIDEO_MASK = 0x3 << 6, + VERSIONS_PCB_VIDEO_DP_1_2 = 0x0 << 6, + VERSIONS_PCB_VIDEO_HDMI_2_0 = 0x1 << 6, + VERSIONS_PCB_TRANSMISSION_MASK = 0x3 << 4, + VERSIONS_PCB_TRANSMISSION_FIBER_10G = 0x0 << 4, + VERSIONS_PCB_TRANSMISSION_CAT_10G = 0x1 << 4, + VERSIONS_PCB_TRANSMISSION_FIBER_3G = 0x2 << 4, + VERSIONS_PCB_TRANSMISSION_CAT_1G = 0x3 << 4, + VERSIONS_HW_VER_MASK = 0xf << 0, + }; + u16 raw_versions; + + memset(versions, 0, sizeof(struct fpga_versions)); + + FPGA_GET_REG(fpga, versions, &raw_versions); + + versions->video_channel = raw_versions & VERSIONS_FPGA_VIDEO_CHANNEL; + versions->con_side = raw_versions & VERSIONS_FPGA_CON_SIDE; + + switch (raw_versions & VERSIONS_PCB_VIDEO_MASK) { + case VERSIONS_PCB_VIDEO_DP_1_2: + versions->pcb_video_type = PCB_DP_1_2; + break; + + case VERSIONS_PCB_VIDEO_HDMI_2_0: + versions->pcb_video_type = PCB_HDMI_2_0; + break; + } + + switch (raw_versions & VERSIONS_PCB_TRANSMISSION_MASK) { + case VERSIONS_PCB_TRANSMISSION_FIBER_10G: + versions->pcb_transmission_type = PCB_FIBER_10G; + break; + + case VERSIONS_PCB_TRANSMISSION_CAT_10G: + versions->pcb_transmission_type = PCB_CAT_10G; + break; + + case VERSIONS_PCB_TRANSMISSION_FIBER_3G: + versions->pcb_transmission_type = PCB_FIBER_3G; + break; + + case VERSIONS_PCB_TRANSMISSION_CAT_1G: + versions->pcb_transmission_type = PCB_CAT_1G; + break; + + } + + versions->hw_version = raw_versions & VERSIONS_HW_VER_MASK; + + return 0; +} + +static int get_features(unsigned int fpga, struct fpga_features *features) +{ + enum { + FEATURE_SPDIF_RX = BIT(15), + FEATURE_SPDIF_TX = BIT(14), + FEATURE_PCM_RX = BIT(13), + FEATURE_PCM_TX = BIT(12), + FEATURE_RAM_MASK = GENMASK(11, 8), + FEATURE_RAM_DDR2_32BIT_295MBPS = 0x0 << 8, + FEATURE_RAM_DDR3_32BIT_590MBPS = 0x1 << 8, + FEATURE_RAM_DDR3_48BIT_590MBPS = 0x2 << 8, + FEATURE_RAM_DDR3_64BIT_1800MBPS = 0x3 << 8, + FEATURE_RAM_DDR3_48BIT_1800MBPS = 0x4 << 8, + FEATURE_CARRIER_SPEED_MASK = GENMASK(7, 6), + FEATURE_CARRIER_SPEED_1G = 0x0 << 6, + FEATURE_CARRIER_SPEED_2_5G = 0x1 << 6, + FEATURE_CARRIER_SPEED_10G = 0x2 << 6, + FEATURE_CARRIERS_MASK = GENMASK(5, 4), + FEATURE_CARRIERS_0 = 0x0 << 4, + FEATURE_CARRIERS_1 = 0x1 << 4, + FEATURE_CARRIERS_2 = 0x2 << 4, + FEATURE_CARRIERS_4 = 0x3 << 4, + FEATURE_USB2 = BIT(3), + FEATURE_VIDEOCHANNELS_MASK = GENMASK(2, 0), + FEATURE_VIDEOCHANNELS_0 = 0x0 << 0, + FEATURE_VIDEOCHANNELS_1 = 0x1 << 0, + FEATURE_VIDEOCHANNELS_1_1 = 0x2 << 0, + FEATURE_VIDEOCHANNELS_2 = 0x3 << 0, + }; + + enum { + EXT_FEATURE_OSD = BIT(15), + EXT_FEATURE_ETHERNET = BIT(9), + EXT_FEATURE_INTERLACE = BIT(8), + EXT_FEATURE_RS232 = BIT(7), + EXT_FEATURE_COMPRESSION_PERF_MASK = GENMASK(6, 4), + EXT_FEATURE_COMPRESSION_PERF_1X = 0x0 << 4, + EXT_FEATURE_COMPRESSION_PERF_2X = 0x1 << 4, + EXT_FEATURE_COMPRESSION_PERF_4X = 0x2 << 4, + EXT_FEATURE_COMPRESSION_TYPE1 = BIT(0), + EXT_FEATURE_COMPRESSION_TYPE2 = BIT(1), + EXT_FEATURE_COMPRESSION_TYPE3 = BIT(2), + }; + + u16 raw_features; + u16 raw_extended_features; + + memset(features, 0, sizeof(struct fpga_features)); + + FPGA_GET_REG(fpga, fpga_features, &raw_features); + FPGA_GET_REG(fpga, fpga_ext_features, &raw_extended_features); + + switch (raw_features & FEATURE_VIDEOCHANNELS_MASK) { + case FEATURE_VIDEOCHANNELS_0: + features->video_channels = 0; + break; + + case FEATURE_VIDEOCHANNELS_1: + features->video_channels = 1; + break; + + case FEATURE_VIDEOCHANNELS_1_1: + case FEATURE_VIDEOCHANNELS_2: + features->video_channels = 2; + break; + }; + + switch (raw_features & FEATURE_CARRIERS_MASK) { + case FEATURE_CARRIERS_0: + features->carriers = 0; + break; + + case FEATURE_CARRIERS_1: + features->carriers = 1; + break; + + case FEATURE_CARRIERS_2: + features->carriers = 2; + break; + + case FEATURE_CARRIERS_4: + features->carriers = 4; + break; + } + + switch (raw_features & FEATURE_CARRIER_SPEED_MASK) { + case FEATURE_CARRIER_SPEED_1G: + features->carrier_speed = CARRIER_SPEED_1G; + break; + case FEATURE_CARRIER_SPEED_2_5G: + features->carrier_speed = CARRIER_SPEED_2_5G; + break; + case FEATURE_CARRIER_SPEED_10G: + features->carrier_speed = CARRIER_SPEED_10G; + break; + } + + switch (raw_features & FEATURE_RAM_MASK) { + case FEATURE_RAM_DDR2_32BIT_295MBPS: + features->ram_config = RAM_DDR2_32BIT_295MBPS; + break; + + case FEATURE_RAM_DDR3_32BIT_590MBPS: + features->ram_config = RAM_DDR3_32BIT_590MBPS; + break; + + case FEATURE_RAM_DDR3_48BIT_590MBPS: + features->ram_config = RAM_DDR3_48BIT_590MBPS; + break; + + case FEATURE_RAM_DDR3_64BIT_1800MBPS: + features->ram_config = RAM_DDR3_64BIT_1800MBPS; + break; + + case FEATURE_RAM_DDR3_48BIT_1800MBPS: + features->ram_config = RAM_DDR3_48BIT_1800MBPS; + break; + } + + features->pcm_tx = raw_features & FEATURE_PCM_TX; + features->pcm_rx = raw_features & FEATURE_PCM_RX; + features->spdif_tx = raw_features & FEATURE_SPDIF_TX; + features->spdif_rx = raw_features & FEATURE_SPDIF_RX; + features->usb2 = raw_features & FEATURE_USB2; + features->rs232 = raw_extended_features & EXT_FEATURE_RS232; + features->compression_type1 = raw_extended_features & EXT_FEATURE_COMPRESSION_TYPE1; + features->compression_type2 = raw_extended_features & EXT_FEATURE_COMPRESSION_TYPE2; + features->compression_type3 = raw_extended_features & EXT_FEATURE_COMPRESSION_TYPE3; + features->interlace = raw_extended_features & EXT_FEATURE_INTERLACE; + features->osd = raw_extended_features & EXT_FEATURE_OSD; + features->compression_pipes = raw_extended_features & EXT_FEATURE_COMPRESSION_PERF_MASK; + + return 0; +} + +#else + +static int get_versions(unsigned int fpga, struct fpga_versions *versions) +{ + enum { + /* HW version encoding is a mess, leave it for the moment */ + VERSIONS_HW_VER_MASK = 0xf << 0, + VERSIONS_PIX_CLOCK_GEN_IDT8N3QV01 = BIT(4), + VERSIONS_SFP = BIT(5), + VERSIONS_VIDEO_MASK = 0x7 << 6, + VERSIONS_VIDEO_DVI = 0x0 << 6, + VERSIONS_VIDEO_DP_165 = 0x1 << 6, + VERSIONS_VIDEO_DP_300 = 0x2 << 6, + VERSIONS_VIDEO_HDMI = 0x3 << 6, + VERSIONS_UT_MASK = 0xf << 12, + VERSIONS_UT_MAIN_SERVER = 0x0 << 12, + VERSIONS_UT_MAIN_USER = 0x1 << 12, + VERSIONS_UT_VIDEO_SERVER = 0x2 << 12, + VERSIONS_UT_VIDEO_USER = 0x3 << 12, + }; + u16 raw_versions; + + memset(versions, 0, sizeof(struct fpga_versions)); + + FPGA_GET_REG(fpga, versions, &raw_versions); + + switch (raw_versions & VERSIONS_UT_MASK) { + case VERSIONS_UT_MAIN_SERVER: + versions->video_channel = false; + versions->con_side = false; + break; + + case VERSIONS_UT_MAIN_USER: + versions->video_channel = false; + versions->con_side = true; + break; + + case VERSIONS_UT_VIDEO_SERVER: + versions->video_channel = true; + versions->con_side = false; + break; + + case VERSIONS_UT_VIDEO_USER: + versions->video_channel = true; + versions->con_side = true; + break; + + } + + switch (raw_versions & VERSIONS_VIDEO_MASK) { + case VERSIONS_VIDEO_DVI: + versions->pcb_video_type = PCB_DVI_SL; + break; + + case VERSIONS_VIDEO_DP_165: + versions->pcb_video_type = PCB_DP_165MPIX; + break; + + case VERSIONS_VIDEO_DP_300: + versions->pcb_video_type = PCB_DP_300MPIX; + break; + + case VERSIONS_VIDEO_HDMI: + versions->pcb_video_type = PCB_HDMI; + break; + } + + versions->hw_version = raw_versions & VERSIONS_HW_VER_MASK; + + if (raw_versions & VERSIONS_SFP) + versions->pcb_transmission_type = PCB_FIBER_3G; + else + versions->pcb_transmission_type = PCB_CAT_1G; + + return 0; +} + +static int get_features(unsigned int fpga, struct fpga_features *features) +{ + enum { + FEATURE_CARRIER_SPEED_2_5 = BIT(4), + FEATURE_RAM_MASK = 0x7 << 5, + FEATURE_RAM_DDR2_32BIT = 0x0 << 5, + FEATURE_RAM_DDR3_32BIT = 0x1 << 5, + FEATURE_RAM_DDR3_48BIT = 0x2 << 5, + FEATURE_PCM_AUDIO_TX = BIT(9), + FEATURE_PCM_AUDIO_RX = BIT(10), + FEATURE_OSD = BIT(11), + FEATURE_USB20 = BIT(12), + FEATURE_COMPRESSION_MASK = 7 << 13, + FEATURE_COMPRESSION_TYPE1 = 0x1 << 13, + FEATURE_COMPRESSION_TYPE1_TYPE2 = 0x3 << 13, + FEATURE_COMPRESSION_TYPE1_TYPE2_TYPE3 = 0x7 << 13, + }; + + enum { + EXTENDED_FEATURE_SPDIF_AUDIO_TX = BIT(0), + EXTENDED_FEATURE_SPDIF_AUDIO_RX = BIT(1), + EXTENDED_FEATURE_RS232 = BIT(2), + EXTENDED_FEATURE_COMPRESSION_PIPES = BIT(3), + EXTENDED_FEATURE_INTERLACE = BIT(4), + }; + + u16 raw_features; +#ifdef GDSYS_LEGACY_DRIVERS + u16 raw_extended_features; +#endif + + memset(features, 0, sizeof(struct fpga_features)); + + FPGA_GET_REG(fpga, fpga_features, &raw_features); +#ifdef GDSYS_LEGACY_DRIVERS + FPGA_GET_REG(fpga, fpga_ext_features, &raw_extended_features); +#endif + + features->video_channels = raw_features & 0x3; + features->carriers = (raw_features >> 2) & 0x3; + + features->carrier_speed = (raw_features & FEATURE_CARRIER_SPEED_2_5) + ? CARRIER_SPEED_2_5G : CARRIER_SPEED_1G; + + switch (raw_features & FEATURE_RAM_MASK) { + case FEATURE_RAM_DDR2_32BIT: + features->ram_config = RAM_DDR2_32BIT_295MBPS; + break; + + case FEATURE_RAM_DDR3_32BIT: + features->ram_config = RAM_DDR3_32BIT_590MBPS; + break; + + case FEATURE_RAM_DDR3_48BIT: + features->ram_config = RAM_DDR3_48BIT_590MBPS; + break; + } + + features->pcm_tx = raw_features & FEATURE_PCM_AUDIO_TX; + features->pcm_rx = raw_features & FEATURE_PCM_AUDIO_RX; +#ifdef GDSYS_LEGACY_DRIVERS + features->spdif_tx = raw_extended_features & EXTENDED_FEATURE_SPDIF_AUDIO_TX; + features->spdif_rx = raw_extended_features & EXTENDED_FEATURE_SPDIF_AUDIO_RX; +#endif + + features->usb2 = raw_features & FEATURE_USB20; +#ifdef GDSYS_LEGACY_DRIVERS + features->rs232 = raw_extended_features & EXTENDED_FEATURE_RS232; +#endif + + features->compression_type1 = false; + features->compression_type2 = false; + features->compression_type3 = false; + switch (raw_features & FEATURE_COMPRESSION_MASK) { + case FEATURE_COMPRESSION_TYPE1_TYPE2_TYPE3: + features->compression_type3 = true; + case FEATURE_COMPRESSION_TYPE1_TYPE2: + features->compression_type2 = true; + case FEATURE_COMPRESSION_TYPE1: + features->compression_type1 = true; + break; + } + +#ifdef GDSYS_LEGACY_DRIVERS + features->interlace = raw_extended_features & EXTENDED_FEATURE_INTERLACE; +#endif + features->osd = raw_features & FEATURE_OSD; +#ifdef GDSYS_LEGACY_DRIVERS + features->compression_pipes = raw_extended_features & EXTENDED_FEATURE_COMPRESSION_PIPES; +#endif + + return 0; +} + +#include <linux/bitops.h> +#endif + +bool ioep_fpga_has_osd(unsigned int fpga) +{ + struct fpga_features features; + + get_features(fpga, &features); + + return features.osd; +} + +void ioep_fpga_print_info(unsigned int fpga) +{ + u16 fpga_version; + struct fpga_versions versions; + struct fpga_features features; + + FPGA_GET_REG(fpga, fpga_version, &fpga_version); + get_versions(fpga, &versions); + get_features(fpga, &features); + + if (versions.video_channel) + printf("Videochannel"); + else + printf("Mainchannel"); + + if (versions.con_side) + printf(" User"); + else + printf(" Server"); + +// FIXME +#if 0 + if (versions & (1<<4)) + printf(" UC"); +#endif + + switch(versions.pcb_transmission_type) { + case PCB_CAT_1G: + case PCB_CAT_10G: + printf(" CAT"); + break; + case PCB_FIBER_3G: + case PCB_FIBER_10G: + printf(" Fiber"); + break; + }; + + switch (versions.pcb_video_type) { + case PCB_DVI_SL: + printf(" DVI,"); + break; + case PCB_DP_165MPIX: + printf(" DP 165MPix/s,"); + break; + case PCB_DP_300MPIX: + printf(" DP 300MPix/s,"); + break; + case PCB_HDMI: + printf(" HDMI,"); + break; + case PCB_DP_1_2: + printf(" DP 1.2,"); + break; + case PCB_HDMI_2_0: + printf(" HDMI 2.0,"); + break; + } + + printf(" FPGA V %d.%02d\n features: ", + fpga_version / 100, fpga_version % 100); + + if (!features.compression_type1 && + !features.compression_type2 && + !features.compression_type3) + printf("no compression, "); + + if (features.compression_type1) + printf("type1, "); + + if (features.compression_type2) + printf("type2, "); + + if (features.compression_type3) + printf("type3, "); + + printf("%sosd", features.osd ? "" : "no "); + + if (features.pcm_rx && features.pcm_tx) + printf(", pcm rx+tx"); + else if(features.pcm_rx) + printf(", pcm rx"); + else if(features.pcm_tx) + printf(", pcm tx"); + + if (features.spdif_rx && features.spdif_tx) + printf(", spdif rx+tx"); + else if(features.spdif_rx) + printf(", spdif rx"); + else if(features.spdif_tx) + printf(", spdif tx"); + + puts(",\n "); + + switch (features.sysclock) { + case SYSCLK_147456: + printf("clock 147.456 MHz"); + break; + } + + switch (features.ram_config) { + case RAM_DDR2_32BIT_295MBPS: + printf(", RAM 32 bit DDR2"); + break; + case RAM_DDR3_32BIT_590MBPS: + printf(", RAM 32 bit DDR3"); + break; + case RAM_DDR3_48BIT_590MBPS: + case RAM_DDR3_48BIT_1800MBPS: + printf(", RAM 48 bit DDR3"); + break; + case RAM_DDR3_64BIT_1800MBPS: + printf(", RAM 64 bit DDR3"); + break; + } + + printf(", %d carrier(s)", features.carriers); + + switch(features.carrier_speed) { + case CARRIER_SPEED_1G: + printf(", 1Gbit/s"); + break; + case CARRIER_SPEED_3G: + printf(", 3Gbit/s"); + break; + case CARRIER_SPEED_10G: + printf(", 10Gbit/s"); + break; + } + + printf(", %d video channel(s)\n", features.video_channels); +} + +#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */ diff --git a/roms/u-boot/board/gdsys/common/ioep-fpga.h b/roms/u-boot/board/gdsys/common/ioep-fpga.h new file mode 100644 index 000000000..53570b936 --- /dev/null +++ b/roms/u-boot/board/gdsys/common/ioep-fpga.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2014 + * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc + */ + +#ifndef _IOEP_FPGA_H_ +#define _IOEP_FPGA_H_ + +void ioep_fpga_print_info(unsigned int fpga); +bool ioep_fpga_has_osd(unsigned int fpga); + +#endif diff --git a/roms/u-boot/board/gdsys/common/osd.c b/roms/u-boot/board/gdsys/common/osd.c new file mode 100644 index 000000000..679f8f301 --- /dev/null +++ b/roms/u-boot/board/gdsys/common/osd.c @@ -0,0 +1,506 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2010 + * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc + */ + +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS + +#include <common.h> +#include <command.h> +#include <i2c.h> +#include <malloc.h> +#include <linux/stringify.h> + +#include "ch7301.h" +#include "dp501.h" +#include <gdsys_fpga.h> + +#define ICS8N3QV01_I2C_ADDR 0x6E +#define ICS8N3QV01_FREF 114285000 +#define ICS8N3QV01_FREF_LL 114285000LL +#define ICS8N3QV01_F_DEFAULT_0 156250000LL +#define ICS8N3QV01_F_DEFAULT_1 125000000LL +#define ICS8N3QV01_F_DEFAULT_2 100000000LL +#define ICS8N3QV01_F_DEFAULT_3 25175000LL + +#define SIL1178_MASTER_I2C_ADDRESS 0x38 +#define SIL1178_SLAVE_I2C_ADDRESS 0x39 + +#define PIXCLK_640_480_60 25180000 +#define MAX_X_CHARS 53 +#define MAX_Y_CHARS 26 + +#ifdef CONFIG_SYS_OSD_DH +#define MAX_OSD_SCREEN 8 +#define OSD_DH_BASE 4 +#else +#define MAX_OSD_SCREEN 4 +#endif + +#ifdef CONFIG_SYS_OSD_DH +#define OSD_SET_REG(screen, fld, val) \ + do { \ + if (screen >= OSD_DH_BASE) \ + FPGA_SET_REG(screen - OSD_DH_BASE, osd1.fld, val); \ + else \ + FPGA_SET_REG(screen, osd0.fld, val); \ + } while (0) +#else +#define OSD_SET_REG(screen, fld, val) \ + FPGA_SET_REG(screen, osd0.fld, val) +#endif + +#ifdef CONFIG_SYS_OSD_DH +#define OSD_GET_REG(screen, fld, val) \ + do { \ + if (screen >= OSD_DH_BASE) \ + FPGA_GET_REG(screen - OSD_DH_BASE, osd1.fld, val); \ + else \ + FPGA_GET_REG(screen, osd0.fld, val); \ + } while (0) +#else +#define OSD_GET_REG(screen, fld, val) \ + FPGA_GET_REG(screen, osd0.fld, val) +#endif + +unsigned int base_width; +unsigned int base_height; +size_t bufsize; +u16 *buf; + +unsigned int osd_screen_mask = 0; + +#ifdef CONFIG_SYS_ICS8N3QV01_I2C +int ics8n3qv01_i2c[] = CONFIG_SYS_ICS8N3QV01_I2C; +#endif + +#ifdef CONFIG_SYS_SIL1178_I2C +int sil1178_i2c[] = CONFIG_SYS_SIL1178_I2C; +#endif + +#ifdef CONFIG_SYS_MPC92469AC +static void mpc92469ac_calc_parameters(unsigned int fout, + unsigned int *post_div, unsigned int *feedback_div) +{ + unsigned int n = *post_div; + unsigned int m = *feedback_div; + unsigned int a; + unsigned int b = 14745600 / 16; + + if (fout < 50169600) + n = 8; + else if (fout < 100339199) + n = 4; + else if (fout < 200678399) + n = 2; + else + n = 1; + + a = fout * n + (b / 2); /* add b/2 for proper rounding */ + + m = a / b; + + *post_div = n; + *feedback_div = m; +} + +static void mpc92469ac_set(unsigned screen, unsigned int fout) +{ + unsigned int n; + unsigned int m; + unsigned int bitval = 0; + mpc92469ac_calc_parameters(fout, &n, &m); + + switch (n) { + case 1: + bitval = 0x00; + break; + case 2: + bitval = 0x01; + break; + case 4: + bitval = 0x02; + break; + case 8: + bitval = 0x03; + break; + } + + FPGA_SET_REG(screen, mpc3w_control, (bitval << 9) | m); +} +#endif + +#ifdef CONFIG_SYS_ICS8N3QV01_I2C + +static unsigned int ics8n3qv01_get_fout_calc(unsigned index) +{ + unsigned long long n; + unsigned long long mint; + unsigned long long mfrac; + u8 reg_a, reg_b, reg_c, reg_d, reg_f; + unsigned long long fout_calc; + + if (index > 3) + return 0; + + reg_a = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 0 + index); + reg_b = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 4 + index); + reg_c = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 8 + index); + reg_d = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 12 + index); + reg_f = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 20 + index); + + mint = ((reg_a >> 1) & 0x1f) | (reg_f & 0x20); + mfrac = ((reg_a & 0x01) << 17) | (reg_b << 9) | (reg_c << 1) + | (reg_d >> 7); + n = reg_d & 0x7f; + + fout_calc = (mint * ICS8N3QV01_FREF_LL + + mfrac * ICS8N3QV01_FREF_LL / 262144LL + + ICS8N3QV01_FREF_LL / 524288LL + + n / 2) + / n + * 1000000 + / (1000000 - 100); + + return fout_calc; +} + + +static void ics8n3qv01_calc_parameters(unsigned int fout, + unsigned int *_mint, unsigned int *_mfrac, + unsigned int *_n) +{ + unsigned int n; + unsigned int foutiic; + unsigned int fvcoiic; + unsigned int mint; + unsigned long long mfrac; + + n = (2215000000U + fout / 2) / fout; + if ((n & 1) && (n > 5)) + n -= 1; + + foutiic = fout - (fout / 10000); + fvcoiic = foutiic * n; + + mint = fvcoiic / 114285000; + if ((mint < 17) || (mint > 63)) + printf("ics8n3qv01_calc_parameters: cannot determine mint\n"); + + mfrac = ((unsigned long long)fvcoiic % 114285000LL) * 262144LL + / 114285000LL; + + *_mint = mint; + *_mfrac = mfrac; + *_n = n; +} + +static void ics8n3qv01_set(unsigned int fout) +{ + unsigned int n; + unsigned int mint; + unsigned int mfrac; + unsigned int fout_calc; + unsigned long long fout_prog; + long long off_ppm; + u8 reg0, reg4, reg8, reg12, reg18, reg20; + + fout_calc = ics8n3qv01_get_fout_calc(1); + off_ppm = (fout_calc - ICS8N3QV01_F_DEFAULT_1) * 1000000 + / ICS8N3QV01_F_DEFAULT_1; + printf(" PLL is off by %lld ppm\n", off_ppm); + fout_prog = (unsigned long long)fout * (unsigned long long)fout_calc + / ICS8N3QV01_F_DEFAULT_1; + ics8n3qv01_calc_parameters(fout_prog, &mint, &mfrac, &n); + + reg0 = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 0) & 0xc0; + reg0 |= (mint & 0x1f) << 1; + reg0 |= (mfrac >> 17) & 0x01; + i2c_reg_write(ICS8N3QV01_I2C_ADDR, 0, reg0); + + reg4 = mfrac >> 9; + i2c_reg_write(ICS8N3QV01_I2C_ADDR, 4, reg4); + + reg8 = mfrac >> 1; + i2c_reg_write(ICS8N3QV01_I2C_ADDR, 8, reg8); + + reg12 = mfrac << 7; + reg12 |= n & 0x7f; + i2c_reg_write(ICS8N3QV01_I2C_ADDR, 12, reg12); + + reg18 = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 18) & 0x03; + reg18 |= 0x20; + i2c_reg_write(ICS8N3QV01_I2C_ADDR, 18, reg18); + + reg20 = i2c_reg_read(ICS8N3QV01_I2C_ADDR, 20) & 0x1f; + reg20 |= mint & (1 << 5); + i2c_reg_write(ICS8N3QV01_I2C_ADDR, 20, reg20); +} +#endif + +static int osd_write_videomem(unsigned screen, unsigned offset, + u16 *data, size_t charcount) +{ + unsigned int k; + + for (k = 0; k < charcount; ++k) { + if (offset + k >= bufsize) + return -1; +#ifdef CONFIG_SYS_OSD_DH + if (screen >= OSD_DH_BASE) + FPGA_SET_REG(screen - OSD_DH_BASE, + videomem1[offset + k], data[k]); + else + FPGA_SET_REG(screen, videomem0[offset + k], data[k]); +#else + FPGA_SET_REG(screen, videomem0[offset + k], data[k]); +#endif + } + + return charcount; +} + +static int osd_print(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + unsigned screen; + + if (argc < 5) { + cmd_usage(cmdtp); + return 1; + } + + for (screen = 0; screen < MAX_OSD_SCREEN; ++screen) { + unsigned x; + unsigned y; + unsigned charcount; + unsigned len; + u8 color; + unsigned int k; + char *text; + int res; + + if (!(osd_screen_mask & (1 << screen))) + continue; + + x = simple_strtoul(argv[1], NULL, 16); + y = simple_strtoul(argv[2], NULL, 16); + color = simple_strtoul(argv[3], NULL, 16); + text = argv[4]; + charcount = strlen(text); + len = (charcount > bufsize) ? bufsize : charcount; + + for (k = 0; k < len; ++k) + buf[k] = (text[k] << 8) | color; + + res = osd_write_videomem(screen, y * base_width + x, buf, len); + if (res < 0) + return res; + + OSD_SET_REG(screen, control, 0x0049); + } + + return 0; +} + +int osd_probe(unsigned screen) +{ + u16 version; + u16 features; + int old_bus = i2c_get_bus_num(); + bool pixclock_present = false; + bool output_driver_present = false; + + OSD_GET_REG(0, version, &version); + OSD_GET_REG(0, features, &features); + + base_width = ((features & 0x3f00) >> 8) + 1; + base_height = (features & 0x001f) + 1; + bufsize = base_width * base_height; + buf = malloc(sizeof(u16) * bufsize); + if (!buf) + return -1; + +#ifdef CONFIG_SYS_OSD_DH + printf("OSD%d-%d: Digital-OSD version %01d.%02d, %d" "x%d characters\n", + (screen >= OSD_DH_BASE) ? (screen - OSD_DH_BASE) : screen, + (screen > 3) ? 1 : 0, version/100, version%100, base_width, + base_height); +#else + printf("OSD%d: Digital-OSD version %01d.%02d, %d" "x%d characters\n", + screen, version/100, version%100, base_width, base_height); +#endif + /* setup pixclock */ + +#ifdef CONFIG_SYS_MPC92469AC + pixclock_present = true; + mpc92469ac_set(screen, PIXCLK_640_480_60); +#endif + +#ifdef CONFIG_SYS_ICS8N3QV01_I2C + i2c_set_bus_num(ics8n3qv01_i2c[screen]); + if (!i2c_probe(ICS8N3QV01_I2C_ADDR)) { + ics8n3qv01_set(PIXCLK_640_480_60); + pixclock_present = true; + } +#endif + + if (!pixclock_present) + printf(" no pixelclock found\n"); + + /* setup output driver */ + +#ifdef CONFIG_SYS_CH7301_I2C + if (!ch7301_probe(screen, true)) + output_driver_present = true; +#endif + +#ifdef CONFIG_SYS_SIL1178_I2C + i2c_set_bus_num(sil1178_i2c[screen]); + if (!i2c_probe(SIL1178_SLAVE_I2C_ADDRESS)) { + if (i2c_reg_read(SIL1178_SLAVE_I2C_ADDRESS, 0x02) == 0x06) { + /* + * magic initialization sequence, + * adapted from datasheet + */ + i2c_reg_write(SIL1178_SLAVE_I2C_ADDRESS, 0x08, 0x36); + i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0f, 0x44); + i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0f, 0x4c); + i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0e, 0x10); + i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0a, 0x80); + i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x09, 0x30); + i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0c, 0x89); + i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x0d, 0x60); + i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x08, 0x36); + i2c_reg_write(SIL1178_MASTER_I2C_ADDRESS, 0x08, 0x37); + output_driver_present = true; + } + } +#endif + +#ifdef CONFIG_SYS_DP501_I2C + if (!dp501_probe(screen, true)) + output_driver_present = true; +#endif + + if (!output_driver_present) + printf(" no output driver found\n"); + + OSD_SET_REG(screen, xy_size, ((32 - 1) << 8) | (16 - 1)); + OSD_SET_REG(screen, x_pos, 0x007f); + OSD_SET_REG(screen, y_pos, 0x005f); + + if (pixclock_present && output_driver_present) + osd_screen_mask |= 1 << screen; + + i2c_set_bus_num(old_bus); + + return 0; +} + +int osd_write(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + unsigned screen; + + if ((argc < 4) || (strlen(argv[3]) % 4)) { + cmd_usage(cmdtp); + return 1; + } + + for (screen = 0; screen < MAX_OSD_SCREEN; ++screen) { + unsigned x; + unsigned y; + unsigned k; + u16 buffer[base_width]; + char *rp; + u16 *wp = buffer; + unsigned count = (argc > 4) ? + simple_strtoul(argv[4], NULL, 16) : 1; + + if (!(osd_screen_mask & (1 << screen))) + continue; + + x = simple_strtoul(argv[1], NULL, 16); + y = simple_strtoul(argv[2], NULL, 16); + rp = argv[3]; + + + while (*rp) { + char substr[5]; + + memcpy(substr, rp, 4); + substr[4] = 0; + *wp = simple_strtoul(substr, NULL, 16); + + rp += 4; + wp++; + if (wp - buffer > base_width) + break; + } + + for (k = 0; k < count; ++k) { + unsigned offset = + y * base_width + x + k * (wp - buffer); + osd_write_videomem(screen, offset, buffer, + wp - buffer); + } + + OSD_SET_REG(screen, control, 0x0049); + } + + return 0; +} + +int osd_size(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + unsigned screen; + unsigned x; + unsigned y; + + if (argc < 3) { + cmd_usage(cmdtp); + return 1; + } + + x = simple_strtoul(argv[1], NULL, 16); + y = simple_strtoul(argv[2], NULL, 16); + + if (!x || (x > 64) || (x > MAX_X_CHARS) || + !y || (y > 32) || (y > MAX_Y_CHARS)) { + cmd_usage(cmdtp); + return 1; + } + + for (screen = 0; screen < MAX_OSD_SCREEN; ++screen) { + if (!(osd_screen_mask & (1 << screen))) + continue; + + OSD_SET_REG(screen, xy_size, ((x - 1) << 8) | (y - 1)); + OSD_SET_REG(screen, x_pos, 32767 * (640 - 12 * x) / 65535); + OSD_SET_REG(screen, y_pos, 32767 * (480 - 18 * y) / 65535); + } + + return 0; +} + +U_BOOT_CMD( + osdw, 5, 0, osd_write, + "write 16-bit hex encoded buffer to osd memory", + "pos_x pos_y buffer count\n" +); + +U_BOOT_CMD( + osdp, 5, 0, osd_print, + "write ASCII buffer to osd memory", + "pos_x pos_y color text\n" +); + +U_BOOT_CMD( + osdsize, 3, 0, osd_size, + "set OSD XY size in characters", + "size_x(max. " __stringify(MAX_X_CHARS) + ") size_y(max. " __stringify(MAX_Y_CHARS) ")\n" +); + +#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */ diff --git a/roms/u-boot/board/gdsys/common/osd.h b/roms/u-boot/board/gdsys/common/osd.h new file mode 100644 index 000000000..4e8e53ab4 --- /dev/null +++ b/roms/u-boot/board/gdsys/common/osd.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2010 + * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc + */ + +#ifndef _OSD_H_ +#define _OSD_H_ + +int ch7301_probe(unsigned screen, bool power); +int osd_probe(unsigned screen); + +#endif diff --git a/roms/u-boot/board/gdsys/common/osd_cmd.c b/roms/u-boot/board/gdsys/common/osd_cmd.c new file mode 100644 index 000000000..fe6249794 --- /dev/null +++ b/roms/u-boot/board/gdsys/common/osd_cmd.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2017 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + * + * based on the gdsys osd driver, which is + * + * (C) Copyright 2010 + * Dirk Eibach, Guntermann & Drunck GmbH, eibach@gdsys.de + */ + +#include <common.h> +#include <command.h> +#include <dm.h> +#include <hexdump.h> +#include <video_osd.h> +#include <malloc.h> + +static int do_osd_write(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct udevice *dev; + uint x, y; + uint count; + char *hexstr; + u8 *buffer; + size_t buflen; + int res; + + if (argc < 4 || (strlen(argv[3])) % 2) + return CMD_RET_USAGE; + + x = simple_strtoul(argv[1], NULL, 16); + y = simple_strtoul(argv[2], NULL, 16); + hexstr = argv[3]; + count = (argc > 4) ? simple_strtoul(argv[4], NULL, 16) : 1; + + buflen = strlen(hexstr) / 2; + + buffer = malloc(buflen); + if (!buffer) { + puts("Memory allocation failure\n"); + return CMD_RET_FAILURE; + } + + res = hex2bin(buffer, hexstr, buflen); + if (res) { + free(buffer); + puts("Hexadecimal input contained invalid characters\n"); + return CMD_RET_FAILURE; + } + + for (uclass_first_device(UCLASS_VIDEO_OSD, &dev); + dev; + uclass_next_device(&dev)) { + int res; + + res = video_osd_set_mem(dev, x, y, buffer, buflen, count); + if (res) { + free(buffer); + printf("Could not write to video mem on osd %s\n", + dev->name); + return CMD_RET_FAILURE; + } + } + + free(buffer); + + return CMD_RET_SUCCESS; +} + +static int do_osd_print(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct udevice *dev; + uint x, y; + u8 color; + char *text; + + if (argc < 5) + return CMD_RET_USAGE; + + x = simple_strtoul(argv[1], NULL, 16); + y = simple_strtoul(argv[2], NULL, 16); + color = simple_strtoul(argv[3], NULL, 16); + text = argv[4]; + + for (uclass_first_device(UCLASS_VIDEO_OSD, &dev); + dev; + uclass_next_device(&dev)) { + int res; + + res = video_osd_print(dev, x, y, color, text); + if (res) { + printf("Could not print string to osd %s\n", dev->name); + return CMD_RET_FAILURE; + } + } + + return CMD_RET_SUCCESS; +} + +static int do_osd_size(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct udevice *dev; + uint x, y; + + if (argc < 3) + return CMD_RET_USAGE; + + x = simple_strtoul(argv[1], NULL, 16); + y = simple_strtoul(argv[2], NULL, 16); + + for (uclass_first_device(UCLASS_VIDEO_OSD, &dev); + dev; + uclass_next_device(&dev)) { + int res; + + res = video_osd_set_size(dev, x, y); + + if (res) { + printf("Could not set size on osd %s\n", dev->name); + return CMD_RET_FAILURE; + } + } + + return CMD_RET_SUCCESS; +} + +U_BOOT_CMD( + osdw, 5, 0, do_osd_write, + "write 16-bit hex encoded buffer to osd memory", + "osdw [pos_x] [pos_y] [buffer] [count] - write 8-bit hex encoded buffer to osd memory\n" +); + +U_BOOT_CMD( + osdp, 5, 0, do_osd_print, + "write ASCII buffer to osd memory", + "osdp [pos_x] [pos_y] [color] [text] - write ASCII buffer to osd memory\n" +); + +U_BOOT_CMD( + osdsize, 3, 0, do_osd_size, + "set OSD XY size in characters", + "osdsize [size_x] [size_y] - set OSD XY size in characters\n" +); diff --git a/roms/u-boot/board/gdsys/mpc8308/Kconfig b/roms/u-boot/board/gdsys/mpc8308/Kconfig new file mode 100644 index 000000000..c3fd0518b --- /dev/null +++ b/roms/u-boot/board/gdsys/mpc8308/Kconfig @@ -0,0 +1,83 @@ +if TARGET_GAZERBEAM + +config GDSYS_LEGACY_OSD_CMDS + bool + help + Use the 'osdw', 'osdp', and 'osdsize' legacy commands required by + gdsys devices. + +config GDSYS_LEGACY_DRIVERS + bool + help + Enable the gdsys legacy drivers under board/gdsys/common. If this + option is not set, all relevant DM drivers must be configured for the + device in question. + +config SYS_FPGA0_BASE + hex + default E0600000 + help + The base address of the first FPGA's register map. + +config SYS_FPGA0_SIZE + hex + default 1 + help + The base address of the first FPGA's register map. + +config SYS_FPGA1_BASE + hex + help + The base address of the second FPGA's register map. + +config SYS_FPGA1_SIZE + hex + help + The base address of the second FPGA's register map. + +config SYS_BOARD + default "mpc8308" + +config SYS_VENDOR + default "gdsys" + +config SYS_CONFIG_NAME + default "gazerbeam" + +config SYS_FPGA1_BASE + default E0700000 + +config SYS_FPGA1_SIZE + default 1 + +config GDSYS_LEGACY_OSD_CMDS + default y + +choice + prompt "FPGA flavor selection" + +config SYS_FPGA_FLAVOR_LEGACY + bool "Legacy flavor" + help + This enables support for the gdsys pre-Gazerbeam FPGA memory layout. + +config SYS_FPGA_FLAVOR_GAZERBEAM + bool "Gazerbeam flavor" + help + This enables support for the gdsys FPGA memory layout of the + Gazerbeam board. + +endchoice + +config EXTENDED_FEATURES + bool "FPGA extended features" + depends on GDSYS_LEGACY_DRIVERS + help + Enable support for the extended features field of the IHS FPGA. + +config CMD_IOLOOP + bool "Enable 'ioloop' and 'ioreflect' commands" + help + These commands provide FPGA tests. + +endif diff --git a/roms/u-boot/board/gdsys/mpc8308/MAINTAINERS b/roms/u-boot/board/gdsys/mpc8308/MAINTAINERS new file mode 100644 index 000000000..dc0b389f7 --- /dev/null +++ b/roms/u-boot/board/gdsys/mpc8308/MAINTAINERS @@ -0,0 +1,6 @@ +MPC8308 BOARD +M: Dirk Eibach <dirk.eibach@gdsys.cc> +S: Maintained +F: board/gdsys/mpc8308/ +F: include/configs/gazerbeam.h +F: configs/gazerbeam_defconfig diff --git a/roms/u-boot/board/gdsys/mpc8308/Makefile b/roms/u-boot/board/gdsys/mpc8308/Makefile new file mode 100644 index 000000000..f86d997bc --- /dev/null +++ b/roms/u-boot/board/gdsys/mpc8308/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2014 +# Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc + +obj-y := mpc8308.o sdram.o +obj-$(CONFIG_TARGET_GAZERBEAM) += gazerbeam.o diff --git a/roms/u-boot/board/gdsys/mpc8308/gazerbeam.c b/roms/u-boot/board/gdsys/mpc8308/gazerbeam.c new file mode 100644 index 000000000..3d4a7e57f --- /dev/null +++ b/roms/u-boot/board/gdsys/mpc8308/gazerbeam.c @@ -0,0 +1,186 @@ +/* + * (C) Copyright 2015 + * Dirk Eibach, Guntermann & Drunck GmbH, eibach@gdsys.de + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <command.h> +#include <dm.h> +#include <env.h> +#include <fdt_support.h> +#include <fsl_esdhc.h> +#include <init.h> +#include <miiphy.h> +#include <misc.h> +#include <sysinfo.h> +#include <tpm-v1.h> +#include <video_osd.h> +#include <asm/global_data.h> + +#include "../common/ihs_mdio.h" +#include "../../../drivers/sysinfo/gazerbeam.h" + +DECLARE_GLOBAL_DATA_PTR; + +struct ihs_mdio_info ihs_mdio_info[] = { + { .fpga = NULL, .name = "ihs0", .base = 0x58 }, + { .fpga = NULL, .name = "ihs1", .base = 0x58 }, +}; + +static int get_tpm(struct udevice **devp) +{ + int rc; + + rc = uclass_first_device_err(UCLASS_TPM, devp); + if (rc) { + printf("Could not find TPM (ret=%d)\n", rc); + return CMD_RET_FAILURE; + } + + return 0; +} + +int board_early_init_r(void) +{ + struct udevice *sysinfo; + struct udevice *serdes; + int mc = 0; + int con = 0; + + if (sysinfo_get(&sysinfo)) + puts("Could not find sysinfo information device.\n"); + + /* Initialize serdes */ + uclass_get_device_by_phandle(UCLASS_MISC, sysinfo, "serdes", &serdes); + + if (sysinfo_detect(sysinfo)) + puts("Device information detection failed.\n"); + + sysinfo_get_int(sysinfo, BOARD_MULTICHANNEL, &mc); + sysinfo_get_int(sysinfo, BOARD_VARIANT, &con); + + if (mc == 2 || mc == 1) + dev_disable_by_path("/immr@e0000000/i2c@3100/pca9698@22"); + + if (mc == 4) { + dev_disable_by_path("/immr@e0000000/i2c@3100/pca9698@20"); + dev_enable_by_path("/localbus@e0005000/iocon_uart@2,0"); + dev_enable_by_path("/fpga1bus"); + } + + if (mc == 2 || con == VAR_CON) { + dev_enable_by_path("/fpga0bus/fpga0_video1"); + dev_enable_by_path("/fpga0bus/fpga0_iic_video1"); + dev_enable_by_path("/fpga0bus/fpga0_axi_video1"); + } + + if (con == VAR_CON) { + dev_enable_by_path("/fpga0bus/fpga0_video0"); + dev_enable_by_path("/fpga0bus/fpga0_iic_video0"); + dev_enable_by_path("/fpga0bus/fpga0_axi_video0"); + } + + return 0; +} + +int checksysinfo(void) +{ + struct udevice *sysinfo; + char *s = env_get("serial#"); + int mc = 0; + int con = 0; + + if (sysinfo_get(&sysinfo)) + puts("Could not find sysinfo information device.\n"); + + sysinfo_get_int(sysinfo, BOARD_MULTICHANNEL, &mc); + sysinfo_get_int(sysinfo, BOARD_VARIANT, &con); + + puts("Board: Gazerbeam "); + printf("%s ", mc == 4 ? "MC4" : mc == 2 ? "MC2" : "SC"); + printf("%s", con == VAR_CON ? "CON" : "CPU"); + + if (s) { + puts(", serial# "); + puts(s); + } + + puts("\n"); + + return 0; +} + +static void display_osd_info(struct udevice *osd, + struct video_osd_info *osd_info) +{ + printf("OSD-%s: Digital-OSD version %01d.%02d, %d x %d characters\n", + osd->name, osd_info->major_version, osd_info->minor_version, + osd_info->width, osd_info->height); +} + +int last_stage_init(void) +{ + int fpga_hw_rev = 0; + int i; + struct udevice *sysinfo; + struct udevice *osd; + struct video_osd_info osd_info; + struct udevice *tpm; + int ret; + + if (sysinfo_get(&sysinfo)) + puts("Could not find sysinfo information device.\n"); + + if (sysinfo) { + int res = sysinfo_get_int(sysinfo, BOARD_HWVERSION, + &fpga_hw_rev); + + if (res) + printf("Could not determind FPGA HW revision (res = %d)\n", + res); + } + + env_set_ulong("fpga_hw_rev", fpga_hw_rev); + + ret = get_tpm(&tpm); + if (ret || tpm_init(tpm) || tpm1_startup(tpm, TPM_ST_CLEAR) || + tpm1_continue_self_test(tpm)) { + printf("TPM init failed\n"); + } + + if (fpga_hw_rev >= 4) { + for (i = 0; i < 4; i++) { + struct udevice *rxaui; + char name[8]; + + snprintf(name, sizeof(name), "rxaui%d", i); + /* Disable RXAUI polarity inversion */ + ret = uclass_get_device_by_phandle(UCLASS_MISC, sysinfo, + name, &rxaui); + if (!ret) + misc_set_enabled(rxaui, false); + } + } + + for (uclass_first_device(UCLASS_VIDEO_OSD, &osd); + osd; + uclass_next_device(&osd)) { + video_osd_get_info(osd, &osd_info); + display_osd_info(osd, &osd_info); + } + + return 0; +} + +#if defined(CONFIG_OF_BOARD_SETUP) +int ft_board_setup(void *blob, struct bd_info *bd) +{ + ft_cpu_setup(blob, bd); + fsl_fdt_fixup_dr_usb(blob, bd); + fdt_fixup_esdhc(blob, bd); + + return 0; +} +#endif diff --git a/roms/u-boot/board/gdsys/mpc8308/mpc8308.c b/roms/u-boot/board/gdsys/mpc8308/mpc8308.c new file mode 100644 index 000000000..0f90f8ad3 --- /dev/null +++ b/roms/u-boot/board/gdsys/mpc8308/mpc8308.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2014 + * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc + */ + +#include <common.h> +#include <command.h> +#include <init.h> +#include <asm/processor.h> +#include <asm/io.h> +#include <asm/global_data.h> +#include <linux/delay.h> + +#include "mpc8308.h" +#include <gdsys_fpga.h> + +#define REFLECTION_TESTPATTERN 0xdede +#define REFLECTION_TESTPATTERN_INV (~REFLECTION_TESTPATTERN & 0xffff) + +#ifdef CONFIG_SYS_FPGA_NO_RFL_HI +#define REFLECTION_TESTREG reflection_low +#else +#define REFLECTION_TESTREG reflection_high +#endif + +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_GDSYS_LEGACY_DRIVERS +/* as gpio output status cannot be read back, we have to buffer it locally */ +u32 gpio0_out; + +void setbits_gpio0_out(u32 mask) +{ + immap_t *immr = (immap_t *)CONFIG_SYS_IMMR; + + gpio0_out |= mask; + out_be32(&immr->gpio[0].dat, gpio0_out); +} + +void clrbits_gpio0_out(u32 mask) +{ + immap_t *immr = (immap_t *)CONFIG_SYS_IMMR; + + gpio0_out &= ~mask; + out_be32(&immr->gpio[0].dat, gpio0_out); +} + +int get_fpga_state(uint dev) +{ + return gd->arch.fpga_state[dev]; +} + +int board_early_init_f(void) +{ + uint k; + + for (k = 0; k < CONFIG_SYS_FPGA_COUNT; ++k) + gd->arch.fpga_state[k] = 0; + + return 0; +} + +int board_early_init_r(void) +{ + uint k; + uint ctr; + + for (k = 0; k < CONFIG_SYS_FPGA_COUNT; ++k) + gd->arch.fpga_state[k] = 0; + + /* + * reset FPGA + */ + mpc8308_init(); + + mpc8308_set_fpga_reset(1); + + mpc8308_setup_hw(); + + for (k = 0; k < CONFIG_SYS_FPGA_COUNT; ++k) { + ctr = 0; + while (!mpc8308_get_fpga_done(k)) { + mdelay(100); + if (ctr++ > 5) { + gd->arch.fpga_state[k] |= + FPGA_STATE_DONE_FAILED; + break; + } + } + } + + udelay(10); + + mpc8308_set_fpga_reset(0); + + for (k = 0; k < CONFIG_SYS_FPGA_COUNT; ++k) { + /* + * wait for fpga out of reset + */ + ctr = 0; + while (1) { + u16 val; + + FPGA_SET_REG(k, reflection_low, REFLECTION_TESTPATTERN); + + FPGA_GET_REG(k, REFLECTION_TESTREG, &val); + if (val == REFLECTION_TESTPATTERN_INV) + break; + + mdelay(100); + if (ctr++ > 5) { + gd->arch.fpga_state[k] |= + FPGA_STATE_REFLECTION_FAILED; + break; + } + } + } + + return 0; +} +#endif diff --git a/roms/u-boot/board/gdsys/mpc8308/mpc8308.h b/roms/u-boot/board/gdsys/mpc8308/mpc8308.h new file mode 100644 index 000000000..1e4f24fb2 --- /dev/null +++ b/roms/u-boot/board/gdsys/mpc8308/mpc8308.h @@ -0,0 +1,13 @@ +#ifndef __MPC8308_H_ +#define __MPC8308_H_ + +void setbits_gpio0_out(u32 mask); +void clrbits_gpio0_out(u32 mask); + +/* functions to be provided by board implementation */ +void mpc8308_init(void); +void mpc8308_set_fpga_reset(unsigned state); +void mpc8308_setup_hw(void); +int mpc8308_get_fpga_done(unsigned fpga); + +#endif /* __MPC8308_H_ */ diff --git a/roms/u-boot/board/gdsys/mpc8308/sdram.c b/roms/u-boot/board/gdsys/mpc8308/sdram.c new file mode 100644 index 000000000..bfd55f54e --- /dev/null +++ b/roms/u-boot/board/gdsys/mpc8308/sdram.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2007 Freescale Semiconductor, Inc. + * Copyright (C) 2010 Ilya Yanok, Emcraft Systems, yanok@emcraft.com + * + * Authors: Nick.Spence@freescale.com + * Wilson.Lo@freescale.com + * scottwood@freescale.com + * + * This files is mostly identical to the original from + * board\freescale\mpc8315erdb\sdram.c + */ + +#ifndef CONFIG_MPC83XX_SDRAM + +#include <common.h> +#include <init.h> +#include <mpc83xx.h> +#include <spd_sdram.h> + +#include <asm/bitops.h> +#include <asm/global_data.h> +#include <asm/io.h> + +#include <asm/processor.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* Fixed sdram init -- doesn't use serial presence detect. + * + * This is useful for faster booting in configs where the RAM is unlikely + * to be changed, or for things like NAND booting where space is tight. + */ +static long fixed_sdram(void) +{ + immap_t *im = (immap_t *)CONFIG_SYS_IMMR; + u32 msize = CONFIG_SYS_DDR_SIZE * 1024 * 1024; + u32 msize_log2 = __ilog2(msize); + + out_be32(&im->sysconf.ddrlaw[0].bar, + CONFIG_SYS_SDRAM_BASE & 0xfffff000); + out_be32(&im->sysconf.ddrlaw[0].ar, LBLAWAR_EN | (msize_log2 - 1)); + out_be32(&im->sysconf.ddrcdr, CONFIG_SYS_DDRCDR_VALUE); + + out_be32(&im->ddr.csbnds[0].csbnds, (msize - 1) >> 24); + out_be32(&im->ddr.cs_config[0], CONFIG_SYS_DDR_CS0_CONFIG); + + /* Currently we use only one CS, so disable the other bank. */ + out_be32(&im->ddr.cs_config[1], 0); + + out_be32(&im->ddr.sdram_clk_cntl, CONFIG_SYS_DDR_SDRAM_CLK_CNTL); + out_be32(&im->ddr.timing_cfg_3, CONFIG_SYS_DDR_TIMING_3); + out_be32(&im->ddr.timing_cfg_1, CONFIG_SYS_DDR_TIMING_1); + out_be32(&im->ddr.timing_cfg_2, CONFIG_SYS_DDR_TIMING_2); + out_be32(&im->ddr.timing_cfg_0, CONFIG_SYS_DDR_TIMING_0); + + out_be32(&im->ddr.sdram_cfg, CONFIG_SYS_DDR_SDRAM_CFG); + out_be32(&im->ddr.sdram_cfg2, CONFIG_SYS_DDR_SDRAM_CFG2); + out_be32(&im->ddr.sdram_mode, CONFIG_SYS_DDR_MODE); + out_be32(&im->ddr.sdram_mode2, CONFIG_SYS_DDR_MODE2); + + out_be32(&im->ddr.sdram_interval, CONFIG_SYS_DDR_INTERVAL); + sync(); + + /* enable DDR controller */ + setbits_be32(&im->ddr.sdram_cfg, SDRAM_CFG_MEM_EN); + sync(); + + return get_ram_size(CONFIG_SYS_SDRAM_BASE, msize); +} + +int dram_init(void) +{ + immap_t *im = (immap_t *)CONFIG_SYS_IMMR; + u32 msize; + + if ((in_be32(&im->sysconf.immrbar) & IMMRBAR_BASE_ADDR) != (u32)im) + return -ENXIO; + + /* DDR SDRAM */ + msize = fixed_sdram(); + + /* return total bus SDRAM size(bytes) -- DDR */ + gd->ram_size = msize; + + return 0; +} + +#endif /* !CONFIG_MPC83XX_SDRAM */ |