mirror of
https://github.com/hardkernel/linux.git
synced 2026-04-21 04:51:09 +09:00
rk2928: add board-rk2928-fpga.c timer.c, irqs.h add IRQ_DEBUG_UART define
This commit is contained in:
@@ -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
|
||||
|
||||
129
arch/arm/mach-rk2928/board-rk2928-fpga.c
Normal file
129
arch/arm/mach-rk2928/board-rk2928-fpga.c
Normal 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
|
||||
@@ -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)
|
||||
|
||||
215
arch/arm/mach-rk2928/timer.c
Normal file
215
arch/arm/mach-rk2928/timer.c
Normal 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
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user