diff options
author | David Hendricks <dhendricks@fb.com> | 2017-12-01 20:49:48 -0800 |
---|---|---|
committer | Patrick Rudolph <siro@das-labor.org> | 2018-07-10 07:01:57 +0000 |
commit | 8cbd569f74d8929387730e45b0d6e993b1365c02 (patch) | |
tree | ca6414a4d81e37280887b0da0f1a6120a50f0a3a | |
parent | 03d31427338ba59d3a354ac1beb3b0c153471768 (diff) | |
download | coreboot-8cbd569f74d8929387730e45b0d6e993b1365c02.tar.xz |
cavium: Add CN81xx SoC and eval board support
This adds Cavium CN81xx SoC and SFF EVB files.
Code is based off of Cavium's Octeon-TX SDK:
https://github.com/Cavium-Open-Source-Distributions/OCTEON-TX-SDK
BDK coreboot differences:
bootblock:
- Get rid of BDK header
- Add Kconfig for link address
- Move CAR setup code into assembly
- Move unaligned memory access enable into assembly
- Implement custom bootblock entry function
- Add CLIB and CSIB blobs
romstage:
- Use minimal DRAM init only
devicetree:
- Convert FTD to static C file containing key value pairs
Tested on CN81xx:
- Boots to payload
- Tested with GNU/Linux 4.16.3
- All hardware is usable (after applying additional commits)
Implemented in future commits:
- Vboot integration
- MMU suuport
- L2 Cache handling
- ATF from external repo
- Devicetree patching
- Extended DRAM testing
- UART init
Not working:
- Booting a payload
- Booting upstream ATF
TODO:
- Configuration straps
Change-Id: I47b4412d29203b45aee49bfa026c1d86ef7ce688
Signed-off-by: David Hendricks <dhendricks@fb.com>
Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Reviewed-on: https://review.coreboot.org/23037
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: David Hendricks <david.hendricks@gmail.com>
55 files changed, 5750 insertions, 9 deletions
diff --git a/src/mainboard/cavium/Kconfig b/src/mainboard/cavium/Kconfig new file mode 100644 index 0000000000..ec0a791119 --- /dev/null +++ b/src/mainboard/cavium/Kconfig @@ -0,0 +1,30 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2018 Facebook Inc +## +## 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; version 2 of the License. +## +## 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. +## +if VENDOR_CAVIUM + +choice + prompt "Mainboard model" + +source "src/mainboard/cavium/*/Kconfig.name" + +endchoice + +source "src/mainboard/cavium/*/Kconfig" + +config MAINBOARD_VENDOR + string "Mainboard Vendor" + default "Cavium" + +endif # VENDOR_CAVIUM diff --git a/src/mainboard/cavium/Kconfig.name b/src/mainboard/cavium/Kconfig.name new file mode 100644 index 0000000000..e1d0b64d4d --- /dev/null +++ b/src/mainboard/cavium/Kconfig.name @@ -0,0 +1,2 @@ +config VENDOR_CAVIUM + bool "Cavium" diff --git a/src/mainboard/cavium/cn8100_sff_evb/Kconfig b/src/mainboard/cavium/cn8100_sff_evb/Kconfig new file mode 100644 index 0000000000..c311b1dbd8 --- /dev/null +++ b/src/mainboard/cavium/cn8100_sff_evb/Kconfig @@ -0,0 +1,68 @@ +## +## This file is part of the coreboot project. +## +## Copyright 2018 Facebook, Inc. +## +## 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; version 2 of the License. +## +## 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. +## + +if BOARD_CAVIUM_CN8100_SFF_EVB + +config BOARD_SPECIFIC_OPTIONS + def_bool y + select BOARD_ROMSIZE_KB_16384 + select COMMON_CBFS_SPI_WRAPPER + select RTC + select SOC_CAVIUM_CN81XX + select SPI_FLASH + select SPI_FLASH_STMICRO + +config MAINBOARD_DIR + string + default "cavium/cn8100_sff_evb" + +config MAINBOARD_VENDOR + string + default "Cavium" + +config DRAM_SIZE_MB + int + default 8192 + +config BOOT_DEVICE_SPI_FLASH_BUS + int + default 0 + +config CONSOLE_SERIAL_UART_ADDRESS + hex + depends on DRIVERS_UART + default 0x87E028000000 + +config UART_FOR_CONSOLE + int + depends on DRIVERS_UART + default 0 + +config FMDFILE + string + default "src/mainboard/$(CONFIG_MAINBOARD_DIR)/board.fmd" + +########################################################## +#### Update below when adding a new derivative board. #### +########################################################## +config DEVICETREE + string + default "devicetree.cb" + +config MAINBOARD_PART_NUMBER + string + default "CN8100_SFF_EVB" + +endif diff --git a/src/mainboard/cavium/cn8100_sff_evb/Kconfig.name b/src/mainboard/cavium/cn8100_sff_evb/Kconfig.name new file mode 100644 index 0000000000..988be4a8f9 --- /dev/null +++ b/src/mainboard/cavium/cn8100_sff_evb/Kconfig.name @@ -0,0 +1,2 @@ +config BOARD_CAVIUM_CN8100_SFF_EVB + bool "CN8100 SFF EVB" diff --git a/src/mainboard/cavium/cn8100_sff_evb/Makefile.inc b/src/mainboard/cavium/cn8100_sff_evb/Makefile.inc new file mode 100644 index 0000000000..97a03c4d28 --- /dev/null +++ b/src/mainboard/cavium/cn8100_sff_evb/Makefile.inc @@ -0,0 +1,27 @@ +## +## This file is part of the coreboot project. +## +## Copyright 2017-present Facebook, Inc. +## +## 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; version 2 of the License. +## +## 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. +## + +bootblock-y += bootblock.c +bootblock-y += memlayout.ld + +romstage-y += memlayout.ld +romstage-y += romstage.c +romstage-y += bdk_devicetree.c + +ramstage-y += mainboard.c +ramstage-y += memlayout.ld +ramstage-y += bdk_devicetree.c + +verstage-y += memlayout.ld diff --git a/src/mainboard/cavium/cn8100_sff_evb/bdk_devicetree.c b/src/mainboard/cavium/cn8100_sff_evb/bdk_devicetree.c new file mode 100644 index 0000000000..7bc04ce01e --- /dev/null +++ b/src/mainboard/cavium/cn8100_sff_evb/bdk_devicetree.c @@ -0,0 +1,125 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2017-present Facebook, Inc. + * + * 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; version 2 of the License. + * + * 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. + * + */ + +// This file is automatically generated. +// DO NOT EDIT BY HAND. + +#include <bdk-devicetree.h> + +const struct bdk_devicetree_key_value devtree[] = { +{"DDR-CONFIG-DQX-CTL", "0x4"}, +{"DDR-CONFIG-WODT-MASK.RANKS2.DIMMS2", "0xc0c0303"}, +{"DDR-CONFIG-WODT-MASK.RANKS4.DIMMS1", "0x1030203"}, +{"DDR-CONFIG-MODE1-RTT-WR.RANKS1.DIMMS1.RANK0", "0x4"}, +{"DDR-CONFIG-MODE1-RTT-WR.RANKS1.DIMMS2.RANK0", "0x4"}, +{"DDR-CONFIG-MODE1-RTT-WR.RANKS1.DIMMS2.RANK2", "0x4"}, +{"DDR-CONFIG-MODE1-RTT-WR.RANKS2.DIMMS1.RANK0", "0x2"}, +{"DDR-CONFIG-MODE1-RTT-WR.RANKS2.DIMMS1.RANK1", "0x2"}, +{"DDR-CONFIG-MODE1-RTT-WR.RANKS2.DIMMS2", "0x2"}, +{"DDR-CONFIG-MODE1-RTT-WR.RANKS4", "0x1"}, +{"DDR-CONFIG-MODE1-DIC.RANKS4.DIMMS1", "0x1"}, +{"DDR-CONFIG-MODE1-RTT-NOM.RANKS2.DIMMS2", "0x2"}, +{"DDR-CONFIG-MODE1-RTT-NOM.RANKS4.DIMMS1.RANK0", "0x4"}, +{"DDR-CONFIG-MODE1-RTT-NOM.RANKS4.DIMMS1.RANK2", "0x4"}, +{"DDR-CONFIG-MODE2-RTT-PARK.RANKS1.DIMMS1.RANK0", "0x1"}, +{"DDR-CONFIG-MODE2-RTT-PARK.RANKS1.DIMMS2.RANK0", "0x5"}, +{"DDR-CONFIG-MODE2-RTT-PARK.RANKS1.DIMMS2.RANK2", "0x5"}, +{"DDR-CONFIG-MODE2-RTT-PARK.RANKS2.DIMMS1.RANK0", "0x2"}, +{"DDR-CONFIG-MODE2-RTT-PARK.RANKS2.DIMMS1.RANK1", "0x2"}, +{"DDR-CONFIG-MODE2-RTT-PARK.RANKS2.DIMMS2", "0x1"}, +{"DDR-CONFIG-MODE2-RTT-PARK.RANKS4.DIMMS1.RANK0", "0x6"}, +{"DDR-CONFIG-MODE2-RTT-PARK.RANKS4.DIMMS1.RANK1", "0x6"}, +{"DDR-CONFIG-MODE2-VREF-VALUE.RANKS1.DIMMS1.RANK0", "0x22"}, +{"DDR-CONFIG-MODE2-VREF-VALUE.RANKS1.DIMMS2.RANK0", "0x1f"}, +{"DDR-CONFIG-MODE2-VREF-VALUE.RANKS1.DIMMS2.RANK2", "0x1f"}, +{"DDR-CONFIG-MODE2-VREF-VALUE.RANKS2.DIMMS1.RANK0", "0x19"}, +{"DDR-CONFIG-MODE2-VREF-VALUE.RANKS2.DIMMS1.RANK1", "0x19"}, +{"DDR-CONFIG-MODE2-VREF-VALUE.RANKS2.DIMMS2", "0x19"}, +{"DDR-CONFIG-MODE2-VREF-VALUE.RANKS4.DIMMS1.RANK0", "0x1f"}, +{"DDR-CONFIG-MODE2-VREF-VALUE.RANKS4.DIMMS1.RANK1", "0x1f"}, +{"DDR-CONFIG-RODT-CTL.RANKS1.DIMMS1", "0x7"}, +{"DDR-CONFIG-RODT-CTL.RANKS1.DIMMS2", "0x3"}, +{"DDR-CONFIG-RODT-CTL.RANKS2.DIMMS1", "0x3"}, +{"DDR-CONFIG-RODT-CTL.RANKS2.DIMMS2", "0x7"}, +{"DDR-CONFIG-RODT-CTL.RANKS4.DIMMS1", "0x7"}, +{"DDR-CONFIG-RODT-MASK.RANKS2.DIMMS2", "0x4080102"}, +{"DDR-CONFIG-RODT-MASK.RANKS4.DIMMS1", "0x1010202"}, +{"DDR-CONFIG-CUSTOM-MIN-RTT-NOM-IDX", "0x1"}, +{"DDR-CONFIG-CUSTOM-MAX-RTT-NOM-IDX", "0x7"}, +{"DDR-CONFIG-CUSTOM-MIN-RODT-CTL", "0x1"}, +{"DDR-CONFIG-CUSTOM-MAX-RODT-CTL", "0x7"}, +{"DDR-CONFIG-CUSTOM-CK-CTL", "0x4"}, +{"DDR-CONFIG-CUSTOM-CMD-CTL", "0x4"}, +{"DDR-CONFIG-CUSTOM-CTL-CTL", "0x4"}, +{"DDR-CONFIG-CUSTOM-OFFSET-EN", "0x1"}, +{"DDR-CONFIG-CUSTOM-OFFSET", "0x2"}, +{"DDR-CONFIG-CUSTOM-DDR2T", "0x1"}, +{"DDR-CONFIG-CUSTOM-MAXIMUM-ADJACENT-RLEVEL-DELAY-INCREMENT", "0x2"}, +{"DDR-CONFIG-CUSTOM-FPRCH2", "0x2"}, +{"PHY-ADDRESS.N0.BGX0.P0", "0xff000010"}, +{"PHY-ADDRESS.N0.BGX0.P1", "0xff000011"}, +{"PHY-ADDRESS.N0.BGX0.P2", "0xff000012"}, +{"PHY-ADDRESS.N0.BGX0.P3", "0xff000013"}, +{"PHY-ADDRESS.N0.BGX1.P0", "0xff002014"}, +{"PHY-ADDRESS.N0.BGX1.P1", "0xff002014"}, +{"PHY-ADDRESS.N0.BGX2.P0", "0xff000000"}, +{"BGX-ENABLE.N0.BGX0.P0", "1"}, +{"BGX-ENABLE.N0.BGX0.P1", "1"}, +{"BGX-ENABLE.N0.BGX0.P2", "1"}, +{"BGX-ENABLE.N0.BGX0.P3", "1"}, +{"BGX-ENABLE.N0.BGX1.P0", "1"}, +{"BGX-ENABLE.N0.BGX1.P1", "1"}, +{"BGX-ENABLE.N0.BGX2.P0", "1"}, +{"BDK-NUM-PACKET-BUFFERS", "0x1000"}, +{"BDK-PACKET-BUFFER-SIZE", "0x400"}, +{"BDK-SHOW-LINK-STATUS", "1"}, +{"BDK-COREMASK", "0"}, +{"MULTI-NODE", "0"}, +{"QLM-AUTO-CONFIG", "0"}, +{"QLM-DIP-AUTO-CONFIG", "1"}, +{"DDR-SPEED.N0", "1333"}, +{"DDR-CONFIG-SPD-ADDR.DIMM0.LMC0", "0x1050"}, +{"USB-PWR-GPIO.N0.PORT0", "12"}, +{"USB-PWR-GPIO-POLARITY.N0.PORT0", "0"}, +{"USB-REFCLK-SRC.N0.PORT0", "0"}, +{"GPIO-PIN-SELECT-GPIO15", "0x24f"}, +{"GPIO-PIN-SELECT-GPIO16", "0x24e"}, +{"GPIO-PIN-SELECT-GPIO17", "0x24b"}, +{"GPIO-PIN-SELECT-GPIO18", "0x247"}, +{"GPIO-PIN-SELECT-GPIO19", "0x24d"}, +{"GPIO-PIN-SELECT-GPIO20", "0x24c"}, +{"GPIO-PIN-SELECT-GPIO37", "0x24a"}, +{"GPIO-PIN-SELECT-GPIO38", "0x246"}, +{"GPIO-PIN-SELECT-GPIO7", "0xe1"}, +{"GPIO-PIN-SELECT-GPIO24", "0xeb"}, +{"GPIO-PIN-SELECT-GPIO27", "0xed"}, +{"GPIO-PIN-SELECT-GPIO28", "0xe3"}, +{"GPIO-PIN-SELECT-GPIO29", "0xe0"}, +{"GPIO-PIN-SELECT-GPIO30", "0xe2"}, +{"GPIO-PIN-SELECT-GPIO40", "0x112"}, +{"GPIO-PIN-SELECT-GPIO41", "0x113"}, +{"GPIO-PIN-SELECT-GPIO42", "0x114"}, +{"GPIO-PIN-SELECT-GPIO43", "0x115"}, +{"GPIO-PIN-SELECT-GPIO44", "0x116"}, +{"GPIO-PIN-SELECT-GPIO45", "0x117"}, +{"GPIO-PIN-SELECT-GPIO46", "0x118"}, +{"GPIO-PIN-SELECT-GPIO47", "0x119"}, +{"GPIO-POLARITY-GPIO7", "1"}, +{"GPIO-POLARITY-GPIO27", "1"}, +{"GPIO-POLARITY-GPIO28", "1"}, +{"GPIO-POLARITY-GPIO30", "1"}, +{0, 0}, +}; diff --git a/src/mainboard/cavium/cn8100_sff_evb/board.fmd b/src/mainboard/cavium/cn8100_sff_evb/board.fmd new file mode 100644 index 0000000000..19987274ff --- /dev/null +++ b/src/mainboard/cavium/cn8100_sff_evb/board.fmd @@ -0,0 +1,24 @@ +FLASH@0x0 8M { + WP_RO@0x0 0x400000 { + RO_SECTION@0x0 0x200000 { + # bootblock includes trusted/non-trusted CLIB, CSIB, + # and BL1FWs packaged in + # src/soc/cavium/common/Makefile.inc. + BOOTBLOCK@0x10000 0x70000 + FMAP@0x90000 0x1000 + COREBOOT(CBFS)@0x100000 0x100000 + } + } + RW_SECTION_A@0x400000 0xe8000 { + VBLOCK_A@0x0 0x2000 + FW_MAIN_A(CBFS)@0x2000 0xe5f00 + RW_FWID_A@0xe7f00 0x100 + } + RW_UNUSED@0x4e8000 0x8000 + RW_ELOG@0x5d8000 0x1000 + RW_SHARED@0x5e0000 0x10000 { + SHARED_DATA@0x0 0x10000 + } + RW_NVRAM@0x5f0000 0x10000 + CONSOLE@0x700000 0x100000 +} diff --git a/src/mainboard/cavium/cn8100_sff_evb/board_info.txt b/src/mainboard/cavium/cn8100_sff_evb/board_info.txt new file mode 100644 index 0000000000..98a6c46b7f --- /dev/null +++ b/src/mainboard/cavium/cn8100_sff_evb/board_info.txt @@ -0,0 +1,6 @@ +Vendor name: Cavium +Board name: CN81XX SFF EVB +Category: eval +ROM protocol: SPI +ROM socketed: n +Flashrom support: n diff --git a/src/mainboard/cavium/cn8100_sff_evb/bootblock.c b/src/mainboard/cavium/cn8100_sff_evb/bootblock.c new file mode 100644 index 0000000000..36332cc6e3 --- /dev/null +++ b/src/mainboard/cavium/cn8100_sff_evb/bootblock.c @@ -0,0 +1,46 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 Facebook, Inc. + * + * 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; version 2 of the License. + * + * 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. + */ + +#include <bootblock_common.h> +#include <soc/soc.h> +#include <soc/spi.h> +#include <soc/uart.h> + +void bootblock_mainboard_early_init(void) +{ + if (IS_ENABLED(CONFIG_BOOTBLOCK_CONSOLE)) { + if (!uart_is_enabled(0)) + uart_setup(0, CONFIG_TTYS0_BAUD); + if (!uart_is_enabled(1)) + uart_setup(0, CONFIG_TTYS0_BAUD); + } +} + +static void configure_spi_flash(void) +{ + /* FIXME: Only tested on EM100 Pro */ + spi_init_custom(0, // bus + 25000000, // speed Hz + 0, // idle low disabled + 0, // zero idle cycles between transfers + 0, // MSB first + 0, // Chip select 0 + 1); // assert is high +} + +void bootblock_mainboard_init(void) +{ + configure_spi_flash(); +} diff --git a/src/mainboard/cavium/cn8100_sff_evb/cn81xx-linux.dtsi b/src/mainboard/cavium/cn8100_sff_evb/cn81xx-linux.dtsi new file mode 100644 index 0000000000..d82b5ac05e --- /dev/null +++ b/src/mainboard/cavium/cn8100_sff_evb/cn81xx-linux.dtsi @@ -0,0 +1,496 @@ +/* + * Cavium Thunder DTS file - Thunder SoC description + * + * Copyright (C) 2016, Cavium Inc. + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) 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; version 2 of the License. + * + * 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/ { + model = "Cavium ThunderX CN81XX board"; + compatible = "cavium,thunder-81xx"; + interrupt-parent = <&gic0>; + #address-cells = <2>; + #size-cells = <2>; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + core1 { + cpu = <&CPU1>; + }; + core2 { + cpu = <&CPU2>; + }; + core3 { + cpu = <&CPU3>; + }; + }; + }; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "cavium,thunder", "arm,armv8"; + reg = <0x0 0x000>; + enable-method = "psci"; + /* socket 0 */ + numa-node-id = <0>; + next-level-cache = <&thunderx_L2_0>; + }; + CPU1: cpu@1 { + device_type = "cpu"; + compatible = "cavium,thunder", "arm,armv8"; + reg = <0x0 0x001>; + enable-method = "psci"; + numa-node-id = <0>; + next-level-cache = <&thunderx_L2_0>; + }; + CPU2: cpu@2 { + device_type = "cpu"; + compatible = "cavium,thunder", "arm,armv8"; + reg = <0x0 0x002>; + enable-method = "psci"; + numa-node-id = <0>; + next-level-cache = <&thunderx_L2_0>; + }; + CPU3: cpu@3 { + device_type = "cpu"; + compatible = "cavium,thunder", "arm,armv8"; + reg = <0x0 0x003>; + enable-method = "psci"; + numa-node-id = <0>; + next-level-cache = <&thunderx_L2_0>; + }; + }; + + thunderx_L2_0: l2-cache0 { + compatible = "cache"; + numa-node-id = <0>; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <1 13 4>, + <1 14 4>, + <1 11 4>, + <1 10 4>; + }; + + pmu { + compatible = "cavium,thunder-pmu", "arm,armv8-pmuv3"; + interrupts = <1 7 4>; + }; + + mmc_supply_3v3: mmc_supply_3v3 { + compatible = "regulator-fixed"; + regulator-name = "mmc_supply_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + gpio = <&gpio_6_0 8 0>; + enable-active-high; + }; + + gic0: interrupt-controller@801000000000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + #address-cells = <2>; + #size-cells = <2>; + #redistributor-regions = <1>; + ranges; + interrupt-controller; + reg = <0x8010 0x00000000 0x0 0x010000>, /* GICD */ + <0x8010 0x80000000 0x0 0x600000>; /* GICR */ + interrupts = <1 9 4>; + + its: gic-its@801000020000 { + compatible = "arm,gic-v3-its"; + reg = <0x8010 0x20000 0x0 0x200000>; + msi-controller; + numa-node-id = <0>; + }; + }; + + soc@0 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + numa-node-id = <0>; + + refclkuaa: refclkuaa { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <116640000>; + clock-output-names = "refclkuaa"; + }; + + sclk: sclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <800000000>; + clock-output-names = "sclk"; + }; + + uaa0: serial@87e028000000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x87e0 0x28000000 0x0 0x1000>; + interrupts = <0 5 4>; + clocks = <&refclkuaa>; + clock-names = "apb_pclk"; + skip-init; + }; + + uaa1: serial@87e029000000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x87e0 0x29000000 0x0 0x1000>; + interrupts = <0 6 4>; + clocks = <&refclkuaa>; + clock-names = "apb_pclk"; + skip-init; + }; + + uaa2: serial@87e02a000000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x87e0 0x2a000000 0x0 0x1000>; + interrupts = <0 7 4>; + clocks = <&refclkuaa>; + clock-names = "apb_pclk"; + skip-init; + }; + + uaa3: serial@87e02b000000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x87e0 0x2b000000 0x0 0x1000>; + interrupts = <0 8 4>; + clocks = <&refclkuaa>; + clock-names = "apb_pclk"; + skip-init; + }; + + watch-dog@8440000a0000 { + compatible = "arm,sbsa-gwdt"; + reg = <0x8440 0xa0000 0x0 0x1000>, <0x8440 0xb0000 0x0 0x1000>; + interrupts = <0 9 4>; + }; + + pbus0: nor@0 { + compatible = "cfi-flash"; + reg = <0x8000 0x0 0x0 0x800000>; + device-width = <1>; + bank-width = <1>; + clocks = <&sclk>; + }; + + smmu0@830000000000 { + compatible = "cavium,smmu-v2"; + reg = <0x8300 0x0 0x0 0x2000000>; + #global-interrupts = <1>; + interrupts = <0 68 4>, <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, + <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, + <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, + <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, + <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, + <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, + <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, + <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, + <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, + <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, + <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>, <0 69 4>; + + mmu-masters = <&ecam0 0x100>, + <&pem0 0x200>, + <&pem1 0x300>, + <&pem2 0x400>; + + }; + + ecam0: pci@848000000000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + msi-parent = <&its>; + msi-map = <0 &its 0 0x10000>; + bus-range = <0 31>; + #size-cells = <2>; + #address-cells = <3>; + #stream-id-cells = <1>; + u-boot,dm-pre-reloc; + dma-coherent; + reg = <0x8480 0x00000000 0 0x02000000>; /* Configuration space */ + ranges = <0x03000000 0x8010 0x00000000 0x8010 0x00000000 0x080 0x00000000>, /* mem ranges */ + <0x03000000 0x8100 0x00000000 0x8100 0x00000000 0x80 0x00000000>, /* SATA */ + <0x03000000 0x8680 0x00000000 0x8680 0x00000000 0x160 0x28000000>, /* UARTs */ + <0x03000000 0x87e0 0x2c000000 0x87e0 0x2c000000 0x000 0x94000000>, /* PEMs */ + <0x03000000 0x8400 0x00000000 0x8400 0x00000000 0x010 0x00000000>, /* RNM */ + <0x03000000 0x8430 0x00000000 0x8430 0x00000000 0x02 0x00000000>, /* NIC0*/ + <0x03000000 0x87e0 0xc6000000 0x87e0 0xc6000000 0x01f 0x3a000000>; + + mrml_bridge: mrml-bridge0@1,0 { + compatible = "pci-bridge", "cavium,thunder-8890-mrml-bridge"; + #size-cells = <2>; + #address-cells = <3>; + ranges = <0x03000000 0x87e0 0x00000000 0x03000000 0x87e0 0x00000000 0x10 0x00000000>; + reg = <0x0800 0 0 0 0>; /* DEVFN = 0x08 (1:0) */ + device_type = "pci"; + u-boot,dm-pre-reloc; + + mdio-nexus@1,3 { + compatible = "cavium,thunder-8890-mdio-nexus"; + #address-cells = <2>; + #size-cells = <2>; + reg = <0x0b00 0 0 0 0>; /* DEVFN = 0x0b (1:3) */ + assigned-addresses = <0x03000000 0x87e0 0x05000000 0x0 0x800000>; + ranges = <0x87e0 0x05000000 0x03000000 0x87e0 0x05000000 0x0 0x800000>; + mdio0@87e005003800 { + compatible = "cavium,thunder-8890-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x87e0 0x05003800 0x0 0x30>; + }; + mdio1@87e005003880 { + compatible = "cavium,thunder-8890-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x87e0 0x05003880 0x0 0x30>; + }; + }; + + mmc_1_4: mmc@1,4 { + compatible = "cavium,thunder-8890-mmc"; + reg = <0x0c00 0 0 0 0>; /* DEVFN = 0x0c (1:4) */ + #address-cells = <1>; + #size-cells = <0>; + clocks = <&sclk>; + }; + + i2c_9_0: i2c@9,0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "cavium,thunder-8890-twsi"; + reg = <0x4800 0 0 0 0>; /* DEVFN = 0x48 (9:0) */ + clock-frequency = <100000>; + clocks = <&sclk>; + u-boot,dm-pre-reloc; + }; + + i2c_9_1: i2c@9,1 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "cavium,thunder-8890-twsi"; + reg = <0x4900 0 0 0 0>; /* DEVFN = 0x49 (9:1) */ + clock-frequency = <100000>; + clocks = <&sclk>; + u-boot,dm-pre-reloc; + }; + + rgx0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "cavium,thunder-8890-bgx"; + reg = <0x9000 0 0 0 0>; /* DEVFN = 0x90 (16:1) */ + }; + bgx0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "cavium,thunder-8890-bgx"; + reg = <0x8000 0 0 0 0>; /* DEVFN = 0x80 (16:0) */ + }; + bgx1 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "cavium,thunder-8890-bgx"; + reg = <0x8100 0 0 0 0>; /* DEVFN = 0x81 (16:1) */ + }; + }; + + spi_7_0: spi@7,0 { + compatible = "cavium,thunder-8190-spi"; + reg = <0x3800 0x0 0x0 0x0 0x0>; /* DEVFN = 0x38 (7:0) */ + #address-cells = <1>; + #size-cells = <0>; + clocks = <&sclk>; + }; + + gpio_6_0: gpio0@6,0 { + #gpio-cells = <2>; + compatible = "cavium,thunder-8890-gpio"; + gpio-controller; + reg = <0x3000 0 0 0 0>; /* DEVFN = 0x30 (6:0) */ + u-boot,dm-pre-reloc; + }; + + nfc: nand@b,0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "cavium,cn8130-nand"; + reg = <0x5800 0 0 0 0>; /* DEVFN = 0x58 (b:0) */ + clocks = <&sclk>; + }; + }; + + pem0: pci@87e0c0000000 { + + /* "cavium,pci-host-thunder-pem" implies that + the first bus in bus-range has config access + via the "PEM space", subsequent buses have + config assess via the "Configuration space". + The "mem64 PEM" range is used to map the PEM + BAR0, which is used by the AER and PME MSI-X + sources. UEFI and Linux must assign the same + bus number to each device, otherwise Linux + enumeration gets confused. Because UEFI + skips the PEM bus and its PCIe-RC bridge it + uses a numbering that starts 1 bus higher. + */ + + compatible = "cavium,pci-host-thunder-pem"; + device_type = "pci"; + msi-parent = <&its>; + msi-map = <0 &its 0 0x10000>; + bus-range = <0x1f 0x57>; + #size-cells = <2>; + #address-cells = <3>; + #stream-id-cells = <1>; + dma-coherent; + reg = <0x8800 0x1f000000 0x0 0x39000000>, /* Configuration space */ + <0x87e0 0xc0000000 0x0 0x01000000>; /* PEM space */ + ranges = <0x01000000 0x00 0x00000000 0x8830 0x00000000 0x00 0x00010000>, /* I/O */ + <0x03000000 0x00 0x10000000 0x8810 0x10000000 0x0f 0xf0000000>, /* mem64 */ + <0x43000000 0x10 0x00000000 0x8820 0x00000000 0x10 0x00000000>, /* mem64-pref */ + <0x03000000 0x87e0 0xc0000000 0x87e0 0xc0000000 0x00 0x01000000>; /* mem64 PEM */ + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic0 0 0 0 16 4>, /* INTA */ + <0 0 0 2 &gic0 0 0 0 17 4>, /* INTB */ + <0 0 0 3 &gic0 0 0 0 18 4>, /* INTC */ + <0 0 0 4 &gic0 0 0 0 19 4>; /* INTD */ + }; + + pem1: pci@87e0c1000000 { + compatible = "cavium,pci-host-thunder-pem"; + device_type = "pci"; + msi-parent = <&its>; + msi-map = <0 &its 0 0x10000>; + bus-range = <0x57 0x8f>; + #size-cells = <2>; + #address-cells = <3>; + #stream-id-cells = <1>; + dma-coherent; + reg = <0x8840 0x57000000 0x0 0x39000000>, /* Configuration space */ + <0x87e0 0xc1000000 0x0 0x01000000>; /* PEM space */ + ranges = <0x01000000 0x00 0x00010000 0x8870 0x00010000 0x00 0x00010000>, /* I/O */ + <0x03000000 0x00 0x10000000 0x8850 0x10000000 0x0f 0xf0000000>, /* mem64 */ + <0x43000000 0x10 0x00000000 0x8860 0x00000000 0x10 0x00000000>, /* mem64-pref */ + <0x03000000 0x87e0 0xc1000000 0x87e0 0xc1000000 0x00 0x01000000>; /* mem64 PEM */ + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic0 0 0 0 20 4>, /* INTA */ + <0 0 0 2 &gic0 0 0 0 21 4>, /* INTB */ + <0 0 0 3 &gic0 0 0 0 22 4>, /* INTC */ + <0 0 0 4 &gic0 0 0 0 23 4>; /* INTD */ + }; + + pem2: pci@87e0c2000000 { + compatible = "cavium,pci-host-thunder-pem"; + device_type = "pci"; + msi-parent = <&its>; + msi-map = <0 &its 0 0x10000>; + bus-range = <0x8f 0xc7>; + #size-cells = <2>; + #address-cells = <3>; + #stream-id-cells = <1>; + dma-coherent; + reg = <0x8880 0x8f000000 0x0 0x39000000>, /* Configuration space */ + <0x87e0 0xc2000000 0x0 0x01000000>; /* PEM space */ + ranges = <0x01000000 0x00 0x00020000 0x88b0 0x00020000 0x00 0x00010000>, /* I/O */ + <0x03000000 0x00 0x10000000 0x8890 0x10000000 0x0f 0xf0000000>, /* mem64 */ + <0x43000000 0x10 0x00000000 0x88a0 0x00000000 0x10 0x00000000>, /* mem64-pref */ + <0x03000000 0x87e0 0xc2000000 0x87e0 0xc2000000 0x00 0x01000000>; /* mem64 PEM */ + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic0 0 0 0 24 4>, /* INTA */ + <0 0 0 2 &gic0 0 0 0 25 4>, /* INTB */ + <0 0 0 3 &gic0 0 0 0 26 4>, /* INTC */ + <0 0 0 4 &gic0 0 0 0 27 4>; /* INTD */ + }; + + tdm: tdm@d,0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "cavium,thunder-8190-tdm"; + reg = <0x6800 0 0 0>; /* DEVFN = 0x68 (d:0) */ + clocks = <&sclk>; + }; + }; + + aliases { + serial0 = &uaa0; + serial1 = &uaa1; + serial2 = &uaa2; + serial3 = &uaa3; + i2c0 = &i2c_9_0; + i2c1 = &i2c_9_1; + spi0 = &spi_7_0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + + memory@0 { + device_type = "memory"; + reg = <0x0 0x01400000 0x0 0x7EC00000>; + /* socket 0 */ + numa-node-id = <0>; + }; +}; diff --git a/src/mainboard/cavium/cn8100_sff_evb/ddr4-common.dtsi b/src/mainboard/cavium/cn8100_sff_evb/ddr4-common.dtsi new file mode 100644 index 0000000000..72ff649014 --- /dev/null +++ b/src/mainboard/cavium/cn8100_sff_evb/ddr4-common.dtsi @@ -0,0 +1,802 @@ +/***********************license start*********************************** +* Copyright (c) 2003-2016 Cavium Inc. (support@cavium.com). All rights +* reserved. +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* +* * Neither the name of Cavium Inc. nor the names of +* its contributors may be used to endorse or promote products +* derived from this software without specific prior written +* permission. +* +* This Software, including technical data, may be subject to U.S. export +* control laws, including the U.S. Export Administration Act and its +* associated regulations, and may be subject to export or import +* regulations in other countries. +* +* TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" +* AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR +* WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT +* TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY +* REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT +* DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES +* OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR +* PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, +* QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK +* ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU. +***********************license end**************************************/ +/ { +cavium,bdk { + /* Speed grade to use for DRAM in MT/s. Hardware may adjust this value + slightly to improve DRAM stability, so scope measurements may not + exactly match the frequency with MT/s. The Cavium supported speed + grades are: + 0 (auto-set from SPD contents) + 666 MT/s (DDR3 only) + 800 MT/s (DDR3 only) + 1066 MT/s (DDR3 only) + 1333 MT/s (DDR3 only) + 1600 MT/s + 1866 MT/s + 2133 MT/s (DDR4 only) + Parameters: + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-SPEED.N%d = "0"; + + /* Set to use a an alternate reference clock for DRAM than the usual + 50Mhz reference. The value of here specifies the frequency of the + alternate clock in Mhz. Currently the only supported reference + clock frequencies are 50Mhz and 100Mhz. + Parameters: + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-ALT-REFCLK.N%d = "0"; + + /* TWSI address of the DIMM SPD. The encoding of this address is + : [15:12]: TWSI bus the DIMM is connected to. + [11:7]: Reserved, set to zero. + [6:0]: TWSI address for the DIMM. + A value of zero means the DIMMs are not accessible. Hard coded + values will be read from DDR-CONFIG-SPD-DATA.Parameters: + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-SPD-ADDR.DIMM%d.LMC%d.N%d = "0"; + // Note: The SPD addresses are not specified here so boards don't + // inherit a default. The default causes trouble with UEFI when it + // builds SMBIOS tables. + + /* DIMM SPD data to be used if memory doesn't support the standard + TWSI access to DIMM SPDs. The format of this is a binary blob + stored in the device tree. An example would be: + Parameters: + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-SPD-DATA.DIMM%d.LMC%d.N%d = []; + + /* Drive strength control for DDR_DQ* / DDR_DQS_*_P/N drivers. + 0x1 = 24 ohm. + 0x2 = 26.67 ohm. + 0x3 = 30 ohm. + 0x4 = 34.3 ohm. + 0x5 = 40 ohm. + 0x6 = 48 ohm. + 0x7 = 60 ohm. + _ else = Reserved. + Parameters: + RANKS#: Specifies that this parameter only applies to DIMMs + with the supplied number of ranks. Support ranks is 1, 2, + or 4. Optional. + DIMMS#: Specifies that this parameter only applies when the + DIMMs per memory controller matches. Support number of + DIMMs is 1 or 2. Optional. + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-DQX-CTL.RANKS%d.DIMMS%d.LMC%d.N%d = "0"; + DDR-CONFIG-DQX-CTL = "0x4"; + + /* LMC Write OnDieTermination Mask Register + System designers may desire to terminate DQ/DQS lines for + higher-frequency DDR operations, especially on a multirank system. + DDR3 DQ/DQS I/Os have built-in termination resistors that can be + turned on or off by the controller, after meeting TAOND and TAOF + timing requirements. Each rank has its own ODT pin that fans out + to all of the memory parts in that DIMM. System designers may + prefer different combinations of ODT ONs for write operations into + different ranks. CNXXXX supports full programmability by way of + the mask register below. Each rank position has its own 8-bit + programmable field. When the controller does a write to that rank, + it sets the 4 ODT pins to the mask pins below. For example, when + doing a write into Rank0, a system designer may desire to terminate + the lines with the resistor on DIMM0/Rank1. The mask WODT_D0_R0 + would then be {00000010}. + CNXXXX drives the appropriate mask values on the ODT pins by + default. If this feature is not required, write 0x0 in this + register. When a given RANK is selected, the WODT mask for that + RANK is used. + Parameters: + RANKS#: Specifies that this parameter only applies to DIMMs + with the supplied number of ranks. Support ranks is 1, 2, + or 4. Optional. + DIMMS#: Specifies that this parameter only applies when the + DIMMs per memory controller matches. Support number of + DIMMs is 1 or 2. Optional. + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-WODT-MASK.RANKS%d.DIMMS%d.LMC%d.N%d = "0"; + DDR-CONFIG-WODT-MASK.RANKS2.DIMMS2 = "0xc0c0303"; + DDR-CONFIG-WODT-MASK.RANKS4.DIMMS1 = "0x1030203"; + + /* Partial array self-refresh per rank. LMC writes this value to + MR2[PASR] in the rank (i.e. DIMM0_CS0) DDR3 parts when selected + during power-up/init, write-leveling, and, if + LMC()_CONFIG[SREF_WITH_DLL] is set, self-refresh entry and exit + instruction sequences. See LMC()_SEQ_CTL[SEQ_SEL,INIT_START] and + LMC()_CONFIG[RANKMASK] and LMC()_RESET_CTL[DDR3PWARM,DDR3PSOFT]. + Parameters: + RANKS#: Specifies that this parameter only applies to DIMMs + with the supplied number of ranks. Support ranks is 1, 2, + or 4. Optional. + DIMMS#: Specifies that this parameter only applies when the + DIMMs per memory controller matches. Support number of + DIMMs is 1 or 2. Optional. + RANK#: Parameter can be different for each rank of a DIMM. This + specifies which rank the value is for. Rank must be + 0-3. Optional. + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-MODE1-PASR.RANKS%d.DIMMS%d.RANK%d.LMC%d.N%d = "0"; + + /* Auto self-refresh per rank. LMC writes this value to MR2[ASR] in + the rank (i.e. DIMM0_CS0) DDR3 parts when selected during + power-up/init, write-leveling, and, if LMC()_CONFIG[SREF_WITH_DLL] + is set, self-refresh entry and exit instruction sequences. See + LMC()_SEQ_CTL[SEQ_SEL,INIT_START] and LMC()_CONFIG[RANKMASK] and + LMC()_RESET_CTL [DDR3PWARM,DDR3PSOFT]. + Parameters: + RANKS#: Specifies that this parameter only applies to DIMMs + with the supplied number of ranks. Support ranks is 1, 2, + or 4. Optional. + DIMMS#: Specifies that this parameter only applies when the + DIMMs per memory controller matches. Support number of + DIMMs is 1 or 2. Optional. + RANK#: Parameter can be different for each rank of a DIMM. This + specifies which rank the value is for. Rank must be + 0-3. Optional. + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-MODE1-ASR.RANKS%d.DIMMS%d.RANK%d.LMC%d.N%d = "0"; + + /* Self-refresh temperature range per rank. LMC writes this value to + MR2[SRT] in the rank (i.e. DIMM0_CS0) DDR3 parts when selected + during power-up/init, write-leveling, and, if + LMC()_CONFIG[SREF_WITH_DLL] is set, self-refresh entry and exit + instruction sequences. See LMC()_SEQ_CTL[SEQ_SEL,INIT_START] and + LMC()_CONFIG[RANKMASK] and LMC()_RESET_CTL[DDR3PWARM,DDR3PSOFT]. + Parameters: + RANKS#: Specifies that this parameter only applies to DIMMs + with the supplied number of ranks. Support ranks is 1, 2, + or 4. Optional. + DIMMS#: Specifies that this parameter only applies when the + DIMMs per memory controller matches. Support number of + DIMMs is 1 or 2. Optional. + RANK#: Parameter can be different for each rank of a DIMM. This + specifies which rank the value is for. Rank must be + 0-3. Optional. + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-MODE1-SRT.RANKS%d.DIMMS%d.RANK%d.LMC%d.N%d = "0"; + + /* RTT_WR per rank. LMC writes this value to MR2[RTT_WR] in the rank + (i.e. DIMM0_CS0) DDR3 parts when selected during power-up/init, + write-leveling, and, if LMC()_CONFIG[SREF_WITH_DLL] is set, + self-refresh entry and exit instruction sequences. See + LMC()_SEQ_CTL[SEQ_SEL,INIT_START] and LMC()_CONFIG[RANKMASK] and + LMC()_RESET_CTL[DDR3PWARM, DDR3PSOFT]. + Parameters: + RANKS#: Specifies that this parameter only applies to DIMMs + with the supplied number of ranks. Support ranks is 1, 2, + or 4. Optional. + DIMMS#: Specifies that this parameter only applies when the + DIMMs per memory controller matches. Support number of + DIMMs is 1 or 2. Optional. + RANK#: Parameter can be different for each rank of a DIMM. This + specifies which rank the value is for. Rank must be + 0-3. Optional. + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-MODE1-RTT-WR.RANKS%d.DIMMS%d.RANK%d.LMC%d.N%d = "0"; + + //DDR-CONFIG-MODE1-RTT-WR.RANKS1 = "0x4"; + DDR-CONFIG-MODE1-RTT-WR.RANKS1.DIMMS1.RANK0 = "0x4"; + DDR-CONFIG-MODE1-RTT-WR.RANKS1.DIMMS2.RANK0 = "0x4"; + DDR-CONFIG-MODE1-RTT-WR.RANKS1.DIMMS2.RANK2 = "0x4"; + + //DDR-CONFIG-MODE1-RTT-WR.RANKS2 = "0x2"; + DDR-CONFIG-MODE1-RTT-WR.RANKS2.DIMMS1.RANK0 = "0x2"; + DDR-CONFIG-MODE1-RTT-WR.RANKS2.DIMMS1.RANK1 = "0x2"; + DDR-CONFIG-MODE1-RTT-WR.RANKS2.DIMMS2 = "0x2"; + + DDR-CONFIG-MODE1-RTT-WR.RANKS4 = "0x1"; + + /* Output driver impedance control per rank. LMC writes this value + to MR1[D.I.C.] in the rank (i.e. DIMM0_CS0) DDR3 parts when + selected during power-up/init, write-leveling, and, if + LMC()_CONFIG[SREF_WITH_DLL] is set, self-refresh entry and exit + instruction sequences. See LMC()_SEQ_CTL[SEQ_SEL,INIT_START] and + LMC()_CONFIG[RANKMASK] and LMC()_RESET_CTL[DDR3PWARM,DDR3PSOFT]. + Parameters: + RANKS#: Specifies that this parameter only applies to DIMMs + with the supplied number of ranks. Support ranks is 1, 2, + or 4. Optional. + DIMMS#: Specifies that this parameter only applies when the + DIMMs per memory controller matches. Support number of + DIMMs is 1 or 2. Optional. + RANK#: Parameter can be different for each rank of a DIMM. This + specifies which rank the value is for. Rank must be + 0-3. Optional. + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-MODE1-DIC.RANKS%d.DIMMS%d.RANK%d.LMC%d.N%d = "0"; + DDR-CONFIG-MODE1-DIC.RANKS4.DIMMS1 = "0x1"; + + /* RTT_NOM per rank. LMC writes this value to MR1[RTT_NOM] in the + rank (i.e. DIMM0_CS0) DDR3 parts when selected during + power-up/init, write-leveling, and, if LMC()_CONFIG[SREF_WITH_DLL] + is set, self-refresh entry and exit instruction sequences. See + LMC()_SEQ_CTL[SEQ_SEL,INIT_START] and LMC()_CONFIG[RANKMASK] and + LMC()_RESET_CTL[DDR3PWARM, DDR3PSOFT]. Per JEDEC DDR3 + specifications, if RTT_NOM is used during write operations, only + values MR1[RTT_NOM] = 1 (RZQ/4), 2 (RZQ/2), or 3 (RZQ/6) are + allowed. Otherwise, values MR1[RTT_NOM] = 4 (RZQ/12) and 5 (RZQ/8) + are also allowed. + Parameters: + RANKS#: Specifies that this parameter only applies to DIMMs + with the supplied number of ranks. Support ranks is 1, 2, + or 4. Optional. + DIMMS#: Specifies that this parameter only applies when the + DIMMs per memory controller matches. Support number of + DIMMs is 1 or 2. Optional. + RANK#: Parameter can be different for each rank of a DIMM. This + specifies which rank the value is for. Rank must be + 0-3. Optional. + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-MODE1-RTT-NOM.RANKS%d.DIMMS%d.RANK%d.LMC%d.N%d = "0"; + DDR-CONFIG-MODE1-RTT-NOM.RANKS2.DIMMS2 = "0x2"; + DDR-CONFIG-MODE1-RTT-NOM.RANKS4.DIMMS1.RANK0 = "0x4"; + DDR-CONFIG-MODE1-RTT-NOM.RANKS4.DIMMS1.RANK2 = "0x4"; + + /* Host Interface DQ/DQS Output Driver Impedance control for DIMM0's + Data Buffer. This is the default value used during Host Interface + Write Leveling in LRDIMM environment, i.e., + LMC()_CONFIG[LRDIMM_ENA] = 1, LMC()_SEQ_CTL[SEQ_SEL] = 0x6. + 0x0 = RZQ/6 (40 ohm). + 0x1 = RZQ/7 (34 ohm). + 0x2 = RZQ/5 (48 ohm). + 0x3-0x7 = Reserved. + Parameters: + RANKS#: Specifies that this parameter only applies to DIMMs + with the supplied number of ranks. Support ranks is 1, 2, + or 4. Optional. + DIMMS#: Specifies that this parameter only applies when the + DIMMs per memory controller matches. Support number of + DIMMs is 1 or 2. Optional. + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-MODE1-DB-OUTPUT-IMPEDANCE.RANKS%d.DIMMS%d.LMC%d.N%d = "0"; + + /* RTT park value per rank. + Parameters: + RANKS#: Specifies that this parameter only applies to DIMMs + with the supplied number of ranks. Support ranks is 1, 2, + or 4. Optional. + DIMMS#: Specifies that this parameter only applies when the + DIMMs per memory controller matches. Support number of + DIMMs is 1 or 2. Optional. + RANK#: Parameter can be different for each rank of a DIMM. This + specifies which rank the value is for. Rank must be + 0-3. Optional. + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-MODE2-RTT-PARK.RANKS%d.DIMMS%d.RANK%d.LMC%d.N%d = "0"; + + //DDR-CONFIG-MODE2-RTT-PARK.RANKS1.DIMMS1 = "0x1"; + DDR-CONFIG-MODE2-RTT-PARK.RANKS1.DIMMS1.RANK0 = "0x1"; + + //DDR-CONFIG-MODE2-RTT-PARK.RANKS1.DIMMS2 = "0x5"; + DDR-CONFIG-MODE2-RTT-PARK.RANKS1.DIMMS2.RANK0 = "0x5"; + DDR-CONFIG-MODE2-RTT-PARK.RANKS1.DIMMS2.RANK2 = "0x5"; + + //DDR-CONFIG-MODE2-RTT-PARK.RANKS2.DIMMS1 = "0x2"; + DDR-CONFIG-MODE2-RTT-PARK.RANKS2.DIMMS1.RANK0 = "0x2"; + DDR-CONFIG-MODE2-RTT-PARK.RANKS2.DIMMS1.RANK1 = "0x2"; + + DDR-CONFIG-MODE2-RTT-PARK.RANKS2.DIMMS2 = "0x1"; + DDR-CONFIG-MODE2-RTT-PARK.RANKS4.DIMMS1.RANK0 = "0x6"; + DDR-CONFIG-MODE2-RTT-PARK.RANKS4.DIMMS1.RANK1 = "0x6"; + + /* VREF value per rank. + Parameters: + RANKS#: Specifies that this parameter only applies to DIMMs + with the supplied number of ranks. Support ranks is 1, 2, + or 4. Optional. + DIMMS#: Specifies that this parameter only applies when the + DIMMs per memory controller matches. Support number of + DIMMs is 1 or 2. Optional. + RANK#: Parameter can be different for each rank of a DIMM. This + specifies which rank the value is for. Rank must be + 0-3. Optional. + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-MODE2-VREF-VALUE.RANKS%d.DIMMS%d.RANK%d.LMC%d.N%d = "0"; + + //DDR-CONFIG-MODE2-VREF-VALUE.RANKS1.DIMMS1 = "0x22"; + DDR-CONFIG-MODE2-VREF-VALUE.RANKS1.DIMMS1.RANK0 = "0x22"; + + //DDR-CONFIG-MODE2-VREF-VALUE.RANKS1.DIMMS2 = "0x1f"; + DDR-CONFIG-MODE2-VREF-VALUE.RANKS1.DIMMS2.RANK0 = "0x1f"; + DDR-CONFIG-MODE2-VREF-VALUE.RANKS1.DIMMS2.RANK2 = "0x1f"; + + //DDR-CONFIG-MODE2-VREF-VALUE.RANKS2.DIMMS1 = "0x19"; + DDR-CONFIG-MODE2-VREF-VALUE.RANKS2.DIMMS1.RANK0 = "0x19"; + DDR-CONFIG-MODE2-VREF-VALUE.RANKS2.DIMMS1.RANK1 = "0x19"; + + DDR-CONFIG-MODE2-VREF-VALUE.RANKS2.DIMMS2 = "0x19"; + DDR-CONFIG-MODE2-VREF-VALUE.RANKS4.DIMMS1.RANK0 = "0x1f"; + DDR-CONFIG-MODE2-VREF-VALUE.RANKS4.DIMMS1.RANK1 = "0x1f"; + + /* VREF range per rank. + Parameters: + RANKS#: Specifies that this parameter only applies to DIMMs + with the supplied number of ranks. Support ranks is 1, 2, + or 4. Optional. + DIMMS#: Specifies that this parameter only applies when the + DIMMs per memory controller matches. Support number of + DIMMs is 1 or 2. Optional. + RANK#: Parameter can be different for each rank of a DIMM. This + specifies which rank the value is for. Rank must be + 0-3. Optional. + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-MODE2-VREF-RANGE.RANKS%d.DIMMS%d.RANK%d.LMC%d.N%d = "0"; + + /* Vref training mode enable, used for all ranks. + Parameters: + RANKS#: Specifies that this parameter only applies to DIMMs + with the supplied number of ranks. Support ranks is 1, 2, + or 4. Optional. + DIMMS#: Specifies that this parameter only applies when the + DIMMs per memory controller matches. Support number of + DIMMs is 1 or 2. Optional. + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-MODE2-VREFDQ-TRAIN-EN.RANKS%d.DIMMS%d.LMC%d.N%d = "0"; + + /* RODT NCTL impedance control bits. This field controls ODT values + during a memory read. + 0x0 = No ODT. + 0x1 = 20 ohm. + 0x2 = 30 ohm. + 0x3 = 40 ohm. + 0x4 = 60 ohm. + 0x5 = 120 ohm. + _ else = Reserved. + In DDR4 mode: + 0x0 = No ODT. + 0x1 = 40 ohm. + 0x2 = 60 ohm. + 0x3 = 80 ohm. + 0x4 = 120 ohm. + 0x5 = 240 ohm. + 0x6 = 34 ohm. + 0x7 = 48 ohm. + _ else = Reserved. + Parameters: + RANKS#: Specifies that this parameter only applies to DIMMs + with the supplied number of ranks. Support ranks is 1, 2, + or 4. Optional. + DIMMS#: Specifies that this parameter only applies when the + DIMMs per memory controller matches. Support number of + DIMMs is 1 or 2. Optional. + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-RODT-CTL.RANKS%d.DIMMS%d.LMC%d.N%d = "0"; + DDR-CONFIG-RODT-CTL.RANKS1.DIMMS1 = "0x7"; + DDR-CONFIG-RODT-CTL.RANKS1.DIMMS2 = "0x3"; + DDR-CONFIG-RODT-CTL.RANKS2.DIMMS1 = "0x3"; + DDR-CONFIG-RODT-CTL.RANKS2.DIMMS2 = "0x7"; + DDR-CONFIG-RODT-CTL.RANKS4.DIMMS1 = "0x7"; + + /* LMC Read OnDieTermination Mask Register + System designers may desire to terminate DQ/DQS lines for higher + frequency DDR operations, especially on a multirank system. DDR3 + DQ/DQS I/Os have built-in termination resistors that can be turned + on or off by the controller, after meeting TAOND and TAOF timing + requirements. + Each rank has its own ODT pin that fans out to all the memory + parts in that DIMM. System designers may prefer different + combinations of ODT ONs for read operations into different ranks. + CNXXXX supports full programmability by way of the mask register + below. Each rank position has its own 4-bit programmable field. + When the controller does a read to that rank, it sets the 4 ODT + pins to the MASK pins below. For example, when doing a read from + Rank0, a system designer may desire to terminate the lines with + the resistor on DIMM0/Rank1. The mask RODT_D0_R0 would then be {0010}. + CNXXXX drives the appropriate mask values on the ODT pins by + default. If this feature is not required, write 0x0 in this + register. Note that, as per the JEDEC DDR3 specifications, the ODT + pin for the rank that is being read should always be 0x0. When a + given RANK is selected, the RODT mask for that rank is used. + Parameters: + RANKS#: Specifies that this parameter only applies to DIMMs + with the supplied number of ranks. Support ranks is 1, 2, + or 4. Optional. + DIMMS#: Specifies that this parameter only applies when the + DIMMs per memory controller matches. Support number of + DIMMs is 1 or 2. Optional. + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-RODT-MASK.RANKS%d.DIMMS%d.LMC%d.N%d = "0"; + DDR-CONFIG-RODT-MASK.RANKS2.DIMMS2 = "0x4080102"; + DDR-CONFIG-RODT-MASK.RANKS4.DIMMS1 = "0x1010202"; + + /* 1=120ohms, 2=60ohms, 3=40ohms, 4=30ohms, 5=20ohms + Parameters: + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-CUSTOM-MIN-RTT-NOM-IDX.LMC%d.N%d = "1"; + DDR-CONFIG-CUSTOM-MIN-RTT-NOM-IDX = "0x1"; + + /* 1=120ohms, 2=60ohms, 3=40ohms, 4=30ohms, 5=20ohms + Parameters: + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-CUSTOM-MAX-RTT-NOM-IDX.LMC%d.N%d = "5"; + DDR-CONFIG-CUSTOM-MAX-RTT-NOM-IDX = "0x7"; + + /* 1=20ohms, 2=30ohms, 3=40ohms, 4=60ohms, 5=120ohms + Parameters: + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-CUSTOM-MIN-RODT-CTL.LMC%d.N%d = "1"; + DDR-CONFIG-CUSTOM-MIN-RODT-CTL = "0x1"; + + /* 1=20ohms, 2=30ohms, 3=40ohms, 4=60ohms, 5=120ohms + Parameters: + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-CUSTOM-MAX-RODT-CTL.LMC%d.N%d = "5"; + DDR-CONFIG-CUSTOM-MAX-RODT-CTL = "0x7"; + + /* Drive strength control for DDR_CK_X_P, DDR_DIMMX_CSX_L, + DDR_DIMMX_ODT_X drivers. + Parameters: + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-CUSTOM-CK-CTL.LMC%d.N%d = "0"; + DDR-CONFIG-CUSTOM-CK-CTL = "0x4"; + + /* Drive strength control for CMD/A/RESET_L/CKEX drivers. + Parameters: + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-CUSTOM-CMD-CTL.LMC%d.N%d = "0"; + DDR-CONFIG-CUSTOM-CMD-CTL = "0x4"; + + /* Drive strength control for ODT, etc. drivers. + In DDR3 mode: + 0x1 = 24 ohm. + 0x2 = 26.67 ohm. + 0x3 = 30 ohm. + 0x4 = 34.3 ohm. + 0x5 = 40 ohm. + 0x6 = 48 ohm. + 0x7 = 60 ohm. + else = Reserved. + In DDR4 mode: + 0x0 = Reserved. + 0x1 = Reserved. + 0x2 = 26 ohm. + 0x3 = 30 ohm. + 0x4 = 34 ohm. + 0x5 = 40 ohm. + 0x6 = 48 ohm. + else = Reserved. + Parameters: + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-CUSTOM-CTL-CTL.LMC%d.N%d = "0"; + DDR-CONFIG-CUSTOM-CTL-CTL = "0x4"; + + /* Minimum allowed CAS Latency + Parameters: + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-CUSTOM-MIN-CAS-LATENCY.LMC%d.N%d = "0"; + + /* When set, LMC attempts to select the read-leveling setting that is + LMC()_RLEVEL_CTL[OFFSET] settings earlier than the last passing + read-leveling setting in the largest contiguous sequence of + passing settings. When clear, or if the setting selected by + LMC()_RLEVEL_CTL[OFFSET] did not pass, LMC selects the middle + setting in the largest contiguous sequence of passing settings, + rounding earlier when necessary. + Parameters: + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-CUSTOM-OFFSET-EN.LMC%d.N%d = "1"; + DDR-CONFIG-CUSTOM-OFFSET-EN = "0x1"; + + /* The offset used when LMC()_RLEVEL_CTL[OFFSET] is set. + Parameters: + %s: This setting can by specified by DRAM type (UDIMM or RDIMM) + Different settings can be used for each, or the type can be + omitted to use the same setting for both. + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-CUSTOM-OFFSET.%s.LMC%d.N%d = "0"; + DDR-CONFIG-CUSTOM-OFFSET = "0x2"; + + /* Enables software interpretation of per-byte read delays using the + measurements collected by the chip rather than completely relying + on the automatically to determine the delays. 1=software + computation is recommended since a more complete analysis is + implemented in software. + Parameters: + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-CUSTOM-RLEVEL-COMPUTE.LMC%d.N%d = "0"; + + /* Set to 2 unless instructed differently by Cavium. + Parameters: + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-CUSTOM-RLEVEL-COMP-OFFSET.%s.LMC%d.N%d = "2"; + + /* Turn on the DDR 2T mode. 2-cycle window for CMD and address. This + mode helps relieve setup time pressure on the address and command + bus. Please refer to Micron's tech note tn_47_01 titled DDR2-533 + Memory Design Guide for Two DIMM Unbuffered Systems for physical + details. + Parameters: + %s: This setting can by specified by DRAM type (UDIMM or RDIMM) + Different settings can be used for each, or the type can be + omitted to use the same setting for both. + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-CUSTOM-DDR2T.%s.LMC%d.N%d = "0"; + DDR-CONFIG-CUSTOM-DDR2T = "0x1"; + + /* As result of the flyby topology prescribed in the JEDEC + specifications the byte delays should maintain a consistent + increasing or decreasing trend across the bytes on standard DIMMs. + This setting can be used disable that check for unusual + circumstances where the check is not useful. + Parameters: + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-CUSTOM-DISABLE-SEQUENTIAL-DELAY-CHECK.LMC%d.N%d = "0"; + + /* An additional sequential delay check for the delays that result + from the flyby topology. This value specifies the maximum + difference between the delays of adjacent bytes. A value of 0 + disables this check. + Parameters: + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-CUSTOM-MAXIMUM-ADJACENT-RLEVEL-DELAY-INCREMENT.LMC%d.N%d = "0"; + DDR-CONFIG-CUSTOM-MAXIMUM-ADJACENT-RLEVEL-DELAY-INCREMENT = "0x2"; + + /* The parity input signal PAR_IN on each DIMM must be strapped high + or low on the board. This bit is programmed into + LMC0_DIMM_CTL[PARITY] and it must be set to match the board + strapping. This signal is typically strapped low. + Parameters: + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-CUSTOM-PARITY.LMC%d.N%d = "0"; + + /* Front Porch Enable: When set, the turn-off time for the default + DDR_DQ/DQS drivers is FPRCH2 CKs earlier. + 0 = 0 CKs + 1 = 1 CKs + 2 = 2 CKs + Parameters: + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-CUSTOM-FPRCH2.LMC%d.N%d = "0"; + DDR-CONFIG-CUSTOM-FPRCH2 = "0x2"; + + /* Enable 32-bit datapath mode. Set to 1 if only 32 DQ pins are + used. + Parameters: + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-CUSTOM-MODE32B.LMC%d.N%d = "0"; + + /* Use Measured VREF + Parameters: + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-CUSTOM-MEASURED-VREF.LMC%d.N%d = "0"; + + /* Supply a custom DLL write offset + Parameters: + BYTE#: Byte lane to apply the parameter to (0-8). + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-CUSTOM-DLL-WRITE-OFFSET.BYTE%d.LMC%d.N%d = "0"; + + /* Supply a custom DLL read offset + Parameters: + BYTE#: Byte lane to apply the parameter to (0-8). + LMC#: Parameter can be different for memory controller. This + specifies which LMC the value is for. LMC must be + 0-3. Optional. + N#: Parameter can be different for each node. This specifies + which node the value is for. Node must be 0-3. Optional. */ + //DDR-CONFIG-CUSTOM-DLL-READ-OFFSET.BYTE%d.LMC%d.N%d = "0"; + + /* Choose the debug logging level used during DRAM initialization. + Zero disables debug logging. The possible debug levels are: + 0: Off, no logging + 1: Logging of DRAM initialization at a normal detail level + 2: Logging of DRAM initialization at FAE detail level + 3: Logging of DRAM initialization at TME detail level + 4: Logging of DRAM initialization at DEV detail level + 5: Logging of DRAM initialization at DEV2 detail level + 6: Logging of DRAM initialization at DEV3 detail level + 7: Logging of DRAM initialization at DEV4 detail level + Add in the following for special trace features. + 16: Trace specialized DRAM controller sequences. + 32: Trace every DRAM controller register write. */ + //DDR-VERBOSE = "0"; + + /* Run a short DRAM test after DRAM is initialized as quick check + for functionality. This is normally not needed required. Boards + with poor DRAM power supplies may use this to detect failures + during boot. This should be used in combination with the watchdog + timer. */ + //DDR-TEST-BOOT = "0"; + + /* The DRAM initialization code has the ability to toggle a GPIO to + signal when it is running. Boards may need to mux TWSI access + between a BMC and the SOC so the BMC can monitor DIMM temperatures + and health. This GPIO will be driven high when the SOC may read + from the SPDs on the DIMMs. When driven low, another device (BMC) + may takeover the TWSI connections to the DIMMS. The default value + (-1) disables this feature. */ + //DDR-CONFIG-GPIO = "-1"; + + /* Scramble DRAM to prevent snooping. This options programs the DRAM + controller to scramble addresses and data with random values. + Supported values: + 0: No scrambling + 1: Always scramble + 2: Scramble only when using trusted boot (Default) */ + //DDR-CONFIG-SCRAMBLE = "2"; +}; /* cavium,bdk */ +}; /* / */ diff --git a/src/mainboard/cavium/cn8100_sff_evb/devicetree.cb b/src/mainboard/cavium/cn8100_sff_evb/devicetree.cb new file mode 100644 index 0000000000..cd495e1f54 --- /dev/null +++ b/src/mainboard/cavium/cn8100_sff_evb/devicetree.cb @@ -0,0 +1,18 @@ +## +## This file is part of the coreboot project. +## +## Copyright 2017-present Facebook, Inc. +## +## 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; version 2 of the License. +## +## 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. +## + +chip soc/cavium/cn81xx + device cpu_cluster 0 on end +end diff --git a/src/mainboard/cavium/cn8100_sff_evb/mainboard.c b/src/mainboard/cavium/cn8100_sff_evb/mainboard.c new file mode 100644 index 0000000000..b6d4ad8a7c --- /dev/null +++ b/src/mainboard/cavium/cn8100_sff_evb/mainboard.c @@ -0,0 +1,216 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2017-2018 Facebook, Inc. + * Copyright 2003-2017 Cavium Inc. (support@cavium.com) + * + * 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; version 2 of the License. + * + * 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. + * + * Derived from Cavium's BSD-3 Clause OCTEONTX-SDK-6.2.0. + */ + +#include <device/device.h> +#include <libbdk-hal/bdk-config.h> +#include <libbdk-hal/bdk-twsi.h> +#include <soc/twsi.h> +#include <soc/gpio.h> +#include <delay.h> + +extern const struct bdk_devicetree_key_value devtree[]; + +static void mainboard_init(struct device *dev) +{ + /* FIXME: stub */ +} + +static void mainboard_enable(struct device *dev) +{ + dev->ops->init = &mainboard_init; + + bdk_config_set_fdt(devtree); + + /* + * Adapted from Cavium's devicetree TWSI-WRITE: + * Init board-specific I2C hardware: + */ + twsi_init(0, I2C_SPEED_STANDARD); + + /* Initialize IO expander U6 to power-up defaults */ + /* float all pins 0.0-0.7 */ + bdk_twsix_write_ia(0,0,0x21,6,1,1,0xff); + /* float all pins 1.0-1.7 */ + bdk_twsix_write_ia(0,0,0x21,7,1,1,0xff); + /* 0.x: all outputs low, but disabled */ + bdk_twsix_write_ia(0,0,0x21,2,1,1,0x00); + /* 1.x: all outputs low, but disabled */ + bdk_twsix_write_ia(0,0,0x21,3,1,1,0x00); + /* 0.x: no polarity inversion */ + bdk_twsix_write_ia(0,0,0x21,4,1,1,0x00); + /* 1.x: no polarity inversion */ + bdk_twsix_write_ia(0,0,0x21,5,1,1,0x00); + /* Initialize IO expander U89 to power-up defaults */ + /* float all pins 0.0-0.7 */ + bdk_twsix_write_ia(0,0,0x22,6,1,1,0xff); + /* float all pins 1.0-1.7 */ + bdk_twsix_write_ia(0,0,0x22,7,1,1,0xff); + /* 0.x: all outputs low, but disabled */ + bdk_twsix_write_ia(0,0,0x22,2,1,1,0x00); + /* 1.x: all outputs low, but disabled */ + bdk_twsix_write_ia(0,0,0x22,3,1,1,0x00); + /* 0.x: no polarity inversion */ + bdk_twsix_write_ia(0,0,0x22,4,1,1,0x00); + /* 1.x: no polarity inversion */ + bdk_twsix_write_ia(0,0,0x22,5,1,1,0x00); + /* set outputs SLIC_RESET_L=0 and SPI_SEL=0 */ + bdk_twsix_write_ia(0,0,0x21,6,1,1,0xee); /* 0.0 & 0.4 are outputs */ + + /* Select channel-0 in PCA9546A to enable SFI */ + bdk_twsix_write_ia(0, 0, 0x70, 0, 1, 1, 0x7); + mdelay(10); + /* Configure I2C-GPIO expander I/O directions */ + bdk_twsix_write_ia(0, 0, 0x22, 6, 1, 1, 0x07); + mdelay(10); + /* Configure I2C-GPIO expander I/O directions */ + bdk_twsix_write_ia(0, 0, 0x22, 7, 1, 1, 0x38); + mdelay(10); + /* Turn on SFP+ Transmitters */ + bdk_twsix_write_ia(0, 0, 0x22, 2, 1, 1, 0x0); + mdelay(10); + /* Set VSC7224 to I2C mode */ + bdk_twsix_write_ia(0, 0, 0x22, 3, 1, 1, 0x0); + mdelay(10); + /* Assert VSC7224 reset*/ + bdk_twsix_write_ia(0, 0, 0x22, 2, 1, 1, 0x80); + mdelay(50); + /* Deassert VSC7224 reset*/ + bdk_twsix_write_ia(0, 0, 0x22, 2, 1, 1, 0x0); + mdelay(50); + /* Page select FSYNC0 (0x30) */ + bdk_twsix_write_ia(0, 0, 0x14, 0x7f, 2, 1, 0x0030); + mdelay(10); + /* Set FSYNC0 for 10.3125Gbps See Table 3 */ + bdk_twsix_write_ia(0, 0, 0x14, 0x80, 2, 1, 0x2841); + mdelay(10); + bdk_twsix_write_ia(0, 0, 0x14, 0x81, 2, 1, 0x0008); + mdelay(10); + bdk_twsix_write_ia(0, 0, 0x14, 0x82, 2, 1, 0x7a00); + mdelay(10); + bdk_twsix_write_ia(0, 0, 0x14, 0x83, 2, 1, 0x000f); + mdelay(10); + bdk_twsix_write_ia(0, 0, 0x14, 0x84, 2, 1, 0x9c18); + mdelay(10); + bdk_twsix_write_ia(0, 0, 0x14, 0x85, 2, 1, 0x0); + mdelay(10); + + /* All channels Rx settings set equally */ + bdk_twsix_write_ia(0, 0, 0x14, 0x7f, 2, 1, 0x0050); + mdelay(10); + /* Shrink EQ_BUFF */ + bdk_twsix_write_ia(0, 0, 0x14, 0x82, 2, 1, 0x0014); + mdelay(10); + /* Select min DFE Delay (DFE_DELAY) */ + bdk_twsix_write_ia(0, 0, 0x14, 0x90, 2, 1, 0x5585); + mdelay(10); + /* Set DFE 1-3 limit (DXMAX) = 32dec, AP Max limit = 127 decimal */ + bdk_twsix_write_ia(0, 0, 0x14, 0x92, 2, 1, 0x207f); + mdelay(10); + /* Set AP Min limit = 32 decimal */ + bdk_twsix_write_ia(0, 0, 0x14, 0x93, 2, 1, 0x2000); + mdelay(10); + /* Set DFE Averaging to the slowest (DFE_AVG) */ + bdk_twsix_write_ia(0, 0, 0x14, 0x94, 2, 1, 0x0031); + mdelay(10); + /* Set Inductor Bypass OD_IND_BYP = 0 & fastest Rise/Fall */ + bdk_twsix_write_ia(0, 0, 0x14, 0x9c, 2, 1, 0x0000); + mdelay(10); + /* Setting DFE Boost = none. Must set for rev C + * (if DFE in adapt mode) */ + bdk_twsix_write_ia(0, 0, 0x14, 0xaa, 2, 1, 0x0888); + mdelay(10); + /* Setting EQ Min/Max = 8/72 */ + bdk_twsix_write_ia(0, 0, 0x14, 0xa8, 2, 1, 0x2408); + mdelay(10); + /* Setting EQVGA = 96, when in EQVGA manual mode */ + bdk_twsix_write_ia(0, 0, 0x14, 0xa9, 2, 1, 0x0060); + mdelay(10); + /* Setting SW_BFOCM, bits 15:14 to 01 */ + bdk_twsix_write_ia(0, 0, 0x14, 0x87, 2, 1, 0x4021); + mdelay(10); + /* Turn off adaptive input equalization and VGA adaptive algorithm + * control */ + bdk_twsix_write_ia(0, 0, 0x14, 0x89, 2, 1, 0x7313); + mdelay(10); + /* Turn on adaptive input equalization and VGA adaptive algorithm + * control */ + bdk_twsix_write_ia(0, 0, 0x14, 0x89, 2, 1, 0x7f13); + mdelay(10); + + /* TAP settings for each channel 0-3 */ + /* Ch-0 Tx */ + bdk_twsix_write_ia(0, 0, 0x14, 0x7f, 2, 1, 0x0000); + mdelay(10); + bdk_twsix_write_ia(0, 0, 0x14, 0x99, 2, 1, 0x001f); + mdelay(10); + bdk_twsix_write_ia(0, 0, 0x14, 0x9a, 2, 1, 0x000f); + mdelay(10); + bdk_twsix_write_ia(0, 0, 0x14, 0x9b, 2, 1, 0x0004); + mdelay(10); + + /* Ch-1 Rx */ + bdk_twsix_write_ia(0, 0, 0x14, 0x7f, 2, 1, 0x0001); + mdelay(10); + bdk_twsix_write_ia(0, 0, 0x14, 0x97, 2, 1, 0x1400); + mdelay(10); + /* Transmitter Output polarity Inverted (Unfortunately, + * Rx polarity lines are wrongly inverted on board */ + bdk_twsix_write_ia(0, 0, 0x14, 0x97, 2, 1, 0x4000); + mdelay(10); + bdk_twsix_write_ia(0, 0, 0x14, 0x99, 2, 1, 0x000f); + mdelay(10); + + /* Ch-2 Tx */ + bdk_twsix_write_ia(0, 0, 0x14, 0x7f, 2, 1, 0x0002); + mdelay(10); + bdk_twsix_write_ia(0, 0, 0x14, 0x99, 2, 1, 0x001f); + mdelay(10); + bdk_twsix_write_ia(0, 0, 0x14, 0x9a, 2, 1, 0x000f); + mdelay(10); + bdk_twsix_write_ia(0, 0, 0x14, 0x9b, 2, 1, 0x0004); + mdelay(10); + + /* Ch-3 Rx */ + bdk_twsix_write_ia(0, 0, 0x14, 0x7f, 2, 1, 0x0003); + mdelay(10); + bdk_twsix_write_ia(0, 0, 0x14, 0x97, 2, 1, 0x1400); + mdelay(10); + /* Transmitter Output polarity Inverted (Unfortunately, + * Rx polarity lines are wrongly inverted on board */ + bdk_twsix_write_ia(0, 0, 0x14, 0x97, 2, 1, 0x4000); + mdelay(10); + bdk_twsix_write_ia(0, 0, 0x14, 0x99, 2, 1, 0x000f); + mdelay(10); + + /** + * The following hardware magically starts working after toggling + * GPIO_10_PHY_RESET_L: + * * SATA PHY + * * GBE PHY + * * XFI PHY + * * MMC + */ + gpio_output(10, 0); + udelay(100); + gpio_output(10, 1); +} + +struct chip_operations mainboard_ops = { + .name = CONFIG_MAINBOARD_PART_NUMBER, + .enable_dev = mainboard_enable, +}; diff --git a/src/mainboard/cavium/cn8100_sff_evb/memlayout.ld b/src/mainboard/cavium/cn8100_sff_evb/memlayout.ld new file mode 100644 index 0000000000..9349362cfa --- /dev/null +++ b/src/mainboard/cavium/cn8100_sff_evb/memlayout.ld @@ -0,0 +1 @@ + #include <soc/memlayout.ld> diff --git a/src/mainboard/cavium/cn8100_sff_evb/romstage.c b/src/mainboard/cavium/cn8100_sff_evb/romstage.c new file mode 100644 index 0000000000..c35d0b3876 --- /dev/null +++ b/src/mainboard/cavium/cn8100_sff_evb/romstage.c @@ -0,0 +1,45 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2017-present Facebook, Inc. + * + * 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; version 2 of the License. + * + * 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. + * + */ + +#include <arch/exception.h> +#include <cbmem.h> +#include <romstage_handoff.h> +#include <soc/sdram.h> +#include <soc/timer.h> +#include <stdlib.h> +#include <console/console.h> +#include <program_loading.h> +#include <libbdk-hal/bdk-config.h> +#include <string.h> + +extern const struct bdk_devicetree_key_value devtree[]; + +void main(void) +{ + watchdog_poke(0); + + console_init(); + exception_init(); + + bdk_config_set_fdt(devtree); + + sdram_init(); + + watchdog_poke(0); + + cbmem_initialize_empty(); + run_ramstage(); +} diff --git a/src/mainboard/cavium/cn8100_sff_evb/sff8104-linux.dts b/src/mainboard/cavium/cn8100_sff_evb/sff8104-linux.dts new file mode 100644 index 0000000000..1448ee6220 --- /dev/null +++ b/src/mainboard/cavium/cn8100_sff_evb/sff8104-linux.dts @@ -0,0 +1,282 @@ +/* + * Cavium Thunder DTS file - Thunder board description + * + * Copyright (C) 2016, Cavium Inc. + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) 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; version 2 of the License. + * + * 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; + +/include/ "cn81xx-linux.dtsi" + +&mrml_bridge { + mdio-nexus@1,3 { + mdio0@87e005003800 { + rgmii00: rgmii00 { + reg = <0> ; + compatible = "marvell,88e1510", "ethernet-phy-ieee802.3-c22"; + }; + + qsgmii00: qsgmii00 { + qlm-mode = "0x000,qsgmii"; + reg = <0x10> ; + compatible = "vitesse,vsc8574", "ethernet-phy-ieee802.3-c22"; + }; + qsgmii01: qsgmii01 { + qlm-mode = "0x001,qsgmii"; + reg = <0x11> ; + compatible = "vitesse,vsc8574", "ethernet-phy-ieee802.3-c22"; + }; + qsgmii02: qsgmii02 { + qlm-mode = "0x002,qsgmii"; + reg = <0x12> ; + compatible = "vitesse,vsc8574", "ethernet-phy-ieee802.3-c22"; + }; + qsgmii03: qsgmii03 { + qlm-mode = "0x003,qsgmii"; + reg = <0x13> ; + compatible = "vitesse,vsc8574", "ethernet-phy-ieee802.3-c22"; + }; + }; + mdio1@87e005003880 { + xfi00: xfi00 { + qlm-mode = "0x000,xfi"; + reg = <0x0>; + compatible = "aquantia,aqr105", "ethernet-phy-ieee802.3-c45"; + }; + }; + }; + + rgx0 { + rgmii00 { + reg = <0>; + local-mac-address = [00 00 00 00 00 00]; + phy-handle = <&rgmii00>; + }; + }; + + bgx0 { + /* typename+qlm+typenumber eg : + qsgmii+bgx0+sgmmi0 + */ + qsgmii00 { + reg = <0>; + qlm-mode = "0x000,qsgmii"; + local-mac-address = [00 00 00 00 00 00]; + phy-handle = <&qsgmii00>; + }; + qsgmii01 { + reg = <1>; + qlm-mode = "0x001,qsgmii"; + local-mac-address = [00 00 00 00 00 00]; + phy-handle = <&qsgmii01>; + }; + qsgmii02 { + reg = <2>; + qlm-mode = "0x002,qsgmii"; + local-mac-address = [00 00 00 00 00 00]; + phy-handle = <&qsgmii02>; + }; + qsgmii03 { + reg = <3>; + qlm-mode = "0x003,qsgmii"; + local-mac-address = [00 00 00 00 00 00]; + phy-handle = <&qsgmii03>; + }; + + xfi00 { + reg = <0>; + qlm-mode = "0x000,xfi"; + local-mac-address = [00 00 00 00 00 00]; + phy-handle = <&xfi00>; + }; + }; + + bgx1 { + xfi10 { + reg = <0>; + qlm-mode = "0x010,xfi"; + local-mac-address = [00 00 00 00 00 00]; + }; + + xfi11 { + reg = <1>; + qlm-mode = "0x011,xfi"; + local-mac-address = [00 00 00 00 00 00]; + }; + }; + + +}; + +&mmc_1_4 { + /* NOTE: the BDK is responsible for swapping the two slots. + * Unfortunately there does not appear to be any way to read the + * position of SW2-7 in software. + */ + mmc-slot@0 { + compatible = "mmc-slot"; + reg = <0>; + vmmc-supply = <&mmc_supply_3v3>; + max-frequency = <26000000>; + /* 1.8v is not supported */ + no-1-8-v; + /* Bus width is only 4 bits maximum */ + bus-width = <4>; + /* No write-protect switch is present */ + disable-wp; + /* There is no card detection available; polling must be used. */ + broken-cd; + /* High-speed mode is supported */ + cap-sd-highspeed; + /* speed up device probing */ + no-sdio; + no-mmc; + }; + mmc-slot@1 { + compatible = "mmc-slot"; + reg = <1>; + vmmc-supply = <&mmc_supply_3v3>; + max-frequency = <26000000>; + mmc-ddr-3_3v; + /* 1.8v is not supported */ + no-1-8-v; + /* Bus width is only 8 bits maximum */ + bus-width = <8>; + /* No write-protect switch is present */ + disable-wp; + /* There is no card detection available; polling must be used. */ + broken-cd; + /* High-speed mode is supported */ + cap-mmc-highspeed; + /* eMMC device is soldered onto the board */ + non-removable; + /* speed up device probing */ + no-sdio; + no-sd; + }; +}; + +&i2c_9_0 { + /* another pca9535 at 0x20 is only visible via jtag */ + gpio1: gpio-i2c@21 { + compatible = "nxp,pca9535"; + gpio-controller; + reg = <0x21>; + gpio_base = <48>; + pins = <48 16>; + ngpios = <16>; // standard + n_gpios = <16>; // deprecated, driver required + #gpio-cells = <2>; + }; + + gpio2: gpio-i2c@22 { + compatible = "nxp,pca9535"; + gpio-controller; + reg = <0x22>; + gpio_base = <64>; + pins = <64 16>; + ngpios = <16>; // standard + n_gpios = <16>; // deprecated, driver required + #gpio-cells = <2>; + }; + + mux@70 { + compatible = "nxp,pca9546"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + }; +}; + +&i2c_9_1 { + rom@54 { + compatible = "atmel,24c256"; + reg = <0x54>; + pagesize = <64>; + }; + + rtc@68 { + compatible = "isil,isl12057"; + reg = <0x68>; + }; +}; + +&spi_7_0 { + flash@0 { + compatible = "micron,n25q128a13", "spi-flash", "jedec,spi-nor"; + reg = <0x0>; + spi-max-frequency = <16000000>; + #address-cells = <1>; + #size-cells = <1>; + }; + flash@1 { + compatible = "spinand,mt29f", "mt29f"; + reg = <0x1>; + spi-max-frequency = <50000000>; + #address-cells = <1>; + #size-cells = <1>; + nand-ecc-mode = "none"; + }; +}; + +&nfc { + nand@1 { + reg = <0x1>; + nand-ecc-mode = "none"; + }; +}; diff --git a/src/soc/cavium/Kconfig b/src/soc/cavium/Kconfig new file mode 100644 index 0000000000..49070cfbf2 --- /dev/null +++ b/src/soc/cavium/Kconfig @@ -0,0 +1,2 @@ +# Load all chipsets +source "src/soc/cavium/*/Kconfig" diff --git a/src/soc/cavium/cn81xx/Kconfig b/src/soc/cavium/cn81xx/Kconfig new file mode 100644 index 0000000000..ca8fbd0f46 --- /dev/null +++ b/src/soc/cavium/cn81xx/Kconfig @@ -0,0 +1,27 @@ +config SOC_CAVIUM_CN81XX + bool + default n + select ARCH_BOOTBLOCK_ARMV8_64 + select ARCH_RAMSTAGE_ARMV8_64 + select ARCH_ROMSTAGE_ARMV8_64 + select ARCH_VERSTAGE_ARMV8_64 + select BOOTBLOCK_CONSOLE + select DRIVERS_UART_PL011 + select GENERIC_UDELAY + select HAVE_MONOTONIC_TIMER + select UART_OVERRIDE_REFCLK + select SOC_CAVIUM_COMMON + +if SOC_CAVIUM_CN81XX + +config ARCH_ARMV8_EXTENSION + int + default 1 + +config HEAP_SIZE + default 0x10000 + +config STACK_SIZE + default 0x2000 + +endif diff --git a/src/soc/cavium/cn81xx/Makefile.inc b/src/soc/cavium/cn81xx/Makefile.inc new file mode 100644 index 0000000000..d265c19bb8 --- /dev/null +++ b/src/soc/cavium/cn81xx/Makefile.inc @@ -0,0 +1,70 @@ +## +## This file is part of the coreboot project. +## +## Copyright 2017-present Facebook, Inc. +## +## 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; version 2 of the License. +## +## 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. +## + +ifeq ($(CONFIG_SOC_CAVIUM_CN81XX),y) + +# bootblock +bootblock-$(CONFIG_BOOTBLOCK_CUSTOM) += bootblock_custom.S +bootblock-y += bootblock.c +bootblock-y += twsi.c +bootblock-y += clock.c +bootblock-y += gpio.c +bootblock-y += timer.c +bootblock-y += spi.c +bootblock-y += uart.c +bootblock-y += cpu.c +ifeq ($(CONFIG_BOOTBLOCK_CONSOLE),y) +bootblock-$(CONFIG_DRIVERS_UART) += uart.c +endif + +################################################################################ +# romstage + +romstage-y += twsi.c +romstage-y += clock.c +romstage-y += gpio.c +romstage-y += timer.c +romstage-y += spi.c +romstage-y += uart.c +romstage-$(CONFIG_DRIVERS_UART) += uart.c +romstage-< += cpu.c + +romstage-y += sdram.c +romstage-y += ../common/cbmem.c +# BDK coreboot interface +romstage-y += ../common/bdk-coreboot.c + + +################################################################################ +# ramstage + +ramstage-y += twsi.c +ramstage-y += clock.c +ramstage-y += gpio.c +ramstage-y += timer.c +ramstage-y += spi.c +ramstage-y += uart.c +ramstage-$(CONFIG_DRIVERS_UART) += uart.c +ramstage-y += sdram.c +ramstage-y += soc.c +ramstage-y += cpu.c + +# BDK coreboot interface +ramstage-y += ../common/bdk-coreboot.c + + +CPPFLAGS_common += -Isrc/soc/cavium/cn81xx/include + +endif diff --git a/src/soc/cavium/cn81xx/bootblock.c b/src/soc/cavium/cn81xx/bootblock.c new file mode 100644 index 0000000000..8517467de1 --- /dev/null +++ b/src/soc/cavium/cn81xx/bootblock.c @@ -0,0 +1,50 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 Facebook, Inc. + * Copyright 2003-2017 Cavium Inc. <support@cavium.com> + * + * 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; version 2 of the License. + * + * 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. + * + * Derived from Cavium's BSD-3 Clause OCTEONTX-SDK-6.2.0. + */ + +#include <arch/io.h> +#include <commonlib/helpers.h> +#include <soc/bootblock.h> +#include <soc/sysreg.h> +#include <soc/timer.h> +#include <libbdk-arch/bdk-asm.h> + +static void init_sysreg(void) +{ + /* The defaults for write buffer timeouts are poor */ + u64 cvmmemctl0; + BDK_MRS(s3_0_c11_c0_4, cvmmemctl0); + cvmmemctl0 |= AP_CVMMEMCTL0_EL1_WBFTONSHENA | + AP_CVMMEMCTL0_EL1_WBFTOMRGCLRENA; + BDK_MSR(s3_0_c11_c0_4, cvmmemctl0); +} + +void bootblock_soc_early_init(void) +{ +} + +void bootblock_soc_init(void) +{ + /* initialize system registers */ + init_sysreg(); + + /* Set watchdog to 5 seconds timeout */ + watchdog_set(0, 5000); + watchdog_poke(0); + + /* TODO: additional clock init? */ +} diff --git a/src/soc/cavium/cn81xx/bootblock_custom.S b/src/soc/cavium/cn81xx/bootblock_custom.S new file mode 100644 index 0000000000..69985b7834 --- /dev/null +++ b/src/soc/cavium/cn81xx/bootblock_custom.S @@ -0,0 +1,257 @@ +/* + * Early initialization code for aarch64 (a.k.a. armv8) + * + * Copyright 2016 Cavium, Inc. <support@cavium.com> + * Copyright 2018-present Facebook, Inc. + * + * 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; version 2 of + * the License. + * + * 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. + */ + +#include <arch/asm.h> +#include <soc/addressmap.h> + +ENTRY(_start) + .org 0 + /** + * According to the reference manual the first instruction is fetched from + * offset 0x100, but at offset 0 a branch instruction is always placed. + * Support two entry points for now. + * To save memory put the cavium specific init code between those to entry + * points. + */ + ic ialluis + fmov d30, x0 /* Save X0 in FPR for use later */ + fmov d31, x1 /* Save X1 in FPR for use later */ + adr x1, _start /* x1 = _start location based on PC */ + fmov d29, x1 /* Save PC in FPR for use later */ + +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + /* Change the core to big endian mode for EL3 */ + mrs x0, SCTLR_EL3 + mov x1, 1<<25 /* Set SCTLR_EL3[ee]=1 */ + orr x0, x0, x1 + msr SCTLR_EL3, x0 + #define ENDIAN_CONVERT64(reg) rev reg, reg + #define ENDIAN_CONVERT32(reg) rev reg, reg + #define ENDIAN_CONVERT16(reg) rev16 reg, reg +#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + /* Nothing needed, default is little endian */ + #define ENDIAN_CONVERT64(reg) + #define ENDIAN_CONVERT32(reg) + #define ENDIAN_CONVERT16(reg) +#else + #error Unknown endianness +#endif + + mov x0, (LMC0_PF_BAR0 >> 32) + lsl x0, x0, 32 + mov x1, (LMC0_PF_BAR0 & 0xffffffff) + orr x0, x0, x1 + + /* Test if DRAM PLL is running */ + ldr x1, [x0, LMC0_DDR_PLL_CTL0] + + tst x1, 0x80 + + b.ne cache_setup_done + + bl _setup_car + +cache_setup_done: + + /* Check that we're running on the node we're linked for */ + mrs x0, MPIDR_EL1 + ubfx x0, x0, 16, 8 /* Bits 23:16 are the physical node ID */ + mov x1, 0x0 + cmp x0, x1 + + b.ne _wfi + +node_check_done: + /* Get code position */ + mov x1, 0x020000 + mov x0, BOOTROM_OFFSET + add x1, x0, x1 + + adr x0, _start + + /** + * Check if IROM has loaded the code to CONFIG_BOOTROM_OFFSET. + * In case the offset is wrong, try to relocate. + * Ideally the following code is never executed. + * FIXME: Add region overlap check. + */ + cmp x0, x1 + b.eq after_relocate + +relocate: + /* Get bootblock length */ + ldr x2, =_program + ldr x3, =_eprogram + sub x2, x2, x3 + b copy_code + +.align 7 +copy_code: + ldp q0, q1, [x1], 32 /* Load 32 bytes */ + subs w2, w2, 32 /* Subtract 32 from length, setting flags */ + stp q0, q1, [x0], 32 /* Store 32 bytes */ + b.gt copy_code /* Repeat if length is still positive */ + dmb sy + + /* Load the actual location we're suppose to be at */ + adr x0, after_relocate /* Relative address */ + adr x1, _start /* Relative address */ + sub x0, x0, x1 /* This only works if _start is suppose to be zero */ + mov x1, BOOTROM_OFFSET + add x0, x0, x1 + br x0 /* Branch to relocated code */ + + ic ialluis /* Clear the icache now that all code is correct */ + +after_relocate: + /* Allow unaligned memory access as long as MMU is disabled */ + mrs x22, s3_0_c11_c0_4 + orr x22, x22, # (1 << 37) /* Set DCVA47 */ + msr s3_0_c11_c0_4, x22 + + bl start + + /* Real entry point */ + .org 0x100 + b _start +ENDPROC(_start) + + +ENTRY(_setup_car) + mrs x0, MIDR_EL1 + ubfx x0, x0, 4, 12 /* Bits 15:4 are the part number */ + cmp x0, 0xb0 + b.ge _wfi + +thunder1_cache_setup: + /** + * Setup L2 cache to allow secure access to all of the address space + * thunder1 compability list: + * - CN81XX + * - CN83XX + * - CN88XX + */ + #define REGIONX_START 0x1000 + #define REGIONX_END 0x1008 + #define REGIONX_ATTR 0x1010 + mov x0, L2C_PF_BAR0 >> 32 + lsl x0, x0, 32 + mov x1, (L2C_PF_BAR0 & 0xffffffff) + orr x0, x0, x1 + str xzr, [x0, REGIONX_START] /* Start of zero */ + mov x1, 0x3fffff00000 /* End of max address */ + ENDIAN_CONVERT64(x1) + str x1, [x0, REGIONX_END] + mov x1, 2 /* Secure only access */ + ENDIAN_CONVERT64(x1) + str x1, [x0, REGIONX_ATTR] + /* Update way partition to allow core 0 to write to L2 */ + #define L2C_WPAR_PP0_OFFSET 0x40000 + mov x1, L2C_WPAR_PP0_OFFSET + str xzr, [x0, x1] + ldr xzr, [x0, x1] /* Read back to make sure done */ + #undef REGIONX_START + #undef REGIONX_END + #undef REGIONX_ATTR + #undef L2C_WPAR_PP0_OFFSET + + /** + * At this point the whole CAR is readable and writeable, but if + * we touch to many cache-lines our code might get flushed out. + * We have to lock all cache-lines that are to be used as RAM, which are + * the ones marked as SRAM in memlayout. + */ + mrs x0, CTR_EL0 /* Get cache-line size */ + /* [19:16] - Indicates (Log2(number of words in cache line) */ + ubfx x0, x0, 16, 4 + mov x1, 4 /* Bytes in a word (32-bit) */ + lsl x0, x1, x0 /* Number of Bytes in x0 */ + + sub x1, x0, 1 + mvn x1, x1 /* Place mask in x1 */ + + ldr x3, =_sram + and x3, x3, x1 /* Align addresses with cache-lines */ + ldr x4, =_esram + add x4, x4, x0 + sub x4, x4, 1 + and x4, x4, x1 /* Align addresses with cache-lines */ + sub x2, x4, x3 /* Store sram length in x2 */ + +lock_cache_lines: + sys #0, c11, c1, #4, x3 + add x3, x3, x0 /* Increment address by cache-line bytes */ + subs w2, w2, w0 /* Subtract cache-line bytes from length */ + b.gt lock_cache_lines /* Repeat if length is still positive */ + + /** + * The locked region isn't considered dirty by L2. Do read/write of + * each cache line to force each to be dirty. This is needed across the + * whole line to make sure the L2 dirty bits are all up to date. + * NOTE: If we'd relocate we could memset the whole memory ! + */ + ldr x3, =_sram + and x3, x3, x1 /* Align addresses with cache-lines */ + ldr x4, =_esram + add x4, x4, x0 + sub x4, x4, 1 + and x4, x4, x1 /* Align addresses with cache-lines */ + sub x2, x4, x3 /* Store sram length in x2 */ + mov x4, x3 + b dirty_cache_line + +.align 7 +dirty_cache_line: + ldp q0, q1, [x3], 32 /* Load 32 bytes */ + subs w2, w2, 32 /* Subtract 32 from length, setting flags */ + stp q0, q1, [x4], 32 /* Store 32 bytes */ + b.gt dirty_cache_line /* Repeat if length is still positive */ + dmb sy + +clear_interrupts: + /** + * As the memory controller isn't running, but we access the DRAM's + * address space, some interrupt flags had been set. + * Tidy up our mess now on (valid for CN81XX only). + */ + mov x0, (L2C_TAD0_INT_W1C >> 32) + lsl x0, x0, 32 + mov x1, (L2C_TAD0_INT_W1C & 0xffffffff) + orr x0, x0, x1 + + ldr x1, [x0] + orr x1, x1, 0x1c00 /* Clear WRDISLMC, RDDISLMC, RDNXM */ + str x1, [x0] + + ret +ENDPROC(_setup_car) + +ENTRY(_wfi) + wfi +ENDPROC(_wfi) + +ENTRY(start) + bl arm64_init_cpu + + fmov x0, d30 /* The original X0, info from previous image */ + fmov x1, d31 /* The original X1, info from previous image */ + fmov x2, d29 /* The original PC we were loaded at */ + + /* Call C entry */ + bl bootblock_main + +ENDPROC(start) diff --git a/src/soc/cavium/cn81xx/chip.h b/src/soc/cavium/cn81xx/chip.h new file mode 100644 index 0000000000..9716a5da6a --- /dev/null +++ b/src/soc/cavium/cn81xx/chip.h @@ -0,0 +1,22 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018-present Facebook, Inc. + * + * 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; version 2 of the License. + * + * 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. + */ + +#ifndef __SOC_CAVIUM_CN81XX_CHIP_H +#define __SOC_CAVIUM_CN81XX_CHIP_H + +struct soc_cavium_cn81xx_config { +}; + +#endif /* __SOC_CAVIUM_CN81XX_CHIP_H */ diff --git a/src/soc/cavium/cn81xx/clock.c b/src/soc/cavium/cn81xx/clock.c new file mode 100644 index 0000000000..bd6514cd41 --- /dev/null +++ b/src/soc/cavium/cn81xx/clock.c @@ -0,0 +1,79 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 Facebook, Inc. + * Copyright 2003-2017 Cavium Inc. <support@cavium.com> + * + * 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; version 2 of the License. + * + * 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. + */ +#include <soc/clock.h> +#include <arch/io.h> +#include <soc/addressmap.h> + +#define PLL_REF_CLK 50000000 /* 50 MHz */ + +union cavm_rst_boot { + u64 u; + struct { + u64 rboot_pin:1; + u64 rboot:1; + u64 lboot:10; + u64 lboot_ext23:6; + u64 lboot_ext45:6; + u64 reserved_24_29:6; + u64 lboot_oci:3; + u64 pnr_mul:6; + u64 reserved_39_39:1; + u64 c_mul:7; + u64 reserved_47_54:8; + u64 dis_scan:1; + u64 dis_huk:1; + u64 vrm_err:1; + u64 jt_tstmode:1; + u64 ckill_ppdis:1; + u64 trusted_mode:1; + u64 ejtagdis:1; + u64 jtcsrdis:1; + u64 chipkill:1; + } s; +}; + +/** + * Returns the reference clock speed in Hz + */ +u64 thunderx_get_ref_clock(void) +{ + return PLL_REF_CLK; +} + + +/** + * Returns the I/O clock speed in Hz + */ +u64 thunderx_get_io_clock(void) +{ + union cavm_rst_boot rst_boot; + + rst_boot.u = read64((void *)RST_PF_BAR0); + + return rst_boot.s.pnr_mul * PLL_REF_CLK; +} + +/** + * Returns the core clock speed in Hz + */ +u64 thunderx_get_core_clock(void) +{ + union cavm_rst_boot rst_boot; + + rst_boot.u = read64((void *)RST_PF_BAR0); + + return rst_boot.s.c_mul * PLL_REF_CLK; +} diff --git a/src/soc/cavium/cn81xx/cpu.c b/src/soc/cavium/cn81xx/cpu.c new file mode 100644 index 0000000000..c054aa8987 --- /dev/null +++ b/src/soc/cavium/cn81xx/cpu.c @@ -0,0 +1,26 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018-present Facebook, Inc. + * + * 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; version 2 of the License. + * + * 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. + */ + +#include <types.h> +#include <arch/io.h> +#include <soc/cpu.h> +#include <bdk-coreboot.h> + +/* Return the number of cores available in the chip */ +size_t cpu_get_num_cores(void) +{ + uint64_t available = read64((void *)0x87e006001738ll); + return bdk_dpop(available); +} diff --git a/src/soc/cavium/cn81xx/gpio.c b/src/soc/cavium/cn81xx/gpio.c new file mode 100644 index 0000000000..340ac1bc73 --- /dev/null +++ b/src/soc/cavium/cn81xx/gpio.c @@ -0,0 +1,193 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 Facebook, Inc. + * + * 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; version 2 of the License. + * + * 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. + */ + +#include <console/console.h> +#include <soc/gpio.h> +#include <arch/io.h> +#include <endian.h> +#include <soc/addressmap.h> + +union gpio_const { + u64 u; + struct { + u64 gpios:8; /** Number of GPIOs implemented */ + u64 pp:8; /** Number of PP vectors */ + u64:48; /* Reserved */ + } s; +}; +union bit_cfg { + u64 u; + struct { + u64 tx_oe : 1; /* Output Enable */ + u64 xor : 1; /* Invert */ + u64 int_en : 1; /* Interrupt Enable */ + u64 int_type : 1; /* Type of Interrupt */ + u64 filt_cnt : 4; /* Glitch filter counter */ + u64 filt_sel : 4; /* Glitch filter select */ + u64 tx_od : 1; /* Set Output to Open Drain */ + u64 : 3; + u64 pin_sel : 10; /* Select type of pin */ + u64 : 38; + } s; +}; + +struct cavium_gpio { + u64 rx_dat; + u64 tx_set; + u64 tx_clr; + u64 multicast; + u64 ocla_exten_trg; + u64 strap; + u64 reserved[12]; + union gpio_const gpio_const; /* Offset 90 */ + u64 reserved2[109]; + union bit_cfg bit_cfg[48]; /* Offset 400 */ +}; + +/* Base address of GPIO BAR */ +static const void *gpio_get_baseaddr(void) +{ + return (const void *)GPIO_PF_BAR0; +} + +/* Number of GPIO pins. Usually 48. */ +gpio_t gpio_pin_count(void) +{ + struct cavium_gpio *regs = (struct cavium_gpio *)gpio_get_baseaddr(); + union gpio_const gpio_const; + + gpio_const.u = read64(®s->gpio_const.u); + + if (gpio_const.s.gpios > 64) + return 64; // FIXME: Add support for more than 64 GPIOs + return gpio_const.s.gpios; +} + +/* Set GPIO to software control and direction INPUT */ +void gpio_input(gpio_t gpio) +{ + struct cavium_gpio *regs = (struct cavium_gpio *)gpio_get_baseaddr(); + union bit_cfg bit_cfg; + + if (gpio >= gpio_pin_count()) + return; + + printk(BIOS_SPEW, "GPIO(%u): direction input\n", gpio); + + bit_cfg.u = read64(®s->bit_cfg[gpio]); + bit_cfg.s.pin_sel = 0; + bit_cfg.s.tx_oe = 0; + write64(®s->bit_cfg[gpio], bit_cfg.u); +} + +/* Set GPIO of direction OUTPUT to level */ +void gpio_set(gpio_t gpio, int value) +{ + struct cavium_gpio *regs = (struct cavium_gpio *)gpio_get_baseaddr(); + + if (gpio >= gpio_pin_count()) + return; + + printk(BIOS_SPEW, "GPIO(%u): level: %u\n", gpio, !!value); + + if (value) + write64(®s->tx_set, 1 << gpio); + else + write64(®s->tx_clr, 1 << gpio); +} + +/* Set GPIO direction to OUTPUT with level */ +void gpio_output(gpio_t gpio, int value) +{ + struct cavium_gpio *regs = (struct cavium_gpio *)gpio_get_baseaddr(); + union bit_cfg bit_cfg; + + if (gpio >= gpio_pin_count()) + return; + + gpio_set(gpio, value); + + printk(BIOS_SPEW, "GPIO(%u): direction output with level: %u\n", gpio, + !!value); + + bit_cfg.u = read64(®s->bit_cfg[gpio]); + bit_cfg.s.pin_sel = 0; + bit_cfg.s.tx_oe = 1; + write64(®s->bit_cfg[gpio], bit_cfg.u); +} + +/* Set GPIO invert flag, that affects INPUT and OUTPUT */ +void gpio_invert(gpio_t gpio, int value) +{ + struct cavium_gpio *regs = (struct cavium_gpio *)gpio_get_baseaddr(); + union bit_cfg bit_cfg; + + if (gpio >= gpio_pin_count()) + return; + + bit_cfg.u = read64(®s->bit_cfg[gpio]); + bit_cfg.s.xor = !!value; + write64(®s->bit_cfg[gpio], bit_cfg.u); + + printk(BIOS_SPEW, "GPIO(%u): invert: %s\n", gpio, value ? "ON" : "OFF"); +} + +/* Read GPIO level with direction set to INPUT */ +int gpio_get(gpio_t gpio) +{ + struct cavium_gpio *regs = (struct cavium_gpio *)gpio_get_baseaddr(); + + if (gpio >= gpio_pin_count()) + return 0; + + const u64 reg = read64(®s->rx_dat); + printk(BIOS_SPEW, "GPIO(%u): input: %u\n", gpio, !!(reg & (1 << gpio))); + + return !!(reg & (1 << gpio)); +} + +/* Read GPIO STRAP level sampled at cold boot */ +int gpio_strap_value(gpio_t gpio) +{ + struct cavium_gpio *regs = (struct cavium_gpio *)gpio_get_baseaddr(); + + if (gpio >= gpio_pin_count()) + return 0; + + const u64 reg = read64(®s->strap); + printk(BIOS_SPEW, "GPIO(%u): strap: %u\n", gpio, !!(reg & (1 << gpio))); + + return !!(reg & (1 << gpio)); +} + +/* FIXME: Parse devicetree ? */ +void gpio_init(void) +{ + const size_t pin_count = gpio_pin_count(); + + printk(BIOS_DEBUG, "GPIO: base address: %p, pin count: %zd\n", + gpio_get_baseaddr(), pin_count); + + if (!pin_count) + return; +} + +void gpio_input_pulldown(gpio_t gpio) +{ +} + +void gpio_input_pullup(gpio_t gpio) +{ +} diff --git a/src/soc/cavium/cn81xx/include/soc/addressmap.h b/src/soc/cavium/cn81xx/include/soc/addressmap.h new file mode 100644 index 0000000000..e23549450b --- /dev/null +++ b/src/soc/cavium/cn81xx/include/soc/addressmap.h @@ -0,0 +1,123 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2017-present Facebook, Inc. + * + * 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; version 2 of the License. + * + * 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. + */ + +#ifndef __SOC_CAVIUM_CN81XX_ADDRESSMAP_H__ +#define __SOC_CAVIUM_CN81XX_ADDRESSMAP_H__ + +#define MAX_DRAM_ADDRESS 0x2000000000ULL /* 128GB */ + +/* Physical addressed with bit 47 set indicate I/O memory space. */ + +/* ARM code entry vector */ +#define BOOTROM_OFFSET 0x100000 + +/* L2C */ +#define L2C_PF_BAR0 0x87E080800000ULL +#define L2C_TAD0_PF_BAR0 (0x87E050000000ULL + 0x10000) +#define L2C_TAD0_INT_W1C (0x87E050000000ULL + 0x40000) +#define L2C_CBC0_PF_BAR0 0x87E058000000ULL +#define L2C_MCI0_PF_BAR0 0x87E05C000000ULL + +/* LMC */ +#define LMC0_PF_BAR0 0x87E088000000ULL +#define LMC0_DDR_PLL_CTL0 0x258 + +/* OCLA */ + +/* IOB */ +#define IOBN0_PF_BAR0 0x87E0F0000000ULL +#define MRML_PF_BAR0 0x87E0FC000000ULL + +/* SMMU */ +#define SMMU_PF_BAR0 0x830000000000ULL + +/* GTI */ +#define GTI_PF_BAR0 0x844000000000ULL + +/* PCC */ +#define ECAM_PF_BAR2 0x848000000000ULL + +/* CPT */ +/* SLI */ + +/* RST */ +#define RST_PF_BAR0 (0x87E006000000ULL + 0x1600) +#define FUSF_PF_BAR0 0x87E004000000ULL +#define MIO_FUS_PF_BAR0 0x87E003000000ULL +#define MIO_BOOT_PF_BAR0 0x87E000000000ULL + +/* PTP */ +#define MIO_PTP_PF_BAR0 0x807000000000ULL + +/* GIC */ +/* NIC */ +/* LBK */ + +#define GTI_PF_BAR0 0x844000000000ULL + +/* DAP */ +/* BCH */ +/* KEY */ +/* RNG */ + +#define GSER0_PF_BAR0 (0x87E090000000ULL + (0 << 24)) +#define GSER1_PF_BAR0 (0x87E090000000ULL + (1 << 24)) +#define GSER2_PF_BAR0 (0x87E090000000ULL + (2 << 24)) +#define GSER3_PF_BAR0 (0x87E090000000ULL + (3 << 24)) +#define GSERx_PF_BAR0(x) \ + ((((x) == 0) || ((x) == 1) || ((x) == 2) || ((x) == 3)) ? \ + (0x87E090000000ULL + ((x) << 24)) : 0) + +/* PEM */ +/* SATA */ +/* USB */ + +/* UAA */ +#define UAA0_PF_BAR0 (0x87E028000000ULL + (0 << 24)) +#define UAA1_PF_BAR0 (0x87E028000000ULL + (1 << 24)) +#define UAA2_PF_BAR0 (0x87E028000000ULL + (2 << 24)) +#define UAA3_PF_BAR0 (0x87E028000000ULL + (3 << 24)) +#define UAAx_PF_BAR0(x) \ + ((((x) == 0) || ((x) == 1) || ((x) == 2) || ((x) == 3)) ? \ + (0x87E028000000ULL + ((x) << 24)) : 0) + + +/* TWSI */ +#define MIO_TWS0_PF_BAR0 (0x87E0D0000000ULL + (0 << 24)) +#define MIO_TWS1_PF_BAR0 (0x87E0D0000000ULL + (1 << 24)) +#define MIO_TWSx_PF_BAR0(x) \ + ((((x) == 0) || ((x) == 1)) ? (0x87E0D0000000ULL + ((x) << 24)) : 0) + +/* GPIO */ +#define GPIO_PF_BAR0 0x803000000000ULL + +/* SGPIO */ +#define SGP_PF_BAR0 0x803000000000ULL + +/* SMI */ + +/* SPI */ +#define MPI_PF_BAR0 (0x804000000000ULL + 0x1000) + +/* PCM */ +/* PBUS */ +/* NDF */ +/* EMM */ + +/* VRM */ +/* VRM BARs are spaced apart by 0x1000000 */ +#define VRM0_PF_BAR0 0x87E021000000ULL + +#endif /* __SOC_CAVIUM_CN81XX_ADDRESSMAP_H__ */ diff --git a/src/soc/cavium/cn81xx/include/soc/clock.h b/src/soc/cavium/cn81xx/include/soc/clock.h new file mode 100644 index 0000000000..d436c121cb --- /dev/null +++ b/src/soc/cavium/cn81xx/include/soc/clock.h @@ -0,0 +1,26 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2017-present Facebook, Inc. + * Copyright 2003-2017 Cavium Inc. <support@cavium.com> + * + * 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; version 2 of the License. + * + * 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. + */ + +#ifndef SRC_SOC_CAVIUM_CN81XX_INCLUDE_CLOCK_H_ +#define SRC_SOC_CAVIUM_CN81XX_INCLUDE_CLOCK_H_ + +#include <types.h> + +u64 thunderx_get_ref_clock(void); +u64 thunderx_get_io_clock(void); +u64 thunderx_get_core_clock(void); + +#endif /* SRC_SOC_CAVIUM_CN81XX_INCLUDE_CLOCK_H_ */ diff --git a/src/soc/cavium/cn81xx/include/soc/cpu.h b/src/soc/cavium/cn81xx/include/soc/cpu.h new file mode 100644 index 0000000000..df3c06955a --- /dev/null +++ b/src/soc/cavium/cn81xx/include/soc/cpu.h @@ -0,0 +1,22 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2017-present Facebook, Inc. + * Copyright 2003-2017 Cavium Inc. <support@cavium.com> + * + * 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; version 2 of the License. + * + * 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. + */ + +#ifndef __SOC_CAVIUM_CN81XX_CPU_H__ +#define __SOC_CAVIUM_CN81XX_CPU_H__ + +size_t cpu_get_num_cores(void); + +#endif /* __SOC_CAVIUM_CN81XX_CPU_H__ */ diff --git a/src/soc/cavium/cn81xx/include/soc/gpio.h b/src/soc/cavium/cn81xx/include/soc/gpio.h new file mode 100644 index 0000000000..6986482f79 --- /dev/null +++ b/src/soc/cavium/cn81xx/include/soc/gpio.h @@ -0,0 +1,34 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2016 Rockchip Inc. + * Copyright 2018-present Facebook, Inc. + * + * 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; version 2 of the License. + * + * 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. + */ + +#ifndef __COREBOOT_SRC_SOC_CAVIUM_COMMON_INCLUDE_SOC_GPIO_H +#define __COREBOOT_SRC_SOC_CAVIUM_COMMON_INCLUDE_SOC_GPIO_H + +#include <types.h> + +typedef u32 gpio_t; +#include <gpio.h> + +/* The following functions must be implemented by SoC/board code. */ + + +gpio_t gpio_pin_count(void); +void gpio_invert(gpio_t gpio, int value); +int gpio_strap_value(gpio_t gpio); + +void gpio_init(void); + +#endif diff --git a/src/soc/cavium/cn81xx/include/soc/memlayout.ld b/src/soc/cavium/cn81xx/include/soc/memlayout.ld new file mode 100644 index 0000000000..f0ac2c9da5 --- /dev/null +++ b/src/soc/cavium/cn81xx/include/soc/memlayout.ld @@ -0,0 +1,41 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2016 Rockchip Inc. + * Copyright 2017-present Facebook, Inc. + * + * 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; version 2 of the License. + * + * 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. + */ + +#include <memlayout.h> +#include <soc/addressmap.h> +#include <arch/header.ld> + +SECTIONS +{ + DRAM_START(0x00000000) + /* FIXME: Place BL31 in first 1MiB */ + + /* bootblock-custom.S does setup CAR from SRAM_START to SRAM_END */ + SRAM_START(BOOTROM_OFFSET) + STACK(BOOTROM_OFFSET, 16K) + TIMESTAMP(BOOTROM_OFFSET + 0x4000, 4K) + PRERAM_CBFS_CACHE(BOOTROM_OFFSET + 0x6000, 8K) + PRERAM_CBMEM_CONSOLE(BOOTROM_OFFSET + 0x8000, 8K) + + BOOTBLOCK(BOOTROM_OFFSET + 0x20000, 64K) + ROMSTAGE(BOOTROM_OFFSET + 0x40000, 256K) + SRAM_END(BOOTROM_OFFSET + 0x80000) + TTB(BOOTROM_OFFSET + 0x80000, 128K) + RAMSTAGE(BOOTROM_OFFSET + 0xa0000, 512K) + + /* Leave some space for the payload */ + POSTRAM_CBFS_CACHE(0x2000000, 16M) +} diff --git a/src/soc/cavium/cn81xx/include/soc/sdram.h b/src/soc/cavium/cn81xx/include/soc/sdram.h new file mode 100644 index 0000000000..5a3e5196b5 --- /dev/null +++ b/src/soc/cavium/cn81xx/include/soc/sdram.h @@ -0,0 +1,25 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2017-present Facebook, Inc. + * Copyright 2003-2017 Cavium Inc. <support@cavium.com> + * + * 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; version 2 of the License. + * + * 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. + */ + +#ifndef __SOC_CAVIUM_CN81XX_SDRAM_H__ +#define __SOC_CAVIUM_CN81XX_SDRAM_H__ + +#include <types.h> + +size_t sdram_size_mb(void); +void sdram_init(void); + +#endif /* !__SOC_CAVIUM_CN81XX_SDRAM_H__ */ diff --git a/src/soc/cavium/cn81xx/include/soc/soc.h b/src/soc/cavium/cn81xx/include/soc/soc.h new file mode 100644 index 0000000000..a751e64846 --- /dev/null +++ b/src/soc/cavium/cn81xx/include/soc/soc.h @@ -0,0 +1,43 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2017-present Facebook, Inc. + * + * 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; version 2 of the License. + * + * 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. + */ + +#ifndef __SOC_CAVIUM_CN81XX_INCLUDE_SOC_SOC_H +#define __SOC_CAVIUM_CN81XX_INCLUDE_SOC_SOC_H + +#include <inttypes.h> +#include <types.h> + +/* MIO BOOT Registers */ +struct cn81xx_mio_boot { + u8 rsvd0[0xb0]; + u64 thr; + u8 rsvd1[0x8]; + u64 pin_defs; + u8 rsvd2[0x8]; + u64 ap_jump; + u64 rom_limit; + u8 rsvd3[0x18]; + u64 bist_stat; +}; +check_member(cn81xx_mio_boot, bist_stat, 0xf8); + +/* + * 0 = Board supplies 100MHz to DLM_REF_CLK + * 1 = bOard supplies 50MHz to PLL_REFCLK + * */ +#define MIO_BOOT_PIN_DEFS_UART0_RTS (1 << 16) +#define MIO_BOOT_PIN_DEFS_UART1_RTS (1 << 17) + +#endif /* ! __SOC_CAVIUM_CN81XX_INCLUDE_SOC_SOC_H */ diff --git a/src/soc/cavium/cn81xx/include/soc/spi.h b/src/soc/cavium/cn81xx/include/soc/spi.h new file mode 100644 index 0000000000..bb69daac91 --- /dev/null +++ b/src/soc/cavium/cn81xx/include/soc/spi.h @@ -0,0 +1,40 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2017-present Facebook, Inc. + * + * 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; version 2 of the License. + * + * 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. + */ + +#ifndef __COREBOOT_SRC_SOC_CN81XX_INCLUDE_SOC_SPI_H +#define __COREBOOT_SRC_SOC_CN81XX_INCLUDE_SOC_SPI_H + +/* This driver serves as a CBFS media source. */ +#include <spi-generic.h> +#include <stddef.h> + +void spi_enable(const size_t bus); +void spi_disable(const size_t bus); +void spi_set_cs(const size_t bus, + const size_t chip_select, + const size_t assert_is_low); +void spi_set_clock(const size_t bus, + const size_t speed_hz, + const size_t idle_low, + const size_t idle_cycles); +void spi_set_lsbmsb(const size_t bus, const size_t lsb_first); +void spi_init_custom(const size_t bus, + const size_t speed_hz, + const size_t idle_low, + const size_t idle_cycles, + const size_t lsb_first, + const size_t chip_select, + const size_t assert_is_low); +#endif /* ! __COREBOOT_SRC_SOC_CN81XX_INCLUDE_SOC_SPI_H */ diff --git a/src/soc/cavium/cn81xx/include/soc/timer.h b/src/soc/cavium/cn81xx/include/soc/timer.h new file mode 100644 index 0000000000..a12f68e422 --- /dev/null +++ b/src/soc/cavium/cn81xx/include/soc/timer.h @@ -0,0 +1,30 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2017-present Facebook, Inc. + * + * 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; version 2 of the License. + * + * 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. + */ + +#ifndef __SOC_CAVIUM_CN81XX_TIMER_H__ +#define __SOC_CAVIUM_CN81XX_TIMER_H__ + +#include <inttypes.h> +#include <types.h> +#include <timer.h> +#include <delay.h> + +/* Watchdog functions */ +void watchdog_set(const size_t index, unsigned int timeout_ms); +void watchdog_poke(const size_t index); +void watchdog_disable(const size_t index); +int watchdog_is_running(const size_t index); + +#endif /* __SOC_CAVIUM_CN81XX_TIMER_H__ */ diff --git a/src/soc/cavium/cn81xx/include/soc/twsi.h b/src/soc/cavium/cn81xx/include/soc/twsi.h new file mode 100644 index 0000000000..6c5211e63b --- /dev/null +++ b/src/soc/cavium/cn81xx/include/soc/twsi.h @@ -0,0 +1,23 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2017-present Facebook, Inc. + * + * 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; version 2 of the License. + * + * 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. + */ +#include <types.h> +#include <device/i2c.h> + +#ifndef __SOC_CAVIUM_CN81XX_INCLUDE_SOC_TWSI_H +#define __SOC_CAVIUM_CN81XX_INCLUDE_SOC_TWSI_H + +int twsi_init(unsigned int bus, enum i2c_speed hz); + +#endif diff --git a/src/soc/cavium/cn81xx/include/soc/uart.h b/src/soc/cavium/cn81xx/include/soc/uart.h new file mode 100644 index 0000000000..e4022068bc --- /dev/null +++ b/src/soc/cavium/cn81xx/include/soc/uart.h @@ -0,0 +1,25 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2017-present Facebook, Inc. + * + * 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; version 2 of the License. + * + * 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. + */ + +#ifndef __SOC_CAVIUM_COMMON_INCLUDE_SOC_UART_H +#define __SOC_CAVIUM_COMMON_INCLUDE_SOC_UART_H + +#include <inttypes.h> +#include <types.h> + +int uart_is_enabled(const size_t bus); +int uart_setup(const size_t bus, int baudrate); + +#endif /* __SOC_CAVIUM_COMMON_INCLUDE_SOC_UART_H */ diff --git a/src/soc/cavium/cn81xx/sdram.c b/src/soc/cavium/cn81xx/sdram.c new file mode 100644 index 0000000000..77717ea78d --- /dev/null +++ b/src/soc/cavium/cn81xx/sdram.c @@ -0,0 +1,94 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 Facebook, Inc. + * Copyright 2003-2017 Cavium Inc. <support@cavium.com> + * + * 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; version 2 of the License. + * + * 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. + * + * Derived from Cavium's BSD-3 Clause OCTEONTX-SDK-6.2.0. + */ + +#include <console/console.h> +#include <soc/sdram.h> + +#include <libbdk-arch/bdk-warn.h> +#include <libbdk-arch/bdk-csrs-rst.h> +#include <libbdk-boot/bdk-watchdog.h> +#include <libbdk-dram/bdk-dram-config.h> +#include <libbdk-dram/bdk-dram-test.h> +#include <libbdk-hal/bdk-config.h> +#include <libbdk-hal/bdk-utils.h> +#include <libbdk-hal/bdk-l2c.h> +#include <libdram/libdram-config.h> + +size_t sdram_size_mb(void) +{ + return bdk_dram_get_size_mbytes(0); +} + +/* based on bdk_boot_dram() */ +void sdram_init(void) +{ + printk(BIOS_DEBUG, "Initializing DRAM\n"); + + /** + * FIXME: second arg is actually a desired frequency if set (the + * function usually obtains frequency via the config). That might + * be useful if FDT or u-boot env is too cumbersome. + */ + int mbytes = bdk_dram_config(0, 0); + if (mbytes < 0) { + bdk_error("N0: Failed DRAM init\n"); + die("DRAM INIT FAILED !\n"); + } + + /* Poke the watchdog */ + bdk_watchdog_poke(); + + /* Report DRAM status */ + printf("N0: DRAM:%s\n", bdk_dram_get_info_string(0)); + + /* See if we should test this node's DRAM during boot */ + int test_dram = bdk_config_get_int(BDK_CONFIG_DRAM_BOOT_TEST, 0); + if (test_dram) { + /* Run the address test to make sure DRAM works */ + if (bdk_dram_test(13, 0, 0x10000000000ull, BDK_DRAM_TEST_NO_STATS | (1<<0))) { + /** + * FIXME(dhendrix): This should be handled by mainboard code since we + * don't necessarily have a BMC to report to. Also, we need to figure out + * if we need to keep going as to avoid getting into a boot loop. + */ + // bdk_boot_status(BDK_BOOT_STATUS_REQUEST_POWER_CYCLE); + printk(BIOS_ERR, "%s: Failed DRAM test.\n", __func__); + } + bdk_watchdog_poke(); + /* Put other node core back in reset */ + if (0 != bdk_numa_master()) + BDK_CSR_WRITE(0, BDK_RST_PP_RESET, -1); + /* Clear DRAM */ + uint64_t skip = 0; + if (0 == bdk_numa_master()) + skip = bdk_dram_get_top_of_bdk(); + void *base = bdk_phys_to_ptr(bdk_numa_get_address(0, skip)); + bdk_zero_memory(base, ((uint64_t)mbytes << 20) - skip); + bdk_watchdog_poke(); + } + + /* Unlock L2 now that DRAM works */ + if (0 == bdk_numa_master()) { + uint64_t l2_size = bdk_l2c_get_cache_size_bytes(0); + BDK_TRACE(INIT, "Unlocking L2\n"); + bdk_l2c_unlock_mem_region(0, 0, l2_size); + bdk_watchdog_poke(); + } + + printk(BIOS_INFO, "SDRAM initialization finished.\n"); +} diff --git a/src/soc/cavium/cn81xx/soc.c b/src/soc/cavium/cn81xx/soc.c new file mode 100644 index 0000000000..03f9122404 --- /dev/null +++ b/src/soc/cavium/cn81xx/soc.c @@ -0,0 +1,65 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 Facebook, Inc. + * Copyright 2003-2017 Cavium Inc. <support@cavium.com> + * + * 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; version 2 of the License. + * + * 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. + * + * Derived from Cavium's BSD-3 Clause OCTEONTX-SDK-6.2.0. + */ + +#include <bootmode.h> +#include <console/console.h> +#include <cpu/cpu.h> +#include <device/device.h> +#include <soc/addressmap.h> +#include <soc/clock.h> +#include <soc/sdram.h> +#include <soc/timer.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <symbols.h> +#include <libbdk-boot/bdk-boot.h> + +static void soc_read_resources(device_t dev) +{ + ram_resource(dev, 0, (uintptr_t)_dram / KiB, sdram_size_mb() * KiB); +} + +static void soc_init(device_t dev) +{ + /* Init ECAM, MDIO, PEM, PHY, QLM ... */ + bdk_boot(); + + /* TODO: additional trustzone init */ +} + +static void soc_final(device_t dev) +{ + watchdog_disable(0); +} + +static struct device_operations soc_ops = { + .read_resources = soc_read_resources, + .init = soc_init, + .final = soc_final, +}; + +static void enable_soc_dev(device_t dev) +{ + dev->ops = &soc_ops; +} + +struct chip_operations soc_cavium_cn81xx_ops = { + CHIP_NAME("SOC Cavium CN81XX") + .enable_dev = enable_soc_dev, +}; diff --git a/src/soc/cavium/cn81xx/spi.c b/src/soc/cavium/cn81xx/spi.c new file mode 100644 index 0000000000..5a5865e36e --- /dev/null +++ b/src/soc/cavium/cn81xx/spi.c @@ -0,0 +1,401 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 Facebook, Inc. + * Copyright 2003-2017 Cavium Inc. <support@cavium.com> + * + * 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; version 2 of the License. + * + * 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. + * + * Derived from Cavium's BSD-3 Clause OCTEONTX-SDK-6.2.0. + */ + +#include <arch/io.h> +#include <assert.h> +#include <console/console.h> +#include <delay.h> +#include <endian.h> +#include <soc/addressmap.h> +#include <soc/spi.h> +#include <soc/clock.h> +#include <spi-generic.h> +#include <spi_flash.h> +#include <stdlib.h> +#include <timer.h> + +union cavium_spi_cfg { + u64 u; + struct { + u64 enable : 1; + u64 idlelow : 1; + u64 clk_cont : 1; + u64 wireor : 1; + u64 lsbfirst : 1; + u64 : 2; + u64 cshi : 1; + u64 idleclks : 2; + u64 tristate : 1; + u64 cslate : 1; + u64 csena : 4; /* Must be one */ + u64 clkdiv : 13; + u64 : 35; + } s; +}; + +union cavium_spi_sts { + u64 u; + struct { + u64 busy : 1; + u64 mpi_intr : 1; + u64 : 6; + u64 rxnum : 5; + u64 : 51; + } s; +}; + +union cavium_spi_tx { + u64 u; + struct { + u64 totnum : 5; + u64 : 3; + u64 txnum : 5; + u64 : 3; + u64 leavecs : 1; + u64 : 3; + u64 csid : 2; + u64 : 42; + } s; +}; + +struct cavium_spi { + union cavium_spi_cfg cfg; + union cavium_spi_sts sts; + union cavium_spi_tx tx; + u64 rsvd1; + u64 sts_w1s; + u64 rsvd2; + u64 int_ena_w1c; + u64 int_ena_w1s; + u64 wide_dat; + u8 rsvd4[0x38]; + u64 dat[8]; +}; + +check_member(cavium_spi, cfg, 0); +check_member(cavium_spi, sts, 0x8); +check_member(cavium_spi, tx, 0x10); +check_member(cavium_spi, dat[7], 0xb8); + +struct cavium_spi_slave { + struct cavium_spi *regs; + int cs; +}; + +#define SPI_TIMEOUT_US 5000 + +static struct cavium_spi_slave cavium_spi_slaves[] = { + { + .regs = (struct cavium_spi *)MPI_PF_BAR0, + .cs = 0, + }, +}; + +static struct cavium_spi_slave *to_cavium_spi(const struct spi_slave *slave) +{ + assert(slave->bus < ARRAY_SIZE(cavium_spi_slaves)); + return &cavium_spi_slaves[slave->bus]; +} + +/** + * Enable the SPI controller. Pins are driven. + * + * @param bus The SPI bus to operate on + */ +void spi_enable(const size_t bus) +{ + union cavium_spi_cfg cfg; + + assert(bus < ARRAY_SIZE(cavium_spi_slaves)); + if (bus >= ARRAY_SIZE(cavium_spi_slaves)) + return; + + struct cavium_spi *regs = cavium_spi_slaves[bus].regs; + + cfg.u = read64(®s->cfg); + cfg.s.csena = 0xf; + cfg.s.enable = 1; + write64(®s->cfg, cfg.u); +} + +/** + * Disable the SPI controller. Pins are tristated. + * + * @param bus The SPI bus to operate on + */ +void spi_disable(const size_t bus) +{ + union cavium_spi_cfg cfg; + + assert(bus < ARRAY_SIZE(cavium_spi_slaves)); + if (bus >= ARRAY_SIZE(cavium_spi_slaves)) + return; + + struct cavium_spi *regs = cavium_spi_slaves[bus].regs; + + cfg.u = read64(®s->cfg); + cfg.s.csena = 0xf; + cfg.s.enable = 0; + write64(®s->cfg, cfg.u); +} + +/** + * Set SPI Chip select line and level if asserted. + * + * @param bus The SPI bus to operate on + * @param chip_select The chip select pin to use (0 - 3) + * @param assert_is_low CS pin state is low when asserted + */ +void spi_set_cs(const size_t bus, + const size_t chip_select, + const size_t assert_is_low) +{ + union cavium_spi_cfg cfg; + + assert(bus < ARRAY_SIZE(cavium_spi_slaves)); + if (bus >= ARRAY_SIZE(cavium_spi_slaves)) + return; + + cavium_spi_slaves[bus].cs = chip_select & 0x3; + struct cavium_spi *regs = cavium_spi_slaves[bus].regs; + + cfg.u = read64(®s->cfg); + cfg.s.csena = 0xf; + cfg.s.cshi = !assert_is_low; + write64(®s->cfg, cfg.u); + + //FIXME: CS2/3: Change pin mux here +} + +/** + * Set SPI clock frequency. + * + * @param bus The SPI bus to operate on + * @param speed_hz The SPI frequency in Hz + * @param idle_low The SPI clock idles low + * @param idle_cycles Number of CLK cycles between two commands (0 - 3) + + */ +void spi_set_clock(const size_t bus, + const size_t speed_hz, + const size_t idle_low, + const size_t idle_cycles) +{ + union cavium_spi_cfg cfg; + + assert(bus < ARRAY_SIZE(cavium_spi_slaves)); + if (bus >= ARRAY_SIZE(cavium_spi_slaves)) + return; + + struct cavium_spi *regs = cavium_spi_slaves[bus].regs; + const uint64_t sclk = thunderx_get_io_clock(); + + cfg.u = read64(®s->cfg); + cfg.s.csena = 0xf; + cfg.s.clk_cont = 0; + cfg.s.idlelow = !!idle_low; + cfg.s.idleclks = idle_cycles & 0x3; + cfg.s.clkdiv = MIN(sclk / (2ULL * speed_hz), 0x1fff); + write64(®s->cfg, cfg.u); + + printk(BIOS_DEBUG, "SPI: set clock to %lld kHz\n", + (sclk / (2ULL * cfg.s.clkdiv)) >> 10); +} + +/** + * Set SPI LSB/MSB first. + * + * @param bus The SPI bus to operate on + * @param lsb_first The SPI operates LSB first + * + */ +void spi_set_lsbmsb(const size_t bus, const size_t lsb_first) +{ + union cavium_spi_cfg cfg; + + assert(bus < ARRAY_SIZE(cavium_spi_slaves)); + if (bus >= ARRAY_SIZE(cavium_spi_slaves)) + return; + + struct cavium_spi *regs = cavium_spi_slaves[bus].regs; + + cfg.u = read64(®s->cfg); + cfg.s.csena = 0xf; + cfg.s.lsbfirst = !!lsb_first; + write64(®s->cfg, cfg.u); +} + +/** + * Init SPI with custom parameters and enable SPI controller. + * + * @param bus The SPI bus to operate on + * @param speed_hz The SPI frequency in Hz + * @param idle_low The SPI clock idles low + * @param idle_cycles Number of CLK cycles between two commands (0 - 3) + * @param lsb_first The SPI operates LSB first + * @param chip_select The chip select pin to use (0 - 3) + * @param assert_is_low CS pin state is low when asserted + */ +void spi_init_custom(const size_t bus, + const size_t speed_hz, + const size_t idle_low, + const size_t idle_cycles, + const size_t lsb_first, + const size_t chip_select, + const size_t assert_is_low) +{ + spi_disable(bus); + spi_set_clock(bus, speed_hz, idle_low, idle_cycles); + spi_set_lsbmsb(bus, lsb_first); + spi_set_cs(bus, chip_select, assert_is_low); + spi_enable(bus); +} + +/** + * Init all SPI controllers with default values and enable all SPI controller. + * + */ +void spi_init(void) +{ + for (size_t i = 0; i < ARRAY_SIZE(cavium_spi_slaves); i++) { + spi_disable(i); + spi_set_clock(i, 12500000, 0, 0); + spi_set_lsbmsb(i, 0); + spi_set_cs(i, 0, 1); + spi_enable(i); + } +} + +static int cavium_spi_wait(struct cavium_spi *regs) +{ + struct stopwatch sw; + union cavium_spi_sts sts; + + stopwatch_init_usecs_expire(&sw, SPI_TIMEOUT_US); + do { + sts.u = read64(®s->sts); + if (!sts.s.busy) + return 0; + } while (!stopwatch_expired(&sw)); + printk(BIOS_DEBUG, "SPI: Timed out after %uus\n", SPI_TIMEOUT_US); + return -1; +} + +static int do_xfer(const struct spi_slave *slave, struct spi_op *vector, + int leavecs) +{ + struct cavium_spi *regs = to_cavium_spi(slave)->regs; + uint8_t *out_buf = (uint8_t *)vector->dout; + size_t bytesout = vector->bytesout; + uint8_t *in_buf = (uint8_t *)vector->din; + size_t bytesin = vector->bytesin; + union cavium_spi_sts sts; + union cavium_spi_tx tx; + + /** + * The CN81xx SPI controller is half-duplex and has 8 data registers. + * If >8 bytes remain in the transfer then we must set LEAVECS = 1 so + * that the /CS remains asserted. Once <=8 bytes remain we must set + * LEAVECS = 0 so that /CS is de-asserted, thus completing the transfer. + */ + while (bytesout) { + size_t out_now = MIN(bytesout, 8); + unsigned int i; + + for (i = 0; i < out_now; i++) + write64(®s->dat[i], out_buf[i] & 0xff); + + tx.u = 0; + tx.s.csid = to_cavium_spi(slave)->cs; + if (leavecs || ((bytesout > 8) || bytesin)) + tx.s.leavecs = 1; + /* number of bytes to transmit goes in both TXNUM and TOTNUM */ + tx.s.totnum = out_now; + tx.s.txnum = out_now; + write64(®s->tx, tx.u); + + /* check status */ + if (cavium_spi_wait(regs) < 0) + return -1; + + bytesout -= out_now; + out_buf += out_now; + } + + while (bytesin) { + size_t in_now = MIN(bytesin, 8); + unsigned int i; + + tx.u = 0; + tx.s.csid = to_cavium_spi(slave)->cs; + if (leavecs || (bytesin > 8)) + tx.s.leavecs = 1; + tx.s.totnum = in_now; + write64(®s->tx, tx.u); + + /* check status */ + if (cavium_spi_wait(regs) < 0) + return -1; + + sts.u = read64(®s->sts); + if (sts.s.rxnum != in_now) { + printk(BIOS_ERR, + "SPI: Incorrect number of bytes received: %u.\n", + sts.s.rxnum); + return -1; + } + + for (i = 0; i < in_now; i++) { + *in_buf = (uint8_t)((read64(®s->dat[i]) & 0xff)); + in_buf++; + } + bytesin -= in_now; + } + + return 0; +} + +static int spi_ctrlr_xfer_vector(const struct spi_slave *slave, + struct spi_op vectors[], size_t count) +{ + int i; + + for (i = 0; i < count; i++) { + if (do_xfer(slave, &vectors[i], count - 1 == i ? 0 : 1)) { + printk(BIOS_ERR, + "SPI: Failed to transfer %zu vectors.\n", count); + return -1; + } + } + + return 0; +} +static const struct spi_ctrlr spi_ctrlr = { + + .xfer_vector = spi_ctrlr_xfer_vector, + .max_xfer_size = SPI_CTRLR_DEFAULT_MAX_XFER_SIZE, +}; + +const struct spi_ctrlr_buses spi_ctrlr_bus_map[] = { + { + .ctrlr = &spi_ctrlr, + .bus_start = 0, + .bus_end = ARRAY_SIZE(cavium_spi_slaves) - 1, + }, +}; +const size_t spi_ctrlr_bus_map_count = ARRAY_SIZE(spi_ctrlr_bus_map); diff --git a/src/soc/cavium/cn81xx/timer.c b/src/soc/cavium/cn81xx/timer.c new file mode 100644 index 0000000000..0321a49ad9 --- /dev/null +++ b/src/soc/cavium/cn81xx/timer.c @@ -0,0 +1,226 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 Facebook, Inc. + * Copyright 2003-2017 Cavium Inc. + * + * 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; version 2 of the License. + * + * 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. + * + * Derived from Cavium's BSD-3 Clause OCTEONTX-SDK-6.2.0. + */ + +#include <arch/io.h> +#include <console/console.h> +#include <inttypes.h> +#include <soc/clock.h> +#include <soc/timer.h> +#include <stdint.h> +#include <timer.h> +#include <soc/addressmap.h> +#include <assert.h> + +/* Global System Timers Unit (GTI) registers */ +struct cn81xx_timer { + u32 cc_cntcr; + u32 cc_cntsr; + u64 cc_cntcv; + u8 rsvd[0x10]; + u32 cc_cntfid0; + u32 cc_cntfid1; + u8 rsvd2[0x98]; + u32 cc_cntrate; + u32 cc_cntracc; + u64 cc_cntadd; + u64 cc_cntmb; + u64 cc_cntmbts; + u64 cc_cntmb_int; + u64 cc_cntmb_int_set; + u64 cc_cntmb_int_ena_clr; + u64 cc_cntmb_int_ena_set; + u64 cc_imp_ctl; + u8 skip[0x1fef8]; + u32 ctl_cntfrq; + u32 ctl_cntnsar; + u32 ctl_cnttidr; + u8 rsvd3[0x34]; + u32 ctl_cntacr0; + u8 skip2[0x1ffb8]; + u64 cwd_wdog[48]; /* Offset 0x40000 */ + u8 skip3[0xfe80]; + u64 cwd_poke[48]; /* Offset 0x50000 */ +}; + +check_member(cn81xx_timer, cc_imp_ctl, 0x100); +check_member(cn81xx_timer, ctl_cntacr0, 0x20040); +check_member(cn81xx_timer, cwd_wdog[0], 0x40000); +check_member(cn81xx_timer, cwd_poke[0], 0x50000); + + +#define GTI_CC_CNTCR_EN (1 << 0) +#define GTI_CC_CNTCR_HDBG (1 << 1) +#define GTI_CC_CNTCR_FCREQ (1 << 8) + +#define GTI_CC_CNTSR_DBGH (1 << 1) +#define GTI_CC_CNTSR_FCACK (1 << 8) + +#define GTI_CWD_WDOG_MODE_SHIFT 0 +#define GTI_CWD_WDOG_MODE_MASK 0x3 +#define GTI_CWD_WDOG_STATE_SHIFT 2 +#define GTI_CWD_WDOG_STATE_MASK 0x3 +#define GTI_CWD_WDOG_LEN_SHIFT 4 +#define GTI_CWD_WDOG_LEN_MASK 0xffff +#define GTI_CWD_WDOG_CNT_SHIFT 20 +#define GTI_CWD_WDOG_CNT_MASK 0xffffff +#define GTI_CWD_WDOC_DSTOP (1 << 44) +#define GTI_CWD_WDOC_GSTOP (1 << 45) + +static uint64_t timer_raw_value(void) +{ + struct cn81xx_timer *timer = (void *)GTI_PF_BAR0; + + return read64(&timer->cc_cntcv); +} + +/** + * Get GTI counter value. + * @param mt Structure to fill + */ +void timer_monotonic_get(struct mono_time *mt) +{ + mono_time_set_usecs(mt, timer_raw_value()); +} + +/** + * Init Global System Timers Unit (GTI). + * Configure timer to run at 1MHz tick-rate. + */ +void init_timer(void) +{ + struct cn81xx_timer *gti = (struct cn81xx_timer *)GTI_PF_BAR0; + + /* Check if the counter was already setup */ + if (gti->cc_cntcr & GTI_CC_CNTCR_EN) + return; + + u64 sclk = thunderx_get_io_clock(); + + /* Use coprocessor clock source */ + write32(>i->cc_imp_ctl, 0); + + /* Setup counter to operate at 1MHz */ + const size_t tickrate = 1000000; + write32(>i->cc_cntfid0, tickrate); + write32(>i->ctl_cntfrq, tickrate); + write32(>i->cc_cntrate, ((1ULL << 32) * tickrate) / sclk); + + /* Enable the counter */ + setbits_le32(>i->cc_cntcr, GTI_CC_CNTCR_EN); + + //u32 u = (CNTPS_CTL_EL1_IMASK | CNTPS_CTL_EL1_EN); + //BDK_MSR(CNTPS_CTL_EL1, u); +} + +/** + * Setup the watchdog to expire in timeout_ms milliseconds. When the watchdog + * expires, the chip three things happen: + * 1) Expire 1: interrupt that is ignored by the BDK + * 2) Expire 2: DEL3T interrupt, which is disabled and ignored + * 3) Expire 3: Soft reset of the chip + * + * Since we want a soft reset, we actually program the watchdog to expire at + * the timeout / 3. + * + * @param index Index of watchdog to configure + * @param timeout_ms Timeout in milliseconds. + */ +void watchdog_set(const size_t index, unsigned int timeout_ms) +{ + uint64_t sclk = thunderx_get_io_clock(); + uint64_t timeout_sclk = sclk * timeout_ms / 1000; + struct cn81xx_timer *timer = (struct cn81xx_timer *)GTI_PF_BAR0; + + assert(index < ARRAY_SIZE(timer->cwd_wdog)); + if (index >= ARRAY_SIZE(timer->cwd_wdog)) + return; + + /* + * Per comment above, we want the watchdog to expire at 3x the rate + * specified + */ + timeout_sclk /= 3; + /* Watchdog counts in 1024 cycle steps */ + uint64_t timeout_wdog = timeout_sclk >> 10; + /* We can only specify the upper 16 bits of a 24 bit value. Round up */ + timeout_wdog = (timeout_wdog + 0xff) >> 8; + /* If the timeout overflows the hardware limit, set max */ + if (timeout_wdog >= 0x10000) + timeout_wdog = 0xffff; + + printk(BIOS_DEBUG, "Watchdog: Set to expire %llu SCLK cycles\n", + timeout_wdog << 18); + clrsetbits_le64(&timer->cwd_wdog[index], + (GTI_CWD_WDOG_LEN_MASK << GTI_CWD_WDOG_LEN_SHIFT) | + (GTI_CWD_WDOG_MODE_MASK << GTI_CWD_WDOG_MODE_SHIFT), + (timeout_wdog << GTI_CWD_WDOG_LEN_SHIFT) | + (3 << GTI_CWD_WDOG_MODE_SHIFT)); +} + +/** + * Signal the watchdog that we are still running. + * + * @param index Index of watchdog to configure. + */ +void watchdog_poke(const size_t index) +{ + struct cn81xx_timer *timer = (struct cn81xx_timer *)GTI_PF_BAR0; + + assert(index < ARRAY_SIZE(timer->cwd_poke)); + if (index >= ARRAY_SIZE(timer->cwd_poke)) + return; + + write64(&timer->cwd_poke[0], 0); +} + +/** + * Disable the hardware watchdog + * + * @param index Index of watchdog to configure. + */ +void watchdog_disable(const size_t index) +{ + struct cn81xx_timer *timer = (struct cn81xx_timer *)GTI_PF_BAR0; + + assert(index < ARRAY_SIZE(timer->cwd_wdog)); + if (index >= ARRAY_SIZE(timer->cwd_wdog)) + return; + + write64(&timer->cwd_wdog[index], 0); + printk(BIOS_DEBUG, "Watchdog: Disabled\n"); +} + +/** + * Return true if the watchdog is configured and running + * + * @param index Index of watchdog to configure. + * + * @return Non-zero if watchdog is running. + */ +int watchdog_is_running(const size_t index) +{ + struct cn81xx_timer *timer = (struct cn81xx_timer *)GTI_PF_BAR0; + + assert(index < ARRAY_SIZE(timer->cwd_wdog)); + if (index >= ARRAY_SIZE(timer->cwd_wdog)) + return 0; + + uint64_t val = read64(&timer->cwd_wdog[index]); + + return !!(val & (GTI_CWD_WDOG_MODE_MASK << GTI_CWD_WDOG_MODE_SHIFT)); +} diff --git a/src/soc/cavium/cn81xx/twsi.c b/src/soc/cavium/cn81xx/twsi.c new file mode 100644 index 0000000000..e86cac7c8d --- /dev/null +++ b/src/soc/cavium/cn81xx/twsi.c @@ -0,0 +1,696 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 Facebook, Inc. + * Copyright 2003-2017 Cavium Inc. + * + * 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; version 2 of the License. + * + * 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. + * + * Derived from Cavium's BSD-3 Clause OCTEONTX-SDK-6.2.0. + */ +#include <console/console.h> +#include <soc/twsi.h> +#include <soc/clock.h> +#include <device/i2c.h> +#include <device/i2c_simple.h> +#include <assert.h> +#include <delay.h> +#include <arch/io.h> +#include <soc/addressmap.h> + +#define TWSI_THP 24 + +#define TWSI_SW_TWSI 0x1000 +#define TWSI_TWSI_SW 0x1008 +#define TWSI_INT 0x1010 +#define TWSI_SW_TWSI_EXT 0x1018 + +union twsx_sw_twsi { + u64 u; + struct { + u64 data:32; + u64 eop_ia:3; + u64 ia:5; + u64 addr:10; + u64 scr:2; + u64 size:3; + u64 sovr:1; + u64 r:1; + u64 op:4; + u64 eia:1; + u64 slonly:1; + u64 v:1; + } s; +}; + +union twsx_sw_twsi_ext { + u64 u; + struct { + u64 data:32; + u64 ia:8; + u64 :24; + } s; +}; + +union twsx_int { + u64 u; + struct { + u64 st_int:1; /** TWSX_SW_TWSI register update int */ + u64 ts_int:1; /** TWSX_TWSI_SW register update int */ + u64 core_int:1; /** TWSI core interrupt, ignored for HLC */ + u64 :5; /** Reserved */ + u64 sda_ovr:1; /** SDA testing override */ + u64 scl_ovr:1; /** SCL testing override */ + u64 sda:1; /** SDA signal */ + u64 scl:1; /** SCL signal */ + u64 :52; /** Reserved */ + } s; +}; + +enum { + TWSI_OP_WRITE = 0, + TWSI_OP_READ = 1, +}; + +enum { + TWSI_EOP_SLAVE_ADDR = 0, + TWSI_EOP_CLK_CTL = 3, + TWSI_SW_EOP_IA = 6, +}; + +enum { + TWSI_SLAVEADD = 0, + TWSI_DATA = 1, + TWSI_CTL = 2, + TWSI_CLKCTL = 3, + TWSI_STAT = 3, + TWSI_SLAVEADD_EXT = 4, + TWSI_RST = 7, +}; + +enum { + TWSI_CTL_AAK = (1 << 2), + TWSI_CTL_IFLG = (1 << 3), + TWSI_CTL_STP = (1 << 4), + TWSI_CTL_STA = (1 << 5), + TWSI_CTL_ENAB = (1 << 6), + TWSI_CTL_CE = (1 << 7), +}; + +enum { + /** Bus error */ + TWSI_STAT_BUS_ERROR = 0x00, + /** Start condition transmitted */ + TWSI_STAT_START = 0x08, + /** Repeat start condition transmitted */ + TWSI_STAT_RSTART = 0x10, + /** Address + write bit transmitted, ACK received */ + TWSI_STAT_TXADDR_ACK = 0x18, + /** Address + write bit transmitted, /ACK received */ + TWSI_STAT_TXADDR_NAK = 0x20, + /** Data byte transmitted in master mode, ACK received */ + TWSI_STAT_TXDATA_ACK = 0x28, + /** Data byte transmitted in master mode, ACK received */ + TWSI_STAT_TXDATA_NAK = 0x30, + /** Arbitration lost in address or data byte */ + TWSI_STAT_TX_ARB_LOST = 0x38, + /** Address + read bit transmitted, ACK received */ + TWSI_STAT_RXADDR_ACK = 0x40, + /** Address + read bit transmitted, /ACK received */ + TWSI_STAT_RXADDR_NAK = 0x48, + /** Data byte received in master mode, ACK transmitted */ + TWSI_STAT_RXDATA_ACK_SENT = 0x50, + /** Data byte received, NACK transmitted */ + TWSI_STAT_RXDATA_NAK_SENT = 0x58, + /** Slave address received, sent ACK */ + TWSI_STAT_SLAVE_RXADDR_ACK = 0x60, + /** + * Arbitration lost in address as master, slave address + write bit + * received, ACK transmitted + */ + TWSI_STAT_TX_ACK_ARB_LOST = 0x68, + /** General call address received, ACK transmitted */ + TWSI_STAT_RX_GEN_ADDR_ACK = 0x70, + /** + * Arbitration lost in address as master, general call address + * received, ACK transmitted + */ + TWSI_STAT_RX_GEN_ADDR_ARB_LOST = 0x78, + /** Data byte received after slave address received, ACK transmitted */ + TWSI_STAT_SLAVE_RXDATA_ACK = 0x80, + /** Data byte received after slave address received, /ACK transmitted */ + TWSI_STAT_SLAVE_RXDATA_NAK = 0x88, + /** + * Data byte received after general call address received, ACK + * transmitted + */ + TWSI_STAT_GEN_RXADDR_ACK = 0x90, + /** + * Data byte received after general call address received, /ACK + * transmitted + */ + TWSI_STAT_GEN_RXADDR_NAK = 0x98, + /** STOP or repeated START condition received in slave mode */ + TWSI_STAT_STOP_MULTI_START = 0xA0, + /** Slave address + read bit received, ACK transmitted */ + TWSI_STAT_SLAVE_RXADDR2_ACK = 0xA8, + /** + * Arbitration lost in address as master, slave address + read bit + * received, ACK transmitted + */ + TWSI_STAT_RXDATA_ACK_ARB_LOST = 0xB0, + /** Data byte transmitted in slave mode, ACK received */ + TWSI_STAT_SLAVE_TXDATA_ACK = 0xB8, + /** Data byte transmitted in slave mode, /ACK received */ + TWSI_STAT_SLAVE_TXDATA_NAK = 0xC0, + /** Last byte transmitted in slave mode, ACK received */ + TWSI_STAT_SLAVE_TXDATA_END_ACK = 0xC8, + /** Second address byte + write bit transmitted, ACK received */ + TWSI_STAT_TXADDR2DATA_ACK = 0xD0, + /** Second address byte + write bit transmitted, /ACK received */ + TWSI_STAT_TXADDR2DATA_NAK = 0xD8, + /** No relevant status information */ + TWSI_STAT_IDLE = 0xF8 +}; + +/** + * Returns true if we lost arbitration + * + * @param code status code + * @param final_read true if this is the final read operation + * + * @return true if arbitration has been lost, false if it hasn't been lost. + */ +static int twsi_i2c_lost_arb(u8 code, int final_read) +{ + switch (code) { + /* Arbitration lost */ + case TWSI_STAT_TX_ARB_LOST: + case TWSI_STAT_TX_ACK_ARB_LOST: + case TWSI_STAT_RX_GEN_ADDR_ARB_LOST: + case TWSI_STAT_RXDATA_ACK_ARB_LOST: + return -1; + + /* Being addressed as slave, should back off and listen */ + case TWSI_STAT_SLAVE_RXADDR_ACK: + case TWSI_STAT_RX_GEN_ADDR_ACK: + case TWSI_STAT_GEN_RXADDR_ACK: + case TWSI_STAT_GEN_RXADDR_NAK: + return -1; + + /* Core busy as slave */ + case TWSI_STAT_SLAVE_RXDATA_ACK: + case TWSI_STAT_SLAVE_RXDATA_NAK: + case TWSI_STAT_STOP_MULTI_START: + case TWSI_STAT_SLAVE_RXADDR2_ACK: + case TWSI_STAT_SLAVE_TXDATA_ACK: + case TWSI_STAT_SLAVE_TXDATA_NAK: + case TWSI_STAT_SLAVE_TXDATA_END_ACK: + return -1; + + /* Ack allowed on pre-terminal bytes only */ + case TWSI_STAT_RXDATA_ACK_SENT: + if (!final_read) + return 0; + return -1; + + /* NAK allowed on terminal byte only */ + case TWSI_STAT_RXDATA_NAK_SENT: + if (!final_read) + return 0; + return -1; + + case TWSI_STAT_TXDATA_NAK: + case TWSI_STAT_TXADDR_NAK: + case TWSI_STAT_RXADDR_NAK: + case TWSI_STAT_TXADDR2DATA_NAK: + return -1; + } + return 0; +} + +#define RST_BOOT_PNR_MUL(Val) ((Val >> 33) & 0x1F) + +/** + * Writes to the MIO_TWS(0..5)_SW_TWSI register + * + * @param baseaddr Base address of i2c registers + * @param sw_twsi value to write + * + * @return 0 for success, otherwise error + */ +static u64 twsi_write_sw(void *baseaddr, union twsx_sw_twsi sw_twsi) +{ + unsigned long timeout = 500000; + + sw_twsi.s.r = 0; + sw_twsi.s.v = 1; + + printk(BIOS_SPEW, "%s(%p, 0x%llx)\n", __func__, baseaddr, sw_twsi.u); + write64(baseaddr + TWSI_SW_TWSI, sw_twsi.u); + do { + sw_twsi.u = read64(baseaddr + TWSI_SW_TWSI); + timeout--; + } while (sw_twsi.s.v != 0 && timeout > 0); + + if (sw_twsi.s.v) + printk(BIOS_ERR, "%s: timed out\n", __func__); + return sw_twsi.u; +} + +/** + * Reads the MIO_TWS(0..5)_SW_TWSI register + * + * @param baseaddr Base address of i2c registers + * @param sw_twsi value for eia and op, etc. to read + * + * @return value of the register + */ +static u64 twsi_read_sw(void *baseaddr, union twsx_sw_twsi sw_twsi) +{ + unsigned long timeout = 500000; + sw_twsi.s.r = 1; + sw_twsi.s.v = 1; + + printk(BIOS_SPEW, "%s(%p, 0x%llx)\n", __func__, baseaddr, sw_twsi.u); + write64(baseaddr + TWSI_SW_TWSI, sw_twsi.u); + + do { + sw_twsi.u = read64(baseaddr + TWSI_SW_TWSI); + timeout--; + } while (sw_twsi.s.v != 0 && timeout > 0); + + if (sw_twsi.s.v) + printk(BIOS_ERR, "%s: Error writing 0x%llx\n", __func__, + sw_twsi.u); + + printk(BIOS_SPEW, "%s: Returning 0x%llx\n", __func__, sw_twsi.u); + return sw_twsi.u; +} + +/** + * Write control register + * + * @param baseaddr Base address for i2c registers + * @param data data to write + */ +static void twsi_write_ctl(void *baseaddr, const u8 data) +{ + union twsx_sw_twsi twsi_sw; + + printk(BIOS_SPEW, "%s(%p, 0x%x)\n", __func__, baseaddr, data); + twsi_sw.u = 0; + + twsi_sw.s.op = TWSI_SW_EOP_IA; + twsi_sw.s.eop_ia = TWSI_CTL; + twsi_sw.s.data = data; + + twsi_write_sw(baseaddr, twsi_sw); +} + +/** + * Reads the TWSI Control Register + * + * @param[in] baseaddr Base address for i2c + * + * @return 8-bit TWSI control register + */ +static u32 twsi_read_ctl(void *baseaddr) +{ + union twsx_sw_twsi sw_twsi; + + sw_twsi.u = 0; + sw_twsi.s.op = TWSI_SW_EOP_IA; + sw_twsi.s.eop_ia = TWSI_CTL; + + sw_twsi.u = twsi_read_sw(baseaddr, sw_twsi); + printk(BIOS_SPEW, "%s(%p): 0x%x\n", __func__, baseaddr, sw_twsi.s.data); + return sw_twsi.s.data; +} + +/** + * Read i2c status register + * + * @param baseaddr Base address of i2c registers + * + * @return value of status register + */ +static u8 twsi_read_status(void *baseaddr) +{ + union twsx_sw_twsi twsi_sw; + + twsi_sw.u = 0; + twsi_sw.s.op = TWSI_SW_EOP_IA; + twsi_sw.s.eop_ia = TWSI_STAT; + + return twsi_read_sw(baseaddr, twsi_sw); +} + +/** + * Waits for an i2c operation to complete + * + * @param baseaddr Base address of registers + * + * @return 0 for success, 1 if timeout + */ +static int twsi_wait(void *baseaddr) +{ + unsigned long timeout = 500000; + u8 twsi_ctl; + + printk(BIOS_SPEW, "%s(%p)\n", __func__, baseaddr); + do { + twsi_ctl = twsi_read_ctl(baseaddr); + twsi_ctl &= TWSI_CTL_IFLG; + timeout--; + } while (!twsi_ctl && timeout > 0); + + printk(BIOS_SPEW, " return: %u\n", !twsi_ctl); + return !twsi_ctl; +} + +/** + * Sends an i2c stop condition + * + * @param baseaddr register base address + * + * @return 0 for success, -1 if error + */ +static int twsi_stop(void *baseaddr) +{ + u8 stat; + twsi_write_ctl(baseaddr, TWSI_CTL_STP | TWSI_CTL_ENAB); + + stat = twsi_read_status(baseaddr); + if (stat != TWSI_STAT_IDLE) { + printk(BIOS_ERR, "%s: Bad status on bus@%p\n", __func__, + baseaddr); + return -1; + } + return 0; +} + +/** + * Manually clear the I2C bus and send a stop + */ +static void twsi_unblock(void *baseaddr) +{ + int i; + union twsx_int int_reg; + + int_reg.u = 0; + for (i = 0; i < 9; i++) { + int_reg.s.scl_ovr = 0; + write64(baseaddr + TWSI_INT, int_reg.u); + udelay(5); + int_reg.s.scl_ovr = 1; + write64(baseaddr + TWSI_INT, int_reg.u); + udelay(5); + } + int_reg.s.sda_ovr = 1; + write64(baseaddr + TWSI_INT, int_reg.u); + udelay(5); + int_reg.s.scl_ovr = 0; + write64(baseaddr + TWSI_INT, int_reg.u); + udelay(5); + int_reg.u = 0; + write64(baseaddr + TWSI_INT, int_reg.u); + udelay(5); +} + +/** + * Unsticks the i2c bus + * + * @param baseaddr base address of registers + */ +static int twsi_start_unstick(void *baseaddr) +{ + twsi_stop(baseaddr); + + twsi_unblock(baseaddr); + + return 0; +} + +/** + * Sends an i2c start condition + * + * @param baseaddr base address of registers + * + * @return 0 for success, otherwise error + */ +static int twsi_start(void *baseaddr) +{ + int result; + u8 stat; + + printk(BIOS_SPEW, "%s(%p)\n", __func__, baseaddr); + twsi_write_ctl(baseaddr, TWSI_CTL_STA | TWSI_CTL_ENAB); + result = twsi_wait(baseaddr); + if (result) { + stat = twsi_read_status(baseaddr); + printk(BIOS_SPEW, "%s: result: 0x%x, status: 0x%x\n", __func__, + result, stat); + switch (stat) { + case TWSI_STAT_START: + case TWSI_STAT_RSTART: + return 0; + case TWSI_STAT_RXADDR_ACK: + default: + return twsi_start_unstick(baseaddr); + } + } + printk(BIOS_SPEW, "%s: success\n", __func__); + return 0; +} + +/** + * Writes data to the i2c bus + * + * @param baseraddr register base address + * @param slave_addr address of slave to write to + * @param buffer Pointer to buffer to write + * @param length Number of bytes in buffer to write + * + * @return 0 for success, otherwise error + */ +static int twsi_write_data(void *baseaddr, const u8 slave_addr, + const u8 *buffer, const unsigned int length) +{ + union twsx_sw_twsi twsi_sw; + unsigned int curr = 0; + int result; + + printk(BIOS_SPEW, "%s(%p, 0x%x, %p, 0x%x)\n", __func__, baseaddr, + slave_addr, buffer, length); + result = twsi_start(baseaddr); + if (result) { + printk(BIOS_ERR, "%s: Could not start BUS transaction\n", + __func__); + return -1; + } + + result = twsi_wait(baseaddr); + if (result) { + printk(BIOS_ERR, "%s: wait failed\n", __func__); + return result; + } + + twsi_sw.u = 0; + twsi_sw.s.op = TWSI_SW_EOP_IA; + twsi_sw.s.eop_ia = TWSI_DATA; + twsi_sw.s.data = (u32) (slave_addr << 1) | TWSI_OP_WRITE; + + twsi_write_sw(baseaddr, twsi_sw); + twsi_write_ctl(baseaddr, TWSI_CTL_ENAB); + + printk(BIOS_SPEW, "%s: Waiting\n", __func__); + result = twsi_wait(baseaddr); + if (result) { + printk(BIOS_ERR, "%s: Timed out writing slave address 0x%x\n", + __func__, slave_addr); + return result; + } + result = twsi_read_status(baseaddr); + if ((result = twsi_read_status(baseaddr)) != TWSI_STAT_TXADDR_ACK) { + twsi_stop(baseaddr); + return twsi_i2c_lost_arb(result, 0); + } + + while (curr < length) { + twsi_sw.u = 0; + twsi_sw.s.op = TWSI_SW_EOP_IA; + twsi_sw.s.eop_ia = TWSI_DATA; + twsi_sw.s.data = buffer[curr++]; + + twsi_write_sw(baseaddr, twsi_sw); + twsi_write_ctl(baseaddr, TWSI_CTL_ENAB); + + result = twsi_wait(baseaddr); + if (result) { + printk(BIOS_ERR, "%s: Timed out writing data to 0x%x\n", + __func__, slave_addr); + return result; + } + } + + printk(BIOS_SPEW, "%s: Stopping\n", __func__); + return twsi_stop(baseaddr); +} + +/** + * Performs a read transaction on the i2c bus + * + * @param baseaddr Base address of twsi registers + * @param slave_addr i2c bus address to read from + * @param buffer buffer to read into + * @param length number of bytes to read + * + * @return 0 for success, otherwise error + */ +static int twsi_read_data(void *baseaddr, const u8 slave_addr, + u8 *buffer, const unsigned int length) +{ + union twsx_sw_twsi twsi_sw; + unsigned int curr = 0; + int result; + + printk(BIOS_SPEW, "%s(%p, 0x%x, %p, %u)\n", __func__, baseaddr, + slave_addr, buffer, length); + result = twsi_start(baseaddr); + if (result) { + printk(BIOS_ERR, "%s: start failed\n", __func__); + return result; + } + + result = twsi_wait(baseaddr); + if (result) { + printk(BIOS_ERR, "%s: wait failed\n", __func__); + return result; + } + + twsi_sw.u = 0; + + twsi_sw.s.op = TWSI_SW_EOP_IA; + twsi_sw.s.eop_ia = TWSI_DATA; + + twsi_sw.s.data = (u32) (slave_addr << 1) | TWSI_OP_READ; + + twsi_write_sw(baseaddr, twsi_sw); + twsi_write_ctl(baseaddr, TWSI_CTL_ENAB); + + result = twsi_wait(baseaddr); + if (result) { + printk(BIOS_ERR, "%s: waiting for sending addr failed\n", __func__); + return result; + } + + result = twsi_read_status(baseaddr); + if (result != TWSI_STAT_RXADDR_ACK) { + twsi_stop(baseaddr); + return twsi_i2c_lost_arb(result, 0); + } + + while (curr < length) { + twsi_write_ctl(baseaddr, TWSI_CTL_ENAB | + ((curr < length - 1) ? TWSI_CTL_AAK : 0)); + + result = twsi_wait(baseaddr); + if (result) { + printk(BIOS_ERR, "%s: waiting for data failed\n", + __func__); + return result; + } + + twsi_sw.u = twsi_read_sw(baseaddr, twsi_sw); + buffer[curr++] = twsi_sw.s.data; + } + + twsi_stop(baseaddr); + + return 0; +} + +static int twsi_set_speed(void *baseaddr, const unsigned int speed) +{ + u64 io_clock_hz; + int n_div; + int m_div; + union twsx_sw_twsi sw_twsi; + + io_clock_hz = thunderx_get_io_clock(); + + /* Set the TWSI clock to a conservative TWSI_BUS_FREQ. Compute the + * clocks M divider based on the SCLK. + * TWSI freq = (core freq) / (20 x (M+1) x (thp+1) x 2^N) + * M = ((core freq) / (20 x (TWSI freq) x (thp+1) x 2^N)) - 1 + */ + for (n_div = 0; n_div < 8; n_div++) { + m_div = io_clock_hz / (20 * speed * (TWSI_THP + 1)); + m_div /= 1 << n_div; + m_div -= 1; + if (m_div < 16) + break; + } + if (m_div >= 16) + return -1; + + sw_twsi.u = 0; + sw_twsi.s.v = 1; + sw_twsi.s.op = 0x6; /* See EOP field */ + sw_twsi.s.r = 0; /* Select CLKCTL when R = 0 */ + sw_twsi.s.eop_ia = 3; /* R=0 selects CLKCTL, R=1 selects STAT */ + sw_twsi.s.data = ((m_div & 0xf) << 3) | ((n_div & 0x7) << 0); + + twsi_write_sw(baseaddr, sw_twsi); + return 0; +} + +int twsi_init(unsigned int bus, enum i2c_speed hz) +{ + void *baseaddr = (void *)MIO_TWSx_PF_BAR0(bus); + if (!baseaddr) + return -1; + + if (twsi_set_speed(baseaddr, hz) < 0) + return -1; + + /* Enable TWSI, HLC disable, STOP, NAK */ + twsi_write_ctl(baseaddr, TWSI_CTL_ENAB); + + return 0; +} + +int platform_i2c_transfer(unsigned bus, struct i2c_msg *segments, + int seg_count) +{ + int result; + void *baseaddr = (void *)MIO_TWSx_PF_BAR0(bus); + if (!baseaddr) + return -1; + + printk(BIOS_SPEW, "%s: %d messages\n", __func__, seg_count); + for (; seg_count > 0; seg_count--, segments++) { + if (segments->flags & I2C_M_RD) { + result = twsi_read_data(baseaddr, segments->slave, + segments->buf, segments->len); + } else { + result = twsi_write_data(baseaddr, segments->slave, + segments->buf, segments->len); + } + if (result) { + printk(BIOS_ERR, "%s: error transmitting data\n", + __func__); + return -1; + } + } + + return 0; +} diff --git a/src/soc/cavium/cn81xx/uart.c b/src/soc/cavium/cn81xx/uart.c new file mode 100644 index 0000000000..9fb83871ad --- /dev/null +++ b/src/soc/cavium/cn81xx/uart.c @@ -0,0 +1,265 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 Facebook, Inc. + * Copyright 2003-2017 Cavium Inc. <support@cavium.com> + * + * 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; version 2 of the License. + * + * 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. + * + * Derived from Cavium's BSD-3 Clause OCTEONTX-SDK-6.2.0. + */ + +#include <arch/io.h> +#include <console/uart.h> +#include <delay.h> +#include <endian.h> +#include <stdint.h> +#include <soc/clock.h> +#include <soc/uart.h> +#include <assert.h> +#include <soc/addressmap.h> +#include <drivers/uart/pl011.h> + +union cn81xx_uart_ctl { + u64 u; + struct { + u64 uctl_rst : 1; + u64 uaa_rst : 1; + u64 : 2; + u64 csclk_en : 1; + u64 : 19; + u64 h_clkdiv_sel : 3; + u64 : 1; + u64 h_clkdiv_rst : 1; + u64 h_clk_byp_sel : 1; + u64 h_clk_en : 1; + u64 : 33; + } s; +}; + +struct cn81xx_uart { + struct pl011_uart pl011; + union cn81xx_uart_ctl uctl_ctl; + u8 rsvd4[0x8]; + u64 uctl_spare0; + u8 rsvd5[0xe0]; + u64 uctl_spare1; +}; + +#define UART_IBRD_BAUD_DIVINT_SHIFT 0 +#define UART_IBRD_BAUD_DIVINT_MASK 0xffff + +#define UART_FBRD_BAUD_DIVFRAC_SHIFT 0 +#define UART_FBRD_BAUD_DIVFRAC_MASK 0x3f + + +check_member(cn81xx_uart, uctl_ctl, 0x1000); +check_member(cn81xx_uart, uctl_spare1, 0x10f8); + +#define UART_SCLK_DIV 3 + +/** + * Returns the current UART HCLK divider + * + * @param reg The H_CLKDIV_SEL value + * @return The HCLK divider + */ +static size_t uart_sclk_divisor(const size_t reg) +{ + static const u8 div[] = {1, 2, 4, 6, 8, 16, 24, 32}; + + assert(reg < ARRAY_SIZE(div)); + + return div[reg]; +} + +/** + * Returns the current UART HCLK + * + * @param uart The UART to operate on + * @return The HCLK in Hz + */ +static size_t uart_hclk(struct cn81xx_uart *uart) +{ + union cn81xx_uart_ctl ctl; + const uint64_t sclk = thunderx_get_io_clock(); + + ctl.u = read64(&uart->uctl_ctl); + return sclk / uart_sclk_divisor(ctl.s.h_clkdiv_sel); +} + +unsigned int uart_platform_refclk(void) +{ + struct cn81xx_uart *uart = + (struct cn81xx_uart *)CONFIG_CONSOLE_SERIAL_UART_ADDRESS; + + if (!uart) + return 0; + + return uart_hclk(uart); +} + +uintptr_t uart_platform_base(int idx) +{ + return CONFIG_CONSOLE_SERIAL_UART_ADDRESS; +} + +/** + * Waits given count if HCLK cycles + * + * @param uart The UART to operate on + * @param hclks The number of HCLK cycles to wait + */ +static void uart_wait_hclk(struct cn81xx_uart *uart, const size_t hclks) +{ + const size_t hclk = uart_hclk(uart); + const size_t delay = (hclks * 1000000ULL) / hclk; + udelay(MAX(delay, 1)); +} + +/** + * Returns the UART state. + * + * @param bus The UART to operate on + * @return Boolean: True if UART is enabled + */ +int uart_is_enabled(const size_t bus) +{ + struct cn81xx_uart *uart = (struct cn81xx_uart *)UAAx_PF_BAR0(bus); + union cn81xx_uart_ctl ctl; + + assert(uart); + if (!uart) + return 0; + + ctl.u = read64(&uart->uctl_ctl); + return !!ctl.s.csclk_en; +} + +/** + * Setup UART with desired BAUD rate in 8N1, no parity mode. + * + * @param bus The UART to operate on + * @param baudrate baudrate to set up + * + * @return Boolean: True on error + */ +int uart_setup(const size_t bus, int baudrate) +{ + union cn81xx_uart_ctl ctl; + struct cn81xx_uart *uart = (struct cn81xx_uart *)UAAx_PF_BAR0(bus); + + assert(uart); + if (!uart) + return 1; + + /* 1.2.1 Initialization Sequence (Power-On/Hard/Cold Reset) */ + /* 1. Wait for IOI reset (srst_n) to deassert. */ + + /** + * 2. Assert all resets: + * a. UAA reset: UCTL_CTL[UAA_RST] = 1 + * b. UCTL reset: UCTL_CTL[UCTL_RST] = 1 + */ + ctl.u = read64(&uart->uctl_ctl); + ctl.s.uctl_rst = 1; + ctl.s.uaa_rst = 1; + write64(&uart->uctl_ctl, ctl.u); + + /** + * 3. Configure the HCLK: + * a. Reset the clock dividers: UCTL_CTL[H_CLKDIV_RST] = 1. + * b. Select the HCLK frequency + * i. UCTL_CTL[H_CLKDIV] = desired value, + * ii. UCTL_CTL[H_CLKDIV_EN] = 1 to enable the HCLK. + * iii. Readback UCTL_CTL to ensure the values take effect. + * c. Deassert the HCLK clock divider reset: UCTL_CTL[H_CLKDIV_RST] = 0. + */ + ctl.u = read64(&uart->uctl_ctl); + ctl.s.h_clkdiv_sel = UART_SCLK_DIV; + write64(&uart->uctl_ctl, ctl.u); + + ctl.u = read64(&uart->uctl_ctl); + ctl.s.h_clk_byp_sel = 0; + write64(&uart->uctl_ctl, ctl.u); + + ctl.u = read64(&uart->uctl_ctl); + ctl.s.h_clk_en = 1; + write64(&uart->uctl_ctl, ctl.u); + + ctl.u = read64(&uart->uctl_ctl); + ctl.s.h_clkdiv_rst = 0; + write64(&uart->uctl_ctl, ctl.u); + + /** + * 4. Wait 20 HCLK cycles from step 3 for HCLK to start and async fifo + * to properly reset. + */ + uart_wait_hclk(uart, 20 + 1); + + /** + * 5. Deassert UCTL and UAHC resets: + * a. UCTL_CTL[UCTL_RST] = 0 + * b. Wait 10 HCLK cycles. + * c. UCTL_CTL[UAHC_RST] = 0 + * d. You will have to wait 10 HCLK cycles before accessing any + * HCLK-only registers. + */ + ctl.u = read64(&uart->uctl_ctl); + ctl.s.uctl_rst = 0; + write64(&uart->uctl_ctl, ctl.u); + + uart_wait_hclk(uart, 10 + 1); + + ctl.u = read64(&uart->uctl_ctl); + ctl.s.uaa_rst = 0; + write64(&uart->uctl_ctl, ctl.u); + + uart_wait_hclk(uart, 10 + 1); + + /** + * 6. Enable conditional SCLK of UCTL by writing + * UCTL_CTL[CSCLK_EN] = 1. + */ + ctl.u = read64(&uart->uctl_ctl); + ctl.s.csclk_en = 1; + write64(&uart->uctl_ctl, ctl.u); + + /** + * 7. Initialize the integer and fractional baud rate divider registers + * UARTIBRD and UARTFBRD as follows: + * a. Baud Rate Divisor = UARTCLK/(16xBaud Rate) = BRDI + BRDF + * b. The fractional register BRDF, m is calculated as + * integer(BRDF x 64 + 0.5) + * Example calculation: + * If the required baud rate is 230400 and hclk = 4MHz then: + * Baud Rate Divisor = (4x10^6)/(16x230400) = 1.085 + * This means BRDI = 1 and BRDF = 0.085. + * Therefore, fractional part, BRDF = integer((0.085x64)+0.5) = 5 + * Generated baud rate divider = 1+5/64 = 1.078 + */ + u64 divisor = thunderx_get_io_clock() / + (baudrate * 16 * uart_sclk_divisor(UART_SCLK_DIV) / 64); + write32(&uart->pl011.ibrd, divisor >> 6); + write32(&uart->pl011.fbrd, divisor & UART_FBRD_BAUD_DIVFRAC_MASK); + + /** + * 8. Program the line control register UAA(0..1)_LCR_H and the control + * register UAA(0..1)_CR + */ + /* 8-bits, FIFO enable */ + write32(&uart->pl011.lcr_h, PL011_UARTLCR_H_WLEN_8 | + PL011_UARTLCR_H_FEN); + /* RX/TX enable, UART enable */ + write32(&uart->pl011.cr, PL011_UARTCR_RXE | PL011_UARTCR_TXE | + PL011_UARTCR_UARTEN); + + return 0; +} diff --git a/src/soc/cavium/common/Kconfig b/src/soc/cavium/common/Kconfig new file mode 100644 index 0000000000..1161ac2263 --- /dev/null +++ b/src/soc/cavium/common/Kconfig @@ -0,0 +1,12 @@ +config SOC_CAVIUM_COMMON + bool + default n + select BOOTBLOCK_CUSTOM + select CAVIUM_BDK + select FLATTENED_DEVICE_TREE +# FIXME: No Cavium support in ATF +# select ARM64_USE_ARM_TRUSTED_FIRMWARE + +if SOC_CAVIUM_COMMON + +endif diff --git a/src/soc/cavium/common/Makefile.inc b/src/soc/cavium/common/Makefile.inc new file mode 100644 index 0000000000..89add5f3f1 --- /dev/null +++ b/src/soc/cavium/common/Makefile.inc @@ -0,0 +1,58 @@ +## +## This file is part of the coreboot project. +## +## Copyright 2017-present Facebook, Inc. +## +## 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; version 2 of the License. +## +## 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. +## + +ifeq ($(CONFIG_SOC_CAVIUM_COMMON),y) + +CFLAGS_arm64 += -Wstack-usage=8192 + +bootblock-$(CONFIG_BOOTBLOCK_CUSTOM) += bootblock.c + +################################################################################ +# romstage + +romstage-y += cbmem.c +romstage-y += bdk-coreboot.c + +################################################################################ +# ramstage + +ramstage-y += cbmem.c +ramstage-$(CONFIG_ARM64_USE_ARM_TRUSTED_FIRMWARE) += bl31_plat_params.c + +CPPFLAGS_common += -Isrc/soc/cavium/common/include + +ROM_HEADER_BIN := $(objgenerated)/rom_header.bin +ROM_HEADER_SOURCES += rom_clib_s_nbl1fw +ROM_HEADER_SOURCES += rom_csib_s_nbl1fw + +ROM_HEADER_DEPS := $(foreach f, $(ROM_HEADER_SOURCES), src/soc/cavium/common/$(f).bin.hex) + +# Include ROM header +$(ROM_HEADER_BIN): $(ROM_HEADER_DEPS) + for f in $+; \ + do for c in $$(cat $$f | grep -v ^#); \ + do printf $$(printf '\%o' 0x$$c); \ + done; \ + done > $@ + +$(objcbfs)/bootblock.bin: $(objcbfs)/bootblock.raw.bin $(ROM_HEADER_BIN) + @printf " GEN $(subst $(obj)/,,$(@))\n" + dd if=/dev/zero ibs=1 count=$$(($(shell stat --printf="%s" $(objcbfs)/bootblock.raw.bin) + 0x10000)) of=$@ status=none + # Insert CLIB at 0x0 and CSIB at 0x100 + dd if=$(ROM_HEADER_BIN) of=$@ bs=1 seek=0 conv=notrunc status=none + # Insert bootblock at 0x10000 + dd if=$(objcbfs)/bootblock.raw.bin of=$@ bs=1 seek=$$((0x10000)) conv=notrunc status=none + +endif diff --git a/src/soc/cavium/common/bdk-coreboot.c b/src/soc/cavium/common/bdk-coreboot.c new file mode 100644 index 0000000000..ff30edfa79 --- /dev/null +++ b/src/soc/cavium/common/bdk-coreboot.c @@ -0,0 +1,130 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2017-present Facebook, Inc. + * Copyright 2003-2017 Cavium Inc. <support@cavium.com> + * + * 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; version 2 of the License. + * + * 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. + * + * This file consists of data imported from bdk-config.c + */ +// coreboot +#include <string.h> +#include <assert.h> +#include <device/i2c.h> +#include <device/i2c_simple.h> +#include <endian.h> +#include <arch/io.h> +#include <delay.h> +#include <reset.h> +#include <soc/timer.h> + +// BDK +#include <libbdk-arch/bdk-numa.h> +#include <libbdk-hal/bdk-config.h> +#include <libbdk-hal/bdk-twsi.h> +#include <libbdk-boot/bdk-watchdog.h> + +/** + * Do a twsi read from a 7 bit device address using an (optional) + * internal address. Up to 4 bytes can be read at a time. + * + * @param twsi_id which TWSI bus to use + * @param dev_addr Device address (7 bit) + * @param internal_addr + * Internal address. Can be 0, 1 or 2 bytes in width + * @param num_bytes Number of data bytes to read (1-4) + * @param ia_width_bytes + * Internal address size in bytes (0, 1, or 2) + * + * @return Read data, or -1 on failure + */ +int64_t bdk_twsix_read_ia(bdk_node_t node, int twsi_id, uint8_t dev_addr, + uint16_t internal_addr, int num_bytes, + int ia_width_bytes) +{ + struct i2c_msg seg[2]; + u32 buf; + + assert (num_bytes < 5); + assert (ia_width_bytes < 3); + + seg[0].flags = 0; + seg[0].slave = dev_addr; + seg[0].buf = (u8 *)&internal_addr; + seg[0].len = ia_width_bytes; + seg[1].flags = I2C_M_RD; + seg[1].slave = dev_addr; + seg[1].buf = (u8 *)&buf; + seg[1].len = num_bytes; + + if (i2c_transfer(twsi_id, seg, ARRAY_SIZE(seg)) < 0) + return -1; + + return cpu_to_be32(buf); +} + +/** + * Write 1-8 bytes to a TWSI device using an internal address. + * + * @param twsi_id which TWSI interface to use + * @param dev_addr TWSI device address (7 bit only) + * @param internal_addr + * TWSI internal address (0, 8, or 16 bits) + * @param num_bytes Number of bytes to write (1-8) + * @param ia_width_bytes + * internal address width, in bytes (0, 1, 2) + * @param data Data to write. Data is written MSB first on the twsi bus, and + * only the lower num_bytes bytes of the argument are valid. (If + * a 2 byte write is done, only the low 2 bytes of the argument is + * used. + * + * @return Zero on success, -1 on error + */ +int bdk_twsix_write_ia(bdk_node_t node, int twsi_id, uint8_t dev_addr, + uint16_t internal_addr, int num_bytes, + int ia_width_bytes, uint64_t data) +{ + struct i2c_msg seg; + u8 buf[10]; + + assert (num_bytes <= 8); + assert (ia_width_bytes < 3); + + memcpy(buf, &internal_addr, ia_width_bytes); + memcpy(&buf[ia_width_bytes], &data, num_bytes); + + seg.flags = 0; + seg.slave = dev_addr; + seg.buf = buf; + seg.len = num_bytes + ia_width_bytes; + + return platform_i2c_transfer(twsi_id, &seg, 1); +} + +void bdk_watchdog_set(unsigned int timeout_ms) +{ + watchdog_set(0, timeout_ms); +} + +void bdk_watchdog_poke(void) +{ + watchdog_poke(0); +} + +void bdk_watchdog_disable(void) +{ + watchdog_disable(0); +} + +int bdk_watchdog_is_running(void) +{ + return watchdog_is_running(0); +} diff --git a/src/soc/cavium/common/bl31_plat_params.c b/src/soc/cavium/common/bl31_plat_params.c new file mode 100644 index 0000000000..583eac8059 --- /dev/null +++ b/src/soc/cavium/common/bl31_plat_params.c @@ -0,0 +1,32 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2016 Rockchip Inc. + * + * 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; version 2 of the License. + * + * 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. + * + */ + +#include <arm_tf.h> +#include <assert.h> +#include <soc/bl31_plat_params.h> + +static struct bl31_plat_param *plat_params; + +void register_bl31_param(struct bl31_plat_param *param) +{ + param->next = plat_params; + plat_params = param; +} + +void *soc_get_bl31_plat_params(bl31_params_t *bl31_params) +{ + return plat_params; +} diff --git a/src/soc/cavium/common/bootblock.c b/src/soc/cavium/common/bootblock.c new file mode 100644 index 0000000000..c61a8d7dc1 --- /dev/null +++ b/src/soc/cavium/common/bootblock.c @@ -0,0 +1,68 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018-present Facebook, Inc. + * + * 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; version 2 of + * the License. + * + * 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. + */ + +#include <arch/exception.h> +#include <console/console.h> +#include <delay.h> +#include <program_loading.h> +#include <symbols.h> +#include <timestamp.h> +#include <soc/bootblock.h> + +DECLARE_OPTIONAL_REGION(timestamp); + +__attribute__((weak)) void bootblock_mainboard_early_init(void) { /* no-op */ } +__attribute__((weak)) void bootblock_soc_early_init(void) { /* do nothing */ } +__attribute__((weak)) void bootblock_soc_init(void) { /* do nothing */ } +__attribute__((weak)) void bootblock_mainboard_init(void) { /* do nothing */ } + + +/* C code entry point for the boot block */ +void bootblock_main(const uint64_t reg_x0, + const uint64_t reg_x1, + const uint64_t reg_pc) +{ + uint64_t base_timestamp = 0; + + init_timer(); + + if (IS_ENABLED(CONFIG_COLLECT_TIMESTAMPS)) + base_timestamp = timestamp_get(); + + /* Initialize timestamps if we have TIMESTAMP region in memlayout.ld. */ + if (IS_ENABLED(CONFIG_COLLECT_TIMESTAMPS) && _timestamp_size > 0) + timestamp_init(base_timestamp); + + bootblock_soc_early_init(); + bootblock_mainboard_early_init(); + + if (IS_ENABLED(CONFIG_BOOTBLOCK_CONSOLE)) { + console_init(); + exception_init(); + + if (reg_x0) + printk(BIOS_ERR, + "BOOTBLOCK: RST Boot Failure Code %lld\n", + reg_x0); + + printk(BIOS_DEBUG, "BOOTBLOCK: FDT 0x%llX\n", reg_x1); + } + + bootblock_soc_init(); + bootblock_mainboard_init(); + + run_romstage(); +} diff --git a/src/soc/cavium/common/cbmem.c b/src/soc/cavium/common/cbmem.c new file mode 100644 index 0000000000..401f8b2a65 --- /dev/null +++ b/src/soc/cavium/common/cbmem.c @@ -0,0 +1,26 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2014 Rockchip Inc. + * + * 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; version 2 of the License. + * + * 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. + */ + +#include <cbmem.h> +#include <soc/addressmap.h> +#include <soc/sdram.h> +#include <stdlib.h> +#include <symbols.h> + +void *cbmem_top(void) +{ + return (void *)min((uintptr_t)_dram + sdram_size_mb() * MiB, + MAX_DRAM_ADDRESS); +} diff --git a/src/soc/cavium/common/include/soc/bl31_plat_params.h b/src/soc/cavium/common/include/soc/bl31_plat_params.h new file mode 100644 index 0000000000..3407e90c07 --- /dev/null +++ b/src/soc/cavium/common/include/soc/bl31_plat_params.h @@ -0,0 +1,25 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2016 Rockchip Inc. + * + * 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; version 2 of the License. + * + * 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. + * + */ + +#ifndef __BL31_PLAT_PARAMS_H__ +#define __BL31_PLAT_PARAMS_H__ + +// FIXME: use correct path one ATF is upstream +#include <arm-trusted-firmware/plat/rockchip/common/include/plat_params.h> + +void register_bl31_param(struct bl31_plat_param *param); + +#endif/* __BL31_PLAT_PARAMS_H__ */ diff --git a/src/soc/cavium/common/include/soc/bootblock.h b/src/soc/cavium/common/include/soc/bootblock.h new file mode 100644 index 0000000000..040c5a3a67 --- /dev/null +++ b/src/soc/cavium/common/include/soc/bootblock.h @@ -0,0 +1,29 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018-present Facebook, Inc. + * + * 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; version 2 of + * the License. + * + * 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. + */ +#ifndef SRC_SOC_CAVIUM_COMMON_INCLUDE_SOC_BOOTBLOCK_H_ +#define SRC_SOC_CAVIUM_COMMON_INCLUDE_SOC_BOOTBLOCK_H_ + +void bootblock_mainboard_early_init(void); +void bootblock_soc_early_init(void); +void bootblock_soc_init(void); +void bootblock_mainboard_init(void); + +void bootblock_main(const uint64_t reg_x0, + const uint64_t reg_x1, + const uint64_t reg_pc); + + +#endif /* SRC_SOC_CAVIUM_COMMON_INCLUDE_SOC_BOOTBLOCK_H_ */ diff --git a/src/soc/cavium/common/include/soc/sysreg.h b/src/soc/cavium/common/include/soc/sysreg.h new file mode 100644 index 0000000000..655fe09cb6 --- /dev/null +++ b/src/soc/cavium/common/include/soc/sysreg.h @@ -0,0 +1,65 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018-present Facebook, Inc. + * Copyright (c) 2003-2017 Cavium Inc. (support@cavium.com). All rights + * + * 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; version 2 of + * the License. + * + * 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. + */ +#ifndef __SOC_CAVIUM_COMMON_INCLUDE_SOC_SYSREG_H +#define __SOC_CAVIUM_COMMON_INCLUDE_SOC_SYSREG_H + +/* TODO: add CVMCTL_EL1 */ + +#define AP_CVMMEMCTL0_EL1_NODE_SHIFT 61 +#define AP_CVMMEMCTL0_EL1_NODE_MASK 0x3 +#define AP_CVMMEMCTL0_EL1_STEXFAILCNT_SHIFT 58 +#define AP_CVMMEMCTL0_EL1_STEXFAILCNT_MASK 0x7 +#define AP_CVMMEMCTL0_EL1_WFELDEX1DIS (1 << 57) +#define AP_CVMMEMCTL0_EL1_STLSTALLFORCE (1 << 56) +#define AP_CVMMEMCTL0_EL1_DMBSTALLFORCE (1 << 55) +#define AP_CVMMEMCTL0_EL1_TLBINOPDIS (1 << 54) +#define AP_CVMMEMCTL0_EL1_TLBIICFLUSH (1 << 53) +#define AP_CVMMEMCTL0_EL1_GSYNCTO_SHIFT 48 +#define AP_CVMMEMCTL0_EL1_GSYNCTO_MASK 0x1f +#define AP_CVMMEMCTL0_EL1_UTLBFILLBYPDIS (1 << 47) +#define AP_CVMMEMCTL0_EL1_TLBIALL (1 << 46) +#define AP_CVMMEMCTL0_EL1_WBFDSBFLUSHALL (1 << 45) +#define AP_CVMMEMCTL0_EL1_WBFDMBFLUSHNEXT (1 << 44) +#define AP_CVMMEMCTL0_EL1_STEXL2CFORCE (1 << 43) +#define AP_CVMMEMCTL0_EL1_WCUMISSFORCE (1 << 41) +#define AP_CVMMEMCTL0_EL1_REPLAYPREFDIS (1 << 40) +#define AP_CVMMEMCTL0_EL1_ZVAL2CDIS (1 << 39) +#define AP_CVMMEMCTL0_EL1_LDIL2CDIS (1 << 38) +#define AP_CVMMEMCTL0_EL1_DVCA47 (1 << 37) +#define AP_CVMMEMCTL0_EL1_STPREFDIS (1 << 36) +#define AP_CVMMEMCTL0_EL1_LDPREFDIS (1 << 35) +#define AP_CVMMEMCTL0_EL1_WFILDEXDIS (1 << 34) +#define AP_CVMMEMCTL0_EL1_WFITO_SHIFT 31 +#define AP_CVMMEMCTL0_EL1_WFITO_MASK 0x7 +#define AP_CVMMEMCTL0_EL1_RBFSHORTTO_SHIFT 26 +#define AP_CVMMEMCTL0_EL1_RBFSHORTTO_MASK 0x1f +#define AP_CVMMEMCTL0_EL1_RBFTO_SHIFT 21 +#define AP_CVMMEMCTL0_EL1_RBFTO_MASK 0x1f +#define AP_CVMMEMCTL0_EL1_WBFALLBARRIER (1 << 20) +#define AP_CVMMEMCTL0_EL1_WBFNOMERGE (1 << 19) +#define AP_CVMMEMCTL0_EL1_WBFTONSHENA (1 << 18) +#define AP_CVMMEMCTL0_EL1_WBFTOMRGCLRENA (1 << 17) +#define AP_CVMMEMCTL0_EL1_WBFTO_SHIFT 12 +#define AP_CVMMEMCTL0_EL1_WBFTO_MASK 0x1f +#define AP_CVMMEMCTL0_EL1_WBFTHRESH_SHIFT 7 +#define AP_CVMMEMCTL0_EL1_WBFTHRESH_MASK 0x1f +#define AP_CVMMEMCTL0_EL1_UTLBENTRIESM1_SHIFT 2 +#define AP_CVMMEMCTL0_EL1_UTLBENTRIESM1_MASK 0x1f +#define AP_CVMMEMCTL0_EL1_CCLKFORCE (1 << 1) +#define AP_CVMMEMCTL0_EL1_MCLKFORCE (1 << 0) + +#endif /* __SOC_CAVIUM_COMMON_INCLUDE_SOC_SYSREG_H */ diff --git a/src/soc/cavium/common/rom_clib_s_nbl1fw.bin.hex b/src/soc/cavium/common/rom_clib_s_nbl1fw.bin.hex new file mode 100644 index 0000000000..231c6a60b1 --- /dev/null +++ b/src/soc/cavium/common/rom_clib_s_nbl1fw.bin.hex @@ -0,0 +1,16 @@ +43 56 4d 5f 43 4c 49 42 00 00 00 00 00 00 00 00 +00 00 02 00 00 00 00 00 00 00 03 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 diff --git a/src/soc/cavium/common/rom_csib_s_nbl1fw.bin.hex b/src/soc/cavium/common/rom_csib_s_nbl1fw.bin.hex new file mode 100644 index 0000000000..f7a2021aaf --- /dev/null +++ b/src/soc/cavium/common/rom_csib_s_nbl1fw.bin.hex @@ -0,0 +1,16 @@ +43 56 4d 5f 43 53 49 42 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 diff --git a/src/vendorcode/cavium/include/bdk/bdk-coreboot.h b/src/vendorcode/cavium/include/bdk/bdk-coreboot.h new file mode 100644 index 0000000000..7b417b6c02 --- /dev/null +++ b/src/vendorcode/cavium/include/bdk/bdk-coreboot.h @@ -0,0 +1,173 @@ +/* + * This file is part of the coreboot project. + * Copyright (c) 2003-2017 Cavium Inc. (support@cavium.com). All rights + * reserved. + * Copyright 2018-present Facebook, Inc. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * access.h: Wrappers for memory access + */ + +#ifndef __BDK_BDK_COREBOOT_H +#define __BDK_BDK_COREBOOT_H + +#include <arch/io.h> +#include <delay.h> + +/** + * Convert a memory pointer (void*) into a hardware compatible + * memory address (uint64_t). Cavium hardware widgets don't + * understand logical addresses. + * + * @param ptr C style memory pointer + * @return Hardware physical address + */ +static inline uint64_t bdk_ptr_to_phys(void *ptr) +{ + /* PA = VA for coreboot's purposes */ + return (uint64_t)ptr; +} + +/** + * Convert a hardware physical address (uint64_t) into a + * memory pointer (void *). + * + * @param physical_address + * Hardware physical address to memory + * @return Pointer to memory + */ +static inline void *bdk_phys_to_ptr(uint64_t physical_address) +{ + /* PA = VA for coreboot's purposes */ + return (void *)physical_address; +} + +static inline void bdk_write64_int64(uint64_t address, int64_t value) +{ + dmb(); + *(volatile int64_t *)address = value; + dmb(); +} + +static inline void bdk_write64_uint64(uint64_t address, uint64_t value) +{ + write64(bdk_phys_to_ptr(address), value); +} + +static inline void bdk_write64_int32(uint64_t address, int32_t value) +{ + dmb(); + *(volatile int32_t *)address = value; + dmb(); +} + +static inline void bdk_write64_uint32(uint64_t address, uint32_t value) +{ + write32(bdk_phys_to_ptr(address), value); +} + +static inline void bdk_write64_int16(uint64_t address, int16_t value) +{ + dmb(); + *(volatile int16_t *)address = value; + dmb(); +} + +static inline void bdk_write64_uint16(uint64_t address, uint16_t value) +{ + write16(bdk_phys_to_ptr(address), value); +} + +static inline void bdk_write64_int8(uint64_t address, int8_t value) +{ + dmb(); + *(volatile int8_t *)address = value; + dmb(); +} + +static inline void bdk_write64_uint8(uint64_t address, uint8_t value) +{ + write8(bdk_phys_to_ptr(address), value); +} + +static inline int64_t bdk_read64_int64(uint64_t address) +{ + return *(volatile int64_t *)bdk_phys_to_ptr(address); +} + +static inline uint64_t bdk_read64_uint64(uint64_t address) +{ + return read64(bdk_phys_to_ptr(address)); +} + +static inline int32_t bdk_read64_int32(uint64_t address) +{ + return *(volatile int32_t *)bdk_phys_to_ptr(address); +} + +static inline uint32_t bdk_read64_uint32(uint64_t address) +{ + return read32(bdk_phys_to_ptr(address)); +} + +static inline int16_t bdk_read64_int16(uint64_t address) +{ + return *(volatile int16_t *)bdk_phys_to_ptr(address); +} + +static inline uint16_t bdk_read64_uint16(uint64_t address) +{ + return read16(bdk_phys_to_ptr(address)); +} + +static inline int8_t bdk_read64_int8(uint64_t address) +{ + return *(volatile int8_t *)bdk_phys_to_ptr(address); +} + +static inline uint8_t bdk_read64_uint8(uint64_t address) +{ + return read8(bdk_phys_to_ptr(address)); +} + +/** + * Returns the number of bits set in the provided value. + * Simple wrapper for POP instruction. + * + * @param val 32 bit value to count set bits in + * + * @return Number of bits set + */ +inline uint32_t bdk_pop(uint32_t v) +{ + /* Use parallel SWAR algorithm */ + v = v - ((v >> 1) & 0x55555555); + v = (v & 0x33333333) + ((v >> 2) & 0x33333333); + return (((v + (v >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; +} + +/** + * Returns the number of bits set in the provided value. + * Simple wrapper for DPOP instruction. + * + * @param val 64 bit value to count set bits in + * + * @return Number of bits set + */ +inline int bdk_dpop(uint64_t val) +{ + return bdk_pop(val & 0xffffffff) + bdk_pop(val >> 32); +} + +/** + * Wait for the specified number of micro seconds + * + * @param usec micro seconds to wait + */ +static inline void bdk_wait_usec(uint64_t usec) +{ + udelay((unsigned int)usec); +} + +#endif /* !__BDK_BDK_COREBOOT_H */ diff --git a/src/vendorcode/cavium/include/bdk/bdk-minimal.h b/src/vendorcode/cavium/include/bdk/bdk-minimal.h index 3ecf5a700a..e22e8a1524 100644 --- a/src/vendorcode/cavium/include/bdk/bdk-minimal.h +++ b/src/vendorcode/cavium/include/bdk/bdk-minimal.h @@ -10,13 +10,12 @@ * bdk-minimal.h: Subset of bdk.h used by coreboot */ -#ifndef __SOC_CAVIUM_COMMON_BDK_MINIMAL_H__ -#define __SOC_CAVIUM_COMMON_BDK_MINIMAL_H__ +#ifndef BDK_MINIMAL_H__ +#define BDK_MINIMAL_H__ #include <console/console.h> /* for printk */ #include <endian.h> #include <stddef.h> /* for NULL */ -#include <libbdk-hal/bdk-access.h> #define bdk_le16_to_cpu(x) le16_to_cpu(x) #define bdk_le32_to_cpu(x) le32_to_cpu(x) @@ -28,11 +27,6 @@ #define bdk_cpu_to_le32(x) cpu_to_le32(x) #define bdk_cpu_to_le64(x) cpu_to_le64(x) -#define __BYTE_ORDER __BYTE_ORDER__ -/* Watch out for __BIG_ENDIAN. coreboot usually checks if it's defined at all - * but the Cavium BDK checks its value. */ -#define __BIG_ENDIAN 4321 - #define printf(format, ...) printk(BIOS_DEBUG, format, ##__VA_ARGS__) #define puts(str) printk(BIOS_INFO, str) #define fflush(x) /* output gets flushed automatically */ @@ -42,8 +36,10 @@ #include <libbdk-arch/bdk-asm.h> #include <libbdk-arch/bdk-model.h> #include <libbdk-arch/bdk-numa.h> +#include <libbdk-hal/bdk-access.h> #include <libbdk-arch/bdk-require.h> + #include <libbdk-arch/bdk-csr.h> #include <libbdk-os/bdk-thread.h> @@ -57,4 +53,4 @@ static inline char *getenv(const char *name) { return NULL; } -#endif /* !__SOC_CAVIUM_COMMON_BDK_MINIMAL_H__ */ +#endif /* BDK_MINIMAL_H__ */ |