From 4712fa35c1b04a421c8722501a37eb481b379e1f Mon Sep 17 00:00:00 2001 From: Konstantin Porotchkin Date: Mon, 20 Mar 2017 16:41:14 +0200 Subject: drivers: Add drivers for Marvell A7K and A8K platforms Add Marvell drivers for A7K and A8K SoC families Change-Id: I7fb530e543e4f64782f41f8a058b6aabd82af9e8 Signed-off-by: Haim Boot Signed-off-by: Konstantin Porotchkin Reviewed-on: http://vgitil04.il.marvell.com:8080/37916 --- docs/marvell/misc/mvebu-amb.txt | 45 ++ docs/marvell/misc/mvebu-ccu.txt | 38 ++ docs/marvell/misc/mvebu-iob.txt | 56 +++ docs/marvell/misc/mvebu-rfu.txt | 48 +++ drivers/marvell/amb_adec.c | 166 +++++++ drivers/marvell/cache_llc.c | 99 +++++ drivers/marvell/ccu.c | 266 ++++++++++++ drivers/marvell/comphy.h | 390 +++++++++++++++++ drivers/marvell/dw-pcie-ep.c | 178 ++++++++ drivers/marvell/i2c/a8k_i2c.c | 563 ++++++++++++++++++++++++ drivers/marvell/icu.c | 143 +++++++ drivers/marvell/iob.c | 206 +++++++++ drivers/marvell/mci.c | 617 +++++++++++++++++++++++++++ drivers/marvell/mochi/apn806_setup.c | 216 ++++++++++ drivers/marvell/mochi/cp110_setup.c | 400 +++++++++++++++++ drivers/marvell/pci_ep.h | 59 +++ drivers/marvell/pcie-comphy-cp110.c | 418 ++++++++++++++++++ drivers/marvell/rfu.c | 197 +++++++++ include/drivers/marvell/a8k_i2c.h | 61 +++ include/drivers/marvell/amb_adec.h | 68 +++ include/drivers/marvell/cache_llc.h | 33 ++ include/drivers/marvell/ccu.h | 63 +++ include/drivers/marvell/i2c.h | 46 ++ include/drivers/marvell/icu.h | 60 +++ include/drivers/marvell/iob.h | 61 +++ include/drivers/marvell/mci.h | 260 +++++++++++ include/drivers/marvell/mochi/apn806_setup.h | 60 +++ include/drivers/marvell/mochi/cp110_setup.h | 59 +++ include/drivers/marvell/rfu.h | 64 +++ 29 files changed, 4940 insertions(+) create mode 100644 docs/marvell/misc/mvebu-amb.txt create mode 100644 docs/marvell/misc/mvebu-ccu.txt create mode 100644 docs/marvell/misc/mvebu-iob.txt create mode 100644 docs/marvell/misc/mvebu-rfu.txt create mode 100644 drivers/marvell/amb_adec.c create mode 100644 drivers/marvell/cache_llc.c create mode 100644 drivers/marvell/ccu.c create mode 100644 drivers/marvell/comphy.h create mode 100644 drivers/marvell/dw-pcie-ep.c create mode 100644 drivers/marvell/i2c/a8k_i2c.c create mode 100644 drivers/marvell/icu.c create mode 100644 drivers/marvell/iob.c create mode 100644 drivers/marvell/mci.c create mode 100644 drivers/marvell/mochi/apn806_setup.c create mode 100644 drivers/marvell/mochi/cp110_setup.c create mode 100644 drivers/marvell/pci_ep.h create mode 100644 drivers/marvell/pcie-comphy-cp110.c create mode 100644 drivers/marvell/rfu.c create mode 100644 include/drivers/marvell/a8k_i2c.h create mode 100644 include/drivers/marvell/amb_adec.h create mode 100644 include/drivers/marvell/cache_llc.h create mode 100644 include/drivers/marvell/ccu.h create mode 100644 include/drivers/marvell/i2c.h create mode 100644 include/drivers/marvell/icu.h create mode 100644 include/drivers/marvell/iob.h create mode 100644 include/drivers/marvell/mci.h create mode 100644 include/drivers/marvell/mochi/apn806_setup.h create mode 100644 include/drivers/marvell/mochi/cp110_setup.h create mode 100644 include/drivers/marvell/rfu.h diff --git a/docs/marvell/misc/mvebu-amb.txt b/docs/marvell/misc/mvebu-amb.txt new file mode 100644 index 00000000..40a74674 --- /dev/null +++ b/docs/marvell/misc/mvebu-amb.txt @@ -0,0 +1,45 @@ +AMB - AXI MBUS address decoding +------------------------------- + +- The Runit offers a second level of address windows lookup. It is used to map transaction towards +the CD BootROM, SPI0, SPI1 and Device bus (NOR). +- The Runit contains eight configurable windows. Each window defines a contiguous, +address space and the properties associated with that address space. + +Unit Bank ATTR +Device-Bus DEV_BOOT_CS 0x2F + DEV_CS0 0x3E + DEV_CS1 0x3D + DEV_CS2 0x3B + DEV_CS3 0x37 +SPI-0 SPI_A_CS0 0x1E + SPI_A_CS1 0x5E + SPI_A_CS2 0x9E + SPI_A_CS3 0xDE + SPI_A_CS4 0x1F + SPI_A_CS5 0x5F + SPI_A_CS6 0x9F + SPI_A_CS7 0xDF +SPI1 SPI_B_CS0 0x1A + SPI_B_CS1 0x5A + SPI_B_CS2 0x9A + SPI_B_CS3 0xDA +BOOT_ROM BOOT_ROM 0x1D +UART UART 0x01 + +Mandatory functions: + - marvell_get_amb_reg_offs + returns the base address of the AXI-MBUS(AMB) unit + - marvell_get_amb_memory_map + returns the AMB windows configuration and the number of windows + +Mandatory structures: + amb_memory_map - Array that include the configuration of the windows + every window/entry is a struct which has 2 parameters: + - base address of the window + - Attribute of the window + +Examples: + struct amb_win amb_memory_map[] = { + {0xf900, AMB_DEV_CS0_ID}, + }; diff --git a/docs/marvell/misc/mvebu-ccu.txt b/docs/marvell/misc/mvebu-ccu.txt new file mode 100644 index 00000000..c8b5df5d --- /dev/null +++ b/docs/marvell/misc/mvebu-ccu.txt @@ -0,0 +1,38 @@ +Marvell CCU address decoding bindings +===================================== + +The CCU node includes a description of the address decoding configuration. + +Mandatory functions: + - marvell_get_ccu_reg_offs + returns the base address of the CCU unit + - marvell_get_ccu_max_win + returns the number of the max mbus windows + - marvell_get_ccu_memory_map + return the CCU windows configuration and the number of windows + +Mandatory structures: + ccu_memory_map - Array that includes the configuration of the windows + every window/entry is a struct which has 5 parameters: + - High base address of the window + - Low base address of the window + - High size of the window + - Low size of the window + - Target-ID of the window + +Note: if the base address is more than 32 bits, it should be divided into high and low. + The same goes for the Size field. If it is larger than 32 bits, it is divided into + high and low. + Base example: + base address: 0x10f0000000 should be divided into: + base address high: 0x10 + base address low: 0xf0000000 + Size example: + size: 0x1E00F00000 should be divided into: + size high: 0x1E + size low: 0x00F00000 + +Example: + struct ccu_win ccu_memory_map[] = { + {0x0, 0xf2000000, 0x0, 0xe000000, IO_0_TID}, /* IO window */ + }; diff --git a/docs/marvell/misc/mvebu-iob.txt b/docs/marvell/misc/mvebu-iob.txt new file mode 100644 index 00000000..5bd81c62 --- /dev/null +++ b/docs/marvell/misc/mvebu-iob.txt @@ -0,0 +1,56 @@ +Marvell IOB address decoding bindings +===================================== + +The IOB includes a description of the address decoding configuration. + +IOB supports up to n (in CP110 n=24) windows for external memory transaction. +When a transaction passes through the IOB, its address is compared to each of +the enabled windows. If there is a hit and it passes the security checks, it is +advanced to the target port. + +Mandatory functions: + - marvell_get_iob_reg_offs + returns the base address of the IOB unit + - marvell_get_iob_max_win + returns the number of the max IOB windows + - marvell_get_iob_memory_map + returns the IOB windows configuration and the number of windows + +Mandatory structures: + iob_memory_map - Array that include the configuration of the windows + every window/entry is a struct which has 5 parameters: + - High base address of the window + - Low base address of the window + - High size of the window + - Low size of the window + - Target-ID of the window + +Target ID options: + - 0x0 = Internal configuration space + - 0x1 = MCI0 + - 0x2 = PEX1_X1 + - 0x3 = PEX2_X1 + - 0x4 = PEX0_X4 + - 0x5 = NAND flash + - 0x6 = RUNIT (NOR/SPI/BootRoom) + - 0x7 = MCI1 + +Note: if the base address is more than 32 bits, it divided into high and low. + The same goes for the Size field, if it more that 32 bits, it divided into + high and low. + Base example: + base address: 0x10f0000000 should divided into: + base address high: 0x10 + base address low: 0xf0000000 + Size example: + size: 0x1E00F00000 should divided into: + size high: 0x1E + size low: 0x00F00000 + +Example: + struct iob_win iob_memory_map[] = { + {0x0, 0xf7000000, 0x0, 0x1000000, PEX1_TID}, /* PEX1_X1 window */ + {0x0, 0xf8000000, 0x0, 0x1000000, PEX2_TID}, /* PEX2_X1 window */ + {0x0, 0xf6000000, 0x0, 0x1000000, PEX0_TID}, /* PEX0_X4 window */ + {0x0, 0xf9000000, 0x0, 0x1000000, NAND_TID} /* NAND window */ + }; diff --git a/docs/marvell/misc/mvebu-rfu.txt b/docs/marvell/misc/mvebu-rfu.txt new file mode 100644 index 00000000..e525c960 --- /dev/null +++ b/docs/marvell/misc/mvebu-rfu.txt @@ -0,0 +1,48 @@ +Marvell RFU address decoding bindings +===================================== + +The RFU includes a description of the address decoding configuration. + +Transactions that are decoded by CCU windows as IO peripheral, have an additional +layer of decoding. This additional address decoding layer defines one of the +following targets: + 0x0 = BootRom + 0x1 = STM (Serial Trace Macro-cell, a programmer's port into trace stream) + 0x2 = SPI direct access + 0x3 = PCIe registers + 0x4 = MCI Port + 0x5 = PCIe port + +Mandatory functions: + - marvell_get_rfu_reg_offs + returns the base address of the RFU unit + - marvell_get_rfu_memory_map + returns the RFU windows configuration and the number of windows + +Mandatory structures: + rfu_memory_map - Array that include the configuration of the windows + every window/entry is a struct which has 5 parameters: + - High base address of the window + - Low base address of the window + - High size of the window + - Low size of the window + - Target-ID of the window + +Note: if the base address is more than 32 bits, it divided into high and low. + The same goes for the Size field, if it more that 32 bits, is divided into + high and low. + Base example: + base address: 0x10f0000000 should divided into: + base address high: 0x10 + base address low: 0xf0000000 + Size example: + size: 0x1E00F00000 should divided into: + size high: 0x1E + size low: 0x00F00000 + +Example: + struct rfu_win rfu_memory_map[] = { + {0x0, 0xfe000000, 0x0, 0x1f00000, PCIE_PORT_TID}, /* PCIe window 31Mb for PCIe port*/ + {0x0, 0xffe00000, 0x0, 0x100000, PCIE_REGS_TID}, /* PCI-REG window 64Kb for PCIe-reg*/ + {0x0, 0xf6000000, 0x0, 0x100000, MCIPHY_TID}, /* MCI window 1Mb for PHY-reg*/ + }; diff --git a/drivers/marvell/amb_adec.c b/drivers/marvell/amb_adec.c new file mode 100644 index 00000000..2a827a6f --- /dev/null +++ b/drivers/marvell/amb_adec.c @@ -0,0 +1,166 @@ +/* +* *************************************************************************** +* 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 +#include +#include +#include +#include + +#if LOG_LEVEL >= LOG_LEVEL_INFO +#define DEBUG_ADDR_MAP +#endif + +/* common defines */ +#define WIN_ENABLE_BIT (0x1) + +#define AMB_WIN_CR_OFFSET(win) (amb_base + 0x0 + (0x8 * win)) +#define AMB_ATTR_OFFSET 8 +#define AMB_ATTR_MASK 0xFF +#define AMB_SIZE_OFFSET 16 +#define AMB_SIZE_MASK 0xFF + +#define AMB_WIN_BASE_OFFSET(win) (amb_base + 0x4 + (0x8 * win)) +#define AMB_BASE_OFFSET 16 + +#define AMB_WIN_ALIGNMENT_64K (0x10000) +#define AMB_WIN_ALIGNMENT_1M (0x100000) + +uintptr_t amb_base; + +static void amb_check_win(struct amb_win *win, uint32_t win_num) +{ + uint32_t alignment_value = AMB_WIN_ALIGNMENT_1M; + uint32_t base_addr = win->base_addr << AMB_BASE_OFFSET; + + /* for AMB The base is always 1M aligned */ + /* check if address is aligned to 1M */ + + if (IS_NOT_ALIGN(base_addr, alignment_value)) { + win->base_addr = ALIGN_UP(base_addr, alignment_value); + printf("Warning: Window %d: base address unaligned to 0x%x\n", win_num, alignment_value); + printf("Align up the base address to 0x%x\n", win->base_addr); + } + + /* size parameter validity check */ + if (!IS_POWER_OF_2(win->win_size)) { + printf("Warning: Window %d: window size is not power of 2 (0x%x)\n", win_num, win->win_size); + win->win_size = ROUND_UP_TO_POW_OF_2(win->win_size); + printf("Rounding size to 0x%x\n", win->win_size); + } +} + +static void amb_enable_win(struct amb_win *win, uint32_t win_num) +{ + uint32_t ctrl, base, size; + + size = (win->win_size / AMB_WIN_ALIGNMENT_64K) - 1; /* size is 64KB granularity. + * The number of 1s specifies the size of the + * window in 64 KB granularity. 0 is 64KB */ + ctrl = (size << AMB_SIZE_OFFSET) | (win->attribute << AMB_ATTR_OFFSET); + base = win->base_addr << AMB_BASE_OFFSET; + + mmio_write_32(AMB_WIN_BASE_OFFSET(win_num), base); + mmio_write_32(AMB_WIN_CR_OFFSET(win_num), ctrl); + + /* enable window after configuring window size (and attributes) */ + ctrl |= WIN_ENABLE_BIT; + mmio_write_32(AMB_WIN_CR_OFFSET(win_num), ctrl); +} +#ifdef DEBUG_ADDR_MAP +static void dump_amb_adec(void) +{ + uint32_t ctrl, base, win_id, attr; + uint32_t size, size_count; + + /* Dump all AMB windows */ + printf("bank attribute base size\n"); + printf("--------------------------------------------\n"); + for (win_id = 0; win_id < AMB_MAX_WIN_ID; win_id++) { + ctrl = mmio_read_32(AMB_WIN_CR_OFFSET(win_id)); + if (ctrl & WIN_ENABLE_BIT) { + base = mmio_read_32(AMB_WIN_BASE_OFFSET(win_id)); + attr = (ctrl >> AMB_ATTR_OFFSET) & AMB_ATTR_MASK; + size_count = (ctrl >> AMB_SIZE_OFFSET) & AMB_SIZE_MASK; + size = (size_count + 1) * AMB_WIN_ALIGNMENT_64K; + printf("amb 0x%04x 0x%08x 0x%08x\n", attr, base, size); + } + } + + return; +} +#endif + +int init_amb_adec(int cp_index) +{ + struct amb_win *win; + uint32_t win_id, win_reg; + uint32_t win_count; + + INFO("Initializing AXI to MBus Bridge Address decoding\n"); + + /* Get the base address of the AMB address decoding */ + amb_base = marvell_get_amb_reg_offs(cp_index); + + /* Get the array of the windows and its size */ + marvell_get_amb_memory_map(&win, &win_count); + if (win_count <= 0) + INFO("no windows configurations found\n"); + + if (win_count > AMB_MAX_WIN_ID) { + INFO("number of windows is bigger than %d\n", AMB_MAX_WIN_ID); + return 0; + } + + /* disable all AMB windows */ + for (win_id = 0; win_id < AMB_MAX_WIN_ID; win_id++) { + win_reg = mmio_read_32(AMB_WIN_CR_OFFSET(win_id)); + win_reg &= ~WIN_ENABLE_BIT; + mmio_write_32(AMB_WIN_CR_OFFSET(win_id), win_reg); + } + + /* enable relevant windows */ + for (win_id = 0; win_id < win_count; win_id++, win++) { + amb_check_win(win, win_id); + amb_enable_win(win, win_id); + } + +#ifdef DEBUG_ADDR_MAP + dump_amb_adec(); +#endif + + INFO("Done AXI to MBus Bridge Address decoding Initializing\n"); + + return 0; +} diff --git a/drivers/marvell/cache_llc.c b/drivers/marvell/cache_llc.c new file mode 100644 index 00000000..cb5eed3c --- /dev/null +++ b/drivers/marvell/cache_llc.c @@ -0,0 +1,99 @@ +/* + * *************************************************************************** + * Copyright (C) 2015 Marvell International Ltd. + * *************************************************************************** + * 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, either version 2 of the License, or any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * *************************************************************************** + */ + +#include +#include +#include + +#define LLC_CTRL 0x100 +#define LLC_CACHE_SYNC 0x700 +#define L2X0_INV_WAY 0x77C +#define L2X0_CLEAN_WAY 0x7BC +#define L2X0_CLEAN_INV_WAY 0x7FC + +#define LLC_CTRL_EN 1 +#define LLC_EXCLUSIVE_EN 0x100 +#define LLC_WAY_MASK 0xFFFFFFFF + +void llc_cache_sync(void) +{ + mmio_write_32(MVEBU_LLC_BASE + LLC_CACHE_SYNC, 0); + /* Atumic write no need to wait */ +} + +void llc_flush_all(void) +{ + mmio_write_32(MVEBU_LLC_BASE + L2X0_CLEAN_INV_WAY, LLC_WAY_MASK); + llc_cache_sync(); +} + +void llc_clean_all(void) +{ + mmio_write_32(MVEBU_LLC_BASE + L2X0_CLEAN_WAY, LLC_WAY_MASK); + llc_cache_sync(); +} + +void llc_inv_all(void) +{ + mmio_write_32(MVEBU_LLC_BASE + L2X0_INV_WAY, LLC_WAY_MASK); + llc_cache_sync(); +} + +void llc_disable(void) +{ + llc_flush_all(); + mmio_write_32(MVEBU_LLC_BASE + LLC_CTRL, 0); + __asm__ volatile("dsb st"); +} + +void llc_enable(int excl_mode) +{ + uint32_t val; + + __asm__ volatile("dsb sy"); + llc_inv_all(); + __asm__ volatile("dsb sy"); + + val = LLC_CTRL_EN; + if (excl_mode) + val |= LLC_EXCLUSIVE_EN; + + mmio_write_32(MVEBU_LLC_BASE + LLC_CTRL, val); + __asm__ volatile("dsb sy"); +} + +int llc_is_exclusive(void) +{ + uint32_t reg; + + reg = mmio_read_32(MVEBU_LLC_BASE + LLC_CTRL); + + if ((reg & (LLC_CTRL_EN | LLC_EXCLUSIVE_EN)) == (LLC_CTRL_EN | LLC_EXCLUSIVE_EN)) + return 1; + return 0; +} + +void llc_save(void) +{ + /* TBD */ +} + +void llc_resume(void) +{ + /* TBD */ +} diff --git a/drivers/marvell/ccu.c b/drivers/marvell/ccu.c new file mode 100644 index 00000000..4edfeb8b --- /dev/null +++ b/drivers/marvell/ccu.c @@ -0,0 +1,266 @@ +/* +* *************************************************************************** +* 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 +#include +#include +#include +#include +#include + +#if LOG_LEVEL >= LOG_LEVEL_INFO +#define DEBUG_ADDR_MAP +#endif + +/* common defines */ +#define WIN_ENABLE_BIT (0x1) +/* Physical address of the base of the window = {AddrLow[19:0],20’h0} */ +#define ADDRESS_SHIFT (20 - 4) +#define ADDRESS_MASK (0xFFFFFFF0) +#define CCU_WIN_ALIGNMENT (0x100000) + +/* AP registers */ +#define CCU_MAX_WIN_NUM (8) +#define CCU_WIN_CR_OFFSET(win) (ccu_info->ccu_base + 0x0 + (0x10 * win)) +#define CCU_TARGET_ID_OFFSET (8) +#define CCU_TARGET_ID_MASK (0x7F) + +#define CCU_WIN_SCR_OFFSET(win) (ccu_info->ccu_base + 0x4 + (0x10 * win)) +#define CCU_WIN_ENA_WRITE_SECURE (0x1) +#define CCU_WIN_ENA_READ_SECURE (0x2) + +#define CCU_WIN_ALR_OFFSET(win) (ccu_info->ccu_base + 0x8 + (0x10 * win)) +#define CCU_WIN_AHR_OFFSET(win) (ccu_info->ccu_base + 0xC + (0x10 * win)) + +#define CCU_WIN_GCR_OFFSET (ccu_info->ccu_base + 0xD0) +#define CCU_GCR_TARGET_OFFSET (8) +#define CCU_GCR_TARGET_MASK (0xF) + + +struct ccu_configuration { + uintptr_t ccu_base; + uint32_t max_win; +}; + +struct ccu_configuration ccu_config; +struct ccu_configuration *ccu_info = &ccu_config; + +#ifdef DEBUG_ADDR_MAP +struct ccu_target_name_map { + enum ccu_target_ids trgt_id; + char name[10]; +}; + +struct ccu_target_name_map ccu_target_name_table[] = { + {IO_0_TID, "IO-0 "}, + {DRAM_0_TID, "DRAM-0 "}, + {IO_1_TID, "IO-1 "}, + {CFG_REG_TID, "CFG-REG"}, + {RAR_TID, "RAR "}, + {SRAM_TID, "SRAM "}, + {DRAM_1_TID, "DRAM-1 "}, + {INVALID_TID, "INVALID"}, +}; + +static char *ccu_target_name_get(enum ccu_target_ids trgt_id) +{ + int i; + + for (i = 0; i < CCU_MAX_TID; i++) + if (ccu_target_name_table[i].trgt_id == trgt_id) + return ccu_target_name_table[i].name; + return ccu_target_name_get(INVALID_TID); +} + +static void dump_ccu(void) +{ + uint32_t win_id, win_cr, alr, ahr; + uint8_t target_id; + uint64_t start, end; + + /* Dump all AP windows */ + printf("bank id target start end\n"); + printf("----------------------------------------------------\n"); + for (win_id = 0; win_id < ccu_info->max_win; win_id++) { + win_cr = mmio_read_32(CCU_WIN_CR_OFFSET(win_id)); + printf("Win %d: 0x%lx: 0x%x\n", win_id, CCU_WIN_CR_OFFSET(win_id), win_cr); + if (win_cr & WIN_ENABLE_BIT) { + printf("\tWin %d: Enabled\n", win_id); + target_id = (win_cr >> CCU_TARGET_ID_OFFSET) & CCU_TARGET_ID_MASK; + alr = mmio_read_32(CCU_WIN_ALR_OFFSET(win_id)); + ahr = mmio_read_32(CCU_WIN_AHR_OFFSET(win_id)); + start = ((uint64_t)alr << ADDRESS_SHIFT); + end = (((uint64_t)ahr + 0x10) << ADDRESS_SHIFT); + printf("ccu %02x %s 0x%016lx 0x%016lx\n" + , win_id, ccu_target_name_get(target_id), start, end); + } + } + win_cr = mmio_read_32(CCU_WIN_GCR_OFFSET); + target_id = (win_cr >> CCU_GCR_TARGET_OFFSET) & CCU_GCR_TARGET_MASK; + printf("ccu GCR %s - all other transactions\n", ccu_target_name_get(target_id)); + + return; +} +#endif + +static void ccu_win_check(struct ccu_win *win, uint32_t win_num) +{ + uint64_t start_addr, win_size; + + /* check if address is aligned to 1M */ + start_addr = ((uint64_t)win->base_addr_high << 32) + win->base_addr_low; + if (IS_NOT_ALIGN(start_addr, CCU_WIN_ALIGNMENT)) { + start_addr = ALIGN_UP(start_addr, CCU_WIN_ALIGNMENT); + ERROR("Window %d: base address unaligned to 0x%x\n", win_num, CCU_WIN_ALIGNMENT); + printf("Align up the base address to 0x%lx\n", start_addr); + win->base_addr_high = (uint32_t)(start_addr >> 32); + win->base_addr_low = (uint32_t)(start_addr); + } + + /* size parameter validity check */ + win_size = ((uint64_t)win->win_size_high << 32) + win->win_size_low; + if (IS_NOT_ALIGN(win_size, CCU_WIN_ALIGNMENT)) { + win_size = ALIGN_UP(win_size, CCU_WIN_ALIGNMENT); + ERROR("Window %d: window size unaligned to 0x%x\n", win_num, CCU_WIN_ALIGNMENT); + printf("Aligning size to 0x%lx\n", win_size); + win->win_size_high = (uint32_t)(win_size >> 32); + win->win_size_low = (uint32_t)(win_size); + } +} + +static void ccu_enable_win(struct ccu_win *win, uint32_t win_id) +{ + uint32_t ccu_win_reg; + uint32_t alr, ahr; + uint64_t start_addr, end_addr; + + start_addr = ((uint64_t)win->base_addr_high << 32) + win->base_addr_low; + end_addr = (start_addr + (((uint64_t)win->win_size_high << 32) + win->win_size_low) - 1); + alr = (uint32_t)((start_addr >> ADDRESS_SHIFT) & ADDRESS_MASK); + ahr = (uint32_t)((end_addr >> ADDRESS_SHIFT) & ADDRESS_MASK); + + mmio_write_32(CCU_WIN_ALR_OFFSET(win_id), alr); + mmio_write_32(CCU_WIN_AHR_OFFSET(win_id), ahr); + + ccu_win_reg = WIN_ENABLE_BIT; + ccu_win_reg |= (win->target_id & CCU_TARGET_ID_MASK) << CCU_TARGET_ID_OFFSET; + mmio_write_32(CCU_WIN_CR_OFFSET(win_id), ccu_win_reg); +} + +static int skip_ccu_window(uint32_t win_reg) +{ + uint8_t target_id; + + /* avoid overriding internal register and SRAM windows + At SPL stage BootROM open the SRAM window and close it + at the end of the SPL stage */ + if (win_reg & WIN_ENABLE_BIT) { + target_id = (win_reg >> CCU_TARGET_ID_OFFSET) & CCU_TARGET_ID_MASK; + if (((target_id) == SRAM_TID) || ((target_id) == CFG_REG_TID)) + return 1; + } + + return 0; +} + +int init_ccu(void) +{ + struct ccu_win *win; + uint32_t win_id, win_reg; + uint32_t win_count, array_id; + + INFO("Initializing CCU Address decoding\n"); + + /* Get the base address of the address decoding CCU */ + ccu_info->ccu_base = marvell_get_ccu_reg_offs(); + + /* Get the maximum number of CCU windows supported */ + ccu_info->max_win = marvell_get_ccu_max_win(); + if ((ccu_info->max_win == 0) || (ccu_info->max_win > CCU_MAX_WIN_NUM)) { + ccu_info->max_win = CCU_MAX_WIN_NUM; + ERROR("failed reading max windows number, set window max size to %d\n", ccu_info->max_win); + } + + /* Get the array of the windows and fill the map data */ + marvell_get_ccu_memory_map(&win, &win_count); + if (win_count <= 0) { + INFO("no windows configurations found\n"); + return 0; + } + + /* Set the default target ID to DRAM 0 */ + win_reg = (DRAM_0_TID & CCU_GCR_TARGET_MASK) << CCU_GCR_TARGET_OFFSET; + mmio_write_32(CCU_WIN_GCR_OFFSET, win_reg); + + /* disable AP windows */ + for (win_id = 0; win_id < ccu_info->max_win; win_id++) { + win_reg = mmio_read_32(CCU_WIN_CR_OFFSET(win_id)); + if (skip_ccu_window(win_reg)) + continue; + + win_reg &= ~WIN_ENABLE_BIT; + mmio_write_32(CCU_WIN_CR_OFFSET(win_id), win_reg); + + /* enable write secure (and clear read secure) */ + win_reg = CCU_WIN_ENA_WRITE_SECURE; + mmio_write_32(CCU_WIN_SCR_OFFSET(win_id), win_reg); + } + + for (win_id = 0, array_id = 0; + ((win_id < ccu_info->max_win) && (array_id < win_count)); win_id++) { + /* win_id is the index of the current ccu window + array_id is the index of the current FDT window entry */ + + win_reg = mmio_read_32(CCU_WIN_CR_OFFSET(win_id)); + if (skip_ccu_window(win_reg)) + continue; + + ccu_win_check(win, win_id); + ccu_enable_win(win, win_id); + + win++; + array_id++; + } + + if (array_id != win_count) + ERROR("Set only %d CCU windows. expected %d", array_id, win_count); + +#ifdef DEBUG_ADDR_MAP + dump_ccu(); +#endif + + INFO("Done CCU Address decoding Initializing\n"); + + return 0; +} diff --git a/drivers/marvell/comphy.h b/drivers/marvell/comphy.h new file mode 100644 index 00000000..67807c49 --- /dev/null +++ b/drivers/marvell/comphy.h @@ -0,0 +1,390 @@ +/* +* *************************************************************************** +* 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. +* +*************************************************************************** +*/ + +#ifndef _COMPHY_H_ +#define _COMPHY_H_ + +/* COMPHY registers */ +#define COMMON_PHY_CFG1_REG 0x0 +#define COMMON_PHY_CFG1_PWR_UP_OFFSET 1 +#define COMMON_PHY_CFG1_PWR_UP_MASK (0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET) +#define COMMON_PHY_CFG1_PIPE_SELECT_OFFSET 2 +#define COMMON_PHY_CFG1_PIPE_SELECT_MASK (0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET) +#define COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET 13 +#define COMMON_PHY_CFG1_PWR_ON_RESET_MASK (0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET) +#define COMMON_PHY_CFG1_CORE_RSTN_OFFSET 14 +#define COMMON_PHY_CFG1_CORE_RSTN_MASK (0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET) +#define COMMON_PHY_PHY_MODE_OFFSET 15 +#define COMMON_PHY_PHY_MODE_MASK (0x1 << COMMON_PHY_PHY_MODE_OFFSET) + +#define COMMON_PHY_CFG6_REG 0x14 +#define COMMON_PHY_CFG6_IF_40_SEL_OFFSET 18 +#define COMMON_PHY_CFG6_IF_40_SEL_MASK (0x1 << COMMON_PHY_CFG6_IF_40_SEL_OFFSET) + +#define COMMON_SELECTOR_PHY_OFFSET 0x140 +#define COMMON_SELECTOR_PIPE_OFFSET 0x144 + +#define COMMON_PHY_SD_CTRL1 0x148 +#define COMMON_PHY_SD_CTRL1_COMPHY_0_4_PORT_OFFSET 0 +#define COMMON_PHY_SD_CTRL1_COMPHY_0_4_PORT_MASK 0xFFFF +#define COMMON_PHY_SD_CTRL1_PCIE_X4_EN_OFFSET 24 +#define COMMON_PHY_SD_CTRL1_PCIE_X4_EN_MASK (0x1 << COMMON_PHY_SD_CTRL1_PCIE_X4_EN_OFFSET) +#define COMMON_PHY_SD_CTRL1_PCIE_X2_EN_OFFSET 25 +#define COMMON_PHY_SD_CTRL1_PCIE_X2_EN_MASK (0x1 << COMMON_PHY_SD_CTRL1_PCIE_X2_EN_OFFSET) +#define COMMON_PHY_SD_CTRL1_RXAUI1_OFFSET 26 +#define COMMON_PHY_SD_CTRL1_RXAUI1_MASK (0x1 << COMMON_PHY_SD_CTRL1_RXAUI1_OFFSET) +#define COMMON_PHY_SD_CTRL1_RXAUI0_OFFSET 27 +#define COMMON_PHY_SD_CTRL1_RXAUI0_MASK (0x1 << COMMON_PHY_SD_CTRL1_RXAUI0_OFFSET) + +#define DFX_DEV_GEN_CTRL12 0x80 +#define DFX_DEV_GEN_PCIE_CLK_SRC_OFFSET 7 +#define DFX_DEV_GEN_PCIE_CLK_SRC_MASK (0x3 << DFX_DEV_GEN_PCIE_CLK_SRC_OFFSET) + +#define MAX_LANE_OPTIONS 10 +#define MAX_UTMI_PHY_COUNT 3 + + +/* SerDes IP register */ +#define SD_EXTERNAL_CONFIG0_REG 0 +#define SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET 1 +#define SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK (1 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET) +#define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET 3 +#define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK (0xf << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET) +#define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET 7 +#define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK (0xf << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET) +#define SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET 11 +#define SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK (1 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET) +#define SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET 12 +#define SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK (1 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET) +#define SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET 14 +#define SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK (1 << SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET) +#define SD_EXTERNAL_CONFIG0_MEDIA_MODE_OFFSET 15 +#define SD_EXTERNAL_CONFIG0_MEDIA_MODE_MASK (0x1 << SD_EXTERNAL_CONFIG0_MEDIA_MODE_OFFSET) + +#define SD_EXTERNAL_CONFIG1_REG 0x4 +#define SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET 3 +#define SD_EXTERNAL_CONFIG1_RESET_IN_MASK (0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET) +#define SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET 4 +#define SD_EXTERNAL_CONFIG1_RX_INIT_MASK (0x1 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET) +#define SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET 5 +#define SD_EXTERNAL_CONFIG1_RESET_CORE_MASK (0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET) +#define SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET 6 +#define SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK (0x1 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET) + +#define SD_EXTERNAL_CONFIG2_REG 0x8 +#define SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET 4 +#define SD_EXTERNAL_CONFIG2_PIN_DFE_EN_MASK (0x1 << SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET) + +#define SD_EXTERNAL_STATUS0_REG 0x18 +#define SD_EXTERNAL_STATUS0_PLL_TX_OFFSET 2 +#define SD_EXTERNAL_STATUS0_PLL_TX_MASK (0x1 << SD_EXTERNAL_STATUS0_PLL_TX_OFFSET) +#define SD_EXTERNAL_STATUS0_PLL_RX_OFFSET 3 +#define SD_EXTERNAL_STATUS0_PLL_RX_MASK (0x1 << SD_EXTERNAL_STATUS0_PLL_RX_OFFSET) +#define SD_EXTERNAL_STATUS0_RX_INIT_OFFSET 4 +#define SD_EXTERNAL_STATUS0_RX_INIT_MASK (0x1 << SD_EXTERNAL_STATUS0_RX_INIT_OFFSET) +#define SD_EXTERNAL_STATUS0_RF_RESET_IN_OFFSET 6 +#define SD_EXTERNAL_STATUS0_RF_RESET_IN_MASK (0x1 << SD_EXTERNAL_STATUS0_RF_RESET_IN_OFFSET) + +/* HPIPE register */ +#define HPIPE_PWR_PLL_REG 0x4 +#define HPIPE_PWR_PLL_REF_FREQ_OFFSET 0 +#define HPIPE_PWR_PLL_REF_FREQ_MASK (0x1f << HPIPE_PWR_PLL_REF_FREQ_OFFSET) +#define HPIPE_PWR_PLL_PHY_MODE_OFFSET 5 +#define HPIPE_PWR_PLL_PHY_MODE_MASK (0x7 << HPIPE_PWR_PLL_PHY_MODE_OFFSET) + +#define HPIPE_KVCO_CALIB_CTRL_REG 0x8 +#define HPIPE_KVCO_CALIB_CTRL_MAX_PLL_OFFSET 12 +#define HPIPE_KVCO_CALIB_CTRL_MAX_PLL_MASK (0x1 << HPIPE_KVCO_CALIB_CTRL_MAX_PLL_OFFSET) + +#define HPIPE_CAL_REG1_REG 0xc +#define HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET 10 +#define HPIPE_CAL_REG_1_EXT_TXIMP_MASK (0x1f << HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET) +#define HPIPE_CAL_REG_1_EXT_TXIMP_EN_OFFSET 15 +#define HPIPE_CAL_REG_1_EXT_TXIMP_EN_MASK (0x1 << HPIPE_CAL_REG_1_EXT_TXIMP_EN_OFFSET) + +#define HPIPE_SQUELCH_FFE_SETTING_REG 0x018 + +#define HPIPE_DFE_REG0 0x01C +#define HPIPE_DFE_RES_FORCE_OFFSET 15 +#define HPIPE_DFE_RES_FORCE_MASK (0x1 << HPIPE_DFE_RES_FORCE_OFFSET) + +#define HPIPE_DFE_F3_F5_REG 0x028 +#define HPIPE_DFE_F3_F5_DFE_EN_OFFSET 14 +#define HPIPE_DFE_F3_F5_DFE_EN_MASK (0x1 << HPIPE_DFE_F3_F5_DFE_EN_OFFSET) +#define HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET 15 +#define HPIPE_DFE_F3_F5_DFE_CTRL_MASK (0x1 << HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET) + +#define HPIPE_G1_SET_0_REG 0x034 +#define HPIPE_G1_SET_0_G1_TX_AMP_OFFSET 1 +#define HPIPE_G1_SET_0_G1_TX_AMP_MASK (0x1f << HPIPE_G1_SET_0_G1_TX_AMP_OFFSET) +#define HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET 7 +#define HPIPE_G1_SET_0_G1_TX_EMPH1_MASK (0xf << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET) + +#define HPIPE_G1_SET_1_REG 0x038 +#define HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET 0 +#define HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK (0x7 << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET) +#define HPIPE_G1_SET_1_G1_RX_SELMUPP_OFFSET 3 +#define HPIPE_G1_SET_1_G1_RX_SELMUPP_MASK (0x7 << HPIPE_G1_SET_1_G1_RX_SELMUPP_OFFSET) +#define HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET 10 +#define HPIPE_G1_SET_1_G1_RX_DFE_EN_MASK (0x1 << HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET) + +#define HPIPE_G2_SETTINGS_1_REG 0x040 + +#define HPIPE_G3_SETTINGS_1_REG 0x048 +#define HPIPE_G3_RX_SELMUPI_OFFSET 0 +#define HPIPE_G3_RX_SELMUPI_MASK (0x7 << HPIPE_G3_RX_SELMUPI_OFFSET) +#define HPIPE_G3_RX_SELMUPF_OFFSET 3 +#define HPIPE_G3_RX_SELMUPF_MASK (0x7 << HPIPE_G3_RX_SELMUPF_OFFSET) +#define HPIPE_G3_SETTING_BIT_OFFSET 13 +#define HPIPE_G3_SETTING_BIT_MASK (0x1 << HPIPE_G3_SETTING_BIT_OFFSET) + +#define HPIPE_LOOPBACK_REG 0x08c +#define HPIPE_LOOPBACK_SEL_OFFSET 1 +#define HPIPE_LOOPBACK_SEL_MASK (0x7 << HPIPE_LOOPBACK_SEL_OFFSET) + +#define HPIPE_SYNC_PATTERN_REG 0x090 + +#define HPIPE_INTERFACE_REG 0x94 +#define HPIPE_INTERFACE_GEN_MAX_OFFSET 10 +#define HPIPE_INTERFACE_GEN_MAX_MASK (0x3 << HPIPE_INTERFACE_GEN_MAX_OFFSET) +#define HPIPE_INTERFACE_LINK_TRAIN_OFFSET 14 +#define HPIPE_INTERFACE_LINK_TRAIN_MASK (0x1 << HPIPE_INTERFACE_LINK_TRAIN_OFFSET) + +#define HPIPE_ISOLATE_MODE_REG 0x98 +#define HPIPE_ISOLATE_MODE_GEN_RX_OFFSET 0 +#define HPIPE_ISOLATE_MODE_GEN_RX_MASK (0xf << HPIPE_ISOLATE_MODE_GEN_RX_OFFSET) +#define HPIPE_ISOLATE_MODE_GEN_TX_OFFSET 4 +#define HPIPE_ISOLATE_MODE_GEN_TX_MASK (0xf << HPIPE_ISOLATE_MODE_GEN_TX_OFFSET) + +#define HPIPE_G1_SET_2_REG 0xf4 +#define HPIPE_G1_SET_2_G1_TX_EMPH0_OFFSET 0 +#define HPIPE_G1_SET_2_G1_TX_EMPH0_MASK (0xf << HPIPE_G1_SET_2_G1_TX_EMPH0_OFFSET) +#define HPIPE_G1_SET_2_G1_TX_EMPH0_EN_OFFSET 4 +#define HPIPE_G1_SET_2_G1_TX_EMPH0_EN_MASK (0x1 << HPIPE_G1_SET_2_G1_TX_EMPH0_MASK) + +#define HPIPE_VTHIMPCAL_CTRL_REG 0x104 + +#define HPIPE_PCIE_REG0 0x120 +#define HPIPE_PCIE_IDLE_SYNC_OFFSET 12 +#define HPIPE_PCIE_IDLE_SYNC_MASK (0x1 << HPIPE_PCIE_IDLE_SYNC_OFFSET) +#define HPIPE_PCIE_SEL_BITS_OFFSET 13 +#define HPIPE_PCIE_SEL_BITS_MASK (0x3 << HPIPE_PCIE_SEL_BITS_OFFSET) + +#define HPIPE_LANE_ALIGN_REG 0x124 +#define HPIPE_LANE_ALIGN_OFF_OFFSET 12 +#define HPIPE_LANE_ALIGN_OFF_MASK (0x1 << HPIPE_LANE_ALIGN_OFF_OFFSET) + +#define HPIPE_MISC_REG 0x13C +#define HPIPE_MISC_CLK100M_125M_OFFSET 4 +#define HPIPE_MISC_CLK100M_125M_MASK (0x1 << HPIPE_MISC_CLK100M_125M_OFFSET) +#define HPIPE_MISC_ICP_FORCE_OFFSET 5 +#define HPIPE_MISC_ICP_FORCE_MASK (0x1 << HPIPE_MISC_ICP_FORCE_OFFSET) +#define HPIPE_MISC_TXDCLK_2X_OFFSET 6 +#define HPIPE_MISC_TXDCLK_2X_MASK (0x1 << HPIPE_MISC_TXDCLK_2X_OFFSET) +#define HPIPE_MISC_CLK500_EN_OFFSET 7 +#define HPIPE_MISC_CLK500_EN_MASK (0x1 << HPIPE_MISC_CLK500_EN_OFFSET) +#define HPIPE_MISC_REFCLK_SEL_OFFSET 10 +#define HPIPE_MISC_REFCLK_SEL_MASK (0x1 << HPIPE_MISC_REFCLK_SEL_OFFSET) + +#define HPIPE_RX_CONTROL_1_REG 0x140 +#define HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET 11 +#define HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK (0x1 << HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET) +#define HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET 12 +#define HPIPE_RX_CONTROL_1_CLK8T_EN_MASK (0x1 << HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET) + +#define HPIPE_PWR_CTR_REG 0x148 +#define HPIPE_PWR_CTR_RST_DFE_OFFSET 0 +#define HPIPE_PWR_CTR_RST_DFE_MASK (0x1 << HPIPE_PWR_CTR_RST_DFE_OFFSET) +#define HPIPE_PWR_CTR_SFT_RST_OFFSET 10 +#define HPIPE_PWR_CTR_SFT_RST_MASK (0x1 << HPIPE_PWR_CTR_SFT_RST_OFFSET) + +#define HPIPE_PLLINTP_REG1 0x150 + +#define HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG 0x16C +#define HPIPE_SMAPLER_OFFSET 12 +#define HPIPE_SMAPLER_MASK (0x1 << HPIPE_SMAPLER_OFFSET) + +#define HPIPE_TX_REG1_REG 0x174 +#define HPIPE_TX_REG1_TX_EMPH_RES_OFFSET 5 +#define HPIPE_TX_REG1_TX_EMPH_RES_MASK (0x3 << HPIPE_TX_REG1_TX_EMPH_RES_OFFSET) +#define HPIPE_TX_REG1_SLC_EN_OFFSET 10 +#define HPIPE_TX_REG1_SLC_EN_MASK (0x3f << HPIPE_TX_REG1_SLC_EN_OFFSET) + +#define HPIPE_PWR_CTR_DTL_REG 0x184 +#define HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET 2 +#define HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK (0x1 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET) + +#define HPIPE_RX_REG3 0x188 + +#define HPIPE_TX_TRAIN_CTRL_0_REG 0x268 +#define HPIPE_TX_TRAIN_P2P_HOLD_OFFSET 15 +#define HPIPE_TX_TRAIN_P2P_HOLD_MASK (0x1 << HPIPE_TX_TRAIN_P2P_HOLD_OFFSET) + +#define HPIPE_TX_TRAIN_CTRL_REG 0x26C +#define HPIPE_TX_TRAIN_CTRL_G1_OFFSET 0 +#define HPIPE_TX_TRAIN_CTRL_G1_MASK (0x1 << HPIPE_TX_TRAIN_CTRL_G1_OFFSET) +#define HPIPE_TX_TRAIN_CTRL_GN1_OFFSET 1 +#define HPIPE_TX_TRAIN_CTRL_GN1_MASK (0x1 << HPIPE_TX_TRAIN_CTRL_GN1_OFFSET) +#define HPIPE_TX_TRAIN_CTRL_G0_OFFSET 2 +#define HPIPE_TX_TRAIN_CTRL_G0_MASK (0x1 << HPIPE_TX_TRAIN_CTRL_G0_OFFSET) + +#define HPIPE_TX_TRAIN_CTRL_4_REG 0x278 +#define HPIPE_TRX_TRAIN_TIMER_OFFSET 0 +#define HPIPE_TRX_TRAIN_TIMER_MASK (0x3FF << HPIPE_TRX_TRAIN_TIMER_OFFSET) + +#define HPIPE_PCIE_REG1 0x288 +#define HPIPE_PCIE_REG3 0x290 + +#define HPIPE_TX_TRAIN_CTRL_5_REG 0x2A4 +#define HPIPE_TX_TRAIN_START_SQ_EN_OFFSET 11 +#define HPIPE_TX_TRAIN_START_SQ_EN_MASK (0x1 << HPIPE_TX_TRAIN_START_SQ_EN_OFFSET) +#define HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET 12 +#define HPIPE_TX_TRAIN_START_FRM_DET_EN_MASK (0x1 << HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET) +#define HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET 13 +#define HPIPE_TX_TRAIN_START_FRM_LOCK_EN_MASK (0x1 << HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET) +#define HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET 14 +#define HPIPE_TX_TRAIN_WAIT_TIME_EN_MASK (0x1 << HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET) + +#define HPIPE_TX_TRAIN_REG 0x31C +#define HPIPE_TX_TRAIN_CHK_INIT_OFFSET 4 +#define HPIPE_TX_TRAIN_CHK_INIT_MASK (0x1 << HPIPE_TX_TRAIN_CHK_INIT_OFFSET) +#define HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET 7 +#define HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_MASK (0x1 << HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET) + +#define HPIPE_TX_TRAIN_CTRL_11_REG 0x438 +#define HPIPE_TX_STATUS_CHECK_MODE_OFFSET 6 +#define HPIPE_TX_TX_STATUS_CHECK_MODE_MASK (0x1 << HPIPE_TX_STATUS_CHECK_MODE_OFFSET) +#define HPIPE_TX_NUM_OF_PRESET_OFFSET 10 +#define HPIPE_TX_NUM_OF_PRESET_MASK (0x7 << HPIPE_TX_NUM_OF_PRESET_OFFSET) +#define HPIPE_TX_SWEEP_PRESET_EN_OFFSET 15 +#define HPIPE_TX_SWEEP_PRESET_EN_MASK (0x1 << HPIPE_TX_SWEEP_PRESET_EN_OFFSET) + +#define HPIPE_G1_SETTINGS_3_REG 0x440 +#define HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_OFFSET 9 +#define HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_MASK (0x1 << HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_OFFSET) + +#define HPIPE_G1_SETTINGS_4_REG 0x444 +#define HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET 8 +#define HPIPE_G1_SETTINGS_4_G1_DFE_RES_MASK (0x3 << HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET) + +#define HPIPE_G2_SETTINGS_3_REG 0x448 +#define HPIPE_G2_SETTINGS_4_REG 0x44C + +#define HPIPE_G3_SETTING_3_REG 0x450 +#define HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET 12 +#define HPIPE_G3_FFE_DEG_RES_LEVEL_MASK (0x3 << HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET) +#define HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET 14 +#define HPIPE_G3_FFE_LOAD_RES_LEVEL_MASK (0x3 << HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET) + +#define HPIPE_G3_SETTING_4_REG 0x454 +#define HPIPE_G3_DFE_RES_OFFSET 8 +#define HPIPE_G3_DFE_RES_MASK (0x3 << HPIPE_G3_DFE_RES_OFFSET) + +#define HPIPE_DFE_CTRL_28_REG 0x49C +#define HPIPE_DFE_CTRL_28_PIPE4_OFFSET 7 +#define HPIPE_DFE_CTRL_28_PIPE4_MASK (0x1 << HPIPE_DFE_CTRL_28_PIPE4_OFFSET) + +#define HPIPE_G1_SETTING_5_REG 0x538 +#define HPIPE_G1_SETTING_5_G1_ICP_OFFSET 0 +#define HPIPE_G1_SETTING_5_G1_ICP_MASK (0xf << HPIPE_G1_SETTING_5_G1_ICP_OFFSET) + +#define HPIPE_LANE_CONFIG0_REG 0x600 +#define HPIPE_LANE_CONFIG0_TXDEEMPH0_OFFSET 0 +#define HPIPE_LANE_CONFIG0_TXDEEMPH0_MASK (0x1 << HPIPE_LANE_CONFIG0_TXDEEMPH0_OFFSET) + +#define HPIPE_LANE_CONFIG1_REG 0x604 +#define HPIPE_LANE_CONFIG1_MAX_PLL_OFFSET 9 +#define HPIPE_LANE_CONFIG1_MAX_PLL_MASK (0x1 << HPIPE_LANE_CONFIG1_MAX_PLL_OFFSET) +#define HPIPE_LANE_CONFIG1_GEN2_PLL_OFFSET 10 +#define HPIPE_LANE_CONFIG1_GEN2_PLL_MASK (0x1 << HPIPE_LANE_CONFIG1_GEN2_PLL_OFFSET) + +#define HPIPE_LANE_STATUS1_REG 0x60C +#define HPIPE_LANE_STATUS1_PCLK_EN_OFFSET 0 +#define HPIPE_LANE_STATUS1_PCLK_EN_MASK (0x1 << HPIPE_LANE_STATUS1_PCLK_EN_OFFSET) + +#define HPIPE_LANE_CFG4_REG 0x620 +#define HPIPE_LANE_CFG4_DFE_CTRL_OFFSET 0 +#define HPIPE_LANE_CFG4_DFE_CTRL_MASK (0x7 << HPIPE_LANE_CFG4_DFE_CTRL_OFFSET) +#define HPIPE_LANE_CFG4_DFE_OVER_OFFSET 6 +#define HPIPE_LANE_CFG4_DFE_OVER_MASK (0x1 << HPIPE_LANE_CFG4_DFE_OVER_OFFSET) +#define HPIPE_LANE_CFG4_SSC_CTRL_OFFSET 7 +#define HPIPE_LANE_CFG4_SSC_CTRL_MASK (0x1 << HPIPE_LANE_CFG4_SSC_CTRL_OFFSET) + +#define HPIPE_LANE_EQU_CONFIG_0_REG 0x69C +#define HPIPE_CFG_PHY_RC_EP_OFFSET 12 +#define HPIPE_CFG_PHY_RC_EP_MASK (0x1 << HPIPE_CFG_PHY_RC_EP_OFFSET) + +#define HPIPE_LANE_EQ_CFG1_REG 0x6a0 +#define HPIPE_CFG_UPDATE_POLARITY_OFFSET 12 +#define HPIPE_CFG_UPDATE_POLARITY_MASK (0x1 << HPIPE_CFG_UPDATE_POLARITY_OFFSET) + +#define HPIPE_RST_CLK_CTRL_REG 0x704 +#define HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET 0 +#define HPIPE_RST_CLK_CTRL_PIPE_RST_MASK (0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET) +#define HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET 2 +#define HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK (0x1 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET) +#define HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET 3 +#define HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK (0x1 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET) +#define HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET 9 +#define HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK (0x1 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET) + +#define HPIPE_TST_MODE_CTRL_REG 0x708 +#define HPIPE_TST_MODE_CTRL_MODE_MARGIN_OFFSET 2 +#define HPIPE_TST_MODE_CTRL_MODE_MARGIN_MASK (0x1 << HPIPE_TST_MODE_CTRL_MODE_MARGIN_OFFSET) + +#define HPIPE_CLK_SRC_LO_REG 0x70c +#define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_OFFSET 1 +#define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_MASK (0x1 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_OFFSET) +#define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_OFFSET 2 +#define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_MASK (0x3 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_OFFSET) +#define HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET 5 +#define HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK (0x7 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET) + +#define HPIPE_CLK_SRC_HI_REG 0x710 +#define HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET 0 +#define HPIPE_CLK_SRC_HI_LANE_STRT_MASK (0x1 << HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET) +#define HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET 1 +#define HPIPE_CLK_SRC_HI_LANE_BREAK_MASK (0x1 << HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET) +#define HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET 2 +#define HPIPE_CLK_SRC_HI_LANE_MASTER_MASK (0x1 << HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET) +#define HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET 7 +#define HPIPE_CLK_SRC_HI_MODE_PIPE_MASK (0x1 << HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET) + +#define HPIPE_GLOBAL_MISC_CTRL 0x718 +#define HPIPE_GLOBAL_PM_CTRL 0x740 +#define HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET 0 +#define HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK (0xFF << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET) + +#endif /* _COMPHY_H_ */ + diff --git a/drivers/marvell/dw-pcie-ep.c b/drivers/marvell/dw-pcie-ep.c new file mode 100644 index 00000000..ed8e72e2 --- /dev/null +++ b/drivers/marvell/dw-pcie-ep.c @@ -0,0 +1,178 @@ +/* +* *************************************************************************** +* 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 +#include + +#define PCIE_CFG_VENDOR 0x0 +#define PCIE_CFG_DEVICE 0x2 +#define PCIE_CFG_CMD 0x4 +#define PCIE_CFG_CMD_IO_EN (1 << 0) +#define PCIE_CFG_CMD_MEM_EN (1 << 1) +#define PCIE_CFG_CMD_MASTER_EN (1 << 2) +#define PCIE_CFG_STATUS 0x6 + +#define PCIE_GLOBAL_CONTROL 0x8000 +#define PCIE_CFG_RETRY_EN (1 << 9) +#define PCIE_APP_LTSSM_EN (1 << 2) +#define PCIE_DEVICE_TYPE_OFFSET (4) +#define PCIE_DEVICE_TYPE_MASK (0xF) +#define PCIE_DEVICE_TYPE_EP (0x0) /* Endpoint */ +#define PCIE_DEVICE_TYPE_LEP (0x1) /* Legacy endpoint */ +#define PCIE_DEVICE_TYPE_RC (0x4) /* Root complex */ + +#define PCIE_LINK_CTL_2 0xA0 +#define TARGET_LINK_SPEED_MASK 0xF +#define PCIE_LINK_CAPABILITY 0x7C + +#define PCIE_GEN3_EQU_CTRL 0x8A8 +#define GEN3_EQU_EVAL_2MS_DISABLE (1 << 5) + +#define PCIE_ARCACHE_TRC 0x8050 +#define PCIE_AWCACHE_TRC 0x8054 +#define ARCACHE_SHAREABLE_CACHEABLE 0x3511 +#define AWCACHE_SHAREABLE_CACHEABLE 0x5311 + +#define LINK_SPEED_GEN_1 0x1 +#define LINK_SPEED_GEN_2 0x2 +#define LINK_SPEED_GEN_3 0x3 + +/* iATU registers */ +#define PCIE_IATU_VIEWPORT 0x900 +#define PCIE_IATU_CR1 0x904 +#define PCIE_IATU_CR2 0x908 +#define PCIE_IATU_CR2_EN (0x1 << 31) +#define PCIE_IATU_LOWER_BASE 0x90C +#define PCIE_IATU_UPPER_BASE 0x910 +#define PCIE_IATU_LIMIT 0x914 +#define PCIE_IATU_LOWER_TARGET 0x918 +#define PCIE_IATU_UPPER_TARGET 0x91C + +#define DW_OUTBOUND_ATU_BASE 0x8000000000ull +#define DW_OUTBOUND_ATU_SIZE 0x100000000ull +#define DW_OUTBOUND_ATU_TARGET 0x0 + + +void dw_pcie_configure(uintptr_t regs_base, uint32_t cap_speed) +{ + uint32_t reg; + + /* Set link to GEN 3 */; + reg = mmio_read_32(regs_base + PCIE_LINK_CTL_2); + reg &= ~TARGET_LINK_SPEED_MASK; + reg |= cap_speed; + mmio_write_32(regs_base + PCIE_LINK_CTL_2, reg); + + reg = mmio_read_32(regs_base + PCIE_LINK_CAPABILITY); + reg &= ~TARGET_LINK_SPEED_MASK; + reg |= cap_speed; + mmio_write_32(regs_base + PCIE_LINK_CAPABILITY, reg); + + reg = mmio_read_32(regs_base + PCIE_GEN3_EQU_CTRL); + reg |= GEN3_EQU_EVAL_2MS_DISABLE; + mmio_write_32(regs_base + PCIE_GEN3_EQU_CTRL, reg); +} + +int dw_pcie_link_up(uintptr_t regs_base, uint32_t cap_speed, int is_end_point) +{ + uint32_t reg; + + /* Disable LTSSM state machine to enable configuration */ + reg = mmio_read_32(regs_base + PCIE_GLOBAL_CONTROL); + reg &= ~(PCIE_APP_LTSSM_EN); + reg &= ~(PCIE_DEVICE_TYPE_MASK << PCIE_DEVICE_TYPE_OFFSET); + if (!is_end_point) + reg |= (PCIE_DEVICE_TYPE_RC << PCIE_DEVICE_TYPE_OFFSET); + mmio_write_32(regs_base + PCIE_GLOBAL_CONTROL, reg); + + /* Set the PCIe master AXI attributes */ + mmio_write_32(regs_base + PCIE_ARCACHE_TRC, ARCACHE_SHAREABLE_CACHEABLE); + mmio_write_32(regs_base + PCIE_AWCACHE_TRC, AWCACHE_SHAREABLE_CACHEABLE); + + /* DW pre link configurations */ + dw_pcie_configure(regs_base, cap_speed); + + /* Configuration done. Start LTSSM */ + reg = mmio_read_32(regs_base + PCIE_GLOBAL_CONTROL); + reg |= PCIE_APP_LTSSM_EN; + mmio_write_32(regs_base + PCIE_GLOBAL_CONTROL, reg); + + /* As the end-point we dont need to check if a + * link was established*/ + + return 1; +} + +void dw_pcie_open_out_atu(uintptr_t dw_base, int win_id, uint64_t local_base, + uint64_t remote_base, uint64_t size) +{ + mmio_write_32(dw_base + PCIE_IATU_VIEWPORT, win_id); + mmio_write_32(dw_base + PCIE_IATU_LOWER_BASE, local_base & UINT32_MAX); + mmio_write_32(dw_base + PCIE_IATU_UPPER_BASE, local_base >> 32); + mmio_write_32(dw_base + PCIE_IATU_LOWER_TARGET, remote_base & UINT32_MAX); + mmio_write_32(dw_base + PCIE_IATU_UPPER_TARGET, remote_base >> 32); + mmio_write_32(dw_base + PCIE_IATU_LIMIT, size - 1); + mmio_write_32(dw_base + PCIE_IATU_CR2, PCIE_IATU_CR2_EN); +} + +void dw_pcie_master_enable(uintptr_t dw_base) +{ + mmio_write_32(dw_base + PCIE_CFG_CMD, PCIE_CFG_CMD_MEM_EN | + PCIE_CFG_CMD_IO_EN | + PCIE_CFG_CMD_MASTER_EN); +} + +void dw_pcie_delay_cfg(uintptr_t dw_base) +{ + uint32_t ctrl; + ctrl = mmio_read_32(dw_base + PCIE_GLOBAL_CONTROL); + ctrl |= PCIE_CFG_RETRY_EN; + mmio_write_32(dw_base + PCIE_GLOBAL_CONTROL, ctrl); +} + +void dw_pcie_ep_init(uintptr_t dw_base, uint8_t delay_cfg, uint8_t master_en) +{ + dw_pcie_link_up(dw_base, LINK_SPEED_GEN_3, 1); + + if (master_en) { + dw_pcie_open_out_atu(dw_base, 0, DW_OUTBOUND_ATU_BASE, + DW_OUTBOUND_ATU_TARGET, DW_OUTBOUND_ATU_SIZE); + dw_pcie_master_enable(dw_base); + } + + if (delay_cfg) + dw_pcie_delay_cfg(dw_base); + + return; +} diff --git a/drivers/marvell/i2c/a8k_i2c.c b/drivers/marvell/i2c/a8k_i2c.c new file mode 100644 index 00000000..1356fc07 --- /dev/null +++ b/drivers/marvell/i2c/a8k_i2c.c @@ -0,0 +1,563 @@ +/* +* *************************************************************************** +* 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. +* +*************************************************************************** +*/ + +/* This driver provides I2C support for A8K */ + +#include +#include +#include +#include +#include + +#if LOG_LEVEL >= LOG_LEVEL_VERBOSE +#define DEBUG_I2C +#endif + +#define CONFIG_SYS_TCLK 250000000 +#define CONFIG_SYS_I2C_SPEED 100000 +#define CONFIG_SYS_I2C_SLAVE 0x0 +#define I2C_TIMEOUT_VALUE 0x500 +#define I2C_MAX_RETRY_CNT 1000 +#define I2C_CMD_WRITE 0x0 +#define I2C_CMD_READ 0x1 + +#define I2C_DATA_ADDR_7BIT_OFFS 0x1 +#define I2C_DATA_ADDR_7BIT_MASK (0xFF << I2C_DATA_ADDR_7BIT_OFFS) + +#define I2C_CONTROL_ACK 0x00000004 +#define I2C_CONTROL_IFLG 0x00000008 +#define I2C_CONTROL_STOP 0x00000010 +#define I2C_CONTROL_START 0x00000020 +#define I2C_CONTROL_TWSIEN 0x00000040 +#define I2C_CONTROL_INTEN 0x00000080 + +#define I2C_STATUS_START 0x08 +#define I2C_STATUS_REPEATED_START 0x10 +#define I2C_STATUS_ADDR_W_ACK 0x18 +#define I2C_STATUS_DATA_W_ACK 0x28 +#define I2C_STATUS_LOST_ARB_DATA_ADDR_TRANSFER 0x38 +#define I2C_STATUS_ADDR_R_ACK 0x40 +#define I2C_STATUS_DATA_R_ACK 0x50 +#define I2C_STATUS_DATA_R_NAK 0x58 +#define I2C_STATUS_LOST_ARB_GENERAL_CALL 0x78 +#define I2C_STATUS_IDLE 0xF8 + +#define EPERM 1 /* Operation not permitted */ +#define EAGAIN 11 /* Try again */ +#define ETIMEDOUT 110 /* Connection timed out */ + +struct marvell_i2c_regs { + uint32_t slave_address; + uint32_t data; + uint32_t control; + union { + uint32_t status; /* when reading */ + uint32_t baudrate; /* when writing */ + } u; + uint32_t xtnd_slave_addr; + uint32_t reserved[2]; + uint32_t soft_reset; +}; + +static struct marvell_i2c_regs *base; + +static int marvell_i2c_lost_arbitration(uint32_t *status) +{ + *status = mmio_read_32((uintptr_t)&base->u.status); + if ((I2C_STATUS_LOST_ARB_DATA_ADDR_TRANSFER == *status) || (I2C_STATUS_LOST_ARB_GENERAL_CALL == *status)) + return -EAGAIN; + + return 0; +} + +static void marvell_i2c_interrupt_clear(void) +{ + uint32_t reg; + + /* Wait for 1 ms to prevent I2C register write after write issues */ + udelay(1000); + reg = mmio_read_32((uintptr_t)&base->control); + reg &= ~(I2C_CONTROL_IFLG); + mmio_write_32((uintptr_t)&base->control, reg); + /* Wait for 1 ms for the clear to take effect */ + udelay(1000); + + return; +} + +static int marvell_i2c_interrupt_get(void) +{ + uint32_t reg; + + /* get the interrupt flag bit */ + reg = mmio_read_32((uintptr_t)&base->control); + reg &= I2C_CONTROL_IFLG; + return reg && I2C_CONTROL_IFLG; +} + +static int marvell_i2c_wait_interrupt(void) +{ + uint32_t timeout = 0; + while (!marvell_i2c_interrupt_get() && (timeout++ < I2C_TIMEOUT_VALUE)) + ; + if (timeout >= I2C_TIMEOUT_VALUE) + return -ETIMEDOUT; + + return 0; +} + +static int marvell_i2c_start_bit_set(void) +{ + int is_int_flag = 0; + uint32_t status; + + if (marvell_i2c_interrupt_get()) + is_int_flag = 1; + + /* set start bit */ + mmio_write_32((uintptr_t)&base->control, mmio_read_32((uintptr_t)&base->control) | I2C_CONTROL_START); + + /* in case that the int flag was set before i.e. repeated start bit */ + if (is_int_flag) { + INFO("%s: repeated start Bit\n", __func__); + marvell_i2c_interrupt_clear(); + } + + if (marvell_i2c_wait_interrupt()) { + ERROR("Start clear bit timeout\n"); + return -ETIMEDOUT; + } + + /* check that start bit went down */ + if ((mmio_read_32((uintptr_t)&base->control) & I2C_CONTROL_START) != 0) { + ERROR("Start bit didn't went down\n"); + return -EPERM; + } + + /* check the status */ + if (marvell_i2c_lost_arbitration(&status)) { + INFO("%s - %d: Lost arbitration, got status %x\n", __func__, __LINE__, status); + return -EAGAIN; + } + if ((status != I2C_STATUS_START) && (status != I2C_STATUS_REPEATED_START)) { + ERROR("Got status %x after enable start bit.\n", status); + return -EPERM; + } + + return 0; +} + +static int marvell_i2c_stop_bit_set(void) +{ + int timeout; + uint32_t status; + + /* Generate stop bit */ + mmio_write_32((uintptr_t)&base->control, mmio_read_32((uintptr_t)&base->control) | I2C_CONTROL_STOP); + marvell_i2c_interrupt_clear(); + + timeout = 0; + /* Read control register, check the control stop bit */ + while ((mmio_read_32((uintptr_t)&base->control) & I2C_CONTROL_STOP) && (timeout++ < I2C_TIMEOUT_VALUE)) + ; + if (timeout >= I2C_TIMEOUT_VALUE) { + ERROR("Stop bit didn't went down\n"); + return -ETIMEDOUT; + } + + /* check that stop bit went down */ + if ((mmio_read_32((uintptr_t)&base->control) & I2C_CONTROL_STOP) != 0) { + ERROR("Stop bit didn't went down\n"); + return -EPERM; + } + + /* check the status */ + if (marvell_i2c_lost_arbitration(&status)) { + INFO("%s - %d: Lost arbitration, got status %x\n", __func__, __LINE__, status); + return -EAGAIN; + } + if (status != I2C_STATUS_IDLE) { + ERROR("Got status %x after enable stop bit.\n", status); + return -EPERM; + } + + return 0; +} + +static int marvell_i2c_address_set(uint8_t chain, int command) +{ + uint32_t reg, status; + + reg = (chain << I2C_DATA_ADDR_7BIT_OFFS) & I2C_DATA_ADDR_7BIT_MASK; + reg |= command; + mmio_write_32((uintptr_t)&base->data, reg); + udelay(1000); + + marvell_i2c_interrupt_clear(); + + if (marvell_i2c_wait_interrupt()) { + ERROR("Start clear bit timeout\n"); + return -ETIMEDOUT; + } + + /* check the status */ + if (marvell_i2c_lost_arbitration(&status)) { + INFO("%s - %d: Lost arbitration, got status %x\n", __func__, __LINE__, status); + return -EAGAIN; + } + if (((status != I2C_STATUS_ADDR_R_ACK) && (command == I2C_CMD_READ)) || + ((status != I2C_STATUS_ADDR_W_ACK) && (command == I2C_CMD_WRITE))) { + /* only in debug, since in boot we try to read the SPD of both DRAM, and we don't + want error messages in case DIMM doesn't exist. */ + INFO("%s: ERROR - status %x addr in %s mode.\n", __func__, status, (command == I2C_CMD_WRITE) ? + "Write" : "Read"); + return -EPERM; + } + + return 0; +} + +static unsigned int marvell_i2c_bus_speed_set(unsigned int requested_speed) +{ + unsigned int n, m, freq, margin, min_margin = 0xffffffff; + unsigned int actual_n = 0, actual_m = 0; + int val; + + /* Calucalte N and M for the TWSI clock baud rate */ + for (n = 0; n < 8; n++) { + for (m = 0; m < 16; m++) { + freq = CONFIG_SYS_TCLK / (10 * (m + 1) * (2 << n)); + val = requested_speed - freq; + margin = (val > 0) ? val : -val; + + if ((freq <= requested_speed) && (margin < min_margin)) { + min_margin = margin; + actual_n = n; + actual_m = m; + } + } + } + INFO("%s: actual_n = %u, actual_m = %u\n", __func__, actual_n, actual_m); + /* Set the baud rate */ + mmio_write_32((uintptr_t)&base->u.baudrate, (actual_m << 3) | actual_n); + + return 0; +} + +#ifdef DEBUG_I2C +static int marvell_i2c_probe(uint8_t chip) +{ + int ret = 0; + + ret = marvell_i2c_start_bit_set(); + if (ret != 0) { + marvell_i2c_stop_bit_set(); + ERROR("%s - %d: %s", __func__, __LINE__, "marvell_i2c_start_bit_set failed\n"); + return -EPERM; + } + + ret = marvell_i2c_address_set(chip, I2C_CMD_WRITE); + if (ret != 0) { + marvell_i2c_stop_bit_set(); + INFO("%s - %d: %s", __func__, __LINE__, "marvell_i2c_address_set failed\n"); + return -EPERM; + } + + marvell_i2c_stop_bit_set(); + + INFO("%s: successful I2C probe\n", __func__); + + return ret; +} +#endif + +/* regular i2c transaction */ +static int marvell_i2c_data_receive(uint8_t *p_block, uint32_t block_size) +{ + uint32_t reg, status, block_size_read = block_size; + + /* Wait for cause interrupt */ + if (marvell_i2c_wait_interrupt()) { + ERROR("Start clear bit timeout\n"); + return -ETIMEDOUT; + } + while (block_size_read) { + if (block_size_read == 1) { + reg = mmio_read_32((uintptr_t)&base->control); + reg &= ~(I2C_CONTROL_ACK); + mmio_write_32((uintptr_t)&base->control, reg); + } + marvell_i2c_interrupt_clear(); + + if (marvell_i2c_wait_interrupt()) { + ERROR("Start clear bit timeout\n"); + return -ETIMEDOUT; + } + /* check the status */ + if (marvell_i2c_lost_arbitration(&status)) { + INFO("%s - %d: Lost arbitration, got status %x\n", __func__, __LINE__, status); + return -EAGAIN; + } + if ((status != I2C_STATUS_DATA_R_ACK) && (block_size_read != 1)) { + ERROR("Status %x in read transaction\n", status); + return -EPERM; + } + if ((status != I2C_STATUS_DATA_R_NAK) && (block_size_read == 1)) { + ERROR("Status %x in Rd Terminate\n", status); + return -EPERM; + } + + /* read the data */ + *p_block = (uint8_t) mmio_read_32((uintptr_t)&base->data); + INFO("%s: place %d read %x\n", __func__, block_size - block_size_read, *p_block); + p_block++; + block_size_read--; + } + + return 0; +} + +static int marvell_i2c_data_transmit(uint8_t *p_block, uint32_t block_size) +{ + uint32_t status, block_size_write = block_size; + + if (marvell_i2c_wait_interrupt()) { + ERROR("Start clear bit timeout\n"); + return -ETIMEDOUT; + } + + while (block_size_write) { + /* write the data */ + mmio_write_32((uintptr_t)&base->data, (uint32_t) *p_block); + INFO("%s: index = %d, data = %x\n", __func__, block_size - block_size_write, *p_block); + p_block++; + block_size_write--; + + marvell_i2c_interrupt_clear(); + + if (marvell_i2c_wait_interrupt()) { + ERROR("Start clear bit timeout\n"); + return -ETIMEDOUT; + } + + /* check the status */ + if (marvell_i2c_lost_arbitration(&status)) { + INFO("%s - %d: Lost arbitration, got status %x\n", __func__, __LINE__, status); + return -EAGAIN; + } + if (status != I2C_STATUS_DATA_W_ACK) { + ERROR("Status %x in write transaction\n", status); + return -EPERM; + } + } + + return 0; +} + +static int marvell_i2c_target_offset_set(uint8_t chip, uint32_t addr, int alen) +{ + uint8_t off_block[2]; + uint32_t off_size; + + if (alen == 2) { /* 2-byte addresses support */ + off_block[0] = (addr >> 8) & 0xff; + off_block[1] = addr & 0xff; + off_size = 2; + } else { /* 1-byte addresses support */ + off_block[0] = addr & 0xff; + off_size = 1; + } + INFO("%s: off_size = %x addr1 = %x addr2 = %x\n", __func__, off_size, off_block[0], off_block[1]); + return marvell_i2c_data_transmit(off_block, off_size); +} + +/* ------------------------------------------------------------------------ */ +/* API Functions */ +/* ------------------------------------------------------------------------ */ +void i2c_init(void *i2c_base) +{ + /* For I2C speed and slave address, now we do not set them since + * we just provide the working speed and slave address in plat_def.h + * for i2c_init + */ + base = (struct marvell_i2c_regs *)i2c_base; + + /* Reset the I2C logic */ + mmio_write_32((uintptr_t)&base->soft_reset, 0); + + udelay(2000); + + marvell_i2c_bus_speed_set(CONFIG_SYS_I2C_SPEED); + + /* Enable the I2C and slave */ + mmio_write_32((uintptr_t)&base->control, I2C_CONTROL_TWSIEN | I2C_CONTROL_ACK); + + /* set the I2C slave address */ + mmio_write_32((uintptr_t)&base->xtnd_slave_addr, 0); + mmio_write_32((uintptr_t)&base->slave_address, CONFIG_SYS_I2C_SLAVE); + + /* unmask I2C interrupt */ + mmio_write_32((uintptr_t)&base->control, mmio_read_32((uintptr_t)&base->control) | I2C_CONTROL_INTEN); + + udelay(1000); +} + +/* + * i2c_read: - Read multiple bytes from an i2c device + * + * The higher level routines take into account that this function is only + * called with len < page length of the device (see configuration file) + * + * @chip: address of the chip which is to be read + * @addr: i2c data address within the chip + * @alen: length of the i2c data address (1..2 bytes) + * @buffer: where to write the data + * @len: how much byte do we want to read + * @return: 0 in case of success + */ +int i2c_read(uint8_t chip, uint32_t addr, int alen, uint8_t *buffer, int len) +{ + int ret = 0; + uint32_t counter = 0; + +#ifdef DEBUG_I2C + marvell_i2c_probe(chip); +#endif + + do { + if (ret != -EAGAIN && ret) { + ERROR("i2c transaction failed, after %d retries\n", counter); + marvell_i2c_stop_bit_set(); + return ret; + } + + /* wait for 1 ms for the interrupt clear to take effect */ + if (counter > 0) + udelay(1000); + counter++; + + ret = marvell_i2c_start_bit_set(); + if (ret) + continue; + + /* if EEPROM device */ + if (alen != 0) { + ret = marvell_i2c_address_set(chip, I2C_CMD_WRITE); + if (ret) + continue; + + ret = marvell_i2c_target_offset_set(chip, addr, alen); + if (ret) + continue; + ret = marvell_i2c_start_bit_set(); + if (ret) + continue; + } + + ret = marvell_i2c_address_set(chip, I2C_CMD_READ); + if (ret) + continue; + + ret = marvell_i2c_data_receive(buffer, len); + if (ret) + continue; + + ret = marvell_i2c_stop_bit_set(); + } while ((ret == -EAGAIN) && (counter < I2C_MAX_RETRY_CNT)); + + if (counter == I2C_MAX_RETRY_CNT) + ERROR("I2C transactions failed, got EAGAIN %d times\n", I2C_MAX_RETRY_CNT); + mmio_write_32((uintptr_t)&base->control, mmio_read_32((uintptr_t)&base->control) | I2C_CONTROL_ACK); + + udelay(1000); + return 0; +} + +/* + * i2c_write: - Write multiple bytes to an i2c device + * + * The higher level routines take into account that this function is only + * called with len < page length of the device (see configuration file) + * + * @chip: address of the chip which is to be written + * @addr: i2c data address within the chip + * @alen: length of the i2c data address (1..2 bytes) + * @buffer: where to find the data to be written + * @len: how much byte do we want to read + * @return: 0 in case of success + */ +int i2c_write(uint8_t chip, uint32_t addr, int alen, uint8_t *buffer, int len) +{ + int ret = 0; + uint32_t counter = 0; + + do { + if (ret != -EAGAIN && ret) { + ERROR("i2c transaction failed\n"); + marvell_i2c_stop_bit_set(); + return ret; + } + /* wait for 1 ms for the interrupt clear to take effect */ + if (counter > 0) + udelay(1000); + counter++; + + ret = marvell_i2c_start_bit_set(); + if (ret) + continue; + + ret = marvell_i2c_address_set(chip, I2C_CMD_WRITE); + if (ret) + continue; + + /* if EEPROM device */ + if (alen != 0) { + ret = marvell_i2c_target_offset_set(chip, addr, alen); + if (ret) + continue; + } + + ret = marvell_i2c_data_transmit(buffer, len); + if (ret) + continue; + + ret = marvell_i2c_stop_bit_set(); + } while ((ret == -EAGAIN) && (counter < I2C_MAX_RETRY_CNT)); + + if (counter == I2C_MAX_RETRY_CNT) + ERROR("I2C transactions failed, got EAGAIN %d times\n", I2C_MAX_RETRY_CNT); + + udelay(1000); + return 0; +} diff --git a/drivers/marvell/icu.c b/drivers/marvell/icu.c new file mode 100644 index 00000000..12e95048 --- /dev/null +++ b/drivers/marvell/icu.c @@ -0,0 +1,143 @@ +/* +* *************************************************************************** +* 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 +#include +#include + +#define ICU_SET_SPI_AL(x) (0x10 + (0x10 * x)) +#define ICU_SET_SPI_AH(x) (0x14 + (0x10 * x)) +#define ICU_CLR_SPI_AL(x) (0x18 + (0x10 * x)) +#define ICU_CLR_SPI_AH(x) (0x1c + (0x10 * x)) +#define ICU_INT_CFG(x) (0x100 + 4 * x) + +#define ICU_INT_ENABLE_OFFSET (24) +#define ICU_IS_EDGE_OFFSET (28) +#define ICU_GROUP_OFFSET (29) + +enum icu_group { + ICU_GRP_NSR = 0, + ICU_GRP_SR = 1, + ICU_GRP_LPI = 2, + ICU_GRP_VLPI = 3, + ICU_GRP_SEI = 4, + ICU_GRP_REI = 5, + ICU_GRP_MAX, +}; + +struct icu_msi { + enum icu_group group; + uintptr_t set_spi_addr; + uintptr_t clr_spi_addr; +}; + +#define MAX_ICU_IRQS 207 + +/* Allocate the MSI address per interrupt group, + * unsopprted groups get NULL address */ +static struct icu_msi msi_addr[] = { + {ICU_GRP_NSR, 0xf03f0040, 0xf03f0048}, /* Non secure interrupts*/ + {ICU_GRP_SR, 0, 0x0}, /* Secure interrupts */ + {ICU_GRP_LPI, 0x0, 0x0}, /* LPI interrupts */ + {ICU_GRP_VLPI, 0x0, 0x0}, /* Virtual LPI interrupts */ + {ICU_GRP_SEI, 0xf03f0230, 0xf03f0230}, /* System error interrupts */ + {ICU_GRP_REI, 0xf03f0270, 0xf03f0270}, /* RAM error interrupts */ +}; + +static void icu_clear_irq(uintptr_t icu_base, int nr) +{ + mmio_write_32(icu_base + ICU_INT_CFG(nr), 0); +} + +static void icu_set_irq(uintptr_t icu_base, const struct icu_irq *irq, + uint32_t spi_base, enum icu_group group) +{ + uint32_t icu_int; + + icu_int = (irq->spi_id + spi_base) | (1 << ICU_INT_ENABLE_OFFSET); + icu_int |= irq->is_edge << ICU_IS_EDGE_OFFSET; + icu_int |= group << ICU_GROUP_OFFSET; + + mmio_write_32(icu_base + ICU_INT_CFG(irq->icu_id), icu_int); +} + +/* + * This function uses 2 spi values to initialize the ICU + * spi_base: used to set the base of the SPI id in the MSI message + * generated by the ICU. AP806-Z1 required spi_base=64 while + * AP806-A0 uses spi_base=0 + * spi_offset: used to shift the multi instance interrupts between CP-0 + * and CP-1 + */ +void icu_init(int cp_index, int spi_base, int spi_offset, + const struct icu_config *config) +{ + int i; + const struct icu_irq *irq; + struct icu_msi *msi; + uintptr_t icu_base = MVEBU_ICU_REG_BASE(cp_index); + + /* Set the addres for SET_SPI and CLR_SPI registers in AP */ + msi = msi_addr; + for (i = 0; i < ICU_GRP_MAX; i++, msi++) { + mmio_write_32(icu_base + ICU_SET_SPI_AL(msi->group), msi->set_spi_addr & 0xFFFFFFFF); + mmio_write_32(icu_base + ICU_SET_SPI_AH(msi->group), msi->set_spi_addr >> 32); + mmio_write_32(icu_base + ICU_CLR_SPI_AL(msi->group), msi->clr_spi_addr & 0xFFFFFFFF); + mmio_write_32(icu_base + ICU_CLR_SPI_AH(msi->group), msi->clr_spi_addr >> 32); + } + + /* Mask all ICU interrupts */ + for (i = 0; i < MAX_ICU_IRQS; i++) + icu_clear_irq(icu_base, i); + + /* Configure the ICU interrupt lines */ + /* Multi instance interrupts use different SPI ID for CP-1*/ + irq = config->ns_multi.map; + for (i = 0; i < config->ns_multi.size; i++, irq++) + icu_set_irq(icu_base, irq, spi_base + spi_offset, ICU_GRP_NSR); + + irq = config->ns_single.map; + for (i = 0; i < config->ns_single.size; i++, irq++) + icu_set_irq(icu_base, irq, spi_base, ICU_GRP_NSR); + + irq = config->sei.map; + for (i = 0; i < config->sei.size; i++, irq++) + icu_set_irq(icu_base, irq, spi_base, ICU_GRP_SEI); + + irq = config->rei.map; + for (i = 0; i < config->rei.size; i++, irq++) + icu_set_irq(icu_base, irq, spi_base, ICU_GRP_REI); + + return; +} diff --git a/drivers/marvell/iob.c b/drivers/marvell/iob.c new file mode 100644 index 00000000..2a559c25 --- /dev/null +++ b/drivers/marvell/iob.c @@ -0,0 +1,206 @@ +/* +* *************************************************************************** +* 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 +#include +#include +#include +#include +#include + +#if LOG_LEVEL >= LOG_LEVEL_INFO +#define DEBUG_ADDR_MAP +#endif + +/* common defines */ +#define WIN_ENABLE_BIT (0x1) +/* Physical address of the base of the window = {AddrLow[19:0],20`h0} */ +#define ADDRESS_SHIFT (20 - 4) +#define ADDRESS_MASK (0xFFFFFFF0) +#define IOB_WIN_ALIGNMENT (0x100000) + +/* IOB registers */ +#define IOB_MAX_WIN_NUM (24) + +#define IOB_WIN_CR_OFFSET(win) (iob_info->iob_base + 0x0 + (0x20 * win)) +#define IOB_TARGET_ID_OFFSET (8) +#define IOB_TARGET_ID_MASK (0xF) + +#define IOB_WIN_SCR_OFFSET(win) (iob_info->iob_base + 0x4 + (0x20 * win)) +#define IOB_WIN_ENA_CTRL_WRITE_SECURE (0x1) +#define IOB_WIN_ENA_CTRL_READ_SECURE (0x2) +#define IOB_WIN_ENA_WRITE_SECURE (0x4) +#define IOB_WIN_ENA_READ_SECURE (0x8) + +#define IOB_WIN_ALR_OFFSET(win) (iob_info->iob_base + 0x8 + (0x20 * win)) +#define IOB_WIN_AHR_OFFSET(win) (iob_info->iob_base + 0xC + (0x20 * win)) + +struct iob_configuration { + uintptr_t iob_base; + uint32_t max_win; +}; + +struct iob_configuration iob_config; +struct iob_configuration *iob_info = &iob_config; + +static void iob_win_check(struct iob_win *win, uint32_t win_num) +{ + uint64_t base_addr, win_size; + + /* check if address is aligned to the size */ + base_addr = ((uint64_t)win->base_addr_high << 32) + win->base_addr_low; + if (IS_NOT_ALIGN(base_addr, IOB_WIN_ALIGNMENT)) { + base_addr = ALIGN_UP(base_addr, IOB_WIN_ALIGNMENT); + ERROR("Window %d: base address unaligned to 0x%x\n", win_num, IOB_WIN_ALIGNMENT); + printf("Align up the base address to 0x%lx\n", base_addr); + win->base_addr_high = (uint32_t)(base_addr >> 32); + win->base_addr_low = (uint32_t)(base_addr); + } + + /* size parameter validity check */ + win_size = ((uint64_t)win->win_size_high << 32) + win->win_size_low; + if (IS_NOT_ALIGN(win_size, IOB_WIN_ALIGNMENT)) { + win_size = ALIGN_UP(win_size, IOB_WIN_ALIGNMENT); + ERROR("Window %d: window size unaligned to 0x%x\n", win_num, IOB_WIN_ALIGNMENT); + printf("Aligning size to 0x%lx\n", win_size); + win->win_size_high = (uint32_t)(win_size >> 32); + win->win_size_low = (uint32_t)(win_size); + } +} + +static void iob_enable_win(struct iob_win *win, uint32_t win_id) +{ + uint32_t iob_win_reg; + uint32_t alr, ahr; + uint64_t start_addr, end_addr; + + iob_win_reg = WIN_ENABLE_BIT; + iob_win_reg |= (win->target_id & IOB_TARGET_ID_MASK) << IOB_TARGET_ID_OFFSET; + mmio_write_32(IOB_WIN_CR_OFFSET(win_id), iob_win_reg); + + start_addr = ((uint64_t)win->base_addr_high << 32) + win->base_addr_low; + end_addr = (start_addr + (((uint64_t)win->win_size_high << 32) + win->win_size_low) - 1); + alr = (uint32_t)((start_addr >> ADDRESS_SHIFT) & ADDRESS_MASK); + ahr = (uint32_t)((end_addr >> ADDRESS_SHIFT) & ADDRESS_MASK); + + mmio_write_32(IOB_WIN_ALR_OFFSET(win_id), alr); + mmio_write_32(IOB_WIN_AHR_OFFSET(win_id), ahr); +} + +#ifdef DEBUG_ADDR_MAP +static void dump_iob(void) +{ + uint32_t win_id, win_cr, alr, ahr; + uint8_t target_id; + uint64_t start, end; + char *iob_target_name[IOB_MAX_TID] = {"CONFIG", "MCI0 ", "PEX1 ", "PEX2 ", + "PEX0 ", "NAND ", "RUNIT", "MCI1 "}; + + /* Dump all IOB windows */ + printf("bank id target start end\n"); + printf("----------------------------------------------------\n"); + for (win_id = 0; win_id < iob_info->max_win; win_id++) { + win_cr = mmio_read_32(IOB_WIN_CR_OFFSET(win_id)); + if (win_cr & WIN_ENABLE_BIT) { + target_id = (win_cr >> IOB_TARGET_ID_OFFSET) & IOB_TARGET_ID_MASK; + alr = mmio_read_32(IOB_WIN_ALR_OFFSET(win_id)); + start = ((uint64_t)alr << ADDRESS_SHIFT); + if (win_id != 0) { + ahr = mmio_read_32(IOB_WIN_AHR_OFFSET(win_id)); + end = (((uint64_t)ahr + 0x10) << ADDRESS_SHIFT); + } else { + /* Window #0 size is hardcoded to 16MB, as it's + ** reserved for CP configuration space. */ + end = start + (16 << 20); + } + printf("iob %02d %s 0x%016lx 0x%016lx\n" + , win_id, iob_target_name[target_id], start, end); + } + } + + return; +} +#endif + +int init_iob(int cp_index) +{ + struct iob_win *win; + uint32_t win_id, win_reg; + uint32_t win_count; + + INFO("Initializing IOB Address decoding\n"); + + /* Get the base address of the address decoding MBUS */ + iob_info->iob_base = marvell_get_iob_reg_offs(cp_index); + + /* Get the maximum number of iob windows supported */ + iob_info->max_win = marvell_get_iob_max_win(); + if (iob_info->max_win == 0) { + iob_info->max_win = IOB_MAX_WIN_NUM; + ERROR("IOB win num cannot be 0. Setting to default num (%d)\n", IOB_MAX_WIN_NUM); + } + + /* Get the array of the windows and fill the map data */ + marvell_get_iob_memory_map(&win, &win_count, cp_index); + if (win_count <= 0) { + INFO("no windows configurations found\n"); + return 0; + } + + /* disable all IOB windows, start from win_id = 1 because can't disable internal register window */ + for (win_id = 1; win_id < iob_info->max_win; win_id++) { + win_reg = mmio_read_32(IOB_WIN_CR_OFFSET(win_id)); + win_reg &= ~WIN_ENABLE_BIT; + mmio_write_32(IOB_WIN_CR_OFFSET(win_id), win_reg); + + win_reg = ~IOB_WIN_ENA_CTRL_WRITE_SECURE; + win_reg &= ~IOB_WIN_ENA_CTRL_READ_SECURE; + win_reg &= ~IOB_WIN_ENA_WRITE_SECURE; + win_reg &= ~IOB_WIN_ENA_READ_SECURE; + mmio_write_32(IOB_WIN_SCR_OFFSET(win_id), win_reg); + } + + for (win_id = 1; win_id < win_count + 1; win_id++, win++) { + iob_win_check(win, win_id); + iob_enable_win(win, win_id); + } + +#ifdef DEBUG_ADDR_MAP + dump_iob(); +#endif + + INFO("Done IOB Address decoding Initializing\n"); + + return 0; +} diff --git a/drivers/marvell/mci.c b/drivers/marvell/mci.c new file mode 100644 index 00000000..b9815161 --- /dev/null +++ b/drivers/marvell/mci.c @@ -0,0 +1,617 @@ +/* + * *************************************************************************** + * 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 +#include +#include +#include +#include +#include +#include + +enum { + MCI_CMD_WRITE, + MCI_CMD_READ +}; + +/* Write wrapper callback for debug: + * will print written data in case LOG_LEVEL >= 40 + */ +static void mci_mmio_write_32(uintptr_t addr, uint32_t value) +{ + VERBOSE("Write:\t0x%x = 0x%x\n", (uint32_t)addr, value); + mmio_write_32(addr, value); +} +/* Read wrapper callback for debug: + * will print read data in case LOG_LEVEL >= 40 + */ +static uint32_t mci_mmio_read_32(uintptr_t addr) +{ + uint32_t value; + value = mmio_read_32(addr); + VERBOSE("Read:\t0x%x = 0x%x\n", (uint32_t)addr, value); + return value; +} + +/* MCI indirect access command completion polling: + * Each write/read command done via MCI indirect registers must be polled + * for command completions status. + * + * Returns 1 in case of error + * Returns 0 in case of command completed successfully. + */ +static int mci_poll_command_completion(int mci_index, int command_type) +{ + uint32_t mci_cmd_value = 0, retry_count = 100; + uint32_t completion_flags = MCI_INDIRECT_CTRL_CMD_DONE; + + /* Read commands require validating that requested data is ready */ + if (command_type == MCI_CMD_READ) + completion_flags |= MCI_INDIRECT_CTRL_DATA_READY; + + do { + /* wait 1 ms before each polling */ + mdelay(1); + mci_cmd_value = mci_mmio_read_32(MCI_ACCESS_CMD_REG(mci_index)); + } while (((mci_cmd_value & completion_flags) != completion_flags) && + (retry_count-- > 0)); + + if (retry_count == 0) { + ERROR("%s: MCI command timeout (command status = 0x%x)\n", __func__, mci_cmd_value); + return 1; + } + + return 0; +} + +/* Routine to enable register-mode access to PHYs over MCI0 indirect read/write*/ +static void mci_enable_phy_regs_access(int mci_index) +{ + uint32_t reg_data = MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE | + MCI_PHY_CTRL_MCI_MAJOR | MCI_PHY_CTRL_MCI_MINOR; + + /* Enable PHY REG access on remote (CP, device mode, GID=2) */ + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), reg_data); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) | + MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT)); + mci_poll_command_completion(mci_index, MCI_CMD_WRITE); + + /* Enable PHY REG access localy (AP, host mode, GID=0) */ + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), + reg_data | MCI_PHY_CTRL_MCI_PHY_MODE_HOST); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) | + MCI_INDIRECT_CTRL_LOCAL_PKT); + mci_poll_command_completion(mci_index, MCI_CMD_WRITE); +} + +/* read mci0 PHY/CTRL registers via indirect (local) access */ +static uint32_t mci_indirect_read(int reg_num, enum mci_register_type reg_type, int mci_index) +{ + uint32_t indirect_reg_address = MCI_INDIRECT_REG_CTRL_ADDR(reg_num) | + MCI_INDIRECT_CTRL_READ_CMD; + + /* Access to PHY registers requires special configuration */ + if (reg_type == MCI_REG_TYPE_PHY) + indirect_reg_address |= MCI_INDIRECT_CTRL_PHY_ACCESS_EN; + + /* Local access - same chip */ + indirect_reg_address |= MCI_INDIRECT_CTRL_LOCAL_PKT; + + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), indirect_reg_address); + return mci_mmio_read_32(MCI_WRITE_READ_DATA_REG(mci_index)); +} + +/* Force MCI link speed to 8Gbps */ +static void mci_link_force_speed_8g(int mci_index) +{ + uint32_t reg_data; + + /* Force link speed localy on AP PHY */ + reg_data = PWM2_SPEED_V3_8G | PWM2_SPEED_FORCE | + PWM2_RX_LINE_EN | PWM2_TX_LINE_EN; + + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), reg_data); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_PWM2_REG_NUM) | + MCI_INDIRECT_CTRL_PHY_ACCESS_EN | + MCI_INDIRECT_CTRL_LOCAL_PKT); + + /* Force link speed remotely on CP PHY */ + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), reg_data); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_PWM2_REG_NUM) | + MCI_INDIRECT_CTRL_PHY_ACCESS_EN | + MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT)); + + /* Enable SW power state requests control mode */ + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), + MCI_PHY_P0_IDLE_MIN_IDLE_COUNT | + MCI_PHY_P0_IDLE_SW_PWR_REQ_EN | + MCI_PHY_P0_IDLE_SW_RETRAIN_MODE); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_P0_IDLE_CTRL_REG_NUM) | + MCI_INDIRECT_CTRL_LOCAL_PKT); + + /* Toggle power state request */ + reg_data = MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE | + MCI_PHY_CTRL_MCI_PHY_MODE_HOST | + MCI_PHY_CTRL_MCI_SLEEP_REQ | + MCI_PHY_CTRL_MCI_MAJOR | + MCI_PHY_CTRL_MCI_MINOR; + + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), reg_data); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) | + MCI_INDIRECT_CTRL_LOCAL_PKT); + + reg_data &= ~MCI_PHY_CTRL_MCI_SLEEP_REQ; + + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), reg_data); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) | + MCI_INDIRECT_CTRL_LOCAL_PKT); + + /* Return power state requests control mode back to HW */ + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), + MCI_PHY_P0_IDLE_MIN_IDLE_COUNT | + MCI_PHY_P0_IDLE_SW_RETRAIN_MODE); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_P0_IDLE_CTRL_REG_NUM) | + MCI_INDIRECT_CTRL_LOCAL_PKT); + + /* Reset all fields in link CRC control register */ + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), 0); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_LINK_CRC_CTRL_REG_NUM) | + MCI_INDIRECT_CTRL_LOCAL_PKT); +} + +/* Perform 3 configurations in one command: PCI mode, queues separation and cache bit */ +static int mci_axi_set_pcie_mode(int mci_index) +{ + uint32_t reg_data; + + /* This configuration makes MCI IP behave consistently with AXI protocol. + * It should be configured at one side only (for example localy at AP). + * The IP takes care of performing the same configurations at MCI on another + * side (for example remotely at CP). + */ + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), + MCI_AXI_ACCESS_PCIE_MODE | + MCI_AXI_ACCESS_CACHE_CHECK | + MCI_AXI_ACCESS_FORCE_POST_WR | + MCI_AXI_ACCESS_DISABLE_CLK_GATING); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_AXI_ACCESS_DATA_REG_NUM) | + MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB) | + MCI_INDIRECT_CTRL_LOCAL_PKT | + MCI_INDIRECT_CTRL_CIRCULAR_CMD); + + /* if Write command was successful, verify PCIe mode */ + if (mci_poll_command_completion(mci_index, MCI_CMD_WRITE) == 0) { + /* Verify the PCIe mode selected */ + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_HB_CTRL_TX_CTRL_REG_NUM) | + MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB) | + MCI_INDIRECT_CTRL_LOCAL_PKT | + MCI_INDIRECT_CTRL_READ_CMD); + /* if read was completed, verify PCIe mode */ + if (mci_poll_command_completion(mci_index, MCI_CMD_READ) == 0) { + reg_data = mci_mmio_read_32(MCI_WRITE_READ_DATA_REG(mci_index)); + if (reg_data & MCI_HB_CTRL_TX_CTRL_PCIE_MODE) + return 0; + } + } + return 1; +} + +/* Reduce sequence FIFO timer expiration threshold */ +static int mci_axi_set_fifo_thresh(int mci_index) +{ + uint32_t reg_data; + + /* This configuration reduces sequence FIFO timer expiration threshold (to 0x7 instead of 0xA). + * In MCI 1.6 version this configuration prevents possible functional issues. + * In version 1.82 the configuration prevents performance degradation + */ + /* Configure local AP side */ + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), + MCI_CTRL_IHB_MODE_CFG_REG_DEF_VAL); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_CTRL_IHB_MODE_CFG_REG_NUM) | + MCI_INDIRECT_CTRL_LOCAL_PKT); + + /* Check the command execution status */ + reg_data = mci_mmio_read_32(MCI_ACCESS_CMD_REG(mci_index)); + if (reg_data | MCI_INDIRECT_CTRL_CMD_DONE) { + /* Configure remote CP side */ + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), + MCI_CTRL_IHB_MODE_CFG_REG_DEF_VAL); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_CTRL_IHB_MODE_CFG_REG_NUM) | + MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT)); + + /* Check the command execution status */ + reg_data = mci_mmio_read_32(MCI_ACCESS_CMD_REG(mci_index)); + if (reg_data | MCI_INDIRECT_CTRL_CMD_DONE) + return 0; + } + + return 1; +} + +/* Reduce sequence FIFO timer expiration threshold for A1, including PIDI workaround */ +static int mci_axi_set_fifo_thresh_a1(int mci_index) +{ + uint32_t reg_data, ret = 0; + + /* This configuration reduces sequence FIFO timer expiration threshold (to 0x7 instead of 0xA). + * In MCI 1.6 version this configuration prevents possible functional issues. + * In version 1.82 the configuration prevents performance degradation + */ + + /* Configure local AP side */ + /* PIDI Workaround for entering PIDI mode */ + reg_data = MCI_PHY_CTRL_PIDI_MODE | MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE + | MCI_PHY_CTRL_MCI_PHY_MODE_HOST + | MCI_PHY_CTRL_MCI_MAJOR | MCI_PHY_CTRL_MCI_MINOR_A1; + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), reg_data); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) | MCI_INDIRECT_CTRL_LOCAL_PKT); + ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); + + /* Reduce the threshold */ + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), + MCI_CTRL_IHB_MODE_CFG_REG_DEF_VAL_A1); + + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_CTRL_IHB_MODE_CFG_REG_NUM) | + MCI_INDIRECT_CTRL_LOCAL_PKT); + ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); + + /* Exit PIDI mode */ + reg_data = MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE | MCI_PHY_CTRL_MCI_PHY_MODE_HOST + | MCI_PHY_CTRL_MCI_MAJOR | MCI_PHY_CTRL_MCI_MINOR_A1; + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), reg_data); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) | MCI_INDIRECT_CTRL_LOCAL_PKT); + ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); + + + /* Configure remote CP side */ + /* PIDI Workaround for entering PIDI mode */ + reg_data = MCI_PHY_CTRL_PIDI_MODE | MCI_PHY_CTRL_MCI_MAJOR | MCI_PHY_CTRL_MCI_MINOR_A1; + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), reg_data); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) | MCI_CTRL_IHB_MODE_FWD_MOD); + ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); + + /* Reduce the threshold */ + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), + MCI_CTRL_IHB_MODE_CFG_REG_DEF_VAL_A1); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_CTRL_IHB_MODE_CFG_REG_NUM) | + MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT)); + ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); + + /* Exit PIDI mode */ + reg_data = MCI_PHY_CTRL_MCI_MAJOR | MCI_PHY_CTRL_MCI_MINOR_A1; + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), reg_data); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) | MCI_CTRL_IHB_MODE_FWD_MOD); + + ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); + + return ret; +} + +/* Configure: + * 1. AP & CP TX thresholds and delta configurations + * 2. DLO & DLI FIFO full threshold + * 3. RX thresholds and delta configurations + * 4. CP AR and AW outstanding + * 5. AP AR and AW outstanding + */ +static int mci_axi_set_fifo_rx_tx_thresh_a1(int mci_index) +{ + uint32_t ret = 0; + + /* AP TX thresholds and delta configurations (IHB_reg 0x1) */ + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), + MCI_CTRL_TX_MEM_CFG_REG_DEF_VAL); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_CTRL_TX_MEM_CFG_REG_NUM) | + MCI_INDIRECT_CTRL_LOCAL_PKT); + ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); + + /* CP TX thresholds and delta configurations (IHB_reg 0x1) */ + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), + MCI_CTRL_TX_MEM_CFG_REG_DEF_VAL); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_CTRL_TX_MEM_CFG_REG_NUM) | + MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT)); + ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); + + /* AP DLO & DLI FIFO full threshold & Auto-Link enable (IHB_reg 0x8) */ + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), + MCI_CTRL_MCI_PHY_SET_REG_DEF_VAL | MCI_CTRL_MCI_PHY_SET_AUTO_LINK_EN(1)); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_CTRL_MCI_PHY_SETTINGS_REG_NUM) | + MCI_INDIRECT_CTRL_LOCAL_PKT); + ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); + + /* CP DLO & DLI FIFO full threshold (IHB_reg 0x8) */ + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), + MCI_CTRL_MCI_PHY_SET_REG_DEF_VAL); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_CTRL_MCI_PHY_SETTINGS_REG_NUM) | + MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT)); + ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); + + /* AP RX thresholds and delta configurations (IHB_reg 0x0) */ + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), + MCI_CTRL_RX_MEM_CFG_REG_DEF_VAL); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_CTRL_RX_MEM_CFG_REG_NUM) | + MCI_INDIRECT_CTRL_LOCAL_PKT); + ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); + + /* CP RX thresholds and delta configurations (IHB_reg 0x0) */ + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), + MCI_CTRL_RX_MEM_CFG_REG_DEF_VAL); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_CTRL_RX_MEM_CFG_REG_NUM) | + MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT)); + ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); + + /* AP AR & AW maximum AXI outstanding request configuration (HB_reg 0xd) */ + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), + MCI_HB_CTRL_TX_CTRL_PRI_TH_QOS(8) | + MCI_HB_CTRL_TX_CTRL_MAX_RD_CNT(7) | + MCI_HB_CTRL_TX_CTRL_MAX_WR_CNT(7)); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_HB_CTRL_TX_CTRL_REG_NUM) | + MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB) | + MCI_INDIRECT_CTRL_LOCAL_PKT); + ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); + + /* CP AR & AW maximum AXI outstanding request configuration (HB_reg 0xd) */ + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), + MCI_HB_CTRL_TX_CTRL_PRI_TH_QOS(8) | + MCI_HB_CTRL_TX_CTRL_MAX_RD_CNT(15) | + MCI_HB_CTRL_TX_CTRL_MAX_WR_CNT(15)); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_HB_CTRL_TX_CTRL_REG_NUM) | + MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT) | + MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB)); + ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); + + return ret; +} + +/* configure MCI to allow read & write transactions to arrive at the same time. + * Without the below configuration, MCI won't sent response to CPU for transactions + * which arrived simultaneously and will lead to CPU hang. + * The below will configure MCI to be able to pass transactions from/to CP/AP. + */ +int mci_enable_simultaneous_transactions(int mci_index) +{ + uint32_t ret = 0; + + /* ID assignment (assigning global ID offset to CP) */ + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(0), + MCI_DID_GLOBAL_ASSIGN_REQ_MCI_LOCAL_ID(2) | + MCI_DID_GLOBAL_ASSIGN_REQ_MCI_COUNT(2) | + MCI_DID_GLOBAL_ASSIGN_REQ_HOPS_NUM(2)); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(0), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_DID_GLOBAL_ASSIGNMENT_REQUEST_REG) | + MCI_INDIRECT_CTRL_ASSIGN_CMD); + ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); + + /* Assigning destination ID=3 to all transactions entering from AXI at AP */ + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(0), + MCI_HB_CTRL_WIN0_DEST_VALID_FLAG(1) | + MCI_HB_CTRL_WIN0_DEST_ID(3)); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(0), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_HB_CTRL_WIN0_DESTINATION_REG_NUM) | + MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB) | + MCI_INDIRECT_CTRL_LOCAL_PKT); + ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); + + /* Assigning destination ID=1 to all transactions entering from AXI at CP */ + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(0), + MCI_HB_CTRL_WIN0_DEST_VALID_FLAG(1) | + MCI_HB_CTRL_WIN0_DEST_ID(1)); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(0), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_HB_CTRL_WIN0_DESTINATION_REG_NUM) | + MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT) | + MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB)); + ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); + + /* End address to all transactions entering from AXI at AP. This will lead to + * get match for any AXI address, and receive destination ID=3 */ + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(0), 0xffffffff); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(0), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_HB_CTRL_WIN0_ADDRESS_MASK_REG_NUM) | + MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB) | + MCI_INDIRECT_CTRL_LOCAL_PKT); + ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); + + /* End address to all transactions entering from AXI at CP. This will lead to + * get match for any AXI address, and receive destination ID=1 */ + mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(0), 0xffffffff); + mci_mmio_write_32(MCI_ACCESS_CMD_REG(0), + MCI_INDIRECT_REG_CTRL_ADDR(MCI_HB_CTRL_WIN0_ADDRESS_MASK_REG_NUM) | + MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT) | + MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB)); + ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); + + return ret; +} + +/* For A1 revision, configure the MCI link for performance improvement: + * - set MCI to support read/write transactions to arrive at the same time + * - Switch AXI to PCIe mode + * - Reduce sequence FIFO threshold + * - Configure RX/TX FIFO thresholds + * + * Note: + * We don't exit on error code from any sub routine, to try (best effort) to + * complete the MCI configuration. + * (If we exit - Bootloader will surely fail to boot) + */ +int mci_configure_a1(int mci_index) +{ + int rval; + + /* set MCI to support read/write transactions to arrive at the same time */ + rval = mci_enable_simultaneous_transactions(mci_index); + if (rval) + ERROR("Failed to set MCI for simultaneous read/write transactions\n"); + + /* enable PHY register mode read/write access */ + mci_enable_phy_regs_access(mci_index); + + /* Configure MCI for more consistent behavior with AXI protocol */ + rval = mci_axi_set_pcie_mode(mci_index); + if (rval) + ERROR("Failed to set MCI to AXI PCIe mode\n"); + + /* reduce FIFO global threshold */ + rval = mci_axi_set_fifo_thresh_a1(mci_index); + if (rval) + ERROR("Failed to set MCI FIFO global threshold\n"); + + /* configure RX/TX FIFO thresholds */ + rval = mci_axi_set_fifo_rx_tx_thresh_a1(mci_index); + if (rval) + ERROR("Failed to set MCI RX/TX FIFO threshold\n"); + + return 1; +} + +/* For A0 revision, Initialize the MCI link and check its status. + * - Configure MCI indirect access registers for register-mode access + * - Foce MCI link speed to 8Gbps + * - Switch AXI to PCIe mode + * - Reduce sequence FIFO threshold + * - Check the status of MCI link + * - Reset SoC on unrecoverable link fail + */ +int mci_link_init_a0(int mci_index) +{ + uint32_t ctrl_status, phy_status, link_error; + int rval, n; + + /* enable PHY register mode read/write access */ + mci_enable_phy_regs_access(mci_index); + + INFO("Force the MCI0 link speed to 8GBps\n"); + /* APN806-A0: Force link speed to 8Gbps */ + mci_link_force_speed_8g(mci_index); + + /* Configure MCI for more consistent behavior with AXI protocol */ + rval = mci_axi_set_pcie_mode(mci_index); + if (rval) + ERROR("Failed to set AXI PCIe mode\n"); + + /* reduce FIFO threshold */ + rval = mci_axi_set_fifo_thresh(mci_index); + if (rval) + ERROR("Failed to set FIFO threshold\n"); + + for (n = 0; n < LINK_READY_TIMEOUT; n++) { + /* MCI Controller link status*/ + ctrl_status = mci_indirect_read(MCI_CTRL_STATUS_REG_NUM, MCI_REG_TYPE_CTRL, mci_index); + + /* MCI PHY link status: PWM Control #3*/ + phy_status = mci_indirect_read(MCI_PHY_PWM3_REG_NUM, MCI_REG_TYPE_PHY, mci_index); + + if (ctrl_status == MCI_CTRL_PHY_READY) + break; + } + + if (ctrl_status != MCI_CTRL_PHY_READY) { + ERROR(" Link failed (MCI status: 0x%x, PWM_CTRL #3 = 0x%x)\n", + ctrl_status, phy_status); + goto reboot; + } + + link_error = (phy_status & PWM3_LINK_ERROR_MASK) >> PWM3_LINK_ERROR_OFFSET; + if (link_error) { + ERROR(" Link Error #%d: (MCI status: 0%x)\n", link_error, ctrl_status); + goto reboot; + } + INFO("MCI0 link is UP\n"); + + return 1; + +reboot: + /* Unrecoverable error, no WA exists, requires HW reset */ + ERROR("REBOOTING..."); + plat_marvell_system_reset(); + /* Never reached */ + return 0; +} + +/* Initialize MCI + * - Performance improvements for A0 & A1 + * - A0 revision configuration include MCI link initialization */ +int mci_initialize(int mci_index) +{ + INFO("MCI%d initialization:\n", mci_index); + + if (apn806_rev_id_get() == APN806_REV_ID_A0) + return mci_link_init_a0(0); + + /* Else, for A1 configure MCI for improved performance */ + mci_configure_a1(0); + return 1; /* Link is always guaranteed for A1 */ +} + +/* MCIx indirect access register are based by default at 0xf4000000/0xf6000000 + * to avoid conflict of internal registers of units connected via MCIx, which + * can be based on the same address (i.e CP1 base is also 0xf4000000), + * the following routines remaps the MCIx indirect bases to another domain + */ +void mci_remap_indirect_access_base(void) +{ + uint32_t i; + + for (i = 0; i < MCI_MAX_UNIT_ID; ++i) { + mci_mmio_write_32(MCIX4_REG_START_ADDRESS_REG(i), + MVEBU_MCI_REG_BASE_REMAP(i) >> MCI_REMAP_OFF_SHIFT); + } +} diff --git a/drivers/marvell/mochi/apn806_setup.c b/drivers/marvell/mochi/apn806_setup.c new file mode 100644 index 00000000..95dff189 --- /dev/null +++ b/drivers/marvell/mochi/apn806_setup.c @@ -0,0 +1,216 @@ +/* +* *************************************************************************** +* 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 +#include +#include +#include +#include +#include +#include + +#define SMMU_sACR (MVEBU_SMMU_BASE + 0x10) +#define SMMU_sACR_PG_64K (1 << 16) + +#define CCU_GSPMU_CR (MVEBU_CCU_BASE + 0x3F0) +#define GSPMU_CPU_CONTROL (0x1 << 0) + +#define CCU_HTC_CR (MVEBU_CCU_BASE + 0x200) +#define CCU_SET_POC_OFFSET 5 + +#define CCU_LTC_CR (MVEBU_CCU_BASE + 0x300) +#define CCU_CLEAN_INV_WRITE_OFFSET 8 + +/* Secure MoChi incoming access */ +#define SEC_MOCHI_IN_ACC_REG (MVEBU_RFU_BASE + 0x4738) +#define SEC_MOCHI_IN_ACC_IHB0_EN (1) +#define SEC_MOCHI_IN_ACC_IHB1_EN (1 << 3) +#define SEC_MOCHI_IN_ACC_IHB2_EN (1 << 6) +#define SEC_MOCHI_IN_ACC_PIDI_EN (1 << 9) +#define SEC_IN_ACCESS_ENA_ALL_MASTERS (SEC_MOCHI_IN_ACC_IHB0_EN | \ + SEC_MOCHI_IN_ACC_IHB1_EN | \ + SEC_MOCHI_IN_ACC_IHB2_EN | \ + SEC_MOCHI_IN_ACC_PIDI_EN) + +/* Misc SoC configurations Base*/ +#define MVEBU_MISC_SOC_BASE (MVEBU_REGS_BASE + 0x6F4300) + +/* SYSRST_OUTn Config definitions */ +#define MVEBU_SYSRST_OUT_CONFIG_REG (MVEBU_MISC_SOC_BASE + 0x4) +#define WD_MASK_SYS_RST_OUT (1 << 2) + +/* + * AXI Configuration. + */ + +/* Used for Units of AP-806 (e.g. SDIO and etc) */ +#define MVEBU_AXI_ATTR_BASE (MVEBU_REGS_BASE + 0x6F4580) +#define MVEBU_AXI_ATTR_REG(index) (MVEBU_AXI_ATTR_BASE + 0x4 * index) + +enum axi_attr { + AXI_SDIO_ATTR = 0, + AXI_DFX_ATTR, + AXI_MAX_ATTR, +}; + +static void apn_sec_masters_access_en(uint32_t enable) +{ + uint32_t reg; + + /* Open/Close incoming access for all masters. + The access is disabled in trusted boot mode + Could only be done in EL3 + */ + reg = mmio_read_32(SEC_MOCHI_IN_ACC_REG); + if (enable) + mmio_write_32(SEC_MOCHI_IN_ACC_REG, reg | SEC_IN_ACCESS_ENA_ALL_MASTERS); + else + mmio_write_32(SEC_MOCHI_IN_ACC_REG, reg & ~SEC_IN_ACCESS_ENA_ALL_MASTERS); +} + +void setup_smmu(void) +{ + uint32_t reg; + + /* Set the SMMU page size to 64 KB */ + reg = mmio_read_32(SMMU_sACR); + reg |= SMMU_sACR_PG_64K; + mmio_write_32(SMMU_sACR, reg); +} + +void init_aurora2(void) +{ + uint32_t reg; + + /* Enable GSPMU control by CPU */ + reg = mmio_read_32(CCU_GSPMU_CR); + reg |= GSPMU_CPU_CONTROL; + mmio_write_32(CCU_GSPMU_CR, reg); + +#if !LLC_DISABLE + /* Enable LLC in exclusive mode */ + llc_enable(1); + + /* Set point of coherency to DDR. + This is required by units which have + SW cache coherency */ + reg = mmio_read_32(CCU_HTC_CR); + reg |= (0x1 << CCU_SET_POC_OFFSET); + mmio_write_32(CCU_HTC_CR, reg); + + /* A0 Only: cache line clean & invalidate instead of) + ** cache line invalidate only - to avoid system hang + ** due to memory coherency issue */ + if (apn806_rev_id_get() == APN806_REV_ID_A0) { + reg = mmio_read_32(CCU_LTC_CR); + reg |= (0x1 << CCU_CLEAN_INV_WRITE_OFFSET); + mmio_write_32(CCU_LTC_CR, reg); + } +#endif /* !LLC_DISABLE */ +} + +void apn806_axi_attr_init(void) +{ + uint32_t index, data; + + /* Initialize AXI attributes for APN806 */ + + /* Go over the AXI attributes and set Ax-Cache and Ax-Domain */ + for (index = 0; index < AXI_MAX_ATTR; index++) { + switch (index) { + /* DFX works with no coherent only - + there's no option to configure the Ax-Cache and Ax-Domain */ + case AXI_DFX_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(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(index), data); + } + } + + return; +} + +void misc_soc_configurations(void) +{ + uint32_t reg; + + /* Un-mask Watchdog reset from influencing the SYSRST_OUTn. + * Otherwise, upon WD timeout, the WD reset singal won't trigger reset + */ + reg = mmio_read_32(MVEBU_SYSRST_OUT_CONFIG_REG); + reg &= ~(WD_MASK_SYS_RST_OUT); + mmio_write_32(MVEBU_SYSRST_OUT_CONFIG_REG, reg); +} + +void apn806_init(void) +{ + /* Setup Aurora2. */ + init_aurora2(); + + /* configure MCI mapping */ + mci_remap_indirect_access_base(); + + /* configure RFU windows */ + init_rfu(); + + /* configure CCU windows */ + init_ccu(); + + /* configure the SMMU */ + setup_smmu(); + + /* Open APN incoming access for all masters */ + apn_sec_masters_access_en(1); + + /* configure axi for APN*/ + apn806_axi_attr_init(); + + /* misc configuration of the SoC */ + misc_soc_configurations(); +} 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 +#include +#include +#include +#include +#include + +/* + 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); +} diff --git a/drivers/marvell/pci_ep.h b/drivers/marvell/pci_ep.h new file mode 100644 index 00000000..55882026 --- /dev/null +++ b/drivers/marvell/pci_ep.h @@ -0,0 +1,59 @@ +/* +* *************************************************************************** +* 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. +* +*************************************************************************** +*/ + +#ifndef _PCIE_EP_H_ +#define _PCIE_EP_H_ + +#define PCIE_MAX_BARS 6 +#define PCIE_MAX_LANES 16 + +struct pci_hw_cfg { + uint8_t delay_cfg; + uint8_t master_en; + uint8_t lane_width; + uint8_t lane_ids[PCIE_MAX_LANES]; + uint8_t clk_src; + uint8_t clk_out; + uint8_t is_end_point; + uintptr_t mac_base; + uintptr_t comphy_base; + uintptr_t hpipe_base; + uintptr_t dfx_base; +}; + +void dw_pcie_ep_init(uintptr_t dw_base, uint8_t delay_cfg, uint8_t master_en); +int comphy_pcie_power_up(uint32_t lane, struct pci_hw_cfg *hw); + +#endif /* _PCIE_EP_H_ */ + diff --git a/drivers/marvell/pcie-comphy-cp110.c b/drivers/marvell/pcie-comphy-cp110.c new file mode 100644 index 00000000..cdfb8876 --- /dev/null +++ b/drivers/marvell/pcie-comphy-cp110.c @@ -0,0 +1,418 @@ +/* +* *************************************************************************** +* 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 +#include +#include +#include +#include "comphy.h" +#include "pci_ep.h" + +#define SD_ADDR(base, lane) (base + 0x1000 * lane) +#define HPIPE_ADDR(base, lane) (SD_ADDR(base, lane) + 0x800) +#define COMPHY_ADDR(base, lane) (base + 0x28 * lane) + + +void reg_set(uintptr_t addr, uint32_t data, uint32_t mask) +{ + uint32_t reg_data; + reg_data = mmio_read_32(addr); + reg_data &= ~mask; + reg_data |= data; + mmio_write_32(addr, reg_data); +} + +uint32_t polling_with_timeout(uintptr_t addr, uint32_t val, uint32_t mask, unsigned long usec_timout) +{ + uint32_t data; + + do { + udelay(1); + data = mmio_read_32(addr) & mask; + } while (data != val && --usec_timout > 0); + + if (usec_timout == 0) + return data; + return 0; +} + +void comphy_mux_set_pcie(uintptr_t comphy_addr, int lane) +{ + uint32_t val, mask; + + /* Set the PIPE as PCIe Gen3 */ + mask = 0xF << (4 * lane); + val = 0x4 << (4 * lane); + reg_set(comphy_addr + COMMON_SELECTOR_PIPE_OFFSET, val, mask); + + /* Disconnect the Ethernet PHYs */ + mask = 0xF << (4 * lane); + val = 0; + reg_set(comphy_addr + COMMON_SELECTOR_PHY_OFFSET, val, mask); +} + +int comphy_pcie_power_up(uint32_t lane, struct pci_hw_cfg *hw) +{ + uint32_t mask, data, ret = 1; + uintptr_t hpipe_addr = HPIPE_ADDR(hw->hpipe_base, lane); + uintptr_t comphy_addr = COMPHY_ADDR(hw->comphy_base, lane); + uintptr_t addr; + + printf("Setting up Comphy lane %d as PCIe\n", lane); + + INFO("PCIe clock = %x\n", hw->clk_out); + INFO("PCIe RC = %d\n", !hw->is_end_point); + INFO("PCIe Width = %d\n", hw->lane_width); + + comphy_mux_set_pcie(comphy_addr, lane); + + /* enable PCIe by4 and by2 */ + if (lane == 0) { + if (hw->lane_width == 4) { + reg_set(hw->comphy_base + COMMON_PHY_SD_CTRL1, + 0x1 << COMMON_PHY_SD_CTRL1_PCIE_X4_EN_OFFSET, COMMON_PHY_SD_CTRL1_PCIE_X4_EN_MASK); + } else if (hw->lane_width == 2) { + reg_set(hw->comphy_base + COMMON_PHY_SD_CTRL1, + 0x1 << COMMON_PHY_SD_CTRL1_PCIE_X2_EN_OFFSET, COMMON_PHY_SD_CTRL1_PCIE_X2_EN_MASK); + } + } + + /* if PCIe clock is output and clock source from SerDes lane 5, need to configure the clock-source MUX. + ** By default, the clock source is from lane 4 */ + if (hw->clk_out && hw->clk_src && (lane == 5)) + reg_set(hw->dfx_base + DFX_DEV_GEN_CTRL12, 0x3 << DFX_DEV_GEN_PCIE_CLK_SRC_OFFSET, + DFX_DEV_GEN_PCIE_CLK_SRC_MASK); + + INFO("stage: RFU configurations - hard reset comphy\n"); + /* RFU configurations - hard reset comphy */ + mask = COMMON_PHY_CFG1_PWR_UP_MASK; + data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET; + mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK; + data |= 0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET; + mask |= COMMON_PHY_CFG1_PWR_ON_RESET_MASK; + data |= 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET; + mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK; + data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET; + mask |= COMMON_PHY_PHY_MODE_MASK; + data |= 0x0 << COMMON_PHY_PHY_MODE_OFFSET; + reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask); + + /* release from hard reset */ + mask = COMMON_PHY_CFG1_PWR_ON_RESET_MASK; + data = 0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET; + mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK; + data |= 0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET; + reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask); + + /* Wait 1ms - until band gap and ref clock ready */ + mdelay(1); + /* Start comphy Configuration */ + INFO("stage: Comphy configuration\n"); + /* Set PIPE soft reset */ + mask = HPIPE_RST_CLK_CTRL_PIPE_RST_MASK; + data = 0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET; + /* Set PHY datapath width mode for V0 */ + mask |= HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK; + data |= 0x1 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET; + /* Set Data bus width USB mode for V0 */ + mask |= HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK; + data |= 0x0 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET; + /* Set CORE_CLK output frequency for 250Mhz */ + mask |= HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK; + data |= 0x0 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET; + reg_set(hpipe_addr + HPIPE_RST_CLK_CTRL_REG, data, mask); + /* Set PLL ready delay for 0x2 */ + data = 0x2 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET; + mask = HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK; + if (hw->lane_width != 1) { + data |= 0x1 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_OFFSET; + mask |= HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_MASK; + data |= 0x1 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_OFFSET; + mask |= HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_MASK; + } + reg_set(hpipe_addr + HPIPE_CLK_SRC_LO_REG, data, mask); + + /* Set PIPE mode interface to PCIe3 - 0x1 & set lane order */ + data = 0x1 << HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET; + mask = HPIPE_CLK_SRC_HI_MODE_PIPE_MASK; + if (hw->lane_width != 1) { + mask |= HPIPE_CLK_SRC_HI_LANE_STRT_MASK; + mask |= HPIPE_CLK_SRC_HI_LANE_MASTER_MASK; + mask |= HPIPE_CLK_SRC_HI_LANE_BREAK_MASK; + if (lane == 0) { + data |= 0x1 << HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET; + data |= 0x1 << HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET; + } else if (lane == (hw->lane_width - 1)) { + data |= 0x1 << HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET; + } + } + reg_set(hpipe_addr + HPIPE_CLK_SRC_HI_REG, data, mask); + /* Config update polarity equalization */ + reg_set(hpipe_addr + HPIPE_LANE_EQ_CFG1_REG, + 0x1 << HPIPE_CFG_UPDATE_POLARITY_OFFSET, HPIPE_CFG_UPDATE_POLARITY_MASK); + /* Set PIPE version 4 to mode enable */ + reg_set(hpipe_addr + HPIPE_DFE_CTRL_28_REG, + 0x1 << HPIPE_DFE_CTRL_28_PIPE4_OFFSET, HPIPE_DFE_CTRL_28_PIPE4_MASK); + /* TODO: check if pcie clock is output/input - for bringup use input*/ + /* Enable PIN clock 100M_125M */ + mask = 0; + data = 0; + /* Only if clock is output, configure the clock-source mux */ + if (hw->clk_out) { + mask |= HPIPE_MISC_CLK100M_125M_MASK; + data |= 0x1 << HPIPE_MISC_CLK100M_125M_OFFSET; + } + /* Set PIN_TXDCLK_2X Clock Frequency Selection for outputs 500MHz clock */ + mask |= HPIPE_MISC_TXDCLK_2X_MASK; + data |= 0x0 << HPIPE_MISC_TXDCLK_2X_OFFSET; + /* Enable 500MHz Clock */ + mask |= HPIPE_MISC_CLK500_EN_MASK; + data |= 0x1 << HPIPE_MISC_CLK500_EN_OFFSET; + if (hw->clk_out) { /* output */ + /* Set reference clock comes from group 1 */ + mask |= HPIPE_MISC_REFCLK_SEL_MASK; + data |= 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET; + } else { + /* Set reference clock comes from group 2 */ + mask |= HPIPE_MISC_REFCLK_SEL_MASK; + data |= 0x1 << HPIPE_MISC_REFCLK_SEL_OFFSET; + } + reg_set(hpipe_addr + HPIPE_MISC_REG, data, mask); + if (hw->clk_out) { /* output */ + /* Set reference frequcency select - 0x2 for 25MHz*/ + mask = HPIPE_PWR_PLL_REF_FREQ_MASK; + data = 0x2 << HPIPE_PWR_PLL_REF_FREQ_OFFSET; + } else { + /* Set reference frequcency select - 0x0 for 100MHz*/ + mask = HPIPE_PWR_PLL_REF_FREQ_MASK; + data = 0x0 << HPIPE_PWR_PLL_REF_FREQ_OFFSET; + } + /* Set PHY mode to PCIe */ + mask |= HPIPE_PWR_PLL_PHY_MODE_MASK; + data |= 0x3 << HPIPE_PWR_PLL_PHY_MODE_OFFSET; + reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask); + + /* ref clock alignment */ + if (hw->lane_width != 1) { + mask = HPIPE_LANE_ALIGN_OFF_MASK; + data = 0x0 << HPIPE_LANE_ALIGN_OFF_OFFSET; + reg_set(hpipe_addr + HPIPE_LANE_ALIGN_REG, data, mask); + } + + /* Set the amount of time spent in the LoZ state - set for 0x7 only if + the PCIe clock is output */ + if (hw->clk_out) + reg_set(hpipe_addr + HPIPE_GLOBAL_PM_CTRL, + 0x7 << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET, HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK); + + /* Set Maximal PHY Generation Setting(8Gbps) */ + mask = HPIPE_INTERFACE_GEN_MAX_MASK; + data = 0x2 << HPIPE_INTERFACE_GEN_MAX_OFFSET; + /* Set Link Train Mode (Tx training control pins are used) */ + mask |= HPIPE_INTERFACE_LINK_TRAIN_MASK; + data |= 0x1 << HPIPE_INTERFACE_LINK_TRAIN_OFFSET; + reg_set(hpipe_addr + HPIPE_INTERFACE_REG, data, mask); + + /* Set Idle_sync enable */ + mask = HPIPE_PCIE_IDLE_SYNC_MASK; + data = 0x1 << HPIPE_PCIE_IDLE_SYNC_OFFSET; + /* Select bits for PCIE Gen3(32bit) */ + mask |= HPIPE_PCIE_SEL_BITS_MASK; + data |= 0x2 << HPIPE_PCIE_SEL_BITS_OFFSET; + reg_set(hpipe_addr + HPIPE_PCIE_REG0, data, mask); + + /* Enable Tx_adapt_g1 */ + mask = HPIPE_TX_TRAIN_CTRL_G1_MASK; + data = 0x1 << HPIPE_TX_TRAIN_CTRL_G1_OFFSET; + /* Enable Tx_adapt_gn1 */ + mask |= HPIPE_TX_TRAIN_CTRL_GN1_MASK; + data |= 0x1 << HPIPE_TX_TRAIN_CTRL_GN1_OFFSET; + /* Disable Tx_adapt_g0 */ + mask |= HPIPE_TX_TRAIN_CTRL_G0_MASK; + data |= 0x0 << HPIPE_TX_TRAIN_CTRL_G0_OFFSET; + reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_REG, data, mask); + + /* Set reg_tx_train_chk_init */ + mask = HPIPE_TX_TRAIN_CHK_INIT_MASK; + data = 0x0 << HPIPE_TX_TRAIN_CHK_INIT_OFFSET; + /* Enable TX_COE_FM_PIN_PCIE3_EN */ + mask |= HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_MASK; + data |= 0x1 << HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET; + reg_set(hpipe_addr + HPIPE_TX_TRAIN_REG, data, mask); + + INFO("stage: TRx training parameters\n"); + /* Set Preset sweep configurations */ + mask = HPIPE_TX_TX_STATUS_CHECK_MODE_MASK; + data = 0x1 << HPIPE_TX_STATUS_CHECK_MODE_OFFSET; + + mask |= HPIPE_TX_NUM_OF_PRESET_MASK; + data |= 0x7 << HPIPE_TX_NUM_OF_PRESET_OFFSET; + + mask |= HPIPE_TX_SWEEP_PRESET_EN_MASK; + data |= 0x1 << HPIPE_TX_SWEEP_PRESET_EN_OFFSET; + reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_11_REG, data, mask); + + /* Tx train start configuration */ + mask = HPIPE_TX_TRAIN_START_SQ_EN_MASK; + data = 0x1 << HPIPE_TX_TRAIN_START_SQ_EN_OFFSET; + + mask |= HPIPE_TX_TRAIN_START_FRM_DET_EN_MASK; + data |= 0x0 << HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET; + + mask |= HPIPE_TX_TRAIN_START_FRM_LOCK_EN_MASK; + data |= 0x0 << HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET; + + mask |= HPIPE_TX_TRAIN_WAIT_TIME_EN_MASK; + data |= 0x1 << HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET; + reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_5_REG, data, mask); + + /* Enable Tx train P2P */ + mask = HPIPE_TX_TRAIN_P2P_HOLD_MASK; + data = 0x1 << HPIPE_TX_TRAIN_P2P_HOLD_OFFSET; + reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_0_REG, data, mask); + + /* Configure Tx train timeout */ + mask = HPIPE_TRX_TRAIN_TIMER_MASK; + data = 0x17 << HPIPE_TRX_TRAIN_TIMER_OFFSET; + reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_4_REG, data, mask); + + /* Disable G0/G1/GN1 adaptation */ + mask = HPIPE_TX_TRAIN_CTRL_G1_MASK | HPIPE_TX_TRAIN_CTRL_GN1_MASK + | HPIPE_TX_TRAIN_CTRL_G0_OFFSET; + data = 0; + reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_REG, data, mask); + + /* Disable DTL frequency loop */ + mask = HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK; + data = 0x0 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET; + reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG, data, mask); + + /* Configure G3 DFE */ + mask = HPIPE_G3_DFE_RES_MASK; + data = 0x3 << HPIPE_G3_DFE_RES_OFFSET; + reg_set(hpipe_addr + HPIPE_G3_SETTING_4_REG, data, mask); + + /* Force DFE resolution (use GEN table value) */ + mask = HPIPE_DFE_RES_FORCE_MASK; + data = 0x1 << HPIPE_DFE_RES_FORCE_OFFSET; + reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask); + + /* Configure initial and final coefficient value for receiver */ + mask = HPIPE_G3_RX_SELMUPI_MASK; + data = 0x1 << HPIPE_G3_RX_SELMUPI_OFFSET; + + mask |= HPIPE_G3_RX_SELMUPF_MASK; + data |= 0x1 << HPIPE_G3_RX_SELMUPF_OFFSET; + + mask |= HPIPE_G3_SETTING_BIT_MASK; + data |= 0x0 << HPIPE_G3_SETTING_BIT_OFFSET; + reg_set(hpipe_addr + HPIPE_G3_SETTINGS_1_REG, data, mask); + + /* Trigger sampler enable pulse */ + mask = HPIPE_SMAPLER_MASK; + data = 0x1 << HPIPE_SMAPLER_OFFSET; + reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask); + udelay(5); + reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, 0, mask); + + /* FFE resistor tuning for different bandwidth */ + mask = HPIPE_G3_FFE_DEG_RES_LEVEL_MASK; + data = 0x1 << HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET; + + mask |= HPIPE_G3_FFE_LOAD_RES_LEVEL_MASK; + data |= 0x1 << HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET; + reg_set(hpipe_addr + HPIPE_G3_SETTING_3_REG, data, mask); + + if (!hw->is_end_point) { + /* Set phy in root complex mode */ + mask = HPIPE_CFG_PHY_RC_EP_MASK; + data = 0x1 << HPIPE_CFG_PHY_RC_EP_OFFSET; + reg_set(hpipe_addr + HPIPE_LANE_EQU_CONFIG_0_REG, data, mask); + } + + INFO("stage: Comphy power up\n"); + + /* for PCIe by4 or by2 - release from reset only after finish to configure all lanes */ + if ((hw->lane_width == 1) || (lane == (hw->lane_width - 1))) { + uint32_t i, start_lane, end_lane; + + if (hw->lane_width != 1) { + /* allows writing to all lanes in one write */ + reg_set(hw->comphy_base + COMMON_PHY_SD_CTRL1, + 0x0 << COMMON_PHY_SD_CTRL1_COMPHY_0_4_PORT_OFFSET, + COMMON_PHY_SD_CTRL1_COMPHY_0_4_PORT_MASK); + start_lane = 0; + end_lane = hw->lane_width; + + /* Release from PIPE soft reset + for PCIe by4 or by2 - release from soft reset all lanes - can't use + read modify write */ + reg_set(HPIPE_ADDR(hw->hpipe_base, 0) + HPIPE_RST_CLK_CTRL_REG, + 0x24, 0xffffffff); + } else { + start_lane = lane; + end_lane = lane + 1; + + /* Release from PIPE soft reset + for PCIe by4 or by2 - release from soft reset all lanes */ + reg_set(hpipe_addr + HPIPE_RST_CLK_CTRL_REG, + 0x0 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET, HPIPE_RST_CLK_CTRL_PIPE_RST_MASK); + } + + + if (hw->lane_width != 1) { + /* disable writing to all lanes with one write */ + reg_set(hw->comphy_base + COMMON_PHY_SD_CTRL1, + 0x3210 << COMMON_PHY_SD_CTRL1_COMPHY_0_4_PORT_OFFSET, + COMMON_PHY_SD_CTRL1_COMPHY_0_4_PORT_MASK); + } + + INFO("stage: Check PLL\n"); + /* Read lane status */ + for (i = start_lane; i < end_lane; i++) { + addr = HPIPE_ADDR(hw->hpipe_base, i) + HPIPE_LANE_STATUS1_REG; + data = HPIPE_LANE_STATUS1_PCLK_EN_MASK; + mask = data; + data = polling_with_timeout(addr, data, mask, 15000); + if (data != 0) { + INFO("Read from reg = 0x%lx - value = 0x%x\n", + hpipe_addr + HPIPE_LANE_STATUS1_REG, data); + ERROR("HPIPE_LANE_STATUS1_PCLK_EN_MASK is 0\n"); + ret = 0; + } + } + } + + return ret; +} diff --git a/drivers/marvell/rfu.c b/drivers/marvell/rfu.c new file mode 100644 index 00000000..39b37395 --- /dev/null +++ b/drivers/marvell/rfu.c @@ -0,0 +1,197 @@ +/* +* *************************************************************************** +* 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 +#include +#include +#include +#include +#include + +#if LOG_LEVEL >= LOG_LEVEL_INFO +#define DEBUG_ADDR_MAP +#endif + +/* common defines */ +#define WIN_ENABLE_BIT (0x1) +/* Physical address of the base of the window = {Addr[19:0],20`h0} */ +#define ADDRESS_SHIFT (20 - 4) +#define ADDRESS_MASK (0xFFFFFFF0) +#define RFU_WIN_ALIGNMENT_1M (0x100000) +#define RFU_WIN_ALIGNMENT_64K (0x10000) + +/* AP registers */ +#define RFU_WIN_ALR_OFFSET(win) (rfu_base + 0x0 + (0x10 * win)) +#define RFU_WIN_AHR_OFFSET(win) (rfu_base + 0x8 + (0x10 * win)) +#define RFU_WIN_CR_OFFSET(win) (rfu_base + 0xC + (0x10 * win)) +#define RFU_GCR_OFFSET (rfu_base + 0x70) + + +uintptr_t rfu_base; + + +static void rfu_win_check(struct rfu_win *win, uint32_t win_num) +{ + uint64_t base_addr, win_size; + uint32_t alignment_value = RFU_WIN_ALIGNMENT_1M; + + /* for RFU The base is always 1M aligned */ + /* check if address is aligned to 1M */ + base_addr = ((uint64_t)win->base_addr_high << 32) + win->base_addr_low; + if (IS_NOT_ALIGN(base_addr, RFU_WIN_ALIGNMENT_1M)) { + base_addr = ALIGN_UP(base_addr, RFU_WIN_ALIGNMENT_1M); + ERROR("Window %d: base address unaligned to 0x%x\n", win_num, RFU_WIN_ALIGNMENT_1M); + printf("Align up the base address to 0x%lx\n", base_addr); + win->base_addr_high = (uint32_t)(base_addr >> 32); + win->base_addr_low = (uint32_t)(base_addr); + } + + /* size parameter validity check */ + win_size = ((uint64_t)win->win_size_high << 32) + win->win_size_low; + if (IS_NOT_ALIGN(win_size, alignment_value)) { + win_size = ALIGN_UP(win_size, alignment_value); + ERROR("Window %d: window size unaligned to 0x%x\n", win_num, alignment_value); + printf("Aligning size to 0x%lx\n", win_size); + win->win_size_high = (uint32_t)(win_size >> 32); + win->win_size_low = (uint32_t)(win_size); + } +} + +static void rfu_enable_win(struct rfu_win *win, uint32_t win_num) +{ + uint32_t alr, ahr; + uint64_t start_addr, end_addr; + + if (win->target_id < 0 || win->target_id >= RFU_MAX_WIN_ID) { + ERROR("target ID = %d, is invalid\n", win->target_id); + return; + } + + /* calculate 64bit start-address and end-address */ + start_addr = ((uint64_t)win->base_addr_high << 32) + win->base_addr_low; + end_addr = (start_addr + (((uint64_t)win->win_size_high << 32) + win->win_size_low) - 1); + + alr = (uint32_t)((start_addr >> ADDRESS_SHIFT) & ADDRESS_MASK); + alr |= WIN_ENABLE_BIT; + ahr = (uint32_t)((end_addr >> ADDRESS_SHIFT) & ADDRESS_MASK); + + /* write start address and end address for rfu window */ + mmio_write_32(RFU_WIN_ALR_OFFSET(win_num), alr); + mmio_write_32(RFU_WIN_AHR_OFFSET(win_num), ahr); + + /* write window target */ + mmio_write_32(RFU_WIN_CR_OFFSET(win_num), win->target_id); +} + +#ifdef DEBUG_ADDR_MAP +static void dump_rfu(void) +{ + uint32_t trgt_id, win_id; + uint32_t alr, ahr; + uint64_t start, end; + char *rfu_target_name[RFU_MAX_TID] = {"MCI-0 ", "MCI-1 ", "MCI-2 ", "PIDI ", + "SPI ", "STM ", "BootRoom "}; + + /* Dump all RFU windows */ + printf("bank target start end\n"); + printf("----------------------------------------------------\n"); + for (win_id = 0; win_id < RFU_MAX_WIN_ID; win_id++) { + alr = mmio_read_32(RFU_WIN_ALR_OFFSET(win_id)); + if (alr & WIN_ENABLE_BIT) { + alr &= ~WIN_ENABLE_BIT; + /* in case this is BOOTROM window */ + if (win_id == 0) { + ahr = alr; + trgt_id = BOOTROM_TID; + } else { + ahr = mmio_read_32(RFU_WIN_AHR_OFFSET(win_id)); + trgt_id = mmio_read_32(RFU_WIN_CR_OFFSET(win_id)); + } + start = ((uint64_t)alr << ADDRESS_SHIFT); + end = (((uint64_t)ahr + 0x10) << ADDRESS_SHIFT); + printf("rfu %s 0x%016lx 0x%016lx\n", rfu_target_name[trgt_id], start, end); + } + } + printf("rfu PIDI-port - all other IO transactions\n"); + + return; +} +#endif + +int init_rfu(void) +{ + struct rfu_win *win; + uint32_t win_id, win_reg; + uint32_t win_count; + + INFO("Initializing RFU Address decoding\n"); + + /* Get the base address of the address decoding MBUS */ + rfu_base = marvell_get_rfu_reg_offs(); + + /* Get the array of the windows and its size */ + marvell_get_rfu_memory_map(&win, &win_count); + if (win_count <= 0) { + INFO("no windows configurations found\n"); + } + if (win_count > RFU_MAX_WIN_ID) { + INFO("number of windows is bigger than %d\n", RFU_MAX_WIN_ID); + return 0; + } + + /* set the default target id to PIDI */ + win_reg = PIDI_TID; + mmio_write_32(RFU_GCR_OFFSET, win_reg); + + /* disable all RFU windows */ + for (win_id = 0; win_id < RFU_MAX_WIN_ID; win_id++) { + win_reg = mmio_read_32(RFU_WIN_ALR_OFFSET(win_id)); + win_reg &= ~WIN_ENABLE_BIT; + mmio_write_32(RFU_WIN_ALR_OFFSET(win_id), win_reg); + } + + /* enable relevant windows, starting from win_id=1 because index 0 dedicated for BootRom */ + for (win_id = 1; win_id <= win_count; win_id++, win++) { + rfu_win_check(win, win_id); + rfu_enable_win(win, win_id); + } + +#ifdef DEBUG_ADDR_MAP + dump_rfu(); +#endif + + INFO("Done RFU Address decoding Initializing\n"); + + return 0; +} diff --git a/include/drivers/marvell/a8k_i2c.h b/include/drivers/marvell/a8k_i2c.h new file mode 100644 index 00000000..22d1dac7 --- /dev/null +++ b/include/drivers/marvell/a8k_i2c.h @@ -0,0 +1,61 @@ +/* +* *************************************************************************** +* 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. +* +*************************************************************************** +*/ + +#ifndef _A8K_I2C_H_ +#define _A8K_I2C_H_ + +/* + * Initialization, must be called once on start up, may be called + * repeatedly to change the speed and slave addresses. + */ +void i2c_init(void *i2c_base); + +/* + * Read/Write interface: + * chip: I2C chip address, range 0..127 + * addr: Memory (register) address within the chip + * alen: Number of bytes to use for addr (typically 1, 2 for larger + * memories, 0 for register type devices with only one + * register) + * buffer: Where to read/write the data + * len: How many bytes to read/write + * + * Returns: 0 on success, not 0 on failure + */ +int i2c_read(uint8_t chip, unsigned int addr, int alen, + uint8_t *buffer, int len); + +int i2c_write(uint8_t chip, unsigned int addr, int alen, + uint8_t *buffer, int len); +#endif diff --git a/include/drivers/marvell/amb_adec.h b/include/drivers/marvell/amb_adec.h new file mode 100644 index 00000000..ad782537 --- /dev/null +++ b/include/drivers/marvell/amb_adec.h @@ -0,0 +1,68 @@ +/* +* *************************************************************************** +* 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. +* +*************************************************************************** +*/ + +#ifndef _AMB_ADEC_H_ +#define _AMB_ADEC_H_ + +#include + +struct amb_win { + uint32_t base_addr; + uint32_t win_size; + uint32_t attribute; +}; + +enum amb_attribute_ids { + AMB_SPI0_CS0_ID = 0x1E, + AMB_SPI0_CS1_ID = 0x5E, + AMB_SPI0_CS2_ID = 0x9E, + AMB_SPI0_CS3_ID = 0xDE, + AMB_SPI1_CS0_ID = 0x1A, + AMB_SPI1_CS1_ID = 0x5A, + AMB_SPI1_CS2_ID = 0x9A, + AMB_SPI1_CS3_ID = 0xDA, + AMB_DEV_CS0_ID = 0x3E, + AMB_DEV_CS1_ID = 0x3D, + AMB_DEV_CS2_ID = 0x3B, + AMB_DEV_CS3_ID = 0x37, + AMB_BOOT_CS_ID = 0x2f, + AMB_BOOT_ROM_ID = 0x1D, +}; + +#define AMB_MAX_WIN_ID 7 + +int init_amb_adec(int cp_index); + +#endif /* _AMB_ADEC_H_ */ + diff --git a/include/drivers/marvell/cache_llc.h b/include/drivers/marvell/cache_llc.h new file mode 100644 index 00000000..2c8d65db --- /dev/null +++ b/include/drivers/marvell/cache_llc.h @@ -0,0 +1,33 @@ +/* + * *************************************************************************** + * Copyright (C) 2015 Marvell International Ltd. + * *************************************************************************** + * 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, either version 2 of the License, or any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * *************************************************************************** + */ + +#ifndef _CACHE_LLC_H_ +#define _CACHE_LLC_H_ + +void llc_cache_sync(void); +void llc_flush_all(void); +void llc_clean_all(void); +void llc_inv_all(void); +void llc_disable(void); +void llc_enable(int excl_mode); +int llc_is_exclusive(void); +void llc_save(void); +void llc_resume(void); + +#endif /* _CACHE_LLC_H_ */ + diff --git a/include/drivers/marvell/ccu.h b/include/drivers/marvell/ccu.h new file mode 100644 index 00000000..748d72b1 --- /dev/null +++ b/include/drivers/marvell/ccu.h @@ -0,0 +1,63 @@ +/* +* *************************************************************************** +* 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. +* +*************************************************************************** +*/ + +#ifndef _CCU_H_ +#define _CCU_H_ + +#include + +struct ccu_win { + uint32_t base_addr_high; + uint32_t base_addr_low; + uint32_t win_size_high; + uint32_t win_size_low; + uint32_t target_id; +}; + +enum ccu_target_ids { + IO_0_TID = 0x00, + DRAM_0_TID = 0x03, + IO_1_TID = 0x0F, + CFG_REG_TID = 0x10, + RAR_TID = 0x20, + SRAM_TID = 0x40, + DRAM_1_TID = 0xC0, + CCU_MAX_TID, + INVALID_TID = 0xFF +}; + +int init_ccu(void); + +#endif /* _CCU_H_ */ + diff --git a/include/drivers/marvell/i2c.h b/include/drivers/marvell/i2c.h new file mode 100644 index 00000000..e26add9d --- /dev/null +++ b/include/drivers/marvell/i2c.h @@ -0,0 +1,46 @@ +/* +* *************************************************************************** +* 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. +* +*************************************************************************** +*/ + +#ifndef _I2C_H_ +#define _I2C_H_ + + +void i2c_init(void); + +int i2c_read(uint8_t chip, unsigned int addr, int alen, + uint8_t *buffer, int len); + +int i2c_write(uint8_t chip, unsigned int addr, int alen, + uint8_t *buffer, int len); +#endif diff --git a/include/drivers/marvell/icu.h b/include/drivers/marvell/icu.h new file mode 100644 index 00000000..5c14a81f --- /dev/null +++ b/include/drivers/marvell/icu.h @@ -0,0 +1,60 @@ +/* +* *************************************************************************** +* 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. +* +*************************************************************************** +*/ + +#ifndef _ICU_H_ +#define _ICU_H_ + +struct icu_irq { + uint8_t icu_id; + uint8_t spi_id; + uint8_t is_edge; +}; + +struct icu_config_entry { + const struct icu_irq *map; + int size; +}; + +struct icu_config { + struct icu_config_entry ns_multi; + struct icu_config_entry ns_single; + struct icu_config_entry sei; + struct icu_config_entry rei; +}; + +void icu_init(int cp_index, int spi_base, int spi_offset, + const struct icu_config *config); + +#endif /* _ICU_H_ */ + diff --git a/include/drivers/marvell/iob.h b/include/drivers/marvell/iob.h new file mode 100644 index 00000000..4fb328da --- /dev/null +++ b/include/drivers/marvell/iob.h @@ -0,0 +1,61 @@ +/* +* *************************************************************************** +* 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. +* +*************************************************************************** +*/ + +#ifndef _IOB_H_ +#define _IOB_H_ + +struct iob_win { + uint32_t base_addr_high; + uint32_t base_addr_low; + uint32_t win_size_high; + uint32_t win_size_low; + uint32_t target_id; +}; + +enum target_ids_iob { + INTERNAL_TID = 0x0, + MCI0_TID = 0x1, + PEX1_TID = 0x2, + PEX2_TID = 0x3, + PEX0_TID = 0x4, + NAND_TID = 0x5, + RUNIT_TID = 0x6, + MCI1_TID = 0x7, + IOB_MAX_TID +}; + +int init_iob(int cp_index); + +#endif /* _IOB_H_ */ + diff --git a/include/drivers/marvell/mci.h b/include/drivers/marvell/mci.h new file mode 100644 index 00000000..3a46f1e4 --- /dev/null +++ b/include/drivers/marvell/mci.h @@ -0,0 +1,260 @@ +/* + * *************************************************************************** + * 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. + * + *************************************************************************** + */ + +#ifndef _MCI_H_ +#define _MCI_H_ + +/* MCI indirect access definitions */ +#define MCI_MAX_UNIT_ID 2 +/* SoC RFU / IHBx4 Control */ +#define MCIX4_REG_START_ADDRESS_REG(unit_id) (MVEBU_REGS_BASE + 0x6F4218 + (unit_id * 0x20)) +#define MCI_REMAP_OFF_SHIFT 8 + +/* /HB /Units /Direct_regs /Direct regs /Configuration Register Write/Read Data Register */ +#define MCI_WRITE_READ_DATA_REG(mci_index) MVEBU_MCI_REG_BASE_REMAP(mci_index) +/* /HB /Units /Direct_regs /Direct regs /Configuration Register Access Command Register */ +#define MCI_ACCESS_CMD_REG(mci_index) (MVEBU_MCI_REG_BASE_REMAP(mci_index) + 0x4) +/* Access Command fields : + * bit[3:0] - Sub command: 1 => Periferal Config Register Read, + * 0 => Periferal Config Refister Write, + * 2 => Periferal Assign ID request, + * 3 => Circular Config Write + * bit[5] - 1 => Local (same chip access) 0 => Remote + * bit[15:8] - Destination hop ID. Put Global ID (GID) here (see scheme below). + * bit[23:22] - 0x3 IHB PHY REG address space, 0x0 IHB Controller space + * bit[21:16] - Low 6 bits of offset. Hight 2 bits are taken from bit[28:27] + * of IHB_PHY_CTRL (must be set before any PHY register access occures): + * /IHB_REG /IHB_REGInterchip Hopping Bus Registers /IHB Version Control Register + * + * ixi_ihb_top IHB PHY + * AXI ----------------------------- ------------- + * <--| axi_hb_top | ihb_pipe_top |-->| | + * -->| GID=1 | GID=0 |<--| | + * ----------------------------- ------------- + */ +#define MCI_INDIRECT_CTRL_READ_CMD 0x1 +#define MCI_INDIRECT_CTRL_ASSIGN_CMD 0x2 +#define MCI_INDIRECT_CTRL_CIRCULAR_CMD 0x3 +#define MCI_INDIRECT_CTRL_LOCAL_PKT (1 << 5) +#define MCI_INDIRECT_CTRL_CMD_DONE_OFFSET 6 +#define MCI_INDIRECT_CTRL_CMD_DONE (1 << MCI_INDIRECT_CTRL_CMD_DONE_OFFSET) +#define MCI_INDIRECT_CTRL_DATA_READY_OFFSET 7 +#define MCI_INDIRECT_CTRL_DATA_READY (1 << MCI_INDIRECT_CTRL_DATA_READY_OFFSET) +#define MCI_INDIRECT_CTRL_HOPID_OFFSET 8 +#define MCI_INDIRECT_CTRL_HOPID(id) (((id) & 0xFF) << MCI_INDIRECT_CTRL_HOPID_OFFSET) +#define MCI_INDIRECT_CTRL_REG_CHIPID_OFFSET 16 +#define MCI_INDIRECT_REG_CTRL_ADDR(reg_num) (reg_num << MCI_INDIRECT_CTRL_REG_CHIPID_OFFSET) +/* PHY access domain */ +#define MCI_INDIRECT_CTRL_PHY_ACCESS_EN (0xC0 << MCI_INDIRECT_CTRL_REG_CHIPID_OFFSET) +/* Hop ID values */ +#define GID_IHB_PIPE 0 +#define GID_AXI_HB 1 +#define GID_IHB_EXT 2 + + +#define MCI_DID_GLOBAL_ASSIGNMENT_REQUEST_REG 0x2 +/* Target MCi Local ID (LID, which is = self DID) */ +#define MCI_DID_GLOBAL_ASSIGN_REQ_MCI_LOCAL_ID(val) (((val) & 0xFF) << 16) +/* Bits [15:8]: Number of MCis on chip of target MCi */ +#define MCI_DID_GLOBAL_ASSIGN_REQ_MCI_COUNT(val) (((val) & 0xFF) << 8) +/* Bits [7:0]: Number of hops on chip of target MCi */ +#define MCI_DID_GLOBAL_ASSIGN_REQ_HOPS_NUM(val) (((val) & 0xFF) << 0) + +/* IHB_REG domain registers */ +/* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers/ + * Rx Memory Configuration Register (RX_MEM_CFG) */ +#define MCI_CTRL_RX_MEM_CFG_REG_NUM 0x0 +#define MCI_CTRL_RX_TX_MEM_CFG_RQ_THRESH(val) (((val) & 0xFF) << 24) +#define MCI_CTRL_RX_TX_MEM_CFG_PQ_THRESH(val) (((val) & 0xFF) << 16) +#define MCI_CTRL_RX_TX_MEM_CFG_NQ_THRESH(val) (((val) & 0xFF) << 8) +#define MCI_CTRL_RX_TX_MEM_CFG_DELTA_THRESH(val) (((val) & 0xF) << 4) +#define MCI_CTRL_RX_TX_MEM_CFG_RTC(val) (((val) & 0x3) << 2) +#define MCI_CTRL_RX_TX_MEM_CFG_WTC(val) (((val) & 0x3) << 0) +#define MCI_CTRL_RX_MEM_CFG_REG_DEF_VAL (MCI_CTRL_RX_TX_MEM_CFG_RQ_THRESH(0x8) | \ + MCI_CTRL_RX_TX_MEM_CFG_PQ_THRESH(0x8) | \ + MCI_CTRL_RX_TX_MEM_CFG_NQ_THRESH(0x8) | \ + MCI_CTRL_RX_TX_MEM_CFG_DELTA_THRESH(3) | \ + MCI_CTRL_RX_TX_MEM_CFG_RTC(1) | \ + MCI_CTRL_RX_TX_MEM_CFG_WTC(1)) + + +/* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers/ + * Tx Memory Configuration Register (TX_MEM_CFG) */ +#define MCI_CTRL_TX_MEM_CFG_REG_NUM 0x1 +/* field mapping for TX mem config register are the as for RX register - see register above */ +#define MCI_CTRL_TX_MEM_CFG_REG_DEF_VAL (MCI_CTRL_RX_TX_MEM_CFG_RQ_THRESH(0x20) | \ + MCI_CTRL_RX_TX_MEM_CFG_PQ_THRESH(0x20) | \ + MCI_CTRL_RX_TX_MEM_CFG_NQ_THRESH(0x20) | \ + MCI_CTRL_RX_TX_MEM_CFG_DELTA_THRESH(2) | \ + MCI_CTRL_RX_TX_MEM_CFG_RTC(1) | \ + MCI_CTRL_RX_TX_MEM_CFG_WTC(1)) + +/* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers /IHB Link CRC Control */ +/* MCi Link CRC Control Register (MCi_CRC_CTRL) */ +#define MCI_LINK_CRC_CTRL_REG_NUM 0x4 + +/* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers /IHB Status Register */ +/* MCi Status Register (MCi_STS) */ +#define MCI_CTRL_STATUS_REG_NUM 0x5 +#define MCI_CTRL_STATUS_REG_PHY_READY (1 << 12) +#define MCI_CTRL_STATUS_REG_LINK_PRESENT (1 << 15) +#define MCI_CTRL_STATUS_REG_PHY_CID_VIO_OFFSET 24 +#define MCI_CTRL_STATUS_REG_PHY_CID_VIO_MASK (0xF << MCI_CTRL_STATUS_REG_PHY_CID_VIO_OFFSET) +/* Expected successful Link result, including reserved bit */ +#define MCI_CTRL_PHY_READY (MCI_CTRL_STATUS_REG_PHY_READY | \ + MCI_CTRL_STATUS_REG_LINK_PRESENT | \ + MCI_CTRL_STATUS_REG_PHY_CID_VIO_MASK) + +/* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers/ + * MCi PHY Speed Settings Register (MCi_PHY_SETTING) */ +#define MCI_CTRL_MCI_PHY_SETTINGS_REG_NUM 0x8 +#define MCI_CTRL_MCI_PHY_SET_DLO_FIFO_FULL_TRESH(val) (((val) & 0xF) << 28) +#define MCI_CTRL_MCI_PHY_SET_PHY_MAX_SPEED(val) (((val) & 0xF) << 12) +#define MCI_CTRL_MCI_PHY_SET_PHYCLK_SEL(val) (((val) & 0xF) << 8) +#define MCI_CTRL_MCI_PHY_SET_REFCLK_FREQ_SEL(val) (((val) & 0xF) << 4) +#define MCI_CTRL_MCI_PHY_SET_AUTO_LINK_EN(val) (((val) & 0x1) << 1) +#define MCI_CTRL_MCI_PHY_SET_REG_DEF_VAL (MCI_CTRL_MCI_PHY_SET_DLO_FIFO_FULL_TRESH(0x3) | \ + MCI_CTRL_MCI_PHY_SET_PHY_MAX_SPEED(0x3) | \ + MCI_CTRL_MCI_PHY_SET_PHYCLK_SEL(0x2) | \ + MCI_CTRL_MCI_PHY_SET_REFCLK_FREQ_SEL(0x1)) + +/* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers /IHB Mode Config */ +#define MCI_CTRL_IHB_MODE_CFG_REG_NUM 0x25 +#define MCI_CTRL_IHB_MODE_HBCLK_DIV(val) ((val) & 0xFF) +#define MCI_CTRL_IHB_MODE_CHUNK_MOD_OFFSET 8 +#define MCI_CTRL_IHB_MODE_CHUNK_MOD (1 << MCI_CTRL_IHB_MODE_CHUNK_MOD_OFFSET) +#define MCI_CTRL_IHB_MODE_FWD_MOD_OFFSET 9 +#define MCI_CTRL_IHB_MODE_FWD_MOD (1 << MCI_CTRL_IHB_MODE_FWD_MOD_OFFSET) +#define MCI_CTRL_IHB_MODE_SEQFF_FINE_MOD(val) (((val) & 0xF) << 12) +#define MCI_CTRL_IHB_MODE_RX_COMB_THRESH(val) (((val) & 0xFF) << 16) +#define MCI_CTRL_IHB_MODE_TX_COMB_THRESH(val) (((val) & 0xFF) << 24) +#define MCI_CTRL_IHB_MODE_CFG_REG_DEF_VAL (MCI_CTRL_IHB_MODE_HBCLK_DIV(7) | \ + MCI_CTRL_IHB_MODE_FWD_MOD | \ + MCI_CTRL_IHB_MODE_SEQFF_FINE_MOD(0xF) | \ + MCI_CTRL_IHB_MODE_RX_COMB_THRESH(0x2D) | \ + MCI_CTRL_IHB_MODE_TX_COMB_THRESH(0x45)) + +#define MCI_CTRL_IHB_MODE_CFG_REG_DEF_VAL_A1 (MCI_CTRL_IHB_MODE_HBCLK_DIV(6) | \ + MCI_CTRL_IHB_MODE_FWD_MOD | \ + MCI_CTRL_IHB_MODE_SEQFF_FINE_MOD(0xF) | \ + MCI_CTRL_IHB_MODE_RX_COMB_THRESH(0x0b) | \ + MCI_CTRL_IHB_MODE_TX_COMB_THRESH(0x40)) +/* AXI_HB registers */ +#define MCI_AXI_ACCESS_DATA_REG_NUM 0x0 +#define MCI_AXI_ACCESS_PCIE_MODE 1 +#define MCI_AXI_ACCESS_CACHE_CHECK_OFFSET 5 +#define MCI_AXI_ACCESS_CACHE_CHECK (1 << MCI_AXI_ACCESS_CACHE_CHECK_OFFSET) +#define MCI_AXI_ACCESS_FORCE_POST_WR_OFFSET 6 +#define MCI_AXI_ACCESS_FORCE_POST_WR (1 << MCI_AXI_ACCESS_FORCE_POST_WR_OFFSET) +#define MCI_AXI_ACCESS_DISABLE_CLK_GATING_OFFSET 9 +#define MCI_AXI_ACCESS_DISABLE_CLK_GATING (1 << MCI_AXI_ACCESS_DISABLE_CLK_GATING_OFFSET) + +/* /HB /Units /HB_REG /HB_REGHopping Bus Registers /Window 0 Address Mask Register */ +#define MCI_HB_CTRL_WIN0_ADDRESS_MASK_REG_NUM 0x2 + +/* /HB /Units /HB_REG /HB_REGHopping Bus Registers /Window 0 Destination Register */ +#define MCI_HB_CTRL_WIN0_DESTINATION_REG_NUM 0x3 +#define MCI_HB_CTRL_WIN0_DEST_VALID_FLAG(val) (((val) & 0x1) << 16) +#define MCI_HB_CTRL_WIN0_DEST_ID(val) (((val) & 0xfF) << 0) + +/* /HB /Units /HB_REG /HB_REGHopping Bus Registers /Tx Control Register */ +#define MCI_HB_CTRL_TX_CTRL_REG_NUM 0xD +#define MCI_HB_CTRL_TX_CTRL_PCIE_MODE_OFFSET 24 +#define MCI_HB_CTRL_TX_CTRL_PCIE_MODE (1 << MCI_HB_CTRL_TX_CTRL_PCIE_MODE_OFFSET) +#define MCI_HB_CTRL_TX_CTRL_PRI_TH_QOS(val) (((val) & 0xF) << 12) +#define MCI_HB_CTRL_TX_CTRL_MAX_RD_CNT(val) (((val) & 0xF) << 6) +#define MCI_HB_CTRL_TX_CTRL_MAX_WR_CNT(val) (((val) & 0xF) << 0) + +/* HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers /IHB PHY Idle Control Register */ +#define MCI_PHY_P0_IDLE_CTRL_REG_NUM 0x6 +#define MCI_PHY_P0_IDLE_MIN_IDLE_COUNT_OFFSET 12 +#define MCI_PHY_P0_IDLE_MIN_IDLE_COUNT (0xF << MCI_PHY_P0_IDLE_MIN_IDLE_COUNT_OFFSET) +#define MCI_PHY_P0_IDLE_SW_PWR_REQ_EN_OFFSET 16 +#define MCI_PHY_P0_IDLE_SW_PWR_REQ_EN (1 << MCI_PHY_P0_IDLE_SW_PWR_REQ_EN_OFFSET) +#define MCI_PHY_P0_IDLE_SW_RETRAIN_MODE_OFFSET 20 +#define MCI_PHY_P0_IDLE_SW_RETRAIN_MODE (1 << MCI_PHY_P0_IDLE_SW_RETRAIN_MODE_OFFSET) + +/* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers /IHB Version Control Register */ +#define MCI_PHY_CTRL_REG_NUM 0x7 +#define MCI_PHY_CTRL_MCI_MINOR 0x6 /* BITS [3:0] */ +#define MCI_PHY_CTRL_MCI_MINOR_A1 0x8 /* BITS [3:0] */ +#define MCI_PHY_CTRL_MCI_MAJOR_OFFSET 4 +#define MCI_PHY_CTRL_MCI_MAJOR (1 << MCI_PHY_CTRL_MCI_MAJOR_OFFSET) +#define MCI_PHY_CTRL_MCI_SLEEP_REQ_OFFSET 11 +#define MCI_PHY_CTRL_MCI_SLEEP_REQ (1 << MCI_PHY_CTRL_MCI_SLEEP_REQ_OFFSET) +#define MCI_PHY_CTRL_MCI_PHY_MODE_OFFSET 24 /* Host=1 / Device=0 PHY mode */ +#define MCI_PHY_CTRL_MCI_PHY_MODE_HOST (1 << MCI_PHY_CTRL_MCI_PHY_MODE_OFFSET) +#define MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE_OFFSET 25 /* Register=1 / PWM=0 interface */ +#define MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE (1 << MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE_OFFSET) +#define MCI_PHY_CTRL_MCI_PHY_RESET_CORE_OFFSET 26 /* PHY code InReset=1 */ +#define MCI_PHY_CTRL_MCI_PHY_RESET_CORE (1 << MCI_PHY_CTRL_MCI_PHY_RESET_CORE_OFFSET) +#define MCI_PHY_CTRL_PHY_ADDR_MSB_OFFSET 27 +#define MCI_PHY_CTRL_PHY_ADDR_MSB(addr) (((addr) & 0x3) << MCI_PHY_CTRL_PHY_ADDR_MSB_OFFSET) +#define MCI_PHY_CTRL_PIDI_MODE_OFFSET 31 +#define MCI_PHY_CTRL_PIDI_MODE (1 << MCI_PHY_CTRL_PIDI_MODE_OFFSET) +/* /IHB_8G_X4_PHY_V /Units /Registers /PWM Control Register 2 */ +#define MCI_PHY_PWM2_REG_NUM 0x6 +#define PWM2_SPEED_V3_8G (3) +#define PWM2_SPEED_V2_4G (2) +#define PWM2_SPEED_V1_2G (1) +#define PWM2_SPEED_V0_1G (0) +#define PWM2_SPEED_FORCE_OFFSET 10 +#define PWM2_SPEED_FORCE (1 << PWM2_SPEED_FORCE_OFFSET) +#define PWM2_RX_LINE_EN_OFFSET 21 +#define PWM2_RX_LINE_EN (1 << PWM2_RX_LINE_EN_OFFSET) +#define PWM2_TX_LINE_EN_OFFSET 29 +#define PWM2_TX_LINE_EN (1 << PWM2_TX_LINE_EN_OFFSET) + +/* /IHB_8G_X4_PHY_V /Units /Registers /PWM Control Register 3 */ +#define MCI_PHY_PWM3_REG_NUM 0x7 +#define PWM3_LINK_ERROR_OFFSET 8 /* [11:8] : LINK_ERROR */ +#define PWM3_LINK_ERROR_MASK (0xF << PWM3_LINK_ERROR_OFFSET) +#define PWM3_NUM_OF_LANES_OFFSET 20 /* [20:22] : AUTO_NUMBER_OF_LANES */ +#define PWM3_NUM_OF_LANES_MASK (0x7 << PWM3_NUM_OF_LANES_OFFSET) +#define PWM3_LINK_SPEED_MASK 0x7 /* [3:0] AUTO_SPEED */ + +/* Number of times to wait for the MCI link ready after MCI configurations + * Normally takes 34-35 successive reads + */ +#define LINK_READY_TIMEOUT 100 + +enum mci_register_type { + MCI_REG_TYPE_PHY = 0, + MCI_REG_TYPE_CTRL, +}; + +void mci_remap_indirect_access_base(void); +int mci_initialize(int mci_index); + +#endif /* _MCI_H_ */ diff --git a/include/drivers/marvell/mochi/apn806_setup.h b/include/drivers/marvell/mochi/apn806_setup.h new file mode 100644 index 00000000..ca41269e --- /dev/null +++ b/include/drivers/marvell/mochi/apn806_setup.h @@ -0,0 +1,60 @@ +/* +* *************************************************************************** +* 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. +* +*************************************************************************** +*/ +#ifndef __APN806_SETUP_H__ +#define __APN806_SETUP_H__ + +#include + +#define APN806_REV_ID_A0 0 +#define APN806_REV_ID_A1 1 + +/* APN806 revision ID */ +#define MVEBU_CSS_GWD_CTRL_IIDR2_REG (MVEBU_REGS_BASE + 0x610FCC) +#define GWD_IIDR2_REV_ID_OFFSET 12 +#define GWD_IIDR2_REV_ID_MASK 0xF + +void apn806_init(void); + +static inline int apn806_rev_id_get(void) +{ + /* Returns: + * - 0 (APN806_REV_ID_A0) for A0 + * - 1 (APN806_REV_ID_A1) for A1 + */ + return (mmio_read_32(MVEBU_CSS_GWD_CTRL_IIDR2_REG) >> + GWD_IIDR2_REV_ID_OFFSET) & + GWD_IIDR2_REV_ID_MASK; +} + +#endif /* __APN806_SETUP_H__ */ diff --git a/include/drivers/marvell/mochi/cp110_setup.h b/include/drivers/marvell/mochi/cp110_setup.h new file mode 100644 index 00000000..6ccbaaa5 --- /dev/null +++ b/include/drivers/marvell/mochi/cp110_setup.h @@ -0,0 +1,59 @@ +/* +* *************************************************************************** +* 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. +* +*************************************************************************** +*/ +#ifndef __PLAT_CP110_H__ +#define __PLAT_CP110_H__ + +#define MVEBU_DEVICE_ID_REG (MVEBU_CP_DFX_BASE(0) + 0x40) +#define MVEBU_DEVICE_ID_OFFSET (0) +#define MVEBU_DEVICE_ID_MASK (0xffff << MVEBU_DEVICE_ID_OFFSET) +#define MVEBU_DEVICE_REV_OFFSET (16) +#define MVEBU_DEVICE_REV_MASK (0xf << MVEBU_DEVICE_REV_OFFSET) +#define MVEBU_70X0_DEV_ID (0x7040) +#define MVEBU_80X0_DEV_ID (0x8040) + +static inline uint32_t cp110_device_id_get(void) +{ + /* Returns: + * - MVEBU_70X0_DEV_ID for A70X0 family + * - MVEBU_80X0_DEV_ID for A80X0 family + */ + return (mmio_read_32(MVEBU_DEVICE_ID_REG) >> + MVEBU_DEVICE_ID_OFFSET) & + MVEBU_DEVICE_ID_MASK; +} + +void cp110_init(int cp_index); +void cp110_ble_init(int cp_index); + +#endif /* __PLAT_CP110_H__ */ diff --git a/include/drivers/marvell/rfu.h b/include/drivers/marvell/rfu.h new file mode 100644 index 00000000..1b09bb87 --- /dev/null +++ b/include/drivers/marvell/rfu.h @@ -0,0 +1,64 @@ +/* +* *************************************************************************** +* 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. +* +*************************************************************************** +*/ + +#ifndef _RFU_H_ +#define _RFU_H_ + +#include + +struct rfu_win { + uint32_t base_addr_high; + uint32_t base_addr_low; + uint32_t win_size_high; + uint32_t win_size_low; + uint32_t target_id; +}; + +enum rfu_target_ids { + MCI_0_TID = 0x0, + MCI_1_TID = 0x1, + MCI_2_TID = 0x2, + PIDI_TID = 0x3, + SPI_TID = 0x4, + STM_TID = 0x5, + BOOTROM_TID = 0x6, + RFU_MAX_TID +}; + +#define RFU_MAX_WIN_ID 7 + +int init_rfu(void); + +#endif /* _RFU_H_ */ + -- cgit