mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-03 09:04:21 +08:00
Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
* 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: powerpc/mm: Lockless get_user_pages_fast() for 64-bit (v3) powerpc: Don't use the wrong thread_struct for ptrace get/set VSX regs powerpc: Fix ptrace buffer size for VSX powerpc: Correctly hookup PTRACE_GET/SETVSRREGS for 32 bit processes ide/powermac: Fix use of uninitialized pointer on media-bay powerpc: Allow non-hcall return values for lparcfg writes ipmi/powerpc: Use linux/of_{device,platform}.h instead of asm powerpc/fsl: proliferate simple-bus compatibility to soc nodes Documentation: remove old sbc8260 board specific information cpm2: Rework baud rate generators configuration to support external clocks. powerpc: rtc_cmos_setup: assign interrupts only if there is i8259 PIC cpm_uart: Add generic clock API support to set baudrates cpm_uart: Modem control lines support powerpc: implement GPIO LIB API on CPM1 Freescale SoC. cpm2: Implement GPIO LIB API on CPM2 Freescale SoC. powerpc: Fix 8xx build failure powerpc: clean up the Book-E HW watchpoint support
This commit is contained in:
commit
660fc1f4d8
@ -20,8 +20,6 @@ mpc52xx-device-tree-bindings.txt
|
||||
- MPC5200 Device Tree Bindings
|
||||
ppc_htab.txt
|
||||
- info about the Linux/PPC /proc/ppc_htab entry
|
||||
SBC8260_memory_mapping.txt
|
||||
- EST SBC8260 board info
|
||||
smp.txt
|
||||
- use and state info about Linux/PPC on MP machines
|
||||
sound.txt
|
||||
|
@ -1,197 +0,0 @@
|
||||
Please mail me (Jon Diekema, diekema_jon@si.com or diekema@cideas.com)
|
||||
if you have questions, comments or corrections.
|
||||
|
||||
* EST SBC8260 Linux memory mapping rules
|
||||
|
||||
http://www.estc.com/
|
||||
http://www.estc.com/products/boards/SBC8260-8240_ds.html
|
||||
|
||||
Initial conditions:
|
||||
-------------------
|
||||
|
||||
Tasks that need to be perform by the boot ROM before control is
|
||||
transferred to zImage (compressed Linux kernel):
|
||||
|
||||
- Define the IMMR to 0xf0000000
|
||||
|
||||
- Initialize the memory controller so that RAM is available at
|
||||
physical address 0x00000000. On the SBC8260 is this 16M (64M)
|
||||
SDRAM.
|
||||
|
||||
- The boot ROM should only clear the RAM that it is using.
|
||||
|
||||
The reason for doing this is to enhances the chances of a
|
||||
successful post mortem on a Linux panic. One of the first
|
||||
items to examine is the 16k (LOG_BUF_LEN) circular console
|
||||
buffer called log_buf which is defined in kernel/printk.c.
|
||||
|
||||
- To enhance boot ROM performance, the I-cache can be enabled.
|
||||
|
||||
Date: Mon, 22 May 2000 14:21:10 -0700
|
||||
From: Neil Russell <caret@c-side.com>
|
||||
|
||||
LiMon (LInux MONitor) runs with and starts Linux with MMU
|
||||
off, I-cache enabled, D-cache disabled. The I-cache doesn't
|
||||
need hints from the MMU to work correctly as the D-cache
|
||||
does. No D-cache means no special code to handle devices in
|
||||
the presence of cache (no snooping, etc). The use of the
|
||||
I-cache means that the monitor can run acceptably fast
|
||||
directly from ROM, rather than having to copy it to RAM.
|
||||
|
||||
- Build the board information structure (see
|
||||
include/asm-ppc/est8260.h for its definition)
|
||||
|
||||
- The compressed Linux kernel (zImage) contains a bootstrap loader
|
||||
that is position independent; you can load it into any RAM,
|
||||
ROM or FLASH memory address >= 0x00500000 (above 5 MB), or
|
||||
at its link address of 0x00400000 (4 MB).
|
||||
|
||||
Note: If zImage is loaded at its link address of 0x00400000 (4 MB),
|
||||
then zImage will skip the step of moving itself to
|
||||
its link address.
|
||||
|
||||
- Load R3 with the address of the board information structure
|
||||
|
||||
- Transfer control to zImage
|
||||
|
||||
- The Linux console port is SMC1, and the baud rate is controlled
|
||||
from the bi_baudrate field of the board information structure.
|
||||
On thing to keep in mind when picking the baud rate, is that
|
||||
there is no flow control on the SMC ports. I would stick
|
||||
with something safe and standard like 19200.
|
||||
|
||||
On the EST SBC8260, the SMC1 port is on the COM1 connector of
|
||||
the board.
|
||||
|
||||
|
||||
EST SBC8260 defaults:
|
||||
---------------------
|
||||
|
||||
Chip
|
||||
Memory Sel Bus Use
|
||||
--------------------- --- --- ----------------------------------
|
||||
0x00000000-0x03FFFFFF CS2 60x (16M or 64M)/64M SDRAM
|
||||
0x04000000-0x04FFFFFF CS4 local 4M/16M SDRAM (soldered to the board)
|
||||
0x21000000-0x21000000 CS7 60x 1B/64K Flash present detect (from the flash SIMM)
|
||||
0x21000001-0x21000001 CS7 60x 1B/64K Switches (read) and LEDs (write)
|
||||
0x22000000-0x2200FFFF CS5 60x 8K/64K EEPROM
|
||||
0xFC000000-0xFCFFFFFF CS6 60x 2M/16M flash (8 bits wide, soldered to the board)
|
||||
0xFE000000-0xFFFFFFFF CS0 60x 4M/16M flash (SIMM)
|
||||
|
||||
Notes:
|
||||
------
|
||||
|
||||
- The chip selects can map 32K blocks and up (powers of 2)
|
||||
|
||||
- The SDRAM machine can handled up to 128Mbytes per chip select
|
||||
|
||||
- Linux uses the 60x bus memory (the SDRAM DIMM) for the
|
||||
communications buffers.
|
||||
|
||||
- BATs can map 128K-256Mbytes each. There are four data BATs and
|
||||
four instruction BATs. Generally the data and instruction BATs
|
||||
are mapped the same.
|
||||
|
||||
- The IMMR must be set above the kernel virtual memory addresses,
|
||||
which start at 0xC0000000. Otherwise, the kernel may crash as
|
||||
soon as you start any threads or processes due to VM collisions
|
||||
in the kernel or user process space.
|
||||
|
||||
|
||||
Details from Dan Malek <dan_malek@mvista.com> on 10/29/1999:
|
||||
|
||||
The user application virtual space consumes the first 2 Gbytes
|
||||
(0x00000000 to 0x7FFFFFFF). The kernel virtual text starts at
|
||||
0xC0000000, with data following. There is a "protection hole"
|
||||
between the end of kernel data and the start of the kernel
|
||||
dynamically allocated space, but this space is still within
|
||||
0xCxxxxxxx.
|
||||
|
||||
Obviously the kernel can't map any physical addresses 1:1 in
|
||||
these ranges.
|
||||
|
||||
|
||||
Details from Dan Malek <dan_malek@mvista.com> on 5/19/2000:
|
||||
|
||||
During the early kernel initialization, the kernel virtual
|
||||
memory allocator is not operational. Prior to this KVM
|
||||
initialization, we choose to map virtual to physical addresses
|
||||
1:1. That is, the kernel virtual address exactly matches the
|
||||
physical address on the bus. These mappings are typically done
|
||||
in arch/ppc/kernel/head.S, or arch/ppc/mm/init.c. Only
|
||||
absolutely necessary mappings should be done at this time, for
|
||||
example board control registers or a serial uart. Normal device
|
||||
driver initialization should map resources later when necessary.
|
||||
|
||||
Although platform dependent, and certainly the case for embedded
|
||||
8xx, traditionally memory is mapped at physical address zero,
|
||||
and I/O devices above physical address 0x80000000. The lowest
|
||||
and highest (above 0xf0000000) I/O addresses are traditionally
|
||||
used for devices or registers we need to map during kernel
|
||||
initialization and prior to KVM operation. For this reason,
|
||||
and since it followed prior PowerPC platform examples, I chose
|
||||
to map the embedded 8xx kernel to the 0xc0000000 virtual address.
|
||||
This way, we can enable the MMU to map the kernel for proper
|
||||
operation, and still map a few windows before the KVM is operational.
|
||||
|
||||
On some systems, you could possibly run the kernel at the
|
||||
0x80000000 or any other virtual address. It just depends upon
|
||||
mapping that must be done prior to KVM operational. You can never
|
||||
map devices or kernel spaces that overlap with the user virtual
|
||||
space. This is why default IMMR mapping used by most BDM tools
|
||||
won't work. They put the IMMR at something like 0x10000000 or
|
||||
0x02000000 for example. You simply can't map these addresses early
|
||||
in the kernel, and continue proper system operation.
|
||||
|
||||
The embedded 8xx/82xx kernel is mature enough that all you should
|
||||
need to do is map the IMMR someplace at or above 0xf0000000 and it
|
||||
should boot far enough to get serial console messages and KGDB
|
||||
connected on any platform. There are lots of other subtle memory
|
||||
management design features that you simply don't need to worry
|
||||
about. If you are changing functions related to MMU initialization,
|
||||
you are likely breaking things that are known to work and are
|
||||
heading down a path of disaster and frustration. Your changes
|
||||
should be to make the flexibility of the processor fit Linux,
|
||||
not force arbitrary and non-workable memory mappings into Linux.
|
||||
|
||||
- You don't want to change KERNELLOAD or KERNELBASE, otherwise the
|
||||
virtual memory and MMU code will get confused.
|
||||
|
||||
arch/ppc/Makefile:KERNELLOAD = 0xc0000000
|
||||
|
||||
include/asm-ppc/page.h:#define PAGE_OFFSET 0xc0000000
|
||||
include/asm-ppc/page.h:#define KERNELBASE PAGE_OFFSET
|
||||
|
||||
- RAM is at physical address 0x00000000, and gets mapped to
|
||||
virtual address 0xC0000000 for the kernel.
|
||||
|
||||
|
||||
Physical addresses used by the Linux kernel:
|
||||
--------------------------------------------
|
||||
|
||||
0x00000000-0x3FFFFFFF 1GB reserved for RAM
|
||||
0xF0000000-0xF001FFFF 128K IMMR 64K used for dual port memory,
|
||||
64K for 8260 registers
|
||||
|
||||
|
||||
Logical addresses used by the Linux kernel:
|
||||
-------------------------------------------
|
||||
|
||||
0xF0000000-0xFFFFFFFF 256M BAT0 (IMMR: dual port RAM, registers)
|
||||
0xE0000000-0xEFFFFFFF 256M BAT1 (I/O space for custom boards)
|
||||
0xC0000000-0xCFFFFFFF 256M BAT2 (RAM)
|
||||
0xD0000000-0xDFFFFFFF 256M BAT3 (if RAM > 256MByte)
|
||||
|
||||
|
||||
EST SBC8260 Linux mapping:
|
||||
--------------------------
|
||||
|
||||
DBAT0, IBAT0, cache inhibited:
|
||||
|
||||
Chip
|
||||
Memory Sel Use
|
||||
--------------------- --- ---------------------------------
|
||||
0xF0000000-0xF001FFFF n/a IMMR: dual port RAM, registers
|
||||
|
||||
DBAT1, IBAT1, cache inhibited:
|
||||
|
@ -7,6 +7,15 @@ Currently defined compatibles:
|
||||
- fsl,cpm2-scc-uart
|
||||
- fsl,qe-uart
|
||||
|
||||
Modem control lines connected to GPIO controllers are listed in the gpios
|
||||
property as described in booting-without-of.txt, section IX.1 in the following
|
||||
order:
|
||||
|
||||
CTS, RTS, DCD, DSR, DTR, and RI.
|
||||
|
||||
The gpios property is optional and can be left out when control lines are
|
||||
not used.
|
||||
|
||||
Example:
|
||||
|
||||
serial@11a00 {
|
||||
@ -18,4 +27,6 @@ Example:
|
||||
interrupt-parent = <&PIC>;
|
||||
fsl,cpm-brg = <1>;
|
||||
fsl,cpm-command = <00800000>;
|
||||
gpios = <&gpio_c 15 0
|
||||
&gpio_d 29 0>;
|
||||
};
|
||||
|
@ -42,6 +42,9 @@ config GENERIC_HARDIRQS
|
||||
bool
|
||||
default y
|
||||
|
||||
config HAVE_GET_USER_PAGES_FAST
|
||||
def_bool PPC64
|
||||
|
||||
config HAVE_SETUP_PER_CPU_AREA
|
||||
def_bool PPC64
|
||||
|
||||
|
@ -68,6 +68,7 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
device_type = "soc";
|
||||
compatible = "simple-bus";
|
||||
ranges = <0x0 0xe0000000 0x00100000>;
|
||||
reg = <0xe0000000 0x00000200>;
|
||||
bus-frequency = <132000000>;
|
||||
|
@ -51,6 +51,7 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
device_type = "soc";
|
||||
compatible = "simple-bus";
|
||||
ranges = <0x0 0xe0000000 0x00100000>;
|
||||
reg = <0xe0000000 0x00000200>;
|
||||
bus-frequency = <0>;
|
||||
|
@ -52,6 +52,7 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
device_type = "soc";
|
||||
compatible = "simple-bus";
|
||||
ranges = <0x0 0xe0000000 0x00100000>;
|
||||
reg = <0xe0000000 0x00000200>;
|
||||
bus-frequency = <0>; // from bootloader
|
||||
|
@ -50,6 +50,7 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
device_type = "soc";
|
||||
compatible = "simple-bus";
|
||||
ranges = <0x0 0xe0000000 0x00100000>;
|
||||
reg = <0xe0000000 0x00000200>;
|
||||
bus-frequency = <0>; // from bootloader
|
||||
|
@ -57,6 +57,7 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
device_type = "soc";
|
||||
compatible = "simple-bus";
|
||||
ranges = <0x0 0xe0000000 0x00100000>;
|
||||
reg = <0xe0000000 0x00000200>;
|
||||
bus-frequency = <0>;
|
||||
|
@ -61,6 +61,7 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
device_type = "soc";
|
||||
compatible = "simple-bus";
|
||||
ranges = <0x0 0xe0000000 0x00100000>;
|
||||
reg = <0xe0000000 0x00000200>;
|
||||
bus-frequency = <264000000>;
|
||||
|
@ -149,18 +149,14 @@
|
||||
};
|
||||
|
||||
crypto@30000 {
|
||||
compatible = "fsl,sec2-crypto";
|
||||
compatible = "fsl,sec2.0";
|
||||
reg = <0x30000 0x10000>;
|
||||
interrupts = <11 8>;
|
||||
interrupts = <11 0x8>;
|
||||
interrupt-parent = <&ipic>;
|
||||
num-channels = <4>;
|
||||
channel-fifo-len = <24>;
|
||||
exec-units-mask = <0x7e>;
|
||||
/*
|
||||
* desc mask is for rev1.x, we need runtime fixup
|
||||
* for >=2.x
|
||||
*/
|
||||
descriptor-types-mask = <0x1010ebf>;
|
||||
fsl,num-channels = <4>;
|
||||
fsl,channel-fifo-len = <24>;
|
||||
fsl,exec-units-mask = <0x7e>;
|
||||
fsl,descriptor-types-mask = <0x01010ebf>;
|
||||
};
|
||||
|
||||
ipic: interrupt-controller@700 {
|
||||
|
@ -117,6 +117,7 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
device_type = "soc";
|
||||
compatible = "simple-bus";
|
||||
ranges = <0x0 0xe0000000 0x00100000>;
|
||||
reg = <0xe0000000 0x00000200>;
|
||||
bus-frequency = <0>;
|
||||
|
@ -117,6 +117,7 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
device_type = "soc";
|
||||
compatible = "simple-bus";
|
||||
ranges = <0x0 0xe0000000 0x00100000>;
|
||||
reg = <0xe0000000 0x00000200>;
|
||||
bus-frequency = <0>;
|
||||
|
@ -117,6 +117,7 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
device_type = "soc";
|
||||
compatible = "simple-bus";
|
||||
ranges = <0x0 0xe0000000 0x00100000>;
|
||||
reg = <0xe0000000 0x00000200>;
|
||||
bus-frequency = <0>;
|
||||
|
@ -49,6 +49,7 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
device_type = "soc";
|
||||
compatible = "simple-bus";
|
||||
ranges = <0x0 0xffe00000 0x100000>;
|
||||
reg = <0xffe00000 0x1000>;
|
||||
bus-frequency = <0>; // Filled out by uboot.
|
||||
|
@ -53,6 +53,7 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
device_type = "soc";
|
||||
compatible = "simple-bus";
|
||||
ranges = <0x0 0xe0000000 0x100000>;
|
||||
reg = <0xe0000000 0x100000>; // CCSRBAR 1M
|
||||
bus-frequency = <0>;
|
||||
|
@ -53,6 +53,7 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
device_type = "soc";
|
||||
compatible = "simple-bus";
|
||||
ranges = <0x0 0xe0000000 0x100000>;
|
||||
reg = <0xe0000000 0x1000>; // CCSRBAR 1M
|
||||
bus-frequency = <0>;
|
||||
|
@ -54,6 +54,7 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
device_type = "soc";
|
||||
compatible = "simple-bus";
|
||||
|
||||
ranges = <0x0 0xe0000000 0x100000>;
|
||||
reg = <0xe0000000 0x1000>; // CCSRBAR 1M
|
||||
|
@ -58,6 +58,7 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
device_type = "soc";
|
||||
compatible = "simple-bus";
|
||||
ranges = <0x0 0xe0000000 0x100000>;
|
||||
reg = <0xe0000000 0x1000>; // CCSRBAR
|
||||
bus-frequency = <0>;
|
||||
|
@ -53,6 +53,7 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
device_type = "soc";
|
||||
compatible = "simple-bus";
|
||||
ranges = <0x0 0xe0000000 0x100000>;
|
||||
reg = <0xe0000000 0x1000>; // CCSRBAR 1M
|
||||
bus-frequency = <0>;
|
||||
|
@ -53,6 +53,7 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
device_type = "soc";
|
||||
compatible = "simple-bus";
|
||||
ranges = <0x0 0xe0000000 0x100000>;
|
||||
reg = <0xe0000000 0x200>;
|
||||
bus-frequency = <330000000>;
|
||||
|
@ -60,6 +60,7 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
device_type = "soc";
|
||||
compatible = "simple-bus";
|
||||
ranges = <0x0 0xe0000000 0x100000>;
|
||||
reg = <0xe0000000 0x1000>;
|
||||
bus-frequency = <0>;
|
||||
|
@ -68,6 +68,7 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
device_type = "soc";
|
||||
compatible = "simple-bus";
|
||||
ranges = <0x0 0xffe00000 0x100000>;
|
||||
reg = <0xffe00000 0x1000>; // CCSRBAR & soc regs, remove once parse code for immrbase fixed
|
||||
bus-frequency = <0>; // Filled out by uboot.
|
||||
|
@ -636,10 +636,6 @@ static ssize_t lparcfg_write(struct file *file, const char __user * buf,
|
||||
retval = -EIO;
|
||||
} else if (retval == H_PARAMETER) {
|
||||
retval = -EINVAL;
|
||||
} else {
|
||||
printk(KERN_WARNING "%s: received unknown hv return code %ld",
|
||||
__func__, retval);
|
||||
retval = -EIO;
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
@ -375,7 +375,7 @@ static int vsr_get(struct task_struct *target, const struct user_regset *regset,
|
||||
flush_vsx_to_thread(target);
|
||||
|
||||
for (i = 0; i < 32 ; i++)
|
||||
buf[i] = current->thread.fpr[i][TS_VSRLOWOFFSET];
|
||||
buf[i] = target->thread.fpr[i][TS_VSRLOWOFFSET];
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
buf, 0, 32 * sizeof(double));
|
||||
|
||||
@ -394,7 +394,7 @@ static int vsr_set(struct task_struct *target, const struct user_regset *regset,
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
buf, 0, 32 * sizeof(double));
|
||||
for (i = 0; i < 32 ; i++)
|
||||
current->thread.fpr[i][TS_VSRLOWOFFSET] = buf[i];
|
||||
target->thread.fpr[i][TS_VSRLOWOFFSET] = buf[i];
|
||||
|
||||
|
||||
return ret;
|
||||
@ -975,15 +975,13 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
||||
case PTRACE_GETVSRREGS:
|
||||
return copy_regset_to_user(child, &user_ppc_native_view,
|
||||
REGSET_VSX,
|
||||
0, (32 * sizeof(vector128) +
|
||||
sizeof(u32)),
|
||||
0, 32 * sizeof(double),
|
||||
(void __user *) data);
|
||||
|
||||
case PTRACE_SETVSRREGS:
|
||||
return copy_regset_from_user(child, &user_ppc_native_view,
|
||||
REGSET_VSX,
|
||||
0, (32 * sizeof(vector128) +
|
||||
sizeof(u32)),
|
||||
0, 32 * sizeof(double),
|
||||
(const void __user *) data);
|
||||
#endif
|
||||
#ifdef CONFIG_SPE
|
||||
|
@ -294,6 +294,8 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
|
||||
case PTRACE_SETFPREGS:
|
||||
case PTRACE_GETVRREGS:
|
||||
case PTRACE_SETVRREGS:
|
||||
case PTRACE_GETVSRREGS:
|
||||
case PTRACE_SETVSRREGS:
|
||||
case PTRACE_GETREGS64:
|
||||
case PTRACE_SETREGS64:
|
||||
case PPC_PTRACE_GETFPREGS:
|
||||
|
@ -12,7 +12,8 @@ obj-y := fault.o mem.o \
|
||||
mmu_context_$(CONFIG_WORD_SIZE).o
|
||||
hash-$(CONFIG_PPC_NATIVE) := hash_native_64.o
|
||||
obj-$(CONFIG_PPC64) += hash_utils_64.o \
|
||||
slb_low.o slb.o stab.o mmap.o $(hash-y)
|
||||
slb_low.o slb.o stab.o \
|
||||
gup.o mmap.o $(hash-y)
|
||||
obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o
|
||||
obj-$(CONFIG_PPC_STD_MMU) += hash_low_$(CONFIG_WORD_SIZE).o \
|
||||
tlb_$(CONFIG_WORD_SIZE).o
|
||||
|
280
arch/powerpc/mm/gup.c
Normal file
280
arch/powerpc/mm/gup.c
Normal file
@ -0,0 +1,280 @@
|
||||
/*
|
||||
* Lockless get_user_pages_fast for powerpc
|
||||
*
|
||||
* Copyright (C) 2008 Nick Piggin
|
||||
* Copyright (C) 2008 Novell Inc.
|
||||
*/
|
||||
#undef DEBUG
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/hugetlb.h>
|
||||
#include <linux/vmstat.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
/*
|
||||
* The performance critical leaf functions are made noinline otherwise gcc
|
||||
* inlines everything into a single function which results in too much
|
||||
* register pressure.
|
||||
*/
|
||||
static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
|
||||
unsigned long end, int write, struct page **pages, int *nr)
|
||||
{
|
||||
unsigned long mask, result;
|
||||
pte_t *ptep;
|
||||
|
||||
result = _PAGE_PRESENT|_PAGE_USER;
|
||||
if (write)
|
||||
result |= _PAGE_RW;
|
||||
mask = result | _PAGE_SPECIAL;
|
||||
|
||||
ptep = pte_offset_kernel(&pmd, addr);
|
||||
do {
|
||||
pte_t pte = *ptep;
|
||||
struct page *page;
|
||||
|
||||
if ((pte_val(pte) & mask) != result)
|
||||
return 0;
|
||||
VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
|
||||
page = pte_page(pte);
|
||||
if (!page_cache_get_speculative(page))
|
||||
return 0;
|
||||
if (unlikely(pte != *ptep)) {
|
||||
put_page(page);
|
||||
return 0;
|
||||
}
|
||||
pages[*nr] = page;
|
||||
(*nr)++;
|
||||
|
||||
} while (ptep++, addr += PAGE_SIZE, addr != end);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HUGETLB_PAGE
|
||||
static noinline int gup_huge_pte(pte_t *ptep, struct hstate *hstate,
|
||||
unsigned long *addr, unsigned long end,
|
||||
int write, struct page **pages, int *nr)
|
||||
{
|
||||
unsigned long mask;
|
||||
unsigned long pte_end;
|
||||
struct page *head, *page;
|
||||
pte_t pte;
|
||||
int refs;
|
||||
|
||||
pte_end = (*addr + huge_page_size(hstate)) & huge_page_mask(hstate);
|
||||
if (pte_end < end)
|
||||
end = pte_end;
|
||||
|
||||
pte = *ptep;
|
||||
mask = _PAGE_PRESENT|_PAGE_USER;
|
||||
if (write)
|
||||
mask |= _PAGE_RW;
|
||||
if ((pte_val(pte) & mask) != mask)
|
||||
return 0;
|
||||
/* hugepages are never "special" */
|
||||
VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
|
||||
|
||||
refs = 0;
|
||||
head = pte_page(pte);
|
||||
page = head + ((*addr & ~huge_page_mask(hstate)) >> PAGE_SHIFT);
|
||||
do {
|
||||
VM_BUG_ON(compound_head(page) != head);
|
||||
pages[*nr] = page;
|
||||
(*nr)++;
|
||||
page++;
|
||||
refs++;
|
||||
} while (*addr += PAGE_SIZE, *addr != end);
|
||||
|
||||
if (!page_cache_add_speculative(head, refs)) {
|
||||
*nr -= refs;
|
||||
return 0;
|
||||
}
|
||||
if (unlikely(pte != *ptep)) {
|
||||
/* Could be optimized better */
|
||||
while (*nr) {
|
||||
put_page(page);
|
||||
(*nr)--;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* CONFIG_HUGETLB_PAGE */
|
||||
|
||||
static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
|
||||
int write, struct page **pages, int *nr)
|
||||
{
|
||||
unsigned long next;
|
||||
pmd_t *pmdp;
|
||||
|
||||
pmdp = pmd_offset(&pud, addr);
|
||||
do {
|
||||
pmd_t pmd = *pmdp;
|
||||
|
||||
next = pmd_addr_end(addr, end);
|
||||
if (pmd_none(pmd))
|
||||
return 0;
|
||||
if (!gup_pte_range(pmd, addr, next, write, pages, nr))
|
||||
return 0;
|
||||
} while (pmdp++, addr = next, addr != end);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end,
|
||||
int write, struct page **pages, int *nr)
|
||||
{
|
||||
unsigned long next;
|
||||
pud_t *pudp;
|
||||
|
||||
pudp = pud_offset(&pgd, addr);
|
||||
do {
|
||||
pud_t pud = *pudp;
|
||||
|
||||
next = pud_addr_end(addr, end);
|
||||
if (pud_none(pud))
|
||||
return 0;
|
||||
if (!gup_pmd_range(pud, addr, next, write, pages, nr))
|
||||
return 0;
|
||||
} while (pudp++, addr = next, addr != end);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int get_user_pages_fast(unsigned long start, int nr_pages, int write,
|
||||
struct page **pages)
|
||||
{
|
||||
struct mm_struct *mm = current->mm;
|
||||
unsigned long addr, len, end;
|
||||
unsigned long next;
|
||||
pgd_t *pgdp;
|
||||
int psize, nr = 0;
|
||||
unsigned int shift;
|
||||
|
||||
pr_debug("%s(%lx,%x,%s)\n", __func__, start, nr_pages, write ? "write" : "read");
|
||||
|
||||
start &= PAGE_MASK;
|
||||
addr = start;
|
||||
len = (unsigned long) nr_pages << PAGE_SHIFT;
|
||||
end = start + len;
|
||||
|
||||
if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ,
|
||||
start, len)))
|
||||
goto slow_irqon;
|
||||
|
||||
pr_debug(" aligned: %lx .. %lx\n", start, end);
|
||||
|
||||
#ifdef CONFIG_HUGETLB_PAGE
|
||||
/* We bail out on slice boundary crossing when hugetlb is
|
||||
* enabled in order to not have to deal with two different
|
||||
* page table formats
|
||||
*/
|
||||
if (addr < SLICE_LOW_TOP) {
|
||||
if (end > SLICE_LOW_TOP)
|
||||
goto slow_irqon;
|
||||
|
||||
if (unlikely(GET_LOW_SLICE_INDEX(addr) !=
|
||||
GET_LOW_SLICE_INDEX(end - 1)))
|
||||
goto slow_irqon;
|
||||
} else {
|
||||
if (unlikely(GET_HIGH_SLICE_INDEX(addr) !=
|
||||
GET_HIGH_SLICE_INDEX(end - 1)))
|
||||
goto slow_irqon;
|
||||
}
|
||||
#endif /* CONFIG_HUGETLB_PAGE */
|
||||
|
||||
/*
|
||||
* XXX: batch / limit 'nr', to avoid large irq off latency
|
||||
* needs some instrumenting to determine the common sizes used by
|
||||
* important workloads (eg. DB2), and whether limiting the batch size
|
||||
* will decrease performance.
|
||||
*
|
||||
* It seems like we're in the clear for the moment. Direct-IO is
|
||||
* the main guy that batches up lots of get_user_pages, and even
|
||||
* they are limited to 64-at-a-time which is not so many.
|
||||
*/
|
||||
/*
|
||||
* This doesn't prevent pagetable teardown, but does prevent
|
||||
* the pagetables from being freed on powerpc.
|
||||
*
|
||||
* So long as we atomically load page table pointers versus teardown,
|
||||
* we can follow the address down to the the page and take a ref on it.
|
||||
*/
|
||||
local_irq_disable();
|
||||
|
||||
psize = get_slice_psize(mm, addr);
|
||||
shift = mmu_psize_defs[psize].shift;
|
||||
|
||||
#ifdef CONFIG_HUGETLB_PAGE
|
||||
if (unlikely(mmu_huge_psizes[psize])) {
|
||||
pte_t *ptep;
|
||||
unsigned long a = addr;
|
||||
unsigned long sz = ((1UL) << shift);
|
||||
struct hstate *hstate = size_to_hstate(sz);
|
||||
|
||||
BUG_ON(!hstate);
|
||||
/*
|
||||
* XXX: could be optimized to avoid hstate
|
||||
* lookup entirely (just use shift)
|
||||
*/
|
||||
|
||||
do {
|
||||
VM_BUG_ON(shift != mmu_psize_defs[get_slice_psize(mm, a)].shift);
|
||||
ptep = huge_pte_offset(mm, a);
|
||||
pr_debug(" %016lx: huge ptep %p\n", a, ptep);
|
||||
if (!ptep || !gup_huge_pte(ptep, hstate, &a, end, write, pages,
|
||||
&nr))
|
||||
goto slow;
|
||||
} while (a != end);
|
||||
} else
|
||||
#endif /* CONFIG_HUGETLB_PAGE */
|
||||
{
|
||||
pgdp = pgd_offset(mm, addr);
|
||||
do {
|
||||
pgd_t pgd = *pgdp;
|
||||
|
||||
VM_BUG_ON(shift != mmu_psize_defs[get_slice_psize(mm, addr)].shift);
|
||||
pr_debug(" %016lx: normal pgd %p\n", addr, (void *)pgd);
|
||||
next = pgd_addr_end(addr, end);
|
||||
if (pgd_none(pgd))
|
||||
goto slow;
|
||||
if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
|
||||
goto slow;
|
||||
} while (pgdp++, addr = next, addr != end);
|
||||
}
|
||||
local_irq_enable();
|
||||
|
||||
VM_BUG_ON(nr != (end - start) >> PAGE_SHIFT);
|
||||
return nr;
|
||||
|
||||
{
|
||||
int ret;
|
||||
|
||||
slow:
|
||||
local_irq_enable();
|
||||
slow_irqon:
|
||||
pr_debug(" slow path ! nr = %d\n", nr);
|
||||
|
||||
/* Try to get the remaining pages with get_user_pages */
|
||||
start += nr << PAGE_SHIFT;
|
||||
pages += nr;
|
||||
|
||||
down_read(&mm->mmap_sem);
|
||||
ret = get_user_pages(current, mm, start,
|
||||
(end - start) >> PAGE_SHIFT, write, 0, pages, NULL);
|
||||
up_read(&mm->mmap_sem);
|
||||
|
||||
/* Have to be a bit careful with return values */
|
||||
if (nr > 0) {
|
||||
if (ret < 0)
|
||||
ret = nr;
|
||||
else
|
||||
ret += nr;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
@ -105,6 +105,7 @@ static void __init mpc832x_sys_setup_arch(void)
|
||||
static struct of_device_id mpc832x_ids[] = {
|
||||
{ .type = "soc", },
|
||||
{ .compatible = "soc", },
|
||||
{ .compatible = "simple-bus", },
|
||||
{ .type = "qe", },
|
||||
{ .compatible = "fsl,qe", },
|
||||
{},
|
||||
|
@ -115,6 +115,7 @@ static void __init mpc832x_rdb_setup_arch(void)
|
||||
static struct of_device_id mpc832x_ids[] = {
|
||||
{ .type = "soc", },
|
||||
{ .compatible = "soc", },
|
||||
{ .compatible = "simple-bus", },
|
||||
{ .type = "qe", },
|
||||
{ .compatible = "fsl,qe", },
|
||||
{},
|
||||
|
@ -41,6 +41,7 @@
|
||||
|
||||
static struct of_device_id __initdata mpc834x_itx_ids[] = {
|
||||
{ .compatible = "fsl,pq2pro-localbus", },
|
||||
{ .compatible = "simple-bus", },
|
||||
{},
|
||||
};
|
||||
|
||||
|
@ -111,6 +111,7 @@ static void __init mpc834x_mds_init_IRQ(void)
|
||||
static struct of_device_id mpc834x_ids[] = {
|
||||
{ .type = "soc", },
|
||||
{ .compatible = "soc", },
|
||||
{ .compatible = "simple-bus", },
|
||||
{},
|
||||
};
|
||||
|
||||
|
@ -136,6 +136,7 @@ static void __init mpc836x_mds_setup_arch(void)
|
||||
static struct of_device_id mpc836x_ids[] = {
|
||||
{ .type = "soc", },
|
||||
{ .compatible = "soc", },
|
||||
{ .compatible = "simple-bus", },
|
||||
{ .type = "qe", },
|
||||
{ .compatible = "fsl,qe", },
|
||||
{},
|
||||
|
@ -83,6 +83,7 @@ static void __init sbc834x_init_IRQ(void)
|
||||
static struct __initdata of_device_id sbc834x_ids[] = {
|
||||
{ .type = "soc", },
|
||||
{ .compatible = "soc", },
|
||||
{ .compatible = "simple-bus", },
|
||||
{},
|
||||
};
|
||||
|
||||
|
@ -222,6 +222,7 @@ static void ksi8560_show_cpuinfo(struct seq_file *m)
|
||||
|
||||
static struct of_device_id __initdata of_bus_ids[] = {
|
||||
{ .type = "soc", },
|
||||
{ .type = "simple-bus", },
|
||||
{ .name = "cpm", },
|
||||
{ .name = "localbus", },
|
||||
{},
|
||||
|
@ -91,6 +91,7 @@ static void __init mpc8536_ds_setup_arch(void)
|
||||
static struct of_device_id __initdata mpc8536_ds_ids[] = {
|
||||
{ .type = "soc", },
|
||||
{ .compatible = "soc", },
|
||||
{ .compatible = "simple-bus", },
|
||||
{},
|
||||
};
|
||||
|
||||
|
@ -230,6 +230,7 @@ static struct of_device_id __initdata of_bus_ids[] = {
|
||||
{ .type = "soc", },
|
||||
{ .name = "cpm", },
|
||||
{ .name = "localbus", },
|
||||
{ .compatible = "simple-bus", },
|
||||
{},
|
||||
};
|
||||
|
||||
|
@ -186,6 +186,7 @@ static int __init mpc8544_ds_probe(void)
|
||||
static struct of_device_id __initdata mpc85xxds_ids[] = {
|
||||
{ .type = "soc", },
|
||||
{ .compatible = "soc", },
|
||||
{ .compatible = "simple-bus", },
|
||||
{},
|
||||
};
|
||||
|
||||
|
@ -260,6 +260,7 @@ machine_arch_initcall(mpc85xx_mds, board_fixups);
|
||||
static struct of_device_id mpc85xx_ids[] = {
|
||||
{ .type = "soc", },
|
||||
{ .compatible = "soc", },
|
||||
{ .compatible = "simple-bus", },
|
||||
{ .type = "qe", },
|
||||
{ .compatible = "fsl,qe", },
|
||||
{},
|
||||
|
@ -217,6 +217,7 @@ static struct of_device_id __initdata of_bus_ids[] = {
|
||||
{ .type = "soc", },
|
||||
{ .name = "cpm", },
|
||||
{ .name = "localbus", },
|
||||
{ .compatible = "simple-bus", },
|
||||
{},
|
||||
};
|
||||
|
||||
|
@ -105,6 +105,16 @@ config 8xx_COPYBACK
|
||||
|
||||
If in doubt, say Y here.
|
||||
|
||||
config 8xx_GPIO
|
||||
bool "GPIO API Support"
|
||||
select GENERIC_GPIO
|
||||
select ARCH_REQUIRE_GPIOLIB
|
||||
help
|
||||
Saying Y here will cause the ports on an MPC8xx processor to be used
|
||||
with the GPIO API. If you say N here, the kernel needs less memory.
|
||||
|
||||
If in doubt, say Y here.
|
||||
|
||||
config 8xx_CPU6
|
||||
bool "CPU6 Silicon Errata (860 Pre Rev. C)"
|
||||
help
|
||||
|
@ -254,6 +254,8 @@ config CPM2
|
||||
select CPM
|
||||
select PPC_LIB_RHEAP
|
||||
select PPC_PCI_CHOICE
|
||||
select ARCH_REQUIRE_GPIOLIB
|
||||
select GENERIC_GPIO
|
||||
help
|
||||
The CPM2 (Communications Processor Module) is a coprocessor on
|
||||
embedded CPUs made by Freescale. Selecting this option means that
|
||||
@ -281,6 +283,7 @@ config FSL_ULI1575
|
||||
|
||||
config CPM
|
||||
bool
|
||||
select PPC_CLOCK
|
||||
|
||||
config OF_RTC
|
||||
bool
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/8xx_immap.h>
|
||||
@ -42,6 +43,10 @@
|
||||
|
||||
#include <asm/fs_pd.h>
|
||||
|
||||
#ifdef CONFIG_8xx_GPIO
|
||||
#include <linux/of_gpio.h>
|
||||
#endif
|
||||
|
||||
#define CPM_MAP_SIZE (0x4000)
|
||||
|
||||
cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */
|
||||
@ -290,20 +295,24 @@ struct cpm_ioport16 {
|
||||
__be16 res[3];
|
||||
};
|
||||
|
||||
struct cpm_ioport32 {
|
||||
__be32 dir, par, sor;
|
||||
struct cpm_ioport32b {
|
||||
__be32 dir, par, odr, dat;
|
||||
};
|
||||
|
||||
struct cpm_ioport32e {
|
||||
__be32 dir, par, sor, odr, dat;
|
||||
};
|
||||
|
||||
static void cpm1_set_pin32(int port, int pin, int flags)
|
||||
{
|
||||
struct cpm_ioport32 __iomem *iop;
|
||||
struct cpm_ioport32e __iomem *iop;
|
||||
pin = 1 << (31 - pin);
|
||||
|
||||
if (port == CPM_PORTB)
|
||||
iop = (struct cpm_ioport32 __iomem *)
|
||||
iop = (struct cpm_ioport32e __iomem *)
|
||||
&mpc8xx_immr->im_cpm.cp_pbdir;
|
||||
else
|
||||
iop = (struct cpm_ioport32 __iomem *)
|
||||
iop = (struct cpm_ioport32e __iomem *)
|
||||
&mpc8xx_immr->im_cpm.cp_pedir;
|
||||
|
||||
if (flags & CPM_PIN_OUTPUT)
|
||||
@ -498,3 +507,251 @@ int cpm1_clk_setup(enum cpm_clk_target target, int clock, int mode)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* GPIO LIB API implementation
|
||||
*/
|
||||
#ifdef CONFIG_8xx_GPIO
|
||||
|
||||
struct cpm1_gpio16_chip {
|
||||
struct of_mm_gpio_chip mm_gc;
|
||||
spinlock_t lock;
|
||||
|
||||
/* shadowed data register to clear/set bits safely */
|
||||
u16 cpdata;
|
||||
};
|
||||
|
||||
static inline struct cpm1_gpio16_chip *
|
||||
to_cpm1_gpio16_chip(struct of_mm_gpio_chip *mm_gc)
|
||||
{
|
||||
return container_of(mm_gc, struct cpm1_gpio16_chip, mm_gc);
|
||||
}
|
||||
|
||||
static void cpm1_gpio16_save_regs(struct of_mm_gpio_chip *mm_gc)
|
||||
{
|
||||
struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
|
||||
struct cpm_ioport16 __iomem *iop = mm_gc->regs;
|
||||
|
||||
cpm1_gc->cpdata = in_be16(&iop->dat);
|
||||
}
|
||||
|
||||
static int cpm1_gpio16_get(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
||||
struct cpm_ioport16 __iomem *iop = mm_gc->regs;
|
||||
u16 pin_mask;
|
||||
|
||||
pin_mask = 1 << (15 - gpio);
|
||||
|
||||
return !!(in_be16(&iop->dat) & pin_mask);
|
||||
}
|
||||
|
||||
static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value)
|
||||
{
|
||||
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
||||
struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
|
||||
struct cpm_ioport16 __iomem *iop = mm_gc->regs;
|
||||
unsigned long flags;
|
||||
u16 pin_mask = 1 << (15 - gpio);
|
||||
|
||||
spin_lock_irqsave(&cpm1_gc->lock, flags);
|
||||
|
||||
if (value)
|
||||
cpm1_gc->cpdata |= pin_mask;
|
||||
else
|
||||
cpm1_gc->cpdata &= ~pin_mask;
|
||||
|
||||
out_be16(&iop->dat, cpm1_gc->cpdata);
|
||||
|
||||
spin_unlock_irqrestore(&cpm1_gc->lock, flags);
|
||||
}
|
||||
|
||||
static int cpm1_gpio16_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
{
|
||||
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
||||
struct cpm_ioport16 __iomem *iop = mm_gc->regs;
|
||||
u16 pin_mask;
|
||||
|
||||
pin_mask = 1 << (15 - gpio);
|
||||
|
||||
setbits16(&iop->dir, pin_mask);
|
||||
|
||||
cpm1_gpio16_set(gc, gpio, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cpm1_gpio16_dir_in(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
||||
struct cpm_ioport16 __iomem *iop = mm_gc->regs;
|
||||
u16 pin_mask;
|
||||
|
||||
pin_mask = 1 << (15 - gpio);
|
||||
|
||||
clrbits16(&iop->dir, pin_mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpm1_gpiochip_add16(struct device_node *np)
|
||||
{
|
||||
struct cpm1_gpio16_chip *cpm1_gc;
|
||||
struct of_mm_gpio_chip *mm_gc;
|
||||
struct of_gpio_chip *of_gc;
|
||||
struct gpio_chip *gc;
|
||||
|
||||
cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL);
|
||||
if (!cpm1_gc)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&cpm1_gc->lock);
|
||||
|
||||
mm_gc = &cpm1_gc->mm_gc;
|
||||
of_gc = &mm_gc->of_gc;
|
||||
gc = &of_gc->gc;
|
||||
|
||||
mm_gc->save_regs = cpm1_gpio16_save_regs;
|
||||
of_gc->gpio_cells = 2;
|
||||
gc->ngpio = 16;
|
||||
gc->direction_input = cpm1_gpio16_dir_in;
|
||||
gc->direction_output = cpm1_gpio16_dir_out;
|
||||
gc->get = cpm1_gpio16_get;
|
||||
gc->set = cpm1_gpio16_set;
|
||||
|
||||
return of_mm_gpiochip_add(np, mm_gc);
|
||||
}
|
||||
|
||||
struct cpm1_gpio32_chip {
|
||||
struct of_mm_gpio_chip mm_gc;
|
||||
spinlock_t lock;
|
||||
|
||||
/* shadowed data register to clear/set bits safely */
|
||||
u32 cpdata;
|
||||
};
|
||||
|
||||
static inline struct cpm1_gpio32_chip *
|
||||
to_cpm1_gpio32_chip(struct of_mm_gpio_chip *mm_gc)
|
||||
{
|
||||
return container_of(mm_gc, struct cpm1_gpio32_chip, mm_gc);
|
||||
}
|
||||
|
||||
static void cpm1_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc)
|
||||
{
|
||||
struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
|
||||
struct cpm_ioport32b __iomem *iop = mm_gc->regs;
|
||||
|
||||
cpm1_gc->cpdata = in_be32(&iop->dat);
|
||||
}
|
||||
|
||||
static int cpm1_gpio32_get(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
||||
struct cpm_ioport32b __iomem *iop = mm_gc->regs;
|
||||
u32 pin_mask;
|
||||
|
||||
pin_mask = 1 << (31 - gpio);
|
||||
|
||||
return !!(in_be32(&iop->dat) & pin_mask);
|
||||
}
|
||||
|
||||
static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
|
||||
{
|
||||
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
||||
struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
|
||||
struct cpm_ioport32b __iomem *iop = mm_gc->regs;
|
||||
unsigned long flags;
|
||||
u32 pin_mask = 1 << (31 - gpio);
|
||||
|
||||
spin_lock_irqsave(&cpm1_gc->lock, flags);
|
||||
|
||||
if (value)
|
||||
cpm1_gc->cpdata |= pin_mask;
|
||||
else
|
||||
cpm1_gc->cpdata &= ~pin_mask;
|
||||
|
||||
out_be32(&iop->dat, cpm1_gc->cpdata);
|
||||
|
||||
spin_unlock_irqrestore(&cpm1_gc->lock, flags);
|
||||
}
|
||||
|
||||
static int cpm1_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
{
|
||||
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
||||
struct cpm_ioport32b __iomem *iop = mm_gc->regs;
|
||||
u32 pin_mask;
|
||||
|
||||
pin_mask = 1 << (31 - gpio);
|
||||
|
||||
setbits32(&iop->dir, pin_mask);
|
||||
|
||||
cpm1_gpio32_set(gc, gpio, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cpm1_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
||||
struct cpm_ioport32b __iomem *iop = mm_gc->regs;
|
||||
u32 pin_mask;
|
||||
|
||||
pin_mask = 1 << (31 - gpio);
|
||||
|
||||
clrbits32(&iop->dir, pin_mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpm1_gpiochip_add32(struct device_node *np)
|
||||
{
|
||||
struct cpm1_gpio32_chip *cpm1_gc;
|
||||
struct of_mm_gpio_chip *mm_gc;
|
||||
struct of_gpio_chip *of_gc;
|
||||
struct gpio_chip *gc;
|
||||
|
||||
cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL);
|
||||
if (!cpm1_gc)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&cpm1_gc->lock);
|
||||
|
||||
mm_gc = &cpm1_gc->mm_gc;
|
||||
of_gc = &mm_gc->of_gc;
|
||||
gc = &of_gc->gc;
|
||||
|
||||
mm_gc->save_regs = cpm1_gpio32_save_regs;
|
||||
of_gc->gpio_cells = 2;
|
||||
gc->ngpio = 32;
|
||||
gc->direction_input = cpm1_gpio32_dir_in;
|
||||
gc->direction_output = cpm1_gpio32_dir_out;
|
||||
gc->get = cpm1_gpio32_get;
|
||||
gc->set = cpm1_gpio32_set;
|
||||
|
||||
return of_mm_gpiochip_add(np, mm_gc);
|
||||
}
|
||||
|
||||
static int cpm_init_par_io(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
|
||||
for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-a")
|
||||
cpm1_gpiochip_add16(np);
|
||||
|
||||
for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-b")
|
||||
cpm1_gpiochip_add32(np);
|
||||
|
||||
for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-c")
|
||||
cpm1_gpiochip_add16(np);
|
||||
|
||||
for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-d")
|
||||
cpm1_gpiochip_add16(np);
|
||||
|
||||
/* Port E uses CPM2 layout */
|
||||
for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-e")
|
||||
cpm2_gpiochip_add32(np);
|
||||
return 0;
|
||||
}
|
||||
arch_initcall(cpm_init_par_io);
|
||||
|
||||
#endif /* CONFIG_8xx_GPIO */
|
||||
|
@ -115,16 +115,10 @@ EXPORT_SYMBOL(cpm_command);
|
||||
* Baud rate clocks are zero-based in the driver code (as that maps
|
||||
* to port numbers). Documentation uses 1-based numbering.
|
||||
*/
|
||||
#define BRG_INT_CLK (get_brgfreq())
|
||||
#define BRG_UART_CLK (BRG_INT_CLK/16)
|
||||
|
||||
/* This function is used by UARTS, or anything else that uses a 16x
|
||||
* oversampled clock.
|
||||
*/
|
||||
void
|
||||
cpm_setbrg(uint brg, uint rate)
|
||||
void __cpm2_setbrg(uint brg, uint rate, uint clk, int div16, int src)
|
||||
{
|
||||
u32 __iomem *bp;
|
||||
u32 val;
|
||||
|
||||
/* This is good enough to get SMCs running.....
|
||||
*/
|
||||
@ -135,34 +129,14 @@ cpm_setbrg(uint brg, uint rate)
|
||||
brg -= 4;
|
||||
}
|
||||
bp += brg;
|
||||
out_be32(bp, (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN);
|
||||
|
||||
cpm2_unmap(bp);
|
||||
}
|
||||
|
||||
/* This function is used to set high speed synchronous baud rate
|
||||
* clocks.
|
||||
*/
|
||||
void
|
||||
cpm2_fastbrg(uint brg, uint rate, int div16)
|
||||
{
|
||||
u32 __iomem *bp;
|
||||
u32 val;
|
||||
|
||||
if (brg < 4) {
|
||||
bp = cpm2_map_size(im_brgc1, 16);
|
||||
} else {
|
||||
bp = cpm2_map_size(im_brgc5, 16);
|
||||
brg -= 4;
|
||||
}
|
||||
bp += brg;
|
||||
val = ((BRG_INT_CLK / rate) << 1) | CPM_BRG_EN;
|
||||
val = (((clk / rate) - 1) << 1) | CPM_BRG_EN | src;
|
||||
if (div16)
|
||||
val |= CPM_BRG_DIV16;
|
||||
|
||||
out_be32(bp, val);
|
||||
cpm2_unmap(bp);
|
||||
}
|
||||
EXPORT_SYMBOL(__cpm2_setbrg);
|
||||
|
||||
int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode)
|
||||
{
|
||||
@ -377,3 +351,14 @@ void cpm2_set_pin(int port, int pin, int flags)
|
||||
else
|
||||
clrbits32(&iop[port].odr, pin);
|
||||
}
|
||||
|
||||
static int cpm_init_par_io(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
|
||||
for_each_compatible_node(np, NULL, "fsl,cpm2-pario-bank")
|
||||
cpm2_gpiochip_add32(np);
|
||||
return 0;
|
||||
}
|
||||
arch_initcall(cpm_init_par_io);
|
||||
|
||||
|
@ -19,6 +19,8 @@
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <asm/udbg.h>
|
||||
#include <asm/io.h>
|
||||
@ -28,6 +30,10 @@
|
||||
|
||||
#include <mm/mmu_decl.h>
|
||||
|
||||
#if defined(CONFIG_CPM2) || defined(CONFIG_8xx_GPIO)
|
||||
#include <linux/of_gpio.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PPC_EARLY_DEBUG_CPM
|
||||
static u32 __iomem *cpm_udbg_txdesc =
|
||||
(u32 __iomem __force *)CONFIG_PPC_EARLY_DEBUG_CPM_ADDR;
|
||||
@ -207,3 +213,120 @@ dma_addr_t cpm_muram_dma(void __iomem *addr)
|
||||
return muram_pbase + ((u8 __iomem *)addr - muram_vbase);
|
||||
}
|
||||
EXPORT_SYMBOL(cpm_muram_dma);
|
||||
|
||||
#if defined(CONFIG_CPM2) || defined(CONFIG_8xx_GPIO)
|
||||
|
||||
struct cpm2_ioports {
|
||||
u32 dir, par, sor, odr, dat;
|
||||
u32 res[3];
|
||||
};
|
||||
|
||||
struct cpm2_gpio32_chip {
|
||||
struct of_mm_gpio_chip mm_gc;
|
||||
spinlock_t lock;
|
||||
|
||||
/* shadowed data register to clear/set bits safely */
|
||||
u32 cpdata;
|
||||
};
|
||||
|
||||
static inline struct cpm2_gpio32_chip *
|
||||
to_cpm2_gpio32_chip(struct of_mm_gpio_chip *mm_gc)
|
||||
{
|
||||
return container_of(mm_gc, struct cpm2_gpio32_chip, mm_gc);
|
||||
}
|
||||
|
||||
static void cpm2_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc)
|
||||
{
|
||||
struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc);
|
||||
struct cpm2_ioports __iomem *iop = mm_gc->regs;
|
||||
|
||||
cpm2_gc->cpdata = in_be32(&iop->dat);
|
||||
}
|
||||
|
||||
static int cpm2_gpio32_get(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
||||
struct cpm2_ioports __iomem *iop = mm_gc->regs;
|
||||
u32 pin_mask;
|
||||
|
||||
pin_mask = 1 << (31 - gpio);
|
||||
|
||||
return !!(in_be32(&iop->dat) & pin_mask);
|
||||
}
|
||||
|
||||
static void cpm2_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
|
||||
{
|
||||
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
||||
struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc);
|
||||
struct cpm2_ioports __iomem *iop = mm_gc->regs;
|
||||
unsigned long flags;
|
||||
u32 pin_mask = 1 << (31 - gpio);
|
||||
|
||||
spin_lock_irqsave(&cpm2_gc->lock, flags);
|
||||
|
||||
if (value)
|
||||
cpm2_gc->cpdata |= pin_mask;
|
||||
else
|
||||
cpm2_gc->cpdata &= ~pin_mask;
|
||||
|
||||
out_be32(&iop->dat, cpm2_gc->cpdata);
|
||||
|
||||
spin_unlock_irqrestore(&cpm2_gc->lock, flags);
|
||||
}
|
||||
|
||||
static int cpm2_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
{
|
||||
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
||||
struct cpm2_ioports __iomem *iop = mm_gc->regs;
|
||||
u32 pin_mask;
|
||||
|
||||
pin_mask = 1 << (31 - gpio);
|
||||
|
||||
setbits32(&iop->dir, pin_mask);
|
||||
|
||||
cpm2_gpio32_set(gc, gpio, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cpm2_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
||||
struct cpm2_ioports __iomem *iop = mm_gc->regs;
|
||||
u32 pin_mask;
|
||||
|
||||
pin_mask = 1 << (31 - gpio);
|
||||
|
||||
clrbits32(&iop->dir, pin_mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpm2_gpiochip_add32(struct device_node *np)
|
||||
{
|
||||
struct cpm2_gpio32_chip *cpm2_gc;
|
||||
struct of_mm_gpio_chip *mm_gc;
|
||||
struct of_gpio_chip *of_gc;
|
||||
struct gpio_chip *gc;
|
||||
|
||||
cpm2_gc = kzalloc(sizeof(*cpm2_gc), GFP_KERNEL);
|
||||
if (!cpm2_gc)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&cpm2_gc->lock);
|
||||
|
||||
mm_gc = &cpm2_gc->mm_gc;
|
||||
of_gc = &mm_gc->of_gc;
|
||||
gc = &of_gc->gc;
|
||||
|
||||
mm_gc->save_regs = cpm2_gpio32_save_regs;
|
||||
of_gc->gpio_cells = 2;
|
||||
gc->ngpio = 32;
|
||||
gc->direction_input = cpm2_gpio32_dir_in;
|
||||
gc->direction_output = cpm2_gpio32_dir_out;
|
||||
gc->get = cpm2_gpio32_get;
|
||||
gc->set = cpm2_gpio32_set;
|
||||
|
||||
return of_mm_gpiochip_add(np, mm_gc);
|
||||
}
|
||||
#endif /* CONFIG_CPM2 || CONFIG_8xx_GPIO */
|
||||
|
@ -21,6 +21,7 @@ static int __init add_rtc(void)
|
||||
struct device_node *np;
|
||||
struct platform_device *pd;
|
||||
struct resource res[2];
|
||||
unsigned int num_res = 1;
|
||||
int ret;
|
||||
|
||||
memset(&res, 0, sizeof(res));
|
||||
@ -41,14 +42,24 @@ static int __init add_rtc(void)
|
||||
if (res[0].start != RTC_PORT(0))
|
||||
return -EINVAL;
|
||||
|
||||
/* Use a fixed interrupt value of 8 since on PPC if we are using this
|
||||
* its off an i8259 which we ensure has interrupt numbers 0..15. */
|
||||
res[1].start = 8;
|
||||
res[1].end = 8;
|
||||
res[1].flags = IORESOURCE_IRQ;
|
||||
np = of_find_compatible_node(NULL, NULL, "chrp,iic");
|
||||
if (!np)
|
||||
np = of_find_compatible_node(NULL, NULL, "pnpPNP,000");
|
||||
if (np) {
|
||||
of_node_put(np);
|
||||
/*
|
||||
* Use a fixed interrupt value of 8 since on PPC if we are
|
||||
* using this its off an i8259 which we ensure has interrupt
|
||||
* numbers 0..15.
|
||||
*/
|
||||
res[1].start = 8;
|
||||
res[1].end = 8;
|
||||
res[1].flags = IORESOURCE_IRQ;
|
||||
num_res++;
|
||||
}
|
||||
|
||||
pd = platform_device_register_simple("rtc_cmos", -1,
|
||||
&res[0], 2);
|
||||
&res[0], num_res);
|
||||
|
||||
if (IS_ERR(pd))
|
||||
return PTR_ERR(pd);
|
||||
|
@ -66,8 +66,8 @@
|
||||
#include <linux/ctype.h>
|
||||
|
||||
#ifdef CONFIG_PPC_OF
|
||||
#include <asm/of_device.h>
|
||||
#include <asm/of_platform.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_platform.h>
|
||||
#endif
|
||||
|
||||
#define PFX "ipmi_si: "
|
||||
|
@ -1086,6 +1086,11 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, hw_regs_t *hw)
|
||||
/* Make sure we have sane timings */
|
||||
sanitize_timings(pmif);
|
||||
|
||||
host = ide_host_alloc(&d, hws);
|
||||
if (host == NULL)
|
||||
return -ENOMEM;
|
||||
hwif = host->ports[0];
|
||||
|
||||
#ifndef CONFIG_PPC64
|
||||
/* XXX FIXME: Media bay stuff need re-organizing */
|
||||
if (np->parent && np->parent->name
|
||||
@ -1119,11 +1124,11 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, hw_regs_t *hw)
|
||||
pmif->mdev ? "macio" : "PCI", pmif->aapl_bus_id,
|
||||
pmif->mediabay ? " (mediabay)" : "", hw->irq);
|
||||
|
||||
rc = ide_host_add(&d, hws, &host);
|
||||
if (rc)
|
||||
rc = ide_host_register(host, &d, hws);
|
||||
if (rc) {
|
||||
ide_host_free(host);
|
||||
return rc;
|
||||
|
||||
hwif = host->ports[0];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -50,6 +50,15 @@
|
||||
|
||||
#define SCC_WAIT_CLOSING 100
|
||||
|
||||
#define GPIO_CTS 0
|
||||
#define GPIO_RTS 1
|
||||
#define GPIO_DCD 2
|
||||
#define GPIO_DSR 3
|
||||
#define GPIO_DTR 4
|
||||
#define GPIO_RI 5
|
||||
|
||||
#define NUM_GPIOS (GPIO_RI+1)
|
||||
|
||||
struct uart_cpm_port {
|
||||
struct uart_port port;
|
||||
u16 rx_nrfifos;
|
||||
@ -68,6 +77,7 @@ struct uart_cpm_port {
|
||||
unsigned char *rx_buf;
|
||||
u32 flags;
|
||||
void (*set_lineif)(struct uart_cpm_port *);
|
||||
struct clk *clk;
|
||||
u8 brg;
|
||||
uint dp_addr;
|
||||
void *mem_addr;
|
||||
@ -82,6 +92,7 @@ struct uart_cpm_port {
|
||||
int wait_closing;
|
||||
/* value to combine with opcode to form cpm command */
|
||||
u32 command;
|
||||
int gpios[NUM_GPIOS];
|
||||
};
|
||||
|
||||
extern int cpm_uart_nr;
|
||||
|
@ -43,6 +43,9 @@
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/fs_uart_pd.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
@ -96,13 +99,41 @@ static unsigned int cpm_uart_tx_empty(struct uart_port *port)
|
||||
|
||||
static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
/* Whee. Do nothing. */
|
||||
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
|
||||
|
||||
if (pinfo->gpios[GPIO_RTS] >= 0)
|
||||
gpio_set_value(pinfo->gpios[GPIO_RTS], !(mctrl & TIOCM_RTS));
|
||||
|
||||
if (pinfo->gpios[GPIO_DTR] >= 0)
|
||||
gpio_set_value(pinfo->gpios[GPIO_DTR], !(mctrl & TIOCM_DTR));
|
||||
}
|
||||
|
||||
static unsigned int cpm_uart_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
/* Whee. Do nothing. */
|
||||
return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
|
||||
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
|
||||
unsigned int mctrl = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
|
||||
|
||||
if (pinfo->gpios[GPIO_CTS] >= 0) {
|
||||
if (gpio_get_value(pinfo->gpios[GPIO_CTS]))
|
||||
mctrl &= ~TIOCM_CTS;
|
||||
}
|
||||
|
||||
if (pinfo->gpios[GPIO_DSR] >= 0) {
|
||||
if (gpio_get_value(pinfo->gpios[GPIO_DSR]))
|
||||
mctrl &= ~TIOCM_DSR;
|
||||
}
|
||||
|
||||
if (pinfo->gpios[GPIO_DCD] >= 0) {
|
||||
if (gpio_get_value(pinfo->gpios[GPIO_DCD]))
|
||||
mctrl &= ~TIOCM_CAR;
|
||||
}
|
||||
|
||||
if (pinfo->gpios[GPIO_RI] >= 0) {
|
||||
if (!gpio_get_value(pinfo->gpios[GPIO_RI]))
|
||||
mctrl |= TIOCM_RNG;
|
||||
}
|
||||
|
||||
return mctrl;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -566,7 +597,10 @@ static void cpm_uart_set_termios(struct uart_port *port,
|
||||
out_be16(&sccp->scc_psmr, (sbits << 12) | scval);
|
||||
}
|
||||
|
||||
cpm_set_brg(pinfo->brg - 1, baud);
|
||||
if (pinfo->clk)
|
||||
clk_set_rate(pinfo->clk, baud);
|
||||
else
|
||||
cpm_set_brg(pinfo->brg - 1, baud);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
@ -991,14 +1025,23 @@ static int cpm_uart_init_port(struct device_node *np,
|
||||
void __iomem *mem, *pram;
|
||||
int len;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
data = of_get_property(np, "fsl,cpm-brg", &len);
|
||||
if (!data || len != 4) {
|
||||
printk(KERN_ERR "CPM UART %s has no/invalid "
|
||||
"fsl,cpm-brg property.\n", np->name);
|
||||
return -EINVAL;
|
||||
data = of_get_property(np, "clock", NULL);
|
||||
if (data) {
|
||||
struct clk *clk = clk_get(NULL, (const char*)data);
|
||||
if (!IS_ERR(clk))
|
||||
pinfo->clk = clk;
|
||||
}
|
||||
if (!pinfo->clk) {
|
||||
data = of_get_property(np, "fsl,cpm-brg", &len);
|
||||
if (!data || len != 4) {
|
||||
printk(KERN_ERR "CPM UART %s has no/invalid "
|
||||
"fsl,cpm-brg property.\n", np->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
pinfo->brg = *data;
|
||||
}
|
||||
pinfo->brg = *data;
|
||||
|
||||
data = of_get_property(np, "fsl,cpm-command", &len);
|
||||
if (!data || len != 4) {
|
||||
@ -1050,6 +1093,9 @@ static int cpm_uart_init_port(struct device_node *np,
|
||||
goto out_pram;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_GPIOS; i++)
|
||||
pinfo->gpios[i] = of_get_gpio(np, i);
|
||||
|
||||
return cpm_uart_request_port(&pinfo->port);
|
||||
|
||||
out_pram:
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
/* Opcodes common to CPM1 and CPM2
|
||||
*/
|
||||
@ -100,4 +101,6 @@ unsigned long cpm_muram_offset(void __iomem *addr);
|
||||
dma_addr_t cpm_muram_dma(void __iomem *addr);
|
||||
int cpm_command(u32 command, u8 opcode);
|
||||
|
||||
int cpm2_gpiochip_add32(struct device_node *np);
|
||||
|
||||
#endif
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include <asm/immap_cpm2.h>
|
||||
#include <asm/cpm.h>
|
||||
#include <sysdev/fsl_soc.h>
|
||||
|
||||
#ifdef CONFIG_PPC_85xx
|
||||
#define CPM_MAP_ADDR (get_immrbase() + 0x80000)
|
||||
@ -93,10 +94,40 @@ extern cpm_cpm2_t __iomem *cpmp; /* Pointer to comm processor */
|
||||
#define cpm_dpfree cpm_muram_free
|
||||
#define cpm_dpram_addr cpm_muram_addr
|
||||
|
||||
extern void cpm_setbrg(uint brg, uint rate);
|
||||
extern void cpm2_fastbrg(uint brg, uint rate, int div16);
|
||||
extern void cpm2_reset(void);
|
||||
|
||||
/* Baud rate generators.
|
||||
*/
|
||||
#define CPM_BRG_RST ((uint)0x00020000)
|
||||
#define CPM_BRG_EN ((uint)0x00010000)
|
||||
#define CPM_BRG_EXTC_INT ((uint)0x00000000)
|
||||
#define CPM_BRG_EXTC_CLK3_9 ((uint)0x00004000)
|
||||
#define CPM_BRG_EXTC_CLK5_15 ((uint)0x00008000)
|
||||
#define CPM_BRG_ATB ((uint)0x00002000)
|
||||
#define CPM_BRG_CD_MASK ((uint)0x00001ffe)
|
||||
#define CPM_BRG_DIV16 ((uint)0x00000001)
|
||||
|
||||
#define CPM2_BRG_INT_CLK (get_brgfreq())
|
||||
#define CPM2_BRG_UART_CLK (CPM2_BRG_INT_CLK/16)
|
||||
|
||||
extern void __cpm2_setbrg(uint brg, uint rate, uint clk, int div16, int src);
|
||||
|
||||
/* This function is used by UARTS, or anything else that uses a 16x
|
||||
* oversampled clock.
|
||||
*/
|
||||
static inline void cpm_setbrg(uint brg, uint rate)
|
||||
{
|
||||
__cpm2_setbrg(brg, rate, CPM2_BRG_UART_CLK, 0, CPM_BRG_EXTC_INT);
|
||||
}
|
||||
|
||||
/* This function is used to set high speed synchronous baud rate
|
||||
* clocks.
|
||||
*/
|
||||
static inline void cpm2_fastbrg(uint brg, uint rate, int div16)
|
||||
{
|
||||
__cpm2_setbrg(brg, rate, CPM2_BRG_INT_CLK, div16, CPM_BRG_EXTC_INT);
|
||||
}
|
||||
|
||||
/* Function code bits, usually generic to devices.
|
||||
*/
|
||||
#define CPMFCR_GBL ((u_char)0x20) /* Set memory snooping */
|
||||
@ -195,17 +226,6 @@ typedef struct smc_uart {
|
||||
#define SMCM_TX ((unsigned char)0x02)
|
||||
#define SMCM_RX ((unsigned char)0x01)
|
||||
|
||||
/* Baud rate generators.
|
||||
*/
|
||||
#define CPM_BRG_RST ((uint)0x00020000)
|
||||
#define CPM_BRG_EN ((uint)0x00010000)
|
||||
#define CPM_BRG_EXTC_INT ((uint)0x00000000)
|
||||
#define CPM_BRG_EXTC_CLK3_9 ((uint)0x00004000)
|
||||
#define CPM_BRG_EXTC_CLK5_15 ((uint)0x00008000)
|
||||
#define CPM_BRG_ATB ((uint)0x00002000)
|
||||
#define CPM_BRG_CD_MASK ((uint)0x00001ffe)
|
||||
#define CPM_BRG_DIV16 ((uint)0x00000001)
|
||||
|
||||
/* SCCs.
|
||||
*/
|
||||
#define SCC_GSMRH_IRP ((uint)0x00040000)
|
||||
|
@ -461,6 +461,8 @@ void pgtable_cache_init(void);
|
||||
return pt;
|
||||
}
|
||||
|
||||
pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long address);
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* _ASM_POWERPC_PGTABLE_PPC64_H_ */
|
||||
|
@ -143,6 +143,29 @@ static inline int page_cache_get_speculative(struct page *page)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Same as above, but add instead of inc (could just be merged)
|
||||
*/
|
||||
static inline int page_cache_add_speculative(struct page *page, int count)
|
||||
{
|
||||
VM_BUG_ON(in_interrupt());
|
||||
|
||||
#if !defined(CONFIG_SMP) && defined(CONFIG_CLASSIC_RCU)
|
||||
# ifdef CONFIG_PREEMPT
|
||||
VM_BUG_ON(!in_atomic());
|
||||
# endif
|
||||
VM_BUG_ON(page_count(page) == 0);
|
||||
atomic_add(count, &page->_count);
|
||||
|
||||
#else
|
||||
if (unlikely(!atomic_add_unless(&page->_count, count, 0)))
|
||||
return 0;
|
||||
#endif
|
||||
VM_BUG_ON(PageCompound(page) && page != compound_head(page));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int page_freeze_refs(struct page *page, int count)
|
||||
{
|
||||
return likely(atomic_cmpxchg(&page->_count, count, 0) == count);
|
||||
|
Loading…
Reference in New Issue
Block a user