* Re: [PATCH 8/25] powerpc: Improve support for 4xx indirect DCRs
From: Benjamin Herrenschmidt @ 2007-12-10 4:54 UTC (permalink / raw)
To: Josh Boyer; +Cc: linuxppc-dev
In-Reply-To: <20071206201913.498185e6@zod.rchland.ibm.com>
powerpc: Improve support for 4xx indirect DCRs
Accessing indirect DCRs is done via a pair of address/data DCRs.
Such accesses are thus inherently racy, vs. interrupts, preemption
and possibly SMP if 4xx SMP cores are ever used.
This updates the mfdcri/mtdcri macros in dcr-native.h (which were
so far unused) to use a spinlock.
In addition, add some common definitions to a new dcr-regs.h file.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
Index: linux-work/include/asm-powerpc/dcr-native.h
===================================================================
--- linux-work.orig/include/asm-powerpc/dcr-native.h 2007-12-10 15:52:26.000000000 +1100
+++ linux-work/include/asm-powerpc/dcr-native.h 2007-12-10 15:53:36.000000000 +1100
@@ -22,6 +22,8 @@
#ifdef __KERNEL__
#ifndef __ASSEMBLY__
+#include <linux/spinlock.h>
+
typedef struct {
unsigned int base;
} dcr_host_t;
@@ -55,20 +57,28 @@ do { \
} while (0)
/* R/W of indirect DCRs make use of standard naming conventions for DCRs */
-#define mfdcri(base, reg) \
-({ \
- mtdcr(base ## _CFGADDR, base ## _ ## reg); \
- mfdcr(base ## _CFGDATA); \
+extern spinlock_t dcr_ind_lock;
+
+#define mfdcri(base, reg) \
+({ \
+ unsigned long flags; \
+ unsigned int val; \
+ spin_lock_irqsave(&dcr_ind_lock, flags); \
+ mtdcr(DCRN_ ## base ## _CONFIG_ADDR, reg); \
+ val = mfdcr(DCRN_ ## base ## _CONFIG_DATA); \
+ spin_unlock_irqrestore(&dcr_ind_lock, flags); \
+ val; \
})
-#define mtdcri(base, reg, data) \
-do { \
- mtdcr(base ## _CFGADDR, base ## _ ## reg); \
- mtdcr(base ## _CFGDATA, data); \
+#define mtdcri(base, reg, data) \
+do { \
+ unsigned long flags; \
+ spin_lock_irqsave(&dcr_ind_lock, flags); \
+ mtdcr(DCRN_ ## base ## _CONFIG_ADDR, reg); \
+ mtdcr(DCRN_ ## base ## _CONFIG_DATA, data); \
+ spin_unlock_irqrestore(&dcr_ind_lock, flags); \
} while (0)
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_DCR_NATIVE_H */
-
-
Index: linux-work/include/asm-powerpc/dcr-regs.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-work/include/asm-powerpc/dcr-regs.h 2007-12-10 15:53:33.000000000 +1100
@@ -0,0 +1,71 @@
+/*
+ * Common DCR / SDR / CPR register definitions used on various IBM/AMCC
+ * 4xx processors
+ *
+ * Copyright 2007 Benjamin Herrenschmidt, IBM Corp
+ * <benh@kernel.crashing.org>
+ *
+ * Mostly lifted from asm-ppc/ibm4xx.h by
+ *
+ * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *
+ */
+
+#ifndef __DCR_REGS_H__
+#define __DCR_REGS_H__
+
+/*
+ * Most DCRs used for controlling devices such as the MAL, DMA engine,
+ * etc... are obtained for the device tree.
+ *
+ * The definitions in this files are fixed DCRs and indirect DCRs that
+ * are commonly used outside of specific drivers or refer to core
+ * common registers that may occasionally have to be tweaked outside
+ * of the driver main register set
+ */
+
+/* CPRs (440GX and 440SP/440SPe) */
+#define DCRN_CPR0_CONFIG_ADDR 0xc
+#define DCRN_CPR0_CONFIG_DATA 0xd
+
+/* SDRs (440GX and 440SP/440SPe) */
+#define DCRN_SDR0_CONFIG_ADDR 0xe
+#define DCRN_SDR0_CONFIG_DATA 0xf
+
+#define SDR0_PFC0 0x4100
+#define SDR0_PFC1 0x4101
+#define SDR0_PFC1_EPS 0x1c00000
+#define SDR0_PFC1_EPS_SHIFT 22
+#define SDR0_PFC1_RMII 0x02000000
+#define SDR0_MFR 0x4300
+#define SDR0_MFR_TAH0 0x80000000 /* TAHOE0 Enable */
+#define SDR0_MFR_TAH1 0x40000000 /* TAHOE1 Enable */
+#define SDR0_MFR_PCM 0x10000000 /* PPC440GP irq compat mode */
+#define SDR0_MFR_ECS 0x08000000 /* EMAC int clk */
+#define SDR0_MFR_T0TXFL 0x00080000
+#define SDR0_MFR_T0TXFH 0x00040000
+#define SDR0_MFR_T1TXFL 0x00020000
+#define SDR0_MFR_T1TXFH 0x00010000
+#define SDR0_MFR_E0TXFL 0x00008000
+#define SDR0_MFR_E0TXFH 0x00004000
+#define SDR0_MFR_E0RXFL 0x00002000
+#define SDR0_MFR_E0RXFH 0x00001000
+#define SDR0_MFR_E1TXFL 0x00000800
+#define SDR0_MFR_E1TXFH 0x00000400
+#define SDR0_MFR_E1RXFL 0x00000200
+#define SDR0_MFR_E1RXFH 0x00000100
+#define SDR0_MFR_E2TXFL 0x00000080
+#define SDR0_MFR_E2TXFH 0x00000040
+#define SDR0_MFR_E2RXFL 0x00000020
+#define SDR0_MFR_E2RXFH 0x00000010
+#define SDR0_MFR_E3TXFL 0x00000008
+#define SDR0_MFR_E3TXFH 0x00000004
+#define SDR0_MFR_E3RXFL 0x00000002
+#define SDR0_MFR_E3RXFH 0x00000001
+#define SDR0_UART0 0x0120
+#define SDR0_UART1 0x0121
+#define SDR0_UART2 0x0122
+#define SDR0_UART3 0x0123
+#define SDR0_CUST0 0x4000
+
+#endif /* __DCR_REGS_H__ */
^ permalink raw reply
* Re: [PATCH] Fix rounding bug in emulation for double float operating
From: David Gibson @ 2007-12-10 4:56 UTC (permalink / raw)
To: Liu Yu; +Cc: linuxppc-dev
In-Reply-To: <11972628522442-git-send-email-b13201@freescale.com>
On Mon, Dec 10, 2007 at 01:00:52PM +0800, Liu Yu wrote:
>
> This patch fixes rounding bug in emulation for double float operating on PowerPC platform.
>
> When pack double float operand, it need to truncate the tail due to the limited precision.
> If the truncated part is not zero, the last bit of work bit (totally 3 bits) need to '|' 1.
>
> This patch is completed in _FP_FRAC_SRS_2(X,N,sz) (arch/powerpc/math-emu/op-2.h).
> Originally the code leftwards rotates the operand to just keep the truncated part,
> then check whether it is zero. However, the number it rotates is not correct when
> N is not smaller than _FP_W_TYPE_SIZE, and it will cause the work bit '|' 1 in the improper case.
>
> This patch fixes this issue.
>
> Signed-off-by: Liu Yu <b13201@freescale.com>
Wow someone deciphered the hideous macro hell of the math emulation
code enough to fix a bug. I don't suppose you'd care to fix the
millions of warnings that the math-emu code generates...?
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
^ permalink raw reply
* Re: [PATCH 16/25] powerpc: EP405 boards support for arch/powerpc
From: Benjamin Herrenschmidt @ 2007-12-10 4:56 UTC (permalink / raw)
To: Josh Boyer; +Cc: linuxppc-dev
In-Reply-To: <20071206210550.520e5131@zod.rchland.ibm.com>
powerpc: EP405 boards support for arch/powerpc
Brings EP405 support to arch/powerpc. The IRQ routing for the CPLD
comes from a device-tree property, PCI is working to the point where
I can see the video card, USB device, and south bridge.
This should work with both EP405 and EP405PC.
I've not totally figured out how IRQs are wired on this hardware
though, thus at this stage, expect only USB interrupts working,
pretty much the same as what arch/ppc did.
Also, the flash, nvram, rtc and temp control still have to be wired.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
Note about IRQ routing: The doc is very obscure in that area.
I _think_ the SB interrupt on the CPLD is actually the Windond's
8259 output and the NB interrupt is the PCI_A...PCI_D mux in
there (which can be implemented as a cascaded controller) but
I haven't sorted that out yet. If anybody from Embedded Planet
is around, I could use some advice there.
If my deductions are correct, then we would need to wire up the
8259 driver to SB, which should be trivial provided I stick the
windbond bridge in the device-tree, or at least part of it,
and probably implement a cascaded controller for the PCI IRQ
A...D mux thingy, which should also be trivial.
Note also that it tends to lockup during the transition from
the boot wrapper to the kernel, before udbg is started. I didn't
have a RiscWatch at hand so I haven't yet been able to track that
down. It's random though, quite weird. Maybe some stale TLB entries
or cache content that isn't cleared properly...
Index: linux-work/arch/powerpc/boot/Makefile
===================================================================
--- linux-work.orig/arch/powerpc/boot/Makefile 2007-12-10 15:52:04.000000000 +1100
+++ linux-work/arch/powerpc/boot/Makefile 2007-12-10 15:54:23.000000000 +1100
@@ -56,7 +56,7 @@ src-plat := of.c cuboot-52xx.c cuboot-83
cuboot-ebony.c treeboot-ebony.c prpmc2800.c \
ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \
cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c cuboot-bamboo.c \
- fixed-head.S ep88xc.c cuboot-hpc2.c
+ fixed-head.S ep88xc.c cuboot-hpc2.c ep405.c
src-boot := $(src-wlib) $(src-plat) empty.c
src-boot := $(addprefix $(obj)/, $(src-boot))
@@ -150,6 +150,7 @@ image-$(CONFIG_DEFAULT_UIMAGE) += uImag
ifneq ($(CONFIG_DEVICE_TREE),"")
image-$(CONFIG_PPC_8xx) += cuImage.8xx
image-$(CONFIG_PPC_EP88XC) += zImage.ep88xc
+image-$(CONFIG_EP405) += zImage.ep405
image-$(CONFIG_8260) += cuImage.pq2
image-$(CONFIG_PPC_MPC52xx) += cuImage.52xx
image-$(CONFIG_PPC_83xx) += cuImage.83xx
Index: linux-work/arch/powerpc/boot/ep405.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-work/arch/powerpc/boot/ep405.c 2007-12-10 15:54:23.000000000 +1100
@@ -0,0 +1,74 @@
+/*
+ * Embedded Planet EP405 with PlanetCore firmware
+ *
+ * (c) Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp,\
+ *
+ * Based on ep88xc.c by
+ *
+ * Scott Wood <scottwood@freescale.com>
+ *
+ * Copyright (c) 2007 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 version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include "ops.h"
+#include "stdio.h"
+#include "planetcore.h"
+#include "dcr.h"
+#include "4xx.h"
+#include "io.h"
+
+static char *table;
+static u64 mem_size;
+
+static void platform_fixups(void)
+{
+ u64 val;
+ void *nvrtc;
+
+ dt_fixup_memory(0, mem_size);
+ planetcore_set_mac_addrs(table);
+
+ if (!planetcore_get_decimal(table, PLANETCORE_KEY_CRYSTAL_HZ, &val)) {
+ printf("No PlanetCore crystal frequency key.\r\n");
+ return;
+ }
+ ibm405gp_fixup_clocks(val, 0xa8c000);
+ ibm4xx_quiesce_eth((u32 *)0xef600800, NULL);
+ ibm4xx_fixup_ebc_ranges("/plb/ebc");
+
+ if (!planetcore_get_decimal(table, PLANETCORE_KEY_KB_NVRAM, &val)) {
+ printf("No PlanetCore NVRAM size key.\r\n");
+ return;
+ }
+ nvrtc = finddevice("/plb/ebc/nvrtc@4,200000");
+ if (nvrtc != NULL) {
+ u32 reg[3] = { 4, 0x200000, 0};
+ getprop(nvrtc, "reg", reg, 3);
+ reg[2] = (val << 10) & 0xffffffff;
+ setprop(nvrtc, "reg", reg, 3);
+ }
+}
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ table = (char *)r3;
+ planetcore_prepare_table(table);
+
+ if (!planetcore_get_decimal(table, PLANETCORE_KEY_MB_RAM, &mem_size))
+ return;
+
+ mem_size *= 1024 * 1024;
+ simple_alloc_init(_end, mem_size - (unsigned long)_end, 32, 64);
+
+ ft_init(_dtb_start, _dtb_end - _dtb_start, 32);
+
+ planetcore_set_stdout_path(table);
+
+ serial_console_init();
+ platform_ops.fixups = platform_fixups;
+}
Index: linux-work/arch/powerpc/boot/dts/ep405.dts
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-work/arch/powerpc/boot/dts/ep405.dts 2007-12-10 15:55:04.000000000 +1100
@@ -0,0 +1,221 @@
+/*
+ * Device Tree Source for EP405
+ *
+ * Copyright 2007 IBM Corp.
+ * Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without
+ * any warranty of any kind, whether express or implied.
+ */
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ model = "ep405";
+ compatible = "ep405";
+ dcr-parent = <&/cpus/PowerPC,405GP@0>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,405GP@0 {
+ device_type = "cpu";
+ reg = <0>;
+ clock-frequency = <bebc200>; /* Filled in by zImage */
+ timebase-frequency = <0>; /* Filled in by zImage */
+ i-cache-line-size = <20>;
+ d-cache-line-size = <20>;
+ i-cache-size = <4000>;
+ d-cache-size = <4000>;
+ dcr-controller;
+ dcr-access-method = "native";
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0 0>; /* Filled in by zImage */
+ };
+
+ UIC0: interrupt-controller {
+ compatible = "ibm,uic";
+ interrupt-controller;
+ cell-index = <0>;
+ dcr-reg = <0c0 9>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ };
+
+ plb {
+ compatible = "ibm,plb3";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ clock-frequency = <0>; /* Filled in by zImage */
+
+ SDRAM0: memory-controller {
+ compatible = "ibm,sdram-405gp";
+ dcr-reg = <010 2>;
+ };
+
+ MAL: mcmal {
+ compatible = "ibm,mcmal-405gp", "ibm,mcmal";
+ dcr-reg = <180 62>;
+ num-tx-chans = <1>;
+ num-rx-chans = <1>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <
+ b 4 /* TXEOB */
+ c 4 /* RXEOB */
+ a 4 /* SERR */
+ d 4 /* TXDE */
+ e 4 /* RXDE */>;
+ };
+
+ POB0: opb {
+ compatible = "ibm,opb-405gp", "ibm,opb";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <ef600000 ef600000 a00000>;
+ dcr-reg = <0a0 5>;
+ clock-frequency = <0>; /* Filled in by zImage */
+
+ UART0: serial@ef600300 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <ef600300 8>;
+ virtual-reg = <ef600300>;
+ clock-frequency = <0>; /* Filled in by zImage */
+ current-speed = <2580>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <0 4>;
+ };
+
+ UART1: serial@ef600400 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <ef600400 8>;
+ virtual-reg = <ef600400>;
+ clock-frequency = <0>; /* Filled in by zImage */
+ current-speed = <2580>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <1 4>;
+ };
+
+ IIC: i2c@ef600500 {
+ compatible = "ibm,iic-405gp", "ibm,iic";
+ reg = <ef600500 11>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <2 4>;
+ };
+
+ GPIO: gpio@ef600700 {
+ compatible = "ibm,gpio-405gp";
+ reg = <ef600700 20>;
+ };
+
+ EMAC: ethernet@ef600800 {
+ linux,network-index = <0>;
+ device_type = "network";
+ compatible = "ibm,emac-405gp", "ibm,emac";
+ interrupt-parent = <&UIC0>;
+ interrupts = <
+ f 4 /* Ethernet */
+ 9 4 /* Ethernet Wake Up */>;
+ local-mac-address = [000000000000]; /* Filled in by zImage */
+ reg = <ef600800 70>;
+ mal-device = <&MAL>;
+ mal-tx-channel = <0>;
+ mal-rx-channel = <0>;
+ cell-index = <0>;
+ max-frame-size = <5dc>;
+ rx-fifo-size = <1000>;
+ tx-fifo-size = <800>;
+ phy-mode = "rmii";
+ phy-map = <00000000>;
+ };
+
+ };
+
+ EBC0: ebc {
+ compatible = "ibm,ebc-405gp", "ibm,ebc";
+ dcr-reg = <012 2>;
+ #address-cells = <2>;
+ #size-cells = <1>;
+
+
+ /* The ranges property is supplied by the bootwrapper
+ * and is based on the firmware's configuration of the
+ * EBC bridge
+ */
+ clock-frequency = <0>; /* Filled in by zImage */
+
+ /* NVRAM and RTC */
+ nvrtc@4,200000 {
+ compatible = "ds1742";
+ reg = <4 200000 0>; /* size fixed up by zImage */
+ };
+
+ /* "BCSR" CPLD contains a PCI irq controller */
+ bcsr@4,0 {
+ compatible = "ep405-bcsr";
+ reg = <4 0 10>;
+ interrupt-controller;
+ /* Routing table */
+ irq-routing = [ 00 /* SYSERR */
+ 01 /* STTM */
+ 01 /* RTC */
+ 01 /* FENET */
+ 02 /* NB PCIIRQ mux ? */
+ 03 /* SB Winbond 8259 ? */
+ 04 /* Serial Ring */
+ 05 /* USB (ep405pc) */
+ 06 /* XIRQ 0 */
+ 06 /* XIRQ 1 */
+ 06 /* XIRQ 2 */
+ 06 /* XIRQ 3 */
+ 06 /* XIRQ 4 */
+ 06 /* XIRQ 5 */
+ 06 /* XIRQ 6 */
+ 07]; /* Reserved */
+ };
+ };
+
+ PCI0: pci@ec000000 {
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ compatible = "ibm,plb405gp-pci", "ibm,plb-pci";
+ primary;
+ reg = <eec00000 8 /* Config space access */
+ eed80000 4 /* IACK */
+ eed80000 4 /* Special cycle */
+ ef480000 40>; /* Internal registers */
+
+ /* Outbound ranges, one memory and one IO,
+ * later cannot be changed. Chip supports a second
+ * IO range but we don't use it for now
+ */
+ ranges = <02000000 0 80000000 80000000 0 20000000
+ 01000000 0 00000000 e8000000 0 00010000>;
+
+ /* Inbound 2GB range starting at 0 */
+ dma-ranges = <42000000 0 0 0 0 80000000>;
+
+ /* That's all I know about IRQs on that thing ... */
+ interrupt-map-mask = <f800 0 0 0>;
+ interrupt-map = <
+ /* USB */
+ 7000 0 0 0 &UIC0 1e 8 /* IRQ5 */
+ >;
+ };
+ };
+
+ chosen {
+ linux,stdout-path = "/plb/opb/serial@ef600300";
+ };
+};
Index: linux-work/arch/powerpc/boot/4xx.c
===================================================================
--- linux-work.orig/arch/powerpc/boot/4xx.c 2007-12-10 15:52:04.000000000 +1100
+++ linux-work/arch/powerpc/boot/4xx.c 2007-12-10 15:54:23.000000000 +1100
@@ -179,13 +179,16 @@ void ibm40x_dbcr_reset(void)
#define EMAC_RESET 0x20000000
void ibm4xx_quiesce_eth(u32 *emac0, u32 *emac1)
{
- /* Quiesce the MAL and EMAC(s) since PIBS/OpenBIOS don't do this for us */
+ /* Quiesce the MAL and EMAC(s) since PIBS/OpenBIOS don't
+ * do this for us
+ */
if (emac0)
*emac0 = EMAC_RESET;
if (emac1)
*emac1 = EMAC_RESET;
mtdcr(DCRN_MAL0_CFG, MAL_RESET);
+ while (mfdcr(DCRN_MAL0_CFG) & MAL_RESET) {};
}
/* Read 4xx EBC bus bridge registers to get mappings of the peripheral
@@ -298,3 +301,53 @@ void ibm440ep_fixup_clocks(unsigned int
dt_fixup_clock("/plb/opb/serial@ef600500", uart0);
dt_fixup_clock("/plb/opb/serial@ef600600", uart0);
}
+
+void ibm405gp_fixup_clocks(unsigned int sysclk, unsigned int ser_clk)
+{
+ u32 pllmr = mfdcr(DCRN_CPC0_PLLMR);
+ u32 cpc0_cr0 = mfdcr(DCRN_405_CPC0_CR0);
+ u32 cpc0_cr1 = mfdcr(DCRN_405_CPC0_CR1);
+ u32 cpu, plb, opb, ebc, tb, uart0, uart1, m;
+ u32 fwdv, fbdv, cbdv, opdv, epdv, udiv;
+
+ fwdv = (8 - ((pllmr & 0xe0000000) >> 29));
+ fbdv = (pllmr & 0x1e000000) >> 25;
+ cbdv = ((pllmr & 0x00060000) >> 17) + 1;
+ opdv = ((pllmr & 0x00018000) >> 15) + 1;
+ epdv = ((pllmr & 0x00001800) >> 13) + 2;
+ udiv = ((cpc0_cr0 & 0x3e) >> 1) + 1;
+
+ m = fwdv * fbdv * cbdv;
+
+ cpu = sysclk * m / fwdv;
+ plb = cpu / cbdv;
+ opb = plb / opdv;
+ ebc = plb / epdv;
+
+ if (cpc0_cr0 & 0x80) {
+ /* uart0 uses the external clock */
+ uart0 = ser_clk;
+ } else {
+ uart0 = cpu / udiv;
+ }
+
+ if (cpc0_cr0 & 0x40) {
+ /* uart1 uses the external clock */
+ uart1 = ser_clk;
+ } else {
+ uart1 = cpu / udiv;
+ }
+
+ /* setup the timebase clock to tick at the cpu frequency */
+ cpc0_cr1 = cpc0_cr1 & ~0x00800000;
+ mtdcr(DCRN_405_CPC0_CR1, cpc0_cr1);
+ tb = cpu;
+
+ dt_fixup_cpu_clocks(cpu, tb, 0);
+ dt_fixup_clock("/plb", plb);
+ dt_fixup_clock("/plb/opb", opb);
+ dt_fixup_clock("/plb/ebc", ebc);
+ dt_fixup_clock("/plb/opb/serial@ef600300", uart0);
+ dt_fixup_clock("/plb/opb/serial@ef600400", uart1);
+}
+
Index: linux-work/arch/powerpc/boot/treeboot-walnut.c
===================================================================
--- linux-work.orig/arch/powerpc/boot/treeboot-walnut.c 2007-12-10 15:52:04.000000000 +1100
+++ linux-work/arch/powerpc/boot/treeboot-walnut.c 2007-12-10 15:54:23.000000000 +1100
@@ -20,55 +20,6 @@
BSS_STACK(4096);
-void ibm405gp_fixup_clocks(unsigned int sysclk, unsigned int ser_clk)
-{
- u32 pllmr = mfdcr(DCRN_CPC0_PLLMR);
- u32 cpc0_cr0 = mfdcr(DCRN_405_CPC0_CR0);
- u32 cpc0_cr1 = mfdcr(DCRN_405_CPC0_CR1);
- u32 cpu, plb, opb, ebc, tb, uart0, uart1, m;
- u32 fwdv, fbdv, cbdv, opdv, epdv, udiv;
-
- fwdv = (8 - ((pllmr & 0xe0000000) >> 29));
- fbdv = (pllmr & 0x1e000000) >> 25;
- cbdv = ((pllmr & 0x00060000) >> 17) + 1;
- opdv = ((pllmr & 0x00018000) >> 15) + 1;
- epdv = ((pllmr & 0x00001800) >> 13) + 2;
- udiv = ((cpc0_cr0 & 0x3e) >> 1) + 1;
-
- m = fwdv * fbdv * cbdv;
-
- cpu = sysclk * m / fwdv;
- plb = cpu / cbdv;
- opb = plb / opdv;
- ebc = plb / epdv;
-
- if (cpc0_cr0 & 0x80) {
- /* uart0 uses the external clock */
- uart0 = ser_clk;
- } else {
- uart0 = cpu / udiv;
- }
-
- if (cpc0_cr0 & 0x40) {
- /* uart1 uses the external clock */
- uart1 = ser_clk;
- } else {
- uart1 = cpu / udiv;
- }
-
- /* setup the timebase clock to tick at the cpu frequency */
- cpc0_cr1 = cpc0_cr1 & ~0x00800000;
- mtdcr(DCRN_405_CPC0_CR1, cpc0_cr1);
- tb = cpu;
-
- dt_fixup_cpu_clocks(cpu, tb, 0);
- dt_fixup_clock("/plb", plb);
- dt_fixup_clock("/plb/opb", opb);
- dt_fixup_clock("/plb/ebc", ebc);
- dt_fixup_clock("/plb/opb/serial@ef600300", uart0);
- dt_fixup_clock("/plb/opb/serial@ef600400", uart1);
-}
-
static void walnut_flashsel_fixup(void)
{
void *devp, *sram;
Index: linux-work/arch/powerpc/platforms/40x/Kconfig
===================================================================
--- linux-work.orig/arch/powerpc/platforms/40x/Kconfig 2007-12-10 15:52:04.000000000 +1100
+++ linux-work/arch/powerpc/platforms/40x/Kconfig 2007-12-10 15:54:23.000000000 +1100
@@ -14,20 +14,13 @@
# help
# This option enables support for the CPCI405 board.
-#config EP405
-# bool "EP405/EP405PC"
-# depends on 40x
-# default n
-# select 405GP
-# help
-# This option enables support for the EP405/EP405PC boards.
-
-#config EP405PC
-# bool "EP405PC Support"
-# depends on EP405
-# default y
-# help
-# This option enables support for the extra features of the EP405PC board.
+config EP405
+ bool "EP405/EP405PC"
+ depends on 40x
+ default n
+ select 405GP
+ help
+ This option enables support for the EP405/EP405PC boards.
config KILAUEA
bool "Kilauea"
Index: linux-work/arch/powerpc/platforms/40x/Makefile
===================================================================
--- linux-work.orig/arch/powerpc/platforms/40x/Makefile 2007-12-10 15:52:04.000000000 +1100
+++ linux-work/arch/powerpc/platforms/40x/Makefile 2007-12-10 15:54:23.000000000 +1100
@@ -1,3 +1,4 @@
obj-$(CONFIG_KILAUEA) += kilauea.o
obj-$(CONFIG_WALNUT) += walnut.o
obj-$(CONFIG_XILINX_VIRTEX_GENERIC_BOARD) += virtex.o
+obj-$(CONFIG_EP405) += ep405.o
Index: linux-work/arch/powerpc/platforms/40x/ep405.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-work/arch/powerpc/platforms/40x/ep405.c 2007-12-10 15:55:38.000000000 +1100
@@ -0,0 +1,124 @@
+/*
+ * Architecture- / platform-specific boot-time initialization code for
+ * IBM PowerPC 4xx based boards. Adapted from original
+ * code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
+ * <dan@net4x.com>.
+ *
+ * Copyright(c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
+ *
+ * Rewritten and ported to the merged powerpc tree:
+ * Copyright 2007 IBM Corporation
+ * Josh Boyer <jwboyer@linux.vnet.ibm.com>
+ *
+ * Adapted to EP405 by Ben. Herrenschmidt <benh@kernel.crashing.org>
+ *
+ * TODO: Wire up the PCI IRQ mux and the southbridge interrupts
+ *
+ * 2002 (c) MontaVista, Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/init.h>
+#include <linux/of_platform.h>
+
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <asm/time.h>
+#include <asm/uic.h>
+#include <asm/pci-bridge.h>
+
+static struct device_node *bcsr_node;
+static void __iomem *bcsr_regs;
+
+/* BCSR registers */
+#define BCSR_ID 0
+#define BCSR_PCI_CTRL 1
+#define BCSR_FLASH_NV_POR_CTRL 2
+#define BCSR_FENET_UART_CTRL 3
+#define BCSR_PCI_IRQ 4
+#define BCSR_XIRQ_SELECT 5
+#define BCSR_XIRQ_ROUTING 6
+#define BCSR_XIRQ_STATUS 7
+#define BCSR_XIRQ_STATUS2 8
+#define BCSR_SW_STAT_LED_CTRL 9
+#define BCSR_GPIO_IRQ_PAR_CTRL 10
+/* there's more, can't be bothered typing them tho */
+
+
+static struct of_device_id ep405_of_bus[] = {
+ { .compatible = "ibm,plb3", },
+ { .compatible = "ibm,opb", },
+ { .compatible = "ibm,ebc", },
+ {},
+};
+
+static int __init ep405_device_probe(void)
+{
+ if (!machine_is(ep405))
+ return 0;
+
+ of_platform_bus_probe(NULL, ep405_of_bus, NULL);
+
+ return 0;
+}
+device_initcall(ep405_device_probe);
+
+static void __init ep405_init_bcsr(void)
+{
+ const u8 *irq_routing;
+ int i;
+
+ /* Find the bloody thing & map it */
+ bcsr_node = of_find_compatible_node(NULL, NULL, "ep405-bcsr");
+ if (bcsr_node == NULL) {
+ printk(KERN_ERR "EP405 BCSR not found !\n");
+ return;
+ }
+ bcsr_regs = of_iomap(bcsr_node, 0);
+ if (bcsr_regs == NULL) {
+ printk(KERN_ERR "EP405 BCSR failed to map !\n");
+ return;
+ }
+
+ /* Get the irq-routing property and apply the routing to the CPLD */
+ irq_routing = of_get_property(bcsr_node, "irq-routing", NULL);
+ if (irq_routing == NULL)
+ return;
+ for (i = 0; i < 16; i++) {
+ u8 irq = irq_routing[i];
+ out_8(bcsr_regs + BCSR_XIRQ_SELECT, i);
+ out_8(bcsr_regs + BCSR_XIRQ_ROUTING, irq);
+ }
+ in_8(bcsr_regs + BCSR_XIRQ_SELECT);
+ mb();
+ out_8(bcsr_regs + BCSR_GPIO_IRQ_PAR_CTRL, 0xfe);
+}
+
+static void __init ep405_setup_arch(void)
+{
+ /* Find & init the BCSR CPLD */
+ ep405_init_bcsr();
+}
+
+static int __init ep405_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+
+ if (!of_flat_dt_is_compatible(root, "ep405"))
+ return 0;
+
+ return 1;
+}
+
+define_machine(ep405) {
+ .name = "EP405",
+ .probe = ep405_probe,
+ .setup_arch = ep405_setup_arch,
+ .progress = udbg_progress,
+ .init_IRQ = uic_init_tree,
+ .get_irq = uic_get_irq,
+ .calibrate_decr = generic_calibrate_decr,
+};
Index: linux-work/arch/powerpc/boot/4xx.h
===================================================================
--- linux-work.orig/arch/powerpc/boot/4xx.h 2007-12-10 15:52:04.000000000 +1100
+++ linux-work/arch/powerpc/boot/4xx.h 2007-12-10 15:54:23.000000000 +1100
@@ -18,5 +18,6 @@ void ibm40x_dbcr_reset(void);
void ibm4xx_quiesce_eth(u32 *emac0, u32 *emac1);
void ibm4xx_fixup_ebc_ranges(const char *ebc);
void ibm440ep_fixup_clocks(unsigned int sysclk, unsigned int ser_clk);
+void ibm405gp_fixup_clocks(unsigned int sysclk, unsigned int ser_clk);
#endif /* _POWERPC_BOOT_4XX_H_ */
Index: linux-work/arch/powerpc/boot/wrapper
===================================================================
--- linux-work.orig/arch/powerpc/boot/wrapper 2007-12-10 15:52:04.000000000 +1100
+++ linux-work/arch/powerpc/boot/wrapper 2007-12-10 15:54:23.000000000 +1100
@@ -163,7 +163,7 @@ ps3)
ksection=.kernel:vmlinux.bin
isection=.kernel:initrd
;;
-ep88xc)
+ep88xc|ep405)
platformo="$object/fixed-head.o $object/$platform.o"
binary=y
;;
Index: linux-work/arch/powerpc/configs/ep405_defconfig
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-work/arch/powerpc/configs/ep405_defconfig 2007-12-10 15:54:23.000000000 +1100
@@ -0,0 +1,951 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.24-rc2
+# Wed Nov 21 16:44:30 2007
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+# CONFIG_6xx is not set
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_8xx is not set
+CONFIG_40x=y
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_4xx=y
+# CONFIG_PPC_MM_SLICES is not set
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_OF=y
+CONFIG_PPC_UDBG_16550=y
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+# CONFIG_DEFAULT_UIMAGE is not set
+CONFIG_PPC_DCR_NATIVE=y
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_PPC_DCR=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+CONFIG_LBD=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Platform support
+#
+# CONFIG_PPC_MPC52xx is not set
+# CONFIG_PPC_MPC5200 is not set
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PQ2ADS is not set
+CONFIG_EP405=y
+# CONFIG_KILAUEA is not set
+# CONFIG_WALNUT is not set
+# CONFIG_XILINX_VIRTEX_GENERIC_BOARD is not set
+CONFIG_405GP=y
+CONFIG_IBM405_ERR77=y
+CONFIG_IBM405_ERR51=y
+# CONFIG_MPIC is not set
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPM2 is not set
+# CONFIG_FSL_ULI1575 is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_MATH_EMULATION is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+CONFIG_SUSPEND_UP_POSSIBLE=y
+CONFIG_HIBERNATION_UP_POSSIBLE=y
+CONFIG_SECCOMP=y
+CONFIG_WANT_DEVICE_TREE=y
+CONFIG_DEVICE_TREE="ep405.dts"
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
+# CONFIG_PCIEPORTBUS is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
+# CONFIG_PCI_MSI is not set
+CONFIG_PCI_LEGACY=y
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0xc0000000
+CONFIG_CONSISTENT_START=0xff100000
+CONFIG_CONSISTENT_SIZE=0x00200000
+CONFIG_BOOT_LOAD=0x00400000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=m
+CONFIG_MTD_BLOCK=m
+# CONFIG_MTD_BLOCK_RO is not set
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP_OF=y
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+CONFIG_OF_DEVICE=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=35000
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_XILINX_SYSACE is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_IP1000 is not set
+# CONFIG_ARCNET is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_IBM_NEW_EMAC=y
+CONFIG_IBM_NEW_EMAC_RXB=128
+CONFIG_IBM_NEW_EMAC_TXB=64
+CONFIG_IBM_NEW_EMAC_POLL_WEIGHT=32
+CONFIG_IBM_NEW_EMAC_RX_COPY_THRESHOLD=256
+CONFIG_IBM_NEW_EMAC_RX_SKB_HEADROOM=0
+# CONFIG_IBM_NEW_EMAC_DEBUG is not set
+CONFIG_IBM_NEW_EMAC_ZMII=y
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_B44 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+CONFIG_NETDEV_10000=y
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGBE is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+# CONFIG_NIU is not set
+# CONFIG_MLX4_CORE is not set
+# CONFIG_TEHUTI is not set
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PCI=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_RSA is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PPC_OF=y
+CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
+CONFIG_USB_OHCI_HCD_PPC_OF_LE=y
+CONFIG_USB_OHCI_HCD_PCI=y
+CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y
+CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_EDAC is not set
+# CONFIG_RTC_CLASS is not set
+
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+# CONFIG_UCC_SLOW is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_INSTRUMENTATION=y
+# CONFIG_PROFILING is not set
+# CONFIG_KPROBES is not set
+# CONFIG_MARKERS is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_DEBUGGER is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=y
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_PPC_CLOCK is not set
^ permalink raw reply
* RE: [PATCH] Fix rounding bug in emulation for double floatoperating
From: Liu Yu @ 2007-12-10 5:25 UTC (permalink / raw)
To: David Gibson; +Cc: linuxppc-dev
In-Reply-To: <20071210045616.GC29611@localhost.localdomain>
=20
> -----Original Message-----
> From: David Gibson [mailto:david@gibson.dropbear.id.au]=20
> Sent: Monday, December 10, 2007 12:56 PM
> To: Liu Yu
> Cc: linuxppc-dev@ozlabs.org
> Subject: Re: [PATCH] Fix rounding bug in emulation for double=20
> floatoperating
>=20
>=20
> On Mon, Dec 10, 2007 at 01:00:52PM +0800, Liu Yu wrote:
> >=20
> > This patch fixes rounding bug in emulation for double float=20
> operating on PowerPC platform.
> >=20
> > When pack double float operand, it need to truncate the=20
> tail due to the limited precision.
> > If the truncated part is not zero, the last bit of work bit=20
> (totally 3 bits) need to '|' 1.
> >=20
> > This patch is completed in _FP_FRAC_SRS_2(X,N,sz)=20
> (arch/powerpc/math-emu/op-2.h).
> > Originally the code leftwards rotates the operand to just keep the=20
> > truncated part, then check whether it is zero. However, the=20
> number it=20
> > rotates is not correct when N is not smaller than=20
> _FP_W_TYPE_SIZE, and it will cause the work bit '|' 1 in the=20
> improper case.
> >=20
> > This patch fixes this issue.
> >=20
> > Signed-off-by: Liu Yu <b13201@freescale.com>
>=20
> Wow someone deciphered the hideous macro hell of the math=20
> emulation code enough to fix a bug. I don't suppose you'd=20
> care to fix the millions of warnings that the math-emu code=20
> generates...?
Oh, I don't like macro define either. But it's really a bug...
^ permalink raw reply
* Re: [PATCH 19/25] powerpc: Wire up PCI on Bamboo board
From: Benjamin Herrenschmidt @ 2007-12-10 5:40 UTC (permalink / raw)
To: Josh Boyer; +Cc: linuxppc-dev
In-Reply-To: <20071206211906.2e1c099f@zod.rchland.ibm.com>
powerpc: Wire up PCI on Bamboo board
This adds the device-tree bits & call to ppc4xx_pci_find_bridges()
to make PCI work on the Bamboo board
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
Index: linux-work/arch/powerpc/boot/dts/bamboo.dts
===================================================================
--- linux-work.orig/arch/powerpc/boot/dts/bamboo.dts 2007-12-10 15:56:59.000000000 +1100
+++ linux-work/arch/powerpc/boot/dts/bamboo.dts 2007-12-10 16:39:51.000000000 +1100
@@ -239,10 +239,48 @@
zmii-channel = <1>;
};
};
+
+ PCI0: pci@ec000000 {
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ compatible = "ibm,plb440ep-pci", "ibm,plb-pci";
+ primary;
+ reg = <0 eec00000 8 /* Config space access */
+ 0 eed80000 4 /* IACK */
+ 0 eed80000 4 /* Special cycle */
+ 0 ef480000 40>; /* Internal registers */
+
+ /* Outbound ranges, one memory and one IO,
+ * later cannot be changed. Chip supports a second
+ * IO range but we don't use it for now
+ */
+ ranges = <02000000 0 a0000000 0 a0000000 0 20000000
+ 01000000 0 00000000 0 e8000000 0 00010000>;
+
+ /* Inbound 2GB range starting at 0 */
+ dma-ranges = <42000000 0 0 0 0 0 80000000>;
+
+ /* Bamboo has all 4 IRQ pins tied together per slot */
+ interrupt-map-mask = <f800 0 0 0>;
+ interrupt-map = <
+ /* IDSEL 1 */
+ 0800 0 0 0 &UIC0 1c 8
+
+ /* IDSEL 2 */
+ 1000 0 0 0 &UIC0 1b 8
+
+ /* IDSEL 3 */
+ 1800 0 0 0 &UIC0 1a 8
+
+ /* IDSEL 4 */
+ 2000 0 0 0 &UIC0 19 8
+ >;
+ };
};
chosen {
linux,stdout-path = "/plb/opb/serial@ef600300";
- bootargs = "console=ttyS0,115200";
};
};
^ permalink raw reply
* Re: [PATCH 23/25] powerpc: Rework 4xx clock probing in boot wrapper
From: Benjamin Herrenschmidt @ 2007-12-10 5:43 UTC (permalink / raw)
To: Josh Boyer; +Cc: linuxppc-dev
In-Reply-To: <20071206212744.7257f1a2@zod.rchland.ibm.com>
On Thu, 2007-12-06 at 21:27 -0600, Josh Boyer wrote:
> On Thu, 06 Dec 2007 19:00:22 +1100
> Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
>
> > Index: linux-work/arch/powerpc/boot/reg.h
> > ===================================================================
> > --- linux-work.orig/arch/powerpc/boot/reg.h 2007-12-03 14:26:09.000000000 +1100
> > +++ linux-work/arch/powerpc/boot/reg.h 2007-12-03 14:26:09.000000000 +1100
> > @@ -24,6 +24,14 @@ static inline u32 mfpvr(void)
> > : "=r" (rval)); rval; })
> > #define mtspr(rn, v) asm volatile("mtspr " __stringify(rn) ",%0" : : "r" (v))
> >
> > +#define __stringify_1(x) #x
> > +#define __stringify(x) __stringify_1(x)
> > +
> > +#define mfspr(rn) ({unsigned long rval; \
> > + asm volatile("mfspr %0," __stringify(rn) \
> > + : "=r" (rval)); rval; })
> > +#define mtspr(rn, v) asm volatile("mtspr " __stringify(rn) ",%0" : : "r" (v))
> > +
>
> You felt like duplicating this? It was added in the previous patch. :)
Want a new patch or can you just remove that bit ?
Ben.
^ permalink raw reply
* Re: [PATCH 18/25] powerpc: Base support for 440GX Taishan eval board
From: Benjamin Herrenschmidt @ 2007-12-10 5:39 UTC (permalink / raw)
To: Josh Boyer; +Cc: linuxppc-dev
In-Reply-To: <20071206211758.6f086161@zod.rchland.ibm.com>
powerpc: Base support for 440GX Taishan eval board
From: Hugh Blemings <hugh@blemings.org>
Signed-off-by: Hugh Blemings <hugh@blemings.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
This needs a bit of cleanup still, probably not to be merged as-is
just yet (like using mtdcri/mfdcri for CPR access).
Index: linux-work/arch/powerpc/boot/dcr.h
===================================================================
--- linux-work.orig/arch/powerpc/boot/dcr.h 2007-12-10 15:52:04.000000000 +1100
+++ linux-work/arch/powerpc/boot/dcr.h 2007-12-10 15:56:56.000000000 +1100
@@ -139,4 +139,31 @@ static const unsigned long sdram_bxcr[]
#define DCRN_405_CPC0_CR0 0xb1
#define DCRN_405_CPC0_CR1 0xb2
+
+/* 440GX Clock control etc */
+
+
+#define DCRN_CPR0_CLKUPD 0x020
+#define DCRN_CPR0_PLLC 0x040
+#define DCRN_CPR0_PLLD 0x060
+#define DCRN_CPR0_PRIMAD 0x080
+#define DCRN_CPR0_PRIMBD 0x0a0
+#define DCRN_CPR0_OPBD 0x0c0
+#define DCRN_CPR0_PERD 0x0e0
+#define DCRN_CPR0_MALD 0x100
+
+/* CPRs read/write helper macros - based off include/asm-ppc/ibm44x.h */
+
+#define DCRN_CPR0_CFGADDR 0xc
+#define DCRN_CPR0_CFGDATA 0xd
+
+#define CPR0_READ(offset) ({\
+ mtdcr(DCRN_CPR0_CFGADDR, offset); \
+ mfdcr(DCRN_CPR0_CFGDATA); })
+#define CPR0_WRITE(offset, data) ({\
+ mtdcr(DCRN_CPR0_CFGADDR, offset); \
+ mtdcr(DCRN_CPR0_CFGDATA, data); })
+
+
+
#endif /* _PPC_BOOT_DCR_H_ */
Index: linux-work/arch/powerpc/boot/Makefile
===================================================================
--- linux-work.orig/arch/powerpc/boot/Makefile 2007-12-10 15:54:23.000000000 +1100
+++ linux-work/arch/powerpc/boot/Makefile 2007-12-10 15:56:56.000000000 +1100
@@ -37,8 +37,10 @@ BOOTCFLAGS += -I$(obj) -I$(srctree)/$(ob
$(obj)/4xx.o: BOOTCFLAGS += -mcpu=440
$(obj)/ebony.o: BOOTCFLAGS += -mcpu=440
+$(obj)/cuboot-taishan.o: BOOTCFLAGS += -mcpu=440
$(obj)/treeboot-walnut.o: BOOTCFLAGS += -mcpu=405
+
zlib := inffast.c inflate.c inftrees.c
zlibheader := inffast.h inffixed.h inflate.h inftrees.h infutil.h
zliblinuxheader := zlib.h zconf.h zutil.h
@@ -56,7 +58,7 @@ src-plat := of.c cuboot-52xx.c cuboot-83
cuboot-ebony.c treeboot-ebony.c prpmc2800.c \
ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \
cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c cuboot-bamboo.c \
- fixed-head.S ep88xc.c cuboot-hpc2.c ep405.c
+ fixed-head.S ep88xc.c cuboot-hpc2.c ep405.c cuboot-taishan.c
src-boot := $(src-wlib) $(src-plat) empty.c
src-boot := $(addprefix $(obj)/, $(src-boot))
@@ -160,6 +162,7 @@ image-$(CONFIG_EBONY) += treeImage.ebo
image-$(CONFIG_BAMBOO) += treeImage.bamboo cuImage.bamboo
image-$(CONFIG_SEQUOIA) += cuImage.sequoia
image-$(CONFIG_WALNUT) += treeImage.walnut
+image-$(CONFIG_TAISHAN) += cuImage.taishan
endif
# For 32-bit powermacs, build the COFF and miboot images
Index: linux-work/arch/powerpc/Kconfig.debug
===================================================================
--- linux-work.orig/arch/powerpc/Kconfig.debug 2007-12-10 15:54:22.000000000 +1100
+++ linux-work/arch/powerpc/Kconfig.debug 2007-12-10 15:56:56.000000000 +1100
@@ -225,7 +225,8 @@ config PPC_EARLY_DEBUG_44x
depends on 44x
help
Select this to enable early debugging for IBM 44x chips via the
- inbuilt serial port.
+ inbuilt serial port. If you enable this, ensure you set
+ PPC_EARLY_DEBUG_44x_PHYSLOW below to suit your target board.
config PPC_EARLY_DEBUG_40x
bool "Early serial debugging for IBM/AMCC 40x CPUs"
@@ -250,6 +251,9 @@ config PPC_EARLY_DEBUG_44x_PHYSLOW
hex "Low 32 bits of early debug UART physical address"
depends on PPC_EARLY_DEBUG_44x
default "0x40000200"
+ help
+ You probably want 0x40000200 for ebony boards and
+ 0x40000300 for taishan
config PPC_EARLY_DEBUG_44x_PHYSHIGH
hex "EPRN of early debug UART physical address"
Index: linux-work/arch/powerpc/platforms/44x/Kconfig
===================================================================
--- linux-work.orig/arch/powerpc/platforms/44x/Kconfig 2007-12-10 15:52:04.000000000 +1100
+++ linux-work/arch/powerpc/platforms/44x/Kconfig 2007-12-10 16:36:44.000000000 +1100
@@ -22,6 +22,15 @@ config SEQUOIA
help
This option enables support for the AMCC PPC440EPX evaluation board.
+config TAISHAN
+ bool "Taishan"
+ depends on 44x
+ default n
+ select 440GX
+ help
+ This option enables support for the AMCC PPC440GX "Taishan"
+ evaluation board.
+
#config LUAN
# bool "Luan"
# depends on 44x
@@ -58,6 +67,10 @@ config 440GP
config 440GX
bool
+ select IBM_NEW_EMAC_EMAC4
+ select IBM_NEW_EMAC_RGMII
+ select IBM_NEW_EMAC_ZMII #test only
+ select IBM_NEW_EMAC_TAH #test only
config 440SP
bool
Index: linux-work/arch/powerpc/platforms/44x/Makefile
===================================================================
--- linux-work.orig/arch/powerpc/platforms/44x/Makefile 2007-12-10 15:52:04.000000000 +1100
+++ linux-work/arch/powerpc/platforms/44x/Makefile 2007-12-10 15:56:56.000000000 +1100
@@ -1,4 +1,5 @@
obj-$(CONFIG_44x) := misc_44x.o
obj-$(CONFIG_EBONY) += ebony.o
+obj-$(CONFIG_TAISHAN) += taishan.o
obj-$(CONFIG_BAMBOO) += bamboo.o
obj-$(CONFIG_SEQUOIA) += sequoia.o
Index: linux-work/arch/powerpc/platforms/44x/taishan.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-work/arch/powerpc/platforms/44x/taishan.c 2007-12-10 16:37:07.000000000 +1100
@@ -0,0 +1,74 @@
+/*
+ * Taishan board specific routines based off ebony.c code
+ * original copyrights below
+ *
+ * Matt Porter <mporter@kernel.crashing.org>
+ * Copyright 2002-2005 MontaVista Software Inc.
+ *
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ * Copyright (c) 2003-2005 Zultys Technologies
+ *
+ * Rewritten and ported to the merged powerpc tree:
+ * Copyright 2007 David Gibson <dwg@au1.ibm.com>, IBM Corporation.
+ *
+ * Modified from ebony.c for taishan:
+ * Copyright 2007 Hugh Blemings <hugh@au.ibm.com>, IBM Corporation.
+ *
+ * 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/init.h>
+#include <linux/of_platform.h>
+
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <asm/time.h>
+#include <asm/uic.h>
+#include <asm/pci-bridge.h>
+
+#include "44x.h"
+
+static struct of_device_id taishan_of_bus[] = {
+ { .compatible = "ibm,plb4", },
+ { .compatible = "ibm,opb", },
+ { .compatible = "ibm,ebc", },
+ {},
+};
+
+static int __init taishan_device_probe(void)
+{
+ if (!machine_is(taishan))
+ return 0;
+
+ of_platform_bus_probe(NULL, taishan_of_bus, NULL);
+
+ return 0;
+}
+device_initcall(taishan_device_probe);
+
+/*
+ * Called very early, MMU is off, device-tree isn't unflattened
+ */
+static int __init taishan_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+
+ if (!of_flat_dt_is_compatible(root, "amcc,taishan"))
+ return 0;
+
+ return 1;
+}
+
+define_machine(taishan) {
+ .name = "Taishan",
+ .probe = taishan_probe,
+ .progress = udbg_progress,
+ .init_IRQ = uic_init_tree,
+ .get_irq = uic_get_irq,
+ .restart = ppc44x_reset_system,
+ .calibrate_decr = generic_calibrate_decr,
+};
Index: linux-work/arch/powerpc/boot/dts/taishan.dts
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-work/arch/powerpc/boot/dts/taishan.dts 2007-12-10 16:38:54.000000000 +1100
@@ -0,0 +1,375 @@
+/*
+ * Device Tree Source for IBM/AMCC Taishan
+ *
+ * Copyright 2007 IBM Corp.
+ * Hugh Blemings <hugh@au.ibm.com> based off code by
+ * Josh Boyer <jwboyer@linux.vnet.ibm.com>, David Gibson <dwg@au1.ibm.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without
+ * any warranty of any kind, whether express or implied.
+ */
+
+/ {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ model = "amcc,taishan";
+ compatible = "amcc,taishan";
+ dcr-parent = <&/cpus/PowerPC,440GX@0>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,440GX@0 {
+ device_type = "cpu";
+ reg = <0>;
+ clock-frequency = <2FAF0800>; // 800MHz
+ timebase-frequency = <0>; // Filled in by zImage
+ i-cache-line-size = <32>;
+ d-cache-line-size = <32>;
+ i-cache-size = <8000>; /* 32 kB */
+ d-cache-size = <8000>; /* 32 kB */
+ dcr-controller;
+ dcr-access-method = "native";
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0 0 0>; // Filled in by zImage
+ };
+
+
+ UICB0: interrupt-controller-base {
+ compatible = "ibm,uic-440gx", "ibm,uic";
+ interrupt-controller;
+ cell-index = <3>;
+ dcr-reg = <200 009>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ };
+
+
+ UIC0: interrupt-controller0 {
+ compatible = "ibm,uic-440gx", "ibm,uic";
+ interrupt-controller;
+ cell-index = <0>;
+ dcr-reg = <0c0 009>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupts = <01 4 00 4>; /* cascade - first non-critical */
+ interrupt-parent = <&UICB0>;
+
+ };
+
+ UIC1: interrupt-controller1 {
+ compatible = "ibm,uic-440gx", "ibm,uic";
+ interrupt-controller;
+ cell-index = <1>;
+ dcr-reg = <0d0 009>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupts = <03 4 02 4>; /* cascade */
+ interrupt-parent = <&UICB0>;
+ };
+
+ UIC2: interrupt-controller2 {
+ compatible = "ibm,uic-440gx", "ibm,uic";
+ interrupt-controller;
+ cell-index = <2>; /* was 1 */
+ dcr-reg = <210 009>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupts = <05 4 04 4>; /* cascade */
+ interrupt-parent = <&UICB0>;
+ };
+
+
+ CPC0: cpc {
+ compatible = "ibm,cpc-440gp";
+ dcr-reg = <0b0 003 0e0 010>;
+ // FIXME: anything else?
+ };
+
+ plb {
+ compatible = "ibm,plb-440gx", "ibm,plb4";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges;
+ clock-frequency = <9896800>; // 160MHz
+
+ SDRAM0: memory-controller {
+ compatible = "ibm,sdram-440gp";
+ dcr-reg = <010 2>;
+ // FIXME: anything else?
+ };
+
+ SRAM0: sram {
+ compatible = "ibm,sram-440gp";
+ dcr-reg = <020 8 00a 1>;
+ };
+
+ DMA0: dma {
+ // FIXME: ???
+ compatible = "ibm,dma-440gp";
+ dcr-reg = <100 027>;
+ };
+
+ MAL0: mcmal {
+ compatible = "ibm,mcmal-440gx", "ibm,mcmal2";
+ dcr-reg = <180 62>;
+ num-tx-chans = <4>;
+ num-rx-chans = <4>;
+ interrupt-parent = <&MAL0>;
+ interrupts = <0 1 2 3 4>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = </*TXEOB*/ 0 &UIC0 a 4
+ /*RXEOB*/ 1 &UIC0 b 4
+ /*SERR*/ 2 &UIC1 0 4
+ /*TXDE*/ 3 &UIC1 1 4
+ /*RXDE*/ 4 &UIC1 2 4>;
+ interrupt-map-mask = <ffffffff>;
+ };
+
+ POB0: opb {
+ compatible = "ibm,opb-440gx", "ibm,opb";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ /* Wish there was a nicer way of specifying a full 32-bit
+ range */
+ ranges = <00000000 1 00000000 80000000
+ 80000000 1 80000000 80000000>;
+ dcr-reg = <090 00b>;
+ interrupt-parent = <&UIC1>;
+ interrupts = <7 4>;
+ clock-frequency = <4C4B400>; // 80MHz
+
+
+ EBC0: ebc {
+ compatible = "ibm,ebc-440gx", "ibm,ebc";
+ dcr-reg = <012 2>;
+ #address-cells = <2>;
+ #size-cells = <1>;
+ clock-frequency = <4C4B400>; // 80MHz
+
+ /* ranges property is supplied by zImage
+ * based on firmware's configuration of the
+ * EBC bridge */
+
+ interrupts = <5 4>;
+ interrupt-parent = <&UIC1>;
+
+ /* TODO: Add other EBC devices */
+ };
+
+
+
+ UART0: serial@40000200 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <40000200 8>;
+ virtual-reg = <e0000200>;
+ clock-frequency = <A8C000>;
+ current-speed = <1C200>; /* 115200 */
+ interrupt-parent = <&UIC0>;
+ interrupts = <0 4>;
+ };
+
+ UART1: serial@40000300 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <40000300 8>;
+ virtual-reg = <e0000300>;
+ clock-frequency = <A8C000>;
+ current-speed = <1C200>; /* 115200 */
+ interrupt-parent = <&UIC0>;
+ interrupts = <1 4>;
+ };
+
+ IIC0: i2c@40000400 {
+ /* FIXME */
+ device_type = "i2c";
+ compatible = "ibm,iic-440gp", "ibm,iic";
+ reg = <40000400 14>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <2 4>;
+ };
+ IIC1: i2c@40000500 {
+ /* FIXME */
+ device_type = "i2c";
+ compatible = "ibm,iic-440gp", "ibm,iic";
+ reg = <40000500 14>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <3 4>;
+ };
+
+ GPIO0: gpio@40000700 {
+ /* FIXME */
+ compatible = "ibm,gpio-440gp";
+ reg = <40000700 20>;
+ };
+
+ ZMII0: emac-zmii@40000780 {
+ device_type = "zgmii-interface";
+ compatible = "ibm,zmii-440gx", "ibm,zmii";
+ reg = <40000780 c>;
+ };
+
+ RGMII0: emac-rgmii@40000790 {
+ device_type = "rgmii-interface";
+ compatible = "ibm,rgmii";
+ reg = <40000790 8>;
+ };
+
+
+ EMAC0: ethernet@40000800 {
+ unused = <1>;
+ linux,network-index = <2>;
+ device_type = "network";
+ compatible = "ibm,emac-440gx", "ibm,emac4";
+ interrupt-parent = <&UIC1>;
+ interrupts = <1c 4 1d 4>;
+ reg = <40000800 70>;
+ local-mac-address = [000000000000]; // Filled in by zImage
+ mal-device = <&MAL0>;
+ mal-tx-channel = <0>;
+ mal-rx-channel = <0>;
+ cell-index = <0>;
+ max-frame-size = <5dc>;
+ rx-fifo-size = <1000>;
+ tx-fifo-size = <800>;
+ phy-mode = "rmii";
+ phy-map = <00000001>;
+ zmii-device = <&ZMII0>;
+ zmii-channel = <0>;
+ };
+ EMAC1: ethernet@40000900 {
+ unused = <1>;
+ linux,network-index = <3>;
+ device_type = "network";
+ compatible = "ibm,emac-440gx", "ibm,emac4";
+ interrupt-parent = <&UIC1>;
+ interrupts = <1e 4 1f 4>;
+ reg = <40000900 70>;
+ local-mac-address = [000000000000]; // Filled in by zImage
+ mal-device = <&MAL0>;
+ mal-tx-channel = <1>;
+ mal-rx-channel = <1>;
+ cell-index = <1>;
+ max-frame-size = <5dc>;
+ rx-fifo-size = <1000>;
+ tx-fifo-size = <800>;
+ phy-mode = "rmii";
+ phy-map = <00000001>;
+ zmii-device = <&ZMII0>;
+ zmii-channel = <1>;
+ };
+
+ EMAC2: ethernet@40000c00 {
+ linux,network-index = <0>;
+ device_type = "network";
+ compatible = "ibm,emac-440gx", "ibm,emac4";
+ interrupt-parent = <&UIC2>;
+ interrupts = <0 4 1 4>;
+ reg = <40000c00 70>;
+ local-mac-address = [000000000000]; // Filled in by zImage
+ mal-device = <&MAL0>;
+ mal-tx-channel = <2>;
+ mal-rx-channel = <2>;
+ cell-index = <2>;
+ max-frame-size = <5dc>;
+ rx-fifo-size = <1000>;
+ tx-fifo-size = <800>;
+ phy-mode = "rgmii";
+ phy-map = <00000001>;
+ rgmii-device = <&RGMII0>;
+ rgmii-channel = <0>;
+ zmii-device = <&ZMII0>;
+ zmii-channel = <2>;
+ };
+
+ EMAC3: ethernet@40000e00 {
+ linux,network-index = <1>;
+ device_type = "network";
+ compatible = "ibm,emac-440gx", "ibm,emac4";
+ interrupt-parent = <&UIC2>;
+ interrupts = <2 4 3 4>;
+ reg = <40000e00 70>;
+ local-mac-address = [000000000000]; // Filled in by zImage
+ mal-device = <&MAL0>;
+ mal-tx-channel = <3>;
+ mal-rx-channel = <3>;
+ cell-index = <3>;
+ max-frame-size = <5dc>;
+ rx-fifo-size = <1000>;
+ tx-fifo-size = <800>;
+ phy-mode = "rgmii";
+ phy-map = <00000003>;
+ rgmii-device = <&RGMII0>;
+ rgmii-channel = <1>;
+ zmii-device = <&ZMII0>;
+ zmii-channel = <3>;
+ };
+
+
+ GPT0: gpt@40000a00 {
+ /* FIXME */
+ reg = <40000a00 d4>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <12 4 13 4 14 4 15 4 16 4>;
+ };
+
+ };
+
+ PCIX0: pci@20ec00000 {
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ compatible = "ibm,plb440gp-pcix", "ibm,plb-pcix";
+ primary;
+ large-inbound-windows;
+ enable-msi-hole;
+ reg = <2 0ec00000 8 /* Config space access */
+ 0 0 0 /* no IACK cycles */
+ 2 0ed00000 4 /* Special cycles */
+ 2 0ec80000 100 /* Internal registers */
+ 2 0ec80100 fc>; /* Internal messaging registers */
+
+ /* Outbound ranges, one memory and one IO,
+ * later cannot be changed
+ */
+ ranges = <02000000 0 80000000 00000003 80000000 0 80000000
+ 01000000 0 00000000 00000002 08000000 0 00010000>;
+
+ /* Inbound 2GB range starting at 0 */
+ dma-ranges = <42000000 0 0 0 0 0 80000000>;
+
+ interrupt-map-mask = <f800 0 0 7>;
+ interrupt-map = <
+ /* IDSEL 1 */
+ 0800 0 0 1 &UIC0 17 8
+ 0800 0 0 2 &UIC0 18 8
+ 0800 0 0 3 &UIC0 19 8
+ 0800 0 0 4 &UIC0 1a 8
+
+ /* IDSEL 2 */
+ 1000 0 0 1 &UIC0 18 8
+ 1000 0 0 2 &UIC0 19 8
+ 1000 0 0 3 &UIC0 1a 8
+ 1000 0 0 4 &UIC0 17 8
+ >;
+ };
+ };
+
+ chosen {
+ linux,stdout-path = "/plb/opb/serial@40000300";
+ };
+};
Index: linux-work/arch/powerpc/boot/cuboot-taishan.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-work/arch/powerpc/boot/cuboot-taishan.c 2007-12-10 15:56:56.000000000 +1100
@@ -0,0 +1,56 @@
+/*
+ * Old U-boot compatibility for Taishan
+ *
+ * Author: Hugh Blemings <hugh@au.ibm.com>
+ *
+ * Copyright 2007 Hugh Blemings, IBM Corporation.
+ * Based on cuboot-ebony.c which is:
+ * Copyright 2007 David Gibson, IBM Corporation.
+ * Based on cuboot-83xx.c, which is:
+ * Copyright (c) 2007 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 version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include "ops.h"
+#include "stdio.h"
+#include "cuboot.h"
+#include "reg.h"
+#include "dcr.h"
+#include "4xx.h"
+
+#define TARGET_44x
+#include "ppcboot.h"
+
+static bd_t bd;
+
+BSS_STACK(4096);
+
+static void taishan_fixups(void)
+{
+ /* FIXME: sysclk should be derived by reading the FPGA
+ registers */
+ unsigned long sysclk = 33000000;
+
+ /* 440EP Clock logic is all but identical to 440GX
+ so we just use that code for now at least */
+ ibm440ep_fixup_clocks(sysclk, 6 * 1843200);
+
+ ibm4xx_fixup_memsize();
+
+ dt_fixup_mac_addresses(bd.bi_enetaddr, bd.bi_enet1addr);
+
+ ibm4xx_fixup_ebc_ranges("/plb/opb/ebc");
+}
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ CUBOOT_INIT();
+
+ platform_ops.fixups = taishan_fixups;
+ ft_init(_dtb_start, _dtb_end - _dtb_start, 32);
+ serial_console_init();
+}
^ permalink raw reply
* RE: Xilinx ML310 Linux 2.6 PCI bridge
From: Stephen Neuendorffer @ 2007-12-10 5:46 UTC (permalink / raw)
To: Grant Likely, Jean-Samuel Chenard; +Cc: linuxppc-embedded
In-Reply-To: <fa686aa40712091223x3efb1143kfd81277890fb74ae@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 2337 bytes --]
I would strongly recommend not spending a huge amount of time on the ml310. The University program board is dirt cheap for universities, very well supported under Linux, using either secretlab.ca or git.xilinx.com and you won't spend your time getting PCI to place and route correctly, followed by figuring out how to get Linux to talk to it nicely.
If your lab can afford a bee2, then you should be able to afford one (or better yet, several) xupv2p's to go with it.
http://www.xilinx.com/univ/xupv2p.html
Steve
-----Original Message-----
From: linuxppc-embedded-bounces+stephen=neuendorffer.name@ozlabs.org on behalf of Grant Likely
Sent: Sun 12/9/2007 12:23 PM
To: Jean-Samuel Chenard
Cc: linuxppc-embedded@ozlabs.org
Subject: Re: Xilinx ML310 Linux 2.6 PCI bridge
On 12/9/07, Jean-Samuel Chenard <jsamch@macs.ece.mcgill.ca> wrote:
> On Dec 9, 2007 1:18 AM, Grant Likely <grant.likely@secretlab.ca> wrote:
> > On 12/8/07, Jean-Samuel Chenard <jsamch@macs.ece.mcgill.ca> wrote:
> > > Thanks to the valuable information provided by this discussion group and
> > > particularly by Grant Likely from Secret Lab Technologies, I was able to
> > > setup and run Linux 2.6 on my ML-310 development platform.
> >
> > Congratulations. If you had to make any changes to get it to work
> > then please send me your patches.
>
> Thank you for the quick reply.
No problem.
>
> I will directly update Secret Lab's Wiki pages. Those pages are the
> ones that got me going really quickly, so I will add a few of my
> observations directly on your pages so everyone can benefit.
Much appreciated; thank you!
> My real target is the control FPGA on a BEE2 box
> (http://bee2.eecs.berkeley.edu) and on that particular setup, the
> control FPGA is directly connected to an LXT971A Ethernet PHY, so I'll
> use the ethernet MAC from Xilinx.
Cool platform. Yes, you should have much better luck with the EMAC
core. The driver needs some work to be acceptable for mainline, but
it should be functional.
Cheers,
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195
_______________________________________________
Linuxppc-embedded mailing list
Linuxppc-embedded@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-embedded
[-- Attachment #2: Type: text/html, Size: 3247 bytes --]
^ permalink raw reply
* [PATCH] pci: Fix bus resource assignment on 32 bits with 64b resources
From: Benjamin Herrenschmidt @ 2007-12-10 6:15 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: linuxppc-dev, linux-pci, linux-kernel
The current pci_assign_unassigned_resources() code doesn't work properly
on 32 bits platforms with 64 bits resources. The main reason is the use
of unsigned long in various places instead of resource_size_t.
This fixes it, along with some tricks to avoid casting to 64 bits on
platforms that don't need it in every printk around.
This is a pre-requisite for making powerpc use the generic code instead of
its own half-useful implementation.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
This version now uses casts as Greg asked for and adds proper setup
of the prefetchable base & limit "upper" registers when using 64 bits
resources.
drivers/pci/setup-bus.c | 59 +++++++++++++++++++++++++++++-------------------
include/linux/pci.h | 4 +--
2 files changed, 38 insertions(+), 25 deletions(-)
Index: linux-work/drivers/pci/setup-bus.c
===================================================================
--- linux-work.orig/drivers/pci/setup-bus.c 2007-12-10 16:56:51.000000000 +1100
+++ linux-work/drivers/pci/setup-bus.c 2007-12-10 17:12:27.000000000 +1100
@@ -89,8 +89,9 @@ void pci_setup_cardbus(struct pci_bus *b
* The IO resource is allocated a range twice as large as it
* would normally need. This allows us to set both IO regs.
*/
- printk(" IO window: %08lx-%08lx\n",
- region.start, region.end);
+ printk(KERN_INFO " IO window: 0x%08lx-0x%08lx\n",
+ (unsigned long)region.start,
+ (unsigned long)region.end);
pci_write_config_dword(bridge, PCI_CB_IO_BASE_0,
region.start);
pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0,
@@ -99,8 +100,9 @@ void pci_setup_cardbus(struct pci_bus *b
pcibios_resource_to_bus(bridge, ®ion, bus->resource[1]);
if (bus->resource[1]->flags & IORESOURCE_IO) {
- printk(" IO window: %08lx-%08lx\n",
- region.start, region.end);
+ printk(KERN_INFO " IO window: 0x%08lx-0x%08lx\n",
+ (unsigned long)region.start,
+ (unsigned long)region.end);
pci_write_config_dword(bridge, PCI_CB_IO_BASE_1,
region.start);
pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1,
@@ -109,8 +111,9 @@ void pci_setup_cardbus(struct pci_bus *b
pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]);
if (bus->resource[2]->flags & IORESOURCE_MEM) {
- printk(" PREFETCH window: %08lx-%08lx\n",
- region.start, region.end);
+ printk(KERN_INFO " PREFETCH window: 0x%08lx-0x%08lx\n",
+ (unsigned long)region.start,
+ (unsigned long)region.end);
pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0,
region.start);
pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0,
@@ -119,8 +122,9 @@ void pci_setup_cardbus(struct pci_bus *b
pcibios_resource_to_bus(bridge, ®ion, bus->resource[3]);
if (bus->resource[3]->flags & IORESOURCE_MEM) {
- printk(" MEM window: %08lx-%08lx\n",
- region.start, region.end);
+ printk(KERN_INFO " MEM window: 0x%08lx-0x%08lx\n",
+ (unsigned long)region.start,
+ (unsigned long)region.end);
pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1,
region.start);
pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1,
@@ -145,7 +149,7 @@ pci_setup_bridge(struct pci_bus *bus)
{
struct pci_dev *bridge = bus->self;
struct pci_bus_region region;
- u32 l, io_upper16;
+ u32 l, bu, lu, io_upper16;
DBG(KERN_INFO "PCI: Bridge: %s\n", pci_name(bridge));
@@ -159,7 +163,8 @@ pci_setup_bridge(struct pci_bus *bus)
/* Set up upper 16 bits of I/O base/limit. */
io_upper16 = (region.end & 0xffff0000) | (region.start >> 16);
DBG(KERN_INFO " IO window: %04lx-%04lx\n",
- region.start, region.end);
+ (unsigned long)region.start,
+ (unsigned long)region.end);
}
else {
/* Clear upper 16 bits of I/O base/limit. */
@@ -180,8 +185,9 @@ pci_setup_bridge(struct pci_bus *bus)
if (bus->resource[1]->flags & IORESOURCE_MEM) {
l = (region.start >> 16) & 0xfff0;
l |= region.end & 0xfff00000;
- DBG(KERN_INFO " MEM window: %08lx-%08lx\n",
- region.start, region.end);
+ DBG(KERN_INFO " MEM window: 0x%08lx-0x%08lx\n",
+ (unsigned long)region.start,
+ (unsigned long)region.end);
}
else {
l = 0x0000fff0;
@@ -195,12 +201,18 @@ pci_setup_bridge(struct pci_bus *bus)
pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
/* Set up PREF base/limit. */
+ bu = lu = 0;
pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]);
if (bus->resource[2]->flags & IORESOURCE_PREFETCH) {
l = (region.start >> 16) & 0xfff0;
l |= region.end & 0xfff00000;
- DBG(KERN_INFO " PREFETCH window: %08lx-%08lx\n",
- region.start, region.end);
+#ifdef CONFIG_RESOURCES_64BIT
+ bu = region.start >> 32;
+ lu = region.end >> 32;
+#endif
+ DBG(KERN_INFO " PREFETCH window: 0x%016llx-0x%016llx\n",
+ (unsigned long long)region.start,
+ (unsigned long long)region.end);
}
else {
l = 0x0000fff0;
@@ -208,8 +220,9 @@ pci_setup_bridge(struct pci_bus *bus)
}
pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
- /* Clear out the upper 32 bits of PREF base. */
- pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0);
+ /* Set the upper 32 bits of PREF base & limit. */
+ pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu);
+ pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu);
pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl);
}
@@ -323,8 +336,8 @@ static void pbus_size_io(struct pci_bus
static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type)
{
struct pci_dev *dev;
- unsigned long min_align, align, size;
- unsigned long aligns[12]; /* Alignments from 1Mb to 2Gb */
+ resource_size_t min_align, align, size;
+ resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */
int order, max_order;
struct resource *b_res = find_free_bus_resource(bus, type);
@@ -340,7 +353,7 @@ static int pbus_size_mem(struct pci_bus
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
struct resource *r = &dev->resource[i];
- unsigned long r_size;
+ resource_size_t r_size;
if (r->parent || (r->flags & mask) != type)
continue;
@@ -350,10 +363,10 @@ static int pbus_size_mem(struct pci_bus
order = __ffs(align) - 20;
if (order > 11) {
printk(KERN_WARNING "PCI: region %s/%d "
- "too large: %llx-%llx\n",
+ "too large: 0x%016llx-0x%016llx\n",
pci_name(dev), i,
- (unsigned long long)r->start,
- (unsigned long long)r->end);
+ (unsigned long long)r->start,
+ (unsigned long long)r->end);
r->flags = 0;
continue;
}
@@ -372,7 +385,7 @@ static int pbus_size_mem(struct pci_bus
align = 0;
min_align = 0;
for (order = 0; order <= max_order; order++) {
- unsigned long align1 = 1UL << (order + 20);
+ resource_size_t align1 = RESOURCE_ORDER(order + 20);
if (!align)
min_align = align1;
Index: linux-work/include/linux/pci.h
===================================================================
--- linux-work.orig/include/linux/pci.h 2007-12-10 16:56:51.000000000 +1100
+++ linux-work/include/linux/pci.h 2007-12-10 16:57:20.000000000 +1100
@@ -314,8 +314,8 @@ struct pci_raw_ops {
extern struct pci_raw_ops *raw_pci_ops;
struct pci_bus_region {
- unsigned long start;
- unsigned long end;
+ resource_size_t start;
+ resource_size_t end;
};
struct pci_dynids {
^ permalink raw reply
* Re: [PATCH] pci: Fix bus resource assignment on 32 bits with 64b resources
From: Benjamin Herrenschmidt @ 2007-12-10 6:19 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: linuxppc-dev, linux-pci, linux-kernel
In-Reply-To: <20071210061559.2E3DDDDE02@ozlabs.org>
On Mon, 2007-12-10 at 17:15 +1100, Benjamin Herrenschmidt wrote:
> The current pci_assign_unassigned_resources() code doesn't work properly
> on 32 bits platforms with 64 bits resources. The main reason is the use
> of unsigned long in various places instead of resource_size_t.
>
> This fixes it, along with some tricks to avoid casting to 64 bits on
> platforms that don't need it in every printk around.
>
> This is a pre-requisite for making powerpc use the generic code instead of
> its own half-useful implementation.
>
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> ---
>
> This version now uses casts as Greg asked for and adds proper setup
> of the prefetchable base & limit "upper" registers when using 64 bits
> resources.
Crap ! Ignore it. I forgot to quilt ref again... won't build.
Sending it again, with a separate patch fixing a warning in setup-res.c
that isn't directly related to the changes to setup-bus.c
Cheers,
Ben.
^ permalink raw reply
* [PATCH 1/2] pci: Fix bus resource assignment on 32 bits with 64b resources
From: Benjamin Herrenschmidt @ 2007-12-10 6:32 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: linuxppc-dev, linux-pci, linux-kernel
The current pci_assign_unassigned_resources() code doesn't work properly
on 32 bits platforms with 64 bits resources. The main reason is the use
of unsigned long in various places instead of resource_size_t.
This fixes it, along with some tricks to avoid casting to 64 bits on
platforms that don't need it in every printk around.
This is a pre-requisite for making powerpc use the generic code instead of
its own half-useful implementation.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
This version now uses casts as Greg asked for and adds proper setup
of the prefetchable base & limit "upper" registers when using 64 bits
resources.
(and builds ... sorry about that)
drivers/pci/setup-bus.c | 64 ++++++++++++++++++++++++++++++------------------
include/linux/pci.h | 4 +--
2 files changed, 42 insertions(+), 26 deletions(-)
Index: linux-work/drivers/pci/setup-bus.c
===================================================================
--- linux-work.orig/drivers/pci/setup-bus.c 2007-12-10 17:16:44.000000000 +1100
+++ linux-work/drivers/pci/setup-bus.c 2007-12-10 17:21:53.000000000 +1100
@@ -89,8 +89,9 @@ void pci_setup_cardbus(struct pci_bus *b
* The IO resource is allocated a range twice as large as it
* would normally need. This allows us to set both IO regs.
*/
- printk(" IO window: %08lx-%08lx\n",
- region.start, region.end);
+ printk(KERN_INFO " IO window: 0x%08lx-0x%08lx\n",
+ (unsigned long)region.start,
+ (unsigned long)region.end);
pci_write_config_dword(bridge, PCI_CB_IO_BASE_0,
region.start);
pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0,
@@ -99,8 +100,9 @@ void pci_setup_cardbus(struct pci_bus *b
pcibios_resource_to_bus(bridge, ®ion, bus->resource[1]);
if (bus->resource[1]->flags & IORESOURCE_IO) {
- printk(" IO window: %08lx-%08lx\n",
- region.start, region.end);
+ printk(KERN_INFO " IO window: 0x%08lx-0x%08lx\n",
+ (unsigned long)region.start,
+ (unsigned long)region.end);
pci_write_config_dword(bridge, PCI_CB_IO_BASE_1,
region.start);
pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1,
@@ -109,8 +111,9 @@ void pci_setup_cardbus(struct pci_bus *b
pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]);
if (bus->resource[2]->flags & IORESOURCE_MEM) {
- printk(" PREFETCH window: %08lx-%08lx\n",
- region.start, region.end);
+ printk(KERN_INFO " PREFETCH window: 0x%08lx-0x%08lx\n",
+ (unsigned long)region.start,
+ (unsigned long)region.end);
pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0,
region.start);
pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0,
@@ -119,8 +122,9 @@ void pci_setup_cardbus(struct pci_bus *b
pcibios_resource_to_bus(bridge, ®ion, bus->resource[3]);
if (bus->resource[3]->flags & IORESOURCE_MEM) {
- printk(" MEM window: %08lx-%08lx\n",
- region.start, region.end);
+ printk(KERN_INFO " MEM window: 0x%08lx-0x%08lx\n",
+ (unsigned long)region.start,
+ (unsigned long)region.end);
pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1,
region.start);
pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1,
@@ -145,7 +149,7 @@ pci_setup_bridge(struct pci_bus *bus)
{
struct pci_dev *bridge = bus->self;
struct pci_bus_region region;
- u32 l, io_upper16;
+ u32 l, bu, lu, io_upper16;
DBG(KERN_INFO "PCI: Bridge: %s\n", pci_name(bridge));
@@ -159,7 +163,8 @@ pci_setup_bridge(struct pci_bus *bus)
/* Set up upper 16 bits of I/O base/limit. */
io_upper16 = (region.end & 0xffff0000) | (region.start >> 16);
DBG(KERN_INFO " IO window: %04lx-%04lx\n",
- region.start, region.end);
+ (unsigned long)region.start,
+ (unsigned long)region.end);
}
else {
/* Clear upper 16 bits of I/O base/limit. */
@@ -180,8 +185,9 @@ pci_setup_bridge(struct pci_bus *bus)
if (bus->resource[1]->flags & IORESOURCE_MEM) {
l = (region.start >> 16) & 0xfff0;
l |= region.end & 0xfff00000;
- DBG(KERN_INFO " MEM window: %08lx-%08lx\n",
- region.start, region.end);
+ DBG(KERN_INFO " MEM window: 0x%08lx-0x%08lx\n",
+ (unsigned long)region.start,
+ (unsigned long)region.end);
}
else {
l = 0x0000fff0;
@@ -195,12 +201,18 @@ pci_setup_bridge(struct pci_bus *bus)
pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
/* Set up PREF base/limit. */
+ bu = lu = 0;
pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]);
if (bus->resource[2]->flags & IORESOURCE_PREFETCH) {
l = (region.start >> 16) & 0xfff0;
l |= region.end & 0xfff00000;
- DBG(KERN_INFO " PREFETCH window: %08lx-%08lx\n",
- region.start, region.end);
+#ifdef CONFIG_RESOURCES_64BIT
+ bu = region.start >> 32;
+ lu = region.end >> 32;
+#endif
+ DBG(KERN_INFO " PREFETCH window: 0x%016llx-0x%016llx\n",
+ (unsigned long long)region.start,
+ (unsigned long long)region.end);
}
else {
l = 0x0000fff0;
@@ -208,8 +220,9 @@ pci_setup_bridge(struct pci_bus *bus)
}
pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
- /* Clear out the upper 32 bits of PREF base. */
- pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0);
+ /* Set the upper 32 bits of PREF base & limit. */
+ pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu);
+ pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu);
pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl);
}
@@ -323,8 +336,8 @@ static void pbus_size_io(struct pci_bus
static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type)
{
struct pci_dev *dev;
- unsigned long min_align, align, size;
- unsigned long aligns[12]; /* Alignments from 1Mb to 2Gb */
+ resource_size_t min_align, align, size;
+ resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */
int order, max_order;
struct resource *b_res = find_free_bus_resource(bus, type);
@@ -340,7 +353,7 @@ static int pbus_size_mem(struct pci_bus
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
struct resource *r = &dev->resource[i];
- unsigned long r_size;
+ resource_size_t r_size;
if (r->parent || (r->flags & mask) != type)
continue;
@@ -350,10 +363,10 @@ static int pbus_size_mem(struct pci_bus
order = __ffs(align) - 20;
if (order > 11) {
printk(KERN_WARNING "PCI: region %s/%d "
- "too large: %llx-%llx\n",
+ "too large: 0x%016llx-0x%016llx\n",
pci_name(dev), i,
- (unsigned long long)r->start,
- (unsigned long long)r->end);
+ (unsigned long long)r->start,
+ (unsigned long long)r->end);
r->flags = 0;
continue;
}
@@ -372,8 +385,11 @@ static int pbus_size_mem(struct pci_bus
align = 0;
min_align = 0;
for (order = 0; order <= max_order; order++) {
- unsigned long align1 = 1UL << (order + 20);
-
+#ifdef CONFIG_RESOURCES_64BIT
+ resource_size_t align1 = 1ULL << (order + 20);
+#else
+ resource_size_t align1 = 1U << (order + 20);
+#endif
if (!align)
min_align = align1;
else if (ALIGN(align + min_align, min_align) < align1)
Index: linux-work/include/linux/pci.h
===================================================================
--- linux-work.orig/include/linux/pci.h 2007-12-10 17:16:44.000000000 +1100
+++ linux-work/include/linux/pci.h 2007-12-10 17:16:46.000000000 +1100
@@ -314,8 +314,8 @@ struct pci_raw_ops {
extern struct pci_raw_ops *raw_pci_ops;
struct pci_bus_region {
- unsigned long start;
- unsigned long end;
+ resource_size_t start;
+ resource_size_t end;
};
struct pci_dynids {
^ permalink raw reply
* [PATCH 2/2] pci: Fix warning in setup-res.c on 32-bit platforms with 64-bit resources
From: Benjamin Herrenschmidt @ 2007-12-10 6:32 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: linuxppc-dev, linux-pci, linux-kernel
This adds appropriate casts to avoid a warning and print the correct
values in pr_debug.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
drivers/pci/setup-res.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
Index: linux-work/drivers/pci/setup-res.c
===================================================================
--- linux-work.orig/drivers/pci/setup-res.c 2007-12-10 17:17:32.000000000 +1100
+++ linux-work/drivers/pci/setup-res.c 2007-12-10 17:17:54.000000000 +1100
@@ -51,10 +51,12 @@ pci_update_resource(struct pci_dev *dev,
pcibios_resource_to_bus(dev, ®ion, res);
- pr_debug(" got res [%llx:%llx] bus [%lx:%lx] flags %lx for "
+ pr_debug(" got res [%llx:%llx] bus [%llx:%llx] flags %lx for "
"BAR %d of %s\n", (unsigned long long)res->start,
(unsigned long long)res->end,
- region.start, region.end, res->flags, resno, pci_name(dev));
+ (unsigned long long)region.start,
+ (unsigned long long)region.end,
+ (unsigned long)res->flags, resno, pci_name(dev));
new = region.start | (res->flags & PCI_REGION_FLAG_MASK);
if (res->flags & IORESOURCE_IO)
^ permalink raw reply
* [PATCH] [POWERPC] 4xx: Add 440SPe revA runtime detection to PCIe driver
From: Stefan Roese @ 2007-12-10 7:37 UTC (permalink / raw)
To: linuxppc-dev
This patch adds runtime detection of the 440SPe revision A chips. These
chips are equipped with a slighly different PCIe core and need special/
different initialization. The compatible node is changed to
"plb-pciex-440spe" ("A" and "B" dropped). This is needed for boards that
can be equipped with both PPC revisions like the AMCC Yucca.
Signed-off-by: Stefan Roese <sr@denx.de>
---
arch/powerpc/boot/dts/katmai.dts | 6 +++---
arch/powerpc/sysdev/ppc4xx_pci.c | 25 +++++++++++++++++--------
2 files changed, 20 insertions(+), 11 deletions(-)
diff --git a/arch/powerpc/boot/dts/katmai.dts b/arch/powerpc/boot/dts/katmai.dts
index 2bea84f..824cf4e 100644
--- a/arch/powerpc/boot/dts/katmai.dts
+++ b/arch/powerpc/boot/dts/katmai.dts
@@ -269,7 +269,7 @@
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
- compatible = "ibm,plb-pciex-440speB", "ibm,plb-pciex";
+ compatible = "ibm,plb-pciex-440spe", "ibm,plb-pciex";
primary;
port = <0>; /* port number */
reg = <d 00000000 20000000 /* Config space access */
@@ -310,7 +310,7 @@
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
- compatible = "ibm,plb-pciex-440speB", "ibm,plb-pciex";
+ compatible = "ibm,plb-pciex-440spe", "ibm,plb-pciex";
primary;
port = <1>; /* port number */
reg = <d 20000000 20000000 /* Config space access */
@@ -351,7 +351,7 @@
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
- compatible = "ibm,plb-pciex-440speB", "ibm,plb-pciex";
+ compatible = "ibm,plb-pciex-440spe", "ibm,plb-pciex";
primary;
port = <2>; /* port number */
reg = <d 40000000 20000000 /* Config space access */
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c
index bd85a40..744b5ca 100644
--- a/arch/powerpc/sysdev/ppc4xx_pci.c
+++ b/arch/powerpc/sysdev/ppc4xx_pci.c
@@ -49,6 +49,15 @@ extern unsigned long total_memory;
#define RES_TO_U32_HIGH(val) (0)
#endif
+static inline int ppc440spe_revA(void)
+{
+ /* Catch both 440SPe variants, with and without RAID6 support */
+ if ((mfspr(SPRN_PVR) & 0xffefffff) == 0x53421890)
+ return 1;
+ else
+ return 0;
+}
+
static void fixup_ppc4xx_pci_bridge(struct pci_dev *dev)
{
struct pci_controller *hose;
@@ -521,8 +530,7 @@ static void __init ppc4xx_probe_pcix_bridge(struct device_node *np)
*
* We support 3 parts currently based on the compatible property:
*
- * ibm,plb-pciex-440speA
- * ibm,plb-pciex-440speB
+ * ibm,plb-pciex-440spe
* ibm,plb-pciex-405ex
*
* Anything else will be rejected for now as they are all subtly
@@ -693,7 +701,7 @@ static int ppc440spe_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
mtdcri(SDR0, port->sdr_base + PESDRn_DLPSET, val);
mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET1, 0x20222222);
- if (of_device_is_compatible(port->node, "ibm,plb-pciex-440speA"))
+ if (ppc440spe_revA())
mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET2, 0x11000000);
mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL0SET1, 0x35000000);
mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL1SET1, 0x35000000);
@@ -772,7 +780,6 @@ static struct ppc4xx_pciex_hwops ppc440speB_pcie_hwops __initdata =
.setup_utl = ppc440speB_pciex_init_utl,
};
-
#endif /* CONFIG_44x */
#ifdef CONFIG_40x
@@ -888,10 +895,12 @@ static int __init ppc4xx_pciex_check_core_init(struct device_node *np)
return 0;
#ifdef CONFIG_44x
- if (of_device_is_compatible(np, "ibm,plb-pciex-440speA"))
- ppc4xx_pciex_hwops = &ppc440speA_pcie_hwops;
- else if (of_device_is_compatible(np, "ibm,plb-pciex-440speB"))
- ppc4xx_pciex_hwops = &ppc440speB_pcie_hwops;
+ if (of_device_is_compatible(np, "ibm,plb-pciex-440spe")) {
+ if (ppc440spe_revA())
+ ppc4xx_pciex_hwops = &ppc440speA_pcie_hwops;
+ else
+ ppc4xx_pciex_hwops = &ppc440speB_pcie_hwops;
+ }
#endif /* CONFIG_44x */
#ifdef CONFIG_40x
if (of_device_is_compatible(np, "ibm,plb-pciex-405ex"))
--
1.5.3.7.949.g2221a6
^ permalink raw reply related
* [PATCH] IB/ehca: Return correct #SGEs for SRQ
From: Joachim Fenkes @ 2007-12-10 11:20 UTC (permalink / raw)
To: LinuxPPC-Dev, LKML, OF-General, Roland Dreier, OF-EWG
Cc: Stefan Roscher, Christoph Raisch, Marcus Eder
Firmware would round up the number of SGEs to four, because the WQE
structure holds four SGEs. For SRQ, only three are supported, so return a
fixed value instead.
Signed-off-by: Joachim Fenkes <fenkes@de.ibm.com>
---
The patch will apply cleanly on top of Roland's git. Please review and apply
for 2.6.24 -- Thanks!
drivers/infiniband/hw/ehca/ehca_qp.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
index dd12668..eff5fb5 100644
--- a/drivers/infiniband/hw/ehca/ehca_qp.c
+++ b/drivers/infiniband/hw/ehca/ehca_qp.c
@@ -838,7 +838,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
/* copy back return values */
srq_init_attr->attr.max_wr = qp_init_attr.cap.max_recv_wr;
- srq_init_attr->attr.max_sge = qp_init_attr.cap.max_recv_sge;
+ srq_init_attr->attr.max_sge = 3;
/* drive SRQ into RTR state */
mqpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
@@ -1750,7 +1750,7 @@ int ehca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr)
}
srq_attr->max_wr = qpcb->max_nr_outst_recv_wr - 1;
- srq_attr->max_sge = qpcb->actual_nr_sges_in_rq_wqe;
+ srq_attr->max_sge = 3;
srq_attr->srq_limit = EHCA_BMASK_GET(
MQPCB_CURR_SRQ_LIMIT, qpcb->curr_srq_limit);
--
1.5.2
^ permalink raw reply related
* (no subject)
From: Aggrwal Poonam @ 2007-12-10 11:58 UTC (permalink / raw)
To: linuxppc-dev
With Regards
Poonam=20
=20
=20
^ permalink raw reply
* Re: [PATCH 23/25] powerpc: Rework 4xx clock probing in boot wrapper
From: Josh Boyer @ 2007-12-10 11:54 UTC (permalink / raw)
To: benh; +Cc: linuxppc-dev
In-Reply-To: <1197265411.6563.56.camel@pasglop>
On Mon, 10 Dec 2007 16:43:31 +1100
Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
>
> On Thu, 2007-12-06 at 21:27 -0600, Josh Boyer wrote:
> > On Thu, 06 Dec 2007 19:00:22 +1100
> > Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
> >
> > > Index: linux-work/arch/powerpc/boot/reg.h
> > > ===================================================================
> > > --- linux-work.orig/arch/powerpc/boot/reg.h 2007-12-03 14:26:09.000000000 +1100
> > > +++ linux-work/arch/powerpc/boot/reg.h 2007-12-03 14:26:09.000000000 +1100
> > > @@ -24,6 +24,14 @@ static inline u32 mfpvr(void)
> > > : "=r" (rval)); rval; })
> > > #define mtspr(rn, v) asm volatile("mtspr " __stringify(rn) ",%0" : : "r" (v))
> > >
> > > +#define __stringify_1(x) #x
> > > +#define __stringify(x) __stringify_1(x)
> > > +
> > > +#define mfspr(rn) ({unsigned long rval; \
> > > + asm volatile("mfspr %0," __stringify(rn) \
> > > + : "=r" (rval)); rval; })
> > > +#define mtspr(rn, v) asm volatile("mtspr " __stringify(rn) ",%0" : : "r" (v))
> > > +
> >
> > You felt like duplicating this? It was added in the previous patch. :)
>
> Want a new patch or can you just remove that bit ?
I can remove it on my final apply.
josh
^ permalink raw reply
* FW: [PATCH 0/3] UCC TDM driver for MPC83xx platforms
From: Aggrwal Poonam @ 2007-12-10 12:00 UTC (permalink / raw)
To: linuxppc-dev
=20
There are three patches
[PATCH 1/3] drivers/misc : UCC TDM driver for mpc83xx platforms. This
driver is usable in VoIP iind of applications to interface with SLIC
kind of devices to exchange TDM voice samples.
[PATCH 2/3] arch/ : Platform changes
- device tree entries for UCC TDM driver for MPC8323ERDB platform.
- QE changes related to TDM , like,
1) Modified ucc_fast_init so that it can be used by fast UCC
based TDM driver. Mainly changes have been made to configure TDM clocks
and Fsyncs.
2) Modified get_brg_clk so that it can return the input frequncy
and input source of any BRG by reading the corresponding entries from
device tree.
3) Added new nodes brg and clocks in the device tree which
represent input clocks for different BRGs.
4) Modified qe_setbrg accordingly.
- new device tree entries added for "clocks" and "brg"
[PATCH 3/3] Documentation
- Modified Documentation to explain the device tree entries related to
UCC TDM driver and the new nodes added("clocks" and "brg")
The patch applies over a merge of galak's for-2.6.25 plus for-2.6.24
plus of_doc_update branches.
In brief the steps were
git clone
git://git.kernel.org/pub/scm/linux/kernel/git/galak/powerpc.git
powerpc-galak git checkout -b for-2.6.25 origin/for-2.6.25 git checkout
-b for-2.6.24 origin/for-2.6.24 git checkout -b of_doc_update
origin/of_doc_update
git pull . for-2.6.24 # merge the other two
git pull . for-2.6.25=20
git checkout -b tdm # clean slate for tdm rebase work
Also after applying the patches changes have to be made corresponding to
Tabi's patch "qe: add function qe_clock_source".
The driver has been tested with a VoIP stack and application on
MPC8323ERDB.
With Regards
Poonam=20
=20
=20
^ permalink raw reply
* [PATCH 1/3] drivers/misc :UCC based TDM driver for MPC83xx platforms.
From: Poonam_Aggrwal-b10812 @ 2007-12-10 12:04 UTC (permalink / raw)
To: rubini, linux-kernel, linuxppc-dev, netdev, kumar.gala
Cc: michael.barkowski, rich.cutler, ashish.kalra
From: Poonam Aggrwal <b10812@freescale.com>
The UCC TDM driver basically multiplexes and demultiplexes data from
different channels. It can interface with for example SLIC kind of devices
to receive TDM data demultiplex it and send to upper applications. At the
transmit end it receives data for different channels multiplexes it and
sends them on the TDM channel. It internally uses TSA( Time Slot Assigner)
which does multiplexing and demultiplexing, UCC to perform SDMA between
host buffers and the TSA, CMX to connect TSA to UCC.
This driver will run on MPC8323E-RDB platforms.
Signed-off-by: Poonam Aggrwal <b10812@freescale.com>
Signed-off-by: Ashish Kalra <ashish.kalra@freescale.com>
Signed-off-by: Kim Phillips <Kim.Phillips@freescale.com>
Signed-off-by: Michael Barkowski <michael.barkowski@freescale.com>
---
drivers/misc/Kconfig | 21 +
drivers/misc/Makefile | 1 +
drivers/misc/ucc_tdm.c | 1068 ++++++++++++++++++++++++++++++++++++++++++++++++
drivers/misc/ucc_tdm.h | 227 ++++++++++
4 files changed, 1317 insertions(+), 0 deletions(-)
create mode 100644 drivers/misc/ucc_tdm.c
create mode 100644 drivers/misc/ucc_tdm.h
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index b5e67c0..698a72c 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -219,6 +219,27 @@ config THINKPAD_ACPI_BAY
If you are not sure, say Y here.
+config UCC_TDM
+ bool "Freescale UCC TDM Driver"
+ depends on QUICC_ENGINE && UCC_FAST
+ default n
+ ---help---
+ The TDM driver is for UCC based TDM devices for example, TDM device on
+ MPC832x RDB. Select it to run PowerVoIP on MPC832x RDB board.
+ The TDM driver can interface with SLIC kind of devices to transmit
+ and receive TDM samples. The TDM driver receives Time Division
+ multiplexed samples(for different channels) from the SLIC device,
+ demutiplexes them and sends them to the upper layers. At the transmit
+ end the TDM drivers receives samples for different channels, it
+ multiplexes them and sends them to the SLIC device.
+
+config TDM_LINEAR_PCM
+ bool "Linear PCM mode"
+ depends on UCC_TDM
+ ---help---
+ This mode should be selected if the TDM driver interface with the
+ SLIC device is linear PCM(e.g. 16 bit samples). If not selected the
+ interface will be 8 bit u-law.
config ATMEL_SSC
tristate "Device driver for Atmel SSC peripheral"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 87f2685..6f0c49d 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -17,3 +17,4 @@ obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o
obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
+obj-$(CONFIG_UCC_TDM) += ucc_tdm.o
diff --git a/drivers/misc/ucc_tdm.c b/drivers/misc/ucc_tdm.c
new file mode 100644
index 0000000..232d537
--- /dev/null
+++ b/drivers/misc/ucc_tdm.c
@@ -0,0 +1,1068 @@
+/*
+ * drivers/misc/ucc_tdm.c
+ *
+ * UCC Based Linux TDM Driver
+ * This driver is designed to support UCC based TDM for PowerPC processors.
+ * This driver can interface with SLIC device to run VOIP kind of
+ * applications.
+ *
+ * Author: Ashish Kalra & Poonam Aggrwal
+ *
+ * Copyright (c) 2007 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/autoconf.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/skbuff.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/string.h>
+#include <linux/irq.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/wait.h>
+#include <linux/timer.h>
+
+#include <asm/immap_qe.h>
+#include <asm/qe.h>
+#include <asm/ucc.h>
+#include <asm/ucc_fast.h>
+#include <asm/ucc_slow.h>
+
+#include "ucc_tdm.h"
+#define DRV_DESC "Freescale QE UCC TDM Driver"
+#define DRV_NAME "ucc_tdm"
+
+/*
+ * define the following #define if snooping or hardware-based cache coherency
+ * is disabled on the UCC transparent controller.This flag enables
+ * software-based cache-coherency support by explicitly flushing data cache
+ * contents after setting up the TDM output buffer(s) and invalidating the
+ * data cache contents before the TDM input buffer(s) are read.
+ */
+#undef UCC_CACHE_SNOOPING_DISABLED
+
+#define MAX_NUM_TDM_DEVICES 8
+
+static struct tdm_ctrl *tdm_ctrl[MAX_NUM_TDM_DEVICES];
+
+static int num_tdm_devices;
+static int num_tdm_clients;
+
+#define PREV_PHASE(x) ((x == 0) ? MAX_PHASE : (x - 1))
+#define NEXT_PHASE(x) (((x + 1) > MAX_PHASE) ? 0 : (x + 1))
+
+static struct ucc_tdm_info utdm_primary_info = {
+ .uf_info = {
+ .tsa = 1,
+ .cdp = 1,
+ .cds = 1,
+ .ctsp = 1,
+ .ctss = 1,
+ .revd = 1,
+ .urfs = 0x128,
+ .utfs = 0x128,
+ .utfet = 0,
+ .utftt = 0x128,
+ .ufpt = 256,
+ .ttx_trx = UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_TRANSPARENT,
+ .tenc = UCC_FAST_TX_ENCODING_NRZ,
+ .renc = UCC_FAST_RX_ENCODING_NRZ,
+ .tcrc = UCC_FAST_16_BIT_CRC,
+ .synl = UCC_FAST_SYNC_LEN_NOT_USED,
+ },
+ .ucc_busy = 0,
+};
+
+static struct ucc_tdm_info utdm_info[8];
+
+static void dump_siram(struct tdm_ctrl *tdm_c)
+{
+#if defined(DEBUG)
+ int i;
+ u16 phy_num_ts;
+
+ phy_num_ts = tdm_c->physical_num_ts;
+
+ pr_debug("SI TxRAM dump\n");
+ /* each slot entry in SI RAM is of 2 bytes */
+ for (i = 0; i < phy_num_ts * 2; i++)
+ pr_debug("%x ", in_8(&qe_immr->sir.tx[i]));
+ pr_debug("\nSI RxRAM dump\n");
+ for (i = 0; i < phy_num_ts * 2; i++)
+ pr_debug("%x ", in_8(&qe_immr->sir.rx[i]));
+ pr_debug("\n");
+#endif
+}
+
+static void dump_ucc(struct tdm_ctrl *tdm_c)
+{
+#if defined(DEBUG)
+ struct ucc_transparent_pram *ucc_pram;
+
+ ucc_pram = tdm_c->ucc_pram;
+
+ pr_debug("%s Dumping UCC Registers\n", __FUNCTION__);
+ ucc_fast_dump_regs(tdm_c->uf_private);
+ pr_debug("%s Dumping UCC Parameter RAM\n", __FUNCTION__);
+ pr_debug("rbase = 0x%x\n", in_be32(&ucc_pram->rbase));
+ pr_debug("rbptr = 0x%x\n", in_be32(&ucc_pram->rbptr));
+ pr_debug("mrblr = 0x%x\n", in_be16(&ucc_pram->mrblr));
+ pr_debug("rbdlen = 0x%x\n", in_be16(&ucc_pram->rbdlen));
+ pr_debug("rbdstat = 0x%x\n", in_be16(&ucc_pram->rbdstat));
+ pr_debug("rstate = 0x%x\n", in_be32(&ucc_pram->rstate));
+ pr_debug("rdptr = 0x%x\n", in_be32(&ucc_pram->rdptr));
+ pr_debug("tbase = 0x%x\n", in_be32(&ucc_pram->tbase));
+ pr_debug("tbptr = 0x%x\n", in_be32(&ucc_pram->tbptr));
+ pr_debug("tbdlen = 0x%x\n", in_be16(&ucc_pram->tbdlen));
+ pr_debug("tbdstat = 0x%x\n", in_be16(&ucc_pram->tbdstat));
+ pr_debug("tstate = 0x%x\n", in_be32(&ucc_pram->tstate));
+ pr_debug("tdptr = 0x%x\n", in_be32(&ucc_pram->tdptr));
+#endif
+}
+/*
+ * converts u-law compressed samples to linear PCM
+ * If the CONFIG_TDM_LINEAR_PCM flag is not set the
+ * TDM driver receives u-law compressed data from the
+ * SLIC device. This function converts the compressed
+ * data to linear PCM and sends it to upper layers.
+ */
+static inline int ulaw2int(unsigned char log)
+{
+ u32 sign, segment, temp, quant;
+ int val;
+
+ temp = log ^ 0xFF;
+ sign = (temp & 0x80) >> 7;
+ segment = (temp & 0x70) >> 4;
+ quant = temp & 0x0F;
+ quant <<= 1;
+ quant += 33;
+ quant <<= segment;
+ if (sign)
+ val = 33 - quant;
+ else
+ val = quant - 33;
+
+ val *= 4;
+ return val;
+}
+
+/*
+ * converts linear PCM samples to u-law compressed format.
+ * If the CONFIG_TDM_LINEAR_PCM flag is not set the
+ * TDM driver calls this function to convert the PCM samples
+ * to u-law compressed format before sending them to SLIC
+ * device.
+ */
+static inline u8 int2ulaw(short linear)
+{
+ u8 quant, ret;
+ u16 output, absol, temp;
+ u32 i, sign;
+ char segment;
+
+ ret = 0;
+ if (linear >= 0)
+ linear = (linear >> 2);
+ else
+ linear = (0xc000 | (linear >> 2));
+
+ absol = abs(linear) + 33;
+ temp = absol;
+ sign = (linear >= 0) ? 1 : 0;
+ for (i = 0; i < 16; i++) {
+ output = temp & 0x8000;
+ if (output)
+ break;
+ temp <<= 1;
+ }
+ segment = 11 - i;
+ quant = (absol >> segment) & 0x0F;
+ segment--;
+ segment <<= 4;
+ output = segment + quant;
+ if (absol > 8191)
+ output = 0x7F;
+ if (sign)
+ ret ^= 0xFF;
+ else
+ ret ^= 0x7F;
+ return ret;
+}
+
+/*
+ * For use when a framing bit is not present
+ * Program current-route SI ram
+ * Set SIxRAM TDMx
+ * Entries must be in units of 8.
+ * SIR_UCC -> Channel Select
+ * SIR_CNT -> Number of bits or bytes
+ * SIR_BYTE -> Byte or Bit resolution
+ * SIR_LAST -> Indicates last entry in SIxRAM
+ * SIR_IDLE -> The Tx data pin is Tri-stated and the Rx data pin is
+ * ignored
+ */
+static void set_siram(struct tdm_ctrl *tdm_c, enum comm_dir dir)
+{
+ const u16 *mask;
+ u16 temp_mask = 1;
+ u16 siram_code = 0;
+ u32 i, j, k;
+ u32 ucc;
+ u32 phy_num_ts;
+
+ phy_num_ts = tdm_c->physical_num_ts;
+ ucc = tdm_c->ut_info->uf_info.ucc_num;
+
+ if (dir == COMM_DIR_RX)
+ mask = tdm_c->rx_mask;
+ else
+ mask = tdm_c->tx_mask;
+ k = 0;
+ j = 0;
+ for (i = 0; i < phy_num_ts; i++) {
+ if ((mask[k] & temp_mask) == temp_mask)
+ siram_code = SIR_UCC(ucc) | SIR_CNT(0) | SIR_BYTE;
+ else
+ siram_code = SIR_IDLE | SIR_CNT(0) | SIR_BYTE;
+ if (dir == COMM_DIR_RX)
+ SET_RX_SI_RAM(i, siram_code);
+ else
+ SET_TX_SI_RAM(i, siram_code);
+ temp_mask = temp_mask << 1;
+ j++;
+ if (j >= 16) {
+ j = 0;
+ temp_mask = 0x0001;
+ k++;
+ }
+ }
+ siram_code = siram_code | SIR_LAST;
+
+ if (dir == COMM_DIR_RX)
+ SET_RX_SI_RAM(phy_num_ts - 1, siram_code);
+ else
+ SET_TX_SI_RAM(phy_num_ts - 1, siram_code);
+}
+
+static void config_si(struct tdm_ctrl *tdm_c)
+{
+ u8 rxsyncdelay, txsyncdelay, tdm_port;
+ u16 sixmr_val = 0;
+ u32 tdma_mode_off;
+ u16 *si1_tdm_mode_reg;
+
+ tdm_port = tdm_c->tdm_port;
+
+ set_siram(tdm_c, COMM_DIR_RX);
+
+ set_siram(tdm_c, COMM_DIR_TX);
+
+ rxsyncdelay = tdm_c->cfg_ctrl.rx_fr_sync_delay;
+ txsyncdelay = tdm_c->cfg_ctrl.tx_fr_sync_delay;
+ if (tdm_c->cfg_ctrl.com_pin)
+ sixmr_val |= SIMODE_CRT;
+ if (tdm_c->cfg_ctrl.fr_sync_level == 1)
+ sixmr_val |= SIMODE_SL;
+ if (tdm_c->cfg_ctrl.clk_edge == 1)
+ sixmr_val |= SIMODE_CE;
+ if (tdm_c->cfg_ctrl.fr_sync_edge == 1)
+ sixmr_val |= SIMODE_FE;
+ sixmr_val |= (SIMODE_TFSD(txsyncdelay) | SIMODE_RFSD(rxsyncdelay));
+
+ tdma_mode_off = SI_TDM_MODE_REGISTER_OFFSET * tdm_c->tdm_port;
+
+ si1_tdm_mode_reg = (u8 *)&qe_immr->si1 + tdma_mode_off;
+ out_be16(si1_tdm_mode_reg, sixmr_val);
+
+ dump_siram(tdm_c);
+}
+
+static int tdm_init(struct tdm_ctrl *tdm_c)
+{
+ u32 tdm_port, ucc, act_num_ts;
+ int ret, i, err;
+ u32 cecr_subblock;
+ u32 pram_offset;
+ u32 rxbdt_offset;
+ u32 txbdt_offset;
+ u32 rx_ucode_buf_offset, tx_ucode_buf_offset;
+ u16 bd_status, bd_len;
+ enum qe_clock clock;
+ struct qe_bd __iomem *rx_bd, *tx_bd;
+
+ tdm_port = tdm_c->tdm_port;
+ ucc = tdm_c->ut_info->uf_info.ucc_num;
+ act_num_ts = tdm_c->cfg_ctrl.active_num_ts;
+
+ /*
+ * TDM Tx and Rx CLKs = 2048 KHz.
+ */
+ if (strstr(tdm_c->ut_info->uf_info.tdm_tx_clk, "BRG")) {
+ clock = qe_clock_source(tdm_c->ut_info->uf_info.tdm_tx_clk);
+ err = qe_setbrg(clock, 2048000, 1);
+ if (err < 0) {
+ printk(KERN_ERR "%s: Failed to set %s\n", __FUNCTION__,
+ tdm_c->ut_info->uf_info.tdm_tx_clk);
+ return err;
+ }
+ }
+ if (strstr(tdm_c->ut_info->uf_info.tdm_rx_clk, "BRG")) {
+ clock = qe_clock_source(tdm_c->ut_info->uf_info.tdm_rx_clk);
+ err = qe_setbrg(clock, 2048000, 1);
+ if (err < 0) {
+ printk(KERN_ERR "%s: Failed to set %s\n", __FUNCTION__,
+ tdm_c->ut_info->uf_info.tdm_rx_clk);
+ return err;
+ }
+ }
+ /*
+ * TDM FSyncs = 4 KHz.
+ */
+ if (strstr(tdm_c->ut_info->uf_info.tdm_tx_sync, "BRG")) {
+ clock = qe_clock_source(tdm_c->ut_info->uf_info.tdm_tx_sync);
+ err = qe_setbrg(clock, 4000, 1);
+ if (err < 0) {
+ printk(KERN_ERR "%s: Failed to set %s\n", __FUNCTION__,
+ tdm_c->ut_info->uf_info.tdm_tx_sync);
+ return err;
+ }
+ }
+ if (strstr(tdm_c->ut_info->uf_info.tdm_rx_sync, "BRG")) {
+ clock = qe_clock_source(tdm_c->ut_info->uf_info.tdm_rx_sync);
+ err = qe_setbrg(clock, 4000, 1);
+ if (err < 0) {
+ printk(KERN_ERR "%s: Failed to set %s\n", __FUNCTION__,
+ tdm_c->ut_info->uf_info.tdm_rx_sync);
+ return err;
+ }
+ }
+
+ tdm_c->ut_info->uf_info.uccm_mask = (u32)
+ ((UCC_TRANS_UCCE_RXB | UCC_TRANS_UCCE_BSY) << 16);
+
+ if (ucc_fast_init(&(tdm_c->ut_info->uf_info), &tdm_c->uf_private)) {
+ printk(KERN_ERR "%s: Failed to init uccf\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+
+ ucc_fast_disable(tdm_c->uf_private, COMM_DIR_RX | COMM_DIR_TX);
+
+ /* Write to QE CECR, UCCx channel to Stop Transmission */
+ cecr_subblock = ucc_fast_get_qe_cr_subblock(ucc);
+ qe_issue_cmd(QE_STOP_TX, cecr_subblock,
+ (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0);
+
+ pram_offset = qe_muram_alloc(UCC_TRANSPARENT_PRAM_SIZE,
+ ALIGNMENT_OF_UCC_SLOW_PRAM);
+ if (IS_ERR_VALUE(pram_offset)) {
+ printk(KERN_ERR "%s: Cannot allocate MURAM memory for"
+ " transparent UCC\n", __FUNCTION__);
+ ret = -ENOMEM;
+ goto pram_alloc_error;
+ }
+
+ cecr_subblock = ucc_fast_get_qe_cr_subblock(ucc);
+ qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, cecr_subblock,
+ QE_CR_PROTOCOL_UNSPECIFIED, pram_offset);
+
+ tdm_c->ucc_pram = qe_muram_addr(pram_offset);
+ tdm_c->ucc_pram_offset = pram_offset;
+
+ /*
+ * zero-out pram, this will also ensure RSTATE, TSTATE are cleared, also
+ * DISFC & CRCEC counters will be initialized.
+ */
+ memset(tdm_c->ucc_pram, 0, sizeof(struct ucc_transparent_pram));
+
+ /* rbase, tbase alignment is 8. */
+ rxbdt_offset = qe_muram_alloc(NR_BUFS * sizeof(struct qe_bd),
+ QE_ALIGNMENT_OF_BD);
+ if (IS_ERR_VALUE(rxbdt_offset)) {
+ printk(KERN_ERR "%s: Cannot allocate MURAM memory for RxBDs\n",
+ __FUNCTION__);
+ ret = -ENOMEM;
+ goto rxbd_alloc_error;
+ }
+ txbdt_offset = qe_muram_alloc(NR_BUFS * sizeof(struct qe_bd),
+ QE_ALIGNMENT_OF_BD);
+ if (IS_ERR_VALUE(txbdt_offset)) {
+ printk(KERN_ERR "%s: Cannot allocate MURAM memory for TxBDs\n",
+ __FUNCTION__);
+ ret = -ENOMEM;
+ goto txbd_alloc_error;
+ }
+ tdm_c->tx_bd = qe_muram_addr(txbdt_offset);
+ tdm_c->rx_bd = qe_muram_addr(rxbdt_offset);
+
+ tdm_c->tx_bd_offset = txbdt_offset;
+ tdm_c->rx_bd_offset = rxbdt_offset;
+
+ rx_bd = tdm_c->rx_bd;
+ tx_bd = tdm_c->tx_bd;
+
+ out_be32(&tdm_c->ucc_pram->rbase, (u32) immrbar_virt_to_phys(rx_bd));
+ out_be32(&tdm_c->ucc_pram->tbase, (u32) immrbar_virt_to_phys(tx_bd));
+
+ for (i = 0; i < NR_BUFS - 1; i++) {
+ bd_status = (u16) ((R_E | R_CM | R_I) >> 16);
+ bd_len = 0;
+ out_be16(&rx_bd->length, bd_len);
+ out_be16(&rx_bd->status, bd_status);
+ out_be32(&rx_bd->buf,
+ tdm_c->dma_input_addr + i * SAMPLE_DEPTH * act_num_ts);
+ rx_bd += 1;
+
+ bd_status = (u16) ((T_R | T_CM) >> 16);
+ bd_len = SAMPLE_DEPTH * act_num_ts;
+ out_be16(&tx_bd->length, bd_len);
+ out_be16(&tx_bd->status, bd_status);
+ out_be32(&tx_bd->buf,
+ tdm_c->dma_output_addr + i * SAMPLE_DEPTH * act_num_ts);
+ tx_bd += 1;
+ }
+
+ bd_status = (u16) ((R_E | R_CM | R_I | R_W) >> 16);
+ bd_len = 0;
+ out_be16(&rx_bd->length, bd_len);
+ out_be16(&rx_bd->status, bd_status);
+ out_be32(&rx_bd->buf,
+ tdm_c->dma_input_addr + i * SAMPLE_DEPTH * act_num_ts);
+
+ bd_status = (u16) ((T_R | T_CM | T_W) >> 16);
+ bd_len = SAMPLE_DEPTH * act_num_ts;
+ out_be16(&tx_bd->length, bd_len);
+ out_be16(&tx_bd->status, bd_status);
+ out_be32(&tx_bd->buf,
+ tdm_c->dma_output_addr + i * SAMPLE_DEPTH * act_num_ts);
+
+ config_si(tdm_c);
+
+ setbits32(&qe_immr->ic.qimr, (0x80000000 >> ucc));
+
+ rx_ucode_buf_offset = qe_muram_alloc(32, 32);
+ if (IS_ERR_VALUE(rx_ucode_buf_offset)) {
+ printk(KERN_ERR "%s: Cannot allocate MURAM mem for Rx"
+ " ucode buf\n", __FUNCTION__);
+ ret = -ENOMEM;
+ goto rxucode_buf_alloc_error;
+ }
+
+ tx_ucode_buf_offset = qe_muram_alloc(32, 32);
+ if (IS_ERR_VALUE(tx_ucode_buf_offset)) {
+ printk(KERN_ERR "%s: Cannot allocate MURAM mem for Tx"
+ " ucode buf\n", __FUNCTION__);
+ ret = -ENOMEM;
+ goto txucode_buf_alloc_error;
+ }
+ out_be16(&tdm_c->ucc_pram->riptr, (u16) rx_ucode_buf_offset);
+ out_be16(&tdm_c->ucc_pram->tiptr, (u16) tx_ucode_buf_offset);
+
+ tdm_c->rx_ucode_buf_offset = rx_ucode_buf_offset;
+ tdm_c->tx_ucode_buf_offset = tx_ucode_buf_offset;
+
+ /*
+ * set the receive buffer descriptor maximum size to be
+ * SAMPLE_DEPTH * number of active RX channels
+ */
+ out_be16(&tdm_c->ucc_pram->mrblr, (u16) SAMPLE_DEPTH * act_num_ts);
+
+ /*
+ * enable snooping and BE byte ordering on the UCC pram's
+ * tstate & rstate registers.
+ */
+ out_be32(&tdm_c->ucc_pram->tstate, 0x30000000);
+ out_be32(&tdm_c->ucc_pram->rstate, 0x30000000);
+
+ /*Put UCC transparent controller into serial interface mode. */
+ out_be32(&tdm_c->uf_regs->upsmr, 0);
+
+ /* Reset TX and RX for UCCx */
+ cecr_subblock = ucc_fast_get_qe_cr_subblock(ucc);
+ qe_issue_cmd(QE_INIT_TX_RX, cecr_subblock,
+ (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0);
+
+ return 0;
+
+txucode_buf_alloc_error:
+ qe_muram_free(rx_ucode_buf_offset);
+rxucode_buf_alloc_error:
+ qe_muram_free(txbdt_offset);
+txbd_alloc_error:
+ qe_muram_free(rxbdt_offset);
+rxbd_alloc_error:
+ qe_muram_free(pram_offset);
+pram_alloc_error:
+ ucc_fast_free(tdm_c->uf_private);
+ return ret;
+}
+
+static void tdm_deinit(struct tdm_ctrl *tdm_c)
+{
+ qe_muram_free(tdm_c->rx_ucode_buf_offset);
+ qe_muram_free(tdm_c->tx_ucode_buf_offset);
+
+ if (tdm_c->rx_bd_offset) {
+ qe_muram_free(tdm_c->rx_bd_offset);
+ tdm_c->rx_bd = NULL;
+ tdm_c->rx_bd_offset = 0;
+ }
+ if (tdm_c->tx_bd_offset) {
+ qe_muram_free(tdm_c->tx_bd_offset);
+ tdm_c->tx_bd = NULL;
+ tdm_c->tx_bd_offset = 0;
+ }
+ if (tdm_c->ucc_pram_offset) {
+ qe_muram_free(tdm_c->ucc_pram_offset);
+ tdm_c->ucc_pram = NULL;
+ tdm_c->ucc_pram_offset = 0;
+ }
+}
+
+
+static irqreturn_t tdm_isr(int irq, void *dev_id)
+{
+ u8 *input_tdm_buffer, *output_tdm_buffer;
+ u32 txb, rxb;
+ u32 ucc;
+ register u32 ucce = 0;
+ struct tdm_ctrl *tdm_c;
+ tdm_c = (struct tdm_ctrl *)dev_id;
+
+ tdm_c->tdm_icnt++;
+ ucc = tdm_c->ut_info->uf_info.ucc_num;
+ input_tdm_buffer = tdm_c->tdm_input_data;
+ output_tdm_buffer = tdm_c->tdm_output_data;
+
+ if (in_be32(tdm_c->uf_private->p_ucce) &
+ (UCC_TRANS_UCCE_BSY << 16)) {
+ out_be32(tdm_c->uf_private->p_ucce,
+ (UCC_TRANS_UCCE_BSY << 16));
+ pr_info("%s: From tdm isr busy interrupt\n",
+ __FUNCTION__);
+ dump_ucc(tdm_c);
+
+ return IRQ_HANDLED;
+ }
+
+ if (tdm_c->tdm_flag == 1) {
+ /* track phases for Rx/Tx */
+ tdm_c->phase_rx = NEXT_PHASE(tdm_c->phase_rx);
+ tdm_c->phase_tx = NEXT_PHASE(tdm_c->phase_tx);
+#if defined(CONFIG_TDM_HW_LB_TSA_SLIC)
+ {
+ u32 temp_rx, temp_tx, phase_tx, phase_rx;
+ int i;
+ phase_rx = tdm_c->phase_rx;
+ phase_tx = tdm_c->phase_tx;
+ phase_rx = PREV_PHASE(phase_rx);
+ phase_tx = PREV_PHASE(phase_tx);
+ temp_rx = phase_rx * SAMPLE_DEPTH * ACTIVE_CH;
+ temp_tx = phase_tx * SAMPLE_DEPTH * ACTIVE_CH;
+
+ /*check if loopback received data on TS0 is correct. */
+ pr_debug("%s: check if loopback received data on TS0"
+ " is correct\n", __FUNCTION__);
+ pr_debug("%d,%d ", phase_rx, phase_tx);
+ for (i = 0; i < 8; i++)
+ pr_debug("%1d,%1d ",
+ input_tdm_buffer[temp_rx + i],
+ output_tdm_buffer[temp_tx + i]);
+ pr_debug("\n");
+ }
+#endif
+
+ /* schedule BH */
+ wake_up_interruptible(&tdm_c->wakeup_event);
+ } else {
+ if (tdm_c->tdm_icnt == STUTTER_INT_CNT) {
+ txb = in_be32(&tdm_c->ucc_pram->tbptr) -
+ in_be32(&tdm_c->ucc_pram->tbase);
+ rxb = in_be32(&tdm_c->ucc_pram->rbptr) -
+ in_be32(&tdm_c->ucc_pram->rbase);
+ tdm_c->phase_tx = txb / sizeof(struct qe_bd);
+ tdm_c->phase_rx = rxb / sizeof(struct qe_bd);
+
+#if defined(CONFIG_TDM_HW_LB_TSA_SLIC)
+ tdm_c->phase_tx = tdm_c->phase_rx;
+#endif
+
+ /* signal "stuttering" period is over */
+ tdm_c->tdm_flag = 1;
+
+ pr_debug("%s: stuttering period is over\n",
+ __FUNCTION__);
+
+ if (in_be32(tdm_c->uf_private->p_ucce) &
+ (UCC_TRANS_UCCE_TXE << 16)) {
+ u32 cecr_subblock;
+ out_be32(tdm_c->uf_private->p_ucce,
+ (UCC_TRANS_UCCE_TXE << 16));
+ pr_debug("%s: From tdm isr txe interrupt\n",
+ __FUNCTION__);
+
+ cecr_subblock =
+ ucc_fast_get_qe_cr_subblock(ucc);
+ qe_issue_cmd(QE_RESTART_TX, cecr_subblock,
+ (u8) QE_CR_PROTOCOL_UNSPECIFIED,
+ 0);
+ }
+ }
+ }
+
+ ucce = (in_be32(tdm_c->uf_private->p_ucce)
+ & in_be32(tdm_c->uf_private->p_uccm));
+
+ out_be32(tdm_c->uf_private->p_ucce, ucce);
+
+ return IRQ_HANDLED;
+}
+
+static int tdm_start(struct tdm_ctrl *tdm_c)
+{
+ if (request_irq(tdm_c->ut_info->uf_info.irq, tdm_isr,
+ 0, "tdm", tdm_c)) {
+ printk(KERN_ERR "%s: request_irq for tdm_isr failed\n",
+ __FUNCTION__);
+ return -ENODEV;
+ }
+
+ ucc_fast_enable(tdm_c->uf_private, COMM_DIR_RX | COMM_DIR_TX);
+
+#if !defined(CONFIG_TDM_LINEAR_PCM)
+ pr_info("%s 8-bit u-law compressed mode active\n", __FUNCTION__);
+#else
+ pr_info("%s 16-bit linear pcm mode active with"
+ " slots 0 & 2\n", __FUNCTION__);
+#endif
+
+ dump_siram(tdm_c);
+ dump_ucc(tdm_c);
+
+ setbits8(&(qe_immr->si1.siglmr1_h), (0x1 << tdm_c->tdm_port));
+ pr_info("%s UCC based TDM enabled\n", __FUNCTION__);
+
+ return 0;
+}
+
+static void tdm_stop(struct tdm_ctrl *tdm_c)
+{
+ u32 port, si;
+ u32 ucc;
+ u32 cecr_subblock;
+
+ port = tdm_c->tdm_port;
+ si = tdm_c->si;
+ ucc = tdm_c->ut_info->uf_info.ucc_num;
+ cecr_subblock = ucc_fast_get_qe_cr_subblock(ucc);
+
+ qe_issue_cmd(QE_GRACEFUL_STOP_TX, cecr_subblock,
+ (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0);
+ qe_issue_cmd(QE_CLOSE_RX_BD, cecr_subblock,
+ (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0);
+
+ clrbits8(&qe_immr->si1.siglmr1_h, (0x1 << port));
+ ucc_fast_disable(tdm_c->uf_private, COMM_DIR_RX);
+ ucc_fast_disable(tdm_c->uf_private, COMM_DIR_TX);
+ free_irq(tdm_c->ut_info->uf_info.irq, tdm_c);
+}
+
+
+static void config_tdm(struct tdm_ctrl *tdm_c)
+{
+ u32 i, j, k;
+
+ j = 0;
+ k = 0;
+
+ /* Set Mask Bits */
+ for (i = 0; i < ACTIVE_CH; i++) {
+ tdm_c->tx_mask[k] |= (1 << j);
+ tdm_c->rx_mask[k] |= (1 << j);
+ j++;
+ if (j >= 16) {
+ j = 0;
+ k++;
+ }
+ }
+ /* physical number of slots in a frame */
+ tdm_c->physical_num_ts = NUM_TS;
+
+ /* common receive and transmit pins */
+ tdm_c->cfg_ctrl.com_pin = 1;
+
+ /* L1R/TSYNC active logic "1" */
+ tdm_c->cfg_ctrl.fr_sync_level = 0;
+
+ /*
+ * TX data on rising edge of clock
+ * RX data on falling edge
+ */
+ tdm_c->cfg_ctrl.clk_edge = 0;
+
+ /* Frame sync sampled on falling edge */
+ tdm_c->cfg_ctrl.fr_sync_edge = 0;
+
+ /* no bit delay */
+ tdm_c->cfg_ctrl.rx_fr_sync_delay = 0;
+
+ /* no bit delay */
+ tdm_c->cfg_ctrl.tx_fr_sync_delay = 0;
+
+#if !defined(CONFIG_TDM_HW_LB_TSA_SLIC)
+ if (tdm_c->leg_slic) {
+ /* Need 1 bit delay for Legrity SLIC */
+ tdm_c->cfg_ctrl.rx_fr_sync_delay = 1;
+ tdm_c->cfg_ctrl.tx_fr_sync_delay = 1;
+ pr_info("%s Delay for Legerity!\n", __FUNCTION__);
+ }
+#endif
+
+ tdm_c->cfg_ctrl.active_num_ts = ACTIVE_CH;
+}
+
+static void tdm_read(u32 driver_handle, short chn_id, short *pcm_buffer,
+ short len)
+{
+ int i;
+ u32 phase_rx;
+ /* point to where to start for the current phase data processing */
+ u32 temp_rx;
+
+ struct tdm_ctrl *tdm_c = (struct tdm_ctrl *)(driver_handle);
+
+#if !defined(CONFIG_TDM_LINEAR_PCM)
+ u8 *input_tdm_buffer = tdm_c->tdm_input_data;
+
+#else
+ u16 *input_tdm_buffer =
+ (u16 *)tdm_c->tdm_input_data;
+
+#endif
+ phase_rx = tdm_c->phase_rx;
+ phase_rx = PREV_PHASE(phase_rx);
+
+ temp_rx = phase_rx * SAMPLE_DEPTH * EFF_ACTIVE_CH;
+
+#if defined(UCC_CACHE_SNOOPING_DISABLED)
+ flush_dcache_range((size_t) &input_tdm_buffer[temp_rx],
+ (size_t) &input_tdm_buffer[temp_rx +
+ SAMPLE_DEPTH * ACTIVE_CH]);
+#endif
+ for (i = 0; i < len; i++) {
+#if !defined(CONFIG_TDM_LINEAR_PCM)
+ pcm_buffer[i] =
+ ulaw2int(input_tdm_buffer[i * EFF_ACTIVE_CH +
+ temp_rx + chn_id]);
+#else
+ pcm_buffer[i] =
+ input_tdm_buffer[i * EFF_ACTIVE_CH + temp_rx + chn_id];
+#endif
+
+ }
+
+}
+
+static void tdm_write(u32 driver_handle, short chn_id, short *pcm_buffer,
+ short len)
+{
+ int i;
+ int phase_tx;
+ u32 txb;
+ /* point to where to start for the current phase data processing */
+ int temp_tx;
+ struct tdm_ctrl *tdm_c = (struct tdm_ctrl *)(driver_handle);
+
+#if !defined(CONFIG_TDM_LINEAR_PCM)
+ u8 *output_tdm_buffer;
+ output_tdm_buffer = tdm_c->tdm_output_data;
+#else
+ u16 *output_tdm_buffer;
+ output_tdm_buffer = (u16 *)tdm_c->tdm_output_data;
+#endif
+ txb = in_be32(&tdm_c->ucc_pram->tbptr) -
+ in_be32(&tdm_c->ucc_pram->tbase);
+ phase_tx = txb / sizeof(struct qe_bd);
+
+ phase_tx = PREV_PHASE(phase_tx);
+
+ temp_tx = phase_tx * SAMPLE_DEPTH * EFF_ACTIVE_CH;
+
+ for (i = 0; i < len; i++) {
+#if !defined(CONFIG_TDM_LINEAR_PCM)
+ output_tdm_buffer[i * EFF_ACTIVE_CH + temp_tx + chn_id] =
+ int2ulaw(pcm_buffer[i]);
+#else
+ output_tdm_buffer[i * EFF_ACTIVE_CH + temp_tx + chn_id] =
+ pcm_buffer[i];
+#endif
+ }
+
+#if defined(UCC_CACHE_SNOOPING_DISABLED)
+ flush_dcache_range((size_t) &output_tdm_buffer[temp_tx],
+ (size_t) &output_tdm_buffer[temp_tx + SAMPLE_DEPTH *
+ ACTIVE_CH]);
+#endif
+}
+
+
+static int tdm_register_client(struct tdm_client *tdm_client)
+{
+ if (num_tdm_clients == num_tdm_devices) {
+ printk(KERN_ERR "all TDM devices busy\n");
+ return -EBUSY;
+ }
+
+ num_tdm_clients++;
+ tdm_client->driver_handle = (u32)(tdm_ctrl[num_tdm_clients - 1]);
+ tdm_client->tdm_read = tdm_read;
+ tdm_client->tdm_write = tdm_write;
+ tdm_client->wakeup_event =
+ &(tdm_ctrl[num_tdm_clients - 1]->wakeup_event);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tdm_register_client);
+
+static int tdm_deregister_client(struct tdm_client *tdm_client)
+{
+ num_tdm_clients--;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tdm_deregister_client);
+
+static int ucc_tdm_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device_node *np = ofdev->node;
+ struct resource res;
+ const unsigned int *prop;
+ u32 ucc_num, device_num, err, ret = 0;
+ struct device_node *np_tmp = NULL;
+ dma_addr_t physaddr;
+ void *tdm_buff;
+ struct ucc_tdm_info *ut_info;
+
+ prop = of_get_property(np, "device-id", NULL);
+ ucc_num = *prop - 1;
+ if ((ucc_num < 0) || (ucc_num > 7))
+ return -ENODEV;
+
+ ut_info = &utdm_info[ucc_num];
+ if (ut_info == NULL) {
+ printk(KERN_ERR "additional data missing\n");
+ return -ENODEV;
+ }
+ if (ut_info->ucc_busy) {
+ printk(KERN_ERR "UCC in use by another TDM driver instance\n");
+ return -EBUSY;
+ }
+
+ ut_info->ucc_busy = 1;
+ tdm_ctrl[num_tdm_devices++] =
+ kzalloc(sizeof(struct tdm_ctrl), GFP_KERNEL);
+ if (!tdm_ctrl[num_tdm_devices - 1]) {
+ printk(KERN_ERR "%s: no memory to allocate for"
+ " tdm control structure\n", __FUNCTION__);
+ num_tdm_devices--;
+ return -ENOMEM;
+ }
+ device_num = num_tdm_devices - 1;
+
+ tdm_ctrl[device_num]->device = &ofdev->dev;
+ tdm_ctrl[device_num]->ut_info = ut_info;
+
+ tdm_ctrl[device_num]->ut_info->uf_info.ucc_num = ucc_num;
+
+ prop = of_get_property(np, "fsl,tdm-num", NULL);
+ if (prop == NULL) {
+ ret = -EINVAL;
+ goto get_property_error;
+ }
+
+ tdm_ctrl[device_num]->tdm_port = *prop - 1;
+
+ if (tdm_ctrl[device_num]->tdm_port > 3) {
+ ret = -EINVAL;
+ goto get_property_error;
+ }
+
+ prop = of_get_property(np, "fsl,si-num", NULL);
+ if (prop == NULL) {
+ ret = -EINVAL;
+ goto get_property_error;
+ }
+
+ tdm_ctrl[device_num]->si = *prop - 1;
+
+ tdm_ctrl[device_num]->ut_info->uf_info.tdm_tx_clk =
+ (char *) of_get_property(np, "fsl,tdm-tx-clk", NULL);
+ if (tdm_ctrl[device_num]->ut_info->uf_info.tdm_tx_clk == NULL) {
+ ret = -EINVAL;
+ goto get_property_error;
+ }
+
+ tdm_ctrl[device_num]->ut_info->uf_info.tdm_rx_clk =
+ (char *) of_get_property(np, "fsl,tdm-rx-clk", NULL);
+ if (tdm_ctrl[device_num]->ut_info->uf_info.tdm_rx_clk == NULL) {
+ ret = -EINVAL;
+ goto get_property_error;
+ }
+
+ tdm_ctrl[device_num]->ut_info->uf_info.tdm_tx_sync =
+ (char *) of_get_property(np, "fsl,tdm-tx-sync", NULL);
+ if (tdm_ctrl[device_num]->ut_info->uf_info.tdm_tx_sync == NULL) {
+ ret = -EINVAL;
+ goto get_property_error;
+ }
+
+ tdm_ctrl[device_num]->ut_info->uf_info.tdm_rx_sync =
+ (char *) of_get_property(np, "fsl,tdm-rx-sync", NULL);
+ if (tdm_ctrl[device_num]->ut_info->uf_info.tdm_rx_sync == NULL) {
+ ret = -EINVAL;
+ goto get_property_error;
+ }
+
+ tdm_ctrl[device_num]->ut_info->uf_info.irq =
+ irq_of_parse_and_map(np, 0);
+ err = of_address_to_resource(np, 0, &res);
+ if (err) {
+ ret = EINVAL;
+ goto get_property_error;
+ }
+ tdm_ctrl[device_num]->ut_info->uf_info.regs = res.start;
+ tdm_ctrl[device_num]->uf_regs = of_iomap(np, 0);
+
+ np_tmp = of_find_compatible_node(np_tmp, "slic", "legerity-slic");
+ if (np_tmp != NULL)
+ tdm_ctrl[device_num]->leg_slic = 1;
+ else
+ tdm_ctrl[device_num]->leg_slic = 0;
+
+ config_tdm(tdm_ctrl[device_num]);
+
+ tdm_buff = dma_alloc_coherent(NULL, 2 * NR_BUFS * SAMPLE_DEPTH *
+ tdm_ctrl[device_num]->cfg_ctrl.active_num_ts,
+ &physaddr, GFP_KERNEL);
+ if (!tdm_buff) {
+ printk(KERN_ERR "ucc-tdm: could not allocate buffer"
+ "descriptors\n");
+ ret = -ENOMEM;
+ goto get_property_error;
+ }
+
+ tdm_ctrl[device_num]->tdm_input_data = tdm_buff;
+ tdm_ctrl[device_num]->dma_input_addr = physaddr;
+
+ tdm_ctrl[device_num]->tdm_output_data = tdm_buff + NR_BUFS *
+ SAMPLE_DEPTH * tdm_ctrl[device_num]->cfg_ctrl.active_num_ts;
+ tdm_ctrl[device_num]->dma_output_addr = physaddr + NR_BUFS *
+ SAMPLE_DEPTH * tdm_ctrl[device_num]->cfg_ctrl.active_num_ts;
+
+ init_waitqueue_head(&(tdm_ctrl[device_num]->wakeup_event));
+
+ ret = tdm_init(tdm_ctrl[device_num]);
+ if (ret != 0)
+ goto tdm_init_error;
+
+ ret = tdm_start(tdm_ctrl[device_num]);
+ if (ret != 0)
+ goto tdm_start_error;
+
+ dev_set_drvdata(&(ofdev->dev), tdm_ctrl[device_num]);
+
+ pr_info("%s UCC based tdm module installed\n", __FUNCTION__);
+ return 0;
+
+tdm_start_error:
+ tdm_deinit(tdm_ctrl[device_num]);
+tdm_init_error:
+ dma_free_coherent(NULL, 2 * NR_BUFS * SAMPLE_DEPTH *
+ tdm_ctrl[device_num]->cfg_ctrl.active_num_ts,
+ tdm_ctrl[device_num]->tdm_input_data,
+ tdm_ctrl[device_num]->dma_input_addr);
+
+get_property_error:
+ kfree(tdm_ctrl[device_num]);
+ return ret;
+}
+
+static int ucc_tdm_remove(struct of_device *ofdev)
+{
+ struct tdm_ctrl *tdm_c;
+ struct ucc_tdm_info *ut_info;
+ u32 ucc_num;
+
+ tdm_c = dev_get_drvdata(&(ofdev->dev));
+ ucc_num = tdm_c->ut_info->uf_info.ucc_num;
+ ut_info = &utdm_info[ucc_num];
+ tdm_stop(tdm_c);
+ tdm_deinit(tdm_c);
+
+ ucc_fast_free(tdm_c->uf_private);
+
+ dma_free_coherent(NULL, 2 * NR_BUFS * SAMPLE_DEPTH *
+ tdm_c->cfg_ctrl.active_num_ts,
+ tdm_c->tdm_input_data,
+ tdm_c->dma_input_addr);
+
+ num_tdm_devices--;
+ kfree(tdm_c);
+
+ ut_info->ucc_busy = 0;
+
+ pr_info("%s UCC based tdm module uninstalled\n", __FUNCTION__);
+ return 0;
+}
+
+static struct of_device_id ucc_tdm_match[] = {
+ {
+ .type = "tdm",
+ .compatible = "fsl,ucc-tdm",
+ }, {},
+};
+
+MODULE_DEVICE_TABLE(of, ucc_tdm_match);
+
+static struct of_platform_driver ucc_tdm_driver = {
+ .name = DRV_NAME,
+ .match_table = ucc_tdm_match,
+ .probe = ucc_tdm_probe,
+ .remove = ucc_tdm_remove,
+};
+
+static int __init ucc_tdm_init(void)
+{
+ u32 i;
+
+ pr_info("ucc_tdm: " DRV_DESC "\n");
+ for (i = 0; i < 8; i++)
+ memcpy(&(utdm_info[i]), &utdm_primary_info,
+ sizeof(utdm_primary_info));
+
+ return of_register_platform_driver(&ucc_tdm_driver);
+}
+
+static void __exit ucc_tdm_exit(void)
+{
+ of_unregister_platform_driver(&ucc_tdm_driver);
+}
+
+module_init(ucc_tdm_init);
+module_exit(ucc_tdm_exit);
+MODULE_AUTHOR("Freescale Semiconductor, Inc");
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/ucc_tdm.h b/drivers/misc/ucc_tdm.h
new file mode 100644
index 0000000..d0f376b
--- /dev/null
+++ b/drivers/misc/ucc_tdm.h
@@ -0,0 +1,227 @@
+/*
+ * drivers/misc/ucc_tdm.h
+ *
+ * UCC Based Linux TDM Driver
+ * This driver is designed to support UCC based TDM for PowerPC processors.
+ * This driver can interface with SLIC device to run VOIP kind of
+ * applications.
+ *
+ * Author: Ashish Kalra & Poonam Aggrwal
+ *
+ * Copyright (c) 2007 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.
+ */
+
+#ifndef TDM_H
+#define TDM_H
+
+#define NUM_TS 8
+#define ACTIVE_CH 8
+
+/* SAMPLE_DEPTH is the sample depth is the number of frames before
+ * an interrupt. Must be a multiple of 4
+ */
+#define SAMPLE_DEPTH 80
+
+/* define the number of Rx interrupts to go by for initial stuttering */
+#define STUTTER_INT_CNT 1
+
+/* BMRx Field Descriptions to specify tstate and rstate in UCC parameter RAM*/
+#define EN_BUS_SNOOPING 0x20
+#define BE_BO 0x10
+
+/* UPSMR Register for Transparent UCC controller Bit definitions*/
+#define NBO 0x00000000 /* Normal Mode 1 bit of data per clock */
+
+/* SI Mode register bit definitions */
+#define NORMAL_OPERATION 0x0000
+#define AUTO_ECHO 0x0400
+#define INTERNAL_LB 0x0800
+#define CONTROL_LB 0x0c00
+#define SIMODE_CRT (0x8000 >> 9)
+#define SIMODE_SL (0x8000 >> 10)
+#define SIMODE_CE (0x8000 >> 11)
+#define SIMODE_FE (0x8000 >> 12)
+#define SIMODE_GM (0x8000 >> 13)
+#define SIMODE_TFSD(val) (val)
+#define SIMODE_RFSD(val) ((val) << 8)
+
+#define SI_TDM_MODE_REGISTER_OFFSET 0
+
+#define R_CM 0x02000000
+#define T_CM 0x02000000
+
+#define SET_RX_SI_RAM(n, val) \
+ out_be16((u16 *)&qe_immr->sir.rx[(n)*2], (u16)(val))
+
+#define SET_TX_SI_RAM(n, val) \
+ out_be16((u16 *)&qe_immr->sir.tx[(n)*2], (u16)(val))
+
+/* SI RAM entries */
+#define SIR_LAST 0x0001
+#define SIR_CNT(n) ((n) << 2)
+#define SIR_BYTE 0x0002
+#define SIR_BIT 0x0000
+#define SIR_IDLE 0
+#define SIR_UCC(uccx) (((uccx+9)) << 5)
+
+/* BRGC Register Bit definitions */
+#define BRGC_RESET (0x1<<17)
+#define BRGC_EN (0x1<<16)
+#define BRGC_EXTC_QE (0x00<<14)
+#define BRGC_EXTC_CLK3 (0x01<<14)
+#define BRGC_EXTC_CLK5 (0x01<<15)
+#define BRGC_EXTC_CLK9 (0x01<<14)
+#define BRGC_EXTC_CLK11 (0x01<<14)
+#define BRGC_EXTC_CLK13 (0x01<<14)
+#define BRGC_EXTC_CLK15 (0x01<<15)
+#define BRGC_ATB (0x1<<13)
+#define BRGC_DIV16 (0x1)
+
+/* structure representing UCC transparent parameter RAM */
+struct ucc_transparent_pram {
+ __be16 riptr;
+ __be16 tiptr;
+ __be16 res0;
+ __be16 mrblr;
+ __be32 rstate;
+ __be32 rbase;
+ __be16 rbdstat;
+ __be16 rbdlen;
+ __be32 rdptr;
+ __be32 tstate;
+ __be32 tbase;
+ __be16 tbdstat;
+ __be16 tbdlen;
+ __be32 tdptr;
+ __be32 rbptr;
+ __be32 tbptr;
+ __be32 rcrc;
+ __be32 res1;
+ __be32 tcrc;
+ __be32 res2;
+ __be32 res3;
+ __be32 c_mask;
+ __be32 c_pres;
+ __be16 disfc;
+ __be16 crcec;
+ __be32 res4[4];
+ __be16 ts_tmp;
+ __be16 tmp_mb;
+};
+
+#define UCC_TRANSPARENT_PRAM_SIZE 0x100
+
+struct tdm_cfg {
+ u8 com_pin; /* Common receive and transmit pins
+ * 0 = separate pins
+ * 1 = common pins
+ */
+
+ u8 fr_sync_level; /* SLx bit Frame Sync Polarity
+ * 0 = L1R/TSYNC active logic "1"
+ * 1 = L1R/TSYNC active logic "0"
+ */
+
+ u8 clk_edge; /* CEx bit Tx Rx Clock Edge
+ * 0 = TX data on rising edge of clock
+ * RX data on falling edge
+ * 1 = TX data on falling edge of clock
+ * RX data on rising edge
+ */
+
+ u8 fr_sync_edge; /* FEx bit Frame sync edge
+ * Determine when the sync pulses are sampled
+ * 0 = Falling edge
+ * 1 = Rising edge
+ */
+
+ u8 rx_fr_sync_delay; /* TFSDx/RFSDx bits Frame Sync Delay
+ * 00 = no bit delay
+ * 01 = 1 bit delay
+ * 10 = 2 bit delay
+ * 11 = 3 bit delay
+ */
+
+ u8 tx_fr_sync_delay; /* TFSDx/RFSDx bits Frame Sync Delay
+ * 00 = no bit delay
+ * 01 = 1 bit delay
+ * 10 = 2 bit delay
+ * 11 = 3 bit delay
+ */
+
+ u8 active_num_ts; /* Number of active time slots in TDM
+ * assume same active Rx/Tx time slots
+ */
+};
+
+struct ucc_tdm_info {
+ struct ucc_fast_info uf_info;
+ u32 ucc_busy;
+};
+
+struct tdm_ctrl {
+ struct device *device;
+ struct ucc_fast_private *uf_private;
+ struct ucc_tdm_info *ut_info;
+ u32 tdm_port; /* port for this tdm:TDMA,TDMB,TDMC,TDMD */
+ u32 si; /* serial interface: 0 or 1 */
+ struct ucc_fast __iomem *uf_regs; /* UCC Fast registers */
+ u16 rx_mask[8]; /* Active Receive channels LSB is ch0 */
+ u16 tx_mask[8]; /* Active Transmit channels LSB is ch0 */
+ /* Only channels less than the number of FRAME_SIZE are implemented */
+ struct tdm_cfg cfg_ctrl; /* Signaling controls configuration */
+ u8 *tdm_input_data; /* buffer used for Rx by the tdm */
+ u8 *tdm_output_data; /* buffer used for Tx by the tdm */
+
+ dma_addr_t dma_input_addr; /* dma mapped buffer for TDM Rx */
+ dma_addr_t dma_output_addr; /* dma mapped buffer for TDM Tx */
+ u16 physical_num_ts; /* physical number of timeslots in the tdm
+ frame */
+ u32 phase_rx; /* cycles through 0, 1, 2 */
+ u32 phase_tx; /* cycles through 0, 1, 2 */
+ /*
+ * the following two variables are for dealing with "stutter" problem
+ * "stutter" period is about 20 frames or so, varies depending active
+ * channel num depending on the sample depth, the code should let a
+ * few Rx interrupts go by
+ */
+ u32 tdm_icnt;
+ u32 tdm_flag;
+ struct ucc_transparent_pram __iomem *ucc_pram;
+ struct qe_bd __iomem *tx_bd;
+ struct qe_bd __iomem *rx_bd;
+ u32 ucc_pram_offset;
+ u32 tx_bd_offset;
+ u32 rx_bd_offset;
+ u32 rx_ucode_buf_offset;
+ u32 tx_ucode_buf_offset;
+ bool leg_slic;
+ wait_queue_head_t wakeup_event;
+};
+
+struct tdm_client {
+ u32 driver_handle;
+ void (*tdm_read)(u32 driver_handle, short chn_id,
+ short *pcm_buffer, short len);
+ void (*tdm_write)(u32 driver_handle, short chn_id,
+ short *pcm_buffer, short len);
+ wait_queue_head_t *wakeup_event;
+ };
+
+
+#ifndef CONFIG_TDM_LINEAR_PCM
+ #define MAX_PHASE 2
+ #define NR_BUFS 3
+ #define EFF_ACTIVE_CH ACTIVE_CH
+#else
+ #define MAX_PHASE 1
+ #define NR_BUFS 2
+ #define EFF_ACTIVE_CH ACTIVE_CH / 2
+#endif
+
+#endif
--
1.5.2.4
^ permalink raw reply related
* [PATCH 2/3] arch/ : Platform changes for UCC TDM driver for MPC8323ERDB.Also includes related QE changes.
From: Poonam_Aggrwal-b10812 @ 2007-12-10 12:09 UTC (permalink / raw)
To: rubini, linux-kernel, netdev, kumar.gala, linuxppc-dev
Cc: michael.barkowski, rich.cutler, ashish.kalra
From: Poonam Aggrwal <b10812@freescale.com>
This patch makes necessary changes in the QE and UCC framework to support
TDM. It also adds support to configure the BRG properly through device
tree entries. Includes the device tree changes for UCC TDM driver as well.
It also includes device tree entries for UCC TDM driver.
Tested on MPC8323ERDB platform.
Signed-off-by: Poonam Aggrwal <b10812@freescale.com>
Signed-off-by: Ashish Kalra <ashish.kalra@freescale.com>
Signed-off-by: Kim Phillips <Kim.Phillips@freescale.com>
Signed-off-by: Michael Barkowski <michael.barkowski@freescale.com>
---
arch/powerpc/boot/dts/mpc832x_rdb.dts | 58 +++++++
arch/powerpc/sysdev/qe_lib/qe.c | 128 ++++++++++++++--
arch/powerpc/sysdev/qe_lib/ucc.c | 265 +++++++++++++++++++++++++++++++++
arch/powerpc/sysdev/qe_lib/ucc_fast.c | 37 +++++
include/asm-powerpc/qe.h | 8 +
include/asm-powerpc/ucc.h | 4 +
include/asm-powerpc/ucc_fast.h | 4 +
7 files changed, 492 insertions(+), 12 deletions(-)
diff --git a/arch/powerpc/boot/dts/mpc832x_rdb.dts b/arch/powerpc/boot/dts/mpc832x_rdb.dts
index 388c8a7..333408c 100644
--- a/arch/powerpc/boot/dts/mpc832x_rdb.dts
+++ b/arch/powerpc/boot/dts/mpc832x_rdb.dts
@@ -105,6 +105,17 @@
device_type = "par_io";
num-ports = <7>;
+ ucc1pio:ucc_pin@01 {
+ pio-map = <
+ /* port pin dir open_drain assignment has_irq */
+ 0 e 2 0 1 0 /* CLK11 */
+ 3 16 1 0 2 0 /* BRG9 */
+ 3 1b 1 0 2 0 /* BRG3 */
+ 0 0 3 0 2 0 /* TDMATxD0 */
+ 0 4 3 0 2 0 /* TDMARxD0 */
+ 3 1b 2 0 1 0>; /* CLK1 */
+ };
+
ucc2pio:ucc_pin@02 {
pio-map = <
/* port pin dir open_drain assignment has_irq */
@@ -169,6 +180,36 @@
};
};
+ clocks {
+ compatible = "fsl,cpm-clocks";
+ /* clock freqs in Hz(for CLK1~CLK24).
+ * CLK11 is 1024KHz,
+ * all other clocks unused
+ * #clock-cells define number of cells
+ * used by the clock-frequency.
+ * right now only #clock cells=1 is
+ * implemented. Provision is there to
+ * handle frequencies >4Gig
+ */
+ #clock-cells = <1>;
+ clock-frequency = <0 0 0 0 0 0
+ 0 0 0 0 d#1024000 0
+ 0 0 0 0 0 0
+ 0 0 0 0 0 0>;
+ };
+
+ brg@640 {
+ compatible = "fsl,cpm-brg";
+ /* input clock sources for all the 16 BRGs.
+ * 1-24 for CLK1 to CLK24.
+ * BRG9 uses CLK11,BRG1 and BRG2-8 use
+ * the QE clock.
+ */
+ fsl,brg-sources = <0 0 0 0 0 0 0 0
+ b 0 0 0 0 0 0 0>;
+ reg = <640 7f>;
+ };
+
spi@4c0 {
device_type = "spi";
compatible = "fsl_spi";
@@ -187,6 +228,23 @@
mode = "cpu";
};
+ ucc@2000 {
+ device_type = "tdm";
+ compatible = "fsl,ucc-tdm";
+ model = "UCC";
+ device-id = <1>;
+ fsl,tdm-num = <1>;
+ fsl,si-num = <1>;
+ fsl,tdm-tx-clk = "CLK1";
+ fsl,tdm-rx-clk = "CLK1";
+ fsl,tdm-tx-sync = "BRG9";
+ fsl,tdm-rx-sync = "BRG9";
+ reg = <2000 200>;
+ interrupts = <20>;
+ interrupt-parent = <&qeic>;
+ pio-handle = <&ucc1pio>;
+ };
+
ucc@3000 {
device_type = "network";
compatible = "ucc_geth";
diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c
index 1df3b4a..abcf0b4 100644
--- a/arch/powerpc/sysdev/qe_lib/qe.c
+++ b/arch/powerpc/sysdev/qe_lib/qe.c
@@ -149,22 +149,116 @@ EXPORT_SYMBOL(qe_issue_cmd);
*/
static unsigned int brg_clk = 0;
-unsigned int get_brg_clk(void)
+u32 get_brg_clk(enum qe_clock brgclk, enum qe_clock *brg_source)
{
- struct device_node *qe;
- if (brg_clk)
- return brg_clk;
+ struct device_node *qe, *brg, *clocks;
+ enum qe_clock brg_src;
+ u32 brg_input_freq = 0;
+ u32 brg_num;
+ const unsigned int *prop;
- qe = of_find_node_by_type(NULL, "qe");
- if (qe) {
+ *brg_source = 0;
+
+ brg_num = brgclk - QE_BRG1;
+ brg = of_find_compatible_node(NULL, NULL, "fsl,cpm-brg");
+ if (brg) {
unsigned int size;
- const u32 *prop = of_get_property(qe, "brg-frequency", &size);
- brg_clk = *prop;
- of_node_put(qe);
- };
+ prop = of_get_property(brg,
+ "fsl,brg-sources", &size);
+
+ brg_src = *(prop + brg_num);
+ if (brg_src == 0) {
+ *brg_source = 0;
+ if (brg_clk > 0) {
+ of_node_put(brg);
+ return brg_clk;
+ }
+ qe = of_find_node_by_type(NULL, "qe");
+ if (qe) {
+ unsigned int size;
+ prop = of_get_property
+ (qe, "brg-frequency", &size);
+ of_node_put(qe);
+ of_node_put(brg);
+ return *prop;
+ }
+ } else {
+ *brg_source = brg_src + QE_CLK1 - 1;
+ clocks = of_find_compatible_node(NULL, NULL,
+ "fsl,cpm-clocks");
+ prop = of_get_property(clocks,
+ "#clock-cells", &size);
+ /*
+ * clock-cells = 1 only supported right now.
+ */
+ if (*prop != 1)
+ return 0;
+ prop = of_get_property(clocks,
+ "clock-frequency", &size);
+
+ brg_input_freq = *(prop+(brg_src - 1));
+ of_node_put(clocks);
+ of_node_put(brg);
+ return brg_input_freq;
+ }
+ }
return brg_clk;
}
+u32 qe_brg_src(int brg_num, enum qe_clock brg_src)
+{
+ u32 clock_bits, shift;
+
+ clock_bits = 0;
+
+ switch (brg_num) {
+ case 1:
+ case 2:
+ case 5:
+ case 6:
+ switch (brg_src) {
+ case QE_CLK3: clock_bits = 1; break;
+ case QE_CLK5: clock_bits = 2; break;
+ default: break;
+ }
+ break;
+ case 3:
+ case 4:
+ case 7:
+ case 8:
+ switch (brg_src) {
+ case QE_CLK9: clock_bits = 1; break;
+ case QE_CLK15: clock_bits = 2; break;
+ default: break;
+ }
+ break;
+ case 9:
+ case 10:
+ switch (brg_src) {
+ case QE_CLK11: clock_bits = 1; break;
+ default: break;
+ }
+ break;
+ case 11:
+ case 15:
+ case 16:
+ switch (brg_src) {
+ case QE_CLK13: clock_bits = 1; break;
+ default: break;
+ }
+ break;
+ default: clock_bits = 0; break;
+ }
+ shift = 14;
+
+ if (!clock_bits)
+ return -ENOENT;
+
+ clock_bits <<= shift;
+
+ return clock_bits;
+}
+
/* Program the BRG to the given sampling rate and multiplier
*
* @brg: the BRG, QE_BRG1 - QE_BRG16
@@ -177,11 +271,18 @@ int qe_setbrg(enum qe_clock brg, unsigned int rate, unsigned int multiplier)
{
u32 divisor, tempval;
u32 div16 = 0;
+ u32 brg_clock;
+ enum qe_clock brgsrc;
+ u32 src_bits = 0;
if ((brg < QE_BRG1) || (brg > QE_BRG16))
return -EINVAL;
- divisor = get_brg_clk() / (rate * multiplier);
+ brg_clock = get_brg_clk(brg, &brgsrc);
+ if (!brg_clock)
+ return -EINVAL;
+
+ divisor = brg_clock / (rate * multiplier);
if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
div16 = QE_BRGC_DIV16;
@@ -194,8 +295,11 @@ int qe_setbrg(enum qe_clock brg, unsigned int rate, unsigned int multiplier)
if (!div16 && (divisor & 1))
divisor++;
+ if (brgsrc > 0)
+ src_bits = qe_brg_src(brg - QE_BRG1 + 1, brgsrc);
+
tempval = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) |
- QE_BRGC_ENABLE | div16;
+ QE_BRGC_ENABLE | div16 | src_bits;
out_be32(&qe_immr->brg.brgc[brg - QE_BRG1], tempval);
diff --git a/arch/powerpc/sysdev/qe_lib/ucc.c b/arch/powerpc/sysdev/qe_lib/ucc.c
index 0e348d9..f2de0ed 100644
--- a/arch/powerpc/sysdev/qe_lib/ucc.c
+++ b/arch/powerpc/sysdev/qe_lib/ucc.c
@@ -213,3 +213,268 @@ int ucc_set_qe_mux_rxtx(unsigned int ucc_num, enum qe_clock clock,
return 0;
}
+
+int ucc_set_tdm_rxtx_clk(int tdm_num, char *clk_src, enum comm_dir mode)
+{
+ enum qe_clock clock;
+ u32 clock_bits, shift;
+ struct qe_mux *qe_mux_reg = NULL;
+
+ clock_bits = 0;
+ qe_mux_reg = &qe_immr->qmx;
+
+ if ((tdm_num > 3 || tdm_num < 0))
+ return -EINVAL;
+
+ /* The communications direction must be RX or TX */
+ if (!((mode == COMM_DIR_RX) || (mode == COMM_DIR_TX)))
+ return -EINVAL;
+
+ clock = qe_clock_source(clk_src);
+ switch (mode) {
+ case COMM_DIR_RX:
+ switch (tdm_num) {
+ case 0:
+ switch (clock) {
+ case QE_BRG3: clock_bits = 1; break;
+ case QE_BRG4: clock_bits = 2; break;
+ case QE_CLK1: clock_bits = 4; break;
+ case QE_CLK2: clock_bits = 5; break;
+ case QE_CLK3: clock_bits = 6; break;
+ case QE_CLK8: clock_bits = 7; break;
+ default: break;
+ }
+ shift = 28;
+ break;
+ case 1:
+ switch (clock) {
+ case QE_BRG3: clock_bits = 1; break;
+ case QE_BRG4: clock_bits = 2; break;
+ case QE_CLK1: clock_bits = 4; break;
+ case QE_CLK2: clock_bits = 5; break;
+ case QE_CLK5: clock_bits = 6; break;
+ case QE_CLK10: clock_bits = 7; break;
+ default: break;
+ }
+ shift = 24;
+ break;
+ case 2:
+ switch (clock) {
+ case QE_BRG3: clock_bits = 1; break;
+ case QE_BRG4: clock_bits = 2; break;
+ case QE_CLK1: clock_bits = 4; break;
+ case QE_CLK2: clock_bits = 5; break;
+ case QE_CLK7: clock_bits = 6; break;
+ case QE_CLK12: clock_bits = 7; break;
+ default: break;
+ }
+ shift = 20;
+ break;
+ case 3:
+ switch (clock) {
+ case QE_BRG3: clock_bits = 1; break;
+ case QE_BRG4: clock_bits = 2; break;
+ case QE_CLK1: clock_bits = 4; break;
+ case QE_CLK2: clock_bits = 5; break;
+ case QE_CLK9: clock_bits = 6; break;
+ case QE_CLK14: clock_bits = 7; break;
+ default: break;
+ }
+ shift = 16;
+ break;
+ default:
+ break;
+ }
+ break;
+ case COMM_DIR_TX:
+ switch (tdm_num) {
+ case 0:
+ switch (clock) {
+ case QE_BRG3: clock_bits = 1; break;
+ case QE_BRG4: clock_bits = 2; break;
+ case QE_CLK1: clock_bits = 4; break;
+ case QE_CLK2: clock_bits = 5; break;
+ case QE_CLK4: clock_bits = 6; break;
+ case QE_CLK9: clock_bits = 7; break;
+ default: break;
+ }
+ shift = 12;
+ break;
+ case 1:
+ switch (clock) {
+ case QE_BRG3: clock_bits = 1; break;
+ case QE_BRG4: clock_bits = 2; break;
+ case QE_CLK1: clock_bits = 4; break;
+ case QE_CLK2: clock_bits = 5; break;
+ case QE_CLK6: clock_bits = 6; break;
+ case QE_CLK11: clock_bits = 7; break;
+ default: break;
+ }
+ shift = 8;
+ break;
+ case 2:
+ switch (clock) {
+ case QE_BRG3: clock_bits = 1; break;
+ case QE_BRG4: clock_bits = 2; break;
+ case QE_CLK1: clock_bits = 4; break;
+ case QE_CLK2: clock_bits = 5; break;
+ case QE_CLK8: clock_bits = 6; break;
+ case QE_CLK13: clock_bits = 7; break;
+ default: break;
+ }
+ shift = 4;
+ break;
+ case 3:
+ switch (clock) {
+ case QE_BRG3: clock_bits = 1; break;
+ case QE_BRG4: clock_bits = 2; break;
+ case QE_CLK1: clock_bits = 4; break;
+ case QE_CLK2: clock_bits = 5; break;
+ case QE_CLK10: clock_bits = 6; break;
+ case QE_CLK15: clock_bits = 7; break;
+ default: break;
+ }
+ shift = 0;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!clock_bits)
+ return -ENOENT;
+
+ clock_bits <<= shift;
+
+ qe_mux_reg->cmxsi1cr_l |= clock_bits;
+
+ return 0;
+}
+
+int ucc_set_tdm_rxtx_sync(int tdm_num, char *sync_src, enum comm_dir mode)
+{
+ enum qe_clock clock;
+ u32 shift, clock_bits;
+ struct qe_mux *qe_mux_reg = NULL;
+ int source;
+
+ source = -1;
+ qe_mux_reg = &qe_immr->qmx;
+
+ if ((tdm_num > 3 || tdm_num < 0))
+ return -EINVAL;
+
+ /* The communications direction must be RX or TX */
+ if (!((mode == COMM_DIR_RX) || (mode == COMM_DIR_TX)))
+ return -EINVAL;
+
+ switch (mode) {
+ case COMM_DIR_RX:
+ if (strcasecmp("RSYNC", sync_src) == 0) {
+ source = 0;
+ shift = 0;
+ break;
+ }
+ clock = qe_clock_source(sync_src);
+ switch (tdm_num) {
+ case 0:
+ switch (clock) {
+ case QE_BRG9: source = 1; break;
+ case QE_BRG10: source = 2; break;
+ default: source = -1; break;
+ }
+ shift = 30;
+ break;
+ case 1:
+ switch (clock) {
+ case QE_BRG9: source = 1; break;
+ case QE_BRG10: source = 2; break;
+ default: source = -1; break;
+ }
+ shift = 28;
+ break;
+ case 2:
+ switch (clock) {
+ case QE_BRG9: source = 1; break;
+ case QE_BRG11: source = 2; break;
+ default: source = -1; break;
+ }
+ shift = 26;
+ break;
+ case 3:
+ switch (clock) {
+ case QE_BRG9: source = 1; break;
+ case QE_BRG11: source = 2; break;
+ default: source = -1; break;
+ }
+ shift = 24;
+ break;
+ default:
+ source = -1;
+ break;
+ }
+ break;
+ case COMM_DIR_TX:
+ if (strcasecmp("TSYNC", sync_src) == 0) {
+ source = 0;
+ shift = 0;
+ break;
+ }
+ clock = qe_clock_source(sync_src);
+ switch (tdm_num) {
+ case 0:
+ switch (clock) {
+ case QE_BRG9: source = 1; break;
+ case QE_BRG10: source = 2; break;
+ default: source = -1; break;
+ }
+ shift = 14;
+ break;
+ case 1:
+ switch (clock) {
+ case QE_BRG9: source = 1; break;
+ case QE_BRG10: source = 2; break;
+ default: source = -1; break;
+ }
+ shift = 12;
+ break;
+ case 2:
+ switch (clock) {
+ case QE_BRG9: source = 1; break;
+ case QE_BRG11: source = 2; break;
+ default: source = -1; break;
+ }
+ shift = 10;
+ break;
+ case 3:
+ switch (clock) {
+ case QE_BRG9: source = 1; break;
+ case QE_BRG11: source = 2; break;
+ default: source = -1; break;
+ }
+ shift = 8;
+ break;
+ default:
+ source = -1;
+ break;
+ }
+ break;
+ default:
+ source = -1;
+ break;
+ }
+
+ if (source == -1)
+ return -ENOENT;
+
+ clock_bits = (u32) source;
+ clock_bits <<= shift;
+
+
+ qe_mux_reg->cmxsi1syr |= clock_bits;
+
+ return 0;
+}
diff --git a/arch/powerpc/sysdev/qe_lib/ucc_fast.c b/arch/powerpc/sysdev/qe_lib/ucc_fast.c
index 3223acb..9c8559f 100644
--- a/arch/powerpc/sysdev/qe_lib/ucc_fast.c
+++ b/arch/powerpc/sysdev/qe_lib/ucc_fast.c
@@ -327,6 +327,43 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc
ucc_fast_free(uccf);
return -EINVAL;
}
+ } else {
+ /* TDM Rx clock routing */
+ if ((uf_info->tdm_rx_clk != NULL) &&
+ ucc_set_tdm_rxtx_clk(uf_info->ucc_num,
+ uf_info->tdm_rx_clk, COMM_DIR_RX)) {
+ printk(KERN_ERR "%s: illegal value for TDM RX clock",
+ __FUNCTION__);
+ ucc_fast_free(uccf);
+ return -EINVAL;
+ }
+ /* TDM Tx clock routing */
+ if ((uf_info->tdm_tx_clk != NULL) &&
+ ucc_set_tdm_rxtx_clk(uf_info->ucc_num,
+ uf_info->tdm_tx_clk, COMM_DIR_TX)) {
+ printk(KERN_ERR "%s: illegal value for TDM TX clock",
+ __FUNCTION__);
+ ucc_fast_free(uccf);
+ return -EINVAL;
+ }
+ /* TDM Rx sync routing */
+ if ((uf_info->tdm_rx_sync != NULL) &&
+ ucc_set_tdm_rxtx_sync(uf_info->ucc_num,
+ uf_info->tdm_rx_sync, COMM_DIR_RX)) {
+ printk(KERN_ERR "%s: illegal value for TDM RX"
+ "Frame sync", __FUNCTION__);
+ ucc_fast_free(uccf);
+ return -EINVAL;
+ }
+ /* TDM Tx sync routing */
+ if ((uf_info->tdm_tx_sync != NULL) &&
+ ucc_set_tdm_rxtx_sync(uf_info->ucc_num,
+ uf_info->tdm_tx_sync, COMM_DIR_TX)) {
+ printk(KERN_ERR "%s: illegal value for TDM TX"
+ "Frame sync", __FUNCTION__);
+ ucc_fast_free(uccf);
+ return -EINVAL;
+ }
}
/* Set interrupt mask register at UCC level. */
diff --git a/include/asm-powerpc/qe.h b/include/asm-powerpc/qe.h
index bcf60be..51de236 100644
--- a/include/asm-powerpc/qe.h
+++ b/include/asm-powerpc/qe.h
@@ -497,6 +497,14 @@ struct ucc_slow_pram {
#define UCC_GETH_UCCE_RXF1 0x00000002
#define UCC_GETH_UCCE_RXF0 0x00000001
+/* Transparent UCC Event Register (UCCE) */
+#define UCC_TRANS_UCCE_GRA 0x0080
+#define UCC_TRANS_UCCE_TXE 0x0010
+#define UCC_TRANS_UCCE_RXF 0x0008
+#define UCC_TRANS_UCCE_BSY 0x0004
+#define UCC_TRANS_UCCE_TXB 0x0002
+#define UCC_TRANS_UCCE_RXB 0x0001
+
/* UPSMR, when used as a UART */
#define UCC_UART_UPSMR_FLC 0x8000
#define UCC_UART_UPSMR_SL 0x4000
diff --git a/include/asm-powerpc/ucc.h b/include/asm-powerpc/ucc.h
index 46b09ba..153db97 100644
--- a/include/asm-powerpc/ucc.h
+++ b/include/asm-powerpc/ucc.h
@@ -42,6 +42,10 @@ int ucc_set_qe_mux_mii_mng(unsigned int ucc_num);
int ucc_set_qe_mux_rxtx(unsigned int ucc_num, enum qe_clock clock,
enum comm_dir mode);
+int ucc_set_tdm_rxtx_clk(int tdm_num, char *clk_src, enum comm_dir mode);
+
+int ucc_set_tdm_rxtx_sync(int tdm_num, char *clk_src, enum comm_dir mode);
+
int ucc_mux_set_grant_tsa_bkpt(unsigned int ucc_num, int set, u32 mask);
/* QE MUX clock routing for UCC
diff --git a/include/asm-powerpc/ucc_fast.h b/include/asm-powerpc/ucc_fast.h
index f529f70..d267983 100644
--- a/include/asm-powerpc/ucc_fast.h
+++ b/include/asm-powerpc/ucc_fast.h
@@ -152,6 +152,10 @@ struct ucc_fast_info {
enum ucc_fast_rx_decoding_method renc;
enum ucc_fast_transparent_tcrc tcrc;
enum ucc_fast_sync_len synl;
+ char *tdm_rx_clk;
+ char *tdm_tx_clk;
+ char *tdm_rx_sync;
+ char *tdm_tx_sync;
};
struct ucc_fast_private {
--
1.5.2.4
^ permalink raw reply related
* [PATCH 3/3] Modified Documentation to explain dts entries for UCC TDM driver.
From: Poonam_Aggrwal-b10812 @ 2007-12-10 12:13 UTC (permalink / raw)
To: rubini, kumar.gala, linux-kernel, netdev, linuxppc-dev
Cc: michael.barkowski, rich.cutler, ashish.kalra
From: Poonam Aggrwal <b10812@freescale.com>
Modified Documentation to explain new properties introduced for UCC TDM
driver. Also two new nodes have been added "brg" and "clocks" to configure
a BRG from device tree.
Signed-off-by: Poonam Aggrwal <b10812@freescale.com>
Signed-off-by: Ashish Kalra <ashish.kalra@freescale.com>
Signed-off-by: Kim Phillips <Kim.Phillips@freescale.com>
Signed-off-by: Michael Barkowski <michael.barkowski@freescale.com>
---
Documentation/powerpc/booting-without-of.txt | 96 +++++++++++++++++++++++++-
1 files changed, 94 insertions(+), 2 deletions(-)
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index e9a3cb1..94a6b4b 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -1613,8 +1613,8 @@ platforms are moved over to use the flattened-device-tree model.
Required properties:
- device_type : should be "network", "hldc", "uart", "transparent"
- "bisync" or "atm".
- - compatible : could be "ucc_geth" or "fsl_atm" and so on.
+ "bisync", "atm" or "tdm".
+ - compatible : could be "ucc_geth", "fsl_atm" or "fsl,ucc_tdm" and so on.
- model : should be "UCC".
- device-id : the ucc number(1-8), corresponding to UCCx in UM.
- reg : Offset and length of the register set for the device
@@ -1666,7 +1666,44 @@ platforms are moved over to use the flattened-device-tree model.
pio-handle = <140001>;
};
+ Required properties for tdm device_type:
+ - instead of tx-clock and rx-clock following clock properties are
+ required:
+ - fsl,tdm-tx-clk : This property selects the TX clock source for TDM
+ from a bank of clocks.
+ - fsl,tdm-rx-clk : This property selects the RX clock source for TDM
+ from a bank of clocks.
+ - fsl,tdm-tx-sync : This property selects the TX Frame sync source
+ for TDM from a bank of clocks.
+ - fsl,tdm-rx-sync : This property selects the TX Frame sync source
+ for TDM from a bank of clocks.
+
+ All the above mentioned properties are string type with possible
+ values
+ "CLK1", "CLK2", "CLK3"..."CLK24" and so on
+ "BRG1", "BRG2", "BRG3"..."BRG16" and so on
+
+ - fsl,tdm-num : TDM to be used (1,2,3 or 4 for TDMA TDMB TDMC TDMD)
+ - fsl,si-num : Serial Interface to be used.
+ Example:
+ ucc@2000 {
+ device_type = "tdm";
+ compatible = "fsl,ucc-tdm";
+ model = "UCC";
+ device-id = <1>;
+ fsl,tdm-num = <1>;
+ fsl,si-num = <1>;
+ fsl,tdm-tx-clk = "CLK1";
+ fsl,tdm-rx-clk = "CLK1";
+ fsl,tdm-tx-sync = "BRG9";
+ fsl,tdm-rx-sync = "BRG9";
+ reg = <2000 200>;
+ interrupts = <20>;
+ interrupt-parent = <&qeic>;
+ pio-handle = <&ucc1pio>;
+ };
+
v) Parallel I/O Ports
This node configures Parallel I/O ports for CPUs with QE support.
@@ -1772,6 +1809,61 @@ platforms are moved over to use the flattened-device-tree model.
};
};
+ viii) Clocks (clocks)
+ This node specifies the frequency values for all the external clocks
+ viz CLK1 to CLK24 in Hz.
+
+ Required Properties:
+ - compatible : should be "fsl,cpm-clocks".
+ - #clock-cells : It specifies the number of cells occupied by clock-frequency
+ property. Currently #clock-cells = 1 is only supported and implemented.
+ This property is kept for future in case we need frequencies higher than
+ 4 GHz.
+ - clock-frequency : It is a list of u32 values to represent the frequency
+ of each external clock(CLK1 to CLK24) in Hz.Each entry occupies
+ number of cells specified by #clock-cells property(1 for now).
+
+ Example:
+
+ clocks {
+ compatible = "fsl,cpm-clocks";
+ #clock-cells = <1>;
+ /* clock freqs in Hz(for CLK1~CLK24).
+ * CLK11 is 1024KHz,
+ * all other clocks unused
+ */
+ clock-frequency = <0 0 0 0 0 0
+ 0 0 0 0 0 d#1024000 0
+ 0 0 0 0 0 0
+ 0 0 0 0 0 0>;
+ };
+
+ ix) Baud Rate Generator (BRG)
+
+ Required properties:
+ - compatible : shpuld be "fsl,cpm-brg"
+ - fsl,brg-sources : define the input clock for all 16 BRGs. The input
+ clock source could be 1 to 24 for CLK1 to CLK24. Zero means that the
+ particular BRG will be driven by QE clock(BRGCLK).
+ - reg : This property defines the address and size of the memory-mapped
+ registers of the BRG.
+
+ Example:
+
+ brg@640 {
+ compatible = "fsl,qe-brg";
+ /* input clock sources for all the 16 BRGs.
+ * 1-24 for CLK1 to CLK24.
+ * BRG9 uses CLK11 others use
+ * the QE clock.
+ */
+ fsl,brg-sources = <0 0 0 0 0 0 0 0
+ b 0 0 0 0 0 0 0>;
+ reg = <640 7f>;
+ };
+
+ In the above entry, for BRG9 the input clock is 0xb(decimal 11) ie QE_CLK11.
+
j) CFI or JEDEC memory-mapped NOR flash
Flash chips (Memory Technology Devices) are often used for solid state
--
1.5.2.4
^ permalink raw reply related
* Re: [PATCH] Fix rounding bug in emulation for double floatoperating
From: Kumar Gala @ 2007-12-10 15:00 UTC (permalink / raw)
To: Liu Yu; +Cc: linuxppc-dev, David Gibson
In-Reply-To: <6EBEC19BF4A8F843BCD6B9155BBE2515C79D0D@zch01exm26.fsl.freescale.net>
On Dec 9, 2007, at 11:25 PM, Liu Yu wrote:
>
>
>
>
>
>> -----Original Message-----
>> From: David Gibson [mailto:david@gibson.dropbear.id.au]
>> Sent: Monday, December 10, 2007 12:56 PM
>> To: Liu Yu
>> Cc: linuxppc-dev@ozlabs.org
>> Subject: Re: [PATCH] Fix rounding bug in emulation for double
>> floatoperating
>>
>>
>> On Mon, Dec 10, 2007 at 01:00:52PM +0800, Liu Yu wrote:
>>>
>>> This patch fixes rounding bug in emulation for double float
>> operating on PowerPC platform.
>>>
>>> When pack double float operand, it need to truncate the
>> tail due to the limited precision.
>>> If the truncated part is not zero, the last bit of work bit
>> (totally 3 bits) need to '|' 1.
>>>
>>> This patch is completed in _FP_FRAC_SRS_2(X,N,sz)
>> (arch/powerpc/math-emu/op-2.h).
>>> Originally the code leftwards rotates the operand to just keep the
>>> truncated part, then check whether it is zero. However, the
>> number it
>>> rotates is not correct when N is not smaller than
>> _FP_W_TYPE_SIZE, and it will cause the work bit '|' 1 in the
>> improper case.
>>>
>>> This patch fixes this issue.
>>>
>>> Signed-off-by: Liu Yu <b13201@freescale.com>
>>
>> Wow someone deciphered the hideous macro hell of the math
>> emulation code enough to fix a bug. I don't suppose you'd
>> care to fix the millions of warnings that the math-emu code
>> generates...?
>
> Oh, I don't like macro define either. But it's really a bug...
how did you find this?
- k
^ permalink raw reply
* Re: [PATCH] windfarm: add PowerMac 12,1 support
From: Étienne Bersac @ 2007-12-10 15:11 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <1196955051.6862.10.camel@thilivren>
From: Étienne Bersac <bersace03@gmail.com>
Hi,
Here is an updated patch that fix the potential bug, CPU param detection
failure might not be detected. Please review it.
Regards,
Étienne.
Signed-off-by: Étienne Bersac <bersace03@gmail.com>
---
Implement fan control for PowerMac 12,1 machines. This needs update to
windfarm_lm75 and windfarm_max6690 sensors drivers in order to properly
match sensors by their location. The code is based on windfarm_pm81
driver, adapted to the complexity of PowerMac 12,1 : 4 system control
loops instead of one, per-control target correction and per-model
control rubber-banding.
All the data are copied from Darwin 8.10 AppleMacRISC4PE-185.0.0 module
as well as correction formula.
diff --git a/arch/powerpc/configs/g5_defconfig b/arch/powerpc/configs/g5_defconfig
index 0a6fa1f..7125837 100644
--- a/arch/powerpc/configs/g5_defconfig
+++ b/arch/powerpc/configs/g5_defconfig
@@ -656,6 +656,7 @@ CONFIG_WINDFARM=y
CONFIG_WINDFARM_PM81=y
CONFIG_WINDFARM_PM91=y
CONFIG_WINDFARM_PM112=y
+CONFIG_WINDFARM_PM121=y
# CONFIG_PMAC_RACKMETER is not set
CONFIG_NETDEVICES=y
# CONFIG_NETDEVICES_MULTIQUEUE is not set
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index 77f50b6..2d028e6 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -234,6 +234,14 @@ config WINDFARM_PM112
which are the recent dual and quad G5 machines using the
970MP dual-core processor.
+config WINDFARM_PM121
+ tristate "Support for thermal management on PowerMac12,1"
+ depends on WINDFARM && I2C && PMAC_SMU
+ select I2C_POWERMAC
+ help
+ This driver provides thermal control for the PowerMac12,1
+ which is the iMac G5 (iSight) 970MP
+
config ANSLCD
tristate "Support for ANS LCD display"
depends on ADB_CUDA && PPC_PMAC
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
index 2dfc3f4..e3132ef 100644
--- a/drivers/macintosh/Makefile
+++ b/drivers/macintosh/Makefile
@@ -42,4 +42,9 @@ obj-$(CONFIG_WINDFARM_PM112) += windfarm_pm112.o windfarm_smu_sat.o \
windfarm_smu_sensors.o \
windfarm_max6690_sensor.o \
windfarm_lm75_sensor.o windfarm_pid.o
+obj-$(CONFIG_WINDFARM_PM121) += windfarm_pm121.o windfarm_smu_sat.o \
+ windfarm_smu_controls.o \
+ windfarm_smu_sensors.o \
+ windfarm_max6690_sensor.o \
+ windfarm_lm75_sensor.o windfarm_pid.o
obj-$(CONFIG_PMAC_RACKMETER) += rack-meter.o
diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c
index 7e10c3a..b92b959 100644
--- a/drivers/macintosh/windfarm_lm75_sensor.c
+++ b/drivers/macintosh/windfarm_lm75_sensor.c
@@ -127,6 +127,12 @@ static struct wf_lm75_sensor *wf_lm75_create(struct i2c_adapter *adapter,
*/
if (!strcmp(loc, "Hard drive") || !strcmp(loc, "DRIVE BAY"))
lm->sens.name = "hd-temp";
+ else if (!strcmp(loc, "Incoming Air Temp"))
+ lm->sens.name = "incoming-air-temp";
+ else if (!strcmp(loc, "ODD Temp"))
+ lm->sens.name = "optical-drive-temp";
+ else if (!strcmp(loc, "HD Temp"))
+ lm->sens.name = "hard-drive-temp";
else
goto fail;
diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c
index 5f03aab..c2b6d1c 100644
--- a/drivers/macintosh/windfarm_max6690_sensor.c
+++ b/drivers/macintosh/windfarm_max6690_sensor.c
@@ -77,10 +77,11 @@ static struct wf_sensor_ops wf_max6690_ops = {
.owner = THIS_MODULE,
};
-static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr)
+static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr,
+ const char *loc)
{
struct wf_6690_sensor *max;
- char *name = "backside-temp";
+ char *name = NULL;
max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL);
if (max == NULL) {
@@ -89,6 +90,15 @@ static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr)
return;
}
+ if (!strcmp(loc, "BACKSIDE"))
+ name = "backside-temp";
+ else if (!strcmp(loc, "NB Ambient"))
+ name = "north-bridge-temp";
+ else if (!strcmp(loc, "GPU Ambient"))
+ name = "gpu-temp";
+ else
+ goto fail;
+
max->sens.ops = &wf_max6690_ops;
max->sens.name = name;
max->i2c.addr = addr >> 1;
@@ -138,9 +148,7 @@ static int wf_max6690_attach(struct i2c_adapter *adapter)
if (loc == NULL || addr == 0)
continue;
printk("found max6690, loc=%s addr=0x%02x\n", loc, addr);
- if (strcmp(loc, "BACKSIDE"))
- continue;
- wf_max6690_create(adapter, addr);
+ wf_max6690_create(adapter, addr, loc);
}
return 0;
diff --git a/drivers/macintosh/windfarm_pm121.c b/drivers/macintosh/windfarm_pm121.c
new file mode 100644
index 0000000..e3a9c50
--- /dev/null
+++ b/drivers/macintosh/windfarm_pm121.c
@@ -0,0 +1,1053 @@
+/*
+ * Windfarm PowerMac thermal control. iMac G5 iSight
+ *
+ * (c) Copyright 2007 Étienne Bersac <bersace@gmail.com>
+ *
+ * Bits & pieces from windfarm_pm81.c by (c) Copyright 2005 Benjamin
+ * Herrenschmidt, IBM Corp. <benh@kernel.crashing.org>
+ *
+ * Released under the term of the GNU GPL v2.
+ *
+ *
+ *
+ * PowerMac12,1
+ * ============
+ *
+ *
+ * The algorithm used is the PID control algorithm, used the same way
+ * the published Darwin code does, using the same values that are
+ * present in the Darwin 8.10 snapshot property lists (note however
+ * that none of the code has been re-used, it's a complete
+ * re-implementation
+ *
+ * There is two models using PowerMac12,1. Model 2 is iMac G5 iSight
+ * 17" while Model 3 is iMac G5 20". They do have both the same
+ * controls with a tiny difference. The control-ids of hard-drive-fan
+ * and cpu-fan is swapped.
+ *
+ *
+ * Target Correction :
+ *
+ * controls have a target correction calculated as :
+ *
+ * new_min = ((((average_power * slope) >> 16) + offset) >> 16) + min_value
+ * new_value = max(new_value, max(new_min, 0))
+ *
+ * OD Fan control correction.
+ *
+ * # model_id: 2
+ * offset : -19563152
+ * slope : 1956315
+ *
+ * # model_id: 3
+ * offset : -15650652
+ * slope : 1565065
+ *
+ * HD Fan control correction.
+ *
+ * # model_id: 2
+ * offset : -15650652
+ * slope : 1565065
+ *
+ * # model_id: 3
+ * offset : -19563152
+ * slope : 1956315
+ *
+ * CPU Fan control correction.
+ *
+ * # model_id: 2
+ * offset : -25431900
+ * slope : 2543190
+ *
+ * # model_id: 3
+ * offset : -15650652
+ * slope : 1565065
+ *
+ *
+ * Target rubber-banding :
+ *
+ * Some controls have a target correction which depends on another
+ * control value. The correction is computed in the following way :
+ *
+ * new_min = ref_value * slope + offset
+ *
+ * ref_value is the value of the reference control. If new_min is
+ * greater than 0, then we correct the target value using :
+ *
+ * new_target = max (new_target, new_min >> 16)
+ *
+ *
+ * # model_id : 2
+ * control : cpu-fan
+ * ref : optical-drive-fan
+ * offset : -15650652
+ * slope : 1565065
+ *
+ * # model_id : 3
+ * control : optical-drive-fan
+ * ref : hard-drive-fan
+ * offset : -32768000
+ * slope : 65536
+ *
+ *
+ * In order to have the moste efficient correction with those
+ * dependencies, we must trigger HD loop before OD loop before CPU
+ * loop.
+ *
+ *
+ * The various control loops found in Darwin config file are:
+ *
+ * HD Fan control loop.
+ *
+ * # model_id: 2
+ * control : hard-drive-fan
+ * sensor : hard-drive-temp
+ * PID params : G_d = 0x00000000
+ * G_p = 0x002D70A3
+ * G_r = 0x00019999
+ * History = 2 entries
+ * Input target = 0x370000
+ * Interval = 5s
+ *
+ * # model_id: 3
+ * control : hard-drive-fan
+ * sensor : hard-drive-temp
+ * PID params : G_d = 0x00000000
+ * G_p = 0x002170A3
+ * G_r = 0x00019999
+ * History = 2 entries
+ * Input target = 0x370000
+ * Interval = 5s
+ *
+ * OD Fan control loop.
+ *
+ * # model_id: 2
+ * control : optical-drive-fan
+ * sensor : optical-drive-temp
+ * PID params : G_d = 0x00000000
+ * G_p = 0x001FAE14
+ * G_r = 0x00019999
+ * History = 2 entries
+ * Input target = 0x320000
+ * Interval = 5s
+ *
+ * # model_id: 3
+ * control : optical-drive-fan
+ * sensor : optical-drive-temp
+ * PID params : G_d = 0x00000000
+ * G_p = 0x001FAE14
+ * G_r = 0x00019999
+ * History = 2 entries
+ * Input target = 0x320000
+ * Interval = 5s
+ *
+ * GPU Fan control loop.
+ *
+ * # model_id: 2
+ * control : hard-drive-fan
+ * sensor : gpu-temp
+ * PID params : G_d = 0x00000000
+ * G_p = 0x002A6666
+ * G_r = 0x00019999
+ * History = 2 entries
+ * Input target = 0x5A0000
+ * Interval = 5s
+ *
+ * # model_id: 3
+ * control : cpu-fan
+ * sensor : gpu-temp
+ * PID params : G_d = 0x00000000
+ * G_p = 0x0010CCCC
+ * G_r = 0x00019999
+ * History = 2 entries
+ * Input target = 0x500000
+ * Interval = 5s
+ *
+ * KODIAK (aka northbridge) Fan control loop.
+ *
+ * # model_id: 2
+ * control : optical-drive-fan
+ * sensor : north-bridge-temp
+ * PID params : G_d = 0x00000000
+ * G_p = 0x003BD70A
+ * G_r = 0x00019999
+ * History = 2 entries
+ * Input target = 0x550000
+ * Interval = 5s
+ *
+ * # model_id: 3
+ * control : hard-drive-fan
+ * sensor : north-bridge-temp
+ * PID params : G_d = 0x00000000
+ * G_p = 0x0030F5C2
+ * G_r = 0x00019999
+ * History = 2 entries
+ * Input target = 0x550000
+ * Interval = 5s
+ *
+ * CPU Fan control loop.
+ *
+ * control : cpu-fan
+ * sensors : cpu-temp, cpu-power
+ * PID params : from SDB partition
+ *
+ *
+ * CPU Slew control loop.
+ *
+ * control : cpufreq-clamp
+ * sensor : cpu-temp
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/kmod.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/sections.h>
+#include <asm/smu.h>
+
+#include "windfarm.h"
+#include "windfarm_pid.h"
+
+#define VERSION "0.4"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(args...) printk(args)
+#else
+#define DBG(args...) do { } while (0)
+#endif
+
+static int pm121_mach_model; /* machine model id */
+
+/* Controls & sensors */
+static struct wf_sensor *sensor_cpu_power;
+static struct wf_sensor *sensor_cpu_temp;
+static struct wf_sensor *sensor_cpu_voltage;
+static struct wf_sensor *sensor_cpu_current;
+static struct wf_sensor *sensor_gpu_temp;
+static struct wf_sensor *sensor_north_bridge_temp;
+static struct wf_sensor *sensor_hard_drive_temp;
+static struct wf_sensor *sensor_optical_drive_temp;
+static struct wf_sensor *sensor_incoming_air_temp; /* unused ! */
+
+enum {
+ FAN_CPU,
+ FAN_HD,
+ FAN_OD,
+ CPUFREQ,
+ N_CONTROLS
+};
+static struct wf_control *controls[N_CONTROLS] = {};
+
+/* Set to kick the control loop into life */
+static int pm121_all_controls_ok, pm121_all_sensors_ok, pm121_started;
+
+enum {
+ FAILURE_FAN = 1 << 0,
+ FAILURE_SENSOR = 1 << 1,
+ FAILURE_OVERTEMP = 1 << 2
+};
+
+/* All sys loops. Note the HD before the OD loop in order to have it
+ run before. */
+enum {
+ LOOP_GPU, /* control = hd or cpu, but luckily,
+ it doesn't matter */
+ LOOP_HD, /* control = hd */
+ LOOP_KODIAK, /* control = hd or od */
+ LOOP_OD, /* control = od */
+ N_LOOPS
+};
+
+static const char *loop_names[N_LOOPS] = {
+ "GPU",
+ "HD",
+ "KODIAK",
+ "OD",
+};
+
+#define PM121_NUM_CONFIGS 2
+
+static unsigned int pm121_failure_state;
+static int pm121_readjust, pm121_skipping;
+static s32 average_power;
+
+struct pm121_correction {
+ int offset;
+ int slope;
+};
+
+struct pm121_correction corrections[N_CONTROLS][PM121_NUM_CONFIGS] = {
+ /* FAN_OD */
+ {
+ /* MODEL 2 */
+ { .offset = -19563152,
+ .slope = 1956315
+ },
+ /* MODEL 3 */
+ { .offset = -15650652,
+ .slope = 1565065
+ },
+ },
+ /* FAN_HD */
+ {
+ /* MODEL 2 */
+ { .offset = -15650652,
+ .slope = 1565065
+ },
+ /* MODEL 3 */
+ { .offset = -19563152,
+ .slope = 1956315
+ },
+ },
+ /* FAN_CPU */
+ {
+ /* MODEL 2 */
+ { .offset = -25431900,
+ .slope = 2543190
+ },
+ /* MODEL 3 */
+ { .offset = -15650652,
+ .slope = 1565065
+ },
+ },
+ /* CPUFREQ has no correction (and is not implemented at all) */
+};
+
+struct pm121_connection {
+ unsigned int control_id;
+ unsigned int ref_id;
+ struct pm121_correction correction;
+};
+
+static struct pm121_connection pm121_connections[] = {
+ /* MODEL 2 */
+ { .control_id = FAN_CPU,
+ .ref_id = FAN_OD,
+ { .offset = -32768000,
+ .slope = 65536
+ }
+ },
+ /* MODEL 3 */
+ { .control_id = FAN_OD,
+ .ref_id = FAN_HD,
+ { .offset = -32768000,
+ .slope = 65536
+ }
+ },
+};
+
+/* pointer to the current model connection */
+static struct pm121_connection *pm121_connection;
+
+/*
+ * ****** System Fans Control Loop ******
+ *
+ */
+
+/* Since each loop handles only one control and we want to avoid
+ * writing virtual control, we store the control correction with the
+ * loop params. Some data are not set, there are common to all loop
+ * and thus, hardcoded.
+ */
+struct pm121_sys_param {
+ /* purely informative since we use mach_model-2 as index */
+ int model_id;
+ struct wf_sensor **sensor; /* use sensor_id instead ? */
+ s32 gp, itarget;
+ unsigned int control_id;
+};
+
+static struct pm121_sys_param
+pm121_sys_all_params[N_LOOPS][PM121_NUM_CONFIGS] = {
+ /* GPU Fan control loop */
+ {
+ { .model_id = 2,
+ .sensor = &sensor_gpu_temp,
+ .gp = 0x002A6666,
+ .itarget = 0x5A0000,
+ .control_id = FAN_HD,
+ },
+ { .model_id = 3,
+ .sensor = &sensor_gpu_temp,
+ .gp = 0x0010CCCC,
+ .itarget = 0x500000,
+ .control_id = FAN_CPU,
+ },
+ },
+ /* HD Fan control loop */
+ {
+ { .model_id = 2,
+ .sensor = &sensor_hard_drive_temp,
+ .gp = 0x002D70A3,
+ .itarget = 0x370000,
+ .control_id = FAN_HD,
+ },
+ { .model_id = 3,
+ .sensor = &sensor_hard_drive_temp,
+ .gp = 0x002170A3,
+ .itarget = 0x370000,
+ .control_id = FAN_HD,
+ },
+ },
+ /* KODIAK Fan control loop */
+ {
+ { .model_id = 2,
+ .sensor = &sensor_north_bridge_temp,
+ .gp = 0x003BD70A,
+ .itarget = 0x550000,
+ .control_id = FAN_OD,
+ },
+ { .model_id = 3,
+ .sensor = &sensor_north_bridge_temp,
+ .gp = 0x0030F5C2,
+ .itarget = 0x550000,
+ .control_id = FAN_HD,
+ },
+ },
+ /* OD Fan control loop */
+ {
+ { .model_id = 2,
+ .sensor = &sensor_optical_drive_temp,
+ .gp = 0x001FAE14,
+ .itarget = 0x320000,
+ .control_id = FAN_OD,
+ },
+ { .model_id = 3,
+ .sensor = &sensor_optical_drive_temp,
+ .gp = 0x001FAE14,
+ .itarget = 0x320000,
+ .control_id = FAN_OD,
+ },
+ },
+};
+
+/* the hardcoded values */
+#define PM121_SYS_GD 0x00000000
+#define PM121_SYS_GR 0x00019999
+#define PM121_SYS_HISTORY_SIZE 2
+#define PM121_SYS_INTERVAL 5
+
+/* State data used by the system fans control loop
+ */
+struct pm121_sys_state {
+ int ticks;
+ s32 setpoint;
+ struct wf_pid_state pid;
+};
+
+struct pm121_sys_state *pm121_sys_state[N_LOOPS] = {};
+
+/*
+ * ****** CPU Fans Control Loop ******
+ *
+ */
+
+#define PM121_CPU_INTERVAL 1
+
+/* State data used by the cpu fans control loop
+ */
+struct pm121_cpu_state {
+ int ticks;
+ s32 setpoint;
+ struct wf_cpu_pid_state pid;
+};
+
+static struct pm121_cpu_state *pm121_cpu_state;
+
+
+
+/*
+ * ***** Implementation *****
+ *
+ */
+
+/* correction the value using the output-low-bound correction algo */
+static s32 pm121_correct(s32 new_setpoint,
+ unsigned int control_id,
+ s32 min)
+{
+ s32 new_min;
+ struct pm121_correction *correction;
+ correction = &corrections[control_id][pm121_mach_model - 2];
+
+ new_min = (average_power * correction->slope) >> 16;
+ new_min += correction->offset;
+ new_min = (new_min >> 16) + min;
+
+ return max(new_setpoint, max(new_min, 0));
+}
+
+static s32 pm121_connect(unsigned int control_id, s32 setpoint)
+{
+ s32 new_min, value, new_setpoint;
+
+ if (pm121_connection->control_id == control_id) {
+ controls[control_id]->ops->get_value(controls[control_id],
+ &value);
+ new_min = value * pm121_connection->correction.slope;
+ new_min += pm121_connection->correction.offset;
+ if (new_min > 0) {
+ new_setpoint = max(setpoint, (new_min >> 16));
+ if (new_setpoint != setpoint) {
+ DBG("pm121: %s depending on %s, "
+ "corrected from %d to %d RPM\n",
+ controls[control_id]->name,
+ controls[pm121_connection->ref_id]->name,
+ (int) setpoint, (int) new_setpoint);
+ }
+ } else
+ new_setpoint = setpoint;
+ }
+ /* no connection */
+ else
+ new_setpoint = setpoint;
+
+ return new_setpoint;
+}
+
+/* FAN LOOPS */
+static void pm121_create_sys_fans(int loop_id)
+{
+ struct pm121_sys_param *param = NULL;
+ struct wf_pid_param pid_param;
+ struct wf_control *control = NULL;
+ int i;
+
+ /* First, locate the params for this model */
+ for (i = 0; i < PM121_NUM_CONFIGS; i++) {
+ if (pm121_sys_all_params[loop_id][i].model_id == pm121_mach_model) {
+ param = &(pm121_sys_all_params[loop_id][i]);
+ break;
+ }
+ }
+
+ /* No params found, put fans to max */
+ if (param == NULL) {
+ printk(KERN_WARNING "pm121: %s fan config not found "
+ " for this machine model\n",
+ loop_names[loop_id]);
+ goto fail;
+ }
+
+ control = controls[param->control_id];
+
+ /* Alloc & initialize state */
+ pm121_sys_state[loop_id] = kmalloc(sizeof(struct pm121_sys_state),
+ GFP_KERNEL);
+ if (pm121_sys_state[loop_id] == NULL) {
+ printk(KERN_WARNING "pm121: Memory allocation error\n");
+ goto fail;
+ }
+ pm121_sys_state[loop_id]->ticks = 1;
+
+ /* Fill PID params */
+ pid_param.gd = PM121_SYS_GD;
+ pid_param.gp = param->gp;
+ pid_param.gr = PM121_SYS_GR;
+ pid_param.interval = PM121_SYS_INTERVAL;
+ pid_param.history_len = PM121_SYS_HISTORY_SIZE;
+ pid_param.itarget = param->itarget;
+ pid_param.min = control->ops->get_min(control);
+ pid_param.max = control->ops->get_max(control);
+
+ wf_pid_init(&pm121_sys_state[loop_id]->pid, &pid_param);
+
+ DBG("pm121: %s Fan control loop initialized.\n"
+ " itarged=%d.%03d, min=%d RPM, max=%d RPM\n",
+ loop_names[loop_id], FIX32TOPRINT(pid_param.itarget),
+ pid_param.min, pid_param.max);
+ return;
+
+ fail:
+ /* note that this is not optimal since another loop may still
+ control the same control */
+ printk(KERN_WARNING "pm121: failed to set up %s loop "
+ "setting \"%s\" to max speed.\n",
+ loop_names[loop_id], control->name);
+
+ if (control)
+ wf_control_set_max(control);
+}
+
+static void pm121_sys_fans_tick(int loop_id)
+{
+ struct pm121_sys_param *param;
+ struct pm121_sys_state *st;
+ struct wf_sensor *sensor;
+ struct wf_control *control;
+ s32 temp, new_setpoint;
+ int rc;
+
+ param = &(pm121_sys_all_params[loop_id][pm121_mach_model-2]);
+ st = pm121_sys_state[loop_id];
+ sensor = *(param->sensor);
+ control = controls[param->control_id];
+
+ if (--st->ticks != 0) {
+ if (pm121_readjust)
+ goto readjust;
+ return;
+ }
+ st->ticks = PM121_SYS_INTERVAL;
+
+ rc = sensor->ops->get_value(sensor, &temp);
+ if (rc) {
+ printk(KERN_WARNING "windfarm: %s sensor error %d\n",
+ sensor->name, rc);
+ pm121_failure_state |= FAILURE_SENSOR;
+ return;
+ }
+
+ DBG("pm121: %s Fan tick ! %s: %d.%03d\n",
+ loop_names[loop_id], sensor->name,
+ FIX32TOPRINT(temp));
+
+ new_setpoint = wf_pid_run(&st->pid, temp);
+
+ /* correction */
+ new_setpoint = pm121_correct(new_setpoint,
+ param->control_id,
+ st->pid.param.min);
+ /* linked corretion */
+ new_setpoint = pm121_connect(param->control_id, new_setpoint);
+
+ if (new_setpoint == st->setpoint)
+ return;
+ st->setpoint = new_setpoint;
+ DBG("pm121: %s corrected setpoint: %d RPM\n",
+ control->name, (int)new_setpoint);
+ readjust:
+ if (control && pm121_failure_state == 0) {
+ rc = control->ops->set_value(control, st->setpoint);
+ if (rc) {
+ printk(KERN_WARNING "windfarm: %s fan error %d\n",
+ control->name, rc);
+ pm121_failure_state |= FAILURE_FAN;
+ }
+ }
+}
+
+
+/* CPU LOOP */
+static void pm121_create_cpu_fans(void)
+{
+ struct wf_cpu_pid_param pid_param;
+ const struct smu_sdbp_header *hdr;
+ struct smu_sdbp_cpupiddata *piddata;
+ struct smu_sdbp_fvt *fvt;
+ struct wf_control *fan_cpu;
+ s32 tmax, tdelta, maxpow, powadj;
+
+ fan_cpu = controls[FAN_CPU];
+
+ /* First, locate the PID params in SMU SBD */
+ hdr = smu_get_sdb_partition(SMU_SDB_CPUPIDDATA_ID, NULL);
+ if (hdr == 0) {
+ printk(KERN_WARNING "pm121: CPU PID fan config not found.\n");
+ goto fail;
+ }
+ piddata = (struct smu_sdbp_cpupiddata *)&hdr[1];
+
+ /* Get the FVT params for operating point 0 (the only supported one
+ * for now) in order to get tmax
+ */
+ hdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL);
+ if (hdr) {
+ fvt = (struct smu_sdbp_fvt *)&hdr[1];
+ tmax = ((s32)fvt->maxtemp) << 16;
+ } else
+ tmax = 0x5e0000; /* 94 degree default */
+
+ /* Alloc & initialize state */
+ pm121_cpu_state = kmalloc(sizeof(struct pm121_cpu_state),
+ GFP_KERNEL);
+ if (pm121_cpu_state == NULL)
+ goto fail;
+ pm121_cpu_state->ticks = 1;
+
+ /* Fill PID params */
+ pid_param.interval = PM121_CPU_INTERVAL;
+ pid_param.history_len = piddata->history_len;
+ if (pid_param.history_len > WF_CPU_PID_MAX_HISTORY) {
+ printk(KERN_WARNING "pm121: History size overflow on "
+ "CPU control loop (%d)\n", piddata->history_len);
+ pid_param.history_len = WF_CPU_PID_MAX_HISTORY;
+ }
+ pid_param.gd = piddata->gd;
+ pid_param.gp = piddata->gp;
+ pid_param.gr = piddata->gr / pid_param.history_len;
+
+ tdelta = ((s32)piddata->target_temp_delta) << 16;
+ maxpow = ((s32)piddata->max_power) << 16;
+ powadj = ((s32)piddata->power_adj) << 16;
+
+ pid_param.tmax = tmax;
+ pid_param.ttarget = tmax - tdelta;
+ pid_param.pmaxadj = maxpow - powadj;
+
+ pid_param.min = fan_cpu->ops->get_min(fan_cpu);
+ pid_param.max = fan_cpu->ops->get_max(fan_cpu);
+
+ wf_cpu_pid_init(&pm121_cpu_state->pid, &pid_param);
+
+ DBG("pm121: CPU Fan control initialized.\n");
+ DBG(" ttarged=%d.%03d, tmax=%d.%03d, min=%d RPM, max=%d RPM,\n",
+ FIX32TOPRINT(pid_param.ttarget), FIX32TOPRINT(pid_param.tmax),
+ pid_param.min, pid_param.max);
+
+ return;
+
+ fail:
+ printk(KERN_WARNING "pm121: CPU fan config not found, max fan speed\n");
+
+ if (controls[CPUFREQ])
+ wf_control_set_max(controls[CPUFREQ]);
+ if (fan_cpu)
+ wf_control_set_max(fan_cpu);
+}
+
+
+static void pm121_cpu_fans_tick(struct pm121_cpu_state *st)
+{
+ s32 new_setpoint, temp, power;
+ struct wf_control *fan_cpu = NULL;
+ int rc;
+
+ if (--st->ticks != 0) {
+ if (pm121_readjust)
+ goto readjust;
+ return;
+ }
+ st->ticks = PM121_CPU_INTERVAL;
+
+ fan_cpu = controls[FAN_CPU];
+
+ rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp);
+ if (rc) {
+ printk(KERN_WARNING "pm121: CPU temp sensor error %d\n",
+ rc);
+ pm121_failure_state |= FAILURE_SENSOR;
+ return;
+ }
+
+ rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power);
+ if (rc) {
+ printk(KERN_WARNING "pm121: CPU power sensor error %d\n",
+ rc);
+ pm121_failure_state |= FAILURE_SENSOR;
+ return;
+ }
+
+ DBG("pm121: CPU Fans tick ! CPU temp: %d.%03d°C, power: %d.%03d\n",
+ FIX32TOPRINT(temp), FIX32TOPRINT(power));
+
+#ifdef HACKED_OVERTEMP
+#define MAX 0x4a0000
+#else
+#define MAX st->pid.param.tmax
+#endif
+ if (temp > MAX)
+ pm121_failure_state |= FAILURE_OVERTEMP;
+
+#undef MAX
+
+ new_setpoint = wf_cpu_pid_run(&st->pid, power, temp);
+
+ /* correction */
+ new_setpoint = pm121_correct(new_setpoint,
+ FAN_CPU,
+ st->pid.param.min);
+
+ /* connected correction */
+ new_setpoint = pm121_connect(FAN_CPU, new_setpoint);
+
+ if (st->setpoint == new_setpoint)
+ return;
+ st->setpoint = new_setpoint;
+ DBG("pm121: CPU corrected setpoint: %d RPM\n", (int)new_setpoint);
+
+ readjust:
+ if (fan_cpu && pm121_failure_state == 0) {
+ rc = fan_cpu->ops->set_value(fan_cpu, st->setpoint);
+ if (rc) {
+ printk(KERN_WARNING "pm121: %s fan error %d\n",
+ fan_cpu->name, rc);
+ pm121_failure_state |= FAILURE_FAN;
+ }
+ }
+}
+
+/*
+ * ****** Common ******
+ *
+ */
+
+static void pm121_tick(void)
+{
+ unsigned int last_failure = pm121_failure_state;
+ unsigned int new_failure;
+ s32 total_power;
+ int i;
+
+ if (!pm121_started) {
+ DBG("pm121: creating control loops !\n");
+ for (i = 0; i < N_LOOPS; i++)
+ pm121_create_sys_fans(i);
+
+ pm121_create_cpu_fans();
+ pm121_started = 1;
+ }
+
+ /* skipping ticks */
+ if (pm121_skipping && --pm121_skipping)
+ return;
+
+ /* compute average power */
+ total_power = 0;
+ for (i = 0; i < pm121_cpu_state->pid.param.history_len; i++)
+ total_power += pm121_cpu_state->pid.powers[i];
+
+ average_power = total_power / pm121_cpu_state->pid.param.history_len;
+
+
+ pm121_failure_state = 0;
+ for (i = 0 ; i < N_LOOPS; i++) {
+ if (pm121_sys_state[i])
+ pm121_sys_fans_tick(i);
+ }
+
+ if (pm121_cpu_state)
+ pm121_cpu_fans_tick(pm121_cpu_state);
+
+ pm121_readjust = 0;
+ new_failure = pm121_failure_state & ~last_failure;
+
+ /* If entering failure mode, clamp cpufreq and ramp all
+ * fans to full speed.
+ */
+ if (pm121_failure_state && !last_failure) {
+ for (i = 0; i < N_CONTROLS; i++) {
+ if (controls[i])
+ wf_control_set_max(controls[i]);
+ }
+ }
+
+ /* If leaving failure mode, unclamp cpufreq and readjust
+ * all fans on next iteration
+ */
+ if (!pm121_failure_state && last_failure) {
+ if (controls[CPUFREQ])
+ wf_control_set_min(controls[CPUFREQ]);
+ pm121_readjust = 1;
+ }
+
+ /* Overtemp condition detected, notify and start skipping a couple
+ * ticks to let the temperature go down
+ */
+ if (new_failure & FAILURE_OVERTEMP) {
+ wf_set_overtemp();
+ pm121_skipping = 2;
+ }
+
+ /* We only clear the overtemp condition if overtemp is cleared
+ * _and_ no other failure is present. Since a sensor error will
+ * clear the overtemp condition (can't measure temperature) at
+ * the control loop levels, but we don't want to keep it clear
+ * here in this case
+ */
+ if (new_failure == 0 && last_failure & FAILURE_OVERTEMP)
+ wf_clear_overtemp();
+}
+
+
+
+
+#define pm121_register_control(control, match, id) \
+ if (controls[id] == NULL && !strcmp(control->name,match)) { \
+ if (wf_get_control(control) == 0) \
+ controls[id] = control; \
+ } \
+ all = all && controls[id];
+
+static void pm121_new_control(struct wf_control *ct)
+{
+ int all = 1;
+
+ if (pm121_all_controls_ok)
+ return;
+
+ pm121_register_control(ct, "optical-drive-fan", FAN_OD);
+ pm121_register_control(ct, "hard-drive-fan", FAN_HD);
+ pm121_register_control(ct, "cpu-fan", FAN_CPU);
+ pm121_register_control(ct, "cpufreq-clamp", CPUFREQ);
+
+ if (all)
+ pm121_all_controls_ok = 1;
+}
+#undef pm121_register_control
+
+
+
+
+#define pm121_register_sensor(sensor, match, var) \
+ if (var == NULL && !strcmp(sensor->name,match)) { \
+ if (wf_get_sensor(sensor) == 0) \
+ var = sensor; \
+ } \
+ all = all && var;
+
+static void pm121_new_sensor(struct wf_sensor *sr)
+{
+ int all = 1;
+
+ if (pm121_all_sensors_ok)
+ return;
+
+ pm121_register_sensor(sr, "cpu-temp",
+ sensor_cpu_temp);
+ pm121_register_sensor(sr, "cpu-current",
+ sensor_cpu_current);
+ pm121_register_sensor(sr, "cpu-voltage",
+ sensor_cpu_voltage);
+ pm121_register_sensor(sr, "cpu-power",
+ sensor_cpu_power);
+ pm121_register_sensor(sr, "hard-drive-temp",
+ sensor_hard_drive_temp);
+ pm121_register_sensor(sr, "optical-drive-temp",
+ sensor_optical_drive_temp);
+ pm121_register_sensor(sr, "incoming-air-temp",
+ sensor_incoming_air_temp);
+ pm121_register_sensor(sr, "north-bridge-temp",
+ sensor_north_bridge_temp);
+ pm121_register_sensor(sr, "gpu-temp",
+ sensor_gpu_temp);
+
+ if (all)
+ pm121_all_sensors_ok = 1;
+}
+
+#undef pm121_register_sensor
+
+
+
+static int pm121_notify(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ switch (event) {
+ case WF_EVENT_NEW_CONTROL:
+ DBG("pm121: new control %s detected\n",
+ ((struct wf_control *)data)->name);
+ pm121_new_control(data);
+ break;
+ case WF_EVENT_NEW_SENSOR:
+ DBG("pm121: new sensor %s detected\n",
+ ((struct wf_sensor *)data)->name);
+ pm121_new_sensor(data);
+ break;
+ case WF_EVENT_TICK:
+ if (pm121_all_controls_ok && pm121_all_sensors_ok)
+ pm121_tick();
+ break;
+ }
+
+ return 0;
+}
+
+static struct notifier_block pm121_events = {
+ .notifier_call = pm121_notify,
+};
+
+static int pm121_init_pm(void)
+{
+ const struct smu_sdbp_header *hdr;
+
+ hdr = smu_get_sdb_partition(SMU_SDB_SENSORTREE_ID, NULL);
+ if (hdr != 0) {
+ struct smu_sdbp_sensortree *st =
+ (struct smu_sdbp_sensortree *)&hdr[1];
+ pm121_mach_model = st->model_id;
+ }
+
+ pm121_connection = &pm121_connections[pm121_mach_model - 2];
+
+ printk(KERN_INFO "pm121: Initializing for iMac G5 iSight model ID %d\n",
+ pm121_mach_model);
+
+ return 0;
+}
+
+
+static int pm121_probe(struct platform_device *ddev)
+{
+ wf_register_client(&pm121_events);
+
+ return 0;
+}
+
+static int __devexit pm121_remove(struct platform_device *ddev)
+{
+ wf_unregister_client(&pm121_events);
+ return 0;
+}
+
+static struct platform_driver pm121_driver = {
+ .probe = pm121_probe,
+ .remove = __devexit_p(pm121_remove),
+ .driver = {
+ .name = "windfarm",
+ .bus = &platform_bus_type,
+ },
+};
+
+
+static int __init pm121_init(void)
+{
+ int rc = -ENODEV;
+
+ if (machine_is_compatible("PowerMac12,1"))
+ rc = pm121_init_pm();
+
+ if (rc == 0) {
+#ifdef MODULE
+ request_module("windfarm_smu_controls");
+ request_module("windfarm_smu_sensors");
+ request_module("windfarm_smu_sat");
+ request_module("windfarm_lm75_sensor");
+ request_module("windfarm_max6690_sensor");
+ request_module("windfarm_cpufreq_clamp");
+
+#endif /* MODULE */
+ platform_driver_register(&pm121_driver);
+ }
+
+ return rc;
+}
+
+static void __exit pm121_exit(void)
+{
+
+ platform_driver_unregister(&pm121_driver);
+}
+
+
+module_init(pm121_init);
+module_exit(pm121_exit);
+
+MODULE_AUTHOR("Étienne Bersac <bersace@gmail.com>");
+MODULE_DESCRIPTION("Thermal control logic for iMac G5 (iSight)");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c
index 58c2590..961fa0e 100644
--- a/drivers/macintosh/windfarm_smu_controls.c
+++ b/drivers/macintosh/windfarm_smu_controls.c
@@ -218,6 +218,10 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node,
fct->ctrl.name = "cpu-fan";
else if (!strcmp(l, "Hard Drive") || !strcmp(l, "Hard drive"))
fct->ctrl.name = "drive-bay-fan";
+ else if (!strcmp(l, "HDD Fan")) /* seen on iMac G5 iSight */
+ fct->ctrl.name = "hard-drive-fan";
+ else if (!strcmp(l, "ODD Fan")) /* same */
+ fct->ctrl.name = "optical-drive-fan";
/* Unrecognized fan, bail out */
if (fct->ctrl.name == NULL)
^ permalink raw reply related
* Re: [PATCH 3/4] Convert PowerPC MPC i2c to of_platform_driver from platform_driver
From: Kumar Gala @ 2007-12-10 15:34 UTC (permalink / raw)
To: Jon Smirl; +Cc: linuxppc-dev, i2c
In-Reply-To: <20071209233654.2327.18925.stgit@terra.home>
On Dec 9, 2007, at 5:36 PM, Jon Smirl wrote:
> Convert MPC i2c driver from being a platform_driver to an open
> firmware version. Error returns were improved. Routine names were
> changed from fsl_ to mpc_ to make them match the file name.
>
> Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
> ---
>
> arch/powerpc/sysdev/fsl_soc.c | 96 ---------------------
> drivers/i2c/busses/i2c-mpc.c | 190 +++++++++++++++++++++++++++
> +-------------
> 2 files changed, 129 insertions(+), 157 deletions(-)
this patch breaks arch/ppc users which are platform_driver based and
I'm guessing a number of arch/powerpc users which don't
of_platform_bus_probe().
Also, you should split out the conversion and error fixing into
separate patches.
- k
^ permalink raw reply
* Re: [PATCH] windfarm: add PowerMac 12,1 support
From: Arnd Bergmann @ 2007-12-10 15:39 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <1197299517.6822.2.camel@thilivren>
On Monday 10 December 2007, =C3=89tienne Bersac wrote:
> From: =C3=89tienne Bersac <bersace03@gmail.com>
>=20
> Here is an updated patch that fix the potential bug, CPU param detection
> failure might not be detected. Please review it.=20
I didn't find much interesting to complain about, just a few style
issues that could be improved. Good work!
> -static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr)
> +static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr,
> + const char *loc)
> {
> struct wf_6690_sensor *max;
> - char *name =3D "backside-temp";
> + char *name =3D NULL;
> =20
It's better not to initialize local variables like this one, instead of
assigning them to 0 or NULL. When it's not initialized, gcc is able to
warn about cases where you don't assign a meaningful value before using
it.
> +#undef DEBUG
> +
> +#ifdef DEBUG
> +#define DBG(args...) printk(args)
> +#else
> +#define DBG(args...) do { } while (0)
> +#endif
Don't define your own macros like these, but instead use the ones that
are there. If possible, use 'dev_dbg()', otherwise 'pr_debug()'.
> +static int pm121_mach_model; /* machine model id */
> +
> +/* Controls & sensors */
> +static struct wf_sensor *sensor_cpu_power;
> +static struct wf_sensor *sensor_cpu_temp;
> +static struct wf_sensor *sensor_cpu_voltage;
> +static struct wf_sensor *sensor_cpu_current;
> +static struct wf_sensor *sensor_gpu_temp;
> +static struct wf_sensor *sensor_north_bridge_temp;
> +static struct wf_sensor *sensor_hard_drive_temp;
> +static struct wf_sensor *sensor_optical_drive_temp;
> +static struct wf_sensor *sensor_incoming_air_temp; /* unused ! */
> +static struct wf_control *controls[N_CONTROLS] =3D {};
> +
> +static unsigned int pm121_failure_state;
> +static int pm121_readjust, pm121_skipping;
> +static s32 average_power;
Having many global variables is typically a sign that you are doing
something wrong. It's better to attach all the data you have to your
device structure.
Have you checked that you are doing the right locking when accessing
these variables from concurrent threads?
> +struct pm121_correction {
> + int offset;
> + int slope;
> +};
> +
> +struct pm121_correction corrections[N_CONTROLS][PM121_NUM_CONFIGS] =3D {
This looks like it could be 'const'. 'static const' variables are better
because it becomes obvious that you don't need locking to access them.
> +static struct pm121_connection pm121_connections[] =3D {
same here.
> +static struct pm121_sys_param
> +pm121_sys_all_params[N_LOOPS][PM121_NUM_CONFIGS] =3D {
and here.
> +#ifdef HACKED_OVERTEMP
> +#define MAX 0x4a0000
> +#else
> +#define MAX st->pid.param.tmax
> +#endif
> + if (temp > MAX)
> + pm121_failure_state |=3D FAILURE_OVERTEMP;
> +
> +#undef MAX
You don't define HACKED_OVERTEMP anywhere, so you basicall have dead
code here. It's probably better to remove that for the upstream version,
even if it was helpful for your debugging.
> +
> +#define pm121_register_control(control, match, id) \
> + if (controls[id] =3D=3D NULL && !strcmp(control->name,match)) { \
> + if (wf_get_control(control) =3D=3D 0) \
> + controls[id] =3D control; \
> + } \
> + all =3D all && controls[id];
Does this need to be a macro? If possible, use static functions
for this kind of stuff. They will normally be inlined, which gives
you the same object code in the end.
> +static int __init pm121_init(void)
> +{
> + int rc =3D -ENODEV;
> +
> + if (machine_is_compatible("PowerMac12,1"))
> + rc =3D pm121_init_pm();
> +
> + if (rc =3D=3D 0) {
> +#ifdef MODULE
> + request_module("windfarm_smu_controls");
> + request_module("windfarm_smu_sensors");
> + request_module("windfarm_smu_sat");
> + request_module("windfarm_lm75_sensor");
> + request_module("windfarm_max6690_sensor");
> + request_module("windfarm_cpufreq_clamp");
> +
> +#endif /* MODULE */
> + platform_driver_register(&pm121_driver);
> + }
> +
> + return rc;
> +}
Why the #ifdef MODULE here? It's normally better to have identical
code for modular and built-in cases.
Arnd <><
^ permalink raw reply
* Re: [PATCH 3/4] Convert PowerPC MPC i2c to of_platform_driver from platform_driver
From: Jon Smirl @ 2007-12-10 16:12 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev, i2c
In-Reply-To: <1E5FF6FC-E905-4FAF-84ED-A96B0E0ACCA8@kernel.crashing.org>
On 12/10/07, Kumar Gala <galak@kernel.crashing.org> wrote:
>
> On Dec 9, 2007, at 5:36 PM, Jon Smirl wrote:
>
> > Convert MPC i2c driver from being a platform_driver to an open
> > firmware version. Error returns were improved. Routine names were
> > changed from fsl_ to mpc_ to make them match the file name.
> >
> > Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
> > ---
> >
> > arch/powerpc/sysdev/fsl_soc.c | 96 ---------------------
> > drivers/i2c/busses/i2c-mpc.c | 190 +++++++++++++++++++++++++++
> > +-------------
> > 2 files changed, 129 insertions(+), 157 deletions(-)
>
> this patch breaks arch/ppc users which are platform_driver based and
> I'm guessing a number of arch/powerpc users which don't
> of_platform_bus_probe().
We should just make two copies of the driver. All of this is needed to
allow automatic loading of the correct i2c modules as dictated by the
device tree. I'm working on the same support for automatically loading
audio codec drivers.
> Also, you should split out the conversion and error fixing into
> separate patches.
I can spin another revision to move those nine lines adding missing
error returns to another patch.
>
> - k
>
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox