blob: d8634bebbdf759286137b2bc17390cf92229c3cf [file] [log] [blame]
/*
* Copyright (C) 2012 Linaro Limited
* Mathieu Poirier <mathieu.poirier@linaro.org>
*
* Based on original code from Joakim Axelsson at ST-Ericsson
* (C) Copyright 2010 ST-Ericsson
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/io.h>
#include <asm/arch/prcmu.h>
#include <asm/arch/clock.h>
#include <asm/arch/hardware.h>
#include <asm/arch/hardware.h>
#define CPUID_DB8500V1 0x411fc091
#define CPUID_DB8500V2 0x412fc091
#define ASICID_DB8500V11 0x008500A1
#define CACHE_CONTR_BASE 0xA0412000
/* Cache controller register offsets
* as found in ARM's technical reference manual
*/
#define CACHE_INVAL_BY_WAY (CACHE_CONTR_BASE + 0x77C)
#define CACHE_LOCKDOWN_BY_D (CACHE_CONTR_BASE + 0X900)
#define CACHE_LOCKDOWN_BY_I (CACHE_CONTR_BASE + 0X904)
static unsigned int read_asicid(void);
static inline unsigned int read_cpuid(void)
{
unsigned int val;
/* Main ID register (MIDR) */
asm("mrc p15, 0, %0, c0, c0, 0"
: "=r" (val)
:
: "cc");
return val;
}
static int cpu_is_u8500v11(void)
{
return read_asicid() == ASICID_DB8500V11;
}
static int cpu_is_u8500v2(void)
{
return read_cpuid() == CPUID_DB8500V2;
}
static unsigned int read_asicid(void)
{
unsigned int *address;
if (cpu_is_u8500v2())
address = (void *) U8500_ASIC_ID_LOC_V2;
else
address = (void *) U8500_ASIC_ID_LOC_ED_V1;
return readl(address);
}
void cpu_cache_initialization(void)
{
unsigned int value;
/* invalidate all cache entries */
writel(0xFFFF, CACHE_INVAL_BY_WAY);
/* ways are set to '0' when they are totally
* cleaned and invalidated
*/
do {
value = readl(CACHE_INVAL_BY_WAY);
} while (value & 0xFF);
/* Invalidate register 9 D and I lockdown */
writel(0xFF, CACHE_LOCKDOWN_BY_D);
writel(0xFF, CACHE_LOCKDOWN_BY_I);
}
#ifdef CONFIG_ARCH_CPU_INIT
/*
* SOC specific cpu init
*/
int arch_cpu_init(void)
{
db8500_prcmu_init();
db8500_clocks_init();
return 0;
}
#endif /* CONFIG_ARCH_CPU_INIT */
#ifdef CONFIG_MMC
int u8500_mmc_power_init(void)
{
int ret;
int enable, voltage;
int ab8500_revision;
if (!cpu_is_u8500v11() && !cpu_is_u8500v2())
return 0;
/* Get AB8500 revision */
ret = ab8500_read(AB8500_MISC, AB8500_REV_REG);
if (ret < 0)
goto out;
ab8500_revision = ret;
/*
* On v1.1 HREF boards (HREF+), Vaux3 needs to be enabled for the SD
* card to work. This is done by enabling the regulators in the AB8500
* via PRCMU I2C transactions.
*
* This code is derived from the handling of AB8500_LDO_VAUX3 in
* ab8500_ldo_enable() and ab8500_ldo_disable() in Linux.
*
* Turn off and delay is required to have it work across soft reboots.
*/
/* Turn off (read-modify-write) */
ret = ab8500_read(AB8500_REGU_CTRL2,
AB8500_REGU_VRF1VAUX3_REGU_REG);
if (ret < 0)
goto out;
enable = ret;
/* Turn off */
ret = ab8500_write(AB8500_REGU_CTRL2,
AB8500_REGU_VRF1VAUX3_REGU_REG,
enable & ~LDO_VAUX3_ENABLE_MASK);
if (ret < 0)
goto out;
udelay(10 * 1000);
/* Set the voltage to 2.91 V or 2.9 V without overriding VRF1 value */
ret = ab8500_read(AB8500_REGU_CTRL2,
AB8500_REGU_VRF1VAUX3_SEL_REG);
if (ret < 0)
goto out;
voltage = ret;
if (ab8500_revision < 0x20) {
voltage &= ~LDO_VAUX3_SEL_MASK;
voltage |= LDO_VAUX3_SEL_2V9;
} else {
voltage &= ~LDO_VAUX3_V2_SEL_MASK;
voltage |= LDO_VAUX3_V2_SEL_2V91;
}
ret = ab8500_write(AB8500_REGU_CTRL2,
AB8500_REGU_VRF1VAUX3_SEL_REG, voltage);
if (ret < 0)
goto out;
/* Turn on the supply */
enable &= ~LDO_VAUX3_ENABLE_MASK;
enable |= LDO_VAUX3_ENABLE_VAL;
ret = ab8500_write(AB8500_REGU_CTRL2,
AB8500_REGU_VRF1VAUX3_REGU_REG, enable);
out:
return ret;
}
#endif /* CONFIG_MMC */