diff options
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/Kconfig | 16 | ||||
-rw-r--r-- | arch/powerpc/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/powerpc/sysdev/Makefile | 3 | ||||
-rw-r--r-- | arch/powerpc/sysdev/dcr-low.S | 39 | ||||
-rw-r--r-- | arch/powerpc/sysdev/dcr.c | 137 |
5 files changed, 194 insertions, 2 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 96316c866107..0e564d30fc46 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -160,9 +160,11 @@ config PPC_86xx config 40x bool "AMCC 40x" + select PPC_DCR_NATIVE config 44x bool "AMCC 44x" + select PPC_DCR_NATIVE config 8xx bool "Freescale 8xx" @@ -208,6 +210,19 @@ config PPC_FPU bool default y if PPC64 +config PPC_DCR_NATIVE + bool + default n + +config PPC_DCR_MMIO + bool + default n + +config PPC_DCR + bool + depends on PPC_DCR_NATIVE || PPC_DCR_MMIO + default y + config BOOKE bool depends on E200 || E500 @@ -453,6 +468,7 @@ config PPC_CELL config PPC_CELL_NATIVE bool select PPC_CELL + select PPC_DCR_MMIO default n config PPC_IBM_CELL_BLADE diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index d8240ce22120..f34d158b9628 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -58,6 +58,7 @@ obj-$(CONFIG_BOOTX_TEXT) += btext.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_PPC_UDBG_16550) += legacy_serial.o udbg_16550.o + module-$(CONFIG_PPC64) += module_64.o obj-$(CONFIG_MODULES) += $(module-y) diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 5b87f7b42a1f..8ba11ab5e614 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -5,8 +5,7 @@ endif obj-$(CONFIG_MPIC) += mpic.o obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o obj-$(CONFIG_PPC_MPC106) += grackle.o -obj-$(CONFIG_BOOKE) += dcr.o -obj-$(CONFIG_40x) += dcr.o +obj-$(CONFIG_PPC_DCR) += dcr.o dcr-low.o obj-$(CONFIG_U3_DART) += dart_iommu.o obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o obj-$(CONFIG_FSL_SOC) += fsl_soc.o diff --git a/arch/powerpc/sysdev/dcr-low.S b/arch/powerpc/sysdev/dcr-low.S new file mode 100644 index 000000000000..2078f39e2f17 --- /dev/null +++ b/arch/powerpc/sysdev/dcr-low.S @@ -0,0 +1,39 @@ +/* + * "Indirect" DCR access + * + * Copyright (c) 2004 Eugene Surovegin <ebs@ebshome.net> + * + * 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 <asm/ppc_asm.h> +#include <asm/processor.h> + +#define DCR_ACCESS_PROLOG(table) \ + rlwinm r3,r3,4,18,27; \ + lis r5,table@h; \ + ori r5,r5,table@l; \ + add r3,r3,r5; \ + mtctr r3; \ + bctr + +_GLOBAL(__mfdcr) + DCR_ACCESS_PROLOG(__mfdcr_table) + +_GLOBAL(__mtdcr) + DCR_ACCESS_PROLOG(__mtdcr_table) + +__mfdcr_table: + mfdcr r3,0; blr +__mtdcr_table: + mtdcr 0,r4; blr + +dcr = 1 + .rept 1023 + mfdcr r3,dcr; blr + mtdcr dcr,r4; blr + dcr = dcr + 1 + .endr diff --git a/arch/powerpc/sysdev/dcr.c b/arch/powerpc/sysdev/dcr.c new file mode 100644 index 000000000000..dffeeaeca1d9 --- /dev/null +++ b/arch/powerpc/sysdev/dcr.c @@ -0,0 +1,137 @@ +/* + * (c) Copyright 2006 Benjamin Herrenschmidt, IBM Corp. + * <benh@kernel.crashing.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#undef DEBUG + +#include <linux/kernel.h> +#include <asm/prom.h> +#include <asm/dcr.h> + +unsigned int dcr_resource_start(struct device_node *np, unsigned int index) +{ + unsigned int ds; + const u32 *dr = get_property(np, "dcr-reg", &ds); + + if (dr == NULL || ds & 1 || index >= (ds / 8)) + return 0; + + return dr[index * 2]; +} + +unsigned int dcr_resource_len(struct device_node *np, unsigned int index) +{ + unsigned int ds; + const u32 *dr = get_property(np, "dcr-reg", &ds); + + if (dr == NULL || ds & 1 || index >= (ds / 8)) + return 0; + + return dr[index * 2 + 1]; +} + +#ifndef CONFIG_PPC_DCR_NATIVE + +static struct device_node * find_dcr_parent(struct device_node * node) +{ + struct device_node *par, *tmp; + const u32 *p; + + for (par = of_node_get(node); par;) { + if (get_property(par, "dcr-controller", NULL)) + break; + p = get_property(par, "dcr-parent", NULL); + tmp = par; + if (p == NULL) + par = of_get_parent(par); + else + par = of_find_node_by_phandle(*p); + of_node_put(tmp); + } + return par; +} + +u64 of_translate_dcr_address(struct device_node *dev, + unsigned int dcr_n, + unsigned int *out_stride) +{ + struct device_node *dp; + const u32 *p; + unsigned int stride; + u64 ret; + + dp = find_dcr_parent(dev); + if (dp == NULL) + return OF_BAD_ADDR; + + /* Stride is not properly defined yet, default to 0x10 for Axon */ + p = get_property(dp, "dcr-mmio-stride", NULL); + stride = (p == NULL) ? 0x10 : *p; + + /* XXX FIXME: Which property name is to use of the 2 following ? */ + p = get_property(dp, "dcr-mmio-range", NULL); + if (p == NULL) + p = get_property(dp, "dcr-mmio-space", NULL); + if (p == NULL) + return OF_BAD_ADDR; + + /* Maybe could do some better range checking here */ + ret = of_translate_address(dp, p); + if (ret != OF_BAD_ADDR) + ret += (u64)(stride) * (u64)dcr_n; + if (out_stride) + *out_stride = stride; + return ret; +} + +dcr_host_t dcr_map(struct device_node *dev, unsigned int dcr_n, + unsigned int dcr_c) +{ + dcr_host_t ret = { .token = NULL, .stride = 0 }; + u64 addr; + + pr_debug("dcr_map(%s, 0x%x, 0x%x)\n", + dev->full_name, dcr_n, dcr_c); + + addr = of_translate_dcr_address(dev, dcr_n, &ret.stride); + pr_debug("translates to addr: 0x%lx, stride: 0x%x\n", + addr, ret.stride); + if (addr == OF_BAD_ADDR) + return ret; + pr_debug("mapping 0x%x bytes\n", dcr_c * ret.stride); + ret.token = ioremap(addr, dcr_c * ret.stride); + if (ret.token == NULL) + return ret; + pr_debug("mapped at 0x%p -> base is 0x%p\n", + ret.token, ret.token - dcr_n * ret.stride); + ret.token -= dcr_n * ret.stride; + return ret; +} + +void dcr_unmap(dcr_host_t host, unsigned int dcr_n, unsigned int dcr_c) +{ + dcr_host_t h = host; + + if (h.token == NULL) + return; + h.token -= dcr_n * h.stride; + iounmap(h.token); + h.token = NULL; +} + +#endif /* !defined(CONFIG_PPC_DCR_NATIVE) */ |