1251877Speter/*
2251877Speter * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3251877Speter *
4251877Speter * SPDX-License-Identifier: GPL-2.0-only
5251877Speter */
6251877Speter
7251877Speter#include <autoconf.h>
8251877Speter#include <elfloader.h>
9251877Speter#include <printf.h>
10251877Speter
11251877Speter/* The code for enabling SError is from L4T (Linux for Tegra).
12251877Speter * Read the Parker TRM 17.12 and 17.13 for NVIDIA-specific
13251877Speter * SError extensions and the ARI (abstract request interface).
14251877Speter */
15251877Speter
16251877Speter
17251877Speter#define SMC_SIP_INVOKE_MCE      0xc2ffff00
18251877Speter#define MCE_SMC_ENUM_MAX        0xff
19251877Speter#define ARI_MCA_GLOBAL_CONFIG   0x12
20251877Speter#define ARI_MCA_WRITE_SERR      0x2
21251877Speter#define NR_SMC_REGS             6
22251877Speter
23251877Spetertypedef union {
24251877Speter    struct {
25251877Speter        uint8_t cmd;
26262339Speter        uint8_t subidx;
27262339Speter        uint8_t idx;
28262339Speter        uint8_t inst;
29251877Speter    };
30251877Speter    struct {
31253895Speter        uint32_t low;
32253895Speter        uint32_t high;
33253895Speter    };
34253895Speter    uint64_t data;
35253895Speter} mca_cmd_t;
36253895Speter
37253895Speterstruct mce_regs {
38251877Speter    uint64_t args[NR_SMC_REGS];
39251877Speter};
40251877Speter
41251877Speterstatic __attribute__((noinline)) int send_smc(uint8_t func, struct mce_regs *regs)
42251877Speter{
43251877Speter    uint32_t ret = SMC_SIP_INVOKE_MCE | (func & MCE_SMC_ENUM_MAX);
44251877Speter    asm volatile(
45251877Speter        "mov    x0, %x0\n"
46251877Speter        "ldp    x1, x2, [%1, #16 * 0] \n"
47251877Speter        "ldp    x3, x4, [%1, #16 * 1] \n"
48251877Speter        "ldp    x5, x6, [%1, #16 * 2] \n"
49251877Speter        "isb\n"
50251877Speter        "smc #0\n"
51253895Speter        "mov %x0, x0\n"
52253895Speter        "stp x0, x1, [%1, #16 * 0]\n"
53251877Speter        "stp x2, x3, [%1, #16 * 1]\n"
54253895Speter        : "+r"(ret)
55253895Speter        : "r"(regs)
56253895Speter        : "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8",
57253895Speter        "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17");
58253895Speter    return ret;
59253895Speter}
60253895Speter
61253895Speter
62253895Speterstatic void tegra_mce_write_uncore_mca(mca_cmd_t cmd, uint64_t data, uint32_t *err)
63253895Speter{
64251877Speter    struct mce_regs regs;
65251877Speter    regs.args[0] = cmd.data;
66251877Speter    regs.args[1] = data;
67251877Speter    send_smc(13, &regs);
68251877Speter    *err = (uint32_t)regs.args[3];
69251877Speter}
70251877Speter
71251877Speterstatic void enable_serr(void)
72251877Speter{
73251877Speter    uint32_t err;
74251877Speter    mca_cmd_t cmd;
75251877Speter    cmd.data = 0;
76251877Speter    cmd.cmd = ARI_MCA_WRITE_SERR;
77251877Speter    cmd.idx = ARI_MCA_GLOBAL_CONFIG;
78251877Speter    tegra_mce_write_uncore_mca(cmd, 1, &err);
79251877Speter    printf("Enabling TX2 SError result %d\n", err);
80251877Speter}
81251877Speter
82251877Speter/* Enable SError report for TX2 */
83251877Spetervoid platform_init(void)
84251877Speter{
85251877Speter    enable_serr();
86251877Speter}
87251877Speter
88251877Speter