1/*
2 * Copyright 2014, General Dynamics C4 Systems
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#include <config.h>
8#include <api/types.h>
9#include <arch/machine.h>
10#include <arch/machine/hardware.h>
11#include <util.h>
12
13/* Prototyped here as this is referenced from assembly */
14void arm_errata(void);
15
16#ifdef ARM1136_WORKAROUND
17/*
18 * Potentially work around ARM1136 errata #364296, which can cause data
19 * cache corruption.
20 *
21 * The fix involves disabling hit-under-miss via an undocumented bit in
22 * the aux control register, as well as the FI bit in the control
23 * register. The result of enabling these two bits is for fast
24 * interrupts to *not* be enabled, but hit-under-miss to be disabled. We
25 * only need to do this for a particular revision of the ARM1136.
26 */
27BOOT_CODE static void errata_arm1136(void)
28{
29    /* See if we are affected by the errata. */
30    if ((getProcessorID() & ~0xf) == ARM1136_R0PX) {
31
32        /* Enable the Fast Interrupts bit in the control register. */
33        writeSystemControlRegister(
34            readSystemControlRegister() | BIT(CONTROL_FI));
35
36        /* Set undocumented bit 31 in the auxiliary control register */
37        writeAuxiliaryControlRegister(
38            readAuxiliaryControlRegister() | BIT(31));
39    }
40}
41#endif
42
43#ifdef CONFIG_ARM_ERRATA_773022
44/*
45 * There is an errata for Cortex-A15 up to r0p4 where the loop buffer
46 * may deliver incorrect instructions. The work around is to disable
47 * the loop buffer. Errata is number 773022.
48 */
49BOOT_CODE static void errata_armA15_773022(void)
50{
51    /* Fetch the processor primary part number. */
52    uint32_t proc_id = getProcessorID();
53    uint32_t variant = (proc_id >> 20) & MASK(4);
54    uint32_t revision = proc_id & MASK(4);
55    uint32_t part = (proc_id >> 4) & MASK(12);
56
57    /* Check that we are running A15 and a revision upto r0p4. */
58    if (part == 0xc0f && variant == 0 && revision <= 4) {
59        /* Disable loop buffer in the auxiliary control register */
60        writeAuxiliaryControlRegister(
61            readAuxiliaryControlRegister() | BIT(1));
62    }
63}
64#endif
65
66BOOT_CODE void VISIBLE arm_errata(void)
67{
68#ifdef ARM1136_WORKAROUND
69    errata_arm1136();
70#endif
71#ifdef CONFIG_ARM_ERRATA_773022
72    errata_armA15_773022();
73#endif
74}
75
76