Commit 5cccd37e authored by dmitry pervushin's avatar dmitry pervushin Committed by Russell King

[ARM] 5477/1: Freescale STMP platform support [6/10]

Sources: common STMP3xxx platform support
Signed-off-by: default avatardmitry pervushin <dpervushin@embeddedalley.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent e317872a
if ARCH_STMP3XXX
menu "Freescale STMP3xxx implementations"
choice
prompt "Select STMP3xxx chip family"
config ARCH_STMP37XX
bool "Freescale SMTP37xx"
select CPU_ARM926T
---help---
STMP37xx refers to 3700 through 3769 chips
config ARCH_STMP378X
bool "Freescale STMP378x"
select CPU_ARM926T
---help---
STMP378x refers to 3780 through 3789 chips
endchoice
choice
prompt "Select STMP3xxx board type"
config MACH_STMP37XX
depends on ARCH_STMP37XX
bool "Freescale STMP37xx development board"
config MACH_STMP378X
depends on ARCH_STMP378X
bool "Freescale STMP378x development board"
endchoice
endmenu
endif
#
# Makefile for the linux kernel.
#
# Object file lists.
obj-y += core.o timer.o irq.o dma.o clock.o pinmux.o
This diff is collapsed.
/*
* Clock control driver for Freescale STMP37XX/STMP378X - internal header file
*
* Author: Vitaly Wool <vital@embeddedalley.com>
*
* Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
* Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#ifndef __ARCH_ARM_STMX3XXX_CLOCK_H__
#define __ARCH_ARM_STMX3XXX_CLOCK_H__
#ifndef __ASSEMBLER__
struct clk_ops {
int (*enable) (struct clk *);
int (*disable) (struct clk *);
long (*get_rate) (struct clk *);
long (*round_rate) (struct clk *, u32);
int (*set_rate) (struct clk *, u32);
int (*set_parent) (struct clk *, struct clk *);
};
struct clk {
struct clk *parent;
u32 rate;
u32 flags;
u8 scale_shift;
u8 enable_shift;
u8 bypass_shift;
u8 busy_bit;
s8 usage;
int enable_wait;
int enable_negate;
u32 saved_div;
void __iomem *enable_reg;
void __iomem *scale_reg;
void __iomem *bypass_reg;
void __iomem *busy_reg;
struct clk_ops *ops;
};
#endif /* __ASSEMBLER__ */
/* Flags */
#define RATE_PROPAGATES (1<<0)
#define NEEDS_INITIALIZATION (1<<1)
#define PARENT_SET_RATE (1<<2)
#define FIXED_RATE (1<<3)
#define ENABLED (1<<4)
#define NEEDS_SET_PARENT (1<<5)
#endif
/*
* Freescale STMP37XX/STMP378X core routines
*
* Embedded Alley Solutions, Inc <source@embeddedalley.com>
*
* Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
* Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
#include <mach/stmp3xxx.h>
#include <mach/dma.h>
#include <mach/regs-clkctrl.h>
static int __stmp3xxx_reset_block(void __iomem *hwreg, int just_enable)
{
u32 c;
int timeout;
/* the process of software reset of IP block is done
in several steps:
- clear SFTRST and wait for block is enabled;
- clear clock gating (CLKGATE bit);
- set the SFTRST again and wait for block is in reset;
- clear SFTRST and wait for reset completion.
*/
c = __raw_readl(hwreg);
c &= ~(1<<31); /* clear SFTRST */
__raw_writel(c, hwreg);
for (timeout = 1000000; timeout > 0; timeout--)
/* still in SFTRST state ? */
if ((__raw_readl(hwreg) & (1<<31)) == 0)
break;
if (timeout <= 0) {
printk(KERN_ERR"%s(%p): timeout when enabling\n",
__func__, hwreg);
return -ETIME;
}
c = __raw_readl(hwreg);
c &= ~(1<<30); /* clear CLKGATE */
__raw_writel(c, hwreg);
if (!just_enable) {
c = __raw_readl(hwreg);
c |= (1<<31); /* now again set SFTRST */
__raw_writel(c, hwreg);
for (timeout = 1000000; timeout > 0; timeout--)
/* poll until CLKGATE set */
if (__raw_readl(hwreg) & (1<<30))
break;
if (timeout <= 0) {
printk(KERN_ERR"%s(%p): timeout when resetting\n",
__func__, hwreg);
return -ETIME;
}
c = __raw_readl(hwreg);
c &= ~(1<<31); /* clear SFTRST */
__raw_writel(c, hwreg);
for (timeout = 1000000; timeout > 0; timeout--)
/* still in SFTRST state ? */
if ((__raw_readl(hwreg) & (1<<31)) == 0)
break;
if (timeout <= 0) {
printk(KERN_ERR"%s(%p): timeout when enabling "
"after reset\n", __func__, hwreg);
return -ETIME;
}
c = __raw_readl(hwreg);
c &= ~(1<<30); /* clear CLKGATE */
__raw_writel(c, hwreg);
}
for (timeout = 1000000; timeout > 0; timeout--)
/* still in SFTRST state ? */
if ((__raw_readl(hwreg) & (1<<30)) == 0)
break;
if (timeout <= 0) {
printk(KERN_ERR"%s(%p): timeout when unclockgating\n",
__func__, hwreg);
return -ETIME;
}
return 0;
}
int stmp3xxx_reset_block(void __iomem *hwreg, int just_enable)
{
int try = 10;
int r;
while (try--) {
r = __stmp3xxx_reset_block(hwreg, just_enable);
if (!r)
break;
pr_debug("%s: try %d failed\n", __func__, 10 - try);
}
return r;
}
EXPORT_SYMBOL(stmp3xxx_reset_block);
struct platform_device stmp3xxx_dbguart = {
.name = "stmp3xxx-dbguart",
.id = -1,
};
void __init stmp3xxx_init(void)
{
/* Turn off auto-slow and other tricks */
HW_CLKCTRL_HBUS_CLR(0x07f00000U);
stmp3xxx_dma_init();
}
This diff is collapsed.
/*
* Freescale STMP37XX/STMP378X common interrupt handling code
*
* Author: Vladislav Buzov <vbuzov@embeddedalley.com>
*
* Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
* Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/sysdev.h>
#include <mach/stmp3xxx.h>
#include <mach/regs-icoll.h>
void __init stmp3xxx_init_irq(struct irq_chip *chip)
{
unsigned int i;
/* Reset the interrupt controller */
HW_ICOLL_CTRL_CLR(BM_ICOLL_CTRL_CLKGATE);
udelay(10);
HW_ICOLL_CTRL_CLR(BM_ICOLL_CTRL_SFTRST);
udelay(10);
HW_ICOLL_CTRL_SET(BM_ICOLL_CTRL_SFTRST);
while (!(HW_ICOLL_CTRL_RD() & BM_ICOLL_CTRL_CLKGATE))
continue;
HW_ICOLL_CTRL_CLR(BM_ICOLL_CTRL_SFTRST | BM_ICOLL_CTRL_CLKGATE);
/* Disable all interrupts initially */
for (i = 0; i < NR_REAL_IRQS; i++) {
chip->mask(i);
set_irq_chip(i, chip);
set_irq_handler(i, handle_level_irq);
set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
}
/* Ensure vector is cleared */
HW_ICOLL_LEVELACK_WR(1);
HW_ICOLL_LEVELACK_WR(2);
HW_ICOLL_LEVELACK_WR(4);
HW_ICOLL_LEVELACK_WR(8);
HW_ICOLL_VECTOR_WR(0);
/* Barrier */
(void) HW_ICOLL_STAT_RD();
}
This diff is collapsed.
/*
* System timer for Freescale STMP37XX/STMP378X
*
* Embedded Alley Solutions, Inc <source@embeddedalley.com>
*
* Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
* Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <asm/mach/time.h>
#include <mach/stmp3xxx.h>
#include <mach/regs-timrot.h>
static irqreturn_t
stmp3xxx_timer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *c = dev_id;
if (HW_TIMROT_TIMCTRLn_RD(0) & (1<<15)) {
HW_TIMROT_TIMCTRLn_CLR(0, (1<<15));
c->event_handler(c);
} else if (HW_TIMROT_TIMCTRLn_RD(1) & (1<<15)) {
HW_TIMROT_TIMCTRLn_CLR(1, (1<<15));
HW_TIMROT_TIMCTRLn_CLR(1, BM_TIMROT_TIMCTRLn_IRQ_EN);
HW_TIMROT_TIMCOUNTn_WR(1, 0xFFFF);
}
return IRQ_HANDLED;
}
static cycle_t stmp3xxx_clock_read(void)
{
return ~((HW_TIMROT_TIMCOUNTn_RD(1) & 0xFFFF0000) >> 16);
}
static int
stmp3xxx_timrot_set_next_event(unsigned long delta,
struct clock_event_device *dev)
{
HW_TIMROT_TIMCOUNTn_WR(0, delta); /* reload */
return 0;
}
static void
stmp3xxx_timrot_set_mode(enum clock_event_mode mode,
struct clock_event_device *dev)
{
}
static struct clock_event_device ckevt_timrot = {
.name = "timrot",
.features = CLOCK_EVT_FEAT_ONESHOT,
.shift = 32,
.set_next_event = stmp3xxx_timrot_set_next_event,
.set_mode = stmp3xxx_timrot_set_mode,
};
static struct clocksource cksrc_stmp3xxx = {
.name = "cksrc_stmp3xxx",
.rating = 250,
.read = stmp3xxx_clock_read,
.mask = CLOCKSOURCE_MASK(16),
.shift = 10,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
static struct irqaction stmp3xxx_timer_irq = {
.name = "stmp3xxx_timer",
.flags = IRQF_DISABLED | IRQF_TIMER,
.handler = stmp3xxx_timer_interrupt,
.dev_id = &ckevt_timrot,
};
/*
* Set up timer interrupt, and return the current time in seconds.
*/
static void __init stmp3xxx_init_timer(void)
{
cksrc_stmp3xxx.mult = clocksource_hz2mult(CLOCK_TICK_RATE,
cksrc_stmp3xxx.shift);
ckevt_timrot.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC,
ckevt_timrot.shift);
ckevt_timrot.min_delta_ns = clockevent_delta2ns(2, &ckevt_timrot);
ckevt_timrot.max_delta_ns = clockevent_delta2ns(0xFFF, &ckevt_timrot);
ckevt_timrot.cpumask = cpumask_of(0);
HW_TIMROT_ROTCTRL_CLR(BM_TIMROT_ROTCTRL_SFTRST |
BM_TIMROT_ROTCTRL_CLKGATE);
HW_TIMROT_TIMCOUNTn_WR(0, 0);
HW_TIMROT_TIMCOUNTn_WR(1, 0);
HW_TIMROT_TIMCTRLn_WR(0,
(BF_TIMROT_TIMCTRLn_SELECT(8) | /* 32 kHz */
BF_TIMROT_TIMCTRLn_PRESCALE(0) |
BM_TIMROT_TIMCTRLn_RELOAD |
BM_TIMROT_TIMCTRLn_UPDATE |
BM_TIMROT_TIMCTRLn_IRQ_EN));
HW_TIMROT_TIMCTRLn_WR(1,
(BF_TIMROT_TIMCTRLn_SELECT(8) | /* 32 kHz */
BF_TIMROT_TIMCTRLn_PRESCALE(0) |
BM_TIMROT_TIMCTRLn_RELOAD |
BM_TIMROT_TIMCTRLn_UPDATE));
HW_TIMROT_TIMCOUNTn_WR(0, CLOCK_TICK_RATE / HZ - 1);
HW_TIMROT_TIMCOUNTn_WR(1, 0xFFFF); /* reload */
setup_irq(IRQ_TIMER0, &stmp3xxx_timer_irq);
clocksource_register(&cksrc_stmp3xxx);
clockevents_register_device(&ckevt_timrot);
}
#ifdef CONFIG_PM
void stmp3xxx_suspend_timer(void)
{
HW_TIMROT_TIMCTRLn_CLR(0, BM_TIMROT_TIMCTRLn_IRQ_EN);
HW_TIMROT_TIMCTRLn_CLR(0, (1<<15));
HW_TIMROT_ROTCTRL_SET(BM_TIMROT_ROTCTRL_CLKGATE);
}
void stmp3xxx_resume_timer(void)
{
HW_TIMROT_ROTCTRL_CLR(BM_TIMROT_ROTCTRL_SFTRST |
BM_TIMROT_ROTCTRL_CLKGATE);
HW_TIMROT_TIMCTRLn_WR(0,
(BF_TIMROT_TIMCTRLn_SELECT(8) | /* 32 kHz */
BF_TIMROT_TIMCTRLn_PRESCALE(0) |
BM_TIMROT_TIMCTRLn_UPDATE |
BM_TIMROT_TIMCTRLn_IRQ_EN));
HW_TIMROT_TIMCTRLn_WR(1,
(BF_TIMROT_TIMCTRLn_SELECT(8) | /* 32 kHz */
BF_TIMROT_TIMCTRLn_PRESCALE(0) |
BM_TIMROT_TIMCTRLn_RELOAD |
BM_TIMROT_TIMCTRLn_UPDATE));
HW_TIMROT_TIMCOUNTn_WR(0, CLOCK_TICK_RATE / HZ - 1);
HW_TIMROT_TIMCOUNTn_WR(1, 0xFFFF); /* reload */
}
#else
#define stmp3xxx_suspend_timer NULL
#define stmp3xxx_resume_timer NULL
#endif /* CONFIG_PM */
struct sys_timer stmp3xxx_timer = {
.init = stmp3xxx_init_timer,
.suspend = stmp3xxx_suspend_timer,
.resume = stmp3xxx_resume_timer,
};
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