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>
This commit is contained in:
David Hendricks 2017-12-01 20:49:48 -08:00 committed by Patrick Rudolph
parent 03d3142733
commit 8cbd569f74
55 changed files with 5750 additions and 9 deletions

View file

@ -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

View file

@ -0,0 +1,2 @@
config VENDOR_CAVIUM
bool "Cavium"

View file

@ -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

View file

@ -0,0 +1,2 @@
config BOARD_CAVIUM_CN8100_SFF_EVB
bool "CN8100 SFF EVB"

View file

@ -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

View file

@ -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},
};

View file

@ -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
}

View file

@ -0,0 +1,6 @@
Vendor name: Cavium
Board name: CN81XX SFF EVB
Category: eval
ROM protocol: SPI
ROM socketed: n
Flashrom support: n

View file

@ -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();
}

View file

@ -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>;
};
};

View file

@ -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 */
}; /* / */

View file

@ -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

View file

@ -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,
};

View file

@ -0,0 +1 @@
#include <soc/memlayout.ld>

View file

@ -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();
}

View file

@ -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";
};
};

2
src/soc/cavium/Kconfig Normal file
View file

@ -0,0 +1,2 @@
# Load all chipsets
source "src/soc/cavium/*/Kconfig"

View file

@ -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

View file

@ -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

View file

@ -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? */
}

View file

@ -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)

View file

@ -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 */

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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(&regs->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(&regs->bit_cfg[gpio]);
bit_cfg.s.pin_sel = 0;
bit_cfg.s.tx_oe = 0;
write64(&regs->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(&regs->tx_set, 1 << gpio);
else
write64(&regs->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(&regs->bit_cfg[gpio]);
bit_cfg.s.pin_sel = 0;
bit_cfg.s.tx_oe = 1;
write64(&regs->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(&regs->bit_cfg[gpio]);
bit_cfg.s.xor = !!value;
write64(&regs->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(&regs->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(&regs->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)
{
}

View file

@ -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__ */

View file

@ -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_ */

View file

@ -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__ */

View file

@ -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

View file

@ -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)
}

View file

@ -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__ */

View file

@ -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 */

View file

@ -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 */

View file

@ -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__ */

View file

@ -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

View file

@ -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 */

View file

@ -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");
}

View file

@ -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,
};

401
src/soc/cavium/cn81xx/spi.c Normal file
View file

@ -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(&regs->cfg);
cfg.s.csena = 0xf;
cfg.s.enable = 1;
write64(&regs->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(&regs->cfg);
cfg.s.csena = 0xf;
cfg.s.enable = 0;
write64(&regs->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(&regs->cfg);
cfg.s.csena = 0xf;
cfg.s.cshi = !assert_is_low;
write64(&regs->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(&regs->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(&regs->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(&regs->cfg);
cfg.s.csena = 0xf;
cfg.s.lsbfirst = !!lsb_first;
write64(&regs->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(&regs->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(&regs->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(&regs->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(&regs->tx, tx.u);
/* check status */
if (cavium_spi_wait(regs) < 0)
return -1;
sts.u = read64(&regs->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(&regs->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);

View file

@ -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(&gti->cc_imp_ctl, 0);
/* Setup counter to operate at 1MHz */
const size_t tickrate = 1000000;
write32(&gti->cc_cntfid0, tickrate);
write32(&gti->ctl_cntfrq, tickrate);
write32(&gti->cc_cntrate, ((1ULL << 32) * tickrate) / sclk);
/* Enable the counter */
setbits_le32(&gti->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));
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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();
}

View file

@ -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);
}

View file

@ -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__ */

View file

@ -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_ */

View file

@ -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 */

View file

@ -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

View file

@ -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

View file

@ -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 */

View file

@ -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__ */