exynos5250: Get rid of the PWM timer code we shouldn't be using anymore

This code was left over from U-Boot and was superceded by the MCT.

Change-Id: Ia85e3b7281dcdd4740238dddd0dfc6f0ba2c94da
Signed-off-by: Gabe Black <gabeblack@google.com>
Reviewed-on: https://gerrit.chromium.org/gerrit/63778
Commit-Queue: Gabe Black <gabeblack@chromium.org>
Reviewed-by: Gabe Black <gabeblack@chromium.org>
Tested-by: Gabe Black <gabeblack@chromium.org>
Reviewed-on: http://review.coreboot.org/4401
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Georgi <patrick@georgi-clan.de>
This commit is contained in:
Gabe Black 2013-07-30 15:11:35 -07:00 committed by Patrick Georgi
parent 2c116febab
commit 9b764a0dcc
10 changed files with 33 additions and 363 deletions

View File

@ -14,7 +14,6 @@ bootblock-$(CONFIG_BOOTBLOCK_CONSOLE) += uart.c
endif endif
bootblock-y += wakeup.c bootblock-y += wakeup.c
bootblock-y += gpio.c bootblock-y += gpio.c
bootblock-$(CONFIG_BOOTBLOCK_CONSOLE) += pwm.c
bootblock-$(CONFIG_BOOTBLOCK_CONSOLE) += timer.c bootblock-$(CONFIG_BOOTBLOCK_CONSOLE) += timer.c
romstage-y += spi.c romstage-y += spi.c
@ -30,7 +29,6 @@ ifeq ($(CONFIG_CONSOLE_SERIAL_UART),y)
romstage-$(CONFIG_EARLY_CONSOLE) += uart.c romstage-$(CONFIG_EARLY_CONSOLE) += uart.c
endif endif
romstage-y += wakeup.c romstage-y += wakeup.c
romstage-y += pwm.c # needed by timer.c
romstage-y += gpio.c romstage-y += gpio.c
romstage-y += timer.c romstage-y += timer.c
romstage-y += i2c.c romstage-y += i2c.c
@ -46,7 +44,6 @@ ramstage-y += cpu.c
ramstage-y += tmu.c ramstage-y += tmu.c
ramstage-y += mct.c ramstage-y += mct.c
ramstage-y += monotonic_timer.c ramstage-y += monotonic_timer.c
ramstage-y += pwm.c # needed by timer.c
ramstage-y += timer.c ramstage-y += timer.c
ramstage-y += gpio.c ramstage-y += gpio.c
ramstage-y += i2c.c ramstage-y += i2c.c

View File

@ -610,9 +610,8 @@ int clock_epll_set_rate(unsigned long rate)
unsigned int epll_con, epll_con_k; unsigned int epll_con, epll_con_k;
unsigned int i; unsigned int i;
unsigned int lockcnt; unsigned int lockcnt;
unsigned int start; struct mono_time current, end;
struct exynos5_clock *clk = struct exynos5_clock *clk = samsung_get_base_clock();
samsung_get_base_clock();
epll_con = readl(&clk->epll_con0); epll_con = readl(&clk->epll_con0);
epll_con &= ~((EPLL_CON0_LOCK_DET_EN_MASK << epll_con &= ~((EPLL_CON0_LOCK_DET_EN_MASK <<
@ -646,14 +645,19 @@ int clock_epll_set_rate(unsigned long rate)
writel(epll_con, &clk->epll_con0); writel(epll_con, &clk->epll_con0);
writel(epll_con_k, &clk->epll_con1); writel(epll_con_k, &clk->epll_con1);
start = get_timer(0); timer_monotonic_get(&current);
end = current;
mono_time_add_msecs(&end, TIMEOUT_EPLL_LOCK);
while (!(readl(&clk->epll_con0) & while (!(readl(&clk->epll_con0) &
(0x1 << EXYNOS5_EPLLCON0_LOCKED_SHIFT))) { (0x1 << EXYNOS5_EPLLCON0_LOCKED_SHIFT))) {
if (get_timer(start) > TIMEOUT_EPLL_LOCK) { if (mono_time_after(&current, &end)) {
printk(BIOS_DEBUG, "%s: Timeout waiting for EPLL lock\n", __func__); printk(BIOS_DEBUG,
"%s: Timeout waiting for EPLL lock\n",
__func__);
return -1; return -1;
} }
timer_monotonic_get(&current);
} }
return 0; return 0;

View File

@ -73,7 +73,6 @@
#define EXYNOS5_SPI1_BASE 0x12D30000 #define EXYNOS5_SPI1_BASE 0x12D30000
#define EXYNOS5_I2C_BASE 0x12C60000 #define EXYNOS5_I2C_BASE 0x12C60000
#define EXYNOS5_SPI_BASE 0x12D20000 #define EXYNOS5_SPI_BASE 0x12D20000
#define EXYNOS5_PWMTIMER_BASE 0x12DD0000
#define EXYNOS5_SPI_ISP_BASE 0x131A0000 #define EXYNOS5_SPI_ISP_BASE 0x131A0000
#define EXYNOS5_I2S_BASE 0x12D60000 #define EXYNOS5_I2S_BASE 0x12D60000
#define EXYNOS5_GPIO_PART3_BASE 0x13400000 /* E00..H17 */ #define EXYNOS5_GPIO_PART3_BASE 0x13400000 /* E00..H17 */
@ -108,7 +107,6 @@
#define samsung_get_base_sromc() ((struct exynos5_sromc *)EXYNOS5_SROMC_BASE) #define samsung_get_base_sromc() ((struct exynos5_sromc *)EXYNOS5_SROMC_BASE)
#define samsung_get_base_swreset() ((struct exynos5_swreset *)EXYNOS5_SWRESET) #define samsung_get_base_swreset() ((struct exynos5_swreset *)EXYNOS5_SWRESET)
#define samsung_get_base_sysreg() ((struct exynos5_sysreg *)EXYNOS5_SYSREG_BASE) #define samsung_get_base_sysreg() ((struct exynos5_sysreg *)EXYNOS5_SYSREG_BASE)
#define samsung_get_base_timer() ((struct s5p_timer *)EXYNOS5_PWMTIMER_BASE)
#define samsung_get_base_uart() ((struct exynos5_uart *)EXYNOS5_UART_BASE) #define samsung_get_base_uart() ((struct exynos5_uart *)EXYNOS5_UART_BASE)
#define samsung_get_base_usb_phy() ((struct exynos5_usb_phy *)EXYNOS5_USBPHY_BASE) #define samsung_get_base_usb_phy() ((struct exynos5_usb_phy *)EXYNOS5_USBPHY_BASE)
#define samsung_get_base_usb_otg() ((struct exynos5_usb_otg *)EXYNOS5_USBOTG_BASE) #define samsung_get_base_usb_otg() ((struct exynos5_usb_otg *)EXYNOS5_USBOTG_BASE)

View File

@ -120,7 +120,7 @@ unsigned int s5p_dp_get_pll_lock_status(struct s5p_dp_device *dp)
int s5p_dp_init_analog_func(struct s5p_dp_device *dp) int s5p_dp_init_analog_func(struct s5p_dp_device *dp)
{ {
u32 reg; u32 reg;
u32 start; struct mono_time current, end;
struct exynos5_dp *base = dp->base; struct exynos5_dp *base = dp->base;
writel(0x00, &base->dp_phy_pd); writel(0x00, &base->dp_phy_pd);
@ -135,13 +135,17 @@ int s5p_dp_init_analog_func(struct s5p_dp_device *dp)
clrbits_le32(&base->dp_pll_ctl, DP_PLL_PD); clrbits_le32(&base->dp_pll_ctl, DP_PLL_PD);
start = get_timer(0); timer_monotonic_get(&current);
end = current;
mono_time_add_msecs(&end, PLL_LOCK_TIMEOUT);
while (s5p_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { while (s5p_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
if (get_timer(start) > PLL_LOCK_TIMEOUT) { if (mono_time_after(&current, &end)) {
printk(BIOS_ERR, "%s: PLL is not locked\n", printk(BIOS_ERR, "%s: PLL is not locked\n",
__func__); __func__);
return -1; return -1;
} }
timer_monotonic_get(&current);
} }
} }
@ -431,11 +435,14 @@ void s5p_dp_enable_video_master(struct s5p_dp_device *dp)
int s5p_dp_is_video_stream_on(struct s5p_dp_device *dp) int s5p_dp_is_video_stream_on(struct s5p_dp_device *dp)
{ {
u32 reg, i = 0; u32 reg, i = 0;
u32 start; struct mono_time current, end;
struct exynos5_dp *base = dp->base; struct exynos5_dp *base = dp->base;
/* Wait for 4 VSYNC_DET interrupts */ /* Wait for 4 VSYNC_DET interrupts */
start = get_timer(0); timer_monotonic_get(&current);
end = current;
mono_time_add_msecs(&end, STREAM_ON_TIMEOUT);
do { do {
reg = readl(&base->common_int_sta_1); reg = readl(&base->common_int_sta_1);
if (reg & VSYNC_DET) { if (reg & VSYNC_DET) {
@ -444,7 +451,8 @@ int s5p_dp_is_video_stream_on(struct s5p_dp_device *dp)
} }
if (i == 4) if (i == 4)
break; break;
} while (get_timer(start) <= STREAM_ON_TIMEOUT); timer_monotonic_get(&current);
} while (mono_time_before(&current, &end));
if (i != 4) { if (i != 4) {
printk(BIOS_DEBUG, "s5p_dp_is_video_stream_on timeout\n"); printk(BIOS_DEBUG, "s5p_dp_is_video_stream_on timeout\n");

View File

@ -26,7 +26,6 @@
#include <timer.h> #include <timer.h>
#include <delay.h> #include <delay.h>
#include <console/console.h> #include <console/console.h>
#include "timer.h"
#include "cpu.h" #include "cpu.h"
#include "power.h" #include "power.h"
#include "sysreg.h" #include "sysreg.h"
@ -411,20 +410,24 @@ static int s5p_dp_hw_link_training(struct s5p_dp_device *dp,
{ {
int pll_is_locked = 0; int pll_is_locked = 0;
u32 data; u32 data;
u32 start;
int lane; int lane;
struct mono_time current, end;
struct exynos5_dp *base = dp->base; struct exynos5_dp *base = dp->base;
/* Stop Video */ /* Stop Video */
clrbits_le32(&base->video_ctl_1, VIDEO_EN); clrbits_le32(&base->video_ctl_1, VIDEO_EN);
start = get_timer(0); timer_monotonic_get(&current);
end = current;
mono_time_add_msecs(&end, PLL_LOCK_TIMEOUT);
while ((pll_is_locked = s5p_dp_get_pll_lock_status(dp)) == PLL_UNLOCKED) { while ((pll_is_locked = s5p_dp_get_pll_lock_status(dp)) == PLL_UNLOCKED) {
if (get_timer(start) > PLL_LOCK_TIMEOUT) { if (mono_time_after(&current, &end)) {
/* Ignore this error, and try to continue */ /* Ignore this error, and try to continue */
printk(BIOS_ERR, "PLL is not locked yet.\n"); printk(BIOS_ERR, "PLL is not locked yet.\n");
break; break;
} }
timer_monotonic_get(&current);
} }
printk(BIOS_SPEW, "PLL is %slocked\n", printk(BIOS_SPEW, "PLL is %slocked\n",
pll_is_locked == PLL_LOCKED ? "": "not "); pll_is_locked == PLL_LOCKED ? "": "not ");

View File

@ -37,7 +37,6 @@ void timer_monotonic_get(struct mono_time *mt)
uint64_t usecs_elapsed; uint64_t usecs_elapsed;
if (!mono_counter.initialized) { if (!mono_counter.initialized) {
init_timer();
mono_counter.last_value = mct_raw_value(); mono_counter.last_value = mct_raw_value();
mono_counter.initialized = 1; mono_counter.initialized = 1;
} }

View File

@ -1,186 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2011 Samsung Electronics
*
* 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 "clk.h"
#include "cpu.h"
#include "periph.h"
#include "pwm.h"
int pwm_enable(int pwm_id)
{
struct s5p_timer *const pwm = samsung_get_base_timer();
unsigned long tcon;
tcon = readl(&pwm->tcon);
tcon |= TCON_START(pwm_id);
writel(tcon, &pwm->tcon);
return 0;
}
int pwm_check_enabled(int pwm_id)
{
const struct s5p_timer *pwm = samsung_get_base_timer();
const unsigned long tcon = readl(&pwm->tcon);
return tcon & TCON_START(pwm_id);
}
void pwm_disable(int pwm_id)
{
struct s5p_timer *const pwm = samsung_get_base_timer();
unsigned long tcon;
tcon = readl(&pwm->tcon);
tcon &= ~TCON_START(pwm_id);
writel(tcon, &pwm->tcon);
}
static unsigned long pwm_calc_tin(int pwm_id, unsigned long freq)
{
unsigned long tin_parent_rate;
unsigned int div;
tin_parent_rate = clock_get_periph_rate(PERIPH_ID_PWM0);
for (div = 2; div <= 16; div *= 2) {
if ((tin_parent_rate / (div << 16)) < freq)
return tin_parent_rate / div;
}
return tin_parent_rate / 16;
}
#define NS_IN_SEC 1000000000UL
int pwm_config(int pwm_id, int duty_ns, int period_ns)
{
struct s5p_timer *const pwm = samsung_get_base_timer();
unsigned int offset;
unsigned long tin_rate;
unsigned long tin_ns;
unsigned long frequency;
unsigned long tcon;
unsigned long tcnt;
unsigned long tcmp;
/*
* We currently avoid using 64bit arithmetic by using the
* fact that anything faster than 1GHz is easily representable
* by 32bits.
*/
if (period_ns > NS_IN_SEC || duty_ns > NS_IN_SEC || period_ns == 0)
return -1;
if (duty_ns > period_ns)
return -1;
frequency = NS_IN_SEC / period_ns;
/* Check to see if we are changing the clock rate of the PWM */
tin_rate = pwm_calc_tin(pwm_id, frequency);
tin_ns = NS_IN_SEC / tin_rate;
tcnt = period_ns / tin_ns;
/* Note, counters count down */
tcmp = duty_ns / tin_ns;
tcmp = tcnt - tcmp;
/* Update the PWM register block. */
offset = pwm_id * 3;
if (pwm_id < 4) {
writel(tcnt, &pwm->tcntb0 + offset);
writel(tcmp, &pwm->tcmpb0 + offset);
}
tcon = readl(&pwm->tcon);
tcon |= TCON_UPDATE(pwm_id);
if (pwm_id < 4)
tcon |= TCON_AUTO_RELOAD(pwm_id);
else
tcon |= TCON4_AUTO_RELOAD;
writel(tcon, &pwm->tcon);
tcon &= ~TCON_UPDATE(pwm_id);
writel(tcon, &pwm->tcon);
return 0;
}
int pwm_init(int pwm_id, int div, int invert)
{
u32 val;
struct s5p_timer *const pwm = samsung_get_base_timer();
unsigned long ticks_per_period;
unsigned int offset, prescaler;
/*
* Timer Freq(HZ) =
* PWM_CLK / { (prescaler_value + 1) * (divider_value) }
*/
val = readl(&pwm->tcfg0);
if (pwm_id < 2) {
prescaler = PRESCALER_0;
val &= ~0xff;
val |= (prescaler & 0xff);
} else {
prescaler = PRESCALER_1;
val &= ~(0xff << 8);
val |= (prescaler & 0xff) << 8;
}
writel(val, &pwm->tcfg0);
val = readl(&pwm->tcfg1);
val &= ~(0xf << MUX_DIV_SHIFT(pwm_id));
val |= (div & 0xf) << MUX_DIV_SHIFT(pwm_id);
writel(val, &pwm->tcfg1);
if (pwm_id == 4) {
/*
* TODO(sjg): Use this as a countdown timer for now. We count
* down from the maximum value to 0, then reset.
*/
ticks_per_period = -1UL;
} else {
const unsigned long pwm_hz = 1000;
unsigned long timer_rate_hz = clock_get_periph_rate(
PERIPH_ID_PWM0) / ((prescaler + 1) * (1 << div));
ticks_per_period = timer_rate_hz / pwm_hz;
}
/* set count value */
offset = pwm_id * 3;
writel(ticks_per_period, &pwm->tcntb0 + offset);
val = readl(&pwm->tcon) & ~(0xf << TCON_OFFSET(pwm_id));
if (invert && (pwm_id < 4))
val |= TCON_INVERTER(pwm_id);
writel(val, &pwm->tcon);
pwm_enable(pwm_id);
return 0;
}

View File

@ -1,70 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 Samsung Electronics
*
* 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 CPU_SAMSUNG_EXYNOS5250_PWM_H
#define CPU_SAMSUNG_EXYNOS5250_PWM_H
#define PRESCALER_0 (8 - 1) /* prescaler of timer 0, 1 */
#define PRESCALER_1 (16 - 1) /* prescaler of timer 2, 3, 4 */
/* Divider MUX */
#define MUX_DIV_1 0 /* 1/1 period */
#define MUX_DIV_2 1 /* 1/2 period */
#define MUX_DIV_4 2 /* 1/4 period */
#define MUX_DIV_8 3 /* 1/8 period */
#define MUX_DIV_16 4 /* 1/16 period */
#define MUX_DIV_SHIFT(x) (x * 4)
#define TCON_OFFSET(x) ((x + 1) * (!!x) << 2)
#define TCON_START(x) (1 << TCON_OFFSET(x))
#define TCON_UPDATE(x) (1 << (TCON_OFFSET(x) + 1))
#define TCON_INVERTER(x) (1 << (TCON_OFFSET(x) + 2))
#define TCON_AUTO_RELOAD(x) (1 << (TCON_OFFSET(x) + 3))
#define TCON4_AUTO_RELOAD (1 << 22)
struct s5p_timer {
unsigned int tcfg0;
unsigned int tcfg1;
unsigned int tcon;
unsigned int tcntb0;
unsigned int tcmpb0;
unsigned int tcnto0;
unsigned int tcntb1;
unsigned int tcmpb1;
unsigned int tcnto1;
unsigned int tcntb2;
unsigned int tcmpb2;
unsigned int tcnto2;
unsigned int tcntb3;
unsigned int tcmpb3;
unsigned int tcnto3;
unsigned int tcntb4;
unsigned int tcnto4;
unsigned int tintcstat;
};
int pwm_config(int pwm_id, int duty_ns, int period_ns);
int pwm_check_enabled(int pwm_id);
void pwm_disable(int pwm_id);
int pwm_enable(int pwm_id);
int pwm_init(int pwm_id, int div, int invert);
#endif

View File

@ -18,72 +18,14 @@
*/ */
#include <console/console.h> #include <console/console.h>
#include <arch/io.h>
#include <timer.h> #include <timer.h>
#include <delay.h> #include <delay.h>
#include "timer.h"
#include "pwm.h"
#include "clk.h" #include "clk.h"
#include "cpu.h"
static unsigned long long timer_reset_value;
static unsigned long lastinc;
/* macro to read the 16 bit timer */
static inline struct s5p_timer *s5p_get_base_timer(void)
{
return samsung_get_base_timer();
}
/**
* Read the countdown timer.
*
* This operates at 1MHz and counts downwards. It will wrap about every
* hour (2^32 microseconds).
*
* @return current value of timer
*/
static unsigned long timer_get_us_down(void)
{
struct s5p_timer *const timer = s5p_get_base_timer();
return readl(&timer->tcnto4);
}
void init_timer(void) void init_timer(void)
{ {
/* Timer may have been enabled in SPL */ mct_start();
if (!pwm_check_enabled(4)) {
/* PWM Timer 4 */
pwm_init(4, MUX_DIV_4, 0);
pwm_config(4, 100000, 100000);
pwm_enable(4);
/* Use this as the current monotonic time in us */
timer_reset_value = 0;
/* Use this as the last timer value we saw */
lastinc = timer_get_us_down();
}
}
/*
* timer without interrupts
*/
unsigned long get_timer(unsigned long base)
{
unsigned long now = timer_get_us_down();
/*
* Increment the time by the amount elapsed since the last read.
* The timer may have wrapped around, but it makes no difference to
* our arithmetic here.
*/
timer_reset_value += lastinc - now;
lastinc = now;
/* Divide by 1000 to convert from us to ms */
return timer_reset_value / 1000 - base;
} }
/* delay x useconds */ /* delay x useconds */

View File

@ -1,25 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright 2013 Google 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 CPU_SAMSUNG_EXYNOS5250_TIMER_H
#define CPU_SAMSUNG_EXYNOS5250_TIMER_H
unsigned long get_timer(unsigned long base);
#endif