rk2928: add board-rk2928-fpga.c timer.c, irqs.h add IRQ_DEBUG_UART define

This commit is contained in:
黄涛
2012-07-09 20:03:06 +08:00
parent cfd51ed06f
commit 009df1d1a5
4 changed files with 350 additions and 0 deletions

View File

@@ -1,4 +1,7 @@
obj-y += common.o
obj-y += io.o
obj-y += reset.o
obj-y += timer.o
obj-$(CONFIG_PM) += pm.o
obj-$(CONFIG_MACH_RK2928_FPGA) += board-rk2928-fpga.o

View File

@@ -0,0 +1,129 @@
/* arch/arm/mach-rk2928/board-rk2928-fpga.c
*
* Copyright (C) 2012 ROCKCHIP, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/skbuff.h>
#include <linux/spi/spi.h>
#include <linux/mmc/host.h>
#include <linux/ion.h>
#include <linux/cpufreq.h>
#include <linux/clk.h>
#include <asm/setup.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/flash.h>
#include <asm/hardware/gic.h>
#include <mach/board.h>
#include <mach/hardware.h>
#include <mach/io.h>
#include <mach/gpio.h>
#include <linux/fb.h>
#include <linux/regulator/machine.h>
#include <linux/rfkill-rk.h>
#include <linux/sensor-dev.h>
static void __init rk2928_board_init(void)
{
}
static void __init rk2928_reserve(void)
{
board_mem_reserved();
}
#include <linux/clkdev.h>
struct clk {
const char *name;
unsigned long rate;
};
static struct clk xin24m = {
.name = "xin24m",
.rate = 24000000,
};
#define CLK(dev, con, ck) \
{ \
.dev_id = dev, \
.con_id = con, \
.clk = ck, \
}
static struct clk_lookup clks[] = {
CLK("rk30_i2c.0", "i2c", &xin24m),
CLK("rk30_i2c.1", "i2c", &xin24m),
CLK("rk30_i2c.2", "i2c", &xin24m),
CLK("rk30_i2c.3", "i2c", &xin24m),
CLK("rk29xx_spim.0", "spi", &xin24m),
CLK("rk29xx_spim.1", "spi", &xin24m),
};
void __init rk30_clock_init(void)
{
struct clk_lookup *lk;
for (lk = clks; lk < clks + ARRAY_SIZE(clks); lk++) {
clkdev_add(lk);
}
}
int clk_enable(struct clk *clk)
{
return 0;
}
EXPORT_SYMBOL(clk_enable);
void clk_disable(struct clk *clk)
{
}
EXPORT_SYMBOL(clk_disable);
unsigned long clk_get_rate(struct clk *clk)
{
return 24000000;
}
EXPORT_SYMBOL(clk_get_rate);
int clk_set_rate(struct clk *clk, unsigned long rate)
{
return 0;
}
EXPORT_SYMBOL(clk_set_rate);
int clk_set_parent(struct clk *clk, struct clk *parent)
{
return 0;
}
EXPORT_SYMBOL(clk_set_parent);
MACHINE_START(RK2928, "RK2928board")
.boot_params = PLAT_PHYS_OFFSET + 0x800,
.fixup = rk2928_fixup,
.reserve = &rk2928_reserve,
.map_io = rk2928_map_io,
.init_irq = rk2928_init_irq,
.timer = &rk2928_timer,
.init_machine = rk2928_board_init,
MACHINE_END

View File

@@ -55,6 +55,9 @@
//hhb@rock-chips.com this spi is used for fiq_debugger signal irq
#define IRQ_UART_SIGNAL 127
#if CONFIG_RK_DEBUG_UART >= 0 && CONFIG_RK_DEBUG_UART < 3
#define IRQ_DEBUG_UART (IRQ_UART0 + CONFIG_RK_DEBUG_UART)
#endif
#define NR_GIC_IRQS (4 * 32)
#define NR_GPIO_IRQS (4 * 32)

View File

@@ -0,0 +1,215 @@
/* linux/arch/arm/mach-rk2928/timer.c
*
* Copyright (C) 2012 ROCKCHIP, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/init.h>
#include <linux/time.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/clk.h>
#include <linux/clockchips.h>
#include <linux/io.h>
#include <asm/sched_clock.h>
#include <asm/mach/time.h>
#define TIMER_LOAD_COUNT 0x0000
#define TIMER_CUR_VALUE 0x0004
#define TIMER_CONTROL_REG 0x0008
#define TIMER_EOI 0x000C
#define TIMER_INT_STATUS 0x0010
#define TIMER_DISABLE 6
#define TIMER_ENABLE 3
#define TIMER_ENABLE_FREE_RUNNING 5
static inline void timer_write(u32 n, u32 v, u32 offset)
{
__raw_writel(v, RK2928_TIMER0_BASE + 0x2000 * n + offset);
dsb();
}
static inline u32 timer_read(u32 n, u32 offset)
{
return __raw_readl(RK2928_TIMER0_BASE + 0x2000 * n + offset);
}
#define RK_TIMER_ENABLE(n) timer_write(n, TIMER_ENABLE, TIMER_CONTROL_REG)
#define RK_TIMER_ENABLE_FREE_RUNNING(n) timer_write(n, TIMER_ENABLE_FREE_RUNNING, TIMER_CONTROL_REG)
#define RK_TIMER_DISABLE(n) timer_write(n, TIMER_DISABLE, TIMER_CONTROL_REG)
#define RK_TIMER_SETCOUNT(n, count) timer_write(n, count, TIMER_LOAD_COUNT)
#define RK_TIMER_GETCOUNT(n) timer_read(n, TIMER_LOAD_COUNT)
#define RK_TIMER_READVALUE(n) timer_read(n, TIMER_CUR_VALUE)
#define RK_TIMER_INT_CLEAR(n) timer_read(n, TIMER_EOI)
#define RK_TIMER_INT_STATUS(n) timer_read(n, TIMER_INT_STATUS)
#define TIMER_CLKEVT 0 /* timer0 */
#define IRQ_NR_TIMER_CLKEVT IRQ_TIMER0
#define TIMER_CLKEVT_NAME "timer0"
#define TIMER_CLKSRC 1 /* timer1 */
#define IRQ_NR_TIMER_CLKSRC IRQ_TIMER1
#define TIMER_CLKSRC_NAME "timer1"
static int rk2928_timer_set_next_event(unsigned long cycles, struct clock_event_device *evt)
{
do {
RK_TIMER_DISABLE(TIMER_CLKEVT);
RK_TIMER_SETCOUNT(TIMER_CLKEVT, cycles);
RK_TIMER_ENABLE(TIMER_CLKEVT);
} while (RK_TIMER_READVALUE(TIMER_CLKEVT) > cycles);
return 0;
}
static void rk2928_timer_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
{
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
rk2928_timer_set_next_event(24000000 / HZ - 1, evt);
break;
case CLOCK_EVT_MODE_RESUME:
case CLOCK_EVT_MODE_ONESHOT:
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
RK_TIMER_DISABLE(TIMER_CLKEVT);
break;
}
}
static struct clock_event_device rk2928_timer_clockevent = {
.name = TIMER_CLKEVT_NAME,
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.rating = 200,
.set_next_event = rk2928_timer_set_next_event,
.set_mode = rk2928_timer_set_mode,
};
static irqreturn_t rk2928_timer_clockevent_interrupt(int irq, void *dev_id)
{
struct clock_event_device *evt = dev_id;
RK_TIMER_INT_CLEAR(TIMER_CLKEVT);
if (evt->mode == CLOCK_EVT_MODE_ONESHOT)
RK_TIMER_DISABLE(TIMER_CLKEVT);
evt->event_handler(evt);
return IRQ_HANDLED;
}
static struct irqaction rk2928_timer_clockevent_irq = {
.name = TIMER_CLKEVT_NAME,
.flags = IRQF_DISABLED | IRQF_TIMER,
.handler = rk2928_timer_clockevent_interrupt,
.irq = IRQ_NR_TIMER_CLKEVT,
.dev_id = &rk2928_timer_clockevent,
};
static __init int rk2928_timer_init_clockevent(void)
{
struct clock_event_device *ce = &rk2928_timer_clockevent;
struct clk *clk = clk_get(NULL, TIMER_CLKEVT_NAME);
struct clk *pclk = clk_get(NULL, "pclk_" TIMER_CLKEVT_NAME);
struct clk *pclk_periph = clk_get(NULL, "pclk_periph");
clk_set_parent(clk, pclk_periph);
clk_enable(pclk);
clk_enable(clk);
RK_TIMER_DISABLE(TIMER_CLKEVT);
setup_irq(rk2928_timer_clockevent_irq.irq, &rk2928_timer_clockevent_irq);
ce->irq = rk2928_timer_clockevent_irq.irq;
ce->cpumask = cpu_all_mask;
clockevents_config_and_register(ce, clk_get_rate(clk), 0xF, 0xFFFFFFFF);
return 0;
}
static cycle_t rk2928_timer_read(struct clocksource *cs)
{
return ~RK_TIMER_READVALUE(TIMER_CLKSRC);
}
#define MASK (u32)~0
static struct clocksource rk2928_timer_clocksource = {
.name = TIMER_CLKSRC_NAME,
.rating = 200,
.read = rk2928_timer_read,
.mask = CLOCKSOURCE_MASK(32),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
static void __init rk2928_timer_init_clocksource(void)
{
static char err[] __initdata = KERN_ERR "%s: can't register clocksource!\n";
struct clocksource *cs = &rk2928_timer_clocksource;
struct clk *clk = clk_get(NULL, TIMER_CLKSRC_NAME);
struct clk *pclk = clk_get(NULL, "pclk_" TIMER_CLKSRC_NAME);
struct clk *pclk_periph = clk_get(NULL, "pclk_periph");
clk_set_parent(clk, pclk_periph);
clk_enable(pclk);
clk_enable(clk);
RK_TIMER_DISABLE(TIMER_CLKSRC);
clk_disable(clk);
RK_TIMER_SETCOUNT(TIMER_CLKSRC, 0xFFFFFFFF);
RK_TIMER_ENABLE_FREE_RUNNING(TIMER_CLKSRC);
clk_enable(clk);
if (clocksource_register_hz(cs, clk_get_rate(clk)))
printk(err, cs->name);
}
#ifdef CONFIG_HAVE_SCHED_CLOCK
static DEFINE_CLOCK_DATA(cd);
unsigned long long notrace sched_clock(void)
{
u32 cyc = ~RK_TIMER_READVALUE(TIMER_CLKSRC);
return cyc_to_sched_clock(&cd, cyc, MASK);
}
static void notrace rk2928_update_sched_clock(void)
{
u32 cyc = ~RK_TIMER_READVALUE(TIMER_CLKSRC);
update_sched_clock(&cd, cyc, MASK);
}
static void __init rk2928_sched_clock_init(void)
{
init_sched_clock(&cd, rk2928_update_sched_clock, 32, clk_get_rate(clk_get(NULL, TIMER_CLKSRC_NAME)));
}
#endif
static void __init rk2928_timer_init(void)
{
rk2928_timer_init_clocksource();
rk2928_timer_init_clockevent();
#ifdef CONFIG_HAVE_SCHED_CLOCK
rk2928_sched_clock_init();
#endif
}
struct sys_timer rk2928_timer = {
.init = rk2928_timer_init
};