Commit 778ef4e7 authored by Robin Gong's avatar Robin Gong Committed by Jason Liu

ENGR00181348-1 :sabresd pfuze support cpu internal LDO bypass

VDDCORE output directly from pfuze not internal anatop regulator,VDDCORE can
be adjust by pfuze regulator with deifferent cpu frequency, these patch should
be used with u-boot related patch, because LDO bypass is set on u-boot. u-boot
and kernel can be configured by CONFIG_MX6_INTER_LDO_BYPASS, by default it is
disabled, can be used on RevC. These code is put in arch/arm.
Signed-off-by: default avatarRobin Gong <B38343@freescale.com>
parent 3e440e5b
......@@ -172,4 +172,13 @@ config IMX_PCIE
bool "PCI Express support"
select PCI
config MX6_INTER_LDO_BYPASS
bool "Internal LDO in MX6Q/DL bypass"
depends on REGULATOR_PFUZE100 && CPU_FREQ_IMX && ARCH_MX6
default n
help
This is choosed for bypass internal LDO in MX6. If choose it, internal
LDO will replaced by external pmic regulator(e.g. pfuze100), VDDCORE
can be adjust automatically adjust by cpu frequency.
endif
......@@ -1470,7 +1470,11 @@ static struct platform_pwm_backlight_data mx6_sabresd_pwm_backlight_data = {
};
static struct mxc_dvfs_platform_data sabresd_dvfscore_data = {
#ifdef CONFIG_MX6_INTER_LDO_BYPASS
.reg_id = "VDDCORE",
#else
.reg_id = "cpu_vddgp",
#endif
.clk1_id = "cpu_clk",
.clk2_id = "gpc_dvfs_clk",
.gpc_cntr_offset = MXC_GPC_CNTR_OFFSET,
......@@ -1669,8 +1673,9 @@ static void __init mx6_sabresd_board_init(void)
imx6q_add_dma();
imx6q_add_dvfs_core(&sabresd_dvfscore_data);
#ifndef CONFIG_MX6_INTER_LDO_BYPASS
mx6_cpu_regulator_init();
#endif
imx6q_add_device_buttons();
/* enable sensor 3v3 and 1v8 */
......
......@@ -65,6 +65,14 @@
#define PFUZE100_SWBSTCON1_SWBSTMOD_M (0x3<<2)
#ifdef CONFIG_MX6_INTER_LDO_BYPASS
static struct regulator_consumer_supply sw1_consumers[] = {
{
.supply = "VDDCORE",
}
};
#endif
static struct regulator_consumer_supply sw2_consumers[] = {
{
.supply = "MICVDD",
......@@ -139,6 +147,11 @@ static struct regulator_init_data sw1a_init = {
.boot_on = 1,
.always_on = 1,
},
#ifdef CONFIG_MX6_INTER_LDO_BYPASS
.num_consumer_supplies = ARRAY_SIZE(sw1_consumers),
.consumer_supplies = sw1_consumers,
#endif
};
static struct regulator_init_data sw1b_init = {
......@@ -368,11 +381,6 @@ static int pfuze100_init(struct mc_pfuze *pfuze)
PFUZE100_SW1ASTANDBY_STBY_VAL);
if (ret)
goto err;
ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1BSTANDBY,
PFUZE100_SW1BSTANDBY_STBY_M,
PFUZE100_SW1BSTANDBY_STBY_VAL);
if (ret)
goto err;
ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1CSTANDBY,
PFUZE100_SW1CSTANDBY_STBY_M,
PFUZE100_SW1CSTANDBY_STBY_VAL);
......
......@@ -22,7 +22,7 @@
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <asm/smp_plat.h>
#include <asm/cpu.h>
......@@ -32,6 +32,47 @@
#define CLK32_FREQ 32768
#define NANOSECOND (1000 * 1000 * 1000)
/*If using cpu internal ldo bypass,we need config pmic by I2C in suspend
interface, but cpufreq driver as sys_dev is more later to suspend than I2C
driver, so we should implement another I2C operate function which isolated
with kernel I2C driver, these code is copied from u-boot*/
#ifdef CONFIG_MX6_INTER_LDO_BYPASS
#define IADR 0x00
#define IFDR 0x04
#define I2CR 0x08
#define I2SR 0x0c
#define I2DR 0x10
#define I2CR_IEN (1 << 7)
#define I2CR_IIEN (1 << 6)
#define I2CR_MSTA (1 << 5)
#define I2CR_MTX (1 << 4)
#define I2CR_TX_NO_AK (1 << 3)
#define I2CR_RSTA (1 << 2)
#define I2SR_ICF (1 << 7)
#define I2SR_IBB (1 << 5)
#define I2SR_IIF (1 << 1)
#define I2SR_RX_NO_AK (1 << 0)
#define I2C_MAX_TIMEOUT 100000
#define I2C_TIMEOUT_TICKET 1
#define CCM_CCGR2 0x70
/*#define MX6_I2CRAW_DEBUG*/
#ifdef MX6_I2CRAW_DEBUG
#define DPRINTF(args...) printk(args)
#else
#define DPRINTF(args...)
#endif
/*judge for pfuze regulator driver suspend or not, after pfuze regulator
suspend and before resume, should use i2c raw read/write to configure
voltage, it's safe enough, otherwise mxc_cpufreq_suspend will be failed
since i2c/pfuze have been suspend firstly.*/
extern int cpu_freq_suspend_in;
#endif
static int cpu_freq_khz_min;
static int cpu_freq_khz_max;
......@@ -51,11 +92,108 @@ extern int set_low_bus_freq(void);
extern int set_high_bus_freq(int high_bus_speed);
extern int low_freq_bus_used(void);
#ifdef CONFIG_MX6_INTER_LDO_BYPASS
static void __iomem *i2c_base;/*i2c for pmic*/
static void __iomem *ccm_base;/*ccm_base*/
static int wait_busy(void)
{
int timeout = I2C_MAX_TIMEOUT;
while ((!(readb(i2c_base + I2SR) & I2SR_IBB) && (--timeout))) {
writeb(0, i2c_base + I2SR);
udelay(I2C_TIMEOUT_TICKET);
}
return timeout ? timeout : (readb(i2c_base + I2SR) & I2SR_IBB);
}
static int wait_complete(void)
{
int timeout = I2C_MAX_TIMEOUT;
while ((!(readb(i2c_base + I2SR) & I2SR_ICF)) && (--timeout)) {
writeb(0, i2c_base + I2SR);
udelay(I2C_TIMEOUT_TICKET);
}
DPRINTF("%s:%x\n", __func__, readb(i2c_base + I2SR));
{
int i;
for (i = 0; i < 200; i++)
udelay(10);
}
writeb(0, i2c_base + I2SR); /* clear interrupt */
return timeout;
}
static int tx_byte(u8 byte)
{
writeb(byte, i2c_base + I2DR);
if (!wait_complete() || readb(i2c_base + I2SR) & I2SR_RX_NO_AK) {
DPRINTF("%s:%x <= %x\n", __func__, readb(i2c_base + I2SR),
byte);
return -1;
}
DPRINTF("%s:%x\n", __func__, byte);
return 0;
}
static int i2c_addr(unsigned char chip, u32 addr, int alen)
{
writeb(I2CR_IEN | I2CR_MSTA | I2CR_MTX, i2c_base + I2CR);
if (!wait_busy()) {
DPRINTF("%s:trigger start fail(%x)\n",
__func__, readb(i2c_base + I2SR));
return -1;
}
if (tx_byte(chip << 1) || (readb(i2c_base + I2SR) & I2SR_RX_NO_AK)) {
DPRINTF("%s:chip address cycle fail(%x)\n",
__func__, readb(i2c_base + I2SR));
return -1;
}
while (alen--)
if (tx_byte((addr >> (alen * 8)) & 0xff) ||
(readb(i2c_base + I2SR) & I2SR_RX_NO_AK)) {
DPRINTF("%s:device address cycle fail(%x)\n",
__func__, readb(i2c_base + I2SR));
return -1;
}
return 0;
}
static int i2c_write(unsigned char chip, u32 addr, int alen, unsigned char *buf,
int len)
{
int timeout = I2C_MAX_TIMEOUT;
DPRINTF("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n",
__func__, chip, addr, alen, len);
if (i2c_addr(chip, addr, alen))
return -1;
while (len--)
if (tx_byte(*buf++))
return -1;
writeb(I2CR_IEN, i2c_base + I2CR);
while (readb(i2c_base + I2SR) & I2SR_IBB && --timeout)
udelay(I2C_TIMEOUT_TICKET);
return 0;
}
#endif
int set_cpu_freq(int freq)
{
int i, ret = 0;
int org_cpu_rate;
int gp_volt = 0;
#ifdef CONFIG_MX6_INTER_LDO_BYPASS
unsigned char data;
#endif
org_cpu_rate = clk_get_rate(cpu_clk);
if (org_cpu_rate == freq)
......@@ -68,13 +206,56 @@ int set_cpu_freq(int freq)
if (gp_volt == 0)
return ret;
#ifdef CONFIG_MX6_INTER_LDO_BYPASS
if (cpu_freq_suspend_in) {
u32 value;
/*init I2C*/
value = __raw_readl(ccm_base + CCM_CCGR2);
__raw_writel(value | 0x300, ccm_base + CCM_CCGR2);
udelay(1);
value = readb(i2c_base + I2CR);
writeb(value | (1 << 7), i2c_base + I2CR);
value = readb(i2c_base + I2SR);
writeb(0, i2c_base + I2SR);
switch (freq) {
case 1200000000:/*1.275*/
data = 0x27;
break;
case 996000000:/*1.225V*/
data = 0x25;
break;
case 792000000:/*1.1V*/
case 672000000:
data = 0x20;
break;
case 396000000:/*0.95V*/
data = 0x1a;
break;
case 198000000:/*0.85V*/
data = 0x16;
break;
default:
printk(KERN_ERR "suspend freq error:%d!!!\n", freq);
break;
}
}
#endif
/*Set the voltage for the GP domain. */
if (freq > org_cpu_rate) {
if (low_bus_freq_mode)
set_high_bus_freq(0);
#ifdef CONFIG_MX6_INTER_LDO_BYPASS
if (cpu_freq_suspend_in) {
ret = i2c_write(0x8, 0x20, 1, &data, 1);
udelay(10);
} else
ret = regulator_set_voltage(cpu_regulator, gp_volt,
gp_volt);
#else
ret = regulator_set_voltage(cpu_regulator, gp_volt,
gp_volt);
#endif
if (ret < 0) {
printk(KERN_DEBUG "COULD NOT SET GP VOLTAGE!!!!\n");
return ret;
......@@ -89,8 +270,18 @@ int set_cpu_freq(int freq)
}
if (freq < org_cpu_rate) {
#ifdef CONFIG_MX6_INTER_LDO_BYPASS
if (cpu_freq_suspend_in) {
ret = i2c_write(0x8, 0x20, 1, &data, 1);
udelay(10);
} else
ret = regulator_set_voltage(cpu_regulator, gp_volt,
gp_volt);
#else
ret = regulator_set_voltage(cpu_regulator, gp_volt,
gp_volt);
#endif
if (ret < 0) {
printk(KERN_DEBUG "COULD NOT SET GP VOLTAGE!!!!\n");
return ret;
......@@ -184,8 +375,17 @@ static int mxc_cpufreq_suspend(struct cpufreq_policy *policy)
{
pre_suspend_rate = clk_get_rate(cpu_clk);
/* Set to max freq and voltage */
/*There should be *1000, but if fix the typo error, found
hard to pass streng test, it means we didn't move cpu freq
to highest freq in suspend, but if we choose bypass, we
have to do this, so use macro to decrease the impact on
released code, the 1Ghz issue should be fixed in the future*/
if (pre_suspend_rate != (imx_freq_table[0].frequency * 1000))
#ifdef CONFIG_MX6_INTER_LDO_BYPASS
set_cpu_freq(imx_freq_table[0].frequency * 1000);
#else
set_cpu_freq(imx_freq_table[0].frequency);
#endif
return 0;
}
......@@ -194,7 +394,6 @@ static int mxc_cpufreq_resume(struct cpufreq_policy *policy)
{
if (clk_get_rate(cpu_clk) != pre_suspend_rate)
set_cpu_freq(pre_suspend_rate);
return 0;
}
......@@ -301,8 +500,14 @@ static struct cpufreq_driver mxc_driver = {
.name = "imx",
};
extern void mx6_cpu_regulator_init(void);
static int __init mxc_cpufreq_driver_init(void)
{
#ifdef CONFIG_MX6_INTER_LDO_BYPASS
mx6_cpu_regulator_init();
i2c_base = MX6_IO_ADDRESS(MX6Q_I2C2_BASE_ADDR);
ccm_base = MX6_IO_ADDRESS(CCM_BASE_ADDR);
#endif
return cpufreq_register_driver(&mxc_driver);
}
......
/*
* Copyright (C) 1999 ARM Limited
* Copyright (C) 2000 Deep Blue Solutions Ltd
* Copyright 2006-2011 Freescale Semiconductor, Inc.
* Copyright 2006-2012 Freescale Semiconductor, Inc.
* Copyright 2008 Juergen Beisert, kernel@pengutronix.de
* Copyright 2009 Ilya Yanok, Emcraft Systems Ltd, yanok@emcraft.com
*
......@@ -41,7 +41,11 @@ void arch_reset(char mode, const char *cmd)
#ifdef CONFIG_ARCH_MX6
/* wait for reset to assert... */
#ifdef CONFIG_MX6_INTER_LDO_BYPASS
wcr_enable = 0x14; /*reset system by extern pmic*/
#else
wcr_enable = (1 << 2);
#endif
__raw_writew(wcr_enable, wdog_base);
/* errata TKT039676, SRS bit may be missed when
SRC sample it, need to write the wdog controller
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment