Merge remote-tracking branch 'scott/next' into next

Merge Freescale updates
This commit is contained in:
Benjamin Herrenschmidt 2013-07-02 17:42:17 +10:00
commit dd8164c1dd
18 changed files with 1410 additions and 43 deletions

View file

@ -0,0 +1,309 @@
===============================================================================
Freescale Interlaken Look-Aside Controller Device Bindings
Copyright 2012 Freescale Semiconductor Inc.
CONTENTS
- Interlaken Look-Aside Controller (LAC) Node
- Example LAC Node
- Interlaken Look-Aside Controller (LAC) Software Portal Node
- Interlaken Look-Aside Controller (LAC) Software Portal Child Nodes
- Example LAC SWP Node with Child Nodes
==============================================================================
Interlaken Look-Aside Controller (LAC) Node
DESCRIPTION
The Interlaken is a narrow, high speed channelized chip-to-chip interface. To
facilitate interoperability between a data path device and a look-aside
co-processor, the Interlaken Look-Aside protocol is defined for short
transaction-related transfers. Although based on the Interlaken protocol,
Interlaken Look-Aside is not directly compatible with Interlaken and can be
considered a different operation mode.
The Interlaken LA controller connects internal platform to Interlaken serial
interface. It accepts LA command through software portals, which are system
memory mapped 4KB spaces. The LA commands are then translated into the
Interlaken control words and data words, which are sent on TX side to TCAM
through SerDes lanes.
There are two 4KiB spaces defined within the LAC global register memory map.
There is a full register set at 0x0000-0x0FFF (also known as the "hypervisor"
version), and a subset at 0x1000-0x1FFF. The former is a superset of the
latter, and includes certain registers that should not be accessible to
partitioned software. Separate nodes are used for each region, with a phandle
linking the hypervisor node to the normal operating node.
PROPERTIES
- compatible
Usage: required
Value type: <string>
Definition: Must include "fsl,interlaken-lac". This represents only
those LAC CCSR registers not protected in partitioned
software. The version of the device is determined by the LAC
IP Block Revision Register (IPBRR0) at offset 0x0BF8.
Table of correspondences between IPBRR0 values and example
chips:
Value Device
----------- -------
0x02000100 T4240
The Hypervisor node has a different compatible. It must include
"fsl,interlaken-lac-hv". This node represents the protected
LAC register space and is required except inside a partition
where access to the hypervisor node is to be denied.
- fsl,non-hv-node
Usage: required in "fsl,interlaken-lac-hv"
Value type: <phandle>
Definition: Points to the non-protected LAC CCSR mapped register space
node.
- reg
Usage: required
Value type: <prop-encoded-array>
Definition: A standard property. The first resource represents the
Interlaken LAC configuration registers.
- interrupts:
Usage: required in non-hv node only
Value type: <prop-encoded-array>
Definition: Interrupt mapping for Interlaken LAC error IRQ.
EXAMPLE
lac: lac@229000 {
compatible = "fsl,interlaken-lac"
reg = <0x229000 0x1000>;
interrupts = <16 2 1 18>;
};
lac-hv@228000 {
compatible = "fsl,interlaken-lac-hv"
reg = <0x228000 0x1000>;
fsl,non-hv-node = <&lac>;
};
===============================================================================
Interlaken Look-Aside Controller (LAC) Software Portal Container Node
DESCRIPTION
The Interlaken Look-Aside Controller (LAC) utilizes Software Portals to accept
Interlaken Look-Aside (ILA) commands. The Interlaken LAC software portal
memory map occupies 128KB of memory space. The software portal memory space is
intended to be cache-enabled. WIMG for each software space is required to be
0010 if stashing is enabled; otherwise, WIMG can be 0000 or 0010.
PROPERTIES
- #address-cells
Usage: required
Value type: <u32>
Definition: A standard property. Must have a value of 1.
- #size-cells
Usage: required
Value type: <u32>
Definition: A standard property. Must have a value of 1.
- compatible
Usage: required
Value type: <string>
Definition: Must include "fsl,interlaken-lac-portals"
- ranges
Usage: required
Value type: <prop-encoded-array>
Definition: A standard property. Specifies the address and length
of the LAC portal memory space.
===============================================================================
Interlaken Look-Aside Controller (LAC) Software Portals Child Nodes
DESCRIPTION
There are up to 24 available software portals with each software portal
requiring 4KB of consecutive memory within the software portal memory mapped
space.
PROPERTIES
- compatible
Usage: required
Value type: <string>
Definition: Must include "fsl,interlaken-lac-portal-vX.Y" where X is
the Major version (IP_MJ) found in the LAC IP Block Revision
Register (IPBRR0), at offset 0x0BF8, and Y is the Minor version
(IP_MN).
Table of correspondences between version values and example chips:
Value Device
------ -------
1.0 T4240
- reg
Usage: required
Value type: <prop-encoded-array>
Definition: A standard property. The first resource represents the
Interlaken LAC software portal registers.
- fsl,liodn
Value type: <u32>
Definition: The logical I/O device number (LIODN) for this device. The
LIODN is a number expressed by this device and used to perform
look-ups in the IOMMU (PAMU) address table when performing
DMAs. This property is automatically added by u-boot.
===============================================================================
EXAMPLE
lac-portals {
#address-cells = <0x1>;
#size-cells = <0x1>;
compatible = "fsl,interlaken-lac-portals";
ranges = <0x0 0xf 0xf4400000 0x20000>;
lportal0: lac-portal@0 {
compatible = "fsl,interlaken-lac-portal-v1.0";
fsl,liodn = <0x204>;
reg = <0x0 0x1000>;
};
lportal1: lac-portal@1000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
fsl,liodn = <0x205>;
reg = <0x1000 0x1000>;
};
lportal2: lac-portal@2000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
fsl,liodn = <0x206>;
reg = <0x2000 0x1000>;
};
lportal3: lac-portal@3000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
fsl,liodn = <0x207>;
reg = <0x3000 0x1000>;
};
lportal4: lac-portal@4000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
fsl,liodn = <0x208>;
reg = <0x4000 0x1000>;
};
lportal5: lac-portal@5000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
fsl,liodn = <0x209>;
reg = <0x5000 0x1000>;
};
lportal6: lac-portal@6000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
fsl,liodn = <0x20A>;
reg = <0x6000 0x1000>;
};
lportal7: lac-portal@7000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
fsl,liodn = <0x20B>;
reg = <0x7000 0x1000>;
};
lportal8: lac-portal@8000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
fsl,liodn = <0x20C>;
reg = <0x8000 0x1000>;
};
lportal9: lac-portal@9000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
fsl,liodn = <0x20D>;
reg = <0x9000 0x1000>;
};
lportal10: lac-portal@A000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
fsl,liodn = <0x20E>;
reg = <0xA000 0x1000>;
};
lportal11: lac-portal@B000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
fsl,liodn = <0x20F>;
reg = <0xB000 0x1000>;
};
lportal12: lac-portal@C000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
fsl,liodn = <0x210>;
reg = <0xC000 0x1000>;
};
lportal13: lac-portal@D000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
fsl,liodn = <0x211>;
reg = <0xD000 0x1000>;
};
lportal14: lac-portal@E000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
fsl,liodn = <0x212>;
reg = <0xE000 0x1000>;
};
lportal15: lac-portal@F000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
fsl,liodn = <0x213>;
reg = <0xF000 0x1000>;
};
lportal16: lac-portal@10000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
fsl,liodn = <0x214>;
reg = <0x10000 0x1000>;
};
lportal17: lac-portal@11000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
fsl,liodn = <0x215>;
reg = <0x11000 0x1000>;
};
lportal8: lac-portal@1200 {
compatible = "fsl,interlaken-lac-portal-v1.0";
fsl,liodn = <0x216>;
reg = <0x12000 0x1000>;
};
lportal19: lac-portal@13000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
fsl,liodn = <0x217>;
reg = <0x13000 0x1000>;
};
lportal20: lac-portal@14000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
fsl,liodn = <0x218>;
reg = <0x14000 0x1000>;
};
lportal21: lac-portal@15000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
fsl,liodn = <0x219>;
reg = <0x15000 0x1000>;
};
lportal22: lac-portal@16000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
fsl,liodn = <0x21A>;
reg = <0x16000 0x1000>;
};
lportal23: lac-portal@17000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
fsl,liodn = <0x21B>;
reg = <0x17000 0x1000>;
};
};

View file

@ -0,0 +1,156 @@
/* T4240 Interlaken LAC Portal device tree stub with 24 portals.
*
* Copyright 2012 Freescale Semiconductor Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Freescale Semiconductor nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") as published by the Free Software
* Foundation, either version 2 of that License or (at your option) any
* later version.
*
* THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "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 Freescale Semiconductor BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON 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.
*/
#address-cells = <0x1>;
#size-cells = <0x1>;
compatible = "fsl,interlaken-lac-portals";
lportal0: lac-portal@0 {
compatible = "fsl,interlaken-lac-portal-v1.0";
reg = <0x0 0x1000>;
};
lportal1: lac-portal@1000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
reg = <0x1000 0x1000>;
};
lportal2: lac-portal@2000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
reg = <0x2000 0x1000>;
};
lportal3: lac-portal@3000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
reg = <0x3000 0x1000>;
};
lportal4: lac-portal@4000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
reg = <0x4000 0x1000>;
};
lportal5: lac-portal@5000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
reg = <0x5000 0x1000>;
};
lportal6: lac-portal@6000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
reg = <0x6000 0x1000>;
};
lportal7: lac-portal@7000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
reg = <0x7000 0x1000>;
};
lportal8: lac-portal@8000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
reg = <0x8000 0x1000>;
};
lportal9: lac-portal@9000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
reg = <0x9000 0x1000>;
};
lportal10: lac-portal@A000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
reg = <0xA000 0x1000>;
};
lportal11: lac-portal@B000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
reg = <0xB000 0x1000>;
};
lportal12: lac-portal@C000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
reg = <0xC000 0x1000>;
};
lportal13: lac-portal@D000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
reg = <0xD000 0x1000>;
};
lportal14: lac-portal@E000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
reg = <0xE000 0x1000>;
};
lportal15: lac-portal@F000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
reg = <0xF000 0x1000>;
};
lportal16: lac-portal@10000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
reg = <0x10000 0x1000>;
};
lportal17: lac-portal@11000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
reg = <0x11000 0x1000>;
};
lportal18: lac-portal@1200 {
compatible = "fsl,interlaken-lac-portal-v1.0";
reg = <0x12000 0x1000>;
};
lportal19: lac-portal@13000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
reg = <0x13000 0x1000>;
};
lportal20: lac-portal@14000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
reg = <0x14000 0x1000>;
};
lportal21: lac-portal@15000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
reg = <0x15000 0x1000>;
};
lportal22: lac-portal@16000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
reg = <0x16000 0x1000>;
};
lportal23: lac-portal@17000 {
compatible = "fsl,interlaken-lac-portal-v1.0";
reg = <0x17000 0x1000>;
};

View file

@ -0,0 +1,45 @@
/*
* T4 Interlaken Look-aside Controller (LAC) device tree stub
*
* Copyright 2012 Freescale Semiconductor Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Freescale Semiconductor nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") as published by the Free Software
* Foundation, either version 2 of that License or (at your option) any
* later version.
*
* THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "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 Freescale Semiconductor BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON 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.
*/
lac: lac@229000 {
compatible = "fsl,interlaken-lac";
reg = <0x229000 0x1000>;
interrupts = <16 2 1 18>;
};
lac-hv@228000 {
compatible = "fsl,interlaken-lac-hv";
reg = <0x228000 0x1000>;
fsl,non-hv-node = <&lac>;
};

View file

@ -131,6 +131,7 @@ CONFIG_DUMMY=y
CONFIG_FS_ENET=y
CONFIG_UCC_GETH=y
CONFIG_GIANFAR=y
CONFIG_E1000E=y
CONFIG_MARVELL_PHY=y
CONFIG_DAVICOM_PHY=y
CONFIG_CICADA_PHY=y

View file

@ -339,6 +339,8 @@ struct mpic
#endif
};
extern struct bus_type mpic_subsys;
/*
* MPIC flags (passed to mpic_alloc)
*
@ -393,6 +395,9 @@ struct mpic
#define MPIC_REGSET_STANDARD MPIC_REGSET(0) /* Original MPIC */
#define MPIC_REGSET_TSI108 MPIC_REGSET(1) /* Tsi108/109 PIC */
/* Get the version of primary MPIC */
extern u32 fsl_mpic_primary_get_version(void);
/* Allocate the controller structure and setup the linux irq descs
* for the range if interrupts passed in. No HW initialization is
* actually performed.

View file

@ -0,0 +1,46 @@
/*
* arch/powerpc/include/asm/mpic_timer.h
*
* Header file for Mpic Global Timer
*
* Copyright 2013 Freescale Semiconductor, Inc.
*
* Author: Wang Dongsheng <Dongsheng.Wang@freescale.com>
* Li Yang <leoli@freescale.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.
*/
#ifndef __MPIC_TIMER__
#define __MPIC_TIMER__
#include <linux/interrupt.h>
#include <linux/time.h>
struct mpic_timer {
void *dev;
struct cascade_priv *cascade_handle;
unsigned int num;
unsigned int irq;
};
#ifdef CONFIG_MPIC_TIMER
struct mpic_timer *mpic_request_timer(irq_handler_t fn, void *dev,
const struct timeval *time);
void mpic_start_timer(struct mpic_timer *handle);
void mpic_stop_timer(struct mpic_timer *handle);
void mpic_get_remain_time(struct mpic_timer *handle, struct timeval *time);
void mpic_free_timer(struct mpic_timer *handle);
#else
struct mpic_timer *mpic_request_timer(irq_handler_t fn, void *dev,
const struct timeval *time) { return NULL; }
void mpic_start_timer(struct mpic_timer *handle) { }
void mpic_stop_timer(struct mpic_timer *handle) { }
void mpic_get_remain_time(struct mpic_timer *handle, struct timeval *time) { }
void mpic_free_timer(struct mpic_timer *handle) { }
#endif
#endif

View file

@ -231,17 +231,7 @@ static struct i2c_driver mcu_driver = {
.id_table = mcu_ids,
};
static int __init mcu_init(void)
{
return i2c_add_driver(&mcu_driver);
}
module_init(mcu_init);
static void __exit mcu_exit(void)
{
i2c_del_driver(&mcu_driver);
}
module_exit(mcu_exit);
module_i2c_driver(mcu_driver);
MODULE_DESCRIPTION("Power Management and GPIO expander driver for "
"MPC8349E-mITX-compatible MCU");

View file

@ -75,12 +75,7 @@ define_machine(p5020_ds) {
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
#endif
/* coreint doesn't play nice with lazy EE, use legacy mpic for now */
#ifdef CONFIG_PPC64
.get_irq = mpic_get_irq,
#else
.get_irq = mpic_get_coreint_irq,
#endif
.restart = fsl_rstcr_restart,
.calibrate_decr = generic_calibrate_decr,
.progress = udbg_progress,

View file

@ -66,12 +66,7 @@ define_machine(p5040_ds) {
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
#endif
/* coreint doesn't play nice with lazy EE, use legacy mpic for now */
#ifdef CONFIG_PPC64
.get_irq = mpic_get_irq,
#else
.get_irq = mpic_get_coreint_irq,
#endif
.restart = fsl_rstcr_restart,
.calibrate_decr = generic_calibrate_decr,
.progress = udbg_progress,

View file

@ -75,12 +75,7 @@ define_machine(t4240_qds) {
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
#endif
/* coreint doesn't play nice with lazy EE, use legacy mpic for now */
#ifdef CONFIG_PPC64
.get_irq = mpic_get_irq,
#else
.get_irq = mpic_get_coreint_irq,
#endif
.restart = fsl_rstcr_restart,
.calibrate_decr = generic_calibrate_decr,
.progress = udbg_progress,

View file

@ -219,19 +219,12 @@ void mpc8xx_restart(char *cmd)
static void cpm_cascade(unsigned int irq, struct irq_desc *desc)
{
struct irq_chip *chip;
int cascade_irq;
if ((cascade_irq = cpm_get_irq()) >= 0) {
struct irq_desc *cdesc = irq_to_desc(cascade_irq);
struct irq_chip *chip = irq_desc_get_chip(desc);
int cascade_irq = cpm_get_irq();
if (cascade_irq >= 0)
generic_handle_irq(cascade_irq);
chip = irq_desc_get_chip(cdesc);
chip->irq_eoi(&cdesc->irq_data);
}
chip = irq_desc_get_chip(desc);
chip->irq_eoi(&desc->irq_data);
}

View file

@ -86,6 +86,27 @@ config MPIC
bool
default n
config MPIC_TIMER
bool "MPIC Global Timer"
depends on MPIC && FSL_SOC
default n
help
The MPIC global timer is a hardware timer inside the
Freescale PIC complying with OpenPIC standard. When the
specified interval times out, the hardware timer generates
an interrupt. The driver currently is only tested on fsl
chip, but it can potentially support other global timers
complying with the OpenPIC standard.
config FSL_MPIC_TIMER_WAKEUP
tristate "Freescale MPIC global timer wakeup driver"
depends on FSL_SOC && MPIC_TIMER && PM
default n
help
The driver provides a way to wake up the system by MPIC
timer.
e.g. "echo 5 > /sys/devices/system/mpic/timer_wakeup"
config PPC_EPAPR_HV_PIC
bool
default n

View file

@ -4,6 +4,8 @@ ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC)
mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o
obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y)
obj-$(CONFIG_MPIC_TIMER) += mpic_timer.o
obj-$(CONFIG_FSL_MPIC_TIMER_WAKEUP) += fsl_mpic_timer_wakeup.o
mpic-msgr-obj-$(CONFIG_MPIC_MSGR) += mpic_msgr.o
obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) $(mpic-msgr-obj-y)
obj-$(CONFIG_PPC_EPAPR_HV_PIC) += ehv_pic.o

View file

@ -0,0 +1,161 @@
/*
* MPIC timer wakeup driver
*
* Copyright 2013 Freescale Semiconductor, Inc.
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <asm/mpic_timer.h>
#include <asm/mpic.h>
struct fsl_mpic_timer_wakeup {
struct mpic_timer *timer;
struct work_struct free_work;
};
static struct fsl_mpic_timer_wakeup *fsl_wakeup;
static DEFINE_MUTEX(sysfs_lock);
static void fsl_free_resource(struct work_struct *ws)
{
struct fsl_mpic_timer_wakeup *wakeup =
container_of(ws, struct fsl_mpic_timer_wakeup, free_work);
mutex_lock(&sysfs_lock);
if (wakeup->timer) {
disable_irq_wake(wakeup->timer->irq);
mpic_free_timer(wakeup->timer);
}
wakeup->timer = NULL;
mutex_unlock(&sysfs_lock);
}
static irqreturn_t fsl_mpic_timer_irq(int irq, void *dev_id)
{
struct fsl_mpic_timer_wakeup *wakeup = dev_id;
schedule_work(&wakeup->free_work);
return wakeup->timer ? IRQ_HANDLED : IRQ_NONE;
}
static ssize_t fsl_timer_wakeup_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct timeval interval;
int val = 0;
mutex_lock(&sysfs_lock);
if (fsl_wakeup->timer) {
mpic_get_remain_time(fsl_wakeup->timer, &interval);
val = interval.tv_sec + 1;
}
mutex_unlock(&sysfs_lock);
return sprintf(buf, "%d\n", val);
}
static ssize_t fsl_timer_wakeup_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
{
struct timeval interval;
int ret;
interval.tv_usec = 0;
if (kstrtol(buf, 0, &interval.tv_sec))
return -EINVAL;
mutex_lock(&sysfs_lock);
if (fsl_wakeup->timer) {
disable_irq_wake(fsl_wakeup->timer->irq);
mpic_free_timer(fsl_wakeup->timer);
fsl_wakeup->timer = NULL;
}
if (!interval.tv_sec) {
mutex_unlock(&sysfs_lock);
return count;
}
fsl_wakeup->timer = mpic_request_timer(fsl_mpic_timer_irq,
fsl_wakeup, &interval);
if (!fsl_wakeup->timer) {
mutex_unlock(&sysfs_lock);
return -EINVAL;
}
ret = enable_irq_wake(fsl_wakeup->timer->irq);
if (ret) {
mpic_free_timer(fsl_wakeup->timer);
fsl_wakeup->timer = NULL;
mutex_unlock(&sysfs_lock);
return ret;
}
mpic_start_timer(fsl_wakeup->timer);
mutex_unlock(&sysfs_lock);
return count;
}
static struct device_attribute mpic_attributes = __ATTR(timer_wakeup, 0644,
fsl_timer_wakeup_show, fsl_timer_wakeup_store);
static int __init fsl_wakeup_sys_init(void)
{
int ret;
fsl_wakeup = kzalloc(sizeof(struct fsl_mpic_timer_wakeup), GFP_KERNEL);
if (!fsl_wakeup)
return -ENOMEM;
INIT_WORK(&fsl_wakeup->free_work, fsl_free_resource);
ret = device_create_file(mpic_subsys.dev_root, &mpic_attributes);
if (ret)
kfree(fsl_wakeup);
return ret;
}
static void __exit fsl_wakeup_sys_exit(void)
{
device_remove_file(mpic_subsys.dev_root, &mpic_attributes);
mutex_lock(&sysfs_lock);
if (fsl_wakeup->timer) {
disable_irq_wake(fsl_wakeup->timer->irq);
mpic_free_timer(fsl_wakeup->timer);
}
kfree(fsl_wakeup);
mutex_unlock(&sysfs_lock);
}
module_init(fsl_wakeup_sys_init);
module_exit(fsl_wakeup_sys_exit);
MODULE_DESCRIPTION("Freescale MPIC global timer wakeup driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Wang Dongsheng <dongsheng.wang@freescale.com>");

View file

@ -48,6 +48,12 @@
#define DBG(fmt...)
#endif
struct bus_type mpic_subsys = {
.name = "mpic",
.dev_name = "mpic",
};
EXPORT_SYMBOL_GPL(mpic_subsys);
static struct mpic *mpics;
static struct mpic *mpic_primary;
static DEFINE_RAW_SPINLOCK(mpic_lock);
@ -920,6 +926,22 @@ int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type)
return IRQ_SET_MASK_OK_NOCOPY;
}
static int mpic_irq_set_wake(struct irq_data *d, unsigned int on)
{
struct irq_desc *desc = container_of(d, struct irq_desc, irq_data);
struct mpic *mpic = mpic_from_irq_data(d);
if (!(mpic->flags & MPIC_FSL))
return -ENXIO;
if (on)
desc->action->flags |= IRQF_NO_SUSPEND;
else
desc->action->flags &= ~IRQF_NO_SUSPEND;
return 0;
}
void mpic_set_vector(unsigned int virq, unsigned int vector)
{
struct mpic *mpic = mpic_from_irq(virq);
@ -957,6 +979,7 @@ static struct irq_chip mpic_irq_chip = {
.irq_unmask = mpic_unmask_irq,
.irq_eoi = mpic_end_irq,
.irq_set_type = mpic_set_irq_type,
.irq_set_wake = mpic_irq_set_wake,
};
#ifdef CONFIG_SMP
@ -971,6 +994,7 @@ static struct irq_chip mpic_tm_chip = {
.irq_mask = mpic_mask_tm,
.irq_unmask = mpic_unmask_tm,
.irq_eoi = mpic_end_irq,
.irq_set_wake = mpic_irq_set_wake,
};
#ifdef CONFIG_MPIC_U3_HT_IRQS
@ -1173,10 +1197,33 @@ static struct irq_domain_ops mpic_host_ops = {
.xlate = mpic_host_xlate,
};
static u32 fsl_mpic_get_version(struct mpic *mpic)
{
u32 brr1;
if (!(mpic->flags & MPIC_FSL))
return 0;
brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
MPIC_FSL_BRR1);
return brr1 & MPIC_FSL_BRR1_VER;
}
/*
* Exported functions
*/
u32 fsl_mpic_primary_get_version(void)
{
struct mpic *mpic = mpic_primary;
if (mpic)
return fsl_mpic_get_version(mpic);
return 0;
}
struct mpic * __init mpic_alloc(struct device_node *node,
phys_addr_t phys_addr,
unsigned int flags,
@ -1323,7 +1370,6 @@ struct mpic * __init mpic_alloc(struct device_node *node,
mpic_map(mpic, mpic->paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
if (mpic->flags & MPIC_FSL) {
u32 brr1;
int ret;
/*
@ -1334,9 +1380,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
mpic_map(mpic, mpic->paddr, &mpic->thiscpuregs,
MPIC_CPU_THISBASE, 0x1000);
brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
MPIC_FSL_BRR1);
fsl_version = brr1 & MPIC_FSL_BRR1_VER;
fsl_version = fsl_mpic_get_version(mpic);
/* Error interrupt mask register (EIMR) is required for
* handling individual device error interrupts. EIMR
@ -1526,9 +1570,7 @@ void __init mpic_init(struct mpic *mpic)
mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf);
if (mpic->flags & MPIC_FSL) {
u32 brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
MPIC_FSL_BRR1);
u32 version = brr1 & MPIC_FSL_BRR1_VER;
u32 version = fsl_mpic_get_version(mpic);
/*
* Timer group B is present at the latest in MPIC 3.1 (e.g.
@ -1999,6 +2041,8 @@ static struct syscore_ops mpic_syscore_ops = {
static int mpic_init_sys(void)
{
register_syscore_ops(&mpic_syscore_ops);
subsys_system_register(&mpic_subsys, NULL);
return 0;
}

View file

@ -0,0 +1,593 @@
/*
* MPIC timer driver
*
* Copyright 2013 Freescale Semiconductor, Inc.
* Author: Dongsheng Wang <Dongsheng.Wang@freescale.com>
* Li Yang <leoli@freescale.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.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/syscore_ops.h>
#include <sysdev/fsl_soc.h>
#include <asm/io.h>
#include <asm/mpic_timer.h>
#define FSL_GLOBAL_TIMER 0x1
/* Clock Ratio
* Divide by 64 0x00000300
* Divide by 32 0x00000200
* Divide by 16 0x00000100
* Divide by 8 0x00000000 (Hardware default div)
*/
#define MPIC_TIMER_TCR_CLKDIV 0x00000300
#define MPIC_TIMER_TCR_ROVR_OFFSET 24
#define TIMER_STOP 0x80000000
#define TIMERS_PER_GROUP 4
#define MAX_TICKS (~0U >> 1)
#define MAX_TICKS_CASCADE (~0U)
#define TIMER_OFFSET(num) (1 << (TIMERS_PER_GROUP - 1 - num))
/* tv_usec should be less than ONE_SECOND, otherwise use tv_sec */
#define ONE_SECOND 1000000
struct timer_regs {
u32 gtccr;
u32 res0[3];
u32 gtbcr;
u32 res1[3];
u32 gtvpr;
u32 res2[3];
u32 gtdr;
u32 res3[3];
};
struct cascade_priv {
u32 tcr_value; /* TCR register: CASC & ROVR value */
unsigned int cascade_map; /* cascade map */
unsigned int timer_num; /* cascade control timer */
};
struct timer_group_priv {
struct timer_regs __iomem *regs;
struct mpic_timer timer[TIMERS_PER_GROUP];
struct list_head node;
unsigned int timerfreq;
unsigned int idle;
unsigned int flags;
spinlock_t lock;
void __iomem *group_tcr;
};
static struct cascade_priv cascade_timer[] = {
/* cascade timer 0 and 1 */
{0x1, 0xc, 0x1},
/* cascade timer 1 and 2 */
{0x2, 0x6, 0x2},
/* cascade timer 2 and 3 */
{0x4, 0x3, 0x3}
};
static LIST_HEAD(timer_group_list);
static void convert_ticks_to_time(struct timer_group_priv *priv,
const u64 ticks, struct timeval *time)
{
u64 tmp_sec;
time->tv_sec = (__kernel_time_t)div_u64(ticks, priv->timerfreq);
tmp_sec = (u64)time->tv_sec * (u64)priv->timerfreq;
time->tv_usec = (__kernel_suseconds_t)
div_u64((ticks - tmp_sec) * 1000000, priv->timerfreq);
return;
}
/* the time set by the user is converted to "ticks" */
static int convert_time_to_ticks(struct timer_group_priv *priv,
const struct timeval *time, u64 *ticks)
{
u64 max_value; /* prevent u64 overflow */
u64 tmp = 0;
u64 tmp_sec;
u64 tmp_ms;
u64 tmp_us;
max_value = div_u64(ULLONG_MAX, priv->timerfreq);
if (time->tv_sec > max_value ||
(time->tv_sec == max_value && time->tv_usec > 0))
return -EINVAL;
tmp_sec = (u64)time->tv_sec * (u64)priv->timerfreq;
tmp += tmp_sec;
tmp_ms = time->tv_usec / 1000;
tmp_ms = div_u64((u64)tmp_ms * (u64)priv->timerfreq, 1000);
tmp += tmp_ms;
tmp_us = time->tv_usec % 1000;
tmp_us = div_u64((u64)tmp_us * (u64)priv->timerfreq, 1000000);
tmp += tmp_us;
*ticks = tmp;
return 0;
}
/* detect whether there is a cascade timer available */
static struct mpic_timer *detect_idle_cascade_timer(
struct timer_group_priv *priv)
{
struct cascade_priv *casc_priv;
unsigned int map;
unsigned int array_size = ARRAY_SIZE(cascade_timer);
unsigned int num;
unsigned int i;
unsigned long flags;
casc_priv = cascade_timer;
for (i = 0; i < array_size; i++) {
spin_lock_irqsave(&priv->lock, flags);
map = casc_priv->cascade_map & priv->idle;
if (map == casc_priv->cascade_map) {
num = casc_priv->timer_num;
priv->timer[num].cascade_handle = casc_priv;
/* set timer busy */
priv->idle &= ~casc_priv->cascade_map;
spin_unlock_irqrestore(&priv->lock, flags);
return &priv->timer[num];
}
spin_unlock_irqrestore(&priv->lock, flags);
casc_priv++;
}
return NULL;
}
static int set_cascade_timer(struct timer_group_priv *priv, u64 ticks,
unsigned int num)
{
struct cascade_priv *casc_priv;
u32 tcr;
u32 tmp_ticks;
u32 rem_ticks;
/* set group tcr reg for cascade */
casc_priv = priv->timer[num].cascade_handle;
if (!casc_priv)
return -EINVAL;
tcr = casc_priv->tcr_value |
(casc_priv->tcr_value << MPIC_TIMER_TCR_ROVR_OFFSET);
setbits32(priv->group_tcr, tcr);
tmp_ticks = div_u64_rem(ticks, MAX_TICKS_CASCADE, &rem_ticks);
out_be32(&priv->regs[num].gtccr, 0);
out_be32(&priv->regs[num].gtbcr, tmp_ticks | TIMER_STOP);
out_be32(&priv->regs[num - 1].gtccr, 0);
out_be32(&priv->regs[num - 1].gtbcr, rem_ticks);
return 0;
}
static struct mpic_timer *get_cascade_timer(struct timer_group_priv *priv,
u64 ticks)
{
struct mpic_timer *allocated_timer;
/* Two cascade timers: Support the maximum time */
const u64 max_ticks = (u64)MAX_TICKS * (u64)MAX_TICKS_CASCADE;
int ret;
if (ticks > max_ticks)
return NULL;
/* detect idle timer */
allocated_timer = detect_idle_cascade_timer(priv);
if (!allocated_timer)
return NULL;
/* set ticks to timer */
ret = set_cascade_timer(priv, ticks, allocated_timer->num);
if (ret < 0)
return NULL;
return allocated_timer;
}
static struct mpic_timer *get_timer(const struct timeval *time)
{
struct timer_group_priv *priv;
struct mpic_timer *timer;
u64 ticks;
unsigned int num;
unsigned int i;
unsigned long flags;
int ret;
list_for_each_entry(priv, &timer_group_list, node) {
ret = convert_time_to_ticks(priv, time, &ticks);
if (ret < 0)
return NULL;
if (ticks > MAX_TICKS) {
if (!(priv->flags & FSL_GLOBAL_TIMER))
return NULL;
timer = get_cascade_timer(priv, ticks);
if (!timer)
continue;
return timer;
}
for (i = 0; i < TIMERS_PER_GROUP; i++) {
/* one timer: Reverse allocation */
num = TIMERS_PER_GROUP - 1 - i;
spin_lock_irqsave(&priv->lock, flags);
if (priv->idle & (1 << i)) {
/* set timer busy */
priv->idle &= ~(1 << i);
/* set ticks & stop timer */
out_be32(&priv->regs[num].gtbcr,
ticks | TIMER_STOP);
out_be32(&priv->regs[num].gtccr, 0);
priv->timer[num].cascade_handle = NULL;
spin_unlock_irqrestore(&priv->lock, flags);
return &priv->timer[num];
}
spin_unlock_irqrestore(&priv->lock, flags);
}
}
return NULL;
}
/**
* mpic_start_timer - start hardware timer
* @handle: the timer to be started.
*
* It will do ->fn(->dev) callback from the hardware interrupt at
* the ->timeval point in the future.
*/
void mpic_start_timer(struct mpic_timer *handle)
{
struct timer_group_priv *priv = container_of(handle,
struct timer_group_priv, timer[handle->num]);
clrbits32(&priv->regs[handle->num].gtbcr, TIMER_STOP);
}
EXPORT_SYMBOL(mpic_start_timer);
/**
* mpic_stop_timer - stop hardware timer
* @handle: the timer to be stoped
*
* The timer periodically generates an interrupt. Unless user stops the timer.
*/
void mpic_stop_timer(struct mpic_timer *handle)
{
struct timer_group_priv *priv = container_of(handle,
struct timer_group_priv, timer[handle->num]);
struct cascade_priv *casc_priv;
setbits32(&priv->regs[handle->num].gtbcr, TIMER_STOP);
casc_priv = priv->timer[handle->num].cascade_handle;
if (casc_priv) {
out_be32(&priv->regs[handle->num].gtccr, 0);
out_be32(&priv->regs[handle->num - 1].gtccr, 0);
} else {
out_be32(&priv->regs[handle->num].gtccr, 0);
}
}
EXPORT_SYMBOL(mpic_stop_timer);
/**
* mpic_get_remain_time - get timer time
* @handle: the timer to be selected.
* @time: time for timer
*
* Query timer remaining time.
*/
void mpic_get_remain_time(struct mpic_timer *handle, struct timeval *time)
{
struct timer_group_priv *priv = container_of(handle,
struct timer_group_priv, timer[handle->num]);
struct cascade_priv *casc_priv;
u64 ticks;
u32 tmp_ticks;
casc_priv = priv->timer[handle->num].cascade_handle;
if (casc_priv) {
tmp_ticks = in_be32(&priv->regs[handle->num].gtccr);
ticks = ((u64)tmp_ticks & UINT_MAX) * (u64)MAX_TICKS_CASCADE;
tmp_ticks = in_be32(&priv->regs[handle->num - 1].gtccr);
ticks += tmp_ticks;
} else {
ticks = in_be32(&priv->regs[handle->num].gtccr);
}
convert_ticks_to_time(priv, ticks, time);
}
EXPORT_SYMBOL(mpic_get_remain_time);
/**
* mpic_free_timer - free hardware timer
* @handle: the timer to be removed.
*
* Free the timer.
*
* Note: can not be used in interrupt context.
*/
void mpic_free_timer(struct mpic_timer *handle)
{
struct timer_group_priv *priv = container_of(handle,
struct timer_group_priv, timer[handle->num]);
struct cascade_priv *casc_priv;
unsigned long flags;
mpic_stop_timer(handle);
casc_priv = priv->timer[handle->num].cascade_handle;
free_irq(priv->timer[handle->num].irq, priv->timer[handle->num].dev);
spin_lock_irqsave(&priv->lock, flags);
if (casc_priv) {
u32 tcr;
tcr = casc_priv->tcr_value | (casc_priv->tcr_value <<
MPIC_TIMER_TCR_ROVR_OFFSET);
clrbits32(priv->group_tcr, tcr);
priv->idle |= casc_priv->cascade_map;
priv->timer[handle->num].cascade_handle = NULL;
} else {
priv->idle |= TIMER_OFFSET(handle->num);
}
spin_unlock_irqrestore(&priv->lock, flags);
}
EXPORT_SYMBOL(mpic_free_timer);
/**
* mpic_request_timer - get a hardware timer
* @fn: interrupt handler function
* @dev: callback function of the data
* @time: time for timer
*
* This executes the "request_irq", returning NULL
* else "handle" on success.
*/
struct mpic_timer *mpic_request_timer(irq_handler_t fn, void *dev,
const struct timeval *time)
{
struct mpic_timer *allocated_timer;
int ret;
if (list_empty(&timer_group_list))
return NULL;
if (!(time->tv_sec + time->tv_usec) ||
time->tv_sec < 0 || time->tv_usec < 0)
return NULL;
if (time->tv_usec > ONE_SECOND)
return NULL;
allocated_timer = get_timer(time);
if (!allocated_timer)
return NULL;
ret = request_irq(allocated_timer->irq, fn,
IRQF_TRIGGER_LOW, "global-timer", dev);
if (ret) {
mpic_free_timer(allocated_timer);
return NULL;
}
allocated_timer->dev = dev;
return allocated_timer;
}
EXPORT_SYMBOL(mpic_request_timer);
static int timer_group_get_freq(struct device_node *np,
struct timer_group_priv *priv)
{
u32 div;
if (priv->flags & FSL_GLOBAL_TIMER) {
struct device_node *dn;
dn = of_find_compatible_node(NULL, NULL, "fsl,mpic");
if (dn) {
of_property_read_u32(dn, "clock-frequency",
&priv->timerfreq);
of_node_put(dn);
}
}
if (priv->timerfreq <= 0)
return -EINVAL;
if (priv->flags & FSL_GLOBAL_TIMER) {
div = (1 << (MPIC_TIMER_TCR_CLKDIV >> 8)) * 8;
priv->timerfreq /= div;
}
return 0;
}
static int timer_group_get_irq(struct device_node *np,
struct timer_group_priv *priv)
{
const u32 all_timer[] = { 0, TIMERS_PER_GROUP };
const u32 *p;
u32 offset;
u32 count;
unsigned int i;
unsigned int j;
unsigned int irq_index = 0;
unsigned int irq;
int len;
p = of_get_property(np, "fsl,available-ranges", &len);
if (p && len % (2 * sizeof(u32)) != 0) {
pr_err("%s: malformed available-ranges property.\n",
np->full_name);
return -EINVAL;
}
if (!p) {
p = all_timer;
len = sizeof(all_timer);
}
len /= 2 * sizeof(u32);
for (i = 0; i < len; i++) {
offset = p[i * 2];
count = p[i * 2 + 1];
for (j = 0; j < count; j++) {
irq = irq_of_parse_and_map(np, irq_index);
if (!irq) {
pr_err("%s: irq parse and map failed.\n",
np->full_name);
return -EINVAL;
}
/* Set timer idle */
priv->idle |= TIMER_OFFSET((offset + j));
priv->timer[offset + j].irq = irq;
priv->timer[offset + j].num = offset + j;
irq_index++;
}
}
return 0;
}
static void timer_group_init(struct device_node *np)
{
struct timer_group_priv *priv;
unsigned int i = 0;
int ret;
priv = kzalloc(sizeof(struct timer_group_priv), GFP_KERNEL);
if (!priv) {
pr_err("%s: cannot allocate memory for group.\n",
np->full_name);
return;
}
if (of_device_is_compatible(np, "fsl,mpic-global-timer"))
priv->flags |= FSL_GLOBAL_TIMER;
priv->regs = of_iomap(np, i++);
if (!priv->regs) {
pr_err("%s: cannot ioremap timer register address.\n",
np->full_name);
goto out;
}
if (priv->flags & FSL_GLOBAL_TIMER) {
priv->group_tcr = of_iomap(np, i++);
if (!priv->group_tcr) {
pr_err("%s: cannot ioremap tcr address.\n",
np->full_name);
goto out;
}
}
ret = timer_group_get_freq(np, priv);
if (ret < 0) {
pr_err("%s: cannot get timer frequency.\n", np->full_name);
goto out;
}
ret = timer_group_get_irq(np, priv);
if (ret < 0) {
pr_err("%s: cannot get timer irqs.\n", np->full_name);
goto out;
}
spin_lock_init(&priv->lock);
/* Init FSL timer hardware */
if (priv->flags & FSL_GLOBAL_TIMER)
setbits32(priv->group_tcr, MPIC_TIMER_TCR_CLKDIV);
list_add_tail(&priv->node, &timer_group_list);
return;
out:
if (priv->regs)
iounmap(priv->regs);
if (priv->group_tcr)
iounmap(priv->group_tcr);
kfree(priv);
}
static void mpic_timer_resume(void)
{
struct timer_group_priv *priv;
list_for_each_entry(priv, &timer_group_list, node) {
/* Init FSL timer hardware */
if (priv->flags & FSL_GLOBAL_TIMER)
setbits32(priv->group_tcr, MPIC_TIMER_TCR_CLKDIV);
}
}
static const struct of_device_id mpic_timer_ids[] = {
{ .compatible = "fsl,mpic-global-timer", },
{},
};
static struct syscore_ops mpic_timer_syscore_ops = {
.resume = mpic_timer_resume,
};
static int __init mpic_timer_init(void)
{
struct device_node *np = NULL;
for_each_matching_node(np, mpic_timer_ids)
timer_group_init(np);
register_syscore_ops(&mpic_timer_syscore_ops);
if (list_empty(&timer_group_list))
return -ENODEV;
return 0;
}
subsys_initcall(mpic_timer_init);

View file

@ -338,6 +338,14 @@ static int cpm_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
tptr = 0;
rptr = 0;
/*
* If there was a collision in the last i2c transaction,
* Set I2COM_MASTER as it was cleared during collision.
*/
if (in_be16(&tbdf->cbd_sc) & BD_SC_CL) {
out_8(&cpm->i2c_reg->i2com, I2COM_MASTER);
}
while (tptr < num) {
pmsg = &msgs[tptr];
dev_dbg(&adap->dev, "R: %d T: %d\n", rptr, tptr);

View file

@ -138,6 +138,14 @@ static void __booke_wdt_enable(void *data)
val &= ~WDTP_MASK;
val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(booke_wdt_period));
#ifdef CONFIG_PPC_BOOK3E_64
/*
* Crit ints are currently broken on PPC64 Book-E, so
* just disable them for now.
*/
val &= ~TCR_WIE;
#endif
mtspr(SPRN_TCR, val);
}