blob: c472cc14e791e5829f1a1ed3cae4fcbb3faca93b [file] [log] [blame]
/*
* Copyright (C) 2015 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <arch/io.h>
#include <delay.h>
#include <console/console.h>
#include <soc/tz.h>
#include <soc/hw_init.h>
/*****************************************************************************
* TrustZone
*****************************************************************************/
#define IHOST_SCU_SECURE_ACCESS 0x19020054
#define SMAU_NIC_IDM_TZ_BASE 0x180150a0
#define SMAU_DDR_TZ_BASE 0x18015200
#define SMAU_FLASH0_TZ_BASE 0x18015300
#define SMAU_FLASH1_TZ_BASE 0x18015308
#define SMAU_FLASH2_TZ_BASE 0x18015310
#define SMAU_FLASH3_TZ_BASE 0x18015318
#define SMAU_TZ_BASE_ENABLE 0x00000001
#define CRMU_IPROC_ADDR_RANGE0_LOW 0x03024c30
#define CRMU_IPROC_ADDR_RANGE0_HIGH 0x03024c34
#define CRMU_ADDR_MASK 0xffffff00
#define CRMU_ADDR_VALID 0x00000001
#define CRMU_ADDR_START 0x03010000
#define CRMU_ADDR_END 0x03100000
static void scu_ns_config(void)
{
/*
* Enable NS SCU access to ARM global timer, private timer, and
* components
*/
write32((void *)IHOST_SCU_SECURE_ACCESS, 0xFFF);
}
static void smau_ns_config(void)
{
unsigned int val;
/* Disable SMAU NIC IDM TZ */
val = read32((void *)SMAU_NIC_IDM_TZ_BASE);
val &= ~SMAU_TZ_BASE_ENABLE;
write32((void *)SMAU_NIC_IDM_TZ_BASE, val);
/*
* Disable DDR TZ base
*
* This means the entire DDR is marked as NS
*
* NOTE: In the future, multiple regions of DDR may need to be marked
* as SECURE for secure OS and other TZ usages
*/
val = read32((void *)SMAU_DDR_TZ_BASE);
val &= ~SMAU_TZ_BASE_ENABLE;
write32((void *)SMAU_DDR_TZ_BASE, val);
/*
* Disable flash TZ support
*
* The entire flash is currently marked as NS
*
* NOTE: In the future, multiple regions of flash may need to be marked
* as SECURE for secure OS and other TZ firmware/data storage
*/
/* Flash 0: ROM */
val = read32((void *)SMAU_FLASH0_TZ_BASE);
val &= ~SMAU_TZ_BASE_ENABLE;
write32((void *)SMAU_FLASH0_TZ_BASE, val);
/* Flash 1: QSPI */
val = read32((void *)SMAU_FLASH1_TZ_BASE);
val &= ~SMAU_TZ_BASE_ENABLE;
write32((void *)SMAU_FLASH1_TZ_BASE, val);
/* Flash 2: NAND */
val = read32((void *)SMAU_FLASH2_TZ_BASE);
val &= ~SMAU_TZ_BASE_ENABLE;
write32((void *)SMAU_FLASH2_TZ_BASE, val);
/* Flash 3: PNOR */
val = read32((void *)SMAU_FLASH3_TZ_BASE);
val &= ~SMAU_TZ_BASE_ENABLE;
write32((void *)SMAU_FLASH3_TZ_BASE, val);
}
static void crmu_ns_config(void)
{
/*
* Currently open up the entire CRMU to allow iPROC NS access
*
* NOTE: In the future, we might want to protect particular CRMU
* sub-blocks to allow SECURE access only. That can be done by
* programing the CRMU IPROC address range registers. Up to 4 access
* windows can be created
*/
write32((void *)CRMU_IPROC_ADDR_RANGE0_LOW,
(CRMU_ADDR_START & CRMU_ADDR_MASK) | CRMU_ADDR_VALID);
write32((void *)CRMU_IPROC_ADDR_RANGE0_HIGH,
(CRMU_ADDR_END & CRMU_ADDR_MASK) | CRMU_ADDR_VALID);
}
static void tz_init(void)
{
/* Configure the Cygnus for non-secure access */
/* ARM Cortex A9 SCU NS access configuration */
scu_ns_config();
/* SMAU NS related configurations */
smau_ns_config();
/* CRMU NS related configurations */
crmu_ns_config();
/*
* Configure multiple masters and slaves to run in NS
*/
tz_set_non_virtual_slaves_security(0xFFFFFFFF, TZ_STATE_NON_SECURE);
tz_set_periph_security(0xFFFFFFFF, TZ_STATE_NON_SECURE);
tz_set_masters_security(0xFFFFFFFF, TZ_STATE_NON_SECURE);
tz_set_wrapper_security(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
TZ_STATE_NON_SECURE);
tz_set_cfg_slaves_security(0xFFFFFFFF, TZ_STATE_NON_SECURE);
tz_set_ext_slaves_security(0xFFFFFFFF, TZ_STATE_NON_SECURE);
/* configure sec peripherals to be accessed from non-secure world */
tz_set_sec_periphs_security(0xFFFFFFFF &
~(CYGNUS_sec_periph_APBz_sotp |
CYGNUS_sec_periph_APBz_tzpc),
TZ_STATE_NON_SECURE);
/* default sram to non-secure */
tz_set_sram_sec_region(0);
}
/*****************************************************************************
* DMAC
*****************************************************************************/
#define DMAC_M0_IDM_RESET_CONTROL 0x1810f800
#define DMAC_RESET_MASK 0x00000001
#define DMAC_RESET_TIMEOUT 1000
static void dmac_init(void)
{
unsigned int val, timeout;
/* bring the DMAC block out of reset */
val = read32((void *)DMAC_M0_IDM_RESET_CONTROL);
val |= DMAC_RESET_MASK;
write32((void *)DMAC_M0_IDM_RESET_CONTROL, val);
udelay(10);
val &= ~DMAC_RESET_MASK;
write32((void *)DMAC_M0_IDM_RESET_CONTROL, val);
timeout = 0;
while (read32((void *)DMAC_M0_IDM_RESET_CONTROL) & DMAC_RESET_MASK) {
udelay(1);
if (timeout++ > DMAC_RESET_TIMEOUT)
die("Failed to bring PL330 DMAC out of reset\n");
}
}
/*****************************************************************************
* Neon
*****************************************************************************/
#define CRU_CONTROL 0x1800e000
#define CRU_CONTROL_NEON_RESET_N 0x00000040
#define CRU_IHOST_PWRDWN_EN 0x1800e004
#define CRU_IHOST_PWRDWN_EN_CLAMPON_NEON 0x00100000
#define CRU_IHOST_PWRDWN_EN_PWRON_NEON 0x00200000
#define CRU_IHOST_PWRDWN_EN_PWROK_NEON 0x00400000
#define CRU_IHOST_PWRDWN_STATUS 0x1800e008
#define CRU_IHOST_PWRDWN_STATUS_PWRON_NEON 0x00200000
#define CRU_IHOST_PWRDWN_STATUS_PWROK_NEON 0x00400000
#define CRU_STATUS_DELAY_US 1
#define CRU_MAX_RETRY_COUNT 10
#define CRU_RETRY_INTVL_US 1
static void neon_init(void)
{
unsigned int i, val;
/* put Neon into reset */
val = read32((void *)CRU_CONTROL);
val &= ~CRU_CONTROL_NEON_RESET_N;
write32((void *)CRU_CONTROL, val);
/* assert the power on register bit */
val = read32((void *)CRU_IHOST_PWRDWN_EN);
val |= CRU_IHOST_PWRDWN_EN_PWRON_NEON;
write32((void *)CRU_IHOST_PWRDWN_EN, val);
/* wait for power on */
i = 0;
while (!(read32((void *)CRU_IHOST_PWRDWN_STATUS) &
CRU_IHOST_PWRDWN_STATUS_PWRON_NEON)) {
udelay(CRU_RETRY_INTVL_US);
if (i++ >= CRU_MAX_RETRY_COUNT)
die("Failed to ack NEON power on\n");
}
udelay(CRU_STATUS_DELAY_US);
/* assert the power ok register bit */
val = read32((void *)CRU_IHOST_PWRDWN_EN);
val |= CRU_IHOST_PWRDWN_EN_PWROK_NEON;
write32((void *)CRU_IHOST_PWRDWN_EN, val);
/* wait for power ok */
i = 0;
while (!(read32((void *)CRU_IHOST_PWRDWN_STATUS) &
CRU_IHOST_PWRDWN_STATUS_PWROK_NEON)) {
udelay(CRU_RETRY_INTVL_US);
if (i++ >= CRU_MAX_RETRY_COUNT)
die("Failed to ack NEON power ok\n");
}
udelay(CRU_STATUS_DELAY_US);
/* clamp off for the NEON block */
val = read32((void *)CRU_IHOST_PWRDWN_EN);
val &= ~CRU_IHOST_PWRDWN_EN_CLAMPON_NEON;
write32((void *)CRU_IHOST_PWRDWN_EN, val);
udelay(CRU_STATUS_DELAY_US);
/* bring NEON out of reset */
val = read32((void *)CRU_CONTROL);
val |= CRU_CONTROL_NEON_RESET_N;
write32((void *)CRU_CONTROL, val);
}
/*****************************************************************************
* PCIe
*****************************************************************************/
#define CRMU_PCIE_CFG 0x0301d0a0
#define PCIE0_LNK_PHY_IDDQ 0x00000004
#define PCIE1_LNK_PHY_IDDQ 0x00000400
static void pcie_init(void)
{
unsigned int val;
/*
* Force all AFEs of both PCIe0 and PCIe1 to be powered down, including
* pad biasing
*
* This brings down the PCIe interfaces to the lowest possible power
* mode
*/
val = read32((void *)CRMU_PCIE_CFG);
val |= PCIE1_LNK_PHY_IDDQ | PCIE0_LNK_PHY_IDDQ;
write32((void *)CRMU_PCIE_CFG, val);
}
/*****************************************************************************
* M0
*****************************************************************************/
#define CRMU_MCU_ACCESS_CONTROL 0x03024c00
#define CRMU_MCU_ACCESS_MODE_SECURE 0x2
static void M0_init(void)
{
/* Set M0 as a secure master */
write32((void *)CRMU_MCU_ACCESS_CONTROL, CRMU_MCU_ACCESS_MODE_SECURE);
}
/*****************************************************************************
* CCU
*****************************************************************************/
#define IHOST_PROC_CLK_WR_ACCESS 0x19000000
#define IHOST_PROC_CLK_POLICY_FREQ 0x19000008
#define IHOST_PROC_CLK_POLICY_CTL 0x1900000c
#define IHOST_PROC_CLK_POLICY0_MASK 0x19000010
#define IHOST_PROC_CLK_POLICY1_MASK 0x19000014
#define IHOST_PROC_CLK_POLICY2_MASK 0x19000018
#define IHOST_PROC_CLK_POLICY3_MASK 0x1900001c
#define IHOST_PROC_CLK_INTEN 0x19000020
#define IHOST_PROC_CLK_INTSTAT 0x19000024
#define IHOST_PROC_CLK_LVM_EN 0x19000034
#define IHOST_PROC_CLK_LVM0_3 0x19000038
#define IHOST_PROC_CLK_LVM4_7 0x1900003c
#define IHOST_PROC_CLK_VLT0_3 0x19000040
#define IHOST_PROC_CLK_VLT4_7 0x19000044
#define IHOST_PROC_CLK_BUS_QUIESC 0x19000100
#define IHOST_PROC_CLK_CORE0_CLKGATE 0x19000200
#define IHOST_PROC_CLK_CORE1_CLKGATE 0x19000204
#define IHOST_PROC_CLK_ARM_SWITCH_CLKGATE 0x19000210
#define IHOST_PROC_CLK_ARM_PERIPH_CLKGATE 0x19000300
#define IHOST_PROC_CLK_APB0_CLKGATE 0x19000400
#define IHOST_PROC_CLK_PL310_DIV 0x19000a00
#define IHOST_PROC_CLK_PL310_TRIGGER 0x19000a04
#define IHOST_PROC_CLK_ARM_SWITCH_DIV 0x19000a08
#define IHOST_PROC_CLK_ARM_SWITCH_TRIGGER 0x19000a0c
#define IHOST_PROC_CLK_APB_DIV 0x19000a10
#define IHOST_PROC_CLK_APB_DIV_TRIGGER 0x19000a14
#define IHOST_PROC_CLK_PLLARMA 0x19000c00
#define IHOST_PROC_CLK_PLLARMB 0x19000c04
#define IHOST_PROC_CLK_PLLARMC 0x19000c08
#define IHOST_PROC_CLK_PLLARMCTRL0 0x19000c0c
#define IHOST_PROC_CLK_PLLARMCTRL1 0x19000c10
#define IHOST_PROC_CLK_PLLARMCTRL2 0x19000c14
#define IHOST_PROC_CLK_PLLARMCTRL3 0x19000c18
#define IHOST_PROC_CLK_PLLARMCTRL4 0x19000c1c
#define IHOST_PROC_CLK_PLLARMCTRL5 0x19000c20
#define IHOST_PROC_CLK_PLLARM_OFFSET 0x19000c24
#define IHOST_PROC_CLK_ARM_DIV 0x19000e00
#define IHOST_PROC_CLK_ARM_SEG_TRG 0x19000e04
#define IHOST_PROC_CLK_ARM_SEG_TRG_OVERRIDE 0x19000e08
#define IHOST_PROC_CLK_PLL_DEBUG 0x19000e10
#define IHOST_PROC_CLK_ACTIVITY_MON1 0x19000e20
#define IHOST_PROC_CLK_ACTIVITY_MON2 0x19000e24
#define IHOST_PROC_CLK_CLKGATE_DBG 0x19000e40
#define IHOST_PROC_CLK_APB_CLKGATE_DBG1 0x19000e48
#define IHOST_PROC_CLK_CLKMON 0x19000e64
#define IHOST_PROC_CLK_POLICY_DBG 0x19000ec0
#define IHOST_PROC_CLK_TGTMASK_DBG1 0x19000ec4
#define IHOST_PROC_RST_WR_ACCESS 0x19000f00
#define IHOST_PROC_RST_SOFT_RSTN 0x19000f04
#define IHOST_PROC_RST_A9_CORE_SOFT_RSTN 0x19000f08
#define WR_ACCESS_PRIVATE_ACCESS_MODE 0x80000000
static uint32_t ccu_reg[] = {
IHOST_PROC_CLK_WR_ACCESS,
IHOST_PROC_CLK_POLICY_FREQ,
IHOST_PROC_CLK_POLICY_CTL,
IHOST_PROC_CLK_POLICY0_MASK,
IHOST_PROC_CLK_POLICY1_MASK,
IHOST_PROC_CLK_POLICY2_MASK,
IHOST_PROC_CLK_POLICY3_MASK,
IHOST_PROC_CLK_INTEN,
IHOST_PROC_CLK_INTSTAT,
IHOST_PROC_CLK_LVM_EN,
IHOST_PROC_CLK_LVM0_3,
IHOST_PROC_CLK_LVM4_7,
IHOST_PROC_CLK_VLT0_3,
IHOST_PROC_CLK_VLT4_7,
IHOST_PROC_CLK_BUS_QUIESC,
IHOST_PROC_CLK_CORE0_CLKGATE,
IHOST_PROC_CLK_CORE1_CLKGATE,
IHOST_PROC_CLK_ARM_SWITCH_CLKGATE,
IHOST_PROC_CLK_ARM_PERIPH_CLKGATE,
IHOST_PROC_CLK_APB0_CLKGATE,
IHOST_PROC_CLK_PL310_DIV,
IHOST_PROC_CLK_PL310_TRIGGER,
IHOST_PROC_CLK_ARM_SWITCH_DIV,
IHOST_PROC_CLK_ARM_SWITCH_TRIGGER,
IHOST_PROC_CLK_APB_DIV,
IHOST_PROC_CLK_APB_DIV_TRIGGER,
IHOST_PROC_CLK_PLLARMA,
IHOST_PROC_CLK_PLLARMB,
IHOST_PROC_CLK_PLLARMC,
IHOST_PROC_CLK_PLLARMCTRL0,
IHOST_PROC_CLK_PLLARMCTRL1,
IHOST_PROC_CLK_PLLARMCTRL2,
IHOST_PROC_CLK_PLLARMCTRL3,
IHOST_PROC_CLK_PLLARMCTRL4,
IHOST_PROC_CLK_PLLARMCTRL5,
IHOST_PROC_CLK_PLLARM_OFFSET,
IHOST_PROC_CLK_ARM_DIV,
IHOST_PROC_CLK_ARM_SEG_TRG,
IHOST_PROC_CLK_ARM_SEG_TRG_OVERRIDE,
IHOST_PROC_CLK_PLL_DEBUG,
IHOST_PROC_CLK_ACTIVITY_MON1,
IHOST_PROC_CLK_ACTIVITY_MON2,
IHOST_PROC_CLK_CLKGATE_DBG,
IHOST_PROC_CLK_APB_CLKGATE_DBG1,
IHOST_PROC_CLK_CLKMON,
IHOST_PROC_CLK_POLICY_DBG,
IHOST_PROC_CLK_TGTMASK_DBG1,
IHOST_PROC_RST_WR_ACCESS,
IHOST_PROC_RST_SOFT_RSTN,
IHOST_PROC_RST_A9_CORE_SOFT_RSTN
};
#define CCU_REG_TABLE_SIZE (sizeof(ccu_reg)/sizeof(ccu_reg[0]))
/* Set priv_access_mode field to unrestricted (0) */
static void ccu_init(void)
{
uint32_t val;
uint32_t i;
for (i = 0; i < CCU_REG_TABLE_SIZE; i++) {
val = read32((void *)(ccu_reg[i]));
val &= ~WR_ACCESS_PRIVATE_ACCESS_MODE;
write32((void *)(ccu_reg[i]), val);
}
}
/*****************************************************************************
* LCD
*****************************************************************************/
#define ASIU_TOP_CLK_GATING_CTRL 0x180aa024
#define ASIU_TOP_CLK_GATING_CTRL_LCD_CLK_GATE_EN 0x00000010
#define ASIU_TOP_CLK_GATING_CTRL_MIPI_DSI_CLK_GATE_EN 0x00000008
#define ASIU_TOP_CLK_GATING_CTRL_GFX_CLK_GATE_EN 0x00000001
#define ASIU_TOP_CLK_GATING_CTRL_AUD_CLK_GATE_EN 0x00000002
static void lcd_init(void)
{
unsigned int val;
/* make sure the LCD clock is ungated */
val = read32((void *)ASIU_TOP_CLK_GATING_CTRL);
val |= ASIU_TOP_CLK_GATING_CTRL_LCD_CLK_GATE_EN;
write32((void *)ASIU_TOP_CLK_GATING_CTRL, val);
}
/*******************************************************************
* Default priority settings in Cygnus
*
* Master Name Default Priority
* ==================== =================
* ihost_m0 12
* mhost0_m0 12
* mhost1_m0 ` 12
* pcie0_m0 9
* pcie0_m1 9
* cmicd_m0 7
* amac_m0 7
* amac_m1 7
* ext_m0 (LCD) 5
* ext_m1 (V3D) 5
* sdio_m0 3
* sdio_m1 3
* usb2h_m0 3
* usb2d_m0 3
* dmu_m0 3
* a9jtag_m0 0
*
*****************************************************************************/
#define AXIIC_EXT_M0_READ_QOS 0x1a057100
#define AXIIC_EXT_M0_READ_MASK 0x0000000f
#define AXIIC_EXT_M0_WRITE_QOS 0x1a057104
#define AXIIC_EXT_M0_WRITE_MASK 0x0000000f
static void lcd_qos_init(unsigned int qos)
{
unsigned int val;
val = read32((void *)AXIIC_EXT_M0_READ_QOS);
val &= ~AXIIC_EXT_M0_READ_MASK;
val |= (qos & AXIIC_EXT_M0_READ_MASK);
write32((void *)AXIIC_EXT_M0_READ_QOS, val);
val = read32((void *)AXIIC_EXT_M0_WRITE_QOS);
val &= ~AXIIC_EXT_M0_WRITE_MASK;
val |= (qos & AXIIC_EXT_M0_WRITE_MASK);
write32((void *)AXIIC_EXT_M0_WRITE_QOS, val);
}
/*****************************************************************************
* V3D
*****************************************************************************/
static void v3d_init(void)
{
unsigned int val;
/* make sure the V3D clock is ungated */
val = read32((void *)ASIU_TOP_CLK_GATING_CTRL);
val |= ASIU_TOP_CLK_GATING_CTRL_MIPI_DSI_CLK_GATE_EN |
ASIU_TOP_CLK_GATING_CTRL_GFX_CLK_GATE_EN;
write32((void *)ASIU_TOP_CLK_GATING_CTRL, val);
}
/*****************************************************************************
* Audio
*****************************************************************************/
#define CRMU_PLL_AON_CTRL 0x0301c020
#define CRMU_PLL_AON_CTRL_ASIU_AUDIO_GENPLL_PWRON_PLL 0x00000800
#define CRMU_PLL_AON_CTRL_ASIU_AUDIO_GENPLL_PWRON_BG 0x00000400
#define CRMU_PLL_AON_CTRL_ASIU_AUDIO_GENPLL_PWRON_LDO 0x00000200
#define CRMU_PLL_AON_CTRL_ASIU_AUDIO_GENPLL_ISO_IN 0x00000100
static void audio_init(void)
{
unsigned int val;
/* Ungate (enable) audio clock. */
val = read32((void *)ASIU_TOP_CLK_GATING_CTRL);
val |= ASIU_TOP_CLK_GATING_CTRL_AUD_CLK_GATE_EN;
write32((void *)ASIU_TOP_CLK_GATING_CTRL, val);
/* Power on audio GEN PLL, LDO, and BG. Input isolation = normal. */
val = read32((void *)CRMU_PLL_AON_CTRL);
val |= CRMU_PLL_AON_CTRL_ASIU_AUDIO_GENPLL_PWRON_BG;
val |= CRMU_PLL_AON_CTRL_ASIU_AUDIO_GENPLL_PWRON_LDO;
val |= CRMU_PLL_AON_CTRL_ASIU_AUDIO_GENPLL_PWRON_PLL;
val &= ~CRMU_PLL_AON_CTRL_ASIU_AUDIO_GENPLL_ISO_IN;
write32((void *)CRMU_PLL_AON_CTRL, val);
}
/*****************************************************************************
* SDIO
*****************************************************************************/
#define CRMU_SDIO_1P8_FAIL_CONTROL 0x0301c0a0
#define UHS1_18V_VREG_FAIL 0x00000001
#define SDIO_IDM0_IO_CONTROL_DIRECT 0x18116408
#define SDIO_IDM1_IO_CONTROL_DIRECT 0x18117408
#define SDIO_CMD_COMFLICT_DISABLE 0x00400000
#define SDIO_FEEDBACK_CLK_EN 0x00200000
#define SDIO_CLK_ENABLE 0x00000001
#define CDRU_SDIO0_IO_CONTROL 0x0301d144
#define CDRU_SDIO1_IO_CONTROL 0x0301d140
#define INPUT_DISABLE 0x00000080
#define SLEW_RATE_ENABLE 0x00000040
#define PULL_UP_ENABLE 0x00000020
#define PULL_DOWN_ENABLE 0x00000010
#define HYSTERESIS_ENABLE 0x00000008
#define SDIO_DEFAULT_DRIVE_STRENGTH 0x4 /* 8 mA */
#define SDIO_IDM0_IDM_RESET_CONTROL 0x18116800
#define SDIO_IDM1_IDM_RESET_CONTROL 0x18117800
#define SDIO_RESET_MASK 0x00000001
#define SDIO_RESET_TIMEOUT 1000
#define CRMU_SDIO_CONTROL0 0x0301d088
#define CRMU_SDIO_CONTROL1 0x0301d08c
#define CRMU_SDIO_CONTROL2 0x0301d090
#define CRMU_SDIO_CONTROL3 0x0301d094
#define CRMU_SDIO_CONTROL4 0x0301d098
#define CRMU_SDIO_CONTROL5 0x0301d09c
/*
* SDIO_CAPS_L
*
* Field Bit(s)
* ===========================
* DDR50 31
* SDR104 30
* SDR50 29
* SLOTTYPE 28:27
* ASYNCHIRQ 26
* SYSBUS64 25
* V18 24
* V3 23
* V33 22
* SUPRSM 21
* SDMA 20
* HSPEED 19
* ADMA2 18
* EXTBUSMED 17
* MAXBLK 16:15
* BCLK 14:7
* TOUT 6
* TOUTFREQ 5:0
*/
#define SDIO_CAPS_L 0xA17C0000
/*
* SDIO_CAPS_H
*
* Field Bit(s)
* ===========================
* reserved 31:20
* SPIBLOCKMODE 19
* SPIMODE_CAP 18
* CLOCKMULT 17:10
* RETUNE_MODE 9:8
* USETUNE_SDR50 7
* TMRCNT_RETUNE 6:3
* DRVR_TYPED 2
* DRVR_TYPEC 1
* DRVR_TYPEA 0
*/
#define SDIO_CAPS_H 0x000C0087
/*
* Preset value
*
* Field Bit(s)
* ===========================
* Driver Strength 12:11
* Clock Generator 10
* SDCLK Frequeency 9:0
*/
/*
* SDIO_PRESETVAL1
*
* Field Bit(s) Description
* ============================================================
* DDR50_PRESET 25:13 Preset Value for DDR50
* DEFAULT_PRESET 12:0 Preset Value for Default Speed
*/
#define SDIO_PRESETVAL1 0x01004004
/*
* SDIO_PRESETVAL2
*
* Field Bit(s) Description
* ============================================================
* HIGH_SPEED_PRESET 25:13 Preset Value for High Speed
* INIT_PRESET 12:0 Preset Value for Initialization
*/
#define SDIO_PRESETVAL2 0x01004100
/*
* SDIO_PRESETVAL3
*
* Field Bit(s) Description
* ============================================================
* SDR104_PRESET 25:13 Preset Value for SDR104
* SDR12_PRESET 12:0 Preset Value for SDR12
*/
#define SDIO_PRESETVAL3 0x00000004
/*
* SDIO_PRESETVAL4
*
* Field Bit(s) Description
* ============================================================
* SDR25_PRESET 25:13 Preset Value for SDR25
* SDR50_PRESET 12:0 Preset Value for SDR50
*/
#define SDIO_PRESETVAL4 0x01005001
static void sdio_ctrl_init(unsigned int idx)
{
unsigned int sdio_idm_io_control_direct_reg;
unsigned int cdru_sdio_io_control_reg;
unsigned int sdio_idm_reset_control_reg;
unsigned int val, timeout;
switch (idx) {
case 0:
sdio_idm_io_control_direct_reg = SDIO_IDM0_IO_CONTROL_DIRECT;
cdru_sdio_io_control_reg = CDRU_SDIO0_IO_CONTROL;
sdio_idm_reset_control_reg = SDIO_IDM0_IDM_RESET_CONTROL;
break;
case 1:
sdio_idm_io_control_direct_reg = SDIO_IDM1_IO_CONTROL_DIRECT;
cdru_sdio_io_control_reg = CDRU_SDIO1_IO_CONTROL;
sdio_idm_reset_control_reg = SDIO_IDM1_IDM_RESET_CONTROL;
break;
default:
return;
}
/*
* Disable the cmd conflict error interrupt and enable feedback clock
*/
val = read32((void *)sdio_idm_io_control_direct_reg);
val |= SDIO_CMD_COMFLICT_DISABLE | SDIO_FEEDBACK_CLK_EN |
SDIO_CLK_ENABLE;
write32((void *)sdio_idm_io_control_direct_reg, val);
/*
* Set drive strength, enable hysteresis and slew rate control
*/
val = SDIO_DEFAULT_DRIVE_STRENGTH |
HYSTERESIS_ENABLE | SLEW_RATE_ENABLE;
write32((void *)cdru_sdio_io_control_reg, val);
/* Reset SDIO controller */
val = read32((void *)sdio_idm_reset_control_reg);
val |= SDIO_RESET_MASK;
write32((void *)sdio_idm_reset_control_reg, SDIO_RESET_MASK);
udelay(10);
val &= ~SDIO_RESET_MASK;
write32((void *)sdio_idm_reset_control_reg, val);
timeout = 0;
while (read32((void *)sdio_idm_reset_control_reg) & SDIO_RESET_MASK) {
udelay(1);
if (timeout++ > SDIO_RESET_TIMEOUT)
die("Failed to bring SDIO out of reset\n");
}
}
static void sdio_init(void)
{
unsigned int val;
/*
* Configure SDIO host controller capabilities
* (common setting for all SDIO controllers)
*/
write32((void *)CRMU_SDIO_CONTROL0, SDIO_CAPS_H);
write32((void *)CRMU_SDIO_CONTROL1, SDIO_CAPS_L);
/*
* Configure SDIO host controller preset values
* (common setting for all SDIO controllers)
*/
write32((void *)CRMU_SDIO_CONTROL2, SDIO_PRESETVAL1);
write32((void *)CRMU_SDIO_CONTROL3, SDIO_PRESETVAL2);
write32((void *)CRMU_SDIO_CONTROL4, SDIO_PRESETVAL3);
write32((void *)CRMU_SDIO_CONTROL5, SDIO_PRESETVAL4);
/*
* The sdhci driver attempts to change the SDIO IO voltage for UHS-I
* cards by setting the EN1P8V in control2 register then checks the
* outcome by reading it back.
* Cygnus does not have an internal regulator for the SDIO IO voltage
* but can be configured to indicate success (leave EN1P8V set)
* or failure (clear EN1P8V).
*
* Clear CRMU_SDIO_UHS1_18V_VREG_FAIL in CRMU_SDIO_1P8_FAIL_CONTROL
* register to indicate success.
* (common setting for all SDIO controllers)
*/
val = read32((void *)CRMU_SDIO_1P8_FAIL_CONTROL);
val &= ~UHS1_18V_VREG_FAIL;
write32((void *)CRMU_SDIO_1P8_FAIL_CONTROL, val);
/*
* Initialize each SDIO controller
*/
sdio_ctrl_init(0);
sdio_ctrl_init(1);
}
void hw_init(void)
{
tz_init();
printk(BIOS_INFO, "trustzone initialized\n");
dmac_init();
printk(BIOS_INFO, "PL330 DMAC initialized\n");
lcd_init();
lcd_qos_init(15);
printk(BIOS_INFO, "LCD initialized\n");
v3d_init();
printk(BIOS_INFO, "V3D initialized\n");
audio_init();
printk(BIOS_INFO, "audio initialized\n");
neon_init();
printk(BIOS_INFO, "neon initialized\n");
pcie_init();
printk(BIOS_INFO, "PCIe initialized\n");
M0_init();
printk(BIOS_INFO, "M0 initialized\n");
ccu_init();
printk(BIOS_INFO, "CCU initialized\n");
sdio_init();
printk(BIOS_INFO, "SDIO initialized\n");
}