summaryrefslogtreecommitdiff
path: root/drivers/marvell/mochi/cp110_setup.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/marvell/mochi/cp110_setup.c')
-rw-r--r--drivers/marvell/mochi/cp110_setup.c400
1 files changed, 400 insertions, 0 deletions
diff --git a/drivers/marvell/mochi/cp110_setup.c b/drivers/marvell/mochi/cp110_setup.c
new file mode 100644
index 00000000..5538a588
--- /dev/null
+++ b/drivers/marvell/mochi/cp110_setup.c
@@ -0,0 +1,400 @@
+/*
+* ***************************************************************************
+* Copyright (C) 2016 Marvell International Ltd.
+* ***************************************************************************
+*
+* 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 Marvell 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 IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+*
+***************************************************************************
+*/
+
+#include <plat_def.h>
+#include <apn806_setup.h>
+#include <amb_adec.h>
+#include <iob.h>
+#include <icu.h>
+#include <mmio.h>
+
+/*
+ ICU configuration
+ */
+/* Multi instance sources, multipllied in dual CP mode */
+static const struct icu_irq irq_map_ns_multi[] = {
+ {22, 0, 0}, /* PCIx4 INT A interrupt */
+ {23, 1, 0}, /* PCIx1 INT A interrupt */
+ {24, 2, 0}, /* PCIx1 INT A interrupt */
+
+ {33, 3, 0}, /* PPv2 DBG AXI monitor */
+ {34, 3, 0}, /* HB1 AXI monitor */
+ {35, 3, 0}, /* AP AXI monitor */
+ {36, 3, 0}, /* PPv2 AXI monitor */
+
+ {38, 4, 0}, /* PPv2 Misc */
+
+ {39, 5, 0}, /* PPv2 irq */
+ {40, 6, 0}, /* PPv2 irq */
+ {41, 7, 0}, /* PPv2 irq */
+ {42, 8, 0}, /* PPv2 irq */
+ {43, 9, 0}, /* PPv2 irq */
+ {44, 10, 0}, /* PPv2 irq */
+ {45, 11, 0}, /* PPv2 irq */
+ {46, 12, 0}, /* PPv2 irq */
+ {47, 13, 0}, /* PPv2 irq */
+ {48, 14, 0}, /* PPv2 irq */
+ {49, 15, 0}, /* PPv2 irq */
+ {50, 16, 0}, /* PPv2 irq */
+ {51, 17, 0}, /* PPv2 irq */
+ {52, 18, 0}, /* PPv2 irq */
+ {53, 19, 0}, /* PPv2 irq */
+ {54, 20, 0}, /* PPv2 irq */
+
+ {78, 21, 0}, /* MG irq */
+ {88, 22, 0}, /* EIP-197 ring-0 */
+ {89, 23, 0}, /* EIP-197 ring-1 */
+ {90, 24, 0}, /* EIP-197 ring-2 */
+ {91, 25, 0}, /* EIP-197 ring-3 */
+ {92, 26, 0}, /* EIP-197 int */
+ {95, 27, 0}, /* EIP-150 irq */
+ {102, 28, 0}, /* USB3 Device irq */
+ {105, 29, 0}, /* USB3 Host-1 irq */
+ {106, 30, 0}, /* USB3 Host-0 irq */
+ {107, 31, 0}, /* SATA Host-1 irq */
+ {109, 31, 0}, /* SATA Host-0 irq */
+ {126, 33, 0}, /* PTP irq */
+ {127, 34, 0}, /* GOP-3 irq */
+ {128, 35, 0}, /* GOP-2 irq */
+ {129, 36, 0}, /* GOP-0 irq */
+
+ /* PPv2 interrupts which originally assigned as single interrupts.
+ * To avoid updating Device tree, left original SPI assignment 60-63,
+ * hence there is a gap between previous multi interrupts */
+ {55, 60, 0}, /* PPv2 irq */
+ {56, 61, 0}, /* PPv2 irq */
+ {57, 62, 0}, /* PPv2 irq */
+ {58, 63, 0}, /* PPv2 irq */
+};
+
+/* Single instance sources, not multiplies in dual CP mode */
+static const struct icu_irq irq_map_ns_single[] = {
+ {27, 37, 0}, /* SD/MMC */
+ {76, 38, 0}, /* Audio */
+ {77, 39, 0}, /* MSS RTC */
+ {79, 40, 0}, /* GPIO 56-63 */
+ {80, 41, 0}, /* GPIO 48-55 */
+ {81, 42, 0}, /* GPIO 40-47 */
+ {82, 43, 0}, /* GPIO 32-39 */
+ {83, 44, 0}, /* GPIO 24-31 */
+ {84, 45, 0}, /* GPIO 16-23 */
+ {85, 46, 0}, /* GPIO 8-15 */
+ {86, 47, 0}, /* GPIO 0-7 */
+ {111, 48, 0}, /* TDM-MC func 1 */
+ {112, 49, 0}, /* TDM-MC func 0 */
+ {113, 50, 0}, /* TDM-MC irq */
+ {115, 51, 0}, /* NAND irq */
+ {117, 52, 0}, /* SPI-1 irq */
+ {118, 53, 0}, /* SPI-0 irq */
+ {120, 54, 0}, /* I2C 0 irq */
+ {121, 55, 0}, /* I2C 1 irq */
+ {122, 56, 0}, /* UART 0 irq */
+ {123, 57, 0}, /* UART 1 irq */
+ {124, 58, 0}, /* UART 2 irq */
+ {125, 59, 0}, /* UART 3 irq */
+};
+
+/* SEI - System Error Interrupts */
+/* Note: SPI ID 0-20 are reserved for North-Bridge */
+static struct icu_irq irq_map_sei[] = {
+ {11, 21, 0}, /* SEI error CP-2-CP */
+ {15, 22, 0}, /* PIDI-64 SOC */
+ {16, 23, 0}, /* D2D error irq */
+ {17, 24, 0}, /* D2D irq */
+ {18, 25, 0}, /* NAND error */
+ {19, 26, 0}, /* PCIx4 error */
+ {20, 27, 0}, /* PCIx1_0 error */
+ {21, 28, 0}, /* PCIx1_1 error */
+ {25, 29, 0}, /* SDIO reg error */
+ {75, 30, 0}, /* IOB error */
+ {94, 31, 0}, /* EIP150 error */
+ {97, 32, 0}, /* XOR-1 system error */
+ {99, 33, 0}, /* XOR-0 system error */
+ {108, 34, 0}, /* SATA-1 error */
+ {110, 35, 0}, /* SATA-0 error */
+ {114, 36, 0}, /* TDM-MC error */
+ {116, 37, 0}, /* DFX server irq */
+ {117, 38, 0}, /* Device bus error */
+ {147, 39, 0}, /* Audio error */
+ {171, 40, 0}, /* PIDI Sync error */
+};
+
+/* REI - RAM Error Interrupts */
+static const struct icu_irq irq_map_rei[] = {
+ {12, 0, 0}, /* REI error CP-2-CP */
+ {26, 1, 0}, /* SDIO memory error */
+ {87, 2, 0}, /* EIP-197 ECC error */
+ {93, 3, 1}, /* EIP-150 RAM error */
+ {96, 4, 0}, /* XOR-1 memory irq */
+ {98, 5, 0}, /* XOR-0 memory irq */
+ {100, 6, 1}, /* USB3 device tx parity */
+ {101, 7, 1}, /* USB3 device rq parity */
+ {103, 8, 1}, /* USB3H-1 RAM error */
+ {104, 9, 1}, /* USB3H-0 RAM error */
+};
+
+static const struct icu_config icu_config = {
+ .ns_multi = { irq_map_ns_multi, ARRAY_SIZE(irq_map_ns_multi) },
+ .ns_single = { irq_map_ns_single, ARRAY_SIZE(irq_map_ns_single) },
+ .sei = { irq_map_sei, ARRAY_SIZE(irq_map_sei) },
+ .rei = { irq_map_rei, ARRAY_SIZE(irq_map_rei) },
+};
+
+/*
+ * AXI Configuration.
+ */
+
+ /* Used for Units of CP-110 (e.g. USB device, USB Host, and etc) */
+#define MVEBU_AXI_ATTR_BASE(cp_index) (MVEBU_CP_REGS_BASE(cp_index) + 0x441300)
+#define MVEBU_AXI_ATTR_REG(cp_index, index) (MVEBU_AXI_ATTR_BASE(cp_index) + 0x4 * index)
+
+/* AXI Protection bits */
+#define MVEBU_AXI_PROT_BASE(cp_index) (MVEBU_CP_REGS_BASE(cp_index) + 0x441200)
+
+/* AXI Protection regs for A0 revision */
+#define MVEBU_AXI_PROT_REG_A0(cp_index, index) ((index <= 6) ? (MVEBU_AXI_PROT_BASE(cp_index) + 0x4 * index) : \
+ (MVEBU_AXI_PROT_BASE(cp_index) + 0x20 + 0x4 * (index - 7)))
+#define MVEBU_AXI_PROT_REGS_NUM_A0 (9)
+
+/* AXI Protection regs for A1 revision */
+#define MVEBU_AXI_PROT_REG(cp_index, index) ((index <= 4) ? (MVEBU_AXI_PROT_BASE(cp_index) + 0x4 * index) : \
+ (MVEBU_AXI_PROT_BASE(cp_index) + 0x18))
+#define MVEBU_AXI_PROT_REGS_NUM (6)
+
+#define MVEBU_SOC_CFGS_BASE(cp_index) (MVEBU_CP_REGS_BASE(cp_index) + 0x441900)
+#define MVEBU_SOC_CFG_REG(cp_index, index) (MVEBU_SOC_CFGS_BASE(cp_index) + 0x4 * index)
+#define MVEBU_SOC_CFG_REG_NUM (0)
+#define MVEBU_SOC_CFG_GLOG_SECURE_EN_MASK (0xE)
+
+/* SATA3 MBUS to AXI regs */
+#define MVEBU_SATA_M2A_AXI_PORT_CTRL_REG(cp_index) (MVEBU_CP_REGS_BASE(cp_index) + 0x54ff04)
+
+/* AXI to MBUS bridge registers */
+#define MVEBU_AMB_IP_BRIDGE_WIN_REG(cp_index, win) (MVEBU_AMB_IP_BASE(cp_index) + (win * 0x8))
+#define MVEBU_AMB_IP_BRIDGE_WIN_EN_OFFSET 0
+#define MVEBU_AMB_IP_BRIDGE_WIN_EN_MASK (0x1 << MVEBU_AMB_IP_BRIDGE_WIN_EN_OFFSET)
+#define MVEBU_AMB_IP_BRIDGE_WIN_SIZE_OFFSET 16
+#define MVEBU_AMB_IP_BRIDGE_WIN_SIZE_MASK (0xffff << MVEBU_AMB_IP_BRIDGE_WIN_SIZE_OFFSET)
+
+enum axi_attr {
+ AXI_ADUNIT_ATTR = 0,
+ AXI_COMUNIT_ATTR,
+ AXI_EIP197_ATTR,
+ AXI_USB3D_ATTR,
+ AXI_USB3H0_ATTR,
+ AXI_USB3H1_ATTR,
+ AXI_SATA0_ATTR,
+ AXI_SATA1_ATTR,
+ AXI_DAP_ATTR,
+ AXI_DFX_ATTR,
+ AXI_DBG_TRC_ATTR = 12,
+ AXI_SDIO_ATTR,
+ AXI_MSS_ATTR,
+ AXI_MAX_ATTR,
+};
+
+/* Most stream IDS are configured centrally in the CP-110 RFU
+ * but some are configured inside the unit registers
+ */
+#define RFU_STREAM_ID_BASE (0x450000)
+#define AUDIO_STREAM_ID_REG (RFU_STREAM_ID_BASE + 0x0)
+#define TDM_STREAM_ID_REG (RFU_STREAM_ID_BASE + 0x4)
+#define USB3D_STREAM_ID_REG (RFU_STREAM_ID_BASE + 0x8)
+#define USB3H_0_STREAM_ID_REG (RFU_STREAM_ID_BASE + 0xC)
+#define USB3H_1_STREAM_ID_REG (RFU_STREAM_ID_BASE + 0x10)
+#define SATA_0_STREAM_ID_REG (RFU_STREAM_ID_BASE + 0x14)
+#define SATA_1_STREAM_ID_REG (RFU_STREAM_ID_BASE + 0x18)
+#define DBG_TRC_STREAM_ID_REG (RFU_STREAM_ID_BASE + 0x24)
+#define SDIO_STREAM_ID_REG (RFU_STREAM_ID_BASE + 0x28)
+#define DAP_STREAM_ID_REG (RFU_STREAM_ID_BASE + 0x2C)
+
+#define CP_DMA_0_STREAM_ID_REG (0x6B0010)
+#define CP_DMA_1_STREAM_ID_REG (0x6D0010)
+
+/* We allocate IDs 0-127 for PCI since
+ * SR-IOV devices can generate many functions
+ * that need a unique Stream-ID.
+ */
+#define MAX_PCIE_STREAM_ID (0x80)
+
+uintptr_t stream_id_reg[] = {
+ AUDIO_STREAM_ID_REG,
+ TDM_STREAM_ID_REG,
+ USB3D_STREAM_ID_REG,
+ USB3H_0_STREAM_ID_REG,
+ USB3H_1_STREAM_ID_REG,
+ SATA_0_STREAM_ID_REG,
+ SATA_1_STREAM_ID_REG,
+ DBG_TRC_STREAM_ID_REG,
+ SDIO_STREAM_ID_REG,
+ DAP_STREAM_ID_REG,
+ CP_DMA_0_STREAM_ID_REG,
+ CP_DMA_1_STREAM_ID_REG,
+ 0
+};
+
+void cp110_errata_wa_init(int cp_index)
+{
+ uint32_t data;
+
+ /* ERRATA GL-4076863 (STORM-916):
+ * Reset value for global_secure_enable inputs must be changed from '1' to '0'.
+ * When asserted, only "secured" transactions can enter IHB configuration space.
+ * However, blocking AXI transactions is performed by IOB.
+ * Performing it also at IHB/HB complicates programming model.
+ *
+ * Enable non-secure access in SOC configuration register */
+ data = mmio_read_32(MVEBU_SOC_CFG_REG(cp_index, MVEBU_SOC_CFG_REG_NUM));
+ data &= ~MVEBU_SOC_CFG_GLOG_SECURE_EN_MASK;
+ mmio_write_32(MVEBU_SOC_CFG_REG(cp_index, MVEBU_SOC_CFG_REG_NUM), data);
+}
+
+/* Set a unique stream id for all DMA capable devices */
+void cp110_stream_id_init(uintptr_t cp110_base)
+{
+ int i = 0;
+ uint32_t stream_id = MAX_PCIE_STREAM_ID;
+
+ while (stream_id_reg[i]) {
+ /* SATA port 0/1 are in the same SATA unit, and they should use
+ ** the same STREAM ID number */
+ if (stream_id_reg[i] == SATA_0_STREAM_ID_REG)
+ mmio_write_32(cp110_base + stream_id_reg[i++], stream_id);
+ else
+ mmio_write_32(cp110_base + stream_id_reg[i++], stream_id++);
+ }
+}
+
+void cp110_axi_attr_init(int cp_index)
+{
+ uint32_t index, data;
+
+ /* Initialize AXI attributes for Armada-7K/8K SoC */
+
+ /* Go over the AXI attributes and set Ax-Cache and Ax-Domain */
+ for (index = 0; index < AXI_MAX_ATTR; index++) {
+ switch (index) {
+ /* DFX and MSS unit works with no coherent only -
+ there's no option to configure the Ax-Cache and Ax-Domain */
+ case AXI_DFX_ATTR:
+ case AXI_MSS_ATTR:
+ continue;
+ default:
+ /* Set Ax-Cache as cacheable, no allocate, modifiable, bufferable
+ The values are different because Read & Write definition
+ is different in Ax-Cache */
+ data = mmio_read_32(MVEBU_AXI_ATTR_REG(cp_index, index));
+ data &= ~MVEBU_AXI_ATTR_ARCACHE_MASK;
+ data |= (CACHE_ATTR_WRITE_ALLOC | CACHE_ATTR_CACHEABLE | CACHE_ATTR_BUFFERABLE)
+ << MVEBU_AXI_ATTR_ARCACHE_OFFSET;
+ data &= ~MVEBU_AXI_ATTR_AWCACHE_MASK;
+ data |= (CACHE_ATTR_READ_ALLOC | CACHE_ATTR_CACHEABLE | CACHE_ATTR_BUFFERABLE)
+ << MVEBU_AXI_ATTR_AWCACHE_OFFSET;
+ /* Set Ax-Domain as Outer domain */
+ data &= ~MVEBU_AXI_ATTR_ARDOMAIN_MASK;
+ data |= DOMAIN_OUTER_SHAREABLE << MVEBU_AXI_ATTR_ARDOMAIN_OFFSET;
+ data &= ~MVEBU_AXI_ATTR_AWDOMAIN_MASK;
+ data |= DOMAIN_OUTER_SHAREABLE << MVEBU_AXI_ATTR_AWDOMAIN_OFFSET;
+ mmio_write_32(MVEBU_AXI_ATTR_REG(cp_index, index), data);
+ }
+ }
+
+ if (apn806_rev_id_get() == APN806_REV_ID_A1) {
+ /* SATA IOCC supported in A1 rev only:
+ * Cache attributes for SATA MBUS to AXI configuration */
+ data = mmio_read_32(MVEBU_SATA_M2A_AXI_PORT_CTRL_REG(cp_index));
+ data &= ~MVEBU_SATA_M2A_AXI_AWCACHE_MASK;
+ data |= (CACHE_ATTR_WRITE_ALLOC | CACHE_ATTR_CACHEABLE | CACHE_ATTR_BUFFERABLE)
+ << MVEBU_SATA_M2A_AXI_AWCACHE_OFFSET;
+ data &= ~MVEBU_SATA_M2A_AXI_ARCACHE_MASK;
+ data |= (CACHE_ATTR_READ_ALLOC | CACHE_ATTR_CACHEABLE | CACHE_ATTR_BUFFERABLE)
+ << MVEBU_SATA_M2A_AXI_ARCACHE_OFFSET;
+ mmio_write_32(MVEBU_SATA_M2A_AXI_PORT_CTRL_REG(cp_index), data);
+
+ /* Set all IO's AXI attribute to non-secure access. */
+ for (index = 0; index < MVEBU_AXI_PROT_REGS_NUM; index++)
+ mmio_write_32(MVEBU_AXI_PROT_REG(cp_index, index), DOMAIN_SYSTEM_SHAREABLE);
+ } else {
+ /* for A0 rev only set AXI attribute to non-secure access
+ * (different AXI_PROT reg mapping vs A1) */
+ for (index = 0; index < MVEBU_AXI_PROT_REGS_NUM_A0; index++)
+ mmio_write_32(MVEBU_AXI_PROT_REG_A0(cp_index, index), DOMAIN_SYSTEM_SHAREABLE);
+ }
+
+ return;
+}
+
+void amb_bridge_init(int cp_index)
+{
+ uint32_t reg;
+
+ /* Open AMB bridge Window to Access COMPHY/MDIO registers */
+ reg = mmio_read_32(MVEBU_AMB_IP_BRIDGE_WIN_REG(cp_index, 0));
+ reg &= ~(MVEBU_AMB_IP_BRIDGE_WIN_SIZE_MASK | MVEBU_AMB_IP_BRIDGE_WIN_EN_MASK);
+ reg |= (0x7ff << MVEBU_AMB_IP_BRIDGE_WIN_SIZE_OFFSET | 0x1 << MVEBU_AMB_IP_BRIDGE_WIN_EN_OFFSET);
+ mmio_write_32(MVEBU_AMB_IP_BRIDGE_WIN_REG(cp_index, 0), reg);
+}
+
+void cp110_init(int cp_index)
+{
+ /* configure AXI-MBUS windows for CP0*/
+ init_amb_adec(cp_index);
+
+ /* configure IOB windows for CP0*/
+ init_iob(cp_index);
+
+ /* configure axi for CP0*/
+ cp110_axi_attr_init(cp_index);
+
+ /* Execute SW WA for erratas */
+ cp110_errata_wa_init(cp_index);
+
+ /* configure icu for CP0 */
+ /* ICU - Interrupt Consolidation unit
+ * CP0: interrupt 0..63 mapped to ID 64..127 in AP
+ * CP1: interrupt 64..127 mapped to ID 288..351 in AP */
+ icu_init(cp_index, 0, cp_index * 64, &icu_config);
+
+ /* configure stream id for CP0 */
+ cp110_stream_id_init(MVEBU_CP_REGS_BASE(cp_index));
+
+ /* Open AMB bridge for comphy for CP0 & CP1*/
+ amb_bridge_init(cp_index);
+}
+
+/* Do the minimal setup required to configure the CP in BLE */
+void cp110_ble_init(int cp_index)
+{
+ amb_bridge_init(cp_index);
+}