rockchip: support pwm regulator
BUG=None TEST=Boot Veyron Pinky and test the VDD_LOG Original-Change-Id: Ie2eef918e04ba0e13879e915b0b0bef44aef550e Original-Signed-off-by: huang lin <hl@rock-chips.com> Original-Reviewed-on: https://chromium-review.googlesource.com/219753 Original-Reviewed-by: Julius Werner <jwerner@chromium.org> Original-Commit-Queue: Julius Werner <jwerner@chromium.org> Change-Id: I444b47564d90b3480b351fdd8460e5b94e71927c (cherry picked from commit 4491d9c4037161fd8c4cc40856167bf73182fda6) Signed-off-by: Aaron Durbin <adurbin@chromium.org> Reviewed-on: http://review.coreboot.org/9240 Reviewed-by: Patrick Georgi <pgeorgi@google.com> Tested-by: build bot (Jenkins)
This commit is contained in:
parent
bbcffd9e25
commit
bfdd732b80
|
@ -28,11 +28,32 @@
|
||||||
#include <timestamp.h>
|
#include <timestamp.h>
|
||||||
#include <arch/cache.h>
|
#include <arch/cache.h>
|
||||||
#include <arch/exception.h>
|
#include <arch/exception.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
#include <vendorcode/google/chromeos/chromeos.h>
|
#include <vendorcode/google/chromeos/chromeos.h>
|
||||||
#include <soc/rockchip/rk3288/sdram.h>
|
#include <soc/rockchip/rk3288/sdram.h>
|
||||||
#include <soc/rockchip/rk3288/clock.h>
|
#include <soc/rockchip/rk3288/clock.h>
|
||||||
|
#include <soc/rockchip/rk3288/pwm.h>
|
||||||
|
#include <soc/rockchip/rk3288/grf.h>
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
|
|
||||||
|
static void regulate_vdd_log(unsigned int mv)
|
||||||
|
{
|
||||||
|
unsigned int duty_ns;
|
||||||
|
const u32 period_ns = 2000; /* pwm period: 2000ns */
|
||||||
|
const u32 max_regulator_mv = 1350; /* 1.35V */
|
||||||
|
const u32 min_regulator_mv = 870; /* 0.87V */
|
||||||
|
|
||||||
|
writel(IOMUX_PWM1, &rk3288_grf->iomux_pwm1);
|
||||||
|
|
||||||
|
assert((mv >= min_regulator_mv) && (mv <= max_regulator_mv));
|
||||||
|
|
||||||
|
duty_ns = (max_regulator_mv - mv) * period_ns /
|
||||||
|
(max_regulator_mv - min_regulator_mv);
|
||||||
|
|
||||||
|
pwm_init(1, period_ns, duty_ns);
|
||||||
|
}
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
#if CONFIG_COLLECT_TIMESTAMPS
|
#if CONFIG_COLLECT_TIMESTAMPS
|
||||||
|
@ -49,6 +70,8 @@ void main(void)
|
||||||
|
|
||||||
console_init();
|
console_init();
|
||||||
|
|
||||||
|
/* vdd_log 1200mv is enough for ddr run 666Mhz */
|
||||||
|
regulate_vdd_log(1200);
|
||||||
#if CONFIG_COLLECT_TIMESTAMPS
|
#if CONFIG_COLLECT_TIMESTAMPS
|
||||||
before_dram_time = timestamp_get();
|
before_dram_time = timestamp_get();
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -51,6 +51,7 @@ romstage-y += gpio.c
|
||||||
romstage-y += spi.c
|
romstage-y += spi.c
|
||||||
romstage-y += media.c
|
romstage-y += media.c
|
||||||
romstage-y += sdram.c
|
romstage-y += sdram.c
|
||||||
|
romstage-y += pwm.c
|
||||||
|
|
||||||
ramstage-y += soc.c
|
ramstage-y += soc.c
|
||||||
ramstage-y += cbmem.c
|
ramstage-y += cbmem.c
|
||||||
|
@ -62,6 +63,7 @@ ramstage-y += spi.c
|
||||||
ramstage-y += gpio.c
|
ramstage-y += gpio.c
|
||||||
ramstage-y += media.c
|
ramstage-y += media.c
|
||||||
ramstage-y += rk808.c
|
ramstage-y += rk808.c
|
||||||
|
ramstage-y += pwm.c
|
||||||
ramstage-$(CONFIG_DRIVERS_UART) += uart.c
|
ramstage-$(CONFIG_DRIVERS_UART) += uart.c
|
||||||
|
|
||||||
$(objcbfs)/bootblock.raw.elf: $(objcbfs)/bootblock.elf
|
$(objcbfs)/bootblock.raw.elf: $(objcbfs)/bootblock.elf
|
||||||
|
|
|
@ -109,6 +109,32 @@ static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 2, 4);
|
||||||
/* m0 core axi clock div: clk = clk_src / (div_con + 1) */
|
/* m0 core axi clock div: clk = clk_src / (div_con + 1) */
|
||||||
#define M0_DIV_MSK (0xF)
|
#define M0_DIV_MSK (0xF)
|
||||||
|
|
||||||
|
/*******************CLKSEL1 BITS***************************/
|
||||||
|
/* pd bus clk pll sel: codec or general */
|
||||||
|
#define PD_BUS_SEL_PLL_MSK (1 << 15)
|
||||||
|
#define PD_BUS_SEL_CPLL (0 << 15)
|
||||||
|
#define PD_BUS_SEL_GPLL (1 << 15)
|
||||||
|
|
||||||
|
/* pd bus pclk div:
|
||||||
|
* pclk = pd_bus_aclk /(div + 1)
|
||||||
|
*/
|
||||||
|
#define PD_BUS_PCLK_DIV_SHIFT (12)
|
||||||
|
#define PD_BUS_PCLK_DIV_MSK (0x7 << 12)
|
||||||
|
|
||||||
|
/* pd bus hclk div:
|
||||||
|
* aclk_bus: hclk_bus = 1:1 or 2:1 or 4:1
|
||||||
|
*/
|
||||||
|
#define PD_BUS_HCLK_DIV_SHIFT (8)
|
||||||
|
#define PD_BUS_HCLK_DIV_MSK (0x3 << 8)
|
||||||
|
|
||||||
|
/* pd bus aclk div:
|
||||||
|
* pd_bus_aclk = pd_bus_src_clk /(div0 * div1)
|
||||||
|
*/
|
||||||
|
#define PD_BUS_ACLK_DIV0_SHIFT (3)
|
||||||
|
#define PD_BUS_ACLK_DIV0_MASK (0x1f << 3)
|
||||||
|
#define PD_BUS_ACLK_DIV1_SHIFT (0)
|
||||||
|
#define PD_BUS_ACLK_DIV1_MASK (0x7 << 0)
|
||||||
|
|
||||||
/*******************CLKSEL10 BITS***************************/
|
/*******************CLKSEL10 BITS***************************/
|
||||||
/* peripheral bus clk pll sel: codec or general */
|
/* peripheral bus clk pll sel: codec or general */
|
||||||
#define PERI_SEL_PLL_MSK (1 << 15)
|
#define PERI_SEL_PLL_MSK (1 << 15)
|
||||||
|
@ -133,6 +159,7 @@ static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 2, 4);
|
||||||
*/
|
*/
|
||||||
#define PERI_ACLK_DIV_SHIFT (0x0)
|
#define PERI_ACLK_DIV_SHIFT (0x0)
|
||||||
#define PERI_ACLK_DIV_MSK (0x1F)
|
#define PERI_ACLK_DIV_MSK (0x1F)
|
||||||
|
#define PERI_ACLK_DIV_SHIFT (0)
|
||||||
|
|
||||||
/*******************CLKSEL37 BITS***************************/
|
/*******************CLKSEL37 BITS***************************/
|
||||||
#define L2_DIV_MSK (0x7)
|
#define L2_DIV_MSK (0x7)
|
||||||
|
@ -186,8 +213,28 @@ static int rkclk_set_pll(u32 *pll_con, const struct pll_div *pll_div_cfg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO:
|
||||||
|
it should be replaced by lib.h function
|
||||||
|
'unsigned long log2(unsigned long x)'
|
||||||
|
*/
|
||||||
|
static unsigned int log2(unsigned int value)
|
||||||
|
{
|
||||||
|
unsigned int div = 0;
|
||||||
|
|
||||||
|
while (value != 1) {
|
||||||
|
div++;
|
||||||
|
value = ALIGN_UP(value, 2) / 2;
|
||||||
|
}
|
||||||
|
return div;
|
||||||
|
}
|
||||||
|
|
||||||
void rkclk_init(void)
|
void rkclk_init(void)
|
||||||
{
|
{
|
||||||
|
u32 aclk_div;
|
||||||
|
u32 hclk_div;
|
||||||
|
u32 pclk_div;
|
||||||
|
|
||||||
/* pll enter slow-mode */
|
/* pll enter slow-mode */
|
||||||
writel(RK_CLRSETBITS(APLL_MODE_MSK, APLL_MODE_SLOW)
|
writel(RK_CLRSETBITS(APLL_MODE_MSK, APLL_MODE_SLOW)
|
||||||
| RK_CLRSETBITS(GPLL_MODE_MSK, GPLL_MODE_SLOW)
|
| RK_CLRSETBITS(GPLL_MODE_MSK, GPLL_MODE_SLOW)
|
||||||
|
@ -231,16 +278,52 @@ void rkclk_init(void)
|
||||||
| RK_CLRSETBITS(PCLK_DBG_DIV_MSK, (3 << PCLK_DBG_DIV_SHIFT)),
|
| RK_CLRSETBITS(PCLK_DBG_DIV_MSK, (3 << PCLK_DBG_DIV_SHIFT)),
|
||||||
&cru_ptr->cru_clksel_con[37]);
|
&cru_ptr->cru_clksel_con[37]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pd_bus clock pll source selection and
|
||||||
|
* set up dependent divisors for PCLK/HCLK and ACLK clocks.
|
||||||
|
*/
|
||||||
|
aclk_div = GPLL_HZ / PD_BUS_ACLK_HZ - 1;
|
||||||
|
assert((aclk_div + 1) * PD_BUS_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f);
|
||||||
|
hclk_div = PD_BUS_ACLK_HZ / PD_BUS_HCLK_HZ - 1;
|
||||||
|
assert((hclk_div + 1) * PD_BUS_HCLK_HZ ==
|
||||||
|
PD_BUS_ACLK_HZ && (hclk_div < 0x4) && (hclk_div != 0x2));
|
||||||
|
|
||||||
|
pclk_div = PD_BUS_ACLK_HZ / PD_BUS_PCLK_HZ - 1;
|
||||||
|
assert((pclk_div + 1) * PD_BUS_PCLK_HZ ==
|
||||||
|
PD_BUS_ACLK_HZ && pclk_div < 0x7);
|
||||||
|
|
||||||
|
writel(RK_SETBITS(PD_BUS_SEL_GPLL)
|
||||||
|
| RK_CLRSETBITS(PD_BUS_PCLK_DIV_MSK,
|
||||||
|
pclk_div << PD_BUS_PCLK_DIV_SHIFT)
|
||||||
|
| RK_CLRSETBITS(PD_BUS_HCLK_DIV_MSK,
|
||||||
|
hclk_div << PD_BUS_HCLK_DIV_SHIFT)
|
||||||
|
| RK_CLRSETBITS(PD_BUS_ACLK_DIV0_MASK,
|
||||||
|
aclk_div << PD_BUS_ACLK_DIV0_SHIFT)
|
||||||
|
| RK_CLRSETBITS(PD_BUS_ACLK_DIV1_MASK, 0 << 0),
|
||||||
|
&cru_ptr->cru_clksel_con[1]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* peri clock pll source selection and
|
* peri clock pll source selection and
|
||||||
* set up dependent divisors for PCLK/HCLK and ACLK clocks.
|
* set up dependent divisors for PCLK/HCLK and ACLK clocks.
|
||||||
* peri clock select gpll, gpll clk = 594MHz
|
|
||||||
* aclk = 148.5MHz, hclk = 148.5Mhz, pclk = 74.25MHz
|
|
||||||
*/
|
*/
|
||||||
writel(RK_SETBITS(PERI_SEL_PLL_MSK)
|
aclk_div = GPLL_HZ / PERI_ACLK_HZ - 1;
|
||||||
| RK_CLRSETBITS(PERI_PCLK_DIV_MSK, 1 << PERI_PCLK_DIV_SHIFT)
|
assert((aclk_div + 1) * PERI_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f);
|
||||||
| RK_CLRSETBITS(PERI_HCLK_DIV_MSK, 0 << PERI_HCLK_DIV_SHIFT)
|
|
||||||
| RK_CLRSETBITS(PERI_ACLK_DIV_MSK, 3 << 0),
|
hclk_div = log2(PERI_ACLK_HZ / PERI_HCLK_HZ);
|
||||||
|
assert((1 << hclk_div) * PERI_HCLK_HZ ==
|
||||||
|
PERI_ACLK_HZ && (hclk_div < 0x4));
|
||||||
|
|
||||||
|
pclk_div = log2(PERI_ACLK_HZ / PERI_PCLK_HZ);
|
||||||
|
assert((1 << pclk_div) * PERI_PCLK_HZ ==
|
||||||
|
PERI_ACLK_HZ && (pclk_div < 0x4));
|
||||||
|
|
||||||
|
writel(RK_SETBITS(PERI_SEL_GPLL)
|
||||||
|
| RK_CLRSETBITS(PERI_PCLK_DIV_MSK,
|
||||||
|
pclk_div << PERI_PCLK_DIV_SHIFT)
|
||||||
|
| RK_CLRSETBITS(PERI_HCLK_DIV_MSK,
|
||||||
|
hclk_div << PERI_HCLK_DIV_SHIFT)
|
||||||
|
| RK_CLRSETBITS(PERI_ACLK_DIV_MSK,
|
||||||
|
aclk_div << PERI_ACLK_DIV_SHIFT),
|
||||||
&cru_ptr->cru_clksel_con[10]);
|
&cru_ptr->cru_clksel_con[10]);
|
||||||
|
|
||||||
/* PLL enter normal-mode */
|
/* PLL enter normal-mode */
|
||||||
|
|
|
@ -26,6 +26,14 @@
|
||||||
#define GPLL_HZ 594000000
|
#define GPLL_HZ 594000000
|
||||||
#define CPLL_HZ 384000000
|
#define CPLL_HZ 384000000
|
||||||
|
|
||||||
|
#define PD_BUS_ACLK_HZ 148500000
|
||||||
|
#define PD_BUS_HCLK_HZ 148500000
|
||||||
|
#define PD_BUS_PCLK_HZ 74250000
|
||||||
|
|
||||||
|
#define PERI_ACLK_HZ 148500000
|
||||||
|
#define PERI_HCLK_HZ 148500000
|
||||||
|
#define PERI_PCLK_HZ 74250000
|
||||||
|
|
||||||
void rkclk_init(void);
|
void rkclk_init(void);
|
||||||
void rkclk_configure_spi(unsigned int bus, unsigned int hz);
|
void rkclk_configure_spi(unsigned int bus, unsigned int hz);
|
||||||
void rkclk_ddr_reset(u32 ch, u32 ctl, u32 phy);
|
void rkclk_ddr_reset(u32 ch, u32 ctl, u32 phy);
|
||||||
|
|
|
@ -87,6 +87,7 @@ struct rk3288_grf_regs {
|
||||||
union {
|
union {
|
||||||
u32 gpio7a_iomux;
|
u32 gpio7a_iomux;
|
||||||
u32 iomux_pwm0;
|
u32 iomux_pwm0;
|
||||||
|
u32 iomux_pwm1;
|
||||||
};
|
};
|
||||||
u32 gpio7b_iomux;
|
u32 gpio7b_iomux;
|
||||||
union {
|
union {
|
||||||
|
@ -215,4 +216,5 @@ static struct rk3288_sgrf_regs * const rk3288_sgrf = (void *)GRF_SECURE_BASE;
|
||||||
2 << 2 | 2 << 0)
|
2 << 2 | 2 << 0)
|
||||||
#define IOMUX_EMMCPWREN RK_CLRSETBITS(0x3 << 2, 0x2 << 2)
|
#define IOMUX_EMMCPWREN RK_CLRSETBITS(0x3 << 2, 0x2 << 2)
|
||||||
#define IOMUX_EMMCCMD RK_CLRSETBITS(0x3f, 2 << 4 | 2 << 2 | 2 << 0)
|
#define IOMUX_EMMCCMD RK_CLRSETBITS(0x3f, 2 << 4 | 2 << 2 | 2 << 0)
|
||||||
|
#define IOMUX_PWM1 RK_SETBITS(1 << 2)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the coreboot project.
|
||||||
|
*
|
||||||
|
* Copyright 2014 Rockchip Inc.
|
||||||
|
*
|
||||||
|
* 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 <console/console.h>
|
||||||
|
#include <arch/io.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <timer.h>
|
||||||
|
#include <delay.h>
|
||||||
|
|
||||||
|
#include "addressmap.h"
|
||||||
|
#include "grf.h"
|
||||||
|
#include "soc.h"
|
||||||
|
#include "pwm.h"
|
||||||
|
#include "clock.h"
|
||||||
|
|
||||||
|
struct pwm_ctl {
|
||||||
|
u32 pwm_cnt;
|
||||||
|
u32 pwm_period_hpr;
|
||||||
|
u32 pwm_duty_lpr;
|
||||||
|
u32 pwm_ctrl;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rk3288_pwm_regs {
|
||||||
|
struct pwm_ctl pwm[4];
|
||||||
|
u32 intsts;
|
||||||
|
u32 int_en;
|
||||||
|
};
|
||||||
|
check_member(rk3288_pwm_regs, int_en, 0x44);
|
||||||
|
|
||||||
|
#define RK_PWM_DISABLE (0 << 0)
|
||||||
|
#define RK_PWM_ENABLE (1 << 0)
|
||||||
|
|
||||||
|
|
||||||
|
#define PWM_ONE_SHOT (0 << 1)
|
||||||
|
#define PWM_CONTINUOUS (1 << 1)
|
||||||
|
#define RK_PWM_CAPTURE (1 << 2)
|
||||||
|
|
||||||
|
#define PWM_DUTY_POSTIVE (1 << 3)
|
||||||
|
#define PWM_DUTY_NEGATIVE (0 << 3)
|
||||||
|
|
||||||
|
#define PWM_INACTIVE_POSTIVE (1 << 4)
|
||||||
|
#define PWM_INACTIVE_NEGATIVE (0 << 4)
|
||||||
|
|
||||||
|
#define PWM_OUTPUT_LEFT (0 << 5)
|
||||||
|
#define PWM_OUTPUT_CENTER (1 << 5)
|
||||||
|
|
||||||
|
#define PWM_LP_ENABLE (1 << 8)
|
||||||
|
#define PWM_LP_DISABLE (0 << 8)
|
||||||
|
|
||||||
|
#define PWM_SEL_SCALE_CLK (1 << 9)
|
||||||
|
#define PWM_SEL_SRC_CLK (0 << 9)
|
||||||
|
|
||||||
|
struct rk3288_pwm_regs *rk3288_pwm = (void *)RK_PWM0123_BASE;
|
||||||
|
|
||||||
|
void pwm_init(u32 id, u32 period_ns, u32 duty_ns)
|
||||||
|
{
|
||||||
|
unsigned long period, duty;
|
||||||
|
|
||||||
|
/*use rk pwm*/
|
||||||
|
writel(RK_SETBITS(1 << 0), &rk3288_grf->soc_con2);
|
||||||
|
|
||||||
|
writel(PWM_SEL_SRC_CLK | PWM_OUTPUT_LEFT | PWM_LP_DISABLE |
|
||||||
|
PWM_CONTINUOUS | PWM_DUTY_POSTIVE | PWM_INACTIVE_POSTIVE |
|
||||||
|
RK_PWM_DISABLE,
|
||||||
|
&rk3288_pwm->pwm[id].pwm_ctrl);
|
||||||
|
|
||||||
|
period = (PD_BUS_PCLK_HZ / 1000) * period_ns / USECS_PER_SEC;
|
||||||
|
duty = (PD_BUS_PCLK_HZ / 1000) * duty_ns / USECS_PER_SEC;
|
||||||
|
|
||||||
|
writel(period, &rk3288_pwm->pwm[id].pwm_period_hpr);
|
||||||
|
writel(duty, &rk3288_pwm->pwm[id].pwm_duty_lpr);
|
||||||
|
setbits_le32(&rk3288_pwm->pwm[id].pwm_ctrl, RK_PWM_ENABLE);
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the coreboot project.
|
||||||
|
*
|
||||||
|
* Copyright 2014 Rockchip Inc.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SOC_ROCKCHIP_RK3288_PWM_H__
|
||||||
|
#define __SOC_ROCKCHIP_RK3288_PWM_H__
|
||||||
|
|
||||||
|
void pwm_init(u32 id, u32 period_ns, u32 duty_ns);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue