M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions
+29
View File
@@ -0,0 +1,29 @@
# We keep common IP's here for Nomadik and other similar
# familiy of processors from ST-Ericsson. At the moment we have
# just MTU, others to follow soon.
config PLAT_NOMADIK
bool
depends on ARCH_NOMADIK || ARCH_U8500
select CLKSRC_MMIO
default y
help
Common platform code for Nomadik and other ST-Ericsson
platforms.
if PLAT_NOMADIK
config HAS_MTU
bool
help
Support for Multi Timer Unit. MTU provides access
to multiple interrupt generating programmable
32-bit free running decrementing counters.
config NOMADIK_MTU_SCHED_CLOCK
bool
depends on HAS_MTU
help
Use the Multi Timer Unit as the sched_clock.
endif
+5
View File
@@ -0,0 +1,5 @@
# arch/arm/plat-nomadik/Makefile
# Copyright 2009 ST-Ericsson
# Licensed under GPLv2
obj-$(CONFIG_HAS_MTU) += timer.o
@@ -0,0 +1,88 @@
/*
* Structures and registers for GPIO access in the Nomadik SoC
*
* Copyright (C) 2008 STMicroelectronics
* Author: Prafulla WADASKAR <prafulla.wadaskar@st.com>
* Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it>
*
* 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.
*/
#ifndef __PLAT_NOMADIK_GPIO
#define __PLAT_NOMADIK_GPIO
/*
* "nmk_gpio" and "NMK_GPIO" stand for "Nomadik GPIO", leaving
* the "gpio" namespace for generic and cross-machine functions
*/
/* Register in the logic block */
#define NMK_GPIO_DAT 0x00
#define NMK_GPIO_DATS 0x04
#define NMK_GPIO_DATC 0x08
#define NMK_GPIO_PDIS 0x0c
#define NMK_GPIO_DIR 0x10
#define NMK_GPIO_DIRS 0x14
#define NMK_GPIO_DIRC 0x18
#define NMK_GPIO_SLPC 0x1c
#define NMK_GPIO_AFSLA 0x20
#define NMK_GPIO_AFSLB 0x24
#define NMK_GPIO_RIMSC 0x40
#define NMK_GPIO_FIMSC 0x44
#define NMK_GPIO_IS 0x48
#define NMK_GPIO_IC 0x4c
#define NMK_GPIO_RWIMSC 0x50
#define NMK_GPIO_FWIMSC 0x54
#define NMK_GPIO_WKS 0x58
/* Alternate functions: function C is set in hw by setting both A and B */
#define NMK_GPIO_ALT_GPIO 0
#define NMK_GPIO_ALT_A 1
#define NMK_GPIO_ALT_B 2
#define NMK_GPIO_ALT_C (NMK_GPIO_ALT_A | NMK_GPIO_ALT_B)
/* Pull up/down values */
enum nmk_gpio_pull {
NMK_GPIO_PULL_NONE,
NMK_GPIO_PULL_UP,
NMK_GPIO_PULL_DOWN,
};
/* Sleep mode */
enum nmk_gpio_slpm {
NMK_GPIO_SLPM_INPUT,
NMK_GPIO_SLPM_WAKEUP_ENABLE = NMK_GPIO_SLPM_INPUT,
NMK_GPIO_SLPM_NOCHANGE,
NMK_GPIO_SLPM_WAKEUP_DISABLE = NMK_GPIO_SLPM_NOCHANGE,
};
extern int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode);
extern int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull);
extern int nmk_gpio_set_mode(int gpio, int gpio_mode);
extern int nmk_gpio_get_mode(int gpio);
extern void nmk_gpio_wakeups_suspend(void);
extern void nmk_gpio_wakeups_resume(void);
extern void nmk_gpio_clocks_enable(void);
extern void nmk_gpio_clocks_disable(void);
extern void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up);
/*
* Platform data to register a block: only the initial gpio/irq number.
*/
struct nmk_gpio_platform_data {
char *name;
int first_gpio;
int first_irq;
int num_gpio;
u32 (*get_secondary_status)(unsigned int bank);
void (*set_ioforce)(bool enable);
bool supports_sleepmode;
};
#endif /* __PLAT_NOMADIK_GPIO */
@@ -0,0 +1,39 @@
/*
* Copyright (C) 2009 ST-Ericsson
*
* 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.
*/
#ifndef __PLAT_I2C_H
#define __PLAT_I2C_H
enum i2c_freq_mode {
I2C_FREQ_MODE_STANDARD, /* up to 100 Kb/s */
I2C_FREQ_MODE_FAST, /* up to 400 Kb/s */
I2C_FREQ_MODE_HIGH_SPEED, /* up to 3.4 Mb/s */
I2C_FREQ_MODE_FAST_PLUS, /* up to 1 Mb/s */
};
/**
* struct nmk_i2c_controller - client specific controller configuration
* @clk_freq: clock frequency for the operation mode
* @slsu: Slave data setup time in ns.
* The needed setup time for three modes of operation
* are 250ns, 100ns and 10ns respectively thus leading
* to the values of 14, 6, 2 for a 48 MHz i2c clk
* @tft: Tx FIFO Threshold in bytes
* @rft: Rx FIFO Threshold in bytes
* @timeout Slave response timeout(ms)
* @sm: speed mode
*/
struct nmk_i2c_controller {
unsigned long clk_freq;
unsigned short slsu;
unsigned char tft;
unsigned char rft;
int timeout;
enum i2c_freq_mode sm;
};
#endif /* __PLAT_I2C_H */
@@ -0,0 +1,9 @@
#ifndef __PLAT_MTU_H
#define __PLAT_MTU_H
void nmdk_timer_init(void __iomem *base);
void nmdk_clkevt_reset(void);
void nmdk_clksrc_reset(void);
#endif /* __PLAT_MTU_H */
@@ -0,0 +1,139 @@
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License terms: GNU General Public License, version 2
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
*
* Based on arch/arm/mach-pxa/include/mach/mfp.h:
* Copyright (C) 2007 Marvell International Ltd.
* eric miao <eric.miao@marvell.com>
*/
#ifndef __PLAT_PINCFG_H
#define __PLAT_PINCFG_H
/*
* pin configurations are represented by 32-bit integers:
*
* bit 0.. 8 - Pin Number (512 Pins Maximum)
* bit 9..10 - Alternate Function Selection
* bit 11..12 - Pull up/down state
* bit 13 - Sleep mode behaviour
* bit 14 - Direction
* bit 15 - Value (if output)
* bit 16..18 - SLPM pull up/down state
* bit 19..20 - SLPM direction
* bit 21..22 - SLPM Value (if output)
*
* to facilitate the definition, the following macros are provided
*
* PIN_CFG_DEFAULT - default config (0):
* pull up/down = disabled
* sleep mode = input/wakeup
* direction = input
* value = low
* SLPM direction = same as normal
* SLPM pull = same as normal
* SLPM value = same as normal
*
* PIN_CFG - default config with alternate function
*/
typedef unsigned long pin_cfg_t;
#define PIN_NUM_MASK 0x1ff
#define PIN_NUM(x) ((x) & PIN_NUM_MASK)
#define PIN_ALT_SHIFT 9
#define PIN_ALT_MASK (0x3 << PIN_ALT_SHIFT)
#define PIN_ALT(x) (((x) & PIN_ALT_MASK) >> PIN_ALT_SHIFT)
#define PIN_GPIO (NMK_GPIO_ALT_GPIO << PIN_ALT_SHIFT)
#define PIN_ALT_A (NMK_GPIO_ALT_A << PIN_ALT_SHIFT)
#define PIN_ALT_B (NMK_GPIO_ALT_B << PIN_ALT_SHIFT)
#define PIN_ALT_C (NMK_GPIO_ALT_C << PIN_ALT_SHIFT)
#define PIN_PULL_SHIFT 11
#define PIN_PULL_MASK (0x3 << PIN_PULL_SHIFT)
#define PIN_PULL(x) (((x) & PIN_PULL_MASK) >> PIN_PULL_SHIFT)
#define PIN_PULL_NONE (NMK_GPIO_PULL_NONE << PIN_PULL_SHIFT)
#define PIN_PULL_UP (NMK_GPIO_PULL_UP << PIN_PULL_SHIFT)
#define PIN_PULL_DOWN (NMK_GPIO_PULL_DOWN << PIN_PULL_SHIFT)
#define PIN_SLPM_SHIFT 13
#define PIN_SLPM_MASK (0x1 << PIN_SLPM_SHIFT)
#define PIN_SLPM(x) (((x) & PIN_SLPM_MASK) >> PIN_SLPM_SHIFT)
#define PIN_SLPM_MAKE_INPUT (NMK_GPIO_SLPM_INPUT << PIN_SLPM_SHIFT)
#define PIN_SLPM_NOCHANGE (NMK_GPIO_SLPM_NOCHANGE << PIN_SLPM_SHIFT)
/* These two replace the above in DB8500v2+ */
#define PIN_SLPM_WAKEUP_ENABLE (NMK_GPIO_SLPM_WAKEUP_ENABLE << PIN_SLPM_SHIFT)
#define PIN_SLPM_WAKEUP_DISABLE (NMK_GPIO_SLPM_WAKEUP_DISABLE << PIN_SLPM_SHIFT)
#define PIN_DIR_SHIFT 14
#define PIN_DIR_MASK (0x1 << PIN_DIR_SHIFT)
#define PIN_DIR(x) (((x) & PIN_DIR_MASK) >> PIN_DIR_SHIFT)
#define PIN_DIR_INPUT (0 << PIN_DIR_SHIFT)
#define PIN_DIR_OUTPUT (1 << PIN_DIR_SHIFT)
#define PIN_VAL_SHIFT 15
#define PIN_VAL_MASK (0x1 << PIN_VAL_SHIFT)
#define PIN_VAL(x) (((x) & PIN_VAL_MASK) >> PIN_VAL_SHIFT)
#define PIN_VAL_LOW (0 << PIN_VAL_SHIFT)
#define PIN_VAL_HIGH (1 << PIN_VAL_SHIFT)
#define PIN_SLPM_PULL_SHIFT 16
#define PIN_SLPM_PULL_MASK (0x7 << PIN_SLPM_PULL_SHIFT)
#define PIN_SLPM_PULL(x) \
(((x) & PIN_SLPM_PULL_MASK) >> PIN_SLPM_PULL_SHIFT)
#define PIN_SLPM_PULL_NONE \
((1 + NMK_GPIO_PULL_NONE) << PIN_SLPM_PULL_SHIFT)
#define PIN_SLPM_PULL_UP \
((1 + NMK_GPIO_PULL_UP) << PIN_SLPM_PULL_SHIFT)
#define PIN_SLPM_PULL_DOWN \
((1 + NMK_GPIO_PULL_DOWN) << PIN_SLPM_PULL_SHIFT)
#define PIN_SLPM_DIR_SHIFT 19
#define PIN_SLPM_DIR_MASK (0x3 << PIN_SLPM_DIR_SHIFT)
#define PIN_SLPM_DIR(x) \
(((x) & PIN_SLPM_DIR_MASK) >> PIN_SLPM_DIR_SHIFT)
#define PIN_SLPM_DIR_INPUT ((1 + 0) << PIN_SLPM_DIR_SHIFT)
#define PIN_SLPM_DIR_OUTPUT ((1 + 1) << PIN_SLPM_DIR_SHIFT)
#define PIN_SLPM_VAL_SHIFT 21
#define PIN_SLPM_VAL_MASK (0x3 << PIN_SLPM_VAL_SHIFT)
#define PIN_SLPM_VAL(x) \
(((x) & PIN_SLPM_VAL_MASK) >> PIN_SLPM_VAL_SHIFT)
#define PIN_SLPM_VAL_LOW ((1 + 0) << PIN_SLPM_VAL_SHIFT)
#define PIN_SLPM_VAL_HIGH ((1 + 1) << PIN_SLPM_VAL_SHIFT)
/* Shortcuts. Use these instead of separate DIR, PULL, and VAL. */
#define PIN_INPUT_PULLDOWN (PIN_DIR_INPUT | PIN_PULL_DOWN)
#define PIN_INPUT_PULLUP (PIN_DIR_INPUT | PIN_PULL_UP)
#define PIN_INPUT_NOPULL (PIN_DIR_INPUT | PIN_PULL_NONE)
#define PIN_OUTPUT_LOW (PIN_DIR_OUTPUT | PIN_VAL_LOW)
#define PIN_OUTPUT_HIGH (PIN_DIR_OUTPUT | PIN_VAL_HIGH)
#define PIN_SLPM_INPUT_PULLDOWN (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_DOWN)
#define PIN_SLPM_INPUT_PULLUP (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_UP)
#define PIN_SLPM_INPUT_NOPULL (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_NONE)
#define PIN_SLPM_OUTPUT_LOW (PIN_SLPM_DIR_OUTPUT | PIN_SLPM_VAL_LOW)
#define PIN_SLPM_OUTPUT_HIGH (PIN_SLPM_DIR_OUTPUT | PIN_SLPM_VAL_HIGH)
#define PIN_CFG_DEFAULT (0)
#define PIN_CFG(num, alt) \
(PIN_CFG_DEFAULT |\
(PIN_NUM(num) | PIN_##alt))
#define PIN_CFG_INPUT(num, alt, pull) \
(PIN_CFG_DEFAULT |\
(PIN_NUM(num) | PIN_##alt | PIN_INPUT_##pull))
#define PIN_CFG_OUTPUT(num, alt, val) \
(PIN_CFG_DEFAULT |\
(PIN_NUM(num) | PIN_##alt | PIN_OUTPUT_##val))
extern int nmk_config_pin(pin_cfg_t cfg, bool sleep);
extern int nmk_config_pins(pin_cfg_t *cfgs, int num);
extern int nmk_config_pins_sleep(pin_cfg_t *cfgs, int num);
#endif
@@ -0,0 +1,50 @@
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License v2
* Author: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com>
*
* ux500 Scroll key and Keypad Encoder (SKE) header
*/
#ifndef __SKE_H
#define __SKE_H
#include <linux/input/matrix_keypad.h>
/* register definitions for SKE peripheral */
#define SKE_CR 0x00
#define SKE_VAL0 0x04
#define SKE_VAL1 0x08
#define SKE_DBCR 0x0C
#define SKE_IMSC 0x10
#define SKE_RIS 0x14
#define SKE_MIS 0x18
#define SKE_ICR 0x1C
/*
* Keypad module
*/
/**
* struct keypad_platform_data - structure for platform specific data
* @init: pointer to keypad init function
* @exit: pointer to keypad deinitialisation function
* @keymap_data: matrix scan code table for keycodes
* @krow: maximum number of rows
* @kcol: maximum number of columns
* @debounce_ms: platform specific debounce time
* @no_autorepeat: flag for auto repetition
* @wakeup_enable: allow waking up the system
*/
struct ske_keypad_platform_data {
int (*init)(void);
int (*exit)(void);
const struct matrix_keymap_data *keymap_data;
u8 krow;
u8 kcol;
u8 debounce_ms;
bool no_autorepeat;
bool wakeup_enable;
};
#endif /*__SKE_KPD_H*/
@@ -0,0 +1,223 @@
/*
* Copyright (C) ST-Ericsson SA 2007-2010
* Author: Per Forlin <per.forlin@stericsson.com> for ST-Ericsson
* Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
* License terms: GNU General Public License (GPL) version 2
*/
#ifndef STE_DMA40_H
#define STE_DMA40_H
#include <linux/dmaengine.h>
#include <linux/scatterlist.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
/*
* Maxium size for a single dma descriptor
* Size is limited to 16 bits.
* Size is in the units of addr-widths (1,2,4,8 bytes)
* Larger transfers will be split up to multiple linked desc
*/
#define STEDMA40_MAX_SEG_SIZE 0xFFFF
/* dev types for memcpy */
#define STEDMA40_DEV_DST_MEMORY (-1)
#define STEDMA40_DEV_SRC_MEMORY (-1)
enum stedma40_mode {
STEDMA40_MODE_LOGICAL = 0,
STEDMA40_MODE_PHYSICAL,
STEDMA40_MODE_OPERATION,
};
enum stedma40_mode_opt {
STEDMA40_PCHAN_BASIC_MODE = 0,
STEDMA40_LCHAN_SRC_LOG_DST_LOG = 0,
STEDMA40_PCHAN_MODULO_MODE,
STEDMA40_PCHAN_DOUBLE_DST_MODE,
STEDMA40_LCHAN_SRC_PHY_DST_LOG,
STEDMA40_LCHAN_SRC_LOG_DST_PHY,
};
#define STEDMA40_ESIZE_8_BIT 0x0
#define STEDMA40_ESIZE_16_BIT 0x1
#define STEDMA40_ESIZE_32_BIT 0x2
#define STEDMA40_ESIZE_64_BIT 0x3
/* The value 4 indicates that PEN-reg shall be set to 0 */
#define STEDMA40_PSIZE_PHY_1 0x4
#define STEDMA40_PSIZE_PHY_2 0x0
#define STEDMA40_PSIZE_PHY_4 0x1
#define STEDMA40_PSIZE_PHY_8 0x2
#define STEDMA40_PSIZE_PHY_16 0x3
/*
* The number of elements differ in logical and
* physical mode
*/
#define STEDMA40_PSIZE_LOG_1 STEDMA40_PSIZE_PHY_2
#define STEDMA40_PSIZE_LOG_4 STEDMA40_PSIZE_PHY_4
#define STEDMA40_PSIZE_LOG_8 STEDMA40_PSIZE_PHY_8
#define STEDMA40_PSIZE_LOG_16 STEDMA40_PSIZE_PHY_16
/* Maximum number of possible physical channels */
#define STEDMA40_MAX_PHYS 32
enum stedma40_flow_ctrl {
STEDMA40_NO_FLOW_CTRL,
STEDMA40_FLOW_CTRL,
};
enum stedma40_periph_data_width {
STEDMA40_BYTE_WIDTH = STEDMA40_ESIZE_8_BIT,
STEDMA40_HALFWORD_WIDTH = STEDMA40_ESIZE_16_BIT,
STEDMA40_WORD_WIDTH = STEDMA40_ESIZE_32_BIT,
STEDMA40_DOUBLEWORD_WIDTH = STEDMA40_ESIZE_64_BIT
};
enum stedma40_xfer_dir {
STEDMA40_MEM_TO_MEM = 1,
STEDMA40_MEM_TO_PERIPH,
STEDMA40_PERIPH_TO_MEM,
STEDMA40_PERIPH_TO_PERIPH
};
/**
* struct stedma40_chan_cfg - dst/src channel configuration
*
* @big_endian: true if the src/dst should be read as big endian
* @data_width: Data width of the src/dst hardware
* @p_size: Burst size
* @flow_ctrl: Flow control on/off.
*/
struct stedma40_half_channel_info {
bool big_endian;
enum stedma40_periph_data_width data_width;
int psize;
enum stedma40_flow_ctrl flow_ctrl;
};
/**
* struct stedma40_chan_cfg - Structure to be filled by client drivers.
*
* @dir: MEM 2 MEM, PERIPH 2 MEM , MEM 2 PERIPH, PERIPH 2 PERIPH
* @high_priority: true if high-priority
* @realtime: true if realtime mode is to be enabled. Only available on DMA40
* version 3+, i.e DB8500v2+
* @mode: channel mode: physical, logical, or operation
* @mode_opt: options for the chosen channel mode
* @src_dev_type: Src device type
* @dst_dev_type: Dst device type
* @src_info: Parameters for dst half channel
* @dst_info: Parameters for dst half channel
* @use_fixed_channel: if true, use physical channel specified by phy_channel
* @phy_channel: physical channel to use, only if use_fixed_channel is true
*
* This structure has to be filled by the client drivers.
* It is recommended to do all dma configurations for clients in the machine.
*
*/
struct stedma40_chan_cfg {
enum stedma40_xfer_dir dir;
bool high_priority;
bool realtime;
enum stedma40_mode mode;
enum stedma40_mode_opt mode_opt;
int src_dev_type;
int dst_dev_type;
struct stedma40_half_channel_info src_info;
struct stedma40_half_channel_info dst_info;
bool use_fixed_channel;
int phy_channel;
};
/**
* struct stedma40_platform_data - Configuration struct for the dma device.
*
* @dev_len: length of dev_tx and dev_rx
* @dev_tx: mapping between destination event line and io address
* @dev_rx: mapping between source event line and io address
* @memcpy: list of memcpy event lines
* @memcpy_len: length of memcpy
* @memcpy_conf_phy: default configuration of physical channel memcpy
* @memcpy_conf_log: default configuration of logical channel memcpy
* @disabled_channels: A vector, ending with -1, that marks physical channels
* that are for different reasons not available for the driver.
*/
struct stedma40_platform_data {
u32 dev_len;
const dma_addr_t *dev_tx;
const dma_addr_t *dev_rx;
int *memcpy;
u32 memcpy_len;
struct stedma40_chan_cfg *memcpy_conf_phy;
struct stedma40_chan_cfg *memcpy_conf_log;
int disabled_channels[STEDMA40_MAX_PHYS];
bool use_esram_lcla;
};
#ifdef CONFIG_STE_DMA40
/**
* stedma40_filter() - Provides stedma40_chan_cfg to the
* ste_dma40 dma driver via the dmaengine framework.
* does some checking of what's provided.
*
* Never directly called by client. It used by dmaengine.
* @chan: dmaengine handle.
* @data: Must be of type: struct stedma40_chan_cfg and is
* the configuration of the framework.
*
*
*/
bool stedma40_filter(struct dma_chan *chan, void *data);
/**
* stedma40_slave_mem() - Transfers a raw data buffer to or from a slave
* (=device)
*
* @chan: dmaengine handle
* @addr: source or destination physicall address.
* @size: bytes to transfer
* @direction: direction of transfer
* @flags: is actually enum dma_ctrl_flags. See dmaengine.h
*/
static inline struct
dma_async_tx_descriptor *stedma40_slave_mem(struct dma_chan *chan,
dma_addr_t addr,
unsigned int size,
enum dma_transfer_direction direction,
unsigned long flags)
{
struct scatterlist sg;
sg_init_table(&sg, 1);
sg.dma_address = addr;
sg.length = size;
return dmaengine_prep_slave_sg(chan, &sg, 1, direction, flags);
}
#else
static inline bool stedma40_filter(struct dma_chan *chan, void *data)
{
return false;
}
static inline struct
dma_async_tx_descriptor *stedma40_slave_mem(struct dma_chan *chan,
dma_addr_t addr,
unsigned int size,
enum dma_transfer_direction direction,
unsigned long flags)
{
return NULL;
}
#endif
#endif
+223
View File
@@ -0,0 +1,223 @@
/*
* linux/arch/arm/plat-nomadik/timer.c
*
* Copyright (C) 2008 STMicroelectronics
* Copyright (C) 2010 Alessandro Rubini
* Copyright (C) 2010 Linus Walleij for ST-Ericsson
*
* 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/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/clockchips.h>
#include <linux/clk.h>
#include <linux/jiffies.h>
#include <linux/err.h>
#include <asm/mach/time.h>
#include <asm/sched_clock.h>
/*
* The MTU device hosts four different counters, with 4 set of
* registers. These are register names.
*/
#define MTU_IMSC 0x00 /* Interrupt mask set/clear */
#define MTU_RIS 0x04 /* Raw interrupt status */
#define MTU_MIS 0x08 /* Masked interrupt status */
#define MTU_ICR 0x0C /* Interrupt clear register */
/* per-timer registers take 0..3 as argument */
#define MTU_LR(x) (0x10 + 0x10 * (x) + 0x00) /* Load value */
#define MTU_VAL(x) (0x10 + 0x10 * (x) + 0x04) /* Current value */
#define MTU_CR(x) (0x10 + 0x10 * (x) + 0x08) /* Control reg */
#define MTU_BGLR(x) (0x10 + 0x10 * (x) + 0x0c) /* At next overflow */
/* bits for the control register */
#define MTU_CRn_ENA 0x80
#define MTU_CRn_PERIODIC 0x40 /* if 0 = free-running */
#define MTU_CRn_PRESCALE_MASK 0x0c
#define MTU_CRn_PRESCALE_1 0x00
#define MTU_CRn_PRESCALE_16 0x04
#define MTU_CRn_PRESCALE_256 0x08
#define MTU_CRn_32BITS 0x02
#define MTU_CRn_ONESHOT 0x01 /* if 0 = wraps reloading from BGLR*/
/* Other registers are usual amba/primecell registers, currently not used */
#define MTU_ITCR 0xff0
#define MTU_ITOP 0xff4
#define MTU_PERIPH_ID0 0xfe0
#define MTU_PERIPH_ID1 0xfe4
#define MTU_PERIPH_ID2 0xfe8
#define MTU_PERIPH_ID3 0xfeC
#define MTU_PCELL0 0xff0
#define MTU_PCELL1 0xff4
#define MTU_PCELL2 0xff8
#define MTU_PCELL3 0xffC
static void __iomem *mtu_base;
static bool clkevt_periodic;
static u32 clk_prescale;
static u32 nmdk_cycle; /* write-once */
#ifdef CONFIG_NOMADIK_MTU_SCHED_CLOCK
/*
* Override the global weak sched_clock symbol with this
* local implementation which uses the clocksource to get some
* better resolution when scheduling the kernel.
*/
static u32 notrace nomadik_read_sched_clock(void)
{
if (unlikely(!mtu_base))
return 0;
return -readl(mtu_base + MTU_VAL(0));
}
#endif
/* Clockevent device: use one-shot mode */
static int nmdk_clkevt_next(unsigned long evt, struct clock_event_device *ev)
{
writel(1 << 1, mtu_base + MTU_IMSC);
writel(evt, mtu_base + MTU_LR(1));
/* Load highest value, enable device, enable interrupts */
writel(MTU_CRn_ONESHOT | clk_prescale |
MTU_CRn_32BITS | MTU_CRn_ENA,
mtu_base + MTU_CR(1));
return 0;
}
void nmdk_clkevt_reset(void)
{
if (clkevt_periodic) {
/* Timer: configure load and background-load, and fire it up */
writel(nmdk_cycle, mtu_base + MTU_LR(1));
writel(nmdk_cycle, mtu_base + MTU_BGLR(1));
writel(MTU_CRn_PERIODIC | clk_prescale |
MTU_CRn_32BITS | MTU_CRn_ENA,
mtu_base + MTU_CR(1));
writel(1 << 1, mtu_base + MTU_IMSC);
} else {
/* Generate an interrupt to start the clockevent again */
(void) nmdk_clkevt_next(nmdk_cycle, NULL);
}
}
static void nmdk_clkevt_mode(enum clock_event_mode mode,
struct clock_event_device *dev)
{
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
clkevt_periodic = true;
nmdk_clkevt_reset();
break;
case CLOCK_EVT_MODE_ONESHOT:
clkevt_periodic = false;
break;
case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_UNUSED:
writel(0, mtu_base + MTU_IMSC);
/* disable timer */
writel(0, mtu_base + MTU_CR(1));
/* load some high default value */
writel(0xffffffff, mtu_base + MTU_LR(1));
break;
case CLOCK_EVT_MODE_RESUME:
break;
}
}
static struct clock_event_device nmdk_clkevt = {
.name = "mtu_1",
.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
.rating = 200,
.set_mode = nmdk_clkevt_mode,
.set_next_event = nmdk_clkevt_next,
};
/*
* IRQ Handler for timer 1 of the MTU block.
*/
static irqreturn_t nmdk_timer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *evdev = dev_id;
writel(1 << 1, mtu_base + MTU_ICR); /* Interrupt clear reg */
evdev->event_handler(evdev);
return IRQ_HANDLED;
}
static struct irqaction nmdk_timer_irq = {
.name = "Nomadik Timer Tick",
.flags = IRQF_DISABLED | IRQF_TIMER,
.handler = nmdk_timer_interrupt,
.dev_id = &nmdk_clkevt,
};
void nmdk_clksrc_reset(void)
{
/* Disable */
writel(0, mtu_base + MTU_CR(0));
/* ClockSource: configure load and background-load, and fire it up */
writel(nmdk_cycle, mtu_base + MTU_LR(0));
writel(nmdk_cycle, mtu_base + MTU_BGLR(0));
writel(clk_prescale | MTU_CRn_32BITS | MTU_CRn_ENA,
mtu_base + MTU_CR(0));
}
void __init nmdk_timer_init(void __iomem *base)
{
unsigned long rate;
struct clk *clk0;
mtu_base = base;
clk0 = clk_get_sys("mtu0", NULL);
BUG_ON(IS_ERR(clk0));
BUG_ON(clk_prepare(clk0) < 0);
BUG_ON(clk_enable(clk0) < 0);
/*
* Tick rate is 2.4MHz for Nomadik and 2.4Mhz, 100MHz or 133 MHz
* for ux500.
* Use a divide-by-16 counter if the tick rate is more than 32MHz.
* At 32 MHz, the timer (with 32 bit counter) can be programmed
* to wake-up at a max 127s a head in time. Dividing a 2.4 MHz timer
* with 16 gives too low timer resolution.
*/
rate = clk_get_rate(clk0);
if (rate > 32000000) {
rate /= 16;
clk_prescale = MTU_CRn_PRESCALE_16;
} else {
clk_prescale = MTU_CRn_PRESCALE_1;
}
nmdk_cycle = (rate + HZ/2) / HZ;
/* Timer 0 is the free running clocksource */
nmdk_clksrc_reset();
if (clocksource_mmio_init(mtu_base + MTU_VAL(0), "mtu_0",
rate, 200, 32, clocksource_mmio_readl_down))
pr_err("timer: failed to initialize clock source %s\n",
"mtu_0");
#ifdef CONFIG_NOMADIK_MTU_SCHED_CLOCK
setup_sched_clock(nomadik_read_sched_clock, 32, rate);
#endif
/* Timer 1 is used for events, register irq and clockevents */
setup_irq(IRQ_MTU0, &nmdk_timer_irq);
nmdk_clkevt.cpumask = cpumask_of(0);
clockevents_config_and_register(&nmdk_clkevt, rate, 2, 0xffffffffU);
}