mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-09 01:28:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
161
arch/arm/plat-omap/Kconfig
Normal file
161
arch/arm/plat-omap/Kconfig
Normal file
|
@ -0,0 +1,161 @@
|
|||
config ARCH_OMAP
|
||||
bool
|
||||
|
||||
if ARCH_OMAP
|
||||
|
||||
menu "TI OMAP Common Features"
|
||||
|
||||
config ARCH_OMAP_OTG
|
||||
bool
|
||||
|
||||
comment "OMAP Feature Selections"
|
||||
|
||||
config OMAP_DEBUG_DEVICES
|
||||
bool
|
||||
help
|
||||
For debug cards on TI reference boards.
|
||||
|
||||
config OMAP_DEBUG_LEDS
|
||||
def_bool y if NEW_LEDS
|
||||
depends on OMAP_DEBUG_DEVICES
|
||||
select LEDS_CLASS
|
||||
|
||||
config POWER_AVS_OMAP
|
||||
bool "AVS(Adaptive Voltage Scaling) support for OMAP IP versions 1&2"
|
||||
depends on POWER_AVS && (ARCH_OMAP3 || ARCH_OMAP4) && PM
|
||||
select POWER_SUPPLY
|
||||
help
|
||||
Say Y to enable AVS(Adaptive Voltage Scaling)
|
||||
support on OMAP containing the version 1 or
|
||||
version 2 of the SmartReflex IP.
|
||||
V1 is the 65nm version used in OMAP3430.
|
||||
V2 is the update for the 45nm version of the IP used in OMAP3630
|
||||
and OMAP4430
|
||||
|
||||
Please note, that by default SmartReflex is only
|
||||
initialized and not enabled. To enable the automatic voltage
|
||||
compensation for vdd mpu and vdd core from user space,
|
||||
user must write 1 to
|
||||
/debug/smartreflex/sr_<X>/autocomp,
|
||||
where X is mpu_iva or core for OMAP3.
|
||||
Optionally autocompensation can be enabled in the kernel
|
||||
by default during system init via the enable_on_init flag
|
||||
which an be passed as platform data to the smartreflex driver.
|
||||
|
||||
config POWER_AVS_OMAP_CLASS3
|
||||
bool "Class 3 mode of Smartreflex Implementation"
|
||||
depends on POWER_AVS_OMAP && TWL4030_CORE
|
||||
help
|
||||
Say Y to enable Class 3 implementation of Smartreflex
|
||||
|
||||
Class 3 implementation of Smartreflex employs continuous hardware
|
||||
voltage calibration.
|
||||
|
||||
config OMAP_RESET_CLOCKS
|
||||
bool "Reset unused clocks during boot"
|
||||
depends on ARCH_OMAP
|
||||
help
|
||||
Say Y if you want to reset unused clocks during boot.
|
||||
This option saves power, but assumes all drivers are
|
||||
using the clock framework. Broken drivers that do not
|
||||
yet use clock framework may not work with this option.
|
||||
If you are booting from another operating system, you
|
||||
probably do not want this option enabled until your
|
||||
device drivers work properly.
|
||||
|
||||
config OMAP_MUX
|
||||
bool "OMAP multiplexing support"
|
||||
depends on ARCH_OMAP
|
||||
default y
|
||||
help
|
||||
Pin multiplexing support for OMAP boards. If your bootloader
|
||||
sets the multiplexing correctly, say N. Otherwise, or if unsure,
|
||||
say Y.
|
||||
|
||||
config OMAP_MUX_DEBUG
|
||||
bool "Multiplexing debug output"
|
||||
depends on OMAP_MUX
|
||||
help
|
||||
Makes the multiplexing functions print out a lot of debug info.
|
||||
This is useful if you want to find out the correct values of the
|
||||
multiplexing registers.
|
||||
|
||||
config OMAP_MUX_WARNINGS
|
||||
bool "Warn about pins the bootloader didn't set up"
|
||||
depends on OMAP_MUX
|
||||
default y
|
||||
help
|
||||
Choose Y here to warn whenever driver initialization logic needs
|
||||
to change the pin multiplexing setup. When there are no warnings
|
||||
printed, it's safe to deselect OMAP_MUX for your product.
|
||||
|
||||
config OMAP_MPU_TIMER
|
||||
bool "Use mpu timer"
|
||||
depends on ARCH_OMAP1
|
||||
help
|
||||
Select this option if you want to use the OMAP mpu timer. This
|
||||
timer provides more intra-tick resolution than the 32KHz timer,
|
||||
but consumes more power.
|
||||
|
||||
config OMAP_32K_TIMER
|
||||
bool "Use 32KHz timer"
|
||||
depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS
|
||||
default y if (ARCH_OMAP16XX || ARCH_OMAP2PLUS)
|
||||
help
|
||||
Select this option if you want to enable the OMAP 32KHz timer.
|
||||
This timer saves power compared to the OMAP_MPU_TIMER, and has
|
||||
support for no tick during idle. The 32KHz timer provides less
|
||||
intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is
|
||||
currently only available for OMAP16XX, 24XX, 34XX, OMAP4/5 and DRA7XX.
|
||||
|
||||
On OMAP2PLUS this value is only used for CONFIG_HZ and
|
||||
CLOCK_TICK_RATE compile time calculation.
|
||||
The actual timer selection is done in the board file
|
||||
through the (DT_)MACHINE_START structure.
|
||||
|
||||
|
||||
config OMAP3_L2_AUX_SECURE_SAVE_RESTORE
|
||||
bool "OMAP3 HS/EMU save and restore for L2 AUX control register"
|
||||
depends on ARCH_OMAP3 && PM
|
||||
default n
|
||||
help
|
||||
Without this option, L2 Auxiliary control register contents are
|
||||
lost during off-mode entry on HS/EMU devices. This feature
|
||||
requires support from PPA / boot-loader in HS/EMU devices, which
|
||||
currently does not exist by default.
|
||||
|
||||
config OMAP3_L2_AUX_SECURE_SERVICE_SET_ID
|
||||
int "Service ID for the support routine to set L2 AUX control"
|
||||
depends on OMAP3_L2_AUX_SECURE_SAVE_RESTORE
|
||||
default 43
|
||||
help
|
||||
PPA routine service ID for setting L2 auxiliary control register.
|
||||
|
||||
config OMAP_DM_TIMER
|
||||
bool "Use dual-mode timer"
|
||||
depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS
|
||||
help
|
||||
Select this option if you want to use OMAP Dual-Mode timers.
|
||||
|
||||
config OMAP_SERIAL_WAKE
|
||||
bool "Enable wake-up events for serial ports"
|
||||
depends on ARCH_OMAP1 && OMAP_MUX
|
||||
default y
|
||||
help
|
||||
Select this option if you want to have your system wake up
|
||||
to data on the serial RX line. This allows you to wake the
|
||||
system from serial console.
|
||||
|
||||
choice
|
||||
prompt "OMAP PM layer selection"
|
||||
depends on ARCH_OMAP
|
||||
default OMAP_PM_NOOP
|
||||
|
||||
config OMAP_PM_NOOP
|
||||
bool "No-op/debug PM layer"
|
||||
|
||||
endchoice
|
||||
|
||||
endmenu
|
||||
|
||||
endif
|
16
arch/arm/plat-omap/Makefile
Normal file
16
arch/arm/plat-omap/Makefile
Normal file
|
@ -0,0 +1,16 @@
|
|||
#
|
||||
# Makefile for the linux kernel.
|
||||
#
|
||||
|
||||
ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/arch/arm/plat-omap/include
|
||||
|
||||
# Common support
|
||||
obj-y := sram.o dma.o counter_32k.o
|
||||
|
||||
# omap_device support (OMAP2+ only at the moment)
|
||||
|
||||
obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
|
||||
obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o
|
||||
i2c-omap-$(CONFIG_I2C_OMAP) := i2c.o
|
||||
obj-y += $(i2c-omap-m) $(i2c-omap-y)
|
||||
|
123
arch/arm/plat-omap/counter_32k.c
Normal file
123
arch/arm/plat-omap/counter_32k.c
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* OMAP 32ksynctimer/counter_32k-related code
|
||||
*
|
||||
* Copyright (C) 2009 Texas Instruments
|
||||
* Copyright (C) 2010 Nokia Corporation
|
||||
* Tony Lindgren <tony@atomide.com>
|
||||
* Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* NOTE: This timer is not the same timer as the old OMAP1 MPU timer.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/sched_clock.h>
|
||||
|
||||
#include <asm/mach/time.h>
|
||||
|
||||
#include <plat/counter-32k.h>
|
||||
|
||||
/* OMAP2_32KSYNCNT_CR_OFF: offset of 32ksync counter register */
|
||||
#define OMAP2_32KSYNCNT_REV_OFF 0x0
|
||||
#define OMAP2_32KSYNCNT_REV_SCHEME (0x3 << 30)
|
||||
#define OMAP2_32KSYNCNT_CR_OFF_LOW 0x10
|
||||
#define OMAP2_32KSYNCNT_CR_OFF_HIGH 0x30
|
||||
|
||||
/*
|
||||
* 32KHz clocksource ... always available, on pretty most chips except
|
||||
* OMAP 730 and 1510. Other timers could be used as clocksources, with
|
||||
* higher resolution in free-running counter modes (e.g. 12 MHz xtal),
|
||||
* but systems won't necessarily want to spend resources that way.
|
||||
*/
|
||||
static void __iomem *sync32k_cnt_reg;
|
||||
|
||||
static u64 notrace omap_32k_read_sched_clock(void)
|
||||
{
|
||||
return sync32k_cnt_reg ? readl_relaxed(sync32k_cnt_reg) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap_read_persistent_clock - Return time from a persistent clock.
|
||||
*
|
||||
* Reads the time from a source which isn't disabled during PM, the
|
||||
* 32k sync timer. Convert the cycles elapsed since last read into
|
||||
* nsecs and adds to a monotonically increasing timespec.
|
||||
*/
|
||||
static struct timespec persistent_ts;
|
||||
static cycles_t cycles;
|
||||
static unsigned int persistent_mult, persistent_shift;
|
||||
static DEFINE_SPINLOCK(read_persistent_clock_lock);
|
||||
|
||||
static void omap_read_persistent_clock(struct timespec *ts)
|
||||
{
|
||||
unsigned long long nsecs;
|
||||
cycles_t last_cycles;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&read_persistent_clock_lock, flags);
|
||||
|
||||
last_cycles = cycles;
|
||||
cycles = sync32k_cnt_reg ? readl_relaxed(sync32k_cnt_reg) : 0;
|
||||
|
||||
nsecs = clocksource_cyc2ns(cycles - last_cycles,
|
||||
persistent_mult, persistent_shift);
|
||||
|
||||
timespec_add_ns(&persistent_ts, nsecs);
|
||||
|
||||
*ts = persistent_ts;
|
||||
|
||||
spin_unlock_irqrestore(&read_persistent_clock_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* omap_init_clocksource_32k - setup and register counter 32k as a
|
||||
* kernel clocksource
|
||||
* @pbase: base addr of counter_32k module
|
||||
* @size: size of counter_32k to map
|
||||
*
|
||||
* Returns 0 upon success or negative error code upon failure.
|
||||
*
|
||||
*/
|
||||
int __init omap_init_clocksource_32k(void __iomem *vbase)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* 32k sync Counter IP register offsets vary between the
|
||||
* highlander version and the legacy ones.
|
||||
* The 'SCHEME' bits(30-31) of the revision register is used
|
||||
* to identify the version.
|
||||
*/
|
||||
if (readl_relaxed(vbase + OMAP2_32KSYNCNT_REV_OFF) &
|
||||
OMAP2_32KSYNCNT_REV_SCHEME)
|
||||
sync32k_cnt_reg = vbase + OMAP2_32KSYNCNT_CR_OFF_HIGH;
|
||||
else
|
||||
sync32k_cnt_reg = vbase + OMAP2_32KSYNCNT_CR_OFF_LOW;
|
||||
|
||||
/*
|
||||
* 120000 rough estimate from the calculations in
|
||||
* __clocksource_updatefreq_scale.
|
||||
*/
|
||||
clocks_calc_mult_shift(&persistent_mult, &persistent_shift,
|
||||
32768, NSEC_PER_SEC, 120000);
|
||||
|
||||
ret = clocksource_mmio_init(sync32k_cnt_reg, "32k_counter", 32768,
|
||||
250, 32, clocksource_mmio_readl_up);
|
||||
if (ret) {
|
||||
pr_err("32k_counter: can't register clocksource\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
sched_clock_register(omap_32k_read_sched_clock, 32, 32768);
|
||||
register_persistent_clock(NULL, omap_read_persistent_clock);
|
||||
pr_info("OMAP clocksource: 32k_counter at 32768 Hz\n");
|
||||
|
||||
return 0;
|
||||
}
|
174
arch/arm/plat-omap/debug-leds.c
Normal file
174
arch/arm/plat-omap/debug-leds.c
Normal file
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* linux/arch/arm/plat-omap/debug-leds.c
|
||||
*
|
||||
* Copyright 2011 by Bryan Wu <bryan.wu@canonical.com>
|
||||
* Copyright 2003 by Texas Instruments Incorporated
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_data/gpio-omap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
/* Many OMAP development platforms reuse the same "debug board"; these
|
||||
* platforms include H2, H3, H4, and Perseus2. There are 16 LEDs on the
|
||||
* debug board (all green), accessed through FPGA registers.
|
||||
*/
|
||||
|
||||
/* NOTE: most boards don't have a static mapping for the FPGA ... */
|
||||
struct h2p2_dbg_fpga {
|
||||
/* offset 0x00 */
|
||||
u16 smc91x[8];
|
||||
/* offset 0x10 */
|
||||
u16 fpga_rev;
|
||||
u16 board_rev;
|
||||
u16 gpio_outputs;
|
||||
u16 leds;
|
||||
/* offset 0x18 */
|
||||
u16 misc_inputs;
|
||||
u16 lan_status;
|
||||
u16 lan_reset;
|
||||
u16 reserved0;
|
||||
/* offset 0x20 */
|
||||
u16 ps2_data;
|
||||
u16 ps2_ctrl;
|
||||
/* plus also 4 rs232 ports ... */
|
||||
};
|
||||
|
||||
static struct h2p2_dbg_fpga __iomem *fpga;
|
||||
|
||||
static u16 fpga_led_state;
|
||||
|
||||
struct dbg_led {
|
||||
struct led_classdev cdev;
|
||||
u16 mask;
|
||||
};
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
const char *trigger;
|
||||
} dbg_leds[] = {
|
||||
{ "dbg:d4", "heartbeat", },
|
||||
{ "dbg:d5", "cpu0", },
|
||||
{ "dbg:d6", "default-on", },
|
||||
{ "dbg:d7", },
|
||||
{ "dbg:d8", },
|
||||
{ "dbg:d9", },
|
||||
{ "dbg:d10", },
|
||||
{ "dbg:d11", },
|
||||
{ "dbg:d12", },
|
||||
{ "dbg:d13", },
|
||||
{ "dbg:d14", },
|
||||
{ "dbg:d15", },
|
||||
{ "dbg:d16", },
|
||||
{ "dbg:d17", },
|
||||
{ "dbg:d18", },
|
||||
{ "dbg:d19", },
|
||||
};
|
||||
|
||||
/*
|
||||
* The triggers lines up below will only be used if the
|
||||
* LED triggers are compiled in.
|
||||
*/
|
||||
static void dbg_led_set(struct led_classdev *cdev,
|
||||
enum led_brightness b)
|
||||
{
|
||||
struct dbg_led *led = container_of(cdev, struct dbg_led, cdev);
|
||||
u16 reg;
|
||||
|
||||
reg = readw_relaxed(&fpga->leds);
|
||||
if (b != LED_OFF)
|
||||
reg |= led->mask;
|
||||
else
|
||||
reg &= ~led->mask;
|
||||
writew_relaxed(reg, &fpga->leds);
|
||||
}
|
||||
|
||||
static enum led_brightness dbg_led_get(struct led_classdev *cdev)
|
||||
{
|
||||
struct dbg_led *led = container_of(cdev, struct dbg_led, cdev);
|
||||
u16 reg;
|
||||
|
||||
reg = readw_relaxed(&fpga->leds);
|
||||
return (reg & led->mask) ? LED_FULL : LED_OFF;
|
||||
}
|
||||
|
||||
static int fpga_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *iomem;
|
||||
int i;
|
||||
|
||||
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!iomem)
|
||||
return -ENODEV;
|
||||
|
||||
fpga = ioremap(iomem->start, resource_size(iomem));
|
||||
writew_relaxed(0xff, &fpga->leds);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dbg_leds); i++) {
|
||||
struct dbg_led *led;
|
||||
|
||||
led = kzalloc(sizeof(*led), GFP_KERNEL);
|
||||
if (!led)
|
||||
break;
|
||||
|
||||
led->cdev.name = dbg_leds[i].name;
|
||||
led->cdev.brightness_set = dbg_led_set;
|
||||
led->cdev.brightness_get = dbg_led_get;
|
||||
led->cdev.default_trigger = dbg_leds[i].trigger;
|
||||
led->mask = BIT(i);
|
||||
|
||||
if (led_classdev_register(NULL, &led->cdev) < 0) {
|
||||
kfree(led);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fpga_suspend_noirq(struct device *dev)
|
||||
{
|
||||
fpga_led_state = readw_relaxed(&fpga->leds);
|
||||
writew_relaxed(0xff, &fpga->leds);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fpga_resume_noirq(struct device *dev)
|
||||
{
|
||||
writew_relaxed(~fpga_led_state, &fpga->leds);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops fpga_dev_pm_ops = {
|
||||
.suspend_noirq = fpga_suspend_noirq,
|
||||
.resume_noirq = fpga_resume_noirq,
|
||||
};
|
||||
|
||||
static struct platform_driver led_driver = {
|
||||
.driver.name = "omap_dbg_led",
|
||||
.driver.pm = &fpga_dev_pm_ops,
|
||||
.probe = fpga_probe,
|
||||
};
|
||||
|
||||
static int __init fpga_init(void)
|
||||
{
|
||||
if (machine_is_omap_h4()
|
||||
|| machine_is_omap_h3()
|
||||
|| machine_is_omap_h2()
|
||||
|| machine_is_omap_perseus2()
|
||||
)
|
||||
return platform_driver_register(&led_driver);
|
||||
return 0;
|
||||
}
|
||||
fs_initcall(fpga_init);
|
1474
arch/arm/plat-omap/dma.c
Normal file
1474
arch/arm/plat-omap/dma.c
Normal file
File diff suppressed because it is too large
Load diff
952
arch/arm/plat-omap/dmtimer.c
Normal file
952
arch/arm/plat-omap/dmtimer.c
Normal file
|
@ -0,0 +1,952 @@
|
|||
/*
|
||||
* linux/arch/arm/plat-omap/dmtimer.c
|
||||
*
|
||||
* OMAP Dual-Mode Timers
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
|
||||
* Tarun Kanti DebBarma <tarun.kanti@ti.com>
|
||||
* Thara Gopinath <thara@ti.com>
|
||||
*
|
||||
* dmtimer adaptation to platform_driver.
|
||||
*
|
||||
* Copyright (C) 2005 Nokia Corporation
|
||||
* OMAP2 support by Juha Yrjola
|
||||
* API improvements and OMAP2 clock framework support by Timo Teras
|
||||
*
|
||||
* Copyright (C) 2009 Texas Instruments
|
||||
* Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
|
||||
*
|
||||
* 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; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* 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.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/dmtimer-omap.h>
|
||||
|
||||
#include <plat/dmtimer.h>
|
||||
|
||||
static u32 omap_reserved_systimers;
|
||||
static LIST_HEAD(omap_timer_list);
|
||||
static DEFINE_SPINLOCK(dm_timer_lock);
|
||||
|
||||
enum {
|
||||
REQUEST_ANY = 0,
|
||||
REQUEST_BY_ID,
|
||||
REQUEST_BY_CAP,
|
||||
REQUEST_BY_NODE,
|
||||
};
|
||||
|
||||
/**
|
||||
* omap_dm_timer_read_reg - read timer registers in posted and non-posted mode
|
||||
* @timer: timer pointer over which read operation to perform
|
||||
* @reg: lowest byte holds the register offset
|
||||
*
|
||||
* The posted mode bit is encoded in reg. Note that in posted mode write
|
||||
* pending bit must be checked. Otherwise a read of a non completed write
|
||||
* will produce an error.
|
||||
*/
|
||||
static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
|
||||
{
|
||||
WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
|
||||
return __omap_dm_timer_read(timer, reg, timer->posted);
|
||||
}
|
||||
|
||||
/**
|
||||
* omap_dm_timer_write_reg - write timer registers in posted and non-posted mode
|
||||
* @timer: timer pointer over which write operation is to perform
|
||||
* @reg: lowest byte holds the register offset
|
||||
* @value: data to write into the register
|
||||
*
|
||||
* The posted mode bit is encoded in reg. Note that in posted mode the write
|
||||
* pending bit must be checked. Otherwise a write on a register which has a
|
||||
* pending write will be lost.
|
||||
*/
|
||||
static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
|
||||
u32 value)
|
||||
{
|
||||
WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
|
||||
__omap_dm_timer_write(timer, reg, value, timer->posted);
|
||||
}
|
||||
|
||||
static void omap_timer_restore_context(struct omap_dm_timer *timer)
|
||||
{
|
||||
omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
|
||||
timer->context.twer);
|
||||
omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
|
||||
timer->context.tcrr);
|
||||
omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG,
|
||||
timer->context.tldr);
|
||||
omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG,
|
||||
timer->context.tmar);
|
||||
omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
|
||||
timer->context.tsicr);
|
||||
writel_relaxed(timer->context.tier, timer->irq_ena);
|
||||
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG,
|
||||
timer->context.tclr);
|
||||
}
|
||||
|
||||
static int omap_dm_timer_reset(struct omap_dm_timer *timer)
|
||||
{
|
||||
u32 l, timeout = 100000;
|
||||
|
||||
if (timer->revision != 1)
|
||||
return -EINVAL;
|
||||
|
||||
omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
|
||||
|
||||
do {
|
||||
l = __omap_dm_timer_read(timer,
|
||||
OMAP_TIMER_V1_SYS_STAT_OFFSET, 0);
|
||||
} while (!l && timeout--);
|
||||
|
||||
if (!timeout) {
|
||||
dev_err(&timer->pdev->dev, "Timer failed to reset\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* Configure timer for smart-idle mode */
|
||||
l = __omap_dm_timer_read(timer, OMAP_TIMER_OCP_CFG_OFFSET, 0);
|
||||
l |= 0x2 << 0x3;
|
||||
__omap_dm_timer_write(timer, OMAP_TIMER_OCP_CFG_OFFSET, l, 0);
|
||||
|
||||
timer->posted = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap_dm_timer_prepare(struct omap_dm_timer *timer)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* FIXME: OMAP1 devices do not use the clock framework for dmtimers so
|
||||
* do not call clk_get() for these devices.
|
||||
*/
|
||||
if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
|
||||
timer->fclk = clk_get(&timer->pdev->dev, "fck");
|
||||
if (WARN_ON_ONCE(IS_ERR(timer->fclk))) {
|
||||
dev_err(&timer->pdev->dev, ": No fclk handle.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
omap_dm_timer_enable(timer);
|
||||
|
||||
if (timer->capability & OMAP_TIMER_NEEDS_RESET) {
|
||||
rc = omap_dm_timer_reset(timer);
|
||||
if (rc) {
|
||||
omap_dm_timer_disable(timer);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
__omap_dm_timer_enable_posted(timer);
|
||||
omap_dm_timer_disable(timer);
|
||||
|
||||
return omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
|
||||
}
|
||||
|
||||
static inline u32 omap_dm_timer_reserved_systimer(int id)
|
||||
{
|
||||
return (omap_reserved_systimers & (1 << (id - 1))) ? 1 : 0;
|
||||
}
|
||||
|
||||
int omap_dm_timer_reserve_systimer(int id)
|
||||
{
|
||||
if (omap_dm_timer_reserved_systimer(id))
|
||||
return -ENODEV;
|
||||
|
||||
omap_reserved_systimers |= (1 << (id - 1));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct omap_dm_timer *_omap_dm_timer_request(int req_type, void *data)
|
||||
{
|
||||
struct omap_dm_timer *timer = NULL, *t;
|
||||
struct device_node *np = NULL;
|
||||
unsigned long flags;
|
||||
u32 cap = 0;
|
||||
int id = 0;
|
||||
|
||||
switch (req_type) {
|
||||
case REQUEST_BY_ID:
|
||||
id = *(int *)data;
|
||||
break;
|
||||
case REQUEST_BY_CAP:
|
||||
cap = *(u32 *)data;
|
||||
break;
|
||||
case REQUEST_BY_NODE:
|
||||
np = (struct device_node *)data;
|
||||
break;
|
||||
default:
|
||||
/* REQUEST_ANY */
|
||||
break;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&dm_timer_lock, flags);
|
||||
list_for_each_entry(t, &omap_timer_list, node) {
|
||||
if (t->reserved)
|
||||
continue;
|
||||
|
||||
switch (req_type) {
|
||||
case REQUEST_BY_ID:
|
||||
if (id == t->pdev->id) {
|
||||
timer = t;
|
||||
timer->reserved = 1;
|
||||
goto found;
|
||||
}
|
||||
break;
|
||||
case REQUEST_BY_CAP:
|
||||
if (cap == (t->capability & cap)) {
|
||||
/*
|
||||
* If timer is not NULL, we have already found
|
||||
* one timer but it was not an exact match
|
||||
* because it had more capabilites that what
|
||||
* was required. Therefore, unreserve the last
|
||||
* timer found and see if this one is a better
|
||||
* match.
|
||||
*/
|
||||
if (timer)
|
||||
timer->reserved = 0;
|
||||
timer = t;
|
||||
timer->reserved = 1;
|
||||
|
||||
/* Exit loop early if we find an exact match */
|
||||
if (t->capability == cap)
|
||||
goto found;
|
||||
}
|
||||
break;
|
||||
case REQUEST_BY_NODE:
|
||||
if (np == t->pdev->dev.of_node) {
|
||||
timer = t;
|
||||
timer->reserved = 1;
|
||||
goto found;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* REQUEST_ANY */
|
||||
timer = t;
|
||||
timer->reserved = 1;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
found:
|
||||
spin_unlock_irqrestore(&dm_timer_lock, flags);
|
||||
|
||||
if (timer && omap_dm_timer_prepare(timer)) {
|
||||
timer->reserved = 0;
|
||||
timer = NULL;
|
||||
}
|
||||
|
||||
if (!timer)
|
||||
pr_debug("%s: timer request failed!\n", __func__);
|
||||
|
||||
return timer;
|
||||
}
|
||||
|
||||
struct omap_dm_timer *omap_dm_timer_request(void)
|
||||
{
|
||||
return _omap_dm_timer_request(REQUEST_ANY, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_request);
|
||||
|
||||
struct omap_dm_timer *omap_dm_timer_request_specific(int id)
|
||||
{
|
||||
/* Requesting timer by ID is not supported when device tree is used */
|
||||
if (of_have_populated_dt()) {
|
||||
pr_warn("%s: Please use omap_dm_timer_request_by_cap/node()\n",
|
||||
__func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return _omap_dm_timer_request(REQUEST_BY_ID, &id);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
|
||||
|
||||
/**
|
||||
* omap_dm_timer_request_by_cap - Request a timer by capability
|
||||
* @cap: Bit mask of capabilities to match
|
||||
*
|
||||
* Find a timer based upon capabilities bit mask. Callers of this function
|
||||
* should use the definitions found in the plat/dmtimer.h file under the
|
||||
* comment "timer capabilities used in hwmod database". Returns pointer to
|
||||
* timer handle on success and a NULL pointer on failure.
|
||||
*/
|
||||
struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap)
|
||||
{
|
||||
return _omap_dm_timer_request(REQUEST_BY_CAP, &cap);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_request_by_cap);
|
||||
|
||||
/**
|
||||
* omap_dm_timer_request_by_node - Request a timer by device-tree node
|
||||
* @np: Pointer to device-tree timer node
|
||||
*
|
||||
* Request a timer based upon a device node pointer. Returns pointer to
|
||||
* timer handle on success and a NULL pointer on failure.
|
||||
*/
|
||||
struct omap_dm_timer *omap_dm_timer_request_by_node(struct device_node *np)
|
||||
{
|
||||
if (!np)
|
||||
return NULL;
|
||||
|
||||
return _omap_dm_timer_request(REQUEST_BY_NODE, np);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_request_by_node);
|
||||
|
||||
int omap_dm_timer_free(struct omap_dm_timer *timer)
|
||||
{
|
||||
if (unlikely(!timer))
|
||||
return -EINVAL;
|
||||
|
||||
clk_put(timer->fclk);
|
||||
|
||||
WARN_ON(!timer->reserved);
|
||||
timer->reserved = 0;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_free);
|
||||
|
||||
void omap_dm_timer_enable(struct omap_dm_timer *timer)
|
||||
{
|
||||
int c;
|
||||
|
||||
pm_runtime_get_sync(&timer->pdev->dev);
|
||||
|
||||
if (!(timer->capability & OMAP_TIMER_ALWON)) {
|
||||
if (timer->get_context_loss_count) {
|
||||
c = timer->get_context_loss_count(&timer->pdev->dev);
|
||||
if (c != timer->ctx_loss_count) {
|
||||
omap_timer_restore_context(timer);
|
||||
timer->ctx_loss_count = c;
|
||||
}
|
||||
} else {
|
||||
omap_timer_restore_context(timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
|
||||
|
||||
void omap_dm_timer_disable(struct omap_dm_timer *timer)
|
||||
{
|
||||
pm_runtime_put_sync(&timer->pdev->dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
|
||||
|
||||
int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
|
||||
{
|
||||
if (timer)
|
||||
return timer->irq;
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
|
||||
|
||||
#if defined(CONFIG_ARCH_OMAP1)
|
||||
#include <mach/hardware.h>
|
||||
/**
|
||||
* omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR
|
||||
* @inputmask: current value of idlect mask
|
||||
*/
|
||||
__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
|
||||
{
|
||||
int i = 0;
|
||||
struct omap_dm_timer *timer = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
/* If ARMXOR cannot be idled this function call is unnecessary */
|
||||
if (!(inputmask & (1 << 1)))
|
||||
return inputmask;
|
||||
|
||||
/* If any active timer is using ARMXOR return modified mask */
|
||||
spin_lock_irqsave(&dm_timer_lock, flags);
|
||||
list_for_each_entry(timer, &omap_timer_list, node) {
|
||||
u32 l;
|
||||
|
||||
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
|
||||
if (l & OMAP_TIMER_CTRL_ST) {
|
||||
if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
|
||||
inputmask &= ~(1 << 1);
|
||||
else
|
||||
inputmask &= ~(1 << 2);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
spin_unlock_irqrestore(&dm_timer_lock, flags);
|
||||
|
||||
return inputmask;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
|
||||
|
||||
#else
|
||||
|
||||
struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
|
||||
{
|
||||
if (timer && !IS_ERR(timer->fclk))
|
||||
return timer->fclk;
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk);
|
||||
|
||||
__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
|
||||
{
|
||||
BUG();
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
|
||||
|
||||
#endif
|
||||
|
||||
int omap_dm_timer_trigger(struct omap_dm_timer *timer)
|
||||
{
|
||||
if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
|
||||
pr_err("%s: timer not available or enabled.\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
|
||||
|
||||
int omap_dm_timer_start(struct omap_dm_timer *timer)
|
||||
{
|
||||
u32 l;
|
||||
|
||||
if (unlikely(!timer))
|
||||
return -EINVAL;
|
||||
|
||||
omap_dm_timer_enable(timer);
|
||||
|
||||
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
|
||||
if (!(l & OMAP_TIMER_CTRL_ST)) {
|
||||
l |= OMAP_TIMER_CTRL_ST;
|
||||
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
|
||||
}
|
||||
|
||||
/* Save the context */
|
||||
timer->context.tclr = l;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_start);
|
||||
|
||||
int omap_dm_timer_stop(struct omap_dm_timer *timer)
|
||||
{
|
||||
unsigned long rate = 0;
|
||||
|
||||
if (unlikely(!timer))
|
||||
return -EINVAL;
|
||||
|
||||
if (!(timer->capability & OMAP_TIMER_NEEDS_RESET))
|
||||
rate = clk_get_rate(timer->fclk);
|
||||
|
||||
__omap_dm_timer_stop(timer, timer->posted, rate);
|
||||
|
||||
/*
|
||||
* Since the register values are computed and written within
|
||||
* __omap_dm_timer_stop, we need to use read to retrieve the
|
||||
* context.
|
||||
*/
|
||||
timer->context.tclr =
|
||||
omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
|
||||
omap_dm_timer_disable(timer);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
|
||||
|
||||
int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
|
||||
{
|
||||
int ret;
|
||||
char *parent_name = NULL;
|
||||
struct clk *parent;
|
||||
struct dmtimer_platform_data *pdata;
|
||||
|
||||
if (unlikely(!timer))
|
||||
return -EINVAL;
|
||||
|
||||
pdata = timer->pdev->dev.platform_data;
|
||||
|
||||
if (source < 0 || source >= 3)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* FIXME: Used for OMAP1 devices only because they do not currently
|
||||
* use the clock framework to set the parent clock. To be removed
|
||||
* once OMAP1 migrated to using clock framework for dmtimers
|
||||
*/
|
||||
if (pdata && pdata->set_timer_src)
|
||||
return pdata->set_timer_src(timer->pdev, source);
|
||||
|
||||
if (IS_ERR(timer->fclk))
|
||||
return -EINVAL;
|
||||
|
||||
switch (source) {
|
||||
case OMAP_TIMER_SRC_SYS_CLK:
|
||||
parent_name = "timer_sys_ck";
|
||||
break;
|
||||
|
||||
case OMAP_TIMER_SRC_32_KHZ:
|
||||
parent_name = "timer_32k_ck";
|
||||
break;
|
||||
|
||||
case OMAP_TIMER_SRC_EXT_CLK:
|
||||
parent_name = "timer_ext_ck";
|
||||
break;
|
||||
}
|
||||
|
||||
parent = clk_get(&timer->pdev->dev, parent_name);
|
||||
if (IS_ERR(parent)) {
|
||||
pr_err("%s: %s not found\n", __func__, parent_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = clk_set_parent(timer->fclk, parent);
|
||||
if (ret < 0)
|
||||
pr_err("%s: failed to set %s as parent\n", __func__,
|
||||
parent_name);
|
||||
|
||||
clk_put(parent);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
|
||||
|
||||
int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
|
||||
unsigned int load)
|
||||
{
|
||||
u32 l;
|
||||
|
||||
if (unlikely(!timer))
|
||||
return -EINVAL;
|
||||
|
||||
omap_dm_timer_enable(timer);
|
||||
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
|
||||
if (autoreload)
|
||||
l |= OMAP_TIMER_CTRL_AR;
|
||||
else
|
||||
l &= ~OMAP_TIMER_CTRL_AR;
|
||||
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
|
||||
omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
|
||||
|
||||
omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
|
||||
/* Save the context */
|
||||
timer->context.tclr = l;
|
||||
timer->context.tldr = load;
|
||||
omap_dm_timer_disable(timer);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
|
||||
|
||||
/* Optimized set_load which removes costly spin wait in timer_start */
|
||||
int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
|
||||
unsigned int load)
|
||||
{
|
||||
u32 l;
|
||||
|
||||
if (unlikely(!timer))
|
||||
return -EINVAL;
|
||||
|
||||
omap_dm_timer_enable(timer);
|
||||
|
||||
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
|
||||
if (autoreload) {
|
||||
l |= OMAP_TIMER_CTRL_AR;
|
||||
omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
|
||||
} else {
|
||||
l &= ~OMAP_TIMER_CTRL_AR;
|
||||
}
|
||||
l |= OMAP_TIMER_CTRL_ST;
|
||||
|
||||
__omap_dm_timer_load_start(timer, l, load, timer->posted);
|
||||
|
||||
/* Save the context */
|
||||
timer->context.tclr = l;
|
||||
timer->context.tldr = load;
|
||||
timer->context.tcrr = load;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
|
||||
|
||||
int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
|
||||
unsigned int match)
|
||||
{
|
||||
u32 l;
|
||||
|
||||
if (unlikely(!timer))
|
||||
return -EINVAL;
|
||||
|
||||
omap_dm_timer_enable(timer);
|
||||
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
|
||||
if (enable)
|
||||
l |= OMAP_TIMER_CTRL_CE;
|
||||
else
|
||||
l &= ~OMAP_TIMER_CTRL_CE;
|
||||
omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
|
||||
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
|
||||
|
||||
/* Save the context */
|
||||
timer->context.tclr = l;
|
||||
timer->context.tmar = match;
|
||||
omap_dm_timer_disable(timer);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
|
||||
|
||||
int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
|
||||
int toggle, int trigger)
|
||||
{
|
||||
u32 l;
|
||||
|
||||
if (unlikely(!timer))
|
||||
return -EINVAL;
|
||||
|
||||
omap_dm_timer_enable(timer);
|
||||
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
|
||||
l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
|
||||
OMAP_TIMER_CTRL_PT | (0x03 << 10));
|
||||
if (def_on)
|
||||
l |= OMAP_TIMER_CTRL_SCPWM;
|
||||
if (toggle)
|
||||
l |= OMAP_TIMER_CTRL_PT;
|
||||
l |= trigger << 10;
|
||||
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
|
||||
|
||||
/* Save the context */
|
||||
timer->context.tclr = l;
|
||||
omap_dm_timer_disable(timer);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
|
||||
|
||||
int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
|
||||
{
|
||||
u32 l;
|
||||
|
||||
if (unlikely(!timer))
|
||||
return -EINVAL;
|
||||
|
||||
omap_dm_timer_enable(timer);
|
||||
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
|
||||
l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
|
||||
if (prescaler >= 0x00 && prescaler <= 0x07) {
|
||||
l |= OMAP_TIMER_CTRL_PRE;
|
||||
l |= prescaler << 2;
|
||||
}
|
||||
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
|
||||
|
||||
/* Save the context */
|
||||
timer->context.tclr = l;
|
||||
omap_dm_timer_disable(timer);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
|
||||
|
||||
int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
|
||||
unsigned int value)
|
||||
{
|
||||
if (unlikely(!timer))
|
||||
return -EINVAL;
|
||||
|
||||
omap_dm_timer_enable(timer);
|
||||
__omap_dm_timer_int_enable(timer, value);
|
||||
|
||||
/* Save the context */
|
||||
timer->context.tier = value;
|
||||
timer->context.twer = value;
|
||||
omap_dm_timer_disable(timer);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
|
||||
|
||||
/**
|
||||
* omap_dm_timer_set_int_disable - disable timer interrupts
|
||||
* @timer: pointer to timer handle
|
||||
* @mask: bit mask of interrupts to be disabled
|
||||
*
|
||||
* Disables the specified timer interrupts for a timer.
|
||||
*/
|
||||
int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask)
|
||||
{
|
||||
u32 l = mask;
|
||||
|
||||
if (unlikely(!timer))
|
||||
return -EINVAL;
|
||||
|
||||
omap_dm_timer_enable(timer);
|
||||
|
||||
if (timer->revision == 1)
|
||||
l = readl_relaxed(timer->irq_ena) & ~mask;
|
||||
|
||||
writel_relaxed(l, timer->irq_dis);
|
||||
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG) & ~mask;
|
||||
omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, l);
|
||||
|
||||
/* Save the context */
|
||||
timer->context.tier &= ~mask;
|
||||
timer->context.twer &= ~mask;
|
||||
omap_dm_timer_disable(timer);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_disable);
|
||||
|
||||
unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
|
||||
{
|
||||
unsigned int l;
|
||||
|
||||
if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
|
||||
pr_err("%s: timer not available or enabled.\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
l = readl_relaxed(timer->irq_stat);
|
||||
|
||||
return l;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
|
||||
|
||||
int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
|
||||
{
|
||||
if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev)))
|
||||
return -EINVAL;
|
||||
|
||||
__omap_dm_timer_write_status(timer, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
|
||||
|
||||
unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
|
||||
{
|
||||
if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
|
||||
pr_err("%s: timer not iavailable or enabled.\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return __omap_dm_timer_read_counter(timer, timer->posted);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
|
||||
|
||||
int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
|
||||
{
|
||||
if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
|
||||
pr_err("%s: timer not available or enabled.\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
|
||||
|
||||
/* Save the context */
|
||||
timer->context.tcrr = value;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
|
||||
|
||||
int omap_dm_timers_active(void)
|
||||
{
|
||||
struct omap_dm_timer *timer;
|
||||
|
||||
list_for_each_entry(timer, &omap_timer_list, node) {
|
||||
if (!timer->reserved)
|
||||
continue;
|
||||
|
||||
if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
|
||||
OMAP_TIMER_CTRL_ST) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_dm_timers_active);
|
||||
|
||||
static const struct of_device_id omap_timer_match[];
|
||||
|
||||
/**
|
||||
* omap_dm_timer_probe - probe function called for every registered device
|
||||
* @pdev: pointer to current timer platform device
|
||||
*
|
||||
* Called by driver framework at the end of device registration for all
|
||||
* timer devices.
|
||||
*/
|
||||
static int omap_dm_timer_probe(struct platform_device *pdev)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct omap_dm_timer *timer;
|
||||
struct resource *mem, *irq;
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct of_device_id *match;
|
||||
const struct dmtimer_platform_data *pdata;
|
||||
|
||||
match = of_match_device(of_match_ptr(omap_timer_match), dev);
|
||||
pdata = match ? match->data : dev->platform_data;
|
||||
|
||||
if (!pdata && !dev->of_node) {
|
||||
dev_err(dev, "%s: no platform data.\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (unlikely(!irq)) {
|
||||
dev_err(dev, "%s: no IRQ resource.\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (unlikely(!mem)) {
|
||||
dev_err(dev, "%s: no memory resource.\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
timer = devm_kzalloc(dev, sizeof(struct omap_dm_timer), GFP_KERNEL);
|
||||
if (!timer) {
|
||||
dev_err(dev, "%s: memory alloc failed!\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
timer->fclk = ERR_PTR(-ENODEV);
|
||||
timer->io_base = devm_ioremap_resource(dev, mem);
|
||||
if (IS_ERR(timer->io_base))
|
||||
return PTR_ERR(timer->io_base);
|
||||
|
||||
if (dev->of_node) {
|
||||
if (of_find_property(dev->of_node, "ti,timer-alwon", NULL))
|
||||
timer->capability |= OMAP_TIMER_ALWON;
|
||||
if (of_find_property(dev->of_node, "ti,timer-dsp", NULL))
|
||||
timer->capability |= OMAP_TIMER_HAS_DSP_IRQ;
|
||||
if (of_find_property(dev->of_node, "ti,timer-pwm", NULL))
|
||||
timer->capability |= OMAP_TIMER_HAS_PWM;
|
||||
if (of_find_property(dev->of_node, "ti,timer-secure", NULL))
|
||||
timer->capability |= OMAP_TIMER_SECURE;
|
||||
} else {
|
||||
timer->id = pdev->id;
|
||||
timer->capability = pdata->timer_capability;
|
||||
timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
|
||||
timer->get_context_loss_count = pdata->get_context_loss_count;
|
||||
}
|
||||
|
||||
if (pdata)
|
||||
timer->errata = pdata->timer_errata;
|
||||
|
||||
timer->irq = irq->start;
|
||||
timer->pdev = pdev;
|
||||
|
||||
/* Skip pm_runtime_enable for OMAP1 */
|
||||
if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
|
||||
pm_runtime_enable(dev);
|
||||
pm_runtime_irq_safe(dev);
|
||||
}
|
||||
|
||||
if (!timer->reserved) {
|
||||
pm_runtime_get_sync(dev);
|
||||
__omap_dm_timer_init_regs(timer);
|
||||
pm_runtime_put(dev);
|
||||
}
|
||||
|
||||
/* add the timer element to the list */
|
||||
spin_lock_irqsave(&dm_timer_lock, flags);
|
||||
list_add_tail(&timer->node, &omap_timer_list);
|
||||
spin_unlock_irqrestore(&dm_timer_lock, flags);
|
||||
|
||||
dev_dbg(dev, "Device Probed.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap_dm_timer_remove - cleanup a registered timer device
|
||||
* @pdev: pointer to current timer platform device
|
||||
*
|
||||
* Called by driver framework whenever a timer device is unregistered.
|
||||
* In addition to freeing platform resources it also deletes the timer
|
||||
* entry from the local list.
|
||||
*/
|
||||
static int omap_dm_timer_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dm_timer *timer;
|
||||
unsigned long flags;
|
||||
int ret = -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&dm_timer_lock, flags);
|
||||
list_for_each_entry(timer, &omap_timer_list, node)
|
||||
if (!strcmp(dev_name(&timer->pdev->dev),
|
||||
dev_name(&pdev->dev))) {
|
||||
list_del(&timer->node);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&dm_timer_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dmtimer_platform_data omap3plus_pdata = {
|
||||
.timer_errata = OMAP_TIMER_ERRATA_I103_I767,
|
||||
};
|
||||
|
||||
static const struct of_device_id omap_timer_match[] = {
|
||||
{
|
||||
.compatible = "ti,omap2420-timer",
|
||||
},
|
||||
{
|
||||
.compatible = "ti,omap3430-timer",
|
||||
.data = &omap3plus_pdata,
|
||||
},
|
||||
{
|
||||
.compatible = "ti,omap4430-timer",
|
||||
.data = &omap3plus_pdata,
|
||||
},
|
||||
{
|
||||
.compatible = "ti,omap5430-timer",
|
||||
.data = &omap3plus_pdata,
|
||||
},
|
||||
{
|
||||
.compatible = "ti,am335x-timer",
|
||||
.data = &omap3plus_pdata,
|
||||
},
|
||||
{
|
||||
.compatible = "ti,am335x-timer-1ms",
|
||||
.data = &omap3plus_pdata,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, omap_timer_match);
|
||||
|
||||
static struct platform_driver omap_dm_timer_driver = {
|
||||
.probe = omap_dm_timer_probe,
|
||||
.remove = omap_dm_timer_remove,
|
||||
.driver = {
|
||||
.name = "omap_timer",
|
||||
.of_match_table = of_match_ptr(omap_timer_match),
|
||||
},
|
||||
};
|
||||
|
||||
early_platform_init("earlytimer", &omap_dm_timer_driver);
|
||||
module_platform_driver(omap_dm_timer_driver);
|
||||
|
||||
MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:" DRIVER_NAME);
|
||||
MODULE_AUTHOR("Texas Instruments Inc");
|
116
arch/arm/plat-omap/i2c.c
Normal file
116
arch/arm/plat-omap/i2c.c
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* linux/arch/arm/plat-omap/i2c.c
|
||||
*
|
||||
* Helper module for board specific I2C bus registration
|
||||
*
|
||||
* Copyright (C) 2007 Nokia Corporation.
|
||||
*
|
||||
* Contact: Jarkko Nikula <jhnikula@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-omap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <plat/i2c.h>
|
||||
|
||||
#define OMAP_I2C_MAX_CONTROLLERS 4
|
||||
static struct omap_i2c_bus_platform_data i2c_pdata[OMAP_I2C_MAX_CONTROLLERS];
|
||||
|
||||
#define OMAP_I2C_CMDLINE_SETUP (BIT(31))
|
||||
|
||||
/**
|
||||
* omap_i2c_bus_setup - Process command line options for the I2C bus speed
|
||||
* @str: String of options
|
||||
*
|
||||
* This function allow to override the default I2C bus speed for given I2C
|
||||
* bus with a command line option.
|
||||
*
|
||||
* Format: i2c_bus=bus_id,clkrate (in kHz)
|
||||
*
|
||||
* Returns 1 on success, 0 otherwise.
|
||||
*/
|
||||
static int __init omap_i2c_bus_setup(char *str)
|
||||
{
|
||||
int ints[3];
|
||||
|
||||
get_options(str, 3, ints);
|
||||
if (ints[0] < 2 || ints[1] < 1 ||
|
||||
ints[1] > OMAP_I2C_MAX_CONTROLLERS)
|
||||
return 0;
|
||||
i2c_pdata[ints[1] - 1].clkrate = ints[2];
|
||||
i2c_pdata[ints[1] - 1].clkrate |= OMAP_I2C_CMDLINE_SETUP;
|
||||
|
||||
return 1;
|
||||
}
|
||||
__setup("i2c_bus=", omap_i2c_bus_setup);
|
||||
|
||||
/*
|
||||
* Register busses defined in command line but that are not registered with
|
||||
* omap_register_i2c_bus from board initialization code.
|
||||
*/
|
||||
int __init omap_register_i2c_bus_cmdline(void)
|
||||
{
|
||||
int i, err = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(i2c_pdata); i++)
|
||||
if (i2c_pdata[i].clkrate & OMAP_I2C_CMDLINE_SETUP) {
|
||||
i2c_pdata[i].clkrate &= ~OMAP_I2C_CMDLINE_SETUP;
|
||||
err = omap_i2c_add_bus(&i2c_pdata[i], i + 1);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap_register_i2c_bus - register I2C bus with device descriptors
|
||||
* @bus_id: bus id counting from number 1
|
||||
* @clkrate: clock rate of the bus in kHz
|
||||
* @info: pointer into I2C device descriptor table or NULL
|
||||
* @len: number of descriptors in the table
|
||||
*
|
||||
* Returns 0 on success or an error code.
|
||||
*/
|
||||
int __init omap_register_i2c_bus(int bus_id, u32 clkrate,
|
||||
struct i2c_board_info const *info,
|
||||
unsigned len)
|
||||
{
|
||||
int err;
|
||||
|
||||
BUG_ON(bus_id < 1 || bus_id > OMAP_I2C_MAX_CONTROLLERS);
|
||||
|
||||
if (info) {
|
||||
err = i2c_register_board_info(bus_id, info, len);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!i2c_pdata[bus_id - 1].clkrate)
|
||||
i2c_pdata[bus_id - 1].clkrate = clkrate;
|
||||
|
||||
i2c_pdata[bus_id - 1].clkrate &= ~OMAP_I2C_CMDLINE_SETUP;
|
||||
|
||||
return omap_i2c_add_bus(&i2c_pdata[bus_id - 1], bus_id);
|
||||
}
|
1
arch/arm/plat-omap/include/plat/counter-32k.h
Normal file
1
arch/arm/plat-omap/include/plat/counter-32k.h
Normal file
|
@ -0,0 +1 @@
|
|||
int omap_init_clocksource_32k(void __iomem *vbase);
|
35
arch/arm/plat-omap/include/plat/cpu.h
Normal file
35
arch/arm/plat-omap/include/plat/cpu.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* OMAP cpu type detection
|
||||
*
|
||||
* Copyright (C) 2004, 2008 Nokia Corporation
|
||||
*
|
||||
* Copyright (C) 2009-11 Texas Instruments.
|
||||
*
|
||||
* Written by Tony Lindgren <tony.lindgren@nokia.com>
|
||||
*
|
||||
* Added OMAP4/5 specific defines - Santosh Shilimkar<santosh.shilimkar@ti.com>
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ASM_ARCH_OMAP_CPU_H
|
||||
#define __ASM_ARCH_OMAP_CPU_H
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP1
|
||||
#include <mach/soc.h>
|
||||
#endif
|
||||
|
||||
#endif
|
418
arch/arm/plat-omap/include/plat/dmtimer.h
Normal file
418
arch/arm/plat-omap/include/plat/dmtimer.h
Normal file
|
@ -0,0 +1,418 @@
|
|||
/*
|
||||
* arch/arm/plat-omap/include/plat/dmtimer.h
|
||||
*
|
||||
* OMAP Dual-Mode Timers
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
|
||||
* Tarun Kanti DebBarma <tarun.kanti@ti.com>
|
||||
* Thara Gopinath <thara@ti.com>
|
||||
*
|
||||
* Platform device conversion and hwmod support.
|
||||
*
|
||||
* Copyright (C) 2005 Nokia Corporation
|
||||
* Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
|
||||
* PWM and clock framwork support by Timo Teras.
|
||||
*
|
||||
* 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; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* 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.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#ifndef __ASM_ARCH_DMTIMER_H
|
||||
#define __ASM_ARCH_DMTIMER_H
|
||||
|
||||
/* clock sources */
|
||||
#define OMAP_TIMER_SRC_SYS_CLK 0x00
|
||||
#define OMAP_TIMER_SRC_32_KHZ 0x01
|
||||
#define OMAP_TIMER_SRC_EXT_CLK 0x02
|
||||
|
||||
/* timer interrupt enable bits */
|
||||
#define OMAP_TIMER_INT_CAPTURE (1 << 2)
|
||||
#define OMAP_TIMER_INT_OVERFLOW (1 << 1)
|
||||
#define OMAP_TIMER_INT_MATCH (1 << 0)
|
||||
|
||||
/* trigger types */
|
||||
#define OMAP_TIMER_TRIGGER_NONE 0x00
|
||||
#define OMAP_TIMER_TRIGGER_OVERFLOW 0x01
|
||||
#define OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE 0x02
|
||||
|
||||
/* posted mode types */
|
||||
#define OMAP_TIMER_NONPOSTED 0x00
|
||||
#define OMAP_TIMER_POSTED 0x01
|
||||
|
||||
/* timer capabilities used in hwmod database */
|
||||
#define OMAP_TIMER_SECURE 0x80000000
|
||||
#define OMAP_TIMER_ALWON 0x40000000
|
||||
#define OMAP_TIMER_HAS_PWM 0x20000000
|
||||
#define OMAP_TIMER_NEEDS_RESET 0x10000000
|
||||
#define OMAP_TIMER_HAS_DSP_IRQ 0x08000000
|
||||
|
||||
/*
|
||||
* timer errata flags
|
||||
*
|
||||
* Errata i103/i767 impacts all OMAP3/4/5 devices including AM33xx. This
|
||||
* errata prevents us from using posted mode on these devices, unless the
|
||||
* timer counter register is never read. For more details please refer to
|
||||
* the OMAP3/4/5 errata documents.
|
||||
*/
|
||||
#define OMAP_TIMER_ERRATA_I103_I767 0x80000000
|
||||
|
||||
struct omap_timer_capability_dev_attr {
|
||||
u32 timer_capability;
|
||||
};
|
||||
|
||||
struct timer_regs {
|
||||
u32 tidr;
|
||||
u32 tier;
|
||||
u32 twer;
|
||||
u32 tclr;
|
||||
u32 tcrr;
|
||||
u32 tldr;
|
||||
u32 ttrg;
|
||||
u32 twps;
|
||||
u32 tmar;
|
||||
u32 tcar1;
|
||||
u32 tsicr;
|
||||
u32 tcar2;
|
||||
u32 tpir;
|
||||
u32 tnir;
|
||||
u32 tcvr;
|
||||
u32 tocr;
|
||||
u32 towr;
|
||||
};
|
||||
|
||||
struct omap_dm_timer {
|
||||
int id;
|
||||
int irq;
|
||||
struct clk *fclk;
|
||||
|
||||
void __iomem *io_base;
|
||||
void __iomem *irq_stat; /* TISR/IRQSTATUS interrupt status */
|
||||
void __iomem *irq_ena; /* irq enable */
|
||||
void __iomem *irq_dis; /* irq disable, only on v2 ip */
|
||||
void __iomem *pend; /* write pending */
|
||||
void __iomem *func_base; /* function register base */
|
||||
|
||||
unsigned long rate;
|
||||
unsigned reserved:1;
|
||||
unsigned posted:1;
|
||||
struct timer_regs context;
|
||||
int (*get_context_loss_count)(struct device *);
|
||||
int ctx_loss_count;
|
||||
int revision;
|
||||
u32 capability;
|
||||
u32 errata;
|
||||
struct platform_device *pdev;
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
int omap_dm_timer_reserve_systimer(int id);
|
||||
struct omap_dm_timer *omap_dm_timer_request(void);
|
||||
struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id);
|
||||
struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap);
|
||||
struct omap_dm_timer *omap_dm_timer_request_by_node(struct device_node *np);
|
||||
int omap_dm_timer_free(struct omap_dm_timer *timer);
|
||||
void omap_dm_timer_enable(struct omap_dm_timer *timer);
|
||||
void omap_dm_timer_disable(struct omap_dm_timer *timer);
|
||||
|
||||
int omap_dm_timer_get_irq(struct omap_dm_timer *timer);
|
||||
|
||||
u32 omap_dm_timer_modify_idlect_mask(u32 inputmask);
|
||||
struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer);
|
||||
|
||||
int omap_dm_timer_trigger(struct omap_dm_timer *timer);
|
||||
int omap_dm_timer_start(struct omap_dm_timer *timer);
|
||||
int omap_dm_timer_stop(struct omap_dm_timer *timer);
|
||||
|
||||
int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source);
|
||||
int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, unsigned int value);
|
||||
int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, unsigned int value);
|
||||
int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, unsigned int match);
|
||||
int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, int toggle, int trigger);
|
||||
int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler);
|
||||
|
||||
int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value);
|
||||
int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask);
|
||||
|
||||
unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer);
|
||||
int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value);
|
||||
unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer);
|
||||
int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value);
|
||||
|
||||
int omap_dm_timers_active(void);
|
||||
|
||||
/*
|
||||
* Do not use the defines below, they are not needed. They should be only
|
||||
* used by dmtimer.c and sys_timer related code.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The interrupt registers are different between v1 and v2 ip.
|
||||
* These registers are offsets from timer->iobase.
|
||||
*/
|
||||
#define OMAP_TIMER_ID_OFFSET 0x00
|
||||
#define OMAP_TIMER_OCP_CFG_OFFSET 0x10
|
||||
|
||||
#define OMAP_TIMER_V1_SYS_STAT_OFFSET 0x14
|
||||
#define OMAP_TIMER_V1_STAT_OFFSET 0x18
|
||||
#define OMAP_TIMER_V1_INT_EN_OFFSET 0x1c
|
||||
|
||||
#define OMAP_TIMER_V2_IRQSTATUS_RAW 0x24
|
||||
#define OMAP_TIMER_V2_IRQSTATUS 0x28
|
||||
#define OMAP_TIMER_V2_IRQENABLE_SET 0x2c
|
||||
#define OMAP_TIMER_V2_IRQENABLE_CLR 0x30
|
||||
|
||||
/*
|
||||
* The functional registers have a different base on v1 and v2 ip.
|
||||
* These registers are offsets from timer->func_base. The func_base
|
||||
* is samae as io_base for v1 and io_base + 0x14 for v2 ip.
|
||||
*
|
||||
*/
|
||||
#define OMAP_TIMER_V2_FUNC_OFFSET 0x14
|
||||
|
||||
#define _OMAP_TIMER_WAKEUP_EN_OFFSET 0x20
|
||||
#define _OMAP_TIMER_CTRL_OFFSET 0x24
|
||||
#define OMAP_TIMER_CTRL_GPOCFG (1 << 14)
|
||||
#define OMAP_TIMER_CTRL_CAPTMODE (1 << 13)
|
||||
#define OMAP_TIMER_CTRL_PT (1 << 12)
|
||||
#define OMAP_TIMER_CTRL_TCM_LOWTOHIGH (0x1 << 8)
|
||||
#define OMAP_TIMER_CTRL_TCM_HIGHTOLOW (0x2 << 8)
|
||||
#define OMAP_TIMER_CTRL_TCM_BOTHEDGES (0x3 << 8)
|
||||
#define OMAP_TIMER_CTRL_SCPWM (1 << 7)
|
||||
#define OMAP_TIMER_CTRL_CE (1 << 6) /* compare enable */
|
||||
#define OMAP_TIMER_CTRL_PRE (1 << 5) /* prescaler enable */
|
||||
#define OMAP_TIMER_CTRL_PTV_SHIFT 2 /* prescaler value shift */
|
||||
#define OMAP_TIMER_CTRL_POSTED (1 << 2)
|
||||
#define OMAP_TIMER_CTRL_AR (1 << 1) /* auto-reload enable */
|
||||
#define OMAP_TIMER_CTRL_ST (1 << 0) /* start timer */
|
||||
#define _OMAP_TIMER_COUNTER_OFFSET 0x28
|
||||
#define _OMAP_TIMER_LOAD_OFFSET 0x2c
|
||||
#define _OMAP_TIMER_TRIGGER_OFFSET 0x30
|
||||
#define _OMAP_TIMER_WRITE_PEND_OFFSET 0x34
|
||||
#define WP_NONE 0 /* no write pending bit */
|
||||
#define WP_TCLR (1 << 0)
|
||||
#define WP_TCRR (1 << 1)
|
||||
#define WP_TLDR (1 << 2)
|
||||
#define WP_TTGR (1 << 3)
|
||||
#define WP_TMAR (1 << 4)
|
||||
#define WP_TPIR (1 << 5)
|
||||
#define WP_TNIR (1 << 6)
|
||||
#define WP_TCVR (1 << 7)
|
||||
#define WP_TOCR (1 << 8)
|
||||
#define WP_TOWR (1 << 9)
|
||||
#define _OMAP_TIMER_MATCH_OFFSET 0x38
|
||||
#define _OMAP_TIMER_CAPTURE_OFFSET 0x3c
|
||||
#define _OMAP_TIMER_IF_CTRL_OFFSET 0x40
|
||||
#define _OMAP_TIMER_CAPTURE2_OFFSET 0x44 /* TCAR2, 34xx only */
|
||||
#define _OMAP_TIMER_TICK_POS_OFFSET 0x48 /* TPIR, 34xx only */
|
||||
#define _OMAP_TIMER_TICK_NEG_OFFSET 0x4c /* TNIR, 34xx only */
|
||||
#define _OMAP_TIMER_TICK_COUNT_OFFSET 0x50 /* TCVR, 34xx only */
|
||||
#define _OMAP_TIMER_TICK_INT_MASK_SET_OFFSET 0x54 /* TOCR, 34xx only */
|
||||
#define _OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET 0x58 /* TOWR, 34xx only */
|
||||
|
||||
/* register offsets with the write pending bit encoded */
|
||||
#define WPSHIFT 16
|
||||
|
||||
#define OMAP_TIMER_WAKEUP_EN_REG (_OMAP_TIMER_WAKEUP_EN_OFFSET \
|
||||
| (WP_NONE << WPSHIFT))
|
||||
|
||||
#define OMAP_TIMER_CTRL_REG (_OMAP_TIMER_CTRL_OFFSET \
|
||||
| (WP_TCLR << WPSHIFT))
|
||||
|
||||
#define OMAP_TIMER_COUNTER_REG (_OMAP_TIMER_COUNTER_OFFSET \
|
||||
| (WP_TCRR << WPSHIFT))
|
||||
|
||||
#define OMAP_TIMER_LOAD_REG (_OMAP_TIMER_LOAD_OFFSET \
|
||||
| (WP_TLDR << WPSHIFT))
|
||||
|
||||
#define OMAP_TIMER_TRIGGER_REG (_OMAP_TIMER_TRIGGER_OFFSET \
|
||||
| (WP_TTGR << WPSHIFT))
|
||||
|
||||
#define OMAP_TIMER_WRITE_PEND_REG (_OMAP_TIMER_WRITE_PEND_OFFSET \
|
||||
| (WP_NONE << WPSHIFT))
|
||||
|
||||
#define OMAP_TIMER_MATCH_REG (_OMAP_TIMER_MATCH_OFFSET \
|
||||
| (WP_TMAR << WPSHIFT))
|
||||
|
||||
#define OMAP_TIMER_CAPTURE_REG (_OMAP_TIMER_CAPTURE_OFFSET \
|
||||
| (WP_NONE << WPSHIFT))
|
||||
|
||||
#define OMAP_TIMER_IF_CTRL_REG (_OMAP_TIMER_IF_CTRL_OFFSET \
|
||||
| (WP_NONE << WPSHIFT))
|
||||
|
||||
#define OMAP_TIMER_CAPTURE2_REG (_OMAP_TIMER_CAPTURE2_OFFSET \
|
||||
| (WP_NONE << WPSHIFT))
|
||||
|
||||
#define OMAP_TIMER_TICK_POS_REG (_OMAP_TIMER_TICK_POS_OFFSET \
|
||||
| (WP_TPIR << WPSHIFT))
|
||||
|
||||
#define OMAP_TIMER_TICK_NEG_REG (_OMAP_TIMER_TICK_NEG_OFFSET \
|
||||
| (WP_TNIR << WPSHIFT))
|
||||
|
||||
#define OMAP_TIMER_TICK_COUNT_REG (_OMAP_TIMER_TICK_COUNT_OFFSET \
|
||||
| (WP_TCVR << WPSHIFT))
|
||||
|
||||
#define OMAP_TIMER_TICK_INT_MASK_SET_REG \
|
||||
(_OMAP_TIMER_TICK_INT_MASK_SET_OFFSET | (WP_TOCR << WPSHIFT))
|
||||
|
||||
#define OMAP_TIMER_TICK_INT_MASK_COUNT_REG \
|
||||
(_OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET | (WP_TOWR << WPSHIFT))
|
||||
|
||||
static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
|
||||
int posted)
|
||||
{
|
||||
if (posted)
|
||||
while (readl_relaxed(timer->pend) & (reg >> WPSHIFT))
|
||||
cpu_relax();
|
||||
|
||||
return readl_relaxed(timer->func_base + (reg & 0xff));
|
||||
}
|
||||
|
||||
static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
|
||||
u32 reg, u32 val, int posted)
|
||||
{
|
||||
if (posted)
|
||||
while (readl_relaxed(timer->pend) & (reg >> WPSHIFT))
|
||||
cpu_relax();
|
||||
|
||||
writel_relaxed(val, timer->func_base + (reg & 0xff));
|
||||
}
|
||||
|
||||
static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
|
||||
{
|
||||
u32 tidr;
|
||||
|
||||
/* Assume v1 ip if bits [31:16] are zero */
|
||||
tidr = readl_relaxed(timer->io_base);
|
||||
if (!(tidr >> 16)) {
|
||||
timer->revision = 1;
|
||||
timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET;
|
||||
timer->irq_ena = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET;
|
||||
timer->irq_dis = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET;
|
||||
timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET;
|
||||
timer->func_base = timer->io_base;
|
||||
} else {
|
||||
timer->revision = 2;
|
||||
timer->irq_stat = timer->io_base + OMAP_TIMER_V2_IRQSTATUS;
|
||||
timer->irq_ena = timer->io_base + OMAP_TIMER_V2_IRQENABLE_SET;
|
||||
timer->irq_dis = timer->io_base + OMAP_TIMER_V2_IRQENABLE_CLR;
|
||||
timer->pend = timer->io_base +
|
||||
_OMAP_TIMER_WRITE_PEND_OFFSET +
|
||||
OMAP_TIMER_V2_FUNC_OFFSET;
|
||||
timer->func_base = timer->io_base + OMAP_TIMER_V2_FUNC_OFFSET;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* __omap_dm_timer_enable_posted - enables write posted mode
|
||||
* @timer: pointer to timer instance handle
|
||||
*
|
||||
* Enables the write posted mode for the timer. When posted mode is enabled
|
||||
* writes to certain timer registers are immediately acknowledged by the
|
||||
* internal bus and hence prevents stalling the CPU waiting for the write to
|
||||
* complete. Enabling this feature can improve performance for writing to the
|
||||
* timer registers.
|
||||
*/
|
||||
static inline void __omap_dm_timer_enable_posted(struct omap_dm_timer *timer)
|
||||
{
|
||||
if (timer->posted)
|
||||
return;
|
||||
|
||||
if (timer->errata & OMAP_TIMER_ERRATA_I103_I767) {
|
||||
timer->posted = OMAP_TIMER_NONPOSTED;
|
||||
__omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
__omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG,
|
||||
OMAP_TIMER_CTRL_POSTED, 0);
|
||||
timer->context.tsicr = OMAP_TIMER_CTRL_POSTED;
|
||||
timer->posted = OMAP_TIMER_POSTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* __omap_dm_timer_override_errata - override errata flags for a timer
|
||||
* @timer: pointer to timer handle
|
||||
* @errata: errata flags to be ignored
|
||||
*
|
||||
* For a given timer, override a timer errata by clearing the flags
|
||||
* specified by the errata argument. A specific erratum should only be
|
||||
* overridden for a timer if the timer is used in such a way the erratum
|
||||
* has no impact.
|
||||
*/
|
||||
static inline void __omap_dm_timer_override_errata(struct omap_dm_timer *timer,
|
||||
u32 errata)
|
||||
{
|
||||
timer->errata &= ~errata;
|
||||
}
|
||||
|
||||
static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer,
|
||||
int posted, unsigned long rate)
|
||||
{
|
||||
u32 l;
|
||||
|
||||
l = __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted);
|
||||
if (l & OMAP_TIMER_CTRL_ST) {
|
||||
l &= ~0x1;
|
||||
__omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, l, posted);
|
||||
#ifdef CONFIG_ARCH_OMAP2PLUS
|
||||
/* Readback to make sure write has completed */
|
||||
__omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted);
|
||||
/*
|
||||
* Wait for functional clock period x 3.5 to make sure that
|
||||
* timer is stopped
|
||||
*/
|
||||
udelay(3500000 / rate + 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Ack possibly pending interrupt */
|
||||
writel_relaxed(OMAP_TIMER_INT_OVERFLOW, timer->irq_stat);
|
||||
}
|
||||
|
||||
static inline void __omap_dm_timer_load_start(struct omap_dm_timer *timer,
|
||||
u32 ctrl, unsigned int load,
|
||||
int posted)
|
||||
{
|
||||
__omap_dm_timer_write(timer, OMAP_TIMER_COUNTER_REG, load, posted);
|
||||
__omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, ctrl, posted);
|
||||
}
|
||||
|
||||
static inline void __omap_dm_timer_int_enable(struct omap_dm_timer *timer,
|
||||
unsigned int value)
|
||||
{
|
||||
writel_relaxed(value, timer->irq_ena);
|
||||
__omap_dm_timer_write(timer, OMAP_TIMER_WAKEUP_EN_REG, value, 0);
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
__omap_dm_timer_read_counter(struct omap_dm_timer *timer, int posted)
|
||||
{
|
||||
return __omap_dm_timer_read(timer, OMAP_TIMER_COUNTER_REG, posted);
|
||||
}
|
||||
|
||||
static inline void __omap_dm_timer_write_status(struct omap_dm_timer *timer,
|
||||
unsigned int value)
|
||||
{
|
||||
writel_relaxed(value, timer->irq_stat);
|
||||
}
|
||||
|
||||
#endif /* __ASM_ARCH_DMTIMER_H */
|
53
arch/arm/plat-omap/include/plat/i2c.h
Normal file
53
arch/arm/plat-omap/include/plat/i2c.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Helper module for board specific I2C bus registration
|
||||
*
|
||||
* Copyright (C) 2009 Nokia Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 __PLAT_OMAP_I2C_H
|
||||
#define __PLAT_OMAP_I2C_H
|
||||
|
||||
struct i2c_board_info;
|
||||
struct omap_i2c_bus_platform_data;
|
||||
|
||||
int omap_i2c_add_bus(struct omap_i2c_bus_platform_data *i2c_pdata,
|
||||
int bus_id);
|
||||
|
||||
#if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
|
||||
extern int omap_register_i2c_bus(int bus_id, u32 clkrate,
|
||||
struct i2c_board_info const *info,
|
||||
unsigned len);
|
||||
extern int omap_register_i2c_bus_cmdline(void);
|
||||
#else
|
||||
static inline int omap_register_i2c_bus(int bus_id, u32 clkrate,
|
||||
struct i2c_board_info const *info,
|
||||
unsigned len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int omap_register_i2c_bus_cmdline(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct omap_hwmod;
|
||||
int omap_i2c_reset(struct omap_hwmod *oh);
|
||||
|
||||
#endif /* __PLAT_OMAP_I2C_H */
|
16
arch/arm/plat-omap/include/plat/sram.h
Normal file
16
arch/arm/plat-omap/include/plat/sram.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
int omap_sram_init(void);
|
||||
|
||||
void omap_map_sram(unsigned long start, unsigned long size,
|
||||
unsigned long skip, int cached);
|
||||
void omap_sram_reset(void);
|
||||
|
||||
extern void *omap_sram_push_address(unsigned long size);
|
||||
|
||||
/* Macro to push a function to the internal SRAM, using the fncpy API */
|
||||
#define omap_sram_push(funcp, size) ({ \
|
||||
typeof(&(funcp)) _res = NULL; \
|
||||
void *_sram_address = omap_sram_push_address(size); \
|
||||
if (_sram_address) \
|
||||
_res = fncpy(_sram_address, &(funcp), size); \
|
||||
_res; \
|
||||
})
|
98
arch/arm/plat-omap/sram.c
Normal file
98
arch/arm/plat-omap/sram.c
Normal file
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* linux/arch/arm/plat-omap/sram.c
|
||||
*
|
||||
* OMAP SRAM detection and management
|
||||
*
|
||||
* Copyright (C) 2005 Nokia Corporation
|
||||
* Written by Tony Lindgren <tony@atomide.com>
|
||||
*
|
||||
* Copyright (C) 2009-2012 Texas Instruments
|
||||
* Added OMAP4/5 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#undef DEBUG
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <asm/fncpy.h>
|
||||
#include <asm/tlb.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
#include <asm/mach/map.h>
|
||||
|
||||
#include <plat/sram.h>
|
||||
|
||||
#define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1)))
|
||||
|
||||
static void __iomem *omap_sram_base;
|
||||
static unsigned long omap_sram_skip;
|
||||
static unsigned long omap_sram_size;
|
||||
static void __iomem *omap_sram_ceil;
|
||||
|
||||
/*
|
||||
* Memory allocator for SRAM: calculates the new ceiling address
|
||||
* for pushing a function using the fncpy API.
|
||||
*
|
||||
* Note that fncpy requires the returned address to be aligned
|
||||
* to an 8-byte boundary.
|
||||
*/
|
||||
void *omap_sram_push_address(unsigned long size)
|
||||
{
|
||||
unsigned long available, new_ceil = (unsigned long)omap_sram_ceil;
|
||||
|
||||
available = omap_sram_ceil - (omap_sram_base + omap_sram_skip);
|
||||
|
||||
if (size > available) {
|
||||
pr_err("Not enough space in SRAM\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new_ceil -= size;
|
||||
new_ceil = ROUND_DOWN(new_ceil, FNCPY_ALIGN);
|
||||
omap_sram_ceil = IOMEM(new_ceil);
|
||||
|
||||
return (void *)omap_sram_ceil;
|
||||
}
|
||||
|
||||
/*
|
||||
* The SRAM context is lost during off-idle and stack
|
||||
* needs to be reset.
|
||||
*/
|
||||
void omap_sram_reset(void)
|
||||
{
|
||||
omap_sram_ceil = omap_sram_base + omap_sram_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that we cannot use ioremap for SRAM, as clock init needs SRAM early.
|
||||
*/
|
||||
void __init omap_map_sram(unsigned long start, unsigned long size,
|
||||
unsigned long skip, int cached)
|
||||
{
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
start = ROUND_DOWN(start, PAGE_SIZE);
|
||||
omap_sram_size = size;
|
||||
omap_sram_skip = skip;
|
||||
omap_sram_base = __arm_ioremap_exec(start, size, cached);
|
||||
if (!omap_sram_base) {
|
||||
pr_err("SRAM: Could not map\n");
|
||||
return;
|
||||
}
|
||||
|
||||
omap_sram_reset();
|
||||
|
||||
/*
|
||||
* Looks like we need to preserve some bootloader code at the
|
||||
* beginning of SRAM for jumping to flash for reboot to work...
|
||||
*/
|
||||
memset_io(omap_sram_base + omap_sram_skip, 0,
|
||||
omap_sram_size - omap_sram_skip);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue